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