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