video: fbdev: replace strnicmp with strncasecmp
[sfrench/cifs-2.6.git] / drivers / video / fbdev / 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 #if !defined(CONFIG_FB_SIS_300) && !defined(CONFIG_FB_SIS_315)
64 #warning Neither CONFIG_FB_SIS_300 nor CONFIG_FB_SIS_315 is set
65 #warning sisfb will not work!
66 #endif
67
68 static void sisfb_handle_command(struct sis_video_info *ivideo,
69                                  struct sisfb_cmd *sisfb_command);
70
71 /* ------------------ Internal helper routines ----------------- */
72
73 static void __init
74 sisfb_setdefaultparms(void)
75 {
76         sisfb_off               = 0;
77         sisfb_parm_mem          = 0;
78         sisfb_accel             = -1;
79         sisfb_ypan              = -1;
80         sisfb_max               = -1;
81         sisfb_userom            = -1;
82         sisfb_useoem            = -1;
83         sisfb_mode_idx          = -1;
84         sisfb_parm_rate         = -1;
85         sisfb_crt1off           = 0;
86         sisfb_forcecrt1         = -1;
87         sisfb_crt2type          = -1;
88         sisfb_crt2flags         = 0;
89         sisfb_pdc               = 0xff;
90         sisfb_pdca              = 0xff;
91         sisfb_scalelcd          = -1;
92         sisfb_specialtiming     = CUT_NONE;
93         sisfb_lvdshl            = -1;
94         sisfb_dstn              = 0;
95         sisfb_fstn              = 0;
96         sisfb_tvplug            = -1;
97         sisfb_tvstd             = -1;
98         sisfb_tvxposoffset      = 0;
99         sisfb_tvyposoffset      = 0;
100         sisfb_nocrt2rate        = 0;
101 #if !defined(__i386__) && !defined(__x86_64__)
102         sisfb_resetcard         = 0;
103         sisfb_videoram          = 0;
104 #endif
105 }
106
107 /* ------------- Parameter parsing -------------- */
108
109 static void sisfb_search_vesamode(unsigned int vesamode, bool quiet)
110 {
111         int i = 0, j = 0;
112
113         /* We don't know the hardware specs yet and there is no ivideo */
114
115         if(vesamode == 0) {
116                 if(!quiet)
117                         printk(KERN_ERR "sisfb: Invalid mode. Using default.\n");
118
119                 sisfb_mode_idx = DEFAULT_MODE;
120
121                 return;
122         }
123
124         vesamode &= 0x1dff;  /* Clean VESA mode number from other flags */
125
126         while(sisbios_mode[i++].mode_no[0] != 0) {
127                 if( (sisbios_mode[i-1].vesa_mode_no_1 == vesamode) ||
128                     (sisbios_mode[i-1].vesa_mode_no_2 == vesamode) ) {
129                         if(sisfb_fstn) {
130                                 if(sisbios_mode[i-1].mode_no[1] == 0x50 ||
131                                    sisbios_mode[i-1].mode_no[1] == 0x56 ||
132                                    sisbios_mode[i-1].mode_no[1] == 0x53)
133                                         continue;
134                         } else {
135                                 if(sisbios_mode[i-1].mode_no[1] == 0x5a ||
136                                    sisbios_mode[i-1].mode_no[1] == 0x5b)
137                                         continue;
138                         }
139                         sisfb_mode_idx = i - 1;
140                         j = 1;
141                         break;
142                 }
143         }
144         if((!j) && !quiet)
145                 printk(KERN_ERR "sisfb: Invalid VESA mode 0x%x'\n", vesamode);
146 }
147
148 static void sisfb_search_mode(char *name, bool quiet)
149 {
150         unsigned int j = 0, xres = 0, yres = 0, depth = 0, rate = 0;
151         int i = 0;
152         char strbuf[16], strbuf1[20];
153         char *nameptr = name;
154
155         /* We don't know the hardware specs yet and there is no ivideo */
156
157         if(name == NULL) {
158                 if(!quiet)
159                         printk(KERN_ERR "sisfb: Internal error, using default mode.\n");
160
161                 sisfb_mode_idx = DEFAULT_MODE;
162                 return;
163         }
164
165         if(!strncasecmp(name, sisbios_mode[MODE_INDEX_NONE].name, strlen(name))) {
166                 if(!quiet)
167                         printk(KERN_ERR "sisfb: Mode 'none' not supported anymore. Using default.\n");
168
169                 sisfb_mode_idx = DEFAULT_MODE;
170                 return;
171         }
172
173         if(strlen(name) <= 19) {
174                 strcpy(strbuf1, name);
175                 for(i = 0; i < strlen(strbuf1); i++) {
176                         if(strbuf1[i] < '0' || strbuf1[i] > '9') strbuf1[i] = ' ';
177                 }
178
179                 /* This does some fuzzy mode naming detection */
180                 if(sscanf(strbuf1, "%u %u %u %u", &xres, &yres, &depth, &rate) == 4) {
181                         if((rate <= 32) || (depth > 32)) {
182                                 j = rate; rate = depth; depth = j;
183                         }
184                         sprintf(strbuf, "%ux%ux%u", xres, yres, depth);
185                         nameptr = strbuf;
186                         sisfb_parm_rate = rate;
187                 } else if(sscanf(strbuf1, "%u %u %u", &xres, &yres, &depth) == 3) {
188                         sprintf(strbuf, "%ux%ux%u", xres, yres, depth);
189                         nameptr = strbuf;
190                 } else {
191                         xres = 0;
192                         if((sscanf(strbuf1, "%u %u", &xres, &yres) == 2) && (xres != 0)) {
193                                 sprintf(strbuf, "%ux%ux8", xres, yres);
194                                 nameptr = strbuf;
195                         } else {
196                                 sisfb_search_vesamode(simple_strtoul(name, NULL, 0), quiet);
197                                 return;
198                         }
199                 }
200         }
201
202         i = 0; j = 0;
203         while(sisbios_mode[i].mode_no[0] != 0) {
204                 if(!strncasecmp(nameptr, sisbios_mode[i++].name, strlen(nameptr))) {
205                         if(sisfb_fstn) {
206                                 if(sisbios_mode[i-1].mode_no[1] == 0x50 ||
207                                    sisbios_mode[i-1].mode_no[1] == 0x56 ||
208                                    sisbios_mode[i-1].mode_no[1] == 0x53)
209                                         continue;
210                         } else {
211                                 if(sisbios_mode[i-1].mode_no[1] == 0x5a ||
212                                    sisbios_mode[i-1].mode_no[1] == 0x5b)
213                                         continue;
214                         }
215                         sisfb_mode_idx = i - 1;
216                         j = 1;
217                         break;
218                 }
219         }
220
221         if((!j) && !quiet)
222                 printk(KERN_ERR "sisfb: Invalid mode '%s'\n", nameptr);
223 }
224
225 #ifndef MODULE
226 static void sisfb_get_vga_mode_from_kernel(void)
227 {
228 #ifdef CONFIG_X86
229         char mymode[32];
230         int  mydepth = screen_info.lfb_depth;
231
232         if(screen_info.orig_video_isVGA != VIDEO_TYPE_VLFB) return;
233
234         if( (screen_info.lfb_width >= 320) && (screen_info.lfb_width <= 2048) &&
235             (screen_info.lfb_height >= 200) && (screen_info.lfb_height <= 1536) &&
236             (mydepth >= 8) && (mydepth <= 32) ) {
237
238                 if(mydepth == 24) mydepth = 32;
239
240                 sprintf(mymode, "%ux%ux%u", screen_info.lfb_width,
241                                         screen_info.lfb_height,
242                                         mydepth);
243
244                 printk(KERN_DEBUG
245                         "sisfb: Using vga mode %s pre-set by kernel as default\n",
246                         mymode);
247
248                 sisfb_search_mode(mymode, true);
249         }
250 #endif
251         return;
252 }
253 #endif
254
255 static void __init
256 sisfb_search_crt2type(const char *name)
257 {
258         int i = 0;
259
260         /* We don't know the hardware specs yet and there is no ivideo */
261
262         if(name == NULL) return;
263
264         while(sis_crt2type[i].type_no != -1) {
265                 if(!strncasecmp(name, sis_crt2type[i].name, strlen(sis_crt2type[i].name))) {
266                         sisfb_crt2type = sis_crt2type[i].type_no;
267                         sisfb_tvplug = sis_crt2type[i].tvplug_no;
268                         sisfb_crt2flags = sis_crt2type[i].flags;
269                         break;
270                 }
271                 i++;
272         }
273
274         sisfb_dstn = (sisfb_crt2flags & FL_550_DSTN) ? 1 : 0;
275         sisfb_fstn = (sisfb_crt2flags & FL_550_FSTN) ? 1 : 0;
276
277         if(sisfb_crt2type < 0)
278                 printk(KERN_ERR "sisfb: Invalid CRT2 type: %s\n", name);
279 }
280
281 static void __init
282 sisfb_search_tvstd(const char *name)
283 {
284         int i = 0;
285
286         /* We don't know the hardware specs yet and there is no ivideo */
287
288         if(name == NULL)
289                 return;
290
291         while(sis_tvtype[i].type_no != -1) {
292                 if(!strncasecmp(name, sis_tvtype[i].name, strlen(sis_tvtype[i].name))) {
293                         sisfb_tvstd = sis_tvtype[i].type_no;
294                         break;
295                 }
296                 i++;
297         }
298 }
299
300 static void __init
301 sisfb_search_specialtiming(const char *name)
302 {
303         int i = 0;
304         bool found = false;
305
306         /* We don't know the hardware specs yet and there is no ivideo */
307
308         if(name == NULL)
309                 return;
310
311         if(!strncasecmp(name, "none", 4)) {
312                 sisfb_specialtiming = CUT_FORCENONE;
313                 printk(KERN_DEBUG "sisfb: Special timing disabled\n");
314         } else {
315                 while(mycustomttable[i].chipID != 0) {
316                         if(!strncasecmp(name,mycustomttable[i].optionName,
317                            strlen(mycustomttable[i].optionName))) {
318                                 sisfb_specialtiming = mycustomttable[i].SpecialID;
319                                 found = true;
320                                 printk(KERN_INFO "sisfb: Special timing for %s %s forced (\"%s\")\n",
321                                         mycustomttable[i].vendorName,
322                                         mycustomttable[i].cardName,
323                                         mycustomttable[i].optionName);
324                                 break;
325                         }
326                         i++;
327                 }
328                 if(!found) {
329                         printk(KERN_WARNING "sisfb: Invalid SpecialTiming parameter, valid are:");
330                         printk(KERN_WARNING "\t\"none\" (to disable special timings)\n");
331                         i = 0;
332                         while(mycustomttable[i].chipID != 0) {
333                                 printk(KERN_WARNING "\t\"%s\" (for %s %s)\n",
334                                         mycustomttable[i].optionName,
335                                         mycustomttable[i].vendorName,
336                                         mycustomttable[i].cardName);
337                                 i++;
338                         }
339                 }
340         }
341 }
342
343 /* ----------- Various detection routines ----------- */
344
345 static void sisfb_detect_custom_timing(struct sis_video_info *ivideo)
346 {
347         unsigned char *biosver = NULL;
348         unsigned char *biosdate = NULL;
349         bool footprint;
350         u32 chksum = 0;
351         int i, j;
352
353         if(ivideo->SiS_Pr.UseROM) {
354                 biosver = ivideo->SiS_Pr.VirtualRomBase + 0x06;
355                 biosdate = ivideo->SiS_Pr.VirtualRomBase + 0x2c;
356                 for(i = 0; i < 32768; i++)
357                         chksum += ivideo->SiS_Pr.VirtualRomBase[i];
358         }
359
360         i = 0;
361         do {
362                 if( (mycustomttable[i].chipID == ivideo->chip)                  &&
363                     ((!strlen(mycustomttable[i].biosversion)) ||
364                      (ivideo->SiS_Pr.UseROM &&
365                       (!strncmp(mycustomttable[i].biosversion, biosver,
366                                 strlen(mycustomttable[i].biosversion)))))       &&
367                     ((!strlen(mycustomttable[i].biosdate)) ||
368                      (ivideo->SiS_Pr.UseROM &&
369                       (!strncmp(mycustomttable[i].biosdate, biosdate,
370                                 strlen(mycustomttable[i].biosdate)))))          &&
371                     ((!mycustomttable[i].bioschksum) ||
372                      (ivideo->SiS_Pr.UseROM &&
373                       (mycustomttable[i].bioschksum == chksum)))                &&
374                     (mycustomttable[i].pcisubsysvendor == ivideo->subsysvendor) &&
375                     (mycustomttable[i].pcisubsyscard == ivideo->subsysdevice) ) {
376                         footprint = true;
377                         for(j = 0; j < 5; j++) {
378                                 if(mycustomttable[i].biosFootprintAddr[j]) {
379                                         if(ivideo->SiS_Pr.UseROM) {
380                                                 if(ivideo->SiS_Pr.VirtualRomBase[mycustomttable[i].biosFootprintAddr[j]] !=
381                                                         mycustomttable[i].biosFootprintData[j]) {
382                                                         footprint = false;
383                                                 }
384                                         } else
385                                                 footprint = false;
386                                 }
387                         }
388                         if(footprint) {
389                                 ivideo->SiS_Pr.SiS_CustomT = mycustomttable[i].SpecialID;
390                                 printk(KERN_DEBUG "sisfb: Identified [%s %s], special timing applies\n",
391                                         mycustomttable[i].vendorName,
392                                 mycustomttable[i].cardName);
393                                 printk(KERN_DEBUG "sisfb: [specialtiming parameter name: %s]\n",
394                                         mycustomttable[i].optionName);
395                                 break;
396                         }
397                 }
398                 i++;
399         } while(mycustomttable[i].chipID);
400 }
401
402 static bool 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 sisfb_handle_ddc(struct sis_video_info *ivideo,
504                              struct sisfb_monitor *monitor, int crtno)
505 {
506         unsigned short temp, i, realcrtno = crtno;
507         unsigned char  buffer[256];
508
509         monitor->datavalid = false;
510
511         if(crtno) {
512            if(ivideo->vbflags & CRT2_LCD)      realcrtno = 1;
513            else if(ivideo->vbflags & CRT2_VGA) realcrtno = 2;
514            else return;
515         }
516
517         if((ivideo->sisfb_crt1off) && (!crtno))
518                 return;
519
520         temp = SiS_HandleDDC(&ivideo->SiS_Pr, ivideo->vbflags, ivideo->sisvga_engine,
521                                 realcrtno, 0, &buffer[0], ivideo->vbflags2);
522         if((!temp) || (temp == 0xffff)) {
523            printk(KERN_INFO "sisfb: CRT%d DDC probing failed\n", crtno + 1);
524            return;
525         } else {
526            printk(KERN_INFO "sisfb: CRT%d DDC supported\n", crtno + 1);
527            printk(KERN_INFO "sisfb: CRT%d DDC level: %s%s%s%s\n",
528                 crtno + 1,
529                 (temp & 0x1a) ? "" : "[none of the supported]",
530                 (temp & 0x02) ? "2 " : "",
531                 (temp & 0x08) ? "D&P" : "",
532                 (temp & 0x10) ? "FPDI-2" : "");
533            if(temp & 0x02) {
534               i = 3;  /* Number of retrys */
535               do {
536                  temp = SiS_HandleDDC(&ivideo->SiS_Pr, ivideo->vbflags, ivideo->sisvga_engine,
537                                      realcrtno, 1, &buffer[0], ivideo->vbflags2);
538               } while((temp) && i--);
539               if(!temp) {
540                  if(sisfb_interpret_edid(monitor, &buffer[0])) {
541                     printk(KERN_INFO "sisfb: Monitor range H %d-%dKHz, V %d-%dHz, Max. dotclock %dMHz\n",
542                         monitor->hmin, monitor->hmax, monitor->vmin, monitor->vmax,
543                         monitor->dclockmax / 1000);
544                  } else {
545                     printk(KERN_INFO "sisfb: CRT%d DDC EDID corrupt\n", crtno + 1);
546                  }
547               } else {
548                  printk(KERN_INFO "sisfb: CRT%d DDC reading failed\n", crtno + 1);
549               }
550            } else {
551               printk(KERN_INFO "sisfb: VESA D&P and FPDI-2 not supported yet\n");
552            }
553         }
554 }
555
556 /* -------------- Mode validation --------------- */
557
558 static bool
559 sisfb_verify_rate(struct sis_video_info *ivideo, struct sisfb_monitor *monitor,
560                 int mode_idx, int rate_idx, int rate)
561 {
562         int htotal, vtotal;
563         unsigned int dclock, hsync;
564
565         if(!monitor->datavalid)
566                 return true;
567
568         if(mode_idx < 0)
569                 return false;
570
571         /* Skip for 320x200, 320x240, 640x400 */
572         switch(sisbios_mode[mode_idx].mode_no[ivideo->mni]) {
573         case 0x59:
574         case 0x41:
575         case 0x4f:
576         case 0x50:
577         case 0x56:
578         case 0x53:
579         case 0x2f:
580         case 0x5d:
581         case 0x5e:
582                 return true;
583 #ifdef CONFIG_FB_SIS_315
584         case 0x5a:
585         case 0x5b:
586                 if(ivideo->sisvga_engine == SIS_315_VGA) return true;
587 #endif
588         }
589
590         if(rate < (monitor->vmin - 1))
591                 return false;
592         if(rate > (monitor->vmax + 1))
593                 return false;
594
595         if(sisfb_gettotalfrommode(&ivideo->SiS_Pr,
596                                   sisbios_mode[mode_idx].mode_no[ivideo->mni],
597                                   &htotal, &vtotal, rate_idx)) {
598                 dclock = (htotal * vtotal * rate) / 1000;
599                 if(dclock > (monitor->dclockmax + 1000))
600                         return false;
601                 hsync = dclock / htotal;
602                 if(hsync < (monitor->hmin - 1))
603                         return false;
604                 if(hsync > (monitor->hmax + 1))
605                         return false;
606         } else {
607                 return false;
608         }
609         return true;
610 }
611
612 static int
613 sisfb_validate_mode(struct sis_video_info *ivideo, int myindex, u32 vbflags)
614 {
615         u16 xres=0, yres, myres;
616
617 #ifdef CONFIG_FB_SIS_300
618         if(ivideo->sisvga_engine == SIS_300_VGA) {
619                 if(!(sisbios_mode[myindex].chipset & MD_SIS300))
620                         return -1 ;
621         }
622 #endif
623 #ifdef CONFIG_FB_SIS_315
624         if(ivideo->sisvga_engine == SIS_315_VGA) {
625                 if(!(sisbios_mode[myindex].chipset & MD_SIS315))
626                         return -1;
627         }
628 #endif
629
630         myres = sisbios_mode[myindex].yres;
631
632         switch(vbflags & VB_DISPTYPE_DISP2) {
633
634         case CRT2_LCD:
635                 xres = ivideo->lcdxres; yres = ivideo->lcdyres;
636
637                 if((ivideo->SiS_Pr.SiS_CustomT != CUT_PANEL848) &&
638                    (ivideo->SiS_Pr.SiS_CustomT != CUT_PANEL856)) {
639                         if(sisbios_mode[myindex].xres > xres)
640                                 return -1;
641                         if(myres > yres)
642                                 return -1;
643                 }
644
645                 if(ivideo->sisfb_fstn) {
646                         if(sisbios_mode[myindex].xres == 320) {
647                                 if(myres == 240) {
648                                         switch(sisbios_mode[myindex].mode_no[1]) {
649                                                 case 0x50: myindex = MODE_FSTN_8;  break;
650                                                 case 0x56: myindex = MODE_FSTN_16; break;
651                                                 case 0x53: return -1;
652                                         }
653                                 }
654                         }
655                 }
656
657                 if(SiS_GetModeID_LCD(ivideo->sisvga_engine, vbflags, sisbios_mode[myindex].xres,
658                                 sisbios_mode[myindex].yres, 0, ivideo->sisfb_fstn,
659                                 ivideo->SiS_Pr.SiS_CustomT, xres, yres, ivideo->vbflags2) < 0x14) {
660                         return -1;
661                 }
662                 break;
663
664         case CRT2_TV:
665                 if(SiS_GetModeID_TV(ivideo->sisvga_engine, vbflags, sisbios_mode[myindex].xres,
666                                 sisbios_mode[myindex].yres, 0, ivideo->vbflags2) < 0x14) {
667                         return -1;
668                 }
669                 break;
670
671         case CRT2_VGA:
672                 if(SiS_GetModeID_VGA2(ivideo->sisvga_engine, vbflags, sisbios_mode[myindex].xres,
673                                 sisbios_mode[myindex].yres, 0, ivideo->vbflags2) < 0x14) {
674                         return -1;
675                 }
676                 break;
677         }
678
679         return myindex;
680 }
681
682 static u8
683 sisfb_search_refresh_rate(struct sis_video_info *ivideo, unsigned int rate, int mode_idx)
684 {
685         int i = 0;
686         u16 xres = sisbios_mode[mode_idx].xres;
687         u16 yres = sisbios_mode[mode_idx].yres;
688
689         ivideo->rate_idx = 0;
690         while((sisfb_vrate[i].idx != 0) && (sisfb_vrate[i].xres <= xres)) {
691                 if((sisfb_vrate[i].xres == xres) && (sisfb_vrate[i].yres == yres)) {
692                         if(sisfb_vrate[i].refresh == rate) {
693                                 ivideo->rate_idx = sisfb_vrate[i].idx;
694                                 break;
695                         } else if(sisfb_vrate[i].refresh > rate) {
696                                 if((sisfb_vrate[i].refresh - rate) <= 3) {
697                                         DPRINTK("sisfb: Adjusting rate from %d up to %d\n",
698                                                 rate, sisfb_vrate[i].refresh);
699                                         ivideo->rate_idx = sisfb_vrate[i].idx;
700                                         ivideo->refresh_rate = sisfb_vrate[i].refresh;
701                                 } else if((sisfb_vrate[i].idx != 1) &&
702                                                 ((rate - sisfb_vrate[i-1].refresh) <= 2)) {
703                                         DPRINTK("sisfb: Adjusting rate from %d down to %d\n",
704                                                 rate, sisfb_vrate[i-1].refresh);
705                                         ivideo->rate_idx = sisfb_vrate[i-1].idx;
706                                         ivideo->refresh_rate = sisfb_vrate[i-1].refresh;
707                                 }
708                                 break;
709                         } else if((rate - sisfb_vrate[i].refresh) <= 2) {
710                                 DPRINTK("sisfb: Adjusting rate from %d down to %d\n",
711                                                 rate, sisfb_vrate[i].refresh);
712                                 ivideo->rate_idx = sisfb_vrate[i].idx;
713                                 break;
714                         }
715                 }
716                 i++;
717         }
718         if(ivideo->rate_idx > 0) {
719                 return ivideo->rate_idx;
720         } else {
721                 printk(KERN_INFO "sisfb: Unsupported rate %d for %dx%d\n",
722                                 rate, xres, yres);
723                 return 0;
724         }
725 }
726
727 static bool
728 sisfb_bridgeisslave(struct sis_video_info *ivideo)
729 {
730         unsigned char P1_00;
731
732         if(!(ivideo->vbflags2 & VB2_VIDEOBRIDGE))
733                 return false;
734
735         P1_00 = SiS_GetReg(SISPART1, 0x00);
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         temp = SiS_GetReg(SISCR, 0x17);
750         if(!(temp & 0x80))
751                 return false;
752
753         temp = SiS_GetReg(SISSR, 0x1f);
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 (SiS_GetRegByte(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 ((!(SiS_GetRegByte(SISINPSTAT) & 0x08)) && --watchdog);
782         watchdog = 65536;
783         while ((SiS_GetRegByte(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         temp = SiS_GetReg(SISPART1, reg);
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                 reg1 = SiS_GetReg(SISPART1, (idx+0)); /* 30 */
836                 reg2 = SiS_GetReg(SISPART1, (idx+1)); /* 31 */
837                 reg3 = SiS_GetReg(SISPART1, (idx+2)); /* 32 */
838                 reg4 = SiS_GetReg(SISPART1, (idx+3)); /* 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 = SiS_GetRegByte(SISINPSTAT);
852                 if(reg1 & 0x08) ret |= FB_VBLANK_VSYNCING;
853                 if(reg1 & 0x01) ret |= FB_VBLANK_VBLANKING;
854                 reg1 = SiS_GetReg(SISCR, 0x20);
855                 reg1 = SiS_GetReg(SISCR, 0x1b);
856                 reg2 = SiS_GetReg(SISCR, 0x1c);
857                 reg3 = SiS_GetReg(SISCR, 0x1d);
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                                 SiS_SetRegANDOR(SISCR, ivideo->SiS_Pr.SiS_MyCR63, 0xbf, cr63);
929                         }
930
931                         if(!(sisfb_bridgeisslave(ivideo))) {
932                                 SiS_SetRegANDOR(SISSR, 0x01, ~0x20, sr01);
933                                 SiS_SetRegANDOR(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                         SiS_SetRegANDOR(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                                 SiS_SetRegANDOR(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                                 SiS_SetRegANDOR(SISPART2, 0x00, 0x1f, p2_0);
975                         }
976                 }
977
978         } else if(ivideo->currentvbflags & CRT2_VGA) {
979
980                 if(ivideo->vbflags2 & VB2_30xB) {
981                         SiS_SetRegANDOR(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                 SiS_SetReg(SISCR, 0x13, (HDisplay1 & 0xFF));
1113                 SiS_SetRegANDOR(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                 SiS_SetRegOR(SISPART1, ivideo->CRT2_write_enable, 0x01);
1119                 SiS_SetReg(SISPART1, 0x07, (HDisplay2 & 0xFF));
1120                 SiS_SetRegANDOR(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         SiS_SetReg(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         SiS_SetReg(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         SiS_SetReg(SISSR, IND_SIS_PASSWORD, SIS_PASSWORD);
1307
1308         SiS_SetReg(SISCR, 0x0D, base & 0xFF);
1309         SiS_SetReg(SISCR, 0x0C, (base >> 8) & 0xFF);
1310         SiS_SetReg(SISSR, 0x0D, (base >> 16) & 0xFF);
1311         if(ivideo->sisvga_engine == SIS_315_VGA) {
1312                 SiS_SetRegANDOR(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                 SiS_SetRegOR(SISPART1, ivideo->CRT2_write_enable, 0x01);
1321                 SiS_SetReg(SISPART1, 0x06, (base & 0xFF));
1322                 SiS_SetReg(SISPART1, 0x05, ((base >> 8) & 0xFF));
1323                 SiS_SetReg(SISPART1, 0x04, ((base >> 16) & 0xFF));
1324                 if(ivideo->sisvga_engine == SIS_315_VGA) {
1325                         SiS_SetRegANDOR(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_info *info,
1332               struct fb_var_screeninfo *var)
1333 {
1334         ivideo->current_base = var->yoffset * info->var.xres_virtual
1335                              + var->xoffset;
1336
1337         /* calculate base bpp dep. */
1338         switch (info->var.bits_per_pixel) {
1339         case 32:
1340                 break;
1341         case 16:
1342                 ivideo->current_base >>= 1;
1343                 break;
1344         case 8:
1345         default:
1346                 ivideo->current_base >>= 2;
1347                 break;
1348         }
1349
1350         ivideo->current_base += (ivideo->video_offset >> 2);
1351
1352         sisfb_set_base_CRT1(ivideo, ivideo->current_base);
1353         sisfb_set_base_CRT2(ivideo, ivideo->current_base);
1354
1355         return 0;
1356 }
1357
1358 static int
1359 sisfb_open(struct fb_info *info, int user)
1360 {
1361         return 0;
1362 }
1363
1364 static int
1365 sisfb_release(struct fb_info *info, int user)
1366 {
1367         return 0;
1368 }
1369
1370 static int
1371 sisfb_setcolreg(unsigned regno, unsigned red, unsigned green, unsigned blue,
1372                 unsigned transp, struct fb_info *info)
1373 {
1374         struct sis_video_info *ivideo = (struct sis_video_info *)info->par;
1375
1376         if(regno >= sisfb_get_cmap_len(&info->var))
1377                 return 1;
1378
1379         switch(info->var.bits_per_pixel) {
1380         case 8:
1381                 SiS_SetRegByte(SISDACA, regno);
1382                 SiS_SetRegByte(SISDACD, (red >> 10));
1383                 SiS_SetRegByte(SISDACD, (green >> 10));
1384                 SiS_SetRegByte(SISDACD, (blue >> 10));
1385                 if(ivideo->currentvbflags & VB_DISPTYPE_DISP2) {
1386                         SiS_SetRegByte(SISDAC2A, regno);
1387                         SiS_SetRegByte(SISDAC2D, (red >> 8));
1388                         SiS_SetRegByte(SISDAC2D, (green >> 8));
1389                         SiS_SetRegByte(SISDAC2D, (blue >> 8));
1390                 }
1391                 break;
1392         case 16:
1393                 if (regno >= 16)
1394                         break;
1395
1396                 ((u32 *)(info->pseudo_palette))[regno] =
1397                                 (red & 0xf800)          |
1398                                 ((green & 0xfc00) >> 5) |
1399                                 ((blue & 0xf800) >> 11);
1400                 break;
1401         case 32:
1402                 if (regno >= 16)
1403                         break;
1404
1405                 red >>= 8;
1406                 green >>= 8;
1407                 blue >>= 8;
1408                 ((u32 *)(info->pseudo_palette))[regno] =
1409                                 (red << 16) | (green << 8) | (blue);
1410                 break;
1411         }
1412         return 0;
1413 }
1414
1415 static int
1416 sisfb_set_par(struct fb_info *info)
1417 {
1418         int err;
1419
1420         if((err = sisfb_do_set_var(&info->var, 1, info)))
1421                 return err;
1422
1423         sisfb_get_fix(&info->fix, -1, info);
1424
1425         return 0;
1426 }
1427
1428 static int
1429 sisfb_check_var(struct fb_var_screeninfo *var, struct fb_info *info)
1430 {
1431         struct sis_video_info *ivideo = (struct sis_video_info *)info->par;
1432         unsigned int htotal = 0, vtotal = 0, myrateindex = 0;
1433         unsigned int drate = 0, hrate = 0, maxyres;
1434         int found_mode = 0;
1435         int refresh_rate, search_idx, tidx;
1436         bool recalc_clock = false;
1437         u32 pixclock;
1438
1439         htotal = var->left_margin + var->xres + var->right_margin + var->hsync_len;
1440
1441         vtotal = var->upper_margin + var->lower_margin + var->vsync_len;
1442
1443         pixclock = var->pixclock;
1444
1445         if((var->vmode & FB_VMODE_MASK) == FB_VMODE_NONINTERLACED) {
1446                 vtotal += var->yres;
1447                 vtotal <<= 1;
1448         } else if((var->vmode & FB_VMODE_MASK) == FB_VMODE_DOUBLE) {
1449                 vtotal += var->yres;
1450                 vtotal <<= 2;
1451         } else if((var->vmode & FB_VMODE_MASK) == FB_VMODE_INTERLACED) {
1452                 vtotal += var->yres;
1453                 vtotal <<= 1;
1454         } else
1455                 vtotal += var->yres;
1456
1457         if(!(htotal) || !(vtotal)) {
1458                 SISFAIL("sisfb: no valid timing data");
1459         }
1460
1461         search_idx = 0;
1462         while( (sisbios_mode[search_idx].mode_no[0] != 0) &&
1463                (sisbios_mode[search_idx].xres <= var->xres) ) {
1464                 if( (sisbios_mode[search_idx].xres == var->xres) &&
1465                     (sisbios_mode[search_idx].yres == var->yres) &&
1466                     (sisbios_mode[search_idx].bpp == var->bits_per_pixel)) {
1467                         if((tidx = sisfb_validate_mode(ivideo, search_idx,
1468                                                 ivideo->currentvbflags)) > 0) {
1469                                 found_mode = 1;
1470                                 search_idx = tidx;
1471                                 break;
1472                         }
1473                 }
1474                 search_idx++;
1475         }
1476
1477         if(!found_mode) {
1478                 search_idx = 0;
1479                 while(sisbios_mode[search_idx].mode_no[0] != 0) {
1480                    if( (var->xres <= sisbios_mode[search_idx].xres) &&
1481                        (var->yres <= sisbios_mode[search_idx].yres) &&
1482                        (var->bits_per_pixel == sisbios_mode[search_idx].bpp) ) {
1483                         if((tidx = sisfb_validate_mode(ivideo,search_idx,
1484                                                 ivideo->currentvbflags)) > 0) {
1485                                 found_mode = 1;
1486                                 search_idx = tidx;
1487                                 break;
1488                         }
1489                    }
1490                    search_idx++;
1491                 }
1492                 if(found_mode) {
1493                         printk(KERN_DEBUG
1494                                 "sisfb: Adapted from %dx%dx%d to %dx%dx%d\n",
1495                                 var->xres, var->yres, var->bits_per_pixel,
1496                                 sisbios_mode[search_idx].xres,
1497                                 sisbios_mode[search_idx].yres,
1498                                 var->bits_per_pixel);
1499                         var->xres = sisbios_mode[search_idx].xres;
1500                         var->yres = sisbios_mode[search_idx].yres;
1501                 } else {
1502                         printk(KERN_ERR
1503                                 "sisfb: Failed to find supported mode near %dx%dx%d\n",
1504                                 var->xres, var->yres, var->bits_per_pixel);
1505                         return -EINVAL;
1506                 }
1507         }
1508
1509         if( ((ivideo->vbflags2 & VB2_LVDS) ||
1510              ((ivideo->vbflags2 & VB2_30xBDH) && (ivideo->currentvbflags & CRT2_LCD))) &&
1511             (var->bits_per_pixel == 8) ) {
1512                 /* Slave modes on LVDS and 301B-DH */
1513                 refresh_rate = 60;
1514                 recalc_clock = true;
1515         } else if( (ivideo->current_htotal == htotal) &&
1516                    (ivideo->current_vtotal == vtotal) &&
1517                    (ivideo->current_pixclock == pixclock) ) {
1518                 /* x=x & y=y & c=c -> assume depth change */
1519                 drate = 1000000000 / pixclock;
1520                 hrate = (drate * 1000) / htotal;
1521                 refresh_rate = (unsigned int) (hrate * 2 / vtotal);
1522         } else if( ( (ivideo->current_htotal != htotal) ||
1523                      (ivideo->current_vtotal != vtotal) ) &&
1524                    (ivideo->current_pixclock == var->pixclock) ) {
1525                 /* x!=x | y!=y & c=c -> invalid pixclock */
1526                 if(ivideo->sisfb_lastrates[sisbios_mode[search_idx].mode_no[ivideo->mni]]) {
1527                         refresh_rate =
1528                                 ivideo->sisfb_lastrates[sisbios_mode[search_idx].mode_no[ivideo->mni]];
1529                 } else if(ivideo->sisfb_parm_rate != -1) {
1530                         /* Sic, sisfb_parm_rate - want to know originally desired rate here */
1531                         refresh_rate = ivideo->sisfb_parm_rate;
1532                 } else {
1533                         refresh_rate = 60;
1534                 }
1535                 recalc_clock = true;
1536         } else if((pixclock) && (htotal) && (vtotal)) {
1537                 drate = 1000000000 / pixclock;
1538                 hrate = (drate * 1000) / htotal;
1539                 refresh_rate = (unsigned int) (hrate * 2 / vtotal);
1540         } else if(ivideo->current_refresh_rate) {
1541                 refresh_rate = ivideo->current_refresh_rate;
1542                 recalc_clock = true;
1543         } else {
1544                 refresh_rate = 60;
1545                 recalc_clock = true;
1546         }
1547
1548         myrateindex = sisfb_search_refresh_rate(ivideo, refresh_rate, search_idx);
1549
1550         /* Eventually recalculate timing and clock */
1551         if(recalc_clock) {
1552                 if(!myrateindex) myrateindex = sisbios_mode[search_idx].rate_idx;
1553                 var->pixclock = (u32) (1000000000 / sisfb_mode_rate_to_dclock(&ivideo->SiS_Pr,
1554                                                 sisbios_mode[search_idx].mode_no[ivideo->mni],
1555                                                 myrateindex));
1556                 sisfb_mode_rate_to_ddata(&ivideo->SiS_Pr,
1557                                         sisbios_mode[search_idx].mode_no[ivideo->mni],
1558                                         myrateindex, var);
1559                 if((var->vmode & FB_VMODE_MASK) == FB_VMODE_DOUBLE) {
1560                         var->pixclock <<= 1;
1561                 }
1562         }
1563
1564         if(ivideo->sisfb_thismonitor.datavalid) {
1565                 if(!sisfb_verify_rate(ivideo, &ivideo->sisfb_thismonitor, search_idx,
1566                                 myrateindex, refresh_rate)) {
1567                         printk(KERN_INFO
1568                                 "sisfb: WARNING: Refresh rate exceeds monitor specs!\n");
1569                 }
1570         }
1571
1572         /* Adapt RGB settings */
1573         sisfb_bpp_to_var(ivideo, var);
1574
1575         if(var->xres > var->xres_virtual)
1576                 var->xres_virtual = var->xres;
1577
1578         if(ivideo->sisfb_ypan) {
1579                 maxyres = sisfb_calc_maxyres(ivideo, var);
1580                 if(ivideo->sisfb_max) {
1581                         var->yres_virtual = maxyres;
1582                 } else {
1583                         if(var->yres_virtual > maxyres) {
1584                                 var->yres_virtual = maxyres;
1585                         }
1586                 }
1587                 if(var->yres_virtual <= var->yres) {
1588                         var->yres_virtual = var->yres;
1589                 }
1590         } else {
1591                 if(var->yres != var->yres_virtual) {
1592                         var->yres_virtual = var->yres;
1593                 }
1594                 var->xoffset = 0;
1595                 var->yoffset = 0;
1596         }
1597
1598         /* Truncate offsets to maximum if too high */
1599         if(var->xoffset > var->xres_virtual - var->xres) {
1600                 var->xoffset = var->xres_virtual - var->xres - 1;
1601         }
1602
1603         if(var->yoffset > var->yres_virtual - var->yres) {
1604                 var->yoffset = var->yres_virtual - var->yres - 1;
1605         }
1606
1607         /* Set everything else to 0 */
1608         var->red.msb_right =
1609                 var->green.msb_right =
1610                 var->blue.msb_right =
1611                 var->transp.offset =
1612                 var->transp.length =
1613                 var->transp.msb_right = 0;
1614
1615         return 0;
1616 }
1617
1618 static int
1619 sisfb_pan_display(struct fb_var_screeninfo *var, struct fb_info* info)
1620 {
1621         struct sis_video_info *ivideo = (struct sis_video_info *)info->par;
1622         int err;
1623
1624         if (var->vmode & FB_VMODE_YWRAP)
1625                 return -EINVAL;
1626
1627         if (var->xoffset + info->var.xres > info->var.xres_virtual ||
1628             var->yoffset + info->var.yres > info->var.yres_virtual)
1629                 return -EINVAL;
1630
1631         err = sisfb_pan_var(ivideo, info, var);
1632         if (err < 0)
1633                 return err;
1634
1635         info->var.xoffset = var->xoffset;
1636         info->var.yoffset = var->yoffset;
1637
1638         return 0;
1639 }
1640
1641 static int
1642 sisfb_blank(int blank, struct fb_info *info)
1643 {
1644         struct sis_video_info *ivideo = (struct sis_video_info *)info->par;
1645
1646         return sisfb_myblank(ivideo, blank);
1647 }
1648
1649 /* ----------- FBDev related routines for all series ---------- */
1650
1651 static int      sisfb_ioctl(struct fb_info *info, unsigned int cmd,
1652                             unsigned long arg)
1653 {
1654         struct sis_video_info   *ivideo = (struct sis_video_info *)info->par;
1655         struct sis_memreq       sismemreq;
1656         struct fb_vblank        sisvbblank;
1657         u32                     gpu32 = 0;
1658 #ifndef __user
1659 #define __user
1660 #endif
1661         u32 __user              *argp = (u32 __user *)arg;
1662
1663         switch(cmd) {
1664            case FBIO_ALLOC:
1665                 if(!capable(CAP_SYS_RAWIO))
1666                         return -EPERM;
1667
1668                 if(copy_from_user(&sismemreq, (void __user *)arg, sizeof(sismemreq)))
1669                         return -EFAULT;
1670
1671                 sis_malloc(&sismemreq);
1672
1673                 if(copy_to_user((void __user *)arg, &sismemreq, sizeof(sismemreq))) {
1674                         sis_free((u32)sismemreq.offset);
1675                         return -EFAULT;
1676                 }
1677                 break;
1678
1679            case FBIO_FREE:
1680                 if(!capable(CAP_SYS_RAWIO))
1681                         return -EPERM;
1682
1683                 if(get_user(gpu32, argp))
1684                         return -EFAULT;
1685
1686                 sis_free(gpu32);
1687                 break;
1688
1689            case FBIOGET_VBLANK:
1690
1691                 memset(&sisvbblank, 0, sizeof(struct fb_vblank));
1692
1693                 sisvbblank.count = 0;
1694                 sisvbblank.flags = sisfb_setupvbblankflags(ivideo, &sisvbblank.vcount, &sisvbblank.hcount);
1695
1696                 if(copy_to_user((void __user *)arg, &sisvbblank, sizeof(sisvbblank)))
1697                         return -EFAULT;
1698
1699                 break;
1700
1701            case SISFB_GET_INFO_SIZE:
1702                 return put_user(sizeof(struct sisfb_info), argp);
1703
1704            case SISFB_GET_INFO_OLD:
1705                 if(ivideo->warncount++ < 10)
1706                         printk(KERN_INFO
1707                                 "sisfb: Deprecated ioctl call received - update your application!\n");
1708            case SISFB_GET_INFO:  /* For communication with X driver */
1709                 ivideo->sisfb_infoblock.sisfb_id         = SISFB_ID;
1710                 ivideo->sisfb_infoblock.sisfb_version    = VER_MAJOR;
1711                 ivideo->sisfb_infoblock.sisfb_revision   = VER_MINOR;
1712                 ivideo->sisfb_infoblock.sisfb_patchlevel = VER_LEVEL;
1713                 ivideo->sisfb_infoblock.chip_id = ivideo->chip_id;
1714                 ivideo->sisfb_infoblock.sisfb_pci_vendor = ivideo->chip_vendor;
1715                 ivideo->sisfb_infoblock.memory = ivideo->video_size / 1024;
1716                 ivideo->sisfb_infoblock.heapstart = ivideo->heapstart / 1024;
1717                 if(ivideo->modechanged) {
1718                         ivideo->sisfb_infoblock.fbvidmode = ivideo->mode_no;
1719                 } else {
1720                         ivideo->sisfb_infoblock.fbvidmode = ivideo->modeprechange;
1721                 }
1722                 ivideo->sisfb_infoblock.sisfb_caps = ivideo->caps;
1723                 ivideo->sisfb_infoblock.sisfb_tqlen = ivideo->cmdQueueSize / 1024;
1724                 ivideo->sisfb_infoblock.sisfb_pcibus = ivideo->pcibus;
1725                 ivideo->sisfb_infoblock.sisfb_pcislot = ivideo->pcislot;
1726                 ivideo->sisfb_infoblock.sisfb_pcifunc = ivideo->pcifunc;
1727                 ivideo->sisfb_infoblock.sisfb_lcdpdc = ivideo->detectedpdc;
1728                 ivideo->sisfb_infoblock.sisfb_lcdpdca = ivideo->detectedpdca;
1729                 ivideo->sisfb_infoblock.sisfb_lcda = ivideo->detectedlcda;
1730                 ivideo->sisfb_infoblock.sisfb_vbflags = ivideo->vbflags;
1731                 ivideo->sisfb_infoblock.sisfb_currentvbflags = ivideo->currentvbflags;
1732                 ivideo->sisfb_infoblock.sisfb_scalelcd = ivideo->SiS_Pr.UsePanelScaler;
1733                 ivideo->sisfb_infoblock.sisfb_specialtiming = ivideo->SiS_Pr.SiS_CustomT;
1734                 ivideo->sisfb_infoblock.sisfb_haveemi = ivideo->SiS_Pr.HaveEMI ? 1 : 0;
1735                 ivideo->sisfb_infoblock.sisfb_haveemilcd = ivideo->SiS_Pr.HaveEMILCD ? 1 : 0;
1736                 ivideo->sisfb_infoblock.sisfb_emi30 = ivideo->SiS_Pr.EMI_30;
1737                 ivideo->sisfb_infoblock.sisfb_emi31 = ivideo->SiS_Pr.EMI_31;
1738                 ivideo->sisfb_infoblock.sisfb_emi32 = ivideo->SiS_Pr.EMI_32;
1739                 ivideo->sisfb_infoblock.sisfb_emi33 = ivideo->SiS_Pr.EMI_33;
1740                 ivideo->sisfb_infoblock.sisfb_tvxpos = (u16)(ivideo->tvxpos + 32);
1741                 ivideo->sisfb_infoblock.sisfb_tvypos = (u16)(ivideo->tvypos + 32);
1742                 ivideo->sisfb_infoblock.sisfb_heapsize = ivideo->sisfb_heap_size / 1024;
1743                 ivideo->sisfb_infoblock.sisfb_videooffset = ivideo->video_offset;
1744                 ivideo->sisfb_infoblock.sisfb_curfstn = ivideo->curFSTN;
1745                 ivideo->sisfb_infoblock.sisfb_curdstn = ivideo->curDSTN;
1746                 ivideo->sisfb_infoblock.sisfb_vbflags2 = ivideo->vbflags2;
1747                 ivideo->sisfb_infoblock.sisfb_can_post = ivideo->sisfb_can_post ? 1 : 0;
1748                 ivideo->sisfb_infoblock.sisfb_card_posted = ivideo->sisfb_card_posted ? 1 : 0;
1749                 ivideo->sisfb_infoblock.sisfb_was_boot_device = ivideo->sisfb_was_boot_device ? 1 : 0;
1750
1751                 if(copy_to_user((void __user *)arg, &ivideo->sisfb_infoblock,
1752                                                 sizeof(ivideo->sisfb_infoblock)))
1753                         return -EFAULT;
1754
1755                 break;
1756
1757            case SISFB_GET_VBRSTATUS_OLD:
1758                 if(ivideo->warncount++ < 10)
1759                         printk(KERN_INFO
1760                                 "sisfb: Deprecated ioctl call received - update your application!\n");
1761            case SISFB_GET_VBRSTATUS:
1762                 if(sisfb_CheckVBRetrace(ivideo))
1763                         return put_user((u32)1, argp);
1764                 else
1765                         return put_user((u32)0, argp);
1766
1767            case SISFB_GET_AUTOMAXIMIZE_OLD:
1768                 if(ivideo->warncount++ < 10)
1769                         printk(KERN_INFO
1770                                 "sisfb: Deprecated ioctl call received - update your application!\n");
1771            case SISFB_GET_AUTOMAXIMIZE:
1772                 if(ivideo->sisfb_max)
1773                         return put_user((u32)1, argp);
1774                 else
1775                         return put_user((u32)0, argp);
1776
1777            case SISFB_SET_AUTOMAXIMIZE_OLD:
1778                 if(ivideo->warncount++ < 10)
1779                         printk(KERN_INFO
1780                                 "sisfb: Deprecated ioctl call received - update your application!\n");
1781            case SISFB_SET_AUTOMAXIMIZE:
1782                 if(get_user(gpu32, argp))
1783                         return -EFAULT;
1784
1785                 ivideo->sisfb_max = (gpu32) ? 1 : 0;
1786                 break;
1787
1788            case SISFB_SET_TVPOSOFFSET:
1789                 if(get_user(gpu32, argp))
1790                         return -EFAULT;
1791
1792                 sisfb_set_TVxposoffset(ivideo, ((int)(gpu32 >> 16)) - 32);
1793                 sisfb_set_TVyposoffset(ivideo, ((int)(gpu32 & 0xffff)) - 32);
1794                 break;
1795
1796            case SISFB_GET_TVPOSOFFSET:
1797                 return put_user((u32)(((ivideo->tvxpos+32)<<16)|((ivideo->tvypos+32)&0xffff)),
1798                                                         argp);
1799
1800            case SISFB_COMMAND:
1801                 if(copy_from_user(&ivideo->sisfb_command, (void __user *)arg,
1802                                                         sizeof(struct sisfb_cmd)))
1803                         return -EFAULT;
1804
1805                 sisfb_handle_command(ivideo, &ivideo->sisfb_command);
1806
1807                 if(copy_to_user((void __user *)arg, &ivideo->sisfb_command,
1808                                                         sizeof(struct sisfb_cmd)))
1809                         return -EFAULT;
1810
1811                 break;
1812
1813            case SISFB_SET_LOCK:
1814                 if(get_user(gpu32, argp))
1815                         return -EFAULT;
1816
1817                 ivideo->sisfblocked = (gpu32) ? 1 : 0;
1818                 break;
1819
1820            default:
1821 #ifdef SIS_NEW_CONFIG_COMPAT
1822                 return -ENOIOCTLCMD;
1823 #else
1824                 return -EINVAL;
1825 #endif
1826         }
1827         return 0;
1828 }
1829
1830 static int
1831 sisfb_get_fix(struct fb_fix_screeninfo *fix, int con, struct fb_info *info)
1832 {
1833         struct sis_video_info *ivideo = (struct sis_video_info *)info->par;
1834
1835         memset(fix, 0, sizeof(struct fb_fix_screeninfo));
1836
1837         strlcpy(fix->id, ivideo->myid, sizeof(fix->id));
1838
1839         mutex_lock(&info->mm_lock);
1840         fix->smem_start  = ivideo->video_base + ivideo->video_offset;
1841         fix->smem_len    = ivideo->sisfb_mem;
1842         mutex_unlock(&info->mm_lock);
1843         fix->type        = FB_TYPE_PACKED_PIXELS;
1844         fix->type_aux    = 0;
1845         fix->visual      = (ivideo->video_bpp == 8) ? FB_VISUAL_PSEUDOCOLOR : FB_VISUAL_TRUECOLOR;
1846         fix->xpanstep    = 1;
1847         fix->ypanstep    = (ivideo->sisfb_ypan) ? 1 : 0;
1848         fix->ywrapstep   = 0;
1849         fix->line_length = ivideo->video_linelength;
1850         fix->mmio_start  = ivideo->mmio_base;
1851         fix->mmio_len    = ivideo->mmio_size;
1852         if(ivideo->sisvga_engine == SIS_300_VGA) {
1853                 fix->accel = FB_ACCEL_SIS_GLAMOUR;
1854         } else if((ivideo->chip == SIS_330) ||
1855                   (ivideo->chip == SIS_760) ||
1856                   (ivideo->chip == SIS_761)) {
1857                 fix->accel = FB_ACCEL_SIS_XABRE;
1858         } else if(ivideo->chip == XGI_20) {
1859                 fix->accel = FB_ACCEL_XGI_VOLARI_Z;
1860         } else if(ivideo->chip >= XGI_40) {
1861                 fix->accel = FB_ACCEL_XGI_VOLARI_V;
1862         } else {
1863                 fix->accel = FB_ACCEL_SIS_GLAMOUR_2;
1864         }
1865
1866         return 0;
1867 }
1868
1869 /* ----------------  fb_ops structures ----------------- */
1870
1871 static struct fb_ops sisfb_ops = {
1872         .owner          = THIS_MODULE,
1873         .fb_open        = sisfb_open,
1874         .fb_release     = sisfb_release,
1875         .fb_check_var   = sisfb_check_var,
1876         .fb_set_par     = sisfb_set_par,
1877         .fb_setcolreg   = sisfb_setcolreg,
1878         .fb_pan_display = sisfb_pan_display,
1879         .fb_blank       = sisfb_blank,
1880         .fb_fillrect    = fbcon_sis_fillrect,
1881         .fb_copyarea    = fbcon_sis_copyarea,
1882         .fb_imageblit   = cfb_imageblit,
1883         .fb_sync        = fbcon_sis_sync,
1884 #ifdef SIS_NEW_CONFIG_COMPAT
1885         .fb_compat_ioctl= sisfb_ioctl,
1886 #endif
1887         .fb_ioctl       = sisfb_ioctl
1888 };
1889
1890 /* ---------------- Chip generation dependent routines ---------------- */
1891
1892 static struct pci_dev *sisfb_get_northbridge(int basechipid)
1893 {
1894         struct pci_dev *pdev = NULL;
1895         int nbridgenum, nbridgeidx, i;
1896         static const unsigned short nbridgeids[] = {
1897                 PCI_DEVICE_ID_SI_540,   /* for SiS 540 VGA */
1898                 PCI_DEVICE_ID_SI_630,   /* for SiS 630/730 VGA */
1899                 PCI_DEVICE_ID_SI_730,
1900                 PCI_DEVICE_ID_SI_550,   /* for SiS 550 VGA */
1901                 PCI_DEVICE_ID_SI_650,   /* for SiS 650/651/740 VGA */
1902                 PCI_DEVICE_ID_SI_651,
1903                 PCI_DEVICE_ID_SI_740,
1904                 PCI_DEVICE_ID_SI_661,   /* for SiS 661/741/660/760/761 VGA */
1905                 PCI_DEVICE_ID_SI_741,
1906                 PCI_DEVICE_ID_SI_660,
1907                 PCI_DEVICE_ID_SI_760,
1908                 PCI_DEVICE_ID_SI_761
1909         };
1910
1911         switch(basechipid) {
1912 #ifdef CONFIG_FB_SIS_300
1913         case SIS_540:   nbridgeidx = 0; nbridgenum = 1; break;
1914         case SIS_630:   nbridgeidx = 1; nbridgenum = 2; break;
1915 #endif
1916 #ifdef CONFIG_FB_SIS_315
1917         case SIS_550:   nbridgeidx = 3; nbridgenum = 1; break;
1918         case SIS_650:   nbridgeidx = 4; nbridgenum = 3; break;
1919         case SIS_660:   nbridgeidx = 7; nbridgenum = 5; break;
1920 #endif
1921         default:        return NULL;
1922         }
1923         for(i = 0; i < nbridgenum; i++) {
1924                 if((pdev = pci_get_device(PCI_VENDOR_ID_SI,
1925                                 nbridgeids[nbridgeidx+i], NULL)))
1926                         break;
1927         }
1928         return pdev;
1929 }
1930
1931 static int sisfb_get_dram_size(struct sis_video_info *ivideo)
1932 {
1933 #if defined(CONFIG_FB_SIS_300) || defined(CONFIG_FB_SIS_315)
1934         u8 reg;
1935 #endif
1936
1937         ivideo->video_size = 0;
1938         ivideo->UMAsize = ivideo->LFBsize = 0;
1939
1940         switch(ivideo->chip) {
1941 #ifdef CONFIG_FB_SIS_300
1942         case SIS_300:
1943                 reg = SiS_GetReg(SISSR, 0x14);
1944                 ivideo->video_size = ((reg & 0x3F) + 1) << 20;
1945                 break;
1946         case SIS_540:
1947         case SIS_630:
1948         case SIS_730:
1949                 if(!ivideo->nbridge)
1950                         return -1;
1951                 pci_read_config_byte(ivideo->nbridge, 0x63, &reg);
1952                 ivideo->video_size = 1 << (((reg & 0x70) >> 4) + 21);
1953                 break;
1954 #endif
1955 #ifdef CONFIG_FB_SIS_315
1956         case SIS_315H:
1957         case SIS_315PRO:
1958         case SIS_315:
1959                 reg = SiS_GetReg(SISSR, 0x14);
1960                 ivideo->video_size = (1 << ((reg & 0xf0) >> 4)) << 20;
1961                 switch((reg >> 2) & 0x03) {
1962                 case 0x01:
1963                 case 0x03:
1964                         ivideo->video_size <<= 1;
1965                         break;
1966                 case 0x02:
1967                         ivideo->video_size += (ivideo->video_size/2);
1968                 }
1969                 break;
1970         case SIS_330:
1971                 reg = SiS_GetReg(SISSR, 0x14);
1972                 ivideo->video_size = (1 << ((reg & 0xf0) >> 4)) << 20;
1973                 if(reg & 0x0c) ivideo->video_size <<= 1;
1974                 break;
1975         case SIS_550:
1976         case SIS_650:
1977         case SIS_740:
1978                 reg = SiS_GetReg(SISSR, 0x14);
1979                 ivideo->video_size = (((reg & 0x3f) + 1) << 2) << 20;
1980                 break;
1981         case SIS_661:
1982         case SIS_741:
1983                 reg = SiS_GetReg(SISCR, 0x79);
1984                 ivideo->video_size = (1 << ((reg & 0xf0) >> 4)) << 20;
1985                 break;
1986         case SIS_660:
1987         case SIS_760:
1988         case SIS_761:
1989                 reg = SiS_GetReg(SISCR, 0x79);
1990                 reg = (reg & 0xf0) >> 4;
1991                 if(reg) {
1992                         ivideo->video_size = (1 << reg) << 20;
1993                         ivideo->UMAsize = ivideo->video_size;
1994                 }
1995                 reg = SiS_GetReg(SISCR, 0x78);
1996                 reg &= 0x30;
1997                 if(reg) {
1998                         if(reg == 0x10) {
1999                                 ivideo->LFBsize = (32 << 20);
2000                         } else {
2001                                 ivideo->LFBsize = (64 << 20);
2002                         }
2003                         ivideo->video_size += ivideo->LFBsize;
2004                 }
2005                 break;
2006         case SIS_340:
2007         case XGI_20:
2008         case XGI_40:
2009                 reg = SiS_GetReg(SISSR, 0x14);
2010                 ivideo->video_size = (1 << ((reg & 0xf0) >> 4)) << 20;
2011                 if(ivideo->chip != XGI_20) {
2012                         reg = (reg & 0x0c) >> 2;
2013                         if(ivideo->revision_id == 2) {
2014                                 if(reg & 0x01) reg = 0x02;
2015                                 else           reg = 0x00;
2016                         }
2017                         if(reg == 0x02)         ivideo->video_size <<= 1;
2018                         else if(reg == 0x03)    ivideo->video_size <<= 2;
2019                 }
2020                 break;
2021 #endif
2022         default:
2023                 return -1;
2024         }
2025         return 0;
2026 }
2027
2028 /* -------------- video bridge device detection --------------- */
2029
2030 static void sisfb_detect_VB_connect(struct sis_video_info *ivideo)
2031 {
2032         u8 cr32, temp;
2033
2034         /* No CRT2 on XGI Z7 */
2035         if(ivideo->chip == XGI_20) {
2036                 ivideo->sisfb_crt1off = 0;
2037                 return;
2038         }
2039
2040 #ifdef CONFIG_FB_SIS_300
2041         if(ivideo->sisvga_engine == SIS_300_VGA) {
2042                 temp = SiS_GetReg(SISSR, 0x17);
2043                 if((temp & 0x0F) && (ivideo->chip != SIS_300)) {
2044                         /* PAL/NTSC is stored on SR16 on such machines */
2045                         if(!(ivideo->vbflags & (TV_PAL | TV_NTSC | TV_PALM | TV_PALN))) {
2046                                 temp = SiS_GetReg(SISSR, 0x16);
2047                                 if(temp & 0x20)
2048                                         ivideo->vbflags |= TV_PAL;
2049                                 else
2050                                         ivideo->vbflags |= TV_NTSC;
2051                         }
2052                 }
2053         }
2054 #endif
2055
2056         cr32 = SiS_GetReg(SISCR, 0x32);
2057
2058         if(cr32 & SIS_CRT1) {
2059                 ivideo->sisfb_crt1off = 0;
2060         } else {
2061                 ivideo->sisfb_crt1off = (cr32 & 0xDF) ? 1 : 0;
2062         }
2063
2064         ivideo->vbflags &= ~(CRT2_TV | CRT2_LCD | CRT2_VGA);
2065
2066         if(cr32 & SIS_VB_TV)   ivideo->vbflags |= CRT2_TV;
2067         if(cr32 & SIS_VB_LCD)  ivideo->vbflags |= CRT2_LCD;
2068         if(cr32 & SIS_VB_CRT2) ivideo->vbflags |= CRT2_VGA;
2069
2070         /* Check given parms for hardware compatibility.
2071          * (Cannot do this in the search_xx routines since we don't
2072          * know what hardware we are running on then)
2073          */
2074
2075         if(ivideo->chip != SIS_550) {
2076            ivideo->sisfb_dstn = ivideo->sisfb_fstn = 0;
2077         }
2078
2079         if(ivideo->sisfb_tvplug != -1) {
2080            if( (ivideo->sisvga_engine != SIS_315_VGA) ||
2081                (!(ivideo->vbflags2 & VB2_SISYPBPRBRIDGE)) ) {
2082               if(ivideo->sisfb_tvplug & TV_YPBPR) {
2083                  ivideo->sisfb_tvplug = -1;
2084                  printk(KERN_ERR "sisfb: YPbPr not supported\n");
2085               }
2086            }
2087         }
2088         if(ivideo->sisfb_tvplug != -1) {
2089            if( (ivideo->sisvga_engine != SIS_315_VGA) ||
2090                (!(ivideo->vbflags2 & VB2_SISHIVISIONBRIDGE)) ) {
2091               if(ivideo->sisfb_tvplug & TV_HIVISION) {
2092                  ivideo->sisfb_tvplug = -1;
2093                  printk(KERN_ERR "sisfb: HiVision not supported\n");
2094               }
2095            }
2096         }
2097         if(ivideo->sisfb_tvstd != -1) {
2098            if( (!(ivideo->vbflags2 & VB2_SISBRIDGE)) &&
2099                (!((ivideo->sisvga_engine == SIS_315_VGA) &&
2100                         (ivideo->vbflags2 & VB2_CHRONTEL))) ) {
2101               if(ivideo->sisfb_tvstd & (TV_PALM | TV_PALN | TV_NTSCJ)) {
2102                  ivideo->sisfb_tvstd = -1;
2103                  printk(KERN_ERR "sisfb: PALM/PALN/NTSCJ not supported\n");
2104               }
2105            }
2106         }
2107
2108         /* Detect/set TV plug & type */
2109         if(ivideo->sisfb_tvplug != -1) {
2110                 ivideo->vbflags |= ivideo->sisfb_tvplug;
2111         } else {
2112                 if(cr32 & SIS_VB_YPBPR)          ivideo->vbflags |= (TV_YPBPR|TV_YPBPR525I); /* default: 480i */
2113                 else if(cr32 & SIS_VB_HIVISION)  ivideo->vbflags |= TV_HIVISION;
2114                 else if(cr32 & SIS_VB_SCART)     ivideo->vbflags |= TV_SCART;
2115                 else {
2116                         if(cr32 & SIS_VB_SVIDEO)    ivideo->vbflags |= TV_SVIDEO;
2117                         if(cr32 & SIS_VB_COMPOSITE) ivideo->vbflags |= TV_AVIDEO;
2118                 }
2119         }
2120
2121         if(!(ivideo->vbflags & (TV_YPBPR | TV_HIVISION))) {
2122             if(ivideo->sisfb_tvstd != -1) {
2123                ivideo->vbflags &= ~(TV_NTSC | TV_PAL | TV_PALM | TV_PALN | TV_NTSCJ);
2124                ivideo->vbflags |= ivideo->sisfb_tvstd;
2125             }
2126             if(ivideo->vbflags & TV_SCART) {
2127                ivideo->vbflags &= ~(TV_NTSC | TV_PALM | TV_PALN | TV_NTSCJ);
2128                ivideo->vbflags |= TV_PAL;
2129             }
2130             if(!(ivideo->vbflags & (TV_PAL | TV_NTSC | TV_PALM | TV_PALN | TV_NTSCJ))) {
2131                 if(ivideo->sisvga_engine == SIS_300_VGA) {
2132                         temp = SiS_GetReg(SISSR, 0x38);
2133                         if(temp & 0x01) ivideo->vbflags |= TV_PAL;
2134                         else            ivideo->vbflags |= TV_NTSC;
2135                 } else if((ivideo->chip <= SIS_315PRO) || (ivideo->chip >= SIS_330)) {
2136                         temp = SiS_GetReg(SISSR, 0x38);
2137                         if(temp & 0x01) ivideo->vbflags |= TV_PAL;
2138                         else            ivideo->vbflags |= TV_NTSC;
2139                 } else {
2140                         temp = SiS_GetReg(SISCR, 0x79);
2141                         if(temp & 0x20) ivideo->vbflags |= TV_PAL;
2142                         else            ivideo->vbflags |= TV_NTSC;
2143                 }
2144             }
2145         }
2146
2147         /* Copy forceCRT1 option to CRT1off if option is given */
2148         if(ivideo->sisfb_forcecrt1 != -1) {
2149            ivideo->sisfb_crt1off = (ivideo->sisfb_forcecrt1) ? 0 : 1;
2150         }
2151 }
2152
2153 /* ------------------ Sensing routines ------------------ */
2154
2155 static bool sisfb_test_DDC1(struct sis_video_info *ivideo)
2156 {
2157     unsigned short old;
2158     int count = 48;
2159
2160     old = SiS_ReadDDC1Bit(&ivideo->SiS_Pr);
2161     do {
2162         if(old != SiS_ReadDDC1Bit(&ivideo->SiS_Pr)) break;
2163     } while(count--);
2164     return (count != -1);
2165 }
2166
2167 static void sisfb_sense_crt1(struct sis_video_info *ivideo)
2168 {
2169     bool mustwait = false;
2170     u8  sr1F, cr17;
2171 #ifdef CONFIG_FB_SIS_315
2172     u8  cr63=0;
2173 #endif
2174     u16 temp = 0xffff;
2175     int i;
2176
2177     sr1F = SiS_GetReg(SISSR, 0x1F);
2178     SiS_SetRegOR(SISSR, 0x1F, 0x04);
2179     SiS_SetRegAND(SISSR, 0x1F, 0x3F);
2180     if(sr1F & 0xc0) mustwait = true;
2181
2182 #ifdef CONFIG_FB_SIS_315
2183     if(ivideo->sisvga_engine == SIS_315_VGA) {
2184        cr63 = SiS_GetReg(SISCR, ivideo->SiS_Pr.SiS_MyCR63);
2185        cr63 &= 0x40;
2186        SiS_SetRegAND(SISCR, ivideo->SiS_Pr.SiS_MyCR63, 0xBF);
2187     }
2188 #endif
2189
2190     cr17 = SiS_GetReg(SISCR, 0x17);
2191     cr17 &= 0x80;
2192     if(!cr17) {
2193        SiS_SetRegOR(SISCR, 0x17, 0x80);
2194        mustwait = true;
2195        SiS_SetReg(SISSR, 0x00, 0x01);
2196        SiS_SetReg(SISSR, 0x00, 0x03);
2197     }
2198
2199     if(mustwait) {
2200        for(i=0; i < 10; i++) sisfbwaitretracecrt1(ivideo);
2201     }
2202
2203 #ifdef CONFIG_FB_SIS_315
2204     if(ivideo->chip >= SIS_330) {
2205        SiS_SetRegAND(SISCR, 0x32, ~0x20);
2206        if(ivideo->chip >= SIS_340) {
2207            SiS_SetReg(SISCR, 0x57, 0x4a);
2208        } else {
2209            SiS_SetReg(SISCR, 0x57, 0x5f);
2210        }
2211         SiS_SetRegOR(SISCR, 0x53, 0x02);
2212         while ((SiS_GetRegByte(SISINPSTAT)) & 0x01)    break;
2213         while (!((SiS_GetRegByte(SISINPSTAT)) & 0x01)) break;
2214         if ((SiS_GetRegByte(SISMISCW)) & 0x10) temp = 1;
2215         SiS_SetRegAND(SISCR, 0x53, 0xfd);
2216         SiS_SetRegAND(SISCR, 0x57, 0x00);
2217     }
2218 #endif
2219
2220     if(temp == 0xffff) {
2221        i = 3;
2222        do {
2223           temp = SiS_HandleDDC(&ivideo->SiS_Pr, ivideo->vbflags,
2224                 ivideo->sisvga_engine, 0, 0, NULL, ivideo->vbflags2);
2225        } while(((temp == 0) || (temp == 0xffff)) && i--);
2226
2227        if((temp == 0) || (temp == 0xffff)) {
2228           if(sisfb_test_DDC1(ivideo)) temp = 1;
2229        }
2230     }
2231
2232     if((temp) && (temp != 0xffff)) {
2233        SiS_SetRegOR(SISCR, 0x32, 0x20);
2234     }
2235
2236 #ifdef CONFIG_FB_SIS_315
2237     if(ivideo->sisvga_engine == SIS_315_VGA) {
2238         SiS_SetRegANDOR(SISCR, ivideo->SiS_Pr.SiS_MyCR63, 0xBF, cr63);
2239     }
2240 #endif
2241
2242     SiS_SetRegANDOR(SISCR, 0x17, 0x7F, cr17);
2243
2244     SiS_SetReg(SISSR, 0x1F, sr1F);
2245 }
2246
2247 /* Determine and detect attached devices on SiS30x */
2248 static void SiS_SenseLCD(struct sis_video_info *ivideo)
2249 {
2250         unsigned char buffer[256];
2251         unsigned short temp, realcrtno, i;
2252         u8 reg, cr37 = 0, paneltype = 0;
2253         u16 xres, yres;
2254
2255         ivideo->SiS_Pr.PanelSelfDetected = false;
2256
2257         /* LCD detection only for TMDS bridges */
2258         if(!(ivideo->vbflags2 & VB2_SISTMDSBRIDGE))
2259                 return;
2260         if(ivideo->vbflags2 & VB2_30xBDH)
2261                 return;
2262
2263         /* If LCD already set up by BIOS, skip it */
2264         reg = SiS_GetReg(SISCR, 0x32);
2265         if(reg & 0x08)
2266                 return;
2267
2268         realcrtno = 1;
2269         if(ivideo->SiS_Pr.DDCPortMixup)
2270                 realcrtno = 0;
2271
2272         /* Check DDC capabilities */
2273         temp = SiS_HandleDDC(&ivideo->SiS_Pr, ivideo->vbflags, ivideo->sisvga_engine,
2274                                 realcrtno, 0, &buffer[0], ivideo->vbflags2);
2275
2276         if((!temp) || (temp == 0xffff) || (!(temp & 0x02)))
2277                 return;
2278
2279         /* Read DDC data */
2280         i = 3;  /* Number of retrys */
2281         do {
2282                 temp = SiS_HandleDDC(&ivideo->SiS_Pr, ivideo->vbflags,
2283                                 ivideo->sisvga_engine, realcrtno, 1,
2284                                 &buffer[0], ivideo->vbflags2);
2285         } while((temp) && i--);
2286
2287         if(temp)
2288                 return;
2289
2290         /* No digital device */
2291         if(!(buffer[0x14] & 0x80))
2292                 return;
2293
2294         /* First detailed timing preferred timing? */
2295         if(!(buffer[0x18] & 0x02))
2296                 return;
2297
2298         xres = buffer[0x38] | ((buffer[0x3a] & 0xf0) << 4);
2299         yres = buffer[0x3b] | ((buffer[0x3d] & 0xf0) << 4);
2300
2301         switch(xres) {
2302                 case 1024:
2303                         if(yres == 768)
2304                                 paneltype = 0x02;
2305                         break;
2306                 case 1280:
2307                         if(yres == 1024)
2308                                 paneltype = 0x03;
2309                         break;
2310                 case 1600:
2311                         if((yres == 1200) && (ivideo->vbflags2 & VB2_30xC))
2312                                 paneltype = 0x0b;
2313                         break;
2314         }
2315
2316         if(!paneltype)
2317                 return;
2318
2319         if(buffer[0x23])
2320                 cr37 |= 0x10;
2321
2322         if((buffer[0x47] & 0x18) == 0x18)
2323                 cr37 |= ((((buffer[0x47] & 0x06) ^ 0x06) << 5) | 0x20);
2324         else
2325                 cr37 |= 0xc0;
2326
2327         SiS_SetReg(SISCR, 0x36, paneltype);
2328         cr37 &= 0xf1;
2329         SiS_SetRegANDOR(SISCR, 0x37, 0x0c, cr37);
2330         SiS_SetRegOR(SISCR, 0x32, 0x08);
2331
2332         ivideo->SiS_Pr.PanelSelfDetected = true;
2333 }
2334
2335 static int SISDoSense(struct sis_video_info *ivideo, u16 type, u16 test)
2336 {
2337     int temp, mytest, result, i, j;
2338
2339     for(j = 0; j < 10; j++) {
2340        result = 0;
2341        for(i = 0; i < 3; i++) {
2342           mytest = test;
2343            SiS_SetReg(SISPART4, 0x11, (type & 0x00ff));
2344           temp = (type >> 8) | (mytest & 0x00ff);
2345           SiS_SetRegANDOR(SISPART4, 0x10, 0xe0, temp);
2346           SiS_DDC2Delay(&ivideo->SiS_Pr, 0x1500);
2347           mytest >>= 8;
2348           mytest &= 0x7f;
2349            temp = SiS_GetReg(SISPART4, 0x03);
2350           temp ^= 0x0e;
2351           temp &= mytest;
2352           if(temp == mytest) result++;
2353 #if 1
2354           SiS_SetReg(SISPART4, 0x11, 0x00);
2355           SiS_SetRegAND(SISPART4, 0x10, 0xe0);
2356           SiS_DDC2Delay(&ivideo->SiS_Pr, 0x1000);
2357 #endif
2358        }
2359        if((result == 0) || (result >= 2)) break;
2360     }
2361     return result;
2362 }
2363
2364 static void SiS_Sense30x(struct sis_video_info *ivideo)
2365 {
2366     u8  backupP4_0d,backupP2_00,backupP2_4d,backupSR_1e,biosflag=0;
2367     u16 svhs=0, svhs_c=0;
2368     u16 cvbs=0, cvbs_c=0;
2369     u16 vga2=0, vga2_c=0;
2370     int myflag, result;
2371     char stdstr[] = "sisfb: Detected";
2372     char tvstr[]  = "TV connected to";
2373
2374     if(ivideo->vbflags2 & VB2_301) {
2375        svhs = 0x00b9; cvbs = 0x00b3; vga2 = 0x00d1;
2376        myflag = SiS_GetReg(SISPART4, 0x01);
2377        if(myflag & 0x04) {
2378           svhs = 0x00dd; cvbs = 0x00ee; vga2 = 0x00fd;
2379        }
2380     } else if(ivideo->vbflags2 & (VB2_301B | VB2_302B)) {
2381        svhs = 0x016b; cvbs = 0x0174; vga2 = 0x0190;
2382     } else if(ivideo->vbflags2 & (VB2_301LV | VB2_302LV)) {
2383        svhs = 0x0200; cvbs = 0x0100;
2384     } else if(ivideo->vbflags2 & (VB2_301C | VB2_302ELV | VB2_307T | VB2_307LV)) {
2385        svhs = 0x016b; cvbs = 0x0110; vga2 = 0x0190;
2386     } else
2387        return;
2388
2389     vga2_c = 0x0e08; svhs_c = 0x0404; cvbs_c = 0x0804;
2390     if(ivideo->vbflags & (VB2_301LV|VB2_302LV|VB2_302ELV|VB2_307LV)) {
2391        svhs_c = 0x0408; cvbs_c = 0x0808;
2392     }
2393
2394     biosflag = 2;
2395     if(ivideo->haveXGIROM) {
2396        biosflag = ivideo->bios_abase[0x58] & 0x03;
2397     } else if(ivideo->newrom) {
2398        if(ivideo->bios_abase[0x5d] & 0x04) biosflag |= 0x01;
2399     } else if(ivideo->sisvga_engine == SIS_300_VGA) {
2400        if(ivideo->bios_abase) {
2401           biosflag = ivideo->bios_abase[0xfe] & 0x03;
2402        }
2403     }
2404
2405     if(ivideo->chip == SIS_300) {
2406        myflag = SiS_GetReg(SISSR, 0x3b);
2407        if(!(myflag & 0x01)) vga2 = vga2_c = 0;
2408     }
2409
2410     if(!(ivideo->vbflags2 & VB2_SISVGA2BRIDGE)) {
2411        vga2 = vga2_c = 0;
2412     }
2413
2414     backupSR_1e = SiS_GetReg(SISSR, 0x1e);
2415     SiS_SetRegOR(SISSR, 0x1e, 0x20);
2416
2417     backupP4_0d = SiS_GetReg(SISPART4, 0x0d);
2418     if(ivideo->vbflags2 & VB2_30xC) {
2419         SiS_SetRegANDOR(SISPART4, 0x0d, ~0x07, 0x01);
2420     } else {
2421        SiS_SetRegOR(SISPART4, 0x0d, 0x04);
2422     }
2423     SiS_DDC2Delay(&ivideo->SiS_Pr, 0x2000);
2424
2425     backupP2_00 = SiS_GetReg(SISPART2, 0x00);
2426     SiS_SetReg(SISPART2, 0x00, ((backupP2_00 | 0x1c) & 0xfc));
2427
2428     backupP2_4d = SiS_GetReg(SISPART2, 0x4d);
2429     if(ivideo->vbflags2 & VB2_SISYPBPRBRIDGE) {
2430         SiS_SetReg(SISPART2, 0x4d, (backupP2_4d & ~0x10));
2431     }
2432
2433     if(!(ivideo->vbflags2 & VB2_30xCLV)) {
2434        SISDoSense(ivideo, 0, 0);
2435     }
2436
2437     SiS_SetRegAND(SISCR, 0x32, ~0x14);
2438
2439     if(vga2_c || vga2) {
2440        if(SISDoSense(ivideo, vga2, vga2_c)) {
2441           if(biosflag & 0x01) {
2442              printk(KERN_INFO "%s %s SCART output\n", stdstr, tvstr);
2443              SiS_SetRegOR(SISCR, 0x32, 0x04);
2444           } else {
2445              printk(KERN_INFO "%s secondary VGA connection\n", stdstr);
2446              SiS_SetRegOR(SISCR, 0x32, 0x10);
2447           }
2448        }
2449     }
2450
2451     SiS_SetRegAND(SISCR, 0x32, 0x3f);
2452
2453     if(ivideo->vbflags2 & VB2_30xCLV) {
2454        SiS_SetRegOR(SISPART4, 0x0d, 0x04);
2455     }
2456
2457     if((ivideo->sisvga_engine == SIS_315_VGA) && (ivideo->vbflags2 & VB2_SISYPBPRBRIDGE)) {
2458        SiS_SetReg(SISPART2, 0x4d, (backupP2_4d | 0x10));
2459        SiS_DDC2Delay(&ivideo->SiS_Pr, 0x2000);
2460        if((result = SISDoSense(ivideo, svhs, 0x0604))) {
2461           if((result = SISDoSense(ivideo, cvbs, 0x0804))) {
2462              printk(KERN_INFO "%s %s YPbPr component output\n", stdstr, tvstr);
2463              SiS_SetRegOR(SISCR, 0x32, 0x80);
2464           }
2465        }
2466        SiS_SetReg(SISPART2, 0x4d, backupP2_4d);
2467     }
2468
2469     SiS_SetRegAND(SISCR, 0x32, ~0x03);
2470
2471     if(!(ivideo->vbflags & TV_YPBPR)) {
2472        if((result = SISDoSense(ivideo, svhs, svhs_c))) {
2473           printk(KERN_INFO "%s %s SVIDEO output\n", stdstr, tvstr);
2474            SiS_SetRegOR(SISCR, 0x32, 0x02);
2475        }
2476        if((biosflag & 0x02) || (!result)) {
2477           if(SISDoSense(ivideo, cvbs, cvbs_c)) {
2478              printk(KERN_INFO "%s %s COMPOSITE output\n", stdstr, tvstr);
2479              SiS_SetRegOR(SISCR, 0x32, 0x01);
2480           }
2481        }
2482     }
2483
2484     SISDoSense(ivideo, 0, 0);
2485
2486     SiS_SetReg(SISPART2, 0x00, backupP2_00);
2487     SiS_SetReg(SISPART4, 0x0d, backupP4_0d);
2488     SiS_SetReg(SISSR, 0x1e, backupSR_1e);
2489
2490     if(ivideo->vbflags2 & VB2_30xCLV) {
2491         biosflag = SiS_GetReg(SISPART2, 0x00);
2492        if(biosflag & 0x20) {
2493           for(myflag = 2; myflag > 0; myflag--) {
2494              biosflag ^= 0x20;
2495              SiS_SetReg(SISPART2, 0x00, biosflag);
2496           }
2497        }
2498     }
2499
2500     SiS_SetReg(SISPART2, 0x00, backupP2_00);
2501 }
2502
2503 /* Determine and detect attached TV's on Chrontel */
2504 static void SiS_SenseCh(struct sis_video_info *ivideo)
2505 {
2506 #if defined(CONFIG_FB_SIS_300) || defined(CONFIG_FB_SIS_315)
2507     u8 temp1, temp2;
2508     char stdstr[] = "sisfb: Chrontel: Detected TV connected to";
2509 #endif
2510 #ifdef CONFIG_FB_SIS_300
2511     unsigned char test[3];
2512     int i;
2513 #endif
2514
2515     if(ivideo->chip < SIS_315H) {
2516
2517 #ifdef CONFIG_FB_SIS_300
2518        ivideo->SiS_Pr.SiS_IF_DEF_CH70xx = 1;            /* Chrontel 700x */
2519        SiS_SetChrontelGPIO(&ivideo->SiS_Pr, 0x9c);      /* Set general purpose IO for Chrontel communication */
2520        SiS_DDC2Delay(&ivideo->SiS_Pr, 1000);
2521        temp1 = SiS_GetCH700x(&ivideo->SiS_Pr, 0x25);
2522        /* See Chrontel TB31 for explanation */
2523        temp2 = SiS_GetCH700x(&ivideo->SiS_Pr, 0x0e);
2524        if(((temp2 & 0x07) == 0x01) || (temp2 & 0x04)) {
2525           SiS_SetCH700x(&ivideo->SiS_Pr, 0x0e, 0x0b);
2526           SiS_DDC2Delay(&ivideo->SiS_Pr, 300);
2527        }
2528        temp2 = SiS_GetCH700x(&ivideo->SiS_Pr, 0x25);
2529        if(temp2 != temp1) temp1 = temp2;
2530
2531        if((temp1 >= 0x22) && (temp1 <= 0x50)) {
2532            /* Read power status */
2533            temp1 = SiS_GetCH700x(&ivideo->SiS_Pr, 0x0e);
2534            if((temp1 & 0x03) != 0x03) {
2535                 /* Power all outputs */
2536                 SiS_SetCH700x(&ivideo->SiS_Pr, 0x0e,0x0b);
2537                 SiS_DDC2Delay(&ivideo->SiS_Pr, 300);
2538            }
2539            /* Sense connected TV devices */
2540            for(i = 0; i < 3; i++) {
2541                SiS_SetCH700x(&ivideo->SiS_Pr, 0x10, 0x01);
2542                SiS_DDC2Delay(&ivideo->SiS_Pr, 0x96);
2543                SiS_SetCH700x(&ivideo->SiS_Pr, 0x10, 0x00);
2544                SiS_DDC2Delay(&ivideo->SiS_Pr, 0x96);
2545                temp1 = SiS_GetCH700x(&ivideo->SiS_Pr, 0x10);
2546                if(!(temp1 & 0x08))       test[i] = 0x02;
2547                else if(!(temp1 & 0x02))  test[i] = 0x01;
2548                else                      test[i] = 0;
2549                SiS_DDC2Delay(&ivideo->SiS_Pr, 0x96);
2550            }
2551
2552            if(test[0] == test[1])      temp1 = test[0];
2553            else if(test[0] == test[2]) temp1 = test[0];
2554            else if(test[1] == test[2]) temp1 = test[1];
2555            else {
2556                 printk(KERN_INFO
2557                         "sisfb: TV detection unreliable - test results varied\n");
2558                 temp1 = test[2];
2559            }
2560            if(temp1 == 0x02) {
2561                 printk(KERN_INFO "%s SVIDEO output\n", stdstr);
2562                 ivideo->vbflags |= TV_SVIDEO;
2563                 SiS_SetRegOR(SISCR, 0x32, 0x02);
2564                 SiS_SetRegAND(SISCR, 0x32, ~0x05);
2565            } else if (temp1 == 0x01) {
2566                 printk(KERN_INFO "%s CVBS output\n", stdstr);
2567                 ivideo->vbflags |= TV_AVIDEO;
2568                 SiS_SetRegOR(SISCR, 0x32, 0x01);
2569                 SiS_SetRegAND(SISCR, 0x32, ~0x06);
2570            } else {
2571                 SiS_SetCH70xxANDOR(&ivideo->SiS_Pr, 0x0e, 0x01, 0xF8);
2572                 SiS_SetRegAND(SISCR, 0x32, ~0x07);
2573            }
2574        } else if(temp1 == 0) {
2575           SiS_SetCH70xxANDOR(&ivideo->SiS_Pr, 0x0e, 0x01, 0xF8);
2576           SiS_SetRegAND(SISCR, 0x32, ~0x07);
2577        }
2578        /* Set general purpose IO for Chrontel communication */
2579        SiS_SetChrontelGPIO(&ivideo->SiS_Pr, 0x00);
2580 #endif
2581
2582     } else {
2583
2584 #ifdef CONFIG_FB_SIS_315
2585         ivideo->SiS_Pr.SiS_IF_DEF_CH70xx = 2;           /* Chrontel 7019 */
2586         temp1 = SiS_GetCH701x(&ivideo->SiS_Pr, 0x49);
2587         SiS_SetCH701x(&ivideo->SiS_Pr, 0x49, 0x20);
2588         SiS_DDC2Delay(&ivideo->SiS_Pr, 0x96);
2589         temp2 = SiS_GetCH701x(&ivideo->SiS_Pr, 0x20);
2590         temp2 |= 0x01;
2591         SiS_SetCH701x(&ivideo->SiS_Pr, 0x20, temp2);
2592         SiS_DDC2Delay(&ivideo->SiS_Pr, 0x96);
2593         temp2 ^= 0x01;
2594         SiS_SetCH701x(&ivideo->SiS_Pr, 0x20, temp2);
2595         SiS_DDC2Delay(&ivideo->SiS_Pr, 0x96);
2596         temp2 = SiS_GetCH701x(&ivideo->SiS_Pr, 0x20);
2597         SiS_SetCH701x(&ivideo->SiS_Pr, 0x49, temp1);
2598         temp1 = 0;
2599         if(temp2 & 0x02) temp1 |= 0x01;
2600         if(temp2 & 0x10) temp1 |= 0x01;
2601         if(temp2 & 0x04) temp1 |= 0x02;
2602         if( (temp1 & 0x01) && (temp1 & 0x02) ) temp1 = 0x04;
2603         switch(temp1) {
2604         case 0x01:
2605              printk(KERN_INFO "%s CVBS output\n", stdstr);
2606              ivideo->vbflags |= TV_AVIDEO;
2607              SiS_SetRegOR(SISCR, 0x32, 0x01);
2608              SiS_SetRegAND(SISCR, 0x32, ~0x06);
2609              break;
2610         case 0x02:
2611              printk(KERN_INFO "%s SVIDEO output\n", stdstr);
2612              ivideo->vbflags |= TV_SVIDEO;
2613              SiS_SetRegOR(SISCR, 0x32, 0x02);
2614              SiS_SetRegAND(SISCR, 0x32, ~0x05);
2615              break;
2616         case 0x04:
2617              printk(KERN_INFO "%s SCART output\n", stdstr);
2618              SiS_SetRegOR(SISCR, 0x32, 0x04);
2619              SiS_SetRegAND(SISCR, 0x32, ~0x03);
2620              break;
2621         default:
2622              SiS_SetRegAND(SISCR, 0x32, ~0x07);
2623         }
2624 #endif
2625     }
2626 }
2627
2628 static void sisfb_get_VB_type(struct sis_video_info *ivideo)
2629 {
2630         char stdstr[]    = "sisfb: Detected";
2631         char bridgestr[] = "video bridge";
2632         u8 vb_chipid;
2633         u8 reg;
2634
2635         /* No CRT2 on XGI Z7 */
2636         if(ivideo->chip == XGI_20)
2637                 return;
2638
2639         vb_chipid = SiS_GetReg(SISPART4, 0x00);
2640         switch(vb_chipid) {
2641         case 0x01:
2642                 reg = SiS_GetReg(SISPART4, 0x01);
2643                 if(reg < 0xb0) {
2644                         ivideo->vbflags |= VB_301;      /* Deprecated */
2645                         ivideo->vbflags2 |= VB2_301;
2646                         printk(KERN_INFO "%s SiS301 %s\n", stdstr, bridgestr);
2647                 } else if(reg < 0xc0) {
2648                         ivideo->vbflags |= VB_301B;     /* Deprecated */
2649                         ivideo->vbflags2 |= VB2_301B;
2650                         reg = SiS_GetReg(SISPART4, 0x23);
2651                         if(!(reg & 0x02)) {
2652                            ivideo->vbflags |= VB_30xBDH;        /* Deprecated */
2653                            ivideo->vbflags2 |= VB2_30xBDH;
2654                            printk(KERN_INFO "%s SiS301B-DH %s\n", stdstr, bridgestr);
2655                         } else {
2656                            printk(KERN_INFO "%s SiS301B %s\n", stdstr, bridgestr);
2657                         }
2658                 } else if(reg < 0xd0) {
2659                         ivideo->vbflags |= VB_301C;     /* Deprecated */
2660                         ivideo->vbflags2 |= VB2_301C;
2661                         printk(KERN_INFO "%s SiS301C %s\n", stdstr, bridgestr);
2662                 } else if(reg < 0xe0) {
2663                         ivideo->vbflags |= VB_301LV;    /* Deprecated */
2664                         ivideo->vbflags2 |= VB2_301LV;
2665                         printk(KERN_INFO "%s SiS301LV %s\n", stdstr, bridgestr);
2666                 } else if(reg <= 0xe1) {
2667                         reg = SiS_GetReg(SISPART4, 0x39);
2668                         if(reg == 0xff) {
2669                            ivideo->vbflags |= VB_302LV; /* Deprecated */
2670                            ivideo->vbflags2 |= VB2_302LV;
2671                            printk(KERN_INFO "%s SiS302LV %s\n", stdstr, bridgestr);
2672                         } else {
2673                            ivideo->vbflags |= VB_301C;  /* Deprecated */
2674                            ivideo->vbflags2 |= VB2_301C;
2675                            printk(KERN_INFO "%s SiS301C(P4) %s\n", stdstr, bridgestr);
2676 #if 0
2677                            ivideo->vbflags |= VB_302ELV;        /* Deprecated */
2678                            ivideo->vbflags2 |= VB2_302ELV;
2679                            printk(KERN_INFO "%s SiS302ELV %s\n", stdstr, bridgestr);
2680 #endif
2681                         }
2682                 }
2683                 break;
2684         case 0x02:
2685                 ivideo->vbflags |= VB_302B;     /* Deprecated */
2686                 ivideo->vbflags2 |= VB2_302B;
2687                 printk(KERN_INFO "%s SiS302B %s\n", stdstr, bridgestr);
2688                 break;
2689         }
2690
2691         if((!(ivideo->vbflags2 & VB2_VIDEOBRIDGE)) && (ivideo->chip != SIS_300)) {
2692                 reg = SiS_GetReg(SISCR, 0x37);
2693                 reg &= SIS_EXTERNAL_CHIP_MASK;
2694                 reg >>= 1;
2695                 if(ivideo->sisvga_engine == SIS_300_VGA) {
2696 #ifdef CONFIG_FB_SIS_300
2697                         switch(reg) {
2698                            case SIS_EXTERNAL_CHIP_LVDS:
2699                                 ivideo->vbflags |= VB_LVDS;     /* Deprecated */
2700                                 ivideo->vbflags2 |= VB2_LVDS;
2701                                 break;
2702                            case SIS_EXTERNAL_CHIP_TRUMPION:
2703                                 ivideo->vbflags |= (VB_LVDS | VB_TRUMPION);     /* Deprecated */
2704                                 ivideo->vbflags2 |= (VB2_LVDS | VB2_TRUMPION);
2705                                 break;
2706                            case SIS_EXTERNAL_CHIP_CHRONTEL:
2707                                 ivideo->vbflags |= VB_CHRONTEL; /* Deprecated */
2708                                 ivideo->vbflags2 |= VB2_CHRONTEL;
2709                                 break;
2710                            case SIS_EXTERNAL_CHIP_LVDS_CHRONTEL:
2711                                 ivideo->vbflags |= (VB_LVDS | VB_CHRONTEL);     /* Deprecated */
2712                                 ivideo->vbflags2 |= (VB2_LVDS | VB2_CHRONTEL);
2713                                 break;
2714                         }
2715                         if(ivideo->vbflags2 & VB2_CHRONTEL) ivideo->chronteltype = 1;
2716 #endif
2717                 } else if(ivideo->chip < SIS_661) {
2718 #ifdef CONFIG_FB_SIS_315
2719                         switch (reg) {
2720                            case SIS310_EXTERNAL_CHIP_LVDS:
2721                                 ivideo->vbflags |= VB_LVDS;     /* Deprecated */
2722                                 ivideo->vbflags2 |= VB2_LVDS;
2723                                 break;
2724                            case SIS310_EXTERNAL_CHIP_LVDS_CHRONTEL:
2725                                 ivideo->vbflags |= (VB_LVDS | VB_CHRONTEL);     /* Deprecated */
2726                                 ivideo->vbflags2 |= (VB2_LVDS | VB2_CHRONTEL);
2727                                 break;
2728                         }
2729                         if(ivideo->vbflags2 & VB2_CHRONTEL) ivideo->chronteltype = 2;
2730 #endif
2731                 } else if(ivideo->chip >= SIS_661) {
2732 #ifdef CONFIG_FB_SIS_315
2733                         reg = SiS_GetReg(SISCR, 0x38);
2734                         reg >>= 5;
2735                         switch(reg) {
2736                            case 0x02:
2737                                 ivideo->vbflags |= VB_LVDS;     /* Deprecated */
2738                                 ivideo->vbflags2 |= VB2_LVDS;
2739                                 break;
2740                            case 0x03:
2741                                 ivideo->vbflags |= (VB_LVDS | VB_CHRONTEL);     /* Deprecated */
2742                                 ivideo->vbflags2 |= (VB2_LVDS | VB2_CHRONTEL);
2743                                 break;
2744                            case 0x04:
2745                                 ivideo->vbflags |= (VB_LVDS | VB_CONEXANT);     /* Deprecated */
2746                                 ivideo->vbflags2 |= (VB2_LVDS | VB2_CONEXANT);
2747                                 break;
2748                         }
2749                         if(ivideo->vbflags2 & VB2_CHRONTEL) ivideo->chronteltype = 2;
2750 #endif
2751                 }
2752                 if(ivideo->vbflags2 & VB2_LVDS) {
2753                    printk(KERN_INFO "%s LVDS transmitter\n", stdstr);
2754                 }
2755                 if((ivideo->sisvga_engine == SIS_300_VGA) && (ivideo->vbflags2 & VB2_TRUMPION)) {
2756                    printk(KERN_INFO "%s Trumpion Zurac LCD scaler\n", stdstr);
2757                 }
2758                 if(ivideo->vbflags2 & VB2_CHRONTEL) {
2759                    printk(KERN_INFO "%s Chrontel TV encoder\n", stdstr);
2760                 }
2761                 if((ivideo->chip >= SIS_661) && (ivideo->vbflags2 & VB2_CONEXANT)) {
2762                    printk(KERN_INFO "%s Conexant external device\n", stdstr);
2763                 }
2764         }
2765
2766         if(ivideo->vbflags2 & VB2_SISBRIDGE) {
2767                 SiS_SenseLCD(ivideo);
2768                 SiS_Sense30x(ivideo);
2769         } else if(ivideo->vbflags2 & VB2_CHRONTEL) {
2770                 SiS_SenseCh(ivideo);
2771         }
2772 }
2773
2774 /* ---------- Engine initialization routines ------------ */
2775
2776 static void
2777 sisfb_engine_init(struct sis_video_info *ivideo)
2778 {
2779
2780         /* Initialize command queue (we use MMIO only) */
2781
2782         /* BEFORE THIS IS CALLED, THE ENGINES *MUST* BE SYNC'ED */
2783
2784         ivideo->caps &= ~(TURBO_QUEUE_CAP    |
2785                           MMIO_CMD_QUEUE_CAP |
2786                           VM_CMD_QUEUE_CAP   |
2787                           AGP_CMD_QUEUE_CAP);
2788
2789 #ifdef CONFIG_FB_SIS_300
2790         if(ivideo->sisvga_engine == SIS_300_VGA) {
2791                 u32 tqueue_pos;
2792                 u8 tq_state;
2793
2794                 tqueue_pos = (ivideo->video_size - ivideo->cmdQueueSize) / (64 * 1024);
2795
2796                 tq_state = SiS_GetReg(SISSR, IND_SIS_TURBOQUEUE_SET);
2797                 tq_state |= 0xf0;
2798                 tq_state &= 0xfc;
2799                 tq_state |= (u8)(tqueue_pos >> 8);
2800                 SiS_SetReg(SISSR, IND_SIS_TURBOQUEUE_SET, tq_state);
2801
2802                 SiS_SetReg(SISSR, IND_SIS_TURBOQUEUE_ADR, (u8)(tqueue_pos & 0xff));
2803
2804                 ivideo->caps |= TURBO_QUEUE_CAP;
2805         }
2806 #endif
2807
2808 #ifdef CONFIG_FB_SIS_315
2809         if(ivideo->sisvga_engine == SIS_315_VGA) {
2810                 u32 tempq = 0, templ;
2811                 u8  temp;
2812
2813                 if(ivideo->chip == XGI_20) {
2814                         switch(ivideo->cmdQueueSize) {
2815                         case (64 * 1024):
2816                                 temp = SIS_CMD_QUEUE_SIZE_Z7_64k;
2817                                 break;
2818                         case (128 * 1024):
2819                         default:
2820                                 temp = SIS_CMD_QUEUE_SIZE_Z7_128k;
2821                         }
2822                 } else {
2823                         switch(ivideo->cmdQueueSize) {
2824                         case (4 * 1024 * 1024):
2825                                 temp = SIS_CMD_QUEUE_SIZE_4M;
2826                                 break;
2827                         case (2 * 1024 * 1024):
2828                                 temp = SIS_CMD_QUEUE_SIZE_2M;
2829                                 break;
2830                         case (1 * 1024 * 1024):
2831                                 temp = SIS_CMD_QUEUE_SIZE_1M;
2832                                 break;
2833                         default:
2834                         case (512 * 1024):
2835                                 temp = SIS_CMD_QUEUE_SIZE_512k;
2836                         }
2837                 }
2838
2839                 SiS_SetReg(SISSR, IND_SIS_CMDQUEUE_THRESHOLD, COMMAND_QUEUE_THRESHOLD);
2840                 SiS_SetReg(SISSR, IND_SIS_CMDQUEUE_SET, SIS_CMD_QUEUE_RESET);
2841
2842                 if((ivideo->chip >= XGI_40) && ivideo->modechanged) {
2843                         /* Must disable dual pipe on XGI_40. Can't do
2844                          * this in MMIO mode, because it requires
2845                          * setting/clearing a bit in the MMIO fire trigger
2846                          * register.
2847                          */
2848                         if(!((templ = MMIO_IN32(ivideo->mmio_vbase, 0x8240)) & (1 << 10))) {
2849
2850                                 MMIO_OUT32(ivideo->mmio_vbase, Q_WRITE_PTR, 0);
2851
2852                                 SiS_SetReg(SISSR, IND_SIS_CMDQUEUE_SET, (temp | SIS_VRAM_CMDQUEUE_ENABLE));
2853
2854                                 tempq = MMIO_IN32(ivideo->mmio_vbase, Q_READ_PTR);
2855                                 MMIO_OUT32(ivideo->mmio_vbase, Q_WRITE_PTR, tempq);
2856
2857                                 tempq = (u32)(ivideo->video_size - ivideo->cmdQueueSize);
2858                                 MMIO_OUT32(ivideo->mmio_vbase, Q_BASE_ADDR, tempq);
2859
2860                                 writel(0x16800000 + 0x8240, ivideo->video_vbase + tempq);
2861                                 writel(templ | (1 << 10), ivideo->video_vbase + tempq + 4);
2862                                 writel(0x168F0000, ivideo->video_vbase + tempq + 8);
2863                                 writel(0x168F0000, ivideo->video_vbase + tempq + 12);
2864
2865                                 MMIO_OUT32(ivideo->mmio_vbase, Q_WRITE_PTR, (tempq + 16));
2866
2867                                 sisfb_syncaccel(ivideo);
2868
2869                                 SiS_SetReg(SISSR, IND_SIS_CMDQUEUE_SET, SIS_CMD_QUEUE_RESET);
2870
2871                         }
2872                 }
2873
2874                 tempq = MMIO_IN32(ivideo->mmio_vbase, MMIO_QUEUE_READPORT);
2875                 MMIO_OUT32(ivideo->mmio_vbase, MMIO_QUEUE_WRITEPORT, tempq);
2876
2877                 temp |= (SIS_MMIO_CMD_ENABLE | SIS_CMD_AUTO_CORR);
2878                 SiS_SetReg(SISSR, IND_SIS_CMDQUEUE_SET, temp);
2879
2880                 tempq = (u32)(ivideo->video_size - ivideo->cmdQueueSize);
2881                 MMIO_OUT32(ivideo->mmio_vbase, MMIO_QUEUE_PHYBASE, tempq);
2882
2883                 ivideo->caps |= MMIO_CMD_QUEUE_CAP;
2884         }
2885 #endif
2886
2887         ivideo->engineok = 1;
2888 }
2889
2890 static void sisfb_detect_lcd_type(struct sis_video_info *ivideo)
2891 {
2892         u8 reg;
2893         int i;
2894
2895         reg = SiS_GetReg(SISCR, 0x36);
2896         reg &= 0x0f;
2897         if(ivideo->sisvga_engine == SIS_300_VGA) {
2898                 ivideo->CRT2LCDType = sis300paneltype[reg];
2899         } else if(ivideo->chip >= SIS_661) {
2900                 ivideo->CRT2LCDType = sis661paneltype[reg];
2901         } else {
2902                 ivideo->CRT2LCDType = sis310paneltype[reg];
2903                 if((ivideo->chip == SIS_550) && (sisfb_fstn)) {
2904                         if((ivideo->CRT2LCDType != LCD_320x240_2) &&
2905                            (ivideo->CRT2LCDType != LCD_320x240_3)) {
2906                                 ivideo->CRT2LCDType = LCD_320x240;
2907                         }
2908                 }
2909         }
2910
2911         if(ivideo->CRT2LCDType == LCD_UNKNOWN) {
2912                 /* For broken BIOSes: Assume 1024x768, RGB18 */
2913                 ivideo->CRT2LCDType = LCD_1024x768;
2914                 SiS_SetRegANDOR(SISCR, 0x36, 0xf0, 0x02);
2915                 SiS_SetRegANDOR(SISCR, 0x37, 0xee, 0x01);
2916                 printk(KERN_DEBUG "sisfb: Invalid panel ID (%02x), assuming 1024x768, RGB18\n", reg);
2917         }
2918
2919         for(i = 0; i < SIS_LCD_NUMBER; i++) {
2920                 if(ivideo->CRT2LCDType == sis_lcd_data[i].lcdtype) {
2921                         ivideo->lcdxres = sis_lcd_data[i].xres;
2922                         ivideo->lcdyres = sis_lcd_data[i].yres;
2923                         ivideo->lcddefmodeidx = sis_lcd_data[i].default_mode_idx;
2924                         break;
2925                 }
2926         }
2927
2928 #ifdef CONFIG_FB_SIS_300
2929         if(ivideo->SiS_Pr.SiS_CustomT == CUT_BARCO1366) {
2930                 ivideo->lcdxres = 1360; ivideo->lcdyres = 1024;
2931                 ivideo->lcddefmodeidx = DEFAULT_MODE_1360;
2932         } else if(ivideo->SiS_Pr.SiS_CustomT == CUT_PANEL848) {
2933                 ivideo->lcdxres =  848; ivideo->lcdyres =  480;
2934                 ivideo->lcddefmodeidx = DEFAULT_MODE_848;
2935         } else if(ivideo->SiS_Pr.SiS_CustomT == CUT_PANEL856) {
2936                 ivideo->lcdxres =  856; ivideo->lcdyres =  480;
2937                 ivideo->lcddefmodeidx = DEFAULT_MODE_856;
2938         }
2939 #endif
2940
2941         printk(KERN_DEBUG "sisfb: Detected %dx%d flat panel\n",
2942                         ivideo->lcdxres, ivideo->lcdyres);
2943 }
2944
2945 static void sisfb_save_pdc_emi(struct sis_video_info *ivideo)
2946 {
2947 #ifdef CONFIG_FB_SIS_300
2948         /* Save the current PanelDelayCompensation if the LCD is currently used */
2949         if(ivideo->sisvga_engine == SIS_300_VGA) {
2950                 if(ivideo->vbflags2 & (VB2_LVDS | VB2_30xBDH)) {
2951                         int tmp;
2952                         tmp = SiS_GetReg(SISCR, 0x30);
2953                         if(tmp & 0x20) {
2954                                 /* Currently on LCD? If yes, read current pdc */
2955                                 ivideo->detectedpdc = SiS_GetReg(SISPART1, 0x13);
2956                                 ivideo->detectedpdc &= 0x3c;
2957                                 if(ivideo->SiS_Pr.PDC == -1) {
2958                                         /* Let option override detection */
2959                                         ivideo->SiS_Pr.PDC = ivideo->detectedpdc;
2960                                 }
2961                                 printk(KERN_INFO "sisfb: Detected LCD PDC 0x%02x\n",
2962                                         ivideo->detectedpdc);
2963                         }
2964                         if((ivideo->SiS_Pr.PDC != -1) &&
2965                            (ivideo->SiS_Pr.PDC != ivideo->detectedpdc)) {
2966                                 printk(KERN_INFO "sisfb: Using LCD PDC 0x%02x\n",
2967                                         ivideo->SiS_Pr.PDC);
2968                         }
2969                 }
2970         }
2971 #endif
2972
2973 #ifdef CONFIG_FB_SIS_315
2974         if(ivideo->sisvga_engine == SIS_315_VGA) {
2975
2976                 /* Try to find about LCDA */
2977                 if(ivideo->vbflags2 & VB2_SISLCDABRIDGE) {
2978                         int tmp;
2979                         tmp = SiS_GetReg(SISPART1, 0x13);
2980                         if(tmp & 0x04) {