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