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