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