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