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