[PATCH] sisfb update
[deliverable/linux.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,
2005 .fb_cursor = soft_cursor,
2006 .fb_sync = fbcon_sis_sync,
2007#ifdef SIS_NEW_CONFIG_COMPAT
2008 .fb_compat_ioctl= sisfb_compat_ioctl,
1da177e4 2009#endif
544393fe 2010 .fb_ioctl = sisfb_ioctl
1da177e4
LT
2011};
2012#endif
2013
2014/* ---------------- Chip generation dependent routines ---------------- */
2015
544393fe
TW
2016static struct pci_dev * __devinit
2017sisfb_get_northbridge(int basechipid)
1da177e4
LT
2018{
2019 struct pci_dev *pdev = NULL;
2020 int nbridgenum, nbridgeidx, i;
544393fe 2021 static const unsigned short nbridgeids[] = {
1da177e4
LT
2022 PCI_DEVICE_ID_SI_540, /* for SiS 540 VGA */
2023 PCI_DEVICE_ID_SI_630, /* for SiS 630/730 VGA */
2024 PCI_DEVICE_ID_SI_730,
2025 PCI_DEVICE_ID_SI_550, /* for SiS 550 VGA */
2026 PCI_DEVICE_ID_SI_650, /* for SiS 650/651/740 VGA */
2027 PCI_DEVICE_ID_SI_651,
2028 PCI_DEVICE_ID_SI_740,
544393fe 2029 PCI_DEVICE_ID_SI_661, /* for SiS 661/741/660/760/761 VGA */
1da177e4
LT
2030 PCI_DEVICE_ID_SI_741,
2031 PCI_DEVICE_ID_SI_660,
544393fe
TW
2032 PCI_DEVICE_ID_SI_760,
2033 PCI_DEVICE_ID_SI_761
1da177e4
LT
2034 };
2035
544393fe 2036 switch(basechipid) {
1da177e4
LT
2037#ifdef CONFIG_FB_SIS_300
2038 case SIS_540: nbridgeidx = 0; nbridgenum = 1; break;
2039 case SIS_630: nbridgeidx = 1; nbridgenum = 2; break;
2040#endif
2041#ifdef CONFIG_FB_SIS_315
2042 case SIS_550: nbridgeidx = 3; nbridgenum = 1; break;
2043 case SIS_650: nbridgeidx = 4; nbridgenum = 3; break;
544393fe 2044 case SIS_660: nbridgeidx = 7; nbridgenum = 5; break;
1da177e4
LT
2045#endif
2046 default: return NULL;
2047 }
2048 for(i = 0; i < nbridgenum; i++) {
544393fe
TW
2049 if((pdev = SIS_PCI_GET_DEVICE(PCI_VENDOR_ID_SI,
2050 nbridgeids[nbridgeidx+i], NULL)))
2051 break;
1da177e4
LT
2052 }
2053 return pdev;
2054}
2055
544393fe
TW
2056static int __devinit
2057sisfb_get_dram_size(struct sis_video_info *ivideo)
1da177e4
LT
2058{
2059#if defined(CONFIG_FB_SIS_300) || defined(CONFIG_FB_SIS_315)
2060 u8 reg;
2061#endif
2062
2063 ivideo->video_size = 0;
544393fe 2064 ivideo->UMAsize = ivideo->LFBsize = 0;
1da177e4
LT
2065
2066 switch(ivideo->chip) {
2067#ifdef CONFIG_FB_SIS_300
2068 case SIS_300:
544393fe 2069 inSISIDXREG(SISSR, 0x14, reg);
1da177e4
LT
2070 ivideo->video_size = ((reg & 0x3F) + 1) << 20;
2071 break;
2072 case SIS_540:
2073 case SIS_630:
2074 case SIS_730:
544393fe
TW
2075 if(!ivideo->nbridge)
2076 return -1;
2077 pci_read_config_byte(ivideo->nbridge, 0x63, &reg);
1da177e4
LT
2078 ivideo->video_size = 1 << (((reg & 0x70) >> 4) + 21);
2079 break;
2080#endif
2081#ifdef CONFIG_FB_SIS_315
2082 case SIS_315H:
2083 case SIS_315PRO:
2084 case SIS_315:
544393fe 2085 inSISIDXREG(SISSR, 0x14, reg);
1da177e4
LT
2086 ivideo->video_size = (1 << ((reg & 0xf0) >> 4)) << 20;
2087 switch((reg >> 2) & 0x03) {
2088 case 0x01:
2089 case 0x03:
544393fe
TW
2090 ivideo->video_size <<= 1;
2091 break;
1da177e4 2092 case 0x02:
544393fe 2093 ivideo->video_size += (ivideo->video_size/2);
1da177e4 2094 }
544393fe 2095 break;
1da177e4 2096 case SIS_330:
544393fe 2097 inSISIDXREG(SISSR, 0x14, reg);
1da177e4
LT
2098 ivideo->video_size = (1 << ((reg & 0xf0) >> 4)) << 20;
2099 if(reg & 0x0c) ivideo->video_size <<= 1;
544393fe 2100 break;
1da177e4
LT
2101 case SIS_550:
2102 case SIS_650:
2103 case SIS_740:
544393fe 2104 inSISIDXREG(SISSR, 0x14, reg);
1da177e4
LT
2105 ivideo->video_size = (((reg & 0x3f) + 1) << 2) << 20;
2106 break;
2107 case SIS_661:
2108 case SIS_741:
544393fe 2109 inSISIDXREG(SISCR, 0x79, reg);
1da177e4 2110 ivideo->video_size = (1 << ((reg & 0xf0) >> 4)) << 20;
544393fe 2111 break;
1da177e4
LT
2112 case SIS_660:
2113 case SIS_760:
544393fe 2114 case SIS_761:
1da177e4
LT
2115 inSISIDXREG(SISCR, 0x79, reg);
2116 reg = (reg & 0xf0) >> 4;
544393fe
TW
2117 if(reg) {
2118 ivideo->video_size = (1 << reg) << 20;
2119 ivideo->UMAsize = ivideo->video_size;
2120 }
1da177e4
LT
2121 inSISIDXREG(SISCR, 0x78, reg);
2122 reg &= 0x30;
2123 if(reg) {
544393fe
TW
2124 if(reg == 0x10) {
2125 ivideo->LFBsize = (32 << 20);
2126 } else {
2127 ivideo->LFBsize = (64 << 20);
2128 }
2129 ivideo->video_size += ivideo->LFBsize;
2130 }
2131 break;
2132 case SIS_340:
2133 case XGI_20:
2134 case XGI_40:
2135 inSISIDXREG(SISSR, 0x14, reg);
2136 ivideo->video_size = (1 << ((reg & 0xf0) >> 4)) << 20;
2137 if(ivideo->chip != XGI_20) {
2138 reg = (reg & 0x0c) >> 2;
2139 if(ivideo->revision_id == 2) {
2140 if(reg & 0x01) reg = 0x02;
2141 else reg = 0x00;
2142 }
2143 if(reg == 0x02) ivideo->video_size <<= 1;
2144 else if(reg == 0x03) ivideo->video_size <<= 2;
1da177e4 2145 }
544393fe 2146 break;
1da177e4
LT
2147#endif
2148 default:
2149 return -1;
2150 }
2151 return 0;
2152}
2153
2154/* -------------- video bridge device detection --------------- */
2155
544393fe
TW
2156static void __devinit
2157sisfb_detect_VB_connect(struct sis_video_info *ivideo)
1da177e4
LT
2158{
2159 u8 cr32, temp;
2160
544393fe
TW
2161 /* No CRT2 on XGI Z7 */
2162 if(ivideo->chip == XGI_20) {
2163 ivideo->sisfb_crt1off = 0;
2164 return;
2165 }
2166
1da177e4
LT
2167#ifdef CONFIG_FB_SIS_300
2168 if(ivideo->sisvga_engine == SIS_300_VGA) {
2169 inSISIDXREG(SISSR, 0x17, temp);
2170 if((temp & 0x0F) && (ivideo->chip != SIS_300)) {
2171 /* PAL/NTSC is stored on SR16 on such machines */
2172 if(!(ivideo->vbflags & (TV_PAL | TV_NTSC | TV_PALM | TV_PALN))) {
544393fe 2173 inSISIDXREG(SISSR, 0x16, temp);
1da177e4
LT
2174 if(temp & 0x20)
2175 ivideo->vbflags |= TV_PAL;
2176 else
2177 ivideo->vbflags |= TV_NTSC;
2178 }
2179 }
2180 }
2181#endif
2182
2183 inSISIDXREG(SISCR, 0x32, cr32);
2184
2185 if(cr32 & SIS_CRT1) {
2186 ivideo->sisfb_crt1off = 0;
2187 } else {
2188 ivideo->sisfb_crt1off = (cr32 & 0xDF) ? 1 : 0;
2189 }
2190
2191 ivideo->vbflags &= ~(CRT2_TV | CRT2_LCD | CRT2_VGA);
2192
2193 if(cr32 & SIS_VB_TV) ivideo->vbflags |= CRT2_TV;
2194 if(cr32 & SIS_VB_LCD) ivideo->vbflags |= CRT2_LCD;
2195 if(cr32 & SIS_VB_CRT2) ivideo->vbflags |= CRT2_VGA;
2196
2197 /* Check given parms for hardware compatibility.
2198 * (Cannot do this in the search_xx routines since we don't
2199 * know what hardware we are running on then)
2200 */
2201
2202 if(ivideo->chip != SIS_550) {
2203 ivideo->sisfb_dstn = ivideo->sisfb_fstn = 0;
2204 }
2205
2206 if(ivideo->sisfb_tvplug != -1) {
2207 if( (ivideo->sisvga_engine != SIS_315_VGA) ||
544393fe 2208 (!(ivideo->vbflags2 & VB2_SISYPBPRBRIDGE)) ) {
1da177e4 2209 if(ivideo->sisfb_tvplug & TV_YPBPR) {
544393fe 2210 ivideo->sisfb_tvplug = -1;
1da177e4
LT
2211 printk(KERN_ERR "sisfb: YPbPr not supported\n");
2212 }
2213 }
2214 }
2215 if(ivideo->sisfb_tvplug != -1) {
2216 if( (ivideo->sisvga_engine != SIS_315_VGA) ||
544393fe 2217 (!(ivideo->vbflags2 & VB2_SISHIVISIONBRIDGE)) ) {
1da177e4 2218 if(ivideo->sisfb_tvplug & TV_HIVISION) {
544393fe 2219 ivideo->sisfb_tvplug = -1;
1da177e4
LT
2220 printk(KERN_ERR "sisfb: HiVision not supported\n");
2221 }
2222 }
2223 }
2224 if(ivideo->sisfb_tvstd != -1) {
544393fe
TW
2225 if( (!(ivideo->vbflags2 & VB2_SISBRIDGE)) &&
2226 (!((ivideo->sisvga_engine == SIS_315_VGA) &&
2227 (ivideo->vbflags2 & VB2_CHRONTEL))) ) {
1da177e4 2228 if(ivideo->sisfb_tvstd & (TV_PALN | TV_PALN | TV_NTSCJ)) {
544393fe
TW
2229 ivideo->sisfb_tvstd = -1;
2230 printk(KERN_ERR "sisfb: PALM/PALN/NTSCJ not supported\n");
1da177e4
LT
2231 }
2232 }
2233 }
2234
2235 /* Detect/set TV plug & type */
2236 if(ivideo->sisfb_tvplug != -1) {
2237 ivideo->vbflags |= ivideo->sisfb_tvplug;
2238 } else {
2239 if(cr32 & SIS_VB_YPBPR) ivideo->vbflags |= (TV_YPBPR|TV_YPBPR525I); /* default: 480i */
2240 else if(cr32 & SIS_VB_HIVISION) ivideo->vbflags |= TV_HIVISION;
2241 else if(cr32 & SIS_VB_SCART) ivideo->vbflags |= TV_SCART;
544393fe 2242 else {
1da177e4
LT
2243 if(cr32 & SIS_VB_SVIDEO) ivideo->vbflags |= TV_SVIDEO;
2244 if(cr32 & SIS_VB_COMPOSITE) ivideo->vbflags |= TV_AVIDEO;
2245 }
2246 }
2247
2248 if(!(ivideo->vbflags & (TV_YPBPR | TV_HIVISION))) {
2249 if(ivideo->sisfb_tvstd != -1) {
2250 ivideo->vbflags &= ~(TV_NTSC | TV_PAL | TV_PALM | TV_PALN | TV_NTSCJ);
2251 ivideo->vbflags |= ivideo->sisfb_tvstd;
2252 }
2253 if(ivideo->vbflags & TV_SCART) {
2254 ivideo->vbflags &= ~(TV_NTSC | TV_PALM | TV_PALN | TV_NTSCJ);
2255 ivideo->vbflags |= TV_PAL;
2256 }
2257 if(!(ivideo->vbflags & (TV_PAL | TV_NTSC | TV_PALM | TV_PALN | TV_NTSCJ))) {
2258 if(ivideo->sisvga_engine == SIS_300_VGA) {
544393fe 2259 inSISIDXREG(SISSR, 0x38, temp);
1da177e4
LT
2260 if(temp & 0x01) ivideo->vbflags |= TV_PAL;
2261 else ivideo->vbflags |= TV_NTSC;
2262 } else if((ivideo->chip <= SIS_315PRO) || (ivideo->chip >= SIS_330)) {
544393fe 2263 inSISIDXREG(SISSR, 0x38, temp);
1da177e4
LT
2264 if(temp & 0x01) ivideo->vbflags |= TV_PAL;
2265 else ivideo->vbflags |= TV_NTSC;
544393fe
TW
2266 } else {
2267 inSISIDXREG(SISCR, 0x79, temp);
1da177e4
LT
2268 if(temp & 0x20) ivideo->vbflags |= TV_PAL;
2269 else ivideo->vbflags |= TV_NTSC;
544393fe 2270 }
1da177e4
LT
2271 }
2272 }
2273
2274 /* Copy forceCRT1 option to CRT1off if option is given */
544393fe
TW
2275 if(ivideo->sisfb_forcecrt1 != -1) {
2276 ivideo->sisfb_crt1off = (ivideo->sisfb_forcecrt1) ? 0 : 1;
1da177e4
LT
2277 }
2278}
2279
2280/* ------------------ Sensing routines ------------------ */
2281
544393fe
TW
2282static BOOLEAN __devinit
2283sisfb_test_DDC1(struct sis_video_info *ivideo)
1da177e4
LT
2284{
2285 unsigned short old;
2286 int count = 48;
2287
2288 old = SiS_ReadDDC1Bit(&ivideo->SiS_Pr);
2289 do {
544393fe 2290 if(old != SiS_ReadDDC1Bit(&ivideo->SiS_Pr)) break;
1da177e4
LT
2291 } while(count--);
2292 return (count == -1) ? FALSE : TRUE;
2293}
2294
544393fe
TW
2295static void __devinit
2296sisfb_sense_crt1(struct sis_video_info *ivideo)
1da177e4
LT
2297{
2298 BOOLEAN mustwait = FALSE;
2299 u8 sr1F, cr17;
2300#ifdef CONFIG_FB_SIS_315
2301 u8 cr63=0;
2302#endif
2303 u16 temp = 0xffff;
2304 int i;
2305
2306 inSISIDXREG(SISSR,0x1F,sr1F);
2307 orSISIDXREG(SISSR,0x1F,0x04);
2308 andSISIDXREG(SISSR,0x1F,0x3F);
2309 if(sr1F & 0xc0) mustwait = TRUE;
2310
2311#ifdef CONFIG_FB_SIS_315
2312 if(ivideo->sisvga_engine == SIS_315_VGA) {
2313 inSISIDXREG(SISCR,ivideo->SiS_Pr.SiS_MyCR63,cr63);
2314 cr63 &= 0x40;
2315 andSISIDXREG(SISCR,ivideo->SiS_Pr.SiS_MyCR63,0xBF);
2316 }
2317#endif
2318
2319 inSISIDXREG(SISCR,0x17,cr17);
2320 cr17 &= 0x80;
2321 if(!cr17) {
2322 orSISIDXREG(SISCR,0x17,0x80);
2323 mustwait = TRUE;
2324 outSISIDXREG(SISSR, 0x00, 0x01);
2325 outSISIDXREG(SISSR, 0x00, 0x03);
2326 }
2327
2328 if(mustwait) {
2329 for(i=0; i < 10; i++) sisfbwaitretracecrt1(ivideo);
2330 }
2331
2332#ifdef CONFIG_FB_SIS_315
2333 if(ivideo->chip >= SIS_330) {
2334 andSISIDXREG(SISCR,0x32,~0x20);
2335 if(ivideo->chip >= SIS_340) {
2336 outSISIDXREG(SISCR, 0x57, 0x4a);
2337 } else {
2338 outSISIDXREG(SISCR, 0x57, 0x5f);
2339 }
2340 orSISIDXREG(SISCR, 0x53, 0x02);
2341 while((inSISREG(SISINPSTAT)) & 0x01) break;
2342 while(!((inSISREG(SISINPSTAT)) & 0x01)) break;
2343 if((inSISREG(SISMISCW)) & 0x10) temp = 1;
2344 andSISIDXREG(SISCR, 0x53, 0xfd);
2345 andSISIDXREG(SISCR, 0x57, 0x00);
2346 }
2347#endif
2348
2349 if(temp == 0xffff) {
2350 i = 3;
2351 do {
544393fe
TW
2352 temp = SiS_HandleDDC(&ivideo->SiS_Pr, ivideo->vbflags,
2353 ivideo->sisvga_engine, 0, 0, NULL, ivideo->vbflags2);
1da177e4
LT
2354 } while(((temp == 0) || (temp == 0xffff)) && i--);
2355
2356 if((temp == 0) || (temp == 0xffff)) {
2357 if(sisfb_test_DDC1(ivideo)) temp = 1;
2358 }
2359 }
2360
2361 if((temp) && (temp != 0xffff)) {
2362 orSISIDXREG(SISCR,0x32,0x20);
2363 }
2364
2365#ifdef CONFIG_FB_SIS_315
2366 if(ivideo->sisvga_engine == SIS_315_VGA) {
2367 setSISIDXREG(SISCR,ivideo->SiS_Pr.SiS_MyCR63,0xBF,cr63);
2368 }
2369#endif
2370
2371 setSISIDXREG(SISCR,0x17,0x7F,cr17);
2372
2373 outSISIDXREG(SISSR,0x1F,sr1F);
2374}
2375
2376/* Determine and detect attached devices on SiS30x */
544393fe
TW
2377static void __devinit
2378SiS_SenseLCD(struct sis_video_info *ivideo)
2379{
2380 unsigned char buffer[256];
2381 unsigned short temp, realcrtno, i;
2382 u8 reg, cr37 = 0, paneltype = 0;
2383 u16 xres, yres;
2384
2385 ivideo->SiS_Pr.PanelSelfDetected = FALSE;
2386
2387 /* LCD detection only for TMDS bridges */
2388 if(!(ivideo->vbflags2 & VB2_SISTMDSBRIDGE))
2389 return;
2390 if(ivideo->vbflags2 & VB2_30xBDH)
2391 return;
2392
2393 /* If LCD already set up by BIOS, skip it */
2394 inSISIDXREG(SISCR, 0x32, reg);
2395 if(reg & 0x08)
2396 return;
2397
2398 realcrtno = 1;
2399 if(ivideo->SiS_Pr.DDCPortMixup)
2400 realcrtno = 0;
2401
2402 /* Check DDC capabilities */
2403 temp = SiS_HandleDDC(&ivideo->SiS_Pr, ivideo->vbflags, ivideo->sisvga_engine,
2404 realcrtno, 0, &buffer[0], ivideo->vbflags2);
2405
2406 if((!temp) || (temp == 0xffff) || (!(temp & 0x02)))
2407 return;
2408
2409 /* Read DDC data */
2410 i = 3; /* Number of retrys */
2411 do {
2412 temp = SiS_HandleDDC(&ivideo->SiS_Pr, ivideo->vbflags,
2413 ivideo->sisvga_engine, realcrtno, 1,
2414 &buffer[0], ivideo->vbflags2);
2415 } while((temp) && i--);
2416
2417 if(temp)
2418 return;
2419
2420 /* No digital device */
2421 if(!(buffer[0x14] & 0x80))
2422 return;
2423
2424 /* First detailed timing preferred timing? */
2425 if(!(buffer[0x18] & 0x02))
2426 return;
2427
2428 xres = buffer[0x38] | ((buffer[0x3a] & 0xf0) << 4);
2429 yres = buffer[0x3b] | ((buffer[0x3d] & 0xf0) << 4);
2430
2431 switch(xres) {
2432 case 1024:
2433 if(yres == 768)
2434 paneltype = 0x02;
2435 break;
2436 case 1280:
2437 if(yres == 1024)
2438 paneltype = 0x03;
2439 break;
2440 case 1600:
2441 if((yres == 1200) && (ivideo->vbflags2 & VB2_30xC))
2442 paneltype = 0x0b;
2443 break;
2444 }
2445
2446 if(!paneltype)
2447 return;
2448
2449 if(buffer[0x23])
2450 cr37 |= 0x10;
2451
2452 if((buffer[0x47] & 0x18) == 0x18)
2453 cr37 |= ((((buffer[0x47] & 0x06) ^ 0x06) << 5) | 0x20);
2454 else
2455 cr37 |= 0xc0;
2456
2457 outSISIDXREG(SISCR, 0x36, paneltype);
2458 cr37 &= 0xf1;
2459 setSISIDXREG(SISCR, 0x37, 0x0c, cr37);
2460 orSISIDXREG(SISCR, 0x32, 0x08);
2461
2462 ivideo->SiS_Pr.PanelSelfDetected = TRUE;
2463}
2464
2465static int __devinit
2466SISDoSense(struct sis_video_info *ivideo, u16 type, u16 test)
1da177e4
LT
2467{
2468 int temp, mytest, result, i, j;
2469
2470 for(j = 0; j < 10; j++) {
2471 result = 0;
2472 for(i = 0; i < 3; i++) {
2473 mytest = test;
2474 outSISIDXREG(SISPART4,0x11,(type & 0x00ff));
2475 temp = (type >> 8) | (mytest & 0x00ff);
2476 setSISIDXREG(SISPART4,0x10,0xe0,temp);
2477 SiS_DDC2Delay(&ivideo->SiS_Pr, 0x1500);
2478 mytest >>= 8;
2479 mytest &= 0x7f;
2480 inSISIDXREG(SISPART4,0x03,temp);
2481 temp ^= 0x0e;
2482 temp &= mytest;
2483 if(temp == mytest) result++;
2484#if 1
2485 outSISIDXREG(SISPART4,0x11,0x00);
2486 andSISIDXREG(SISPART4,0x10,0xe0);
2487 SiS_DDC2Delay(&ivideo->SiS_Pr, 0x1000);
2488#endif
2489 }
2490 if((result == 0) || (result >= 2)) break;
2491 }
544393fe 2492 return result;
1da177e4
LT
2493}
2494
544393fe
TW
2495static void __devinit
2496SiS_Sense30x(struct sis_video_info *ivideo)
1da177e4
LT
2497{
2498 u8 backupP4_0d,backupP2_00,backupP2_4d,backupSR_1e,biosflag=0;
2499 u16 svhs=0, svhs_c=0;
2500 u16 cvbs=0, cvbs_c=0;
2501 u16 vga2=0, vga2_c=0;
2502 int myflag, result;
2503 char stdstr[] = "sisfb: Detected";
2504 char tvstr[] = "TV connected to";
2505
544393fe 2506 if(ivideo->vbflags2 & VB2_301) {
1da177e4
LT
2507 svhs = 0x00b9; cvbs = 0x00b3; vga2 = 0x00d1;
2508 inSISIDXREG(SISPART4,0x01,myflag);
2509 if(myflag & 0x04) {
2510 svhs = 0x00dd; cvbs = 0x00ee; vga2 = 0x00fd;
2511 }
544393fe 2512 } else if(ivideo->vbflags2 & (VB2_301B | VB2_302B)) {
1da177e4 2513 svhs = 0x016b; cvbs = 0x0174; vga2 = 0x0190;
544393fe 2514 } else if(ivideo->vbflags2 & (VB2_301LV | VB2_302LV)) {
1da177e4 2515 svhs = 0x0200; cvbs = 0x0100;
544393fe 2516 } else if(ivideo->vbflags2 & (VB2_301C | VB2_302ELV | VB2_307T | VB2_307LV)) {
1da177e4 2517 svhs = 0x016b; cvbs = 0x0110; vga2 = 0x0190;
544393fe
TW
2518 } else
2519 return;
1da177e4
LT
2520
2521 vga2_c = 0x0e08; svhs_c = 0x0404; cvbs_c = 0x0804;
544393fe 2522 if(ivideo->vbflags & (VB2_301LV|VB2_302LV|VB2_302ELV|VB2_307LV)) {
1da177e4
LT
2523 svhs_c = 0x0408; cvbs_c = 0x0808;
2524 }
544393fe 2525
1da177e4 2526 biosflag = 2;
544393fe
TW
2527 if(ivideo->haveXGIROM) {
2528 biosflag = ivideo->bios_abase[0x58] & 0x03;
2529 } else if(ivideo->newrom) {
2530 if(ivideo->bios_abase[0x5d] & 0x04) biosflag |= 0x01;
2531 } else if(ivideo->sisvga_engine == SIS_300_VGA) {
2532 if(ivideo->bios_abase) {
2533 biosflag = ivideo->bios_abase[0xfe] & 0x03;
2534 }
2535 }
1da177e4
LT
2536
2537 if(ivideo->chip == SIS_300) {
2538 inSISIDXREG(SISSR,0x3b,myflag);
2539 if(!(myflag & 0x01)) vga2 = vga2_c = 0;
2540 }
2541
544393fe
TW
2542 if(!(ivideo->vbflags2 & VB2_SISVGA2BRIDGE)) {
2543 vga2 = vga2_c = 0;
2544 }
2545
1da177e4
LT
2546 inSISIDXREG(SISSR,0x1e,backupSR_1e);
2547 orSISIDXREG(SISSR,0x1e,0x20);
2548
2549 inSISIDXREG(SISPART4,0x0d,backupP4_0d);
544393fe 2550 if(ivideo->vbflags2 & VB2_30xC) {
1da177e4
LT
2551 setSISIDXREG(SISPART4,0x0d,~0x07,0x01);
2552 } else {
2553 orSISIDXREG(SISPART4,0x0d,0x04);
2554 }
2555 SiS_DDC2Delay(&ivideo->SiS_Pr, 0x2000);
2556
2557 inSISIDXREG(SISPART2,0x00,backupP2_00);
2558 outSISIDXREG(SISPART2,0x00,((backupP2_00 | 0x1c) & 0xfc));
2559
2560 inSISIDXREG(SISPART2,0x4d,backupP2_4d);
544393fe 2561 if(ivideo->vbflags2 & VB2_SISYPBPRBRIDGE) {
1da177e4
LT
2562 outSISIDXREG(SISPART2,0x4d,(backupP2_4d & ~0x10));
2563 }
2564
544393fe 2565 if(!(ivideo->vbflags2 & VB2_30xCLV)) {
1da177e4
LT
2566 SISDoSense(ivideo, 0, 0);
2567 }
2568
2569 andSISIDXREG(SISCR, 0x32, ~0x14);
2570
2571 if(vga2_c || vga2) {
2572 if(SISDoSense(ivideo, vga2, vga2_c)) {
2573 if(biosflag & 0x01) {
2574 printk(KERN_INFO "%s %s SCART output\n", stdstr, tvstr);
2575 orSISIDXREG(SISCR, 0x32, 0x04);
2576 } else {
2577 printk(KERN_INFO "%s secondary VGA connection\n", stdstr);
2578 orSISIDXREG(SISCR, 0x32, 0x10);
2579 }
2580 }
2581 }
2582
2583 andSISIDXREG(SISCR, 0x32, 0x3f);
2584
544393fe 2585 if(ivideo->vbflags2 & VB2_30xCLV) {
1da177e4
LT
2586 orSISIDXREG(SISPART4,0x0d,0x04);
2587 }
2588
544393fe 2589 if((ivideo->sisvga_engine == SIS_315_VGA) && (ivideo->vbflags2 & VB2_SISYPBPRBRIDGE)) {
1da177e4
LT
2590 outSISIDXREG(SISPART2,0x4d,(backupP2_4d | 0x10));
2591 SiS_DDC2Delay(&ivideo->SiS_Pr, 0x2000);
2592 if((result = SISDoSense(ivideo, svhs, 0x0604))) {
2593 if((result = SISDoSense(ivideo, cvbs, 0x0804))) {
2594 printk(KERN_INFO "%s %s YPbPr component output\n", stdstr, tvstr);
2595 orSISIDXREG(SISCR,0x32,0x80);
2596 }
2597 }
2598 outSISIDXREG(SISPART2,0x4d,backupP2_4d);
2599 }
2600
2601 andSISIDXREG(SISCR, 0x32, ~0x03);
2602
2603 if(!(ivideo->vbflags & TV_YPBPR)) {
2604 if((result = SISDoSense(ivideo, svhs, svhs_c))) {
2605 printk(KERN_INFO "%s %s SVIDEO output\n", stdstr, tvstr);
2606 orSISIDXREG(SISCR, 0x32, 0x02);
2607 }
2608 if((biosflag & 0x02) || (!result)) {
2609 if(SISDoSense(ivideo, cvbs, cvbs_c)) {
2610 printk(KERN_INFO "%s %s COMPOSITE output\n", stdstr, tvstr);
2611 orSISIDXREG(SISCR, 0x32, 0x01);
2612 }
2613 }
2614 }
2615
2616 SISDoSense(ivideo, 0, 0);
2617
2618 outSISIDXREG(SISPART2,0x00,backupP2_00);
2619 outSISIDXREG(SISPART4,0x0d,backupP4_0d);
2620 outSISIDXREG(SISSR,0x1e,backupSR_1e);
2621
544393fe 2622 if(ivideo->vbflags2 & VB2_30xCLV) {
1da177e4
LT
2623 inSISIDXREG(SISPART2,0x00,biosflag);
2624 if(biosflag & 0x20) {
2625 for(myflag = 2; myflag > 0; myflag--) {
2626 biosflag ^= 0x20;
2627 outSISIDXREG(SISPART2,0x00,biosflag);
2628 }
2629 }
2630 }
2631
2632 outSISIDXREG(SISPART2,0x00,backupP2_00);
2633}
2634
2635/* Determine and detect attached TV's on Chrontel */
544393fe
TW
2636static void __devinit
2637SiS_SenseCh(struct sis_video_info *ivideo)
1da177e4
LT
2638{
2639#if defined(CONFIG_FB_SIS_300) || defined(CONFIG_FB_SIS_315)
2640 u8 temp1, temp2;
2641 char stdstr[] = "sisfb: Chrontel: Detected TV connected to";
2642#endif
2643#ifdef CONFIG_FB_SIS_300
2644 unsigned char test[3];
2645 int i;
2646#endif
2647
2648 if(ivideo->chip < SIS_315H) {
2649
2650#ifdef CONFIG_FB_SIS_300
2651 ivideo->SiS_Pr.SiS_IF_DEF_CH70xx = 1; /* Chrontel 700x */
2652 SiS_SetChrontelGPIO(&ivideo->SiS_Pr, 0x9c); /* Set general purpose IO for Chrontel communication */
2653 SiS_DDC2Delay(&ivideo->SiS_Pr, 1000);
2654 temp1 = SiS_GetCH700x(&ivideo->SiS_Pr, 0x25);
2655 /* See Chrontel TB31 for explanation */
2656 temp2 = SiS_GetCH700x(&ivideo->SiS_Pr, 0x0e);
2657 if(((temp2 & 0x07) == 0x01) || (temp2 & 0x04)) {
544393fe 2658 SiS_SetCH700x(&ivideo->SiS_Pr, 0x0e, 0x0b);
1da177e4
LT
2659 SiS_DDC2Delay(&ivideo->SiS_Pr, 300);
2660 }
2661 temp2 = SiS_GetCH700x(&ivideo->SiS_Pr, 0x25);
2662 if(temp2 != temp1) temp1 = temp2;
2663
2664 if((temp1 >= 0x22) && (temp1 <= 0x50)) {
2665 /* Read power status */
2666 temp1 = SiS_GetCH700x(&ivideo->SiS_Pr, 0x0e);
2667 if((temp1 & 0x03) != 0x03) {
544393fe
TW
2668 /* Power all outputs */
2669 SiS_SetCH700x(&ivideo->SiS_Pr, 0x0e,0x0b);
1da177e4
LT
2670 SiS_DDC2Delay(&ivideo->SiS_Pr, 300);
2671 }
2672 /* Sense connected TV devices */
2673 for(i = 0; i < 3; i++) {
544393fe 2674 SiS_SetCH700x(&ivideo->SiS_Pr, 0x10, 0x01);
1da177e4 2675 SiS_DDC2Delay(&ivideo->SiS_Pr, 0x96);
544393fe 2676 SiS_SetCH700x(&ivideo->SiS_Pr, 0x10, 0x00);
1da177e4
LT
2677 SiS_DDC2Delay(&ivideo->SiS_Pr, 0x96);
2678 temp1 = SiS_GetCH700x(&ivideo->SiS_Pr, 0x10);
2679 if(!(temp1 & 0x08)) test[i] = 0x02;
2680 else if(!(temp1 & 0x02)) test[i] = 0x01;
2681 else test[i] = 0;
2682 SiS_DDC2Delay(&ivideo->SiS_Pr, 0x96);
2683 }
2684
2685 if(test[0] == test[1]) temp1 = test[0];
2686 else if(test[0] == test[2]) temp1 = test[0];
2687 else if(test[1] == test[2]) temp1 = test[1];
2688 else {
544393fe 2689 printk(KERN_INFO
1da177e4
LT
2690 "sisfb: TV detection unreliable - test results varied\n");
2691 temp1 = test[2];
2692 }
2693 if(temp1 == 0x02) {
2694 printk(KERN_INFO "%s SVIDEO output\n", stdstr);
2695 ivideo->vbflags |= TV_SVIDEO;
2696 orSISIDXREG(SISCR, 0x32, 0x02);
2697 andSISIDXREG(SISCR, 0x32, ~0x05);
2698 } else if (temp1 == 0x01) {
2699 printk(KERN_INFO "%s CVBS output\n", stdstr);
2700 ivideo->vbflags |= TV_AVIDEO;
2701 orSISIDXREG(SISCR, 0x32, 0x01);
2702 andSISIDXREG(SISCR, 0x32, ~0x06);
2703 } else {
544393fe 2704 SiS_SetCH70xxANDOR(&ivideo->SiS_Pr, 0x0e, 0x01, 0xF8);
1da177e4
LT
2705 andSISIDXREG(SISCR, 0x32, ~0x07);
2706 }
2707 } else if(temp1 == 0) {
544393fe 2708 SiS_SetCH70xxANDOR(&ivideo->SiS_Pr, 0x0e, 0x01, 0xF8);
1da177e4
LT
2709 andSISIDXREG(SISCR, 0x32, ~0x07);
2710 }
2711 /* Set general purpose IO for Chrontel communication */
2712 SiS_SetChrontelGPIO(&ivideo->SiS_Pr, 0x00);
2713#endif
2714
2715 } else {
2716
2717#ifdef CONFIG_FB_SIS_315
2718 ivideo->SiS_Pr.SiS_IF_DEF_CH70xx = 2; /* Chrontel 7019 */
544393fe
TW
2719 temp1 = SiS_GetCH701x(&ivideo->SiS_Pr, 0x49);
2720 SiS_SetCH701x(&ivideo->SiS_Pr, 0x49, 0x20);
1da177e4
LT
2721 SiS_DDC2Delay(&ivideo->SiS_Pr, 0x96);
2722 temp2 = SiS_GetCH701x(&ivideo->SiS_Pr, 0x20);
2723 temp2 |= 0x01;
544393fe 2724 SiS_SetCH701x(&ivideo->SiS_Pr, 0x20, temp2);
1da177e4
LT
2725 SiS_DDC2Delay(&ivideo->SiS_Pr, 0x96);
2726 temp2 ^= 0x01;
544393fe 2727 SiS_SetCH701x(&ivideo->SiS_Pr, 0x20, temp2);
1da177e4
LT
2728 SiS_DDC2Delay(&ivideo->SiS_Pr, 0x96);
2729 temp2 = SiS_GetCH701x(&ivideo->SiS_Pr, 0x20);
544393fe
TW
2730 SiS_SetCH701x(&ivideo->SiS_Pr, 0x49, temp1);
2731 temp1 = 0;
1da177e4
LT
2732 if(temp2 & 0x02) temp1 |= 0x01;
2733 if(temp2 & 0x10) temp1 |= 0x01;
2734 if(temp2 & 0x04) temp1 |= 0x02;
2735 if( (temp1 & 0x01) && (temp1 & 0x02) ) temp1 = 0x04;
2736 switch(temp1) {
2737 case 0x01:
2738 printk(KERN_INFO "%s CVBS output\n", stdstr);
2739 ivideo->vbflags |= TV_AVIDEO;
2740 orSISIDXREG(SISCR, 0x32, 0x01);
2741 andSISIDXREG(SISCR, 0x32, ~0x06);
544393fe 2742 break;
1da177e4
LT
2743 case 0x02:
2744 printk(KERN_INFO "%s SVIDEO output\n", stdstr);
2745 ivideo->vbflags |= TV_SVIDEO;
2746 orSISIDXREG(SISCR, 0x32, 0x02);
2747 andSISIDXREG(SISCR, 0x32, ~0x05);
544393fe 2748 break;
1da177e4
LT
2749 case 0x04:
2750 printk(KERN_INFO "%s SCART output\n", stdstr);
2751 orSISIDXREG(SISCR, 0x32, 0x04);
2752 andSISIDXREG(SISCR, 0x32, ~0x03);
544393fe 2753 break;
1da177e4
LT
2754 default:
2755 andSISIDXREG(SISCR, 0x32, ~0x07);
2756 }
2757#endif
2758 }
2759}
2760
544393fe
TW
2761static void __devinit
2762sisfb_get_VB_type(struct sis_video_info *ivideo)
1da177e4 2763{
544393fe
TW
2764 char stdstr[] = "sisfb: Detected";
2765 char bridgestr[] = "video bridge";
2766 u8 vb_chipid;
2767 u8 reg;
1da177e4 2768
544393fe
TW
2769 /* No CRT2 on XGI Z7 */
2770 if(ivideo->chip == XGI_20)
2771 return;
1da177e4 2772
544393fe
TW
2773 inSISIDXREG(SISPART4, 0x00, vb_chipid);
2774 switch(vb_chipid) {
2775 case 0x01:
2776 inSISIDXREG(SISPART4, 0x01, reg);
2777 if(reg < 0xb0) {
2778 ivideo->vbflags |= VB_301; /* Deprecated */
2779 ivideo->vbflags2 |= VB2_301;
2780 printk(KERN_INFO "%s SiS301 %s\n", stdstr, bridgestr);
2781 } else if(reg < 0xc0) {
2782 ivideo->vbflags |= VB_301B; /* Deprecated */
2783 ivideo->vbflags2 |= VB2_301B;
2784 inSISIDXREG(SISPART4,0x23,reg);
2785 if(!(reg & 0x02)) {
2786 ivideo->vbflags |= VB_30xBDH; /* Deprecated */
2787 ivideo->vbflags2 |= VB2_30xBDH;
2788 printk(KERN_INFO "%s SiS301B-DH %s\n", stdstr, bridgestr);
2789 } else {
2790 printk(KERN_INFO "%s SiS301B %s\n", stdstr, bridgestr);
2791 }
2792 } else if(reg < 0xd0) {
2793 ivideo->vbflags |= VB_301C; /* Deprecated */
2794 ivideo->vbflags2 |= VB2_301C;
2795 printk(KERN_INFO "%s SiS301C %s\n", stdstr, bridgestr);
2796 } else if(reg < 0xe0) {
2797 ivideo->vbflags |= VB_301LV; /* Deprecated */
2798 ivideo->vbflags2 |= VB2_301LV;
2799 printk(KERN_INFO "%s SiS301LV %s\n", stdstr, bridgestr);
2800 } else if(reg <= 0xe1) {
2801 inSISIDXREG(SISPART4,0x39,reg);
2802 if(reg == 0xff) {
2803 ivideo->vbflags |= VB_302LV; /* Deprecated */
2804 ivideo->vbflags2 |= VB2_302LV;
2805 printk(KERN_INFO "%s SiS302LV %s\n", stdstr, bridgestr);
2806 } else {
2807 ivideo->vbflags |= VB_301C; /* Deprecated */
2808 ivideo->vbflags2 |= VB2_301C;
2809 printk(KERN_INFO "%s SiS301C(P4) %s\n", stdstr, bridgestr);
2810#if 0
2811 ivideo->vbflags |= VB_302ELV; /* Deprecated */
2812 ivideo->vbflags2 |= VB2_302ELV;
2813 printk(KERN_INFO "%s SiS302ELV %s\n", stdstr, bridgestr);
2814#endif
2815 }
2816 }
2817 break;
2818 case 0x02:
2819 ivideo->vbflags |= VB_302B; /* Deprecated */
2820 ivideo->vbflags2 |= VB2_302B;
2821 printk(KERN_INFO "%s SiS302B %s\n", stdstr, bridgestr);
2822 break;
1da177e4
LT
2823 }
2824
544393fe
TW
2825 if((!(ivideo->vbflags2 & VB2_VIDEOBRIDGE)) && (ivideo->chip != SIS_300)) {
2826 inSISIDXREG(SISCR, 0x37, reg);
2827 reg &= SIS_EXTERNAL_CHIP_MASK;
2828 reg >>= 1;
2829 if(ivideo->sisvga_engine == SIS_300_VGA) {
2830#ifdef CONFIG_FB_SIS_300
2831 switch(reg) {
2832 case SIS_EXTERNAL_CHIP_LVDS:
2833 ivideo->vbflags |= VB_LVDS; /* Deprecated */
2834 ivideo->vbflags2 |= VB2_LVDS;
2835 break;
2836 case SIS_EXTERNAL_CHIP_TRUMPION:
2837 ivideo->vbflags |= (VB_LVDS | VB_TRUMPION); /* Deprecated */
2838 ivideo->vbflags2 |= (VB2_LVDS | VB2_TRUMPION);
2839 break;
2840 case SIS_EXTERNAL_CHIP_CHRONTEL:
2841 ivideo->vbflags |= VB_CHRONTEL; /* Deprecated */
2842 ivideo->vbflags2 |= VB2_CHRONTEL;
2843 break;
2844 case SIS_EXTERNAL_CHIP_LVDS_CHRONTEL:
2845 ivideo->vbflags |= (VB_LVDS | VB_CHRONTEL); /* Deprecated */
2846 ivideo->vbflags2 |= (VB2_LVDS | VB2_CHRONTEL);
2847 break;
2848 }
2849 if(ivideo->vbflags2 & VB2_CHRONTEL) ivideo->chronteltype = 1;
2850#endif
2851 } else if(ivideo->chip < SIS_661) {
2852#ifdef CONFIG_FB_SIS_315
2853 switch (reg) {
2854 case SIS310_EXTERNAL_CHIP_LVDS:
2855 ivideo->vbflags |= VB_LVDS; /* Deprecated */
2856 ivideo->vbflags2 |= VB2_LVDS;
2857 break;
2858 case SIS310_EXTERNAL_CHIP_LVDS_CHRONTEL:
2859 ivideo->vbflags |= (VB_LVDS | VB_CHRONTEL); /* Deprecated */
2860 ivideo->vbflags2 |= (VB2_LVDS | VB2_CHRONTEL);
2861 break;
2862 }
2863 if(ivideo->vbflags2 & VB2_CHRONTEL) ivideo->chronteltype = 2;
2864#endif
2865 } else if(ivideo->chip >= SIS_661) {
2866#ifdef CONFIG_FB_SIS_315
2867 inSISIDXREG(SISCR, 0x38, reg);
2868 reg >>= 5;
2869 switch(reg) {
2870 case 0x02:
2871 ivideo->vbflags |= VB_LVDS; /* Deprecated */
2872 ivideo->vbflags2 |= VB2_LVDS;
2873 break;
2874 case 0x03:
2875 ivideo->vbflags |= (VB_LVDS | VB_CHRONTEL); /* Deprecated */
2876 ivideo->vbflags2 |= (VB2_LVDS | VB2_CHRONTEL);
2877 break;
2878 case 0x04:
2879 ivideo->vbflags |= (VB_LVDS | VB_CONEXANT); /* Deprecated */
2880 ivideo->vbflags2 |= (VB2_LVDS | VB2_CONEXANT);
2881 break;
2882 }
2883 if(ivideo->vbflags2 & VB2_CHRONTEL) ivideo->chronteltype = 2;
2884#endif
2885 }
2886 if(ivideo->vbflags2 & VB2_LVDS) {
2887 printk(KERN_INFO "%s LVDS transmitter\n", stdstr);
2888 }
2889 if((ivideo->sisvga_engine == SIS_300_VGA) && (ivideo->vbflags2 & VB2_TRUMPION)) {
2890 printk(KERN_INFO "%s Trumpion Zurac LCD scaler\n", stdstr);
2891 }
2892 if(ivideo->vbflags2 & VB2_CHRONTEL) {
2893 printk(KERN_INFO "%s Chrontel TV encoder\n", stdstr);
2894 }
2895 if((ivideo->chip >= SIS_661) && (ivideo->vbflags2 & VB2_CONEXANT)) {
2896 printk(KERN_INFO "%s Conexant external device\n", stdstr);
2897 }
2898 }
2899
2900 if(ivideo->vbflags2 & VB2_SISBRIDGE) {
2901 SiS_SenseLCD(ivideo);
2902 SiS_Sense30x(ivideo);
2903 } else if(ivideo->vbflags2 & VB2_CHRONTEL) {
2904 SiS_SenseCh(ivideo);
2905 }
2906}
2907
2908/* ---------- Engine initialization routines ------------ */
2909
2910static void
2911sisfb_engine_init(struct sis_video_info *ivideo)
1da177e4 2912{
1da177e4 2913
544393fe 2914 /* Initialize command queue (we use MMIO only) */
1da177e4 2915
544393fe 2916 /* BEFORE THIS IS CALLED, THE ENGINES *MUST* BE SYNC'ED */
1da177e4 2917
544393fe
TW
2918 ivideo->caps &= ~(TURBO_QUEUE_CAP |
2919 MMIO_CMD_QUEUE_CAP |
2920 VM_CMD_QUEUE_CAP |
2921 AGP_CMD_QUEUE_CAP);
2922
2923#ifdef CONFIG_FB_SIS_300
2924 if(ivideo->sisvga_engine == SIS_300_VGA) {
2925 u32 tqueue_pos;
2926 u8 tq_state;
2927
2928 tqueue_pos = (ivideo->video_size - ivideo->cmdQueueSize) / (64 * 1024);
2929
2930 inSISIDXREG(SISSR, IND_SIS_TURBOQUEUE_SET, tq_state);
2931 tq_state |= 0xf0;
2932 tq_state &= 0xfc;
2933 tq_state |= (u8)(tqueue_pos >> 8);
2934 outSISIDXREG(SISSR, IND_SIS_TURBOQUEUE_SET, tq_state);
2935
2936 outSISIDXREG(SISSR, IND_SIS_TURBOQUEUE_ADR, (u8)(tqueue_pos & 0xff));
2937
2938 ivideo->caps |= TURBO_QUEUE_CAP;
2939 }
2940#endif
1da177e4
LT
2941
2942#ifdef CONFIG_FB_SIS_315
544393fe
TW
2943 if(ivideo->sisvga_engine == SIS_315_VGA) {
2944 u32 tempq = 0, templ;
2945 u8 temp;
2946
2947 if(ivideo->chip == XGI_20) {
2948 switch(ivideo->cmdQueueSize) {
2949 case (64 * 1024):
2950 temp = SIS_CMD_QUEUE_SIZE_Z7_64k;
2951 break;
2952 case (128 * 1024):
2953 default:
2954 temp = SIS_CMD_QUEUE_SIZE_Z7_128k;
2955 }
2956 } else {
2957 switch(ivideo->cmdQueueSize) {
2958 case (4 * 1024 * 1024):
2959 temp = SIS_CMD_QUEUE_SIZE_4M;
2960 break;
2961 case (2 * 1024 * 1024):
2962 temp = SIS_CMD_QUEUE_SIZE_2M;
2963 break;
2964 case (1 * 1024 * 1024):
2965 temp = SIS_CMD_QUEUE_SIZE_1M;
2966 break;
2967 default:
2968 case (512 * 1024):
2969 temp = SIS_CMD_QUEUE_SIZE_512k;
2970 }
2971 }
2972
2973 outSISIDXREG(SISSR, IND_SIS_CMDQUEUE_THRESHOLD, COMMAND_QUEUE_THRESHOLD);
2974 outSISIDXREG(SISSR, IND_SIS_CMDQUEUE_SET, SIS_CMD_QUEUE_RESET);
2975
2976 if((ivideo->chip >= XGI_40) && ivideo->modechanged) {
2977 /* Must disable dual pipe on XGI_40. Can't do
2978 * this in MMIO mode, because it requires
2979 * setting/clearing a bit in the MMIO fire trigger
2980 * register.
2981 */
2982 if(!((templ = MMIO_IN32(ivideo->mmio_vbase, 0x8240)) & (1 << 10))) {
2983
2984 MMIO_OUT32(ivideo->mmio_vbase, Q_WRITE_PTR, 0);
2985
2986 outSISIDXREG(SISSR, IND_SIS_CMDQUEUE_SET, (temp | SIS_VRAM_CMDQUEUE_ENABLE));
2987
2988 tempq = MMIO_IN32(ivideo->mmio_vbase, Q_READ_PTR);
2989 MMIO_OUT32(ivideo->mmio_vbase, Q_WRITE_PTR, tempq);
1da177e4 2990
544393fe
TW
2991 tempq = (u32)(ivideo->video_size - ivideo->cmdQueueSize);
2992 MMIO_OUT32(ivideo->mmio_vbase, Q_BASE_ADDR, tempq);
1da177e4 2993
544393fe
TW
2994 writel(0x16800000 + 0x8240, ivideo->video_vbase + tempq);
2995 writel(templ | (1 << 10), ivideo->video_vbase + tempq + 4);
2996 writel(0x168F0000, ivideo->video_vbase + tempq + 8);
2997 writel(0x168F0000, ivideo->video_vbase + tempq + 12);
2998
2999 MMIO_OUT32(ivideo->mmio_vbase, Q_WRITE_PTR, (tempq + 16));
3000
3001 sisfb_syncaccel(ivideo);
3002
3003 outSISIDXREG(SISSR, IND_SIS_CMDQUEUE_SET, SIS_CMD_QUEUE_RESET);
3004
3005 }
3006 }
3007
3008 tempq = MMIO_IN32(ivideo->mmio_vbase, MMIO_QUEUE_READPORT);
3009 MMIO_OUT32(ivideo->mmio_vbase, MMIO_QUEUE_WRITEPORT, tempq);
3010
3011 temp |= (SIS_MMIO_CMD_ENABLE | SIS_CMD_AUTO_CORR);
3012 outSISIDXREG(SISSR, IND_SIS_CMDQUEUE_SET, temp);
3013
3014 tempq = (u32)(ivideo->video_size - ivideo->cmdQueueSize);
3015 MMIO_OUT32(ivideo->mmio_vbase, MMIO_QUEUE_PHYBASE, tempq);
3016
3017 ivideo->caps |= MMIO_CMD_QUEUE_CAP;
3018 }
3019#endif
3020
3021 ivideo->engineok = 1;
3022}
3023
3024static void __devinit
3025sisfb_detect_lcd_type(struct sis_video_info *ivideo)
3026{
3027 u8 reg;
3028 int i;
1da177e4 3029
544393fe
TW
3030 inSISIDXREG(SISCR, 0x36, reg);
3031 reg &= 0x0f;
3032 if(ivideo->sisvga_engine == SIS_300_VGA) {
3033 ivideo->CRT2LCDType = sis300paneltype[reg];
3034 } else if(ivideo->chip >= SIS_661) {
3035 ivideo->CRT2LCDType = sis661paneltype[reg];
3036 } else {
3037 ivideo->CRT2LCDType = sis310paneltype[reg];
3038 if((ivideo->chip == SIS_550) && (sisfb_fstn)) {
3039 if((ivideo->CRT2LCDType != LCD_320x240_2) &&
3040 (ivideo->CRT2LCDType != LCD_320x240_3)) {
3041 ivideo->CRT2LCDType = LCD_320x240;
3042 }
3043 }
3044 }
1da177e4 3045
544393fe
TW
3046 if(ivideo->CRT2LCDType == LCD_UNKNOWN) {
3047 /* For broken BIOSes: Assume 1024x768, RGB18 */
3048 ivideo->CRT2LCDType = LCD_1024x768;
3049 setSISIDXREG(SISCR,0x36,0xf0,0x02);
3050 setSISIDXREG(SISCR,0x37,0xee,0x01);
3051 printk(KERN_DEBUG "sisfb: Invalid panel ID (%02x), assuming 1024x768, RGB18\n", reg);
3052 }
1da177e4 3053
544393fe
TW
3054 for(i = 0; i < SIS_LCD_NUMBER; i++) {
3055 if(ivideo->CRT2LCDType == sis_lcd_data[i].lcdtype) {
3056 ivideo->lcdxres = sis_lcd_data[i].xres;
3057 ivideo->lcdyres = sis_lcd_data[i].yres;
3058 ivideo->lcddefmodeidx = sis_lcd_data[i].default_mode_idx;
3059 break;
3060 }
3061 }
1da177e4 3062
544393fe
TW
3063#ifdef CONFIG_FB_SIS_300
3064 if(ivideo->SiS_Pr.SiS_CustomT == CUT_BARCO1366) {
3065 ivideo->lcdxres = 1360; ivideo->lcdyres = 1024;
3066 ivideo->lcddefmodeidx = DEFAULT_MODE_1360;
3067 } else if(ivideo->SiS_Pr.SiS_CustomT == CUT_PANEL848) {
3068 ivideo->lcdxres = 848; ivideo->lcdyres = 480;
3069 ivideo->lcddefmodeidx = DEFAULT_MODE_848;
3070 } else if(ivideo->SiS_Pr.SiS_CustomT == CUT_PANEL856) {
3071 ivideo->lcdxres = 856; ivideo->lcdyres = 480;
3072 ivideo->lcddefmodeidx = DEFAULT_MODE_856;
3073 }
1da177e4
LT
3074#endif
3075
544393fe
TW
3076 printk(KERN_DEBUG "sisfb: Detected %dx%d flat panel\n",
3077 ivideo->lcdxres, ivideo->lcdyres);
3078}
3079
3080static void __devinit
3081sisfb_save_pdc_emi(struct sis_video_info *ivideo)
3082{
1da177e4 3083#ifdef CONFIG_FB_SIS_300
544393fe
TW
3084 /* Save the current PanelDelayCompensation if the LCD is currently used */
3085 if(ivideo->sisvga_engine == SIS_300_VGA) {
3086 if(ivideo->vbflags2 & (VB2_LVDS | VB2_30xBDH)) {
3087 int tmp;
3088 inSISIDXREG(SISCR,0x30,tmp);
3089 if(tmp & 0x20) {
3090 /* Currently on LCD? If yes, read current pdc */
3091 inSISIDXREG(SISPART1,0x13,ivideo->detectedpdc);
3092 ivideo->detectedpdc &= 0x3c;
3093 if(ivideo->SiS_Pr.PDC == -1) {
3094 /* Let option override detection */
3095 ivideo->SiS_Pr.PDC = ivideo->detectedpdc;
3096 }
3097 printk(KERN_INFO "sisfb: Detected LCD PDC 0x%02x\n",
3098 ivideo->detectedpdc);
3099 }
3100 if((ivideo->SiS_Pr.PDC != -1) &&
3101 (ivideo->SiS_Pr.PDC != ivideo->detectedpdc)) {
3102 printk(KERN_INFO "sisfb: Using LCD PDC 0x%02x\n",
3103 ivideo->SiS_Pr.PDC);
3104 }
3105 }
3106 }
3107#endif
3108
3109#ifdef CONFIG_FB_SIS_315
3110 if(ivideo->sisvga_engine == SIS_315_VGA) {
1da177e4 3111
544393fe
TW
3112 /* Try to find about LCDA */
3113 if(ivideo->vbflags2 & VB2_SISLCDABRIDGE) {
3114 int tmp;
3115 inSISIDXREG(SISPART1,0x13,tmp);
3116 if(tmp & 0x04) {
3117 ivideo->SiS_Pr.SiS_UseLCDA = TRUE;
3118 ivideo->detectedlcda = 0x03;
3119 }
3120 }
1da177e4 3121
544393fe
TW
3122 /* Save PDC */
3123 if(ivideo->vbflags2 & VB2_SISLVDSBRIDGE) {
3124 int tmp;
3125 inSISIDXREG(SISCR,0x30,tmp);
3126 if((tmp & 0x20) || (ivideo->detectedlcda != 0xff)) {
3127 /* Currently on LCD? If yes, read current pdc */
3128 u8 pdc;
3129 inSISIDXREG(SISPART1,0x2D,pdc);
3130 ivideo->detectedpdc = (pdc & 0x0f) << 1;
3131 ivideo->detectedpdca = (pdc & 0xf0) >> 3;
3132 inSISIDXREG(SISPART1,0x35,pdc);
3133 ivideo->detectedpdc |= ((pdc >> 7) & 0x01);
3134 inSISIDXREG(SISPART1,0x20,pdc);
3135 ivideo->detectedpdca |= ((pdc >> 6) & 0x01);
3136 if(ivideo->newrom) {
3137 /* New ROM invalidates other PDC resp. */
3138 if(ivideo->detectedlcda != 0xff) {
3139 ivideo->detectedpdc = 0xff;
3140 } else {
3141 ivideo->detectedpdca = 0xff;
3142 }
3143 }
3144 if(ivideo->SiS_Pr.PDC == -1) {
3145 if(ivideo->detectedpdc != 0xff) {
3146 ivideo->SiS_Pr.PDC = ivideo->detectedpdc;
3147 }
3148 }
3149 if(ivideo->SiS_Pr.PDCA == -1) {
3150 if(ivideo->detectedpdca != 0xff) {
3151 ivideo->SiS_Pr.PDCA = ivideo->detectedpdca;
3152 }
3153 }
3154 if(ivideo->detectedpdc != 0xff) {
3155 printk(KERN_INFO
3156 "sisfb: Detected LCD PDC 0x%02x (for LCD=CRT2)\n",
3157 ivideo->detectedpdc);
3158 }
3159 if(ivideo->detectedpdca != 0xff) {
3160 printk(KERN_INFO
3161 "sisfb: Detected LCD PDC1 0x%02x (for LCD=CRT1)\n",
3162 ivideo->detectedpdca);
3163 }
3164 }
1da177e4 3165
544393fe
TW
3166 /* Save EMI */
3167 if(ivideo->vbflags2 & VB2_SISEMIBRIDGE) {
3168 inSISIDXREG(SISPART4,0x30,ivideo->SiS_Pr.EMI_30);
3169 inSISIDXREG(SISPART4,0x31,ivideo->SiS_Pr.EMI_31);
3170 inSISIDXREG(SISPART4,0x32,ivideo->SiS_Pr.EMI_32);
3171 inSISIDXREG(SISPART4,0x33,ivideo->SiS_Pr.EMI_33);
3172 ivideo->SiS_Pr.HaveEMI = TRUE;
3173 if((tmp & 0x20) || (ivideo->detectedlcda != 0xff)) {
3174 ivideo->SiS_Pr.HaveEMILCD = TRUE;
3175 }
3176 }
3177 }
1da177e4 3178
544393fe
TW
3179 /* Let user override detected PDCs (all bridges) */
3180 if(ivideo->vbflags2 & VB2_30xBLV) {
3181 if((ivideo->SiS_Pr.PDC != -1) &&
3182 (ivideo->SiS_Pr.PDC != ivideo->detectedpdc)) {
3183 printk(KERN_INFO "sisfb: Using LCD PDC 0x%02x (for LCD=CRT2)\n",
3184 ivideo->SiS_Pr.PDC);
3185 }
3186 if((ivideo->SiS_Pr.PDCA != -1) &&
3187 (ivideo->SiS_Pr.PDCA != ivideo->detectedpdca)) {
3188 printk(KERN_INFO "sisfb: Using LCD PDC1 0x%02x (for LCD=CRT1)\n",
3189 ivideo->SiS_Pr.PDCA);
3190 }
3191 }
1da177e4 3192
544393fe 3193 }
1da177e4 3194#endif
544393fe
TW
3195}
3196
3197/* -------------------- Memory manager routines ---------------------- */
3198
3199static u32 __devinit
3200sisfb_getheapstart(struct sis_video_info *ivideo)
3201{
3202 u32 ret = ivideo->sisfb_parm_mem * 1024;
3203 u32 maxoffs = ivideo->video_size - ivideo->hwcursor_size - ivideo->cmdQueueSize;
3204 u32 def;
3205
3206 /* Calculate heap start = end of memory for console
3207 *
3208 * CCCCCCCCDDDDDDDDDDDDDDDDDDDDDDDDDDDDHHHHQQQQQQQQQQ
3209 * C = console, D = heap, H = HWCursor, Q = cmd-queue
3210 *
3211 * On 76x in UMA+LFB mode, the layout is as follows:
3212 * DDDDDDDDDDDCCCCCCCCCCCCCCCCCCCCCCCCHHHHQQQQQQQQQQQ
3213 * where the heap is the entire UMA area, eventually
3214 * into the LFB area if the given mem parameter is
3215 * higher than the size of the UMA memory.
3216 *
3217 * Basically given by "mem" parameter
3218 *
3219 * maximum = videosize - cmd_queue - hwcursor
3220 * (results in a heap of size 0)
3221 * default = SiS 300: depends on videosize
3222 * SiS 315/330/340/XGI: 32k below max
3223 */
3224
3225 if(ivideo->sisvga_engine == SIS_300_VGA) {
3226 if(ivideo->video_size > 0x1000000) {
3227 def = 0xc00000;
3228 } else if(ivideo->video_size > 0x800000) {
3229 def = 0x800000;
3230 } else {
3231 def = 0x400000;
3232 }
3233 } else if(ivideo->UMAsize && ivideo->LFBsize) {
3234 ret = def = 0;
3235 } else {
3236 def = maxoffs - 0x8000;
3237 }
3238
3239 /* Use default for secondary card for now (FIXME) */
3240 if((!ret) || (ret > maxoffs) || (ivideo->cardnumber != 0))
3241 ret = def;
3242
3243 return ret;
3244}
3245
3246static u32 __devinit
3247sisfb_getheapsize(struct sis_video_info *ivideo)
3248{
3249 u32 max = ivideo->video_size - ivideo->hwcursor_size - ivideo->cmdQueueSize;
3250 u32 ret = 0;
3251
3252 if(ivideo->UMAsize && ivideo->LFBsize) {
3253 if( (!ivideo->sisfb_parm_mem) ||
3254 ((ivideo->sisfb_parm_mem * 1024) > max) ||
3255 ((max - (ivideo->sisfb_parm_mem * 1024)) < ivideo->UMAsize) ) {
3256 ret = ivideo->UMAsize;
3257 max -= ivideo->UMAsize;
3258 } else {
3259 ret = max - (ivideo->sisfb_parm_mem * 1024);
3260 max = ivideo->sisfb_parm_mem * 1024;
3261 }
3262 ivideo->video_offset = ret;
3263 ivideo->sisfb_mem = max;
3264 } else {
3265 ret = max - ivideo->heapstart;
3266 ivideo->sisfb_mem = ivideo->heapstart;
3267 }
1da177e4 3268
544393fe
TW
3269 return ret;
3270}
1da177e4 3271
544393fe
TW
3272static int __devinit
3273sisfb_heap_init(struct sis_video_info *ivideo)
3274{
3275 struct SIS_OH *poh;
1da177e4 3276
544393fe
TW
3277 ivideo->video_offset = 0;
3278 if(ivideo->sisfb_parm_mem) {
3279 if( (ivideo->sisfb_parm_mem < (2 * 1024 * 1024)) ||
3280 (ivideo->sisfb_parm_mem > ivideo->video_size) ) {
3281 ivideo->sisfb_parm_mem = 0;
3282 }
3283 }
1da177e4 3284
544393fe
TW
3285 ivideo->heapstart = sisfb_getheapstart(ivideo);
3286 ivideo->sisfb_heap_size = sisfb_getheapsize(ivideo);
1da177e4 3287
544393fe
TW
3288 ivideo->sisfb_heap_start = ivideo->video_vbase + ivideo->heapstart;
3289 ivideo->sisfb_heap_end = ivideo->sisfb_heap_start + ivideo->sisfb_heap_size;
1da177e4 3290
544393fe
TW
3291 printk(KERN_INFO "sisfb: Memory heap starting at %dK, size %dK\n",
3292 (int)(ivideo->heapstart / 1024), (int)(ivideo->sisfb_heap_size / 1024));
1da177e4 3293
544393fe 3294 ivideo->sisfb_heap.vinfo = ivideo;
1da177e4 3295
544393fe
TW
3296 ivideo->sisfb_heap.poha_chain = NULL;
3297 ivideo->sisfb_heap.poh_freelist = NULL;
1da177e4 3298
544393fe
TW
3299 poh = sisfb_poh_new_node(&ivideo->sisfb_heap);
3300 if(poh == NULL)
3301 return 1;
1da177e4 3302
544393fe
TW
3303 poh->poh_next = &ivideo->sisfb_heap.oh_free;
3304 poh->poh_prev = &ivideo->sisfb_heap.oh_free;
3305 poh->size = ivideo->sisfb_heap_size;
3306 poh->offset = ivideo->heapstart;
1da177e4 3307
544393fe
TW
3308 ivideo->sisfb_heap.oh_free.poh_next = poh;
3309 ivideo->sisfb_heap.oh_free.poh_prev = poh;
3310 ivideo->sisfb_heap.oh_free.size = 0;
3311 ivideo->sisfb_heap.max_freesize = poh->size;
1da177e4 3312
544393fe
TW
3313 ivideo->sisfb_heap.oh_used.poh_next = &ivideo->sisfb_heap.oh_used;
3314 ivideo->sisfb_heap.oh_used.poh_prev = &ivideo->sisfb_heap.oh_used;
3315 ivideo->sisfb_heap.oh_used.size = SENTINEL;
1da177e4 3316
544393fe
TW
3317 if(ivideo->cardnumber == 0) {
3318 /* For the first card, make this heap the "global" one
3319 * for old DRM (which could handle only one card)
3320 */
3321 sisfb_heap = &ivideo->sisfb_heap;
3322 }
1da177e4 3323
544393fe 3324 return 0;
1da177e4
LT
3325}
3326
544393fe
TW
3327static struct SIS_OH *
3328sisfb_poh_new_node(struct SIS_HEAP *memheap)
1da177e4 3329{
544393fe
TW
3330 struct SIS_OHALLOC *poha;
3331 struct SIS_OH *poh;
3332 unsigned long cOhs;
3333 int i;
1da177e4 3334
544393fe 3335 if(memheap->poh_freelist == NULL) {
1da177e4 3336 poha = kmalloc(SIS_OH_ALLOC_SIZE, GFP_KERNEL);
544393fe
TW
3337 if(!poha)
3338 return NULL;
1da177e4 3339
544393fe
TW
3340 poha->poha_next = memheap->poha_chain;
3341 memheap->poha_chain = poha;
1da177e4 3342
544393fe 3343 cOhs = (SIS_OH_ALLOC_SIZE - sizeof(struct SIS_OHALLOC)) / sizeof(struct SIS_OH) + 1;
1da177e4
LT
3344
3345 poh = &poha->aoh[0];
3346 for(i = cOhs - 1; i != 0; i--) {
3347 poh->poh_next = poh + 1;
3348 poh = poh + 1;
3349 }
3350
3351 poh->poh_next = NULL;
544393fe 3352 memheap->poh_freelist = &poha->aoh[0];
1da177e4
LT
3353 }
3354
544393fe
TW
3355 poh = memheap->poh_freelist;
3356 memheap->poh_freelist = poh->poh_next;
1da177e4 3357
544393fe 3358 return poh;
1da177e4
LT
3359}
3360
544393fe
TW
3361static struct SIS_OH *
3362sisfb_poh_allocate(struct SIS_HEAP *memheap, u32 size)
1da177e4 3363{
544393fe
TW
3364 struct SIS_OH *pohThis;
3365 struct SIS_OH *pohRoot;
3366 int bAllocated = 0;
1da177e4 3367
544393fe 3368 if(size > memheap->max_freesize) {
1da177e4
LT
3369 DPRINTK("sisfb: Can't allocate %dk video memory\n",
3370 (unsigned int) size / 1024);
544393fe 3371 return NULL;
1da177e4
LT
3372 }
3373
544393fe 3374 pohThis = memheap->oh_free.poh_next;
1da177e4 3375
544393fe
TW
3376 while(pohThis != &memheap->oh_free) {
3377 if(size <= pohThis->size) {
1da177e4
LT
3378 bAllocated = 1;
3379 break;
3380 }
3381 pohThis = pohThis->poh_next;
3382 }
3383
3384 if(!bAllocated) {
3385 DPRINTK("sisfb: Can't allocate %dk video memory\n",
3386 (unsigned int) size / 1024);
544393fe 3387 return NULL;
1da177e4
LT
3388 }
3389
3390 if(size == pohThis->size) {
3391 pohRoot = pohThis;
3392 sisfb_delete_node(pohThis);
3393 } else {
544393fe
TW
3394 pohRoot = sisfb_poh_new_node(memheap);
3395 if(pohRoot == NULL)
3396 return NULL;
1da177e4
LT
3397
3398 pohRoot->offset = pohThis->offset;
3399 pohRoot->size = size;
3400
3401 pohThis->offset += size;
3402 pohThis->size -= size;
3403 }
3404
544393fe 3405 memheap->max_freesize -= size;
1da177e4 3406
544393fe 3407 pohThis = &memheap->oh_used;
1da177e4
LT
3408 sisfb_insert_node(pohThis, pohRoot);
3409
544393fe 3410 return pohRoot;
1da177e4
LT
3411}
3412
3413static void
544393fe 3414sisfb_delete_node(struct SIS_OH *poh)
1da177e4 3415{
544393fe
TW
3416 poh->poh_prev->poh_next = poh->poh_next;
3417 poh->poh_next->poh_prev = poh->poh_prev;
1da177e4
LT
3418}
3419
3420static void
544393fe 3421sisfb_insert_node(struct SIS_OH *pohList, struct SIS_OH *poh)
1da177e4 3422{
544393fe 3423 struct SIS_OH *pohTemp = pohList->poh_next;
1da177e4
LT
3424
3425 pohList->poh_next = poh;
3426 pohTemp->poh_prev = poh;
3427
3428 poh->poh_prev = pohList;
3429 poh->poh_next = pohTemp;
3430}
3431
544393fe
TW
3432static struct SIS_OH *
3433sisfb_poh_free(struct SIS_HEAP *memheap, u32 base)
1da177e4 3434{
544393fe
TW
3435 struct SIS_OH *pohThis;
3436 struct SIS_OH *poh_freed;
3437 struct SIS_OH *poh_prev;
3438 struct SIS_OH *poh_next;
3439 u32 ulUpper;
3440 u32 ulLower;
3441 int foundNode = 0;
1da177e4 3442
544393fe 3443 poh_freed = memheap->oh_used.poh_next;
1da177e4 3444
544393fe 3445 while(poh_freed != &memheap->oh_used) {
1da177e4
LT
3446 if(poh_freed->offset == base) {
3447 foundNode = 1;
3448 break;
3449 }
3450
3451 poh_freed = poh_freed->poh_next;
3452 }
3453
544393fe
TW
3454 if(!foundNode)
3455 return NULL;
1da177e4 3456
544393fe 3457 memheap->max_freesize += poh_freed->size;
1da177e4
LT
3458
3459 poh_prev = poh_next = NULL;
3460 ulUpper = poh_freed->offset + poh_freed->size;
3461 ulLower = poh_freed->offset;
3462
544393fe 3463 pohThis = memheap->oh_free.poh_next;
1da177e4 3464
544393fe 3465 while(pohThis != &memheap->oh_free) {
1da177e4
LT
3466 if(pohThis->offset == ulUpper) {
3467 poh_next = pohThis;
3468 } else if((pohThis->offset + pohThis->size) == ulLower) {
3469 poh_prev = pohThis;
3470 }
3471 pohThis = pohThis->poh_next;
3472 }
3473
3474 sisfb_delete_node(poh_freed);
3475
3476 if(poh_prev && poh_next) {
3477 poh_prev->size += (poh_freed->size + poh_next->size);
3478 sisfb_delete_node(poh_next);
544393fe
TW
3479 sisfb_free_node(memheap, poh_freed);
3480 sisfb_free_node(memheap, poh_next);
3481 return poh_prev;
1da177e4
LT
3482 }
3483
3484 if(poh_prev) {
3485 poh_prev->size += poh_freed->size;
544393fe
TW
3486 sisfb_free_node(memheap, poh_freed);
3487 return poh_prev;
1da177e4
LT
3488 }
3489
3490 if(poh_next) {
3491 poh_next->size += poh_freed->size;
3492 poh_next->offset = poh_freed->offset;
544393fe
TW
3493 sisfb_free_node(memheap, poh_freed);
3494 return poh_next;
1da177e4
LT
3495 }
3496
544393fe 3497 sisfb_insert_node(&memheap->oh_free, poh_freed);
1da177e4 3498
544393fe 3499 return poh_freed;
1da177e4
LT
3500}
3501
3502static void
544393fe 3503sisfb_free_node(struct SIS_HEAP *memheap, struct SIS_OH *poh)
1da177e4 3504{
544393fe
TW
3505 if(poh == NULL)
3506 return;
1da177e4 3507
544393fe
TW
3508 poh->poh_next = memheap->poh_freelist;
3509 memheap->poh_freelist = poh;
1da177e4
LT
3510}
3511
544393fe
TW
3512static void
3513sis_int_malloc(struct sis_video_info *ivideo, struct sis_memreq *req)
1da177e4 3514{
544393fe 3515 struct SIS_OH *poh = NULL;
1da177e4 3516
544393fe
TW
3517 if((ivideo) && (ivideo->sisfb_id == SISFB_ID) && (!ivideo->havenoheap))
3518 poh = sisfb_poh_allocate(&ivideo->sisfb_heap, (u32)req->size);
1da177e4
LT
3519
3520 if(poh == NULL) {
544393fe
TW
3521 req->offset = req->size = 0;
3522 DPRINTK("sisfb: Video RAM allocation failed\n");
1da177e4 3523 } else {
544393fe
TW
3524 req->offset = poh->offset;
3525 req->size = poh->size;
3526 DPRINTK("sisfb: Video RAM allocation succeeded: 0x%lx\n",
3527 (poh->offset + ivideo->video_vbase));
1da177e4
LT
3528 }
3529}
3530
544393fe
TW
3531void
3532sis_malloc(struct sis_memreq *req)
3533{
3534 struct sis_video_info *ivideo = sisfb_heap->vinfo;
3535
3536 if(&ivideo->sisfb_heap == sisfb_heap)
3537 sis_int_malloc(ivideo, req);
3538 else
3539 req->offset = req->size = 0;
3540}
1da177e4
LT
3541
3542void
544393fe
TW
3543sis_malloc_new(struct pci_dev *pdev, struct sis_memreq *req)
3544{
3545 struct sis_video_info *ivideo = pci_get_drvdata(pdev);
3546
3547 sis_int_malloc(ivideo, req);
3548}
3549
3550/* sis_free: u32 because "base" is offset inside video ram, can never be >4GB */
3551
3552static void
3553sis_int_free(struct sis_video_info *ivideo, u32 base)
1da177e4 3554{
544393fe 3555 struct SIS_OH *poh;
1da177e4 3556
544393fe
TW
3557 if((!ivideo) || (ivideo->sisfb_id != SISFB_ID) || (ivideo->havenoheap))
3558 return;
1da177e4 3559
544393fe 3560 poh = sisfb_poh_free(&ivideo->sisfb_heap, base);
1da177e4
LT
3561
3562 if(poh == NULL) {
3563 DPRINTK("sisfb: sisfb_poh_free() failed at base 0x%x\n",
3564 (unsigned int) base);
3565 }
3566}
3567
544393fe
TW
3568void
3569sis_free(u32 base)
3570{
3571 struct sis_video_info *ivideo = sisfb_heap->vinfo;
3572
3573 sis_int_free(ivideo, base);
3574}
3575
3576void
3577sis_free_new(struct pci_dev *pdev, u32 base)
3578{
3579 struct sis_video_info *ivideo = pci_get_drvdata(pdev);
3580
3581 sis_int_free(ivideo, base);
3582}
3583
1da177e4
LT
3584/* --------------------- SetMode routines ------------------------- */
3585
544393fe
TW
3586static void
3587sisfb_check_engine_and_sync(struct sis_video_info *ivideo)
3588{
3589 u8 cr30, cr31;
3590
3591 /* Check if MMIO and engines are enabled,
3592 * and sync in case they are. Can't use
3593 * ivideo->accel here, as this might have
3594 * been changed before this is called.
3595 */
3596 inSISIDXREG(SISSR, IND_SIS_PCI_ADDRESS_SET, cr30);
3597 inSISIDXREG(SISSR, IND_SIS_MODULE_ENABLE, cr31);
3598 /* MMIO and 2D/3D engine enabled? */
3599 if((cr30 & SIS_MEM_MAP_IO_ENABLE) && (cr31 & 0x42)) {
3600#ifdef CONFIG_FB_SIS_300
3601 if(ivideo->sisvga_engine == SIS_300_VGA) {
3602 /* Don't care about TurboQueue. It's
3603 * enough to know that the engines
3604 * are enabled
3605 */
3606 sisfb_syncaccel(ivideo);
3607 }
3608#endif
3609#ifdef CONFIG_FB_SIS_315
3610 if(ivideo->sisvga_engine == SIS_315_VGA) {
3611 /* Check that any queue mode is
3612 * enabled, and that the queue
3613 * is not in the state of "reset"
3614 */
3615 inSISIDXREG(SISSR, 0x26, cr30);
3616 if((cr30 & 0xe0) && (!(cr30 & 0x01))) {
3617 sisfb_syncaccel(ivideo);
3618 }
3619 }
3620#endif
3621 }
3622}
3623
1da177e4
LT
3624static void
3625sisfb_pre_setmode(struct sis_video_info *ivideo)
3626{
3627 u8 cr30 = 0, cr31 = 0, cr33 = 0, cr35 = 0, cr38 = 0;
3628 int tvregnum = 0;
3629
3630 ivideo->currentvbflags &= (VB_VIDEOBRIDGE | VB_DISPTYPE_DISP2);
3631
544393fe
TW
3632 outSISIDXREG(SISSR, 0x05, 0x86);
3633
1da177e4
LT
3634 inSISIDXREG(SISCR, 0x31, cr31);
3635 cr31 &= ~0x60;
3636 cr31 |= 0x04;
3637
3638 cr33 = ivideo->rate_idx & 0x0F;
3639
3640#ifdef CONFIG_FB_SIS_315
3641 if(ivideo->sisvga_engine == SIS_315_VGA) {
3642 if(ivideo->chip >= SIS_661) {
3643 inSISIDXREG(SISCR, 0x38, cr38);
3644 cr38 &= ~0x07; /* Clear LCDA/DualEdge and YPbPr bits */
3645 } else {
3646 tvregnum = 0x38;
3647 inSISIDXREG(SISCR, tvregnum, cr38);
3648 cr38 &= ~0x3b; /* Clear LCDA/DualEdge and YPbPr bits */
3649 }
3650 }
3651#endif
3652#ifdef CONFIG_FB_SIS_300
3653 if(ivideo->sisvga_engine == SIS_300_VGA) {
3654 tvregnum = 0x35;
3655 inSISIDXREG(SISCR, tvregnum, cr38);
3656 }
3657#endif
3658
3659 SiS_SetEnableDstn(&ivideo->SiS_Pr, FALSE);
3660 SiS_SetEnableFstn(&ivideo->SiS_Pr, FALSE);
544393fe 3661 ivideo->curFSTN = ivideo->curDSTN = 0;
1da177e4
LT
3662
3663 switch(ivideo->currentvbflags & VB_DISPTYPE_DISP2) {
3664
3665 case CRT2_TV:
3666 cr38 &= ~0xc0; /* Clear PAL-M / PAL-N bits */
544393fe 3667 if((ivideo->vbflags & TV_YPBPR) && (ivideo->vbflags2 & VB2_SISYPBPRBRIDGE)) {
1da177e4 3668#ifdef CONFIG_FB_SIS_315
544393fe
TW
3669 if(ivideo->chip >= SIS_661) {
3670 cr38 |= 0x04;
3671 if(ivideo->vbflags & TV_YPBPR525P) cr35 |= 0x20;
1da177e4
LT
3672 else if(ivideo->vbflags & TV_YPBPR750P) cr35 |= 0x40;
3673 else if(ivideo->vbflags & TV_YPBPR1080I) cr35 |= 0x60;
3674 cr30 |= SIS_SIMULTANEOUS_VIEW_ENABLE;
3675 cr35 &= ~0x01;
3676 ivideo->currentvbflags |= (TV_YPBPR | (ivideo->vbflags & TV_YPBPRALL));
544393fe
TW
3677 } else if(ivideo->sisvga_engine == SIS_315_VGA) {
3678 cr30 |= (0x80 | SIS_SIMULTANEOUS_VIEW_ENABLE);
1da177e4 3679 cr38 |= 0x08;
544393fe 3680 if(ivideo->vbflags & TV_YPBPR525P) cr38 |= 0x10;
1da177e4
LT
3681 else if(ivideo->vbflags & TV_YPBPR750P) cr38 |= 0x20;
3682 else if(ivideo->vbflags & TV_YPBPR1080I) cr38 |= 0x30;
3683 cr31 &= ~0x01;
3684 ivideo->currentvbflags |= (TV_YPBPR | (ivideo->vbflags & TV_YPBPRALL));
544393fe
TW
3685 }
3686#endif
3687 } else if((ivideo->vbflags & TV_HIVISION) &&
3688 (ivideo->vbflags2 & VB2_SISHIVISIONBRIDGE)) {
3689 if(ivideo->chip >= SIS_661) {
3690 cr38 |= 0x04;
3691 cr35 |= 0x60;
3692 } else {
3693 cr30 |= 0x80;
3694 }
1da177e4 3695 cr30 |= SIS_SIMULTANEOUS_VIEW_ENABLE;
544393fe
TW
3696 cr31 |= 0x01;
3697 cr35 |= 0x01;
1da177e4
LT
3698 ivideo->currentvbflags |= TV_HIVISION;
3699 } else if(ivideo->vbflags & TV_SCART) {
3700 cr30 = (SIS_VB_OUTPUT_SCART | SIS_SIMULTANEOUS_VIEW_ENABLE);
3701 cr31 |= 0x01;
3702 cr35 |= 0x01;
3703 ivideo->currentvbflags |= TV_SCART;
3704 } else {
3705 if(ivideo->vbflags & TV_SVIDEO) {
3706 cr30 = (SIS_VB_OUTPUT_SVIDEO | SIS_SIMULTANEOUS_VIEW_ENABLE);
3707 ivideo->currentvbflags |= TV_SVIDEO;
3708 }
3709 if(ivideo->vbflags & TV_AVIDEO) {
3710 cr30 = (SIS_VB_OUTPUT_COMPOSITE | SIS_SIMULTANEOUS_VIEW_ENABLE);
3711 ivideo->currentvbflags |= TV_AVIDEO;
3712 }
3713 }
3714 cr31 |= SIS_DRIVER_MODE;
3715
544393fe
TW
3716 if(ivideo->vbflags & (TV_AVIDEO | TV_SVIDEO)) {
3717 if(ivideo->vbflags & TV_PAL) {
1da177e4
LT
3718 cr31 |= 0x01; cr35 |= 0x01;
3719 ivideo->currentvbflags |= TV_PAL;
3720 if(ivideo->vbflags & TV_PALM) {
3721 cr38 |= 0x40; cr35 |= 0x04;
3722 ivideo->currentvbflags |= TV_PALM;
3723 } else if(ivideo->vbflags & TV_PALN) {
3724 cr38 |= 0x80; cr35 |= 0x08;
3725 ivideo->currentvbflags |= TV_PALN;
544393fe
TW
3726 }
3727 } else {
1da177e4
LT
3728 cr31 &= ~0x01; cr35 &= ~0x01;
3729 ivideo->currentvbflags |= TV_NTSC;
3730 if(ivideo->vbflags & TV_NTSCJ) {
3731 cr38 |= 0x40; cr35 |= 0x02;
3732 ivideo->currentvbflags |= TV_NTSCJ;
544393fe 3733 }
1da177e4
LT
3734 }
3735 }
3736 break;
3737
3738 case CRT2_LCD:
3739 cr30 = (SIS_VB_OUTPUT_LCD | SIS_SIMULTANEOUS_VIEW_ENABLE);
3740 cr31 |= SIS_DRIVER_MODE;
3741 SiS_SetEnableDstn(&ivideo->SiS_Pr, ivideo->sisfb_dstn);
3742 SiS_SetEnableFstn(&ivideo->SiS_Pr, ivideo->sisfb_fstn);
544393fe
TW
3743 ivideo->curFSTN = ivideo->sisfb_fstn;
3744 ivideo->curDSTN = ivideo->sisfb_dstn;
1da177e4
LT
3745 break;
3746
3747 case CRT2_VGA:
3748 cr30 = (SIS_VB_OUTPUT_CRT2 | SIS_SIMULTANEOUS_VIEW_ENABLE);
3749 cr31 |= SIS_DRIVER_MODE;
3750 if(ivideo->sisfb_nocrt2rate) {
3751 cr33 |= (sisbios_mode[ivideo->sisfb_mode_idx].rate_idx << 4);
3752 } else {
3753 cr33 |= ((ivideo->rate_idx & 0x0F) << 4);
3754 }
3755 break;
3756
3757 default: /* disable CRT2 */
3758 cr30 = 0x00;
3759 cr31 |= (SIS_DRIVER_MODE | SIS_VB_OUTPUT_DISABLE);
3760 }
3761
3762 outSISIDXREG(SISCR, 0x30, cr30);
3763 outSISIDXREG(SISCR, 0x33, cr33);
3764
3765 if(ivideo->chip >= SIS_661) {
3766#ifdef CONFIG_FB_SIS_315
3767 cr31 &= ~0x01; /* Clear PAL flag (now in CR35) */
3768 setSISIDXREG(SISCR, 0x35, ~0x10, cr35); /* Leave overscan bit alone */
3769 cr38 &= 0x07; /* Use only LCDA and HiVision/YPbPr bits */
3770 setSISIDXREG(SISCR, 0x38, 0xf8, cr38);
3771#endif
3772 } else if(ivideo->chip != SIS_300) {
3773 outSISIDXREG(SISCR, tvregnum, cr38);
3774 }
3775 outSISIDXREG(SISCR, 0x31, cr31);
3776
1da177e4 3777 ivideo->SiS_Pr.SiS_UseOEM = ivideo->sisfb_useoem;
544393fe
TW
3778
3779 sisfb_check_engine_and_sync(ivideo);
1da177e4
LT
3780}
3781
3782/* Fix SR11 for 661 and later */
3783#ifdef CONFIG_FB_SIS_315
3784static void
3785sisfb_fixup_SR11(struct sis_video_info *ivideo)
3786{
544393fe
TW
3787 u8 tmpreg;
3788
3789 if(ivideo->chip >= SIS_661) {
3790 inSISIDXREG(SISSR,0x11,tmpreg);
3791 if(tmpreg & 0x20) {
3792 inSISIDXREG(SISSR,0x3e,tmpreg);
3793 tmpreg = (tmpreg + 1) & 0xff;
3794 outSISIDXREG(SISSR,0x3e,tmpreg);
3795 inSISIDXREG(SISSR,0x11,tmpreg);
3796 }
3797 if(tmpreg & 0xf0) {
3798 andSISIDXREG(SISSR,0x11,0x0f);
3799 }
3800 }
1da177e4
LT
3801}
3802#endif
3803
544393fe
TW
3804static void
3805sisfb_set_TVxposoffset(struct sis_video_info *ivideo, int val)
1da177e4 3806{
544393fe
TW
3807 if(val > 32) val = 32;
3808 if(val < -32) val = -32;
3809 ivideo->tvxpos = val;
1da177e4 3810
544393fe
TW
3811 if(ivideo->sisfblocked) return;
3812 if(!ivideo->modechanged) return;
1da177e4 3813
544393fe 3814 if(ivideo->currentvbflags & CRT2_TV) {
1da177e4 3815
544393fe 3816 if(ivideo->vbflags2 & VB2_CHRONTEL) {
1da177e4 3817
544393fe 3818 int x = ivideo->tvx;
1da177e4 3819
544393fe
TW
3820 switch(ivideo->chronteltype) {
3821 case 1:
3822 x += val;
3823 if(x < 0) x = 0;
3824 outSISIDXREG(SISSR,0x05,0x86);
3825 SiS_SetCH700x(&ivideo->SiS_Pr, 0x0a, (x & 0xff));
3826 SiS_SetCH70xxANDOR(&ivideo->SiS_Pr, 0x08, ((x & 0x0100) >> 7), 0xFD);
3827 break;
3828 case 2:
3829 /* Not supported by hardware */
3830 break;
3831 }
3832
3833 } else if(ivideo->vbflags2 & VB2_SISBRIDGE) {
3834
3835 u8 p2_1f,p2_20,p2_2b,p2_42,p2_43;
3836 unsigned short temp;
3837
3838 p2_1f = ivideo->p2_1f;
3839 p2_20 = ivideo->p2_20;
3840 p2_2b = ivideo->p2_2b;
3841 p2_42 = ivideo->p2_42;
3842 p2_43 = ivideo->p2_43;
3843
3844 temp = p2_1f | ((p2_20 & 0xf0) << 4);
3845 temp += (val * 2);
3846 p2_1f = temp & 0xff;
3847 p2_20 = (temp & 0xf00) >> 4;
3848 p2_2b = ((p2_2b & 0x0f) + (val * 2)) & 0x0f;
3849 temp = p2_43 | ((p2_42 & 0xf0) << 4);
3850 temp += (val * 2);
3851 p2_43 = temp & 0xff;
3852 p2_42 = (temp & 0xf00) >> 4;
3853 outSISIDXREG(SISPART2,0x1f,p2_1f);
3854 setSISIDXREG(SISPART2,0x20,0x0F,p2_20);
3855 setSISIDXREG(SISPART2,0x2b,0xF0,p2_2b);
3856 setSISIDXREG(SISPART2,0x42,0x0F,p2_42);
3857 outSISIDXREG(SISPART2,0x43,p2_43);
3858 }
3859 }
1da177e4
LT
3860}
3861
544393fe
TW
3862static void
3863sisfb_set_TVyposoffset(struct sis_video_info *ivideo, int val)
1da177e4 3864{
544393fe
TW
3865 if(val > 32) val = 32;
3866 if(val < -32) val = -32;
3867 ivideo->tvypos = val;
3868
3869 if(ivideo->sisfblocked) return;
3870 if(!ivideo->modechanged) return;
3871
3872 if(ivideo->currentvbflags & CRT2_TV) {
3873
3874 if(ivideo->vbflags2 & VB2_CHRONTEL) {
3875
3876 int y = ivideo->tvy;
3877
3878 switch(ivideo->chronteltype) {
3879 case 1:
3880 y -= val;
3881 if(y < 0) y = 0;
3882 outSISIDXREG(SISSR,0x05,0x86);
3883 SiS_SetCH700x(&ivideo->SiS_Pr, 0x0b, (y & 0xff));
3884 SiS_SetCH70xxANDOR(&ivideo->SiS_Pr, 0x08, ((y & 0x0100) >> 8), 0xFE);
3885 break;
3886 case 2:
3887 /* Not supported by hardware */
3888 break;
3889 }
3890
3891 } else if(ivideo->vbflags2 & VB2_SISBRIDGE) {
3892
3893 char p2_01, p2_02;
3894 val /= 2;
3895 p2_01 = ivideo->p2_01;
3896 p2_02 = ivideo->p2_02;
3897
3898 p2_01 += val;
3899 p2_02 += val;
3900 if(!(ivideo->currentvbflags & (TV_HIVISION | TV_YPBPR))) {
3901 while((p2_01 <= 0) || (p2_02 <= 0)) {
3902 p2_01 += 2;
3903 p2_02 += 2;
3904 }
3905 }
3906 outSISIDXREG(SISPART2,0x01,p2_01);
3907 outSISIDXREG(SISPART2,0x02,p2_02);
3908 }
3909 }
1da177e4
LT
3910}
3911
3912static void
3913sisfb_post_setmode(struct sis_video_info *ivideo)
3914{
3915 BOOLEAN crt1isoff = FALSE;
3916 BOOLEAN doit = TRUE;
3917#if defined(CONFIG_FB_SIS_300) || defined(CONFIG_FB_SIS_315)
3918 u8 reg;
3919#endif
3920#ifdef CONFIG_FB_SIS_315
3921 u8 reg1;
3922#endif
3923
544393fe 3924 outSISIDXREG(SISSR, 0x05, 0x86);
1da177e4
LT
3925
3926#ifdef CONFIG_FB_SIS_315
3927 sisfb_fixup_SR11(ivideo);
3928#endif
3929
3930 /* Now we actually HAVE changed the display mode */
544393fe 3931 ivideo->modechanged = 1;
1da177e4
LT
3932
3933 /* We can't switch off CRT1 if bridge is in slave mode */
544393fe 3934 if(ivideo->vbflags2 & VB2_VIDEOBRIDGE) {
1da177e4 3935 if(sisfb_bridgeisslave(ivideo)) doit = FALSE;
544393fe
TW
3936 } else
3937 ivideo->sisfb_crt1off = 0;
1da177e4
LT
3938
3939#ifdef CONFIG_FB_SIS_300
3940 if(ivideo->sisvga_engine == SIS_300_VGA) {
544393fe
TW
3941 if((ivideo->sisfb_crt1off) && (doit)) {
3942 crt1isoff = TRUE;
3943 reg = 0x00;
3944 } else {
3945 crt1isoff = FALSE;
3946 reg = 0x80;
3947 }
3948 setSISIDXREG(SISCR, 0x17, 0x7f, reg);
1da177e4
LT
3949 }
3950#endif
3951#ifdef CONFIG_FB_SIS_315
3952 if(ivideo->sisvga_engine == SIS_315_VGA) {
544393fe
TW
3953 if((ivideo->sisfb_crt1off) && (doit)) {
3954 crt1isoff = TRUE;
3955 reg = 0x40;
3956 reg1 = 0xc0;
3957 } else {
3958 crt1isoff = FALSE;
3959 reg = 0x00;
3960 reg1 = 0x00;
3961 }
3962 setSISIDXREG(SISCR, ivideo->SiS_Pr.SiS_MyCR63, ~0x40, reg);
3963 setSISIDXREG(SISSR, 0x1f, ~0xc0, reg1);
1da177e4
LT
3964 }
3965#endif
3966
3967 if(crt1isoff) {
544393fe
TW
3968 ivideo->currentvbflags &= ~VB_DISPTYPE_CRT1;
3969 ivideo->currentvbflags |= VB_SINGLE_MODE;
1da177e4 3970 } else {
544393fe
TW
3971 ivideo->currentvbflags |= VB_DISPTYPE_CRT1;
3972 if(ivideo->currentvbflags & VB_DISPTYPE_CRT2) {
3973 ivideo->currentvbflags |= VB_MIRROR_MODE;
3974 } else {
3975 ivideo->currentvbflags |= VB_SINGLE_MODE;
3976 }
1da177e4
LT
3977 }
3978
544393fe 3979 andSISIDXREG(SISSR, IND_SIS_RAMDAC_CONTROL, ~0x04);
1da177e4
LT
3980
3981 if(ivideo->currentvbflags & CRT2_TV) {
544393fe
TW
3982 if(ivideo->vbflags2 & VB2_SISBRIDGE) {
3983 inSISIDXREG(SISPART2,0x1f,ivideo->p2_1f);
3984 inSISIDXREG(SISPART2,0x20,ivideo->p2_20);
3985 inSISIDXREG(SISPART2,0x2b,ivideo->p2_2b);
3986 inSISIDXREG(SISPART2,0x42,ivideo->p2_42);
3987 inSISIDXREG(SISPART2,0x43,ivideo->p2_43);
3988 inSISIDXREG(SISPART2,0x01,ivideo->p2_01);
3989 inSISIDXREG(SISPART2,0x02,ivideo->p2_02);
3990 } else if(ivideo->vbflags2 & VB2_CHRONTEL) {
3991 if(ivideo->chronteltype == 1) {
3992 ivideo->tvx = SiS_GetCH700x(&ivideo->SiS_Pr, 0x0a);
3993 ivideo->tvx |= (((SiS_GetCH700x(&ivideo->SiS_Pr, 0x08) & 0x02) >> 1) << 8);
3994 ivideo->tvy = SiS_GetCH700x(&ivideo->SiS_Pr, 0x0b);
3995 ivideo->tvy |= ((SiS_GetCH700x(&ivideo->SiS_Pr, 0x08) & 0x01) << 8);
3996 }
3997 }
1da177e4
LT
3998 }
3999
4000 if(ivideo->tvxpos) {
544393fe 4001 sisfb_set_TVxposoffset(ivideo, ivideo->tvxpos);
1da177e4
LT
4002 }
4003 if(ivideo->tvypos) {
544393fe 4004 sisfb_set_TVyposoffset(ivideo, ivideo->tvypos);
1da177e4
LT
4005 }
4006
544393fe
TW
4007 /* Eventually sync engines */
4008 sisfb_check_engine_and_sync(ivideo);
1da177e4 4009
544393fe
TW
4010 /* (Re-)Initialize chip engines */
4011 if(ivideo->accel) {
4012 sisfb_engine_init(ivideo);
4013 } else {
4014 ivideo->engineok = 0;
4015 }
4016}
1da177e4 4017
544393fe
TW
4018static int
4019sisfb_reset_mode(struct sis_video_info *ivideo)
4020{
4021 if(sisfb_set_mode(ivideo, 0))
4022 return 1;
1da177e4 4023
544393fe
TW
4024 sisfb_set_pitch(ivideo);
4025 sisfb_set_base_CRT1(ivideo, ivideo->current_base);
4026 sisfb_set_base_CRT2(ivideo, ivideo->current_base);
1da177e4 4027
544393fe
TW
4028 return 0;
4029}
4030
4031static void
4032sisfb_handle_command(struct sis_video_info *ivideo, struct sisfb_cmd *sisfb_command)
4033{
4034 int mycrt1off;
1da177e4 4035
544393fe
TW
4036 switch(sisfb_command->sisfb_cmd) {
4037 case SISFB_CMD_GETVBFLAGS:
4038 if(!ivideo->modechanged) {
4039 sisfb_command->sisfb_result[0] = SISFB_CMD_ERR_EARLY;
4040 } else {
4041 sisfb_command->sisfb_result[0] = SISFB_CMD_ERR_OK;
4042 sisfb_command->sisfb_result[1] = ivideo->currentvbflags;
4043 sisfb_command->sisfb_result[2] = ivideo->vbflags2;
4044 }
4045 break;
4046 case SISFB_CMD_SWITCHCRT1:
4047 /* arg[0]: 0 = off, 1 = on, 99 = query */
4048 if(!ivideo->modechanged) {
4049 sisfb_command->sisfb_result[0] = SISFB_CMD_ERR_EARLY;
4050 } else if(sisfb_command->sisfb_arg[0] == 99) {
4051 /* Query */
4052 sisfb_command->sisfb_result[1] = ivideo->sisfb_crt1off ? 0 : 1;
4053 sisfb_command->sisfb_result[0] = SISFB_CMD_ERR_OK;
4054 } else if(ivideo->sisfblocked) {
4055 sisfb_command->sisfb_result[0] = SISFB_CMD_ERR_LOCKED;
4056 } else if((!(ivideo->currentvbflags & CRT2_ENABLE)) &&
4057 (sisfb_command->sisfb_arg[0] == 0)) {
4058 sisfb_command->sisfb_result[0] = SISFB_CMD_ERR_NOCRT2;
4059 } else {
4060 sisfb_command->sisfb_result[0] = SISFB_CMD_ERR_OK;
4061 mycrt1off = sisfb_command->sisfb_arg[0] ? 0 : 1;
4062 if( ((ivideo->currentvbflags & VB_DISPTYPE_CRT1) && mycrt1off) ||
4063 ((!(ivideo->currentvbflags & VB_DISPTYPE_CRT1)) && !mycrt1off) ) {
4064 ivideo->sisfb_crt1off = mycrt1off;
4065 if(sisfb_reset_mode(ivideo)) {
4066 sisfb_command->sisfb_result[0] = SISFB_CMD_ERR_OTHER;
1da177e4
LT
4067 }
4068 }
544393fe 4069 sisfb_command->sisfb_result[1] = ivideo->sisfb_crt1off ? 0 : 1;
1da177e4 4070 }
544393fe
TW
4071 break;
4072 /* more to come */
4073 default:
4074 sisfb_command->sisfb_result[0] = SISFB_CMD_ERR_UNKNOWN;
4075 printk(KERN_ERR "sisfb: Unknown command 0x%x\n",
4076 sisfb_command->sisfb_cmd);
1da177e4
LT
4077 }
4078}
4079
4080#ifndef MODULE
544393fe
TW
4081SISINITSTATIC int __init
4082sisfb_setup(char *options)
1da177e4
LT
4083{
4084 char *this_opt;
1da177e4 4085
544393fe 4086 sisfb_setdefaultparms();
1da177e4 4087
544393fe 4088 if(!options || !(*options))
1da177e4 4089 return 0;
1da177e4
LT
4090
4091 while((this_opt = strsep(&options, ",")) != NULL) {
4092
4093 if(!(*this_opt)) continue;
4094
4095 if(!strnicmp(this_opt, "off", 3)) {
4096 sisfb_off = 1;
4097 } else if(!strnicmp(this_opt, "forcecrt2type:", 14)) {
4098 /* Need to check crt2 type first for fstn/dstn */
4099 sisfb_search_crt2type(this_opt + 14);
4100 } else if(!strnicmp(this_opt, "tvmode:",7)) {
1da177e4 4101 sisfb_search_tvstd(this_opt + 7);
544393fe
TW
4102 } else if(!strnicmp(this_opt, "tvstandard:",11)) {
4103 sisfb_search_tvstd(this_opt + 11);
1da177e4
LT
4104 } else if(!strnicmp(this_opt, "mode:", 5)) {
4105 sisfb_search_mode(this_opt + 5, FALSE);
4106 } else if(!strnicmp(this_opt, "vesa:", 5)) {
4107 sisfb_search_vesamode(simple_strtoul(this_opt + 5, NULL, 0), FALSE);
4108#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
4109 } else if(!strnicmp(this_opt, "inverse", 7)) {
4110 sisfb_inverse = 1;
4111 /* fb_invert_cmaps(); */
4112 } else if(!strnicmp(this_opt, "font:", 5)) {
544393fe 4113 if(strlen(this_opt + 5) < 40) {
1da177e4
LT
4114 strncpy(sisfb_fontname, this_opt + 5, sizeof(sisfb_fontname) - 1);
4115 sisfb_fontname[sizeof(sisfb_fontname) - 1] = '\0';
4116 }
4117#endif
4118 } else if(!strnicmp(this_opt, "rate:", 5)) {
4119 sisfb_parm_rate = simple_strtoul(this_opt + 5, NULL, 0);
1da177e4
LT
4120 } else if(!strnicmp(this_opt, "forcecrt1:", 10)) {
4121 sisfb_forcecrt1 = (int)simple_strtoul(this_opt + 10, NULL, 0);
544393fe
TW
4122 } else if(!strnicmp(this_opt, "mem:",4)) {
4123 sisfb_parm_mem = simple_strtoul(this_opt + 4, NULL, 0);
1da177e4 4124 } else if(!strnicmp(this_opt, "pdc:", 4)) {
544393fe 4125 sisfb_pdc = simple_strtoul(this_opt + 4, NULL, 0);
1da177e4 4126 } else if(!strnicmp(this_opt, "pdc1:", 5)) {
544393fe 4127 sisfb_pdca = simple_strtoul(this_opt + 5, NULL, 0);
1da177e4
LT
4128 } else if(!strnicmp(this_opt, "noaccel", 7)) {
4129 sisfb_accel = 0;
4130 } else if(!strnicmp(this_opt, "accel", 5)) {
4131 sisfb_accel = -1;
4132 } else if(!strnicmp(this_opt, "noypan", 6)) {
544393fe 4133 sisfb_ypan = 0;
1da177e4 4134 } else if(!strnicmp(this_opt, "ypan", 4)) {
544393fe 4135 sisfb_ypan = -1;
1da177e4 4136 } else if(!strnicmp(this_opt, "nomax", 5)) {
544393fe 4137 sisfb_max = 0;
1da177e4 4138 } else if(!strnicmp(this_opt, "max", 3)) {
544393fe 4139 sisfb_max = -1;
1da177e4
LT
4140 } else if(!strnicmp(this_opt, "userom:", 7)) {
4141 sisfb_userom = (int)simple_strtoul(this_opt + 7, NULL, 0);
4142 } else if(!strnicmp(this_opt, "useoem:", 7)) {
4143 sisfb_useoem = (int)simple_strtoul(this_opt + 7, NULL, 0);
4144 } else if(!strnicmp(this_opt, "nocrt2rate", 10)) {
4145 sisfb_nocrt2rate = 1;
544393fe
TW
4146 } else if(!strnicmp(this_opt, "scalelcd:", 9)) {
4147 unsigned long temp = 2;
4148 temp = simple_strtoul(this_opt + 9, NULL, 0);
4149 if((temp == 0) || (temp == 1)) {
1da177e4 4150 sisfb_scalelcd = temp ^ 1;
544393fe 4151 }
1da177e4 4152 } else if(!strnicmp(this_opt, "tvxposoffset:", 13)) {
544393fe
TW
4153 int temp = 0;
4154 temp = (int)simple_strtol(this_opt + 13, NULL, 0);
4155 if((temp >= -32) && (temp <= 32)) {
1da177e4 4156 sisfb_tvxposoffset = temp;
544393fe 4157 }
1da177e4 4158 } else if(!strnicmp(this_opt, "tvyposoffset:", 13)) {
544393fe
TW
4159 int temp = 0;
4160 temp = (int)simple_strtol(this_opt + 13, NULL, 0);
4161 if((temp >= -32) && (temp <= 32)) {
1da177e4 4162 sisfb_tvyposoffset = temp;
544393fe 4163 }
1da177e4
LT
4164 } else if(!strnicmp(this_opt, "specialtiming:", 14)) {
4165 sisfb_search_specialtiming(this_opt + 14);
4166 } else if(!strnicmp(this_opt, "lvdshl:", 7)) {
544393fe
TW
4167 int temp = 4;
4168 temp = simple_strtoul(this_opt + 7, NULL, 0);
4169 if((temp >= 0) && (temp <= 3)) {
1da177e4 4170 sisfb_lvdshl = temp;
544393fe 4171 }
1da177e4
LT
4172 } else if(this_opt[0] >= '0' && this_opt[0] <= '9') {
4173 sisfb_search_mode(this_opt, TRUE);
4174#if !defined(__i386__) && !defined(__x86_64__)
544393fe
TW
4175 } else if(!strnicmp(this_opt, "resetcard", 9)) {
4176 sisfb_resetcard = 1;
1da177e4 4177 } else if(!strnicmp(this_opt, "videoram:", 9)) {
544393fe 4178 sisfb_videoram = simple_strtoul(this_opt + 9, NULL, 0);
1da177e4
LT
4179#endif
4180 } else {
4181 printk(KERN_INFO "sisfb: Invalid option %s\n", this_opt);
4182 }
4183
4184 }
4185
544393fe
TW
4186 return 0;
4187}
4188#endif
4189
4190static int __devinit
4191sisfb_check_rom(SIS_IOTYPE1 *rom_base, struct sis_video_info *ivideo)
4192{
4193 SIS_IOTYPE1 *rom;
4194 int romptr;
4195
4196 if((readb(rom_base) != 0x55) || (readb(rom_base + 1) != 0xaa))
4197 return 0;
4198
4199 romptr = (readb(rom_base + 0x18) | (readb(rom_base + 0x19) << 8));
4200 if(romptr > (0x10000 - 8))
4201 return 0;
4202
4203 rom = rom_base + romptr;
4204
4205 if((readb(rom) != 'P') || (readb(rom + 1) != 'C') ||
4206 (readb(rom + 2) != 'I') || (readb(rom + 3) != 'R'))
4207 return 0;
4208
4209 if((readb(rom + 4) | (readb(rom + 5) << 8)) != ivideo->chip_vendor)
4210 return 0;
4211
4212 if((readb(rom + 6) | (readb(rom + 7) << 8)) != ivideo->chip_id)
4213 return 0;
4214
4215 return 1;
4216}
4217
4218static unsigned char * __devinit
4219sisfb_find_rom(struct pci_dev *pdev)
4220{
4221 struct sis_video_info *ivideo = pci_get_drvdata(pdev);
4222 SIS_IOTYPE1 *rom_base;
4223 unsigned char *myrombase = NULL;
4224 u32 temp;
4225#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,11)
4226 size_t romsize;
4227
4228 /* First, try the official pci ROM functions (except
4229 * on integrated chipsets which have no ROM).
4230 */
4231
4232 if(!ivideo->nbridge) {
4233
4234 if((rom_base = pci_map_rom(pdev, &romsize))) {
4235
4236 if(sisfb_check_rom(rom_base, ivideo)) {
4237
4238 if((myrombase = vmalloc(65536))) {
4239
4240 /* Work around bug in pci/rom.c: Folks forgot to check
4241 * whether the size retrieved from the BIOS image eventually
4242 * is larger than the mapped size
4243 */
4244 if(pci_resource_len(pdev, PCI_ROM_RESOURCE) < romsize)
4245 romsize = pci_resource_len(pdev, PCI_ROM_RESOURCE);
4246
4247 memcpy_fromio(myrombase, rom_base,
4248 (romsize > 65536) ? 65536 : romsize);
4249 }
4250 }
4251 pci_unmap_rom(pdev, rom_base);
4252 }
4253 }
4254
4255 if(myrombase) return myrombase;
4256#endif
4257
4258 /* Otherwise do it the conventional way. */
4259
4260#if defined(__i386__) || defined(__x86_64__)
4261
4262 for(temp = 0x000c0000; temp < 0x000f0000; temp += 0x00001000) {
4263
4264 rom_base = ioremap(temp, 65536);
4265 if(!rom_base)
4266 continue;
4267
4268 if(!sisfb_check_rom(rom_base, ivideo)) {
4269 iounmap(rom_base);
4270 continue;
4271 }
4272
4273 if((myrombase = vmalloc(65536)))
4274 memcpy_fromio(myrombase, rom_base, 65536);
4275
4276 iounmap(rom_base);
4277 break;
4278
4279 }
4280
4281#else
4282
4283 pci_read_config_dword(pdev, PCI_ROM_ADDRESS, &temp);
4284 pci_write_config_dword(pdev, PCI_ROM_ADDRESS,
4285 (ivideo->video_base & PCI_ROM_ADDRESS_MASK) | PCI_ROM_ADDRESS_ENABLE);
4286
4287 rom_base = ioremap(ivideo->video_base, 65536);
4288 if(rom_base) {
4289 if(sisfb_check_rom(rom_base, ivideo)) {
4290 if((myrombase = vmalloc(65536)))
4291 memcpy_fromio(myrombase, rom_base, 65536);
4292 }
4293 iounmap(rom_base);
4294 }
4295
4296 pci_write_config_dword(pdev, PCI_ROM_ADDRESS, temp);
4297
4298#endif
4299
4300 return myrombase;
4301}
4302
4303static void __devinit
4304sisfb_post_map_vram(struct sis_video_info *ivideo, unsigned int *mapsize,
4305 unsigned int min)
4306{
4307 ivideo->video_vbase = ioremap(ivideo->video_base, (*mapsize));
4308
4309 if(!ivideo->video_vbase) {
4310 printk(KERN_ERR
4311 "sisfb: Unable to map maximum video RAM for size detection\n");
4312 (*mapsize) >>= 1;
4313 while((!(ivideo->video_vbase = ioremap(ivideo->video_base, (*mapsize))))) {
4314 (*mapsize) >>= 1;
4315 if((*mapsize) < (min << 20))
4316 break;
4317 }
4318 if(ivideo->video_vbase) {
4319 printk(KERN_ERR
4320 "sisfb: Video RAM size detection limited to %dMB\n",
4321 (int)((*mapsize) >> 20));
4322 }
4323 }
4324}
4325
4326#ifdef CONFIG_FB_SIS_300
4327static int __devinit
4328sisfb_post_300_buswidth(struct sis_video_info *ivideo)
4329{
4330 SIS_IOTYPE1 *FBAddress = ivideo->video_vbase;
4331 unsigned short temp;
4332 unsigned char reg;
4333 int i, j;
4334
4335 andSISIDXREG(SISSR, 0x15, 0xFB);
4336 orSISIDXREG(SISSR, 0x15, 0x04);
4337 outSISIDXREG(SISSR, 0x13, 0x00);
4338 outSISIDXREG(SISSR, 0x14, 0xBF);
4339
4340 for(i = 0; i < 2; i++) {
4341 temp = 0x1234;
4342 for(j = 0; j < 4; j++) {
4343 writew(temp, FBAddress);
4344 if(readw(FBAddress) == temp)
4345 break;
4346 orSISIDXREG(SISSR, 0x3c, 0x01);
4347 inSISIDXREG(SISSR, 0x05, reg);
4348 inSISIDXREG(SISSR, 0x05, reg);
4349 andSISIDXREG(SISSR, 0x3c, 0xfe);
4350 inSISIDXREG(SISSR, 0x05, reg);
4351 inSISIDXREG(SISSR, 0x05, reg);
4352 temp++;
4353 }
4354 }
4355
4356 writel(0x01234567L, FBAddress);
4357 writel(0x456789ABL, (FBAddress + 4));
4358 writel(0x89ABCDEFL, (FBAddress + 8));
4359 writel(0xCDEF0123L, (FBAddress + 12));
4360
4361 inSISIDXREG(SISSR, 0x3b, reg);
4362 if(reg & 0x01) {
4363 if(readl((FBAddress + 12)) == 0xCDEF0123L)
4364 return 4; /* Channel A 128bit */
4365 }
4366
4367 if(readl((FBAddress + 4)) == 0x456789ABL)
4368 return 2; /* Channel B 64bit */
4369
4370 return 1; /* 32bit */
4371}
4372
4373static int __devinit
4374sisfb_post_300_rwtest(struct sis_video_info *ivideo, int iteration, int buswidth,
4375 int PseudoRankCapacity, int PseudoAdrPinCount,
4376 unsigned int mapsize)
4377{
4378 SIS_IOTYPE1 *FBAddr = ivideo->video_vbase;
4379 unsigned short sr14;
4380 unsigned int k, RankCapacity, PageCapacity, BankNumHigh, BankNumMid;
4381 unsigned int PhysicalAdrOtherPage, PhysicalAdrHigh, PhysicalAdrHalfPage;
4382 static const unsigned short SiS_DRAMType[17][5] = {
4383 {0x0C,0x0A,0x02,0x40,0x39},
4384 {0x0D,0x0A,0x01,0x40,0x48},
4385 {0x0C,0x09,0x02,0x20,0x35},
4386 {0x0D,0x09,0x01,0x20,0x44},
4387 {0x0C,0x08,0x02,0x10,0x31},
4388 {0x0D,0x08,0x01,0x10,0x40},
4389 {0x0C,0x0A,0x01,0x20,0x34},
4390 {0x0C,0x09,0x01,0x08,0x32},
4391 {0x0B,0x08,0x02,0x08,0x21},
4392 {0x0C,0x08,0x01,0x08,0x30},
4393 {0x0A,0x08,0x02,0x04,0x11},
4394 {0x0B,0x0A,0x01,0x10,0x28},
4395 {0x09,0x08,0x02,0x02,0x01},
4396 {0x0B,0x09,0x01,0x08,0x24},
4397 {0x0B,0x08,0x01,0x04,0x20},
4398 {0x0A,0x08,0x01,0x02,0x10},
4399 {0x09,0x08,0x01,0x01,0x00}
4400 };
4401
4402 for(k = 0; k <= 16; k++) {
4403
4404 RankCapacity = buswidth * SiS_DRAMType[k][3];
4405
4406 if(RankCapacity != PseudoRankCapacity)
4407 continue;
4408
4409 if((SiS_DRAMType[k][2] + SiS_DRAMType[k][0]) > PseudoAdrPinCount)
4410 continue;
4411
4412 BankNumHigh = RankCapacity * 16 * iteration - 1;
4413 if(iteration == 3) { /* Rank No */
4414 BankNumMid = RankCapacity * 16 - 1;
4415 } else {
4416 BankNumMid = RankCapacity * 16 * iteration / 2 - 1;
4417 }
4418
4419 PageCapacity = (1 << SiS_DRAMType[k][1]) * buswidth * 4;
4420 PhysicalAdrHigh = BankNumHigh;
4421 PhysicalAdrHalfPage = (PageCapacity / 2 + PhysicalAdrHigh) % PageCapacity;
4422 PhysicalAdrOtherPage = PageCapacity * SiS_DRAMType[k][2] + PhysicalAdrHigh;
4423
4424 andSISIDXREG(SISSR, 0x15, 0xFB); /* Test */
4425 orSISIDXREG(SISSR, 0x15, 0x04); /* Test */
4426 sr14 = (SiS_DRAMType[k][3] * buswidth) - 1;
4427 if(buswidth == 4) sr14 |= 0x80;
4428 else if(buswidth == 2) sr14 |= 0x40;
4429 outSISIDXREG(SISSR, 0x13, SiS_DRAMType[k][4]);
4430 outSISIDXREG(SISSR, 0x14, sr14);
4431
4432 BankNumHigh <<= 16;
4433 BankNumMid <<= 16;
4434
4435 if((BankNumHigh + PhysicalAdrHigh >= mapsize) ||
4436 (BankNumMid + PhysicalAdrHigh >= mapsize) ||
4437 (BankNumHigh + PhysicalAdrHalfPage >= mapsize) ||
4438 (BankNumHigh + PhysicalAdrOtherPage >= mapsize))
4439 continue;
4440
4441 /* Write data */
4442 writew(((unsigned short)PhysicalAdrHigh),
4443 (FBAddr + BankNumHigh + PhysicalAdrHigh));
4444 writew(((unsigned short)BankNumMid),
4445 (FBAddr + BankNumMid + PhysicalAdrHigh));
4446 writew(((unsigned short)PhysicalAdrHalfPage),
4447 (FBAddr + BankNumHigh + PhysicalAdrHalfPage));
4448 writew(((unsigned short)PhysicalAdrOtherPage),
4449 (FBAddr + BankNumHigh + PhysicalAdrOtherPage));
4450
4451 /* Read data */
4452 if(readw(FBAddr + BankNumHigh + PhysicalAdrHigh) == PhysicalAdrHigh)
4453 return 1;
4454 }
4455
4456 return 0;
4457}
4458
4459static void __devinit
4460sisfb_post_300_ramsize(struct pci_dev *pdev, unsigned int mapsize)
4461{
4462 struct sis_video_info *ivideo = pci_get_drvdata(pdev);
4463 int i, j, buswidth;
4464 int PseudoRankCapacity, PseudoAdrPinCount;
4465
4466 buswidth = sisfb_post_300_buswidth(ivideo);
4467
4468 for(i = 6; i >= 0; i--) {
4469 PseudoRankCapacity = 1 << i;
4470 for(j = 4; j >= 1; j--) {
4471 PseudoAdrPinCount = 15 - j;
4472 if((PseudoRankCapacity * j) <= 64) {
4473 if(sisfb_post_300_rwtest(ivideo,
4474 j,
4475 buswidth,
4476 PseudoRankCapacity,
4477 PseudoAdrPinCount,
4478 mapsize))
4479 return;
4480 }
4481 }
4482 }
4483}
4484
4485static void __devinit
4486sisfb_post_sis300(struct pci_dev *pdev)
4487{
4488 struct sis_video_info *ivideo = pci_get_drvdata(pdev);
4489 unsigned char *bios = ivideo->SiS_Pr.VirtualRomBase;
4490 u8 reg, v1, v2, v3, v4, v5, v6, v7, v8;
4491 u16 index, rindex, memtype = 0;
4492 unsigned int mapsize;
4493
4494 if(!ivideo->SiS_Pr.UseROM)
4495 bios = NULL;
4496
4497 outSISIDXREG(SISSR, 0x05, 0x86);
4498
4499 if(bios) {
4500 if(bios[0x52] & 0x80) {
4501 memtype = bios[0x52];
4502 } else {
4503 inSISIDXREG(SISSR, 0x3a, memtype);
4504 }
4505 memtype &= 0x07;
4506 }
4507
4508 v3 = 0x80; v6 = 0x80;
4509 if(ivideo->revision_id <= 0x13) {
4510 v1 = 0x44; v2 = 0x42;
4511 v4 = 0x44; v5 = 0x42;
4512 } else {
4513 v1 = 0x68; v2 = 0x43; /* Assume 125Mhz MCLK */
4514 v4 = 0x68; v5 = 0x43; /* Assume 125Mhz ECLK */
4515 if(bios) {
4516 index = memtype * 5;
4517 rindex = index + 0x54;
4518 v1 = bios[rindex++];
4519 v2 = bios[rindex++];
4520 v3 = bios[rindex++];
4521 rindex = index + 0x7c;
4522 v4 = bios[rindex++];
4523 v5 = bios[rindex++];
4524 v6 = bios[rindex++];
4525 }
4526 }
4527 outSISIDXREG(SISSR, 0x28, v1);
4528 outSISIDXREG(SISSR, 0x29, v2);
4529 outSISIDXREG(SISSR, 0x2a, v3);
4530 outSISIDXREG(SISSR, 0x2e, v4);
4531 outSISIDXREG(SISSR, 0x2f, v5);
4532 outSISIDXREG(SISSR, 0x30, v6);
4533
4534 v1 = 0x10;
4535 if(bios)
4536 v1 = bios[0xa4];
4537 outSISIDXREG(SISSR, 0x07, v1); /* DAC speed */
4538
4539 outSISIDXREG(SISSR, 0x11, 0x0f); /* DDC, power save */
4540
4541 v1 = 0x01; v2 = 0x43; v3 = 0x1e; v4 = 0x2a;
4542 v5 = 0x06; v6 = 0x00; v7 = 0x00; v8 = 0x00;
4543 if(bios) {
4544 memtype += 0xa5;
4545 v1 = bios[memtype];
4546 v2 = bios[memtype + 8];
4547 v3 = bios[memtype + 16];
4548 v4 = bios[memtype + 24];
4549 v5 = bios[memtype + 32];
4550 v6 = bios[memtype + 40];
4551 v7 = bios[memtype + 48];
4552 v8 = bios[memtype + 56];
4553 }
4554 if(ivideo->revision_id >= 0x80)
4555 v3 &= 0xfd;
4556 outSISIDXREG(SISSR, 0x15, v1); /* Ram type (assuming 0, BIOS 0xa5 step 8) */
4557 outSISIDXREG(SISSR, 0x16, v2);
4558 outSISIDXREG(SISSR, 0x17, v3);
4559 outSISIDXREG(SISSR, 0x18, v4);
4560 outSISIDXREG(SISSR, 0x19, v5);
4561 outSISIDXREG(SISSR, 0x1a, v6);
4562 outSISIDXREG(SISSR, 0x1b, v7);
4563 outSISIDXREG(SISSR, 0x1c, v8); /* ---- */
4564 andSISIDXREG(SISSR, 0x15 ,0xfb);
4565 orSISIDXREG(SISSR, 0x15, 0x04);
4566 if(bios) {
4567 if(bios[0x53] & 0x02) {
4568 orSISIDXREG(SISSR, 0x19, 0x20);
4569 }
4570 }
4571 v1 = 0x04; /* DAC pedestal (BIOS 0xe5) */
4572 if(ivideo->revision_id >= 0x80)
4573 v1 |= 0x01;
4574 outSISIDXREG(SISSR, 0x1f, v1);
4575 outSISIDXREG(SISSR, 0x20, 0xa4); /* linear & relocated io & disable a0000 */
4576 v1 = 0xf6; v2 = 0x0d; v3 = 0x00;
4577 if(bios) {
4578 v1 = bios[0xe8];
4579 v2 = bios[0xe9];
4580 v3 = bios[0xea];
4581 }
4582 outSISIDXREG(SISSR, 0x23, v1);
4583 outSISIDXREG(SISSR, 0x24, v2);
4584 outSISIDXREG(SISSR, 0x25, v3);
4585 outSISIDXREG(SISSR, 0x21, 0x84);
4586 outSISIDXREG(SISSR, 0x22, 0x00);
4587 outSISIDXREG(SISCR, 0x37, 0x00);
4588 orSISIDXREG(SISPART1, 0x24, 0x01); /* unlock crt2 */
4589 outSISIDXREG(SISPART1, 0x00, 0x00);
4590 v1 = 0x40; v2 = 0x11;
4591 if(bios) {
4592 v1 = bios[0xec];
4593 v2 = bios[0xeb];
4594 }
4595 outSISIDXREG(SISPART1, 0x02, v1);
4596
4597 if(ivideo->revision_id >= 0x80)
4598 v2 &= ~0x01;
4599
4600 inSISIDXREG(SISPART4, 0x00, reg);
4601 if((reg == 1) || (reg == 2)) {
4602 outSISIDXREG(SISCR, 0x37, 0x02);
4603 outSISIDXREG(SISPART2, 0x00, 0x1c);
4604 v4 = 0x00; v5 = 0x00; v6 = 0x10;
4605 if(ivideo->SiS_Pr.UseROM) {
4606 v4 = bios[0xf5];
4607 v5 = bios[0xf6];
4608 v6 = bios[0xf7];
4609 }
4610 outSISIDXREG(SISPART4, 0x0d, v4);
4611 outSISIDXREG(SISPART4, 0x0e, v5);
4612 outSISIDXREG(SISPART4, 0x10, v6);
4613 outSISIDXREG(SISPART4, 0x0f, 0x3f);
4614 inSISIDXREG(SISPART4, 0x01, reg);
4615 if(reg >= 0xb0) {
4616 inSISIDXREG(SISPART4, 0x23, reg);
4617 reg &= 0x20;
4618 reg <<= 1;
4619 outSISIDXREG(SISPART4, 0x23, reg);
4620 }
4621 } else {
4622 v2 &= ~0x10;
4623 }
4624 outSISIDXREG(SISSR, 0x32, v2);
4625
4626 andSISIDXREG(SISPART1, 0x24, 0xfe); /* Lock CRT2 */
4627
4628 inSISIDXREG(SISSR, 0x16, reg);
4629 reg &= 0xc3;
4630 outSISIDXREG(SISCR, 0x35, reg);
4631 outSISIDXREG(SISCR, 0x83, 0x00);
4632#if !defined(__i386__) && !defined(__x86_64__)
4633 if(sisfb_videoram) {
4634 outSISIDXREG(SISSR, 0x13, 0x28); /* ? */
4635 reg = ((sisfb_videoram >> 10) - 1) | 0x40;
4636 outSISIDXREG(SISSR, 0x14, reg);
4637 } else {
4638#endif
4639 /* Need to map max FB size for finding out about RAM size */
4640 mapsize = 64 << 20;
4641 sisfb_post_map_vram(ivideo, &mapsize, 4);
4642
4643 if(ivideo->video_vbase) {
4644 sisfb_post_300_ramsize(pdev, mapsize);
4645 iounmap(ivideo->video_vbase);
4646 } else {
4647 printk(KERN_DEBUG
4648 "sisfb: Failed to map memory for size detection, assuming 8MB\n");
4649 outSISIDXREG(SISSR, 0x13, 0x28); /* ? */
4650 outSISIDXREG(SISSR, 0x14, 0x47); /* 8MB, 64bit default */
4651 }
4652#if !defined(__i386__) && !defined(__x86_64__)
4653 }
4654#endif
4655 if(bios) {
4656 v1 = bios[0xe6];
4657 v2 = bios[0xe7];
4658 } else {
4659 inSISIDXREG(SISSR, 0x3a, reg);
4660 if((reg & 0x30) == 0x30) {
4661 v1 = 0x04; /* PCI */
4662 v2 = 0x92;
4663 } else {
4664 v1 = 0x14; /* AGP */
4665 v2 = 0xb2;
4666 }
4667 }
4668 outSISIDXREG(SISSR, 0x21, v1);
4669 outSISIDXREG(SISSR, 0x22, v2);
4670
4671 /* Sense CRT1 */
4672 sisfb_sense_crt1(ivideo);
4673
4674 /* Set default mode, don't clear screen */
4675 ivideo->SiS_Pr.SiS_UseOEM = FALSE;
4676 SiS_SetEnableDstn(&ivideo->SiS_Pr, FALSE);
4677 SiS_SetEnableFstn(&ivideo->SiS_Pr, FALSE);
4678 ivideo->curFSTN = ivideo->curDSTN = 0;
4679 ivideo->SiS_Pr.VideoMemorySize = 8 << 20;
4680 SiSSetMode(&ivideo->SiS_Pr, 0x2e | 0x80);
4681
4682 outSISIDXREG(SISSR, 0x05, 0x86);
4683
4684 /* Display off */
4685 orSISIDXREG(SISSR, 0x01, 0x20);
4686
4687 /* Save mode number in CR34 */
4688 outSISIDXREG(SISCR, 0x34, 0x2e);
4689
4690 /* Let everyone know what the current mode is */
4691 ivideo->modeprechange = 0x2e;
4692}
4693#endif
4694
4695#ifdef CONFIG_FB_SIS_315
4696#if 0
4697static void __devinit
4698sisfb_post_sis315330(struct pci_dev *pdev)
4699{
4700 /* TODO */
4701}
4702#endif
4703
4704static void __devinit
4705sisfb_post_xgi_delay(struct sis_video_info *ivideo, int delay)
4706{
4707 unsigned int i;
4708 u8 reg;
4709
4710 for(i = 0; i <= (delay * 10 * 36); i++) {
4711 inSISIDXREG(SISSR, 0x05, reg);
4712 reg++;
4713 }
4714}
4715
4716static int __devinit
4717sisfb_find_host_bridge(struct sis_video_info *ivideo, struct pci_dev *mypdev,
4718 unsigned short pcivendor)
4719{
4720 struct pci_dev *pdev = NULL;
4721 unsigned short temp;
4722 int ret = 0;
4723
4724 while((pdev = SIS_PCI_GET_CLASS(PCI_CLASS_BRIDGE_HOST, pdev))) {
4725 temp = pdev->vendor;
4726 SIS_PCI_PUT_DEVICE(pdev);
4727 if(temp == pcivendor) {
4728 ret = 1;
4729 break;
4730 }
4731 }
4732
4733 return ret;
4734}
4735
4736static int __devinit
4737sisfb_post_xgi_rwtest(struct sis_video_info *ivideo, int starta,
4738 unsigned int enda, unsigned int mapsize)
4739{
4740 unsigned int pos;
4741 int i;
4742
4743 writel(0, ivideo->video_vbase);
4744
4745 for(i = starta; i <= enda; i++) {
4746 pos = 1 << i;
4747 if(pos < mapsize)
4748 writel(pos, ivideo->video_vbase + pos);
4749 }
4750
4751 sisfb_post_xgi_delay(ivideo, 150);
4752
4753 if(readl(ivideo->video_vbase) != 0)
4754 return 0;
4755
4756 for(i = starta; i <= enda; i++) {
4757 pos = 1 << i;
4758 if(pos < mapsize) {
4759 if(readl(ivideo->video_vbase + pos) != pos)
4760 return 0;
4761 } else
4762 return 0;
4763 }
4764
4765 return 1;
4766}
4767
4768static void __devinit
4769sisfb_post_xgi_ramsize(struct sis_video_info *ivideo)
4770{
4771 unsigned int buswidth, ranksize, channelab, mapsize;
4772 int i, j, k, l;
4773 u8 reg, sr14;
4774 static const u8 dramsr13[12 * 5] = {
4775 0x02, 0x0e, 0x0b, 0x80, 0x5d,
4776 0x02, 0x0e, 0x0a, 0x40, 0x59,
4777 0x02, 0x0d, 0x0b, 0x40, 0x4d,
4778 0x02, 0x0e, 0x09, 0x20, 0x55,
4779 0x02, 0x0d, 0x0a, 0x20, 0x49,
4780 0x02, 0x0c, 0x0b, 0x20, 0x3d,
4781 0x02, 0x0e, 0x08, 0x10, 0x51,
4782 0x02, 0x0d, 0x09, 0x10, 0x45,
4783 0x02, 0x0c, 0x0a, 0x10, 0x39,
4784 0x02, 0x0d, 0x08, 0x08, 0x41,
4785 0x02, 0x0c, 0x09, 0x08, 0x35,
4786 0x02, 0x0c, 0x08, 0x04, 0x31
4787 };
4788 static const u8 dramsr13_4[4 * 5] = {
4789 0x02, 0x0d, 0x09, 0x40, 0x45,
4790 0x02, 0x0c, 0x09, 0x20, 0x35,
4791 0x02, 0x0c, 0x08, 0x10, 0x31,
4792 0x02, 0x0b, 0x08, 0x08, 0x21
4793 };
4794
4795 /* Enable linear mode, disable 0xa0000 address decoding */
4796 /* We disable a0000 address decoding, because
4797 * - if running on x86, if the card is disabled, it means
4798 * that another card is in the system. We don't want
4799 * to interphere with that primary card's textmode.
4800 * - if running on non-x86, there usually is no VGA window
4801 * at a0000.
4802 */
4803 orSISIDXREG(SISSR, 0x20, (0x80 | 0x04));
4804
4805 /* Need to map max FB size for finding out about RAM size */
4806 mapsize = 256 << 20;
4807 sisfb_post_map_vram(ivideo, &mapsize, 32);
4808
4809 if(!ivideo->video_vbase) {
4810 printk(KERN_ERR "sisfb: Unable to detect RAM size. Setting default.\n");
4811 outSISIDXREG(SISSR, 0x13, 0x35);
4812 outSISIDXREG(SISSR, 0x14, 0x41);
4813 /* TODO */
4814 return;
4815 }
4816
4817 /* Non-interleaving */
4818 outSISIDXREG(SISSR, 0x15, 0x00);
4819 /* No tiling */
4820 outSISIDXREG(SISSR, 0x1c, 0x00);
4821
4822 if(ivideo->chip == XGI_20) {
4823
4824 channelab = 1;
4825 inSISIDXREG(SISCR, 0x97, reg);
4826 if(!(reg & 0x01)) { /* Single 32/16 */
4827 buswidth = 32;
4828 outSISIDXREG(SISSR, 0x13, 0xb1);
4829 outSISIDXREG(SISSR, 0x14, 0x52);
4830 sisfb_post_xgi_delay(ivideo, 1);
4831 sr14 = 0x02;
4832 if(sisfb_post_xgi_rwtest(ivideo, 23, 24, mapsize))
4833 goto bail_out;
4834
4835 outSISIDXREG(SISSR, 0x13, 0x31);
4836 outSISIDXREG(SISSR, 0x14, 0x42);
4837 sisfb_post_xgi_delay(ivideo, 1);
4838 if(sisfb_post_xgi_rwtest(ivideo, 23, 23, mapsize))
4839 goto bail_out;
4840
4841 buswidth = 16;
4842 outSISIDXREG(SISSR, 0x13, 0xb1);
4843 outSISIDXREG(SISSR, 0x14, 0x41);
4844 sisfb_post_xgi_delay(ivideo, 1);
4845 sr14 = 0x01;
4846 if(sisfb_post_xgi_rwtest(ivideo, 22, 23, mapsize))
4847 goto bail_out;
4848 else
4849 outSISIDXREG(SISSR, 0x13, 0x31);
4850 } else { /* Dual 16/8 */
4851 buswidth = 16;
4852 outSISIDXREG(SISSR, 0x13, 0xb1);
4853 outSISIDXREG(SISSR, 0x14, 0x41);
4854 sisfb_post_xgi_delay(ivideo, 1);
4855 sr14 = 0x01;
4856 if(sisfb_post_xgi_rwtest(ivideo, 22, 23, mapsize))
4857 goto bail_out;
4858
4859 outSISIDXREG(SISSR, 0x13, 0x31);
4860 outSISIDXREG(SISSR, 0x14, 0x31);
4861 sisfb_post_xgi_delay(ivideo, 1);
4862 if(sisfb_post_xgi_rwtest(ivideo, 22, 22, mapsize))
4863 goto bail_out;
4864
4865 buswidth = 8;
4866 outSISIDXREG(SISSR, 0x13, 0xb1);
4867 outSISIDXREG(SISSR, 0x14, 0x30);
4868 sisfb_post_xgi_delay(ivideo, 1);
4869 sr14 = 0x00;
4870 if(sisfb_post_xgi_rwtest(ivideo, 21, 22, mapsize))
4871 goto bail_out;
4872 else
4873 outSISIDXREG(SISSR, 0x13, 0x31);
4874 }
4875
4876 } else { /* XGI_40 */
4877
4878 inSISIDXREG(SISCR, 0x97, reg);
4879 if(!(reg & 0x10)) {
4880 inSISIDXREG(SISSR, 0x39, reg);
4881 reg >>= 1;
4882 }
4883
4884 if(reg & 0x01) { /* DDRII */
4885 buswidth = 32;
4886 if(ivideo->revision_id == 2) {
4887 channelab = 2;
4888 outSISIDXREG(SISSR, 0x13, 0xa1);
4889 outSISIDXREG(SISSR, 0x14, 0x44);
4890 sr14 = 0x04;
4891 sisfb_post_xgi_delay(ivideo, 1);
4892 if(sisfb_post_xgi_rwtest(ivideo, 23, 24, mapsize))
4893 goto bail_out;
4894
4895 outSISIDXREG(SISSR, 0x13, 0x21);
4896 outSISIDXREG(SISSR, 0x14, 0x34);
4897 if(sisfb_post_xgi_rwtest(ivideo, 22, 23, mapsize))
4898 goto bail_out;
4899
4900 channelab = 1;
4901 outSISIDXREG(SISSR, 0x13, 0xa1);
4902 outSISIDXREG(SISSR, 0x14, 0x40);
4903 sr14 = 0x00;
4904 if(sisfb_post_xgi_rwtest(ivideo, 22, 23, mapsize))
4905 goto bail_out;
4906
4907 outSISIDXREG(SISSR, 0x13, 0x21);
4908 outSISIDXREG(SISSR, 0x14, 0x30);
4909 } else {
4910 channelab = 3;
4911 outSISIDXREG(SISSR, 0x13, 0xa1);
4912 outSISIDXREG(SISSR, 0x14, 0x4c);
4913 sr14 = 0x0c;
4914 sisfb_post_xgi_delay(ivideo, 1);
4915 if(sisfb_post_xgi_rwtest(ivideo, 23, 25, mapsize))
4916 goto bail_out;
4917
4918 channelab = 2;
4919 outSISIDXREG(SISSR, 0x14, 0x48);
4920 sisfb_post_xgi_delay(ivideo, 1);
4921 sr14 = 0x08;
4922 if(sisfb_post_xgi_rwtest(ivideo, 23, 24, mapsize))
4923 goto bail_out;
4924
4925 outSISIDXREG(SISSR, 0x13, 0x21);
4926 outSISIDXREG(SISSR, 0x14, 0x3c);
4927 sr14 = 0x0c;
4928
4929 if(sisfb_post_xgi_rwtest(ivideo, 23, 24, mapsize)) {
4930 channelab = 3;
4931 } else {
4932 channelab = 2;
4933 outSISIDXREG(SISSR, 0x14, 0x38);
4934 sr14 = 0x08;
4935 }
4936 }
4937 sisfb_post_xgi_delay(ivideo, 1);
4938
4939 } else { /* DDR */
4940
4941 buswidth = 64;
4942 if(ivideo->revision_id == 2) {
4943 channelab = 1;
4944 outSISIDXREG(SISSR, 0x13, 0xa1);
4945 outSISIDXREG(SISSR, 0x14, 0x52);
4946 sisfb_post_xgi_delay(ivideo, 1);
4947 sr14 = 0x02;
4948 if(sisfb_post_xgi_rwtest(ivideo, 23, 24, mapsize))
4949 goto bail_out;
4950
4951 outSISIDXREG(SISSR, 0x13, 0x21);
4952 outSISIDXREG(SISSR, 0x14, 0x42);
4953 } else {
4954 channelab = 2;
4955 outSISIDXREG(SISSR, 0x13, 0xa1);
4956 outSISIDXREG(SISSR, 0x14, 0x5a);
4957 sisfb_post_xgi_delay(ivideo, 1);
4958 sr14 = 0x0a;
4959 if(sisfb_post_xgi_rwtest(ivideo, 24, 25, mapsize))
4960 goto bail_out;
4961
4962 outSISIDXREG(SISSR, 0x13, 0x21);
4963 outSISIDXREG(SISSR, 0x14, 0x4a);
4964 }
4965 sisfb_post_xgi_delay(ivideo, 1);
4966
4967 }
4968 }
4969
4970bail_out:
4971 setSISIDXREG(SISSR, 0x14, 0xf0, sr14);
4972 sisfb_post_xgi_delay(ivideo, 1);
4973
4974 j = (ivideo->chip == XGI_20) ? 5 : 9;
4975 k = (ivideo->chip == XGI_20) ? 12 : 4;
4976
4977 for(i = 0; i < k; i++) {
4978
4979 reg = (ivideo->chip == XGI_20) ?
4980 dramsr13[(i * 5) + 4] : dramsr13_4[(i * 5) + 4];
4981 setSISIDXREG(SISSR, 0x13, 0x80, reg);
4982 sisfb_post_xgi_delay(ivideo, 50);
4983
4984 ranksize = (ivideo->chip == XGI_20) ?
4985 dramsr13[(i * 5) + 3] : dramsr13_4[(i * 5) + 3];
4986
4987 inSISIDXREG(SISSR, 0x13, reg);
4988 if(reg & 0x80) ranksize <<= 1;
4989
4990 if(ivideo->chip == XGI_20) {
4991 if(buswidth == 16) ranksize <<= 1;
4992 else if(buswidth == 32) ranksize <<= 2;
4993 } else {
4994 if(buswidth == 64) ranksize <<= 1;
4995 }
4996
4997 reg = 0;
4998 l = channelab;
4999 if(l == 3) l = 4;
5000 if((ranksize * l) <= 256) {
5001 while((ranksize >>= 1)) reg += 0x10;
5002 }
5003
5004 if(!reg) continue;
5005
5006 setSISIDXREG(SISSR, 0x14, 0x0f, (reg & 0xf0));
5007 sisfb_post_xgi_delay(ivideo, 1);
5008
5009 if(sisfb_post_xgi_rwtest(ivideo, j, ((reg >> 4) + channelab - 2 + 20), mapsize))
5010 break;
5011 }
5012
5013 iounmap(ivideo->video_vbase);
5014}
1da177e4 5015
544393fe
TW
5016static void __devinit
5017sisfb_post_xgi_setclocks(struct sis_video_info *ivideo, u8 regb)
5018{
5019 u8 v1, v2, v3;
5020 int index;
5021 static const u8 cs90[8 * 3] = {
5022 0x16, 0x01, 0x01,
5023 0x3e, 0x03, 0x01,
5024 0x7c, 0x08, 0x01,
5025 0x79, 0x06, 0x01,
5026 0x29, 0x01, 0x81,
5027 0x5c, 0x23, 0x01,
5028 0x5c, 0x23, 0x01,
5029 0x5c, 0x23, 0x01
5030 };
5031 static const u8 csb8[8 * 3] = {
5032 0x5c, 0x23, 0x01,
5033 0x29, 0x01, 0x01,
5034 0x7c, 0x08, 0x01,
5035 0x79, 0x06, 0x01,
5036 0x29, 0x01, 0x81,
5037 0x5c, 0x23, 0x01,
5038 0x5c, 0x23, 0x01,
5039 0x5c, 0x23, 0x01
5040 };
1da177e4 5041
544393fe
TW
5042 regb = 0; /* ! */
5043
5044 index = regb * 3;
5045 v1 = cs90[index]; v2 = cs90[index + 1]; v3 = cs90[index + 2];
5046 if(ivideo->haveXGIROM) {
5047 v1 = ivideo->bios_abase[0x90 + index];
5048 v2 = ivideo->bios_abase[0x90 + index + 1];
5049 v3 = ivideo->bios_abase[0x90 + index + 2];
5050 }
5051 outSISIDXREG(SISSR, 0x28, v1);
5052 outSISIDXREG(SISSR, 0x29, v2);
5053 outSISIDXREG(SISSR, 0x2a, v3);
5054 sisfb_post_xgi_delay(ivideo, 0x43);
5055 sisfb_post_xgi_delay(ivideo, 0x43);
5056 sisfb_post_xgi_delay(ivideo, 0x43);
5057 index = regb * 3;
5058 v1 = csb8[index]; v2 = csb8[index + 1]; v3 = csb8[index + 2];
5059 if(ivideo->haveXGIROM) {
5060 v1 = ivideo->bios_abase[0xb8 + index];
5061 v2 = ivideo->bios_abase[0xb8 + index + 1];
5062 v3 = ivideo->bios_abase[0xb8 + index + 2];
5063 }
5064 outSISIDXREG(SISSR, 0x2e, v1);
5065 outSISIDXREG(SISSR, 0x2f, v2);
5066 outSISIDXREG(SISSR, 0x30, v3);
5067 sisfb_post_xgi_delay(ivideo, 0x43);
5068 sisfb_post_xgi_delay(ivideo, 0x43);
5069 sisfb_post_xgi_delay(ivideo, 0x43);
1da177e4 5070}
1da177e4 5071
544393fe
TW
5072static int __devinit
5073sisfb_post_xgi(struct pci_dev *pdev)
1da177e4
LT
5074{
5075 struct sis_video_info *ivideo = pci_get_drvdata(pdev);
544393fe
TW
5076 unsigned char *bios = ivideo->bios_abase;
5077 struct pci_dev *mypdev = NULL;
5078 const u8 *ptr, *ptr2;
5079 u8 v1, v2, v3, v4, v5, reg, ramtype;
5080 u32 rega, regb, regd;
5081 int i, j, k, index;
5082 static const u8 cs78[3] = { 0xf6, 0x0d, 0x00 };
5083 static const u8 cs76[2] = { 0xa3, 0xfb };
5084 static const u8 cs7b[3] = { 0xc0, 0x11, 0x00 };
5085 static const u8 cs158[8] = {
5086 0x88, 0xaa, 0x48, 0x00, 0x00, 0x00, 0x00, 0x00
5087 };
5088 static const u8 cs160[8] = {
5089 0x44, 0x77, 0x77, 0x00, 0x00, 0x00, 0x00, 0x00
5090 };
5091 static const u8 cs168[8] = {
5092 0x48, 0x78, 0x88, 0x00, 0x00, 0x00, 0x00, 0x00
5093 };
5094 static const u8 cs128[3 * 8] = {
5095 0x90, 0x28, 0x24, 0x00, 0x00, 0x00, 0x00, 0x00,
5096 0x77, 0x44, 0x44, 0x00, 0x00, 0x00, 0x00, 0x00,
5097 0x77, 0x44, 0x44, 0x00, 0x00, 0x00, 0x00, 0x00
5098 };
5099 static const u8 cs148[2 * 8] = {
5100 0x55, 0x55, 0x55, 0x00, 0x00, 0x00, 0x00, 0x00,
5101 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
5102 };
5103 static const u8 cs31a[8 * 4] = {
5104 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
5105 0xaa, 0xaa, 0xaa, 0xaa, 0x00, 0x00, 0x00, 0x00,
5106 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
5107 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
5108 };
5109 static const u8 cs33a[8 * 4] = {
5110 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
5111 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
5112 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
5113 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
5114 };
5115 static const u8 cs45a[8 * 2] = {
5116 0x00, 0x00, 0xa0, 0x00, 0xa0, 0x00, 0x00, 0x00,
5117 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
5118 };
5119 static const u8 cs170[7 * 8] = {
5120 0x54, 0x32, 0x44, 0x00, 0x00, 0x00, 0x00, 0x00,
5121 0x54, 0x43, 0x44, 0x00, 0x00, 0x00, 0x00, 0x00,
5122 0x0a, 0x05, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00,
5123 0x44, 0x34, 0x44, 0x00, 0x00, 0x00, 0x00, 0x00,
5124 0x10, 0x0a, 0x0a, 0x00, 0x00, 0x00, 0x00, 0x00,
5125 0x11, 0x0c, 0x0c, 0x00, 0x00, 0x00, 0x00, 0x00,
5126 0x05, 0x05, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00
5127 };
5128 static const u8 cs1a8[3 * 8] = {
5129 0xf0, 0xf0, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x00,
5130 0x05, 0x02, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00,
5131 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
5132 };
5133 static const u8 cs100[2 * 8] = {
5134 0xc4, 0x04, 0x84, 0x00, 0x00, 0x00, 0x00, 0x00,
5135 0xc4, 0x04, 0x84, 0x00, 0x00, 0x00, 0x00, 0x00
5136 };
1da177e4 5137
544393fe
TW
5138 /* VGA enable */
5139 reg = inSISREG(SISVGAENABLE) | 0x01;
5140 outSISREG(SISVGAENABLE, reg);
1da177e4 5141
544393fe
TW
5142 /* Misc */
5143 reg = inSISREG(SISMISCR) | 0x01;
5144 outSISREG(SISMISCW, reg);
1da177e4 5145
544393fe
TW
5146 /* Unlock SR */
5147 outSISIDXREG(SISSR, 0x05, 0x86);
5148 inSISIDXREG(SISSR, 0x05, reg);
5149 if(reg != 0xa1)
5150 return 0;
1da177e4 5151
544393fe
TW
5152 /* Clear some regs */
5153 for(i = 0; i < 0x22; i++) {
5154 if(0x06 + i == 0x20) continue;
5155 outSISIDXREG(SISSR, 0x06 + i, 0x00);
5156 }
5157 for(i = 0; i < 0x0b; i++) {
5158 outSISIDXREG(SISSR, 0x31 + i, 0x00);
5159 }
5160 for(i = 0; i < 0x10; i++) {
5161 outSISIDXREG(SISCR, 0x30 + i, 0x00);
5162 }
1da177e4 5163
544393fe
TW
5164 ptr = cs78;
5165 if(ivideo->haveXGIROM) {
5166 ptr = (const u8 *)&bios[0x78];
5167 }
5168 for(i = 0; i < 3; i++) {
5169 outSISIDXREG(SISSR, 0x23 + i, ptr[i]);
5170 }
1da177e4 5171
544393fe
TW
5172 ptr = cs76;
5173 if(ivideo->haveXGIROM) {
5174 ptr = (const u8 *)&bios[0x76];
5175 }
5176 for(i = 0; i < 2; i++) {
5177 outSISIDXREG(SISSR, 0x21 + i, ptr[i]);
5178 }
1da177e4 5179
544393fe
TW
5180 v1 = 0x18; v2 = 0x00;
5181 if(ivideo->haveXGIROM) {
5182 v1 = bios[0x74];
5183 v2 = bios[0x75];
5184 }
5185 outSISIDXREG(SISSR, 0x07, v1);
5186 outSISIDXREG(SISSR, 0x11, 0x0f);
5187 outSISIDXREG(SISSR, 0x1f, v2);
5188 /* PCI linear mode, RelIO enabled, A0000 decoding disabled */
5189 outSISIDXREG(SISSR, 0x20, 0x80 | 0x20 | 0x04);
5190 outSISIDXREG(SISSR, 0x27, 0x74);
1da177e4 5191
544393fe
TW
5192 ptr = cs7b;
5193 if(ivideo->haveXGIROM) {
5194 ptr = (const u8 *)&bios[0x7b];
5195 }
5196 for(i = 0; i < 3; i++) {
5197 outSISIDXREG(SISSR, 0x31 + i, ptr[i]);
5198 }
1da177e4 5199
544393fe
TW
5200 if(ivideo->chip == XGI_40) {
5201 if(ivideo->revision_id == 2) {
5202 setSISIDXREG(SISSR, 0x3b, 0x3f, 0xc0);
5203 }
5204 outSISIDXREG(SISCR, 0x7d, 0xfe);
5205 outSISIDXREG(SISCR, 0x7e, 0x0f);
5206 }
5207 if(ivideo->revision_id == 0) { /* 40 *and* 20? */
5208 andSISIDXREG(SISCR, 0x58, 0xd7);
5209 inSISIDXREG(SISCR, 0xcb, reg);
5210 if(reg & 0x20) {
5211 setSISIDXREG(SISCR, 0x58, 0xd7, (reg & 0x10) ? 0x08 : 0x20); /* =0x28 Z7 ? */
5212 }
5213 }
1da177e4 5214
544393fe
TW
5215 reg = (ivideo->chip == XGI_40) ? 0x20 : 0x00;
5216 setSISIDXREG(SISCR, 0x38, 0x1f, reg);
1da177e4 5217
544393fe
TW
5218 if(ivideo->chip == XGI_20) {
5219 outSISIDXREG(SISSR, 0x36, 0x70);
5220 } else {
5221 outSISIDXREG(SISVID, 0x00, 0x86);
5222 outSISIDXREG(SISVID, 0x32, 0x00);
5223 outSISIDXREG(SISVID, 0x30, 0x00);
5224 outSISIDXREG(SISVID, 0x32, 0x01);
5225 outSISIDXREG(SISVID, 0x30, 0x00);
5226 andSISIDXREG(SISVID, 0x2f, 0xdf);
5227 andSISIDXREG(SISCAP, 0x00, 0x3f);
5228
5229 outSISIDXREG(SISPART1, 0x2f, 0x01);
5230 outSISIDXREG(SISPART1, 0x00, 0x00);
5231 outSISIDXREG(SISPART1, 0x02, bios[0x7e]);
5232 outSISIDXREG(SISPART1, 0x2e, 0x08);
5233 andSISIDXREG(SISPART1, 0x35, 0x7f);
5234 andSISIDXREG(SISPART1, 0x50, 0xfe);
5235
5236 inSISIDXREG(SISPART4, 0x00, reg);
5237 if(reg == 1 || reg == 2) {
5238 outSISIDXREG(SISPART2, 0x00, 0x1c);
5239 outSISIDXREG(SISPART4, 0x0d, bios[0x7f]);
5240 outSISIDXREG(SISPART4, 0x0e, bios[0x80]);
5241 outSISIDXREG(SISPART4, 0x10, bios[0x81]);
5242 andSISIDXREG(SISPART4, 0x0f, 0x3f);
5243
5244 inSISIDXREG(SISPART4, 0x01, reg);
5245 if((reg & 0xf0) >= 0xb0) {
5246 inSISIDXREG(SISPART4, 0x23, reg);
5247 if(reg & 0x20) reg |= 0x40;
5248 outSISIDXREG(SISPART4, 0x23, reg);
5249 reg = (reg & 0x20) ? 0x02 : 0x00;
5250 setSISIDXREG(SISPART1, 0x1e, 0xfd, reg);
5251 }
5252 }
1da177e4 5253
544393fe
TW
5254 v1 = bios[0x77];
5255
5256 inSISIDXREG(SISSR, 0x3b, reg);
5257 if(reg & 0x02) {
5258 inSISIDXREG(SISSR, 0x3a, reg);
5259 v2 = (reg & 0x30) >> 3;
5260 if(!(v2 & 0x04)) v2 ^= 0x02;
5261 inSISIDXREG(SISSR, 0x39, reg);
5262 if(reg & 0x80) v2 |= 0x80;
5263 v2 |= 0x01;
5264
5265 if((mypdev = SIS_PCI_GET_DEVICE(PCI_VENDOR_ID_SI, 0x0730, NULL))) {
5266 SIS_PCI_PUT_DEVICE(mypdev);
5267 if(((v2 & 0x06) == 2) || ((v2 & 0x06) == 4))
5268 v2 &= 0xf9;
5269 v2 |= 0x08;
5270 v1 &= 0xfe;
5271 } else {
5272 mypdev = SIS_PCI_GET_DEVICE(PCI_VENDOR_ID_SI, 0x0735, NULL);
5273 if(!mypdev)
5274 mypdev = SIS_PCI_GET_DEVICE(PCI_VENDOR_ID_SI, 0x0645, NULL);
5275 if(!mypdev)
5276 mypdev = SIS_PCI_GET_DEVICE(PCI_VENDOR_ID_SI, 0x0650, NULL);
5277 if(mypdev) {
5278 pci_read_config_dword(mypdev, 0x94, &regd);
5279 regd &= 0xfffffeff;
5280 pci_write_config_dword(mypdev, 0x94, regd);
5281 v1 &= 0xfe;
5282 SIS_PCI_PUT_DEVICE(mypdev);
5283 } else if(sisfb_find_host_bridge(ivideo, pdev, PCI_VENDOR_ID_SI)) {
5284 v1 &= 0xfe;
5285 } else if(sisfb_find_host_bridge(ivideo, pdev, 0x1106) ||
5286 sisfb_find_host_bridge(ivideo, pdev, 0x1022) ||
5287 sisfb_find_host_bridge(ivideo, pdev, 0x700e) ||
5288 sisfb_find_host_bridge(ivideo, pdev, 0x10de)) {
5289 if((v2 & 0x06) == 4)
5290 v2 ^= 0x06;
5291 v2 |= 0x08;
5292 }
5293 }
5294 setSISIDXREG(SISCR, 0x5f, 0xf0, v2);
5295 }
5296 outSISIDXREG(SISSR, 0x22, v1);
5297
5298 if(ivideo->revision_id == 2) {
5299 inSISIDXREG(SISSR, 0x3b, v1);
5300 inSISIDXREG(SISSR, 0x3a, v2);
5301 regd = bios[0x90 + 3] | (bios[0x90 + 4] << 8);
5302 if( (!(v1 & 0x02)) && (v2 & 0x30) && (regd < 0xcf) )
5303 setSISIDXREG(SISCR, 0x5f, 0xf1, 0x01);
5304
5305 if((mypdev = SIS_PCI_GET_DEVICE(0x10de, 0x01e0, NULL))) {
5306 /* TODO: set CR5f &0xf1 | 0x01 for version 6570
5307 * of nforce 2 ROM
5308 */
5309 if(0)
5310 setSISIDXREG(SISCR, 0x5f, 0xf1, 0x01);
5311 SIS_PCI_PUT_DEVICE(mypdev);
5312 }
5313 }
1da177e4 5314
544393fe
TW
5315 v1 = 0x30;
5316 inSISIDXREG(SISSR, 0x3b, reg);
5317 inSISIDXREG(SISCR, 0x5f, v2);
5318 if((!(reg & 0x02)) && (v2 & 0x0e))
5319 v1 |= 0x08;
5320 outSISIDXREG(SISSR, 0x27, v1);
1da177e4 5321
544393fe
TW
5322 if(bios[0x64] & 0x01) {
5323 setSISIDXREG(SISCR, 0x5f, 0xf0, bios[0x64]);
5324 }
5325
5326 v1 = bios[0x4f7];
5327 pci_read_config_dword(pdev, 0x50, &regd);
5328 regd = (regd >> 20) & 0x0f;
5329 if(regd == 1) {
5330 v1 &= 0xfc;
5331 orSISIDXREG(SISCR, 0x5f, 0x08);
5332 }
5333 outSISIDXREG(SISCR, 0x48, v1);
5334
5335 setSISIDXREG(SISCR, 0x47, 0x04, bios[0x4f6] & 0xfb);
5336 setSISIDXREG(SISCR, 0x49, 0xf0, bios[0x4f8] & 0x0f);
5337 setSISIDXREG(SISCR, 0x4a, 0x60, bios[0x4f9] & 0x9f);
5338 setSISIDXREG(SISCR, 0x4b, 0x08, bios[0x4fa] & 0xf7);
5339 setSISIDXREG(SISCR, 0x4c, 0x80, bios[0x4fb] & 0x7f);
5340 outSISIDXREG(SISCR, 0x70, bios[0x4fc]);
5341 setSISIDXREG(SISCR, 0x71, 0xf0, bios[0x4fd] & 0x0f);
5342 outSISIDXREG(SISCR, 0x74, 0xd0);
5343 setSISIDXREG(SISCR, 0x74, 0xcf, bios[0x4fe] & 0x30);
5344 setSISIDXREG(SISCR, 0x75, 0xe0, bios[0x4ff] & 0x1f);
5345 setSISIDXREG(SISCR, 0x76, 0xe0, bios[0x500] & 0x1f);
5346 v1 = bios[0x501];
5347 if((mypdev = SIS_PCI_GET_DEVICE(0x8086, 0x2530, NULL))) {
5348 v1 = 0xf0;
5349 SIS_PCI_PUT_DEVICE(mypdev);
5350 }
5351 outSISIDXREG(SISCR, 0x77, v1);
1da177e4 5352 }
1da177e4 5353
544393fe 5354 /* RAM type */
1da177e4 5355
544393fe 5356 regb = 0; /* ! */
1da177e4 5357
544393fe
TW
5358 v1 = 0xff;
5359 if(ivideo->haveXGIROM) {
5360 v1 = bios[0x140 + regb];
1da177e4 5361 }
544393fe 5362 outSISIDXREG(SISCR, 0x6d, v1);
1da177e4 5363
544393fe
TW
5364 ptr = cs128;
5365 if(ivideo->haveXGIROM) {
5366 ptr = (const u8 *)&bios[0x128];
1da177e4 5367 }
544393fe
TW
5368 for(i = 0, j = 0; i < 3; i++, j += 8) {
5369 outSISIDXREG(SISCR, 0x68 + i, ptr[j + regb]);
1da177e4
LT
5370 }
5371
544393fe
TW
5372 ptr = cs31a;
5373 ptr2 = cs33a;
5374 if(ivideo->haveXGIROM) {
5375 index = (ivideo->chip == XGI_20) ? 0x31a : 0x3a6;
5376 ptr = (const u8 *)&bios[index];
5377 ptr2 = (const u8 *)&bios[index + 0x20];
1da177e4 5378 }
544393fe
TW
5379 for(i = 0; i < 2; i++) {
5380 if(i == 0) {
5381 regd = le32_to_cpu(((u32 *)ptr)[regb]);
5382 rega = 0x6b;
5383 } else {
5384 regd = le32_to_cpu(((u32 *)ptr2)[regb]);
5385 rega = 0x6e;
5386 }
5387 reg = 0x00;
5388 for(j = 0; j < 16; j++) {
5389 reg &= 0xf3;
5390 if(regd & 0x01) reg |= 0x04;
5391 if(regd & 0x02) reg |= 0x08;
5392 regd >>= 2;
5393 outSISIDXREG(SISCR, rega, reg);
5394 inSISIDXREG(SISCR, rega, reg);
5395 inSISIDXREG(SISCR, rega, reg);
5396 reg += 0x10;
5397 }
1da177e4 5398 }
544393fe
TW
5399
5400 andSISIDXREG(SISCR, 0x6e, 0xfc);
5401
5402 ptr = NULL;
5403 if(ivideo->haveXGIROM) {
5404 index = (ivideo->chip == XGI_20) ? 0x35a : 0x3e6;
5405 ptr = (const u8 *)&bios[index];
1da177e4 5406 }
544393fe
TW
5407 for(i = 0; i < 4; i++) {
5408 setSISIDXREG(SISCR, 0x6e, 0xfc, i);
5409 reg = 0x00;
5410 for(j = 0; j < 2; j++) {
5411 regd = 0;
5412 if(ptr) {
5413 regd = le32_to_cpu(((u32 *)ptr)[regb * 8]);
5414 ptr += 4;
5415 }
5416 /* reg = 0x00; */
5417 for(k = 0; k < 16; k++) {
5418 reg &= 0xfc;
5419 if(regd & 0x01) reg |= 0x01;
5420 if(regd & 0x02) reg |= 0x02;
5421 regd >>= 2;
5422 outSISIDXREG(SISCR, 0x6f, reg);
5423 inSISIDXREG(SISCR, 0x6f, reg);
5424 inSISIDXREG(SISCR, 0x6f, reg);
5425 reg += 0x08;
5426 }
5427 }
1da177e4 5428 }
544393fe
TW
5429
5430 ptr = cs148;
5431 if(ivideo->haveXGIROM) {
5432 ptr = (const u8 *)&bios[0x148];
1da177e4 5433 }
544393fe
TW
5434 for(i = 0, j = 0; i < 2; i++, j += 8) {
5435 outSISIDXREG(SISCR, 0x80 + i, ptr[j + regb]);
1da177e4 5436 }
1da177e4 5437
544393fe 5438 andSISIDXREG(SISCR, 0x89, 0x8f);
1da177e4 5439
544393fe
TW
5440 ptr = cs45a;
5441 if(ivideo->haveXGIROM) {
5442 index = (ivideo->chip == XGI_20) ? 0x45a : 0x4e6;
5443 ptr = (const u8 *)&bios[index];
5444 }
5445 regd = le16_to_cpu(((const u16 *)ptr)[regb]);
5446 reg = 0x80;
5447 for(i = 0; i < 5; i++) {
5448 reg &= 0xfc;
5449 if(regd & 0x01) reg |= 0x01;
5450 if(regd & 0x02) reg |= 0x02;
5451 regd >>= 2;
5452 outSISIDXREG(SISCR, 0x89, reg);
5453 inSISIDXREG(SISCR, 0x89, reg);
5454 inSISIDXREG(SISCR, 0x89, reg);
5455 reg += 0x10;
5456 }
1da177e4 5457
544393fe
TW
5458 v1 = 0xb5; v2 = 0x20; v3 = 0xf0; v4 = 0x13;
5459 if(ivideo->haveXGIROM) {
5460 v1 = bios[0x118 + regb];
5461 v2 = bios[0xf8 + regb];
5462 v3 = bios[0x120 + regb];
5463 v4 = bios[0x1ca];
1da177e4 5464 }
544393fe
TW
5465 outSISIDXREG(SISCR, 0x45, v1 & 0x0f);
5466 outSISIDXREG(SISCR, 0x99, (v1 >> 4) & 0x07);
5467 orSISIDXREG(SISCR, 0x40, v1 & 0x80);
5468 outSISIDXREG(SISCR, 0x41, v2);
5469
5470 ptr = cs170;
5471 if(ivideo->haveXGIROM) {
5472 ptr = (const u8 *)&bios[0x170];
1da177e4 5473 }
544393fe
TW
5474 for(i = 0, j = 0; i < 7; i++, j += 8) {
5475 outSISIDXREG(SISCR, 0x90 + i, ptr[j + regb]);
1da177e4
LT
5476 }
5477
544393fe
TW
5478 outSISIDXREG(SISCR, 0x59, v3);
5479
5480 ptr = cs1a8;
5481 if(ivideo->haveXGIROM) {
5482 ptr = (const u8 *)&bios[0x1a8];
5483 }
5484 for(i = 0, j = 0; i < 3; i++, j += 8) {
5485 outSISIDXREG(SISCR, 0xc3 + i, ptr[j + regb]);
1da177e4 5486 }
1da177e4 5487
544393fe
TW
5488 ptr = cs100;
5489 if(ivideo->haveXGIROM) {
5490 ptr = (const u8 *)&bios[0x100];
5491 }
5492 for(i = 0, j = 0; i < 2; i++, j += 8) {
5493 outSISIDXREG(SISCR, 0x8a + i, ptr[j + regb]);
5494 }
1da177e4 5495
544393fe 5496 outSISIDXREG(SISCR, 0xcf, v4);
1da177e4 5497
544393fe
TW
5498 outSISIDXREG(SISCR, 0x83, 0x09);
5499 outSISIDXREG(SISCR, 0x87, 0x00);
1da177e4 5500
544393fe
TW
5501 if(ivideo->chip == XGI_40) {
5502 if( (ivideo->revision_id == 1) ||
5503 (ivideo->revision_id == 2) ) {
5504 outSISIDXREG(SISCR, 0x8c, 0x87);
5505 }
5506 }
1da177e4 5507
544393fe
TW
5508 outSISIDXREG(SISSR, 0x17, 0x00);
5509 outSISIDXREG(SISSR, 0x1a, 0x87);
1da177e4 5510
544393fe
TW
5511 if(ivideo->chip == XGI_20) {
5512 outSISIDXREG(SISSR, 0x15, 0x00);
5513 outSISIDXREG(SISSR, 0x1c, 0x00);
1da177e4
LT
5514 }
5515
544393fe
TW
5516 ramtype = 0x00; v1 = 0x10;
5517 if(ivideo->haveXGIROM) {
5518 ramtype = bios[0x62];
5519 v1 = bios[0x1d2];
5520 }
5521 if(!(ramtype & 0x80)) {
5522 if(ivideo->chip == XGI_20) {
5523 outSISIDXREG(SISCR, 0x97, v1);
5524 inSISIDXREG(SISCR, 0x97, reg);
5525 if(reg & 0x10) {
5526 ramtype = (reg & 0x01) << 1;
5527 }
5528 } else {
5529 inSISIDXREG(SISSR, 0x39, reg);
5530 ramtype = reg & 0x02;
5531 if(!(ramtype)) {
5532 inSISIDXREG(SISSR, 0x3a, reg);
5533 ramtype = (reg >> 1) & 0x01;
5534 }
5535 }
1da177e4 5536 }
544393fe
TW
5537 ramtype &= 0x07;
5538
5539 regb = 0; /* ! */
5540
5541 switch(ramtype) {
5542 case 0:
5543 sisfb_post_xgi_setclocks(ivideo, regb);
5544 if((ivideo->chip == XGI_20) ||
5545 (ivideo->revision_id == 1) ||
5546 (ivideo->revision_id == 2)) {
5547 v1 = cs158[regb]; v2 = cs160[regb]; v3 = cs168[regb];
5548 if(ivideo->haveXGIROM) {
5549 v1 = bios[regb + 0x158];
5550 v2 = bios[regb + 0x160];
5551 v3 = bios[regb + 0x168];
5552 }
5553 outSISIDXREG(SISCR, 0x82, v1);
5554 outSISIDXREG(SISCR, 0x85, v2);
5555 outSISIDXREG(SISCR, 0x86, v3);
5556 } else {
5557 outSISIDXREG(SISCR, 0x82, 0x88);
5558 outSISIDXREG(SISCR, 0x86, 0x00);
5559 inSISIDXREG(SISCR, 0x86, reg);
5560 outSISIDXREG(SISCR, 0x86, 0x88);
5561 inSISIDXREG(SISCR, 0x86, reg);
5562 outSISIDXREG(SISCR, 0x86, bios[regb + 0x168]);
5563 outSISIDXREG(SISCR, 0x82, 0x77);
5564 outSISIDXREG(SISCR, 0x85, 0x00);
5565 inSISIDXREG(SISCR, 0x85, reg);
5566 outSISIDXREG(SISCR, 0x85, 0x88);
5567 inSISIDXREG(SISCR, 0x85, reg);
5568 outSISIDXREG(SISCR, 0x85, bios[regb + 0x160]);
5569 outSISIDXREG(SISCR, 0x82, bios[regb + 0x158]);
5570 }
5571 if(ivideo->chip == XGI_40) {
5572 outSISIDXREG(SISCR, 0x97, 0x00);
5573 }
5574 outSISIDXREG(SISCR, 0x98, 0x01);
5575 outSISIDXREG(SISCR, 0x9a, 0x02);
1da177e4 5576
544393fe
TW
5577 outSISIDXREG(SISSR, 0x18, 0x01);
5578 if((ivideo->chip == XGI_20) ||
5579 (ivideo->revision_id == 2)) {
5580 outSISIDXREG(SISSR, 0x19, 0x40);
5581 } else {
5582 outSISIDXREG(SISSR, 0x19, 0x20);
5583 }
5584 outSISIDXREG(SISSR, 0x16, 0x00);
5585 outSISIDXREG(SISSR, 0x16, 0x80);
5586 if((ivideo->chip == XGI_20) || (bios[0x1cb] != 0x0c)) {
5587 sisfb_post_xgi_delay(ivideo, 0x43);
5588 sisfb_post_xgi_delay(ivideo, 0x43);
5589 sisfb_post_xgi_delay(ivideo, 0x43);
5590 outSISIDXREG(SISSR, 0x18, 0x00);
5591 if((ivideo->chip == XGI_20) ||
5592 (ivideo->revision_id == 2)) {
5593 outSISIDXREG(SISSR, 0x19, 0x40);
5594 } else {
5595 outSISIDXREG(SISSR, 0x19, 0x20);
5596 }
5597 } else if((ivideo->chip == XGI_40) && (bios[0x1cb] == 0x0c)) {
5598 /* outSISIDXREG(SISSR, 0x16, 0x0c); */ /* ? */
5599 }
5600 outSISIDXREG(SISSR, 0x16, 0x00);
5601 outSISIDXREG(SISSR, 0x16, 0x80);
5602 sisfb_post_xgi_delay(ivideo, 4);
5603 v1 = 0x31; v2 = 0x03; v3 = 0x83; v4 = 0x03; v5 = 0x83;
5604 if(ivideo->haveXGIROM) {
5605 v1 = bios[0xf0];
5606 index = (ivideo->chip == XGI_20) ? 0x4b2 : 0x53e;
5607 v2 = bios[index];
5608 v3 = bios[index + 1];
5609 v4 = bios[index + 2];
5610 v5 = bios[index + 3];
5611 }
5612 outSISIDXREG(SISSR, 0x18, v1);
5613 outSISIDXREG(SISSR, 0x19, ((ivideo->chip == XGI_20) ? 0x02 : 0x01));
5614 outSISIDXREG(SISSR, 0x16, v2);
5615 outSISIDXREG(SISSR, 0x16, v3);
5616 sisfb_post_xgi_delay(ivideo, 0x43);
5617 outSISIDXREG(SISSR, 0x1b, 0x03);
5618 sisfb_post_xgi_delay(ivideo, 0x22);
5619 outSISIDXREG(SISSR, 0x18, v1);
5620 outSISIDXREG(SISSR, 0x19, 0x00);
5621 outSISIDXREG(SISSR, 0x16, v4);
5622 outSISIDXREG(SISSR, 0x16, v5);
5623 outSISIDXREG(SISSR, 0x1b, 0x00);
5624 break;
5625 case 1:
5626 outSISIDXREG(SISCR, 0x82, 0x77);
5627 outSISIDXREG(SISCR, 0x86, 0x00);
5628 inSISIDXREG(SISCR, 0x86, reg);
5629 outSISIDXREG(SISCR, 0x86, 0x88);
5630 inSISIDXREG(SISCR, 0x86, reg);
5631 v1 = cs168[regb]; v2 = cs160[regb]; v3 = cs158[regb];
5632 if(ivideo->haveXGIROM) {
5633 v1 = bios[regb + 0x168];
5634 v2 = bios[regb + 0x160];
5635 v3 = bios[regb + 0x158];
5636 }
5637 outSISIDXREG(SISCR, 0x86, v1);
5638 outSISIDXREG(SISCR, 0x82, 0x77);
5639 outSISIDXREG(SISCR, 0x85, 0x00);
5640 inSISIDXREG(SISCR, 0x85, reg);
5641 outSISIDXREG(SISCR, 0x85, 0x88);
5642 inSISIDXREG(SISCR, 0x85, reg);
5643 outSISIDXREG(SISCR, 0x85, v2);
5644 outSISIDXREG(SISCR, 0x82, v3);
5645 outSISIDXREG(SISCR, 0x98, 0x01);
5646 outSISIDXREG(SISCR, 0x9a, 0x02);
5647
5648 outSISIDXREG(SISSR, 0x28, 0x64);
5649 outSISIDXREG(SISSR, 0x29, 0x63);
5650 sisfb_post_xgi_delay(ivideo, 15);
5651 outSISIDXREG(SISSR, 0x18, 0x00);
5652 outSISIDXREG(SISSR, 0x19, 0x20);
5653 outSISIDXREG(SISSR, 0x16, 0x00);
5654 outSISIDXREG(SISSR, 0x16, 0x80);
5655 outSISIDXREG(SISSR, 0x18, 0xc5);
5656 outSISIDXREG(SISSR, 0x19, 0x23);
5657 outSISIDXREG(SISSR, 0x16, 0x00);
5658 outSISIDXREG(SISSR, 0x16, 0x80);
5659 sisfb_post_xgi_delay(ivideo, 1);
5660 outSISIDXREG(SISCR, 0x97,0x11);
5661 sisfb_post_xgi_setclocks(ivideo, regb);
5662 sisfb_post_xgi_delay(ivideo, 0x46);
5663 outSISIDXREG(SISSR, 0x18, 0xc5);
5664 outSISIDXREG(SISSR, 0x19, 0x23);
5665 outSISIDXREG(SISSR, 0x16, 0x00);
5666 outSISIDXREG(SISSR, 0x16, 0x80);
5667 sisfb_post_xgi_delay(ivideo, 1);
5668 outSISIDXREG(SISSR, 0x1b, 0x04);
5669 sisfb_post_xgi_delay(ivideo, 1);
5670 outSISIDXREG(SISSR, 0x1b, 0x00);
5671 sisfb_post_xgi_delay(ivideo, 1);
5672 v1 = 0x31;
5673 if(ivideo->haveXGIROM) {
5674 v1 = bios[0xf0];
5675 }
5676 outSISIDXREG(SISSR, 0x18, v1);
5677 outSISIDXREG(SISSR, 0x19, 0x06);
5678 outSISIDXREG(SISSR, 0x16, 0x04);
5679 outSISIDXREG(SISSR, 0x16, 0x84);
5680 sisfb_post_xgi_delay(ivideo, 1);
5681 break;
5682 default:
5683 sisfb_post_xgi_setclocks(ivideo, regb);
5684 if((ivideo->chip == XGI_40) &&
5685 ((ivideo->revision_id == 1) ||
5686 (ivideo->revision_id == 2))) {
5687 outSISIDXREG(SISCR, 0x82, bios[regb + 0x158]);
5688 outSISIDXREG(SISCR, 0x85, bios[regb + 0x160]);
5689 outSISIDXREG(SISCR, 0x86, bios[regb + 0x168]);
5690 } else {
5691 outSISIDXREG(SISCR, 0x82, 0x88);
5692 outSISIDXREG(SISCR, 0x86, 0x00);
5693 inSISIDXREG(SISCR, 0x86, reg);
5694 outSISIDXREG(SISCR, 0x86, 0x88);
5695 outSISIDXREG(SISCR, 0x82, 0x77);
5696 outSISIDXREG(SISCR, 0x85, 0x00);
5697 inSISIDXREG(SISCR, 0x85, reg);
5698 outSISIDXREG(SISCR, 0x85, 0x88);
5699 inSISIDXREG(SISCR, 0x85, reg);
5700 v1 = cs160[regb]; v2 = cs158[regb];
5701 if(ivideo->haveXGIROM) {
5702 v1 = bios[regb + 0x160];
5703 v2 = bios[regb + 0x158];
5704 }
5705 outSISIDXREG(SISCR, 0x85, v1);
5706 outSISIDXREG(SISCR, 0x82, v2);
5707 }
5708 if(ivideo->chip == XGI_40) {
5709 outSISIDXREG(SISCR, 0x97, 0x11);
5710 }
5711 if((ivideo->chip == XGI_40) && (ivideo->revision_id == 2)) {
5712 outSISIDXREG(SISCR, 0x98, 0x01);
5713 } else {
5714 outSISIDXREG(SISCR, 0x98, 0x03);
5715 }
5716 outSISIDXREG(SISCR, 0x9a, 0x02);
1da177e4 5717
544393fe
TW
5718 if(ivideo->chip == XGI_40) {
5719 outSISIDXREG(SISSR, 0x18, 0x01);
5720 } else {
5721 outSISIDXREG(SISSR, 0x18, 0x00);
5722 }
5723 outSISIDXREG(SISSR, 0x19, 0x40);
5724 outSISIDXREG(SISSR, 0x16, 0x00);
5725 outSISIDXREG(SISSR, 0x16, 0x80);
5726 if((ivideo->chip == XGI_40) && (bios[0x1cb] != 0x0c)) {
5727 sisfb_post_xgi_delay(ivideo, 0x43);
5728 sisfb_post_xgi_delay(ivideo, 0x43);
5729 sisfb_post_xgi_delay(ivideo, 0x43);
5730 outSISIDXREG(SISSR, 0x18, 0x00);
5731 outSISIDXREG(SISSR, 0x19, 0x40);
5732 outSISIDXREG(SISSR, 0x16, 0x00);
5733 outSISIDXREG(SISSR, 0x16, 0x80);
5734 }
5735 sisfb_post_xgi_delay(ivideo, 4);
5736 v1 = 0x31;
5737 if(ivideo->haveXGIROM) {
5738 v1 = bios[0xf0];
5739 }
5740 outSISIDXREG(SISSR, 0x18, v1);
5741 outSISIDXREG(SISSR, 0x19, 0x01);
5742 if(ivideo->chip == XGI_40) {
5743 outSISIDXREG(SISSR, 0x16, bios[0x53e]);
5744 outSISIDXREG(SISSR, 0x16, bios[0x53f]);
5745 } else {
5746 outSISIDXREG(SISSR, 0x16, 0x05);
5747 outSISIDXREG(SISSR, 0x16, 0x85);
5748 }
5749 sisfb_post_xgi_delay(ivideo, 0x43);
5750 if(ivideo->chip == XGI_40) {
5751 outSISIDXREG(SISSR, 0x1b, 0x01);
5752 } else {
5753 outSISIDXREG(SISSR, 0x1b, 0x03);
5754 }
5755 sisfb_post_xgi_delay(ivideo, 0x22);
5756 outSISIDXREG(SISSR, 0x18, v1);
5757 outSISIDXREG(SISSR, 0x19, 0x00);
5758 if(ivideo->chip == XGI_40) {
5759 outSISIDXREG(SISSR, 0x16, bios[0x540]);
5760 outSISIDXREG(SISSR, 0x16, bios[0x541]);
5761 } else {
5762 outSISIDXREG(SISSR, 0x16, 0x05);
5763 outSISIDXREG(SISSR, 0x16, 0x85);
5764 }
5765 outSISIDXREG(SISSR, 0x1b, 0x00);
1da177e4 5766 }
1da177e4 5767
544393fe
TW
5768 regb = 0; /* ! */
5769 v1 = 0x03;
5770 if(ivideo->haveXGIROM) {
5771 v1 = bios[0x110 + regb];
1da177e4 5772 }
544393fe 5773 outSISIDXREG(SISSR, 0x1b, v1);
1da177e4 5774
544393fe
TW
5775 /* RAM size */
5776 v1 = 0x00; v2 = 0x00;
5777 if(ivideo->haveXGIROM) {
5778 v1 = bios[0x62];
5779 v2 = bios[0x63];
1da177e4 5780 }
544393fe
TW
5781 regb = 0; /* ! */
5782 regd = 1 << regb;
5783 if((v1 & 0x40) && (v2 & regd) && ivideo->haveXGIROM) {
1da177e4 5784
544393fe
TW
5785 outSISIDXREG(SISSR, 0x13, bios[regb + 0xe0]);
5786 outSISIDXREG(SISSR, 0x14, bios[regb + 0xe0 + 8]);
1da177e4 5787
544393fe 5788 } else {
1da177e4 5789
544393fe
TW
5790 /* Set default mode, don't clear screen */
5791 ivideo->SiS_Pr.SiS_UseOEM = FALSE;
5792 SiS_SetEnableDstn(&ivideo->SiS_Pr, FALSE);
5793 SiS_SetEnableFstn(&ivideo->SiS_Pr, FALSE);
5794 ivideo->curFSTN = ivideo->curDSTN = 0;
5795 ivideo->SiS_Pr.VideoMemorySize = 8 << 20;
5796 SiSSetMode(&ivideo->SiS_Pr, 0x2e | 0x80);
1da177e4 5797
544393fe 5798 outSISIDXREG(SISSR, 0x05, 0x86);
1da177e4 5799
544393fe
TW
5800 /* Disable read-cache */
5801 andSISIDXREG(SISSR, 0x21, 0xdf);
5802 sisfb_post_xgi_ramsize(ivideo);
5803 /* Enable read-cache */
5804 orSISIDXREG(SISSR, 0x21, 0x20);
1da177e4 5805
544393fe 5806 }
1da177e4 5807
544393fe
TW
5808#if 0
5809 printk(KERN_DEBUG "-----------------\n");
5810 for(i = 0; i < 0xff; i++) {
5811 inSISIDXREG(SISCR, i, reg);
5812 printk(KERN_DEBUG "CR%02x(%x) = 0x%02x\n", i, SISCR, reg);
5813 }
5814 for(i = 0; i < 0x40; i++) {
5815 inSISIDXREG(SISSR, i, reg);
5816 printk(KERN_DEBUG "SR%02x(%x) = 0x%02x\n", i, SISSR, reg);
5817 }
5818 printk(KERN_DEBUG "-----------------\n");
5819#endif
1da177e4 5820
544393fe
TW
5821 /* Sense CRT1 */
5822 if(ivideo->chip == XGI_20) {
5823 orSISIDXREG(SISCR, 0x32, 0x20);
1da177e4 5824 } else {
544393fe
TW
5825 inSISIDXREG(SISPART4, 0x00, reg);
5826 if((reg == 1) || (reg == 2)) {
5827 sisfb_sense_crt1(ivideo);
5828 } else {
5829 orSISIDXREG(SISCR, 0x32, 0x20);
5830 }
1da177e4
LT
5831 }
5832
544393fe
TW
5833 /* Set default mode, don't clear screen */
5834 ivideo->SiS_Pr.SiS_UseOEM = FALSE;
5835 SiS_SetEnableDstn(&ivideo->SiS_Pr, FALSE);
5836 SiS_SetEnableFstn(&ivideo->SiS_Pr, FALSE);
5837 ivideo->curFSTN = ivideo->curDSTN = 0;
5838 SiSSetMode(&ivideo->SiS_Pr, 0x2e | 0x80);
5839
5840 outSISIDXREG(SISSR, 0x05, 0x86);
5841
5842 /* Display off */
5843 orSISIDXREG(SISSR, 0x01, 0x20);
5844
5845 /* Save mode number in CR34 */
5846 outSISIDXREG(SISCR, 0x34, 0x2e);
5847
5848 /* Let everyone know what the current mode is */
5849 ivideo->modeprechange = 0x2e;
5850
5851 if(ivideo->chip == XGI_40) {
5852 inSISIDXREG(SISCR, 0xca, reg);
5853 inSISIDXREG(SISCR, 0xcc, v1);
5854 if((reg & 0x10) && (!(v1 & 0x04))) {
5855 printk(KERN_ERR
5856 "sisfb: Please connect power to the card.\n");
5857 return 0;
5858 }
1da177e4 5859 }
1da177e4 5860
544393fe 5861 return 1;
1da177e4
LT
5862}
5863#endif
5864
544393fe
TW
5865static int __devinit
5866sisfb_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
1da177e4 5867{
544393fe
TW
5868 struct sisfb_chip_info *chipinfo = &sisfb_chip_info[ent->driver_data];
5869 struct sis_video_info *ivideo = NULL;
5870 struct fb_info *sis_fb_info = NULL;
1da177e4
LT
5871 u16 reg16;
5872 u8 reg;
544393fe 5873 int i, ret;
1da177e4 5874
544393fe
TW
5875 if(sisfb_off)
5876 return -ENXIO;
1da177e4
LT
5877
5878#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,3))
5879 sis_fb_info = framebuffer_alloc(sizeof(*ivideo), &pdev->dev);
544393fe
TW
5880 if(!sis_fb_info)
5881 return -ENOMEM;
1da177e4
LT
5882#else
5883 sis_fb_info = kmalloc(sizeof(*sis_fb_info) + sizeof(*ivideo), GFP_KERNEL);
544393fe
TW
5884 if(!sis_fb_info)
5885 return -ENOMEM;
1da177e4
LT
5886 memset(sis_fb_info, 0, sizeof(*sis_fb_info) + sizeof(*ivideo));
5887 sis_fb_info->par = ((char *)sis_fb_info + sizeof(*sis_fb_info));
5888#endif
5889
5890 ivideo = (struct sis_video_info *)sis_fb_info->par;
5891 ivideo->memyselfandi = sis_fb_info;
5892
544393fe
TW
5893 ivideo->sisfb_id = SISFB_ID;
5894
1da177e4 5895 if(card_list == NULL) {
544393fe 5896 ivideo->cardnumber = 0;
1da177e4 5897 } else {
544393fe
TW
5898 struct sis_video_info *countvideo = card_list;
5899 ivideo->cardnumber = 1;
5900 while((countvideo = countvideo->next) != 0)
5901 ivideo->cardnumber++;
1da177e4
LT
5902 }
5903
5904 strncpy(ivideo->myid, chipinfo->chip_name, 30);
5905
5906 ivideo->warncount = 0;
5907 ivideo->chip_id = pdev->device;
544393fe 5908 ivideo->chip_vendor = pdev->vendor;
1da177e4 5909 pci_read_config_byte(pdev, PCI_REVISION_ID, &ivideo->revision_id);
544393fe 5910 ivideo->SiS_Pr.ChipRevision = ivideo->revision_id;
1da177e4 5911 pci_read_config_word(pdev, PCI_COMMAND, &reg16);
544393fe 5912 ivideo->sisvga_enabled = reg16 & 0x01;
1da177e4
LT
5913 ivideo->pcibus = pdev->bus->number;
5914 ivideo->pcislot = PCI_SLOT(pdev->devfn);
5915 ivideo->pcifunc = PCI_FUNC(pdev->devfn);
5916 ivideo->subsysvendor = pdev->subsystem_vendor;
5917 ivideo->subsysdevice = pdev->subsystem_device;
544393fe
TW
5918#ifdef SIS_OLD_CONFIG_COMPAT
5919 ivideo->ioctl32registered = 0;
5920#endif
1da177e4
LT
5921
5922#ifndef MODULE
5923 if(sisfb_mode_idx == -1) {
5924 sisfb_get_vga_mode_from_kernel();
5925 }
5926#endif
5927
5928 ivideo->chip = chipinfo->chip;
5929 ivideo->sisvga_engine = chipinfo->vgaengine;
5930 ivideo->hwcursor_size = chipinfo->hwcursor_size;
5931 ivideo->CRT2_write_enable = chipinfo->CRT2_write_enable;
5932 ivideo->mni = chipinfo->mni;
5933
5934 ivideo->detectedpdc = 0xff;
5935 ivideo->detectedpdca = 0xff;
5936 ivideo->detectedlcda = 0xff;
5937
5938 ivideo->sisfb_thismonitor.datavalid = FALSE;
5939
544393fe
TW
5940 ivideo->current_base = 0;
5941
5942 ivideo->engineok = 0;
5943
5944 ivideo->sisfb_was_boot_device = 0;
5945#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,12))
5946 if(pdev->resource[PCI_ROM_RESOURCE].flags & IORESOURCE_ROM_SHADOW) {
5947 if(ivideo->sisvga_enabled)
5948 ivideo->sisfb_was_boot_device = 1;
5949 else {
5950 printk(KERN_DEBUG "sisfb: PCI device is disabled, "
5951 "but marked as boot video device ???\n");
5952 printk(KERN_DEBUG "sisfb: I will not accept this "
5953 "as the primary VGA device\n");
5954 }
5955 }
5956#endif
5957
1da177e4
LT
5958 ivideo->sisfb_parm_mem = sisfb_parm_mem;
5959 ivideo->sisfb_accel = sisfb_accel;
5960 ivideo->sisfb_ypan = sisfb_ypan;
5961 ivideo->sisfb_max = sisfb_max;
5962 ivideo->sisfb_userom = sisfb_userom;
5963 ivideo->sisfb_useoem = sisfb_useoem;
5964 ivideo->sisfb_mode_idx = sisfb_mode_idx;
5965 ivideo->sisfb_parm_rate = sisfb_parm_rate;
5966 ivideo->sisfb_crt1off = sisfb_crt1off;
5967 ivideo->sisfb_forcecrt1 = sisfb_forcecrt1;
5968 ivideo->sisfb_crt2type = sisfb_crt2type;
5969 ivideo->sisfb_crt2flags = sisfb_crt2flags;
5970 /* pdc(a), scalelcd, special timing, lvdshl handled below */
5971 ivideo->sisfb_dstn = sisfb_dstn;
5972 ivideo->sisfb_fstn = sisfb_fstn;
5973 ivideo->sisfb_tvplug = sisfb_tvplug;
5974 ivideo->sisfb_tvstd = sisfb_tvstd;
5975 ivideo->tvxpos = sisfb_tvxposoffset;
5976 ivideo->tvypos = sisfb_tvyposoffset;
1da177e4
LT
5977 ivideo->sisfb_nocrt2rate = sisfb_nocrt2rate;
5978#if LINUX_VERSION_CODE <= KERNEL_VERSION(2,5,0)
5979 ivideo->sisfb_inverse = sisfb_inverse;
5980#endif
5981
5982 ivideo->refresh_rate = 0;
5983 if(ivideo->sisfb_parm_rate != -1) {
544393fe 5984 ivideo->refresh_rate = ivideo->sisfb_parm_rate;
1da177e4
LT
5985 }
5986
5987 ivideo->SiS_Pr.UsePanelScaler = sisfb_scalelcd;
5988 ivideo->SiS_Pr.CenterScreen = -1;
5989 ivideo->SiS_Pr.SiS_CustomT = sisfb_specialtiming;
5990 ivideo->SiS_Pr.LVDSHL = sisfb_lvdshl;
5991
5992 ivideo->SiS_Pr.SiS_Backup70xx = 0xff;
544393fe
TW
5993 ivideo->SiS_Pr.SiS_CHOverScan = -1;
5994 ivideo->SiS_Pr.SiS_ChSW = FALSE;
1da177e4
LT
5995 ivideo->SiS_Pr.SiS_UseLCDA = FALSE;
5996 ivideo->SiS_Pr.HaveEMI = FALSE;
5997 ivideo->SiS_Pr.HaveEMILCD = FALSE;
5998 ivideo->SiS_Pr.OverruleEMI = FALSE;
5999 ivideo->SiS_Pr.SiS_SensibleSR11 = FALSE;
6000 ivideo->SiS_Pr.SiS_MyCR63 = 0x63;
6001 ivideo->SiS_Pr.PDC = -1;
6002 ivideo->SiS_Pr.PDCA = -1;
544393fe 6003 ivideo->SiS_Pr.DDCPortMixup = FALSE;
1da177e4
LT
6004#ifdef CONFIG_FB_SIS_315
6005 if(ivideo->chip >= SIS_330) {
544393fe
TW
6006 ivideo->SiS_Pr.SiS_MyCR63 = 0x53;
6007 if(ivideo->chip >= SIS_661) {
6008 ivideo->SiS_Pr.SiS_SensibleSR11 = TRUE;
6009 }
1da177e4
LT
6010 }
6011#endif
6012
6013 memcpy(&ivideo->default_var, &my_default_var, sizeof(my_default_var));
6014
6015 pci_set_drvdata(pdev, ivideo);
6016
6017 /* Patch special cases */
6018 if((ivideo->nbridge = sisfb_get_northbridge(ivideo->chip))) {
6019 switch(ivideo->nbridge->device) {
6020#ifdef CONFIG_FB_SIS_300
6021 case PCI_DEVICE_ID_SI_730:
544393fe 6022 ivideo->chip = SIS_730;
1da177e4 6023 strcpy(ivideo->myid, "SiS 730");
544393fe 6024 break;
1da177e4
LT
6025#endif
6026#ifdef CONFIG_FB_SIS_315
6027 case PCI_DEVICE_ID_SI_651:
6028 /* ivideo->chip is ok */
6029 strcpy(ivideo->myid, "SiS 651");
6030 break;
6031 case PCI_DEVICE_ID_SI_740:
544393fe 6032 ivideo->chip = SIS_740;
1da177e4
LT
6033 strcpy(ivideo->myid, "SiS 740");
6034 break;
6035 case PCI_DEVICE_ID_SI_661:
544393fe 6036 ivideo->chip = SIS_661;
1da177e4
LT
6037 strcpy(ivideo->myid, "SiS 661");
6038 break;
6039 case PCI_DEVICE_ID_SI_741:
544393fe 6040 ivideo->chip = SIS_741;
1da177e4
LT
6041 strcpy(ivideo->myid, "SiS 741");
6042 break;
6043 case PCI_DEVICE_ID_SI_760:
544393fe 6044 ivideo->chip = SIS_760;
1da177e4
LT
6045 strcpy(ivideo->myid, "SiS 760");
6046 break;
544393fe
TW
6047 case PCI_DEVICE_ID_SI_761:
6048 ivideo->chip = SIS_761;
6049 strcpy(ivideo->myid, "SiS 761");
6050 break;
1da177e4 6051#endif
544393fe
TW
6052 default:
6053 break;
1da177e4
LT
6054 }
6055 }
6056
6057#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
6058 strcpy(sis_fb_info->modename, ivideo->myid);
6059#endif
6060
544393fe
TW
6061 ivideo->SiS_Pr.ChipType = ivideo->chip;
6062
6063 ivideo->SiS_Pr.ivideo = (void *)ivideo;
1da177e4
LT
6064
6065#ifdef CONFIG_FB_SIS_315
544393fe
TW
6066 if((ivideo->SiS_Pr.ChipType == SIS_315PRO) ||
6067 (ivideo->SiS_Pr.ChipType == SIS_315)) {
6068 ivideo->SiS_Pr.ChipType = SIS_315H;
1da177e4
LT
6069 }
6070#endif
6071
544393fe
TW
6072 if(!ivideo->sisvga_enabled) {
6073 if(pci_enable_device(pdev)) {
6074 if(ivideo->nbridge) SIS_PCI_PUT_DEVICE(ivideo->nbridge);
6075 pci_set_drvdata(pdev, NULL);
6076 kfree(sis_fb_info);
6077 return -EIO;
6078 }
6079 }
6080
1da177e4
LT
6081 ivideo->video_base = pci_resource_start(pdev, 0);
6082 ivideo->mmio_base = pci_resource_start(pdev, 1);
6083 ivideo->mmio_size = pci_resource_len(pdev, 1);
544393fe
TW
6084 ivideo->SiS_Pr.RelIO = pci_resource_start(pdev, 2) + 0x30;
6085 ivideo->SiS_Pr.IOAddress = ivideo->vga_base = ivideo->SiS_Pr.RelIO;
1da177e4 6086
544393fe 6087 SiSRegInit(&ivideo->SiS_Pr, ivideo->SiS_Pr.IOAddress);
1da177e4
LT
6088
6089#ifdef CONFIG_FB_SIS_300
6090 /* Find PCI systems for Chrontel/GPIO communication setup */
6091 if(ivideo->chip == SIS_630) {
544393fe
TW
6092 i = 0;
6093 do {
6094 if(mychswtable[i].subsysVendor == ivideo->subsysvendor &&
6095 mychswtable[i].subsysCard == ivideo->subsysdevice) {
6096 ivideo->SiS_Pr.SiS_ChSW = TRUE;
6097 printk(KERN_DEBUG "sisfb: Identified [%s %s] "
6098 "requiring Chrontel/GPIO setup\n",
6099 mychswtable[i].vendorName,
6100 mychswtable[i].cardName);
6101 ivideo->lpcdev = SIS_PCI_GET_DEVICE(PCI_VENDOR_ID_SI, 0x0008, NULL);
6102 break;
6103 }
6104 i++;
6105 } while(mychswtable[i].subsysVendor != 0);
6106 }
6107#endif
6108
6109#ifdef CONFIG_FB_SIS_315
6110 if((ivideo->chip == SIS_760) && (ivideo->nbridge)) {
6111 ivideo->lpcdev = SIS_PCI_GET_SLOT(ivideo->nbridge->bus, (2 << 3));
1da177e4
LT
6112 }
6113#endif
6114
544393fe 6115 outSISIDXREG(SISSR, 0x05, 0x86);
1da177e4 6116
544393fe 6117 if( (!ivideo->sisvga_enabled)
1da177e4 6118#if !defined(__i386__) && !defined(__x86_64__)
544393fe 6119 || (sisfb_resetcard)
1da177e4 6120#endif
544393fe
TW
6121 ) {
6122 for(i = 0x30; i <= 0x3f; i++) {
6123 outSISIDXREG(SISCR, i, 0x00);
6124 }
1da177e4
LT
6125 }
6126
6127 /* Find out about current video mode */
6128 ivideo->modeprechange = 0x03;
544393fe 6129 inSISIDXREG(SISCR, 0x34, reg);
1da177e4
LT
6130 if(reg & 0x7f) {
6131 ivideo->modeprechange = reg & 0x7f;
544393fe 6132 } else if(ivideo->sisvga_enabled) {
1da177e4 6133#if defined(__i386__) || defined(__x86_64__)
544393fe 6134 unsigned char SIS_IOTYPE2 *tt = ioremap(0x400, 0x100);
1da177e4 6135 if(tt) {
544393fe
TW
6136 ivideo->modeprechange = readb(tt + 0x49);
6137 iounmap(tt);
1da177e4
LT
6138 }
6139#endif
6140 }
6141
6142#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
6143#ifdef MODULE
6144 if((reg & 0x80) && (reg != 0xff)) {
544393fe
TW
6145 if((sisbios_mode[ivideo->sisfb_mode_idx].mode_no[ivideo->mni])
6146 != 0xFF) {
6147 printk(KERN_INFO "sisfb: Cannot initialize display mode, "
6148 "X server is active\n");
6149 ret = -EBUSY;
6150 goto error_4;
6151 }
1da177e4 6152 }
1da177e4 6153#endif
1da177e4
LT
6154#endif
6155
544393fe 6156 /* Search and copy ROM image */
1da177e4 6157 ivideo->bios_abase = NULL;
544393fe
TW
6158 ivideo->SiS_Pr.VirtualRomBase = NULL;
6159 ivideo->SiS_Pr.UseROM = FALSE;
6160 ivideo->haveXGIROM = ivideo->SiS_Pr.SiS_XGIROM = FALSE;
1da177e4 6161 if(ivideo->sisfb_userom) {
544393fe
TW
6162 ivideo->SiS_Pr.VirtualRomBase = sisfb_find_rom(pdev);
6163 ivideo->bios_abase = ivideo->SiS_Pr.VirtualRomBase;
6164 ivideo->SiS_Pr.UseROM = (ivideo->SiS_Pr.VirtualRomBase) ? TRUE : FALSE;
6165 printk(KERN_INFO "sisfb: Video ROM %sfound\n",
6166 ivideo->SiS_Pr.UseROM ? "" : "not ");
6167 if((ivideo->SiS_Pr.UseROM) && (ivideo->chip >= XGI_20)) {
6168 ivideo->SiS_Pr.UseROM = FALSE;
6169 ivideo->haveXGIROM = ivideo->SiS_Pr.SiS_XGIROM = TRUE;
6170 if( (ivideo->revision_id == 2) &&
6171 (!(ivideo->bios_abase[0x1d1] & 0x01)) ) {
6172 ivideo->SiS_Pr.DDCPortMixup = TRUE;
6173 }
6174 }
1da177e4 6175 } else {
544393fe 6176 printk(KERN_INFO "sisfb: Video ROM usage disabled\n");
1da177e4
LT
6177 }
6178
544393fe 6179 /* Find systems for special custom timing */
1da177e4 6180 if(ivideo->SiS_Pr.SiS_CustomT == CUT_NONE) {
544393fe 6181 sisfb_detect_custom_timing(ivideo);
1da177e4
LT
6182 }
6183
544393fe
TW
6184 /* POST card in case this has not been done by the BIOS */
6185 if( (!ivideo->sisvga_enabled)
1da177e4 6186#if !defined(__i386__) && !defined(__x86_64__)
544393fe 6187 || (sisfb_resetcard)
1da177e4 6188#endif
544393fe
TW
6189 ) {
6190#ifdef CONFIG_FB_SIS_300
6191 if(ivideo->sisvga_engine == SIS_300_VGA) {
1da177e4
LT
6192 if(ivideo->chip == SIS_300) {
6193 sisfb_post_sis300(pdev);
544393fe 6194 ivideo->sisfb_can_post = 1;
1da177e4
LT
6195 }
6196 }
1da177e4
LT
6197#endif
6198
6199#ifdef CONFIG_FB_SIS_315
544393fe
TW
6200 if(ivideo->sisvga_engine == SIS_315_VGA) {
6201 int result = 1;
6202 /* if((ivideo->chip == SIS_315H) ||
1da177e4
LT
6203 (ivideo->chip == SIS_315) ||
6204 (ivideo->chip == SIS_315PRO) ||
6205 (ivideo->chip == SIS_330)) {
6206 sisfb_post_sis315330(pdev);
544393fe
TW
6207 } else */ if(ivideo->chip == XGI_20) {
6208 result = sisfb_post_xgi(pdev);
6209 ivideo->sisfb_can_post = 1;
6210 } else if((ivideo->chip == XGI_40) && ivideo->haveXGIROM) {
6211 result = sisfb_post_xgi(pdev);
6212 ivideo->sisfb_can_post = 1;
6213 } else {
6214 printk(KERN_INFO "sisfb: Card is not "
6215 "POSTed and sisfb can't do this either.\n");
6216 }
6217 if(!result) {
6218 printk(KERN_ERR "sisfb: Failed to POST card\n");
6219 ret = -ENODEV;
6220 goto error_3;
1da177e4
LT
6221 }
6222 }
1da177e4 6223#endif
544393fe 6224 }
1da177e4 6225
544393fe
TW
6226 ivideo->sisfb_card_posted = 1;
6227
6228 /* Find out about RAM size */
1da177e4 6229 if(sisfb_get_dram_size(ivideo)) {
544393fe
TW
6230 printk(KERN_INFO "sisfb: Fatal error: Unable to determine VRAM size.\n");
6231 ret = -ENODEV;
6232 goto error_3;
1da177e4
LT
6233 }
6234
544393fe
TW
6235
6236 /* Enable PCI addressing and MMIO */
1da177e4
LT
6237 if((ivideo->sisfb_mode_idx < 0) ||
6238 ((sisbios_mode[ivideo->sisfb_mode_idx].mode_no[ivideo->mni]) != 0xFF)) {
544393fe
TW
6239 /* Enable PCI_LINEAR_ADDRESSING and MMIO_ENABLE */
6240 orSISIDXREG(SISSR, IND_SIS_PCI_ADDRESS_SET, (SIS_PCI_ADDR_ENABLE | SIS_MEM_MAP_IO_ENABLE));
6241 /* Enable 2D accelerator engine */
6242 orSISIDXREG(SISSR, IND_SIS_MODULE_ENABLE, SIS_ENABLE_2D);
1da177e4
LT
6243 }
6244
6245 if(sisfb_pdc != 0xff) {
544393fe
TW
6246 if(ivideo->sisvga_engine == SIS_300_VGA)
6247 sisfb_pdc &= 0x3c;
6248 else
6249 sisfb_pdc &= 0x1f;
6250 ivideo->SiS_Pr.PDC = sisfb_pdc;
1da177e4
LT
6251 }
6252#ifdef CONFIG_FB_SIS_315
6253 if(ivideo->sisvga_engine == SIS_315_VGA) {
544393fe
TW
6254 if(sisfb_pdca != 0xff)
6255 ivideo->SiS_Pr.PDCA = sisfb_pdca & 0x1f;
1da177e4
LT
6256 }
6257#endif
6258
6259 if(!request_mem_region(ivideo->video_base, ivideo->video_size, "sisfb FB")) {
544393fe
TW
6260 printk(KERN_ERR "sisfb: Fatal error: Unable to reserve %dMB framebuffer memory\n",
6261 (int)(ivideo->video_size >> 20));
1da177e4 6262 printk(KERN_ERR "sisfb: Is there another framebuffer driver active?\n");
544393fe
TW
6263 ret = -ENODEV;
6264 goto error_3;
1da177e4
LT
6265 }
6266
6267 if(!request_mem_region(ivideo->mmio_base, ivideo->mmio_size, "sisfb MMIO")) {
6268 printk(KERN_ERR "sisfb: Fatal error: Unable to reserve MMIO region\n");
544393fe
TW
6269 ret = -ENODEV;
6270 goto error_2;
1da177e4
LT
6271 }
6272
6273 ivideo->video_vbase = ioremap(ivideo->video_base, ivideo->video_size);
544393fe 6274 ivideo->SiS_Pr.VideoMemoryAddress = ivideo->video_vbase;
1da177e4 6275 if(!ivideo->video_vbase) {
544393fe
TW
6276 printk(KERN_ERR "sisfb: Fatal error: Unable to map framebuffer memory\n");
6277 ret = -ENODEV;
6278 goto error_1;
1da177e4
LT
6279 }
6280
6281 ivideo->mmio_vbase = ioremap(ivideo->mmio_base, ivideo->mmio_size);
6282 if(!ivideo->mmio_vbase) {
544393fe
TW
6283 printk(KERN_ERR "sisfb: Fatal error: Unable to map MMIO region\n");
6284 ret = -ENODEV;
6285error_0: iounmap(ivideo->video_vbase);
6286error_1: release_mem_region(ivideo->video_base, ivideo->video_size);
6287error_2: release_mem_region(ivideo->mmio_base, ivideo->mmio_size);
6288error_3: vfree(ivideo->bios_abase);
6289#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
6290error_4:
6291#endif
6292 if(ivideo->lpcdev)
6293 SIS_PCI_PUT_DEVICE(ivideo->lpcdev);
6294 if(ivideo->nbridge)
6295 SIS_PCI_PUT_DEVICE(ivideo->nbridge);
1da177e4 6296 pci_set_drvdata(pdev, NULL);
544393fe
TW
6297 if(!ivideo->sisvga_enabled)
6298 pci_disable_device(pdev);
6299 kfree(sis_fb_info);
6300 return ret;
1da177e4
LT
6301 }
6302
544393fe
TW
6303 printk(KERN_INFO "sisfb: Video RAM at 0x%lx, mapped to 0x%lx, size %ldk\n",
6304 ivideo->video_base, (unsigned long)ivideo->video_vbase, ivideo->video_size / 1024);
6305
6306 if(ivideo->video_offset) {
6307 printk(KERN_INFO "sisfb: Viewport offset %ldk\n",
6308 ivideo->video_offset / 1024);
6309 }
1da177e4
LT
6310
6311 printk(KERN_INFO "sisfb: MMIO at 0x%lx, mapped to 0x%lx, size %ldk\n",
544393fe
TW
6312 ivideo->mmio_base, (unsigned long)ivideo->mmio_vbase, ivideo->mmio_size / 1024);
6313
6314
6315 /* Determine the size of the command queue */
6316 if(ivideo->sisvga_engine == SIS_300_VGA) {
6317 ivideo->cmdQueueSize = TURBO_QUEUE_AREA_SIZE;
6318 } else {
6319 if(ivideo->chip == XGI_20) {
6320 ivideo->cmdQueueSize = COMMAND_QUEUE_AREA_SIZE_Z7;
6321 } else {
6322 ivideo->cmdQueueSize = COMMAND_QUEUE_AREA_SIZE;
6323 }
6324 }
1da177e4 6325
544393fe
TW
6326 /* Engines are no longer initialized here; this is
6327 * now done after the first mode-switch (if the
6328 * submitted var has its acceleration flags set).
6329 */
6330
6331 /* Calculate the base of the (unused) hw cursor */
6332 ivideo->hwcursor_vbase = ivideo->video_vbase
6333 + ivideo->video_size
6334 - ivideo->cmdQueueSize
6335 - ivideo->hwcursor_size;
6336 ivideo->caps |= HW_CURSOR_CAP;
6337
6338 /* Initialize offscreen memory manager */
1da177e4
LT
6339 if((ivideo->havenoheap = sisfb_heap_init(ivideo))) {
6340 printk(KERN_WARNING "sisfb: Failed to initialize offscreen memory heap\n");
6341 }
6342
6343 /* Used for clearing the screen only, therefore respect our mem limit */
544393fe
TW
6344 ivideo->SiS_Pr.VideoMemoryAddress += ivideo->video_offset;
6345 ivideo->SiS_Pr.VideoMemorySize = ivideo->sisfb_mem;
1da177e4 6346
544393fe 6347 ivideo->mtrr = -1;
1da177e4
LT
6348
6349 ivideo->vbflags = 0;
6350 ivideo->lcddefmodeidx = DEFAULT_LCDMODE;
6351 ivideo->tvdefmodeidx = DEFAULT_TVMODE;
6352 ivideo->defmodeidx = DEFAULT_MODE;
6353
544393fe
TW
6354 ivideo->newrom = 0;
6355 if(ivideo->chip < XGI_20) {
6356 if(ivideo->bios_abase) {
6357 ivideo->newrom = SiSDetermineROMLayout661(&ivideo->SiS_Pr);
6358 }
6359 }
1da177e4
LT
6360
6361 if((ivideo->sisfb_mode_idx < 0) ||
6362 ((sisbios_mode[ivideo->sisfb_mode_idx].mode_no[ivideo->mni]) != 0xFF)) {
6363
6364 sisfb_sense_crt1(ivideo);
6365
6366 sisfb_get_VB_type(ivideo);
6367
544393fe 6368 if(ivideo->vbflags2 & VB2_VIDEOBRIDGE) {
1da177e4
LT
6369 sisfb_detect_VB_connect(ivideo);
6370 }
6371
6372 ivideo->currentvbflags = ivideo->vbflags & (VB_VIDEOBRIDGE | TV_STANDARD);
6373
544393fe
TW
6374 /* Decide on which CRT2 device to use */
6375 if(ivideo->vbflags2 & VB2_VIDEOBRIDGE) {
6376 if(ivideo->sisfb_crt2type != -1) {
6377 if((ivideo->sisfb_crt2type == CRT2_LCD) &&
6378 (ivideo->vbflags & CRT2_LCD)) {
6379 ivideo->currentvbflags |= CRT2_LCD;
6380 } else if(ivideo->sisfb_crt2type != CRT2_LCD) {
6381 ivideo->currentvbflags |= ivideo->sisfb_crt2type;
6382 }
6383 } else {
6384 /* Chrontel 700x TV detection often unreliable, therefore
6385 * use a different default order on such machines
6386 */
6387 if((ivideo->sisvga_engine == SIS_300_VGA) &&
6388 (ivideo->vbflags2 & VB2_CHRONTEL)) {
6389 if(ivideo->vbflags & CRT2_LCD)
6390 ivideo->currentvbflags |= CRT2_LCD;
6391 else if(ivideo->vbflags & CRT2_TV)
6392 ivideo->currentvbflags |= CRT2_TV;
6393 else if(ivideo->vbflags & CRT2_VGA)
6394 ivideo->currentvbflags |= CRT2_VGA;
6395 } else {
6396 if(ivideo->vbflags & CRT2_TV)
6397 ivideo->currentvbflags |= CRT2_TV;
6398 else if(ivideo->vbflags & CRT2_LCD)
6399 ivideo->currentvbflags |= CRT2_LCD;
6400 else if(ivideo->vbflags & CRT2_VGA)
6401 ivideo->currentvbflags |= CRT2_VGA;
6402 }
6403 }
1da177e4
LT
6404 }
6405
6406 if(ivideo->vbflags & CRT2_LCD) {
544393fe 6407 sisfb_detect_lcd_type(ivideo);
1da177e4 6408 }
1da177e4 6409
544393fe 6410 sisfb_save_pdc_emi(ivideo);
1da177e4
LT
6411
6412 if(!ivideo->sisfb_crt1off) {
544393fe 6413 sisfb_handle_ddc(ivideo, &ivideo->sisfb_thismonitor, 0);
1da177e4 6414 } else {
544393fe
TW
6415 if((ivideo->vbflags2 & VB2_SISTMDSBRIDGE) &&
6416 (ivideo->vbflags & (CRT2_VGA | CRT2_LCD))) {
6417 sisfb_handle_ddc(ivideo, &ivideo->sisfb_thismonitor, 1);
6418 }
1da177e4
LT
6419 }
6420
6421 if(ivideo->sisfb_mode_idx >= 0) {
6422 int bu = ivideo->sisfb_mode_idx;
6423 ivideo->sisfb_mode_idx = sisfb_validate_mode(ivideo,
6424 ivideo->sisfb_mode_idx, ivideo->currentvbflags);
6425 if(bu != ivideo->sisfb_mode_idx) {
6426 printk(KERN_ERR "Mode %dx%dx%d failed validation\n",
6427 sisbios_mode[bu].xres,
6428 sisbios_mode[bu].yres,
6429 sisbios_mode[bu].bpp);
6430 }
6431 }
6432
6433 if(ivideo->sisfb_mode_idx < 0) {
6434 switch(ivideo->currentvbflags & VB_DISPTYPE_DISP2) {
6435 case CRT2_LCD:
6436 ivideo->sisfb_mode_idx = ivideo->lcddefmodeidx;
6437 break;
6438 case CRT2_TV:
6439 ivideo->sisfb_mode_idx = ivideo->tvdefmodeidx;
6440 break;
6441 default:
6442 ivideo->sisfb_mode_idx = ivideo->defmodeidx;
6443 break;
6444 }
6445 }
6446
6447 ivideo->mode_no = sisbios_mode[ivideo->sisfb_mode_idx].mode_no[ivideo->mni];
6448
6449 if(ivideo->refresh_rate != 0) {
544393fe
TW
6450 sisfb_search_refresh_rate(ivideo, ivideo->refresh_rate,
6451 ivideo->sisfb_mode_idx);
1da177e4
LT
6452 }
6453
6454 if(ivideo->rate_idx == 0) {
6455 ivideo->rate_idx = sisbios_mode[ivideo->sisfb_mode_idx].rate_idx;
6456 ivideo->refresh_rate = 60;
6457 }
6458
6459 if(ivideo->sisfb_thismonitor.datavalid) {
544393fe
TW
6460 if(!sisfb_verify_rate(ivideo, &ivideo->sisfb_thismonitor,
6461 ivideo->sisfb_mode_idx,
6462 ivideo->rate_idx,
6463 ivideo->refresh_rate)) {
6464 printk(KERN_INFO "sisfb: WARNING: Refresh rate "
6465 "exceeds monitor specs!\n");
1da177e4
LT
6466 }
6467 }
6468
6469 ivideo->video_bpp = sisbios_mode[ivideo->sisfb_mode_idx].bpp;
6470 ivideo->video_width = sisbios_mode[ivideo->sisfb_mode_idx].xres;
6471 ivideo->video_height = sisbios_mode[ivideo->sisfb_mode_idx].yres;
6472
6473 sisfb_set_vparms(ivideo);
1da177e4 6474
544393fe
TW
6475#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
6476
6477 /* ---------------- For 2.4: Now switch the mode ------------------ */
6478
6479 printk(KERN_INFO "sisfb: Setting mode %dx%dx%d (%dHz)\n",
6480 ivideo->video_width, ivideo->video_height, ivideo->video_bpp,
1da177e4
LT
6481 ivideo->refresh_rate);
6482
544393fe
TW
6483 /* Determine whether or not acceleration is to be
6484 * used. Need to know before pre/post_set_mode()
6485 */
6486 ivideo->accel = 0;
6487 ivideo->default_var.accel_flags &= ~FB_ACCELF_TEXT;
6488 if(ivideo->sisfb_accel) {
6489 ivideo->accel = -1;
6490 ivideo->default_var.accel_flags |= FB_ACCELF_TEXT;
6491 }
6492
6493 /* Now switch the mode */
1da177e4
LT
6494 sisfb_pre_setmode(ivideo);
6495
544393fe 6496 if(SiSSetMode(&ivideo->SiS_Pr, ivideo->mode_no) == 0) {
1da177e4
LT
6497 printk(KERN_ERR "sisfb: Fatal error: Setting mode[0x%x] failed\n",
6498 ivideo->mode_no);
544393fe 6499 ret = -EINVAL;
1da177e4 6500 iounmap(ivideo->mmio_vbase);
544393fe 6501 goto error_0;
1da177e4
LT
6502 }
6503
6504 outSISIDXREG(SISSR, IND_SIS_PASSWORD, SIS_PASSWORD);
6505
6506 sisfb_post_setmode(ivideo);
6507
6508 /* Maximize regardless of sisfb_max at startup */
6509 ivideo->default_var.yres_virtual = 32767;
6510
6511 /* Force reset of x virtual in crtc_to_var */
6512 ivideo->default_var.xres_virtual = 0;
6513
544393fe 6514 /* Copy mode timing to var */
1da177e4
LT
6515 sisfb_crtc_to_var(ivideo, &ivideo->default_var);
6516
544393fe 6517 /* Find out about screen pitch */
1da177e4
LT
6518 sisfb_calc_pitch(ivideo, &ivideo->default_var);
6519 sisfb_set_pitch(ivideo);
6520
544393fe 6521 /* Init the accelerator (does nothing currently) */
1da177e4 6522 sisfb_initaccel(ivideo);
544393fe
TW
6523
6524 /* Init some fbinfo entries */
1da177e4
LT
6525 sis_fb_info->node = -1;
6526 sis_fb_info->flags = FBINFO_FLAG_DEFAULT;
6527 sis_fb_info->fbops = &sisfb_ops;
6528 sis_fb_info->disp = &ivideo->sis_disp;
6529 sis_fb_info->blank = &sisfb_blank;
6530 sis_fb_info->switch_con = &sisfb_switch;
6531 sis_fb_info->updatevar = &sisfb_update_var;
6532 sis_fb_info->changevar = NULL;
6533 strcpy(sis_fb_info->fontname, sisfb_fontname);
6534
6535 sisfb_set_disp(-1, &ivideo->default_var, sis_fb_info);
6536
6537#else /* --------- For 2.6: Setup a somewhat sane default var ------------ */
6538
6539 printk(KERN_INFO "sisfb: Default mode is %dx%dx%d (%dHz)\n",
544393fe 6540 ivideo->video_width, ivideo->video_height, ivideo->video_bpp,
1da177e4
LT
6541 ivideo->refresh_rate);
6542
544393fe 6543 /* Set up the default var according to chosen default display mode */
1da177e4
LT
6544 ivideo->default_var.xres = ivideo->default_var.xres_virtual = ivideo->video_width;
6545 ivideo->default_var.yres = ivideo->default_var.yres_virtual = ivideo->video_height;
6546 ivideo->default_var.bits_per_pixel = ivideo->video_bpp;
6547
6548 sisfb_bpp_to_var(ivideo, &ivideo->default_var);
544393fe 6549
1da177e4 6550 ivideo->default_var.pixclock = (u32) (1000000000 /
544393fe
TW
6551 sisfb_mode_rate_to_dclock(&ivideo->SiS_Pr, ivideo->mode_no, ivideo->rate_idx));
6552
6553 if(sisfb_mode_rate_to_ddata(&ivideo->SiS_Pr, ivideo->mode_no,
6554 ivideo->rate_idx, &ivideo->default_var)) {
6555 if((ivideo->default_var.vmode & FB_VMODE_MASK) == FB_VMODE_DOUBLE) {
6556 ivideo->default_var.pixclock <<= 1;
6557 }
6558 }
1da177e4
LT
6559
6560 if(ivideo->sisfb_ypan) {
544393fe
TW
6561 /* Maximize regardless of sisfb_max at startup */
6562 ivideo->default_var.yres_virtual =
6563 sisfb_calc_maxyres(ivideo, &ivideo->default_var);
6564 if(ivideo->default_var.yres_virtual < ivideo->default_var.yres) {
6565 ivideo->default_var.yres_virtual = ivideo->default_var.yres;
6566 }
1da177e4
LT
6567 }
6568
6569 sisfb_calc_pitch(ivideo, &ivideo->default_var);
6570
6571 ivideo->accel = 0;
6572 if(ivideo->sisfb_accel) {
544393fe 6573 ivideo->accel = -1;
1da177e4 6574#ifdef STUPID_ACCELF_TEXT_SHIT
544393fe 6575 ivideo->default_var.accel_flags |= FB_ACCELF_TEXT;
1da177e4
LT
6576#endif
6577 }
6578 sisfb_initaccel(ivideo);
6579
6580#if defined(FBINFO_HWACCEL_DISABLED) && defined(FBINFO_HWACCEL_XPAN)
6581 sis_fb_info->flags = FBINFO_DEFAULT |
6582 FBINFO_HWACCEL_YPAN |
6583 FBINFO_HWACCEL_XPAN |
6584 FBINFO_HWACCEL_COPYAREA |
6585 FBINFO_HWACCEL_FILLRECT |
6586 ((ivideo->accel) ? 0 : FBINFO_HWACCEL_DISABLED);
6587#else
6588 sis_fb_info->flags = FBINFO_FLAG_DEFAULT;
6589#endif
6590 sis_fb_info->var = ivideo->default_var;
6591 sis_fb_info->fix = ivideo->sisfb_fix;
544393fe 6592 sis_fb_info->screen_base = ivideo->video_vbase + ivideo->video_offset;
1da177e4
LT
6593 sis_fb_info->fbops = &sisfb_ops;
6594
6595 sisfb_get_fix(&sis_fb_info->fix, -1, sis_fb_info);
6596 sis_fb_info->pseudo_palette = ivideo->pseudo_palette;
544393fe 6597
1da177e4
LT
6598 fb_alloc_cmap(&sis_fb_info->cmap, 256 , 0);
6599#endif /* 2.6 */
6600
544393fe 6601 printk(KERN_DEBUG "sisfb: Initial vbflags 0x%x\n", (int)ivideo->vbflags);
1da177e4
LT
6602
6603#ifdef CONFIG_MTRR
6604 ivideo->mtrr = mtrr_add(ivideo->video_base, ivideo->video_size,
6605 MTRR_TYPE_WRCOMB, 1);
544393fe 6606 if(ivideo->mtrr < 0) {
1da177e4
LT
6607 printk(KERN_DEBUG "sisfb: Failed to add MTRRs\n");
6608 }
6609#endif
6610
6611#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
6612 vc_resize_con(1, 1, 0);
6613#endif
6614
6615 if(register_framebuffer(sis_fb_info) < 0) {
6616 printk(KERN_ERR "sisfb: Fatal error: Failed to register framebuffer\n");
544393fe 6617 ret = -EINVAL;
1da177e4 6618 iounmap(ivideo->mmio_vbase);
544393fe 6619 goto error_0;
1da177e4
LT
6620 }
6621
6622 ivideo->registered = 1;
6623
6624 /* Enlist us */
6625 ivideo->next = card_list;
6626 card_list = ivideo;
6627
544393fe
TW
6628#ifdef SIS_OLD_CONFIG_COMPAT
6629 {
6630 int ret;
6631 /* Our ioctls are all "32/64bit compatible" */
6632 ret = register_ioctl32_conversion(FBIO_ALLOC, NULL);
6633 ret |= register_ioctl32_conversion(FBIO_FREE, NULL);
6634 ret |= register_ioctl32_conversion(FBIOGET_VBLANK, NULL);
6635 ret |= register_ioctl32_conversion(SISFB_GET_INFO_SIZE, NULL);
6636 ret |= register_ioctl32_conversion(SISFB_GET_INFO, NULL);
6637 ret |= register_ioctl32_conversion(SISFB_GET_TVPOSOFFSET, NULL);
6638 ret |= register_ioctl32_conversion(SISFB_SET_TVPOSOFFSET, NULL);
6639 ret |= register_ioctl32_conversion(SISFB_SET_LOCK, NULL);
6640 ret |= register_ioctl32_conversion(SISFB_GET_VBRSTATUS, NULL);
6641 ret |= register_ioctl32_conversion(SISFB_GET_AUTOMAXIMIZE, NULL);
6642 ret |= register_ioctl32_conversion(SISFB_SET_AUTOMAXIMIZE, NULL);
6643 ret |= register_ioctl32_conversion(SISFB_COMMAND, NULL);
6644 if(ret)
6645 printk(KERN_ERR
6646 "sisfb: Error registering ioctl32 translations\n");
6647 else
6648 ivideo->ioctl32registered = 1;
6649 }
6650#endif
6651
1da177e4 6652 printk(KERN_INFO "sisfb: 2D acceleration is %s, y-panning %s\n",
544393fe
TW
6653 ivideo->sisfb_accel ? "enabled" : "disabled",
6654 ivideo->sisfb_ypan ?
6655 (ivideo->sisfb_max ? "enabled (auto-max)" :
6656 "enabled (no auto-max)") :
6657 "disabled");
1da177e4
LT
6658
6659
544393fe 6660 printk(KERN_INFO "fb%d: %s frame buffer device version %d.%d.%d\n",
1da177e4 6661#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
544393fe 6662 GET_FB_IDX(sis_fb_info->node),
1da177e4 6663#else
544393fe 6664 sis_fb_info->node,
1da177e4
LT
6665#endif
6666 ivideo->myid, VER_MAJOR, VER_MINOR, VER_LEVEL);
6667
544393fe 6668 printk(KERN_INFO "sisfb: Copyright (C) 2001-2005 Thomas Winischhofer\n");
1da177e4
LT
6669
6670 } /* if mode = "none" */
6671
6672 return 0;
6673}
6674
6675/*****************************************************/
6676/* PCI DEVICE HANDLING */
6677/*****************************************************/
6678
6679static void __devexit sisfb_remove(struct pci_dev *pdev)
6680{
544393fe
TW
6681 struct sis_video_info *ivideo = pci_get_drvdata(pdev);
6682 struct fb_info *sis_fb_info = ivideo->memyselfandi;
6683 int registered = ivideo->registered;
6684 int modechanged = ivideo->modechanged;
6685
6686#ifdef SIS_OLD_CONFIG_COMPAT
6687 if(ivideo->ioctl32registered) {
6688 int ret;
6689 ret = unregister_ioctl32_conversion(FBIO_ALLOC);
6690 ret |= unregister_ioctl32_conversion(FBIO_FREE);
6691 ret |= unregister_ioctl32_conversion(FBIOGET_VBLANK);
6692 ret |= unregister_ioctl32_conversion(SISFB_GET_INFO_SIZE);
6693 ret |= unregister_ioctl32_conversion(SISFB_GET_INFO);
6694 ret |= unregister_ioctl32_conversion(SISFB_GET_TVPOSOFFSET);
6695 ret |= unregister_ioctl32_conversion(SISFB_SET_TVPOSOFFSET);
6696 ret |= unregister_ioctl32_conversion(SISFB_SET_LOCK);
6697 ret |= unregister_ioctl32_conversion(SISFB_GET_VBRSTATUS);
6698 ret |= unregister_ioctl32_conversion(SISFB_GET_AUTOMAXIMIZE);
6699 ret |= unregister_ioctl32_conversion(SISFB_SET_AUTOMAXIMIZE);
6700 ret |= unregister_ioctl32_conversion(SISFB_COMMAND);
6701 if(ret)
6702 printk(KERN_ERR
6703 "sisfb: Error unregistering ioctl32 translations\n");
6704 }
6705#endif
1da177e4
LT
6706
6707 /* Unmap */
1da177e4 6708 iounmap(ivideo->mmio_vbase);
544393fe 6709 iounmap(ivideo->video_vbase);
1da177e4
LT
6710
6711 /* Release mem regions */
6712 release_mem_region(ivideo->video_base, ivideo->video_size);
6713 release_mem_region(ivideo->mmio_base, ivideo->mmio_size);
6714
544393fe
TW
6715 vfree(ivideo->bios_abase);
6716
6717 if(ivideo->lpcdev)
6718 SIS_PCI_PUT_DEVICE(ivideo->lpcdev);
6719
6720 if(ivideo->nbridge)
6721 SIS_PCI_PUT_DEVICE(ivideo->nbridge);
6722
1da177e4
LT
6723#ifdef CONFIG_MTRR
6724 /* Release MTRR region */
544393fe 6725 if(ivideo->mtrr >= 0)
1da177e4 6726 mtrr_del(ivideo->mtrr, ivideo->video_base, ivideo->video_size);
1da177e4
LT
6727#endif
6728
544393fe
TW
6729 pci_set_drvdata(pdev, NULL);
6730
6731 /* If device was disabled when starting, disable
6732 * it when quitting.
6733 */
6734 if(!ivideo->sisvga_enabled)
6735 pci_disable_device(pdev);
6736
1da177e4
LT
6737 /* Unregister the framebuffer */
6738 if(ivideo->registered) {
6739 unregister_framebuffer(sis_fb_info);
6740#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,3))
6741 framebuffer_release(sis_fb_info);
6742#else
6743 kfree(sis_fb_info);
6744#endif
6745 }
6746
544393fe 6747 /* OK, our ivideo is gone for good from here. */
1da177e4
LT
6748
6749 /* TODO: Restore the initial mode
6750 * This sounds easy but is as good as impossible
6751 * on many machines with SiS chip and video bridge
6752 * since text modes are always set up differently
6753 * from machine to machine. Depends on the type
6754 * of integration between chipset and bridge.
6755 */
544393fe
TW
6756 if(registered && modechanged)
6757 printk(KERN_INFO
6758 "sisfb: Restoring of text mode not supported yet\n");
1da177e4
LT
6759};
6760
6761static struct pci_driver sisfb_driver = {
6762 .name = "sisfb",
6763 .id_table = sisfb_pci_table,
544393fe 6764 .probe = sisfb_probe,
1da177e4
LT
6765 .remove = __devexit_p(sisfb_remove)
6766};
6767
6768SISINITSTATIC int __init sisfb_init(void)
6769{
6770#if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,8)
6771#ifndef MODULE
6772 char *options = NULL;
6773
6774 if(fb_get_options("sisfb", &options))
6775 return -ENODEV;
544393fe 6776
1da177e4
LT
6777 sisfb_setup(options);
6778#endif
6779#endif
544393fe 6780 return pci_register_driver(&sisfb_driver);
1da177e4
LT
6781}
6782
6783#if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,8)
6784#ifndef MODULE
6785module_init(sisfb_init);
6786#endif
6787#endif
6788
6789/*****************************************************/
6790/* MODULE */
6791/*****************************************************/
6792
6793#ifdef MODULE
6794
544393fe
TW
6795static char *mode = NULL;
6796static int vesa = -1;
6797static unsigned int rate = 0;
6798static unsigned int crt1off = 1;
6799static unsigned int mem = 0;
6800static char *forcecrt2type = NULL;
6801static int forcecrt1 = -1;
6802static int pdc = -1;
6803static int pdc1 = -1;
6804static int noaccel = -1;
6805static int noypan = -1;
6806static int nomax = -1;
6807#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
6808static int inverse = 0;
6809#endif
6810static int userom = -1;
6811static int useoem = -1;
6812static char *tvstandard = NULL;
6813static int nocrt2rate = 0;
6814static int scalelcd = -1;
6815static char *specialtiming = NULL;
6816static int lvdshl = -1;
6817static int tvxposoffset = 0, tvyposoffset = 0;
6818#if !defined(__i386__) && !defined(__x86_64__)
6819static int resetcard = 0;
6820static int videoram = 0;
6821#endif
6822
6823static int __init sisfb_init_module(void)
6824{
6825 sisfb_setdefaultparms();
6826
6827 if(rate)
6828 sisfb_parm_rate = rate;
6829
6830 if((scalelcd == 0) || (scalelcd == 1))
6831 sisfb_scalelcd = scalelcd ^ 1;
6832
6833 /* Need to check crt2 type first for fstn/dstn */
6834
6835 if(forcecrt2type)
6836 sisfb_search_crt2type(forcecrt2type);
6837
6838 if(tvstandard)
6839 sisfb_search_tvstd(tvstandard);
6840
6841 if(mode)
6842 sisfb_search_mode(mode, FALSE);
6843 else if(vesa != -1)
6844 sisfb_search_vesamode(vesa, FALSE);
6845
6846 sisfb_crt1off = (crt1off == 0) ? 1 : 0;
6847
6848 sisfb_forcecrt1 = forcecrt1;
6849 if(forcecrt1 == 1)
6850 sisfb_crt1off = 0;
6851 else if(forcecrt1 == 0)
6852 sisfb_crt1off = 1;
6853
6854 if(noaccel == 1)
6855 sisfb_accel = 0;
6856 else if(noaccel == 0)
6857 sisfb_accel = 1;
6858
6859 if(noypan == 1)
6860 sisfb_ypan = 0;
6861 else if(noypan == 0)
6862 sisfb_ypan = 1;
6863
6864 if(nomax == 1)
6865 sisfb_max = 0;
6866 else if(nomax == 0)
6867 sisfb_max = 1;
6868
1da177e4 6869#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
544393fe
TW
6870 if(inverse) sisfb_inverse = 1;
6871#endif
6872
6873 if(mem)
6874 sisfb_parm_mem = mem;
6875
6876 if(userom != -1)
6877 sisfb_userom = userom;
6878
6879 if(useoem != -1)
6880 sisfb_useoem = useoem;
6881
6882 if(pdc != -1)
6883 sisfb_pdc = (pdc & 0x7f);
6884
6885 if(pdc1 != -1)
6886 sisfb_pdca = (pdc1 & 0x1f);
6887
6888 sisfb_nocrt2rate = nocrt2rate;
6889
6890 if(specialtiming)
6891 sisfb_search_specialtiming(specialtiming);
6892
6893 if((lvdshl >= 0) && (lvdshl <= 3))
6894 sisfb_lvdshl = lvdshl;
6895
6896 sisfb_tvxposoffset = tvxposoffset;
6897 sisfb_tvyposoffset = tvyposoffset;
6898
1da177e4 6899#if !defined(__i386__) && !defined(__x86_64__)
544393fe
TW
6900 sisfb_resetcard = (resetcard) ? 1 : 0;
6901 if(videoram)
6902 sisfb_videoram = videoram;
1da177e4
LT
6903#endif
6904
544393fe
TW
6905 return sisfb_init();
6906}
6907
6908static void __exit sisfb_remove_module(void)
6909{
6910 pci_unregister_driver(&sisfb_driver);
6911 printk(KERN_DEBUG "sisfb: Module unloaded\n");
6912}
6913
6914module_init(sisfb_init_module);
6915module_exit(sisfb_remove_module);
6916
6917MODULE_DESCRIPTION("SiS 300/540/630/730/315/55x/65x/661/74x/330/76x/34x, XGI V3XT/V5/V8/Z7 framebuffer device driver");
1da177e4
LT
6918MODULE_LICENSE("GPL");
6919MODULE_AUTHOR("Thomas Winischhofer <thomas@winischhofer.net>, Others");
6920
6921#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
6922MODULE_PARM(mem, "i");
6923MODULE_PARM(noaccel, "i");
6924MODULE_PARM(noypan, "i");
6925MODULE_PARM(nomax, "i");
6926MODULE_PARM(userom, "i");
6927MODULE_PARM(useoem, "i");
6928MODULE_PARM(mode, "s");
6929MODULE_PARM(vesa, "i");
6930MODULE_PARM(rate, "i");
6931MODULE_PARM(forcecrt1, "i");
6932MODULE_PARM(forcecrt2type, "s");
6933MODULE_PARM(scalelcd, "i");
6934MODULE_PARM(pdc, "i");
6935MODULE_PARM(pdc1, "i");
6936MODULE_PARM(specialtiming, "s");
6937MODULE_PARM(lvdshl, "i");
6938MODULE_PARM(tvstandard, "s");
6939MODULE_PARM(tvxposoffset, "i");
6940MODULE_PARM(tvyposoffset, "i");
1da177e4
LT
6941MODULE_PARM(nocrt2rate, "i");
6942MODULE_PARM(inverse, "i");
6943#if !defined(__i386__) && !defined(__x86_64__)
6944MODULE_PARM(resetcard, "i");
6945MODULE_PARM(videoram, "i");
6946#endif
6947#endif
6948
6949#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0)
6950module_param(mem, int, 0);
6951module_param(noaccel, int, 0);
6952module_param(noypan, int, 0);
6953module_param(nomax, int, 0);
6954module_param(userom, int, 0);
6955module_param(useoem, int, 0);
6956module_param(mode, charp, 0);
6957module_param(vesa, int, 0);
6958module_param(rate, int, 0);
6959module_param(forcecrt1, int, 0);
6960module_param(forcecrt2type, charp, 0);
6961module_param(scalelcd, int, 0);
6962module_param(pdc, int, 0);
6963module_param(pdc1, int, 0);
6964module_param(specialtiming, charp, 0);
6965module_param(lvdshl, int, 0);
6966module_param(tvstandard, charp, 0);
6967module_param(tvxposoffset, int, 0);
6968module_param(tvyposoffset, int, 0);
1da177e4
LT
6969module_param(nocrt2rate, int, 0);
6970#if !defined(__i386__) && !defined(__x86_64__)
6971module_param(resetcard, int, 0);
6972module_param(videoram, int, 0);
6973#endif
6974#endif
6975
544393fe 6976#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
1da177e4
LT
6977MODULE_PARM_DESC(mem,
6978 "\nDetermines the beginning of the video memory heap in KB. This heap is used\n"
6979 "for video RAM management for eg. DRM/DRI. On 300 series, the default depends\n"
6980 "on the amount of video RAM available. If 8MB of video RAM or less is available,\n"
6981 "the heap starts at 4096KB, if between 8 and 16MB are available at 8192KB,\n"
544393fe 6982 "otherwise at 12288KB. On 315/330/340 series, the heap size is 32KB by default.\n"
1da177e4
LT
6983 "The value is to be specified without 'KB' and must match the MaxXFBMem setting\n"
6984 "for XFree86 4.x/X.org 6.7 and later.\n");
544393fe
TW
6985#else
6986MODULE_PARM_DESC(mem,
6987 "\nDetermines the beginning of the video memory heap in KB. This heap is used\n"
6988 "for video RAM management for eg. DRM/DRI. On 300 series, the default depends\n"
6989 "on the amount of video RAM available. If 8MB of video RAM or less is available,\n"
6990 "the heap starts at 4096KB, if between 8 and 16MB are available at 8192KB,\n"
6991 "otherwise at 12288KB. On 315/330/340 series, the heap size is 32KB by default.\n"
6992 "The value is to be specified without 'KB'.\n");
6993#endif
1da177e4
LT
6994
6995MODULE_PARM_DESC(noaccel,
544393fe 6996 "\nIf set to anything other than 0, 2D acceleration will be disabled.\n"
1da177e4
LT
6997 "(default: 0)\n");
6998
6999MODULE_PARM_DESC(noypan,
544393fe
TW
7000 "\nIf set to anything other than 0, y-panning will be disabled and scrolling\n"
7001 "will be performed by redrawing the screen. (default: 0)\n");
1da177e4
LT
7002
7003MODULE_PARM_DESC(nomax,
544393fe 7004 "\nIf y-panning is enabled, sisfb will by default use the entire available video\n"
1da177e4
LT
7005 "memory for the virtual screen in order to optimize scrolling performance. If\n"
7006 "this is set to anything other than 0, sisfb will not do this and thereby \n"
7007 "enable the user to positively specify a virtual Y size of the screen using\n"
7008 "fbset. (default: 0)\n");
7009
7010#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
7011MODULE_PARM_DESC(mode,
544393fe
TW
7012 "\nSelects the desired display mode in the format [X]x[Y]x[Depth], eg.\n"
7013 "1024x768x16. Other formats supported include XxY-Depth and\n"
7014 "XxY-Depth@Rate. If the parameter is only one (decimal or hexadecimal)\n"
1da177e4
LT
7015 "number, it will be interpreted as a VESA mode number. (default: none if\n"
7016 "sisfb is a module; this leaves the console untouched and the driver will\n"
7017 "only do the video memory management for eg. DRM/DRI; 800x600x8 if sisfb\n"
7018 "is in the kernel)\n");
7019MODULE_PARM_DESC(vesa,
544393fe
TW
7020 "\nSelects the desired display mode by VESA defined mode number, eg. 0x117\n"
7021 "(default: 0x0000 if sisfb is a module; this leaves the console untouched\n"
1da177e4
LT
7022 "and the driver will only do the video memory management for eg. DRM/DRI;\n"
7023 "0x0103 if sisfb is in the kernel)\n");
7024#endif
7025
7026#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0)
7027MODULE_PARM_DESC(mode,
544393fe
TW
7028 "\nSelects the desired default display mode in the format XxYxDepth,\n"
7029 "eg. 1024x768x16. Other formats supported include XxY-Depth and\n"
1da177e4
LT
7030 "XxY-Depth@Rate. If the parameter is only one (decimal or hexadecimal)\n"
7031 "number, it will be interpreted as a VESA mode number. (default: 800x600x8)\n");
7032
7033MODULE_PARM_DESC(vesa,
544393fe
TW
7034 "\nSelects the desired default display mode by VESA defined mode number, eg.\n"
7035 "0x117 (default: 0x0103)\n");
1da177e4
LT
7036#endif
7037
7038MODULE_PARM_DESC(rate,
7039 "\nSelects the desired vertical refresh rate for CRT1 (external VGA) in Hz.\n"
7040 "If the mode is specified in the format XxY-Depth@Rate, this parameter\n"
7041 "will be ignored (default: 60)\n");
7042
7043MODULE_PARM_DESC(forcecrt1,
7044 "\nNormally, the driver autodetects whether or not CRT1 (external VGA) is \n"
7045 "connected. With this option, the detection can be overridden (1=CRT1 ON,\n"
7046 "0=CRT1 OFF) (default: [autodetected])\n");
7047
7048MODULE_PARM_DESC(forcecrt2type,
7049 "\nIf this option is omitted, the driver autodetects CRT2 output devices, such as\n"
7050 "LCD, TV or secondary VGA. With this option, this autodetection can be\n"
7051 "overridden. Possible parameters are LCD, TV, VGA or NONE. NONE disables CRT2.\n"
7052 "On systems with a SiS video bridge, parameters SVIDEO, COMPOSITE or SCART can\n"
7053 "be used instead of TV to override the TV detection. Furthermore, on systems\n"
7054 "with a SiS video bridge, SVIDEO+COMPOSITE, HIVISION, YPBPR480I, YPBPR480P,\n"
7055 "YPBPR720P and YPBPR1080I are understood. However, whether or not these work\n"
7056 "depends on the very hardware in use. (default: [autodetected])\n");
7057
7058MODULE_PARM_DESC(scalelcd,
7059 "\nSetting this to 1 will force the driver to scale the LCD image to the panel's\n"
7060 "native resolution. Setting it to 0 will disable scaling; LVDS panels will\n"
7061 "show black bars around the image, TMDS panels will probably do the scaling\n"
7062 "themselves. Default: 1 on LVDS panels, 0 on TMDS panels\n");
7063
7064MODULE_PARM_DESC(pdc,
544393fe 7065 "\nThis is for manually selecting the LCD panel delay compensation. The driver\n"
1da177e4
LT
7066 "should detect this correctly in most cases; however, sometimes this is not\n"
7067 "possible. If you see 'small waves' on the LCD, try setting this to 4, 32 or 24\n"
544393fe
TW
7068 "on a 300 series chipset; 6 on other chipsets. If the problem persists, try\n"
7069 "other values (on 300 series: between 4 and 60 in steps of 4; otherwise: any\n"
7070 "value from 0 to 31). (default: autodetected, if LCD is active during start)\n");
1da177e4
LT
7071
7072#ifdef CONFIG_FB_SIS_315
7073MODULE_PARM_DESC(pdc1,
544393fe 7074 "\nThis is same as pdc, but for LCD-via CRT1. Hence, this is for the 315/330/340\n"
1da177e4
LT
7075 "series only. (default: autodetected if LCD is in LCD-via-CRT1 mode during\n"
7076 "startup) - Note: currently, this has no effect because LCD-via-CRT1 is not\n"
7077 "implemented yet.\n");
7078#endif
7079
7080MODULE_PARM_DESC(specialtiming,
7081 "\nPlease refer to documentation for more information on this option.\n");
7082
7083MODULE_PARM_DESC(lvdshl,
7084 "\nPlease refer to documentation for more information on this option.\n");
7085
7086MODULE_PARM_DESC(tvstandard,
7087 "\nThis allows overriding the BIOS default for the TV standard. Valid choices are\n"
7088 "pal, ntsc, palm and paln. (default: [auto; pal or ntsc only])\n");
7089
7090MODULE_PARM_DESC(tvxposoffset,
7091 "\nRelocate TV output horizontally. Possible parameters: -32 through 32.\n"
7092 "Default: 0\n");
7093
7094MODULE_PARM_DESC(tvyposoffset,
7095 "\nRelocate TV output vertically. Possible parameters: -32 through 32.\n"
7096 "Default: 0\n");
7097
1da177e4
LT
7098MODULE_PARM_DESC(nocrt2rate,
7099 "\nSetting this to 1 will force the driver to use the default refresh rate for\n"
7100 "CRT2 if CRT2 type is VGA. (default: 0, use same rate as CRT1)\n");
7101
7102#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
7103MODULE_PARM_DESC(inverse,
544393fe 7104 "\nSetting this to anything but 0 should invert the display colors, but this\n"
1da177e4
LT
7105 "does not seem to work. (default: 0)\n");
7106#endif
7107
7108#if !defined(__i386__) && !defined(__x86_64__)
7109#ifdef CONFIG_FB_SIS_300
7110MODULE_PARM_DESC(resetcard,
7111 "\nSet this to 1 in order to reset (POST) the card on non-x86 machines where\n"
544393fe
TW
7112 "the BIOS did not POST the card (only supported for SiS 300/305 and XGI cards\n"
7113 "currently). Default: 0\n");
1da177e4
LT
7114
7115MODULE_PARM_DESC(videoram,
7116 "\nSet this to the amount of video RAM (in kilobyte) the card has. Required on\n"
7117 "some non-x86 architectures where the memory auto detection fails. Only\n"
544393fe 7118 "relevant if resetcard is set, too. SiS300/305 only. Default: [auto-detect]\n");
1da177e4 7119#endif
1da177e4
LT
7120#endif
7121
1da177e4
LT
7122#endif /* /MODULE */
7123
544393fe 7124/* _GPL only for new symbols. */
1da177e4
LT
7125EXPORT_SYMBOL(sis_malloc);
7126EXPORT_SYMBOL(sis_free);
544393fe
TW
7127EXPORT_SYMBOL_GPL(sis_malloc_new);
7128EXPORT_SYMBOL_GPL(sis_free_new);
7129
1da177e4
LT
7130
7131
This page took 0.448134 seconds and 5 git commands to generate.