blob: 42c54b69726e8b769ada57f5c90ac7eedd5bf093 [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,
2005 .fb_cursor = soft_cursor,
2006 .fb_sync = fbcon_sis_sync,
2007#ifdef SIS_NEW_CONFIG_COMPAT
2008 .fb_compat_ioctl= sisfb_compat_ioctl,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002009#endif
Thomas Winischhofer544393f2005-09-09 13:04:45 -07002010 .fb_ioctl = sisfb_ioctl
Linus Torvalds1da177e2005-04-16 15:20:36 -07002011};
2012#endif
2013
2014/* ---------------- Chip generation dependent routines ---------------- */
2015
Thomas Winischhofer544393f2005-09-09 13:04:45 -07002016static struct pci_dev * __devinit
2017sisfb_get_northbridge(int basechipid)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002018{
2019 struct pci_dev *pdev = NULL;
2020 int nbridgenum, nbridgeidx, i;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07002021 static const unsigned short nbridgeids[] = {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002022 PCI_DEVICE_ID_SI_540, /* for SiS 540 VGA */
2023 PCI_DEVICE_ID_SI_630, /* for SiS 630/730 VGA */
2024 PCI_DEVICE_ID_SI_730,
2025 PCI_DEVICE_ID_SI_550, /* for SiS 550 VGA */
2026 PCI_DEVICE_ID_SI_650, /* for SiS 650/651/740 VGA */
2027 PCI_DEVICE_ID_SI_651,
2028 PCI_DEVICE_ID_SI_740,
Thomas Winischhofer544393f2005-09-09 13:04:45 -07002029 PCI_DEVICE_ID_SI_661, /* for SiS 661/741/660/760/761 VGA */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002030 PCI_DEVICE_ID_SI_741,
2031 PCI_DEVICE_ID_SI_660,
Thomas Winischhofer544393f2005-09-09 13:04:45 -07002032 PCI_DEVICE_ID_SI_760,
2033 PCI_DEVICE_ID_SI_761
Linus Torvalds1da177e2005-04-16 15:20:36 -07002034 };
2035
Thomas Winischhofer544393f2005-09-09 13:04:45 -07002036 switch(basechipid) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002037#ifdef CONFIG_FB_SIS_300
2038 case SIS_540: nbridgeidx = 0; nbridgenum = 1; break;
2039 case SIS_630: nbridgeidx = 1; nbridgenum = 2; break;
2040#endif
2041#ifdef CONFIG_FB_SIS_315
2042 case SIS_550: nbridgeidx = 3; nbridgenum = 1; break;
2043 case SIS_650: nbridgeidx = 4; nbridgenum = 3; break;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07002044 case SIS_660: nbridgeidx = 7; nbridgenum = 5; break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002045#endif
2046 default: return NULL;
2047 }
2048 for(i = 0; i < nbridgenum; i++) {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07002049 if((pdev = SIS_PCI_GET_DEVICE(PCI_VENDOR_ID_SI,
2050 nbridgeids[nbridgeidx+i], NULL)))
2051 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002052 }
2053 return pdev;
2054}
2055
Thomas Winischhofer544393f2005-09-09 13:04:45 -07002056static int __devinit
2057sisfb_get_dram_size(struct sis_video_info *ivideo)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002058{
2059#if defined(CONFIG_FB_SIS_300) || defined(CONFIG_FB_SIS_315)
2060 u8 reg;
2061#endif
2062
2063 ivideo->video_size = 0;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07002064 ivideo->UMAsize = ivideo->LFBsize = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002065
2066 switch(ivideo->chip) {
2067#ifdef CONFIG_FB_SIS_300
2068 case SIS_300:
Thomas Winischhofer544393f2005-09-09 13:04:45 -07002069 inSISIDXREG(SISSR, 0x14, reg);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002070 ivideo->video_size = ((reg & 0x3F) + 1) << 20;
2071 break;
2072 case SIS_540:
2073 case SIS_630:
2074 case SIS_730:
Thomas Winischhofer544393f2005-09-09 13:04:45 -07002075 if(!ivideo->nbridge)
2076 return -1;
2077 pci_read_config_byte(ivideo->nbridge, 0x63, &reg);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002078 ivideo->video_size = 1 << (((reg & 0x70) >> 4) + 21);
2079 break;
2080#endif
2081#ifdef CONFIG_FB_SIS_315
2082 case SIS_315H:
2083 case SIS_315PRO:
2084 case SIS_315:
Thomas Winischhofer544393f2005-09-09 13:04:45 -07002085 inSISIDXREG(SISSR, 0x14, reg);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002086 ivideo->video_size = (1 << ((reg & 0xf0) >> 4)) << 20;
2087 switch((reg >> 2) & 0x03) {
2088 case 0x01:
2089 case 0x03:
Thomas Winischhofer544393f2005-09-09 13:04:45 -07002090 ivideo->video_size <<= 1;
2091 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002092 case 0x02:
Thomas Winischhofer544393f2005-09-09 13:04:45 -07002093 ivideo->video_size += (ivideo->video_size/2);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002094 }
Thomas Winischhofer544393f2005-09-09 13:04:45 -07002095 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002096 case SIS_330:
Thomas Winischhofer544393f2005-09-09 13:04:45 -07002097 inSISIDXREG(SISSR, 0x14, reg);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002098 ivideo->video_size = (1 << ((reg & 0xf0) >> 4)) << 20;
2099 if(reg & 0x0c) ivideo->video_size <<= 1;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07002100 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002101 case SIS_550:
2102 case SIS_650:
2103 case SIS_740:
Thomas Winischhofer544393f2005-09-09 13:04:45 -07002104 inSISIDXREG(SISSR, 0x14, reg);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002105 ivideo->video_size = (((reg & 0x3f) + 1) << 2) << 20;
2106 break;
2107 case SIS_661:
2108 case SIS_741:
Thomas Winischhofer544393f2005-09-09 13:04:45 -07002109 inSISIDXREG(SISCR, 0x79, reg);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002110 ivideo->video_size = (1 << ((reg & 0xf0) >> 4)) << 20;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07002111 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002112 case SIS_660:
2113 case SIS_760:
Thomas Winischhofer544393f2005-09-09 13:04:45 -07002114 case SIS_761:
Linus Torvalds1da177e2005-04-16 15:20:36 -07002115 inSISIDXREG(SISCR, 0x79, reg);
2116 reg = (reg & 0xf0) >> 4;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07002117 if(reg) {
2118 ivideo->video_size = (1 << reg) << 20;
2119 ivideo->UMAsize = ivideo->video_size;
2120 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002121 inSISIDXREG(SISCR, 0x78, reg);
2122 reg &= 0x30;
2123 if(reg) {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07002124 if(reg == 0x10) {
2125 ivideo->LFBsize = (32 << 20);
2126 } else {
2127 ivideo->LFBsize = (64 << 20);
2128 }
2129 ivideo->video_size += ivideo->LFBsize;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002130 }
Thomas Winischhofer544393f2005-09-09 13:04:45 -07002131 break;
2132 case SIS_340:
2133 case XGI_20:
2134 case XGI_40:
2135 inSISIDXREG(SISSR, 0x14, reg);
2136 ivideo->video_size = (1 << ((reg & 0xf0) >> 4)) << 20;
2137 if(ivideo->chip != XGI_20) {
2138 reg = (reg & 0x0c) >> 2;
2139 if(ivideo->revision_id == 2) {
2140 if(reg & 0x01) reg = 0x02;
2141 else reg = 0x00;
2142 }
2143 if(reg == 0x02) ivideo->video_size <<= 1;
2144 else if(reg == 0x03) ivideo->video_size <<= 2;
2145 }
2146 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002147#endif
2148 default:
2149 return -1;
2150 }
2151 return 0;
2152}
2153
2154/* -------------- video bridge device detection --------------- */
2155
Thomas Winischhofer544393f2005-09-09 13:04:45 -07002156static void __devinit
2157sisfb_detect_VB_connect(struct sis_video_info *ivideo)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002158{
2159 u8 cr32, temp;
2160
Thomas Winischhofer544393f2005-09-09 13:04:45 -07002161 /* No CRT2 on XGI Z7 */
2162 if(ivideo->chip == XGI_20) {
2163 ivideo->sisfb_crt1off = 0;
2164 return;
2165 }
2166
Linus Torvalds1da177e2005-04-16 15:20:36 -07002167#ifdef CONFIG_FB_SIS_300
2168 if(ivideo->sisvga_engine == SIS_300_VGA) {
2169 inSISIDXREG(SISSR, 0x17, temp);
2170 if((temp & 0x0F) && (ivideo->chip != SIS_300)) {
2171 /* PAL/NTSC is stored on SR16 on such machines */
2172 if(!(ivideo->vbflags & (TV_PAL | TV_NTSC | TV_PALM | TV_PALN))) {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07002173 inSISIDXREG(SISSR, 0x16, temp);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002174 if(temp & 0x20)
2175 ivideo->vbflags |= TV_PAL;
2176 else
2177 ivideo->vbflags |= TV_NTSC;
2178 }
2179 }
2180 }
2181#endif
2182
2183 inSISIDXREG(SISCR, 0x32, cr32);
2184
2185 if(cr32 & SIS_CRT1) {
2186 ivideo->sisfb_crt1off = 0;
2187 } else {
2188 ivideo->sisfb_crt1off = (cr32 & 0xDF) ? 1 : 0;
2189 }
2190
2191 ivideo->vbflags &= ~(CRT2_TV | CRT2_LCD | CRT2_VGA);
2192
2193 if(cr32 & SIS_VB_TV) ivideo->vbflags |= CRT2_TV;
2194 if(cr32 & SIS_VB_LCD) ivideo->vbflags |= CRT2_LCD;
2195 if(cr32 & SIS_VB_CRT2) ivideo->vbflags |= CRT2_VGA;
2196
2197 /* Check given parms for hardware compatibility.
2198 * (Cannot do this in the search_xx routines since we don't
2199 * know what hardware we are running on then)
2200 */
2201
2202 if(ivideo->chip != SIS_550) {
2203 ivideo->sisfb_dstn = ivideo->sisfb_fstn = 0;
2204 }
2205
2206 if(ivideo->sisfb_tvplug != -1) {
2207 if( (ivideo->sisvga_engine != SIS_315_VGA) ||
Thomas Winischhofer544393f2005-09-09 13:04:45 -07002208 (!(ivideo->vbflags2 & VB2_SISYPBPRBRIDGE)) ) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002209 if(ivideo->sisfb_tvplug & TV_YPBPR) {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07002210 ivideo->sisfb_tvplug = -1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002211 printk(KERN_ERR "sisfb: YPbPr not supported\n");
2212 }
2213 }
2214 }
2215 if(ivideo->sisfb_tvplug != -1) {
2216 if( (ivideo->sisvga_engine != SIS_315_VGA) ||
Thomas Winischhofer544393f2005-09-09 13:04:45 -07002217 (!(ivideo->vbflags2 & VB2_SISHIVISIONBRIDGE)) ) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002218 if(ivideo->sisfb_tvplug & TV_HIVISION) {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07002219 ivideo->sisfb_tvplug = -1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002220 printk(KERN_ERR "sisfb: HiVision not supported\n");
2221 }
2222 }
2223 }
2224 if(ivideo->sisfb_tvstd != -1) {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07002225 if( (!(ivideo->vbflags2 & VB2_SISBRIDGE)) &&
2226 (!((ivideo->sisvga_engine == SIS_315_VGA) &&
2227 (ivideo->vbflags2 & VB2_CHRONTEL))) ) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002228 if(ivideo->sisfb_tvstd & (TV_PALN | TV_PALN | TV_NTSCJ)) {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07002229 ivideo->sisfb_tvstd = -1;
2230 printk(KERN_ERR "sisfb: PALM/PALN/NTSCJ not supported\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002231 }
2232 }
2233 }
2234
2235 /* Detect/set TV plug & type */
2236 if(ivideo->sisfb_tvplug != -1) {
2237 ivideo->vbflags |= ivideo->sisfb_tvplug;
2238 } else {
2239 if(cr32 & SIS_VB_YPBPR) ivideo->vbflags |= (TV_YPBPR|TV_YPBPR525I); /* default: 480i */
2240 else if(cr32 & SIS_VB_HIVISION) ivideo->vbflags |= TV_HIVISION;
2241 else if(cr32 & SIS_VB_SCART) ivideo->vbflags |= TV_SCART;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07002242 else {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002243 if(cr32 & SIS_VB_SVIDEO) ivideo->vbflags |= TV_SVIDEO;
2244 if(cr32 & SIS_VB_COMPOSITE) ivideo->vbflags |= TV_AVIDEO;
2245 }
2246 }
2247
2248 if(!(ivideo->vbflags & (TV_YPBPR | TV_HIVISION))) {
2249 if(ivideo->sisfb_tvstd != -1) {
2250 ivideo->vbflags &= ~(TV_NTSC | TV_PAL | TV_PALM | TV_PALN | TV_NTSCJ);
2251 ivideo->vbflags |= ivideo->sisfb_tvstd;
2252 }
2253 if(ivideo->vbflags & TV_SCART) {
2254 ivideo->vbflags &= ~(TV_NTSC | TV_PALM | TV_PALN | TV_NTSCJ);
2255 ivideo->vbflags |= TV_PAL;
2256 }
2257 if(!(ivideo->vbflags & (TV_PAL | TV_NTSC | TV_PALM | TV_PALN | TV_NTSCJ))) {
2258 if(ivideo->sisvga_engine == SIS_300_VGA) {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07002259 inSISIDXREG(SISSR, 0x38, temp);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002260 if(temp & 0x01) ivideo->vbflags |= TV_PAL;
2261 else ivideo->vbflags |= TV_NTSC;
2262 } else if((ivideo->chip <= SIS_315PRO) || (ivideo->chip >= SIS_330)) {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07002263 inSISIDXREG(SISSR, 0x38, temp);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002264 if(temp & 0x01) ivideo->vbflags |= TV_PAL;
2265 else ivideo->vbflags |= TV_NTSC;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07002266 } else {
2267 inSISIDXREG(SISCR, 0x79, temp);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002268 if(temp & 0x20) ivideo->vbflags |= TV_PAL;
2269 else ivideo->vbflags |= TV_NTSC;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07002270 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002271 }
2272 }
2273
2274 /* Copy forceCRT1 option to CRT1off if option is given */
Thomas Winischhofer544393f2005-09-09 13:04:45 -07002275 if(ivideo->sisfb_forcecrt1 != -1) {
2276 ivideo->sisfb_crt1off = (ivideo->sisfb_forcecrt1) ? 0 : 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002277 }
2278}
2279
2280/* ------------------ Sensing routines ------------------ */
2281
Thomas Winischhofer544393f2005-09-09 13:04:45 -07002282static BOOLEAN __devinit
2283sisfb_test_DDC1(struct sis_video_info *ivideo)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002284{
2285 unsigned short old;
2286 int count = 48;
2287
2288 old = SiS_ReadDDC1Bit(&ivideo->SiS_Pr);
2289 do {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07002290 if(old != SiS_ReadDDC1Bit(&ivideo->SiS_Pr)) break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002291 } while(count--);
2292 return (count == -1) ? FALSE : TRUE;
2293}
2294
Thomas Winischhofer544393f2005-09-09 13:04:45 -07002295static void __devinit
2296sisfb_sense_crt1(struct sis_video_info *ivideo)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002297{
2298 BOOLEAN mustwait = FALSE;
2299 u8 sr1F, cr17;
2300#ifdef CONFIG_FB_SIS_315
2301 u8 cr63=0;
2302#endif
2303 u16 temp = 0xffff;
2304 int i;
2305
2306 inSISIDXREG(SISSR,0x1F,sr1F);
2307 orSISIDXREG(SISSR,0x1F,0x04);
2308 andSISIDXREG(SISSR,0x1F,0x3F);
2309 if(sr1F & 0xc0) mustwait = TRUE;
2310
2311#ifdef CONFIG_FB_SIS_315
2312 if(ivideo->sisvga_engine == SIS_315_VGA) {
2313 inSISIDXREG(SISCR,ivideo->SiS_Pr.SiS_MyCR63,cr63);
2314 cr63 &= 0x40;
2315 andSISIDXREG(SISCR,ivideo->SiS_Pr.SiS_MyCR63,0xBF);
2316 }
2317#endif
2318
2319 inSISIDXREG(SISCR,0x17,cr17);
2320 cr17 &= 0x80;
2321 if(!cr17) {
2322 orSISIDXREG(SISCR,0x17,0x80);
2323 mustwait = TRUE;
2324 outSISIDXREG(SISSR, 0x00, 0x01);
2325 outSISIDXREG(SISSR, 0x00, 0x03);
2326 }
2327
2328 if(mustwait) {
2329 for(i=0; i < 10; i++) sisfbwaitretracecrt1(ivideo);
2330 }
2331
2332#ifdef CONFIG_FB_SIS_315
2333 if(ivideo->chip >= SIS_330) {
2334 andSISIDXREG(SISCR,0x32,~0x20);
2335 if(ivideo->chip >= SIS_340) {
2336 outSISIDXREG(SISCR, 0x57, 0x4a);
2337 } else {
2338 outSISIDXREG(SISCR, 0x57, 0x5f);
2339 }
2340 orSISIDXREG(SISCR, 0x53, 0x02);
2341 while((inSISREG(SISINPSTAT)) & 0x01) break;
2342 while(!((inSISREG(SISINPSTAT)) & 0x01)) break;
2343 if((inSISREG(SISMISCW)) & 0x10) temp = 1;
2344 andSISIDXREG(SISCR, 0x53, 0xfd);
2345 andSISIDXREG(SISCR, 0x57, 0x00);
2346 }
2347#endif
2348
2349 if(temp == 0xffff) {
2350 i = 3;
2351 do {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07002352 temp = SiS_HandleDDC(&ivideo->SiS_Pr, ivideo->vbflags,
2353 ivideo->sisvga_engine, 0, 0, NULL, ivideo->vbflags2);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002354 } while(((temp == 0) || (temp == 0xffff)) && i--);
2355
2356 if((temp == 0) || (temp == 0xffff)) {
2357 if(sisfb_test_DDC1(ivideo)) temp = 1;
2358 }
2359 }
2360
2361 if((temp) && (temp != 0xffff)) {
2362 orSISIDXREG(SISCR,0x32,0x20);
2363 }
2364
2365#ifdef CONFIG_FB_SIS_315
2366 if(ivideo->sisvga_engine == SIS_315_VGA) {
2367 setSISIDXREG(SISCR,ivideo->SiS_Pr.SiS_MyCR63,0xBF,cr63);
2368 }
2369#endif
2370
2371 setSISIDXREG(SISCR,0x17,0x7F,cr17);
2372
2373 outSISIDXREG(SISSR,0x1F,sr1F);
2374}
2375
2376/* Determine and detect attached devices on SiS30x */
Thomas Winischhofer544393f2005-09-09 13:04:45 -07002377static void __devinit
2378SiS_SenseLCD(struct sis_video_info *ivideo)
2379{
2380 unsigned char buffer[256];
2381 unsigned short temp, realcrtno, i;
2382 u8 reg, cr37 = 0, paneltype = 0;
2383 u16 xres, yres;
2384
2385 ivideo->SiS_Pr.PanelSelfDetected = FALSE;
2386
2387 /* LCD detection only for TMDS bridges */
2388 if(!(ivideo->vbflags2 & VB2_SISTMDSBRIDGE))
2389 return;
2390 if(ivideo->vbflags2 & VB2_30xBDH)
2391 return;
2392
2393 /* If LCD already set up by BIOS, skip it */
2394 inSISIDXREG(SISCR, 0x32, reg);
2395 if(reg & 0x08)
2396 return;
2397
2398 realcrtno = 1;
2399 if(ivideo->SiS_Pr.DDCPortMixup)
2400 realcrtno = 0;
2401
2402 /* Check DDC capabilities */
2403 temp = SiS_HandleDDC(&ivideo->SiS_Pr, ivideo->vbflags, ivideo->sisvga_engine,
2404 realcrtno, 0, &buffer[0], ivideo->vbflags2);
2405
2406 if((!temp) || (temp == 0xffff) || (!(temp & 0x02)))
2407 return;
2408
2409 /* Read DDC data */
2410 i = 3; /* Number of retrys */
2411 do {
2412 temp = SiS_HandleDDC(&ivideo->SiS_Pr, ivideo->vbflags,
2413 ivideo->sisvga_engine, realcrtno, 1,
2414 &buffer[0], ivideo->vbflags2);
2415 } while((temp) && i--);
2416
2417 if(temp)
2418 return;
2419
2420 /* No digital device */
2421 if(!(buffer[0x14] & 0x80))
2422 return;
2423
2424 /* First detailed timing preferred timing? */
2425 if(!(buffer[0x18] & 0x02))
2426 return;
2427
2428 xres = buffer[0x38] | ((buffer[0x3a] & 0xf0) << 4);
2429 yres = buffer[0x3b] | ((buffer[0x3d] & 0xf0) << 4);
2430
2431 switch(xres) {
2432 case 1024:
2433 if(yres == 768)
2434 paneltype = 0x02;
2435 break;
2436 case 1280:
2437 if(yres == 1024)
2438 paneltype = 0x03;
2439 break;
2440 case 1600:
2441 if((yres == 1200) && (ivideo->vbflags2 & VB2_30xC))
2442 paneltype = 0x0b;
2443 break;
2444 }
2445
2446 if(!paneltype)
2447 return;
2448
2449 if(buffer[0x23])
2450 cr37 |= 0x10;
2451
2452 if((buffer[0x47] & 0x18) == 0x18)
2453 cr37 |= ((((buffer[0x47] & 0x06) ^ 0x06) << 5) | 0x20);
2454 else
2455 cr37 |= 0xc0;
2456
2457 outSISIDXREG(SISCR, 0x36, paneltype);
2458 cr37 &= 0xf1;
2459 setSISIDXREG(SISCR, 0x37, 0x0c, cr37);
2460 orSISIDXREG(SISCR, 0x32, 0x08);
2461
2462 ivideo->SiS_Pr.PanelSelfDetected = TRUE;
2463}
2464
2465static int __devinit
2466SISDoSense(struct sis_video_info *ivideo, u16 type, u16 test)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002467{
2468 int temp, mytest, result, i, j;
2469
2470 for(j = 0; j < 10; j++) {
2471 result = 0;
2472 for(i = 0; i < 3; i++) {
2473 mytest = test;
2474 outSISIDXREG(SISPART4,0x11,(type & 0x00ff));
2475 temp = (type >> 8) | (mytest & 0x00ff);
2476 setSISIDXREG(SISPART4,0x10,0xe0,temp);
2477 SiS_DDC2Delay(&ivideo->SiS_Pr, 0x1500);
2478 mytest >>= 8;
2479 mytest &= 0x7f;
2480 inSISIDXREG(SISPART4,0x03,temp);
2481 temp ^= 0x0e;
2482 temp &= mytest;
2483 if(temp == mytest) result++;
2484#if 1
2485 outSISIDXREG(SISPART4,0x11,0x00);
2486 andSISIDXREG(SISPART4,0x10,0xe0);
2487 SiS_DDC2Delay(&ivideo->SiS_Pr, 0x1000);
2488#endif
2489 }
2490 if((result == 0) || (result >= 2)) break;
2491 }
Thomas Winischhofer544393f2005-09-09 13:04:45 -07002492 return result;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002493}
2494
Thomas Winischhofer544393f2005-09-09 13:04:45 -07002495static void __devinit
2496SiS_Sense30x(struct sis_video_info *ivideo)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002497{
2498 u8 backupP4_0d,backupP2_00,backupP2_4d,backupSR_1e,biosflag=0;
2499 u16 svhs=0, svhs_c=0;
2500 u16 cvbs=0, cvbs_c=0;
2501 u16 vga2=0, vga2_c=0;
2502 int myflag, result;
2503 char stdstr[] = "sisfb: Detected";
2504 char tvstr[] = "TV connected to";
2505
Thomas Winischhofer544393f2005-09-09 13:04:45 -07002506 if(ivideo->vbflags2 & VB2_301) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002507 svhs = 0x00b9; cvbs = 0x00b3; vga2 = 0x00d1;
2508 inSISIDXREG(SISPART4,0x01,myflag);
2509 if(myflag & 0x04) {
2510 svhs = 0x00dd; cvbs = 0x00ee; vga2 = 0x00fd;
2511 }
Thomas Winischhofer544393f2005-09-09 13:04:45 -07002512 } else if(ivideo->vbflags2 & (VB2_301B | VB2_302B)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002513 svhs = 0x016b; cvbs = 0x0174; vga2 = 0x0190;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07002514 } else if(ivideo->vbflags2 & (VB2_301LV | VB2_302LV)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002515 svhs = 0x0200; cvbs = 0x0100;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07002516 } else if(ivideo->vbflags2 & (VB2_301C | VB2_302ELV | VB2_307T | VB2_307LV)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002517 svhs = 0x016b; cvbs = 0x0110; vga2 = 0x0190;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07002518 } else
2519 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002520
2521 vga2_c = 0x0e08; svhs_c = 0x0404; cvbs_c = 0x0804;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07002522 if(ivideo->vbflags & (VB2_301LV|VB2_302LV|VB2_302ELV|VB2_307LV)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002523 svhs_c = 0x0408; cvbs_c = 0x0808;
2524 }
Thomas Winischhofer544393f2005-09-09 13:04:45 -07002525
Linus Torvalds1da177e2005-04-16 15:20:36 -07002526 biosflag = 2;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07002527 if(ivideo->haveXGIROM) {
2528 biosflag = ivideo->bios_abase[0x58] & 0x03;
2529 } else if(ivideo->newrom) {
2530 if(ivideo->bios_abase[0x5d] & 0x04) biosflag |= 0x01;
2531 } else if(ivideo->sisvga_engine == SIS_300_VGA) {
2532 if(ivideo->bios_abase) {
2533 biosflag = ivideo->bios_abase[0xfe] & 0x03;
2534 }
2535 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002536
2537 if(ivideo->chip == SIS_300) {
2538 inSISIDXREG(SISSR,0x3b,myflag);
2539 if(!(myflag & 0x01)) vga2 = vga2_c = 0;
2540 }
2541
Thomas Winischhofer544393f2005-09-09 13:04:45 -07002542 if(!(ivideo->vbflags2 & VB2_SISVGA2BRIDGE)) {
2543 vga2 = vga2_c = 0;
2544 }
2545
Linus Torvalds1da177e2005-04-16 15:20:36 -07002546 inSISIDXREG(SISSR,0x1e,backupSR_1e);
2547 orSISIDXREG(SISSR,0x1e,0x20);
2548
2549 inSISIDXREG(SISPART4,0x0d,backupP4_0d);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07002550 if(ivideo->vbflags2 & VB2_30xC) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002551 setSISIDXREG(SISPART4,0x0d,~0x07,0x01);
2552 } else {
2553 orSISIDXREG(SISPART4,0x0d,0x04);
2554 }
2555 SiS_DDC2Delay(&ivideo->SiS_Pr, 0x2000);
2556
2557 inSISIDXREG(SISPART2,0x00,backupP2_00);
2558 outSISIDXREG(SISPART2,0x00,((backupP2_00 | 0x1c) & 0xfc));
2559
2560 inSISIDXREG(SISPART2,0x4d,backupP2_4d);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07002561 if(ivideo->vbflags2 & VB2_SISYPBPRBRIDGE) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002562 outSISIDXREG(SISPART2,0x4d,(backupP2_4d & ~0x10));
2563 }
2564
Thomas Winischhofer544393f2005-09-09 13:04:45 -07002565 if(!(ivideo->vbflags2 & VB2_30xCLV)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002566 SISDoSense(ivideo, 0, 0);
2567 }
2568
2569 andSISIDXREG(SISCR, 0x32, ~0x14);
2570
2571 if(vga2_c || vga2) {
2572 if(SISDoSense(ivideo, vga2, vga2_c)) {
2573 if(biosflag & 0x01) {
2574 printk(KERN_INFO "%s %s SCART output\n", stdstr, tvstr);
2575 orSISIDXREG(SISCR, 0x32, 0x04);
2576 } else {
2577 printk(KERN_INFO "%s secondary VGA connection\n", stdstr);
2578 orSISIDXREG(SISCR, 0x32, 0x10);
2579 }
2580 }
2581 }
2582
2583 andSISIDXREG(SISCR, 0x32, 0x3f);
2584
Thomas Winischhofer544393f2005-09-09 13:04:45 -07002585 if(ivideo->vbflags2 & VB2_30xCLV) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002586 orSISIDXREG(SISPART4,0x0d,0x04);
2587 }
2588
Thomas Winischhofer544393f2005-09-09 13:04:45 -07002589 if((ivideo->sisvga_engine == SIS_315_VGA) && (ivideo->vbflags2 & VB2_SISYPBPRBRIDGE)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002590 outSISIDXREG(SISPART2,0x4d,(backupP2_4d | 0x10));
2591 SiS_DDC2Delay(&ivideo->SiS_Pr, 0x2000);
2592 if((result = SISDoSense(ivideo, svhs, 0x0604))) {
2593 if((result = SISDoSense(ivideo, cvbs, 0x0804))) {
2594 printk(KERN_INFO "%s %s YPbPr component output\n", stdstr, tvstr);
2595 orSISIDXREG(SISCR,0x32,0x80);
2596 }
2597 }
2598 outSISIDXREG(SISPART2,0x4d,backupP2_4d);
2599 }
2600
2601 andSISIDXREG(SISCR, 0x32, ~0x03);
2602
2603 if(!(ivideo->vbflags & TV_YPBPR)) {
2604 if((result = SISDoSense(ivideo, svhs, svhs_c))) {
2605 printk(KERN_INFO "%s %s SVIDEO output\n", stdstr, tvstr);
2606 orSISIDXREG(SISCR, 0x32, 0x02);
2607 }
2608 if((biosflag & 0x02) || (!result)) {
2609 if(SISDoSense(ivideo, cvbs, cvbs_c)) {
2610 printk(KERN_INFO "%s %s COMPOSITE output\n", stdstr, tvstr);
2611 orSISIDXREG(SISCR, 0x32, 0x01);
2612 }
2613 }
2614 }
2615
2616 SISDoSense(ivideo, 0, 0);
2617
2618 outSISIDXREG(SISPART2,0x00,backupP2_00);
2619 outSISIDXREG(SISPART4,0x0d,backupP4_0d);
2620 outSISIDXREG(SISSR,0x1e,backupSR_1e);
2621
Thomas Winischhofer544393f2005-09-09 13:04:45 -07002622 if(ivideo->vbflags2 & VB2_30xCLV) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002623 inSISIDXREG(SISPART2,0x00,biosflag);
2624 if(biosflag & 0x20) {
2625 for(myflag = 2; myflag > 0; myflag--) {
2626 biosflag ^= 0x20;
2627 outSISIDXREG(SISPART2,0x00,biosflag);
2628 }
2629 }
2630 }
2631
2632 outSISIDXREG(SISPART2,0x00,backupP2_00);
2633}
2634
2635/* Determine and detect attached TV's on Chrontel */
Thomas Winischhofer544393f2005-09-09 13:04:45 -07002636static void __devinit
2637SiS_SenseCh(struct sis_video_info *ivideo)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002638{
2639#if defined(CONFIG_FB_SIS_300) || defined(CONFIG_FB_SIS_315)
2640 u8 temp1, temp2;
2641 char stdstr[] = "sisfb: Chrontel: Detected TV connected to";
2642#endif
2643#ifdef CONFIG_FB_SIS_300
2644 unsigned char test[3];
2645 int i;
2646#endif
2647
2648 if(ivideo->chip < SIS_315H) {
2649
2650#ifdef CONFIG_FB_SIS_300
2651 ivideo->SiS_Pr.SiS_IF_DEF_CH70xx = 1; /* Chrontel 700x */
2652 SiS_SetChrontelGPIO(&ivideo->SiS_Pr, 0x9c); /* Set general purpose IO for Chrontel communication */
2653 SiS_DDC2Delay(&ivideo->SiS_Pr, 1000);
2654 temp1 = SiS_GetCH700x(&ivideo->SiS_Pr, 0x25);
2655 /* See Chrontel TB31 for explanation */
2656 temp2 = SiS_GetCH700x(&ivideo->SiS_Pr, 0x0e);
2657 if(((temp2 & 0x07) == 0x01) || (temp2 & 0x04)) {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07002658 SiS_SetCH700x(&ivideo->SiS_Pr, 0x0e, 0x0b);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002659 SiS_DDC2Delay(&ivideo->SiS_Pr, 300);
2660 }
2661 temp2 = SiS_GetCH700x(&ivideo->SiS_Pr, 0x25);
2662 if(temp2 != temp1) temp1 = temp2;
2663
2664 if((temp1 >= 0x22) && (temp1 <= 0x50)) {
2665 /* Read power status */
2666 temp1 = SiS_GetCH700x(&ivideo->SiS_Pr, 0x0e);
2667 if((temp1 & 0x03) != 0x03) {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07002668 /* Power all outputs */
2669 SiS_SetCH700x(&ivideo->SiS_Pr, 0x0e,0x0b);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002670 SiS_DDC2Delay(&ivideo->SiS_Pr, 300);
2671 }
2672 /* Sense connected TV devices */
2673 for(i = 0; i < 3; i++) {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07002674 SiS_SetCH700x(&ivideo->SiS_Pr, 0x10, 0x01);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002675 SiS_DDC2Delay(&ivideo->SiS_Pr, 0x96);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07002676 SiS_SetCH700x(&ivideo->SiS_Pr, 0x10, 0x00);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002677 SiS_DDC2Delay(&ivideo->SiS_Pr, 0x96);
2678 temp1 = SiS_GetCH700x(&ivideo->SiS_Pr, 0x10);
2679 if(!(temp1 & 0x08)) test[i] = 0x02;
2680 else if(!(temp1 & 0x02)) test[i] = 0x01;
2681 else test[i] = 0;
2682 SiS_DDC2Delay(&ivideo->SiS_Pr, 0x96);
2683 }
2684
2685 if(test[0] == test[1]) temp1 = test[0];
2686 else if(test[0] == test[2]) temp1 = test[0];
2687 else if(test[1] == test[2]) temp1 = test[1];
2688 else {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07002689 printk(KERN_INFO
Linus Torvalds1da177e2005-04-16 15:20:36 -07002690 "sisfb: TV detection unreliable - test results varied\n");
2691 temp1 = test[2];
2692 }
2693 if(temp1 == 0x02) {
2694 printk(KERN_INFO "%s SVIDEO output\n", stdstr);
2695 ivideo->vbflags |= TV_SVIDEO;
2696 orSISIDXREG(SISCR, 0x32, 0x02);
2697 andSISIDXREG(SISCR, 0x32, ~0x05);
2698 } else if (temp1 == 0x01) {
2699 printk(KERN_INFO "%s CVBS output\n", stdstr);
2700 ivideo->vbflags |= TV_AVIDEO;
2701 orSISIDXREG(SISCR, 0x32, 0x01);
2702 andSISIDXREG(SISCR, 0x32, ~0x06);
2703 } else {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07002704 SiS_SetCH70xxANDOR(&ivideo->SiS_Pr, 0x0e, 0x01, 0xF8);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002705 andSISIDXREG(SISCR, 0x32, ~0x07);
2706 }
2707 } else if(temp1 == 0) {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07002708 SiS_SetCH70xxANDOR(&ivideo->SiS_Pr, 0x0e, 0x01, 0xF8);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002709 andSISIDXREG(SISCR, 0x32, ~0x07);
2710 }
2711 /* Set general purpose IO for Chrontel communication */
2712 SiS_SetChrontelGPIO(&ivideo->SiS_Pr, 0x00);
2713#endif
2714
2715 } else {
2716
2717#ifdef CONFIG_FB_SIS_315
2718 ivideo->SiS_Pr.SiS_IF_DEF_CH70xx = 2; /* Chrontel 7019 */
Thomas Winischhofer544393f2005-09-09 13:04:45 -07002719 temp1 = SiS_GetCH701x(&ivideo->SiS_Pr, 0x49);
2720 SiS_SetCH701x(&ivideo->SiS_Pr, 0x49, 0x20);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002721 SiS_DDC2Delay(&ivideo->SiS_Pr, 0x96);
2722 temp2 = SiS_GetCH701x(&ivideo->SiS_Pr, 0x20);
2723 temp2 |= 0x01;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07002724 SiS_SetCH701x(&ivideo->SiS_Pr, 0x20, temp2);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002725 SiS_DDC2Delay(&ivideo->SiS_Pr, 0x96);
2726 temp2 ^= 0x01;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07002727 SiS_SetCH701x(&ivideo->SiS_Pr, 0x20, temp2);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002728 SiS_DDC2Delay(&ivideo->SiS_Pr, 0x96);
2729 temp2 = SiS_GetCH701x(&ivideo->SiS_Pr, 0x20);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07002730 SiS_SetCH701x(&ivideo->SiS_Pr, 0x49, temp1);
2731 temp1 = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002732 if(temp2 & 0x02) temp1 |= 0x01;
2733 if(temp2 & 0x10) temp1 |= 0x01;
2734 if(temp2 & 0x04) temp1 |= 0x02;
2735 if( (temp1 & 0x01) && (temp1 & 0x02) ) temp1 = 0x04;
2736 switch(temp1) {
2737 case 0x01:
2738 printk(KERN_INFO "%s CVBS output\n", stdstr);
2739 ivideo->vbflags |= TV_AVIDEO;
2740 orSISIDXREG(SISCR, 0x32, 0x01);
2741 andSISIDXREG(SISCR, 0x32, ~0x06);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07002742 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002743 case 0x02:
2744 printk(KERN_INFO "%s SVIDEO output\n", stdstr);
2745 ivideo->vbflags |= TV_SVIDEO;
2746 orSISIDXREG(SISCR, 0x32, 0x02);
2747 andSISIDXREG(SISCR, 0x32, ~0x05);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07002748 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002749 case 0x04:
2750 printk(KERN_INFO "%s SCART output\n", stdstr);
2751 orSISIDXREG(SISCR, 0x32, 0x04);
2752 andSISIDXREG(SISCR, 0x32, ~0x03);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07002753 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002754 default:
2755 andSISIDXREG(SISCR, 0x32, ~0x07);
2756 }
2757#endif
2758 }
2759}
2760
Thomas Winischhofer544393f2005-09-09 13:04:45 -07002761static void __devinit
2762sisfb_get_VB_type(struct sis_video_info *ivideo)
2763{
2764 char stdstr[] = "sisfb: Detected";
2765 char bridgestr[] = "video bridge";
2766 u8 vb_chipid;
2767 u8 reg;
2768
2769 /* No CRT2 on XGI Z7 */
2770 if(ivideo->chip == XGI_20)
2771 return;
2772
2773 inSISIDXREG(SISPART4, 0x00, vb_chipid);
2774 switch(vb_chipid) {
2775 case 0x01:
2776 inSISIDXREG(SISPART4, 0x01, reg);
2777 if(reg < 0xb0) {
2778 ivideo->vbflags |= VB_301; /* Deprecated */
2779 ivideo->vbflags2 |= VB2_301;
2780 printk(KERN_INFO "%s SiS301 %s\n", stdstr, bridgestr);
2781 } else if(reg < 0xc0) {
2782 ivideo->vbflags |= VB_301B; /* Deprecated */
2783 ivideo->vbflags2 |= VB2_301B;
2784 inSISIDXREG(SISPART4,0x23,reg);
2785 if(!(reg & 0x02)) {
2786 ivideo->vbflags |= VB_30xBDH; /* Deprecated */
2787 ivideo->vbflags2 |= VB2_30xBDH;
2788 printk(KERN_INFO "%s SiS301B-DH %s\n", stdstr, bridgestr);
2789 } else {
2790 printk(KERN_INFO "%s SiS301B %s\n", stdstr, bridgestr);
2791 }
2792 } else if(reg < 0xd0) {
2793 ivideo->vbflags |= VB_301C; /* Deprecated */
2794 ivideo->vbflags2 |= VB2_301C;
2795 printk(KERN_INFO "%s SiS301C %s\n", stdstr, bridgestr);
2796 } else if(reg < 0xe0) {
2797 ivideo->vbflags |= VB_301LV; /* Deprecated */
2798 ivideo->vbflags2 |= VB2_301LV;
2799 printk(KERN_INFO "%s SiS301LV %s\n", stdstr, bridgestr);
2800 } else if(reg <= 0xe1) {
2801 inSISIDXREG(SISPART4,0x39,reg);
2802 if(reg == 0xff) {
2803 ivideo->vbflags |= VB_302LV; /* Deprecated */
2804 ivideo->vbflags2 |= VB2_302LV;
2805 printk(KERN_INFO "%s SiS302LV %s\n", stdstr, bridgestr);
2806 } else {
2807 ivideo->vbflags |= VB_301C; /* Deprecated */
2808 ivideo->vbflags2 |= VB2_301C;
2809 printk(KERN_INFO "%s SiS301C(P4) %s\n", stdstr, bridgestr);
2810#if 0
2811 ivideo->vbflags |= VB_302ELV; /* Deprecated */
2812 ivideo->vbflags2 |= VB2_302ELV;
2813 printk(KERN_INFO "%s SiS302ELV %s\n", stdstr, bridgestr);
2814#endif
2815 }
2816 }
2817 break;
2818 case 0x02:
2819 ivideo->vbflags |= VB_302B; /* Deprecated */
2820 ivideo->vbflags2 |= VB2_302B;
2821 printk(KERN_INFO "%s SiS302B %s\n", stdstr, bridgestr);
2822 break;
2823 }
2824
2825 if((!(ivideo->vbflags2 & VB2_VIDEOBRIDGE)) && (ivideo->chip != SIS_300)) {
2826 inSISIDXREG(SISCR, 0x37, reg);
2827 reg &= SIS_EXTERNAL_CHIP_MASK;
2828 reg >>= 1;
2829 if(ivideo->sisvga_engine == SIS_300_VGA) {
2830#ifdef CONFIG_FB_SIS_300
2831 switch(reg) {
2832 case SIS_EXTERNAL_CHIP_LVDS:
2833 ivideo->vbflags |= VB_LVDS; /* Deprecated */
2834 ivideo->vbflags2 |= VB2_LVDS;
2835 break;
2836 case SIS_EXTERNAL_CHIP_TRUMPION:
2837 ivideo->vbflags |= (VB_LVDS | VB_TRUMPION); /* Deprecated */
2838 ivideo->vbflags2 |= (VB2_LVDS | VB2_TRUMPION);
2839 break;
2840 case SIS_EXTERNAL_CHIP_CHRONTEL:
2841 ivideo->vbflags |= VB_CHRONTEL; /* Deprecated */
2842 ivideo->vbflags2 |= VB2_CHRONTEL;
2843 break;
2844 case SIS_EXTERNAL_CHIP_LVDS_CHRONTEL:
2845 ivideo->vbflags |= (VB_LVDS | VB_CHRONTEL); /* Deprecated */
2846 ivideo->vbflags2 |= (VB2_LVDS | VB2_CHRONTEL);
2847 break;
2848 }
2849 if(ivideo->vbflags2 & VB2_CHRONTEL) ivideo->chronteltype = 1;
2850#endif
2851 } else if(ivideo->chip < SIS_661) {
2852#ifdef CONFIG_FB_SIS_315
2853 switch (reg) {
2854 case SIS310_EXTERNAL_CHIP_LVDS:
2855 ivideo->vbflags |= VB_LVDS; /* Deprecated */
2856 ivideo->vbflags2 |= VB2_LVDS;
2857 break;
2858 case SIS310_EXTERNAL_CHIP_LVDS_CHRONTEL:
2859 ivideo->vbflags |= (VB_LVDS | VB_CHRONTEL); /* Deprecated */
2860 ivideo->vbflags2 |= (VB2_LVDS | VB2_CHRONTEL);
2861 break;
2862 }
2863 if(ivideo->vbflags2 & VB2_CHRONTEL) ivideo->chronteltype = 2;
2864#endif
2865 } else if(ivideo->chip >= SIS_661) {
2866#ifdef CONFIG_FB_SIS_315
2867 inSISIDXREG(SISCR, 0x38, reg);
2868 reg >>= 5;
2869 switch(reg) {
2870 case 0x02:
2871 ivideo->vbflags |= VB_LVDS; /* Deprecated */
2872 ivideo->vbflags2 |= VB2_LVDS;
2873 break;
2874 case 0x03:
2875 ivideo->vbflags |= (VB_LVDS | VB_CHRONTEL); /* Deprecated */
2876 ivideo->vbflags2 |= (VB2_LVDS | VB2_CHRONTEL);
2877 break;
2878 case 0x04:
2879 ivideo->vbflags |= (VB_LVDS | VB_CONEXANT); /* Deprecated */
2880 ivideo->vbflags2 |= (VB2_LVDS | VB2_CONEXANT);
2881 break;
2882 }
2883 if(ivideo->vbflags2 & VB2_CHRONTEL) ivideo->chronteltype = 2;
2884#endif
2885 }
2886 if(ivideo->vbflags2 & VB2_LVDS) {
2887 printk(KERN_INFO "%s LVDS transmitter\n", stdstr);
2888 }
2889 if((ivideo->sisvga_engine == SIS_300_VGA) && (ivideo->vbflags2 & VB2_TRUMPION)) {
2890 printk(KERN_INFO "%s Trumpion Zurac LCD scaler\n", stdstr);
2891 }
2892 if(ivideo->vbflags2 & VB2_CHRONTEL) {
2893 printk(KERN_INFO "%s Chrontel TV encoder\n", stdstr);
2894 }
2895 if((ivideo->chip >= SIS_661) && (ivideo->vbflags2 & VB2_CONEXANT)) {
2896 printk(KERN_INFO "%s Conexant external device\n", stdstr);
2897 }
2898 }
2899
2900 if(ivideo->vbflags2 & VB2_SISBRIDGE) {
2901 SiS_SenseLCD(ivideo);
2902 SiS_Sense30x(ivideo);
2903 } else if(ivideo->vbflags2 & VB2_CHRONTEL) {
2904 SiS_SenseCh(ivideo);
2905 }
2906}
2907
2908/* ---------- Engine initialization routines ------------ */
2909
2910static void
2911sisfb_engine_init(struct sis_video_info *ivideo)
2912{
2913
2914 /* Initialize command queue (we use MMIO only) */
2915
2916 /* BEFORE THIS IS CALLED, THE ENGINES *MUST* BE SYNC'ED */
2917
2918 ivideo->caps &= ~(TURBO_QUEUE_CAP |
2919 MMIO_CMD_QUEUE_CAP |
2920 VM_CMD_QUEUE_CAP |
2921 AGP_CMD_QUEUE_CAP);
2922
2923#ifdef CONFIG_FB_SIS_300
2924 if(ivideo->sisvga_engine == SIS_300_VGA) {
2925 u32 tqueue_pos;
2926 u8 tq_state;
2927
2928 tqueue_pos = (ivideo->video_size - ivideo->cmdQueueSize) / (64 * 1024);
2929
2930 inSISIDXREG(SISSR, IND_SIS_TURBOQUEUE_SET, tq_state);
2931 tq_state |= 0xf0;
2932 tq_state &= 0xfc;
2933 tq_state |= (u8)(tqueue_pos >> 8);
2934 outSISIDXREG(SISSR, IND_SIS_TURBOQUEUE_SET, tq_state);
2935
2936 outSISIDXREG(SISSR, IND_SIS_TURBOQUEUE_ADR, (u8)(tqueue_pos & 0xff));
2937
2938 ivideo->caps |= TURBO_QUEUE_CAP;
2939 }
2940#endif
2941
2942#ifdef CONFIG_FB_SIS_315
2943 if(ivideo->sisvga_engine == SIS_315_VGA) {
2944 u32 tempq = 0, templ;
2945 u8 temp;
2946
2947 if(ivideo->chip == XGI_20) {
2948 switch(ivideo->cmdQueueSize) {
2949 case (64 * 1024):
2950 temp = SIS_CMD_QUEUE_SIZE_Z7_64k;
2951 break;
2952 case (128 * 1024):
2953 default:
2954 temp = SIS_CMD_QUEUE_SIZE_Z7_128k;
2955 }
2956 } else {
2957 switch(ivideo->cmdQueueSize) {
2958 case (4 * 1024 * 1024):
2959 temp = SIS_CMD_QUEUE_SIZE_4M;
2960 break;
2961 case (2 * 1024 * 1024):
2962 temp = SIS_CMD_QUEUE_SIZE_2M;
2963 break;
2964 case (1 * 1024 * 1024):
2965 temp = SIS_CMD_QUEUE_SIZE_1M;
2966 break;
2967 default:
2968 case (512 * 1024):
2969 temp = SIS_CMD_QUEUE_SIZE_512k;
2970 }
2971 }
2972
2973 outSISIDXREG(SISSR, IND_SIS_CMDQUEUE_THRESHOLD, COMMAND_QUEUE_THRESHOLD);
2974 outSISIDXREG(SISSR, IND_SIS_CMDQUEUE_SET, SIS_CMD_QUEUE_RESET);
2975
2976 if((ivideo->chip >= XGI_40) && ivideo->modechanged) {
2977 /* Must disable dual pipe on XGI_40. Can't do
2978 * this in MMIO mode, because it requires
2979 * setting/clearing a bit in the MMIO fire trigger
2980 * register.
2981 */
2982 if(!((templ = MMIO_IN32(ivideo->mmio_vbase, 0x8240)) & (1 << 10))) {
2983
2984 MMIO_OUT32(ivideo->mmio_vbase, Q_WRITE_PTR, 0);
2985
2986 outSISIDXREG(SISSR, IND_SIS_CMDQUEUE_SET, (temp | SIS_VRAM_CMDQUEUE_ENABLE));
2987
2988 tempq = MMIO_IN32(ivideo->mmio_vbase, Q_READ_PTR);
2989 MMIO_OUT32(ivideo->mmio_vbase, Q_WRITE_PTR, tempq);
2990
2991 tempq = (u32)(ivideo->video_size - ivideo->cmdQueueSize);
2992 MMIO_OUT32(ivideo->mmio_vbase, Q_BASE_ADDR, tempq);
2993
2994 writel(0x16800000 + 0x8240, ivideo->video_vbase + tempq);
2995 writel(templ | (1 << 10), ivideo->video_vbase + tempq + 4);
2996 writel(0x168F0000, ivideo->video_vbase + tempq + 8);
2997 writel(0x168F0000, ivideo->video_vbase + tempq + 12);
2998
2999 MMIO_OUT32(ivideo->mmio_vbase, Q_WRITE_PTR, (tempq + 16));
3000
3001 sisfb_syncaccel(ivideo);
3002
3003 outSISIDXREG(SISSR, IND_SIS_CMDQUEUE_SET, SIS_CMD_QUEUE_RESET);
3004
3005 }
3006 }
3007
3008 tempq = MMIO_IN32(ivideo->mmio_vbase, MMIO_QUEUE_READPORT);
3009 MMIO_OUT32(ivideo->mmio_vbase, MMIO_QUEUE_WRITEPORT, tempq);
3010
3011 temp |= (SIS_MMIO_CMD_ENABLE | SIS_CMD_AUTO_CORR);
3012 outSISIDXREG(SISSR, IND_SIS_CMDQUEUE_SET, temp);
3013
3014 tempq = (u32)(ivideo->video_size - ivideo->cmdQueueSize);
3015 MMIO_OUT32(ivideo->mmio_vbase, MMIO_QUEUE_PHYBASE, tempq);
3016
3017 ivideo->caps |= MMIO_CMD_QUEUE_CAP;
3018 }
3019#endif
3020
3021 ivideo->engineok = 1;
3022}
3023
3024static void __devinit
3025sisfb_detect_lcd_type(struct sis_video_info *ivideo)
3026{
3027 u8 reg;
3028 int i;
3029
3030 inSISIDXREG(SISCR, 0x36, reg);
3031 reg &= 0x0f;
3032 if(ivideo->sisvga_engine == SIS_300_VGA) {
3033 ivideo->CRT2LCDType = sis300paneltype[reg];
3034 } else if(ivideo->chip >= SIS_661) {
3035 ivideo->CRT2LCDType = sis661paneltype[reg];
3036 } else {
3037 ivideo->CRT2LCDType = sis310paneltype[reg];
3038 if((ivideo->chip == SIS_550) && (sisfb_fstn)) {
3039 if((ivideo->CRT2LCDType != LCD_320x240_2) &&
3040 (ivideo->CRT2LCDType != LCD_320x240_3)) {
3041 ivideo->CRT2LCDType = LCD_320x240;
3042 }
3043 }
3044 }
3045
3046 if(ivideo->CRT2LCDType == LCD_UNKNOWN) {
3047 /* For broken BIOSes: Assume 1024x768, RGB18 */
3048 ivideo->CRT2LCDType = LCD_1024x768;
3049 setSISIDXREG(SISCR,0x36,0xf0,0x02);
3050 setSISIDXREG(SISCR,0x37,0xee,0x01);
3051 printk(KERN_DEBUG "sisfb: Invalid panel ID (%02x), assuming 1024x768, RGB18\n", reg);
3052 }
3053
3054 for(i = 0; i < SIS_LCD_NUMBER; i++) {
3055 if(ivideo->CRT2LCDType == sis_lcd_data[i].lcdtype) {
3056 ivideo->lcdxres = sis_lcd_data[i].xres;
3057 ivideo->lcdyres = sis_lcd_data[i].yres;
3058 ivideo->lcddefmodeidx = sis_lcd_data[i].default_mode_idx;
3059 break;
3060 }
3061 }
3062
3063#ifdef CONFIG_FB_SIS_300
3064 if(ivideo->SiS_Pr.SiS_CustomT == CUT_BARCO1366) {
3065 ivideo->lcdxres = 1360; ivideo->lcdyres = 1024;
3066 ivideo->lcddefmodeidx = DEFAULT_MODE_1360;
3067 } else if(ivideo->SiS_Pr.SiS_CustomT == CUT_PANEL848) {
3068 ivideo->lcdxres = 848; ivideo->lcdyres = 480;
3069 ivideo->lcddefmodeidx = DEFAULT_MODE_848;
3070 } else if(ivideo->SiS_Pr.SiS_CustomT == CUT_PANEL856) {
3071 ivideo->lcdxres = 856; ivideo->lcdyres = 480;
3072 ivideo->lcddefmodeidx = DEFAULT_MODE_856;
3073 }
3074#endif
3075
3076 printk(KERN_DEBUG "sisfb: Detected %dx%d flat panel\n",
3077 ivideo->lcdxres, ivideo->lcdyres);
3078}
3079
3080static void __devinit
3081sisfb_save_pdc_emi(struct sis_video_info *ivideo)
3082{
3083#ifdef CONFIG_FB_SIS_300
3084 /* Save the current PanelDelayCompensation if the LCD is currently used */
3085 if(ivideo->sisvga_engine == SIS_300_VGA) {
3086 if(ivideo->vbflags2 & (VB2_LVDS | VB2_30xBDH)) {
3087 int tmp;
3088 inSISIDXREG(SISCR,0x30,tmp);
3089 if(tmp & 0x20) {
3090 /* Currently on LCD? If yes, read current pdc */
3091 inSISIDXREG(SISPART1,0x13,ivideo->detectedpdc);
3092 ivideo->detectedpdc &= 0x3c;
3093 if(ivideo->SiS_Pr.PDC == -1) {
3094 /* Let option override detection */
3095 ivideo->SiS_Pr.PDC = ivideo->detectedpdc;
3096 }
3097 printk(KERN_INFO "sisfb: Detected LCD PDC 0x%02x\n",
3098 ivideo->detectedpdc);
3099 }
3100 if((ivideo->SiS_Pr.PDC != -1) &&
3101 (ivideo->SiS_Pr.PDC != ivideo->detectedpdc)) {
3102 printk(KERN_INFO "sisfb: Using LCD PDC 0x%02x\n",
3103 ivideo->SiS_Pr.PDC);
3104 }
3105 }
3106 }
3107#endif
3108
3109#ifdef CONFIG_FB_SIS_315
3110 if(ivideo->sisvga_engine == SIS_315_VGA) {
3111
3112 /* Try to find about LCDA */
3113 if(ivideo->vbflags2 & VB2_SISLCDABRIDGE) {
3114 int tmp;
3115 inSISIDXREG(SISPART1,0x13,tmp);
3116 if(tmp & 0x04) {
3117 ivideo->SiS_Pr.SiS_UseLCDA = TRUE;
3118 ivideo->detectedlcda = 0x03;
3119 }
3120 }
3121
3122 /* Save PDC */
3123 if(ivideo->vbflags2 & VB2_SISLVDSBRIDGE) {
3124 int tmp;
3125 inSISIDXREG(SISCR,0x30,tmp);
3126 if((tmp & 0x20) || (ivideo->detectedlcda != 0xff)) {
3127 /* Currently on LCD? If yes, read current pdc */
3128 u8 pdc;
3129 inSISIDXREG(SISPART1,0x2D,pdc);
3130 ivideo->detectedpdc = (pdc & 0x0f) << 1;
3131 ivideo->detectedpdca = (pdc & 0xf0) >> 3;
3132 inSISIDXREG(SISPART1,0x35,pdc);
3133 ivideo->detectedpdc |= ((pdc >> 7) & 0x01);
3134 inSISIDXREG(SISPART1,0x20,pdc);
3135 ivideo->detectedpdca |= ((pdc >> 6) & 0x01);
3136 if(ivideo->newrom) {
3137 /* New ROM invalidates other PDC resp. */
3138 if(ivideo->detectedlcda != 0xff) {
3139 ivideo->detectedpdc = 0xff;
3140 } else {
3141 ivideo->detectedpdca = 0xff;
3142 }
3143 }
3144 if(ivideo->SiS_Pr.PDC == -1) {
3145 if(ivideo->detectedpdc != 0xff) {
3146 ivideo->SiS_Pr.PDC = ivideo->detectedpdc;
3147 }
3148 }
3149 if(ivideo->SiS_Pr.PDCA == -1) {
3150 if(ivideo->detectedpdca != 0xff) {
3151 ivideo->SiS_Pr.PDCA = ivideo->detectedpdca;
3152 }
3153 }
3154 if(ivideo->detectedpdc != 0xff) {
3155 printk(KERN_INFO
3156 "sisfb: Detected LCD PDC 0x%02x (for LCD=CRT2)\n",
3157 ivideo->detectedpdc);
3158 }
3159 if(ivideo->detectedpdca != 0xff) {
3160 printk(KERN_INFO
3161 "sisfb: Detected LCD PDC1 0x%02x (for LCD=CRT1)\n",
3162 ivideo->detectedpdca);
3163 }
3164 }
3165
3166 /* Save EMI */
3167 if(ivideo->vbflags2 & VB2_SISEMIBRIDGE) {
3168 inSISIDXREG(SISPART4,0x30,ivideo->SiS_Pr.EMI_30);
3169 inSISIDXREG(SISPART4,0x31,ivideo->SiS_Pr.EMI_31);
3170 inSISIDXREG(SISPART4,0x32,ivideo->SiS_Pr.EMI_32);
3171 inSISIDXREG(SISPART4,0x33,ivideo->SiS_Pr.EMI_33);
3172 ivideo->SiS_Pr.HaveEMI = TRUE;
3173 if((tmp & 0x20) || (ivideo->detectedlcda != 0xff)) {
3174 ivideo->SiS_Pr.HaveEMILCD = TRUE;
3175 }
3176 }
3177 }
3178
3179 /* Let user override detected PDCs (all bridges) */
3180 if(ivideo->vbflags2 & VB2_30xBLV) {
3181 if((ivideo->SiS_Pr.PDC != -1) &&
3182 (ivideo->SiS_Pr.PDC != ivideo->detectedpdc)) {
3183 printk(KERN_INFO "sisfb: Using LCD PDC 0x%02x (for LCD=CRT2)\n",
3184 ivideo->SiS_Pr.PDC);
3185 }
3186 if((ivideo->SiS_Pr.PDCA != -1) &&
3187 (ivideo->SiS_Pr.PDCA != ivideo->detectedpdca)) {
3188 printk(KERN_INFO "sisfb: Using LCD PDC1 0x%02x (for LCD=CRT1)\n",
3189 ivideo->SiS_Pr.PDCA);
3190 }
3191 }
3192
3193 }
3194#endif
3195}
3196
3197/* -------------------- Memory manager routines ---------------------- */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003198
3199static u32 __devinit
3200sisfb_getheapstart(struct sis_video_info *ivideo)
3201{
3202 u32 ret = ivideo->sisfb_parm_mem * 1024;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003203 u32 maxoffs = ivideo->video_size - ivideo->hwcursor_size - ivideo->cmdQueueSize;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003204 u32 def;
3205
3206 /* Calculate heap start = end of memory for console
3207 *
3208 * CCCCCCCCDDDDDDDDDDDDDDDDDDDDDDDDDDDDHHHHQQQQQQQQQQ
3209 * C = console, D = heap, H = HWCursor, Q = cmd-queue
3210 *
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003211 * On 76x in UMA+LFB mode, the layout is as follows:
3212 * DDDDDDDDDDDCCCCCCCCCCCCCCCCCCCCCCCCHHHHQQQQQQQQQQQ
3213 * where the heap is the entire UMA area, eventually
3214 * into the LFB area if the given mem parameter is
3215 * higher than the size of the UMA memory.
3216 *
Linus Torvalds1da177e2005-04-16 15:20:36 -07003217 * Basically given by "mem" parameter
3218 *
3219 * maximum = videosize - cmd_queue - hwcursor
3220 * (results in a heap of size 0)
3221 * default = SiS 300: depends on videosize
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003222 * SiS 315/330/340/XGI: 32k below max
Linus Torvalds1da177e2005-04-16 15:20:36 -07003223 */
3224
3225 if(ivideo->sisvga_engine == SIS_300_VGA) {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003226 if(ivideo->video_size > 0x1000000) {
3227 def = 0xc00000;
3228 } else if(ivideo->video_size > 0x800000) {
3229 def = 0x800000;
3230 } else {
3231 def = 0x400000;
3232 }
3233 } else if(ivideo->UMAsize && ivideo->LFBsize) {
3234 ret = def = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003235 } else {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003236 def = maxoffs - 0x8000;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003237 }
3238
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003239 /* Use default for secondary card for now (FIXME) */
3240 if((!ret) || (ret > maxoffs) || (ivideo->cardnumber != 0))
3241 ret = def;
3242
3243 return ret;
3244}
3245
3246static u32 __devinit
3247sisfb_getheapsize(struct sis_video_info *ivideo)
3248{
3249 u32 max = ivideo->video_size - ivideo->hwcursor_size - ivideo->cmdQueueSize;
3250 u32 ret = 0;
3251
3252 if(ivideo->UMAsize && ivideo->LFBsize) {
3253 if( (!ivideo->sisfb_parm_mem) ||
3254 ((ivideo->sisfb_parm_mem * 1024) > max) ||
3255 ((max - (ivideo->sisfb_parm_mem * 1024)) < ivideo->UMAsize) ) {
3256 ret = ivideo->UMAsize;
3257 max -= ivideo->UMAsize;
3258 } else {
3259 ret = max - (ivideo->sisfb_parm_mem * 1024);
3260 max = ivideo->sisfb_parm_mem * 1024;
3261 }
3262 ivideo->video_offset = ret;
3263 ivideo->sisfb_mem = max;
3264 } else {
3265 ret = max - ivideo->heapstart;
3266 ivideo->sisfb_mem = ivideo->heapstart;
3267 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003268
3269 return ret;
3270}
3271
3272static int __devinit
3273sisfb_heap_init(struct sis_video_info *ivideo)
3274{
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003275 struct SIS_OH *poh;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003276
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003277 ivideo->video_offset = 0;
3278 if(ivideo->sisfb_parm_mem) {
3279 if( (ivideo->sisfb_parm_mem < (2 * 1024 * 1024)) ||
3280 (ivideo->sisfb_parm_mem > ivideo->video_size) ) {
3281 ivideo->sisfb_parm_mem = 0;
3282 }
3283 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003284
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003285 ivideo->heapstart = sisfb_getheapstart(ivideo);
3286 ivideo->sisfb_heap_size = sisfb_getheapsize(ivideo);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003287
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003288 ivideo->sisfb_heap_start = ivideo->video_vbase + ivideo->heapstart;
3289 ivideo->sisfb_heap_end = ivideo->sisfb_heap_start + ivideo->sisfb_heap_size;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003290
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003291 printk(KERN_INFO "sisfb: Memory heap starting at %dK, size %dK\n",
3292 (int)(ivideo->heapstart / 1024), (int)(ivideo->sisfb_heap_size / 1024));
Linus Torvalds1da177e2005-04-16 15:20:36 -07003293
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003294 ivideo->sisfb_heap.vinfo = ivideo;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003295
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003296 ivideo->sisfb_heap.poha_chain = NULL;
3297 ivideo->sisfb_heap.poh_freelist = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003298
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003299 poh = sisfb_poh_new_node(&ivideo->sisfb_heap);
3300 if(poh == NULL)
3301 return 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003302
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003303 poh->poh_next = &ivideo->sisfb_heap.oh_free;
3304 poh->poh_prev = &ivideo->sisfb_heap.oh_free;
3305 poh->size = ivideo->sisfb_heap_size;
3306 poh->offset = ivideo->heapstart;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003307
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003308 ivideo->sisfb_heap.oh_free.poh_next = poh;
3309 ivideo->sisfb_heap.oh_free.poh_prev = poh;
3310 ivideo->sisfb_heap.oh_free.size = 0;
3311 ivideo->sisfb_heap.max_freesize = poh->size;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003312
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003313 ivideo->sisfb_heap.oh_used.poh_next = &ivideo->sisfb_heap.oh_used;
3314 ivideo->sisfb_heap.oh_used.poh_prev = &ivideo->sisfb_heap.oh_used;
3315 ivideo->sisfb_heap.oh_used.size = SENTINEL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003316
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003317 if(ivideo->cardnumber == 0) {
3318 /* For the first card, make this heap the "global" one
3319 * for old DRM (which could handle only one card)
3320 */
3321 sisfb_heap = &ivideo->sisfb_heap;
3322 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003323
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003324 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003325}
3326
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003327static struct SIS_OH *
3328sisfb_poh_new_node(struct SIS_HEAP *memheap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003329{
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003330 struct SIS_OHALLOC *poha;
3331 struct SIS_OH *poh;
3332 unsigned long cOhs;
3333 int i;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003334
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003335 if(memheap->poh_freelist == NULL) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003336 poha = kmalloc(SIS_OH_ALLOC_SIZE, GFP_KERNEL);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003337 if(!poha)
3338 return NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003339
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003340 poha->poha_next = memheap->poha_chain;
3341 memheap->poha_chain = poha;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003342
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003343 cOhs = (SIS_OH_ALLOC_SIZE - sizeof(struct SIS_OHALLOC)) / sizeof(struct SIS_OH) + 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003344
3345 poh = &poha->aoh[0];
3346 for(i = cOhs - 1; i != 0; i--) {
3347 poh->poh_next = poh + 1;
3348 poh = poh + 1;
3349 }
3350
3351 poh->poh_next = NULL;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003352 memheap->poh_freelist = &poha->aoh[0];
Linus Torvalds1da177e2005-04-16 15:20:36 -07003353 }
3354
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003355 poh = memheap->poh_freelist;
3356 memheap->poh_freelist = poh->poh_next;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003357
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003358 return poh;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003359}
3360
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003361static struct SIS_OH *
3362sisfb_poh_allocate(struct SIS_HEAP *memheap, u32 size)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003363{
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003364 struct SIS_OH *pohThis;
3365 struct SIS_OH *pohRoot;
3366 int bAllocated = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003367
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003368 if(size > memheap->max_freesize) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003369 DPRINTK("sisfb: Can't allocate %dk video memory\n",
3370 (unsigned int) size / 1024);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003371 return NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003372 }
3373
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003374 pohThis = memheap->oh_free.poh_next;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003375
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003376 while(pohThis != &memheap->oh_free) {
3377 if(size <= pohThis->size) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003378 bAllocated = 1;
3379 break;
3380 }
3381 pohThis = pohThis->poh_next;
3382 }
3383
3384 if(!bAllocated) {
3385 DPRINTK("sisfb: Can't allocate %dk video memory\n",
3386 (unsigned int) size / 1024);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003387 return NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003388 }
3389
3390 if(size == pohThis->size) {
3391 pohRoot = pohThis;
3392 sisfb_delete_node(pohThis);
3393 } else {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003394 pohRoot = sisfb_poh_new_node(memheap);
3395 if(pohRoot == NULL)
3396 return NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003397
3398 pohRoot->offset = pohThis->offset;
3399 pohRoot->size = size;
3400
3401 pohThis->offset += size;
3402 pohThis->size -= size;
3403 }
3404
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003405 memheap->max_freesize -= size;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003406
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003407 pohThis = &memheap->oh_used;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003408 sisfb_insert_node(pohThis, pohRoot);
3409
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003410 return pohRoot;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003411}
3412
3413static void
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003414sisfb_delete_node(struct SIS_OH *poh)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003415{
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003416 poh->poh_prev->poh_next = poh->poh_next;
3417 poh->poh_next->poh_prev = poh->poh_prev;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003418}
3419
3420static void
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003421sisfb_insert_node(struct SIS_OH *pohList, struct SIS_OH *poh)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003422{
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003423 struct SIS_OH *pohTemp = pohList->poh_next;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003424
3425 pohList->poh_next = poh;
3426 pohTemp->poh_prev = poh;
3427
3428 poh->poh_prev = pohList;
3429 poh->poh_next = pohTemp;
3430}
3431
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003432static struct SIS_OH *
3433sisfb_poh_free(struct SIS_HEAP *memheap, u32 base)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003434{
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003435 struct SIS_OH *pohThis;
3436 struct SIS_OH *poh_freed;
3437 struct SIS_OH *poh_prev;
3438 struct SIS_OH *poh_next;
3439 u32 ulUpper;
3440 u32 ulLower;
3441 int foundNode = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003442
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003443 poh_freed = memheap->oh_used.poh_next;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003444
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003445 while(poh_freed != &memheap->oh_used) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003446 if(poh_freed->offset == base) {
3447 foundNode = 1;
3448 break;
3449 }
3450
3451 poh_freed = poh_freed->poh_next;
3452 }
3453
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003454 if(!foundNode)
3455 return NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003456
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003457 memheap->max_freesize += poh_freed->size;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003458
3459 poh_prev = poh_next = NULL;
3460 ulUpper = poh_freed->offset + poh_freed->size;
3461 ulLower = poh_freed->offset;
3462
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003463 pohThis = memheap->oh_free.poh_next;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003464
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003465 while(pohThis != &memheap->oh_free) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003466 if(pohThis->offset == ulUpper) {
3467 poh_next = pohThis;
3468 } else if((pohThis->offset + pohThis->size) == ulLower) {
3469 poh_prev = pohThis;
3470 }
3471 pohThis = pohThis->poh_next;
3472 }
3473
3474 sisfb_delete_node(poh_freed);
3475
3476 if(poh_prev && poh_next) {
3477 poh_prev->size += (poh_freed->size + poh_next->size);
3478 sisfb_delete_node(poh_next);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003479 sisfb_free_node(memheap, poh_freed);
3480 sisfb_free_node(memheap, poh_next);
3481 return poh_prev;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003482 }
3483
3484 if(poh_prev) {
3485 poh_prev->size += poh_freed->size;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003486 sisfb_free_node(memheap, poh_freed);
3487 return poh_prev;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003488 }
3489
3490 if(poh_next) {
3491 poh_next->size += poh_freed->size;
3492 poh_next->offset = poh_freed->offset;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003493 sisfb_free_node(memheap, poh_freed);
3494 return poh_next;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003495 }
3496
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003497 sisfb_insert_node(&memheap->oh_free, poh_freed);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003498
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003499 return poh_freed;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003500}
3501
3502static void
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003503sisfb_free_node(struct SIS_HEAP *memheap, struct SIS_OH *poh)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003504{
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003505 if(poh == NULL)
3506 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003507
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003508 poh->poh_next = memheap->poh_freelist;
3509 memheap->poh_freelist = poh;
3510}
3511
3512static void
3513sis_int_malloc(struct sis_video_info *ivideo, struct sis_memreq *req)
3514{
3515 struct SIS_OH *poh = NULL;
3516
3517 if((ivideo) && (ivideo->sisfb_id == SISFB_ID) && (!ivideo->havenoheap))
3518 poh = sisfb_poh_allocate(&ivideo->sisfb_heap, (u32)req->size);
3519
3520 if(poh == NULL) {
3521 req->offset = req->size = 0;
3522 DPRINTK("sisfb: Video RAM allocation failed\n");
3523 } else {
3524 req->offset = poh->offset;
3525 req->size = poh->size;
3526 DPRINTK("sisfb: Video RAM allocation succeeded: 0x%lx\n",
3527 (poh->offset + ivideo->video_vbase));
3528 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003529}
3530
3531void
3532sis_malloc(struct sis_memreq *req)
3533{
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003534 struct sis_video_info *ivideo = sisfb_heap->vinfo;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003535
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003536 if(&ivideo->sisfb_heap == sisfb_heap)
3537 sis_int_malloc(ivideo, req);
3538 else
3539 req->offset = req->size = 0;
3540}
Linus Torvalds1da177e2005-04-16 15:20:36 -07003541
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003542void
3543sis_malloc_new(struct pci_dev *pdev, struct sis_memreq *req)
3544{
3545 struct sis_video_info *ivideo = pci_get_drvdata(pdev);
3546
3547 sis_int_malloc(ivideo, req);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003548}
3549
3550/* sis_free: u32 because "base" is offset inside video ram, can never be >4GB */
3551
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003552static void
3553sis_int_free(struct sis_video_info *ivideo, u32 base)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003554{
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003555 struct SIS_OH *poh;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003556
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003557 if((!ivideo) || (ivideo->sisfb_id != SISFB_ID) || (ivideo->havenoheap))
3558 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003559
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003560 poh = sisfb_poh_free(&ivideo->sisfb_heap, base);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003561
3562 if(poh == NULL) {
3563 DPRINTK("sisfb: sisfb_poh_free() failed at base 0x%x\n",
3564 (unsigned int) base);
3565 }
3566}
3567
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003568void
3569sis_free(u32 base)
3570{
3571 struct sis_video_info *ivideo = sisfb_heap->vinfo;
3572
3573 sis_int_free(ivideo, base);
3574}
3575
3576void
3577sis_free_new(struct pci_dev *pdev, u32 base)
3578{
3579 struct sis_video_info *ivideo = pci_get_drvdata(pdev);
3580
3581 sis_int_free(ivideo, base);
3582}
3583
Linus Torvalds1da177e2005-04-16 15:20:36 -07003584/* --------------------- SetMode routines ------------------------- */
3585
3586static void
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003587sisfb_check_engine_and_sync(struct sis_video_info *ivideo)
3588{
3589 u8 cr30, cr31;
3590
3591 /* Check if MMIO and engines are enabled,
3592 * and sync in case they are. Can't use
3593 * ivideo->accel here, as this might have
3594 * been changed before this is called.
3595 */
3596 inSISIDXREG(SISSR, IND_SIS_PCI_ADDRESS_SET, cr30);
3597 inSISIDXREG(SISSR, IND_SIS_MODULE_ENABLE, cr31);
3598 /* MMIO and 2D/3D engine enabled? */
3599 if((cr30 & SIS_MEM_MAP_IO_ENABLE) && (cr31 & 0x42)) {
3600#ifdef CONFIG_FB_SIS_300
3601 if(ivideo->sisvga_engine == SIS_300_VGA) {
3602 /* Don't care about TurboQueue. It's
3603 * enough to know that the engines
3604 * are enabled
3605 */
3606 sisfb_syncaccel(ivideo);
3607 }
3608#endif
3609#ifdef CONFIG_FB_SIS_315
3610 if(ivideo->sisvga_engine == SIS_315_VGA) {
3611 /* Check that any queue mode is
3612 * enabled, and that the queue
3613 * is not in the state of "reset"
3614 */
3615 inSISIDXREG(SISSR, 0x26, cr30);
3616 if((cr30 & 0xe0) && (!(cr30 & 0x01))) {
3617 sisfb_syncaccel(ivideo);
3618 }
3619 }
3620#endif
3621 }
3622}
3623
3624static void
Linus Torvalds1da177e2005-04-16 15:20:36 -07003625sisfb_pre_setmode(struct sis_video_info *ivideo)
3626{
3627 u8 cr30 = 0, cr31 = 0, cr33 = 0, cr35 = 0, cr38 = 0;
3628 int tvregnum = 0;
3629
3630 ivideo->currentvbflags &= (VB_VIDEOBRIDGE | VB_DISPTYPE_DISP2);
3631
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003632 outSISIDXREG(SISSR, 0x05, 0x86);
3633
Linus Torvalds1da177e2005-04-16 15:20:36 -07003634 inSISIDXREG(SISCR, 0x31, cr31);
3635 cr31 &= ~0x60;
3636 cr31 |= 0x04;
3637
3638 cr33 = ivideo->rate_idx & 0x0F;
3639
3640#ifdef CONFIG_FB_SIS_315
3641 if(ivideo->sisvga_engine == SIS_315_VGA) {
3642 if(ivideo->chip >= SIS_661) {
3643 inSISIDXREG(SISCR, 0x38, cr38);
3644 cr38 &= ~0x07; /* Clear LCDA/DualEdge and YPbPr bits */
3645 } else {
3646 tvregnum = 0x38;
3647 inSISIDXREG(SISCR, tvregnum, cr38);
3648 cr38 &= ~0x3b; /* Clear LCDA/DualEdge and YPbPr bits */
3649 }
3650 }
3651#endif
3652#ifdef CONFIG_FB_SIS_300
3653 if(ivideo->sisvga_engine == SIS_300_VGA) {
3654 tvregnum = 0x35;
3655 inSISIDXREG(SISCR, tvregnum, cr38);
3656 }
3657#endif
3658
3659 SiS_SetEnableDstn(&ivideo->SiS_Pr, FALSE);
3660 SiS_SetEnableFstn(&ivideo->SiS_Pr, FALSE);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003661 ivideo->curFSTN = ivideo->curDSTN = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003662
3663 switch(ivideo->currentvbflags & VB_DISPTYPE_DISP2) {
3664
3665 case CRT2_TV:
3666 cr38 &= ~0xc0; /* Clear PAL-M / PAL-N bits */
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003667 if((ivideo->vbflags & TV_YPBPR) && (ivideo->vbflags2 & VB2_SISYPBPRBRIDGE)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003668#ifdef CONFIG_FB_SIS_315
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003669 if(ivideo->chip >= SIS_661) {
3670 cr38 |= 0x04;
3671 if(ivideo->vbflags & TV_YPBPR525P) cr35 |= 0x20;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003672 else if(ivideo->vbflags & TV_YPBPR750P) cr35 |= 0x40;
3673 else if(ivideo->vbflags & TV_YPBPR1080I) cr35 |= 0x60;
3674 cr30 |= SIS_SIMULTANEOUS_VIEW_ENABLE;
3675 cr35 &= ~0x01;
3676 ivideo->currentvbflags |= (TV_YPBPR | (ivideo->vbflags & TV_YPBPRALL));
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003677 } else if(ivideo->sisvga_engine == SIS_315_VGA) {
3678 cr30 |= (0x80 | SIS_SIMULTANEOUS_VIEW_ENABLE);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003679 cr38 |= 0x08;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003680 if(ivideo->vbflags & TV_YPBPR525P) cr38 |= 0x10;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003681 else if(ivideo->vbflags & TV_YPBPR750P) cr38 |= 0x20;
3682 else if(ivideo->vbflags & TV_YPBPR1080I) cr38 |= 0x30;
3683 cr31 &= ~0x01;
3684 ivideo->currentvbflags |= (TV_YPBPR | (ivideo->vbflags & TV_YPBPRALL));
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003685 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003686#endif
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003687 } else if((ivideo->vbflags & TV_HIVISION) &&
3688 (ivideo->vbflags2 & VB2_SISHIVISIONBRIDGE)) {
3689 if(ivideo->chip >= SIS_661) {
3690 cr38 |= 0x04;
3691 cr35 |= 0x60;
3692 } else {
3693 cr30 |= 0x80;
3694 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003695 cr30 |= SIS_SIMULTANEOUS_VIEW_ENABLE;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003696 cr31 |= 0x01;
3697 cr35 |= 0x01;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003698 ivideo->currentvbflags |= TV_HIVISION;
3699 } else if(ivideo->vbflags & TV_SCART) {
3700 cr30 = (SIS_VB_OUTPUT_SCART | SIS_SIMULTANEOUS_VIEW_ENABLE);
3701 cr31 |= 0x01;
3702 cr35 |= 0x01;
3703 ivideo->currentvbflags |= TV_SCART;
3704 } else {
3705 if(ivideo->vbflags & TV_SVIDEO) {
3706 cr30 = (SIS_VB_OUTPUT_SVIDEO | SIS_SIMULTANEOUS_VIEW_ENABLE);
3707 ivideo->currentvbflags |= TV_SVIDEO;
3708 }
3709 if(ivideo->vbflags & TV_AVIDEO) {
3710 cr30 = (SIS_VB_OUTPUT_COMPOSITE | SIS_SIMULTANEOUS_VIEW_ENABLE);
3711 ivideo->currentvbflags |= TV_AVIDEO;
3712 }
3713 }
3714 cr31 |= SIS_DRIVER_MODE;
3715
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003716 if(ivideo->vbflags & (TV_AVIDEO | TV_SVIDEO)) {
3717 if(ivideo->vbflags & TV_PAL) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003718 cr31 |= 0x01; cr35 |= 0x01;
3719 ivideo->currentvbflags |= TV_PAL;
3720 if(ivideo->vbflags & TV_PALM) {
3721 cr38 |= 0x40; cr35 |= 0x04;
3722 ivideo->currentvbflags |= TV_PALM;
3723 } else if(ivideo->vbflags & TV_PALN) {
3724 cr38 |= 0x80; cr35 |= 0x08;
3725 ivideo->currentvbflags |= TV_PALN;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003726 }
3727 } else {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003728 cr31 &= ~0x01; cr35 &= ~0x01;
3729 ivideo->currentvbflags |= TV_NTSC;
3730 if(ivideo->vbflags & TV_NTSCJ) {
3731 cr38 |= 0x40; cr35 |= 0x02;
3732 ivideo->currentvbflags |= TV_NTSCJ;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003733 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003734 }
3735 }
3736 break;
3737
3738 case CRT2_LCD:
3739 cr30 = (SIS_VB_OUTPUT_LCD | SIS_SIMULTANEOUS_VIEW_ENABLE);
3740 cr31 |= SIS_DRIVER_MODE;
3741 SiS_SetEnableDstn(&ivideo->SiS_Pr, ivideo->sisfb_dstn);
3742 SiS_SetEnableFstn(&ivideo->SiS_Pr, ivideo->sisfb_fstn);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003743 ivideo->curFSTN = ivideo->sisfb_fstn;
3744 ivideo->curDSTN = ivideo->sisfb_dstn;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003745 break;
3746
3747 case CRT2_VGA:
3748 cr30 = (SIS_VB_OUTPUT_CRT2 | SIS_SIMULTANEOUS_VIEW_ENABLE);
3749 cr31 |= SIS_DRIVER_MODE;
3750 if(ivideo->sisfb_nocrt2rate) {
3751 cr33 |= (sisbios_mode[ivideo->sisfb_mode_idx].rate_idx << 4);
3752 } else {
3753 cr33 |= ((ivideo->rate_idx & 0x0F) << 4);
3754 }
3755 break;
3756
3757 default: /* disable CRT2 */
3758 cr30 = 0x00;
3759 cr31 |= (SIS_DRIVER_MODE | SIS_VB_OUTPUT_DISABLE);
3760 }
3761
3762 outSISIDXREG(SISCR, 0x30, cr30);
3763 outSISIDXREG(SISCR, 0x33, cr33);
3764
3765 if(ivideo->chip >= SIS_661) {
3766#ifdef CONFIG_FB_SIS_315
3767 cr31 &= ~0x01; /* Clear PAL flag (now in CR35) */
3768 setSISIDXREG(SISCR, 0x35, ~0x10, cr35); /* Leave overscan bit alone */
3769 cr38 &= 0x07; /* Use only LCDA and HiVision/YPbPr bits */
3770 setSISIDXREG(SISCR, 0x38, 0xf8, cr38);
3771#endif
3772 } else if(ivideo->chip != SIS_300) {
3773 outSISIDXREG(SISCR, tvregnum, cr38);
3774 }
3775 outSISIDXREG(SISCR, 0x31, cr31);
3776
Linus Torvalds1da177e2005-04-16 15:20:36 -07003777 ivideo->SiS_Pr.SiS_UseOEM = ivideo->sisfb_useoem;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003778
3779 sisfb_check_engine_and_sync(ivideo);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003780}
3781
3782/* Fix SR11 for 661 and later */
3783#ifdef CONFIG_FB_SIS_315
3784static void
3785sisfb_fixup_SR11(struct sis_video_info *ivideo)
3786{
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003787 u8 tmpreg;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003788
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003789 if(ivideo->chip >= SIS_661) {
3790 inSISIDXREG(SISSR,0x11,tmpreg);
3791 if(tmpreg & 0x20) {
3792 inSISIDXREG(SISSR,0x3e,tmpreg);
3793 tmpreg = (tmpreg + 1) & 0xff;
3794 outSISIDXREG(SISSR,0x3e,tmpreg);
3795 inSISIDXREG(SISSR,0x11,tmpreg);
3796 }
3797 if(tmpreg & 0xf0) {
3798 andSISIDXREG(SISSR,0x11,0x0f);
3799 }
3800 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003801}
3802#endif
3803
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003804static void
3805sisfb_set_TVxposoffset(struct sis_video_info *ivideo, int val)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003806{
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003807 if(val > 32) val = 32;
3808 if(val < -32) val = -32;
3809 ivideo->tvxpos = val;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003810
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003811 if(ivideo->sisfblocked) return;
3812 if(!ivideo->modechanged) return;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003813
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003814 if(ivideo->currentvbflags & CRT2_TV) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003815
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003816 if(ivideo->vbflags2 & VB2_CHRONTEL) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003817
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003818 int x = ivideo->tvx;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003819
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003820 switch(ivideo->chronteltype) {
3821 case 1:
3822 x += val;
3823 if(x < 0) x = 0;
3824 outSISIDXREG(SISSR,0x05,0x86);
3825 SiS_SetCH700x(&ivideo->SiS_Pr, 0x0a, (x & 0xff));
3826 SiS_SetCH70xxANDOR(&ivideo->SiS_Pr, 0x08, ((x & 0x0100) >> 7), 0xFD);
3827 break;
3828 case 2:
3829 /* Not supported by hardware */
3830 break;
3831 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003832
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003833 } else if(ivideo->vbflags2 & VB2_SISBRIDGE) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003834
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003835 u8 p2_1f,p2_20,p2_2b,p2_42,p2_43;
3836 unsigned short temp;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003837
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003838 p2_1f = ivideo->p2_1f;
3839 p2_20 = ivideo->p2_20;
3840 p2_2b = ivideo->p2_2b;
3841 p2_42 = ivideo->p2_42;
3842 p2_43 = ivideo->p2_43;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003843
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003844 temp = p2_1f | ((p2_20 & 0xf0) << 4);
3845 temp += (val * 2);
3846 p2_1f = temp & 0xff;
3847 p2_20 = (temp & 0xf00) >> 4;
3848 p2_2b = ((p2_2b & 0x0f) + (val * 2)) & 0x0f;
3849 temp = p2_43 | ((p2_42 & 0xf0) << 4);
3850 temp += (val * 2);
3851 p2_43 = temp & 0xff;
3852 p2_42 = (temp & 0xf00) >> 4;
3853 outSISIDXREG(SISPART2,0x1f,p2_1f);
3854 setSISIDXREG(SISPART2,0x20,0x0F,p2_20);
3855 setSISIDXREG(SISPART2,0x2b,0xF0,p2_2b);
3856 setSISIDXREG(SISPART2,0x42,0x0F,p2_42);
3857 outSISIDXREG(SISPART2,0x43,p2_43);
3858 }
3859 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003860}
3861
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003862static void
3863sisfb_set_TVyposoffset(struct sis_video_info *ivideo, int val)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003864{
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003865 if(val > 32) val = 32;
3866 if(val < -32) val = -32;
3867 ivideo->tvypos = val;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003868
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003869 if(ivideo->sisfblocked) return;
3870 if(!ivideo->modechanged) return;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003871
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003872 if(ivideo->currentvbflags & CRT2_TV) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003873
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003874 if(ivideo->vbflags2 & VB2_CHRONTEL) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003875
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003876 int y = ivideo->tvy;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003877
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003878 switch(ivideo->chronteltype) {
3879 case 1:
3880 y -= val;
3881 if(y < 0) y = 0;
3882 outSISIDXREG(SISSR,0x05,0x86);
3883 SiS_SetCH700x(&ivideo->SiS_Pr, 0x0b, (y & 0xff));
3884 SiS_SetCH70xxANDOR(&ivideo->SiS_Pr, 0x08, ((y & 0x0100) >> 8), 0xFE);
3885 break;
3886 case 2:
3887 /* Not supported by hardware */
3888 break;
3889 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003890
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003891 } else if(ivideo->vbflags2 & VB2_SISBRIDGE) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003892
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003893 char p2_01, p2_02;
3894 val /= 2;
3895 p2_01 = ivideo->p2_01;
3896 p2_02 = ivideo->p2_02;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003897
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003898 p2_01 += val;
3899 p2_02 += val;
3900 if(!(ivideo->currentvbflags & (TV_HIVISION | TV_YPBPR))) {
3901 while((p2_01 <= 0) || (p2_02 <= 0)) {
3902 p2_01 += 2;
3903 p2_02 += 2;
3904 }
3905 }
3906 outSISIDXREG(SISPART2,0x01,p2_01);
3907 outSISIDXREG(SISPART2,0x02,p2_02);
3908 }
3909 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003910}
3911
3912static void
3913sisfb_post_setmode(struct sis_video_info *ivideo)
3914{
3915 BOOLEAN crt1isoff = FALSE;
3916 BOOLEAN doit = TRUE;
3917#if defined(CONFIG_FB_SIS_300) || defined(CONFIG_FB_SIS_315)
3918 u8 reg;
3919#endif
3920#ifdef CONFIG_FB_SIS_315
3921 u8 reg1;
3922#endif
3923
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003924 outSISIDXREG(SISSR, 0x05, 0x86);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003925
3926#ifdef CONFIG_FB_SIS_315
3927 sisfb_fixup_SR11(ivideo);
3928#endif
3929
3930 /* Now we actually HAVE changed the display mode */
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003931 ivideo->modechanged = 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003932
3933 /* We can't switch off CRT1 if bridge is in slave mode */
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003934 if(ivideo->vbflags2 & VB2_VIDEOBRIDGE) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003935 if(sisfb_bridgeisslave(ivideo)) doit = FALSE;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003936 } else
3937 ivideo->sisfb_crt1off = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003938
3939#ifdef CONFIG_FB_SIS_300
3940 if(ivideo->sisvga_engine == SIS_300_VGA) {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003941 if((ivideo->sisfb_crt1off) && (doit)) {
3942 crt1isoff = TRUE;
3943 reg = 0x00;
3944 } else {
3945 crt1isoff = FALSE;
3946 reg = 0x80;
3947 }
3948 setSISIDXREG(SISCR, 0x17, 0x7f, reg);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003949 }
3950#endif
3951#ifdef CONFIG_FB_SIS_315
3952 if(ivideo->sisvga_engine == SIS_315_VGA) {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003953 if((ivideo->sisfb_crt1off) && (doit)) {
3954 crt1isoff = TRUE;
3955 reg = 0x40;
3956 reg1 = 0xc0;
3957 } else {
3958 crt1isoff = FALSE;
3959 reg = 0x00;
3960 reg1 = 0x00;
3961 }
3962 setSISIDXREG(SISCR, ivideo->SiS_Pr.SiS_MyCR63, ~0x40, reg);
3963 setSISIDXREG(SISSR, 0x1f, ~0xc0, reg1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003964 }
3965#endif
3966
3967 if(crt1isoff) {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003968 ivideo->currentvbflags &= ~VB_DISPTYPE_CRT1;
3969 ivideo->currentvbflags |= VB_SINGLE_MODE;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003970 } else {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003971 ivideo->currentvbflags |= VB_DISPTYPE_CRT1;
3972 if(ivideo->currentvbflags & VB_DISPTYPE_CRT2) {
3973 ivideo->currentvbflags |= VB_MIRROR_MODE;
3974 } else {
3975 ivideo->currentvbflags |= VB_SINGLE_MODE;
3976 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003977 }
3978
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003979 andSISIDXREG(SISSR, IND_SIS_RAMDAC_CONTROL, ~0x04);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003980
3981 if(ivideo->currentvbflags & CRT2_TV) {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003982 if(ivideo->vbflags2 & VB2_SISBRIDGE) {
3983 inSISIDXREG(SISPART2,0x1f,ivideo->p2_1f);
3984 inSISIDXREG(SISPART2,0x20,ivideo->p2_20);
3985 inSISIDXREG(SISPART2,0x2b,ivideo->p2_2b);
3986 inSISIDXREG(SISPART2,0x42,ivideo->p2_42);
3987 inSISIDXREG(SISPART2,0x43,ivideo->p2_43);
3988 inSISIDXREG(SISPART2,0x01,ivideo->p2_01);
3989 inSISIDXREG(SISPART2,0x02,ivideo->p2_02);
3990 } else if(ivideo->vbflags2 & VB2_CHRONTEL) {
3991 if(ivideo->chronteltype == 1) {
3992 ivideo->tvx = SiS_GetCH700x(&ivideo->SiS_Pr, 0x0a);
3993 ivideo->tvx |= (((SiS_GetCH700x(&ivideo->SiS_Pr, 0x08) & 0x02) >> 1) << 8);
3994 ivideo->tvy = SiS_GetCH700x(&ivideo->SiS_Pr, 0x0b);
3995 ivideo->tvy |= ((SiS_GetCH700x(&ivideo->SiS_Pr, 0x08) & 0x01) << 8);
3996 }
3997 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003998 }
3999
4000 if(ivideo->tvxpos) {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004001 sisfb_set_TVxposoffset(ivideo, ivideo->tvxpos);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004002 }
4003 if(ivideo->tvypos) {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004004 sisfb_set_TVyposoffset(ivideo, ivideo->tvypos);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004005 }
4006
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004007 /* Eventually sync engines */
4008 sisfb_check_engine_and_sync(ivideo);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004009
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004010 /* (Re-)Initialize chip engines */
4011 if(ivideo->accel) {
4012 sisfb_engine_init(ivideo);
4013 } else {
4014 ivideo->engineok = 0;
4015 }
4016}
Linus Torvalds1da177e2005-04-16 15:20:36 -07004017
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004018static int
4019sisfb_reset_mode(struct sis_video_info *ivideo)
4020{
4021 if(sisfb_set_mode(ivideo, 0))
4022 return 1;
4023
4024 sisfb_set_pitch(ivideo);
4025 sisfb_set_base_CRT1(ivideo, ivideo->current_base);
4026 sisfb_set_base_CRT2(ivideo, ivideo->current_base);
4027
4028 return 0;
4029}
4030
4031static void
4032sisfb_handle_command(struct sis_video_info *ivideo, struct sisfb_cmd *sisfb_command)
4033{
4034 int mycrt1off;
4035
4036 switch(sisfb_command->sisfb_cmd) {
4037 case SISFB_CMD_GETVBFLAGS:
4038 if(!ivideo->modechanged) {
4039 sisfb_command->sisfb_result[0] = SISFB_CMD_ERR_EARLY;
4040 } else {
4041 sisfb_command->sisfb_result[0] = SISFB_CMD_ERR_OK;
4042 sisfb_command->sisfb_result[1] = ivideo->currentvbflags;
4043 sisfb_command->sisfb_result[2] = ivideo->vbflags2;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004044 }
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004045 break;
4046 case SISFB_CMD_SWITCHCRT1:
4047 /* arg[0]: 0 = off, 1 = on, 99 = query */
4048 if(!ivideo->modechanged) {
4049 sisfb_command->sisfb_result[0] = SISFB_CMD_ERR_EARLY;
4050 } else if(sisfb_command->sisfb_arg[0] == 99) {
4051 /* Query */
4052 sisfb_command->sisfb_result[1] = ivideo->sisfb_crt1off ? 0 : 1;
4053 sisfb_command->sisfb_result[0] = SISFB_CMD_ERR_OK;
4054 } else if(ivideo->sisfblocked) {
4055 sisfb_command->sisfb_result[0] = SISFB_CMD_ERR_LOCKED;
4056 } else if((!(ivideo->currentvbflags & CRT2_ENABLE)) &&
4057 (sisfb_command->sisfb_arg[0] == 0)) {
4058 sisfb_command->sisfb_result[0] = SISFB_CMD_ERR_NOCRT2;
4059 } else {
4060 sisfb_command->sisfb_result[0] = SISFB_CMD_ERR_OK;
4061 mycrt1off = sisfb_command->sisfb_arg[0] ? 0 : 1;
4062 if( ((ivideo->currentvbflags & VB_DISPTYPE_CRT1) && mycrt1off) ||
4063 ((!(ivideo->currentvbflags & VB_DISPTYPE_CRT1)) && !mycrt1off) ) {
4064 ivideo->sisfb_crt1off = mycrt1off;
4065 if(sisfb_reset_mode(ivideo)) {
4066 sisfb_command->sisfb_result[0] = SISFB_CMD_ERR_OTHER;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004067 }
4068 }
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004069 sisfb_command->sisfb_result[1] = ivideo->sisfb_crt1off ? 0 : 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004070 }
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004071 break;
4072 /* more to come */
4073 default:
4074 sisfb_command->sisfb_result[0] = SISFB_CMD_ERR_UNKNOWN;
4075 printk(KERN_ERR "sisfb: Unknown command 0x%x\n",
4076 sisfb_command->sisfb_cmd);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004077 }
4078}
4079
4080#ifndef MODULE
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004081SISINITSTATIC int __init
4082sisfb_setup(char *options)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004083{
4084 char *this_opt;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004085
Linus Torvalds1da177e2005-04-16 15:20:36 -07004086 sisfb_setdefaultparms();
4087
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004088 if(!options || !(*options))
Linus Torvalds1da177e2005-04-16 15:20:36 -07004089 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004090
4091 while((this_opt = strsep(&options, ",")) != NULL) {
4092
4093 if(!(*this_opt)) continue;
4094
4095 if(!strnicmp(this_opt, "off", 3)) {
4096 sisfb_off = 1;
4097 } else if(!strnicmp(this_opt, "forcecrt2type:", 14)) {
4098 /* Need to check crt2 type first for fstn/dstn */
4099 sisfb_search_crt2type(this_opt + 14);
4100 } else if(!strnicmp(this_opt, "tvmode:",7)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004101 sisfb_search_tvstd(this_opt + 7);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004102 } else if(!strnicmp(this_opt, "tvstandard:",11)) {
4103 sisfb_search_tvstd(this_opt + 11);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004104 } else if(!strnicmp(this_opt, "mode:", 5)) {
4105 sisfb_search_mode(this_opt + 5, FALSE);
4106 } else if(!strnicmp(this_opt, "vesa:", 5)) {
4107 sisfb_search_vesamode(simple_strtoul(this_opt + 5, NULL, 0), FALSE);
4108#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
4109 } else if(!strnicmp(this_opt, "inverse", 7)) {
4110 sisfb_inverse = 1;
4111 /* fb_invert_cmaps(); */
4112 } else if(!strnicmp(this_opt, "font:", 5)) {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004113 if(strlen(this_opt + 5) < 40) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004114 strncpy(sisfb_fontname, this_opt + 5, sizeof(sisfb_fontname) - 1);
4115 sisfb_fontname[sizeof(sisfb_fontname) - 1] = '\0';
4116 }
4117#endif
4118 } else if(!strnicmp(this_opt, "rate:", 5)) {
4119 sisfb_parm_rate = simple_strtoul(this_opt + 5, NULL, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004120 } else if(!strnicmp(this_opt, "forcecrt1:", 10)) {
4121 sisfb_forcecrt1 = (int)simple_strtoul(this_opt + 10, NULL, 0);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004122 } else if(!strnicmp(this_opt, "mem:",4)) {
4123 sisfb_parm_mem = simple_strtoul(this_opt + 4, NULL, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004124 } else if(!strnicmp(this_opt, "pdc:", 4)) {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004125 sisfb_pdc = simple_strtoul(this_opt + 4, NULL, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004126 } else if(!strnicmp(this_opt, "pdc1:", 5)) {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004127 sisfb_pdca = simple_strtoul(this_opt + 5, NULL, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004128 } else if(!strnicmp(this_opt, "noaccel", 7)) {
4129 sisfb_accel = 0;
4130 } else if(!strnicmp(this_opt, "accel", 5)) {
4131 sisfb_accel = -1;
4132 } else if(!strnicmp(this_opt, "noypan", 6)) {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004133 sisfb_ypan = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004134 } else if(!strnicmp(this_opt, "ypan", 4)) {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004135 sisfb_ypan = -1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004136 } else if(!strnicmp(this_opt, "nomax", 5)) {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004137 sisfb_max = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004138 } else if(!strnicmp(this_opt, "max", 3)) {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004139 sisfb_max = -1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004140 } else if(!strnicmp(this_opt, "userom:", 7)) {
4141 sisfb_userom = (int)simple_strtoul(this_opt + 7, NULL, 0);
4142 } else if(!strnicmp(this_opt, "useoem:", 7)) {
4143 sisfb_useoem = (int)simple_strtoul(this_opt + 7, NULL, 0);
4144 } else if(!strnicmp(this_opt, "nocrt2rate", 10)) {
4145 sisfb_nocrt2rate = 1;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004146 } else if(!strnicmp(this_opt, "scalelcd:", 9)) {
4147 unsigned long temp = 2;
4148 temp = simple_strtoul(this_opt + 9, NULL, 0);
4149 if((temp == 0) || (temp == 1)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004150 sisfb_scalelcd = temp ^ 1;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004151 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004152 } else if(!strnicmp(this_opt, "tvxposoffset:", 13)) {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004153 int temp = 0;
4154 temp = (int)simple_strtol(this_opt + 13, NULL, 0);
4155 if((temp >= -32) && (temp <= 32)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004156 sisfb_tvxposoffset = temp;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004157 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004158 } else if(!strnicmp(this_opt, "tvyposoffset:", 13)) {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004159 int temp = 0;
4160 temp = (int)simple_strtol(this_opt + 13, NULL, 0);
4161 if((temp >= -32) && (temp <= 32)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004162 sisfb_tvyposoffset = temp;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004163 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004164 } else if(!strnicmp(this_opt, "specialtiming:", 14)) {
4165 sisfb_search_specialtiming(this_opt + 14);
4166 } else if(!strnicmp(this_opt, "lvdshl:", 7)) {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004167 int temp = 4;
4168 temp = simple_strtoul(this_opt + 7, NULL, 0);
4169 if((temp >= 0) && (temp <= 3)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004170 sisfb_lvdshl = temp;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004171 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004172 } else if(this_opt[0] >= '0' && this_opt[0] <= '9') {
4173 sisfb_search_mode(this_opt, TRUE);
4174#if !defined(__i386__) && !defined(__x86_64__)
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004175 } else if(!strnicmp(this_opt, "resetcard", 9)) {
4176 sisfb_resetcard = 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004177 } else if(!strnicmp(this_opt, "videoram:", 9)) {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004178 sisfb_videoram = simple_strtoul(this_opt + 9, NULL, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004179#endif
4180 } else {
4181 printk(KERN_INFO "sisfb: Invalid option %s\n", this_opt);
4182 }
4183
4184 }
4185
Linus Torvalds1da177e2005-04-16 15:20:36 -07004186 return 0;
4187}
4188#endif
4189
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004190static int __devinit
4191sisfb_check_rom(SIS_IOTYPE1 *rom_base, struct sis_video_info *ivideo)
4192{
4193 SIS_IOTYPE1 *rom;
4194 int romptr;
4195
4196 if((readb(rom_base) != 0x55) || (readb(rom_base + 1) != 0xaa))
4197 return 0;
4198
4199 romptr = (readb(rom_base + 0x18) | (readb(rom_base + 0x19) << 8));
4200 if(romptr > (0x10000 - 8))
4201 return 0;
4202
4203 rom = rom_base + romptr;
4204
4205 if((readb(rom) != 'P') || (readb(rom + 1) != 'C') ||
4206 (readb(rom + 2) != 'I') || (readb(rom + 3) != 'R'))
4207 return 0;
4208
4209 if((readb(rom + 4) | (readb(rom + 5) << 8)) != ivideo->chip_vendor)
4210 return 0;
4211
4212 if((readb(rom + 6) | (readb(rom + 7) << 8)) != ivideo->chip_id)
4213 return 0;
4214
4215 return 1;
4216}
4217
4218static unsigned char * __devinit
4219sisfb_find_rom(struct pci_dev *pdev)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004220{
4221 struct sis_video_info *ivideo = pci_get_drvdata(pdev);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004222 SIS_IOTYPE1 *rom_base;
4223 unsigned char *myrombase = NULL;
4224 u32 temp;
4225#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,11)
4226 size_t romsize;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004227
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004228 /* First, try the official pci ROM functions (except
4229 * on integrated chipsets which have no ROM).
4230 */
4231
4232 if(!ivideo->nbridge) {
4233
4234 if((rom_base = pci_map_rom(pdev, &romsize))) {
4235
4236 if(sisfb_check_rom(rom_base, ivideo)) {
4237
4238 if((myrombase = vmalloc(65536))) {
4239
4240 /* Work around bug in pci/rom.c: Folks forgot to check
4241 * whether the size retrieved from the BIOS image eventually
4242 * is larger than the mapped size
4243 */
4244 if(pci_resource_len(pdev, PCI_ROM_RESOURCE) < romsize)
4245 romsize = pci_resource_len(pdev, PCI_ROM_RESOURCE);
4246
4247 memcpy_fromio(myrombase, rom_base,
4248 (romsize > 65536) ? 65536 : romsize);
4249 }
4250 }
4251 pci_unmap_rom(pdev, rom_base);
4252 }
4253 }
4254
4255 if(myrombase) return myrombase;
4256#endif
4257
4258 /* Otherwise do it the conventional way. */
Linus Torvalds1da177e2005-04-16 15:20:36 -07004259
4260#if defined(__i386__) || defined(__x86_64__)
4261
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004262 for(temp = 0x000c0000; temp < 0x000f0000; temp += 0x00001000) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004263
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004264 rom_base = ioremap(temp, 65536);
4265 if(!rom_base)
4266 continue;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004267
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004268 if(!sisfb_check_rom(rom_base, ivideo)) {
4269 iounmap(rom_base);
4270 continue;
4271 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004272
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004273 if((myrombase = vmalloc(65536)))
4274 memcpy_fromio(myrombase, rom_base, 65536);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004275
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004276 iounmap(rom_base);
4277 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004278
Linus Torvalds1da177e2005-04-16 15:20:36 -07004279 }
4280
4281#else
4282
4283 pci_read_config_dword(pdev, PCI_ROM_ADDRESS, &temp);
4284 pci_write_config_dword(pdev, PCI_ROM_ADDRESS,
4285 (ivideo->video_base & PCI_ROM_ADDRESS_MASK) | PCI_ROM_ADDRESS_ENABLE);
4286
4287 rom_base = ioremap(ivideo->video_base, 65536);
4288 if(rom_base) {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004289 if(sisfb_check_rom(rom_base, ivideo)) {
4290 if((myrombase = vmalloc(65536)))
4291 memcpy_fromio(myrombase, rom_base, 65536);
4292 }
4293 iounmap(rom_base);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004294 }
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004295
4296 pci_write_config_dword(pdev, PCI_ROM_ADDRESS, temp);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004297
4298#endif
4299
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004300 return myrombase;
4301}
4302
4303static void __devinit
4304sisfb_post_map_vram(struct sis_video_info *ivideo, unsigned int *mapsize,
4305 unsigned int min)
4306{
4307 ivideo->video_vbase = ioremap(ivideo->video_base, (*mapsize));
4308
4309 if(!ivideo->video_vbase) {
4310 printk(KERN_ERR
4311 "sisfb: Unable to map maximum video RAM for size detection\n");
4312 (*mapsize) >>= 1;
4313 while((!(ivideo->video_vbase = ioremap(ivideo->video_base, (*mapsize))))) {
4314 (*mapsize) >>= 1;
4315 if((*mapsize) < (min << 20))
4316 break;
4317 }
4318 if(ivideo->video_vbase) {
4319 printk(KERN_ERR
4320 "sisfb: Video RAM size detection limited to %dMB\n",
4321 (int)((*mapsize) >> 20));
4322 }
4323 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004324}
4325
4326#ifdef CONFIG_FB_SIS_300
4327static int __devinit
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004328sisfb_post_300_buswidth(struct sis_video_info *ivideo)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004329{
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004330 SIS_IOTYPE1 *FBAddress = ivideo->video_vbase;
4331 unsigned short temp;
4332 unsigned char reg;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004333 int i, j;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004334
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004335 andSISIDXREG(SISSR, 0x15, 0xFB);
4336 orSISIDXREG(SISSR, 0x15, 0x04);
4337 outSISIDXREG(SISSR, 0x13, 0x00);
4338 outSISIDXREG(SISSR, 0x14, 0xBF);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004339
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004340 for(i = 0; i < 2; i++) {
4341 temp = 0x1234;
4342 for(j = 0; j < 4; j++) {
4343 writew(temp, FBAddress);
4344 if(readw(FBAddress) == temp)
4345 break;
4346 orSISIDXREG(SISSR, 0x3c, 0x01);
4347 inSISIDXREG(SISSR, 0x05, reg);
4348 inSISIDXREG(SISSR, 0x05, reg);
4349 andSISIDXREG(SISSR, 0x3c, 0xfe);
4350 inSISIDXREG(SISSR, 0x05, reg);
4351 inSISIDXREG(SISSR, 0x05, reg);
4352 temp++;
4353 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004354 }
4355
4356 writel(0x01234567L, FBAddress);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004357 writel(0x456789ABL, (FBAddress + 4));
4358 writel(0x89ABCDEFL, (FBAddress + 8));
4359 writel(0xCDEF0123L, (FBAddress + 12));
4360
4361 inSISIDXREG(SISSR, 0x3b, reg);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004362 if(reg & 0x01) {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004363 if(readl((FBAddress + 12)) == 0xCDEF0123L)
4364 return 4; /* Channel A 128bit */
Linus Torvalds1da177e2005-04-16 15:20:36 -07004365 }
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004366
4367 if(readl((FBAddress + 4)) == 0x456789ABL)
4368 return 2; /* Channel B 64bit */
4369
4370 return 1; /* 32bit */
4371}
4372
4373static int __devinit
4374sisfb_post_300_rwtest(struct sis_video_info *ivideo, int iteration, int buswidth,
4375 int PseudoRankCapacity, int PseudoAdrPinCount,
4376 unsigned int mapsize)
4377{
4378 SIS_IOTYPE1 *FBAddr = ivideo->video_vbase;
4379 unsigned short sr14;
4380 unsigned int k, RankCapacity, PageCapacity, BankNumHigh, BankNumMid;
4381 unsigned int PhysicalAdrOtherPage, PhysicalAdrHigh, PhysicalAdrHalfPage;
4382 static const unsigned short SiS_DRAMType[17][5] = {
4383 {0x0C,0x0A,0x02,0x40,0x39},
4384 {0x0D,0x0A,0x01,0x40,0x48},
4385 {0x0C,0x09,0x02,0x20,0x35},
4386 {0x0D,0x09,0x01,0x20,0x44},
4387 {0x0C,0x08,0x02,0x10,0x31},
4388 {0x0D,0x08,0x01,0x10,0x40},
4389 {0x0C,0x0A,0x01,0x20,0x34},
4390 {0x0C,0x09,0x01,0x08,0x32},
4391 {0x0B,0x08,0x02,0x08,0x21},
4392 {0x0C,0x08,0x01,0x08,0x30},
4393 {0x0A,0x08,0x02,0x04,0x11},
4394 {0x0B,0x0A,0x01,0x10,0x28},
4395 {0x09,0x08,0x02,0x02,0x01},
4396 {0x0B,0x09,0x01,0x08,0x24},
4397 {0x0B,0x08,0x01,0x04,0x20},
4398 {0x0A,0x08,0x01,0x02,0x10},
4399 {0x09,0x08,0x01,0x01,0x00}
4400 };
4401
4402 for(k = 0; k <= 16; k++) {
4403
4404 RankCapacity = buswidth * SiS_DRAMType[k][3];
4405
4406 if(RankCapacity != PseudoRankCapacity)
4407 continue;
4408
4409 if((SiS_DRAMType[k][2] + SiS_DRAMType[k][0]) > PseudoAdrPinCount)
4410 continue;
4411
4412 BankNumHigh = RankCapacity * 16 * iteration - 1;
4413 if(iteration == 3) { /* Rank No */
4414 BankNumMid = RankCapacity * 16 - 1;
4415 } else {
4416 BankNumMid = RankCapacity * 16 * iteration / 2 - 1;
4417 }
4418
4419 PageCapacity = (1 << SiS_DRAMType[k][1]) * buswidth * 4;
4420 PhysicalAdrHigh = BankNumHigh;
4421 PhysicalAdrHalfPage = (PageCapacity / 2 + PhysicalAdrHigh) % PageCapacity;
4422 PhysicalAdrOtherPage = PageCapacity * SiS_DRAMType[k][2] + PhysicalAdrHigh;
4423
4424 andSISIDXREG(SISSR, 0x15, 0xFB); /* Test */
4425 orSISIDXREG(SISSR, 0x15, 0x04); /* Test */
4426 sr14 = (SiS_DRAMType[k][3] * buswidth) - 1;
4427 if(buswidth == 4) sr14 |= 0x80;
4428 else if(buswidth == 2) sr14 |= 0x40;
4429 outSISIDXREG(SISSR, 0x13, SiS_DRAMType[k][4]);
4430 outSISIDXREG(SISSR, 0x14, sr14);
4431
4432 BankNumHigh <<= 16;
4433 BankNumMid <<= 16;
4434
4435 if((BankNumHigh + PhysicalAdrHigh >= mapsize) ||
4436 (BankNumMid + PhysicalAdrHigh >= mapsize) ||
4437 (BankNumHigh + PhysicalAdrHalfPage >= mapsize) ||
4438 (BankNumHigh + PhysicalAdrOtherPage >= mapsize))
4439 continue;
4440
4441 /* Write data */
4442 writew(((unsigned short)PhysicalAdrHigh),
4443 (FBAddr + BankNumHigh + PhysicalAdrHigh));
4444 writew(((unsigned short)BankNumMid),
4445 (FBAddr + BankNumMid + PhysicalAdrHigh));
4446 writew(((unsigned short)PhysicalAdrHalfPage),
4447 (FBAddr + BankNumHigh + PhysicalAdrHalfPage));
4448 writew(((unsigned short)PhysicalAdrOtherPage),
4449 (FBAddr + BankNumHigh + PhysicalAdrOtherPage));
4450
4451 /* Read data */
4452 if(readw(FBAddr + BankNumHigh + PhysicalAdrHigh) == PhysicalAdrHigh)
4453 return 1;
4454 }
4455
4456 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004457}
4458
4459static void __devinit
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004460sisfb_post_300_ramsize(struct pci_dev *pdev, unsigned int mapsize)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004461{
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004462 struct sis_video_info *ivideo = pci_get_drvdata(pdev);
4463 int i, j, buswidth;
4464 int PseudoRankCapacity, PseudoAdrPinCount;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004465
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004466 buswidth = sisfb_post_300_buswidth(ivideo);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004467
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004468 for(i = 6; i >= 0; i--) {
4469 PseudoRankCapacity = 1 << i;
4470 for(j = 4; j >= 1; j--) {
4471 PseudoAdrPinCount = 15 - j;
4472 if((PseudoRankCapacity * j) <= 64) {
4473 if(sisfb_post_300_rwtest(ivideo,
4474 j,
4475 buswidth,
4476 PseudoRankCapacity,
4477 PseudoAdrPinCount,
4478 mapsize))
4479 return;
4480 }
4481 }
4482 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004483}
4484
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004485static void __devinit
4486sisfb_post_sis300(struct pci_dev *pdev)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004487{
4488 struct sis_video_info *ivideo = pci_get_drvdata(pdev);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004489 unsigned char *bios = ivideo->SiS_Pr.VirtualRomBase;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004490 u8 reg, v1, v2, v3, v4, v5, v6, v7, v8;
4491 u16 index, rindex, memtype = 0;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004492 unsigned int mapsize;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004493
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004494 if(!ivideo->SiS_Pr.UseROM)
4495 bios = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004496
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004497 outSISIDXREG(SISSR, 0x05, 0x86);
4498
4499 if(bios) {
4500 if(bios[0x52] & 0x80) {
4501 memtype = bios[0x52];
4502 } else {
4503 inSISIDXREG(SISSR, 0x3a, memtype);
4504 }
4505 memtype &= 0x07;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004506 }
4507
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004508 v3 = 0x80; v6 = 0x80;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004509 if(ivideo->revision_id <= 0x13) {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004510 v1 = 0x44; v2 = 0x42;
4511 v4 = 0x44; v5 = 0x42;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004512 } else {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004513 v1 = 0x68; v2 = 0x43; /* Assume 125Mhz MCLK */
4514 v4 = 0x68; v5 = 0x43; /* Assume 125Mhz ECLK */
4515 if(bios) {
4516 index = memtype * 5;
4517 rindex = index + 0x54;
4518 v1 = bios[rindex++];
4519 v2 = bios[rindex++];
4520 v3 = bios[rindex++];
4521 rindex = index + 0x7c;
4522 v4 = bios[rindex++];
4523 v5 = bios[rindex++];
4524 v6 = bios[rindex++];
4525 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004526 }
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004527 outSISIDXREG(SISSR, 0x28, v1);
4528 outSISIDXREG(SISSR, 0x29, v2);
4529 outSISIDXREG(SISSR, 0x2a, v3);
4530 outSISIDXREG(SISSR, 0x2e, v4);
4531 outSISIDXREG(SISSR, 0x2f, v5);
4532 outSISIDXREG(SISSR, 0x30, v6);
4533
Linus Torvalds1da177e2005-04-16 15:20:36 -07004534 v1 = 0x10;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004535 if(bios)
4536 v1 = bios[0xa4];
4537 outSISIDXREG(SISSR, 0x07, v1); /* DAC speed */
4538
4539 outSISIDXREG(SISSR, 0x11, 0x0f); /* DDC, power save */
4540
Linus Torvalds1da177e2005-04-16 15:20:36 -07004541 v1 = 0x01; v2 = 0x43; v3 = 0x1e; v4 = 0x2a;
4542 v5 = 0x06; v6 = 0x00; v7 = 0x00; v8 = 0x00;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004543 if(bios) {
4544 memtype += 0xa5;
4545 v1 = bios[memtype];
4546 v2 = bios[memtype + 8];
4547 v3 = bios[memtype + 16];
4548 v4 = bios[memtype + 24];
4549 v5 = bios[memtype + 32];
4550 v6 = bios[memtype + 40];
4551 v7 = bios[memtype + 48];
4552 v8 = bios[memtype + 56];
Linus Torvalds1da177e2005-04-16 15:20:36 -07004553 }
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004554 if(ivideo->revision_id >= 0x80)
4555 v3 &= 0xfd;
4556 outSISIDXREG(SISSR, 0x15, v1); /* Ram type (assuming 0, BIOS 0xa5 step 8) */
4557 outSISIDXREG(SISSR, 0x16, v2);
4558 outSISIDXREG(SISSR, 0x17, v3);
4559 outSISIDXREG(SISSR, 0x18, v4);
4560 outSISIDXREG(SISSR, 0x19, v5);
4561 outSISIDXREG(SISSR, 0x1a, v6);
4562 outSISIDXREG(SISSR, 0x1b, v7);
4563 outSISIDXREG(SISSR, 0x1c, v8); /* ---- */
4564 andSISIDXREG(SISSR, 0x15 ,0xfb);
4565 orSISIDXREG(SISSR, 0x15, 0x04);
4566 if(bios) {
4567 if(bios[0x53] & 0x02) {
4568 orSISIDXREG(SISSR, 0x19, 0x20);
4569 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004570 }
4571 v1 = 0x04; /* DAC pedestal (BIOS 0xe5) */
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004572 if(ivideo->revision_id >= 0x80)
4573 v1 |= 0x01;
4574 outSISIDXREG(SISSR, 0x1f, v1);
4575 outSISIDXREG(SISSR, 0x20, 0xa4); /* linear & relocated io & disable a0000 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07004576 v1 = 0xf6; v2 = 0x0d; v3 = 0x00;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004577 if(bios) {
4578 v1 = bios[0xe8];
4579 v2 = bios[0xe9];
4580 v3 = bios[0xea];
Linus Torvalds1da177e2005-04-16 15:20:36 -07004581 }
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004582 outSISIDXREG(SISSR, 0x23, v1);
4583 outSISIDXREG(SISSR, 0x24, v2);
4584 outSISIDXREG(SISSR, 0x25, v3);
4585 outSISIDXREG(SISSR, 0x21, 0x84);
4586 outSISIDXREG(SISSR, 0x22, 0x00);
4587 outSISIDXREG(SISCR, 0x37, 0x00);
4588 orSISIDXREG(SISPART1, 0x24, 0x01); /* unlock crt2 */
4589 outSISIDXREG(SISPART1, 0x00, 0x00);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004590 v1 = 0x40; v2 = 0x11;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004591 if(bios) {
4592 v1 = bios[0xec];
4593 v2 = bios[0xeb];
Linus Torvalds1da177e2005-04-16 15:20:36 -07004594 }
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004595 outSISIDXREG(SISPART1, 0x02, v1);
4596
4597 if(ivideo->revision_id >= 0x80)
4598 v2 &= ~0x01;
4599
4600 inSISIDXREG(SISPART4, 0x00, reg);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004601 if((reg == 1) || (reg == 2)) {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004602 outSISIDXREG(SISCR, 0x37, 0x02);
4603 outSISIDXREG(SISPART2, 0x00, 0x1c);
4604 v4 = 0x00; v5 = 0x00; v6 = 0x10;
4605 if(ivideo->SiS_Pr.UseROM) {
4606 v4 = bios[0xf5];
4607 v5 = bios[0xf6];
4608 v6 = bios[0xf7];
4609 }
4610 outSISIDXREG(SISPART4, 0x0d, v4);
4611 outSISIDXREG(SISPART4, 0x0e, v5);
4612 outSISIDXREG(SISPART4, 0x10, v6);
4613 outSISIDXREG(SISPART4, 0x0f, 0x3f);
4614 inSISIDXREG(SISPART4, 0x01, reg);
4615 if(reg >= 0xb0) {
4616 inSISIDXREG(SISPART4, 0x23, reg);
4617 reg &= 0x20;
4618 reg <<= 1;
4619 outSISIDXREG(SISPART4, 0x23, reg);
4620 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004621 } else {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004622 v2 &= ~0x10;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004623 }
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004624 outSISIDXREG(SISSR, 0x32, v2);
4625
4626 andSISIDXREG(SISPART1, 0x24, 0xfe); /* Lock CRT2 */
4627
4628 inSISIDXREG(SISSR, 0x16, reg);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004629 reg &= 0xc3;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004630 outSISIDXREG(SISCR, 0x35, reg);
4631 outSISIDXREG(SISCR, 0x83, 0x00);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004632#if !defined(__i386__) && !defined(__x86_64__)
4633 if(sisfb_videoram) {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004634 outSISIDXREG(SISSR, 0x13, 0x28); /* ? */
4635 reg = ((sisfb_videoram >> 10) - 1) | 0x40;
4636 outSISIDXREG(SISSR, 0x14, reg);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004637 } else {
4638#endif
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004639 /* Need to map max FB size for finding out about RAM size */
4640 mapsize = 64 << 20;
4641 sisfb_post_map_vram(ivideo, &mapsize, 4);
4642
4643 if(ivideo->video_vbase) {
4644 sisfb_post_300_ramsize(pdev, mapsize);
4645 iounmap(ivideo->video_vbase);
4646 } else {
4647 printk(KERN_DEBUG
4648 "sisfb: Failed to map memory for size detection, assuming 8MB\n");
4649 outSISIDXREG(SISSR, 0x13, 0x28); /* ? */
4650 outSISIDXREG(SISSR, 0x14, 0x47); /* 8MB, 64bit default */
4651 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004652#if !defined(__i386__) && !defined(__x86_64__)
4653 }
4654#endif
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004655 if(bios) {
4656 v1 = bios[0xe6];
4657 v2 = bios[0xe7];
Linus Torvalds1da177e2005-04-16 15:20:36 -07004658 } else {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004659 inSISIDXREG(SISSR, 0x3a, reg);
4660 if((reg & 0x30) == 0x30) {
4661 v1 = 0x04; /* PCI */
4662 v2 = 0x92;
4663 } else {
4664 v1 = 0x14; /* AGP */
4665 v2 = 0xb2;
4666 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004667 }
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004668 outSISIDXREG(SISSR, 0x21, v1);
4669 outSISIDXREG(SISSR, 0x22, v2);
4670
4671 /* Sense CRT1 */
4672 sisfb_sense_crt1(ivideo);
4673
4674 /* Set default mode, don't clear screen */
4675 ivideo->SiS_Pr.SiS_UseOEM = FALSE;
4676 SiS_SetEnableDstn(&ivideo->SiS_Pr, FALSE);
4677 SiS_SetEnableFstn(&ivideo->SiS_Pr, FALSE);
4678 ivideo->curFSTN = ivideo->curDSTN = 0;
4679 ivideo->SiS_Pr.VideoMemorySize = 8 << 20;
4680 SiSSetMode(&ivideo->SiS_Pr, 0x2e | 0x80);
4681
4682 outSISIDXREG(SISSR, 0x05, 0x86);
4683
4684 /* Display off */
4685 orSISIDXREG(SISSR, 0x01, 0x20);
4686
4687 /* Save mode number in CR34 */
4688 outSISIDXREG(SISCR, 0x34, 0x2e);
4689
4690 /* Let everyone know what the current mode is */
4691 ivideo->modeprechange = 0x2e;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004692}
4693#endif
4694
4695#ifdef CONFIG_FB_SIS_315
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004696#if 0
4697static void __devinit
4698sisfb_post_sis315330(struct pci_dev *pdev)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004699{
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004700 /* TODO */
Linus Torvalds1da177e2005-04-16 15:20:36 -07004701}
4702#endif
4703
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004704static void __devinit
4705sisfb_post_xgi_delay(struct sis_video_info *ivideo, int delay)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004706{
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004707 unsigned int i;
4708 u8 reg;
4709
4710 for(i = 0; i <= (delay * 10 * 36); i++) {
4711 inSISIDXREG(SISSR, 0x05, reg);
4712 reg++;
4713 }
4714}
4715
4716static int __devinit
4717sisfb_find_host_bridge(struct sis_video_info *ivideo, struct pci_dev *mypdev,
4718 unsigned short pcivendor)
4719{
4720 struct pci_dev *pdev = NULL;
4721 unsigned short temp;
4722 int ret = 0;
4723
4724 while((pdev = SIS_PCI_GET_CLASS(PCI_CLASS_BRIDGE_HOST, pdev))) {
4725 temp = pdev->vendor;
4726 SIS_PCI_PUT_DEVICE(pdev);
4727 if(temp == pcivendor) {
4728 ret = 1;
4729 break;
4730 }
4731 }
4732
4733 return ret;
4734}
4735
4736static int __devinit
4737sisfb_post_xgi_rwtest(struct sis_video_info *ivideo, int starta,
4738 unsigned int enda, unsigned int mapsize)
4739{
4740 unsigned int pos;
4741 int i;
4742
4743 writel(0, ivideo->video_vbase);
4744
4745 for(i = starta; i <= enda; i++) {
4746 pos = 1 << i;
4747 if(pos < mapsize)
4748 writel(pos, ivideo->video_vbase + pos);
4749 }
4750
4751 sisfb_post_xgi_delay(ivideo, 150);
4752
4753 if(readl(ivideo->video_vbase) != 0)
4754 return 0;
4755
4756 for(i = starta; i <= enda; i++) {
4757 pos = 1 << i;
4758 if(pos < mapsize) {
4759 if(readl(ivideo->video_vbase + pos) != pos)
4760 return 0;
4761 } else
4762 return 0;
4763 }
4764
4765 return 1;
4766}
4767
4768static void __devinit
4769sisfb_post_xgi_ramsize(struct sis_video_info *ivideo)
4770{
4771 unsigned int buswidth, ranksize, channelab, mapsize;
4772 int i, j, k, l;
4773 u8 reg, sr14;
4774 static const u8 dramsr13[12 * 5] = {
4775 0x02, 0x0e, 0x0b, 0x80, 0x5d,
4776 0x02, 0x0e, 0x0a, 0x40, 0x59,
4777 0x02, 0x0d, 0x0b, 0x40, 0x4d,
4778 0x02, 0x0e, 0x09, 0x20, 0x55,
4779 0x02, 0x0d, 0x0a, 0x20, 0x49,
4780 0x02, 0x0c, 0x0b, 0x20, 0x3d,
4781 0x02, 0x0e, 0x08, 0x10, 0x51,
4782 0x02, 0x0d, 0x09, 0x10, 0x45,
4783 0x02, 0x0c, 0x0a, 0x10, 0x39,
4784 0x02, 0x0d, 0x08, 0x08, 0x41,
4785 0x02, 0x0c, 0x09, 0x08, 0x35,
4786 0x02, 0x0c, 0x08, 0x04, 0x31
4787 };
4788 static const u8 dramsr13_4[4 * 5] = {
4789 0x02, 0x0d, 0x09, 0x40, 0x45,
4790 0x02, 0x0c, 0x09, 0x20, 0x35,
4791 0x02, 0x0c, 0x08, 0x10, 0x31,
4792 0x02, 0x0b, 0x08, 0x08, 0x21
4793 };
4794
4795 /* Enable linear mode, disable 0xa0000 address decoding */
4796 /* We disable a0000 address decoding, because
4797 * - if running on x86, if the card is disabled, it means
4798 * that another card is in the system. We don't want
4799 * to interphere with that primary card's textmode.
4800 * - if running on non-x86, there usually is no VGA window
4801 * at a0000.
4802 */
4803 orSISIDXREG(SISSR, 0x20, (0x80 | 0x04));
4804
4805 /* Need to map max FB size for finding out about RAM size */
4806 mapsize = 256 << 20;
4807 sisfb_post_map_vram(ivideo, &mapsize, 32);
4808
4809 if(!ivideo->video_vbase) {
4810 printk(KERN_ERR "sisfb: Unable to detect RAM size. Setting default.\n");
4811 outSISIDXREG(SISSR, 0x13, 0x35);
4812 outSISIDXREG(SISSR, 0x14, 0x41);
4813 /* TODO */
4814 return;
4815 }
4816
4817 /* Non-interleaving */
4818 outSISIDXREG(SISSR, 0x15, 0x00);
4819 /* No tiling */
4820 outSISIDXREG(SISSR, 0x1c, 0x00);
4821
4822 if(ivideo->chip == XGI_20) {
4823
4824 channelab = 1;
4825 inSISIDXREG(SISCR, 0x97, reg);
4826 if(!(reg & 0x01)) { /* Single 32/16 */
4827 buswidth = 32;
4828 outSISIDXREG(SISSR, 0x13, 0xb1);
4829 outSISIDXREG(SISSR, 0x14, 0x52);
4830 sisfb_post_xgi_delay(ivideo, 1);
4831 sr14 = 0x02;
4832 if(sisfb_post_xgi_rwtest(ivideo, 23, 24, mapsize))
4833 goto bail_out;
4834
4835 outSISIDXREG(SISSR, 0x13, 0x31);
4836 outSISIDXREG(SISSR, 0x14, 0x42);
4837 sisfb_post_xgi_delay(ivideo, 1);
4838 if(sisfb_post_xgi_rwtest(ivideo, 23, 23, mapsize))
4839 goto bail_out;
4840
4841 buswidth = 16;
4842 outSISIDXREG(SISSR, 0x13, 0xb1);
4843 outSISIDXREG(SISSR, 0x14, 0x41);
4844 sisfb_post_xgi_delay(ivideo, 1);
4845 sr14 = 0x01;
4846 if(sisfb_post_xgi_rwtest(ivideo, 22, 23, mapsize))
4847 goto bail_out;
4848 else
4849 outSISIDXREG(SISSR, 0x13, 0x31);
4850 } else { /* Dual 16/8 */
4851 buswidth = 16;
4852 outSISIDXREG(SISSR, 0x13, 0xb1);
4853 outSISIDXREG(SISSR, 0x14, 0x41);
4854 sisfb_post_xgi_delay(ivideo, 1);
4855 sr14 = 0x01;
4856 if(sisfb_post_xgi_rwtest(ivideo, 22, 23, mapsize))
4857 goto bail_out;
4858
4859 outSISIDXREG(SISSR, 0x13, 0x31);
4860 outSISIDXREG(SISSR, 0x14, 0x31);
4861 sisfb_post_xgi_delay(ivideo, 1);
4862 if(sisfb_post_xgi_rwtest(ivideo, 22, 22, mapsize))
4863 goto bail_out;
4864
4865 buswidth = 8;
4866 outSISIDXREG(SISSR, 0x13, 0xb1);
4867 outSISIDXREG(SISSR, 0x14, 0x30);
4868 sisfb_post_xgi_delay(ivideo, 1);
4869 sr14 = 0x00;
4870 if(sisfb_post_xgi_rwtest(ivideo, 21, 22, mapsize))
4871 goto bail_out;
4872 else
4873 outSISIDXREG(SISSR, 0x13, 0x31);
4874 }
4875
4876 } else { /* XGI_40 */
4877
4878 inSISIDXREG(SISCR, 0x97, reg);
4879 if(!(reg & 0x10)) {
4880 inSISIDXREG(SISSR, 0x39, reg);
4881 reg >>= 1;
4882 }
4883
4884 if(reg & 0x01) { /* DDRII */
4885 buswidth = 32;
4886 if(ivideo->revision_id == 2) {
4887 channelab = 2;
4888 outSISIDXREG(SISSR, 0x13, 0xa1);
4889 outSISIDXREG(SISSR, 0x14, 0x44);
4890 sr14 = 0x04;
4891 sisfb_post_xgi_delay(ivideo, 1);
4892 if(sisfb_post_xgi_rwtest(ivideo, 23, 24, mapsize))
4893 goto bail_out;
4894
4895 outSISIDXREG(SISSR, 0x13, 0x21);
4896 outSISIDXREG(SISSR, 0x14, 0x34);
4897 if(sisfb_post_xgi_rwtest(ivideo, 22, 23, mapsize))
4898 goto bail_out;
4899
4900 channelab = 1;
4901 outSISIDXREG(SISSR, 0x13, 0xa1);
4902 outSISIDXREG(SISSR, 0x14, 0x40);
4903 sr14 = 0x00;
4904 if(sisfb_post_xgi_rwtest(ivideo, 22, 23, mapsize))
4905 goto bail_out;
4906
4907 outSISIDXREG(SISSR, 0x13, 0x21);
4908 outSISIDXREG(SISSR, 0x14, 0x30);
4909 } else {
4910 channelab = 3;
4911 outSISIDXREG(SISSR, 0x13, 0xa1);
4912 outSISIDXREG(SISSR, 0x14, 0x4c);
4913 sr14 = 0x0c;
4914 sisfb_post_xgi_delay(ivideo, 1);
4915 if(sisfb_post_xgi_rwtest(ivideo, 23, 25, mapsize))
4916 goto bail_out;
4917
4918 channelab = 2;
4919 outSISIDXREG(SISSR, 0x14, 0x48);
4920 sisfb_post_xgi_delay(ivideo, 1);
4921 sr14 = 0x08;
4922 if(sisfb_post_xgi_rwtest(ivideo, 23, 24, mapsize))
4923 goto bail_out;
4924
4925 outSISIDXREG(SISSR, 0x13, 0x21);
4926 outSISIDXREG(SISSR, 0x14, 0x3c);
4927 sr14 = 0x0c;
4928
4929 if(sisfb_post_xgi_rwtest(ivideo, 23, 24, mapsize)) {
4930 channelab = 3;
4931 } else {
4932 channelab = 2;
4933 outSISIDXREG(SISSR, 0x14, 0x38);
4934 sr14 = 0x08;
4935 }
4936 }
4937 sisfb_post_xgi_delay(ivideo, 1);
4938
4939 } else { /* DDR */
4940
4941 buswidth = 64;
4942 if(ivideo->revision_id == 2) {
4943 channelab = 1;
4944 outSISIDXREG(SISSR, 0x13, 0xa1);
4945 outSISIDXREG(SISSR, 0x14, 0x52);
4946 sisfb_post_xgi_delay(ivideo, 1);
4947 sr14 = 0x02;
4948 if(sisfb_post_xgi_rwtest(ivideo, 23, 24, mapsize))
4949 goto bail_out;
4950
4951 outSISIDXREG(SISSR, 0x13, 0x21);
4952 outSISIDXREG(SISSR, 0x14, 0x42);
4953 } else {
4954 channelab = 2;
4955 outSISIDXREG(SISSR, 0x13, 0xa1);
4956 outSISIDXREG(SISSR, 0x14, 0x5a);
4957 sisfb_post_xgi_delay(ivideo, 1);
4958 sr14 = 0x0a;
4959 if(sisfb_post_xgi_rwtest(ivideo, 24, 25, mapsize))
4960 goto bail_out;
4961
4962 outSISIDXREG(SISSR, 0x13, 0x21);
4963 outSISIDXREG(SISSR, 0x14, 0x4a);
4964 }
4965 sisfb_post_xgi_delay(ivideo, 1);
4966
4967 }
4968 }
4969
4970bail_out:
4971 setSISIDXREG(SISSR, 0x14, 0xf0, sr14);
4972 sisfb_post_xgi_delay(ivideo, 1);
4973
4974 j = (ivideo->chip == XGI_20) ? 5 : 9;
4975 k = (ivideo->chip == XGI_20) ? 12 : 4;
4976
4977 for(i = 0; i < k; i++) {
4978
4979 reg = (ivideo->chip == XGI_20) ?
4980 dramsr13[(i * 5) + 4] : dramsr13_4[(i * 5) + 4];
4981 setSISIDXREG(SISSR, 0x13, 0x80, reg);
4982 sisfb_post_xgi_delay(ivideo, 50);
4983
4984 ranksize = (ivideo->chip == XGI_20) ?
4985 dramsr13[(i * 5) + 3] : dramsr13_4[(i * 5) + 3];
4986
4987 inSISIDXREG(SISSR, 0x13, reg);
4988 if(reg & 0x80) ranksize <<= 1;
4989
4990 if(ivideo->chip == XGI_20) {
4991 if(buswidth == 16) ranksize <<= 1;
4992 else if(buswidth == 32) ranksize <<= 2;
4993 } else {
4994 if(buswidth == 64) ranksize <<= 1;
4995 }
4996
4997 reg = 0;
4998 l = channelab;
4999 if(l == 3) l = 4;
5000 if((ranksize * l) <= 256) {
5001 while((ranksize >>= 1)) reg += 0x10;
5002 }
5003
5004 if(!reg) continue;
5005
5006 setSISIDXREG(SISSR, 0x14, 0x0f, (reg & 0xf0));
5007 sisfb_post_xgi_delay(ivideo, 1);
5008
5009 if(sisfb_post_xgi_rwtest(ivideo, j, ((reg >> 4) + channelab - 2 + 20), mapsize))
5010 break;
5011 }
5012
5013 iounmap(ivideo->video_vbase);
5014}
5015
5016static void __devinit
5017sisfb_post_xgi_setclocks(struct sis_video_info *ivideo, u8 regb)
5018{
5019 u8 v1, v2, v3;
5020 int index;
5021 static const u8 cs90[8 * 3] = {
5022 0x16, 0x01, 0x01,
5023 0x3e, 0x03, 0x01,
5024 0x7c, 0x08, 0x01,
5025 0x79, 0x06, 0x01,
5026 0x29, 0x01, 0x81,
5027 0x5c, 0x23, 0x01,
5028 0x5c, 0x23, 0x01,
5029 0x5c, 0x23, 0x01
5030 };
5031 static const u8 csb8[8 * 3] = {
5032 0x5c, 0x23, 0x01,
5033 0x29, 0x01, 0x01,
5034 0x7c, 0x08, 0x01,
5035 0x79, 0x06, 0x01,
5036 0x29, 0x01, 0x81,
5037 0x5c, 0x23, 0x01,
5038 0x5c, 0x23, 0x01,
5039 0x5c, 0x23, 0x01
5040 };
5041
5042 regb = 0; /* ! */
5043
5044 index = regb * 3;
5045 v1 = cs90[index]; v2 = cs90[index + 1]; v3 = cs90[index + 2];
5046 if(ivideo->haveXGIROM) {
5047 v1 = ivideo->bios_abase[0x90 + index];
5048 v2 = ivideo->bios_abase[0x90 + index + 1];
5049 v3 = ivideo->bios_abase[0x90 + index + 2];
5050 }
5051 outSISIDXREG(SISSR, 0x28, v1);
5052 outSISIDXREG(SISSR, 0x29, v2);
5053 outSISIDXREG(SISSR, 0x2a, v3);
5054 sisfb_post_xgi_delay(ivideo, 0x43);
5055 sisfb_post_xgi_delay(ivideo, 0x43);
5056 sisfb_post_xgi_delay(ivideo, 0x43);
5057 index = regb * 3;
5058 v1 = csb8[index]; v2 = csb8[index + 1]; v3 = csb8[index + 2];
5059 if(ivideo->haveXGIROM) {
5060 v1 = ivideo->bios_abase[0xb8 + index];
5061 v2 = ivideo->bios_abase[0xb8 + index + 1];
5062 v3 = ivideo->bios_abase[0xb8 + index + 2];
5063 }
5064 outSISIDXREG(SISSR, 0x2e, v1);
5065 outSISIDXREG(SISSR, 0x2f, v2);
5066 outSISIDXREG(SISSR, 0x30, v3);
5067 sisfb_post_xgi_delay(ivideo, 0x43);
5068 sisfb_post_xgi_delay(ivideo, 0x43);
5069 sisfb_post_xgi_delay(ivideo, 0x43);
5070}
5071
5072static int __devinit
5073sisfb_post_xgi(struct pci_dev *pdev)
5074{
5075 struct sis_video_info *ivideo = pci_get_drvdata(pdev);
5076 unsigned char *bios = ivideo->bios_abase;
5077 struct pci_dev *mypdev = NULL;
5078 const u8 *ptr, *ptr2;
5079 u8 v1, v2, v3, v4, v5, reg, ramtype;
5080 u32 rega, regb, regd;
5081 int i, j, k, index;
5082 static const u8 cs78[3] = { 0xf6, 0x0d, 0x00 };
5083 static const u8 cs76[2] = { 0xa3, 0xfb };
5084 static const u8 cs7b[3] = { 0xc0, 0x11, 0x00 };
5085 static const u8 cs158[8] = {
5086 0x88, 0xaa, 0x48, 0x00, 0x00, 0x00, 0x00, 0x00
5087 };
5088 static const u8 cs160[8] = {
5089 0x44, 0x77, 0x77, 0x00, 0x00, 0x00, 0x00, 0x00
5090 };
5091 static const u8 cs168[8] = {
5092 0x48, 0x78, 0x88, 0x00, 0x00, 0x00, 0x00, 0x00
5093 };
5094 static const u8 cs128[3 * 8] = {
5095 0x90, 0x28, 0x24, 0x00, 0x00, 0x00, 0x00, 0x00,
5096 0x77, 0x44, 0x44, 0x00, 0x00, 0x00, 0x00, 0x00,
5097 0x77, 0x44, 0x44, 0x00, 0x00, 0x00, 0x00, 0x00
5098 };
5099 static const u8 cs148[2 * 8] = {
5100 0x55, 0x55, 0x55, 0x00, 0x00, 0x00, 0x00, 0x00,
5101 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
5102 };
5103 static const u8 cs31a[8 * 4] = {
5104 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
5105 0xaa, 0xaa, 0xaa, 0xaa, 0x00, 0x00, 0x00, 0x00,
5106 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
5107 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
5108 };
5109 static const u8 cs33a[8 * 4] = {
5110 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
5111 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
5112 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
5113 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
5114 };
5115 static const u8 cs45a[8 * 2] = {
5116 0x00, 0x00, 0xa0, 0x00, 0xa0, 0x00, 0x00, 0x00,
5117 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
5118 };
5119 static const u8 cs170[7 * 8] = {
5120 0x54, 0x32, 0x44, 0x00, 0x00, 0x00, 0x00, 0x00,
5121 0x54, 0x43, 0x44, 0x00, 0x00, 0x00, 0x00, 0x00,
5122 0x0a, 0x05, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00,
5123 0x44, 0x34, 0x44, 0x00, 0x00, 0x00, 0x00, 0x00,
5124 0x10, 0x0a, 0x0a, 0x00, 0x00, 0x00, 0x00, 0x00,
5125 0x11, 0x0c, 0x0c, 0x00, 0x00, 0x00, 0x00, 0x00,
5126 0x05, 0x05, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00
5127 };
5128 static const u8 cs1a8[3 * 8] = {
5129 0xf0, 0xf0, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x00,
5130 0x05, 0x02, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00,
5131 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
5132 };
5133 static const u8 cs100[2 * 8] = {
5134 0xc4, 0x04, 0x84, 0x00, 0x00, 0x00, 0x00, 0x00,
5135 0xc4, 0x04, 0x84, 0x00, 0x00, 0x00, 0x00, 0x00
5136 };
5137
5138 /* VGA enable */
5139 reg = inSISREG(SISVGAENABLE) | 0x01;
5140 outSISREG(SISVGAENABLE, reg);
5141
5142 /* Misc */
5143 reg = inSISREG(SISMISCR) | 0x01;
5144 outSISREG(SISMISCW, reg);
5145
5146 /* Unlock SR */
5147 outSISIDXREG(SISSR, 0x05, 0x86);
5148 inSISIDXREG(SISSR, 0x05, reg);
5149 if(reg != 0xa1)
5150 return 0;
5151
5152 /* Clear some regs */
5153 for(i = 0; i < 0x22; i++) {
5154 if(0x06 + i == 0x20) continue;
5155 outSISIDXREG(SISSR, 0x06 + i, 0x00);
5156 }
5157 for(i = 0; i < 0x0b; i++) {
5158 outSISIDXREG(SISSR, 0x31 + i, 0x00);
5159 }
5160 for(i = 0; i < 0x10; i++) {
5161 outSISIDXREG(SISCR, 0x30 + i, 0x00);
5162 }
5163
5164 ptr = cs78;
5165 if(ivideo->haveXGIROM) {
5166 ptr = (const u8 *)&bios[0x78];
5167 }
5168 for(i = 0; i < 3; i++) {
5169 outSISIDXREG(SISSR, 0x23 + i, ptr[i]);
5170 }
5171
5172 ptr = cs76;
5173 if(ivideo->haveXGIROM) {
5174 ptr = (const u8 *)&bios[0x76];
5175 }
5176 for(i = 0; i < 2; i++) {
5177 outSISIDXREG(SISSR, 0x21 + i, ptr[i]);
5178 }
5179
5180 v1 = 0x18; v2 = 0x00;
5181 if(ivideo->haveXGIROM) {
5182 v1 = bios[0x74];
5183 v2 = bios[0x75];
5184 }
5185 outSISIDXREG(SISSR, 0x07, v1);
5186 outSISIDXREG(SISSR, 0x11, 0x0f);
5187 outSISIDXREG(SISSR, 0x1f, v2);
5188 /* PCI linear mode, RelIO enabled, A0000 decoding disabled */
5189 outSISIDXREG(SISSR, 0x20, 0x80 | 0x20 | 0x04);
5190 outSISIDXREG(SISSR, 0x27, 0x74);
5191
5192 ptr = cs7b;
5193 if(ivideo->haveXGIROM) {
5194 ptr = (const u8 *)&bios[0x7b];
5195 }
5196 for(i = 0; i < 3; i++) {
5197 outSISIDXREG(SISSR, 0x31 + i, ptr[i]);
5198 }
5199
5200 if(ivideo->chip == XGI_40) {
5201 if(ivideo->revision_id == 2) {
5202 setSISIDXREG(SISSR, 0x3b, 0x3f, 0xc0);
5203 }
5204 outSISIDXREG(SISCR, 0x7d, 0xfe);
5205 outSISIDXREG(SISCR, 0x7e, 0x0f);
5206 }
5207 if(ivideo->revision_id == 0) { /* 40 *and* 20? */
5208 andSISIDXREG(SISCR, 0x58, 0xd7);
5209 inSISIDXREG(SISCR, 0xcb, reg);
5210 if(reg & 0x20) {
5211 setSISIDXREG(SISCR, 0x58, 0xd7, (reg & 0x10) ? 0x08 : 0x20); /* =0x28 Z7 ? */
5212 }
5213 }
5214
5215 reg = (ivideo->chip == XGI_40) ? 0x20 : 0x00;
5216 setSISIDXREG(SISCR, 0x38, 0x1f, reg);
5217
5218 if(ivideo->chip == XGI_20) {
5219 outSISIDXREG(SISSR, 0x36, 0x70);
5220 } else {
5221 outSISIDXREG(SISVID, 0x00, 0x86);
5222 outSISIDXREG(SISVID, 0x32, 0x00);
5223 outSISIDXREG(SISVID, 0x30, 0x00);
5224 outSISIDXREG(SISVID, 0x32, 0x01);
5225 outSISIDXREG(SISVID, 0x30, 0x00);
5226 andSISIDXREG(SISVID, 0x2f, 0xdf);
5227 andSISIDXREG(SISCAP, 0x00, 0x3f);
5228
5229 outSISIDXREG(SISPART1, 0x2f, 0x01);
5230 outSISIDXREG(SISPART1, 0x00, 0x00);
5231 outSISIDXREG(SISPART1, 0x02, bios[0x7e]);
5232 outSISIDXREG(SISPART1, 0x2e, 0x08);
5233 andSISIDXREG(SISPART1, 0x35, 0x7f);
5234 andSISIDXREG(SISPART1, 0x50, 0xfe);
5235
5236 inSISIDXREG(SISPART4, 0x00, reg);
5237 if(reg == 1 || reg == 2) {
5238 outSISIDXREG(SISPART2, 0x00, 0x1c);
5239 outSISIDXREG(SISPART4, 0x0d, bios[0x7f]);
5240 outSISIDXREG(SISPART4, 0x0e, bios[0x80]);
5241 outSISIDXREG(SISPART4, 0x10, bios[0x81]);
5242 andSISIDXREG(SISPART4, 0x0f, 0x3f);
5243
5244 inSISIDXREG(SISPART4, 0x01, reg);
5245 if((reg & 0xf0) >= 0xb0) {
5246 inSISIDXREG(SISPART4, 0x23, reg);
5247 if(reg & 0x20) reg |= 0x40;
5248 outSISIDXREG(SISPART4, 0x23, reg);
5249 reg = (reg & 0x20) ? 0x02 : 0x00;
5250 setSISIDXREG(SISPART1, 0x1e, 0xfd, reg);
5251 }
5252 }
5253
5254 v1 = bios[0x77];
5255
5256 inSISIDXREG(SISSR, 0x3b, reg);
5257 if(reg & 0x02) {
5258 inSISIDXREG(SISSR, 0x3a, reg);
5259 v2 = (reg & 0x30) >> 3;
5260 if(!(v2 & 0x04)) v2 ^= 0x02;
5261 inSISIDXREG(SISSR, 0x39, reg);
5262 if(reg & 0x80) v2 |= 0x80;
5263 v2 |= 0x01;
5264
5265 if((mypdev = SIS_PCI_GET_DEVICE(PCI_VENDOR_ID_SI, 0x0730, NULL))) {
5266 SIS_PCI_PUT_DEVICE(mypdev);
5267 if(((v2 & 0x06) == 2) || ((v2 & 0x06) == 4))
5268 v2 &= 0xf9;
5269 v2 |= 0x08;
5270 v1 &= 0xfe;
5271 } else {
5272 mypdev = SIS_PCI_GET_DEVICE(PCI_VENDOR_ID_SI, 0x0735, NULL);
5273 if(!mypdev)
5274 mypdev = SIS_PCI_GET_DEVICE(PCI_VENDOR_ID_SI, 0x0645, NULL);
5275 if(!mypdev)
5276 mypdev = SIS_PCI_GET_DEVICE(PCI_VENDOR_ID_SI, 0x0650, NULL);
5277 if(mypdev) {
5278 pci_read_config_dword(mypdev, 0x94, &regd);
5279 regd &= 0xfffffeff;
5280 pci_write_config_dword(mypdev, 0x94, regd);
5281 v1 &= 0xfe;
5282 SIS_PCI_PUT_DEVICE(mypdev);
5283 } else if(sisfb_find_host_bridge(ivideo, pdev, PCI_VENDOR_ID_SI)) {
5284 v1 &= 0xfe;
5285 } else if(sisfb_find_host_bridge(ivideo, pdev, 0x1106) ||
5286 sisfb_find_host_bridge(ivideo, pdev, 0x1022) ||
5287 sisfb_find_host_bridge(ivideo, pdev, 0x700e) ||
5288 sisfb_find_host_bridge(ivideo, pdev, 0x10de)) {
5289 if((v2 & 0x06) == 4)
5290 v2 ^= 0x06;
5291 v2 |= 0x08;
5292 }
5293 }
5294 setSISIDXREG(SISCR, 0x5f, 0xf0, v2);
5295 }
5296 outSISIDXREG(SISSR, 0x22, v1);
5297
5298 if(ivideo->revision_id == 2) {
5299 inSISIDXREG(SISSR, 0x3b, v1);
5300 inSISIDXREG(SISSR, 0x3a, v2);
5301 regd = bios[0x90 + 3] | (bios[0x90 + 4] << 8);
5302 if( (!(v1 & 0x02)) && (v2 & 0x30) && (regd < 0xcf) )
5303 setSISIDXREG(SISCR, 0x5f, 0xf1, 0x01);
5304
5305 if((mypdev = SIS_PCI_GET_DEVICE(0x10de, 0x01e0, NULL))) {
5306 /* TODO: set CR5f &0xf1 | 0x01 for version 6570
5307 * of nforce 2 ROM
5308 */
5309 if(0)
5310 setSISIDXREG(SISCR, 0x5f, 0xf1, 0x01);
5311 SIS_PCI_PUT_DEVICE(mypdev);
5312 }
5313 }
5314
5315 v1 = 0x30;
5316 inSISIDXREG(SISSR, 0x3b, reg);
5317 inSISIDXREG(SISCR, 0x5f, v2);
5318 if((!(reg & 0x02)) && (v2 & 0x0e))
5319 v1 |= 0x08;
5320 outSISIDXREG(SISSR, 0x27, v1);
5321
5322 if(bios[0x64] & 0x01) {
5323 setSISIDXREG(SISCR, 0x5f, 0xf0, bios[0x64]);
5324 }
5325
5326 v1 = bios[0x4f7];
5327 pci_read_config_dword(pdev, 0x50, &regd);
5328 regd = (regd >> 20) & 0x0f;
5329 if(regd == 1) {
5330 v1 &= 0xfc;
5331 orSISIDXREG(SISCR, 0x5f, 0x08);
5332 }
5333 outSISIDXREG(SISCR, 0x48, v1);
5334
5335 setSISIDXREG(SISCR, 0x47, 0x04, bios[0x4f6] & 0xfb);
5336 setSISIDXREG(SISCR, 0x49, 0xf0, bios[0x4f8] & 0x0f);
5337 setSISIDXREG(SISCR, 0x4a, 0x60, bios[0x4f9] & 0x9f);
5338 setSISIDXREG(SISCR, 0x4b, 0x08, bios[0x4fa] & 0xf7);
5339 setSISIDXREG(SISCR, 0x4c, 0x80, bios[0x4fb] & 0x7f);
5340 outSISIDXREG(SISCR, 0x70, bios[0x4fc]);
5341 setSISIDXREG(SISCR, 0x71, 0xf0, bios[0x4fd] & 0x0f);
5342 outSISIDXREG(SISCR, 0x74, 0xd0);
5343 setSISIDXREG(SISCR, 0x74, 0xcf, bios[0x4fe] & 0x30);
5344 setSISIDXREG(SISCR, 0x75, 0xe0, bios[0x4ff] & 0x1f);
5345 setSISIDXREG(SISCR, 0x76, 0xe0, bios[0x500] & 0x1f);
5346 v1 = bios[0x501];
5347 if((mypdev = SIS_PCI_GET_DEVICE(0x8086, 0x2530, NULL))) {
5348 v1 = 0xf0;
5349 SIS_PCI_PUT_DEVICE(mypdev);
5350 }
5351 outSISIDXREG(SISCR, 0x77, v1);
5352 }
5353
5354 /* RAM type */
5355
5356 regb = 0; /* ! */
5357
5358 v1 = 0xff;
5359 if(ivideo->haveXGIROM) {
5360 v1 = bios[0x140 + regb];
5361 }
5362 outSISIDXREG(SISCR, 0x6d, v1);
5363
5364 ptr = cs128;
5365 if(ivideo->haveXGIROM) {
5366 ptr = (const u8 *)&bios[0x128];
5367 }
5368 for(i = 0, j = 0; i < 3; i++, j += 8) {
5369 outSISIDXREG(SISCR, 0x68 + i, ptr[j + regb]);
5370 }
5371
5372 ptr = cs31a;
5373 ptr2 = cs33a;
5374 if(ivideo->haveXGIROM) {
5375 index = (ivideo->chip == XGI_20) ? 0x31a : 0x3a6;
5376 ptr = (const u8 *)&bios[index];
5377 ptr2 = (const u8 *)&bios[index + 0x20];
5378 }
5379 for(i = 0; i < 2; i++) {
5380 if(i == 0) {
5381 regd = le32_to_cpu(((u32 *)ptr)[regb]);
5382 rega = 0x6b;
5383 } else {
5384 regd = le32_to_cpu(((u32 *)ptr2)[regb]);
5385 rega = 0x6e;
5386 }
5387 reg = 0x00;
5388 for(j = 0; j < 16; j++) {
5389 reg &= 0xf3;
5390 if(regd & 0x01) reg |= 0x04;
5391 if(regd & 0x02) reg |= 0x08;
5392 regd >>= 2;
5393 outSISIDXREG(SISCR, rega, reg);
5394 inSISIDXREG(SISCR, rega, reg);
5395 inSISIDXREG(SISCR, rega, reg);
5396 reg += 0x10;
5397 }
5398 }
5399
5400 andSISIDXREG(SISCR, 0x6e, 0xfc);
5401
5402 ptr = NULL;
5403 if(ivideo->haveXGIROM) {
5404 index = (ivideo->chip == XGI_20) ? 0x35a : 0x3e6;
5405 ptr = (const u8 *)&bios[index];
5406 }
5407 for(i = 0; i < 4; i++) {
5408 setSISIDXREG(SISCR, 0x6e, 0xfc, i);
5409 reg = 0x00;
5410 for(j = 0; j < 2; j++) {
5411 regd = 0;
5412 if(ptr) {
5413 regd = le32_to_cpu(((u32 *)ptr)[regb * 8]);
5414 ptr += 4;
5415 }
5416 /* reg = 0x00; */
5417 for(k = 0; k < 16; k++) {
5418 reg &= 0xfc;
5419 if(regd & 0x01) reg |= 0x01;
5420 if(regd & 0x02) reg |= 0x02;
5421 regd >>= 2;
5422 outSISIDXREG(SISCR, 0x6f, reg);
5423 inSISIDXREG(SISCR, 0x6f, reg);
5424 inSISIDXREG(SISCR, 0x6f, reg);
5425 reg += 0x08;
5426 }
5427 }
5428 }
5429
5430 ptr = cs148;
5431 if(ivideo->haveXGIROM) {
5432 ptr = (const u8 *)&bios[0x148];
5433 }
5434 for(i = 0, j = 0; i < 2; i++, j += 8) {
5435 outSISIDXREG(SISCR, 0x80 + i, ptr[j + regb]);
5436 }
5437
5438 andSISIDXREG(SISCR, 0x89, 0x8f);
5439
5440 ptr = cs45a;
5441 if(ivideo->haveXGIROM) {
5442 index = (ivideo->chip == XGI_20) ? 0x45a : 0x4e6;
5443 ptr = (const u8 *)&bios[index];
5444 }
5445 regd = le16_to_cpu(((const u16 *)ptr)[regb]);
5446 reg = 0x80;
5447 for(i = 0; i < 5; i++) {
5448 reg &= 0xfc;
5449 if(regd & 0x01) reg |= 0x01;
5450 if(regd & 0x02) reg |= 0x02;
5451 regd >>= 2;
5452 outSISIDXREG(SISCR, 0x89, reg);
5453 inSISIDXREG(SISCR, 0x89, reg);
5454 inSISIDXREG(SISCR, 0x89, reg);
5455 reg += 0x10;
5456 }
5457
5458 v1 = 0xb5; v2 = 0x20; v3 = 0xf0; v4 = 0x13;
5459 if(ivideo->haveXGIROM) {
5460 v1 = bios[0x118 + regb];
5461 v2 = bios[0xf8 + regb];
5462 v3 = bios[0x120 + regb];
5463 v4 = bios[0x1ca];
5464 }
5465 outSISIDXREG(SISCR, 0x45, v1 & 0x0f);
5466 outSISIDXREG(SISCR, 0x99, (v1 >> 4) & 0x07);
5467 orSISIDXREG(SISCR, 0x40, v1 & 0x80);
5468 outSISIDXREG(SISCR, 0x41, v2);
5469
5470 ptr = cs170;
5471 if(ivideo->haveXGIROM) {
5472 ptr = (const u8 *)&bios[0x170];
5473 }
5474 for(i = 0, j = 0; i < 7; i++, j += 8) {
5475 outSISIDXREG(SISCR, 0x90 + i, ptr[j + regb]);
5476 }
5477
5478 outSISIDXREG(SISCR, 0x59, v3);
5479
5480 ptr = cs1a8;
5481 if(ivideo->haveXGIROM) {
5482 ptr = (const u8 *)&bios[0x1a8];
5483 }
5484 for(i = 0, j = 0; i < 3; i++, j += 8) {
5485 outSISIDXREG(SISCR, 0xc3 + i, ptr[j + regb]);
5486 }
5487
5488 ptr = cs100;
5489 if(ivideo->haveXGIROM) {
5490 ptr = (const u8 *)&bios[0x100];
5491 }
5492 for(i = 0, j = 0; i < 2; i++, j += 8) {
5493 outSISIDXREG(SISCR, 0x8a + i, ptr[j + regb]);
5494 }
5495
5496 outSISIDXREG(SISCR, 0xcf, v4);
5497
5498 outSISIDXREG(SISCR, 0x83, 0x09);
5499 outSISIDXREG(SISCR, 0x87, 0x00);
5500
5501 if(ivideo->chip == XGI_40) {
5502 if( (ivideo->revision_id == 1) ||
5503 (ivideo->revision_id == 2) ) {
5504 outSISIDXREG(SISCR, 0x8c, 0x87);
5505 }
5506 }
5507
5508 outSISIDXREG(SISSR, 0x17, 0x00);
5509 outSISIDXREG(SISSR, 0x1a, 0x87);
5510
5511 if(ivideo->chip == XGI_20) {
5512 outSISIDXREG(SISSR, 0x15, 0x00);
5513 outSISIDXREG(SISSR, 0x1c, 0x00);
5514 }
5515
5516 ramtype = 0x00; v1 = 0x10;
5517 if(ivideo->haveXGIROM) {
5518 ramtype = bios[0x62];
5519 v1 = bios[0x1d2];
5520 }
5521 if(!(ramtype & 0x80)) {
5522 if(ivideo->chip == XGI_20) {
5523 outSISIDXREG(SISCR, 0x97, v1);
5524 inSISIDXREG(SISCR, 0x97, reg);
5525 if(reg & 0x10) {
5526 ramtype = (reg & 0x01) << 1;
5527 }
5528 } else {
5529 inSISIDXREG(SISSR, 0x39, reg);
5530 ramtype = reg & 0x02;
5531 if(!(ramtype)) {
5532 inSISIDXREG(SISSR, 0x3a, reg);
5533 ramtype = (reg >> 1) & 0x01;
5534 }
5535 }
5536 }
5537 ramtype &= 0x07;
5538
5539 regb = 0; /* ! */
5540
5541 switch(ramtype) {
5542 case 0:
5543 sisfb_post_xgi_setclocks(ivideo, regb);
5544 if((ivideo->chip == XGI_20) ||
5545 (ivideo->revision_id == 1) ||
5546 (ivideo->revision_id == 2)) {
5547 v1 = cs158[regb]; v2 = cs160[regb]; v3 = cs168[regb];
5548 if(ivideo->haveXGIROM) {
5549 v1 = bios[regb + 0x158];
5550 v2 = bios[regb + 0x160];
5551 v3 = bios[regb + 0x168];
5552 }
5553 outSISIDXREG(SISCR, 0x82, v1);
5554 outSISIDXREG(SISCR, 0x85, v2);
5555 outSISIDXREG(SISCR, 0x86, v3);
5556 } else {
5557 outSISIDXREG(SISCR, 0x82, 0x88);
5558 outSISIDXREG(SISCR, 0x86, 0x00);
5559 inSISIDXREG(SISCR, 0x86, reg);
5560 outSISIDXREG(SISCR, 0x86, 0x88);
5561 inSISIDXREG(SISCR, 0x86, reg);
5562 outSISIDXREG(SISCR, 0x86, bios[regb + 0x168]);
5563 outSISIDXREG(SISCR, 0x82, 0x77);
5564 outSISIDXREG(SISCR, 0x85, 0x00);
5565 inSISIDXREG(SISCR, 0x85, reg);
5566 outSISIDXREG(SISCR, 0x85, 0x88);
5567 inSISIDXREG(SISCR, 0x85, reg);
5568 outSISIDXREG(SISCR, 0x85, bios[regb + 0x160]);
5569 outSISIDXREG(SISCR, 0x82, bios[regb + 0x158]);
5570 }
5571 if(ivideo->chip == XGI_40) {
5572 outSISIDXREG(SISCR, 0x97, 0x00);
5573 }
5574 outSISIDXREG(SISCR, 0x98, 0x01);
5575 outSISIDXREG(SISCR, 0x9a, 0x02);
5576
5577 outSISIDXREG(SISSR, 0x18, 0x01);
5578 if((ivideo->chip == XGI_20) ||
5579 (ivideo->revision_id == 2)) {
5580 outSISIDXREG(SISSR, 0x19, 0x40);
5581 } else {
5582 outSISIDXREG(SISSR, 0x19, 0x20);
5583 }
5584 outSISIDXREG(SISSR, 0x16, 0x00);
5585 outSISIDXREG(SISSR, 0x16, 0x80);
5586 if((ivideo->chip == XGI_20) || (bios[0x1cb] != 0x0c)) {
5587 sisfb_post_xgi_delay(ivideo, 0x43);
5588 sisfb_post_xgi_delay(ivideo, 0x43);
5589 sisfb_post_xgi_delay(ivideo, 0x43);
5590 outSISIDXREG(SISSR, 0x18, 0x00);
5591 if((ivideo->chip == XGI_20) ||
5592 (ivideo->revision_id == 2)) {
5593 outSISIDXREG(SISSR, 0x19, 0x40);
5594 } else {
5595 outSISIDXREG(SISSR, 0x19, 0x20);
5596 }
5597 } else if((ivideo->chip == XGI_40) && (bios[0x1cb] == 0x0c)) {
5598 /* outSISIDXREG(SISSR, 0x16, 0x0c); */ /* ? */
5599 }
5600 outSISIDXREG(SISSR, 0x16, 0x00);
5601 outSISIDXREG(SISSR, 0x16, 0x80);
5602 sisfb_post_xgi_delay(ivideo, 4);
5603 v1 = 0x31; v2 = 0x03; v3 = 0x83; v4 = 0x03; v5 = 0x83;
5604 if(ivideo->haveXGIROM) {
5605 v1 = bios[0xf0];
5606 index = (ivideo->chip == XGI_20) ? 0x4b2 : 0x53e;
5607 v2 = bios[index];
5608 v3 = bios[index + 1];
5609 v4 = bios[index + 2];
5610 v5 = bios[index + 3];
5611 }
5612 outSISIDXREG(SISSR, 0x18, v1);
5613 outSISIDXREG(SISSR, 0x19, ((ivideo->chip == XGI_20) ? 0x02 : 0x01));
5614 outSISIDXREG(SISSR, 0x16, v2);
5615 outSISIDXREG(SISSR, 0x16, v3);
5616 sisfb_post_xgi_delay(ivideo, 0x43);
5617 outSISIDXREG(SISSR, 0x1b, 0x03);
5618 sisfb_post_xgi_delay(ivideo, 0x22);
5619 outSISIDXREG(SISSR, 0x18, v1);
5620 outSISIDXREG(SISSR, 0x19, 0x00);
5621 outSISIDXREG(SISSR, 0x16, v4);
5622 outSISIDXREG(SISSR, 0x16, v5);
5623 outSISIDXREG(SISSR, 0x1b, 0x00);
5624 break;
5625 case 1:
5626 outSISIDXREG(SISCR, 0x82, 0x77);
5627 outSISIDXREG(SISCR, 0x86, 0x00);
5628 inSISIDXREG(SISCR, 0x86, reg);
5629 outSISIDXREG(SISCR, 0x86, 0x88);
5630 inSISIDXREG(SISCR, 0x86, reg);
5631 v1 = cs168[regb]; v2 = cs160[regb]; v3 = cs158[regb];
5632 if(ivideo->haveXGIROM) {
5633 v1 = bios[regb + 0x168];
5634 v2 = bios[regb + 0x160];
5635 v3 = bios[regb + 0x158];
5636 }
5637 outSISIDXREG(SISCR, 0x86, v1);
5638 outSISIDXREG(SISCR, 0x82, 0x77);
5639 outSISIDXREG(SISCR, 0x85, 0x00);
5640 inSISIDXREG(SISCR, 0x85, reg);
5641 outSISIDXREG(SISCR, 0x85, 0x88);
5642 inSISIDXREG(SISCR, 0x85, reg);
5643 outSISIDXREG(SISCR, 0x85, v2);
5644 outSISIDXREG(SISCR, 0x82, v3);
5645 outSISIDXREG(SISCR, 0x98, 0x01);
5646 outSISIDXREG(SISCR, 0x9a, 0x02);
5647
5648 outSISIDXREG(SISSR, 0x28, 0x64);
5649 outSISIDXREG(SISSR, 0x29, 0x63);
5650 sisfb_post_xgi_delay(ivideo, 15);
5651 outSISIDXREG(SISSR, 0x18, 0x00);
5652 outSISIDXREG(SISSR, 0x19, 0x20);
5653 outSISIDXREG(SISSR, 0x16, 0x00);
5654 outSISIDXREG(SISSR, 0x16, 0x80);
5655 outSISIDXREG(SISSR, 0x18, 0xc5);
5656 outSISIDXREG(SISSR, 0x19, 0x23);
5657 outSISIDXREG(SISSR, 0x16, 0x00);
5658 outSISIDXREG(SISSR, 0x16, 0x80);
5659 sisfb_post_xgi_delay(ivideo, 1);
5660 outSISIDXREG(SISCR, 0x97,0x11);
5661 sisfb_post_xgi_setclocks(ivideo, regb);
5662 sisfb_post_xgi_delay(ivideo, 0x46);
5663 outSISIDXREG(SISSR, 0x18, 0xc5);
5664 outSISIDXREG(SISSR, 0x19, 0x23);
5665 outSISIDXREG(SISSR, 0x16, 0x00);
5666 outSISIDXREG(SISSR, 0x16, 0x80);
5667 sisfb_post_xgi_delay(ivideo, 1);
5668 outSISIDXREG(SISSR, 0x1b, 0x04);
5669 sisfb_post_xgi_delay(ivideo, 1);
5670 outSISIDXREG(SISSR, 0x1b, 0x00);
5671 sisfb_post_xgi_delay(ivideo, 1);
5672 v1 = 0x31;
5673 if(ivideo->haveXGIROM) {
5674 v1 = bios[0xf0];
5675 }
5676 outSISIDXREG(SISSR, 0x18, v1);
5677 outSISIDXREG(SISSR, 0x19, 0x06);
5678 outSISIDXREG(SISSR, 0x16, 0x04);
5679 outSISIDXREG(SISSR, 0x16, 0x84);
5680 sisfb_post_xgi_delay(ivideo, 1);
5681 break;
5682 default:
5683 sisfb_post_xgi_setclocks(ivideo, regb);
5684 if((ivideo->chip == XGI_40) &&
5685 ((ivideo->revision_id == 1) ||
5686 (ivideo->revision_id == 2))) {
5687 outSISIDXREG(SISCR, 0x82, bios[regb + 0x158]);
5688 outSISIDXREG(SISCR, 0x85, bios[regb + 0x160]);
5689 outSISIDXREG(SISCR, 0x86, bios[regb + 0x168]);
5690 } else {
5691 outSISIDXREG(SISCR, 0x82, 0x88);
5692 outSISIDXREG(SISCR, 0x86, 0x00);
5693 inSISIDXREG(SISCR, 0x86, reg);
5694 outSISIDXREG(SISCR, 0x86, 0x88);
5695 outSISIDXREG(SISCR, 0x82, 0x77);
5696 outSISIDXREG(SISCR, 0x85, 0x00);
5697 inSISIDXREG(SISCR, 0x85, reg);
5698 outSISIDXREG(SISCR, 0x85, 0x88);
5699 inSISIDXREG(SISCR, 0x85, reg);
5700 v1 = cs160[regb]; v2 = cs158[regb];
5701 if(ivideo->haveXGIROM) {
5702 v1 = bios[regb + 0x160];
5703 v2 = bios[regb + 0x158];
5704 }
5705 outSISIDXREG(SISCR, 0x85, v1);
5706 outSISIDXREG(SISCR, 0x82, v2);
5707 }
5708 if(ivideo->chip == XGI_40) {
5709 outSISIDXREG(SISCR, 0x97, 0x11);
5710 }
5711 if((ivideo->chip == XGI_40) && (ivideo->revision_id == 2)) {
5712 outSISIDXREG(SISCR, 0x98, 0x01);
5713 } else {
5714 outSISIDXREG(SISCR, 0x98, 0x03);
5715 }
5716 outSISIDXREG(SISCR, 0x9a, 0x02);
5717
5718 if(ivideo->chip == XGI_40) {
5719 outSISIDXREG(SISSR, 0x18, 0x01);
5720 } else {
5721 outSISIDXREG(SISSR, 0x18, 0x00);
5722 }
5723 outSISIDXREG(SISSR, 0x19, 0x40);
5724 outSISIDXREG(SISSR, 0x16, 0x00);
5725 outSISIDXREG(SISSR, 0x16, 0x80);
5726 if((ivideo->chip == XGI_40) && (bios[0x1cb] != 0x0c)) {
5727 sisfb_post_xgi_delay(ivideo, 0x43);
5728 sisfb_post_xgi_delay(ivideo, 0x43);
5729 sisfb_post_xgi_delay(ivideo, 0x43);
5730 outSISIDXREG(SISSR, 0x18, 0x00);
5731 outSISIDXREG(SISSR, 0x19, 0x40);
5732 outSISIDXREG(SISSR, 0x16, 0x00);
5733 outSISIDXREG(SISSR, 0x16, 0x80);
5734 }
5735 sisfb_post_xgi_delay(ivideo, 4);
5736 v1 = 0x31;
5737 if(ivideo->haveXGIROM) {
5738 v1 = bios[0xf0];
5739 }
5740 outSISIDXREG(SISSR, 0x18, v1);
5741 outSISIDXREG(SISSR, 0x19, 0x01);
5742 if(ivideo->chip == XGI_40) {
5743 outSISIDXREG(SISSR, 0x16, bios[0x53e]);
5744 outSISIDXREG(SISSR, 0x16, bios[0x53f]);
5745 } else {
5746 outSISIDXREG(SISSR, 0x16, 0x05);
5747 outSISIDXREG(SISSR, 0x16, 0x85);
5748 }
5749 sisfb_post_xgi_delay(ivideo, 0x43);
5750 if(ivideo->chip == XGI_40) {
5751 outSISIDXREG(SISSR, 0x1b, 0x01);
5752 } else {
5753 outSISIDXREG(SISSR, 0x1b, 0x03);
5754 }
5755 sisfb_post_xgi_delay(ivideo, 0x22);
5756 outSISIDXREG(SISSR, 0x18, v1);
5757 outSISIDXREG(SISSR, 0x19, 0x00);
5758 if(ivideo->chip == XGI_40) {
5759 outSISIDXREG(SISSR, 0x16, bios[0x540]);
5760 outSISIDXREG(SISSR, 0x16, bios[0x541]);
5761 } else {
5762 outSISIDXREG(SISSR, 0x16, 0x05);
5763 outSISIDXREG(SISSR, 0x16, 0x85);
5764 }
5765 outSISIDXREG(SISSR, 0x1b, 0x00);
5766 }
5767
5768 regb = 0; /* ! */
5769 v1 = 0x03;
5770 if(ivideo->haveXGIROM) {
5771 v1 = bios[0x110 + regb];
5772 }
5773 outSISIDXREG(SISSR, 0x1b, v1);
5774
5775 /* RAM size */
5776 v1 = 0x00; v2 = 0x00;
5777 if(ivideo->haveXGIROM) {
5778 v1 = bios[0x62];
5779 v2 = bios[0x63];
5780 }
5781 regb = 0; /* ! */
5782 regd = 1 << regb;
5783 if((v1 & 0x40) && (v2 & regd) && ivideo->haveXGIROM) {
5784
5785 outSISIDXREG(SISSR, 0x13, bios[regb + 0xe0]);
5786 outSISIDXREG(SISSR, 0x14, bios[regb + 0xe0 + 8]);
5787
5788 } else {
5789
5790 /* Set default mode, don't clear screen */
5791 ivideo->SiS_Pr.SiS_UseOEM = FALSE;
5792 SiS_SetEnableDstn(&ivideo->SiS_Pr, FALSE);
5793 SiS_SetEnableFstn(&ivideo->SiS_Pr, FALSE);
5794 ivideo->curFSTN = ivideo->curDSTN = 0;
5795 ivideo->SiS_Pr.VideoMemorySize = 8 << 20;
5796 SiSSetMode(&ivideo->SiS_Pr, 0x2e | 0x80);
5797
5798 outSISIDXREG(SISSR, 0x05, 0x86);
5799
5800 /* Disable read-cache */
5801 andSISIDXREG(SISSR, 0x21, 0xdf);
5802 sisfb_post_xgi_ramsize(ivideo);
5803 /* Enable read-cache */
5804 orSISIDXREG(SISSR, 0x21, 0x20);
5805
5806 }
5807
5808#if 0
5809 printk(KERN_DEBUG "-----------------\n");
5810 for(i = 0; i < 0xff; i++) {
5811 inSISIDXREG(SISCR, i, reg);
5812 printk(KERN_DEBUG "CR%02x(%x) = 0x%02x\n", i, SISCR, reg);
5813 }
5814 for(i = 0; i < 0x40; i++) {
5815 inSISIDXREG(SISSR, i, reg);
5816 printk(KERN_DEBUG "SR%02x(%x) = 0x%02x\n", i, SISSR, reg);
5817 }
5818 printk(KERN_DEBUG "-----------------\n");
5819#endif
5820
5821 /* Sense CRT1 */
5822 if(ivideo->chip == XGI_20) {
5823 orSISIDXREG(SISCR, 0x32, 0x20);
5824 } else {
5825 inSISIDXREG(SISPART4, 0x00, reg);
5826 if((reg == 1) || (reg == 2)) {
5827 sisfb_sense_crt1(ivideo);
5828 } else {
5829 orSISIDXREG(SISCR, 0x32, 0x20);
5830 }
5831 }
5832
5833 /* Set default mode, don't clear screen */
5834 ivideo->SiS_Pr.SiS_UseOEM = FALSE;
5835 SiS_SetEnableDstn(&ivideo->SiS_Pr, FALSE);
5836 SiS_SetEnableFstn(&ivideo->SiS_Pr, FALSE);
5837 ivideo->curFSTN = ivideo->curDSTN = 0;
5838 SiSSetMode(&ivideo->SiS_Pr, 0x2e | 0x80);
5839
5840 outSISIDXREG(SISSR, 0x05, 0x86);
5841
5842 /* Display off */
5843 orSISIDXREG(SISSR, 0x01, 0x20);
5844
5845 /* Save mode number in CR34 */
5846 outSISIDXREG(SISCR, 0x34, 0x2e);
5847
5848 /* Let everyone know what the current mode is */
5849 ivideo->modeprechange = 0x2e;
5850
5851 if(ivideo->chip == XGI_40) {
5852 inSISIDXREG(SISCR, 0xca, reg);
5853 inSISIDXREG(SISCR, 0xcc, v1);
5854 if((reg & 0x10) && (!(v1 & 0x04))) {
5855 printk(KERN_ERR
5856 "sisfb: Please connect power to the card.\n");
5857 return 0;
5858 }
5859 }
5860
5861 return 1;
5862}
5863#endif
5864
5865static int __devinit
5866sisfb_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
5867{
5868 struct sisfb_chip_info *chipinfo = &sisfb_chip_info[ent->driver_data];
5869 struct sis_video_info *ivideo = NULL;
5870 struct fb_info *sis_fb_info = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005871 u16 reg16;
5872 u8 reg;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07005873 int i, ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005874
Thomas Winischhofer544393f2005-09-09 13:04:45 -07005875 if(sisfb_off)
5876 return -ENXIO;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005877
5878#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,3))
5879 sis_fb_info = framebuffer_alloc(sizeof(*ivideo), &pdev->dev);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07005880 if(!sis_fb_info)
5881 return -ENOMEM;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005882#else
5883 sis_fb_info = kmalloc(sizeof(*sis_fb_info) + sizeof(*ivideo), GFP_KERNEL);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07005884 if(!sis_fb_info)
5885 return -ENOMEM;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005886 memset(sis_fb_info, 0, sizeof(*sis_fb_info) + sizeof(*ivideo));
5887 sis_fb_info->par = ((char *)sis_fb_info + sizeof(*sis_fb_info));
5888#endif
5889
5890 ivideo = (struct sis_video_info *)sis_fb_info->par;
5891 ivideo->memyselfandi = sis_fb_info;
5892
Thomas Winischhofer544393f2005-09-09 13:04:45 -07005893 ivideo->sisfb_id = SISFB_ID;
5894
Linus Torvalds1da177e2005-04-16 15:20:36 -07005895 if(card_list == NULL) {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07005896 ivideo->cardnumber = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005897 } else {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07005898 struct sis_video_info *countvideo = card_list;
5899 ivideo->cardnumber = 1;
5900 while((countvideo = countvideo->next) != 0)
5901 ivideo->cardnumber++;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005902 }
5903
5904 strncpy(ivideo->myid, chipinfo->chip_name, 30);
5905
5906 ivideo->warncount = 0;
5907 ivideo->chip_id = pdev->device;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07005908 ivideo->chip_vendor = pdev->vendor;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005909 pci_read_config_byte(pdev, PCI_REVISION_ID, &ivideo->revision_id);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07005910 ivideo->SiS_Pr.ChipRevision = ivideo->revision_id;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005911 pci_read_config_word(pdev, PCI_COMMAND, &reg16);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07005912 ivideo->sisvga_enabled = reg16 & 0x01;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005913 ivideo->pcibus = pdev->bus->number;
5914 ivideo->pcislot = PCI_SLOT(pdev->devfn);
5915 ivideo->pcifunc = PCI_FUNC(pdev->devfn);
5916 ivideo->subsysvendor = pdev->subsystem_vendor;
5917 ivideo->subsysdevice = pdev->subsystem_device;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07005918#ifdef SIS_OLD_CONFIG_COMPAT
5919 ivideo->ioctl32registered = 0;
5920#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -07005921
5922#ifndef MODULE
5923 if(sisfb_mode_idx == -1) {
5924 sisfb_get_vga_mode_from_kernel();
5925 }
5926#endif
5927
5928 ivideo->chip = chipinfo->chip;
5929 ivideo->sisvga_engine = chipinfo->vgaengine;
5930 ivideo->hwcursor_size = chipinfo->hwcursor_size;
5931 ivideo->CRT2_write_enable = chipinfo->CRT2_write_enable;
5932 ivideo->mni = chipinfo->mni;
5933
5934 ivideo->detectedpdc = 0xff;
5935 ivideo->detectedpdca = 0xff;
5936 ivideo->detectedlcda = 0xff;
5937
5938 ivideo->sisfb_thismonitor.datavalid = FALSE;
5939
Thomas Winischhofer544393f2005-09-09 13:04:45 -07005940 ivideo->current_base = 0;
5941
5942 ivideo->engineok = 0;
5943
5944 ivideo->sisfb_was_boot_device = 0;
5945#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,12))
5946 if(pdev->resource[PCI_ROM_RESOURCE].flags & IORESOURCE_ROM_SHADOW) {
5947 if(ivideo->sisvga_enabled)
5948 ivideo->sisfb_was_boot_device = 1;
5949 else {
5950 printk(KERN_DEBUG "sisfb: PCI device is disabled, "
5951 "but marked as boot video device ???\n");
5952 printk(KERN_DEBUG "sisfb: I will not accept this "
5953 "as the primary VGA device\n");
5954 }
5955 }
5956#endif
5957
Linus Torvalds1da177e2005-04-16 15:20:36 -07005958 ivideo->sisfb_parm_mem = sisfb_parm_mem;
5959 ivideo->sisfb_accel = sisfb_accel;
5960 ivideo->sisfb_ypan = sisfb_ypan;
5961 ivideo->sisfb_max = sisfb_max;
5962 ivideo->sisfb_userom = sisfb_userom;
5963 ivideo->sisfb_useoem = sisfb_useoem;
5964 ivideo->sisfb_mode_idx = sisfb_mode_idx;
5965 ivideo->sisfb_parm_rate = sisfb_parm_rate;
5966 ivideo->sisfb_crt1off = sisfb_crt1off;
5967 ivideo->sisfb_forcecrt1 = sisfb_forcecrt1;
5968 ivideo->sisfb_crt2type = sisfb_crt2type;
5969 ivideo->sisfb_crt2flags = sisfb_crt2flags;
5970 /* pdc(a), scalelcd, special timing, lvdshl handled below */
5971 ivideo->sisfb_dstn = sisfb_dstn;
5972 ivideo->sisfb_fstn = sisfb_fstn;
5973 ivideo->sisfb_tvplug = sisfb_tvplug;
5974 ivideo->sisfb_tvstd = sisfb_tvstd;
5975 ivideo->tvxpos = sisfb_tvxposoffset;
5976 ivideo->tvypos = sisfb_tvyposoffset;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005977 ivideo->sisfb_nocrt2rate = sisfb_nocrt2rate;
5978#if LINUX_VERSION_CODE <= KERNEL_VERSION(2,5,0)
5979 ivideo->sisfb_inverse = sisfb_inverse;
5980#endif
5981
5982 ivideo->refresh_rate = 0;
5983 if(ivideo->sisfb_parm_rate != -1) {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07005984 ivideo->refresh_rate = ivideo->sisfb_parm_rate;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005985 }
5986
5987 ivideo->SiS_Pr.UsePanelScaler = sisfb_scalelcd;
5988 ivideo->SiS_Pr.CenterScreen = -1;
5989 ivideo->SiS_Pr.SiS_CustomT = sisfb_specialtiming;
5990 ivideo->SiS_Pr.LVDSHL = sisfb_lvdshl;
5991
5992 ivideo->SiS_Pr.SiS_Backup70xx = 0xff;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07005993 ivideo->SiS_Pr.SiS_CHOverScan = -1;
5994 ivideo->SiS_Pr.SiS_ChSW = FALSE;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005995 ivideo->SiS_Pr.SiS_UseLCDA = FALSE;
5996 ivideo->SiS_Pr.HaveEMI = FALSE;
5997 ivideo->SiS_Pr.HaveEMILCD = FALSE;
5998 ivideo->SiS_Pr.OverruleEMI = FALSE;
5999 ivideo->SiS_Pr.SiS_SensibleSR11 = FALSE;
6000 ivideo->SiS_Pr.SiS_MyCR63 = 0x63;
6001 ivideo->SiS_Pr.PDC = -1;
6002 ivideo->SiS_Pr.PDCA = -1;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006003 ivideo->SiS_Pr.DDCPortMixup = FALSE;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006004#ifdef CONFIG_FB_SIS_315
6005 if(ivideo->chip >= SIS_330) {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006006 ivideo->SiS_Pr.SiS_MyCR63 = 0x53;
6007 if(ivideo->chip >= SIS_661) {
6008 ivideo->SiS_Pr.SiS_SensibleSR11 = TRUE;
6009 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07006010 }
6011#endif
6012
6013 memcpy(&ivideo->default_var, &my_default_var, sizeof(my_default_var));
6014
6015 pci_set_drvdata(pdev, ivideo);
6016
6017 /* Patch special cases */
6018 if((ivideo->nbridge = sisfb_get_northbridge(ivideo->chip))) {
6019 switch(ivideo->nbridge->device) {
6020#ifdef CONFIG_FB_SIS_300
6021 case PCI_DEVICE_ID_SI_730:
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006022 ivideo->chip = SIS_730;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006023 strcpy(ivideo->myid, "SiS 730");
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006024 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006025#endif
6026#ifdef CONFIG_FB_SIS_315
6027 case PCI_DEVICE_ID_SI_651:
6028 /* ivideo->chip is ok */
6029 strcpy(ivideo->myid, "SiS 651");
6030 break;
6031 case PCI_DEVICE_ID_SI_740:
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006032 ivideo->chip = SIS_740;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006033 strcpy(ivideo->myid, "SiS 740");
6034 break;
6035 case PCI_DEVICE_ID_SI_661:
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006036 ivideo->chip = SIS_661;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006037 strcpy(ivideo->myid, "SiS 661");
6038 break;
6039 case PCI_DEVICE_ID_SI_741:
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006040 ivideo->chip = SIS_741;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006041 strcpy(ivideo->myid, "SiS 741");
6042 break;
6043 case PCI_DEVICE_ID_SI_760:
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006044 ivideo->chip = SIS_760;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006045 strcpy(ivideo->myid, "SiS 760");
6046 break;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006047 case PCI_DEVICE_ID_SI_761:
6048 ivideo->chip = SIS_761;
6049 strcpy(ivideo->myid, "SiS 761");
6050 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006051#endif
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006052 default:
6053 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006054 }
6055 }
6056
6057#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
6058 strcpy(sis_fb_info->modename, ivideo->myid);
6059#endif
6060
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006061 ivideo->SiS_Pr.ChipType = ivideo->chip;
6062
6063 ivideo->SiS_Pr.ivideo = (void *)ivideo;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006064
6065#ifdef CONFIG_FB_SIS_315
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006066 if((ivideo->SiS_Pr.ChipType == SIS_315PRO) ||
6067 (ivideo->SiS_Pr.ChipType == SIS_315)) {
6068 ivideo->SiS_Pr.ChipType = SIS_315H;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006069 }
6070#endif
6071
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006072 if(!ivideo->sisvga_enabled) {
6073 if(pci_enable_device(pdev)) {
6074 if(ivideo->nbridge) SIS_PCI_PUT_DEVICE(ivideo->nbridge);
6075 pci_set_drvdata(pdev, NULL);
6076 kfree(sis_fb_info);
6077 return -EIO;
6078 }
6079 }
6080
Linus Torvalds1da177e2005-04-16 15:20:36 -07006081 ivideo->video_base = pci_resource_start(pdev, 0);
6082 ivideo->mmio_base = pci_resource_start(pdev, 1);
6083 ivideo->mmio_size = pci_resource_len(pdev, 1);
6084 ivideo->SiS_Pr.RelIO = pci_resource_start(pdev, 2) + 0x30;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006085 ivideo->SiS_Pr.IOAddress = ivideo->vga_base = ivideo->SiS_Pr.RelIO;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006086
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006087 SiSRegInit(&ivideo->SiS_Pr, ivideo->SiS_Pr.IOAddress);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006088
6089#ifdef CONFIG_FB_SIS_300
6090 /* Find PCI systems for Chrontel/GPIO communication setup */
6091 if(ivideo->chip == SIS_630) {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006092 i = 0;
6093 do {
6094 if(mychswtable[i].subsysVendor == ivideo->subsysvendor &&
6095 mychswtable[i].subsysCard == ivideo->subsysdevice) {
6096 ivideo->SiS_Pr.SiS_ChSW = TRUE;
6097 printk(KERN_DEBUG "sisfb: Identified [%s %s] "
6098 "requiring Chrontel/GPIO setup\n",
6099 mychswtable[i].vendorName,
6100 mychswtable[i].cardName);
6101 ivideo->lpcdev = SIS_PCI_GET_DEVICE(PCI_VENDOR_ID_SI, 0x0008, NULL);
6102 break;
6103 }
6104 i++;
6105 } while(mychswtable[i].subsysVendor != 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006106 }
6107#endif
6108
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006109#ifdef CONFIG_FB_SIS_315
6110 if((ivideo->chip == SIS_760) && (ivideo->nbridge)) {
6111 ivideo->lpcdev = SIS_PCI_GET_SLOT(ivideo->nbridge->bus, (2 << 3));
6112 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07006113#endif
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006114
6115 outSISIDXREG(SISSR, 0x05, 0x86);
6116
6117 if( (!ivideo->sisvga_enabled)
6118#if !defined(__i386__) && !defined(__x86_64__)
6119 || (sisfb_resetcard)
6120#endif
6121 ) {
6122 for(i = 0x30; i <= 0x3f; i++) {
6123 outSISIDXREG(SISCR, i, 0x00);
6124 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07006125 }
6126
6127 /* Find out about current video mode */
6128 ivideo->modeprechange = 0x03;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006129 inSISIDXREG(SISCR, 0x34, reg);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006130 if(reg & 0x7f) {
6131 ivideo->modeprechange = reg & 0x7f;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006132 } else if(ivideo->sisvga_enabled) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07006133#if defined(__i386__) || defined(__x86_64__)
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006134 unsigned char SIS_IOTYPE2 *tt = ioremap(0x400, 0x100);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006135 if(tt) {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006136 ivideo->modeprechange = readb(tt + 0x49);
6137 iounmap(tt);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006138 }
6139#endif
6140 }
6141
6142#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
6143#ifdef MODULE
6144 if((reg & 0x80) && (reg != 0xff)) {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006145 if((sisbios_mode[ivideo->sisfb_mode_idx].mode_no[ivideo->mni])
6146 != 0xFF) {
6147 printk(KERN_INFO "sisfb: Cannot initialize display mode, "
6148 "X server is active\n");
6149 ret = -EBUSY;
6150 goto error_4;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006151 }
6152 }
6153#endif
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006154#endif
6155
6156 /* Search and copy ROM image */
6157 ivideo->bios_abase = NULL;
6158 ivideo->SiS_Pr.VirtualRomBase = NULL;
6159 ivideo->SiS_Pr.UseROM = FALSE;
6160 ivideo->haveXGIROM = ivideo->SiS_Pr.SiS_XGIROM = FALSE;
6161 if(ivideo->sisfb_userom) {
6162 ivideo->SiS_Pr.VirtualRomBase = sisfb_find_rom(pdev);
6163 ivideo->bios_abase = ivideo->SiS_Pr.VirtualRomBase;
6164 ivideo->SiS_Pr.UseROM = (ivideo->SiS_Pr.VirtualRomBase) ? TRUE : FALSE;
6165 printk(KERN_INFO "sisfb: Video ROM %sfound\n",
6166 ivideo->SiS_Pr.UseROM ? "" : "not ");
6167 if((ivideo->SiS_Pr.UseROM) && (ivideo->chip >= XGI_20)) {
6168 ivideo->SiS_Pr.UseROM = FALSE;
6169 ivideo->haveXGIROM = ivideo->SiS_Pr.SiS_XGIROM = TRUE;
6170 if( (ivideo->revision_id == 2) &&
6171 (!(ivideo->bios_abase[0x1d1] & 0x01)) ) {
6172 ivideo->SiS_Pr.DDCPortMixup = TRUE;
6173 }
6174 }
6175 } else {
6176 printk(KERN_INFO "sisfb: Video ROM usage disabled\n");
6177 }
6178
6179 /* Find systems for special custom timing */
6180 if(ivideo->SiS_Pr.SiS_CustomT == CUT_NONE) {
6181 sisfb_detect_custom_timing(ivideo);
6182 }
6183
6184 /* POST card in case this has not been done by the BIOS */
6185 if( (!ivideo->sisvga_enabled)
6186#if !defined(__i386__) && !defined(__x86_64__)
6187 || (sisfb_resetcard)
6188#endif
6189 ) {
6190#ifdef CONFIG_FB_SIS_300
6191 if(ivideo->sisvga_engine == SIS_300_VGA) {
6192 if(ivideo->chip == SIS_300) {
6193 sisfb_post_sis300(pdev);
6194 ivideo->sisfb_can_post = 1;
6195 }
6196 }
6197#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -07006198
6199#ifdef CONFIG_FB_SIS_315
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006200 if(ivideo->sisvga_engine == SIS_315_VGA) {
6201 int result = 1;
6202 /* if((ivideo->chip == SIS_315H) ||
Linus Torvalds1da177e2005-04-16 15:20:36 -07006203 (ivideo->chip == SIS_315) ||
6204 (ivideo->chip == SIS_315PRO) ||
6205 (ivideo->chip == SIS_330)) {
6206 sisfb_post_sis315330(pdev);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006207 } else */ if(ivideo->chip == XGI_20) {
6208 result = sisfb_post_xgi(pdev);
6209 ivideo->sisfb_can_post = 1;
6210 } else if((ivideo->chip == XGI_40) && ivideo->haveXGIROM) {
6211 result = sisfb_post_xgi(pdev);
6212 ivideo->sisfb_can_post = 1;
6213 } else {
6214 printk(KERN_INFO "sisfb: Card is not "
6215 "POSTed and sisfb can't do this either.\n");
6216 }
6217 if(!result) {
6218 printk(KERN_ERR "sisfb: Failed to POST card\n");
6219 ret = -ENODEV;
6220 goto error_3;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006221 }
6222 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07006223#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -07006224 }
6225
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006226 ivideo->sisfb_card_posted = 1;
6227
6228 /* Find out about RAM size */
6229 if(sisfb_get_dram_size(ivideo)) {
6230 printk(KERN_INFO "sisfb: Fatal error: Unable to determine VRAM size.\n");
6231 ret = -ENODEV;
6232 goto error_3;
6233 }
6234
6235
6236 /* Enable PCI addressing and MMIO */
Linus Torvalds1da177e2005-04-16 15:20:36 -07006237 if((ivideo->sisfb_mode_idx < 0) ||
6238 ((sisbios_mode[ivideo->sisfb_mode_idx].mode_no[ivideo->mni]) != 0xFF)) {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006239 /* Enable PCI_LINEAR_ADDRESSING and MMIO_ENABLE */
6240 orSISIDXREG(SISSR, IND_SIS_PCI_ADDRESS_SET, (SIS_PCI_ADDR_ENABLE | SIS_MEM_MAP_IO_ENABLE));
6241 /* Enable 2D accelerator engine */
6242 orSISIDXREG(SISSR, IND_SIS_MODULE_ENABLE, SIS_ENABLE_2D);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006243 }
6244
6245 if(sisfb_pdc != 0xff) {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006246 if(ivideo->sisvga_engine == SIS_300_VGA)
6247 sisfb_pdc &= 0x3c;
6248 else
6249 sisfb_pdc &= 0x1f;
6250 ivideo->SiS_Pr.PDC = sisfb_pdc;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006251 }
6252#ifdef CONFIG_FB_SIS_315
6253 if(ivideo->sisvga_engine == SIS_315_VGA) {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006254 if(sisfb_pdca != 0xff)
6255 ivideo->SiS_Pr.PDCA = sisfb_pdca & 0x1f;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006256 }
6257#endif
6258
6259 if(!request_mem_region(ivideo->video_base, ivideo->video_size, "sisfb FB")) {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006260 printk(KERN_ERR "sisfb: Fatal error: Unable to reserve %dMB framebuffer memory\n",
6261 (int)(ivideo->video_size >> 20));
Linus Torvalds1da177e2005-04-16 15:20:36 -07006262 printk(KERN_ERR "sisfb: Is there another framebuffer driver active?\n");
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006263 ret = -ENODEV;
6264 goto error_3;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006265 }
6266
6267 if(!request_mem_region(ivideo->mmio_base, ivideo->mmio_size, "sisfb MMIO")) {
6268 printk(KERN_ERR "sisfb: Fatal error: Unable to reserve MMIO region\n");
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006269 ret = -ENODEV;
6270 goto error_2;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006271 }
6272
6273 ivideo->video_vbase = ioremap(ivideo->video_base, ivideo->video_size);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006274 ivideo->SiS_Pr.VideoMemoryAddress = ivideo->video_vbase;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006275 if(!ivideo->video_vbase) {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006276 printk(KERN_ERR "sisfb: Fatal error: Unable to map framebuffer memory\n");
6277 ret = -ENODEV;
6278 goto error_1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006279 }
6280
6281 ivideo->mmio_vbase = ioremap(ivideo->mmio_base, ivideo->mmio_size);
6282 if(!ivideo->mmio_vbase) {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006283 printk(KERN_ERR "sisfb: Fatal error: Unable to map MMIO region\n");
6284 ret = -ENODEV;
6285error_0: iounmap(ivideo->video_vbase);
6286error_1: release_mem_region(ivideo->video_base, ivideo->video_size);
6287error_2: release_mem_region(ivideo->mmio_base, ivideo->mmio_size);
6288error_3: vfree(ivideo->bios_abase);
6289#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
6290error_4:
6291#endif
6292 if(ivideo->lpcdev)
6293 SIS_PCI_PUT_DEVICE(ivideo->lpcdev);
6294 if(ivideo->nbridge)
6295 SIS_PCI_PUT_DEVICE(ivideo->nbridge);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006296 pci_set_drvdata(pdev, NULL);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006297 if(!ivideo->sisvga_enabled)
6298 pci_disable_device(pdev);
6299 kfree(sis_fb_info);
6300 return ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006301 }
6302
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006303 printk(KERN_INFO "sisfb: Video RAM at 0x%lx, mapped to 0x%lx, size %ldk\n",
6304 ivideo->video_base, (unsigned long)ivideo->video_vbase, ivideo->video_size / 1024);
6305
6306 if(ivideo->video_offset) {
6307 printk(KERN_INFO "sisfb: Viewport offset %ldk\n",
6308 ivideo->video_offset / 1024);
6309 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07006310
6311 printk(KERN_INFO "sisfb: MMIO at 0x%lx, mapped to 0x%lx, size %ldk\n",
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006312 ivideo->mmio_base, (unsigned long)ivideo->mmio_vbase, ivideo->mmio_size / 1024);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006313
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006314
6315 /* Determine the size of the command queue */
6316 if(ivideo->sisvga_engine == SIS_300_VGA) {
6317 ivideo->cmdQueueSize = TURBO_QUEUE_AREA_SIZE;
6318 } else {
6319 if(ivideo->chip == XGI_20) {
6320 ivideo->cmdQueueSize = COMMAND_QUEUE_AREA_SIZE_Z7;
6321 } else {
6322 ivideo->cmdQueueSize = COMMAND_QUEUE_AREA_SIZE;
6323 }
6324 }
6325
6326 /* Engines are no longer initialized here; this is
6327 * now done after the first mode-switch (if the
6328 * submitted var has its acceleration flags set).
6329 */
6330
6331 /* Calculate the base of the (unused) hw cursor */
6332 ivideo->hwcursor_vbase = ivideo->video_vbase
6333 + ivideo->video_size
6334 - ivideo->cmdQueueSize
6335 - ivideo->hwcursor_size;
6336 ivideo->caps |= HW_CURSOR_CAP;
6337
6338 /* Initialize offscreen memory manager */
Linus Torvalds1da177e2005-04-16 15:20:36 -07006339 if((ivideo->havenoheap = sisfb_heap_init(ivideo))) {
6340 printk(KERN_WARNING "sisfb: Failed to initialize offscreen memory heap\n");
6341 }
6342
6343 /* Used for clearing the screen only, therefore respect our mem limit */
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006344 ivideo->SiS_Pr.VideoMemoryAddress += ivideo->video_offset;
6345 ivideo->SiS_Pr.VideoMemorySize = ivideo->sisfb_mem;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006346
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006347 ivideo->mtrr = -1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006348
6349 ivideo->vbflags = 0;
6350 ivideo->lcddefmodeidx = DEFAULT_LCDMODE;
6351 ivideo->tvdefmodeidx = DEFAULT_TVMODE;
6352 ivideo->defmodeidx = DEFAULT_MODE;
6353
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006354 ivideo->newrom = 0;
6355 if(ivideo->chip < XGI_20) {
6356 if(ivideo->bios_abase) {
6357 ivideo->newrom = SiSDetermineROMLayout661(&ivideo->SiS_Pr);
6358 }
6359 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07006360
6361 if((ivideo->sisfb_mode_idx < 0) ||
6362 ((sisbios_mode[ivideo->sisfb_mode_idx].mode_no[ivideo->mni]) != 0xFF)) {
6363
6364 sisfb_sense_crt1(ivideo);
6365
6366 sisfb_get_VB_type(ivideo);
6367
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006368 if(ivideo->vbflags2 & VB2_VIDEOBRIDGE) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07006369 sisfb_detect_VB_connect(ivideo);
6370 }
6371
6372 ivideo->currentvbflags = ivideo->vbflags & (VB_VIDEOBRIDGE | TV_STANDARD);
6373
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006374 /* Decide on which CRT2 device to use */
6375 if(ivideo->vbflags2 & VB2_VIDEOBRIDGE) {
6376 if(ivideo->sisfb_crt2type != -1) {
6377 if((ivideo->sisfb_crt2type == CRT2_LCD) &&
6378 (ivideo->vbflags & CRT2_LCD)) {
6379 ivideo->currentvbflags |= CRT2_LCD;
6380 } else if(ivideo->sisfb_crt2type != CRT2_LCD) {
6381 ivideo->currentvbflags |= ivideo->sisfb_crt2type;
6382 }
6383 } else {
6384 /* Chrontel 700x TV detection often unreliable, therefore
6385 * use a different default order on such machines
6386 */
6387 if((ivideo->sisvga_engine == SIS_300_VGA) &&
6388 (ivideo->vbflags2 & VB2_CHRONTEL)) {
6389 if(ivideo->vbflags & CRT2_LCD)
6390 ivideo->currentvbflags |= CRT2_LCD;
6391 else if(ivideo->vbflags & CRT2_TV)
6392 ivideo->currentvbflags |= CRT2_TV;
6393 else if(ivideo->vbflags & CRT2_VGA)
6394 ivideo->currentvbflags |= CRT2_VGA;
6395 } else {
6396 if(ivideo->vbflags & CRT2_TV)
6397 ivideo->currentvbflags |= CRT2_TV;
6398 else if(ivideo->vbflags & CRT2_LCD)
6399 ivideo->currentvbflags |= CRT2_LCD;
6400 else if(ivideo->vbflags & CRT2_VGA)
6401 ivideo->currentvbflags |= CRT2_VGA;
6402 }
6403 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07006404 }
6405
6406 if(ivideo->vbflags & CRT2_LCD) {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006407 sisfb_detect_lcd_type(ivideo);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006408 }
6409
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006410 sisfb_save_pdc_emi(ivideo);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006411
6412 if(!ivideo->sisfb_crt1off) {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006413 sisfb_handle_ddc(ivideo, &ivideo->sisfb_thismonitor, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006414 } else {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006415 if((ivideo->vbflags2 & VB2_SISTMDSBRIDGE) &&
6416 (ivideo->vbflags & (CRT2_VGA | CRT2_LCD))) {
6417 sisfb_handle_ddc(ivideo, &ivideo->sisfb_thismonitor, 1);
6418 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07006419 }
6420
6421 if(ivideo->sisfb_mode_idx >= 0) {
6422 int bu = ivideo->sisfb_mode_idx;
6423 ivideo->sisfb_mode_idx = sisfb_validate_mode(ivideo,
6424 ivideo->sisfb_mode_idx, ivideo->currentvbflags);
6425 if(bu != ivideo->sisfb_mode_idx) {
6426 printk(KERN_ERR "Mode %dx%dx%d failed validation\n",
6427 sisbios_mode[bu].xres,
6428 sisbios_mode[bu].yres,
6429 sisbios_mode[bu].bpp);
6430 }
6431 }
6432
6433 if(ivideo->sisfb_mode_idx < 0) {
6434 switch(ivideo->currentvbflags & VB_DISPTYPE_DISP2) {
6435 case CRT2_LCD:
6436 ivideo->sisfb_mode_idx = ivideo->lcddefmodeidx;
6437 break;
6438 case CRT2_TV:
6439 ivideo->sisfb_mode_idx = ivideo->tvdefmodeidx;
6440 break;
6441 default:
6442 ivideo->sisfb_mode_idx = ivideo->defmodeidx;
6443 break;
6444 }
6445 }
6446
6447 ivideo->mode_no = sisbios_mode[ivideo->sisfb_mode_idx].mode_no[ivideo->mni];
6448
6449 if(ivideo->refresh_rate != 0) {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006450 sisfb_search_refresh_rate(ivideo, ivideo->refresh_rate,
6451 ivideo->sisfb_mode_idx);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006452 }
6453
6454 if(ivideo->rate_idx == 0) {
6455 ivideo->rate_idx = sisbios_mode[ivideo->sisfb_mode_idx].rate_idx;
6456 ivideo->refresh_rate = 60;
6457 }
6458
6459 if(ivideo->sisfb_thismonitor.datavalid) {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006460 if(!sisfb_verify_rate(ivideo, &ivideo->sisfb_thismonitor,
6461 ivideo->sisfb_mode_idx,
6462 ivideo->rate_idx,
6463 ivideo->refresh_rate)) {
6464 printk(KERN_INFO "sisfb: WARNING: Refresh rate "
6465 "exceeds monitor specs!\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07006466 }
6467 }
6468
6469 ivideo->video_bpp = sisbios_mode[ivideo->sisfb_mode_idx].bpp;
6470 ivideo->video_width = sisbios_mode[ivideo->sisfb_mode_idx].xres;
6471 ivideo->video_height = sisbios_mode[ivideo->sisfb_mode_idx].yres;
6472
6473 sisfb_set_vparms(ivideo);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006474
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006475#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
6476
6477 /* ---------------- For 2.4: Now switch the mode ------------------ */
6478
6479 printk(KERN_INFO "sisfb: Setting mode %dx%dx%d (%dHz)\n",
6480 ivideo->video_width, ivideo->video_height, ivideo->video_bpp,
Linus Torvalds1da177e2005-04-16 15:20:36 -07006481 ivideo->refresh_rate);
6482
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006483 /* Determine whether or not acceleration is to be
6484 * used. Need to know before pre/post_set_mode()
6485 */
6486 ivideo->accel = 0;
6487 ivideo->default_var.accel_flags &= ~FB_ACCELF_TEXT;
6488 if(ivideo->sisfb_accel) {
6489 ivideo->accel = -1;
6490 ivideo->default_var.accel_flags |= FB_ACCELF_TEXT;
6491 }
6492
6493 /* Now switch the mode */
Linus Torvalds1da177e2005-04-16 15:20:36 -07006494 sisfb_pre_setmode(ivideo);
6495
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006496 if(SiSSetMode(&ivideo->SiS_Pr, ivideo->mode_no) == 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07006497 printk(KERN_ERR "sisfb: Fatal error: Setting mode[0x%x] failed\n",
6498 ivideo->mode_no);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006499 ret = -EINVAL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006500 iounmap(ivideo->mmio_vbase);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006501 goto error_0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006502 }
6503
6504 outSISIDXREG(SISSR, IND_SIS_PASSWORD, SIS_PASSWORD);
6505
6506 sisfb_post_setmode(ivideo);
6507
6508 /* Maximize regardless of sisfb_max at startup */
6509 ivideo->default_var.yres_virtual = 32767;
6510
6511 /* Force reset of x virtual in crtc_to_var */
6512 ivideo->default_var.xres_virtual = 0;
6513
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006514 /* Copy mode timing to var */
Linus Torvalds1da177e2005-04-16 15:20:36 -07006515 sisfb_crtc_to_var(ivideo, &ivideo->default_var);
6516
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006517 /* Find out about screen pitch */
Linus Torvalds1da177e2005-04-16 15:20:36 -07006518 sisfb_calc_pitch(ivideo, &ivideo->default_var);
6519 sisfb_set_pitch(ivideo);
6520
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006521 /* Init the accelerator (does nothing currently) */
Linus Torvalds1da177e2005-04-16 15:20:36 -07006522 sisfb_initaccel(ivideo);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006523
6524 /* Init some fbinfo entries */
Linus Torvalds1da177e2005-04-16 15:20:36 -07006525 sis_fb_info->node = -1;
6526 sis_fb_info->flags = FBINFO_FLAG_DEFAULT;
6527 sis_fb_info->fbops = &sisfb_ops;
6528 sis_fb_info->disp = &ivideo->sis_disp;
6529 sis_fb_info->blank = &sisfb_blank;
6530 sis_fb_info->switch_con = &sisfb_switch;
6531 sis_fb_info->updatevar = &sisfb_update_var;
6532 sis_fb_info->changevar = NULL;
6533 strcpy(sis_fb_info->fontname, sisfb_fontname);
6534
6535 sisfb_set_disp(-1, &ivideo->default_var, sis_fb_info);
6536
6537#else /* --------- For 2.6: Setup a somewhat sane default var ------------ */
6538
6539 printk(KERN_INFO "sisfb: Default mode is %dx%dx%d (%dHz)\n",
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006540 ivideo->video_width, ivideo->video_height, ivideo->video_bpp,
Linus Torvalds1da177e2005-04-16 15:20:36 -07006541 ivideo->refresh_rate);
6542
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006543 /* Set up the default var according to chosen default display mode */
Linus Torvalds1da177e2005-04-16 15:20:36 -07006544 ivideo->default_var.xres = ivideo->default_var.xres_virtual = ivideo->video_width;
6545 ivideo->default_var.yres = ivideo->default_var.yres_virtual = ivideo->video_height;
6546 ivideo->default_var.bits_per_pixel = ivideo->video_bpp;
6547
6548 sisfb_bpp_to_var(ivideo, &ivideo->default_var);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006549
Linus Torvalds1da177e2005-04-16 15:20:36 -07006550 ivideo->default_var.pixclock = (u32) (1000000000 /
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006551 sisfb_mode_rate_to_dclock(&ivideo->SiS_Pr, ivideo->mode_no, ivideo->rate_idx));
6552
6553 if(sisfb_mode_rate_to_ddata(&ivideo->SiS_Pr, ivideo->mode_no,
6554 ivideo->rate_idx, &ivideo->default_var)) {
6555 if((ivideo->default_var.vmode & FB_VMODE_MASK) == FB_VMODE_DOUBLE) {
6556 ivideo->default_var.pixclock <<= 1;
6557 }
6558 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07006559
6560 if(ivideo->sisfb_ypan) {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006561 /* Maximize regardless of sisfb_max at startup */
6562 ivideo->default_var.yres_virtual =
6563 sisfb_calc_maxyres(ivideo, &ivideo->default_var);
6564 if(ivideo->default_var.yres_virtual < ivideo->default_var.yres) {
6565 ivideo->default_var.yres_virtual = ivideo->default_var.yres;
6566 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07006567 }
6568
6569 sisfb_calc_pitch(ivideo, &ivideo->default_var);
6570
6571 ivideo->accel = 0;
6572 if(ivideo->sisfb_accel) {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006573 ivideo->accel = -1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006574#ifdef STUPID_ACCELF_TEXT_SHIT
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006575 ivideo->default_var.accel_flags |= FB_ACCELF_TEXT;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006576#endif
6577 }
6578 sisfb_initaccel(ivideo);
6579
6580#if defined(FBINFO_HWACCEL_DISABLED) && defined(FBINFO_HWACCEL_XPAN)
6581 sis_fb_info->flags = FBINFO_DEFAULT |
6582 FBINFO_HWACCEL_YPAN |
6583 FBINFO_HWACCEL_XPAN |
6584 FBINFO_HWACCEL_COPYAREA |
6585 FBINFO_HWACCEL_FILLRECT |
6586 ((ivideo->accel) ? 0 : FBINFO_HWACCEL_DISABLED);
6587#else
6588 sis_fb_info->flags = FBINFO_FLAG_DEFAULT;
6589#endif
6590 sis_fb_info->var = ivideo->default_var;
6591 sis_fb_info->fix = ivideo->sisfb_fix;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006592 sis_fb_info->screen_base = ivideo->video_vbase + ivideo->video_offset;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006593 sis_fb_info->fbops = &sisfb_ops;
6594
6595 sisfb_get_fix(&sis_fb_info->fix, -1, sis_fb_info);
6596 sis_fb_info->pseudo_palette = ivideo->pseudo_palette;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006597
Linus Torvalds1da177e2005-04-16 15:20:36 -07006598 fb_alloc_cmap(&sis_fb_info->cmap, 256 , 0);
6599#endif /* 2.6 */
6600
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006601 printk(KERN_DEBUG "sisfb: Initial vbflags 0x%x\n", (int)ivideo->vbflags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006602
6603#ifdef CONFIG_MTRR
6604 ivideo->mtrr = mtrr_add(ivideo->video_base, ivideo->video_size,
6605 MTRR_TYPE_WRCOMB, 1);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006606 if(ivideo->mtrr < 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07006607 printk(KERN_DEBUG "sisfb: Failed to add MTRRs\n");
6608 }
6609#endif
6610
6611#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
6612 vc_resize_con(1, 1, 0);
6613#endif
6614
6615 if(register_framebuffer(sis_fb_info) < 0) {
6616 printk(KERN_ERR "sisfb: Fatal error: Failed to register framebuffer\n");
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006617 ret = -EINVAL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006618 iounmap(ivideo->mmio_vbase);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006619 goto error_0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006620 }
6621
6622 ivideo->registered = 1;
6623
6624 /* Enlist us */
6625 ivideo->next = card_list;
6626 card_list = ivideo;
6627
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006628#ifdef SIS_OLD_CONFIG_COMPAT
6629 {
6630 int ret;
6631 /* Our ioctls are all "32/64bit compatible" */
6632 ret = register_ioctl32_conversion(FBIO_ALLOC, NULL);
6633 ret |= register_ioctl32_conversion(FBIO_FREE, NULL);
6634 ret |= register_ioctl32_conversion(FBIOGET_VBLANK, NULL);
6635 ret |= register_ioctl32_conversion(SISFB_GET_INFO_SIZE, NULL);
6636 ret |= register_ioctl32_conversion(SISFB_GET_INFO, NULL);
6637 ret |= register_ioctl32_conversion(SISFB_GET_TVPOSOFFSET, NULL);
6638 ret |= register_ioctl32_conversion(SISFB_SET_TVPOSOFFSET, NULL);
6639 ret |= register_ioctl32_conversion(SISFB_SET_LOCK, NULL);
6640 ret |= register_ioctl32_conversion(SISFB_GET_VBRSTATUS, NULL);
6641 ret |= register_ioctl32_conversion(SISFB_GET_AUTOMAXIMIZE, NULL);
6642 ret |= register_ioctl32_conversion(SISFB_SET_AUTOMAXIMIZE, NULL);
6643 ret |= register_ioctl32_conversion(SISFB_COMMAND, NULL);
6644 if(ret)
6645 printk(KERN_ERR
6646 "sisfb: Error registering ioctl32 translations\n");
6647 else
6648 ivideo->ioctl32registered = 1;
6649 }
6650#endif
6651
Linus Torvalds1da177e2005-04-16 15:20:36 -07006652 printk(KERN_INFO "sisfb: 2D acceleration is %s, y-panning %s\n",
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006653 ivideo->sisfb_accel ? "enabled" : "disabled",
6654 ivideo->sisfb_ypan ?
6655 (ivideo->sisfb_max ? "enabled (auto-max)" :
6656 "enabled (no auto-max)") :
6657 "disabled");
Linus Torvalds1da177e2005-04-16 15:20:36 -07006658
6659
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006660 printk(KERN_INFO "fb%d: %s frame buffer device version %d.%d.%d\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07006661#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006662 GET_FB_IDX(sis_fb_info->node),
Linus Torvalds1da177e2005-04-16 15:20:36 -07006663#else
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006664 sis_fb_info->node,
Linus Torvalds1da177e2005-04-16 15:20:36 -07006665#endif
6666 ivideo->myid, VER_MAJOR, VER_MINOR, VER_LEVEL);
6667
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006668 printk(KERN_INFO "sisfb: Copyright (C) 2001-2005 Thomas Winischhofer\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07006669
6670 } /* if mode = "none" */
6671
6672 return 0;
6673}
6674
6675/*****************************************************/
6676/* PCI DEVICE HANDLING */
6677/*****************************************************/
6678
6679static void __devexit sisfb_remove(struct pci_dev *pdev)
6680{
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006681 struct sis_video_info *ivideo = pci_get_drvdata(pdev);
6682 struct fb_info *sis_fb_info = ivideo->memyselfandi;
6683 int registered = ivideo->registered;
6684 int modechanged = ivideo->modechanged;
6685
6686#ifdef SIS_OLD_CONFIG_COMPAT
6687 if(ivideo->ioctl32registered) {
6688 int ret;
6689 ret = unregister_ioctl32_conversion(FBIO_ALLOC);
6690 ret |= unregister_ioctl32_conversion(FBIO_FREE);
6691 ret |= unregister_ioctl32_conversion(FBIOGET_VBLANK);
6692 ret |= unregister_ioctl32_conversion(SISFB_GET_INFO_SIZE);
6693 ret |= unregister_ioctl32_conversion(SISFB_GET_INFO);
6694 ret |= unregister_ioctl32_conversion(SISFB_GET_TVPOSOFFSET);
6695 ret |= unregister_ioctl32_conversion(SISFB_SET_TVPOSOFFSET);
6696 ret |= unregister_ioctl32_conversion(SISFB_SET_LOCK);
6697 ret |= unregister_ioctl32_conversion(SISFB_GET_VBRSTATUS);
6698 ret |= unregister_ioctl32_conversion(SISFB_GET_AUTOMAXIMIZE);
6699 ret |= unregister_ioctl32_conversion(SISFB_SET_AUTOMAXIMIZE);
6700 ret |= unregister_ioctl32_conversion(SISFB_COMMAND);
6701 if(ret)
6702 printk(KERN_ERR
6703 "sisfb: Error unregistering ioctl32 translations\n");
6704 }
6705#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -07006706
6707 /* Unmap */
Linus Torvalds1da177e2005-04-16 15:20:36 -07006708 iounmap(ivideo->mmio_vbase);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006709 iounmap(ivideo->video_vbase);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006710
6711 /* Release mem regions */
6712 release_mem_region(ivideo->video_base, ivideo->video_size);
6713 release_mem_region(ivideo->mmio_base, ivideo->mmio_size);
6714
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006715 vfree(ivideo->bios_abase);
6716
6717 if(ivideo->lpcdev)
6718 SIS_PCI_PUT_DEVICE(ivideo->lpcdev);
6719
6720 if(ivideo->nbridge)
6721 SIS_PCI_PUT_DEVICE(ivideo->nbridge);
6722
Linus Torvalds1da177e2005-04-16 15:20:36 -07006723#ifdef CONFIG_MTRR
6724 /* Release MTRR region */
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006725 if(ivideo->mtrr >= 0)
Linus Torvalds1da177e2005-04-16 15:20:36 -07006726 mtrr_del(ivideo->mtrr, ivideo->video_base, ivideo->video_size);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006727#endif
6728
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006729 pci_set_drvdata(pdev, NULL);
6730
6731 /* If device was disabled when starting, disable
6732 * it when quitting.
6733 */
6734 if(!ivideo->sisvga_enabled)
6735 pci_disable_device(pdev);
6736
Linus Torvalds1da177e2005-04-16 15:20:36 -07006737 /* Unregister the framebuffer */
6738 if(ivideo->registered) {
6739 unregister_framebuffer(sis_fb_info);
6740#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,3))
6741 framebuffer_release(sis_fb_info);
6742#else
6743 kfree(sis_fb_info);
6744#endif
6745 }
6746
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006747 /* OK, our ivideo is gone for good from here. */
Linus Torvalds1da177e2005-04-16 15:20:36 -07006748
6749 /* TODO: Restore the initial mode
6750 * This sounds easy but is as good as impossible
6751 * on many machines with SiS chip and video bridge
6752 * since text modes are always set up differently
6753 * from machine to machine. Depends on the type
6754 * of integration between chipset and bridge.
6755 */
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006756 if(registered && modechanged)
6757 printk(KERN_INFO
6758 "sisfb: Restoring of text mode not supported yet\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07006759};
6760
6761static struct pci_driver sisfb_driver = {
6762 .name = "sisfb",
6763 .id_table = sisfb_pci_table,
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006764 .probe = sisfb_probe,
Linus Torvalds1da177e2005-04-16 15:20:36 -07006765 .remove = __devexit_p(sisfb_remove)
6766};
6767
6768SISINITSTATIC int __init sisfb_init(void)
6769{
6770#if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,8)
6771#ifndef MODULE
6772 char *options = NULL;
6773
6774 if(fb_get_options("sisfb", &options))
6775 return -ENODEV;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006776
Linus Torvalds1da177e2005-04-16 15:20:36 -07006777 sisfb_setup(options);
6778#endif
6779#endif
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006780 return pci_register_driver(&sisfb_driver);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006781}
6782
6783#if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,8)
6784#ifndef MODULE
6785module_init(sisfb_init);
6786#endif
6787#endif
6788
6789/*****************************************************/
6790/* MODULE */
6791/*****************************************************/
6792
6793#ifdef MODULE
6794
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006795static char *mode = NULL;
6796static int vesa = -1;
6797static unsigned int rate = 0;
6798static unsigned int crt1off = 1;
6799static unsigned int mem = 0;
6800static char *forcecrt2type = NULL;
6801static int forcecrt1 = -1;
6802static int pdc = -1;
6803static int pdc1 = -1;
6804static int noaccel = -1;
6805static int noypan = -1;
6806static int nomax = -1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006807#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006808static int inverse = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006809#endif
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006810static int userom = -1;
6811static int useoem = -1;
6812static char *tvstandard = NULL;
6813static int nocrt2rate = 0;
6814static int scalelcd = -1;
6815static char *specialtiming = NULL;
6816static int lvdshl = -1;
6817static int tvxposoffset = 0, tvyposoffset = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006818#if !defined(__i386__) && !defined(__x86_64__)
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006819static int resetcard = 0;
6820static int videoram = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006821#endif
6822
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006823static int __init sisfb_init_module(void)
6824{
6825 sisfb_setdefaultparms();
6826
6827 if(rate)
6828 sisfb_parm_rate = rate;
6829
6830 if((scalelcd == 0) || (scalelcd == 1))
6831 sisfb_scalelcd = scalelcd ^ 1;
6832
6833 /* Need to check crt2 type first for fstn/dstn */
6834
6835 if(forcecrt2type)
6836 sisfb_search_crt2type(forcecrt2type);
6837
6838 if(tvstandard)
6839 sisfb_search_tvstd(tvstandard);
6840
6841 if(mode)
6842 sisfb_search_mode(mode, FALSE);
6843 else if(vesa != -1)
6844 sisfb_search_vesamode(vesa, FALSE);
6845
6846 sisfb_crt1off = (crt1off == 0) ? 1 : 0;
6847
6848 sisfb_forcecrt1 = forcecrt1;
6849 if(forcecrt1 == 1)
6850 sisfb_crt1off = 0;
6851 else if(forcecrt1 == 0)
6852 sisfb_crt1off = 1;
6853
6854 if(noaccel == 1)
6855 sisfb_accel = 0;
6856 else if(noaccel == 0)
6857 sisfb_accel = 1;
6858
6859 if(noypan == 1)
6860 sisfb_ypan = 0;
6861 else if(noypan == 0)
6862 sisfb_ypan = 1;
6863
6864 if(nomax == 1)
6865 sisfb_max = 0;
6866 else if(nomax == 0)
6867 sisfb_max = 1;
6868
6869#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
6870 if(inverse) sisfb_inverse = 1;
6871#endif
6872
6873 if(mem)
6874 sisfb_parm_mem = mem;
6875
6876 if(userom != -1)
6877 sisfb_userom = userom;
6878
6879 if(useoem != -1)
6880 sisfb_useoem = useoem;
6881
6882 if(pdc != -1)
6883 sisfb_pdc = (pdc & 0x7f);
6884
6885 if(pdc1 != -1)
6886 sisfb_pdca = (pdc1 & 0x1f);
6887
6888 sisfb_nocrt2rate = nocrt2rate;
6889
6890 if(specialtiming)
6891 sisfb_search_specialtiming(specialtiming);
6892
6893 if((lvdshl >= 0) && (lvdshl <= 3))
6894 sisfb_lvdshl = lvdshl;
6895
6896 sisfb_tvxposoffset = tvxposoffset;
6897 sisfb_tvyposoffset = tvyposoffset;
6898
6899#if !defined(__i386__) && !defined(__x86_64__)
6900 sisfb_resetcard = (resetcard) ? 1 : 0;
6901 if(videoram)
6902 sisfb_videoram = videoram;
6903#endif
6904
6905 return sisfb_init();
6906}
6907
6908static void __exit sisfb_remove_module(void)
6909{
6910 pci_unregister_driver(&sisfb_driver);
6911 printk(KERN_DEBUG "sisfb: Module unloaded\n");
6912}
6913
6914module_init(sisfb_init_module);
6915module_exit(sisfb_remove_module);
6916
6917MODULE_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 -07006918MODULE_LICENSE("GPL");
6919MODULE_AUTHOR("Thomas Winischhofer <thomas@winischhofer.net>, Others");
6920
6921#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
6922MODULE_PARM(mem, "i");
6923MODULE_PARM(noaccel, "i");
6924MODULE_PARM(noypan, "i");
6925MODULE_PARM(nomax, "i");
6926MODULE_PARM(userom, "i");
6927MODULE_PARM(useoem, "i");
6928MODULE_PARM(mode, "s");
6929MODULE_PARM(vesa, "i");
6930MODULE_PARM(rate, "i");
6931MODULE_PARM(forcecrt1, "i");
6932MODULE_PARM(forcecrt2type, "s");
6933MODULE_PARM(scalelcd, "i");
6934MODULE_PARM(pdc, "i");
6935MODULE_PARM(pdc1, "i");
6936MODULE_PARM(specialtiming, "s");
6937MODULE_PARM(lvdshl, "i");
6938MODULE_PARM(tvstandard, "s");
6939MODULE_PARM(tvxposoffset, "i");
6940MODULE_PARM(tvyposoffset, "i");
Linus Torvalds1da177e2005-04-16 15:20:36 -07006941MODULE_PARM(nocrt2rate, "i");
6942MODULE_PARM(inverse, "i");
6943#if !defined(__i386__) && !defined(__x86_64__)
6944MODULE_PARM(resetcard, "i");
6945MODULE_PARM(videoram, "i");
6946#endif
6947#endif
6948
6949#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0)
6950module_param(mem, int, 0);
6951module_param(noaccel, int, 0);
6952module_param(noypan, int, 0);
6953module_param(nomax, int, 0);
6954module_param(userom, int, 0);
6955module_param(useoem, int, 0);
6956module_param(mode, charp, 0);
6957module_param(vesa, int, 0);
6958module_param(rate, int, 0);
6959module_param(forcecrt1, int, 0);
6960module_param(forcecrt2type, charp, 0);
6961module_param(scalelcd, int, 0);
6962module_param(pdc, int, 0);
6963module_param(pdc1, int, 0);
6964module_param(specialtiming, charp, 0);
6965module_param(lvdshl, int, 0);
6966module_param(tvstandard, charp, 0);
6967module_param(tvxposoffset, int, 0);
6968module_param(tvyposoffset, int, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006969module_param(nocrt2rate, int, 0);
6970#if !defined(__i386__) && !defined(__x86_64__)
6971module_param(resetcard, int, 0);
6972module_param(videoram, int, 0);
6973#endif
6974#endif
6975
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006976#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
Linus Torvalds1da177e2005-04-16 15:20:36 -07006977MODULE_PARM_DESC(mem,
6978 "\nDetermines the beginning of the video memory heap in KB. This heap is used\n"
6979 "for video RAM management for eg. DRM/DRI. On 300 series, the default depends\n"
6980 "on the amount of video RAM available. If 8MB of video RAM or less is available,\n"
6981 "the heap starts at 4096KB, if between 8 and 16MB are available at 8192KB,\n"
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006982 "otherwise at 12288KB. On 315/330/340 series, the heap size is 32KB by default.\n"
Linus Torvalds1da177e2005-04-16 15:20:36 -07006983 "The value is to be specified without 'KB' and must match the MaxXFBMem setting\n"
6984 "for XFree86 4.x/X.org 6.7 and later.\n");
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006985#else
6986MODULE_PARM_DESC(mem,
6987 "\nDetermines the beginning of the video memory heap in KB. This heap is used\n"
6988 "for video RAM management for eg. DRM/DRI. On 300 series, the default depends\n"
6989 "on the amount of video RAM available. If 8MB of video RAM or less is available,\n"
6990 "the heap starts at 4096KB, if between 8 and 16MB are available at 8192KB,\n"
6991 "otherwise at 12288KB. On 315/330/340 series, the heap size is 32KB by default.\n"
6992 "The value is to be specified without 'KB'.\n");
6993#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -07006994
6995MODULE_PARM_DESC(noaccel,
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006996 "\nIf set to anything other than 0, 2D acceleration will be disabled.\n"
Linus Torvalds1da177e2005-04-16 15:20:36 -07006997 "(default: 0)\n");
6998
6999MODULE_PARM_DESC(noypan,
Thomas Winischhofer544393f2005-09-09 13:04:45 -07007000 "\nIf set to anything other than 0, y-panning will be disabled and scrolling\n"
7001 "will be performed by redrawing the screen. (default: 0)\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07007002
7003MODULE_PARM_DESC(nomax,
Thomas Winischhofer544393f2005-09-09 13:04:45 -07007004 "\nIf y-panning is enabled, sisfb will by default use the entire available video\n"
Linus Torvalds1da177e2005-04-16 15:20:36 -07007005 "memory for the virtual screen in order to optimize scrolling performance. If\n"
7006 "this is set to anything other than 0, sisfb will not do this and thereby \n"
7007 "enable the user to positively specify a virtual Y size of the screen using\n"
7008 "fbset. (default: 0)\n");
7009
7010#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
7011MODULE_PARM_DESC(mode,
Thomas Winischhofer544393f2005-09-09 13:04:45 -07007012 "\nSelects the desired display mode in the format [X]x[Y]x[Depth], eg.\n"
7013 "1024x768x16. Other formats supported include XxY-Depth and\n"
7014 "XxY-Depth@Rate. If the parameter is only one (decimal or hexadecimal)\n"
Linus Torvalds1da177e2005-04-16 15:20:36 -07007015 "number, it will be interpreted as a VESA mode number. (default: none if\n"
7016 "sisfb is a module; this leaves the console untouched and the driver will\n"
7017 "only do the video memory management for eg. DRM/DRI; 800x600x8 if sisfb\n"
7018 "is in the kernel)\n");
7019MODULE_PARM_DESC(vesa,
Thomas Winischhofer544393f2005-09-09 13:04:45 -07007020 "\nSelects the desired display mode by VESA defined mode number, eg. 0x117\n"
7021 "(default: 0x0000 if sisfb is a module; this leaves the console untouched\n"
Linus Torvalds1da177e2005-04-16 15:20:36 -07007022 "and the driver will only do the video memory management for eg. DRM/DRI;\n"
7023 "0x0103 if sisfb is in the kernel)\n");
7024#endif
7025
7026#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0)
7027MODULE_PARM_DESC(mode,
Thomas Winischhofer544393f2005-09-09 13:04:45 -07007028 "\nSelects the desired default display mode in the format XxYxDepth,\n"
7029 "eg. 1024x768x16. Other formats supported include XxY-Depth and\n"
Linus Torvalds1da177e2005-04-16 15:20:36 -07007030 "XxY-Depth@Rate. If the parameter is only one (decimal or hexadecimal)\n"
7031 "number, it will be interpreted as a VESA mode number. (default: 800x600x8)\n");
7032
7033MODULE_PARM_DESC(vesa,
Thomas Winischhofer544393f2005-09-09 13:04:45 -07007034 "\nSelects the desired default display mode by VESA defined mode number, eg.\n"
7035 "0x117 (default: 0x0103)\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07007036#endif
7037
7038MODULE_PARM_DESC(rate,
7039 "\nSelects the desired vertical refresh rate for CRT1 (external VGA) in Hz.\n"
7040 "If the mode is specified in the format XxY-Depth@Rate, this parameter\n"
7041 "will be ignored (default: 60)\n");
7042
7043MODULE_PARM_DESC(forcecrt1,
7044 "\nNormally, the driver autodetects whether or not CRT1 (external VGA) is \n"
7045 "connected. With this option, the detection can be overridden (1=CRT1 ON,\n"
7046 "0=CRT1 OFF) (default: [autodetected])\n");
7047
7048MODULE_PARM_DESC(forcecrt2type,
7049 "\nIf this option is omitted, the driver autodetects CRT2 output devices, such as\n"
7050 "LCD, TV or secondary VGA. With this option, this autodetection can be\n"
7051 "overridden. Possible parameters are LCD, TV, VGA or NONE. NONE disables CRT2.\n"
7052 "On systems with a SiS video bridge, parameters SVIDEO, COMPOSITE or SCART can\n"
7053 "be used instead of TV to override the TV detection. Furthermore, on systems\n"
7054 "with a SiS video bridge, SVIDEO+COMPOSITE, HIVISION, YPBPR480I, YPBPR480P,\n"
7055 "YPBPR720P and YPBPR1080I are understood. However, whether or not these work\n"
7056 "depends on the very hardware in use. (default: [autodetected])\n");
7057
7058MODULE_PARM_DESC(scalelcd,
7059 "\nSetting this to 1 will force the driver to scale the LCD image to the panel's\n"
7060 "native resolution. Setting it to 0 will disable scaling; LVDS panels will\n"
7061 "show black bars around the image, TMDS panels will probably do the scaling\n"
7062 "themselves. Default: 1 on LVDS panels, 0 on TMDS panels\n");
7063
7064MODULE_PARM_DESC(pdc,
Thomas Winischhofer544393f2005-09-09 13:04:45 -07007065 "\nThis is for manually selecting the LCD panel delay compensation. The driver\n"
Linus Torvalds1da177e2005-04-16 15:20:36 -07007066 "should detect this correctly in most cases; however, sometimes this is not\n"
7067 "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 -07007068 "on a 300 series chipset; 6 on other chipsets. If the problem persists, try\n"
7069 "other values (on 300 series: between 4 and 60 in steps of 4; otherwise: any\n"
7070 "value from 0 to 31). (default: autodetected, if LCD is active during start)\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07007071
7072#ifdef CONFIG_FB_SIS_315
7073MODULE_PARM_DESC(pdc1,
Thomas Winischhofer544393f2005-09-09 13:04:45 -07007074 "\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 -07007075 "series only. (default: autodetected if LCD is in LCD-via-CRT1 mode during\n"
7076 "startup) - Note: currently, this has no effect because LCD-via-CRT1 is not\n"
7077 "implemented yet.\n");
7078#endif
7079
7080MODULE_PARM_DESC(specialtiming,
7081 "\nPlease refer to documentation for more information on this option.\n");
7082
7083MODULE_PARM_DESC(lvdshl,
7084 "\nPlease refer to documentation for more information on this option.\n");
7085
7086MODULE_PARM_DESC(tvstandard,
7087 "\nThis allows overriding the BIOS default for the TV standard. Valid choices are\n"
7088 "pal, ntsc, palm and paln. (default: [auto; pal or ntsc only])\n");
7089
7090MODULE_PARM_DESC(tvxposoffset,
7091 "\nRelocate TV output horizontally. Possible parameters: -32 through 32.\n"
7092 "Default: 0\n");
7093
7094MODULE_PARM_DESC(tvyposoffset,
7095 "\nRelocate TV output vertically. Possible parameters: -32 through 32.\n"
7096 "Default: 0\n");
7097
Linus Torvalds1da177e2005-04-16 15:20:36 -07007098MODULE_PARM_DESC(nocrt2rate,
7099 "\nSetting this to 1 will force the driver to use the default refresh rate for\n"
7100 "CRT2 if CRT2 type is VGA. (default: 0, use same rate as CRT1)\n");
7101
7102#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
7103MODULE_PARM_DESC(inverse,
Thomas Winischhofer544393f2005-09-09 13:04:45 -07007104 "\nSetting this to anything but 0 should invert the display colors, but this\n"
Linus Torvalds1da177e2005-04-16 15:20:36 -07007105 "does not seem to work. (default: 0)\n");
7106#endif
7107
7108#if !defined(__i386__) && !defined(__x86_64__)
7109#ifdef CONFIG_FB_SIS_300
7110MODULE_PARM_DESC(resetcard,
7111 "\nSet this to 1 in order to reset (POST) the card on non-x86 machines where\n"
Thomas Winischhofer544393f2005-09-09 13:04:45 -07007112 "the BIOS did not POST the card (only supported for SiS 300/305 and XGI cards\n"
7113 "currently). Default: 0\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07007114
7115MODULE_PARM_DESC(videoram,
7116 "\nSet this to the amount of video RAM (in kilobyte) the card has. Required on\n"
7117 "some non-x86 architectures where the memory auto detection fails. Only\n"
Thomas Winischhofer544393f2005-09-09 13:04:45 -07007118 "relevant if resetcard is set, too. SiS300/305 only. Default: [auto-detect]\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07007119#endif
7120#endif
7121
Linus Torvalds1da177e2005-04-16 15:20:36 -07007122#endif /* /MODULE */
7123
Thomas Winischhofer544393f2005-09-09 13:04:45 -07007124/* _GPL only for new symbols. */
Linus Torvalds1da177e2005-04-16 15:20:36 -07007125EXPORT_SYMBOL(sis_malloc);
7126EXPORT_SYMBOL(sis_free);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07007127EXPORT_SYMBOL_GPL(sis_malloc_new);
7128EXPORT_SYMBOL_GPL(sis_free_new);
7129
Linus Torvalds1da177e2005-04-16 15:20:36 -07007130
7131