[PATCH] fbcon/fbdev: Move softcursor out of fbdev to fbcon
[safe/jmp/linux-2.6] / 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 #ifdef CONFIG_FB_SOFT_CURSOR
2006         .fb_cursor      = soft_cursor,
2007 #endif
2008         .fb_sync        = fbcon_sis_sync,
2009 #ifdef SIS_NEW_CONFIG_COMPAT
2010         .fb_compat_ioctl= sisfb_compat_ioctl,
2011 #endif
2012         .fb_ioctl       = sisfb_ioctl
2013 };
2014 #endif
2015
2016 /* ---------------- Chip generation dependent routines ---------------- */
2017
2018 static struct pci_dev * __devinit
2019 sisfb_get_northbridge(int basechipid)
2020 {
2021         struct pci_dev *pdev = NULL;
2022         int nbridgenum, nbridgeidx, i;
2023         static const unsigned short nbridgeids[] = {
2024                 PCI_DEVICE_ID_SI_540,   /* for SiS 540 VGA */
2025                 PCI_DEVICE_ID_SI_630,   /* for SiS 630/730 VGA */
2026                 PCI_DEVICE_ID_SI_730,
2027                 PCI_DEVICE_ID_SI_550,   /* for SiS 550 VGA */
2028                 PCI_DEVICE_ID_SI_650,   /* for SiS 650/651/740 VGA */
2029                 PCI_DEVICE_ID_SI_651,
2030                 PCI_DEVICE_ID_SI_740,
2031                 PCI_DEVICE_ID_SI_661,   /* for SiS 661/741/660/760/761 VGA */
2032                 PCI_DEVICE_ID_SI_741,
2033                 PCI_DEVICE_ID_SI_660,
2034                 PCI_DEVICE_ID_SI_760,
2035                 PCI_DEVICE_ID_SI_761
2036         };
2037
2038         switch(basechipid) {
2039 #ifdef CONFIG_FB_SIS_300
2040         case SIS_540:   nbridgeidx = 0; nbridgenum = 1; break;
2041         case SIS_630:   nbridgeidx = 1; nbridgenum = 2; break;
2042 #endif
2043 #ifdef CONFIG_FB_SIS_315
2044         case SIS_550:   nbridgeidx = 3; nbridgenum = 1; break;
2045         case SIS_650:   nbridgeidx = 4; nbridgenum = 3; break;
2046         case SIS_660:   nbridgeidx = 7; nbridgenum = 5; break;
2047 #endif
2048         default:        return NULL;
2049         }
2050         for(i = 0; i < nbridgenum; i++) {
2051                 if((pdev = SIS_PCI_GET_DEVICE(PCI_VENDOR_ID_SI,
2052                                 nbridgeids[nbridgeidx+i], NULL)))
2053                         break;
2054         }
2055         return pdev;
2056 }
2057
2058 static int __devinit
2059 sisfb_get_dram_size(struct sis_video_info *ivideo)
2060 {
2061 #if defined(CONFIG_FB_SIS_300) || defined(CONFIG_FB_SIS_315)
2062         u8 reg;
2063 #endif
2064
2065         ivideo->video_size = 0;
2066         ivideo->UMAsize = ivideo->LFBsize = 0;
2067
2068         switch(ivideo->chip) {
2069 #ifdef CONFIG_FB_SIS_300
2070         case SIS_300:
2071                 inSISIDXREG(SISSR, 0x14, reg);
2072                 ivideo->video_size = ((reg & 0x3F) + 1) << 20;
2073                 break;
2074         case SIS_540:
2075         case SIS_630:
2076         case SIS_730:
2077                 if(!ivideo->nbridge)
2078                         return -1;
2079                 pci_read_config_byte(ivideo->nbridge, 0x63, &reg);
2080                 ivideo->video_size = 1 << (((reg & 0x70) >> 4) + 21);
2081                 break;
2082 #endif
2083 #ifdef CONFIG_FB_SIS_315
2084         case SIS_315H:
2085         case SIS_315PRO:
2086         case SIS_315:
2087                 inSISIDXREG(SISSR, 0x14, reg);
2088                 ivideo->video_size = (1 << ((reg & 0xf0) >> 4)) << 20;
2089                 switch((reg >> 2) & 0x03) {
2090                 case 0x01:
2091                 case 0x03:
2092                         ivideo->video_size <<= 1;
2093                         break;
2094                 case 0x02:
2095                         ivideo->video_size += (ivideo->video_size/2);
2096                 }
2097                 break;
2098         case SIS_330:
2099                 inSISIDXREG(SISSR, 0x14, reg);
2100                 ivideo->video_size = (1 << ((reg & 0xf0) >> 4)) << 20;
2101                 if(reg & 0x0c) ivideo->video_size <<= 1;
2102                 break;
2103         case SIS_550:
2104         case SIS_650:
2105         case SIS_740:
2106                 inSISIDXREG(SISSR, 0x14, reg);
2107                 ivideo->video_size = (((reg & 0x3f) + 1) << 2) << 20;
2108                 break;
2109         case SIS_661:
2110         case SIS_741:
2111                 inSISIDXREG(SISCR, 0x79, reg);
2112                 ivideo->video_size = (1 << ((reg & 0xf0) >> 4)) << 20;
2113                 break;
2114         case SIS_660:
2115         case SIS_760:
2116         case SIS_761:
2117                 inSISIDXREG(SISCR, 0x79, reg);
2118                 reg = (reg & 0xf0) >> 4;
2119                 if(reg) {
2120                         ivideo->video_size = (1 << reg) << 20;
2121                         ivideo->UMAsize = ivideo->video_size;
2122                 }
2123                 inSISIDXREG(SISCR, 0x78, reg);
2124                 reg &= 0x30;
2125                 if(reg) {
2126                         if(reg == 0x10) {
2127                                 ivideo->LFBsize = (32 << 20);
2128                         } else {
2129                                 ivideo->LFBsize = (64 << 20);
2130                         }
2131                         ivideo->video_size += ivideo->LFBsize;
2132                 }
2133                 break;
2134         case SIS_340:
2135         case XGI_20:
2136         case XGI_40:
2137                 inSISIDXREG(SISSR, 0x14, reg);
2138                 ivideo->video_size = (1 << ((reg & 0xf0) >> 4)) << 20;
2139                 if(ivideo->chip != XGI_20) {
2140                         reg = (reg & 0x0c) >> 2;
2141                         if(ivideo->revision_id == 2) {
2142                                 if(reg & 0x01) reg = 0x02;
2143                                 else           reg = 0x00;
2144                         }
2145                         if(reg == 0x02)         ivideo->video_size <<= 1;
2146                         else if(reg == 0x03)    ivideo->video_size <<= 2;
2147                 }
2148                 break;
2149 #endif
2150         default:
2151                 return -1;
2152         }
2153         return 0;
2154 }
2155
2156 /* -------------- video bridge device detection --------------- */
2157
2158 static void __devinit
2159 sisfb_detect_VB_connect(struct sis_video_info *ivideo)
2160 {
2161         u8 cr32, temp;
2162
2163         /* No CRT2 on XGI Z7 */
2164         if(ivideo->chip == XGI_20) {
2165                 ivideo->sisfb_crt1off = 0;
2166                 return;
2167         }
2168
2169 #ifdef CONFIG_FB_SIS_300
2170         if(ivideo->sisvga_engine == SIS_300_VGA) {
2171                 inSISIDXREG(SISSR, 0x17, temp);
2172                 if((temp & 0x0F) && (ivideo->chip != SIS_300)) {
2173                         /* PAL/NTSC is stored on SR16 on such machines */
2174                         if(!(ivideo->vbflags & (TV_PAL | TV_NTSC | TV_PALM | TV_PALN))) {
2175                                 inSISIDXREG(SISSR, 0x16, temp);
2176                                 if(temp & 0x20)
2177                                         ivideo->vbflags |= TV_PAL;
2178                                 else
2179                                         ivideo->vbflags |= TV_NTSC;
2180                         }
2181                 }
2182         }
2183 #endif
2184
2185         inSISIDXREG(SISCR, 0x32, cr32);
2186
2187         if(cr32 & SIS_CRT1) {
2188                 ivideo->sisfb_crt1off = 0;
2189         } else {
2190                 ivideo->sisfb_crt1off = (cr32 & 0xDF) ? 1 : 0;
2191         }
2192
2193         ivideo->vbflags &= ~(CRT2_TV | CRT2_LCD | CRT2_VGA);
2194
2195         if(cr32 & SIS_VB_TV)   ivideo->vbflags |= CRT2_TV;
2196         if(cr32 & SIS_VB_LCD)  ivideo->vbflags |= CRT2_LCD;
2197         if(cr32 & SIS_VB_CRT2) ivideo->vbflags |= CRT2_VGA;
2198
2199         /* Check given parms for hardware compatibility.
2200          * (Cannot do this in the search_xx routines since we don't
2201          * know what hardware we are running on then)
2202          */
2203
2204         if(ivideo->chip != SIS_550) {
2205            ivideo->sisfb_dstn = ivideo->sisfb_fstn = 0;
2206         }
2207
2208         if(ivideo->sisfb_tvplug != -1) {
2209            if( (ivideo->sisvga_engine != SIS_315_VGA) ||
2210                (!(ivideo->vbflags2 & VB2_SISYPBPRBRIDGE)) ) {
2211               if(ivideo->sisfb_tvplug & TV_YPBPR) {
2212                  ivideo->sisfb_tvplug = -1;
2213                  printk(KERN_ERR "sisfb: YPbPr not supported\n");
2214               }
2215            }
2216         }
2217         if(ivideo->sisfb_tvplug != -1) {
2218            if( (ivideo->sisvga_engine != SIS_315_VGA) ||
2219                (!(ivideo->vbflags2 & VB2_SISHIVISIONBRIDGE)) ) {
2220               if(ivideo->sisfb_tvplug & TV_HIVISION) {
2221                  ivideo->sisfb_tvplug = -1;
2222                  printk(KERN_ERR "sisfb: HiVision not supported\n");
2223               }
2224            }
2225         }
2226         if(ivideo->sisfb_tvstd != -1) {
2227            if( (!(ivideo->vbflags2 & VB2_SISBRIDGE)) &&
2228                (!((ivideo->sisvga_engine == SIS_315_VGA) &&
2229                         (ivideo->vbflags2 & VB2_CHRONTEL))) ) {
2230               if(ivideo->sisfb_tvstd & (TV_PALN | TV_PALN | TV_NTSCJ)) {
2231                  ivideo->sisfb_tvstd = -1;
2232                  printk(KERN_ERR "sisfb: PALM/PALN/NTSCJ not supported\n");
2233               }
2234            }
2235         }
2236
2237         /* Detect/set TV plug & type */
2238         if(ivideo->sisfb_tvplug != -1) {
2239                 ivideo->vbflags |= ivideo->sisfb_tvplug;
2240         } else {
2241                 if(cr32 & SIS_VB_YPBPR)          ivideo->vbflags |= (TV_YPBPR|TV_YPBPR525I); /* default: 480i */
2242                 else if(cr32 & SIS_VB_HIVISION)  ivideo->vbflags |= TV_HIVISION;
2243                 else if(cr32 & SIS_VB_SCART)     ivideo->vbflags |= TV_SCART;
2244                 else {
2245                         if(cr32 & SIS_VB_SVIDEO)    ivideo->vbflags |= TV_SVIDEO;
2246                         if(cr32 & SIS_VB_COMPOSITE) ivideo->vbflags |= TV_AVIDEO;
2247                 }
2248         }
2249
2250         if(!(ivideo->vbflags & (TV_YPBPR | TV_HIVISION))) {
2251             if(ivideo->sisfb_tvstd != -1) {
2252                ivideo->vbflags &= ~(TV_NTSC | TV_PAL | TV_PALM | TV_PALN | TV_NTSCJ);
2253                ivideo->vbflags |= ivideo->sisfb_tvstd;
2254             }
2255             if(ivideo->vbflags & TV_SCART) {
2256                ivideo->vbflags &= ~(TV_NTSC | TV_PALM | TV_PALN | TV_NTSCJ);
2257                ivideo->vbflags |= TV_PAL;
2258             }
2259             if(!(ivideo->vbflags & (TV_PAL | TV_NTSC | TV_PALM | TV_PALN | TV_NTSCJ))) {
2260                 if(ivideo->sisvga_engine == SIS_300_VGA) {
2261                         inSISIDXREG(SISSR, 0x38, temp);
2262                         if(temp & 0x01) ivideo->vbflags |= TV_PAL;
2263                         else            ivideo->vbflags |= TV_NTSC;
2264                 } else if((ivideo->chip <= SIS_315PRO) || (ivideo->chip >= SIS_330)) {
2265                         inSISIDXREG(SISSR, 0x38, temp);
2266                         if(temp & 0x01) ivideo->vbflags |= TV_PAL;
2267                         else            ivideo->vbflags |= TV_NTSC;
2268                 } else {
2269                         inSISIDXREG(SISCR, 0x79, temp);
2270                         if(temp & 0x20) ivideo->vbflags |= TV_PAL;
2271                         else            ivideo->vbflags |= TV_NTSC;
2272                 }
2273             }
2274         }
2275
2276         /* Copy forceCRT1 option to CRT1off if option is given */
2277         if(ivideo->sisfb_forcecrt1 != -1) {
2278            ivideo->sisfb_crt1off = (ivideo->sisfb_forcecrt1) ? 0 : 1;
2279         }
2280 }
2281
2282 /* ------------------ Sensing routines ------------------ */
2283
2284 static BOOLEAN __devinit
2285 sisfb_test_DDC1(struct sis_video_info *ivideo)
2286 {
2287     unsigned short old;
2288     int count = 48;
2289
2290     old = SiS_ReadDDC1Bit(&ivideo->SiS_Pr);
2291     do {
2292         if(old != SiS_ReadDDC1Bit(&ivideo->SiS_Pr)) break;
2293     } while(count--);
2294     return (count == -1) ? FALSE : TRUE;
2295 }
2296
2297 static void __devinit
2298 sisfb_sense_crt1(struct sis_video_info *ivideo)
2299 {
2300     BOOLEAN mustwait = FALSE;
2301     u8  sr1F, cr17;
2302 #ifdef CONFIG_FB_SIS_315
2303     u8  cr63=0;
2304 #endif
2305     u16 temp = 0xffff;
2306     int i;
2307
2308     inSISIDXREG(SISSR,0x1F,sr1F);
2309     orSISIDXREG(SISSR,0x1F,0x04);
2310     andSISIDXREG(SISSR,0x1F,0x3F);
2311     if(sr1F & 0xc0) mustwait = TRUE;
2312
2313 #ifdef CONFIG_FB_SIS_315
2314     if(ivideo->sisvga_engine == SIS_315_VGA) {
2315        inSISIDXREG(SISCR,ivideo->SiS_Pr.SiS_MyCR63,cr63);
2316        cr63 &= 0x40;
2317        andSISIDXREG(SISCR,ivideo->SiS_Pr.SiS_MyCR63,0xBF);
2318     }
2319 #endif
2320
2321     inSISIDXREG(SISCR,0x17,cr17);
2322     cr17 &= 0x80;
2323     if(!cr17) {
2324        orSISIDXREG(SISCR,0x17,0x80);
2325        mustwait = TRUE;
2326        outSISIDXREG(SISSR, 0x00, 0x01);
2327        outSISIDXREG(SISSR, 0x00, 0x03);
2328     }
2329
2330     if(mustwait) {
2331        for(i=0; i < 10; i++) sisfbwaitretracecrt1(ivideo);
2332     }
2333
2334 #ifdef CONFIG_FB_SIS_315
2335     if(ivideo->chip >= SIS_330) {
2336        andSISIDXREG(SISCR,0x32,~0x20);
2337        if(ivideo->chip >= SIS_340) {
2338           outSISIDXREG(SISCR, 0x57, 0x4a);
2339        } else {
2340           outSISIDXREG(SISCR, 0x57, 0x5f);
2341        }
2342        orSISIDXREG(SISCR, 0x53, 0x02);
2343        while((inSISREG(SISINPSTAT)) & 0x01)    break;
2344        while(!((inSISREG(SISINPSTAT)) & 0x01)) break;
2345        if((inSISREG(SISMISCW)) & 0x10) temp = 1;
2346        andSISIDXREG(SISCR, 0x53, 0xfd);
2347        andSISIDXREG(SISCR, 0x57, 0x00);
2348     }
2349 #endif
2350
2351     if(temp == 0xffff) {
2352        i = 3;
2353        do {
2354           temp = SiS_HandleDDC(&ivideo->SiS_Pr, ivideo->vbflags,
2355                 ivideo->sisvga_engine, 0, 0, NULL, ivideo->vbflags2);
2356        } while(((temp == 0) || (temp == 0xffff)) && i--);
2357
2358        if((temp == 0) || (temp == 0xffff)) {
2359           if(sisfb_test_DDC1(ivideo)) temp = 1;
2360        }
2361     }
2362
2363     if((temp) && (temp != 0xffff)) {
2364        orSISIDXREG(SISCR,0x32,0x20);
2365     }
2366
2367 #ifdef CONFIG_FB_SIS_315
2368     if(ivideo->sisvga_engine == SIS_315_VGA) {
2369        setSISIDXREG(SISCR,ivideo->SiS_Pr.SiS_MyCR63,0xBF,cr63);
2370     }
2371 #endif
2372
2373     setSISIDXREG(SISCR,0x17,0x7F,cr17);
2374
2375     outSISIDXREG(SISSR,0x1F,sr1F);
2376 }
2377
2378 /* Determine and detect attached devices on SiS30x */
2379 static void __devinit
2380 SiS_SenseLCD(struct sis_video_info *ivideo)
2381 {
2382         unsigned char buffer[256];
2383         unsigned short temp, realcrtno, i;
2384         u8 reg, cr37 = 0, paneltype = 0;
2385         u16 xres, yres;
2386
2387         ivideo->SiS_Pr.PanelSelfDetected = FALSE;
2388
2389         /* LCD detection only for TMDS bridges */
2390         if(!(ivideo->vbflags2 & VB2_SISTMDSBRIDGE))
2391                 return;
2392         if(ivideo->vbflags2 & VB2_30xBDH)
2393                 return;
2394
2395         /* If LCD already set up by BIOS, skip it */
2396         inSISIDXREG(SISCR, 0x32, reg);
2397         if(reg & 0x08)
2398                 return;
2399
2400         realcrtno = 1;
2401         if(ivideo->SiS_Pr.DDCPortMixup)
2402                 realcrtno = 0;
2403
2404         /* Check DDC capabilities */
2405         temp = SiS_HandleDDC(&ivideo->SiS_Pr, ivideo->vbflags, ivideo->sisvga_engine,
2406                                 realcrtno, 0, &buffer[0], ivideo->vbflags2);
2407
2408         if((!temp) || (temp == 0xffff) || (!(temp & 0x02)))
2409                 return;
2410
2411         /* Read DDC data */
2412         i = 3;  /* Number of retrys */
2413         do {
2414                 temp = SiS_HandleDDC(&ivideo->SiS_Pr, ivideo->vbflags,
2415                                 ivideo->sisvga_engine, realcrtno, 1,
2416                                 &buffer[0], ivideo->vbflags2);
2417         } while((temp) && i--);
2418
2419         if(temp)
2420                 return;
2421
2422         /* No digital device */
2423         if(!(buffer[0x14] & 0x80))
2424                 return;
2425
2426         /* First detailed timing preferred timing? */
2427         if(!(buffer[0x18] & 0x02))
2428                 return;
2429
2430         xres = buffer[0x38] | ((buffer[0x3a] & 0xf0) << 4);
2431         yres = buffer[0x3b] | ((buffer[0x3d] & 0xf0) << 4);
2432
2433         switch(xres) {
2434                 case 1024:
2435                         if(yres == 768)
2436                                 paneltype = 0x02;
2437                         break;
2438                 case 1280:
2439                         if(yres == 1024)
2440                                 paneltype = 0x03;
2441                         break;
2442                 case 1600:
2443                         if((yres == 1200) && (ivideo->vbflags2 & VB2_30xC))
2444                                 paneltype = 0x0b;
2445                         break;
2446         }
2447
2448         if(!paneltype)
2449                 return;
2450
2451         if(buffer[0x23])
2452                 cr37 |= 0x10;
2453
2454         if((buffer[0x47] & 0x18) == 0x18)
2455                 cr37 |= ((((buffer[0x47] & 0x06) ^ 0x06) << 5) | 0x20);
2456         else
2457                 cr37 |= 0xc0;
2458
2459         outSISIDXREG(SISCR, 0x36, paneltype);
2460         cr37 &= 0xf1;
2461         setSISIDXREG(SISCR, 0x37, 0x0c, cr37);
2462         orSISIDXREG(SISCR, 0x32, 0x08);
2463
2464         ivideo->SiS_Pr.PanelSelfDetected = TRUE;
2465 }
2466
2467 static int __devinit
2468 SISDoSense(struct sis_video_info *ivideo, u16 type, u16 test)
2469 {
2470     int temp, mytest, result, i, j;
2471
2472     for(j = 0; j < 10; j++) {
2473        result = 0;
2474        for(i = 0; i < 3; i++) {
2475           mytest = test;
2476           outSISIDXREG(SISPART4,0x11,(type & 0x00ff));
2477           temp = (type >> 8) | (mytest & 0x00ff);
2478           setSISIDXREG(SISPART4,0x10,0xe0,temp);
2479           SiS_DDC2Delay(&ivideo->SiS_Pr, 0x1500);
2480           mytest >>= 8;
2481           mytest &= 0x7f;
2482           inSISIDXREG(SISPART4,0x03,temp);
2483           temp ^= 0x0e;
2484           temp &= mytest;
2485           if(temp == mytest) result++;
2486 #if 1
2487           outSISIDXREG(SISPART4,0x11,0x00);
2488           andSISIDXREG(SISPART4,0x10,0xe0);
2489           SiS_DDC2Delay(&ivideo->SiS_Pr, 0x1000);
2490 #endif
2491        }
2492        if((result == 0) || (result >= 2)) break;
2493     }
2494     return result;
2495 }
2496
2497 static void __devinit
2498 SiS_Sense30x(struct sis_video_info *ivideo)
2499 {
2500     u8  backupP4_0d,backupP2_00,backupP2_4d,backupSR_1e,biosflag=0;
2501     u16 svhs=0, svhs_c=0;
2502     u16 cvbs=0, cvbs_c=0;
2503     u16 vga2=0, vga2_c=0;
2504     int myflag, result;
2505     char stdstr[] = "sisfb: Detected";
2506     char tvstr[]  = "TV connected to";
2507
2508     if(ivideo->vbflags2 & VB2_301) {
2509        svhs = 0x00b9; cvbs = 0x00b3; vga2 = 0x00d1;
2510        inSISIDXREG(SISPART4,0x01,myflag);
2511        if(myflag & 0x04) {
2512           svhs = 0x00dd; cvbs = 0x00ee; vga2 = 0x00fd;
2513        }
2514     } else if(ivideo->vbflags2 & (VB2_301B | VB2_302B)) {
2515        svhs = 0x016b; cvbs = 0x0174; vga2 = 0x0190;
2516     } else if(ivideo->vbflags2 & (VB2_301LV | VB2_302LV)) {
2517        svhs = 0x0200; cvbs = 0x0100;
2518     } else if(ivideo->vbflags2 & (VB2_301C | VB2_302ELV | VB2_307T | VB2_307LV)) {
2519        svhs = 0x016b; cvbs = 0x0110; vga2 = 0x0190;
2520     } else
2521        return;
2522
2523     vga2_c = 0x0e08; svhs_c = 0x0404; cvbs_c = 0x0804;
2524     if(ivideo->vbflags & (VB2_301LV|VB2_302LV|VB2_302ELV|VB2_307LV)) {
2525        svhs_c = 0x0408; cvbs_c = 0x0808;
2526     }
2527
2528     biosflag = 2;
2529     if(ivideo->haveXGIROM) {
2530        biosflag = ivideo->bios_abase[0x58] & 0x03;
2531     } else if(ivideo->newrom) {
2532        if(ivideo->bios_abase[0x5d] & 0x04) biosflag |= 0x01;
2533     } else if(ivideo->sisvga_engine == SIS_300_VGA) {
2534        if(ivideo->bios_abase) {
2535           biosflag = ivideo->bios_abase[0xfe] & 0x03;
2536        }
2537     }
2538
2539     if(ivideo->chip == SIS_300) {
2540        inSISIDXREG(SISSR,0x3b,myflag);
2541        if(!(myflag & 0x01)) vga2 = vga2_c = 0;
2542     }
2543
2544     if(!(ivideo->vbflags2 & VB2_SISVGA2BRIDGE)) {
2545        vga2 = vga2_c = 0;
2546     }
2547
2548     inSISIDXREG(SISSR,0x1e,backupSR_1e);
2549     orSISIDXREG(SISSR,0x1e,0x20);
2550
2551     inSISIDXREG(SISPART4,0x0d,backupP4_0d);
2552     if(ivideo->vbflags2 & VB2_30xC) {
2553        setSISIDXREG(SISPART4,0x0d,~0x07,0x01);
2554     } else {
2555        orSISIDXREG(SISPART4,0x0d,0x04);
2556     }
2557     SiS_DDC2Delay(&ivideo->SiS_Pr, 0x2000);
2558
2559     inSISIDXREG(SISPART2,0x00,backupP2_00);
2560     outSISIDXREG(SISPART2,0x00,((backupP2_00 | 0x1c) & 0xfc));
2561
2562     inSISIDXREG(SISPART2,0x4d,backupP2_4d);
2563     if(ivideo->vbflags2 & VB2_SISYPBPRBRIDGE) {
2564        outSISIDXREG(SISPART2,0x4d,(backupP2_4d & ~0x10));
2565     }
2566
2567     if(!(ivideo->vbflags2 & VB2_30xCLV)) {
2568        SISDoSense(ivideo, 0, 0);
2569     }
2570
2571     andSISIDXREG(SISCR, 0x32, ~0x14);
2572
2573     if(vga2_c || vga2) {
2574        if(SISDoSense(ivideo, vga2, vga2_c)) {
2575           if(biosflag & 0x01) {
2576              printk(KERN_INFO "%s %s SCART output\n", stdstr, tvstr);
2577              orSISIDXREG(SISCR, 0x32, 0x04);
2578           } else {
2579              printk(KERN_INFO "%s secondary VGA connection\n", stdstr);
2580              orSISIDXREG(SISCR, 0x32, 0x10);
2581           }
2582        }
2583     }
2584
2585     andSISIDXREG(SISCR, 0x32, 0x3f);
2586
2587     if(ivideo->vbflags2 & VB2_30xCLV) {
2588        orSISIDXREG(SISPART4,0x0d,0x04);
2589     }
2590
2591     if((ivideo->sisvga_engine == SIS_315_VGA) && (ivideo->vbflags2 & VB2_SISYPBPRBRIDGE)) {
2592        outSISIDXREG(SISPART2,0x4d,(backupP2_4d | 0x10));
2593        SiS_DDC2Delay(&ivideo->SiS_Pr, 0x2000);
2594        if((result = SISDoSense(ivideo, svhs, 0x0604))) {
2595           if((result = SISDoSense(ivideo, cvbs, 0x0804))) {
2596              printk(KERN_INFO "%s %s YPbPr component output\n", stdstr, tvstr);
2597              orSISIDXREG(SISCR,0x32,0x80);
2598           }
2599        }
2600        outSISIDXREG(SISPART2,0x4d,backupP2_4d);
2601     }
2602
2603     andSISIDXREG(SISCR, 0x32, ~0x03);
2604
2605     if(!(ivideo->vbflags & TV_YPBPR)) {
2606        if((result = SISDoSense(ivideo, svhs, svhs_c))) {
2607           printk(KERN_INFO "%s %s SVIDEO output\n", stdstr, tvstr);
2608           orSISIDXREG(SISCR, 0x32, 0x02);
2609        }
2610        if((biosflag & 0x02) || (!result)) {
2611           if(SISDoSense(ivideo, cvbs, cvbs_c)) {
2612              printk(KERN_INFO "%s %s COMPOSITE output\n", stdstr, tvstr);
2613              orSISIDXREG(SISCR, 0x32, 0x01);
2614           }
2615        }
2616     }
2617
2618     SISDoSense(ivideo, 0, 0);
2619
2620     outSISIDXREG(SISPART2,0x00,backupP2_00);
2621     outSISIDXREG(SISPART4,0x0d,backupP4_0d);
2622     outSISIDXREG(SISSR,0x1e,backupSR_1e);
2623
2624     if(ivideo->vbflags2 & VB2_30xCLV) {
2625        inSISIDXREG(SISPART2,0x00,biosflag);
2626        if(biosflag & 0x20) {
2627           for(myflag = 2; myflag > 0; myflag--) {
2628              biosflag ^= 0x20;
2629              outSISIDXREG(SISPART2,0x00,biosflag);
2630           }
2631        }
2632     }
2633
2634     outSISIDXREG(SISPART2,0x00,backupP2_00);
2635 }
2636
2637 /* Determine and detect attached TV's on Chrontel */
2638 static void __devinit
2639 SiS_SenseCh(struct sis_video_info *ivideo)
2640 {
2641 #if defined(CONFIG_FB_SIS_300) || defined(CONFIG_FB_SIS_315)
2642     u8 temp1, temp2;
2643     char stdstr[] = "sisfb: Chrontel: Detected TV connected to";
2644 #endif
2645 #ifdef CONFIG_FB_SIS_300
2646     unsigned char test[3];
2647     int i;
2648 #endif
2649
2650     if(ivideo->chip < SIS_315H) {
2651
2652 #ifdef CONFIG_FB_SIS_300
2653        ivideo->SiS_Pr.SiS_IF_DEF_CH70xx = 1;            /* Chrontel 700x */
2654        SiS_SetChrontelGPIO(&ivideo->SiS_Pr, 0x9c);      /* Set general purpose IO for Chrontel communication */
2655        SiS_DDC2Delay(&ivideo->SiS_Pr, 1000);
2656        temp1 = SiS_GetCH700x(&ivideo->SiS_Pr, 0x25);
2657        /* See Chrontel TB31 for explanation */
2658        temp2 = SiS_GetCH700x(&ivideo->SiS_Pr, 0x0e);
2659        if(((temp2 & 0x07) == 0x01) || (temp2 & 0x04)) {
2660           SiS_SetCH700x(&ivideo->SiS_Pr, 0x0e, 0x0b);
2661           SiS_DDC2Delay(&ivideo->SiS_Pr, 300);
2662        }
2663        temp2 = SiS_GetCH700x(&ivideo->SiS_Pr, 0x25);
2664        if(temp2 != temp1) temp1 = temp2;
2665
2666        if((temp1 >= 0x22) && (temp1 <= 0x50)) {
2667            /* Read power status */
2668            temp1 = SiS_GetCH700x(&ivideo->SiS_Pr, 0x0e);
2669            if((temp1 & 0x03) != 0x03) {
2670                 /* Power all outputs */
2671                 SiS_SetCH700x(&ivideo->SiS_Pr, 0x0e,0x0b);
2672                 SiS_DDC2Delay(&ivideo->SiS_Pr, 300);
2673            }
2674            /* Sense connected TV devices */
2675            for(i = 0; i < 3; i++) {
2676                SiS_SetCH700x(&ivideo->SiS_Pr, 0x10, 0x01);
2677                SiS_DDC2Delay(&ivideo->SiS_Pr, 0x96);
2678                SiS_SetCH700x(&ivideo->SiS_Pr, 0x10, 0x00);
2679                SiS_DDC2Delay(&ivideo->SiS_Pr, 0x96);
2680                temp1 = SiS_GetCH700x(&ivideo->SiS_Pr, 0x10);
2681                if(!(temp1 & 0x08))       test[i] = 0x02;
2682                else if(!(temp1 & 0x02))  test[i] = 0x01;
2683                else                      test[i] = 0;
2684                SiS_DDC2Delay(&ivideo->SiS_Pr, 0x96);
2685            }
2686
2687            if(test[0] == test[1])      temp1 = test[0];
2688            else if(test[0] == test[2]) temp1 = test[0];
2689            else if(test[1] == test[2]) temp1 = test[1];
2690            else {
2691                 printk(KERN_INFO
2692                         "sisfb: TV detection unreliable - test results varied\n");
2693                 temp1 = test[2];
2694            }
2695            if(temp1 == 0x02) {
2696                 printk(KERN_INFO "%s SVIDEO output\n", stdstr);
2697                 ivideo->vbflags |= TV_SVIDEO;
2698                 orSISIDXREG(SISCR, 0x32, 0x02);
2699                 andSISIDXREG(SISCR, 0x32, ~0x05);
2700            } else if (temp1 == 0x01) {
2701                 printk(KERN_INFO "%s CVBS output\n", stdstr);
2702                 ivideo->vbflags |= TV_AVIDEO;
2703                 orSISIDXREG(SISCR, 0x32, 0x01);
2704                 andSISIDXREG(SISCR, 0x32, ~0x06);
2705            } else {
2706                 SiS_SetCH70xxANDOR(&ivideo->SiS_Pr, 0x0e, 0x01, 0xF8);
2707                 andSISIDXREG(SISCR, 0x32, ~0x07);
2708            }
2709        } else if(temp1 == 0) {
2710           SiS_SetCH70xxANDOR(&ivideo->SiS_Pr, 0x0e, 0x01, 0xF8);
2711           andSISIDXREG(SISCR, 0x32, ~0x07);
2712        }
2713        /* Set general purpose IO for Chrontel communication */
2714        SiS_SetChrontelGPIO(&ivideo->SiS_Pr, 0x00);
2715 #endif
2716
2717     } else {
2718
2719 #ifdef CONFIG_FB_SIS_315
2720         ivideo->SiS_Pr.SiS_IF_DEF_CH70xx = 2;           /* Chrontel 7019 */
2721         temp1 = SiS_GetCH701x(&ivideo->SiS_Pr, 0x49);
2722         SiS_SetCH701x(&ivideo->SiS_Pr, 0x49, 0x20);
2723         SiS_DDC2Delay(&ivideo->SiS_Pr, 0x96);
2724         temp2 = SiS_GetCH701x(&ivideo->SiS_Pr, 0x20);
2725         temp2 |= 0x01;
2726         SiS_SetCH701x(&ivideo->SiS_Pr, 0x20, temp2);
2727         SiS_DDC2Delay(&ivideo->SiS_Pr, 0x96);
2728         temp2 ^= 0x01;
2729         SiS_SetCH701x(&ivideo->SiS_Pr, 0x20, temp2);
2730         SiS_DDC2Delay(&ivideo->SiS_Pr, 0x96);
2731         temp2 = SiS_GetCH701x(&ivideo->SiS_Pr, 0x20);
2732         SiS_SetCH701x(&ivideo->SiS_Pr, 0x49, temp1);
2733         temp1 = 0;
2734         if(temp2 & 0x02) temp1 |= 0x01;
2735         if(temp2 & 0x10) temp1 |= 0x01;
2736         if(temp2 & 0x04) temp1 |= 0x02;
2737         if( (temp1 & 0x01) && (temp1 & 0x02) ) temp1 = 0x04;
2738         switch(temp1) {
2739         case 0x01:
2740              printk(KERN_INFO "%s CVBS output\n", stdstr);
2741              ivideo->vbflags |= TV_AVIDEO;
2742              orSISIDXREG(SISCR, 0x32, 0x01);
2743              andSISIDXREG(SISCR, 0x32, ~0x06);
2744              break;
2745         case 0x02:
2746              printk(KERN_INFO "%s SVIDEO output\n", stdstr);
2747              ivideo->vbflags |= TV_SVIDEO;
2748              orSISIDXREG(SISCR, 0x32, 0x02);
2749              andSISIDXREG(SISCR, 0x32, ~0x05);
2750              break;
2751         case 0x04:
2752              printk(KERN_INFO "%s SCART output\n", stdstr);
2753              orSISIDXREG(SISCR, 0x32, 0x04);
2754              andSISIDXREG(SISCR, 0x32, ~0x03);
2755              break;
2756         default:
2757              andSISIDXREG(SISCR, 0x32, ~0x07);
2758         }
2759 #endif
2760     }
2761 }
2762
2763 static void __devinit
2764 sisfb_get_VB_type(struct sis_video_info *ivideo)
2765 {
2766         char stdstr[]    = "sisfb: Detected";
2767         char bridgestr[] = "video bridge";
2768         u8 vb_chipid;
2769         u8 reg;
2770
2771         /* No CRT2 on XGI Z7 */
2772         if(ivideo->chip == XGI_20)
2773                 return;
2774
2775         inSISIDXREG(SISPART4, 0x00, vb_chipid);
2776         switch(vb_chipid) {
2777         case 0x01:
2778                 inSISIDXREG(SISPART4, 0x01, reg);
2779                 if(reg < 0xb0) {
2780                         ivideo->vbflags |= VB_301;      /* Deprecated */
2781                         ivideo->vbflags2 |= VB2_301;
2782                         printk(KERN_INFO "%s SiS301 %s\n", stdstr, bridgestr);
2783                 } else if(reg < 0xc0) {
2784                         ivideo->vbflags |= VB_301B;     /* Deprecated */
2785                         ivideo->vbflags2 |= VB2_301B;
2786                         inSISIDXREG(SISPART4,0x23,reg);
2787                         if(!(reg & 0x02)) {
2788                            ivideo->vbflags |= VB_30xBDH;        /* Deprecated */
2789                            ivideo->vbflags2 |= VB2_30xBDH;
2790                            printk(KERN_INFO "%s SiS301B-DH %s\n", stdstr, bridgestr);
2791                         } else {
2792                            printk(KERN_INFO "%s SiS301B %s\n", stdstr, bridgestr);
2793                         }
2794                 } else if(reg < 0xd0) {
2795                         ivideo->vbflags |= VB_301C;     /* Deprecated */
2796                         ivideo->vbflags2 |= VB2_301C;
2797                         printk(KERN_INFO "%s SiS301C %s\n", stdstr, bridgestr);
2798                 } else if(reg < 0xe0) {
2799                         ivideo->vbflags |= VB_301LV;    /* Deprecated */
2800                         ivideo->vbflags2 |= VB2_301LV;
2801                         printk(KERN_INFO "%s SiS301LV %s\n", stdstr, bridgestr);
2802                 } else if(reg <= 0xe1) {
2803                         inSISIDXREG(SISPART4,0x39,reg);
2804                         if(reg == 0xff) {
2805                            ivideo->vbflags |= VB_302LV; /* Deprecated */
2806                            ivideo->vbflags2 |= VB2_302LV;
2807                            printk(KERN_INFO "%s SiS302LV %s\n", stdstr, bridgestr);
2808                         } else {
2809                            ivideo->vbflags |= VB_301C;  /* Deprecated */
2810                            ivideo->vbflags2 |= VB2_301C;
2811                            printk(KERN_INFO "%s SiS301C(P4) %s\n", stdstr, bridgestr);
2812 #if 0
2813                            ivideo->vbflags |= VB_302ELV;        /* Deprecated */
2814                            ivideo->vbflags2 |= VB2_302ELV;
2815                            printk(KERN_INFO "%s SiS302ELV %s\n", stdstr, bridgestr);
2816 #endif
2817                         }
2818                 }
2819                 break;
2820         case 0x02:
2821                 ivideo->vbflags |= VB_302B;     /* Deprecated */
2822                 ivideo->vbflags2 |= VB2_302B;
2823                 printk(KERN_INFO "%s SiS302B %s\n", stdstr, bridgestr);
2824                 break;
2825         }
2826
2827         if((!(ivideo->vbflags2 & VB2_VIDEOBRIDGE)) && (ivideo->chip != SIS_300)) {
2828                 inSISIDXREG(SISCR, 0x37, reg);
2829                 reg &= SIS_EXTERNAL_CHIP_MASK;
2830                 reg >>= 1;
2831                 if(ivideo->sisvga_engine == SIS_300_VGA) {
2832 #ifdef CONFIG_FB_SIS_300
2833                         switch(reg) {
2834                            case SIS_EXTERNAL_CHIP_LVDS:
2835                                 ivideo->vbflags |= VB_LVDS;     /* Deprecated */
2836                                 ivideo->vbflags2 |= VB2_LVDS;
2837                                 break;
2838                            case SIS_EXTERNAL_CHIP_TRUMPION:
2839                                 ivideo->vbflags |= (VB_LVDS | VB_TRUMPION);     /* Deprecated */
2840                                 ivideo->vbflags2 |= (VB2_LVDS | VB2_TRUMPION);
2841                                 break;
2842                            case SIS_EXTERNAL_CHIP_CHRONTEL:
2843                                 ivideo->vbflags |= VB_CHRONTEL; /* Deprecated */
2844                                 ivideo->vbflags2 |= VB2_CHRONTEL;
2845                                 break;
2846                            case SIS_EXTERNAL_CHIP_LVDS_CHRONTEL:
2847                                 ivideo->vbflags |= (VB_LVDS | VB_CHRONTEL);     /* Deprecated */
2848                                 ivideo->vbflags2 |= (VB2_LVDS | VB2_CHRONTEL);
2849                                 break;
2850                         }
2851                         if(ivideo->vbflags2 & VB2_CHRONTEL) ivideo->chronteltype = 1;
2852 #endif
2853                 } else if(ivideo->chip < SIS_661) {
2854 #ifdef CONFIG_FB_SIS_315
2855                         switch (reg) {
2856                            case SIS310_EXTERNAL_CHIP_LVDS:
2857                                 ivideo->vbflags |= VB_LVDS;     /* Deprecated */
2858                                 ivideo->vbflags2 |= VB2_LVDS;
2859                                 break;
2860                            case SIS310_EXTERNAL_CHIP_LVDS_CHRONTEL:
2861                                 ivideo->vbflags |= (VB_LVDS | VB_CHRONTEL);     /* Deprecated */
2862                                 ivideo->vbflags2 |= (VB2_LVDS | VB2_CHRONTEL);
2863                                 break;
2864                         }
2865                         if(ivideo->vbflags2 & VB2_CHRONTEL) ivideo->chronteltype = 2;
2866 #endif
2867                 } else if(ivideo->chip >= SIS_661) {
2868 #ifdef CONFIG_FB_SIS_315
2869                         inSISIDXREG(SISCR, 0x38, reg);
2870                         reg >>= 5;
2871                         switch(reg) {
2872                            case 0x02:
2873                                 ivideo->vbflags |= VB_LVDS;     /* Deprecated */
2874                                 ivideo->vbflags2 |= VB2_LVDS;
2875                                 break;
2876                            case 0x03:
2877                                 ivideo->vbflags |= (VB_LVDS | VB_CHRONTEL);     /* Deprecated */
2878                                 ivideo->vbflags2 |= (VB2_LVDS | VB2_CHRONTEL);
2879                                 break;
2880                            case 0x04:
2881                                 ivideo->vbflags |= (VB_LVDS | VB_CONEXANT);     /* Deprecated */
2882                                 ivideo->vbflags2 |= (VB2_LVDS | VB2_CONEXANT);
2883                                 break;
2884                         }
2885                         if(ivideo->vbflags2 & VB2_CHRONTEL) ivideo->chronteltype = 2;
2886 #endif
2887                 }
2888                 if(ivideo->vbflags2 & VB2_LVDS) {
2889                    printk(KERN_INFO "%s LVDS transmitter\n", stdstr);
2890                 }
2891                 if((ivideo->sisvga_engine == SIS_300_VGA) && (ivideo->vbflags2 & VB2_TRUMPION)) {
2892                    printk(KERN_INFO "%s Trumpion Zurac LCD scaler\n", stdstr);
2893                 }
2894                 if(ivideo->vbflags2 & VB2_CHRONTEL) {
2895                    printk(KERN_INFO "%s Chrontel TV encoder\n", stdstr);
2896                 }
2897                 if((ivideo->chip >= SIS_661) && (ivideo->vbflags2 & VB2_CONEXANT)) {
2898                    printk(KERN_INFO "%s Conexant external device\n", stdstr);
2899                 }
2900         }
2901
2902         if(ivideo->vbflags2 & VB2_SISBRIDGE) {
2903                 SiS_SenseLCD(ivideo);
2904                 SiS_Sense30x(ivideo);
2905         } else if(ivideo->vbflags2 & VB2_CHRONTEL) {
2906                 SiS_SenseCh(ivideo);
2907         }
2908 }
2909
2910 /* ---------- Engine initialization routines ------------ */
2911
2912 static void
2913 sisfb_engine_init(struct sis_video_info *ivideo)
2914 {
2915
2916         /* Initialize command queue (we use MMIO only) */
2917
2918         /* BEFORE THIS IS CALLED, THE ENGINES *MUST* BE SYNC'ED */
2919
2920         ivideo->caps &= ~(TURBO_QUEUE_CAP    |
2921                           MMIO_CMD_QUEUE_CAP |
2922                           VM_CMD_QUEUE_CAP   |
2923                           AGP_CMD_QUEUE_CAP);
2924
2925 #ifdef CONFIG_FB_SIS_300
2926         if(ivideo->sisvga_engine == SIS_300_VGA) {
2927                 u32 tqueue_pos;
2928                 u8 tq_state;
2929
2930                 tqueue_pos = (ivideo->video_size - ivideo->cmdQueueSize) / (64 * 1024);
2931
2932                 inSISIDXREG(SISSR, IND_SIS_TURBOQUEUE_SET, tq_state);
2933                 tq_state |= 0xf0;
2934                 tq_state &= 0xfc;
2935                 tq_state |= (u8)(tqueue_pos >> 8);
2936                 outSISIDXREG(SISSR, IND_SIS_TURBOQUEUE_SET, tq_state);
2937
2938                 outSISIDXREG(SISSR, IND_SIS_TURBOQUEUE_ADR, (u8)(tqueue_pos & 0xff));
2939
2940                 ivideo->caps |= TURBO_QUEUE_CAP;
2941         }
2942 #endif
2943
2944 #ifdef CONFIG_FB_SIS_315
2945         if(ivideo->sisvga_engine == SIS_315_VGA) {
2946                 u32 tempq = 0, templ;
2947                 u8  temp;
2948
2949                 if(ivideo->chip == XGI_20) {
2950                         switch(ivideo->cmdQueueSize) {
2951                         case (64 * 1024):
2952                                 temp = SIS_CMD_QUEUE_SIZE_Z7_64k;
2953                                 break;
2954                         case (128 * 1024):
2955                         default:
2956                                 temp = SIS_CMD_QUEUE_SIZE_Z7_128k;
2957                         }
2958                 } else {
2959                         switch(ivideo->cmdQueueSize) {
2960                         case (4 * 1024 * 1024):
2961                                 temp = SIS_CMD_QUEUE_SIZE_4M;
2962                                 break;
2963                         case (2 * 1024 * 1024):
2964                                 temp = SIS_CMD_QUEUE_SIZE_2M;
2965                                 break;
2966                         case (1 * 1024 * 1024):
2967                                 temp = SIS_CMD_QUEUE_SIZE_1M;
2968                                 break;
2969                         default:
2970                         case (512 * 1024):
2971                                 temp = SIS_CMD_QUEUE_SIZE_512k;
2972                         }
2973                 }
2974
2975                 outSISIDXREG(SISSR, IND_SIS_CMDQUEUE_THRESHOLD, COMMAND_QUEUE_THRESHOLD);
2976                 outSISIDXREG(SISSR, IND_SIS_CMDQUEUE_SET, SIS_CMD_QUEUE_RESET);
2977
2978                 if((ivideo->chip >= XGI_40) && ivideo->modechanged) {
2979                         /* Must disable dual pipe on XGI_40. Can't do
2980                          * this in MMIO mode, because it requires
2981                          * setting/clearing a bit in the MMIO fire trigger
2982                          * register.
2983                          */
2984                         if(!((templ = MMIO_IN32(ivideo->mmio_vbase, 0x8240)) & (1 << 10))) {
2985
2986                                 MMIO_OUT32(ivideo->mmio_vbase, Q_WRITE_PTR, 0);
2987
2988                                 outSISIDXREG(SISSR, IND_SIS_CMDQUEUE_SET, (temp | SIS_VRAM_CMDQUEUE_ENABLE));
2989
2990                                 tempq = MMIO_IN32(ivideo->mmio_vbase, Q_READ_PTR);
2991                                 MMIO_OUT32(ivideo->mmio_vbase, Q_WRITE_PTR, tempq);
2992
2993                                 tempq = (u32)(ivideo->video_size - ivideo->cmdQueueSize);
2994                                 MMIO_OUT32(ivideo->mmio_vbase, Q_BASE_ADDR, tempq);
2995
2996                                 writel(0x16800000 + 0x8240, ivideo->video_vbase + tempq);
2997                                 writel(templ | (1 << 10), ivideo->video_vbase + tempq + 4);
2998                                 writel(0x168F0000, ivideo->video_vbase + tempq + 8);
2999                                 writel(0x168F0000, ivideo->video_vbase + tempq + 12);
3000
3001                                 MMIO_OUT32(ivideo->mmio_vbase, Q_WRITE_PTR, (tempq + 16));
3002
3003                                 sisfb_syncaccel(ivideo);
3004
3005                                 outSISIDXREG(SISSR, IND_SIS_CMDQUEUE_SET, SIS_CMD_QUEUE_RESET);
3006
3007                         }
3008                 }
3009
3010                 tempq = MMIO_IN32(ivideo->mmio_vbase, MMIO_QUEUE_READPORT);
3011                 MMIO_OUT32(ivideo->mmio_vbase, MMIO_QUEUE_WRITEPORT, tempq);
3012
3013                 temp |= (SIS_MMIO_CMD_ENABLE | SIS_CMD_AUTO_CORR);
3014                 outSISIDXREG(SISSR, IND_SIS_CMDQUEUE_SET, temp);
3015
3016                 tempq = (u32)(ivideo->video_size - ivideo->cmdQueueSize);
3017                 MMIO_OUT32(ivideo->mmio_vbase, MMIO_QUEUE_PHYBASE, tempq);
3018
3019                 ivideo->caps |= MMIO_CMD_QUEUE_CAP;
3020         }
3021 #endif
3022
3023         ivideo->engineok = 1;
3024 }
3025
3026 static void __devinit
3027 sisfb_detect_lcd_type(struct sis_video_info *ivideo)
3028 {
3029         u8 reg;
3030         int i;
3031
3032         inSISIDXREG(SISCR, 0x36, reg);
3033         reg &= 0x0f;
3034         if(ivideo->sisvga_engine == SIS_300_VGA) {
3035                 ivideo->CRT2LCDType = sis300paneltype[reg];
3036         } else if(ivideo->chip >= SIS_661) {
3037                 ivideo->CRT2LCDType = sis661paneltype[reg];
3038         } else {
3039                 ivideo->CRT2LCDType = sis310paneltype[reg];
3040                 if((ivideo->chip == SIS_550) && (sisfb_fstn)) {
3041                         if((ivideo->CRT2LCDType != LCD_320x240_2) &&
3042                            (ivideo->CRT2LCDType != LCD_320x240_3)) {
3043                                 ivideo->CRT2LCDType = LCD_320x240;
3044                         }
3045                 }
3046         }
3047
3048         if(ivideo->CRT2LCDType == LCD_UNKNOWN) {
3049                 /* For broken BIOSes: Assume 1024x768, RGB18 */
3050                 ivideo->CRT2LCDType = LCD_1024x768;
3051                 setSISIDXREG(SISCR,0x36,0xf0,0x02);
3052                 setSISIDXREG(SISCR,0x37,0xee,0x01);
3053                 printk(KERN_DEBUG "sisfb: Invalid panel ID (%02x), assuming 1024x768, RGB18\n", reg);
3054         }
3055
3056         for(i = 0; i < SIS_LCD_NUMBER; i++) {
3057                 if(ivideo->CRT2LCDType == sis_lcd_data[i].lcdtype) {
3058                         ivideo->lcdxres = sis_lcd_data[i].xres;
3059                         ivideo->lcdyres = sis_lcd_data[i].yres;
3060                         ivideo->lcddefmodeidx = sis_lcd_data[i].default_mode_idx;
3061                         break;
3062                 }
3063         }
3064
3065 #ifdef CONFIG_FB_SIS_300
3066         if(ivideo->SiS_Pr.SiS_CustomT == CUT_BARCO1366) {
3067                 ivideo->lcdxres = 1360; ivideo->lcdyres = 1024;
3068                 ivideo->lcddefmodeidx = DEFAULT_MODE_1360;
3069         } else if(ivideo->SiS_Pr.SiS_CustomT == CUT_PANEL848) {
3070                 ivideo->lcdxres =  848; ivideo->lcdyres =  480;
3071                 ivideo->lcddefmodeidx = DEFAULT_MODE_848;
3072         } else if(ivideo->SiS_Pr.SiS_CustomT == CUT_PANEL856) {
3073                 ivideo->lcdxres =  856; ivideo->lcdyres =  480;
3074                 ivideo->lcddefmodeidx = DEFAULT_MODE_856;
3075         }
3076 #endif
3077
3078         printk(KERN_DEBUG "sisfb: Detected %dx%d flat panel\n",
3079                         ivideo->lcdxres, ivideo->lcdyres);
3080 }
3081
3082 static void __devinit
3083 sisfb_save_pdc_emi(struct sis_video_info *ivideo)
3084 {
3085 #ifdef CONFIG_FB_SIS_300
3086         /* Save the current PanelDelayCompensation if the LCD is currently used */
3087         if(ivideo->sisvga_engine == SIS_300_VGA) {
3088                 if(ivideo->vbflags2 & (VB2_LVDS | VB2_30xBDH)) {
3089                         int tmp;
3090                         inSISIDXREG(SISCR,0x30,tmp);
3091                         if(tmp & 0x20) {
3092                                 /* Currently on LCD? If yes, read current pdc */
3093                                 inSISIDXREG(SISPART1,0x13,ivideo->detectedpdc);
3094                                 ivideo->detectedpdc &= 0x3c;
3095                                 if(ivideo->SiS_Pr.PDC == -1) {
3096                                         /* Let option override detection */
3097                                         ivideo->SiS_Pr.PDC = ivideo->detectedpdc;
3098                                 }
3099                                 printk(KERN_INFO "sisfb: Detected LCD PDC 0x%02x\n",
3100                                         ivideo->detectedpdc);
3101                         }
3102                         if((ivideo->SiS_Pr.PDC != -1) &&
3103                            (ivideo->SiS_Pr.PDC != ivideo->detectedpdc)) {
3104                                 printk(KERN_INFO "sisfb: Using LCD PDC 0x%02x\n",
3105                                         ivideo->SiS_Pr.PDC);
3106                         }
3107                 }
3108         }
3109 #endif
3110
3111 #ifdef CONFIG_FB_SIS_315
3112         if(ivideo->sisvga_engine == SIS_315_VGA) {
3113
3114                 /* Try to find about LCDA */
3115                 if(ivideo->vbflags2 & VB2_SISLCDABRIDGE) {
3116                         int tmp;
3117                         inSISIDXREG(SISPART1,0x13,tmp);
3118                         if(tmp & 0x04) {
3119                                 ivideo->SiS_Pr.SiS_UseLCDA = TRUE;
3120                                 ivideo->detectedlcda = 0x03;
3121                         }
3122                 }
3123
3124                 /* Save PDC */
3125                 if(ivideo->vbflags2 & VB2_SISLVDSBRIDGE) {
3126                         int tmp;
3127                         inSISIDXREG(SISCR,0x30,tmp);
3128                         if((tmp & 0x20) || (ivideo->detectedlcda != 0xff)) {
3129                                 /* Currently on LCD? If yes, read current pdc */
3130                                 u8 pdc;
3131                                 inSISIDXREG(SISPART1,0x2D,pdc);
3132                                 ivideo->detectedpdc  = (pdc & 0x0f) << 1;
3133                                 ivideo->detectedpdca = (pdc & 0xf0) >> 3;
3134                                 inSISIDXREG(SISPART1,0x35,pdc);
3135                                 ivideo->detectedpdc |= ((pdc >> 7) & 0x01);
3136                                 inSISIDXREG(SISPART1,0x20,pdc);
3137                                 ivideo->detectedpdca |= ((pdc >> 6) & 0x01);
3138                                 if(ivideo->newrom) {
3139                                         /* New ROM invalidates other PDC resp. */
3140                                         if(ivideo->detectedlcda != 0xff) {
3141                                                 ivideo->detectedpdc = 0xff;
3142                                         } else {
3143                                                 ivideo->detectedpdca = 0xff;
3144                                         }
3145                                 }
3146                                 if(ivideo->SiS_Pr.PDC == -1) {
3147                                         if(ivideo->detectedpdc != 0xff) {
3148                                                 ivideo->SiS_Pr.PDC = ivideo->detectedpdc;
3149                                         }
3150                                 }
3151                                 if(ivideo->SiS_Pr.PDCA == -1) {
3152                                         if(ivideo->detectedpdca != 0xff) {
3153                                                 ivideo->SiS_Pr.PDCA = ivideo->detectedpdca;
3154                                         }
3155                                 }
3156                                 if(ivideo->detectedpdc != 0xff) {
3157                                         printk(KERN_INFO
3158                                                 "sisfb: Detected LCD PDC 0x%02x (for LCD=CRT2)\n",
3159                                                 ivideo->detectedpdc);
3160                                 }
3161                                 if(ivideo->detectedpdca != 0xff) {
3162                                         printk(KERN_INFO
3163                                                 "sisfb: Detected LCD PDC1 0x%02x (for LCD=CRT1)\n",
3164                                                 ivideo->detectedpdca);
3165                                 }
3166                         }
3167
3168                         /* Save EMI */
3169                         if(ivideo->vbflags2 & VB2_SISEMIBRIDGE) {
3170                                 inSISIDXREG(SISPART4,0x30,ivideo->SiS_Pr.EMI_30);
3171                                 inSISIDXREG(SISPART4,0x31,ivideo->SiS_Pr.EMI_31);
3172                                 inSISIDXREG(SISPART4,0x32,ivideo->SiS_Pr.EMI_32);
3173                                 inSISIDXREG(SISPART4,0x33,ivideo->SiS_Pr.EMI_33);
3174                                 ivideo->SiS_Pr.HaveEMI = TRUE;
3175                                 if((tmp & 0x20) || (ivideo->detectedlcda != 0xff)) {
3176                                         ivideo->SiS_Pr.HaveEMILCD = TRUE;
3177                                 }
3178                         }
3179                 }
3180
3181                 /* Let user override detected PDCs (all bridges) */
3182                 if(ivideo->vbflags2 & VB2_30xBLV) {
3183                         if((ivideo->SiS_Pr.PDC != -1) &&
3184                            (ivideo->SiS_Pr.PDC != ivideo->detectedpdc)) {
3185                                 printk(KERN_INFO "sisfb: Using LCD PDC 0x%02x (for LCD=CRT2)\n",
3186                                         ivideo->SiS_Pr.PDC);
3187                         }
3188                         if((ivideo->SiS_Pr.PDCA != -1) &&
3189                            (ivideo->SiS_Pr.PDCA != ivideo->detectedpdca)) {
3190                                 printk(KERN_INFO "sisfb: Using LCD PDC1 0x%02x (for LCD=CRT1)\n",
3191                                  ivideo->SiS_Pr.PDCA);
3192                         }
3193                 }
3194
3195         }
3196 #endif
3197 }
3198
3199 /* -------------------- Memory manager routines ---------------------- */
3200
3201 static u32 __devinit
3202 sisfb_getheapstart(struct sis_video_info *ivideo)
3203 {
3204         u32 ret = ivideo->sisfb_parm_mem * 1024;
3205         u32 maxoffs = ivideo->video_size - ivideo->hwcursor_size - ivideo->cmdQueueSize;
3206         u32 def;
3207
3208         /* Calculate heap start = end of memory for console
3209          *
3210          * CCCCCCCCDDDDDDDDDDDDDDDDDDDDDDDDDDDDHHHHQQQQQQQQQQ
3211          * C = console, D = heap, H = HWCursor, Q = cmd-queue
3212          *
3213          * On 76x in UMA+LFB mode, the layout is as follows:
3214          * DDDDDDDDDDDCCCCCCCCCCCCCCCCCCCCCCCCHHHHQQQQQQQQQQQ
3215          * where the heap is the entire UMA area, eventually
3216          * into the LFB area if the given mem parameter is
3217          * higher than the size of the UMA memory.
3218          *
3219          * Basically given by "mem" parameter
3220          *
3221          * maximum = videosize - cmd_queue - hwcursor
3222          *           (results in a heap of size 0)
3223          * default = SiS 300: depends on videosize
3224          *           SiS 315/330/340/XGI: 32k below max
3225          */
3226
3227         if(ivideo->sisvga_engine == SIS_300_VGA) {
3228                 if(ivideo->video_size > 0x1000000) {
3229                         def = 0xc00000;
3230                 } else if(ivideo->video_size > 0x800000) {
3231                         def = 0x800000;
3232                 } else {
3233                         def = 0x400000;
3234                 }
3235         } else if(ivideo->UMAsize && ivideo->LFBsize) {
3236                 ret = def = 0;
3237         } else {
3238                 def = maxoffs - 0x8000;
3239         }
3240
3241         /* Use default for secondary card for now (FIXME) */
3242         if((!ret) || (ret > maxoffs) || (ivideo->cardnumber != 0))
3243                 ret = def;
3244
3245         return ret;
3246 }
3247
3248 static u32 __devinit
3249 sisfb_getheapsize(struct sis_video_info *ivideo)
3250 {
3251         u32 max = ivideo->video_size - ivideo->hwcursor_size - ivideo->cmdQueueSize;
3252         u32 ret = 0;
3253
3254         if(ivideo->UMAsize && ivideo->LFBsize) {
3255                 if( (!ivideo->sisfb_parm_mem)                   ||
3256                     ((ivideo->sisfb_parm_mem * 1024) > max)     ||
3257                     ((max - (ivideo->sisfb_parm_mem * 1024)) < ivideo->UMAsize) ) {
3258                         ret = ivideo->UMAsize;
3259                         max -= ivideo->UMAsize;
3260                 } else {
3261                         ret = max - (ivideo->sisfb_parm_mem * 1024);
3262                         max = ivideo->sisfb_parm_mem * 1024;
3263                 }
3264                 ivideo->video_offset = ret;
3265                 ivideo->sisfb_mem = max;
3266         } else {
3267                 ret = max - ivideo->heapstart;
3268                 ivideo->sisfb_mem = ivideo->heapstart;
3269         }
3270
3271         return ret;
3272 }
3273
3274 static int __devinit
3275 sisfb_heap_init(struct sis_video_info *ivideo)
3276 {
3277         struct SIS_OH *poh;
3278
3279         ivideo->video_offset = 0;
3280         if(ivideo->sisfb_parm_mem) {
3281                 if( (ivideo->sisfb_parm_mem < (2 * 1024 * 1024)) ||
3282                     (ivideo->sisfb_parm_mem > ivideo->video_size) ) {
3283                         ivideo->sisfb_parm_mem = 0;
3284                 }
3285         }
3286
3287         ivideo->heapstart = sisfb_getheapstart(ivideo);
3288         ivideo->sisfb_heap_size = sisfb_getheapsize(ivideo);
3289
3290         ivideo->sisfb_heap_start = ivideo->video_vbase + ivideo->heapstart;
3291         ivideo->sisfb_heap_end   = ivideo->sisfb_heap_start + ivideo->sisfb_heap_size;
3292
3293         printk(KERN_INFO "sisfb: Memory heap starting at %dK, size %dK\n",
3294                 (int)(ivideo->heapstart / 1024), (int)(ivideo->sisfb_heap_size / 1024));
3295
3296         ivideo->sisfb_heap.vinfo = ivideo;
3297
3298         ivideo->sisfb_heap.poha_chain = NULL;
3299         ivideo->sisfb_heap.poh_freelist = NULL;
3300
3301         poh = sisfb_poh_new_node(&ivideo->sisfb_heap);
3302         if(poh == NULL)
3303                 return 1;
3304
3305         poh->poh_next = &ivideo->sisfb_heap.oh_free;
3306         poh->poh_prev = &ivideo->sisfb_heap.oh_free;
3307         poh->size = ivideo->sisfb_heap_size;
3308         poh->offset = ivideo->heapstart;
3309
3310         ivideo->sisfb_heap.oh_free.poh_next = poh;
3311         ivideo->sisfb_heap.oh_free.poh_prev = poh;
3312         ivideo->sisfb_heap.oh_free.size = 0;
3313         ivideo->sisfb_heap.max_freesize = poh->size;
3314
3315         ivideo->sisfb_heap.oh_used.poh_next = &ivideo->sisfb_heap.oh_used;
3316         ivideo->sisfb_heap.oh_used.poh_prev = &ivideo->sisfb_heap.oh_used;
3317         ivideo->sisfb_heap.oh_used.size = SENTINEL;
3318
3319         if(ivideo->cardnumber == 0) {
3320                 /* For the first card, make this heap the "global" one
3321                  * for old DRM (which could handle only one card)
3322                  */
3323                 sisfb_heap = &ivideo->sisfb_heap;
3324         }
3325
3326         return 0;
3327 }
3328
3329 static struct SIS_OH *
3330 sisfb_poh_new_node(struct SIS_HEAP *memheap)
3331 {
3332         struct SIS_OHALLOC      *poha;
3333         struct SIS_OH           *poh;
3334         unsigned long           cOhs;
3335         int                     i;
3336
3337         if(memheap->poh_freelist == NULL) {
3338                 poha = kmalloc(SIS_OH_ALLOC_SIZE, GFP_KERNEL);
3339                 if(!poha)
3340                         return NULL;
3341
3342                 poha->poha_next = memheap->poha_chain;
3343                 memheap->poha_chain = poha;
3344
3345                 cOhs = (SIS_OH_ALLOC_SIZE - sizeof(struct SIS_OHALLOC)) / sizeof(struct SIS_OH) + 1;
3346
3347                 poh = &poha->aoh[0];
3348                 for(i = cOhs - 1; i != 0; i--) {
3349                         poh->poh_next = poh + 1;
3350                         poh = poh + 1;
3351                 }
3352
3353                 poh->poh_next = NULL;
3354                 memheap->poh_freelist = &poha->aoh[0];
3355         }
3356
3357         poh = memheap->poh_freelist;
3358         memheap->poh_freelist = poh->poh_next;
3359
3360         return poh;
3361 }
3362
3363 static struct SIS_OH *
3364 sisfb_poh_allocate(struct SIS_HEAP *memheap, u32 size)
3365 {
3366         struct SIS_OH   *pohThis;
3367         struct SIS_OH   *pohRoot;
3368         int             bAllocated = 0;
3369
3370         if(size > memheap->max_freesize) {
3371                 DPRINTK("sisfb: Can't allocate %dk video memory\n",
3372                         (unsigned int) size / 1024);
3373                 return NULL;
3374         }
3375
3376         pohThis = memheap->oh_free.poh_next;
3377
3378         while(pohThis != &memheap->oh_free) {
3379                 if(size <= pohThis->size) {
3380                         bAllocated = 1;
3381                         break;
3382                 }
3383                 pohThis = pohThis->poh_next;
3384         }
3385
3386         if(!bAllocated) {
3387                 DPRINTK("sisfb: Can't allocate %dk video memory\n",
3388                         (unsigned int) size / 1024);
3389                 return NULL;
3390         }
3391
3392         if(size == pohThis->size) {
3393                 pohRoot = pohThis;
3394                 sisfb_delete_node(pohThis);
3395         } else {
3396                 pohRoot = sisfb_poh_new_node(memheap);
3397                 if(pohRoot == NULL)
3398                         return NULL;
3399
3400                 pohRoot->offset = pohThis->offset;
3401                 pohRoot->size = size;
3402
3403                 pohThis->offset += size;
3404                 pohThis->size -= size;
3405         }
3406
3407         memheap->max_freesize -= size;
3408
3409         pohThis = &memheap->oh_used;
3410         sisfb_insert_node(pohThis, pohRoot);
3411
3412         return pohRoot;
3413 }
3414
3415 static void
3416 sisfb_delete_node(struct SIS_OH *poh)
3417 {
3418         poh->poh_prev->poh_next = poh->poh_next;
3419         poh->poh_next->poh_prev = poh->poh_prev;
3420 }
3421
3422 static void
3423 sisfb_insert_node(struct SIS_OH *pohList, struct SIS_OH *poh)
3424 {
3425         struct SIS_OH *pohTemp = pohList->poh_next;
3426
3427         pohList->poh_next = poh;
3428         pohTemp->poh_prev = poh;
3429
3430         poh->poh_prev = pohList;
3431         poh->poh_next = pohTemp;
3432 }
3433
3434 static struct SIS_OH *
3435 sisfb_poh_free(struct SIS_HEAP *memheap, u32 base)
3436 {
3437         struct SIS_OH *pohThis;
3438         struct SIS_OH *poh_freed;
3439         struct SIS_OH *poh_prev;
3440         struct SIS_OH *poh_next;
3441         u32    ulUpper;
3442         u32    ulLower;
3443         int    foundNode = 0;
3444
3445         poh_freed = memheap->oh_used.poh_next;
3446
3447         while(poh_freed != &memheap->oh_used) {
3448                 if(poh_freed->offset == base) {
3449                         foundNode = 1;
3450                         break;
3451                 }
3452
3453                 poh_freed = poh_freed->poh_next;
3454         }
3455
3456         if(!foundNode)
3457                 return NULL;
3458
3459         memheap->max_freesize += poh_freed->size;
3460
3461         poh_prev = poh_next = NULL;
3462         ulUpper = poh_freed->offset + poh_freed->size;
3463         ulLower = poh_freed->offset;
3464
3465         pohThis = memheap->oh_free.poh_next;
3466
3467         while(pohThis != &memheap->oh_free) {
3468                 if(pohThis->offset == ulUpper) {
3469                         poh_next = pohThis;
3470                 } else if((pohThis->offset + pohThis->size) == ulLower) {
3471                         poh_prev = pohThis;
3472                 }
3473                 pohThis = pohThis->poh_next;
3474         }
3475
3476         sisfb_delete_node(poh_freed);
3477
3478         if(poh_prev && poh_next) {
3479                 poh_prev->size += (poh_freed->size + poh_next->size);
3480                 sisfb_delete_node(poh_next);
3481                 sisfb_free_node(memheap, poh_freed);
3482                 sisfb_free_node(memheap, poh_next);
3483                 return poh_prev;
3484         }
3485
3486         if(poh_prev) {
3487                 poh_prev->size += poh_freed->size;
3488                 sisfb_free_node(memheap, poh_freed);
3489                 return poh_prev;
3490         }
3491
3492         if(poh_next) {
3493                 poh_next->size += poh_freed->size;
3494                 poh_next->offset = poh_freed->offset;
3495                 sisfb_free_node(memheap, poh_freed);
3496                 return poh_next;
3497         }
3498
3499         sisfb_insert_node(&memheap->oh_free, poh_freed);
3500
3501         return poh_freed;
3502 }
3503
3504 static void
3505 sisfb_free_node(struct SIS_HEAP *memheap, struct SIS_OH *poh)
3506 {
3507         if(poh == NULL)
3508                 return;
3509
3510         poh->poh_next = memheap->poh_freelist;
3511         memheap->poh_freelist = poh;
3512 }
3513
3514 static void
3515 sis_int_malloc(struct sis_video_info *ivideo, struct sis_memreq *req)
3516 {
3517         struct SIS_OH *poh = NULL;
3518
3519         if((ivideo) && (ivideo->sisfb_id == SISFB_ID) && (!ivideo->havenoheap))
3520                 poh = sisfb_poh_allocate(&ivideo->sisfb_heap, (u32)req->size);
3521
3522         if(poh == NULL) {
3523                 req->offset = req->size = 0;
3524                 DPRINTK("sisfb: Video RAM allocation failed\n");
3525         } else {
3526                 req->offset = poh->offset;
3527                 req->size = poh->size;
3528                 DPRINTK("sisfb: Video RAM allocation succeeded: 0x%lx\n",
3529                         (poh->offset + ivideo->video_vbase));
3530         }
3531 }
3532
3533 void
3534 sis_malloc(struct sis_memreq *req)
3535 {
3536         struct sis_video_info *ivideo = sisfb_heap->vinfo;
3537
3538         if(&ivideo->sisfb_heap == sisfb_heap)
3539                 sis_int_malloc(ivideo, req);
3540         else
3541                 req->offset = req->size = 0;
3542 }
3543
3544 void
3545 sis_malloc_new(struct pci_dev *pdev, struct sis_memreq *req)
3546 {
3547         struct sis_video_info *ivideo = pci_get_drvdata(pdev);
3548
3549         sis_int_malloc(ivideo, req);
3550 }
3551
3552 /* sis_free: u32 because "base" is offset inside video ram, can never be >4GB */
3553
3554 static void
3555 sis_int_free(struct sis_video_info *ivideo, u32 base)
3556 {
3557         struct SIS_OH *poh;
3558
3559         if((!ivideo) || (ivideo->sisfb_id != SISFB_ID) || (ivideo->havenoheap))
3560                 return;
3561
3562         poh = sisfb_poh_free(&ivideo->sisfb_heap, base);
3563
3564         if(poh == NULL) {
3565                 DPRINTK("sisfb: sisfb_poh_free() failed at base 0x%x\n",
3566                         (unsigned int) base);
3567         }
3568 }
3569
3570 void
3571 sis_free(u32 base)
3572 {
3573         struct sis_video_info *ivideo = sisfb_heap->vinfo;
3574
3575         sis_int_free(ivideo, base);
3576 }
3577
3578 void
3579 sis_free_new(struct pci_dev *pdev, u32 base)
3580 {
3581         struct sis_video_info *ivideo = pci_get_drvdata(pdev);
3582
3583         sis_int_free(ivideo, base);
3584 }
3585
3586 /* --------------------- SetMode routines ------------------------- */
3587
3588 static void
3589 sisfb_check_engine_and_sync(struct sis_video_info *ivideo)
3590 {
3591         u8 cr30, cr31;
3592
3593         /* Check if MMIO and engines are enabled,
3594          * and sync in case they are. Can't use
3595          * ivideo->accel here, as this might have
3596          * been changed before this is called.
3597          */
3598         inSISIDXREG(SISSR, IND_SIS_PCI_ADDRESS_SET, cr30);
3599         inSISIDXREG(SISSR, IND_SIS_MODULE_ENABLE, cr31);
3600         /* MMIO and 2D/3D engine enabled? */
3601         if((cr30 & SIS_MEM_MAP_IO_ENABLE) && (cr31 & 0x42)) {
3602 #ifdef CONFIG_FB_SIS_300
3603                 if(ivideo->sisvga_engine == SIS_300_VGA) {
3604                         /* Don't care about TurboQueue. It's
3605                          * enough to know that the engines
3606                          * are enabled
3607                          */
3608                         sisfb_syncaccel(ivideo);
3609                 }
3610 #endif
3611 #ifdef CONFIG_FB_SIS_315
3612                 if(ivideo->sisvga_engine == SIS_315_VGA) {
3613                         /* Check that any queue mode is
3614                          * enabled, and that the queue
3615                          * is not in the state of "reset"
3616                          */
3617                         inSISIDXREG(SISSR, 0x26, cr30);
3618                         if((cr30 & 0xe0) && (!(cr30 & 0x01))) {
3619                                 sisfb_syncaccel(ivideo);
3620                         }
3621                 }
3622 #endif
3623         }
3624 }
3625
3626 static void
3627 sisfb_pre_setmode(struct sis_video_info *ivideo)
3628 {
3629         u8 cr30 = 0, cr31 = 0, cr33 = 0, cr35 = 0, cr38 = 0;
3630         int tvregnum = 0;
3631
3632         ivideo->currentvbflags &= (VB_VIDEOBRIDGE | VB_DISPTYPE_DISP2);
3633
3634         outSISIDXREG(SISSR, 0x05, 0x86);
3635
3636         inSISIDXREG(SISCR, 0x31, cr31);
3637         cr31 &= ~0x60;
3638         cr31 |= 0x04;
3639
3640         cr33 = ivideo->rate_idx & 0x0F;
3641
3642 #ifdef CONFIG_FB_SIS_315
3643         if(ivideo->sisvga_engine == SIS_315_VGA) {
3644            if(ivideo->chip >= SIS_661) {
3645               inSISIDXREG(SISCR, 0x38, cr38);
3646               cr38 &= ~0x07;  /* Clear LCDA/DualEdge and YPbPr bits */
3647            } else {
3648               tvregnum = 0x38;
3649               inSISIDXREG(SISCR, tvregnum, cr38);
3650               cr38 &= ~0x3b;  /* Clear LCDA/DualEdge and YPbPr bits */
3651            }
3652         }
3653 #endif
3654 #ifdef CONFIG_FB_SIS_300
3655         if(ivideo->sisvga_engine == SIS_300_VGA) {
3656            tvregnum = 0x35;
3657            inSISIDXREG(SISCR, tvregnum, cr38);
3658         }
3659 #endif
3660
3661         SiS_SetEnableDstn(&ivideo->SiS_Pr, FALSE);
3662         SiS_SetEnableFstn(&ivideo->SiS_Pr, FALSE);
3663         ivideo->curFSTN = ivideo->curDSTN = 0;
3664
3665         switch(ivideo->currentvbflags & VB_DISPTYPE_DISP2) {
3666
3667            case CRT2_TV:
3668               cr38 &= ~0xc0;   /* Clear PAL-M / PAL-N bits */
3669               if((ivideo->vbflags & TV_YPBPR) && (ivideo->vbflags2 & VB2_SISYPBPRBRIDGE)) {
3670 #ifdef CONFIG_FB_SIS_315
3671                  if(ivideo->chip >= SIS_661) {
3672                     cr38 |= 0x04;
3673                     if(ivideo->vbflags & TV_YPBPR525P)       cr35 |= 0x20;
3674                     else if(ivideo->vbflags & TV_YPBPR750P)  cr35 |= 0x40;
3675                     else if(ivideo->vbflags & TV_YPBPR1080I) cr35 |= 0x60;
3676                     cr30 |= SIS_SIMULTANEOUS_VIEW_ENABLE;
3677                     cr35 &= ~0x01;
3678                     ivideo->currentvbflags |= (TV_YPBPR | (ivideo->vbflags & TV_YPBPRALL));
3679                  } else if(ivideo->sisvga_engine == SIS_315_VGA) {
3680                     cr30 |= (0x80 | SIS_SIMULTANEOUS_VIEW_ENABLE);
3681                     cr38 |= 0x08;
3682                     if(ivideo->vbflags & TV_YPBPR525P)       cr38 |= 0x10;
3683                     else if(ivideo->vbflags & TV_YPBPR750P)  cr38 |= 0x20;
3684                     else if(ivideo->vbflags & TV_YPBPR1080I) cr38 |= 0x30;
3685                     cr31 &= ~0x01;
3686                     ivideo->currentvbflags |= (TV_YPBPR | (ivideo->vbflags & TV_YPBPRALL));
3687                  }
3688 #endif
3689               } else if((ivideo->vbflags & TV_HIVISION) &&
3690                                 (ivideo->vbflags2 & VB2_SISHIVISIONBRIDGE)) {
3691                  if(ivideo->chip >= SIS_661) {
3692                     cr38 |= 0x04;
3693                     cr35 |= 0x60;
3694                  } else {
3695                     cr30 |= 0x80;
3696                  }
3697                  cr30 |= SIS_SIMULTANEOUS_VIEW_ENABLE;
3698                  cr31 |= 0x01;
3699                  cr35 |= 0x01;
3700                  ivideo->currentvbflags |= TV_HIVISION;
3701               } else if(ivideo->vbflags & TV_SCART) {
3702                  cr30 = (SIS_VB_OUTPUT_SCART | SIS_SIMULTANEOUS_VIEW_ENABLE);
3703                  cr31 |= 0x01;
3704                  cr35 |= 0x01;
3705                  ivideo->currentvbflags |= TV_SCART;
3706               } else {
3707                  if(ivideo->vbflags & TV_SVIDEO) {
3708                     cr30 = (SIS_VB_OUTPUT_SVIDEO | SIS_SIMULTANEOUS_VIEW_ENABLE);
3709                     ivideo->currentvbflags |= TV_SVIDEO;
3710                  }
3711                  if(ivideo->vbflags & TV_AVIDEO) {
3712                     cr30 = (SIS_VB_OUTPUT_COMPOSITE | SIS_SIMULTANEOUS_VIEW_ENABLE);
3713                     ivideo->currentvbflags |= TV_AVIDEO;
3714                  }
3715               }
3716               cr31 |= SIS_DRIVER_MODE;
3717
3718               if(ivideo->vbflags & (TV_AVIDEO | TV_SVIDEO)) {
3719                  if(ivideo->vbflags & TV_PAL) {
3720                     cr31 |= 0x01; cr35 |= 0x01;
3721                     ivideo->currentvbflags |= TV_PAL;
3722                     if(ivideo->vbflags & TV_PALM) {
3723                        cr38 |= 0x40; cr35 |= 0x04;
3724                        ivideo->currentvbflags |= TV_PALM;
3725                     } else if(ivideo->vbflags & TV_PALN) {
3726                        cr38 |= 0x80; cr35 |= 0x08;
3727                        ivideo->currentvbflags |= TV_PALN;
3728                     }
3729                  } else {
3730                     cr31 &= ~0x01; cr35 &= ~0x01;
3731                     ivideo->currentvbflags |= TV_NTSC;
3732                     if(ivideo->vbflags & TV_NTSCJ) {
3733                        cr38 |= 0x40; cr35 |= 0x02;
3734                        ivideo->currentvbflags |= TV_NTSCJ;
3735                     }
3736                  }
3737               }
3738               break;
3739
3740            case CRT2_LCD:
3741               cr30  = (SIS_VB_OUTPUT_LCD | SIS_SIMULTANEOUS_VIEW_ENABLE);
3742               cr31 |= SIS_DRIVER_MODE;
3743               SiS_SetEnableDstn(&ivideo->SiS_Pr, ivideo->sisfb_dstn);
3744               SiS_SetEnableFstn(&ivideo->SiS_Pr, ivideo->sisfb_fstn);
3745               ivideo->curFSTN = ivideo->sisfb_fstn;
3746               ivideo->curDSTN = ivideo->sisfb_dstn;
3747               break;
3748
3749            case CRT2_VGA:
3750               cr30 = (SIS_VB_OUTPUT_CRT2 | SIS_SIMULTANEOUS_VIEW_ENABLE);
3751               cr31 |= SIS_DRIVER_MODE;
3752               if(ivideo->sisfb_nocrt2rate) {
3753                  cr33 |= (sisbios_mode[ivideo->sisfb_mode_idx].rate_idx << 4);
3754               } else {
3755                  cr33 |= ((ivideo->rate_idx & 0x0F) << 4);
3756               }
3757               break;
3758
3759            default:     /* disable CRT2 */
3760               cr30 = 0x00;
3761               cr31 |= (SIS_DRIVER_MODE | SIS_VB_OUTPUT_DISABLE);
3762         }
3763
3764         outSISIDXREG(SISCR, 0x30, cr30);
3765         outSISIDXREG(SISCR, 0x33, cr33);
3766
3767         if(ivideo->chip >= SIS_661) {
3768 #ifdef CONFIG_FB_SIS_315
3769            cr31 &= ~0x01;                          /* Clear PAL flag (now in CR35) */
3770            setSISIDXREG(SISCR, 0x35, ~0x10, cr35); /* Leave overscan bit alone */
3771            cr38 &= 0x07;                           /* Use only LCDA and HiVision/YPbPr bits */
3772            setSISIDXREG(SISCR, 0x38, 0xf8, cr38);
3773 #endif
3774         } else if(ivideo->chip != SIS_300) {
3775            outSISIDXREG(SISCR, tvregnum, cr38);
3776         }
3777         outSISIDXREG(SISCR, 0x31, cr31);
3778
3779         ivideo->SiS_Pr.SiS_UseOEM = ivideo->sisfb_useoem;
3780
3781         sisfb_check_engine_and_sync(ivideo);
3782 }
3783
3784 /* Fix SR11 for 661 and later */
3785 #ifdef CONFIG_FB_SIS_315
3786 static void
3787 sisfb_fixup_SR11(struct sis_video_info *ivideo)
3788 {
3789         u8  tmpreg;
3790
3791         if(ivideo->chip >= SIS_661) {
3792                 inSISIDXREG(SISSR,0x11,tmpreg);
3793                 if(tmpreg & 0x20) {
3794                         inSISIDXREG(SISSR,0x3e,tmpreg);
3795                         tmpreg = (tmpreg + 1) & 0xff;
3796                         outSISIDXREG(SISSR,0x3e,tmpreg);
3797                         inSISIDXREG(SISSR,0x11,tmpreg);
3798                 }
3799                 if(tmpreg & 0xf0) {
3800                         andSISIDXREG(SISSR,0x11,0x0f);
3801                 }
3802         }
3803 }
3804 #endif
3805
3806 static void
3807 sisfb_set_TVxposoffset(struct sis_video_info *ivideo, int val)
3808 {
3809         if(val > 32) val = 32;
3810         if(val < -32) val = -32;
3811         ivideo->tvxpos = val;
3812
3813         if(ivideo->sisfblocked) return;
3814         if(!ivideo->modechanged) return;
3815
3816         if(ivideo->currentvbflags & CRT2_TV) {
3817
3818                 if(ivideo->vbflags2 & VB2_CHRONTEL) {
3819
3820                         int x = ivideo->tvx;
3821
3822                         switch(ivideo->chronteltype) {
3823                         case 1:
3824                                 x += val;
3825                                 if(x < 0) x = 0;
3826                                 outSISIDXREG(SISSR,0x05,0x86);
3827                                 SiS_SetCH700x(&ivideo->SiS_Pr, 0x0a, (x & 0xff));
3828                                 SiS_SetCH70xxANDOR(&ivideo->SiS_Pr, 0x08, ((x & 0x0100) >> 7), 0xFD);
3829                                 break;
3830                         case 2:
3831                                 /* Not supported by hardware */
3832                                 break;
3833                         }
3834
3835                 } else if(ivideo->vbflags2 & VB2_SISBRIDGE) {
3836
3837                         u8 p2_1f,p2_20,p2_2b,p2_42,p2_43;
3838                         unsigned short temp;
3839
3840                         p2_1f = ivideo->p2_1f;
3841                         p2_20 = ivideo->p2_20;
3842                         p2_2b = ivideo->p2_2b;
3843                         p2_42 = ivideo->p2_42;
3844                         p2_43 = ivideo->p2_43;
3845
3846                         temp = p2_1f | ((p2_20 & 0xf0) << 4);
3847                         temp += (val * 2);
3848                         p2_1f = temp & 0xff;
3849                         p2_20 = (temp & 0xf00) >> 4;
3850                         p2_2b = ((p2_2b & 0x0f) + (val * 2)) & 0x0f;
3851                         temp = p2_43 | ((p2_42 & 0xf0) << 4);
3852                         temp += (val * 2);
3853                         p2_43 = temp & 0xff;
3854                         p2_42 = (temp & 0xf00) >> 4;
3855                         outSISIDXREG(SISPART2,0x1f,p2_1f);
3856                         setSISIDXREG(SISPART2,0x20,0x0F,p2_20);
3857                         setSISIDXREG(SISPART2,0x2b,0xF0,p2_2b);
3858                         setSISIDXREG(SISPART2,0x42,0x0F,p2_42);
3859                         outSISIDXREG(SISPART2,0x43,p2_43);
3860                 }
3861         }
3862 }
3863
3864 static void
3865 sisfb_set_TVyposoffset(struct sis_video_info *ivideo, int val)
3866 {
3867         if(val > 32) val = 32;
3868         if(val < -32) val = -32;
3869         ivideo->tvypos = val;
3870
3871         if(ivideo->sisfblocked) return;
3872         if(!ivideo->modechanged) return;
3873
3874         if(ivideo->currentvbflags & CRT2_TV) {
3875
3876                 if(ivideo->vbflags2 & VB2_CHRONTEL) {
3877
3878                         int y = ivideo->tvy;
3879
3880                         switch(ivideo->chronteltype) {
3881                         case 1:
3882                                 y -= val;
3883                                 if(y < 0) y = 0;
3884                                 outSISIDXREG(SISSR,0x05,0x86);
3885                                 SiS_SetCH700x(&ivideo->SiS_Pr, 0x0b, (y & 0xff));
3886                                 SiS_SetCH70xxANDOR(&ivideo->SiS_Pr, 0x08, ((y & 0x0100) >> 8), 0xFE);
3887                                 break;
3888                         case 2:
3889                                 /* Not supported by hardware */
3890                                 break;
3891                         }
3892
3893                 } else if(ivideo->vbflags2 & VB2_SISBRIDGE) {
3894
3895                         char p2_01, p2_02;
3896                         val /= 2;
3897                         p2_01 = ivideo->p2_01;
3898                         p2_02 = ivideo->p2_02;
3899
3900                         p2_01 += val;
3901                         p2_02 += val;
3902                         if(!(ivideo->currentvbflags & (TV_HIVISION | TV_YPBPR))) {
3903                                 while((p2_01 <= 0) || (p2_02 <= 0)) {
3904                                         p2_01 += 2;
3905                                         p2_02 += 2;
3906                                 }
3907                         }
3908                         outSISIDXREG(SISPART2,0x01,p2_01);
3909                         outSISIDXREG(SISPART2,0x02,p2_02);
3910                 }
3911         }
3912 }
3913
3914 static void
3915 sisfb_post_setmode(struct sis_video_info *ivideo)
3916 {
3917         BOOLEAN crt1isoff = FALSE;
3918         BOOLEAN doit = TRUE;
3919 #if defined(CONFIG_FB_SIS_300) || defined(CONFIG_FB_SIS_315)
3920         u8 reg;
3921 #endif
3922 #ifdef CONFIG_FB_SIS_315
3923         u8 reg1;
3924 #endif
3925
3926         outSISIDXREG(SISSR, 0x05, 0x86);
3927
3928 #ifdef CONFIG_FB_SIS_315
3929         sisfb_fixup_SR11(ivideo);
3930 #endif
3931
3932         /* Now we actually HAVE changed the display mode */
3933         ivideo->modechanged = 1;
3934
3935         /* We can't switch off CRT1 if bridge is in slave mode */
3936         if(ivideo->vbflags2 & VB2_VIDEOBRIDGE) {
3937                 if(sisfb_bridgeisslave(ivideo)) doit = FALSE;
3938         } else
3939                 ivideo->sisfb_crt1off = 0;
3940
3941 #ifdef CONFIG_FB_SIS_300
3942         if(ivideo->sisvga_engine == SIS_300_VGA) {
3943                 if((ivideo->sisfb_crt1off) && (doit)) {
3944                         crt1isoff = TRUE;
3945                         reg = 0x00;
3946                 } else {
3947                         crt1isoff = FALSE;
3948                         reg = 0x80;
3949                 }
3950                 setSISIDXREG(SISCR, 0x17, 0x7f, reg);
3951         }
3952 #endif
3953 #ifdef CONFIG_FB_SIS_315
3954         if(ivideo->sisvga_engine == SIS_315_VGA) {
3955                 if((ivideo->sisfb_crt1off) && (doit)) {
3956                         crt1isoff = TRUE;
3957                         reg  = 0x40;
3958                         reg1 = 0xc0;
3959                 } else {
3960                         crt1isoff = FALSE;
3961                         reg  = 0x00;
3962                         reg1 = 0x00;
3963                 }
3964                 setSISIDXREG(SISCR, ivideo->SiS_Pr.SiS_MyCR63, ~0x40, reg);
3965                 setSISIDXREG(SISSR, 0x1f, ~0xc0, reg1);
3966         }
3967 #endif
3968
3969         if(crt1isoff) {
3970                 ivideo->currentvbflags &= ~VB_DISPTYPE_CRT1;
3971                 ivideo->currentvbflags |= VB_SINGLE_MODE;
3972         } else {
3973                 ivideo->currentvbflags |= VB_DISPTYPE_CRT1;
3974                 if(ivideo->currentvbflags & VB_DISPTYPE_CRT2) {
3975                         ivideo->currentvbflags |= VB_MIRROR_MODE;
3976                 } else {
3977                         ivideo->currentvbflags |= VB_SINGLE_MODE;
3978                 }
3979         }
3980
3981         andSISIDXREG(SISSR, IND_SIS_RAMDAC_CONTROL, ~0x04);
3982
3983         if(ivideo->currentvbflags & CRT2_TV) {
3984                 if(ivideo->vbflags2 & VB2_SISBRIDGE) {
3985                         inSISIDXREG(SISPART2,0x1f,ivideo->p2_1f);
3986                         inSISIDXREG(SISPART2,0x20,ivideo->p2_20);
3987                         inSISIDXREG(SISPART2,0x2b,ivideo->p2_2b);
3988                         inSISIDXREG(SISPART2,0x42,ivideo->p2_42);
3989                         inSISIDXREG(SISPART2,0x43,ivideo->p2_43);
3990                         inSISIDXREG(SISPART2,0x01,ivideo->p2_01);
3991                         inSISIDXREG(SISPART2,0x02,ivideo->p2_02);
3992                 } else if(ivideo->vbflags2 & VB2_CHRONTEL) {
3993                         if(ivideo->chronteltype == 1) {
3994                                 ivideo->tvx = SiS_GetCH700x(&ivideo->SiS_Pr, 0x0a);
3995                                 ivideo->tvx |= (((SiS_GetCH700x(&ivideo->SiS_Pr, 0x08) & 0x02) >> 1) << 8);
3996                                 ivideo->tvy = SiS_GetCH700x(&ivideo->SiS_Pr, 0x0b);
3997                                 ivideo->tvy |= ((SiS_GetCH700x(&ivideo->SiS_Pr, 0x08) & 0x01) << 8);
3998                         }
3999                 }
4000         }
4001
4002         if(ivideo->tvxpos) {
4003                 sisfb_set_TVxposoffset(ivideo, ivideo->tvxpos);
4004         }
4005         if(ivideo->tvypos) {
4006                 sisfb_set_TVyposoffset(ivideo, ivideo->tvypos);
4007         }
4008
4009         /* Eventually sync engines */
4010         sisfb_check_engine_and_sync(ivideo);
4011
4012         /* (Re-)Initialize chip engines */
4013         if(ivideo->accel) {
4014                 sisfb_engine_init(ivideo);
4015         } else {
4016                 ivideo->engineok = 0;
4017         }
4018 }
4019
4020 static int
4021 sisfb_reset_mode(struct sis_video_info *ivideo)
4022 {
4023         if(sisfb_set_mode(ivideo, 0))
4024                 return 1;
4025
4026         sisfb_set_pitch(ivideo);
4027         sisfb_set_base_CRT1(ivideo, ivideo->current_base);
4028         sisfb_set_base_CRT2(ivideo, ivideo->current_base);
4029
4030         return 0;
4031 }
4032
4033 static void
4034 sisfb_handle_command(struct sis_video_info *ivideo, struct sisfb_cmd *sisfb_command)
4035 {
4036         int mycrt1off;
4037
4038         switch(sisfb_command->sisfb_cmd) {
4039         case SISFB_CMD_GETVBFLAGS:
4040                 if(!ivideo->modechanged) {
4041                         sisfb_command->sisfb_result[0] = SISFB_CMD_ERR_EARLY;
4042                 } else {
4043                         sisfb_command->sisfb_result[0] = SISFB_CMD_ERR_OK;
4044                         sisfb_command->sisfb_result[1] = ivideo->currentvbflags;
4045                         sisfb_command->sisfb_result[2] = ivideo->vbflags2;
4046                 }
4047                 break;
4048         case SISFB_CMD_SWITCHCRT1:
4049                 /* arg[0]: 0 = off, 1 = on, 99 = query */
4050                 if(!ivideo->modechanged) {
4051                         sisfb_command->sisfb_result[0] = SISFB_CMD_ERR_EARLY;
4052                 } else if(sisfb_command->sisfb_arg[0] == 99) {
4053                         /* Query */
4054                         sisfb_command->sisfb_result[1] = ivideo->sisfb_crt1off ? 0 : 1;
4055                         sisfb_command->sisfb_result[0] = SISFB_CMD_ERR_OK;
4056                 } else if(ivideo->sisfblocked) {
4057                         sisfb_command->sisfb_result[0] = SISFB_CMD_ERR_LOCKED;
4058                 } else if((!(ivideo->currentvbflags & CRT2_ENABLE)) &&
4059                                         (sisfb_command->sisfb_arg[0] == 0)) {
4060                         sisfb_command->sisfb_result[0] = SISFB_CMD_ERR_NOCRT2;
4061                 } else {
4062                         sisfb_command->sisfb_result[0] = SISFB_CMD_ERR_OK;
4063                         mycrt1off = sisfb_command->sisfb_arg[0] ? 0 : 1;
4064                         if( ((ivideo->currentvbflags & VB_DISPTYPE_CRT1) && mycrt1off) ||
4065                             ((!(ivideo->currentvbflags & VB_DISPTYPE_CRT1)) && !mycrt1off) ) {
4066                                 ivideo->sisfb_crt1off = mycrt1off;
4067                                 if(sisfb_reset_mode(ivideo)) {
4068                                         sisfb_command->sisfb_result[0] = SISFB_CMD_ERR_OTHER;
4069                                 }
4070                         }
4071                         sisfb_command->sisfb_result[1] = ivideo->sisfb_crt1off ? 0 : 1;
4072                 }
4073                 break;
4074         /* more to come */
4075         default:
4076                 sisfb_command->sisfb_result[0] = SISFB_CMD_ERR_UNKNOWN;
4077                 printk(KERN_ERR "sisfb: Unknown command 0x%x\n",
4078                         sisfb_command->sisfb_cmd);
4079         }
4080 }
4081
4082 #ifndef MODULE
4083 SISINITSTATIC int __init
4084 sisfb_setup(char *options)
4085 {
4086         char *this_opt;
4087
4088         sisfb_setdefaultparms();
4089
4090         if(!options || !(*options))
4091                 return 0;
4092
4093         while((this_opt = strsep(&options, ",")) != NULL) {
4094
4095                 if(!(*this_opt)) continue;
4096
4097                 if(!strnicmp(this_opt, "off", 3)) {
4098                         sisfb_off = 1;
4099                 } else if(!strnicmp(this_opt, "forcecrt2type:", 14)) {
4100                         /* Need to check crt2 type first for fstn/dstn */
4101                         sisfb_search_crt2type(this_opt + 14);
4102                 } else if(!strnicmp(this_opt, "tvmode:",7)) {
4103                         sisfb_search_tvstd(this_opt + 7);
4104                 } else if(!strnicmp(this_opt, "tvstandard:",11)) {
4105                         sisfb_search_tvstd(this_opt + 11);
4106                 } else if(!strnicmp(this_opt, "mode:", 5)) {
4107                         sisfb_search_mode(this_opt + 5, FALSE);
4108                 } else if(!strnicmp(this_opt, "vesa:", 5)) {
4109                         sisfb_search_vesamode(simple_strtoul(this_opt + 5, NULL, 0), FALSE);
4110 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
4111                 } else if(!strnicmp(this_opt, "inverse", 7)) {
4112                         sisfb_inverse = 1;
4113                         /* fb_invert_cmaps(); */
4114                 } else if(!strnicmp(this_opt, "font:", 5)) {
4115                         if(strlen(this_opt + 5) < 40) {
4116                            strncpy(sisfb_fontname, this_opt + 5, sizeof(sisfb_fontname) - 1);
4117                            sisfb_fontname[sizeof(sisfb_fontname) - 1] = '\0';
4118                         }
4119 #endif
4120                 } else if(!strnicmp(this_opt, "rate:", 5)) {
4121                         sisfb_parm_rate = simple_strtoul(this_opt + 5, NULL, 0);
4122                 } else if(!strnicmp(this_opt, "forcecrt1:", 10)) {
4123                         sisfb_forcecrt1 = (int)simple_strtoul(this_opt + 10, NULL, 0);
4124                 } else if(!strnicmp(this_opt, "mem:",4)) {
4125                         sisfb_parm_mem = simple_strtoul(this_opt + 4, NULL, 0);
4126                 } else if(!strnicmp(this_opt, "pdc:", 4)) {
4127                         sisfb_pdc = simple_strtoul(this_opt + 4, NULL, 0);
4128                 } else if(!strnicmp(this_opt, "pdc1:", 5)) {
4129                         sisfb_pdca = simple_strtoul(this_opt + 5, NULL, 0);
4130                 } else if(!strnicmp(this_opt, "noaccel", 7)) {
4131                         sisfb_accel = 0;
4132                 } else if(!strnicmp(this_opt, "accel", 5)) {
4133                         sisfb_accel = -1;
4134                 } else if(!strnicmp(this_opt, "noypan", 6)) {
4135                         sisfb_ypan = 0;
4136                 } else if(!strnicmp(this_opt, "ypan", 4)) {
4137                         sisfb_ypan = -1;
4138                 } else if(!strnicmp(this_opt, "nomax", 5)) {
4139                         sisfb_max = 0;
4140                 } else if(!strnicmp(this_opt, "max", 3)) {
4141                         sisfb_max = -1;
4142                 } else if(!strnicmp(this_opt, "userom:", 7)) {
4143                         sisfb_userom = (int)simple_strtoul(this_opt + 7, NULL, 0);
4144                 } else if(!strnicmp(this_opt, "useoem:", 7)) {
4145                         sisfb_useoem = (int)simple_strtoul(this_opt + 7, NULL, 0);
4146                 } else if(!strnicmp(this_opt, "nocrt2rate", 10)) {
4147                         sisfb_nocrt2rate = 1;
4148                 } else if(!strnicmp(this_opt, "scalelcd:", 9)) {
4149                         unsigned long temp = 2;
4150                         temp = simple_strtoul(this_opt + 9, NULL, 0);
4151                         if((temp == 0) || (temp == 1)) {
4152                            sisfb_scalelcd = temp ^ 1;
4153                         }
4154                 } else if(!strnicmp(this_opt, "tvxposoffset:", 13)) {
4155                         int temp = 0;
4156                         temp = (int)simple_strtol(this_opt + 13, NULL, 0);
4157                         if((temp >= -32) && (temp <= 32)) {
4158                            sisfb_tvxposoffset = temp;
4159                         }
4160                 } else if(!strnicmp(this_opt, "tvyposoffset:", 13)) {
4161                         int temp = 0;
4162                         temp = (int)simple_strtol(this_opt + 13, NULL, 0);
4163                         if((temp >= -32) && (temp <= 32)) {
4164                            sisfb_tvyposoffset = temp;
4165                         }
4166                 } else if(!strnicmp(this_opt, "specialtiming:", 14)) {
4167                         sisfb_search_specialtiming(this_opt + 14);
4168                 } else if(!strnicmp(this_opt, "lvdshl:", 7)) {
4169                         int temp = 4;
4170                         temp = simple_strtoul(this_opt + 7, NULL, 0);
4171                         if((temp >= 0) && (temp <= 3)) {
4172                            sisfb_lvdshl = temp;
4173                         }
4174                 } else if(this_opt[0] >= '0' && this_opt[0] <= '9') {
4175                         sisfb_search_mode(this_opt, TRUE);
4176 #if !defined(__i386__) && !defined(__x86_64__)
4177                 } else if(!strnicmp(this_opt, "resetcard", 9)) {
4178                         sisfb_resetcard = 1;
4179                 } else if(!strnicmp(this_opt, "videoram:", 9)) {
4180                         sisfb_videoram = simple_strtoul(this_opt + 9, NULL, 0);
4181 #endif
4182                 } else {
4183                         printk(KERN_INFO "sisfb: Invalid option %s\n", this_opt);
4184                 }
4185
4186         }
4187
4188         return 0;
4189 }
4190 #endif
4191
4192 static int __devinit
4193 sisfb_check_rom(SIS_IOTYPE1 *rom_base, struct sis_video_info *ivideo)
4194 {
4195         SIS_IOTYPE1 *rom;
4196         int romptr;
4197
4198         if((readb(rom_base) != 0x55) || (readb(rom_base + 1) != 0xaa))
4199                 return 0;
4200
4201         romptr = (readb(rom_base + 0x18) | (readb(rom_base + 0x19) << 8));
4202         if(romptr > (0x10000 - 8))
4203                 return 0;
4204
4205         rom = rom_base + romptr;
4206
4207         if((readb(rom)     != 'P') || (readb(rom + 1) != 'C') ||
4208            (readb(rom + 2) != 'I') || (readb(rom + 3) != 'R'))
4209                 return 0;
4210
4211         if((readb(rom + 4) | (readb(rom + 5) << 8)) != ivideo->chip_vendor)
4212                 return 0;
4213
4214         if((readb(rom + 6) | (readb(rom + 7) << 8)) != ivideo->chip_id)
4215                 return 0;
4216
4217         return 1;
4218 }
4219
4220 static unsigned char * __devinit
4221 sisfb_find_rom(struct pci_dev *pdev)
4222 {
4223         struct sis_video_info *ivideo = pci_get_drvdata(pdev);
4224         SIS_IOTYPE1 *rom_base;
4225         unsigned char *myrombase = NULL;
4226         u32 temp;
4227 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,11)
4228         size_t romsize;
4229
4230         /* First, try the official pci ROM functions (except
4231          * on integrated chipsets which have no ROM).
4232          */
4233
4234         if(!ivideo->nbridge) {
4235
4236                 if((rom_base = pci_map_rom(pdev, &romsize))) {
4237
4238                         if(sisfb_check_rom(rom_base, ivideo)) {
4239
4240                                 if((myrombase = vmalloc(65536))) {
4241
4242                                         /* Work around bug in pci/rom.c: Folks forgot to check
4243                                          * whether the size retrieved from the BIOS image eventually
4244                                          * is larger than the mapped size
4245                                          */
4246                                         if(pci_resource_len(pdev, PCI_ROM_RESOURCE) < romsize)
4247                                                 romsize = pci_resource_len(pdev, PCI_ROM_RESOURCE);
4248
4249                                         memcpy_fromio(myrombase, rom_base,
4250                                                         (romsize > 65536) ? 65536 : romsize);
4251                                 }
4252                         }
4253                         pci_unmap_rom(pdev, rom_base);
4254                 }
4255         }
4256
4257         if(myrombase) return myrombase;
4258 #endif
4259
4260         /* Otherwise do it the conventional way. */
4261
4262 #if defined(__i386__) || defined(__x86_64__)
4263
4264         for(temp = 0x000c0000; temp < 0x000f0000; temp += 0x00001000) {
4265
4266                 rom_base = ioremap(temp, 65536);
4267                 if(!rom_base)
4268                         continue;
4269
4270                 if(!sisfb_check_rom(rom_base, ivideo)) {
4271                         iounmap(rom_base);
4272                         continue;
4273                 }
4274
4275                 if((myrombase = vmalloc(65536)))
4276                         memcpy_fromio(myrombase, rom_base, 65536);
4277
4278                 iounmap(rom_base);
4279                 break;
4280
4281         }
4282
4283 #else
4284
4285         pci_read_config_dword(pdev, PCI_ROM_ADDRESS, &temp);
4286         pci_write_config_dword(pdev, PCI_ROM_ADDRESS,
4287                         (ivideo->video_base & PCI_ROM_ADDRESS_MASK) | PCI_ROM_ADDRESS_ENABLE);
4288
4289         rom_base = ioremap(ivideo->video_base, 65536);
4290         if(rom_base) {
4291                 if(sisfb_check_rom(rom_base, ivideo)) {
4292                         if((myrombase = vmalloc(65536)))
4293                                 memcpy_fromio(myrombase, rom_base, 65536);
4294                 }
4295                 iounmap(rom_base);
4296         }
4297
4298         pci_write_config_dword(pdev, PCI_ROM_ADDRESS, temp);
4299
4300 #endif
4301
4302         return myrombase;
4303 }
4304
4305 static void __devinit
4306 sisfb_post_map_vram(struct sis_video_info *ivideo, unsigned int *mapsize,
4307                         unsigned int min)
4308 {
4309         ivideo->video_vbase = ioremap(ivideo->video_base, (*mapsize));
4310
4311         if(!ivideo->video_vbase) {
4312                 printk(KERN_ERR
4313                         "sisfb: Unable to map maximum video RAM for size detection\n");
4314                 (*mapsize) >>= 1;
4315                 while((!(ivideo->video_vbase = ioremap(ivideo->video_base, (*mapsize))))) {
4316                         (*mapsize) >>= 1;
4317                         if((*mapsize) < (min << 20))
4318                                 break;
4319                 }
4320                 if(ivideo->video_vbase) {
4321                         printk(KERN_ERR
4322                                 "sisfb: Video RAM size detection limited to %dMB\n",
4323                                 (int)((*mapsize) >> 20));
4324                 }
4325         }
4326 }
4327
4328 #ifdef CONFIG_FB_SIS_300
4329 static int __devinit
4330 sisfb_post_300_buswidth(struct sis_video_info *ivideo)
4331 {
4332         SIS_IOTYPE1 *FBAddress = ivideo->video_vbase;
4333         unsigned short temp;
4334         unsigned char reg;
4335         int i, j;
4336
4337         andSISIDXREG(SISSR, 0x15, 0xFB);
4338         orSISIDXREG(SISSR, 0x15, 0x04);
4339         outSISIDXREG(SISSR, 0x13, 0x00);
4340         outSISIDXREG(SISSR, 0x14, 0xBF);
4341
4342         for(i = 0; i < 2; i++) {
4343                 temp = 0x1234;
4344                 for(j = 0; j < 4; j++) {
4345                         writew(temp, FBAddress);
4346                         if(readw(FBAddress) == temp)
4347                                 break;
4348                         orSISIDXREG(SISSR, 0x3c, 0x01);
4349                         inSISIDXREG(SISSR, 0x05, reg);
4350                         inSISIDXREG(SISSR, 0x05, reg);
4351                         andSISIDXREG(SISSR, 0x3c, 0xfe);
4352                         inSISIDXREG(SISSR, 0x05, reg);
4353                         inSISIDXREG(SISSR, 0x05, reg);
4354                         temp++;
4355                 }
4356         }
4357
4358         writel(0x01234567L, FBAddress);
4359         writel(0x456789ABL, (FBAddress + 4));
4360         writel(0x89ABCDEFL, (FBAddress + 8));
4361         writel(0xCDEF0123L, (FBAddress + 12));
4362
4363         inSISIDXREG(SISSR, 0x3b, reg);
4364         if(reg & 0x01) {
4365                 if(readl((FBAddress + 12)) == 0xCDEF0123L)
4366                         return 4;       /* Channel A 128bit */
4367         }
4368
4369         if(readl((FBAddress + 4)) == 0x456789ABL)
4370                 return 2;               /* Channel B 64bit */
4371
4372         return 1;                       /* 32bit */
4373 }
4374
4375 static int __devinit
4376 sisfb_post_300_rwtest(struct sis_video_info *ivideo, int iteration, int buswidth,
4377                         int PseudoRankCapacity, int PseudoAdrPinCount,
4378                         unsigned int mapsize)
4379 {
4380         SIS_IOTYPE1 *FBAddr = ivideo->video_vbase;
4381         unsigned short sr14;
4382         unsigned int k, RankCapacity, PageCapacity, BankNumHigh, BankNumMid;
4383         unsigned int PhysicalAdrOtherPage, PhysicalAdrHigh, PhysicalAdrHalfPage;
4384         static const unsigned short SiS_DRAMType[17][5] = {
4385                 {0x0C,0x0A,0x02,0x40,0x39},
4386                 {0x0D,0x0A,0x01,0x40,0x48},
4387                 {0x0C,0x09,0x02,0x20,0x35},
4388                 {0x0D,0x09,0x01,0x20,0x44},
4389                 {0x0C,0x08,0x02,0x10,0x31},
4390                 {0x0D,0x08,0x01,0x10,0x40},
4391                 {0x0C,0x0A,0x01,0x20,0x34},
4392                 {0x0C,0x09,0x01,0x08,0x32},
4393                 {0x0B,0x08,0x02,0x08,0x21},
4394                 {0x0C,0x08,0x01,0x08,0x30},
4395                 {0x0A,0x08,0x02,0x04,0x11},
4396                 {0x0B,0x0A,0x01,0x10,0x28},
4397                 {0x09,0x08,0x02,0x02,0x01},
4398                 {0x0B,0x09,0x01,0x08,0x24},
4399                 {0x0B,0x08,0x01,0x04,0x20},
4400                 {0x0A,0x08,0x01,0x02,0x10},
4401                 {0x09,0x08,0x01,0x01,0x00}
4402         };
4403
4404          for(k = 0; k <= 16; k++) {
4405
4406                 RankCapacity = buswidth * SiS_DRAMType[k][3];
4407
4408                 if(RankCapacity != PseudoRankCapacity)
4409                         continue;
4410
4411                 if((SiS_DRAMType[k][2] + SiS_DRAMType[k][0]) > PseudoAdrPinCount)
4412                         continue;
4413
4414                 BankNumHigh = RankCapacity * 16 * iteration - 1;
4415                 if(iteration == 3) {             /* Rank No */
4416                         BankNumMid  = RankCapacity * 16 - 1;
4417                 } else {
4418                         BankNumMid  = RankCapacity * 16 * iteration / 2 - 1;
4419                 }
4420
4421                 PageCapacity = (1 << SiS_DRAMType[k][1]) * buswidth * 4;
4422                 PhysicalAdrHigh = BankNumHigh;
4423                 PhysicalAdrHalfPage = (PageCapacity / 2 + PhysicalAdrHigh) % PageCapacity;
4424                 PhysicalAdrOtherPage = PageCapacity * SiS_DRAMType[k][2] + PhysicalAdrHigh;
4425
4426                 andSISIDXREG(SISSR, 0x15, 0xFB); /* Test */
4427                 orSISIDXREG(SISSR, 0x15, 0x04);  /* Test */
4428                 sr14 = (SiS_DRAMType[k][3] * buswidth) - 1;
4429                 if(buswidth == 4)      sr14 |= 0x80;
4430                 else if(buswidth == 2) sr14 |= 0x40;
4431                 outSISIDXREG(SISSR, 0x13, SiS_DRAMType[k][4]);
4432                 outSISIDXREG(SISSR, 0x14, sr14);
4433
4434                 BankNumHigh <<= 16;
4435                 BankNumMid <<= 16;
4436
4437                 if((BankNumHigh + PhysicalAdrHigh      >= mapsize) ||
4438                    (BankNumMid  + PhysicalAdrHigh      >= mapsize) ||
4439                    (BankNumHigh + PhysicalAdrHalfPage  >= mapsize) ||
4440                    (BankNumHigh + PhysicalAdrOtherPage >= mapsize))
4441                         continue;
4442
4443                 /* Write data */
4444                 writew(((unsigned short)PhysicalAdrHigh),
4445                                 (FBAddr + BankNumHigh + PhysicalAdrHigh));
4446                 writew(((unsigned short)BankNumMid),
4447                                 (FBAddr + BankNumMid  + PhysicalAdrHigh));
4448                 writew(((unsigned short)PhysicalAdrHalfPage),
4449                                 (FBAddr + BankNumHigh + PhysicalAdrHalfPage));
4450                 writew(((unsigned short)PhysicalAdrOtherPage),
4451                                 (FBAddr + BankNumHigh + PhysicalAdrOtherPage));
4452
4453                 /* Read data */
4454                 if(readw(FBAddr + BankNumHigh + PhysicalAdrHigh) == PhysicalAdrHigh)
4455                         return 1;
4456         }
4457
4458         return 0;
4459 }
4460
4461 static void __devinit
4462 sisfb_post_300_ramsize(struct pci_dev *pdev, unsigned int mapsize)
4463 {
4464         struct  sis_video_info *ivideo = pci_get_drvdata(pdev);
4465         int     i, j, buswidth;
4466         int     PseudoRankCapacity, PseudoAdrPinCount;
4467
4468         buswidth = sisfb_post_300_buswidth(ivideo);
4469
4470         for(i = 6; i >= 0; i--) {
4471                 PseudoRankCapacity = 1 << i;
4472                 for(j = 4; j >= 1; j--) {
4473                         PseudoAdrPinCount = 15 - j;
4474                         if((PseudoRankCapacity * j) <= 64) {
4475                                 if(sisfb_post_300_rwtest(ivideo,
4476                                                 j,
4477                                                 buswidth,
4478                                                 PseudoRankCapacity,
4479                                                 PseudoAdrPinCount,
4480                                                 mapsize))
4481                                         return;
4482                         }
4483                 }
4484         }
4485 }
4486
4487 static void __devinit
4488 sisfb_post_sis300(struct pci_dev *pdev)
4489 {
4490         struct sis_video_info *ivideo = pci_get_drvdata(pdev);
4491         unsigned char *bios = ivideo->SiS_Pr.VirtualRomBase;
4492         u8  reg, v1, v2, v3, v4, v5, v6, v7, v8;
4493         u16 index, rindex, memtype = 0;
4494         unsigned int mapsize;
4495
4496         if(!ivideo->SiS_Pr.UseROM)
4497                 bios = NULL;
4498
4499         outSISIDXREG(SISSR, 0x05, 0x86);
4500
4501         if(bios) {
4502                 if(bios[0x52] & 0x80) {
4503                         memtype = bios[0x52];
4504                 } else {
4505                         inSISIDXREG(SISSR, 0x3a, memtype);
4506                 }
4507                 memtype &= 0x07;
4508         }
4509
4510         v3 = 0x80; v6 = 0x80;
4511         if(ivideo->revision_id <= 0x13) {
4512                 v1 = 0x44; v2 = 0x42;
4513                 v4 = 0x44; v5 = 0x42;
4514         } else {
4515                 v1 = 0x68; v2 = 0x43; /* Assume 125Mhz MCLK */
4516                 v4 = 0x68; v5 = 0x43; /* Assume 125Mhz ECLK */
4517                 if(bios) {
4518                         index = memtype * 5;
4519                         rindex = index + 0x54;
4520                         v1 = bios[rindex++];
4521                         v2 = bios[rindex++];
4522                         v3 = bios[rindex++];
4523                         rindex = index + 0x7c;
4524                         v4 = bios[rindex++];
4525                         v5 = bios[rindex++];
4526                         v6 = bios[rindex++];
4527                 }
4528         }
4529         outSISIDXREG(SISSR, 0x28, v1);
4530         outSISIDXREG(SISSR, 0x29, v2);
4531         outSISIDXREG(SISSR, 0x2a, v3);
4532         outSISIDXREG(SISSR, 0x2e, v4);
4533         outSISIDXREG(SISSR, 0x2f, v5);
4534         outSISIDXREG(SISSR, 0x30, v6);
4535
4536         v1 = 0x10;
4537         if(bios)
4538                 v1 = bios[0xa4];
4539         outSISIDXREG(SISSR, 0x07, v1);       /* DAC speed */
4540
4541         outSISIDXREG(SISSR, 0x11, 0x0f);     /* DDC, power save */
4542
4543         v1 = 0x01; v2 = 0x43; v3 = 0x1e; v4 = 0x2a;
4544         v5 = 0x06; v6 = 0x00; v7 = 0x00; v8 = 0x00;
4545         if(bios) {
4546                 memtype += 0xa5;
4547                 v1 = bios[memtype];
4548                 v2 = bios[memtype + 8];
4549                 v3 = bios[memtype + 16];
4550                 v4 = bios[memtype + 24];
4551                 v5 = bios[memtype + 32];
4552                 v6 = bios[memtype + 40];
4553                 v7 = bios[memtype + 48];
4554                 v8 = bios[memtype + 56];
4555         }
4556         if(ivideo->revision_id >= 0x80)
4557                 v3 &= 0xfd;
4558         outSISIDXREG(SISSR, 0x15, v1);       /* Ram type (assuming 0, BIOS 0xa5 step 8) */
4559         outSISIDXREG(SISSR, 0x16, v2);
4560         outSISIDXREG(SISSR, 0x17, v3);
4561         outSISIDXREG(SISSR, 0x18, v4);
4562         outSISIDXREG(SISSR, 0x19, v5);
4563         outSISIDXREG(SISSR, 0x1a, v6);
4564         outSISIDXREG(SISSR, 0x1b, v7);
4565         outSISIDXREG(SISSR, 0x1c, v8);     /* ---- */
4566         andSISIDXREG(SISSR, 0x15 ,0xfb);
4567         orSISIDXREG(SISSR, 0x15, 0x04);
4568         if(bios) {
4569                 if(bios[0x53] & 0x02) {
4570                         orSISIDXREG(SISSR, 0x19, 0x20);
4571                 }
4572         }
4573         v1 = 0x04;                         /* DAC pedestal (BIOS 0xe5) */
4574         if(ivideo->revision_id >= 0x80)
4575                 v1 |= 0x01;
4576         outSISIDXREG(SISSR, 0x1f, v1);
4577         outSISIDXREG(SISSR, 0x20, 0xa4);     /* linear & relocated io & disable a0000 */
4578         v1 = 0xf6; v2 = 0x0d; v3 = 0x00;
4579         if(bios) {
4580                 v1 = bios[0xe8];
4581                 v2 = bios[0xe9];
4582                 v3 = bios[0xea];
4583         }
4584         outSISIDXREG(SISSR, 0x23, v1);
4585         outSISIDXREG(SISSR, 0x24, v2);
4586         outSISIDXREG(SISSR, 0x25, v3);
4587         outSISIDXREG(SISSR, 0x21, 0x84);
4588         outSISIDXREG(SISSR, 0x22, 0x00);
4589         outSISIDXREG(SISCR, 0x37, 0x00);
4590         orSISIDXREG(SISPART1, 0x24, 0x01);   /* unlock crt2 */
4591         outSISIDXREG(SISPART1, 0x00, 0x00);
4592         v1 = 0x40; v2 = 0x11;
4593         if(bios) {
4594                 v1 = bios[0xec];
4595                 v2 = bios[0xeb];
4596         }
4597         outSISIDXREG(SISPART1, 0x02, v1);
4598
4599         if(ivideo->revision_id >= 0x80)
4600                 v2 &= ~0x01;
4601
4602         inSISIDXREG(SISPART4, 0x00, reg);
4603         if((reg == 1) || (reg == 2)) {
4604                 outSISIDXREG(SISCR, 0x37, 0x02);
4605                 outSISIDXREG(SISPART2, 0x00, 0x1c);
4606                 v4 = 0x00; v5 = 0x00; v6 = 0x10;
4607                 if(ivideo->SiS_Pr.UseROM) {
4608                         v4 = bios[0xf5];
4609                         v5 = bios[0xf6];
4610                         v6 = bios[0xf7];
4611                 }
4612                 outSISIDXREG(SISPART4, 0x0d, v4);
4613                 outSISIDXREG(SISPART4, 0x0e, v5);
4614                 outSISIDXREG(SISPART4, 0x10, v6);
4615                 outSISIDXREG(SISPART4, 0x0f, 0x3f);
4616                 inSISIDXREG(SISPART4, 0x01, reg);
4617                 if(reg >= 0xb0) {
4618                         inSISIDXREG(SISPART4, 0x23, reg);
4619                         reg &= 0x20;
4620                         reg <<= 1;
4621                         outSISIDXREG(SISPART4, 0x23, reg);
4622                 }
4623         } else {
4624                 v2 &= ~0x10;
4625         }
4626         outSISIDXREG(SISSR, 0x32, v2);
4627
4628         andSISIDXREG(SISPART1, 0x24, 0xfe);  /* Lock CRT2 */
4629
4630         inSISIDXREG(SISSR, 0x16, reg);
4631         reg &= 0xc3;
4632         outSISIDXREG(SISCR, 0x35, reg);
4633         outSISIDXREG(SISCR, 0x83, 0x00);
4634 #if !defined(__i386__) && !defined(__x86_64__)
4635         if(sisfb_videoram) {
4636                 outSISIDXREG(SISSR, 0x13, 0x28);  /* ? */
4637                 reg = ((sisfb_videoram >> 10) - 1) | 0x40;
4638                 outSISIDXREG(SISSR, 0x14, reg);
4639         } else {
4640 #endif
4641                 /* Need to map max FB size for finding out about RAM size */
4642                 mapsize = 64 << 20;
4643                 sisfb_post_map_vram(ivideo, &mapsize, 4);
4644
4645                 if(ivideo->video_vbase) {
4646                         sisfb_post_300_ramsize(pdev, mapsize);
4647                         iounmap(ivideo->video_vbase);
4648                 } else {
4649                         printk(KERN_DEBUG
4650                                 "sisfb: Failed to map memory for size detection, assuming 8MB\n");
4651                         outSISIDXREG(SISSR, 0x13, 0x28);  /* ? */
4652                         outSISIDXREG(SISSR, 0x14, 0x47);  /* 8MB, 64bit default */
4653                 }
4654 #if !defined(__i386__) && !defined(__x86_64__)
4655         }
4656 #endif
4657         if(bios) {
4658                 v1 = bios[0xe6];
4659                 v2 = bios[0xe7];
4660         } else {
4661                 inSISIDXREG(SISSR, 0x3a, reg);
4662                 if((reg & 0x30) == 0x30) {
4663                         v1 = 0x04; /* PCI */
4664                         v2 = 0x92;
4665                 } else {
4666                         v1 = 0x14; /* AGP */
4667                         v2 = 0xb2;
4668                 }
4669         }
4670         outSISIDXREG(SISSR, 0x21, v1);
4671         outSISIDXREG(SISSR, 0x22, v2);
4672
4673         /* Sense CRT1 */
4674         sisfb_sense_crt1(ivideo);
4675
4676         /* Set default mode, don't clear screen */
4677         ivideo->SiS_Pr.SiS_UseOEM = FALSE;
4678         SiS_SetEnableDstn(&ivideo->SiS_Pr, FALSE);
4679         SiS_SetEnableFstn(&ivideo->SiS_Pr, FALSE);
4680         ivideo->curFSTN = ivideo->curDSTN = 0;
4681         ivideo->SiS_Pr.VideoMemorySize = 8 << 20;
4682         SiSSetMode(&ivideo->SiS_Pr, 0x2e | 0x80);
4683
4684         outSISIDXREG(SISSR, 0x05, 0x86);
4685
4686         /* Display off */
4687         orSISIDXREG(SISSR, 0x01, 0x20);
4688
4689         /* Save mode number in CR34 */
4690         outSISIDXREG(SISCR, 0x34, 0x2e);
4691
4692         /* Let everyone know what the current mode is */
4693         ivideo->modeprechange = 0x2e;
4694 }
4695 #endif
4696
4697 #ifdef CONFIG_FB_SIS_315
4698 #if 0
4699 static void __devinit
4700 sisfb_post_sis315330(struct pci_dev *pdev)
4701 {
4702         /* TODO */
4703 }
4704 #endif
4705
4706 static void __devinit
4707 sisfb_post_xgi_delay(struct sis_video_info *ivideo, int delay)
4708 {
4709         unsigned int i;
4710         u8 reg;
4711
4712         for(i = 0; i <= (delay * 10 * 36); i++) {
4713                 inSISIDXREG(SISSR, 0x05, reg);
4714                 reg++;
4715         }
4716 }
4717
4718 static int __devinit
4719 sisfb_find_host_bridge(struct sis_video_info *ivideo, struct pci_dev *mypdev,
4720                                 unsigned short pcivendor)
4721 {
4722         struct pci_dev *pdev = NULL;
4723         unsigned short temp;
4724         int ret = 0;
4725
4726         while((pdev = SIS_PCI_GET_CLASS(PCI_CLASS_BRIDGE_HOST, pdev))) {
4727                 temp = pdev->vendor;
4728                 SIS_PCI_PUT_DEVICE(pdev);
4729                 if(temp == pcivendor) {
4730                         ret = 1;
4731                         break;
4732                 }
4733         }
4734
4735         return ret;
4736 }
4737
4738 static int __devinit
4739 sisfb_post_xgi_rwtest(struct sis_video_info *ivideo, int starta,
4740                         unsigned int enda, unsigned int mapsize)
4741 {
4742         unsigned int pos;
4743         int i;
4744
4745         writel(0, ivideo->video_vbase);
4746
4747         for(i = starta; i <= enda; i++) {
4748                 pos = 1 << i;
4749                 if(pos < mapsize)
4750                         writel(pos, ivideo->video_vbase + pos);
4751         }
4752
4753         sisfb_post_xgi_delay(ivideo, 150);
4754
4755         if(readl(ivideo->video_vbase) != 0)
4756                 return 0;
4757
4758         for(i = starta; i <= enda; i++) {
4759                 pos = 1 << i;
4760                 if(pos < mapsize) {
4761                         if(readl(ivideo->video_vbase + pos) != pos)
4762                                 return 0;
4763                 } else
4764                         return 0;
4765         }
4766
4767         return 1;
4768 }
4769
4770 static void __devinit
4771 sisfb_post_xgi_ramsize(struct sis_video_info *ivideo)
4772 {
4773         unsigned int buswidth, ranksize, channelab, mapsize;
4774         int i, j, k, l;
4775         u8 reg, sr14;
4776         static const u8 dramsr13[12 * 5] = {
4777                 0x02, 0x0e, 0x0b, 0x80, 0x5d,
4778                 0x02, 0x0e, 0x0a, 0x40, 0x59,
4779                 0x02, 0x0d, 0x0b, 0x40, 0x4d,
4780                 0x02, 0x0e, 0x09, 0x20, 0x55,
4781                 0x02, 0x0d, 0x0a, 0x20, 0x49,
4782                 0x02, 0x0c, 0x0b, 0x20, 0x3d,
4783                 0x02, 0x0e, 0x08, 0x10, 0x51,
4784                 0x02, 0x0d, 0x09, 0x10, 0x45,
4785                 0x02, 0x0c, 0x0a, 0x10, 0x39,
4786                 0x02, 0x0d, 0x08, 0x08, 0x41,
4787                 0x02, 0x0c, 0x09, 0x08, 0x35,
4788                 0x02, 0x0c, 0x08, 0x04, 0x31
4789         };
4790         static const u8 dramsr13_4[4 * 5] = {
4791                 0x02, 0x0d, 0x09, 0x40, 0x45,
4792                 0x02, 0x0c, 0x09, 0x20, 0x35,
4793                 0x02, 0x0c, 0x08, 0x10, 0x31,
4794                 0x02, 0x0b, 0x08, 0x08, 0x21
4795         };
4796
4797         /* Enable linear mode, disable 0xa0000 address decoding */
4798         /* We disable a0000 address decoding, because
4799          * - if running on x86, if the card is disabled, it means
4800          *   that another card is in the system. We don't want
4801          *   to interphere with that primary card's textmode.
4802          * - if running on non-x86, there usually is no VGA window
4803          *   at a0000.
4804          */
4805         orSISIDXREG(SISSR, 0x20, (0x80 | 0x04));
4806
4807         /* Need to map max FB size for finding out about RAM size */
4808         mapsize = 256 << 20;
4809         sisfb_post_map_vram(ivideo, &mapsize, 32);
4810
4811         if(!ivideo->video_vbase) {
4812                 printk(KERN_ERR "sisfb: Unable to detect RAM size. Setting default.\n");
4813                 outSISIDXREG(SISSR, 0x13, 0x35);
4814                 outSISIDXREG(SISSR, 0x14, 0x41);
4815                 /* TODO */
4816                 return;
4817         }
4818
4819         /* Non-interleaving */
4820         outSISIDXREG(SISSR, 0x15, 0x00);
4821         /* No tiling */
4822         outSISIDXREG(SISSR, 0x1c, 0x00);
4823
4824         if(ivideo->chip == XGI_20) {
4825
4826                 channelab = 1;
4827                 inSISIDXREG(SISCR, 0x97, reg);
4828                 if(!(reg & 0x01)) {     /* Single 32/16 */
4829                         buswidth = 32;
4830                         outSISIDXREG(SISSR, 0x13, 0xb1);
4831                         outSISIDXREG(SISSR, 0x14, 0x52);
4832                         sisfb_post_xgi_delay(ivideo, 1);
4833                         sr14 = 0x02;
4834                         if(sisfb_post_xgi_rwtest(ivideo, 23, 24, mapsize))
4835                                 goto bail_out;
4836
4837                         outSISIDXREG(SISSR, 0x13, 0x31);
4838                         outSISIDXREG(SISSR, 0x14, 0x42);
4839                         sisfb_post_xgi_delay(ivideo, 1);
4840                         if(sisfb_post_xgi_rwtest(ivideo, 23, 23, mapsize))
4841                                 goto bail_out;
4842
4843                         buswidth = 16;
4844                         outSISIDXREG(SISSR, 0x13, 0xb1);
4845                         outSISIDXREG(SISSR, 0x14, 0x41);
4846                         sisfb_post_xgi_delay(ivideo, 1);
4847                         sr14 = 0x01;
4848                         if(sisfb_post_xgi_rwtest(ivideo, 22, 23, mapsize))
4849                                 goto bail_out;
4850                         else
4851                                 outSISIDXREG(SISSR, 0x13, 0x31);
4852                 } else {                /* Dual 16/8 */
4853                         buswidth = 16;
4854                         outSISIDXREG(SISSR, 0x13, 0xb1);
4855                         outSISIDXREG(SISSR, 0x14, 0x41);
4856                         sisfb_post_xgi_delay(ivideo, 1);
4857                         sr14 = 0x01;
4858                         if(sisfb_post_xgi_rwtest(ivideo, 22, 23, mapsize))
4859                                 goto bail_out;
4860
4861                         outSISIDXREG(SISSR, 0x13, 0x31);
4862                         outSISIDXREG(SISSR, 0x14, 0x31);
4863                         sisfb_post_xgi_delay(ivideo, 1);
4864                         if(sisfb_post_xgi_rwtest(ivideo, 22, 22, mapsize))
4865                                 goto bail_out;
4866
4867                         buswidth = 8;
4868                         outSISIDXREG(SISSR, 0x13, 0xb1);
4869                         outSISIDXREG(SISSR, 0x14, 0x30);
4870                         sisfb_post_xgi_delay(ivideo, 1);
4871                         sr14 = 0x00;
4872                         if(sisfb_post_xgi_rwtest(ivideo, 21, 22, mapsize))
4873                                 goto bail_out;
4874                         else
4875                                 outSISIDXREG(SISSR, 0x13, 0x31);
4876                 }
4877
4878         } else {        /* XGI_40 */
4879
4880                 inSISIDXREG(SISCR, 0x97, reg);
4881                 if(!(reg & 0x10)) {
4882                         inSISIDXREG(SISSR, 0x39, reg);
4883                         reg >>= 1;
4884                 }
4885
4886                 if(reg & 0x01) {        /* DDRII */
4887                         buswidth = 32;
4888                         if(ivideo->revision_id == 2) {
4889                                 channelab = 2;
4890                                 outSISIDXREG(SISSR, 0x13, 0xa1);
4891                                 outSISIDXREG(SISSR, 0x14, 0x44);
4892                                 sr14 = 0x04;
4893                                 sisfb_post_xgi_delay(ivideo, 1);
4894                                 if(sisfb_post_xgi_rwtest(ivideo, 23, 24, mapsize))
4895                                         goto bail_out;
4896
4897                                 outSISIDXREG(SISSR, 0x13, 0x21);
4898                                 outSISIDXREG(SISSR, 0x14, 0x34);
4899                                 if(sisfb_post_xgi_rwtest(ivideo, 22, 23, mapsize))
4900                                         goto bail_out;
4901
4902                                 channelab = 1;
4903                                 outSISIDXREG(SISSR, 0x13, 0xa1);
4904                                 outSISIDXREG(SISSR, 0x14, 0x40);
4905                                 sr14 = 0x00;
4906                                 if(sisfb_post_xgi_rwtest(ivideo, 22, 23, mapsize))
4907                                         goto bail_out;
4908
4909                                 outSISIDXREG(SISSR, 0x13, 0x21);
4910                                 outSISIDXREG(SISSR, 0x14, 0x30);
4911                         } else {
4912                                 channelab = 3;
4913                                 outSISIDXREG(SISSR, 0x13, 0xa1);
4914                                 outSISIDXREG(SISSR, 0x14, 0x4c);
4915                                 sr14 = 0x0c;
4916                                 sisfb_post_xgi_delay(ivideo, 1);
4917                                 if(sisfb_post_xgi_rwtest(ivideo, 23, 25, mapsize))
4918                                         goto bail_out;
4919
4920                                 channelab = 2;
4921                                 outSISIDXREG(SISSR, 0x14, 0x48);
4922                                 sisfb_post_xgi_delay(ivideo, 1);
4923                                 sr14 = 0x08;
4924                                 if(sisfb_post_xgi_rwtest(ivideo, 23, 24, mapsize))
4925                                         goto bail_out;
4926
4927                                 outSISIDXREG(SISSR, 0x13, 0x21);
4928                                 outSISIDXREG(SISSR, 0x14, 0x3c);
4929                                 sr14 = 0x0c;
4930
4931                                 if(sisfb_post_xgi_rwtest(ivideo, 23, 24, mapsize)) {
4932                                         channelab = 3;
4933                                 } else {
4934                                         channelab = 2;
4935                                         outSISIDXREG(SISSR, 0x14, 0x38);
4936                                         sr14 = 0x08;
4937                                 }
4938                         }
4939                         sisfb_post_xgi_delay(ivideo, 1);
4940
4941                 } else {        /* DDR */
4942
4943                         buswidth = 64;
4944                         if(ivideo->revision_id == 2) {
4945                                 channelab = 1;
4946                                 outSISIDXREG(SISSR, 0x13, 0xa1);
4947                                 outSISIDXREG(SISSR, 0x14, 0x52);
4948                                 sisfb_post_xgi_delay(ivideo, 1);
4949                                 sr14 = 0x02;
4950                                 if(sisfb_post_xgi_rwtest(ivideo, 23, 24, mapsize))
4951                                         goto bail_out;
4952
4953                                 outSISIDXREG(SISSR, 0x13, 0x21);
4954                                 outSISIDXREG(SISSR, 0x14, 0x42);
4955                         } else {
4956                                 channelab = 2;
4957                                 outSISIDXREG(SISSR, 0x13, 0xa1);
4958                                 outSISIDXREG(SISSR, 0x14, 0x5a);
4959                                 sisfb_post_xgi_delay(ivideo, 1);
4960                                 sr14 = 0x0a;
4961                                 if(sisfb_post_xgi_rwtest(ivideo, 24, 25, mapsize))
4962                                         goto bail_out;
4963
4964                                 outSISIDXREG(SISSR, 0x13, 0x21);
4965                                 outSISIDXREG(SISSR, 0x14, 0x4a);
4966                         }
4967                         sisfb_post_xgi_delay(ivideo, 1);
4968
4969                 }
4970         }
4971
4972 bail_out:
4973         setSISIDXREG(SISSR, 0x14, 0xf0, sr14);
4974         sisfb_post_xgi_delay(ivideo, 1);
4975
4976         j = (ivideo->chip == XGI_20) ? 5 : 9;
4977         k = (ivideo->chip == XGI_20) ? 12 : 4;
4978
4979         for(i = 0; i < k; i++) {
4980
4981                 reg = (ivideo->chip == XGI_20) ?
4982                                 dramsr13[(i * 5) + 4] : dramsr13_4[(i * 5) + 4];
4983                 setSISIDXREG(SISSR, 0x13, 0x80, reg);
4984                 sisfb_post_xgi_delay(ivideo, 50);
4985
4986                 ranksize = (ivideo->chip == XGI_20) ?
4987                                 dramsr13[(i * 5) + 3] : dramsr13_4[(i * 5) + 3];
4988
4989                 inSISIDXREG(SISSR, 0x13, reg);
4990                 if(reg & 0x80) ranksize <<= 1;
4991
4992                 if(ivideo->chip == XGI_20) {
4993                         if(buswidth == 16)      ranksize <<= 1;
4994                         else if(buswidth == 32) ranksize <<= 2;
4995                 } else {
4996                         if(buswidth == 64)      ranksize <<= 1;
4997                 }
4998
4999                 reg = 0;
5000                 l = channelab;
5001                 if(l == 3) l = 4;
5002                 if((ranksize * l) <= 256) {
5003                         while((ranksize >>= 1)) reg += 0x10;
5004                 }
5005
5006                 if(!reg) continue;
5007
5008                 setSISIDXREG(SISSR, 0x14, 0x0f, (reg & 0xf0));
5009                 sisfb_post_xgi_delay(ivideo, 1);
5010
5011                 if(sisfb_post_xgi_rwtest(ivideo, j, ((reg >> 4) + channelab - 2 + 20), mapsize))
5012                         break;
5013         }
5014
5015         iounmap(ivideo->video_vbase);
5016 }
5017
5018 static void __devinit
5019 sisfb_post_xgi_setclocks(struct sis_video_info *ivideo, u8 regb)
5020 {
5021         u8 v1, v2, v3;
5022         int index;
5023         static const u8 cs90[8 * 3] = {
5024                 0x16, 0x01, 0x01,
5025                 0x3e, 0x03, 0x01,
5026                 0x7c, 0x08, 0x01,
5027                 0x79, 0x06, 0x01,
5028                 0x29, 0x01, 0x81,
5029                 0x5c, 0x23, 0x01,
5030                 0x5c, 0x23, 0x01,
5031                 0x5c, 0x23, 0x01
5032         };
5033         static const u8 csb8[8 * 3] = {
5034                 0x5c, 0x23, 0x01,
5035                 0x29, 0x01, 0x01,
5036                 0x7c, 0x08, 0x01,
5037                 0x79, 0x06, 0x01,
5038                 0x29, 0x01, 0x81,
5039                 0x5c, 0x23, 0x01,
5040                 0x5c, 0x23, 0x01,
5041                 0x5c, 0x23, 0x01
5042         };
5043
5044         regb = 0;  /* ! */
5045
5046         index = regb * 3;
5047         v1 = cs90[index]; v2 = cs90[index + 1]; v3 = cs90[index + 2];
5048         if(ivideo->haveXGIROM) {
5049                 v1 = ivideo->bios_abase[0x90 + index];
5050                 v2 = ivideo->bios_abase[0x90 + index + 1];
5051                 v3 = ivideo->bios_abase[0x90 + index + 2];
5052         }
5053         outSISIDXREG(SISSR, 0x28, v1);
5054         outSISIDXREG(SISSR, 0x29, v2);
5055         outSISIDXREG(SISSR, 0x2a, v3);
5056         sisfb_post_xgi_delay(ivideo, 0x43);
5057         sisfb_post_xgi_delay(ivideo, 0x43);
5058         sisfb_post_xgi_delay(ivideo, 0x43);
5059         index = regb * 3;
5060         v1 = csb8[index]; v2 = csb8[index + 1]; v3 = csb8[index + 2];
5061         if(ivideo->haveXGIROM) {
5062                 v1 = ivideo->bios_abase[0xb8 + index];
5063                 v2 = ivideo->bios_abase[0xb8 + index + 1];
5064                 v3 = ivideo->bios_abase[0xb8 + index + 2];
5065         }
5066         outSISIDXREG(SISSR, 0x2e, v1);
5067         outSISIDXREG(SISSR, 0x2f, v2);
5068         outSISIDXREG(SISSR, 0x30, v3);
5069         sisfb_post_xgi_delay(ivideo, 0x43);
5070         sisfb_post_xgi_delay(ivideo, 0x43);
5071         sisfb_post_xgi_delay(ivideo, 0x43);
5072 }
5073
5074 static int __devinit
5075 sisfb_post_xgi(struct pci_dev *pdev)
5076 {
5077         struct sis_video_info *ivideo = pci_get_drvdata(pdev);
5078         unsigned char *bios = ivideo->bios_abase;
5079         struct pci_dev *mypdev = NULL;
5080         const u8 *ptr, *ptr2;
5081         u8 v1, v2, v3, v4, v5, reg, ramtype;
5082         u32 rega, regb, regd;
5083         int i, j, k, index;
5084         static const u8 cs78[3] = { 0xf6, 0x0d, 0x00 };
5085         static const u8 cs76[2] = { 0xa3, 0xfb };
5086         static const u8 cs7b[3] = { 0xc0, 0x11, 0x00 };
5087         static const u8 cs158[8] = {
5088                 0x88, 0xaa, 0x48, 0x00, 0x00, 0x00, 0x00, 0x00
5089         };
5090         static const u8 cs160[8] = {
5091                 0x44, 0x77, 0x77, 0x00, 0x00, 0x00, 0x00, 0x00
5092         };
5093         static const u8 cs168[8] = {
5094                 0x48, 0x78, 0x88, 0x00, 0x00, 0x00, 0x00, 0x00
5095         };
5096         static const u8 cs128[3 * 8] = {
5097                 0x90, 0x28, 0x24, 0x00, 0x00, 0x00, 0x00, 0x00,
5098                 0x77, 0x44, 0x44, 0x00, 0x00, 0x00, 0x00, 0x00,
5099                 0x77, 0x44, 0x44, 0x00, 0x00, 0x00, 0x00, 0x00
5100         };
5101         static const u8 cs148[2 * 8] = {
5102                 0x55, 0x55, 0x55, 0x00, 0x00, 0x00, 0x00, 0x00,
5103                 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
5104         };
5105         static const u8 cs31a[8 * 4] = {
5106                 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
5107                 0xaa, 0xaa, 0xaa, 0xaa, 0x00, 0x00, 0x00, 0x00,
5108                 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
5109                 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
5110         };
5111         static const u8 cs33a[8 * 4] = {
5112                 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
5113                 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
5114                 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
5115                 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
5116         };
5117         static const u8 cs45a[8 * 2] = {
5118                 0x00, 0x00, 0xa0, 0x00, 0xa0, 0x00, 0x00, 0x00,
5119                 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
5120         };
5121         static const u8 cs170[7 * 8] = {
5122                 0x54, 0x32, 0x44, 0x00, 0x00, 0x00, 0x00, 0x00,
5123                 0x54, 0x43, 0x44, 0x00, 0x00, 0x00, 0x00, 0x00,
5124                 0x0a, 0x05, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00,
5125                 0x44, 0x34, 0x44, 0x00, 0x00, 0x00, 0x00, 0x00,
5126                 0x10, 0x0a, 0x0a, 0x00, 0x00, 0x00, 0x00, 0x00,
5127                 0x11, 0x0c, 0x0c, 0x00, 0x00, 0x00, 0x00, 0x00,
5128                 0x05, 0x05, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00
5129         };
5130         static const u8 cs1a8[3 * 8] = {
5131                 0xf0, 0xf0, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x00,
5132                 0x05, 0x02, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00,
5133                 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
5134         };
5135         static const u8 cs100[2 * 8] = {
5136                 0xc4, 0x04, 0x84, 0x00, 0x00, 0x00, 0x00, 0x00,
5137                 0xc4, 0x04, 0x84, 0x00, 0x00, 0x00, 0x00, 0x00
5138         };
5139
5140         /* VGA enable */
5141         reg = inSISREG(SISVGAENABLE) | 0x01;
5142         outSISREG(SISVGAENABLE, reg);
5143
5144         /* Misc */
5145         reg = inSISREG(SISMISCR) | 0x01;
5146         outSISREG(SISMISCW, reg);
5147
5148         /* Unlock SR */
5149         outSISIDXREG(SISSR, 0x05, 0x86);
5150         inSISIDXREG(SISSR, 0x05, reg);
5151         if(reg != 0xa1)
5152                 return 0;
5153
5154         /* Clear some regs */
5155         for(i = 0; i < 0x22; i++) {
5156                 if(0x06 + i == 0x20) continue;
5157                 outSISIDXREG(SISSR, 0x06 + i, 0x00);
5158         }
5159         for(i = 0; i < 0x0b; i++) {
5160                 outSISIDXREG(SISSR, 0x31 + i, 0x00);
5161         }
5162         for(i = 0; i < 0x10; i++) {
5163                 outSISIDXREG(SISCR, 0x30 + i, 0x00);
5164         }
5165
5166         ptr = cs78;
5167         if(ivideo->haveXGIROM) {
5168                 ptr = (const u8 *)&bios[0x78];
5169         }
5170         for(i = 0; i < 3; i++) {
5171                 outSISIDXREG(SISSR, 0x23 + i, ptr[i]);
5172         }
5173
5174         ptr = cs76;
5175         if(ivideo->haveXGIROM) {
5176                 ptr = (const u8 *)&bios[0x76];
5177         }
5178         for(i = 0; i < 2; i++) {
5179                 outSISIDXREG(SISSR, 0x21 + i, ptr[i]);
5180         }
5181
5182         v1 = 0x18; v2 = 0x00;
5183         if(ivideo->haveXGIROM) {
5184                 v1 = bios[0x74];
5185                 v2 = bios[0x75];
5186         }
5187         outSISIDXREG(SISSR, 0x07, v1);
5188         outSISIDXREG(SISSR, 0x11, 0x0f);
5189         outSISIDXREG(SISSR, 0x1f, v2);
5190         /* PCI linear mode, RelIO enabled, A0000 decoding disabled */
5191         outSISIDXREG(SISSR, 0x20, 0x80 | 0x20 | 0x04);
5192         outSISIDXREG(SISSR, 0x27, 0x74);
5193
5194         ptr = cs7b;
5195         if(ivideo->haveXGIROM) {
5196                 ptr = (const u8 *)&bios[0x7b];
5197         }
5198         for(i = 0; i < 3; i++) {
5199                 outSISIDXREG(SISSR, 0x31 + i, ptr[i]);
5200         }
5201
5202         if(ivideo->chip == XGI_40) {
5203                 if(ivideo->revision_id == 2) {
5204                         setSISIDXREG(SISSR, 0x3b, 0x3f, 0xc0);
5205                 }
5206                 outSISIDXREG(SISCR, 0x7d, 0xfe);
5207                 outSISIDXREG(SISCR, 0x7e, 0x0f);
5208         }
5209         if(ivideo->revision_id == 0) {  /* 40 *and* 20? */
5210                 andSISIDXREG(SISCR, 0x58, 0xd7);
5211                 inSISIDXREG(SISCR, 0xcb, reg);
5212                 if(reg & 0x20) {
5213                         setSISIDXREG(SISCR, 0x58, 0xd7, (reg & 0x10) ? 0x08 : 0x20); /* =0x28 Z7 ? */
5214                 }
5215         }
5216
5217         reg = (ivideo->chip == XGI_40) ? 0x20 : 0x00;
5218         setSISIDXREG(SISCR, 0x38, 0x1f, reg);
5219
5220         if(ivideo->chip == XGI_20) {
5221                 outSISIDXREG(SISSR, 0x36, 0x70);
5222         } else {
5223                 outSISIDXREG(SISVID, 0x00, 0x86);
5224                 outSISIDXREG(SISVID, 0x32, 0x00);
5225                 outSISIDXREG(SISVID, 0x30, 0x00);
5226                 outSISIDXREG(SISVID, 0x32, 0x01);
5227                 outSISIDXREG(SISVID, 0x30, 0x00);
5228                 andSISIDXREG(SISVID, 0x2f, 0xdf);
5229                 andSISIDXREG(SISCAP, 0x00, 0x3f);
5230
5231                 outSISIDXREG(SISPART1, 0x2f, 0x01);
5232                 outSISIDXREG(SISPART1, 0x00, 0x00);
5233                 outSISIDXREG(SISPART1, 0x02, bios[0x7e]);
5234                 outSISIDXREG(SISPART1, 0x2e, 0x08);
5235                 andSISIDXREG(SISPART1, 0x35, 0x7f);
5236                 andSISIDXREG(SISPART1, 0x50, 0xfe);
5237
5238                 inSISIDXREG(SISPART4, 0x00, reg);
5239                 if(reg == 1 || reg == 2) {
5240                         outSISIDXREG(SISPART2, 0x00, 0x1c);
5241                         outSISIDXREG(SISPART4, 0x0d, bios[0x7f]);
5242                         outSISIDXREG(SISPART4, 0x0e, bios[0x80]);
5243                         outSISIDXREG(SISPART4, 0x10, bios[0x81]);
5244                         andSISIDXREG(SISPART4, 0x0f, 0x3f);
5245
5246                         inSISIDXREG(SISPART4, 0x01, reg);
5247                         if((reg & 0xf0) >= 0xb0) {
5248                                 inSISIDXREG(SISPART4, 0x23, reg);
5249                                 if(reg & 0x20) reg |= 0x40;
5250                                 outSISIDXREG(SISPART4, 0x23, reg);
5251                                 reg = (reg & 0x20) ? 0x02 : 0x00;
5252                                 setSISIDXREG(SISPART1, 0x1e, 0xfd, reg);
5253                         }
5254                 }
5255
5256                 v1 = bios[0x77];
5257
5258                 inSISIDXREG(SISSR, 0x3b, reg);
5259                 if(reg & 0x02) {
5260                         inSISIDXREG(SISSR, 0x3a, reg);
5261                         v2 = (reg & 0x30) >> 3;
5262                         if(!(v2 & 0x04)) v2 ^= 0x02;
5263                         inSISIDXREG(SISSR, 0x39, reg);
5264                         if(reg & 0x80) v2 |= 0x80;
5265                         v2 |= 0x01;
5266
5267                         if((mypdev = SIS_PCI_GET_DEVICE(PCI_VENDOR_ID_SI, 0x0730, NULL))) {
5268                                 SIS_PCI_PUT_DEVICE(mypdev);
5269                                 if(((v2 & 0x06) == 2) || ((v2 & 0x06) == 4))
5270                                         v2 &= 0xf9;
5271                                 v2 |= 0x08;
5272                                 v1 &= 0xfe;
5273                         } else {
5274                                 mypdev = SIS_PCI_GET_DEVICE(PCI_VENDOR_ID_SI, 0x0735, NULL);
5275                                 if(!mypdev)
5276                                         mypdev = SIS_PCI_GET_DEVICE(PCI_VENDOR_ID_SI, 0x0645, NULL);
5277                                 if(!mypdev)
5278                                         mypdev = SIS_PCI_GET_DEVICE(PCI_VENDOR_ID_SI, 0x0650, NULL);
5279                                 if(mypdev) {
5280                                         pci_read_config_dword(mypdev, 0x94, &regd);
5281                                         regd &= 0xfffffeff;
5282                                         pci_write_config_dword(mypdev, 0x94, regd);
5283                                         v1 &= 0xfe;
5284                                         SIS_PCI_PUT_DEVICE(mypdev);
5285                                 } else if(sisfb_find_host_bridge(ivideo, pdev, PCI_VENDOR_ID_SI)) {
5286                                         v1 &= 0xfe;
5287                                 } else if(sisfb_find_host_bridge(ivideo, pdev, 0x1106) ||
5288                                           sisfb_find_host_bridge(ivideo, pdev, 0x1022) ||
5289                                           sisfb_find_host_bridge(ivideo, pdev, 0x700e) ||
5290                                           sisfb_find_host_bridge(ivideo, pdev, 0x10de)) {
5291                                         if((v2 & 0x06) == 4)
5292                                                 v2 ^= 0x06;
5293                                         v2 |= 0x08;
5294                                 }
5295                         }
5296                         setSISIDXREG(SISCR, 0x5f, 0xf0, v2);
5297                 }
5298                 outSISIDXREG(SISSR, 0x22, v1);
5299
5300                 if(ivideo->revision_id == 2) {
5301                         inSISIDXREG(SISSR, 0x3b, v1);
5302                         inSISIDXREG(SISSR, 0x3a, v2);
5303                         regd = bios[0x90 + 3] | (bios[0x90 + 4] << 8);
5304                         if( (!(v1 & 0x02)) && (v2 & 0x30) && (regd < 0xcf) )
5305                                 setSISIDXREG(SISCR, 0x5f, 0xf1, 0x01);
5306
5307                         if((mypdev = SIS_PCI_GET_DEVICE(0x10de, 0x01e0, NULL))) {
5308                                 /* TODO: set CR5f &0xf1 | 0x01 for version 6570
5309                                  * of nforce 2 ROM
5310                                  */
5311                                 if(0)
5312                                         setSISIDXREG(SISCR, 0x5f, 0xf1, 0x01);
5313                                 SIS_PCI_PUT_DEVICE(mypdev);
5314                         }
5315                 }
5316
5317                 v1 = 0x30;
5318                 inSISIDXREG(SISSR, 0x3b, reg);
5319                 inSISIDXREG(SISCR, 0x5f, v2);
5320                 if((!(reg & 0x02)) && (v2 & 0x0e))
5321                         v1 |= 0x08;
5322                 outSISIDXREG(SISSR, 0x27, v1);
5323
5324                 if(bios[0x64] & 0x01) {
5325                         setSISIDXREG(SISCR, 0x5f, 0xf0, bios[0x64]);
5326                 }
5327
5328                 v1 = bios[0x4f7];
5329                 pci_read_config_dword(pdev, 0x50, &regd);
5330                 regd = (regd >> 20) & 0x0f;
5331                 if(regd == 1) {
5332                         v1 &= 0xfc;
5333                         orSISIDXREG(SISCR, 0x5f, 0x08);
5334                 }
5335                 outSISIDXREG(SISCR, 0x48, v1);
5336
5337                 setSISIDXREG(SISCR, 0x47, 0x04, bios[0x4f6] & 0xfb);
5338                 setSISIDXREG(SISCR, 0x49, 0xf0, bios[0x4f8] & 0x0f);
5339                 setSISIDXREG(SISCR, 0x4a, 0x60, bios[0x4f9] & 0x9f);
5340                 setSISIDXREG(SISCR, 0x4b, 0x08, bios[0x4fa] & 0xf7);
5341                 setSISIDXREG(SISCR, 0x4c, 0x80, bios[0x4fb] & 0x7f);
5342                 outSISIDXREG(SISCR, 0x70, bios[0x4fc]);
5343                 setSISIDXREG(SISCR, 0x71, 0xf0, bios[0x4fd] & 0x0f);
5344                 outSISIDXREG(SISCR, 0x74, 0xd0);
5345                 setSISIDXREG(SISCR, 0x74, 0xcf, bios[0x4fe] & 0x30);
5346                 setSISIDXREG(SISCR, 0x75, 0xe0, bios[0x4ff] & 0x1f);
5347                 setSISIDXREG(SISCR, 0x76, 0xe0, bios[0x500] & 0x1f);
5348                 v1 = bios[0x501];
5349                 if((mypdev = SIS_PCI_GET_DEVICE(0x8086, 0x2530, NULL))) {
5350                         v1 = 0xf0;
5351                         SIS_PCI_PUT_DEVICE(mypdev);
5352                 }
5353                 outSISIDXREG(SISCR, 0x77, v1);
5354         }
5355
5356         /* RAM type */
5357
5358         regb = 0;       /* ! */
5359
5360         v1 = 0xff;
5361         if(ivideo->haveXGIROM) {
5362                 v1 = bios[0x140 + regb];
5363         }
5364         outSISIDXREG(SISCR, 0x6d, v1);
5365
5366         ptr = cs128;
5367         if(ivideo->haveXGIROM) {
5368                 ptr = (const u8 *)&bios[0x128];
5369         }
5370         for(i = 0, j = 0; i < 3; i++, j += 8) {
5371                 outSISIDXREG(SISCR, 0x68 + i, ptr[j + regb]);
5372         }
5373
5374         ptr  = cs31a;
5375         ptr2 = cs33a;
5376         if(ivideo->haveXGIROM) {
5377                 index = (ivideo->chip == XGI_20) ? 0x31a : 0x3a6;
5378                 ptr  = (const u8 *)&bios[index];
5379                 ptr2 = (const u8 *)&bios[index + 0x20];
5380         }
5381         for(i = 0; i < 2; i++) {
5382                 if(i == 0) {
5383                         regd = le32_to_cpu(((u32 *)ptr)[regb]);
5384                         rega = 0x6b;
5385                 } else {
5386                         regd = le32_to_cpu(((u32 *)ptr2)[regb]);
5387                         rega = 0x6e;
5388                 }
5389                 reg = 0x00;
5390                 for(j = 0; j < 16; j++) {
5391                         reg &= 0xf3;
5392                         if(regd & 0x01) reg |= 0x04;
5393                         if(regd & 0x02) reg |= 0x08;
5394                         regd >>= 2;
5395                         outSISIDXREG(SISCR, rega, reg);
5396                         inSISIDXREG(SISCR, rega, reg);
5397                         inSISIDXREG(SISCR, rega, reg);
5398                         reg += 0x10;
5399                 }
5400         }
5401
5402         andSISIDXREG(SISCR, 0x6e, 0xfc);
5403
5404         ptr  = NULL;
5405         if(ivideo->haveXGIROM) {
5406                 index = (ivideo->chip == XGI_20) ? 0x35a : 0x3e6;
5407                 ptr  = (const u8 *)&bios[index];
5408         }
5409         for(i = 0; i < 4; i++) {
5410                 setSISIDXREG(SISCR, 0x6e, 0xfc, i);
5411                 reg = 0x00;
5412                 for(j = 0; j < 2; j++) {
5413                         regd = 0;
5414                         if(ptr) {
5415                                 regd = le32_to_cpu(((u32 *)ptr)[regb * 8]);
5416                                 ptr += 4;
5417                         }
5418                         /* reg = 0x00; */
5419                         for(k = 0; k < 16; k++) {
5420                                 reg &= 0xfc;
5421                                 if(regd & 0x01) reg |= 0x01;
5422                                 if(regd & 0x02) reg |= 0x02;
5423                                 regd >>= 2;
5424                                 outSISIDXREG(SISCR, 0x6f, reg);
5425                                 inSISIDXREG(SISCR, 0x6f, reg);
5426                                 inSISIDXREG(SISCR, 0x6f, reg);
5427                                 reg += 0x08;
5428                         }
5429                 }
5430         }
5431
5432         ptr  = cs148;
5433         if(ivideo->haveXGIROM) {
5434                 ptr  = (const u8 *)&bios[0x148];
5435         }
5436         for(i = 0, j = 0; i < 2; i++, j += 8) {
5437                 outSISIDXREG(SISCR, 0x80 + i, ptr[j + regb]);
5438         }
5439
5440         andSISIDXREG(SISCR, 0x89, 0x8f);
5441
5442         ptr  = cs45a;
5443         if(ivideo->haveXGIROM) {
5444                 index = (ivideo->chip == XGI_20) ? 0x45a : 0x4e6;
5445                 ptr  = (const u8 *)&bios[index];
5446         }
5447         regd = le16_to_cpu(((const u16 *)ptr)[regb]);
5448         reg = 0x80;
5449         for(i = 0; i < 5; i++) {
5450                 reg &= 0xfc;
5451                 if(regd & 0x01) reg |= 0x01;
5452                 if(regd & 0x02) reg |= 0x02;
5453                 regd >>= 2;
5454                 outSISIDXREG(SISCR, 0x89, reg);
5455                 inSISIDXREG(SISCR, 0x89, reg);
5456                 inSISIDXREG(SISCR, 0x89, reg);
5457                 reg += 0x10;
5458         }
5459
5460         v1 = 0xb5; v2 = 0x20; v3 = 0xf0; v4 = 0x13;
5461         if(ivideo->haveXGIROM) {
5462                 v1 = bios[0x118 + regb];
5463                 v2 = bios[0xf8 + regb];
5464                 v3 = bios[0x120 + regb];
5465                 v4 = bios[0x1ca];
5466         }
5467         outSISIDXREG(SISCR, 0x45, v1 & 0x0f);
5468         outSISIDXREG(SISCR, 0x99, (v1 >> 4) & 0x07);
5469         orSISIDXREG(SISCR, 0x40, v1 & 0x80);
5470         outSISIDXREG(SISCR, 0x41, v2);
5471
5472         ptr  = cs170;
5473         if(ivideo->haveXGIROM) {
5474                 ptr  = (const u8 *)&bios[0x170];
5475         }
5476         for(i = 0, j = 0; i < 7; i++, j += 8) {
5477                 outSISIDXREG(SISCR, 0x90 + i, ptr[j + regb]);
5478         }
5479
5480         outSISIDXREG(SISCR, 0x59, v3);
5481
5482         ptr  = cs1a8;
5483         if(ivideo->haveXGIROM) {
5484                 ptr  = (const u8 *)&bios[0x1a8];
5485         }
5486         for(i = 0, j = 0; i < 3; i++, j += 8) {
5487                 outSISIDXREG(SISCR, 0xc3 + i, ptr[j + regb]);
5488         }
5489
5490         ptr  = cs100;
5491         if(ivideo->haveXGIROM) {
5492                 ptr  = (const u8 *)&bios[0x100];
5493         }
5494         for(i = 0, j = 0; i < 2; i++, j += 8) {
5495                 outSISIDXREG(SISCR, 0x8a + i, ptr[j + regb]);
5496         }
5497
5498         outSISIDXREG(SISCR, 0xcf, v4);
5499
5500         outSISIDXREG(SISCR, 0x83, 0x09);
5501         outSISIDXREG(SISCR, 0x87, 0x00);
5502
5503         if(ivideo->chip == XGI_40) {
5504                 if( (ivideo->revision_id == 1) ||
5505                     (ivideo->revision_id == 2) ) {
5506                         outSISIDXREG(SISCR, 0x8c, 0x87);
5507                 }
5508         }
5509
5510         outSISIDXREG(SISSR, 0x17, 0x00);
5511         outSISIDXREG(SISSR, 0x1a, 0x87);
5512
5513         if(ivideo->chip == XGI_20) {
5514                 outSISIDXREG(SISSR, 0x15, 0x00);
5515                 outSISIDXREG(SISSR, 0x1c, 0x00);
5516         }
5517
5518         ramtype = 0x00; v1 = 0x10;
5519         if(ivideo->haveXGIROM) {
5520                 ramtype = bios[0x62];
5521                 v1 = bios[0x1d2];
5522         }
5523         if(!(ramtype & 0x80)) {
5524                 if(ivideo->chip == XGI_20) {
5525                         outSISIDXREG(SISCR, 0x97, v1);
5526                         inSISIDXREG(SISCR, 0x97, reg);
5527                         if(reg & 0x10) {
5528                                 ramtype = (reg & 0x01) << 1;
5529                         }
5530                 } else {
5531                         inSISIDXREG(SISSR, 0x39, reg);
5532                         ramtype = reg & 0x02;
5533                         if(!(ramtype)) {
5534                                 inSISIDXREG(SISSR, 0x3a, reg);
5535                                 ramtype = (reg >> 1) & 0x01;
5536                         }
5537                 }
5538         }
5539         ramtype &= 0x07;
5540
5541         regb = 0;       /* ! */
5542
5543         switch(ramtype) {
5544         case 0:
5545                 sisfb_post_xgi_setclocks(ivideo, regb);
5546                 if((ivideo->chip == XGI_20) ||
5547                    (ivideo->revision_id == 1)   ||
5548                    (ivideo->revision_id == 2)) {
5549                         v1 = cs158[regb]; v2 = cs160[regb]; v3 = cs168[regb];
5550                         if(ivideo->haveXGIROM) {
5551                                 v1 = bios[regb + 0x158];
5552                                 v2 = bios[regb + 0x160];
5553                                 v3 = bios[regb + 0x168];
5554                         }
5555                         outSISIDXREG(SISCR, 0x82, v1);
5556                         outSISIDXREG(SISCR, 0x85, v2);
5557                         outSISIDXREG(SISCR, 0x86, v3);
5558                 } else {
5559                         outSISIDXREG(SISCR, 0x82, 0x88);
5560                         outSISIDXREG(SISCR, 0x86, 0x00);
5561                         inSISIDXREG(SISCR, 0x86, reg);
5562                         outSISIDXREG(SISCR, 0x86, 0x88);
5563                         inSISIDXREG(SISCR, 0x86, reg);
5564                         outSISIDXREG(SISCR, 0x86, bios[regb + 0x168]);
5565                         outSISIDXREG(SISCR, 0x82, 0x77);
5566                         outSISIDXREG(SISCR, 0x85, 0x00);
5567                         inSISIDXREG(SISCR, 0x85, reg);
5568                         outSISIDXREG(SISCR, 0x85, 0x88);
5569                         inSISIDXREG(SISCR, 0x85, reg);
5570                         outSISIDXREG(SISCR, 0x85, bios[regb + 0x160]);
5571                         outSISIDXREG(SISCR, 0x82, bios[regb + 0x158]);
5572                 }
5573                 if(ivideo->chip == XGI_40) {
5574                         outSISIDXREG(SISCR, 0x97, 0x00);
5575                 }
5576                 outSISIDXREG(SISCR, 0x98, 0x01);
5577                 outSISIDXREG(SISCR, 0x9a, 0x02);
5578
5579                 outSISIDXREG(SISSR, 0x18, 0x01);
5580                 if((ivideo->chip == XGI_20) ||
5581                    (ivideo->revision_id == 2)) {
5582                         outSISIDXREG(SISSR, 0x19, 0x40);
5583                 } else {
5584                         outSISIDXREG(SISSR, 0x19, 0x20);
5585                 }
5586                 outSISIDXREG(SISSR, 0x16, 0x00);
5587                 outSISIDXREG(SISSR, 0x16, 0x80);
5588                 if((ivideo->chip == XGI_20) || (bios[0x1cb] != 0x0c)) {
5589                         sisfb_post_xgi_delay(ivideo, 0x43);
5590                         sisfb_post_xgi_delay(ivideo, 0x43);
5591                         sisfb_post_xgi_delay(ivideo, 0x43);
5592                         outSISIDXREG(SISSR, 0x18, 0x00);
5593                         if((ivideo->chip == XGI_20) ||
5594                            (ivideo->revision_id == 2)) {
5595                                 outSISIDXREG(SISSR, 0x19, 0x40);
5596                         } else {
5597                                 outSISIDXREG(SISSR, 0x19, 0x20);
5598                         }
5599                 } else if((ivideo->chip == XGI_40) && (bios[0x1cb] == 0x0c)) {
5600                         /* outSISIDXREG(SISSR, 0x16, 0x0c); */ /* ? */
5601                 }
5602                 outSISIDXREG(SISSR, 0x16, 0x00);
5603                 outSISIDXREG(SISSR, 0x16, 0x80);
5604                 sisfb_post_xgi_delay(ivideo, 4);
5605                 v1 = 0x31; v2 = 0x03; v3 = 0x83; v4 = 0x03; v5 = 0x83;
5606                 if(ivideo->haveXGIROM) {
5607                         v1 = bios[0xf0];
5608                         index = (ivideo->chip == XGI_20) ? 0x4b2 : 0x53e;
5609                         v2 = bios[index];
5610                         v3 = bios[index + 1];
5611                         v4 = bios[index + 2];
5612                         v5 = bios[index + 3];
5613                 }
5614                 outSISIDXREG(SISSR, 0x18, v1);
5615                 outSISIDXREG(SISSR, 0x19, ((ivideo->chip == XGI_20) ? 0x02 : 0x01));
5616                 outSISIDXREG(SISSR, 0x16, v2);
5617                 outSISIDXREG(SISSR, 0x16, v3);
5618                 sisfb_post_xgi_delay(ivideo, 0x43);
5619                 outSISIDXREG(SISSR, 0x1b, 0x03);
5620                 sisfb_post_xgi_delay(ivideo, 0x22);
5621                 outSISIDXREG(SISSR, 0x18, v1);
5622                 outSISIDXREG(SISSR, 0x19, 0x00);
5623                 outSISIDXREG(SISSR, 0x16, v4);
5624                 outSISIDXREG(SISSR, 0x16, v5);
5625                 outSISIDXREG(SISSR, 0x1b, 0x00);
5626                 break;
5627         case 1:
5628                 outSISIDXREG(SISCR, 0x82, 0x77);
5629                 outSISIDXREG(SISCR, 0x86, 0x00);
5630                 inSISIDXREG(SISCR, 0x86, reg);
5631                 outSISIDXREG(SISCR, 0x86, 0x88);
5632                 inSISIDXREG(SISCR, 0x86, reg);
5633                 v1 = cs168[regb]; v2 = cs160[regb]; v3 = cs158[regb];
5634                 if(ivideo->haveXGIROM) {
5635                         v1 = bios[regb + 0x168];
5636                         v2 = bios[regb + 0x160];
5637                         v3 = bios[regb + 0x158];
5638                 }
5639                 outSISIDXREG(SISCR, 0x86, v1);
5640                 outSISIDXREG(SISCR, 0x82, 0x77);
5641                 outSISIDXREG(SISCR, 0x85, 0x00);
5642                 inSISIDXREG(SISCR, 0x85, reg);
5643                 outSISIDXREG(SISCR, 0x85, 0x88);
5644                 inSISIDXREG(SISCR, 0x85, reg);
5645                 outSISIDXREG(SISCR, 0x85, v2);
5646                 outSISIDXREG(SISCR, 0x82, v3);
5647                 outSISIDXREG(SISCR, 0x98, 0x01);
5648                 outSISIDXREG(SISCR, 0x9a, 0x02);
5649
5650                 outSISIDXREG(SISSR, 0x28, 0x64);
5651                 outSISIDXREG(SISSR, 0x29, 0x63);
5652                 sisfb_post_xgi_delay(ivideo, 15);
5653                 outSISIDXREG(SISSR, 0x18, 0x00);
5654                 outSISIDXREG(SISSR, 0x19, 0x20);
5655                 outSISIDXREG(SISSR, 0x16, 0x00);
5656                 outSISIDXREG(SISSR, 0x16, 0x80);
5657                 outSISIDXREG(SISSR, 0x18, 0xc5);
5658                 outSISIDXREG(SISSR, 0x19, 0x23);
5659                 outSISIDXREG(SISSR, 0x16, 0x00);
5660                 outSISIDXREG(SISSR, 0x16, 0x80);
5661                 sisfb_post_xgi_delay(ivideo, 1);
5662                 outSISIDXREG(SISCR, 0x97,0x11);
5663                 sisfb_post_xgi_setclocks(ivideo, regb);
5664                 sisfb_post_xgi_delay(ivideo, 0x46);
5665                 outSISIDXREG(SISSR, 0x18, 0xc5);
5666                 outSISIDXREG(SISSR, 0x19, 0x23);
5667                 outSISIDXREG(SISSR, 0x16, 0x00);
5668                 outSISIDXREG(SISSR, 0x16, 0x80);
5669                 sisfb_post_xgi_delay(ivideo, 1);
5670                 outSISIDXREG(SISSR, 0x1b, 0x04);
5671                 sisfb_post_xgi_delay(ivideo, 1);
5672                 outSISIDXREG(SISSR, 0x1b, 0x00);
5673                 sisfb_post_xgi_delay(ivideo, 1);
5674                 v1 = 0x31;
5675                 if(ivideo->haveXGIROM) {
5676                         v1 = bios[0xf0];
5677                 }
5678                 outSISIDXREG(SISSR, 0x18, v1);
5679                 outSISIDXREG(SISSR, 0x19, 0x06);
5680                 outSISIDXREG(SISSR, 0x16, 0x04);
5681                 outSISIDXREG(SISSR, 0x16, 0x84);
5682                 sisfb_post_xgi_delay(ivideo, 1);
5683                 break;
5684         default:
5685                 sisfb_post_xgi_setclocks(ivideo, regb);
5686                 if((ivideo->chip == XGI_40) &&
5687                    ((ivideo->revision_id == 1) ||
5688                     (ivideo->revision_id == 2))) {
5689                         outSISIDXREG(SISCR, 0x82, bios[regb + 0x158]);
5690                         outSISIDXREG(SISCR, 0x85, bios[regb + 0x160]);
5691                         outSISIDXREG(SISCR, 0x86, bios[regb + 0x168]);
5692                 } else {
5693                         outSISIDXREG(SISCR, 0x82, 0x88);
5694                         outSISIDXREG(SISCR, 0x86, 0x00);
5695                         inSISIDXREG(SISCR, 0x86, reg);
5696                         outSISIDXREG(SISCR, 0x86, 0x88);
5697                         outSISIDXREG(SISCR, 0x82, 0x77);
5698                         outSISIDXREG(SISCR, 0x85, 0x00);
5699                         inSISIDXREG(SISCR, 0x85, reg);
5700                         outSISIDXREG(SISCR, 0x85, 0x88);
5701                         inSISIDXREG(SISCR, 0x85, reg);
5702                         v1 = cs160[regb]; v2 = cs158[regb];
5703                         if(ivideo->haveXGIROM) {
5704                                 v1 = bios[regb + 0x160];
5705                                 v2 = bios[regb + 0x158];
5706                         }
5707                         outSISIDXREG(SISCR, 0x85, v1);
5708                         outSISIDXREG(SISCR, 0x82, v2);
5709                 }
5710                 if(ivideo->chip == XGI_40) {
5711                         outSISIDXREG(SISCR, 0x97, 0x11);
5712                 }
5713                 if((ivideo->chip == XGI_40) && (ivideo->revision_id == 2)) {
5714                         outSISIDXREG(SISCR, 0x98, 0x01);
5715                 } else {
5716                         outSISIDXREG(SISCR, 0x98, 0x03);
5717                 }
5718                 outSISIDXREG(SISCR, 0x9a, 0x02);
5719
5720                 if(ivideo->chip == XGI_40) {
5721                         outSISIDXREG(SISSR, 0x18, 0x01);
5722                 } else {
5723                         outSISIDXREG(SISSR, 0x18, 0x00);
5724                 }
5725                 outSISIDXREG(SISSR, 0x19, 0x40);
5726                 outSISIDXREG(SISSR, 0x16, 0x00);
5727                 outSISIDXREG(SISSR, 0x16, 0x80);
5728                 if((ivideo->chip == XGI_40) && (bios[0x1cb] != 0x0c)) {
5729                         sisfb_post_xgi_delay(ivideo, 0x43);
5730                         sisfb_post_xgi_delay(ivideo, 0x43);
5731                         sisfb_post_xgi_delay(ivideo, 0x43);
5732                         outSISIDXREG(SISSR, 0x18, 0x00);
5733                         outSISIDXREG(SISSR, 0x19, 0x40);
5734                         outSISIDXREG(SISSR, 0x16, 0x00);
5735                         outSISIDXREG(SISSR, 0x16, 0x80);
5736                 }
5737                 sisfb_post_xgi_delay(ivideo, 4);
5738                 v1 = 0x31;
5739                 if(ivideo->haveXGIROM) {
5740                         v1 = bios[0xf0];
5741                 }
5742                 outSISIDXREG(SISSR, 0x18, v1);
5743                 outSISIDXREG(SISSR, 0x19, 0x01);
5744                 if(ivideo->chip == XGI_40) {
5745                         outSISIDXREG(SISSR, 0x16, bios[0x53e]);
5746                         outSISIDXREG(SISSR, 0x16, bios[0x53f]);
5747                 } else {
5748                         outSISIDXREG(SISSR, 0x16, 0x05);
5749                         outSISIDXREG(SISSR, 0x16, 0x85);
5750                 }
5751                 sisfb_post_xgi_delay(ivideo, 0x43);
5752                 if(ivideo->chip == XGI_40) {
5753                         outSISIDXREG(SISSR, 0x1b, 0x01);
5754                 } else {
5755                         outSISIDXREG(SISSR, 0x1b, 0x03);
5756                 }
5757                 sisfb_post_xgi_delay(ivideo, 0x22);
5758                 outSISIDXREG(SISSR, 0x18, v1);
5759                 outSISIDXREG(SISSR, 0x19, 0x00);
5760                 if(ivideo->chip == XGI_40) {
5761                         outSISIDXREG(SISSR, 0x16, bios[0x540]);
5762                         outSISIDXREG(SISSR, 0x16, bios[0x541]);
5763                 } else {
5764                         outSISIDXREG(SISSR, 0x16, 0x05);
5765                         outSISIDXREG(SISSR, 0x16, 0x85);
5766                 }
5767                 outSISIDXREG(SISSR, 0x1b, 0x00);
5768         }
5769
5770         regb = 0;       /* ! */
5771         v1 = 0x03;
5772         if(ivideo->haveXGIROM) {
5773                 v1 = bios[0x110 + regb];
5774         }
5775         outSISIDXREG(SISSR, 0x1b, v1);
5776
5777         /* RAM size */
5778         v1 = 0x00; v2 = 0x00;
5779         if(ivideo->haveXGIROM) {
5780                 v1 = bios[0x62];
5781                 v2 = bios[0x63];
5782         }
5783         regb = 0;       /* ! */
5784         regd = 1 << regb;
5785         if((v1 & 0x40) && (v2 & regd) && ivideo->haveXGIROM) {
5786
5787                 outSISIDXREG(SISSR, 0x13, bios[regb + 0xe0]);
5788                 outSISIDXREG(SISSR, 0x14, bios[regb + 0xe0 + 8]);
5789
5790         } else {
5791
5792                 /* Set default mode, don't clear screen */
5793                 ivideo->SiS_Pr.SiS_UseOEM = FALSE;
5794                 SiS_SetEnableDstn(&ivideo->SiS_Pr, FALSE);
5795                 SiS_SetEnableFstn(&ivideo->SiS_Pr, FALSE);
5796                 ivideo->curFSTN = ivideo->curDSTN = 0;
5797                 ivideo->SiS_Pr.VideoMemorySize = 8 << 20;
5798                 SiSSetMode(&ivideo->SiS_Pr, 0x2e | 0x80);
5799
5800                 outSISIDXREG(SISSR, 0x05, 0x86);
5801
5802                 /* Disable read-cache */
5803                 andSISIDXREG(SISSR, 0x21, 0xdf);
5804                 sisfb_post_xgi_ramsize(ivideo);
5805                 /* Enable read-cache */
5806                 orSISIDXREG(SISSR, 0x21, 0x20);
5807
5808         }
5809
5810 #if 0
5811         printk(KERN_DEBUG "-----------------\n");
5812         for(i = 0; i < 0xff; i++) {
5813                 inSISIDXREG(SISCR, i, reg);
5814                 printk(KERN_DEBUG "CR%02x(%x) = 0x%02x\n", i, SISCR, reg);
5815         }
5816         for(i = 0; i < 0x40; i++) {
5817                 inSISIDXREG(SISSR, i, reg);
5818                 printk(KERN_DEBUG "SR%02x(%x) = 0x%02x\n", i, SISSR, reg);
5819         }
5820         printk(KERN_DEBUG "-----------------\n");
5821 #endif
5822
5823         /* Sense CRT1 */
5824         if(ivideo->chip == XGI_20) {
5825                 orSISIDXREG(SISCR, 0x32, 0x20);
5826         } else {
5827                 inSISIDXREG(SISPART4, 0x00, reg);
5828                 if((reg == 1) || (reg == 2)) {
5829                         sisfb_sense_crt1(ivideo);
5830                 } else {
5831                         orSISIDXREG(SISCR, 0x32, 0x20);
5832                 }
5833         }
5834
5835         /* Set default mode, don't clear screen */
5836         ivideo->SiS_Pr.SiS_UseOEM = FALSE;
5837         SiS_SetEnableDstn(&ivideo->SiS_Pr, FALSE);
5838         SiS_SetEnableFstn(&ivideo->SiS_Pr, FALSE);
5839         ivideo->curFSTN = ivideo->curDSTN = 0;
5840         SiSSetMode(&ivideo->SiS_Pr, 0x2e | 0x80);
5841
5842         outSISIDXREG(SISSR, 0x05, 0x86);
5843
5844         /* Display off */
5845         orSISIDXREG(SISSR, 0x01, 0x20);
5846
5847         /* Save mode number in CR34 */
5848         outSISIDXREG(SISCR, 0x34, 0x2e);
5849
5850         /* Let everyone know what the current mode is */
5851         ivideo->modeprechange = 0x2e;
5852
5853         if(ivideo->chip == XGI_40) {
5854                 inSISIDXREG(SISCR, 0xca, reg);
5855                 inSISIDXREG(SISCR, 0xcc, v1);
5856                 if((reg & 0x10) && (!(v1 & 0x04))) {
5857                         printk(KERN_ERR
5858                                 "sisfb: Please connect power to the card.\n");
5859                         return 0;
5860                 }
5861         }
5862
5863         return 1;
5864 }
5865 #endif
5866
5867 static int __devinit
5868 sisfb_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
5869 {
5870         struct sisfb_chip_info  *chipinfo = &sisfb_chip_info[ent->driver_data];
5871         struct sis_video_info   *ivideo = NULL;
5872         struct fb_info          *sis_fb_info = NULL;
5873         u16 reg16;
5874         u8  reg;
5875         int i, ret;
5876
5877         if(sisfb_off)
5878                 return -ENXIO;
5879
5880 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,3))
5881         sis_fb_info = framebuffer_alloc(sizeof(*ivideo), &pdev->dev);
5882         if(!sis_fb_info)
5883                 return -ENOMEM;
5884 #else
5885         sis_fb_info = kmalloc(sizeof(*sis_fb_info) + sizeof(*ivideo), GFP_KERNEL);
5886         if(!sis_fb_info)
5887                 return -ENOMEM;
5888         memset(sis_fb_info, 0, sizeof(*sis_fb_info) + sizeof(*ivideo));
5889         sis_fb_info->par = ((char *)sis_fb_info + sizeof(*sis_fb_info));
5890 #endif
5891
5892         ivideo = (struct sis_video_info *)sis_fb_info->par;
5893         ivideo->memyselfandi = sis_fb_info;
5894
5895         ivideo->sisfb_id = SISFB_ID;
5896
5897         if(card_list == NULL) {
5898                 ivideo->cardnumber = 0;
5899         } else {
5900                 struct sis_video_info *countvideo = card_list;
5901                 ivideo->cardnumber = 1;
5902                 while((countvideo = countvideo->next) != 0)
5903                         ivideo->cardnumber++;
5904         }
5905
5906         strncpy(ivideo->myid, chipinfo->chip_name, 30);
5907
5908         ivideo->warncount = 0;
5909         ivideo->chip_id = pdev->device;
5910         ivideo->chip_vendor = pdev->vendor;
5911         pci_read_config_byte(pdev, PCI_REVISION_ID, &ivideo->revision_id);
5912         ivideo->SiS_Pr.ChipRevision = ivideo->revision_id;
5913         pci_read_config_word(pdev, PCI_COMMAND, &reg16);
5914         ivideo->sisvga_enabled = reg16 & 0x01;
5915         ivideo->pcibus = pdev->bus->number;
5916         ivideo->pcislot = PCI_SLOT(pdev->devfn);
5917         ivideo->pcifunc = PCI_FUNC(pdev->devfn);
5918         ivideo->subsysvendor = pdev->subsystem_vendor;
5919         ivideo->subsysdevice = pdev->subsystem_device;
5920 #ifdef SIS_OLD_CONFIG_COMPAT
5921         ivideo->ioctl32registered = 0;
5922 #endif
5923
5924 #ifndef MODULE
5925         if(sisfb_mode_idx == -1) {
5926                 sisfb_get_vga_mode_from_kernel();
5927         }
5928 #endif
5929
5930         ivideo->chip = chipinfo->chip;
5931         ivideo->sisvga_engine = chipinfo->vgaengine;
5932         ivideo->hwcursor_size = chipinfo->hwcursor_size;
5933         ivideo->CRT2_write_enable = chipinfo->CRT2_write_enable;
5934         ivideo->mni = chipinfo->mni;
5935
5936         ivideo->detectedpdc  = 0xff;
5937         ivideo->detectedpdca = 0xff;
5938         ivideo->detectedlcda = 0xff;
5939
5940         ivideo->sisfb_thismonitor.datavalid = FALSE;
5941
5942         ivideo->current_base = 0;
5943
5944         ivideo->engineok = 0;
5945
5946         ivideo->sisfb_was_boot_device = 0;
5947 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,12))
5948         if(pdev->resource[PCI_ROM_RESOURCE].flags & IORESOURCE_ROM_SHADOW) {
5949                 if(ivideo->sisvga_enabled)
5950                         ivideo->sisfb_was_boot_device = 1;
5951                 else {
5952                         printk(KERN_DEBUG "sisfb: PCI device is disabled, "
5953                                 "but marked as boot video device ???\n");
5954                         printk(KERN_DEBUG "sisfb: I will not accept this "
5955                                 "as the primary VGA device\n");
5956                 }
5957         }
5958 #endif
5959
5960         ivideo->sisfb_parm_mem = sisfb_parm_mem;
5961         ivideo->sisfb_accel = sisfb_accel;
5962         ivideo->sisfb_ypan = sisfb_ypan;
5963         ivideo->sisfb_max = sisfb_max;
5964         ivideo->sisfb_userom = sisfb_userom;
5965         ivideo->sisfb_useoem = sisfb_useoem;
5966         ivideo->sisfb_mode_idx = sisfb_mode_idx;
5967         ivideo->sisfb_parm_rate = sisfb_parm_rate;
5968         ivideo->sisfb_crt1off = sisfb_crt1off;
5969         ivideo->sisfb_forcecrt1 = sisfb_forcecrt1;
5970         ivideo->sisfb_crt2type = sisfb_crt2type;
5971         ivideo->sisfb_crt2flags = sisfb_crt2flags;
5972         /* pdc(a), scalelcd, special timing, lvdshl handled below */
5973         ivideo->sisfb_dstn = sisfb_dstn;
5974         ivideo->sisfb_fstn = sisfb_fstn;
5975         ivideo->sisfb_tvplug = sisfb_tvplug;
5976         ivideo->sisfb_tvstd = sisfb_tvstd;
5977         ivideo->tvxpos = sisfb_tvxposoffset;
5978         ivideo->tvypos = sisfb_tvyposoffset;
5979         ivideo->sisfb_nocrt2rate = sisfb_nocrt2rate;
5980 #if LINUX_VERSION_CODE <= KERNEL_VERSION(2,5,0)
5981         ivideo->sisfb_inverse = sisfb_inverse;
5982 #endif
5983
5984         ivideo->refresh_rate = 0;
5985         if(ivideo->sisfb_parm_rate != -1) {
5986                 ivideo->refresh_rate = ivideo->sisfb_parm_rate;
5987         }
5988
5989         ivideo->SiS_Pr.UsePanelScaler = sisfb_scalelcd;
5990         ivideo->SiS_Pr.CenterScreen = -1;
5991         ivideo->SiS_Pr.SiS_CustomT = sisfb_specialtiming;
5992         ivideo->SiS_Pr.LVDSHL = sisfb_lvdshl;
5993
5994         ivideo->SiS_Pr.SiS_Backup70xx = 0xff;
5995         ivideo->SiS_Pr.SiS_CHOverScan = -1;
5996         ivideo->SiS_Pr.SiS_ChSW = FALSE;
5997         ivideo->SiS_Pr.SiS_UseLCDA = FALSE;
5998         ivideo->SiS_Pr.HaveEMI = FALSE;
5999         ivideo->SiS_Pr.HaveEMILCD = FALSE;
6000         ivideo->SiS_Pr.OverruleEMI = FALSE;
6001         ivideo->SiS_Pr.SiS_SensibleSR11 = FALSE;
6002         ivideo->SiS_Pr.SiS_MyCR63 = 0x63;
6003         ivideo->SiS_Pr.PDC  = -1;
6004         ivideo->SiS_Pr.PDCA = -1;
6005         ivideo->SiS_Pr.DDCPortMixup = FALSE;
6006 #ifdef CONFIG_FB_SIS_315
6007         if(ivideo->chip >= SIS_330) {
6008                 ivideo->SiS_Pr.SiS_MyCR63 = 0x53;
6009                 if(ivideo->chip >= SIS_661) {
6010                         ivideo->SiS_Pr.SiS_SensibleSR11 = TRUE;
6011                 }
6012         }
6013 #endif
6014
6015         memcpy(&ivideo->default_var, &my_default_var, sizeof(my_default_var));
6016
6017         pci_set_drvdata(pdev, ivideo);
6018
6019         /* Patch special cases */
6020         if((ivideo->nbridge = sisfb_get_northbridge(ivideo->chip))) {
6021                 switch(ivideo->nbridge->device) {
6022 #ifdef CONFIG_FB_SIS_300
6023                 case PCI_DEVICE_ID_SI_730:
6024                         ivideo->chip = SIS_730;
6025                         strcpy(ivideo->myid, "SiS 730");
6026                         break;
6027 #endif
6028 #ifdef CONFIG_FB_SIS_315
6029                 case PCI_DEVICE_ID_SI_651:
6030                         /* ivideo->chip is ok */
6031                         strcpy(ivideo->myid, "SiS 651");
6032                         break;
6033                 case PCI_DEVICE_ID_SI_740:
6034                         ivideo->chip = SIS_740;
6035                         strcpy(ivideo->myid, "SiS 740");
6036                         break;
6037                 case PCI_DEVICE_ID_SI_661:
6038                         ivideo->chip = SIS_661;
6039                         strcpy(ivideo->myid, "SiS 661");
6040                         break;
6041                 case PCI_DEVICE_ID_SI_741:
6042                         ivideo->chip = SIS_741;
6043                         strcpy(ivideo->myid, "SiS 741");
6044                         break;
6045                 case PCI_DEVICE_ID_SI_760:
6046                         ivideo->chip = SIS_760;
6047                         strcpy(ivideo->myid, "SiS 760");
6048                         break;
6049                 case PCI_DEVICE_ID_SI_761:
6050                         ivideo->chip = SIS_761;
6051                         strcpy(ivideo->myid, "SiS 761");
6052                         break;
6053 #endif
6054                 default:
6055                         break;
6056                 }
6057         }
6058
6059 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
6060         strcpy(sis_fb_info->modename, ivideo->myid);
6061 #endif
6062
6063         ivideo->SiS_Pr.ChipType = ivideo->chip;
6064
6065         ivideo->SiS_Pr.ivideo = (void *)ivideo;
6066
6067 #ifdef CONFIG_FB_SIS_315
6068         if((ivideo->SiS_Pr.ChipType == SIS_315PRO) ||
6069            (ivideo->SiS_Pr.ChipType == SIS_315)) {
6070                 ivideo->SiS_Pr.ChipType = SIS_315H;
6071         }
6072 #endif
6073
6074         if(!ivideo->sisvga_enabled) {
6075                 if(pci_enable_device(pdev)) {
6076                         if(ivideo->nbridge) SIS_PCI_PUT_DEVICE(ivideo->nbridge);
6077                         pci_set_drvdata(pdev, NULL);
6078                         kfree(sis_fb_info);
6079                         return -EIO;
6080                 }
6081         }
6082
6083         ivideo->video_base = pci_resource_start(pdev, 0);
6084         ivideo->mmio_base  = pci_resource_start(pdev, 1);
6085         ivideo->mmio_size  = pci_resource_len(pdev, 1);
6086         ivideo->SiS_Pr.RelIO = pci_resource_start(pdev, 2) + 0x30;
6087         ivideo->SiS_Pr.IOAddress = ivideo->vga_base = ivideo->SiS_Pr.RelIO;
6088
6089         SiSRegInit(&ivideo->SiS_Pr, ivideo->SiS_Pr.IOAddress);
6090
6091 #ifdef CONFIG_FB_SIS_300
6092         /* Find PCI systems for Chrontel/GPIO communication setup */
6093         if(ivideo->chip == SIS_630) {
6094                 i = 0;
6095                 do {
6096                         if(mychswtable[i].subsysVendor == ivideo->subsysvendor &&
6097                            mychswtable[i].subsysCard   == ivideo->subsysdevice) {
6098                                 ivideo->SiS_Pr.SiS_ChSW = TRUE;
6099                                 printk(KERN_DEBUG "sisfb: Identified [%s %s] "
6100                                         "requiring Chrontel/GPIO setup\n",
6101                                         mychswtable[i].vendorName,
6102                                         mychswtable[i].cardName);
6103                                 ivideo->lpcdev = SIS_PCI_GET_DEVICE(PCI_VENDOR_ID_SI, 0x0008, NULL);
6104                                 break;
6105                         }
6106                         i++;
6107                 } while(mychswtable[i].subsysVendor != 0);
6108         }
6109 #endif
6110
6111 #ifdef CONFIG_FB_SIS_315
6112         if((ivideo->chip == SIS_760) && (ivideo->nbridge)) {
6113                 ivideo->lpcdev = SIS_PCI_GET_SLOT(ivideo->nbridge->bus, (2 << 3));
6114         }
6115 #endif
6116
6117         outSISIDXREG(SISSR, 0x05, 0x86);
6118
6119         if( (!ivideo->sisvga_enabled)
6120 #if !defined(__i386__) && !defined(__x86_64__)
6121                               || (sisfb_resetcard)
6122 #endif
6123                                                    ) {
6124                 for(i = 0x30; i <= 0x3f; i++) {
6125                         outSISIDXREG(SISCR, i, 0x00);
6126                 }
6127         }
6128
6129         /* Find out about current video mode */
6130         ivideo->modeprechange = 0x03;
6131         inSISIDXREG(SISCR, 0x34, reg);
6132         if(reg & 0x7f) {
6133                 ivideo->modeprechange = reg & 0x7f;
6134         } else if(ivideo->sisvga_enabled) {
6135 #if defined(__i386__) || defined(__x86_64__)
6136                 unsigned char SIS_IOTYPE2 *tt = ioremap(0x400, 0x100);
6137                 if(tt) {
6138                         ivideo->modeprechange = readb(tt + 0x49);
6139                         iounmap(tt);
6140                 }
6141 #endif
6142         }
6143
6144 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
6145 #ifdef MODULE
6146         if((reg & 0x80) && (reg != 0xff)) {
6147                 if((sisbios_mode[ivideo->sisfb_mode_idx].mode_no[ivideo->mni])
6148                                                                         != 0xFF) {
6149                         printk(KERN_INFO "sisfb: Cannot initialize display mode, "
6150                                          "X server is active\n");
6151                         ret = -EBUSY;
6152                         goto error_4;
6153                 }
6154         }
6155 #endif
6156 #endif
6157
6158         /* Search and copy ROM image */
6159         ivideo->bios_abase = NULL;
6160         ivideo->SiS_Pr.VirtualRomBase = NULL;
6161         ivideo->SiS_Pr.UseROM = FALSE;
6162         ivideo->haveXGIROM = ivideo->SiS_Pr.SiS_XGIROM = FALSE;
6163         if(ivideo->sisfb_userom) {
6164                 ivideo->SiS_Pr.VirtualRomBase = sisfb_find_rom(pdev);
6165                 ivideo->bios_abase = ivideo->SiS_Pr.VirtualRomBase;
6166                 ivideo->SiS_Pr.UseROM = (ivideo->SiS_Pr.VirtualRomBase) ? TRUE : FALSE;
6167                 printk(KERN_INFO "sisfb: Video ROM %sfound\n",
6168                         ivideo->SiS_Pr.UseROM ? "" : "not ");
6169                 if((ivideo->SiS_Pr.UseROM) && (ivideo->chip >= XGI_20)) {
6170                    ivideo->SiS_Pr.UseROM = FALSE;
6171                    ivideo->haveXGIROM = ivideo->SiS_Pr.SiS_XGIROM = TRUE;
6172                    if( (ivideo->revision_id == 2) &&
6173                        (!(ivideo->bios_abase[0x1d1] & 0x01)) ) {
6174                         ivideo->SiS_Pr.DDCPortMixup = TRUE;
6175                    }
6176                 }
6177         } else {
6178                 printk(KERN_INFO "sisfb: Video ROM usage disabled\n");
6179         }
6180
6181         /* Find systems for special custom timing */
6182         if(ivideo->SiS_Pr.SiS_CustomT == CUT_NONE) {
6183                 sisfb_detect_custom_timing(ivideo);
6184         }
6185
6186         /* POST card in case this has not been done by the BIOS */
6187         if( (!ivideo->sisvga_enabled)
6188 #if !defined(__i386__) && !defined(__x86_64__)
6189                              || (sisfb_resetcard)
6190 #endif
6191                                                  ) {
6192 #ifdef CONFIG_FB_SIS_300
6193                 if(ivideo->sisvga_engine == SIS_300_VGA) {
6194                         if(ivideo->chip == SIS_300) {
6195                                 sisfb_post_sis300(pdev);
6196                                 ivideo->sisfb_can_post = 1;
6197                         }
6198                 }
6199 #endif
6200
6201 #ifdef CONFIG_FB_SIS_315
6202                 if(ivideo->sisvga_engine == SIS_315_VGA) {
6203                         int result = 1;
6204                 /*      if((ivideo->chip == SIS_315H)   ||
6205                            (ivideo->chip == SIS_315)    ||
6206                            (ivideo->chip == SIS_315PRO) ||
6207                            (ivideo->chip == SIS_330)) {
6208                                 sisfb_post_sis315330(pdev);
6209                         } else */ if(ivideo->chip == XGI_20) {
6210                                 result = sisfb_post_xgi(pdev);
6211                                 ivideo->sisfb_can_post = 1;
6212                         } else if((ivideo->chip == XGI_40) && ivideo->haveXGIROM) {
6213                                 result = sisfb_post_xgi(pdev);
6214                                 ivideo->sisfb_can_post = 1;
6215                         } else {
6216                                 printk(KERN_INFO "sisfb: Card is not "
6217                                         "POSTed and sisfb can't do this either.\n");
6218                         }
6219                         if(!result) {
6220                                 printk(KERN_ERR "sisfb: Failed to POST card\n");
6221                                 ret = -ENODEV;
6222                                 goto error_3;
6223                         }
6224                 }
6225 #endif
6226         }
6227
6228         ivideo->sisfb_card_posted = 1;
6229
6230         /* Find out about RAM size */
6231         if(sisfb_get_dram_size(ivideo)) {
6232                 printk(KERN_INFO "sisfb: Fatal error: Unable to determine VRAM size.\n");
6233                 ret = -ENODEV;
6234                 goto error_3;
6235         }
6236
6237
6238         /* Enable PCI addressing and MMIO */
6239         if((ivideo->sisfb_mode_idx < 0) ||
6240            ((sisbios_mode[ivideo->sisfb_mode_idx].mode_no[ivideo->mni]) != 0xFF)) {
6241                 /* Enable PCI_LINEAR_ADDRESSING and MMIO_ENABLE  */
6242                 orSISIDXREG(SISSR, IND_SIS_PCI_ADDRESS_SET, (SIS_PCI_ADDR_ENABLE | SIS_MEM_MAP_IO_ENABLE));
6243                 /* Enable 2D accelerator engine */
6244                 orSISIDXREG(SISSR, IND_SIS_MODULE_ENABLE, SIS_ENABLE_2D);
6245         }
6246
6247         if(sisfb_pdc != 0xff) {
6248                 if(ivideo->sisvga_engine == SIS_300_VGA)
6249                         sisfb_pdc &= 0x3c;
6250                 else
6251                         sisfb_pdc &= 0x1f;
6252                 ivideo->SiS_Pr.PDC = sisfb_pdc;
6253         }
6254 #ifdef CONFIG_FB_SIS_315
6255         if(ivideo->sisvga_engine == SIS_315_VGA) {
6256                 if(sisfb_pdca != 0xff)
6257                         ivideo->SiS_Pr.PDCA = sisfb_pdca & 0x1f;
6258         }
6259 #endif
6260
6261         if(!request_mem_region(ivideo->video_base, ivideo->video_size, "sisfb FB")) {
6262                 printk(KERN_ERR "sisfb: Fatal error: Unable to reserve %dMB framebuffer memory\n",
6263                                 (int)(ivideo->video_size >> 20));
6264                 printk(KERN_ERR "sisfb: Is there another framebuffer driver active?\n");
6265                 ret = -ENODEV;
6266                 goto error_3;
6267         }
6268
6269         if(!request_mem_region(ivideo->mmio_base, ivideo->mmio_size, "sisfb MMIO")) {
6270                 printk(KERN_ERR "sisfb: Fatal error: Unable to reserve MMIO region\n");
6271                 ret = -ENODEV;
6272                 goto error_2;
6273         }
6274
6275         ivideo->video_vbase = ioremap(ivideo->video_base, ivideo->video_size);
6276         ivideo->SiS_Pr.VideoMemoryAddress = ivideo->video_vbase;
6277         if(!ivideo->video_vbase) {
6278                 printk(KERN_ERR "sisfb: Fatal error: Unable to map framebuffer memory\n");
6279                 ret = -ENODEV;
6280                 goto error_1;
6281         }
6282
6283         ivideo->mmio_vbase = ioremap(ivideo->mmio_base, ivideo->mmio_size);
6284         if(!ivideo->mmio_vbase) {
6285                 printk(KERN_ERR "sisfb: Fatal error: Unable to map MMIO region\n");
6286                 ret = -ENODEV;
6287 error_0:        iounmap(ivideo->video_vbase);
6288 error_1:        release_mem_region(ivideo->video_base, ivideo->video_size);
6289 error_2:        release_mem_region(ivideo->mmio_base, ivideo->mmio_size);
6290 error_3:        vfree(ivideo->bios_abase);
6291 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
6292 error_4:
6293 #endif
6294                 if(ivideo->lpcdev)
6295                         SIS_PCI_PUT_DEVICE(ivideo->lpcdev);
6296                 if(ivideo->nbridge)
6297                         SIS_PCI_PUT_DEVICE(ivideo->nbridge);
6298                 pci_set_drvdata(pdev, NULL);
6299                 if(!ivideo->sisvga_enabled)
6300                         pci_disable_device(pdev);
6301                 kfree(sis_fb_info);
6302                 return ret;
6303         }
6304
6305         printk(KERN_INFO "sisfb: Video RAM at 0x%lx, mapped to 0x%lx, size %ldk\n",
6306                 ivideo->video_base, (unsigned long)ivideo->video_vbase, ivideo->video_size / 1024);
6307
6308         if(ivideo->video_offset) {
6309                 printk(KERN_INFO "sisfb: Viewport offset %ldk\n",
6310                         ivideo->video_offset / 1024);
6311         }
6312
6313         printk(KERN_INFO "sisfb: MMIO at 0x%lx, mapped to 0x%lx, size %ldk\n",
6314                 ivideo->mmio_base, (unsigned long)ivideo->mmio_vbase, ivideo->mmio_size / 1024);
6315
6316
6317         /* Determine the size of the command queue */
6318         if(ivideo->sisvga_engine == SIS_300_VGA) {
6319                 ivideo->cmdQueueSize = TURBO_QUEUE_AREA_SIZE;
6320         } else {
6321                 if(ivideo->chip == XGI_20) {
6322                         ivideo->cmdQueueSize = COMMAND_QUEUE_AREA_SIZE_Z7;
6323                 } else {
6324                         ivideo->cmdQueueSize = COMMAND_QUEUE_AREA_SIZE;
6325                 }
6326         }
6327
6328         /* Engines are no longer initialized here; this is
6329          * now done after the first mode-switch (if the
6330          * submitted var has its acceleration flags set).
6331          */
6332
6333         /* Calculate the base of the (unused) hw cursor */
6334         ivideo->hwcursor_vbase = ivideo->video_vbase
6335                                  + ivideo->video_size
6336                                  - ivideo->cmdQueueSize
6337                                  - ivideo->hwcursor_size;
6338         ivideo->caps |= HW_CURSOR_CAP;
6339
6340         /* Initialize offscreen memory manager */
6341         if((ivideo->havenoheap = sisfb_heap_init(ivideo))) {
6342                 printk(KERN_WARNING "sisfb: Failed to initialize offscreen memory heap\n");
6343         }
6344
6345         /* Used for clearing the screen only, therefore respect our mem limit */
6346         ivideo->SiS_Pr.VideoMemoryAddress += ivideo->video_offset;
6347         ivideo->SiS_Pr.VideoMemorySize = ivideo->sisfb_mem;
6348
6349         ivideo->mtrr = -1;
6350
6351         ivideo->vbflags = 0;
6352         ivideo->lcddefmodeidx = DEFAULT_LCDMODE;
6353         ivideo->tvdefmodeidx  = DEFAULT_TVMODE;
6354         ivideo->defmodeidx    = DEFAULT_MODE;
6355
6356         ivideo->newrom = 0;
6357         if(ivideo->chip < XGI_20) {
6358                 if(ivideo->bios_abase) {
6359                         ivideo->newrom = SiSDetermineROMLayout661(&ivideo->SiS_Pr);
6360                 }
6361         }
6362
6363         if((ivideo->sisfb_mode_idx < 0) ||
6364            ((sisbios_mode[ivideo->sisfb_mode_idx].mode_no[ivideo->mni]) != 0xFF)) {
6365
6366                 sisfb_sense_crt1(ivideo);
6367
6368                 sisfb_get_VB_type(ivideo);
6369
6370                 if(ivideo->vbflags2 & VB2_VIDEOBRIDGE) {
6371                         sisfb_detect_VB_connect(ivideo);
6372                 }
6373
6374                 ivideo->currentvbflags = ivideo->vbflags & (VB_VIDEOBRIDGE | TV_STANDARD);
6375
6376                 /* Decide on which CRT2 device to use */
6377                 if(ivideo->vbflags2 & VB2_VIDEOBRIDGE) {
6378                         if(ivideo->sisfb_crt2type != -1) {
6379                                 if((ivideo->sisfb_crt2type == CRT2_LCD) &&
6380                                    (ivideo->vbflags & CRT2_LCD)) {
6381                                         ivideo->currentvbflags |= CRT2_LCD;
6382                                 } else if(ivideo->sisfb_crt2type != CRT2_LCD) {
6383                                         ivideo->currentvbflags |= ivideo->sisfb_crt2type;
6384                                 }
6385                         } else {
6386                                 /* Chrontel 700x TV detection often unreliable, therefore
6387                                  * use a different default order on such machines
6388                                  */
6389                                 if((ivideo->sisvga_engine == SIS_300_VGA) &&
6390                                    (ivideo->vbflags2 & VB2_CHRONTEL)) {
6391                                         if(ivideo->vbflags & CRT2_LCD)
6392                                                 ivideo->currentvbflags |= CRT2_LCD;
6393                                         else if(ivideo->vbflags & CRT2_TV)
6394                                                 ivideo->currentvbflags |= CRT2_TV;
6395                                         else if(ivideo->vbflags & CRT2_VGA)
6396                                                 ivideo->currentvbflags |= CRT2_VGA;
6397                                 } else {
6398                                         if(ivideo->vbflags & CRT2_TV)
6399                                                 ivideo->currentvbflags |= CRT2_TV;
6400                                         else if(ivideo->vbflags & CRT2_LCD)
6401                                                 ivideo->currentvbflags |= CRT2_LCD;
6402                                         else if(ivideo->vbflags & CRT2_VGA)
6403                                                 ivideo->currentvbflags |= CRT2_VGA;
6404                                 }
6405                         }
6406                 }
6407
6408                 if(ivideo->vbflags & CRT2_LCD) {
6409                         sisfb_detect_lcd_type(ivideo);
6410                 }
6411
6412                 sisfb_save_pdc_emi(ivideo);
6413
6414                 if(!ivideo->sisfb_crt1off) {
6415                         sisfb_handle_ddc(ivideo, &ivideo->sisfb_thismonitor, 0);
6416                 } else {
6417                         if((ivideo->vbflags2 & VB2_SISTMDSBRIDGE) &&
6418                            (ivideo->vbflags & (CRT2_VGA | CRT2_LCD))) {
6419                                 sisfb_handle_ddc(ivideo, &ivideo->sisfb_thismonitor, 1);
6420                         }
6421                 }
6422
6423                 if(ivideo->sisfb_mode_idx >= 0) {
6424                         int bu = ivideo->sisfb_mode_idx;
6425                         ivideo->sisfb_mode_idx = sisfb_validate_mode(ivideo,
6426                                         ivideo->sisfb_mode_idx, ivideo->currentvbflags);
6427                         if(bu != ivideo->sisfb_mode_idx) {
6428                                 printk(KERN_ERR "Mode %dx%dx%d failed validation\n",
6429                                         sisbios_mode[bu].xres,
6430                                         sisbios_mode[bu].yres,
6431                                         sisbios_mode[bu].bpp);
6432                         }
6433                 }
6434
6435                 if(ivideo->sisfb_mode_idx < 0) {
6436                         switch(ivideo->currentvbflags & VB_DISPTYPE_DISP2) {
6437                            case CRT2_LCD:
6438                                 ivideo->sisfb_mode_idx = ivideo->lcddefmodeidx;
6439                                 break;
6440                            case CRT2_TV:
6441                                 ivideo->sisfb_mode_idx = ivideo->tvdefmodeidx;
6442                                 break;
6443                            default:
6444                                 ivideo->sisfb_mode_idx = ivideo->defmodeidx;
6445                                 break;
6446                         }
6447                 }
6448
6449                 ivideo->mode_no = sisbios_mode[ivideo->sisfb_mode_idx].mode_no[ivideo->mni];
6450
6451                 if(ivideo->refresh_rate != 0) {
6452                         sisfb_search_refresh_rate(ivideo, ivideo->refresh_rate,
6453                                                 ivideo->sisfb_mode_idx);
6454                 }
6455
6456                 if(ivideo->rate_idx == 0) {
6457                         ivideo->rate_idx = sisbios_mode[ivideo->sisfb_mode_idx].rate_idx;
6458                         ivideo->refresh_rate = 60;
6459                 }
6460
6461                 if(ivideo->sisfb_thismonitor.datavalid) {
6462                         if(!sisfb_verify_rate(ivideo, &ivideo->sisfb_thismonitor,
6463                                                 ivideo->sisfb_mode_idx,
6464                                                 ivideo->rate_idx,
6465                                                 ivideo->refresh_rate)) {
6466                                 printk(KERN_INFO "sisfb: WARNING: Refresh rate "
6467                                                         "exceeds monitor specs!\n");
6468                         }
6469                 }
6470
6471                 ivideo->video_bpp = sisbios_mode[ivideo->sisfb_mode_idx].bpp;
6472                 ivideo->video_width = sisbios_mode[ivideo->sisfb_mode_idx].xres;
6473                 ivideo->video_height = sisbios_mode[ivideo->sisfb_mode_idx].yres;
6474
6475                 sisfb_set_vparms(ivideo);
6476
6477 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
6478
6479                 /* ---------------- For 2.4: Now switch the mode ------------------ */
6480
6481                 printk(KERN_INFO "sisfb: Setting mode %dx%dx%d (%dHz)\n",
6482                         ivideo->video_width, ivideo->video_height, ivideo->video_bpp,
6483                         ivideo->refresh_rate);
6484
6485                 /* Determine whether or not acceleration is to be
6486                  * used. Need to know before pre/post_set_mode()
6487                  */
6488                 ivideo->accel = 0;
6489                 ivideo->default_var.accel_flags &= ~FB_ACCELF_TEXT;
6490                 if(ivideo->sisfb_accel) {
6491                         ivideo->accel = -1;
6492                         ivideo->default_var.accel_flags |= FB_ACCELF_TEXT;
6493                 }
6494
6495                 /* Now switch the mode */
6496                 sisfb_pre_setmode(ivideo);
6497
6498                 if(SiSSetMode(&ivideo->SiS_Pr, ivideo->mode_no) == 0) {
6499                         printk(KERN_ERR "sisfb: Fatal error: Setting mode[0x%x] failed\n",
6500                                                                         ivideo->mode_no);
6501                         ret = -EINVAL;
6502                         iounmap(ivideo->mmio_vbase);
6503                         goto error_0;
6504                 }
6505
6506                 outSISIDXREG(SISSR, IND_SIS_PASSWORD, SIS_PASSWORD);
6507
6508                 sisfb_post_setmode(ivideo);
6509
6510                 /* Maximize regardless of sisfb_max at startup */
6511                 ivideo->default_var.yres_virtual = 32767;
6512
6513                 /* Force reset of x virtual in crtc_to_var */
6514                 ivideo->default_var.xres_virtual = 0;
6515
6516                 /* Copy mode timing to var */
6517                 sisfb_crtc_to_var(ivideo, &ivideo->default_var);
6518
6519                 /* Find out about screen pitch */
6520                 sisfb_calc_pitch(ivideo, &ivideo->default_var);
6521                 sisfb_set_pitch(ivideo);
6522
6523                 /* Init the accelerator (does nothing currently) */
6524                 sisfb_initaccel(ivideo);
6525
6526                 /* Init some fbinfo entries */
6527                 sis_fb_info->node  = -1;
6528                 sis_fb_info->flags = FBINFO_FLAG_DEFAULT;
6529                 sis_fb_info->fbops = &sisfb_ops;
6530                 sis_fb_info->disp  = &ivideo->sis_disp;
6531                 sis_fb_info->blank = &sisfb_blank;
6532                 sis_fb_info->switch_con = &sisfb_switch;
6533                 sis_fb_info->updatevar  = &sisfb_update_var;
6534                 sis_fb_info->changevar  = NULL;
6535                 strcpy(sis_fb_info->fontname, sisfb_fontname);
6536
6537                 sisfb_set_disp(-1, &ivideo->default_var, sis_fb_info);
6538
6539 #else           /* --------- For 2.6: Setup a somewhat sane default var ------------ */
6540
6541                 printk(KERN_INFO "sisfb: Default mode is %dx%dx%d (%dHz)\n",
6542                         ivideo->video_width, ivideo->video_height, ivideo->video_bpp,
6543                         ivideo->refresh_rate);
6544
6545                 /* Set up the default var according to chosen default display mode */
6546                 ivideo->default_var.xres = ivideo->default_var.xres_virtual = ivideo->video_width;
6547                 ivideo->default_var.yres = ivideo->default_var.yres_virtual = ivideo->video_height;
6548                 ivideo->default_var.bits_per_pixel = ivideo->video_bpp;
6549
6550                 sisfb_bpp_to_var(ivideo, &ivideo->default_var);
6551
6552                 ivideo->default_var.pixclock = (u32) (1000000000 /
6553                         sisfb_mode_rate_to_dclock(&ivideo->SiS_Pr, ivideo->mode_no, ivideo->rate_idx));
6554
6555                 if(sisfb_mode_rate_to_ddata(&ivideo->SiS_Pr, ivideo->mode_no,
6556                                                 ivideo->rate_idx, &ivideo->default_var)) {
6557                         if((ivideo->default_var.vmode & FB_VMODE_MASK) == FB_VMODE_DOUBLE) {
6558                                 ivideo->default_var.pixclock <<= 1;
6559                         }
6560                 }
6561
6562                 if(ivideo->sisfb_ypan) {
6563                         /* Maximize regardless of sisfb_max at startup */
6564                         ivideo->default_var.yres_virtual =
6565                                 sisfb_calc_maxyres(ivideo, &ivideo->default_var);
6566                         if(ivideo->default_var.yres_virtual < ivideo->default_var.yres) {
6567                                 ivideo->default_var.yres_virtual = ivideo->default_var.yres;
6568                         }
6569                 }
6570
6571                 sisfb_calc_pitch(ivideo, &ivideo->default_var);
6572
6573                 ivideo->accel = 0;
6574                 if(ivideo->sisfb_accel) {
6575                         ivideo->accel = -1;
6576 #ifdef STUPID_ACCELF_TEXT_SHIT
6577                         ivideo->default_var.accel_flags |= FB_ACCELF_TEXT;
6578 #endif
6579                 }
6580                 sisfb_initaccel(ivideo);
6581
6582 #if defined(FBINFO_HWACCEL_DISABLED) && defined(FBINFO_HWACCEL_XPAN)
6583                 sis_fb_info->flags = FBINFO_DEFAULT             |
6584                                      FBINFO_HWACCEL_YPAN        |
6585                                      FBINFO_HWACCEL_XPAN        |
6586                                      FBINFO_HWACCEL_COPYAREA    |
6587                                      FBINFO_HWACCEL_FILLRECT    |
6588                                      ((ivideo->accel) ? 0 : FBINFO_HWACCEL_DISABLED);
6589 #else
6590                 sis_fb_info->flags = FBINFO_FLAG_DEFAULT;
6591 #endif
6592                 sis_fb_info->var = ivideo->default_var;
6593                 sis_fb_info->fix = ivideo->sisfb_fix;
6594                 sis_fb_info->screen_base = ivideo->video_vbase + ivideo->video_offset;
6595                 sis_fb_info->fbops = &sisfb_ops;
6596
6597                 sisfb_get_fix(&sis_fb_info->fix, -1, sis_fb_info);
6598                 sis_fb_info->pseudo_palette = ivideo->pseudo_palette;
6599
6600                 fb_alloc_cmap(&sis_fb_info->cmap, 256 , 0);
6601 #endif          /* 2.6 */
6602
6603                 printk(KERN_DEBUG "sisfb: Initial vbflags 0x%x\n", (int)ivideo->vbflags);
6604
6605 #ifdef CONFIG_MTRR
6606                 ivideo->mtrr = mtrr_add(ivideo->video_base, ivideo->video_size,
6607                                         MTRR_TYPE_WRCOMB, 1);
6608                 if(ivideo->mtrr < 0) {
6609                         printk(KERN_DEBUG "sisfb: Failed to add MTRRs\n");
6610                 }
6611 #endif
6612
6613 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
6614                 vc_resize_con(1, 1, 0);
6615 #endif
6616
6617                 if(register_framebuffer(sis_fb_info) < 0) {
6618                         printk(KERN_ERR "sisfb: Fatal error: Failed to register framebuffer\n");
6619                         ret = -EINVAL;
6620                         iounmap(ivideo->mmio_vbase);
6621                         goto error_0;
6622                 }
6623
6624                 ivideo->registered = 1;
6625
6626                 /* Enlist us */
6627                 ivideo->next = card_list;
6628                 card_list = ivideo;
6629
6630 #ifdef SIS_OLD_CONFIG_COMPAT
6631                 {
6632                 int ret;
6633                 /* Our ioctls are all "32/64bit compatible" */
6634                 ret =  register_ioctl32_conversion(FBIO_ALLOC,             NULL);
6635                 ret |= register_ioctl32_conversion(FBIO_FREE,              NULL);
6636                 ret |= register_ioctl32_conversion(FBIOGET_VBLANK,         NULL);
6637                 ret |= register_ioctl32_conversion(SISFB_GET_INFO_SIZE,    NULL);
6638                 ret |= register_ioctl32_conversion(SISFB_GET_INFO,         NULL);
6639                 ret |= register_ioctl32_conversion(SISFB_GET_TVPOSOFFSET,  NULL);
6640                 ret |= register_ioctl32_conversion(SISFB_SET_TVPOSOFFSET,  NULL);
6641                 ret |= register_ioctl32_conversion(SISFB_SET_LOCK,         NULL);
6642                 ret |= register_ioctl32_conversion(SISFB_GET_VBRSTATUS,    NULL);
6643                 ret |= register_ioctl32_conversion(SISFB_GET_AUTOMAXIMIZE, NULL);
6644                 ret |= register_ioctl32_conversion(SISFB_SET_AUTOMAXIMIZE, NULL);
6645                 ret |= register_ioctl32_conversion(SISFB_COMMAND,          NULL);
6646                 if(ret)
6647                         printk(KERN_ERR
6648                                 "sisfb: Error registering ioctl32 translations\n");
6649                 else
6650                         ivideo->ioctl32registered = 1;
6651                 }
6652 #endif
6653
6654                 printk(KERN_INFO "sisfb: 2D acceleration is %s, y-panning %s\n",
6655                         ivideo->sisfb_accel ? "enabled" : "disabled",
6656                         ivideo->sisfb_ypan  ?
6657                                 (ivideo->sisfb_max ? "enabled (auto-max)" :
6658                                                 "enabled (no auto-max)") :
6659                                                                         "disabled");
6660
6661
6662                 printk(KERN_INFO "fb%d: %s frame buffer device version %d.%d.%d\n",
6663 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
6664                         GET_FB_IDX(sis_fb_info->node),
6665 #else
6666                         sis_fb_info->node,
6667 #endif
6668                         ivideo->myid, VER_MAJOR, VER_MINOR, VER_LEVEL);
6669
6670                 printk(KERN_INFO "sisfb: Copyright (C) 2001-2005 Thomas Winischhofer\n");
6671
6672         }       /* if mode = "none" */
6673
6674         return 0;
6675 }
6676
6677 /*****************************************************/
6678 /*                PCI DEVICE HANDLING                */
6679 /*****************************************************/
6680
6681 static void __devexit sisfb_remove(struct pci_dev *pdev)
6682 {
6683         struct sis_video_info   *ivideo = pci_get_drvdata(pdev);
6684         struct fb_info          *sis_fb_info = ivideo->memyselfandi;
6685         int                     registered = ivideo->registered;
6686         int                     modechanged = ivideo->modechanged;
6687
6688 #ifdef SIS_OLD_CONFIG_COMPAT
6689         if(ivideo->ioctl32registered) {
6690                 int ret;
6691                 ret =  unregister_ioctl32_conversion(FBIO_ALLOC);
6692                 ret |= unregister_ioctl32_conversion(FBIO_FREE);
6693                 ret |= unregister_ioctl32_conversion(FBIOGET_VBLANK);
6694                 ret |= unregister_ioctl32_conversion(SISFB_GET_INFO_SIZE);
6695                 ret |= unregister_ioctl32_conversion(SISFB_GET_INFO);
6696                 ret |= unregister_ioctl32_conversion(SISFB_GET_TVPOSOFFSET);
6697                 ret |= unregister_ioctl32_conversion(SISFB_SET_TVPOSOFFSET);
6698                 ret |= unregister_ioctl32_conversion(SISFB_SET_LOCK);
6699                 ret |= unregister_ioctl32_conversion(SISFB_GET_VBRSTATUS);
6700                 ret |= unregister_ioctl32_conversion(SISFB_GET_AUTOMAXIMIZE);
6701                 ret |= unregister_ioctl32_conversion(SISFB_SET_AUTOMAXIMIZE);
6702                 ret |= unregister_ioctl32_conversion(SISFB_COMMAND);
6703                 if(ret)
6704                         printk(KERN_ERR
6705                              "sisfb: Error unregistering ioctl32 translations\n");
6706         }
6707 #endif
6708
6709         /* Unmap */
6710         iounmap(ivideo->mmio_vbase);
6711         iounmap(ivideo->video_vbase);
6712
6713         /* Release mem regions */
6714         release_mem_region(ivideo->video_base, ivideo->video_size);
6715         release_mem_region(ivideo->mmio_base, ivideo->mmio_size);
6716
6717         vfree(ivideo->bios_abase);
6718
6719         if(ivideo->lpcdev)
6720                 SIS_PCI_PUT_DEVICE(ivideo->lpcdev);
6721
6722         if(ivideo->nbridge)
6723                 SIS_PCI_PUT_DEVICE(ivideo->nbridge);
6724
6725 #ifdef CONFIG_MTRR
6726         /* Release MTRR region */
6727         if(ivideo->mtrr >= 0)
6728                 mtrr_del(ivideo->mtrr, ivideo->video_base, ivideo->video_size);
6729 #endif
6730
6731         pci_set_drvdata(pdev, NULL);
6732
6733         /* If device was disabled when starting, disable
6734          * it when quitting.
6735          */
6736         if(!ivideo->sisvga_enabled)
6737                 pci_disable_device(pdev);
6738
6739         /* Unregister the framebuffer */
6740         if(ivideo->registered) {
6741                 unregister_framebuffer(sis_fb_info);
6742 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,3))
6743                 framebuffer_release(sis_fb_info);
6744 #else
6745                 kfree(sis_fb_info);
6746 #endif
6747         }
6748
6749         /* OK, our ivideo is gone for good from here. */
6750
6751         /* TODO: Restore the initial mode
6752          * This sounds easy but is as good as impossible
6753          * on many machines with SiS chip and video bridge
6754          * since text modes are always set up differently
6755          * from machine to machine. Depends on the type
6756          * of integration between chipset and bridge.
6757          */
6758         if(registered && modechanged)
6759                 printk(KERN_INFO
6760                         "sisfb: Restoring of text mode not supported yet\n");
6761 };
6762
6763 static struct pci_driver sisfb_driver = {
6764         .name           = "sisfb",
6765         .id_table       = sisfb_pci_table,
6766         .probe          = sisfb_probe,
6767         .remove         = __devexit_p(sisfb_remove)
6768 };
6769
6770 SISINITSTATIC int __init sisfb_init(void)
6771 {
6772 #if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,8)
6773 #ifndef MODULE
6774         char *options = NULL;
6775
6776         if(fb_get_options("sisfb", &options))
6777                 return -ENODEV;
6778
6779         sisfb_setup(options);
6780 #endif
6781 #endif
6782         return pci_register_driver(&sisfb_driver);
6783 }
6784
6785 #if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,8)
6786 #ifndef MODULE
6787 module_init(sisfb_init);
6788 #endif
6789 #endif
6790
6791 /*****************************************************/
6792 /*                      MODULE                       */
6793 /*****************************************************/
6794
6795 #ifdef MODULE
6796
6797 static char             *mode = NULL;
6798 static int              vesa = -1;
6799 static unsigned int     rate = 0;
6800 static unsigned int     crt1off = 1;
6801 static unsigned int     mem = 0;
6802 static char             *forcecrt2type = NULL;
6803 static int              forcecrt1 = -1;
6804 static int              pdc = -1;
6805 static int              pdc1 = -1;
6806 static int              noaccel = -1;
6807 static int              noypan  = -1;
6808 static int              nomax = -1;
6809 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
6810 static int              inverse = 0;
6811 #endif
6812 static int              userom = -1;
6813 static int              useoem = -1;
6814 static char             *tvstandard = NULL;
6815 static int              nocrt2rate = 0;
6816 static int              scalelcd = -1;
6817 static char             *specialtiming = NULL;
6818 static int              lvdshl = -1;
6819 static int              tvxposoffset = 0, tvyposoffset = 0;
6820 #if !defined(__i386__) && !defined(__x86_64__)
6821 static int              resetcard = 0;
6822 static int              videoram = 0;
6823 #endif
6824
6825 static int __init sisfb_init_module(void)
6826 {
6827         sisfb_setdefaultparms();
6828
6829         if(rate)
6830                 sisfb_parm_rate = rate;
6831
6832         if((scalelcd == 0) || (scalelcd == 1))
6833                 sisfb_scalelcd = scalelcd ^ 1;
6834
6835         /* Need to check crt2 type first for fstn/dstn */
6836
6837         if(forcecrt2type)
6838                 sisfb_search_crt2type(forcecrt2type);
6839
6840         if(tvstandard)
6841                 sisfb_search_tvstd(tvstandard);
6842
6843         if(mode)
6844                 sisfb_search_mode(mode, FALSE);
6845         else if(vesa != -1)
6846                 sisfb_search_vesamode(vesa, FALSE);
6847
6848         sisfb_crt1off = (crt1off == 0) ? 1 : 0;
6849
6850         sisfb_forcecrt1 = forcecrt1;
6851         if(forcecrt1 == 1)
6852                 sisfb_crt1off = 0;
6853         else if(forcecrt1 == 0)
6854                 sisfb_crt1off = 1;
6855
6856         if(noaccel == 1)
6857                 sisfb_accel = 0;
6858         else if(noaccel == 0)
6859                 sisfb_accel = 1;
6860
6861         if(noypan == 1)
6862                 sisfb_ypan = 0;
6863         else if(noypan == 0)
6864                 sisfb_ypan = 1;
6865
6866         if(nomax == 1)
6867                 sisfb_max = 0;
6868         else if(nomax == 0)
6869                 sisfb_max = 1;
6870
6871 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
6872         if(inverse) sisfb_inverse = 1;
6873 #endif
6874
6875         if(mem)
6876                 sisfb_parm_mem = mem;
6877
6878         if(userom != -1)
6879                 sisfb_userom = userom;
6880
6881         if(useoem != -1)
6882                 sisfb_useoem = useoem;
6883
6884         if(pdc != -1)
6885                 sisfb_pdc  = (pdc  & 0x7f);
6886
6887         if(pdc1 != -1)
6888                 sisfb_pdca = (pdc1 & 0x1f);
6889
6890         sisfb_nocrt2rate = nocrt2rate;
6891
6892         if(specialtiming)
6893                 sisfb_search_specialtiming(specialtiming);
6894
6895         if((lvdshl >= 0) && (lvdshl <= 3))
6896                 sisfb_lvdshl = lvdshl;
6897
6898         sisfb_tvxposoffset = tvxposoffset;
6899         sisfb_tvyposoffset = tvyposoffset;
6900
6901 #if !defined(__i386__) && !defined(__x86_64__)
6902         sisfb_resetcard = (resetcard) ? 1 : 0;
6903         if(videoram)
6904                 sisfb_videoram = videoram;
6905 #endif
6906
6907         return sisfb_init();
6908 }
6909
6910 static void __exit sisfb_remove_module(void)
6911 {
6912         pci_unregister_driver(&sisfb_driver);
6913         printk(KERN_DEBUG "sisfb: Module unloaded\n");
6914 }
6915
6916 module_init(sisfb_init_module);
6917 module_exit(sisfb_remove_module);
6918
6919 MODULE_DESCRIPTION("SiS 300/540/630/730/315/55x/65x/661/74x/330/76x/34x, XGI V3XT/V5/V8/Z7 framebuffer device driver");
6920 MODULE_LICENSE("GPL");
6921 MODULE_AUTHOR("Thomas Winischhofer <thomas@winischhofer.net>, Others");
6922
6923 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
6924 MODULE_PARM(mem, "i");
6925 MODULE_PARM(noaccel, "i");
6926 MODULE_PARM(noypan, "i");
6927 MODULE_PARM(nomax, "i");
6928 MODULE_PARM(userom, "i");
6929 MODULE_PARM(useoem, "i");
6930 MODULE_PARM(mode, "s");
6931 MODULE_PARM(vesa, "i");
6932 MODULE_PARM(rate, "i");
6933 MODULE_PARM(forcecrt1, "i");
6934 MODULE_PARM(forcecrt2type, "s");
6935 MODULE_PARM(scalelcd, "i");
6936 MODULE_PARM(pdc, "i");
6937 MODULE_PARM(pdc1, "i");
6938 MODULE_PARM(specialtiming, "s");
6939 MODULE_PARM(lvdshl, "i");
6940 MODULE_PARM(tvstandard, "s");
6941 MODULE_PARM(tvxposoffset, "i");
6942 MODULE_PARM(tvyposoffset, "i");
6943 MODULE_PARM(nocrt2rate, "i");
6944 MODULE_PARM(inverse, "i");
6945 #if !defined(__i386__) && !defined(__x86_64__)
6946 MODULE_PARM(resetcard, "i");
6947 MODULE_PARM(videoram, "i");
6948 #endif
6949 #endif
6950
6951 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0)
6952 module_param(mem, int, 0);
6953 module_param(noaccel, int, 0);
6954 module_param(noypan, int, 0);
6955 module_param(nomax, int, 0);
6956 module_param(userom, int, 0);
6957 module_param(useoem, int, 0);
6958 module_param(mode, charp, 0);
6959 module_param(vesa, int, 0);
6960 module_param(rate, int, 0);
6961 module_param(forcecrt1, int, 0);
6962 module_param(forcecrt2type, charp, 0);
6963 module_param(scalelcd, int, 0);
6964 module_param(pdc, int, 0);
6965 module_param(pdc1, int, 0);
6966 module_param(specialtiming, charp, 0);
6967 module_param(lvdshl, int, 0);
6968 module_param(tvstandard, charp, 0);
6969 module_param(tvxposoffset, int, 0);
6970 module_param(tvyposoffset, int, 0);
6971 module_param(nocrt2rate, int, 0);
6972 #if !defined(__i386__) && !defined(__x86_64__)
6973 module_param(resetcard, int, 0);
6974 module_param(videoram, int, 0);
6975 #endif
6976 #endif
6977
6978 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
6979 MODULE_PARM_DESC(mem,
6980         "\nDetermines the beginning of the video memory heap in KB. This heap is used\n"
6981           "for video RAM management for eg. DRM/DRI. On 300 series, the default depends\n"
6982           "on the amount of video RAM available. If 8MB of video RAM or less is available,\n"
6983           "the heap starts at 4096KB, if between 8 and 16MB are available at 8192KB,\n"
6984           "otherwise at 12288KB. On 315/330/340 series, the heap size is 32KB by default.\n"
6985           "The value is to be specified without 'KB' and must match the MaxXFBMem setting\n"
6986           "for XFree86 4.x/X.org 6.7 and later.\n");
6987 #else
6988 MODULE_PARM_DESC(mem,
6989         "\nDetermines the beginning of the video memory heap in KB. This heap is used\n"
6990           "for video RAM management for eg. DRM/DRI. On 300 series, the default depends\n"
6991           "on the amount of video RAM available. If 8MB of video RAM or less is available,\n"
6992           "the heap starts at 4096KB, if between 8 and 16MB are available at 8192KB,\n"
6993           "otherwise at 12288KB. On 315/330/340 series, the heap size is 32KB by default.\n"
6994           "The value is to be specified without 'KB'.\n");
6995 #endif
6996
6997 MODULE_PARM_DESC(noaccel,
6998         "\nIf set to anything other than 0, 2D acceleration will be disabled.\n"
6999           "(default: 0)\n");
7000
7001 MODULE_PARM_DESC(noypan,
7002         "\nIf set to anything other than 0, y-panning will be disabled and scrolling\n"
7003           "will be performed by redrawing the screen. (default: 0)\n");
7004
7005 MODULE_PARM_DESC(nomax,
7006         "\nIf y-panning is enabled, sisfb will by default use the entire available video\n"
7007           "memory for the virtual screen in order to optimize scrolling performance. If\n"
7008           "this is set to anything other than 0, sisfb will not do this and thereby \n"
7009           "enable the user to positively specify a virtual Y size of the screen using\n"
7010           "fbset. (default: 0)\n");
7011
7012 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
7013 MODULE_PARM_DESC(mode,
7014         "\nSelects the desired display mode in the format [X]x[Y]x[Depth], eg.\n"
7015           "1024x768x16. Other formats supported include XxY-Depth and\n"
7016           "XxY-Depth@Rate. If the parameter is only one (decimal or hexadecimal)\n"
7017           "number, it will be interpreted as a VESA mode number. (default: none if\n"
7018           "sisfb is a module; this leaves the console untouched and the driver will\n"
7019           "only do the video memory management for eg. DRM/DRI; 800x600x8 if sisfb\n"
7020           "is in the kernel)\n");
7021 MODULE_PARM_DESC(vesa,
7022         "\nSelects the desired display mode by VESA defined mode number, eg. 0x117\n"
7023           "(default: 0x0000 if sisfb is a module; this leaves the console untouched\n"
7024           "and the driver will only do the video memory management for eg. DRM/DRI;\n"
7025           "0x0103 if sisfb is in the kernel)\n");
7026 #endif
7027
7028 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0)
7029 MODULE_PARM_DESC(mode,
7030         "\nSelects the desired default display mode in the format XxYxDepth,\n"
7031          "eg. 1024x768x16. Other formats supported include XxY-Depth and\n"
7032          "XxY-Depth@Rate. If the parameter is only one (decimal or hexadecimal)\n"
7033          "number, it will be interpreted as a VESA mode number. (default: 800x600x8)\n");
7034
7035 MODULE_PARM_DESC(vesa,
7036         "\nSelects the desired default display mode by VESA defined mode number, eg.\n"
7037          "0x117 (default: 0x0103)\n");
7038 #endif
7039
7040 MODULE_PARM_DESC(rate,
7041         "\nSelects the desired vertical refresh rate for CRT1 (external VGA) in Hz.\n"
7042           "If the mode is specified in the format XxY-Depth@Rate, this parameter\n"
7043           "will be ignored (default: 60)\n");
7044
7045 MODULE_PARM_DESC(forcecrt1,
7046         "\nNormally, the driver autodetects whether or not CRT1 (external VGA) is \n"
7047           "connected. With this option, the detection can be overridden (1=CRT1 ON,\n"
7048           "0=CRT1 OFF) (default: [autodetected])\n");
7049
7050 MODULE_PARM_DESC(forcecrt2type,
7051         "\nIf this option is omitted, the driver autodetects CRT2 output devices, such as\n"
7052           "LCD, TV or secondary VGA. With this option, this autodetection can be\n"
7053           "overridden. Possible parameters are LCD, TV, VGA or NONE. NONE disables CRT2.\n"
7054           "On systems with a SiS video bridge, parameters SVIDEO, COMPOSITE or SCART can\n"
7055           "be used instead of TV to override the TV detection. Furthermore, on systems\n"
7056           "with a SiS video bridge, SVIDEO+COMPOSITE, HIVISION, YPBPR480I, YPBPR480P,\n"
7057           "YPBPR720P and YPBPR1080I are understood. However, whether or not these work\n"
7058           "depends on the very hardware in use. (default: [autodetected])\n");
7059
7060 MODULE_PARM_DESC(scalelcd,
7061         "\nSetting this to 1 will force the driver to scale the LCD image to the panel's\n"
7062           "native resolution. Setting it to 0 will disable scaling; LVDS panels will\n"
7063           "show black bars around the image, TMDS panels will probably do the scaling\n"
7064           "themselves. Default: 1 on LVDS panels, 0 on TMDS panels\n");
7065
7066 MODULE_PARM_DESC(pdc,
7067         "\nThis is for manually selecting the LCD panel delay compensation. The driver\n"
7068           "should detect this correctly in most cases; however, sometimes this is not\n"
7069           "possible. If you see 'small waves' on the LCD, try setting this to 4, 32 or 24\n"
7070           "on a 300 series chipset; 6 on other chipsets. If the problem persists, try\n"
7071           "other values (on 300 series: between 4 and 60 in steps of 4; otherwise: any\n"
7072           "value from 0 to 31). (default: autodetected, if LCD is active during start)\n");
7073
7074 #ifdef CONFIG_FB_SIS_315
7075 MODULE_PARM_DESC(pdc1,
7076         "\nThis is same as pdc, but for LCD-via CRT1. Hence, this is for the 315/330/340\n"
7077           "series only. (default: autodetected if LCD is in LCD-via-CRT1 mode during\n"
7078           "startup) - Note: currently, this has no effect because LCD-via-CRT1 is not\n"
7079           "implemented yet.\n");
7080 #endif
7081
7082 MODULE_PARM_DESC(specialtiming,
7083         "\nPlease refer to documentation for more information on this option.\n");
7084
7085 MODULE_PARM_DESC(lvdshl,
7086         "\nPlease refer to documentation for more information on this option.\n");
7087
7088 MODULE_PARM_DESC(tvstandard,
7089         "\nThis allows overriding the BIOS default for the TV standard. Valid choices are\n"
7090           "pal, ntsc, palm and paln. (default: [auto; pal or ntsc only])\n");
7091
7092 MODULE_PARM_DESC(tvxposoffset,
7093         "\nRelocate TV output horizontally. Possible parameters: -32 through 32.\n"
7094           "Default: 0\n");
7095
7096 MODULE_PARM_DESC(tvyposoffset,
7097         "\nRelocate TV output vertically. Possible parameters: -32 through 32.\n"
7098           "Default: 0\n");
7099
7100 MODULE_PARM_DESC(nocrt2rate,
7101         "\nSetting this to 1 will force the driver to use the default refresh rate for\n"
7102           "CRT2 if CRT2 type is VGA. (default: 0, use same rate as CRT1)\n");
7103
7104 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
7105 MODULE_PARM_DESC(inverse,
7106         "\nSetting this to anything but 0 should invert the display colors, but this\n"
7107           "does not seem to work. (default: 0)\n");
7108 #endif
7109
7110 #if !defined(__i386__) && !defined(__x86_64__)
7111 #ifdef CONFIG_FB_SIS_300
7112 MODULE_PARM_DESC(resetcard,
7113         "\nSet this to 1 in order to reset (POST) the card on non-x86 machines where\n"
7114           "the BIOS did not POST the card (only supported for SiS 300/305 and XGI cards\n"
7115           "currently). Default: 0\n");
7116
7117 MODULE_PARM_DESC(videoram,
7118         "\nSet this to the amount of video RAM (in kilobyte) the card has. Required on\n"
7119           "some non-x86 architectures where the memory auto detection fails. Only\n"
7120           "relevant if resetcard is set, too. SiS300/305 only. Default: [auto-detect]\n");
7121 #endif
7122 #endif
7123
7124 #endif     /*  /MODULE  */
7125
7126 /* _GPL only for new symbols. */
7127 EXPORT_SYMBOL(sis_malloc);
7128 EXPORT_SYMBOL(sis_free);
7129 EXPORT_SYMBOL_GPL(sis_malloc_new);
7130 EXPORT_SYMBOL_GPL(sis_free_new);
7131
7132
7133