blob: f8dfabd73b003e062f483b9b6bad33d56d79f7a7 [file] [log] [blame]
Linus Torvalds1da177e2005-04-16 15:20:36 -07001/*
Thomas Winischhofer544393f2005-09-09 13:04:45 -07002 * 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
Linus Torvalds1da177e2005-04-16 15:20:36 -07005 * frame buffer driver for Linux kernels >= 2.4.14 and >=2.6.3
6 *
Thomas Winischhofer544393f2005-09-09 13:04:45 -07007 * Copyright (C) 2001-2005 Thomas Winischhofer, Vienna, Austria.
Linus Torvalds1da177e2005-04-16 15:20:36 -07008 *
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 *
Thomas Winischhofer544393f2005-09-09 13:04:45 -070023 * Author: Thomas Winischhofer <thomas@winischhofer.net>
Linus Torvalds1da177e2005-04-16 15:20:36 -070024 *
25 * Author of (practically wiped) code base:
26 * SiS (www.sis.com)
Thomas Winischhofer544393f2005-09-09 13:04:45 -070027 * Copyright (C) 1999 Silicon Integrated Systems, Inc.
Linus Torvalds1da177e2005-04-16 15:20:36 -070028 *
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
Linus Torvalds1da177e2005-04-16 15:20:36 -070036#include <linux/version.h>
37#include <linux/module.h>
38#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0)
39#include <linux/moduleparam.h>
40#endif
41#include <linux/kernel.h>
42#include <linux/smp_lock.h>
43#include <linux/spinlock.h>
44#include <linux/errno.h>
45#include <linux/string.h>
46#include <linux/mm.h>
Jon Smirla8f340e2006-07-10 04:44:12 -070047
48#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,18)
Linus Torvalds1da177e2005-04-16 15:20:36 -070049#include <linux/tty.h>
Jon Smirla8f340e2006-07-10 04:44:12 -070050#else
51#include <linux/screen_info.h>
52#endif
53
Linus Torvalds1da177e2005-04-16 15:20:36 -070054#include <linux/slab.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070055#include <linux/fb.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070056#include <linux/selection.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070057#include <linux/ioport.h>
58#include <linux/init.h>
59#include <linux/pci.h>
60#include <linux/vmalloc.h>
Thomas Winischhofer544393f2005-09-09 13:04:45 -070061#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
Linus Torvalds1da177e2005-04-16 15:20:36 -070062#include <linux/vt_kern.h>
Thomas Winischhofer544393f2005-09-09 13:04:45 -070063#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -070064#include <linux/capability.h>
65#include <linux/fs.h>
66#include <linux/types.h>
67#include <asm/uaccess.h>
68#include <asm/io.h>
69#ifdef CONFIG_MTRR
70#include <asm/mtrr.h>
71#endif
72
73#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
74#include <video/fbcon.h>
75#include <video/fbcon-cfb8.h>
76#include <video/fbcon-cfb16.h>
77#include <video/fbcon-cfb24.h>
78#include <video/fbcon-cfb32.h>
79#endif
80
81#include "sis.h"
82#include "sis_main.h"
83
84#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0)
85#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,3)
86#error "This version of sisfb requires at least 2.6.3"
87#endif
88#endif
89
90#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
91#ifdef FBCON_HAS_CFB8
92extern struct display_switch fbcon_sis8;
93#endif
94#ifdef FBCON_HAS_CFB16
95extern struct display_switch fbcon_sis16;
96#endif
97#ifdef FBCON_HAS_CFB32
98extern struct display_switch fbcon_sis32;
99#endif
100#endif
101
Thomas Winischhofer544393f2005-09-09 13:04:45 -0700102static void sisfb_handle_command(struct sis_video_info *ivideo,
103 struct sisfb_cmd *sisfb_command);
104
Linus Torvalds1da177e2005-04-16 15:20:36 -0700105/* ------------------ Internal helper routines ----------------- */
106
107static void __init
108sisfb_setdefaultparms(void)
109{
Thomas Winischhofer544393f2005-09-09 13:04:45 -0700110 sisfb_off = 0;
111 sisfb_parm_mem = 0;
112 sisfb_accel = -1;
113 sisfb_ypan = -1;
114 sisfb_max = -1;
115 sisfb_userom = -1;
116 sisfb_useoem = -1;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700117#ifdef MODULE
118 /* Module: "None" for 2.4, default mode for 2.5+ */
119#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0)
Thomas Winischhofer544393f2005-09-09 13:04:45 -0700120 sisfb_mode_idx = -1;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700121#else
Thomas Winischhofer544393f2005-09-09 13:04:45 -0700122 sisfb_mode_idx = MODE_INDEX_NONE;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700123#endif
124#else
125 /* Static: Default mode */
Thomas Winischhofer544393f2005-09-09 13:04:45 -0700126 sisfb_mode_idx = -1;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700127#endif
Thomas Winischhofer544393f2005-09-09 13:04:45 -0700128 sisfb_parm_rate = -1;
129 sisfb_crt1off = 0;
130 sisfb_forcecrt1 = -1;
131 sisfb_crt2type = -1;
132 sisfb_crt2flags = 0;
133 sisfb_pdc = 0xff;
134 sisfb_pdca = 0xff;
135 sisfb_scalelcd = -1;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700136 sisfb_specialtiming = CUT_NONE;
Thomas Winischhofer544393f2005-09-09 13:04:45 -0700137 sisfb_lvdshl = -1;
138 sisfb_dstn = 0;
139 sisfb_fstn = 0;
140 sisfb_tvplug = -1;
141 sisfb_tvstd = -1;
142 sisfb_tvxposoffset = 0;
143 sisfb_tvyposoffset = 0;
144 sisfb_nocrt2rate = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700145#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
Thomas Winischhofer544393f2005-09-09 13:04:45 -0700146 sisfb_inverse = 0;
147 sisfb_fontname[0] = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700148#endif
149#if !defined(__i386__) && !defined(__x86_64__)
Thomas Winischhofer544393f2005-09-09 13:04:45 -0700150 sisfb_resetcard = 0;
151 sisfb_videoram = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700152#endif
153}
154
Thomas Winischhofer544393f2005-09-09 13:04:45 -0700155/* ------------- Parameter parsing -------------- */
156
Linus Torvalds1da177e2005-04-16 15:20:36 -0700157static void __devinit
158sisfb_search_vesamode(unsigned int vesamode, BOOLEAN quiet)
159{
160 int i = 0, j = 0;
161
Thomas Winischhofer544393f2005-09-09 13:04:45 -0700162 /* We don't know the hardware specs yet and there is no ivideo */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700163
164 if(vesamode == 0) {
165#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
166 sisfb_mode_idx = MODE_INDEX_NONE;
167#else
Thomas Winischhofer544393f2005-09-09 13:04:45 -0700168 if(!quiet)
169 printk(KERN_ERR "sisfb: Invalid mode. Using default.\n");
170
Linus Torvalds1da177e2005-04-16 15:20:36 -0700171 sisfb_mode_idx = DEFAULT_MODE;
172#endif
173 return;
174 }
175
176 vesamode &= 0x1dff; /* Clean VESA mode number from other flags */
177
178 while(sisbios_mode[i++].mode_no[0] != 0) {
179 if( (sisbios_mode[i-1].vesa_mode_no_1 == vesamode) ||
180 (sisbios_mode[i-1].vesa_mode_no_2 == vesamode) ) {
Thomas Winischhofer544393f2005-09-09 13:04:45 -0700181 if(sisfb_fstn) {
182 if(sisbios_mode[i-1].mode_no[1] == 0x50 ||
183 sisbios_mode[i-1].mode_no[1] == 0x56 ||
184 sisbios_mode[i-1].mode_no[1] == 0x53)
185 continue;
186 } else {
187 if(sisbios_mode[i-1].mode_no[1] == 0x5a ||
188 sisbios_mode[i-1].mode_no[1] == 0x5b)
189 continue;
190 }
191 sisfb_mode_idx = i - 1;
192 j = 1;
193 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700194 }
195 }
Thomas Winischhofer544393f2005-09-09 13:04:45 -0700196 if((!j) && !quiet)
197 printk(KERN_ERR "sisfb: Invalid VESA mode 0x%x'\n", vesamode);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700198}
199
Thomas Winischhofer544393f2005-09-09 13:04:45 -0700200static void __devinit
Linus Torvalds1da177e2005-04-16 15:20:36 -0700201sisfb_search_mode(char *name, BOOLEAN quiet)
202{
Linus Torvalds1da177e2005-04-16 15:20:36 -0700203 unsigned int j = 0, xres = 0, yres = 0, depth = 0, rate = 0;
Thomas Winischhofer544393f2005-09-09 13:04:45 -0700204 int i = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700205 char strbuf[16], strbuf1[20];
206 char *nameptr = name;
207
Thomas Winischhofer544393f2005-09-09 13:04:45 -0700208 /* We don't know the hardware specs yet and there is no ivideo */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700209
210 if(name == NULL) {
Thomas Winischhofer544393f2005-09-09 13:04:45 -0700211 if(!quiet)
212 printk(KERN_ERR "sisfb: Internal error, using default mode.\n");
213
214 sisfb_mode_idx = DEFAULT_MODE;
215 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700216 }
217
218#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0)
Thomas Winischhofer544393f2005-09-09 13:04:45 -0700219 if(!strnicmp(name, sisbios_mode[MODE_INDEX_NONE].name, strlen(name))) {
220 if(!quiet)
221 printk(KERN_ERR "sisfb: Mode 'none' not supported anymore. Using default.\n");
222
223 sisfb_mode_idx = DEFAULT_MODE;
224 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700225 }
226#endif
227 if(strlen(name) <= 19) {
Thomas Winischhofer544393f2005-09-09 13:04:45 -0700228 strcpy(strbuf1, name);
229 for(i = 0; i < strlen(strbuf1); i++) {
230 if(strbuf1[i] < '0' || strbuf1[i] > '9') strbuf1[i] = ' ';
231 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700232
Thomas Winischhofer544393f2005-09-09 13:04:45 -0700233 /* This does some fuzzy mode naming detection */
234 if(sscanf(strbuf1, "%u %u %u %u", &xres, &yres, &depth, &rate) == 4) {
235 if((rate <= 32) || (depth > 32)) {
236 j = rate; rate = depth; depth = j;
237 }
238 sprintf(strbuf, "%ux%ux%u", xres, yres, depth);
239 nameptr = strbuf;
240 sisfb_parm_rate = rate;
241 } else if(sscanf(strbuf1, "%u %u %u", &xres, &yres, &depth) == 3) {
242 sprintf(strbuf, "%ux%ux%u", xres, yres, depth);
243 nameptr = strbuf;
244 } else {
245 xres = 0;
246 if((sscanf(strbuf1, "%u %u", &xres, &yres) == 2) && (xres != 0)) {
247 sprintf(strbuf, "%ux%ux8", xres, yres);
248 nameptr = strbuf;
249 } else {
250 sisfb_search_vesamode(simple_strtoul(name, NULL, 0), quiet);
251 return;
252 }
253 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700254 }
255
256 i = 0; j = 0;
257 while(sisbios_mode[i].mode_no[0] != 0) {
258 if(!strnicmp(nameptr, sisbios_mode[i++].name, strlen(nameptr))) {
Thomas Winischhofer544393f2005-09-09 13:04:45 -0700259 if(sisfb_fstn) {
260 if(sisbios_mode[i-1].mode_no[1] == 0x50 ||
261 sisbios_mode[i-1].mode_no[1] == 0x56 ||
262 sisbios_mode[i-1].mode_no[1] == 0x53)
263 continue;
264 } else {
265 if(sisbios_mode[i-1].mode_no[1] == 0x5a ||
266 sisbios_mode[i-1].mode_no[1] == 0x5b)
267 continue;
268 }
269 sisfb_mode_idx = i - 1;
270 j = 1;
271 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700272 }
273 }
Thomas Winischhofer544393f2005-09-09 13:04:45 -0700274
275 if((!j) && !quiet)
276 printk(KERN_ERR "sisfb: Invalid mode '%s'\n", nameptr);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700277}
278
279#ifndef MODULE
280static void __devinit
281sisfb_get_vga_mode_from_kernel(void)
282{
Adrian Bunk31c5cdb2006-06-26 00:26:28 -0700283#ifdef CONFIG_X86
Thomas Winischhofer544393f2005-09-09 13:04:45 -0700284 char mymode[32];
Linus Torvalds1da177e2005-04-16 15:20:36 -0700285 int mydepth = screen_info.lfb_depth;
286
287 if(screen_info.orig_video_isVGA != VIDEO_TYPE_VLFB) return;
288
289 if( (screen_info.lfb_width >= 320) && (screen_info.lfb_width <= 2048) &&
290 (screen_info.lfb_height >= 200) && (screen_info.lfb_height <= 1536) &&
291 (mydepth >= 8) && (mydepth <= 32) ) {
292
Thomas Winischhofer544393f2005-09-09 13:04:45 -0700293 if(mydepth == 24) mydepth = 32;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700294
Thomas Winischhofer544393f2005-09-09 13:04:45 -0700295 sprintf(mymode, "%ux%ux%u", screen_info.lfb_width,
296 screen_info.lfb_height,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700297 mydepth);
298
Thomas Winischhofer544393f2005-09-09 13:04:45 -0700299 printk(KERN_DEBUG
300 "sisfb: Using vga mode %s pre-set by kernel as default\n",
301 mymode);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700302
Thomas Winischhofer544393f2005-09-09 13:04:45 -0700303 sisfb_search_mode(mymode, TRUE);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700304 }
305#endif
306 return;
307}
308#endif
309
310static void __init
311sisfb_search_crt2type(const char *name)
312{
313 int i = 0;
314
Thomas Winischhofer544393f2005-09-09 13:04:45 -0700315 /* We don't know the hardware specs yet and there is no ivideo */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700316
317 if(name == NULL) return;
318
319 while(sis_crt2type[i].type_no != -1) {
Thomas Winischhofer544393f2005-09-09 13:04:45 -0700320 if(!strnicmp(name, sis_crt2type[i].name, strlen(sis_crt2type[i].name))) {
321 sisfb_crt2type = sis_crt2type[i].type_no;
322 sisfb_tvplug = sis_crt2type[i].tvplug_no;
323 sisfb_crt2flags = sis_crt2type[i].flags;
324 break;
325 }
326 i++;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700327 }
328
329 sisfb_dstn = (sisfb_crt2flags & FL_550_DSTN) ? 1 : 0;
330 sisfb_fstn = (sisfb_crt2flags & FL_550_FSTN) ? 1 : 0;
331
Thomas Winischhofer544393f2005-09-09 13:04:45 -0700332 if(sisfb_crt2type < 0)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700333 printk(KERN_ERR "sisfb: Invalid CRT2 type: %s\n", name);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700334}
335
336static void __init
337sisfb_search_tvstd(const char *name)
338{
339 int i = 0;
340
Thomas Winischhofer544393f2005-09-09 13:04:45 -0700341 /* We don't know the hardware specs yet and there is no ivideo */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700342
Thomas Winischhofer544393f2005-09-09 13:04:45 -0700343 if(name == NULL)
344 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700345
346 while(sis_tvtype[i].type_no != -1) {
Thomas Winischhofer544393f2005-09-09 13:04:45 -0700347 if(!strnicmp(name, sis_tvtype[i].name, strlen(sis_tvtype[i].name))) {
348 sisfb_tvstd = sis_tvtype[i].type_no;
349 break;
350 }
351 i++;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700352 }
353}
354
355static void __init
356sisfb_search_specialtiming(const char *name)
357{
358 int i = 0;
359 BOOLEAN found = FALSE;
360
Thomas Winischhofer544393f2005-09-09 13:04:45 -0700361 /* We don't know the hardware specs yet and there is no ivideo */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700362
Thomas Winischhofer544393f2005-09-09 13:04:45 -0700363 if(name == NULL)
364 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700365
366 if(!strnicmp(name, "none", 4)) {
Thomas Winischhofer544393f2005-09-09 13:04:45 -0700367 sisfb_specialtiming = CUT_FORCENONE;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700368 printk(KERN_DEBUG "sisfb: Special timing disabled\n");
369 } else {
Thomas Winischhofer544393f2005-09-09 13:04:45 -0700370 while(mycustomttable[i].chipID != 0) {
371 if(!strnicmp(name,mycustomttable[i].optionName,
372 strlen(mycustomttable[i].optionName))) {
373 sisfb_specialtiming = mycustomttable[i].SpecialID;
374 found = TRUE;
375 printk(KERN_INFO "sisfb: Special timing for %s %s forced (\"%s\")\n",
376 mycustomttable[i].vendorName,
377 mycustomttable[i].cardName,
378 mycustomttable[i].optionName);
379 break;
380 }
381 i++;
382 }
383 if(!found) {
384 printk(KERN_WARNING "sisfb: Invalid SpecialTiming parameter, valid are:");
385 printk(KERN_WARNING "\t\"none\" (to disable special timings)\n");
386 i = 0;
387 while(mycustomttable[i].chipID != 0) {
388 printk(KERN_WARNING "\t\"%s\" (for %s %s)\n",
389 mycustomttable[i].optionName,
390 mycustomttable[i].vendorName,
391 mycustomttable[i].cardName);
392 i++;
393 }
394 }
395 }
396}
397
398/* ----------- Various detection routines ----------- */
399
400static void __devinit
401sisfb_detect_custom_timing(struct sis_video_info *ivideo)
402{
403 unsigned char *biosver = NULL;
404 unsigned char *biosdate = NULL;
405 BOOLEAN footprint;
406 u32 chksum = 0;
407 int i, j;
408
409 if(ivideo->SiS_Pr.UseROM) {
410 biosver = ivideo->SiS_Pr.VirtualRomBase + 0x06;
411 biosdate = ivideo->SiS_Pr.VirtualRomBase + 0x2c;
412 for(i = 0; i < 32768; i++)
413 chksum += ivideo->SiS_Pr.VirtualRomBase[i];
414 }
415
416 i = 0;
417 do {
418 if( (mycustomttable[i].chipID == ivideo->chip) &&
419 ((!strlen(mycustomttable[i].biosversion)) ||
420 (ivideo->SiS_Pr.UseROM &&
421 (!strncmp(mycustomttable[i].biosversion, biosver,
422 strlen(mycustomttable[i].biosversion))))) &&
423 ((!strlen(mycustomttable[i].biosdate)) ||
424 (ivideo->SiS_Pr.UseROM &&
425 (!strncmp(mycustomttable[i].biosdate, biosdate,
426 strlen(mycustomttable[i].biosdate))))) &&
427 ((!mycustomttable[i].bioschksum) ||
428 (ivideo->SiS_Pr.UseROM &&
429 (mycustomttable[i].bioschksum == chksum))) &&
430 (mycustomttable[i].pcisubsysvendor == ivideo->subsysvendor) &&
431 (mycustomttable[i].pcisubsyscard == ivideo->subsysdevice) ) {
432 footprint = TRUE;
433 for(j = 0; j < 5; j++) {
434 if(mycustomttable[i].biosFootprintAddr[j]) {
435 if(ivideo->SiS_Pr.UseROM) {
436 if(ivideo->SiS_Pr.VirtualRomBase[mycustomttable[i].biosFootprintAddr[j]] !=
437 mycustomttable[i].biosFootprintData[j]) {
438 footprint = FALSE;
439 }
440 } else
441 footprint = FALSE;
442 }
443 }
444 if(footprint) {
445 ivideo->SiS_Pr.SiS_CustomT = mycustomttable[i].SpecialID;
446 printk(KERN_DEBUG "sisfb: Identified [%s %s], special timing applies\n",
447 mycustomttable[i].vendorName,
448 mycustomttable[i].cardName);
449 printk(KERN_DEBUG "sisfb: [specialtiming parameter name: %s]\n",
450 mycustomttable[i].optionName);
451 break;
452 }
453 }
454 i++;
455 } while(mycustomttable[i].chipID);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700456}
457
458static BOOLEAN __devinit
459sisfb_interpret_edid(struct sisfb_monitor *monitor, u8 *buffer)
460{
461 int i, j, xres, yres, refresh, index;
462 u32 emodes;
463
464 if(buffer[0] != 0x00 || buffer[1] != 0xff ||
465 buffer[2] != 0xff || buffer[3] != 0xff ||
466 buffer[4] != 0xff || buffer[5] != 0xff ||
467 buffer[6] != 0xff || buffer[7] != 0x00) {
Thomas Winischhofer544393f2005-09-09 13:04:45 -0700468 printk(KERN_DEBUG "sisfb: Bad EDID header\n");
469 return FALSE;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700470 }
471
472 if(buffer[0x12] != 0x01) {
Thomas Winischhofer544393f2005-09-09 13:04:45 -0700473 printk(KERN_INFO "sisfb: EDID version %d not supported\n",
474 buffer[0x12]);
475 return FALSE;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700476 }
477
478 monitor->feature = buffer[0x18];
479
480 if(!buffer[0x14] & 0x80) {
Thomas Winischhofer544393f2005-09-09 13:04:45 -0700481 if(!(buffer[0x14] & 0x08)) {
482 printk(KERN_INFO
483 "sisfb: WARNING: Monitor does not support separate syncs\n");
484 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700485 }
486
487 if(buffer[0x13] >= 0x01) {
488 /* EDID V1 rev 1 and 2: Search for monitor descriptor
489 * to extract ranges
490 */
491 j = 0x36;
492 for(i=0; i<4; i++) {
493 if(buffer[j] == 0x00 && buffer[j + 1] == 0x00 &&
Thomas Winischhofer544393f2005-09-09 13:04:45 -0700494 buffer[j + 2] == 0x00 && buffer[j + 3] == 0xfd &&
Linus Torvalds1da177e2005-04-16 15:20:36 -0700495 buffer[j + 4] == 0x00) {
496 monitor->hmin = buffer[j + 7];
497 monitor->hmax = buffer[j + 8];
498 monitor->vmin = buffer[j + 5];
499 monitor->vmax = buffer[j + 6];
500 monitor->dclockmax = buffer[j + 9] * 10 * 1000;
501 monitor->datavalid = TRUE;
502 break;
503 }
504 j += 18;
505 }
506 }
507
508 if(!monitor->datavalid) {
509 /* Otherwise: Get a range from the list of supported
510 * Estabished Timings. This is not entirely accurate,
511 * because fixed frequency monitors are not supported
512 * that way.
513 */
514 monitor->hmin = 65535; monitor->hmax = 0;
515 monitor->vmin = 65535; monitor->vmax = 0;
516 monitor->dclockmax = 0;
517 emodes = buffer[0x23] | (buffer[0x24] << 8) | (buffer[0x25] << 16);
518 for(i = 0; i < 13; i++) {
519 if(emodes & sisfb_ddcsmodes[i].mask) {
Thomas Winischhofer544393f2005-09-09 13:04:45 -0700520 if(monitor->hmin > sisfb_ddcsmodes[i].h) monitor->hmin = sisfb_ddcsmodes[i].h;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700521 if(monitor->hmax < sisfb_ddcsmodes[i].h) monitor->hmax = sisfb_ddcsmodes[i].h + 1;
522 if(monitor->vmin > sisfb_ddcsmodes[i].v) monitor->vmin = sisfb_ddcsmodes[i].v;
523 if(monitor->vmax < sisfb_ddcsmodes[i].v) monitor->vmax = sisfb_ddcsmodes[i].v;
524 if(monitor->dclockmax < sisfb_ddcsmodes[i].d) monitor->dclockmax = sisfb_ddcsmodes[i].d;
525 }
526 }
527 index = 0x26;
528 for(i = 0; i < 8; i++) {
529 xres = (buffer[index] + 31) * 8;
530 switch(buffer[index + 1] & 0xc0) {
Thomas Winischhofer544393f2005-09-09 13:04:45 -0700531 case 0xc0: yres = (xres * 9) / 16; break;
532 case 0x80: yres = (xres * 4) / 5; break;
533 case 0x40: yres = (xres * 3) / 4; break;
534 default: yres = xres; break;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700535 }
536 refresh = (buffer[index + 1] & 0x3f) + 60;
537 if((xres >= 640) && (yres >= 480)) {
Thomas Winischhofer544393f2005-09-09 13:04:45 -0700538 for(j = 0; j < 8; j++) {
539 if((xres == sisfb_ddcfmodes[j].x) &&
540 (yres == sisfb_ddcfmodes[j].y) &&
Linus Torvalds1da177e2005-04-16 15:20:36 -0700541 (refresh == sisfb_ddcfmodes[j].v)) {
542 if(monitor->hmin > sisfb_ddcfmodes[j].h) monitor->hmin = sisfb_ddcfmodes[j].h;
543 if(monitor->hmax < sisfb_ddcfmodes[j].h) monitor->hmax = sisfb_ddcfmodes[j].h + 1;
544 if(monitor->vmin > sisfb_ddcsmodes[j].v) monitor->vmin = sisfb_ddcsmodes[j].v;
545 if(monitor->vmax < sisfb_ddcsmodes[j].v) monitor->vmax = sisfb_ddcsmodes[j].v;
Thomas Winischhofer544393f2005-09-09 13:04:45 -0700546 if(monitor->dclockmax < sisfb_ddcsmodes[j].d) monitor->dclockmax = sisfb_ddcsmodes[j].d;
547 }
548 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700549 }
550 index += 2;
Thomas Winischhofer544393f2005-09-09 13:04:45 -0700551 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700552 if((monitor->hmin <= monitor->hmax) && (monitor->vmin <= monitor->vmax)) {
553 monitor->datavalid = TRUE;
554 }
555 }
556
Thomas Winischhofer544393f2005-09-09 13:04:45 -0700557 return monitor->datavalid;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700558}
559
560static void __devinit
561sisfb_handle_ddc(struct sis_video_info *ivideo, struct sisfb_monitor *monitor, int crtno)
562{
Thomas Winischhofer544393f2005-09-09 13:04:45 -0700563 unsigned short temp, i, realcrtno = crtno;
564 unsigned char buffer[256];
Linus Torvalds1da177e2005-04-16 15:20:36 -0700565
566 monitor->datavalid = FALSE;
567
568 if(crtno) {
Thomas Winischhofer544393f2005-09-09 13:04:45 -0700569 if(ivideo->vbflags & CRT2_LCD) realcrtno = 1;
570 else if(ivideo->vbflags & CRT2_VGA) realcrtno = 2;
571 else return;
572 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700573
Thomas Winischhofer544393f2005-09-09 13:04:45 -0700574 if((ivideo->sisfb_crt1off) && (!crtno))
575 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700576
Thomas Winischhofer544393f2005-09-09 13:04:45 -0700577 temp = SiS_HandleDDC(&ivideo->SiS_Pr, ivideo->vbflags, ivideo->sisvga_engine,
578 realcrtno, 0, &buffer[0], ivideo->vbflags2);
579 if((!temp) || (temp == 0xffff)) {
580 printk(KERN_INFO "sisfb: CRT%d DDC probing failed\n", crtno + 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700581 return;
Thomas Winischhofer544393f2005-09-09 13:04:45 -0700582 } else {
583 printk(KERN_INFO "sisfb: CRT%d DDC supported\n", crtno + 1);
584 printk(KERN_INFO "sisfb: CRT%d DDC level: %s%s%s%s\n",
585 crtno + 1,
586 (temp & 0x1a) ? "" : "[none of the supported]",
587 (temp & 0x02) ? "2 " : "",
588 (temp & 0x08) ? "D&P" : "",
589 (temp & 0x10) ? "FPDI-2" : "");
590 if(temp & 0x02) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700591 i = 3; /* Number of retrys */
592 do {
Thomas Winischhofer544393f2005-09-09 13:04:45 -0700593 temp = SiS_HandleDDC(&ivideo->SiS_Pr, ivideo->vbflags, ivideo->sisvga_engine,
594 realcrtno, 1, &buffer[0], ivideo->vbflags2);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700595 } while((temp) && i--);
Thomas Winischhofer544393f2005-09-09 13:04:45 -0700596 if(!temp) {
597 if(sisfb_interpret_edid(monitor, &buffer[0])) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700598 printk(KERN_INFO "sisfb: Monitor range H %d-%dKHz, V %d-%dHz, Max. dotclock %dMHz\n",
Thomas Winischhofer544393f2005-09-09 13:04:45 -0700599 monitor->hmin, monitor->hmax, monitor->vmin, monitor->vmax,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700600 monitor->dclockmax / 1000);
601 } else {
Thomas Winischhofer544393f2005-09-09 13:04:45 -0700602 printk(KERN_INFO "sisfb: CRT%d DDC EDID corrupt\n", crtno + 1);
603 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700604 } else {
Thomas Winischhofer544393f2005-09-09 13:04:45 -0700605 printk(KERN_INFO "sisfb: CRT%d DDC reading failed\n", crtno + 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700606 }
607 } else {
608 printk(KERN_INFO "sisfb: VESA D&P and FPDI-2 not supported yet\n");
609 }
610 }
611}
612
Thomas Winischhofer544393f2005-09-09 13:04:45 -0700613/* -------------- Mode validation --------------- */
614
Linus Torvalds1da177e2005-04-16 15:20:36 -0700615static BOOLEAN
616sisfb_verify_rate(struct sis_video_info *ivideo, struct sisfb_monitor *monitor,
617 int mode_idx, int rate_idx, int rate)
618{
619 int htotal, vtotal;
620 unsigned int dclock, hsync;
621
Thomas Winischhofer544393f2005-09-09 13:04:45 -0700622 if(!monitor->datavalid)
623 return TRUE;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700624
Thomas Winischhofer544393f2005-09-09 13:04:45 -0700625 if(mode_idx < 0)
626 return FALSE;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700627
628 /* Skip for 320x200, 320x240, 640x400 */
Thomas Winischhofer544393f2005-09-09 13:04:45 -0700629 switch(sisbios_mode[mode_idx].mode_no[ivideo->mni]) {
630 case 0x59:
631 case 0x41:
632 case 0x4f:
633 case 0x50:
634 case 0x56:
635 case 0x53:
636 case 0x2f:
637 case 0x5d:
638 case 0x5e:
639 return TRUE;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700640#ifdef CONFIG_FB_SIS_315
641 case 0x5a:
642 case 0x5b:
643 if(ivideo->sisvga_engine == SIS_315_VGA) return TRUE;
644#endif
Thomas Winischhofer544393f2005-09-09 13:04:45 -0700645 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700646
Thomas Winischhofer544393f2005-09-09 13:04:45 -0700647 if(rate < (monitor->vmin - 1))
648 return FALSE;
649 if(rate > (monitor->vmax + 1))
650 return FALSE;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700651
Thomas Winischhofer544393f2005-09-09 13:04:45 -0700652 if(sisfb_gettotalfrommode(&ivideo->SiS_Pr,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700653 sisbios_mode[mode_idx].mode_no[ivideo->mni],
Thomas Winischhofer544393f2005-09-09 13:04:45 -0700654 &htotal, &vtotal, rate_idx)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700655 dclock = (htotal * vtotal * rate) / 1000;
Thomas Winischhofer544393f2005-09-09 13:04:45 -0700656 if(dclock > (monitor->dclockmax + 1000))
657 return FALSE;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700658 hsync = dclock / htotal;
Thomas Winischhofer544393f2005-09-09 13:04:45 -0700659 if(hsync < (monitor->hmin - 1))
660 return FALSE;
661 if(hsync > (monitor->hmax + 1))
662 return FALSE;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700663 } else {
Thomas Winischhofer544393f2005-09-09 13:04:45 -0700664 return FALSE;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700665 }
666 return TRUE;
667}
668
669static int
670sisfb_validate_mode(struct sis_video_info *ivideo, int myindex, u32 vbflags)
671{
Thomas Winischhofer544393f2005-09-09 13:04:45 -0700672 u16 xres=0, yres, myres;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700673
674#ifdef CONFIG_FB_SIS_300
Thomas Winischhofer544393f2005-09-09 13:04:45 -0700675 if(ivideo->sisvga_engine == SIS_300_VGA) {
676 if(!(sisbios_mode[myindex].chipset & MD_SIS300))
677 return -1 ;
678 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700679#endif
680#ifdef CONFIG_FB_SIS_315
Thomas Winischhofer544393f2005-09-09 13:04:45 -0700681 if(ivideo->sisvga_engine == SIS_315_VGA) {
682 if(!(sisbios_mode[myindex].chipset & MD_SIS315))
683 return -1;
684 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700685#endif
686
Thomas Winischhofer544393f2005-09-09 13:04:45 -0700687 myres = sisbios_mode[myindex].yres;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700688
Thomas Winischhofer544393f2005-09-09 13:04:45 -0700689 switch(vbflags & VB_DISPTYPE_DISP2) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700690
Thomas Winischhofer544393f2005-09-09 13:04:45 -0700691 case CRT2_LCD:
692 xres = ivideo->lcdxres; yres = ivideo->lcdyres;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700693
Thomas Winischhofer544393f2005-09-09 13:04:45 -0700694 if((ivideo->SiS_Pr.SiS_CustomT != CUT_PANEL848) &&
695 (ivideo->SiS_Pr.SiS_CustomT != CUT_PANEL856)) {
696 if(sisbios_mode[myindex].xres > xres)
697 return -1;
698 if(myres > yres)
699 return -1;
700 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700701
Thomas Winischhofer544393f2005-09-09 13:04:45 -0700702 if(ivideo->sisfb_fstn) {
703 if(sisbios_mode[myindex].xres == 320) {
704 if(myres == 240) {
705 switch(sisbios_mode[myindex].mode_no[1]) {
706 case 0x50: myindex = MODE_FSTN_8; break;
707 case 0x56: myindex = MODE_FSTN_16; break;
708 case 0x53: return -1;
709 }
710 }
711 }
712 }
713
714 if(SiS_GetModeID_LCD(ivideo->sisvga_engine, vbflags, sisbios_mode[myindex].xres,
715 sisbios_mode[myindex].yres, 0, ivideo->sisfb_fstn,
716 ivideo->SiS_Pr.SiS_CustomT, xres, yres, ivideo->vbflags2) < 0x14) {
717 return -1;
718 }
719 break;
720
721 case CRT2_TV:
722 if(SiS_GetModeID_TV(ivideo->sisvga_engine, vbflags, sisbios_mode[myindex].xres,
723 sisbios_mode[myindex].yres, 0, ivideo->vbflags2) < 0x14) {
724 return -1;
725 }
726 break;
727
728 case CRT2_VGA:
729 if(SiS_GetModeID_VGA2(ivideo->sisvga_engine, vbflags, sisbios_mode[myindex].xres,
730 sisbios_mode[myindex].yres, 0, ivideo->vbflags2) < 0x14) {
731 return -1;
732 }
733 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700734 }
735
Thomas Winischhofer544393f2005-09-09 13:04:45 -0700736 return myindex;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700737}
738
739static u8
740sisfb_search_refresh_rate(struct sis_video_info *ivideo, unsigned int rate, int mode_idx)
741{
Linus Torvalds1da177e2005-04-16 15:20:36 -0700742 int i = 0;
Thomas Winischhofer544393f2005-09-09 13:04:45 -0700743 u16 xres = sisbios_mode[mode_idx].xres;
744 u16 yres = sisbios_mode[mode_idx].yres;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700745
746 ivideo->rate_idx = 0;
747 while((sisfb_vrate[i].idx != 0) && (sisfb_vrate[i].xres <= xres)) {
748 if((sisfb_vrate[i].xres == xres) && (sisfb_vrate[i].yres == yres)) {
749 if(sisfb_vrate[i].refresh == rate) {
750 ivideo->rate_idx = sisfb_vrate[i].idx;
751 break;
752 } else if(sisfb_vrate[i].refresh > rate) {
753 if((sisfb_vrate[i].refresh - rate) <= 3) {
754 DPRINTK("sisfb: Adjusting rate from %d up to %d\n",
755 rate, sisfb_vrate[i].refresh);
756 ivideo->rate_idx = sisfb_vrate[i].idx;
757 ivideo->refresh_rate = sisfb_vrate[i].refresh;
758 } else if(((rate - sisfb_vrate[i-1].refresh) <= 2)
759 && (sisfb_vrate[i].idx != 1)) {
760 DPRINTK("sisfb: Adjusting rate from %d down to %d\n",
761 rate, sisfb_vrate[i-1].refresh);
762 ivideo->rate_idx = sisfb_vrate[i-1].idx;
763 ivideo->refresh_rate = sisfb_vrate[i-1].refresh;
Thomas Winischhofer544393f2005-09-09 13:04:45 -0700764 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700765 break;
766 } else if((rate - sisfb_vrate[i].refresh) <= 2) {
767 DPRINTK("sisfb: Adjusting rate from %d down to %d\n",
768 rate, sisfb_vrate[i].refresh);
Thomas Winischhofer544393f2005-09-09 13:04:45 -0700769 ivideo->rate_idx = sisfb_vrate[i].idx;
770 break;
771 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700772 }
773 i++;
774 }
775 if(ivideo->rate_idx > 0) {
776 return ivideo->rate_idx;
777 } else {
778 printk(KERN_INFO "sisfb: Unsupported rate %d for %dx%d\n",
779 rate, xres, yres);
780 return 0;
781 }
782}
783
784static BOOLEAN
785sisfb_bridgeisslave(struct sis_video_info *ivideo)
786{
Thomas Winischhofer544393f2005-09-09 13:04:45 -0700787 unsigned char P1_00;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700788
Thomas Winischhofer544393f2005-09-09 13:04:45 -0700789 if(!(ivideo->vbflags2 & VB2_VIDEOBRIDGE))
790 return FALSE;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700791
Thomas Winischhofer544393f2005-09-09 13:04:45 -0700792 inSISIDXREG(SISPART1,0x00,P1_00);
793 if( ((ivideo->sisvga_engine == SIS_300_VGA) && (P1_00 & 0xa0) == 0x20) ||
794 ((ivideo->sisvga_engine == SIS_315_VGA) && (P1_00 & 0x50) == 0x10) ) {
795 return TRUE;
796 } else {
797 return FALSE;
798 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700799}
800
801static BOOLEAN
802sisfballowretracecrt1(struct sis_video_info *ivideo)
803{
Thomas Winischhofer544393f2005-09-09 13:04:45 -0700804 u8 temp;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700805
Thomas Winischhofer544393f2005-09-09 13:04:45 -0700806 inSISIDXREG(SISCR,0x17,temp);
807 if(!(temp & 0x80))
808 return FALSE;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700809
Thomas Winischhofer544393f2005-09-09 13:04:45 -0700810 inSISIDXREG(SISSR,0x1f,temp);
811 if(temp & 0xc0)
812 return FALSE;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700813
Thomas Winischhofer544393f2005-09-09 13:04:45 -0700814 return TRUE;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700815}
816
817static BOOLEAN
818sisfbcheckvretracecrt1(struct sis_video_info *ivideo)
819{
Thomas Winischhofer544393f2005-09-09 13:04:45 -0700820 if(!sisfballowretracecrt1(ivideo))
821 return FALSE;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700822
Thomas Winischhofer544393f2005-09-09 13:04:45 -0700823 if(inSISREG(SISINPSTAT) & 0x08)
824 return TRUE;
825 else
826 return FALSE;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700827}
828
829static void
830sisfbwaitretracecrt1(struct sis_video_info *ivideo)
831{
Thomas Winischhofer544393f2005-09-09 13:04:45 -0700832 int watchdog;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700833
Thomas Winischhofer544393f2005-09-09 13:04:45 -0700834 if(!sisfballowretracecrt1(ivideo))
835 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700836
Thomas Winischhofer544393f2005-09-09 13:04:45 -0700837 watchdog = 65536;
838 while((!(inSISREG(SISINPSTAT) & 0x08)) && --watchdog);
839 watchdog = 65536;
840 while((inSISREG(SISINPSTAT) & 0x08) && --watchdog);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700841}
842
843static BOOLEAN
844sisfbcheckvretracecrt2(struct sis_video_info *ivideo)
845{
Thomas Winischhofer544393f2005-09-09 13:04:45 -0700846 unsigned char temp, reg;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700847
Thomas Winischhofer544393f2005-09-09 13:04:45 -0700848 switch(ivideo->sisvga_engine) {
849 case SIS_300_VGA: reg = 0x25; break;
850 case SIS_315_VGA: reg = 0x30; break;
851 default: return FALSE;
852 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700853
Thomas Winischhofer544393f2005-09-09 13:04:45 -0700854 inSISIDXREG(SISPART1, reg, temp);
855 if(temp & 0x02)
856 return TRUE;
857 else
858 return FALSE;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700859}
860
861static BOOLEAN
862sisfb_CheckVBRetrace(struct sis_video_info *ivideo)
863{
Thomas Winischhofer544393f2005-09-09 13:04:45 -0700864 if(ivideo->currentvbflags & VB_DISPTYPE_DISP2) {
865 if(!sisfb_bridgeisslave(ivideo)) {
866 return sisfbcheckvretracecrt2(ivideo);
867 }
868 }
869 return sisfbcheckvretracecrt1(ivideo);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700870}
871
872static u32
873sisfb_setupvbblankflags(struct sis_video_info *ivideo, u32 *vcount, u32 *hcount)
874{
Thomas Winischhofer544393f2005-09-09 13:04:45 -0700875 u8 idx, reg1, reg2, reg3, reg4;
876 u32 ret = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700877
Thomas Winischhofer544393f2005-09-09 13:04:45 -0700878 (*vcount) = (*hcount) = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700879
Thomas Winischhofer544393f2005-09-09 13:04:45 -0700880 if((ivideo->currentvbflags & VB_DISPTYPE_DISP2) && (!(sisfb_bridgeisslave(ivideo)))) {
881
882 ret |= (FB_VBLANK_HAVE_VSYNC |
883 FB_VBLANK_HAVE_HBLANK |
884 FB_VBLANK_HAVE_VBLANK |
885 FB_VBLANK_HAVE_VCOUNT |
886 FB_VBLANK_HAVE_HCOUNT);
887 switch(ivideo->sisvga_engine) {
888 case SIS_300_VGA: idx = 0x25; break;
889 default:
890 case SIS_315_VGA: idx = 0x30; break;
891 }
892 inSISIDXREG(SISPART1,(idx+0),reg1); /* 30 */
893 inSISIDXREG(SISPART1,(idx+1),reg2); /* 31 */
894 inSISIDXREG(SISPART1,(idx+2),reg3); /* 32 */
895 inSISIDXREG(SISPART1,(idx+3),reg4); /* 33 */
896 if(reg1 & 0x01) ret |= FB_VBLANK_VBLANKING;
897 if(reg1 & 0x02) ret |= FB_VBLANK_VSYNCING;
898 if(reg4 & 0x80) ret |= FB_VBLANK_HBLANKING;
899 (*vcount) = reg3 | ((reg4 & 0x70) << 4);
900 (*hcount) = reg2 | ((reg4 & 0x0f) << 8);
901
902 } else if(sisfballowretracecrt1(ivideo)) {
903
904 ret |= (FB_VBLANK_HAVE_VSYNC |
905 FB_VBLANK_HAVE_VBLANK |
906 FB_VBLANK_HAVE_VCOUNT |
907 FB_VBLANK_HAVE_HCOUNT);
908 reg1 = inSISREG(SISINPSTAT);
909 if(reg1 & 0x08) ret |= FB_VBLANK_VSYNCING;
910 if(reg1 & 0x01) ret |= FB_VBLANK_VBLANKING;
911 inSISIDXREG(SISCR,0x20,reg1);
912 inSISIDXREG(SISCR,0x1b,reg1);
913 inSISIDXREG(SISCR,0x1c,reg2);
914 inSISIDXREG(SISCR,0x1d,reg3);
915 (*vcount) = reg2 | ((reg3 & 0x07) << 8);
916 (*hcount) = (reg1 | ((reg3 & 0x10) << 4)) << 3;
917 }
918
919 return ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700920}
921
922static int
923sisfb_myblank(struct sis_video_info *ivideo, int blank)
924{
Thomas Winischhofer544393f2005-09-09 13:04:45 -0700925 u8 sr01, sr11, sr1f, cr63=0, p2_0, p1_13;
926 BOOLEAN backlight = TRUE;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700927
Thomas Winischhofer544393f2005-09-09 13:04:45 -0700928 switch(blank) {
929 case FB_BLANK_UNBLANK: /* on */
930 sr01 = 0x00;
931 sr11 = 0x00;
932 sr1f = 0x00;
933 cr63 = 0x00;
934 p2_0 = 0x20;
935 p1_13 = 0x00;
936 backlight = TRUE;
937 break;
938 case FB_BLANK_NORMAL: /* blank */
939 sr01 = 0x20;
940 sr11 = 0x00;
941 sr1f = 0x00;
942 cr63 = 0x00;
943 p2_0 = 0x20;
944 p1_13 = 0x00;
945 backlight = TRUE;
946 break;
947 case FB_BLANK_VSYNC_SUSPEND: /* no vsync */
948 sr01 = 0x20;
949 sr11 = 0x08;
950 sr1f = 0x80;
951 cr63 = 0x40;
952 p2_0 = 0x40;
953 p1_13 = 0x80;
954 backlight = FALSE;
955 break;
956 case FB_BLANK_HSYNC_SUSPEND: /* no hsync */
957 sr01 = 0x20;
958 sr11 = 0x08;
959 sr1f = 0x40;
960 cr63 = 0x40;
961 p2_0 = 0x80;
962 p1_13 = 0x40;
963 backlight = FALSE;
964 break;
965 case FB_BLANK_POWERDOWN: /* off */
966 sr01 = 0x20;
967 sr11 = 0x08;
968 sr1f = 0xc0;
969 cr63 = 0x40;
970 p2_0 = 0xc0;
971 p1_13 = 0xc0;
972 backlight = FALSE;
973 break;
974 default:
975 return 1;
976 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700977
Thomas Winischhofer544393f2005-09-09 13:04:45 -0700978 if(ivideo->currentvbflags & VB_DISPTYPE_CRT1) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700979
Thomas Winischhofer544393f2005-09-09 13:04:45 -0700980 if( (!ivideo->sisfb_thismonitor.datavalid) ||
981 ((ivideo->sisfb_thismonitor.datavalid) &&
982 (ivideo->sisfb_thismonitor.feature & 0xe0))) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700983
Thomas Winischhofer544393f2005-09-09 13:04:45 -0700984 if(ivideo->sisvga_engine == SIS_315_VGA) {
985 setSISIDXREG(SISCR, ivideo->SiS_Pr.SiS_MyCR63, 0xbf, cr63);
986 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700987
Thomas Winischhofer544393f2005-09-09 13:04:45 -0700988 if(!(sisfb_bridgeisslave(ivideo))) {
989 setSISIDXREG(SISSR, 0x01, ~0x20, sr01);
990 setSISIDXREG(SISSR, 0x1f, 0x3f, sr1f);
991 }
992 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700993
Thomas Winischhofer544393f2005-09-09 13:04:45 -0700994 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700995
Thomas Winischhofer544393f2005-09-09 13:04:45 -0700996 if(ivideo->currentvbflags & CRT2_LCD) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700997
Thomas Winischhofer544393f2005-09-09 13:04:45 -0700998 if(ivideo->vbflags2 & VB2_SISLVDSBRIDGE) {
999 if(backlight) {
1000 SiS_SiS30xBLOn(&ivideo->SiS_Pr);
1001 } else {
1002 SiS_SiS30xBLOff(&ivideo->SiS_Pr);
1003 }
1004 } else if(ivideo->sisvga_engine == SIS_315_VGA) {
1005#ifdef CONFIG_FB_SIS_315
1006 if(ivideo->vbflags2 & VB2_CHRONTEL) {
1007 if(backlight) {
1008 SiS_Chrontel701xBLOn(&ivideo->SiS_Pr);
1009 } else {
1010 SiS_Chrontel701xBLOff(&ivideo->SiS_Pr);
1011 }
1012 }
1013#endif
1014 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001015
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001016 if(((ivideo->sisvga_engine == SIS_300_VGA) &&
1017 (ivideo->vbflags2 & (VB2_301|VB2_30xBDH|VB2_LVDS))) ||
1018 ((ivideo->sisvga_engine == SIS_315_VGA) &&
1019 ((ivideo->vbflags2 & (VB2_LVDS | VB2_CHRONTEL)) == VB2_LVDS))) {
1020 setSISIDXREG(SISSR, 0x11, ~0x0c, sr11);
1021 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001022
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001023 if(ivideo->sisvga_engine == SIS_300_VGA) {
1024 if((ivideo->vbflags2 & VB2_30xB) &&
1025 (!(ivideo->vbflags2 & VB2_30xBDH))) {
1026 setSISIDXREG(SISPART1, 0x13, 0x3f, p1_13);
1027 }
1028 } else if(ivideo->sisvga_engine == SIS_315_VGA) {
1029 if((ivideo->vbflags2 & VB2_30xB) &&
1030 (!(ivideo->vbflags2 & VB2_30xBDH))) {
1031 setSISIDXREG(SISPART2, 0x00, 0x1f, p2_0);
1032 }
1033 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001034
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001035 } else if(ivideo->currentvbflags & CRT2_VGA) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001036
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001037 if(ivideo->vbflags2 & VB2_30xB) {
1038 setSISIDXREG(SISPART2, 0x00, 0x1f, p2_0);
1039 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001040
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001041 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001042
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001043 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001044}
1045
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001046/* ------------- Callbacks from init.c/init301.c -------------- */
1047
1048#ifdef CONFIG_FB_SIS_300
1049unsigned int
1050sisfb_read_nbridge_pci_dword(struct SiS_Private *SiS_Pr, int reg)
1051{
1052 struct sis_video_info *ivideo = (struct sis_video_info *)SiS_Pr->ivideo;
1053 u32 val = 0;
1054
1055 pci_read_config_dword(ivideo->nbridge, reg, &val);
1056 return (unsigned int)val;
1057}
1058
1059void
1060sisfb_write_nbridge_pci_dword(struct SiS_Private *SiS_Pr, int reg, unsigned int val)
1061{
1062 struct sis_video_info *ivideo = (struct sis_video_info *)SiS_Pr->ivideo;
1063
1064 pci_write_config_dword(ivideo->nbridge, reg, (u32)val);
1065}
1066
1067unsigned int
1068sisfb_read_lpc_pci_dword(struct SiS_Private *SiS_Pr, int reg)
1069{
1070 struct sis_video_info *ivideo = (struct sis_video_info *)SiS_Pr->ivideo;
1071 u32 val = 0;
1072
1073 if(!ivideo->lpcdev) return 0;
1074
1075 pci_read_config_dword(ivideo->lpcdev, reg, &val);
1076 return (unsigned int)val;
1077}
1078#endif
1079
1080#ifdef CONFIG_FB_SIS_315
1081void
1082sisfb_write_nbridge_pci_byte(struct SiS_Private *SiS_Pr, int reg, unsigned char val)
1083{
1084 struct sis_video_info *ivideo = (struct sis_video_info *)SiS_Pr->ivideo;
1085
1086 pci_write_config_byte(ivideo->nbridge, reg, (u8)val);
1087}
1088
1089unsigned int
1090sisfb_read_mio_pci_word(struct SiS_Private *SiS_Pr, int reg)
1091{
1092 struct sis_video_info *ivideo = (struct sis_video_info *)SiS_Pr->ivideo;
1093 u16 val = 0;
1094
1095 if(!ivideo->lpcdev) return 0;
1096
1097 pci_read_config_word(ivideo->lpcdev, reg, &val);
1098 return (unsigned int)val;
1099}
1100#endif
1101
Linus Torvalds1da177e2005-04-16 15:20:36 -07001102/* ----------- FBDev related routines for all series ----------- */
1103
1104static int
1105sisfb_get_cmap_len(const struct fb_var_screeninfo *var)
1106{
1107 return (var->bits_per_pixel == 8) ? 256 : 16;
1108}
1109
1110static void
1111sisfb_set_vparms(struct sis_video_info *ivideo)
1112{
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001113 switch(ivideo->video_bpp) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001114 case 8:
1115 ivideo->DstColor = 0x0000;
1116 ivideo->SiS310_AccelDepth = 0x00000000;
1117 ivideo->video_cmap_len = 256;
1118 break;
1119 case 16:
1120 ivideo->DstColor = 0x8000;
1121 ivideo->SiS310_AccelDepth = 0x00010000;
1122 ivideo->video_cmap_len = 16;
1123 break;
1124 case 32:
1125 ivideo->DstColor = 0xC000;
1126 ivideo->SiS310_AccelDepth = 0x00020000;
1127 ivideo->video_cmap_len = 16;
1128 break;
1129 default:
1130 ivideo->video_cmap_len = 16;
1131 printk(KERN_ERR "sisfb: Unsupported depth %d", ivideo->video_bpp);
1132 ivideo->accel = 0;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001133 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001134}
1135
1136static int
1137sisfb_calc_maxyres(struct sis_video_info *ivideo, struct fb_var_screeninfo *var)
1138{
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001139 int maxyres = ivideo->sisfb_mem / (var->xres_virtual * (var->bits_per_pixel >> 3));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001140
1141 if(maxyres > 32767) maxyres = 32767;
1142
1143 return maxyres;
1144}
1145
1146static void
1147sisfb_calc_pitch(struct sis_video_info *ivideo, struct fb_var_screeninfo *var)
1148{
1149 ivideo->video_linelength = var->xres_virtual * (var->bits_per_pixel >> 3);
1150 ivideo->scrnpitchCRT1 = ivideo->video_linelength;
1151 if(!(ivideo->currentvbflags & CRT1_LCDA)) {
1152 if((var->vmode & FB_VMODE_MASK) == FB_VMODE_INTERLACED) {
1153 ivideo->scrnpitchCRT1 <<= 1;
1154 }
1155 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001156}
1157
1158static void
1159sisfb_set_pitch(struct sis_video_info *ivideo)
1160{
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001161 BOOLEAN isslavemode = FALSE;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001162 unsigned short HDisplay1 = ivideo->scrnpitchCRT1 >> 3;
1163 unsigned short HDisplay2 = ivideo->video_linelength >> 3;
1164
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001165 if(sisfb_bridgeisslave(ivideo)) isslavemode = TRUE;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001166
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001167 /* We need to set pitch for CRT1 if bridge is in slave mode, too */
1168 if((ivideo->currentvbflags & VB_DISPTYPE_DISP1) || (isslavemode)) {
1169 outSISIDXREG(SISCR,0x13,(HDisplay1 & 0xFF));
1170 setSISIDXREG(SISSR,0x0E,0xF0,(HDisplay1 >> 8));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001171 }
1172
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001173 /* We must not set the pitch for CRT2 if bridge is in slave mode */
1174 if((ivideo->currentvbflags & VB_DISPTYPE_DISP2) && (!isslavemode)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001175 orSISIDXREG(SISPART1,ivideo->CRT2_write_enable,0x01);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001176 outSISIDXREG(SISPART1,0x07,(HDisplay2 & 0xFF));
1177 setSISIDXREG(SISPART1,0x09,0xF0,(HDisplay2 >> 8));
1178 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001179}
1180
1181static void
1182sisfb_bpp_to_var(struct sis_video_info *ivideo, struct fb_var_screeninfo *var)
1183{
1184 ivideo->video_cmap_len = sisfb_get_cmap_len(var);
1185
1186 switch(var->bits_per_pixel) {
1187 case 8:
1188 var->red.offset = var->green.offset = var->blue.offset = 0;
1189 var->red.length = var->green.length = var->blue.length = 6;
1190 break;
1191 case 16:
1192 var->red.offset = 11;
1193 var->red.length = 5;
1194 var->green.offset = 5;
1195 var->green.length = 6;
1196 var->blue.offset = 0;
1197 var->blue.length = 5;
1198 var->transp.offset = 0;
1199 var->transp.length = 0;
1200 break;
1201 case 32:
1202 var->red.offset = 16;
1203 var->red.length = 8;
1204 var->green.offset = 8;
1205 var->green.length = 8;
1206 var->blue.offset = 0;
1207 var->blue.length = 8;
1208 var->transp.offset = 24;
1209 var->transp.length = 8;
1210 break;
1211 }
1212}
1213
1214static int
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001215sisfb_set_mode(struct sis_video_info *ivideo, int clrscrn)
1216{
1217 unsigned short modeno = ivideo->mode_no;
1218
1219 /* >=2.6.12's fbcon clears the screen anyway */
1220#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,12)
1221 if(!clrscrn) modeno |= 0x80;
1222#else
1223 modeno |= 0x80;
1224#endif
1225
1226 outSISIDXREG(SISSR, IND_SIS_PASSWORD, SIS_PASSWORD);
1227
1228 sisfb_pre_setmode(ivideo);
1229
1230 if(SiSSetMode(&ivideo->SiS_Pr, modeno) == 0) {
1231 printk(KERN_ERR "sisfb: Setting mode[0x%x] failed\n", ivideo->mode_no);
1232 return -EINVAL;
1233 }
1234
1235 outSISIDXREG(SISSR, IND_SIS_PASSWORD, SIS_PASSWORD);
1236
1237 sisfb_post_setmode(ivideo);
1238
1239 return 0;
1240}
1241
1242
1243static int
Linus Torvalds1da177e2005-04-16 15:20:36 -07001244sisfb_do_set_var(struct fb_var_screeninfo *var, int isactive, struct fb_info *info)
1245{
1246 struct sis_video_info *ivideo = (struct sis_video_info *)info->par;
1247 unsigned int htotal = 0, vtotal = 0;
1248 unsigned int drate = 0, hrate = 0;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001249 int found_mode = 0, ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001250 int old_mode;
1251 u32 pixclock;
1252
1253 htotal = var->left_margin + var->xres + var->right_margin + var->hsync_len;
1254
1255 vtotal = var->upper_margin + var->lower_margin + var->vsync_len;
1256
1257 pixclock = var->pixclock;
1258
1259 if((var->vmode & FB_VMODE_MASK) == FB_VMODE_NONINTERLACED) {
1260 vtotal += var->yres;
1261 vtotal <<= 1;
1262 } else if((var->vmode & FB_VMODE_MASK) == FB_VMODE_DOUBLE) {
1263 vtotal += var->yres;
1264 vtotal <<= 2;
1265 } else if((var->vmode & FB_VMODE_MASK) == FB_VMODE_INTERLACED) {
1266 vtotal += var->yres;
1267 vtotal <<= 1;
1268 } else vtotal += var->yres;
1269
1270 if(!(htotal) || !(vtotal)) {
1271 DPRINTK("sisfb: Invalid 'var' information\n");
1272 return -EINVAL;
1273 }
1274
1275 if(pixclock && htotal && vtotal) {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001276 drate = 1000000000 / pixclock;
1277 hrate = (drate * 1000) / htotal;
1278 ivideo->refresh_rate = (unsigned int) (hrate * 2 / vtotal);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001279 } else {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001280 ivideo->refresh_rate = 60;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001281 }
1282
1283 old_mode = ivideo->sisfb_mode_idx;
1284 ivideo->sisfb_mode_idx = 0;
1285
1286 while( (sisbios_mode[ivideo->sisfb_mode_idx].mode_no[0] != 0) &&
1287 (sisbios_mode[ivideo->sisfb_mode_idx].xres <= var->xres) ) {
1288 if( (sisbios_mode[ivideo->sisfb_mode_idx].xres == var->xres) &&
1289 (sisbios_mode[ivideo->sisfb_mode_idx].yres == var->yres) &&
1290 (sisbios_mode[ivideo->sisfb_mode_idx].bpp == var->bits_per_pixel)) {
1291 ivideo->mode_no = sisbios_mode[ivideo->sisfb_mode_idx].mode_no[ivideo->mni];
1292 found_mode = 1;
1293 break;
1294 }
1295 ivideo->sisfb_mode_idx++;
1296 }
1297
1298 if(found_mode) {
1299 ivideo->sisfb_mode_idx = sisfb_validate_mode(ivideo,
1300 ivideo->sisfb_mode_idx, ivideo->currentvbflags);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001301 ivideo->mode_no = sisbios_mode[ivideo->sisfb_mode_idx].mode_no[ivideo->mni];
Linus Torvalds1da177e2005-04-16 15:20:36 -07001302 } else {
1303 ivideo->sisfb_mode_idx = -1;
1304 }
1305
1306 if(ivideo->sisfb_mode_idx < 0) {
1307 printk(KERN_ERR "sisfb: Mode %dx%dx%d not supported\n", var->xres,
1308 var->yres, var->bits_per_pixel);
1309 ivideo->sisfb_mode_idx = old_mode;
1310 return -EINVAL;
1311 }
1312
1313 if(sisfb_search_refresh_rate(ivideo, ivideo->refresh_rate, ivideo->sisfb_mode_idx) == 0) {
1314 ivideo->rate_idx = sisbios_mode[ivideo->sisfb_mode_idx].rate_idx;
1315 ivideo->refresh_rate = 60;
1316 }
1317
1318#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
1319 if(ivideo->sisfb_thismonitor.datavalid) {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001320 if(!sisfb_verify_rate(ivideo, &ivideo->sisfb_thismonitor, ivideo->sisfb_mode_idx,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001321 ivideo->rate_idx, ivideo->refresh_rate)) {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001322 printk(KERN_INFO "sisfb: WARNING: Refresh rate exceeds monitor specs!\n");
1323 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001324 }
1325#endif
1326
1327#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
1328 if(((var->activate & FB_ACTIVATE_MASK) == FB_ACTIVATE_NOW) && isactive) {
1329#else
1330 if(isactive) {
1331#endif
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001332 /* If acceleration to be used? Need to know
1333 * before pre/post_set_mode()
1334 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001335 ivideo->accel = 0;
1336#if defined(FBINFO_HWACCEL_DISABLED) && defined(FBINFO_HWACCEL_XPAN)
1337#ifdef STUPID_ACCELF_TEXT_SHIT
1338 if(var->accel_flags & FB_ACCELF_TEXT) {
1339 info->flags &= ~FBINFO_HWACCEL_DISABLED;
1340 } else {
1341 info->flags |= FBINFO_HWACCEL_DISABLED;
1342 }
1343#endif
1344 if(!(info->flags & FBINFO_HWACCEL_DISABLED)) ivideo->accel = -1;
1345#else
1346 if(var->accel_flags & FB_ACCELF_TEXT) ivideo->accel = -1;
1347#endif
1348
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001349 if((ret = sisfb_set_mode(ivideo, 1))) {
1350 return ret;
1351 }
1352
1353 ivideo->video_bpp = sisbios_mode[ivideo->sisfb_mode_idx].bpp;
1354 ivideo->video_width = sisbios_mode[ivideo->sisfb_mode_idx].xres;
1355 ivideo->video_height = sisbios_mode[ivideo->sisfb_mode_idx].yres;
1356
1357 sisfb_calc_pitch(ivideo, var);
1358 sisfb_set_pitch(ivideo);
1359
Linus Torvalds1da177e2005-04-16 15:20:36 -07001360 sisfb_set_vparms(ivideo);
1361
1362 ivideo->current_width = ivideo->video_width;
1363 ivideo->current_height = ivideo->video_height;
1364 ivideo->current_bpp = ivideo->video_bpp;
1365 ivideo->current_htotal = htotal;
1366 ivideo->current_vtotal = vtotal;
1367 ivideo->current_linelength = ivideo->video_linelength;
1368 ivideo->current_pixclock = var->pixclock;
1369 ivideo->current_refresh_rate = ivideo->refresh_rate;
1370#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0)
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001371 ivideo->sisfb_lastrates[ivideo->mode_no] = ivideo->refresh_rate;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001372#endif
1373 }
1374
1375 return 0;
1376}
1377
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001378static void
1379sisfb_set_base_CRT1(struct sis_video_info *ivideo, unsigned int base)
1380{
1381 outSISIDXREG(SISSR, IND_SIS_PASSWORD, SIS_PASSWORD);
1382
1383 outSISIDXREG(SISCR, 0x0D, base & 0xFF);
1384 outSISIDXREG(SISCR, 0x0C, (base >> 8) & 0xFF);
1385 outSISIDXREG(SISSR, 0x0D, (base >> 16) & 0xFF);
1386 if(ivideo->sisvga_engine == SIS_315_VGA) {
1387 setSISIDXREG(SISSR, 0x37, 0xFE, (base >> 24) & 0x01);
1388 }
1389}
1390
1391static void
1392sisfb_set_base_CRT2(struct sis_video_info *ivideo, unsigned int base)
1393{
1394 if(ivideo->currentvbflags & VB_DISPTYPE_DISP2) {
1395 orSISIDXREG(SISPART1, ivideo->CRT2_write_enable, 0x01);
1396 outSISIDXREG(SISPART1, 0x06, (base & 0xFF));
1397 outSISIDXREG(SISPART1, 0x05, ((base >> 8) & 0xFF));
1398 outSISIDXREG(SISPART1, 0x04, ((base >> 16) & 0xFF));
1399 if(ivideo->sisvga_engine == SIS_315_VGA) {
1400 setSISIDXREG(SISPART1, 0x02, 0x7F, ((base >> 24) & 0x01) << 7);
1401 }
1402 }
1403}
1404
Linus Torvalds1da177e2005-04-16 15:20:36 -07001405static int
1406sisfb_pan_var(struct sis_video_info *ivideo, struct fb_var_screeninfo *var)
1407{
Linus Torvalds1da177e2005-04-16 15:20:36 -07001408 if(var->xoffset > (var->xres_virtual - var->xres)) {
1409 return -EINVAL;
1410 }
1411 if(var->yoffset > (var->yres_virtual - var->yres)) {
1412 return -EINVAL;
1413 }
1414
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001415 ivideo->current_base = (var->yoffset * var->xres_virtual) + var->xoffset;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001416
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001417 /* calculate base bpp dep. */
1418 switch(var->bits_per_pixel) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001419 case 32:
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001420 break;
1421 case 16:
1422 ivideo->current_base >>= 1;
1423 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001424 case 8:
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001425 default:
1426 ivideo->current_base >>= 2;
1427 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001428 }
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001429
1430 ivideo->current_base += (ivideo->video_offset >> 2);
1431
1432 sisfb_set_base_CRT1(ivideo, ivideo->current_base);
1433 sisfb_set_base_CRT2(ivideo, ivideo->current_base);
1434
Linus Torvalds1da177e2005-04-16 15:20:36 -07001435 return 0;
1436}
1437
1438/* ------------ FBDev related routines for 2.4 series ----------- */
1439
1440#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
1441
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001442#include "sisfb_fbdev_2_4.h"
Linus Torvalds1da177e2005-04-16 15:20:36 -07001443
Linus Torvalds1da177e2005-04-16 15:20:36 -07001444#endif
1445
1446/* ------------ FBDev related routines for 2.6 series ----------- */
1447
1448#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0)
1449
1450static int
1451sisfb_open(struct fb_info *info, int user)
1452{
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001453 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001454}
1455
1456static int
1457sisfb_release(struct fb_info *info, int user)
1458{
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001459 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001460}
1461
1462static int
1463sisfb_setcolreg(unsigned regno, unsigned red, unsigned green, unsigned blue,
1464 unsigned transp, struct fb_info *info)
1465{
1466 struct sis_video_info *ivideo = (struct sis_video_info *)info->par;
1467
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001468 if(regno >= sisfb_get_cmap_len(&info->var))
1469 return 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001470
1471 switch(info->var.bits_per_pixel) {
1472 case 8:
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001473 outSISREG(SISDACA, regno);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001474 outSISREG(SISDACD, (red >> 10));
1475 outSISREG(SISDACD, (green >> 10));
1476 outSISREG(SISDACD, (blue >> 10));
1477 if(ivideo->currentvbflags & VB_DISPTYPE_DISP2) {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001478 outSISREG(SISDAC2A, regno);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001479 outSISREG(SISDAC2D, (red >> 8));
1480 outSISREG(SISDAC2D, (green >> 8));
1481 outSISREG(SISDAC2D, (blue >> 8));
1482 }
1483 break;
1484 case 16:
1485 ((u32 *)(info->pseudo_palette))[regno] =
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001486 (red & 0xf800) |
1487 ((green & 0xfc00) >> 5) |
1488 ((blue & 0xf800) >> 11);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001489 break;
1490 case 32:
1491 red >>= 8;
1492 green >>= 8;
1493 blue >>= 8;
1494 ((u32 *)(info->pseudo_palette))[regno] =
1495 (red << 16) | (green << 8) | (blue);
1496 break;
1497 }
1498 return 0;
1499}
1500
1501static int
1502sisfb_set_par(struct fb_info *info)
1503{
1504 int err;
1505
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001506 if((err = sisfb_do_set_var(&info->var, 1, info)))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001507 return err;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001508
Linus Torvalds1da177e2005-04-16 15:20:36 -07001509#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,10)
1510 sisfb_get_fix(&info->fix, info->currcon, info);
1511#else
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001512 sisfb_get_fix(&info->fix, -1, info);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001513#endif
1514 return 0;
1515}
1516
1517static int
1518sisfb_check_var(struct fb_var_screeninfo *var, struct fb_info *info)
1519{
1520 struct sis_video_info *ivideo = (struct sis_video_info *)info->par;
1521 unsigned int htotal = 0, vtotal = 0, myrateindex = 0;
1522 unsigned int drate = 0, hrate = 0, maxyres;
1523 int found_mode = 0;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001524 int refresh_rate, search_idx, tidx;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001525 BOOLEAN recalc_clock = FALSE;
1526 u32 pixclock;
1527
1528 htotal = var->left_margin + var->xres + var->right_margin + var->hsync_len;
1529
1530 vtotal = var->upper_margin + var->lower_margin + var->vsync_len;
1531
1532 pixclock = var->pixclock;
1533
1534 if((var->vmode & FB_VMODE_MASK) == FB_VMODE_NONINTERLACED) {
1535 vtotal += var->yres;
1536 vtotal <<= 1;
1537 } else if((var->vmode & FB_VMODE_MASK) == FB_VMODE_DOUBLE) {
1538 vtotal += var->yres;
1539 vtotal <<= 2;
1540 } else if((var->vmode & FB_VMODE_MASK) == FB_VMODE_INTERLACED) {
1541 vtotal += var->yres;
1542 vtotal <<= 1;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001543 } else
1544 vtotal += var->yres;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001545
1546 if(!(htotal) || !(vtotal)) {
1547 SISFAIL("sisfb: no valid timing data");
1548 }
1549
1550 search_idx = 0;
1551 while( (sisbios_mode[search_idx].mode_no[0] != 0) &&
1552 (sisbios_mode[search_idx].xres <= var->xres) ) {
1553 if( (sisbios_mode[search_idx].xres == var->xres) &&
1554 (sisbios_mode[search_idx].yres == var->yres) &&
1555 (sisbios_mode[search_idx].bpp == var->bits_per_pixel)) {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001556 if((tidx = sisfb_validate_mode(ivideo, search_idx,
1557 ivideo->currentvbflags)) > 0) {
1558 found_mode = 1;
1559 search_idx = tidx;
1560 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001561 }
1562 }
1563 search_idx++;
1564 }
1565
1566 if(!found_mode) {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001567 search_idx = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001568 while(sisbios_mode[search_idx].mode_no[0] != 0) {
1569 if( (var->xres <= sisbios_mode[search_idx].xres) &&
1570 (var->yres <= sisbios_mode[search_idx].yres) &&
1571 (var->bits_per_pixel == sisbios_mode[search_idx].bpp) ) {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001572 if((tidx = sisfb_validate_mode(ivideo,search_idx,
1573 ivideo->currentvbflags)) > 0) {
1574 found_mode = 1;
1575 search_idx = tidx;
1576 break;
1577 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001578 }
1579 search_idx++;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001580 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001581 if(found_mode) {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001582 printk(KERN_DEBUG
1583 "sisfb: Adapted from %dx%dx%d to %dx%dx%d\n",
1584 var->xres, var->yres, var->bits_per_pixel,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001585 sisbios_mode[search_idx].xres,
1586 sisbios_mode[search_idx].yres,
1587 var->bits_per_pixel);
1588 var->xres = sisbios_mode[search_idx].xres;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001589 var->yres = sisbios_mode[search_idx].yres;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001590 } else {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001591 printk(KERN_ERR
1592 "sisfb: Failed to find supported mode near %dx%dx%d\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07001593 var->xres, var->yres, var->bits_per_pixel);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001594 return -EINVAL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001595 }
1596 }
1597
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001598 if( ((ivideo->vbflags2 & VB2_LVDS) ||
1599 ((ivideo->vbflags2 & VB2_30xBDH) && (ivideo->currentvbflags & CRT2_LCD))) &&
Linus Torvalds1da177e2005-04-16 15:20:36 -07001600 (var->bits_per_pixel == 8) ) {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001601 /* Slave modes on LVDS and 301B-DH */
1602 refresh_rate = 60;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001603 recalc_clock = TRUE;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001604 } else if( (ivideo->current_htotal == htotal) &&
1605 (ivideo->current_vtotal == vtotal) &&
1606 (ivideo->current_pixclock == pixclock) ) {
1607 /* x=x & y=y & c=c -> assume depth change */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001608 drate = 1000000000 / pixclock;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001609 hrate = (drate * 1000) / htotal;
1610 refresh_rate = (unsigned int) (hrate * 2 / vtotal);
1611 } else if( ( (ivideo->current_htotal != htotal) ||
1612 (ivideo->current_vtotal != vtotal) ) &&
1613 (ivideo->current_pixclock == var->pixclock) ) {
1614 /* x!=x | y!=y & c=c -> invalid pixclock */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001615 if(ivideo->sisfb_lastrates[sisbios_mode[search_idx].mode_no[ivideo->mni]]) {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001616 refresh_rate =
1617 ivideo->sisfb_lastrates[sisbios_mode[search_idx].mode_no[ivideo->mni]];
Linus Torvalds1da177e2005-04-16 15:20:36 -07001618 } else if(ivideo->sisfb_parm_rate != -1) {
1619 /* Sic, sisfb_parm_rate - want to know originally desired rate here */
1620 refresh_rate = ivideo->sisfb_parm_rate;
1621 } else {
1622 refresh_rate = 60;
1623 }
1624 recalc_clock = TRUE;
1625 } else if((pixclock) && (htotal) && (vtotal)) {
1626 drate = 1000000000 / pixclock;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001627 hrate = (drate * 1000) / htotal;
1628 refresh_rate = (unsigned int) (hrate * 2 / vtotal);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001629 } else if(ivideo->current_refresh_rate) {
1630 refresh_rate = ivideo->current_refresh_rate;
1631 recalc_clock = TRUE;
1632 } else {
1633 refresh_rate = 60;
1634 recalc_clock = TRUE;
1635 }
1636
1637 myrateindex = sisfb_search_refresh_rate(ivideo, refresh_rate, search_idx);
1638
1639 /* Eventually recalculate timing and clock */
1640 if(recalc_clock) {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001641 if(!myrateindex) myrateindex = sisbios_mode[search_idx].rate_idx;
1642 var->pixclock = (u32) (1000000000 / sisfb_mode_rate_to_dclock(&ivideo->SiS_Pr,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001643 sisbios_mode[search_idx].mode_no[ivideo->mni],
1644 myrateindex));
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001645 sisfb_mode_rate_to_ddata(&ivideo->SiS_Pr,
1646 sisbios_mode[search_idx].mode_no[ivideo->mni],
1647 myrateindex, var);
1648 if((var->vmode & FB_VMODE_MASK) == FB_VMODE_DOUBLE) {
1649 var->pixclock <<= 1;
1650 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001651 }
1652
1653 if(ivideo->sisfb_thismonitor.datavalid) {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001654 if(!sisfb_verify_rate(ivideo, &ivideo->sisfb_thismonitor, search_idx,
1655 myrateindex, refresh_rate)) {
1656 printk(KERN_INFO
1657 "sisfb: WARNING: Refresh rate exceeds monitor specs!\n");
1658 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001659 }
1660
1661 /* Adapt RGB settings */
1662 sisfb_bpp_to_var(ivideo, var);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001663
Linus Torvalds1da177e2005-04-16 15:20:36 -07001664 /* Sanity check for offsets */
1665 if(var->xoffset < 0) var->xoffset = 0;
1666 if(var->yoffset < 0) var->yoffset = 0;
1667
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001668 if(var->xres > var->xres_virtual)
1669 var->xres_virtual = var->xres;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001670
1671 if(ivideo->sisfb_ypan) {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001672 maxyres = sisfb_calc_maxyres(ivideo, var);
1673 if(ivideo->sisfb_max) {
1674 var->yres_virtual = maxyres;
1675 } else {
1676 if(var->yres_virtual > maxyres) {
1677 var->yres_virtual = maxyres;
1678 }
1679 }
1680 if(var->yres_virtual <= var->yres) {
1681 var->yres_virtual = var->yres;
1682 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001683 } else {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001684 if(var->yres != var->yres_virtual) {
1685 var->yres_virtual = var->yres;
1686 }
1687 var->xoffset = 0;
1688 var->yoffset = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001689 }
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001690
Linus Torvalds1da177e2005-04-16 15:20:36 -07001691 /* Truncate offsets to maximum if too high */
1692 if(var->xoffset > var->xres_virtual - var->xres) {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001693 var->xoffset = var->xres_virtual - var->xres - 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001694 }
1695
1696 if(var->yoffset > var->yres_virtual - var->yres) {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001697 var->yoffset = var->yres_virtual - var->yres - 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001698 }
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001699
Linus Torvalds1da177e2005-04-16 15:20:36 -07001700 /* Set everything else to 0 */
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001701 var->red.msb_right =
1702 var->green.msb_right =
1703 var->blue.msb_right =
1704 var->transp.offset =
1705 var->transp.length =
1706 var->transp.msb_right = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001707
1708 return 0;
1709}
1710
1711static int
1712sisfb_pan_display(struct fb_var_screeninfo *var, struct fb_info* info)
1713{
1714 struct sis_video_info *ivideo = (struct sis_video_info *)info->par;
1715 int err;
1716
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001717 if(var->xoffset > (var->xres_virtual - var->xres))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001718 return -EINVAL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001719
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001720 if(var->yoffset > (var->yres_virtual - var->yres))
1721 return -EINVAL;
1722
1723 if(var->vmode & FB_VMODE_YWRAP)
1724 return -EINVAL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001725
1726 if(var->xoffset + info->var.xres > info->var.xres_virtual ||
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001727 var->yoffset + info->var.yres > info->var.yres_virtual)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001728 return -EINVAL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001729
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001730 if((err = sisfb_pan_var(ivideo, var)) < 0)
1731 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001732
1733 info->var.xoffset = var->xoffset;
1734 info->var.yoffset = var->yoffset;
1735
1736 return 0;
1737}
1738
1739static int
1740sisfb_blank(int blank, struct fb_info *info)
1741{
1742 struct sis_video_info *ivideo = (struct sis_video_info *)info->par;
1743
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001744 return sisfb_myblank(ivideo, blank);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001745}
1746
1747#endif
1748
1749/* ----------- FBDev related routines for all series ---------- */
1750
Christoph Hellwig67a66802006-01-14 13:21:25 -08001751#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,15)
1752static int sisfb_ioctl(struct fb_info *info, unsigned int cmd,
1753 unsigned long arg)
1754#else
1755static int sisfb_ioctl(struct inode *inode, struct file *file,
1756 unsigned int cmd, unsigned long arg,
1757 struct fb_info *info)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001758#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -07001759{
1760 struct sis_video_info *ivideo = (struct sis_video_info *)info->par;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001761 struct sis_memreq sismemreq;
1762 struct fb_vblank sisvbblank;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001763 u32 gpu32 = 0;
1764#ifndef __user
1765#define __user
1766#endif
1767 u32 __user *argp = (u32 __user *)arg;
1768
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001769 switch(cmd) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001770 case FBIO_ALLOC:
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001771 if(!capable(CAP_SYS_RAWIO))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001772 return -EPERM;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001773
1774 if(copy_from_user(&sismemreq, (void __user *)arg, sizeof(sismemreq)))
1775 return -EFAULT;
1776
Linus Torvalds1da177e2005-04-16 15:20:36 -07001777 sis_malloc(&sismemreq);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001778
Linus Torvalds1da177e2005-04-16 15:20:36 -07001779 if(copy_to_user((void __user *)arg, &sismemreq, sizeof(sismemreq))) {
1780 sis_free((u32)sismemreq.offset);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001781 return -EFAULT;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001782 }
1783 break;
1784
1785 case FBIO_FREE:
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001786 if(!capable(CAP_SYS_RAWIO))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001787 return -EPERM;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001788
1789 if(get_user(gpu32, argp))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001790 return -EFAULT;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001791
Linus Torvalds1da177e2005-04-16 15:20:36 -07001792 sis_free(gpu32);
1793 break;
1794
1795 case FBIOGET_VBLANK:
1796 sisvbblank.count = 0;
1797 sisvbblank.flags = sisfb_setupvbblankflags(ivideo, &sisvbblank.vcount, &sisvbblank.hcount);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001798
1799 if(copy_to_user((void __user *)arg, &sisvbblank, sizeof(sisvbblank)))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001800 return -EFAULT;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001801
Linus Torvalds1da177e2005-04-16 15:20:36 -07001802 break;
1803
1804 case SISFB_GET_INFO_SIZE:
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001805 return put_user(sizeof(struct sisfb_info), argp);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001806
1807 case SISFB_GET_INFO_OLD:
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001808 if(ivideo->warncount++ < 10)
1809 printk(KERN_INFO
1810 "sisfb: Deprecated ioctl call received - update your application!\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001811 case SISFB_GET_INFO: /* For communication with X driver */
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001812 ivideo->sisfb_infoblock.sisfb_id = SISFB_ID;
1813 ivideo->sisfb_infoblock.sisfb_version = VER_MAJOR;
1814 ivideo->sisfb_infoblock.sisfb_revision = VER_MINOR;
1815 ivideo->sisfb_infoblock.sisfb_patchlevel = VER_LEVEL;
1816 ivideo->sisfb_infoblock.chip_id = ivideo->chip_id;
1817 ivideo->sisfb_infoblock.sisfb_pci_vendor = ivideo->chip_vendor;
1818 ivideo->sisfb_infoblock.memory = ivideo->video_size / 1024;
1819 ivideo->sisfb_infoblock.heapstart = ivideo->heapstart / 1024;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001820 if(ivideo->modechanged) {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001821 ivideo->sisfb_infoblock.fbvidmode = ivideo->mode_no;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001822 } else {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001823 ivideo->sisfb_infoblock.fbvidmode = ivideo->modeprechange;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001824 }
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001825 ivideo->sisfb_infoblock.sisfb_caps = ivideo->caps;
1826 ivideo->sisfb_infoblock.sisfb_tqlen = ivideo->cmdQueueSize / 1024;
1827 ivideo->sisfb_infoblock.sisfb_pcibus = ivideo->pcibus;
1828 ivideo->sisfb_infoblock.sisfb_pcislot = ivideo->pcislot;
1829 ivideo->sisfb_infoblock.sisfb_pcifunc = ivideo->pcifunc;
1830 ivideo->sisfb_infoblock.sisfb_lcdpdc = ivideo->detectedpdc;
1831 ivideo->sisfb_infoblock.sisfb_lcdpdca = ivideo->detectedpdca;
1832 ivideo->sisfb_infoblock.sisfb_lcda = ivideo->detectedlcda;
1833 ivideo->sisfb_infoblock.sisfb_vbflags = ivideo->vbflags;
1834 ivideo->sisfb_infoblock.sisfb_currentvbflags = ivideo->currentvbflags;
1835 ivideo->sisfb_infoblock.sisfb_scalelcd = ivideo->SiS_Pr.UsePanelScaler;
1836 ivideo->sisfb_infoblock.sisfb_specialtiming = ivideo->SiS_Pr.SiS_CustomT;
1837 ivideo->sisfb_infoblock.sisfb_haveemi = ivideo->SiS_Pr.HaveEMI ? 1 : 0;
1838 ivideo->sisfb_infoblock.sisfb_haveemilcd = ivideo->SiS_Pr.HaveEMILCD ? 1 : 0;
1839 ivideo->sisfb_infoblock.sisfb_emi30 = ivideo->SiS_Pr.EMI_30;
1840 ivideo->sisfb_infoblock.sisfb_emi31 = ivideo->SiS_Pr.EMI_31;
1841 ivideo->sisfb_infoblock.sisfb_emi32 = ivideo->SiS_Pr.EMI_32;
1842 ivideo->sisfb_infoblock.sisfb_emi33 = ivideo->SiS_Pr.EMI_33;
1843 ivideo->sisfb_infoblock.sisfb_tvxpos = (u16)(ivideo->tvxpos + 32);
1844 ivideo->sisfb_infoblock.sisfb_tvypos = (u16)(ivideo->tvypos + 32);
1845 ivideo->sisfb_infoblock.sisfb_heapsize = ivideo->sisfb_heap_size / 1024;
1846 ivideo->sisfb_infoblock.sisfb_videooffset = ivideo->video_offset;
1847 ivideo->sisfb_infoblock.sisfb_curfstn = ivideo->curFSTN;
1848 ivideo->sisfb_infoblock.sisfb_curdstn = ivideo->curDSTN;
1849 ivideo->sisfb_infoblock.sisfb_vbflags2 = ivideo->vbflags2;
1850 ivideo->sisfb_infoblock.sisfb_can_post = ivideo->sisfb_can_post ? 1 : 0;
1851 ivideo->sisfb_infoblock.sisfb_card_posted = ivideo->sisfb_card_posted ? 1 : 0;
1852 ivideo->sisfb_infoblock.sisfb_was_boot_device = ivideo->sisfb_was_boot_device ? 1 : 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001853
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001854 if(copy_to_user((void __user *)arg, &ivideo->sisfb_infoblock,
1855 sizeof(ivideo->sisfb_infoblock)))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001856 return -EFAULT;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001857
Linus Torvalds1da177e2005-04-16 15:20:36 -07001858 break;
1859
1860 case SISFB_GET_VBRSTATUS_OLD:
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001861 if(ivideo->warncount++ < 10)
1862 printk(KERN_INFO
1863 "sisfb: Deprecated ioctl call received - update your application!\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001864 case SISFB_GET_VBRSTATUS:
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001865 if(sisfb_CheckVBRetrace(ivideo))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001866 return put_user((u32)1, argp);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001867 else
Linus Torvalds1da177e2005-04-16 15:20:36 -07001868 return put_user((u32)0, argp);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001869
1870 case SISFB_GET_AUTOMAXIMIZE_OLD:
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001871 if(ivideo->warncount++ < 10)
1872 printk(KERN_INFO
1873 "sisfb: Deprecated ioctl call received - update your application!\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001874 case SISFB_GET_AUTOMAXIMIZE:
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001875 if(ivideo->sisfb_max)
1876 return put_user((u32)1, argp);
1877 else
1878 return put_user((u32)0, argp);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001879
1880 case SISFB_SET_AUTOMAXIMIZE_OLD:
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001881 if(ivideo->warncount++ < 10)
1882 printk(KERN_INFO
1883 "sisfb: Deprecated ioctl call received - update your application!\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001884 case SISFB_SET_AUTOMAXIMIZE:
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001885 if(get_user(gpu32, argp))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001886 return -EFAULT;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001887
Linus Torvalds1da177e2005-04-16 15:20:36 -07001888 ivideo->sisfb_max = (gpu32) ? 1 : 0;
1889 break;
1890
1891 case SISFB_SET_TVPOSOFFSET:
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001892 if(get_user(gpu32, argp))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001893 return -EFAULT;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001894
Linus Torvalds1da177e2005-04-16 15:20:36 -07001895 sisfb_set_TVxposoffset(ivideo, ((int)(gpu32 >> 16)) - 32);
1896 sisfb_set_TVyposoffset(ivideo, ((int)(gpu32 & 0xffff)) - 32);
1897 break;
1898
1899 case SISFB_GET_TVPOSOFFSET:
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001900 return put_user((u32)(((ivideo->tvxpos+32)<<16)|((ivideo->tvypos+32)&0xffff)),
1901 argp);
1902
1903 case SISFB_COMMAND:
1904 if(copy_from_user(&ivideo->sisfb_command, (void __user *)arg,
1905 sizeof(struct sisfb_cmd)))
1906 return -EFAULT;
1907
1908 sisfb_handle_command(ivideo, &ivideo->sisfb_command);
1909
1910 if(copy_to_user((void __user *)arg, &ivideo->sisfb_command,
1911 sizeof(struct sisfb_cmd)))
1912 return -EFAULT;
1913
1914 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001915
1916 case SISFB_SET_LOCK:
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001917 if(get_user(gpu32, argp))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001918 return -EFAULT;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001919
Linus Torvalds1da177e2005-04-16 15:20:36 -07001920 ivideo->sisfblocked = (gpu32) ? 1 : 0;
1921 break;
1922
1923 default:
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001924#ifdef SIS_NEW_CONFIG_COMPAT
Linus Torvalds1da177e2005-04-16 15:20:36 -07001925 return -ENOIOCTLCMD;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001926#else
1927 return -EINVAL;
1928#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -07001929 }
1930 return 0;
1931}
1932
Linus Torvalds1da177e2005-04-16 15:20:36 -07001933static int
1934sisfb_get_fix(struct fb_fix_screeninfo *fix, int con, struct fb_info *info)
1935{
1936 struct sis_video_info *ivideo = (struct sis_video_info *)info->par;
1937
1938 memset(fix, 0, sizeof(struct fb_fix_screeninfo));
1939
1940 strcpy(fix->id, ivideo->myid);
1941
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001942 fix->smem_start = ivideo->video_base + ivideo->video_offset;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001943 fix->smem_len = ivideo->sisfb_mem;
1944 fix->type = FB_TYPE_PACKED_PIXELS;
1945 fix->type_aux = 0;
1946 fix->visual = (ivideo->video_bpp == 8) ? FB_VISUAL_PSEUDOCOLOR : FB_VISUAL_TRUECOLOR;
1947 fix->xpanstep = 1;
1948 fix->ypanstep = (ivideo->sisfb_ypan) ? 1 : 0;
1949 fix->ywrapstep = 0;
1950 fix->line_length = ivideo->video_linelength;
1951 fix->mmio_start = ivideo->mmio_base;
1952 fix->mmio_len = ivideo->mmio_size;
1953 if(ivideo->sisvga_engine == SIS_300_VGA) {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001954 fix->accel = FB_ACCEL_SIS_GLAMOUR;
1955 } else if((ivideo->chip == SIS_330) ||
1956 (ivideo->chip == SIS_760) ||
1957 (ivideo->chip == SIS_761)) {
1958 fix->accel = FB_ACCEL_SIS_XABRE;
1959 } else if(ivideo->chip == XGI_20) {
1960 fix->accel = FB_ACCEL_XGI_VOLARI_Z;
1961 } else if(ivideo->chip >= XGI_40) {
1962 fix->accel = FB_ACCEL_XGI_VOLARI_V;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001963 } else {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001964 fix->accel = FB_ACCEL_SIS_GLAMOUR_2;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001965 }
1966
1967 return 0;
1968}
1969
1970/* ---------------- fb_ops structures ----------------- */
1971
1972#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
1973static struct fb_ops sisfb_ops = {
1974 .owner = THIS_MODULE,
1975 .fb_get_fix = sisfb_get_fix,
1976 .fb_get_var = sisfb_get_var,
1977 .fb_set_var = sisfb_set_var,
1978 .fb_get_cmap = sisfb_get_cmap,
1979 .fb_set_cmap = sisfb_set_cmap,
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001980 .fb_pan_display = sisfb_pan_display,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001981 .fb_ioctl = sisfb_ioctl
1982};
1983#endif
1984
1985#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0)
1986static struct fb_ops sisfb_ops = {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001987 .owner = THIS_MODULE,
1988 .fb_open = sisfb_open,
1989 .fb_release = sisfb_release,
1990 .fb_check_var = sisfb_check_var,
1991 .fb_set_par = sisfb_set_par,
1992 .fb_setcolreg = sisfb_setcolreg,
1993 .fb_pan_display = sisfb_pan_display,
1994 .fb_blank = sisfb_blank,
1995 .fb_fillrect = fbcon_sis_fillrect,
1996 .fb_copyarea = fbcon_sis_copyarea,
1997 .fb_imageblit = cfb_imageblit,
Antonino A. Daplasc465e052005-11-07 01:00:35 -08001998#ifdef CONFIG_FB_SOFT_CURSOR
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001999 .fb_cursor = soft_cursor,
Antonino A. Daplasc465e052005-11-07 01:00:35 -08002000#endif
Thomas Winischhofer544393f2005-09-09 13:04:45 -07002001 .fb_sync = fbcon_sis_sync,
2002#ifdef SIS_NEW_CONFIG_COMPAT
Christoph Hellwig67a66802006-01-14 13:21:25 -08002003 .fb_compat_ioctl= sisfb_ioctl,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002004#endif
Thomas Winischhofer544393f2005-09-09 13:04:45 -07002005 .fb_ioctl = sisfb_ioctl
Linus Torvalds1da177e2005-04-16 15:20:36 -07002006};
2007#endif
2008
2009/* ---------------- Chip generation dependent routines ---------------- */
2010
Thomas Winischhofer544393f2005-09-09 13:04:45 -07002011static struct pci_dev * __devinit
2012sisfb_get_northbridge(int basechipid)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002013{
2014 struct pci_dev *pdev = NULL;
2015 int nbridgenum, nbridgeidx, i;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07002016 static const unsigned short nbridgeids[] = {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002017 PCI_DEVICE_ID_SI_540, /* for SiS 540 VGA */
2018 PCI_DEVICE_ID_SI_630, /* for SiS 630/730 VGA */
2019 PCI_DEVICE_ID_SI_730,
2020 PCI_DEVICE_ID_SI_550, /* for SiS 550 VGA */
2021 PCI_DEVICE_ID_SI_650, /* for SiS 650/651/740 VGA */
2022 PCI_DEVICE_ID_SI_651,
2023 PCI_DEVICE_ID_SI_740,
Thomas Winischhofer544393f2005-09-09 13:04:45 -07002024 PCI_DEVICE_ID_SI_661, /* for SiS 661/741/660/760/761 VGA */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002025 PCI_DEVICE_ID_SI_741,
2026 PCI_DEVICE_ID_SI_660,
Thomas Winischhofer544393f2005-09-09 13:04:45 -07002027 PCI_DEVICE_ID_SI_760,
2028 PCI_DEVICE_ID_SI_761
Linus Torvalds1da177e2005-04-16 15:20:36 -07002029 };
2030
Thomas Winischhofer544393f2005-09-09 13:04:45 -07002031 switch(basechipid) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002032#ifdef CONFIG_FB_SIS_300
2033 case SIS_540: nbridgeidx = 0; nbridgenum = 1; break;
2034 case SIS_630: nbridgeidx = 1; nbridgenum = 2; break;
2035#endif
2036#ifdef CONFIG_FB_SIS_315
2037 case SIS_550: nbridgeidx = 3; nbridgenum = 1; break;
2038 case SIS_650: nbridgeidx = 4; nbridgenum = 3; break;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07002039 case SIS_660: nbridgeidx = 7; nbridgenum = 5; break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002040#endif
2041 default: return NULL;
2042 }
2043 for(i = 0; i < nbridgenum; i++) {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07002044 if((pdev = SIS_PCI_GET_DEVICE(PCI_VENDOR_ID_SI,
2045 nbridgeids[nbridgeidx+i], NULL)))
2046 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002047 }
2048 return pdev;
2049}
2050
Thomas Winischhofer544393f2005-09-09 13:04:45 -07002051static int __devinit
2052sisfb_get_dram_size(struct sis_video_info *ivideo)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002053{
2054#if defined(CONFIG_FB_SIS_300) || defined(CONFIG_FB_SIS_315)
2055 u8 reg;
2056#endif
2057
2058 ivideo->video_size = 0;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07002059 ivideo->UMAsize = ivideo->LFBsize = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002060
2061 switch(ivideo->chip) {
2062#ifdef CONFIG_FB_SIS_300
2063 case SIS_300:
Thomas Winischhofer544393f2005-09-09 13:04:45 -07002064 inSISIDXREG(SISSR, 0x14, reg);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002065 ivideo->video_size = ((reg & 0x3F) + 1) << 20;
2066 break;
2067 case SIS_540:
2068 case SIS_630:
2069 case SIS_730:
Thomas Winischhofer544393f2005-09-09 13:04:45 -07002070 if(!ivideo->nbridge)
2071 return -1;
2072 pci_read_config_byte(ivideo->nbridge, 0x63, &reg);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002073 ivideo->video_size = 1 << (((reg & 0x70) >> 4) + 21);
2074 break;
2075#endif
2076#ifdef CONFIG_FB_SIS_315
2077 case SIS_315H:
2078 case SIS_315PRO:
2079 case SIS_315:
Thomas Winischhofer544393f2005-09-09 13:04:45 -07002080 inSISIDXREG(SISSR, 0x14, reg);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002081 ivideo->video_size = (1 << ((reg & 0xf0) >> 4)) << 20;
2082 switch((reg >> 2) & 0x03) {
2083 case 0x01:
2084 case 0x03:
Thomas Winischhofer544393f2005-09-09 13:04:45 -07002085 ivideo->video_size <<= 1;
2086 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002087 case 0x02:
Thomas Winischhofer544393f2005-09-09 13:04:45 -07002088 ivideo->video_size += (ivideo->video_size/2);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002089 }
Thomas Winischhofer544393f2005-09-09 13:04:45 -07002090 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002091 case SIS_330:
Thomas Winischhofer544393f2005-09-09 13:04:45 -07002092 inSISIDXREG(SISSR, 0x14, reg);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002093 ivideo->video_size = (1 << ((reg & 0xf0) >> 4)) << 20;
2094 if(reg & 0x0c) ivideo->video_size <<= 1;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07002095 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002096 case SIS_550:
2097 case SIS_650:
2098 case SIS_740:
Thomas Winischhofer544393f2005-09-09 13:04:45 -07002099 inSISIDXREG(SISSR, 0x14, reg);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002100 ivideo->video_size = (((reg & 0x3f) + 1) << 2) << 20;
2101 break;
2102 case SIS_661:
2103 case SIS_741:
Thomas Winischhofer544393f2005-09-09 13:04:45 -07002104 inSISIDXREG(SISCR, 0x79, reg);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002105 ivideo->video_size = (1 << ((reg & 0xf0) >> 4)) << 20;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07002106 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002107 case SIS_660:
2108 case SIS_760:
Thomas Winischhofer544393f2005-09-09 13:04:45 -07002109 case SIS_761:
Linus Torvalds1da177e2005-04-16 15:20:36 -07002110 inSISIDXREG(SISCR, 0x79, reg);
2111 reg = (reg & 0xf0) >> 4;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07002112 if(reg) {
2113 ivideo->video_size = (1 << reg) << 20;
2114 ivideo->UMAsize = ivideo->video_size;
2115 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002116 inSISIDXREG(SISCR, 0x78, reg);
2117 reg &= 0x30;
2118 if(reg) {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07002119 if(reg == 0x10) {
2120 ivideo->LFBsize = (32 << 20);
2121 } else {
2122 ivideo->LFBsize = (64 << 20);
2123 }
2124 ivideo->video_size += ivideo->LFBsize;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002125 }
Thomas Winischhofer544393f2005-09-09 13:04:45 -07002126 break;
2127 case SIS_340:
2128 case XGI_20:
2129 case XGI_40:
2130 inSISIDXREG(SISSR, 0x14, reg);
2131 ivideo->video_size = (1 << ((reg & 0xf0) >> 4)) << 20;
2132 if(ivideo->chip != XGI_20) {
2133 reg = (reg & 0x0c) >> 2;
2134 if(ivideo->revision_id == 2) {
2135 if(reg & 0x01) reg = 0x02;
2136 else reg = 0x00;
2137 }
2138 if(reg == 0x02) ivideo->video_size <<= 1;
2139 else if(reg == 0x03) ivideo->video_size <<= 2;
2140 }
2141 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002142#endif
2143 default:
2144 return -1;
2145 }
2146 return 0;
2147}
2148
2149/* -------------- video bridge device detection --------------- */
2150
Thomas Winischhofer544393f2005-09-09 13:04:45 -07002151static void __devinit
2152sisfb_detect_VB_connect(struct sis_video_info *ivideo)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002153{
2154 u8 cr32, temp;
2155
Thomas Winischhofer544393f2005-09-09 13:04:45 -07002156 /* No CRT2 on XGI Z7 */
2157 if(ivideo->chip == XGI_20) {
2158 ivideo->sisfb_crt1off = 0;
2159 return;
2160 }
2161
Linus Torvalds1da177e2005-04-16 15:20:36 -07002162#ifdef CONFIG_FB_SIS_300
2163 if(ivideo->sisvga_engine == SIS_300_VGA) {
2164 inSISIDXREG(SISSR, 0x17, temp);
2165 if((temp & 0x0F) && (ivideo->chip != SIS_300)) {
2166 /* PAL/NTSC is stored on SR16 on such machines */
2167 if(!(ivideo->vbflags & (TV_PAL | TV_NTSC | TV_PALM | TV_PALN))) {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07002168 inSISIDXREG(SISSR, 0x16, temp);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002169 if(temp & 0x20)
2170 ivideo->vbflags |= TV_PAL;
2171 else
2172 ivideo->vbflags |= TV_NTSC;
2173 }
2174 }
2175 }
2176#endif
2177
2178 inSISIDXREG(SISCR, 0x32, cr32);
2179
2180 if(cr32 & SIS_CRT1) {
2181 ivideo->sisfb_crt1off = 0;
2182 } else {
2183 ivideo->sisfb_crt1off = (cr32 & 0xDF) ? 1 : 0;
2184 }
2185
2186 ivideo->vbflags &= ~(CRT2_TV | CRT2_LCD | CRT2_VGA);
2187
2188 if(cr32 & SIS_VB_TV) ivideo->vbflags |= CRT2_TV;
2189 if(cr32 & SIS_VB_LCD) ivideo->vbflags |= CRT2_LCD;
2190 if(cr32 & SIS_VB_CRT2) ivideo->vbflags |= CRT2_VGA;
2191
2192 /* Check given parms for hardware compatibility.
2193 * (Cannot do this in the search_xx routines since we don't
2194 * know what hardware we are running on then)
2195 */
2196
2197 if(ivideo->chip != SIS_550) {
2198 ivideo->sisfb_dstn = ivideo->sisfb_fstn = 0;
2199 }
2200
2201 if(ivideo->sisfb_tvplug != -1) {
2202 if( (ivideo->sisvga_engine != SIS_315_VGA) ||
Thomas Winischhofer544393f2005-09-09 13:04:45 -07002203 (!(ivideo->vbflags2 & VB2_SISYPBPRBRIDGE)) ) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002204 if(ivideo->sisfb_tvplug & TV_YPBPR) {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07002205 ivideo->sisfb_tvplug = -1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002206 printk(KERN_ERR "sisfb: YPbPr not supported\n");
2207 }
2208 }
2209 }
2210 if(ivideo->sisfb_tvplug != -1) {
2211 if( (ivideo->sisvga_engine != SIS_315_VGA) ||
Thomas Winischhofer544393f2005-09-09 13:04:45 -07002212 (!(ivideo->vbflags2 & VB2_SISHIVISIONBRIDGE)) ) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002213 if(ivideo->sisfb_tvplug & TV_HIVISION) {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07002214 ivideo->sisfb_tvplug = -1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002215 printk(KERN_ERR "sisfb: HiVision not supported\n");
2216 }
2217 }
2218 }
2219 if(ivideo->sisfb_tvstd != -1) {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07002220 if( (!(ivideo->vbflags2 & VB2_SISBRIDGE)) &&
2221 (!((ivideo->sisvga_engine == SIS_315_VGA) &&
2222 (ivideo->vbflags2 & VB2_CHRONTEL))) ) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002223 if(ivideo->sisfb_tvstd & (TV_PALN | TV_PALN | TV_NTSCJ)) {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07002224 ivideo->sisfb_tvstd = -1;
2225 printk(KERN_ERR "sisfb: PALM/PALN/NTSCJ not supported\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002226 }
2227 }
2228 }
2229
2230 /* Detect/set TV plug & type */
2231 if(ivideo->sisfb_tvplug != -1) {
2232 ivideo->vbflags |= ivideo->sisfb_tvplug;
2233 } else {
2234 if(cr32 & SIS_VB_YPBPR) ivideo->vbflags |= (TV_YPBPR|TV_YPBPR525I); /* default: 480i */
2235 else if(cr32 & SIS_VB_HIVISION) ivideo->vbflags |= TV_HIVISION;
2236 else if(cr32 & SIS_VB_SCART) ivideo->vbflags |= TV_SCART;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07002237 else {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002238 if(cr32 & SIS_VB_SVIDEO) ivideo->vbflags |= TV_SVIDEO;
2239 if(cr32 & SIS_VB_COMPOSITE) ivideo->vbflags |= TV_AVIDEO;
2240 }
2241 }
2242
2243 if(!(ivideo->vbflags & (TV_YPBPR | TV_HIVISION))) {
2244 if(ivideo->sisfb_tvstd != -1) {
2245 ivideo->vbflags &= ~(TV_NTSC | TV_PAL | TV_PALM | TV_PALN | TV_NTSCJ);
2246 ivideo->vbflags |= ivideo->sisfb_tvstd;
2247 }
2248 if(ivideo->vbflags & TV_SCART) {
2249 ivideo->vbflags &= ~(TV_NTSC | TV_PALM | TV_PALN | TV_NTSCJ);
2250 ivideo->vbflags |= TV_PAL;
2251 }
2252 if(!(ivideo->vbflags & (TV_PAL | TV_NTSC | TV_PALM | TV_PALN | TV_NTSCJ))) {
2253 if(ivideo->sisvga_engine == SIS_300_VGA) {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07002254 inSISIDXREG(SISSR, 0x38, temp);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002255 if(temp & 0x01) ivideo->vbflags |= TV_PAL;
2256 else ivideo->vbflags |= TV_NTSC;
2257 } else if((ivideo->chip <= SIS_315PRO) || (ivideo->chip >= SIS_330)) {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07002258 inSISIDXREG(SISSR, 0x38, temp);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002259 if(temp & 0x01) ivideo->vbflags |= TV_PAL;
2260 else ivideo->vbflags |= TV_NTSC;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07002261 } else {
2262 inSISIDXREG(SISCR, 0x79, temp);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002263 if(temp & 0x20) ivideo->vbflags |= TV_PAL;
2264 else ivideo->vbflags |= TV_NTSC;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07002265 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002266 }
2267 }
2268
2269 /* Copy forceCRT1 option to CRT1off if option is given */
Thomas Winischhofer544393f2005-09-09 13:04:45 -07002270 if(ivideo->sisfb_forcecrt1 != -1) {
2271 ivideo->sisfb_crt1off = (ivideo->sisfb_forcecrt1) ? 0 : 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002272 }
2273}
2274
2275/* ------------------ Sensing routines ------------------ */
2276
Thomas Winischhofer544393f2005-09-09 13:04:45 -07002277static BOOLEAN __devinit
2278sisfb_test_DDC1(struct sis_video_info *ivideo)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002279{
2280 unsigned short old;
2281 int count = 48;
2282
2283 old = SiS_ReadDDC1Bit(&ivideo->SiS_Pr);
2284 do {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07002285 if(old != SiS_ReadDDC1Bit(&ivideo->SiS_Pr)) break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002286 } while(count--);
2287 return (count == -1) ? FALSE : TRUE;
2288}
2289
Thomas Winischhofer544393f2005-09-09 13:04:45 -07002290static void __devinit
2291sisfb_sense_crt1(struct sis_video_info *ivideo)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002292{
2293 BOOLEAN mustwait = FALSE;
2294 u8 sr1F, cr17;
2295#ifdef CONFIG_FB_SIS_315
2296 u8 cr63=0;
2297#endif
2298 u16 temp = 0xffff;
2299 int i;
2300
2301 inSISIDXREG(SISSR,0x1F,sr1F);
2302 orSISIDXREG(SISSR,0x1F,0x04);
2303 andSISIDXREG(SISSR,0x1F,0x3F);
2304 if(sr1F & 0xc0) mustwait = TRUE;
2305
2306#ifdef CONFIG_FB_SIS_315
2307 if(ivideo->sisvga_engine == SIS_315_VGA) {
2308 inSISIDXREG(SISCR,ivideo->SiS_Pr.SiS_MyCR63,cr63);
2309 cr63 &= 0x40;
2310 andSISIDXREG(SISCR,ivideo->SiS_Pr.SiS_MyCR63,0xBF);
2311 }
2312#endif
2313
2314 inSISIDXREG(SISCR,0x17,cr17);
2315 cr17 &= 0x80;
2316 if(!cr17) {
2317 orSISIDXREG(SISCR,0x17,0x80);
2318 mustwait = TRUE;
2319 outSISIDXREG(SISSR, 0x00, 0x01);
2320 outSISIDXREG(SISSR, 0x00, 0x03);
2321 }
2322
2323 if(mustwait) {
2324 for(i=0; i < 10; i++) sisfbwaitretracecrt1(ivideo);
2325 }
2326
2327#ifdef CONFIG_FB_SIS_315
2328 if(ivideo->chip >= SIS_330) {
2329 andSISIDXREG(SISCR,0x32,~0x20);
2330 if(ivideo->chip >= SIS_340) {
2331 outSISIDXREG(SISCR, 0x57, 0x4a);
2332 } else {
2333 outSISIDXREG(SISCR, 0x57, 0x5f);
2334 }
2335 orSISIDXREG(SISCR, 0x53, 0x02);
2336 while((inSISREG(SISINPSTAT)) & 0x01) break;
2337 while(!((inSISREG(SISINPSTAT)) & 0x01)) break;
2338 if((inSISREG(SISMISCW)) & 0x10) temp = 1;
2339 andSISIDXREG(SISCR, 0x53, 0xfd);
2340 andSISIDXREG(SISCR, 0x57, 0x00);
2341 }
2342#endif
2343
2344 if(temp == 0xffff) {
2345 i = 3;
2346 do {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07002347 temp = SiS_HandleDDC(&ivideo->SiS_Pr, ivideo->vbflags,
2348 ivideo->sisvga_engine, 0, 0, NULL, ivideo->vbflags2);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002349 } while(((temp == 0) || (temp == 0xffff)) && i--);
2350
2351 if((temp == 0) || (temp == 0xffff)) {
2352 if(sisfb_test_DDC1(ivideo)) temp = 1;
2353 }
2354 }
2355
2356 if((temp) && (temp != 0xffff)) {
2357 orSISIDXREG(SISCR,0x32,0x20);
2358 }
2359
2360#ifdef CONFIG_FB_SIS_315
2361 if(ivideo->sisvga_engine == SIS_315_VGA) {
2362 setSISIDXREG(SISCR,ivideo->SiS_Pr.SiS_MyCR63,0xBF,cr63);
2363 }
2364#endif
2365
2366 setSISIDXREG(SISCR,0x17,0x7F,cr17);
2367
2368 outSISIDXREG(SISSR,0x1F,sr1F);
2369}
2370
2371/* Determine and detect attached devices on SiS30x */
Thomas Winischhofer544393f2005-09-09 13:04:45 -07002372static void __devinit
2373SiS_SenseLCD(struct sis_video_info *ivideo)
2374{
2375 unsigned char buffer[256];
2376 unsigned short temp, realcrtno, i;
2377 u8 reg, cr37 = 0, paneltype = 0;
2378 u16 xres, yres;
2379
2380 ivideo->SiS_Pr.PanelSelfDetected = FALSE;
2381
2382 /* LCD detection only for TMDS bridges */
2383 if(!(ivideo->vbflags2 & VB2_SISTMDSBRIDGE))
2384 return;
2385 if(ivideo->vbflags2 & VB2_30xBDH)
2386 return;
2387
2388 /* If LCD already set up by BIOS, skip it */
2389 inSISIDXREG(SISCR, 0x32, reg);
2390 if(reg & 0x08)
2391 return;
2392
2393 realcrtno = 1;
2394 if(ivideo->SiS_Pr.DDCPortMixup)
2395 realcrtno = 0;
2396
2397 /* Check DDC capabilities */
2398 temp = SiS_HandleDDC(&ivideo->SiS_Pr, ivideo->vbflags, ivideo->sisvga_engine,
2399 realcrtno, 0, &buffer[0], ivideo->vbflags2);
2400
2401 if((!temp) || (temp == 0xffff) || (!(temp & 0x02)))
2402 return;
2403
2404 /* Read DDC data */
2405 i = 3; /* Number of retrys */
2406 do {
2407 temp = SiS_HandleDDC(&ivideo->SiS_Pr, ivideo->vbflags,
2408 ivideo->sisvga_engine, realcrtno, 1,
2409 &buffer[0], ivideo->vbflags2);
2410 } while((temp) && i--);
2411
2412 if(temp)
2413 return;
2414
2415 /* No digital device */
2416 if(!(buffer[0x14] & 0x80))
2417 return;
2418
2419 /* First detailed timing preferred timing? */
2420 if(!(buffer[0x18] & 0x02))
2421 return;
2422
2423 xres = buffer[0x38] | ((buffer[0x3a] & 0xf0) << 4);
2424 yres = buffer[0x3b] | ((buffer[0x3d] & 0xf0) << 4);
2425
2426 switch(xres) {
2427 case 1024:
2428 if(yres == 768)
2429 paneltype = 0x02;
2430 break;
2431 case 1280:
2432 if(yres == 1024)
2433 paneltype = 0x03;
2434 break;
2435 case 1600:
2436 if((yres == 1200) && (ivideo->vbflags2 & VB2_30xC))
2437 paneltype = 0x0b;
2438 break;
2439 }
2440
2441 if(!paneltype)
2442 return;
2443
2444 if(buffer[0x23])
2445 cr37 |= 0x10;
2446
2447 if((buffer[0x47] & 0x18) == 0x18)
2448 cr37 |= ((((buffer[0x47] & 0x06) ^ 0x06) << 5) | 0x20);
2449 else
2450 cr37 |= 0xc0;
2451
2452 outSISIDXREG(SISCR, 0x36, paneltype);
2453 cr37 &= 0xf1;
2454 setSISIDXREG(SISCR, 0x37, 0x0c, cr37);
2455 orSISIDXREG(SISCR, 0x32, 0x08);
2456
2457 ivideo->SiS_Pr.PanelSelfDetected = TRUE;
2458}
2459
2460static int __devinit
2461SISDoSense(struct sis_video_info *ivideo, u16 type, u16 test)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002462{
2463 int temp, mytest, result, i, j;
2464
2465 for(j = 0; j < 10; j++) {
2466 result = 0;
2467 for(i = 0; i < 3; i++) {
2468 mytest = test;
2469 outSISIDXREG(SISPART4,0x11,(type & 0x00ff));
2470 temp = (type >> 8) | (mytest & 0x00ff);
2471 setSISIDXREG(SISPART4,0x10,0xe0,temp);
2472 SiS_DDC2Delay(&ivideo->SiS_Pr, 0x1500);
2473 mytest >>= 8;
2474 mytest &= 0x7f;
2475 inSISIDXREG(SISPART4,0x03,temp);
2476 temp ^= 0x0e;
2477 temp &= mytest;
2478 if(temp == mytest) result++;
2479#if 1
2480 outSISIDXREG(SISPART4,0x11,0x00);
2481 andSISIDXREG(SISPART4,0x10,0xe0);
2482 SiS_DDC2Delay(&ivideo->SiS_Pr, 0x1000);
2483#endif
2484 }
2485 if((result == 0) || (result >= 2)) break;
2486 }
Thomas Winischhofer544393f2005-09-09 13:04:45 -07002487 return result;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002488}
2489
Thomas Winischhofer544393f2005-09-09 13:04:45 -07002490static void __devinit
2491SiS_Sense30x(struct sis_video_info *ivideo)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002492{
2493 u8 backupP4_0d,backupP2_00,backupP2_4d,backupSR_1e,biosflag=0;
2494 u16 svhs=0, svhs_c=0;
2495 u16 cvbs=0, cvbs_c=0;
2496 u16 vga2=0, vga2_c=0;
2497 int myflag, result;
2498 char stdstr[] = "sisfb: Detected";
2499 char tvstr[] = "TV connected to";
2500
Thomas Winischhofer544393f2005-09-09 13:04:45 -07002501 if(ivideo->vbflags2 & VB2_301) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002502 svhs = 0x00b9; cvbs = 0x00b3; vga2 = 0x00d1;
2503 inSISIDXREG(SISPART4,0x01,myflag);
2504 if(myflag & 0x04) {
2505 svhs = 0x00dd; cvbs = 0x00ee; vga2 = 0x00fd;
2506 }
Thomas Winischhofer544393f2005-09-09 13:04:45 -07002507 } else if(ivideo->vbflags2 & (VB2_301B | VB2_302B)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002508 svhs = 0x016b; cvbs = 0x0174; vga2 = 0x0190;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07002509 } else if(ivideo->vbflags2 & (VB2_301LV | VB2_302LV)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002510 svhs = 0x0200; cvbs = 0x0100;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07002511 } else if(ivideo->vbflags2 & (VB2_301C | VB2_302ELV | VB2_307T | VB2_307LV)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002512 svhs = 0x016b; cvbs = 0x0110; vga2 = 0x0190;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07002513 } else
2514 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002515
2516 vga2_c = 0x0e08; svhs_c = 0x0404; cvbs_c = 0x0804;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07002517 if(ivideo->vbflags & (VB2_301LV|VB2_302LV|VB2_302ELV|VB2_307LV)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002518 svhs_c = 0x0408; cvbs_c = 0x0808;
2519 }
Thomas Winischhofer544393f2005-09-09 13:04:45 -07002520
Linus Torvalds1da177e2005-04-16 15:20:36 -07002521 biosflag = 2;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07002522 if(ivideo->haveXGIROM) {
2523 biosflag = ivideo->bios_abase[0x58] & 0x03;
2524 } else if(ivideo->newrom) {
2525 if(ivideo->bios_abase[0x5d] & 0x04) biosflag |= 0x01;
2526 } else if(ivideo->sisvga_engine == SIS_300_VGA) {
2527 if(ivideo->bios_abase) {
2528 biosflag = ivideo->bios_abase[0xfe] & 0x03;
2529 }
2530 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002531
2532 if(ivideo->chip == SIS_300) {
2533 inSISIDXREG(SISSR,0x3b,myflag);
2534 if(!(myflag & 0x01)) vga2 = vga2_c = 0;
2535 }
2536
Thomas Winischhofer544393f2005-09-09 13:04:45 -07002537 if(!(ivideo->vbflags2 & VB2_SISVGA2BRIDGE)) {
2538 vga2 = vga2_c = 0;
2539 }
2540
Linus Torvalds1da177e2005-04-16 15:20:36 -07002541 inSISIDXREG(SISSR,0x1e,backupSR_1e);
2542 orSISIDXREG(SISSR,0x1e,0x20);
2543
2544 inSISIDXREG(SISPART4,0x0d,backupP4_0d);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07002545 if(ivideo->vbflags2 & VB2_30xC) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002546 setSISIDXREG(SISPART4,0x0d,~0x07,0x01);
2547 } else {
2548 orSISIDXREG(SISPART4,0x0d,0x04);
2549 }
2550 SiS_DDC2Delay(&ivideo->SiS_Pr, 0x2000);
2551
2552 inSISIDXREG(SISPART2,0x00,backupP2_00);
2553 outSISIDXREG(SISPART2,0x00,((backupP2_00 | 0x1c) & 0xfc));
2554
2555 inSISIDXREG(SISPART2,0x4d,backupP2_4d);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07002556 if(ivideo->vbflags2 & VB2_SISYPBPRBRIDGE) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002557 outSISIDXREG(SISPART2,0x4d,(backupP2_4d & ~0x10));
2558 }
2559
Thomas Winischhofer544393f2005-09-09 13:04:45 -07002560 if(!(ivideo->vbflags2 & VB2_30xCLV)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002561 SISDoSense(ivideo, 0, 0);
2562 }
2563
2564 andSISIDXREG(SISCR, 0x32, ~0x14);
2565
2566 if(vga2_c || vga2) {
2567 if(SISDoSense(ivideo, vga2, vga2_c)) {
2568 if(biosflag & 0x01) {
2569 printk(KERN_INFO "%s %s SCART output\n", stdstr, tvstr);
2570 orSISIDXREG(SISCR, 0x32, 0x04);
2571 } else {
2572 printk(KERN_INFO "%s secondary VGA connection\n", stdstr);
2573 orSISIDXREG(SISCR, 0x32, 0x10);
2574 }
2575 }
2576 }
2577
2578 andSISIDXREG(SISCR, 0x32, 0x3f);
2579
Thomas Winischhofer544393f2005-09-09 13:04:45 -07002580 if(ivideo->vbflags2 & VB2_30xCLV) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002581 orSISIDXREG(SISPART4,0x0d,0x04);
2582 }
2583
Thomas Winischhofer544393f2005-09-09 13:04:45 -07002584 if((ivideo->sisvga_engine == SIS_315_VGA) && (ivideo->vbflags2 & VB2_SISYPBPRBRIDGE)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002585 outSISIDXREG(SISPART2,0x4d,(backupP2_4d | 0x10));
2586 SiS_DDC2Delay(&ivideo->SiS_Pr, 0x2000);
2587 if((result = SISDoSense(ivideo, svhs, 0x0604))) {
2588 if((result = SISDoSense(ivideo, cvbs, 0x0804))) {
2589 printk(KERN_INFO "%s %s YPbPr component output\n", stdstr, tvstr);
2590 orSISIDXREG(SISCR,0x32,0x80);
2591 }
2592 }
2593 outSISIDXREG(SISPART2,0x4d,backupP2_4d);
2594 }
2595
2596 andSISIDXREG(SISCR, 0x32, ~0x03);
2597
2598 if(!(ivideo->vbflags & TV_YPBPR)) {
2599 if((result = SISDoSense(ivideo, svhs, svhs_c))) {
2600 printk(KERN_INFO "%s %s SVIDEO output\n", stdstr, tvstr);
2601 orSISIDXREG(SISCR, 0x32, 0x02);
2602 }
2603 if((biosflag & 0x02) || (!result)) {
2604 if(SISDoSense(ivideo, cvbs, cvbs_c)) {
2605 printk(KERN_INFO "%s %s COMPOSITE output\n", stdstr, tvstr);
2606 orSISIDXREG(SISCR, 0x32, 0x01);
2607 }
2608 }
2609 }
2610
2611 SISDoSense(ivideo, 0, 0);
2612
2613 outSISIDXREG(SISPART2,0x00,backupP2_00);
2614 outSISIDXREG(SISPART4,0x0d,backupP4_0d);
2615 outSISIDXREG(SISSR,0x1e,backupSR_1e);
2616
Thomas Winischhofer544393f2005-09-09 13:04:45 -07002617 if(ivideo->vbflags2 & VB2_30xCLV) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002618 inSISIDXREG(SISPART2,0x00,biosflag);
2619 if(biosflag & 0x20) {
2620 for(myflag = 2; myflag > 0; myflag--) {
2621 biosflag ^= 0x20;
2622 outSISIDXREG(SISPART2,0x00,biosflag);
2623 }
2624 }
2625 }
2626
2627 outSISIDXREG(SISPART2,0x00,backupP2_00);
2628}
2629
2630/* Determine and detect attached TV's on Chrontel */
Thomas Winischhofer544393f2005-09-09 13:04:45 -07002631static void __devinit
2632SiS_SenseCh(struct sis_video_info *ivideo)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002633{
2634#if defined(CONFIG_FB_SIS_300) || defined(CONFIG_FB_SIS_315)
2635 u8 temp1, temp2;
2636 char stdstr[] = "sisfb: Chrontel: Detected TV connected to";
2637#endif
2638#ifdef CONFIG_FB_SIS_300
2639 unsigned char test[3];
2640 int i;
2641#endif
2642
2643 if(ivideo->chip < SIS_315H) {
2644
2645#ifdef CONFIG_FB_SIS_300
2646 ivideo->SiS_Pr.SiS_IF_DEF_CH70xx = 1; /* Chrontel 700x */
2647 SiS_SetChrontelGPIO(&ivideo->SiS_Pr, 0x9c); /* Set general purpose IO for Chrontel communication */
2648 SiS_DDC2Delay(&ivideo->SiS_Pr, 1000);
2649 temp1 = SiS_GetCH700x(&ivideo->SiS_Pr, 0x25);
2650 /* See Chrontel TB31 for explanation */
2651 temp2 = SiS_GetCH700x(&ivideo->SiS_Pr, 0x0e);
2652 if(((temp2 & 0x07) == 0x01) || (temp2 & 0x04)) {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07002653 SiS_SetCH700x(&ivideo->SiS_Pr, 0x0e, 0x0b);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002654 SiS_DDC2Delay(&ivideo->SiS_Pr, 300);
2655 }
2656 temp2 = SiS_GetCH700x(&ivideo->SiS_Pr, 0x25);
2657 if(temp2 != temp1) temp1 = temp2;
2658
2659 if((temp1 >= 0x22) && (temp1 <= 0x50)) {
2660 /* Read power status */
2661 temp1 = SiS_GetCH700x(&ivideo->SiS_Pr, 0x0e);
2662 if((temp1 & 0x03) != 0x03) {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07002663 /* Power all outputs */
2664 SiS_SetCH700x(&ivideo->SiS_Pr, 0x0e,0x0b);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002665 SiS_DDC2Delay(&ivideo->SiS_Pr, 300);
2666 }
2667 /* Sense connected TV devices */
2668 for(i = 0; i < 3; i++) {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07002669 SiS_SetCH700x(&ivideo->SiS_Pr, 0x10, 0x01);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002670 SiS_DDC2Delay(&ivideo->SiS_Pr, 0x96);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07002671 SiS_SetCH700x(&ivideo->SiS_Pr, 0x10, 0x00);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002672 SiS_DDC2Delay(&ivideo->SiS_Pr, 0x96);
2673 temp1 = SiS_GetCH700x(&ivideo->SiS_Pr, 0x10);
2674 if(!(temp1 & 0x08)) test[i] = 0x02;
2675 else if(!(temp1 & 0x02)) test[i] = 0x01;
2676 else test[i] = 0;
2677 SiS_DDC2Delay(&ivideo->SiS_Pr, 0x96);
2678 }
2679
2680 if(test[0] == test[1]) temp1 = test[0];
2681 else if(test[0] == test[2]) temp1 = test[0];
2682 else if(test[1] == test[2]) temp1 = test[1];
2683 else {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07002684 printk(KERN_INFO
Linus Torvalds1da177e2005-04-16 15:20:36 -07002685 "sisfb: TV detection unreliable - test results varied\n");
2686 temp1 = test[2];
2687 }
2688 if(temp1 == 0x02) {
2689 printk(KERN_INFO "%s SVIDEO output\n", stdstr);
2690 ivideo->vbflags |= TV_SVIDEO;
2691 orSISIDXREG(SISCR, 0x32, 0x02);
2692 andSISIDXREG(SISCR, 0x32, ~0x05);
2693 } else if (temp1 == 0x01) {
2694 printk(KERN_INFO "%s CVBS output\n", stdstr);
2695 ivideo->vbflags |= TV_AVIDEO;
2696 orSISIDXREG(SISCR, 0x32, 0x01);
2697 andSISIDXREG(SISCR, 0x32, ~0x06);
2698 } else {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07002699 SiS_SetCH70xxANDOR(&ivideo->SiS_Pr, 0x0e, 0x01, 0xF8);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002700 andSISIDXREG(SISCR, 0x32, ~0x07);
2701 }
2702 } else if(temp1 == 0) {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07002703 SiS_SetCH70xxANDOR(&ivideo->SiS_Pr, 0x0e, 0x01, 0xF8);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002704 andSISIDXREG(SISCR, 0x32, ~0x07);
2705 }
2706 /* Set general purpose IO for Chrontel communication */
2707 SiS_SetChrontelGPIO(&ivideo->SiS_Pr, 0x00);
2708#endif
2709
2710 } else {
2711
2712#ifdef CONFIG_FB_SIS_315
2713 ivideo->SiS_Pr.SiS_IF_DEF_CH70xx = 2; /* Chrontel 7019 */
Thomas Winischhofer544393f2005-09-09 13:04:45 -07002714 temp1 = SiS_GetCH701x(&ivideo->SiS_Pr, 0x49);
2715 SiS_SetCH701x(&ivideo->SiS_Pr, 0x49, 0x20);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002716 SiS_DDC2Delay(&ivideo->SiS_Pr, 0x96);
2717 temp2 = SiS_GetCH701x(&ivideo->SiS_Pr, 0x20);
2718 temp2 |= 0x01;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07002719 SiS_SetCH701x(&ivideo->SiS_Pr, 0x20, temp2);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002720 SiS_DDC2Delay(&ivideo->SiS_Pr, 0x96);
2721 temp2 ^= 0x01;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07002722 SiS_SetCH701x(&ivideo->SiS_Pr, 0x20, temp2);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002723 SiS_DDC2Delay(&ivideo->SiS_Pr, 0x96);
2724 temp2 = SiS_GetCH701x(&ivideo->SiS_Pr, 0x20);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07002725 SiS_SetCH701x(&ivideo->SiS_Pr, 0x49, temp1);
2726 temp1 = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002727 if(temp2 & 0x02) temp1 |= 0x01;
2728 if(temp2 & 0x10) temp1 |= 0x01;
2729 if(temp2 & 0x04) temp1 |= 0x02;
2730 if( (temp1 & 0x01) && (temp1 & 0x02) ) temp1 = 0x04;
2731 switch(temp1) {
2732 case 0x01:
2733 printk(KERN_INFO "%s CVBS output\n", stdstr);
2734 ivideo->vbflags |= TV_AVIDEO;
2735 orSISIDXREG(SISCR, 0x32, 0x01);
2736 andSISIDXREG(SISCR, 0x32, ~0x06);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07002737 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002738 case 0x02:
2739 printk(KERN_INFO "%s SVIDEO output\n", stdstr);
2740 ivideo->vbflags |= TV_SVIDEO;
2741 orSISIDXREG(SISCR, 0x32, 0x02);
2742 andSISIDXREG(SISCR, 0x32, ~0x05);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07002743 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002744 case 0x04:
2745 printk(KERN_INFO "%s SCART output\n", stdstr);
2746 orSISIDXREG(SISCR, 0x32, 0x04);
2747 andSISIDXREG(SISCR, 0x32, ~0x03);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07002748 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002749 default:
2750 andSISIDXREG(SISCR, 0x32, ~0x07);
2751 }
2752#endif
2753 }
2754}
2755
Thomas Winischhofer544393f2005-09-09 13:04:45 -07002756static void __devinit
2757sisfb_get_VB_type(struct sis_video_info *ivideo)
2758{
2759 char stdstr[] = "sisfb: Detected";
2760 char bridgestr[] = "video bridge";
2761 u8 vb_chipid;
2762 u8 reg;
2763
2764 /* No CRT2 on XGI Z7 */
2765 if(ivideo->chip == XGI_20)
2766 return;
2767
2768 inSISIDXREG(SISPART4, 0x00, vb_chipid);
2769 switch(vb_chipid) {
2770 case 0x01:
2771 inSISIDXREG(SISPART4, 0x01, reg);
2772 if(reg < 0xb0) {
2773 ivideo->vbflags |= VB_301; /* Deprecated */
2774 ivideo->vbflags2 |= VB2_301;
2775 printk(KERN_INFO "%s SiS301 %s\n", stdstr, bridgestr);
2776 } else if(reg < 0xc0) {
2777 ivideo->vbflags |= VB_301B; /* Deprecated */
2778 ivideo->vbflags2 |= VB2_301B;
2779 inSISIDXREG(SISPART4,0x23,reg);
2780 if(!(reg & 0x02)) {
2781 ivideo->vbflags |= VB_30xBDH; /* Deprecated */
2782 ivideo->vbflags2 |= VB2_30xBDH;
2783 printk(KERN_INFO "%s SiS301B-DH %s\n", stdstr, bridgestr);
2784 } else {
2785 printk(KERN_INFO "%s SiS301B %s\n", stdstr, bridgestr);
2786 }
2787 } else if(reg < 0xd0) {
2788 ivideo->vbflags |= VB_301C; /* Deprecated */
2789 ivideo->vbflags2 |= VB2_301C;
2790 printk(KERN_INFO "%s SiS301C %s\n", stdstr, bridgestr);
2791 } else if(reg < 0xe0) {
2792 ivideo->vbflags |= VB_301LV; /* Deprecated */
2793 ivideo->vbflags2 |= VB2_301LV;
2794 printk(KERN_INFO "%s SiS301LV %s\n", stdstr, bridgestr);
2795 } else if(reg <= 0xe1) {
2796 inSISIDXREG(SISPART4,0x39,reg);
2797 if(reg == 0xff) {
2798 ivideo->vbflags |= VB_302LV; /* Deprecated */
2799 ivideo->vbflags2 |= VB2_302LV;
2800 printk(KERN_INFO "%s SiS302LV %s\n", stdstr, bridgestr);
2801 } else {
2802 ivideo->vbflags |= VB_301C; /* Deprecated */
2803 ivideo->vbflags2 |= VB2_301C;
2804 printk(KERN_INFO "%s SiS301C(P4) %s\n", stdstr, bridgestr);
2805#if 0
2806 ivideo->vbflags |= VB_302ELV; /* Deprecated */
2807 ivideo->vbflags2 |= VB2_302ELV;
2808 printk(KERN_INFO "%s SiS302ELV %s\n", stdstr, bridgestr);
2809#endif
2810 }
2811 }
2812 break;
2813 case 0x02:
2814 ivideo->vbflags |= VB_302B; /* Deprecated */
2815 ivideo->vbflags2 |= VB2_302B;
2816 printk(KERN_INFO "%s SiS302B %s\n", stdstr, bridgestr);
2817 break;
2818 }
2819
2820 if((!(ivideo->vbflags2 & VB2_VIDEOBRIDGE)) && (ivideo->chip != SIS_300)) {
2821 inSISIDXREG(SISCR, 0x37, reg);
2822 reg &= SIS_EXTERNAL_CHIP_MASK;
2823 reg >>= 1;
2824 if(ivideo->sisvga_engine == SIS_300_VGA) {
2825#ifdef CONFIG_FB_SIS_300
2826 switch(reg) {
2827 case SIS_EXTERNAL_CHIP_LVDS:
2828 ivideo->vbflags |= VB_LVDS; /* Deprecated */
2829 ivideo->vbflags2 |= VB2_LVDS;
2830 break;
2831 case SIS_EXTERNAL_CHIP_TRUMPION:
2832 ivideo->vbflags |= (VB_LVDS | VB_TRUMPION); /* Deprecated */
2833 ivideo->vbflags2 |= (VB2_LVDS | VB2_TRUMPION);
2834 break;
2835 case SIS_EXTERNAL_CHIP_CHRONTEL:
2836 ivideo->vbflags |= VB_CHRONTEL; /* Deprecated */
2837 ivideo->vbflags2 |= VB2_CHRONTEL;
2838 break;
2839 case SIS_EXTERNAL_CHIP_LVDS_CHRONTEL:
2840 ivideo->vbflags |= (VB_LVDS | VB_CHRONTEL); /* Deprecated */
2841 ivideo->vbflags2 |= (VB2_LVDS | VB2_CHRONTEL);
2842 break;
2843 }
2844 if(ivideo->vbflags2 & VB2_CHRONTEL) ivideo->chronteltype = 1;
2845#endif
2846 } else if(ivideo->chip < SIS_661) {
2847#ifdef CONFIG_FB_SIS_315
2848 switch (reg) {
2849 case SIS310_EXTERNAL_CHIP_LVDS:
2850 ivideo->vbflags |= VB_LVDS; /* Deprecated */
2851 ivideo->vbflags2 |= VB2_LVDS;
2852 break;
2853 case SIS310_EXTERNAL_CHIP_LVDS_CHRONTEL:
2854 ivideo->vbflags |= (VB_LVDS | VB_CHRONTEL); /* Deprecated */
2855 ivideo->vbflags2 |= (VB2_LVDS | VB2_CHRONTEL);
2856 break;
2857 }
2858 if(ivideo->vbflags2 & VB2_CHRONTEL) ivideo->chronteltype = 2;
2859#endif
2860 } else if(ivideo->chip >= SIS_661) {
2861#ifdef CONFIG_FB_SIS_315
2862 inSISIDXREG(SISCR, 0x38, reg);
2863 reg >>= 5;
2864 switch(reg) {
2865 case 0x02:
2866 ivideo->vbflags |= VB_LVDS; /* Deprecated */
2867 ivideo->vbflags2 |= VB2_LVDS;
2868 break;
2869 case 0x03:
2870 ivideo->vbflags |= (VB_LVDS | VB_CHRONTEL); /* Deprecated */
2871 ivideo->vbflags2 |= (VB2_LVDS | VB2_CHRONTEL);
2872 break;
2873 case 0x04:
2874 ivideo->vbflags |= (VB_LVDS | VB_CONEXANT); /* Deprecated */
2875 ivideo->vbflags2 |= (VB2_LVDS | VB2_CONEXANT);
2876 break;
2877 }
2878 if(ivideo->vbflags2 & VB2_CHRONTEL) ivideo->chronteltype = 2;
2879#endif
2880 }
2881 if(ivideo->vbflags2 & VB2_LVDS) {
2882 printk(KERN_INFO "%s LVDS transmitter\n", stdstr);
2883 }
2884 if((ivideo->sisvga_engine == SIS_300_VGA) && (ivideo->vbflags2 & VB2_TRUMPION)) {
2885 printk(KERN_INFO "%s Trumpion Zurac LCD scaler\n", stdstr);
2886 }
2887 if(ivideo->vbflags2 & VB2_CHRONTEL) {
2888 printk(KERN_INFO "%s Chrontel TV encoder\n", stdstr);
2889 }
2890 if((ivideo->chip >= SIS_661) && (ivideo->vbflags2 & VB2_CONEXANT)) {
2891 printk(KERN_INFO "%s Conexant external device\n", stdstr);
2892 }
2893 }
2894
2895 if(ivideo->vbflags2 & VB2_SISBRIDGE) {
2896 SiS_SenseLCD(ivideo);
2897 SiS_Sense30x(ivideo);
2898 } else if(ivideo->vbflags2 & VB2_CHRONTEL) {
2899 SiS_SenseCh(ivideo);
2900 }
2901}
2902
2903/* ---------- Engine initialization routines ------------ */
2904
2905static void
2906sisfb_engine_init(struct sis_video_info *ivideo)
2907{
2908
2909 /* Initialize command queue (we use MMIO only) */
2910
2911 /* BEFORE THIS IS CALLED, THE ENGINES *MUST* BE SYNC'ED */
2912
2913 ivideo->caps &= ~(TURBO_QUEUE_CAP |
2914 MMIO_CMD_QUEUE_CAP |
2915 VM_CMD_QUEUE_CAP |
2916 AGP_CMD_QUEUE_CAP);
2917
2918#ifdef CONFIG_FB_SIS_300
2919 if(ivideo->sisvga_engine == SIS_300_VGA) {
2920 u32 tqueue_pos;
2921 u8 tq_state;
2922
2923 tqueue_pos = (ivideo->video_size - ivideo->cmdQueueSize) / (64 * 1024);
2924
2925 inSISIDXREG(SISSR, IND_SIS_TURBOQUEUE_SET, tq_state);
2926 tq_state |= 0xf0;
2927 tq_state &= 0xfc;
2928 tq_state |= (u8)(tqueue_pos >> 8);
2929 outSISIDXREG(SISSR, IND_SIS_TURBOQUEUE_SET, tq_state);
2930
2931 outSISIDXREG(SISSR, IND_SIS_TURBOQUEUE_ADR, (u8)(tqueue_pos & 0xff));
2932
2933 ivideo->caps |= TURBO_QUEUE_CAP;
2934 }
2935#endif
2936
2937#ifdef CONFIG_FB_SIS_315
2938 if(ivideo->sisvga_engine == SIS_315_VGA) {
2939 u32 tempq = 0, templ;
2940 u8 temp;
2941
2942 if(ivideo->chip == XGI_20) {
2943 switch(ivideo->cmdQueueSize) {
2944 case (64 * 1024):
2945 temp = SIS_CMD_QUEUE_SIZE_Z7_64k;
2946 break;
2947 case (128 * 1024):
2948 default:
2949 temp = SIS_CMD_QUEUE_SIZE_Z7_128k;
2950 }
2951 } else {
2952 switch(ivideo->cmdQueueSize) {
2953 case (4 * 1024 * 1024):
2954 temp = SIS_CMD_QUEUE_SIZE_4M;
2955 break;
2956 case (2 * 1024 * 1024):
2957 temp = SIS_CMD_QUEUE_SIZE_2M;
2958 break;
2959 case (1 * 1024 * 1024):
2960 temp = SIS_CMD_QUEUE_SIZE_1M;
2961 break;
2962 default:
2963 case (512 * 1024):
2964 temp = SIS_CMD_QUEUE_SIZE_512k;
2965 }
2966 }
2967
2968 outSISIDXREG(SISSR, IND_SIS_CMDQUEUE_THRESHOLD, COMMAND_QUEUE_THRESHOLD);
2969 outSISIDXREG(SISSR, IND_SIS_CMDQUEUE_SET, SIS_CMD_QUEUE_RESET);
2970
2971 if((ivideo->chip >= XGI_40) && ivideo->modechanged) {
2972 /* Must disable dual pipe on XGI_40. Can't do
2973 * this in MMIO mode, because it requires
2974 * setting/clearing a bit in the MMIO fire trigger
2975 * register.
2976 */
2977 if(!((templ = MMIO_IN32(ivideo->mmio_vbase, 0x8240)) & (1 << 10))) {
2978
2979 MMIO_OUT32(ivideo->mmio_vbase, Q_WRITE_PTR, 0);
2980
2981 outSISIDXREG(SISSR, IND_SIS_CMDQUEUE_SET, (temp | SIS_VRAM_CMDQUEUE_ENABLE));
2982
2983 tempq = MMIO_IN32(ivideo->mmio_vbase, Q_READ_PTR);
2984 MMIO_OUT32(ivideo->mmio_vbase, Q_WRITE_PTR, tempq);
2985
2986 tempq = (u32)(ivideo->video_size - ivideo->cmdQueueSize);
2987 MMIO_OUT32(ivideo->mmio_vbase, Q_BASE_ADDR, tempq);
2988
2989 writel(0x16800000 + 0x8240, ivideo->video_vbase + tempq);
2990 writel(templ | (1 << 10), ivideo->video_vbase + tempq + 4);
2991 writel(0x168F0000, ivideo->video_vbase + tempq + 8);
2992 writel(0x168F0000, ivideo->video_vbase + tempq + 12);
2993
2994 MMIO_OUT32(ivideo->mmio_vbase, Q_WRITE_PTR, (tempq + 16));
2995
2996 sisfb_syncaccel(ivideo);
2997
2998 outSISIDXREG(SISSR, IND_SIS_CMDQUEUE_SET, SIS_CMD_QUEUE_RESET);
2999
3000 }
3001 }
3002
3003 tempq = MMIO_IN32(ivideo->mmio_vbase, MMIO_QUEUE_READPORT);
3004 MMIO_OUT32(ivideo->mmio_vbase, MMIO_QUEUE_WRITEPORT, tempq);
3005
3006 temp |= (SIS_MMIO_CMD_ENABLE | SIS_CMD_AUTO_CORR);
3007 outSISIDXREG(SISSR, IND_SIS_CMDQUEUE_SET, temp);
3008
3009 tempq = (u32)(ivideo->video_size - ivideo->cmdQueueSize);
3010 MMIO_OUT32(ivideo->mmio_vbase, MMIO_QUEUE_PHYBASE, tempq);
3011
3012 ivideo->caps |= MMIO_CMD_QUEUE_CAP;
3013 }
3014#endif
3015
3016 ivideo->engineok = 1;
3017}
3018
3019static void __devinit
3020sisfb_detect_lcd_type(struct sis_video_info *ivideo)
3021{
3022 u8 reg;
3023 int i;
3024
3025 inSISIDXREG(SISCR, 0x36, reg);
3026 reg &= 0x0f;
3027 if(ivideo->sisvga_engine == SIS_300_VGA) {
3028 ivideo->CRT2LCDType = sis300paneltype[reg];
3029 } else if(ivideo->chip >= SIS_661) {
3030 ivideo->CRT2LCDType = sis661paneltype[reg];
3031 } else {
3032 ivideo->CRT2LCDType = sis310paneltype[reg];
3033 if((ivideo->chip == SIS_550) && (sisfb_fstn)) {
3034 if((ivideo->CRT2LCDType != LCD_320x240_2) &&
3035 (ivideo->CRT2LCDType != LCD_320x240_3)) {
3036 ivideo->CRT2LCDType = LCD_320x240;
3037 }
3038 }
3039 }
3040
3041 if(ivideo->CRT2LCDType == LCD_UNKNOWN) {
3042 /* For broken BIOSes: Assume 1024x768, RGB18 */
3043 ivideo->CRT2LCDType = LCD_1024x768;
3044 setSISIDXREG(SISCR,0x36,0xf0,0x02);
3045 setSISIDXREG(SISCR,0x37,0xee,0x01);
3046 printk(KERN_DEBUG "sisfb: Invalid panel ID (%02x), assuming 1024x768, RGB18\n", reg);
3047 }
3048
3049 for(i = 0; i < SIS_LCD_NUMBER; i++) {
3050 if(ivideo->CRT2LCDType == sis_lcd_data[i].lcdtype) {
3051 ivideo->lcdxres = sis_lcd_data[i].xres;
3052 ivideo->lcdyres = sis_lcd_data[i].yres;
3053 ivideo->lcddefmodeidx = sis_lcd_data[i].default_mode_idx;
3054 break;
3055 }
3056 }
3057
3058#ifdef CONFIG_FB_SIS_300
3059 if(ivideo->SiS_Pr.SiS_CustomT == CUT_BARCO1366) {
3060 ivideo->lcdxres = 1360; ivideo->lcdyres = 1024;
3061 ivideo->lcddefmodeidx = DEFAULT_MODE_1360;
3062 } else if(ivideo->SiS_Pr.SiS_CustomT == CUT_PANEL848) {
3063 ivideo->lcdxres = 848; ivideo->lcdyres = 480;
3064 ivideo->lcddefmodeidx = DEFAULT_MODE_848;
3065 } else if(ivideo->SiS_Pr.SiS_CustomT == CUT_PANEL856) {
3066 ivideo->lcdxres = 856; ivideo->lcdyres = 480;
3067 ivideo->lcddefmodeidx = DEFAULT_MODE_856;
3068 }
3069#endif
3070
3071 printk(KERN_DEBUG "sisfb: Detected %dx%d flat panel\n",
3072 ivideo->lcdxres, ivideo->lcdyres);
3073}
3074
3075static void __devinit
3076sisfb_save_pdc_emi(struct sis_video_info *ivideo)
3077{
3078#ifdef CONFIG_FB_SIS_300
3079 /* Save the current PanelDelayCompensation if the LCD is currently used */
3080 if(ivideo->sisvga_engine == SIS_300_VGA) {
3081 if(ivideo->vbflags2 & (VB2_LVDS | VB2_30xBDH)) {
3082 int tmp;
3083 inSISIDXREG(SISCR,0x30,tmp);
3084 if(tmp & 0x20) {
3085 /* Currently on LCD? If yes, read current pdc */
3086 inSISIDXREG(SISPART1,0x13,ivideo->detectedpdc);
3087 ivideo->detectedpdc &= 0x3c;
3088 if(ivideo->SiS_Pr.PDC == -1) {
3089 /* Let option override detection */
3090 ivideo->SiS_Pr.PDC = ivideo->detectedpdc;
3091 }
3092 printk(KERN_INFO "sisfb: Detected LCD PDC 0x%02x\n",
3093 ivideo->detectedpdc);
3094 }
3095 if((ivideo->SiS_Pr.PDC != -1) &&
3096 (ivideo->SiS_Pr.PDC != ivideo->detectedpdc)) {
3097 printk(KERN_INFO "sisfb: Using LCD PDC 0x%02x\n",
3098 ivideo->SiS_Pr.PDC);
3099 }
3100 }
3101 }
3102#endif
3103
3104#ifdef CONFIG_FB_SIS_315
3105 if(ivideo->sisvga_engine == SIS_315_VGA) {
3106
3107 /* Try to find about LCDA */
3108 if(ivideo->vbflags2 & VB2_SISLCDABRIDGE) {
3109 int tmp;
3110 inSISIDXREG(SISPART1,0x13,tmp);
3111 if(tmp & 0x04) {
3112 ivideo->SiS_Pr.SiS_UseLCDA = TRUE;
3113 ivideo->detectedlcda = 0x03;
3114 }
3115 }
3116
3117 /* Save PDC */
3118 if(ivideo->vbflags2 & VB2_SISLVDSBRIDGE) {
3119 int tmp;
3120 inSISIDXREG(SISCR,0x30,tmp);
3121 if((tmp & 0x20) || (ivideo->detectedlcda != 0xff)) {
3122 /* Currently on LCD? If yes, read current pdc */
3123 u8 pdc;
3124 inSISIDXREG(SISPART1,0x2D,pdc);
3125 ivideo->detectedpdc = (pdc & 0x0f) << 1;
3126 ivideo->detectedpdca = (pdc & 0xf0) >> 3;
3127 inSISIDXREG(SISPART1,0x35,pdc);
3128 ivideo->detectedpdc |= ((pdc >> 7) & 0x01);
3129 inSISIDXREG(SISPART1,0x20,pdc);
3130 ivideo->detectedpdca |= ((pdc >> 6) & 0x01);
3131 if(ivideo->newrom) {
3132 /* New ROM invalidates other PDC resp. */
3133 if(ivideo->detectedlcda != 0xff) {
3134 ivideo->detectedpdc = 0xff;
3135 } else {
3136 ivideo->detectedpdca = 0xff;
3137 }
3138 }
3139 if(ivideo->SiS_Pr.PDC == -1) {
3140 if(ivideo->detectedpdc != 0xff) {
3141 ivideo->SiS_Pr.PDC = ivideo->detectedpdc;
3142 }
3143 }
3144 if(ivideo->SiS_Pr.PDCA == -1) {
3145 if(ivideo->detectedpdca != 0xff) {
3146 ivideo->SiS_Pr.PDCA = ivideo->detectedpdca;
3147 }
3148 }
3149 if(ivideo->detectedpdc != 0xff) {
3150 printk(KERN_INFO
3151 "sisfb: Detected LCD PDC 0x%02x (for LCD=CRT2)\n",
3152 ivideo->detectedpdc);
3153 }
3154 if(ivideo->detectedpdca != 0xff) {
3155 printk(KERN_INFO
3156 "sisfb: Detected LCD PDC1 0x%02x (for LCD=CRT1)\n",
3157 ivideo->detectedpdca);
3158 }
3159 }
3160
3161 /* Save EMI */
3162 if(ivideo->vbflags2 & VB2_SISEMIBRIDGE) {
3163 inSISIDXREG(SISPART4,0x30,ivideo->SiS_Pr.EMI_30);
3164 inSISIDXREG(SISPART4,0x31,ivideo->SiS_Pr.EMI_31);
3165 inSISIDXREG(SISPART4,0x32,ivideo->SiS_Pr.EMI_32);
3166 inSISIDXREG(SISPART4,0x33,ivideo->SiS_Pr.EMI_33);
3167 ivideo->SiS_Pr.HaveEMI = TRUE;
3168 if((tmp & 0x20) || (ivideo->detectedlcda != 0xff)) {
3169 ivideo->SiS_Pr.HaveEMILCD = TRUE;
3170 }
3171 }
3172 }
3173
3174 /* Let user override detected PDCs (all bridges) */
3175 if(ivideo->vbflags2 & VB2_30xBLV) {
3176 if((ivideo->SiS_Pr.PDC != -1) &&
3177 (ivideo->SiS_Pr.PDC != ivideo->detectedpdc)) {
3178 printk(KERN_INFO "sisfb: Using LCD PDC 0x%02x (for LCD=CRT2)\n",
3179 ivideo->SiS_Pr.PDC);
3180 }
3181 if((ivideo->SiS_Pr.PDCA != -1) &&
3182 (ivideo->SiS_Pr.PDCA != ivideo->detectedpdca)) {
3183 printk(KERN_INFO "sisfb: Using LCD PDC1 0x%02x (for LCD=CRT1)\n",
3184 ivideo->SiS_Pr.PDCA);
3185 }
3186 }
3187
3188 }
3189#endif
3190}
3191
3192/* -------------------- Memory manager routines ---------------------- */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003193
3194static u32 __devinit
3195sisfb_getheapstart(struct sis_video_info *ivideo)
3196{
3197 u32 ret = ivideo->sisfb_parm_mem * 1024;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003198 u32 maxoffs = ivideo->video_size - ivideo->hwcursor_size - ivideo->cmdQueueSize;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003199 u32 def;
3200
3201 /* Calculate heap start = end of memory for console
3202 *
3203 * CCCCCCCCDDDDDDDDDDDDDDDDDDDDDDDDDDDDHHHHQQQQQQQQQQ
3204 * C = console, D = heap, H = HWCursor, Q = cmd-queue
3205 *
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003206 * On 76x in UMA+LFB mode, the layout is as follows:
3207 * DDDDDDDDDDDCCCCCCCCCCCCCCCCCCCCCCCCHHHHQQQQQQQQQQQ
3208 * where the heap is the entire UMA area, eventually
3209 * into the LFB area if the given mem parameter is
3210 * higher than the size of the UMA memory.
3211 *
Linus Torvalds1da177e2005-04-16 15:20:36 -07003212 * Basically given by "mem" parameter
3213 *
3214 * maximum = videosize - cmd_queue - hwcursor
3215 * (results in a heap of size 0)
3216 * default = SiS 300: depends on videosize
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003217 * SiS 315/330/340/XGI: 32k below max
Linus Torvalds1da177e2005-04-16 15:20:36 -07003218 */
3219
3220 if(ivideo->sisvga_engine == SIS_300_VGA) {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003221 if(ivideo->video_size > 0x1000000) {
3222 def = 0xc00000;
3223 } else if(ivideo->video_size > 0x800000) {
3224 def = 0x800000;
3225 } else {
3226 def = 0x400000;
3227 }
3228 } else if(ivideo->UMAsize && ivideo->LFBsize) {
3229 ret = def = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003230 } else {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003231 def = maxoffs - 0x8000;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003232 }
3233
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003234 /* Use default for secondary card for now (FIXME) */
3235 if((!ret) || (ret > maxoffs) || (ivideo->cardnumber != 0))
3236 ret = def;
3237
3238 return ret;
3239}
3240
3241static u32 __devinit
3242sisfb_getheapsize(struct sis_video_info *ivideo)
3243{
3244 u32 max = ivideo->video_size - ivideo->hwcursor_size - ivideo->cmdQueueSize;
3245 u32 ret = 0;
3246
3247 if(ivideo->UMAsize && ivideo->LFBsize) {
3248 if( (!ivideo->sisfb_parm_mem) ||
3249 ((ivideo->sisfb_parm_mem * 1024) > max) ||
3250 ((max - (ivideo->sisfb_parm_mem * 1024)) < ivideo->UMAsize) ) {
3251 ret = ivideo->UMAsize;
3252 max -= ivideo->UMAsize;
3253 } else {
3254 ret = max - (ivideo->sisfb_parm_mem * 1024);
3255 max = ivideo->sisfb_parm_mem * 1024;
3256 }
3257 ivideo->video_offset = ret;
3258 ivideo->sisfb_mem = max;
3259 } else {
3260 ret = max - ivideo->heapstart;
3261 ivideo->sisfb_mem = ivideo->heapstart;
3262 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003263
3264 return ret;
3265}
3266
3267static int __devinit
3268sisfb_heap_init(struct sis_video_info *ivideo)
3269{
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003270 struct SIS_OH *poh;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003271
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003272 ivideo->video_offset = 0;
3273 if(ivideo->sisfb_parm_mem) {
3274 if( (ivideo->sisfb_parm_mem < (2 * 1024 * 1024)) ||
3275 (ivideo->sisfb_parm_mem > ivideo->video_size) ) {
3276 ivideo->sisfb_parm_mem = 0;
3277 }
3278 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003279
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003280 ivideo->heapstart = sisfb_getheapstart(ivideo);
3281 ivideo->sisfb_heap_size = sisfb_getheapsize(ivideo);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003282
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003283 ivideo->sisfb_heap_start = ivideo->video_vbase + ivideo->heapstart;
3284 ivideo->sisfb_heap_end = ivideo->sisfb_heap_start + ivideo->sisfb_heap_size;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003285
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003286 printk(KERN_INFO "sisfb: Memory heap starting at %dK, size %dK\n",
3287 (int)(ivideo->heapstart / 1024), (int)(ivideo->sisfb_heap_size / 1024));
Linus Torvalds1da177e2005-04-16 15:20:36 -07003288
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003289 ivideo->sisfb_heap.vinfo = ivideo;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003290
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003291 ivideo->sisfb_heap.poha_chain = NULL;
3292 ivideo->sisfb_heap.poh_freelist = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003293
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003294 poh = sisfb_poh_new_node(&ivideo->sisfb_heap);
3295 if(poh == NULL)
3296 return 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003297
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003298 poh->poh_next = &ivideo->sisfb_heap.oh_free;
3299 poh->poh_prev = &ivideo->sisfb_heap.oh_free;
3300 poh->size = ivideo->sisfb_heap_size;
3301 poh->offset = ivideo->heapstart;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003302
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003303 ivideo->sisfb_heap.oh_free.poh_next = poh;
3304 ivideo->sisfb_heap.oh_free.poh_prev = poh;
3305 ivideo->sisfb_heap.oh_free.size = 0;
3306 ivideo->sisfb_heap.max_freesize = poh->size;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003307
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003308 ivideo->sisfb_heap.oh_used.poh_next = &ivideo->sisfb_heap.oh_used;
3309 ivideo->sisfb_heap.oh_used.poh_prev = &ivideo->sisfb_heap.oh_used;
3310 ivideo->sisfb_heap.oh_used.size = SENTINEL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003311
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003312 if(ivideo->cardnumber == 0) {
3313 /* For the first card, make this heap the "global" one
3314 * for old DRM (which could handle only one card)
3315 */
3316 sisfb_heap = &ivideo->sisfb_heap;
3317 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003318
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003319 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003320}
3321
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003322static struct SIS_OH *
3323sisfb_poh_new_node(struct SIS_HEAP *memheap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003324{
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003325 struct SIS_OHALLOC *poha;
3326 struct SIS_OH *poh;
3327 unsigned long cOhs;
3328 int i;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003329
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003330 if(memheap->poh_freelist == NULL) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003331 poha = kmalloc(SIS_OH_ALLOC_SIZE, GFP_KERNEL);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003332 if(!poha)
3333 return NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003334
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003335 poha->poha_next = memheap->poha_chain;
3336 memheap->poha_chain = poha;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003337
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003338 cOhs = (SIS_OH_ALLOC_SIZE - sizeof(struct SIS_OHALLOC)) / sizeof(struct SIS_OH) + 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003339
3340 poh = &poha->aoh[0];
3341 for(i = cOhs - 1; i != 0; i--) {
3342 poh->poh_next = poh + 1;
3343 poh = poh + 1;
3344 }
3345
3346 poh->poh_next = NULL;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003347 memheap->poh_freelist = &poha->aoh[0];
Linus Torvalds1da177e2005-04-16 15:20:36 -07003348 }
3349
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003350 poh = memheap->poh_freelist;
3351 memheap->poh_freelist = poh->poh_next;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003352
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003353 return poh;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003354}
3355
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003356static struct SIS_OH *
3357sisfb_poh_allocate(struct SIS_HEAP *memheap, u32 size)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003358{
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003359 struct SIS_OH *pohThis;
3360 struct SIS_OH *pohRoot;
3361 int bAllocated = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003362
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003363 if(size > memheap->max_freesize) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003364 DPRINTK("sisfb: Can't allocate %dk video memory\n",
3365 (unsigned int) size / 1024);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003366 return NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003367 }
3368
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003369 pohThis = memheap->oh_free.poh_next;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003370
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003371 while(pohThis != &memheap->oh_free) {
3372 if(size <= pohThis->size) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003373 bAllocated = 1;
3374 break;
3375 }
3376 pohThis = pohThis->poh_next;
3377 }
3378
3379 if(!bAllocated) {
3380 DPRINTK("sisfb: Can't allocate %dk video memory\n",
3381 (unsigned int) size / 1024);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003382 return NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003383 }
3384
3385 if(size == pohThis->size) {
3386 pohRoot = pohThis;
3387 sisfb_delete_node(pohThis);
3388 } else {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003389 pohRoot = sisfb_poh_new_node(memheap);
3390 if(pohRoot == NULL)
3391 return NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003392
3393 pohRoot->offset = pohThis->offset;
3394 pohRoot->size = size;
3395
3396 pohThis->offset += size;
3397 pohThis->size -= size;
3398 }
3399
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003400 memheap->max_freesize -= size;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003401
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003402 pohThis = &memheap->oh_used;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003403 sisfb_insert_node(pohThis, pohRoot);
3404
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003405 return pohRoot;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003406}
3407
3408static void
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003409sisfb_delete_node(struct SIS_OH *poh)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003410{
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003411 poh->poh_prev->poh_next = poh->poh_next;
3412 poh->poh_next->poh_prev = poh->poh_prev;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003413}
3414
3415static void
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003416sisfb_insert_node(struct SIS_OH *pohList, struct SIS_OH *poh)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003417{
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003418 struct SIS_OH *pohTemp = pohList->poh_next;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003419
3420 pohList->poh_next = poh;
3421 pohTemp->poh_prev = poh;
3422
3423 poh->poh_prev = pohList;
3424 poh->poh_next = pohTemp;
3425}
3426
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003427static struct SIS_OH *
3428sisfb_poh_free(struct SIS_HEAP *memheap, u32 base)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003429{
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003430 struct SIS_OH *pohThis;
3431 struct SIS_OH *poh_freed;
3432 struct SIS_OH *poh_prev;
3433 struct SIS_OH *poh_next;
3434 u32 ulUpper;
3435 u32 ulLower;
3436 int foundNode = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003437
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003438 poh_freed = memheap->oh_used.poh_next;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003439
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003440 while(poh_freed != &memheap->oh_used) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003441 if(poh_freed->offset == base) {
3442 foundNode = 1;
3443 break;
3444 }
3445
3446 poh_freed = poh_freed->poh_next;
3447 }
3448
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003449 if(!foundNode)
3450 return NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003451
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003452 memheap->max_freesize += poh_freed->size;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003453
3454 poh_prev = poh_next = NULL;
3455 ulUpper = poh_freed->offset + poh_freed->size;
3456 ulLower = poh_freed->offset;
3457
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003458 pohThis = memheap->oh_free.poh_next;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003459
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003460 while(pohThis != &memheap->oh_free) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003461 if(pohThis->offset == ulUpper) {
3462 poh_next = pohThis;
3463 } else if((pohThis->offset + pohThis->size) == ulLower) {
3464 poh_prev = pohThis;
3465 }
3466 pohThis = pohThis->poh_next;
3467 }
3468
3469 sisfb_delete_node(poh_freed);
3470
3471 if(poh_prev && poh_next) {
3472 poh_prev->size += (poh_freed->size + poh_next->size);
3473 sisfb_delete_node(poh_next);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003474 sisfb_free_node(memheap, poh_freed);
3475 sisfb_free_node(memheap, poh_next);
3476 return poh_prev;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003477 }
3478
3479 if(poh_prev) {
3480 poh_prev->size += poh_freed->size;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003481 sisfb_free_node(memheap, poh_freed);
3482 return poh_prev;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003483 }
3484
3485 if(poh_next) {
3486 poh_next->size += poh_freed->size;
3487 poh_next->offset = poh_freed->offset;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003488 sisfb_free_node(memheap, poh_freed);
3489 return poh_next;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003490 }
3491
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003492 sisfb_insert_node(&memheap->oh_free, poh_freed);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003493
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003494 return poh_freed;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003495}
3496
3497static void
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003498sisfb_free_node(struct SIS_HEAP *memheap, struct SIS_OH *poh)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003499{
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003500 if(poh == NULL)
3501 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003502
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003503 poh->poh_next = memheap->poh_freelist;
3504 memheap->poh_freelist = poh;
3505}
3506
3507static void
3508sis_int_malloc(struct sis_video_info *ivideo, struct sis_memreq *req)
3509{
3510 struct SIS_OH *poh = NULL;
3511
3512 if((ivideo) && (ivideo->sisfb_id == SISFB_ID) && (!ivideo->havenoheap))
3513 poh = sisfb_poh_allocate(&ivideo->sisfb_heap, (u32)req->size);
3514
3515 if(poh == NULL) {
3516 req->offset = req->size = 0;
3517 DPRINTK("sisfb: Video RAM allocation failed\n");
3518 } else {
3519 req->offset = poh->offset;
3520 req->size = poh->size;
3521 DPRINTK("sisfb: Video RAM allocation succeeded: 0x%lx\n",
3522 (poh->offset + ivideo->video_vbase));
3523 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003524}
3525
3526void
3527sis_malloc(struct sis_memreq *req)
3528{
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003529 struct sis_video_info *ivideo = sisfb_heap->vinfo;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003530
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003531 if(&ivideo->sisfb_heap == sisfb_heap)
3532 sis_int_malloc(ivideo, req);
3533 else
3534 req->offset = req->size = 0;
3535}
Linus Torvalds1da177e2005-04-16 15:20:36 -07003536
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003537void
3538sis_malloc_new(struct pci_dev *pdev, struct sis_memreq *req)
3539{
3540 struct sis_video_info *ivideo = pci_get_drvdata(pdev);
3541
3542 sis_int_malloc(ivideo, req);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003543}
3544
3545/* sis_free: u32 because "base" is offset inside video ram, can never be >4GB */
3546
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003547static void
3548sis_int_free(struct sis_video_info *ivideo, u32 base)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003549{
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003550 struct SIS_OH *poh;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003551
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003552 if((!ivideo) || (ivideo->sisfb_id != SISFB_ID) || (ivideo->havenoheap))
3553 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003554
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003555 poh = sisfb_poh_free(&ivideo->sisfb_heap, base);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003556
3557 if(poh == NULL) {
3558 DPRINTK("sisfb: sisfb_poh_free() failed at base 0x%x\n",
3559 (unsigned int) base);
3560 }
3561}
3562
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003563void
3564sis_free(u32 base)
3565{
3566 struct sis_video_info *ivideo = sisfb_heap->vinfo;
3567
3568 sis_int_free(ivideo, base);
3569}
3570
3571void
3572sis_free_new(struct pci_dev *pdev, u32 base)
3573{
3574 struct sis_video_info *ivideo = pci_get_drvdata(pdev);
3575
3576 sis_int_free(ivideo, base);
3577}
3578
Linus Torvalds1da177e2005-04-16 15:20:36 -07003579/* --------------------- SetMode routines ------------------------- */
3580
3581static void
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003582sisfb_check_engine_and_sync(struct sis_video_info *ivideo)
3583{
3584 u8 cr30, cr31;
3585
3586 /* Check if MMIO and engines are enabled,
3587 * and sync in case they are. Can't use
3588 * ivideo->accel here, as this might have
3589 * been changed before this is called.
3590 */
3591 inSISIDXREG(SISSR, IND_SIS_PCI_ADDRESS_SET, cr30);
3592 inSISIDXREG(SISSR, IND_SIS_MODULE_ENABLE, cr31);
3593 /* MMIO and 2D/3D engine enabled? */
3594 if((cr30 & SIS_MEM_MAP_IO_ENABLE) && (cr31 & 0x42)) {
3595#ifdef CONFIG_FB_SIS_300
3596 if(ivideo->sisvga_engine == SIS_300_VGA) {
3597 /* Don't care about TurboQueue. It's
3598 * enough to know that the engines
3599 * are enabled
3600 */
3601 sisfb_syncaccel(ivideo);
3602 }
3603#endif
3604#ifdef CONFIG_FB_SIS_315
3605 if(ivideo->sisvga_engine == SIS_315_VGA) {
3606 /* Check that any queue mode is
3607 * enabled, and that the queue
3608 * is not in the state of "reset"
3609 */
3610 inSISIDXREG(SISSR, 0x26, cr30);
3611 if((cr30 & 0xe0) && (!(cr30 & 0x01))) {
3612 sisfb_syncaccel(ivideo);
3613 }
3614 }
3615#endif
3616 }
3617}
3618
3619static void
Linus Torvalds1da177e2005-04-16 15:20:36 -07003620sisfb_pre_setmode(struct sis_video_info *ivideo)
3621{
3622 u8 cr30 = 0, cr31 = 0, cr33 = 0, cr35 = 0, cr38 = 0;
3623 int tvregnum = 0;
3624
3625 ivideo->currentvbflags &= (VB_VIDEOBRIDGE | VB_DISPTYPE_DISP2);
3626
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003627 outSISIDXREG(SISSR, 0x05, 0x86);
3628
Linus Torvalds1da177e2005-04-16 15:20:36 -07003629 inSISIDXREG(SISCR, 0x31, cr31);
3630 cr31 &= ~0x60;
3631 cr31 |= 0x04;
3632
3633 cr33 = ivideo->rate_idx & 0x0F;
3634
3635#ifdef CONFIG_FB_SIS_315
3636 if(ivideo->sisvga_engine == SIS_315_VGA) {
3637 if(ivideo->chip >= SIS_661) {
3638 inSISIDXREG(SISCR, 0x38, cr38);
3639 cr38 &= ~0x07; /* Clear LCDA/DualEdge and YPbPr bits */
3640 } else {
3641 tvregnum = 0x38;
3642 inSISIDXREG(SISCR, tvregnum, cr38);
3643 cr38 &= ~0x3b; /* Clear LCDA/DualEdge and YPbPr bits */
3644 }
3645 }
3646#endif
3647#ifdef CONFIG_FB_SIS_300
3648 if(ivideo->sisvga_engine == SIS_300_VGA) {
3649 tvregnum = 0x35;
3650 inSISIDXREG(SISCR, tvregnum, cr38);
3651 }
3652#endif
3653
3654 SiS_SetEnableDstn(&ivideo->SiS_Pr, FALSE);
3655 SiS_SetEnableFstn(&ivideo->SiS_Pr, FALSE);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003656 ivideo->curFSTN = ivideo->curDSTN = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003657
3658 switch(ivideo->currentvbflags & VB_DISPTYPE_DISP2) {
3659
3660 case CRT2_TV:
3661 cr38 &= ~0xc0; /* Clear PAL-M / PAL-N bits */
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003662 if((ivideo->vbflags & TV_YPBPR) && (ivideo->vbflags2 & VB2_SISYPBPRBRIDGE)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003663#ifdef CONFIG_FB_SIS_315
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003664 if(ivideo->chip >= SIS_661) {
3665 cr38 |= 0x04;
3666 if(ivideo->vbflags & TV_YPBPR525P) cr35 |= 0x20;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003667 else if(ivideo->vbflags & TV_YPBPR750P) cr35 |= 0x40;
3668 else if(ivideo->vbflags & TV_YPBPR1080I) cr35 |= 0x60;
3669 cr30 |= SIS_SIMULTANEOUS_VIEW_ENABLE;
3670 cr35 &= ~0x01;
3671 ivideo->currentvbflags |= (TV_YPBPR | (ivideo->vbflags & TV_YPBPRALL));
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003672 } else if(ivideo->sisvga_engine == SIS_315_VGA) {
3673 cr30 |= (0x80 | SIS_SIMULTANEOUS_VIEW_ENABLE);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003674 cr38 |= 0x08;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003675 if(ivideo->vbflags & TV_YPBPR525P) cr38 |= 0x10;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003676 else if(ivideo->vbflags & TV_YPBPR750P) cr38 |= 0x20;
3677 else if(ivideo->vbflags & TV_YPBPR1080I) cr38 |= 0x30;
3678 cr31 &= ~0x01;
3679 ivideo->currentvbflags |= (TV_YPBPR | (ivideo->vbflags & TV_YPBPRALL));
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003680 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003681#endif
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003682 } else if((ivideo->vbflags & TV_HIVISION) &&
3683 (ivideo->vbflags2 & VB2_SISHIVISIONBRIDGE)) {
3684 if(ivideo->chip >= SIS_661) {
3685 cr38 |= 0x04;
3686 cr35 |= 0x60;
3687 } else {
3688 cr30 |= 0x80;
3689 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003690 cr30 |= SIS_SIMULTANEOUS_VIEW_ENABLE;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003691 cr31 |= 0x01;
3692 cr35 |= 0x01;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003693 ivideo->currentvbflags |= TV_HIVISION;
3694 } else if(ivideo->vbflags & TV_SCART) {
3695 cr30 = (SIS_VB_OUTPUT_SCART | SIS_SIMULTANEOUS_VIEW_ENABLE);
3696 cr31 |= 0x01;
3697 cr35 |= 0x01;
3698 ivideo->currentvbflags |= TV_SCART;
3699 } else {
3700 if(ivideo->vbflags & TV_SVIDEO) {
3701 cr30 = (SIS_VB_OUTPUT_SVIDEO | SIS_SIMULTANEOUS_VIEW_ENABLE);
3702 ivideo->currentvbflags |= TV_SVIDEO;
3703 }
3704 if(ivideo->vbflags & TV_AVIDEO) {
3705 cr30 = (SIS_VB_OUTPUT_COMPOSITE | SIS_SIMULTANEOUS_VIEW_ENABLE);
3706 ivideo->currentvbflags |= TV_AVIDEO;
3707 }
3708 }
3709 cr31 |= SIS_DRIVER_MODE;
3710
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003711 if(ivideo->vbflags & (TV_AVIDEO | TV_SVIDEO)) {
3712 if(ivideo->vbflags & TV_PAL) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003713 cr31 |= 0x01; cr35 |= 0x01;
3714 ivideo->currentvbflags |= TV_PAL;
3715 if(ivideo->vbflags & TV_PALM) {
3716 cr38 |= 0x40; cr35 |= 0x04;
3717 ivideo->currentvbflags |= TV_PALM;
3718 } else if(ivideo->vbflags & TV_PALN) {
3719 cr38 |= 0x80; cr35 |= 0x08;
3720 ivideo->currentvbflags |= TV_PALN;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003721 }
3722 } else {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003723 cr31 &= ~0x01; cr35 &= ~0x01;
3724 ivideo->currentvbflags |= TV_NTSC;
3725 if(ivideo->vbflags & TV_NTSCJ) {
3726 cr38 |= 0x40; cr35 |= 0x02;
3727 ivideo->currentvbflags |= TV_NTSCJ;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003728 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003729 }
3730 }
3731 break;
3732
3733 case CRT2_LCD:
3734 cr30 = (SIS_VB_OUTPUT_LCD | SIS_SIMULTANEOUS_VIEW_ENABLE);
3735 cr31 |= SIS_DRIVER_MODE;
3736 SiS_SetEnableDstn(&ivideo->SiS_Pr, ivideo->sisfb_dstn);
3737 SiS_SetEnableFstn(&ivideo->SiS_Pr, ivideo->sisfb_fstn);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003738 ivideo->curFSTN = ivideo->sisfb_fstn;
3739 ivideo->curDSTN = ivideo->sisfb_dstn;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003740 break;
3741
3742 case CRT2_VGA:
3743 cr30 = (SIS_VB_OUTPUT_CRT2 | SIS_SIMULTANEOUS_VIEW_ENABLE);
3744 cr31 |= SIS_DRIVER_MODE;
3745 if(ivideo->sisfb_nocrt2rate) {
3746 cr33 |= (sisbios_mode[ivideo->sisfb_mode_idx].rate_idx << 4);
3747 } else {
3748 cr33 |= ((ivideo->rate_idx & 0x0F) << 4);
3749 }
3750 break;
3751
3752 default: /* disable CRT2 */
3753 cr30 = 0x00;
3754 cr31 |= (SIS_DRIVER_MODE | SIS_VB_OUTPUT_DISABLE);
3755 }
3756
3757 outSISIDXREG(SISCR, 0x30, cr30);
3758 outSISIDXREG(SISCR, 0x33, cr33);
3759
3760 if(ivideo->chip >= SIS_661) {
3761#ifdef CONFIG_FB_SIS_315
3762 cr31 &= ~0x01; /* Clear PAL flag (now in CR35) */
3763 setSISIDXREG(SISCR, 0x35, ~0x10, cr35); /* Leave overscan bit alone */
3764 cr38 &= 0x07; /* Use only LCDA and HiVision/YPbPr bits */
3765 setSISIDXREG(SISCR, 0x38, 0xf8, cr38);
3766#endif
3767 } else if(ivideo->chip != SIS_300) {
3768 outSISIDXREG(SISCR, tvregnum, cr38);
3769 }
3770 outSISIDXREG(SISCR, 0x31, cr31);
3771
Linus Torvalds1da177e2005-04-16 15:20:36 -07003772 ivideo->SiS_Pr.SiS_UseOEM = ivideo->sisfb_useoem;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003773
3774 sisfb_check_engine_and_sync(ivideo);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003775}
3776
3777/* Fix SR11 for 661 and later */
3778#ifdef CONFIG_FB_SIS_315
3779static void
3780sisfb_fixup_SR11(struct sis_video_info *ivideo)
3781{
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003782 u8 tmpreg;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003783
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003784 if(ivideo->chip >= SIS_661) {
3785 inSISIDXREG(SISSR,0x11,tmpreg);
3786 if(tmpreg & 0x20) {
3787 inSISIDXREG(SISSR,0x3e,tmpreg);
3788 tmpreg = (tmpreg + 1) & 0xff;
3789 outSISIDXREG(SISSR,0x3e,tmpreg);
3790 inSISIDXREG(SISSR,0x11,tmpreg);
3791 }
3792 if(tmpreg & 0xf0) {
3793 andSISIDXREG(SISSR,0x11,0x0f);
3794 }
3795 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003796}
3797#endif
3798
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003799static void
3800sisfb_set_TVxposoffset(struct sis_video_info *ivideo, int val)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003801{
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003802 if(val > 32) val = 32;
3803 if(val < -32) val = -32;
3804 ivideo->tvxpos = val;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003805
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003806 if(ivideo->sisfblocked) return;
3807 if(!ivideo->modechanged) return;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003808
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003809 if(ivideo->currentvbflags & CRT2_TV) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003810
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003811 if(ivideo->vbflags2 & VB2_CHRONTEL) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003812
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003813 int x = ivideo->tvx;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003814
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003815 switch(ivideo->chronteltype) {
3816 case 1:
3817 x += val;
3818 if(x < 0) x = 0;
3819 outSISIDXREG(SISSR,0x05,0x86);
3820 SiS_SetCH700x(&ivideo->SiS_Pr, 0x0a, (x & 0xff));
3821 SiS_SetCH70xxANDOR(&ivideo->SiS_Pr, 0x08, ((x & 0x0100) >> 7), 0xFD);
3822 break;
3823 case 2:
3824 /* Not supported by hardware */
3825 break;
3826 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003827
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003828 } else if(ivideo->vbflags2 & VB2_SISBRIDGE) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003829
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003830 u8 p2_1f,p2_20,p2_2b,p2_42,p2_43;
3831 unsigned short temp;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003832
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003833 p2_1f = ivideo->p2_1f;
3834 p2_20 = ivideo->p2_20;
3835 p2_2b = ivideo->p2_2b;
3836 p2_42 = ivideo->p2_42;
3837 p2_43 = ivideo->p2_43;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003838
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003839 temp = p2_1f | ((p2_20 & 0xf0) << 4);
3840 temp += (val * 2);
3841 p2_1f = temp & 0xff;
3842 p2_20 = (temp & 0xf00) >> 4;
3843 p2_2b = ((p2_2b & 0x0f) + (val * 2)) & 0x0f;
3844 temp = p2_43 | ((p2_42 & 0xf0) << 4);
3845 temp += (val * 2);
3846 p2_43 = temp & 0xff;
3847 p2_42 = (temp & 0xf00) >> 4;
3848 outSISIDXREG(SISPART2,0x1f,p2_1f);
3849 setSISIDXREG(SISPART2,0x20,0x0F,p2_20);
3850 setSISIDXREG(SISPART2,0x2b,0xF0,p2_2b);
3851 setSISIDXREG(SISPART2,0x42,0x0F,p2_42);
3852 outSISIDXREG(SISPART2,0x43,p2_43);
3853 }
3854 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003855}
3856
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003857static void
3858sisfb_set_TVyposoffset(struct sis_video_info *ivideo, int val)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003859{
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003860 if(val > 32) val = 32;
3861 if(val < -32) val = -32;
3862 ivideo->tvypos = val;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003863
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003864 if(ivideo->sisfblocked) return;
3865 if(!ivideo->modechanged) return;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003866
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003867 if(ivideo->currentvbflags & CRT2_TV) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003868
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003869 if(ivideo->vbflags2 & VB2_CHRONTEL) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003870
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003871 int y = ivideo->tvy;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003872
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003873 switch(ivideo->chronteltype) {
3874 case 1:
3875 y -= val;
3876 if(y < 0) y = 0;
3877 outSISIDXREG(SISSR,0x05,0x86);
3878 SiS_SetCH700x(&ivideo->SiS_Pr, 0x0b, (y & 0xff));
3879 SiS_SetCH70xxANDOR(&ivideo->SiS_Pr, 0x08, ((y & 0x0100) >> 8), 0xFE);
3880 break;
3881 case 2:
3882 /* Not supported by hardware */
3883 break;
3884 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003885
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003886 } else if(ivideo->vbflags2 & VB2_SISBRIDGE) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003887
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003888 char p2_01, p2_02;
3889 val /= 2;
3890 p2_01 = ivideo->p2_01;
3891 p2_02 = ivideo->p2_02;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003892
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003893 p2_01 += val;
3894 p2_02 += val;
3895 if(!(ivideo->currentvbflags & (TV_HIVISION | TV_YPBPR))) {
3896 while((p2_01 <= 0) || (p2_02 <= 0)) {
3897 p2_01 += 2;
3898 p2_02 += 2;
3899 }
3900 }
3901 outSISIDXREG(SISPART2,0x01,p2_01);
3902 outSISIDXREG(SISPART2,0x02,p2_02);
3903 }
3904 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003905}
3906
3907static void
3908sisfb_post_setmode(struct sis_video_info *ivideo)
3909{
3910 BOOLEAN crt1isoff = FALSE;
3911 BOOLEAN doit = TRUE;
3912#if defined(CONFIG_FB_SIS_300) || defined(CONFIG_FB_SIS_315)
3913 u8 reg;
3914#endif
3915#ifdef CONFIG_FB_SIS_315
3916 u8 reg1;
3917#endif
3918
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003919 outSISIDXREG(SISSR, 0x05, 0x86);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003920
3921#ifdef CONFIG_FB_SIS_315
3922 sisfb_fixup_SR11(ivideo);
3923#endif
3924
3925 /* Now we actually HAVE changed the display mode */
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003926 ivideo->modechanged = 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003927
3928 /* We can't switch off CRT1 if bridge is in slave mode */
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003929 if(ivideo->vbflags2 & VB2_VIDEOBRIDGE) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003930 if(sisfb_bridgeisslave(ivideo)) doit = FALSE;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003931 } else
3932 ivideo->sisfb_crt1off = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003933
3934#ifdef CONFIG_FB_SIS_300
3935 if(ivideo->sisvga_engine == SIS_300_VGA) {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003936 if((ivideo->sisfb_crt1off) && (doit)) {
3937 crt1isoff = TRUE;
3938 reg = 0x00;
3939 } else {
3940 crt1isoff = FALSE;
3941 reg = 0x80;
3942 }
3943 setSISIDXREG(SISCR, 0x17, 0x7f, reg);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003944 }
3945#endif
3946#ifdef CONFIG_FB_SIS_315
3947 if(ivideo->sisvga_engine == SIS_315_VGA) {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003948 if((ivideo->sisfb_crt1off) && (doit)) {
3949 crt1isoff = TRUE;
3950 reg = 0x40;
3951 reg1 = 0xc0;
3952 } else {
3953 crt1isoff = FALSE;
3954 reg = 0x00;
3955 reg1 = 0x00;
3956 }
3957 setSISIDXREG(SISCR, ivideo->SiS_Pr.SiS_MyCR63, ~0x40, reg);
3958 setSISIDXREG(SISSR, 0x1f, ~0xc0, reg1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003959 }
3960#endif
3961
3962 if(crt1isoff) {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003963 ivideo->currentvbflags &= ~VB_DISPTYPE_CRT1;
3964 ivideo->currentvbflags |= VB_SINGLE_MODE;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003965 } else {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003966 ivideo->currentvbflags |= VB_DISPTYPE_CRT1;
3967 if(ivideo->currentvbflags & VB_DISPTYPE_CRT2) {
3968 ivideo->currentvbflags |= VB_MIRROR_MODE;
3969 } else {
3970 ivideo->currentvbflags |= VB_SINGLE_MODE;
3971 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003972 }
3973
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003974 andSISIDXREG(SISSR, IND_SIS_RAMDAC_CONTROL, ~0x04);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003975
3976 if(ivideo->currentvbflags & CRT2_TV) {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003977 if(ivideo->vbflags2 & VB2_SISBRIDGE) {
3978 inSISIDXREG(SISPART2,0x1f,ivideo->p2_1f);
3979 inSISIDXREG(SISPART2,0x20,ivideo->p2_20);
3980 inSISIDXREG(SISPART2,0x2b,ivideo->p2_2b);
3981 inSISIDXREG(SISPART2,0x42,ivideo->p2_42);
3982 inSISIDXREG(SISPART2,0x43,ivideo->p2_43);
3983 inSISIDXREG(SISPART2,0x01,ivideo->p2_01);
3984 inSISIDXREG(SISPART2,0x02,ivideo->p2_02);
3985 } else if(ivideo->vbflags2 & VB2_CHRONTEL) {
3986 if(ivideo->chronteltype == 1) {
3987 ivideo->tvx = SiS_GetCH700x(&ivideo->SiS_Pr, 0x0a);
3988 ivideo->tvx |= (((SiS_GetCH700x(&ivideo->SiS_Pr, 0x08) & 0x02) >> 1) << 8);
3989 ivideo->tvy = SiS_GetCH700x(&ivideo->SiS_Pr, 0x0b);
3990 ivideo->tvy |= ((SiS_GetCH700x(&ivideo->SiS_Pr, 0x08) & 0x01) << 8);
3991 }
3992 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003993 }
3994
3995 if(ivideo->tvxpos) {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003996 sisfb_set_TVxposoffset(ivideo, ivideo->tvxpos);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003997 }
3998 if(ivideo->tvypos) {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003999 sisfb_set_TVyposoffset(ivideo, ivideo->tvypos);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004000 }
4001
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004002 /* Eventually sync engines */
4003 sisfb_check_engine_and_sync(ivideo);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004004
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004005 /* (Re-)Initialize chip engines */
4006 if(ivideo->accel) {
4007 sisfb_engine_init(ivideo);
4008 } else {
4009 ivideo->engineok = 0;
4010 }
4011}
Linus Torvalds1da177e2005-04-16 15:20:36 -07004012
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004013static int
4014sisfb_reset_mode(struct sis_video_info *ivideo)
4015{
4016 if(sisfb_set_mode(ivideo, 0))
4017 return 1;
4018
4019 sisfb_set_pitch(ivideo);
4020 sisfb_set_base_CRT1(ivideo, ivideo->current_base);
4021 sisfb_set_base_CRT2(ivideo, ivideo->current_base);
4022
4023 return 0;
4024}
4025
4026static void
4027sisfb_handle_command(struct sis_video_info *ivideo, struct sisfb_cmd *sisfb_command)
4028{
4029 int mycrt1off;
4030
4031 switch(sisfb_command->sisfb_cmd) {
4032 case SISFB_CMD_GETVBFLAGS:
4033 if(!ivideo->modechanged) {
4034 sisfb_command->sisfb_result[0] = SISFB_CMD_ERR_EARLY;
4035 } else {
4036 sisfb_command->sisfb_result[0] = SISFB_CMD_ERR_OK;
4037 sisfb_command->sisfb_result[1] = ivideo->currentvbflags;
4038 sisfb_command->sisfb_result[2] = ivideo->vbflags2;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004039 }
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004040 break;
4041 case SISFB_CMD_SWITCHCRT1:
4042 /* arg[0]: 0 = off, 1 = on, 99 = query */
4043 if(!ivideo->modechanged) {
4044 sisfb_command->sisfb_result[0] = SISFB_CMD_ERR_EARLY;
4045 } else if(sisfb_command->sisfb_arg[0] == 99) {
4046 /* Query */
4047 sisfb_command->sisfb_result[1] = ivideo->sisfb_crt1off ? 0 : 1;
4048 sisfb_command->sisfb_result[0] = SISFB_CMD_ERR_OK;
4049 } else if(ivideo->sisfblocked) {
4050 sisfb_command->sisfb_result[0] = SISFB_CMD_ERR_LOCKED;
4051 } else if((!(ivideo->currentvbflags & CRT2_ENABLE)) &&
4052 (sisfb_command->sisfb_arg[0] == 0)) {
4053 sisfb_command->sisfb_result[0] = SISFB_CMD_ERR_NOCRT2;
4054 } else {
4055 sisfb_command->sisfb_result[0] = SISFB_CMD_ERR_OK;
4056 mycrt1off = sisfb_command->sisfb_arg[0] ? 0 : 1;
4057 if( ((ivideo->currentvbflags & VB_DISPTYPE_CRT1) && mycrt1off) ||
4058 ((!(ivideo->currentvbflags & VB_DISPTYPE_CRT1)) && !mycrt1off) ) {
4059 ivideo->sisfb_crt1off = mycrt1off;
4060 if(sisfb_reset_mode(ivideo)) {
4061 sisfb_command->sisfb_result[0] = SISFB_CMD_ERR_OTHER;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004062 }
4063 }
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004064 sisfb_command->sisfb_result[1] = ivideo->sisfb_crt1off ? 0 : 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004065 }
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004066 break;
4067 /* more to come */
4068 default:
4069 sisfb_command->sisfb_result[0] = SISFB_CMD_ERR_UNKNOWN;
4070 printk(KERN_ERR "sisfb: Unknown command 0x%x\n",
4071 sisfb_command->sisfb_cmd);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004072 }
4073}
4074
4075#ifndef MODULE
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004076SISINITSTATIC int __init
4077sisfb_setup(char *options)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004078{
4079 char *this_opt;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004080
Linus Torvalds1da177e2005-04-16 15:20:36 -07004081 sisfb_setdefaultparms();
4082
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004083 if(!options || !(*options))
Linus Torvalds1da177e2005-04-16 15:20:36 -07004084 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004085
4086 while((this_opt = strsep(&options, ",")) != NULL) {
4087
4088 if(!(*this_opt)) continue;
4089
4090 if(!strnicmp(this_opt, "off", 3)) {
4091 sisfb_off = 1;
4092 } else if(!strnicmp(this_opt, "forcecrt2type:", 14)) {
4093 /* Need to check crt2 type first for fstn/dstn */
4094 sisfb_search_crt2type(this_opt + 14);
4095 } else if(!strnicmp(this_opt, "tvmode:",7)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004096 sisfb_search_tvstd(this_opt + 7);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004097 } else if(!strnicmp(this_opt, "tvstandard:",11)) {
4098 sisfb_search_tvstd(this_opt + 11);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004099 } else if(!strnicmp(this_opt, "mode:", 5)) {
4100 sisfb_search_mode(this_opt + 5, FALSE);
4101 } else if(!strnicmp(this_opt, "vesa:", 5)) {
4102 sisfb_search_vesamode(simple_strtoul(this_opt + 5, NULL, 0), FALSE);
4103#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
4104 } else if(!strnicmp(this_opt, "inverse", 7)) {
4105 sisfb_inverse = 1;
4106 /* fb_invert_cmaps(); */
4107 } else if(!strnicmp(this_opt, "font:", 5)) {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004108 if(strlen(this_opt + 5) < 40) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004109 strncpy(sisfb_fontname, this_opt + 5, sizeof(sisfb_fontname) - 1);
4110 sisfb_fontname[sizeof(sisfb_fontname) - 1] = '\0';
4111 }
4112#endif
4113 } else if(!strnicmp(this_opt, "rate:", 5)) {
4114 sisfb_parm_rate = simple_strtoul(this_opt + 5, NULL, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004115 } else if(!strnicmp(this_opt, "forcecrt1:", 10)) {
4116 sisfb_forcecrt1 = (int)simple_strtoul(this_opt + 10, NULL, 0);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004117 } else if(!strnicmp(this_opt, "mem:",4)) {
4118 sisfb_parm_mem = simple_strtoul(this_opt + 4, NULL, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004119 } else if(!strnicmp(this_opt, "pdc:", 4)) {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004120 sisfb_pdc = simple_strtoul(this_opt + 4, NULL, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004121 } else if(!strnicmp(this_opt, "pdc1:", 5)) {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004122 sisfb_pdca = simple_strtoul(this_opt + 5, NULL, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004123 } else if(!strnicmp(this_opt, "noaccel", 7)) {
4124 sisfb_accel = 0;
4125 } else if(!strnicmp(this_opt, "accel", 5)) {
4126 sisfb_accel = -1;
4127 } else if(!strnicmp(this_opt, "noypan", 6)) {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004128 sisfb_ypan = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004129 } else if(!strnicmp(this_opt, "ypan", 4)) {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004130 sisfb_ypan = -1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004131 } else if(!strnicmp(this_opt, "nomax", 5)) {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004132 sisfb_max = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004133 } else if(!strnicmp(this_opt, "max", 3)) {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004134 sisfb_max = -1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004135 } else if(!strnicmp(this_opt, "userom:", 7)) {
4136 sisfb_userom = (int)simple_strtoul(this_opt + 7, NULL, 0);
4137 } else if(!strnicmp(this_opt, "useoem:", 7)) {
4138 sisfb_useoem = (int)simple_strtoul(this_opt + 7, NULL, 0);
4139 } else if(!strnicmp(this_opt, "nocrt2rate", 10)) {
4140 sisfb_nocrt2rate = 1;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004141 } else if(!strnicmp(this_opt, "scalelcd:", 9)) {
4142 unsigned long temp = 2;
4143 temp = simple_strtoul(this_opt + 9, NULL, 0);
4144 if((temp == 0) || (temp == 1)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004145 sisfb_scalelcd = temp ^ 1;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004146 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004147 } else if(!strnicmp(this_opt, "tvxposoffset:", 13)) {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004148 int temp = 0;
4149 temp = (int)simple_strtol(this_opt + 13, NULL, 0);
4150 if((temp >= -32) && (temp <= 32)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004151 sisfb_tvxposoffset = temp;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004152 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004153 } else if(!strnicmp(this_opt, "tvyposoffset:", 13)) {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004154 int temp = 0;
4155 temp = (int)simple_strtol(this_opt + 13, NULL, 0);
4156 if((temp >= -32) && (temp <= 32)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004157 sisfb_tvyposoffset = temp;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004158 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004159 } else if(!strnicmp(this_opt, "specialtiming:", 14)) {
4160 sisfb_search_specialtiming(this_opt + 14);
4161 } else if(!strnicmp(this_opt, "lvdshl:", 7)) {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004162 int temp = 4;
4163 temp = simple_strtoul(this_opt + 7, NULL, 0);
4164 if((temp >= 0) && (temp <= 3)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004165 sisfb_lvdshl = temp;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004166 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004167 } else if(this_opt[0] >= '0' && this_opt[0] <= '9') {
4168 sisfb_search_mode(this_opt, TRUE);
4169#if !defined(__i386__) && !defined(__x86_64__)
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004170 } else if(!strnicmp(this_opt, "resetcard", 9)) {
4171 sisfb_resetcard = 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004172 } else if(!strnicmp(this_opt, "videoram:", 9)) {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004173 sisfb_videoram = simple_strtoul(this_opt + 9, NULL, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004174#endif
4175 } else {
4176 printk(KERN_INFO "sisfb: Invalid option %s\n", this_opt);
4177 }
4178
4179 }
4180
Linus Torvalds1da177e2005-04-16 15:20:36 -07004181 return 0;
4182}
4183#endif
4184
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004185static int __devinit
4186sisfb_check_rom(SIS_IOTYPE1 *rom_base, struct sis_video_info *ivideo)
4187{
4188 SIS_IOTYPE1 *rom;
4189 int romptr;
4190
4191 if((readb(rom_base) != 0x55) || (readb(rom_base + 1) != 0xaa))
4192 return 0;
4193
4194 romptr = (readb(rom_base + 0x18) | (readb(rom_base + 0x19) << 8));
4195 if(romptr > (0x10000 - 8))
4196 return 0;
4197
4198 rom = rom_base + romptr;
4199
4200 if((readb(rom) != 'P') || (readb(rom + 1) != 'C') ||
4201 (readb(rom + 2) != 'I') || (readb(rom + 3) != 'R'))
4202 return 0;
4203
4204 if((readb(rom + 4) | (readb(rom + 5) << 8)) != ivideo->chip_vendor)
4205 return 0;
4206
4207 if((readb(rom + 6) | (readb(rom + 7) << 8)) != ivideo->chip_id)
4208 return 0;
4209
4210 return 1;
4211}
4212
4213static unsigned char * __devinit
4214sisfb_find_rom(struct pci_dev *pdev)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004215{
4216 struct sis_video_info *ivideo = pci_get_drvdata(pdev);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004217 SIS_IOTYPE1 *rom_base;
4218 unsigned char *myrombase = NULL;
4219 u32 temp;
4220#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,11)
4221 size_t romsize;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004222
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004223 /* First, try the official pci ROM functions (except
4224 * on integrated chipsets which have no ROM).
4225 */
4226
4227 if(!ivideo->nbridge) {
4228
4229 if((rom_base = pci_map_rom(pdev, &romsize))) {
4230
4231 if(sisfb_check_rom(rom_base, ivideo)) {
4232
4233 if((myrombase = vmalloc(65536))) {
4234
4235 /* Work around bug in pci/rom.c: Folks forgot to check
4236 * whether the size retrieved from the BIOS image eventually
4237 * is larger than the mapped size
4238 */
4239 if(pci_resource_len(pdev, PCI_ROM_RESOURCE) < romsize)
4240 romsize = pci_resource_len(pdev, PCI_ROM_RESOURCE);
4241
4242 memcpy_fromio(myrombase, rom_base,
4243 (romsize > 65536) ? 65536 : romsize);
4244 }
4245 }
4246 pci_unmap_rom(pdev, rom_base);
4247 }
4248 }
4249
4250 if(myrombase) return myrombase;
4251#endif
4252
4253 /* Otherwise do it the conventional way. */
Linus Torvalds1da177e2005-04-16 15:20:36 -07004254
4255#if defined(__i386__) || defined(__x86_64__)
4256
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004257 for(temp = 0x000c0000; temp < 0x000f0000; temp += 0x00001000) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004258
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004259 rom_base = ioremap(temp, 65536);
4260 if(!rom_base)
4261 continue;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004262
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004263 if(!sisfb_check_rom(rom_base, ivideo)) {
4264 iounmap(rom_base);
4265 continue;
4266 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004267
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004268 if((myrombase = vmalloc(65536)))
4269 memcpy_fromio(myrombase, rom_base, 65536);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004270
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004271 iounmap(rom_base);
4272 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004273
Linus Torvalds1da177e2005-04-16 15:20:36 -07004274 }
4275
4276#else
4277
4278 pci_read_config_dword(pdev, PCI_ROM_ADDRESS, &temp);
4279 pci_write_config_dword(pdev, PCI_ROM_ADDRESS,
4280 (ivideo->video_base & PCI_ROM_ADDRESS_MASK) | PCI_ROM_ADDRESS_ENABLE);
4281
4282 rom_base = ioremap(ivideo->video_base, 65536);
4283 if(rom_base) {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004284 if(sisfb_check_rom(rom_base, ivideo)) {
4285 if((myrombase = vmalloc(65536)))
4286 memcpy_fromio(myrombase, rom_base, 65536);
4287 }
4288 iounmap(rom_base);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004289 }
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004290
4291 pci_write_config_dword(pdev, PCI_ROM_ADDRESS, temp);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004292
4293#endif
4294
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004295 return myrombase;
4296}
4297
4298static void __devinit
4299sisfb_post_map_vram(struct sis_video_info *ivideo, unsigned int *mapsize,
4300 unsigned int min)
4301{
4302 ivideo->video_vbase = ioremap(ivideo->video_base, (*mapsize));
4303
4304 if(!ivideo->video_vbase) {
4305 printk(KERN_ERR
4306 "sisfb: Unable to map maximum video RAM for size detection\n");
4307 (*mapsize) >>= 1;
4308 while((!(ivideo->video_vbase = ioremap(ivideo->video_base, (*mapsize))))) {
4309 (*mapsize) >>= 1;
4310 if((*mapsize) < (min << 20))
4311 break;
4312 }
4313 if(ivideo->video_vbase) {
4314 printk(KERN_ERR
4315 "sisfb: Video RAM size detection limited to %dMB\n",
4316 (int)((*mapsize) >> 20));
4317 }
4318 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004319}
4320
4321#ifdef CONFIG_FB_SIS_300
4322static int __devinit
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004323sisfb_post_300_buswidth(struct sis_video_info *ivideo)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004324{
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004325 SIS_IOTYPE1 *FBAddress = ivideo->video_vbase;
4326 unsigned short temp;
4327 unsigned char reg;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004328 int i, j;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004329
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004330 andSISIDXREG(SISSR, 0x15, 0xFB);
4331 orSISIDXREG(SISSR, 0x15, 0x04);
4332 outSISIDXREG(SISSR, 0x13, 0x00);
4333 outSISIDXREG(SISSR, 0x14, 0xBF);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004334
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004335 for(i = 0; i < 2; i++) {
4336 temp = 0x1234;
4337 for(j = 0; j < 4; j++) {
4338 writew(temp, FBAddress);
4339 if(readw(FBAddress) == temp)
4340 break;
4341 orSISIDXREG(SISSR, 0x3c, 0x01);
4342 inSISIDXREG(SISSR, 0x05, reg);
4343 inSISIDXREG(SISSR, 0x05, reg);
4344 andSISIDXREG(SISSR, 0x3c, 0xfe);
4345 inSISIDXREG(SISSR, 0x05, reg);
4346 inSISIDXREG(SISSR, 0x05, reg);
4347 temp++;
4348 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004349 }
4350
4351 writel(0x01234567L, FBAddress);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004352 writel(0x456789ABL, (FBAddress + 4));
4353 writel(0x89ABCDEFL, (FBAddress + 8));
4354 writel(0xCDEF0123L, (FBAddress + 12));
4355
4356 inSISIDXREG(SISSR, 0x3b, reg);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004357 if(reg & 0x01) {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004358 if(readl((FBAddress + 12)) == 0xCDEF0123L)
4359 return 4; /* Channel A 128bit */
Linus Torvalds1da177e2005-04-16 15:20:36 -07004360 }
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004361
4362 if(readl((FBAddress + 4)) == 0x456789ABL)
4363 return 2; /* Channel B 64bit */
4364
4365 return 1; /* 32bit */
4366}
4367
4368static int __devinit
4369sisfb_post_300_rwtest(struct sis_video_info *ivideo, int iteration, int buswidth,
4370 int PseudoRankCapacity, int PseudoAdrPinCount,
4371 unsigned int mapsize)
4372{
4373 SIS_IOTYPE1 *FBAddr = ivideo->video_vbase;
4374 unsigned short sr14;
4375 unsigned int k, RankCapacity, PageCapacity, BankNumHigh, BankNumMid;
4376 unsigned int PhysicalAdrOtherPage, PhysicalAdrHigh, PhysicalAdrHalfPage;
4377 static const unsigned short SiS_DRAMType[17][5] = {
4378 {0x0C,0x0A,0x02,0x40,0x39},
4379 {0x0D,0x0A,0x01,0x40,0x48},
4380 {0x0C,0x09,0x02,0x20,0x35},
4381 {0x0D,0x09,0x01,0x20,0x44},
4382 {0x0C,0x08,0x02,0x10,0x31},
4383 {0x0D,0x08,0x01,0x10,0x40},
4384 {0x0C,0x0A,0x01,0x20,0x34},
4385 {0x0C,0x09,0x01,0x08,0x32},
4386 {0x0B,0x08,0x02,0x08,0x21},
4387 {0x0C,0x08,0x01,0x08,0x30},
4388 {0x0A,0x08,0x02,0x04,0x11},
4389 {0x0B,0x0A,0x01,0x10,0x28},
4390 {0x09,0x08,0x02,0x02,0x01},
4391 {0x0B,0x09,0x01,0x08,0x24},
4392 {0x0B,0x08,0x01,0x04,0x20},
4393 {0x0A,0x08,0x01,0x02,0x10},
4394 {0x09,0x08,0x01,0x01,0x00}
4395 };
4396
4397 for(k = 0; k <= 16; k++) {
4398
4399 RankCapacity = buswidth * SiS_DRAMType[k][3];
4400
4401 if(RankCapacity != PseudoRankCapacity)
4402 continue;
4403
4404 if((SiS_DRAMType[k][2] + SiS_DRAMType[k][0]) > PseudoAdrPinCount)
4405 continue;
4406
4407 BankNumHigh = RankCapacity * 16 * iteration - 1;
4408 if(iteration == 3) { /* Rank No */
4409 BankNumMid = RankCapacity * 16 - 1;
4410 } else {
4411 BankNumMid = RankCapacity * 16 * iteration / 2 - 1;
4412 }
4413
4414 PageCapacity = (1 << SiS_DRAMType[k][1]) * buswidth * 4;
4415 PhysicalAdrHigh = BankNumHigh;
4416 PhysicalAdrHalfPage = (PageCapacity / 2 + PhysicalAdrHigh) % PageCapacity;
4417 PhysicalAdrOtherPage = PageCapacity * SiS_DRAMType[k][2] + PhysicalAdrHigh;
4418
4419 andSISIDXREG(SISSR, 0x15, 0xFB); /* Test */
4420 orSISIDXREG(SISSR, 0x15, 0x04); /* Test */
4421 sr14 = (SiS_DRAMType[k][3] * buswidth) - 1;
4422 if(buswidth == 4) sr14 |= 0x80;
4423 else if(buswidth == 2) sr14 |= 0x40;
4424 outSISIDXREG(SISSR, 0x13, SiS_DRAMType[k][4]);
4425 outSISIDXREG(SISSR, 0x14, sr14);
4426
4427 BankNumHigh <<= 16;
4428 BankNumMid <<= 16;
4429
4430 if((BankNumHigh + PhysicalAdrHigh >= mapsize) ||
4431 (BankNumMid + PhysicalAdrHigh >= mapsize) ||
4432 (BankNumHigh + PhysicalAdrHalfPage >= mapsize) ||
4433 (BankNumHigh + PhysicalAdrOtherPage >= mapsize))
4434 continue;
4435
4436 /* Write data */
4437 writew(((unsigned short)PhysicalAdrHigh),
4438 (FBAddr + BankNumHigh + PhysicalAdrHigh));
4439 writew(((unsigned short)BankNumMid),
4440 (FBAddr + BankNumMid + PhysicalAdrHigh));
4441 writew(((unsigned short)PhysicalAdrHalfPage),
4442 (FBAddr + BankNumHigh + PhysicalAdrHalfPage));
4443 writew(((unsigned short)PhysicalAdrOtherPage),
4444 (FBAddr + BankNumHigh + PhysicalAdrOtherPage));
4445
4446 /* Read data */
4447 if(readw(FBAddr + BankNumHigh + PhysicalAdrHigh) == PhysicalAdrHigh)
4448 return 1;
4449 }
4450
4451 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004452}
4453
4454static void __devinit
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004455sisfb_post_300_ramsize(struct pci_dev *pdev, unsigned int mapsize)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004456{
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004457 struct sis_video_info *ivideo = pci_get_drvdata(pdev);
4458 int i, j, buswidth;
4459 int PseudoRankCapacity, PseudoAdrPinCount;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004460
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004461 buswidth = sisfb_post_300_buswidth(ivideo);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004462
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004463 for(i = 6; i >= 0; i--) {
4464 PseudoRankCapacity = 1 << i;
4465 for(j = 4; j >= 1; j--) {
4466 PseudoAdrPinCount = 15 - j;
4467 if((PseudoRankCapacity * j) <= 64) {
4468 if(sisfb_post_300_rwtest(ivideo,
4469 j,
4470 buswidth,
4471 PseudoRankCapacity,
4472 PseudoAdrPinCount,
4473 mapsize))
4474 return;
4475 }
4476 }
4477 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004478}
4479
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004480static void __devinit
4481sisfb_post_sis300(struct pci_dev *pdev)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004482{
4483 struct sis_video_info *ivideo = pci_get_drvdata(pdev);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004484 unsigned char *bios = ivideo->SiS_Pr.VirtualRomBase;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004485 u8 reg, v1, v2, v3, v4, v5, v6, v7, v8;
4486 u16 index, rindex, memtype = 0;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004487 unsigned int mapsize;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004488
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004489 if(!ivideo->SiS_Pr.UseROM)
4490 bios = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004491
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004492 outSISIDXREG(SISSR, 0x05, 0x86);
4493
4494 if(bios) {
4495 if(bios[0x52] & 0x80) {
4496 memtype = bios[0x52];
4497 } else {
4498 inSISIDXREG(SISSR, 0x3a, memtype);
4499 }
4500 memtype &= 0x07;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004501 }
4502
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004503 v3 = 0x80; v6 = 0x80;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004504 if(ivideo->revision_id <= 0x13) {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004505 v1 = 0x44; v2 = 0x42;
4506 v4 = 0x44; v5 = 0x42;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004507 } else {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004508 v1 = 0x68; v2 = 0x43; /* Assume 125Mhz MCLK */
4509 v4 = 0x68; v5 = 0x43; /* Assume 125Mhz ECLK */
4510 if(bios) {
4511 index = memtype * 5;
4512 rindex = index + 0x54;
4513 v1 = bios[rindex++];
4514 v2 = bios[rindex++];
4515 v3 = bios[rindex++];
4516 rindex = index + 0x7c;
4517 v4 = bios[rindex++];
4518 v5 = bios[rindex++];
4519 v6 = bios[rindex++];
4520 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004521 }
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004522 outSISIDXREG(SISSR, 0x28, v1);
4523 outSISIDXREG(SISSR, 0x29, v2);
4524 outSISIDXREG(SISSR, 0x2a, v3);
4525 outSISIDXREG(SISSR, 0x2e, v4);
4526 outSISIDXREG(SISSR, 0x2f, v5);
4527 outSISIDXREG(SISSR, 0x30, v6);
4528
Linus Torvalds1da177e2005-04-16 15:20:36 -07004529 v1 = 0x10;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004530 if(bios)
4531 v1 = bios[0xa4];
4532 outSISIDXREG(SISSR, 0x07, v1); /* DAC speed */
4533
4534 outSISIDXREG(SISSR, 0x11, 0x0f); /* DDC, power save */
4535
Linus Torvalds1da177e2005-04-16 15:20:36 -07004536 v1 = 0x01; v2 = 0x43; v3 = 0x1e; v4 = 0x2a;
4537 v5 = 0x06; v6 = 0x00; v7 = 0x00; v8 = 0x00;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004538 if(bios) {
4539 memtype += 0xa5;
4540 v1 = bios[memtype];
4541 v2 = bios[memtype + 8];
4542 v3 = bios[memtype + 16];
4543 v4 = bios[memtype + 24];
4544 v5 = bios[memtype + 32];
4545 v6 = bios[memtype + 40];
4546 v7 = bios[memtype + 48];
4547 v8 = bios[memtype + 56];
Linus Torvalds1da177e2005-04-16 15:20:36 -07004548 }
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004549 if(ivideo->revision_id >= 0x80)
4550 v3 &= 0xfd;
4551 outSISIDXREG(SISSR, 0x15, v1); /* Ram type (assuming 0, BIOS 0xa5 step 8) */
4552 outSISIDXREG(SISSR, 0x16, v2);
4553 outSISIDXREG(SISSR, 0x17, v3);
4554 outSISIDXREG(SISSR, 0x18, v4);
4555 outSISIDXREG(SISSR, 0x19, v5);
4556 outSISIDXREG(SISSR, 0x1a, v6);
4557 outSISIDXREG(SISSR, 0x1b, v7);
4558 outSISIDXREG(SISSR, 0x1c, v8); /* ---- */
4559 andSISIDXREG(SISSR, 0x15 ,0xfb);
4560 orSISIDXREG(SISSR, 0x15, 0x04);
4561 if(bios) {
4562 if(bios[0x53] & 0x02) {
4563 orSISIDXREG(SISSR, 0x19, 0x20);
4564 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004565 }
4566 v1 = 0x04; /* DAC pedestal (BIOS 0xe5) */
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004567 if(ivideo->revision_id >= 0x80)
4568 v1 |= 0x01;
4569 outSISIDXREG(SISSR, 0x1f, v1);
4570 outSISIDXREG(SISSR, 0x20, 0xa4); /* linear & relocated io & disable a0000 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07004571 v1 = 0xf6; v2 = 0x0d; v3 = 0x00;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004572 if(bios) {
4573 v1 = bios[0xe8];
4574 v2 = bios[0xe9];
4575 v3 = bios[0xea];
Linus Torvalds1da177e2005-04-16 15:20:36 -07004576 }
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004577 outSISIDXREG(SISSR, 0x23, v1);
4578 outSISIDXREG(SISSR, 0x24, v2);
4579 outSISIDXREG(SISSR, 0x25, v3);
4580 outSISIDXREG(SISSR, 0x21, 0x84);
4581 outSISIDXREG(SISSR, 0x22, 0x00);
4582 outSISIDXREG(SISCR, 0x37, 0x00);
4583 orSISIDXREG(SISPART1, 0x24, 0x01); /* unlock crt2 */
4584 outSISIDXREG(SISPART1, 0x00, 0x00);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004585 v1 = 0x40; v2 = 0x11;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004586 if(bios) {
4587 v1 = bios[0xec];
4588 v2 = bios[0xeb];
Linus Torvalds1da177e2005-04-16 15:20:36 -07004589 }
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004590 outSISIDXREG(SISPART1, 0x02, v1);
4591
4592 if(ivideo->revision_id >= 0x80)
4593 v2 &= ~0x01;
4594
4595 inSISIDXREG(SISPART4, 0x00, reg);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004596 if((reg == 1) || (reg == 2)) {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004597 outSISIDXREG(SISCR, 0x37, 0x02);
4598 outSISIDXREG(SISPART2, 0x00, 0x1c);
4599 v4 = 0x00; v5 = 0x00; v6 = 0x10;
4600 if(ivideo->SiS_Pr.UseROM) {
4601 v4 = bios[0xf5];
4602 v5 = bios[0xf6];
4603 v6 = bios[0xf7];
4604 }
4605 outSISIDXREG(SISPART4, 0x0d, v4);
4606 outSISIDXREG(SISPART4, 0x0e, v5);
4607 outSISIDXREG(SISPART4, 0x10, v6);
4608 outSISIDXREG(SISPART4, 0x0f, 0x3f);
4609 inSISIDXREG(SISPART4, 0x01, reg);
4610 if(reg >= 0xb0) {
4611 inSISIDXREG(SISPART4, 0x23, reg);
4612 reg &= 0x20;
4613 reg <<= 1;
4614 outSISIDXREG(SISPART4, 0x23, reg);
4615 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004616 } else {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004617 v2 &= ~0x10;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004618 }
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004619 outSISIDXREG(SISSR, 0x32, v2);
4620
4621 andSISIDXREG(SISPART1, 0x24, 0xfe); /* Lock CRT2 */
4622
4623 inSISIDXREG(SISSR, 0x16, reg);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004624 reg &= 0xc3;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004625 outSISIDXREG(SISCR, 0x35, reg);
4626 outSISIDXREG(SISCR, 0x83, 0x00);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004627#if !defined(__i386__) && !defined(__x86_64__)
4628 if(sisfb_videoram) {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004629 outSISIDXREG(SISSR, 0x13, 0x28); /* ? */
4630 reg = ((sisfb_videoram >> 10) - 1) | 0x40;
4631 outSISIDXREG(SISSR, 0x14, reg);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004632 } else {
4633#endif
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004634 /* Need to map max FB size for finding out about RAM size */
4635 mapsize = 64 << 20;
4636 sisfb_post_map_vram(ivideo, &mapsize, 4);
4637
4638 if(ivideo->video_vbase) {
4639 sisfb_post_300_ramsize(pdev, mapsize);
4640 iounmap(ivideo->video_vbase);
4641 } else {
4642 printk(KERN_DEBUG
4643 "sisfb: Failed to map memory for size detection, assuming 8MB\n");
4644 outSISIDXREG(SISSR, 0x13, 0x28); /* ? */
4645 outSISIDXREG(SISSR, 0x14, 0x47); /* 8MB, 64bit default */
4646 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004647#if !defined(__i386__) && !defined(__x86_64__)
4648 }
4649#endif
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004650 if(bios) {
4651 v1 = bios[0xe6];
4652 v2 = bios[0xe7];
Linus Torvalds1da177e2005-04-16 15:20:36 -07004653 } else {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004654 inSISIDXREG(SISSR, 0x3a, reg);
4655 if((reg & 0x30) == 0x30) {
4656 v1 = 0x04; /* PCI */
4657 v2 = 0x92;
4658 } else {
4659 v1 = 0x14; /* AGP */
4660 v2 = 0xb2;
4661 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004662 }
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004663 outSISIDXREG(SISSR, 0x21, v1);
4664 outSISIDXREG(SISSR, 0x22, v2);
4665
4666 /* Sense CRT1 */
4667 sisfb_sense_crt1(ivideo);
4668
4669 /* Set default mode, don't clear screen */
4670 ivideo->SiS_Pr.SiS_UseOEM = FALSE;
4671 SiS_SetEnableDstn(&ivideo->SiS_Pr, FALSE);
4672 SiS_SetEnableFstn(&ivideo->SiS_Pr, FALSE);
4673 ivideo->curFSTN = ivideo->curDSTN = 0;
4674 ivideo->SiS_Pr.VideoMemorySize = 8 << 20;
4675 SiSSetMode(&ivideo->SiS_Pr, 0x2e | 0x80);
4676
4677 outSISIDXREG(SISSR, 0x05, 0x86);
4678
4679 /* Display off */
4680 orSISIDXREG(SISSR, 0x01, 0x20);
4681
4682 /* Save mode number in CR34 */
4683 outSISIDXREG(SISCR, 0x34, 0x2e);
4684
4685 /* Let everyone know what the current mode is */
4686 ivideo->modeprechange = 0x2e;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004687}
4688#endif
4689
4690#ifdef CONFIG_FB_SIS_315
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004691#if 0
4692static void __devinit
4693sisfb_post_sis315330(struct pci_dev *pdev)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004694{
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004695 /* TODO */
Linus Torvalds1da177e2005-04-16 15:20:36 -07004696}
4697#endif
4698
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004699static void __devinit
4700sisfb_post_xgi_delay(struct sis_video_info *ivideo, int delay)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004701{
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004702 unsigned int i;
4703 u8 reg;
4704
4705 for(i = 0; i <= (delay * 10 * 36); i++) {
4706 inSISIDXREG(SISSR, 0x05, reg);
4707 reg++;
4708 }
4709}
4710
4711static int __devinit
4712sisfb_find_host_bridge(struct sis_video_info *ivideo, struct pci_dev *mypdev,
4713 unsigned short pcivendor)
4714{
4715 struct pci_dev *pdev = NULL;
4716 unsigned short temp;
4717 int ret = 0;
4718
4719 while((pdev = SIS_PCI_GET_CLASS(PCI_CLASS_BRIDGE_HOST, pdev))) {
4720 temp = pdev->vendor;
4721 SIS_PCI_PUT_DEVICE(pdev);
4722 if(temp == pcivendor) {
4723 ret = 1;
4724 break;
4725 }
4726 }
4727
4728 return ret;
4729}
4730
4731static int __devinit
4732sisfb_post_xgi_rwtest(struct sis_video_info *ivideo, int starta,
4733 unsigned int enda, unsigned int mapsize)
4734{
4735 unsigned int pos;
4736 int i;
4737
4738 writel(0, ivideo->video_vbase);
4739
4740 for(i = starta; i <= enda; i++) {
4741 pos = 1 << i;
4742 if(pos < mapsize)
4743 writel(pos, ivideo->video_vbase + pos);
4744 }
4745
4746 sisfb_post_xgi_delay(ivideo, 150);
4747
4748 if(readl(ivideo->video_vbase) != 0)
4749 return 0;
4750
4751 for(i = starta; i <= enda; i++) {
4752 pos = 1 << i;
4753 if(pos < mapsize) {
4754 if(readl(ivideo->video_vbase + pos) != pos)
4755 return 0;
4756 } else
4757 return 0;
4758 }
4759
4760 return 1;
4761}
4762
4763static void __devinit
4764sisfb_post_xgi_ramsize(struct sis_video_info *ivideo)
4765{
4766 unsigned int buswidth, ranksize, channelab, mapsize;
4767 int i, j, k, l;
4768 u8 reg, sr14;
4769 static const u8 dramsr13[12 * 5] = {
4770 0x02, 0x0e, 0x0b, 0x80, 0x5d,
4771 0x02, 0x0e, 0x0a, 0x40, 0x59,
4772 0x02, 0x0d, 0x0b, 0x40, 0x4d,
4773 0x02, 0x0e, 0x09, 0x20, 0x55,
4774 0x02, 0x0d, 0x0a, 0x20, 0x49,
4775 0x02, 0x0c, 0x0b, 0x20, 0x3d,
4776 0x02, 0x0e, 0x08, 0x10, 0x51,
4777 0x02, 0x0d, 0x09, 0x10, 0x45,
4778 0x02, 0x0c, 0x0a, 0x10, 0x39,
4779 0x02, 0x0d, 0x08, 0x08, 0x41,
4780 0x02, 0x0c, 0x09, 0x08, 0x35,
4781 0x02, 0x0c, 0x08, 0x04, 0x31
4782 };
4783 static const u8 dramsr13_4[4 * 5] = {
4784 0x02, 0x0d, 0x09, 0x40, 0x45,
4785 0x02, 0x0c, 0x09, 0x20, 0x35,
4786 0x02, 0x0c, 0x08, 0x10, 0x31,
4787 0x02, 0x0b, 0x08, 0x08, 0x21
4788 };
4789
4790 /* Enable linear mode, disable 0xa0000 address decoding */
4791 /* We disable a0000 address decoding, because
4792 * - if running on x86, if the card is disabled, it means
4793 * that another card is in the system. We don't want
4794 * to interphere with that primary card's textmode.
4795 * - if running on non-x86, there usually is no VGA window
4796 * at a0000.
4797 */
4798 orSISIDXREG(SISSR, 0x20, (0x80 | 0x04));
4799
4800 /* Need to map max FB size for finding out about RAM size */
4801 mapsize = 256 << 20;
4802 sisfb_post_map_vram(ivideo, &mapsize, 32);
4803
4804 if(!ivideo->video_vbase) {
4805 printk(KERN_ERR "sisfb: Unable to detect RAM size. Setting default.\n");
4806 outSISIDXREG(SISSR, 0x13, 0x35);
4807 outSISIDXREG(SISSR, 0x14, 0x41);
4808 /* TODO */
4809 return;
4810 }
4811
4812 /* Non-interleaving */
4813 outSISIDXREG(SISSR, 0x15, 0x00);
4814 /* No tiling */
4815 outSISIDXREG(SISSR, 0x1c, 0x00);
4816
4817 if(ivideo->chip == XGI_20) {
4818
4819 channelab = 1;
4820 inSISIDXREG(SISCR, 0x97, reg);
4821 if(!(reg & 0x01)) { /* Single 32/16 */
4822 buswidth = 32;
4823 outSISIDXREG(SISSR, 0x13, 0xb1);
4824 outSISIDXREG(SISSR, 0x14, 0x52);
4825 sisfb_post_xgi_delay(ivideo, 1);
4826 sr14 = 0x02;
4827 if(sisfb_post_xgi_rwtest(ivideo, 23, 24, mapsize))
4828 goto bail_out;
4829
4830 outSISIDXREG(SISSR, 0x13, 0x31);
4831 outSISIDXREG(SISSR, 0x14, 0x42);
4832 sisfb_post_xgi_delay(ivideo, 1);
4833 if(sisfb_post_xgi_rwtest(ivideo, 23, 23, mapsize))
4834 goto bail_out;
4835
4836 buswidth = 16;
4837 outSISIDXREG(SISSR, 0x13, 0xb1);
4838 outSISIDXREG(SISSR, 0x14, 0x41);
4839 sisfb_post_xgi_delay(ivideo, 1);
4840 sr14 = 0x01;
4841 if(sisfb_post_xgi_rwtest(ivideo, 22, 23, mapsize))
4842 goto bail_out;
4843 else
4844 outSISIDXREG(SISSR, 0x13, 0x31);
4845 } else { /* Dual 16/8 */
4846 buswidth = 16;
4847 outSISIDXREG(SISSR, 0x13, 0xb1);
4848 outSISIDXREG(SISSR, 0x14, 0x41);
4849 sisfb_post_xgi_delay(ivideo, 1);
4850 sr14 = 0x01;
4851 if(sisfb_post_xgi_rwtest(ivideo, 22, 23, mapsize))
4852 goto bail_out;
4853
4854 outSISIDXREG(SISSR, 0x13, 0x31);
4855 outSISIDXREG(SISSR, 0x14, 0x31);
4856 sisfb_post_xgi_delay(ivideo, 1);
4857 if(sisfb_post_xgi_rwtest(ivideo, 22, 22, mapsize))
4858 goto bail_out;
4859
4860 buswidth = 8;
4861 outSISIDXREG(SISSR, 0x13, 0xb1);
4862 outSISIDXREG(SISSR, 0x14, 0x30);
4863 sisfb_post_xgi_delay(ivideo, 1);
4864 sr14 = 0x00;
4865 if(sisfb_post_xgi_rwtest(ivideo, 21, 22, mapsize))
4866 goto bail_out;
4867 else
4868 outSISIDXREG(SISSR, 0x13, 0x31);
4869 }
4870
4871 } else { /* XGI_40 */
4872
4873 inSISIDXREG(SISCR, 0x97, reg);
4874 if(!(reg & 0x10)) {
4875 inSISIDXREG(SISSR, 0x39, reg);
4876 reg >>= 1;
4877 }
4878
4879 if(reg & 0x01) { /* DDRII */
4880 buswidth = 32;
4881 if(ivideo->revision_id == 2) {
4882 channelab = 2;
4883 outSISIDXREG(SISSR, 0x13, 0xa1);
4884 outSISIDXREG(SISSR, 0x14, 0x44);
4885 sr14 = 0x04;
4886 sisfb_post_xgi_delay(ivideo, 1);
4887 if(sisfb_post_xgi_rwtest(ivideo, 23, 24, mapsize))
4888 goto bail_out;
4889
4890 outSISIDXREG(SISSR, 0x13, 0x21);
4891 outSISIDXREG(SISSR, 0x14, 0x34);
4892 if(sisfb_post_xgi_rwtest(ivideo, 22, 23, mapsize))
4893 goto bail_out;
4894
4895 channelab = 1;
4896 outSISIDXREG(SISSR, 0x13, 0xa1);
4897 outSISIDXREG(SISSR, 0x14, 0x40);
4898 sr14 = 0x00;
4899 if(sisfb_post_xgi_rwtest(ivideo, 22, 23, mapsize))
4900 goto bail_out;
4901
4902 outSISIDXREG(SISSR, 0x13, 0x21);
4903 outSISIDXREG(SISSR, 0x14, 0x30);
4904 } else {
4905 channelab = 3;
4906 outSISIDXREG(SISSR, 0x13, 0xa1);
4907 outSISIDXREG(SISSR, 0x14, 0x4c);
4908 sr14 = 0x0c;
4909 sisfb_post_xgi_delay(ivideo, 1);
4910 if(sisfb_post_xgi_rwtest(ivideo, 23, 25, mapsize))
4911 goto bail_out;
4912
4913 channelab = 2;
4914 outSISIDXREG(SISSR, 0x14, 0x48);
4915 sisfb_post_xgi_delay(ivideo, 1);
4916 sr14 = 0x08;
4917 if(sisfb_post_xgi_rwtest(ivideo, 23, 24, mapsize))
4918 goto bail_out;
4919
4920 outSISIDXREG(SISSR, 0x13, 0x21);
4921 outSISIDXREG(SISSR, 0x14, 0x3c);
4922 sr14 = 0x0c;
4923
4924 if(sisfb_post_xgi_rwtest(ivideo, 23, 24, mapsize)) {
4925 channelab = 3;
4926 } else {
4927 channelab = 2;
4928 outSISIDXREG(SISSR, 0x14, 0x38);
4929 sr14 = 0x08;
4930 }
4931 }
4932 sisfb_post_xgi_delay(ivideo, 1);
4933
4934 } else { /* DDR */
4935
4936 buswidth = 64;
4937 if(ivideo->revision_id == 2) {
4938 channelab = 1;
4939 outSISIDXREG(SISSR, 0x13, 0xa1);
4940 outSISIDXREG(SISSR, 0x14, 0x52);
4941 sisfb_post_xgi_delay(ivideo, 1);
4942 sr14 = 0x02;
4943 if(sisfb_post_xgi_rwtest(ivideo, 23, 24, mapsize))
4944 goto bail_out;
4945
4946 outSISIDXREG(SISSR, 0x13, 0x21);
4947 outSISIDXREG(SISSR, 0x14, 0x42);
4948 } else {
4949 channelab = 2;
4950 outSISIDXREG(SISSR, 0x13, 0xa1);
4951 outSISIDXREG(SISSR, 0x14, 0x5a);
4952 sisfb_post_xgi_delay(ivideo, 1);
4953 sr14 = 0x0a;
4954 if(sisfb_post_xgi_rwtest(ivideo, 24, 25, mapsize))
4955 goto bail_out;
4956
4957 outSISIDXREG(SISSR, 0x13, 0x21);
4958 outSISIDXREG(SISSR, 0x14, 0x4a);
4959 }
4960 sisfb_post_xgi_delay(ivideo, 1);
4961
4962 }
4963 }
4964
4965bail_out:
4966 setSISIDXREG(SISSR, 0x14, 0xf0, sr14);
4967 sisfb_post_xgi_delay(ivideo, 1);
4968
4969 j = (ivideo->chip == XGI_20) ? 5 : 9;
4970 k = (ivideo->chip == XGI_20) ? 12 : 4;
4971
4972 for(i = 0; i < k; i++) {
4973
4974 reg = (ivideo->chip == XGI_20) ?
4975 dramsr13[(i * 5) + 4] : dramsr13_4[(i * 5) + 4];
4976 setSISIDXREG(SISSR, 0x13, 0x80, reg);
4977 sisfb_post_xgi_delay(ivideo, 50);
4978
4979 ranksize = (ivideo->chip == XGI_20) ?
4980 dramsr13[(i * 5) + 3] : dramsr13_4[(i * 5) + 3];
4981
4982 inSISIDXREG(SISSR, 0x13, reg);
4983 if(reg & 0x80) ranksize <<= 1;
4984
4985 if(ivideo->chip == XGI_20) {
4986 if(buswidth == 16) ranksize <<= 1;
4987 else if(buswidth == 32) ranksize <<= 2;
4988 } else {
4989 if(buswidth == 64) ranksize <<= 1;
4990 }
4991
4992 reg = 0;
4993 l = channelab;
4994 if(l == 3) l = 4;
4995 if((ranksize * l) <= 256) {
4996 while((ranksize >>= 1)) reg += 0x10;
4997 }
4998
4999 if(!reg) continue;
5000
5001 setSISIDXREG(SISSR, 0x14, 0x0f, (reg & 0xf0));
5002 sisfb_post_xgi_delay(ivideo, 1);
5003
5004 if(sisfb_post_xgi_rwtest(ivideo, j, ((reg >> 4) + channelab - 2 + 20), mapsize))
5005 break;
5006 }
5007
5008 iounmap(ivideo->video_vbase);
5009}
5010
5011static void __devinit
5012sisfb_post_xgi_setclocks(struct sis_video_info *ivideo, u8 regb)
5013{
5014 u8 v1, v2, v3;
5015 int index;
5016 static const u8 cs90[8 * 3] = {
5017 0x16, 0x01, 0x01,
5018 0x3e, 0x03, 0x01,
5019 0x7c, 0x08, 0x01,
5020 0x79, 0x06, 0x01,
5021 0x29, 0x01, 0x81,
5022 0x5c, 0x23, 0x01,
5023 0x5c, 0x23, 0x01,
5024 0x5c, 0x23, 0x01
5025 };
5026 static const u8 csb8[8 * 3] = {
5027 0x5c, 0x23, 0x01,
5028 0x29, 0x01, 0x01,
5029 0x7c, 0x08, 0x01,
5030 0x79, 0x06, 0x01,
5031 0x29, 0x01, 0x81,
5032 0x5c, 0x23, 0x01,
5033 0x5c, 0x23, 0x01,
5034 0x5c, 0x23, 0x01
5035 };
5036
5037 regb = 0; /* ! */
5038
5039 index = regb * 3;
5040 v1 = cs90[index]; v2 = cs90[index + 1]; v3 = cs90[index + 2];
5041 if(ivideo->haveXGIROM) {
5042 v1 = ivideo->bios_abase[0x90 + index];
5043 v2 = ivideo->bios_abase[0x90 + index + 1];
5044 v3 = ivideo->bios_abase[0x90 + index + 2];
5045 }
5046 outSISIDXREG(SISSR, 0x28, v1);
5047 outSISIDXREG(SISSR, 0x29, v2);
5048 outSISIDXREG(SISSR, 0x2a, v3);
5049 sisfb_post_xgi_delay(ivideo, 0x43);
5050 sisfb_post_xgi_delay(ivideo, 0x43);
5051 sisfb_post_xgi_delay(ivideo, 0x43);
5052 index = regb * 3;
5053 v1 = csb8[index]; v2 = csb8[index + 1]; v3 = csb8[index + 2];
5054 if(ivideo->haveXGIROM) {
5055 v1 = ivideo->bios_abase[0xb8 + index];
5056 v2 = ivideo->bios_abase[0xb8 + index + 1];
5057 v3 = ivideo->bios_abase[0xb8 + index + 2];
5058 }
5059 outSISIDXREG(SISSR, 0x2e, v1);
5060 outSISIDXREG(SISSR, 0x2f, v2);
5061 outSISIDXREG(SISSR, 0x30, v3);
5062 sisfb_post_xgi_delay(ivideo, 0x43);
5063 sisfb_post_xgi_delay(ivideo, 0x43);
5064 sisfb_post_xgi_delay(ivideo, 0x43);
5065}
5066
5067static int __devinit
5068sisfb_post_xgi(struct pci_dev *pdev)
5069{
5070 struct sis_video_info *ivideo = pci_get_drvdata(pdev);
5071 unsigned char *bios = ivideo->bios_abase;
5072 struct pci_dev *mypdev = NULL;
5073 const u8 *ptr, *ptr2;
5074 u8 v1, v2, v3, v4, v5, reg, ramtype;
5075 u32 rega, regb, regd;
5076 int i, j, k, index;
5077 static const u8 cs78[3] = { 0xf6, 0x0d, 0x00 };
5078 static const u8 cs76[2] = { 0xa3, 0xfb };
5079 static const u8 cs7b[3] = { 0xc0, 0x11, 0x00 };
5080 static const u8 cs158[8] = {
5081 0x88, 0xaa, 0x48, 0x00, 0x00, 0x00, 0x00, 0x00
5082 };
5083 static const u8 cs160[8] = {
5084 0x44, 0x77, 0x77, 0x00, 0x00, 0x00, 0x00, 0x00
5085 };
5086 static const u8 cs168[8] = {
5087 0x48, 0x78, 0x88, 0x00, 0x00, 0x00, 0x00, 0x00
5088 };
5089 static const u8 cs128[3 * 8] = {
5090 0x90, 0x28, 0x24, 0x00, 0x00, 0x00, 0x00, 0x00,
5091 0x77, 0x44, 0x44, 0x00, 0x00, 0x00, 0x00, 0x00,
5092 0x77, 0x44, 0x44, 0x00, 0x00, 0x00, 0x00, 0x00
5093 };
5094 static const u8 cs148[2 * 8] = {
5095 0x55, 0x55, 0x55, 0x00, 0x00, 0x00, 0x00, 0x00,
5096 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
5097 };
5098 static const u8 cs31a[8 * 4] = {
5099 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
5100 0xaa, 0xaa, 0xaa, 0xaa, 0x00, 0x00, 0x00, 0x00,
5101 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
5102 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
5103 };
5104 static const u8 cs33a[8 * 4] = {
5105 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
5106 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
5107 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
5108 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
5109 };
5110 static const u8 cs45a[8 * 2] = {
5111 0x00, 0x00, 0xa0, 0x00, 0xa0, 0x00, 0x00, 0x00,
5112 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
5113 };
5114 static const u8 cs170[7 * 8] = {
5115 0x54, 0x32, 0x44, 0x00, 0x00, 0x00, 0x00, 0x00,
5116 0x54, 0x43, 0x44, 0x00, 0x00, 0x00, 0x00, 0x00,
5117 0x0a, 0x05, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00,
5118 0x44, 0x34, 0x44, 0x00, 0x00, 0x00, 0x00, 0x00,
5119 0x10, 0x0a, 0x0a, 0x00, 0x00, 0x00, 0x00, 0x00,
5120 0x11, 0x0c, 0x0c, 0x00, 0x00, 0x00, 0x00, 0x00,
5121 0x05, 0x05, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00
5122 };
5123 static const u8 cs1a8[3 * 8] = {
5124 0xf0, 0xf0, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x00,
5125 0x05, 0x02, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00,
5126 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
5127 };
5128 static const u8 cs100[2 * 8] = {
5129 0xc4, 0x04, 0x84, 0x00, 0x00, 0x00, 0x00, 0x00,
5130 0xc4, 0x04, 0x84, 0x00, 0x00, 0x00, 0x00, 0x00
5131 };
5132
5133 /* VGA enable */
5134 reg = inSISREG(SISVGAENABLE) | 0x01;
5135 outSISREG(SISVGAENABLE, reg);
5136
5137 /* Misc */
5138 reg = inSISREG(SISMISCR) | 0x01;
5139 outSISREG(SISMISCW, reg);
5140
5141 /* Unlock SR */
5142 outSISIDXREG(SISSR, 0x05, 0x86);
5143 inSISIDXREG(SISSR, 0x05, reg);
5144 if(reg != 0xa1)
5145 return 0;
5146
5147 /* Clear some regs */
5148 for(i = 0; i < 0x22; i++) {
5149 if(0x06 + i == 0x20) continue;
5150 outSISIDXREG(SISSR, 0x06 + i, 0x00);
5151 }
5152 for(i = 0; i < 0x0b; i++) {
5153 outSISIDXREG(SISSR, 0x31 + i, 0x00);
5154 }
5155 for(i = 0; i < 0x10; i++) {
5156 outSISIDXREG(SISCR, 0x30 + i, 0x00);
5157 }
5158
5159 ptr = cs78;
5160 if(ivideo->haveXGIROM) {
5161 ptr = (const u8 *)&bios[0x78];
5162 }
5163 for(i = 0; i < 3; i++) {
5164 outSISIDXREG(SISSR, 0x23 + i, ptr[i]);
5165 }
5166
5167 ptr = cs76;
5168 if(ivideo->haveXGIROM) {
5169 ptr = (const u8 *)&bios[0x76];
5170 }
5171 for(i = 0; i < 2; i++) {
5172 outSISIDXREG(SISSR, 0x21 + i, ptr[i]);
5173 }
5174
5175 v1 = 0x18; v2 = 0x00;
5176 if(ivideo->haveXGIROM) {
5177 v1 = bios[0x74];
5178 v2 = bios[0x75];
5179 }
5180 outSISIDXREG(SISSR, 0x07, v1);
5181 outSISIDXREG(SISSR, 0x11, 0x0f);
5182 outSISIDXREG(SISSR, 0x1f, v2);
5183 /* PCI linear mode, RelIO enabled, A0000 decoding disabled */
5184 outSISIDXREG(SISSR, 0x20, 0x80 | 0x20 | 0x04);
5185 outSISIDXREG(SISSR, 0x27, 0x74);
5186
5187 ptr = cs7b;
5188 if(ivideo->haveXGIROM) {
5189 ptr = (const u8 *)&bios[0x7b];
5190 }
5191 for(i = 0; i < 3; i++) {
5192 outSISIDXREG(SISSR, 0x31 + i, ptr[i]);
5193 }
5194
5195 if(ivideo->chip == XGI_40) {
5196 if(ivideo->revision_id == 2) {
5197 setSISIDXREG(SISSR, 0x3b, 0x3f, 0xc0);
5198 }
5199 outSISIDXREG(SISCR, 0x7d, 0xfe);
5200 outSISIDXREG(SISCR, 0x7e, 0x0f);
5201 }
5202 if(ivideo->revision_id == 0) { /* 40 *and* 20? */
5203 andSISIDXREG(SISCR, 0x58, 0xd7);
5204 inSISIDXREG(SISCR, 0xcb, reg);
5205 if(reg & 0x20) {
5206 setSISIDXREG(SISCR, 0x58, 0xd7, (reg & 0x10) ? 0x08 : 0x20); /* =0x28 Z7 ? */
5207 }
5208 }
5209
5210 reg = (ivideo->chip == XGI_40) ? 0x20 : 0x00;
5211 setSISIDXREG(SISCR, 0x38, 0x1f, reg);
5212
5213 if(ivideo->chip == XGI_20) {
5214 outSISIDXREG(SISSR, 0x36, 0x70);
5215 } else {
5216 outSISIDXREG(SISVID, 0x00, 0x86);
5217 outSISIDXREG(SISVID, 0x32, 0x00);
5218 outSISIDXREG(SISVID, 0x30, 0x00);
5219 outSISIDXREG(SISVID, 0x32, 0x01);
5220 outSISIDXREG(SISVID, 0x30, 0x00);
5221 andSISIDXREG(SISVID, 0x2f, 0xdf);
5222 andSISIDXREG(SISCAP, 0x00, 0x3f);
5223
5224 outSISIDXREG(SISPART1, 0x2f, 0x01);
5225 outSISIDXREG(SISPART1, 0x00, 0x00);
5226 outSISIDXREG(SISPART1, 0x02, bios[0x7e]);
5227 outSISIDXREG(SISPART1, 0x2e, 0x08);
5228 andSISIDXREG(SISPART1, 0x35, 0x7f);
5229 andSISIDXREG(SISPART1, 0x50, 0xfe);
5230
5231 inSISIDXREG(SISPART4, 0x00, reg);
5232 if(reg == 1 || reg == 2) {
5233 outSISIDXREG(SISPART2, 0x00, 0x1c);
5234 outSISIDXREG(SISPART4, 0x0d, bios[0x7f]);
5235 outSISIDXREG(SISPART4, 0x0e, bios[0x80]);
5236 outSISIDXREG(SISPART4, 0x10, bios[0x81]);
5237 andSISIDXREG(SISPART4, 0x0f, 0x3f);
5238
5239 inSISIDXREG(SISPART4, 0x01, reg);
5240 if((reg & 0xf0) >= 0xb0) {
5241 inSISIDXREG(SISPART4, 0x23, reg);
5242 if(reg & 0x20) reg |= 0x40;
5243 outSISIDXREG(SISPART4, 0x23, reg);
5244 reg = (reg & 0x20) ? 0x02 : 0x00;
5245 setSISIDXREG(SISPART1, 0x1e, 0xfd, reg);
5246 }
5247 }
5248
5249 v1 = bios[0x77];
5250
5251 inSISIDXREG(SISSR, 0x3b, reg);
5252 if(reg & 0x02) {
5253 inSISIDXREG(SISSR, 0x3a, reg);
5254 v2 = (reg & 0x30) >> 3;
5255 if(!(v2 & 0x04)) v2 ^= 0x02;
5256 inSISIDXREG(SISSR, 0x39, reg);
5257 if(reg & 0x80) v2 |= 0x80;
5258 v2 |= 0x01;
5259
5260 if((mypdev = SIS_PCI_GET_DEVICE(PCI_VENDOR_ID_SI, 0x0730, NULL))) {
5261 SIS_PCI_PUT_DEVICE(mypdev);
5262 if(((v2 & 0x06) == 2) || ((v2 & 0x06) == 4))
5263 v2 &= 0xf9;
5264 v2 |= 0x08;
5265 v1 &= 0xfe;
5266 } else {
5267 mypdev = SIS_PCI_GET_DEVICE(PCI_VENDOR_ID_SI, 0x0735, NULL);
5268 if(!mypdev)
5269 mypdev = SIS_PCI_GET_DEVICE(PCI_VENDOR_ID_SI, 0x0645, NULL);
5270 if(!mypdev)
5271 mypdev = SIS_PCI_GET_DEVICE(PCI_VENDOR_ID_SI, 0x0650, NULL);
5272 if(mypdev) {
5273 pci_read_config_dword(mypdev, 0x94, &regd);
5274 regd &= 0xfffffeff;
5275 pci_write_config_dword(mypdev, 0x94, regd);
5276 v1 &= 0xfe;
5277 SIS_PCI_PUT_DEVICE(mypdev);
5278 } else if(sisfb_find_host_bridge(ivideo, pdev, PCI_VENDOR_ID_SI)) {
5279 v1 &= 0xfe;
5280 } else if(sisfb_find_host_bridge(ivideo, pdev, 0x1106) ||
5281 sisfb_find_host_bridge(ivideo, pdev, 0x1022) ||
5282 sisfb_find_host_bridge(ivideo, pdev, 0x700e) ||
5283 sisfb_find_host_bridge(ivideo, pdev, 0x10de)) {
5284 if((v2 & 0x06) == 4)
5285 v2 ^= 0x06;
5286 v2 |= 0x08;
5287 }
5288 }
5289 setSISIDXREG(SISCR, 0x5f, 0xf0, v2);
5290 }
5291 outSISIDXREG(SISSR, 0x22, v1);
5292
5293 if(ivideo->revision_id == 2) {
5294 inSISIDXREG(SISSR, 0x3b, v1);
5295 inSISIDXREG(SISSR, 0x3a, v2);
5296 regd = bios[0x90 + 3] | (bios[0x90 + 4] << 8);
5297 if( (!(v1 & 0x02)) && (v2 & 0x30) && (regd < 0xcf) )
5298 setSISIDXREG(SISCR, 0x5f, 0xf1, 0x01);
5299
5300 if((mypdev = SIS_PCI_GET_DEVICE(0x10de, 0x01e0, NULL))) {
5301 /* TODO: set CR5f &0xf1 | 0x01 for version 6570
5302 * of nforce 2 ROM
5303 */
5304 if(0)
5305 setSISIDXREG(SISCR, 0x5f, 0xf1, 0x01);
5306 SIS_PCI_PUT_DEVICE(mypdev);
5307 }
5308 }
5309
5310 v1 = 0x30;
5311 inSISIDXREG(SISSR, 0x3b, reg);
5312 inSISIDXREG(SISCR, 0x5f, v2);
5313 if((!(reg & 0x02)) && (v2 & 0x0e))
5314 v1 |= 0x08;
5315 outSISIDXREG(SISSR, 0x27, v1);
5316
5317 if(bios[0x64] & 0x01) {
5318 setSISIDXREG(SISCR, 0x5f, 0xf0, bios[0x64]);
5319 }
5320
5321 v1 = bios[0x4f7];
5322 pci_read_config_dword(pdev, 0x50, &regd);
5323 regd = (regd >> 20) & 0x0f;
5324 if(regd == 1) {
5325 v1 &= 0xfc;
5326 orSISIDXREG(SISCR, 0x5f, 0x08);
5327 }
5328 outSISIDXREG(SISCR, 0x48, v1);
5329
5330 setSISIDXREG(SISCR, 0x47, 0x04, bios[0x4f6] & 0xfb);
5331 setSISIDXREG(SISCR, 0x49, 0xf0, bios[0x4f8] & 0x0f);
5332 setSISIDXREG(SISCR, 0x4a, 0x60, bios[0x4f9] & 0x9f);
5333 setSISIDXREG(SISCR, 0x4b, 0x08, bios[0x4fa] & 0xf7);
5334 setSISIDXREG(SISCR, 0x4c, 0x80, bios[0x4fb] & 0x7f);
5335 outSISIDXREG(SISCR, 0x70, bios[0x4fc]);
5336 setSISIDXREG(SISCR, 0x71, 0xf0, bios[0x4fd] & 0x0f);
5337 outSISIDXREG(SISCR, 0x74, 0xd0);
5338 setSISIDXREG(SISCR, 0x74, 0xcf, bios[0x4fe] & 0x30);
5339 setSISIDXREG(SISCR, 0x75, 0xe0, bios[0x4ff] & 0x1f);
5340 setSISIDXREG(SISCR, 0x76, 0xe0, bios[0x500] & 0x1f);
5341 v1 = bios[0x501];
5342 if((mypdev = SIS_PCI_GET_DEVICE(0x8086, 0x2530, NULL))) {
5343 v1 = 0xf0;
5344 SIS_PCI_PUT_DEVICE(mypdev);
5345 }
5346 outSISIDXREG(SISCR, 0x77, v1);
5347 }
5348
5349 /* RAM type */
5350
5351 regb = 0; /* ! */
5352
5353 v1 = 0xff;
5354 if(ivideo->haveXGIROM) {
5355 v1 = bios[0x140 + regb];
5356 }
5357 outSISIDXREG(SISCR, 0x6d, v1);
5358
5359 ptr = cs128;
5360 if(ivideo->haveXGIROM) {
5361 ptr = (const u8 *)&bios[0x128];
5362 }
5363 for(i = 0, j = 0; i < 3; i++, j += 8) {
5364 outSISIDXREG(SISCR, 0x68 + i, ptr[j + regb]);
5365 }
5366
5367 ptr = cs31a;
5368 ptr2 = cs33a;
5369 if(ivideo->haveXGIROM) {
5370 index = (ivideo->chip == XGI_20) ? 0x31a : 0x3a6;
5371 ptr = (const u8 *)&bios[index];
5372 ptr2 = (const u8 *)&bios[index + 0x20];
5373 }
5374 for(i = 0; i < 2; i++) {
5375 if(i == 0) {
5376 regd = le32_to_cpu(((u32 *)ptr)[regb]);
5377 rega = 0x6b;
5378 } else {
5379 regd = le32_to_cpu(((u32 *)ptr2)[regb]);
5380 rega = 0x6e;
5381 }
5382 reg = 0x00;
5383 for(j = 0; j < 16; j++) {
5384 reg &= 0xf3;
5385 if(regd & 0x01) reg |= 0x04;
5386 if(regd & 0x02) reg |= 0x08;
5387 regd >>= 2;
5388 outSISIDXREG(SISCR, rega, reg);
5389 inSISIDXREG(SISCR, rega, reg);
5390 inSISIDXREG(SISCR, rega, reg);
5391 reg += 0x10;
5392 }
5393 }
5394
5395 andSISIDXREG(SISCR, 0x6e, 0xfc);
5396
5397 ptr = NULL;
5398 if(ivideo->haveXGIROM) {
5399 index = (ivideo->chip == XGI_20) ? 0x35a : 0x3e6;
5400 ptr = (const u8 *)&bios[index];
5401 }
5402 for(i = 0; i < 4; i++) {
5403 setSISIDXREG(SISCR, 0x6e, 0xfc, i);
5404 reg = 0x00;
5405 for(j = 0; j < 2; j++) {
5406 regd = 0;
5407 if(ptr) {
5408 regd = le32_to_cpu(((u32 *)ptr)[regb * 8]);
5409 ptr += 4;
5410 }
5411 /* reg = 0x00; */
5412 for(k = 0; k < 16; k++) {
5413 reg &= 0xfc;
5414 if(regd & 0x01) reg |= 0x01;
5415 if(regd & 0x02) reg |= 0x02;
5416 regd >>= 2;
5417 outSISIDXREG(SISCR, 0x6f, reg);
5418 inSISIDXREG(SISCR, 0x6f, reg);
5419 inSISIDXREG(SISCR, 0x6f, reg);
5420 reg += 0x08;
5421 }
5422 }
5423 }
5424
5425 ptr = cs148;
5426 if(ivideo->haveXGIROM) {
5427 ptr = (const u8 *)&bios[0x148];
5428 }
5429 for(i = 0, j = 0; i < 2; i++, j += 8) {
5430 outSISIDXREG(SISCR, 0x80 + i, ptr[j + regb]);
5431 }
5432
5433 andSISIDXREG(SISCR, 0x89, 0x8f);
5434
5435 ptr = cs45a;
5436 if(ivideo->haveXGIROM) {
5437 index = (ivideo->chip == XGI_20) ? 0x45a : 0x4e6;
5438 ptr = (const u8 *)&bios[index];
5439 }
5440 regd = le16_to_cpu(((const u16 *)ptr)[regb]);
5441 reg = 0x80;
5442 for(i = 0; i < 5; i++) {
5443 reg &= 0xfc;
5444 if(regd & 0x01) reg |= 0x01;
5445 if(regd & 0x02) reg |= 0x02;
5446 regd >>= 2;
5447 outSISIDXREG(SISCR, 0x89, reg);
5448 inSISIDXREG(SISCR, 0x89, reg);
5449 inSISIDXREG(SISCR, 0x89, reg);
5450 reg += 0x10;
5451 }
5452
5453 v1 = 0xb5; v2 = 0x20; v3 = 0xf0; v4 = 0x13;
5454 if(ivideo->haveXGIROM) {
5455 v1 = bios[0x118 + regb];
5456 v2 = bios[0xf8 + regb];
5457 v3 = bios[0x120 + regb];
5458 v4 = bios[0x1ca];
5459 }
5460 outSISIDXREG(SISCR, 0x45, v1 & 0x0f);
5461 outSISIDXREG(SISCR, 0x99, (v1 >> 4) & 0x07);
5462 orSISIDXREG(SISCR, 0x40, v1 & 0x80);
5463 outSISIDXREG(SISCR, 0x41, v2);
5464
5465 ptr = cs170;
5466 if(ivideo->haveXGIROM) {
5467 ptr = (const u8 *)&bios[0x170];
5468 }
5469 for(i = 0, j = 0; i < 7; i++, j += 8) {
5470 outSISIDXREG(SISCR, 0x90 + i, ptr[j + regb]);
5471 }
5472
5473 outSISIDXREG(SISCR, 0x59, v3);
5474
5475 ptr = cs1a8;
5476 if(ivideo->haveXGIROM) {
5477 ptr = (const u8 *)&bios[0x1a8];
5478 }
5479 for(i = 0, j = 0; i < 3; i++, j += 8) {
5480 outSISIDXREG(SISCR, 0xc3 + i, ptr[j + regb]);
5481 }
5482
5483 ptr = cs100;
5484 if(ivideo->haveXGIROM) {
5485 ptr = (const u8 *)&bios[0x100];
5486 }
5487 for(i = 0, j = 0; i < 2; i++, j += 8) {
5488 outSISIDXREG(SISCR, 0x8a + i, ptr[j + regb]);
5489 }
5490
5491 outSISIDXREG(SISCR, 0xcf, v4);
5492
5493 outSISIDXREG(SISCR, 0x83, 0x09);
5494 outSISIDXREG(SISCR, 0x87, 0x00);
5495
5496 if(ivideo->chip == XGI_40) {
5497 if( (ivideo->revision_id == 1) ||
5498 (ivideo->revision_id == 2) ) {
5499 outSISIDXREG(SISCR, 0x8c, 0x87);
5500 }
5501 }
5502
5503 outSISIDXREG(SISSR, 0x17, 0x00);
5504 outSISIDXREG(SISSR, 0x1a, 0x87);
5505
5506 if(ivideo->chip == XGI_20) {
5507 outSISIDXREG(SISSR, 0x15, 0x00);
5508 outSISIDXREG(SISSR, 0x1c, 0x00);
5509 }
5510
5511 ramtype = 0x00; v1 = 0x10;
5512 if(ivideo->haveXGIROM) {
5513 ramtype = bios[0x62];
5514 v1 = bios[0x1d2];
5515 }
5516 if(!(ramtype & 0x80)) {
5517 if(ivideo->chip == XGI_20) {
5518 outSISIDXREG(SISCR, 0x97, v1);
5519 inSISIDXREG(SISCR, 0x97, reg);
5520 if(reg & 0x10) {
5521 ramtype = (reg & 0x01) << 1;
5522 }
5523 } else {
5524 inSISIDXREG(SISSR, 0x39, reg);
5525 ramtype = reg & 0x02;
5526 if(!(ramtype)) {
5527 inSISIDXREG(SISSR, 0x3a, reg);
5528 ramtype = (reg >> 1) & 0x01;
5529 }
5530 }
5531 }
5532 ramtype &= 0x07;
5533
5534 regb = 0; /* ! */
5535
5536 switch(ramtype) {
5537 case 0:
5538 sisfb_post_xgi_setclocks(ivideo, regb);
5539 if((ivideo->chip == XGI_20) ||
5540 (ivideo->revision_id == 1) ||
5541 (ivideo->revision_id == 2)) {
5542 v1 = cs158[regb]; v2 = cs160[regb]; v3 = cs168[regb];
5543 if(ivideo->haveXGIROM) {
5544 v1 = bios[regb + 0x158];
5545 v2 = bios[regb + 0x160];
5546 v3 = bios[regb + 0x168];
5547 }
5548 outSISIDXREG(SISCR, 0x82, v1);
5549 outSISIDXREG(SISCR, 0x85, v2);
5550 outSISIDXREG(SISCR, 0x86, v3);
5551 } else {
5552 outSISIDXREG(SISCR, 0x82, 0x88);
5553 outSISIDXREG(SISCR, 0x86, 0x00);
5554 inSISIDXREG(SISCR, 0x86, reg);
5555 outSISIDXREG(SISCR, 0x86, 0x88);
5556 inSISIDXREG(SISCR, 0x86, reg);
5557 outSISIDXREG(SISCR, 0x86, bios[regb + 0x168]);
5558 outSISIDXREG(SISCR, 0x82, 0x77);
5559 outSISIDXREG(SISCR, 0x85, 0x00);
5560 inSISIDXREG(SISCR, 0x85, reg);
5561 outSISIDXREG(SISCR, 0x85, 0x88);
5562 inSISIDXREG(SISCR, 0x85, reg);
5563 outSISIDXREG(SISCR, 0x85, bios[regb + 0x160]);
5564 outSISIDXREG(SISCR, 0x82, bios[regb + 0x158]);
5565 }
5566 if(ivideo->chip == XGI_40) {
5567 outSISIDXREG(SISCR, 0x97, 0x00);
5568 }
5569 outSISIDXREG(SISCR, 0x98, 0x01);
5570 outSISIDXREG(SISCR, 0x9a, 0x02);
5571
5572 outSISIDXREG(SISSR, 0x18, 0x01);
5573 if((ivideo->chip == XGI_20) ||
5574 (ivideo->revision_id == 2)) {
5575 outSISIDXREG(SISSR, 0x19, 0x40);
5576 } else {
5577 outSISIDXREG(SISSR, 0x19, 0x20);
5578 }
5579 outSISIDXREG(SISSR, 0x16, 0x00);
5580 outSISIDXREG(SISSR, 0x16, 0x80);
5581 if((ivideo->chip == XGI_20) || (bios[0x1cb] != 0x0c)) {
5582 sisfb_post_xgi_delay(ivideo, 0x43);
5583 sisfb_post_xgi_delay(ivideo, 0x43);
5584 sisfb_post_xgi_delay(ivideo, 0x43);
5585 outSISIDXREG(SISSR, 0x18, 0x00);
5586 if((ivideo->chip == XGI_20) ||
5587 (ivideo->revision_id == 2)) {
5588 outSISIDXREG(SISSR, 0x19, 0x40);
5589 } else {
5590 outSISIDXREG(SISSR, 0x19, 0x20);
5591 }
5592 } else if((ivideo->chip == XGI_40) && (bios[0x1cb] == 0x0c)) {
5593 /* outSISIDXREG(SISSR, 0x16, 0x0c); */ /* ? */
5594 }
5595 outSISIDXREG(SISSR, 0x16, 0x00);
5596 outSISIDXREG(SISSR, 0x16, 0x80);
5597 sisfb_post_xgi_delay(ivideo, 4);
5598 v1 = 0x31; v2 = 0x03; v3 = 0x83; v4 = 0x03; v5 = 0x83;
5599 if(ivideo->haveXGIROM) {
5600 v1 = bios[0xf0];
5601 index = (ivideo->chip == XGI_20) ? 0x4b2 : 0x53e;
5602 v2 = bios[index];
5603 v3 = bios[index + 1];
5604 v4 = bios[index + 2];
5605 v5 = bios[index + 3];
5606 }
5607 outSISIDXREG(SISSR, 0x18, v1);
5608 outSISIDXREG(SISSR, 0x19, ((ivideo->chip == XGI_20) ? 0x02 : 0x01));
5609 outSISIDXREG(SISSR, 0x16, v2);
5610 outSISIDXREG(SISSR, 0x16, v3);
5611 sisfb_post_xgi_delay(ivideo, 0x43);
5612 outSISIDXREG(SISSR, 0x1b, 0x03);
5613 sisfb_post_xgi_delay(ivideo, 0x22);
5614 outSISIDXREG(SISSR, 0x18, v1);
5615 outSISIDXREG(SISSR, 0x19, 0x00);
5616 outSISIDXREG(SISSR, 0x16, v4);
5617 outSISIDXREG(SISSR, 0x16, v5);
5618 outSISIDXREG(SISSR, 0x1b, 0x00);
5619 break;
5620 case 1:
5621 outSISIDXREG(SISCR, 0x82, 0x77);
5622 outSISIDXREG(SISCR, 0x86, 0x00);
5623 inSISIDXREG(SISCR, 0x86, reg);
5624 outSISIDXREG(SISCR, 0x86, 0x88);
5625 inSISIDXREG(SISCR, 0x86, reg);
5626 v1 = cs168[regb]; v2 = cs160[regb]; v3 = cs158[regb];
5627 if(ivideo->haveXGIROM) {
5628 v1 = bios[regb + 0x168];
5629 v2 = bios[regb + 0x160];
5630 v3 = bios[regb + 0x158];
5631 }
5632 outSISIDXREG(SISCR, 0x86, v1);
5633 outSISIDXREG(SISCR, 0x82, 0x77);
5634 outSISIDXREG(SISCR, 0x85, 0x00);
5635 inSISIDXREG(SISCR, 0x85, reg);
5636 outSISIDXREG(SISCR, 0x85, 0x88);
5637 inSISIDXREG(SISCR, 0x85, reg);
5638 outSISIDXREG(SISCR, 0x85, v2);
5639 outSISIDXREG(SISCR, 0x82, v3);
5640 outSISIDXREG(SISCR, 0x98, 0x01);
5641 outSISIDXREG(SISCR, 0x9a, 0x02);
5642
5643 outSISIDXREG(SISSR, 0x28, 0x64);
5644 outSISIDXREG(SISSR, 0x29, 0x63);
5645 sisfb_post_xgi_delay(ivideo, 15);
5646 outSISIDXREG(SISSR, 0x18, 0x00);
5647 outSISIDXREG(SISSR, 0x19, 0x20);
5648 outSISIDXREG(SISSR, 0x16, 0x00);
5649 outSISIDXREG(SISSR, 0x16, 0x80);
5650 outSISIDXREG(SISSR, 0x18, 0xc5);
5651 outSISIDXREG(SISSR, 0x19, 0x23);
5652 outSISIDXREG(SISSR, 0x16, 0x00);
5653 outSISIDXREG(SISSR, 0x16, 0x80);
5654 sisfb_post_xgi_delay(ivideo, 1);
5655 outSISIDXREG(SISCR, 0x97,0x11);
5656 sisfb_post_xgi_setclocks(ivideo, regb);
5657 sisfb_post_xgi_delay(ivideo, 0x46);
5658 outSISIDXREG(SISSR, 0x18, 0xc5);
5659 outSISIDXREG(SISSR, 0x19, 0x23);
5660 outSISIDXREG(SISSR, 0x16, 0x00);
5661 outSISIDXREG(SISSR, 0x16, 0x80);
5662 sisfb_post_xgi_delay(ivideo, 1);
5663 outSISIDXREG(SISSR, 0x1b, 0x04);
5664 sisfb_post_xgi_delay(ivideo, 1);
5665 outSISIDXREG(SISSR, 0x1b, 0x00);
5666 sisfb_post_xgi_delay(ivideo, 1);
5667 v1 = 0x31;
5668 if(ivideo->haveXGIROM) {
5669 v1 = bios[0xf0];
5670 }
5671 outSISIDXREG(SISSR, 0x18, v1);
5672 outSISIDXREG(SISSR, 0x19, 0x06);
5673 outSISIDXREG(SISSR, 0x16, 0x04);
5674 outSISIDXREG(SISSR, 0x16, 0x84);
5675 sisfb_post_xgi_delay(ivideo, 1);
5676 break;
5677 default:
5678 sisfb_post_xgi_setclocks(ivideo, regb);
5679 if((ivideo->chip == XGI_40) &&
5680 ((ivideo->revision_id == 1) ||
5681 (ivideo->revision_id == 2))) {
5682 outSISIDXREG(SISCR, 0x82, bios[regb + 0x158]);
5683 outSISIDXREG(SISCR, 0x85, bios[regb + 0x160]);
5684 outSISIDXREG(SISCR, 0x86, bios[regb + 0x168]);
5685 } else {
5686 outSISIDXREG(SISCR, 0x82, 0x88);
5687 outSISIDXREG(SISCR, 0x86, 0x00);
5688 inSISIDXREG(SISCR, 0x86, reg);
5689 outSISIDXREG(SISCR, 0x86, 0x88);
5690 outSISIDXREG(SISCR, 0x82, 0x77);
5691 outSISIDXREG(SISCR, 0x85, 0x00);
5692 inSISIDXREG(SISCR, 0x85, reg);
5693 outSISIDXREG(SISCR, 0x85, 0x88);
5694 inSISIDXREG(SISCR, 0x85, reg);
5695 v1 = cs160[regb]; v2 = cs158[regb];
5696 if(ivideo->haveXGIROM) {
5697 v1 = bios[regb + 0x160];
5698 v2 = bios[regb + 0x158];
5699 }
5700 outSISIDXREG(SISCR, 0x85, v1);
5701 outSISIDXREG(SISCR, 0x82, v2);
5702 }
5703 if(ivideo->chip == XGI_40) {
5704 outSISIDXREG(SISCR, 0x97, 0x11);
5705 }
5706 if((ivideo->chip == XGI_40) && (ivideo->revision_id == 2)) {
5707 outSISIDXREG(SISCR, 0x98, 0x01);
5708 } else {
5709 outSISIDXREG(SISCR, 0x98, 0x03);
5710 }
5711 outSISIDXREG(SISCR, 0x9a, 0x02);
5712
5713 if(ivideo->chip == XGI_40) {
5714 outSISIDXREG(SISSR, 0x18, 0x01);
5715 } else {
5716 outSISIDXREG(SISSR, 0x18, 0x00);
5717 }
5718 outSISIDXREG(SISSR, 0x19, 0x40);
5719 outSISIDXREG(SISSR, 0x16, 0x00);
5720 outSISIDXREG(SISSR, 0x16, 0x80);
5721 if((ivideo->chip == XGI_40) && (bios[0x1cb] != 0x0c)) {
5722 sisfb_post_xgi_delay(ivideo, 0x43);
5723 sisfb_post_xgi_delay(ivideo, 0x43);
5724 sisfb_post_xgi_delay(ivideo, 0x43);
5725 outSISIDXREG(SISSR, 0x18, 0x00);
5726 outSISIDXREG(SISSR, 0x19, 0x40);
5727 outSISIDXREG(SISSR, 0x16, 0x00);
5728 outSISIDXREG(SISSR, 0x16, 0x80);
5729 }
5730 sisfb_post_xgi_delay(ivideo, 4);
5731 v1 = 0x31;
5732 if(ivideo->haveXGIROM) {
5733 v1 = bios[0xf0];
5734 }
5735 outSISIDXREG(SISSR, 0x18, v1);
5736 outSISIDXREG(SISSR, 0x19, 0x01);
5737 if(ivideo->chip == XGI_40) {
5738 outSISIDXREG(SISSR, 0x16, bios[0x53e]);
5739 outSISIDXREG(SISSR, 0x16, bios[0x53f]);
5740 } else {
5741 outSISIDXREG(SISSR, 0x16, 0x05);
5742 outSISIDXREG(SISSR, 0x16, 0x85);
5743 }
5744 sisfb_post_xgi_delay(ivideo, 0x43);
5745 if(ivideo->chip == XGI_40) {
5746 outSISIDXREG(SISSR, 0x1b, 0x01);
5747 } else {
5748 outSISIDXREG(SISSR, 0x1b, 0x03);
5749 }
5750 sisfb_post_xgi_delay(ivideo, 0x22);
5751 outSISIDXREG(SISSR, 0x18, v1);
5752 outSISIDXREG(SISSR, 0x19, 0x00);
5753 if(ivideo->chip == XGI_40) {
5754 outSISIDXREG(SISSR, 0x16, bios[0x540]);
5755 outSISIDXREG(SISSR, 0x16, bios[0x541]);
5756 } else {
5757 outSISIDXREG(SISSR, 0x16, 0x05);
5758 outSISIDXREG(SISSR, 0x16, 0x85);
5759 }
5760 outSISIDXREG(SISSR, 0x1b, 0x00);
5761 }
5762
5763 regb = 0; /* ! */
5764 v1 = 0x03;
5765 if(ivideo->haveXGIROM) {
5766 v1 = bios[0x110 + regb];
5767 }
5768 outSISIDXREG(SISSR, 0x1b, v1);
5769
5770 /* RAM size */
5771 v1 = 0x00; v2 = 0x00;
5772 if(ivideo->haveXGIROM) {
5773 v1 = bios[0x62];
5774 v2 = bios[0x63];
5775 }
5776 regb = 0; /* ! */
5777 regd = 1 << regb;
5778 if((v1 & 0x40) && (v2 & regd) && ivideo->haveXGIROM) {
5779
5780 outSISIDXREG(SISSR, 0x13, bios[regb + 0xe0]);
5781 outSISIDXREG(SISSR, 0x14, bios[regb + 0xe0 + 8]);
5782
5783 } else {
5784
5785 /* Set default mode, don't clear screen */
5786 ivideo->SiS_Pr.SiS_UseOEM = FALSE;
5787 SiS_SetEnableDstn(&ivideo->SiS_Pr, FALSE);
5788 SiS_SetEnableFstn(&ivideo->SiS_Pr, FALSE);
5789 ivideo->curFSTN = ivideo->curDSTN = 0;
5790 ivideo->SiS_Pr.VideoMemorySize = 8 << 20;
5791 SiSSetMode(&ivideo->SiS_Pr, 0x2e | 0x80);
5792
5793 outSISIDXREG(SISSR, 0x05, 0x86);
5794
5795 /* Disable read-cache */
5796 andSISIDXREG(SISSR, 0x21, 0xdf);
5797 sisfb_post_xgi_ramsize(ivideo);
5798 /* Enable read-cache */
5799 orSISIDXREG(SISSR, 0x21, 0x20);
5800
5801 }
5802
5803#if 0
5804 printk(KERN_DEBUG "-----------------\n");
5805 for(i = 0; i < 0xff; i++) {
5806 inSISIDXREG(SISCR, i, reg);
5807 printk(KERN_DEBUG "CR%02x(%x) = 0x%02x\n", i, SISCR, reg);
5808 }
5809 for(i = 0; i < 0x40; i++) {
5810 inSISIDXREG(SISSR, i, reg);
5811 printk(KERN_DEBUG "SR%02x(%x) = 0x%02x\n", i, SISSR, reg);
5812 }
5813 printk(KERN_DEBUG "-----------------\n");
5814#endif
5815
5816 /* Sense CRT1 */
5817 if(ivideo->chip == XGI_20) {
5818 orSISIDXREG(SISCR, 0x32, 0x20);
5819 } else {
5820 inSISIDXREG(SISPART4, 0x00, reg);
5821 if((reg == 1) || (reg == 2)) {
5822 sisfb_sense_crt1(ivideo);
5823 } else {
5824 orSISIDXREG(SISCR, 0x32, 0x20);
5825 }
5826 }
5827
5828 /* Set default mode, don't clear screen */
5829 ivideo->SiS_Pr.SiS_UseOEM = FALSE;
5830 SiS_SetEnableDstn(&ivideo->SiS_Pr, FALSE);
5831 SiS_SetEnableFstn(&ivideo->SiS_Pr, FALSE);
5832 ivideo->curFSTN = ivideo->curDSTN = 0;
5833 SiSSetMode(&ivideo->SiS_Pr, 0x2e | 0x80);
5834
5835 outSISIDXREG(SISSR, 0x05, 0x86);
5836
5837 /* Display off */
5838 orSISIDXREG(SISSR, 0x01, 0x20);
5839
5840 /* Save mode number in CR34 */
5841 outSISIDXREG(SISCR, 0x34, 0x2e);
5842
5843 /* Let everyone know what the current mode is */
5844 ivideo->modeprechange = 0x2e;
5845
5846 if(ivideo->chip == XGI_40) {
5847 inSISIDXREG(SISCR, 0xca, reg);
5848 inSISIDXREG(SISCR, 0xcc, v1);
5849 if((reg & 0x10) && (!(v1 & 0x04))) {
5850 printk(KERN_ERR
5851 "sisfb: Please connect power to the card.\n");
5852 return 0;
5853 }
5854 }
5855
5856 return 1;
5857}
5858#endif
5859
5860static int __devinit
5861sisfb_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
5862{
5863 struct sisfb_chip_info *chipinfo = &sisfb_chip_info[ent->driver_data];
5864 struct sis_video_info *ivideo = NULL;
5865 struct fb_info *sis_fb_info = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005866 u16 reg16;
5867 u8 reg;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07005868 int i, ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005869
Thomas Winischhofer544393f2005-09-09 13:04:45 -07005870 if(sisfb_off)
5871 return -ENXIO;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005872
5873#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,3))
5874 sis_fb_info = framebuffer_alloc(sizeof(*ivideo), &pdev->dev);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07005875 if(!sis_fb_info)
5876 return -ENOMEM;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005877#else
5878 sis_fb_info = kmalloc(sizeof(*sis_fb_info) + sizeof(*ivideo), GFP_KERNEL);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07005879 if(!sis_fb_info)
5880 return -ENOMEM;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005881 memset(sis_fb_info, 0, sizeof(*sis_fb_info) + sizeof(*ivideo));
5882 sis_fb_info->par = ((char *)sis_fb_info + sizeof(*sis_fb_info));
5883#endif
5884
5885 ivideo = (struct sis_video_info *)sis_fb_info->par;
5886 ivideo->memyselfandi = sis_fb_info;
5887
Thomas Winischhofer544393f2005-09-09 13:04:45 -07005888 ivideo->sisfb_id = SISFB_ID;
5889
Linus Torvalds1da177e2005-04-16 15:20:36 -07005890 if(card_list == NULL) {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07005891 ivideo->cardnumber = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005892 } else {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07005893 struct sis_video_info *countvideo = card_list;
5894 ivideo->cardnumber = 1;
5895 while((countvideo = countvideo->next) != 0)
5896 ivideo->cardnumber++;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005897 }
5898
5899 strncpy(ivideo->myid, chipinfo->chip_name, 30);
5900
5901 ivideo->warncount = 0;
5902 ivideo->chip_id = pdev->device;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07005903 ivideo->chip_vendor = pdev->vendor;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005904 pci_read_config_byte(pdev, PCI_REVISION_ID, &ivideo->revision_id);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07005905 ivideo->SiS_Pr.ChipRevision = ivideo->revision_id;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005906 pci_read_config_word(pdev, PCI_COMMAND, &reg16);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07005907 ivideo->sisvga_enabled = reg16 & 0x01;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005908 ivideo->pcibus = pdev->bus->number;
5909 ivideo->pcislot = PCI_SLOT(pdev->devfn);
5910 ivideo->pcifunc = PCI_FUNC(pdev->devfn);
5911 ivideo->subsysvendor = pdev->subsystem_vendor;
5912 ivideo->subsysdevice = pdev->subsystem_device;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07005913#ifdef SIS_OLD_CONFIG_COMPAT
5914 ivideo->ioctl32registered = 0;
5915#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -07005916
5917#ifndef MODULE
5918 if(sisfb_mode_idx == -1) {
5919 sisfb_get_vga_mode_from_kernel();
5920 }
5921#endif
5922
5923 ivideo->chip = chipinfo->chip;
5924 ivideo->sisvga_engine = chipinfo->vgaengine;
5925 ivideo->hwcursor_size = chipinfo->hwcursor_size;
5926 ivideo->CRT2_write_enable = chipinfo->CRT2_write_enable;
5927 ivideo->mni = chipinfo->mni;
5928
5929 ivideo->detectedpdc = 0xff;
5930 ivideo->detectedpdca = 0xff;
5931 ivideo->detectedlcda = 0xff;
5932
5933 ivideo->sisfb_thismonitor.datavalid = FALSE;
5934
Thomas Winischhofer544393f2005-09-09 13:04:45 -07005935 ivideo->current_base = 0;
5936
5937 ivideo->engineok = 0;
5938
5939 ivideo->sisfb_was_boot_device = 0;
5940#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,12))
5941 if(pdev->resource[PCI_ROM_RESOURCE].flags & IORESOURCE_ROM_SHADOW) {
5942 if(ivideo->sisvga_enabled)
5943 ivideo->sisfb_was_boot_device = 1;
5944 else {
5945 printk(KERN_DEBUG "sisfb: PCI device is disabled, "
5946 "but marked as boot video device ???\n");
5947 printk(KERN_DEBUG "sisfb: I will not accept this "
5948 "as the primary VGA device\n");
5949 }
5950 }
5951#endif
5952
Linus Torvalds1da177e2005-04-16 15:20:36 -07005953 ivideo->sisfb_parm_mem = sisfb_parm_mem;
5954 ivideo->sisfb_accel = sisfb_accel;
5955 ivideo->sisfb_ypan = sisfb_ypan;
5956 ivideo->sisfb_max = sisfb_max;
5957 ivideo->sisfb_userom = sisfb_userom;
5958 ivideo->sisfb_useoem = sisfb_useoem;
5959 ivideo->sisfb_mode_idx = sisfb_mode_idx;
5960 ivideo->sisfb_parm_rate = sisfb_parm_rate;
5961 ivideo->sisfb_crt1off = sisfb_crt1off;
5962 ivideo->sisfb_forcecrt1 = sisfb_forcecrt1;
5963 ivideo->sisfb_crt2type = sisfb_crt2type;
5964 ivideo->sisfb_crt2flags = sisfb_crt2flags;
5965 /* pdc(a), scalelcd, special timing, lvdshl handled below */
5966 ivideo->sisfb_dstn = sisfb_dstn;
5967 ivideo->sisfb_fstn = sisfb_fstn;
5968 ivideo->sisfb_tvplug = sisfb_tvplug;
5969 ivideo->sisfb_tvstd = sisfb_tvstd;
5970 ivideo->tvxpos = sisfb_tvxposoffset;
5971 ivideo->tvypos = sisfb_tvyposoffset;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005972 ivideo->sisfb_nocrt2rate = sisfb_nocrt2rate;
5973#if LINUX_VERSION_CODE <= KERNEL_VERSION(2,5,0)
5974 ivideo->sisfb_inverse = sisfb_inverse;
5975#endif
5976
5977 ivideo->refresh_rate = 0;
5978 if(ivideo->sisfb_parm_rate != -1) {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07005979 ivideo->refresh_rate = ivideo->sisfb_parm_rate;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005980 }
5981
5982 ivideo->SiS_Pr.UsePanelScaler = sisfb_scalelcd;
5983 ivideo->SiS_Pr.CenterScreen = -1;
5984 ivideo->SiS_Pr.SiS_CustomT = sisfb_specialtiming;
5985 ivideo->SiS_Pr.LVDSHL = sisfb_lvdshl;
5986
5987 ivideo->SiS_Pr.SiS_Backup70xx = 0xff;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07005988 ivideo->SiS_Pr.SiS_CHOverScan = -1;
5989 ivideo->SiS_Pr.SiS_ChSW = FALSE;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005990 ivideo->SiS_Pr.SiS_UseLCDA = FALSE;
5991 ivideo->SiS_Pr.HaveEMI = FALSE;
5992 ivideo->SiS_Pr.HaveEMILCD = FALSE;
5993 ivideo->SiS_Pr.OverruleEMI = FALSE;
5994 ivideo->SiS_Pr.SiS_SensibleSR11 = FALSE;
5995 ivideo->SiS_Pr.SiS_MyCR63 = 0x63;
5996 ivideo->SiS_Pr.PDC = -1;
5997 ivideo->SiS_Pr.PDCA = -1;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07005998 ivideo->SiS_Pr.DDCPortMixup = FALSE;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005999#ifdef CONFIG_FB_SIS_315
6000 if(ivideo->chip >= SIS_330) {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006001 ivideo->SiS_Pr.SiS_MyCR63 = 0x53;
6002 if(ivideo->chip >= SIS_661) {
6003 ivideo->SiS_Pr.SiS_SensibleSR11 = TRUE;
6004 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07006005 }
6006#endif
6007
6008 memcpy(&ivideo->default_var, &my_default_var, sizeof(my_default_var));
6009
6010 pci_set_drvdata(pdev, ivideo);
6011
6012 /* Patch special cases */
6013 if((ivideo->nbridge = sisfb_get_northbridge(ivideo->chip))) {
6014 switch(ivideo->nbridge->device) {
6015#ifdef CONFIG_FB_SIS_300
6016 case PCI_DEVICE_ID_SI_730:
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006017 ivideo->chip = SIS_730;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006018 strcpy(ivideo->myid, "SiS 730");
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006019 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006020#endif
6021#ifdef CONFIG_FB_SIS_315
6022 case PCI_DEVICE_ID_SI_651:
6023 /* ivideo->chip is ok */
6024 strcpy(ivideo->myid, "SiS 651");
6025 break;
6026 case PCI_DEVICE_ID_SI_740:
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006027 ivideo->chip = SIS_740;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006028 strcpy(ivideo->myid, "SiS 740");
6029 break;
6030 case PCI_DEVICE_ID_SI_661:
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006031 ivideo->chip = SIS_661;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006032 strcpy(ivideo->myid, "SiS 661");
6033 break;
6034 case PCI_DEVICE_ID_SI_741:
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006035 ivideo->chip = SIS_741;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006036 strcpy(ivideo->myid, "SiS 741");
6037 break;
6038 case PCI_DEVICE_ID_SI_760:
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006039 ivideo->chip = SIS_760;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006040 strcpy(ivideo->myid, "SiS 760");
6041 break;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006042 case PCI_DEVICE_ID_SI_761:
6043 ivideo->chip = SIS_761;
6044 strcpy(ivideo->myid, "SiS 761");
6045 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006046#endif
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006047 default:
6048 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006049 }
6050 }
6051
6052#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
6053 strcpy(sis_fb_info->modename, ivideo->myid);
6054#endif
6055
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006056 ivideo->SiS_Pr.ChipType = ivideo->chip;
6057
6058 ivideo->SiS_Pr.ivideo = (void *)ivideo;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006059
6060#ifdef CONFIG_FB_SIS_315
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006061 if((ivideo->SiS_Pr.ChipType == SIS_315PRO) ||
6062 (ivideo->SiS_Pr.ChipType == SIS_315)) {
6063 ivideo->SiS_Pr.ChipType = SIS_315H;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006064 }
6065#endif
6066
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006067 if(!ivideo->sisvga_enabled) {
6068 if(pci_enable_device(pdev)) {
6069 if(ivideo->nbridge) SIS_PCI_PUT_DEVICE(ivideo->nbridge);
6070 pci_set_drvdata(pdev, NULL);
6071 kfree(sis_fb_info);
6072 return -EIO;
6073 }
6074 }
6075
Linus Torvalds1da177e2005-04-16 15:20:36 -07006076 ivideo->video_base = pci_resource_start(pdev, 0);
6077 ivideo->mmio_base = pci_resource_start(pdev, 1);
6078 ivideo->mmio_size = pci_resource_len(pdev, 1);
6079 ivideo->SiS_Pr.RelIO = pci_resource_start(pdev, 2) + 0x30;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006080 ivideo->SiS_Pr.IOAddress = ivideo->vga_base = ivideo->SiS_Pr.RelIO;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006081
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006082 SiSRegInit(&ivideo->SiS_Pr, ivideo->SiS_Pr.IOAddress);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006083
6084#ifdef CONFIG_FB_SIS_300
6085 /* Find PCI systems for Chrontel/GPIO communication setup */
6086 if(ivideo->chip == SIS_630) {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006087 i = 0;
6088 do {
6089 if(mychswtable[i].subsysVendor == ivideo->subsysvendor &&
6090 mychswtable[i].subsysCard == ivideo->subsysdevice) {
6091 ivideo->SiS_Pr.SiS_ChSW = TRUE;
6092 printk(KERN_DEBUG "sisfb: Identified [%s %s] "
6093 "requiring Chrontel/GPIO setup\n",
6094 mychswtable[i].vendorName,
6095 mychswtable[i].cardName);
6096 ivideo->lpcdev = SIS_PCI_GET_DEVICE(PCI_VENDOR_ID_SI, 0x0008, NULL);
6097 break;
6098 }
6099 i++;
6100 } while(mychswtable[i].subsysVendor != 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006101 }
6102#endif
6103
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006104#ifdef CONFIG_FB_SIS_315
6105 if((ivideo->chip == SIS_760) && (ivideo->nbridge)) {
6106 ivideo->lpcdev = SIS_PCI_GET_SLOT(ivideo->nbridge->bus, (2 << 3));
6107 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07006108#endif
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006109
6110 outSISIDXREG(SISSR, 0x05, 0x86);
6111
6112 if( (!ivideo->sisvga_enabled)
6113#if !defined(__i386__) && !defined(__x86_64__)
6114 || (sisfb_resetcard)
6115#endif
6116 ) {
6117 for(i = 0x30; i <= 0x3f; i++) {
6118 outSISIDXREG(SISCR, i, 0x00);
6119 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07006120 }
6121
6122 /* Find out about current video mode */
6123 ivideo->modeprechange = 0x03;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006124 inSISIDXREG(SISCR, 0x34, reg);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006125 if(reg & 0x7f) {
6126 ivideo->modeprechange = reg & 0x7f;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006127 } else if(ivideo->sisvga_enabled) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07006128#if defined(__i386__) || defined(__x86_64__)
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006129 unsigned char SIS_IOTYPE2 *tt = ioremap(0x400, 0x100);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006130 if(tt) {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006131 ivideo->modeprechange = readb(tt + 0x49);
6132 iounmap(tt);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006133 }
6134#endif
6135 }
6136
6137#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
6138#ifdef MODULE
6139 if((reg & 0x80) && (reg != 0xff)) {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006140 if((sisbios_mode[ivideo->sisfb_mode_idx].mode_no[ivideo->mni])
6141 != 0xFF) {
6142 printk(KERN_INFO "sisfb: Cannot initialize display mode, "
6143 "X server is active\n");
6144 ret = -EBUSY;
6145 goto error_4;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006146 }
6147 }
6148#endif
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006149#endif
6150
6151 /* Search and copy ROM image */
6152 ivideo->bios_abase = NULL;
6153 ivideo->SiS_Pr.VirtualRomBase = NULL;
6154 ivideo->SiS_Pr.UseROM = FALSE;
6155 ivideo->haveXGIROM = ivideo->SiS_Pr.SiS_XGIROM = FALSE;
6156 if(ivideo->sisfb_userom) {
6157 ivideo->SiS_Pr.VirtualRomBase = sisfb_find_rom(pdev);
6158 ivideo->bios_abase = ivideo->SiS_Pr.VirtualRomBase;
6159 ivideo->SiS_Pr.UseROM = (ivideo->SiS_Pr.VirtualRomBase) ? TRUE : FALSE;
6160 printk(KERN_INFO "sisfb: Video ROM %sfound\n",
6161 ivideo->SiS_Pr.UseROM ? "" : "not ");
6162 if((ivideo->SiS_Pr.UseROM) && (ivideo->chip >= XGI_20)) {
6163 ivideo->SiS_Pr.UseROM = FALSE;
6164 ivideo->haveXGIROM = ivideo->SiS_Pr.SiS_XGIROM = TRUE;
6165 if( (ivideo->revision_id == 2) &&
6166 (!(ivideo->bios_abase[0x1d1] & 0x01)) ) {
6167 ivideo->SiS_Pr.DDCPortMixup = TRUE;
6168 }
6169 }
6170 } else {
6171 printk(KERN_INFO "sisfb: Video ROM usage disabled\n");
6172 }
6173
6174 /* Find systems for special custom timing */
6175 if(ivideo->SiS_Pr.SiS_CustomT == CUT_NONE) {
6176 sisfb_detect_custom_timing(ivideo);
6177 }
6178
6179 /* POST card in case this has not been done by the BIOS */
6180 if( (!ivideo->sisvga_enabled)
6181#if !defined(__i386__) && !defined(__x86_64__)
6182 || (sisfb_resetcard)
6183#endif
6184 ) {
6185#ifdef CONFIG_FB_SIS_300
6186 if(ivideo->sisvga_engine == SIS_300_VGA) {
6187 if(ivideo->chip == SIS_300) {
6188 sisfb_post_sis300(pdev);
6189 ivideo->sisfb_can_post = 1;
6190 }
6191 }
6192#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -07006193
6194#ifdef CONFIG_FB_SIS_315
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006195 if(ivideo->sisvga_engine == SIS_315_VGA) {
6196 int result = 1;
6197 /* if((ivideo->chip == SIS_315H) ||
Linus Torvalds1da177e2005-04-16 15:20:36 -07006198 (ivideo->chip == SIS_315) ||
6199 (ivideo->chip == SIS_315PRO) ||
6200 (ivideo->chip == SIS_330)) {
6201 sisfb_post_sis315330(pdev);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006202 } else */ if(ivideo->chip == XGI_20) {
6203 result = sisfb_post_xgi(pdev);
6204 ivideo->sisfb_can_post = 1;
6205 } else if((ivideo->chip == XGI_40) && ivideo->haveXGIROM) {
6206 result = sisfb_post_xgi(pdev);
6207 ivideo->sisfb_can_post = 1;
6208 } else {
6209 printk(KERN_INFO "sisfb: Card is not "
6210 "POSTed and sisfb can't do this either.\n");
6211 }
6212 if(!result) {
6213 printk(KERN_ERR "sisfb: Failed to POST card\n");
6214 ret = -ENODEV;
6215 goto error_3;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006216 }
6217 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07006218#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -07006219 }
6220
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006221 ivideo->sisfb_card_posted = 1;
6222
6223 /* Find out about RAM size */
6224 if(sisfb_get_dram_size(ivideo)) {
6225 printk(KERN_INFO "sisfb: Fatal error: Unable to determine VRAM size.\n");
6226 ret = -ENODEV;
6227 goto error_3;
6228 }
6229
6230
6231 /* Enable PCI addressing and MMIO */
Linus Torvalds1da177e2005-04-16 15:20:36 -07006232 if((ivideo->sisfb_mode_idx < 0) ||
6233 ((sisbios_mode[ivideo->sisfb_mode_idx].mode_no[ivideo->mni]) != 0xFF)) {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006234 /* Enable PCI_LINEAR_ADDRESSING and MMIO_ENABLE */
6235 orSISIDXREG(SISSR, IND_SIS_PCI_ADDRESS_SET, (SIS_PCI_ADDR_ENABLE | SIS_MEM_MAP_IO_ENABLE));
6236 /* Enable 2D accelerator engine */
6237 orSISIDXREG(SISSR, IND_SIS_MODULE_ENABLE, SIS_ENABLE_2D);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006238 }
6239
6240 if(sisfb_pdc != 0xff) {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006241 if(ivideo->sisvga_engine == SIS_300_VGA)
6242 sisfb_pdc &= 0x3c;
6243 else
6244 sisfb_pdc &= 0x1f;
6245 ivideo->SiS_Pr.PDC = sisfb_pdc;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006246 }
6247#ifdef CONFIG_FB_SIS_315
6248 if(ivideo->sisvga_engine == SIS_315_VGA) {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006249 if(sisfb_pdca != 0xff)
6250 ivideo->SiS_Pr.PDCA = sisfb_pdca & 0x1f;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006251 }
6252#endif
6253
6254 if(!request_mem_region(ivideo->video_base, ivideo->video_size, "sisfb FB")) {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006255 printk(KERN_ERR "sisfb: Fatal error: Unable to reserve %dMB framebuffer memory\n",
6256 (int)(ivideo->video_size >> 20));
Linus Torvalds1da177e2005-04-16 15:20:36 -07006257 printk(KERN_ERR "sisfb: Is there another framebuffer driver active?\n");
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006258 ret = -ENODEV;
6259 goto error_3;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006260 }
6261
6262 if(!request_mem_region(ivideo->mmio_base, ivideo->mmio_size, "sisfb MMIO")) {
6263 printk(KERN_ERR "sisfb: Fatal error: Unable to reserve MMIO region\n");
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006264 ret = -ENODEV;
6265 goto error_2;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006266 }
6267
6268 ivideo->video_vbase = ioremap(ivideo->video_base, ivideo->video_size);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006269 ivideo->SiS_Pr.VideoMemoryAddress = ivideo->video_vbase;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006270 if(!ivideo->video_vbase) {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006271 printk(KERN_ERR "sisfb: Fatal error: Unable to map framebuffer memory\n");
6272 ret = -ENODEV;
6273 goto error_1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006274 }
6275
6276 ivideo->mmio_vbase = ioremap(ivideo->mmio_base, ivideo->mmio_size);
6277 if(!ivideo->mmio_vbase) {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006278 printk(KERN_ERR "sisfb: Fatal error: Unable to map MMIO region\n");
6279 ret = -ENODEV;
6280error_0: iounmap(ivideo->video_vbase);
6281error_1: release_mem_region(ivideo->video_base, ivideo->video_size);
6282error_2: release_mem_region(ivideo->mmio_base, ivideo->mmio_size);
6283error_3: vfree(ivideo->bios_abase);
6284#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
6285error_4:
6286#endif
6287 if(ivideo->lpcdev)
6288 SIS_PCI_PUT_DEVICE(ivideo->lpcdev);
6289 if(ivideo->nbridge)
6290 SIS_PCI_PUT_DEVICE(ivideo->nbridge);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006291 pci_set_drvdata(pdev, NULL);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006292 if(!ivideo->sisvga_enabled)
6293 pci_disable_device(pdev);
6294 kfree(sis_fb_info);
6295 return ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006296 }
6297
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006298 printk(KERN_INFO "sisfb: Video RAM at 0x%lx, mapped to 0x%lx, size %ldk\n",
6299 ivideo->video_base, (unsigned long)ivideo->video_vbase, ivideo->video_size / 1024);
6300
6301 if(ivideo->video_offset) {
6302 printk(KERN_INFO "sisfb: Viewport offset %ldk\n",
6303 ivideo->video_offset / 1024);
6304 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07006305
6306 printk(KERN_INFO "sisfb: MMIO at 0x%lx, mapped to 0x%lx, size %ldk\n",
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006307 ivideo->mmio_base, (unsigned long)ivideo->mmio_vbase, ivideo->mmio_size / 1024);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006308
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006309
6310 /* Determine the size of the command queue */
6311 if(ivideo->sisvga_engine == SIS_300_VGA) {
6312 ivideo->cmdQueueSize = TURBO_QUEUE_AREA_SIZE;
6313 } else {
6314 if(ivideo->chip == XGI_20) {
6315 ivideo->cmdQueueSize = COMMAND_QUEUE_AREA_SIZE_Z7;
6316 } else {
6317 ivideo->cmdQueueSize = COMMAND_QUEUE_AREA_SIZE;
6318 }
6319 }
6320
6321 /* Engines are no longer initialized here; this is
6322 * now done after the first mode-switch (if the
6323 * submitted var has its acceleration flags set).
6324 */
6325
6326 /* Calculate the base of the (unused) hw cursor */
6327 ivideo->hwcursor_vbase = ivideo->video_vbase
6328 + ivideo->video_size
6329 - ivideo->cmdQueueSize
6330 - ivideo->hwcursor_size;
6331 ivideo->caps |= HW_CURSOR_CAP;
6332
6333 /* Initialize offscreen memory manager */
Linus Torvalds1da177e2005-04-16 15:20:36 -07006334 if((ivideo->havenoheap = sisfb_heap_init(ivideo))) {
6335 printk(KERN_WARNING "sisfb: Failed to initialize offscreen memory heap\n");
6336 }
6337
6338 /* Used for clearing the screen only, therefore respect our mem limit */
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006339 ivideo->SiS_Pr.VideoMemoryAddress += ivideo->video_offset;
6340 ivideo->SiS_Pr.VideoMemorySize = ivideo->sisfb_mem;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006341
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006342 ivideo->mtrr = -1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006343
6344 ivideo->vbflags = 0;
6345 ivideo->lcddefmodeidx = DEFAULT_LCDMODE;
6346 ivideo->tvdefmodeidx = DEFAULT_TVMODE;
6347 ivideo->defmodeidx = DEFAULT_MODE;
6348
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006349 ivideo->newrom = 0;
6350 if(ivideo->chip < XGI_20) {
6351 if(ivideo->bios_abase) {
6352 ivideo->newrom = SiSDetermineROMLayout661(&ivideo->SiS_Pr);
6353 }
6354 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07006355
6356 if((ivideo->sisfb_mode_idx < 0) ||
6357 ((sisbios_mode[ivideo->sisfb_mode_idx].mode_no[ivideo->mni]) != 0xFF)) {
6358
6359 sisfb_sense_crt1(ivideo);
6360
6361 sisfb_get_VB_type(ivideo);
6362
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006363 if(ivideo->vbflags2 & VB2_VIDEOBRIDGE) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07006364 sisfb_detect_VB_connect(ivideo);
6365 }
6366
6367 ivideo->currentvbflags = ivideo->vbflags & (VB_VIDEOBRIDGE | TV_STANDARD);
6368
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006369 /* Decide on which CRT2 device to use */
6370 if(ivideo->vbflags2 & VB2_VIDEOBRIDGE) {
6371 if(ivideo->sisfb_crt2type != -1) {
6372 if((ivideo->sisfb_crt2type == CRT2_LCD) &&
6373 (ivideo->vbflags & CRT2_LCD)) {
6374 ivideo->currentvbflags |= CRT2_LCD;
6375 } else if(ivideo->sisfb_crt2type != CRT2_LCD) {
6376 ivideo->currentvbflags |= ivideo->sisfb_crt2type;
6377 }
6378 } else {
6379 /* Chrontel 700x TV detection often unreliable, therefore
6380 * use a different default order on such machines
6381 */
6382 if((ivideo->sisvga_engine == SIS_300_VGA) &&
6383 (ivideo->vbflags2 & VB2_CHRONTEL)) {
6384 if(ivideo->vbflags & CRT2_LCD)
6385 ivideo->currentvbflags |= CRT2_LCD;
6386 else if(ivideo->vbflags & CRT2_TV)
6387 ivideo->currentvbflags |= CRT2_TV;
6388 else if(ivideo->vbflags & CRT2_VGA)
6389 ivideo->currentvbflags |= CRT2_VGA;
6390 } else {
6391 if(ivideo->vbflags & CRT2_TV)
6392 ivideo->currentvbflags |= CRT2_TV;
6393 else if(ivideo->vbflags & CRT2_LCD)
6394 ivideo->currentvbflags |= CRT2_LCD;
6395 else if(ivideo->vbflags & CRT2_VGA)
6396 ivideo->currentvbflags |= CRT2_VGA;
6397 }
6398 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07006399 }
6400
6401 if(ivideo->vbflags & CRT2_LCD) {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006402 sisfb_detect_lcd_type(ivideo);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006403 }
6404
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006405 sisfb_save_pdc_emi(ivideo);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006406
6407 if(!ivideo->sisfb_crt1off) {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006408 sisfb_handle_ddc(ivideo, &ivideo->sisfb_thismonitor, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006409 } else {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006410 if((ivideo->vbflags2 & VB2_SISTMDSBRIDGE) &&
6411 (ivideo->vbflags & (CRT2_VGA | CRT2_LCD))) {
6412 sisfb_handle_ddc(ivideo, &ivideo->sisfb_thismonitor, 1);
6413 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07006414 }
6415
6416 if(ivideo->sisfb_mode_idx >= 0) {
6417 int bu = ivideo->sisfb_mode_idx;
6418 ivideo->sisfb_mode_idx = sisfb_validate_mode(ivideo,
6419 ivideo->sisfb_mode_idx, ivideo->currentvbflags);
6420 if(bu != ivideo->sisfb_mode_idx) {
6421 printk(KERN_ERR "Mode %dx%dx%d failed validation\n",
6422 sisbios_mode[bu].xres,
6423 sisbios_mode[bu].yres,
6424 sisbios_mode[bu].bpp);
6425 }
6426 }
6427
6428 if(ivideo->sisfb_mode_idx < 0) {
6429 switch(ivideo->currentvbflags & VB_DISPTYPE_DISP2) {
6430 case CRT2_LCD:
6431 ivideo->sisfb_mode_idx = ivideo->lcddefmodeidx;
6432 break;
6433 case CRT2_TV:
6434 ivideo->sisfb_mode_idx = ivideo->tvdefmodeidx;
6435 break;
6436 default:
6437 ivideo->sisfb_mode_idx = ivideo->defmodeidx;
6438 break;
6439 }
6440 }
6441
6442 ivideo->mode_no = sisbios_mode[ivideo->sisfb_mode_idx].mode_no[ivideo->mni];
6443
6444 if(ivideo->refresh_rate != 0) {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006445 sisfb_search_refresh_rate(ivideo, ivideo->refresh_rate,
6446 ivideo->sisfb_mode_idx);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006447 }
6448
6449 if(ivideo->rate_idx == 0) {
6450 ivideo->rate_idx = sisbios_mode[ivideo->sisfb_mode_idx].rate_idx;
6451 ivideo->refresh_rate = 60;
6452 }
6453
6454 if(ivideo->sisfb_thismonitor.datavalid) {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006455 if(!sisfb_verify_rate(ivideo, &ivideo->sisfb_thismonitor,
6456 ivideo->sisfb_mode_idx,
6457 ivideo->rate_idx,
6458 ivideo->refresh_rate)) {
6459 printk(KERN_INFO "sisfb: WARNING: Refresh rate "
6460 "exceeds monitor specs!\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07006461 }
6462 }
6463
6464 ivideo->video_bpp = sisbios_mode[ivideo->sisfb_mode_idx].bpp;
6465 ivideo->video_width = sisbios_mode[ivideo->sisfb_mode_idx].xres;
6466 ivideo->video_height = sisbios_mode[ivideo->sisfb_mode_idx].yres;
6467
6468 sisfb_set_vparms(ivideo);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006469
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006470#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
6471
6472 /* ---------------- For 2.4: Now switch the mode ------------------ */
6473
6474 printk(KERN_INFO "sisfb: Setting mode %dx%dx%d (%dHz)\n",
6475 ivideo->video_width, ivideo->video_height, ivideo->video_bpp,
Linus Torvalds1da177e2005-04-16 15:20:36 -07006476 ivideo->refresh_rate);
6477
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006478 /* Determine whether or not acceleration is to be
6479 * used. Need to know before pre/post_set_mode()
6480 */
6481 ivideo->accel = 0;
6482 ivideo->default_var.accel_flags &= ~FB_ACCELF_TEXT;
6483 if(ivideo->sisfb_accel) {
6484 ivideo->accel = -1;
6485 ivideo->default_var.accel_flags |= FB_ACCELF_TEXT;
6486 }
6487
6488 /* Now switch the mode */
Linus Torvalds1da177e2005-04-16 15:20:36 -07006489 sisfb_pre_setmode(ivideo);
6490
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006491 if(SiSSetMode(&ivideo->SiS_Pr, ivideo->mode_no) == 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07006492 printk(KERN_ERR "sisfb: Fatal error: Setting mode[0x%x] failed\n",
6493 ivideo->mode_no);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006494 ret = -EINVAL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006495 iounmap(ivideo->mmio_vbase);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006496 goto error_0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006497 }
6498
6499 outSISIDXREG(SISSR, IND_SIS_PASSWORD, SIS_PASSWORD);
6500
6501 sisfb_post_setmode(ivideo);
6502
6503 /* Maximize regardless of sisfb_max at startup */
6504 ivideo->default_var.yres_virtual = 32767;
6505
6506 /* Force reset of x virtual in crtc_to_var */
6507 ivideo->default_var.xres_virtual = 0;
6508
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006509 /* Copy mode timing to var */
Linus Torvalds1da177e2005-04-16 15:20:36 -07006510 sisfb_crtc_to_var(ivideo, &ivideo->default_var);
6511
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006512 /* Find out about screen pitch */
Linus Torvalds1da177e2005-04-16 15:20:36 -07006513 sisfb_calc_pitch(ivideo, &ivideo->default_var);
6514 sisfb_set_pitch(ivideo);
6515
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006516 /* Init the accelerator (does nothing currently) */
Linus Torvalds1da177e2005-04-16 15:20:36 -07006517 sisfb_initaccel(ivideo);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006518
6519 /* Init some fbinfo entries */
Linus Torvalds1da177e2005-04-16 15:20:36 -07006520 sis_fb_info->node = -1;
6521 sis_fb_info->flags = FBINFO_FLAG_DEFAULT;
6522 sis_fb_info->fbops = &sisfb_ops;
6523 sis_fb_info->disp = &ivideo->sis_disp;
6524 sis_fb_info->blank = &sisfb_blank;
6525 sis_fb_info->switch_con = &sisfb_switch;
6526 sis_fb_info->updatevar = &sisfb_update_var;
6527 sis_fb_info->changevar = NULL;
6528 strcpy(sis_fb_info->fontname, sisfb_fontname);
6529
6530 sisfb_set_disp(-1, &ivideo->default_var, sis_fb_info);
6531
6532#else /* --------- For 2.6: Setup a somewhat sane default var ------------ */
6533
6534 printk(KERN_INFO "sisfb: Default mode is %dx%dx%d (%dHz)\n",
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006535 ivideo->video_width, ivideo->video_height, ivideo->video_bpp,
Linus Torvalds1da177e2005-04-16 15:20:36 -07006536 ivideo->refresh_rate);
6537
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006538 /* Set up the default var according to chosen default display mode */
Linus Torvalds1da177e2005-04-16 15:20:36 -07006539 ivideo->default_var.xres = ivideo->default_var.xres_virtual = ivideo->video_width;
6540 ivideo->default_var.yres = ivideo->default_var.yres_virtual = ivideo->video_height;
6541 ivideo->default_var.bits_per_pixel = ivideo->video_bpp;
6542
6543 sisfb_bpp_to_var(ivideo, &ivideo->default_var);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006544
Linus Torvalds1da177e2005-04-16 15:20:36 -07006545 ivideo->default_var.pixclock = (u32) (1000000000 /
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006546 sisfb_mode_rate_to_dclock(&ivideo->SiS_Pr, ivideo->mode_no, ivideo->rate_idx));
6547
6548 if(sisfb_mode_rate_to_ddata(&ivideo->SiS_Pr, ivideo->mode_no,
6549 ivideo->rate_idx, &ivideo->default_var)) {
6550 if((ivideo->default_var.vmode & FB_VMODE_MASK) == FB_VMODE_DOUBLE) {
6551 ivideo->default_var.pixclock <<= 1;
6552 }
6553 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07006554
6555 if(ivideo->sisfb_ypan) {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006556 /* Maximize regardless of sisfb_max at startup */
6557 ivideo->default_var.yres_virtual =
6558 sisfb_calc_maxyres(ivideo, &ivideo->default_var);
6559 if(ivideo->default_var.yres_virtual < ivideo->default_var.yres) {
6560 ivideo->default_var.yres_virtual = ivideo->default_var.yres;
6561 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07006562 }
6563
6564 sisfb_calc_pitch(ivideo, &ivideo->default_var);
6565
6566 ivideo->accel = 0;
6567 if(ivideo->sisfb_accel) {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006568 ivideo->accel = -1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006569#ifdef STUPID_ACCELF_TEXT_SHIT
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006570 ivideo->default_var.accel_flags |= FB_ACCELF_TEXT;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006571#endif
6572 }
6573 sisfb_initaccel(ivideo);
6574
6575#if defined(FBINFO_HWACCEL_DISABLED) && defined(FBINFO_HWACCEL_XPAN)
6576 sis_fb_info->flags = FBINFO_DEFAULT |
6577 FBINFO_HWACCEL_YPAN |
6578 FBINFO_HWACCEL_XPAN |
6579 FBINFO_HWACCEL_COPYAREA |
6580 FBINFO_HWACCEL_FILLRECT |
6581 ((ivideo->accel) ? 0 : FBINFO_HWACCEL_DISABLED);
6582#else
6583 sis_fb_info->flags = FBINFO_FLAG_DEFAULT;
6584#endif
6585 sis_fb_info->var = ivideo->default_var;
6586 sis_fb_info->fix = ivideo->sisfb_fix;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006587 sis_fb_info->screen_base = ivideo->video_vbase + ivideo->video_offset;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006588 sis_fb_info->fbops = &sisfb_ops;
6589
6590 sisfb_get_fix(&sis_fb_info->fix, -1, sis_fb_info);
6591 sis_fb_info->pseudo_palette = ivideo->pseudo_palette;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006592
Linus Torvalds1da177e2005-04-16 15:20:36 -07006593 fb_alloc_cmap(&sis_fb_info->cmap, 256 , 0);
6594#endif /* 2.6 */
6595
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006596 printk(KERN_DEBUG "sisfb: Initial vbflags 0x%x\n", (int)ivideo->vbflags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006597
6598#ifdef CONFIG_MTRR
6599 ivideo->mtrr = mtrr_add(ivideo->video_base, ivideo->video_size,
6600 MTRR_TYPE_WRCOMB, 1);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006601 if(ivideo->mtrr < 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07006602 printk(KERN_DEBUG "sisfb: Failed to add MTRRs\n");
6603 }
6604#endif
6605
6606#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
6607 vc_resize_con(1, 1, 0);
6608#endif
6609
6610 if(register_framebuffer(sis_fb_info) < 0) {
6611 printk(KERN_ERR "sisfb: Fatal error: Failed to register framebuffer\n");
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006612 ret = -EINVAL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006613 iounmap(ivideo->mmio_vbase);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006614 goto error_0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006615 }
6616
6617 ivideo->registered = 1;
6618
6619 /* Enlist us */
6620 ivideo->next = card_list;
6621 card_list = ivideo;
6622
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006623#ifdef SIS_OLD_CONFIG_COMPAT
6624 {
6625 int ret;
6626 /* Our ioctls are all "32/64bit compatible" */
6627 ret = register_ioctl32_conversion(FBIO_ALLOC, NULL);
6628 ret |= register_ioctl32_conversion(FBIO_FREE, NULL);
6629 ret |= register_ioctl32_conversion(FBIOGET_VBLANK, NULL);
6630 ret |= register_ioctl32_conversion(SISFB_GET_INFO_SIZE, NULL);
6631 ret |= register_ioctl32_conversion(SISFB_GET_INFO, NULL);
6632 ret |= register_ioctl32_conversion(SISFB_GET_TVPOSOFFSET, NULL);
6633 ret |= register_ioctl32_conversion(SISFB_SET_TVPOSOFFSET, NULL);
6634 ret |= register_ioctl32_conversion(SISFB_SET_LOCK, NULL);
6635 ret |= register_ioctl32_conversion(SISFB_GET_VBRSTATUS, NULL);
6636 ret |= register_ioctl32_conversion(SISFB_GET_AUTOMAXIMIZE, NULL);
6637 ret |= register_ioctl32_conversion(SISFB_SET_AUTOMAXIMIZE, NULL);
6638 ret |= register_ioctl32_conversion(SISFB_COMMAND, NULL);
6639 if(ret)
6640 printk(KERN_ERR
6641 "sisfb: Error registering ioctl32 translations\n");
6642 else
6643 ivideo->ioctl32registered = 1;
6644 }
6645#endif
6646
Linus Torvalds1da177e2005-04-16 15:20:36 -07006647 printk(KERN_INFO "sisfb: 2D acceleration is %s, y-panning %s\n",
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006648 ivideo->sisfb_accel ? "enabled" : "disabled",
6649 ivideo->sisfb_ypan ?
6650 (ivideo->sisfb_max ? "enabled (auto-max)" :
6651 "enabled (no auto-max)") :
6652 "disabled");
Linus Torvalds1da177e2005-04-16 15:20:36 -07006653
6654
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006655 printk(KERN_INFO "fb%d: %s frame buffer device version %d.%d.%d\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07006656#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006657 GET_FB_IDX(sis_fb_info->node),
Linus Torvalds1da177e2005-04-16 15:20:36 -07006658#else
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006659 sis_fb_info->node,
Linus Torvalds1da177e2005-04-16 15:20:36 -07006660#endif
6661 ivideo->myid, VER_MAJOR, VER_MINOR, VER_LEVEL);
6662
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006663 printk(KERN_INFO "sisfb: Copyright (C) 2001-2005 Thomas Winischhofer\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07006664
6665 } /* if mode = "none" */
6666
6667 return 0;
6668}
6669
6670/*****************************************************/
6671/* PCI DEVICE HANDLING */
6672/*****************************************************/
6673
6674static void __devexit sisfb_remove(struct pci_dev *pdev)
6675{
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006676 struct sis_video_info *ivideo = pci_get_drvdata(pdev);
6677 struct fb_info *sis_fb_info = ivideo->memyselfandi;
6678 int registered = ivideo->registered;
6679 int modechanged = ivideo->modechanged;
6680
6681#ifdef SIS_OLD_CONFIG_COMPAT
6682 if(ivideo->ioctl32registered) {
6683 int ret;
6684 ret = unregister_ioctl32_conversion(FBIO_ALLOC);
6685 ret |= unregister_ioctl32_conversion(FBIO_FREE);
6686 ret |= unregister_ioctl32_conversion(FBIOGET_VBLANK);
6687 ret |= unregister_ioctl32_conversion(SISFB_GET_INFO_SIZE);
6688 ret |= unregister_ioctl32_conversion(SISFB_GET_INFO);
6689 ret |= unregister_ioctl32_conversion(SISFB_GET_TVPOSOFFSET);
6690 ret |= unregister_ioctl32_conversion(SISFB_SET_TVPOSOFFSET);
6691 ret |= unregister_ioctl32_conversion(SISFB_SET_LOCK);
6692 ret |= unregister_ioctl32_conversion(SISFB_GET_VBRSTATUS);
6693 ret |= unregister_ioctl32_conversion(SISFB_GET_AUTOMAXIMIZE);
6694 ret |= unregister_ioctl32_conversion(SISFB_SET_AUTOMAXIMIZE);
6695 ret |= unregister_ioctl32_conversion(SISFB_COMMAND);
6696 if(ret)
6697 printk(KERN_ERR
6698 "sisfb: Error unregistering ioctl32 translations\n");
6699 }
6700#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -07006701
6702 /* Unmap */
Linus Torvalds1da177e2005-04-16 15:20:36 -07006703 iounmap(ivideo->mmio_vbase);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006704 iounmap(ivideo->video_vbase);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006705
6706 /* Release mem regions */
6707 release_mem_region(ivideo->video_base, ivideo->video_size);
6708 release_mem_region(ivideo->mmio_base, ivideo->mmio_size);
6709
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006710 vfree(ivideo->bios_abase);
6711
6712 if(ivideo->lpcdev)
6713 SIS_PCI_PUT_DEVICE(ivideo->lpcdev);
6714
6715 if(ivideo->nbridge)
6716 SIS_PCI_PUT_DEVICE(ivideo->nbridge);
6717
Linus Torvalds1da177e2005-04-16 15:20:36 -07006718#ifdef CONFIG_MTRR
6719 /* Release MTRR region */
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006720 if(ivideo->mtrr >= 0)
Linus Torvalds1da177e2005-04-16 15:20:36 -07006721 mtrr_del(ivideo->mtrr, ivideo->video_base, ivideo->video_size);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006722#endif
6723
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006724 pci_set_drvdata(pdev, NULL);
6725
6726 /* If device was disabled when starting, disable
6727 * it when quitting.
6728 */
6729 if(!ivideo->sisvga_enabled)
6730 pci_disable_device(pdev);
6731
Linus Torvalds1da177e2005-04-16 15:20:36 -07006732 /* Unregister the framebuffer */
6733 if(ivideo->registered) {
6734 unregister_framebuffer(sis_fb_info);
6735#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,3))
6736 framebuffer_release(sis_fb_info);
6737#else
6738 kfree(sis_fb_info);
6739#endif
6740 }
6741
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006742 /* OK, our ivideo is gone for good from here. */
Linus Torvalds1da177e2005-04-16 15:20:36 -07006743
6744 /* TODO: Restore the initial mode
6745 * This sounds easy but is as good as impossible
6746 * on many machines with SiS chip and video bridge
6747 * since text modes are always set up differently
6748 * from machine to machine. Depends on the type
6749 * of integration between chipset and bridge.
6750 */
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006751 if(registered && modechanged)
6752 printk(KERN_INFO
6753 "sisfb: Restoring of text mode not supported yet\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07006754};
6755
6756static struct pci_driver sisfb_driver = {
6757 .name = "sisfb",
6758 .id_table = sisfb_pci_table,
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006759 .probe = sisfb_probe,
Linus Torvalds1da177e2005-04-16 15:20:36 -07006760 .remove = __devexit_p(sisfb_remove)
6761};
6762
6763SISINITSTATIC int __init sisfb_init(void)
6764{
6765#if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,8)
6766#ifndef MODULE
6767 char *options = NULL;
6768
6769 if(fb_get_options("sisfb", &options))
6770 return -ENODEV;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006771
Linus Torvalds1da177e2005-04-16 15:20:36 -07006772 sisfb_setup(options);
6773#endif
6774#endif
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006775 return pci_register_driver(&sisfb_driver);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006776}
6777
6778#if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,8)
6779#ifndef MODULE
6780module_init(sisfb_init);
6781#endif
6782#endif
6783
6784/*****************************************************/
6785/* MODULE */
6786/*****************************************************/
6787
6788#ifdef MODULE
6789
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006790static char *mode = NULL;
6791static int vesa = -1;
6792static unsigned int rate = 0;
6793static unsigned int crt1off = 1;
6794static unsigned int mem = 0;
6795static char *forcecrt2type = NULL;
6796static int forcecrt1 = -1;
6797static int pdc = -1;
6798static int pdc1 = -1;
6799static int noaccel = -1;
6800static int noypan = -1;
6801static int nomax = -1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006802#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006803static int inverse = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006804#endif
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006805static int userom = -1;
6806static int useoem = -1;
6807static char *tvstandard = NULL;
6808static int nocrt2rate = 0;
6809static int scalelcd = -1;
6810static char *specialtiming = NULL;
6811static int lvdshl = -1;
6812static int tvxposoffset = 0, tvyposoffset = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006813#if !defined(__i386__) && !defined(__x86_64__)
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006814static int resetcard = 0;
6815static int videoram = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006816#endif
6817
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006818static int __init sisfb_init_module(void)
6819{
6820 sisfb_setdefaultparms();
6821
6822 if(rate)
6823 sisfb_parm_rate = rate;
6824
6825 if((scalelcd == 0) || (scalelcd == 1))
6826 sisfb_scalelcd = scalelcd ^ 1;
6827
6828 /* Need to check crt2 type first for fstn/dstn */
6829
6830 if(forcecrt2type)
6831 sisfb_search_crt2type(forcecrt2type);
6832
6833 if(tvstandard)
6834 sisfb_search_tvstd(tvstandard);
6835
6836 if(mode)
6837 sisfb_search_mode(mode, FALSE);
6838 else if(vesa != -1)
6839 sisfb_search_vesamode(vesa, FALSE);
6840
6841 sisfb_crt1off = (crt1off == 0) ? 1 : 0;
6842
6843 sisfb_forcecrt1 = forcecrt1;
6844 if(forcecrt1 == 1)
6845 sisfb_crt1off = 0;
6846 else if(forcecrt1 == 0)
6847 sisfb_crt1off = 1;
6848
6849 if(noaccel == 1)
6850 sisfb_accel = 0;
6851 else if(noaccel == 0)
6852 sisfb_accel = 1;
6853
6854 if(noypan == 1)
6855 sisfb_ypan = 0;
6856 else if(noypan == 0)
6857 sisfb_ypan = 1;
6858
6859 if(nomax == 1)
6860 sisfb_max = 0;
6861 else if(nomax == 0)
6862 sisfb_max = 1;
6863
6864#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
6865 if(inverse) sisfb_inverse = 1;
6866#endif
6867
6868 if(mem)
6869 sisfb_parm_mem = mem;
6870
6871 if(userom != -1)
6872 sisfb_userom = userom;
6873
6874 if(useoem != -1)
6875 sisfb_useoem = useoem;
6876
6877 if(pdc != -1)
6878 sisfb_pdc = (pdc & 0x7f);
6879
6880 if(pdc1 != -1)
6881 sisfb_pdca = (pdc1 & 0x1f);
6882
6883 sisfb_nocrt2rate = nocrt2rate;
6884
6885 if(specialtiming)
6886 sisfb_search_specialtiming(specialtiming);
6887
6888 if((lvdshl >= 0) && (lvdshl <= 3))
6889 sisfb_lvdshl = lvdshl;
6890
6891 sisfb_tvxposoffset = tvxposoffset;
6892 sisfb_tvyposoffset = tvyposoffset;
6893
6894#if !defined(__i386__) && !defined(__x86_64__)
6895 sisfb_resetcard = (resetcard) ? 1 : 0;
6896 if(videoram)
6897 sisfb_videoram = videoram;
6898#endif
6899
6900 return sisfb_init();
6901}
6902
6903static void __exit sisfb_remove_module(void)
6904{
6905 pci_unregister_driver(&sisfb_driver);
6906 printk(KERN_DEBUG "sisfb: Module unloaded\n");
6907}
6908
6909module_init(sisfb_init_module);
6910module_exit(sisfb_remove_module);
6911
6912MODULE_DESCRIPTION("SiS 300/540/630/730/315/55x/65x/661/74x/330/76x/34x, XGI V3XT/V5/V8/Z7 framebuffer device driver");
Linus Torvalds1da177e2005-04-16 15:20:36 -07006913MODULE_LICENSE("GPL");
6914MODULE_AUTHOR("Thomas Winischhofer <thomas@winischhofer.net>, Others");
6915
6916#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
6917MODULE_PARM(mem, "i");
6918MODULE_PARM(noaccel, "i");
6919MODULE_PARM(noypan, "i");
6920MODULE_PARM(nomax, "i");
6921MODULE_PARM(userom, "i");
6922MODULE_PARM(useoem, "i");
6923MODULE_PARM(mode, "s");
6924MODULE_PARM(vesa, "i");
6925MODULE_PARM(rate, "i");
6926MODULE_PARM(forcecrt1, "i");
6927MODULE_PARM(forcecrt2type, "s");
6928MODULE_PARM(scalelcd, "i");
6929MODULE_PARM(pdc, "i");
6930MODULE_PARM(pdc1, "i");
6931MODULE_PARM(specialtiming, "s");
6932MODULE_PARM(lvdshl, "i");
6933MODULE_PARM(tvstandard, "s");
6934MODULE_PARM(tvxposoffset, "i");
6935MODULE_PARM(tvyposoffset, "i");
Linus Torvalds1da177e2005-04-16 15:20:36 -07006936MODULE_PARM(nocrt2rate, "i");
6937MODULE_PARM(inverse, "i");
6938#if !defined(__i386__) && !defined(__x86_64__)
6939MODULE_PARM(resetcard, "i");
6940MODULE_PARM(videoram, "i");
6941#endif
6942#endif
6943
6944#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0)
6945module_param(mem, int, 0);
6946module_param(noaccel, int, 0);
6947module_param(noypan, int, 0);
6948module_param(nomax, int, 0);
6949module_param(userom, int, 0);
6950module_param(useoem, int, 0);
6951module_param(mode, charp, 0);
6952module_param(vesa, int, 0);
6953module_param(rate, int, 0);
6954module_param(forcecrt1, int, 0);
6955module_param(forcecrt2type, charp, 0);
6956module_param(scalelcd, int, 0);
6957module_param(pdc, int, 0);
6958module_param(pdc1, int, 0);
6959module_param(specialtiming, charp, 0);
6960module_param(lvdshl, int, 0);
6961module_param(tvstandard, charp, 0);
6962module_param(tvxposoffset, int, 0);
6963module_param(tvyposoffset, int, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006964module_param(nocrt2rate, int, 0);
6965#if !defined(__i386__) && !defined(__x86_64__)
6966module_param(resetcard, int, 0);
6967module_param(videoram, int, 0);
6968#endif
6969#endif
6970
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006971#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
Linus Torvalds1da177e2005-04-16 15:20:36 -07006972MODULE_PARM_DESC(mem,
6973 "\nDetermines the beginning of the video memory heap in KB. This heap is used\n"
6974 "for video RAM management for eg. DRM/DRI. On 300 series, the default depends\n"
6975 "on the amount of video RAM available. If 8MB of video RAM or less is available,\n"
6976 "the heap starts at 4096KB, if between 8 and 16MB are available at 8192KB,\n"
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006977 "otherwise at 12288KB. On 315/330/340 series, the heap size is 32KB by default.\n"
Linus Torvalds1da177e2005-04-16 15:20:36 -07006978 "The value is to be specified without 'KB' and must match the MaxXFBMem setting\n"
6979 "for XFree86 4.x/X.org 6.7 and later.\n");
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006980#else
6981MODULE_PARM_DESC(mem,
6982 "\nDetermines the beginning of the video memory heap in KB. This heap is used\n"
6983 "for video RAM management for eg. DRM/DRI. On 300 series, the default depends\n"
6984 "on the amount of video RAM available. If 8MB of video RAM or less is available,\n"
6985 "the heap starts at 4096KB, if between 8 and 16MB are available at 8192KB,\n"
6986 "otherwise at 12288KB. On 315/330/340 series, the heap size is 32KB by default.\n"
6987 "The value is to be specified without 'KB'.\n");
6988#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -07006989
6990MODULE_PARM_DESC(noaccel,
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006991 "\nIf set to anything other than 0, 2D acceleration will be disabled.\n"
Linus Torvalds1da177e2005-04-16 15:20:36 -07006992 "(default: 0)\n");
6993
6994MODULE_PARM_DESC(noypan,
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006995 "\nIf set to anything other than 0, y-panning will be disabled and scrolling\n"
6996 "will be performed by redrawing the screen. (default: 0)\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07006997
6998MODULE_PARM_DESC(nomax,
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006999 "\nIf y-panning is enabled, sisfb will by default use the entire available video\n"
Linus Torvalds1da177e2005-04-16 15:20:36 -07007000 "memory for the virtual screen in order to optimize scrolling performance. If\n"
7001 "this is set to anything other than 0, sisfb will not do this and thereby \n"
7002 "enable the user to positively specify a virtual Y size of the screen using\n"
7003 "fbset. (default: 0)\n");
7004
7005#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
7006MODULE_PARM_DESC(mode,
Thomas Winischhofer544393f2005-09-09 13:04:45 -07007007 "\nSelects the desired display mode in the format [X]x[Y]x[Depth], eg.\n"
7008 "1024x768x16. Other formats supported include XxY-Depth and\n"
7009 "XxY-Depth@Rate. If the parameter is only one (decimal or hexadecimal)\n"
Linus Torvalds1da177e2005-04-16 15:20:36 -07007010 "number, it will be interpreted as a VESA mode number. (default: none if\n"
7011 "sisfb is a module; this leaves the console untouched and the driver will\n"
7012 "only do the video memory management for eg. DRM/DRI; 800x600x8 if sisfb\n"
7013 "is in the kernel)\n");
7014MODULE_PARM_DESC(vesa,
Thomas Winischhofer544393f2005-09-09 13:04:45 -07007015 "\nSelects the desired display mode by VESA defined mode number, eg. 0x117\n"
7016 "(default: 0x0000 if sisfb is a module; this leaves the console untouched\n"
Linus Torvalds1da177e2005-04-16 15:20:36 -07007017 "and the driver will only do the video memory management for eg. DRM/DRI;\n"
7018 "0x0103 if sisfb is in the kernel)\n");
7019#endif
7020
7021#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0)
7022MODULE_PARM_DESC(mode,
Thomas Winischhofer544393f2005-09-09 13:04:45 -07007023 "\nSelects the desired default display mode in the format XxYxDepth,\n"
7024 "eg. 1024x768x16. Other formats supported include XxY-Depth and\n"
Linus Torvalds1da177e2005-04-16 15:20:36 -07007025 "XxY-Depth@Rate. If the parameter is only one (decimal or hexadecimal)\n"
7026 "number, it will be interpreted as a VESA mode number. (default: 800x600x8)\n");
7027
7028MODULE_PARM_DESC(vesa,
Thomas Winischhofer544393f2005-09-09 13:04:45 -07007029 "\nSelects the desired default display mode by VESA defined mode number, eg.\n"
7030 "0x117 (default: 0x0103)\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07007031#endif
7032
7033MODULE_PARM_DESC(rate,
7034 "\nSelects the desired vertical refresh rate for CRT1 (external VGA) in Hz.\n"
7035 "If the mode is specified in the format XxY-Depth@Rate, this parameter\n"
7036 "will be ignored (default: 60)\n");
7037
7038MODULE_PARM_DESC(forcecrt1,
7039 "\nNormally, the driver autodetects whether or not CRT1 (external VGA) is \n"
7040 "connected. With this option, the detection can be overridden (1=CRT1 ON,\n"
7041 "0=CRT1 OFF) (default: [autodetected])\n");
7042
7043MODULE_PARM_DESC(forcecrt2type,
7044 "\nIf this option is omitted, the driver autodetects CRT2 output devices, such as\n"
7045 "LCD, TV or secondary VGA. With this option, this autodetection can be\n"
7046 "overridden. Possible parameters are LCD, TV, VGA or NONE. NONE disables CRT2.\n"
7047 "On systems with a SiS video bridge, parameters SVIDEO, COMPOSITE or SCART can\n"
7048 "be used instead of TV to override the TV detection. Furthermore, on systems\n"
7049 "with a SiS video bridge, SVIDEO+COMPOSITE, HIVISION, YPBPR480I, YPBPR480P,\n"
7050 "YPBPR720P and YPBPR1080I are understood. However, whether or not these work\n"
7051 "depends on the very hardware in use. (default: [autodetected])\n");
7052
7053MODULE_PARM_DESC(scalelcd,
7054 "\nSetting this to 1 will force the driver to scale the LCD image to the panel's\n"
7055 "native resolution. Setting it to 0 will disable scaling; LVDS panels will\n"
7056 "show black bars around the image, TMDS panels will probably do the scaling\n"
7057 "themselves. Default: 1 on LVDS panels, 0 on TMDS panels\n");
7058
7059MODULE_PARM_DESC(pdc,
Thomas Winischhofer544393f2005-09-09 13:04:45 -07007060 "\nThis is for manually selecting the LCD panel delay compensation. The driver\n"
Linus Torvalds1da177e2005-04-16 15:20:36 -07007061 "should detect this correctly in most cases; however, sometimes this is not\n"
7062 "possible. If you see 'small waves' on the LCD, try setting this to 4, 32 or 24\n"
Thomas Winischhofer544393f2005-09-09 13:04:45 -07007063 "on a 300 series chipset; 6 on other chipsets. If the problem persists, try\n"
7064 "other values (on 300 series: between 4 and 60 in steps of 4; otherwise: any\n"
7065 "value from 0 to 31). (default: autodetected, if LCD is active during start)\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07007066
7067#ifdef CONFIG_FB_SIS_315
7068MODULE_PARM_DESC(pdc1,
Thomas Winischhofer544393f2005-09-09 13:04:45 -07007069 "\nThis is same as pdc, but for LCD-via CRT1. Hence, this is for the 315/330/340\n"
Linus Torvalds1da177e2005-04-16 15:20:36 -07007070 "series only. (default: autodetected if LCD is in LCD-via-CRT1 mode during\n"
7071 "startup) - Note: currently, this has no effect because LCD-via-CRT1 is not\n"
7072 "implemented yet.\n");
7073#endif
7074
7075MODULE_PARM_DESC(specialtiming,
7076 "\nPlease refer to documentation for more information on this option.\n");
7077
7078MODULE_PARM_DESC(lvdshl,
7079 "\nPlease refer to documentation for more information on this option.\n");
7080
7081MODULE_PARM_DESC(tvstandard,
7082 "\nThis allows overriding the BIOS default for the TV standard. Valid choices are\n"
7083 "pal, ntsc, palm and paln. (default: [auto; pal or ntsc only])\n");
7084
7085MODULE_PARM_DESC(tvxposoffset,
7086 "\nRelocate TV output horizontally. Possible parameters: -32 through 32.\n"
7087 "Default: 0\n");
7088
7089MODULE_PARM_DESC(tvyposoffset,
7090 "\nRelocate TV output vertically. Possible parameters: -32 through 32.\n"
7091 "Default: 0\n");
7092
Linus Torvalds1da177e2005-04-16 15:20:36 -07007093MODULE_PARM_DESC(nocrt2rate,
7094 "\nSetting this to 1 will force the driver to use the default refresh rate for\n"
7095 "CRT2 if CRT2 type is VGA. (default: 0, use same rate as CRT1)\n");
7096
7097#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
7098MODULE_PARM_DESC(inverse,
Thomas Winischhofer544393f2005-09-09 13:04:45 -07007099 "\nSetting this to anything but 0 should invert the display colors, but this\n"
Linus Torvalds1da177e2005-04-16 15:20:36 -07007100 "does not seem to work. (default: 0)\n");
7101#endif
7102
7103#if !defined(__i386__) && !defined(__x86_64__)
7104#ifdef CONFIG_FB_SIS_300
7105MODULE_PARM_DESC(resetcard,
7106 "\nSet this to 1 in order to reset (POST) the card on non-x86 machines where\n"
Thomas Winischhofer544393f2005-09-09 13:04:45 -07007107 "the BIOS did not POST the card (only supported for SiS 300/305 and XGI cards\n"
7108 "currently). Default: 0\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07007109
7110MODULE_PARM_DESC(videoram,
7111 "\nSet this to the amount of video RAM (in kilobyte) the card has. Required on\n"
7112 "some non-x86 architectures where the memory auto detection fails. Only\n"
Thomas Winischhofer544393f2005-09-09 13:04:45 -07007113 "relevant if resetcard is set, too. SiS300/305 only. Default: [auto-detect]\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07007114#endif
7115#endif
7116
Linus Torvalds1da177e2005-04-16 15:20:36 -07007117#endif /* /MODULE */
7118
Thomas Winischhofer544393f2005-09-09 13:04:45 -07007119/* _GPL only for new symbols. */
Linus Torvalds1da177e2005-04-16 15:20:36 -07007120EXPORT_SYMBOL(sis_malloc);
7121EXPORT_SYMBOL(sis_free);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07007122EXPORT_SYMBOL_GPL(sis_malloc_new);
7123EXPORT_SYMBOL_GPL(sis_free_new);
7124
Linus Torvalds1da177e2005-04-16 15:20:36 -07007125
7126