blob: dea1a46c67c4fe232e24874fd08f15f46e7702b3 [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
1746static int
1747sisfb_ioctl(struct inode *inode, struct file *file,
1748 unsigned int cmd, unsigned long arg,
1749#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
1750 int con,
1751#endif
1752 struct fb_info *info)
1753{
1754 struct sis_video_info *ivideo = (struct sis_video_info *)info->par;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001755 struct sis_memreq sismemreq;
1756 struct fb_vblank sisvbblank;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001757 u32 gpu32 = 0;
1758#ifndef __user
1759#define __user
1760#endif
1761 u32 __user *argp = (u32 __user *)arg;
1762
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001763 switch(cmd) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001764 case FBIO_ALLOC:
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001765 if(!capable(CAP_SYS_RAWIO))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001766 return -EPERM;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001767
1768 if(copy_from_user(&sismemreq, (void __user *)arg, sizeof(sismemreq)))
1769 return -EFAULT;
1770
Linus Torvalds1da177e2005-04-16 15:20:36 -07001771 sis_malloc(&sismemreq);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001772
Linus Torvalds1da177e2005-04-16 15:20:36 -07001773 if(copy_to_user((void __user *)arg, &sismemreq, sizeof(sismemreq))) {
1774 sis_free((u32)sismemreq.offset);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001775 return -EFAULT;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001776 }
1777 break;
1778
1779 case FBIO_FREE:
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001780 if(!capable(CAP_SYS_RAWIO))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001781 return -EPERM;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001782
1783 if(get_user(gpu32, argp))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001784 return -EFAULT;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001785
Linus Torvalds1da177e2005-04-16 15:20:36 -07001786 sis_free(gpu32);
1787 break;
1788
1789 case FBIOGET_VBLANK:
1790 sisvbblank.count = 0;
1791 sisvbblank.flags = sisfb_setupvbblankflags(ivideo, &sisvbblank.vcount, &sisvbblank.hcount);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001792
1793 if(copy_to_user((void __user *)arg, &sisvbblank, sizeof(sisvbblank)))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001794 return -EFAULT;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001795
Linus Torvalds1da177e2005-04-16 15:20:36 -07001796 break;
1797
1798 case SISFB_GET_INFO_SIZE:
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001799 return put_user(sizeof(struct sisfb_info), argp);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001800
1801 case SISFB_GET_INFO_OLD:
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001802 if(ivideo->warncount++ < 10)
1803 printk(KERN_INFO
1804 "sisfb: Deprecated ioctl call received - update your application!\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001805 case SISFB_GET_INFO: /* For communication with X driver */
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001806 ivideo->sisfb_infoblock.sisfb_id = SISFB_ID;
1807 ivideo->sisfb_infoblock.sisfb_version = VER_MAJOR;
1808 ivideo->sisfb_infoblock.sisfb_revision = VER_MINOR;
1809 ivideo->sisfb_infoblock.sisfb_patchlevel = VER_LEVEL;
1810 ivideo->sisfb_infoblock.chip_id = ivideo->chip_id;
1811 ivideo->sisfb_infoblock.sisfb_pci_vendor = ivideo->chip_vendor;
1812 ivideo->sisfb_infoblock.memory = ivideo->video_size / 1024;
1813 ivideo->sisfb_infoblock.heapstart = ivideo->heapstart / 1024;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001814 if(ivideo->modechanged) {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001815 ivideo->sisfb_infoblock.fbvidmode = ivideo->mode_no;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001816 } else {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001817 ivideo->sisfb_infoblock.fbvidmode = ivideo->modeprechange;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001818 }
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001819 ivideo->sisfb_infoblock.sisfb_caps = ivideo->caps;
1820 ivideo->sisfb_infoblock.sisfb_tqlen = ivideo->cmdQueueSize / 1024;
1821 ivideo->sisfb_infoblock.sisfb_pcibus = ivideo->pcibus;
1822 ivideo->sisfb_infoblock.sisfb_pcislot = ivideo->pcislot;
1823 ivideo->sisfb_infoblock.sisfb_pcifunc = ivideo->pcifunc;
1824 ivideo->sisfb_infoblock.sisfb_lcdpdc = ivideo->detectedpdc;
1825 ivideo->sisfb_infoblock.sisfb_lcdpdca = ivideo->detectedpdca;
1826 ivideo->sisfb_infoblock.sisfb_lcda = ivideo->detectedlcda;
1827 ivideo->sisfb_infoblock.sisfb_vbflags = ivideo->vbflags;
1828 ivideo->sisfb_infoblock.sisfb_currentvbflags = ivideo->currentvbflags;
1829 ivideo->sisfb_infoblock.sisfb_scalelcd = ivideo->SiS_Pr.UsePanelScaler;
1830 ivideo->sisfb_infoblock.sisfb_specialtiming = ivideo->SiS_Pr.SiS_CustomT;
1831 ivideo->sisfb_infoblock.sisfb_haveemi = ivideo->SiS_Pr.HaveEMI ? 1 : 0;
1832 ivideo->sisfb_infoblock.sisfb_haveemilcd = ivideo->SiS_Pr.HaveEMILCD ? 1 : 0;
1833 ivideo->sisfb_infoblock.sisfb_emi30 = ivideo->SiS_Pr.EMI_30;
1834 ivideo->sisfb_infoblock.sisfb_emi31 = ivideo->SiS_Pr.EMI_31;
1835 ivideo->sisfb_infoblock.sisfb_emi32 = ivideo->SiS_Pr.EMI_32;
1836 ivideo->sisfb_infoblock.sisfb_emi33 = ivideo->SiS_Pr.EMI_33;
1837 ivideo->sisfb_infoblock.sisfb_tvxpos = (u16)(ivideo->tvxpos + 32);
1838 ivideo->sisfb_infoblock.sisfb_tvypos = (u16)(ivideo->tvypos + 32);
1839 ivideo->sisfb_infoblock.sisfb_heapsize = ivideo->sisfb_heap_size / 1024;
1840 ivideo->sisfb_infoblock.sisfb_videooffset = ivideo->video_offset;
1841 ivideo->sisfb_infoblock.sisfb_curfstn = ivideo->curFSTN;
1842 ivideo->sisfb_infoblock.sisfb_curdstn = ivideo->curDSTN;
1843 ivideo->sisfb_infoblock.sisfb_vbflags2 = ivideo->vbflags2;
1844 ivideo->sisfb_infoblock.sisfb_can_post = ivideo->sisfb_can_post ? 1 : 0;
1845 ivideo->sisfb_infoblock.sisfb_card_posted = ivideo->sisfb_card_posted ? 1 : 0;
1846 ivideo->sisfb_infoblock.sisfb_was_boot_device = ivideo->sisfb_was_boot_device ? 1 : 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001847
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001848 if(copy_to_user((void __user *)arg, &ivideo->sisfb_infoblock,
1849 sizeof(ivideo->sisfb_infoblock)))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001850 return -EFAULT;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001851
Linus Torvalds1da177e2005-04-16 15:20:36 -07001852 break;
1853
1854 case SISFB_GET_VBRSTATUS_OLD:
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001855 if(ivideo->warncount++ < 10)
1856 printk(KERN_INFO
1857 "sisfb: Deprecated ioctl call received - update your application!\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001858 case SISFB_GET_VBRSTATUS:
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001859 if(sisfb_CheckVBRetrace(ivideo))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001860 return put_user((u32)1, argp);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001861 else
Linus Torvalds1da177e2005-04-16 15:20:36 -07001862 return put_user((u32)0, argp);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001863
1864 case SISFB_GET_AUTOMAXIMIZE_OLD:
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001865 if(ivideo->warncount++ < 10)
1866 printk(KERN_INFO
1867 "sisfb: Deprecated ioctl call received - update your application!\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001868 case SISFB_GET_AUTOMAXIMIZE:
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001869 if(ivideo->sisfb_max)
1870 return put_user((u32)1, argp);
1871 else
1872 return put_user((u32)0, argp);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001873
1874 case SISFB_SET_AUTOMAXIMIZE_OLD:
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001875 if(ivideo->warncount++ < 10)
1876 printk(KERN_INFO
1877 "sisfb: Deprecated ioctl call received - update your application!\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001878 case SISFB_SET_AUTOMAXIMIZE:
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001879 if(get_user(gpu32, argp))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001880 return -EFAULT;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001881
Linus Torvalds1da177e2005-04-16 15:20:36 -07001882 ivideo->sisfb_max = (gpu32) ? 1 : 0;
1883 break;
1884
1885 case SISFB_SET_TVPOSOFFSET:
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001886 if(get_user(gpu32, argp))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001887 return -EFAULT;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001888
Linus Torvalds1da177e2005-04-16 15:20:36 -07001889 sisfb_set_TVxposoffset(ivideo, ((int)(gpu32 >> 16)) - 32);
1890 sisfb_set_TVyposoffset(ivideo, ((int)(gpu32 & 0xffff)) - 32);
1891 break;
1892
1893 case SISFB_GET_TVPOSOFFSET:
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001894 return put_user((u32)(((ivideo->tvxpos+32)<<16)|((ivideo->tvypos+32)&0xffff)),
1895 argp);
1896
1897 case SISFB_COMMAND:
1898 if(copy_from_user(&ivideo->sisfb_command, (void __user *)arg,
1899 sizeof(struct sisfb_cmd)))
1900 return -EFAULT;
1901
1902 sisfb_handle_command(ivideo, &ivideo->sisfb_command);
1903
1904 if(copy_to_user((void __user *)arg, &ivideo->sisfb_command,
1905 sizeof(struct sisfb_cmd)))
1906 return -EFAULT;
1907
1908 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001909
1910 case SISFB_SET_LOCK:
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001911 if(get_user(gpu32, argp))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001912 return -EFAULT;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001913
Linus Torvalds1da177e2005-04-16 15:20:36 -07001914 ivideo->sisfblocked = (gpu32) ? 1 : 0;
1915 break;
1916
1917 default:
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001918#ifdef SIS_NEW_CONFIG_COMPAT
Linus Torvalds1da177e2005-04-16 15:20:36 -07001919 return -ENOIOCTLCMD;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001920#else
1921 return -EINVAL;
1922#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -07001923 }
1924 return 0;
1925}
1926
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001927#ifdef SIS_NEW_CONFIG_COMPAT
1928static long
1929sisfb_compat_ioctl(struct file *f, unsigned int cmd, unsigned long arg, struct fb_info *info)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001930{
1931 int ret;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001932
Linus Torvalds1da177e2005-04-16 15:20:36 -07001933 lock_kernel();
1934 ret = sisfb_ioctl(NULL, f, cmd, arg, info);
1935 unlock_kernel();
1936 return ret;
1937}
1938#endif
1939
1940static int
1941sisfb_get_fix(struct fb_fix_screeninfo *fix, int con, struct fb_info *info)
1942{
1943 struct sis_video_info *ivideo = (struct sis_video_info *)info->par;
1944
1945 memset(fix, 0, sizeof(struct fb_fix_screeninfo));
1946
1947 strcpy(fix->id, ivideo->myid);
1948
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001949 fix->smem_start = ivideo->video_base + ivideo->video_offset;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001950 fix->smem_len = ivideo->sisfb_mem;
1951 fix->type = FB_TYPE_PACKED_PIXELS;
1952 fix->type_aux = 0;
1953 fix->visual = (ivideo->video_bpp == 8) ? FB_VISUAL_PSEUDOCOLOR : FB_VISUAL_TRUECOLOR;
1954 fix->xpanstep = 1;
1955 fix->ypanstep = (ivideo->sisfb_ypan) ? 1 : 0;
1956 fix->ywrapstep = 0;
1957 fix->line_length = ivideo->video_linelength;
1958 fix->mmio_start = ivideo->mmio_base;
1959 fix->mmio_len = ivideo->mmio_size;
1960 if(ivideo->sisvga_engine == SIS_300_VGA) {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001961 fix->accel = FB_ACCEL_SIS_GLAMOUR;
1962 } else if((ivideo->chip == SIS_330) ||
1963 (ivideo->chip == SIS_760) ||
1964 (ivideo->chip == SIS_761)) {
1965 fix->accel = FB_ACCEL_SIS_XABRE;
1966 } else if(ivideo->chip == XGI_20) {
1967 fix->accel = FB_ACCEL_XGI_VOLARI_Z;
1968 } else if(ivideo->chip >= XGI_40) {
1969 fix->accel = FB_ACCEL_XGI_VOLARI_V;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001970 } else {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001971 fix->accel = FB_ACCEL_SIS_GLAMOUR_2;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001972 }
1973
1974 return 0;
1975}
1976
1977/* ---------------- fb_ops structures ----------------- */
1978
1979#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
1980static struct fb_ops sisfb_ops = {
1981 .owner = THIS_MODULE,
1982 .fb_get_fix = sisfb_get_fix,
1983 .fb_get_var = sisfb_get_var,
1984 .fb_set_var = sisfb_set_var,
1985 .fb_get_cmap = sisfb_get_cmap,
1986 .fb_set_cmap = sisfb_set_cmap,
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001987 .fb_pan_display = sisfb_pan_display,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001988 .fb_ioctl = sisfb_ioctl
1989};
1990#endif
1991
1992#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0)
1993static struct fb_ops sisfb_ops = {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001994 .owner = THIS_MODULE,
1995 .fb_open = sisfb_open,
1996 .fb_release = sisfb_release,
1997 .fb_check_var = sisfb_check_var,
1998 .fb_set_par = sisfb_set_par,
1999 .fb_setcolreg = sisfb_setcolreg,
2000 .fb_pan_display = sisfb_pan_display,
2001 .fb_blank = sisfb_blank,
2002 .fb_fillrect = fbcon_sis_fillrect,
2003 .fb_copyarea = fbcon_sis_copyarea,
2004 .fb_imageblit = cfb_imageblit,
Antonino A. Daplasc465e052005-11-07 01:00:35 -08002005#ifdef CONFIG_FB_SOFT_CURSOR
Thomas Winischhofer544393f2005-09-09 13:04:45 -07002006 .fb_cursor = soft_cursor,
Antonino A. Daplasc465e052005-11-07 01:00:35 -08002007#endif
Thomas Winischhofer544393f2005-09-09 13:04:45 -07002008 .fb_sync = fbcon_sis_sync,
2009#ifdef SIS_NEW_CONFIG_COMPAT
2010 .fb_compat_ioctl= sisfb_compat_ioctl,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002011#endif
Thomas Winischhofer544393f2005-09-09 13:04:45 -07002012 .fb_ioctl = sisfb_ioctl
Linus Torvalds1da177e2005-04-16 15:20:36 -07002013};
2014#endif
2015
2016/* ---------------- Chip generation dependent routines ---------------- */
2017
Thomas Winischhofer544393f2005-09-09 13:04:45 -07002018static struct pci_dev * __devinit
2019sisfb_get_northbridge(int basechipid)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002020{
2021 struct pci_dev *pdev = NULL;
2022 int nbridgenum, nbridgeidx, i;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07002023 static const unsigned short nbridgeids[] = {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002024 PCI_DEVICE_ID_SI_540, /* for SiS 540 VGA */
2025 PCI_DEVICE_ID_SI_630, /* for SiS 630/730 VGA */
2026 PCI_DEVICE_ID_SI_730,
2027 PCI_DEVICE_ID_SI_550, /* for SiS 550 VGA */
2028 PCI_DEVICE_ID_SI_650, /* for SiS 650/651/740 VGA */
2029 PCI_DEVICE_ID_SI_651,
2030 PCI_DEVICE_ID_SI_740,
Thomas Winischhofer544393f2005-09-09 13:04:45 -07002031 PCI_DEVICE_ID_SI_661, /* for SiS 661/741/660/760/761 VGA */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002032 PCI_DEVICE_ID_SI_741,
2033 PCI_DEVICE_ID_SI_660,
Thomas Winischhofer544393f2005-09-09 13:04:45 -07002034 PCI_DEVICE_ID_SI_760,
2035 PCI_DEVICE_ID_SI_761
Linus Torvalds1da177e2005-04-16 15:20:36 -07002036 };
2037
Thomas Winischhofer544393f2005-09-09 13:04:45 -07002038 switch(basechipid) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002039#ifdef CONFIG_FB_SIS_300
2040 case SIS_540: nbridgeidx = 0; nbridgenum = 1; break;
2041 case SIS_630: nbridgeidx = 1; nbridgenum = 2; break;
2042#endif
2043#ifdef CONFIG_FB_SIS_315
2044 case SIS_550: nbridgeidx = 3; nbridgenum = 1; break;
2045 case SIS_650: nbridgeidx = 4; nbridgenum = 3; break;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07002046 case SIS_660: nbridgeidx = 7; nbridgenum = 5; break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002047#endif
2048 default: return NULL;
2049 }
2050 for(i = 0; i < nbridgenum; i++) {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07002051 if((pdev = SIS_PCI_GET_DEVICE(PCI_VENDOR_ID_SI,
2052 nbridgeids[nbridgeidx+i], NULL)))
2053 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002054 }
2055 return pdev;
2056}
2057
Thomas Winischhofer544393f2005-09-09 13:04:45 -07002058static int __devinit
2059sisfb_get_dram_size(struct sis_video_info *ivideo)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002060{
2061#if defined(CONFIG_FB_SIS_300) || defined(CONFIG_FB_SIS_315)
2062 u8 reg;
2063#endif
2064
2065 ivideo->video_size = 0;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07002066 ivideo->UMAsize = ivideo->LFBsize = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002067
2068 switch(ivideo->chip) {
2069#ifdef CONFIG_FB_SIS_300
2070 case SIS_300:
Thomas Winischhofer544393f2005-09-09 13:04:45 -07002071 inSISIDXREG(SISSR, 0x14, reg);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002072 ivideo->video_size = ((reg & 0x3F) + 1) << 20;
2073 break;
2074 case SIS_540:
2075 case SIS_630:
2076 case SIS_730:
Thomas Winischhofer544393f2005-09-09 13:04:45 -07002077 if(!ivideo->nbridge)
2078 return -1;
2079 pci_read_config_byte(ivideo->nbridge, 0x63, &reg);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002080 ivideo->video_size = 1 << (((reg & 0x70) >> 4) + 21);
2081 break;
2082#endif
2083#ifdef CONFIG_FB_SIS_315
2084 case SIS_315H:
2085 case SIS_315PRO:
2086 case SIS_315:
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 switch((reg >> 2) & 0x03) {
2090 case 0x01:
2091 case 0x03:
Thomas Winischhofer544393f2005-09-09 13:04:45 -07002092 ivideo->video_size <<= 1;
2093 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002094 case 0x02:
Thomas Winischhofer544393f2005-09-09 13:04:45 -07002095 ivideo->video_size += (ivideo->video_size/2);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002096 }
Thomas Winischhofer544393f2005-09-09 13:04:45 -07002097 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002098 case SIS_330:
Thomas Winischhofer544393f2005-09-09 13:04:45 -07002099 inSISIDXREG(SISSR, 0x14, reg);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002100 ivideo->video_size = (1 << ((reg & 0xf0) >> 4)) << 20;
2101 if(reg & 0x0c) ivideo->video_size <<= 1;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07002102 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002103 case SIS_550:
2104 case SIS_650:
2105 case SIS_740:
Thomas Winischhofer544393f2005-09-09 13:04:45 -07002106 inSISIDXREG(SISSR, 0x14, reg);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002107 ivideo->video_size = (((reg & 0x3f) + 1) << 2) << 20;
2108 break;
2109 case SIS_661:
2110 case SIS_741:
Thomas Winischhofer544393f2005-09-09 13:04:45 -07002111 inSISIDXREG(SISCR, 0x79, reg);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002112 ivideo->video_size = (1 << ((reg & 0xf0) >> 4)) << 20;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07002113 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002114 case SIS_660:
2115 case SIS_760:
Thomas Winischhofer544393f2005-09-09 13:04:45 -07002116 case SIS_761:
Linus Torvalds1da177e2005-04-16 15:20:36 -07002117 inSISIDXREG(SISCR, 0x79, reg);
2118 reg = (reg & 0xf0) >> 4;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07002119 if(reg) {
2120 ivideo->video_size = (1 << reg) << 20;
2121 ivideo->UMAsize = ivideo->video_size;
2122 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002123 inSISIDXREG(SISCR, 0x78, reg);
2124 reg &= 0x30;
2125 if(reg) {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07002126 if(reg == 0x10) {
2127 ivideo->LFBsize = (32 << 20);
2128 } else {
2129 ivideo->LFBsize = (64 << 20);
2130 }
2131 ivideo->video_size += ivideo->LFBsize;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002132 }
Thomas Winischhofer544393f2005-09-09 13:04:45 -07002133 break;
2134 case SIS_340:
2135 case XGI_20:
2136 case XGI_40:
2137 inSISIDXREG(SISSR, 0x14, reg);
2138 ivideo->video_size = (1 << ((reg & 0xf0) >> 4)) << 20;
2139 if(ivideo->chip != XGI_20) {
2140 reg = (reg & 0x0c) >> 2;
2141 if(ivideo->revision_id == 2) {
2142 if(reg & 0x01) reg = 0x02;
2143 else reg = 0x00;
2144 }
2145 if(reg == 0x02) ivideo->video_size <<= 1;
2146 else if(reg == 0x03) ivideo->video_size <<= 2;
2147 }
2148 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002149#endif
2150 default:
2151 return -1;
2152 }
2153 return 0;
2154}
2155
2156/* -------------- video bridge device detection --------------- */
2157
Thomas Winischhofer544393f2005-09-09 13:04:45 -07002158static void __devinit
2159sisfb_detect_VB_connect(struct sis_video_info *ivideo)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002160{
2161 u8 cr32, temp;
2162
Thomas Winischhofer544393f2005-09-09 13:04:45 -07002163 /* No CRT2 on XGI Z7 */
2164 if(ivideo->chip == XGI_20) {
2165 ivideo->sisfb_crt1off = 0;
2166 return;
2167 }
2168
Linus Torvalds1da177e2005-04-16 15:20:36 -07002169#ifdef CONFIG_FB_SIS_300
2170 if(ivideo->sisvga_engine == SIS_300_VGA) {
2171 inSISIDXREG(SISSR, 0x17, temp);
2172 if((temp & 0x0F) && (ivideo->chip != SIS_300)) {
2173 /* PAL/NTSC is stored on SR16 on such machines */
2174 if(!(ivideo->vbflags & (TV_PAL | TV_NTSC | TV_PALM | TV_PALN))) {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07002175 inSISIDXREG(SISSR, 0x16, temp);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002176 if(temp & 0x20)
2177 ivideo->vbflags |= TV_PAL;
2178 else
2179 ivideo->vbflags |= TV_NTSC;
2180 }
2181 }
2182 }
2183#endif
2184
2185 inSISIDXREG(SISCR, 0x32, cr32);
2186
2187 if(cr32 & SIS_CRT1) {
2188 ivideo->sisfb_crt1off = 0;
2189 } else {
2190 ivideo->sisfb_crt1off = (cr32 & 0xDF) ? 1 : 0;
2191 }
2192
2193 ivideo->vbflags &= ~(CRT2_TV | CRT2_LCD | CRT2_VGA);
2194
2195 if(cr32 & SIS_VB_TV) ivideo->vbflags |= CRT2_TV;
2196 if(cr32 & SIS_VB_LCD) ivideo->vbflags |= CRT2_LCD;
2197 if(cr32 & SIS_VB_CRT2) ivideo->vbflags |= CRT2_VGA;
2198
2199 /* Check given parms for hardware compatibility.
2200 * (Cannot do this in the search_xx routines since we don't
2201 * know what hardware we are running on then)
2202 */
2203
2204 if(ivideo->chip != SIS_550) {
2205 ivideo->sisfb_dstn = ivideo->sisfb_fstn = 0;
2206 }
2207
2208 if(ivideo->sisfb_tvplug != -1) {
2209 if( (ivideo->sisvga_engine != SIS_315_VGA) ||
Thomas Winischhofer544393f2005-09-09 13:04:45 -07002210 (!(ivideo->vbflags2 & VB2_SISYPBPRBRIDGE)) ) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002211 if(ivideo->sisfb_tvplug & TV_YPBPR) {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07002212 ivideo->sisfb_tvplug = -1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002213 printk(KERN_ERR "sisfb: YPbPr not supported\n");
2214 }
2215 }
2216 }
2217 if(ivideo->sisfb_tvplug != -1) {
2218 if( (ivideo->sisvga_engine != SIS_315_VGA) ||
Thomas Winischhofer544393f2005-09-09 13:04:45 -07002219 (!(ivideo->vbflags2 & VB2_SISHIVISIONBRIDGE)) ) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002220 if(ivideo->sisfb_tvplug & TV_HIVISION) {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07002221 ivideo->sisfb_tvplug = -1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002222 printk(KERN_ERR "sisfb: HiVision not supported\n");
2223 }
2224 }
2225 }
2226 if(ivideo->sisfb_tvstd != -1) {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07002227 if( (!(ivideo->vbflags2 & VB2_SISBRIDGE)) &&
2228 (!((ivideo->sisvga_engine == SIS_315_VGA) &&
2229 (ivideo->vbflags2 & VB2_CHRONTEL))) ) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002230 if(ivideo->sisfb_tvstd & (TV_PALN | TV_PALN | TV_NTSCJ)) {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07002231 ivideo->sisfb_tvstd = -1;
2232 printk(KERN_ERR "sisfb: PALM/PALN/NTSCJ not supported\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002233 }
2234 }
2235 }
2236
2237 /* Detect/set TV plug & type */
2238 if(ivideo->sisfb_tvplug != -1) {
2239 ivideo->vbflags |= ivideo->sisfb_tvplug;
2240 } else {
2241 if(cr32 & SIS_VB_YPBPR) ivideo->vbflags |= (TV_YPBPR|TV_YPBPR525I); /* default: 480i */
2242 else if(cr32 & SIS_VB_HIVISION) ivideo->vbflags |= TV_HIVISION;
2243 else if(cr32 & SIS_VB_SCART) ivideo->vbflags |= TV_SCART;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07002244 else {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002245 if(cr32 & SIS_VB_SVIDEO) ivideo->vbflags |= TV_SVIDEO;
2246 if(cr32 & SIS_VB_COMPOSITE) ivideo->vbflags |= TV_AVIDEO;
2247 }
2248 }
2249
2250 if(!(ivideo->vbflags & (TV_YPBPR | TV_HIVISION))) {
2251 if(ivideo->sisfb_tvstd != -1) {
2252 ivideo->vbflags &= ~(TV_NTSC | TV_PAL | TV_PALM | TV_PALN | TV_NTSCJ);
2253 ivideo->vbflags |= ivideo->sisfb_tvstd;
2254 }
2255 if(ivideo->vbflags & TV_SCART) {
2256 ivideo->vbflags &= ~(TV_NTSC | TV_PALM | TV_PALN | TV_NTSCJ);
2257 ivideo->vbflags |= TV_PAL;
2258 }
2259 if(!(ivideo->vbflags & (TV_PAL | TV_NTSC | TV_PALM | TV_PALN | TV_NTSCJ))) {
2260 if(ivideo->sisvga_engine == SIS_300_VGA) {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07002261 inSISIDXREG(SISSR, 0x38, temp);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002262 if(temp & 0x01) ivideo->vbflags |= TV_PAL;
2263 else ivideo->vbflags |= TV_NTSC;
2264 } else if((ivideo->chip <= SIS_315PRO) || (ivideo->chip >= SIS_330)) {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07002265 inSISIDXREG(SISSR, 0x38, temp);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002266 if(temp & 0x01) ivideo->vbflags |= TV_PAL;
2267 else ivideo->vbflags |= TV_NTSC;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07002268 } else {
2269 inSISIDXREG(SISCR, 0x79, temp);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002270 if(temp & 0x20) ivideo->vbflags |= TV_PAL;
2271 else ivideo->vbflags |= TV_NTSC;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07002272 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002273 }
2274 }
2275
2276 /* Copy forceCRT1 option to CRT1off if option is given */
Thomas Winischhofer544393f2005-09-09 13:04:45 -07002277 if(ivideo->sisfb_forcecrt1 != -1) {
2278 ivideo->sisfb_crt1off = (ivideo->sisfb_forcecrt1) ? 0 : 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002279 }
2280}
2281
2282/* ------------------ Sensing routines ------------------ */
2283
Thomas Winischhofer544393f2005-09-09 13:04:45 -07002284static BOOLEAN __devinit
2285sisfb_test_DDC1(struct sis_video_info *ivideo)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002286{
2287 unsigned short old;
2288 int count = 48;
2289
2290 old = SiS_ReadDDC1Bit(&ivideo->SiS_Pr);
2291 do {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07002292 if(old != SiS_ReadDDC1Bit(&ivideo->SiS_Pr)) break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002293 } while(count--);
2294 return (count == -1) ? FALSE : TRUE;
2295}
2296
Thomas Winischhofer544393f2005-09-09 13:04:45 -07002297static void __devinit
2298sisfb_sense_crt1(struct sis_video_info *ivideo)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002299{
2300 BOOLEAN mustwait = FALSE;
2301 u8 sr1F, cr17;
2302#ifdef CONFIG_FB_SIS_315
2303 u8 cr63=0;
2304#endif
2305 u16 temp = 0xffff;
2306 int i;
2307
2308 inSISIDXREG(SISSR,0x1F,sr1F);
2309 orSISIDXREG(SISSR,0x1F,0x04);
2310 andSISIDXREG(SISSR,0x1F,0x3F);
2311 if(sr1F & 0xc0) mustwait = TRUE;
2312
2313#ifdef CONFIG_FB_SIS_315
2314 if(ivideo->sisvga_engine == SIS_315_VGA) {
2315 inSISIDXREG(SISCR,ivideo->SiS_Pr.SiS_MyCR63,cr63);
2316 cr63 &= 0x40;
2317 andSISIDXREG(SISCR,ivideo->SiS_Pr.SiS_MyCR63,0xBF);
2318 }
2319#endif
2320
2321 inSISIDXREG(SISCR,0x17,cr17);
2322 cr17 &= 0x80;
2323 if(!cr17) {
2324 orSISIDXREG(SISCR,0x17,0x80);
2325 mustwait = TRUE;
2326 outSISIDXREG(SISSR, 0x00, 0x01);
2327 outSISIDXREG(SISSR, 0x00, 0x03);
2328 }
2329
2330 if(mustwait) {
2331 for(i=0; i < 10; i++) sisfbwaitretracecrt1(ivideo);
2332 }
2333
2334#ifdef CONFIG_FB_SIS_315
2335 if(ivideo->chip >= SIS_330) {
2336 andSISIDXREG(SISCR,0x32,~0x20);
2337 if(ivideo->chip >= SIS_340) {
2338 outSISIDXREG(SISCR, 0x57, 0x4a);
2339 } else {
2340 outSISIDXREG(SISCR, 0x57, 0x5f);
2341 }
2342 orSISIDXREG(SISCR, 0x53, 0x02);
2343 while((inSISREG(SISINPSTAT)) & 0x01) break;
2344 while(!((inSISREG(SISINPSTAT)) & 0x01)) break;
2345 if((inSISREG(SISMISCW)) & 0x10) temp = 1;
2346 andSISIDXREG(SISCR, 0x53, 0xfd);
2347 andSISIDXREG(SISCR, 0x57, 0x00);
2348 }
2349#endif
2350
2351 if(temp == 0xffff) {
2352 i = 3;
2353 do {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07002354 temp = SiS_HandleDDC(&ivideo->SiS_Pr, ivideo->vbflags,
2355 ivideo->sisvga_engine, 0, 0, NULL, ivideo->vbflags2);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002356 } while(((temp == 0) || (temp == 0xffff)) && i--);
2357
2358 if((temp == 0) || (temp == 0xffff)) {
2359 if(sisfb_test_DDC1(ivideo)) temp = 1;
2360 }
2361 }
2362
2363 if((temp) && (temp != 0xffff)) {
2364 orSISIDXREG(SISCR,0x32,0x20);
2365 }
2366
2367#ifdef CONFIG_FB_SIS_315
2368 if(ivideo->sisvga_engine == SIS_315_VGA) {
2369 setSISIDXREG(SISCR,ivideo->SiS_Pr.SiS_MyCR63,0xBF,cr63);
2370 }
2371#endif
2372
2373 setSISIDXREG(SISCR,0x17,0x7F,cr17);
2374
2375 outSISIDXREG(SISSR,0x1F,sr1F);
2376}
2377
2378/* Determine and detect attached devices on SiS30x */
Thomas Winischhofer544393f2005-09-09 13:04:45 -07002379static void __devinit
2380SiS_SenseLCD(struct sis_video_info *ivideo)
2381{
2382 unsigned char buffer[256];
2383 unsigned short temp, realcrtno, i;
2384 u8 reg, cr37 = 0, paneltype = 0;
2385 u16 xres, yres;
2386
2387 ivideo->SiS_Pr.PanelSelfDetected = FALSE;
2388
2389 /* LCD detection only for TMDS bridges */
2390 if(!(ivideo->vbflags2 & VB2_SISTMDSBRIDGE))
2391 return;
2392 if(ivideo->vbflags2 & VB2_30xBDH)
2393 return;
2394
2395 /* If LCD already set up by BIOS, skip it */
2396 inSISIDXREG(SISCR, 0x32, reg);
2397 if(reg & 0x08)
2398 return;
2399
2400 realcrtno = 1;
2401 if(ivideo->SiS_Pr.DDCPortMixup)
2402 realcrtno = 0;
2403
2404 /* Check DDC capabilities */
2405 temp = SiS_HandleDDC(&ivideo->SiS_Pr, ivideo->vbflags, ivideo->sisvga_engine,
2406 realcrtno, 0, &buffer[0], ivideo->vbflags2);
2407
2408 if((!temp) || (temp == 0xffff) || (!(temp & 0x02)))
2409 return;
2410
2411 /* Read DDC data */
2412 i = 3; /* Number of retrys */
2413 do {
2414 temp = SiS_HandleDDC(&ivideo->SiS_Pr, ivideo->vbflags,
2415 ivideo->sisvga_engine, realcrtno, 1,
2416 &buffer[0], ivideo->vbflags2);
2417 } while((temp) && i--);
2418
2419 if(temp)
2420 return;
2421
2422 /* No digital device */
2423 if(!(buffer[0x14] & 0x80))
2424 return;
2425
2426 /* First detailed timing preferred timing? */
2427 if(!(buffer[0x18] & 0x02))
2428 return;
2429
2430 xres = buffer[0x38] | ((buffer[0x3a] & 0xf0) << 4);
2431 yres = buffer[0x3b] | ((buffer[0x3d] & 0xf0) << 4);
2432
2433 switch(xres) {
2434 case 1024:
2435 if(yres == 768)
2436 paneltype = 0x02;
2437 break;
2438 case 1280:
2439 if(yres == 1024)
2440 paneltype = 0x03;
2441 break;
2442 case 1600:
2443 if((yres == 1200) && (ivideo->vbflags2 & VB2_30xC))
2444 paneltype = 0x0b;
2445 break;
2446 }
2447
2448 if(!paneltype)
2449 return;
2450
2451 if(buffer[0x23])
2452 cr37 |= 0x10;
2453
2454 if((buffer[0x47] & 0x18) == 0x18)
2455 cr37 |= ((((buffer[0x47] & 0x06) ^ 0x06) << 5) | 0x20);
2456 else
2457 cr37 |= 0xc0;
2458
2459 outSISIDXREG(SISCR, 0x36, paneltype);
2460 cr37 &= 0xf1;
2461 setSISIDXREG(SISCR, 0x37, 0x0c, cr37);
2462 orSISIDXREG(SISCR, 0x32, 0x08);
2463
2464 ivideo->SiS_Pr.PanelSelfDetected = TRUE;
2465}
2466
2467static int __devinit
2468SISDoSense(struct sis_video_info *ivideo, u16 type, u16 test)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002469{
2470 int temp, mytest, result, i, j;
2471
2472 for(j = 0; j < 10; j++) {
2473 result = 0;
2474 for(i = 0; i < 3; i++) {
2475 mytest = test;
2476 outSISIDXREG(SISPART4,0x11,(type & 0x00ff));
2477 temp = (type >> 8) | (mytest & 0x00ff);
2478 setSISIDXREG(SISPART4,0x10,0xe0,temp);
2479 SiS_DDC2Delay(&ivideo->SiS_Pr, 0x1500);
2480 mytest >>= 8;
2481 mytest &= 0x7f;
2482 inSISIDXREG(SISPART4,0x03,temp);
2483 temp ^= 0x0e;
2484 temp &= mytest;
2485 if(temp == mytest) result++;
2486#if 1
2487 outSISIDXREG(SISPART4,0x11,0x00);
2488 andSISIDXREG(SISPART4,0x10,0xe0);
2489 SiS_DDC2Delay(&ivideo->SiS_Pr, 0x1000);
2490#endif
2491 }
2492 if((result == 0) || (result >= 2)) break;
2493 }
Thomas Winischhofer544393f2005-09-09 13:04:45 -07002494 return result;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002495}
2496
Thomas Winischhofer544393f2005-09-09 13:04:45 -07002497static void __devinit
2498SiS_Sense30x(struct sis_video_info *ivideo)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002499{
2500 u8 backupP4_0d,backupP2_00,backupP2_4d,backupSR_1e,biosflag=0;
2501 u16 svhs=0, svhs_c=0;
2502 u16 cvbs=0, cvbs_c=0;
2503 u16 vga2=0, vga2_c=0;
2504 int myflag, result;
2505 char stdstr[] = "sisfb: Detected";
2506 char tvstr[] = "TV connected to";
2507
Thomas Winischhofer544393f2005-09-09 13:04:45 -07002508 if(ivideo->vbflags2 & VB2_301) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002509 svhs = 0x00b9; cvbs = 0x00b3; vga2 = 0x00d1;
2510 inSISIDXREG(SISPART4,0x01,myflag);
2511 if(myflag & 0x04) {
2512 svhs = 0x00dd; cvbs = 0x00ee; vga2 = 0x00fd;
2513 }
Thomas Winischhofer544393f2005-09-09 13:04:45 -07002514 } else if(ivideo->vbflags2 & (VB2_301B | VB2_302B)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002515 svhs = 0x016b; cvbs = 0x0174; vga2 = 0x0190;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07002516 } else if(ivideo->vbflags2 & (VB2_301LV | VB2_302LV)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002517 svhs = 0x0200; cvbs = 0x0100;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07002518 } else if(ivideo->vbflags2 & (VB2_301C | VB2_302ELV | VB2_307T | VB2_307LV)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002519 svhs = 0x016b; cvbs = 0x0110; vga2 = 0x0190;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07002520 } else
2521 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002522
2523 vga2_c = 0x0e08; svhs_c = 0x0404; cvbs_c = 0x0804;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07002524 if(ivideo->vbflags & (VB2_301LV|VB2_302LV|VB2_302ELV|VB2_307LV)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002525 svhs_c = 0x0408; cvbs_c = 0x0808;
2526 }
Thomas Winischhofer544393f2005-09-09 13:04:45 -07002527
Linus Torvalds1da177e2005-04-16 15:20:36 -07002528 biosflag = 2;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07002529 if(ivideo->haveXGIROM) {
2530 biosflag = ivideo->bios_abase[0x58] & 0x03;
2531 } else if(ivideo->newrom) {
2532 if(ivideo->bios_abase[0x5d] & 0x04) biosflag |= 0x01;
2533 } else if(ivideo->sisvga_engine == SIS_300_VGA) {
2534 if(ivideo->bios_abase) {
2535 biosflag = ivideo->bios_abase[0xfe] & 0x03;
2536 }
2537 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002538
2539 if(ivideo->chip == SIS_300) {
2540 inSISIDXREG(SISSR,0x3b,myflag);
2541 if(!(myflag & 0x01)) vga2 = vga2_c = 0;
2542 }
2543
Thomas Winischhofer544393f2005-09-09 13:04:45 -07002544 if(!(ivideo->vbflags2 & VB2_SISVGA2BRIDGE)) {
2545 vga2 = vga2_c = 0;
2546 }
2547
Linus Torvalds1da177e2005-04-16 15:20:36 -07002548 inSISIDXREG(SISSR,0x1e,backupSR_1e);
2549 orSISIDXREG(SISSR,0x1e,0x20);
2550
2551 inSISIDXREG(SISPART4,0x0d,backupP4_0d);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07002552 if(ivideo->vbflags2 & VB2_30xC) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002553 setSISIDXREG(SISPART4,0x0d,~0x07,0x01);
2554 } else {
2555 orSISIDXREG(SISPART4,0x0d,0x04);
2556 }
2557 SiS_DDC2Delay(&ivideo->SiS_Pr, 0x2000);
2558
2559 inSISIDXREG(SISPART2,0x00,backupP2_00);
2560 outSISIDXREG(SISPART2,0x00,((backupP2_00 | 0x1c) & 0xfc));
2561
2562 inSISIDXREG(SISPART2,0x4d,backupP2_4d);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07002563 if(ivideo->vbflags2 & VB2_SISYPBPRBRIDGE) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002564 outSISIDXREG(SISPART2,0x4d,(backupP2_4d & ~0x10));
2565 }
2566
Thomas Winischhofer544393f2005-09-09 13:04:45 -07002567 if(!(ivideo->vbflags2 & VB2_30xCLV)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002568 SISDoSense(ivideo, 0, 0);
2569 }
2570
2571 andSISIDXREG(SISCR, 0x32, ~0x14);
2572
2573 if(vga2_c || vga2) {
2574 if(SISDoSense(ivideo, vga2, vga2_c)) {
2575 if(biosflag & 0x01) {
2576 printk(KERN_INFO "%s %s SCART output\n", stdstr, tvstr);
2577 orSISIDXREG(SISCR, 0x32, 0x04);
2578 } else {
2579 printk(KERN_INFO "%s secondary VGA connection\n", stdstr);
2580 orSISIDXREG(SISCR, 0x32, 0x10);
2581 }
2582 }
2583 }
2584
2585 andSISIDXREG(SISCR, 0x32, 0x3f);
2586
Thomas Winischhofer544393f2005-09-09 13:04:45 -07002587 if(ivideo->vbflags2 & VB2_30xCLV) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002588 orSISIDXREG(SISPART4,0x0d,0x04);
2589 }
2590
Thomas Winischhofer544393f2005-09-09 13:04:45 -07002591 if((ivideo->sisvga_engine == SIS_315_VGA) && (ivideo->vbflags2 & VB2_SISYPBPRBRIDGE)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002592 outSISIDXREG(SISPART2,0x4d,(backupP2_4d | 0x10));
2593 SiS_DDC2Delay(&ivideo->SiS_Pr, 0x2000);
2594 if((result = SISDoSense(ivideo, svhs, 0x0604))) {
2595 if((result = SISDoSense(ivideo, cvbs, 0x0804))) {
2596 printk(KERN_INFO "%s %s YPbPr component output\n", stdstr, tvstr);
2597 orSISIDXREG(SISCR,0x32,0x80);
2598 }
2599 }
2600 outSISIDXREG(SISPART2,0x4d,backupP2_4d);
2601 }
2602
2603 andSISIDXREG(SISCR, 0x32, ~0x03);
2604
2605 if(!(ivideo->vbflags & TV_YPBPR)) {
2606 if((result = SISDoSense(ivideo, svhs, svhs_c))) {
2607 printk(KERN_INFO "%s %s SVIDEO output\n", stdstr, tvstr);
2608 orSISIDXREG(SISCR, 0x32, 0x02);
2609 }
2610 if((biosflag & 0x02) || (!result)) {
2611 if(SISDoSense(ivideo, cvbs, cvbs_c)) {
2612 printk(KERN_INFO "%s %s COMPOSITE output\n", stdstr, tvstr);
2613 orSISIDXREG(SISCR, 0x32, 0x01);
2614 }
2615 }
2616 }
2617
2618 SISDoSense(ivideo, 0, 0);
2619
2620 outSISIDXREG(SISPART2,0x00,backupP2_00);
2621 outSISIDXREG(SISPART4,0x0d,backupP4_0d);
2622 outSISIDXREG(SISSR,0x1e,backupSR_1e);
2623
Thomas Winischhofer544393f2005-09-09 13:04:45 -07002624 if(ivideo->vbflags2 & VB2_30xCLV) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002625 inSISIDXREG(SISPART2,0x00,biosflag);
2626 if(biosflag & 0x20) {
2627 for(myflag = 2; myflag > 0; myflag--) {
2628 biosflag ^= 0x20;
2629 outSISIDXREG(SISPART2,0x00,biosflag);
2630 }
2631 }
2632 }
2633
2634 outSISIDXREG(SISPART2,0x00,backupP2_00);
2635}
2636
2637/* Determine and detect attached TV's on Chrontel */
Thomas Winischhofer544393f2005-09-09 13:04:45 -07002638static void __devinit
2639SiS_SenseCh(struct sis_video_info *ivideo)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002640{
2641#if defined(CONFIG_FB_SIS_300) || defined(CONFIG_FB_SIS_315)
2642 u8 temp1, temp2;
2643 char stdstr[] = "sisfb: Chrontel: Detected TV connected to";
2644#endif
2645#ifdef CONFIG_FB_SIS_300
2646 unsigned char test[3];
2647 int i;
2648#endif
2649
2650 if(ivideo->chip < SIS_315H) {
2651
2652#ifdef CONFIG_FB_SIS_300
2653 ivideo->SiS_Pr.SiS_IF_DEF_CH70xx = 1; /* Chrontel 700x */
2654 SiS_SetChrontelGPIO(&ivideo->SiS_Pr, 0x9c); /* Set general purpose IO for Chrontel communication */
2655 SiS_DDC2Delay(&ivideo->SiS_Pr, 1000);
2656 temp1 = SiS_GetCH700x(&ivideo->SiS_Pr, 0x25);
2657 /* See Chrontel TB31 for explanation */
2658 temp2 = SiS_GetCH700x(&ivideo->SiS_Pr, 0x0e);
2659 if(((temp2 & 0x07) == 0x01) || (temp2 & 0x04)) {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07002660 SiS_SetCH700x(&ivideo->SiS_Pr, 0x0e, 0x0b);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002661 SiS_DDC2Delay(&ivideo->SiS_Pr, 300);
2662 }
2663 temp2 = SiS_GetCH700x(&ivideo->SiS_Pr, 0x25);
2664 if(temp2 != temp1) temp1 = temp2;
2665
2666 if((temp1 >= 0x22) && (temp1 <= 0x50)) {
2667 /* Read power status */
2668 temp1 = SiS_GetCH700x(&ivideo->SiS_Pr, 0x0e);
2669 if((temp1 & 0x03) != 0x03) {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07002670 /* Power all outputs */
2671 SiS_SetCH700x(&ivideo->SiS_Pr, 0x0e,0x0b);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002672 SiS_DDC2Delay(&ivideo->SiS_Pr, 300);
2673 }
2674 /* Sense connected TV devices */
2675 for(i = 0; i < 3; i++) {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07002676 SiS_SetCH700x(&ivideo->SiS_Pr, 0x10, 0x01);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002677 SiS_DDC2Delay(&ivideo->SiS_Pr, 0x96);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07002678 SiS_SetCH700x(&ivideo->SiS_Pr, 0x10, 0x00);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002679 SiS_DDC2Delay(&ivideo->SiS_Pr, 0x96);
2680 temp1 = SiS_GetCH700x(&ivideo->SiS_Pr, 0x10);
2681 if(!(temp1 & 0x08)) test[i] = 0x02;
2682 else if(!(temp1 & 0x02)) test[i] = 0x01;
2683 else test[i] = 0;
2684 SiS_DDC2Delay(&ivideo->SiS_Pr, 0x96);
2685 }
2686
2687 if(test[0] == test[1]) temp1 = test[0];
2688 else if(test[0] == test[2]) temp1 = test[0];
2689 else if(test[1] == test[2]) temp1 = test[1];
2690 else {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07002691 printk(KERN_INFO
Linus Torvalds1da177e2005-04-16 15:20:36 -07002692 "sisfb: TV detection unreliable - test results varied\n");
2693 temp1 = test[2];
2694 }
2695 if(temp1 == 0x02) {
2696 printk(KERN_INFO "%s SVIDEO output\n", stdstr);
2697 ivideo->vbflags |= TV_SVIDEO;
2698 orSISIDXREG(SISCR, 0x32, 0x02);
2699 andSISIDXREG(SISCR, 0x32, ~0x05);
2700 } else if (temp1 == 0x01) {
2701 printk(KERN_INFO "%s CVBS output\n", stdstr);
2702 ivideo->vbflags |= TV_AVIDEO;
2703 orSISIDXREG(SISCR, 0x32, 0x01);
2704 andSISIDXREG(SISCR, 0x32, ~0x06);
2705 } else {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07002706 SiS_SetCH70xxANDOR(&ivideo->SiS_Pr, 0x0e, 0x01, 0xF8);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002707 andSISIDXREG(SISCR, 0x32, ~0x07);
2708 }
2709 } else if(temp1 == 0) {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07002710 SiS_SetCH70xxANDOR(&ivideo->SiS_Pr, 0x0e, 0x01, 0xF8);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002711 andSISIDXREG(SISCR, 0x32, ~0x07);
2712 }
2713 /* Set general purpose IO for Chrontel communication */
2714 SiS_SetChrontelGPIO(&ivideo->SiS_Pr, 0x00);
2715#endif
2716
2717 } else {
2718
2719#ifdef CONFIG_FB_SIS_315
2720 ivideo->SiS_Pr.SiS_IF_DEF_CH70xx = 2; /* Chrontel 7019 */
Thomas Winischhofer544393f2005-09-09 13:04:45 -07002721 temp1 = SiS_GetCH701x(&ivideo->SiS_Pr, 0x49);
2722 SiS_SetCH701x(&ivideo->SiS_Pr, 0x49, 0x20);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002723 SiS_DDC2Delay(&ivideo->SiS_Pr, 0x96);
2724 temp2 = SiS_GetCH701x(&ivideo->SiS_Pr, 0x20);
2725 temp2 |= 0x01;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07002726 SiS_SetCH701x(&ivideo->SiS_Pr, 0x20, temp2);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002727 SiS_DDC2Delay(&ivideo->SiS_Pr, 0x96);
2728 temp2 ^= 0x01;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07002729 SiS_SetCH701x(&ivideo->SiS_Pr, 0x20, temp2);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002730 SiS_DDC2Delay(&ivideo->SiS_Pr, 0x96);
2731 temp2 = SiS_GetCH701x(&ivideo->SiS_Pr, 0x20);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07002732 SiS_SetCH701x(&ivideo->SiS_Pr, 0x49, temp1);
2733 temp1 = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002734 if(temp2 & 0x02) temp1 |= 0x01;
2735 if(temp2 & 0x10) temp1 |= 0x01;
2736 if(temp2 & 0x04) temp1 |= 0x02;
2737 if( (temp1 & 0x01) && (temp1 & 0x02) ) temp1 = 0x04;
2738 switch(temp1) {
2739 case 0x01:
2740 printk(KERN_INFO "%s CVBS output\n", stdstr);
2741 ivideo->vbflags |= TV_AVIDEO;
2742 orSISIDXREG(SISCR, 0x32, 0x01);
2743 andSISIDXREG(SISCR, 0x32, ~0x06);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07002744 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002745 case 0x02:
2746 printk(KERN_INFO "%s SVIDEO output\n", stdstr);
2747 ivideo->vbflags |= TV_SVIDEO;
2748 orSISIDXREG(SISCR, 0x32, 0x02);
2749 andSISIDXREG(SISCR, 0x32, ~0x05);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07002750 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002751 case 0x04:
2752 printk(KERN_INFO "%s SCART output\n", stdstr);
2753 orSISIDXREG(SISCR, 0x32, 0x04);
2754 andSISIDXREG(SISCR, 0x32, ~0x03);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07002755 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002756 default:
2757 andSISIDXREG(SISCR, 0x32, ~0x07);
2758 }
2759#endif
2760 }
2761}
2762
Thomas Winischhofer544393f2005-09-09 13:04:45 -07002763static void __devinit
2764sisfb_get_VB_type(struct sis_video_info *ivideo)
2765{
2766 char stdstr[] = "sisfb: Detected";
2767 char bridgestr[] = "video bridge";
2768 u8 vb_chipid;
2769 u8 reg;
2770
2771 /* No CRT2 on XGI Z7 */
2772 if(ivideo->chip == XGI_20)
2773 return;
2774
2775 inSISIDXREG(SISPART4, 0x00, vb_chipid);
2776 switch(vb_chipid) {
2777 case 0x01:
2778 inSISIDXREG(SISPART4, 0x01, reg);
2779 if(reg < 0xb0) {
2780 ivideo->vbflags |= VB_301; /* Deprecated */
2781 ivideo->vbflags2 |= VB2_301;
2782 printk(KERN_INFO "%s SiS301 %s\n", stdstr, bridgestr);
2783 } else if(reg < 0xc0) {
2784 ivideo->vbflags |= VB_301B; /* Deprecated */
2785 ivideo->vbflags2 |= VB2_301B;
2786 inSISIDXREG(SISPART4,0x23,reg);
2787 if(!(reg & 0x02)) {
2788 ivideo->vbflags |= VB_30xBDH; /* Deprecated */
2789 ivideo->vbflags2 |= VB2_30xBDH;
2790 printk(KERN_INFO "%s SiS301B-DH %s\n", stdstr, bridgestr);
2791 } else {
2792 printk(KERN_INFO "%s SiS301B %s\n", stdstr, bridgestr);
2793 }
2794 } else if(reg < 0xd0) {
2795 ivideo->vbflags |= VB_301C; /* Deprecated */
2796 ivideo->vbflags2 |= VB2_301C;
2797 printk(KERN_INFO "%s SiS301C %s\n", stdstr, bridgestr);
2798 } else if(reg < 0xe0) {
2799 ivideo->vbflags |= VB_301LV; /* Deprecated */
2800 ivideo->vbflags2 |= VB2_301LV;
2801 printk(KERN_INFO "%s SiS301LV %s\n", stdstr, bridgestr);
2802 } else if(reg <= 0xe1) {
2803 inSISIDXREG(SISPART4,0x39,reg);
2804 if(reg == 0xff) {
2805 ivideo->vbflags |= VB_302LV; /* Deprecated */
2806 ivideo->vbflags2 |= VB2_302LV;
2807 printk(KERN_INFO "%s SiS302LV %s\n", stdstr, bridgestr);
2808 } else {
2809 ivideo->vbflags |= VB_301C; /* Deprecated */
2810 ivideo->vbflags2 |= VB2_301C;
2811 printk(KERN_INFO "%s SiS301C(P4) %s\n", stdstr, bridgestr);
2812#if 0
2813 ivideo->vbflags |= VB_302ELV; /* Deprecated */
2814 ivideo->vbflags2 |= VB2_302ELV;
2815 printk(KERN_INFO "%s SiS302ELV %s\n", stdstr, bridgestr);
2816#endif
2817 }
2818 }
2819 break;
2820 case 0x02:
2821 ivideo->vbflags |= VB_302B; /* Deprecated */
2822 ivideo->vbflags2 |= VB2_302B;
2823 printk(KERN_INFO "%s SiS302B %s\n", stdstr, bridgestr);
2824 break;
2825 }
2826
2827 if((!(ivideo->vbflags2 & VB2_VIDEOBRIDGE)) && (ivideo->chip != SIS_300)) {
2828 inSISIDXREG(SISCR, 0x37, reg);
2829 reg &= SIS_EXTERNAL_CHIP_MASK;
2830 reg >>= 1;
2831 if(ivideo->sisvga_engine == SIS_300_VGA) {
2832#ifdef CONFIG_FB_SIS_300
2833 switch(reg) {
2834 case SIS_EXTERNAL_CHIP_LVDS:
2835 ivideo->vbflags |= VB_LVDS; /* Deprecated */
2836 ivideo->vbflags2 |= VB2_LVDS;
2837 break;
2838 case SIS_EXTERNAL_CHIP_TRUMPION:
2839 ivideo->vbflags |= (VB_LVDS | VB_TRUMPION); /* Deprecated */
2840 ivideo->vbflags2 |= (VB2_LVDS | VB2_TRUMPION);
2841 break;
2842 case SIS_EXTERNAL_CHIP_CHRONTEL:
2843 ivideo->vbflags |= VB_CHRONTEL; /* Deprecated */
2844 ivideo->vbflags2 |= VB2_CHRONTEL;
2845 break;
2846 case SIS_EXTERNAL_CHIP_LVDS_CHRONTEL:
2847 ivideo->vbflags |= (VB_LVDS | VB_CHRONTEL); /* Deprecated */
2848 ivideo->vbflags2 |= (VB2_LVDS | VB2_CHRONTEL);
2849 break;
2850 }
2851 if(ivideo->vbflags2 & VB2_CHRONTEL) ivideo->chronteltype = 1;
2852#endif
2853 } else if(ivideo->chip < SIS_661) {
2854#ifdef CONFIG_FB_SIS_315
2855 switch (reg) {
2856 case SIS310_EXTERNAL_CHIP_LVDS:
2857 ivideo->vbflags |= VB_LVDS; /* Deprecated */
2858 ivideo->vbflags2 |= VB2_LVDS;
2859 break;
2860 case SIS310_EXTERNAL_CHIP_LVDS_CHRONTEL:
2861 ivideo->vbflags |= (VB_LVDS | VB_CHRONTEL); /* Deprecated */
2862 ivideo->vbflags2 |= (VB2_LVDS | VB2_CHRONTEL);
2863 break;
2864 }
2865 if(ivideo->vbflags2 & VB2_CHRONTEL) ivideo->chronteltype = 2;
2866#endif
2867 } else if(ivideo->chip >= SIS_661) {
2868#ifdef CONFIG_FB_SIS_315
2869 inSISIDXREG(SISCR, 0x38, reg);
2870 reg >>= 5;
2871 switch(reg) {
2872 case 0x02:
2873 ivideo->vbflags |= VB_LVDS; /* Deprecated */
2874 ivideo->vbflags2 |= VB2_LVDS;
2875 break;
2876 case 0x03:
2877 ivideo->vbflags |= (VB_LVDS | VB_CHRONTEL); /* Deprecated */
2878 ivideo->vbflags2 |= (VB2_LVDS | VB2_CHRONTEL);
2879 break;
2880 case 0x04:
2881 ivideo->vbflags |= (VB_LVDS | VB_CONEXANT); /* Deprecated */
2882 ivideo->vbflags2 |= (VB2_LVDS | VB2_CONEXANT);
2883 break;
2884 }
2885 if(ivideo->vbflags2 & VB2_CHRONTEL) ivideo->chronteltype = 2;
2886#endif
2887 }
2888 if(ivideo->vbflags2 & VB2_LVDS) {
2889 printk(KERN_INFO "%s LVDS transmitter\n", stdstr);
2890 }
2891 if((ivideo->sisvga_engine == SIS_300_VGA) && (ivideo->vbflags2 & VB2_TRUMPION)) {
2892 printk(KERN_INFO "%s Trumpion Zurac LCD scaler\n", stdstr);
2893 }
2894 if(ivideo->vbflags2 & VB2_CHRONTEL) {
2895 printk(KERN_INFO "%s Chrontel TV encoder\n", stdstr);
2896 }
2897 if((ivideo->chip >= SIS_661) && (ivideo->vbflags2 & VB2_CONEXANT)) {
2898 printk(KERN_INFO "%s Conexant external device\n", stdstr);
2899 }
2900 }
2901
2902 if(ivideo->vbflags2 & VB2_SISBRIDGE) {
2903 SiS_SenseLCD(ivideo);
2904 SiS_Sense30x(ivideo);
2905 } else if(ivideo->vbflags2 & VB2_CHRONTEL) {
2906 SiS_SenseCh(ivideo);
2907 }
2908}
2909
2910/* ---------- Engine initialization routines ------------ */
2911
2912static void
2913sisfb_engine_init(struct sis_video_info *ivideo)
2914{
2915
2916 /* Initialize command queue (we use MMIO only) */
2917
2918 /* BEFORE THIS IS CALLED, THE ENGINES *MUST* BE SYNC'ED */
2919
2920 ivideo->caps &= ~(TURBO_QUEUE_CAP |
2921 MMIO_CMD_QUEUE_CAP |
2922 VM_CMD_QUEUE_CAP |
2923 AGP_CMD_QUEUE_CAP);
2924
2925#ifdef CONFIG_FB_SIS_300
2926 if(ivideo->sisvga_engine == SIS_300_VGA) {
2927 u32 tqueue_pos;
2928 u8 tq_state;
2929
2930 tqueue_pos = (ivideo->video_size - ivideo->cmdQueueSize) / (64 * 1024);
2931
2932 inSISIDXREG(SISSR, IND_SIS_TURBOQUEUE_SET, tq_state);
2933 tq_state |= 0xf0;
2934 tq_state &= 0xfc;
2935 tq_state |= (u8)(tqueue_pos >> 8);
2936 outSISIDXREG(SISSR, IND_SIS_TURBOQUEUE_SET, tq_state);
2937
2938 outSISIDXREG(SISSR, IND_SIS_TURBOQUEUE_ADR, (u8)(tqueue_pos & 0xff));
2939
2940 ivideo->caps |= TURBO_QUEUE_CAP;
2941 }
2942#endif
2943
2944#ifdef CONFIG_FB_SIS_315
2945 if(ivideo->sisvga_engine == SIS_315_VGA) {
2946 u32 tempq = 0, templ;
2947 u8 temp;
2948
2949 if(ivideo->chip == XGI_20) {
2950 switch(ivideo->cmdQueueSize) {
2951 case (64 * 1024):
2952 temp = SIS_CMD_QUEUE_SIZE_Z7_64k;
2953 break;
2954 case (128 * 1024):
2955 default:
2956 temp = SIS_CMD_QUEUE_SIZE_Z7_128k;
2957 }
2958 } else {
2959 switch(ivideo->cmdQueueSize) {
2960 case (4 * 1024 * 1024):
2961 temp = SIS_CMD_QUEUE_SIZE_4M;
2962 break;
2963 case (2 * 1024 * 1024):
2964 temp = SIS_CMD_QUEUE_SIZE_2M;
2965 break;
2966 case (1 * 1024 * 1024):
2967 temp = SIS_CMD_QUEUE_SIZE_1M;
2968 break;
2969 default:
2970 case (512 * 1024):
2971 temp = SIS_CMD_QUEUE_SIZE_512k;
2972 }
2973 }
2974
2975 outSISIDXREG(SISSR, IND_SIS_CMDQUEUE_THRESHOLD, COMMAND_QUEUE_THRESHOLD);
2976 outSISIDXREG(SISSR, IND_SIS_CMDQUEUE_SET, SIS_CMD_QUEUE_RESET);
2977
2978 if((ivideo->chip >= XGI_40) && ivideo->modechanged) {
2979 /* Must disable dual pipe on XGI_40. Can't do
2980 * this in MMIO mode, because it requires
2981 * setting/clearing a bit in the MMIO fire trigger
2982 * register.
2983 */
2984 if(!((templ = MMIO_IN32(ivideo->mmio_vbase, 0x8240)) & (1 << 10))) {
2985
2986 MMIO_OUT32(ivideo->mmio_vbase, Q_WRITE_PTR, 0);
2987
2988 outSISIDXREG(SISSR, IND_SIS_CMDQUEUE_SET, (temp | SIS_VRAM_CMDQUEUE_ENABLE));
2989
2990 tempq = MMIO_IN32(ivideo->mmio_vbase, Q_READ_PTR);
2991 MMIO_OUT32(ivideo->mmio_vbase, Q_WRITE_PTR, tempq);
2992
2993 tempq = (u32)(ivideo->video_size - ivideo->cmdQueueSize);
2994 MMIO_OUT32(ivideo->mmio_vbase, Q_BASE_ADDR, tempq);
2995
2996 writel(0x16800000 + 0x8240, ivideo->video_vbase + tempq);
2997 writel(templ | (1 << 10), ivideo->video_vbase + tempq + 4);
2998 writel(0x168F0000, ivideo->video_vbase + tempq + 8);
2999 writel(0x168F0000, ivideo->video_vbase + tempq + 12);
3000
3001 MMIO_OUT32(ivideo->mmio_vbase, Q_WRITE_PTR, (tempq + 16));
3002
3003 sisfb_syncaccel(ivideo);
3004
3005 outSISIDXREG(SISSR, IND_SIS_CMDQUEUE_SET, SIS_CMD_QUEUE_RESET);
3006
3007 }
3008 }
3009
3010 tempq = MMIO_IN32(ivideo->mmio_vbase, MMIO_QUEUE_READPORT);
3011 MMIO_OUT32(ivideo->mmio_vbase, MMIO_QUEUE_WRITEPORT, tempq);
3012
3013 temp |= (SIS_MMIO_CMD_ENABLE | SIS_CMD_AUTO_CORR);
3014 outSISIDXREG(SISSR, IND_SIS_CMDQUEUE_SET, temp);
3015
3016 tempq = (u32)(ivideo->video_size - ivideo->cmdQueueSize);
3017 MMIO_OUT32(ivideo->mmio_vbase, MMIO_QUEUE_PHYBASE, tempq);
3018
3019 ivideo->caps |= MMIO_CMD_QUEUE_CAP;
3020 }
3021#endif
3022
3023 ivideo->engineok = 1;
3024}
3025
3026static void __devinit
3027sisfb_detect_lcd_type(struct sis_video_info *ivideo)
3028{
3029 u8 reg;
3030 int i;
3031
3032 inSISIDXREG(SISCR, 0x36, reg);
3033 reg &= 0x0f;
3034 if(ivideo->sisvga_engine == SIS_300_VGA) {
3035 ivideo->CRT2LCDType = sis300paneltype[reg];
3036 } else if(ivideo->chip >= SIS_661) {
3037 ivideo->CRT2LCDType = sis661paneltype[reg];
3038 } else {
3039 ivideo->CRT2LCDType = sis310paneltype[reg];
3040 if((ivideo->chip == SIS_550) && (sisfb_fstn)) {
3041 if((ivideo->CRT2LCDType != LCD_320x240_2) &&
3042 (ivideo->CRT2LCDType != LCD_320x240_3)) {
3043 ivideo->CRT2LCDType = LCD_320x240;
3044 }
3045 }
3046 }
3047
3048 if(ivideo->CRT2LCDType == LCD_UNKNOWN) {
3049 /* For broken BIOSes: Assume 1024x768, RGB18 */
3050 ivideo->CRT2LCDType = LCD_1024x768;
3051 setSISIDXREG(SISCR,0x36,0xf0,0x02);
3052 setSISIDXREG(SISCR,0x37,0xee,0x01);
3053 printk(KERN_DEBUG "sisfb: Invalid panel ID (%02x), assuming 1024x768, RGB18\n", reg);
3054 }
3055
3056 for(i = 0; i < SIS_LCD_NUMBER; i++) {
3057 if(ivideo->CRT2LCDType == sis_lcd_data[i].lcdtype) {
3058 ivideo->lcdxres = sis_lcd_data[i].xres;
3059 ivideo->lcdyres = sis_lcd_data[i].yres;
3060 ivideo->lcddefmodeidx = sis_lcd_data[i].default_mode_idx;
3061 break;
3062 }
3063 }
3064
3065#ifdef CONFIG_FB_SIS_300
3066 if(ivideo->SiS_Pr.SiS_CustomT == CUT_BARCO1366) {
3067 ivideo->lcdxres = 1360; ivideo->lcdyres = 1024;
3068 ivideo->lcddefmodeidx = DEFAULT_MODE_1360;
3069 } else if(ivideo->SiS_Pr.SiS_CustomT == CUT_PANEL848) {
3070 ivideo->lcdxres = 848; ivideo->lcdyres = 480;
3071 ivideo->lcddefmodeidx = DEFAULT_MODE_848;
3072 } else if(ivideo->SiS_Pr.SiS_CustomT == CUT_PANEL856) {
3073 ivideo->lcdxres = 856; ivideo->lcdyres = 480;
3074 ivideo->lcddefmodeidx = DEFAULT_MODE_856;
3075 }
3076#endif
3077
3078 printk(KERN_DEBUG "sisfb: Detected %dx%d flat panel\n",
3079 ivideo->lcdxres, ivideo->lcdyres);
3080}
3081
3082static void __devinit
3083sisfb_save_pdc_emi(struct sis_video_info *ivideo)
3084{
3085#ifdef CONFIG_FB_SIS_300
3086 /* Save the current PanelDelayCompensation if the LCD is currently used */
3087 if(ivideo->sisvga_engine == SIS_300_VGA) {
3088 if(ivideo->vbflags2 & (VB2_LVDS | VB2_30xBDH)) {
3089 int tmp;
3090 inSISIDXREG(SISCR,0x30,tmp);
3091 if(tmp & 0x20) {
3092 /* Currently on LCD? If yes, read current pdc */
3093 inSISIDXREG(SISPART1,0x13,ivideo->detectedpdc);
3094 ivideo->detectedpdc &= 0x3c;
3095 if(ivideo->SiS_Pr.PDC == -1) {
3096 /* Let option override detection */
3097 ivideo->SiS_Pr.PDC = ivideo->detectedpdc;
3098 }
3099 printk(KERN_INFO "sisfb: Detected LCD PDC 0x%02x\n",
3100 ivideo->detectedpdc);
3101 }
3102 if((ivideo->SiS_Pr.PDC != -1) &&
3103 (ivideo->SiS_Pr.PDC != ivideo->detectedpdc)) {
3104 printk(KERN_INFO "sisfb: Using LCD PDC 0x%02x\n",
3105 ivideo->SiS_Pr.PDC);
3106 }
3107 }
3108 }
3109#endif
3110
3111#ifdef CONFIG_FB_SIS_315
3112 if(ivideo->sisvga_engine == SIS_315_VGA) {
3113
3114 /* Try to find about LCDA */
3115 if(ivideo->vbflags2 & VB2_SISLCDABRIDGE) {
3116 int tmp;
3117 inSISIDXREG(SISPART1,0x13,tmp);
3118 if(tmp & 0x04) {
3119 ivideo->SiS_Pr.SiS_UseLCDA = TRUE;
3120 ivideo->detectedlcda = 0x03;
3121 }
3122 }
3123
3124 /* Save PDC */
3125 if(ivideo->vbflags2 & VB2_SISLVDSBRIDGE) {
3126 int tmp;
3127 inSISIDXREG(SISCR,0x30,tmp);
3128 if((tmp & 0x20) || (ivideo->detectedlcda != 0xff)) {
3129 /* Currently on LCD? If yes, read current pdc */
3130 u8 pdc;
3131 inSISIDXREG(SISPART1,0x2D,pdc);
3132 ivideo->detectedpdc = (pdc & 0x0f) << 1;
3133 ivideo->detectedpdca = (pdc & 0xf0) >> 3;
3134 inSISIDXREG(SISPART1,0x35,pdc);
3135 ivideo->detectedpdc |= ((pdc >> 7) & 0x01);
3136 inSISIDXREG(SISPART1,0x20,pdc);
3137 ivideo->detectedpdca |= ((pdc >> 6) & 0x01);
3138 if(ivideo->newrom) {
3139 /* New ROM invalidates other PDC resp. */
3140 if(ivideo->detectedlcda != 0xff) {
3141 ivideo->detectedpdc = 0xff;
3142 } else {
3143 ivideo->detectedpdca = 0xff;
3144 }
3145 }
3146 if(ivideo->SiS_Pr.PDC == -1) {
3147 if(ivideo->detectedpdc != 0xff) {
3148 ivideo->SiS_Pr.PDC = ivideo->detectedpdc;
3149 }
3150 }
3151 if(ivideo->SiS_Pr.PDCA == -1) {
3152 if(ivideo->detectedpdca != 0xff) {
3153 ivideo->SiS_Pr.PDCA = ivideo->detectedpdca;
3154 }
3155 }
3156 if(ivideo->detectedpdc != 0xff) {
3157 printk(KERN_INFO
3158 "sisfb: Detected LCD PDC 0x%02x (for LCD=CRT2)\n",
3159 ivideo->detectedpdc);
3160 }
3161 if(ivideo->detectedpdca != 0xff) {
3162 printk(KERN_INFO
3163 "sisfb: Detected LCD PDC1 0x%02x (for LCD=CRT1)\n",
3164 ivideo->detectedpdca);
3165 }
3166 }
3167
3168 /* Save EMI */
3169 if(ivideo->vbflags2 & VB2_SISEMIBRIDGE) {
3170 inSISIDXREG(SISPART4,0x30,ivideo->SiS_Pr.EMI_30);
3171 inSISIDXREG(SISPART4,0x31,ivideo->SiS_Pr.EMI_31);
3172 inSISIDXREG(SISPART4,0x32,ivideo->SiS_Pr.EMI_32);
3173 inSISIDXREG(SISPART4,0x33,ivideo->SiS_Pr.EMI_33);
3174 ivideo->SiS_Pr.HaveEMI = TRUE;
3175 if((tmp & 0x20) || (ivideo->detectedlcda != 0xff)) {
3176 ivideo->SiS_Pr.HaveEMILCD = TRUE;
3177 }
3178 }
3179 }
3180
3181 /* Let user override detected PDCs (all bridges) */
3182 if(ivideo->vbflags2 & VB2_30xBLV) {
3183 if((ivideo->SiS_Pr.PDC != -1) &&
3184 (ivideo->SiS_Pr.PDC != ivideo->detectedpdc)) {
3185 printk(KERN_INFO "sisfb: Using LCD PDC 0x%02x (for LCD=CRT2)\n",
3186 ivideo->SiS_Pr.PDC);
3187 }
3188 if((ivideo->SiS_Pr.PDCA != -1) &&
3189 (ivideo->SiS_Pr.PDCA != ivideo->detectedpdca)) {
3190 printk(KERN_INFO "sisfb: Using LCD PDC1 0x%02x (for LCD=CRT1)\n",
3191 ivideo->SiS_Pr.PDCA);
3192 }
3193 }
3194
3195 }
3196#endif
3197}
3198
3199/* -------------------- Memory manager routines ---------------------- */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003200
3201static u32 __devinit
3202sisfb_getheapstart(struct sis_video_info *ivideo)
3203{
3204 u32 ret = ivideo->sisfb_parm_mem * 1024;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003205 u32 maxoffs = ivideo->video_size - ivideo->hwcursor_size - ivideo->cmdQueueSize;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003206 u32 def;
3207
3208 /* Calculate heap start = end of memory for console
3209 *
3210 * CCCCCCCCDDDDDDDDDDDDDDDDDDDDDDDDDDDDHHHHQQQQQQQQQQ
3211 * C = console, D = heap, H = HWCursor, Q = cmd-queue
3212 *
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003213 * On 76x in UMA+LFB mode, the layout is as follows:
3214 * DDDDDDDDDDDCCCCCCCCCCCCCCCCCCCCCCCCHHHHQQQQQQQQQQQ
3215 * where the heap is the entire UMA area, eventually
3216 * into the LFB area if the given mem parameter is
3217 * higher than the size of the UMA memory.
3218 *
Linus Torvalds1da177e2005-04-16 15:20:36 -07003219 * Basically given by "mem" parameter
3220 *
3221 * maximum = videosize - cmd_queue - hwcursor
3222 * (results in a heap of size 0)
3223 * default = SiS 300: depends on videosize
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003224 * SiS 315/330/340/XGI: 32k below max
Linus Torvalds1da177e2005-04-16 15:20:36 -07003225 */
3226
3227 if(ivideo->sisvga_engine == SIS_300_VGA) {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003228 if(ivideo->video_size > 0x1000000) {
3229 def = 0xc00000;
3230 } else if(ivideo->video_size > 0x800000) {
3231 def = 0x800000;
3232 } else {
3233 def = 0x400000;
3234 }
3235 } else if(ivideo->UMAsize && ivideo->LFBsize) {
3236 ret = def = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003237 } else {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003238 def = maxoffs - 0x8000;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003239 }
3240
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003241 /* Use default for secondary card for now (FIXME) */
3242 if((!ret) || (ret > maxoffs) || (ivideo->cardnumber != 0))
3243 ret = def;
3244
3245 return ret;
3246}
3247
3248static u32 __devinit
3249sisfb_getheapsize(struct sis_video_info *ivideo)
3250{
3251 u32 max = ivideo->video_size - ivideo->hwcursor_size - ivideo->cmdQueueSize;
3252 u32 ret = 0;
3253
3254 if(ivideo->UMAsize && ivideo->LFBsize) {
3255 if( (!ivideo->sisfb_parm_mem) ||
3256 ((ivideo->sisfb_parm_mem * 1024) > max) ||
3257 ((max - (ivideo->sisfb_parm_mem * 1024)) < ivideo->UMAsize) ) {
3258 ret = ivideo->UMAsize;
3259 max -= ivideo->UMAsize;
3260 } else {
3261 ret = max - (ivideo->sisfb_parm_mem * 1024);
3262 max = ivideo->sisfb_parm_mem * 1024;
3263 }
3264 ivideo->video_offset = ret;
3265 ivideo->sisfb_mem = max;
3266 } else {
3267 ret = max - ivideo->heapstart;
3268 ivideo->sisfb_mem = ivideo->heapstart;
3269 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003270
3271 return ret;
3272}
3273
3274static int __devinit
3275sisfb_heap_init(struct sis_video_info *ivideo)
3276{
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003277 struct SIS_OH *poh;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003278
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003279 ivideo->video_offset = 0;
3280 if(ivideo->sisfb_parm_mem) {
3281 if( (ivideo->sisfb_parm_mem < (2 * 1024 * 1024)) ||
3282 (ivideo->sisfb_parm_mem > ivideo->video_size) ) {
3283 ivideo->sisfb_parm_mem = 0;
3284 }
3285 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003286
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003287 ivideo->heapstart = sisfb_getheapstart(ivideo);
3288 ivideo->sisfb_heap_size = sisfb_getheapsize(ivideo);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003289
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003290 ivideo->sisfb_heap_start = ivideo->video_vbase + ivideo->heapstart;
3291 ivideo->sisfb_heap_end = ivideo->sisfb_heap_start + ivideo->sisfb_heap_size;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003292
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003293 printk(KERN_INFO "sisfb: Memory heap starting at %dK, size %dK\n",
3294 (int)(ivideo->heapstart / 1024), (int)(ivideo->sisfb_heap_size / 1024));
Linus Torvalds1da177e2005-04-16 15:20:36 -07003295
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003296 ivideo->sisfb_heap.vinfo = ivideo;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003297
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003298 ivideo->sisfb_heap.poha_chain = NULL;
3299 ivideo->sisfb_heap.poh_freelist = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003300
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003301 poh = sisfb_poh_new_node(&ivideo->sisfb_heap);
3302 if(poh == NULL)
3303 return 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003304
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003305 poh->poh_next = &ivideo->sisfb_heap.oh_free;
3306 poh->poh_prev = &ivideo->sisfb_heap.oh_free;
3307 poh->size = ivideo->sisfb_heap_size;
3308 poh->offset = ivideo->heapstart;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003309
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003310 ivideo->sisfb_heap.oh_free.poh_next = poh;
3311 ivideo->sisfb_heap.oh_free.poh_prev = poh;
3312 ivideo->sisfb_heap.oh_free.size = 0;
3313 ivideo->sisfb_heap.max_freesize = poh->size;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003314
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003315 ivideo->sisfb_heap.oh_used.poh_next = &ivideo->sisfb_heap.oh_used;
3316 ivideo->sisfb_heap.oh_used.poh_prev = &ivideo->sisfb_heap.oh_used;
3317 ivideo->sisfb_heap.oh_used.size = SENTINEL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003318
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003319 if(ivideo->cardnumber == 0) {
3320 /* For the first card, make this heap the "global" one
3321 * for old DRM (which could handle only one card)
3322 */
3323 sisfb_heap = &ivideo->sisfb_heap;
3324 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003325
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003326 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003327}
3328
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003329static struct SIS_OH *
3330sisfb_poh_new_node(struct SIS_HEAP *memheap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003331{
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003332 struct SIS_OHALLOC *poha;
3333 struct SIS_OH *poh;
3334 unsigned long cOhs;
3335 int i;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003336
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003337 if(memheap->poh_freelist == NULL) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003338 poha = kmalloc(SIS_OH_ALLOC_SIZE, GFP_KERNEL);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003339 if(!poha)
3340 return NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003341
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003342 poha->poha_next = memheap->poha_chain;
3343 memheap->poha_chain = poha;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003344
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003345 cOhs = (SIS_OH_ALLOC_SIZE - sizeof(struct SIS_OHALLOC)) / sizeof(struct SIS_OH) + 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003346
3347 poh = &poha->aoh[0];
3348 for(i = cOhs - 1; i != 0; i--) {
3349 poh->poh_next = poh + 1;
3350 poh = poh + 1;
3351 }
3352
3353 poh->poh_next = NULL;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003354 memheap->poh_freelist = &poha->aoh[0];
Linus Torvalds1da177e2005-04-16 15:20:36 -07003355 }
3356
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003357 poh = memheap->poh_freelist;
3358 memheap->poh_freelist = poh->poh_next;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003359
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003360 return poh;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003361}
3362
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003363static struct SIS_OH *
3364sisfb_poh_allocate(struct SIS_HEAP *memheap, u32 size)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003365{
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003366 struct SIS_OH *pohThis;
3367 struct SIS_OH *pohRoot;
3368 int bAllocated = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003369
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003370 if(size > memheap->max_freesize) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003371 DPRINTK("sisfb: Can't allocate %dk video memory\n",
3372 (unsigned int) size / 1024);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003373 return NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003374 }
3375
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003376 pohThis = memheap->oh_free.poh_next;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003377
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003378 while(pohThis != &memheap->oh_free) {
3379 if(size <= pohThis->size) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003380 bAllocated = 1;
3381 break;
3382 }
3383 pohThis = pohThis->poh_next;
3384 }
3385
3386 if(!bAllocated) {
3387 DPRINTK("sisfb: Can't allocate %dk video memory\n",
3388 (unsigned int) size / 1024);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003389 return NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003390 }
3391
3392 if(size == pohThis->size) {
3393 pohRoot = pohThis;
3394 sisfb_delete_node(pohThis);
3395 } else {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003396 pohRoot = sisfb_poh_new_node(memheap);
3397 if(pohRoot == NULL)
3398 return NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003399
3400 pohRoot->offset = pohThis->offset;
3401 pohRoot->size = size;
3402
3403 pohThis->offset += size;
3404 pohThis->size -= size;
3405 }
3406
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003407 memheap->max_freesize -= size;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003408
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003409 pohThis = &memheap->oh_used;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003410 sisfb_insert_node(pohThis, pohRoot);
3411
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003412 return pohRoot;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003413}
3414
3415static void
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003416sisfb_delete_node(struct SIS_OH *poh)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003417{
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003418 poh->poh_prev->poh_next = poh->poh_next;
3419 poh->poh_next->poh_prev = poh->poh_prev;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003420}
3421
3422static void
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003423sisfb_insert_node(struct SIS_OH *pohList, struct SIS_OH *poh)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003424{
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003425 struct SIS_OH *pohTemp = pohList->poh_next;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003426
3427 pohList->poh_next = poh;
3428 pohTemp->poh_prev = poh;
3429
3430 poh->poh_prev = pohList;
3431 poh->poh_next = pohTemp;
3432}
3433
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003434static struct SIS_OH *
3435sisfb_poh_free(struct SIS_HEAP *memheap, u32 base)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003436{
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003437 struct SIS_OH *pohThis;
3438 struct SIS_OH *poh_freed;
3439 struct SIS_OH *poh_prev;
3440 struct SIS_OH *poh_next;
3441 u32 ulUpper;
3442 u32 ulLower;
3443 int foundNode = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003444
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003445 poh_freed = memheap->oh_used.poh_next;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003446
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003447 while(poh_freed != &memheap->oh_used) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003448 if(poh_freed->offset == base) {
3449 foundNode = 1;
3450 break;
3451 }
3452
3453 poh_freed = poh_freed->poh_next;
3454 }
3455
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003456 if(!foundNode)
3457 return NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003458
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003459 memheap->max_freesize += poh_freed->size;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003460
3461 poh_prev = poh_next = NULL;
3462 ulUpper = poh_freed->offset + poh_freed->size;
3463 ulLower = poh_freed->offset;
3464
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003465 pohThis = memheap->oh_free.poh_next;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003466
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003467 while(pohThis != &memheap->oh_free) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003468 if(pohThis->offset == ulUpper) {
3469 poh_next = pohThis;
3470 } else if((pohThis->offset + pohThis->size) == ulLower) {
3471 poh_prev = pohThis;
3472 }
3473 pohThis = pohThis->poh_next;
3474 }
3475
3476 sisfb_delete_node(poh_freed);
3477
3478 if(poh_prev && poh_next) {
3479 poh_prev->size += (poh_freed->size + poh_next->size);
3480 sisfb_delete_node(poh_next);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003481 sisfb_free_node(memheap, poh_freed);
3482 sisfb_free_node(memheap, poh_next);
3483 return poh_prev;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003484 }
3485
3486 if(poh_prev) {
3487 poh_prev->size += poh_freed->size;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003488 sisfb_free_node(memheap, poh_freed);
3489 return poh_prev;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003490 }
3491
3492 if(poh_next) {
3493 poh_next->size += poh_freed->size;
3494 poh_next->offset = poh_freed->offset;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003495 sisfb_free_node(memheap, poh_freed);
3496 return poh_next;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003497 }
3498
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003499 sisfb_insert_node(&memheap->oh_free, poh_freed);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003500
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003501 return poh_freed;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003502}
3503
3504static void
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003505sisfb_free_node(struct SIS_HEAP *memheap, struct SIS_OH *poh)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003506{
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003507 if(poh == NULL)
3508 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003509
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003510 poh->poh_next = memheap->poh_freelist;
3511 memheap->poh_freelist = poh;
3512}
3513
3514static void
3515sis_int_malloc(struct sis_video_info *ivideo, struct sis_memreq *req)
3516{
3517 struct SIS_OH *poh = NULL;
3518
3519 if((ivideo) && (ivideo->sisfb_id == SISFB_ID) && (!ivideo->havenoheap))
3520 poh = sisfb_poh_allocate(&ivideo->sisfb_heap, (u32)req->size);
3521
3522 if(poh == NULL) {
3523 req->offset = req->size = 0;
3524 DPRINTK("sisfb: Video RAM allocation failed\n");
3525 } else {
3526 req->offset = poh->offset;
3527 req->size = poh->size;
3528 DPRINTK("sisfb: Video RAM allocation succeeded: 0x%lx\n",
3529 (poh->offset + ivideo->video_vbase));
3530 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003531}
3532
3533void
3534sis_malloc(struct sis_memreq *req)
3535{
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003536 struct sis_video_info *ivideo = sisfb_heap->vinfo;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003537
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003538 if(&ivideo->sisfb_heap == sisfb_heap)
3539 sis_int_malloc(ivideo, req);
3540 else
3541 req->offset = req->size = 0;
3542}
Linus Torvalds1da177e2005-04-16 15:20:36 -07003543
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003544void
3545sis_malloc_new(struct pci_dev *pdev, struct sis_memreq *req)
3546{
3547 struct sis_video_info *ivideo = pci_get_drvdata(pdev);
3548
3549 sis_int_malloc(ivideo, req);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003550}
3551
3552/* sis_free: u32 because "base" is offset inside video ram, can never be >4GB */
3553
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003554static void
3555sis_int_free(struct sis_video_info *ivideo, u32 base)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003556{
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003557 struct SIS_OH *poh;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003558
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003559 if((!ivideo) || (ivideo->sisfb_id != SISFB_ID) || (ivideo->havenoheap))
3560 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003561
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003562 poh = sisfb_poh_free(&ivideo->sisfb_heap, base);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003563
3564 if(poh == NULL) {
3565 DPRINTK("sisfb: sisfb_poh_free() failed at base 0x%x\n",
3566 (unsigned int) base);
3567 }
3568}
3569
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003570void
3571sis_free(u32 base)
3572{
3573 struct sis_video_info *ivideo = sisfb_heap->vinfo;
3574
3575 sis_int_free(ivideo, base);
3576}
3577
3578void
3579sis_free_new(struct pci_dev *pdev, u32 base)
3580{
3581 struct sis_video_info *ivideo = pci_get_drvdata(pdev);
3582
3583 sis_int_free(ivideo, base);
3584}
3585
Linus Torvalds1da177e2005-04-16 15:20:36 -07003586/* --------------------- SetMode routines ------------------------- */
3587
3588static void
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003589sisfb_check_engine_and_sync(struct sis_video_info *ivideo)
3590{
3591 u8 cr30, cr31;
3592
3593 /* Check if MMIO and engines are enabled,
3594 * and sync in case they are. Can't use
3595 * ivideo->accel here, as this might have
3596 * been changed before this is called.
3597 */
3598 inSISIDXREG(SISSR, IND_SIS_PCI_ADDRESS_SET, cr30);
3599 inSISIDXREG(SISSR, IND_SIS_MODULE_ENABLE, cr31);
3600 /* MMIO and 2D/3D engine enabled? */
3601 if((cr30 & SIS_MEM_MAP_IO_ENABLE) && (cr31 & 0x42)) {
3602#ifdef CONFIG_FB_SIS_300
3603 if(ivideo->sisvga_engine == SIS_300_VGA) {
3604 /* Don't care about TurboQueue. It's
3605 * enough to know that the engines
3606 * are enabled
3607 */
3608 sisfb_syncaccel(ivideo);
3609 }
3610#endif
3611#ifdef CONFIG_FB_SIS_315
3612 if(ivideo->sisvga_engine == SIS_315_VGA) {
3613 /* Check that any queue mode is
3614 * enabled, and that the queue
3615 * is not in the state of "reset"
3616 */
3617 inSISIDXREG(SISSR, 0x26, cr30);
3618 if((cr30 & 0xe0) && (!(cr30 & 0x01))) {
3619 sisfb_syncaccel(ivideo);
3620 }
3621 }
3622#endif
3623 }
3624}
3625
3626static void
Linus Torvalds1da177e2005-04-16 15:20:36 -07003627sisfb_pre_setmode(struct sis_video_info *ivideo)
3628{
3629 u8 cr30 = 0, cr31 = 0, cr33 = 0, cr35 = 0, cr38 = 0;
3630 int tvregnum = 0;
3631
3632 ivideo->currentvbflags &= (VB_VIDEOBRIDGE | VB_DISPTYPE_DISP2);
3633
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003634 outSISIDXREG(SISSR, 0x05, 0x86);
3635
Linus Torvalds1da177e2005-04-16 15:20:36 -07003636 inSISIDXREG(SISCR, 0x31, cr31);
3637 cr31 &= ~0x60;
3638 cr31 |= 0x04;
3639
3640 cr33 = ivideo->rate_idx & 0x0F;
3641
3642#ifdef CONFIG_FB_SIS_315
3643 if(ivideo->sisvga_engine == SIS_315_VGA) {
3644 if(ivideo->chip >= SIS_661) {
3645 inSISIDXREG(SISCR, 0x38, cr38);
3646 cr38 &= ~0x07; /* Clear LCDA/DualEdge and YPbPr bits */
3647 } else {
3648 tvregnum = 0x38;
3649 inSISIDXREG(SISCR, tvregnum, cr38);
3650 cr38 &= ~0x3b; /* Clear LCDA/DualEdge and YPbPr bits */
3651 }
3652 }
3653#endif
3654#ifdef CONFIG_FB_SIS_300
3655 if(ivideo->sisvga_engine == SIS_300_VGA) {
3656 tvregnum = 0x35;
3657 inSISIDXREG(SISCR, tvregnum, cr38);
3658 }
3659#endif
3660
3661 SiS_SetEnableDstn(&ivideo->SiS_Pr, FALSE);
3662 SiS_SetEnableFstn(&ivideo->SiS_Pr, FALSE);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003663 ivideo->curFSTN = ivideo->curDSTN = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003664
3665 switch(ivideo->currentvbflags & VB_DISPTYPE_DISP2) {
3666
3667 case CRT2_TV:
3668 cr38 &= ~0xc0; /* Clear PAL-M / PAL-N bits */
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003669 if((ivideo->vbflags & TV_YPBPR) && (ivideo->vbflags2 & VB2_SISYPBPRBRIDGE)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003670#ifdef CONFIG_FB_SIS_315
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003671 if(ivideo->chip >= SIS_661) {
3672 cr38 |= 0x04;
3673 if(ivideo->vbflags & TV_YPBPR525P) cr35 |= 0x20;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003674 else if(ivideo->vbflags & TV_YPBPR750P) cr35 |= 0x40;
3675 else if(ivideo->vbflags & TV_YPBPR1080I) cr35 |= 0x60;
3676 cr30 |= SIS_SIMULTANEOUS_VIEW_ENABLE;
3677 cr35 &= ~0x01;
3678 ivideo->currentvbflags |= (TV_YPBPR | (ivideo->vbflags & TV_YPBPRALL));
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003679 } else if(ivideo->sisvga_engine == SIS_315_VGA) {
3680 cr30 |= (0x80 | SIS_SIMULTANEOUS_VIEW_ENABLE);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003681 cr38 |= 0x08;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003682 if(ivideo->vbflags & TV_YPBPR525P) cr38 |= 0x10;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003683 else if(ivideo->vbflags & TV_YPBPR750P) cr38 |= 0x20;
3684 else if(ivideo->vbflags & TV_YPBPR1080I) cr38 |= 0x30;
3685 cr31 &= ~0x01;
3686 ivideo->currentvbflags |= (TV_YPBPR | (ivideo->vbflags & TV_YPBPRALL));
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003687 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003688#endif
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003689 } else if((ivideo->vbflags & TV_HIVISION) &&
3690 (ivideo->vbflags2 & VB2_SISHIVISIONBRIDGE)) {
3691 if(ivideo->chip >= SIS_661) {
3692 cr38 |= 0x04;
3693 cr35 |= 0x60;
3694 } else {
3695 cr30 |= 0x80;
3696 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003697 cr30 |= SIS_SIMULTANEOUS_VIEW_ENABLE;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003698 cr31 |= 0x01;
3699 cr35 |= 0x01;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003700 ivideo->currentvbflags |= TV_HIVISION;
3701 } else if(ivideo->vbflags & TV_SCART) {
3702 cr30 = (SIS_VB_OUTPUT_SCART | SIS_SIMULTANEOUS_VIEW_ENABLE);
3703 cr31 |= 0x01;
3704 cr35 |= 0x01;
3705 ivideo->currentvbflags |= TV_SCART;
3706 } else {
3707 if(ivideo->vbflags & TV_SVIDEO) {
3708 cr30 = (SIS_VB_OUTPUT_SVIDEO | SIS_SIMULTANEOUS_VIEW_ENABLE);
3709 ivideo->currentvbflags |= TV_SVIDEO;
3710 }
3711 if(ivideo->vbflags & TV_AVIDEO) {
3712 cr30 = (SIS_VB_OUTPUT_COMPOSITE | SIS_SIMULTANEOUS_VIEW_ENABLE);
3713 ivideo->currentvbflags |= TV_AVIDEO;
3714 }
3715 }
3716 cr31 |= SIS_DRIVER_MODE;
3717
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003718 if(ivideo->vbflags & (TV_AVIDEO | TV_SVIDEO)) {
3719 if(ivideo->vbflags & TV_PAL) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003720 cr31 |= 0x01; cr35 |= 0x01;
3721 ivideo->currentvbflags |= TV_PAL;
3722 if(ivideo->vbflags & TV_PALM) {
3723 cr38 |= 0x40; cr35 |= 0x04;
3724 ivideo->currentvbflags |= TV_PALM;
3725 } else if(ivideo->vbflags & TV_PALN) {
3726 cr38 |= 0x80; cr35 |= 0x08;
3727 ivideo->currentvbflags |= TV_PALN;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003728 }
3729 } else {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003730 cr31 &= ~0x01; cr35 &= ~0x01;
3731 ivideo->currentvbflags |= TV_NTSC;
3732 if(ivideo->vbflags & TV_NTSCJ) {
3733 cr38 |= 0x40; cr35 |= 0x02;
3734 ivideo->currentvbflags |= TV_NTSCJ;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003735 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003736 }
3737 }
3738 break;
3739
3740 case CRT2_LCD:
3741 cr30 = (SIS_VB_OUTPUT_LCD | SIS_SIMULTANEOUS_VIEW_ENABLE);
3742 cr31 |= SIS_DRIVER_MODE;
3743 SiS_SetEnableDstn(&ivideo->SiS_Pr, ivideo->sisfb_dstn);
3744 SiS_SetEnableFstn(&ivideo->SiS_Pr, ivideo->sisfb_fstn);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003745 ivideo->curFSTN = ivideo->sisfb_fstn;
3746 ivideo->curDSTN = ivideo->sisfb_dstn;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003747 break;
3748
3749 case CRT2_VGA:
3750 cr30 = (SIS_VB_OUTPUT_CRT2 | SIS_SIMULTANEOUS_VIEW_ENABLE);
3751 cr31 |= SIS_DRIVER_MODE;
3752 if(ivideo->sisfb_nocrt2rate) {
3753 cr33 |= (sisbios_mode[ivideo->sisfb_mode_idx].rate_idx << 4);
3754 } else {
3755 cr33 |= ((ivideo->rate_idx & 0x0F) << 4);
3756 }
3757 break;
3758
3759 default: /* disable CRT2 */
3760 cr30 = 0x00;
3761 cr31 |= (SIS_DRIVER_MODE | SIS_VB_OUTPUT_DISABLE);
3762 }
3763
3764 outSISIDXREG(SISCR, 0x30, cr30);
3765 outSISIDXREG(SISCR, 0x33, cr33);
3766
3767 if(ivideo->chip >= SIS_661) {
3768#ifdef CONFIG_FB_SIS_315
3769 cr31 &= ~0x01; /* Clear PAL flag (now in CR35) */
3770 setSISIDXREG(SISCR, 0x35, ~0x10, cr35); /* Leave overscan bit alone */
3771 cr38 &= 0x07; /* Use only LCDA and HiVision/YPbPr bits */
3772 setSISIDXREG(SISCR, 0x38, 0xf8, cr38);
3773#endif
3774 } else if(ivideo->chip != SIS_300) {
3775 outSISIDXREG(SISCR, tvregnum, cr38);
3776 }
3777 outSISIDXREG(SISCR, 0x31, cr31);
3778
Linus Torvalds1da177e2005-04-16 15:20:36 -07003779 ivideo->SiS_Pr.SiS_UseOEM = ivideo->sisfb_useoem;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003780
3781 sisfb_check_engine_and_sync(ivideo);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003782}
3783
3784/* Fix SR11 for 661 and later */
3785#ifdef CONFIG_FB_SIS_315
3786static void
3787sisfb_fixup_SR11(struct sis_video_info *ivideo)
3788{
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003789 u8 tmpreg;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003790
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003791 if(ivideo->chip >= SIS_661) {
3792 inSISIDXREG(SISSR,0x11,tmpreg);
3793 if(tmpreg & 0x20) {
3794 inSISIDXREG(SISSR,0x3e,tmpreg);
3795 tmpreg = (tmpreg + 1) & 0xff;
3796 outSISIDXREG(SISSR,0x3e,tmpreg);
3797 inSISIDXREG(SISSR,0x11,tmpreg);
3798 }
3799 if(tmpreg & 0xf0) {
3800 andSISIDXREG(SISSR,0x11,0x0f);
3801 }
3802 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003803}
3804#endif
3805
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003806static void
3807sisfb_set_TVxposoffset(struct sis_video_info *ivideo, int val)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003808{
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003809 if(val > 32) val = 32;
3810 if(val < -32) val = -32;
3811 ivideo->tvxpos = val;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003812
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003813 if(ivideo->sisfblocked) return;
3814 if(!ivideo->modechanged) return;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003815
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003816 if(ivideo->currentvbflags & CRT2_TV) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003817
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003818 if(ivideo->vbflags2 & VB2_CHRONTEL) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003819
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003820 int x = ivideo->tvx;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003821
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003822 switch(ivideo->chronteltype) {
3823 case 1:
3824 x += val;
3825 if(x < 0) x = 0;
3826 outSISIDXREG(SISSR,0x05,0x86);
3827 SiS_SetCH700x(&ivideo->SiS_Pr, 0x0a, (x & 0xff));
3828 SiS_SetCH70xxANDOR(&ivideo->SiS_Pr, 0x08, ((x & 0x0100) >> 7), 0xFD);
3829 break;
3830 case 2:
3831 /* Not supported by hardware */
3832 break;
3833 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003834
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003835 } else if(ivideo->vbflags2 & VB2_SISBRIDGE) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003836
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003837 u8 p2_1f,p2_20,p2_2b,p2_42,p2_43;
3838 unsigned short temp;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003839
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003840 p2_1f = ivideo->p2_1f;
3841 p2_20 = ivideo->p2_20;
3842 p2_2b = ivideo->p2_2b;
3843 p2_42 = ivideo->p2_42;
3844 p2_43 = ivideo->p2_43;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003845
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003846 temp = p2_1f | ((p2_20 & 0xf0) << 4);
3847 temp += (val * 2);
3848 p2_1f = temp & 0xff;
3849 p2_20 = (temp & 0xf00) >> 4;
3850 p2_2b = ((p2_2b & 0x0f) + (val * 2)) & 0x0f;
3851 temp = p2_43 | ((p2_42 & 0xf0) << 4);
3852 temp += (val * 2);
3853 p2_43 = temp & 0xff;
3854 p2_42 = (temp & 0xf00) >> 4;
3855 outSISIDXREG(SISPART2,0x1f,p2_1f);
3856 setSISIDXREG(SISPART2,0x20,0x0F,p2_20);
3857 setSISIDXREG(SISPART2,0x2b,0xF0,p2_2b);
3858 setSISIDXREG(SISPART2,0x42,0x0F,p2_42);
3859 outSISIDXREG(SISPART2,0x43,p2_43);
3860 }
3861 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003862}
3863
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003864static void
3865sisfb_set_TVyposoffset(struct sis_video_info *ivideo, int val)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003866{
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003867 if(val > 32) val = 32;
3868 if(val < -32) val = -32;
3869 ivideo->tvypos = val;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003870
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003871 if(ivideo->sisfblocked) return;
3872 if(!ivideo->modechanged) return;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003873
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003874 if(ivideo->currentvbflags & CRT2_TV) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003875
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003876 if(ivideo->vbflags2 & VB2_CHRONTEL) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003877
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003878 int y = ivideo->tvy;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003879
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003880 switch(ivideo->chronteltype) {
3881 case 1:
3882 y -= val;
3883 if(y < 0) y = 0;
3884 outSISIDXREG(SISSR,0x05,0x86);
3885 SiS_SetCH700x(&ivideo->SiS_Pr, 0x0b, (y & 0xff));
3886 SiS_SetCH70xxANDOR(&ivideo->SiS_Pr, 0x08, ((y & 0x0100) >> 8), 0xFE);
3887 break;
3888 case 2:
3889 /* Not supported by hardware */
3890 break;
3891 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003892
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003893 } else if(ivideo->vbflags2 & VB2_SISBRIDGE) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003894
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003895 char p2_01, p2_02;
3896 val /= 2;
3897 p2_01 = ivideo->p2_01;
3898 p2_02 = ivideo->p2_02;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003899
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003900 p2_01 += val;
3901 p2_02 += val;
3902 if(!(ivideo->currentvbflags & (TV_HIVISION | TV_YPBPR))) {
3903 while((p2_01 <= 0) || (p2_02 <= 0)) {
3904 p2_01 += 2;
3905 p2_02 += 2;
3906 }
3907 }
3908 outSISIDXREG(SISPART2,0x01,p2_01);
3909 outSISIDXREG(SISPART2,0x02,p2_02);
3910 }
3911 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003912}
3913
3914static void
3915sisfb_post_setmode(struct sis_video_info *ivideo)
3916{
3917 BOOLEAN crt1isoff = FALSE;
3918 BOOLEAN doit = TRUE;
3919#if defined(CONFIG_FB_SIS_300) || defined(CONFIG_FB_SIS_315)
3920 u8 reg;
3921#endif
3922#ifdef CONFIG_FB_SIS_315
3923 u8 reg1;
3924#endif
3925
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003926 outSISIDXREG(SISSR, 0x05, 0x86);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003927
3928#ifdef CONFIG_FB_SIS_315
3929 sisfb_fixup_SR11(ivideo);
3930#endif
3931
3932 /* Now we actually HAVE changed the display mode */
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003933 ivideo->modechanged = 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003934
3935 /* We can't switch off CRT1 if bridge is in slave mode */
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003936 if(ivideo->vbflags2 & VB2_VIDEOBRIDGE) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003937 if(sisfb_bridgeisslave(ivideo)) doit = FALSE;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003938 } else
3939 ivideo->sisfb_crt1off = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003940
3941#ifdef CONFIG_FB_SIS_300
3942 if(ivideo->sisvga_engine == SIS_300_VGA) {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003943 if((ivideo->sisfb_crt1off) && (doit)) {
3944 crt1isoff = TRUE;
3945 reg = 0x00;
3946 } else {
3947 crt1isoff = FALSE;
3948 reg = 0x80;
3949 }
3950 setSISIDXREG(SISCR, 0x17, 0x7f, reg);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003951 }
3952#endif
3953#ifdef CONFIG_FB_SIS_315
3954 if(ivideo->sisvga_engine == SIS_315_VGA) {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003955 if((ivideo->sisfb_crt1off) && (doit)) {
3956 crt1isoff = TRUE;
3957 reg = 0x40;
3958 reg1 = 0xc0;
3959 } else {
3960 crt1isoff = FALSE;
3961 reg = 0x00;
3962 reg1 = 0x00;
3963 }
3964 setSISIDXREG(SISCR, ivideo->SiS_Pr.SiS_MyCR63, ~0x40, reg);
3965 setSISIDXREG(SISSR, 0x1f, ~0xc0, reg1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003966 }
3967#endif
3968
3969 if(crt1isoff) {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003970 ivideo->currentvbflags &= ~VB_DISPTYPE_CRT1;
3971 ivideo->currentvbflags |= VB_SINGLE_MODE;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003972 } else {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003973 ivideo->currentvbflags |= VB_DISPTYPE_CRT1;
3974 if(ivideo->currentvbflags & VB_DISPTYPE_CRT2) {
3975 ivideo->currentvbflags |= VB_MIRROR_MODE;
3976 } else {
3977 ivideo->currentvbflags |= VB_SINGLE_MODE;
3978 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003979 }
3980
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003981 andSISIDXREG(SISSR, IND_SIS_RAMDAC_CONTROL, ~0x04);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003982
3983 if(ivideo->currentvbflags & CRT2_TV) {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003984 if(ivideo->vbflags2 & VB2_SISBRIDGE) {
3985 inSISIDXREG(SISPART2,0x1f,ivideo->p2_1f);
3986 inSISIDXREG(SISPART2,0x20,ivideo->p2_20);
3987 inSISIDXREG(SISPART2,0x2b,ivideo->p2_2b);
3988 inSISIDXREG(SISPART2,0x42,ivideo->p2_42);
3989 inSISIDXREG(SISPART2,0x43,ivideo->p2_43);
3990 inSISIDXREG(SISPART2,0x01,ivideo->p2_01);
3991 inSISIDXREG(SISPART2,0x02,ivideo->p2_02);
3992 } else if(ivideo->vbflags2 & VB2_CHRONTEL) {
3993 if(ivideo->chronteltype == 1) {
3994 ivideo->tvx = SiS_GetCH700x(&ivideo->SiS_Pr, 0x0a);
3995 ivideo->tvx |= (((SiS_GetCH700x(&ivideo->SiS_Pr, 0x08) & 0x02) >> 1) << 8);
3996 ivideo->tvy = SiS_GetCH700x(&ivideo->SiS_Pr, 0x0b);
3997 ivideo->tvy |= ((SiS_GetCH700x(&ivideo->SiS_Pr, 0x08) & 0x01) << 8);
3998 }
3999 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004000 }
4001
4002 if(ivideo->tvxpos) {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004003 sisfb_set_TVxposoffset(ivideo, ivideo->tvxpos);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004004 }
4005 if(ivideo->tvypos) {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004006 sisfb_set_TVyposoffset(ivideo, ivideo->tvypos);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004007 }
4008
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004009 /* Eventually sync engines */
4010 sisfb_check_engine_and_sync(ivideo);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004011
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004012 /* (Re-)Initialize chip engines */
4013 if(ivideo->accel) {
4014 sisfb_engine_init(ivideo);
4015 } else {
4016 ivideo->engineok = 0;
4017 }
4018}
Linus Torvalds1da177e2005-04-16 15:20:36 -07004019
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004020static int
4021sisfb_reset_mode(struct sis_video_info *ivideo)
4022{
4023 if(sisfb_set_mode(ivideo, 0))
4024 return 1;
4025
4026 sisfb_set_pitch(ivideo);
4027 sisfb_set_base_CRT1(ivideo, ivideo->current_base);
4028 sisfb_set_base_CRT2(ivideo, ivideo->current_base);
4029
4030 return 0;
4031}
4032
4033static void
4034sisfb_handle_command(struct sis_video_info *ivideo, struct sisfb_cmd *sisfb_command)
4035{
4036 int mycrt1off;
4037
4038 switch(sisfb_command->sisfb_cmd) {
4039 case SISFB_CMD_GETVBFLAGS:
4040 if(!ivideo->modechanged) {
4041 sisfb_command->sisfb_result[0] = SISFB_CMD_ERR_EARLY;
4042 } else {
4043 sisfb_command->sisfb_result[0] = SISFB_CMD_ERR_OK;
4044 sisfb_command->sisfb_result[1] = ivideo->currentvbflags;
4045 sisfb_command->sisfb_result[2] = ivideo->vbflags2;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004046 }
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004047 break;
4048 case SISFB_CMD_SWITCHCRT1:
4049 /* arg[0]: 0 = off, 1 = on, 99 = query */
4050 if(!ivideo->modechanged) {
4051 sisfb_command->sisfb_result[0] = SISFB_CMD_ERR_EARLY;
4052 } else if(sisfb_command->sisfb_arg[0] == 99) {
4053 /* Query */
4054 sisfb_command->sisfb_result[1] = ivideo->sisfb_crt1off ? 0 : 1;
4055 sisfb_command->sisfb_result[0] = SISFB_CMD_ERR_OK;
4056 } else if(ivideo->sisfblocked) {
4057 sisfb_command->sisfb_result[0] = SISFB_CMD_ERR_LOCKED;
4058 } else if((!(ivideo->currentvbflags & CRT2_ENABLE)) &&
4059 (sisfb_command->sisfb_arg[0] == 0)) {
4060 sisfb_command->sisfb_result[0] = SISFB_CMD_ERR_NOCRT2;
4061 } else {
4062 sisfb_command->sisfb_result[0] = SISFB_CMD_ERR_OK;
4063 mycrt1off = sisfb_command->sisfb_arg[0] ? 0 : 1;
4064 if( ((ivideo->currentvbflags & VB_DISPTYPE_CRT1) && mycrt1off) ||
4065 ((!(ivideo->currentvbflags & VB_DISPTYPE_CRT1)) && !mycrt1off) ) {
4066 ivideo->sisfb_crt1off = mycrt1off;
4067 if(sisfb_reset_mode(ivideo)) {
4068 sisfb_command->sisfb_result[0] = SISFB_CMD_ERR_OTHER;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004069 }
4070 }
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004071 sisfb_command->sisfb_result[1] = ivideo->sisfb_crt1off ? 0 : 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004072 }
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004073 break;
4074 /* more to come */
4075 default:
4076 sisfb_command->sisfb_result[0] = SISFB_CMD_ERR_UNKNOWN;
4077 printk(KERN_ERR "sisfb: Unknown command 0x%x\n",
4078 sisfb_command->sisfb_cmd);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004079 }
4080}
4081
4082#ifndef MODULE
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004083SISINITSTATIC int __init
4084sisfb_setup(char *options)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004085{
4086 char *this_opt;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004087
Linus Torvalds1da177e2005-04-16 15:20:36 -07004088 sisfb_setdefaultparms();
4089
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004090 if(!options || !(*options))
Linus Torvalds1da177e2005-04-16 15:20:36 -07004091 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004092
4093 while((this_opt = strsep(&options, ",")) != NULL) {
4094
4095 if(!(*this_opt)) continue;
4096
4097 if(!strnicmp(this_opt, "off", 3)) {
4098 sisfb_off = 1;
4099 } else if(!strnicmp(this_opt, "forcecrt2type:", 14)) {
4100 /* Need to check crt2 type first for fstn/dstn */
4101 sisfb_search_crt2type(this_opt + 14);
4102 } else if(!strnicmp(this_opt, "tvmode:",7)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004103 sisfb_search_tvstd(this_opt + 7);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004104 } else if(!strnicmp(this_opt, "tvstandard:",11)) {
4105 sisfb_search_tvstd(this_opt + 11);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004106 } else if(!strnicmp(this_opt, "mode:", 5)) {
4107 sisfb_search_mode(this_opt + 5, FALSE);
4108 } else if(!strnicmp(this_opt, "vesa:", 5)) {
4109 sisfb_search_vesamode(simple_strtoul(this_opt + 5, NULL, 0), FALSE);
4110#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
4111 } else if(!strnicmp(this_opt, "inverse", 7)) {
4112 sisfb_inverse = 1;
4113 /* fb_invert_cmaps(); */
4114 } else if(!strnicmp(this_opt, "font:", 5)) {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004115 if(strlen(this_opt + 5) < 40) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004116 strncpy(sisfb_fontname, this_opt + 5, sizeof(sisfb_fontname) - 1);
4117 sisfb_fontname[sizeof(sisfb_fontname) - 1] = '\0';
4118 }
4119#endif
4120 } else if(!strnicmp(this_opt, "rate:", 5)) {
4121 sisfb_parm_rate = simple_strtoul(this_opt + 5, NULL, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004122 } else if(!strnicmp(this_opt, "forcecrt1:", 10)) {
4123 sisfb_forcecrt1 = (int)simple_strtoul(this_opt + 10, NULL, 0);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004124 } else if(!strnicmp(this_opt, "mem:",4)) {
4125 sisfb_parm_mem = simple_strtoul(this_opt + 4, NULL, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004126 } else if(!strnicmp(this_opt, "pdc:", 4)) {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004127 sisfb_pdc = simple_strtoul(this_opt + 4, NULL, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004128 } else if(!strnicmp(this_opt, "pdc1:", 5)) {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004129 sisfb_pdca = simple_strtoul(this_opt + 5, NULL, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004130 } else if(!strnicmp(this_opt, "noaccel", 7)) {
4131 sisfb_accel = 0;
4132 } else if(!strnicmp(this_opt, "accel", 5)) {
4133 sisfb_accel = -1;
4134 } else if(!strnicmp(this_opt, "noypan", 6)) {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004135 sisfb_ypan = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004136 } else if(!strnicmp(this_opt, "ypan", 4)) {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004137 sisfb_ypan = -1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004138 } else if(!strnicmp(this_opt, "nomax", 5)) {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004139 sisfb_max = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004140 } else if(!strnicmp(this_opt, "max", 3)) {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004141 sisfb_max = -1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004142 } else if(!strnicmp(this_opt, "userom:", 7)) {
4143 sisfb_userom = (int)simple_strtoul(this_opt + 7, NULL, 0);
4144 } else if(!strnicmp(this_opt, "useoem:", 7)) {
4145 sisfb_useoem = (int)simple_strtoul(this_opt + 7, NULL, 0);
4146 } else if(!strnicmp(this_opt, "nocrt2rate", 10)) {
4147 sisfb_nocrt2rate = 1;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004148 } else if(!strnicmp(this_opt, "scalelcd:", 9)) {
4149 unsigned long temp = 2;
4150 temp = simple_strtoul(this_opt + 9, NULL, 0);
4151 if((temp == 0) || (temp == 1)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004152 sisfb_scalelcd = temp ^ 1;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004153 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004154 } else if(!strnicmp(this_opt, "tvxposoffset:", 13)) {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004155 int temp = 0;
4156 temp = (int)simple_strtol(this_opt + 13, NULL, 0);
4157 if((temp >= -32) && (temp <= 32)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004158 sisfb_tvxposoffset = temp;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004159 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004160 } else if(!strnicmp(this_opt, "tvyposoffset:", 13)) {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004161 int temp = 0;
4162 temp = (int)simple_strtol(this_opt + 13, NULL, 0);
4163 if((temp >= -32) && (temp <= 32)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004164 sisfb_tvyposoffset = temp;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004165 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004166 } else if(!strnicmp(this_opt, "specialtiming:", 14)) {
4167 sisfb_search_specialtiming(this_opt + 14);
4168 } else if(!strnicmp(this_opt, "lvdshl:", 7)) {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004169 int temp = 4;
4170 temp = simple_strtoul(this_opt + 7, NULL, 0);
4171 if((temp >= 0) && (temp <= 3)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004172 sisfb_lvdshl = temp;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004173 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004174 } else if(this_opt[0] >= '0' && this_opt[0] <= '9') {
4175 sisfb_search_mode(this_opt, TRUE);
4176#if !defined(__i386__) && !defined(__x86_64__)
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004177 } else if(!strnicmp(this_opt, "resetcard", 9)) {
4178 sisfb_resetcard = 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004179 } else if(!strnicmp(this_opt, "videoram:", 9)) {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004180 sisfb_videoram = simple_strtoul(this_opt + 9, NULL, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004181#endif
4182 } else {
4183 printk(KERN_INFO "sisfb: Invalid option %s\n", this_opt);
4184 }
4185
4186 }
4187
Linus Torvalds1da177e2005-04-16 15:20:36 -07004188 return 0;
4189}
4190#endif
4191
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004192static int __devinit
4193sisfb_check_rom(SIS_IOTYPE1 *rom_base, struct sis_video_info *ivideo)
4194{
4195 SIS_IOTYPE1 *rom;
4196 int romptr;
4197
4198 if((readb(rom_base) != 0x55) || (readb(rom_base + 1) != 0xaa))
4199 return 0;
4200
4201 romptr = (readb(rom_base + 0x18) | (readb(rom_base + 0x19) << 8));
4202 if(romptr > (0x10000 - 8))
4203 return 0;
4204
4205 rom = rom_base + romptr;
4206
4207 if((readb(rom) != 'P') || (readb(rom + 1) != 'C') ||
4208 (readb(rom + 2) != 'I') || (readb(rom + 3) != 'R'))
4209 return 0;
4210
4211 if((readb(rom + 4) | (readb(rom + 5) << 8)) != ivideo->chip_vendor)
4212 return 0;
4213
4214 if((readb(rom + 6) | (readb(rom + 7) << 8)) != ivideo->chip_id)
4215 return 0;
4216
4217 return 1;
4218}
4219
4220static unsigned char * __devinit
4221sisfb_find_rom(struct pci_dev *pdev)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004222{
4223 struct sis_video_info *ivideo = pci_get_drvdata(pdev);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004224 SIS_IOTYPE1 *rom_base;
4225 unsigned char *myrombase = NULL;
4226 u32 temp;
4227#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,11)
4228 size_t romsize;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004229
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004230 /* First, try the official pci ROM functions (except
4231 * on integrated chipsets which have no ROM).
4232 */
4233
4234 if(!ivideo->nbridge) {
4235
4236 if((rom_base = pci_map_rom(pdev, &romsize))) {
4237
4238 if(sisfb_check_rom(rom_base, ivideo)) {
4239
4240 if((myrombase = vmalloc(65536))) {
4241
4242 /* Work around bug in pci/rom.c: Folks forgot to check
4243 * whether the size retrieved from the BIOS image eventually
4244 * is larger than the mapped size
4245 */
4246 if(pci_resource_len(pdev, PCI_ROM_RESOURCE) < romsize)
4247 romsize = pci_resource_len(pdev, PCI_ROM_RESOURCE);
4248
4249 memcpy_fromio(myrombase, rom_base,
4250 (romsize > 65536) ? 65536 : romsize);
4251 }
4252 }
4253 pci_unmap_rom(pdev, rom_base);
4254 }
4255 }
4256
4257 if(myrombase) return myrombase;
4258#endif
4259
4260 /* Otherwise do it the conventional way. */
Linus Torvalds1da177e2005-04-16 15:20:36 -07004261
4262#if defined(__i386__) || defined(__x86_64__)
4263
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004264 for(temp = 0x000c0000; temp < 0x000f0000; temp += 0x00001000) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004265
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004266 rom_base = ioremap(temp, 65536);
4267 if(!rom_base)
4268 continue;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004269
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004270 if(!sisfb_check_rom(rom_base, ivideo)) {
4271 iounmap(rom_base);
4272 continue;
4273 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004274
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004275 if((myrombase = vmalloc(65536)))
4276 memcpy_fromio(myrombase, rom_base, 65536);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004277
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004278 iounmap(rom_base);
4279 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004280
Linus Torvalds1da177e2005-04-16 15:20:36 -07004281 }
4282
4283#else
4284
4285 pci_read_config_dword(pdev, PCI_ROM_ADDRESS, &temp);
4286 pci_write_config_dword(pdev, PCI_ROM_ADDRESS,
4287 (ivideo->video_base & PCI_ROM_ADDRESS_MASK) | PCI_ROM_ADDRESS_ENABLE);
4288
4289 rom_base = ioremap(ivideo->video_base, 65536);
4290 if(rom_base) {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004291 if(sisfb_check_rom(rom_base, ivideo)) {
4292 if((myrombase = vmalloc(65536)))
4293 memcpy_fromio(myrombase, rom_base, 65536);
4294 }
4295 iounmap(rom_base);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004296 }
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004297
4298 pci_write_config_dword(pdev, PCI_ROM_ADDRESS, temp);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004299
4300#endif
4301
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004302 return myrombase;
4303}
4304
4305static void __devinit
4306sisfb_post_map_vram(struct sis_video_info *ivideo, unsigned int *mapsize,
4307 unsigned int min)
4308{
4309 ivideo->video_vbase = ioremap(ivideo->video_base, (*mapsize));
4310
4311 if(!ivideo->video_vbase) {
4312 printk(KERN_ERR
4313 "sisfb: Unable to map maximum video RAM for size detection\n");
4314 (*mapsize) >>= 1;
4315 while((!(ivideo->video_vbase = ioremap(ivideo->video_base, (*mapsize))))) {
4316 (*mapsize) >>= 1;
4317 if((*mapsize) < (min << 20))
4318 break;
4319 }
4320 if(ivideo->video_vbase) {
4321 printk(KERN_ERR
4322 "sisfb: Video RAM size detection limited to %dMB\n",
4323 (int)((*mapsize) >> 20));
4324 }
4325 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004326}
4327
4328#ifdef CONFIG_FB_SIS_300
4329static int __devinit
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004330sisfb_post_300_buswidth(struct sis_video_info *ivideo)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004331{
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004332 SIS_IOTYPE1 *FBAddress = ivideo->video_vbase;
4333 unsigned short temp;
4334 unsigned char reg;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004335 int i, j;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004336
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004337 andSISIDXREG(SISSR, 0x15, 0xFB);
4338 orSISIDXREG(SISSR, 0x15, 0x04);
4339 outSISIDXREG(SISSR, 0x13, 0x00);
4340 outSISIDXREG(SISSR, 0x14, 0xBF);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004341
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004342 for(i = 0; i < 2; i++) {
4343 temp = 0x1234;
4344 for(j = 0; j < 4; j++) {
4345 writew(temp, FBAddress);
4346 if(readw(FBAddress) == temp)
4347 break;
4348 orSISIDXREG(SISSR, 0x3c, 0x01);
4349 inSISIDXREG(SISSR, 0x05, reg);
4350 inSISIDXREG(SISSR, 0x05, reg);
4351 andSISIDXREG(SISSR, 0x3c, 0xfe);
4352 inSISIDXREG(SISSR, 0x05, reg);
4353 inSISIDXREG(SISSR, 0x05, reg);
4354 temp++;
4355 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004356 }
4357
4358 writel(0x01234567L, FBAddress);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004359 writel(0x456789ABL, (FBAddress + 4));
4360 writel(0x89ABCDEFL, (FBAddress + 8));
4361 writel(0xCDEF0123L, (FBAddress + 12));
4362
4363 inSISIDXREG(SISSR, 0x3b, reg);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004364 if(reg & 0x01) {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004365 if(readl((FBAddress + 12)) == 0xCDEF0123L)
4366 return 4; /* Channel A 128bit */
Linus Torvalds1da177e2005-04-16 15:20:36 -07004367 }
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004368
4369 if(readl((FBAddress + 4)) == 0x456789ABL)
4370 return 2; /* Channel B 64bit */
4371
4372 return 1; /* 32bit */
4373}
4374
4375static int __devinit
4376sisfb_post_300_rwtest(struct sis_video_info *ivideo, int iteration, int buswidth,
4377 int PseudoRankCapacity, int PseudoAdrPinCount,
4378 unsigned int mapsize)
4379{
4380 SIS_IOTYPE1 *FBAddr = ivideo->video_vbase;
4381 unsigned short sr14;
4382 unsigned int k, RankCapacity, PageCapacity, BankNumHigh, BankNumMid;
4383 unsigned int PhysicalAdrOtherPage, PhysicalAdrHigh, PhysicalAdrHalfPage;
4384 static const unsigned short SiS_DRAMType[17][5] = {
4385 {0x0C,0x0A,0x02,0x40,0x39},
4386 {0x0D,0x0A,0x01,0x40,0x48},
4387 {0x0C,0x09,0x02,0x20,0x35},
4388 {0x0D,0x09,0x01,0x20,0x44},
4389 {0x0C,0x08,0x02,0x10,0x31},
4390 {0x0D,0x08,0x01,0x10,0x40},
4391 {0x0C,0x0A,0x01,0x20,0x34},
4392 {0x0C,0x09,0x01,0x08,0x32},
4393 {0x0B,0x08,0x02,0x08,0x21},
4394 {0x0C,0x08,0x01,0x08,0x30},
4395 {0x0A,0x08,0x02,0x04,0x11},
4396 {0x0B,0x0A,0x01,0x10,0x28},
4397 {0x09,0x08,0x02,0x02,0x01},
4398 {0x0B,0x09,0x01,0x08,0x24},
4399 {0x0B,0x08,0x01,0x04,0x20},
4400 {0x0A,0x08,0x01,0x02,0x10},
4401 {0x09,0x08,0x01,0x01,0x00}
4402 };
4403
4404 for(k = 0; k <= 16; k++) {
4405
4406 RankCapacity = buswidth * SiS_DRAMType[k][3];
4407
4408 if(RankCapacity != PseudoRankCapacity)
4409 continue;
4410
4411 if((SiS_DRAMType[k][2] + SiS_DRAMType[k][0]) > PseudoAdrPinCount)
4412 continue;
4413
4414 BankNumHigh = RankCapacity * 16 * iteration - 1;
4415 if(iteration == 3) { /* Rank No */
4416 BankNumMid = RankCapacity * 16 - 1;
4417 } else {
4418 BankNumMid = RankCapacity * 16 * iteration / 2 - 1;
4419 }
4420
4421 PageCapacity = (1 << SiS_DRAMType[k][1]) * buswidth * 4;
4422 PhysicalAdrHigh = BankNumHigh;
4423 PhysicalAdrHalfPage = (PageCapacity / 2 + PhysicalAdrHigh) % PageCapacity;
4424 PhysicalAdrOtherPage = PageCapacity * SiS_DRAMType[k][2] + PhysicalAdrHigh;
4425
4426 andSISIDXREG(SISSR, 0x15, 0xFB); /* Test */
4427 orSISIDXREG(SISSR, 0x15, 0x04); /* Test */
4428 sr14 = (SiS_DRAMType[k][3] * buswidth) - 1;
4429 if(buswidth == 4) sr14 |= 0x80;
4430 else if(buswidth == 2) sr14 |= 0x40;
4431 outSISIDXREG(SISSR, 0x13, SiS_DRAMType[k][4]);
4432 outSISIDXREG(SISSR, 0x14, sr14);
4433
4434 BankNumHigh <<= 16;
4435 BankNumMid <<= 16;
4436
4437 if((BankNumHigh + PhysicalAdrHigh >= mapsize) ||
4438 (BankNumMid + PhysicalAdrHigh >= mapsize) ||
4439 (BankNumHigh + PhysicalAdrHalfPage >= mapsize) ||
4440 (BankNumHigh + PhysicalAdrOtherPage >= mapsize))
4441 continue;
4442
4443 /* Write data */
4444 writew(((unsigned short)PhysicalAdrHigh),
4445 (FBAddr + BankNumHigh + PhysicalAdrHigh));
4446 writew(((unsigned short)BankNumMid),
4447 (FBAddr + BankNumMid + PhysicalAdrHigh));
4448 writew(((unsigned short)PhysicalAdrHalfPage),
4449 (FBAddr + BankNumHigh + PhysicalAdrHalfPage));
4450 writew(((unsigned short)PhysicalAdrOtherPage),
4451 (FBAddr + BankNumHigh + PhysicalAdrOtherPage));
4452
4453 /* Read data */
4454 if(readw(FBAddr + BankNumHigh + PhysicalAdrHigh) == PhysicalAdrHigh)
4455 return 1;
4456 }
4457
4458 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004459}
4460
4461static void __devinit
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004462sisfb_post_300_ramsize(struct pci_dev *pdev, unsigned int mapsize)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004463{
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004464 struct sis_video_info *ivideo = pci_get_drvdata(pdev);
4465 int i, j, buswidth;
4466 int PseudoRankCapacity, PseudoAdrPinCount;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004467
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004468 buswidth = sisfb_post_300_buswidth(ivideo);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004469
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004470 for(i = 6; i >= 0; i--) {
4471 PseudoRankCapacity = 1 << i;
4472 for(j = 4; j >= 1; j--) {
4473 PseudoAdrPinCount = 15 - j;
4474 if((PseudoRankCapacity * j) <= 64) {
4475 if(sisfb_post_300_rwtest(ivideo,
4476 j,
4477 buswidth,
4478 PseudoRankCapacity,
4479 PseudoAdrPinCount,
4480 mapsize))
4481 return;
4482 }
4483 }
4484 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004485}
4486
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004487static void __devinit
4488sisfb_post_sis300(struct pci_dev *pdev)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004489{
4490 struct sis_video_info *ivideo = pci_get_drvdata(pdev);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004491 unsigned char *bios = ivideo->SiS_Pr.VirtualRomBase;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004492 u8 reg, v1, v2, v3, v4, v5, v6, v7, v8;
4493 u16 index, rindex, memtype = 0;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004494 unsigned int mapsize;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004495
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004496 if(!ivideo->SiS_Pr.UseROM)
4497 bios = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004498
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004499 outSISIDXREG(SISSR, 0x05, 0x86);
4500
4501 if(bios) {
4502 if(bios[0x52] & 0x80) {
4503 memtype = bios[0x52];
4504 } else {
4505 inSISIDXREG(SISSR, 0x3a, memtype);
4506 }
4507 memtype &= 0x07;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004508 }
4509
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004510 v3 = 0x80; v6 = 0x80;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004511 if(ivideo->revision_id <= 0x13) {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004512 v1 = 0x44; v2 = 0x42;
4513 v4 = 0x44; v5 = 0x42;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004514 } else {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004515 v1 = 0x68; v2 = 0x43; /* Assume 125Mhz MCLK */
4516 v4 = 0x68; v5 = 0x43; /* Assume 125Mhz ECLK */
4517 if(bios) {
4518 index = memtype * 5;
4519 rindex = index + 0x54;
4520 v1 = bios[rindex++];
4521 v2 = bios[rindex++];
4522 v3 = bios[rindex++];
4523 rindex = index + 0x7c;
4524 v4 = bios[rindex++];
4525 v5 = bios[rindex++];
4526 v6 = bios[rindex++];
4527 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004528 }
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004529 outSISIDXREG(SISSR, 0x28, v1);
4530 outSISIDXREG(SISSR, 0x29, v2);
4531 outSISIDXREG(SISSR, 0x2a, v3);
4532 outSISIDXREG(SISSR, 0x2e, v4);
4533 outSISIDXREG(SISSR, 0x2f, v5);
4534 outSISIDXREG(SISSR, 0x30, v6);
4535
Linus Torvalds1da177e2005-04-16 15:20:36 -07004536 v1 = 0x10;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004537 if(bios)
4538 v1 = bios[0xa4];
4539 outSISIDXREG(SISSR, 0x07, v1); /* DAC speed */
4540
4541 outSISIDXREG(SISSR, 0x11, 0x0f); /* DDC, power save */
4542
Linus Torvalds1da177e2005-04-16 15:20:36 -07004543 v1 = 0x01; v2 = 0x43; v3 = 0x1e; v4 = 0x2a;
4544 v5 = 0x06; v6 = 0x00; v7 = 0x00; v8 = 0x00;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004545 if(bios) {
4546 memtype += 0xa5;
4547 v1 = bios[memtype];
4548 v2 = bios[memtype + 8];
4549 v3 = bios[memtype + 16];
4550 v4 = bios[memtype + 24];
4551 v5 = bios[memtype + 32];
4552 v6 = bios[memtype + 40];
4553 v7 = bios[memtype + 48];
4554 v8 = bios[memtype + 56];
Linus Torvalds1da177e2005-04-16 15:20:36 -07004555 }
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004556 if(ivideo->revision_id >= 0x80)
4557 v3 &= 0xfd;
4558 outSISIDXREG(SISSR, 0x15, v1); /* Ram type (assuming 0, BIOS 0xa5 step 8) */
4559 outSISIDXREG(SISSR, 0x16, v2);
4560 outSISIDXREG(SISSR, 0x17, v3);
4561 outSISIDXREG(SISSR, 0x18, v4);
4562 outSISIDXREG(SISSR, 0x19, v5);
4563 outSISIDXREG(SISSR, 0x1a, v6);
4564 outSISIDXREG(SISSR, 0x1b, v7);
4565 outSISIDXREG(SISSR, 0x1c, v8); /* ---- */
4566 andSISIDXREG(SISSR, 0x15 ,0xfb);
4567 orSISIDXREG(SISSR, 0x15, 0x04);
4568 if(bios) {
4569 if(bios[0x53] & 0x02) {
4570 orSISIDXREG(SISSR, 0x19, 0x20);
4571 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004572 }
4573 v1 = 0x04; /* DAC pedestal (BIOS 0xe5) */
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004574 if(ivideo->revision_id >= 0x80)
4575 v1 |= 0x01;
4576 outSISIDXREG(SISSR, 0x1f, v1);
4577 outSISIDXREG(SISSR, 0x20, 0xa4); /* linear & relocated io & disable a0000 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07004578 v1 = 0xf6; v2 = 0x0d; v3 = 0x00;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004579 if(bios) {
4580 v1 = bios[0xe8];
4581 v2 = bios[0xe9];
4582 v3 = bios[0xea];
Linus Torvalds1da177e2005-04-16 15:20:36 -07004583 }
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004584 outSISIDXREG(SISSR, 0x23, v1);
4585 outSISIDXREG(SISSR, 0x24, v2);
4586 outSISIDXREG(SISSR, 0x25, v3);
4587 outSISIDXREG(SISSR, 0x21, 0x84);
4588 outSISIDXREG(SISSR, 0x22, 0x00);
4589 outSISIDXREG(SISCR, 0x37, 0x00);
4590 orSISIDXREG(SISPART1, 0x24, 0x01); /* unlock crt2 */
4591 outSISIDXREG(SISPART1, 0x00, 0x00);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004592 v1 = 0x40; v2 = 0x11;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004593 if(bios) {
4594 v1 = bios[0xec];
4595 v2 = bios[0xeb];
Linus Torvalds1da177e2005-04-16 15:20:36 -07004596 }
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004597 outSISIDXREG(SISPART1, 0x02, v1);
4598
4599 if(ivideo->revision_id >= 0x80)
4600 v2 &= ~0x01;
4601
4602 inSISIDXREG(SISPART4, 0x00, reg);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004603 if((reg == 1) || (reg == 2)) {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004604 outSISIDXREG(SISCR, 0x37, 0x02);
4605 outSISIDXREG(SISPART2, 0x00, 0x1c);
4606 v4 = 0x00; v5 = 0x00; v6 = 0x10;
4607 if(ivideo->SiS_Pr.UseROM) {
4608 v4 = bios[0xf5];
4609 v5 = bios[0xf6];
4610 v6 = bios[0xf7];
4611 }
4612 outSISIDXREG(SISPART4, 0x0d, v4);
4613 outSISIDXREG(SISPART4, 0x0e, v5);
4614 outSISIDXREG(SISPART4, 0x10, v6);
4615 outSISIDXREG(SISPART4, 0x0f, 0x3f);
4616 inSISIDXREG(SISPART4, 0x01, reg);
4617 if(reg >= 0xb0) {
4618 inSISIDXREG(SISPART4, 0x23, reg);
4619 reg &= 0x20;
4620 reg <<= 1;
4621 outSISIDXREG(SISPART4, 0x23, reg);
4622 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004623 } else {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004624 v2 &= ~0x10;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004625 }
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004626 outSISIDXREG(SISSR, 0x32, v2);
4627
4628 andSISIDXREG(SISPART1, 0x24, 0xfe); /* Lock CRT2 */
4629
4630 inSISIDXREG(SISSR, 0x16, reg);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004631 reg &= 0xc3;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004632 outSISIDXREG(SISCR, 0x35, reg);
4633 outSISIDXREG(SISCR, 0x83, 0x00);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004634#if !defined(__i386__) && !defined(__x86_64__)
4635 if(sisfb_videoram) {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004636 outSISIDXREG(SISSR, 0x13, 0x28); /* ? */
4637 reg = ((sisfb_videoram >> 10) - 1) | 0x40;
4638 outSISIDXREG(SISSR, 0x14, reg);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004639 } else {
4640#endif
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004641 /* Need to map max FB size for finding out about RAM size */
4642 mapsize = 64 << 20;
4643 sisfb_post_map_vram(ivideo, &mapsize, 4);
4644
4645 if(ivideo->video_vbase) {
4646 sisfb_post_300_ramsize(pdev, mapsize);
4647 iounmap(ivideo->video_vbase);
4648 } else {
4649 printk(KERN_DEBUG
4650 "sisfb: Failed to map memory for size detection, assuming 8MB\n");
4651 outSISIDXREG(SISSR, 0x13, 0x28); /* ? */
4652 outSISIDXREG(SISSR, 0x14, 0x47); /* 8MB, 64bit default */
4653 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004654#if !defined(__i386__) && !defined(__x86_64__)
4655 }
4656#endif
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004657 if(bios) {
4658 v1 = bios[0xe6];
4659 v2 = bios[0xe7];
Linus Torvalds1da177e2005-04-16 15:20:36 -07004660 } else {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004661 inSISIDXREG(SISSR, 0x3a, reg);
4662 if((reg & 0x30) == 0x30) {
4663 v1 = 0x04; /* PCI */
4664 v2 = 0x92;
4665 } else {
4666 v1 = 0x14; /* AGP */
4667 v2 = 0xb2;
4668 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004669 }
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004670 outSISIDXREG(SISSR, 0x21, v1);
4671 outSISIDXREG(SISSR, 0x22, v2);
4672
4673 /* Sense CRT1 */
4674 sisfb_sense_crt1(ivideo);
4675
4676 /* Set default mode, don't clear screen */
4677 ivideo->SiS_Pr.SiS_UseOEM = FALSE;
4678 SiS_SetEnableDstn(&ivideo->SiS_Pr, FALSE);
4679 SiS_SetEnableFstn(&ivideo->SiS_Pr, FALSE);
4680 ivideo->curFSTN = ivideo->curDSTN = 0;
4681 ivideo->SiS_Pr.VideoMemorySize = 8 << 20;
4682 SiSSetMode(&ivideo->SiS_Pr, 0x2e | 0x80);
4683
4684 outSISIDXREG(SISSR, 0x05, 0x86);
4685
4686 /* Display off */
4687 orSISIDXREG(SISSR, 0x01, 0x20);
4688
4689 /* Save mode number in CR34 */
4690 outSISIDXREG(SISCR, 0x34, 0x2e);
4691
4692 /* Let everyone know what the current mode is */
4693 ivideo->modeprechange = 0x2e;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004694}
4695#endif
4696
4697#ifdef CONFIG_FB_SIS_315
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004698#if 0
4699static void __devinit
4700sisfb_post_sis315330(struct pci_dev *pdev)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004701{
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004702 /* TODO */
Linus Torvalds1da177e2005-04-16 15:20:36 -07004703}
4704#endif
4705
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004706static void __devinit
4707sisfb_post_xgi_delay(struct sis_video_info *ivideo, int delay)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004708{
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004709 unsigned int i;
4710 u8 reg;
4711
4712 for(i = 0; i <= (delay * 10 * 36); i++) {
4713 inSISIDXREG(SISSR, 0x05, reg);
4714 reg++;
4715 }
4716}
4717
4718static int __devinit
4719sisfb_find_host_bridge(struct sis_video_info *ivideo, struct pci_dev *mypdev,
4720 unsigned short pcivendor)
4721{
4722 struct pci_dev *pdev = NULL;
4723 unsigned short temp;
4724 int ret = 0;
4725
4726 while((pdev = SIS_PCI_GET_CLASS(PCI_CLASS_BRIDGE_HOST, pdev))) {
4727 temp = pdev->vendor;
4728 SIS_PCI_PUT_DEVICE(pdev);
4729 if(temp == pcivendor) {
4730 ret = 1;
4731 break;
4732 }
4733 }
4734
4735 return ret;
4736}
4737
4738static int __devinit
4739sisfb_post_xgi_rwtest(struct sis_video_info *ivideo, int starta,
4740 unsigned int enda, unsigned int mapsize)
4741{
4742 unsigned int pos;
4743 int i;
4744
4745 writel(0, ivideo->video_vbase);
4746
4747 for(i = starta; i <= enda; i++) {
4748 pos = 1 << i;
4749 if(pos < mapsize)
4750 writel(pos, ivideo->video_vbase + pos);
4751 }
4752
4753 sisfb_post_xgi_delay(ivideo, 150);
4754
4755 if(readl(ivideo->video_vbase) != 0)
4756 return 0;
4757
4758 for(i = starta; i <= enda; i++) {
4759 pos = 1 << i;
4760 if(pos < mapsize) {
4761 if(readl(ivideo->video_vbase + pos) != pos)
4762 return 0;
4763 } else
4764 return 0;
4765 }
4766
4767 return 1;
4768}
4769
4770static void __devinit
4771sisfb_post_xgi_ramsize(struct sis_video_info *ivideo)
4772{
4773 unsigned int buswidth, ranksize, channelab, mapsize;
4774 int i, j, k, l;
4775 u8 reg, sr14;
4776 static const u8 dramsr13[12 * 5] = {
4777 0x02, 0x0e, 0x0b, 0x80, 0x5d,
4778 0x02, 0x0e, 0x0a, 0x40, 0x59,
4779 0x02, 0x0d, 0x0b, 0x40, 0x4d,
4780 0x02, 0x0e, 0x09, 0x20, 0x55,
4781 0x02, 0x0d, 0x0a, 0x20, 0x49,
4782 0x02, 0x0c, 0x0b, 0x20, 0x3d,
4783 0x02, 0x0e, 0x08, 0x10, 0x51,
4784 0x02, 0x0d, 0x09, 0x10, 0x45,
4785 0x02, 0x0c, 0x0a, 0x10, 0x39,
4786 0x02, 0x0d, 0x08, 0x08, 0x41,
4787 0x02, 0x0c, 0x09, 0x08, 0x35,
4788 0x02, 0x0c, 0x08, 0x04, 0x31
4789 };
4790 static const u8 dramsr13_4[4 * 5] = {
4791 0x02, 0x0d, 0x09, 0x40, 0x45,
4792 0x02, 0x0c, 0x09, 0x20, 0x35,
4793 0x02, 0x0c, 0x08, 0x10, 0x31,
4794 0x02, 0x0b, 0x08, 0x08, 0x21
4795 };
4796
4797 /* Enable linear mode, disable 0xa0000 address decoding */
4798 /* We disable a0000 address decoding, because
4799 * - if running on x86, if the card is disabled, it means
4800 * that another card is in the system. We don't want
4801 * to interphere with that primary card's textmode.
4802 * - if running on non-x86, there usually is no VGA window
4803 * at a0000.
4804 */
4805 orSISIDXREG(SISSR, 0x20, (0x80 | 0x04));
4806
4807 /* Need to map max FB size for finding out about RAM size */
4808 mapsize = 256 << 20;
4809 sisfb_post_map_vram(ivideo, &mapsize, 32);
4810
4811 if(!ivideo->video_vbase) {
4812 printk(KERN_ERR "sisfb: Unable to detect RAM size. Setting default.\n");
4813 outSISIDXREG(SISSR, 0x13, 0x35);
4814 outSISIDXREG(SISSR, 0x14, 0x41);
4815 /* TODO */
4816 return;
4817 }
4818
4819 /* Non-interleaving */
4820 outSISIDXREG(SISSR, 0x15, 0x00);
4821 /* No tiling */
4822 outSISIDXREG(SISSR, 0x1c, 0x00);
4823
4824 if(ivideo->chip == XGI_20) {
4825
4826 channelab = 1;
4827 inSISIDXREG(SISCR, 0x97, reg);
4828 if(!(reg & 0x01)) { /* Single 32/16 */
4829 buswidth = 32;
4830 outSISIDXREG(SISSR, 0x13, 0xb1);
4831 outSISIDXREG(SISSR, 0x14, 0x52);
4832 sisfb_post_xgi_delay(ivideo, 1);
4833 sr14 = 0x02;
4834 if(sisfb_post_xgi_rwtest(ivideo, 23, 24, mapsize))
4835 goto bail_out;
4836
4837 outSISIDXREG(SISSR, 0x13, 0x31);
4838 outSISIDXREG(SISSR, 0x14, 0x42);
4839 sisfb_post_xgi_delay(ivideo, 1);
4840 if(sisfb_post_xgi_rwtest(ivideo, 23, 23, mapsize))
4841 goto bail_out;
4842
4843 buswidth = 16;
4844 outSISIDXREG(SISSR, 0x13, 0xb1);
4845 outSISIDXREG(SISSR, 0x14, 0x41);
4846 sisfb_post_xgi_delay(ivideo, 1);
4847 sr14 = 0x01;
4848 if(sisfb_post_xgi_rwtest(ivideo, 22, 23, mapsize))
4849 goto bail_out;
4850 else
4851 outSISIDXREG(SISSR, 0x13, 0x31);
4852 } else { /* Dual 16/8 */
4853 buswidth = 16;
4854 outSISIDXREG(SISSR, 0x13, 0xb1);
4855 outSISIDXREG(SISSR, 0x14, 0x41);
4856 sisfb_post_xgi_delay(ivideo, 1);
4857 sr14 = 0x01;
4858 if(sisfb_post_xgi_rwtest(ivideo, 22, 23, mapsize))
4859 goto bail_out;
4860
4861 outSISIDXREG(SISSR, 0x13, 0x31);
4862 outSISIDXREG(SISSR, 0x14, 0x31);
4863 sisfb_post_xgi_delay(ivideo, 1);
4864 if(sisfb_post_xgi_rwtest(ivideo, 22, 22, mapsize))
4865 goto bail_out;
4866
4867 buswidth = 8;
4868 outSISIDXREG(SISSR, 0x13, 0xb1);
4869 outSISIDXREG(SISSR, 0x14, 0x30);
4870 sisfb_post_xgi_delay(ivideo, 1);
4871 sr14 = 0x00;
4872 if(sisfb_post_xgi_rwtest(ivideo, 21, 22, mapsize))
4873 goto bail_out;
4874 else
4875 outSISIDXREG(SISSR, 0x13, 0x31);
4876 }
4877
4878 } else { /* XGI_40 */
4879
4880 inSISIDXREG(SISCR, 0x97, reg);
4881 if(!(reg & 0x10)) {
4882 inSISIDXREG(SISSR, 0x39, reg);
4883 reg >>= 1;
4884 }
4885
4886 if(reg & 0x01) { /* DDRII */
4887 buswidth = 32;
4888 if(ivideo->revision_id == 2) {
4889 channelab = 2;
4890 outSISIDXREG(SISSR, 0x13, 0xa1);
4891 outSISIDXREG(SISSR, 0x14, 0x44);
4892 sr14 = 0x04;
4893 sisfb_post_xgi_delay(ivideo, 1);
4894 if(sisfb_post_xgi_rwtest(ivideo, 23, 24, mapsize))
4895 goto bail_out;
4896
4897 outSISIDXREG(SISSR, 0x13, 0x21);
4898 outSISIDXREG(SISSR, 0x14, 0x34);
4899 if(sisfb_post_xgi_rwtest(ivideo, 22, 23, mapsize))
4900 goto bail_out;
4901
4902 channelab = 1;
4903 outSISIDXREG(SISSR, 0x13, 0xa1);
4904 outSISIDXREG(SISSR, 0x14, 0x40);
4905 sr14 = 0x00;
4906 if(sisfb_post_xgi_rwtest(ivideo, 22, 23, mapsize))
4907 goto bail_out;
4908
4909 outSISIDXREG(SISSR, 0x13, 0x21);
4910 outSISIDXREG(SISSR, 0x14, 0x30);
4911 } else {
4912 channelab = 3;
4913 outSISIDXREG(SISSR, 0x13, 0xa1);
4914 outSISIDXREG(SISSR, 0x14, 0x4c);
4915 sr14 = 0x0c;
4916 sisfb_post_xgi_delay(ivideo, 1);
4917 if(sisfb_post_xgi_rwtest(ivideo, 23, 25, mapsize))
4918 goto bail_out;
4919
4920 channelab = 2;
4921 outSISIDXREG(SISSR, 0x14, 0x48);
4922 sisfb_post_xgi_delay(ivideo, 1);
4923 sr14 = 0x08;
4924 if(sisfb_post_xgi_rwtest(ivideo, 23, 24, mapsize))
4925 goto bail_out;
4926
4927 outSISIDXREG(SISSR, 0x13, 0x21);
4928 outSISIDXREG(SISSR, 0x14, 0x3c);
4929 sr14 = 0x0c;
4930
4931 if(sisfb_post_xgi_rwtest(ivideo, 23, 24, mapsize)) {
4932 channelab = 3;
4933 } else {
4934 channelab = 2;
4935 outSISIDXREG(SISSR, 0x14, 0x38);
4936 sr14 = 0x08;
4937 }
4938 }
4939 sisfb_post_xgi_delay(ivideo, 1);
4940
4941 } else { /* DDR */
4942
4943 buswidth = 64;
4944 if(ivideo->revision_id == 2) {
4945 channelab = 1;
4946 outSISIDXREG(SISSR, 0x13, 0xa1);
4947 outSISIDXREG(SISSR, 0x14, 0x52);
4948 sisfb_post_xgi_delay(ivideo, 1);
4949 sr14 = 0x02;
4950 if(sisfb_post_xgi_rwtest(ivideo, 23, 24, mapsize))
4951 goto bail_out;
4952
4953 outSISIDXREG(SISSR, 0x13, 0x21);
4954 outSISIDXREG(SISSR, 0x14, 0x42);
4955 } else {
4956 channelab = 2;
4957 outSISIDXREG(SISSR, 0x13, 0xa1);
4958 outSISIDXREG(SISSR, 0x14, 0x5a);
4959 sisfb_post_xgi_delay(ivideo, 1);
4960 sr14 = 0x0a;
4961 if(sisfb_post_xgi_rwtest(ivideo, 24, 25, mapsize))
4962 goto bail_out;
4963
4964 outSISIDXREG(SISSR, 0x13, 0x21);
4965 outSISIDXREG(SISSR, 0x14, 0x4a);
4966 }
4967 sisfb_post_xgi_delay(ivideo, 1);
4968
4969 }
4970 }
4971
4972bail_out:
4973 setSISIDXREG(SISSR, 0x14, 0xf0, sr14);
4974 sisfb_post_xgi_delay(ivideo, 1);
4975
4976 j = (ivideo->chip == XGI_20) ? 5 : 9;
4977 k = (ivideo->chip == XGI_20) ? 12 : 4;
4978
4979 for(i = 0; i < k; i++) {
4980
4981 reg = (ivideo->chip == XGI_20) ?
4982 dramsr13[(i * 5) + 4] : dramsr13_4[(i * 5) + 4];
4983 setSISIDXREG(SISSR, 0x13, 0x80, reg);
4984 sisfb_post_xgi_delay(ivideo, 50);
4985
4986 ranksize = (ivideo->chip == XGI_20) ?
4987 dramsr13[(i * 5) + 3] : dramsr13_4[(i * 5) + 3];
4988
4989 inSISIDXREG(SISSR, 0x13, reg);
4990 if(reg & 0x80) ranksize <<= 1;
4991
4992 if(ivideo->chip == XGI_20) {
4993 if(buswidth == 16) ranksize <<= 1;
4994 else if(buswidth == 32) ranksize <<= 2;
4995 } else {
4996 if(buswidth == 64) ranksize <<= 1;
4997 }
4998
4999 reg = 0;
5000 l = channelab;
5001 if(l == 3) l = 4;
5002 if((ranksize * l) <= 256) {
5003 while((ranksize >>= 1)) reg += 0x10;
5004 }
5005
5006 if(!reg) continue;
5007
5008 setSISIDXREG(SISSR, 0x14, 0x0f, (reg & 0xf0));
5009 sisfb_post_xgi_delay(ivideo, 1);
5010
5011 if(sisfb_post_xgi_rwtest(ivideo, j, ((reg >> 4) + channelab - 2 + 20), mapsize))
5012 break;
5013 }
5014
5015 iounmap(ivideo->video_vbase);
5016}
5017
5018static void __devinit
5019sisfb_post_xgi_setclocks(struct sis_video_info *ivideo, u8 regb)
5020{
5021 u8 v1, v2, v3;
5022 int index;
5023 static const u8 cs90[8 * 3] = {
5024 0x16, 0x01, 0x01,
5025 0x3e, 0x03, 0x01,
5026 0x7c, 0x08, 0x01,
5027 0x79, 0x06, 0x01,
5028 0x29, 0x01, 0x81,
5029 0x5c, 0x23, 0x01,
5030 0x5c, 0x23, 0x01,
5031 0x5c, 0x23, 0x01
5032 };
5033 static const u8 csb8[8 * 3] = {
5034 0x5c, 0x23, 0x01,
5035 0x29, 0x01, 0x01,
5036 0x7c, 0x08, 0x01,
5037 0x79, 0x06, 0x01,
5038 0x29, 0x01, 0x81,
5039 0x5c, 0x23, 0x01,
5040 0x5c, 0x23, 0x01,
5041 0x5c, 0x23, 0x01
5042 };
5043
5044 regb = 0; /* ! */
5045
5046 index = regb * 3;
5047 v1 = cs90[index]; v2 = cs90[index + 1]; v3 = cs90[index + 2];
5048 if(ivideo->haveXGIROM) {
5049 v1 = ivideo->bios_abase[0x90 + index];
5050 v2 = ivideo->bios_abase[0x90 + index + 1];
5051 v3 = ivideo->bios_abase[0x90 + index + 2];
5052 }
5053 outSISIDXREG(SISSR, 0x28, v1);
5054 outSISIDXREG(SISSR, 0x29, v2);
5055 outSISIDXREG(SISSR, 0x2a, v3);
5056 sisfb_post_xgi_delay(ivideo, 0x43);
5057 sisfb_post_xgi_delay(ivideo, 0x43);
5058 sisfb_post_xgi_delay(ivideo, 0x43);
5059 index = regb * 3;
5060 v1 = csb8[index]; v2 = csb8[index + 1]; v3 = csb8[index + 2];
5061 if(ivideo->haveXGIROM) {
5062 v1 = ivideo->bios_abase[0xb8 + index];
5063 v2 = ivideo->bios_abase[0xb8 + index + 1];
5064 v3 = ivideo->bios_abase[0xb8 + index + 2];
5065 }
5066 outSISIDXREG(SISSR, 0x2e, v1);
5067 outSISIDXREG(SISSR, 0x2f, v2);
5068 outSISIDXREG(SISSR, 0x30, v3);
5069 sisfb_post_xgi_delay(ivideo, 0x43);
5070 sisfb_post_xgi_delay(ivideo, 0x43);
5071 sisfb_post_xgi_delay(ivideo, 0x43);
5072}
5073
5074static int __devinit
5075sisfb_post_xgi(struct pci_dev *pdev)
5076{
5077 struct sis_video_info *ivideo = pci_get_drvdata(pdev);
5078 unsigned char *bios = ivideo->bios_abase;
5079 struct pci_dev *mypdev = NULL;
5080 const u8 *ptr, *ptr2;
5081 u8 v1, v2, v3, v4, v5, reg, ramtype;
5082 u32 rega, regb, regd;
5083 int i, j, k, index;
5084 static const u8 cs78[3] = { 0xf6, 0x0d, 0x00 };
5085 static const u8 cs76[2] = { 0xa3, 0xfb };
5086 static const u8 cs7b[3] = { 0xc0, 0x11, 0x00 };
5087 static const u8 cs158[8] = {
5088 0x88, 0xaa, 0x48, 0x00, 0x00, 0x00, 0x00, 0x00
5089 };
5090 static const u8 cs160[8] = {
5091 0x44, 0x77, 0x77, 0x00, 0x00, 0x00, 0x00, 0x00
5092 };
5093 static const u8 cs168[8] = {
5094 0x48, 0x78, 0x88, 0x00, 0x00, 0x00, 0x00, 0x00
5095 };
5096 static const u8 cs128[3 * 8] = {
5097 0x90, 0x28, 0x24, 0x00, 0x00, 0x00, 0x00, 0x00,
5098 0x77, 0x44, 0x44, 0x00, 0x00, 0x00, 0x00, 0x00,
5099 0x77, 0x44, 0x44, 0x00, 0x00, 0x00, 0x00, 0x00
5100 };
5101 static const u8 cs148[2 * 8] = {
5102 0x55, 0x55, 0x55, 0x00, 0x00, 0x00, 0x00, 0x00,
5103 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
5104 };
5105 static const u8 cs31a[8 * 4] = {
5106 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
5107 0xaa, 0xaa, 0xaa, 0xaa, 0x00, 0x00, 0x00, 0x00,
5108 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
5109 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
5110 };
5111 static const u8 cs33a[8 * 4] = {
5112 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
5113 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
5114 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
5115 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
5116 };
5117 static const u8 cs45a[8 * 2] = {
5118 0x00, 0x00, 0xa0, 0x00, 0xa0, 0x00, 0x00, 0x00,
5119 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
5120 };
5121 static const u8 cs170[7 * 8] = {
5122 0x54, 0x32, 0x44, 0x00, 0x00, 0x00, 0x00, 0x00,
5123 0x54, 0x43, 0x44, 0x00, 0x00, 0x00, 0x00, 0x00,
5124 0x0a, 0x05, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00,
5125 0x44, 0x34, 0x44, 0x00, 0x00, 0x00, 0x00, 0x00,
5126 0x10, 0x0a, 0x0a, 0x00, 0x00, 0x00, 0x00, 0x00,
5127 0x11, 0x0c, 0x0c, 0x00, 0x00, 0x00, 0x00, 0x00,
5128 0x05, 0x05, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00
5129 };
5130 static const u8 cs1a8[3 * 8] = {
5131 0xf0, 0xf0, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x00,
5132 0x05, 0x02, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00,
5133 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
5134 };
5135 static const u8 cs100[2 * 8] = {
5136 0xc4, 0x04, 0x84, 0x00, 0x00, 0x00, 0x00, 0x00,
5137 0xc4, 0x04, 0x84, 0x00, 0x00, 0x00, 0x00, 0x00
5138 };
5139
5140 /* VGA enable */
5141 reg = inSISREG(SISVGAENABLE) | 0x01;
5142 outSISREG(SISVGAENABLE, reg);
5143
5144 /* Misc */
5145 reg = inSISREG(SISMISCR) | 0x01;
5146 outSISREG(SISMISCW, reg);
5147
5148 /* Unlock SR */
5149 outSISIDXREG(SISSR, 0x05, 0x86);
5150 inSISIDXREG(SISSR, 0x05, reg);
5151 if(reg != 0xa1)
5152 return 0;
5153
5154 /* Clear some regs */
5155 for(i = 0; i < 0x22; i++) {
5156 if(0x06 + i == 0x20) continue;
5157 outSISIDXREG(SISSR, 0x06 + i, 0x00);
5158 }
5159 for(i = 0; i < 0x0b; i++) {
5160 outSISIDXREG(SISSR, 0x31 + i, 0x00);
5161 }
5162 for(i = 0; i < 0x10; i++) {
5163 outSISIDXREG(SISCR, 0x30 + i, 0x00);
5164 }
5165
5166 ptr = cs78;
5167 if(ivideo->haveXGIROM) {
5168 ptr = (const u8 *)&bios[0x78];
5169 }
5170 for(i = 0; i < 3; i++) {
5171 outSISIDXREG(SISSR, 0x23 + i, ptr[i]);
5172 }
5173
5174 ptr = cs76;
5175 if(ivideo->haveXGIROM) {
5176 ptr = (const u8 *)&bios[0x76];
5177 }
5178 for(i = 0; i < 2; i++) {
5179 outSISIDXREG(SISSR, 0x21 + i, ptr[i]);
5180 }
5181
5182 v1 = 0x18; v2 = 0x00;
5183 if(ivideo->haveXGIROM) {
5184 v1 = bios[0x74];
5185 v2 = bios[0x75];
5186 }
5187 outSISIDXREG(SISSR, 0x07, v1);
5188 outSISIDXREG(SISSR, 0x11, 0x0f);
5189 outSISIDXREG(SISSR, 0x1f, v2);
5190 /* PCI linear mode, RelIO enabled, A0000 decoding disabled */
5191 outSISIDXREG(SISSR, 0x20, 0x80 | 0x20 | 0x04);
5192 outSISIDXREG(SISSR, 0x27, 0x74);
5193
5194 ptr = cs7b;
5195 if(ivideo->haveXGIROM) {
5196 ptr = (const u8 *)&bios[0x7b];
5197 }
5198 for(i = 0; i < 3; i++) {
5199 outSISIDXREG(SISSR, 0x31 + i, ptr[i]);
5200 }
5201
5202 if(ivideo->chip == XGI_40) {
5203 if(ivideo->revision_id == 2) {
5204 setSISIDXREG(SISSR, 0x3b, 0x3f, 0xc0);
5205 }
5206 outSISIDXREG(SISCR, 0x7d, 0xfe);
5207 outSISIDXREG(SISCR, 0x7e, 0x0f);
5208 }
5209 if(ivideo->revision_id == 0) { /* 40 *and* 20? */
5210 andSISIDXREG(SISCR, 0x58, 0xd7);
5211 inSISIDXREG(SISCR, 0xcb, reg);
5212 if(reg & 0x20) {
5213 setSISIDXREG(SISCR, 0x58, 0xd7, (reg & 0x10) ? 0x08 : 0x20); /* =0x28 Z7 ? */
5214 }
5215 }
5216
5217 reg = (ivideo->chip == XGI_40) ? 0x20 : 0x00;
5218 setSISIDXREG(SISCR, 0x38, 0x1f, reg);
5219
5220 if(ivideo->chip == XGI_20) {
5221 outSISIDXREG(SISSR, 0x36, 0x70);
5222 } else {
5223 outSISIDXREG(SISVID, 0x00, 0x86);
5224 outSISIDXREG(SISVID, 0x32, 0x00);
5225 outSISIDXREG(SISVID, 0x30, 0x00);
5226 outSISIDXREG(SISVID, 0x32, 0x01);
5227 outSISIDXREG(SISVID, 0x30, 0x00);
5228 andSISIDXREG(SISVID, 0x2f, 0xdf);
5229 andSISIDXREG(SISCAP, 0x00, 0x3f);
5230
5231 outSISIDXREG(SISPART1, 0x2f, 0x01);
5232 outSISIDXREG(SISPART1, 0x00, 0x00);
5233 outSISIDXREG(SISPART1, 0x02, bios[0x7e]);
5234 outSISIDXREG(SISPART1, 0x2e, 0x08);
5235 andSISIDXREG(SISPART1, 0x35, 0x7f);
5236 andSISIDXREG(SISPART1, 0x50, 0xfe);
5237
5238 inSISIDXREG(SISPART4, 0x00, reg);
5239 if(reg == 1 || reg == 2) {
5240 outSISIDXREG(SISPART2, 0x00, 0x1c);
5241 outSISIDXREG(SISPART4, 0x0d, bios[0x7f]);
5242 outSISIDXREG(SISPART4, 0x0e, bios[0x80]);
5243 outSISIDXREG(SISPART4, 0x10, bios[0x81]);
5244 andSISIDXREG(SISPART4, 0x0f, 0x3f);
5245
5246 inSISIDXREG(SISPART4, 0x01, reg);
5247 if((reg & 0xf0) >= 0xb0) {
5248 inSISIDXREG(SISPART4, 0x23, reg);
5249 if(reg & 0x20) reg |= 0x40;
5250 outSISIDXREG(SISPART4, 0x23, reg);
5251 reg = (reg & 0x20) ? 0x02 : 0x00;
5252 setSISIDXREG(SISPART1, 0x1e, 0xfd, reg);
5253 }
5254 }
5255
5256 v1 = bios[0x77];
5257
5258 inSISIDXREG(SISSR, 0x3b, reg);
5259 if(reg & 0x02) {
5260 inSISIDXREG(SISSR, 0x3a, reg);
5261 v2 = (reg & 0x30) >> 3;
5262 if(!(v2 & 0x04)) v2 ^= 0x02;
5263 inSISIDXREG(SISSR, 0x39, reg);
5264 if(reg & 0x80) v2 |= 0x80;
5265 v2 |= 0x01;
5266
5267 if((mypdev = SIS_PCI_GET_DEVICE(PCI_VENDOR_ID_SI, 0x0730, NULL))) {
5268 SIS_PCI_PUT_DEVICE(mypdev);
5269 if(((v2 & 0x06) == 2) || ((v2 & 0x06) == 4))
5270 v2 &= 0xf9;
5271 v2 |= 0x08;
5272 v1 &= 0xfe;
5273 } else {
5274 mypdev = SIS_PCI_GET_DEVICE(PCI_VENDOR_ID_SI, 0x0735, NULL);
5275 if(!mypdev)
5276 mypdev = SIS_PCI_GET_DEVICE(PCI_VENDOR_ID_SI, 0x0645, NULL);
5277 if(!mypdev)
5278 mypdev = SIS_PCI_GET_DEVICE(PCI_VENDOR_ID_SI, 0x0650, NULL);
5279 if(mypdev) {
5280 pci_read_config_dword(mypdev, 0x94, &regd);
5281 regd &= 0xfffffeff;
5282 pci_write_config_dword(mypdev, 0x94, regd);
5283 v1 &= 0xfe;
5284 SIS_PCI_PUT_DEVICE(mypdev);
5285 } else if(sisfb_find_host_bridge(ivideo, pdev, PCI_VENDOR_ID_SI)) {
5286 v1 &= 0xfe;
5287 } else if(sisfb_find_host_bridge(ivideo, pdev, 0x1106) ||
5288 sisfb_find_host_bridge(ivideo, pdev, 0x1022) ||
5289 sisfb_find_host_bridge(ivideo, pdev, 0x700e) ||
5290 sisfb_find_host_bridge(ivideo, pdev, 0x10de)) {
5291 if((v2 & 0x06) == 4)
5292 v2 ^= 0x06;
5293 v2 |= 0x08;
5294 }
5295 }
5296 setSISIDXREG(SISCR, 0x5f, 0xf0, v2);
5297 }
5298 outSISIDXREG(SISSR, 0x22, v1);
5299
5300 if(ivideo->revision_id == 2) {
5301 inSISIDXREG(SISSR, 0x3b, v1);
5302 inSISIDXREG(SISSR, 0x3a, v2);
5303 regd = bios[0x90 + 3] | (bios[0x90 + 4] << 8);
5304 if( (!(v1 & 0x02)) && (v2 & 0x30) && (regd < 0xcf) )
5305 setSISIDXREG(SISCR, 0x5f, 0xf1, 0x01);
5306
5307 if((mypdev = SIS_PCI_GET_DEVICE(0x10de, 0x01e0, NULL))) {
5308 /* TODO: set CR5f &0xf1 | 0x01 for version 6570
5309 * of nforce 2 ROM
5310 */
5311 if(0)
5312 setSISIDXREG(SISCR, 0x5f, 0xf1, 0x01);
5313 SIS_PCI_PUT_DEVICE(mypdev);
5314 }
5315 }
5316
5317 v1 = 0x30;
5318 inSISIDXREG(SISSR, 0x3b, reg);
5319 inSISIDXREG(SISCR, 0x5f, v2);
5320 if((!(reg & 0x02)) && (v2 & 0x0e))
5321 v1 |= 0x08;
5322 outSISIDXREG(SISSR, 0x27, v1);
5323
5324 if(bios[0x64] & 0x01) {
5325 setSISIDXREG(SISCR, 0x5f, 0xf0, bios[0x64]);
5326 }
5327
5328 v1 = bios[0x4f7];
5329 pci_read_config_dword(pdev, 0x50, &regd);
5330 regd = (regd >> 20) & 0x0f;
5331 if(regd == 1) {
5332 v1 &= 0xfc;
5333 orSISIDXREG(SISCR, 0x5f, 0x08);
5334 }
5335 outSISIDXREG(SISCR, 0x48, v1);
5336
5337 setSISIDXREG(SISCR, 0x47, 0x04, bios[0x4f6] & 0xfb);
5338 setSISIDXREG(SISCR, 0x49, 0xf0, bios[0x4f8] & 0x0f);
5339 setSISIDXREG(SISCR, 0x4a, 0x60, bios[0x4f9] & 0x9f);
5340 setSISIDXREG(SISCR, 0x4b, 0x08, bios[0x4fa] & 0xf7);
5341 setSISIDXREG(SISCR, 0x4c, 0x80, bios[0x4fb] & 0x7f);
5342 outSISIDXREG(SISCR, 0x70, bios[0x4fc]);
5343 setSISIDXREG(SISCR, 0x71, 0xf0, bios[0x4fd] & 0x0f);
5344 outSISIDXREG(SISCR, 0x74, 0xd0);
5345 setSISIDXREG(SISCR, 0x74, 0xcf, bios[0x4fe] & 0x30);
5346 setSISIDXREG(SISCR, 0x75, 0xe0, bios[0x4ff] & 0x1f);
5347 setSISIDXREG(SISCR, 0x76, 0xe0, bios[0x500] & 0x1f);
5348 v1 = bios[0x501];
5349 if((mypdev = SIS_PCI_GET_DEVICE(0x8086, 0x2530, NULL))) {
5350 v1 = 0xf0;
5351 SIS_PCI_PUT_DEVICE(mypdev);
5352 }
5353 outSISIDXREG(SISCR, 0x77, v1);
5354 }
5355
5356 /* RAM type */
5357
5358 regb = 0; /* ! */
5359
5360 v1 = 0xff;
5361 if(ivideo->haveXGIROM) {
5362 v1 = bios[0x140 + regb];
5363 }
5364 outSISIDXREG(SISCR, 0x6d, v1);
5365
5366 ptr = cs128;
5367 if(ivideo->haveXGIROM) {
5368 ptr = (const u8 *)&bios[0x128];
5369 }
5370 for(i = 0, j = 0; i < 3; i++, j += 8) {
5371 outSISIDXREG(SISCR, 0x68 + i, ptr[j + regb]);
5372 }
5373
5374 ptr = cs31a;
5375 ptr2 = cs33a;
5376 if(ivideo->haveXGIROM) {
5377 index = (ivideo->chip == XGI_20) ? 0x31a : 0x3a6;
5378 ptr = (const u8 *)&bios[index];
5379 ptr2 = (const u8 *)&bios[index + 0x20];
5380 }
5381 for(i = 0; i < 2; i++) {
5382 if(i == 0) {
5383 regd = le32_to_cpu(((u32 *)ptr)[regb]);
5384 rega = 0x6b;
5385 } else {
5386 regd = le32_to_cpu(((u32 *)ptr2)[regb]);
5387 rega = 0x6e;
5388 }
5389 reg = 0x00;
5390 for(j = 0; j < 16; j++) {
5391 reg &= 0xf3;
5392 if(regd & 0x01) reg |= 0x04;
5393 if(regd & 0x02) reg |= 0x08;
5394 regd >>= 2;
5395 outSISIDXREG(SISCR, rega, reg);
5396 inSISIDXREG(SISCR, rega, reg);
5397 inSISIDXREG(SISCR, rega, reg);
5398 reg += 0x10;
5399 }
5400 }
5401
5402 andSISIDXREG(SISCR, 0x6e, 0xfc);
5403
5404 ptr = NULL;
5405 if(ivideo->haveXGIROM) {
5406 index = (ivideo->chip == XGI_20) ? 0x35a : 0x3e6;
5407 ptr = (const u8 *)&bios[index];
5408 }
5409 for(i = 0; i < 4; i++) {
5410 setSISIDXREG(SISCR, 0x6e, 0xfc, i);
5411 reg = 0x00;
5412 for(j = 0; j < 2; j++) {
5413 regd = 0;
5414 if(ptr) {
5415 regd = le32_to_cpu(((u32 *)ptr)[regb * 8]);
5416 ptr += 4;
5417 }
5418 /* reg = 0x00; */
5419 for(k = 0; k < 16; k++) {
5420 reg &= 0xfc;
5421 if(regd & 0x01) reg |= 0x01;
5422 if(regd & 0x02) reg |= 0x02;
5423 regd >>= 2;
5424 outSISIDXREG(SISCR, 0x6f, reg);
5425 inSISIDXREG(SISCR, 0x6f, reg);
5426 inSISIDXREG(SISCR, 0x6f, reg);
5427 reg += 0x08;
5428 }
5429 }
5430 }
5431
5432 ptr = cs148;
5433 if(ivideo->haveXGIROM) {
5434 ptr = (const u8 *)&bios[0x148];
5435 }
5436 for(i = 0, j = 0; i < 2; i++, j += 8) {
5437 outSISIDXREG(SISCR, 0x80 + i, ptr[j + regb]);
5438 }
5439
5440 andSISIDXREG(SISCR, 0x89, 0x8f);
5441
5442 ptr = cs45a;
5443 if(ivideo->haveXGIROM) {
5444 index = (ivideo->chip == XGI_20) ? 0x45a : 0x4e6;
5445 ptr = (const u8 *)&bios[index];
5446 }
5447 regd = le16_to_cpu(((const u16 *)ptr)[regb]);
5448 reg = 0x80;
5449 for(i = 0; i < 5; i++) {
5450 reg &= 0xfc;
5451 if(regd & 0x01) reg |= 0x01;
5452 if(regd & 0x02) reg |= 0x02;
5453 regd >>= 2;
5454 outSISIDXREG(SISCR, 0x89, reg);
5455 inSISIDXREG(SISCR, 0x89, reg);
5456 inSISIDXREG(SISCR, 0x89, reg);
5457 reg += 0x10;
5458 }
5459
5460 v1 = 0xb5; v2 = 0x20; v3 = 0xf0; v4 = 0x13;
5461 if(ivideo->haveXGIROM) {
5462 v1 = bios[0x118 + regb];
5463 v2 = bios[0xf8 + regb];
5464 v3 = bios[0x120 + regb];
5465 v4 = bios[0x1ca];
5466 }
5467 outSISIDXREG(SISCR, 0x45, v1 & 0x0f);
5468 outSISIDXREG(SISCR, 0x99, (v1 >> 4) & 0x07);
5469 orSISIDXREG(SISCR, 0x40, v1 & 0x80);
5470 outSISIDXREG(SISCR, 0x41, v2);
5471
5472 ptr = cs170;
5473 if(ivideo->haveXGIROM) {
5474 ptr = (const u8 *)&bios[0x170];
5475 }
5476 for(i = 0, j = 0; i < 7; i++, j += 8) {
5477 outSISIDXREG(SISCR, 0x90 + i, ptr[j + regb]);
5478 }
5479
5480 outSISIDXREG(SISCR, 0x59, v3);
5481
5482 ptr = cs1a8;
5483 if(ivideo->haveXGIROM) {
5484 ptr = (const u8 *)&bios[0x1a8];
5485 }
5486 for(i = 0, j = 0; i < 3; i++, j += 8) {
5487 outSISIDXREG(SISCR, 0xc3 + i, ptr[j + regb]);
5488 }
5489
5490 ptr = cs100;
5491 if(ivideo->haveXGIROM) {
5492 ptr = (const u8 *)&bios[0x100];
5493 }
5494 for(i = 0, j = 0; i < 2; i++, j += 8) {
5495 outSISIDXREG(SISCR, 0x8a + i, ptr[j + regb]);
5496 }
5497
5498 outSISIDXREG(SISCR, 0xcf, v4);
5499
5500 outSISIDXREG(SISCR, 0x83, 0x09);
5501 outSISIDXREG(SISCR, 0x87, 0x00);
5502
5503 if(ivideo->chip == XGI_40) {
5504 if( (ivideo->revision_id == 1) ||
5505 (ivideo->revision_id == 2) ) {
5506 outSISIDXREG(SISCR, 0x8c, 0x87);
5507 }
5508 }
5509
5510 outSISIDXREG(SISSR, 0x17, 0x00);
5511 outSISIDXREG(SISSR, 0x1a, 0x87);
5512
5513 if(ivideo->chip == XGI_20) {
5514 outSISIDXREG(SISSR, 0x15, 0x00);
5515 outSISIDXREG(SISSR, 0x1c, 0x00);
5516 }
5517
5518 ramtype = 0x00; v1 = 0x10;
5519 if(ivideo->haveXGIROM) {
5520 ramtype = bios[0x62];
5521 v1 = bios[0x1d2];
5522 }
5523 if(!(ramtype & 0x80)) {
5524 if(ivideo->chip == XGI_20) {
5525 outSISIDXREG(SISCR, 0x97, v1);
5526 inSISIDXREG(SISCR, 0x97, reg);
5527 if(reg & 0x10) {
5528 ramtype = (reg & 0x01) << 1;
5529 }
5530 } else {
5531 inSISIDXREG(SISSR, 0x39, reg);
5532 ramtype = reg & 0x02;
5533 if(!(ramtype)) {
5534 inSISIDXREG(SISSR, 0x3a, reg);
5535 ramtype = (reg >> 1) & 0x01;
5536 }
5537 }
5538 }
5539 ramtype &= 0x07;
5540
5541 regb = 0; /* ! */
5542
5543 switch(ramtype) {
5544 case 0:
5545 sisfb_post_xgi_setclocks(ivideo, regb);
5546 if((ivideo->chip == XGI_20) ||
5547 (ivideo->revision_id == 1) ||
5548 (ivideo->revision_id == 2)) {
5549 v1 = cs158[regb]; v2 = cs160[regb]; v3 = cs168[regb];
5550 if(ivideo->haveXGIROM) {
5551 v1 = bios[regb + 0x158];
5552 v2 = bios[regb + 0x160];
5553 v3 = bios[regb + 0x168];
5554 }
5555 outSISIDXREG(SISCR, 0x82, v1);
5556 outSISIDXREG(SISCR, 0x85, v2);
5557 outSISIDXREG(SISCR, 0x86, v3);
5558 } else {
5559 outSISIDXREG(SISCR, 0x82, 0x88);
5560 outSISIDXREG(SISCR, 0x86, 0x00);
5561 inSISIDXREG(SISCR, 0x86, reg);
5562 outSISIDXREG(SISCR, 0x86, 0x88);
5563 inSISIDXREG(SISCR, 0x86, reg);
5564 outSISIDXREG(SISCR, 0x86, bios[regb + 0x168]);
5565 outSISIDXREG(SISCR, 0x82, 0x77);
5566 outSISIDXREG(SISCR, 0x85, 0x00);
5567 inSISIDXREG(SISCR, 0x85, reg);
5568 outSISIDXREG(SISCR, 0x85, 0x88);
5569 inSISIDXREG(SISCR, 0x85, reg);
5570 outSISIDXREG(SISCR, 0x85, bios[regb + 0x160]);
5571 outSISIDXREG(SISCR, 0x82, bios[regb + 0x158]);
5572 }
5573 if(ivideo->chip == XGI_40) {
5574 outSISIDXREG(SISCR, 0x97, 0x00);
5575 }
5576 outSISIDXREG(SISCR, 0x98, 0x01);
5577 outSISIDXREG(SISCR, 0x9a, 0x02);
5578
5579 outSISIDXREG(SISSR, 0x18, 0x01);
5580 if((ivideo->chip == XGI_20) ||
5581 (ivideo->revision_id == 2)) {
5582 outSISIDXREG(SISSR, 0x19, 0x40);
5583 } else {
5584 outSISIDXREG(SISSR, 0x19, 0x20);
5585 }
5586 outSISIDXREG(SISSR, 0x16, 0x00);
5587 outSISIDXREG(SISSR, 0x16, 0x80);
5588 if((ivideo->chip == XGI_20) || (bios[0x1cb] != 0x0c)) {
5589 sisfb_post_xgi_delay(ivideo, 0x43);
5590 sisfb_post_xgi_delay(ivideo, 0x43);
5591 sisfb_post_xgi_delay(ivideo, 0x43);
5592 outSISIDXREG(SISSR, 0x18, 0x00);
5593 if((ivideo->chip == XGI_20) ||
5594 (ivideo->revision_id == 2)) {
5595 outSISIDXREG(SISSR, 0x19, 0x40);
5596 } else {
5597 outSISIDXREG(SISSR, 0x19, 0x20);
5598 }
5599 } else if((ivideo->chip == XGI_40) && (bios[0x1cb] == 0x0c)) {
5600 /* outSISIDXREG(SISSR, 0x16, 0x0c); */ /* ? */
5601 }
5602 outSISIDXREG(SISSR, 0x16, 0x00);
5603 outSISIDXREG(SISSR, 0x16, 0x80);
5604 sisfb_post_xgi_delay(ivideo, 4);
5605 v1 = 0x31; v2 = 0x03; v3 = 0x83; v4 = 0x03; v5 = 0x83;
5606 if(ivideo->haveXGIROM) {
5607 v1 = bios[0xf0];
5608 index = (ivideo->chip == XGI_20) ? 0x4b2 : 0x53e;
5609 v2 = bios[index];
5610 v3 = bios[index + 1];
5611 v4 = bios[index + 2];
5612 v5 = bios[index + 3];
5613 }
5614 outSISIDXREG(SISSR, 0x18, v1);
5615 outSISIDXREG(SISSR, 0x19, ((ivideo->chip == XGI_20) ? 0x02 : 0x01));
5616 outSISIDXREG(SISSR, 0x16, v2);
5617 outSISIDXREG(SISSR, 0x16, v3);
5618 sisfb_post_xgi_delay(ivideo, 0x43);
5619 outSISIDXREG(SISSR, 0x1b, 0x03);
5620 sisfb_post_xgi_delay(ivideo, 0x22);
5621 outSISIDXREG(SISSR, 0x18, v1);
5622 outSISIDXREG(SISSR, 0x19, 0x00);
5623 outSISIDXREG(SISSR, 0x16, v4);
5624 outSISIDXREG(SISSR, 0x16, v5);
5625 outSISIDXREG(SISSR, 0x1b, 0x00);
5626 break;
5627 case 1:
5628 outSISIDXREG(SISCR, 0x82, 0x77);
5629 outSISIDXREG(SISCR, 0x86, 0x00);
5630 inSISIDXREG(SISCR, 0x86, reg);
5631 outSISIDXREG(SISCR, 0x86, 0x88);
5632 inSISIDXREG(SISCR, 0x86, reg);
5633 v1 = cs168[regb]; v2 = cs160[regb]; v3 = cs158[regb];
5634 if(ivideo->haveXGIROM) {
5635 v1 = bios[regb + 0x168];
5636 v2 = bios[regb + 0x160];
5637 v3 = bios[regb + 0x158];
5638 }
5639 outSISIDXREG(SISCR, 0x86, v1);
5640 outSISIDXREG(SISCR, 0x82, 0x77);
5641 outSISIDXREG(SISCR, 0x85, 0x00);
5642 inSISIDXREG(SISCR, 0x85, reg);
5643 outSISIDXREG(SISCR, 0x85, 0x88);
5644 inSISIDXREG(SISCR, 0x85, reg);
5645 outSISIDXREG(SISCR, 0x85, v2);
5646 outSISIDXREG(SISCR, 0x82, v3);
5647 outSISIDXREG(SISCR, 0x98, 0x01);
5648 outSISIDXREG(SISCR, 0x9a, 0x02);
5649
5650 outSISIDXREG(SISSR, 0x28, 0x64);
5651 outSISIDXREG(SISSR, 0x29, 0x63);
5652 sisfb_post_xgi_delay(ivideo, 15);
5653 outSISIDXREG(SISSR, 0x18, 0x00);
5654 outSISIDXREG(SISSR, 0x19, 0x20);
5655 outSISIDXREG(SISSR, 0x16, 0x00);
5656 outSISIDXREG(SISSR, 0x16, 0x80);
5657 outSISIDXREG(SISSR, 0x18, 0xc5);
5658 outSISIDXREG(SISSR, 0x19, 0x23);
5659 outSISIDXREG(SISSR, 0x16, 0x00);
5660 outSISIDXREG(SISSR, 0x16, 0x80);
5661 sisfb_post_xgi_delay(ivideo, 1);
5662 outSISIDXREG(SISCR, 0x97,0x11);
5663 sisfb_post_xgi_setclocks(ivideo, regb);
5664 sisfb_post_xgi_delay(ivideo, 0x46);
5665 outSISIDXREG(SISSR, 0x18, 0xc5);
5666 outSISIDXREG(SISSR, 0x19, 0x23);
5667 outSISIDXREG(SISSR, 0x16, 0x00);
5668 outSISIDXREG(SISSR, 0x16, 0x80);
5669 sisfb_post_xgi_delay(ivideo, 1);
5670 outSISIDXREG(SISSR, 0x1b, 0x04);
5671 sisfb_post_xgi_delay(ivideo, 1);
5672 outSISIDXREG(SISSR, 0x1b, 0x00);
5673 sisfb_post_xgi_delay(ivideo, 1);
5674 v1 = 0x31;
5675 if(ivideo->haveXGIROM) {
5676 v1 = bios[0xf0];
5677 }
5678 outSISIDXREG(SISSR, 0x18, v1);
5679 outSISIDXREG(SISSR, 0x19, 0x06);
5680 outSISIDXREG(SISSR, 0x16, 0x04);
5681 outSISIDXREG(SISSR, 0x16, 0x84);
5682 sisfb_post_xgi_delay(ivideo, 1);
5683 break;
5684 default:
5685 sisfb_post_xgi_setclocks(ivideo, regb);
5686 if((ivideo->chip == XGI_40) &&
5687 ((ivideo->revision_id == 1) ||
5688 (ivideo->revision_id == 2))) {
5689 outSISIDXREG(SISCR, 0x82, bios[regb + 0x158]);
5690 outSISIDXREG(SISCR, 0x85, bios[regb + 0x160]);
5691 outSISIDXREG(SISCR, 0x86, bios[regb + 0x168]);
5692 } else {
5693 outSISIDXREG(SISCR, 0x82, 0x88);
5694 outSISIDXREG(SISCR, 0x86, 0x00);
5695 inSISIDXREG(SISCR, 0x86, reg);
5696 outSISIDXREG(SISCR, 0x86, 0x88);
5697 outSISIDXREG(SISCR, 0x82, 0x77);
5698 outSISIDXREG(SISCR, 0x85, 0x00);
5699 inSISIDXREG(SISCR, 0x85, reg);
5700 outSISIDXREG(SISCR, 0x85, 0x88);
5701 inSISIDXREG(SISCR, 0x85, reg);
5702 v1 = cs160[regb]; v2 = cs158[regb];
5703 if(ivideo->haveXGIROM) {
5704 v1 = bios[regb + 0x160];
5705 v2 = bios[regb + 0x158];
5706 }
5707 outSISIDXREG(SISCR, 0x85, v1);
5708 outSISIDXREG(SISCR, 0x82, v2);
5709 }
5710 if(ivideo->chip == XGI_40) {
5711 outSISIDXREG(SISCR, 0x97, 0x11);
5712 }
5713 if((ivideo->chip == XGI_40) && (ivideo->revision_id == 2)) {
5714 outSISIDXREG(SISCR, 0x98, 0x01);
5715 } else {
5716 outSISIDXREG(SISCR, 0x98, 0x03);
5717 }
5718 outSISIDXREG(SISCR, 0x9a, 0x02);
5719
5720 if(ivideo->chip == XGI_40) {
5721 outSISIDXREG(SISSR, 0x18, 0x01);
5722 } else {
5723 outSISIDXREG(SISSR, 0x18, 0x00);
5724 }
5725 outSISIDXREG(SISSR, 0x19, 0x40);
5726 outSISIDXREG(SISSR, 0x16, 0x00);
5727 outSISIDXREG(SISSR, 0x16, 0x80);
5728 if((ivideo->chip == XGI_40) && (bios[0x1cb] != 0x0c)) {
5729 sisfb_post_xgi_delay(ivideo, 0x43);
5730 sisfb_post_xgi_delay(ivideo, 0x43);
5731 sisfb_post_xgi_delay(ivideo, 0x43);
5732 outSISIDXREG(SISSR, 0x18, 0x00);
5733 outSISIDXREG(SISSR, 0x19, 0x40);
5734 outSISIDXREG(SISSR, 0x16, 0x00);
5735 outSISIDXREG(SISSR, 0x16, 0x80);
5736 }
5737 sisfb_post_xgi_delay(ivideo, 4);
5738 v1 = 0x31;
5739 if(ivideo->haveXGIROM) {
5740 v1 = bios[0xf0];
5741 }
5742 outSISIDXREG(SISSR, 0x18, v1);
5743 outSISIDXREG(SISSR, 0x19, 0x01);
5744 if(ivideo->chip == XGI_40) {
5745 outSISIDXREG(SISSR, 0x16, bios[0x53e]);
5746 outSISIDXREG(SISSR, 0x16, bios[0x53f]);
5747 } else {
5748 outSISIDXREG(SISSR, 0x16, 0x05);
5749 outSISIDXREG(SISSR, 0x16, 0x85);
5750 }
5751 sisfb_post_xgi_delay(ivideo, 0x43);
5752 if(ivideo->chip == XGI_40) {
5753 outSISIDXREG(SISSR, 0x1b, 0x01);
5754 } else {
5755 outSISIDXREG(SISSR, 0x1b, 0x03);
5756 }
5757 sisfb_post_xgi_delay(ivideo, 0x22);
5758 outSISIDXREG(SISSR, 0x18, v1);
5759 outSISIDXREG(SISSR, 0x19, 0x00);
5760 if(ivideo->chip == XGI_40) {
5761 outSISIDXREG(SISSR, 0x16, bios[0x540]);
5762 outSISIDXREG(SISSR, 0x16, bios[0x541]);
5763 } else {
5764 outSISIDXREG(SISSR, 0x16, 0x05);
5765 outSISIDXREG(SISSR, 0x16, 0x85);
5766 }
5767 outSISIDXREG(SISSR, 0x1b, 0x00);
5768 }
5769
5770 regb = 0; /* ! */
5771 v1 = 0x03;
5772 if(ivideo->haveXGIROM) {
5773 v1 = bios[0x110 + regb];
5774 }
5775 outSISIDXREG(SISSR, 0x1b, v1);
5776
5777 /* RAM size */
5778 v1 = 0x00; v2 = 0x00;
5779 if(ivideo->haveXGIROM) {
5780 v1 = bios[0x62];
5781 v2 = bios[0x63];
5782 }
5783 regb = 0; /* ! */
5784 regd = 1 << regb;
5785 if((v1 & 0x40) && (v2 & regd) && ivideo->haveXGIROM) {
5786
5787 outSISIDXREG(SISSR, 0x13, bios[regb + 0xe0]);
5788 outSISIDXREG(SISSR, 0x14, bios[regb + 0xe0 + 8]);
5789
5790 } else {
5791
5792 /* Set default mode, don't clear screen */
5793 ivideo->SiS_Pr.SiS_UseOEM = FALSE;
5794 SiS_SetEnableDstn(&ivideo->SiS_Pr, FALSE);
5795 SiS_SetEnableFstn(&ivideo->SiS_Pr, FALSE);
5796 ivideo->curFSTN = ivideo->curDSTN = 0;
5797 ivideo->SiS_Pr.VideoMemorySize = 8 << 20;
5798 SiSSetMode(&ivideo->SiS_Pr, 0x2e | 0x80);
5799
5800 outSISIDXREG(SISSR, 0x05, 0x86);
5801
5802 /* Disable read-cache */
5803 andSISIDXREG(SISSR, 0x21, 0xdf);
5804 sisfb_post_xgi_ramsize(ivideo);
5805 /* Enable read-cache */
5806 orSISIDXREG(SISSR, 0x21, 0x20);
5807
5808 }
5809
5810#if 0
5811 printk(KERN_DEBUG "-----------------\n");
5812 for(i = 0; i < 0xff; i++) {
5813 inSISIDXREG(SISCR, i, reg);
5814 printk(KERN_DEBUG "CR%02x(%x) = 0x%02x\n", i, SISCR, reg);
5815 }
5816 for(i = 0; i < 0x40; i++) {
5817 inSISIDXREG(SISSR, i, reg);
5818 printk(KERN_DEBUG "SR%02x(%x) = 0x%02x\n", i, SISSR, reg);
5819 }
5820 printk(KERN_DEBUG "-----------------\n");
5821#endif
5822
5823 /* Sense CRT1 */
5824 if(ivideo->chip == XGI_20) {
5825 orSISIDXREG(SISCR, 0x32, 0x20);
5826 } else {
5827 inSISIDXREG(SISPART4, 0x00, reg);
5828 if((reg == 1) || (reg == 2)) {
5829 sisfb_sense_crt1(ivideo);
5830 } else {
5831 orSISIDXREG(SISCR, 0x32, 0x20);
5832 }
5833 }
5834
5835 /* Set default mode, don't clear screen */
5836 ivideo->SiS_Pr.SiS_UseOEM = FALSE;
5837 SiS_SetEnableDstn(&ivideo->SiS_Pr, FALSE);
5838 SiS_SetEnableFstn(&ivideo->SiS_Pr, FALSE);
5839 ivideo->curFSTN = ivideo->curDSTN = 0;
5840 SiSSetMode(&ivideo->SiS_Pr, 0x2e | 0x80);
5841
5842 outSISIDXREG(SISSR, 0x05, 0x86);
5843
5844 /* Display off */
5845 orSISIDXREG(SISSR, 0x01, 0x20);
5846
5847 /* Save mode number in CR34 */
5848 outSISIDXREG(SISCR, 0x34, 0x2e);
5849
5850 /* Let everyone know what the current mode is */
5851 ivideo->modeprechange = 0x2e;
5852
5853 if(ivideo->chip == XGI_40) {
5854 inSISIDXREG(SISCR, 0xca, reg);
5855 inSISIDXREG(SISCR, 0xcc, v1);
5856 if((reg & 0x10) && (!(v1 & 0x04))) {
5857 printk(KERN_ERR
5858 "sisfb: Please connect power to the card.\n");
5859 return 0;
5860 }
5861 }
5862
5863 return 1;
5864}
5865#endif
5866
5867static int __devinit
5868sisfb_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
5869{
5870 struct sisfb_chip_info *chipinfo = &sisfb_chip_info[ent->driver_data];
5871 struct sis_video_info *ivideo = NULL;
5872 struct fb_info *sis_fb_info = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005873 u16 reg16;
5874 u8 reg;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07005875 int i, ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005876
Thomas Winischhofer544393f2005-09-09 13:04:45 -07005877 if(sisfb_off)
5878 return -ENXIO;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005879
5880#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,3))
5881 sis_fb_info = framebuffer_alloc(sizeof(*ivideo), &pdev->dev);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07005882 if(!sis_fb_info)
5883 return -ENOMEM;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005884#else
5885 sis_fb_info = kmalloc(sizeof(*sis_fb_info) + sizeof(*ivideo), GFP_KERNEL);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07005886 if(!sis_fb_info)
5887 return -ENOMEM;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005888 memset(sis_fb_info, 0, sizeof(*sis_fb_info) + sizeof(*ivideo));
5889 sis_fb_info->par = ((char *)sis_fb_info + sizeof(*sis_fb_info));
5890#endif
5891
5892 ivideo = (struct sis_video_info *)sis_fb_info->par;
5893 ivideo->memyselfandi = sis_fb_info;
5894
Thomas Winischhofer544393f2005-09-09 13:04:45 -07005895 ivideo->sisfb_id = SISFB_ID;
5896
Linus Torvalds1da177e2005-04-16 15:20:36 -07005897 if(card_list == NULL) {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07005898 ivideo->cardnumber = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005899 } else {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07005900 struct sis_video_info *countvideo = card_list;
5901 ivideo->cardnumber = 1;
5902 while((countvideo = countvideo->next) != 0)
5903 ivideo->cardnumber++;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005904 }
5905
5906 strncpy(ivideo->myid, chipinfo->chip_name, 30);
5907
5908 ivideo->warncount = 0;
5909 ivideo->chip_id = pdev->device;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07005910 ivideo->chip_vendor = pdev->vendor;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005911 pci_read_config_byte(pdev, PCI_REVISION_ID, &ivideo->revision_id);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07005912 ivideo->SiS_Pr.ChipRevision = ivideo->revision_id;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005913 pci_read_config_word(pdev, PCI_COMMAND, &reg16);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07005914 ivideo->sisvga_enabled = reg16 & 0x01;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005915 ivideo->pcibus = pdev->bus->number;
5916 ivideo->pcislot = PCI_SLOT(pdev->devfn);
5917 ivideo->pcifunc = PCI_FUNC(pdev->devfn);
5918 ivideo->subsysvendor = pdev->subsystem_vendor;
5919 ivideo->subsysdevice = pdev->subsystem_device;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07005920#ifdef SIS_OLD_CONFIG_COMPAT
5921 ivideo->ioctl32registered = 0;
5922#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -07005923
5924#ifndef MODULE
5925 if(sisfb_mode_idx == -1) {
5926 sisfb_get_vga_mode_from_kernel();
5927 }
5928#endif
5929
5930 ivideo->chip = chipinfo->chip;
5931 ivideo->sisvga_engine = chipinfo->vgaengine;
5932 ivideo->hwcursor_size = chipinfo->hwcursor_size;
5933 ivideo->CRT2_write_enable = chipinfo->CRT2_write_enable;
5934 ivideo->mni = chipinfo->mni;
5935
5936 ivideo->detectedpdc = 0xff;
5937 ivideo->detectedpdca = 0xff;
5938 ivideo->detectedlcda = 0xff;
5939
5940 ivideo->sisfb_thismonitor.datavalid = FALSE;
5941
Thomas Winischhofer544393f2005-09-09 13:04:45 -07005942 ivideo->current_base = 0;
5943
5944 ivideo->engineok = 0;
5945
5946 ivideo->sisfb_was_boot_device = 0;
5947#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,12))
5948 if(pdev->resource[PCI_ROM_RESOURCE].flags & IORESOURCE_ROM_SHADOW) {
5949 if(ivideo->sisvga_enabled)
5950 ivideo->sisfb_was_boot_device = 1;
5951 else {
5952 printk(KERN_DEBUG "sisfb: PCI device is disabled, "
5953 "but marked as boot video device ???\n");
5954 printk(KERN_DEBUG "sisfb: I will not accept this "
5955 "as the primary VGA device\n");
5956 }
5957 }
5958#endif
5959
Linus Torvalds1da177e2005-04-16 15:20:36 -07005960 ivideo->sisfb_parm_mem = sisfb_parm_mem;
5961 ivideo->sisfb_accel = sisfb_accel;
5962 ivideo->sisfb_ypan = sisfb_ypan;
5963 ivideo->sisfb_max = sisfb_max;
5964 ivideo->sisfb_userom = sisfb_userom;
5965 ivideo->sisfb_useoem = sisfb_useoem;
5966 ivideo->sisfb_mode_idx = sisfb_mode_idx;
5967 ivideo->sisfb_parm_rate = sisfb_parm_rate;
5968 ivideo->sisfb_crt1off = sisfb_crt1off;
5969 ivideo->sisfb_forcecrt1 = sisfb_forcecrt1;
5970 ivideo->sisfb_crt2type = sisfb_crt2type;
5971 ivideo->sisfb_crt2flags = sisfb_crt2flags;
5972 /* pdc(a), scalelcd, special timing, lvdshl handled below */
5973 ivideo->sisfb_dstn = sisfb_dstn;
5974 ivideo->sisfb_fstn = sisfb_fstn;
5975 ivideo->sisfb_tvplug = sisfb_tvplug;
5976 ivideo->sisfb_tvstd = sisfb_tvstd;
5977 ivideo->tvxpos = sisfb_tvxposoffset;
5978 ivideo->tvypos = sisfb_tvyposoffset;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005979 ivideo->sisfb_nocrt2rate = sisfb_nocrt2rate;
5980#if LINUX_VERSION_CODE <= KERNEL_VERSION(2,5,0)
5981 ivideo->sisfb_inverse = sisfb_inverse;
5982#endif
5983
5984 ivideo->refresh_rate = 0;
5985 if(ivideo->sisfb_parm_rate != -1) {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07005986 ivideo->refresh_rate = ivideo->sisfb_parm_rate;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005987 }
5988
5989 ivideo->SiS_Pr.UsePanelScaler = sisfb_scalelcd;
5990 ivideo->SiS_Pr.CenterScreen = -1;
5991 ivideo->SiS_Pr.SiS_CustomT = sisfb_specialtiming;
5992 ivideo->SiS_Pr.LVDSHL = sisfb_lvdshl;
5993
5994 ivideo->SiS_Pr.SiS_Backup70xx = 0xff;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07005995 ivideo->SiS_Pr.SiS_CHOverScan = -1;
5996 ivideo->SiS_Pr.SiS_ChSW = FALSE;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005997 ivideo->SiS_Pr.SiS_UseLCDA = FALSE;
5998 ivideo->SiS_Pr.HaveEMI = FALSE;
5999 ivideo->SiS_Pr.HaveEMILCD = FALSE;
6000 ivideo->SiS_Pr.OverruleEMI = FALSE;
6001 ivideo->SiS_Pr.SiS_SensibleSR11 = FALSE;
6002 ivideo->SiS_Pr.SiS_MyCR63 = 0x63;
6003 ivideo->SiS_Pr.PDC = -1;
6004 ivideo->SiS_Pr.PDCA = -1;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006005 ivideo->SiS_Pr.DDCPortMixup = FALSE;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006006#ifdef CONFIG_FB_SIS_315
6007 if(ivideo->chip >= SIS_330) {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006008 ivideo->SiS_Pr.SiS_MyCR63 = 0x53;
6009 if(ivideo->chip >= SIS_661) {
6010 ivideo->SiS_Pr.SiS_SensibleSR11 = TRUE;
6011 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07006012 }
6013#endif
6014
6015 memcpy(&ivideo->default_var, &my_default_var, sizeof(my_default_var));
6016
6017 pci_set_drvdata(pdev, ivideo);
6018
6019 /* Patch special cases */
6020 if((ivideo->nbridge = sisfb_get_northbridge(ivideo->chip))) {
6021 switch(ivideo->nbridge->device) {
6022#ifdef CONFIG_FB_SIS_300
6023 case PCI_DEVICE_ID_SI_730:
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006024 ivideo->chip = SIS_730;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006025 strcpy(ivideo->myid, "SiS 730");
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006026 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006027#endif
6028#ifdef CONFIG_FB_SIS_315
6029 case PCI_DEVICE_ID_SI_651:
6030 /* ivideo->chip is ok */
6031 strcpy(ivideo->myid, "SiS 651");
6032 break;
6033 case PCI_DEVICE_ID_SI_740:
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006034 ivideo->chip = SIS_740;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006035 strcpy(ivideo->myid, "SiS 740");
6036 break;
6037 case PCI_DEVICE_ID_SI_661:
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006038 ivideo->chip = SIS_661;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006039 strcpy(ivideo->myid, "SiS 661");
6040 break;
6041 case PCI_DEVICE_ID_SI_741:
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006042 ivideo->chip = SIS_741;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006043 strcpy(ivideo->myid, "SiS 741");
6044 break;
6045 case PCI_DEVICE_ID_SI_760:
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006046 ivideo->chip = SIS_760;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006047 strcpy(ivideo->myid, "SiS 760");
6048 break;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006049 case PCI_DEVICE_ID_SI_761:
6050 ivideo->chip = SIS_761;
6051 strcpy(ivideo->myid, "SiS 761");
6052 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006053#endif
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006054 default:
6055 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006056 }
6057 }
6058
6059#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
6060 strcpy(sis_fb_info->modename, ivideo->myid);
6061#endif
6062
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006063 ivideo->SiS_Pr.ChipType = ivideo->chip;
6064
6065 ivideo->SiS_Pr.ivideo = (void *)ivideo;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006066
6067#ifdef CONFIG_FB_SIS_315
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006068 if((ivideo->SiS_Pr.ChipType == SIS_315PRO) ||
6069 (ivideo->SiS_Pr.ChipType == SIS_315)) {
6070 ivideo->SiS_Pr.ChipType = SIS_315H;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006071 }
6072#endif
6073
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006074 if(!ivideo->sisvga_enabled) {
6075 if(pci_enable_device(pdev)) {
6076 if(ivideo->nbridge) SIS_PCI_PUT_DEVICE(ivideo->nbridge);
6077 pci_set_drvdata(pdev, NULL);
6078 kfree(sis_fb_info);
6079 return -EIO;
6080 }
6081 }
6082
Linus Torvalds1da177e2005-04-16 15:20:36 -07006083 ivideo->video_base = pci_resource_start(pdev, 0);
6084 ivideo->mmio_base = pci_resource_start(pdev, 1);
6085 ivideo->mmio_size = pci_resource_len(pdev, 1);
6086 ivideo->SiS_Pr.RelIO = pci_resource_start(pdev, 2) + 0x30;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006087 ivideo->SiS_Pr.IOAddress = ivideo->vga_base = ivideo->SiS_Pr.RelIO;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006088
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006089 SiSRegInit(&ivideo->SiS_Pr, ivideo->SiS_Pr.IOAddress);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006090
6091#ifdef CONFIG_FB_SIS_300
6092 /* Find PCI systems for Chrontel/GPIO communication setup */
6093 if(ivideo->chip == SIS_630) {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006094 i = 0;
6095 do {
6096 if(mychswtable[i].subsysVendor == ivideo->subsysvendor &&
6097 mychswtable[i].subsysCard == ivideo->subsysdevice) {
6098 ivideo->SiS_Pr.SiS_ChSW = TRUE;
6099 printk(KERN_DEBUG "sisfb: Identified [%s %s] "
6100 "requiring Chrontel/GPIO setup\n",
6101 mychswtable[i].vendorName,
6102 mychswtable[i].cardName);
6103 ivideo->lpcdev = SIS_PCI_GET_DEVICE(PCI_VENDOR_ID_SI, 0x0008, NULL);
6104 break;
6105 }
6106 i++;
6107 } while(mychswtable[i].subsysVendor != 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006108 }
6109#endif
6110
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006111#ifdef CONFIG_FB_SIS_315
6112 if((ivideo->chip == SIS_760) && (ivideo->nbridge)) {
6113 ivideo->lpcdev = SIS_PCI_GET_SLOT(ivideo->nbridge->bus, (2 << 3));
6114 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07006115#endif
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006116
6117 outSISIDXREG(SISSR, 0x05, 0x86);
6118
6119 if( (!ivideo->sisvga_enabled)
6120#if !defined(__i386__) && !defined(__x86_64__)
6121 || (sisfb_resetcard)
6122#endif
6123 ) {
6124 for(i = 0x30; i <= 0x3f; i++) {
6125 outSISIDXREG(SISCR, i, 0x00);
6126 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07006127 }
6128
6129 /* Find out about current video mode */
6130 ivideo->modeprechange = 0x03;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006131 inSISIDXREG(SISCR, 0x34, reg);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006132 if(reg & 0x7f) {
6133 ivideo->modeprechange = reg & 0x7f;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006134 } else if(ivideo->sisvga_enabled) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07006135#if defined(__i386__) || defined(__x86_64__)
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006136 unsigned char SIS_IOTYPE2 *tt = ioremap(0x400, 0x100);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006137 if(tt) {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006138 ivideo->modeprechange = readb(tt + 0x49);
6139 iounmap(tt);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006140 }
6141#endif
6142 }
6143
6144#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
6145#ifdef MODULE
6146 if((reg & 0x80) && (reg != 0xff)) {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006147 if((sisbios_mode[ivideo->sisfb_mode_idx].mode_no[ivideo->mni])
6148 != 0xFF) {
6149 printk(KERN_INFO "sisfb: Cannot initialize display mode, "
6150 "X server is active\n");
6151 ret = -EBUSY;
6152 goto error_4;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006153 }
6154 }
6155#endif
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006156#endif
6157
6158 /* Search and copy ROM image */
6159 ivideo->bios_abase = NULL;
6160 ivideo->SiS_Pr.VirtualRomBase = NULL;
6161 ivideo->SiS_Pr.UseROM = FALSE;
6162 ivideo->haveXGIROM = ivideo->SiS_Pr.SiS_XGIROM = FALSE;
6163 if(ivideo->sisfb_userom) {
6164 ivideo->SiS_Pr.VirtualRomBase = sisfb_find_rom(pdev);
6165 ivideo->bios_abase = ivideo->SiS_Pr.VirtualRomBase;
6166 ivideo->SiS_Pr.UseROM = (ivideo->SiS_Pr.VirtualRomBase) ? TRUE : FALSE;
6167 printk(KERN_INFO "sisfb: Video ROM %sfound\n",
6168 ivideo->SiS_Pr.UseROM ? "" : "not ");
6169 if((ivideo->SiS_Pr.UseROM) && (ivideo->chip >= XGI_20)) {
6170 ivideo->SiS_Pr.UseROM = FALSE;
6171 ivideo->haveXGIROM = ivideo->SiS_Pr.SiS_XGIROM = TRUE;
6172 if( (ivideo->revision_id == 2) &&
6173 (!(ivideo->bios_abase[0x1d1] & 0x01)) ) {
6174 ivideo->SiS_Pr.DDCPortMixup = TRUE;
6175 }
6176 }
6177 } else {
6178 printk(KERN_INFO "sisfb: Video ROM usage disabled\n");
6179 }
6180
6181 /* Find systems for special custom timing */
6182 if(ivideo->SiS_Pr.SiS_CustomT == CUT_NONE) {
6183 sisfb_detect_custom_timing(ivideo);
6184 }
6185
6186 /* POST card in case this has not been done by the BIOS */
6187 if( (!ivideo->sisvga_enabled)
6188#if !defined(__i386__) && !defined(__x86_64__)
6189 || (sisfb_resetcard)
6190#endif
6191 ) {
6192#ifdef CONFIG_FB_SIS_300
6193 if(ivideo->sisvga_engine == SIS_300_VGA) {
6194 if(ivideo->chip == SIS_300) {
6195 sisfb_post_sis300(pdev);
6196 ivideo->sisfb_can_post = 1;
6197 }
6198 }
6199#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -07006200
6201#ifdef CONFIG_FB_SIS_315
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006202 if(ivideo->sisvga_engine == SIS_315_VGA) {
6203 int result = 1;
6204 /* if((ivideo->chip == SIS_315H) ||
Linus Torvalds1da177e2005-04-16 15:20:36 -07006205 (ivideo->chip == SIS_315) ||
6206 (ivideo->chip == SIS_315PRO) ||
6207 (ivideo->chip == SIS_330)) {
6208 sisfb_post_sis315330(pdev);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006209 } else */ if(ivideo->chip == XGI_20) {
6210 result = sisfb_post_xgi(pdev);
6211 ivideo->sisfb_can_post = 1;
6212 } else if((ivideo->chip == XGI_40) && ivideo->haveXGIROM) {
6213 result = sisfb_post_xgi(pdev);
6214 ivideo->sisfb_can_post = 1;
6215 } else {
6216 printk(KERN_INFO "sisfb: Card is not "
6217 "POSTed and sisfb can't do this either.\n");
6218 }
6219 if(!result) {
6220 printk(KERN_ERR "sisfb: Failed to POST card\n");
6221 ret = -ENODEV;
6222 goto error_3;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006223 }
6224 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07006225#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -07006226 }
6227
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006228 ivideo->sisfb_card_posted = 1;
6229
6230 /* Find out about RAM size */
6231 if(sisfb_get_dram_size(ivideo)) {
6232 printk(KERN_INFO "sisfb: Fatal error: Unable to determine VRAM size.\n");
6233 ret = -ENODEV;
6234 goto error_3;
6235 }
6236
6237
6238 /* Enable PCI addressing and MMIO */
Linus Torvalds1da177e2005-04-16 15:20:36 -07006239 if((ivideo->sisfb_mode_idx < 0) ||
6240 ((sisbios_mode[ivideo->sisfb_mode_idx].mode_no[ivideo->mni]) != 0xFF)) {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006241 /* Enable PCI_LINEAR_ADDRESSING and MMIO_ENABLE */
6242 orSISIDXREG(SISSR, IND_SIS_PCI_ADDRESS_SET, (SIS_PCI_ADDR_ENABLE | SIS_MEM_MAP_IO_ENABLE));
6243 /* Enable 2D accelerator engine */
6244 orSISIDXREG(SISSR, IND_SIS_MODULE_ENABLE, SIS_ENABLE_2D);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006245 }
6246
6247 if(sisfb_pdc != 0xff) {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006248 if(ivideo->sisvga_engine == SIS_300_VGA)
6249 sisfb_pdc &= 0x3c;
6250 else
6251 sisfb_pdc &= 0x1f;
6252 ivideo->SiS_Pr.PDC = sisfb_pdc;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006253 }
6254#ifdef CONFIG_FB_SIS_315
6255 if(ivideo->sisvga_engine == SIS_315_VGA) {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006256 if(sisfb_pdca != 0xff)
6257 ivideo->SiS_Pr.PDCA = sisfb_pdca & 0x1f;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006258 }
6259#endif
6260
6261 if(!request_mem_region(ivideo->video_base, ivideo->video_size, "sisfb FB")) {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006262 printk(KERN_ERR "sisfb: Fatal error: Unable to reserve %dMB framebuffer memory\n",
6263 (int)(ivideo->video_size >> 20));
Linus Torvalds1da177e2005-04-16 15:20:36 -07006264 printk(KERN_ERR "sisfb: Is there another framebuffer driver active?\n");
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006265 ret = -ENODEV;
6266 goto error_3;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006267 }
6268
6269 if(!request_mem_region(ivideo->mmio_base, ivideo->mmio_size, "sisfb MMIO")) {
6270 printk(KERN_ERR "sisfb: Fatal error: Unable to reserve MMIO region\n");
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006271 ret = -ENODEV;
6272 goto error_2;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006273 }
6274
6275 ivideo->video_vbase = ioremap(ivideo->video_base, ivideo->video_size);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006276 ivideo->SiS_Pr.VideoMemoryAddress = ivideo->video_vbase;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006277 if(!ivideo->video_vbase) {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006278 printk(KERN_ERR "sisfb: Fatal error: Unable to map framebuffer memory\n");
6279 ret = -ENODEV;
6280 goto error_1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006281 }
6282
6283 ivideo->mmio_vbase = ioremap(ivideo->mmio_base, ivideo->mmio_size);
6284 if(!ivideo->mmio_vbase) {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006285 printk(KERN_ERR "sisfb: Fatal error: Unable to map MMIO region\n");
6286 ret = -ENODEV;
6287error_0: iounmap(ivideo->video_vbase);
6288error_1: release_mem_region(ivideo->video_base, ivideo->video_size);
6289error_2: release_mem_region(ivideo->mmio_base, ivideo->mmio_size);
6290error_3: vfree(ivideo->bios_abase);
6291#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
6292error_4:
6293#endif
6294 if(ivideo->lpcdev)
6295 SIS_PCI_PUT_DEVICE(ivideo->lpcdev);
6296 if(ivideo->nbridge)
6297 SIS_PCI_PUT_DEVICE(ivideo->nbridge);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006298 pci_set_drvdata(pdev, NULL);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006299 if(!ivideo->sisvga_enabled)
6300 pci_disable_device(pdev);
6301 kfree(sis_fb_info);
6302 return ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006303 }
6304
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006305 printk(KERN_INFO "sisfb: Video RAM at 0x%lx, mapped to 0x%lx, size %ldk\n",
6306 ivideo->video_base, (unsigned long)ivideo->video_vbase, ivideo->video_size / 1024);
6307
6308 if(ivideo->video_offset) {
6309 printk(KERN_INFO "sisfb: Viewport offset %ldk\n",
6310 ivideo->video_offset / 1024);
6311 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07006312
6313 printk(KERN_INFO "sisfb: MMIO at 0x%lx, mapped to 0x%lx, size %ldk\n",
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006314 ivideo->mmio_base, (unsigned long)ivideo->mmio_vbase, ivideo->mmio_size / 1024);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006315
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006316
6317 /* Determine the size of the command queue */
6318 if(ivideo->sisvga_engine == SIS_300_VGA) {
6319 ivideo->cmdQueueSize = TURBO_QUEUE_AREA_SIZE;
6320 } else {
6321 if(ivideo->chip == XGI_20) {
6322 ivideo->cmdQueueSize = COMMAND_QUEUE_AREA_SIZE_Z7;
6323 } else {
6324 ivideo->cmdQueueSize = COMMAND_QUEUE_AREA_SIZE;
6325 }
6326 }
6327
6328 /* Engines are no longer initialized here; this is
6329 * now done after the first mode-switch (if the
6330 * submitted var has its acceleration flags set).
6331 */
6332
6333 /* Calculate the base of the (unused) hw cursor */
6334 ivideo->hwcursor_vbase = ivideo->video_vbase
6335 + ivideo->video_size
6336 - ivideo->cmdQueueSize
6337 - ivideo->hwcursor_size;
6338 ivideo->caps |= HW_CURSOR_CAP;
6339
6340 /* Initialize offscreen memory manager */
Linus Torvalds1da177e2005-04-16 15:20:36 -07006341 if((ivideo->havenoheap = sisfb_heap_init(ivideo))) {
6342 printk(KERN_WARNING "sisfb: Failed to initialize offscreen memory heap\n");
6343 }
6344
6345 /* Used for clearing the screen only, therefore respect our mem limit */
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006346 ivideo->SiS_Pr.VideoMemoryAddress += ivideo->video_offset;
6347 ivideo->SiS_Pr.VideoMemorySize = ivideo->sisfb_mem;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006348
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006349 ivideo->mtrr = -1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006350
6351 ivideo->vbflags = 0;
6352 ivideo->lcddefmodeidx = DEFAULT_LCDMODE;
6353 ivideo->tvdefmodeidx = DEFAULT_TVMODE;
6354 ivideo->defmodeidx = DEFAULT_MODE;
6355
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006356 ivideo->newrom = 0;
6357 if(ivideo->chip < XGI_20) {
6358 if(ivideo->bios_abase) {
6359 ivideo->newrom = SiSDetermineROMLayout661(&ivideo->SiS_Pr);
6360 }
6361 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07006362
6363 if((ivideo->sisfb_mode_idx < 0) ||
6364 ((sisbios_mode[ivideo->sisfb_mode_idx].mode_no[ivideo->mni]) != 0xFF)) {
6365
6366 sisfb_sense_crt1(ivideo);
6367
6368 sisfb_get_VB_type(ivideo);
6369
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006370 if(ivideo->vbflags2 & VB2_VIDEOBRIDGE) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07006371 sisfb_detect_VB_connect(ivideo);
6372 }
6373
6374 ivideo->currentvbflags = ivideo->vbflags & (VB_VIDEOBRIDGE | TV_STANDARD);
6375
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006376 /* Decide on which CRT2 device to use */
6377 if(ivideo->vbflags2 & VB2_VIDEOBRIDGE) {
6378 if(ivideo->sisfb_crt2type != -1) {
6379 if((ivideo->sisfb_crt2type == CRT2_LCD) &&
6380 (ivideo->vbflags & CRT2_LCD)) {
6381 ivideo->currentvbflags |= CRT2_LCD;
6382 } else if(ivideo->sisfb_crt2type != CRT2_LCD) {
6383 ivideo->currentvbflags |= ivideo->sisfb_crt2type;
6384 }
6385 } else {
6386 /* Chrontel 700x TV detection often unreliable, therefore
6387 * use a different default order on such machines
6388 */
6389 if((ivideo->sisvga_engine == SIS_300_VGA) &&
6390 (ivideo->vbflags2 & VB2_CHRONTEL)) {
6391 if(ivideo->vbflags & CRT2_LCD)
6392 ivideo->currentvbflags |= CRT2_LCD;
6393 else if(ivideo->vbflags & CRT2_TV)
6394 ivideo->currentvbflags |= CRT2_TV;
6395 else if(ivideo->vbflags & CRT2_VGA)
6396 ivideo->currentvbflags |= CRT2_VGA;
6397 } else {
6398 if(ivideo->vbflags & CRT2_TV)
6399 ivideo->currentvbflags |= CRT2_TV;
6400 else if(ivideo->vbflags & CRT2_LCD)
6401 ivideo->currentvbflags |= CRT2_LCD;
6402 else if(ivideo->vbflags & CRT2_VGA)
6403 ivideo->currentvbflags |= CRT2_VGA;
6404 }
6405 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07006406 }
6407
6408 if(ivideo->vbflags & CRT2_LCD) {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006409 sisfb_detect_lcd_type(ivideo);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006410 }
6411
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006412 sisfb_save_pdc_emi(ivideo);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006413
6414 if(!ivideo->sisfb_crt1off) {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006415 sisfb_handle_ddc(ivideo, &ivideo->sisfb_thismonitor, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006416 } else {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006417 if((ivideo->vbflags2 & VB2_SISTMDSBRIDGE) &&
6418 (ivideo->vbflags & (CRT2_VGA | CRT2_LCD))) {
6419 sisfb_handle_ddc(ivideo, &ivideo->sisfb_thismonitor, 1);
6420 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07006421 }
6422
6423 if(ivideo->sisfb_mode_idx >= 0) {
6424 int bu = ivideo->sisfb_mode_idx;
6425 ivideo->sisfb_mode_idx = sisfb_validate_mode(ivideo,
6426 ivideo->sisfb_mode_idx, ivideo->currentvbflags);
6427 if(bu != ivideo->sisfb_mode_idx) {
6428 printk(KERN_ERR "Mode %dx%dx%d failed validation\n",
6429 sisbios_mode[bu].xres,
6430 sisbios_mode[bu].yres,
6431 sisbios_mode[bu].bpp);
6432 }
6433 }
6434
6435 if(ivideo->sisfb_mode_idx < 0) {
6436 switch(ivideo->currentvbflags & VB_DISPTYPE_DISP2) {
6437 case CRT2_LCD:
6438 ivideo->sisfb_mode_idx = ivideo->lcddefmodeidx;
6439 break;
6440 case CRT2_TV:
6441 ivideo->sisfb_mode_idx = ivideo->tvdefmodeidx;
6442 break;
6443 default:
6444 ivideo->sisfb_mode_idx = ivideo->defmodeidx;
6445 break;
6446 }
6447 }
6448
6449 ivideo->mode_no = sisbios_mode[ivideo->sisfb_mode_idx].mode_no[ivideo->mni];
6450
6451 if(ivideo->refresh_rate != 0) {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006452 sisfb_search_refresh_rate(ivideo, ivideo->refresh_rate,
6453 ivideo->sisfb_mode_idx);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006454 }
6455
6456 if(ivideo->rate_idx == 0) {
6457 ivideo->rate_idx = sisbios_mode[ivideo->sisfb_mode_idx].rate_idx;
6458 ivideo->refresh_rate = 60;
6459 }
6460
6461 if(ivideo->sisfb_thismonitor.datavalid) {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006462 if(!sisfb_verify_rate(ivideo, &ivideo->sisfb_thismonitor,
6463 ivideo->sisfb_mode_idx,
6464 ivideo->rate_idx,
6465 ivideo->refresh_rate)) {
6466 printk(KERN_INFO "sisfb: WARNING: Refresh rate "
6467 "exceeds monitor specs!\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07006468 }
6469 }
6470
6471 ivideo->video_bpp = sisbios_mode[ivideo->sisfb_mode_idx].bpp;
6472 ivideo->video_width = sisbios_mode[ivideo->sisfb_mode_idx].xres;
6473 ivideo->video_height = sisbios_mode[ivideo->sisfb_mode_idx].yres;
6474
6475 sisfb_set_vparms(ivideo);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006476
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006477#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
6478
6479 /* ---------------- For 2.4: Now switch the mode ------------------ */
6480
6481 printk(KERN_INFO "sisfb: Setting mode %dx%dx%d (%dHz)\n",
6482 ivideo->video_width, ivideo->video_height, ivideo->video_bpp,
Linus Torvalds1da177e2005-04-16 15:20:36 -07006483 ivideo->refresh_rate);
6484
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006485 /* Determine whether or not acceleration is to be
6486 * used. Need to know before pre/post_set_mode()
6487 */
6488 ivideo->accel = 0;
6489 ivideo->default_var.accel_flags &= ~FB_ACCELF_TEXT;
6490 if(ivideo->sisfb_accel) {
6491 ivideo->accel = -1;
6492 ivideo->default_var.accel_flags |= FB_ACCELF_TEXT;
6493 }
6494
6495 /* Now switch the mode */
Linus Torvalds1da177e2005-04-16 15:20:36 -07006496 sisfb_pre_setmode(ivideo);
6497
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006498 if(SiSSetMode(&ivideo->SiS_Pr, ivideo->mode_no) == 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07006499 printk(KERN_ERR "sisfb: Fatal error: Setting mode[0x%x] failed\n",
6500 ivideo->mode_no);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006501 ret = -EINVAL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006502 iounmap(ivideo->mmio_vbase);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006503 goto error_0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006504 }
6505
6506 outSISIDXREG(SISSR, IND_SIS_PASSWORD, SIS_PASSWORD);
6507
6508 sisfb_post_setmode(ivideo);
6509
6510 /* Maximize regardless of sisfb_max at startup */
6511 ivideo->default_var.yres_virtual = 32767;
6512
6513 /* Force reset of x virtual in crtc_to_var */
6514 ivideo->default_var.xres_virtual = 0;
6515
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006516 /* Copy mode timing to var */
Linus Torvalds1da177e2005-04-16 15:20:36 -07006517 sisfb_crtc_to_var(ivideo, &ivideo->default_var);
6518
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006519 /* Find out about screen pitch */
Linus Torvalds1da177e2005-04-16 15:20:36 -07006520 sisfb_calc_pitch(ivideo, &ivideo->default_var);
6521 sisfb_set_pitch(ivideo);
6522
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006523 /* Init the accelerator (does nothing currently) */
Linus Torvalds1da177e2005-04-16 15:20:36 -07006524 sisfb_initaccel(ivideo);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006525
6526 /* Init some fbinfo entries */
Linus Torvalds1da177e2005-04-16 15:20:36 -07006527 sis_fb_info->node = -1;
6528 sis_fb_info->flags = FBINFO_FLAG_DEFAULT;
6529 sis_fb_info->fbops = &sisfb_ops;
6530 sis_fb_info->disp = &ivideo->sis_disp;
6531 sis_fb_info->blank = &sisfb_blank;
6532 sis_fb_info->switch_con = &sisfb_switch;
6533 sis_fb_info->updatevar = &sisfb_update_var;
6534 sis_fb_info->changevar = NULL;
6535 strcpy(sis_fb_info->fontname, sisfb_fontname);
6536
6537 sisfb_set_disp(-1, &ivideo->default_var, sis_fb_info);
6538
6539#else /* --------- For 2.6: Setup a somewhat sane default var ------------ */
6540
6541 printk(KERN_INFO "sisfb: Default mode is %dx%dx%d (%dHz)\n",
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006542 ivideo->video_width, ivideo->video_height, ivideo->video_bpp,
Linus Torvalds1da177e2005-04-16 15:20:36 -07006543 ivideo->refresh_rate);
6544
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006545 /* Set up the default var according to chosen default display mode */
Linus Torvalds1da177e2005-04-16 15:20:36 -07006546 ivideo->default_var.xres = ivideo->default_var.xres_virtual = ivideo->video_width;
6547 ivideo->default_var.yres = ivideo->default_var.yres_virtual = ivideo->video_height;
6548 ivideo->default_var.bits_per_pixel = ivideo->video_bpp;
6549
6550 sisfb_bpp_to_var(ivideo, &ivideo->default_var);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006551
Linus Torvalds1da177e2005-04-16 15:20:36 -07006552 ivideo->default_var.pixclock = (u32) (1000000000 /
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006553 sisfb_mode_rate_to_dclock(&ivideo->SiS_Pr, ivideo->mode_no, ivideo->rate_idx));
6554
6555 if(sisfb_mode_rate_to_ddata(&ivideo->SiS_Pr, ivideo->mode_no,
6556 ivideo->rate_idx, &ivideo->default_var)) {
6557 if((ivideo->default_var.vmode & FB_VMODE_MASK) == FB_VMODE_DOUBLE) {
6558 ivideo->default_var.pixclock <<= 1;
6559 }
6560 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07006561
6562 if(ivideo->sisfb_ypan) {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006563 /* Maximize regardless of sisfb_max at startup */
6564 ivideo->default_var.yres_virtual =
6565 sisfb_calc_maxyres(ivideo, &ivideo->default_var);
6566 if(ivideo->default_var.yres_virtual < ivideo->default_var.yres) {
6567 ivideo->default_var.yres_virtual = ivideo->default_var.yres;
6568 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07006569 }
6570
6571 sisfb_calc_pitch(ivideo, &ivideo->default_var);
6572
6573 ivideo->accel = 0;
6574 if(ivideo->sisfb_accel) {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006575 ivideo->accel = -1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006576#ifdef STUPID_ACCELF_TEXT_SHIT
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006577 ivideo->default_var.accel_flags |= FB_ACCELF_TEXT;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006578#endif
6579 }
6580 sisfb_initaccel(ivideo);
6581
6582#if defined(FBINFO_HWACCEL_DISABLED) && defined(FBINFO_HWACCEL_XPAN)
6583 sis_fb_info->flags = FBINFO_DEFAULT |
6584 FBINFO_HWACCEL_YPAN |
6585 FBINFO_HWACCEL_XPAN |
6586 FBINFO_HWACCEL_COPYAREA |
6587 FBINFO_HWACCEL_FILLRECT |
6588 ((ivideo->accel) ? 0 : FBINFO_HWACCEL_DISABLED);
6589#else
6590 sis_fb_info->flags = FBINFO_FLAG_DEFAULT;
6591#endif
6592 sis_fb_info->var = ivideo->default_var;
6593 sis_fb_info->fix = ivideo->sisfb_fix;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006594 sis_fb_info->screen_base = ivideo->video_vbase + ivideo->video_offset;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006595 sis_fb_info->fbops = &sisfb_ops;
6596
6597 sisfb_get_fix(&sis_fb_info->fix, -1, sis_fb_info);
6598 sis_fb_info->pseudo_palette = ivideo->pseudo_palette;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006599
Linus Torvalds1da177e2005-04-16 15:20:36 -07006600 fb_alloc_cmap(&sis_fb_info->cmap, 256 , 0);
6601#endif /* 2.6 */
6602
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006603 printk(KERN_DEBUG "sisfb: Initial vbflags 0x%x\n", (int)ivideo->vbflags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006604
6605#ifdef CONFIG_MTRR
6606 ivideo->mtrr = mtrr_add(ivideo->video_base, ivideo->video_size,
6607 MTRR_TYPE_WRCOMB, 1);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006608 if(ivideo->mtrr < 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07006609 printk(KERN_DEBUG "sisfb: Failed to add MTRRs\n");
6610 }
6611#endif
6612
6613#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
6614 vc_resize_con(1, 1, 0);
6615#endif
6616
6617 if(register_framebuffer(sis_fb_info) < 0) {
6618 printk(KERN_ERR "sisfb: Fatal error: Failed to register framebuffer\n");
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006619 ret = -EINVAL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006620 iounmap(ivideo->mmio_vbase);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006621 goto error_0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006622 }
6623
6624 ivideo->registered = 1;
6625
6626 /* Enlist us */
6627 ivideo->next = card_list;
6628 card_list = ivideo;
6629
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006630#ifdef SIS_OLD_CONFIG_COMPAT
6631 {
6632 int ret;
6633 /* Our ioctls are all "32/64bit compatible" */
6634 ret = register_ioctl32_conversion(FBIO_ALLOC, NULL);
6635 ret |= register_ioctl32_conversion(FBIO_FREE, NULL);
6636 ret |= register_ioctl32_conversion(FBIOGET_VBLANK, NULL);
6637 ret |= register_ioctl32_conversion(SISFB_GET_INFO_SIZE, NULL);
6638 ret |= register_ioctl32_conversion(SISFB_GET_INFO, NULL);
6639 ret |= register_ioctl32_conversion(SISFB_GET_TVPOSOFFSET, NULL);
6640 ret |= register_ioctl32_conversion(SISFB_SET_TVPOSOFFSET, NULL);
6641 ret |= register_ioctl32_conversion(SISFB_SET_LOCK, NULL);
6642 ret |= register_ioctl32_conversion(SISFB_GET_VBRSTATUS, NULL);
6643 ret |= register_ioctl32_conversion(SISFB_GET_AUTOMAXIMIZE, NULL);
6644 ret |= register_ioctl32_conversion(SISFB_SET_AUTOMAXIMIZE, NULL);
6645 ret |= register_ioctl32_conversion(SISFB_COMMAND, NULL);
6646 if(ret)
6647 printk(KERN_ERR
6648 "sisfb: Error registering ioctl32 translations\n");
6649 else
6650 ivideo->ioctl32registered = 1;
6651 }
6652#endif
6653
Linus Torvalds1da177e2005-04-16 15:20:36 -07006654 printk(KERN_INFO "sisfb: 2D acceleration is %s, y-panning %s\n",
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006655 ivideo->sisfb_accel ? "enabled" : "disabled",
6656 ivideo->sisfb_ypan ?
6657 (ivideo->sisfb_max ? "enabled (auto-max)" :
6658 "enabled (no auto-max)") :
6659 "disabled");
Linus Torvalds1da177e2005-04-16 15:20:36 -07006660
6661
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006662 printk(KERN_INFO "fb%d: %s frame buffer device version %d.%d.%d\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07006663#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006664 GET_FB_IDX(sis_fb_info->node),
Linus Torvalds1da177e2005-04-16 15:20:36 -07006665#else
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006666 sis_fb_info->node,
Linus Torvalds1da177e2005-04-16 15:20:36 -07006667#endif
6668 ivideo->myid, VER_MAJOR, VER_MINOR, VER_LEVEL);
6669
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006670 printk(KERN_INFO "sisfb: Copyright (C) 2001-2005 Thomas Winischhofer\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07006671
6672 } /* if mode = "none" */
6673
6674 return 0;
6675}
6676
6677/*****************************************************/
6678/* PCI DEVICE HANDLING */
6679/*****************************************************/
6680
6681static void __devexit sisfb_remove(struct pci_dev *pdev)
6682{
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006683 struct sis_video_info *ivideo = pci_get_drvdata(pdev);
6684 struct fb_info *sis_fb_info = ivideo->memyselfandi;
6685 int registered = ivideo->registered;
6686 int modechanged = ivideo->modechanged;
6687
6688#ifdef SIS_OLD_CONFIG_COMPAT
6689 if(ivideo->ioctl32registered) {
6690 int ret;
6691 ret = unregister_ioctl32_conversion(FBIO_ALLOC);
6692 ret |= unregister_ioctl32_conversion(FBIO_FREE);
6693 ret |= unregister_ioctl32_conversion(FBIOGET_VBLANK);
6694 ret |= unregister_ioctl32_conversion(SISFB_GET_INFO_SIZE);
6695 ret |= unregister_ioctl32_conversion(SISFB_GET_INFO);
6696 ret |= unregister_ioctl32_conversion(SISFB_GET_TVPOSOFFSET);
6697 ret |= unregister_ioctl32_conversion(SISFB_SET_TVPOSOFFSET);
6698 ret |= unregister_ioctl32_conversion(SISFB_SET_LOCK);
6699 ret |= unregister_ioctl32_conversion(SISFB_GET_VBRSTATUS);
6700 ret |= unregister_ioctl32_conversion(SISFB_GET_AUTOMAXIMIZE);
6701 ret |= unregister_ioctl32_conversion(SISFB_SET_AUTOMAXIMIZE);
6702 ret |= unregister_ioctl32_conversion(SISFB_COMMAND);
6703 if(ret)
6704 printk(KERN_ERR
6705 "sisfb: Error unregistering ioctl32 translations\n");
6706 }
6707#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -07006708
6709 /* Unmap */
Linus Torvalds1da177e2005-04-16 15:20:36 -07006710 iounmap(ivideo->mmio_vbase);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006711 iounmap(ivideo->video_vbase);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006712
6713 /* Release mem regions */
6714 release_mem_region(ivideo->video_base, ivideo->video_size);
6715 release_mem_region(ivideo->mmio_base, ivideo->mmio_size);
6716
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006717 vfree(ivideo->bios_abase);
6718
6719 if(ivideo->lpcdev)
6720 SIS_PCI_PUT_DEVICE(ivideo->lpcdev);
6721
6722 if(ivideo->nbridge)
6723 SIS_PCI_PUT_DEVICE(ivideo->nbridge);
6724
Linus Torvalds1da177e2005-04-16 15:20:36 -07006725#ifdef CONFIG_MTRR
6726 /* Release MTRR region */
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006727 if(ivideo->mtrr >= 0)
Linus Torvalds1da177e2005-04-16 15:20:36 -07006728 mtrr_del(ivideo->mtrr, ivideo->video_base, ivideo->video_size);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006729#endif
6730
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006731 pci_set_drvdata(pdev, NULL);
6732
6733 /* If device was disabled when starting, disable
6734 * it when quitting.
6735 */
6736 if(!ivideo->sisvga_enabled)
6737 pci_disable_device(pdev);
6738
Linus Torvalds1da177e2005-04-16 15:20:36 -07006739 /* Unregister the framebuffer */
6740 if(ivideo->registered) {
6741 unregister_framebuffer(sis_fb_info);
6742#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,3))
6743 framebuffer_release(sis_fb_info);
6744#else
6745 kfree(sis_fb_info);
6746#endif
6747 }
6748
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006749 /* OK, our ivideo is gone for good from here. */
Linus Torvalds1da177e2005-04-16 15:20:36 -07006750
6751 /* TODO: Restore the initial mode
6752 * This sounds easy but is as good as impossible
6753 * on many machines with SiS chip and video bridge
6754 * since text modes are always set up differently
6755 * from machine to machine. Depends on the type
6756 * of integration between chipset and bridge.
6757 */
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006758 if(registered && modechanged)
6759 printk(KERN_INFO
6760 "sisfb: Restoring of text mode not supported yet\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07006761};
6762
6763static struct pci_driver sisfb_driver = {
6764 .name = "sisfb",
6765 .id_table = sisfb_pci_table,
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006766 .probe = sisfb_probe,
Linus Torvalds1da177e2005-04-16 15:20:36 -07006767 .remove = __devexit_p(sisfb_remove)
6768};
6769
6770SISINITSTATIC int __init sisfb_init(void)
6771{
6772#if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,8)
6773#ifndef MODULE
6774 char *options = NULL;
6775
6776 if(fb_get_options("sisfb", &options))
6777 return -ENODEV;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006778
Linus Torvalds1da177e2005-04-16 15:20:36 -07006779 sisfb_setup(options);
6780#endif
6781#endif
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006782 return pci_register_driver(&sisfb_driver);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006783}
6784
6785#if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,8)
6786#ifndef MODULE
6787module_init(sisfb_init);
6788#endif
6789#endif
6790
6791/*****************************************************/
6792/* MODULE */
6793/*****************************************************/
6794
6795#ifdef MODULE
6796
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006797static char *mode = NULL;
6798static int vesa = -1;
6799static unsigned int rate = 0;
6800static unsigned int crt1off = 1;
6801static unsigned int mem = 0;
6802static char *forcecrt2type = NULL;
6803static int forcecrt1 = -1;
6804static int pdc = -1;
6805static int pdc1 = -1;
6806static int noaccel = -1;
6807static int noypan = -1;
6808static int nomax = -1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006809#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006810static int inverse = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006811#endif
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006812static int userom = -1;
6813static int useoem = -1;
6814static char *tvstandard = NULL;
6815static int nocrt2rate = 0;
6816static int scalelcd = -1;
6817static char *specialtiming = NULL;
6818static int lvdshl = -1;
6819static int tvxposoffset = 0, tvyposoffset = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006820#if !defined(__i386__) && !defined(__x86_64__)
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006821static int resetcard = 0;
6822static int videoram = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006823#endif
6824
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006825static int __init sisfb_init_module(void)
6826{
6827 sisfb_setdefaultparms();
6828
6829 if(rate)
6830 sisfb_parm_rate = rate;
6831
6832 if((scalelcd == 0) || (scalelcd == 1))
6833 sisfb_scalelcd = scalelcd ^ 1;
6834
6835 /* Need to check crt2 type first for fstn/dstn */
6836
6837 if(forcecrt2type)
6838 sisfb_search_crt2type(forcecrt2type);
6839
6840 if(tvstandard)
6841 sisfb_search_tvstd(tvstandard);
6842
6843 if(mode)
6844 sisfb_search_mode(mode, FALSE);
6845 else if(vesa != -1)
6846 sisfb_search_vesamode(vesa, FALSE);
6847
6848 sisfb_crt1off = (crt1off == 0) ? 1 : 0;
6849
6850 sisfb_forcecrt1 = forcecrt1;
6851 if(forcecrt1 == 1)
6852 sisfb_crt1off = 0;
6853 else if(forcecrt1 == 0)
6854 sisfb_crt1off = 1;
6855
6856 if(noaccel == 1)
6857 sisfb_accel = 0;
6858 else if(noaccel == 0)
6859 sisfb_accel = 1;
6860
6861 if(noypan == 1)
6862 sisfb_ypan = 0;
6863 else if(noypan == 0)
6864 sisfb_ypan = 1;
6865
6866 if(nomax == 1)
6867 sisfb_max = 0;
6868 else if(nomax == 0)
6869 sisfb_max = 1;
6870
6871#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
6872 if(inverse) sisfb_inverse = 1;
6873#endif
6874
6875 if(mem)
6876 sisfb_parm_mem = mem;
6877
6878 if(userom != -1)
6879 sisfb_userom = userom;
6880
6881 if(useoem != -1)
6882 sisfb_useoem = useoem;
6883
6884 if(pdc != -1)
6885 sisfb_pdc = (pdc & 0x7f);
6886
6887 if(pdc1 != -1)
6888 sisfb_pdca = (pdc1 & 0x1f);
6889
6890 sisfb_nocrt2rate = nocrt2rate;
6891
6892 if(specialtiming)
6893 sisfb_search_specialtiming(specialtiming);
6894
6895 if((lvdshl >= 0) && (lvdshl <= 3))
6896 sisfb_lvdshl = lvdshl;
6897
6898 sisfb_tvxposoffset = tvxposoffset;
6899 sisfb_tvyposoffset = tvyposoffset;
6900
6901#if !defined(__i386__) && !defined(__x86_64__)
6902 sisfb_resetcard = (resetcard) ? 1 : 0;
6903 if(videoram)
6904 sisfb_videoram = videoram;
6905#endif
6906
6907 return sisfb_init();
6908}
6909
6910static void __exit sisfb_remove_module(void)
6911{
6912 pci_unregister_driver(&sisfb_driver);
6913 printk(KERN_DEBUG "sisfb: Module unloaded\n");
6914}
6915
6916module_init(sisfb_init_module);
6917module_exit(sisfb_remove_module);
6918
6919MODULE_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 -07006920MODULE_LICENSE("GPL");
6921MODULE_AUTHOR("Thomas Winischhofer <thomas@winischhofer.net>, Others");
6922
6923#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
6924MODULE_PARM(mem, "i");
6925MODULE_PARM(noaccel, "i");
6926MODULE_PARM(noypan, "i");
6927MODULE_PARM(nomax, "i");
6928MODULE_PARM(userom, "i");
6929MODULE_PARM(useoem, "i");
6930MODULE_PARM(mode, "s");
6931MODULE_PARM(vesa, "i");
6932MODULE_PARM(rate, "i");
6933MODULE_PARM(forcecrt1, "i");
6934MODULE_PARM(forcecrt2type, "s");
6935MODULE_PARM(scalelcd, "i");
6936MODULE_PARM(pdc, "i");
6937MODULE_PARM(pdc1, "i");
6938MODULE_PARM(specialtiming, "s");
6939MODULE_PARM(lvdshl, "i");
6940MODULE_PARM(tvstandard, "s");
6941MODULE_PARM(tvxposoffset, "i");
6942MODULE_PARM(tvyposoffset, "i");
Linus Torvalds1da177e2005-04-16 15:20:36 -07006943MODULE_PARM(nocrt2rate, "i");
6944MODULE_PARM(inverse, "i");
6945#if !defined(__i386__) && !defined(__x86_64__)
6946MODULE_PARM(resetcard, "i");
6947MODULE_PARM(videoram, "i");
6948#endif
6949#endif
6950
6951#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0)
6952module_param(mem, int, 0);
6953module_param(noaccel, int, 0);
6954module_param(noypan, int, 0);
6955module_param(nomax, int, 0);
6956module_param(userom, int, 0);
6957module_param(useoem, int, 0);
6958module_param(mode, charp, 0);
6959module_param(vesa, int, 0);
6960module_param(rate, int, 0);
6961module_param(forcecrt1, int, 0);
6962module_param(forcecrt2type, charp, 0);
6963module_param(scalelcd, int, 0);
6964module_param(pdc, int, 0);
6965module_param(pdc1, int, 0);
6966module_param(specialtiming, charp, 0);
6967module_param(lvdshl, int, 0);
6968module_param(tvstandard, charp, 0);
6969module_param(tvxposoffset, int, 0);
6970module_param(tvyposoffset, int, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006971module_param(nocrt2rate, int, 0);
6972#if !defined(__i386__) && !defined(__x86_64__)
6973module_param(resetcard, int, 0);
6974module_param(videoram, int, 0);
6975#endif
6976#endif
6977
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006978#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
Linus Torvalds1da177e2005-04-16 15:20:36 -07006979MODULE_PARM_DESC(mem,
6980 "\nDetermines the beginning of the video memory heap in KB. This heap is used\n"
6981 "for video RAM management for eg. DRM/DRI. On 300 series, the default depends\n"
6982 "on the amount of video RAM available. If 8MB of video RAM or less is available,\n"
6983 "the heap starts at 4096KB, if between 8 and 16MB are available at 8192KB,\n"
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006984 "otherwise at 12288KB. On 315/330/340 series, the heap size is 32KB by default.\n"
Linus Torvalds1da177e2005-04-16 15:20:36 -07006985 "The value is to be specified without 'KB' and must match the MaxXFBMem setting\n"
6986 "for XFree86 4.x/X.org 6.7 and later.\n");
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006987#else
6988MODULE_PARM_DESC(mem,
6989 "\nDetermines the beginning of the video memory heap in KB. This heap is used\n"
6990 "for video RAM management for eg. DRM/DRI. On 300 series, the default depends\n"
6991 "on the amount of video RAM available. If 8MB of video RAM or less is available,\n"
6992 "the heap starts at 4096KB, if between 8 and 16MB are available at 8192KB,\n"
6993 "otherwise at 12288KB. On 315/330/340 series, the heap size is 32KB by default.\n"
6994 "The value is to be specified without 'KB'.\n");
6995#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -07006996
6997MODULE_PARM_DESC(noaccel,
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006998 "\nIf set to anything other than 0, 2D acceleration will be disabled.\n"
Linus Torvalds1da177e2005-04-16 15:20:36 -07006999 "(default: 0)\n");
7000
7001MODULE_PARM_DESC(noypan,
Thomas Winischhofer544393f2005-09-09 13:04:45 -07007002 "\nIf set to anything other than 0, y-panning will be disabled and scrolling\n"
7003 "will be performed by redrawing the screen. (default: 0)\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07007004
7005MODULE_PARM_DESC(nomax,
Thomas Winischhofer544393f2005-09-09 13:04:45 -07007006 "\nIf y-panning is enabled, sisfb will by default use the entire available video\n"
Linus Torvalds1da177e2005-04-16 15:20:36 -07007007 "memory for the virtual screen in order to optimize scrolling performance. If\n"
7008 "this is set to anything other than 0, sisfb will not do this and thereby \n"
7009 "enable the user to positively specify a virtual Y size of the screen using\n"
7010 "fbset. (default: 0)\n");
7011
7012#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
7013MODULE_PARM_DESC(mode,
Thomas Winischhofer544393f2005-09-09 13:04:45 -07007014 "\nSelects the desired display mode in the format [X]x[Y]x[Depth], eg.\n"
7015 "1024x768x16. Other formats supported include XxY-Depth and\n"
7016 "XxY-Depth@Rate. If the parameter is only one (decimal or hexadecimal)\n"
Linus Torvalds1da177e2005-04-16 15:20:36 -07007017 "number, it will be interpreted as a VESA mode number. (default: none if\n"
7018 "sisfb is a module; this leaves the console untouched and the driver will\n"
7019 "only do the video memory management for eg. DRM/DRI; 800x600x8 if sisfb\n"
7020 "is in the kernel)\n");
7021MODULE_PARM_DESC(vesa,
Thomas Winischhofer544393f2005-09-09 13:04:45 -07007022 "\nSelects the desired display mode by VESA defined mode number, eg. 0x117\n"
7023 "(default: 0x0000 if sisfb is a module; this leaves the console untouched\n"
Linus Torvalds1da177e2005-04-16 15:20:36 -07007024 "and the driver will only do the video memory management for eg. DRM/DRI;\n"
7025 "0x0103 if sisfb is in the kernel)\n");
7026#endif
7027
7028#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0)
7029MODULE_PARM_DESC(mode,
Thomas Winischhofer544393f2005-09-09 13:04:45 -07007030 "\nSelects the desired default display mode in the format XxYxDepth,\n"
7031 "eg. 1024x768x16. Other formats supported include XxY-Depth and\n"
Linus Torvalds1da177e2005-04-16 15:20:36 -07007032 "XxY-Depth@Rate. If the parameter is only one (decimal or hexadecimal)\n"
7033 "number, it will be interpreted as a VESA mode number. (default: 800x600x8)\n");
7034
7035MODULE_PARM_DESC(vesa,
Thomas Winischhofer544393f2005-09-09 13:04:45 -07007036 "\nSelects the desired default display mode by VESA defined mode number, eg.\n"
7037 "0x117 (default: 0x0103)\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07007038#endif
7039
7040MODULE_PARM_DESC(rate,
7041 "\nSelects the desired vertical refresh rate for CRT1 (external VGA) in Hz.\n"
7042 "If the mode is specified in the format XxY-Depth@Rate, this parameter\n"
7043 "will be ignored (default: 60)\n");
7044
7045MODULE_PARM_DESC(forcecrt1,
7046 "\nNormally, the driver autodetects whether or not CRT1 (external VGA) is \n"
7047 "connected. With this option, the detection can be overridden (1=CRT1 ON,\n"
7048 "0=CRT1 OFF) (default: [autodetected])\n");
7049
7050MODULE_PARM_DESC(forcecrt2type,
7051 "\nIf this option is omitted, the driver autodetects CRT2 output devices, such as\n"
7052 "LCD, TV or secondary VGA. With this option, this autodetection can be\n"
7053 "overridden. Possible parameters are LCD, TV, VGA or NONE. NONE disables CRT2.\n"
7054 "On systems with a SiS video bridge, parameters SVIDEO, COMPOSITE or SCART can\n"
7055 "be used instead of TV to override the TV detection. Furthermore, on systems\n"
7056 "with a SiS video bridge, SVIDEO+COMPOSITE, HIVISION, YPBPR480I, YPBPR480P,\n"
7057 "YPBPR720P and YPBPR1080I are understood. However, whether or not these work\n"
7058 "depends on the very hardware in use. (default: [autodetected])\n");
7059
7060MODULE_PARM_DESC(scalelcd,
7061 "\nSetting this to 1 will force the driver to scale the LCD image to the panel's\n"
7062 "native resolution. Setting it to 0 will disable scaling; LVDS panels will\n"
7063 "show black bars around the image, TMDS panels will probably do the scaling\n"
7064 "themselves. Default: 1 on LVDS panels, 0 on TMDS panels\n");
7065
7066MODULE_PARM_DESC(pdc,
Thomas Winischhofer544393f2005-09-09 13:04:45 -07007067 "\nThis is for manually selecting the LCD panel delay compensation. The driver\n"
Linus Torvalds1da177e2005-04-16 15:20:36 -07007068 "should detect this correctly in most cases; however, sometimes this is not\n"
7069 "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 -07007070 "on a 300 series chipset; 6 on other chipsets. If the problem persists, try\n"
7071 "other values (on 300 series: between 4 and 60 in steps of 4; otherwise: any\n"
7072 "value from 0 to 31). (default: autodetected, if LCD is active during start)\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07007073
7074#ifdef CONFIG_FB_SIS_315
7075MODULE_PARM_DESC(pdc1,
Thomas Winischhofer544393f2005-09-09 13:04:45 -07007076 "\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 -07007077 "series only. (default: autodetected if LCD is in LCD-via-CRT1 mode during\n"
7078 "startup) - Note: currently, this has no effect because LCD-via-CRT1 is not\n"
7079 "implemented yet.\n");
7080#endif
7081
7082MODULE_PARM_DESC(specialtiming,
7083 "\nPlease refer to documentation for more information on this option.\n");
7084
7085MODULE_PARM_DESC(lvdshl,
7086 "\nPlease refer to documentation for more information on this option.\n");
7087
7088MODULE_PARM_DESC(tvstandard,
7089 "\nThis allows overriding the BIOS default for the TV standard. Valid choices are\n"
7090 "pal, ntsc, palm and paln. (default: [auto; pal or ntsc only])\n");
7091
7092MODULE_PARM_DESC(tvxposoffset,
7093 "\nRelocate TV output horizontally. Possible parameters: -32 through 32.\n"
7094 "Default: 0\n");
7095
7096MODULE_PARM_DESC(tvyposoffset,
7097 "\nRelocate TV output vertically. Possible parameters: -32 through 32.\n"
7098 "Default: 0\n");
7099
Linus Torvalds1da177e2005-04-16 15:20:36 -07007100MODULE_PARM_DESC(nocrt2rate,
7101 "\nSetting this to 1 will force the driver to use the default refresh rate for\n"
7102 "CRT2 if CRT2 type is VGA. (default: 0, use same rate as CRT1)\n");
7103
7104#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
7105MODULE_PARM_DESC(inverse,
Thomas Winischhofer544393f2005-09-09 13:04:45 -07007106 "\nSetting this to anything but 0 should invert the display colors, but this\n"
Linus Torvalds1da177e2005-04-16 15:20:36 -07007107 "does not seem to work. (default: 0)\n");
7108#endif
7109
7110#if !defined(__i386__) && !defined(__x86_64__)
7111#ifdef CONFIG_FB_SIS_300
7112MODULE_PARM_DESC(resetcard,
7113 "\nSet this to 1 in order to reset (POST) the card on non-x86 machines where\n"
Thomas Winischhofer544393f2005-09-09 13:04:45 -07007114 "the BIOS did not POST the card (only supported for SiS 300/305 and XGI cards\n"
7115 "currently). Default: 0\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07007116
7117MODULE_PARM_DESC(videoram,
7118 "\nSet this to the amount of video RAM (in kilobyte) the card has. Required on\n"
7119 "some non-x86 architectures where the memory auto detection fails. Only\n"
Thomas Winischhofer544393f2005-09-09 13:04:45 -07007120 "relevant if resetcard is set, too. SiS300/305 only. Default: [auto-detect]\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07007121#endif
7122#endif
7123
Linus Torvalds1da177e2005-04-16 15:20:36 -07007124#endif /* /MODULE */
7125
Thomas Winischhofer544393f2005-09-09 13:04:45 -07007126/* _GPL only for new symbols. */
Linus Torvalds1da177e2005-04-16 15:20:36 -07007127EXPORT_SYMBOL(sis_malloc);
7128EXPORT_SYMBOL(sis_free);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07007129EXPORT_SYMBOL_GPL(sis_malloc_new);
7130EXPORT_SYMBOL_GPL(sis_free_new);
7131
Linus Torvalds1da177e2005-04-16 15:20:36 -07007132
7133