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