blob: 8adf5bf91eee075716b12d95d5eb26ef6c0312bc [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
36#include <linux/config.h>
37#include <linux/version.h>
38#include <linux/module.h>
39#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0)
40#include <linux/moduleparam.h>
41#endif
42#include <linux/kernel.h>
43#include <linux/smp_lock.h>
44#include <linux/spinlock.h>
45#include <linux/errno.h>
46#include <linux/string.h>
47#include <linux/mm.h>
48#include <linux/tty.h>
49#include <linux/slab.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070050#include <linux/fb.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070051#include <linux/selection.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070052#include <linux/ioport.h>
53#include <linux/init.h>
54#include <linux/pci.h>
55#include <linux/vmalloc.h>
Thomas Winischhofer544393f2005-09-09 13:04:45 -070056#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
Linus Torvalds1da177e2005-04-16 15:20:36 -070057#include <linux/vt_kern.h>
Thomas Winischhofer544393f2005-09-09 13:04:45 -070058#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -070059#include <linux/capability.h>
60#include <linux/fs.h>
61#include <linux/types.h>
62#include <asm/uaccess.h>
63#include <asm/io.h>
64#ifdef CONFIG_MTRR
65#include <asm/mtrr.h>
66#endif
67
68#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
69#include <video/fbcon.h>
70#include <video/fbcon-cfb8.h>
71#include <video/fbcon-cfb16.h>
72#include <video/fbcon-cfb24.h>
73#include <video/fbcon-cfb32.h>
74#endif
75
76#include "sis.h"
77#include "sis_main.h"
78
79#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0)
80#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,3)
81#error "This version of sisfb requires at least 2.6.3"
82#endif
83#endif
84
85#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
86#ifdef FBCON_HAS_CFB8
87extern struct display_switch fbcon_sis8;
88#endif
89#ifdef FBCON_HAS_CFB16
90extern struct display_switch fbcon_sis16;
91#endif
92#ifdef FBCON_HAS_CFB32
93extern struct display_switch fbcon_sis32;
94#endif
95#endif
96
Thomas Winischhofer544393f2005-09-09 13:04:45 -070097static void sisfb_handle_command(struct sis_video_info *ivideo,
98 struct sisfb_cmd *sisfb_command);
99
Linus Torvalds1da177e2005-04-16 15:20:36 -0700100/* ------------------ Internal helper routines ----------------- */
101
102static void __init
103sisfb_setdefaultparms(void)
104{
Thomas Winischhofer544393f2005-09-09 13:04:45 -0700105 sisfb_off = 0;
106 sisfb_parm_mem = 0;
107 sisfb_accel = -1;
108 sisfb_ypan = -1;
109 sisfb_max = -1;
110 sisfb_userom = -1;
111 sisfb_useoem = -1;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700112#ifdef MODULE
113 /* Module: "None" for 2.4, default mode for 2.5+ */
114#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0)
Thomas Winischhofer544393f2005-09-09 13:04:45 -0700115 sisfb_mode_idx = -1;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700116#else
Thomas Winischhofer544393f2005-09-09 13:04:45 -0700117 sisfb_mode_idx = MODE_INDEX_NONE;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700118#endif
119#else
120 /* Static: Default mode */
Thomas Winischhofer544393f2005-09-09 13:04:45 -0700121 sisfb_mode_idx = -1;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700122#endif
Thomas Winischhofer544393f2005-09-09 13:04:45 -0700123 sisfb_parm_rate = -1;
124 sisfb_crt1off = 0;
125 sisfb_forcecrt1 = -1;
126 sisfb_crt2type = -1;
127 sisfb_crt2flags = 0;
128 sisfb_pdc = 0xff;
129 sisfb_pdca = 0xff;
130 sisfb_scalelcd = -1;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700131 sisfb_specialtiming = CUT_NONE;
Thomas Winischhofer544393f2005-09-09 13:04:45 -0700132 sisfb_lvdshl = -1;
133 sisfb_dstn = 0;
134 sisfb_fstn = 0;
135 sisfb_tvplug = -1;
136 sisfb_tvstd = -1;
137 sisfb_tvxposoffset = 0;
138 sisfb_tvyposoffset = 0;
139 sisfb_nocrt2rate = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700140#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
Thomas Winischhofer544393f2005-09-09 13:04:45 -0700141 sisfb_inverse = 0;
142 sisfb_fontname[0] = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700143#endif
144#if !defined(__i386__) && !defined(__x86_64__)
Thomas Winischhofer544393f2005-09-09 13:04:45 -0700145 sisfb_resetcard = 0;
146 sisfb_videoram = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700147#endif
148}
149
Thomas Winischhofer544393f2005-09-09 13:04:45 -0700150/* ------------- Parameter parsing -------------- */
151
Linus Torvalds1da177e2005-04-16 15:20:36 -0700152static void __devinit
153sisfb_search_vesamode(unsigned int vesamode, BOOLEAN quiet)
154{
155 int i = 0, j = 0;
156
Thomas Winischhofer544393f2005-09-09 13:04:45 -0700157 /* We don't know the hardware specs yet and there is no ivideo */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700158
159 if(vesamode == 0) {
160#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
161 sisfb_mode_idx = MODE_INDEX_NONE;
162#else
Thomas Winischhofer544393f2005-09-09 13:04:45 -0700163 if(!quiet)
164 printk(KERN_ERR "sisfb: Invalid mode. Using default.\n");
165
Linus Torvalds1da177e2005-04-16 15:20:36 -0700166 sisfb_mode_idx = DEFAULT_MODE;
167#endif
168 return;
169 }
170
171 vesamode &= 0x1dff; /* Clean VESA mode number from other flags */
172
173 while(sisbios_mode[i++].mode_no[0] != 0) {
174 if( (sisbios_mode[i-1].vesa_mode_no_1 == vesamode) ||
175 (sisbios_mode[i-1].vesa_mode_no_2 == vesamode) ) {
Thomas Winischhofer544393f2005-09-09 13:04:45 -0700176 if(sisfb_fstn) {
177 if(sisbios_mode[i-1].mode_no[1] == 0x50 ||
178 sisbios_mode[i-1].mode_no[1] == 0x56 ||
179 sisbios_mode[i-1].mode_no[1] == 0x53)
180 continue;
181 } else {
182 if(sisbios_mode[i-1].mode_no[1] == 0x5a ||
183 sisbios_mode[i-1].mode_no[1] == 0x5b)
184 continue;
185 }
186 sisfb_mode_idx = i - 1;
187 j = 1;
188 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700189 }
190 }
Thomas Winischhofer544393f2005-09-09 13:04:45 -0700191 if((!j) && !quiet)
192 printk(KERN_ERR "sisfb: Invalid VESA mode 0x%x'\n", vesamode);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700193}
194
Thomas Winischhofer544393f2005-09-09 13:04:45 -0700195static void __devinit
Linus Torvalds1da177e2005-04-16 15:20:36 -0700196sisfb_search_mode(char *name, BOOLEAN quiet)
197{
Linus Torvalds1da177e2005-04-16 15:20:36 -0700198 unsigned int j = 0, xres = 0, yres = 0, depth = 0, rate = 0;
Thomas Winischhofer544393f2005-09-09 13:04:45 -0700199 int i = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700200 char strbuf[16], strbuf1[20];
201 char *nameptr = name;
202
Thomas Winischhofer544393f2005-09-09 13:04:45 -0700203 /* We don't know the hardware specs yet and there is no ivideo */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700204
205 if(name == NULL) {
Thomas Winischhofer544393f2005-09-09 13:04:45 -0700206 if(!quiet)
207 printk(KERN_ERR "sisfb: Internal error, using default mode.\n");
208
209 sisfb_mode_idx = DEFAULT_MODE;
210 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700211 }
212
213#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0)
Thomas Winischhofer544393f2005-09-09 13:04:45 -0700214 if(!strnicmp(name, sisbios_mode[MODE_INDEX_NONE].name, strlen(name))) {
215 if(!quiet)
216 printk(KERN_ERR "sisfb: Mode 'none' not supported anymore. Using default.\n");
217
218 sisfb_mode_idx = DEFAULT_MODE;
219 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700220 }
221#endif
222 if(strlen(name) <= 19) {
Thomas Winischhofer544393f2005-09-09 13:04:45 -0700223 strcpy(strbuf1, name);
224 for(i = 0; i < strlen(strbuf1); i++) {
225 if(strbuf1[i] < '0' || strbuf1[i] > '9') strbuf1[i] = ' ';
226 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700227
Thomas Winischhofer544393f2005-09-09 13:04:45 -0700228 /* This does some fuzzy mode naming detection */
229 if(sscanf(strbuf1, "%u %u %u %u", &xres, &yres, &depth, &rate) == 4) {
230 if((rate <= 32) || (depth > 32)) {
231 j = rate; rate = depth; depth = j;
232 }
233 sprintf(strbuf, "%ux%ux%u", xres, yres, depth);
234 nameptr = strbuf;
235 sisfb_parm_rate = rate;
236 } else if(sscanf(strbuf1, "%u %u %u", &xres, &yres, &depth) == 3) {
237 sprintf(strbuf, "%ux%ux%u", xres, yres, depth);
238 nameptr = strbuf;
239 } else {
240 xres = 0;
241 if((sscanf(strbuf1, "%u %u", &xres, &yres) == 2) && (xres != 0)) {
242 sprintf(strbuf, "%ux%ux8", xres, yres);
243 nameptr = strbuf;
244 } else {
245 sisfb_search_vesamode(simple_strtoul(name, NULL, 0), quiet);
246 return;
247 }
248 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700249 }
250
251 i = 0; j = 0;
252 while(sisbios_mode[i].mode_no[0] != 0) {
253 if(!strnicmp(nameptr, sisbios_mode[i++].name, strlen(nameptr))) {
Thomas Winischhofer544393f2005-09-09 13:04:45 -0700254 if(sisfb_fstn) {
255 if(sisbios_mode[i-1].mode_no[1] == 0x50 ||
256 sisbios_mode[i-1].mode_no[1] == 0x56 ||
257 sisbios_mode[i-1].mode_no[1] == 0x53)
258 continue;
259 } else {
260 if(sisbios_mode[i-1].mode_no[1] == 0x5a ||
261 sisbios_mode[i-1].mode_no[1] == 0x5b)
262 continue;
263 }
264 sisfb_mode_idx = i - 1;
265 j = 1;
266 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700267 }
268 }
Thomas Winischhofer544393f2005-09-09 13:04:45 -0700269
270 if((!j) && !quiet)
271 printk(KERN_ERR "sisfb: Invalid mode '%s'\n", nameptr);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700272}
273
274#ifndef MODULE
275static void __devinit
276sisfb_get_vga_mode_from_kernel(void)
277{
278#if (defined(__i386__) || defined(__x86_64__)) && defined(CONFIG_VIDEO_SELECT)
Thomas Winischhofer544393f2005-09-09 13:04:45 -0700279 char mymode[32];
Linus Torvalds1da177e2005-04-16 15:20:36 -0700280 int mydepth = screen_info.lfb_depth;
281
282 if(screen_info.orig_video_isVGA != VIDEO_TYPE_VLFB) return;
283
284 if( (screen_info.lfb_width >= 320) && (screen_info.lfb_width <= 2048) &&
285 (screen_info.lfb_height >= 200) && (screen_info.lfb_height <= 1536) &&
286 (mydepth >= 8) && (mydepth <= 32) ) {
287
Thomas Winischhofer544393f2005-09-09 13:04:45 -0700288 if(mydepth == 24) mydepth = 32;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700289
Thomas Winischhofer544393f2005-09-09 13:04:45 -0700290 sprintf(mymode, "%ux%ux%u", screen_info.lfb_width,
291 screen_info.lfb_height,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700292 mydepth);
293
Thomas Winischhofer544393f2005-09-09 13:04:45 -0700294 printk(KERN_DEBUG
295 "sisfb: Using vga mode %s pre-set by kernel as default\n",
296 mymode);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700297
Thomas Winischhofer544393f2005-09-09 13:04:45 -0700298 sisfb_search_mode(mymode, TRUE);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700299 }
300#endif
301 return;
302}
303#endif
304
305static void __init
306sisfb_search_crt2type(const char *name)
307{
308 int i = 0;
309
Thomas Winischhofer544393f2005-09-09 13:04:45 -0700310 /* We don't know the hardware specs yet and there is no ivideo */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700311
312 if(name == NULL) return;
313
314 while(sis_crt2type[i].type_no != -1) {
Thomas Winischhofer544393f2005-09-09 13:04:45 -0700315 if(!strnicmp(name, sis_crt2type[i].name, strlen(sis_crt2type[i].name))) {
316 sisfb_crt2type = sis_crt2type[i].type_no;
317 sisfb_tvplug = sis_crt2type[i].tvplug_no;
318 sisfb_crt2flags = sis_crt2type[i].flags;
319 break;
320 }
321 i++;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700322 }
323
324 sisfb_dstn = (sisfb_crt2flags & FL_550_DSTN) ? 1 : 0;
325 sisfb_fstn = (sisfb_crt2flags & FL_550_FSTN) ? 1 : 0;
326
Thomas Winischhofer544393f2005-09-09 13:04:45 -0700327 if(sisfb_crt2type < 0)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700328 printk(KERN_ERR "sisfb: Invalid CRT2 type: %s\n", name);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700329}
330
331static void __init
332sisfb_search_tvstd(const char *name)
333{
334 int i = 0;
335
Thomas Winischhofer544393f2005-09-09 13:04:45 -0700336 /* We don't know the hardware specs yet and there is no ivideo */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700337
Thomas Winischhofer544393f2005-09-09 13:04:45 -0700338 if(name == NULL)
339 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700340
341 while(sis_tvtype[i].type_no != -1) {
Thomas Winischhofer544393f2005-09-09 13:04:45 -0700342 if(!strnicmp(name, sis_tvtype[i].name, strlen(sis_tvtype[i].name))) {
343 sisfb_tvstd = sis_tvtype[i].type_no;
344 break;
345 }
346 i++;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700347 }
348}
349
350static void __init
351sisfb_search_specialtiming(const char *name)
352{
353 int i = 0;
354 BOOLEAN found = FALSE;
355
Thomas Winischhofer544393f2005-09-09 13:04:45 -0700356 /* We don't know the hardware specs yet and there is no ivideo */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700357
Thomas Winischhofer544393f2005-09-09 13:04:45 -0700358 if(name == NULL)
359 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700360
361 if(!strnicmp(name, "none", 4)) {
Thomas Winischhofer544393f2005-09-09 13:04:45 -0700362 sisfb_specialtiming = CUT_FORCENONE;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700363 printk(KERN_DEBUG "sisfb: Special timing disabled\n");
364 } else {
Thomas Winischhofer544393f2005-09-09 13:04:45 -0700365 while(mycustomttable[i].chipID != 0) {
366 if(!strnicmp(name,mycustomttable[i].optionName,
367 strlen(mycustomttable[i].optionName))) {
368 sisfb_specialtiming = mycustomttable[i].SpecialID;
369 found = TRUE;
370 printk(KERN_INFO "sisfb: Special timing for %s %s forced (\"%s\")\n",
371 mycustomttable[i].vendorName,
372 mycustomttable[i].cardName,
373 mycustomttable[i].optionName);
374 break;
375 }
376 i++;
377 }
378 if(!found) {
379 printk(KERN_WARNING "sisfb: Invalid SpecialTiming parameter, valid are:");
380 printk(KERN_WARNING "\t\"none\" (to disable special timings)\n");
381 i = 0;
382 while(mycustomttable[i].chipID != 0) {
383 printk(KERN_WARNING "\t\"%s\" (for %s %s)\n",
384 mycustomttable[i].optionName,
385 mycustomttable[i].vendorName,
386 mycustomttable[i].cardName);
387 i++;
388 }
389 }
390 }
391}
392
393/* ----------- Various detection routines ----------- */
394
395static void __devinit
396sisfb_detect_custom_timing(struct sis_video_info *ivideo)
397{
398 unsigned char *biosver = NULL;
399 unsigned char *biosdate = NULL;
400 BOOLEAN footprint;
401 u32 chksum = 0;
402 int i, j;
403
404 if(ivideo->SiS_Pr.UseROM) {
405 biosver = ivideo->SiS_Pr.VirtualRomBase + 0x06;
406 biosdate = ivideo->SiS_Pr.VirtualRomBase + 0x2c;
407 for(i = 0; i < 32768; i++)
408 chksum += ivideo->SiS_Pr.VirtualRomBase[i];
409 }
410
411 i = 0;
412 do {
413 if( (mycustomttable[i].chipID == ivideo->chip) &&
414 ((!strlen(mycustomttable[i].biosversion)) ||
415 (ivideo->SiS_Pr.UseROM &&
416 (!strncmp(mycustomttable[i].biosversion, biosver,
417 strlen(mycustomttable[i].biosversion))))) &&
418 ((!strlen(mycustomttable[i].biosdate)) ||
419 (ivideo->SiS_Pr.UseROM &&
420 (!strncmp(mycustomttable[i].biosdate, biosdate,
421 strlen(mycustomttable[i].biosdate))))) &&
422 ((!mycustomttable[i].bioschksum) ||
423 (ivideo->SiS_Pr.UseROM &&
424 (mycustomttable[i].bioschksum == chksum))) &&
425 (mycustomttable[i].pcisubsysvendor == ivideo->subsysvendor) &&
426 (mycustomttable[i].pcisubsyscard == ivideo->subsysdevice) ) {
427 footprint = TRUE;
428 for(j = 0; j < 5; j++) {
429 if(mycustomttable[i].biosFootprintAddr[j]) {
430 if(ivideo->SiS_Pr.UseROM) {
431 if(ivideo->SiS_Pr.VirtualRomBase[mycustomttable[i].biosFootprintAddr[j]] !=
432 mycustomttable[i].biosFootprintData[j]) {
433 footprint = FALSE;
434 }
435 } else
436 footprint = FALSE;
437 }
438 }
439 if(footprint) {
440 ivideo->SiS_Pr.SiS_CustomT = mycustomttable[i].SpecialID;
441 printk(KERN_DEBUG "sisfb: Identified [%s %s], special timing applies\n",
442 mycustomttable[i].vendorName,
443 mycustomttable[i].cardName);
444 printk(KERN_DEBUG "sisfb: [specialtiming parameter name: %s]\n",
445 mycustomttable[i].optionName);
446 break;
447 }
448 }
449 i++;
450 } while(mycustomttable[i].chipID);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700451}
452
453static BOOLEAN __devinit
454sisfb_interpret_edid(struct sisfb_monitor *monitor, u8 *buffer)
455{
456 int i, j, xres, yres, refresh, index;
457 u32 emodes;
458
459 if(buffer[0] != 0x00 || buffer[1] != 0xff ||
460 buffer[2] != 0xff || buffer[3] != 0xff ||
461 buffer[4] != 0xff || buffer[5] != 0xff ||
462 buffer[6] != 0xff || buffer[7] != 0x00) {
Thomas Winischhofer544393f2005-09-09 13:04:45 -0700463 printk(KERN_DEBUG "sisfb: Bad EDID header\n");
464 return FALSE;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700465 }
466
467 if(buffer[0x12] != 0x01) {
Thomas Winischhofer544393f2005-09-09 13:04:45 -0700468 printk(KERN_INFO "sisfb: EDID version %d not supported\n",
469 buffer[0x12]);
470 return FALSE;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700471 }
472
473 monitor->feature = buffer[0x18];
474
475 if(!buffer[0x14] & 0x80) {
Thomas Winischhofer544393f2005-09-09 13:04:45 -0700476 if(!(buffer[0x14] & 0x08)) {
477 printk(KERN_INFO
478 "sisfb: WARNING: Monitor does not support separate syncs\n");
479 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700480 }
481
482 if(buffer[0x13] >= 0x01) {
483 /* EDID V1 rev 1 and 2: Search for monitor descriptor
484 * to extract ranges
485 */
486 j = 0x36;
487 for(i=0; i<4; i++) {
488 if(buffer[j] == 0x00 && buffer[j + 1] == 0x00 &&
Thomas Winischhofer544393f2005-09-09 13:04:45 -0700489 buffer[j + 2] == 0x00 && buffer[j + 3] == 0xfd &&
Linus Torvalds1da177e2005-04-16 15:20:36 -0700490 buffer[j + 4] == 0x00) {
491 monitor->hmin = buffer[j + 7];
492 monitor->hmax = buffer[j + 8];
493 monitor->vmin = buffer[j + 5];
494 monitor->vmax = buffer[j + 6];
495 monitor->dclockmax = buffer[j + 9] * 10 * 1000;
496 monitor->datavalid = TRUE;
497 break;
498 }
499 j += 18;
500 }
501 }
502
503 if(!monitor->datavalid) {
504 /* Otherwise: Get a range from the list of supported
505 * Estabished Timings. This is not entirely accurate,
506 * because fixed frequency monitors are not supported
507 * that way.
508 */
509 monitor->hmin = 65535; monitor->hmax = 0;
510 monitor->vmin = 65535; monitor->vmax = 0;
511 monitor->dclockmax = 0;
512 emodes = buffer[0x23] | (buffer[0x24] << 8) | (buffer[0x25] << 16);
513 for(i = 0; i < 13; i++) {
514 if(emodes & sisfb_ddcsmodes[i].mask) {
Thomas Winischhofer544393f2005-09-09 13:04:45 -0700515 if(monitor->hmin > sisfb_ddcsmodes[i].h) monitor->hmin = sisfb_ddcsmodes[i].h;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700516 if(monitor->hmax < sisfb_ddcsmodes[i].h) monitor->hmax = sisfb_ddcsmodes[i].h + 1;
517 if(monitor->vmin > sisfb_ddcsmodes[i].v) monitor->vmin = sisfb_ddcsmodes[i].v;
518 if(monitor->vmax < sisfb_ddcsmodes[i].v) monitor->vmax = sisfb_ddcsmodes[i].v;
519 if(monitor->dclockmax < sisfb_ddcsmodes[i].d) monitor->dclockmax = sisfb_ddcsmodes[i].d;
520 }
521 }
522 index = 0x26;
523 for(i = 0; i < 8; i++) {
524 xres = (buffer[index] + 31) * 8;
525 switch(buffer[index + 1] & 0xc0) {
Thomas Winischhofer544393f2005-09-09 13:04:45 -0700526 case 0xc0: yres = (xres * 9) / 16; break;
527 case 0x80: yres = (xres * 4) / 5; break;
528 case 0x40: yres = (xres * 3) / 4; break;
529 default: yres = xres; break;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700530 }
531 refresh = (buffer[index + 1] & 0x3f) + 60;
532 if((xres >= 640) && (yres >= 480)) {
Thomas Winischhofer544393f2005-09-09 13:04:45 -0700533 for(j = 0; j < 8; j++) {
534 if((xres == sisfb_ddcfmodes[j].x) &&
535 (yres == sisfb_ddcfmodes[j].y) &&
Linus Torvalds1da177e2005-04-16 15:20:36 -0700536 (refresh == sisfb_ddcfmodes[j].v)) {
537 if(monitor->hmin > sisfb_ddcfmodes[j].h) monitor->hmin = sisfb_ddcfmodes[j].h;
538 if(monitor->hmax < sisfb_ddcfmodes[j].h) monitor->hmax = sisfb_ddcfmodes[j].h + 1;
539 if(monitor->vmin > sisfb_ddcsmodes[j].v) monitor->vmin = sisfb_ddcsmodes[j].v;
540 if(monitor->vmax < sisfb_ddcsmodes[j].v) monitor->vmax = sisfb_ddcsmodes[j].v;
Thomas Winischhofer544393f2005-09-09 13:04:45 -0700541 if(monitor->dclockmax < sisfb_ddcsmodes[j].d) monitor->dclockmax = sisfb_ddcsmodes[j].d;
542 }
543 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700544 }
545 index += 2;
Thomas Winischhofer544393f2005-09-09 13:04:45 -0700546 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700547 if((monitor->hmin <= monitor->hmax) && (monitor->vmin <= monitor->vmax)) {
548 monitor->datavalid = TRUE;
549 }
550 }
551
Thomas Winischhofer544393f2005-09-09 13:04:45 -0700552 return monitor->datavalid;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700553}
554
555static void __devinit
556sisfb_handle_ddc(struct sis_video_info *ivideo, struct sisfb_monitor *monitor, int crtno)
557{
Thomas Winischhofer544393f2005-09-09 13:04:45 -0700558 unsigned short temp, i, realcrtno = crtno;
559 unsigned char buffer[256];
Linus Torvalds1da177e2005-04-16 15:20:36 -0700560
561 monitor->datavalid = FALSE;
562
563 if(crtno) {
Thomas Winischhofer544393f2005-09-09 13:04:45 -0700564 if(ivideo->vbflags & CRT2_LCD) realcrtno = 1;
565 else if(ivideo->vbflags & CRT2_VGA) realcrtno = 2;
566 else return;
567 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700568
Thomas Winischhofer544393f2005-09-09 13:04:45 -0700569 if((ivideo->sisfb_crt1off) && (!crtno))
570 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700571
Thomas Winischhofer544393f2005-09-09 13:04:45 -0700572 temp = SiS_HandleDDC(&ivideo->SiS_Pr, ivideo->vbflags, ivideo->sisvga_engine,
573 realcrtno, 0, &buffer[0], ivideo->vbflags2);
574 if((!temp) || (temp == 0xffff)) {
575 printk(KERN_INFO "sisfb: CRT%d DDC probing failed\n", crtno + 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700576 return;
Thomas Winischhofer544393f2005-09-09 13:04:45 -0700577 } else {
578 printk(KERN_INFO "sisfb: CRT%d DDC supported\n", crtno + 1);
579 printk(KERN_INFO "sisfb: CRT%d DDC level: %s%s%s%s\n",
580 crtno + 1,
581 (temp & 0x1a) ? "" : "[none of the supported]",
582 (temp & 0x02) ? "2 " : "",
583 (temp & 0x08) ? "D&P" : "",
584 (temp & 0x10) ? "FPDI-2" : "");
585 if(temp & 0x02) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700586 i = 3; /* Number of retrys */
587 do {
Thomas Winischhofer544393f2005-09-09 13:04:45 -0700588 temp = SiS_HandleDDC(&ivideo->SiS_Pr, ivideo->vbflags, ivideo->sisvga_engine,
589 realcrtno, 1, &buffer[0], ivideo->vbflags2);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700590 } while((temp) && i--);
Thomas Winischhofer544393f2005-09-09 13:04:45 -0700591 if(!temp) {
592 if(sisfb_interpret_edid(monitor, &buffer[0])) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700593 printk(KERN_INFO "sisfb: Monitor range H %d-%dKHz, V %d-%dHz, Max. dotclock %dMHz\n",
Thomas Winischhofer544393f2005-09-09 13:04:45 -0700594 monitor->hmin, monitor->hmax, monitor->vmin, monitor->vmax,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700595 monitor->dclockmax / 1000);
596 } else {
Thomas Winischhofer544393f2005-09-09 13:04:45 -0700597 printk(KERN_INFO "sisfb: CRT%d DDC EDID corrupt\n", crtno + 1);
598 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700599 } else {
Thomas Winischhofer544393f2005-09-09 13:04:45 -0700600 printk(KERN_INFO "sisfb: CRT%d DDC reading failed\n", crtno + 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700601 }
602 } else {
603 printk(KERN_INFO "sisfb: VESA D&P and FPDI-2 not supported yet\n");
604 }
605 }
606}
607
Thomas Winischhofer544393f2005-09-09 13:04:45 -0700608/* -------------- Mode validation --------------- */
609
Linus Torvalds1da177e2005-04-16 15:20:36 -0700610static BOOLEAN
611sisfb_verify_rate(struct sis_video_info *ivideo, struct sisfb_monitor *monitor,
612 int mode_idx, int rate_idx, int rate)
613{
614 int htotal, vtotal;
615 unsigned int dclock, hsync;
616
Thomas Winischhofer544393f2005-09-09 13:04:45 -0700617 if(!monitor->datavalid)
618 return TRUE;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700619
Thomas Winischhofer544393f2005-09-09 13:04:45 -0700620 if(mode_idx < 0)
621 return FALSE;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700622
623 /* Skip for 320x200, 320x240, 640x400 */
Thomas Winischhofer544393f2005-09-09 13:04:45 -0700624 switch(sisbios_mode[mode_idx].mode_no[ivideo->mni]) {
625 case 0x59:
626 case 0x41:
627 case 0x4f:
628 case 0x50:
629 case 0x56:
630 case 0x53:
631 case 0x2f:
632 case 0x5d:
633 case 0x5e:
634 return TRUE;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700635#ifdef CONFIG_FB_SIS_315
636 case 0x5a:
637 case 0x5b:
638 if(ivideo->sisvga_engine == SIS_315_VGA) return TRUE;
639#endif
Thomas Winischhofer544393f2005-09-09 13:04:45 -0700640 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700641
Thomas Winischhofer544393f2005-09-09 13:04:45 -0700642 if(rate < (monitor->vmin - 1))
643 return FALSE;
644 if(rate > (monitor->vmax + 1))
645 return FALSE;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700646
Thomas Winischhofer544393f2005-09-09 13:04:45 -0700647 if(sisfb_gettotalfrommode(&ivideo->SiS_Pr,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700648 sisbios_mode[mode_idx].mode_no[ivideo->mni],
Thomas Winischhofer544393f2005-09-09 13:04:45 -0700649 &htotal, &vtotal, rate_idx)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700650 dclock = (htotal * vtotal * rate) / 1000;
Thomas Winischhofer544393f2005-09-09 13:04:45 -0700651 if(dclock > (monitor->dclockmax + 1000))
652 return FALSE;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700653 hsync = dclock / htotal;
Thomas Winischhofer544393f2005-09-09 13:04:45 -0700654 if(hsync < (monitor->hmin - 1))
655 return FALSE;
656 if(hsync > (monitor->hmax + 1))
657 return FALSE;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700658 } else {
Thomas Winischhofer544393f2005-09-09 13:04:45 -0700659 return FALSE;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700660 }
661 return TRUE;
662}
663
664static int
665sisfb_validate_mode(struct sis_video_info *ivideo, int myindex, u32 vbflags)
666{
Thomas Winischhofer544393f2005-09-09 13:04:45 -0700667 u16 xres=0, yres, myres;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700668
669#ifdef CONFIG_FB_SIS_300
Thomas Winischhofer544393f2005-09-09 13:04:45 -0700670 if(ivideo->sisvga_engine == SIS_300_VGA) {
671 if(!(sisbios_mode[myindex].chipset & MD_SIS300))
672 return -1 ;
673 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700674#endif
675#ifdef CONFIG_FB_SIS_315
Thomas Winischhofer544393f2005-09-09 13:04:45 -0700676 if(ivideo->sisvga_engine == SIS_315_VGA) {
677 if(!(sisbios_mode[myindex].chipset & MD_SIS315))
678 return -1;
679 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700680#endif
681
Thomas Winischhofer544393f2005-09-09 13:04:45 -0700682 myres = sisbios_mode[myindex].yres;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700683
Thomas Winischhofer544393f2005-09-09 13:04:45 -0700684 switch(vbflags & VB_DISPTYPE_DISP2) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700685
Thomas Winischhofer544393f2005-09-09 13:04:45 -0700686 case CRT2_LCD:
687 xres = ivideo->lcdxres; yres = ivideo->lcdyres;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700688
Thomas Winischhofer544393f2005-09-09 13:04:45 -0700689 if((ivideo->SiS_Pr.SiS_CustomT != CUT_PANEL848) &&
690 (ivideo->SiS_Pr.SiS_CustomT != CUT_PANEL856)) {
691 if(sisbios_mode[myindex].xres > xres)
692 return -1;
693 if(myres > yres)
694 return -1;
695 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700696
Thomas Winischhofer544393f2005-09-09 13:04:45 -0700697 if(ivideo->sisfb_fstn) {
698 if(sisbios_mode[myindex].xres == 320) {
699 if(myres == 240) {
700 switch(sisbios_mode[myindex].mode_no[1]) {
701 case 0x50: myindex = MODE_FSTN_8; break;
702 case 0x56: myindex = MODE_FSTN_16; break;
703 case 0x53: return -1;
704 }
705 }
706 }
707 }
708
709 if(SiS_GetModeID_LCD(ivideo->sisvga_engine, vbflags, sisbios_mode[myindex].xres,
710 sisbios_mode[myindex].yres, 0, ivideo->sisfb_fstn,
711 ivideo->SiS_Pr.SiS_CustomT, xres, yres, ivideo->vbflags2) < 0x14) {
712 return -1;
713 }
714 break;
715
716 case CRT2_TV:
717 if(SiS_GetModeID_TV(ivideo->sisvga_engine, vbflags, sisbios_mode[myindex].xres,
718 sisbios_mode[myindex].yres, 0, ivideo->vbflags2) < 0x14) {
719 return -1;
720 }
721 break;
722
723 case CRT2_VGA:
724 if(SiS_GetModeID_VGA2(ivideo->sisvga_engine, vbflags, sisbios_mode[myindex].xres,
725 sisbios_mode[myindex].yres, 0, ivideo->vbflags2) < 0x14) {
726 return -1;
727 }
728 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700729 }
730
Thomas Winischhofer544393f2005-09-09 13:04:45 -0700731 return myindex;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700732}
733
734static u8
735sisfb_search_refresh_rate(struct sis_video_info *ivideo, unsigned int rate, int mode_idx)
736{
Linus Torvalds1da177e2005-04-16 15:20:36 -0700737 int i = 0;
Thomas Winischhofer544393f2005-09-09 13:04:45 -0700738 u16 xres = sisbios_mode[mode_idx].xres;
739 u16 yres = sisbios_mode[mode_idx].yres;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700740
741 ivideo->rate_idx = 0;
742 while((sisfb_vrate[i].idx != 0) && (sisfb_vrate[i].xres <= xres)) {
743 if((sisfb_vrate[i].xres == xres) && (sisfb_vrate[i].yres == yres)) {
744 if(sisfb_vrate[i].refresh == rate) {
745 ivideo->rate_idx = sisfb_vrate[i].idx;
746 break;
747 } else if(sisfb_vrate[i].refresh > rate) {
748 if((sisfb_vrate[i].refresh - rate) <= 3) {
749 DPRINTK("sisfb: Adjusting rate from %d up to %d\n",
750 rate, sisfb_vrate[i].refresh);
751 ivideo->rate_idx = sisfb_vrate[i].idx;
752 ivideo->refresh_rate = sisfb_vrate[i].refresh;
753 } else if(((rate - sisfb_vrate[i-1].refresh) <= 2)
754 && (sisfb_vrate[i].idx != 1)) {
755 DPRINTK("sisfb: Adjusting rate from %d down to %d\n",
756 rate, sisfb_vrate[i-1].refresh);
757 ivideo->rate_idx = sisfb_vrate[i-1].idx;
758 ivideo->refresh_rate = sisfb_vrate[i-1].refresh;
Thomas Winischhofer544393f2005-09-09 13:04:45 -0700759 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700760 break;
761 } else if((rate - sisfb_vrate[i].refresh) <= 2) {
762 DPRINTK("sisfb: Adjusting rate from %d down to %d\n",
763 rate, sisfb_vrate[i].refresh);
Thomas Winischhofer544393f2005-09-09 13:04:45 -0700764 ivideo->rate_idx = sisfb_vrate[i].idx;
765 break;
766 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700767 }
768 i++;
769 }
770 if(ivideo->rate_idx > 0) {
771 return ivideo->rate_idx;
772 } else {
773 printk(KERN_INFO "sisfb: Unsupported rate %d for %dx%d\n",
774 rate, xres, yres);
775 return 0;
776 }
777}
778
779static BOOLEAN
780sisfb_bridgeisslave(struct sis_video_info *ivideo)
781{
Thomas Winischhofer544393f2005-09-09 13:04:45 -0700782 unsigned char P1_00;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700783
Thomas Winischhofer544393f2005-09-09 13:04:45 -0700784 if(!(ivideo->vbflags2 & VB2_VIDEOBRIDGE))
785 return FALSE;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700786
Thomas Winischhofer544393f2005-09-09 13:04:45 -0700787 inSISIDXREG(SISPART1,0x00,P1_00);
788 if( ((ivideo->sisvga_engine == SIS_300_VGA) && (P1_00 & 0xa0) == 0x20) ||
789 ((ivideo->sisvga_engine == SIS_315_VGA) && (P1_00 & 0x50) == 0x10) ) {
790 return TRUE;
791 } else {
792 return FALSE;
793 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700794}
795
796static BOOLEAN
797sisfballowretracecrt1(struct sis_video_info *ivideo)
798{
Thomas Winischhofer544393f2005-09-09 13:04:45 -0700799 u8 temp;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700800
Thomas Winischhofer544393f2005-09-09 13:04:45 -0700801 inSISIDXREG(SISCR,0x17,temp);
802 if(!(temp & 0x80))
803 return FALSE;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700804
Thomas Winischhofer544393f2005-09-09 13:04:45 -0700805 inSISIDXREG(SISSR,0x1f,temp);
806 if(temp & 0xc0)
807 return FALSE;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700808
Thomas Winischhofer544393f2005-09-09 13:04:45 -0700809 return TRUE;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700810}
811
812static BOOLEAN
813sisfbcheckvretracecrt1(struct sis_video_info *ivideo)
814{
Thomas Winischhofer544393f2005-09-09 13:04:45 -0700815 if(!sisfballowretracecrt1(ivideo))
816 return FALSE;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700817
Thomas Winischhofer544393f2005-09-09 13:04:45 -0700818 if(inSISREG(SISINPSTAT) & 0x08)
819 return TRUE;
820 else
821 return FALSE;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700822}
823
824static void
825sisfbwaitretracecrt1(struct sis_video_info *ivideo)
826{
Thomas Winischhofer544393f2005-09-09 13:04:45 -0700827 int watchdog;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700828
Thomas Winischhofer544393f2005-09-09 13:04:45 -0700829 if(!sisfballowretracecrt1(ivideo))
830 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700831
Thomas Winischhofer544393f2005-09-09 13:04:45 -0700832 watchdog = 65536;
833 while((!(inSISREG(SISINPSTAT) & 0x08)) && --watchdog);
834 watchdog = 65536;
835 while((inSISREG(SISINPSTAT) & 0x08) && --watchdog);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700836}
837
838static BOOLEAN
839sisfbcheckvretracecrt2(struct sis_video_info *ivideo)
840{
Thomas Winischhofer544393f2005-09-09 13:04:45 -0700841 unsigned char temp, reg;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700842
Thomas Winischhofer544393f2005-09-09 13:04:45 -0700843 switch(ivideo->sisvga_engine) {
844 case SIS_300_VGA: reg = 0x25; break;
845 case SIS_315_VGA: reg = 0x30; break;
846 default: return FALSE;
847 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700848
Thomas Winischhofer544393f2005-09-09 13:04:45 -0700849 inSISIDXREG(SISPART1, reg, temp);
850 if(temp & 0x02)
851 return TRUE;
852 else
853 return FALSE;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700854}
855
856static BOOLEAN
857sisfb_CheckVBRetrace(struct sis_video_info *ivideo)
858{
Thomas Winischhofer544393f2005-09-09 13:04:45 -0700859 if(ivideo->currentvbflags & VB_DISPTYPE_DISP2) {
860 if(!sisfb_bridgeisslave(ivideo)) {
861 return sisfbcheckvretracecrt2(ivideo);
862 }
863 }
864 return sisfbcheckvretracecrt1(ivideo);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700865}
866
867static u32
868sisfb_setupvbblankflags(struct sis_video_info *ivideo, u32 *vcount, u32 *hcount)
869{
Thomas Winischhofer544393f2005-09-09 13:04:45 -0700870 u8 idx, reg1, reg2, reg3, reg4;
871 u32 ret = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700872
Thomas Winischhofer544393f2005-09-09 13:04:45 -0700873 (*vcount) = (*hcount) = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700874
Thomas Winischhofer544393f2005-09-09 13:04:45 -0700875 if((ivideo->currentvbflags & VB_DISPTYPE_DISP2) && (!(sisfb_bridgeisslave(ivideo)))) {
876
877 ret |= (FB_VBLANK_HAVE_VSYNC |
878 FB_VBLANK_HAVE_HBLANK |
879 FB_VBLANK_HAVE_VBLANK |
880 FB_VBLANK_HAVE_VCOUNT |
881 FB_VBLANK_HAVE_HCOUNT);
882 switch(ivideo->sisvga_engine) {
883 case SIS_300_VGA: idx = 0x25; break;
884 default:
885 case SIS_315_VGA: idx = 0x30; break;
886 }
887 inSISIDXREG(SISPART1,(idx+0),reg1); /* 30 */
888 inSISIDXREG(SISPART1,(idx+1),reg2); /* 31 */
889 inSISIDXREG(SISPART1,(idx+2),reg3); /* 32 */
890 inSISIDXREG(SISPART1,(idx+3),reg4); /* 33 */
891 if(reg1 & 0x01) ret |= FB_VBLANK_VBLANKING;
892 if(reg1 & 0x02) ret |= FB_VBLANK_VSYNCING;
893 if(reg4 & 0x80) ret |= FB_VBLANK_HBLANKING;
894 (*vcount) = reg3 | ((reg4 & 0x70) << 4);
895 (*hcount) = reg2 | ((reg4 & 0x0f) << 8);
896
897 } else if(sisfballowretracecrt1(ivideo)) {
898
899 ret |= (FB_VBLANK_HAVE_VSYNC |
900 FB_VBLANK_HAVE_VBLANK |
901 FB_VBLANK_HAVE_VCOUNT |
902 FB_VBLANK_HAVE_HCOUNT);
903 reg1 = inSISREG(SISINPSTAT);
904 if(reg1 & 0x08) ret |= FB_VBLANK_VSYNCING;
905 if(reg1 & 0x01) ret |= FB_VBLANK_VBLANKING;
906 inSISIDXREG(SISCR,0x20,reg1);
907 inSISIDXREG(SISCR,0x1b,reg1);
908 inSISIDXREG(SISCR,0x1c,reg2);
909 inSISIDXREG(SISCR,0x1d,reg3);
910 (*vcount) = reg2 | ((reg3 & 0x07) << 8);
911 (*hcount) = (reg1 | ((reg3 & 0x10) << 4)) << 3;
912 }
913
914 return ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700915}
916
917static int
918sisfb_myblank(struct sis_video_info *ivideo, int blank)
919{
Thomas Winischhofer544393f2005-09-09 13:04:45 -0700920 u8 sr01, sr11, sr1f, cr63=0, p2_0, p1_13;
921 BOOLEAN backlight = TRUE;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700922
Thomas Winischhofer544393f2005-09-09 13:04:45 -0700923 switch(blank) {
924 case FB_BLANK_UNBLANK: /* on */
925 sr01 = 0x00;
926 sr11 = 0x00;
927 sr1f = 0x00;
928 cr63 = 0x00;
929 p2_0 = 0x20;
930 p1_13 = 0x00;
931 backlight = TRUE;
932 break;
933 case FB_BLANK_NORMAL: /* blank */
934 sr01 = 0x20;
935 sr11 = 0x00;
936 sr1f = 0x00;
937 cr63 = 0x00;
938 p2_0 = 0x20;
939 p1_13 = 0x00;
940 backlight = TRUE;
941 break;
942 case FB_BLANK_VSYNC_SUSPEND: /* no vsync */
943 sr01 = 0x20;
944 sr11 = 0x08;
945 sr1f = 0x80;
946 cr63 = 0x40;
947 p2_0 = 0x40;
948 p1_13 = 0x80;
949 backlight = FALSE;
950 break;
951 case FB_BLANK_HSYNC_SUSPEND: /* no hsync */
952 sr01 = 0x20;
953 sr11 = 0x08;
954 sr1f = 0x40;
955 cr63 = 0x40;
956 p2_0 = 0x80;
957 p1_13 = 0x40;
958 backlight = FALSE;
959 break;
960 case FB_BLANK_POWERDOWN: /* off */
961 sr01 = 0x20;
962 sr11 = 0x08;
963 sr1f = 0xc0;
964 cr63 = 0x40;
965 p2_0 = 0xc0;
966 p1_13 = 0xc0;
967 backlight = FALSE;
968 break;
969 default:
970 return 1;
971 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700972
Thomas Winischhofer544393f2005-09-09 13:04:45 -0700973 if(ivideo->currentvbflags & VB_DISPTYPE_CRT1) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700974
Thomas Winischhofer544393f2005-09-09 13:04:45 -0700975 if( (!ivideo->sisfb_thismonitor.datavalid) ||
976 ((ivideo->sisfb_thismonitor.datavalid) &&
977 (ivideo->sisfb_thismonitor.feature & 0xe0))) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700978
Thomas Winischhofer544393f2005-09-09 13:04:45 -0700979 if(ivideo->sisvga_engine == SIS_315_VGA) {
980 setSISIDXREG(SISCR, ivideo->SiS_Pr.SiS_MyCR63, 0xbf, cr63);
981 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700982
Thomas Winischhofer544393f2005-09-09 13:04:45 -0700983 if(!(sisfb_bridgeisslave(ivideo))) {
984 setSISIDXREG(SISSR, 0x01, ~0x20, sr01);
985 setSISIDXREG(SISSR, 0x1f, 0x3f, sr1f);
986 }
987 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700988
Thomas Winischhofer544393f2005-09-09 13:04:45 -0700989 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700990
Thomas Winischhofer544393f2005-09-09 13:04:45 -0700991 if(ivideo->currentvbflags & CRT2_LCD) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700992
Thomas Winischhofer544393f2005-09-09 13:04:45 -0700993 if(ivideo->vbflags2 & VB2_SISLVDSBRIDGE) {
994 if(backlight) {
995 SiS_SiS30xBLOn(&ivideo->SiS_Pr);
996 } else {
997 SiS_SiS30xBLOff(&ivideo->SiS_Pr);
998 }
999 } else if(ivideo->sisvga_engine == SIS_315_VGA) {
1000#ifdef CONFIG_FB_SIS_315
1001 if(ivideo->vbflags2 & VB2_CHRONTEL) {
1002 if(backlight) {
1003 SiS_Chrontel701xBLOn(&ivideo->SiS_Pr);
1004 } else {
1005 SiS_Chrontel701xBLOff(&ivideo->SiS_Pr);
1006 }
1007 }
1008#endif
1009 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001010
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001011 if(((ivideo->sisvga_engine == SIS_300_VGA) &&
1012 (ivideo->vbflags2 & (VB2_301|VB2_30xBDH|VB2_LVDS))) ||
1013 ((ivideo->sisvga_engine == SIS_315_VGA) &&
1014 ((ivideo->vbflags2 & (VB2_LVDS | VB2_CHRONTEL)) == VB2_LVDS))) {
1015 setSISIDXREG(SISSR, 0x11, ~0x0c, sr11);
1016 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001017
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001018 if(ivideo->sisvga_engine == SIS_300_VGA) {
1019 if((ivideo->vbflags2 & VB2_30xB) &&
1020 (!(ivideo->vbflags2 & VB2_30xBDH))) {
1021 setSISIDXREG(SISPART1, 0x13, 0x3f, p1_13);
1022 }
1023 } else if(ivideo->sisvga_engine == SIS_315_VGA) {
1024 if((ivideo->vbflags2 & VB2_30xB) &&
1025 (!(ivideo->vbflags2 & VB2_30xBDH))) {
1026 setSISIDXREG(SISPART2, 0x00, 0x1f, p2_0);
1027 }
1028 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001029
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001030 } else if(ivideo->currentvbflags & CRT2_VGA) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001031
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001032 if(ivideo->vbflags2 & VB2_30xB) {
1033 setSISIDXREG(SISPART2, 0x00, 0x1f, p2_0);
1034 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001035
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001036 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001037
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001038 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001039}
1040
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001041/* ------------- Callbacks from init.c/init301.c -------------- */
1042
1043#ifdef CONFIG_FB_SIS_300
1044unsigned int
1045sisfb_read_nbridge_pci_dword(struct SiS_Private *SiS_Pr, int reg)
1046{
1047 struct sis_video_info *ivideo = (struct sis_video_info *)SiS_Pr->ivideo;
1048 u32 val = 0;
1049
1050 pci_read_config_dword(ivideo->nbridge, reg, &val);
1051 return (unsigned int)val;
1052}
1053
1054void
1055sisfb_write_nbridge_pci_dword(struct SiS_Private *SiS_Pr, int reg, unsigned int val)
1056{
1057 struct sis_video_info *ivideo = (struct sis_video_info *)SiS_Pr->ivideo;
1058
1059 pci_write_config_dword(ivideo->nbridge, reg, (u32)val);
1060}
1061
1062unsigned int
1063sisfb_read_lpc_pci_dword(struct SiS_Private *SiS_Pr, int reg)
1064{
1065 struct sis_video_info *ivideo = (struct sis_video_info *)SiS_Pr->ivideo;
1066 u32 val = 0;
1067
1068 if(!ivideo->lpcdev) return 0;
1069
1070 pci_read_config_dword(ivideo->lpcdev, reg, &val);
1071 return (unsigned int)val;
1072}
1073#endif
1074
1075#ifdef CONFIG_FB_SIS_315
1076void
1077sisfb_write_nbridge_pci_byte(struct SiS_Private *SiS_Pr, int reg, unsigned char val)
1078{
1079 struct sis_video_info *ivideo = (struct sis_video_info *)SiS_Pr->ivideo;
1080
1081 pci_write_config_byte(ivideo->nbridge, reg, (u8)val);
1082}
1083
1084unsigned int
1085sisfb_read_mio_pci_word(struct SiS_Private *SiS_Pr, int reg)
1086{
1087 struct sis_video_info *ivideo = (struct sis_video_info *)SiS_Pr->ivideo;
1088 u16 val = 0;
1089
1090 if(!ivideo->lpcdev) return 0;
1091
1092 pci_read_config_word(ivideo->lpcdev, reg, &val);
1093 return (unsigned int)val;
1094}
1095#endif
1096
Linus Torvalds1da177e2005-04-16 15:20:36 -07001097/* ----------- FBDev related routines for all series ----------- */
1098
1099static int
1100sisfb_get_cmap_len(const struct fb_var_screeninfo *var)
1101{
1102 return (var->bits_per_pixel == 8) ? 256 : 16;
1103}
1104
1105static void
1106sisfb_set_vparms(struct sis_video_info *ivideo)
1107{
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001108 switch(ivideo->video_bpp) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001109 case 8:
1110 ivideo->DstColor = 0x0000;
1111 ivideo->SiS310_AccelDepth = 0x00000000;
1112 ivideo->video_cmap_len = 256;
1113 break;
1114 case 16:
1115 ivideo->DstColor = 0x8000;
1116 ivideo->SiS310_AccelDepth = 0x00010000;
1117 ivideo->video_cmap_len = 16;
1118 break;
1119 case 32:
1120 ivideo->DstColor = 0xC000;
1121 ivideo->SiS310_AccelDepth = 0x00020000;
1122 ivideo->video_cmap_len = 16;
1123 break;
1124 default:
1125 ivideo->video_cmap_len = 16;
1126 printk(KERN_ERR "sisfb: Unsupported depth %d", ivideo->video_bpp);
1127 ivideo->accel = 0;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001128 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001129}
1130
1131static int
1132sisfb_calc_maxyres(struct sis_video_info *ivideo, struct fb_var_screeninfo *var)
1133{
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001134 int maxyres = ivideo->sisfb_mem / (var->xres_virtual * (var->bits_per_pixel >> 3));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001135
1136 if(maxyres > 32767) maxyres = 32767;
1137
1138 return maxyres;
1139}
1140
1141static void
1142sisfb_calc_pitch(struct sis_video_info *ivideo, struct fb_var_screeninfo *var)
1143{
1144 ivideo->video_linelength = var->xres_virtual * (var->bits_per_pixel >> 3);
1145 ivideo->scrnpitchCRT1 = ivideo->video_linelength;
1146 if(!(ivideo->currentvbflags & CRT1_LCDA)) {
1147 if((var->vmode & FB_VMODE_MASK) == FB_VMODE_INTERLACED) {
1148 ivideo->scrnpitchCRT1 <<= 1;
1149 }
1150 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001151}
1152
1153static void
1154sisfb_set_pitch(struct sis_video_info *ivideo)
1155{
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001156 BOOLEAN isslavemode = FALSE;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001157 unsigned short HDisplay1 = ivideo->scrnpitchCRT1 >> 3;
1158 unsigned short HDisplay2 = ivideo->video_linelength >> 3;
1159
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001160 if(sisfb_bridgeisslave(ivideo)) isslavemode = TRUE;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001161
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001162 /* We need to set pitch for CRT1 if bridge is in slave mode, too */
1163 if((ivideo->currentvbflags & VB_DISPTYPE_DISP1) || (isslavemode)) {
1164 outSISIDXREG(SISCR,0x13,(HDisplay1 & 0xFF));
1165 setSISIDXREG(SISSR,0x0E,0xF0,(HDisplay1 >> 8));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001166 }
1167
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001168 /* We must not set the pitch for CRT2 if bridge is in slave mode */
1169 if((ivideo->currentvbflags & VB_DISPTYPE_DISP2) && (!isslavemode)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001170 orSISIDXREG(SISPART1,ivideo->CRT2_write_enable,0x01);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001171 outSISIDXREG(SISPART1,0x07,(HDisplay2 & 0xFF));
1172 setSISIDXREG(SISPART1,0x09,0xF0,(HDisplay2 >> 8));
1173 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001174}
1175
1176static void
1177sisfb_bpp_to_var(struct sis_video_info *ivideo, struct fb_var_screeninfo *var)
1178{
1179 ivideo->video_cmap_len = sisfb_get_cmap_len(var);
1180
1181 switch(var->bits_per_pixel) {
1182 case 8:
1183 var->red.offset = var->green.offset = var->blue.offset = 0;
1184 var->red.length = var->green.length = var->blue.length = 6;
1185 break;
1186 case 16:
1187 var->red.offset = 11;
1188 var->red.length = 5;
1189 var->green.offset = 5;
1190 var->green.length = 6;
1191 var->blue.offset = 0;
1192 var->blue.length = 5;
1193 var->transp.offset = 0;
1194 var->transp.length = 0;
1195 break;
1196 case 32:
1197 var->red.offset = 16;
1198 var->red.length = 8;
1199 var->green.offset = 8;
1200 var->green.length = 8;
1201 var->blue.offset = 0;
1202 var->blue.length = 8;
1203 var->transp.offset = 24;
1204 var->transp.length = 8;
1205 break;
1206 }
1207}
1208
1209static int
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001210sisfb_set_mode(struct sis_video_info *ivideo, int clrscrn)
1211{
1212 unsigned short modeno = ivideo->mode_no;
1213
1214 /* >=2.6.12's fbcon clears the screen anyway */
1215#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,12)
1216 if(!clrscrn) modeno |= 0x80;
1217#else
1218 modeno |= 0x80;
1219#endif
1220
1221 outSISIDXREG(SISSR, IND_SIS_PASSWORD, SIS_PASSWORD);
1222
1223 sisfb_pre_setmode(ivideo);
1224
1225 if(SiSSetMode(&ivideo->SiS_Pr, modeno) == 0) {
1226 printk(KERN_ERR "sisfb: Setting mode[0x%x] failed\n", ivideo->mode_no);
1227 return -EINVAL;
1228 }
1229
1230 outSISIDXREG(SISSR, IND_SIS_PASSWORD, SIS_PASSWORD);
1231
1232 sisfb_post_setmode(ivideo);
1233
1234 return 0;
1235}
1236
1237
1238static int
Linus Torvalds1da177e2005-04-16 15:20:36 -07001239sisfb_do_set_var(struct fb_var_screeninfo *var, int isactive, struct fb_info *info)
1240{
1241 struct sis_video_info *ivideo = (struct sis_video_info *)info->par;
1242 unsigned int htotal = 0, vtotal = 0;
1243 unsigned int drate = 0, hrate = 0;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001244 int found_mode = 0, ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001245 int old_mode;
1246 u32 pixclock;
1247
1248 htotal = var->left_margin + var->xres + var->right_margin + var->hsync_len;
1249
1250 vtotal = var->upper_margin + var->lower_margin + var->vsync_len;
1251
1252 pixclock = var->pixclock;
1253
1254 if((var->vmode & FB_VMODE_MASK) == FB_VMODE_NONINTERLACED) {
1255 vtotal += var->yres;
1256 vtotal <<= 1;
1257 } else if((var->vmode & FB_VMODE_MASK) == FB_VMODE_DOUBLE) {
1258 vtotal += var->yres;
1259 vtotal <<= 2;
1260 } else if((var->vmode & FB_VMODE_MASK) == FB_VMODE_INTERLACED) {
1261 vtotal += var->yres;
1262 vtotal <<= 1;
1263 } else vtotal += var->yres;
1264
1265 if(!(htotal) || !(vtotal)) {
1266 DPRINTK("sisfb: Invalid 'var' information\n");
1267 return -EINVAL;
1268 }
1269
1270 if(pixclock && htotal && vtotal) {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001271 drate = 1000000000 / pixclock;
1272 hrate = (drate * 1000) / htotal;
1273 ivideo->refresh_rate = (unsigned int) (hrate * 2 / vtotal);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001274 } else {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001275 ivideo->refresh_rate = 60;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001276 }
1277
1278 old_mode = ivideo->sisfb_mode_idx;
1279 ivideo->sisfb_mode_idx = 0;
1280
1281 while( (sisbios_mode[ivideo->sisfb_mode_idx].mode_no[0] != 0) &&
1282 (sisbios_mode[ivideo->sisfb_mode_idx].xres <= var->xres) ) {
1283 if( (sisbios_mode[ivideo->sisfb_mode_idx].xres == var->xres) &&
1284 (sisbios_mode[ivideo->sisfb_mode_idx].yres == var->yres) &&
1285 (sisbios_mode[ivideo->sisfb_mode_idx].bpp == var->bits_per_pixel)) {
1286 ivideo->mode_no = sisbios_mode[ivideo->sisfb_mode_idx].mode_no[ivideo->mni];
1287 found_mode = 1;
1288 break;
1289 }
1290 ivideo->sisfb_mode_idx++;
1291 }
1292
1293 if(found_mode) {
1294 ivideo->sisfb_mode_idx = sisfb_validate_mode(ivideo,
1295 ivideo->sisfb_mode_idx, ivideo->currentvbflags);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001296 ivideo->mode_no = sisbios_mode[ivideo->sisfb_mode_idx].mode_no[ivideo->mni];
Linus Torvalds1da177e2005-04-16 15:20:36 -07001297 } else {
1298 ivideo->sisfb_mode_idx = -1;
1299 }
1300
1301 if(ivideo->sisfb_mode_idx < 0) {
1302 printk(KERN_ERR "sisfb: Mode %dx%dx%d not supported\n", var->xres,
1303 var->yres, var->bits_per_pixel);
1304 ivideo->sisfb_mode_idx = old_mode;
1305 return -EINVAL;
1306 }
1307
1308 if(sisfb_search_refresh_rate(ivideo, ivideo->refresh_rate, ivideo->sisfb_mode_idx) == 0) {
1309 ivideo->rate_idx = sisbios_mode[ivideo->sisfb_mode_idx].rate_idx;
1310 ivideo->refresh_rate = 60;
1311 }
1312
1313#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
1314 if(ivideo->sisfb_thismonitor.datavalid) {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001315 if(!sisfb_verify_rate(ivideo, &ivideo->sisfb_thismonitor, ivideo->sisfb_mode_idx,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001316 ivideo->rate_idx, ivideo->refresh_rate)) {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001317 printk(KERN_INFO "sisfb: WARNING: Refresh rate exceeds monitor specs!\n");
1318 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001319 }
1320#endif
1321
1322#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
1323 if(((var->activate & FB_ACTIVATE_MASK) == FB_ACTIVATE_NOW) && isactive) {
1324#else
1325 if(isactive) {
1326#endif
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001327 /* If acceleration to be used? Need to know
1328 * before pre/post_set_mode()
1329 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001330 ivideo->accel = 0;
1331#if defined(FBINFO_HWACCEL_DISABLED) && defined(FBINFO_HWACCEL_XPAN)
1332#ifdef STUPID_ACCELF_TEXT_SHIT
1333 if(var->accel_flags & FB_ACCELF_TEXT) {
1334 info->flags &= ~FBINFO_HWACCEL_DISABLED;
1335 } else {
1336 info->flags |= FBINFO_HWACCEL_DISABLED;
1337 }
1338#endif
1339 if(!(info->flags & FBINFO_HWACCEL_DISABLED)) ivideo->accel = -1;
1340#else
1341 if(var->accel_flags & FB_ACCELF_TEXT) ivideo->accel = -1;
1342#endif
1343
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001344 if((ret = sisfb_set_mode(ivideo, 1))) {
1345 return ret;
1346 }
1347
1348 ivideo->video_bpp = sisbios_mode[ivideo->sisfb_mode_idx].bpp;
1349 ivideo->video_width = sisbios_mode[ivideo->sisfb_mode_idx].xres;
1350 ivideo->video_height = sisbios_mode[ivideo->sisfb_mode_idx].yres;
1351
1352 sisfb_calc_pitch(ivideo, var);
1353 sisfb_set_pitch(ivideo);
1354
Linus Torvalds1da177e2005-04-16 15:20:36 -07001355 sisfb_set_vparms(ivideo);
1356
1357 ivideo->current_width = ivideo->video_width;
1358 ivideo->current_height = ivideo->video_height;
1359 ivideo->current_bpp = ivideo->video_bpp;
1360 ivideo->current_htotal = htotal;
1361 ivideo->current_vtotal = vtotal;
1362 ivideo->current_linelength = ivideo->video_linelength;
1363 ivideo->current_pixclock = var->pixclock;
1364 ivideo->current_refresh_rate = ivideo->refresh_rate;
1365#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0)
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001366 ivideo->sisfb_lastrates[ivideo->mode_no] = ivideo->refresh_rate;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001367#endif
1368 }
1369
1370 return 0;
1371}
1372
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001373static void
1374sisfb_set_base_CRT1(struct sis_video_info *ivideo, unsigned int base)
1375{
1376 outSISIDXREG(SISSR, IND_SIS_PASSWORD, SIS_PASSWORD);
1377
1378 outSISIDXREG(SISCR, 0x0D, base & 0xFF);
1379 outSISIDXREG(SISCR, 0x0C, (base >> 8) & 0xFF);
1380 outSISIDXREG(SISSR, 0x0D, (base >> 16) & 0xFF);
1381 if(ivideo->sisvga_engine == SIS_315_VGA) {
1382 setSISIDXREG(SISSR, 0x37, 0xFE, (base >> 24) & 0x01);
1383 }
1384}
1385
1386static void
1387sisfb_set_base_CRT2(struct sis_video_info *ivideo, unsigned int base)
1388{
1389 if(ivideo->currentvbflags & VB_DISPTYPE_DISP2) {
1390 orSISIDXREG(SISPART1, ivideo->CRT2_write_enable, 0x01);
1391 outSISIDXREG(SISPART1, 0x06, (base & 0xFF));
1392 outSISIDXREG(SISPART1, 0x05, ((base >> 8) & 0xFF));
1393 outSISIDXREG(SISPART1, 0x04, ((base >> 16) & 0xFF));
1394 if(ivideo->sisvga_engine == SIS_315_VGA) {
1395 setSISIDXREG(SISPART1, 0x02, 0x7F, ((base >> 24) & 0x01) << 7);
1396 }
1397 }
1398}
1399
Linus Torvalds1da177e2005-04-16 15:20:36 -07001400static int
1401sisfb_pan_var(struct sis_video_info *ivideo, struct fb_var_screeninfo *var)
1402{
Linus Torvalds1da177e2005-04-16 15:20:36 -07001403 if(var->xoffset > (var->xres_virtual - var->xres)) {
1404 return -EINVAL;
1405 }
1406 if(var->yoffset > (var->yres_virtual - var->yres)) {
1407 return -EINVAL;
1408 }
1409
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001410 ivideo->current_base = (var->yoffset * var->xres_virtual) + var->xoffset;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001411
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001412 /* calculate base bpp dep. */
1413 switch(var->bits_per_pixel) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001414 case 32:
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001415 break;
1416 case 16:
1417 ivideo->current_base >>= 1;
1418 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001419 case 8:
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001420 default:
1421 ivideo->current_base >>= 2;
1422 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001423 }
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001424
1425 ivideo->current_base += (ivideo->video_offset >> 2);
1426
1427 sisfb_set_base_CRT1(ivideo, ivideo->current_base);
1428 sisfb_set_base_CRT2(ivideo, ivideo->current_base);
1429
Linus Torvalds1da177e2005-04-16 15:20:36 -07001430 return 0;
1431}
1432
1433/* ------------ FBDev related routines for 2.4 series ----------- */
1434
1435#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
1436
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001437#include "sisfb_fbdev_2_4.h"
Linus Torvalds1da177e2005-04-16 15:20:36 -07001438
Linus Torvalds1da177e2005-04-16 15:20:36 -07001439#endif
1440
1441/* ------------ FBDev related routines for 2.6 series ----------- */
1442
1443#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0)
1444
1445static int
1446sisfb_open(struct fb_info *info, int user)
1447{
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001448 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001449}
1450
1451static int
1452sisfb_release(struct fb_info *info, int user)
1453{
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001454 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001455}
1456
1457static int
1458sisfb_setcolreg(unsigned regno, unsigned red, unsigned green, unsigned blue,
1459 unsigned transp, struct fb_info *info)
1460{
1461 struct sis_video_info *ivideo = (struct sis_video_info *)info->par;
1462
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001463 if(regno >= sisfb_get_cmap_len(&info->var))
1464 return 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001465
1466 switch(info->var.bits_per_pixel) {
1467 case 8:
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001468 outSISREG(SISDACA, regno);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001469 outSISREG(SISDACD, (red >> 10));
1470 outSISREG(SISDACD, (green >> 10));
1471 outSISREG(SISDACD, (blue >> 10));
1472 if(ivideo->currentvbflags & VB_DISPTYPE_DISP2) {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001473 outSISREG(SISDAC2A, regno);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001474 outSISREG(SISDAC2D, (red >> 8));
1475 outSISREG(SISDAC2D, (green >> 8));
1476 outSISREG(SISDAC2D, (blue >> 8));
1477 }
1478 break;
1479 case 16:
1480 ((u32 *)(info->pseudo_palette))[regno] =
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001481 (red & 0xf800) |
1482 ((green & 0xfc00) >> 5) |
1483 ((blue & 0xf800) >> 11);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001484 break;
1485 case 32:
1486 red >>= 8;
1487 green >>= 8;
1488 blue >>= 8;
1489 ((u32 *)(info->pseudo_palette))[regno] =
1490 (red << 16) | (green << 8) | (blue);
1491 break;
1492 }
1493 return 0;
1494}
1495
1496static int
1497sisfb_set_par(struct fb_info *info)
1498{
1499 int err;
1500
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001501 if((err = sisfb_do_set_var(&info->var, 1, info)))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001502 return err;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001503
Linus Torvalds1da177e2005-04-16 15:20:36 -07001504#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,10)
1505 sisfb_get_fix(&info->fix, info->currcon, info);
1506#else
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001507 sisfb_get_fix(&info->fix, -1, info);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001508#endif
1509 return 0;
1510}
1511
1512static int
1513sisfb_check_var(struct fb_var_screeninfo *var, struct fb_info *info)
1514{
1515 struct sis_video_info *ivideo = (struct sis_video_info *)info->par;
1516 unsigned int htotal = 0, vtotal = 0, myrateindex = 0;
1517 unsigned int drate = 0, hrate = 0, maxyres;
1518 int found_mode = 0;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001519 int refresh_rate, search_idx, tidx;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001520 BOOLEAN recalc_clock = FALSE;
1521 u32 pixclock;
1522
1523 htotal = var->left_margin + var->xres + var->right_margin + var->hsync_len;
1524
1525 vtotal = var->upper_margin + var->lower_margin + var->vsync_len;
1526
1527 pixclock = var->pixclock;
1528
1529 if((var->vmode & FB_VMODE_MASK) == FB_VMODE_NONINTERLACED) {
1530 vtotal += var->yres;
1531 vtotal <<= 1;
1532 } else if((var->vmode & FB_VMODE_MASK) == FB_VMODE_DOUBLE) {
1533 vtotal += var->yres;
1534 vtotal <<= 2;
1535 } else if((var->vmode & FB_VMODE_MASK) == FB_VMODE_INTERLACED) {
1536 vtotal += var->yres;
1537 vtotal <<= 1;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001538 } else
1539 vtotal += var->yres;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001540
1541 if(!(htotal) || !(vtotal)) {
1542 SISFAIL("sisfb: no valid timing data");
1543 }
1544
1545 search_idx = 0;
1546 while( (sisbios_mode[search_idx].mode_no[0] != 0) &&
1547 (sisbios_mode[search_idx].xres <= var->xres) ) {
1548 if( (sisbios_mode[search_idx].xres == var->xres) &&
1549 (sisbios_mode[search_idx].yres == var->yres) &&
1550 (sisbios_mode[search_idx].bpp == var->bits_per_pixel)) {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001551 if((tidx = sisfb_validate_mode(ivideo, search_idx,
1552 ivideo->currentvbflags)) > 0) {
1553 found_mode = 1;
1554 search_idx = tidx;
1555 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001556 }
1557 }
1558 search_idx++;
1559 }
1560
1561 if(!found_mode) {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001562 search_idx = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001563 while(sisbios_mode[search_idx].mode_no[0] != 0) {
1564 if( (var->xres <= sisbios_mode[search_idx].xres) &&
1565 (var->yres <= sisbios_mode[search_idx].yres) &&
1566 (var->bits_per_pixel == sisbios_mode[search_idx].bpp) ) {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001567 if((tidx = sisfb_validate_mode(ivideo,search_idx,
1568 ivideo->currentvbflags)) > 0) {
1569 found_mode = 1;
1570 search_idx = tidx;
1571 break;
1572 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001573 }
1574 search_idx++;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001575 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001576 if(found_mode) {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001577 printk(KERN_DEBUG
1578 "sisfb: Adapted from %dx%dx%d to %dx%dx%d\n",
1579 var->xres, var->yres, var->bits_per_pixel,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001580 sisbios_mode[search_idx].xres,
1581 sisbios_mode[search_idx].yres,
1582 var->bits_per_pixel);
1583 var->xres = sisbios_mode[search_idx].xres;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001584 var->yres = sisbios_mode[search_idx].yres;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001585 } else {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001586 printk(KERN_ERR
1587 "sisfb: Failed to find supported mode near %dx%dx%d\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07001588 var->xres, var->yres, var->bits_per_pixel);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001589 return -EINVAL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001590 }
1591 }
1592
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001593 if( ((ivideo->vbflags2 & VB2_LVDS) ||
1594 ((ivideo->vbflags2 & VB2_30xBDH) && (ivideo->currentvbflags & CRT2_LCD))) &&
Linus Torvalds1da177e2005-04-16 15:20:36 -07001595 (var->bits_per_pixel == 8) ) {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001596 /* Slave modes on LVDS and 301B-DH */
1597 refresh_rate = 60;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001598 recalc_clock = TRUE;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001599 } else if( (ivideo->current_htotal == htotal) &&
1600 (ivideo->current_vtotal == vtotal) &&
1601 (ivideo->current_pixclock == pixclock) ) {
1602 /* x=x & y=y & c=c -> assume depth change */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001603 drate = 1000000000 / pixclock;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001604 hrate = (drate * 1000) / htotal;
1605 refresh_rate = (unsigned int) (hrate * 2 / vtotal);
1606 } else if( ( (ivideo->current_htotal != htotal) ||
1607 (ivideo->current_vtotal != vtotal) ) &&
1608 (ivideo->current_pixclock == var->pixclock) ) {
1609 /* x!=x | y!=y & c=c -> invalid pixclock */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001610 if(ivideo->sisfb_lastrates[sisbios_mode[search_idx].mode_no[ivideo->mni]]) {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001611 refresh_rate =
1612 ivideo->sisfb_lastrates[sisbios_mode[search_idx].mode_no[ivideo->mni]];
Linus Torvalds1da177e2005-04-16 15:20:36 -07001613 } else if(ivideo->sisfb_parm_rate != -1) {
1614 /* Sic, sisfb_parm_rate - want to know originally desired rate here */
1615 refresh_rate = ivideo->sisfb_parm_rate;
1616 } else {
1617 refresh_rate = 60;
1618 }
1619 recalc_clock = TRUE;
1620 } else if((pixclock) && (htotal) && (vtotal)) {
1621 drate = 1000000000 / pixclock;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001622 hrate = (drate * 1000) / htotal;
1623 refresh_rate = (unsigned int) (hrate * 2 / vtotal);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001624 } else if(ivideo->current_refresh_rate) {
1625 refresh_rate = ivideo->current_refresh_rate;
1626 recalc_clock = TRUE;
1627 } else {
1628 refresh_rate = 60;
1629 recalc_clock = TRUE;
1630 }
1631
1632 myrateindex = sisfb_search_refresh_rate(ivideo, refresh_rate, search_idx);
1633
1634 /* Eventually recalculate timing and clock */
1635 if(recalc_clock) {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001636 if(!myrateindex) myrateindex = sisbios_mode[search_idx].rate_idx;
1637 var->pixclock = (u32) (1000000000 / sisfb_mode_rate_to_dclock(&ivideo->SiS_Pr,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001638 sisbios_mode[search_idx].mode_no[ivideo->mni],
1639 myrateindex));
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001640 sisfb_mode_rate_to_ddata(&ivideo->SiS_Pr,
1641 sisbios_mode[search_idx].mode_no[ivideo->mni],
1642 myrateindex, var);
1643 if((var->vmode & FB_VMODE_MASK) == FB_VMODE_DOUBLE) {
1644 var->pixclock <<= 1;
1645 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001646 }
1647
1648 if(ivideo->sisfb_thismonitor.datavalid) {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001649 if(!sisfb_verify_rate(ivideo, &ivideo->sisfb_thismonitor, search_idx,
1650 myrateindex, refresh_rate)) {
1651 printk(KERN_INFO
1652 "sisfb: WARNING: Refresh rate exceeds monitor specs!\n");
1653 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001654 }
1655
1656 /* Adapt RGB settings */
1657 sisfb_bpp_to_var(ivideo, var);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001658
Linus Torvalds1da177e2005-04-16 15:20:36 -07001659 /* Sanity check for offsets */
1660 if(var->xoffset < 0) var->xoffset = 0;
1661 if(var->yoffset < 0) var->yoffset = 0;
1662
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001663 if(var->xres > var->xres_virtual)
1664 var->xres_virtual = var->xres;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001665
1666 if(ivideo->sisfb_ypan) {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001667 maxyres = sisfb_calc_maxyres(ivideo, var);
1668 if(ivideo->sisfb_max) {
1669 var->yres_virtual = maxyres;
1670 } else {
1671 if(var->yres_virtual > maxyres) {
1672 var->yres_virtual = maxyres;
1673 }
1674 }
1675 if(var->yres_virtual <= var->yres) {
1676 var->yres_virtual = var->yres;
1677 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001678 } else {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001679 if(var->yres != var->yres_virtual) {
1680 var->yres_virtual = var->yres;
1681 }
1682 var->xoffset = 0;
1683 var->yoffset = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001684 }
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001685
Linus Torvalds1da177e2005-04-16 15:20:36 -07001686 /* Truncate offsets to maximum if too high */
1687 if(var->xoffset > var->xres_virtual - var->xres) {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001688 var->xoffset = var->xres_virtual - var->xres - 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001689 }
1690
1691 if(var->yoffset > var->yres_virtual - var->yres) {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001692 var->yoffset = var->yres_virtual - var->yres - 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001693 }
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001694
Linus Torvalds1da177e2005-04-16 15:20:36 -07001695 /* Set everything else to 0 */
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001696 var->red.msb_right =
1697 var->green.msb_right =
1698 var->blue.msb_right =
1699 var->transp.offset =
1700 var->transp.length =
1701 var->transp.msb_right = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001702
1703 return 0;
1704}
1705
1706static int
1707sisfb_pan_display(struct fb_var_screeninfo *var, struct fb_info* info)
1708{
1709 struct sis_video_info *ivideo = (struct sis_video_info *)info->par;
1710 int err;
1711
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001712 if(var->xoffset > (var->xres_virtual - var->xres))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001713 return -EINVAL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001714
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001715 if(var->yoffset > (var->yres_virtual - var->yres))
1716 return -EINVAL;
1717
1718 if(var->vmode & FB_VMODE_YWRAP)
1719 return -EINVAL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001720
1721 if(var->xoffset + info->var.xres > info->var.xres_virtual ||
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001722 var->yoffset + info->var.yres > info->var.yres_virtual)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001723 return -EINVAL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001724
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001725 if((err = sisfb_pan_var(ivideo, var)) < 0)
1726 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001727
1728 info->var.xoffset = var->xoffset;
1729 info->var.yoffset = var->yoffset;
1730
1731 return 0;
1732}
1733
1734static int
1735sisfb_blank(int blank, struct fb_info *info)
1736{
1737 struct sis_video_info *ivideo = (struct sis_video_info *)info->par;
1738
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001739 return sisfb_myblank(ivideo, blank);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001740}
1741
1742#endif
1743
1744/* ----------- FBDev related routines for all series ---------- */
1745
Christoph Hellwig67a66802006-01-14 13:21:25 -08001746#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,15)
1747static int sisfb_ioctl(struct fb_info *info, unsigned int cmd,
1748 unsigned long arg)
1749#else
1750static int sisfb_ioctl(struct inode *inode, struct file *file,
1751 unsigned int cmd, unsigned long arg,
1752 struct fb_info *info)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001753#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -07001754{
1755 struct sis_video_info *ivideo = (struct sis_video_info *)info->par;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001756 struct sis_memreq sismemreq;
1757 struct fb_vblank sisvbblank;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001758 u32 gpu32 = 0;
1759#ifndef __user
1760#define __user
1761#endif
1762 u32 __user *argp = (u32 __user *)arg;
1763
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001764 switch(cmd) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001765 case FBIO_ALLOC:
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001766 if(!capable(CAP_SYS_RAWIO))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001767 return -EPERM;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001768
1769 if(copy_from_user(&sismemreq, (void __user *)arg, sizeof(sismemreq)))
1770 return -EFAULT;
1771
Linus Torvalds1da177e2005-04-16 15:20:36 -07001772 sis_malloc(&sismemreq);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001773
Linus Torvalds1da177e2005-04-16 15:20:36 -07001774 if(copy_to_user((void __user *)arg, &sismemreq, sizeof(sismemreq))) {
1775 sis_free((u32)sismemreq.offset);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001776 return -EFAULT;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001777 }
1778 break;
1779
1780 case FBIO_FREE:
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001781 if(!capable(CAP_SYS_RAWIO))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001782 return -EPERM;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001783
1784 if(get_user(gpu32, argp))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001785 return -EFAULT;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001786
Linus Torvalds1da177e2005-04-16 15:20:36 -07001787 sis_free(gpu32);
1788 break;
1789
1790 case FBIOGET_VBLANK:
1791 sisvbblank.count = 0;
1792 sisvbblank.flags = sisfb_setupvbblankflags(ivideo, &sisvbblank.vcount, &sisvbblank.hcount);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001793
1794 if(copy_to_user((void __user *)arg, &sisvbblank, sizeof(sisvbblank)))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001795 return -EFAULT;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001796
Linus Torvalds1da177e2005-04-16 15:20:36 -07001797 break;
1798
1799 case SISFB_GET_INFO_SIZE:
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001800 return put_user(sizeof(struct sisfb_info), argp);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001801
1802 case SISFB_GET_INFO_OLD:
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001803 if(ivideo->warncount++ < 10)
1804 printk(KERN_INFO
1805 "sisfb: Deprecated ioctl call received - update your application!\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001806 case SISFB_GET_INFO: /* For communication with X driver */
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001807 ivideo->sisfb_infoblock.sisfb_id = SISFB_ID;
1808 ivideo->sisfb_infoblock.sisfb_version = VER_MAJOR;
1809 ivideo->sisfb_infoblock.sisfb_revision = VER_MINOR;
1810 ivideo->sisfb_infoblock.sisfb_patchlevel = VER_LEVEL;
1811 ivideo->sisfb_infoblock.chip_id = ivideo->chip_id;
1812 ivideo->sisfb_infoblock.sisfb_pci_vendor = ivideo->chip_vendor;
1813 ivideo->sisfb_infoblock.memory = ivideo->video_size / 1024;
1814 ivideo->sisfb_infoblock.heapstart = ivideo->heapstart / 1024;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001815 if(ivideo->modechanged) {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001816 ivideo->sisfb_infoblock.fbvidmode = ivideo->mode_no;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001817 } else {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001818 ivideo->sisfb_infoblock.fbvidmode = ivideo->modeprechange;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001819 }
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001820 ivideo->sisfb_infoblock.sisfb_caps = ivideo->caps;
1821 ivideo->sisfb_infoblock.sisfb_tqlen = ivideo->cmdQueueSize / 1024;
1822 ivideo->sisfb_infoblock.sisfb_pcibus = ivideo->pcibus;
1823 ivideo->sisfb_infoblock.sisfb_pcislot = ivideo->pcislot;
1824 ivideo->sisfb_infoblock.sisfb_pcifunc = ivideo->pcifunc;
1825 ivideo->sisfb_infoblock.sisfb_lcdpdc = ivideo->detectedpdc;
1826 ivideo->sisfb_infoblock.sisfb_lcdpdca = ivideo->detectedpdca;
1827 ivideo->sisfb_infoblock.sisfb_lcda = ivideo->detectedlcda;
1828 ivideo->sisfb_infoblock.sisfb_vbflags = ivideo->vbflags;
1829 ivideo->sisfb_infoblock.sisfb_currentvbflags = ivideo->currentvbflags;
1830 ivideo->sisfb_infoblock.sisfb_scalelcd = ivideo->SiS_Pr.UsePanelScaler;
1831 ivideo->sisfb_infoblock.sisfb_specialtiming = ivideo->SiS_Pr.SiS_CustomT;
1832 ivideo->sisfb_infoblock.sisfb_haveemi = ivideo->SiS_Pr.HaveEMI ? 1 : 0;
1833 ivideo->sisfb_infoblock.sisfb_haveemilcd = ivideo->SiS_Pr.HaveEMILCD ? 1 : 0;
1834 ivideo->sisfb_infoblock.sisfb_emi30 = ivideo->SiS_Pr.EMI_30;
1835 ivideo->sisfb_infoblock.sisfb_emi31 = ivideo->SiS_Pr.EMI_31;
1836 ivideo->sisfb_infoblock.sisfb_emi32 = ivideo->SiS_Pr.EMI_32;
1837 ivideo->sisfb_infoblock.sisfb_emi33 = ivideo->SiS_Pr.EMI_33;
1838 ivideo->sisfb_infoblock.sisfb_tvxpos = (u16)(ivideo->tvxpos + 32);
1839 ivideo->sisfb_infoblock.sisfb_tvypos = (u16)(ivideo->tvypos + 32);
1840 ivideo->sisfb_infoblock.sisfb_heapsize = ivideo->sisfb_heap_size / 1024;
1841 ivideo->sisfb_infoblock.sisfb_videooffset = ivideo->video_offset;
1842 ivideo->sisfb_infoblock.sisfb_curfstn = ivideo->curFSTN;
1843 ivideo->sisfb_infoblock.sisfb_curdstn = ivideo->curDSTN;
1844 ivideo->sisfb_infoblock.sisfb_vbflags2 = ivideo->vbflags2;
1845 ivideo->sisfb_infoblock.sisfb_can_post = ivideo->sisfb_can_post ? 1 : 0;
1846 ivideo->sisfb_infoblock.sisfb_card_posted = ivideo->sisfb_card_posted ? 1 : 0;
1847 ivideo->sisfb_infoblock.sisfb_was_boot_device = ivideo->sisfb_was_boot_device ? 1 : 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001848
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001849 if(copy_to_user((void __user *)arg, &ivideo->sisfb_infoblock,
1850 sizeof(ivideo->sisfb_infoblock)))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001851 return -EFAULT;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001852
Linus Torvalds1da177e2005-04-16 15:20:36 -07001853 break;
1854
1855 case SISFB_GET_VBRSTATUS_OLD:
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001856 if(ivideo->warncount++ < 10)
1857 printk(KERN_INFO
1858 "sisfb: Deprecated ioctl call received - update your application!\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001859 case SISFB_GET_VBRSTATUS:
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001860 if(sisfb_CheckVBRetrace(ivideo))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001861 return put_user((u32)1, argp);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001862 else
Linus Torvalds1da177e2005-04-16 15:20:36 -07001863 return put_user((u32)0, argp);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001864
1865 case SISFB_GET_AUTOMAXIMIZE_OLD:
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001866 if(ivideo->warncount++ < 10)
1867 printk(KERN_INFO
1868 "sisfb: Deprecated ioctl call received - update your application!\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001869 case SISFB_GET_AUTOMAXIMIZE:
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001870 if(ivideo->sisfb_max)
1871 return put_user((u32)1, argp);
1872 else
1873 return put_user((u32)0, argp);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001874
1875 case SISFB_SET_AUTOMAXIMIZE_OLD:
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001876 if(ivideo->warncount++ < 10)
1877 printk(KERN_INFO
1878 "sisfb: Deprecated ioctl call received - update your application!\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001879 case SISFB_SET_AUTOMAXIMIZE:
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001880 if(get_user(gpu32, argp))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001881 return -EFAULT;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001882
Linus Torvalds1da177e2005-04-16 15:20:36 -07001883 ivideo->sisfb_max = (gpu32) ? 1 : 0;
1884 break;
1885
1886 case SISFB_SET_TVPOSOFFSET:
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001887 if(get_user(gpu32, argp))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001888 return -EFAULT;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001889
Linus Torvalds1da177e2005-04-16 15:20:36 -07001890 sisfb_set_TVxposoffset(ivideo, ((int)(gpu32 >> 16)) - 32);
1891 sisfb_set_TVyposoffset(ivideo, ((int)(gpu32 & 0xffff)) - 32);
1892 break;
1893
1894 case SISFB_GET_TVPOSOFFSET:
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001895 return put_user((u32)(((ivideo->tvxpos+32)<<16)|((ivideo->tvypos+32)&0xffff)),
1896 argp);
1897
1898 case SISFB_COMMAND:
1899 if(copy_from_user(&ivideo->sisfb_command, (void __user *)arg,
1900 sizeof(struct sisfb_cmd)))
1901 return -EFAULT;
1902
1903 sisfb_handle_command(ivideo, &ivideo->sisfb_command);
1904
1905 if(copy_to_user((void __user *)arg, &ivideo->sisfb_command,
1906 sizeof(struct sisfb_cmd)))
1907 return -EFAULT;
1908
1909 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001910
1911 case SISFB_SET_LOCK:
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001912 if(get_user(gpu32, argp))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001913 return -EFAULT;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001914
Linus Torvalds1da177e2005-04-16 15:20:36 -07001915 ivideo->sisfblocked = (gpu32) ? 1 : 0;
1916 break;
1917
1918 default:
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001919#ifdef SIS_NEW_CONFIG_COMPAT
Linus Torvalds1da177e2005-04-16 15:20:36 -07001920 return -ENOIOCTLCMD;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001921#else
1922 return -EINVAL;
1923#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -07001924 }
1925 return 0;
1926}
1927
Linus Torvalds1da177e2005-04-16 15:20:36 -07001928static int
1929sisfb_get_fix(struct fb_fix_screeninfo *fix, int con, struct fb_info *info)
1930{
1931 struct sis_video_info *ivideo = (struct sis_video_info *)info->par;
1932
1933 memset(fix, 0, sizeof(struct fb_fix_screeninfo));
1934
1935 strcpy(fix->id, ivideo->myid);
1936
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001937 fix->smem_start = ivideo->video_base + ivideo->video_offset;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001938 fix->smem_len = ivideo->sisfb_mem;
1939 fix->type = FB_TYPE_PACKED_PIXELS;
1940 fix->type_aux = 0;
1941 fix->visual = (ivideo->video_bpp == 8) ? FB_VISUAL_PSEUDOCOLOR : FB_VISUAL_TRUECOLOR;
1942 fix->xpanstep = 1;
1943 fix->ypanstep = (ivideo->sisfb_ypan) ? 1 : 0;
1944 fix->ywrapstep = 0;
1945 fix->line_length = ivideo->video_linelength;
1946 fix->mmio_start = ivideo->mmio_base;
1947 fix->mmio_len = ivideo->mmio_size;
1948 if(ivideo->sisvga_engine == SIS_300_VGA) {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001949 fix->accel = FB_ACCEL_SIS_GLAMOUR;
1950 } else if((ivideo->chip == SIS_330) ||
1951 (ivideo->chip == SIS_760) ||
1952 (ivideo->chip == SIS_761)) {
1953 fix->accel = FB_ACCEL_SIS_XABRE;
1954 } else if(ivideo->chip == XGI_20) {
1955 fix->accel = FB_ACCEL_XGI_VOLARI_Z;
1956 } else if(ivideo->chip >= XGI_40) {
1957 fix->accel = FB_ACCEL_XGI_VOLARI_V;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001958 } else {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001959 fix->accel = FB_ACCEL_SIS_GLAMOUR_2;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001960 }
1961
1962 return 0;
1963}
1964
1965/* ---------------- fb_ops structures ----------------- */
1966
1967#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
1968static struct fb_ops sisfb_ops = {
1969 .owner = THIS_MODULE,
1970 .fb_get_fix = sisfb_get_fix,
1971 .fb_get_var = sisfb_get_var,
1972 .fb_set_var = sisfb_set_var,
1973 .fb_get_cmap = sisfb_get_cmap,
1974 .fb_set_cmap = sisfb_set_cmap,
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001975 .fb_pan_display = sisfb_pan_display,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001976 .fb_ioctl = sisfb_ioctl
1977};
1978#endif
1979
1980#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0)
1981static struct fb_ops sisfb_ops = {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001982 .owner = THIS_MODULE,
1983 .fb_open = sisfb_open,
1984 .fb_release = sisfb_release,
1985 .fb_check_var = sisfb_check_var,
1986 .fb_set_par = sisfb_set_par,
1987 .fb_setcolreg = sisfb_setcolreg,
1988 .fb_pan_display = sisfb_pan_display,
1989 .fb_blank = sisfb_blank,
1990 .fb_fillrect = fbcon_sis_fillrect,
1991 .fb_copyarea = fbcon_sis_copyarea,
1992 .fb_imageblit = cfb_imageblit,
Antonino A. Daplasc465e052005-11-07 01:00:35 -08001993#ifdef CONFIG_FB_SOFT_CURSOR
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001994 .fb_cursor = soft_cursor,
Antonino A. Daplasc465e052005-11-07 01:00:35 -08001995#endif
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001996 .fb_sync = fbcon_sis_sync,
1997#ifdef SIS_NEW_CONFIG_COMPAT
Christoph Hellwig67a66802006-01-14 13:21:25 -08001998 .fb_compat_ioctl= sisfb_ioctl,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001999#endif
Thomas Winischhofer544393f2005-09-09 13:04:45 -07002000 .fb_ioctl = sisfb_ioctl
Linus Torvalds1da177e2005-04-16 15:20:36 -07002001};
2002#endif
2003
2004/* ---------------- Chip generation dependent routines ---------------- */
2005
Thomas Winischhofer544393f2005-09-09 13:04:45 -07002006static struct pci_dev * __devinit
2007sisfb_get_northbridge(int basechipid)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002008{
2009 struct pci_dev *pdev = NULL;
2010 int nbridgenum, nbridgeidx, i;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07002011 static const unsigned short nbridgeids[] = {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002012 PCI_DEVICE_ID_SI_540, /* for SiS 540 VGA */
2013 PCI_DEVICE_ID_SI_630, /* for SiS 630/730 VGA */
2014 PCI_DEVICE_ID_SI_730,
2015 PCI_DEVICE_ID_SI_550, /* for SiS 550 VGA */
2016 PCI_DEVICE_ID_SI_650, /* for SiS 650/651/740 VGA */
2017 PCI_DEVICE_ID_SI_651,
2018 PCI_DEVICE_ID_SI_740,
Thomas Winischhofer544393f2005-09-09 13:04:45 -07002019 PCI_DEVICE_ID_SI_661, /* for SiS 661/741/660/760/761 VGA */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002020 PCI_DEVICE_ID_SI_741,
2021 PCI_DEVICE_ID_SI_660,
Thomas Winischhofer544393f2005-09-09 13:04:45 -07002022 PCI_DEVICE_ID_SI_760,
2023 PCI_DEVICE_ID_SI_761
Linus Torvalds1da177e2005-04-16 15:20:36 -07002024 };
2025
Thomas Winischhofer544393f2005-09-09 13:04:45 -07002026 switch(basechipid) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002027#ifdef CONFIG_FB_SIS_300
2028 case SIS_540: nbridgeidx = 0; nbridgenum = 1; break;
2029 case SIS_630: nbridgeidx = 1; nbridgenum = 2; break;
2030#endif
2031#ifdef CONFIG_FB_SIS_315
2032 case SIS_550: nbridgeidx = 3; nbridgenum = 1; break;
2033 case SIS_650: nbridgeidx = 4; nbridgenum = 3; break;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07002034 case SIS_660: nbridgeidx = 7; nbridgenum = 5; break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002035#endif
2036 default: return NULL;
2037 }
2038 for(i = 0; i < nbridgenum; i++) {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07002039 if((pdev = SIS_PCI_GET_DEVICE(PCI_VENDOR_ID_SI,
2040 nbridgeids[nbridgeidx+i], NULL)))
2041 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002042 }
2043 return pdev;
2044}
2045
Thomas Winischhofer544393f2005-09-09 13:04:45 -07002046static int __devinit
2047sisfb_get_dram_size(struct sis_video_info *ivideo)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002048{
2049#if defined(CONFIG_FB_SIS_300) || defined(CONFIG_FB_SIS_315)
2050 u8 reg;
2051#endif
2052
2053 ivideo->video_size = 0;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07002054 ivideo->UMAsize = ivideo->LFBsize = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002055
2056 switch(ivideo->chip) {
2057#ifdef CONFIG_FB_SIS_300
2058 case SIS_300:
Thomas Winischhofer544393f2005-09-09 13:04:45 -07002059 inSISIDXREG(SISSR, 0x14, reg);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002060 ivideo->video_size = ((reg & 0x3F) + 1) << 20;
2061 break;
2062 case SIS_540:
2063 case SIS_630:
2064 case SIS_730:
Thomas Winischhofer544393f2005-09-09 13:04:45 -07002065 if(!ivideo->nbridge)
2066 return -1;
2067 pci_read_config_byte(ivideo->nbridge, 0x63, &reg);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002068 ivideo->video_size = 1 << (((reg & 0x70) >> 4) + 21);
2069 break;
2070#endif
2071#ifdef CONFIG_FB_SIS_315
2072 case SIS_315H:
2073 case SIS_315PRO:
2074 case SIS_315:
Thomas Winischhofer544393f2005-09-09 13:04:45 -07002075 inSISIDXREG(SISSR, 0x14, reg);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002076 ivideo->video_size = (1 << ((reg & 0xf0) >> 4)) << 20;
2077 switch((reg >> 2) & 0x03) {
2078 case 0x01:
2079 case 0x03:
Thomas Winischhofer544393f2005-09-09 13:04:45 -07002080 ivideo->video_size <<= 1;
2081 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002082 case 0x02:
Thomas Winischhofer544393f2005-09-09 13:04:45 -07002083 ivideo->video_size += (ivideo->video_size/2);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002084 }
Thomas Winischhofer544393f2005-09-09 13:04:45 -07002085 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002086 case SIS_330:
Thomas Winischhofer544393f2005-09-09 13:04:45 -07002087 inSISIDXREG(SISSR, 0x14, reg);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002088 ivideo->video_size = (1 << ((reg & 0xf0) >> 4)) << 20;
2089 if(reg & 0x0c) ivideo->video_size <<= 1;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07002090 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002091 case SIS_550:
2092 case SIS_650:
2093 case SIS_740:
Thomas Winischhofer544393f2005-09-09 13:04:45 -07002094 inSISIDXREG(SISSR, 0x14, reg);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002095 ivideo->video_size = (((reg & 0x3f) + 1) << 2) << 20;
2096 break;
2097 case SIS_661:
2098 case SIS_741:
Thomas Winischhofer544393f2005-09-09 13:04:45 -07002099 inSISIDXREG(SISCR, 0x79, reg);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002100 ivideo->video_size = (1 << ((reg & 0xf0) >> 4)) << 20;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07002101 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002102 case SIS_660:
2103 case SIS_760:
Thomas Winischhofer544393f2005-09-09 13:04:45 -07002104 case SIS_761:
Linus Torvalds1da177e2005-04-16 15:20:36 -07002105 inSISIDXREG(SISCR, 0x79, reg);
2106 reg = (reg & 0xf0) >> 4;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07002107 if(reg) {
2108 ivideo->video_size = (1 << reg) << 20;
2109 ivideo->UMAsize = ivideo->video_size;
2110 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002111 inSISIDXREG(SISCR, 0x78, reg);
2112 reg &= 0x30;
2113 if(reg) {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07002114 if(reg == 0x10) {
2115 ivideo->LFBsize = (32 << 20);
2116 } else {
2117 ivideo->LFBsize = (64 << 20);
2118 }
2119 ivideo->video_size += ivideo->LFBsize;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002120 }
Thomas Winischhofer544393f2005-09-09 13:04:45 -07002121 break;
2122 case SIS_340:
2123 case XGI_20:
2124 case XGI_40:
2125 inSISIDXREG(SISSR, 0x14, reg);
2126 ivideo->video_size = (1 << ((reg & 0xf0) >> 4)) << 20;
2127 if(ivideo->chip != XGI_20) {
2128 reg = (reg & 0x0c) >> 2;
2129 if(ivideo->revision_id == 2) {
2130 if(reg & 0x01) reg = 0x02;
2131 else reg = 0x00;
2132 }
2133 if(reg == 0x02) ivideo->video_size <<= 1;
2134 else if(reg == 0x03) ivideo->video_size <<= 2;
2135 }
2136 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002137#endif
2138 default:
2139 return -1;
2140 }
2141 return 0;
2142}
2143
2144/* -------------- video bridge device detection --------------- */
2145
Thomas Winischhofer544393f2005-09-09 13:04:45 -07002146static void __devinit
2147sisfb_detect_VB_connect(struct sis_video_info *ivideo)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002148{
2149 u8 cr32, temp;
2150
Thomas Winischhofer544393f2005-09-09 13:04:45 -07002151 /* No CRT2 on XGI Z7 */
2152 if(ivideo->chip == XGI_20) {
2153 ivideo->sisfb_crt1off = 0;
2154 return;
2155 }
2156
Linus Torvalds1da177e2005-04-16 15:20:36 -07002157#ifdef CONFIG_FB_SIS_300
2158 if(ivideo->sisvga_engine == SIS_300_VGA) {
2159 inSISIDXREG(SISSR, 0x17, temp);
2160 if((temp & 0x0F) && (ivideo->chip != SIS_300)) {
2161 /* PAL/NTSC is stored on SR16 on such machines */
2162 if(!(ivideo->vbflags & (TV_PAL | TV_NTSC | TV_PALM | TV_PALN))) {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07002163 inSISIDXREG(SISSR, 0x16, temp);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002164 if(temp & 0x20)
2165 ivideo->vbflags |= TV_PAL;
2166 else
2167 ivideo->vbflags |= TV_NTSC;
2168 }
2169 }
2170 }
2171#endif
2172
2173 inSISIDXREG(SISCR, 0x32, cr32);
2174
2175 if(cr32 & SIS_CRT1) {
2176 ivideo->sisfb_crt1off = 0;
2177 } else {
2178 ivideo->sisfb_crt1off = (cr32 & 0xDF) ? 1 : 0;
2179 }
2180
2181 ivideo->vbflags &= ~(CRT2_TV | CRT2_LCD | CRT2_VGA);
2182
2183 if(cr32 & SIS_VB_TV) ivideo->vbflags |= CRT2_TV;
2184 if(cr32 & SIS_VB_LCD) ivideo->vbflags |= CRT2_LCD;
2185 if(cr32 & SIS_VB_CRT2) ivideo->vbflags |= CRT2_VGA;
2186
2187 /* Check given parms for hardware compatibility.
2188 * (Cannot do this in the search_xx routines since we don't
2189 * know what hardware we are running on then)
2190 */
2191
2192 if(ivideo->chip != SIS_550) {
2193 ivideo->sisfb_dstn = ivideo->sisfb_fstn = 0;
2194 }
2195
2196 if(ivideo->sisfb_tvplug != -1) {
2197 if( (ivideo->sisvga_engine != SIS_315_VGA) ||
Thomas Winischhofer544393f2005-09-09 13:04:45 -07002198 (!(ivideo->vbflags2 & VB2_SISYPBPRBRIDGE)) ) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002199 if(ivideo->sisfb_tvplug & TV_YPBPR) {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07002200 ivideo->sisfb_tvplug = -1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002201 printk(KERN_ERR "sisfb: YPbPr not supported\n");
2202 }
2203 }
2204 }
2205 if(ivideo->sisfb_tvplug != -1) {
2206 if( (ivideo->sisvga_engine != SIS_315_VGA) ||
Thomas Winischhofer544393f2005-09-09 13:04:45 -07002207 (!(ivideo->vbflags2 & VB2_SISHIVISIONBRIDGE)) ) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002208 if(ivideo->sisfb_tvplug & TV_HIVISION) {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07002209 ivideo->sisfb_tvplug = -1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002210 printk(KERN_ERR "sisfb: HiVision not supported\n");
2211 }
2212 }
2213 }
2214 if(ivideo->sisfb_tvstd != -1) {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07002215 if( (!(ivideo->vbflags2 & VB2_SISBRIDGE)) &&
2216 (!((ivideo->sisvga_engine == SIS_315_VGA) &&
2217 (ivideo->vbflags2 & VB2_CHRONTEL))) ) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002218 if(ivideo->sisfb_tvstd & (TV_PALN | TV_PALN | TV_NTSCJ)) {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07002219 ivideo->sisfb_tvstd = -1;
2220 printk(KERN_ERR "sisfb: PALM/PALN/NTSCJ not supported\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002221 }
2222 }
2223 }
2224
2225 /* Detect/set TV plug & type */
2226 if(ivideo->sisfb_tvplug != -1) {
2227 ivideo->vbflags |= ivideo->sisfb_tvplug;
2228 } else {
2229 if(cr32 & SIS_VB_YPBPR) ivideo->vbflags |= (TV_YPBPR|TV_YPBPR525I); /* default: 480i */
2230 else if(cr32 & SIS_VB_HIVISION) ivideo->vbflags |= TV_HIVISION;
2231 else if(cr32 & SIS_VB_SCART) ivideo->vbflags |= TV_SCART;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07002232 else {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002233 if(cr32 & SIS_VB_SVIDEO) ivideo->vbflags |= TV_SVIDEO;
2234 if(cr32 & SIS_VB_COMPOSITE) ivideo->vbflags |= TV_AVIDEO;
2235 }
2236 }
2237
2238 if(!(ivideo->vbflags & (TV_YPBPR | TV_HIVISION))) {
2239 if(ivideo->sisfb_tvstd != -1) {
2240 ivideo->vbflags &= ~(TV_NTSC | TV_PAL | TV_PALM | TV_PALN | TV_NTSCJ);
2241 ivideo->vbflags |= ivideo->sisfb_tvstd;
2242 }
2243 if(ivideo->vbflags & TV_SCART) {
2244 ivideo->vbflags &= ~(TV_NTSC | TV_PALM | TV_PALN | TV_NTSCJ);
2245 ivideo->vbflags |= TV_PAL;
2246 }
2247 if(!(ivideo->vbflags & (TV_PAL | TV_NTSC | TV_PALM | TV_PALN | TV_NTSCJ))) {
2248 if(ivideo->sisvga_engine == SIS_300_VGA) {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07002249 inSISIDXREG(SISSR, 0x38, temp);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002250 if(temp & 0x01) ivideo->vbflags |= TV_PAL;
2251 else ivideo->vbflags |= TV_NTSC;
2252 } else if((ivideo->chip <= SIS_315PRO) || (ivideo->chip >= SIS_330)) {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07002253 inSISIDXREG(SISSR, 0x38, temp);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002254 if(temp & 0x01) ivideo->vbflags |= TV_PAL;
2255 else ivideo->vbflags |= TV_NTSC;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07002256 } else {
2257 inSISIDXREG(SISCR, 0x79, temp);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002258 if(temp & 0x20) ivideo->vbflags |= TV_PAL;
2259 else ivideo->vbflags |= TV_NTSC;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07002260 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002261 }
2262 }
2263
2264 /* Copy forceCRT1 option to CRT1off if option is given */
Thomas Winischhofer544393f2005-09-09 13:04:45 -07002265 if(ivideo->sisfb_forcecrt1 != -1) {
2266 ivideo->sisfb_crt1off = (ivideo->sisfb_forcecrt1) ? 0 : 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002267 }
2268}
2269
2270/* ------------------ Sensing routines ------------------ */
2271
Thomas Winischhofer544393f2005-09-09 13:04:45 -07002272static BOOLEAN __devinit
2273sisfb_test_DDC1(struct sis_video_info *ivideo)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002274{
2275 unsigned short old;
2276 int count = 48;
2277
2278 old = SiS_ReadDDC1Bit(&ivideo->SiS_Pr);
2279 do {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07002280 if(old != SiS_ReadDDC1Bit(&ivideo->SiS_Pr)) break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002281 } while(count--);
2282 return (count == -1) ? FALSE : TRUE;
2283}
2284
Thomas Winischhofer544393f2005-09-09 13:04:45 -07002285static void __devinit
2286sisfb_sense_crt1(struct sis_video_info *ivideo)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002287{
2288 BOOLEAN mustwait = FALSE;
2289 u8 sr1F, cr17;
2290#ifdef CONFIG_FB_SIS_315
2291 u8 cr63=0;
2292#endif
2293 u16 temp = 0xffff;
2294 int i;
2295
2296 inSISIDXREG(SISSR,0x1F,sr1F);
2297 orSISIDXREG(SISSR,0x1F,0x04);
2298 andSISIDXREG(SISSR,0x1F,0x3F);
2299 if(sr1F & 0xc0) mustwait = TRUE;
2300
2301#ifdef CONFIG_FB_SIS_315
2302 if(ivideo->sisvga_engine == SIS_315_VGA) {
2303 inSISIDXREG(SISCR,ivideo->SiS_Pr.SiS_MyCR63,cr63);
2304 cr63 &= 0x40;
2305 andSISIDXREG(SISCR,ivideo->SiS_Pr.SiS_MyCR63,0xBF);
2306 }
2307#endif
2308
2309 inSISIDXREG(SISCR,0x17,cr17);
2310 cr17 &= 0x80;
2311 if(!cr17) {
2312 orSISIDXREG(SISCR,0x17,0x80);
2313 mustwait = TRUE;
2314 outSISIDXREG(SISSR, 0x00, 0x01);
2315 outSISIDXREG(SISSR, 0x00, 0x03);
2316 }
2317
2318 if(mustwait) {
2319 for(i=0; i < 10; i++) sisfbwaitretracecrt1(ivideo);
2320 }
2321
2322#ifdef CONFIG_FB_SIS_315
2323 if(ivideo->chip >= SIS_330) {
2324 andSISIDXREG(SISCR,0x32,~0x20);
2325 if(ivideo->chip >= SIS_340) {
2326 outSISIDXREG(SISCR, 0x57, 0x4a);
2327 } else {
2328 outSISIDXREG(SISCR, 0x57, 0x5f);
2329 }
2330 orSISIDXREG(SISCR, 0x53, 0x02);
2331 while((inSISREG(SISINPSTAT)) & 0x01) break;
2332 while(!((inSISREG(SISINPSTAT)) & 0x01)) break;
2333 if((inSISREG(SISMISCW)) & 0x10) temp = 1;
2334 andSISIDXREG(SISCR, 0x53, 0xfd);
2335 andSISIDXREG(SISCR, 0x57, 0x00);
2336 }
2337#endif
2338
2339 if(temp == 0xffff) {
2340 i = 3;
2341 do {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07002342 temp = SiS_HandleDDC(&ivideo->SiS_Pr, ivideo->vbflags,
2343 ivideo->sisvga_engine, 0, 0, NULL, ivideo->vbflags2);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002344 } while(((temp == 0) || (temp == 0xffff)) && i--);
2345
2346 if((temp == 0) || (temp == 0xffff)) {
2347 if(sisfb_test_DDC1(ivideo)) temp = 1;
2348 }
2349 }
2350
2351 if((temp) && (temp != 0xffff)) {
2352 orSISIDXREG(SISCR,0x32,0x20);
2353 }
2354
2355#ifdef CONFIG_FB_SIS_315
2356 if(ivideo->sisvga_engine == SIS_315_VGA) {
2357 setSISIDXREG(SISCR,ivideo->SiS_Pr.SiS_MyCR63,0xBF,cr63);
2358 }
2359#endif
2360
2361 setSISIDXREG(SISCR,0x17,0x7F,cr17);
2362
2363 outSISIDXREG(SISSR,0x1F,sr1F);
2364}
2365
2366/* Determine and detect attached devices on SiS30x */
Thomas Winischhofer544393f2005-09-09 13:04:45 -07002367static void __devinit
2368SiS_SenseLCD(struct sis_video_info *ivideo)
2369{
2370 unsigned char buffer[256];
2371 unsigned short temp, realcrtno, i;
2372 u8 reg, cr37 = 0, paneltype = 0;
2373 u16 xres, yres;
2374
2375 ivideo->SiS_Pr.PanelSelfDetected = FALSE;
2376
2377 /* LCD detection only for TMDS bridges */
2378 if(!(ivideo->vbflags2 & VB2_SISTMDSBRIDGE))
2379 return;
2380 if(ivideo->vbflags2 & VB2_30xBDH)
2381 return;
2382
2383 /* If LCD already set up by BIOS, skip it */
2384 inSISIDXREG(SISCR, 0x32, reg);
2385 if(reg & 0x08)
2386 return;
2387
2388 realcrtno = 1;
2389 if(ivideo->SiS_Pr.DDCPortMixup)
2390 realcrtno = 0;
2391
2392 /* Check DDC capabilities */
2393 temp = SiS_HandleDDC(&ivideo->SiS_Pr, ivideo->vbflags, ivideo->sisvga_engine,
2394 realcrtno, 0, &buffer[0], ivideo->vbflags2);
2395
2396 if((!temp) || (temp == 0xffff) || (!(temp & 0x02)))
2397 return;
2398
2399 /* Read DDC data */
2400 i = 3; /* Number of retrys */
2401 do {
2402 temp = SiS_HandleDDC(&ivideo->SiS_Pr, ivideo->vbflags,
2403 ivideo->sisvga_engine, realcrtno, 1,
2404 &buffer[0], ivideo->vbflags2);
2405 } while((temp) && i--);
2406
2407 if(temp)
2408 return;
2409
2410 /* No digital device */
2411 if(!(buffer[0x14] & 0x80))
2412 return;
2413
2414 /* First detailed timing preferred timing? */
2415 if(!(buffer[0x18] & 0x02))
2416 return;
2417
2418 xres = buffer[0x38] | ((buffer[0x3a] & 0xf0) << 4);
2419 yres = buffer[0x3b] | ((buffer[0x3d] & 0xf0) << 4);
2420
2421 switch(xres) {
2422 case 1024:
2423 if(yres == 768)
2424 paneltype = 0x02;
2425 break;
2426 case 1280:
2427 if(yres == 1024)
2428 paneltype = 0x03;
2429 break;
2430 case 1600:
2431 if((yres == 1200) && (ivideo->vbflags2 & VB2_30xC))
2432 paneltype = 0x0b;
2433 break;
2434 }
2435
2436 if(!paneltype)
2437 return;
2438
2439 if(buffer[0x23])
2440 cr37 |= 0x10;
2441
2442 if((buffer[0x47] & 0x18) == 0x18)
2443 cr37 |= ((((buffer[0x47] & 0x06) ^ 0x06) << 5) | 0x20);
2444 else
2445 cr37 |= 0xc0;
2446
2447 outSISIDXREG(SISCR, 0x36, paneltype);
2448 cr37 &= 0xf1;
2449 setSISIDXREG(SISCR, 0x37, 0x0c, cr37);
2450 orSISIDXREG(SISCR, 0x32, 0x08);
2451
2452 ivideo->SiS_Pr.PanelSelfDetected = TRUE;
2453}
2454
2455static int __devinit
2456SISDoSense(struct sis_video_info *ivideo, u16 type, u16 test)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002457{
2458 int temp, mytest, result, i, j;
2459
2460 for(j = 0; j < 10; j++) {
2461 result = 0;
2462 for(i = 0; i < 3; i++) {
2463 mytest = test;
2464 outSISIDXREG(SISPART4,0x11,(type & 0x00ff));
2465 temp = (type >> 8) | (mytest & 0x00ff);
2466 setSISIDXREG(SISPART4,0x10,0xe0,temp);
2467 SiS_DDC2Delay(&ivideo->SiS_Pr, 0x1500);
2468 mytest >>= 8;
2469 mytest &= 0x7f;
2470 inSISIDXREG(SISPART4,0x03,temp);
2471 temp ^= 0x0e;
2472 temp &= mytest;
2473 if(temp == mytest) result++;
2474#if 1
2475 outSISIDXREG(SISPART4,0x11,0x00);
2476 andSISIDXREG(SISPART4,0x10,0xe0);
2477 SiS_DDC2Delay(&ivideo->SiS_Pr, 0x1000);
2478#endif
2479 }
2480 if((result == 0) || (result >= 2)) break;
2481 }
Thomas Winischhofer544393f2005-09-09 13:04:45 -07002482 return result;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002483}
2484
Thomas Winischhofer544393f2005-09-09 13:04:45 -07002485static void __devinit
2486SiS_Sense30x(struct sis_video_info *ivideo)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002487{
2488 u8 backupP4_0d,backupP2_00,backupP2_4d,backupSR_1e,biosflag=0;
2489 u16 svhs=0, svhs_c=0;
2490 u16 cvbs=0, cvbs_c=0;
2491 u16 vga2=0, vga2_c=0;
2492 int myflag, result;
2493 char stdstr[] = "sisfb: Detected";
2494 char tvstr[] = "TV connected to";
2495
Thomas Winischhofer544393f2005-09-09 13:04:45 -07002496 if(ivideo->vbflags2 & VB2_301) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002497 svhs = 0x00b9; cvbs = 0x00b3; vga2 = 0x00d1;
2498 inSISIDXREG(SISPART4,0x01,myflag);
2499 if(myflag & 0x04) {
2500 svhs = 0x00dd; cvbs = 0x00ee; vga2 = 0x00fd;
2501 }
Thomas Winischhofer544393f2005-09-09 13:04:45 -07002502 } else if(ivideo->vbflags2 & (VB2_301B | VB2_302B)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002503 svhs = 0x016b; cvbs = 0x0174; vga2 = 0x0190;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07002504 } else if(ivideo->vbflags2 & (VB2_301LV | VB2_302LV)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002505 svhs = 0x0200; cvbs = 0x0100;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07002506 } else if(ivideo->vbflags2 & (VB2_301C | VB2_302ELV | VB2_307T | VB2_307LV)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002507 svhs = 0x016b; cvbs = 0x0110; vga2 = 0x0190;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07002508 } else
2509 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002510
2511 vga2_c = 0x0e08; svhs_c = 0x0404; cvbs_c = 0x0804;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07002512 if(ivideo->vbflags & (VB2_301LV|VB2_302LV|VB2_302ELV|VB2_307LV)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002513 svhs_c = 0x0408; cvbs_c = 0x0808;
2514 }
Thomas Winischhofer544393f2005-09-09 13:04:45 -07002515
Linus Torvalds1da177e2005-04-16 15:20:36 -07002516 biosflag = 2;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07002517 if(ivideo->haveXGIROM) {
2518 biosflag = ivideo->bios_abase[0x58] & 0x03;
2519 } else if(ivideo->newrom) {
2520 if(ivideo->bios_abase[0x5d] & 0x04) biosflag |= 0x01;
2521 } else if(ivideo->sisvga_engine == SIS_300_VGA) {
2522 if(ivideo->bios_abase) {
2523 biosflag = ivideo->bios_abase[0xfe] & 0x03;
2524 }
2525 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002526
2527 if(ivideo->chip == SIS_300) {
2528 inSISIDXREG(SISSR,0x3b,myflag);
2529 if(!(myflag & 0x01)) vga2 = vga2_c = 0;
2530 }
2531
Thomas Winischhofer544393f2005-09-09 13:04:45 -07002532 if(!(ivideo->vbflags2 & VB2_SISVGA2BRIDGE)) {
2533 vga2 = vga2_c = 0;
2534 }
2535
Linus Torvalds1da177e2005-04-16 15:20:36 -07002536 inSISIDXREG(SISSR,0x1e,backupSR_1e);
2537 orSISIDXREG(SISSR,0x1e,0x20);
2538
2539 inSISIDXREG(SISPART4,0x0d,backupP4_0d);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07002540 if(ivideo->vbflags2 & VB2_30xC) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002541 setSISIDXREG(SISPART4,0x0d,~0x07,0x01);
2542 } else {
2543 orSISIDXREG(SISPART4,0x0d,0x04);
2544 }
2545 SiS_DDC2Delay(&ivideo->SiS_Pr, 0x2000);
2546
2547 inSISIDXREG(SISPART2,0x00,backupP2_00);
2548 outSISIDXREG(SISPART2,0x00,((backupP2_00 | 0x1c) & 0xfc));
2549
2550 inSISIDXREG(SISPART2,0x4d,backupP2_4d);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07002551 if(ivideo->vbflags2 & VB2_SISYPBPRBRIDGE) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002552 outSISIDXREG(SISPART2,0x4d,(backupP2_4d & ~0x10));
2553 }
2554
Thomas Winischhofer544393f2005-09-09 13:04:45 -07002555 if(!(ivideo->vbflags2 & VB2_30xCLV)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002556 SISDoSense(ivideo, 0, 0);
2557 }
2558
2559 andSISIDXREG(SISCR, 0x32, ~0x14);
2560
2561 if(vga2_c || vga2) {
2562 if(SISDoSense(ivideo, vga2, vga2_c)) {
2563 if(biosflag & 0x01) {
2564 printk(KERN_INFO "%s %s SCART output\n", stdstr, tvstr);
2565 orSISIDXREG(SISCR, 0x32, 0x04);
2566 } else {
2567 printk(KERN_INFO "%s secondary VGA connection\n", stdstr);
2568 orSISIDXREG(SISCR, 0x32, 0x10);
2569 }
2570 }
2571 }
2572
2573 andSISIDXREG(SISCR, 0x32, 0x3f);
2574
Thomas Winischhofer544393f2005-09-09 13:04:45 -07002575 if(ivideo->vbflags2 & VB2_30xCLV) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002576 orSISIDXREG(SISPART4,0x0d,0x04);
2577 }
2578
Thomas Winischhofer544393f2005-09-09 13:04:45 -07002579 if((ivideo->sisvga_engine == SIS_315_VGA) && (ivideo->vbflags2 & VB2_SISYPBPRBRIDGE)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002580 outSISIDXREG(SISPART2,0x4d,(backupP2_4d | 0x10));
2581 SiS_DDC2Delay(&ivideo->SiS_Pr, 0x2000);
2582 if((result = SISDoSense(ivideo, svhs, 0x0604))) {
2583 if((result = SISDoSense(ivideo, cvbs, 0x0804))) {
2584 printk(KERN_INFO "%s %s YPbPr component output\n", stdstr, tvstr);
2585 orSISIDXREG(SISCR,0x32,0x80);
2586 }
2587 }
2588 outSISIDXREG(SISPART2,0x4d,backupP2_4d);
2589 }
2590
2591 andSISIDXREG(SISCR, 0x32, ~0x03);
2592
2593 if(!(ivideo->vbflags & TV_YPBPR)) {
2594 if((result = SISDoSense(ivideo, svhs, svhs_c))) {
2595 printk(KERN_INFO "%s %s SVIDEO output\n", stdstr, tvstr);
2596 orSISIDXREG(SISCR, 0x32, 0x02);
2597 }
2598 if((biosflag & 0x02) || (!result)) {
2599 if(SISDoSense(ivideo, cvbs, cvbs_c)) {
2600 printk(KERN_INFO "%s %s COMPOSITE output\n", stdstr, tvstr);
2601 orSISIDXREG(SISCR, 0x32, 0x01);
2602 }
2603 }
2604 }
2605
2606 SISDoSense(ivideo, 0, 0);
2607
2608 outSISIDXREG(SISPART2,0x00,backupP2_00);
2609 outSISIDXREG(SISPART4,0x0d,backupP4_0d);
2610 outSISIDXREG(SISSR,0x1e,backupSR_1e);
2611
Thomas Winischhofer544393f2005-09-09 13:04:45 -07002612 if(ivideo->vbflags2 & VB2_30xCLV) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002613 inSISIDXREG(SISPART2,0x00,biosflag);
2614 if(biosflag & 0x20) {
2615 for(myflag = 2; myflag > 0; myflag--) {
2616 biosflag ^= 0x20;
2617 outSISIDXREG(SISPART2,0x00,biosflag);
2618 }
2619 }
2620 }
2621
2622 outSISIDXREG(SISPART2,0x00,backupP2_00);
2623}
2624
2625/* Determine and detect attached TV's on Chrontel */
Thomas Winischhofer544393f2005-09-09 13:04:45 -07002626static void __devinit
2627SiS_SenseCh(struct sis_video_info *ivideo)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002628{
2629#if defined(CONFIG_FB_SIS_300) || defined(CONFIG_FB_SIS_315)
2630 u8 temp1, temp2;
2631 char stdstr[] = "sisfb: Chrontel: Detected TV connected to";
2632#endif
2633#ifdef CONFIG_FB_SIS_300
2634 unsigned char test[3];
2635 int i;
2636#endif
2637
2638 if(ivideo->chip < SIS_315H) {
2639
2640#ifdef CONFIG_FB_SIS_300
2641 ivideo->SiS_Pr.SiS_IF_DEF_CH70xx = 1; /* Chrontel 700x */
2642 SiS_SetChrontelGPIO(&ivideo->SiS_Pr, 0x9c); /* Set general purpose IO for Chrontel communication */
2643 SiS_DDC2Delay(&ivideo->SiS_Pr, 1000);
2644 temp1 = SiS_GetCH700x(&ivideo->SiS_Pr, 0x25);
2645 /* See Chrontel TB31 for explanation */
2646 temp2 = SiS_GetCH700x(&ivideo->SiS_Pr, 0x0e);
2647 if(((temp2 & 0x07) == 0x01) || (temp2 & 0x04)) {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07002648 SiS_SetCH700x(&ivideo->SiS_Pr, 0x0e, 0x0b);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002649 SiS_DDC2Delay(&ivideo->SiS_Pr, 300);
2650 }
2651 temp2 = SiS_GetCH700x(&ivideo->SiS_Pr, 0x25);
2652 if(temp2 != temp1) temp1 = temp2;
2653
2654 if((temp1 >= 0x22) && (temp1 <= 0x50)) {
2655 /* Read power status */
2656 temp1 = SiS_GetCH700x(&ivideo->SiS_Pr, 0x0e);
2657 if((temp1 & 0x03) != 0x03) {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07002658 /* Power all outputs */
2659 SiS_SetCH700x(&ivideo->SiS_Pr, 0x0e,0x0b);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002660 SiS_DDC2Delay(&ivideo->SiS_Pr, 300);
2661 }
2662 /* Sense connected TV devices */
2663 for(i = 0; i < 3; i++) {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07002664 SiS_SetCH700x(&ivideo->SiS_Pr, 0x10, 0x01);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002665 SiS_DDC2Delay(&ivideo->SiS_Pr, 0x96);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07002666 SiS_SetCH700x(&ivideo->SiS_Pr, 0x10, 0x00);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002667 SiS_DDC2Delay(&ivideo->SiS_Pr, 0x96);
2668 temp1 = SiS_GetCH700x(&ivideo->SiS_Pr, 0x10);
2669 if(!(temp1 & 0x08)) test[i] = 0x02;
2670 else if(!(temp1 & 0x02)) test[i] = 0x01;
2671 else test[i] = 0;
2672 SiS_DDC2Delay(&ivideo->SiS_Pr, 0x96);
2673 }
2674
2675 if(test[0] == test[1]) temp1 = test[0];
2676 else if(test[0] == test[2]) temp1 = test[0];
2677 else if(test[1] == test[2]) temp1 = test[1];
2678 else {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07002679 printk(KERN_INFO
Linus Torvalds1da177e2005-04-16 15:20:36 -07002680 "sisfb: TV detection unreliable - test results varied\n");
2681 temp1 = test[2];
2682 }
2683 if(temp1 == 0x02) {
2684 printk(KERN_INFO "%s SVIDEO output\n", stdstr);
2685 ivideo->vbflags |= TV_SVIDEO;
2686 orSISIDXREG(SISCR, 0x32, 0x02);
2687 andSISIDXREG(SISCR, 0x32, ~0x05);
2688 } else if (temp1 == 0x01) {
2689 printk(KERN_INFO "%s CVBS output\n", stdstr);
2690 ivideo->vbflags |= TV_AVIDEO;
2691 orSISIDXREG(SISCR, 0x32, 0x01);
2692 andSISIDXREG(SISCR, 0x32, ~0x06);
2693 } else {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07002694 SiS_SetCH70xxANDOR(&ivideo->SiS_Pr, 0x0e, 0x01, 0xF8);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002695 andSISIDXREG(SISCR, 0x32, ~0x07);
2696 }
2697 } else if(temp1 == 0) {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07002698 SiS_SetCH70xxANDOR(&ivideo->SiS_Pr, 0x0e, 0x01, 0xF8);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002699 andSISIDXREG(SISCR, 0x32, ~0x07);
2700 }
2701 /* Set general purpose IO for Chrontel communication */
2702 SiS_SetChrontelGPIO(&ivideo->SiS_Pr, 0x00);
2703#endif
2704
2705 } else {
2706
2707#ifdef CONFIG_FB_SIS_315
2708 ivideo->SiS_Pr.SiS_IF_DEF_CH70xx = 2; /* Chrontel 7019 */
Thomas Winischhofer544393f2005-09-09 13:04:45 -07002709 temp1 = SiS_GetCH701x(&ivideo->SiS_Pr, 0x49);
2710 SiS_SetCH701x(&ivideo->SiS_Pr, 0x49, 0x20);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002711 SiS_DDC2Delay(&ivideo->SiS_Pr, 0x96);
2712 temp2 = SiS_GetCH701x(&ivideo->SiS_Pr, 0x20);
2713 temp2 |= 0x01;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07002714 SiS_SetCH701x(&ivideo->SiS_Pr, 0x20, temp2);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002715 SiS_DDC2Delay(&ivideo->SiS_Pr, 0x96);
2716 temp2 ^= 0x01;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07002717 SiS_SetCH701x(&ivideo->SiS_Pr, 0x20, temp2);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002718 SiS_DDC2Delay(&ivideo->SiS_Pr, 0x96);
2719 temp2 = SiS_GetCH701x(&ivideo->SiS_Pr, 0x20);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07002720 SiS_SetCH701x(&ivideo->SiS_Pr, 0x49, temp1);
2721 temp1 = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002722 if(temp2 & 0x02) temp1 |= 0x01;
2723 if(temp2 & 0x10) temp1 |= 0x01;
2724 if(temp2 & 0x04) temp1 |= 0x02;
2725 if( (temp1 & 0x01) && (temp1 & 0x02) ) temp1 = 0x04;
2726 switch(temp1) {
2727 case 0x01:
2728 printk(KERN_INFO "%s CVBS output\n", stdstr);
2729 ivideo->vbflags |= TV_AVIDEO;
2730 orSISIDXREG(SISCR, 0x32, 0x01);
2731 andSISIDXREG(SISCR, 0x32, ~0x06);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07002732 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002733 case 0x02:
2734 printk(KERN_INFO "%s SVIDEO output\n", stdstr);
2735 ivideo->vbflags |= TV_SVIDEO;
2736 orSISIDXREG(SISCR, 0x32, 0x02);
2737 andSISIDXREG(SISCR, 0x32, ~0x05);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07002738 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002739 case 0x04:
2740 printk(KERN_INFO "%s SCART output\n", stdstr);
2741 orSISIDXREG(SISCR, 0x32, 0x04);
2742 andSISIDXREG(SISCR, 0x32, ~0x03);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07002743 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002744 default:
2745 andSISIDXREG(SISCR, 0x32, ~0x07);
2746 }
2747#endif
2748 }
2749}
2750
Thomas Winischhofer544393f2005-09-09 13:04:45 -07002751static void __devinit
2752sisfb_get_VB_type(struct sis_video_info *ivideo)
2753{
2754 char stdstr[] = "sisfb: Detected";
2755 char bridgestr[] = "video bridge";
2756 u8 vb_chipid;
2757 u8 reg;
2758
2759 /* No CRT2 on XGI Z7 */
2760 if(ivideo->chip == XGI_20)
2761 return;
2762
2763 inSISIDXREG(SISPART4, 0x00, vb_chipid);
2764 switch(vb_chipid) {
2765 case 0x01:
2766 inSISIDXREG(SISPART4, 0x01, reg);
2767 if(reg < 0xb0) {
2768 ivideo->vbflags |= VB_301; /* Deprecated */
2769 ivideo->vbflags2 |= VB2_301;
2770 printk(KERN_INFO "%s SiS301 %s\n", stdstr, bridgestr);
2771 } else if(reg < 0xc0) {
2772 ivideo->vbflags |= VB_301B; /* Deprecated */
2773 ivideo->vbflags2 |= VB2_301B;
2774 inSISIDXREG(SISPART4,0x23,reg);
2775 if(!(reg & 0x02)) {
2776 ivideo->vbflags |= VB_30xBDH; /* Deprecated */
2777 ivideo->vbflags2 |= VB2_30xBDH;
2778 printk(KERN_INFO "%s SiS301B-DH %s\n", stdstr, bridgestr);
2779 } else {
2780 printk(KERN_INFO "%s SiS301B %s\n", stdstr, bridgestr);
2781 }
2782 } else if(reg < 0xd0) {
2783 ivideo->vbflags |= VB_301C; /* Deprecated */
2784 ivideo->vbflags2 |= VB2_301C;
2785 printk(KERN_INFO "%s SiS301C %s\n", stdstr, bridgestr);
2786 } else if(reg < 0xe0) {
2787 ivideo->vbflags |= VB_301LV; /* Deprecated */
2788 ivideo->vbflags2 |= VB2_301LV;
2789 printk(KERN_INFO "%s SiS301LV %s\n", stdstr, bridgestr);
2790 } else if(reg <= 0xe1) {
2791 inSISIDXREG(SISPART4,0x39,reg);
2792 if(reg == 0xff) {
2793 ivideo->vbflags |= VB_302LV; /* Deprecated */
2794 ivideo->vbflags2 |= VB2_302LV;
2795 printk(KERN_INFO "%s SiS302LV %s\n", stdstr, bridgestr);
2796 } else {
2797 ivideo->vbflags |= VB_301C; /* Deprecated */
2798 ivideo->vbflags2 |= VB2_301C;
2799 printk(KERN_INFO "%s SiS301C(P4) %s\n", stdstr, bridgestr);
2800#if 0
2801 ivideo->vbflags |= VB_302ELV; /* Deprecated */
2802 ivideo->vbflags2 |= VB2_302ELV;
2803 printk(KERN_INFO "%s SiS302ELV %s\n", stdstr, bridgestr);
2804#endif
2805 }
2806 }
2807 break;
2808 case 0x02:
2809 ivideo->vbflags |= VB_302B; /* Deprecated */
2810 ivideo->vbflags2 |= VB2_302B;
2811 printk(KERN_INFO "%s SiS302B %s\n", stdstr, bridgestr);
2812 break;
2813 }
2814
2815 if((!(ivideo->vbflags2 & VB2_VIDEOBRIDGE)) && (ivideo->chip != SIS_300)) {
2816 inSISIDXREG(SISCR, 0x37, reg);
2817 reg &= SIS_EXTERNAL_CHIP_MASK;
2818 reg >>= 1;
2819 if(ivideo->sisvga_engine == SIS_300_VGA) {
2820#ifdef CONFIG_FB_SIS_300
2821 switch(reg) {
2822 case SIS_EXTERNAL_CHIP_LVDS:
2823 ivideo->vbflags |= VB_LVDS; /* Deprecated */
2824 ivideo->vbflags2 |= VB2_LVDS;
2825 break;
2826 case SIS_EXTERNAL_CHIP_TRUMPION:
2827 ivideo->vbflags |= (VB_LVDS | VB_TRUMPION); /* Deprecated */
2828 ivideo->vbflags2 |= (VB2_LVDS | VB2_TRUMPION);
2829 break;
2830 case SIS_EXTERNAL_CHIP_CHRONTEL:
2831 ivideo->vbflags |= VB_CHRONTEL; /* Deprecated */
2832 ivideo->vbflags2 |= VB2_CHRONTEL;
2833 break;
2834 case SIS_EXTERNAL_CHIP_LVDS_CHRONTEL:
2835 ivideo->vbflags |= (VB_LVDS | VB_CHRONTEL); /* Deprecated */
2836 ivideo->vbflags2 |= (VB2_LVDS | VB2_CHRONTEL);
2837 break;
2838 }
2839 if(ivideo->vbflags2 & VB2_CHRONTEL) ivideo->chronteltype = 1;
2840#endif
2841 } else if(ivideo->chip < SIS_661) {
2842#ifdef CONFIG_FB_SIS_315
2843 switch (reg) {
2844 case SIS310_EXTERNAL_CHIP_LVDS:
2845 ivideo->vbflags |= VB_LVDS; /* Deprecated */
2846 ivideo->vbflags2 |= VB2_LVDS;
2847 break;
2848 case SIS310_EXTERNAL_CHIP_LVDS_CHRONTEL:
2849 ivideo->vbflags |= (VB_LVDS | VB_CHRONTEL); /* Deprecated */
2850 ivideo->vbflags2 |= (VB2_LVDS | VB2_CHRONTEL);
2851 break;
2852 }
2853 if(ivideo->vbflags2 & VB2_CHRONTEL) ivideo->chronteltype = 2;
2854#endif
2855 } else if(ivideo->chip >= SIS_661) {
2856#ifdef CONFIG_FB_SIS_315
2857 inSISIDXREG(SISCR, 0x38, reg);
2858 reg >>= 5;
2859 switch(reg) {
2860 case 0x02:
2861 ivideo->vbflags |= VB_LVDS; /* Deprecated */
2862 ivideo->vbflags2 |= VB2_LVDS;
2863 break;
2864 case 0x03:
2865 ivideo->vbflags |= (VB_LVDS | VB_CHRONTEL); /* Deprecated */
2866 ivideo->vbflags2 |= (VB2_LVDS | VB2_CHRONTEL);
2867 break;
2868 case 0x04:
2869 ivideo->vbflags |= (VB_LVDS | VB_CONEXANT); /* Deprecated */
2870 ivideo->vbflags2 |= (VB2_LVDS | VB2_CONEXANT);
2871 break;
2872 }
2873 if(ivideo->vbflags2 & VB2_CHRONTEL) ivideo->chronteltype = 2;
2874#endif
2875 }
2876 if(ivideo->vbflags2 & VB2_LVDS) {
2877 printk(KERN_INFO "%s LVDS transmitter\n", stdstr);
2878 }
2879 if((ivideo->sisvga_engine == SIS_300_VGA) && (ivideo->vbflags2 & VB2_TRUMPION)) {
2880 printk(KERN_INFO "%s Trumpion Zurac LCD scaler\n", stdstr);
2881 }
2882 if(ivideo->vbflags2 & VB2_CHRONTEL) {
2883 printk(KERN_INFO "%s Chrontel TV encoder\n", stdstr);
2884 }
2885 if((ivideo->chip >= SIS_661) && (ivideo->vbflags2 & VB2_CONEXANT)) {
2886 printk(KERN_INFO "%s Conexant external device\n", stdstr);
2887 }
2888 }
2889
2890 if(ivideo->vbflags2 & VB2_SISBRIDGE) {
2891 SiS_SenseLCD(ivideo);
2892 SiS_Sense30x(ivideo);
2893 } else if(ivideo->vbflags2 & VB2_CHRONTEL) {
2894 SiS_SenseCh(ivideo);
2895 }
2896}
2897
2898/* ---------- Engine initialization routines ------------ */
2899
2900static void
2901sisfb_engine_init(struct sis_video_info *ivideo)
2902{
2903
2904 /* Initialize command queue (we use MMIO only) */
2905
2906 /* BEFORE THIS IS CALLED, THE ENGINES *MUST* BE SYNC'ED */
2907
2908 ivideo->caps &= ~(TURBO_QUEUE_CAP |
2909 MMIO_CMD_QUEUE_CAP |
2910 VM_CMD_QUEUE_CAP |
2911 AGP_CMD_QUEUE_CAP);
2912
2913#ifdef CONFIG_FB_SIS_300
2914 if(ivideo->sisvga_engine == SIS_300_VGA) {
2915 u32 tqueue_pos;
2916 u8 tq_state;
2917
2918 tqueue_pos = (ivideo->video_size - ivideo->cmdQueueSize) / (64 * 1024);
2919
2920 inSISIDXREG(SISSR, IND_SIS_TURBOQUEUE_SET, tq_state);
2921 tq_state |= 0xf0;
2922 tq_state &= 0xfc;
2923 tq_state |= (u8)(tqueue_pos >> 8);
2924 outSISIDXREG(SISSR, IND_SIS_TURBOQUEUE_SET, tq_state);
2925
2926 outSISIDXREG(SISSR, IND_SIS_TURBOQUEUE_ADR, (u8)(tqueue_pos & 0xff));
2927
2928 ivideo->caps |= TURBO_QUEUE_CAP;
2929 }
2930#endif
2931
2932#ifdef CONFIG_FB_SIS_315
2933 if(ivideo->sisvga_engine == SIS_315_VGA) {
2934 u32 tempq = 0, templ;
2935 u8 temp;
2936
2937 if(ivideo->chip == XGI_20) {
2938 switch(ivideo->cmdQueueSize) {
2939 case (64 * 1024):
2940 temp = SIS_CMD_QUEUE_SIZE_Z7_64k;
2941 break;
2942 case (128 * 1024):
2943 default:
2944 temp = SIS_CMD_QUEUE_SIZE_Z7_128k;
2945 }
2946 } else {
2947 switch(ivideo->cmdQueueSize) {
2948 case (4 * 1024 * 1024):
2949 temp = SIS_CMD_QUEUE_SIZE_4M;
2950 break;
2951 case (2 * 1024 * 1024):
2952 temp = SIS_CMD_QUEUE_SIZE_2M;
2953 break;
2954 case (1 * 1024 * 1024):
2955 temp = SIS_CMD_QUEUE_SIZE_1M;
2956 break;
2957 default:
2958 case (512 * 1024):
2959 temp = SIS_CMD_QUEUE_SIZE_512k;
2960 }
2961 }
2962
2963 outSISIDXREG(SISSR, IND_SIS_CMDQUEUE_THRESHOLD, COMMAND_QUEUE_THRESHOLD);
2964 outSISIDXREG(SISSR, IND_SIS_CMDQUEUE_SET, SIS_CMD_QUEUE_RESET);
2965
2966 if((ivideo->chip >= XGI_40) && ivideo->modechanged) {
2967 /* Must disable dual pipe on XGI_40. Can't do
2968 * this in MMIO mode, because it requires
2969 * setting/clearing a bit in the MMIO fire trigger
2970 * register.
2971 */
2972 if(!((templ = MMIO_IN32(ivideo->mmio_vbase, 0x8240)) & (1 << 10))) {
2973
2974 MMIO_OUT32(ivideo->mmio_vbase, Q_WRITE_PTR, 0);
2975
2976 outSISIDXREG(SISSR, IND_SIS_CMDQUEUE_SET, (temp | SIS_VRAM_CMDQUEUE_ENABLE));
2977
2978 tempq = MMIO_IN32(ivideo->mmio_vbase, Q_READ_PTR);
2979 MMIO_OUT32(ivideo->mmio_vbase, Q_WRITE_PTR, tempq);
2980
2981 tempq = (u32)(ivideo->video_size - ivideo->cmdQueueSize);
2982 MMIO_OUT32(ivideo->mmio_vbase, Q_BASE_ADDR, tempq);
2983
2984 writel(0x16800000 + 0x8240, ivideo->video_vbase + tempq);
2985 writel(templ | (1 << 10), ivideo->video_vbase + tempq + 4);
2986 writel(0x168F0000, ivideo->video_vbase + tempq + 8);
2987 writel(0x168F0000, ivideo->video_vbase + tempq + 12);
2988
2989 MMIO_OUT32(ivideo->mmio_vbase, Q_WRITE_PTR, (tempq + 16));
2990
2991 sisfb_syncaccel(ivideo);
2992
2993 outSISIDXREG(SISSR, IND_SIS_CMDQUEUE_SET, SIS_CMD_QUEUE_RESET);
2994
2995 }
2996 }
2997
2998 tempq = MMIO_IN32(ivideo->mmio_vbase, MMIO_QUEUE_READPORT);
2999 MMIO_OUT32(ivideo->mmio_vbase, MMIO_QUEUE_WRITEPORT, tempq);
3000
3001 temp |= (SIS_MMIO_CMD_ENABLE | SIS_CMD_AUTO_CORR);
3002 outSISIDXREG(SISSR, IND_SIS_CMDQUEUE_SET, temp);
3003
3004 tempq = (u32)(ivideo->video_size - ivideo->cmdQueueSize);
3005 MMIO_OUT32(ivideo->mmio_vbase, MMIO_QUEUE_PHYBASE, tempq);
3006
3007 ivideo->caps |= MMIO_CMD_QUEUE_CAP;
3008 }
3009#endif
3010
3011 ivideo->engineok = 1;
3012}
3013
3014static void __devinit
3015sisfb_detect_lcd_type(struct sis_video_info *ivideo)
3016{
3017 u8 reg;
3018 int i;
3019
3020 inSISIDXREG(SISCR, 0x36, reg);
3021 reg &= 0x0f;
3022 if(ivideo->sisvga_engine == SIS_300_VGA) {
3023 ivideo->CRT2LCDType = sis300paneltype[reg];
3024 } else if(ivideo->chip >= SIS_661) {
3025 ivideo->CRT2LCDType = sis661paneltype[reg];
3026 } else {
3027 ivideo->CRT2LCDType = sis310paneltype[reg];
3028 if((ivideo->chip == SIS_550) && (sisfb_fstn)) {
3029 if((ivideo->CRT2LCDType != LCD_320x240_2) &&
3030 (ivideo->CRT2LCDType != LCD_320x240_3)) {
3031 ivideo->CRT2LCDType = LCD_320x240;
3032 }
3033 }
3034 }
3035
3036 if(ivideo->CRT2LCDType == LCD_UNKNOWN) {
3037 /* For broken BIOSes: Assume 1024x768, RGB18 */
3038 ivideo->CRT2LCDType = LCD_1024x768;
3039 setSISIDXREG(SISCR,0x36,0xf0,0x02);
3040 setSISIDXREG(SISCR,0x37,0xee,0x01);
3041 printk(KERN_DEBUG "sisfb: Invalid panel ID (%02x), assuming 1024x768, RGB18\n", reg);
3042 }
3043
3044 for(i = 0; i < SIS_LCD_NUMBER; i++) {
3045 if(ivideo->CRT2LCDType == sis_lcd_data[i].lcdtype) {
3046 ivideo->lcdxres = sis_lcd_data[i].xres;
3047 ivideo->lcdyres = sis_lcd_data[i].yres;
3048 ivideo->lcddefmodeidx = sis_lcd_data[i].default_mode_idx;
3049 break;
3050 }
3051 }
3052
3053#ifdef CONFIG_FB_SIS_300
3054 if(ivideo->SiS_Pr.SiS_CustomT == CUT_BARCO1366) {
3055 ivideo->lcdxres = 1360; ivideo->lcdyres = 1024;
3056 ivideo->lcddefmodeidx = DEFAULT_MODE_1360;
3057 } else if(ivideo->SiS_Pr.SiS_CustomT == CUT_PANEL848) {
3058 ivideo->lcdxres = 848; ivideo->lcdyres = 480;
3059 ivideo->lcddefmodeidx = DEFAULT_MODE_848;
3060 } else if(ivideo->SiS_Pr.SiS_CustomT == CUT_PANEL856) {
3061 ivideo->lcdxres = 856; ivideo->lcdyres = 480;
3062 ivideo->lcddefmodeidx = DEFAULT_MODE_856;
3063 }
3064#endif
3065
3066 printk(KERN_DEBUG "sisfb: Detected %dx%d flat panel\n",
3067 ivideo->lcdxres, ivideo->lcdyres);
3068}
3069
3070static void __devinit
3071sisfb_save_pdc_emi(struct sis_video_info *ivideo)
3072{
3073#ifdef CONFIG_FB_SIS_300
3074 /* Save the current PanelDelayCompensation if the LCD is currently used */
3075 if(ivideo->sisvga_engine == SIS_300_VGA) {
3076 if(ivideo->vbflags2 & (VB2_LVDS | VB2_30xBDH)) {
3077 int tmp;
3078 inSISIDXREG(SISCR,0x30,tmp);
3079 if(tmp & 0x20) {
3080 /* Currently on LCD? If yes, read current pdc */
3081 inSISIDXREG(SISPART1,0x13,ivideo->detectedpdc);
3082 ivideo->detectedpdc &= 0x3c;
3083 if(ivideo->SiS_Pr.PDC == -1) {
3084 /* Let option override detection */
3085 ivideo->SiS_Pr.PDC = ivideo->detectedpdc;
3086 }
3087 printk(KERN_INFO "sisfb: Detected LCD PDC 0x%02x\n",
3088 ivideo->detectedpdc);
3089 }
3090 if((ivideo->SiS_Pr.PDC != -1) &&
3091 (ivideo->SiS_Pr.PDC != ivideo->detectedpdc)) {
3092 printk(KERN_INFO "sisfb: Using LCD PDC 0x%02x\n",
3093 ivideo->SiS_Pr.PDC);
3094 }
3095 }
3096 }
3097#endif
3098
3099#ifdef CONFIG_FB_SIS_315
3100 if(ivideo->sisvga_engine == SIS_315_VGA) {
3101
3102 /* Try to find about LCDA */
3103 if(ivideo->vbflags2 & VB2_SISLCDABRIDGE) {
3104 int tmp;
3105 inSISIDXREG(SISPART1,0x13,tmp);
3106 if(tmp & 0x04) {
3107 ivideo->SiS_Pr.SiS_UseLCDA = TRUE;
3108 ivideo->detectedlcda = 0x03;
3109 }
3110 }
3111
3112 /* Save PDC */
3113 if(ivideo->vbflags2 & VB2_SISLVDSBRIDGE) {
3114 int tmp;
3115 inSISIDXREG(SISCR,0x30,tmp);
3116 if((tmp & 0x20) || (ivideo->detectedlcda != 0xff)) {
3117 /* Currently on LCD? If yes, read current pdc */
3118 u8 pdc;
3119 inSISIDXREG(SISPART1,0x2D,pdc);
3120 ivideo->detectedpdc = (pdc & 0x0f) << 1;
3121 ivideo->detectedpdca = (pdc & 0xf0) >> 3;
3122 inSISIDXREG(SISPART1,0x35,pdc);
3123 ivideo->detectedpdc |= ((pdc >> 7) & 0x01);
3124 inSISIDXREG(SISPART1,0x20,pdc);
3125 ivideo->detectedpdca |= ((pdc >> 6) & 0x01);
3126 if(ivideo->newrom) {
3127 /* New ROM invalidates other PDC resp. */
3128 if(ivideo->detectedlcda != 0xff) {
3129 ivideo->detectedpdc = 0xff;
3130 } else {
3131 ivideo->detectedpdca = 0xff;
3132 }
3133 }
3134 if(ivideo->SiS_Pr.PDC == -1) {
3135 if(ivideo->detectedpdc != 0xff) {
3136 ivideo->SiS_Pr.PDC = ivideo->detectedpdc;
3137 }
3138 }
3139 if(ivideo->SiS_Pr.PDCA == -1) {
3140 if(ivideo->detectedpdca != 0xff) {
3141 ivideo->SiS_Pr.PDCA = ivideo->detectedpdca;
3142 }
3143 }
3144 if(ivideo->detectedpdc != 0xff) {
3145 printk(KERN_INFO
3146 "sisfb: Detected LCD PDC 0x%02x (for LCD=CRT2)\n",
3147 ivideo->detectedpdc);
3148 }
3149 if(ivideo->detectedpdca != 0xff) {
3150 printk(KERN_INFO
3151 "sisfb: Detected LCD PDC1 0x%02x (for LCD=CRT1)\n",
3152 ivideo->detectedpdca);
3153 }
3154 }
3155
3156 /* Save EMI */
3157 if(ivideo->vbflags2 & VB2_SISEMIBRIDGE) {
3158 inSISIDXREG(SISPART4,0x30,ivideo->SiS_Pr.EMI_30);
3159 inSISIDXREG(SISPART4,0x31,ivideo->SiS_Pr.EMI_31);
3160 inSISIDXREG(SISPART4,0x32,ivideo->SiS_Pr.EMI_32);
3161 inSISIDXREG(SISPART4,0x33,ivideo->SiS_Pr.EMI_33);
3162 ivideo->SiS_Pr.HaveEMI = TRUE;
3163 if((tmp & 0x20) || (ivideo->detectedlcda != 0xff)) {
3164 ivideo->SiS_Pr.HaveEMILCD = TRUE;
3165 }
3166 }
3167 }
3168
3169 /* Let user override detected PDCs (all bridges) */
3170 if(ivideo->vbflags2 & VB2_30xBLV) {
3171 if((ivideo->SiS_Pr.PDC != -1) &&
3172 (ivideo->SiS_Pr.PDC != ivideo->detectedpdc)) {
3173 printk(KERN_INFO "sisfb: Using LCD PDC 0x%02x (for LCD=CRT2)\n",
3174 ivideo->SiS_Pr.PDC);
3175 }
3176 if((ivideo->SiS_Pr.PDCA != -1) &&
3177 (ivideo->SiS_Pr.PDCA != ivideo->detectedpdca)) {
3178 printk(KERN_INFO "sisfb: Using LCD PDC1 0x%02x (for LCD=CRT1)\n",
3179 ivideo->SiS_Pr.PDCA);
3180 }
3181 }
3182
3183 }
3184#endif
3185}
3186
3187/* -------------------- Memory manager routines ---------------------- */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003188
3189static u32 __devinit
3190sisfb_getheapstart(struct sis_video_info *ivideo)
3191{
3192 u32 ret = ivideo->sisfb_parm_mem * 1024;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003193 u32 maxoffs = ivideo->video_size - ivideo->hwcursor_size - ivideo->cmdQueueSize;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003194 u32 def;
3195
3196 /* Calculate heap start = end of memory for console
3197 *
3198 * CCCCCCCCDDDDDDDDDDDDDDDDDDDDDDDDDDDDHHHHQQQQQQQQQQ
3199 * C = console, D = heap, H = HWCursor, Q = cmd-queue
3200 *
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003201 * On 76x in UMA+LFB mode, the layout is as follows:
3202 * DDDDDDDDDDDCCCCCCCCCCCCCCCCCCCCCCCCHHHHQQQQQQQQQQQ
3203 * where the heap is the entire UMA area, eventually
3204 * into the LFB area if the given mem parameter is
3205 * higher than the size of the UMA memory.
3206 *
Linus Torvalds1da177e2005-04-16 15:20:36 -07003207 * Basically given by "mem" parameter
3208 *
3209 * maximum = videosize - cmd_queue - hwcursor
3210 * (results in a heap of size 0)
3211 * default = SiS 300: depends on videosize
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003212 * SiS 315/330/340/XGI: 32k below max
Linus Torvalds1da177e2005-04-16 15:20:36 -07003213 */
3214
3215 if(ivideo->sisvga_engine == SIS_300_VGA) {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003216 if(ivideo->video_size > 0x1000000) {
3217 def = 0xc00000;
3218 } else if(ivideo->video_size > 0x800000) {
3219 def = 0x800000;
3220 } else {
3221 def = 0x400000;
3222 }
3223 } else if(ivideo->UMAsize && ivideo->LFBsize) {
3224 ret = def = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003225 } else {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003226 def = maxoffs - 0x8000;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003227 }
3228
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003229 /* Use default for secondary card for now (FIXME) */
3230 if((!ret) || (ret > maxoffs) || (ivideo->cardnumber != 0))
3231 ret = def;
3232
3233 return ret;
3234}
3235
3236static u32 __devinit
3237sisfb_getheapsize(struct sis_video_info *ivideo)
3238{
3239 u32 max = ivideo->video_size - ivideo->hwcursor_size - ivideo->cmdQueueSize;
3240 u32 ret = 0;
3241
3242 if(ivideo->UMAsize && ivideo->LFBsize) {
3243 if( (!ivideo->sisfb_parm_mem) ||
3244 ((ivideo->sisfb_parm_mem * 1024) > max) ||
3245 ((max - (ivideo->sisfb_parm_mem * 1024)) < ivideo->UMAsize) ) {
3246 ret = ivideo->UMAsize;
3247 max -= ivideo->UMAsize;
3248 } else {
3249 ret = max - (ivideo->sisfb_parm_mem * 1024);
3250 max = ivideo->sisfb_parm_mem * 1024;
3251 }
3252 ivideo->video_offset = ret;
3253 ivideo->sisfb_mem = max;
3254 } else {
3255 ret = max - ivideo->heapstart;
3256 ivideo->sisfb_mem = ivideo->heapstart;
3257 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003258
3259 return ret;
3260}
3261
3262static int __devinit
3263sisfb_heap_init(struct sis_video_info *ivideo)
3264{
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003265 struct SIS_OH *poh;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003266
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003267 ivideo->video_offset = 0;
3268 if(ivideo->sisfb_parm_mem) {
3269 if( (ivideo->sisfb_parm_mem < (2 * 1024 * 1024)) ||
3270 (ivideo->sisfb_parm_mem > ivideo->video_size) ) {
3271 ivideo->sisfb_parm_mem = 0;
3272 }
3273 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003274
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003275 ivideo->heapstart = sisfb_getheapstart(ivideo);
3276 ivideo->sisfb_heap_size = sisfb_getheapsize(ivideo);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003277
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003278 ivideo->sisfb_heap_start = ivideo->video_vbase + ivideo->heapstart;
3279 ivideo->sisfb_heap_end = ivideo->sisfb_heap_start + ivideo->sisfb_heap_size;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003280
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003281 printk(KERN_INFO "sisfb: Memory heap starting at %dK, size %dK\n",
3282 (int)(ivideo->heapstart / 1024), (int)(ivideo->sisfb_heap_size / 1024));
Linus Torvalds1da177e2005-04-16 15:20:36 -07003283
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003284 ivideo->sisfb_heap.vinfo = ivideo;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003285
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003286 ivideo->sisfb_heap.poha_chain = NULL;
3287 ivideo->sisfb_heap.poh_freelist = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003288
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003289 poh = sisfb_poh_new_node(&ivideo->sisfb_heap);
3290 if(poh == NULL)
3291 return 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003292
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003293 poh->poh_next = &ivideo->sisfb_heap.oh_free;
3294 poh->poh_prev = &ivideo->sisfb_heap.oh_free;
3295 poh->size = ivideo->sisfb_heap_size;
3296 poh->offset = ivideo->heapstart;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003297
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003298 ivideo->sisfb_heap.oh_free.poh_next = poh;
3299 ivideo->sisfb_heap.oh_free.poh_prev = poh;
3300 ivideo->sisfb_heap.oh_free.size = 0;
3301 ivideo->sisfb_heap.max_freesize = poh->size;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003302
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003303 ivideo->sisfb_heap.oh_used.poh_next = &ivideo->sisfb_heap.oh_used;
3304 ivideo->sisfb_heap.oh_used.poh_prev = &ivideo->sisfb_heap.oh_used;
3305 ivideo->sisfb_heap.oh_used.size = SENTINEL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003306
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003307 if(ivideo->cardnumber == 0) {
3308 /* For the first card, make this heap the "global" one
3309 * for old DRM (which could handle only one card)
3310 */
3311 sisfb_heap = &ivideo->sisfb_heap;
3312 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003313
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003314 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003315}
3316
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003317static struct SIS_OH *
3318sisfb_poh_new_node(struct SIS_HEAP *memheap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003319{
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003320 struct SIS_OHALLOC *poha;
3321 struct SIS_OH *poh;
3322 unsigned long cOhs;
3323 int i;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003324
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003325 if(memheap->poh_freelist == NULL) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003326 poha = kmalloc(SIS_OH_ALLOC_SIZE, GFP_KERNEL);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003327 if(!poha)
3328 return NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003329
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003330 poha->poha_next = memheap->poha_chain;
3331 memheap->poha_chain = poha;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003332
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003333 cOhs = (SIS_OH_ALLOC_SIZE - sizeof(struct SIS_OHALLOC)) / sizeof(struct SIS_OH) + 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003334
3335 poh = &poha->aoh[0];
3336 for(i = cOhs - 1; i != 0; i--) {
3337 poh->poh_next = poh + 1;
3338 poh = poh + 1;
3339 }
3340
3341 poh->poh_next = NULL;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003342 memheap->poh_freelist = &poha->aoh[0];
Linus Torvalds1da177e2005-04-16 15:20:36 -07003343 }
3344
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003345 poh = memheap->poh_freelist;
3346 memheap->poh_freelist = poh->poh_next;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003347
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003348 return poh;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003349}
3350
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003351static struct SIS_OH *
3352sisfb_poh_allocate(struct SIS_HEAP *memheap, u32 size)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003353{
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003354 struct SIS_OH *pohThis;
3355 struct SIS_OH *pohRoot;
3356 int bAllocated = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003357
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003358 if(size > memheap->max_freesize) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003359 DPRINTK("sisfb: Can't allocate %dk video memory\n",
3360 (unsigned int) size / 1024);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003361 return NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003362 }
3363
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003364 pohThis = memheap->oh_free.poh_next;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003365
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003366 while(pohThis != &memheap->oh_free) {
3367 if(size <= pohThis->size) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003368 bAllocated = 1;
3369 break;
3370 }
3371 pohThis = pohThis->poh_next;
3372 }
3373
3374 if(!bAllocated) {
3375 DPRINTK("sisfb: Can't allocate %dk video memory\n",
3376 (unsigned int) size / 1024);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003377 return NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003378 }
3379
3380 if(size == pohThis->size) {
3381 pohRoot = pohThis;
3382 sisfb_delete_node(pohThis);
3383 } else {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003384 pohRoot = sisfb_poh_new_node(memheap);
3385 if(pohRoot == NULL)
3386 return NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003387
3388 pohRoot->offset = pohThis->offset;
3389 pohRoot->size = size;
3390
3391 pohThis->offset += size;
3392 pohThis->size -= size;
3393 }
3394
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003395 memheap->max_freesize -= size;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003396
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003397 pohThis = &memheap->oh_used;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003398 sisfb_insert_node(pohThis, pohRoot);
3399
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003400 return pohRoot;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003401}
3402
3403static void
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003404sisfb_delete_node(struct SIS_OH *poh)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003405{
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003406 poh->poh_prev->poh_next = poh->poh_next;
3407 poh->poh_next->poh_prev = poh->poh_prev;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003408}
3409
3410static void
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003411sisfb_insert_node(struct SIS_OH *pohList, struct SIS_OH *poh)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003412{
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003413 struct SIS_OH *pohTemp = pohList->poh_next;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003414
3415 pohList->poh_next = poh;
3416 pohTemp->poh_prev = poh;
3417
3418 poh->poh_prev = pohList;
3419 poh->poh_next = pohTemp;
3420}
3421
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003422static struct SIS_OH *
3423sisfb_poh_free(struct SIS_HEAP *memheap, u32 base)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003424{
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003425 struct SIS_OH *pohThis;
3426 struct SIS_OH *poh_freed;
3427 struct SIS_OH *poh_prev;
3428 struct SIS_OH *poh_next;
3429 u32 ulUpper;
3430 u32 ulLower;
3431 int foundNode = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003432
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003433 poh_freed = memheap->oh_used.poh_next;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003434
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003435 while(poh_freed != &memheap->oh_used) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003436 if(poh_freed->offset == base) {
3437 foundNode = 1;
3438 break;
3439 }
3440
3441 poh_freed = poh_freed->poh_next;
3442 }
3443
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003444 if(!foundNode)
3445 return NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003446
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003447 memheap->max_freesize += poh_freed->size;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003448
3449 poh_prev = poh_next = NULL;
3450 ulUpper = poh_freed->offset + poh_freed->size;
3451 ulLower = poh_freed->offset;
3452
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003453 pohThis = memheap->oh_free.poh_next;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003454
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003455 while(pohThis != &memheap->oh_free) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003456 if(pohThis->offset == ulUpper) {
3457 poh_next = pohThis;
3458 } else if((pohThis->offset + pohThis->size) == ulLower) {
3459 poh_prev = pohThis;
3460 }
3461 pohThis = pohThis->poh_next;
3462 }
3463
3464 sisfb_delete_node(poh_freed);
3465
3466 if(poh_prev && poh_next) {
3467 poh_prev->size += (poh_freed->size + poh_next->size);
3468 sisfb_delete_node(poh_next);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003469 sisfb_free_node(memheap, poh_freed);
3470 sisfb_free_node(memheap, poh_next);
3471 return poh_prev;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003472 }
3473
3474 if(poh_prev) {
3475 poh_prev->size += poh_freed->size;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003476 sisfb_free_node(memheap, poh_freed);
3477 return poh_prev;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003478 }
3479
3480 if(poh_next) {
3481 poh_next->size += poh_freed->size;
3482 poh_next->offset = poh_freed->offset;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003483 sisfb_free_node(memheap, poh_freed);
3484 return poh_next;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003485 }
3486
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003487 sisfb_insert_node(&memheap->oh_free, poh_freed);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003488
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003489 return poh_freed;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003490}
3491
3492static void
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003493sisfb_free_node(struct SIS_HEAP *memheap, struct SIS_OH *poh)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003494{
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003495 if(poh == NULL)
3496 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003497
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003498 poh->poh_next = memheap->poh_freelist;
3499 memheap->poh_freelist = poh;
3500}
3501
3502static void
3503sis_int_malloc(struct sis_video_info *ivideo, struct sis_memreq *req)
3504{
3505 struct SIS_OH *poh = NULL;
3506
3507 if((ivideo) && (ivideo->sisfb_id == SISFB_ID) && (!ivideo->havenoheap))
3508 poh = sisfb_poh_allocate(&ivideo->sisfb_heap, (u32)req->size);
3509
3510 if(poh == NULL) {
3511 req->offset = req->size = 0;
3512 DPRINTK("sisfb: Video RAM allocation failed\n");
3513 } else {
3514 req->offset = poh->offset;
3515 req->size = poh->size;
3516 DPRINTK("sisfb: Video RAM allocation succeeded: 0x%lx\n",
3517 (poh->offset + ivideo->video_vbase));
3518 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003519}
3520
3521void
3522sis_malloc(struct sis_memreq *req)
3523{
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003524 struct sis_video_info *ivideo = sisfb_heap->vinfo;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003525
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003526 if(&ivideo->sisfb_heap == sisfb_heap)
3527 sis_int_malloc(ivideo, req);
3528 else
3529 req->offset = req->size = 0;
3530}
Linus Torvalds1da177e2005-04-16 15:20:36 -07003531
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003532void
3533sis_malloc_new(struct pci_dev *pdev, struct sis_memreq *req)
3534{
3535 struct sis_video_info *ivideo = pci_get_drvdata(pdev);
3536
3537 sis_int_malloc(ivideo, req);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003538}
3539
3540/* sis_free: u32 because "base" is offset inside video ram, can never be >4GB */
3541
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003542static void
3543sis_int_free(struct sis_video_info *ivideo, u32 base)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003544{
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003545 struct SIS_OH *poh;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003546
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003547 if((!ivideo) || (ivideo->sisfb_id != SISFB_ID) || (ivideo->havenoheap))
3548 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003549
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003550 poh = sisfb_poh_free(&ivideo->sisfb_heap, base);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003551
3552 if(poh == NULL) {
3553 DPRINTK("sisfb: sisfb_poh_free() failed at base 0x%x\n",
3554 (unsigned int) base);
3555 }
3556}
3557
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003558void
3559sis_free(u32 base)
3560{
3561 struct sis_video_info *ivideo = sisfb_heap->vinfo;
3562
3563 sis_int_free(ivideo, base);
3564}
3565
3566void
3567sis_free_new(struct pci_dev *pdev, u32 base)
3568{
3569 struct sis_video_info *ivideo = pci_get_drvdata(pdev);
3570
3571 sis_int_free(ivideo, base);
3572}
3573
Linus Torvalds1da177e2005-04-16 15:20:36 -07003574/* --------------------- SetMode routines ------------------------- */
3575
3576static void
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003577sisfb_check_engine_and_sync(struct sis_video_info *ivideo)
3578{
3579 u8 cr30, cr31;
3580
3581 /* Check if MMIO and engines are enabled,
3582 * and sync in case they are. Can't use
3583 * ivideo->accel here, as this might have
3584 * been changed before this is called.
3585 */
3586 inSISIDXREG(SISSR, IND_SIS_PCI_ADDRESS_SET, cr30);
3587 inSISIDXREG(SISSR, IND_SIS_MODULE_ENABLE, cr31);
3588 /* MMIO and 2D/3D engine enabled? */
3589 if((cr30 & SIS_MEM_MAP_IO_ENABLE) && (cr31 & 0x42)) {
3590#ifdef CONFIG_FB_SIS_300
3591 if(ivideo->sisvga_engine == SIS_300_VGA) {
3592 /* Don't care about TurboQueue. It's
3593 * enough to know that the engines
3594 * are enabled
3595 */
3596 sisfb_syncaccel(ivideo);
3597 }
3598#endif
3599#ifdef CONFIG_FB_SIS_315
3600 if(ivideo->sisvga_engine == SIS_315_VGA) {
3601 /* Check that any queue mode is
3602 * enabled, and that the queue
3603 * is not in the state of "reset"
3604 */
3605 inSISIDXREG(SISSR, 0x26, cr30);
3606 if((cr30 & 0xe0) && (!(cr30 & 0x01))) {
3607 sisfb_syncaccel(ivideo);
3608 }
3609 }
3610#endif
3611 }
3612}
3613
3614static void
Linus Torvalds1da177e2005-04-16 15:20:36 -07003615sisfb_pre_setmode(struct sis_video_info *ivideo)
3616{
3617 u8 cr30 = 0, cr31 = 0, cr33 = 0, cr35 = 0, cr38 = 0;
3618 int tvregnum = 0;
3619
3620 ivideo->currentvbflags &= (VB_VIDEOBRIDGE | VB_DISPTYPE_DISP2);
3621
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003622 outSISIDXREG(SISSR, 0x05, 0x86);
3623
Linus Torvalds1da177e2005-04-16 15:20:36 -07003624 inSISIDXREG(SISCR, 0x31, cr31);
3625 cr31 &= ~0x60;
3626 cr31 |= 0x04;
3627
3628 cr33 = ivideo->rate_idx & 0x0F;
3629
3630#ifdef CONFIG_FB_SIS_315
3631 if(ivideo->sisvga_engine == SIS_315_VGA) {
3632 if(ivideo->chip >= SIS_661) {
3633 inSISIDXREG(SISCR, 0x38, cr38);
3634 cr38 &= ~0x07; /* Clear LCDA/DualEdge and YPbPr bits */
3635 } else {
3636 tvregnum = 0x38;
3637 inSISIDXREG(SISCR, tvregnum, cr38);
3638 cr38 &= ~0x3b; /* Clear LCDA/DualEdge and YPbPr bits */
3639 }
3640 }
3641#endif
3642#ifdef CONFIG_FB_SIS_300
3643 if(ivideo->sisvga_engine == SIS_300_VGA) {
3644 tvregnum = 0x35;
3645 inSISIDXREG(SISCR, tvregnum, cr38);
3646 }
3647#endif
3648
3649 SiS_SetEnableDstn(&ivideo->SiS_Pr, FALSE);
3650 SiS_SetEnableFstn(&ivideo->SiS_Pr, FALSE);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003651 ivideo->curFSTN = ivideo->curDSTN = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003652
3653 switch(ivideo->currentvbflags & VB_DISPTYPE_DISP2) {
3654
3655 case CRT2_TV:
3656 cr38 &= ~0xc0; /* Clear PAL-M / PAL-N bits */
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003657 if((ivideo->vbflags & TV_YPBPR) && (ivideo->vbflags2 & VB2_SISYPBPRBRIDGE)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003658#ifdef CONFIG_FB_SIS_315
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003659 if(ivideo->chip >= SIS_661) {
3660 cr38 |= 0x04;
3661 if(ivideo->vbflags & TV_YPBPR525P) cr35 |= 0x20;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003662 else if(ivideo->vbflags & TV_YPBPR750P) cr35 |= 0x40;
3663 else if(ivideo->vbflags & TV_YPBPR1080I) cr35 |= 0x60;
3664 cr30 |= SIS_SIMULTANEOUS_VIEW_ENABLE;
3665 cr35 &= ~0x01;
3666 ivideo->currentvbflags |= (TV_YPBPR | (ivideo->vbflags & TV_YPBPRALL));
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003667 } else if(ivideo->sisvga_engine == SIS_315_VGA) {
3668 cr30 |= (0x80 | SIS_SIMULTANEOUS_VIEW_ENABLE);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003669 cr38 |= 0x08;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003670 if(ivideo->vbflags & TV_YPBPR525P) cr38 |= 0x10;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003671 else if(ivideo->vbflags & TV_YPBPR750P) cr38 |= 0x20;
3672 else if(ivideo->vbflags & TV_YPBPR1080I) cr38 |= 0x30;
3673 cr31 &= ~0x01;
3674 ivideo->currentvbflags |= (TV_YPBPR | (ivideo->vbflags & TV_YPBPRALL));
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003675 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003676#endif
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003677 } else if((ivideo->vbflags & TV_HIVISION) &&
3678 (ivideo->vbflags2 & VB2_SISHIVISIONBRIDGE)) {
3679 if(ivideo->chip >= SIS_661) {
3680 cr38 |= 0x04;
3681 cr35 |= 0x60;
3682 } else {
3683 cr30 |= 0x80;
3684 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003685 cr30 |= SIS_SIMULTANEOUS_VIEW_ENABLE;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003686 cr31 |= 0x01;
3687 cr35 |= 0x01;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003688 ivideo->currentvbflags |= TV_HIVISION;
3689 } else if(ivideo->vbflags & TV_SCART) {
3690 cr30 = (SIS_VB_OUTPUT_SCART | SIS_SIMULTANEOUS_VIEW_ENABLE);
3691 cr31 |= 0x01;
3692 cr35 |= 0x01;
3693 ivideo->currentvbflags |= TV_SCART;
3694 } else {
3695 if(ivideo->vbflags & TV_SVIDEO) {
3696 cr30 = (SIS_VB_OUTPUT_SVIDEO | SIS_SIMULTANEOUS_VIEW_ENABLE);
3697 ivideo->currentvbflags |= TV_SVIDEO;
3698 }
3699 if(ivideo->vbflags & TV_AVIDEO) {
3700 cr30 = (SIS_VB_OUTPUT_COMPOSITE | SIS_SIMULTANEOUS_VIEW_ENABLE);
3701 ivideo->currentvbflags |= TV_AVIDEO;
3702 }
3703 }
3704 cr31 |= SIS_DRIVER_MODE;
3705
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003706 if(ivideo->vbflags & (TV_AVIDEO | TV_SVIDEO)) {
3707 if(ivideo->vbflags & TV_PAL) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003708 cr31 |= 0x01; cr35 |= 0x01;
3709 ivideo->currentvbflags |= TV_PAL;
3710 if(ivideo->vbflags & TV_PALM) {
3711 cr38 |= 0x40; cr35 |= 0x04;
3712 ivideo->currentvbflags |= TV_PALM;
3713 } else if(ivideo->vbflags & TV_PALN) {
3714 cr38 |= 0x80; cr35 |= 0x08;
3715 ivideo->currentvbflags |= TV_PALN;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003716 }
3717 } else {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003718 cr31 &= ~0x01; cr35 &= ~0x01;
3719 ivideo->currentvbflags |= TV_NTSC;
3720 if(ivideo->vbflags & TV_NTSCJ) {
3721 cr38 |= 0x40; cr35 |= 0x02;
3722 ivideo->currentvbflags |= TV_NTSCJ;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003723 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003724 }
3725 }
3726 break;
3727
3728 case CRT2_LCD:
3729 cr30 = (SIS_VB_OUTPUT_LCD | SIS_SIMULTANEOUS_VIEW_ENABLE);
3730 cr31 |= SIS_DRIVER_MODE;
3731 SiS_SetEnableDstn(&ivideo->SiS_Pr, ivideo->sisfb_dstn);
3732 SiS_SetEnableFstn(&ivideo->SiS_Pr, ivideo->sisfb_fstn);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003733 ivideo->curFSTN = ivideo->sisfb_fstn;
3734 ivideo->curDSTN = ivideo->sisfb_dstn;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003735 break;
3736
3737 case CRT2_VGA:
3738 cr30 = (SIS_VB_OUTPUT_CRT2 | SIS_SIMULTANEOUS_VIEW_ENABLE);
3739 cr31 |= SIS_DRIVER_MODE;
3740 if(ivideo->sisfb_nocrt2rate) {
3741 cr33 |= (sisbios_mode[ivideo->sisfb_mode_idx].rate_idx << 4);
3742 } else {
3743 cr33 |= ((ivideo->rate_idx & 0x0F) << 4);
3744 }
3745 break;
3746
3747 default: /* disable CRT2 */
3748 cr30 = 0x00;
3749 cr31 |= (SIS_DRIVER_MODE | SIS_VB_OUTPUT_DISABLE);
3750 }
3751
3752 outSISIDXREG(SISCR, 0x30, cr30);
3753 outSISIDXREG(SISCR, 0x33, cr33);
3754
3755 if(ivideo->chip >= SIS_661) {
3756#ifdef CONFIG_FB_SIS_315
3757 cr31 &= ~0x01; /* Clear PAL flag (now in CR35) */
3758 setSISIDXREG(SISCR, 0x35, ~0x10, cr35); /* Leave overscan bit alone */
3759 cr38 &= 0x07; /* Use only LCDA and HiVision/YPbPr bits */
3760 setSISIDXREG(SISCR, 0x38, 0xf8, cr38);
3761#endif
3762 } else if(ivideo->chip != SIS_300) {
3763 outSISIDXREG(SISCR, tvregnum, cr38);
3764 }
3765 outSISIDXREG(SISCR, 0x31, cr31);
3766
Linus Torvalds1da177e2005-04-16 15:20:36 -07003767 ivideo->SiS_Pr.SiS_UseOEM = ivideo->sisfb_useoem;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003768
3769 sisfb_check_engine_and_sync(ivideo);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003770}
3771
3772/* Fix SR11 for 661 and later */
3773#ifdef CONFIG_FB_SIS_315
3774static void
3775sisfb_fixup_SR11(struct sis_video_info *ivideo)
3776{
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003777 u8 tmpreg;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003778
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003779 if(ivideo->chip >= SIS_661) {
3780 inSISIDXREG(SISSR,0x11,tmpreg);
3781 if(tmpreg & 0x20) {
3782 inSISIDXREG(SISSR,0x3e,tmpreg);
3783 tmpreg = (tmpreg + 1) & 0xff;
3784 outSISIDXREG(SISSR,0x3e,tmpreg);
3785 inSISIDXREG(SISSR,0x11,tmpreg);
3786 }
3787 if(tmpreg & 0xf0) {
3788 andSISIDXREG(SISSR,0x11,0x0f);
3789 }
3790 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003791}
3792#endif
3793
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003794static void
3795sisfb_set_TVxposoffset(struct sis_video_info *ivideo, int val)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003796{
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003797 if(val > 32) val = 32;
3798 if(val < -32) val = -32;
3799 ivideo->tvxpos = val;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003800
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003801 if(ivideo->sisfblocked) return;
3802 if(!ivideo->modechanged) return;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003803
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003804 if(ivideo->currentvbflags & CRT2_TV) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003805
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003806 if(ivideo->vbflags2 & VB2_CHRONTEL) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003807
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003808 int x = ivideo->tvx;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003809
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003810 switch(ivideo->chronteltype) {
3811 case 1:
3812 x += val;
3813 if(x < 0) x = 0;
3814 outSISIDXREG(SISSR,0x05,0x86);
3815 SiS_SetCH700x(&ivideo->SiS_Pr, 0x0a, (x & 0xff));
3816 SiS_SetCH70xxANDOR(&ivideo->SiS_Pr, 0x08, ((x & 0x0100) >> 7), 0xFD);
3817 break;
3818 case 2:
3819 /* Not supported by hardware */
3820 break;
3821 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003822
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003823 } else if(ivideo->vbflags2 & VB2_SISBRIDGE) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003824
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003825 u8 p2_1f,p2_20,p2_2b,p2_42,p2_43;
3826 unsigned short temp;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003827
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003828 p2_1f = ivideo->p2_1f;
3829 p2_20 = ivideo->p2_20;
3830 p2_2b = ivideo->p2_2b;
3831 p2_42 = ivideo->p2_42;
3832 p2_43 = ivideo->p2_43;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003833
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003834 temp = p2_1f | ((p2_20 & 0xf0) << 4);
3835 temp += (val * 2);
3836 p2_1f = temp & 0xff;
3837 p2_20 = (temp & 0xf00) >> 4;
3838 p2_2b = ((p2_2b & 0x0f) + (val * 2)) & 0x0f;
3839 temp = p2_43 | ((p2_42 & 0xf0) << 4);
3840 temp += (val * 2);
3841 p2_43 = temp & 0xff;
3842 p2_42 = (temp & 0xf00) >> 4;
3843 outSISIDXREG(SISPART2,0x1f,p2_1f);
3844 setSISIDXREG(SISPART2,0x20,0x0F,p2_20);
3845 setSISIDXREG(SISPART2,0x2b,0xF0,p2_2b);
3846 setSISIDXREG(SISPART2,0x42,0x0F,p2_42);
3847 outSISIDXREG(SISPART2,0x43,p2_43);
3848 }
3849 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003850}
3851
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003852static void
3853sisfb_set_TVyposoffset(struct sis_video_info *ivideo, int val)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003854{
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003855 if(val > 32) val = 32;
3856 if(val < -32) val = -32;
3857 ivideo->tvypos = val;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003858
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003859 if(ivideo->sisfblocked) return;
3860 if(!ivideo->modechanged) return;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003861
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003862 if(ivideo->currentvbflags & CRT2_TV) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003863
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003864 if(ivideo->vbflags2 & VB2_CHRONTEL) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003865
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003866 int y = ivideo->tvy;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003867
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003868 switch(ivideo->chronteltype) {
3869 case 1:
3870 y -= val;
3871 if(y < 0) y = 0;
3872 outSISIDXREG(SISSR,0x05,0x86);
3873 SiS_SetCH700x(&ivideo->SiS_Pr, 0x0b, (y & 0xff));
3874 SiS_SetCH70xxANDOR(&ivideo->SiS_Pr, 0x08, ((y & 0x0100) >> 8), 0xFE);
3875 break;
3876 case 2:
3877 /* Not supported by hardware */
3878 break;
3879 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003880
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003881 } else if(ivideo->vbflags2 & VB2_SISBRIDGE) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003882
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003883 char p2_01, p2_02;
3884 val /= 2;
3885 p2_01 = ivideo->p2_01;
3886 p2_02 = ivideo->p2_02;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003887
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003888 p2_01 += val;
3889 p2_02 += val;
3890 if(!(ivideo->currentvbflags & (TV_HIVISION | TV_YPBPR))) {
3891 while((p2_01 <= 0) || (p2_02 <= 0)) {
3892 p2_01 += 2;
3893 p2_02 += 2;
3894 }
3895 }
3896 outSISIDXREG(SISPART2,0x01,p2_01);
3897 outSISIDXREG(SISPART2,0x02,p2_02);
3898 }
3899 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003900}
3901
3902static void
3903sisfb_post_setmode(struct sis_video_info *ivideo)
3904{
3905 BOOLEAN crt1isoff = FALSE;
3906 BOOLEAN doit = TRUE;
3907#if defined(CONFIG_FB_SIS_300) || defined(CONFIG_FB_SIS_315)
3908 u8 reg;
3909#endif
3910#ifdef CONFIG_FB_SIS_315
3911 u8 reg1;
3912#endif
3913
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003914 outSISIDXREG(SISSR, 0x05, 0x86);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003915
3916#ifdef CONFIG_FB_SIS_315
3917 sisfb_fixup_SR11(ivideo);
3918#endif
3919
3920 /* Now we actually HAVE changed the display mode */
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003921 ivideo->modechanged = 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003922
3923 /* We can't switch off CRT1 if bridge is in slave mode */
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003924 if(ivideo->vbflags2 & VB2_VIDEOBRIDGE) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003925 if(sisfb_bridgeisslave(ivideo)) doit = FALSE;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003926 } else
3927 ivideo->sisfb_crt1off = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003928
3929#ifdef CONFIG_FB_SIS_300
3930 if(ivideo->sisvga_engine == SIS_300_VGA) {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003931 if((ivideo->sisfb_crt1off) && (doit)) {
3932 crt1isoff = TRUE;
3933 reg = 0x00;
3934 } else {
3935 crt1isoff = FALSE;
3936 reg = 0x80;
3937 }
3938 setSISIDXREG(SISCR, 0x17, 0x7f, reg);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003939 }
3940#endif
3941#ifdef CONFIG_FB_SIS_315
3942 if(ivideo->sisvga_engine == SIS_315_VGA) {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003943 if((ivideo->sisfb_crt1off) && (doit)) {
3944 crt1isoff = TRUE;
3945 reg = 0x40;
3946 reg1 = 0xc0;
3947 } else {
3948 crt1isoff = FALSE;
3949 reg = 0x00;
3950 reg1 = 0x00;
3951 }
3952 setSISIDXREG(SISCR, ivideo->SiS_Pr.SiS_MyCR63, ~0x40, reg);
3953 setSISIDXREG(SISSR, 0x1f, ~0xc0, reg1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003954 }
3955#endif
3956
3957 if(crt1isoff) {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003958 ivideo->currentvbflags &= ~VB_DISPTYPE_CRT1;
3959 ivideo->currentvbflags |= VB_SINGLE_MODE;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003960 } else {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003961 ivideo->currentvbflags |= VB_DISPTYPE_CRT1;
3962 if(ivideo->currentvbflags & VB_DISPTYPE_CRT2) {
3963 ivideo->currentvbflags |= VB_MIRROR_MODE;
3964 } else {
3965 ivideo->currentvbflags |= VB_SINGLE_MODE;
3966 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003967 }
3968
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003969 andSISIDXREG(SISSR, IND_SIS_RAMDAC_CONTROL, ~0x04);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003970
3971 if(ivideo->currentvbflags & CRT2_TV) {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003972 if(ivideo->vbflags2 & VB2_SISBRIDGE) {
3973 inSISIDXREG(SISPART2,0x1f,ivideo->p2_1f);
3974 inSISIDXREG(SISPART2,0x20,ivideo->p2_20);
3975 inSISIDXREG(SISPART2,0x2b,ivideo->p2_2b);
3976 inSISIDXREG(SISPART2,0x42,ivideo->p2_42);
3977 inSISIDXREG(SISPART2,0x43,ivideo->p2_43);
3978 inSISIDXREG(SISPART2,0x01,ivideo->p2_01);
3979 inSISIDXREG(SISPART2,0x02,ivideo->p2_02);
3980 } else if(ivideo->vbflags2 & VB2_CHRONTEL) {
3981 if(ivideo->chronteltype == 1) {
3982 ivideo->tvx = SiS_GetCH700x(&ivideo->SiS_Pr, 0x0a);
3983 ivideo->tvx |= (((SiS_GetCH700x(&ivideo->SiS_Pr, 0x08) & 0x02) >> 1) << 8);
3984 ivideo->tvy = SiS_GetCH700x(&ivideo->SiS_Pr, 0x0b);
3985 ivideo->tvy |= ((SiS_GetCH700x(&ivideo->SiS_Pr, 0x08) & 0x01) << 8);
3986 }
3987 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003988 }
3989
3990 if(ivideo->tvxpos) {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003991 sisfb_set_TVxposoffset(ivideo, ivideo->tvxpos);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003992 }
3993 if(ivideo->tvypos) {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003994 sisfb_set_TVyposoffset(ivideo, ivideo->tvypos);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003995 }
3996
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003997 /* Eventually sync engines */
3998 sisfb_check_engine_and_sync(ivideo);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003999
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004000 /* (Re-)Initialize chip engines */
4001 if(ivideo->accel) {
4002 sisfb_engine_init(ivideo);
4003 } else {
4004 ivideo->engineok = 0;
4005 }
4006}
Linus Torvalds1da177e2005-04-16 15:20:36 -07004007
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004008static int
4009sisfb_reset_mode(struct sis_video_info *ivideo)
4010{
4011 if(sisfb_set_mode(ivideo, 0))
4012 return 1;
4013
4014 sisfb_set_pitch(ivideo);
4015 sisfb_set_base_CRT1(ivideo, ivideo->current_base);
4016 sisfb_set_base_CRT2(ivideo, ivideo->current_base);
4017
4018 return 0;
4019}
4020
4021static void
4022sisfb_handle_command(struct sis_video_info *ivideo, struct sisfb_cmd *sisfb_command)
4023{
4024 int mycrt1off;
4025
4026 switch(sisfb_command->sisfb_cmd) {
4027 case SISFB_CMD_GETVBFLAGS:
4028 if(!ivideo->modechanged) {
4029 sisfb_command->sisfb_result[0] = SISFB_CMD_ERR_EARLY;
4030 } else {
4031 sisfb_command->sisfb_result[0] = SISFB_CMD_ERR_OK;
4032 sisfb_command->sisfb_result[1] = ivideo->currentvbflags;
4033 sisfb_command->sisfb_result[2] = ivideo->vbflags2;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004034 }
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004035 break;
4036 case SISFB_CMD_SWITCHCRT1:
4037 /* arg[0]: 0 = off, 1 = on, 99 = query */
4038 if(!ivideo->modechanged) {
4039 sisfb_command->sisfb_result[0] = SISFB_CMD_ERR_EARLY;
4040 } else if(sisfb_command->sisfb_arg[0] == 99) {
4041 /* Query */
4042 sisfb_command->sisfb_result[1] = ivideo->sisfb_crt1off ? 0 : 1;
4043 sisfb_command->sisfb_result[0] = SISFB_CMD_ERR_OK;
4044 } else if(ivideo->sisfblocked) {
4045 sisfb_command->sisfb_result[0] = SISFB_CMD_ERR_LOCKED;
4046 } else if((!(ivideo->currentvbflags & CRT2_ENABLE)) &&
4047 (sisfb_command->sisfb_arg[0] == 0)) {
4048 sisfb_command->sisfb_result[0] = SISFB_CMD_ERR_NOCRT2;
4049 } else {
4050 sisfb_command->sisfb_result[0] = SISFB_CMD_ERR_OK;
4051 mycrt1off = sisfb_command->sisfb_arg[0] ? 0 : 1;
4052 if( ((ivideo->currentvbflags & VB_DISPTYPE_CRT1) && mycrt1off) ||
4053 ((!(ivideo->currentvbflags & VB_DISPTYPE_CRT1)) && !mycrt1off) ) {
4054 ivideo->sisfb_crt1off = mycrt1off;
4055 if(sisfb_reset_mode(ivideo)) {
4056 sisfb_command->sisfb_result[0] = SISFB_CMD_ERR_OTHER;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004057 }
4058 }
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004059 sisfb_command->sisfb_result[1] = ivideo->sisfb_crt1off ? 0 : 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004060 }
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004061 break;
4062 /* more to come */
4063 default:
4064 sisfb_command->sisfb_result[0] = SISFB_CMD_ERR_UNKNOWN;
4065 printk(KERN_ERR "sisfb: Unknown command 0x%x\n",
4066 sisfb_command->sisfb_cmd);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004067 }
4068}
4069
4070#ifndef MODULE
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004071SISINITSTATIC int __init
4072sisfb_setup(char *options)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004073{
4074 char *this_opt;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004075
Linus Torvalds1da177e2005-04-16 15:20:36 -07004076 sisfb_setdefaultparms();
4077
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004078 if(!options || !(*options))
Linus Torvalds1da177e2005-04-16 15:20:36 -07004079 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004080
4081 while((this_opt = strsep(&options, ",")) != NULL) {
4082
4083 if(!(*this_opt)) continue;
4084
4085 if(!strnicmp(this_opt, "off", 3)) {
4086 sisfb_off = 1;
4087 } else if(!strnicmp(this_opt, "forcecrt2type:", 14)) {
4088 /* Need to check crt2 type first for fstn/dstn */
4089 sisfb_search_crt2type(this_opt + 14);
4090 } else if(!strnicmp(this_opt, "tvmode:",7)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004091 sisfb_search_tvstd(this_opt + 7);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004092 } else if(!strnicmp(this_opt, "tvstandard:",11)) {
4093 sisfb_search_tvstd(this_opt + 11);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004094 } else if(!strnicmp(this_opt, "mode:", 5)) {
4095 sisfb_search_mode(this_opt + 5, FALSE);
4096 } else if(!strnicmp(this_opt, "vesa:", 5)) {
4097 sisfb_search_vesamode(simple_strtoul(this_opt + 5, NULL, 0), FALSE);
4098#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
4099 } else if(!strnicmp(this_opt, "inverse", 7)) {
4100 sisfb_inverse = 1;
4101 /* fb_invert_cmaps(); */
4102 } else if(!strnicmp(this_opt, "font:", 5)) {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004103 if(strlen(this_opt + 5) < 40) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004104 strncpy(sisfb_fontname, this_opt + 5, sizeof(sisfb_fontname) - 1);
4105 sisfb_fontname[sizeof(sisfb_fontname) - 1] = '\0';
4106 }
4107#endif
4108 } else if(!strnicmp(this_opt, "rate:", 5)) {
4109 sisfb_parm_rate = simple_strtoul(this_opt + 5, NULL, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004110 } else if(!strnicmp(this_opt, "forcecrt1:", 10)) {
4111 sisfb_forcecrt1 = (int)simple_strtoul(this_opt + 10, NULL, 0);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004112 } else if(!strnicmp(this_opt, "mem:",4)) {
4113 sisfb_parm_mem = simple_strtoul(this_opt + 4, NULL, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004114 } else if(!strnicmp(this_opt, "pdc:", 4)) {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004115 sisfb_pdc = simple_strtoul(this_opt + 4, NULL, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004116 } else if(!strnicmp(this_opt, "pdc1:", 5)) {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004117 sisfb_pdca = simple_strtoul(this_opt + 5, NULL, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004118 } else if(!strnicmp(this_opt, "noaccel", 7)) {
4119 sisfb_accel = 0;
4120 } else if(!strnicmp(this_opt, "accel", 5)) {
4121 sisfb_accel = -1;
4122 } else if(!strnicmp(this_opt, "noypan", 6)) {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004123 sisfb_ypan = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004124 } else if(!strnicmp(this_opt, "ypan", 4)) {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004125 sisfb_ypan = -1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004126 } else if(!strnicmp(this_opt, "nomax", 5)) {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004127 sisfb_max = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004128 } else if(!strnicmp(this_opt, "max", 3)) {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004129 sisfb_max = -1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004130 } else if(!strnicmp(this_opt, "userom:", 7)) {
4131 sisfb_userom = (int)simple_strtoul(this_opt + 7, NULL, 0);
4132 } else if(!strnicmp(this_opt, "useoem:", 7)) {
4133 sisfb_useoem = (int)simple_strtoul(this_opt + 7, NULL, 0);
4134 } else if(!strnicmp(this_opt, "nocrt2rate", 10)) {
4135 sisfb_nocrt2rate = 1;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004136 } else if(!strnicmp(this_opt, "scalelcd:", 9)) {
4137 unsigned long temp = 2;
4138 temp = simple_strtoul(this_opt + 9, NULL, 0);
4139 if((temp == 0) || (temp == 1)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004140 sisfb_scalelcd = temp ^ 1;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004141 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004142 } else if(!strnicmp(this_opt, "tvxposoffset:", 13)) {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004143 int temp = 0;
4144 temp = (int)simple_strtol(this_opt + 13, NULL, 0);
4145 if((temp >= -32) && (temp <= 32)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004146 sisfb_tvxposoffset = temp;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004147 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004148 } else if(!strnicmp(this_opt, "tvyposoffset:", 13)) {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004149 int temp = 0;
4150 temp = (int)simple_strtol(this_opt + 13, NULL, 0);
4151 if((temp >= -32) && (temp <= 32)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004152 sisfb_tvyposoffset = temp;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004153 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004154 } else if(!strnicmp(this_opt, "specialtiming:", 14)) {
4155 sisfb_search_specialtiming(this_opt + 14);
4156 } else if(!strnicmp(this_opt, "lvdshl:", 7)) {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004157 int temp = 4;
4158 temp = simple_strtoul(this_opt + 7, NULL, 0);
4159 if((temp >= 0) && (temp <= 3)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004160 sisfb_lvdshl = temp;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004161 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004162 } else if(this_opt[0] >= '0' && this_opt[0] <= '9') {
4163 sisfb_search_mode(this_opt, TRUE);
4164#if !defined(__i386__) && !defined(__x86_64__)
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004165 } else if(!strnicmp(this_opt, "resetcard", 9)) {
4166 sisfb_resetcard = 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004167 } else if(!strnicmp(this_opt, "videoram:", 9)) {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004168 sisfb_videoram = simple_strtoul(this_opt + 9, NULL, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004169#endif
4170 } else {
4171 printk(KERN_INFO "sisfb: Invalid option %s\n", this_opt);
4172 }
4173
4174 }
4175
Linus Torvalds1da177e2005-04-16 15:20:36 -07004176 return 0;
4177}
4178#endif
4179
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004180static int __devinit
4181sisfb_check_rom(SIS_IOTYPE1 *rom_base, struct sis_video_info *ivideo)
4182{
4183 SIS_IOTYPE1 *rom;
4184 int romptr;
4185
4186 if((readb(rom_base) != 0x55) || (readb(rom_base + 1) != 0xaa))
4187 return 0;
4188
4189 romptr = (readb(rom_base + 0x18) | (readb(rom_base + 0x19) << 8));
4190 if(romptr > (0x10000 - 8))
4191 return 0;
4192
4193 rom = rom_base + romptr;
4194
4195 if((readb(rom) != 'P') || (readb(rom + 1) != 'C') ||
4196 (readb(rom + 2) != 'I') || (readb(rom + 3) != 'R'))
4197 return 0;
4198
4199 if((readb(rom + 4) | (readb(rom + 5) << 8)) != ivideo->chip_vendor)
4200 return 0;
4201
4202 if((readb(rom + 6) | (readb(rom + 7) << 8)) != ivideo->chip_id)
4203 return 0;
4204
4205 return 1;
4206}
4207
4208static unsigned char * __devinit
4209sisfb_find_rom(struct pci_dev *pdev)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004210{
4211 struct sis_video_info *ivideo = pci_get_drvdata(pdev);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004212 SIS_IOTYPE1 *rom_base;
4213 unsigned char *myrombase = NULL;
4214 u32 temp;
4215#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,11)
4216 size_t romsize;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004217
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004218 /* First, try the official pci ROM functions (except
4219 * on integrated chipsets which have no ROM).
4220 */
4221
4222 if(!ivideo->nbridge) {
4223
4224 if((rom_base = pci_map_rom(pdev, &romsize))) {
4225
4226 if(sisfb_check_rom(rom_base, ivideo)) {
4227
4228 if((myrombase = vmalloc(65536))) {
4229
4230 /* Work around bug in pci/rom.c: Folks forgot to check
4231 * whether the size retrieved from the BIOS image eventually
4232 * is larger than the mapped size
4233 */
4234 if(pci_resource_len(pdev, PCI_ROM_RESOURCE) < romsize)
4235 romsize = pci_resource_len(pdev, PCI_ROM_RESOURCE);
4236
4237 memcpy_fromio(myrombase, rom_base,
4238 (romsize > 65536) ? 65536 : romsize);
4239 }
4240 }
4241 pci_unmap_rom(pdev, rom_base);
4242 }
4243 }
4244
4245 if(myrombase) return myrombase;
4246#endif
4247
4248 /* Otherwise do it the conventional way. */
Linus Torvalds1da177e2005-04-16 15:20:36 -07004249
4250#if defined(__i386__) || defined(__x86_64__)
4251
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004252 for(temp = 0x000c0000; temp < 0x000f0000; temp += 0x00001000) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004253
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004254 rom_base = ioremap(temp, 65536);
4255 if(!rom_base)
4256 continue;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004257
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004258 if(!sisfb_check_rom(rom_base, ivideo)) {
4259 iounmap(rom_base);
4260 continue;
4261 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004262
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004263 if((myrombase = vmalloc(65536)))
4264 memcpy_fromio(myrombase, rom_base, 65536);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004265
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004266 iounmap(rom_base);
4267 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004268
Linus Torvalds1da177e2005-04-16 15:20:36 -07004269 }
4270
4271#else
4272
4273 pci_read_config_dword(pdev, PCI_ROM_ADDRESS, &temp);
4274 pci_write_config_dword(pdev, PCI_ROM_ADDRESS,
4275 (ivideo->video_base & PCI_ROM_ADDRESS_MASK) | PCI_ROM_ADDRESS_ENABLE);
4276
4277 rom_base = ioremap(ivideo->video_base, 65536);
4278 if(rom_base) {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004279 if(sisfb_check_rom(rom_base, ivideo)) {
4280 if((myrombase = vmalloc(65536)))
4281 memcpy_fromio(myrombase, rom_base, 65536);
4282 }
4283 iounmap(rom_base);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004284 }
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004285
4286 pci_write_config_dword(pdev, PCI_ROM_ADDRESS, temp);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004287
4288#endif
4289
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004290 return myrombase;
4291}
4292
4293static void __devinit
4294sisfb_post_map_vram(struct sis_video_info *ivideo, unsigned int *mapsize,
4295 unsigned int min)
4296{
4297 ivideo->video_vbase = ioremap(ivideo->video_base, (*mapsize));
4298
4299 if(!ivideo->video_vbase) {
4300 printk(KERN_ERR
4301 "sisfb: Unable to map maximum video RAM for size detection\n");
4302 (*mapsize) >>= 1;
4303 while((!(ivideo->video_vbase = ioremap(ivideo->video_base, (*mapsize))))) {
4304 (*mapsize) >>= 1;
4305 if((*mapsize) < (min << 20))
4306 break;
4307 }
4308 if(ivideo->video_vbase) {
4309 printk(KERN_ERR
4310 "sisfb: Video RAM size detection limited to %dMB\n",
4311 (int)((*mapsize) >> 20));
4312 }
4313 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004314}
4315
4316#ifdef CONFIG_FB_SIS_300
4317static int __devinit
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004318sisfb_post_300_buswidth(struct sis_video_info *ivideo)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004319{
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004320 SIS_IOTYPE1 *FBAddress = ivideo->video_vbase;
4321 unsigned short temp;
4322 unsigned char reg;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004323 int i, j;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004324
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004325 andSISIDXREG(SISSR, 0x15, 0xFB);
4326 orSISIDXREG(SISSR, 0x15, 0x04);
4327 outSISIDXREG(SISSR, 0x13, 0x00);
4328 outSISIDXREG(SISSR, 0x14, 0xBF);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004329
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004330 for(i = 0; i < 2; i++) {
4331 temp = 0x1234;
4332 for(j = 0; j < 4; j++) {
4333 writew(temp, FBAddress);
4334 if(readw(FBAddress) == temp)
4335 break;
4336 orSISIDXREG(SISSR, 0x3c, 0x01);
4337 inSISIDXREG(SISSR, 0x05, reg);
4338 inSISIDXREG(SISSR, 0x05, reg);
4339 andSISIDXREG(SISSR, 0x3c, 0xfe);
4340 inSISIDXREG(SISSR, 0x05, reg);
4341 inSISIDXREG(SISSR, 0x05, reg);
4342 temp++;
4343 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004344 }
4345
4346 writel(0x01234567L, FBAddress);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004347 writel(0x456789ABL, (FBAddress + 4));
4348 writel(0x89ABCDEFL, (FBAddress + 8));
4349 writel(0xCDEF0123L, (FBAddress + 12));
4350
4351 inSISIDXREG(SISSR, 0x3b, reg);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004352 if(reg & 0x01) {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004353 if(readl((FBAddress + 12)) == 0xCDEF0123L)
4354 return 4; /* Channel A 128bit */
Linus Torvalds1da177e2005-04-16 15:20:36 -07004355 }
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004356
4357 if(readl((FBAddress + 4)) == 0x456789ABL)
4358 return 2; /* Channel B 64bit */
4359
4360 return 1; /* 32bit */
4361}
4362
4363static int __devinit
4364sisfb_post_300_rwtest(struct sis_video_info *ivideo, int iteration, int buswidth,
4365 int PseudoRankCapacity, int PseudoAdrPinCount,
4366 unsigned int mapsize)
4367{
4368 SIS_IOTYPE1 *FBAddr = ivideo->video_vbase;
4369 unsigned short sr14;
4370 unsigned int k, RankCapacity, PageCapacity, BankNumHigh, BankNumMid;
4371 unsigned int PhysicalAdrOtherPage, PhysicalAdrHigh, PhysicalAdrHalfPage;
4372 static const unsigned short SiS_DRAMType[17][5] = {
4373 {0x0C,0x0A,0x02,0x40,0x39},
4374 {0x0D,0x0A,0x01,0x40,0x48},
4375 {0x0C,0x09,0x02,0x20,0x35},
4376 {0x0D,0x09,0x01,0x20,0x44},
4377 {0x0C,0x08,0x02,0x10,0x31},
4378 {0x0D,0x08,0x01,0x10,0x40},
4379 {0x0C,0x0A,0x01,0x20,0x34},
4380 {0x0C,0x09,0x01,0x08,0x32},
4381 {0x0B,0x08,0x02,0x08,0x21},
4382 {0x0C,0x08,0x01,0x08,0x30},
4383 {0x0A,0x08,0x02,0x04,0x11},
4384 {0x0B,0x0A,0x01,0x10,0x28},
4385 {0x09,0x08,0x02,0x02,0x01},
4386 {0x0B,0x09,0x01,0x08,0x24},
4387 {0x0B,0x08,0x01,0x04,0x20},
4388 {0x0A,0x08,0x01,0x02,0x10},
4389 {0x09,0x08,0x01,0x01,0x00}
4390 };
4391
4392 for(k = 0; k <= 16; k++) {
4393
4394 RankCapacity = buswidth * SiS_DRAMType[k][3];
4395
4396 if(RankCapacity != PseudoRankCapacity)
4397 continue;
4398
4399 if((SiS_DRAMType[k][2] + SiS_DRAMType[k][0]) > PseudoAdrPinCount)
4400 continue;
4401
4402 BankNumHigh = RankCapacity * 16 * iteration - 1;
4403 if(iteration == 3) { /* Rank No */
4404 BankNumMid = RankCapacity * 16 - 1;
4405 } else {
4406 BankNumMid = RankCapacity * 16 * iteration / 2 - 1;
4407 }
4408
4409 PageCapacity = (1 << SiS_DRAMType[k][1]) * buswidth * 4;
4410 PhysicalAdrHigh = BankNumHigh;
4411 PhysicalAdrHalfPage = (PageCapacity / 2 + PhysicalAdrHigh) % PageCapacity;
4412 PhysicalAdrOtherPage = PageCapacity * SiS_DRAMType[k][2] + PhysicalAdrHigh;
4413
4414 andSISIDXREG(SISSR, 0x15, 0xFB); /* Test */
4415 orSISIDXREG(SISSR, 0x15, 0x04); /* Test */
4416 sr14 = (SiS_DRAMType[k][3] * buswidth) - 1;
4417 if(buswidth == 4) sr14 |= 0x80;
4418 else if(buswidth == 2) sr14 |= 0x40;
4419 outSISIDXREG(SISSR, 0x13, SiS_DRAMType[k][4]);
4420 outSISIDXREG(SISSR, 0x14, sr14);
4421
4422 BankNumHigh <<= 16;
4423 BankNumMid <<= 16;
4424
4425 if((BankNumHigh + PhysicalAdrHigh >= mapsize) ||
4426 (BankNumMid + PhysicalAdrHigh >= mapsize) ||
4427 (BankNumHigh + PhysicalAdrHalfPage >= mapsize) ||
4428 (BankNumHigh + PhysicalAdrOtherPage >= mapsize))
4429 continue;
4430
4431 /* Write data */
4432 writew(((unsigned short)PhysicalAdrHigh),
4433 (FBAddr + BankNumHigh + PhysicalAdrHigh));
4434 writew(((unsigned short)BankNumMid),
4435 (FBAddr + BankNumMid + PhysicalAdrHigh));
4436 writew(((unsigned short)PhysicalAdrHalfPage),
4437 (FBAddr + BankNumHigh + PhysicalAdrHalfPage));
4438 writew(((unsigned short)PhysicalAdrOtherPage),
4439 (FBAddr + BankNumHigh + PhysicalAdrOtherPage));
4440
4441 /* Read data */
4442 if(readw(FBAddr + BankNumHigh + PhysicalAdrHigh) == PhysicalAdrHigh)
4443 return 1;
4444 }
4445
4446 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004447}
4448
4449static void __devinit
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004450sisfb_post_300_ramsize(struct pci_dev *pdev, unsigned int mapsize)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004451{
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004452 struct sis_video_info *ivideo = pci_get_drvdata(pdev);
4453 int i, j, buswidth;
4454 int PseudoRankCapacity, PseudoAdrPinCount;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004455
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004456 buswidth = sisfb_post_300_buswidth(ivideo);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004457
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004458 for(i = 6; i >= 0; i--) {
4459 PseudoRankCapacity = 1 << i;
4460 for(j = 4; j >= 1; j--) {
4461 PseudoAdrPinCount = 15 - j;
4462 if((PseudoRankCapacity * j) <= 64) {
4463 if(sisfb_post_300_rwtest(ivideo,
4464 j,
4465 buswidth,
4466 PseudoRankCapacity,
4467 PseudoAdrPinCount,
4468 mapsize))
4469 return;
4470 }
4471 }
4472 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004473}
4474
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004475static void __devinit
4476sisfb_post_sis300(struct pci_dev *pdev)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004477{
4478 struct sis_video_info *ivideo = pci_get_drvdata(pdev);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004479 unsigned char *bios = ivideo->SiS_Pr.VirtualRomBase;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004480 u8 reg, v1, v2, v3, v4, v5, v6, v7, v8;
4481 u16 index, rindex, memtype = 0;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004482 unsigned int mapsize;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004483
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004484 if(!ivideo->SiS_Pr.UseROM)
4485 bios = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004486
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004487 outSISIDXREG(SISSR, 0x05, 0x86);
4488
4489 if(bios) {
4490 if(bios[0x52] & 0x80) {
4491 memtype = bios[0x52];
4492 } else {
4493 inSISIDXREG(SISSR, 0x3a, memtype);
4494 }
4495 memtype &= 0x07;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004496 }
4497
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004498 v3 = 0x80; v6 = 0x80;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004499 if(ivideo->revision_id <= 0x13) {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004500 v1 = 0x44; v2 = 0x42;
4501 v4 = 0x44; v5 = 0x42;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004502 } else {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004503 v1 = 0x68; v2 = 0x43; /* Assume 125Mhz MCLK */
4504 v4 = 0x68; v5 = 0x43; /* Assume 125Mhz ECLK */
4505 if(bios) {
4506 index = memtype * 5;
4507 rindex = index + 0x54;
4508 v1 = bios[rindex++];
4509 v2 = bios[rindex++];
4510 v3 = bios[rindex++];
4511 rindex = index + 0x7c;
4512 v4 = bios[rindex++];
4513 v5 = bios[rindex++];
4514 v6 = bios[rindex++];
4515 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004516 }
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004517 outSISIDXREG(SISSR, 0x28, v1);
4518 outSISIDXREG(SISSR, 0x29, v2);
4519 outSISIDXREG(SISSR, 0x2a, v3);
4520 outSISIDXREG(SISSR, 0x2e, v4);
4521 outSISIDXREG(SISSR, 0x2f, v5);
4522 outSISIDXREG(SISSR, 0x30, v6);
4523
Linus Torvalds1da177e2005-04-16 15:20:36 -07004524 v1 = 0x10;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004525 if(bios)
4526 v1 = bios[0xa4];
4527 outSISIDXREG(SISSR, 0x07, v1); /* DAC speed */
4528
4529 outSISIDXREG(SISSR, 0x11, 0x0f); /* DDC, power save */
4530
Linus Torvalds1da177e2005-04-16 15:20:36 -07004531 v1 = 0x01; v2 = 0x43; v3 = 0x1e; v4 = 0x2a;
4532 v5 = 0x06; v6 = 0x00; v7 = 0x00; v8 = 0x00;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004533 if(bios) {
4534 memtype += 0xa5;
4535 v1 = bios[memtype];
4536 v2 = bios[memtype + 8];
4537 v3 = bios[memtype + 16];
4538 v4 = bios[memtype + 24];
4539 v5 = bios[memtype + 32];
4540 v6 = bios[memtype + 40];
4541 v7 = bios[memtype + 48];
4542 v8 = bios[memtype + 56];
Linus Torvalds1da177e2005-04-16 15:20:36 -07004543 }
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004544 if(ivideo->revision_id >= 0x80)
4545 v3 &= 0xfd;
4546 outSISIDXREG(SISSR, 0x15, v1); /* Ram type (assuming 0, BIOS 0xa5 step 8) */
4547 outSISIDXREG(SISSR, 0x16, v2);
4548 outSISIDXREG(SISSR, 0x17, v3);
4549 outSISIDXREG(SISSR, 0x18, v4);
4550 outSISIDXREG(SISSR, 0x19, v5);
4551 outSISIDXREG(SISSR, 0x1a, v6);
4552 outSISIDXREG(SISSR, 0x1b, v7);
4553 outSISIDXREG(SISSR, 0x1c, v8); /* ---- */
4554 andSISIDXREG(SISSR, 0x15 ,0xfb);
4555 orSISIDXREG(SISSR, 0x15, 0x04);
4556 if(bios) {
4557 if(bios[0x53] & 0x02) {
4558 orSISIDXREG(SISSR, 0x19, 0x20);
4559 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004560 }
4561 v1 = 0x04; /* DAC pedestal (BIOS 0xe5) */
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004562 if(ivideo->revision_id >= 0x80)
4563 v1 |= 0x01;
4564 outSISIDXREG(SISSR, 0x1f, v1);
4565 outSISIDXREG(SISSR, 0x20, 0xa4); /* linear & relocated io & disable a0000 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07004566 v1 = 0xf6; v2 = 0x0d; v3 = 0x00;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004567 if(bios) {
4568 v1 = bios[0xe8];
4569 v2 = bios[0xe9];
4570 v3 = bios[0xea];
Linus Torvalds1da177e2005-04-16 15:20:36 -07004571 }
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004572 outSISIDXREG(SISSR, 0x23, v1);
4573 outSISIDXREG(SISSR, 0x24, v2);
4574 outSISIDXREG(SISSR, 0x25, v3);
4575 outSISIDXREG(SISSR, 0x21, 0x84);
4576 outSISIDXREG(SISSR, 0x22, 0x00);
4577 outSISIDXREG(SISCR, 0x37, 0x00);
4578 orSISIDXREG(SISPART1, 0x24, 0x01); /* unlock crt2 */
4579 outSISIDXREG(SISPART1, 0x00, 0x00);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004580 v1 = 0x40; v2 = 0x11;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004581 if(bios) {
4582 v1 = bios[0xec];
4583 v2 = bios[0xeb];
Linus Torvalds1da177e2005-04-16 15:20:36 -07004584 }
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004585 outSISIDXREG(SISPART1, 0x02, v1);
4586
4587 if(ivideo->revision_id >= 0x80)
4588 v2 &= ~0x01;
4589
4590 inSISIDXREG(SISPART4, 0x00, reg);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004591 if((reg == 1) || (reg == 2)) {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004592 outSISIDXREG(SISCR, 0x37, 0x02);
4593 outSISIDXREG(SISPART2, 0x00, 0x1c);
4594 v4 = 0x00; v5 = 0x00; v6 = 0x10;
4595 if(ivideo->SiS_Pr.UseROM) {
4596 v4 = bios[0xf5];
4597 v5 = bios[0xf6];
4598 v6 = bios[0xf7];
4599 }
4600 outSISIDXREG(SISPART4, 0x0d, v4);
4601 outSISIDXREG(SISPART4, 0x0e, v5);
4602 outSISIDXREG(SISPART4, 0x10, v6);
4603 outSISIDXREG(SISPART4, 0x0f, 0x3f);
4604 inSISIDXREG(SISPART4, 0x01, reg);
4605 if(reg >= 0xb0) {
4606 inSISIDXREG(SISPART4, 0x23, reg);
4607 reg &= 0x20;
4608 reg <<= 1;
4609 outSISIDXREG(SISPART4, 0x23, reg);
4610 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004611 } else {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004612 v2 &= ~0x10;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004613 }
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004614 outSISIDXREG(SISSR, 0x32, v2);
4615
4616 andSISIDXREG(SISPART1, 0x24, 0xfe); /* Lock CRT2 */
4617
4618 inSISIDXREG(SISSR, 0x16, reg);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004619 reg &= 0xc3;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004620 outSISIDXREG(SISCR, 0x35, reg);
4621 outSISIDXREG(SISCR, 0x83, 0x00);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004622#if !defined(__i386__) && !defined(__x86_64__)
4623 if(sisfb_videoram) {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004624 outSISIDXREG(SISSR, 0x13, 0x28); /* ? */
4625 reg = ((sisfb_videoram >> 10) - 1) | 0x40;
4626 outSISIDXREG(SISSR, 0x14, reg);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004627 } else {
4628#endif
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004629 /* Need to map max FB size for finding out about RAM size */
4630 mapsize = 64 << 20;
4631 sisfb_post_map_vram(ivideo, &mapsize, 4);
4632
4633 if(ivideo->video_vbase) {
4634 sisfb_post_300_ramsize(pdev, mapsize);
4635 iounmap(ivideo->video_vbase);
4636 } else {
4637 printk(KERN_DEBUG
4638 "sisfb: Failed to map memory for size detection, assuming 8MB\n");
4639 outSISIDXREG(SISSR, 0x13, 0x28); /* ? */
4640 outSISIDXREG(SISSR, 0x14, 0x47); /* 8MB, 64bit default */
4641 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004642#if !defined(__i386__) && !defined(__x86_64__)
4643 }
4644#endif
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004645 if(bios) {
4646 v1 = bios[0xe6];
4647 v2 = bios[0xe7];
Linus Torvalds1da177e2005-04-16 15:20:36 -07004648 } else {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004649 inSISIDXREG(SISSR, 0x3a, reg);
4650 if((reg & 0x30) == 0x30) {
4651 v1 = 0x04; /* PCI */
4652 v2 = 0x92;
4653 } else {
4654 v1 = 0x14; /* AGP */
4655 v2 = 0xb2;
4656 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004657 }
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004658 outSISIDXREG(SISSR, 0x21, v1);
4659 outSISIDXREG(SISSR, 0x22, v2);
4660
4661 /* Sense CRT1 */
4662 sisfb_sense_crt1(ivideo);
4663
4664 /* Set default mode, don't clear screen */
4665 ivideo->SiS_Pr.SiS_UseOEM = FALSE;
4666 SiS_SetEnableDstn(&ivideo->SiS_Pr, FALSE);
4667 SiS_SetEnableFstn(&ivideo->SiS_Pr, FALSE);
4668 ivideo->curFSTN = ivideo->curDSTN = 0;
4669 ivideo->SiS_Pr.VideoMemorySize = 8 << 20;
4670 SiSSetMode(&ivideo->SiS_Pr, 0x2e | 0x80);
4671
4672 outSISIDXREG(SISSR, 0x05, 0x86);
4673
4674 /* Display off */
4675 orSISIDXREG(SISSR, 0x01, 0x20);
4676
4677 /* Save mode number in CR34 */
4678 outSISIDXREG(SISCR, 0x34, 0x2e);
4679
4680 /* Let everyone know what the current mode is */
4681 ivideo->modeprechange = 0x2e;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004682}
4683#endif
4684
4685#ifdef CONFIG_FB_SIS_315
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004686#if 0
4687static void __devinit
4688sisfb_post_sis315330(struct pci_dev *pdev)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004689{
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004690 /* TODO */
Linus Torvalds1da177e2005-04-16 15:20:36 -07004691}
4692#endif
4693
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004694static void __devinit
4695sisfb_post_xgi_delay(struct sis_video_info *ivideo, int delay)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004696{
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004697 unsigned int i;
4698 u8 reg;
4699
4700 for(i = 0; i <= (delay * 10 * 36); i++) {
4701 inSISIDXREG(SISSR, 0x05, reg);
4702 reg++;
4703 }
4704}
4705
4706static int __devinit
4707sisfb_find_host_bridge(struct sis_video_info *ivideo, struct pci_dev *mypdev,
4708 unsigned short pcivendor)
4709{
4710 struct pci_dev *pdev = NULL;
4711 unsigned short temp;
4712 int ret = 0;
4713
4714 while((pdev = SIS_PCI_GET_CLASS(PCI_CLASS_BRIDGE_HOST, pdev))) {
4715 temp = pdev->vendor;
4716 SIS_PCI_PUT_DEVICE(pdev);
4717 if(temp == pcivendor) {
4718 ret = 1;
4719 break;
4720 }
4721 }
4722
4723 return ret;
4724}
4725
4726static int __devinit
4727sisfb_post_xgi_rwtest(struct sis_video_info *ivideo, int starta,
4728 unsigned int enda, unsigned int mapsize)
4729{
4730 unsigned int pos;
4731 int i;
4732
4733 writel(0, ivideo->video_vbase);
4734
4735 for(i = starta; i <= enda; i++) {
4736 pos = 1 << i;
4737 if(pos < mapsize)
4738 writel(pos, ivideo->video_vbase + pos);
4739 }
4740
4741 sisfb_post_xgi_delay(ivideo, 150);
4742
4743 if(readl(ivideo->video_vbase) != 0)
4744 return 0;
4745
4746 for(i = starta; i <= enda; i++) {
4747 pos = 1 << i;
4748 if(pos < mapsize) {
4749 if(readl(ivideo->video_vbase + pos) != pos)
4750 return 0;
4751 } else
4752 return 0;
4753 }
4754
4755 return 1;
4756}
4757
4758static void __devinit
4759sisfb_post_xgi_ramsize(struct sis_video_info *ivideo)
4760{
4761 unsigned int buswidth, ranksize, channelab, mapsize;
4762 int i, j, k, l;
4763 u8 reg, sr14;
4764 static const u8 dramsr13[12 * 5] = {
4765 0x02, 0x0e, 0x0b, 0x80, 0x5d,
4766 0x02, 0x0e, 0x0a, 0x40, 0x59,
4767 0x02, 0x0d, 0x0b, 0x40, 0x4d,
4768 0x02, 0x0e, 0x09, 0x20, 0x55,
4769 0x02, 0x0d, 0x0a, 0x20, 0x49,
4770 0x02, 0x0c, 0x0b, 0x20, 0x3d,
4771 0x02, 0x0e, 0x08, 0x10, 0x51,
4772 0x02, 0x0d, 0x09, 0x10, 0x45,
4773 0x02, 0x0c, 0x0a, 0x10, 0x39,
4774 0x02, 0x0d, 0x08, 0x08, 0x41,
4775 0x02, 0x0c, 0x09, 0x08, 0x35,
4776 0x02, 0x0c, 0x08, 0x04, 0x31
4777 };
4778 static const u8 dramsr13_4[4 * 5] = {
4779 0x02, 0x0d, 0x09, 0x40, 0x45,
4780 0x02, 0x0c, 0x09, 0x20, 0x35,
4781 0x02, 0x0c, 0x08, 0x10, 0x31,
4782 0x02, 0x0b, 0x08, 0x08, 0x21
4783 };
4784
4785 /* Enable linear mode, disable 0xa0000 address decoding */
4786 /* We disable a0000 address decoding, because
4787 * - if running on x86, if the card is disabled, it means
4788 * that another card is in the system. We don't want
4789 * to interphere with that primary card's textmode.
4790 * - if running on non-x86, there usually is no VGA window
4791 * at a0000.
4792 */
4793 orSISIDXREG(SISSR, 0x20, (0x80 | 0x04));
4794
4795 /* Need to map max FB size for finding out about RAM size */
4796 mapsize = 256 << 20;
4797 sisfb_post_map_vram(ivideo, &mapsize, 32);
4798
4799 if(!ivideo->video_vbase) {
4800 printk(KERN_ERR "sisfb: Unable to detect RAM size. Setting default.\n");
4801 outSISIDXREG(SISSR, 0x13, 0x35);
4802 outSISIDXREG(SISSR, 0x14, 0x41);
4803 /* TODO */
4804 return;
4805 }
4806
4807 /* Non-interleaving */
4808 outSISIDXREG(SISSR, 0x15, 0x00);
4809 /* No tiling */
4810 outSISIDXREG(SISSR, 0x1c, 0x00);
4811
4812 if(ivideo->chip == XGI_20) {
4813
4814 channelab = 1;
4815 inSISIDXREG(SISCR, 0x97, reg);
4816 if(!(reg & 0x01)) { /* Single 32/16 */
4817 buswidth = 32;
4818 outSISIDXREG(SISSR, 0x13, 0xb1);
4819 outSISIDXREG(SISSR, 0x14, 0x52);
4820 sisfb_post_xgi_delay(ivideo, 1);
4821 sr14 = 0x02;
4822 if(sisfb_post_xgi_rwtest(ivideo, 23, 24, mapsize))
4823 goto bail_out;
4824
4825 outSISIDXREG(SISSR, 0x13, 0x31);
4826 outSISIDXREG(SISSR, 0x14, 0x42);
4827 sisfb_post_xgi_delay(ivideo, 1);
4828 if(sisfb_post_xgi_rwtest(ivideo, 23, 23, mapsize))
4829 goto bail_out;
4830
4831 buswidth = 16;
4832 outSISIDXREG(SISSR, 0x13, 0xb1);
4833 outSISIDXREG(SISSR, 0x14, 0x41);
4834 sisfb_post_xgi_delay(ivideo, 1);
4835 sr14 = 0x01;
4836 if(sisfb_post_xgi_rwtest(ivideo, 22, 23, mapsize))
4837 goto bail_out;
4838 else
4839 outSISIDXREG(SISSR, 0x13, 0x31);
4840 } else { /* Dual 16/8 */
4841 buswidth = 16;
4842 outSISIDXREG(SISSR, 0x13, 0xb1);
4843 outSISIDXREG(SISSR, 0x14, 0x41);
4844 sisfb_post_xgi_delay(ivideo, 1);
4845 sr14 = 0x01;
4846 if(sisfb_post_xgi_rwtest(ivideo, 22, 23, mapsize))
4847 goto bail_out;
4848
4849 outSISIDXREG(SISSR, 0x13, 0x31);
4850 outSISIDXREG(SISSR, 0x14, 0x31);
4851 sisfb_post_xgi_delay(ivideo, 1);
4852 if(sisfb_post_xgi_rwtest(ivideo, 22, 22, mapsize))
4853 goto bail_out;
4854
4855 buswidth = 8;
4856 outSISIDXREG(SISSR, 0x13, 0xb1);
4857 outSISIDXREG(SISSR, 0x14, 0x30);
4858 sisfb_post_xgi_delay(ivideo, 1);
4859 sr14 = 0x00;
4860 if(sisfb_post_xgi_rwtest(ivideo, 21, 22, mapsize))
4861 goto bail_out;
4862 else
4863 outSISIDXREG(SISSR, 0x13, 0x31);
4864 }
4865
4866 } else { /* XGI_40 */
4867
4868 inSISIDXREG(SISCR, 0x97, reg);
4869 if(!(reg & 0x10)) {
4870 inSISIDXREG(SISSR, 0x39, reg);
4871 reg >>= 1;
4872 }
4873
4874 if(reg & 0x01) { /* DDRII */
4875 buswidth = 32;
4876 if(ivideo->revision_id == 2) {
4877 channelab = 2;
4878 outSISIDXREG(SISSR, 0x13, 0xa1);
4879 outSISIDXREG(SISSR, 0x14, 0x44);
4880 sr14 = 0x04;
4881 sisfb_post_xgi_delay(ivideo, 1);
4882 if(sisfb_post_xgi_rwtest(ivideo, 23, 24, mapsize))
4883 goto bail_out;
4884
4885 outSISIDXREG(SISSR, 0x13, 0x21);
4886 outSISIDXREG(SISSR, 0x14, 0x34);
4887 if(sisfb_post_xgi_rwtest(ivideo, 22, 23, mapsize))
4888 goto bail_out;
4889
4890 channelab = 1;
4891 outSISIDXREG(SISSR, 0x13, 0xa1);
4892 outSISIDXREG(SISSR, 0x14, 0x40);
4893 sr14 = 0x00;
4894 if(sisfb_post_xgi_rwtest(ivideo, 22, 23, mapsize))
4895 goto bail_out;
4896
4897 outSISIDXREG(SISSR, 0x13, 0x21);
4898 outSISIDXREG(SISSR, 0x14, 0x30);
4899 } else {
4900 channelab = 3;
4901 outSISIDXREG(SISSR, 0x13, 0xa1);
4902 outSISIDXREG(SISSR, 0x14, 0x4c);
4903 sr14 = 0x0c;
4904 sisfb_post_xgi_delay(ivideo, 1);
4905 if(sisfb_post_xgi_rwtest(ivideo, 23, 25, mapsize))
4906 goto bail_out;
4907
4908 channelab = 2;
4909 outSISIDXREG(SISSR, 0x14, 0x48);
4910 sisfb_post_xgi_delay(ivideo, 1);
4911 sr14 = 0x08;
4912 if(sisfb_post_xgi_rwtest(ivideo, 23, 24, mapsize))
4913 goto bail_out;
4914
4915 outSISIDXREG(SISSR, 0x13, 0x21);
4916 outSISIDXREG(SISSR, 0x14, 0x3c);
4917 sr14 = 0x0c;
4918
4919 if(sisfb_post_xgi_rwtest(ivideo, 23, 24, mapsize)) {
4920 channelab = 3;
4921 } else {
4922 channelab = 2;
4923 outSISIDXREG(SISSR, 0x14, 0x38);
4924 sr14 = 0x08;
4925 }
4926 }
4927 sisfb_post_xgi_delay(ivideo, 1);
4928
4929 } else { /* DDR */
4930
4931 buswidth = 64;
4932 if(ivideo->revision_id == 2) {
4933 channelab = 1;
4934 outSISIDXREG(SISSR, 0x13, 0xa1);
4935 outSISIDXREG(SISSR, 0x14, 0x52);
4936 sisfb_post_xgi_delay(ivideo, 1);
4937 sr14 = 0x02;
4938 if(sisfb_post_xgi_rwtest(ivideo, 23, 24, mapsize))
4939 goto bail_out;
4940
4941 outSISIDXREG(SISSR, 0x13, 0x21);
4942 outSISIDXREG(SISSR, 0x14, 0x42);
4943 } else {
4944 channelab = 2;
4945 outSISIDXREG(SISSR, 0x13, 0xa1);
4946 outSISIDXREG(SISSR, 0x14, 0x5a);
4947 sisfb_post_xgi_delay(ivideo, 1);
4948 sr14 = 0x0a;
4949 if(sisfb_post_xgi_rwtest(ivideo, 24, 25, mapsize))
4950 goto bail_out;
4951
4952 outSISIDXREG(SISSR, 0x13, 0x21);
4953 outSISIDXREG(SISSR, 0x14, 0x4a);
4954 }
4955 sisfb_post_xgi_delay(ivideo, 1);
4956
4957 }
4958 }
4959
4960bail_out:
4961 setSISIDXREG(SISSR, 0x14, 0xf0, sr14);
4962 sisfb_post_xgi_delay(ivideo, 1);
4963
4964 j = (ivideo->chip == XGI_20) ? 5 : 9;
4965 k = (ivideo->chip == XGI_20) ? 12 : 4;
4966
4967 for(i = 0; i < k; i++) {
4968
4969 reg = (ivideo->chip == XGI_20) ?
4970 dramsr13[(i * 5) + 4] : dramsr13_4[(i * 5) + 4];
4971 setSISIDXREG(SISSR, 0x13, 0x80, reg);
4972 sisfb_post_xgi_delay(ivideo, 50);
4973
4974 ranksize = (ivideo->chip == XGI_20) ?
4975 dramsr13[(i * 5) + 3] : dramsr13_4[(i * 5) + 3];
4976
4977 inSISIDXREG(SISSR, 0x13, reg);
4978 if(reg & 0x80) ranksize <<= 1;
4979
4980 if(ivideo->chip == XGI_20) {
4981 if(buswidth == 16) ranksize <<= 1;
4982 else if(buswidth == 32) ranksize <<= 2;
4983 } else {
4984 if(buswidth == 64) ranksize <<= 1;
4985 }
4986
4987 reg = 0;
4988 l = channelab;
4989 if(l == 3) l = 4;
4990 if((ranksize * l) <= 256) {
4991 while((ranksize >>= 1)) reg += 0x10;
4992 }
4993
4994 if(!reg) continue;
4995
4996 setSISIDXREG(SISSR, 0x14, 0x0f, (reg & 0xf0));
4997 sisfb_post_xgi_delay(ivideo, 1);
4998
4999 if(sisfb_post_xgi_rwtest(ivideo, j, ((reg >> 4) + channelab - 2 + 20), mapsize))
5000 break;
5001 }
5002
5003 iounmap(ivideo->video_vbase);
5004}
5005
5006static void __devinit
5007sisfb_post_xgi_setclocks(struct sis_video_info *ivideo, u8 regb)
5008{
5009 u8 v1, v2, v3;
5010 int index;
5011 static const u8 cs90[8 * 3] = {
5012 0x16, 0x01, 0x01,
5013 0x3e, 0x03, 0x01,
5014 0x7c, 0x08, 0x01,
5015 0x79, 0x06, 0x01,
5016 0x29, 0x01, 0x81,
5017 0x5c, 0x23, 0x01,
5018 0x5c, 0x23, 0x01,
5019 0x5c, 0x23, 0x01
5020 };
5021 static const u8 csb8[8 * 3] = {
5022 0x5c, 0x23, 0x01,
5023 0x29, 0x01, 0x01,
5024 0x7c, 0x08, 0x01,
5025 0x79, 0x06, 0x01,
5026 0x29, 0x01, 0x81,
5027 0x5c, 0x23, 0x01,
5028 0x5c, 0x23, 0x01,
5029 0x5c, 0x23, 0x01
5030 };
5031
5032 regb = 0; /* ! */
5033
5034 index = regb * 3;
5035 v1 = cs90[index]; v2 = cs90[index + 1]; v3 = cs90[index + 2];
5036 if(ivideo->haveXGIROM) {
5037 v1 = ivideo->bios_abase[0x90 + index];
5038 v2 = ivideo->bios_abase[0x90 + index + 1];
5039 v3 = ivideo->bios_abase[0x90 + index + 2];
5040 }
5041 outSISIDXREG(SISSR, 0x28, v1);
5042 outSISIDXREG(SISSR, 0x29, v2);
5043 outSISIDXREG(SISSR, 0x2a, v3);
5044 sisfb_post_xgi_delay(ivideo, 0x43);
5045 sisfb_post_xgi_delay(ivideo, 0x43);
5046 sisfb_post_xgi_delay(ivideo, 0x43);
5047 index = regb * 3;
5048 v1 = csb8[index]; v2 = csb8[index + 1]; v3 = csb8[index + 2];
5049 if(ivideo->haveXGIROM) {
5050 v1 = ivideo->bios_abase[0xb8 + index];
5051 v2 = ivideo->bios_abase[0xb8 + index + 1];
5052 v3 = ivideo->bios_abase[0xb8 + index + 2];
5053 }
5054 outSISIDXREG(SISSR, 0x2e, v1);
5055 outSISIDXREG(SISSR, 0x2f, v2);
5056 outSISIDXREG(SISSR, 0x30, v3);
5057 sisfb_post_xgi_delay(ivideo, 0x43);
5058 sisfb_post_xgi_delay(ivideo, 0x43);
5059 sisfb_post_xgi_delay(ivideo, 0x43);
5060}
5061
5062static int __devinit
5063sisfb_post_xgi(struct pci_dev *pdev)
5064{
5065 struct sis_video_info *ivideo = pci_get_drvdata(pdev);
5066 unsigned char *bios = ivideo->bios_abase;
5067 struct pci_dev *mypdev = NULL;
5068 const u8 *ptr, *ptr2;
5069 u8 v1, v2, v3, v4, v5, reg, ramtype;
5070 u32 rega, regb, regd;
5071 int i, j, k, index;
5072 static const u8 cs78[3] = { 0xf6, 0x0d, 0x00 };
5073 static const u8 cs76[2] = { 0xa3, 0xfb };
5074 static const u8 cs7b[3] = { 0xc0, 0x11, 0x00 };
5075 static const u8 cs158[8] = {
5076 0x88, 0xaa, 0x48, 0x00, 0x00, 0x00, 0x00, 0x00
5077 };
5078 static const u8 cs160[8] = {
5079 0x44, 0x77, 0x77, 0x00, 0x00, 0x00, 0x00, 0x00
5080 };
5081 static const u8 cs168[8] = {
5082 0x48, 0x78, 0x88, 0x00, 0x00, 0x00, 0x00, 0x00
5083 };
5084 static const u8 cs128[3 * 8] = {
5085 0x90, 0x28, 0x24, 0x00, 0x00, 0x00, 0x00, 0x00,
5086 0x77, 0x44, 0x44, 0x00, 0x00, 0x00, 0x00, 0x00,
5087 0x77, 0x44, 0x44, 0x00, 0x00, 0x00, 0x00, 0x00
5088 };
5089 static const u8 cs148[2 * 8] = {
5090 0x55, 0x55, 0x55, 0x00, 0x00, 0x00, 0x00, 0x00,
5091 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
5092 };
5093 static const u8 cs31a[8 * 4] = {
5094 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
5095 0xaa, 0xaa, 0xaa, 0xaa, 0x00, 0x00, 0x00, 0x00,
5096 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
5097 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
5098 };
5099 static const u8 cs33a[8 * 4] = {
5100 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
5101 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
5102 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
5103 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
5104 };
5105 static const u8 cs45a[8 * 2] = {
5106 0x00, 0x00, 0xa0, 0x00, 0xa0, 0x00, 0x00, 0x00,
5107 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
5108 };
5109 static const u8 cs170[7 * 8] = {
5110 0x54, 0x32, 0x44, 0x00, 0x00, 0x00, 0x00, 0x00,
5111 0x54, 0x43, 0x44, 0x00, 0x00, 0x00, 0x00, 0x00,
5112 0x0a, 0x05, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00,
5113 0x44, 0x34, 0x44, 0x00, 0x00, 0x00, 0x00, 0x00,
5114 0x10, 0x0a, 0x0a, 0x00, 0x00, 0x00, 0x00, 0x00,
5115 0x11, 0x0c, 0x0c, 0x00, 0x00, 0x00, 0x00, 0x00,
5116 0x05, 0x05, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00
5117 };
5118 static const u8 cs1a8[3 * 8] = {
5119 0xf0, 0xf0, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x00,
5120 0x05, 0x02, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00,
5121 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
5122 };
5123 static const u8 cs100[2 * 8] = {
5124 0xc4, 0x04, 0x84, 0x00, 0x00, 0x00, 0x00, 0x00,
5125 0xc4, 0x04, 0x84, 0x00, 0x00, 0x00, 0x00, 0x00
5126 };
5127
5128 /* VGA enable */
5129 reg = inSISREG(SISVGAENABLE) | 0x01;
5130 outSISREG(SISVGAENABLE, reg);
5131
5132 /* Misc */
5133 reg = inSISREG(SISMISCR) | 0x01;
5134 outSISREG(SISMISCW, reg);
5135
5136 /* Unlock SR */
5137 outSISIDXREG(SISSR, 0x05, 0x86);
5138 inSISIDXREG(SISSR, 0x05, reg);
5139 if(reg != 0xa1)
5140 return 0;
5141
5142 /* Clear some regs */
5143 for(i = 0; i < 0x22; i++) {
5144 if(0x06 + i == 0x20) continue;
5145 outSISIDXREG(SISSR, 0x06 + i, 0x00);
5146 }
5147 for(i = 0; i < 0x0b; i++) {
5148 outSISIDXREG(SISSR, 0x31 + i, 0x00);
5149 }
5150 for(i = 0; i < 0x10; i++) {
5151 outSISIDXREG(SISCR, 0x30 + i, 0x00);
5152 }
5153
5154 ptr = cs78;
5155 if(ivideo->haveXGIROM) {
5156 ptr = (const u8 *)&bios[0x78];
5157 }
5158 for(i = 0; i < 3; i++) {
5159 outSISIDXREG(SISSR, 0x23 + i, ptr[i]);
5160 }
5161
5162 ptr = cs76;
5163 if(ivideo->haveXGIROM) {
5164 ptr = (const u8 *)&bios[0x76];
5165 }
5166 for(i = 0; i < 2; i++) {
5167 outSISIDXREG(SISSR, 0x21 + i, ptr[i]);
5168 }
5169
5170 v1 = 0x18; v2 = 0x00;
5171 if(ivideo->haveXGIROM) {
5172 v1 = bios[0x74];
5173 v2 = bios[0x75];
5174 }
5175 outSISIDXREG(SISSR, 0x07, v1);
5176 outSISIDXREG(SISSR, 0x11, 0x0f);
5177 outSISIDXREG(SISSR, 0x1f, v2);
5178 /* PCI linear mode, RelIO enabled, A0000 decoding disabled */
5179 outSISIDXREG(SISSR, 0x20, 0x80 | 0x20 | 0x04);
5180 outSISIDXREG(SISSR, 0x27, 0x74);
5181
5182 ptr = cs7b;
5183 if(ivideo->haveXGIROM) {
5184 ptr = (const u8 *)&bios[0x7b];
5185 }
5186 for(i = 0; i < 3; i++) {
5187 outSISIDXREG(SISSR, 0x31 + i, ptr[i]);
5188 }
5189
5190 if(ivideo->chip == XGI_40) {
5191 if(ivideo->revision_id == 2) {
5192 setSISIDXREG(SISSR, 0x3b, 0x3f, 0xc0);
5193 }
5194 outSISIDXREG(SISCR, 0x7d, 0xfe);
5195 outSISIDXREG(SISCR, 0x7e, 0x0f);
5196 }
5197 if(ivideo->revision_id == 0) { /* 40 *and* 20? */
5198 andSISIDXREG(SISCR, 0x58, 0xd7);
5199 inSISIDXREG(SISCR, 0xcb, reg);
5200 if(reg & 0x20) {
5201 setSISIDXREG(SISCR, 0x58, 0xd7, (reg & 0x10) ? 0x08 : 0x20); /* =0x28 Z7 ? */
5202 }
5203 }
5204
5205 reg = (ivideo->chip == XGI_40) ? 0x20 : 0x00;
5206 setSISIDXREG(SISCR, 0x38, 0x1f, reg);
5207
5208 if(ivideo->chip == XGI_20) {
5209 outSISIDXREG(SISSR, 0x36, 0x70);
5210 } else {
5211 outSISIDXREG(SISVID, 0x00, 0x86);
5212 outSISIDXREG(SISVID, 0x32, 0x00);
5213 outSISIDXREG(SISVID, 0x30, 0x00);
5214 outSISIDXREG(SISVID, 0x32, 0x01);
5215 outSISIDXREG(SISVID, 0x30, 0x00);
5216 andSISIDXREG(SISVID, 0x2f, 0xdf);
5217 andSISIDXREG(SISCAP, 0x00, 0x3f);
5218
5219 outSISIDXREG(SISPART1, 0x2f, 0x01);
5220 outSISIDXREG(SISPART1, 0x00, 0x00);
5221 outSISIDXREG(SISPART1, 0x02, bios[0x7e]);
5222 outSISIDXREG(SISPART1, 0x2e, 0x08);
5223 andSISIDXREG(SISPART1, 0x35, 0x7f);
5224 andSISIDXREG(SISPART1, 0x50, 0xfe);
5225
5226 inSISIDXREG(SISPART4, 0x00, reg);
5227 if(reg == 1 || reg == 2) {
5228 outSISIDXREG(SISPART2, 0x00, 0x1c);
5229 outSISIDXREG(SISPART4, 0x0d, bios[0x7f]);
5230 outSISIDXREG(SISPART4, 0x0e, bios[0x80]);
5231 outSISIDXREG(SISPART4, 0x10, bios[0x81]);
5232 andSISIDXREG(SISPART4, 0x0f, 0x3f);
5233
5234 inSISIDXREG(SISPART4, 0x01, reg);
5235 if((reg & 0xf0) >= 0xb0) {
5236 inSISIDXREG(SISPART4, 0x23, reg);
5237 if(reg & 0x20) reg |= 0x40;
5238 outSISIDXREG(SISPART4, 0x23, reg);
5239 reg = (reg & 0x20) ? 0x02 : 0x00;
5240 setSISIDXREG(SISPART1, 0x1e, 0xfd, reg);
5241 }
5242 }
5243
5244 v1 = bios[0x77];
5245
5246 inSISIDXREG(SISSR, 0x3b, reg);
5247 if(reg & 0x02) {
5248 inSISIDXREG(SISSR, 0x3a, reg);
5249 v2 = (reg & 0x30) >> 3;
5250 if(!(v2 & 0x04)) v2 ^= 0x02;
5251 inSISIDXREG(SISSR, 0x39, reg);
5252 if(reg & 0x80) v2 |= 0x80;
5253 v2 |= 0x01;
5254
5255 if((mypdev = SIS_PCI_GET_DEVICE(PCI_VENDOR_ID_SI, 0x0730, NULL))) {
5256 SIS_PCI_PUT_DEVICE(mypdev);
5257 if(((v2 & 0x06) == 2) || ((v2 & 0x06) == 4))
5258 v2 &= 0xf9;
5259 v2 |= 0x08;
5260 v1 &= 0xfe;
5261 } else {
5262 mypdev = SIS_PCI_GET_DEVICE(PCI_VENDOR_ID_SI, 0x0735, NULL);
5263 if(!mypdev)
5264 mypdev = SIS_PCI_GET_DEVICE(PCI_VENDOR_ID_SI, 0x0645, NULL);
5265 if(!mypdev)
5266 mypdev = SIS_PCI_GET_DEVICE(PCI_VENDOR_ID_SI, 0x0650, NULL);
5267 if(mypdev) {
5268 pci_read_config_dword(mypdev, 0x94, &regd);
5269 regd &= 0xfffffeff;
5270 pci_write_config_dword(mypdev, 0x94, regd);
5271 v1 &= 0xfe;
5272 SIS_PCI_PUT_DEVICE(mypdev);
5273 } else if(sisfb_find_host_bridge(ivideo, pdev, PCI_VENDOR_ID_SI)) {
5274 v1 &= 0xfe;
5275 } else if(sisfb_find_host_bridge(ivideo, pdev, 0x1106) ||
5276 sisfb_find_host_bridge(ivideo, pdev, 0x1022) ||
5277 sisfb_find_host_bridge(ivideo, pdev, 0x700e) ||
5278 sisfb_find_host_bridge(ivideo, pdev, 0x10de)) {
5279 if((v2 & 0x06) == 4)
5280 v2 ^= 0x06;
5281 v2 |= 0x08;
5282 }
5283 }
5284 setSISIDXREG(SISCR, 0x5f, 0xf0, v2);
5285 }
5286 outSISIDXREG(SISSR, 0x22, v1);
5287
5288 if(ivideo->revision_id == 2) {
5289 inSISIDXREG(SISSR, 0x3b, v1);
5290 inSISIDXREG(SISSR, 0x3a, v2);
5291 regd = bios[0x90 + 3] | (bios[0x90 + 4] << 8);
5292 if( (!(v1 & 0x02)) && (v2 & 0x30) && (regd < 0xcf) )
5293 setSISIDXREG(SISCR, 0x5f, 0xf1, 0x01);
5294
5295 if((mypdev = SIS_PCI_GET_DEVICE(0x10de, 0x01e0, NULL))) {
5296 /* TODO: set CR5f &0xf1 | 0x01 for version 6570
5297 * of nforce 2 ROM
5298 */
5299 if(0)
5300 setSISIDXREG(SISCR, 0x5f, 0xf1, 0x01);
5301 SIS_PCI_PUT_DEVICE(mypdev);
5302 }
5303 }
5304
5305 v1 = 0x30;
5306 inSISIDXREG(SISSR, 0x3b, reg);
5307 inSISIDXREG(SISCR, 0x5f, v2);
5308 if((!(reg & 0x02)) && (v2 & 0x0e))
5309 v1 |= 0x08;
5310 outSISIDXREG(SISSR, 0x27, v1);
5311
5312 if(bios[0x64] & 0x01) {
5313 setSISIDXREG(SISCR, 0x5f, 0xf0, bios[0x64]);
5314 }
5315
5316 v1 = bios[0x4f7];
5317 pci_read_config_dword(pdev, 0x50, &regd);
5318 regd = (regd >> 20) & 0x0f;
5319 if(regd == 1) {
5320 v1 &= 0xfc;
5321 orSISIDXREG(SISCR, 0x5f, 0x08);
5322 }
5323 outSISIDXREG(SISCR, 0x48, v1);
5324
5325 setSISIDXREG(SISCR, 0x47, 0x04, bios[0x4f6] & 0xfb);
5326 setSISIDXREG(SISCR, 0x49, 0xf0, bios[0x4f8] & 0x0f);
5327 setSISIDXREG(SISCR, 0x4a, 0x60, bios[0x4f9] & 0x9f);
5328 setSISIDXREG(SISCR, 0x4b, 0x08, bios[0x4fa] & 0xf7);
5329 setSISIDXREG(SISCR, 0x4c, 0x80, bios[0x4fb] & 0x7f);
5330 outSISIDXREG(SISCR, 0x70, bios[0x4fc]);
5331 setSISIDXREG(SISCR, 0x71, 0xf0, bios[0x4fd] & 0x0f);
5332 outSISIDXREG(SISCR, 0x74, 0xd0);
5333 setSISIDXREG(SISCR, 0x74, 0xcf, bios[0x4fe] & 0x30);
5334 setSISIDXREG(SISCR, 0x75, 0xe0, bios[0x4ff] & 0x1f);
5335 setSISIDXREG(SISCR, 0x76, 0xe0, bios[0x500] & 0x1f);
5336 v1 = bios[0x501];
5337 if((mypdev = SIS_PCI_GET_DEVICE(0x8086, 0x2530, NULL))) {
5338 v1 = 0xf0;
5339 SIS_PCI_PUT_DEVICE(mypdev);
5340 }
5341 outSISIDXREG(SISCR, 0x77, v1);
5342 }
5343
5344 /* RAM type */
5345
5346 regb = 0; /* ! */
5347
5348 v1 = 0xff;
5349 if(ivideo->haveXGIROM) {
5350 v1 = bios[0x140 + regb];
5351 }
5352 outSISIDXREG(SISCR, 0x6d, v1);
5353
5354 ptr = cs128;
5355 if(ivideo->haveXGIROM) {
5356 ptr = (const u8 *)&bios[0x128];
5357 }
5358 for(i = 0, j = 0; i < 3; i++, j += 8) {
5359 outSISIDXREG(SISCR, 0x68 + i, ptr[j + regb]);
5360 }
5361
5362 ptr = cs31a;
5363 ptr2 = cs33a;
5364 if(ivideo->haveXGIROM) {
5365 index = (ivideo->chip == XGI_20) ? 0x31a : 0x3a6;
5366 ptr = (const u8 *)&bios[index];
5367 ptr2 = (const u8 *)&bios[index + 0x20];
5368 }
5369 for(i = 0; i < 2; i++) {
5370 if(i == 0) {
5371 regd = le32_to_cpu(((u32 *)ptr)[regb]);
5372 rega = 0x6b;
5373 } else {
5374 regd = le32_to_cpu(((u32 *)ptr2)[regb]);
5375 rega = 0x6e;
5376 }
5377 reg = 0x00;
5378 for(j = 0; j < 16; j++) {
5379 reg &= 0xf3;
5380 if(regd & 0x01) reg |= 0x04;
5381 if(regd & 0x02) reg |= 0x08;
5382 regd >>= 2;
5383 outSISIDXREG(SISCR, rega, reg);
5384 inSISIDXREG(SISCR, rega, reg);
5385 inSISIDXREG(SISCR, rega, reg);
5386 reg += 0x10;
5387 }
5388 }
5389
5390 andSISIDXREG(SISCR, 0x6e, 0xfc);
5391
5392 ptr = NULL;
5393 if(ivideo->haveXGIROM) {
5394 index = (ivideo->chip == XGI_20) ? 0x35a : 0x3e6;
5395 ptr = (const u8 *)&bios[index];
5396 }
5397 for(i = 0; i < 4; i++) {
5398 setSISIDXREG(SISCR, 0x6e, 0xfc, i);
5399 reg = 0x00;
5400 for(j = 0; j < 2; j++) {
5401 regd = 0;
5402 if(ptr) {
5403 regd = le32_to_cpu(((u32 *)ptr)[regb * 8]);
5404 ptr += 4;
5405 }
5406 /* reg = 0x00; */
5407 for(k = 0; k < 16; k++) {
5408 reg &= 0xfc;
5409 if(regd & 0x01) reg |= 0x01;
5410 if(regd & 0x02) reg |= 0x02;
5411 regd >>= 2;
5412 outSISIDXREG(SISCR, 0x6f, reg);
5413 inSISIDXREG(SISCR, 0x6f, reg);
5414 inSISIDXREG(SISCR, 0x6f, reg);
5415 reg += 0x08;
5416 }
5417 }
5418 }
5419
5420 ptr = cs148;
5421 if(ivideo->haveXGIROM) {
5422 ptr = (const u8 *)&bios[0x148];
5423 }
5424 for(i = 0, j = 0; i < 2; i++, j += 8) {
5425 outSISIDXREG(SISCR, 0x80 + i, ptr[j + regb]);
5426 }
5427
5428 andSISIDXREG(SISCR, 0x89, 0x8f);
5429
5430 ptr = cs45a;
5431 if(ivideo->haveXGIROM) {
5432 index = (ivideo->chip == XGI_20) ? 0x45a : 0x4e6;
5433 ptr = (const u8 *)&bios[index];
5434 }
5435 regd = le16_to_cpu(((const u16 *)ptr)[regb]);
5436 reg = 0x80;
5437 for(i = 0; i < 5; i++) {
5438 reg &= 0xfc;
5439 if(regd & 0x01) reg |= 0x01;
5440 if(regd & 0x02) reg |= 0x02;
5441 regd >>= 2;
5442 outSISIDXREG(SISCR, 0x89, reg);
5443 inSISIDXREG(SISCR, 0x89, reg);
5444 inSISIDXREG(SISCR, 0x89, reg);
5445 reg += 0x10;
5446 }
5447
5448 v1 = 0xb5; v2 = 0x20; v3 = 0xf0; v4 = 0x13;
5449 if(ivideo->haveXGIROM) {
5450 v1 = bios[0x118 + regb];
5451 v2 = bios[0xf8 + regb];
5452 v3 = bios[0x120 + regb];
5453 v4 = bios[0x1ca];
5454 }
5455 outSISIDXREG(SISCR, 0x45, v1 & 0x0f);
5456 outSISIDXREG(SISCR, 0x99, (v1 >> 4) & 0x07);
5457 orSISIDXREG(SISCR, 0x40, v1 & 0x80);
5458 outSISIDXREG(SISCR, 0x41, v2);
5459
5460 ptr = cs170;
5461 if(ivideo->haveXGIROM) {
5462 ptr = (const u8 *)&bios[0x170];
5463 }
5464 for(i = 0, j = 0; i < 7; i++, j += 8) {
5465 outSISIDXREG(SISCR, 0x90 + i, ptr[j + regb]);
5466 }
5467
5468 outSISIDXREG(SISCR, 0x59, v3);
5469
5470 ptr = cs1a8;
5471 if(ivideo->haveXGIROM) {
5472 ptr = (const u8 *)&bios[0x1a8];
5473 }
5474 for(i = 0, j = 0; i < 3; i++, j += 8) {
5475 outSISIDXREG(SISCR, 0xc3 + i, ptr[j + regb]);
5476 }
5477
5478 ptr = cs100;
5479 if(ivideo->haveXGIROM) {
5480 ptr = (const u8 *)&bios[0x100];
5481 }
5482 for(i = 0, j = 0; i < 2; i++, j += 8) {
5483 outSISIDXREG(SISCR, 0x8a + i, ptr[j + regb]);
5484 }
5485
5486 outSISIDXREG(SISCR, 0xcf, v4);
5487
5488 outSISIDXREG(SISCR, 0x83, 0x09);
5489 outSISIDXREG(SISCR, 0x87, 0x00);
5490
5491 if(ivideo->chip == XGI_40) {
5492 if( (ivideo->revision_id == 1) ||
5493 (ivideo->revision_id == 2) ) {
5494 outSISIDXREG(SISCR, 0x8c, 0x87);
5495 }
5496 }
5497
5498 outSISIDXREG(SISSR, 0x17, 0x00);
5499 outSISIDXREG(SISSR, 0x1a, 0x87);
5500
5501 if(ivideo->chip == XGI_20) {
5502 outSISIDXREG(SISSR, 0x15, 0x00);
5503 outSISIDXREG(SISSR, 0x1c, 0x00);
5504 }
5505
5506 ramtype = 0x00; v1 = 0x10;
5507 if(ivideo->haveXGIROM) {
5508 ramtype = bios[0x62];
5509 v1 = bios[0x1d2];
5510 }
5511 if(!(ramtype & 0x80)) {
5512 if(ivideo->chip == XGI_20) {
5513 outSISIDXREG(SISCR, 0x97, v1);
5514 inSISIDXREG(SISCR, 0x97, reg);
5515 if(reg & 0x10) {
5516 ramtype = (reg & 0x01) << 1;
5517 }
5518 } else {
5519 inSISIDXREG(SISSR, 0x39, reg);
5520 ramtype = reg & 0x02;
5521 if(!(ramtype)) {
5522 inSISIDXREG(SISSR, 0x3a, reg);
5523 ramtype = (reg >> 1) & 0x01;
5524 }
5525 }
5526 }
5527 ramtype &= 0x07;
5528
5529 regb = 0; /* ! */
5530
5531 switch(ramtype) {
5532 case 0:
5533 sisfb_post_xgi_setclocks(ivideo, regb);
5534 if((ivideo->chip == XGI_20) ||
5535 (ivideo->revision_id == 1) ||
5536 (ivideo->revision_id == 2)) {
5537 v1 = cs158[regb]; v2 = cs160[regb]; v3 = cs168[regb];
5538 if(ivideo->haveXGIROM) {
5539 v1 = bios[regb + 0x158];
5540 v2 = bios[regb + 0x160];
5541 v3 = bios[regb + 0x168];
5542 }
5543 outSISIDXREG(SISCR, 0x82, v1);
5544 outSISIDXREG(SISCR, 0x85, v2);
5545 outSISIDXREG(SISCR, 0x86, v3);
5546 } else {
5547 outSISIDXREG(SISCR, 0x82, 0x88);
5548 outSISIDXREG(SISCR, 0x86, 0x00);
5549 inSISIDXREG(SISCR, 0x86, reg);
5550 outSISIDXREG(SISCR, 0x86, 0x88);
5551 inSISIDXREG(SISCR, 0x86, reg);
5552 outSISIDXREG(SISCR, 0x86, bios[regb + 0x168]);
5553 outSISIDXREG(SISCR, 0x82, 0x77);
5554 outSISIDXREG(SISCR, 0x85, 0x00);
5555 inSISIDXREG(SISCR, 0x85, reg);
5556 outSISIDXREG(SISCR, 0x85, 0x88);
5557 inSISIDXREG(SISCR, 0x85, reg);
5558 outSISIDXREG(SISCR, 0x85, bios[regb + 0x160]);
5559 outSISIDXREG(SISCR, 0x82, bios[regb + 0x158]);
5560 }
5561 if(ivideo->chip == XGI_40) {
5562 outSISIDXREG(SISCR, 0x97, 0x00);
5563 }
5564 outSISIDXREG(SISCR, 0x98, 0x01);
5565 outSISIDXREG(SISCR, 0x9a, 0x02);
5566
5567 outSISIDXREG(SISSR, 0x18, 0x01);
5568 if((ivideo->chip == XGI_20) ||
5569 (ivideo->revision_id == 2)) {
5570 outSISIDXREG(SISSR, 0x19, 0x40);
5571 } else {
5572 outSISIDXREG(SISSR, 0x19, 0x20);
5573 }
5574 outSISIDXREG(SISSR, 0x16, 0x00);
5575 outSISIDXREG(SISSR, 0x16, 0x80);
5576 if((ivideo->chip == XGI_20) || (bios[0x1cb] != 0x0c)) {
5577 sisfb_post_xgi_delay(ivideo, 0x43);
5578 sisfb_post_xgi_delay(ivideo, 0x43);
5579 sisfb_post_xgi_delay(ivideo, 0x43);
5580 outSISIDXREG(SISSR, 0x18, 0x00);
5581 if((ivideo->chip == XGI_20) ||
5582 (ivideo->revision_id == 2)) {
5583 outSISIDXREG(SISSR, 0x19, 0x40);
5584 } else {
5585 outSISIDXREG(SISSR, 0x19, 0x20);
5586 }
5587 } else if((ivideo->chip == XGI_40) && (bios[0x1cb] == 0x0c)) {
5588 /* outSISIDXREG(SISSR, 0x16, 0x0c); */ /* ? */
5589 }
5590 outSISIDXREG(SISSR, 0x16, 0x00);
5591 outSISIDXREG(SISSR, 0x16, 0x80);
5592 sisfb_post_xgi_delay(ivideo, 4);
5593 v1 = 0x31; v2 = 0x03; v3 = 0x83; v4 = 0x03; v5 = 0x83;
5594 if(ivideo->haveXGIROM) {
5595 v1 = bios[0xf0];
5596 index = (ivideo->chip == XGI_20) ? 0x4b2 : 0x53e;
5597 v2 = bios[index];
5598 v3 = bios[index + 1];
5599 v4 = bios[index + 2];
5600 v5 = bios[index + 3];
5601 }
5602 outSISIDXREG(SISSR, 0x18, v1);
5603 outSISIDXREG(SISSR, 0x19, ((ivideo->chip == XGI_20) ? 0x02 : 0x01));
5604 outSISIDXREG(SISSR, 0x16, v2);
5605 outSISIDXREG(SISSR, 0x16, v3);
5606 sisfb_post_xgi_delay(ivideo, 0x43);
5607 outSISIDXREG(SISSR, 0x1b, 0x03);
5608 sisfb_post_xgi_delay(ivideo, 0x22);
5609 outSISIDXREG(SISSR, 0x18, v1);
5610 outSISIDXREG(SISSR, 0x19, 0x00);
5611 outSISIDXREG(SISSR, 0x16, v4);
5612 outSISIDXREG(SISSR, 0x16, v5);
5613 outSISIDXREG(SISSR, 0x1b, 0x00);
5614 break;
5615 case 1:
5616 outSISIDXREG(SISCR, 0x82, 0x77);
5617 outSISIDXREG(SISCR, 0x86, 0x00);
5618 inSISIDXREG(SISCR, 0x86, reg);
5619 outSISIDXREG(SISCR, 0x86, 0x88);
5620 inSISIDXREG(SISCR, 0x86, reg);
5621 v1 = cs168[regb]; v2 = cs160[regb]; v3 = cs158[regb];
5622 if(ivideo->haveXGIROM) {
5623 v1 = bios[regb + 0x168];
5624 v2 = bios[regb + 0x160];
5625 v3 = bios[regb + 0x158];
5626 }
5627 outSISIDXREG(SISCR, 0x86, v1);
5628 outSISIDXREG(SISCR, 0x82, 0x77);
5629 outSISIDXREG(SISCR, 0x85, 0x00);
5630 inSISIDXREG(SISCR, 0x85, reg);
5631 outSISIDXREG(SISCR, 0x85, 0x88);
5632 inSISIDXREG(SISCR, 0x85, reg);
5633 outSISIDXREG(SISCR, 0x85, v2);
5634 outSISIDXREG(SISCR, 0x82, v3);
5635 outSISIDXREG(SISCR, 0x98, 0x01);
5636 outSISIDXREG(SISCR, 0x9a, 0x02);
5637
5638 outSISIDXREG(SISSR, 0x28, 0x64);
5639 outSISIDXREG(SISSR, 0x29, 0x63);
5640 sisfb_post_xgi_delay(ivideo, 15);
5641 outSISIDXREG(SISSR, 0x18, 0x00);
5642 outSISIDXREG(SISSR, 0x19, 0x20);
5643 outSISIDXREG(SISSR, 0x16, 0x00);
5644 outSISIDXREG(SISSR, 0x16, 0x80);
5645 outSISIDXREG(SISSR, 0x18, 0xc5);
5646 outSISIDXREG(SISSR, 0x19, 0x23);
5647 outSISIDXREG(SISSR, 0x16, 0x00);
5648 outSISIDXREG(SISSR, 0x16, 0x80);
5649 sisfb_post_xgi_delay(ivideo, 1);
5650 outSISIDXREG(SISCR, 0x97,0x11);
5651 sisfb_post_xgi_setclocks(ivideo, regb);
5652 sisfb_post_xgi_delay(ivideo, 0x46);
5653 outSISIDXREG(SISSR, 0x18, 0xc5);
5654 outSISIDXREG(SISSR, 0x19, 0x23);
5655 outSISIDXREG(SISSR, 0x16, 0x00);
5656 outSISIDXREG(SISSR, 0x16, 0x80);
5657 sisfb_post_xgi_delay(ivideo, 1);
5658 outSISIDXREG(SISSR, 0x1b, 0x04);
5659 sisfb_post_xgi_delay(ivideo, 1);
5660 outSISIDXREG(SISSR, 0x1b, 0x00);
5661 sisfb_post_xgi_delay(ivideo, 1);
5662 v1 = 0x31;
5663 if(ivideo->haveXGIROM) {
5664 v1 = bios[0xf0];
5665 }
5666 outSISIDXREG(SISSR, 0x18, v1);
5667 outSISIDXREG(SISSR, 0x19, 0x06);
5668 outSISIDXREG(SISSR, 0x16, 0x04);
5669 outSISIDXREG(SISSR, 0x16, 0x84);
5670 sisfb_post_xgi_delay(ivideo, 1);
5671 break;
5672 default:
5673 sisfb_post_xgi_setclocks(ivideo, regb);
5674 if((ivideo->chip == XGI_40) &&
5675 ((ivideo->revision_id == 1) ||
5676 (ivideo->revision_id == 2))) {
5677 outSISIDXREG(SISCR, 0x82, bios[regb + 0x158]);
5678 outSISIDXREG(SISCR, 0x85, bios[regb + 0x160]);
5679 outSISIDXREG(SISCR, 0x86, bios[regb + 0x168]);
5680 } else {
5681 outSISIDXREG(SISCR, 0x82, 0x88);
5682 outSISIDXREG(SISCR, 0x86, 0x00);
5683 inSISIDXREG(SISCR, 0x86, reg);
5684 outSISIDXREG(SISCR, 0x86, 0x88);
5685 outSISIDXREG(SISCR, 0x82, 0x77);
5686 outSISIDXREG(SISCR, 0x85, 0x00);
5687 inSISIDXREG(SISCR, 0x85, reg);
5688 outSISIDXREG(SISCR, 0x85, 0x88);
5689 inSISIDXREG(SISCR, 0x85, reg);
5690 v1 = cs160[regb]; v2 = cs158[regb];
5691 if(ivideo->haveXGIROM) {
5692 v1 = bios[regb + 0x160];
5693 v2 = bios[regb + 0x158];
5694 }
5695 outSISIDXREG(SISCR, 0x85, v1);
5696 outSISIDXREG(SISCR, 0x82, v2);
5697 }
5698 if(ivideo->chip == XGI_40) {
5699 outSISIDXREG(SISCR, 0x97, 0x11);
5700 }
5701 if((ivideo->chip == XGI_40) && (ivideo->revision_id == 2)) {
5702 outSISIDXREG(SISCR, 0x98, 0x01);
5703 } else {
5704 outSISIDXREG(SISCR, 0x98, 0x03);
5705 }
5706 outSISIDXREG(SISCR, 0x9a, 0x02);
5707
5708 if(ivideo->chip == XGI_40) {
5709 outSISIDXREG(SISSR, 0x18, 0x01);
5710 } else {
5711 outSISIDXREG(SISSR, 0x18, 0x00);
5712 }
5713 outSISIDXREG(SISSR, 0x19, 0x40);
5714 outSISIDXREG(SISSR, 0x16, 0x00);
5715 outSISIDXREG(SISSR, 0x16, 0x80);
5716 if((ivideo->chip == XGI_40) && (bios[0x1cb] != 0x0c)) {
5717 sisfb_post_xgi_delay(ivideo, 0x43);
5718 sisfb_post_xgi_delay(ivideo, 0x43);
5719 sisfb_post_xgi_delay(ivideo, 0x43);
5720 outSISIDXREG(SISSR, 0x18, 0x00);
5721 outSISIDXREG(SISSR, 0x19, 0x40);
5722 outSISIDXREG(SISSR, 0x16, 0x00);
5723 outSISIDXREG(SISSR, 0x16, 0x80);
5724 }
5725 sisfb_post_xgi_delay(ivideo, 4);
5726 v1 = 0x31;
5727 if(ivideo->haveXGIROM) {
5728 v1 = bios[0xf0];
5729 }
5730 outSISIDXREG(SISSR, 0x18, v1);
5731 outSISIDXREG(SISSR, 0x19, 0x01);
5732 if(ivideo->chip == XGI_40) {
5733 outSISIDXREG(SISSR, 0x16, bios[0x53e]);
5734 outSISIDXREG(SISSR, 0x16, bios[0x53f]);
5735 } else {
5736 outSISIDXREG(SISSR, 0x16, 0x05);
5737 outSISIDXREG(SISSR, 0x16, 0x85);
5738 }
5739 sisfb_post_xgi_delay(ivideo, 0x43);
5740 if(ivideo->chip == XGI_40) {
5741 outSISIDXREG(SISSR, 0x1b, 0x01);
5742 } else {
5743 outSISIDXREG(SISSR, 0x1b, 0x03);
5744 }
5745 sisfb_post_xgi_delay(ivideo, 0x22);
5746 outSISIDXREG(SISSR, 0x18, v1);
5747 outSISIDXREG(SISSR, 0x19, 0x00);
5748 if(ivideo->chip == XGI_40) {
5749 outSISIDXREG(SISSR, 0x16, bios[0x540]);
5750 outSISIDXREG(SISSR, 0x16, bios[0x541]);
5751 } else {
5752 outSISIDXREG(SISSR, 0x16, 0x05);
5753 outSISIDXREG(SISSR, 0x16, 0x85);
5754 }
5755 outSISIDXREG(SISSR, 0x1b, 0x00);
5756 }
5757
5758 regb = 0; /* ! */
5759 v1 = 0x03;
5760 if(ivideo->haveXGIROM) {
5761 v1 = bios[0x110 + regb];
5762 }
5763 outSISIDXREG(SISSR, 0x1b, v1);
5764
5765 /* RAM size */
5766 v1 = 0x00; v2 = 0x00;
5767 if(ivideo->haveXGIROM) {
5768 v1 = bios[0x62];
5769 v2 = bios[0x63];
5770 }
5771 regb = 0; /* ! */
5772 regd = 1 << regb;
5773 if((v1 & 0x40) && (v2 & regd) && ivideo->haveXGIROM) {
5774
5775 outSISIDXREG(SISSR, 0x13, bios[regb + 0xe0]);
5776 outSISIDXREG(SISSR, 0x14, bios[regb + 0xe0 + 8]);
5777
5778 } else {
5779
5780 /* Set default mode, don't clear screen */
5781 ivideo->SiS_Pr.SiS_UseOEM = FALSE;
5782 SiS_SetEnableDstn(&ivideo->SiS_Pr, FALSE);
5783 SiS_SetEnableFstn(&ivideo->SiS_Pr, FALSE);
5784 ivideo->curFSTN = ivideo->curDSTN = 0;
5785 ivideo->SiS_Pr.VideoMemorySize = 8 << 20;
5786 SiSSetMode(&ivideo->SiS_Pr, 0x2e | 0x80);
5787
5788 outSISIDXREG(SISSR, 0x05, 0x86);
5789
5790 /* Disable read-cache */
5791 andSISIDXREG(SISSR, 0x21, 0xdf);
5792 sisfb_post_xgi_ramsize(ivideo);
5793 /* Enable read-cache */
5794 orSISIDXREG(SISSR, 0x21, 0x20);
5795
5796 }
5797
5798#if 0
5799 printk(KERN_DEBUG "-----------------\n");
5800 for(i = 0; i < 0xff; i++) {
5801 inSISIDXREG(SISCR, i, reg);
5802 printk(KERN_DEBUG "CR%02x(%x) = 0x%02x\n", i, SISCR, reg);
5803 }
5804 for(i = 0; i < 0x40; i++) {
5805 inSISIDXREG(SISSR, i, reg);
5806 printk(KERN_DEBUG "SR%02x(%x) = 0x%02x\n", i, SISSR, reg);
5807 }
5808 printk(KERN_DEBUG "-----------------\n");
5809#endif
5810
5811 /* Sense CRT1 */
5812 if(ivideo->chip == XGI_20) {
5813 orSISIDXREG(SISCR, 0x32, 0x20);
5814 } else {
5815 inSISIDXREG(SISPART4, 0x00, reg);
5816 if((reg == 1) || (reg == 2)) {
5817 sisfb_sense_crt1(ivideo);
5818 } else {
5819 orSISIDXREG(SISCR, 0x32, 0x20);
5820 }
5821 }
5822
5823 /* Set default mode, don't clear screen */
5824 ivideo->SiS_Pr.SiS_UseOEM = FALSE;
5825 SiS_SetEnableDstn(&ivideo->SiS_Pr, FALSE);
5826 SiS_SetEnableFstn(&ivideo->SiS_Pr, FALSE);
5827 ivideo->curFSTN = ivideo->curDSTN = 0;
5828 SiSSetMode(&ivideo->SiS_Pr, 0x2e | 0x80);
5829
5830 outSISIDXREG(SISSR, 0x05, 0x86);
5831
5832 /* Display off */
5833 orSISIDXREG(SISSR, 0x01, 0x20);
5834
5835 /* Save mode number in CR34 */
5836 outSISIDXREG(SISCR, 0x34, 0x2e);
5837
5838 /* Let everyone know what the current mode is */
5839 ivideo->modeprechange = 0x2e;
5840
5841 if(ivideo->chip == XGI_40) {
5842 inSISIDXREG(SISCR, 0xca, reg);
5843 inSISIDXREG(SISCR, 0xcc, v1);
5844 if((reg & 0x10) && (!(v1 & 0x04))) {
5845 printk(KERN_ERR
5846 "sisfb: Please connect power to the card.\n");
5847 return 0;
5848 }
5849 }
5850
5851 return 1;
5852}
5853#endif
5854
5855static int __devinit
5856sisfb_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
5857{
5858 struct sisfb_chip_info *chipinfo = &sisfb_chip_info[ent->driver_data];
5859 struct sis_video_info *ivideo = NULL;
5860 struct fb_info *sis_fb_info = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005861 u16 reg16;
5862 u8 reg;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07005863 int i, ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005864
Thomas Winischhofer544393f2005-09-09 13:04:45 -07005865 if(sisfb_off)
5866 return -ENXIO;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005867
5868#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,3))
5869 sis_fb_info = framebuffer_alloc(sizeof(*ivideo), &pdev->dev);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07005870 if(!sis_fb_info)
5871 return -ENOMEM;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005872#else
5873 sis_fb_info = kmalloc(sizeof(*sis_fb_info) + sizeof(*ivideo), GFP_KERNEL);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07005874 if(!sis_fb_info)
5875 return -ENOMEM;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005876 memset(sis_fb_info, 0, sizeof(*sis_fb_info) + sizeof(*ivideo));
5877 sis_fb_info->par = ((char *)sis_fb_info + sizeof(*sis_fb_info));
5878#endif
5879
5880 ivideo = (struct sis_video_info *)sis_fb_info->par;
5881 ivideo->memyselfandi = sis_fb_info;
5882
Thomas Winischhofer544393f2005-09-09 13:04:45 -07005883 ivideo->sisfb_id = SISFB_ID;
5884
Linus Torvalds1da177e2005-04-16 15:20:36 -07005885 if(card_list == NULL) {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07005886 ivideo->cardnumber = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005887 } else {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07005888 struct sis_video_info *countvideo = card_list;
5889 ivideo->cardnumber = 1;
5890 while((countvideo = countvideo->next) != 0)
5891 ivideo->cardnumber++;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005892 }
5893
5894 strncpy(ivideo->myid, chipinfo->chip_name, 30);
5895
5896 ivideo->warncount = 0;
5897 ivideo->chip_id = pdev->device;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07005898 ivideo->chip_vendor = pdev->vendor;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005899 pci_read_config_byte(pdev, PCI_REVISION_ID, &ivideo->revision_id);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07005900 ivideo->SiS_Pr.ChipRevision = ivideo->revision_id;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005901 pci_read_config_word(pdev, PCI_COMMAND, &reg16);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07005902 ivideo->sisvga_enabled = reg16 & 0x01;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005903 ivideo->pcibus = pdev->bus->number;
5904 ivideo->pcislot = PCI_SLOT(pdev->devfn);
5905 ivideo->pcifunc = PCI_FUNC(pdev->devfn);
5906 ivideo->subsysvendor = pdev->subsystem_vendor;
5907 ivideo->subsysdevice = pdev->subsystem_device;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07005908#ifdef SIS_OLD_CONFIG_COMPAT
5909 ivideo->ioctl32registered = 0;
5910#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -07005911
5912#ifndef MODULE
5913 if(sisfb_mode_idx == -1) {
5914 sisfb_get_vga_mode_from_kernel();
5915 }
5916#endif
5917
5918 ivideo->chip = chipinfo->chip;
5919 ivideo->sisvga_engine = chipinfo->vgaengine;
5920 ivideo->hwcursor_size = chipinfo->hwcursor_size;
5921 ivideo->CRT2_write_enable = chipinfo->CRT2_write_enable;
5922 ivideo->mni = chipinfo->mni;
5923
5924 ivideo->detectedpdc = 0xff;
5925 ivideo->detectedpdca = 0xff;
5926 ivideo->detectedlcda = 0xff;
5927
5928 ivideo->sisfb_thismonitor.datavalid = FALSE;
5929
Thomas Winischhofer544393f2005-09-09 13:04:45 -07005930 ivideo->current_base = 0;
5931
5932 ivideo->engineok = 0;
5933
5934 ivideo->sisfb_was_boot_device = 0;
5935#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,12))
5936 if(pdev->resource[PCI_ROM_RESOURCE].flags & IORESOURCE_ROM_SHADOW) {
5937 if(ivideo->sisvga_enabled)
5938 ivideo->sisfb_was_boot_device = 1;
5939 else {
5940 printk(KERN_DEBUG "sisfb: PCI device is disabled, "
5941 "but marked as boot video device ???\n");
5942 printk(KERN_DEBUG "sisfb: I will not accept this "
5943 "as the primary VGA device\n");
5944 }
5945 }
5946#endif
5947
Linus Torvalds1da177e2005-04-16 15:20:36 -07005948 ivideo->sisfb_parm_mem = sisfb_parm_mem;
5949 ivideo->sisfb_accel = sisfb_accel;
5950 ivideo->sisfb_ypan = sisfb_ypan;
5951 ivideo->sisfb_max = sisfb_max;
5952 ivideo->sisfb_userom = sisfb_userom;
5953 ivideo->sisfb_useoem = sisfb_useoem;
5954 ivideo->sisfb_mode_idx = sisfb_mode_idx;
5955 ivideo->sisfb_parm_rate = sisfb_parm_rate;
5956 ivideo->sisfb_crt1off = sisfb_crt1off;
5957 ivideo->sisfb_forcecrt1 = sisfb_forcecrt1;
5958 ivideo->sisfb_crt2type = sisfb_crt2type;
5959 ivideo->sisfb_crt2flags = sisfb_crt2flags;
5960 /* pdc(a), scalelcd, special timing, lvdshl handled below */
5961 ivideo->sisfb_dstn = sisfb_dstn;
5962 ivideo->sisfb_fstn = sisfb_fstn;
5963 ivideo->sisfb_tvplug = sisfb_tvplug;
5964 ivideo->sisfb_tvstd = sisfb_tvstd;
5965 ivideo->tvxpos = sisfb_tvxposoffset;
5966 ivideo->tvypos = sisfb_tvyposoffset;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005967 ivideo->sisfb_nocrt2rate = sisfb_nocrt2rate;
5968#if LINUX_VERSION_CODE <= KERNEL_VERSION(2,5,0)
5969 ivideo->sisfb_inverse = sisfb_inverse;
5970#endif
5971
5972 ivideo->refresh_rate = 0;
5973 if(ivideo->sisfb_parm_rate != -1) {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07005974 ivideo->refresh_rate = ivideo->sisfb_parm_rate;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005975 }
5976
5977 ivideo->SiS_Pr.UsePanelScaler = sisfb_scalelcd;
5978 ivideo->SiS_Pr.CenterScreen = -1;
5979 ivideo->SiS_Pr.SiS_CustomT = sisfb_specialtiming;
5980 ivideo->SiS_Pr.LVDSHL = sisfb_lvdshl;
5981
5982 ivideo->SiS_Pr.SiS_Backup70xx = 0xff;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07005983 ivideo->SiS_Pr.SiS_CHOverScan = -1;
5984 ivideo->SiS_Pr.SiS_ChSW = FALSE;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005985 ivideo->SiS_Pr.SiS_UseLCDA = FALSE;
5986 ivideo->SiS_Pr.HaveEMI = FALSE;
5987 ivideo->SiS_Pr.HaveEMILCD = FALSE;
5988 ivideo->SiS_Pr.OverruleEMI = FALSE;
5989 ivideo->SiS_Pr.SiS_SensibleSR11 = FALSE;
5990 ivideo->SiS_Pr.SiS_MyCR63 = 0x63;
5991 ivideo->SiS_Pr.PDC = -1;
5992 ivideo->SiS_Pr.PDCA = -1;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07005993 ivideo->SiS_Pr.DDCPortMixup = FALSE;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005994#ifdef CONFIG_FB_SIS_315
5995 if(ivideo->chip >= SIS_330) {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07005996 ivideo->SiS_Pr.SiS_MyCR63 = 0x53;
5997 if(ivideo->chip >= SIS_661) {
5998 ivideo->SiS_Pr.SiS_SensibleSR11 = TRUE;
5999 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07006000 }
6001#endif
6002
6003 memcpy(&ivideo->default_var, &my_default_var, sizeof(my_default_var));
6004
6005 pci_set_drvdata(pdev, ivideo);
6006
6007 /* Patch special cases */
6008 if((ivideo->nbridge = sisfb_get_northbridge(ivideo->chip))) {
6009 switch(ivideo->nbridge->device) {
6010#ifdef CONFIG_FB_SIS_300
6011 case PCI_DEVICE_ID_SI_730:
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006012 ivideo->chip = SIS_730;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006013 strcpy(ivideo->myid, "SiS 730");
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006014 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006015#endif
6016#ifdef CONFIG_FB_SIS_315
6017 case PCI_DEVICE_ID_SI_651:
6018 /* ivideo->chip is ok */
6019 strcpy(ivideo->myid, "SiS 651");
6020 break;
6021 case PCI_DEVICE_ID_SI_740:
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006022 ivideo->chip = SIS_740;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006023 strcpy(ivideo->myid, "SiS 740");
6024 break;
6025 case PCI_DEVICE_ID_SI_661:
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006026 ivideo->chip = SIS_661;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006027 strcpy(ivideo->myid, "SiS 661");
6028 break;
6029 case PCI_DEVICE_ID_SI_741:
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006030 ivideo->chip = SIS_741;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006031 strcpy(ivideo->myid, "SiS 741");
6032 break;
6033 case PCI_DEVICE_ID_SI_760:
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006034 ivideo->chip = SIS_760;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006035 strcpy(ivideo->myid, "SiS 760");
6036 break;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006037 case PCI_DEVICE_ID_SI_761:
6038 ivideo->chip = SIS_761;
6039 strcpy(ivideo->myid, "SiS 761");
6040 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006041#endif
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006042 default:
6043 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006044 }
6045 }
6046
6047#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
6048 strcpy(sis_fb_info->modename, ivideo->myid);
6049#endif
6050
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006051 ivideo->SiS_Pr.ChipType = ivideo->chip;
6052
6053 ivideo->SiS_Pr.ivideo = (void *)ivideo;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006054
6055#ifdef CONFIG_FB_SIS_315
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006056 if((ivideo->SiS_Pr.ChipType == SIS_315PRO) ||
6057 (ivideo->SiS_Pr.ChipType == SIS_315)) {
6058 ivideo->SiS_Pr.ChipType = SIS_315H;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006059 }
6060#endif
6061
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006062 if(!ivideo->sisvga_enabled) {
6063 if(pci_enable_device(pdev)) {
6064 if(ivideo->nbridge) SIS_PCI_PUT_DEVICE(ivideo->nbridge);
6065 pci_set_drvdata(pdev, NULL);
6066 kfree(sis_fb_info);
6067 return -EIO;
6068 }
6069 }
6070
Linus Torvalds1da177e2005-04-16 15:20:36 -07006071 ivideo->video_base = pci_resource_start(pdev, 0);
6072 ivideo->mmio_base = pci_resource_start(pdev, 1);
6073 ivideo->mmio_size = pci_resource_len(pdev, 1);
6074 ivideo->SiS_Pr.RelIO = pci_resource_start(pdev, 2) + 0x30;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006075 ivideo->SiS_Pr.IOAddress = ivideo->vga_base = ivideo->SiS_Pr.RelIO;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006076
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006077 SiSRegInit(&ivideo->SiS_Pr, ivideo->SiS_Pr.IOAddress);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006078
6079#ifdef CONFIG_FB_SIS_300
6080 /* Find PCI systems for Chrontel/GPIO communication setup */
6081 if(ivideo->chip == SIS_630) {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006082 i = 0;
6083 do {
6084 if(mychswtable[i].subsysVendor == ivideo->subsysvendor &&
6085 mychswtable[i].subsysCard == ivideo->subsysdevice) {
6086 ivideo->SiS_Pr.SiS_ChSW = TRUE;
6087 printk(KERN_DEBUG "sisfb: Identified [%s %s] "
6088 "requiring Chrontel/GPIO setup\n",
6089 mychswtable[i].vendorName,
6090 mychswtable[i].cardName);
6091 ivideo->lpcdev = SIS_PCI_GET_DEVICE(PCI_VENDOR_ID_SI, 0x0008, NULL);
6092 break;
6093 }
6094 i++;
6095 } while(mychswtable[i].subsysVendor != 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006096 }
6097#endif
6098
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006099#ifdef CONFIG_FB_SIS_315
6100 if((ivideo->chip == SIS_760) && (ivideo->nbridge)) {
6101 ivideo->lpcdev = SIS_PCI_GET_SLOT(ivideo->nbridge->bus, (2 << 3));
6102 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07006103#endif
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006104
6105 outSISIDXREG(SISSR, 0x05, 0x86);
6106
6107 if( (!ivideo->sisvga_enabled)
6108#if !defined(__i386__) && !defined(__x86_64__)
6109 || (sisfb_resetcard)
6110#endif
6111 ) {
6112 for(i = 0x30; i <= 0x3f; i++) {
6113 outSISIDXREG(SISCR, i, 0x00);
6114 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07006115 }
6116
6117 /* Find out about current video mode */
6118 ivideo->modeprechange = 0x03;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006119 inSISIDXREG(SISCR, 0x34, reg);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006120 if(reg & 0x7f) {
6121 ivideo->modeprechange = reg & 0x7f;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006122 } else if(ivideo->sisvga_enabled) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07006123#if defined(__i386__) || defined(__x86_64__)
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006124 unsigned char SIS_IOTYPE2 *tt = ioremap(0x400, 0x100);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006125 if(tt) {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006126 ivideo->modeprechange = readb(tt + 0x49);
6127 iounmap(tt);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006128 }
6129#endif
6130 }
6131
6132#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
6133#ifdef MODULE
6134 if((reg & 0x80) && (reg != 0xff)) {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006135 if((sisbios_mode[ivideo->sisfb_mode_idx].mode_no[ivideo->mni])
6136 != 0xFF) {
6137 printk(KERN_INFO "sisfb: Cannot initialize display mode, "
6138 "X server is active\n");
6139 ret = -EBUSY;
6140 goto error_4;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006141 }
6142 }
6143#endif
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006144#endif
6145
6146 /* Search and copy ROM image */
6147 ivideo->bios_abase = NULL;
6148 ivideo->SiS_Pr.VirtualRomBase = NULL;
6149 ivideo->SiS_Pr.UseROM = FALSE;
6150 ivideo->haveXGIROM = ivideo->SiS_Pr.SiS_XGIROM = FALSE;
6151 if(ivideo->sisfb_userom) {
6152 ivideo->SiS_Pr.VirtualRomBase = sisfb_find_rom(pdev);
6153 ivideo->bios_abase = ivideo->SiS_Pr.VirtualRomBase;
6154 ivideo->SiS_Pr.UseROM = (ivideo->SiS_Pr.VirtualRomBase) ? TRUE : FALSE;
6155 printk(KERN_INFO "sisfb: Video ROM %sfound\n",
6156 ivideo->SiS_Pr.UseROM ? "" : "not ");
6157 if((ivideo->SiS_Pr.UseROM) && (ivideo->chip >= XGI_20)) {
6158 ivideo->SiS_Pr.UseROM = FALSE;
6159 ivideo->haveXGIROM = ivideo->SiS_Pr.SiS_XGIROM = TRUE;
6160 if( (ivideo->revision_id == 2) &&
6161 (!(ivideo->bios_abase[0x1d1] & 0x01)) ) {
6162 ivideo->SiS_Pr.DDCPortMixup = TRUE;
6163 }
6164 }
6165 } else {
6166 printk(KERN_INFO "sisfb: Video ROM usage disabled\n");
6167 }
6168
6169 /* Find systems for special custom timing */
6170 if(ivideo->SiS_Pr.SiS_CustomT == CUT_NONE) {
6171 sisfb_detect_custom_timing(ivideo);
6172 }
6173
6174 /* POST card in case this has not been done by the BIOS */
6175 if( (!ivideo->sisvga_enabled)
6176#if !defined(__i386__) && !defined(__x86_64__)
6177 || (sisfb_resetcard)
6178#endif
6179 ) {
6180#ifdef CONFIG_FB_SIS_300
6181 if(ivideo->sisvga_engine == SIS_300_VGA) {
6182 if(ivideo->chip == SIS_300) {
6183 sisfb_post_sis300(pdev);
6184 ivideo->sisfb_can_post = 1;
6185 }
6186 }
6187#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -07006188
6189#ifdef CONFIG_FB_SIS_315
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006190 if(ivideo->sisvga_engine == SIS_315_VGA) {
6191 int result = 1;
6192 /* if((ivideo->chip == SIS_315H) ||
Linus Torvalds1da177e2005-04-16 15:20:36 -07006193 (ivideo->chip == SIS_315) ||
6194 (ivideo->chip == SIS_315PRO) ||
6195 (ivideo->chip == SIS_330)) {
6196 sisfb_post_sis315330(pdev);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006197 } else */ if(ivideo->chip == XGI_20) {
6198 result = sisfb_post_xgi(pdev);
6199 ivideo->sisfb_can_post = 1;
6200 } else if((ivideo->chip == XGI_40) && ivideo->haveXGIROM) {
6201 result = sisfb_post_xgi(pdev);
6202 ivideo->sisfb_can_post = 1;
6203 } else {
6204 printk(KERN_INFO "sisfb: Card is not "
6205 "POSTed and sisfb can't do this either.\n");
6206 }
6207 if(!result) {
6208 printk(KERN_ERR "sisfb: Failed to POST card\n");
6209 ret = -ENODEV;
6210 goto error_3;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006211 }
6212 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07006213#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -07006214 }
6215
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006216 ivideo->sisfb_card_posted = 1;
6217
6218 /* Find out about RAM size */
6219 if(sisfb_get_dram_size(ivideo)) {
6220 printk(KERN_INFO "sisfb: Fatal error: Unable to determine VRAM size.\n");
6221 ret = -ENODEV;
6222 goto error_3;
6223 }
6224
6225
6226 /* Enable PCI addressing and MMIO */
Linus Torvalds1da177e2005-04-16 15:20:36 -07006227 if((ivideo->sisfb_mode_idx < 0) ||
6228 ((sisbios_mode[ivideo->sisfb_mode_idx].mode_no[ivideo->mni]) != 0xFF)) {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006229 /* Enable PCI_LINEAR_ADDRESSING and MMIO_ENABLE */
6230 orSISIDXREG(SISSR, IND_SIS_PCI_ADDRESS_SET, (SIS_PCI_ADDR_ENABLE | SIS_MEM_MAP_IO_ENABLE));
6231 /* Enable 2D accelerator engine */
6232 orSISIDXREG(SISSR, IND_SIS_MODULE_ENABLE, SIS_ENABLE_2D);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006233 }
6234
6235 if(sisfb_pdc != 0xff) {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006236 if(ivideo->sisvga_engine == SIS_300_VGA)
6237 sisfb_pdc &= 0x3c;
6238 else
6239 sisfb_pdc &= 0x1f;
6240 ivideo->SiS_Pr.PDC = sisfb_pdc;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006241 }
6242#ifdef CONFIG_FB_SIS_315
6243 if(ivideo->sisvga_engine == SIS_315_VGA) {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006244 if(sisfb_pdca != 0xff)
6245 ivideo->SiS_Pr.PDCA = sisfb_pdca & 0x1f;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006246 }
6247#endif
6248
6249 if(!request_mem_region(ivideo->video_base, ivideo->video_size, "sisfb FB")) {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006250 printk(KERN_ERR "sisfb: Fatal error: Unable to reserve %dMB framebuffer memory\n",
6251 (int)(ivideo->video_size >> 20));
Linus Torvalds1da177e2005-04-16 15:20:36 -07006252 printk(KERN_ERR "sisfb: Is there another framebuffer driver active?\n");
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006253 ret = -ENODEV;
6254 goto error_3;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006255 }
6256
6257 if(!request_mem_region(ivideo->mmio_base, ivideo->mmio_size, "sisfb MMIO")) {
6258 printk(KERN_ERR "sisfb: Fatal error: Unable to reserve MMIO region\n");
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006259 ret = -ENODEV;
6260 goto error_2;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006261 }
6262
6263 ivideo->video_vbase = ioremap(ivideo->video_base, ivideo->video_size);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006264 ivideo->SiS_Pr.VideoMemoryAddress = ivideo->video_vbase;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006265 if(!ivideo->video_vbase) {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006266 printk(KERN_ERR "sisfb: Fatal error: Unable to map framebuffer memory\n");
6267 ret = -ENODEV;
6268 goto error_1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006269 }
6270
6271 ivideo->mmio_vbase = ioremap(ivideo->mmio_base, ivideo->mmio_size);
6272 if(!ivideo->mmio_vbase) {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006273 printk(KERN_ERR "sisfb: Fatal error: Unable to map MMIO region\n");
6274 ret = -ENODEV;
6275error_0: iounmap(ivideo->video_vbase);
6276error_1: release_mem_region(ivideo->video_base, ivideo->video_size);
6277error_2: release_mem_region(ivideo->mmio_base, ivideo->mmio_size);
6278error_3: vfree(ivideo->bios_abase);
6279#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
6280error_4:
6281#endif
6282 if(ivideo->lpcdev)
6283 SIS_PCI_PUT_DEVICE(ivideo->lpcdev);
6284 if(ivideo->nbridge)
6285 SIS_PCI_PUT_DEVICE(ivideo->nbridge);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006286 pci_set_drvdata(pdev, NULL);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006287 if(!ivideo->sisvga_enabled)
6288 pci_disable_device(pdev);
6289 kfree(sis_fb_info);
6290 return ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006291 }
6292
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006293 printk(KERN_INFO "sisfb: Video RAM at 0x%lx, mapped to 0x%lx, size %ldk\n",
6294 ivideo->video_base, (unsigned long)ivideo->video_vbase, ivideo->video_size / 1024);
6295
6296 if(ivideo->video_offset) {
6297 printk(KERN_INFO "sisfb: Viewport offset %ldk\n",
6298 ivideo->video_offset / 1024);
6299 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07006300
6301 printk(KERN_INFO "sisfb: MMIO at 0x%lx, mapped to 0x%lx, size %ldk\n",
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006302 ivideo->mmio_base, (unsigned long)ivideo->mmio_vbase, ivideo->mmio_size / 1024);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006303
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006304
6305 /* Determine the size of the command queue */
6306 if(ivideo->sisvga_engine == SIS_300_VGA) {
6307 ivideo->cmdQueueSize = TURBO_QUEUE_AREA_SIZE;
6308 } else {
6309 if(ivideo->chip == XGI_20) {
6310 ivideo->cmdQueueSize = COMMAND_QUEUE_AREA_SIZE_Z7;
6311 } else {
6312 ivideo->cmdQueueSize = COMMAND_QUEUE_AREA_SIZE;
6313 }
6314 }
6315
6316 /* Engines are no longer initialized here; this is
6317 * now done after the first mode-switch (if the
6318 * submitted var has its acceleration flags set).
6319 */
6320
6321 /* Calculate the base of the (unused) hw cursor */
6322 ivideo->hwcursor_vbase = ivideo->video_vbase
6323 + ivideo->video_size
6324 - ivideo->cmdQueueSize
6325 - ivideo->hwcursor_size;
6326 ivideo->caps |= HW_CURSOR_CAP;
6327
6328 /* Initialize offscreen memory manager */
Linus Torvalds1da177e2005-04-16 15:20:36 -07006329 if((ivideo->havenoheap = sisfb_heap_init(ivideo))) {
6330 printk(KERN_WARNING "sisfb: Failed to initialize offscreen memory heap\n");
6331 }
6332
6333 /* Used for clearing the screen only, therefore respect our mem limit */
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006334 ivideo->SiS_Pr.VideoMemoryAddress += ivideo->video_offset;
6335 ivideo->SiS_Pr.VideoMemorySize = ivideo->sisfb_mem;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006336
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006337 ivideo->mtrr = -1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006338
6339 ivideo->vbflags = 0;
6340 ivideo->lcddefmodeidx = DEFAULT_LCDMODE;
6341 ivideo->tvdefmodeidx = DEFAULT_TVMODE;
6342 ivideo->defmodeidx = DEFAULT_MODE;
6343
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006344 ivideo->newrom = 0;
6345 if(ivideo->chip < XGI_20) {
6346 if(ivideo->bios_abase) {
6347 ivideo->newrom = SiSDetermineROMLayout661(&ivideo->SiS_Pr);
6348 }
6349 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07006350
6351 if((ivideo->sisfb_mode_idx < 0) ||
6352 ((sisbios_mode[ivideo->sisfb_mode_idx].mode_no[ivideo->mni]) != 0xFF)) {
6353
6354 sisfb_sense_crt1(ivideo);
6355
6356 sisfb_get_VB_type(ivideo);
6357
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006358 if(ivideo->vbflags2 & VB2_VIDEOBRIDGE) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07006359 sisfb_detect_VB_connect(ivideo);
6360 }
6361
6362 ivideo->currentvbflags = ivideo->vbflags & (VB_VIDEOBRIDGE | TV_STANDARD);
6363
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006364 /* Decide on which CRT2 device to use */
6365 if(ivideo->vbflags2 & VB2_VIDEOBRIDGE) {
6366 if(ivideo->sisfb_crt2type != -1) {
6367 if((ivideo->sisfb_crt2type == CRT2_LCD) &&
6368 (ivideo->vbflags & CRT2_LCD)) {
6369 ivideo->currentvbflags |= CRT2_LCD;
6370 } else if(ivideo->sisfb_crt2type != CRT2_LCD) {
6371 ivideo->currentvbflags |= ivideo->sisfb_crt2type;
6372 }
6373 } else {
6374 /* Chrontel 700x TV detection often unreliable, therefore
6375 * use a different default order on such machines
6376 */
6377 if((ivideo->sisvga_engine == SIS_300_VGA) &&
6378 (ivideo->vbflags2 & VB2_CHRONTEL)) {
6379 if(ivideo->vbflags & CRT2_LCD)
6380 ivideo->currentvbflags |= CRT2_LCD;
6381 else if(ivideo->vbflags & CRT2_TV)
6382 ivideo->currentvbflags |= CRT2_TV;
6383 else if(ivideo->vbflags & CRT2_VGA)
6384 ivideo->currentvbflags |= CRT2_VGA;
6385 } else {
6386 if(ivideo->vbflags & CRT2_TV)
6387 ivideo->currentvbflags |= CRT2_TV;
6388 else if(ivideo->vbflags & CRT2_LCD)
6389 ivideo->currentvbflags |= CRT2_LCD;
6390 else if(ivideo->vbflags & CRT2_VGA)
6391 ivideo->currentvbflags |= CRT2_VGA;
6392 }
6393 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07006394 }
6395
6396 if(ivideo->vbflags & CRT2_LCD) {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006397 sisfb_detect_lcd_type(ivideo);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006398 }
6399
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006400 sisfb_save_pdc_emi(ivideo);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006401
6402 if(!ivideo->sisfb_crt1off) {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006403 sisfb_handle_ddc(ivideo, &ivideo->sisfb_thismonitor, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006404 } else {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006405 if((ivideo->vbflags2 & VB2_SISTMDSBRIDGE) &&
6406 (ivideo->vbflags & (CRT2_VGA | CRT2_LCD))) {
6407 sisfb_handle_ddc(ivideo, &ivideo->sisfb_thismonitor, 1);
6408 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07006409 }
6410
6411 if(ivideo->sisfb_mode_idx >= 0) {
6412 int bu = ivideo->sisfb_mode_idx;
6413 ivideo->sisfb_mode_idx = sisfb_validate_mode(ivideo,
6414 ivideo->sisfb_mode_idx, ivideo->currentvbflags);
6415 if(bu != ivideo->sisfb_mode_idx) {
6416 printk(KERN_ERR "Mode %dx%dx%d failed validation\n",
6417 sisbios_mode[bu].xres,
6418 sisbios_mode[bu].yres,
6419 sisbios_mode[bu].bpp);
6420 }
6421 }
6422
6423 if(ivideo->sisfb_mode_idx < 0) {
6424 switch(ivideo->currentvbflags & VB_DISPTYPE_DISP2) {
6425 case CRT2_LCD:
6426 ivideo->sisfb_mode_idx = ivideo->lcddefmodeidx;
6427 break;
6428 case CRT2_TV:
6429 ivideo->sisfb_mode_idx = ivideo->tvdefmodeidx;
6430 break;
6431 default:
6432 ivideo->sisfb_mode_idx = ivideo->defmodeidx;
6433 break;
6434 }
6435 }
6436
6437 ivideo->mode_no = sisbios_mode[ivideo->sisfb_mode_idx].mode_no[ivideo->mni];
6438
6439 if(ivideo->refresh_rate != 0) {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006440 sisfb_search_refresh_rate(ivideo, ivideo->refresh_rate,
6441 ivideo->sisfb_mode_idx);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006442 }
6443
6444 if(ivideo->rate_idx == 0) {
6445 ivideo->rate_idx = sisbios_mode[ivideo->sisfb_mode_idx].rate_idx;
6446 ivideo->refresh_rate = 60;
6447 }
6448
6449 if(ivideo->sisfb_thismonitor.datavalid) {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006450 if(!sisfb_verify_rate(ivideo, &ivideo->sisfb_thismonitor,
6451 ivideo->sisfb_mode_idx,
6452 ivideo->rate_idx,
6453 ivideo->refresh_rate)) {
6454 printk(KERN_INFO "sisfb: WARNING: Refresh rate "
6455 "exceeds monitor specs!\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07006456 }
6457 }
6458
6459 ivideo->video_bpp = sisbios_mode[ivideo->sisfb_mode_idx].bpp;
6460 ivideo->video_width = sisbios_mode[ivideo->sisfb_mode_idx].xres;
6461 ivideo->video_height = sisbios_mode[ivideo->sisfb_mode_idx].yres;
6462
6463 sisfb_set_vparms(ivideo);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006464
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006465#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
6466
6467 /* ---------------- For 2.4: Now switch the mode ------------------ */
6468
6469 printk(KERN_INFO "sisfb: Setting mode %dx%dx%d (%dHz)\n",
6470 ivideo->video_width, ivideo->video_height, ivideo->video_bpp,
Linus Torvalds1da177e2005-04-16 15:20:36 -07006471 ivideo->refresh_rate);
6472
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006473 /* Determine whether or not acceleration is to be
6474 * used. Need to know before pre/post_set_mode()
6475 */
6476 ivideo->accel = 0;
6477 ivideo->default_var.accel_flags &= ~FB_ACCELF_TEXT;
6478 if(ivideo->sisfb_accel) {
6479 ivideo->accel = -1;
6480 ivideo->default_var.accel_flags |= FB_ACCELF_TEXT;
6481 }
6482
6483 /* Now switch the mode */
Linus Torvalds1da177e2005-04-16 15:20:36 -07006484 sisfb_pre_setmode(ivideo);
6485
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006486 if(SiSSetMode(&ivideo->SiS_Pr, ivideo->mode_no) == 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07006487 printk(KERN_ERR "sisfb: Fatal error: Setting mode[0x%x] failed\n",
6488 ivideo->mode_no);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006489 ret = -EINVAL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006490 iounmap(ivideo->mmio_vbase);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006491 goto error_0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006492 }
6493
6494 outSISIDXREG(SISSR, IND_SIS_PASSWORD, SIS_PASSWORD);
6495
6496 sisfb_post_setmode(ivideo);
6497
6498 /* Maximize regardless of sisfb_max at startup */
6499 ivideo->default_var.yres_virtual = 32767;
6500
6501 /* Force reset of x virtual in crtc_to_var */
6502 ivideo->default_var.xres_virtual = 0;
6503
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006504 /* Copy mode timing to var */
Linus Torvalds1da177e2005-04-16 15:20:36 -07006505 sisfb_crtc_to_var(ivideo, &ivideo->default_var);
6506
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006507 /* Find out about screen pitch */
Linus Torvalds1da177e2005-04-16 15:20:36 -07006508 sisfb_calc_pitch(ivideo, &ivideo->default_var);
6509 sisfb_set_pitch(ivideo);
6510
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006511 /* Init the accelerator (does nothing currently) */
Linus Torvalds1da177e2005-04-16 15:20:36 -07006512 sisfb_initaccel(ivideo);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006513
6514 /* Init some fbinfo entries */
Linus Torvalds1da177e2005-04-16 15:20:36 -07006515 sis_fb_info->node = -1;
6516 sis_fb_info->flags = FBINFO_FLAG_DEFAULT;
6517 sis_fb_info->fbops = &sisfb_ops;
6518 sis_fb_info->disp = &ivideo->sis_disp;
6519 sis_fb_info->blank = &sisfb_blank;
6520 sis_fb_info->switch_con = &sisfb_switch;
6521 sis_fb_info->updatevar = &sisfb_update_var;
6522 sis_fb_info->changevar = NULL;
6523 strcpy(sis_fb_info->fontname, sisfb_fontname);
6524
6525 sisfb_set_disp(-1, &ivideo->default_var, sis_fb_info);
6526
6527#else /* --------- For 2.6: Setup a somewhat sane default var ------------ */
6528
6529 printk(KERN_INFO "sisfb: Default mode is %dx%dx%d (%dHz)\n",
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006530 ivideo->video_width, ivideo->video_height, ivideo->video_bpp,
Linus Torvalds1da177e2005-04-16 15:20:36 -07006531 ivideo->refresh_rate);
6532
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006533 /* Set up the default var according to chosen default display mode */
Linus Torvalds1da177e2005-04-16 15:20:36 -07006534 ivideo->default_var.xres = ivideo->default_var.xres_virtual = ivideo->video_width;
6535 ivideo->default_var.yres = ivideo->default_var.yres_virtual = ivideo->video_height;
6536 ivideo->default_var.bits_per_pixel = ivideo->video_bpp;
6537
6538 sisfb_bpp_to_var(ivideo, &ivideo->default_var);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006539
Linus Torvalds1da177e2005-04-16 15:20:36 -07006540 ivideo->default_var.pixclock = (u32) (1000000000 /
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006541 sisfb_mode_rate_to_dclock(&ivideo->SiS_Pr, ivideo->mode_no, ivideo->rate_idx));
6542
6543 if(sisfb_mode_rate_to_ddata(&ivideo->SiS_Pr, ivideo->mode_no,
6544 ivideo->rate_idx, &ivideo->default_var)) {
6545 if((ivideo->default_var.vmode & FB_VMODE_MASK) == FB_VMODE_DOUBLE) {
6546 ivideo->default_var.pixclock <<= 1;
6547 }
6548 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07006549
6550 if(ivideo->sisfb_ypan) {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006551 /* Maximize regardless of sisfb_max at startup */
6552 ivideo->default_var.yres_virtual =
6553 sisfb_calc_maxyres(ivideo, &ivideo->default_var);
6554 if(ivideo->default_var.yres_virtual < ivideo->default_var.yres) {
6555 ivideo->default_var.yres_virtual = ivideo->default_var.yres;
6556 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07006557 }
6558
6559 sisfb_calc_pitch(ivideo, &ivideo->default_var);
6560
6561 ivideo->accel = 0;
6562 if(ivideo->sisfb_accel) {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006563 ivideo->accel = -1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006564#ifdef STUPID_ACCELF_TEXT_SHIT
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006565 ivideo->default_var.accel_flags |= FB_ACCELF_TEXT;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006566#endif
6567 }
6568 sisfb_initaccel(ivideo);
6569
6570#if defined(FBINFO_HWACCEL_DISABLED) && defined(FBINFO_HWACCEL_XPAN)
6571 sis_fb_info->flags = FBINFO_DEFAULT |
6572 FBINFO_HWACCEL_YPAN |
6573 FBINFO_HWACCEL_XPAN |
6574 FBINFO_HWACCEL_COPYAREA |
6575 FBINFO_HWACCEL_FILLRECT |
6576 ((ivideo->accel) ? 0 : FBINFO_HWACCEL_DISABLED);
6577#else
6578 sis_fb_info->flags = FBINFO_FLAG_DEFAULT;
6579#endif
6580 sis_fb_info->var = ivideo->default_var;
6581 sis_fb_info->fix = ivideo->sisfb_fix;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006582 sis_fb_info->screen_base = ivideo->video_vbase + ivideo->video_offset;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006583 sis_fb_info->fbops = &sisfb_ops;
6584
6585 sisfb_get_fix(&sis_fb_info->fix, -1, sis_fb_info);
6586 sis_fb_info->pseudo_palette = ivideo->pseudo_palette;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006587
Linus Torvalds1da177e2005-04-16 15:20:36 -07006588 fb_alloc_cmap(&sis_fb_info->cmap, 256 , 0);
6589#endif /* 2.6 */
6590
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006591 printk(KERN_DEBUG "sisfb: Initial vbflags 0x%x\n", (int)ivideo->vbflags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006592
6593#ifdef CONFIG_MTRR
6594 ivideo->mtrr = mtrr_add(ivideo->video_base, ivideo->video_size,
6595 MTRR_TYPE_WRCOMB, 1);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006596 if(ivideo->mtrr < 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07006597 printk(KERN_DEBUG "sisfb: Failed to add MTRRs\n");
6598 }
6599#endif
6600
6601#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
6602 vc_resize_con(1, 1, 0);
6603#endif
6604
6605 if(register_framebuffer(sis_fb_info) < 0) {
6606 printk(KERN_ERR "sisfb: Fatal error: Failed to register framebuffer\n");
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006607 ret = -EINVAL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006608 iounmap(ivideo->mmio_vbase);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006609 goto error_0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006610 }
6611
6612 ivideo->registered = 1;
6613
6614 /* Enlist us */
6615 ivideo->next = card_list;
6616 card_list = ivideo;
6617
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006618#ifdef SIS_OLD_CONFIG_COMPAT
6619 {
6620 int ret;
6621 /* Our ioctls are all "32/64bit compatible" */
6622 ret = register_ioctl32_conversion(FBIO_ALLOC, NULL);
6623 ret |= register_ioctl32_conversion(FBIO_FREE, NULL);
6624 ret |= register_ioctl32_conversion(FBIOGET_VBLANK, NULL);
6625 ret |= register_ioctl32_conversion(SISFB_GET_INFO_SIZE, NULL);
6626 ret |= register_ioctl32_conversion(SISFB_GET_INFO, NULL);
6627 ret |= register_ioctl32_conversion(SISFB_GET_TVPOSOFFSET, NULL);
6628 ret |= register_ioctl32_conversion(SISFB_SET_TVPOSOFFSET, NULL);
6629 ret |= register_ioctl32_conversion(SISFB_SET_LOCK, NULL);
6630 ret |= register_ioctl32_conversion(SISFB_GET_VBRSTATUS, NULL);
6631 ret |= register_ioctl32_conversion(SISFB_GET_AUTOMAXIMIZE, NULL);
6632 ret |= register_ioctl32_conversion(SISFB_SET_AUTOMAXIMIZE, NULL);
6633 ret |= register_ioctl32_conversion(SISFB_COMMAND, NULL);
6634 if(ret)
6635 printk(KERN_ERR
6636 "sisfb: Error registering ioctl32 translations\n");
6637 else
6638 ivideo->ioctl32registered = 1;
6639 }
6640#endif
6641
Linus Torvalds1da177e2005-04-16 15:20:36 -07006642 printk(KERN_INFO "sisfb: 2D acceleration is %s, y-panning %s\n",
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006643 ivideo->sisfb_accel ? "enabled" : "disabled",
6644 ivideo->sisfb_ypan ?
6645 (ivideo->sisfb_max ? "enabled (auto-max)" :
6646 "enabled (no auto-max)") :
6647 "disabled");
Linus Torvalds1da177e2005-04-16 15:20:36 -07006648
6649
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006650 printk(KERN_INFO "fb%d: %s frame buffer device version %d.%d.%d\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07006651#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006652 GET_FB_IDX(sis_fb_info->node),
Linus Torvalds1da177e2005-04-16 15:20:36 -07006653#else
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006654 sis_fb_info->node,
Linus Torvalds1da177e2005-04-16 15:20:36 -07006655#endif
6656 ivideo->myid, VER_MAJOR, VER_MINOR, VER_LEVEL);
6657
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006658 printk(KERN_INFO "sisfb: Copyright (C) 2001-2005 Thomas Winischhofer\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07006659
6660 } /* if mode = "none" */
6661
6662 return 0;
6663}
6664
6665/*****************************************************/
6666/* PCI DEVICE HANDLING */
6667/*****************************************************/
6668
6669static void __devexit sisfb_remove(struct pci_dev *pdev)
6670{
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006671 struct sis_video_info *ivideo = pci_get_drvdata(pdev);
6672 struct fb_info *sis_fb_info = ivideo->memyselfandi;
6673 int registered = ivideo->registered;
6674 int modechanged = ivideo->modechanged;
6675
6676#ifdef SIS_OLD_CONFIG_COMPAT
6677 if(ivideo->ioctl32registered) {
6678 int ret;
6679 ret = unregister_ioctl32_conversion(FBIO_ALLOC);
6680 ret |= unregister_ioctl32_conversion(FBIO_FREE);
6681 ret |= unregister_ioctl32_conversion(FBIOGET_VBLANK);
6682 ret |= unregister_ioctl32_conversion(SISFB_GET_INFO_SIZE);
6683 ret |= unregister_ioctl32_conversion(SISFB_GET_INFO);
6684 ret |= unregister_ioctl32_conversion(SISFB_GET_TVPOSOFFSET);
6685 ret |= unregister_ioctl32_conversion(SISFB_SET_TVPOSOFFSET);
6686 ret |= unregister_ioctl32_conversion(SISFB_SET_LOCK);
6687 ret |= unregister_ioctl32_conversion(SISFB_GET_VBRSTATUS);
6688 ret |= unregister_ioctl32_conversion(SISFB_GET_AUTOMAXIMIZE);
6689 ret |= unregister_ioctl32_conversion(SISFB_SET_AUTOMAXIMIZE);
6690 ret |= unregister_ioctl32_conversion(SISFB_COMMAND);
6691 if(ret)
6692 printk(KERN_ERR
6693 "sisfb: Error unregistering ioctl32 translations\n");
6694 }
6695#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -07006696
6697 /* Unmap */
Linus Torvalds1da177e2005-04-16 15:20:36 -07006698 iounmap(ivideo->mmio_vbase);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006699 iounmap(ivideo->video_vbase);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006700
6701 /* Release mem regions */
6702 release_mem_region(ivideo->video_base, ivideo->video_size);
6703 release_mem_region(ivideo->mmio_base, ivideo->mmio_size);
6704
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006705 vfree(ivideo->bios_abase);
6706
6707 if(ivideo->lpcdev)
6708 SIS_PCI_PUT_DEVICE(ivideo->lpcdev);
6709
6710 if(ivideo->nbridge)
6711 SIS_PCI_PUT_DEVICE(ivideo->nbridge);
6712
Linus Torvalds1da177e2005-04-16 15:20:36 -07006713#ifdef CONFIG_MTRR
6714 /* Release MTRR region */
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006715 if(ivideo->mtrr >= 0)
Linus Torvalds1da177e2005-04-16 15:20:36 -07006716 mtrr_del(ivideo->mtrr, ivideo->video_base, ivideo->video_size);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006717#endif
6718
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006719 pci_set_drvdata(pdev, NULL);
6720
6721 /* If device was disabled when starting, disable
6722 * it when quitting.
6723 */
6724 if(!ivideo->sisvga_enabled)
6725 pci_disable_device(pdev);
6726
Linus Torvalds1da177e2005-04-16 15:20:36 -07006727 /* Unregister the framebuffer */
6728 if(ivideo->registered) {
6729 unregister_framebuffer(sis_fb_info);
6730#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,3))
6731 framebuffer_release(sis_fb_info);
6732#else
6733 kfree(sis_fb_info);
6734#endif
6735 }
6736
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006737 /* OK, our ivideo is gone for good from here. */
Linus Torvalds1da177e2005-04-16 15:20:36 -07006738
6739 /* TODO: Restore the initial mode
6740 * This sounds easy but is as good as impossible
6741 * on many machines with SiS chip and video bridge
6742 * since text modes are always set up differently
6743 * from machine to machine. Depends on the type
6744 * of integration between chipset and bridge.
6745 */
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006746 if(registered && modechanged)
6747 printk(KERN_INFO
6748 "sisfb: Restoring of text mode not supported yet\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07006749};
6750
6751static struct pci_driver sisfb_driver = {
6752 .name = "sisfb",
6753 .id_table = sisfb_pci_table,
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006754 .probe = sisfb_probe,
Linus Torvalds1da177e2005-04-16 15:20:36 -07006755 .remove = __devexit_p(sisfb_remove)
6756};
6757
6758SISINITSTATIC int __init sisfb_init(void)
6759{
6760#if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,8)
6761#ifndef MODULE
6762 char *options = NULL;
6763
6764 if(fb_get_options("sisfb", &options))
6765 return -ENODEV;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006766
Linus Torvalds1da177e2005-04-16 15:20:36 -07006767 sisfb_setup(options);
6768#endif
6769#endif
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006770 return pci_register_driver(&sisfb_driver);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006771}
6772
6773#if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,8)
6774#ifndef MODULE
6775module_init(sisfb_init);
6776#endif
6777#endif
6778
6779/*****************************************************/
6780/* MODULE */
6781/*****************************************************/
6782
6783#ifdef MODULE
6784
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006785static char *mode = NULL;
6786static int vesa = -1;
6787static unsigned int rate = 0;
6788static unsigned int crt1off = 1;
6789static unsigned int mem = 0;
6790static char *forcecrt2type = NULL;
6791static int forcecrt1 = -1;
6792static int pdc = -1;
6793static int pdc1 = -1;
6794static int noaccel = -1;
6795static int noypan = -1;
6796static int nomax = -1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006797#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006798static int inverse = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006799#endif
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006800static int userom = -1;
6801static int useoem = -1;
6802static char *tvstandard = NULL;
6803static int nocrt2rate = 0;
6804static int scalelcd = -1;
6805static char *specialtiming = NULL;
6806static int lvdshl = -1;
6807static int tvxposoffset = 0, tvyposoffset = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006808#if !defined(__i386__) && !defined(__x86_64__)
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006809static int resetcard = 0;
6810static int videoram = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006811#endif
6812
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006813static int __init sisfb_init_module(void)
6814{
6815 sisfb_setdefaultparms();
6816
6817 if(rate)
6818 sisfb_parm_rate = rate;
6819
6820 if((scalelcd == 0) || (scalelcd == 1))
6821 sisfb_scalelcd = scalelcd ^ 1;
6822
6823 /* Need to check crt2 type first for fstn/dstn */
6824
6825 if(forcecrt2type)
6826 sisfb_search_crt2type(forcecrt2type);
6827
6828 if(tvstandard)
6829 sisfb_search_tvstd(tvstandard);
6830
6831 if(mode)
6832 sisfb_search_mode(mode, FALSE);
6833 else if(vesa != -1)
6834 sisfb_search_vesamode(vesa, FALSE);
6835
6836 sisfb_crt1off = (crt1off == 0) ? 1 : 0;
6837
6838 sisfb_forcecrt1 = forcecrt1;
6839 if(forcecrt1 == 1)
6840 sisfb_crt1off = 0;
6841 else if(forcecrt1 == 0)
6842 sisfb_crt1off = 1;
6843
6844 if(noaccel == 1)
6845 sisfb_accel = 0;
6846 else if(noaccel == 0)
6847 sisfb_accel = 1;
6848
6849 if(noypan == 1)
6850 sisfb_ypan = 0;
6851 else if(noypan == 0)
6852 sisfb_ypan = 1;
6853
6854 if(nomax == 1)
6855 sisfb_max = 0;
6856 else if(nomax == 0)
6857 sisfb_max = 1;
6858
6859#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
6860 if(inverse) sisfb_inverse = 1;
6861#endif
6862
6863 if(mem)
6864 sisfb_parm_mem = mem;
6865
6866 if(userom != -1)
6867 sisfb_userom = userom;
6868
6869 if(useoem != -1)
6870 sisfb_useoem = useoem;
6871
6872 if(pdc != -1)
6873 sisfb_pdc = (pdc & 0x7f);
6874
6875 if(pdc1 != -1)
6876 sisfb_pdca = (pdc1 & 0x1f);
6877
6878 sisfb_nocrt2rate = nocrt2rate;
6879
6880 if(specialtiming)
6881 sisfb_search_specialtiming(specialtiming);
6882
6883 if((lvdshl >= 0) && (lvdshl <= 3))
6884 sisfb_lvdshl = lvdshl;
6885
6886 sisfb_tvxposoffset = tvxposoffset;
6887 sisfb_tvyposoffset = tvyposoffset;
6888
6889#if !defined(__i386__) && !defined(__x86_64__)
6890 sisfb_resetcard = (resetcard) ? 1 : 0;
6891 if(videoram)
6892 sisfb_videoram = videoram;
6893#endif
6894
6895 return sisfb_init();
6896}
6897
6898static void __exit sisfb_remove_module(void)
6899{
6900 pci_unregister_driver(&sisfb_driver);
6901 printk(KERN_DEBUG "sisfb: Module unloaded\n");
6902}
6903
6904module_init(sisfb_init_module);
6905module_exit(sisfb_remove_module);
6906
6907MODULE_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 -07006908MODULE_LICENSE("GPL");
6909MODULE_AUTHOR("Thomas Winischhofer <thomas@winischhofer.net>, Others");
6910
6911#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
6912MODULE_PARM(mem, "i");
6913MODULE_PARM(noaccel, "i");
6914MODULE_PARM(noypan, "i");
6915MODULE_PARM(nomax, "i");
6916MODULE_PARM(userom, "i");
6917MODULE_PARM(useoem, "i");
6918MODULE_PARM(mode, "s");
6919MODULE_PARM(vesa, "i");
6920MODULE_PARM(rate, "i");
6921MODULE_PARM(forcecrt1, "i");
6922MODULE_PARM(forcecrt2type, "s");
6923MODULE_PARM(scalelcd, "i");
6924MODULE_PARM(pdc, "i");
6925MODULE_PARM(pdc1, "i");
6926MODULE_PARM(specialtiming, "s");
6927MODULE_PARM(lvdshl, "i");
6928MODULE_PARM(tvstandard, "s");
6929MODULE_PARM(tvxposoffset, "i");
6930MODULE_PARM(tvyposoffset, "i");
Linus Torvalds1da177e2005-04-16 15:20:36 -07006931MODULE_PARM(nocrt2rate, "i");
6932MODULE_PARM(inverse, "i");
6933#if !defined(__i386__) && !defined(__x86_64__)
6934MODULE_PARM(resetcard, "i");
6935MODULE_PARM(videoram, "i");
6936#endif
6937#endif
6938
6939#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0)
6940module_param(mem, int, 0);
6941module_param(noaccel, int, 0);
6942module_param(noypan, int, 0);
6943module_param(nomax, int, 0);
6944module_param(userom, int, 0);
6945module_param(useoem, int, 0);
6946module_param(mode, charp, 0);
6947module_param(vesa, int, 0);
6948module_param(rate, int, 0);
6949module_param(forcecrt1, int, 0);
6950module_param(forcecrt2type, charp, 0);
6951module_param(scalelcd, int, 0);
6952module_param(pdc, int, 0);
6953module_param(pdc1, int, 0);
6954module_param(specialtiming, charp, 0);
6955module_param(lvdshl, int, 0);
6956module_param(tvstandard, charp, 0);
6957module_param(tvxposoffset, int, 0);
6958module_param(tvyposoffset, int, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006959module_param(nocrt2rate, int, 0);
6960#if !defined(__i386__) && !defined(__x86_64__)
6961module_param(resetcard, int, 0);
6962module_param(videoram, int, 0);
6963#endif
6964#endif
6965
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006966#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
Linus Torvalds1da177e2005-04-16 15:20:36 -07006967MODULE_PARM_DESC(mem,
6968 "\nDetermines the beginning of the video memory heap in KB. This heap is used\n"
6969 "for video RAM management for eg. DRM/DRI. On 300 series, the default depends\n"
6970 "on the amount of video RAM available. If 8MB of video RAM or less is available,\n"
6971 "the heap starts at 4096KB, if between 8 and 16MB are available at 8192KB,\n"
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006972 "otherwise at 12288KB. On 315/330/340 series, the heap size is 32KB by default.\n"
Linus Torvalds1da177e2005-04-16 15:20:36 -07006973 "The value is to be specified without 'KB' and must match the MaxXFBMem setting\n"
6974 "for XFree86 4.x/X.org 6.7 and later.\n");
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006975#else
6976MODULE_PARM_DESC(mem,
6977 "\nDetermines the beginning of the video memory heap in KB. This heap is used\n"
6978 "for video RAM management for eg. DRM/DRI. On 300 series, the default depends\n"
6979 "on the amount of video RAM available. If 8MB of video RAM or less is available,\n"
6980 "the heap starts at 4096KB, if between 8 and 16MB are available at 8192KB,\n"
6981 "otherwise at 12288KB. On 315/330/340 series, the heap size is 32KB by default.\n"
6982 "The value is to be specified without 'KB'.\n");
6983#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -07006984
6985MODULE_PARM_DESC(noaccel,
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006986 "\nIf set to anything other than 0, 2D acceleration will be disabled.\n"
Linus Torvalds1da177e2005-04-16 15:20:36 -07006987 "(default: 0)\n");
6988
6989MODULE_PARM_DESC(noypan,
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006990 "\nIf set to anything other than 0, y-panning will be disabled and scrolling\n"
6991 "will be performed by redrawing the screen. (default: 0)\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07006992
6993MODULE_PARM_DESC(nomax,
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006994 "\nIf y-panning is enabled, sisfb will by default use the entire available video\n"
Linus Torvalds1da177e2005-04-16 15:20:36 -07006995 "memory for the virtual screen in order to optimize scrolling performance. If\n"
6996 "this is set to anything other than 0, sisfb will not do this and thereby \n"
6997 "enable the user to positively specify a virtual Y size of the screen using\n"
6998 "fbset. (default: 0)\n");
6999
7000#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
7001MODULE_PARM_DESC(mode,
Thomas Winischhofer544393f2005-09-09 13:04:45 -07007002 "\nSelects the desired display mode in the format [X]x[Y]x[Depth], eg.\n"
7003 "1024x768x16. Other formats supported include XxY-Depth and\n"
7004 "XxY-Depth@Rate. If the parameter is only one (decimal or hexadecimal)\n"
Linus Torvalds1da177e2005-04-16 15:20:36 -07007005 "number, it will be interpreted as a VESA mode number. (default: none if\n"
7006 "sisfb is a module; this leaves the console untouched and the driver will\n"
7007 "only do the video memory management for eg. DRM/DRI; 800x600x8 if sisfb\n"
7008 "is in the kernel)\n");
7009MODULE_PARM_DESC(vesa,
Thomas Winischhofer544393f2005-09-09 13:04:45 -07007010 "\nSelects the desired display mode by VESA defined mode number, eg. 0x117\n"
7011 "(default: 0x0000 if sisfb is a module; this leaves the console untouched\n"
Linus Torvalds1da177e2005-04-16 15:20:36 -07007012 "and the driver will only do the video memory management for eg. DRM/DRI;\n"
7013 "0x0103 if sisfb is in the kernel)\n");
7014#endif
7015
7016#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0)
7017MODULE_PARM_DESC(mode,
Thomas Winischhofer544393f2005-09-09 13:04:45 -07007018 "\nSelects the desired default display mode in the format XxYxDepth,\n"
7019 "eg. 1024x768x16. Other formats supported include XxY-Depth and\n"
Linus Torvalds1da177e2005-04-16 15:20:36 -07007020 "XxY-Depth@Rate. If the parameter is only one (decimal or hexadecimal)\n"
7021 "number, it will be interpreted as a VESA mode number. (default: 800x600x8)\n");
7022
7023MODULE_PARM_DESC(vesa,
Thomas Winischhofer544393f2005-09-09 13:04:45 -07007024 "\nSelects the desired default display mode by VESA defined mode number, eg.\n"
7025 "0x117 (default: 0x0103)\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07007026#endif
7027
7028MODULE_PARM_DESC(rate,
7029 "\nSelects the desired vertical refresh rate for CRT1 (external VGA) in Hz.\n"
7030 "If the mode is specified in the format XxY-Depth@Rate, this parameter\n"
7031 "will be ignored (default: 60)\n");
7032
7033MODULE_PARM_DESC(forcecrt1,
7034 "\nNormally, the driver autodetects whether or not CRT1 (external VGA) is \n"
7035 "connected. With this option, the detection can be overridden (1=CRT1 ON,\n"
7036 "0=CRT1 OFF) (default: [autodetected])\n");
7037
7038MODULE_PARM_DESC(forcecrt2type,
7039 "\nIf this option is omitted, the driver autodetects CRT2 output devices, such as\n"
7040 "LCD, TV or secondary VGA. With this option, this autodetection can be\n"
7041 "overridden. Possible parameters are LCD, TV, VGA or NONE. NONE disables CRT2.\n"
7042 "On systems with a SiS video bridge, parameters SVIDEO, COMPOSITE or SCART can\n"
7043 "be used instead of TV to override the TV detection. Furthermore, on systems\n"
7044 "with a SiS video bridge, SVIDEO+COMPOSITE, HIVISION, YPBPR480I, YPBPR480P,\n"
7045 "YPBPR720P and YPBPR1080I are understood. However, whether or not these work\n"
7046 "depends on the very hardware in use. (default: [autodetected])\n");
7047
7048MODULE_PARM_DESC(scalelcd,
7049 "\nSetting this to 1 will force the driver to scale the LCD image to the panel's\n"
7050 "native resolution. Setting it to 0 will disable scaling; LVDS panels will\n"
7051 "show black bars around the image, TMDS panels will probably do the scaling\n"
7052 "themselves. Default: 1 on LVDS panels, 0 on TMDS panels\n");
7053
7054MODULE_PARM_DESC(pdc,
Thomas Winischhofer544393f2005-09-09 13:04:45 -07007055 "\nThis is for manually selecting the LCD panel delay compensation. The driver\n"
Linus Torvalds1da177e2005-04-16 15:20:36 -07007056 "should detect this correctly in most cases; however, sometimes this is not\n"
7057 "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 -07007058 "on a 300 series chipset; 6 on other chipsets. If the problem persists, try\n"
7059 "other values (on 300 series: between 4 and 60 in steps of 4; otherwise: any\n"
7060 "value from 0 to 31). (default: autodetected, if LCD is active during start)\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07007061
7062#ifdef CONFIG_FB_SIS_315
7063MODULE_PARM_DESC(pdc1,
Thomas Winischhofer544393f2005-09-09 13:04:45 -07007064 "\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 -07007065 "series only. (default: autodetected if LCD is in LCD-via-CRT1 mode during\n"
7066 "startup) - Note: currently, this has no effect because LCD-via-CRT1 is not\n"
7067 "implemented yet.\n");
7068#endif
7069
7070MODULE_PARM_DESC(specialtiming,
7071 "\nPlease refer to documentation for more information on this option.\n");
7072
7073MODULE_PARM_DESC(lvdshl,
7074 "\nPlease refer to documentation for more information on this option.\n");
7075
7076MODULE_PARM_DESC(tvstandard,
7077 "\nThis allows overriding the BIOS default for the TV standard. Valid choices are\n"
7078 "pal, ntsc, palm and paln. (default: [auto; pal or ntsc only])\n");
7079
7080MODULE_PARM_DESC(tvxposoffset,
7081 "\nRelocate TV output horizontally. Possible parameters: -32 through 32.\n"
7082 "Default: 0\n");
7083
7084MODULE_PARM_DESC(tvyposoffset,
7085 "\nRelocate TV output vertically. Possible parameters: -32 through 32.\n"
7086 "Default: 0\n");
7087
Linus Torvalds1da177e2005-04-16 15:20:36 -07007088MODULE_PARM_DESC(nocrt2rate,
7089 "\nSetting this to 1 will force the driver to use the default refresh rate for\n"
7090 "CRT2 if CRT2 type is VGA. (default: 0, use same rate as CRT1)\n");
7091
7092#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
7093MODULE_PARM_DESC(inverse,
Thomas Winischhofer544393f2005-09-09 13:04:45 -07007094 "\nSetting this to anything but 0 should invert the display colors, but this\n"
Linus Torvalds1da177e2005-04-16 15:20:36 -07007095 "does not seem to work. (default: 0)\n");
7096#endif
7097
7098#if !defined(__i386__) && !defined(__x86_64__)
7099#ifdef CONFIG_FB_SIS_300
7100MODULE_PARM_DESC(resetcard,
7101 "\nSet this to 1 in order to reset (POST) the card on non-x86 machines where\n"
Thomas Winischhofer544393f2005-09-09 13:04:45 -07007102 "the BIOS did not POST the card (only supported for SiS 300/305 and XGI cards\n"
7103 "currently). Default: 0\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07007104
7105MODULE_PARM_DESC(videoram,
7106 "\nSet this to the amount of video RAM (in kilobyte) the card has. Required on\n"
7107 "some non-x86 architectures where the memory auto detection fails. Only\n"
Thomas Winischhofer544393f2005-09-09 13:04:45 -07007108 "relevant if resetcard is set, too. SiS300/305 only. Default: [auto-detect]\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07007109#endif
7110#endif
7111
Linus Torvalds1da177e2005-04-16 15:20:36 -07007112#endif /* /MODULE */
7113
Thomas Winischhofer544393f2005-09-09 13:04:45 -07007114/* _GPL only for new symbols. */
Linus Torvalds1da177e2005-04-16 15:20:36 -07007115EXPORT_SYMBOL(sis_malloc);
7116EXPORT_SYMBOL(sis_free);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07007117EXPORT_SYMBOL_GPL(sis_malloc_new);
7118EXPORT_SYMBOL_GPL(sis_free_new);
7119
Linus Torvalds1da177e2005-04-16 15:20:36 -07007120
7121