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