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