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