blob: 37bd24b8d83b2568d516a16cd58e196e4e2e59f7 [file] [log] [blame]
Linus Torvalds1da177e2005-04-16 15:20:36 -07001/*
Thomas Winischhofer544393f2005-09-09 13:04:45 -07002 * SiS 300/540/630[S]/730[S],
3 * SiS 315[E|PRO]/550/[M]65x/[M]66x[F|M|G]X/[M]74x[GX]/330/[M]76x[GX],
4 * XGI V3XT/V5/V8, Z7
Linus Torvalds1da177e2005-04-16 15:20:36 -07005 * frame buffer driver for Linux kernels >= 2.4.14 and >=2.6.3
6 *
Thomas Winischhofer544393f2005-09-09 13:04:45 -07007 * Copyright (C) 2001-2005 Thomas Winischhofer, Vienna, Austria.
Linus Torvalds1da177e2005-04-16 15:20:36 -07008 *
9 * This program is free software; you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License as published by
11 * the Free Software Foundation; either version 2 of the named License,
12 * or any later version.
13 *
14 * This program is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 * GNU General Public License for more details.
18 *
19 * You should have received a copy of the GNU General Public License
20 * along with this program; if not, write to the Free Software
21 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA
22 *
Thomas Winischhofer544393f2005-09-09 13:04:45 -070023 * Author: Thomas Winischhofer <thomas@winischhofer.net>
Linus Torvalds1da177e2005-04-16 15:20:36 -070024 *
25 * Author of (practically wiped) code base:
26 * SiS (www.sis.com)
Thomas Winischhofer544393f2005-09-09 13:04:45 -070027 * Copyright (C) 1999 Silicon Integrated Systems, Inc.
Linus Torvalds1da177e2005-04-16 15:20:36 -070028 *
29 * See http://www.winischhofer.net/ for more information and updates
30 *
31 * Originally based on the VBE 2.0 compliant graphic boards framebuffer driver,
32 * which is (c) 1998 Gerd Knorr <kraxel@goldbach.in-berlin.de>
33 *
34 */
35
Linus Torvalds1da177e2005-04-16 15:20:36 -070036#include <linux/version.h>
37#include <linux/module.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070038#include <linux/moduleparam.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070039#include <linux/kernel.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070040#include <linux/spinlock.h>
41#include <linux/errno.h>
42#include <linux/string.h>
43#include <linux/mm.h>
Jon Smirla8f340e2006-07-10 04:44:12 -070044
Jon Smirl894673e2006-07-10 04:44:13 -070045#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,17)
Linus Torvalds1da177e2005-04-16 15:20:36 -070046#include <linux/tty.h>
Jon Smirla8f340e2006-07-10 04:44:12 -070047#else
48#include <linux/screen_info.h>
49#endif
50
Linus Torvalds1da177e2005-04-16 15:20:36 -070051#include <linux/slab.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070052#include <linux/fb.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070053#include <linux/selection.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070054#include <linux/ioport.h>
55#include <linux/init.h>
56#include <linux/pci.h>
57#include <linux/vmalloc.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070058#include <linux/capability.h>
59#include <linux/fs.h>
60#include <linux/types.h>
Krzysztof Helt84902b72007-10-16 01:29:04 -070061#include <linux/uaccess.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070062#include <asm/io.h>
63#ifdef CONFIG_MTRR
64#include <asm/mtrr.h>
65#endif
66
Linus Torvalds1da177e2005-04-16 15:20:36 -070067#include "sis.h"
68#include "sis_main.h"
69
Thomas Winischhofer544393f2005-09-09 13:04:45 -070070static void sisfb_handle_command(struct sis_video_info *ivideo,
71 struct sisfb_cmd *sisfb_command);
72
Linus Torvalds1da177e2005-04-16 15:20:36 -070073/* ------------------ Internal helper routines ----------------- */
74
75static void __init
76sisfb_setdefaultparms(void)
77{
Thomas Winischhofer544393f2005-09-09 13:04:45 -070078 sisfb_off = 0;
79 sisfb_parm_mem = 0;
80 sisfb_accel = -1;
81 sisfb_ypan = -1;
82 sisfb_max = -1;
83 sisfb_userom = -1;
84 sisfb_useoem = -1;
Thomas Winischhofer544393f2005-09-09 13:04:45 -070085 sisfb_mode_idx = -1;
Thomas Winischhofer544393f2005-09-09 13:04:45 -070086 sisfb_parm_rate = -1;
87 sisfb_crt1off = 0;
88 sisfb_forcecrt1 = -1;
89 sisfb_crt2type = -1;
90 sisfb_crt2flags = 0;
91 sisfb_pdc = 0xff;
92 sisfb_pdca = 0xff;
93 sisfb_scalelcd = -1;
Linus Torvalds1da177e2005-04-16 15:20:36 -070094 sisfb_specialtiming = CUT_NONE;
Thomas Winischhofer544393f2005-09-09 13:04:45 -070095 sisfb_lvdshl = -1;
96 sisfb_dstn = 0;
97 sisfb_fstn = 0;
98 sisfb_tvplug = -1;
99 sisfb_tvstd = -1;
100 sisfb_tvxposoffset = 0;
101 sisfb_tvyposoffset = 0;
102 sisfb_nocrt2rate = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700103#if !defined(__i386__) && !defined(__x86_64__)
Thomas Winischhofer544393f2005-09-09 13:04:45 -0700104 sisfb_resetcard = 0;
105 sisfb_videoram = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700106#endif
107}
108
Thomas Winischhofer544393f2005-09-09 13:04:45 -0700109/* ------------- Parameter parsing -------------- */
110
Linus Torvalds1da177e2005-04-16 15:20:36 -0700111static void __devinit
Richard Knutssonc30660ea2007-02-12 00:55:06 -0800112sisfb_search_vesamode(unsigned int vesamode, bool quiet)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700113{
114 int i = 0, j = 0;
115
Thomas Winischhofer544393f2005-09-09 13:04:45 -0700116 /* We don't know the hardware specs yet and there is no ivideo */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700117
118 if(vesamode == 0) {
Thomas Winischhofer544393f2005-09-09 13:04:45 -0700119 if(!quiet)
120 printk(KERN_ERR "sisfb: Invalid mode. Using default.\n");
121
Linus Torvalds1da177e2005-04-16 15:20:36 -0700122 sisfb_mode_idx = DEFAULT_MODE;
Michal Piotrowski43704092006-10-03 01:15:00 -0700123
Linus Torvalds1da177e2005-04-16 15:20:36 -0700124 return;
125 }
126
127 vesamode &= 0x1dff; /* Clean VESA mode number from other flags */
128
129 while(sisbios_mode[i++].mode_no[0] != 0) {
130 if( (sisbios_mode[i-1].vesa_mode_no_1 == vesamode) ||
131 (sisbios_mode[i-1].vesa_mode_no_2 == vesamode) ) {
Thomas Winischhofer544393f2005-09-09 13:04:45 -0700132 if(sisfb_fstn) {
133 if(sisbios_mode[i-1].mode_no[1] == 0x50 ||
134 sisbios_mode[i-1].mode_no[1] == 0x56 ||
135 sisbios_mode[i-1].mode_no[1] == 0x53)
136 continue;
137 } else {
138 if(sisbios_mode[i-1].mode_no[1] == 0x5a ||
139 sisbios_mode[i-1].mode_no[1] == 0x5b)
140 continue;
141 }
142 sisfb_mode_idx = i - 1;
143 j = 1;
144 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700145 }
146 }
Thomas Winischhofer544393f2005-09-09 13:04:45 -0700147 if((!j) && !quiet)
148 printk(KERN_ERR "sisfb: Invalid VESA mode 0x%x'\n", vesamode);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700149}
150
Thomas Winischhofer544393f2005-09-09 13:04:45 -0700151static void __devinit
Richard Knutssonc30660ea2007-02-12 00:55:06 -0800152sisfb_search_mode(char *name, bool quiet)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700153{
Linus Torvalds1da177e2005-04-16 15:20:36 -0700154 unsigned int j = 0, xres = 0, yres = 0, depth = 0, rate = 0;
Thomas Winischhofer544393f2005-09-09 13:04:45 -0700155 int i = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700156 char strbuf[16], strbuf1[20];
157 char *nameptr = name;
158
Thomas Winischhofer544393f2005-09-09 13:04:45 -0700159 /* We don't know the hardware specs yet and there is no ivideo */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700160
161 if(name == NULL) {
Thomas Winischhofer544393f2005-09-09 13:04:45 -0700162 if(!quiet)
163 printk(KERN_ERR "sisfb: Internal error, using default mode.\n");
164
165 sisfb_mode_idx = DEFAULT_MODE;
166 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700167 }
168
Thomas Winischhofer544393f2005-09-09 13:04:45 -0700169 if(!strnicmp(name, sisbios_mode[MODE_INDEX_NONE].name, strlen(name))) {
170 if(!quiet)
171 printk(KERN_ERR "sisfb: Mode 'none' not supported anymore. Using default.\n");
172
173 sisfb_mode_idx = DEFAULT_MODE;
174 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700175 }
Michal Piotrowski43704092006-10-03 01:15:00 -0700176
Linus Torvalds1da177e2005-04-16 15:20:36 -0700177 if(strlen(name) <= 19) {
Thomas Winischhofer544393f2005-09-09 13:04:45 -0700178 strcpy(strbuf1, name);
179 for(i = 0; i < strlen(strbuf1); i++) {
180 if(strbuf1[i] < '0' || strbuf1[i] > '9') strbuf1[i] = ' ';
181 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700182
Thomas Winischhofer544393f2005-09-09 13:04:45 -0700183 /* This does some fuzzy mode naming detection */
184 if(sscanf(strbuf1, "%u %u %u %u", &xres, &yres, &depth, &rate) == 4) {
185 if((rate <= 32) || (depth > 32)) {
186 j = rate; rate = depth; depth = j;
187 }
188 sprintf(strbuf, "%ux%ux%u", xres, yres, depth);
189 nameptr = strbuf;
190 sisfb_parm_rate = rate;
191 } else if(sscanf(strbuf1, "%u %u %u", &xres, &yres, &depth) == 3) {
192 sprintf(strbuf, "%ux%ux%u", xres, yres, depth);
193 nameptr = strbuf;
194 } else {
195 xres = 0;
196 if((sscanf(strbuf1, "%u %u", &xres, &yres) == 2) && (xres != 0)) {
197 sprintf(strbuf, "%ux%ux8", xres, yres);
198 nameptr = strbuf;
199 } else {
200 sisfb_search_vesamode(simple_strtoul(name, NULL, 0), quiet);
201 return;
202 }
203 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700204 }
205
206 i = 0; j = 0;
207 while(sisbios_mode[i].mode_no[0] != 0) {
208 if(!strnicmp(nameptr, sisbios_mode[i++].name, strlen(nameptr))) {
Thomas Winischhofer544393f2005-09-09 13:04:45 -0700209 if(sisfb_fstn) {
210 if(sisbios_mode[i-1].mode_no[1] == 0x50 ||
211 sisbios_mode[i-1].mode_no[1] == 0x56 ||
212 sisbios_mode[i-1].mode_no[1] == 0x53)
213 continue;
214 } else {
215 if(sisbios_mode[i-1].mode_no[1] == 0x5a ||
216 sisbios_mode[i-1].mode_no[1] == 0x5b)
217 continue;
218 }
219 sisfb_mode_idx = i - 1;
220 j = 1;
221 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700222 }
223 }
Thomas Winischhofer544393f2005-09-09 13:04:45 -0700224
225 if((!j) && !quiet)
226 printk(KERN_ERR "sisfb: Invalid mode '%s'\n", nameptr);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700227}
228
229#ifndef MODULE
230static void __devinit
231sisfb_get_vga_mode_from_kernel(void)
232{
Adrian Bunk31c5cdb2006-06-26 00:26:28 -0700233#ifdef CONFIG_X86
Thomas Winischhofer544393f2005-09-09 13:04:45 -0700234 char mymode[32];
Linus Torvalds1da177e2005-04-16 15:20:36 -0700235 int mydepth = screen_info.lfb_depth;
236
237 if(screen_info.orig_video_isVGA != VIDEO_TYPE_VLFB) return;
238
239 if( (screen_info.lfb_width >= 320) && (screen_info.lfb_width <= 2048) &&
240 (screen_info.lfb_height >= 200) && (screen_info.lfb_height <= 1536) &&
241 (mydepth >= 8) && (mydepth <= 32) ) {
242
Thomas Winischhofer544393f2005-09-09 13:04:45 -0700243 if(mydepth == 24) mydepth = 32;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700244
Thomas Winischhofer544393f2005-09-09 13:04:45 -0700245 sprintf(mymode, "%ux%ux%u", screen_info.lfb_width,
246 screen_info.lfb_height,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700247 mydepth);
248
Thomas Winischhofer544393f2005-09-09 13:04:45 -0700249 printk(KERN_DEBUG
250 "sisfb: Using vga mode %s pre-set by kernel as default\n",
251 mymode);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700252
Richard Knutssonc30660ea2007-02-12 00:55:06 -0800253 sisfb_search_mode(mymode, true);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700254 }
255#endif
256 return;
257}
258#endif
259
260static void __init
261sisfb_search_crt2type(const char *name)
262{
263 int i = 0;
264
Thomas Winischhofer544393f2005-09-09 13:04:45 -0700265 /* We don't know the hardware specs yet and there is no ivideo */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700266
267 if(name == NULL) return;
268
269 while(sis_crt2type[i].type_no != -1) {
Thomas Winischhofer544393f2005-09-09 13:04:45 -0700270 if(!strnicmp(name, sis_crt2type[i].name, strlen(sis_crt2type[i].name))) {
271 sisfb_crt2type = sis_crt2type[i].type_no;
272 sisfb_tvplug = sis_crt2type[i].tvplug_no;
273 sisfb_crt2flags = sis_crt2type[i].flags;
274 break;
275 }
276 i++;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700277 }
278
279 sisfb_dstn = (sisfb_crt2flags & FL_550_DSTN) ? 1 : 0;
280 sisfb_fstn = (sisfb_crt2flags & FL_550_FSTN) ? 1 : 0;
281
Thomas Winischhofer544393f2005-09-09 13:04:45 -0700282 if(sisfb_crt2type < 0)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700283 printk(KERN_ERR "sisfb: Invalid CRT2 type: %s\n", name);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700284}
285
286static void __init
287sisfb_search_tvstd(const char *name)
288{
289 int i = 0;
290
Thomas Winischhofer544393f2005-09-09 13:04:45 -0700291 /* We don't know the hardware specs yet and there is no ivideo */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700292
Thomas Winischhofer544393f2005-09-09 13:04:45 -0700293 if(name == NULL)
294 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700295
296 while(sis_tvtype[i].type_no != -1) {
Thomas Winischhofer544393f2005-09-09 13:04:45 -0700297 if(!strnicmp(name, sis_tvtype[i].name, strlen(sis_tvtype[i].name))) {
298 sisfb_tvstd = sis_tvtype[i].type_no;
299 break;
300 }
301 i++;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700302 }
303}
304
305static void __init
306sisfb_search_specialtiming(const char *name)
307{
308 int i = 0;
Richard Knutssonc30660ea2007-02-12 00:55:06 -0800309 bool found = false;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700310
Thomas Winischhofer544393f2005-09-09 13:04:45 -0700311 /* We don't know the hardware specs yet and there is no ivideo */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700312
Thomas Winischhofer544393f2005-09-09 13:04:45 -0700313 if(name == NULL)
314 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700315
316 if(!strnicmp(name, "none", 4)) {
Thomas Winischhofer544393f2005-09-09 13:04:45 -0700317 sisfb_specialtiming = CUT_FORCENONE;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700318 printk(KERN_DEBUG "sisfb: Special timing disabled\n");
319 } else {
Thomas Winischhofer544393f2005-09-09 13:04:45 -0700320 while(mycustomttable[i].chipID != 0) {
321 if(!strnicmp(name,mycustomttable[i].optionName,
322 strlen(mycustomttable[i].optionName))) {
323 sisfb_specialtiming = mycustomttable[i].SpecialID;
Richard Knutssonc30660ea2007-02-12 00:55:06 -0800324 found = true;
Thomas Winischhofer544393f2005-09-09 13:04:45 -0700325 printk(KERN_INFO "sisfb: Special timing for %s %s forced (\"%s\")\n",
326 mycustomttable[i].vendorName,
327 mycustomttable[i].cardName,
328 mycustomttable[i].optionName);
329 break;
330 }
331 i++;
332 }
333 if(!found) {
334 printk(KERN_WARNING "sisfb: Invalid SpecialTiming parameter, valid are:");
335 printk(KERN_WARNING "\t\"none\" (to disable special timings)\n");
336 i = 0;
337 while(mycustomttable[i].chipID != 0) {
338 printk(KERN_WARNING "\t\"%s\" (for %s %s)\n",
339 mycustomttable[i].optionName,
340 mycustomttable[i].vendorName,
341 mycustomttable[i].cardName);
342 i++;
343 }
344 }
345 }
346}
347
348/* ----------- Various detection routines ----------- */
349
350static void __devinit
351sisfb_detect_custom_timing(struct sis_video_info *ivideo)
352{
353 unsigned char *biosver = NULL;
354 unsigned char *biosdate = NULL;
Richard Knutssonc30660ea2007-02-12 00:55:06 -0800355 bool footprint;
Thomas Winischhofer544393f2005-09-09 13:04:45 -0700356 u32 chksum = 0;
357 int i, j;
358
359 if(ivideo->SiS_Pr.UseROM) {
360 biosver = ivideo->SiS_Pr.VirtualRomBase + 0x06;
361 biosdate = ivideo->SiS_Pr.VirtualRomBase + 0x2c;
362 for(i = 0; i < 32768; i++)
363 chksum += ivideo->SiS_Pr.VirtualRomBase[i];
364 }
365
366 i = 0;
367 do {
368 if( (mycustomttable[i].chipID == ivideo->chip) &&
369 ((!strlen(mycustomttable[i].biosversion)) ||
370 (ivideo->SiS_Pr.UseROM &&
371 (!strncmp(mycustomttable[i].biosversion, biosver,
372 strlen(mycustomttable[i].biosversion))))) &&
373 ((!strlen(mycustomttable[i].biosdate)) ||
374 (ivideo->SiS_Pr.UseROM &&
375 (!strncmp(mycustomttable[i].biosdate, biosdate,
376 strlen(mycustomttable[i].biosdate))))) &&
377 ((!mycustomttable[i].bioschksum) ||
378 (ivideo->SiS_Pr.UseROM &&
379 (mycustomttable[i].bioschksum == chksum))) &&
380 (mycustomttable[i].pcisubsysvendor == ivideo->subsysvendor) &&
381 (mycustomttable[i].pcisubsyscard == ivideo->subsysdevice) ) {
Richard Knutssonc30660ea2007-02-12 00:55:06 -0800382 footprint = true;
Thomas Winischhofer544393f2005-09-09 13:04:45 -0700383 for(j = 0; j < 5; j++) {
384 if(mycustomttable[i].biosFootprintAddr[j]) {
385 if(ivideo->SiS_Pr.UseROM) {
386 if(ivideo->SiS_Pr.VirtualRomBase[mycustomttable[i].biosFootprintAddr[j]] !=
387 mycustomttable[i].biosFootprintData[j]) {
Richard Knutssonc30660ea2007-02-12 00:55:06 -0800388 footprint = false;
Thomas Winischhofer544393f2005-09-09 13:04:45 -0700389 }
390 } else
Richard Knutssonc30660ea2007-02-12 00:55:06 -0800391 footprint = false;
Thomas Winischhofer544393f2005-09-09 13:04:45 -0700392 }
393 }
394 if(footprint) {
395 ivideo->SiS_Pr.SiS_CustomT = mycustomttable[i].SpecialID;
396 printk(KERN_DEBUG "sisfb: Identified [%s %s], special timing applies\n",
397 mycustomttable[i].vendorName,
398 mycustomttable[i].cardName);
399 printk(KERN_DEBUG "sisfb: [specialtiming parameter name: %s]\n",
400 mycustomttable[i].optionName);
401 break;
402 }
403 }
404 i++;
405 } while(mycustomttable[i].chipID);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700406}
407
Richard Knutssonc30660ea2007-02-12 00:55:06 -0800408static bool __devinit
Linus Torvalds1da177e2005-04-16 15:20:36 -0700409sisfb_interpret_edid(struct sisfb_monitor *monitor, u8 *buffer)
410{
411 int i, j, xres, yres, refresh, index;
412 u32 emodes;
413
414 if(buffer[0] != 0x00 || buffer[1] != 0xff ||
415 buffer[2] != 0xff || buffer[3] != 0xff ||
416 buffer[4] != 0xff || buffer[5] != 0xff ||
417 buffer[6] != 0xff || buffer[7] != 0x00) {
Thomas Winischhofer544393f2005-09-09 13:04:45 -0700418 printk(KERN_DEBUG "sisfb: Bad EDID header\n");
Richard Knutssonc30660ea2007-02-12 00:55:06 -0800419 return false;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700420 }
421
422 if(buffer[0x12] != 0x01) {
Thomas Winischhofer544393f2005-09-09 13:04:45 -0700423 printk(KERN_INFO "sisfb: EDID version %d not supported\n",
424 buffer[0x12]);
Richard Knutssonc30660ea2007-02-12 00:55:06 -0800425 return false;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700426 }
427
428 monitor->feature = buffer[0x18];
429
430 if(!buffer[0x14] & 0x80) {
Thomas Winischhofer544393f2005-09-09 13:04:45 -0700431 if(!(buffer[0x14] & 0x08)) {
432 printk(KERN_INFO
433 "sisfb: WARNING: Monitor does not support separate syncs\n");
434 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700435 }
436
437 if(buffer[0x13] >= 0x01) {
438 /* EDID V1 rev 1 and 2: Search for monitor descriptor
439 * to extract ranges
440 */
441 j = 0x36;
442 for(i=0; i<4; i++) {
443 if(buffer[j] == 0x00 && buffer[j + 1] == 0x00 &&
Thomas Winischhofer544393f2005-09-09 13:04:45 -0700444 buffer[j + 2] == 0x00 && buffer[j + 3] == 0xfd &&
Linus Torvalds1da177e2005-04-16 15:20:36 -0700445 buffer[j + 4] == 0x00) {
446 monitor->hmin = buffer[j + 7];
447 monitor->hmax = buffer[j + 8];
448 monitor->vmin = buffer[j + 5];
449 monitor->vmax = buffer[j + 6];
450 monitor->dclockmax = buffer[j + 9] * 10 * 1000;
Richard Knutssonc30660ea2007-02-12 00:55:06 -0800451 monitor->datavalid = true;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700452 break;
453 }
454 j += 18;
455 }
456 }
457
458 if(!monitor->datavalid) {
459 /* Otherwise: Get a range from the list of supported
460 * Estabished Timings. This is not entirely accurate,
461 * because fixed frequency monitors are not supported
462 * that way.
463 */
464 monitor->hmin = 65535; monitor->hmax = 0;
465 monitor->vmin = 65535; monitor->vmax = 0;
466 monitor->dclockmax = 0;
467 emodes = buffer[0x23] | (buffer[0x24] << 8) | (buffer[0x25] << 16);
468 for(i = 0; i < 13; i++) {
469 if(emodes & sisfb_ddcsmodes[i].mask) {
Thomas Winischhofer544393f2005-09-09 13:04:45 -0700470 if(monitor->hmin > sisfb_ddcsmodes[i].h) monitor->hmin = sisfb_ddcsmodes[i].h;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700471 if(monitor->hmax < sisfb_ddcsmodes[i].h) monitor->hmax = sisfb_ddcsmodes[i].h + 1;
472 if(monitor->vmin > sisfb_ddcsmodes[i].v) monitor->vmin = sisfb_ddcsmodes[i].v;
473 if(monitor->vmax < sisfb_ddcsmodes[i].v) monitor->vmax = sisfb_ddcsmodes[i].v;
474 if(monitor->dclockmax < sisfb_ddcsmodes[i].d) monitor->dclockmax = sisfb_ddcsmodes[i].d;
475 }
476 }
477 index = 0x26;
478 for(i = 0; i < 8; i++) {
479 xres = (buffer[index] + 31) * 8;
480 switch(buffer[index + 1] & 0xc0) {
Thomas Winischhofer544393f2005-09-09 13:04:45 -0700481 case 0xc0: yres = (xres * 9) / 16; break;
482 case 0x80: yres = (xres * 4) / 5; break;
483 case 0x40: yres = (xres * 3) / 4; break;
484 default: yres = xres; break;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700485 }
486 refresh = (buffer[index + 1] & 0x3f) + 60;
487 if((xres >= 640) && (yres >= 480)) {
Thomas Winischhofer544393f2005-09-09 13:04:45 -0700488 for(j = 0; j < 8; j++) {
489 if((xres == sisfb_ddcfmodes[j].x) &&
490 (yres == sisfb_ddcfmodes[j].y) &&
Linus Torvalds1da177e2005-04-16 15:20:36 -0700491 (refresh == sisfb_ddcfmodes[j].v)) {
492 if(monitor->hmin > sisfb_ddcfmodes[j].h) monitor->hmin = sisfb_ddcfmodes[j].h;
493 if(monitor->hmax < sisfb_ddcfmodes[j].h) monitor->hmax = sisfb_ddcfmodes[j].h + 1;
494 if(monitor->vmin > sisfb_ddcsmodes[j].v) monitor->vmin = sisfb_ddcsmodes[j].v;
495 if(monitor->vmax < sisfb_ddcsmodes[j].v) monitor->vmax = sisfb_ddcsmodes[j].v;
Thomas Winischhofer544393f2005-09-09 13:04:45 -0700496 if(monitor->dclockmax < sisfb_ddcsmodes[j].d) monitor->dclockmax = sisfb_ddcsmodes[j].d;
497 }
498 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700499 }
500 index += 2;
Thomas Winischhofer544393f2005-09-09 13:04:45 -0700501 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700502 if((monitor->hmin <= monitor->hmax) && (monitor->vmin <= monitor->vmax)) {
Richard Knutssonc30660ea2007-02-12 00:55:06 -0800503 monitor->datavalid = true;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700504 }
505 }
506
Thomas Winischhofer544393f2005-09-09 13:04:45 -0700507 return monitor->datavalid;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700508}
509
510static void __devinit
511sisfb_handle_ddc(struct sis_video_info *ivideo, struct sisfb_monitor *monitor, int crtno)
512{
Thomas Winischhofer544393f2005-09-09 13:04:45 -0700513 unsigned short temp, i, realcrtno = crtno;
514 unsigned char buffer[256];
Linus Torvalds1da177e2005-04-16 15:20:36 -0700515
Richard Knutssonc30660ea2007-02-12 00:55:06 -0800516 monitor->datavalid = false;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700517
518 if(crtno) {
Thomas Winischhofer544393f2005-09-09 13:04:45 -0700519 if(ivideo->vbflags & CRT2_LCD) realcrtno = 1;
520 else if(ivideo->vbflags & CRT2_VGA) realcrtno = 2;
521 else return;
522 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700523
Thomas Winischhofer544393f2005-09-09 13:04:45 -0700524 if((ivideo->sisfb_crt1off) && (!crtno))
525 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700526
Thomas Winischhofer544393f2005-09-09 13:04:45 -0700527 temp = SiS_HandleDDC(&ivideo->SiS_Pr, ivideo->vbflags, ivideo->sisvga_engine,
528 realcrtno, 0, &buffer[0], ivideo->vbflags2);
529 if((!temp) || (temp == 0xffff)) {
530 printk(KERN_INFO "sisfb: CRT%d DDC probing failed\n", crtno + 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700531 return;
Thomas Winischhofer544393f2005-09-09 13:04:45 -0700532 } else {
533 printk(KERN_INFO "sisfb: CRT%d DDC supported\n", crtno + 1);
534 printk(KERN_INFO "sisfb: CRT%d DDC level: %s%s%s%s\n",
535 crtno + 1,
536 (temp & 0x1a) ? "" : "[none of the supported]",
537 (temp & 0x02) ? "2 " : "",
538 (temp & 0x08) ? "D&P" : "",
539 (temp & 0x10) ? "FPDI-2" : "");
540 if(temp & 0x02) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700541 i = 3; /* Number of retrys */
542 do {
Thomas Winischhofer544393f2005-09-09 13:04:45 -0700543 temp = SiS_HandleDDC(&ivideo->SiS_Pr, ivideo->vbflags, ivideo->sisvga_engine,
544 realcrtno, 1, &buffer[0], ivideo->vbflags2);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700545 } while((temp) && i--);
Thomas Winischhofer544393f2005-09-09 13:04:45 -0700546 if(!temp) {
547 if(sisfb_interpret_edid(monitor, &buffer[0])) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700548 printk(KERN_INFO "sisfb: Monitor range H %d-%dKHz, V %d-%dHz, Max. dotclock %dMHz\n",
Thomas Winischhofer544393f2005-09-09 13:04:45 -0700549 monitor->hmin, monitor->hmax, monitor->vmin, monitor->vmax,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700550 monitor->dclockmax / 1000);
551 } else {
Thomas Winischhofer544393f2005-09-09 13:04:45 -0700552 printk(KERN_INFO "sisfb: CRT%d DDC EDID corrupt\n", crtno + 1);
553 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700554 } else {
Thomas Winischhofer544393f2005-09-09 13:04:45 -0700555 printk(KERN_INFO "sisfb: CRT%d DDC reading failed\n", crtno + 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700556 }
557 } else {
558 printk(KERN_INFO "sisfb: VESA D&P and FPDI-2 not supported yet\n");
559 }
560 }
561}
562
Thomas Winischhofer544393f2005-09-09 13:04:45 -0700563/* -------------- Mode validation --------------- */
564
Richard Knutssonc30660ea2007-02-12 00:55:06 -0800565static bool
Linus Torvalds1da177e2005-04-16 15:20:36 -0700566sisfb_verify_rate(struct sis_video_info *ivideo, struct sisfb_monitor *monitor,
567 int mode_idx, int rate_idx, int rate)
568{
569 int htotal, vtotal;
570 unsigned int dclock, hsync;
571
Thomas Winischhofer544393f2005-09-09 13:04:45 -0700572 if(!monitor->datavalid)
Richard Knutssonc30660ea2007-02-12 00:55:06 -0800573 return true;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700574
Thomas Winischhofer544393f2005-09-09 13:04:45 -0700575 if(mode_idx < 0)
Richard Knutssonc30660ea2007-02-12 00:55:06 -0800576 return false;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700577
578 /* Skip for 320x200, 320x240, 640x400 */
Thomas Winischhofer544393f2005-09-09 13:04:45 -0700579 switch(sisbios_mode[mode_idx].mode_no[ivideo->mni]) {
580 case 0x59:
581 case 0x41:
582 case 0x4f:
583 case 0x50:
584 case 0x56:
585 case 0x53:
586 case 0x2f:
587 case 0x5d:
588 case 0x5e:
Richard Knutssonc30660ea2007-02-12 00:55:06 -0800589 return true;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700590#ifdef CONFIG_FB_SIS_315
591 case 0x5a:
592 case 0x5b:
Richard Knutssonc30660ea2007-02-12 00:55:06 -0800593 if(ivideo->sisvga_engine == SIS_315_VGA) return true;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700594#endif
Thomas Winischhofer544393f2005-09-09 13:04:45 -0700595 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700596
Thomas Winischhofer544393f2005-09-09 13:04:45 -0700597 if(rate < (monitor->vmin - 1))
Richard Knutssonc30660ea2007-02-12 00:55:06 -0800598 return false;
Thomas Winischhofer544393f2005-09-09 13:04:45 -0700599 if(rate > (monitor->vmax + 1))
Richard Knutssonc30660ea2007-02-12 00:55:06 -0800600 return false;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700601
Thomas Winischhofer544393f2005-09-09 13:04:45 -0700602 if(sisfb_gettotalfrommode(&ivideo->SiS_Pr,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700603 sisbios_mode[mode_idx].mode_no[ivideo->mni],
Thomas Winischhofer544393f2005-09-09 13:04:45 -0700604 &htotal, &vtotal, rate_idx)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700605 dclock = (htotal * vtotal * rate) / 1000;
Thomas Winischhofer544393f2005-09-09 13:04:45 -0700606 if(dclock > (monitor->dclockmax + 1000))
Richard Knutssonc30660ea2007-02-12 00:55:06 -0800607 return false;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700608 hsync = dclock / htotal;
Thomas Winischhofer544393f2005-09-09 13:04:45 -0700609 if(hsync < (monitor->hmin - 1))
Richard Knutssonc30660ea2007-02-12 00:55:06 -0800610 return false;
Thomas Winischhofer544393f2005-09-09 13:04:45 -0700611 if(hsync > (monitor->hmax + 1))
Richard Knutssonc30660ea2007-02-12 00:55:06 -0800612 return false;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700613 } else {
Richard Knutssonc30660ea2007-02-12 00:55:06 -0800614 return false;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700615 }
Richard Knutssonc30660ea2007-02-12 00:55:06 -0800616 return true;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700617}
618
619static int
620sisfb_validate_mode(struct sis_video_info *ivideo, int myindex, u32 vbflags)
621{
Thomas Winischhofer544393f2005-09-09 13:04:45 -0700622 u16 xres=0, yres, myres;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700623
624#ifdef CONFIG_FB_SIS_300
Thomas Winischhofer544393f2005-09-09 13:04:45 -0700625 if(ivideo->sisvga_engine == SIS_300_VGA) {
626 if(!(sisbios_mode[myindex].chipset & MD_SIS300))
627 return -1 ;
628 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700629#endif
630#ifdef CONFIG_FB_SIS_315
Thomas Winischhofer544393f2005-09-09 13:04:45 -0700631 if(ivideo->sisvga_engine == SIS_315_VGA) {
632 if(!(sisbios_mode[myindex].chipset & MD_SIS315))
633 return -1;
634 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700635#endif
636
Thomas Winischhofer544393f2005-09-09 13:04:45 -0700637 myres = sisbios_mode[myindex].yres;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700638
Thomas Winischhofer544393f2005-09-09 13:04:45 -0700639 switch(vbflags & VB_DISPTYPE_DISP2) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700640
Thomas Winischhofer544393f2005-09-09 13:04:45 -0700641 case CRT2_LCD:
642 xres = ivideo->lcdxres; yres = ivideo->lcdyres;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700643
Thomas Winischhofer544393f2005-09-09 13:04:45 -0700644 if((ivideo->SiS_Pr.SiS_CustomT != CUT_PANEL848) &&
645 (ivideo->SiS_Pr.SiS_CustomT != CUT_PANEL856)) {
646 if(sisbios_mode[myindex].xres > xres)
647 return -1;
648 if(myres > yres)
649 return -1;
650 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700651
Thomas Winischhofer544393f2005-09-09 13:04:45 -0700652 if(ivideo->sisfb_fstn) {
653 if(sisbios_mode[myindex].xres == 320) {
654 if(myres == 240) {
655 switch(sisbios_mode[myindex].mode_no[1]) {
656 case 0x50: myindex = MODE_FSTN_8; break;
657 case 0x56: myindex = MODE_FSTN_16; break;
658 case 0x53: return -1;
659 }
660 }
661 }
662 }
663
664 if(SiS_GetModeID_LCD(ivideo->sisvga_engine, vbflags, sisbios_mode[myindex].xres,
665 sisbios_mode[myindex].yres, 0, ivideo->sisfb_fstn,
666 ivideo->SiS_Pr.SiS_CustomT, xres, yres, ivideo->vbflags2) < 0x14) {
667 return -1;
668 }
669 break;
670
671 case CRT2_TV:
672 if(SiS_GetModeID_TV(ivideo->sisvga_engine, vbflags, sisbios_mode[myindex].xres,
673 sisbios_mode[myindex].yres, 0, ivideo->vbflags2) < 0x14) {
674 return -1;
675 }
676 break;
677
678 case CRT2_VGA:
679 if(SiS_GetModeID_VGA2(ivideo->sisvga_engine, vbflags, sisbios_mode[myindex].xres,
680 sisbios_mode[myindex].yres, 0, ivideo->vbflags2) < 0x14) {
681 return -1;
682 }
683 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700684 }
685
Thomas Winischhofer544393f2005-09-09 13:04:45 -0700686 return myindex;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700687}
688
689static u8
690sisfb_search_refresh_rate(struct sis_video_info *ivideo, unsigned int rate, int mode_idx)
691{
Linus Torvalds1da177e2005-04-16 15:20:36 -0700692 int i = 0;
Thomas Winischhofer544393f2005-09-09 13:04:45 -0700693 u16 xres = sisbios_mode[mode_idx].xres;
694 u16 yres = sisbios_mode[mode_idx].yres;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700695
696 ivideo->rate_idx = 0;
697 while((sisfb_vrate[i].idx != 0) && (sisfb_vrate[i].xres <= xres)) {
698 if((sisfb_vrate[i].xres == xres) && (sisfb_vrate[i].yres == yres)) {
699 if(sisfb_vrate[i].refresh == rate) {
700 ivideo->rate_idx = sisfb_vrate[i].idx;
701 break;
702 } else if(sisfb_vrate[i].refresh > rate) {
703 if((sisfb_vrate[i].refresh - rate) <= 3) {
704 DPRINTK("sisfb: Adjusting rate from %d up to %d\n",
705 rate, sisfb_vrate[i].refresh);
706 ivideo->rate_idx = sisfb_vrate[i].idx;
707 ivideo->refresh_rate = sisfb_vrate[i].refresh;
708 } else if(((rate - sisfb_vrate[i-1].refresh) <= 2)
709 && (sisfb_vrate[i].idx != 1)) {
710 DPRINTK("sisfb: Adjusting rate from %d down to %d\n",
711 rate, sisfb_vrate[i-1].refresh);
712 ivideo->rate_idx = sisfb_vrate[i-1].idx;
713 ivideo->refresh_rate = sisfb_vrate[i-1].refresh;
Thomas Winischhofer544393f2005-09-09 13:04:45 -0700714 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700715 break;
716 } else if((rate - sisfb_vrate[i].refresh) <= 2) {
717 DPRINTK("sisfb: Adjusting rate from %d down to %d\n",
718 rate, sisfb_vrate[i].refresh);
Thomas Winischhofer544393f2005-09-09 13:04:45 -0700719 ivideo->rate_idx = sisfb_vrate[i].idx;
720 break;
721 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700722 }
723 i++;
724 }
725 if(ivideo->rate_idx > 0) {
726 return ivideo->rate_idx;
727 } else {
728 printk(KERN_INFO "sisfb: Unsupported rate %d for %dx%d\n",
729 rate, xres, yres);
730 return 0;
731 }
732}
733
Richard Knutssonc30660ea2007-02-12 00:55:06 -0800734static bool
Linus Torvalds1da177e2005-04-16 15:20:36 -0700735sisfb_bridgeisslave(struct sis_video_info *ivideo)
736{
Thomas Winischhofer544393f2005-09-09 13:04:45 -0700737 unsigned char P1_00;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700738
Thomas Winischhofer544393f2005-09-09 13:04:45 -0700739 if(!(ivideo->vbflags2 & VB2_VIDEOBRIDGE))
Richard Knutssonc30660ea2007-02-12 00:55:06 -0800740 return false;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700741
Thomas Winischhofer544393f2005-09-09 13:04:45 -0700742 inSISIDXREG(SISPART1,0x00,P1_00);
743 if( ((ivideo->sisvga_engine == SIS_300_VGA) && (P1_00 & 0xa0) == 0x20) ||
744 ((ivideo->sisvga_engine == SIS_315_VGA) && (P1_00 & 0x50) == 0x10) ) {
Richard Knutssonc30660ea2007-02-12 00:55:06 -0800745 return true;
Thomas Winischhofer544393f2005-09-09 13:04:45 -0700746 } else {
Richard Knutssonc30660ea2007-02-12 00:55:06 -0800747 return false;
Thomas Winischhofer544393f2005-09-09 13:04:45 -0700748 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700749}
750
Richard Knutssonc30660ea2007-02-12 00:55:06 -0800751static bool
Linus Torvalds1da177e2005-04-16 15:20:36 -0700752sisfballowretracecrt1(struct sis_video_info *ivideo)
753{
Thomas Winischhofer544393f2005-09-09 13:04:45 -0700754 u8 temp;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700755
Thomas Winischhofer544393f2005-09-09 13:04:45 -0700756 inSISIDXREG(SISCR,0x17,temp);
757 if(!(temp & 0x80))
Richard Knutssonc30660ea2007-02-12 00:55:06 -0800758 return false;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700759
Thomas Winischhofer544393f2005-09-09 13:04:45 -0700760 inSISIDXREG(SISSR,0x1f,temp);
761 if(temp & 0xc0)
Richard Knutssonc30660ea2007-02-12 00:55:06 -0800762 return false;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700763
Richard Knutssonc30660ea2007-02-12 00:55:06 -0800764 return true;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700765}
766
Richard Knutssonc30660ea2007-02-12 00:55:06 -0800767static bool
Linus Torvalds1da177e2005-04-16 15:20:36 -0700768sisfbcheckvretracecrt1(struct sis_video_info *ivideo)
769{
Thomas Winischhofer544393f2005-09-09 13:04:45 -0700770 if(!sisfballowretracecrt1(ivideo))
Richard Knutssonc30660ea2007-02-12 00:55:06 -0800771 return false;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700772
Thomas Winischhofer544393f2005-09-09 13:04:45 -0700773 if(inSISREG(SISINPSTAT) & 0x08)
Richard Knutssonc30660ea2007-02-12 00:55:06 -0800774 return true;
Thomas Winischhofer544393f2005-09-09 13:04:45 -0700775 else
Richard Knutssonc30660ea2007-02-12 00:55:06 -0800776 return false;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700777}
778
779static void
780sisfbwaitretracecrt1(struct sis_video_info *ivideo)
781{
Thomas Winischhofer544393f2005-09-09 13:04:45 -0700782 int watchdog;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700783
Thomas Winischhofer544393f2005-09-09 13:04:45 -0700784 if(!sisfballowretracecrt1(ivideo))
785 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700786
Thomas Winischhofer544393f2005-09-09 13:04:45 -0700787 watchdog = 65536;
788 while((!(inSISREG(SISINPSTAT) & 0x08)) && --watchdog);
789 watchdog = 65536;
790 while((inSISREG(SISINPSTAT) & 0x08) && --watchdog);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700791}
792
Richard Knutssonc30660ea2007-02-12 00:55:06 -0800793static bool
Linus Torvalds1da177e2005-04-16 15:20:36 -0700794sisfbcheckvretracecrt2(struct sis_video_info *ivideo)
795{
Thomas Winischhofer544393f2005-09-09 13:04:45 -0700796 unsigned char temp, reg;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700797
Thomas Winischhofer544393f2005-09-09 13:04:45 -0700798 switch(ivideo->sisvga_engine) {
799 case SIS_300_VGA: reg = 0x25; break;
800 case SIS_315_VGA: reg = 0x30; break;
Richard Knutssonc30660ea2007-02-12 00:55:06 -0800801 default: return false;
Thomas Winischhofer544393f2005-09-09 13:04:45 -0700802 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700803
Thomas Winischhofer544393f2005-09-09 13:04:45 -0700804 inSISIDXREG(SISPART1, reg, temp);
805 if(temp & 0x02)
Richard Knutssonc30660ea2007-02-12 00:55:06 -0800806 return true;
Thomas Winischhofer544393f2005-09-09 13:04:45 -0700807 else
Richard Knutssonc30660ea2007-02-12 00:55:06 -0800808 return false;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700809}
810
Richard Knutssonc30660ea2007-02-12 00:55:06 -0800811static bool
Linus Torvalds1da177e2005-04-16 15:20:36 -0700812sisfb_CheckVBRetrace(struct sis_video_info *ivideo)
813{
Thomas Winischhofer544393f2005-09-09 13:04:45 -0700814 if(ivideo->currentvbflags & VB_DISPTYPE_DISP2) {
815 if(!sisfb_bridgeisslave(ivideo)) {
816 return sisfbcheckvretracecrt2(ivideo);
817 }
818 }
819 return sisfbcheckvretracecrt1(ivideo);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700820}
821
822static u32
823sisfb_setupvbblankflags(struct sis_video_info *ivideo, u32 *vcount, u32 *hcount)
824{
Thomas Winischhofer544393f2005-09-09 13:04:45 -0700825 u8 idx, reg1, reg2, reg3, reg4;
826 u32 ret = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700827
Thomas Winischhofer544393f2005-09-09 13:04:45 -0700828 (*vcount) = (*hcount) = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700829
Thomas Winischhofer544393f2005-09-09 13:04:45 -0700830 if((ivideo->currentvbflags & VB_DISPTYPE_DISP2) && (!(sisfb_bridgeisslave(ivideo)))) {
831
832 ret |= (FB_VBLANK_HAVE_VSYNC |
833 FB_VBLANK_HAVE_HBLANK |
834 FB_VBLANK_HAVE_VBLANK |
835 FB_VBLANK_HAVE_VCOUNT |
836 FB_VBLANK_HAVE_HCOUNT);
837 switch(ivideo->sisvga_engine) {
838 case SIS_300_VGA: idx = 0x25; break;
839 default:
840 case SIS_315_VGA: idx = 0x30; break;
841 }
842 inSISIDXREG(SISPART1,(idx+0),reg1); /* 30 */
843 inSISIDXREG(SISPART1,(idx+1),reg2); /* 31 */
844 inSISIDXREG(SISPART1,(idx+2),reg3); /* 32 */
845 inSISIDXREG(SISPART1,(idx+3),reg4); /* 33 */
846 if(reg1 & 0x01) ret |= FB_VBLANK_VBLANKING;
847 if(reg1 & 0x02) ret |= FB_VBLANK_VSYNCING;
848 if(reg4 & 0x80) ret |= FB_VBLANK_HBLANKING;
849 (*vcount) = reg3 | ((reg4 & 0x70) << 4);
850 (*hcount) = reg2 | ((reg4 & 0x0f) << 8);
851
852 } else if(sisfballowretracecrt1(ivideo)) {
853
854 ret |= (FB_VBLANK_HAVE_VSYNC |
855 FB_VBLANK_HAVE_VBLANK |
856 FB_VBLANK_HAVE_VCOUNT |
857 FB_VBLANK_HAVE_HCOUNT);
858 reg1 = inSISREG(SISINPSTAT);
859 if(reg1 & 0x08) ret |= FB_VBLANK_VSYNCING;
860 if(reg1 & 0x01) ret |= FB_VBLANK_VBLANKING;
861 inSISIDXREG(SISCR,0x20,reg1);
862 inSISIDXREG(SISCR,0x1b,reg1);
863 inSISIDXREG(SISCR,0x1c,reg2);
864 inSISIDXREG(SISCR,0x1d,reg3);
865 (*vcount) = reg2 | ((reg3 & 0x07) << 8);
866 (*hcount) = (reg1 | ((reg3 & 0x10) << 4)) << 3;
867 }
868
869 return ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700870}
871
872static int
873sisfb_myblank(struct sis_video_info *ivideo, int blank)
874{
Thomas Winischhofer544393f2005-09-09 13:04:45 -0700875 u8 sr01, sr11, sr1f, cr63=0, p2_0, p1_13;
Richard Knutssonc30660ea2007-02-12 00:55:06 -0800876 bool backlight = true;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700877
Thomas Winischhofer544393f2005-09-09 13:04:45 -0700878 switch(blank) {
879 case FB_BLANK_UNBLANK: /* on */
880 sr01 = 0x00;
881 sr11 = 0x00;
882 sr1f = 0x00;
883 cr63 = 0x00;
884 p2_0 = 0x20;
885 p1_13 = 0x00;
Richard Knutssonc30660ea2007-02-12 00:55:06 -0800886 backlight = true;
Thomas Winischhofer544393f2005-09-09 13:04:45 -0700887 break;
888 case FB_BLANK_NORMAL: /* blank */
889 sr01 = 0x20;
890 sr11 = 0x00;
891 sr1f = 0x00;
892 cr63 = 0x00;
893 p2_0 = 0x20;
894 p1_13 = 0x00;
Richard Knutssonc30660ea2007-02-12 00:55:06 -0800895 backlight = true;
Thomas Winischhofer544393f2005-09-09 13:04:45 -0700896 break;
897 case FB_BLANK_VSYNC_SUSPEND: /* no vsync */
898 sr01 = 0x20;
899 sr11 = 0x08;
900 sr1f = 0x80;
901 cr63 = 0x40;
902 p2_0 = 0x40;
903 p1_13 = 0x80;
Richard Knutssonc30660ea2007-02-12 00:55:06 -0800904 backlight = false;
Thomas Winischhofer544393f2005-09-09 13:04:45 -0700905 break;
906 case FB_BLANK_HSYNC_SUSPEND: /* no hsync */
907 sr01 = 0x20;
908 sr11 = 0x08;
909 sr1f = 0x40;
910 cr63 = 0x40;
911 p2_0 = 0x80;
912 p1_13 = 0x40;
Richard Knutssonc30660ea2007-02-12 00:55:06 -0800913 backlight = false;
Thomas Winischhofer544393f2005-09-09 13:04:45 -0700914 break;
915 case FB_BLANK_POWERDOWN: /* off */
916 sr01 = 0x20;
917 sr11 = 0x08;
918 sr1f = 0xc0;
919 cr63 = 0x40;
920 p2_0 = 0xc0;
921 p1_13 = 0xc0;
Richard Knutssonc30660ea2007-02-12 00:55:06 -0800922 backlight = false;
Thomas Winischhofer544393f2005-09-09 13:04:45 -0700923 break;
924 default:
925 return 1;
926 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700927
Thomas Winischhofer544393f2005-09-09 13:04:45 -0700928 if(ivideo->currentvbflags & VB_DISPTYPE_CRT1) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700929
Thomas Winischhofer544393f2005-09-09 13:04:45 -0700930 if( (!ivideo->sisfb_thismonitor.datavalid) ||
931 ((ivideo->sisfb_thismonitor.datavalid) &&
932 (ivideo->sisfb_thismonitor.feature & 0xe0))) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700933
Thomas Winischhofer544393f2005-09-09 13:04:45 -0700934 if(ivideo->sisvga_engine == SIS_315_VGA) {
935 setSISIDXREG(SISCR, ivideo->SiS_Pr.SiS_MyCR63, 0xbf, cr63);
936 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700937
Thomas Winischhofer544393f2005-09-09 13:04:45 -0700938 if(!(sisfb_bridgeisslave(ivideo))) {
939 setSISIDXREG(SISSR, 0x01, ~0x20, sr01);
940 setSISIDXREG(SISSR, 0x1f, 0x3f, sr1f);
941 }
942 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700943
Thomas Winischhofer544393f2005-09-09 13:04:45 -0700944 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700945
Thomas Winischhofer544393f2005-09-09 13:04:45 -0700946 if(ivideo->currentvbflags & CRT2_LCD) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700947
Thomas Winischhofer544393f2005-09-09 13:04:45 -0700948 if(ivideo->vbflags2 & VB2_SISLVDSBRIDGE) {
949 if(backlight) {
950 SiS_SiS30xBLOn(&ivideo->SiS_Pr);
951 } else {
952 SiS_SiS30xBLOff(&ivideo->SiS_Pr);
953 }
954 } else if(ivideo->sisvga_engine == SIS_315_VGA) {
955#ifdef CONFIG_FB_SIS_315
956 if(ivideo->vbflags2 & VB2_CHRONTEL) {
957 if(backlight) {
958 SiS_Chrontel701xBLOn(&ivideo->SiS_Pr);
959 } else {
960 SiS_Chrontel701xBLOff(&ivideo->SiS_Pr);
961 }
962 }
963#endif
964 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700965
Thomas Winischhofer544393f2005-09-09 13:04:45 -0700966 if(((ivideo->sisvga_engine == SIS_300_VGA) &&
967 (ivideo->vbflags2 & (VB2_301|VB2_30xBDH|VB2_LVDS))) ||
968 ((ivideo->sisvga_engine == SIS_315_VGA) &&
969 ((ivideo->vbflags2 & (VB2_LVDS | VB2_CHRONTEL)) == VB2_LVDS))) {
970 setSISIDXREG(SISSR, 0x11, ~0x0c, sr11);
971 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700972
Thomas Winischhofer544393f2005-09-09 13:04:45 -0700973 if(ivideo->sisvga_engine == SIS_300_VGA) {
974 if((ivideo->vbflags2 & VB2_30xB) &&
975 (!(ivideo->vbflags2 & VB2_30xBDH))) {
976 setSISIDXREG(SISPART1, 0x13, 0x3f, p1_13);
977 }
978 } else if(ivideo->sisvga_engine == SIS_315_VGA) {
979 if((ivideo->vbflags2 & VB2_30xB) &&
980 (!(ivideo->vbflags2 & VB2_30xBDH))) {
981 setSISIDXREG(SISPART2, 0x00, 0x1f, p2_0);
982 }
983 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700984
Thomas Winischhofer544393f2005-09-09 13:04:45 -0700985 } else if(ivideo->currentvbflags & CRT2_VGA) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700986
Thomas Winischhofer544393f2005-09-09 13:04:45 -0700987 if(ivideo->vbflags2 & VB2_30xB) {
988 setSISIDXREG(SISPART2, 0x00, 0x1f, p2_0);
989 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700990
Thomas Winischhofer544393f2005-09-09 13:04:45 -0700991 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700992
Thomas Winischhofer544393f2005-09-09 13:04:45 -0700993 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700994}
995
Thomas Winischhofer544393f2005-09-09 13:04:45 -0700996/* ------------- Callbacks from init.c/init301.c -------------- */
997
998#ifdef CONFIG_FB_SIS_300
999unsigned int
1000sisfb_read_nbridge_pci_dword(struct SiS_Private *SiS_Pr, int reg)
1001{
1002 struct sis_video_info *ivideo = (struct sis_video_info *)SiS_Pr->ivideo;
1003 u32 val = 0;
1004
1005 pci_read_config_dword(ivideo->nbridge, reg, &val);
1006 return (unsigned int)val;
1007}
1008
1009void
1010sisfb_write_nbridge_pci_dword(struct SiS_Private *SiS_Pr, int reg, unsigned int val)
1011{
1012 struct sis_video_info *ivideo = (struct sis_video_info *)SiS_Pr->ivideo;
1013
1014 pci_write_config_dword(ivideo->nbridge, reg, (u32)val);
1015}
1016
1017unsigned int
1018sisfb_read_lpc_pci_dword(struct SiS_Private *SiS_Pr, int reg)
1019{
1020 struct sis_video_info *ivideo = (struct sis_video_info *)SiS_Pr->ivideo;
1021 u32 val = 0;
1022
1023 if(!ivideo->lpcdev) return 0;
1024
1025 pci_read_config_dword(ivideo->lpcdev, reg, &val);
1026 return (unsigned int)val;
1027}
1028#endif
1029
1030#ifdef CONFIG_FB_SIS_315
1031void
1032sisfb_write_nbridge_pci_byte(struct SiS_Private *SiS_Pr, int reg, unsigned char val)
1033{
1034 struct sis_video_info *ivideo = (struct sis_video_info *)SiS_Pr->ivideo;
1035
1036 pci_write_config_byte(ivideo->nbridge, reg, (u8)val);
1037}
1038
1039unsigned int
1040sisfb_read_mio_pci_word(struct SiS_Private *SiS_Pr, int reg)
1041{
1042 struct sis_video_info *ivideo = (struct sis_video_info *)SiS_Pr->ivideo;
1043 u16 val = 0;
1044
1045 if(!ivideo->lpcdev) return 0;
1046
1047 pci_read_config_word(ivideo->lpcdev, reg, &val);
1048 return (unsigned int)val;
1049}
1050#endif
1051
Linus Torvalds1da177e2005-04-16 15:20:36 -07001052/* ----------- FBDev related routines for all series ----------- */
1053
1054static int
1055sisfb_get_cmap_len(const struct fb_var_screeninfo *var)
1056{
1057 return (var->bits_per_pixel == 8) ? 256 : 16;
1058}
1059
1060static void
1061sisfb_set_vparms(struct sis_video_info *ivideo)
1062{
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001063 switch(ivideo->video_bpp) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001064 case 8:
1065 ivideo->DstColor = 0x0000;
1066 ivideo->SiS310_AccelDepth = 0x00000000;
1067 ivideo->video_cmap_len = 256;
1068 break;
1069 case 16:
1070 ivideo->DstColor = 0x8000;
1071 ivideo->SiS310_AccelDepth = 0x00010000;
1072 ivideo->video_cmap_len = 16;
1073 break;
1074 case 32:
1075 ivideo->DstColor = 0xC000;
1076 ivideo->SiS310_AccelDepth = 0x00020000;
1077 ivideo->video_cmap_len = 16;
1078 break;
1079 default:
1080 ivideo->video_cmap_len = 16;
1081 printk(KERN_ERR "sisfb: Unsupported depth %d", ivideo->video_bpp);
1082 ivideo->accel = 0;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001083 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001084}
1085
1086static int
1087sisfb_calc_maxyres(struct sis_video_info *ivideo, struct fb_var_screeninfo *var)
1088{
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001089 int maxyres = ivideo->sisfb_mem / (var->xres_virtual * (var->bits_per_pixel >> 3));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001090
1091 if(maxyres > 32767) maxyres = 32767;
1092
1093 return maxyres;
1094}
1095
1096static void
1097sisfb_calc_pitch(struct sis_video_info *ivideo, struct fb_var_screeninfo *var)
1098{
1099 ivideo->video_linelength = var->xres_virtual * (var->bits_per_pixel >> 3);
1100 ivideo->scrnpitchCRT1 = ivideo->video_linelength;
1101 if(!(ivideo->currentvbflags & CRT1_LCDA)) {
1102 if((var->vmode & FB_VMODE_MASK) == FB_VMODE_INTERLACED) {
1103 ivideo->scrnpitchCRT1 <<= 1;
1104 }
1105 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001106}
1107
1108static void
1109sisfb_set_pitch(struct sis_video_info *ivideo)
1110{
Richard Knutssonc30660ea2007-02-12 00:55:06 -08001111 bool isslavemode = false;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001112 unsigned short HDisplay1 = ivideo->scrnpitchCRT1 >> 3;
1113 unsigned short HDisplay2 = ivideo->video_linelength >> 3;
1114
Richard Knutssonc30660ea2007-02-12 00:55:06 -08001115 if(sisfb_bridgeisslave(ivideo)) isslavemode = true;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001116
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001117 /* We need to set pitch for CRT1 if bridge is in slave mode, too */
1118 if((ivideo->currentvbflags & VB_DISPTYPE_DISP1) || (isslavemode)) {
1119 outSISIDXREG(SISCR,0x13,(HDisplay1 & 0xFF));
1120 setSISIDXREG(SISSR,0x0E,0xF0,(HDisplay1 >> 8));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001121 }
1122
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001123 /* We must not set the pitch for CRT2 if bridge is in slave mode */
1124 if((ivideo->currentvbflags & VB_DISPTYPE_DISP2) && (!isslavemode)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001125 orSISIDXREG(SISPART1,ivideo->CRT2_write_enable,0x01);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001126 outSISIDXREG(SISPART1,0x07,(HDisplay2 & 0xFF));
1127 setSISIDXREG(SISPART1,0x09,0xF0,(HDisplay2 >> 8));
1128 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001129}
1130
1131static void
1132sisfb_bpp_to_var(struct sis_video_info *ivideo, struct fb_var_screeninfo *var)
1133{
1134 ivideo->video_cmap_len = sisfb_get_cmap_len(var);
1135
1136 switch(var->bits_per_pixel) {
1137 case 8:
1138 var->red.offset = var->green.offset = var->blue.offset = 0;
1139 var->red.length = var->green.length = var->blue.length = 6;
1140 break;
1141 case 16:
1142 var->red.offset = 11;
1143 var->red.length = 5;
1144 var->green.offset = 5;
1145 var->green.length = 6;
1146 var->blue.offset = 0;
1147 var->blue.length = 5;
1148 var->transp.offset = 0;
1149 var->transp.length = 0;
1150 break;
1151 case 32:
1152 var->red.offset = 16;
1153 var->red.length = 8;
1154 var->green.offset = 8;
1155 var->green.length = 8;
1156 var->blue.offset = 0;
1157 var->blue.length = 8;
1158 var->transp.offset = 24;
1159 var->transp.length = 8;
1160 break;
1161 }
1162}
1163
1164static int
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001165sisfb_set_mode(struct sis_video_info *ivideo, int clrscrn)
1166{
1167 unsigned short modeno = ivideo->mode_no;
1168
1169 /* >=2.6.12's fbcon clears the screen anyway */
1170#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,12)
1171 if(!clrscrn) modeno |= 0x80;
1172#else
1173 modeno |= 0x80;
1174#endif
1175
1176 outSISIDXREG(SISSR, IND_SIS_PASSWORD, SIS_PASSWORD);
1177
1178 sisfb_pre_setmode(ivideo);
1179
Richard Knutssonc30660ea2007-02-12 00:55:06 -08001180 if(!SiSSetMode(&ivideo->SiS_Pr, modeno)) {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001181 printk(KERN_ERR "sisfb: Setting mode[0x%x] failed\n", ivideo->mode_no);
1182 return -EINVAL;
1183 }
1184
1185 outSISIDXREG(SISSR, IND_SIS_PASSWORD, SIS_PASSWORD);
1186
1187 sisfb_post_setmode(ivideo);
1188
1189 return 0;
1190}
1191
1192
1193static int
Linus Torvalds1da177e2005-04-16 15:20:36 -07001194sisfb_do_set_var(struct fb_var_screeninfo *var, int isactive, struct fb_info *info)
1195{
1196 struct sis_video_info *ivideo = (struct sis_video_info *)info->par;
1197 unsigned int htotal = 0, vtotal = 0;
1198 unsigned int drate = 0, hrate = 0;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001199 int found_mode = 0, ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001200 int old_mode;
1201 u32 pixclock;
1202
1203 htotal = var->left_margin + var->xres + var->right_margin + var->hsync_len;
1204
1205 vtotal = var->upper_margin + var->lower_margin + var->vsync_len;
1206
1207 pixclock = var->pixclock;
1208
1209 if((var->vmode & FB_VMODE_MASK) == FB_VMODE_NONINTERLACED) {
1210 vtotal += var->yres;
1211 vtotal <<= 1;
1212 } else if((var->vmode & FB_VMODE_MASK) == FB_VMODE_DOUBLE) {
1213 vtotal += var->yres;
1214 vtotal <<= 2;
1215 } else if((var->vmode & FB_VMODE_MASK) == FB_VMODE_INTERLACED) {
1216 vtotal += var->yres;
1217 vtotal <<= 1;
1218 } else vtotal += var->yres;
1219
1220 if(!(htotal) || !(vtotal)) {
1221 DPRINTK("sisfb: Invalid 'var' information\n");
1222 return -EINVAL;
1223 }
1224
1225 if(pixclock && htotal && vtotal) {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001226 drate = 1000000000 / pixclock;
1227 hrate = (drate * 1000) / htotal;
1228 ivideo->refresh_rate = (unsigned int) (hrate * 2 / vtotal);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001229 } else {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001230 ivideo->refresh_rate = 60;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001231 }
1232
1233 old_mode = ivideo->sisfb_mode_idx;
1234 ivideo->sisfb_mode_idx = 0;
1235
1236 while( (sisbios_mode[ivideo->sisfb_mode_idx].mode_no[0] != 0) &&
1237 (sisbios_mode[ivideo->sisfb_mode_idx].xres <= var->xres) ) {
1238 if( (sisbios_mode[ivideo->sisfb_mode_idx].xres == var->xres) &&
1239 (sisbios_mode[ivideo->sisfb_mode_idx].yres == var->yres) &&
1240 (sisbios_mode[ivideo->sisfb_mode_idx].bpp == var->bits_per_pixel)) {
1241 ivideo->mode_no = sisbios_mode[ivideo->sisfb_mode_idx].mode_no[ivideo->mni];
1242 found_mode = 1;
1243 break;
1244 }
1245 ivideo->sisfb_mode_idx++;
1246 }
1247
1248 if(found_mode) {
1249 ivideo->sisfb_mode_idx = sisfb_validate_mode(ivideo,
1250 ivideo->sisfb_mode_idx, ivideo->currentvbflags);
1251 } else {
1252 ivideo->sisfb_mode_idx = -1;
1253 }
1254
1255 if(ivideo->sisfb_mode_idx < 0) {
1256 printk(KERN_ERR "sisfb: Mode %dx%dx%d not supported\n", var->xres,
1257 var->yres, var->bits_per_pixel);
1258 ivideo->sisfb_mode_idx = old_mode;
1259 return -EINVAL;
1260 }
1261
Adrian Bunka9e60e52007-11-14 16:59:02 -08001262 ivideo->mode_no = sisbios_mode[ivideo->sisfb_mode_idx].mode_no[ivideo->mni];
1263
Linus Torvalds1da177e2005-04-16 15:20:36 -07001264 if(sisfb_search_refresh_rate(ivideo, ivideo->refresh_rate, ivideo->sisfb_mode_idx) == 0) {
1265 ivideo->rate_idx = sisbios_mode[ivideo->sisfb_mode_idx].rate_idx;
1266 ivideo->refresh_rate = 60;
1267 }
1268
Linus Torvalds1da177e2005-04-16 15:20:36 -07001269 if(isactive) {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001270 /* If acceleration to be used? Need to know
1271 * before pre/post_set_mode()
1272 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001273 ivideo->accel = 0;
1274#if defined(FBINFO_HWACCEL_DISABLED) && defined(FBINFO_HWACCEL_XPAN)
1275#ifdef STUPID_ACCELF_TEXT_SHIT
1276 if(var->accel_flags & FB_ACCELF_TEXT) {
1277 info->flags &= ~FBINFO_HWACCEL_DISABLED;
1278 } else {
1279 info->flags |= FBINFO_HWACCEL_DISABLED;
1280 }
1281#endif
1282 if(!(info->flags & FBINFO_HWACCEL_DISABLED)) ivideo->accel = -1;
1283#else
1284 if(var->accel_flags & FB_ACCELF_TEXT) ivideo->accel = -1;
1285#endif
1286
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001287 if((ret = sisfb_set_mode(ivideo, 1))) {
1288 return ret;
1289 }
1290
1291 ivideo->video_bpp = sisbios_mode[ivideo->sisfb_mode_idx].bpp;
1292 ivideo->video_width = sisbios_mode[ivideo->sisfb_mode_idx].xres;
1293 ivideo->video_height = sisbios_mode[ivideo->sisfb_mode_idx].yres;
1294
1295 sisfb_calc_pitch(ivideo, var);
1296 sisfb_set_pitch(ivideo);
1297
Linus Torvalds1da177e2005-04-16 15:20:36 -07001298 sisfb_set_vparms(ivideo);
1299
1300 ivideo->current_width = ivideo->video_width;
1301 ivideo->current_height = ivideo->video_height;
1302 ivideo->current_bpp = ivideo->video_bpp;
1303 ivideo->current_htotal = htotal;
1304 ivideo->current_vtotal = vtotal;
1305 ivideo->current_linelength = ivideo->video_linelength;
1306 ivideo->current_pixclock = var->pixclock;
1307 ivideo->current_refresh_rate = ivideo->refresh_rate;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001308 ivideo->sisfb_lastrates[ivideo->mode_no] = ivideo->refresh_rate;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001309 }
1310
1311 return 0;
1312}
1313
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001314static void
1315sisfb_set_base_CRT1(struct sis_video_info *ivideo, unsigned int base)
1316{
1317 outSISIDXREG(SISSR, IND_SIS_PASSWORD, SIS_PASSWORD);
1318
1319 outSISIDXREG(SISCR, 0x0D, base & 0xFF);
1320 outSISIDXREG(SISCR, 0x0C, (base >> 8) & 0xFF);
1321 outSISIDXREG(SISSR, 0x0D, (base >> 16) & 0xFF);
1322 if(ivideo->sisvga_engine == SIS_315_VGA) {
1323 setSISIDXREG(SISSR, 0x37, 0xFE, (base >> 24) & 0x01);
1324 }
1325}
1326
1327static void
1328sisfb_set_base_CRT2(struct sis_video_info *ivideo, unsigned int base)
1329{
1330 if(ivideo->currentvbflags & VB_DISPTYPE_DISP2) {
1331 orSISIDXREG(SISPART1, ivideo->CRT2_write_enable, 0x01);
1332 outSISIDXREG(SISPART1, 0x06, (base & 0xFF));
1333 outSISIDXREG(SISPART1, 0x05, ((base >> 8) & 0xFF));
1334 outSISIDXREG(SISPART1, 0x04, ((base >> 16) & 0xFF));
1335 if(ivideo->sisvga_engine == SIS_315_VGA) {
1336 setSISIDXREG(SISPART1, 0x02, 0x7F, ((base >> 24) & 0x01) << 7);
1337 }
1338 }
1339}
1340
Linus Torvalds1da177e2005-04-16 15:20:36 -07001341static int
1342sisfb_pan_var(struct sis_video_info *ivideo, struct fb_var_screeninfo *var)
1343{
Linus Torvalds1da177e2005-04-16 15:20:36 -07001344 if(var->xoffset > (var->xres_virtual - var->xres)) {
1345 return -EINVAL;
1346 }
1347 if(var->yoffset > (var->yres_virtual - var->yres)) {
1348 return -EINVAL;
1349 }
1350
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001351 ivideo->current_base = (var->yoffset * var->xres_virtual) + var->xoffset;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001352
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001353 /* calculate base bpp dep. */
1354 switch(var->bits_per_pixel) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001355 case 32:
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001356 break;
1357 case 16:
1358 ivideo->current_base >>= 1;
1359 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001360 case 8:
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001361 default:
1362 ivideo->current_base >>= 2;
1363 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001364 }
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001365
1366 ivideo->current_base += (ivideo->video_offset >> 2);
1367
1368 sisfb_set_base_CRT1(ivideo, ivideo->current_base);
1369 sisfb_set_base_CRT2(ivideo, ivideo->current_base);
1370
Linus Torvalds1da177e2005-04-16 15:20:36 -07001371 return 0;
1372}
1373
Linus Torvalds1da177e2005-04-16 15:20:36 -07001374static int
1375sisfb_open(struct fb_info *info, int user)
1376{
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001377 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001378}
1379
1380static int
1381sisfb_release(struct fb_info *info, int user)
1382{
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001383 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001384}
1385
1386static int
1387sisfb_setcolreg(unsigned regno, unsigned red, unsigned green, unsigned blue,
1388 unsigned transp, struct fb_info *info)
1389{
1390 struct sis_video_info *ivideo = (struct sis_video_info *)info->par;
1391
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001392 if(regno >= sisfb_get_cmap_len(&info->var))
1393 return 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001394
1395 switch(info->var.bits_per_pixel) {
1396 case 8:
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001397 outSISREG(SISDACA, regno);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001398 outSISREG(SISDACD, (red >> 10));
1399 outSISREG(SISDACD, (green >> 10));
1400 outSISREG(SISDACD, (blue >> 10));
1401 if(ivideo->currentvbflags & VB_DISPTYPE_DISP2) {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001402 outSISREG(SISDAC2A, regno);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001403 outSISREG(SISDAC2D, (red >> 8));
1404 outSISREG(SISDAC2D, (green >> 8));
1405 outSISREG(SISDAC2D, (blue >> 8));
1406 }
1407 break;
1408 case 16:
Antonino A. Daplas000d5332007-07-17 04:05:44 -07001409 if (regno >= 16)
1410 break;
1411
Linus Torvalds1da177e2005-04-16 15:20:36 -07001412 ((u32 *)(info->pseudo_palette))[regno] =
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001413 (red & 0xf800) |
1414 ((green & 0xfc00) >> 5) |
1415 ((blue & 0xf800) >> 11);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001416 break;
1417 case 32:
Antonino A. Daplas000d5332007-07-17 04:05:44 -07001418 if (regno >= 16)
1419 break;
1420
Linus Torvalds1da177e2005-04-16 15:20:36 -07001421 red >>= 8;
1422 green >>= 8;
1423 blue >>= 8;
1424 ((u32 *)(info->pseudo_palette))[regno] =
1425 (red << 16) | (green << 8) | (blue);
1426 break;
1427 }
1428 return 0;
1429}
1430
1431static int
1432sisfb_set_par(struct fb_info *info)
1433{
1434 int err;
1435
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001436 if((err = sisfb_do_set_var(&info->var, 1, info)))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001437 return err;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001438
Linus Torvalds1da177e2005-04-16 15:20:36 -07001439#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,10)
1440 sisfb_get_fix(&info->fix, info->currcon, info);
1441#else
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001442 sisfb_get_fix(&info->fix, -1, info);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001443#endif
1444 return 0;
1445}
1446
1447static int
1448sisfb_check_var(struct fb_var_screeninfo *var, struct fb_info *info)
1449{
1450 struct sis_video_info *ivideo = (struct sis_video_info *)info->par;
1451 unsigned int htotal = 0, vtotal = 0, myrateindex = 0;
1452 unsigned int drate = 0, hrate = 0, maxyres;
1453 int found_mode = 0;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001454 int refresh_rate, search_idx, tidx;
Richard Knutssonc30660ea2007-02-12 00:55:06 -08001455 bool recalc_clock = false;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001456 u32 pixclock;
1457
1458 htotal = var->left_margin + var->xres + var->right_margin + var->hsync_len;
1459
1460 vtotal = var->upper_margin + var->lower_margin + var->vsync_len;
1461
1462 pixclock = var->pixclock;
1463
1464 if((var->vmode & FB_VMODE_MASK) == FB_VMODE_NONINTERLACED) {
1465 vtotal += var->yres;
1466 vtotal <<= 1;
1467 } else if((var->vmode & FB_VMODE_MASK) == FB_VMODE_DOUBLE) {
1468 vtotal += var->yres;
1469 vtotal <<= 2;
1470 } else if((var->vmode & FB_VMODE_MASK) == FB_VMODE_INTERLACED) {
1471 vtotal += var->yres;
1472 vtotal <<= 1;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001473 } else
1474 vtotal += var->yres;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001475
1476 if(!(htotal) || !(vtotal)) {
1477 SISFAIL("sisfb: no valid timing data");
1478 }
1479
1480 search_idx = 0;
1481 while( (sisbios_mode[search_idx].mode_no[0] != 0) &&
1482 (sisbios_mode[search_idx].xres <= var->xres) ) {
1483 if( (sisbios_mode[search_idx].xres == var->xres) &&
1484 (sisbios_mode[search_idx].yres == var->yres) &&
1485 (sisbios_mode[search_idx].bpp == var->bits_per_pixel)) {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001486 if((tidx = sisfb_validate_mode(ivideo, search_idx,
1487 ivideo->currentvbflags)) > 0) {
1488 found_mode = 1;
1489 search_idx = tidx;
1490 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001491 }
1492 }
1493 search_idx++;
1494 }
1495
1496 if(!found_mode) {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001497 search_idx = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001498 while(sisbios_mode[search_idx].mode_no[0] != 0) {
1499 if( (var->xres <= sisbios_mode[search_idx].xres) &&
1500 (var->yres <= sisbios_mode[search_idx].yres) &&
1501 (var->bits_per_pixel == sisbios_mode[search_idx].bpp) ) {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001502 if((tidx = sisfb_validate_mode(ivideo,search_idx,
1503 ivideo->currentvbflags)) > 0) {
1504 found_mode = 1;
1505 search_idx = tidx;
1506 break;
1507 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001508 }
1509 search_idx++;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001510 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001511 if(found_mode) {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001512 printk(KERN_DEBUG
1513 "sisfb: Adapted from %dx%dx%d to %dx%dx%d\n",
1514 var->xres, var->yres, var->bits_per_pixel,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001515 sisbios_mode[search_idx].xres,
1516 sisbios_mode[search_idx].yres,
1517 var->bits_per_pixel);
1518 var->xres = sisbios_mode[search_idx].xres;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001519 var->yres = sisbios_mode[search_idx].yres;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001520 } else {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001521 printk(KERN_ERR
1522 "sisfb: Failed to find supported mode near %dx%dx%d\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07001523 var->xres, var->yres, var->bits_per_pixel);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001524 return -EINVAL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001525 }
1526 }
1527
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001528 if( ((ivideo->vbflags2 & VB2_LVDS) ||
1529 ((ivideo->vbflags2 & VB2_30xBDH) && (ivideo->currentvbflags & CRT2_LCD))) &&
Linus Torvalds1da177e2005-04-16 15:20:36 -07001530 (var->bits_per_pixel == 8) ) {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001531 /* Slave modes on LVDS and 301B-DH */
1532 refresh_rate = 60;
Richard Knutssonc30660ea2007-02-12 00:55:06 -08001533 recalc_clock = true;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001534 } else if( (ivideo->current_htotal == htotal) &&
1535 (ivideo->current_vtotal == vtotal) &&
1536 (ivideo->current_pixclock == pixclock) ) {
1537 /* x=x & y=y & c=c -> assume depth change */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001538 drate = 1000000000 / pixclock;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001539 hrate = (drate * 1000) / htotal;
1540 refresh_rate = (unsigned int) (hrate * 2 / vtotal);
1541 } else if( ( (ivideo->current_htotal != htotal) ||
1542 (ivideo->current_vtotal != vtotal) ) &&
1543 (ivideo->current_pixclock == var->pixclock) ) {
1544 /* x!=x | y!=y & c=c -> invalid pixclock */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001545 if(ivideo->sisfb_lastrates[sisbios_mode[search_idx].mode_no[ivideo->mni]]) {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001546 refresh_rate =
1547 ivideo->sisfb_lastrates[sisbios_mode[search_idx].mode_no[ivideo->mni]];
Linus Torvalds1da177e2005-04-16 15:20:36 -07001548 } else if(ivideo->sisfb_parm_rate != -1) {
1549 /* Sic, sisfb_parm_rate - want to know originally desired rate here */
1550 refresh_rate = ivideo->sisfb_parm_rate;
1551 } else {
1552 refresh_rate = 60;
1553 }
Richard Knutssonc30660ea2007-02-12 00:55:06 -08001554 recalc_clock = true;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001555 } else if((pixclock) && (htotal) && (vtotal)) {
1556 drate = 1000000000 / pixclock;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001557 hrate = (drate * 1000) / htotal;
1558 refresh_rate = (unsigned int) (hrate * 2 / vtotal);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001559 } else if(ivideo->current_refresh_rate) {
1560 refresh_rate = ivideo->current_refresh_rate;
Richard Knutssonc30660ea2007-02-12 00:55:06 -08001561 recalc_clock = true;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001562 } else {
1563 refresh_rate = 60;
Richard Knutssonc30660ea2007-02-12 00:55:06 -08001564 recalc_clock = true;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001565 }
1566
1567 myrateindex = sisfb_search_refresh_rate(ivideo, refresh_rate, search_idx);
1568
1569 /* Eventually recalculate timing and clock */
1570 if(recalc_clock) {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001571 if(!myrateindex) myrateindex = sisbios_mode[search_idx].rate_idx;
1572 var->pixclock = (u32) (1000000000 / sisfb_mode_rate_to_dclock(&ivideo->SiS_Pr,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001573 sisbios_mode[search_idx].mode_no[ivideo->mni],
1574 myrateindex));
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001575 sisfb_mode_rate_to_ddata(&ivideo->SiS_Pr,
1576 sisbios_mode[search_idx].mode_no[ivideo->mni],
1577 myrateindex, var);
1578 if((var->vmode & FB_VMODE_MASK) == FB_VMODE_DOUBLE) {
1579 var->pixclock <<= 1;
1580 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001581 }
1582
1583 if(ivideo->sisfb_thismonitor.datavalid) {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001584 if(!sisfb_verify_rate(ivideo, &ivideo->sisfb_thismonitor, search_idx,
1585 myrateindex, refresh_rate)) {
1586 printk(KERN_INFO
1587 "sisfb: WARNING: Refresh rate exceeds monitor specs!\n");
1588 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001589 }
1590
1591 /* Adapt RGB settings */
1592 sisfb_bpp_to_var(ivideo, var);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001593
Linus Torvalds1da177e2005-04-16 15:20:36 -07001594 /* Sanity check for offsets */
1595 if(var->xoffset < 0) var->xoffset = 0;
1596 if(var->yoffset < 0) var->yoffset = 0;
1597
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001598 if(var->xres > var->xres_virtual)
1599 var->xres_virtual = var->xres;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001600
1601 if(ivideo->sisfb_ypan) {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001602 maxyres = sisfb_calc_maxyres(ivideo, var);
1603 if(ivideo->sisfb_max) {
1604 var->yres_virtual = maxyres;
1605 } else {
1606 if(var->yres_virtual > maxyres) {
1607 var->yres_virtual = maxyres;
1608 }
1609 }
1610 if(var->yres_virtual <= var->yres) {
1611 var->yres_virtual = var->yres;
1612 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001613 } else {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001614 if(var->yres != var->yres_virtual) {
1615 var->yres_virtual = var->yres;
1616 }
1617 var->xoffset = 0;
1618 var->yoffset = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001619 }
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001620
Linus Torvalds1da177e2005-04-16 15:20:36 -07001621 /* Truncate offsets to maximum if too high */
1622 if(var->xoffset > var->xres_virtual - var->xres) {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001623 var->xoffset = var->xres_virtual - var->xres - 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001624 }
1625
1626 if(var->yoffset > var->yres_virtual - var->yres) {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001627 var->yoffset = var->yres_virtual - var->yres - 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001628 }
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001629
Linus Torvalds1da177e2005-04-16 15:20:36 -07001630 /* Set everything else to 0 */
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001631 var->red.msb_right =
1632 var->green.msb_right =
1633 var->blue.msb_right =
1634 var->transp.offset =
1635 var->transp.length =
1636 var->transp.msb_right = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001637
1638 return 0;
1639}
1640
1641static int
1642sisfb_pan_display(struct fb_var_screeninfo *var, struct fb_info* info)
1643{
1644 struct sis_video_info *ivideo = (struct sis_video_info *)info->par;
1645 int err;
1646
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001647 if(var->xoffset > (var->xres_virtual - var->xres))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001648 return -EINVAL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001649
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001650 if(var->yoffset > (var->yres_virtual - var->yres))
1651 return -EINVAL;
1652
1653 if(var->vmode & FB_VMODE_YWRAP)
1654 return -EINVAL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001655
1656 if(var->xoffset + info->var.xres > info->var.xres_virtual ||
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001657 var->yoffset + info->var.yres > info->var.yres_virtual)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001658 return -EINVAL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001659
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001660 if((err = sisfb_pan_var(ivideo, var)) < 0)
1661 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001662
1663 info->var.xoffset = var->xoffset;
1664 info->var.yoffset = var->yoffset;
1665
1666 return 0;
1667}
1668
1669static int
1670sisfb_blank(int blank, struct fb_info *info)
1671{
1672 struct sis_video_info *ivideo = (struct sis_video_info *)info->par;
1673
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001674 return sisfb_myblank(ivideo, blank);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001675}
1676
Linus Torvalds1da177e2005-04-16 15:20:36 -07001677/* ----------- FBDev related routines for all series ---------- */
1678
Christoph Hellwig67a66802006-01-14 13:21:25 -08001679#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,15)
1680static int sisfb_ioctl(struct fb_info *info, unsigned int cmd,
1681 unsigned long arg)
1682#else
1683static int sisfb_ioctl(struct inode *inode, struct file *file,
1684 unsigned int cmd, unsigned long arg,
1685 struct fb_info *info)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001686#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -07001687{
1688 struct sis_video_info *ivideo = (struct sis_video_info *)info->par;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001689 struct sis_memreq sismemreq;
1690 struct fb_vblank sisvbblank;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001691 u32 gpu32 = 0;
1692#ifndef __user
1693#define __user
1694#endif
1695 u32 __user *argp = (u32 __user *)arg;
1696
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001697 switch(cmd) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001698 case FBIO_ALLOC:
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001699 if(!capable(CAP_SYS_RAWIO))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001700 return -EPERM;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001701
1702 if(copy_from_user(&sismemreq, (void __user *)arg, sizeof(sismemreq)))
1703 return -EFAULT;
1704
Linus Torvalds1da177e2005-04-16 15:20:36 -07001705 sis_malloc(&sismemreq);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001706
Linus Torvalds1da177e2005-04-16 15:20:36 -07001707 if(copy_to_user((void __user *)arg, &sismemreq, sizeof(sismemreq))) {
1708 sis_free((u32)sismemreq.offset);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001709 return -EFAULT;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001710 }
1711 break;
1712
1713 case FBIO_FREE:
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001714 if(!capable(CAP_SYS_RAWIO))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001715 return -EPERM;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001716
1717 if(get_user(gpu32, argp))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001718 return -EFAULT;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001719
Linus Torvalds1da177e2005-04-16 15:20:36 -07001720 sis_free(gpu32);
1721 break;
1722
1723 case FBIOGET_VBLANK:
1724 sisvbblank.count = 0;
1725 sisvbblank.flags = sisfb_setupvbblankflags(ivideo, &sisvbblank.vcount, &sisvbblank.hcount);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001726
1727 if(copy_to_user((void __user *)arg, &sisvbblank, sizeof(sisvbblank)))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001728 return -EFAULT;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001729
Linus Torvalds1da177e2005-04-16 15:20:36 -07001730 break;
1731
1732 case SISFB_GET_INFO_SIZE:
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001733 return put_user(sizeof(struct sisfb_info), argp);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001734
1735 case SISFB_GET_INFO_OLD:
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001736 if(ivideo->warncount++ < 10)
1737 printk(KERN_INFO
1738 "sisfb: Deprecated ioctl call received - update your application!\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001739 case SISFB_GET_INFO: /* For communication with X driver */
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001740 ivideo->sisfb_infoblock.sisfb_id = SISFB_ID;
1741 ivideo->sisfb_infoblock.sisfb_version = VER_MAJOR;
1742 ivideo->sisfb_infoblock.sisfb_revision = VER_MINOR;
1743 ivideo->sisfb_infoblock.sisfb_patchlevel = VER_LEVEL;
1744 ivideo->sisfb_infoblock.chip_id = ivideo->chip_id;
1745 ivideo->sisfb_infoblock.sisfb_pci_vendor = ivideo->chip_vendor;
1746 ivideo->sisfb_infoblock.memory = ivideo->video_size / 1024;
1747 ivideo->sisfb_infoblock.heapstart = ivideo->heapstart / 1024;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001748 if(ivideo->modechanged) {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001749 ivideo->sisfb_infoblock.fbvidmode = ivideo->mode_no;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001750 } else {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001751 ivideo->sisfb_infoblock.fbvidmode = ivideo->modeprechange;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001752 }
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001753 ivideo->sisfb_infoblock.sisfb_caps = ivideo->caps;
1754 ivideo->sisfb_infoblock.sisfb_tqlen = ivideo->cmdQueueSize / 1024;
1755 ivideo->sisfb_infoblock.sisfb_pcibus = ivideo->pcibus;
1756 ivideo->sisfb_infoblock.sisfb_pcislot = ivideo->pcislot;
1757 ivideo->sisfb_infoblock.sisfb_pcifunc = ivideo->pcifunc;
1758 ivideo->sisfb_infoblock.sisfb_lcdpdc = ivideo->detectedpdc;
1759 ivideo->sisfb_infoblock.sisfb_lcdpdca = ivideo->detectedpdca;
1760 ivideo->sisfb_infoblock.sisfb_lcda = ivideo->detectedlcda;
1761 ivideo->sisfb_infoblock.sisfb_vbflags = ivideo->vbflags;
1762 ivideo->sisfb_infoblock.sisfb_currentvbflags = ivideo->currentvbflags;
1763 ivideo->sisfb_infoblock.sisfb_scalelcd = ivideo->SiS_Pr.UsePanelScaler;
1764 ivideo->sisfb_infoblock.sisfb_specialtiming = ivideo->SiS_Pr.SiS_CustomT;
1765 ivideo->sisfb_infoblock.sisfb_haveemi = ivideo->SiS_Pr.HaveEMI ? 1 : 0;
1766 ivideo->sisfb_infoblock.sisfb_haveemilcd = ivideo->SiS_Pr.HaveEMILCD ? 1 : 0;
1767 ivideo->sisfb_infoblock.sisfb_emi30 = ivideo->SiS_Pr.EMI_30;
1768 ivideo->sisfb_infoblock.sisfb_emi31 = ivideo->SiS_Pr.EMI_31;
1769 ivideo->sisfb_infoblock.sisfb_emi32 = ivideo->SiS_Pr.EMI_32;
1770 ivideo->sisfb_infoblock.sisfb_emi33 = ivideo->SiS_Pr.EMI_33;
1771 ivideo->sisfb_infoblock.sisfb_tvxpos = (u16)(ivideo->tvxpos + 32);
1772 ivideo->sisfb_infoblock.sisfb_tvypos = (u16)(ivideo->tvypos + 32);
1773 ivideo->sisfb_infoblock.sisfb_heapsize = ivideo->sisfb_heap_size / 1024;
1774 ivideo->sisfb_infoblock.sisfb_videooffset = ivideo->video_offset;
1775 ivideo->sisfb_infoblock.sisfb_curfstn = ivideo->curFSTN;
1776 ivideo->sisfb_infoblock.sisfb_curdstn = ivideo->curDSTN;
1777 ivideo->sisfb_infoblock.sisfb_vbflags2 = ivideo->vbflags2;
1778 ivideo->sisfb_infoblock.sisfb_can_post = ivideo->sisfb_can_post ? 1 : 0;
1779 ivideo->sisfb_infoblock.sisfb_card_posted = ivideo->sisfb_card_posted ? 1 : 0;
1780 ivideo->sisfb_infoblock.sisfb_was_boot_device = ivideo->sisfb_was_boot_device ? 1 : 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001781
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001782 if(copy_to_user((void __user *)arg, &ivideo->sisfb_infoblock,
1783 sizeof(ivideo->sisfb_infoblock)))
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 break;
1787
1788 case SISFB_GET_VBRSTATUS_OLD:
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001789 if(ivideo->warncount++ < 10)
1790 printk(KERN_INFO
1791 "sisfb: Deprecated ioctl call received - update your application!\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001792 case SISFB_GET_VBRSTATUS:
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001793 if(sisfb_CheckVBRetrace(ivideo))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001794 return put_user((u32)1, argp);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001795 else
Linus Torvalds1da177e2005-04-16 15:20:36 -07001796 return put_user((u32)0, argp);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001797
1798 case SISFB_GET_AUTOMAXIMIZE_OLD:
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001799 if(ivideo->warncount++ < 10)
1800 printk(KERN_INFO
1801 "sisfb: Deprecated ioctl call received - update your application!\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001802 case SISFB_GET_AUTOMAXIMIZE:
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001803 if(ivideo->sisfb_max)
1804 return put_user((u32)1, argp);
1805 else
1806 return put_user((u32)0, argp);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001807
1808 case SISFB_SET_AUTOMAXIMIZE_OLD:
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001809 if(ivideo->warncount++ < 10)
1810 printk(KERN_INFO
1811 "sisfb: Deprecated ioctl call received - update your application!\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001812 case SISFB_SET_AUTOMAXIMIZE:
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001813 if(get_user(gpu32, argp))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001814 return -EFAULT;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001815
Linus Torvalds1da177e2005-04-16 15:20:36 -07001816 ivideo->sisfb_max = (gpu32) ? 1 : 0;
1817 break;
1818
1819 case SISFB_SET_TVPOSOFFSET:
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001820 if(get_user(gpu32, argp))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001821 return -EFAULT;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001822
Linus Torvalds1da177e2005-04-16 15:20:36 -07001823 sisfb_set_TVxposoffset(ivideo, ((int)(gpu32 >> 16)) - 32);
1824 sisfb_set_TVyposoffset(ivideo, ((int)(gpu32 & 0xffff)) - 32);
1825 break;
1826
1827 case SISFB_GET_TVPOSOFFSET:
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001828 return put_user((u32)(((ivideo->tvxpos+32)<<16)|((ivideo->tvypos+32)&0xffff)),
1829 argp);
1830
1831 case SISFB_COMMAND:
1832 if(copy_from_user(&ivideo->sisfb_command, (void __user *)arg,
1833 sizeof(struct sisfb_cmd)))
1834 return -EFAULT;
1835
1836 sisfb_handle_command(ivideo, &ivideo->sisfb_command);
1837
1838 if(copy_to_user((void __user *)arg, &ivideo->sisfb_command,
1839 sizeof(struct sisfb_cmd)))
1840 return -EFAULT;
1841
1842 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001843
1844 case SISFB_SET_LOCK:
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001845 if(get_user(gpu32, argp))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001846 return -EFAULT;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001847
Linus Torvalds1da177e2005-04-16 15:20:36 -07001848 ivideo->sisfblocked = (gpu32) ? 1 : 0;
1849 break;
1850
1851 default:
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001852#ifdef SIS_NEW_CONFIG_COMPAT
Linus Torvalds1da177e2005-04-16 15:20:36 -07001853 return -ENOIOCTLCMD;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001854#else
1855 return -EINVAL;
1856#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -07001857 }
1858 return 0;
1859}
1860
Linus Torvalds1da177e2005-04-16 15:20:36 -07001861static int
1862sisfb_get_fix(struct fb_fix_screeninfo *fix, int con, struct fb_info *info)
1863{
1864 struct sis_video_info *ivideo = (struct sis_video_info *)info->par;
1865
1866 memset(fix, 0, sizeof(struct fb_fix_screeninfo));
1867
1868 strcpy(fix->id, ivideo->myid);
1869
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001870 fix->smem_start = ivideo->video_base + ivideo->video_offset;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001871 fix->smem_len = ivideo->sisfb_mem;
1872 fix->type = FB_TYPE_PACKED_PIXELS;
1873 fix->type_aux = 0;
1874 fix->visual = (ivideo->video_bpp == 8) ? FB_VISUAL_PSEUDOCOLOR : FB_VISUAL_TRUECOLOR;
1875 fix->xpanstep = 1;
1876 fix->ypanstep = (ivideo->sisfb_ypan) ? 1 : 0;
1877 fix->ywrapstep = 0;
1878 fix->line_length = ivideo->video_linelength;
1879 fix->mmio_start = ivideo->mmio_base;
1880 fix->mmio_len = ivideo->mmio_size;
1881 if(ivideo->sisvga_engine == SIS_300_VGA) {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001882 fix->accel = FB_ACCEL_SIS_GLAMOUR;
1883 } else if((ivideo->chip == SIS_330) ||
1884 (ivideo->chip == SIS_760) ||
1885 (ivideo->chip == SIS_761)) {
1886 fix->accel = FB_ACCEL_SIS_XABRE;
1887 } else if(ivideo->chip == XGI_20) {
1888 fix->accel = FB_ACCEL_XGI_VOLARI_Z;
1889 } else if(ivideo->chip >= XGI_40) {
1890 fix->accel = FB_ACCEL_XGI_VOLARI_V;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001891 } else {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001892 fix->accel = FB_ACCEL_SIS_GLAMOUR_2;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001893 }
1894
1895 return 0;
1896}
1897
1898/* ---------------- fb_ops structures ----------------- */
1899
Linus Torvalds1da177e2005-04-16 15:20:36 -07001900static struct fb_ops sisfb_ops = {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001901 .owner = THIS_MODULE,
1902 .fb_open = sisfb_open,
1903 .fb_release = sisfb_release,
1904 .fb_check_var = sisfb_check_var,
1905 .fb_set_par = sisfb_set_par,
1906 .fb_setcolreg = sisfb_setcolreg,
1907 .fb_pan_display = sisfb_pan_display,
1908 .fb_blank = sisfb_blank,
1909 .fb_fillrect = fbcon_sis_fillrect,
1910 .fb_copyarea = fbcon_sis_copyarea,
1911 .fb_imageblit = cfb_imageblit,
Antonino A. Daplasc465e052005-11-07 01:00:35 -08001912#ifdef CONFIG_FB_SOFT_CURSOR
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001913 .fb_cursor = soft_cursor,
Antonino A. Daplasc465e052005-11-07 01:00:35 -08001914#endif
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001915 .fb_sync = fbcon_sis_sync,
1916#ifdef SIS_NEW_CONFIG_COMPAT
Christoph Hellwig67a66802006-01-14 13:21:25 -08001917 .fb_compat_ioctl= sisfb_ioctl,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001918#endif
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001919 .fb_ioctl = sisfb_ioctl
Linus Torvalds1da177e2005-04-16 15:20:36 -07001920};
Linus Torvalds1da177e2005-04-16 15:20:36 -07001921
1922/* ---------------- Chip generation dependent routines ---------------- */
1923
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001924static struct pci_dev * __devinit
1925sisfb_get_northbridge(int basechipid)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001926{
1927 struct pci_dev *pdev = NULL;
1928 int nbridgenum, nbridgeidx, i;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001929 static const unsigned short nbridgeids[] = {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001930 PCI_DEVICE_ID_SI_540, /* for SiS 540 VGA */
1931 PCI_DEVICE_ID_SI_630, /* for SiS 630/730 VGA */
1932 PCI_DEVICE_ID_SI_730,
1933 PCI_DEVICE_ID_SI_550, /* for SiS 550 VGA */
1934 PCI_DEVICE_ID_SI_650, /* for SiS 650/651/740 VGA */
1935 PCI_DEVICE_ID_SI_651,
1936 PCI_DEVICE_ID_SI_740,
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001937 PCI_DEVICE_ID_SI_661, /* for SiS 661/741/660/760/761 VGA */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001938 PCI_DEVICE_ID_SI_741,
1939 PCI_DEVICE_ID_SI_660,
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001940 PCI_DEVICE_ID_SI_760,
1941 PCI_DEVICE_ID_SI_761
Linus Torvalds1da177e2005-04-16 15:20:36 -07001942 };
1943
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001944 switch(basechipid) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001945#ifdef CONFIG_FB_SIS_300
1946 case SIS_540: nbridgeidx = 0; nbridgenum = 1; break;
1947 case SIS_630: nbridgeidx = 1; nbridgenum = 2; break;
1948#endif
1949#ifdef CONFIG_FB_SIS_315
1950 case SIS_550: nbridgeidx = 3; nbridgenum = 1; break;
1951 case SIS_650: nbridgeidx = 4; nbridgenum = 3; break;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001952 case SIS_660: nbridgeidx = 7; nbridgenum = 5; break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001953#endif
1954 default: return NULL;
1955 }
1956 for(i = 0; i < nbridgenum; i++) {
Adrian Bunk0959f0c2007-05-08 00:39:50 -07001957 if((pdev = pci_get_device(PCI_VENDOR_ID_SI,
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001958 nbridgeids[nbridgeidx+i], NULL)))
1959 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001960 }
1961 return pdev;
1962}
1963
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001964static int __devinit
1965sisfb_get_dram_size(struct sis_video_info *ivideo)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001966{
1967#if defined(CONFIG_FB_SIS_300) || defined(CONFIG_FB_SIS_315)
1968 u8 reg;
1969#endif
1970
1971 ivideo->video_size = 0;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001972 ivideo->UMAsize = ivideo->LFBsize = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001973
1974 switch(ivideo->chip) {
1975#ifdef CONFIG_FB_SIS_300
1976 case SIS_300:
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001977 inSISIDXREG(SISSR, 0x14, reg);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001978 ivideo->video_size = ((reg & 0x3F) + 1) << 20;
1979 break;
1980 case SIS_540:
1981 case SIS_630:
1982 case SIS_730:
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001983 if(!ivideo->nbridge)
1984 return -1;
1985 pci_read_config_byte(ivideo->nbridge, 0x63, &reg);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001986 ivideo->video_size = 1 << (((reg & 0x70) >> 4) + 21);
1987 break;
1988#endif
1989#ifdef CONFIG_FB_SIS_315
1990 case SIS_315H:
1991 case SIS_315PRO:
1992 case SIS_315:
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001993 inSISIDXREG(SISSR, 0x14, reg);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001994 ivideo->video_size = (1 << ((reg & 0xf0) >> 4)) << 20;
1995 switch((reg >> 2) & 0x03) {
1996 case 0x01:
1997 case 0x03:
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001998 ivideo->video_size <<= 1;
1999 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002000 case 0x02:
Thomas Winischhofer544393f2005-09-09 13:04:45 -07002001 ivideo->video_size += (ivideo->video_size/2);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002002 }
Thomas Winischhofer544393f2005-09-09 13:04:45 -07002003 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002004 case SIS_330:
Thomas Winischhofer544393f2005-09-09 13:04:45 -07002005 inSISIDXREG(SISSR, 0x14, reg);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002006 ivideo->video_size = (1 << ((reg & 0xf0) >> 4)) << 20;
2007 if(reg & 0x0c) ivideo->video_size <<= 1;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07002008 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002009 case SIS_550:
2010 case SIS_650:
2011 case SIS_740:
Thomas Winischhofer544393f2005-09-09 13:04:45 -07002012 inSISIDXREG(SISSR, 0x14, reg);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002013 ivideo->video_size = (((reg & 0x3f) + 1) << 2) << 20;
2014 break;
2015 case SIS_661:
2016 case SIS_741:
Thomas Winischhofer544393f2005-09-09 13:04:45 -07002017 inSISIDXREG(SISCR, 0x79, reg);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002018 ivideo->video_size = (1 << ((reg & 0xf0) >> 4)) << 20;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07002019 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002020 case SIS_660:
2021 case SIS_760:
Thomas Winischhofer544393f2005-09-09 13:04:45 -07002022 case SIS_761:
Linus Torvalds1da177e2005-04-16 15:20:36 -07002023 inSISIDXREG(SISCR, 0x79, reg);
2024 reg = (reg & 0xf0) >> 4;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07002025 if(reg) {
2026 ivideo->video_size = (1 << reg) << 20;
2027 ivideo->UMAsize = ivideo->video_size;
2028 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002029 inSISIDXREG(SISCR, 0x78, reg);
2030 reg &= 0x30;
2031 if(reg) {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07002032 if(reg == 0x10) {
2033 ivideo->LFBsize = (32 << 20);
2034 } else {
2035 ivideo->LFBsize = (64 << 20);
2036 }
2037 ivideo->video_size += ivideo->LFBsize;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002038 }
Thomas Winischhofer544393f2005-09-09 13:04:45 -07002039 break;
2040 case SIS_340:
2041 case XGI_20:
2042 case XGI_40:
2043 inSISIDXREG(SISSR, 0x14, reg);
2044 ivideo->video_size = (1 << ((reg & 0xf0) >> 4)) << 20;
2045 if(ivideo->chip != XGI_20) {
2046 reg = (reg & 0x0c) >> 2;
2047 if(ivideo->revision_id == 2) {
2048 if(reg & 0x01) reg = 0x02;
2049 else reg = 0x00;
2050 }
2051 if(reg == 0x02) ivideo->video_size <<= 1;
2052 else if(reg == 0x03) ivideo->video_size <<= 2;
2053 }
2054 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002055#endif
2056 default:
2057 return -1;
2058 }
2059 return 0;
2060}
2061
2062/* -------------- video bridge device detection --------------- */
2063
Thomas Winischhofer544393f2005-09-09 13:04:45 -07002064static void __devinit
2065sisfb_detect_VB_connect(struct sis_video_info *ivideo)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002066{
2067 u8 cr32, temp;
2068
Thomas Winischhofer544393f2005-09-09 13:04:45 -07002069 /* No CRT2 on XGI Z7 */
2070 if(ivideo->chip == XGI_20) {
2071 ivideo->sisfb_crt1off = 0;
2072 return;
2073 }
2074
Linus Torvalds1da177e2005-04-16 15:20:36 -07002075#ifdef CONFIG_FB_SIS_300
2076 if(ivideo->sisvga_engine == SIS_300_VGA) {
2077 inSISIDXREG(SISSR, 0x17, temp);
2078 if((temp & 0x0F) && (ivideo->chip != SIS_300)) {
2079 /* PAL/NTSC is stored on SR16 on such machines */
2080 if(!(ivideo->vbflags & (TV_PAL | TV_NTSC | TV_PALM | TV_PALN))) {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07002081 inSISIDXREG(SISSR, 0x16, temp);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002082 if(temp & 0x20)
2083 ivideo->vbflags |= TV_PAL;
2084 else
2085 ivideo->vbflags |= TV_NTSC;
2086 }
2087 }
2088 }
2089#endif
2090
2091 inSISIDXREG(SISCR, 0x32, cr32);
2092
2093 if(cr32 & SIS_CRT1) {
2094 ivideo->sisfb_crt1off = 0;
2095 } else {
2096 ivideo->sisfb_crt1off = (cr32 & 0xDF) ? 1 : 0;
2097 }
2098
2099 ivideo->vbflags &= ~(CRT2_TV | CRT2_LCD | CRT2_VGA);
2100
2101 if(cr32 & SIS_VB_TV) ivideo->vbflags |= CRT2_TV;
2102 if(cr32 & SIS_VB_LCD) ivideo->vbflags |= CRT2_LCD;
2103 if(cr32 & SIS_VB_CRT2) ivideo->vbflags |= CRT2_VGA;
2104
2105 /* Check given parms for hardware compatibility.
2106 * (Cannot do this in the search_xx routines since we don't
2107 * know what hardware we are running on then)
2108 */
2109
2110 if(ivideo->chip != SIS_550) {
2111 ivideo->sisfb_dstn = ivideo->sisfb_fstn = 0;
2112 }
2113
2114 if(ivideo->sisfb_tvplug != -1) {
2115 if( (ivideo->sisvga_engine != SIS_315_VGA) ||
Thomas Winischhofer544393f2005-09-09 13:04:45 -07002116 (!(ivideo->vbflags2 & VB2_SISYPBPRBRIDGE)) ) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002117 if(ivideo->sisfb_tvplug & TV_YPBPR) {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07002118 ivideo->sisfb_tvplug = -1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002119 printk(KERN_ERR "sisfb: YPbPr not supported\n");
2120 }
2121 }
2122 }
2123 if(ivideo->sisfb_tvplug != -1) {
2124 if( (ivideo->sisvga_engine != SIS_315_VGA) ||
Thomas Winischhofer544393f2005-09-09 13:04:45 -07002125 (!(ivideo->vbflags2 & VB2_SISHIVISIONBRIDGE)) ) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002126 if(ivideo->sisfb_tvplug & TV_HIVISION) {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07002127 ivideo->sisfb_tvplug = -1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002128 printk(KERN_ERR "sisfb: HiVision not supported\n");
2129 }
2130 }
2131 }
2132 if(ivideo->sisfb_tvstd != -1) {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07002133 if( (!(ivideo->vbflags2 & VB2_SISBRIDGE)) &&
2134 (!((ivideo->sisvga_engine == SIS_315_VGA) &&
2135 (ivideo->vbflags2 & VB2_CHRONTEL))) ) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002136 if(ivideo->sisfb_tvstd & (TV_PALN | TV_PALN | TV_NTSCJ)) {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07002137 ivideo->sisfb_tvstd = -1;
2138 printk(KERN_ERR "sisfb: PALM/PALN/NTSCJ not supported\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002139 }
2140 }
2141 }
2142
2143 /* Detect/set TV plug & type */
2144 if(ivideo->sisfb_tvplug != -1) {
2145 ivideo->vbflags |= ivideo->sisfb_tvplug;
2146 } else {
2147 if(cr32 & SIS_VB_YPBPR) ivideo->vbflags |= (TV_YPBPR|TV_YPBPR525I); /* default: 480i */
2148 else if(cr32 & SIS_VB_HIVISION) ivideo->vbflags |= TV_HIVISION;
2149 else if(cr32 & SIS_VB_SCART) ivideo->vbflags |= TV_SCART;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07002150 else {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002151 if(cr32 & SIS_VB_SVIDEO) ivideo->vbflags |= TV_SVIDEO;
2152 if(cr32 & SIS_VB_COMPOSITE) ivideo->vbflags |= TV_AVIDEO;
2153 }
2154 }
2155
2156 if(!(ivideo->vbflags & (TV_YPBPR | TV_HIVISION))) {
2157 if(ivideo->sisfb_tvstd != -1) {
2158 ivideo->vbflags &= ~(TV_NTSC | TV_PAL | TV_PALM | TV_PALN | TV_NTSCJ);
2159 ivideo->vbflags |= ivideo->sisfb_tvstd;
2160 }
2161 if(ivideo->vbflags & TV_SCART) {
2162 ivideo->vbflags &= ~(TV_NTSC | TV_PALM | TV_PALN | TV_NTSCJ);
2163 ivideo->vbflags |= TV_PAL;
2164 }
2165 if(!(ivideo->vbflags & (TV_PAL | TV_NTSC | TV_PALM | TV_PALN | TV_NTSCJ))) {
2166 if(ivideo->sisvga_engine == SIS_300_VGA) {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07002167 inSISIDXREG(SISSR, 0x38, temp);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002168 if(temp & 0x01) ivideo->vbflags |= TV_PAL;
2169 else ivideo->vbflags |= TV_NTSC;
2170 } else if((ivideo->chip <= SIS_315PRO) || (ivideo->chip >= SIS_330)) {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07002171 inSISIDXREG(SISSR, 0x38, temp);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002172 if(temp & 0x01) ivideo->vbflags |= TV_PAL;
2173 else ivideo->vbflags |= TV_NTSC;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07002174 } else {
2175 inSISIDXREG(SISCR, 0x79, temp);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002176 if(temp & 0x20) ivideo->vbflags |= TV_PAL;
2177 else ivideo->vbflags |= TV_NTSC;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07002178 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002179 }
2180 }
2181
2182 /* Copy forceCRT1 option to CRT1off if option is given */
Thomas Winischhofer544393f2005-09-09 13:04:45 -07002183 if(ivideo->sisfb_forcecrt1 != -1) {
2184 ivideo->sisfb_crt1off = (ivideo->sisfb_forcecrt1) ? 0 : 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002185 }
2186}
2187
2188/* ------------------ Sensing routines ------------------ */
2189
Richard Knutssonc30660ea2007-02-12 00:55:06 -08002190static bool __devinit
Thomas Winischhofer544393f2005-09-09 13:04:45 -07002191sisfb_test_DDC1(struct sis_video_info *ivideo)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002192{
2193 unsigned short old;
2194 int count = 48;
2195
2196 old = SiS_ReadDDC1Bit(&ivideo->SiS_Pr);
2197 do {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07002198 if(old != SiS_ReadDDC1Bit(&ivideo->SiS_Pr)) break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002199 } while(count--);
Richard Knutssonc30660ea2007-02-12 00:55:06 -08002200 return (count != -1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002201}
2202
Thomas Winischhofer544393f2005-09-09 13:04:45 -07002203static void __devinit
2204sisfb_sense_crt1(struct sis_video_info *ivideo)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002205{
Richard Knutssonc30660ea2007-02-12 00:55:06 -08002206 bool mustwait = false;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002207 u8 sr1F, cr17;
2208#ifdef CONFIG_FB_SIS_315
2209 u8 cr63=0;
2210#endif
2211 u16 temp = 0xffff;
2212 int i;
2213
2214 inSISIDXREG(SISSR,0x1F,sr1F);
2215 orSISIDXREG(SISSR,0x1F,0x04);
2216 andSISIDXREG(SISSR,0x1F,0x3F);
Richard Knutssonc30660ea2007-02-12 00:55:06 -08002217 if(sr1F & 0xc0) mustwait = true;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002218
2219#ifdef CONFIG_FB_SIS_315
2220 if(ivideo->sisvga_engine == SIS_315_VGA) {
2221 inSISIDXREG(SISCR,ivideo->SiS_Pr.SiS_MyCR63,cr63);
2222 cr63 &= 0x40;
2223 andSISIDXREG(SISCR,ivideo->SiS_Pr.SiS_MyCR63,0xBF);
2224 }
2225#endif
2226
2227 inSISIDXREG(SISCR,0x17,cr17);
2228 cr17 &= 0x80;
2229 if(!cr17) {
2230 orSISIDXREG(SISCR,0x17,0x80);
Richard Knutssonc30660ea2007-02-12 00:55:06 -08002231 mustwait = true;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002232 outSISIDXREG(SISSR, 0x00, 0x01);
2233 outSISIDXREG(SISSR, 0x00, 0x03);
2234 }
2235
2236 if(mustwait) {
2237 for(i=0; i < 10; i++) sisfbwaitretracecrt1(ivideo);
2238 }
2239
2240#ifdef CONFIG_FB_SIS_315
2241 if(ivideo->chip >= SIS_330) {
2242 andSISIDXREG(SISCR,0x32,~0x20);
2243 if(ivideo->chip >= SIS_340) {
2244 outSISIDXREG(SISCR, 0x57, 0x4a);
2245 } else {
2246 outSISIDXREG(SISCR, 0x57, 0x5f);
2247 }
2248 orSISIDXREG(SISCR, 0x53, 0x02);
2249 while((inSISREG(SISINPSTAT)) & 0x01) break;
2250 while(!((inSISREG(SISINPSTAT)) & 0x01)) break;
2251 if((inSISREG(SISMISCW)) & 0x10) temp = 1;
2252 andSISIDXREG(SISCR, 0x53, 0xfd);
2253 andSISIDXREG(SISCR, 0x57, 0x00);
2254 }
2255#endif
2256
2257 if(temp == 0xffff) {
2258 i = 3;
2259 do {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07002260 temp = SiS_HandleDDC(&ivideo->SiS_Pr, ivideo->vbflags,
2261 ivideo->sisvga_engine, 0, 0, NULL, ivideo->vbflags2);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002262 } while(((temp == 0) || (temp == 0xffff)) && i--);
2263
2264 if((temp == 0) || (temp == 0xffff)) {
2265 if(sisfb_test_DDC1(ivideo)) temp = 1;
2266 }
2267 }
2268
2269 if((temp) && (temp != 0xffff)) {
2270 orSISIDXREG(SISCR,0x32,0x20);
2271 }
2272
2273#ifdef CONFIG_FB_SIS_315
2274 if(ivideo->sisvga_engine == SIS_315_VGA) {
2275 setSISIDXREG(SISCR,ivideo->SiS_Pr.SiS_MyCR63,0xBF,cr63);
2276 }
2277#endif
2278
2279 setSISIDXREG(SISCR,0x17,0x7F,cr17);
2280
2281 outSISIDXREG(SISSR,0x1F,sr1F);
2282}
2283
2284/* Determine and detect attached devices on SiS30x */
Thomas Winischhofer544393f2005-09-09 13:04:45 -07002285static void __devinit
2286SiS_SenseLCD(struct sis_video_info *ivideo)
2287{
2288 unsigned char buffer[256];
2289 unsigned short temp, realcrtno, i;
2290 u8 reg, cr37 = 0, paneltype = 0;
2291 u16 xres, yres;
2292
Richard Knutssonc30660ea2007-02-12 00:55:06 -08002293 ivideo->SiS_Pr.PanelSelfDetected = false;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07002294
2295 /* LCD detection only for TMDS bridges */
2296 if(!(ivideo->vbflags2 & VB2_SISTMDSBRIDGE))
2297 return;
2298 if(ivideo->vbflags2 & VB2_30xBDH)
2299 return;
2300
2301 /* If LCD already set up by BIOS, skip it */
2302 inSISIDXREG(SISCR, 0x32, reg);
2303 if(reg & 0x08)
2304 return;
2305
2306 realcrtno = 1;
2307 if(ivideo->SiS_Pr.DDCPortMixup)
2308 realcrtno = 0;
2309
2310 /* Check DDC capabilities */
2311 temp = SiS_HandleDDC(&ivideo->SiS_Pr, ivideo->vbflags, ivideo->sisvga_engine,
2312 realcrtno, 0, &buffer[0], ivideo->vbflags2);
2313
2314 if((!temp) || (temp == 0xffff) || (!(temp & 0x02)))
2315 return;
2316
2317 /* Read DDC data */
2318 i = 3; /* Number of retrys */
2319 do {
2320 temp = SiS_HandleDDC(&ivideo->SiS_Pr, ivideo->vbflags,
2321 ivideo->sisvga_engine, realcrtno, 1,
2322 &buffer[0], ivideo->vbflags2);
2323 } while((temp) && i--);
2324
2325 if(temp)
2326 return;
2327
2328 /* No digital device */
2329 if(!(buffer[0x14] & 0x80))
2330 return;
2331
2332 /* First detailed timing preferred timing? */
2333 if(!(buffer[0x18] & 0x02))
2334 return;
2335
2336 xres = buffer[0x38] | ((buffer[0x3a] & 0xf0) << 4);
2337 yres = buffer[0x3b] | ((buffer[0x3d] & 0xf0) << 4);
2338
2339 switch(xres) {
2340 case 1024:
2341 if(yres == 768)
2342 paneltype = 0x02;
2343 break;
2344 case 1280:
2345 if(yres == 1024)
2346 paneltype = 0x03;
2347 break;
2348 case 1600:
2349 if((yres == 1200) && (ivideo->vbflags2 & VB2_30xC))
2350 paneltype = 0x0b;
2351 break;
2352 }
2353
2354 if(!paneltype)
2355 return;
2356
2357 if(buffer[0x23])
2358 cr37 |= 0x10;
2359
2360 if((buffer[0x47] & 0x18) == 0x18)
2361 cr37 |= ((((buffer[0x47] & 0x06) ^ 0x06) << 5) | 0x20);
2362 else
2363 cr37 |= 0xc0;
2364
2365 outSISIDXREG(SISCR, 0x36, paneltype);
2366 cr37 &= 0xf1;
2367 setSISIDXREG(SISCR, 0x37, 0x0c, cr37);
2368 orSISIDXREG(SISCR, 0x32, 0x08);
2369
Richard Knutssonc30660ea2007-02-12 00:55:06 -08002370 ivideo->SiS_Pr.PanelSelfDetected = true;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07002371}
2372
2373static int __devinit
2374SISDoSense(struct sis_video_info *ivideo, u16 type, u16 test)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002375{
2376 int temp, mytest, result, i, j;
2377
2378 for(j = 0; j < 10; j++) {
2379 result = 0;
2380 for(i = 0; i < 3; i++) {
2381 mytest = test;
2382 outSISIDXREG(SISPART4,0x11,(type & 0x00ff));
2383 temp = (type >> 8) | (mytest & 0x00ff);
2384 setSISIDXREG(SISPART4,0x10,0xe0,temp);
2385 SiS_DDC2Delay(&ivideo->SiS_Pr, 0x1500);
2386 mytest >>= 8;
2387 mytest &= 0x7f;
2388 inSISIDXREG(SISPART4,0x03,temp);
2389 temp ^= 0x0e;
2390 temp &= mytest;
2391 if(temp == mytest) result++;
2392#if 1
2393 outSISIDXREG(SISPART4,0x11,0x00);
2394 andSISIDXREG(SISPART4,0x10,0xe0);
2395 SiS_DDC2Delay(&ivideo->SiS_Pr, 0x1000);
2396#endif
2397 }
2398 if((result == 0) || (result >= 2)) break;
2399 }
Thomas Winischhofer544393f2005-09-09 13:04:45 -07002400 return result;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002401}
2402
Thomas Winischhofer544393f2005-09-09 13:04:45 -07002403static void __devinit
2404SiS_Sense30x(struct sis_video_info *ivideo)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002405{
2406 u8 backupP4_0d,backupP2_00,backupP2_4d,backupSR_1e,biosflag=0;
2407 u16 svhs=0, svhs_c=0;
2408 u16 cvbs=0, cvbs_c=0;
2409 u16 vga2=0, vga2_c=0;
2410 int myflag, result;
2411 char stdstr[] = "sisfb: Detected";
2412 char tvstr[] = "TV connected to";
2413
Thomas Winischhofer544393f2005-09-09 13:04:45 -07002414 if(ivideo->vbflags2 & VB2_301) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002415 svhs = 0x00b9; cvbs = 0x00b3; vga2 = 0x00d1;
2416 inSISIDXREG(SISPART4,0x01,myflag);
2417 if(myflag & 0x04) {
2418 svhs = 0x00dd; cvbs = 0x00ee; vga2 = 0x00fd;
2419 }
Thomas Winischhofer544393f2005-09-09 13:04:45 -07002420 } else if(ivideo->vbflags2 & (VB2_301B | VB2_302B)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002421 svhs = 0x016b; cvbs = 0x0174; vga2 = 0x0190;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07002422 } else if(ivideo->vbflags2 & (VB2_301LV | VB2_302LV)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002423 svhs = 0x0200; cvbs = 0x0100;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07002424 } else if(ivideo->vbflags2 & (VB2_301C | VB2_302ELV | VB2_307T | VB2_307LV)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002425 svhs = 0x016b; cvbs = 0x0110; vga2 = 0x0190;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07002426 } else
2427 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002428
2429 vga2_c = 0x0e08; svhs_c = 0x0404; cvbs_c = 0x0804;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07002430 if(ivideo->vbflags & (VB2_301LV|VB2_302LV|VB2_302ELV|VB2_307LV)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002431 svhs_c = 0x0408; cvbs_c = 0x0808;
2432 }
Thomas Winischhofer544393f2005-09-09 13:04:45 -07002433
Linus Torvalds1da177e2005-04-16 15:20:36 -07002434 biosflag = 2;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07002435 if(ivideo->haveXGIROM) {
2436 biosflag = ivideo->bios_abase[0x58] & 0x03;
2437 } else if(ivideo->newrom) {
2438 if(ivideo->bios_abase[0x5d] & 0x04) biosflag |= 0x01;
2439 } else if(ivideo->sisvga_engine == SIS_300_VGA) {
2440 if(ivideo->bios_abase) {
2441 biosflag = ivideo->bios_abase[0xfe] & 0x03;
2442 }
2443 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002444
2445 if(ivideo->chip == SIS_300) {
2446 inSISIDXREG(SISSR,0x3b,myflag);
2447 if(!(myflag & 0x01)) vga2 = vga2_c = 0;
2448 }
2449
Thomas Winischhofer544393f2005-09-09 13:04:45 -07002450 if(!(ivideo->vbflags2 & VB2_SISVGA2BRIDGE)) {
2451 vga2 = vga2_c = 0;
2452 }
2453
Linus Torvalds1da177e2005-04-16 15:20:36 -07002454 inSISIDXREG(SISSR,0x1e,backupSR_1e);
2455 orSISIDXREG(SISSR,0x1e,0x20);
2456
2457 inSISIDXREG(SISPART4,0x0d,backupP4_0d);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07002458 if(ivideo->vbflags2 & VB2_30xC) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002459 setSISIDXREG(SISPART4,0x0d,~0x07,0x01);
2460 } else {
2461 orSISIDXREG(SISPART4,0x0d,0x04);
2462 }
2463 SiS_DDC2Delay(&ivideo->SiS_Pr, 0x2000);
2464
2465 inSISIDXREG(SISPART2,0x00,backupP2_00);
2466 outSISIDXREG(SISPART2,0x00,((backupP2_00 | 0x1c) & 0xfc));
2467
2468 inSISIDXREG(SISPART2,0x4d,backupP2_4d);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07002469 if(ivideo->vbflags2 & VB2_SISYPBPRBRIDGE) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002470 outSISIDXREG(SISPART2,0x4d,(backupP2_4d & ~0x10));
2471 }
2472
Thomas Winischhofer544393f2005-09-09 13:04:45 -07002473 if(!(ivideo->vbflags2 & VB2_30xCLV)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002474 SISDoSense(ivideo, 0, 0);
2475 }
2476
2477 andSISIDXREG(SISCR, 0x32, ~0x14);
2478
2479 if(vga2_c || vga2) {
2480 if(SISDoSense(ivideo, vga2, vga2_c)) {
2481 if(biosflag & 0x01) {
2482 printk(KERN_INFO "%s %s SCART output\n", stdstr, tvstr);
2483 orSISIDXREG(SISCR, 0x32, 0x04);
2484 } else {
2485 printk(KERN_INFO "%s secondary VGA connection\n", stdstr);
2486 orSISIDXREG(SISCR, 0x32, 0x10);
2487 }
2488 }
2489 }
2490
2491 andSISIDXREG(SISCR, 0x32, 0x3f);
2492
Thomas Winischhofer544393f2005-09-09 13:04:45 -07002493 if(ivideo->vbflags2 & VB2_30xCLV) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002494 orSISIDXREG(SISPART4,0x0d,0x04);
2495 }
2496
Thomas Winischhofer544393f2005-09-09 13:04:45 -07002497 if((ivideo->sisvga_engine == SIS_315_VGA) && (ivideo->vbflags2 & VB2_SISYPBPRBRIDGE)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002498 outSISIDXREG(SISPART2,0x4d,(backupP2_4d | 0x10));
2499 SiS_DDC2Delay(&ivideo->SiS_Pr, 0x2000);
2500 if((result = SISDoSense(ivideo, svhs, 0x0604))) {
2501 if((result = SISDoSense(ivideo, cvbs, 0x0804))) {
2502 printk(KERN_INFO "%s %s YPbPr component output\n", stdstr, tvstr);
2503 orSISIDXREG(SISCR,0x32,0x80);
2504 }
2505 }
2506 outSISIDXREG(SISPART2,0x4d,backupP2_4d);
2507 }
2508
2509 andSISIDXREG(SISCR, 0x32, ~0x03);
2510
2511 if(!(ivideo->vbflags & TV_YPBPR)) {
2512 if((result = SISDoSense(ivideo, svhs, svhs_c))) {
2513 printk(KERN_INFO "%s %s SVIDEO output\n", stdstr, tvstr);
2514 orSISIDXREG(SISCR, 0x32, 0x02);
2515 }
2516 if((biosflag & 0x02) || (!result)) {
2517 if(SISDoSense(ivideo, cvbs, cvbs_c)) {
2518 printk(KERN_INFO "%s %s COMPOSITE output\n", stdstr, tvstr);
2519 orSISIDXREG(SISCR, 0x32, 0x01);
2520 }
2521 }
2522 }
2523
2524 SISDoSense(ivideo, 0, 0);
2525
2526 outSISIDXREG(SISPART2,0x00,backupP2_00);
2527 outSISIDXREG(SISPART4,0x0d,backupP4_0d);
2528 outSISIDXREG(SISSR,0x1e,backupSR_1e);
2529
Thomas Winischhofer544393f2005-09-09 13:04:45 -07002530 if(ivideo->vbflags2 & VB2_30xCLV) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002531 inSISIDXREG(SISPART2,0x00,biosflag);
2532 if(biosflag & 0x20) {
2533 for(myflag = 2; myflag > 0; myflag--) {
2534 biosflag ^= 0x20;
2535 outSISIDXREG(SISPART2,0x00,biosflag);
2536 }
2537 }
2538 }
2539
2540 outSISIDXREG(SISPART2,0x00,backupP2_00);
2541}
2542
2543/* Determine and detect attached TV's on Chrontel */
Thomas Winischhofer544393f2005-09-09 13:04:45 -07002544static void __devinit
2545SiS_SenseCh(struct sis_video_info *ivideo)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002546{
2547#if defined(CONFIG_FB_SIS_300) || defined(CONFIG_FB_SIS_315)
2548 u8 temp1, temp2;
2549 char stdstr[] = "sisfb: Chrontel: Detected TV connected to";
2550#endif
2551#ifdef CONFIG_FB_SIS_300
2552 unsigned char test[3];
2553 int i;
2554#endif
2555
2556 if(ivideo->chip < SIS_315H) {
2557
2558#ifdef CONFIG_FB_SIS_300
2559 ivideo->SiS_Pr.SiS_IF_DEF_CH70xx = 1; /* Chrontel 700x */
2560 SiS_SetChrontelGPIO(&ivideo->SiS_Pr, 0x9c); /* Set general purpose IO for Chrontel communication */
2561 SiS_DDC2Delay(&ivideo->SiS_Pr, 1000);
2562 temp1 = SiS_GetCH700x(&ivideo->SiS_Pr, 0x25);
2563 /* See Chrontel TB31 for explanation */
2564 temp2 = SiS_GetCH700x(&ivideo->SiS_Pr, 0x0e);
2565 if(((temp2 & 0x07) == 0x01) || (temp2 & 0x04)) {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07002566 SiS_SetCH700x(&ivideo->SiS_Pr, 0x0e, 0x0b);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002567 SiS_DDC2Delay(&ivideo->SiS_Pr, 300);
2568 }
2569 temp2 = SiS_GetCH700x(&ivideo->SiS_Pr, 0x25);
2570 if(temp2 != temp1) temp1 = temp2;
2571
2572 if((temp1 >= 0x22) && (temp1 <= 0x50)) {
2573 /* Read power status */
2574 temp1 = SiS_GetCH700x(&ivideo->SiS_Pr, 0x0e);
2575 if((temp1 & 0x03) != 0x03) {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07002576 /* Power all outputs */
2577 SiS_SetCH700x(&ivideo->SiS_Pr, 0x0e,0x0b);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002578 SiS_DDC2Delay(&ivideo->SiS_Pr, 300);
2579 }
2580 /* Sense connected TV devices */
2581 for(i = 0; i < 3; i++) {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07002582 SiS_SetCH700x(&ivideo->SiS_Pr, 0x10, 0x01);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002583 SiS_DDC2Delay(&ivideo->SiS_Pr, 0x96);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07002584 SiS_SetCH700x(&ivideo->SiS_Pr, 0x10, 0x00);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002585 SiS_DDC2Delay(&ivideo->SiS_Pr, 0x96);
2586 temp1 = SiS_GetCH700x(&ivideo->SiS_Pr, 0x10);
2587 if(!(temp1 & 0x08)) test[i] = 0x02;
2588 else if(!(temp1 & 0x02)) test[i] = 0x01;
2589 else test[i] = 0;
2590 SiS_DDC2Delay(&ivideo->SiS_Pr, 0x96);
2591 }
2592
2593 if(test[0] == test[1]) temp1 = test[0];
2594 else if(test[0] == test[2]) temp1 = test[0];
2595 else if(test[1] == test[2]) temp1 = test[1];
2596 else {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07002597 printk(KERN_INFO
Linus Torvalds1da177e2005-04-16 15:20:36 -07002598 "sisfb: TV detection unreliable - test results varied\n");
2599 temp1 = test[2];
2600 }
2601 if(temp1 == 0x02) {
2602 printk(KERN_INFO "%s SVIDEO output\n", stdstr);
2603 ivideo->vbflags |= TV_SVIDEO;
2604 orSISIDXREG(SISCR, 0x32, 0x02);
2605 andSISIDXREG(SISCR, 0x32, ~0x05);
2606 } else if (temp1 == 0x01) {
2607 printk(KERN_INFO "%s CVBS output\n", stdstr);
2608 ivideo->vbflags |= TV_AVIDEO;
2609 orSISIDXREG(SISCR, 0x32, 0x01);
2610 andSISIDXREG(SISCR, 0x32, ~0x06);
2611 } else {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07002612 SiS_SetCH70xxANDOR(&ivideo->SiS_Pr, 0x0e, 0x01, 0xF8);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002613 andSISIDXREG(SISCR, 0x32, ~0x07);
2614 }
2615 } else if(temp1 == 0) {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07002616 SiS_SetCH70xxANDOR(&ivideo->SiS_Pr, 0x0e, 0x01, 0xF8);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002617 andSISIDXREG(SISCR, 0x32, ~0x07);
2618 }
2619 /* Set general purpose IO for Chrontel communication */
2620 SiS_SetChrontelGPIO(&ivideo->SiS_Pr, 0x00);
2621#endif
2622
2623 } else {
2624
2625#ifdef CONFIG_FB_SIS_315
2626 ivideo->SiS_Pr.SiS_IF_DEF_CH70xx = 2; /* Chrontel 7019 */
Thomas Winischhofer544393f2005-09-09 13:04:45 -07002627 temp1 = SiS_GetCH701x(&ivideo->SiS_Pr, 0x49);
2628 SiS_SetCH701x(&ivideo->SiS_Pr, 0x49, 0x20);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002629 SiS_DDC2Delay(&ivideo->SiS_Pr, 0x96);
2630 temp2 = SiS_GetCH701x(&ivideo->SiS_Pr, 0x20);
2631 temp2 |= 0x01;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07002632 SiS_SetCH701x(&ivideo->SiS_Pr, 0x20, temp2);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002633 SiS_DDC2Delay(&ivideo->SiS_Pr, 0x96);
2634 temp2 ^= 0x01;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07002635 SiS_SetCH701x(&ivideo->SiS_Pr, 0x20, temp2);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002636 SiS_DDC2Delay(&ivideo->SiS_Pr, 0x96);
2637 temp2 = SiS_GetCH701x(&ivideo->SiS_Pr, 0x20);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07002638 SiS_SetCH701x(&ivideo->SiS_Pr, 0x49, temp1);
2639 temp1 = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002640 if(temp2 & 0x02) temp1 |= 0x01;
2641 if(temp2 & 0x10) temp1 |= 0x01;
2642 if(temp2 & 0x04) temp1 |= 0x02;
2643 if( (temp1 & 0x01) && (temp1 & 0x02) ) temp1 = 0x04;
2644 switch(temp1) {
2645 case 0x01:
2646 printk(KERN_INFO "%s CVBS output\n", stdstr);
2647 ivideo->vbflags |= TV_AVIDEO;
2648 orSISIDXREG(SISCR, 0x32, 0x01);
2649 andSISIDXREG(SISCR, 0x32, ~0x06);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07002650 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002651 case 0x02:
2652 printk(KERN_INFO "%s SVIDEO output\n", stdstr);
2653 ivideo->vbflags |= TV_SVIDEO;
2654 orSISIDXREG(SISCR, 0x32, 0x02);
2655 andSISIDXREG(SISCR, 0x32, ~0x05);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07002656 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002657 case 0x04:
2658 printk(KERN_INFO "%s SCART output\n", stdstr);
2659 orSISIDXREG(SISCR, 0x32, 0x04);
2660 andSISIDXREG(SISCR, 0x32, ~0x03);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07002661 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002662 default:
2663 andSISIDXREG(SISCR, 0x32, ~0x07);
2664 }
2665#endif
2666 }
2667}
2668
Thomas Winischhofer544393f2005-09-09 13:04:45 -07002669static void __devinit
2670sisfb_get_VB_type(struct sis_video_info *ivideo)
2671{
2672 char stdstr[] = "sisfb: Detected";
2673 char bridgestr[] = "video bridge";
2674 u8 vb_chipid;
2675 u8 reg;
2676
2677 /* No CRT2 on XGI Z7 */
2678 if(ivideo->chip == XGI_20)
2679 return;
2680
2681 inSISIDXREG(SISPART4, 0x00, vb_chipid);
2682 switch(vb_chipid) {
2683 case 0x01:
2684 inSISIDXREG(SISPART4, 0x01, reg);
2685 if(reg < 0xb0) {
2686 ivideo->vbflags |= VB_301; /* Deprecated */
2687 ivideo->vbflags2 |= VB2_301;
2688 printk(KERN_INFO "%s SiS301 %s\n", stdstr, bridgestr);
2689 } else if(reg < 0xc0) {
2690 ivideo->vbflags |= VB_301B; /* Deprecated */
2691 ivideo->vbflags2 |= VB2_301B;
2692 inSISIDXREG(SISPART4,0x23,reg);
2693 if(!(reg & 0x02)) {
2694 ivideo->vbflags |= VB_30xBDH; /* Deprecated */
2695 ivideo->vbflags2 |= VB2_30xBDH;
2696 printk(KERN_INFO "%s SiS301B-DH %s\n", stdstr, bridgestr);
2697 } else {
2698 printk(KERN_INFO "%s SiS301B %s\n", stdstr, bridgestr);
2699 }
2700 } else if(reg < 0xd0) {
2701 ivideo->vbflags |= VB_301C; /* Deprecated */
2702 ivideo->vbflags2 |= VB2_301C;
2703 printk(KERN_INFO "%s SiS301C %s\n", stdstr, bridgestr);
2704 } else if(reg < 0xe0) {
2705 ivideo->vbflags |= VB_301LV; /* Deprecated */
2706 ivideo->vbflags2 |= VB2_301LV;
2707 printk(KERN_INFO "%s SiS301LV %s\n", stdstr, bridgestr);
2708 } else if(reg <= 0xe1) {
2709 inSISIDXREG(SISPART4,0x39,reg);
2710 if(reg == 0xff) {
2711 ivideo->vbflags |= VB_302LV; /* Deprecated */
2712 ivideo->vbflags2 |= VB2_302LV;
2713 printk(KERN_INFO "%s SiS302LV %s\n", stdstr, bridgestr);
2714 } else {
2715 ivideo->vbflags |= VB_301C; /* Deprecated */
2716 ivideo->vbflags2 |= VB2_301C;
2717 printk(KERN_INFO "%s SiS301C(P4) %s\n", stdstr, bridgestr);
2718#if 0
2719 ivideo->vbflags |= VB_302ELV; /* Deprecated */
2720 ivideo->vbflags2 |= VB2_302ELV;
2721 printk(KERN_INFO "%s SiS302ELV %s\n", stdstr, bridgestr);
2722#endif
2723 }
2724 }
2725 break;
2726 case 0x02:
2727 ivideo->vbflags |= VB_302B; /* Deprecated */
2728 ivideo->vbflags2 |= VB2_302B;
2729 printk(KERN_INFO "%s SiS302B %s\n", stdstr, bridgestr);
2730 break;
2731 }
2732
2733 if((!(ivideo->vbflags2 & VB2_VIDEOBRIDGE)) && (ivideo->chip != SIS_300)) {
2734 inSISIDXREG(SISCR, 0x37, reg);
2735 reg &= SIS_EXTERNAL_CHIP_MASK;
2736 reg >>= 1;
2737 if(ivideo->sisvga_engine == SIS_300_VGA) {
2738#ifdef CONFIG_FB_SIS_300
2739 switch(reg) {
2740 case SIS_EXTERNAL_CHIP_LVDS:
2741 ivideo->vbflags |= VB_LVDS; /* Deprecated */
2742 ivideo->vbflags2 |= VB2_LVDS;
2743 break;
2744 case SIS_EXTERNAL_CHIP_TRUMPION:
2745 ivideo->vbflags |= (VB_LVDS | VB_TRUMPION); /* Deprecated */
2746 ivideo->vbflags2 |= (VB2_LVDS | VB2_TRUMPION);
2747 break;
2748 case SIS_EXTERNAL_CHIP_CHRONTEL:
2749 ivideo->vbflags |= VB_CHRONTEL; /* Deprecated */
2750 ivideo->vbflags2 |= VB2_CHRONTEL;
2751 break;
2752 case SIS_EXTERNAL_CHIP_LVDS_CHRONTEL:
2753 ivideo->vbflags |= (VB_LVDS | VB_CHRONTEL); /* Deprecated */
2754 ivideo->vbflags2 |= (VB2_LVDS | VB2_CHRONTEL);
2755 break;
2756 }
2757 if(ivideo->vbflags2 & VB2_CHRONTEL) ivideo->chronteltype = 1;
2758#endif
2759 } else if(ivideo->chip < SIS_661) {
2760#ifdef CONFIG_FB_SIS_315
2761 switch (reg) {
2762 case SIS310_EXTERNAL_CHIP_LVDS:
2763 ivideo->vbflags |= VB_LVDS; /* Deprecated */
2764 ivideo->vbflags2 |= VB2_LVDS;
2765 break;
2766 case SIS310_EXTERNAL_CHIP_LVDS_CHRONTEL:
2767 ivideo->vbflags |= (VB_LVDS | VB_CHRONTEL); /* Deprecated */
2768 ivideo->vbflags2 |= (VB2_LVDS | VB2_CHRONTEL);
2769 break;
2770 }
2771 if(ivideo->vbflags2 & VB2_CHRONTEL) ivideo->chronteltype = 2;
2772#endif
2773 } else if(ivideo->chip >= SIS_661) {
2774#ifdef CONFIG_FB_SIS_315
2775 inSISIDXREG(SISCR, 0x38, reg);
2776 reg >>= 5;
2777 switch(reg) {
2778 case 0x02:
2779 ivideo->vbflags |= VB_LVDS; /* Deprecated */
2780 ivideo->vbflags2 |= VB2_LVDS;
2781 break;
2782 case 0x03:
2783 ivideo->vbflags |= (VB_LVDS | VB_CHRONTEL); /* Deprecated */
2784 ivideo->vbflags2 |= (VB2_LVDS | VB2_CHRONTEL);
2785 break;
2786 case 0x04:
2787 ivideo->vbflags |= (VB_LVDS | VB_CONEXANT); /* Deprecated */
2788 ivideo->vbflags2 |= (VB2_LVDS | VB2_CONEXANT);
2789 break;
2790 }
2791 if(ivideo->vbflags2 & VB2_CHRONTEL) ivideo->chronteltype = 2;
2792#endif
2793 }
2794 if(ivideo->vbflags2 & VB2_LVDS) {
2795 printk(KERN_INFO "%s LVDS transmitter\n", stdstr);
2796 }
2797 if((ivideo->sisvga_engine == SIS_300_VGA) && (ivideo->vbflags2 & VB2_TRUMPION)) {
2798 printk(KERN_INFO "%s Trumpion Zurac LCD scaler\n", stdstr);
2799 }
2800 if(ivideo->vbflags2 & VB2_CHRONTEL) {
2801 printk(KERN_INFO "%s Chrontel TV encoder\n", stdstr);
2802 }
2803 if((ivideo->chip >= SIS_661) && (ivideo->vbflags2 & VB2_CONEXANT)) {
2804 printk(KERN_INFO "%s Conexant external device\n", stdstr);
2805 }
2806 }
2807
2808 if(ivideo->vbflags2 & VB2_SISBRIDGE) {
2809 SiS_SenseLCD(ivideo);
2810 SiS_Sense30x(ivideo);
2811 } else if(ivideo->vbflags2 & VB2_CHRONTEL) {
2812 SiS_SenseCh(ivideo);
2813 }
2814}
2815
2816/* ---------- Engine initialization routines ------------ */
2817
2818static void
2819sisfb_engine_init(struct sis_video_info *ivideo)
2820{
2821
2822 /* Initialize command queue (we use MMIO only) */
2823
2824 /* BEFORE THIS IS CALLED, THE ENGINES *MUST* BE SYNC'ED */
2825
2826 ivideo->caps &= ~(TURBO_QUEUE_CAP |
2827 MMIO_CMD_QUEUE_CAP |
2828 VM_CMD_QUEUE_CAP |
2829 AGP_CMD_QUEUE_CAP);
2830
2831#ifdef CONFIG_FB_SIS_300
2832 if(ivideo->sisvga_engine == SIS_300_VGA) {
2833 u32 tqueue_pos;
2834 u8 tq_state;
2835
2836 tqueue_pos = (ivideo->video_size - ivideo->cmdQueueSize) / (64 * 1024);
2837
2838 inSISIDXREG(SISSR, IND_SIS_TURBOQUEUE_SET, tq_state);
2839 tq_state |= 0xf0;
2840 tq_state &= 0xfc;
2841 tq_state |= (u8)(tqueue_pos >> 8);
2842 outSISIDXREG(SISSR, IND_SIS_TURBOQUEUE_SET, tq_state);
2843
2844 outSISIDXREG(SISSR, IND_SIS_TURBOQUEUE_ADR, (u8)(tqueue_pos & 0xff));
2845
2846 ivideo->caps |= TURBO_QUEUE_CAP;
2847 }
2848#endif
2849
2850#ifdef CONFIG_FB_SIS_315
2851 if(ivideo->sisvga_engine == SIS_315_VGA) {
2852 u32 tempq = 0, templ;
2853 u8 temp;
2854
2855 if(ivideo->chip == XGI_20) {
2856 switch(ivideo->cmdQueueSize) {
2857 case (64 * 1024):
2858 temp = SIS_CMD_QUEUE_SIZE_Z7_64k;
2859 break;
2860 case (128 * 1024):
2861 default:
2862 temp = SIS_CMD_QUEUE_SIZE_Z7_128k;
2863 }
2864 } else {
2865 switch(ivideo->cmdQueueSize) {
2866 case (4 * 1024 * 1024):
2867 temp = SIS_CMD_QUEUE_SIZE_4M;
2868 break;
2869 case (2 * 1024 * 1024):
2870 temp = SIS_CMD_QUEUE_SIZE_2M;
2871 break;
2872 case (1 * 1024 * 1024):
2873 temp = SIS_CMD_QUEUE_SIZE_1M;
2874 break;
2875 default:
2876 case (512 * 1024):
2877 temp = SIS_CMD_QUEUE_SIZE_512k;
2878 }
2879 }
2880
2881 outSISIDXREG(SISSR, IND_SIS_CMDQUEUE_THRESHOLD, COMMAND_QUEUE_THRESHOLD);
2882 outSISIDXREG(SISSR, IND_SIS_CMDQUEUE_SET, SIS_CMD_QUEUE_RESET);
2883
2884 if((ivideo->chip >= XGI_40) && ivideo->modechanged) {
2885 /* Must disable dual pipe on XGI_40. Can't do
2886 * this in MMIO mode, because it requires
2887 * setting/clearing a bit in the MMIO fire trigger
2888 * register.
2889 */
2890 if(!((templ = MMIO_IN32(ivideo->mmio_vbase, 0x8240)) & (1 << 10))) {
2891
2892 MMIO_OUT32(ivideo->mmio_vbase, Q_WRITE_PTR, 0);
2893
2894 outSISIDXREG(SISSR, IND_SIS_CMDQUEUE_SET, (temp | SIS_VRAM_CMDQUEUE_ENABLE));
2895
2896 tempq = MMIO_IN32(ivideo->mmio_vbase, Q_READ_PTR);
2897 MMIO_OUT32(ivideo->mmio_vbase, Q_WRITE_PTR, tempq);
2898
2899 tempq = (u32)(ivideo->video_size - ivideo->cmdQueueSize);
2900 MMIO_OUT32(ivideo->mmio_vbase, Q_BASE_ADDR, tempq);
2901
2902 writel(0x16800000 + 0x8240, ivideo->video_vbase + tempq);
2903 writel(templ | (1 << 10), ivideo->video_vbase + tempq + 4);
2904 writel(0x168F0000, ivideo->video_vbase + tempq + 8);
2905 writel(0x168F0000, ivideo->video_vbase + tempq + 12);
2906
2907 MMIO_OUT32(ivideo->mmio_vbase, Q_WRITE_PTR, (tempq + 16));
2908
2909 sisfb_syncaccel(ivideo);
2910
2911 outSISIDXREG(SISSR, IND_SIS_CMDQUEUE_SET, SIS_CMD_QUEUE_RESET);
2912
2913 }
2914 }
2915
2916 tempq = MMIO_IN32(ivideo->mmio_vbase, MMIO_QUEUE_READPORT);
2917 MMIO_OUT32(ivideo->mmio_vbase, MMIO_QUEUE_WRITEPORT, tempq);
2918
2919 temp |= (SIS_MMIO_CMD_ENABLE | SIS_CMD_AUTO_CORR);
2920 outSISIDXREG(SISSR, IND_SIS_CMDQUEUE_SET, temp);
2921
2922 tempq = (u32)(ivideo->video_size - ivideo->cmdQueueSize);
2923 MMIO_OUT32(ivideo->mmio_vbase, MMIO_QUEUE_PHYBASE, tempq);
2924
2925 ivideo->caps |= MMIO_CMD_QUEUE_CAP;
2926 }
2927#endif
2928
2929 ivideo->engineok = 1;
2930}
2931
2932static void __devinit
2933sisfb_detect_lcd_type(struct sis_video_info *ivideo)
2934{
2935 u8 reg;
2936 int i;
2937
2938 inSISIDXREG(SISCR, 0x36, reg);
2939 reg &= 0x0f;
2940 if(ivideo->sisvga_engine == SIS_300_VGA) {
2941 ivideo->CRT2LCDType = sis300paneltype[reg];
2942 } else if(ivideo->chip >= SIS_661) {
2943 ivideo->CRT2LCDType = sis661paneltype[reg];
2944 } else {
2945 ivideo->CRT2LCDType = sis310paneltype[reg];
2946 if((ivideo->chip == SIS_550) && (sisfb_fstn)) {
2947 if((ivideo->CRT2LCDType != LCD_320x240_2) &&
2948 (ivideo->CRT2LCDType != LCD_320x240_3)) {
2949 ivideo->CRT2LCDType = LCD_320x240;
2950 }
2951 }
2952 }
2953
2954 if(ivideo->CRT2LCDType == LCD_UNKNOWN) {
2955 /* For broken BIOSes: Assume 1024x768, RGB18 */
2956 ivideo->CRT2LCDType = LCD_1024x768;
2957 setSISIDXREG(SISCR,0x36,0xf0,0x02);
2958 setSISIDXREG(SISCR,0x37,0xee,0x01);
2959 printk(KERN_DEBUG "sisfb: Invalid panel ID (%02x), assuming 1024x768, RGB18\n", reg);
2960 }
2961
2962 for(i = 0; i < SIS_LCD_NUMBER; i++) {
2963 if(ivideo->CRT2LCDType == sis_lcd_data[i].lcdtype) {
2964 ivideo->lcdxres = sis_lcd_data[i].xres;
2965 ivideo->lcdyres = sis_lcd_data[i].yres;
2966 ivideo->lcddefmodeidx = sis_lcd_data[i].default_mode_idx;
2967 break;
2968 }
2969 }
2970
2971#ifdef CONFIG_FB_SIS_300
2972 if(ivideo->SiS_Pr.SiS_CustomT == CUT_BARCO1366) {
2973 ivideo->lcdxres = 1360; ivideo->lcdyres = 1024;
2974 ivideo->lcddefmodeidx = DEFAULT_MODE_1360;
2975 } else if(ivideo->SiS_Pr.SiS_CustomT == CUT_PANEL848) {
2976 ivideo->lcdxres = 848; ivideo->lcdyres = 480;
2977 ivideo->lcddefmodeidx = DEFAULT_MODE_848;
2978 } else if(ivideo->SiS_Pr.SiS_CustomT == CUT_PANEL856) {
2979 ivideo->lcdxres = 856; ivideo->lcdyres = 480;
2980 ivideo->lcddefmodeidx = DEFAULT_MODE_856;
2981 }
2982#endif
2983
2984 printk(KERN_DEBUG "sisfb: Detected %dx%d flat panel\n",
2985 ivideo->lcdxres, ivideo->lcdyres);
2986}
2987
2988static void __devinit
2989sisfb_save_pdc_emi(struct sis_video_info *ivideo)
2990{
2991#ifdef CONFIG_FB_SIS_300
2992 /* Save the current PanelDelayCompensation if the LCD is currently used */
2993 if(ivideo->sisvga_engine == SIS_300_VGA) {
2994 if(ivideo->vbflags2 & (VB2_LVDS | VB2_30xBDH)) {
2995 int tmp;
2996 inSISIDXREG(SISCR,0x30,tmp);
2997 if(tmp & 0x20) {
2998 /* Currently on LCD? If yes, read current pdc */
2999 inSISIDXREG(SISPART1,0x13,ivideo->detectedpdc);
3000 ivideo->detectedpdc &= 0x3c;
3001 if(ivideo->SiS_Pr.PDC == -1) {
3002 /* Let option override detection */
3003 ivideo->SiS_Pr.PDC = ivideo->detectedpdc;
3004 }
3005 printk(KERN_INFO "sisfb: Detected LCD PDC 0x%02x\n",
3006 ivideo->detectedpdc);
3007 }
3008 if((ivideo->SiS_Pr.PDC != -1) &&
3009 (ivideo->SiS_Pr.PDC != ivideo->detectedpdc)) {
3010 printk(KERN_INFO "sisfb: Using LCD PDC 0x%02x\n",
3011 ivideo->SiS_Pr.PDC);
3012 }
3013 }
3014 }
3015#endif
3016
3017#ifdef CONFIG_FB_SIS_315
3018 if(ivideo->sisvga_engine == SIS_315_VGA) {
3019
3020 /* Try to find about LCDA */
3021 if(ivideo->vbflags2 & VB2_SISLCDABRIDGE) {
3022 int tmp;
3023 inSISIDXREG(SISPART1,0x13,tmp);
3024 if(tmp & 0x04) {
Richard Knutssonc30660ea2007-02-12 00:55:06 -08003025 ivideo->SiS_Pr.SiS_UseLCDA = true;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003026 ivideo->detectedlcda = 0x03;
3027 }
3028 }
3029
3030 /* Save PDC */
3031 if(ivideo->vbflags2 & VB2_SISLVDSBRIDGE) {
3032 int tmp;
3033 inSISIDXREG(SISCR,0x30,tmp);
3034 if((tmp & 0x20) || (ivideo->detectedlcda != 0xff)) {
3035 /* Currently on LCD? If yes, read current pdc */
3036 u8 pdc;
3037 inSISIDXREG(SISPART1,0x2D,pdc);
3038 ivideo->detectedpdc = (pdc & 0x0f) << 1;
3039 ivideo->detectedpdca = (pdc & 0xf0) >> 3;
3040 inSISIDXREG(SISPART1,0x35,pdc);
3041 ivideo->detectedpdc |= ((pdc >> 7) & 0x01);
3042 inSISIDXREG(SISPART1,0x20,pdc);
3043 ivideo->detectedpdca |= ((pdc >> 6) & 0x01);
3044 if(ivideo->newrom) {
3045 /* New ROM invalidates other PDC resp. */
3046 if(ivideo->detectedlcda != 0xff) {
3047 ivideo->detectedpdc = 0xff;
3048 } else {
3049 ivideo->detectedpdca = 0xff;
3050 }
3051 }
3052 if(ivideo->SiS_Pr.PDC == -1) {
3053 if(ivideo->detectedpdc != 0xff) {
3054 ivideo->SiS_Pr.PDC = ivideo->detectedpdc;
3055 }
3056 }
3057 if(ivideo->SiS_Pr.PDCA == -1) {
3058 if(ivideo->detectedpdca != 0xff) {
3059 ivideo->SiS_Pr.PDCA = ivideo->detectedpdca;
3060 }
3061 }
3062 if(ivideo->detectedpdc != 0xff) {
3063 printk(KERN_INFO
3064 "sisfb: Detected LCD PDC 0x%02x (for LCD=CRT2)\n",
3065 ivideo->detectedpdc);
3066 }
3067 if(ivideo->detectedpdca != 0xff) {
3068 printk(KERN_INFO
3069 "sisfb: Detected LCD PDC1 0x%02x (for LCD=CRT1)\n",
3070 ivideo->detectedpdca);
3071 }
3072 }
3073
3074 /* Save EMI */
3075 if(ivideo->vbflags2 & VB2_SISEMIBRIDGE) {
3076 inSISIDXREG(SISPART4,0x30,ivideo->SiS_Pr.EMI_30);
3077 inSISIDXREG(SISPART4,0x31,ivideo->SiS_Pr.EMI_31);
3078 inSISIDXREG(SISPART4,0x32,ivideo->SiS_Pr.EMI_32);
3079 inSISIDXREG(SISPART4,0x33,ivideo->SiS_Pr.EMI_33);
Richard Knutssonc30660ea2007-02-12 00:55:06 -08003080 ivideo->SiS_Pr.HaveEMI = true;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003081 if((tmp & 0x20) || (ivideo->detectedlcda != 0xff)) {
Richard Knutssonc30660ea2007-02-12 00:55:06 -08003082 ivideo->SiS_Pr.HaveEMILCD = true;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003083 }
3084 }
3085 }
3086
3087 /* Let user override detected PDCs (all bridges) */
3088 if(ivideo->vbflags2 & VB2_30xBLV) {
3089 if((ivideo->SiS_Pr.PDC != -1) &&
3090 (ivideo->SiS_Pr.PDC != ivideo->detectedpdc)) {
3091 printk(KERN_INFO "sisfb: Using LCD PDC 0x%02x (for LCD=CRT2)\n",
3092 ivideo->SiS_Pr.PDC);
3093 }
3094 if((ivideo->SiS_Pr.PDCA != -1) &&
3095 (ivideo->SiS_Pr.PDCA != ivideo->detectedpdca)) {
3096 printk(KERN_INFO "sisfb: Using LCD PDC1 0x%02x (for LCD=CRT1)\n",
3097 ivideo->SiS_Pr.PDCA);
3098 }
3099 }
3100
3101 }
3102#endif
3103}
3104
3105/* -------------------- Memory manager routines ---------------------- */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003106
3107static u32 __devinit
3108sisfb_getheapstart(struct sis_video_info *ivideo)
3109{
3110 u32 ret = ivideo->sisfb_parm_mem * 1024;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003111 u32 maxoffs = ivideo->video_size - ivideo->hwcursor_size - ivideo->cmdQueueSize;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003112 u32 def;
3113
3114 /* Calculate heap start = end of memory for console
3115 *
3116 * CCCCCCCCDDDDDDDDDDDDDDDDDDDDDDDDDDDDHHHHQQQQQQQQQQ
3117 * C = console, D = heap, H = HWCursor, Q = cmd-queue
3118 *
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003119 * On 76x in UMA+LFB mode, the layout is as follows:
3120 * DDDDDDDDDDDCCCCCCCCCCCCCCCCCCCCCCCCHHHHQQQQQQQQQQQ
3121 * where the heap is the entire UMA area, eventually
3122 * into the LFB area if the given mem parameter is
3123 * higher than the size of the UMA memory.
3124 *
Linus Torvalds1da177e2005-04-16 15:20:36 -07003125 * Basically given by "mem" parameter
3126 *
3127 * maximum = videosize - cmd_queue - hwcursor
3128 * (results in a heap of size 0)
3129 * default = SiS 300: depends on videosize
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003130 * SiS 315/330/340/XGI: 32k below max
Linus Torvalds1da177e2005-04-16 15:20:36 -07003131 */
3132
3133 if(ivideo->sisvga_engine == SIS_300_VGA) {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003134 if(ivideo->video_size > 0x1000000) {
3135 def = 0xc00000;
3136 } else if(ivideo->video_size > 0x800000) {
3137 def = 0x800000;
3138 } else {
3139 def = 0x400000;
3140 }
3141 } else if(ivideo->UMAsize && ivideo->LFBsize) {
3142 ret = def = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003143 } else {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003144 def = maxoffs - 0x8000;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003145 }
3146
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003147 /* Use default for secondary card for now (FIXME) */
3148 if((!ret) || (ret > maxoffs) || (ivideo->cardnumber != 0))
3149 ret = def;
3150
3151 return ret;
3152}
3153
3154static u32 __devinit
3155sisfb_getheapsize(struct sis_video_info *ivideo)
3156{
3157 u32 max = ivideo->video_size - ivideo->hwcursor_size - ivideo->cmdQueueSize;
3158 u32 ret = 0;
3159
3160 if(ivideo->UMAsize && ivideo->LFBsize) {
3161 if( (!ivideo->sisfb_parm_mem) ||
3162 ((ivideo->sisfb_parm_mem * 1024) > max) ||
3163 ((max - (ivideo->sisfb_parm_mem * 1024)) < ivideo->UMAsize) ) {
3164 ret = ivideo->UMAsize;
3165 max -= ivideo->UMAsize;
3166 } else {
3167 ret = max - (ivideo->sisfb_parm_mem * 1024);
3168 max = ivideo->sisfb_parm_mem * 1024;
3169 }
3170 ivideo->video_offset = ret;
3171 ivideo->sisfb_mem = max;
3172 } else {
3173 ret = max - ivideo->heapstart;
3174 ivideo->sisfb_mem = ivideo->heapstart;
3175 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003176
3177 return ret;
3178}
3179
3180static int __devinit
3181sisfb_heap_init(struct sis_video_info *ivideo)
3182{
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003183 struct SIS_OH *poh;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003184
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003185 ivideo->video_offset = 0;
3186 if(ivideo->sisfb_parm_mem) {
3187 if( (ivideo->sisfb_parm_mem < (2 * 1024 * 1024)) ||
3188 (ivideo->sisfb_parm_mem > ivideo->video_size) ) {
3189 ivideo->sisfb_parm_mem = 0;
3190 }
3191 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003192
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003193 ivideo->heapstart = sisfb_getheapstart(ivideo);
3194 ivideo->sisfb_heap_size = sisfb_getheapsize(ivideo);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003195
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003196 ivideo->sisfb_heap_start = ivideo->video_vbase + ivideo->heapstart;
3197 ivideo->sisfb_heap_end = ivideo->sisfb_heap_start + ivideo->sisfb_heap_size;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003198
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003199 printk(KERN_INFO "sisfb: Memory heap starting at %dK, size %dK\n",
3200 (int)(ivideo->heapstart / 1024), (int)(ivideo->sisfb_heap_size / 1024));
Linus Torvalds1da177e2005-04-16 15:20:36 -07003201
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003202 ivideo->sisfb_heap.vinfo = ivideo;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003203
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003204 ivideo->sisfb_heap.poha_chain = NULL;
3205 ivideo->sisfb_heap.poh_freelist = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003206
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003207 poh = sisfb_poh_new_node(&ivideo->sisfb_heap);
3208 if(poh == NULL)
3209 return 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003210
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003211 poh->poh_next = &ivideo->sisfb_heap.oh_free;
3212 poh->poh_prev = &ivideo->sisfb_heap.oh_free;
3213 poh->size = ivideo->sisfb_heap_size;
3214 poh->offset = ivideo->heapstart;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003215
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003216 ivideo->sisfb_heap.oh_free.poh_next = poh;
3217 ivideo->sisfb_heap.oh_free.poh_prev = poh;
3218 ivideo->sisfb_heap.oh_free.size = 0;
3219 ivideo->sisfb_heap.max_freesize = poh->size;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003220
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003221 ivideo->sisfb_heap.oh_used.poh_next = &ivideo->sisfb_heap.oh_used;
3222 ivideo->sisfb_heap.oh_used.poh_prev = &ivideo->sisfb_heap.oh_used;
3223 ivideo->sisfb_heap.oh_used.size = SENTINEL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003224
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003225 if(ivideo->cardnumber == 0) {
3226 /* For the first card, make this heap the "global" one
3227 * for old DRM (which could handle only one card)
3228 */
3229 sisfb_heap = &ivideo->sisfb_heap;
3230 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003231
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003232 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003233}
3234
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003235static struct SIS_OH *
3236sisfb_poh_new_node(struct SIS_HEAP *memheap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003237{
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003238 struct SIS_OHALLOC *poha;
3239 struct SIS_OH *poh;
3240 unsigned long cOhs;
3241 int i;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003242
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003243 if(memheap->poh_freelist == NULL) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003244 poha = kmalloc(SIS_OH_ALLOC_SIZE, GFP_KERNEL);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003245 if(!poha)
3246 return NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003247
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003248 poha->poha_next = memheap->poha_chain;
3249 memheap->poha_chain = poha;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003250
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003251 cOhs = (SIS_OH_ALLOC_SIZE - sizeof(struct SIS_OHALLOC)) / sizeof(struct SIS_OH) + 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003252
3253 poh = &poha->aoh[0];
3254 for(i = cOhs - 1; i != 0; i--) {
3255 poh->poh_next = poh + 1;
3256 poh = poh + 1;
3257 }
3258
3259 poh->poh_next = NULL;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003260 memheap->poh_freelist = &poha->aoh[0];
Linus Torvalds1da177e2005-04-16 15:20:36 -07003261 }
3262
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003263 poh = memheap->poh_freelist;
3264 memheap->poh_freelist = poh->poh_next;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003265
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003266 return poh;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003267}
3268
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003269static struct SIS_OH *
3270sisfb_poh_allocate(struct SIS_HEAP *memheap, u32 size)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003271{
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003272 struct SIS_OH *pohThis;
3273 struct SIS_OH *pohRoot;
3274 int bAllocated = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003275
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003276 if(size > memheap->max_freesize) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003277 DPRINTK("sisfb: Can't allocate %dk video memory\n",
3278 (unsigned int) size / 1024);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003279 return NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003280 }
3281
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003282 pohThis = memheap->oh_free.poh_next;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003283
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003284 while(pohThis != &memheap->oh_free) {
3285 if(size <= pohThis->size) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003286 bAllocated = 1;
3287 break;
3288 }
3289 pohThis = pohThis->poh_next;
3290 }
3291
3292 if(!bAllocated) {
3293 DPRINTK("sisfb: Can't allocate %dk video memory\n",
3294 (unsigned int) size / 1024);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003295 return NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003296 }
3297
3298 if(size == pohThis->size) {
3299 pohRoot = pohThis;
3300 sisfb_delete_node(pohThis);
3301 } else {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003302 pohRoot = sisfb_poh_new_node(memheap);
3303 if(pohRoot == NULL)
3304 return NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003305
3306 pohRoot->offset = pohThis->offset;
3307 pohRoot->size = size;
3308
3309 pohThis->offset += size;
3310 pohThis->size -= size;
3311 }
3312
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003313 memheap->max_freesize -= size;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003314
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003315 pohThis = &memheap->oh_used;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003316 sisfb_insert_node(pohThis, pohRoot);
3317
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003318 return pohRoot;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003319}
3320
3321static void
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003322sisfb_delete_node(struct SIS_OH *poh)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003323{
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003324 poh->poh_prev->poh_next = poh->poh_next;
3325 poh->poh_next->poh_prev = poh->poh_prev;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003326}
3327
3328static void
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003329sisfb_insert_node(struct SIS_OH *pohList, struct SIS_OH *poh)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003330{
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003331 struct SIS_OH *pohTemp = pohList->poh_next;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003332
3333 pohList->poh_next = poh;
3334 pohTemp->poh_prev = poh;
3335
3336 poh->poh_prev = pohList;
3337 poh->poh_next = pohTemp;
3338}
3339
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003340static struct SIS_OH *
3341sisfb_poh_free(struct SIS_HEAP *memheap, u32 base)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003342{
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003343 struct SIS_OH *pohThis;
3344 struct SIS_OH *poh_freed;
3345 struct SIS_OH *poh_prev;
3346 struct SIS_OH *poh_next;
3347 u32 ulUpper;
3348 u32 ulLower;
3349 int foundNode = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003350
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003351 poh_freed = memheap->oh_used.poh_next;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003352
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003353 while(poh_freed != &memheap->oh_used) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003354 if(poh_freed->offset == base) {
3355 foundNode = 1;
3356 break;
3357 }
3358
3359 poh_freed = poh_freed->poh_next;
3360 }
3361
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003362 if(!foundNode)
3363 return NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003364
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003365 memheap->max_freesize += poh_freed->size;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003366
3367 poh_prev = poh_next = NULL;
3368 ulUpper = poh_freed->offset + poh_freed->size;
3369 ulLower = poh_freed->offset;
3370
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003371 pohThis = memheap->oh_free.poh_next;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003372
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003373 while(pohThis != &memheap->oh_free) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003374 if(pohThis->offset == ulUpper) {
3375 poh_next = pohThis;
3376 } else if((pohThis->offset + pohThis->size) == ulLower) {
3377 poh_prev = pohThis;
3378 }
3379 pohThis = pohThis->poh_next;
3380 }
3381
3382 sisfb_delete_node(poh_freed);
3383
3384 if(poh_prev && poh_next) {
3385 poh_prev->size += (poh_freed->size + poh_next->size);
3386 sisfb_delete_node(poh_next);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003387 sisfb_free_node(memheap, poh_freed);
3388 sisfb_free_node(memheap, poh_next);
3389 return poh_prev;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003390 }
3391
3392 if(poh_prev) {
3393 poh_prev->size += poh_freed->size;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003394 sisfb_free_node(memheap, poh_freed);
3395 return poh_prev;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003396 }
3397
3398 if(poh_next) {
3399 poh_next->size += poh_freed->size;
3400 poh_next->offset = poh_freed->offset;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003401 sisfb_free_node(memheap, poh_freed);
3402 return poh_next;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003403 }
3404
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003405 sisfb_insert_node(&memheap->oh_free, poh_freed);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003406
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003407 return poh_freed;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003408}
3409
3410static void
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003411sisfb_free_node(struct SIS_HEAP *memheap, struct SIS_OH *poh)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003412{
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003413 if(poh == NULL)
3414 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003415
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003416 poh->poh_next = memheap->poh_freelist;
3417 memheap->poh_freelist = poh;
3418}
3419
3420static void
3421sis_int_malloc(struct sis_video_info *ivideo, struct sis_memreq *req)
3422{
3423 struct SIS_OH *poh = NULL;
3424
3425 if((ivideo) && (ivideo->sisfb_id == SISFB_ID) && (!ivideo->havenoheap))
3426 poh = sisfb_poh_allocate(&ivideo->sisfb_heap, (u32)req->size);
3427
3428 if(poh == NULL) {
3429 req->offset = req->size = 0;
3430 DPRINTK("sisfb: Video RAM allocation failed\n");
3431 } else {
3432 req->offset = poh->offset;
3433 req->size = poh->size;
3434 DPRINTK("sisfb: Video RAM allocation succeeded: 0x%lx\n",
3435 (poh->offset + ivideo->video_vbase));
3436 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003437}
3438
3439void
3440sis_malloc(struct sis_memreq *req)
3441{
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003442 struct sis_video_info *ivideo = sisfb_heap->vinfo;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003443
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003444 if(&ivideo->sisfb_heap == sisfb_heap)
3445 sis_int_malloc(ivideo, req);
3446 else
3447 req->offset = req->size = 0;
3448}
Linus Torvalds1da177e2005-04-16 15:20:36 -07003449
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003450void
3451sis_malloc_new(struct pci_dev *pdev, struct sis_memreq *req)
3452{
3453 struct sis_video_info *ivideo = pci_get_drvdata(pdev);
3454
3455 sis_int_malloc(ivideo, req);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003456}
3457
3458/* sis_free: u32 because "base" is offset inside video ram, can never be >4GB */
3459
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003460static void
3461sis_int_free(struct sis_video_info *ivideo, u32 base)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003462{
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003463 struct SIS_OH *poh;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003464
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003465 if((!ivideo) || (ivideo->sisfb_id != SISFB_ID) || (ivideo->havenoheap))
3466 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003467
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003468 poh = sisfb_poh_free(&ivideo->sisfb_heap, base);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003469
3470 if(poh == NULL) {
3471 DPRINTK("sisfb: sisfb_poh_free() failed at base 0x%x\n",
3472 (unsigned int) base);
3473 }
3474}
3475
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003476void
3477sis_free(u32 base)
3478{
3479 struct sis_video_info *ivideo = sisfb_heap->vinfo;
3480
3481 sis_int_free(ivideo, base);
3482}
3483
3484void
3485sis_free_new(struct pci_dev *pdev, u32 base)
3486{
3487 struct sis_video_info *ivideo = pci_get_drvdata(pdev);
3488
3489 sis_int_free(ivideo, base);
3490}
3491
Linus Torvalds1da177e2005-04-16 15:20:36 -07003492/* --------------------- SetMode routines ------------------------- */
3493
3494static void
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003495sisfb_check_engine_and_sync(struct sis_video_info *ivideo)
3496{
3497 u8 cr30, cr31;
3498
3499 /* Check if MMIO and engines are enabled,
3500 * and sync in case they are. Can't use
3501 * ivideo->accel here, as this might have
3502 * been changed before this is called.
3503 */
3504 inSISIDXREG(SISSR, IND_SIS_PCI_ADDRESS_SET, cr30);
3505 inSISIDXREG(SISSR, IND_SIS_MODULE_ENABLE, cr31);
3506 /* MMIO and 2D/3D engine enabled? */
3507 if((cr30 & SIS_MEM_MAP_IO_ENABLE) && (cr31 & 0x42)) {
3508#ifdef CONFIG_FB_SIS_300
3509 if(ivideo->sisvga_engine == SIS_300_VGA) {
3510 /* Don't care about TurboQueue. It's
3511 * enough to know that the engines
3512 * are enabled
3513 */
3514 sisfb_syncaccel(ivideo);
3515 }
3516#endif
3517#ifdef CONFIG_FB_SIS_315
3518 if(ivideo->sisvga_engine == SIS_315_VGA) {
3519 /* Check that any queue mode is
3520 * enabled, and that the queue
3521 * is not in the state of "reset"
3522 */
3523 inSISIDXREG(SISSR, 0x26, cr30);
3524 if((cr30 & 0xe0) && (!(cr30 & 0x01))) {
3525 sisfb_syncaccel(ivideo);
3526 }
3527 }
3528#endif
3529 }
3530}
3531
3532static void
Linus Torvalds1da177e2005-04-16 15:20:36 -07003533sisfb_pre_setmode(struct sis_video_info *ivideo)
3534{
3535 u8 cr30 = 0, cr31 = 0, cr33 = 0, cr35 = 0, cr38 = 0;
3536 int tvregnum = 0;
3537
3538 ivideo->currentvbflags &= (VB_VIDEOBRIDGE | VB_DISPTYPE_DISP2);
3539
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003540 outSISIDXREG(SISSR, 0x05, 0x86);
3541
Linus Torvalds1da177e2005-04-16 15:20:36 -07003542 inSISIDXREG(SISCR, 0x31, cr31);
3543 cr31 &= ~0x60;
3544 cr31 |= 0x04;
3545
3546 cr33 = ivideo->rate_idx & 0x0F;
3547
3548#ifdef CONFIG_FB_SIS_315
3549 if(ivideo->sisvga_engine == SIS_315_VGA) {
3550 if(ivideo->chip >= SIS_661) {
3551 inSISIDXREG(SISCR, 0x38, cr38);
3552 cr38 &= ~0x07; /* Clear LCDA/DualEdge and YPbPr bits */
3553 } else {
3554 tvregnum = 0x38;
3555 inSISIDXREG(SISCR, tvregnum, cr38);
3556 cr38 &= ~0x3b; /* Clear LCDA/DualEdge and YPbPr bits */
3557 }
3558 }
3559#endif
3560#ifdef CONFIG_FB_SIS_300
3561 if(ivideo->sisvga_engine == SIS_300_VGA) {
3562 tvregnum = 0x35;
3563 inSISIDXREG(SISCR, tvregnum, cr38);
3564 }
3565#endif
3566
Richard Knutssonc30660ea2007-02-12 00:55:06 -08003567 SiS_SetEnableDstn(&ivideo->SiS_Pr, false);
3568 SiS_SetEnableFstn(&ivideo->SiS_Pr, false);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003569 ivideo->curFSTN = ivideo->curDSTN = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003570
3571 switch(ivideo->currentvbflags & VB_DISPTYPE_DISP2) {
3572
3573 case CRT2_TV:
3574 cr38 &= ~0xc0; /* Clear PAL-M / PAL-N bits */
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003575 if((ivideo->vbflags & TV_YPBPR) && (ivideo->vbflags2 & VB2_SISYPBPRBRIDGE)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003576#ifdef CONFIG_FB_SIS_315
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003577 if(ivideo->chip >= SIS_661) {
3578 cr38 |= 0x04;
3579 if(ivideo->vbflags & TV_YPBPR525P) cr35 |= 0x20;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003580 else if(ivideo->vbflags & TV_YPBPR750P) cr35 |= 0x40;
3581 else if(ivideo->vbflags & TV_YPBPR1080I) cr35 |= 0x60;
3582 cr30 |= SIS_SIMULTANEOUS_VIEW_ENABLE;
3583 cr35 &= ~0x01;
3584 ivideo->currentvbflags |= (TV_YPBPR | (ivideo->vbflags & TV_YPBPRALL));
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003585 } else if(ivideo->sisvga_engine == SIS_315_VGA) {
3586 cr30 |= (0x80 | SIS_SIMULTANEOUS_VIEW_ENABLE);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003587 cr38 |= 0x08;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003588 if(ivideo->vbflags & TV_YPBPR525P) cr38 |= 0x10;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003589 else if(ivideo->vbflags & TV_YPBPR750P) cr38 |= 0x20;
3590 else if(ivideo->vbflags & TV_YPBPR1080I) cr38 |= 0x30;
3591 cr31 &= ~0x01;
3592 ivideo->currentvbflags |= (TV_YPBPR | (ivideo->vbflags & TV_YPBPRALL));
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003593 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003594#endif
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003595 } else if((ivideo->vbflags & TV_HIVISION) &&
3596 (ivideo->vbflags2 & VB2_SISHIVISIONBRIDGE)) {
3597 if(ivideo->chip >= SIS_661) {
3598 cr38 |= 0x04;
3599 cr35 |= 0x60;
3600 } else {
3601 cr30 |= 0x80;
3602 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003603 cr30 |= SIS_SIMULTANEOUS_VIEW_ENABLE;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003604 cr31 |= 0x01;
3605 cr35 |= 0x01;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003606 ivideo->currentvbflags |= TV_HIVISION;
3607 } else if(ivideo->vbflags & TV_SCART) {
3608 cr30 = (SIS_VB_OUTPUT_SCART | SIS_SIMULTANEOUS_VIEW_ENABLE);
3609 cr31 |= 0x01;
3610 cr35 |= 0x01;
3611 ivideo->currentvbflags |= TV_SCART;
3612 } else {
3613 if(ivideo->vbflags & TV_SVIDEO) {
3614 cr30 = (SIS_VB_OUTPUT_SVIDEO | SIS_SIMULTANEOUS_VIEW_ENABLE);
3615 ivideo->currentvbflags |= TV_SVIDEO;
3616 }
3617 if(ivideo->vbflags & TV_AVIDEO) {
3618 cr30 = (SIS_VB_OUTPUT_COMPOSITE | SIS_SIMULTANEOUS_VIEW_ENABLE);
3619 ivideo->currentvbflags |= TV_AVIDEO;
3620 }
3621 }
3622 cr31 |= SIS_DRIVER_MODE;
3623
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003624 if(ivideo->vbflags & (TV_AVIDEO | TV_SVIDEO)) {
3625 if(ivideo->vbflags & TV_PAL) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003626 cr31 |= 0x01; cr35 |= 0x01;
3627 ivideo->currentvbflags |= TV_PAL;
3628 if(ivideo->vbflags & TV_PALM) {
3629 cr38 |= 0x40; cr35 |= 0x04;
3630 ivideo->currentvbflags |= TV_PALM;
3631 } else if(ivideo->vbflags & TV_PALN) {
3632 cr38 |= 0x80; cr35 |= 0x08;
3633 ivideo->currentvbflags |= TV_PALN;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003634 }
3635 } else {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003636 cr31 &= ~0x01; cr35 &= ~0x01;
3637 ivideo->currentvbflags |= TV_NTSC;
3638 if(ivideo->vbflags & TV_NTSCJ) {
3639 cr38 |= 0x40; cr35 |= 0x02;
3640 ivideo->currentvbflags |= TV_NTSCJ;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003641 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003642 }
3643 }
3644 break;
3645
3646 case CRT2_LCD:
3647 cr30 = (SIS_VB_OUTPUT_LCD | SIS_SIMULTANEOUS_VIEW_ENABLE);
3648 cr31 |= SIS_DRIVER_MODE;
3649 SiS_SetEnableDstn(&ivideo->SiS_Pr, ivideo->sisfb_dstn);
3650 SiS_SetEnableFstn(&ivideo->SiS_Pr, ivideo->sisfb_fstn);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003651 ivideo->curFSTN = ivideo->sisfb_fstn;
3652 ivideo->curDSTN = ivideo->sisfb_dstn;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003653 break;
3654
3655 case CRT2_VGA:
3656 cr30 = (SIS_VB_OUTPUT_CRT2 | SIS_SIMULTANEOUS_VIEW_ENABLE);
3657 cr31 |= SIS_DRIVER_MODE;
3658 if(ivideo->sisfb_nocrt2rate) {
3659 cr33 |= (sisbios_mode[ivideo->sisfb_mode_idx].rate_idx << 4);
3660 } else {
3661 cr33 |= ((ivideo->rate_idx & 0x0F) << 4);
3662 }
3663 break;
3664
3665 default: /* disable CRT2 */
3666 cr30 = 0x00;
3667 cr31 |= (SIS_DRIVER_MODE | SIS_VB_OUTPUT_DISABLE);
3668 }
3669
3670 outSISIDXREG(SISCR, 0x30, cr30);
3671 outSISIDXREG(SISCR, 0x33, cr33);
3672
3673 if(ivideo->chip >= SIS_661) {
3674#ifdef CONFIG_FB_SIS_315
3675 cr31 &= ~0x01; /* Clear PAL flag (now in CR35) */
3676 setSISIDXREG(SISCR, 0x35, ~0x10, cr35); /* Leave overscan bit alone */
3677 cr38 &= 0x07; /* Use only LCDA and HiVision/YPbPr bits */
3678 setSISIDXREG(SISCR, 0x38, 0xf8, cr38);
3679#endif
3680 } else if(ivideo->chip != SIS_300) {
3681 outSISIDXREG(SISCR, tvregnum, cr38);
3682 }
3683 outSISIDXREG(SISCR, 0x31, cr31);
3684
Linus Torvalds1da177e2005-04-16 15:20:36 -07003685 ivideo->SiS_Pr.SiS_UseOEM = ivideo->sisfb_useoem;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003686
3687 sisfb_check_engine_and_sync(ivideo);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003688}
3689
3690/* Fix SR11 for 661 and later */
3691#ifdef CONFIG_FB_SIS_315
3692static void
3693sisfb_fixup_SR11(struct sis_video_info *ivideo)
3694{
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003695 u8 tmpreg;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003696
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003697 if(ivideo->chip >= SIS_661) {
3698 inSISIDXREG(SISSR,0x11,tmpreg);
3699 if(tmpreg & 0x20) {
3700 inSISIDXREG(SISSR,0x3e,tmpreg);
3701 tmpreg = (tmpreg + 1) & 0xff;
3702 outSISIDXREG(SISSR,0x3e,tmpreg);
3703 inSISIDXREG(SISSR,0x11,tmpreg);
3704 }
3705 if(tmpreg & 0xf0) {
3706 andSISIDXREG(SISSR,0x11,0x0f);
3707 }
3708 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003709}
3710#endif
3711
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003712static void
3713sisfb_set_TVxposoffset(struct sis_video_info *ivideo, int val)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003714{
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003715 if(val > 32) val = 32;
3716 if(val < -32) val = -32;
3717 ivideo->tvxpos = val;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003718
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003719 if(ivideo->sisfblocked) return;
3720 if(!ivideo->modechanged) return;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003721
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003722 if(ivideo->currentvbflags & CRT2_TV) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003723
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003724 if(ivideo->vbflags2 & VB2_CHRONTEL) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003725
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003726 int x = ivideo->tvx;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003727
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003728 switch(ivideo->chronteltype) {
3729 case 1:
3730 x += val;
3731 if(x < 0) x = 0;
3732 outSISIDXREG(SISSR,0x05,0x86);
3733 SiS_SetCH700x(&ivideo->SiS_Pr, 0x0a, (x & 0xff));
3734 SiS_SetCH70xxANDOR(&ivideo->SiS_Pr, 0x08, ((x & 0x0100) >> 7), 0xFD);
3735 break;
3736 case 2:
3737 /* Not supported by hardware */
3738 break;
3739 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003740
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003741 } else if(ivideo->vbflags2 & VB2_SISBRIDGE) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003742
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003743 u8 p2_1f,p2_20,p2_2b,p2_42,p2_43;
3744 unsigned short temp;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003745
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003746 p2_1f = ivideo->p2_1f;
3747 p2_20 = ivideo->p2_20;
3748 p2_2b = ivideo->p2_2b;
3749 p2_42 = ivideo->p2_42;
3750 p2_43 = ivideo->p2_43;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003751
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003752 temp = p2_1f | ((p2_20 & 0xf0) << 4);
3753 temp += (val * 2);
3754 p2_1f = temp & 0xff;
3755 p2_20 = (temp & 0xf00) >> 4;
3756 p2_2b = ((p2_2b & 0x0f) + (val * 2)) & 0x0f;
3757 temp = p2_43 | ((p2_42 & 0xf0) << 4);
3758 temp += (val * 2);
3759 p2_43 = temp & 0xff;
3760 p2_42 = (temp & 0xf00) >> 4;
3761 outSISIDXREG(SISPART2,0x1f,p2_1f);
3762 setSISIDXREG(SISPART2,0x20,0x0F,p2_20);
3763 setSISIDXREG(SISPART2,0x2b,0xF0,p2_2b);
3764 setSISIDXREG(SISPART2,0x42,0x0F,p2_42);
3765 outSISIDXREG(SISPART2,0x43,p2_43);
3766 }
3767 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003768}
3769
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003770static void
3771sisfb_set_TVyposoffset(struct sis_video_info *ivideo, int val)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003772{
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003773 if(val > 32) val = 32;
3774 if(val < -32) val = -32;
3775 ivideo->tvypos = val;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003776
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003777 if(ivideo->sisfblocked) return;
3778 if(!ivideo->modechanged) return;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003779
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003780 if(ivideo->currentvbflags & CRT2_TV) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003781
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003782 if(ivideo->vbflags2 & VB2_CHRONTEL) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003783
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003784 int y = ivideo->tvy;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003785
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003786 switch(ivideo->chronteltype) {
3787 case 1:
3788 y -= val;
3789 if(y < 0) y = 0;
3790 outSISIDXREG(SISSR,0x05,0x86);
3791 SiS_SetCH700x(&ivideo->SiS_Pr, 0x0b, (y & 0xff));
3792 SiS_SetCH70xxANDOR(&ivideo->SiS_Pr, 0x08, ((y & 0x0100) >> 8), 0xFE);
3793 break;
3794 case 2:
3795 /* Not supported by hardware */
3796 break;
3797 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003798
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003799 } else if(ivideo->vbflags2 & VB2_SISBRIDGE) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003800
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003801 char p2_01, p2_02;
3802 val /= 2;
3803 p2_01 = ivideo->p2_01;
3804 p2_02 = ivideo->p2_02;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003805
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003806 p2_01 += val;
3807 p2_02 += val;
3808 if(!(ivideo->currentvbflags & (TV_HIVISION | TV_YPBPR))) {
3809 while((p2_01 <= 0) || (p2_02 <= 0)) {
3810 p2_01 += 2;
3811 p2_02 += 2;
3812 }
3813 }
3814 outSISIDXREG(SISPART2,0x01,p2_01);
3815 outSISIDXREG(SISPART2,0x02,p2_02);
3816 }
3817 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003818}
3819
3820static void
3821sisfb_post_setmode(struct sis_video_info *ivideo)
3822{
Richard Knutssonc30660ea2007-02-12 00:55:06 -08003823 bool crt1isoff = false;
3824 bool doit = true;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003825#if defined(CONFIG_FB_SIS_300) || defined(CONFIG_FB_SIS_315)
3826 u8 reg;
3827#endif
3828#ifdef CONFIG_FB_SIS_315
3829 u8 reg1;
3830#endif
3831
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003832 outSISIDXREG(SISSR, 0x05, 0x86);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003833
3834#ifdef CONFIG_FB_SIS_315
3835 sisfb_fixup_SR11(ivideo);
3836#endif
3837
3838 /* Now we actually HAVE changed the display mode */
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003839 ivideo->modechanged = 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003840
3841 /* We can't switch off CRT1 if bridge is in slave mode */
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003842 if(ivideo->vbflags2 & VB2_VIDEOBRIDGE) {
Richard Knutssonc30660ea2007-02-12 00:55:06 -08003843 if(sisfb_bridgeisslave(ivideo)) doit = false;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003844 } else
3845 ivideo->sisfb_crt1off = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003846
3847#ifdef CONFIG_FB_SIS_300
3848 if(ivideo->sisvga_engine == SIS_300_VGA) {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003849 if((ivideo->sisfb_crt1off) && (doit)) {
Richard Knutssonc30660ea2007-02-12 00:55:06 -08003850 crt1isoff = true;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003851 reg = 0x00;
3852 } else {
Richard Knutssonc30660ea2007-02-12 00:55:06 -08003853 crt1isoff = false;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003854 reg = 0x80;
3855 }
3856 setSISIDXREG(SISCR, 0x17, 0x7f, reg);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003857 }
3858#endif
3859#ifdef CONFIG_FB_SIS_315
3860 if(ivideo->sisvga_engine == SIS_315_VGA) {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003861 if((ivideo->sisfb_crt1off) && (doit)) {
Richard Knutssonc30660ea2007-02-12 00:55:06 -08003862 crt1isoff = true;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003863 reg = 0x40;
3864 reg1 = 0xc0;
3865 } else {
Richard Knutssonc30660ea2007-02-12 00:55:06 -08003866 crt1isoff = false;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003867 reg = 0x00;
3868 reg1 = 0x00;
3869 }
3870 setSISIDXREG(SISCR, ivideo->SiS_Pr.SiS_MyCR63, ~0x40, reg);
3871 setSISIDXREG(SISSR, 0x1f, ~0xc0, reg1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003872 }
3873#endif
3874
3875 if(crt1isoff) {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003876 ivideo->currentvbflags &= ~VB_DISPTYPE_CRT1;
3877 ivideo->currentvbflags |= VB_SINGLE_MODE;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003878 } else {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003879 ivideo->currentvbflags |= VB_DISPTYPE_CRT1;
3880 if(ivideo->currentvbflags & VB_DISPTYPE_CRT2) {
3881 ivideo->currentvbflags |= VB_MIRROR_MODE;
3882 } else {
3883 ivideo->currentvbflags |= VB_SINGLE_MODE;
3884 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003885 }
3886
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003887 andSISIDXREG(SISSR, IND_SIS_RAMDAC_CONTROL, ~0x04);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003888
3889 if(ivideo->currentvbflags & CRT2_TV) {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003890 if(ivideo->vbflags2 & VB2_SISBRIDGE) {
3891 inSISIDXREG(SISPART2,0x1f,ivideo->p2_1f);
3892 inSISIDXREG(SISPART2,0x20,ivideo->p2_20);
3893 inSISIDXREG(SISPART2,0x2b,ivideo->p2_2b);
3894 inSISIDXREG(SISPART2,0x42,ivideo->p2_42);
3895 inSISIDXREG(SISPART2,0x43,ivideo->p2_43);
3896 inSISIDXREG(SISPART2,0x01,ivideo->p2_01);
3897 inSISIDXREG(SISPART2,0x02,ivideo->p2_02);
3898 } else if(ivideo->vbflags2 & VB2_CHRONTEL) {
3899 if(ivideo->chronteltype == 1) {
3900 ivideo->tvx = SiS_GetCH700x(&ivideo->SiS_Pr, 0x0a);
3901 ivideo->tvx |= (((SiS_GetCH700x(&ivideo->SiS_Pr, 0x08) & 0x02) >> 1) << 8);
3902 ivideo->tvy = SiS_GetCH700x(&ivideo->SiS_Pr, 0x0b);
3903 ivideo->tvy |= ((SiS_GetCH700x(&ivideo->SiS_Pr, 0x08) & 0x01) << 8);
3904 }
3905 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003906 }
3907
3908 if(ivideo->tvxpos) {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003909 sisfb_set_TVxposoffset(ivideo, ivideo->tvxpos);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003910 }
3911 if(ivideo->tvypos) {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003912 sisfb_set_TVyposoffset(ivideo, ivideo->tvypos);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003913 }
3914
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003915 /* Eventually sync engines */
3916 sisfb_check_engine_and_sync(ivideo);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003917
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003918 /* (Re-)Initialize chip engines */
3919 if(ivideo->accel) {
3920 sisfb_engine_init(ivideo);
3921 } else {
3922 ivideo->engineok = 0;
3923 }
3924}
Linus Torvalds1da177e2005-04-16 15:20:36 -07003925
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003926static int
3927sisfb_reset_mode(struct sis_video_info *ivideo)
3928{
3929 if(sisfb_set_mode(ivideo, 0))
3930 return 1;
3931
3932 sisfb_set_pitch(ivideo);
3933 sisfb_set_base_CRT1(ivideo, ivideo->current_base);
3934 sisfb_set_base_CRT2(ivideo, ivideo->current_base);
3935
3936 return 0;
3937}
3938
3939static void
3940sisfb_handle_command(struct sis_video_info *ivideo, struct sisfb_cmd *sisfb_command)
3941{
3942 int mycrt1off;
3943
3944 switch(sisfb_command->sisfb_cmd) {
3945 case SISFB_CMD_GETVBFLAGS:
3946 if(!ivideo->modechanged) {
3947 sisfb_command->sisfb_result[0] = SISFB_CMD_ERR_EARLY;
3948 } else {
3949 sisfb_command->sisfb_result[0] = SISFB_CMD_ERR_OK;
3950 sisfb_command->sisfb_result[1] = ivideo->currentvbflags;
3951 sisfb_command->sisfb_result[2] = ivideo->vbflags2;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003952 }
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003953 break;
3954 case SISFB_CMD_SWITCHCRT1:
3955 /* arg[0]: 0 = off, 1 = on, 99 = query */
3956 if(!ivideo->modechanged) {
3957 sisfb_command->sisfb_result[0] = SISFB_CMD_ERR_EARLY;
3958 } else if(sisfb_command->sisfb_arg[0] == 99) {
3959 /* Query */
3960 sisfb_command->sisfb_result[1] = ivideo->sisfb_crt1off ? 0 : 1;
3961 sisfb_command->sisfb_result[0] = SISFB_CMD_ERR_OK;
3962 } else if(ivideo->sisfblocked) {
3963 sisfb_command->sisfb_result[0] = SISFB_CMD_ERR_LOCKED;
3964 } else if((!(ivideo->currentvbflags & CRT2_ENABLE)) &&
3965 (sisfb_command->sisfb_arg[0] == 0)) {
3966 sisfb_command->sisfb_result[0] = SISFB_CMD_ERR_NOCRT2;
3967 } else {
3968 sisfb_command->sisfb_result[0] = SISFB_CMD_ERR_OK;
3969 mycrt1off = sisfb_command->sisfb_arg[0] ? 0 : 1;
3970 if( ((ivideo->currentvbflags & VB_DISPTYPE_CRT1) && mycrt1off) ||
3971 ((!(ivideo->currentvbflags & VB_DISPTYPE_CRT1)) && !mycrt1off) ) {
3972 ivideo->sisfb_crt1off = mycrt1off;
3973 if(sisfb_reset_mode(ivideo)) {
3974 sisfb_command->sisfb_result[0] = SISFB_CMD_ERR_OTHER;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003975 }
3976 }
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003977 sisfb_command->sisfb_result[1] = ivideo->sisfb_crt1off ? 0 : 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003978 }
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003979 break;
3980 /* more to come */
3981 default:
3982 sisfb_command->sisfb_result[0] = SISFB_CMD_ERR_UNKNOWN;
3983 printk(KERN_ERR "sisfb: Unknown command 0x%x\n",
3984 sisfb_command->sisfb_cmd);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003985 }
3986}
3987
3988#ifndef MODULE
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003989SISINITSTATIC int __init
3990sisfb_setup(char *options)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003991{
3992 char *this_opt;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003993
Linus Torvalds1da177e2005-04-16 15:20:36 -07003994 sisfb_setdefaultparms();
3995
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003996 if(!options || !(*options))
Linus Torvalds1da177e2005-04-16 15:20:36 -07003997 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003998
3999 while((this_opt = strsep(&options, ",")) != NULL) {
4000
4001 if(!(*this_opt)) continue;
4002
4003 if(!strnicmp(this_opt, "off", 3)) {
4004 sisfb_off = 1;
4005 } else if(!strnicmp(this_opt, "forcecrt2type:", 14)) {
4006 /* Need to check crt2 type first for fstn/dstn */
4007 sisfb_search_crt2type(this_opt + 14);
4008 } else if(!strnicmp(this_opt, "tvmode:",7)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004009 sisfb_search_tvstd(this_opt + 7);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004010 } else if(!strnicmp(this_opt, "tvstandard:",11)) {
4011 sisfb_search_tvstd(this_opt + 11);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004012 } else if(!strnicmp(this_opt, "mode:", 5)) {
Richard Knutssonc30660ea2007-02-12 00:55:06 -08004013 sisfb_search_mode(this_opt + 5, false);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004014 } else if(!strnicmp(this_opt, "vesa:", 5)) {
Richard Knutssonc30660ea2007-02-12 00:55:06 -08004015 sisfb_search_vesamode(simple_strtoul(this_opt + 5, NULL, 0), false);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004016 } else if(!strnicmp(this_opt, "rate:", 5)) {
4017 sisfb_parm_rate = simple_strtoul(this_opt + 5, NULL, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004018 } else if(!strnicmp(this_opt, "forcecrt1:", 10)) {
4019 sisfb_forcecrt1 = (int)simple_strtoul(this_opt + 10, NULL, 0);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004020 } else if(!strnicmp(this_opt, "mem:",4)) {
4021 sisfb_parm_mem = simple_strtoul(this_opt + 4, NULL, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004022 } else if(!strnicmp(this_opt, "pdc:", 4)) {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004023 sisfb_pdc = simple_strtoul(this_opt + 4, NULL, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004024 } else if(!strnicmp(this_opt, "pdc1:", 5)) {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004025 sisfb_pdca = simple_strtoul(this_opt + 5, NULL, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004026 } else if(!strnicmp(this_opt, "noaccel", 7)) {
4027 sisfb_accel = 0;
4028 } else if(!strnicmp(this_opt, "accel", 5)) {
4029 sisfb_accel = -1;
4030 } else if(!strnicmp(this_opt, "noypan", 6)) {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004031 sisfb_ypan = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004032 } else if(!strnicmp(this_opt, "ypan", 4)) {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004033 sisfb_ypan = -1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004034 } else if(!strnicmp(this_opt, "nomax", 5)) {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004035 sisfb_max = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004036 } else if(!strnicmp(this_opt, "max", 3)) {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004037 sisfb_max = -1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004038 } else if(!strnicmp(this_opt, "userom:", 7)) {
4039 sisfb_userom = (int)simple_strtoul(this_opt + 7, NULL, 0);
4040 } else if(!strnicmp(this_opt, "useoem:", 7)) {
4041 sisfb_useoem = (int)simple_strtoul(this_opt + 7, NULL, 0);
4042 } else if(!strnicmp(this_opt, "nocrt2rate", 10)) {
4043 sisfb_nocrt2rate = 1;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004044 } else if(!strnicmp(this_opt, "scalelcd:", 9)) {
4045 unsigned long temp = 2;
4046 temp = simple_strtoul(this_opt + 9, NULL, 0);
4047 if((temp == 0) || (temp == 1)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004048 sisfb_scalelcd = temp ^ 1;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004049 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004050 } else if(!strnicmp(this_opt, "tvxposoffset:", 13)) {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004051 int temp = 0;
4052 temp = (int)simple_strtol(this_opt + 13, NULL, 0);
4053 if((temp >= -32) && (temp <= 32)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004054 sisfb_tvxposoffset = temp;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004055 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004056 } else if(!strnicmp(this_opt, "tvyposoffset:", 13)) {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004057 int temp = 0;
4058 temp = (int)simple_strtol(this_opt + 13, NULL, 0);
4059 if((temp >= -32) && (temp <= 32)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004060 sisfb_tvyposoffset = temp;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004061 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004062 } else if(!strnicmp(this_opt, "specialtiming:", 14)) {
4063 sisfb_search_specialtiming(this_opt + 14);
4064 } else if(!strnicmp(this_opt, "lvdshl:", 7)) {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004065 int temp = 4;
4066 temp = simple_strtoul(this_opt + 7, NULL, 0);
4067 if((temp >= 0) && (temp <= 3)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004068 sisfb_lvdshl = temp;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004069 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004070 } else if(this_opt[0] >= '0' && this_opt[0] <= '9') {
Richard Knutssonc30660ea2007-02-12 00:55:06 -08004071 sisfb_search_mode(this_opt, true);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004072#if !defined(__i386__) && !defined(__x86_64__)
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004073 } else if(!strnicmp(this_opt, "resetcard", 9)) {
4074 sisfb_resetcard = 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004075 } else if(!strnicmp(this_opt, "videoram:", 9)) {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004076 sisfb_videoram = simple_strtoul(this_opt + 9, NULL, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004077#endif
4078 } else {
4079 printk(KERN_INFO "sisfb: Invalid option %s\n", this_opt);
4080 }
4081
4082 }
4083
Linus Torvalds1da177e2005-04-16 15:20:36 -07004084 return 0;
4085}
4086#endif
4087
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004088static int __devinit
4089sisfb_check_rom(SIS_IOTYPE1 *rom_base, struct sis_video_info *ivideo)
4090{
4091 SIS_IOTYPE1 *rom;
4092 int romptr;
4093
4094 if((readb(rom_base) != 0x55) || (readb(rom_base + 1) != 0xaa))
4095 return 0;
4096
4097 romptr = (readb(rom_base + 0x18) | (readb(rom_base + 0x19) << 8));
4098 if(romptr > (0x10000 - 8))
4099 return 0;
4100
4101 rom = rom_base + romptr;
4102
4103 if((readb(rom) != 'P') || (readb(rom + 1) != 'C') ||
4104 (readb(rom + 2) != 'I') || (readb(rom + 3) != 'R'))
4105 return 0;
4106
4107 if((readb(rom + 4) | (readb(rom + 5) << 8)) != ivideo->chip_vendor)
4108 return 0;
4109
4110 if((readb(rom + 6) | (readb(rom + 7) << 8)) != ivideo->chip_id)
4111 return 0;
4112
4113 return 1;
4114}
4115
4116static unsigned char * __devinit
4117sisfb_find_rom(struct pci_dev *pdev)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004118{
4119 struct sis_video_info *ivideo = pci_get_drvdata(pdev);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004120 SIS_IOTYPE1 *rom_base;
4121 unsigned char *myrombase = NULL;
4122 u32 temp;
4123#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,11)
4124 size_t romsize;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004125
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004126 /* First, try the official pci ROM functions (except
4127 * on integrated chipsets which have no ROM).
4128 */
4129
4130 if(!ivideo->nbridge) {
4131
4132 if((rom_base = pci_map_rom(pdev, &romsize))) {
4133
4134 if(sisfb_check_rom(rom_base, ivideo)) {
4135
4136 if((myrombase = vmalloc(65536))) {
4137
4138 /* Work around bug in pci/rom.c: Folks forgot to check
4139 * whether the size retrieved from the BIOS image eventually
4140 * is larger than the mapped size
4141 */
4142 if(pci_resource_len(pdev, PCI_ROM_RESOURCE) < romsize)
4143 romsize = pci_resource_len(pdev, PCI_ROM_RESOURCE);
4144
4145 memcpy_fromio(myrombase, rom_base,
4146 (romsize > 65536) ? 65536 : romsize);
4147 }
4148 }
4149 pci_unmap_rom(pdev, rom_base);
4150 }
4151 }
4152
4153 if(myrombase) return myrombase;
4154#endif
4155
4156 /* Otherwise do it the conventional way. */
Linus Torvalds1da177e2005-04-16 15:20:36 -07004157
4158#if defined(__i386__) || defined(__x86_64__)
4159
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004160 for(temp = 0x000c0000; temp < 0x000f0000; temp += 0x00001000) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004161
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004162 rom_base = ioremap(temp, 65536);
4163 if(!rom_base)
4164 continue;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004165
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004166 if(!sisfb_check_rom(rom_base, ivideo)) {
4167 iounmap(rom_base);
4168 continue;
4169 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004170
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004171 if((myrombase = vmalloc(65536)))
4172 memcpy_fromio(myrombase, rom_base, 65536);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004173
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004174 iounmap(rom_base);
4175 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004176
Linus Torvalds1da177e2005-04-16 15:20:36 -07004177 }
4178
4179#else
4180
4181 pci_read_config_dword(pdev, PCI_ROM_ADDRESS, &temp);
4182 pci_write_config_dword(pdev, PCI_ROM_ADDRESS,
4183 (ivideo->video_base & PCI_ROM_ADDRESS_MASK) | PCI_ROM_ADDRESS_ENABLE);
4184
4185 rom_base = ioremap(ivideo->video_base, 65536);
4186 if(rom_base) {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004187 if(sisfb_check_rom(rom_base, ivideo)) {
4188 if((myrombase = vmalloc(65536)))
4189 memcpy_fromio(myrombase, rom_base, 65536);
4190 }
4191 iounmap(rom_base);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004192 }
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004193
4194 pci_write_config_dword(pdev, PCI_ROM_ADDRESS, temp);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004195
4196#endif
4197
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004198 return myrombase;
4199}
4200
4201static void __devinit
4202sisfb_post_map_vram(struct sis_video_info *ivideo, unsigned int *mapsize,
4203 unsigned int min)
4204{
4205 ivideo->video_vbase = ioremap(ivideo->video_base, (*mapsize));
4206
4207 if(!ivideo->video_vbase) {
4208 printk(KERN_ERR
4209 "sisfb: Unable to map maximum video RAM for size detection\n");
4210 (*mapsize) >>= 1;
4211 while((!(ivideo->video_vbase = ioremap(ivideo->video_base, (*mapsize))))) {
4212 (*mapsize) >>= 1;
4213 if((*mapsize) < (min << 20))
4214 break;
4215 }
4216 if(ivideo->video_vbase) {
4217 printk(KERN_ERR
4218 "sisfb: Video RAM size detection limited to %dMB\n",
4219 (int)((*mapsize) >> 20));
4220 }
4221 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004222}
4223
4224#ifdef CONFIG_FB_SIS_300
4225static int __devinit
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004226sisfb_post_300_buswidth(struct sis_video_info *ivideo)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004227{
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004228 SIS_IOTYPE1 *FBAddress = ivideo->video_vbase;
4229 unsigned short temp;
4230 unsigned char reg;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004231 int i, j;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004232
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004233 andSISIDXREG(SISSR, 0x15, 0xFB);
4234 orSISIDXREG(SISSR, 0x15, 0x04);
4235 outSISIDXREG(SISSR, 0x13, 0x00);
4236 outSISIDXREG(SISSR, 0x14, 0xBF);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004237
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004238 for(i = 0; i < 2; i++) {
4239 temp = 0x1234;
4240 for(j = 0; j < 4; j++) {
4241 writew(temp, FBAddress);
4242 if(readw(FBAddress) == temp)
4243 break;
4244 orSISIDXREG(SISSR, 0x3c, 0x01);
4245 inSISIDXREG(SISSR, 0x05, reg);
4246 inSISIDXREG(SISSR, 0x05, reg);
4247 andSISIDXREG(SISSR, 0x3c, 0xfe);
4248 inSISIDXREG(SISSR, 0x05, reg);
4249 inSISIDXREG(SISSR, 0x05, reg);
4250 temp++;
4251 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004252 }
4253
4254 writel(0x01234567L, FBAddress);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004255 writel(0x456789ABL, (FBAddress + 4));
4256 writel(0x89ABCDEFL, (FBAddress + 8));
4257 writel(0xCDEF0123L, (FBAddress + 12));
4258
4259 inSISIDXREG(SISSR, 0x3b, reg);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004260 if(reg & 0x01) {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004261 if(readl((FBAddress + 12)) == 0xCDEF0123L)
4262 return 4; /* Channel A 128bit */
Linus Torvalds1da177e2005-04-16 15:20:36 -07004263 }
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004264
4265 if(readl((FBAddress + 4)) == 0x456789ABL)
4266 return 2; /* Channel B 64bit */
4267
4268 return 1; /* 32bit */
4269}
4270
4271static int __devinit
4272sisfb_post_300_rwtest(struct sis_video_info *ivideo, int iteration, int buswidth,
4273 int PseudoRankCapacity, int PseudoAdrPinCount,
4274 unsigned int mapsize)
4275{
4276 SIS_IOTYPE1 *FBAddr = ivideo->video_vbase;
4277 unsigned short sr14;
4278 unsigned int k, RankCapacity, PageCapacity, BankNumHigh, BankNumMid;
4279 unsigned int PhysicalAdrOtherPage, PhysicalAdrHigh, PhysicalAdrHalfPage;
4280 static const unsigned short SiS_DRAMType[17][5] = {
4281 {0x0C,0x0A,0x02,0x40,0x39},
4282 {0x0D,0x0A,0x01,0x40,0x48},
4283 {0x0C,0x09,0x02,0x20,0x35},
4284 {0x0D,0x09,0x01,0x20,0x44},
4285 {0x0C,0x08,0x02,0x10,0x31},
4286 {0x0D,0x08,0x01,0x10,0x40},
4287 {0x0C,0x0A,0x01,0x20,0x34},
4288 {0x0C,0x09,0x01,0x08,0x32},
4289 {0x0B,0x08,0x02,0x08,0x21},
4290 {0x0C,0x08,0x01,0x08,0x30},
4291 {0x0A,0x08,0x02,0x04,0x11},
4292 {0x0B,0x0A,0x01,0x10,0x28},
4293 {0x09,0x08,0x02,0x02,0x01},
4294 {0x0B,0x09,0x01,0x08,0x24},
4295 {0x0B,0x08,0x01,0x04,0x20},
4296 {0x0A,0x08,0x01,0x02,0x10},
4297 {0x09,0x08,0x01,0x01,0x00}
4298 };
4299
4300 for(k = 0; k <= 16; k++) {
4301
4302 RankCapacity = buswidth * SiS_DRAMType[k][3];
4303
4304 if(RankCapacity != PseudoRankCapacity)
4305 continue;
4306
4307 if((SiS_DRAMType[k][2] + SiS_DRAMType[k][0]) > PseudoAdrPinCount)
4308 continue;
4309
4310 BankNumHigh = RankCapacity * 16 * iteration - 1;
4311 if(iteration == 3) { /* Rank No */
4312 BankNumMid = RankCapacity * 16 - 1;
4313 } else {
4314 BankNumMid = RankCapacity * 16 * iteration / 2 - 1;
4315 }
4316
4317 PageCapacity = (1 << SiS_DRAMType[k][1]) * buswidth * 4;
4318 PhysicalAdrHigh = BankNumHigh;
4319 PhysicalAdrHalfPage = (PageCapacity / 2 + PhysicalAdrHigh) % PageCapacity;
4320 PhysicalAdrOtherPage = PageCapacity * SiS_DRAMType[k][2] + PhysicalAdrHigh;
4321
4322 andSISIDXREG(SISSR, 0x15, 0xFB); /* Test */
4323 orSISIDXREG(SISSR, 0x15, 0x04); /* Test */
4324 sr14 = (SiS_DRAMType[k][3] * buswidth) - 1;
4325 if(buswidth == 4) sr14 |= 0x80;
4326 else if(buswidth == 2) sr14 |= 0x40;
4327 outSISIDXREG(SISSR, 0x13, SiS_DRAMType[k][4]);
4328 outSISIDXREG(SISSR, 0x14, sr14);
4329
4330 BankNumHigh <<= 16;
4331 BankNumMid <<= 16;
4332
4333 if((BankNumHigh + PhysicalAdrHigh >= mapsize) ||
4334 (BankNumMid + PhysicalAdrHigh >= mapsize) ||
4335 (BankNumHigh + PhysicalAdrHalfPage >= mapsize) ||
4336 (BankNumHigh + PhysicalAdrOtherPage >= mapsize))
4337 continue;
4338
4339 /* Write data */
4340 writew(((unsigned short)PhysicalAdrHigh),
4341 (FBAddr + BankNumHigh + PhysicalAdrHigh));
4342 writew(((unsigned short)BankNumMid),
4343 (FBAddr + BankNumMid + PhysicalAdrHigh));
4344 writew(((unsigned short)PhysicalAdrHalfPage),
4345 (FBAddr + BankNumHigh + PhysicalAdrHalfPage));
4346 writew(((unsigned short)PhysicalAdrOtherPage),
4347 (FBAddr + BankNumHigh + PhysicalAdrOtherPage));
4348
4349 /* Read data */
4350 if(readw(FBAddr + BankNumHigh + PhysicalAdrHigh) == PhysicalAdrHigh)
4351 return 1;
4352 }
4353
4354 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004355}
4356
4357static void __devinit
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004358sisfb_post_300_ramsize(struct pci_dev *pdev, unsigned int mapsize)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004359{
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004360 struct sis_video_info *ivideo = pci_get_drvdata(pdev);
4361 int i, j, buswidth;
4362 int PseudoRankCapacity, PseudoAdrPinCount;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004363
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004364 buswidth = sisfb_post_300_buswidth(ivideo);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004365
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004366 for(i = 6; i >= 0; i--) {
4367 PseudoRankCapacity = 1 << i;
4368 for(j = 4; j >= 1; j--) {
4369 PseudoAdrPinCount = 15 - j;
4370 if((PseudoRankCapacity * j) <= 64) {
4371 if(sisfb_post_300_rwtest(ivideo,
4372 j,
4373 buswidth,
4374 PseudoRankCapacity,
4375 PseudoAdrPinCount,
4376 mapsize))
4377 return;
4378 }
4379 }
4380 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004381}
4382
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004383static void __devinit
4384sisfb_post_sis300(struct pci_dev *pdev)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004385{
4386 struct sis_video_info *ivideo = pci_get_drvdata(pdev);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004387 unsigned char *bios = ivideo->SiS_Pr.VirtualRomBase;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004388 u8 reg, v1, v2, v3, v4, v5, v6, v7, v8;
4389 u16 index, rindex, memtype = 0;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004390 unsigned int mapsize;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004391
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004392 if(!ivideo->SiS_Pr.UseROM)
4393 bios = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004394
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004395 outSISIDXREG(SISSR, 0x05, 0x86);
4396
4397 if(bios) {
4398 if(bios[0x52] & 0x80) {
4399 memtype = bios[0x52];
4400 } else {
4401 inSISIDXREG(SISSR, 0x3a, memtype);
4402 }
4403 memtype &= 0x07;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004404 }
4405
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004406 v3 = 0x80; v6 = 0x80;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004407 if(ivideo->revision_id <= 0x13) {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004408 v1 = 0x44; v2 = 0x42;
4409 v4 = 0x44; v5 = 0x42;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004410 } else {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004411 v1 = 0x68; v2 = 0x43; /* Assume 125Mhz MCLK */
4412 v4 = 0x68; v5 = 0x43; /* Assume 125Mhz ECLK */
4413 if(bios) {
4414 index = memtype * 5;
4415 rindex = index + 0x54;
4416 v1 = bios[rindex++];
4417 v2 = bios[rindex++];
4418 v3 = bios[rindex++];
4419 rindex = index + 0x7c;
4420 v4 = bios[rindex++];
4421 v5 = bios[rindex++];
4422 v6 = bios[rindex++];
4423 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004424 }
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004425 outSISIDXREG(SISSR, 0x28, v1);
4426 outSISIDXREG(SISSR, 0x29, v2);
4427 outSISIDXREG(SISSR, 0x2a, v3);
4428 outSISIDXREG(SISSR, 0x2e, v4);
4429 outSISIDXREG(SISSR, 0x2f, v5);
4430 outSISIDXREG(SISSR, 0x30, v6);
4431
Linus Torvalds1da177e2005-04-16 15:20:36 -07004432 v1 = 0x10;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004433 if(bios)
4434 v1 = bios[0xa4];
4435 outSISIDXREG(SISSR, 0x07, v1); /* DAC speed */
4436
4437 outSISIDXREG(SISSR, 0x11, 0x0f); /* DDC, power save */
4438
Linus Torvalds1da177e2005-04-16 15:20:36 -07004439 v1 = 0x01; v2 = 0x43; v3 = 0x1e; v4 = 0x2a;
4440 v5 = 0x06; v6 = 0x00; v7 = 0x00; v8 = 0x00;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004441 if(bios) {
4442 memtype += 0xa5;
4443 v1 = bios[memtype];
4444 v2 = bios[memtype + 8];
4445 v3 = bios[memtype + 16];
4446 v4 = bios[memtype + 24];
4447 v5 = bios[memtype + 32];
4448 v6 = bios[memtype + 40];
4449 v7 = bios[memtype + 48];
4450 v8 = bios[memtype + 56];
Linus Torvalds1da177e2005-04-16 15:20:36 -07004451 }
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004452 if(ivideo->revision_id >= 0x80)
4453 v3 &= 0xfd;
4454 outSISIDXREG(SISSR, 0x15, v1); /* Ram type (assuming 0, BIOS 0xa5 step 8) */
4455 outSISIDXREG(SISSR, 0x16, v2);
4456 outSISIDXREG(SISSR, 0x17, v3);
4457 outSISIDXREG(SISSR, 0x18, v4);
4458 outSISIDXREG(SISSR, 0x19, v5);
4459 outSISIDXREG(SISSR, 0x1a, v6);
4460 outSISIDXREG(SISSR, 0x1b, v7);
4461 outSISIDXREG(SISSR, 0x1c, v8); /* ---- */
4462 andSISIDXREG(SISSR, 0x15 ,0xfb);
4463 orSISIDXREG(SISSR, 0x15, 0x04);
4464 if(bios) {
4465 if(bios[0x53] & 0x02) {
4466 orSISIDXREG(SISSR, 0x19, 0x20);
4467 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004468 }
4469 v1 = 0x04; /* DAC pedestal (BIOS 0xe5) */
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004470 if(ivideo->revision_id >= 0x80)
4471 v1 |= 0x01;
4472 outSISIDXREG(SISSR, 0x1f, v1);
4473 outSISIDXREG(SISSR, 0x20, 0xa4); /* linear & relocated io & disable a0000 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07004474 v1 = 0xf6; v2 = 0x0d; v3 = 0x00;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004475 if(bios) {
4476 v1 = bios[0xe8];
4477 v2 = bios[0xe9];
4478 v3 = bios[0xea];
Linus Torvalds1da177e2005-04-16 15:20:36 -07004479 }
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004480 outSISIDXREG(SISSR, 0x23, v1);
4481 outSISIDXREG(SISSR, 0x24, v2);
4482 outSISIDXREG(SISSR, 0x25, v3);
4483 outSISIDXREG(SISSR, 0x21, 0x84);
4484 outSISIDXREG(SISSR, 0x22, 0x00);
4485 outSISIDXREG(SISCR, 0x37, 0x00);
4486 orSISIDXREG(SISPART1, 0x24, 0x01); /* unlock crt2 */
4487 outSISIDXREG(SISPART1, 0x00, 0x00);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004488 v1 = 0x40; v2 = 0x11;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004489 if(bios) {
4490 v1 = bios[0xec];
4491 v2 = bios[0xeb];
Linus Torvalds1da177e2005-04-16 15:20:36 -07004492 }
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004493 outSISIDXREG(SISPART1, 0x02, v1);
4494
4495 if(ivideo->revision_id >= 0x80)
4496 v2 &= ~0x01;
4497
4498 inSISIDXREG(SISPART4, 0x00, reg);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004499 if((reg == 1) || (reg == 2)) {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004500 outSISIDXREG(SISCR, 0x37, 0x02);
4501 outSISIDXREG(SISPART2, 0x00, 0x1c);
4502 v4 = 0x00; v5 = 0x00; v6 = 0x10;
4503 if(ivideo->SiS_Pr.UseROM) {
4504 v4 = bios[0xf5];
4505 v5 = bios[0xf6];
4506 v6 = bios[0xf7];
4507 }
4508 outSISIDXREG(SISPART4, 0x0d, v4);
4509 outSISIDXREG(SISPART4, 0x0e, v5);
4510 outSISIDXREG(SISPART4, 0x10, v6);
4511 outSISIDXREG(SISPART4, 0x0f, 0x3f);
4512 inSISIDXREG(SISPART4, 0x01, reg);
4513 if(reg >= 0xb0) {
4514 inSISIDXREG(SISPART4, 0x23, reg);
4515 reg &= 0x20;
4516 reg <<= 1;
4517 outSISIDXREG(SISPART4, 0x23, reg);
4518 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004519 } else {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004520 v2 &= ~0x10;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004521 }
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004522 outSISIDXREG(SISSR, 0x32, v2);
4523
4524 andSISIDXREG(SISPART1, 0x24, 0xfe); /* Lock CRT2 */
4525
4526 inSISIDXREG(SISSR, 0x16, reg);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004527 reg &= 0xc3;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004528 outSISIDXREG(SISCR, 0x35, reg);
4529 outSISIDXREG(SISCR, 0x83, 0x00);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004530#if !defined(__i386__) && !defined(__x86_64__)
4531 if(sisfb_videoram) {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004532 outSISIDXREG(SISSR, 0x13, 0x28); /* ? */
4533 reg = ((sisfb_videoram >> 10) - 1) | 0x40;
4534 outSISIDXREG(SISSR, 0x14, reg);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004535 } else {
4536#endif
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004537 /* Need to map max FB size for finding out about RAM size */
4538 mapsize = 64 << 20;
4539 sisfb_post_map_vram(ivideo, &mapsize, 4);
4540
4541 if(ivideo->video_vbase) {
4542 sisfb_post_300_ramsize(pdev, mapsize);
4543 iounmap(ivideo->video_vbase);
4544 } else {
4545 printk(KERN_DEBUG
4546 "sisfb: Failed to map memory for size detection, assuming 8MB\n");
4547 outSISIDXREG(SISSR, 0x13, 0x28); /* ? */
4548 outSISIDXREG(SISSR, 0x14, 0x47); /* 8MB, 64bit default */
4549 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004550#if !defined(__i386__) && !defined(__x86_64__)
4551 }
4552#endif
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004553 if(bios) {
4554 v1 = bios[0xe6];
4555 v2 = bios[0xe7];
Linus Torvalds1da177e2005-04-16 15:20:36 -07004556 } else {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004557 inSISIDXREG(SISSR, 0x3a, reg);
4558 if((reg & 0x30) == 0x30) {
4559 v1 = 0x04; /* PCI */
4560 v2 = 0x92;
4561 } else {
4562 v1 = 0x14; /* AGP */
4563 v2 = 0xb2;
4564 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004565 }
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004566 outSISIDXREG(SISSR, 0x21, v1);
4567 outSISIDXREG(SISSR, 0x22, v2);
4568
4569 /* Sense CRT1 */
4570 sisfb_sense_crt1(ivideo);
4571
4572 /* Set default mode, don't clear screen */
Richard Knutssonc30660ea2007-02-12 00:55:06 -08004573 ivideo->SiS_Pr.SiS_UseOEM = false;
4574 SiS_SetEnableDstn(&ivideo->SiS_Pr, false);
4575 SiS_SetEnableFstn(&ivideo->SiS_Pr, false);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004576 ivideo->curFSTN = ivideo->curDSTN = 0;
4577 ivideo->SiS_Pr.VideoMemorySize = 8 << 20;
4578 SiSSetMode(&ivideo->SiS_Pr, 0x2e | 0x80);
4579
4580 outSISIDXREG(SISSR, 0x05, 0x86);
4581
4582 /* Display off */
4583 orSISIDXREG(SISSR, 0x01, 0x20);
4584
4585 /* Save mode number in CR34 */
4586 outSISIDXREG(SISCR, 0x34, 0x2e);
4587
4588 /* Let everyone know what the current mode is */
4589 ivideo->modeprechange = 0x2e;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004590}
4591#endif
4592
4593#ifdef CONFIG_FB_SIS_315
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004594#if 0
4595static void __devinit
4596sisfb_post_sis315330(struct pci_dev *pdev)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004597{
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004598 /* TODO */
Linus Torvalds1da177e2005-04-16 15:20:36 -07004599}
4600#endif
4601
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004602static void __devinit
4603sisfb_post_xgi_delay(struct sis_video_info *ivideo, int delay)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004604{
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004605 unsigned int i;
4606 u8 reg;
4607
4608 for(i = 0; i <= (delay * 10 * 36); i++) {
4609 inSISIDXREG(SISSR, 0x05, reg);
4610 reg++;
4611 }
4612}
4613
4614static int __devinit
4615sisfb_find_host_bridge(struct sis_video_info *ivideo, struct pci_dev *mypdev,
4616 unsigned short pcivendor)
4617{
4618 struct pci_dev *pdev = NULL;
4619 unsigned short temp;
4620 int ret = 0;
4621
Adrian Bunk0959f0c2007-05-08 00:39:50 -07004622 while((pdev = pci_get_class(PCI_CLASS_BRIDGE_HOST, pdev))) {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004623 temp = pdev->vendor;
Adrian Bunk0959f0c2007-05-08 00:39:50 -07004624 pci_dev_put(pdev);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004625 if(temp == pcivendor) {
4626 ret = 1;
4627 break;
4628 }
4629 }
4630
4631 return ret;
4632}
4633
4634static int __devinit
4635sisfb_post_xgi_rwtest(struct sis_video_info *ivideo, int starta,
4636 unsigned int enda, unsigned int mapsize)
4637{
4638 unsigned int pos;
4639 int i;
4640
4641 writel(0, ivideo->video_vbase);
4642
4643 for(i = starta; i <= enda; i++) {
4644 pos = 1 << i;
4645 if(pos < mapsize)
4646 writel(pos, ivideo->video_vbase + pos);
4647 }
4648
4649 sisfb_post_xgi_delay(ivideo, 150);
4650
4651 if(readl(ivideo->video_vbase) != 0)
4652 return 0;
4653
4654 for(i = starta; i <= enda; i++) {
4655 pos = 1 << i;
4656 if(pos < mapsize) {
4657 if(readl(ivideo->video_vbase + pos) != pos)
4658 return 0;
4659 } else
4660 return 0;
4661 }
4662
4663 return 1;
4664}
4665
4666static void __devinit
4667sisfb_post_xgi_ramsize(struct sis_video_info *ivideo)
4668{
4669 unsigned int buswidth, ranksize, channelab, mapsize;
4670 int i, j, k, l;
4671 u8 reg, sr14;
4672 static const u8 dramsr13[12 * 5] = {
4673 0x02, 0x0e, 0x0b, 0x80, 0x5d,
4674 0x02, 0x0e, 0x0a, 0x40, 0x59,
4675 0x02, 0x0d, 0x0b, 0x40, 0x4d,
4676 0x02, 0x0e, 0x09, 0x20, 0x55,
4677 0x02, 0x0d, 0x0a, 0x20, 0x49,
4678 0x02, 0x0c, 0x0b, 0x20, 0x3d,
4679 0x02, 0x0e, 0x08, 0x10, 0x51,
4680 0x02, 0x0d, 0x09, 0x10, 0x45,
4681 0x02, 0x0c, 0x0a, 0x10, 0x39,
4682 0x02, 0x0d, 0x08, 0x08, 0x41,
4683 0x02, 0x0c, 0x09, 0x08, 0x35,
4684 0x02, 0x0c, 0x08, 0x04, 0x31
4685 };
4686 static const u8 dramsr13_4[4 * 5] = {
4687 0x02, 0x0d, 0x09, 0x40, 0x45,
4688 0x02, 0x0c, 0x09, 0x20, 0x35,
4689 0x02, 0x0c, 0x08, 0x10, 0x31,
4690 0x02, 0x0b, 0x08, 0x08, 0x21
4691 };
4692
4693 /* Enable linear mode, disable 0xa0000 address decoding */
4694 /* We disable a0000 address decoding, because
4695 * - if running on x86, if the card is disabled, it means
4696 * that another card is in the system. We don't want
4697 * to interphere with that primary card's textmode.
4698 * - if running on non-x86, there usually is no VGA window
4699 * at a0000.
4700 */
4701 orSISIDXREG(SISSR, 0x20, (0x80 | 0x04));
4702
4703 /* Need to map max FB size for finding out about RAM size */
4704 mapsize = 256 << 20;
4705 sisfb_post_map_vram(ivideo, &mapsize, 32);
4706
4707 if(!ivideo->video_vbase) {
4708 printk(KERN_ERR "sisfb: Unable to detect RAM size. Setting default.\n");
4709 outSISIDXREG(SISSR, 0x13, 0x35);
4710 outSISIDXREG(SISSR, 0x14, 0x41);
4711 /* TODO */
4712 return;
4713 }
4714
4715 /* Non-interleaving */
4716 outSISIDXREG(SISSR, 0x15, 0x00);
4717 /* No tiling */
4718 outSISIDXREG(SISSR, 0x1c, 0x00);
4719
4720 if(ivideo->chip == XGI_20) {
4721
4722 channelab = 1;
4723 inSISIDXREG(SISCR, 0x97, reg);
4724 if(!(reg & 0x01)) { /* Single 32/16 */
4725 buswidth = 32;
4726 outSISIDXREG(SISSR, 0x13, 0xb1);
4727 outSISIDXREG(SISSR, 0x14, 0x52);
4728 sisfb_post_xgi_delay(ivideo, 1);
4729 sr14 = 0x02;
4730 if(sisfb_post_xgi_rwtest(ivideo, 23, 24, mapsize))
4731 goto bail_out;
4732
4733 outSISIDXREG(SISSR, 0x13, 0x31);
4734 outSISIDXREG(SISSR, 0x14, 0x42);
4735 sisfb_post_xgi_delay(ivideo, 1);
4736 if(sisfb_post_xgi_rwtest(ivideo, 23, 23, mapsize))
4737 goto bail_out;
4738
4739 buswidth = 16;
4740 outSISIDXREG(SISSR, 0x13, 0xb1);
4741 outSISIDXREG(SISSR, 0x14, 0x41);
4742 sisfb_post_xgi_delay(ivideo, 1);
4743 sr14 = 0x01;
4744 if(sisfb_post_xgi_rwtest(ivideo, 22, 23, mapsize))
4745 goto bail_out;
4746 else
4747 outSISIDXREG(SISSR, 0x13, 0x31);
4748 } else { /* Dual 16/8 */
4749 buswidth = 16;
4750 outSISIDXREG(SISSR, 0x13, 0xb1);
4751 outSISIDXREG(SISSR, 0x14, 0x41);
4752 sisfb_post_xgi_delay(ivideo, 1);
4753 sr14 = 0x01;
4754 if(sisfb_post_xgi_rwtest(ivideo, 22, 23, mapsize))
4755 goto bail_out;
4756
4757 outSISIDXREG(SISSR, 0x13, 0x31);
4758 outSISIDXREG(SISSR, 0x14, 0x31);
4759 sisfb_post_xgi_delay(ivideo, 1);
4760 if(sisfb_post_xgi_rwtest(ivideo, 22, 22, mapsize))
4761 goto bail_out;
4762
4763 buswidth = 8;
4764 outSISIDXREG(SISSR, 0x13, 0xb1);
4765 outSISIDXREG(SISSR, 0x14, 0x30);
4766 sisfb_post_xgi_delay(ivideo, 1);
4767 sr14 = 0x00;
4768 if(sisfb_post_xgi_rwtest(ivideo, 21, 22, mapsize))
4769 goto bail_out;
4770 else
4771 outSISIDXREG(SISSR, 0x13, 0x31);
4772 }
4773
4774 } else { /* XGI_40 */
4775
4776 inSISIDXREG(SISCR, 0x97, reg);
4777 if(!(reg & 0x10)) {
4778 inSISIDXREG(SISSR, 0x39, reg);
4779 reg >>= 1;
4780 }
4781
4782 if(reg & 0x01) { /* DDRII */
4783 buswidth = 32;
4784 if(ivideo->revision_id == 2) {
4785 channelab = 2;
4786 outSISIDXREG(SISSR, 0x13, 0xa1);
4787 outSISIDXREG(SISSR, 0x14, 0x44);
4788 sr14 = 0x04;
4789 sisfb_post_xgi_delay(ivideo, 1);
4790 if(sisfb_post_xgi_rwtest(ivideo, 23, 24, mapsize))
4791 goto bail_out;
4792
4793 outSISIDXREG(SISSR, 0x13, 0x21);
4794 outSISIDXREG(SISSR, 0x14, 0x34);
4795 if(sisfb_post_xgi_rwtest(ivideo, 22, 23, mapsize))
4796 goto bail_out;
4797
4798 channelab = 1;
4799 outSISIDXREG(SISSR, 0x13, 0xa1);
4800 outSISIDXREG(SISSR, 0x14, 0x40);
4801 sr14 = 0x00;
4802 if(sisfb_post_xgi_rwtest(ivideo, 22, 23, mapsize))
4803 goto bail_out;
4804
4805 outSISIDXREG(SISSR, 0x13, 0x21);
4806 outSISIDXREG(SISSR, 0x14, 0x30);
4807 } else {
4808 channelab = 3;
4809 outSISIDXREG(SISSR, 0x13, 0xa1);
4810 outSISIDXREG(SISSR, 0x14, 0x4c);
4811 sr14 = 0x0c;
4812 sisfb_post_xgi_delay(ivideo, 1);
4813 if(sisfb_post_xgi_rwtest(ivideo, 23, 25, mapsize))
4814 goto bail_out;
4815
4816 channelab = 2;
4817 outSISIDXREG(SISSR, 0x14, 0x48);
4818 sisfb_post_xgi_delay(ivideo, 1);
4819 sr14 = 0x08;
4820 if(sisfb_post_xgi_rwtest(ivideo, 23, 24, mapsize))
4821 goto bail_out;
4822
4823 outSISIDXREG(SISSR, 0x13, 0x21);
4824 outSISIDXREG(SISSR, 0x14, 0x3c);
4825 sr14 = 0x0c;
4826
4827 if(sisfb_post_xgi_rwtest(ivideo, 23, 24, mapsize)) {
4828 channelab = 3;
4829 } else {
4830 channelab = 2;
4831 outSISIDXREG(SISSR, 0x14, 0x38);
4832 sr14 = 0x08;
4833 }
4834 }
4835 sisfb_post_xgi_delay(ivideo, 1);
4836
4837 } else { /* DDR */
4838
4839 buswidth = 64;
4840 if(ivideo->revision_id == 2) {
4841 channelab = 1;
4842 outSISIDXREG(SISSR, 0x13, 0xa1);
4843 outSISIDXREG(SISSR, 0x14, 0x52);
4844 sisfb_post_xgi_delay(ivideo, 1);
4845 sr14 = 0x02;
4846 if(sisfb_post_xgi_rwtest(ivideo, 23, 24, mapsize))
4847 goto bail_out;
4848
4849 outSISIDXREG(SISSR, 0x13, 0x21);
4850 outSISIDXREG(SISSR, 0x14, 0x42);
4851 } else {
4852 channelab = 2;
4853 outSISIDXREG(SISSR, 0x13, 0xa1);
4854 outSISIDXREG(SISSR, 0x14, 0x5a);
4855 sisfb_post_xgi_delay(ivideo, 1);
4856 sr14 = 0x0a;
4857 if(sisfb_post_xgi_rwtest(ivideo, 24, 25, mapsize))
4858 goto bail_out;
4859
4860 outSISIDXREG(SISSR, 0x13, 0x21);
4861 outSISIDXREG(SISSR, 0x14, 0x4a);
4862 }
4863 sisfb_post_xgi_delay(ivideo, 1);
4864
4865 }
4866 }
4867
4868bail_out:
4869 setSISIDXREG(SISSR, 0x14, 0xf0, sr14);
4870 sisfb_post_xgi_delay(ivideo, 1);
4871
4872 j = (ivideo->chip == XGI_20) ? 5 : 9;
4873 k = (ivideo->chip == XGI_20) ? 12 : 4;
4874
4875 for(i = 0; i < k; i++) {
4876
4877 reg = (ivideo->chip == XGI_20) ?
4878 dramsr13[(i * 5) + 4] : dramsr13_4[(i * 5) + 4];
4879 setSISIDXREG(SISSR, 0x13, 0x80, reg);
4880 sisfb_post_xgi_delay(ivideo, 50);
4881
4882 ranksize = (ivideo->chip == XGI_20) ?
4883 dramsr13[(i * 5) + 3] : dramsr13_4[(i * 5) + 3];
4884
4885 inSISIDXREG(SISSR, 0x13, reg);
4886 if(reg & 0x80) ranksize <<= 1;
4887
4888 if(ivideo->chip == XGI_20) {
4889 if(buswidth == 16) ranksize <<= 1;
4890 else if(buswidth == 32) ranksize <<= 2;
4891 } else {
4892 if(buswidth == 64) ranksize <<= 1;
4893 }
4894
4895 reg = 0;
4896 l = channelab;
4897 if(l == 3) l = 4;
4898 if((ranksize * l) <= 256) {
4899 while((ranksize >>= 1)) reg += 0x10;
4900 }
4901
4902 if(!reg) continue;
4903
4904 setSISIDXREG(SISSR, 0x14, 0x0f, (reg & 0xf0));
4905 sisfb_post_xgi_delay(ivideo, 1);
4906
4907 if(sisfb_post_xgi_rwtest(ivideo, j, ((reg >> 4) + channelab - 2 + 20), mapsize))
4908 break;
4909 }
4910
4911 iounmap(ivideo->video_vbase);
4912}
4913
4914static void __devinit
4915sisfb_post_xgi_setclocks(struct sis_video_info *ivideo, u8 regb)
4916{
4917 u8 v1, v2, v3;
4918 int index;
4919 static const u8 cs90[8 * 3] = {
4920 0x16, 0x01, 0x01,
4921 0x3e, 0x03, 0x01,
4922 0x7c, 0x08, 0x01,
4923 0x79, 0x06, 0x01,
4924 0x29, 0x01, 0x81,
4925 0x5c, 0x23, 0x01,
4926 0x5c, 0x23, 0x01,
4927 0x5c, 0x23, 0x01
4928 };
4929 static const u8 csb8[8 * 3] = {
4930 0x5c, 0x23, 0x01,
4931 0x29, 0x01, 0x01,
4932 0x7c, 0x08, 0x01,
4933 0x79, 0x06, 0x01,
4934 0x29, 0x01, 0x81,
4935 0x5c, 0x23, 0x01,
4936 0x5c, 0x23, 0x01,
4937 0x5c, 0x23, 0x01
4938 };
4939
4940 regb = 0; /* ! */
4941
4942 index = regb * 3;
4943 v1 = cs90[index]; v2 = cs90[index + 1]; v3 = cs90[index + 2];
4944 if(ivideo->haveXGIROM) {
4945 v1 = ivideo->bios_abase[0x90 + index];
4946 v2 = ivideo->bios_abase[0x90 + index + 1];
4947 v3 = ivideo->bios_abase[0x90 + index + 2];
4948 }
4949 outSISIDXREG(SISSR, 0x28, v1);
4950 outSISIDXREG(SISSR, 0x29, v2);
4951 outSISIDXREG(SISSR, 0x2a, v3);
4952 sisfb_post_xgi_delay(ivideo, 0x43);
4953 sisfb_post_xgi_delay(ivideo, 0x43);
4954 sisfb_post_xgi_delay(ivideo, 0x43);
4955 index = regb * 3;
4956 v1 = csb8[index]; v2 = csb8[index + 1]; v3 = csb8[index + 2];
4957 if(ivideo->haveXGIROM) {
4958 v1 = ivideo->bios_abase[0xb8 + index];
4959 v2 = ivideo->bios_abase[0xb8 + index + 1];
4960 v3 = ivideo->bios_abase[0xb8 + index + 2];
4961 }
4962 outSISIDXREG(SISSR, 0x2e, v1);
4963 outSISIDXREG(SISSR, 0x2f, v2);
4964 outSISIDXREG(SISSR, 0x30, v3);
4965 sisfb_post_xgi_delay(ivideo, 0x43);
4966 sisfb_post_xgi_delay(ivideo, 0x43);
4967 sisfb_post_xgi_delay(ivideo, 0x43);
4968}
4969
4970static int __devinit
4971sisfb_post_xgi(struct pci_dev *pdev)
4972{
4973 struct sis_video_info *ivideo = pci_get_drvdata(pdev);
4974 unsigned char *bios = ivideo->bios_abase;
4975 struct pci_dev *mypdev = NULL;
4976 const u8 *ptr, *ptr2;
4977 u8 v1, v2, v3, v4, v5, reg, ramtype;
4978 u32 rega, regb, regd;
4979 int i, j, k, index;
4980 static const u8 cs78[3] = { 0xf6, 0x0d, 0x00 };
4981 static const u8 cs76[2] = { 0xa3, 0xfb };
4982 static const u8 cs7b[3] = { 0xc0, 0x11, 0x00 };
4983 static const u8 cs158[8] = {
4984 0x88, 0xaa, 0x48, 0x00, 0x00, 0x00, 0x00, 0x00
4985 };
4986 static const u8 cs160[8] = {
4987 0x44, 0x77, 0x77, 0x00, 0x00, 0x00, 0x00, 0x00
4988 };
4989 static const u8 cs168[8] = {
4990 0x48, 0x78, 0x88, 0x00, 0x00, 0x00, 0x00, 0x00
4991 };
4992 static const u8 cs128[3 * 8] = {
4993 0x90, 0x28, 0x24, 0x00, 0x00, 0x00, 0x00, 0x00,
4994 0x77, 0x44, 0x44, 0x00, 0x00, 0x00, 0x00, 0x00,
4995 0x77, 0x44, 0x44, 0x00, 0x00, 0x00, 0x00, 0x00
4996 };
4997 static const u8 cs148[2 * 8] = {
4998 0x55, 0x55, 0x55, 0x00, 0x00, 0x00, 0x00, 0x00,
4999 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
5000 };
5001 static const u8 cs31a[8 * 4] = {
5002 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
5003 0xaa, 0xaa, 0xaa, 0xaa, 0x00, 0x00, 0x00, 0x00,
5004 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
5005 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
5006 };
5007 static const u8 cs33a[8 * 4] = {
5008 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
5009 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
5010 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
5011 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
5012 };
5013 static const u8 cs45a[8 * 2] = {
5014 0x00, 0x00, 0xa0, 0x00, 0xa0, 0x00, 0x00, 0x00,
5015 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
5016 };
5017 static const u8 cs170[7 * 8] = {
5018 0x54, 0x32, 0x44, 0x00, 0x00, 0x00, 0x00, 0x00,
5019 0x54, 0x43, 0x44, 0x00, 0x00, 0x00, 0x00, 0x00,
5020 0x0a, 0x05, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00,
5021 0x44, 0x34, 0x44, 0x00, 0x00, 0x00, 0x00, 0x00,
5022 0x10, 0x0a, 0x0a, 0x00, 0x00, 0x00, 0x00, 0x00,
5023 0x11, 0x0c, 0x0c, 0x00, 0x00, 0x00, 0x00, 0x00,
5024 0x05, 0x05, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00
5025 };
5026 static const u8 cs1a8[3 * 8] = {
5027 0xf0, 0xf0, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x00,
5028 0x05, 0x02, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00,
5029 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
5030 };
5031 static const u8 cs100[2 * 8] = {
5032 0xc4, 0x04, 0x84, 0x00, 0x00, 0x00, 0x00, 0x00,
5033 0xc4, 0x04, 0x84, 0x00, 0x00, 0x00, 0x00, 0x00
5034 };
5035
5036 /* VGA enable */
5037 reg = inSISREG(SISVGAENABLE) | 0x01;
5038 outSISREG(SISVGAENABLE, reg);
5039
5040 /* Misc */
5041 reg = inSISREG(SISMISCR) | 0x01;
5042 outSISREG(SISMISCW, reg);
5043
5044 /* Unlock SR */
5045 outSISIDXREG(SISSR, 0x05, 0x86);
5046 inSISIDXREG(SISSR, 0x05, reg);
5047 if(reg != 0xa1)
5048 return 0;
5049
5050 /* Clear some regs */
5051 for(i = 0; i < 0x22; i++) {
5052 if(0x06 + i == 0x20) continue;
5053 outSISIDXREG(SISSR, 0x06 + i, 0x00);
5054 }
5055 for(i = 0; i < 0x0b; i++) {
5056 outSISIDXREG(SISSR, 0x31 + i, 0x00);
5057 }
5058 for(i = 0; i < 0x10; i++) {
5059 outSISIDXREG(SISCR, 0x30 + i, 0x00);
5060 }
5061
5062 ptr = cs78;
5063 if(ivideo->haveXGIROM) {
5064 ptr = (const u8 *)&bios[0x78];
5065 }
5066 for(i = 0; i < 3; i++) {
5067 outSISIDXREG(SISSR, 0x23 + i, ptr[i]);
5068 }
5069
5070 ptr = cs76;
5071 if(ivideo->haveXGIROM) {
5072 ptr = (const u8 *)&bios[0x76];
5073 }
5074 for(i = 0; i < 2; i++) {
5075 outSISIDXREG(SISSR, 0x21 + i, ptr[i]);
5076 }
5077
5078 v1 = 0x18; v2 = 0x00;
5079 if(ivideo->haveXGIROM) {
5080 v1 = bios[0x74];
5081 v2 = bios[0x75];
5082 }
5083 outSISIDXREG(SISSR, 0x07, v1);
5084 outSISIDXREG(SISSR, 0x11, 0x0f);
5085 outSISIDXREG(SISSR, 0x1f, v2);
5086 /* PCI linear mode, RelIO enabled, A0000 decoding disabled */
5087 outSISIDXREG(SISSR, 0x20, 0x80 | 0x20 | 0x04);
5088 outSISIDXREG(SISSR, 0x27, 0x74);
5089
5090 ptr = cs7b;
5091 if(ivideo->haveXGIROM) {
5092 ptr = (const u8 *)&bios[0x7b];
5093 }
5094 for(i = 0; i < 3; i++) {
5095 outSISIDXREG(SISSR, 0x31 + i, ptr[i]);
5096 }
5097
5098 if(ivideo->chip == XGI_40) {
5099 if(ivideo->revision_id == 2) {
5100 setSISIDXREG(SISSR, 0x3b, 0x3f, 0xc0);
5101 }
5102 outSISIDXREG(SISCR, 0x7d, 0xfe);
5103 outSISIDXREG(SISCR, 0x7e, 0x0f);
5104 }
5105 if(ivideo->revision_id == 0) { /* 40 *and* 20? */
5106 andSISIDXREG(SISCR, 0x58, 0xd7);
5107 inSISIDXREG(SISCR, 0xcb, reg);
5108 if(reg & 0x20) {
5109 setSISIDXREG(SISCR, 0x58, 0xd7, (reg & 0x10) ? 0x08 : 0x20); /* =0x28 Z7 ? */
5110 }
5111 }
5112
5113 reg = (ivideo->chip == XGI_40) ? 0x20 : 0x00;
5114 setSISIDXREG(SISCR, 0x38, 0x1f, reg);
5115
5116 if(ivideo->chip == XGI_20) {
5117 outSISIDXREG(SISSR, 0x36, 0x70);
5118 } else {
5119 outSISIDXREG(SISVID, 0x00, 0x86);
5120 outSISIDXREG(SISVID, 0x32, 0x00);
5121 outSISIDXREG(SISVID, 0x30, 0x00);
5122 outSISIDXREG(SISVID, 0x32, 0x01);
5123 outSISIDXREG(SISVID, 0x30, 0x00);
5124 andSISIDXREG(SISVID, 0x2f, 0xdf);
5125 andSISIDXREG(SISCAP, 0x00, 0x3f);
5126
5127 outSISIDXREG(SISPART1, 0x2f, 0x01);
5128 outSISIDXREG(SISPART1, 0x00, 0x00);
5129 outSISIDXREG(SISPART1, 0x02, bios[0x7e]);
5130 outSISIDXREG(SISPART1, 0x2e, 0x08);
5131 andSISIDXREG(SISPART1, 0x35, 0x7f);
5132 andSISIDXREG(SISPART1, 0x50, 0xfe);
5133
5134 inSISIDXREG(SISPART4, 0x00, reg);
5135 if(reg == 1 || reg == 2) {
5136 outSISIDXREG(SISPART2, 0x00, 0x1c);
5137 outSISIDXREG(SISPART4, 0x0d, bios[0x7f]);
5138 outSISIDXREG(SISPART4, 0x0e, bios[0x80]);
5139 outSISIDXREG(SISPART4, 0x10, bios[0x81]);
5140 andSISIDXREG(SISPART4, 0x0f, 0x3f);
5141
5142 inSISIDXREG(SISPART4, 0x01, reg);
5143 if((reg & 0xf0) >= 0xb0) {
5144 inSISIDXREG(SISPART4, 0x23, reg);
5145 if(reg & 0x20) reg |= 0x40;
5146 outSISIDXREG(SISPART4, 0x23, reg);
5147 reg = (reg & 0x20) ? 0x02 : 0x00;
5148 setSISIDXREG(SISPART1, 0x1e, 0xfd, reg);
5149 }
5150 }
5151
5152 v1 = bios[0x77];
5153
5154 inSISIDXREG(SISSR, 0x3b, reg);
5155 if(reg & 0x02) {
5156 inSISIDXREG(SISSR, 0x3a, reg);
5157 v2 = (reg & 0x30) >> 3;
5158 if(!(v2 & 0x04)) v2 ^= 0x02;
5159 inSISIDXREG(SISSR, 0x39, reg);
5160 if(reg & 0x80) v2 |= 0x80;
5161 v2 |= 0x01;
5162
Adrian Bunk0959f0c2007-05-08 00:39:50 -07005163 if((mypdev = pci_get_device(PCI_VENDOR_ID_SI, 0x0730, NULL))) {
5164 pci_dev_put(mypdev);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07005165 if(((v2 & 0x06) == 2) || ((v2 & 0x06) == 4))
5166 v2 &= 0xf9;
5167 v2 |= 0x08;
5168 v1 &= 0xfe;
5169 } else {
Adrian Bunk0959f0c2007-05-08 00:39:50 -07005170 mypdev = pci_get_device(PCI_VENDOR_ID_SI, 0x0735, NULL);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07005171 if(!mypdev)
Adrian Bunk0959f0c2007-05-08 00:39:50 -07005172 mypdev = pci_get_device(PCI_VENDOR_ID_SI, 0x0645, NULL);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07005173 if(!mypdev)
Adrian Bunk0959f0c2007-05-08 00:39:50 -07005174 mypdev = pci_get_device(PCI_VENDOR_ID_SI, 0x0650, NULL);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07005175 if(mypdev) {
5176 pci_read_config_dword(mypdev, 0x94, &regd);
5177 regd &= 0xfffffeff;
5178 pci_write_config_dword(mypdev, 0x94, regd);
5179 v1 &= 0xfe;
Adrian Bunk0959f0c2007-05-08 00:39:50 -07005180 pci_dev_put(mypdev);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07005181 } else if(sisfb_find_host_bridge(ivideo, pdev, PCI_VENDOR_ID_SI)) {
5182 v1 &= 0xfe;
5183 } else if(sisfb_find_host_bridge(ivideo, pdev, 0x1106) ||
5184 sisfb_find_host_bridge(ivideo, pdev, 0x1022) ||
5185 sisfb_find_host_bridge(ivideo, pdev, 0x700e) ||
5186 sisfb_find_host_bridge(ivideo, pdev, 0x10de)) {
5187 if((v2 & 0x06) == 4)
5188 v2 ^= 0x06;
5189 v2 |= 0x08;
5190 }
5191 }
5192 setSISIDXREG(SISCR, 0x5f, 0xf0, v2);
5193 }
5194 outSISIDXREG(SISSR, 0x22, v1);
5195
5196 if(ivideo->revision_id == 2) {
5197 inSISIDXREG(SISSR, 0x3b, v1);
5198 inSISIDXREG(SISSR, 0x3a, v2);
5199 regd = bios[0x90 + 3] | (bios[0x90 + 4] << 8);
5200 if( (!(v1 & 0x02)) && (v2 & 0x30) && (regd < 0xcf) )
5201 setSISIDXREG(SISCR, 0x5f, 0xf1, 0x01);
5202
Adrian Bunk0959f0c2007-05-08 00:39:50 -07005203 if((mypdev = pci_get_device(0x10de, 0x01e0, NULL))) {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07005204 /* TODO: set CR5f &0xf1 | 0x01 for version 6570
5205 * of nforce 2 ROM
5206 */
5207 if(0)
5208 setSISIDXREG(SISCR, 0x5f, 0xf1, 0x01);
Adrian Bunk0959f0c2007-05-08 00:39:50 -07005209 pci_dev_put(mypdev);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07005210 }
5211 }
5212
5213 v1 = 0x30;
5214 inSISIDXREG(SISSR, 0x3b, reg);
5215 inSISIDXREG(SISCR, 0x5f, v2);
5216 if((!(reg & 0x02)) && (v2 & 0x0e))
5217 v1 |= 0x08;
5218 outSISIDXREG(SISSR, 0x27, v1);
5219
5220 if(bios[0x64] & 0x01) {
5221 setSISIDXREG(SISCR, 0x5f, 0xf0, bios[0x64]);
5222 }
5223
5224 v1 = bios[0x4f7];
5225 pci_read_config_dword(pdev, 0x50, &regd);
5226 regd = (regd >> 20) & 0x0f;
5227 if(regd == 1) {
5228 v1 &= 0xfc;
5229 orSISIDXREG(SISCR, 0x5f, 0x08);
5230 }
5231 outSISIDXREG(SISCR, 0x48, v1);
5232
5233 setSISIDXREG(SISCR, 0x47, 0x04, bios[0x4f6] & 0xfb);
5234 setSISIDXREG(SISCR, 0x49, 0xf0, bios[0x4f8] & 0x0f);
5235 setSISIDXREG(SISCR, 0x4a, 0x60, bios[0x4f9] & 0x9f);
5236 setSISIDXREG(SISCR, 0x4b, 0x08, bios[0x4fa] & 0xf7);
5237 setSISIDXREG(SISCR, 0x4c, 0x80, bios[0x4fb] & 0x7f);
5238 outSISIDXREG(SISCR, 0x70, bios[0x4fc]);
5239 setSISIDXREG(SISCR, 0x71, 0xf0, bios[0x4fd] & 0x0f);
5240 outSISIDXREG(SISCR, 0x74, 0xd0);
5241 setSISIDXREG(SISCR, 0x74, 0xcf, bios[0x4fe] & 0x30);
5242 setSISIDXREG(SISCR, 0x75, 0xe0, bios[0x4ff] & 0x1f);
5243 setSISIDXREG(SISCR, 0x76, 0xe0, bios[0x500] & 0x1f);
5244 v1 = bios[0x501];
Adrian Bunk0959f0c2007-05-08 00:39:50 -07005245 if((mypdev = pci_get_device(0x8086, 0x2530, NULL))) {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07005246 v1 = 0xf0;
Adrian Bunk0959f0c2007-05-08 00:39:50 -07005247 pci_dev_put(mypdev);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07005248 }
5249 outSISIDXREG(SISCR, 0x77, v1);
5250 }
5251
5252 /* RAM type */
5253
5254 regb = 0; /* ! */
5255
5256 v1 = 0xff;
5257 if(ivideo->haveXGIROM) {
5258 v1 = bios[0x140 + regb];
5259 }
5260 outSISIDXREG(SISCR, 0x6d, v1);
5261
5262 ptr = cs128;
5263 if(ivideo->haveXGIROM) {
5264 ptr = (const u8 *)&bios[0x128];
5265 }
5266 for(i = 0, j = 0; i < 3; i++, j += 8) {
5267 outSISIDXREG(SISCR, 0x68 + i, ptr[j + regb]);
5268 }
5269
5270 ptr = cs31a;
5271 ptr2 = cs33a;
5272 if(ivideo->haveXGIROM) {
5273 index = (ivideo->chip == XGI_20) ? 0x31a : 0x3a6;
5274 ptr = (const u8 *)&bios[index];
5275 ptr2 = (const u8 *)&bios[index + 0x20];
5276 }
5277 for(i = 0; i < 2; i++) {
5278 if(i == 0) {
5279 regd = le32_to_cpu(((u32 *)ptr)[regb]);
5280 rega = 0x6b;
5281 } else {
5282 regd = le32_to_cpu(((u32 *)ptr2)[regb]);
5283 rega = 0x6e;
5284 }
5285 reg = 0x00;
5286 for(j = 0; j < 16; j++) {
5287 reg &= 0xf3;
5288 if(regd & 0x01) reg |= 0x04;
5289 if(regd & 0x02) reg |= 0x08;
5290 regd >>= 2;
5291 outSISIDXREG(SISCR, rega, reg);
5292 inSISIDXREG(SISCR, rega, reg);
5293 inSISIDXREG(SISCR, rega, reg);
5294 reg += 0x10;
5295 }
5296 }
5297
5298 andSISIDXREG(SISCR, 0x6e, 0xfc);
5299
5300 ptr = NULL;
5301 if(ivideo->haveXGIROM) {
5302 index = (ivideo->chip == XGI_20) ? 0x35a : 0x3e6;
5303 ptr = (const u8 *)&bios[index];
5304 }
5305 for(i = 0; i < 4; i++) {
5306 setSISIDXREG(SISCR, 0x6e, 0xfc, i);
5307 reg = 0x00;
5308 for(j = 0; j < 2; j++) {
5309 regd = 0;
5310 if(ptr) {
5311 regd = le32_to_cpu(((u32 *)ptr)[regb * 8]);
5312 ptr += 4;
5313 }
5314 /* reg = 0x00; */
5315 for(k = 0; k < 16; k++) {
5316 reg &= 0xfc;
5317 if(regd & 0x01) reg |= 0x01;
5318 if(regd & 0x02) reg |= 0x02;
5319 regd >>= 2;
5320 outSISIDXREG(SISCR, 0x6f, reg);
5321 inSISIDXREG(SISCR, 0x6f, reg);
5322 inSISIDXREG(SISCR, 0x6f, reg);
5323 reg += 0x08;
5324 }
5325 }
5326 }
5327
5328 ptr = cs148;
5329 if(ivideo->haveXGIROM) {
5330 ptr = (const u8 *)&bios[0x148];
5331 }
5332 for(i = 0, j = 0; i < 2; i++, j += 8) {
5333 outSISIDXREG(SISCR, 0x80 + i, ptr[j + regb]);
5334 }
5335
5336 andSISIDXREG(SISCR, 0x89, 0x8f);
5337
5338 ptr = cs45a;
5339 if(ivideo->haveXGIROM) {
5340 index = (ivideo->chip == XGI_20) ? 0x45a : 0x4e6;
5341 ptr = (const u8 *)&bios[index];
5342 }
5343 regd = le16_to_cpu(((const u16 *)ptr)[regb]);
5344 reg = 0x80;
5345 for(i = 0; i < 5; i++) {
5346 reg &= 0xfc;
5347 if(regd & 0x01) reg |= 0x01;
5348 if(regd & 0x02) reg |= 0x02;
5349 regd >>= 2;
5350 outSISIDXREG(SISCR, 0x89, reg);
5351 inSISIDXREG(SISCR, 0x89, reg);
5352 inSISIDXREG(SISCR, 0x89, reg);
5353 reg += 0x10;
5354 }
5355
5356 v1 = 0xb5; v2 = 0x20; v3 = 0xf0; v4 = 0x13;
5357 if(ivideo->haveXGIROM) {
5358 v1 = bios[0x118 + regb];
5359 v2 = bios[0xf8 + regb];
5360 v3 = bios[0x120 + regb];
5361 v4 = bios[0x1ca];
5362 }
5363 outSISIDXREG(SISCR, 0x45, v1 & 0x0f);
5364 outSISIDXREG(SISCR, 0x99, (v1 >> 4) & 0x07);
5365 orSISIDXREG(SISCR, 0x40, v1 & 0x80);
5366 outSISIDXREG(SISCR, 0x41, v2);
5367
5368 ptr = cs170;
5369 if(ivideo->haveXGIROM) {
5370 ptr = (const u8 *)&bios[0x170];
5371 }
5372 for(i = 0, j = 0; i < 7; i++, j += 8) {
5373 outSISIDXREG(SISCR, 0x90 + i, ptr[j + regb]);
5374 }
5375
5376 outSISIDXREG(SISCR, 0x59, v3);
5377
5378 ptr = cs1a8;
5379 if(ivideo->haveXGIROM) {
5380 ptr = (const u8 *)&bios[0x1a8];
5381 }
5382 for(i = 0, j = 0; i < 3; i++, j += 8) {
5383 outSISIDXREG(SISCR, 0xc3 + i, ptr[j + regb]);
5384 }
5385
5386 ptr = cs100;
5387 if(ivideo->haveXGIROM) {
5388 ptr = (const u8 *)&bios[0x100];
5389 }
5390 for(i = 0, j = 0; i < 2; i++, j += 8) {
5391 outSISIDXREG(SISCR, 0x8a + i, ptr[j + regb]);
5392 }
5393
5394 outSISIDXREG(SISCR, 0xcf, v4);
5395
5396 outSISIDXREG(SISCR, 0x83, 0x09);
5397 outSISIDXREG(SISCR, 0x87, 0x00);
5398
5399 if(ivideo->chip == XGI_40) {
5400 if( (ivideo->revision_id == 1) ||
5401 (ivideo->revision_id == 2) ) {
5402 outSISIDXREG(SISCR, 0x8c, 0x87);
5403 }
5404 }
5405
5406 outSISIDXREG(SISSR, 0x17, 0x00);
5407 outSISIDXREG(SISSR, 0x1a, 0x87);
5408
5409 if(ivideo->chip == XGI_20) {
5410 outSISIDXREG(SISSR, 0x15, 0x00);
5411 outSISIDXREG(SISSR, 0x1c, 0x00);
5412 }
5413
5414 ramtype = 0x00; v1 = 0x10;
5415 if(ivideo->haveXGIROM) {
5416 ramtype = bios[0x62];
5417 v1 = bios[0x1d2];
5418 }
5419 if(!(ramtype & 0x80)) {
5420 if(ivideo->chip == XGI_20) {
5421 outSISIDXREG(SISCR, 0x97, v1);
5422 inSISIDXREG(SISCR, 0x97, reg);
5423 if(reg & 0x10) {
5424 ramtype = (reg & 0x01) << 1;
5425 }
5426 } else {
5427 inSISIDXREG(SISSR, 0x39, reg);
5428 ramtype = reg & 0x02;
5429 if(!(ramtype)) {
5430 inSISIDXREG(SISSR, 0x3a, reg);
5431 ramtype = (reg >> 1) & 0x01;
5432 }
5433 }
5434 }
5435 ramtype &= 0x07;
5436
5437 regb = 0; /* ! */
5438
5439 switch(ramtype) {
5440 case 0:
5441 sisfb_post_xgi_setclocks(ivideo, regb);
5442 if((ivideo->chip == XGI_20) ||
5443 (ivideo->revision_id == 1) ||
5444 (ivideo->revision_id == 2)) {
5445 v1 = cs158[regb]; v2 = cs160[regb]; v3 = cs168[regb];
5446 if(ivideo->haveXGIROM) {
5447 v1 = bios[regb + 0x158];
5448 v2 = bios[regb + 0x160];
5449 v3 = bios[regb + 0x168];
5450 }
5451 outSISIDXREG(SISCR, 0x82, v1);
5452 outSISIDXREG(SISCR, 0x85, v2);
5453 outSISIDXREG(SISCR, 0x86, v3);
5454 } else {
5455 outSISIDXREG(SISCR, 0x82, 0x88);
5456 outSISIDXREG(SISCR, 0x86, 0x00);
5457 inSISIDXREG(SISCR, 0x86, reg);
5458 outSISIDXREG(SISCR, 0x86, 0x88);
5459 inSISIDXREG(SISCR, 0x86, reg);
5460 outSISIDXREG(SISCR, 0x86, bios[regb + 0x168]);
5461 outSISIDXREG(SISCR, 0x82, 0x77);
5462 outSISIDXREG(SISCR, 0x85, 0x00);
5463 inSISIDXREG(SISCR, 0x85, reg);
5464 outSISIDXREG(SISCR, 0x85, 0x88);
5465 inSISIDXREG(SISCR, 0x85, reg);
5466 outSISIDXREG(SISCR, 0x85, bios[regb + 0x160]);
5467 outSISIDXREG(SISCR, 0x82, bios[regb + 0x158]);
5468 }
5469 if(ivideo->chip == XGI_40) {
5470 outSISIDXREG(SISCR, 0x97, 0x00);
5471 }
5472 outSISIDXREG(SISCR, 0x98, 0x01);
5473 outSISIDXREG(SISCR, 0x9a, 0x02);
5474
5475 outSISIDXREG(SISSR, 0x18, 0x01);
5476 if((ivideo->chip == XGI_20) ||
5477 (ivideo->revision_id == 2)) {
5478 outSISIDXREG(SISSR, 0x19, 0x40);
5479 } else {
5480 outSISIDXREG(SISSR, 0x19, 0x20);
5481 }
5482 outSISIDXREG(SISSR, 0x16, 0x00);
5483 outSISIDXREG(SISSR, 0x16, 0x80);
5484 if((ivideo->chip == XGI_20) || (bios[0x1cb] != 0x0c)) {
5485 sisfb_post_xgi_delay(ivideo, 0x43);
5486 sisfb_post_xgi_delay(ivideo, 0x43);
5487 sisfb_post_xgi_delay(ivideo, 0x43);
5488 outSISIDXREG(SISSR, 0x18, 0x00);
5489 if((ivideo->chip == XGI_20) ||
5490 (ivideo->revision_id == 2)) {
5491 outSISIDXREG(SISSR, 0x19, 0x40);
5492 } else {
5493 outSISIDXREG(SISSR, 0x19, 0x20);
5494 }
5495 } else if((ivideo->chip == XGI_40) && (bios[0x1cb] == 0x0c)) {
5496 /* outSISIDXREG(SISSR, 0x16, 0x0c); */ /* ? */
5497 }
5498 outSISIDXREG(SISSR, 0x16, 0x00);
5499 outSISIDXREG(SISSR, 0x16, 0x80);
5500 sisfb_post_xgi_delay(ivideo, 4);
5501 v1 = 0x31; v2 = 0x03; v3 = 0x83; v4 = 0x03; v5 = 0x83;
5502 if(ivideo->haveXGIROM) {
5503 v1 = bios[0xf0];
5504 index = (ivideo->chip == XGI_20) ? 0x4b2 : 0x53e;
5505 v2 = bios[index];
5506 v3 = bios[index + 1];
5507 v4 = bios[index + 2];
5508 v5 = bios[index + 3];
5509 }
5510 outSISIDXREG(SISSR, 0x18, v1);
5511 outSISIDXREG(SISSR, 0x19, ((ivideo->chip == XGI_20) ? 0x02 : 0x01));
5512 outSISIDXREG(SISSR, 0x16, v2);
5513 outSISIDXREG(SISSR, 0x16, v3);
5514 sisfb_post_xgi_delay(ivideo, 0x43);
5515 outSISIDXREG(SISSR, 0x1b, 0x03);
5516 sisfb_post_xgi_delay(ivideo, 0x22);
5517 outSISIDXREG(SISSR, 0x18, v1);
5518 outSISIDXREG(SISSR, 0x19, 0x00);
5519 outSISIDXREG(SISSR, 0x16, v4);
5520 outSISIDXREG(SISSR, 0x16, v5);
5521 outSISIDXREG(SISSR, 0x1b, 0x00);
5522 break;
5523 case 1:
5524 outSISIDXREG(SISCR, 0x82, 0x77);
5525 outSISIDXREG(SISCR, 0x86, 0x00);
5526 inSISIDXREG(SISCR, 0x86, reg);
5527 outSISIDXREG(SISCR, 0x86, 0x88);
5528 inSISIDXREG(SISCR, 0x86, reg);
5529 v1 = cs168[regb]; v2 = cs160[regb]; v3 = cs158[regb];
5530 if(ivideo->haveXGIROM) {
5531 v1 = bios[regb + 0x168];
5532 v2 = bios[regb + 0x160];
5533 v3 = bios[regb + 0x158];
5534 }
5535 outSISIDXREG(SISCR, 0x86, v1);
5536 outSISIDXREG(SISCR, 0x82, 0x77);
5537 outSISIDXREG(SISCR, 0x85, 0x00);
5538 inSISIDXREG(SISCR, 0x85, reg);
5539 outSISIDXREG(SISCR, 0x85, 0x88);
5540 inSISIDXREG(SISCR, 0x85, reg);
5541 outSISIDXREG(SISCR, 0x85, v2);
5542 outSISIDXREG(SISCR, 0x82, v3);
5543 outSISIDXREG(SISCR, 0x98, 0x01);
5544 outSISIDXREG(SISCR, 0x9a, 0x02);
5545
5546 outSISIDXREG(SISSR, 0x28, 0x64);
5547 outSISIDXREG(SISSR, 0x29, 0x63);
5548 sisfb_post_xgi_delay(ivideo, 15);
5549 outSISIDXREG(SISSR, 0x18, 0x00);
5550 outSISIDXREG(SISSR, 0x19, 0x20);
5551 outSISIDXREG(SISSR, 0x16, 0x00);
5552 outSISIDXREG(SISSR, 0x16, 0x80);
5553 outSISIDXREG(SISSR, 0x18, 0xc5);
5554 outSISIDXREG(SISSR, 0x19, 0x23);
5555 outSISIDXREG(SISSR, 0x16, 0x00);
5556 outSISIDXREG(SISSR, 0x16, 0x80);
5557 sisfb_post_xgi_delay(ivideo, 1);
5558 outSISIDXREG(SISCR, 0x97,0x11);
5559 sisfb_post_xgi_setclocks(ivideo, regb);
5560 sisfb_post_xgi_delay(ivideo, 0x46);
5561 outSISIDXREG(SISSR, 0x18, 0xc5);
5562 outSISIDXREG(SISSR, 0x19, 0x23);
5563 outSISIDXREG(SISSR, 0x16, 0x00);
5564 outSISIDXREG(SISSR, 0x16, 0x80);
5565 sisfb_post_xgi_delay(ivideo, 1);
5566 outSISIDXREG(SISSR, 0x1b, 0x04);
5567 sisfb_post_xgi_delay(ivideo, 1);
5568 outSISIDXREG(SISSR, 0x1b, 0x00);
5569 sisfb_post_xgi_delay(ivideo, 1);
5570 v1 = 0x31;
5571 if(ivideo->haveXGIROM) {
5572 v1 = bios[0xf0];
5573 }
5574 outSISIDXREG(SISSR, 0x18, v1);
5575 outSISIDXREG(SISSR, 0x19, 0x06);
5576 outSISIDXREG(SISSR, 0x16, 0x04);
5577 outSISIDXREG(SISSR, 0x16, 0x84);
5578 sisfb_post_xgi_delay(ivideo, 1);
5579 break;
5580 default:
5581 sisfb_post_xgi_setclocks(ivideo, regb);
5582 if((ivideo->chip == XGI_40) &&
5583 ((ivideo->revision_id == 1) ||
5584 (ivideo->revision_id == 2))) {
5585 outSISIDXREG(SISCR, 0x82, bios[regb + 0x158]);
5586 outSISIDXREG(SISCR, 0x85, bios[regb + 0x160]);
5587 outSISIDXREG(SISCR, 0x86, bios[regb + 0x168]);
5588 } else {
5589 outSISIDXREG(SISCR, 0x82, 0x88);
5590 outSISIDXREG(SISCR, 0x86, 0x00);
5591 inSISIDXREG(SISCR, 0x86, reg);
5592 outSISIDXREG(SISCR, 0x86, 0x88);
5593 outSISIDXREG(SISCR, 0x82, 0x77);
5594 outSISIDXREG(SISCR, 0x85, 0x00);
5595 inSISIDXREG(SISCR, 0x85, reg);
5596 outSISIDXREG(SISCR, 0x85, 0x88);
5597 inSISIDXREG(SISCR, 0x85, reg);
5598 v1 = cs160[regb]; v2 = cs158[regb];
5599 if(ivideo->haveXGIROM) {
5600 v1 = bios[regb + 0x160];
5601 v2 = bios[regb + 0x158];
5602 }
5603 outSISIDXREG(SISCR, 0x85, v1);
5604 outSISIDXREG(SISCR, 0x82, v2);
5605 }
5606 if(ivideo->chip == XGI_40) {
5607 outSISIDXREG(SISCR, 0x97, 0x11);
5608 }
5609 if((ivideo->chip == XGI_40) && (ivideo->revision_id == 2)) {
5610 outSISIDXREG(SISCR, 0x98, 0x01);
5611 } else {
5612 outSISIDXREG(SISCR, 0x98, 0x03);
5613 }
5614 outSISIDXREG(SISCR, 0x9a, 0x02);
5615
5616 if(ivideo->chip == XGI_40) {
5617 outSISIDXREG(SISSR, 0x18, 0x01);
5618 } else {
5619 outSISIDXREG(SISSR, 0x18, 0x00);
5620 }
5621 outSISIDXREG(SISSR, 0x19, 0x40);
5622 outSISIDXREG(SISSR, 0x16, 0x00);
5623 outSISIDXREG(SISSR, 0x16, 0x80);
5624 if((ivideo->chip == XGI_40) && (bios[0x1cb] != 0x0c)) {
5625 sisfb_post_xgi_delay(ivideo, 0x43);
5626 sisfb_post_xgi_delay(ivideo, 0x43);
5627 sisfb_post_xgi_delay(ivideo, 0x43);
5628 outSISIDXREG(SISSR, 0x18, 0x00);
5629 outSISIDXREG(SISSR, 0x19, 0x40);
5630 outSISIDXREG(SISSR, 0x16, 0x00);
5631 outSISIDXREG(SISSR, 0x16, 0x80);
5632 }
5633 sisfb_post_xgi_delay(ivideo, 4);
5634 v1 = 0x31;
5635 if(ivideo->haveXGIROM) {
5636 v1 = bios[0xf0];
5637 }
5638 outSISIDXREG(SISSR, 0x18, v1);
5639 outSISIDXREG(SISSR, 0x19, 0x01);
5640 if(ivideo->chip == XGI_40) {
5641 outSISIDXREG(SISSR, 0x16, bios[0x53e]);
5642 outSISIDXREG(SISSR, 0x16, bios[0x53f]);
5643 } else {
5644 outSISIDXREG(SISSR, 0x16, 0x05);
5645 outSISIDXREG(SISSR, 0x16, 0x85);
5646 }
5647 sisfb_post_xgi_delay(ivideo, 0x43);
5648 if(ivideo->chip == XGI_40) {
5649 outSISIDXREG(SISSR, 0x1b, 0x01);
5650 } else {
5651 outSISIDXREG(SISSR, 0x1b, 0x03);
5652 }
5653 sisfb_post_xgi_delay(ivideo, 0x22);
5654 outSISIDXREG(SISSR, 0x18, v1);
5655 outSISIDXREG(SISSR, 0x19, 0x00);
5656 if(ivideo->chip == XGI_40) {
5657 outSISIDXREG(SISSR, 0x16, bios[0x540]);
5658 outSISIDXREG(SISSR, 0x16, bios[0x541]);
5659 } else {
5660 outSISIDXREG(SISSR, 0x16, 0x05);
5661 outSISIDXREG(SISSR, 0x16, 0x85);
5662 }
5663 outSISIDXREG(SISSR, 0x1b, 0x00);
5664 }
5665
5666 regb = 0; /* ! */
5667 v1 = 0x03;
5668 if(ivideo->haveXGIROM) {
5669 v1 = bios[0x110 + regb];
5670 }
5671 outSISIDXREG(SISSR, 0x1b, v1);
5672
5673 /* RAM size */
5674 v1 = 0x00; v2 = 0x00;
5675 if(ivideo->haveXGIROM) {
5676 v1 = bios[0x62];
5677 v2 = bios[0x63];
5678 }
5679 regb = 0; /* ! */
5680 regd = 1 << regb;
5681 if((v1 & 0x40) && (v2 & regd) && ivideo->haveXGIROM) {
5682
5683 outSISIDXREG(SISSR, 0x13, bios[regb + 0xe0]);
5684 outSISIDXREG(SISSR, 0x14, bios[regb + 0xe0 + 8]);
5685
5686 } else {
5687
5688 /* Set default mode, don't clear screen */
Richard Knutssonc30660ea2007-02-12 00:55:06 -08005689 ivideo->SiS_Pr.SiS_UseOEM = false;
5690 SiS_SetEnableDstn(&ivideo->SiS_Pr, false);
5691 SiS_SetEnableFstn(&ivideo->SiS_Pr, false);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07005692 ivideo->curFSTN = ivideo->curDSTN = 0;
5693 ivideo->SiS_Pr.VideoMemorySize = 8 << 20;
5694 SiSSetMode(&ivideo->SiS_Pr, 0x2e | 0x80);
5695
5696 outSISIDXREG(SISSR, 0x05, 0x86);
5697
5698 /* Disable read-cache */
5699 andSISIDXREG(SISSR, 0x21, 0xdf);
5700 sisfb_post_xgi_ramsize(ivideo);
5701 /* Enable read-cache */
5702 orSISIDXREG(SISSR, 0x21, 0x20);
5703
5704 }
5705
5706#if 0
5707 printk(KERN_DEBUG "-----------------\n");
5708 for(i = 0; i < 0xff; i++) {
5709 inSISIDXREG(SISCR, i, reg);
5710 printk(KERN_DEBUG "CR%02x(%x) = 0x%02x\n", i, SISCR, reg);
5711 }
5712 for(i = 0; i < 0x40; i++) {
5713 inSISIDXREG(SISSR, i, reg);
5714 printk(KERN_DEBUG "SR%02x(%x) = 0x%02x\n", i, SISSR, reg);
5715 }
5716 printk(KERN_DEBUG "-----------------\n");
5717#endif
5718
5719 /* Sense CRT1 */
5720 if(ivideo->chip == XGI_20) {
5721 orSISIDXREG(SISCR, 0x32, 0x20);
5722 } else {
5723 inSISIDXREG(SISPART4, 0x00, reg);
5724 if((reg == 1) || (reg == 2)) {
5725 sisfb_sense_crt1(ivideo);
5726 } else {
5727 orSISIDXREG(SISCR, 0x32, 0x20);
5728 }
5729 }
5730
5731 /* Set default mode, don't clear screen */
Richard Knutssonc30660ea2007-02-12 00:55:06 -08005732 ivideo->SiS_Pr.SiS_UseOEM = false;
5733 SiS_SetEnableDstn(&ivideo->SiS_Pr, false);
5734 SiS_SetEnableFstn(&ivideo->SiS_Pr, false);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07005735 ivideo->curFSTN = ivideo->curDSTN = 0;
5736 SiSSetMode(&ivideo->SiS_Pr, 0x2e | 0x80);
5737
5738 outSISIDXREG(SISSR, 0x05, 0x86);
5739
5740 /* Display off */
5741 orSISIDXREG(SISSR, 0x01, 0x20);
5742
5743 /* Save mode number in CR34 */
5744 outSISIDXREG(SISCR, 0x34, 0x2e);
5745
5746 /* Let everyone know what the current mode is */
5747 ivideo->modeprechange = 0x2e;
5748
5749 if(ivideo->chip == XGI_40) {
5750 inSISIDXREG(SISCR, 0xca, reg);
5751 inSISIDXREG(SISCR, 0xcc, v1);
5752 if((reg & 0x10) && (!(v1 & 0x04))) {
5753 printk(KERN_ERR
5754 "sisfb: Please connect power to the card.\n");
5755 return 0;
5756 }
5757 }
5758
5759 return 1;
5760}
5761#endif
5762
5763static int __devinit
5764sisfb_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
5765{
5766 struct sisfb_chip_info *chipinfo = &sisfb_chip_info[ent->driver_data];
5767 struct sis_video_info *ivideo = NULL;
5768 struct fb_info *sis_fb_info = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005769 u16 reg16;
5770 u8 reg;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07005771 int i, ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005772
Thomas Winischhofer544393f2005-09-09 13:04:45 -07005773 if(sisfb_off)
5774 return -ENXIO;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005775
Linus Torvalds1da177e2005-04-16 15:20:36 -07005776 sis_fb_info = framebuffer_alloc(sizeof(*ivideo), &pdev->dev);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07005777 if(!sis_fb_info)
5778 return -ENOMEM;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005779
5780 ivideo = (struct sis_video_info *)sis_fb_info->par;
5781 ivideo->memyselfandi = sis_fb_info;
5782
Thomas Winischhofer544393f2005-09-09 13:04:45 -07005783 ivideo->sisfb_id = SISFB_ID;
5784
Linus Torvalds1da177e2005-04-16 15:20:36 -07005785 if(card_list == NULL) {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07005786 ivideo->cardnumber = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005787 } else {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07005788 struct sis_video_info *countvideo = card_list;
5789 ivideo->cardnumber = 1;
5790 while((countvideo = countvideo->next) != 0)
5791 ivideo->cardnumber++;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005792 }
5793
5794 strncpy(ivideo->myid, chipinfo->chip_name, 30);
5795
5796 ivideo->warncount = 0;
5797 ivideo->chip_id = pdev->device;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07005798 ivideo->chip_vendor = pdev->vendor;
Auke Kok44c10132007-06-08 15:46:36 -07005799 ivideo->revision_id = pdev->revision;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07005800 ivideo->SiS_Pr.ChipRevision = ivideo->revision_id;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005801 pci_read_config_word(pdev, PCI_COMMAND, &reg16);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07005802 ivideo->sisvga_enabled = reg16 & 0x01;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005803 ivideo->pcibus = pdev->bus->number;
5804 ivideo->pcislot = PCI_SLOT(pdev->devfn);
5805 ivideo->pcifunc = PCI_FUNC(pdev->devfn);
5806 ivideo->subsysvendor = pdev->subsystem_vendor;
5807 ivideo->subsysdevice = pdev->subsystem_device;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07005808#ifdef SIS_OLD_CONFIG_COMPAT
5809 ivideo->ioctl32registered = 0;
5810#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -07005811
5812#ifndef MODULE
5813 if(sisfb_mode_idx == -1) {
5814 sisfb_get_vga_mode_from_kernel();
5815 }
5816#endif
5817
5818 ivideo->chip = chipinfo->chip;
5819 ivideo->sisvga_engine = chipinfo->vgaengine;
5820 ivideo->hwcursor_size = chipinfo->hwcursor_size;
5821 ivideo->CRT2_write_enable = chipinfo->CRT2_write_enable;
5822 ivideo->mni = chipinfo->mni;
5823
5824 ivideo->detectedpdc = 0xff;
5825 ivideo->detectedpdca = 0xff;
5826 ivideo->detectedlcda = 0xff;
5827
Richard Knutssonc30660ea2007-02-12 00:55:06 -08005828 ivideo->sisfb_thismonitor.datavalid = false;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005829
Thomas Winischhofer544393f2005-09-09 13:04:45 -07005830 ivideo->current_base = 0;
5831
5832 ivideo->engineok = 0;
5833
5834 ivideo->sisfb_was_boot_device = 0;
5835#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,12))
5836 if(pdev->resource[PCI_ROM_RESOURCE].flags & IORESOURCE_ROM_SHADOW) {
5837 if(ivideo->sisvga_enabled)
5838 ivideo->sisfb_was_boot_device = 1;
5839 else {
5840 printk(KERN_DEBUG "sisfb: PCI device is disabled, "
5841 "but marked as boot video device ???\n");
5842 printk(KERN_DEBUG "sisfb: I will not accept this "
5843 "as the primary VGA device\n");
5844 }
5845 }
5846#endif
5847
Linus Torvalds1da177e2005-04-16 15:20:36 -07005848 ivideo->sisfb_parm_mem = sisfb_parm_mem;
5849 ivideo->sisfb_accel = sisfb_accel;
5850 ivideo->sisfb_ypan = sisfb_ypan;
5851 ivideo->sisfb_max = sisfb_max;
5852 ivideo->sisfb_userom = sisfb_userom;
5853 ivideo->sisfb_useoem = sisfb_useoem;
5854 ivideo->sisfb_mode_idx = sisfb_mode_idx;
5855 ivideo->sisfb_parm_rate = sisfb_parm_rate;
5856 ivideo->sisfb_crt1off = sisfb_crt1off;
5857 ivideo->sisfb_forcecrt1 = sisfb_forcecrt1;
5858 ivideo->sisfb_crt2type = sisfb_crt2type;
5859 ivideo->sisfb_crt2flags = sisfb_crt2flags;
5860 /* pdc(a), scalelcd, special timing, lvdshl handled below */
5861 ivideo->sisfb_dstn = sisfb_dstn;
5862 ivideo->sisfb_fstn = sisfb_fstn;
5863 ivideo->sisfb_tvplug = sisfb_tvplug;
5864 ivideo->sisfb_tvstd = sisfb_tvstd;
5865 ivideo->tvxpos = sisfb_tvxposoffset;
5866 ivideo->tvypos = sisfb_tvyposoffset;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005867 ivideo->sisfb_nocrt2rate = sisfb_nocrt2rate;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005868 ivideo->refresh_rate = 0;
5869 if(ivideo->sisfb_parm_rate != -1) {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07005870 ivideo->refresh_rate = ivideo->sisfb_parm_rate;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005871 }
5872
5873 ivideo->SiS_Pr.UsePanelScaler = sisfb_scalelcd;
5874 ivideo->SiS_Pr.CenterScreen = -1;
5875 ivideo->SiS_Pr.SiS_CustomT = sisfb_specialtiming;
5876 ivideo->SiS_Pr.LVDSHL = sisfb_lvdshl;
5877
5878 ivideo->SiS_Pr.SiS_Backup70xx = 0xff;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07005879 ivideo->SiS_Pr.SiS_CHOverScan = -1;
Richard Knutssonc30660ea2007-02-12 00:55:06 -08005880 ivideo->SiS_Pr.SiS_ChSW = false;
5881 ivideo->SiS_Pr.SiS_UseLCDA = false;
5882 ivideo->SiS_Pr.HaveEMI = false;
5883 ivideo->SiS_Pr.HaveEMILCD = false;
5884 ivideo->SiS_Pr.OverruleEMI = false;
5885 ivideo->SiS_Pr.SiS_SensibleSR11 = false;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005886 ivideo->SiS_Pr.SiS_MyCR63 = 0x63;
5887 ivideo->SiS_Pr.PDC = -1;
5888 ivideo->SiS_Pr.PDCA = -1;
Richard Knutssonc30660ea2007-02-12 00:55:06 -08005889 ivideo->SiS_Pr.DDCPortMixup = false;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005890#ifdef CONFIG_FB_SIS_315
5891 if(ivideo->chip >= SIS_330) {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07005892 ivideo->SiS_Pr.SiS_MyCR63 = 0x53;
5893 if(ivideo->chip >= SIS_661) {
Richard Knutssonc30660ea2007-02-12 00:55:06 -08005894 ivideo->SiS_Pr.SiS_SensibleSR11 = true;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07005895 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07005896 }
5897#endif
5898
5899 memcpy(&ivideo->default_var, &my_default_var, sizeof(my_default_var));
5900
5901 pci_set_drvdata(pdev, ivideo);
5902
5903 /* Patch special cases */
5904 if((ivideo->nbridge = sisfb_get_northbridge(ivideo->chip))) {
5905 switch(ivideo->nbridge->device) {
5906#ifdef CONFIG_FB_SIS_300
5907 case PCI_DEVICE_ID_SI_730:
Thomas Winischhofer544393f2005-09-09 13:04:45 -07005908 ivideo->chip = SIS_730;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005909 strcpy(ivideo->myid, "SiS 730");
Thomas Winischhofer544393f2005-09-09 13:04:45 -07005910 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005911#endif
5912#ifdef CONFIG_FB_SIS_315
5913 case PCI_DEVICE_ID_SI_651:
5914 /* ivideo->chip is ok */
5915 strcpy(ivideo->myid, "SiS 651");
5916 break;
5917 case PCI_DEVICE_ID_SI_740:
Thomas Winischhofer544393f2005-09-09 13:04:45 -07005918 ivideo->chip = SIS_740;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005919 strcpy(ivideo->myid, "SiS 740");
5920 break;
5921 case PCI_DEVICE_ID_SI_661:
Thomas Winischhofer544393f2005-09-09 13:04:45 -07005922 ivideo->chip = SIS_661;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005923 strcpy(ivideo->myid, "SiS 661");
5924 break;
5925 case PCI_DEVICE_ID_SI_741:
Thomas Winischhofer544393f2005-09-09 13:04:45 -07005926 ivideo->chip = SIS_741;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005927 strcpy(ivideo->myid, "SiS 741");
5928 break;
5929 case PCI_DEVICE_ID_SI_760:
Thomas Winischhofer544393f2005-09-09 13:04:45 -07005930 ivideo->chip = SIS_760;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005931 strcpy(ivideo->myid, "SiS 760");
5932 break;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07005933 case PCI_DEVICE_ID_SI_761:
5934 ivideo->chip = SIS_761;
5935 strcpy(ivideo->myid, "SiS 761");
5936 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005937#endif
Thomas Winischhofer544393f2005-09-09 13:04:45 -07005938 default:
5939 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005940 }
5941 }
5942
Thomas Winischhofer544393f2005-09-09 13:04:45 -07005943 ivideo->SiS_Pr.ChipType = ivideo->chip;
5944
5945 ivideo->SiS_Pr.ivideo = (void *)ivideo;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005946
5947#ifdef CONFIG_FB_SIS_315
Thomas Winischhofer544393f2005-09-09 13:04:45 -07005948 if((ivideo->SiS_Pr.ChipType == SIS_315PRO) ||
5949 (ivideo->SiS_Pr.ChipType == SIS_315)) {
5950 ivideo->SiS_Pr.ChipType = SIS_315H;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005951 }
5952#endif
5953
Thomas Winischhofer544393f2005-09-09 13:04:45 -07005954 if(!ivideo->sisvga_enabled) {
5955 if(pci_enable_device(pdev)) {
Adrian Bunk0959f0c2007-05-08 00:39:50 -07005956 if(ivideo->nbridge) pci_dev_put(ivideo->nbridge);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07005957 pci_set_drvdata(pdev, NULL);
5958 kfree(sis_fb_info);
5959 return -EIO;
5960 }
5961 }
5962
Linus Torvalds1da177e2005-04-16 15:20:36 -07005963 ivideo->video_base = pci_resource_start(pdev, 0);
5964 ivideo->mmio_base = pci_resource_start(pdev, 1);
5965 ivideo->mmio_size = pci_resource_len(pdev, 1);
5966 ivideo->SiS_Pr.RelIO = pci_resource_start(pdev, 2) + 0x30;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07005967 ivideo->SiS_Pr.IOAddress = ivideo->vga_base = ivideo->SiS_Pr.RelIO;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005968
Thomas Winischhofer544393f2005-09-09 13:04:45 -07005969 SiSRegInit(&ivideo->SiS_Pr, ivideo->SiS_Pr.IOAddress);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005970
5971#ifdef CONFIG_FB_SIS_300
5972 /* Find PCI systems for Chrontel/GPIO communication setup */
5973 if(ivideo->chip == SIS_630) {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07005974 i = 0;
5975 do {
5976 if(mychswtable[i].subsysVendor == ivideo->subsysvendor &&
5977 mychswtable[i].subsysCard == ivideo->subsysdevice) {
Richard Knutssonc30660ea2007-02-12 00:55:06 -08005978 ivideo->SiS_Pr.SiS_ChSW = true;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07005979 printk(KERN_DEBUG "sisfb: Identified [%s %s] "
5980 "requiring Chrontel/GPIO setup\n",
5981 mychswtable[i].vendorName,
5982 mychswtable[i].cardName);
Adrian Bunk0959f0c2007-05-08 00:39:50 -07005983 ivideo->lpcdev = pci_get_device(PCI_VENDOR_ID_SI, 0x0008, NULL);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07005984 break;
5985 }
5986 i++;
5987 } while(mychswtable[i].subsysVendor != 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005988 }
5989#endif
5990
Thomas Winischhofer544393f2005-09-09 13:04:45 -07005991#ifdef CONFIG_FB_SIS_315
5992 if((ivideo->chip == SIS_760) && (ivideo->nbridge)) {
Adrian Bunk0959f0c2007-05-08 00:39:50 -07005993 ivideo->lpcdev = pci_get_slot(ivideo->nbridge->bus, (2 << 3));
Thomas Winischhofer544393f2005-09-09 13:04:45 -07005994 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07005995#endif
Thomas Winischhofer544393f2005-09-09 13:04:45 -07005996
5997 outSISIDXREG(SISSR, 0x05, 0x86);
5998
5999 if( (!ivideo->sisvga_enabled)
6000#if !defined(__i386__) && !defined(__x86_64__)
6001 || (sisfb_resetcard)
6002#endif
6003 ) {
6004 for(i = 0x30; i <= 0x3f; i++) {
6005 outSISIDXREG(SISCR, i, 0x00);
6006 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07006007 }
6008
6009 /* Find out about current video mode */
6010 ivideo->modeprechange = 0x03;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006011 inSISIDXREG(SISCR, 0x34, reg);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006012 if(reg & 0x7f) {
6013 ivideo->modeprechange = reg & 0x7f;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006014 } else if(ivideo->sisvga_enabled) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07006015#if defined(__i386__) || defined(__x86_64__)
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006016 unsigned char SIS_IOTYPE2 *tt = ioremap(0x400, 0x100);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006017 if(tt) {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006018 ivideo->modeprechange = readb(tt + 0x49);
6019 iounmap(tt);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006020 }
6021#endif
6022 }
6023
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006024 /* Search and copy ROM image */
6025 ivideo->bios_abase = NULL;
6026 ivideo->SiS_Pr.VirtualRomBase = NULL;
Richard Knutssonc30660ea2007-02-12 00:55:06 -08006027 ivideo->SiS_Pr.UseROM = false;
6028 ivideo->haveXGIROM = ivideo->SiS_Pr.SiS_XGIROM = false;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006029 if(ivideo->sisfb_userom) {
6030 ivideo->SiS_Pr.VirtualRomBase = sisfb_find_rom(pdev);
6031 ivideo->bios_abase = ivideo->SiS_Pr.VirtualRomBase;
Richard Knutssonc30660ea2007-02-12 00:55:06 -08006032 ivideo->SiS_Pr.UseROM = (bool)(ivideo->SiS_Pr.VirtualRomBase);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006033 printk(KERN_INFO "sisfb: Video ROM %sfound\n",
6034 ivideo->SiS_Pr.UseROM ? "" : "not ");
6035 if((ivideo->SiS_Pr.UseROM) && (ivideo->chip >= XGI_20)) {
Richard Knutssonc30660ea2007-02-12 00:55:06 -08006036 ivideo->SiS_Pr.UseROM = false;
6037 ivideo->haveXGIROM = ivideo->SiS_Pr.SiS_XGIROM = true;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006038 if( (ivideo->revision_id == 2) &&
6039 (!(ivideo->bios_abase[0x1d1] & 0x01)) ) {
Richard Knutssonc30660ea2007-02-12 00:55:06 -08006040 ivideo->SiS_Pr.DDCPortMixup = true;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006041 }
6042 }
6043 } else {
6044 printk(KERN_INFO "sisfb: Video ROM usage disabled\n");
6045 }
6046
6047 /* Find systems for special custom timing */
6048 if(ivideo->SiS_Pr.SiS_CustomT == CUT_NONE) {
6049 sisfb_detect_custom_timing(ivideo);
6050 }
6051
6052 /* POST card in case this has not been done by the BIOS */
6053 if( (!ivideo->sisvga_enabled)
6054#if !defined(__i386__) && !defined(__x86_64__)
6055 || (sisfb_resetcard)
6056#endif
6057 ) {
6058#ifdef CONFIG_FB_SIS_300
6059 if(ivideo->sisvga_engine == SIS_300_VGA) {
6060 if(ivideo->chip == SIS_300) {
6061 sisfb_post_sis300(pdev);
6062 ivideo->sisfb_can_post = 1;
6063 }
6064 }
6065#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -07006066
6067#ifdef CONFIG_FB_SIS_315
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006068 if(ivideo->sisvga_engine == SIS_315_VGA) {
6069 int result = 1;
6070 /* if((ivideo->chip == SIS_315H) ||
Linus Torvalds1da177e2005-04-16 15:20:36 -07006071 (ivideo->chip == SIS_315) ||
6072 (ivideo->chip == SIS_315PRO) ||
6073 (ivideo->chip == SIS_330)) {
6074 sisfb_post_sis315330(pdev);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006075 } else */ if(ivideo->chip == XGI_20) {
6076 result = sisfb_post_xgi(pdev);
6077 ivideo->sisfb_can_post = 1;
6078 } else if((ivideo->chip == XGI_40) && ivideo->haveXGIROM) {
6079 result = sisfb_post_xgi(pdev);
6080 ivideo->sisfb_can_post = 1;
6081 } else {
6082 printk(KERN_INFO "sisfb: Card is not "
6083 "POSTed and sisfb can't do this either.\n");
6084 }
6085 if(!result) {
6086 printk(KERN_ERR "sisfb: Failed to POST card\n");
6087 ret = -ENODEV;
6088 goto error_3;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006089 }
6090 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07006091#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -07006092 }
6093
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006094 ivideo->sisfb_card_posted = 1;
6095
6096 /* Find out about RAM size */
6097 if(sisfb_get_dram_size(ivideo)) {
6098 printk(KERN_INFO "sisfb: Fatal error: Unable to determine VRAM size.\n");
6099 ret = -ENODEV;
6100 goto error_3;
6101 }
6102
6103
6104 /* Enable PCI addressing and MMIO */
Linus Torvalds1da177e2005-04-16 15:20:36 -07006105 if((ivideo->sisfb_mode_idx < 0) ||
6106 ((sisbios_mode[ivideo->sisfb_mode_idx].mode_no[ivideo->mni]) != 0xFF)) {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006107 /* Enable PCI_LINEAR_ADDRESSING and MMIO_ENABLE */
6108 orSISIDXREG(SISSR, IND_SIS_PCI_ADDRESS_SET, (SIS_PCI_ADDR_ENABLE | SIS_MEM_MAP_IO_ENABLE));
6109 /* Enable 2D accelerator engine */
6110 orSISIDXREG(SISSR, IND_SIS_MODULE_ENABLE, SIS_ENABLE_2D);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006111 }
6112
6113 if(sisfb_pdc != 0xff) {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006114 if(ivideo->sisvga_engine == SIS_300_VGA)
6115 sisfb_pdc &= 0x3c;
6116 else
6117 sisfb_pdc &= 0x1f;
6118 ivideo->SiS_Pr.PDC = sisfb_pdc;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006119 }
6120#ifdef CONFIG_FB_SIS_315
6121 if(ivideo->sisvga_engine == SIS_315_VGA) {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006122 if(sisfb_pdca != 0xff)
6123 ivideo->SiS_Pr.PDCA = sisfb_pdca & 0x1f;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006124 }
6125#endif
6126
6127 if(!request_mem_region(ivideo->video_base, ivideo->video_size, "sisfb FB")) {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006128 printk(KERN_ERR "sisfb: Fatal error: Unable to reserve %dMB framebuffer memory\n",
6129 (int)(ivideo->video_size >> 20));
Linus Torvalds1da177e2005-04-16 15:20:36 -07006130 printk(KERN_ERR "sisfb: Is there another framebuffer driver active?\n");
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006131 ret = -ENODEV;
6132 goto error_3;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006133 }
6134
6135 if(!request_mem_region(ivideo->mmio_base, ivideo->mmio_size, "sisfb MMIO")) {
6136 printk(KERN_ERR "sisfb: Fatal error: Unable to reserve MMIO region\n");
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006137 ret = -ENODEV;
6138 goto error_2;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006139 }
6140
6141 ivideo->video_vbase = ioremap(ivideo->video_base, ivideo->video_size);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006142 ivideo->SiS_Pr.VideoMemoryAddress = ivideo->video_vbase;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006143 if(!ivideo->video_vbase) {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006144 printk(KERN_ERR "sisfb: Fatal error: Unable to map framebuffer memory\n");
6145 ret = -ENODEV;
6146 goto error_1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006147 }
6148
6149 ivideo->mmio_vbase = ioremap(ivideo->mmio_base, ivideo->mmio_size);
6150 if(!ivideo->mmio_vbase) {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006151 printk(KERN_ERR "sisfb: Fatal error: Unable to map MMIO region\n");
6152 ret = -ENODEV;
6153error_0: iounmap(ivideo->video_vbase);
6154error_1: release_mem_region(ivideo->video_base, ivideo->video_size);
6155error_2: release_mem_region(ivideo->mmio_base, ivideo->mmio_size);
6156error_3: vfree(ivideo->bios_abase);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006157 if(ivideo->lpcdev)
Adrian Bunk0959f0c2007-05-08 00:39:50 -07006158 pci_dev_put(ivideo->lpcdev);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006159 if(ivideo->nbridge)
Adrian Bunk0959f0c2007-05-08 00:39:50 -07006160 pci_dev_put(ivideo->nbridge);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006161 pci_set_drvdata(pdev, NULL);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006162 if(!ivideo->sisvga_enabled)
6163 pci_disable_device(pdev);
6164 kfree(sis_fb_info);
6165 return ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006166 }
6167
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006168 printk(KERN_INFO "sisfb: Video RAM at 0x%lx, mapped to 0x%lx, size %ldk\n",
6169 ivideo->video_base, (unsigned long)ivideo->video_vbase, ivideo->video_size / 1024);
6170
6171 if(ivideo->video_offset) {
6172 printk(KERN_INFO "sisfb: Viewport offset %ldk\n",
6173 ivideo->video_offset / 1024);
6174 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07006175
6176 printk(KERN_INFO "sisfb: MMIO at 0x%lx, mapped to 0x%lx, size %ldk\n",
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006177 ivideo->mmio_base, (unsigned long)ivideo->mmio_vbase, ivideo->mmio_size / 1024);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006178
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006179
6180 /* Determine the size of the command queue */
6181 if(ivideo->sisvga_engine == SIS_300_VGA) {
6182 ivideo->cmdQueueSize = TURBO_QUEUE_AREA_SIZE;
6183 } else {
6184 if(ivideo->chip == XGI_20) {
6185 ivideo->cmdQueueSize = COMMAND_QUEUE_AREA_SIZE_Z7;
6186 } else {
6187 ivideo->cmdQueueSize = COMMAND_QUEUE_AREA_SIZE;
6188 }
6189 }
6190
6191 /* Engines are no longer initialized here; this is
6192 * now done after the first mode-switch (if the
6193 * submitted var has its acceleration flags set).
6194 */
6195
6196 /* Calculate the base of the (unused) hw cursor */
6197 ivideo->hwcursor_vbase = ivideo->video_vbase
6198 + ivideo->video_size
6199 - ivideo->cmdQueueSize
6200 - ivideo->hwcursor_size;
6201 ivideo->caps |= HW_CURSOR_CAP;
6202
6203 /* Initialize offscreen memory manager */
Linus Torvalds1da177e2005-04-16 15:20:36 -07006204 if((ivideo->havenoheap = sisfb_heap_init(ivideo))) {
6205 printk(KERN_WARNING "sisfb: Failed to initialize offscreen memory heap\n");
6206 }
6207
6208 /* Used for clearing the screen only, therefore respect our mem limit */
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006209 ivideo->SiS_Pr.VideoMemoryAddress += ivideo->video_offset;
6210 ivideo->SiS_Pr.VideoMemorySize = ivideo->sisfb_mem;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006211
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006212 ivideo->mtrr = -1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006213
6214 ivideo->vbflags = 0;
6215 ivideo->lcddefmodeidx = DEFAULT_LCDMODE;
6216 ivideo->tvdefmodeidx = DEFAULT_TVMODE;
6217 ivideo->defmodeidx = DEFAULT_MODE;
6218
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006219 ivideo->newrom = 0;
6220 if(ivideo->chip < XGI_20) {
6221 if(ivideo->bios_abase) {
6222 ivideo->newrom = SiSDetermineROMLayout661(&ivideo->SiS_Pr);
6223 }
6224 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07006225
6226 if((ivideo->sisfb_mode_idx < 0) ||
6227 ((sisbios_mode[ivideo->sisfb_mode_idx].mode_no[ivideo->mni]) != 0xFF)) {
6228
6229 sisfb_sense_crt1(ivideo);
6230
6231 sisfb_get_VB_type(ivideo);
6232
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006233 if(ivideo->vbflags2 & VB2_VIDEOBRIDGE) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07006234 sisfb_detect_VB_connect(ivideo);
6235 }
6236
6237 ivideo->currentvbflags = ivideo->vbflags & (VB_VIDEOBRIDGE | TV_STANDARD);
6238
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006239 /* Decide on which CRT2 device to use */
6240 if(ivideo->vbflags2 & VB2_VIDEOBRIDGE) {
6241 if(ivideo->sisfb_crt2type != -1) {
6242 if((ivideo->sisfb_crt2type == CRT2_LCD) &&
6243 (ivideo->vbflags & CRT2_LCD)) {
6244 ivideo->currentvbflags |= CRT2_LCD;
6245 } else if(ivideo->sisfb_crt2type != CRT2_LCD) {
6246 ivideo->currentvbflags |= ivideo->sisfb_crt2type;
6247 }
6248 } else {
6249 /* Chrontel 700x TV detection often unreliable, therefore
6250 * use a different default order on such machines
6251 */
6252 if((ivideo->sisvga_engine == SIS_300_VGA) &&
6253 (ivideo->vbflags2 & VB2_CHRONTEL)) {
6254 if(ivideo->vbflags & CRT2_LCD)
6255 ivideo->currentvbflags |= CRT2_LCD;
6256 else if(ivideo->vbflags & CRT2_TV)
6257 ivideo->currentvbflags |= CRT2_TV;
6258 else if(ivideo->vbflags & CRT2_VGA)
6259 ivideo->currentvbflags |= CRT2_VGA;
6260 } else {
6261 if(ivideo->vbflags & CRT2_TV)
6262 ivideo->currentvbflags |= CRT2_TV;
6263 else if(ivideo->vbflags & CRT2_LCD)
6264 ivideo->currentvbflags |= CRT2_LCD;
6265 else if(ivideo->vbflags & CRT2_VGA)
6266 ivideo->currentvbflags |= CRT2_VGA;
6267 }
6268 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07006269 }
6270
6271 if(ivideo->vbflags & CRT2_LCD) {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006272 sisfb_detect_lcd_type(ivideo);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006273 }
6274
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006275 sisfb_save_pdc_emi(ivideo);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006276
6277 if(!ivideo->sisfb_crt1off) {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006278 sisfb_handle_ddc(ivideo, &ivideo->sisfb_thismonitor, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006279 } else {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006280 if((ivideo->vbflags2 & VB2_SISTMDSBRIDGE) &&
6281 (ivideo->vbflags & (CRT2_VGA | CRT2_LCD))) {
6282 sisfb_handle_ddc(ivideo, &ivideo->sisfb_thismonitor, 1);
6283 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07006284 }
6285
6286 if(ivideo->sisfb_mode_idx >= 0) {
6287 int bu = ivideo->sisfb_mode_idx;
6288 ivideo->sisfb_mode_idx = sisfb_validate_mode(ivideo,
6289 ivideo->sisfb_mode_idx, ivideo->currentvbflags);
6290 if(bu != ivideo->sisfb_mode_idx) {
6291 printk(KERN_ERR "Mode %dx%dx%d failed validation\n",
6292 sisbios_mode[bu].xres,
6293 sisbios_mode[bu].yres,
6294 sisbios_mode[bu].bpp);
6295 }
6296 }
6297
6298 if(ivideo->sisfb_mode_idx < 0) {
6299 switch(ivideo->currentvbflags & VB_DISPTYPE_DISP2) {
6300 case CRT2_LCD:
6301 ivideo->sisfb_mode_idx = ivideo->lcddefmodeidx;
6302 break;
6303 case CRT2_TV:
6304 ivideo->sisfb_mode_idx = ivideo->tvdefmodeidx;
6305 break;
6306 default:
6307 ivideo->sisfb_mode_idx = ivideo->defmodeidx;
6308 break;
6309 }
6310 }
6311
6312 ivideo->mode_no = sisbios_mode[ivideo->sisfb_mode_idx].mode_no[ivideo->mni];
6313
6314 if(ivideo->refresh_rate != 0) {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006315 sisfb_search_refresh_rate(ivideo, ivideo->refresh_rate,
6316 ivideo->sisfb_mode_idx);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006317 }
6318
6319 if(ivideo->rate_idx == 0) {
6320 ivideo->rate_idx = sisbios_mode[ivideo->sisfb_mode_idx].rate_idx;
6321 ivideo->refresh_rate = 60;
6322 }
6323
6324 if(ivideo->sisfb_thismonitor.datavalid) {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006325 if(!sisfb_verify_rate(ivideo, &ivideo->sisfb_thismonitor,
6326 ivideo->sisfb_mode_idx,
6327 ivideo->rate_idx,
6328 ivideo->refresh_rate)) {
6329 printk(KERN_INFO "sisfb: WARNING: Refresh rate "
6330 "exceeds monitor specs!\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07006331 }
6332 }
6333
6334 ivideo->video_bpp = sisbios_mode[ivideo->sisfb_mode_idx].bpp;
6335 ivideo->video_width = sisbios_mode[ivideo->sisfb_mode_idx].xres;
6336 ivideo->video_height = sisbios_mode[ivideo->sisfb_mode_idx].yres;
6337
6338 sisfb_set_vparms(ivideo);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006339
Linus Torvalds1da177e2005-04-16 15:20:36 -07006340 printk(KERN_INFO "sisfb: Default mode is %dx%dx%d (%dHz)\n",
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006341 ivideo->video_width, ivideo->video_height, ivideo->video_bpp,
Linus Torvalds1da177e2005-04-16 15:20:36 -07006342 ivideo->refresh_rate);
6343
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006344 /* Set up the default var according to chosen default display mode */
Linus Torvalds1da177e2005-04-16 15:20:36 -07006345 ivideo->default_var.xres = ivideo->default_var.xres_virtual = ivideo->video_width;
6346 ivideo->default_var.yres = ivideo->default_var.yres_virtual = ivideo->video_height;
6347 ivideo->default_var.bits_per_pixel = ivideo->video_bpp;
6348
6349 sisfb_bpp_to_var(ivideo, &ivideo->default_var);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006350
Linus Torvalds1da177e2005-04-16 15:20:36 -07006351 ivideo->default_var.pixclock = (u32) (1000000000 /
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006352 sisfb_mode_rate_to_dclock(&ivideo->SiS_Pr, ivideo->mode_no, ivideo->rate_idx));
6353
6354 if(sisfb_mode_rate_to_ddata(&ivideo->SiS_Pr, ivideo->mode_no,
6355 ivideo->rate_idx, &ivideo->default_var)) {
6356 if((ivideo->default_var.vmode & FB_VMODE_MASK) == FB_VMODE_DOUBLE) {
6357 ivideo->default_var.pixclock <<= 1;
6358 }
6359 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07006360
6361 if(ivideo->sisfb_ypan) {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006362 /* Maximize regardless of sisfb_max at startup */
6363 ivideo->default_var.yres_virtual =
6364 sisfb_calc_maxyres(ivideo, &ivideo->default_var);
6365 if(ivideo->default_var.yres_virtual < ivideo->default_var.yres) {
6366 ivideo->default_var.yres_virtual = ivideo->default_var.yres;
6367 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07006368 }
6369
6370 sisfb_calc_pitch(ivideo, &ivideo->default_var);
6371
6372 ivideo->accel = 0;
6373 if(ivideo->sisfb_accel) {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006374 ivideo->accel = -1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006375#ifdef STUPID_ACCELF_TEXT_SHIT
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006376 ivideo->default_var.accel_flags |= FB_ACCELF_TEXT;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006377#endif
6378 }
6379 sisfb_initaccel(ivideo);
6380
6381#if defined(FBINFO_HWACCEL_DISABLED) && defined(FBINFO_HWACCEL_XPAN)
6382 sis_fb_info->flags = FBINFO_DEFAULT |
6383 FBINFO_HWACCEL_YPAN |
6384 FBINFO_HWACCEL_XPAN |
6385 FBINFO_HWACCEL_COPYAREA |
6386 FBINFO_HWACCEL_FILLRECT |
6387 ((ivideo->accel) ? 0 : FBINFO_HWACCEL_DISABLED);
6388#else
6389 sis_fb_info->flags = FBINFO_FLAG_DEFAULT;
6390#endif
6391 sis_fb_info->var = ivideo->default_var;
6392 sis_fb_info->fix = ivideo->sisfb_fix;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006393 sis_fb_info->screen_base = ivideo->video_vbase + ivideo->video_offset;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006394 sis_fb_info->fbops = &sisfb_ops;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006395 sisfb_get_fix(&sis_fb_info->fix, -1, sis_fb_info);
6396 sis_fb_info->pseudo_palette = ivideo->pseudo_palette;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006397
Linus Torvalds1da177e2005-04-16 15:20:36 -07006398 fb_alloc_cmap(&sis_fb_info->cmap, 256 , 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006399
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006400 printk(KERN_DEBUG "sisfb: Initial vbflags 0x%x\n", (int)ivideo->vbflags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006401
6402#ifdef CONFIG_MTRR
6403 ivideo->mtrr = mtrr_add(ivideo->video_base, ivideo->video_size,
6404 MTRR_TYPE_WRCOMB, 1);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006405 if(ivideo->mtrr < 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07006406 printk(KERN_DEBUG "sisfb: Failed to add MTRRs\n");
6407 }
6408#endif
6409
Linus Torvalds1da177e2005-04-16 15:20:36 -07006410 if(register_framebuffer(sis_fb_info) < 0) {
6411 printk(KERN_ERR "sisfb: Fatal error: Failed to register framebuffer\n");
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006412 ret = -EINVAL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006413 iounmap(ivideo->mmio_vbase);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006414 goto error_0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006415 }
6416
6417 ivideo->registered = 1;
6418
6419 /* Enlist us */
6420 ivideo->next = card_list;
6421 card_list = ivideo;
6422
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006423#ifdef SIS_OLD_CONFIG_COMPAT
6424 {
6425 int ret;
6426 /* Our ioctls are all "32/64bit compatible" */
6427 ret = register_ioctl32_conversion(FBIO_ALLOC, NULL);
6428 ret |= register_ioctl32_conversion(FBIO_FREE, NULL);
6429 ret |= register_ioctl32_conversion(FBIOGET_VBLANK, NULL);
6430 ret |= register_ioctl32_conversion(SISFB_GET_INFO_SIZE, NULL);
6431 ret |= register_ioctl32_conversion(SISFB_GET_INFO, NULL);
6432 ret |= register_ioctl32_conversion(SISFB_GET_TVPOSOFFSET, NULL);
6433 ret |= register_ioctl32_conversion(SISFB_SET_TVPOSOFFSET, NULL);
6434 ret |= register_ioctl32_conversion(SISFB_SET_LOCK, NULL);
6435 ret |= register_ioctl32_conversion(SISFB_GET_VBRSTATUS, NULL);
6436 ret |= register_ioctl32_conversion(SISFB_GET_AUTOMAXIMIZE, NULL);
6437 ret |= register_ioctl32_conversion(SISFB_SET_AUTOMAXIMIZE, NULL);
6438 ret |= register_ioctl32_conversion(SISFB_COMMAND, NULL);
6439 if(ret)
6440 printk(KERN_ERR
6441 "sisfb: Error registering ioctl32 translations\n");
6442 else
6443 ivideo->ioctl32registered = 1;
6444 }
6445#endif
6446
Linus Torvalds1da177e2005-04-16 15:20:36 -07006447 printk(KERN_INFO "sisfb: 2D acceleration is %s, y-panning %s\n",
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006448 ivideo->sisfb_accel ? "enabled" : "disabled",
6449 ivideo->sisfb_ypan ?
6450 (ivideo->sisfb_max ? "enabled (auto-max)" :
6451 "enabled (no auto-max)") :
6452 "disabled");
Linus Torvalds1da177e2005-04-16 15:20:36 -07006453
6454
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006455 printk(KERN_INFO "fb%d: %s frame buffer device version %d.%d.%d\n",
Michal Piotrowski43704092006-10-03 01:15:00 -07006456 sis_fb_info->node, ivideo->myid, VER_MAJOR, VER_MINOR, VER_LEVEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006457
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006458 printk(KERN_INFO "sisfb: Copyright (C) 2001-2005 Thomas Winischhofer\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07006459
6460 } /* if mode = "none" */
6461
6462 return 0;
6463}
6464
6465/*****************************************************/
6466/* PCI DEVICE HANDLING */
6467/*****************************************************/
6468
6469static void __devexit sisfb_remove(struct pci_dev *pdev)
6470{
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006471 struct sis_video_info *ivideo = pci_get_drvdata(pdev);
6472 struct fb_info *sis_fb_info = ivideo->memyselfandi;
6473 int registered = ivideo->registered;
6474 int modechanged = ivideo->modechanged;
6475
6476#ifdef SIS_OLD_CONFIG_COMPAT
6477 if(ivideo->ioctl32registered) {
6478 int ret;
6479 ret = unregister_ioctl32_conversion(FBIO_ALLOC);
6480 ret |= unregister_ioctl32_conversion(FBIO_FREE);
6481 ret |= unregister_ioctl32_conversion(FBIOGET_VBLANK);
6482 ret |= unregister_ioctl32_conversion(SISFB_GET_INFO_SIZE);
6483 ret |= unregister_ioctl32_conversion(SISFB_GET_INFO);
6484 ret |= unregister_ioctl32_conversion(SISFB_GET_TVPOSOFFSET);
6485 ret |= unregister_ioctl32_conversion(SISFB_SET_TVPOSOFFSET);
6486 ret |= unregister_ioctl32_conversion(SISFB_SET_LOCK);
6487 ret |= unregister_ioctl32_conversion(SISFB_GET_VBRSTATUS);
6488 ret |= unregister_ioctl32_conversion(SISFB_GET_AUTOMAXIMIZE);
6489 ret |= unregister_ioctl32_conversion(SISFB_SET_AUTOMAXIMIZE);
6490 ret |= unregister_ioctl32_conversion(SISFB_COMMAND);
6491 if(ret)
6492 printk(KERN_ERR
6493 "sisfb: Error unregistering ioctl32 translations\n");
6494 }
6495#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -07006496
6497 /* Unmap */
Linus Torvalds1da177e2005-04-16 15:20:36 -07006498 iounmap(ivideo->mmio_vbase);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006499 iounmap(ivideo->video_vbase);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006500
6501 /* Release mem regions */
6502 release_mem_region(ivideo->video_base, ivideo->video_size);
6503 release_mem_region(ivideo->mmio_base, ivideo->mmio_size);
6504
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006505 vfree(ivideo->bios_abase);
6506
6507 if(ivideo->lpcdev)
Adrian Bunk0959f0c2007-05-08 00:39:50 -07006508 pci_dev_put(ivideo->lpcdev);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006509
6510 if(ivideo->nbridge)
Adrian Bunk0959f0c2007-05-08 00:39:50 -07006511 pci_dev_put(ivideo->nbridge);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006512
Linus Torvalds1da177e2005-04-16 15:20:36 -07006513#ifdef CONFIG_MTRR
6514 /* Release MTRR region */
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006515 if(ivideo->mtrr >= 0)
Linus Torvalds1da177e2005-04-16 15:20:36 -07006516 mtrr_del(ivideo->mtrr, ivideo->video_base, ivideo->video_size);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006517#endif
6518
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006519 pci_set_drvdata(pdev, NULL);
6520
6521 /* If device was disabled when starting, disable
6522 * it when quitting.
6523 */
6524 if(!ivideo->sisvga_enabled)
6525 pci_disable_device(pdev);
6526
Linus Torvalds1da177e2005-04-16 15:20:36 -07006527 /* Unregister the framebuffer */
6528 if(ivideo->registered) {
6529 unregister_framebuffer(sis_fb_info);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006530 framebuffer_release(sis_fb_info);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006531 }
6532
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006533 /* OK, our ivideo is gone for good from here. */
Linus Torvalds1da177e2005-04-16 15:20:36 -07006534
6535 /* TODO: Restore the initial mode
6536 * This sounds easy but is as good as impossible
6537 * on many machines with SiS chip and video bridge
6538 * since text modes are always set up differently
6539 * from machine to machine. Depends on the type
6540 * of integration between chipset and bridge.
6541 */
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006542 if(registered && modechanged)
6543 printk(KERN_INFO
6544 "sisfb: Restoring of text mode not supported yet\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07006545};
6546
6547static struct pci_driver sisfb_driver = {
6548 .name = "sisfb",
6549 .id_table = sisfb_pci_table,
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006550 .probe = sisfb_probe,
Linus Torvalds1da177e2005-04-16 15:20:36 -07006551 .remove = __devexit_p(sisfb_remove)
6552};
6553
6554SISINITSTATIC int __init sisfb_init(void)
6555{
Linus Torvalds1da177e2005-04-16 15:20:36 -07006556#ifndef MODULE
6557 char *options = NULL;
6558
6559 if(fb_get_options("sisfb", &options))
6560 return -ENODEV;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006561
Linus Torvalds1da177e2005-04-16 15:20:36 -07006562 sisfb_setup(options);
6563#endif
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006564 return pci_register_driver(&sisfb_driver);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006565}
6566
Linus Torvalds1da177e2005-04-16 15:20:36 -07006567#ifndef MODULE
6568module_init(sisfb_init);
6569#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -07006570
6571/*****************************************************/
6572/* MODULE */
6573/*****************************************************/
6574
6575#ifdef MODULE
6576
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006577static char *mode = NULL;
6578static int vesa = -1;
6579static unsigned int rate = 0;
6580static unsigned int crt1off = 1;
6581static unsigned int mem = 0;
6582static char *forcecrt2type = NULL;
6583static int forcecrt1 = -1;
6584static int pdc = -1;
6585static int pdc1 = -1;
6586static int noaccel = -1;
6587static int noypan = -1;
6588static int nomax = -1;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006589static int userom = -1;
6590static int useoem = -1;
6591static char *tvstandard = NULL;
6592static int nocrt2rate = 0;
6593static int scalelcd = -1;
6594static char *specialtiming = NULL;
6595static int lvdshl = -1;
6596static int tvxposoffset = 0, tvyposoffset = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006597#if !defined(__i386__) && !defined(__x86_64__)
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006598static int resetcard = 0;
6599static int videoram = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006600#endif
6601
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006602static int __init sisfb_init_module(void)
6603{
6604 sisfb_setdefaultparms();
6605
6606 if(rate)
6607 sisfb_parm_rate = rate;
6608
6609 if((scalelcd == 0) || (scalelcd == 1))
6610 sisfb_scalelcd = scalelcd ^ 1;
6611
6612 /* Need to check crt2 type first for fstn/dstn */
6613
6614 if(forcecrt2type)
6615 sisfb_search_crt2type(forcecrt2type);
6616
6617 if(tvstandard)
6618 sisfb_search_tvstd(tvstandard);
6619
6620 if(mode)
Richard Knutssonc30660ea2007-02-12 00:55:06 -08006621 sisfb_search_mode(mode, false);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006622 else if(vesa != -1)
Richard Knutssonc30660ea2007-02-12 00:55:06 -08006623 sisfb_search_vesamode(vesa, false);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006624
6625 sisfb_crt1off = (crt1off == 0) ? 1 : 0;
6626
6627 sisfb_forcecrt1 = forcecrt1;
6628 if(forcecrt1 == 1)
6629 sisfb_crt1off = 0;
6630 else if(forcecrt1 == 0)
6631 sisfb_crt1off = 1;
6632
6633 if(noaccel == 1)
6634 sisfb_accel = 0;
6635 else if(noaccel == 0)
6636 sisfb_accel = 1;
6637
6638 if(noypan == 1)
6639 sisfb_ypan = 0;
6640 else if(noypan == 0)
6641 sisfb_ypan = 1;
6642
6643 if(nomax == 1)
6644 sisfb_max = 0;
6645 else if(nomax == 0)
6646 sisfb_max = 1;
6647
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006648 if(mem)
6649 sisfb_parm_mem = mem;
6650
6651 if(userom != -1)
6652 sisfb_userom = userom;
6653
6654 if(useoem != -1)
6655 sisfb_useoem = useoem;
6656
6657 if(pdc != -1)
6658 sisfb_pdc = (pdc & 0x7f);
6659
6660 if(pdc1 != -1)
6661 sisfb_pdca = (pdc1 & 0x1f);
6662
6663 sisfb_nocrt2rate = nocrt2rate;
6664
6665 if(specialtiming)
6666 sisfb_search_specialtiming(specialtiming);
6667
6668 if((lvdshl >= 0) && (lvdshl <= 3))
6669 sisfb_lvdshl = lvdshl;
6670
6671 sisfb_tvxposoffset = tvxposoffset;
6672 sisfb_tvyposoffset = tvyposoffset;
6673
6674#if !defined(__i386__) && !defined(__x86_64__)
6675 sisfb_resetcard = (resetcard) ? 1 : 0;
6676 if(videoram)
6677 sisfb_videoram = videoram;
6678#endif
6679
6680 return sisfb_init();
6681}
6682
6683static void __exit sisfb_remove_module(void)
6684{
6685 pci_unregister_driver(&sisfb_driver);
6686 printk(KERN_DEBUG "sisfb: Module unloaded\n");
6687}
6688
6689module_init(sisfb_init_module);
6690module_exit(sisfb_remove_module);
6691
6692MODULE_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 -07006693MODULE_LICENSE("GPL");
6694MODULE_AUTHOR("Thomas Winischhofer <thomas@winischhofer.net>, Others");
6695
Linus Torvalds1da177e2005-04-16 15:20:36 -07006696module_param(mem, int, 0);
6697module_param(noaccel, int, 0);
6698module_param(noypan, int, 0);
6699module_param(nomax, int, 0);
6700module_param(userom, int, 0);
6701module_param(useoem, int, 0);
6702module_param(mode, charp, 0);
6703module_param(vesa, int, 0);
6704module_param(rate, int, 0);
6705module_param(forcecrt1, int, 0);
6706module_param(forcecrt2type, charp, 0);
6707module_param(scalelcd, int, 0);
6708module_param(pdc, int, 0);
6709module_param(pdc1, int, 0);
6710module_param(specialtiming, charp, 0);
6711module_param(lvdshl, int, 0);
6712module_param(tvstandard, charp, 0);
6713module_param(tvxposoffset, int, 0);
6714module_param(tvyposoffset, int, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006715module_param(nocrt2rate, int, 0);
6716#if !defined(__i386__) && !defined(__x86_64__)
6717module_param(resetcard, int, 0);
6718module_param(videoram, int, 0);
6719#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -07006720
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006721MODULE_PARM_DESC(mem,
6722 "\nDetermines the beginning of the video memory heap in KB. This heap is used\n"
6723 "for video RAM management for eg. DRM/DRI. On 300 series, the default depends\n"
6724 "on the amount of video RAM available. If 8MB of video RAM or less is available,\n"
6725 "the heap starts at 4096KB, if between 8 and 16MB are available at 8192KB,\n"
6726 "otherwise at 12288KB. On 315/330/340 series, the heap size is 32KB by default.\n"
6727 "The value is to be specified without 'KB'.\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07006728
6729MODULE_PARM_DESC(noaccel,
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006730 "\nIf set to anything other than 0, 2D acceleration will be disabled.\n"
Linus Torvalds1da177e2005-04-16 15:20:36 -07006731 "(default: 0)\n");
6732
6733MODULE_PARM_DESC(noypan,
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006734 "\nIf set to anything other than 0, y-panning will be disabled and scrolling\n"
6735 "will be performed by redrawing the screen. (default: 0)\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07006736
6737MODULE_PARM_DESC(nomax,
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006738 "\nIf y-panning is enabled, sisfb will by default use the entire available video\n"
Linus Torvalds1da177e2005-04-16 15:20:36 -07006739 "memory for the virtual screen in order to optimize scrolling performance. If\n"
6740 "this is set to anything other than 0, sisfb will not do this and thereby \n"
6741 "enable the user to positively specify a virtual Y size of the screen using\n"
6742 "fbset. (default: 0)\n");
6743
Linus Torvalds1da177e2005-04-16 15:20:36 -07006744MODULE_PARM_DESC(mode,
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006745 "\nSelects the desired default display mode in the format XxYxDepth,\n"
6746 "eg. 1024x768x16. Other formats supported include XxY-Depth and\n"
Linus Torvalds1da177e2005-04-16 15:20:36 -07006747 "XxY-Depth@Rate. If the parameter is only one (decimal or hexadecimal)\n"
6748 "number, it will be interpreted as a VESA mode number. (default: 800x600x8)\n");
6749
6750MODULE_PARM_DESC(vesa,
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006751 "\nSelects the desired default display mode by VESA defined mode number, eg.\n"
6752 "0x117 (default: 0x0103)\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07006753
6754MODULE_PARM_DESC(rate,
6755 "\nSelects the desired vertical refresh rate for CRT1 (external VGA) in Hz.\n"
6756 "If the mode is specified in the format XxY-Depth@Rate, this parameter\n"
6757 "will be ignored (default: 60)\n");
6758
6759MODULE_PARM_DESC(forcecrt1,
6760 "\nNormally, the driver autodetects whether or not CRT1 (external VGA) is \n"
6761 "connected. With this option, the detection can be overridden (1=CRT1 ON,\n"
6762 "0=CRT1 OFF) (default: [autodetected])\n");
6763
6764MODULE_PARM_DESC(forcecrt2type,
6765 "\nIf this option is omitted, the driver autodetects CRT2 output devices, such as\n"
6766 "LCD, TV or secondary VGA. With this option, this autodetection can be\n"
6767 "overridden. Possible parameters are LCD, TV, VGA or NONE. NONE disables CRT2.\n"
6768 "On systems with a SiS video bridge, parameters SVIDEO, COMPOSITE or SCART can\n"
6769 "be used instead of TV to override the TV detection. Furthermore, on systems\n"
6770 "with a SiS video bridge, SVIDEO+COMPOSITE, HIVISION, YPBPR480I, YPBPR480P,\n"
6771 "YPBPR720P and YPBPR1080I are understood. However, whether or not these work\n"
6772 "depends on the very hardware in use. (default: [autodetected])\n");
6773
6774MODULE_PARM_DESC(scalelcd,
6775 "\nSetting this to 1 will force the driver to scale the LCD image to the panel's\n"
6776 "native resolution. Setting it to 0 will disable scaling; LVDS panels will\n"
6777 "show black bars around the image, TMDS panels will probably do the scaling\n"
6778 "themselves. Default: 1 on LVDS panels, 0 on TMDS panels\n");
6779
6780MODULE_PARM_DESC(pdc,
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006781 "\nThis is for manually selecting the LCD panel delay compensation. The driver\n"
Linus Torvalds1da177e2005-04-16 15:20:36 -07006782 "should detect this correctly in most cases; however, sometimes this is not\n"
6783 "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 -07006784 "on a 300 series chipset; 6 on other chipsets. If the problem persists, try\n"
6785 "other values (on 300 series: between 4 and 60 in steps of 4; otherwise: any\n"
6786 "value from 0 to 31). (default: autodetected, if LCD is active during start)\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07006787
6788#ifdef CONFIG_FB_SIS_315
6789MODULE_PARM_DESC(pdc1,
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006790 "\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 -07006791 "series only. (default: autodetected if LCD is in LCD-via-CRT1 mode during\n"
6792 "startup) - Note: currently, this has no effect because LCD-via-CRT1 is not\n"
6793 "implemented yet.\n");
6794#endif
6795
6796MODULE_PARM_DESC(specialtiming,
6797 "\nPlease refer to documentation for more information on this option.\n");
6798
6799MODULE_PARM_DESC(lvdshl,
6800 "\nPlease refer to documentation for more information on this option.\n");
6801
6802MODULE_PARM_DESC(tvstandard,
6803 "\nThis allows overriding the BIOS default for the TV standard. Valid choices are\n"
6804 "pal, ntsc, palm and paln. (default: [auto; pal or ntsc only])\n");
6805
6806MODULE_PARM_DESC(tvxposoffset,
6807 "\nRelocate TV output horizontally. Possible parameters: -32 through 32.\n"
6808 "Default: 0\n");
6809
6810MODULE_PARM_DESC(tvyposoffset,
6811 "\nRelocate TV output vertically. Possible parameters: -32 through 32.\n"
6812 "Default: 0\n");
6813
Linus Torvalds1da177e2005-04-16 15:20:36 -07006814MODULE_PARM_DESC(nocrt2rate,
6815 "\nSetting this to 1 will force the driver to use the default refresh rate for\n"
6816 "CRT2 if CRT2 type is VGA. (default: 0, use same rate as CRT1)\n");
6817
Linus Torvalds1da177e2005-04-16 15:20:36 -07006818#if !defined(__i386__) && !defined(__x86_64__)
6819#ifdef CONFIG_FB_SIS_300
6820MODULE_PARM_DESC(resetcard,
6821 "\nSet this to 1 in order to reset (POST) the card on non-x86 machines where\n"
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006822 "the BIOS did not POST the card (only supported for SiS 300/305 and XGI cards\n"
6823 "currently). Default: 0\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07006824
6825MODULE_PARM_DESC(videoram,
6826 "\nSet this to the amount of video RAM (in kilobyte) the card has. Required on\n"
6827 "some non-x86 architectures where the memory auto detection fails. Only\n"
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006828 "relevant if resetcard is set, too. SiS300/305 only. Default: [auto-detect]\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07006829#endif
6830#endif
6831
Linus Torvalds1da177e2005-04-16 15:20:36 -07006832#endif /* /MODULE */
6833
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006834/* _GPL only for new symbols. */
Linus Torvalds1da177e2005-04-16 15:20:36 -07006835EXPORT_SYMBOL(sis_malloc);
6836EXPORT_SYMBOL(sis_free);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006837EXPORT_SYMBOL_GPL(sis_malloc_new);
6838EXPORT_SYMBOL_GPL(sis_free_new);
6839
Linus Torvalds1da177e2005-04-16 15:20:36 -07006840
6841