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