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