blob: a30e1e13d8be87c7c8135ed79c57a54f3e0c691e [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>
61#include <asm/uaccess.h>
62#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);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001251 ivideo->mode_no = sisbios_mode[ivideo->sisfb_mode_idx].mode_no[ivideo->mni];
Linus Torvalds1da177e2005-04-16 15:20:36 -07001252 } else {
1253 ivideo->sisfb_mode_idx = -1;
1254 }
1255
1256 if(ivideo->sisfb_mode_idx < 0) {
1257 printk(KERN_ERR "sisfb: Mode %dx%dx%d not supported\n", var->xres,
1258 var->yres, var->bits_per_pixel);
1259 ivideo->sisfb_mode_idx = old_mode;
1260 return -EINVAL;
1261 }
1262
1263 if(sisfb_search_refresh_rate(ivideo, ivideo->refresh_rate, ivideo->sisfb_mode_idx) == 0) {
1264 ivideo->rate_idx = sisbios_mode[ivideo->sisfb_mode_idx].rate_idx;
1265 ivideo->refresh_rate = 60;
1266 }
1267
Linus Torvalds1da177e2005-04-16 15:20:36 -07001268 if(isactive) {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001269 /* If acceleration to be used? Need to know
1270 * before pre/post_set_mode()
1271 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001272 ivideo->accel = 0;
1273#if defined(FBINFO_HWACCEL_DISABLED) && defined(FBINFO_HWACCEL_XPAN)
1274#ifdef STUPID_ACCELF_TEXT_SHIT
1275 if(var->accel_flags & FB_ACCELF_TEXT) {
1276 info->flags &= ~FBINFO_HWACCEL_DISABLED;
1277 } else {
1278 info->flags |= FBINFO_HWACCEL_DISABLED;
1279 }
1280#endif
1281 if(!(info->flags & FBINFO_HWACCEL_DISABLED)) ivideo->accel = -1;
1282#else
1283 if(var->accel_flags & FB_ACCELF_TEXT) ivideo->accel = -1;
1284#endif
1285
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001286 if((ret = sisfb_set_mode(ivideo, 1))) {
1287 return ret;
1288 }
1289
1290 ivideo->video_bpp = sisbios_mode[ivideo->sisfb_mode_idx].bpp;
1291 ivideo->video_width = sisbios_mode[ivideo->sisfb_mode_idx].xres;
1292 ivideo->video_height = sisbios_mode[ivideo->sisfb_mode_idx].yres;
1293
1294 sisfb_calc_pitch(ivideo, var);
1295 sisfb_set_pitch(ivideo);
1296
Linus Torvalds1da177e2005-04-16 15:20:36 -07001297 sisfb_set_vparms(ivideo);
1298
1299 ivideo->current_width = ivideo->video_width;
1300 ivideo->current_height = ivideo->video_height;
1301 ivideo->current_bpp = ivideo->video_bpp;
1302 ivideo->current_htotal = htotal;
1303 ivideo->current_vtotal = vtotal;
1304 ivideo->current_linelength = ivideo->video_linelength;
1305 ivideo->current_pixclock = var->pixclock;
1306 ivideo->current_refresh_rate = ivideo->refresh_rate;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001307 ivideo->sisfb_lastrates[ivideo->mode_no] = ivideo->refresh_rate;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001308 }
1309
1310 return 0;
1311}
1312
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001313static void
1314sisfb_set_base_CRT1(struct sis_video_info *ivideo, unsigned int base)
1315{
1316 outSISIDXREG(SISSR, IND_SIS_PASSWORD, SIS_PASSWORD);
1317
1318 outSISIDXREG(SISCR, 0x0D, base & 0xFF);
1319 outSISIDXREG(SISCR, 0x0C, (base >> 8) & 0xFF);
1320 outSISIDXREG(SISSR, 0x0D, (base >> 16) & 0xFF);
1321 if(ivideo->sisvga_engine == SIS_315_VGA) {
1322 setSISIDXREG(SISSR, 0x37, 0xFE, (base >> 24) & 0x01);
1323 }
1324}
1325
1326static void
1327sisfb_set_base_CRT2(struct sis_video_info *ivideo, unsigned int base)
1328{
1329 if(ivideo->currentvbflags & VB_DISPTYPE_DISP2) {
1330 orSISIDXREG(SISPART1, ivideo->CRT2_write_enable, 0x01);
1331 outSISIDXREG(SISPART1, 0x06, (base & 0xFF));
1332 outSISIDXREG(SISPART1, 0x05, ((base >> 8) & 0xFF));
1333 outSISIDXREG(SISPART1, 0x04, ((base >> 16) & 0xFF));
1334 if(ivideo->sisvga_engine == SIS_315_VGA) {
1335 setSISIDXREG(SISPART1, 0x02, 0x7F, ((base >> 24) & 0x01) << 7);
1336 }
1337 }
1338}
1339
Linus Torvalds1da177e2005-04-16 15:20:36 -07001340static int
1341sisfb_pan_var(struct sis_video_info *ivideo, struct fb_var_screeninfo *var)
1342{
Linus Torvalds1da177e2005-04-16 15:20:36 -07001343 if(var->xoffset > (var->xres_virtual - var->xres)) {
1344 return -EINVAL;
1345 }
1346 if(var->yoffset > (var->yres_virtual - var->yres)) {
1347 return -EINVAL;
1348 }
1349
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001350 ivideo->current_base = (var->yoffset * var->xres_virtual) + var->xoffset;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001351
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001352 /* calculate base bpp dep. */
1353 switch(var->bits_per_pixel) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001354 case 32:
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001355 break;
1356 case 16:
1357 ivideo->current_base >>= 1;
1358 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001359 case 8:
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001360 default:
1361 ivideo->current_base >>= 2;
1362 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001363 }
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001364
1365 ivideo->current_base += (ivideo->video_offset >> 2);
1366
1367 sisfb_set_base_CRT1(ivideo, ivideo->current_base);
1368 sisfb_set_base_CRT2(ivideo, ivideo->current_base);
1369
Linus Torvalds1da177e2005-04-16 15:20:36 -07001370 return 0;
1371}
1372
Linus Torvalds1da177e2005-04-16 15:20:36 -07001373static int
1374sisfb_open(struct fb_info *info, int user)
1375{
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001376 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001377}
1378
1379static int
1380sisfb_release(struct fb_info *info, int user)
1381{
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001382 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001383}
1384
1385static int
1386sisfb_setcolreg(unsigned regno, unsigned red, unsigned green, unsigned blue,
1387 unsigned transp, struct fb_info *info)
1388{
1389 struct sis_video_info *ivideo = (struct sis_video_info *)info->par;
1390
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001391 if(regno >= sisfb_get_cmap_len(&info->var))
1392 return 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001393
1394 switch(info->var.bits_per_pixel) {
1395 case 8:
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001396 outSISREG(SISDACA, regno);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001397 outSISREG(SISDACD, (red >> 10));
1398 outSISREG(SISDACD, (green >> 10));
1399 outSISREG(SISDACD, (blue >> 10));
1400 if(ivideo->currentvbflags & VB_DISPTYPE_DISP2) {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001401 outSISREG(SISDAC2A, regno);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001402 outSISREG(SISDAC2D, (red >> 8));
1403 outSISREG(SISDAC2D, (green >> 8));
1404 outSISREG(SISDAC2D, (blue >> 8));
1405 }
1406 break;
1407 case 16:
1408 ((u32 *)(info->pseudo_palette))[regno] =
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001409 (red & 0xf800) |
1410 ((green & 0xfc00) >> 5) |
1411 ((blue & 0xf800) >> 11);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001412 break;
1413 case 32:
1414 red >>= 8;
1415 green >>= 8;
1416 blue >>= 8;
1417 ((u32 *)(info->pseudo_palette))[regno] =
1418 (red << 16) | (green << 8) | (blue);
1419 break;
1420 }
1421 return 0;
1422}
1423
1424static int
1425sisfb_set_par(struct fb_info *info)
1426{
1427 int err;
1428
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001429 if((err = sisfb_do_set_var(&info->var, 1, info)))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001430 return err;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001431
Linus Torvalds1da177e2005-04-16 15:20:36 -07001432#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,10)
1433 sisfb_get_fix(&info->fix, info->currcon, info);
1434#else
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001435 sisfb_get_fix(&info->fix, -1, info);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001436#endif
1437 return 0;
1438}
1439
1440static int
1441sisfb_check_var(struct fb_var_screeninfo *var, struct fb_info *info)
1442{
1443 struct sis_video_info *ivideo = (struct sis_video_info *)info->par;
1444 unsigned int htotal = 0, vtotal = 0, myrateindex = 0;
1445 unsigned int drate = 0, hrate = 0, maxyres;
1446 int found_mode = 0;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001447 int refresh_rate, search_idx, tidx;
Richard Knutssonc30660ea2007-02-12 00:55:06 -08001448 bool recalc_clock = false;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001449 u32 pixclock;
1450
1451 htotal = var->left_margin + var->xres + var->right_margin + var->hsync_len;
1452
1453 vtotal = var->upper_margin + var->lower_margin + var->vsync_len;
1454
1455 pixclock = var->pixclock;
1456
1457 if((var->vmode & FB_VMODE_MASK) == FB_VMODE_NONINTERLACED) {
1458 vtotal += var->yres;
1459 vtotal <<= 1;
1460 } else if((var->vmode & FB_VMODE_MASK) == FB_VMODE_DOUBLE) {
1461 vtotal += var->yres;
1462 vtotal <<= 2;
1463 } else if((var->vmode & FB_VMODE_MASK) == FB_VMODE_INTERLACED) {
1464 vtotal += var->yres;
1465 vtotal <<= 1;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001466 } else
1467 vtotal += var->yres;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001468
1469 if(!(htotal) || !(vtotal)) {
1470 SISFAIL("sisfb: no valid timing data");
1471 }
1472
1473 search_idx = 0;
1474 while( (sisbios_mode[search_idx].mode_no[0] != 0) &&
1475 (sisbios_mode[search_idx].xres <= var->xres) ) {
1476 if( (sisbios_mode[search_idx].xres == var->xres) &&
1477 (sisbios_mode[search_idx].yres == var->yres) &&
1478 (sisbios_mode[search_idx].bpp == var->bits_per_pixel)) {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001479 if((tidx = sisfb_validate_mode(ivideo, search_idx,
1480 ivideo->currentvbflags)) > 0) {
1481 found_mode = 1;
1482 search_idx = tidx;
1483 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001484 }
1485 }
1486 search_idx++;
1487 }
1488
1489 if(!found_mode) {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001490 search_idx = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001491 while(sisbios_mode[search_idx].mode_no[0] != 0) {
1492 if( (var->xres <= sisbios_mode[search_idx].xres) &&
1493 (var->yres <= sisbios_mode[search_idx].yres) &&
1494 (var->bits_per_pixel == sisbios_mode[search_idx].bpp) ) {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001495 if((tidx = sisfb_validate_mode(ivideo,search_idx,
1496 ivideo->currentvbflags)) > 0) {
1497 found_mode = 1;
1498 search_idx = tidx;
1499 break;
1500 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001501 }
1502 search_idx++;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001503 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001504 if(found_mode) {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001505 printk(KERN_DEBUG
1506 "sisfb: Adapted from %dx%dx%d to %dx%dx%d\n",
1507 var->xres, var->yres, var->bits_per_pixel,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001508 sisbios_mode[search_idx].xres,
1509 sisbios_mode[search_idx].yres,
1510 var->bits_per_pixel);
1511 var->xres = sisbios_mode[search_idx].xres;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001512 var->yres = sisbios_mode[search_idx].yres;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001513 } else {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001514 printk(KERN_ERR
1515 "sisfb: Failed to find supported mode near %dx%dx%d\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07001516 var->xres, var->yres, var->bits_per_pixel);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001517 return -EINVAL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001518 }
1519 }
1520
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001521 if( ((ivideo->vbflags2 & VB2_LVDS) ||
1522 ((ivideo->vbflags2 & VB2_30xBDH) && (ivideo->currentvbflags & CRT2_LCD))) &&
Linus Torvalds1da177e2005-04-16 15:20:36 -07001523 (var->bits_per_pixel == 8) ) {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001524 /* Slave modes on LVDS and 301B-DH */
1525 refresh_rate = 60;
Richard Knutssonc30660ea2007-02-12 00:55:06 -08001526 recalc_clock = true;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001527 } else if( (ivideo->current_htotal == htotal) &&
1528 (ivideo->current_vtotal == vtotal) &&
1529 (ivideo->current_pixclock == pixclock) ) {
1530 /* x=x & y=y & c=c -> assume depth change */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001531 drate = 1000000000 / pixclock;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001532 hrate = (drate * 1000) / htotal;
1533 refresh_rate = (unsigned int) (hrate * 2 / vtotal);
1534 } else if( ( (ivideo->current_htotal != htotal) ||
1535 (ivideo->current_vtotal != vtotal) ) &&
1536 (ivideo->current_pixclock == var->pixclock) ) {
1537 /* x!=x | y!=y & c=c -> invalid pixclock */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001538 if(ivideo->sisfb_lastrates[sisbios_mode[search_idx].mode_no[ivideo->mni]]) {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001539 refresh_rate =
1540 ivideo->sisfb_lastrates[sisbios_mode[search_idx].mode_no[ivideo->mni]];
Linus Torvalds1da177e2005-04-16 15:20:36 -07001541 } else if(ivideo->sisfb_parm_rate != -1) {
1542 /* Sic, sisfb_parm_rate - want to know originally desired rate here */
1543 refresh_rate = ivideo->sisfb_parm_rate;
1544 } else {
1545 refresh_rate = 60;
1546 }
Richard Knutssonc30660ea2007-02-12 00:55:06 -08001547 recalc_clock = true;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001548 } else if((pixclock) && (htotal) && (vtotal)) {
1549 drate = 1000000000 / pixclock;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001550 hrate = (drate * 1000) / htotal;
1551 refresh_rate = (unsigned int) (hrate * 2 / vtotal);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001552 } else if(ivideo->current_refresh_rate) {
1553 refresh_rate = ivideo->current_refresh_rate;
Richard Knutssonc30660ea2007-02-12 00:55:06 -08001554 recalc_clock = true;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001555 } else {
1556 refresh_rate = 60;
Richard Knutssonc30660ea2007-02-12 00:55:06 -08001557 recalc_clock = true;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001558 }
1559
1560 myrateindex = sisfb_search_refresh_rate(ivideo, refresh_rate, search_idx);
1561
1562 /* Eventually recalculate timing and clock */
1563 if(recalc_clock) {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001564 if(!myrateindex) myrateindex = sisbios_mode[search_idx].rate_idx;
1565 var->pixclock = (u32) (1000000000 / sisfb_mode_rate_to_dclock(&ivideo->SiS_Pr,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001566 sisbios_mode[search_idx].mode_no[ivideo->mni],
1567 myrateindex));
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001568 sisfb_mode_rate_to_ddata(&ivideo->SiS_Pr,
1569 sisbios_mode[search_idx].mode_no[ivideo->mni],
1570 myrateindex, var);
1571 if((var->vmode & FB_VMODE_MASK) == FB_VMODE_DOUBLE) {
1572 var->pixclock <<= 1;
1573 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001574 }
1575
1576 if(ivideo->sisfb_thismonitor.datavalid) {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001577 if(!sisfb_verify_rate(ivideo, &ivideo->sisfb_thismonitor, search_idx,
1578 myrateindex, refresh_rate)) {
1579 printk(KERN_INFO
1580 "sisfb: WARNING: Refresh rate exceeds monitor specs!\n");
1581 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001582 }
1583
1584 /* Adapt RGB settings */
1585 sisfb_bpp_to_var(ivideo, var);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001586
Linus Torvalds1da177e2005-04-16 15:20:36 -07001587 /* Sanity check for offsets */
1588 if(var->xoffset < 0) var->xoffset = 0;
1589 if(var->yoffset < 0) var->yoffset = 0;
1590
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001591 if(var->xres > var->xres_virtual)
1592 var->xres_virtual = var->xres;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001593
1594 if(ivideo->sisfb_ypan) {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001595 maxyres = sisfb_calc_maxyres(ivideo, var);
1596 if(ivideo->sisfb_max) {
1597 var->yres_virtual = maxyres;
1598 } else {
1599 if(var->yres_virtual > maxyres) {
1600 var->yres_virtual = maxyres;
1601 }
1602 }
1603 if(var->yres_virtual <= var->yres) {
1604 var->yres_virtual = var->yres;
1605 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001606 } else {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001607 if(var->yres != var->yres_virtual) {
1608 var->yres_virtual = var->yres;
1609 }
1610 var->xoffset = 0;
1611 var->yoffset = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001612 }
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001613
Linus Torvalds1da177e2005-04-16 15:20:36 -07001614 /* Truncate offsets to maximum if too high */
1615 if(var->xoffset > var->xres_virtual - var->xres) {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001616 var->xoffset = var->xres_virtual - var->xres - 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001617 }
1618
1619 if(var->yoffset > var->yres_virtual - var->yres) {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001620 var->yoffset = var->yres_virtual - var->yres - 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001621 }
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001622
Linus Torvalds1da177e2005-04-16 15:20:36 -07001623 /* Set everything else to 0 */
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001624 var->red.msb_right =
1625 var->green.msb_right =
1626 var->blue.msb_right =
1627 var->transp.offset =
1628 var->transp.length =
1629 var->transp.msb_right = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001630
1631 return 0;
1632}
1633
1634static int
1635sisfb_pan_display(struct fb_var_screeninfo *var, struct fb_info* info)
1636{
1637 struct sis_video_info *ivideo = (struct sis_video_info *)info->par;
1638 int err;
1639
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001640 if(var->xoffset > (var->xres_virtual - var->xres))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001641 return -EINVAL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001642
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001643 if(var->yoffset > (var->yres_virtual - var->yres))
1644 return -EINVAL;
1645
1646 if(var->vmode & FB_VMODE_YWRAP)
1647 return -EINVAL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001648
1649 if(var->xoffset + info->var.xres > info->var.xres_virtual ||
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001650 var->yoffset + info->var.yres > info->var.yres_virtual)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001651 return -EINVAL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001652
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001653 if((err = sisfb_pan_var(ivideo, var)) < 0)
1654 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001655
1656 info->var.xoffset = var->xoffset;
1657 info->var.yoffset = var->yoffset;
1658
1659 return 0;
1660}
1661
1662static int
1663sisfb_blank(int blank, struct fb_info *info)
1664{
1665 struct sis_video_info *ivideo = (struct sis_video_info *)info->par;
1666
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001667 return sisfb_myblank(ivideo, blank);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001668}
1669
Linus Torvalds1da177e2005-04-16 15:20:36 -07001670/* ----------- FBDev related routines for all series ---------- */
1671
Christoph Hellwig67a66802006-01-14 13:21:25 -08001672#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,15)
1673static int sisfb_ioctl(struct fb_info *info, unsigned int cmd,
1674 unsigned long arg)
1675#else
1676static int sisfb_ioctl(struct inode *inode, struct file *file,
1677 unsigned int cmd, unsigned long arg,
1678 struct fb_info *info)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001679#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -07001680{
1681 struct sis_video_info *ivideo = (struct sis_video_info *)info->par;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001682 struct sis_memreq sismemreq;
1683 struct fb_vblank sisvbblank;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001684 u32 gpu32 = 0;
1685#ifndef __user
1686#define __user
1687#endif
1688 u32 __user *argp = (u32 __user *)arg;
1689
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001690 switch(cmd) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001691 case FBIO_ALLOC:
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001692 if(!capable(CAP_SYS_RAWIO))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001693 return -EPERM;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001694
1695 if(copy_from_user(&sismemreq, (void __user *)arg, sizeof(sismemreq)))
1696 return -EFAULT;
1697
Linus Torvalds1da177e2005-04-16 15:20:36 -07001698 sis_malloc(&sismemreq);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001699
Linus Torvalds1da177e2005-04-16 15:20:36 -07001700 if(copy_to_user((void __user *)arg, &sismemreq, sizeof(sismemreq))) {
1701 sis_free((u32)sismemreq.offset);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001702 return -EFAULT;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001703 }
1704 break;
1705
1706 case FBIO_FREE:
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001707 if(!capable(CAP_SYS_RAWIO))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001708 return -EPERM;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001709
1710 if(get_user(gpu32, argp))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001711 return -EFAULT;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001712
Linus Torvalds1da177e2005-04-16 15:20:36 -07001713 sis_free(gpu32);
1714 break;
1715
1716 case FBIOGET_VBLANK:
1717 sisvbblank.count = 0;
1718 sisvbblank.flags = sisfb_setupvbblankflags(ivideo, &sisvbblank.vcount, &sisvbblank.hcount);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001719
1720 if(copy_to_user((void __user *)arg, &sisvbblank, sizeof(sisvbblank)))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001721 return -EFAULT;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001722
Linus Torvalds1da177e2005-04-16 15:20:36 -07001723 break;
1724
1725 case SISFB_GET_INFO_SIZE:
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001726 return put_user(sizeof(struct sisfb_info), argp);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001727
1728 case SISFB_GET_INFO_OLD:
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001729 if(ivideo->warncount++ < 10)
1730 printk(KERN_INFO
1731 "sisfb: Deprecated ioctl call received - update your application!\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001732 case SISFB_GET_INFO: /* For communication with X driver */
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001733 ivideo->sisfb_infoblock.sisfb_id = SISFB_ID;
1734 ivideo->sisfb_infoblock.sisfb_version = VER_MAJOR;
1735 ivideo->sisfb_infoblock.sisfb_revision = VER_MINOR;
1736 ivideo->sisfb_infoblock.sisfb_patchlevel = VER_LEVEL;
1737 ivideo->sisfb_infoblock.chip_id = ivideo->chip_id;
1738 ivideo->sisfb_infoblock.sisfb_pci_vendor = ivideo->chip_vendor;
1739 ivideo->sisfb_infoblock.memory = ivideo->video_size / 1024;
1740 ivideo->sisfb_infoblock.heapstart = ivideo->heapstart / 1024;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001741 if(ivideo->modechanged) {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001742 ivideo->sisfb_infoblock.fbvidmode = ivideo->mode_no;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001743 } else {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001744 ivideo->sisfb_infoblock.fbvidmode = ivideo->modeprechange;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001745 }
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001746 ivideo->sisfb_infoblock.sisfb_caps = ivideo->caps;
1747 ivideo->sisfb_infoblock.sisfb_tqlen = ivideo->cmdQueueSize / 1024;
1748 ivideo->sisfb_infoblock.sisfb_pcibus = ivideo->pcibus;
1749 ivideo->sisfb_infoblock.sisfb_pcislot = ivideo->pcislot;
1750 ivideo->sisfb_infoblock.sisfb_pcifunc = ivideo->pcifunc;
1751 ivideo->sisfb_infoblock.sisfb_lcdpdc = ivideo->detectedpdc;
1752 ivideo->sisfb_infoblock.sisfb_lcdpdca = ivideo->detectedpdca;
1753 ivideo->sisfb_infoblock.sisfb_lcda = ivideo->detectedlcda;
1754 ivideo->sisfb_infoblock.sisfb_vbflags = ivideo->vbflags;
1755 ivideo->sisfb_infoblock.sisfb_currentvbflags = ivideo->currentvbflags;
1756 ivideo->sisfb_infoblock.sisfb_scalelcd = ivideo->SiS_Pr.UsePanelScaler;
1757 ivideo->sisfb_infoblock.sisfb_specialtiming = ivideo->SiS_Pr.SiS_CustomT;
1758 ivideo->sisfb_infoblock.sisfb_haveemi = ivideo->SiS_Pr.HaveEMI ? 1 : 0;
1759 ivideo->sisfb_infoblock.sisfb_haveemilcd = ivideo->SiS_Pr.HaveEMILCD ? 1 : 0;
1760 ivideo->sisfb_infoblock.sisfb_emi30 = ivideo->SiS_Pr.EMI_30;
1761 ivideo->sisfb_infoblock.sisfb_emi31 = ivideo->SiS_Pr.EMI_31;
1762 ivideo->sisfb_infoblock.sisfb_emi32 = ivideo->SiS_Pr.EMI_32;
1763 ivideo->sisfb_infoblock.sisfb_emi33 = ivideo->SiS_Pr.EMI_33;
1764 ivideo->sisfb_infoblock.sisfb_tvxpos = (u16)(ivideo->tvxpos + 32);
1765 ivideo->sisfb_infoblock.sisfb_tvypos = (u16)(ivideo->tvypos + 32);
1766 ivideo->sisfb_infoblock.sisfb_heapsize = ivideo->sisfb_heap_size / 1024;
1767 ivideo->sisfb_infoblock.sisfb_videooffset = ivideo->video_offset;
1768 ivideo->sisfb_infoblock.sisfb_curfstn = ivideo->curFSTN;
1769 ivideo->sisfb_infoblock.sisfb_curdstn = ivideo->curDSTN;
1770 ivideo->sisfb_infoblock.sisfb_vbflags2 = ivideo->vbflags2;
1771 ivideo->sisfb_infoblock.sisfb_can_post = ivideo->sisfb_can_post ? 1 : 0;
1772 ivideo->sisfb_infoblock.sisfb_card_posted = ivideo->sisfb_card_posted ? 1 : 0;
1773 ivideo->sisfb_infoblock.sisfb_was_boot_device = ivideo->sisfb_was_boot_device ? 1 : 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001774
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001775 if(copy_to_user((void __user *)arg, &ivideo->sisfb_infoblock,
1776 sizeof(ivideo->sisfb_infoblock)))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001777 return -EFAULT;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001778
Linus Torvalds1da177e2005-04-16 15:20:36 -07001779 break;
1780
1781 case SISFB_GET_VBRSTATUS_OLD:
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001782 if(ivideo->warncount++ < 10)
1783 printk(KERN_INFO
1784 "sisfb: Deprecated ioctl call received - update your application!\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001785 case SISFB_GET_VBRSTATUS:
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001786 if(sisfb_CheckVBRetrace(ivideo))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001787 return put_user((u32)1, argp);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001788 else
Linus Torvalds1da177e2005-04-16 15:20:36 -07001789 return put_user((u32)0, argp);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001790
1791 case SISFB_GET_AUTOMAXIMIZE_OLD:
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001792 if(ivideo->warncount++ < 10)
1793 printk(KERN_INFO
1794 "sisfb: Deprecated ioctl call received - update your application!\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001795 case SISFB_GET_AUTOMAXIMIZE:
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001796 if(ivideo->sisfb_max)
1797 return put_user((u32)1, argp);
1798 else
1799 return put_user((u32)0, argp);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001800
1801 case SISFB_SET_AUTOMAXIMIZE_OLD:
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001802 if(ivideo->warncount++ < 10)
1803 printk(KERN_INFO
1804 "sisfb: Deprecated ioctl call received - update your application!\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001805 case SISFB_SET_AUTOMAXIMIZE:
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001806 if(get_user(gpu32, argp))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001807 return -EFAULT;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001808
Linus Torvalds1da177e2005-04-16 15:20:36 -07001809 ivideo->sisfb_max = (gpu32) ? 1 : 0;
1810 break;
1811
1812 case SISFB_SET_TVPOSOFFSET:
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 sisfb_set_TVxposoffset(ivideo, ((int)(gpu32 >> 16)) - 32);
1817 sisfb_set_TVyposoffset(ivideo, ((int)(gpu32 & 0xffff)) - 32);
1818 break;
1819
1820 case SISFB_GET_TVPOSOFFSET:
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001821 return put_user((u32)(((ivideo->tvxpos+32)<<16)|((ivideo->tvypos+32)&0xffff)),
1822 argp);
1823
1824 case SISFB_COMMAND:
1825 if(copy_from_user(&ivideo->sisfb_command, (void __user *)arg,
1826 sizeof(struct sisfb_cmd)))
1827 return -EFAULT;
1828
1829 sisfb_handle_command(ivideo, &ivideo->sisfb_command);
1830
1831 if(copy_to_user((void __user *)arg, &ivideo->sisfb_command,
1832 sizeof(struct sisfb_cmd)))
1833 return -EFAULT;
1834
1835 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001836
1837 case SISFB_SET_LOCK:
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001838 if(get_user(gpu32, argp))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001839 return -EFAULT;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001840
Linus Torvalds1da177e2005-04-16 15:20:36 -07001841 ivideo->sisfblocked = (gpu32) ? 1 : 0;
1842 break;
1843
1844 default:
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001845#ifdef SIS_NEW_CONFIG_COMPAT
Linus Torvalds1da177e2005-04-16 15:20:36 -07001846 return -ENOIOCTLCMD;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001847#else
1848 return -EINVAL;
1849#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -07001850 }
1851 return 0;
1852}
1853
Linus Torvalds1da177e2005-04-16 15:20:36 -07001854static int
1855sisfb_get_fix(struct fb_fix_screeninfo *fix, int con, struct fb_info *info)
1856{
1857 struct sis_video_info *ivideo = (struct sis_video_info *)info->par;
1858
1859 memset(fix, 0, sizeof(struct fb_fix_screeninfo));
1860
1861 strcpy(fix->id, ivideo->myid);
1862
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001863 fix->smem_start = ivideo->video_base + ivideo->video_offset;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001864 fix->smem_len = ivideo->sisfb_mem;
1865 fix->type = FB_TYPE_PACKED_PIXELS;
1866 fix->type_aux = 0;
1867 fix->visual = (ivideo->video_bpp == 8) ? FB_VISUAL_PSEUDOCOLOR : FB_VISUAL_TRUECOLOR;
1868 fix->xpanstep = 1;
1869 fix->ypanstep = (ivideo->sisfb_ypan) ? 1 : 0;
1870 fix->ywrapstep = 0;
1871 fix->line_length = ivideo->video_linelength;
1872 fix->mmio_start = ivideo->mmio_base;
1873 fix->mmio_len = ivideo->mmio_size;
1874 if(ivideo->sisvga_engine == SIS_300_VGA) {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001875 fix->accel = FB_ACCEL_SIS_GLAMOUR;
1876 } else if((ivideo->chip == SIS_330) ||
1877 (ivideo->chip == SIS_760) ||
1878 (ivideo->chip == SIS_761)) {
1879 fix->accel = FB_ACCEL_SIS_XABRE;
1880 } else if(ivideo->chip == XGI_20) {
1881 fix->accel = FB_ACCEL_XGI_VOLARI_Z;
1882 } else if(ivideo->chip >= XGI_40) {
1883 fix->accel = FB_ACCEL_XGI_VOLARI_V;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001884 } else {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001885 fix->accel = FB_ACCEL_SIS_GLAMOUR_2;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001886 }
1887
1888 return 0;
1889}
1890
1891/* ---------------- fb_ops structures ----------------- */
1892
Linus Torvalds1da177e2005-04-16 15:20:36 -07001893static struct fb_ops sisfb_ops = {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001894 .owner = THIS_MODULE,
1895 .fb_open = sisfb_open,
1896 .fb_release = sisfb_release,
1897 .fb_check_var = sisfb_check_var,
1898 .fb_set_par = sisfb_set_par,
1899 .fb_setcolreg = sisfb_setcolreg,
1900 .fb_pan_display = sisfb_pan_display,
1901 .fb_blank = sisfb_blank,
1902 .fb_fillrect = fbcon_sis_fillrect,
1903 .fb_copyarea = fbcon_sis_copyarea,
1904 .fb_imageblit = cfb_imageblit,
Antonino A. Daplasc465e052005-11-07 01:00:35 -08001905#ifdef CONFIG_FB_SOFT_CURSOR
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001906 .fb_cursor = soft_cursor,
Antonino A. Daplasc465e052005-11-07 01:00:35 -08001907#endif
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001908 .fb_sync = fbcon_sis_sync,
1909#ifdef SIS_NEW_CONFIG_COMPAT
Christoph Hellwig67a66802006-01-14 13:21:25 -08001910 .fb_compat_ioctl= sisfb_ioctl,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001911#endif
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001912 .fb_ioctl = sisfb_ioctl
Linus Torvalds1da177e2005-04-16 15:20:36 -07001913};
Linus Torvalds1da177e2005-04-16 15:20:36 -07001914
1915/* ---------------- Chip generation dependent routines ---------------- */
1916
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001917static struct pci_dev * __devinit
1918sisfb_get_northbridge(int basechipid)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001919{
1920 struct pci_dev *pdev = NULL;
1921 int nbridgenum, nbridgeidx, i;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001922 static const unsigned short nbridgeids[] = {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001923 PCI_DEVICE_ID_SI_540, /* for SiS 540 VGA */
1924 PCI_DEVICE_ID_SI_630, /* for SiS 630/730 VGA */
1925 PCI_DEVICE_ID_SI_730,
1926 PCI_DEVICE_ID_SI_550, /* for SiS 550 VGA */
1927 PCI_DEVICE_ID_SI_650, /* for SiS 650/651/740 VGA */
1928 PCI_DEVICE_ID_SI_651,
1929 PCI_DEVICE_ID_SI_740,
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001930 PCI_DEVICE_ID_SI_661, /* for SiS 661/741/660/760/761 VGA */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001931 PCI_DEVICE_ID_SI_741,
1932 PCI_DEVICE_ID_SI_660,
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001933 PCI_DEVICE_ID_SI_760,
1934 PCI_DEVICE_ID_SI_761
Linus Torvalds1da177e2005-04-16 15:20:36 -07001935 };
1936
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001937 switch(basechipid) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001938#ifdef CONFIG_FB_SIS_300
1939 case SIS_540: nbridgeidx = 0; nbridgenum = 1; break;
1940 case SIS_630: nbridgeidx = 1; nbridgenum = 2; break;
1941#endif
1942#ifdef CONFIG_FB_SIS_315
1943 case SIS_550: nbridgeidx = 3; nbridgenum = 1; break;
1944 case SIS_650: nbridgeidx = 4; nbridgenum = 3; break;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001945 case SIS_660: nbridgeidx = 7; nbridgenum = 5; break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001946#endif
1947 default: return NULL;
1948 }
1949 for(i = 0; i < nbridgenum; i++) {
Adrian Bunk0959f0c2007-05-08 00:39:50 -07001950 if((pdev = pci_get_device(PCI_VENDOR_ID_SI,
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001951 nbridgeids[nbridgeidx+i], NULL)))
1952 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001953 }
1954 return pdev;
1955}
1956
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001957static int __devinit
1958sisfb_get_dram_size(struct sis_video_info *ivideo)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001959{
1960#if defined(CONFIG_FB_SIS_300) || defined(CONFIG_FB_SIS_315)
1961 u8 reg;
1962#endif
1963
1964 ivideo->video_size = 0;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001965 ivideo->UMAsize = ivideo->LFBsize = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001966
1967 switch(ivideo->chip) {
1968#ifdef CONFIG_FB_SIS_300
1969 case SIS_300:
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001970 inSISIDXREG(SISSR, 0x14, reg);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001971 ivideo->video_size = ((reg & 0x3F) + 1) << 20;
1972 break;
1973 case SIS_540:
1974 case SIS_630:
1975 case SIS_730:
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001976 if(!ivideo->nbridge)
1977 return -1;
1978 pci_read_config_byte(ivideo->nbridge, 0x63, &reg);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001979 ivideo->video_size = 1 << (((reg & 0x70) >> 4) + 21);
1980 break;
1981#endif
1982#ifdef CONFIG_FB_SIS_315
1983 case SIS_315H:
1984 case SIS_315PRO:
1985 case SIS_315:
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001986 inSISIDXREG(SISSR, 0x14, reg);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001987 ivideo->video_size = (1 << ((reg & 0xf0) >> 4)) << 20;
1988 switch((reg >> 2) & 0x03) {
1989 case 0x01:
1990 case 0x03:
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001991 ivideo->video_size <<= 1;
1992 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001993 case 0x02:
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001994 ivideo->video_size += (ivideo->video_size/2);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001995 }
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001996 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001997 case SIS_330:
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001998 inSISIDXREG(SISSR, 0x14, reg);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001999 ivideo->video_size = (1 << ((reg & 0xf0) >> 4)) << 20;
2000 if(reg & 0x0c) ivideo->video_size <<= 1;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07002001 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002002 case SIS_550:
2003 case SIS_650:
2004 case SIS_740:
Thomas Winischhofer544393f2005-09-09 13:04:45 -07002005 inSISIDXREG(SISSR, 0x14, reg);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002006 ivideo->video_size = (((reg & 0x3f) + 1) << 2) << 20;
2007 break;
2008 case SIS_661:
2009 case SIS_741:
Thomas Winischhofer544393f2005-09-09 13:04:45 -07002010 inSISIDXREG(SISCR, 0x79, reg);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002011 ivideo->video_size = (1 << ((reg & 0xf0) >> 4)) << 20;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07002012 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002013 case SIS_660:
2014 case SIS_760:
Thomas Winischhofer544393f2005-09-09 13:04:45 -07002015 case SIS_761:
Linus Torvalds1da177e2005-04-16 15:20:36 -07002016 inSISIDXREG(SISCR, 0x79, reg);
2017 reg = (reg & 0xf0) >> 4;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07002018 if(reg) {
2019 ivideo->video_size = (1 << reg) << 20;
2020 ivideo->UMAsize = ivideo->video_size;
2021 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002022 inSISIDXREG(SISCR, 0x78, reg);
2023 reg &= 0x30;
2024 if(reg) {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07002025 if(reg == 0x10) {
2026 ivideo->LFBsize = (32 << 20);
2027 } else {
2028 ivideo->LFBsize = (64 << 20);
2029 }
2030 ivideo->video_size += ivideo->LFBsize;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002031 }
Thomas Winischhofer544393f2005-09-09 13:04:45 -07002032 break;
2033 case SIS_340:
2034 case XGI_20:
2035 case XGI_40:
2036 inSISIDXREG(SISSR, 0x14, reg);
2037 ivideo->video_size = (1 << ((reg & 0xf0) >> 4)) << 20;
2038 if(ivideo->chip != XGI_20) {
2039 reg = (reg & 0x0c) >> 2;
2040 if(ivideo->revision_id == 2) {
2041 if(reg & 0x01) reg = 0x02;
2042 else reg = 0x00;
2043 }
2044 if(reg == 0x02) ivideo->video_size <<= 1;
2045 else if(reg == 0x03) ivideo->video_size <<= 2;
2046 }
2047 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002048#endif
2049 default:
2050 return -1;
2051 }
2052 return 0;
2053}
2054
2055/* -------------- video bridge device detection --------------- */
2056
Thomas Winischhofer544393f2005-09-09 13:04:45 -07002057static void __devinit
2058sisfb_detect_VB_connect(struct sis_video_info *ivideo)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002059{
2060 u8 cr32, temp;
2061
Thomas Winischhofer544393f2005-09-09 13:04:45 -07002062 /* No CRT2 on XGI Z7 */
2063 if(ivideo->chip == XGI_20) {
2064 ivideo->sisfb_crt1off = 0;
2065 return;
2066 }
2067
Linus Torvalds1da177e2005-04-16 15:20:36 -07002068#ifdef CONFIG_FB_SIS_300
2069 if(ivideo->sisvga_engine == SIS_300_VGA) {
2070 inSISIDXREG(SISSR, 0x17, temp);
2071 if((temp & 0x0F) && (ivideo->chip != SIS_300)) {
2072 /* PAL/NTSC is stored on SR16 on such machines */
2073 if(!(ivideo->vbflags & (TV_PAL | TV_NTSC | TV_PALM | TV_PALN))) {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07002074 inSISIDXREG(SISSR, 0x16, temp);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002075 if(temp & 0x20)
2076 ivideo->vbflags |= TV_PAL;
2077 else
2078 ivideo->vbflags |= TV_NTSC;
2079 }
2080 }
2081 }
2082#endif
2083
2084 inSISIDXREG(SISCR, 0x32, cr32);
2085
2086 if(cr32 & SIS_CRT1) {
2087 ivideo->sisfb_crt1off = 0;
2088 } else {
2089 ivideo->sisfb_crt1off = (cr32 & 0xDF) ? 1 : 0;
2090 }
2091
2092 ivideo->vbflags &= ~(CRT2_TV | CRT2_LCD | CRT2_VGA);
2093
2094 if(cr32 & SIS_VB_TV) ivideo->vbflags |= CRT2_TV;
2095 if(cr32 & SIS_VB_LCD) ivideo->vbflags |= CRT2_LCD;
2096 if(cr32 & SIS_VB_CRT2) ivideo->vbflags |= CRT2_VGA;
2097
2098 /* Check given parms for hardware compatibility.
2099 * (Cannot do this in the search_xx routines since we don't
2100 * know what hardware we are running on then)
2101 */
2102
2103 if(ivideo->chip != SIS_550) {
2104 ivideo->sisfb_dstn = ivideo->sisfb_fstn = 0;
2105 }
2106
2107 if(ivideo->sisfb_tvplug != -1) {
2108 if( (ivideo->sisvga_engine != SIS_315_VGA) ||
Thomas Winischhofer544393f2005-09-09 13:04:45 -07002109 (!(ivideo->vbflags2 & VB2_SISYPBPRBRIDGE)) ) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002110 if(ivideo->sisfb_tvplug & TV_YPBPR) {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07002111 ivideo->sisfb_tvplug = -1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002112 printk(KERN_ERR "sisfb: YPbPr not supported\n");
2113 }
2114 }
2115 }
2116 if(ivideo->sisfb_tvplug != -1) {
2117 if( (ivideo->sisvga_engine != SIS_315_VGA) ||
Thomas Winischhofer544393f2005-09-09 13:04:45 -07002118 (!(ivideo->vbflags2 & VB2_SISHIVISIONBRIDGE)) ) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002119 if(ivideo->sisfb_tvplug & TV_HIVISION) {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07002120 ivideo->sisfb_tvplug = -1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002121 printk(KERN_ERR "sisfb: HiVision not supported\n");
2122 }
2123 }
2124 }
2125 if(ivideo->sisfb_tvstd != -1) {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07002126 if( (!(ivideo->vbflags2 & VB2_SISBRIDGE)) &&
2127 (!((ivideo->sisvga_engine == SIS_315_VGA) &&
2128 (ivideo->vbflags2 & VB2_CHRONTEL))) ) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002129 if(ivideo->sisfb_tvstd & (TV_PALN | TV_PALN | TV_NTSCJ)) {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07002130 ivideo->sisfb_tvstd = -1;
2131 printk(KERN_ERR "sisfb: PALM/PALN/NTSCJ not supported\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002132 }
2133 }
2134 }
2135
2136 /* Detect/set TV plug & type */
2137 if(ivideo->sisfb_tvplug != -1) {
2138 ivideo->vbflags |= ivideo->sisfb_tvplug;
2139 } else {
2140 if(cr32 & SIS_VB_YPBPR) ivideo->vbflags |= (TV_YPBPR|TV_YPBPR525I); /* default: 480i */
2141 else if(cr32 & SIS_VB_HIVISION) ivideo->vbflags |= TV_HIVISION;
2142 else if(cr32 & SIS_VB_SCART) ivideo->vbflags |= TV_SCART;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07002143 else {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002144 if(cr32 & SIS_VB_SVIDEO) ivideo->vbflags |= TV_SVIDEO;
2145 if(cr32 & SIS_VB_COMPOSITE) ivideo->vbflags |= TV_AVIDEO;
2146 }
2147 }
2148
2149 if(!(ivideo->vbflags & (TV_YPBPR | TV_HIVISION))) {
2150 if(ivideo->sisfb_tvstd != -1) {
2151 ivideo->vbflags &= ~(TV_NTSC | TV_PAL | TV_PALM | TV_PALN | TV_NTSCJ);
2152 ivideo->vbflags |= ivideo->sisfb_tvstd;
2153 }
2154 if(ivideo->vbflags & TV_SCART) {
2155 ivideo->vbflags &= ~(TV_NTSC | TV_PALM | TV_PALN | TV_NTSCJ);
2156 ivideo->vbflags |= TV_PAL;
2157 }
2158 if(!(ivideo->vbflags & (TV_PAL | TV_NTSC | TV_PALM | TV_PALN | TV_NTSCJ))) {
2159 if(ivideo->sisvga_engine == SIS_300_VGA) {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07002160 inSISIDXREG(SISSR, 0x38, temp);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002161 if(temp & 0x01) ivideo->vbflags |= TV_PAL;
2162 else ivideo->vbflags |= TV_NTSC;
2163 } else if((ivideo->chip <= SIS_315PRO) || (ivideo->chip >= SIS_330)) {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07002164 inSISIDXREG(SISSR, 0x38, temp);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002165 if(temp & 0x01) ivideo->vbflags |= TV_PAL;
2166 else ivideo->vbflags |= TV_NTSC;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07002167 } else {
2168 inSISIDXREG(SISCR, 0x79, temp);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002169 if(temp & 0x20) ivideo->vbflags |= TV_PAL;
2170 else ivideo->vbflags |= TV_NTSC;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07002171 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002172 }
2173 }
2174
2175 /* Copy forceCRT1 option to CRT1off if option is given */
Thomas Winischhofer544393f2005-09-09 13:04:45 -07002176 if(ivideo->sisfb_forcecrt1 != -1) {
2177 ivideo->sisfb_crt1off = (ivideo->sisfb_forcecrt1) ? 0 : 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002178 }
2179}
2180
2181/* ------------------ Sensing routines ------------------ */
2182
Richard Knutssonc30660ea2007-02-12 00:55:06 -08002183static bool __devinit
Thomas Winischhofer544393f2005-09-09 13:04:45 -07002184sisfb_test_DDC1(struct sis_video_info *ivideo)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002185{
2186 unsigned short old;
2187 int count = 48;
2188
2189 old = SiS_ReadDDC1Bit(&ivideo->SiS_Pr);
2190 do {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07002191 if(old != SiS_ReadDDC1Bit(&ivideo->SiS_Pr)) break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002192 } while(count--);
Richard Knutssonc30660ea2007-02-12 00:55:06 -08002193 return (count != -1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002194}
2195
Thomas Winischhofer544393f2005-09-09 13:04:45 -07002196static void __devinit
2197sisfb_sense_crt1(struct sis_video_info *ivideo)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002198{
Richard Knutssonc30660ea2007-02-12 00:55:06 -08002199 bool mustwait = false;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002200 u8 sr1F, cr17;
2201#ifdef CONFIG_FB_SIS_315
2202 u8 cr63=0;
2203#endif
2204 u16 temp = 0xffff;
2205 int i;
2206
2207 inSISIDXREG(SISSR,0x1F,sr1F);
2208 orSISIDXREG(SISSR,0x1F,0x04);
2209 andSISIDXREG(SISSR,0x1F,0x3F);
Richard Knutssonc30660ea2007-02-12 00:55:06 -08002210 if(sr1F & 0xc0) mustwait = true;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002211
2212#ifdef CONFIG_FB_SIS_315
2213 if(ivideo->sisvga_engine == SIS_315_VGA) {
2214 inSISIDXREG(SISCR,ivideo->SiS_Pr.SiS_MyCR63,cr63);
2215 cr63 &= 0x40;
2216 andSISIDXREG(SISCR,ivideo->SiS_Pr.SiS_MyCR63,0xBF);
2217 }
2218#endif
2219
2220 inSISIDXREG(SISCR,0x17,cr17);
2221 cr17 &= 0x80;
2222 if(!cr17) {
2223 orSISIDXREG(SISCR,0x17,0x80);
Richard Knutssonc30660ea2007-02-12 00:55:06 -08002224 mustwait = true;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002225 outSISIDXREG(SISSR, 0x00, 0x01);
2226 outSISIDXREG(SISSR, 0x00, 0x03);
2227 }
2228
2229 if(mustwait) {
2230 for(i=0; i < 10; i++) sisfbwaitretracecrt1(ivideo);
2231 }
2232
2233#ifdef CONFIG_FB_SIS_315
2234 if(ivideo->chip >= SIS_330) {
2235 andSISIDXREG(SISCR,0x32,~0x20);
2236 if(ivideo->chip >= SIS_340) {
2237 outSISIDXREG(SISCR, 0x57, 0x4a);
2238 } else {
2239 outSISIDXREG(SISCR, 0x57, 0x5f);
2240 }
2241 orSISIDXREG(SISCR, 0x53, 0x02);
2242 while((inSISREG(SISINPSTAT)) & 0x01) break;
2243 while(!((inSISREG(SISINPSTAT)) & 0x01)) break;
2244 if((inSISREG(SISMISCW)) & 0x10) temp = 1;
2245 andSISIDXREG(SISCR, 0x53, 0xfd);
2246 andSISIDXREG(SISCR, 0x57, 0x00);
2247 }
2248#endif
2249
2250 if(temp == 0xffff) {
2251 i = 3;
2252 do {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07002253 temp = SiS_HandleDDC(&ivideo->SiS_Pr, ivideo->vbflags,
2254 ivideo->sisvga_engine, 0, 0, NULL, ivideo->vbflags2);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002255 } while(((temp == 0) || (temp == 0xffff)) && i--);
2256
2257 if((temp == 0) || (temp == 0xffff)) {
2258 if(sisfb_test_DDC1(ivideo)) temp = 1;
2259 }
2260 }
2261
2262 if((temp) && (temp != 0xffff)) {
2263 orSISIDXREG(SISCR,0x32,0x20);
2264 }
2265
2266#ifdef CONFIG_FB_SIS_315
2267 if(ivideo->sisvga_engine == SIS_315_VGA) {
2268 setSISIDXREG(SISCR,ivideo->SiS_Pr.SiS_MyCR63,0xBF,cr63);
2269 }
2270#endif
2271
2272 setSISIDXREG(SISCR,0x17,0x7F,cr17);
2273
2274 outSISIDXREG(SISSR,0x1F,sr1F);
2275}
2276
2277/* Determine and detect attached devices on SiS30x */
Thomas Winischhofer544393f2005-09-09 13:04:45 -07002278static void __devinit
2279SiS_SenseLCD(struct sis_video_info *ivideo)
2280{
2281 unsigned char buffer[256];
2282 unsigned short temp, realcrtno, i;
2283 u8 reg, cr37 = 0, paneltype = 0;
2284 u16 xres, yres;
2285
Richard Knutssonc30660ea2007-02-12 00:55:06 -08002286 ivideo->SiS_Pr.PanelSelfDetected = false;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07002287
2288 /* LCD detection only for TMDS bridges */
2289 if(!(ivideo->vbflags2 & VB2_SISTMDSBRIDGE))
2290 return;
2291 if(ivideo->vbflags2 & VB2_30xBDH)
2292 return;
2293
2294 /* If LCD already set up by BIOS, skip it */
2295 inSISIDXREG(SISCR, 0x32, reg);
2296 if(reg & 0x08)
2297 return;
2298
2299 realcrtno = 1;
2300 if(ivideo->SiS_Pr.DDCPortMixup)
2301 realcrtno = 0;
2302
2303 /* Check DDC capabilities */
2304 temp = SiS_HandleDDC(&ivideo->SiS_Pr, ivideo->vbflags, ivideo->sisvga_engine,
2305 realcrtno, 0, &buffer[0], ivideo->vbflags2);
2306
2307 if((!temp) || (temp == 0xffff) || (!(temp & 0x02)))
2308 return;
2309
2310 /* Read DDC data */
2311 i = 3; /* Number of retrys */
2312 do {
2313 temp = SiS_HandleDDC(&ivideo->SiS_Pr, ivideo->vbflags,
2314 ivideo->sisvga_engine, realcrtno, 1,
2315 &buffer[0], ivideo->vbflags2);
2316 } while((temp) && i--);
2317
2318 if(temp)
2319 return;
2320
2321 /* No digital device */
2322 if(!(buffer[0x14] & 0x80))
2323 return;
2324
2325 /* First detailed timing preferred timing? */
2326 if(!(buffer[0x18] & 0x02))
2327 return;
2328
2329 xres = buffer[0x38] | ((buffer[0x3a] & 0xf0) << 4);
2330 yres = buffer[0x3b] | ((buffer[0x3d] & 0xf0) << 4);
2331
2332 switch(xres) {
2333 case 1024:
2334 if(yres == 768)
2335 paneltype = 0x02;
2336 break;
2337 case 1280:
2338 if(yres == 1024)
2339 paneltype = 0x03;
2340 break;
2341 case 1600:
2342 if((yres == 1200) && (ivideo->vbflags2 & VB2_30xC))
2343 paneltype = 0x0b;
2344 break;
2345 }
2346
2347 if(!paneltype)
2348 return;
2349
2350 if(buffer[0x23])
2351 cr37 |= 0x10;
2352
2353 if((buffer[0x47] & 0x18) == 0x18)
2354 cr37 |= ((((buffer[0x47] & 0x06) ^ 0x06) << 5) | 0x20);
2355 else
2356 cr37 |= 0xc0;
2357
2358 outSISIDXREG(SISCR, 0x36, paneltype);
2359 cr37 &= 0xf1;
2360 setSISIDXREG(SISCR, 0x37, 0x0c, cr37);
2361 orSISIDXREG(SISCR, 0x32, 0x08);
2362
Richard Knutssonc30660ea2007-02-12 00:55:06 -08002363 ivideo->SiS_Pr.PanelSelfDetected = true;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07002364}
2365
2366static int __devinit
2367SISDoSense(struct sis_video_info *ivideo, u16 type, u16 test)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002368{
2369 int temp, mytest, result, i, j;
2370
2371 for(j = 0; j < 10; j++) {
2372 result = 0;
2373 for(i = 0; i < 3; i++) {
2374 mytest = test;
2375 outSISIDXREG(SISPART4,0x11,(type & 0x00ff));
2376 temp = (type >> 8) | (mytest & 0x00ff);
2377 setSISIDXREG(SISPART4,0x10,0xe0,temp);
2378 SiS_DDC2Delay(&ivideo->SiS_Pr, 0x1500);
2379 mytest >>= 8;
2380 mytest &= 0x7f;
2381 inSISIDXREG(SISPART4,0x03,temp);
2382 temp ^= 0x0e;
2383 temp &= mytest;
2384 if(temp == mytest) result++;
2385#if 1
2386 outSISIDXREG(SISPART4,0x11,0x00);
2387 andSISIDXREG(SISPART4,0x10,0xe0);
2388 SiS_DDC2Delay(&ivideo->SiS_Pr, 0x1000);
2389#endif
2390 }
2391 if((result == 0) || (result >= 2)) break;
2392 }
Thomas Winischhofer544393f2005-09-09 13:04:45 -07002393 return result;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002394}
2395
Thomas Winischhofer544393f2005-09-09 13:04:45 -07002396static void __devinit
2397SiS_Sense30x(struct sis_video_info *ivideo)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002398{
2399 u8 backupP4_0d,backupP2_00,backupP2_4d,backupSR_1e,biosflag=0;
2400 u16 svhs=0, svhs_c=0;
2401 u16 cvbs=0, cvbs_c=0;
2402 u16 vga2=0, vga2_c=0;
2403 int myflag, result;
2404 char stdstr[] = "sisfb: Detected";
2405 char tvstr[] = "TV connected to";
2406
Thomas Winischhofer544393f2005-09-09 13:04:45 -07002407 if(ivideo->vbflags2 & VB2_301) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002408 svhs = 0x00b9; cvbs = 0x00b3; vga2 = 0x00d1;
2409 inSISIDXREG(SISPART4,0x01,myflag);
2410 if(myflag & 0x04) {
2411 svhs = 0x00dd; cvbs = 0x00ee; vga2 = 0x00fd;
2412 }
Thomas Winischhofer544393f2005-09-09 13:04:45 -07002413 } else if(ivideo->vbflags2 & (VB2_301B | VB2_302B)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002414 svhs = 0x016b; cvbs = 0x0174; vga2 = 0x0190;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07002415 } else if(ivideo->vbflags2 & (VB2_301LV | VB2_302LV)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002416 svhs = 0x0200; cvbs = 0x0100;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07002417 } else if(ivideo->vbflags2 & (VB2_301C | VB2_302ELV | VB2_307T | VB2_307LV)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002418 svhs = 0x016b; cvbs = 0x0110; vga2 = 0x0190;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07002419 } else
2420 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002421
2422 vga2_c = 0x0e08; svhs_c = 0x0404; cvbs_c = 0x0804;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07002423 if(ivideo->vbflags & (VB2_301LV|VB2_302LV|VB2_302ELV|VB2_307LV)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002424 svhs_c = 0x0408; cvbs_c = 0x0808;
2425 }
Thomas Winischhofer544393f2005-09-09 13:04:45 -07002426
Linus Torvalds1da177e2005-04-16 15:20:36 -07002427 biosflag = 2;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07002428 if(ivideo->haveXGIROM) {
2429 biosflag = ivideo->bios_abase[0x58] & 0x03;
2430 } else if(ivideo->newrom) {
2431 if(ivideo->bios_abase[0x5d] & 0x04) biosflag |= 0x01;
2432 } else if(ivideo->sisvga_engine == SIS_300_VGA) {
2433 if(ivideo->bios_abase) {
2434 biosflag = ivideo->bios_abase[0xfe] & 0x03;
2435 }
2436 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002437
2438 if(ivideo->chip == SIS_300) {
2439 inSISIDXREG(SISSR,0x3b,myflag);
2440 if(!(myflag & 0x01)) vga2 = vga2_c = 0;
2441 }
2442
Thomas Winischhofer544393f2005-09-09 13:04:45 -07002443 if(!(ivideo->vbflags2 & VB2_SISVGA2BRIDGE)) {
2444 vga2 = vga2_c = 0;
2445 }
2446
Linus Torvalds1da177e2005-04-16 15:20:36 -07002447 inSISIDXREG(SISSR,0x1e,backupSR_1e);
2448 orSISIDXREG(SISSR,0x1e,0x20);
2449
2450 inSISIDXREG(SISPART4,0x0d,backupP4_0d);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07002451 if(ivideo->vbflags2 & VB2_30xC) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002452 setSISIDXREG(SISPART4,0x0d,~0x07,0x01);
2453 } else {
2454 orSISIDXREG(SISPART4,0x0d,0x04);
2455 }
2456 SiS_DDC2Delay(&ivideo->SiS_Pr, 0x2000);
2457
2458 inSISIDXREG(SISPART2,0x00,backupP2_00);
2459 outSISIDXREG(SISPART2,0x00,((backupP2_00 | 0x1c) & 0xfc));
2460
2461 inSISIDXREG(SISPART2,0x4d,backupP2_4d);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07002462 if(ivideo->vbflags2 & VB2_SISYPBPRBRIDGE) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002463 outSISIDXREG(SISPART2,0x4d,(backupP2_4d & ~0x10));
2464 }
2465
Thomas Winischhofer544393f2005-09-09 13:04:45 -07002466 if(!(ivideo->vbflags2 & VB2_30xCLV)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002467 SISDoSense(ivideo, 0, 0);
2468 }
2469
2470 andSISIDXREG(SISCR, 0x32, ~0x14);
2471
2472 if(vga2_c || vga2) {
2473 if(SISDoSense(ivideo, vga2, vga2_c)) {
2474 if(biosflag & 0x01) {
2475 printk(KERN_INFO "%s %s SCART output\n", stdstr, tvstr);
2476 orSISIDXREG(SISCR, 0x32, 0x04);
2477 } else {
2478 printk(KERN_INFO "%s secondary VGA connection\n", stdstr);
2479 orSISIDXREG(SISCR, 0x32, 0x10);
2480 }
2481 }
2482 }
2483
2484 andSISIDXREG(SISCR, 0x32, 0x3f);
2485
Thomas Winischhofer544393f2005-09-09 13:04:45 -07002486 if(ivideo->vbflags2 & VB2_30xCLV) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002487 orSISIDXREG(SISPART4,0x0d,0x04);
2488 }
2489
Thomas Winischhofer544393f2005-09-09 13:04:45 -07002490 if((ivideo->sisvga_engine == SIS_315_VGA) && (ivideo->vbflags2 & VB2_SISYPBPRBRIDGE)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002491 outSISIDXREG(SISPART2,0x4d,(backupP2_4d | 0x10));
2492 SiS_DDC2Delay(&ivideo->SiS_Pr, 0x2000);
2493 if((result = SISDoSense(ivideo, svhs, 0x0604))) {
2494 if((result = SISDoSense(ivideo, cvbs, 0x0804))) {
2495 printk(KERN_INFO "%s %s YPbPr component output\n", stdstr, tvstr);
2496 orSISIDXREG(SISCR,0x32,0x80);
2497 }
2498 }
2499 outSISIDXREG(SISPART2,0x4d,backupP2_4d);
2500 }
2501
2502 andSISIDXREG(SISCR, 0x32, ~0x03);
2503
2504 if(!(ivideo->vbflags & TV_YPBPR)) {
2505 if((result = SISDoSense(ivideo, svhs, svhs_c))) {
2506 printk(KERN_INFO "%s %s SVIDEO output\n", stdstr, tvstr);
2507 orSISIDXREG(SISCR, 0x32, 0x02);
2508 }
2509 if((biosflag & 0x02) || (!result)) {
2510 if(SISDoSense(ivideo, cvbs, cvbs_c)) {
2511 printk(KERN_INFO "%s %s COMPOSITE output\n", stdstr, tvstr);
2512 orSISIDXREG(SISCR, 0x32, 0x01);
2513 }
2514 }
2515 }
2516
2517 SISDoSense(ivideo, 0, 0);
2518
2519 outSISIDXREG(SISPART2,0x00,backupP2_00);
2520 outSISIDXREG(SISPART4,0x0d,backupP4_0d);
2521 outSISIDXREG(SISSR,0x1e,backupSR_1e);
2522
Thomas Winischhofer544393f2005-09-09 13:04:45 -07002523 if(ivideo->vbflags2 & VB2_30xCLV) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002524 inSISIDXREG(SISPART2,0x00,biosflag);
2525 if(biosflag & 0x20) {
2526 for(myflag = 2; myflag > 0; myflag--) {
2527 biosflag ^= 0x20;
2528 outSISIDXREG(SISPART2,0x00,biosflag);
2529 }
2530 }
2531 }
2532
2533 outSISIDXREG(SISPART2,0x00,backupP2_00);
2534}
2535
2536/* Determine and detect attached TV's on Chrontel */
Thomas Winischhofer544393f2005-09-09 13:04:45 -07002537static void __devinit
2538SiS_SenseCh(struct sis_video_info *ivideo)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002539{
2540#if defined(CONFIG_FB_SIS_300) || defined(CONFIG_FB_SIS_315)
2541 u8 temp1, temp2;
2542 char stdstr[] = "sisfb: Chrontel: Detected TV connected to";
2543#endif
2544#ifdef CONFIG_FB_SIS_300
2545 unsigned char test[3];
2546 int i;
2547#endif
2548
2549 if(ivideo->chip < SIS_315H) {
2550
2551#ifdef CONFIG_FB_SIS_300
2552 ivideo->SiS_Pr.SiS_IF_DEF_CH70xx = 1; /* Chrontel 700x */
2553 SiS_SetChrontelGPIO(&ivideo->SiS_Pr, 0x9c); /* Set general purpose IO for Chrontel communication */
2554 SiS_DDC2Delay(&ivideo->SiS_Pr, 1000);
2555 temp1 = SiS_GetCH700x(&ivideo->SiS_Pr, 0x25);
2556 /* See Chrontel TB31 for explanation */
2557 temp2 = SiS_GetCH700x(&ivideo->SiS_Pr, 0x0e);
2558 if(((temp2 & 0x07) == 0x01) || (temp2 & 0x04)) {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07002559 SiS_SetCH700x(&ivideo->SiS_Pr, 0x0e, 0x0b);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002560 SiS_DDC2Delay(&ivideo->SiS_Pr, 300);
2561 }
2562 temp2 = SiS_GetCH700x(&ivideo->SiS_Pr, 0x25);
2563 if(temp2 != temp1) temp1 = temp2;
2564
2565 if((temp1 >= 0x22) && (temp1 <= 0x50)) {
2566 /* Read power status */
2567 temp1 = SiS_GetCH700x(&ivideo->SiS_Pr, 0x0e);
2568 if((temp1 & 0x03) != 0x03) {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07002569 /* Power all outputs */
2570 SiS_SetCH700x(&ivideo->SiS_Pr, 0x0e,0x0b);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002571 SiS_DDC2Delay(&ivideo->SiS_Pr, 300);
2572 }
2573 /* Sense connected TV devices */
2574 for(i = 0; i < 3; i++) {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07002575 SiS_SetCH700x(&ivideo->SiS_Pr, 0x10, 0x01);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002576 SiS_DDC2Delay(&ivideo->SiS_Pr, 0x96);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07002577 SiS_SetCH700x(&ivideo->SiS_Pr, 0x10, 0x00);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002578 SiS_DDC2Delay(&ivideo->SiS_Pr, 0x96);
2579 temp1 = SiS_GetCH700x(&ivideo->SiS_Pr, 0x10);
2580 if(!(temp1 & 0x08)) test[i] = 0x02;
2581 else if(!(temp1 & 0x02)) test[i] = 0x01;
2582 else test[i] = 0;
2583 SiS_DDC2Delay(&ivideo->SiS_Pr, 0x96);
2584 }
2585
2586 if(test[0] == test[1]) temp1 = test[0];
2587 else if(test[0] == test[2]) temp1 = test[0];
2588 else if(test[1] == test[2]) temp1 = test[1];
2589 else {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07002590 printk(KERN_INFO
Linus Torvalds1da177e2005-04-16 15:20:36 -07002591 "sisfb: TV detection unreliable - test results varied\n");
2592 temp1 = test[2];
2593 }
2594 if(temp1 == 0x02) {
2595 printk(KERN_INFO "%s SVIDEO output\n", stdstr);
2596 ivideo->vbflags |= TV_SVIDEO;
2597 orSISIDXREG(SISCR, 0x32, 0x02);
2598 andSISIDXREG(SISCR, 0x32, ~0x05);
2599 } else if (temp1 == 0x01) {
2600 printk(KERN_INFO "%s CVBS output\n", stdstr);
2601 ivideo->vbflags |= TV_AVIDEO;
2602 orSISIDXREG(SISCR, 0x32, 0x01);
2603 andSISIDXREG(SISCR, 0x32, ~0x06);
2604 } else {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07002605 SiS_SetCH70xxANDOR(&ivideo->SiS_Pr, 0x0e, 0x01, 0xF8);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002606 andSISIDXREG(SISCR, 0x32, ~0x07);
2607 }
2608 } else if(temp1 == 0) {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07002609 SiS_SetCH70xxANDOR(&ivideo->SiS_Pr, 0x0e, 0x01, 0xF8);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002610 andSISIDXREG(SISCR, 0x32, ~0x07);
2611 }
2612 /* Set general purpose IO for Chrontel communication */
2613 SiS_SetChrontelGPIO(&ivideo->SiS_Pr, 0x00);
2614#endif
2615
2616 } else {
2617
2618#ifdef CONFIG_FB_SIS_315
2619 ivideo->SiS_Pr.SiS_IF_DEF_CH70xx = 2; /* Chrontel 7019 */
Thomas Winischhofer544393f2005-09-09 13:04:45 -07002620 temp1 = SiS_GetCH701x(&ivideo->SiS_Pr, 0x49);
2621 SiS_SetCH701x(&ivideo->SiS_Pr, 0x49, 0x20);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002622 SiS_DDC2Delay(&ivideo->SiS_Pr, 0x96);
2623 temp2 = SiS_GetCH701x(&ivideo->SiS_Pr, 0x20);
2624 temp2 |= 0x01;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07002625 SiS_SetCH701x(&ivideo->SiS_Pr, 0x20, temp2);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002626 SiS_DDC2Delay(&ivideo->SiS_Pr, 0x96);
2627 temp2 ^= 0x01;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07002628 SiS_SetCH701x(&ivideo->SiS_Pr, 0x20, temp2);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002629 SiS_DDC2Delay(&ivideo->SiS_Pr, 0x96);
2630 temp2 = SiS_GetCH701x(&ivideo->SiS_Pr, 0x20);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07002631 SiS_SetCH701x(&ivideo->SiS_Pr, 0x49, temp1);
2632 temp1 = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002633 if(temp2 & 0x02) temp1 |= 0x01;
2634 if(temp2 & 0x10) temp1 |= 0x01;
2635 if(temp2 & 0x04) temp1 |= 0x02;
2636 if( (temp1 & 0x01) && (temp1 & 0x02) ) temp1 = 0x04;
2637 switch(temp1) {
2638 case 0x01:
2639 printk(KERN_INFO "%s CVBS output\n", stdstr);
2640 ivideo->vbflags |= TV_AVIDEO;
2641 orSISIDXREG(SISCR, 0x32, 0x01);
2642 andSISIDXREG(SISCR, 0x32, ~0x06);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07002643 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002644 case 0x02:
2645 printk(KERN_INFO "%s SVIDEO output\n", stdstr);
2646 ivideo->vbflags |= TV_SVIDEO;
2647 orSISIDXREG(SISCR, 0x32, 0x02);
2648 andSISIDXREG(SISCR, 0x32, ~0x05);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07002649 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002650 case 0x04:
2651 printk(KERN_INFO "%s SCART output\n", stdstr);
2652 orSISIDXREG(SISCR, 0x32, 0x04);
2653 andSISIDXREG(SISCR, 0x32, ~0x03);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07002654 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002655 default:
2656 andSISIDXREG(SISCR, 0x32, ~0x07);
2657 }
2658#endif
2659 }
2660}
2661
Thomas Winischhofer544393f2005-09-09 13:04:45 -07002662static void __devinit
2663sisfb_get_VB_type(struct sis_video_info *ivideo)
2664{
2665 char stdstr[] = "sisfb: Detected";
2666 char bridgestr[] = "video bridge";
2667 u8 vb_chipid;
2668 u8 reg;
2669
2670 /* No CRT2 on XGI Z7 */
2671 if(ivideo->chip == XGI_20)
2672 return;
2673
2674 inSISIDXREG(SISPART4, 0x00, vb_chipid);
2675 switch(vb_chipid) {
2676 case 0x01:
2677 inSISIDXREG(SISPART4, 0x01, reg);
2678 if(reg < 0xb0) {
2679 ivideo->vbflags |= VB_301; /* Deprecated */
2680 ivideo->vbflags2 |= VB2_301;
2681 printk(KERN_INFO "%s SiS301 %s\n", stdstr, bridgestr);
2682 } else if(reg < 0xc0) {
2683 ivideo->vbflags |= VB_301B; /* Deprecated */
2684 ivideo->vbflags2 |= VB2_301B;
2685 inSISIDXREG(SISPART4,0x23,reg);
2686 if(!(reg & 0x02)) {
2687 ivideo->vbflags |= VB_30xBDH; /* Deprecated */
2688 ivideo->vbflags2 |= VB2_30xBDH;
2689 printk(KERN_INFO "%s SiS301B-DH %s\n", stdstr, bridgestr);
2690 } else {
2691 printk(KERN_INFO "%s SiS301B %s\n", stdstr, bridgestr);
2692 }
2693 } else if(reg < 0xd0) {
2694 ivideo->vbflags |= VB_301C; /* Deprecated */
2695 ivideo->vbflags2 |= VB2_301C;
2696 printk(KERN_INFO "%s SiS301C %s\n", stdstr, bridgestr);
2697 } else if(reg < 0xe0) {
2698 ivideo->vbflags |= VB_301LV; /* Deprecated */
2699 ivideo->vbflags2 |= VB2_301LV;
2700 printk(KERN_INFO "%s SiS301LV %s\n", stdstr, bridgestr);
2701 } else if(reg <= 0xe1) {
2702 inSISIDXREG(SISPART4,0x39,reg);
2703 if(reg == 0xff) {
2704 ivideo->vbflags |= VB_302LV; /* Deprecated */
2705 ivideo->vbflags2 |= VB2_302LV;
2706 printk(KERN_INFO "%s SiS302LV %s\n", stdstr, bridgestr);
2707 } else {
2708 ivideo->vbflags |= VB_301C; /* Deprecated */
2709 ivideo->vbflags2 |= VB2_301C;
2710 printk(KERN_INFO "%s SiS301C(P4) %s\n", stdstr, bridgestr);
2711#if 0
2712 ivideo->vbflags |= VB_302ELV; /* Deprecated */
2713 ivideo->vbflags2 |= VB2_302ELV;
2714 printk(KERN_INFO "%s SiS302ELV %s\n", stdstr, bridgestr);
2715#endif
2716 }
2717 }
2718 break;
2719 case 0x02:
2720 ivideo->vbflags |= VB_302B; /* Deprecated */
2721 ivideo->vbflags2 |= VB2_302B;
2722 printk(KERN_INFO "%s SiS302B %s\n", stdstr, bridgestr);
2723 break;
2724 }
2725
2726 if((!(ivideo->vbflags2 & VB2_VIDEOBRIDGE)) && (ivideo->chip != SIS_300)) {
2727 inSISIDXREG(SISCR, 0x37, reg);
2728 reg &= SIS_EXTERNAL_CHIP_MASK;
2729 reg >>= 1;
2730 if(ivideo->sisvga_engine == SIS_300_VGA) {
2731#ifdef CONFIG_FB_SIS_300
2732 switch(reg) {
2733 case SIS_EXTERNAL_CHIP_LVDS:
2734 ivideo->vbflags |= VB_LVDS; /* Deprecated */
2735 ivideo->vbflags2 |= VB2_LVDS;
2736 break;
2737 case SIS_EXTERNAL_CHIP_TRUMPION:
2738 ivideo->vbflags |= (VB_LVDS | VB_TRUMPION); /* Deprecated */
2739 ivideo->vbflags2 |= (VB2_LVDS | VB2_TRUMPION);
2740 break;
2741 case SIS_EXTERNAL_CHIP_CHRONTEL:
2742 ivideo->vbflags |= VB_CHRONTEL; /* Deprecated */
2743 ivideo->vbflags2 |= VB2_CHRONTEL;
2744 break;
2745 case SIS_EXTERNAL_CHIP_LVDS_CHRONTEL:
2746 ivideo->vbflags |= (VB_LVDS | VB_CHRONTEL); /* Deprecated */
2747 ivideo->vbflags2 |= (VB2_LVDS | VB2_CHRONTEL);
2748 break;
2749 }
2750 if(ivideo->vbflags2 & VB2_CHRONTEL) ivideo->chronteltype = 1;
2751#endif
2752 } else if(ivideo->chip < SIS_661) {
2753#ifdef CONFIG_FB_SIS_315
2754 switch (reg) {
2755 case SIS310_EXTERNAL_CHIP_LVDS:
2756 ivideo->vbflags |= VB_LVDS; /* Deprecated */
2757 ivideo->vbflags2 |= VB2_LVDS;
2758 break;
2759 case SIS310_EXTERNAL_CHIP_LVDS_CHRONTEL:
2760 ivideo->vbflags |= (VB_LVDS | VB_CHRONTEL); /* Deprecated */
2761 ivideo->vbflags2 |= (VB2_LVDS | VB2_CHRONTEL);
2762 break;
2763 }
2764 if(ivideo->vbflags2 & VB2_CHRONTEL) ivideo->chronteltype = 2;
2765#endif
2766 } else if(ivideo->chip >= SIS_661) {
2767#ifdef CONFIG_FB_SIS_315
2768 inSISIDXREG(SISCR, 0x38, reg);
2769 reg >>= 5;
2770 switch(reg) {
2771 case 0x02:
2772 ivideo->vbflags |= VB_LVDS; /* Deprecated */
2773 ivideo->vbflags2 |= VB2_LVDS;
2774 break;
2775 case 0x03:
2776 ivideo->vbflags |= (VB_LVDS | VB_CHRONTEL); /* Deprecated */
2777 ivideo->vbflags2 |= (VB2_LVDS | VB2_CHRONTEL);
2778 break;
2779 case 0x04:
2780 ivideo->vbflags |= (VB_LVDS | VB_CONEXANT); /* Deprecated */
2781 ivideo->vbflags2 |= (VB2_LVDS | VB2_CONEXANT);
2782 break;
2783 }
2784 if(ivideo->vbflags2 & VB2_CHRONTEL) ivideo->chronteltype = 2;
2785#endif
2786 }
2787 if(ivideo->vbflags2 & VB2_LVDS) {
2788 printk(KERN_INFO "%s LVDS transmitter\n", stdstr);
2789 }
2790 if((ivideo->sisvga_engine == SIS_300_VGA) && (ivideo->vbflags2 & VB2_TRUMPION)) {
2791 printk(KERN_INFO "%s Trumpion Zurac LCD scaler\n", stdstr);
2792 }
2793 if(ivideo->vbflags2 & VB2_CHRONTEL) {
2794 printk(KERN_INFO "%s Chrontel TV encoder\n", stdstr);
2795 }
2796 if((ivideo->chip >= SIS_661) && (ivideo->vbflags2 & VB2_CONEXANT)) {
2797 printk(KERN_INFO "%s Conexant external device\n", stdstr);
2798 }
2799 }
2800
2801 if(ivideo->vbflags2 & VB2_SISBRIDGE) {
2802 SiS_SenseLCD(ivideo);
2803 SiS_Sense30x(ivideo);
2804 } else if(ivideo->vbflags2 & VB2_CHRONTEL) {
2805 SiS_SenseCh(ivideo);
2806 }
2807}
2808
2809/* ---------- Engine initialization routines ------------ */
2810
2811static void
2812sisfb_engine_init(struct sis_video_info *ivideo)
2813{
2814
2815 /* Initialize command queue (we use MMIO only) */
2816
2817 /* BEFORE THIS IS CALLED, THE ENGINES *MUST* BE SYNC'ED */
2818
2819 ivideo->caps &= ~(TURBO_QUEUE_CAP |
2820 MMIO_CMD_QUEUE_CAP |
2821 VM_CMD_QUEUE_CAP |
2822 AGP_CMD_QUEUE_CAP);
2823
2824#ifdef CONFIG_FB_SIS_300
2825 if(ivideo->sisvga_engine == SIS_300_VGA) {
2826 u32 tqueue_pos;
2827 u8 tq_state;
2828
2829 tqueue_pos = (ivideo->video_size - ivideo->cmdQueueSize) / (64 * 1024);
2830
2831 inSISIDXREG(SISSR, IND_SIS_TURBOQUEUE_SET, tq_state);
2832 tq_state |= 0xf0;
2833 tq_state &= 0xfc;
2834 tq_state |= (u8)(tqueue_pos >> 8);
2835 outSISIDXREG(SISSR, IND_SIS_TURBOQUEUE_SET, tq_state);
2836
2837 outSISIDXREG(SISSR, IND_SIS_TURBOQUEUE_ADR, (u8)(tqueue_pos & 0xff));
2838
2839 ivideo->caps |= TURBO_QUEUE_CAP;
2840 }
2841#endif
2842
2843#ifdef CONFIG_FB_SIS_315
2844 if(ivideo->sisvga_engine == SIS_315_VGA) {
2845 u32 tempq = 0, templ;
2846 u8 temp;
2847
2848 if(ivideo->chip == XGI_20) {
2849 switch(ivideo->cmdQueueSize) {
2850 case (64 * 1024):
2851 temp = SIS_CMD_QUEUE_SIZE_Z7_64k;
2852 break;
2853 case (128 * 1024):
2854 default:
2855 temp = SIS_CMD_QUEUE_SIZE_Z7_128k;
2856 }
2857 } else {
2858 switch(ivideo->cmdQueueSize) {
2859 case (4 * 1024 * 1024):
2860 temp = SIS_CMD_QUEUE_SIZE_4M;
2861 break;
2862 case (2 * 1024 * 1024):
2863 temp = SIS_CMD_QUEUE_SIZE_2M;
2864 break;
2865 case (1 * 1024 * 1024):
2866 temp = SIS_CMD_QUEUE_SIZE_1M;
2867 break;
2868 default:
2869 case (512 * 1024):
2870 temp = SIS_CMD_QUEUE_SIZE_512k;
2871 }
2872 }
2873
2874 outSISIDXREG(SISSR, IND_SIS_CMDQUEUE_THRESHOLD, COMMAND_QUEUE_THRESHOLD);
2875 outSISIDXREG(SISSR, IND_SIS_CMDQUEUE_SET, SIS_CMD_QUEUE_RESET);
2876
2877 if((ivideo->chip >= XGI_40) && ivideo->modechanged) {
2878 /* Must disable dual pipe on XGI_40. Can't do
2879 * this in MMIO mode, because it requires
2880 * setting/clearing a bit in the MMIO fire trigger
2881 * register.
2882 */
2883 if(!((templ = MMIO_IN32(ivideo->mmio_vbase, 0x8240)) & (1 << 10))) {
2884
2885 MMIO_OUT32(ivideo->mmio_vbase, Q_WRITE_PTR, 0);
2886
2887 outSISIDXREG(SISSR, IND_SIS_CMDQUEUE_SET, (temp | SIS_VRAM_CMDQUEUE_ENABLE));
2888
2889 tempq = MMIO_IN32(ivideo->mmio_vbase, Q_READ_PTR);
2890 MMIO_OUT32(ivideo->mmio_vbase, Q_WRITE_PTR, tempq);
2891
2892 tempq = (u32)(ivideo->video_size - ivideo->cmdQueueSize);
2893 MMIO_OUT32(ivideo->mmio_vbase, Q_BASE_ADDR, tempq);
2894
2895 writel(0x16800000 + 0x8240, ivideo->video_vbase + tempq);
2896 writel(templ | (1 << 10), ivideo->video_vbase + tempq + 4);
2897 writel(0x168F0000, ivideo->video_vbase + tempq + 8);
2898 writel(0x168F0000, ivideo->video_vbase + tempq + 12);
2899
2900 MMIO_OUT32(ivideo->mmio_vbase, Q_WRITE_PTR, (tempq + 16));
2901
2902 sisfb_syncaccel(ivideo);
2903
2904 outSISIDXREG(SISSR, IND_SIS_CMDQUEUE_SET, SIS_CMD_QUEUE_RESET);
2905
2906 }
2907 }
2908
2909 tempq = MMIO_IN32(ivideo->mmio_vbase, MMIO_QUEUE_READPORT);
2910 MMIO_OUT32(ivideo->mmio_vbase, MMIO_QUEUE_WRITEPORT, tempq);
2911
2912 temp |= (SIS_MMIO_CMD_ENABLE | SIS_CMD_AUTO_CORR);
2913 outSISIDXREG(SISSR, IND_SIS_CMDQUEUE_SET, temp);
2914
2915 tempq = (u32)(ivideo->video_size - ivideo->cmdQueueSize);
2916 MMIO_OUT32(ivideo->mmio_vbase, MMIO_QUEUE_PHYBASE, tempq);
2917
2918 ivideo->caps |= MMIO_CMD_QUEUE_CAP;
2919 }
2920#endif
2921
2922 ivideo->engineok = 1;
2923}
2924
2925static void __devinit
2926sisfb_detect_lcd_type(struct sis_video_info *ivideo)
2927{
2928 u8 reg;
2929 int i;
2930
2931 inSISIDXREG(SISCR, 0x36, reg);
2932 reg &= 0x0f;
2933 if(ivideo->sisvga_engine == SIS_300_VGA) {
2934 ivideo->CRT2LCDType = sis300paneltype[reg];
2935 } else if(ivideo->chip >= SIS_661) {
2936 ivideo->CRT2LCDType = sis661paneltype[reg];
2937 } else {
2938 ivideo->CRT2LCDType = sis310paneltype[reg];
2939 if((ivideo->chip == SIS_550) && (sisfb_fstn)) {
2940 if((ivideo->CRT2LCDType != LCD_320x240_2) &&
2941 (ivideo->CRT2LCDType != LCD_320x240_3)) {
2942 ivideo->CRT2LCDType = LCD_320x240;
2943 }
2944 }
2945 }
2946
2947 if(ivideo->CRT2LCDType == LCD_UNKNOWN) {
2948 /* For broken BIOSes: Assume 1024x768, RGB18 */
2949 ivideo->CRT2LCDType = LCD_1024x768;
2950 setSISIDXREG(SISCR,0x36,0xf0,0x02);
2951 setSISIDXREG(SISCR,0x37,0xee,0x01);
2952 printk(KERN_DEBUG "sisfb: Invalid panel ID (%02x), assuming 1024x768, RGB18\n", reg);
2953 }
2954
2955 for(i = 0; i < SIS_LCD_NUMBER; i++) {
2956 if(ivideo->CRT2LCDType == sis_lcd_data[i].lcdtype) {
2957 ivideo->lcdxres = sis_lcd_data[i].xres;
2958 ivideo->lcdyres = sis_lcd_data[i].yres;
2959 ivideo->lcddefmodeidx = sis_lcd_data[i].default_mode_idx;
2960 break;
2961 }
2962 }
2963
2964#ifdef CONFIG_FB_SIS_300
2965 if(ivideo->SiS_Pr.SiS_CustomT == CUT_BARCO1366) {
2966 ivideo->lcdxres = 1360; ivideo->lcdyres = 1024;
2967 ivideo->lcddefmodeidx = DEFAULT_MODE_1360;
2968 } else if(ivideo->SiS_Pr.SiS_CustomT == CUT_PANEL848) {
2969 ivideo->lcdxres = 848; ivideo->lcdyres = 480;
2970 ivideo->lcddefmodeidx = DEFAULT_MODE_848;
2971 } else if(ivideo->SiS_Pr.SiS_CustomT == CUT_PANEL856) {
2972 ivideo->lcdxres = 856; ivideo->lcdyres = 480;
2973 ivideo->lcddefmodeidx = DEFAULT_MODE_856;
2974 }
2975#endif
2976
2977 printk(KERN_DEBUG "sisfb: Detected %dx%d flat panel\n",
2978 ivideo->lcdxres, ivideo->lcdyres);
2979}
2980
2981static void __devinit
2982sisfb_save_pdc_emi(struct sis_video_info *ivideo)
2983{
2984#ifdef CONFIG_FB_SIS_300
2985 /* Save the current PanelDelayCompensation if the LCD is currently used */
2986 if(ivideo->sisvga_engine == SIS_300_VGA) {
2987 if(ivideo->vbflags2 & (VB2_LVDS | VB2_30xBDH)) {
2988 int tmp;
2989 inSISIDXREG(SISCR,0x30,tmp);
2990 if(tmp & 0x20) {
2991 /* Currently on LCD? If yes, read current pdc */
2992 inSISIDXREG(SISPART1,0x13,ivideo->detectedpdc);
2993 ivideo->detectedpdc &= 0x3c;
2994 if(ivideo->SiS_Pr.PDC == -1) {
2995 /* Let option override detection */
2996 ivideo->SiS_Pr.PDC = ivideo->detectedpdc;
2997 }
2998 printk(KERN_INFO "sisfb: Detected LCD PDC 0x%02x\n",
2999 ivideo->detectedpdc);
3000 }
3001 if((ivideo->SiS_Pr.PDC != -1) &&
3002 (ivideo->SiS_Pr.PDC != ivideo->detectedpdc)) {
3003 printk(KERN_INFO "sisfb: Using LCD PDC 0x%02x\n",
3004 ivideo->SiS_Pr.PDC);
3005 }
3006 }
3007 }
3008#endif
3009
3010#ifdef CONFIG_FB_SIS_315
3011 if(ivideo->sisvga_engine == SIS_315_VGA) {
3012
3013 /* Try to find about LCDA */
3014 if(ivideo->vbflags2 & VB2_SISLCDABRIDGE) {
3015 int tmp;
3016 inSISIDXREG(SISPART1,0x13,tmp);
3017 if(tmp & 0x04) {
Richard Knutssonc30660ea2007-02-12 00:55:06 -08003018 ivideo->SiS_Pr.SiS_UseLCDA = true;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003019 ivideo->detectedlcda = 0x03;
3020 }
3021 }
3022
3023 /* Save PDC */
3024 if(ivideo->vbflags2 & VB2_SISLVDSBRIDGE) {
3025 int tmp;
3026 inSISIDXREG(SISCR,0x30,tmp);
3027 if((tmp & 0x20) || (ivideo->detectedlcda != 0xff)) {
3028 /* Currently on LCD? If yes, read current pdc */
3029 u8 pdc;
3030 inSISIDXREG(SISPART1,0x2D,pdc);
3031 ivideo->detectedpdc = (pdc & 0x0f) << 1;
3032 ivideo->detectedpdca = (pdc & 0xf0) >> 3;
3033 inSISIDXREG(SISPART1,0x35,pdc);
3034 ivideo->detectedpdc |= ((pdc >> 7) & 0x01);
3035 inSISIDXREG(SISPART1,0x20,pdc);
3036 ivideo->detectedpdca |= ((pdc >> 6) & 0x01);
3037 if(ivideo->newrom) {
3038 /* New ROM invalidates other PDC resp. */
3039 if(ivideo->detectedlcda != 0xff) {
3040 ivideo->detectedpdc = 0xff;
3041 } else {
3042 ivideo->detectedpdca = 0xff;
3043 }
3044 }
3045 if(ivideo->SiS_Pr.PDC == -1) {
3046 if(ivideo->detectedpdc != 0xff) {
3047 ivideo->SiS_Pr.PDC = ivideo->detectedpdc;
3048 }
3049 }
3050 if(ivideo->SiS_Pr.PDCA == -1) {
3051 if(ivideo->detectedpdca != 0xff) {
3052 ivideo->SiS_Pr.PDCA = ivideo->detectedpdca;
3053 }
3054 }
3055 if(ivideo->detectedpdc != 0xff) {
3056 printk(KERN_INFO
3057 "sisfb: Detected LCD PDC 0x%02x (for LCD=CRT2)\n",
3058 ivideo->detectedpdc);
3059 }
3060 if(ivideo->detectedpdca != 0xff) {
3061 printk(KERN_INFO
3062 "sisfb: Detected LCD PDC1 0x%02x (for LCD=CRT1)\n",
3063 ivideo->detectedpdca);
3064 }
3065 }
3066
3067 /* Save EMI */
3068 if(ivideo->vbflags2 & VB2_SISEMIBRIDGE) {
3069 inSISIDXREG(SISPART4,0x30,ivideo->SiS_Pr.EMI_30);
3070 inSISIDXREG(SISPART4,0x31,ivideo->SiS_Pr.EMI_31);
3071 inSISIDXREG(SISPART4,0x32,ivideo->SiS_Pr.EMI_32);
3072 inSISIDXREG(SISPART4,0x33,ivideo->SiS_Pr.EMI_33);
Richard Knutssonc30660ea2007-02-12 00:55:06 -08003073 ivideo->SiS_Pr.HaveEMI = true;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003074 if((tmp & 0x20) || (ivideo->detectedlcda != 0xff)) {
Richard Knutssonc30660ea2007-02-12 00:55:06 -08003075 ivideo->SiS_Pr.HaveEMILCD = true;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003076 }
3077 }
3078 }
3079
3080 /* Let user override detected PDCs (all bridges) */
3081 if(ivideo->vbflags2 & VB2_30xBLV) {
3082 if((ivideo->SiS_Pr.PDC != -1) &&
3083 (ivideo->SiS_Pr.PDC != ivideo->detectedpdc)) {
3084 printk(KERN_INFO "sisfb: Using LCD PDC 0x%02x (for LCD=CRT2)\n",
3085 ivideo->SiS_Pr.PDC);
3086 }
3087 if((ivideo->SiS_Pr.PDCA != -1) &&
3088 (ivideo->SiS_Pr.PDCA != ivideo->detectedpdca)) {
3089 printk(KERN_INFO "sisfb: Using LCD PDC1 0x%02x (for LCD=CRT1)\n",
3090 ivideo->SiS_Pr.PDCA);
3091 }
3092 }
3093
3094 }
3095#endif
3096}
3097
3098/* -------------------- Memory manager routines ---------------------- */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003099
3100static u32 __devinit
3101sisfb_getheapstart(struct sis_video_info *ivideo)
3102{
3103 u32 ret = ivideo->sisfb_parm_mem * 1024;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003104 u32 maxoffs = ivideo->video_size - ivideo->hwcursor_size - ivideo->cmdQueueSize;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003105 u32 def;
3106
3107 /* Calculate heap start = end of memory for console
3108 *
3109 * CCCCCCCCDDDDDDDDDDDDDDDDDDDDDDDDDDDDHHHHQQQQQQQQQQ
3110 * C = console, D = heap, H = HWCursor, Q = cmd-queue
3111 *
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003112 * On 76x in UMA+LFB mode, the layout is as follows:
3113 * DDDDDDDDDDDCCCCCCCCCCCCCCCCCCCCCCCCHHHHQQQQQQQQQQQ
3114 * where the heap is the entire UMA area, eventually
3115 * into the LFB area if the given mem parameter is
3116 * higher than the size of the UMA memory.
3117 *
Linus Torvalds1da177e2005-04-16 15:20:36 -07003118 * Basically given by "mem" parameter
3119 *
3120 * maximum = videosize - cmd_queue - hwcursor
3121 * (results in a heap of size 0)
3122 * default = SiS 300: depends on videosize
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003123 * SiS 315/330/340/XGI: 32k below max
Linus Torvalds1da177e2005-04-16 15:20:36 -07003124 */
3125
3126 if(ivideo->sisvga_engine == SIS_300_VGA) {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003127 if(ivideo->video_size > 0x1000000) {
3128 def = 0xc00000;
3129 } else if(ivideo->video_size > 0x800000) {
3130 def = 0x800000;
3131 } else {
3132 def = 0x400000;
3133 }
3134 } else if(ivideo->UMAsize && ivideo->LFBsize) {
3135 ret = def = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003136 } else {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003137 def = maxoffs - 0x8000;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003138 }
3139
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003140 /* Use default for secondary card for now (FIXME) */
3141 if((!ret) || (ret > maxoffs) || (ivideo->cardnumber != 0))
3142 ret = def;
3143
3144 return ret;
3145}
3146
3147static u32 __devinit
3148sisfb_getheapsize(struct sis_video_info *ivideo)
3149{
3150 u32 max = ivideo->video_size - ivideo->hwcursor_size - ivideo->cmdQueueSize;
3151 u32 ret = 0;
3152
3153 if(ivideo->UMAsize && ivideo->LFBsize) {
3154 if( (!ivideo->sisfb_parm_mem) ||
3155 ((ivideo->sisfb_parm_mem * 1024) > max) ||
3156 ((max - (ivideo->sisfb_parm_mem * 1024)) < ivideo->UMAsize) ) {
3157 ret = ivideo->UMAsize;
3158 max -= ivideo->UMAsize;
3159 } else {
3160 ret = max - (ivideo->sisfb_parm_mem * 1024);
3161 max = ivideo->sisfb_parm_mem * 1024;
3162 }
3163 ivideo->video_offset = ret;
3164 ivideo->sisfb_mem = max;
3165 } else {
3166 ret = max - ivideo->heapstart;
3167 ivideo->sisfb_mem = ivideo->heapstart;
3168 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003169
3170 return ret;
3171}
3172
3173static int __devinit
3174sisfb_heap_init(struct sis_video_info *ivideo)
3175{
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003176 struct SIS_OH *poh;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003177
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003178 ivideo->video_offset = 0;
3179 if(ivideo->sisfb_parm_mem) {
3180 if( (ivideo->sisfb_parm_mem < (2 * 1024 * 1024)) ||
3181 (ivideo->sisfb_parm_mem > ivideo->video_size) ) {
3182 ivideo->sisfb_parm_mem = 0;
3183 }
3184 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003185
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003186 ivideo->heapstart = sisfb_getheapstart(ivideo);
3187 ivideo->sisfb_heap_size = sisfb_getheapsize(ivideo);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003188
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003189 ivideo->sisfb_heap_start = ivideo->video_vbase + ivideo->heapstart;
3190 ivideo->sisfb_heap_end = ivideo->sisfb_heap_start + ivideo->sisfb_heap_size;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003191
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003192 printk(KERN_INFO "sisfb: Memory heap starting at %dK, size %dK\n",
3193 (int)(ivideo->heapstart / 1024), (int)(ivideo->sisfb_heap_size / 1024));
Linus Torvalds1da177e2005-04-16 15:20:36 -07003194
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003195 ivideo->sisfb_heap.vinfo = ivideo;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003196
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003197 ivideo->sisfb_heap.poha_chain = NULL;
3198 ivideo->sisfb_heap.poh_freelist = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003199
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003200 poh = sisfb_poh_new_node(&ivideo->sisfb_heap);
3201 if(poh == NULL)
3202 return 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003203
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003204 poh->poh_next = &ivideo->sisfb_heap.oh_free;
3205 poh->poh_prev = &ivideo->sisfb_heap.oh_free;
3206 poh->size = ivideo->sisfb_heap_size;
3207 poh->offset = ivideo->heapstart;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003208
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003209 ivideo->sisfb_heap.oh_free.poh_next = poh;
3210 ivideo->sisfb_heap.oh_free.poh_prev = poh;
3211 ivideo->sisfb_heap.oh_free.size = 0;
3212 ivideo->sisfb_heap.max_freesize = poh->size;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003213
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003214 ivideo->sisfb_heap.oh_used.poh_next = &ivideo->sisfb_heap.oh_used;
3215 ivideo->sisfb_heap.oh_used.poh_prev = &ivideo->sisfb_heap.oh_used;
3216 ivideo->sisfb_heap.oh_used.size = SENTINEL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003217
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003218 if(ivideo->cardnumber == 0) {
3219 /* For the first card, make this heap the "global" one
3220 * for old DRM (which could handle only one card)
3221 */
3222 sisfb_heap = &ivideo->sisfb_heap;
3223 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003224
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003225 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003226}
3227
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003228static struct SIS_OH *
3229sisfb_poh_new_node(struct SIS_HEAP *memheap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003230{
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003231 struct SIS_OHALLOC *poha;
3232 struct SIS_OH *poh;
3233 unsigned long cOhs;
3234 int i;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003235
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003236 if(memheap->poh_freelist == NULL) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003237 poha = kmalloc(SIS_OH_ALLOC_SIZE, GFP_KERNEL);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003238 if(!poha)
3239 return NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003240
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003241 poha->poha_next = memheap->poha_chain;
3242 memheap->poha_chain = poha;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003243
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003244 cOhs = (SIS_OH_ALLOC_SIZE - sizeof(struct SIS_OHALLOC)) / sizeof(struct SIS_OH) + 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003245
3246 poh = &poha->aoh[0];
3247 for(i = cOhs - 1; i != 0; i--) {
3248 poh->poh_next = poh + 1;
3249 poh = poh + 1;
3250 }
3251
3252 poh->poh_next = NULL;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003253 memheap->poh_freelist = &poha->aoh[0];
Linus Torvalds1da177e2005-04-16 15:20:36 -07003254 }
3255
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003256 poh = memheap->poh_freelist;
3257 memheap->poh_freelist = poh->poh_next;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003258
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003259 return poh;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003260}
3261
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003262static struct SIS_OH *
3263sisfb_poh_allocate(struct SIS_HEAP *memheap, u32 size)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003264{
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003265 struct SIS_OH *pohThis;
3266 struct SIS_OH *pohRoot;
3267 int bAllocated = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003268
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003269 if(size > memheap->max_freesize) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003270 DPRINTK("sisfb: Can't allocate %dk video memory\n",
3271 (unsigned int) size / 1024);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003272 return NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003273 }
3274
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003275 pohThis = memheap->oh_free.poh_next;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003276
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003277 while(pohThis != &memheap->oh_free) {
3278 if(size <= pohThis->size) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003279 bAllocated = 1;
3280 break;
3281 }
3282 pohThis = pohThis->poh_next;
3283 }
3284
3285 if(!bAllocated) {
3286 DPRINTK("sisfb: Can't allocate %dk video memory\n",
3287 (unsigned int) size / 1024);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003288 return NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003289 }
3290
3291 if(size == pohThis->size) {
3292 pohRoot = pohThis;
3293 sisfb_delete_node(pohThis);
3294 } else {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003295 pohRoot = sisfb_poh_new_node(memheap);
3296 if(pohRoot == NULL)
3297 return NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003298
3299 pohRoot->offset = pohThis->offset;
3300 pohRoot->size = size;
3301
3302 pohThis->offset += size;
3303 pohThis->size -= size;
3304 }
3305
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003306 memheap->max_freesize -= size;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003307
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003308 pohThis = &memheap->oh_used;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003309 sisfb_insert_node(pohThis, pohRoot);
3310
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003311 return pohRoot;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003312}
3313
3314static void
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003315sisfb_delete_node(struct SIS_OH *poh)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003316{
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003317 poh->poh_prev->poh_next = poh->poh_next;
3318 poh->poh_next->poh_prev = poh->poh_prev;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003319}
3320
3321static void
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003322sisfb_insert_node(struct SIS_OH *pohList, struct SIS_OH *poh)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003323{
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003324 struct SIS_OH *pohTemp = pohList->poh_next;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003325
3326 pohList->poh_next = poh;
3327 pohTemp->poh_prev = poh;
3328
3329 poh->poh_prev = pohList;
3330 poh->poh_next = pohTemp;
3331}
3332
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003333static struct SIS_OH *
3334sisfb_poh_free(struct SIS_HEAP *memheap, u32 base)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003335{
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003336 struct SIS_OH *pohThis;
3337 struct SIS_OH *poh_freed;
3338 struct SIS_OH *poh_prev;
3339 struct SIS_OH *poh_next;
3340 u32 ulUpper;
3341 u32 ulLower;
3342 int foundNode = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003343
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003344 poh_freed = memheap->oh_used.poh_next;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003345
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003346 while(poh_freed != &memheap->oh_used) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003347 if(poh_freed->offset == base) {
3348 foundNode = 1;
3349 break;
3350 }
3351
3352 poh_freed = poh_freed->poh_next;
3353 }
3354
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003355 if(!foundNode)
3356 return NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003357
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003358 memheap->max_freesize += poh_freed->size;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003359
3360 poh_prev = poh_next = NULL;
3361 ulUpper = poh_freed->offset + poh_freed->size;
3362 ulLower = poh_freed->offset;
3363
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003364 pohThis = memheap->oh_free.poh_next;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003365
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003366 while(pohThis != &memheap->oh_free) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003367 if(pohThis->offset == ulUpper) {
3368 poh_next = pohThis;
3369 } else if((pohThis->offset + pohThis->size) == ulLower) {
3370 poh_prev = pohThis;
3371 }
3372 pohThis = pohThis->poh_next;
3373 }
3374
3375 sisfb_delete_node(poh_freed);
3376
3377 if(poh_prev && poh_next) {
3378 poh_prev->size += (poh_freed->size + poh_next->size);
3379 sisfb_delete_node(poh_next);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003380 sisfb_free_node(memheap, poh_freed);
3381 sisfb_free_node(memheap, poh_next);
3382 return poh_prev;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003383 }
3384
3385 if(poh_prev) {
3386 poh_prev->size += poh_freed->size;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003387 sisfb_free_node(memheap, poh_freed);
3388 return poh_prev;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003389 }
3390
3391 if(poh_next) {
3392 poh_next->size += poh_freed->size;
3393 poh_next->offset = poh_freed->offset;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003394 sisfb_free_node(memheap, poh_freed);
3395 return poh_next;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003396 }
3397
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003398 sisfb_insert_node(&memheap->oh_free, poh_freed);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003399
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003400 return poh_freed;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003401}
3402
3403static void
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003404sisfb_free_node(struct SIS_HEAP *memheap, struct SIS_OH *poh)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003405{
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003406 if(poh == NULL)
3407 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003408
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003409 poh->poh_next = memheap->poh_freelist;
3410 memheap->poh_freelist = poh;
3411}
3412
3413static void
3414sis_int_malloc(struct sis_video_info *ivideo, struct sis_memreq *req)
3415{
3416 struct SIS_OH *poh = NULL;
3417
3418 if((ivideo) && (ivideo->sisfb_id == SISFB_ID) && (!ivideo->havenoheap))
3419 poh = sisfb_poh_allocate(&ivideo->sisfb_heap, (u32)req->size);
3420
3421 if(poh == NULL) {
3422 req->offset = req->size = 0;
3423 DPRINTK("sisfb: Video RAM allocation failed\n");
3424 } else {
3425 req->offset = poh->offset;
3426 req->size = poh->size;
3427 DPRINTK("sisfb: Video RAM allocation succeeded: 0x%lx\n",
3428 (poh->offset + ivideo->video_vbase));
3429 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003430}
3431
3432void
3433sis_malloc(struct sis_memreq *req)
3434{
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003435 struct sis_video_info *ivideo = sisfb_heap->vinfo;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003436
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003437 if(&ivideo->sisfb_heap == sisfb_heap)
3438 sis_int_malloc(ivideo, req);
3439 else
3440 req->offset = req->size = 0;
3441}
Linus Torvalds1da177e2005-04-16 15:20:36 -07003442
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003443void
3444sis_malloc_new(struct pci_dev *pdev, struct sis_memreq *req)
3445{
3446 struct sis_video_info *ivideo = pci_get_drvdata(pdev);
3447
3448 sis_int_malloc(ivideo, req);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003449}
3450
3451/* sis_free: u32 because "base" is offset inside video ram, can never be >4GB */
3452
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003453static void
3454sis_int_free(struct sis_video_info *ivideo, u32 base)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003455{
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003456 struct SIS_OH *poh;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003457
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003458 if((!ivideo) || (ivideo->sisfb_id != SISFB_ID) || (ivideo->havenoheap))
3459 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003460
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003461 poh = sisfb_poh_free(&ivideo->sisfb_heap, base);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003462
3463 if(poh == NULL) {
3464 DPRINTK("sisfb: sisfb_poh_free() failed at base 0x%x\n",
3465 (unsigned int) base);
3466 }
3467}
3468
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003469void
3470sis_free(u32 base)
3471{
3472 struct sis_video_info *ivideo = sisfb_heap->vinfo;
3473
3474 sis_int_free(ivideo, base);
3475}
3476
3477void
3478sis_free_new(struct pci_dev *pdev, u32 base)
3479{
3480 struct sis_video_info *ivideo = pci_get_drvdata(pdev);
3481
3482 sis_int_free(ivideo, base);
3483}
3484
Linus Torvalds1da177e2005-04-16 15:20:36 -07003485/* --------------------- SetMode routines ------------------------- */
3486
3487static void
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003488sisfb_check_engine_and_sync(struct sis_video_info *ivideo)
3489{
3490 u8 cr30, cr31;
3491
3492 /* Check if MMIO and engines are enabled,
3493 * and sync in case they are. Can't use
3494 * ivideo->accel here, as this might have
3495 * been changed before this is called.
3496 */
3497 inSISIDXREG(SISSR, IND_SIS_PCI_ADDRESS_SET, cr30);
3498 inSISIDXREG(SISSR, IND_SIS_MODULE_ENABLE, cr31);
3499 /* MMIO and 2D/3D engine enabled? */
3500 if((cr30 & SIS_MEM_MAP_IO_ENABLE) && (cr31 & 0x42)) {
3501#ifdef CONFIG_FB_SIS_300
3502 if(ivideo->sisvga_engine == SIS_300_VGA) {
3503 /* Don't care about TurboQueue. It's
3504 * enough to know that the engines
3505 * are enabled
3506 */
3507 sisfb_syncaccel(ivideo);
3508 }
3509#endif
3510#ifdef CONFIG_FB_SIS_315
3511 if(ivideo->sisvga_engine == SIS_315_VGA) {
3512 /* Check that any queue mode is
3513 * enabled, and that the queue
3514 * is not in the state of "reset"
3515 */
3516 inSISIDXREG(SISSR, 0x26, cr30);
3517 if((cr30 & 0xe0) && (!(cr30 & 0x01))) {
3518 sisfb_syncaccel(ivideo);
3519 }
3520 }
3521#endif
3522 }
3523}
3524
3525static void
Linus Torvalds1da177e2005-04-16 15:20:36 -07003526sisfb_pre_setmode(struct sis_video_info *ivideo)
3527{
3528 u8 cr30 = 0, cr31 = 0, cr33 = 0, cr35 = 0, cr38 = 0;
3529 int tvregnum = 0;
3530
3531 ivideo->currentvbflags &= (VB_VIDEOBRIDGE | VB_DISPTYPE_DISP2);
3532
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003533 outSISIDXREG(SISSR, 0x05, 0x86);
3534
Linus Torvalds1da177e2005-04-16 15:20:36 -07003535 inSISIDXREG(SISCR, 0x31, cr31);
3536 cr31 &= ~0x60;
3537 cr31 |= 0x04;
3538
3539 cr33 = ivideo->rate_idx & 0x0F;
3540
3541#ifdef CONFIG_FB_SIS_315
3542 if(ivideo->sisvga_engine == SIS_315_VGA) {
3543 if(ivideo->chip >= SIS_661) {
3544 inSISIDXREG(SISCR, 0x38, cr38);
3545 cr38 &= ~0x07; /* Clear LCDA/DualEdge and YPbPr bits */
3546 } else {
3547 tvregnum = 0x38;
3548 inSISIDXREG(SISCR, tvregnum, cr38);
3549 cr38 &= ~0x3b; /* Clear LCDA/DualEdge and YPbPr bits */
3550 }
3551 }
3552#endif
3553#ifdef CONFIG_FB_SIS_300
3554 if(ivideo->sisvga_engine == SIS_300_VGA) {
3555 tvregnum = 0x35;
3556 inSISIDXREG(SISCR, tvregnum, cr38);
3557 }
3558#endif
3559
Richard Knutssonc30660ea2007-02-12 00:55:06 -08003560 SiS_SetEnableDstn(&ivideo->SiS_Pr, false);
3561 SiS_SetEnableFstn(&ivideo->SiS_Pr, false);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003562 ivideo->curFSTN = ivideo->curDSTN = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003563
3564 switch(ivideo->currentvbflags & VB_DISPTYPE_DISP2) {
3565
3566 case CRT2_TV:
3567 cr38 &= ~0xc0; /* Clear PAL-M / PAL-N bits */
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003568 if((ivideo->vbflags & TV_YPBPR) && (ivideo->vbflags2 & VB2_SISYPBPRBRIDGE)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003569#ifdef CONFIG_FB_SIS_315
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003570 if(ivideo->chip >= SIS_661) {
3571 cr38 |= 0x04;
3572 if(ivideo->vbflags & TV_YPBPR525P) cr35 |= 0x20;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003573 else if(ivideo->vbflags & TV_YPBPR750P) cr35 |= 0x40;
3574 else if(ivideo->vbflags & TV_YPBPR1080I) cr35 |= 0x60;
3575 cr30 |= SIS_SIMULTANEOUS_VIEW_ENABLE;
3576 cr35 &= ~0x01;
3577 ivideo->currentvbflags |= (TV_YPBPR | (ivideo->vbflags & TV_YPBPRALL));
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003578 } else if(ivideo->sisvga_engine == SIS_315_VGA) {
3579 cr30 |= (0x80 | SIS_SIMULTANEOUS_VIEW_ENABLE);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003580 cr38 |= 0x08;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003581 if(ivideo->vbflags & TV_YPBPR525P) cr38 |= 0x10;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003582 else if(ivideo->vbflags & TV_YPBPR750P) cr38 |= 0x20;
3583 else if(ivideo->vbflags & TV_YPBPR1080I) cr38 |= 0x30;
3584 cr31 &= ~0x01;
3585 ivideo->currentvbflags |= (TV_YPBPR | (ivideo->vbflags & TV_YPBPRALL));
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003586 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003587#endif
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003588 } else if((ivideo->vbflags & TV_HIVISION) &&
3589 (ivideo->vbflags2 & VB2_SISHIVISIONBRIDGE)) {
3590 if(ivideo->chip >= SIS_661) {
3591 cr38 |= 0x04;
3592 cr35 |= 0x60;
3593 } else {
3594 cr30 |= 0x80;
3595 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003596 cr30 |= SIS_SIMULTANEOUS_VIEW_ENABLE;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003597 cr31 |= 0x01;
3598 cr35 |= 0x01;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003599 ivideo->currentvbflags |= TV_HIVISION;
3600 } else if(ivideo->vbflags & TV_SCART) {
3601 cr30 = (SIS_VB_OUTPUT_SCART | SIS_SIMULTANEOUS_VIEW_ENABLE);
3602 cr31 |= 0x01;
3603 cr35 |= 0x01;
3604 ivideo->currentvbflags |= TV_SCART;
3605 } else {
3606 if(ivideo->vbflags & TV_SVIDEO) {
3607 cr30 = (SIS_VB_OUTPUT_SVIDEO | SIS_SIMULTANEOUS_VIEW_ENABLE);
3608 ivideo->currentvbflags |= TV_SVIDEO;
3609 }
3610 if(ivideo->vbflags & TV_AVIDEO) {
3611 cr30 = (SIS_VB_OUTPUT_COMPOSITE | SIS_SIMULTANEOUS_VIEW_ENABLE);
3612 ivideo->currentvbflags |= TV_AVIDEO;
3613 }
3614 }
3615 cr31 |= SIS_DRIVER_MODE;
3616
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003617 if(ivideo->vbflags & (TV_AVIDEO | TV_SVIDEO)) {
3618 if(ivideo->vbflags & TV_PAL) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003619 cr31 |= 0x01; cr35 |= 0x01;
3620 ivideo->currentvbflags |= TV_PAL;
3621 if(ivideo->vbflags & TV_PALM) {
3622 cr38 |= 0x40; cr35 |= 0x04;
3623 ivideo->currentvbflags |= TV_PALM;
3624 } else if(ivideo->vbflags & TV_PALN) {
3625 cr38 |= 0x80; cr35 |= 0x08;
3626 ivideo->currentvbflags |= TV_PALN;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003627 }
3628 } else {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003629 cr31 &= ~0x01; cr35 &= ~0x01;
3630 ivideo->currentvbflags |= TV_NTSC;
3631 if(ivideo->vbflags & TV_NTSCJ) {
3632 cr38 |= 0x40; cr35 |= 0x02;
3633 ivideo->currentvbflags |= TV_NTSCJ;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003634 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003635 }
3636 }
3637 break;
3638
3639 case CRT2_LCD:
3640 cr30 = (SIS_VB_OUTPUT_LCD | SIS_SIMULTANEOUS_VIEW_ENABLE);
3641 cr31 |= SIS_DRIVER_MODE;
3642 SiS_SetEnableDstn(&ivideo->SiS_Pr, ivideo->sisfb_dstn);
3643 SiS_SetEnableFstn(&ivideo->SiS_Pr, ivideo->sisfb_fstn);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003644 ivideo->curFSTN = ivideo->sisfb_fstn;
3645 ivideo->curDSTN = ivideo->sisfb_dstn;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003646 break;
3647
3648 case CRT2_VGA:
3649 cr30 = (SIS_VB_OUTPUT_CRT2 | SIS_SIMULTANEOUS_VIEW_ENABLE);
3650 cr31 |= SIS_DRIVER_MODE;
3651 if(ivideo->sisfb_nocrt2rate) {
3652 cr33 |= (sisbios_mode[ivideo->sisfb_mode_idx].rate_idx << 4);
3653 } else {
3654 cr33 |= ((ivideo->rate_idx & 0x0F) << 4);
3655 }
3656 break;
3657
3658 default: /* disable CRT2 */
3659 cr30 = 0x00;
3660 cr31 |= (SIS_DRIVER_MODE | SIS_VB_OUTPUT_DISABLE);
3661 }
3662
3663 outSISIDXREG(SISCR, 0x30, cr30);
3664 outSISIDXREG(SISCR, 0x33, cr33);
3665
3666 if(ivideo->chip >= SIS_661) {
3667#ifdef CONFIG_FB_SIS_315
3668 cr31 &= ~0x01; /* Clear PAL flag (now in CR35) */
3669 setSISIDXREG(SISCR, 0x35, ~0x10, cr35); /* Leave overscan bit alone */
3670 cr38 &= 0x07; /* Use only LCDA and HiVision/YPbPr bits */
3671 setSISIDXREG(SISCR, 0x38, 0xf8, cr38);
3672#endif
3673 } else if(ivideo->chip != SIS_300) {
3674 outSISIDXREG(SISCR, tvregnum, cr38);
3675 }
3676 outSISIDXREG(SISCR, 0x31, cr31);
3677
Linus Torvalds1da177e2005-04-16 15:20:36 -07003678 ivideo->SiS_Pr.SiS_UseOEM = ivideo->sisfb_useoem;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003679
3680 sisfb_check_engine_and_sync(ivideo);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003681}
3682
3683/* Fix SR11 for 661 and later */
3684#ifdef CONFIG_FB_SIS_315
3685static void
3686sisfb_fixup_SR11(struct sis_video_info *ivideo)
3687{
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003688 u8 tmpreg;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003689
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003690 if(ivideo->chip >= SIS_661) {
3691 inSISIDXREG(SISSR,0x11,tmpreg);
3692 if(tmpreg & 0x20) {
3693 inSISIDXREG(SISSR,0x3e,tmpreg);
3694 tmpreg = (tmpreg + 1) & 0xff;
3695 outSISIDXREG(SISSR,0x3e,tmpreg);
3696 inSISIDXREG(SISSR,0x11,tmpreg);
3697 }
3698 if(tmpreg & 0xf0) {
3699 andSISIDXREG(SISSR,0x11,0x0f);
3700 }
3701 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003702}
3703#endif
3704
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003705static void
3706sisfb_set_TVxposoffset(struct sis_video_info *ivideo, int val)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003707{
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003708 if(val > 32) val = 32;
3709 if(val < -32) val = -32;
3710 ivideo->tvxpos = val;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003711
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003712 if(ivideo->sisfblocked) return;
3713 if(!ivideo->modechanged) return;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003714
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003715 if(ivideo->currentvbflags & CRT2_TV) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003716
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003717 if(ivideo->vbflags2 & VB2_CHRONTEL) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003718
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003719 int x = ivideo->tvx;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003720
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003721 switch(ivideo->chronteltype) {
3722 case 1:
3723 x += val;
3724 if(x < 0) x = 0;
3725 outSISIDXREG(SISSR,0x05,0x86);
3726 SiS_SetCH700x(&ivideo->SiS_Pr, 0x0a, (x & 0xff));
3727 SiS_SetCH70xxANDOR(&ivideo->SiS_Pr, 0x08, ((x & 0x0100) >> 7), 0xFD);
3728 break;
3729 case 2:
3730 /* Not supported by hardware */
3731 break;
3732 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003733
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003734 } else if(ivideo->vbflags2 & VB2_SISBRIDGE) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003735
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003736 u8 p2_1f,p2_20,p2_2b,p2_42,p2_43;
3737 unsigned short temp;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003738
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003739 p2_1f = ivideo->p2_1f;
3740 p2_20 = ivideo->p2_20;
3741 p2_2b = ivideo->p2_2b;
3742 p2_42 = ivideo->p2_42;
3743 p2_43 = ivideo->p2_43;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003744
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003745 temp = p2_1f | ((p2_20 & 0xf0) << 4);
3746 temp += (val * 2);
3747 p2_1f = temp & 0xff;
3748 p2_20 = (temp & 0xf00) >> 4;
3749 p2_2b = ((p2_2b & 0x0f) + (val * 2)) & 0x0f;
3750 temp = p2_43 | ((p2_42 & 0xf0) << 4);
3751 temp += (val * 2);
3752 p2_43 = temp & 0xff;
3753 p2_42 = (temp & 0xf00) >> 4;
3754 outSISIDXREG(SISPART2,0x1f,p2_1f);
3755 setSISIDXREG(SISPART2,0x20,0x0F,p2_20);
3756 setSISIDXREG(SISPART2,0x2b,0xF0,p2_2b);
3757 setSISIDXREG(SISPART2,0x42,0x0F,p2_42);
3758 outSISIDXREG(SISPART2,0x43,p2_43);
3759 }
3760 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003761}
3762
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003763static void
3764sisfb_set_TVyposoffset(struct sis_video_info *ivideo, int val)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003765{
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003766 if(val > 32) val = 32;
3767 if(val < -32) val = -32;
3768 ivideo->tvypos = val;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003769
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003770 if(ivideo->sisfblocked) return;
3771 if(!ivideo->modechanged) return;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003772
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003773 if(ivideo->currentvbflags & CRT2_TV) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003774
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003775 if(ivideo->vbflags2 & VB2_CHRONTEL) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003776
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003777 int y = ivideo->tvy;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003778
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003779 switch(ivideo->chronteltype) {
3780 case 1:
3781 y -= val;
3782 if(y < 0) y = 0;
3783 outSISIDXREG(SISSR,0x05,0x86);
3784 SiS_SetCH700x(&ivideo->SiS_Pr, 0x0b, (y & 0xff));
3785 SiS_SetCH70xxANDOR(&ivideo->SiS_Pr, 0x08, ((y & 0x0100) >> 8), 0xFE);
3786 break;
3787 case 2:
3788 /* Not supported by hardware */
3789 break;
3790 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003791
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003792 } else if(ivideo->vbflags2 & VB2_SISBRIDGE) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003793
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003794 char p2_01, p2_02;
3795 val /= 2;
3796 p2_01 = ivideo->p2_01;
3797 p2_02 = ivideo->p2_02;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003798
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003799 p2_01 += val;
3800 p2_02 += val;
3801 if(!(ivideo->currentvbflags & (TV_HIVISION | TV_YPBPR))) {
3802 while((p2_01 <= 0) || (p2_02 <= 0)) {
3803 p2_01 += 2;
3804 p2_02 += 2;
3805 }
3806 }
3807 outSISIDXREG(SISPART2,0x01,p2_01);
3808 outSISIDXREG(SISPART2,0x02,p2_02);
3809 }
3810 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003811}
3812
3813static void
3814sisfb_post_setmode(struct sis_video_info *ivideo)
3815{
Richard Knutssonc30660ea2007-02-12 00:55:06 -08003816 bool crt1isoff = false;
3817 bool doit = true;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003818#if defined(CONFIG_FB_SIS_300) || defined(CONFIG_FB_SIS_315)
3819 u8 reg;
3820#endif
3821#ifdef CONFIG_FB_SIS_315
3822 u8 reg1;
3823#endif
3824
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003825 outSISIDXREG(SISSR, 0x05, 0x86);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003826
3827#ifdef CONFIG_FB_SIS_315
3828 sisfb_fixup_SR11(ivideo);
3829#endif
3830
3831 /* Now we actually HAVE changed the display mode */
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003832 ivideo->modechanged = 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003833
3834 /* We can't switch off CRT1 if bridge is in slave mode */
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003835 if(ivideo->vbflags2 & VB2_VIDEOBRIDGE) {
Richard Knutssonc30660ea2007-02-12 00:55:06 -08003836 if(sisfb_bridgeisslave(ivideo)) doit = false;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003837 } else
3838 ivideo->sisfb_crt1off = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003839
3840#ifdef CONFIG_FB_SIS_300
3841 if(ivideo->sisvga_engine == SIS_300_VGA) {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003842 if((ivideo->sisfb_crt1off) && (doit)) {
Richard Knutssonc30660ea2007-02-12 00:55:06 -08003843 crt1isoff = true;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003844 reg = 0x00;
3845 } else {
Richard Knutssonc30660ea2007-02-12 00:55:06 -08003846 crt1isoff = false;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003847 reg = 0x80;
3848 }
3849 setSISIDXREG(SISCR, 0x17, 0x7f, reg);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003850 }
3851#endif
3852#ifdef CONFIG_FB_SIS_315
3853 if(ivideo->sisvga_engine == SIS_315_VGA) {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003854 if((ivideo->sisfb_crt1off) && (doit)) {
Richard Knutssonc30660ea2007-02-12 00:55:06 -08003855 crt1isoff = true;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003856 reg = 0x40;
3857 reg1 = 0xc0;
3858 } else {
Richard Knutssonc30660ea2007-02-12 00:55:06 -08003859 crt1isoff = false;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003860 reg = 0x00;
3861 reg1 = 0x00;
3862 }
3863 setSISIDXREG(SISCR, ivideo->SiS_Pr.SiS_MyCR63, ~0x40, reg);
3864 setSISIDXREG(SISSR, 0x1f, ~0xc0, reg1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003865 }
3866#endif
3867
3868 if(crt1isoff) {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003869 ivideo->currentvbflags &= ~VB_DISPTYPE_CRT1;
3870 ivideo->currentvbflags |= VB_SINGLE_MODE;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003871 } else {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003872 ivideo->currentvbflags |= VB_DISPTYPE_CRT1;
3873 if(ivideo->currentvbflags & VB_DISPTYPE_CRT2) {
3874 ivideo->currentvbflags |= VB_MIRROR_MODE;
3875 } else {
3876 ivideo->currentvbflags |= VB_SINGLE_MODE;
3877 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003878 }
3879
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003880 andSISIDXREG(SISSR, IND_SIS_RAMDAC_CONTROL, ~0x04);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003881
3882 if(ivideo->currentvbflags & CRT2_TV) {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003883 if(ivideo->vbflags2 & VB2_SISBRIDGE) {
3884 inSISIDXREG(SISPART2,0x1f,ivideo->p2_1f);
3885 inSISIDXREG(SISPART2,0x20,ivideo->p2_20);
3886 inSISIDXREG(SISPART2,0x2b,ivideo->p2_2b);
3887 inSISIDXREG(SISPART2,0x42,ivideo->p2_42);
3888 inSISIDXREG(SISPART2,0x43,ivideo->p2_43);
3889 inSISIDXREG(SISPART2,0x01,ivideo->p2_01);
3890 inSISIDXREG(SISPART2,0x02,ivideo->p2_02);
3891 } else if(ivideo->vbflags2 & VB2_CHRONTEL) {
3892 if(ivideo->chronteltype == 1) {
3893 ivideo->tvx = SiS_GetCH700x(&ivideo->SiS_Pr, 0x0a);
3894 ivideo->tvx |= (((SiS_GetCH700x(&ivideo->SiS_Pr, 0x08) & 0x02) >> 1) << 8);
3895 ivideo->tvy = SiS_GetCH700x(&ivideo->SiS_Pr, 0x0b);
3896 ivideo->tvy |= ((SiS_GetCH700x(&ivideo->SiS_Pr, 0x08) & 0x01) << 8);
3897 }
3898 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003899 }
3900
3901 if(ivideo->tvxpos) {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003902 sisfb_set_TVxposoffset(ivideo, ivideo->tvxpos);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003903 }
3904 if(ivideo->tvypos) {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003905 sisfb_set_TVyposoffset(ivideo, ivideo->tvypos);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003906 }
3907
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003908 /* Eventually sync engines */
3909 sisfb_check_engine_and_sync(ivideo);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003910
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003911 /* (Re-)Initialize chip engines */
3912 if(ivideo->accel) {
3913 sisfb_engine_init(ivideo);
3914 } else {
3915 ivideo->engineok = 0;
3916 }
3917}
Linus Torvalds1da177e2005-04-16 15:20:36 -07003918
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003919static int
3920sisfb_reset_mode(struct sis_video_info *ivideo)
3921{
3922 if(sisfb_set_mode(ivideo, 0))
3923 return 1;
3924
3925 sisfb_set_pitch(ivideo);
3926 sisfb_set_base_CRT1(ivideo, ivideo->current_base);
3927 sisfb_set_base_CRT2(ivideo, ivideo->current_base);
3928
3929 return 0;
3930}
3931
3932static void
3933sisfb_handle_command(struct sis_video_info *ivideo, struct sisfb_cmd *sisfb_command)
3934{
3935 int mycrt1off;
3936
3937 switch(sisfb_command->sisfb_cmd) {
3938 case SISFB_CMD_GETVBFLAGS:
3939 if(!ivideo->modechanged) {
3940 sisfb_command->sisfb_result[0] = SISFB_CMD_ERR_EARLY;
3941 } else {
3942 sisfb_command->sisfb_result[0] = SISFB_CMD_ERR_OK;
3943 sisfb_command->sisfb_result[1] = ivideo->currentvbflags;
3944 sisfb_command->sisfb_result[2] = ivideo->vbflags2;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003945 }
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003946 break;
3947 case SISFB_CMD_SWITCHCRT1:
3948 /* arg[0]: 0 = off, 1 = on, 99 = query */
3949 if(!ivideo->modechanged) {
3950 sisfb_command->sisfb_result[0] = SISFB_CMD_ERR_EARLY;
3951 } else if(sisfb_command->sisfb_arg[0] == 99) {
3952 /* Query */
3953 sisfb_command->sisfb_result[1] = ivideo->sisfb_crt1off ? 0 : 1;
3954 sisfb_command->sisfb_result[0] = SISFB_CMD_ERR_OK;
3955 } else if(ivideo->sisfblocked) {
3956 sisfb_command->sisfb_result[0] = SISFB_CMD_ERR_LOCKED;
3957 } else if((!(ivideo->currentvbflags & CRT2_ENABLE)) &&
3958 (sisfb_command->sisfb_arg[0] == 0)) {
3959 sisfb_command->sisfb_result[0] = SISFB_CMD_ERR_NOCRT2;
3960 } else {
3961 sisfb_command->sisfb_result[0] = SISFB_CMD_ERR_OK;
3962 mycrt1off = sisfb_command->sisfb_arg[0] ? 0 : 1;
3963 if( ((ivideo->currentvbflags & VB_DISPTYPE_CRT1) && mycrt1off) ||
3964 ((!(ivideo->currentvbflags & VB_DISPTYPE_CRT1)) && !mycrt1off) ) {
3965 ivideo->sisfb_crt1off = mycrt1off;
3966 if(sisfb_reset_mode(ivideo)) {
3967 sisfb_command->sisfb_result[0] = SISFB_CMD_ERR_OTHER;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003968 }
3969 }
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003970 sisfb_command->sisfb_result[1] = ivideo->sisfb_crt1off ? 0 : 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003971 }
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003972 break;
3973 /* more to come */
3974 default:
3975 sisfb_command->sisfb_result[0] = SISFB_CMD_ERR_UNKNOWN;
3976 printk(KERN_ERR "sisfb: Unknown command 0x%x\n",
3977 sisfb_command->sisfb_cmd);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003978 }
3979}
3980
3981#ifndef MODULE
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003982SISINITSTATIC int __init
3983sisfb_setup(char *options)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003984{
3985 char *this_opt;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003986
Linus Torvalds1da177e2005-04-16 15:20:36 -07003987 sisfb_setdefaultparms();
3988
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003989 if(!options || !(*options))
Linus Torvalds1da177e2005-04-16 15:20:36 -07003990 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003991
3992 while((this_opt = strsep(&options, ",")) != NULL) {
3993
3994 if(!(*this_opt)) continue;
3995
3996 if(!strnicmp(this_opt, "off", 3)) {
3997 sisfb_off = 1;
3998 } else if(!strnicmp(this_opt, "forcecrt2type:", 14)) {
3999 /* Need to check crt2 type first for fstn/dstn */
4000 sisfb_search_crt2type(this_opt + 14);
4001 } else if(!strnicmp(this_opt, "tvmode:",7)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004002 sisfb_search_tvstd(this_opt + 7);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004003 } else if(!strnicmp(this_opt, "tvstandard:",11)) {
4004 sisfb_search_tvstd(this_opt + 11);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004005 } else if(!strnicmp(this_opt, "mode:", 5)) {
Richard Knutssonc30660ea2007-02-12 00:55:06 -08004006 sisfb_search_mode(this_opt + 5, false);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004007 } else if(!strnicmp(this_opt, "vesa:", 5)) {
Richard Knutssonc30660ea2007-02-12 00:55:06 -08004008 sisfb_search_vesamode(simple_strtoul(this_opt + 5, NULL, 0), false);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004009 } else if(!strnicmp(this_opt, "rate:", 5)) {
4010 sisfb_parm_rate = simple_strtoul(this_opt + 5, NULL, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004011 } else if(!strnicmp(this_opt, "forcecrt1:", 10)) {
4012 sisfb_forcecrt1 = (int)simple_strtoul(this_opt + 10, NULL, 0);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004013 } else if(!strnicmp(this_opt, "mem:",4)) {
4014 sisfb_parm_mem = simple_strtoul(this_opt + 4, NULL, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004015 } else if(!strnicmp(this_opt, "pdc:", 4)) {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004016 sisfb_pdc = simple_strtoul(this_opt + 4, NULL, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004017 } else if(!strnicmp(this_opt, "pdc1:", 5)) {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004018 sisfb_pdca = simple_strtoul(this_opt + 5, NULL, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004019 } else if(!strnicmp(this_opt, "noaccel", 7)) {
4020 sisfb_accel = 0;
4021 } else if(!strnicmp(this_opt, "accel", 5)) {
4022 sisfb_accel = -1;
4023 } else if(!strnicmp(this_opt, "noypan", 6)) {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004024 sisfb_ypan = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004025 } else if(!strnicmp(this_opt, "ypan", 4)) {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004026 sisfb_ypan = -1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004027 } else if(!strnicmp(this_opt, "nomax", 5)) {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004028 sisfb_max = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004029 } else if(!strnicmp(this_opt, "max", 3)) {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004030 sisfb_max = -1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004031 } else if(!strnicmp(this_opt, "userom:", 7)) {
4032 sisfb_userom = (int)simple_strtoul(this_opt + 7, NULL, 0);
4033 } else if(!strnicmp(this_opt, "useoem:", 7)) {
4034 sisfb_useoem = (int)simple_strtoul(this_opt + 7, NULL, 0);
4035 } else if(!strnicmp(this_opt, "nocrt2rate", 10)) {
4036 sisfb_nocrt2rate = 1;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004037 } else if(!strnicmp(this_opt, "scalelcd:", 9)) {
4038 unsigned long temp = 2;
4039 temp = simple_strtoul(this_opt + 9, NULL, 0);
4040 if((temp == 0) || (temp == 1)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004041 sisfb_scalelcd = temp ^ 1;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004042 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004043 } else if(!strnicmp(this_opt, "tvxposoffset:", 13)) {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004044 int temp = 0;
4045 temp = (int)simple_strtol(this_opt + 13, NULL, 0);
4046 if((temp >= -32) && (temp <= 32)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004047 sisfb_tvxposoffset = temp;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004048 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004049 } else if(!strnicmp(this_opt, "tvyposoffset:", 13)) {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004050 int temp = 0;
4051 temp = (int)simple_strtol(this_opt + 13, NULL, 0);
4052 if((temp >= -32) && (temp <= 32)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004053 sisfb_tvyposoffset = temp;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004054 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004055 } else if(!strnicmp(this_opt, "specialtiming:", 14)) {
4056 sisfb_search_specialtiming(this_opt + 14);
4057 } else if(!strnicmp(this_opt, "lvdshl:", 7)) {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004058 int temp = 4;
4059 temp = simple_strtoul(this_opt + 7, NULL, 0);
4060 if((temp >= 0) && (temp <= 3)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004061 sisfb_lvdshl = temp;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004062 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004063 } else if(this_opt[0] >= '0' && this_opt[0] <= '9') {
Richard Knutssonc30660ea2007-02-12 00:55:06 -08004064 sisfb_search_mode(this_opt, true);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004065#if !defined(__i386__) && !defined(__x86_64__)
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004066 } else if(!strnicmp(this_opt, "resetcard", 9)) {
4067 sisfb_resetcard = 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004068 } else if(!strnicmp(this_opt, "videoram:", 9)) {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004069 sisfb_videoram = simple_strtoul(this_opt + 9, NULL, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004070#endif
4071 } else {
4072 printk(KERN_INFO "sisfb: Invalid option %s\n", this_opt);
4073 }
4074
4075 }
4076
Linus Torvalds1da177e2005-04-16 15:20:36 -07004077 return 0;
4078}
4079#endif
4080
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004081static int __devinit
4082sisfb_check_rom(SIS_IOTYPE1 *rom_base, struct sis_video_info *ivideo)
4083{
4084 SIS_IOTYPE1 *rom;
4085 int romptr;
4086
4087 if((readb(rom_base) != 0x55) || (readb(rom_base + 1) != 0xaa))
4088 return 0;
4089
4090 romptr = (readb(rom_base + 0x18) | (readb(rom_base + 0x19) << 8));
4091 if(romptr > (0x10000 - 8))
4092 return 0;
4093
4094 rom = rom_base + romptr;
4095
4096 if((readb(rom) != 'P') || (readb(rom + 1) != 'C') ||
4097 (readb(rom + 2) != 'I') || (readb(rom + 3) != 'R'))
4098 return 0;
4099
4100 if((readb(rom + 4) | (readb(rom + 5) << 8)) != ivideo->chip_vendor)
4101 return 0;
4102
4103 if((readb(rom + 6) | (readb(rom + 7) << 8)) != ivideo->chip_id)
4104 return 0;
4105
4106 return 1;
4107}
4108
4109static unsigned char * __devinit
4110sisfb_find_rom(struct pci_dev *pdev)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004111{
4112 struct sis_video_info *ivideo = pci_get_drvdata(pdev);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004113 SIS_IOTYPE1 *rom_base;
4114 unsigned char *myrombase = NULL;
4115 u32 temp;
4116#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,11)
4117 size_t romsize;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004118
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004119 /* First, try the official pci ROM functions (except
4120 * on integrated chipsets which have no ROM).
4121 */
4122
4123 if(!ivideo->nbridge) {
4124
4125 if((rom_base = pci_map_rom(pdev, &romsize))) {
4126
4127 if(sisfb_check_rom(rom_base, ivideo)) {
4128
4129 if((myrombase = vmalloc(65536))) {
4130
4131 /* Work around bug in pci/rom.c: Folks forgot to check
4132 * whether the size retrieved from the BIOS image eventually
4133 * is larger than the mapped size
4134 */
4135 if(pci_resource_len(pdev, PCI_ROM_RESOURCE) < romsize)
4136 romsize = pci_resource_len(pdev, PCI_ROM_RESOURCE);
4137
4138 memcpy_fromio(myrombase, rom_base,
4139 (romsize > 65536) ? 65536 : romsize);
4140 }
4141 }
4142 pci_unmap_rom(pdev, rom_base);
4143 }
4144 }
4145
4146 if(myrombase) return myrombase;
4147#endif
4148
4149 /* Otherwise do it the conventional way. */
Linus Torvalds1da177e2005-04-16 15:20:36 -07004150
4151#if defined(__i386__) || defined(__x86_64__)
4152
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004153 for(temp = 0x000c0000; temp < 0x000f0000; temp += 0x00001000) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004154
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004155 rom_base = ioremap(temp, 65536);
4156 if(!rom_base)
4157 continue;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004158
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004159 if(!sisfb_check_rom(rom_base, ivideo)) {
4160 iounmap(rom_base);
4161 continue;
4162 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004163
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004164 if((myrombase = vmalloc(65536)))
4165 memcpy_fromio(myrombase, rom_base, 65536);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004166
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004167 iounmap(rom_base);
4168 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004169
Linus Torvalds1da177e2005-04-16 15:20:36 -07004170 }
4171
4172#else
4173
4174 pci_read_config_dword(pdev, PCI_ROM_ADDRESS, &temp);
4175 pci_write_config_dword(pdev, PCI_ROM_ADDRESS,
4176 (ivideo->video_base & PCI_ROM_ADDRESS_MASK) | PCI_ROM_ADDRESS_ENABLE);
4177
4178 rom_base = ioremap(ivideo->video_base, 65536);
4179 if(rom_base) {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004180 if(sisfb_check_rom(rom_base, ivideo)) {
4181 if((myrombase = vmalloc(65536)))
4182 memcpy_fromio(myrombase, rom_base, 65536);
4183 }
4184 iounmap(rom_base);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004185 }
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004186
4187 pci_write_config_dword(pdev, PCI_ROM_ADDRESS, temp);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004188
4189#endif
4190
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004191 return myrombase;
4192}
4193
4194static void __devinit
4195sisfb_post_map_vram(struct sis_video_info *ivideo, unsigned int *mapsize,
4196 unsigned int min)
4197{
4198 ivideo->video_vbase = ioremap(ivideo->video_base, (*mapsize));
4199
4200 if(!ivideo->video_vbase) {
4201 printk(KERN_ERR
4202 "sisfb: Unable to map maximum video RAM for size detection\n");
4203 (*mapsize) >>= 1;
4204 while((!(ivideo->video_vbase = ioremap(ivideo->video_base, (*mapsize))))) {
4205 (*mapsize) >>= 1;
4206 if((*mapsize) < (min << 20))
4207 break;
4208 }
4209 if(ivideo->video_vbase) {
4210 printk(KERN_ERR
4211 "sisfb: Video RAM size detection limited to %dMB\n",
4212 (int)((*mapsize) >> 20));
4213 }
4214 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004215}
4216
4217#ifdef CONFIG_FB_SIS_300
4218static int __devinit
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004219sisfb_post_300_buswidth(struct sis_video_info *ivideo)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004220{
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004221 SIS_IOTYPE1 *FBAddress = ivideo->video_vbase;
4222 unsigned short temp;
4223 unsigned char reg;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004224 int i, j;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004225
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004226 andSISIDXREG(SISSR, 0x15, 0xFB);
4227 orSISIDXREG(SISSR, 0x15, 0x04);
4228 outSISIDXREG(SISSR, 0x13, 0x00);
4229 outSISIDXREG(SISSR, 0x14, 0xBF);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004230
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004231 for(i = 0; i < 2; i++) {
4232 temp = 0x1234;
4233 for(j = 0; j < 4; j++) {
4234 writew(temp, FBAddress);
4235 if(readw(FBAddress) == temp)
4236 break;
4237 orSISIDXREG(SISSR, 0x3c, 0x01);
4238 inSISIDXREG(SISSR, 0x05, reg);
4239 inSISIDXREG(SISSR, 0x05, reg);
4240 andSISIDXREG(SISSR, 0x3c, 0xfe);
4241 inSISIDXREG(SISSR, 0x05, reg);
4242 inSISIDXREG(SISSR, 0x05, reg);
4243 temp++;
4244 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004245 }
4246
4247 writel(0x01234567L, FBAddress);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004248 writel(0x456789ABL, (FBAddress + 4));
4249 writel(0x89ABCDEFL, (FBAddress + 8));
4250 writel(0xCDEF0123L, (FBAddress + 12));
4251
4252 inSISIDXREG(SISSR, 0x3b, reg);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004253 if(reg & 0x01) {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004254 if(readl((FBAddress + 12)) == 0xCDEF0123L)
4255 return 4; /* Channel A 128bit */
Linus Torvalds1da177e2005-04-16 15:20:36 -07004256 }
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004257
4258 if(readl((FBAddress + 4)) == 0x456789ABL)
4259 return 2; /* Channel B 64bit */
4260
4261 return 1; /* 32bit */
4262}
4263
4264static int __devinit
4265sisfb_post_300_rwtest(struct sis_video_info *ivideo, int iteration, int buswidth,
4266 int PseudoRankCapacity, int PseudoAdrPinCount,
4267 unsigned int mapsize)
4268{
4269 SIS_IOTYPE1 *FBAddr = ivideo->video_vbase;
4270 unsigned short sr14;
4271 unsigned int k, RankCapacity, PageCapacity, BankNumHigh, BankNumMid;
4272 unsigned int PhysicalAdrOtherPage, PhysicalAdrHigh, PhysicalAdrHalfPage;
4273 static const unsigned short SiS_DRAMType[17][5] = {
4274 {0x0C,0x0A,0x02,0x40,0x39},
4275 {0x0D,0x0A,0x01,0x40,0x48},
4276 {0x0C,0x09,0x02,0x20,0x35},
4277 {0x0D,0x09,0x01,0x20,0x44},
4278 {0x0C,0x08,0x02,0x10,0x31},
4279 {0x0D,0x08,0x01,0x10,0x40},
4280 {0x0C,0x0A,0x01,0x20,0x34},
4281 {0x0C,0x09,0x01,0x08,0x32},
4282 {0x0B,0x08,0x02,0x08,0x21},
4283 {0x0C,0x08,0x01,0x08,0x30},
4284 {0x0A,0x08,0x02,0x04,0x11},
4285 {0x0B,0x0A,0x01,0x10,0x28},
4286 {0x09,0x08,0x02,0x02,0x01},
4287 {0x0B,0x09,0x01,0x08,0x24},
4288 {0x0B,0x08,0x01,0x04,0x20},
4289 {0x0A,0x08,0x01,0x02,0x10},
4290 {0x09,0x08,0x01,0x01,0x00}
4291 };
4292
4293 for(k = 0; k <= 16; k++) {
4294
4295 RankCapacity = buswidth * SiS_DRAMType[k][3];
4296
4297 if(RankCapacity != PseudoRankCapacity)
4298 continue;
4299
4300 if((SiS_DRAMType[k][2] + SiS_DRAMType[k][0]) > PseudoAdrPinCount)
4301 continue;
4302
4303 BankNumHigh = RankCapacity * 16 * iteration - 1;
4304 if(iteration == 3) { /* Rank No */
4305 BankNumMid = RankCapacity * 16 - 1;
4306 } else {
4307 BankNumMid = RankCapacity * 16 * iteration / 2 - 1;
4308 }
4309
4310 PageCapacity = (1 << SiS_DRAMType[k][1]) * buswidth * 4;
4311 PhysicalAdrHigh = BankNumHigh;
4312 PhysicalAdrHalfPage = (PageCapacity / 2 + PhysicalAdrHigh) % PageCapacity;
4313 PhysicalAdrOtherPage = PageCapacity * SiS_DRAMType[k][2] + PhysicalAdrHigh;
4314
4315 andSISIDXREG(SISSR, 0x15, 0xFB); /* Test */
4316 orSISIDXREG(SISSR, 0x15, 0x04); /* Test */
4317 sr14 = (SiS_DRAMType[k][3] * buswidth) - 1;
4318 if(buswidth == 4) sr14 |= 0x80;
4319 else if(buswidth == 2) sr14 |= 0x40;
4320 outSISIDXREG(SISSR, 0x13, SiS_DRAMType[k][4]);
4321 outSISIDXREG(SISSR, 0x14, sr14);
4322
4323 BankNumHigh <<= 16;
4324 BankNumMid <<= 16;
4325
4326 if((BankNumHigh + PhysicalAdrHigh >= mapsize) ||
4327 (BankNumMid + PhysicalAdrHigh >= mapsize) ||
4328 (BankNumHigh + PhysicalAdrHalfPage >= mapsize) ||
4329 (BankNumHigh + PhysicalAdrOtherPage >= mapsize))
4330 continue;
4331
4332 /* Write data */
4333 writew(((unsigned short)PhysicalAdrHigh),
4334 (FBAddr + BankNumHigh + PhysicalAdrHigh));
4335 writew(((unsigned short)BankNumMid),
4336 (FBAddr + BankNumMid + PhysicalAdrHigh));
4337 writew(((unsigned short)PhysicalAdrHalfPage),
4338 (FBAddr + BankNumHigh + PhysicalAdrHalfPage));
4339 writew(((unsigned short)PhysicalAdrOtherPage),
4340 (FBAddr + BankNumHigh + PhysicalAdrOtherPage));
4341
4342 /* Read data */
4343 if(readw(FBAddr + BankNumHigh + PhysicalAdrHigh) == PhysicalAdrHigh)
4344 return 1;
4345 }
4346
4347 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004348}
4349
4350static void __devinit
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004351sisfb_post_300_ramsize(struct pci_dev *pdev, unsigned int mapsize)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004352{
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004353 struct sis_video_info *ivideo = pci_get_drvdata(pdev);
4354 int i, j, buswidth;
4355 int PseudoRankCapacity, PseudoAdrPinCount;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004356
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004357 buswidth = sisfb_post_300_buswidth(ivideo);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004358
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004359 for(i = 6; i >= 0; i--) {
4360 PseudoRankCapacity = 1 << i;
4361 for(j = 4; j >= 1; j--) {
4362 PseudoAdrPinCount = 15 - j;
4363 if((PseudoRankCapacity * j) <= 64) {
4364 if(sisfb_post_300_rwtest(ivideo,
4365 j,
4366 buswidth,
4367 PseudoRankCapacity,
4368 PseudoAdrPinCount,
4369 mapsize))
4370 return;
4371 }
4372 }
4373 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004374}
4375
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004376static void __devinit
4377sisfb_post_sis300(struct pci_dev *pdev)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004378{
4379 struct sis_video_info *ivideo = pci_get_drvdata(pdev);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004380 unsigned char *bios = ivideo->SiS_Pr.VirtualRomBase;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004381 u8 reg, v1, v2, v3, v4, v5, v6, v7, v8;
4382 u16 index, rindex, memtype = 0;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004383 unsigned int mapsize;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004384
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004385 if(!ivideo->SiS_Pr.UseROM)
4386 bios = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004387
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004388 outSISIDXREG(SISSR, 0x05, 0x86);
4389
4390 if(bios) {
4391 if(bios[0x52] & 0x80) {
4392 memtype = bios[0x52];
4393 } else {
4394 inSISIDXREG(SISSR, 0x3a, memtype);
4395 }
4396 memtype &= 0x07;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004397 }
4398
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004399 v3 = 0x80; v6 = 0x80;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004400 if(ivideo->revision_id <= 0x13) {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004401 v1 = 0x44; v2 = 0x42;
4402 v4 = 0x44; v5 = 0x42;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004403 } else {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004404 v1 = 0x68; v2 = 0x43; /* Assume 125Mhz MCLK */
4405 v4 = 0x68; v5 = 0x43; /* Assume 125Mhz ECLK */
4406 if(bios) {
4407 index = memtype * 5;
4408 rindex = index + 0x54;
4409 v1 = bios[rindex++];
4410 v2 = bios[rindex++];
4411 v3 = bios[rindex++];
4412 rindex = index + 0x7c;
4413 v4 = bios[rindex++];
4414 v5 = bios[rindex++];
4415 v6 = bios[rindex++];
4416 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004417 }
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004418 outSISIDXREG(SISSR, 0x28, v1);
4419 outSISIDXREG(SISSR, 0x29, v2);
4420 outSISIDXREG(SISSR, 0x2a, v3);
4421 outSISIDXREG(SISSR, 0x2e, v4);
4422 outSISIDXREG(SISSR, 0x2f, v5);
4423 outSISIDXREG(SISSR, 0x30, v6);
4424
Linus Torvalds1da177e2005-04-16 15:20:36 -07004425 v1 = 0x10;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004426 if(bios)
4427 v1 = bios[0xa4];
4428 outSISIDXREG(SISSR, 0x07, v1); /* DAC speed */
4429
4430 outSISIDXREG(SISSR, 0x11, 0x0f); /* DDC, power save */
4431
Linus Torvalds1da177e2005-04-16 15:20:36 -07004432 v1 = 0x01; v2 = 0x43; v3 = 0x1e; v4 = 0x2a;
4433 v5 = 0x06; v6 = 0x00; v7 = 0x00; v8 = 0x00;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004434 if(bios) {
4435 memtype += 0xa5;
4436 v1 = bios[memtype];
4437 v2 = bios[memtype + 8];
4438 v3 = bios[memtype + 16];
4439 v4 = bios[memtype + 24];
4440 v5 = bios[memtype + 32];
4441 v6 = bios[memtype + 40];
4442 v7 = bios[memtype + 48];
4443 v8 = bios[memtype + 56];
Linus Torvalds1da177e2005-04-16 15:20:36 -07004444 }
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004445 if(ivideo->revision_id >= 0x80)
4446 v3 &= 0xfd;
4447 outSISIDXREG(SISSR, 0x15, v1); /* Ram type (assuming 0, BIOS 0xa5 step 8) */
4448 outSISIDXREG(SISSR, 0x16, v2);
4449 outSISIDXREG(SISSR, 0x17, v3);
4450 outSISIDXREG(SISSR, 0x18, v4);
4451 outSISIDXREG(SISSR, 0x19, v5);
4452 outSISIDXREG(SISSR, 0x1a, v6);
4453 outSISIDXREG(SISSR, 0x1b, v7);
4454 outSISIDXREG(SISSR, 0x1c, v8); /* ---- */
4455 andSISIDXREG(SISSR, 0x15 ,0xfb);
4456 orSISIDXREG(SISSR, 0x15, 0x04);
4457 if(bios) {
4458 if(bios[0x53] & 0x02) {
4459 orSISIDXREG(SISSR, 0x19, 0x20);
4460 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004461 }
4462 v1 = 0x04; /* DAC pedestal (BIOS 0xe5) */
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004463 if(ivideo->revision_id >= 0x80)
4464 v1 |= 0x01;
4465 outSISIDXREG(SISSR, 0x1f, v1);
4466 outSISIDXREG(SISSR, 0x20, 0xa4); /* linear & relocated io & disable a0000 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07004467 v1 = 0xf6; v2 = 0x0d; v3 = 0x00;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004468 if(bios) {
4469 v1 = bios[0xe8];
4470 v2 = bios[0xe9];
4471 v3 = bios[0xea];
Linus Torvalds1da177e2005-04-16 15:20:36 -07004472 }
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004473 outSISIDXREG(SISSR, 0x23, v1);
4474 outSISIDXREG(SISSR, 0x24, v2);
4475 outSISIDXREG(SISSR, 0x25, v3);
4476 outSISIDXREG(SISSR, 0x21, 0x84);
4477 outSISIDXREG(SISSR, 0x22, 0x00);
4478 outSISIDXREG(SISCR, 0x37, 0x00);
4479 orSISIDXREG(SISPART1, 0x24, 0x01); /* unlock crt2 */
4480 outSISIDXREG(SISPART1, 0x00, 0x00);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004481 v1 = 0x40; v2 = 0x11;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004482 if(bios) {
4483 v1 = bios[0xec];
4484 v2 = bios[0xeb];
Linus Torvalds1da177e2005-04-16 15:20:36 -07004485 }
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004486 outSISIDXREG(SISPART1, 0x02, v1);
4487
4488 if(ivideo->revision_id >= 0x80)
4489 v2 &= ~0x01;
4490
4491 inSISIDXREG(SISPART4, 0x00, reg);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004492 if((reg == 1) || (reg == 2)) {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004493 outSISIDXREG(SISCR, 0x37, 0x02);
4494 outSISIDXREG(SISPART2, 0x00, 0x1c);
4495 v4 = 0x00; v5 = 0x00; v6 = 0x10;
4496 if(ivideo->SiS_Pr.UseROM) {
4497 v4 = bios[0xf5];
4498 v5 = bios[0xf6];
4499 v6 = bios[0xf7];
4500 }
4501 outSISIDXREG(SISPART4, 0x0d, v4);
4502 outSISIDXREG(SISPART4, 0x0e, v5);
4503 outSISIDXREG(SISPART4, 0x10, v6);
4504 outSISIDXREG(SISPART4, 0x0f, 0x3f);
4505 inSISIDXREG(SISPART4, 0x01, reg);
4506 if(reg >= 0xb0) {
4507 inSISIDXREG(SISPART4, 0x23, reg);
4508 reg &= 0x20;
4509 reg <<= 1;
4510 outSISIDXREG(SISPART4, 0x23, reg);
4511 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004512 } else {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004513 v2 &= ~0x10;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004514 }
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004515 outSISIDXREG(SISSR, 0x32, v2);
4516
4517 andSISIDXREG(SISPART1, 0x24, 0xfe); /* Lock CRT2 */
4518
4519 inSISIDXREG(SISSR, 0x16, reg);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004520 reg &= 0xc3;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004521 outSISIDXREG(SISCR, 0x35, reg);
4522 outSISIDXREG(SISCR, 0x83, 0x00);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004523#if !defined(__i386__) && !defined(__x86_64__)
4524 if(sisfb_videoram) {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004525 outSISIDXREG(SISSR, 0x13, 0x28); /* ? */
4526 reg = ((sisfb_videoram >> 10) - 1) | 0x40;
4527 outSISIDXREG(SISSR, 0x14, reg);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004528 } else {
4529#endif
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004530 /* Need to map max FB size for finding out about RAM size */
4531 mapsize = 64 << 20;
4532 sisfb_post_map_vram(ivideo, &mapsize, 4);
4533
4534 if(ivideo->video_vbase) {
4535 sisfb_post_300_ramsize(pdev, mapsize);
4536 iounmap(ivideo->video_vbase);
4537 } else {
4538 printk(KERN_DEBUG
4539 "sisfb: Failed to map memory for size detection, assuming 8MB\n");
4540 outSISIDXREG(SISSR, 0x13, 0x28); /* ? */
4541 outSISIDXREG(SISSR, 0x14, 0x47); /* 8MB, 64bit default */
4542 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004543#if !defined(__i386__) && !defined(__x86_64__)
4544 }
4545#endif
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004546 if(bios) {
4547 v1 = bios[0xe6];
4548 v2 = bios[0xe7];
Linus Torvalds1da177e2005-04-16 15:20:36 -07004549 } else {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004550 inSISIDXREG(SISSR, 0x3a, reg);
4551 if((reg & 0x30) == 0x30) {
4552 v1 = 0x04; /* PCI */
4553 v2 = 0x92;
4554 } else {
4555 v1 = 0x14; /* AGP */
4556 v2 = 0xb2;
4557 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004558 }
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004559 outSISIDXREG(SISSR, 0x21, v1);
4560 outSISIDXREG(SISSR, 0x22, v2);
4561
4562 /* Sense CRT1 */
4563 sisfb_sense_crt1(ivideo);
4564
4565 /* Set default mode, don't clear screen */
Richard Knutssonc30660ea2007-02-12 00:55:06 -08004566 ivideo->SiS_Pr.SiS_UseOEM = false;
4567 SiS_SetEnableDstn(&ivideo->SiS_Pr, false);
4568 SiS_SetEnableFstn(&ivideo->SiS_Pr, false);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004569 ivideo->curFSTN = ivideo->curDSTN = 0;
4570 ivideo->SiS_Pr.VideoMemorySize = 8 << 20;
4571 SiSSetMode(&ivideo->SiS_Pr, 0x2e | 0x80);
4572
4573 outSISIDXREG(SISSR, 0x05, 0x86);
4574
4575 /* Display off */
4576 orSISIDXREG(SISSR, 0x01, 0x20);
4577
4578 /* Save mode number in CR34 */
4579 outSISIDXREG(SISCR, 0x34, 0x2e);
4580
4581 /* Let everyone know what the current mode is */
4582 ivideo->modeprechange = 0x2e;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004583}
4584#endif
4585
4586#ifdef CONFIG_FB_SIS_315
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004587#if 0
4588static void __devinit
4589sisfb_post_sis315330(struct pci_dev *pdev)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004590{
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004591 /* TODO */
Linus Torvalds1da177e2005-04-16 15:20:36 -07004592}
4593#endif
4594
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004595static void __devinit
4596sisfb_post_xgi_delay(struct sis_video_info *ivideo, int delay)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004597{
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004598 unsigned int i;
4599 u8 reg;
4600
4601 for(i = 0; i <= (delay * 10 * 36); i++) {
4602 inSISIDXREG(SISSR, 0x05, reg);
4603 reg++;
4604 }
4605}
4606
4607static int __devinit
4608sisfb_find_host_bridge(struct sis_video_info *ivideo, struct pci_dev *mypdev,
4609 unsigned short pcivendor)
4610{
4611 struct pci_dev *pdev = NULL;
4612 unsigned short temp;
4613 int ret = 0;
4614
Adrian Bunk0959f0c2007-05-08 00:39:50 -07004615 while((pdev = pci_get_class(PCI_CLASS_BRIDGE_HOST, pdev))) {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004616 temp = pdev->vendor;
Adrian Bunk0959f0c2007-05-08 00:39:50 -07004617 pci_dev_put(pdev);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004618 if(temp == pcivendor) {
4619 ret = 1;
4620 break;
4621 }
4622 }
4623
4624 return ret;
4625}
4626
4627static int __devinit
4628sisfb_post_xgi_rwtest(struct sis_video_info *ivideo, int starta,
4629 unsigned int enda, unsigned int mapsize)
4630{
4631 unsigned int pos;
4632 int i;
4633
4634 writel(0, ivideo->video_vbase);
4635
4636 for(i = starta; i <= enda; i++) {
4637 pos = 1 << i;
4638 if(pos < mapsize)
4639 writel(pos, ivideo->video_vbase + pos);
4640 }
4641
4642 sisfb_post_xgi_delay(ivideo, 150);
4643
4644 if(readl(ivideo->video_vbase) != 0)
4645 return 0;
4646
4647 for(i = starta; i <= enda; i++) {
4648 pos = 1 << i;
4649 if(pos < mapsize) {
4650 if(readl(ivideo->video_vbase + pos) != pos)
4651 return 0;
4652 } else
4653 return 0;
4654 }
4655
4656 return 1;
4657}
4658
4659static void __devinit
4660sisfb_post_xgi_ramsize(struct sis_video_info *ivideo)
4661{
4662 unsigned int buswidth, ranksize, channelab, mapsize;
4663 int i, j, k, l;
4664 u8 reg, sr14;
4665 static const u8 dramsr13[12 * 5] = {
4666 0x02, 0x0e, 0x0b, 0x80, 0x5d,
4667 0x02, 0x0e, 0x0a, 0x40, 0x59,
4668 0x02, 0x0d, 0x0b, 0x40, 0x4d,
4669 0x02, 0x0e, 0x09, 0x20, 0x55,
4670 0x02, 0x0d, 0x0a, 0x20, 0x49,
4671 0x02, 0x0c, 0x0b, 0x20, 0x3d,
4672 0x02, 0x0e, 0x08, 0x10, 0x51,
4673 0x02, 0x0d, 0x09, 0x10, 0x45,
4674 0x02, 0x0c, 0x0a, 0x10, 0x39,
4675 0x02, 0x0d, 0x08, 0x08, 0x41,
4676 0x02, 0x0c, 0x09, 0x08, 0x35,
4677 0x02, 0x0c, 0x08, 0x04, 0x31
4678 };
4679 static const u8 dramsr13_4[4 * 5] = {
4680 0x02, 0x0d, 0x09, 0x40, 0x45,
4681 0x02, 0x0c, 0x09, 0x20, 0x35,
4682 0x02, 0x0c, 0x08, 0x10, 0x31,
4683 0x02, 0x0b, 0x08, 0x08, 0x21
4684 };
4685
4686 /* Enable linear mode, disable 0xa0000 address decoding */
4687 /* We disable a0000 address decoding, because
4688 * - if running on x86, if the card is disabled, it means
4689 * that another card is in the system. We don't want
4690 * to interphere with that primary card's textmode.
4691 * - if running on non-x86, there usually is no VGA window
4692 * at a0000.
4693 */
4694 orSISIDXREG(SISSR, 0x20, (0x80 | 0x04));
4695
4696 /* Need to map max FB size for finding out about RAM size */
4697 mapsize = 256 << 20;
4698 sisfb_post_map_vram(ivideo, &mapsize, 32);
4699
4700 if(!ivideo->video_vbase) {
4701 printk(KERN_ERR "sisfb: Unable to detect RAM size. Setting default.\n");
4702 outSISIDXREG(SISSR, 0x13, 0x35);
4703 outSISIDXREG(SISSR, 0x14, 0x41);
4704 /* TODO */
4705 return;
4706 }
4707
4708 /* Non-interleaving */
4709 outSISIDXREG(SISSR, 0x15, 0x00);
4710 /* No tiling */
4711 outSISIDXREG(SISSR, 0x1c, 0x00);
4712
4713 if(ivideo->chip == XGI_20) {
4714
4715 channelab = 1;
4716 inSISIDXREG(SISCR, 0x97, reg);
4717 if(!(reg & 0x01)) { /* Single 32/16 */
4718 buswidth = 32;
4719 outSISIDXREG(SISSR, 0x13, 0xb1);
4720 outSISIDXREG(SISSR, 0x14, 0x52);
4721 sisfb_post_xgi_delay(ivideo, 1);
4722 sr14 = 0x02;
4723 if(sisfb_post_xgi_rwtest(ivideo, 23, 24, mapsize))
4724 goto bail_out;
4725
4726 outSISIDXREG(SISSR, 0x13, 0x31);
4727 outSISIDXREG(SISSR, 0x14, 0x42);
4728 sisfb_post_xgi_delay(ivideo, 1);
4729 if(sisfb_post_xgi_rwtest(ivideo, 23, 23, mapsize))
4730 goto bail_out;
4731
4732 buswidth = 16;
4733 outSISIDXREG(SISSR, 0x13, 0xb1);
4734 outSISIDXREG(SISSR, 0x14, 0x41);
4735 sisfb_post_xgi_delay(ivideo, 1);
4736 sr14 = 0x01;
4737 if(sisfb_post_xgi_rwtest(ivideo, 22, 23, mapsize))
4738 goto bail_out;
4739 else
4740 outSISIDXREG(SISSR, 0x13, 0x31);
4741 } else { /* Dual 16/8 */
4742 buswidth = 16;
4743 outSISIDXREG(SISSR, 0x13, 0xb1);
4744 outSISIDXREG(SISSR, 0x14, 0x41);
4745 sisfb_post_xgi_delay(ivideo, 1);
4746 sr14 = 0x01;
4747 if(sisfb_post_xgi_rwtest(ivideo, 22, 23, mapsize))
4748 goto bail_out;
4749
4750 outSISIDXREG(SISSR, 0x13, 0x31);
4751 outSISIDXREG(SISSR, 0x14, 0x31);
4752 sisfb_post_xgi_delay(ivideo, 1);
4753 if(sisfb_post_xgi_rwtest(ivideo, 22, 22, mapsize))
4754 goto bail_out;
4755
4756 buswidth = 8;
4757 outSISIDXREG(SISSR, 0x13, 0xb1);
4758 outSISIDXREG(SISSR, 0x14, 0x30);
4759 sisfb_post_xgi_delay(ivideo, 1);
4760 sr14 = 0x00;
4761 if(sisfb_post_xgi_rwtest(ivideo, 21, 22, mapsize))
4762 goto bail_out;
4763 else
4764 outSISIDXREG(SISSR, 0x13, 0x31);
4765 }
4766
4767 } else { /* XGI_40 */
4768
4769 inSISIDXREG(SISCR, 0x97, reg);
4770 if(!(reg & 0x10)) {
4771 inSISIDXREG(SISSR, 0x39, reg);
4772 reg >>= 1;
4773 }
4774
4775 if(reg & 0x01) { /* DDRII */
4776 buswidth = 32;
4777 if(ivideo->revision_id == 2) {
4778 channelab = 2;
4779 outSISIDXREG(SISSR, 0x13, 0xa1);
4780 outSISIDXREG(SISSR, 0x14, 0x44);
4781 sr14 = 0x04;
4782 sisfb_post_xgi_delay(ivideo, 1);
4783 if(sisfb_post_xgi_rwtest(ivideo, 23, 24, mapsize))
4784 goto bail_out;
4785
4786 outSISIDXREG(SISSR, 0x13, 0x21);
4787 outSISIDXREG(SISSR, 0x14, 0x34);
4788 if(sisfb_post_xgi_rwtest(ivideo, 22, 23, mapsize))
4789 goto bail_out;
4790
4791 channelab = 1;
4792 outSISIDXREG(SISSR, 0x13, 0xa1);
4793 outSISIDXREG(SISSR, 0x14, 0x40);
4794 sr14 = 0x00;
4795 if(sisfb_post_xgi_rwtest(ivideo, 22, 23, mapsize))
4796 goto bail_out;
4797
4798 outSISIDXREG(SISSR, 0x13, 0x21);
4799 outSISIDXREG(SISSR, 0x14, 0x30);
4800 } else {
4801 channelab = 3;
4802 outSISIDXREG(SISSR, 0x13, 0xa1);
4803 outSISIDXREG(SISSR, 0x14, 0x4c);
4804 sr14 = 0x0c;
4805 sisfb_post_xgi_delay(ivideo, 1);
4806 if(sisfb_post_xgi_rwtest(ivideo, 23, 25, mapsize))
4807 goto bail_out;
4808
4809 channelab = 2;
4810 outSISIDXREG(SISSR, 0x14, 0x48);
4811 sisfb_post_xgi_delay(ivideo, 1);
4812 sr14 = 0x08;
4813 if(sisfb_post_xgi_rwtest(ivideo, 23, 24, mapsize))
4814 goto bail_out;
4815
4816 outSISIDXREG(SISSR, 0x13, 0x21);
4817 outSISIDXREG(SISSR, 0x14, 0x3c);
4818 sr14 = 0x0c;
4819
4820 if(sisfb_post_xgi_rwtest(ivideo, 23, 24, mapsize)) {
4821 channelab = 3;
4822 } else {
4823 channelab = 2;
4824 outSISIDXREG(SISSR, 0x14, 0x38);
4825 sr14 = 0x08;
4826 }
4827 }
4828 sisfb_post_xgi_delay(ivideo, 1);
4829
4830 } else { /* DDR */
4831
4832 buswidth = 64;
4833 if(ivideo->revision_id == 2) {
4834 channelab = 1;
4835 outSISIDXREG(SISSR, 0x13, 0xa1);
4836 outSISIDXREG(SISSR, 0x14, 0x52);
4837 sisfb_post_xgi_delay(ivideo, 1);
4838 sr14 = 0x02;
4839 if(sisfb_post_xgi_rwtest(ivideo, 23, 24, mapsize))
4840 goto bail_out;
4841
4842 outSISIDXREG(SISSR, 0x13, 0x21);
4843 outSISIDXREG(SISSR, 0x14, 0x42);
4844 } else {
4845 channelab = 2;
4846 outSISIDXREG(SISSR, 0x13, 0xa1);
4847 outSISIDXREG(SISSR, 0x14, 0x5a);
4848 sisfb_post_xgi_delay(ivideo, 1);
4849 sr14 = 0x0a;
4850 if(sisfb_post_xgi_rwtest(ivideo, 24, 25, mapsize))
4851 goto bail_out;
4852
4853 outSISIDXREG(SISSR, 0x13, 0x21);
4854 outSISIDXREG(SISSR, 0x14, 0x4a);
4855 }
4856 sisfb_post_xgi_delay(ivideo, 1);
4857
4858 }
4859 }
4860
4861bail_out:
4862 setSISIDXREG(SISSR, 0x14, 0xf0, sr14);
4863 sisfb_post_xgi_delay(ivideo, 1);
4864
4865 j = (ivideo->chip == XGI_20) ? 5 : 9;
4866 k = (ivideo->chip == XGI_20) ? 12 : 4;
4867
4868 for(i = 0; i < k; i++) {
4869
4870 reg = (ivideo->chip == XGI_20) ?
4871 dramsr13[(i * 5) + 4] : dramsr13_4[(i * 5) + 4];
4872 setSISIDXREG(SISSR, 0x13, 0x80, reg);
4873 sisfb_post_xgi_delay(ivideo, 50);
4874
4875 ranksize = (ivideo->chip == XGI_20) ?
4876 dramsr13[(i * 5) + 3] : dramsr13_4[(i * 5) + 3];
4877
4878 inSISIDXREG(SISSR, 0x13, reg);
4879 if(reg & 0x80) ranksize <<= 1;
4880
4881 if(ivideo->chip == XGI_20) {
4882 if(buswidth == 16) ranksize <<= 1;
4883 else if(buswidth == 32) ranksize <<= 2;
4884 } else {
4885 if(buswidth == 64) ranksize <<= 1;
4886 }
4887
4888 reg = 0;
4889 l = channelab;
4890 if(l == 3) l = 4;
4891 if((ranksize * l) <= 256) {
4892 while((ranksize >>= 1)) reg += 0x10;
4893 }
4894
4895 if(!reg) continue;
4896
4897 setSISIDXREG(SISSR, 0x14, 0x0f, (reg & 0xf0));
4898 sisfb_post_xgi_delay(ivideo, 1);
4899
4900 if(sisfb_post_xgi_rwtest(ivideo, j, ((reg >> 4) + channelab - 2 + 20), mapsize))
4901 break;
4902 }
4903
4904 iounmap(ivideo->video_vbase);
4905}
4906
4907static void __devinit
4908sisfb_post_xgi_setclocks(struct sis_video_info *ivideo, u8 regb)
4909{
4910 u8 v1, v2, v3;
4911 int index;
4912 static const u8 cs90[8 * 3] = {
4913 0x16, 0x01, 0x01,
4914 0x3e, 0x03, 0x01,
4915 0x7c, 0x08, 0x01,
4916 0x79, 0x06, 0x01,
4917 0x29, 0x01, 0x81,
4918 0x5c, 0x23, 0x01,
4919 0x5c, 0x23, 0x01,
4920 0x5c, 0x23, 0x01
4921 };
4922 static const u8 csb8[8 * 3] = {
4923 0x5c, 0x23, 0x01,
4924 0x29, 0x01, 0x01,
4925 0x7c, 0x08, 0x01,
4926 0x79, 0x06, 0x01,
4927 0x29, 0x01, 0x81,
4928 0x5c, 0x23, 0x01,
4929 0x5c, 0x23, 0x01,
4930 0x5c, 0x23, 0x01
4931 };
4932
4933 regb = 0; /* ! */
4934
4935 index = regb * 3;
4936 v1 = cs90[index]; v2 = cs90[index + 1]; v3 = cs90[index + 2];
4937 if(ivideo->haveXGIROM) {
4938 v1 = ivideo->bios_abase[0x90 + index];
4939 v2 = ivideo->bios_abase[0x90 + index + 1];
4940 v3 = ivideo->bios_abase[0x90 + index + 2];
4941 }
4942 outSISIDXREG(SISSR, 0x28, v1);
4943 outSISIDXREG(SISSR, 0x29, v2);
4944 outSISIDXREG(SISSR, 0x2a, v3);
4945 sisfb_post_xgi_delay(ivideo, 0x43);
4946 sisfb_post_xgi_delay(ivideo, 0x43);
4947 sisfb_post_xgi_delay(ivideo, 0x43);
4948 index = regb * 3;
4949 v1 = csb8[index]; v2 = csb8[index + 1]; v3 = csb8[index + 2];
4950 if(ivideo->haveXGIROM) {
4951 v1 = ivideo->bios_abase[0xb8 + index];
4952 v2 = ivideo->bios_abase[0xb8 + index + 1];
4953 v3 = ivideo->bios_abase[0xb8 + index + 2];
4954 }
4955 outSISIDXREG(SISSR, 0x2e, v1);
4956 outSISIDXREG(SISSR, 0x2f, v2);
4957 outSISIDXREG(SISSR, 0x30, v3);
4958 sisfb_post_xgi_delay(ivideo, 0x43);
4959 sisfb_post_xgi_delay(ivideo, 0x43);
4960 sisfb_post_xgi_delay(ivideo, 0x43);
4961}
4962
4963static int __devinit
4964sisfb_post_xgi(struct pci_dev *pdev)
4965{
4966 struct sis_video_info *ivideo = pci_get_drvdata(pdev);
4967 unsigned char *bios = ivideo->bios_abase;
4968 struct pci_dev *mypdev = NULL;
4969 const u8 *ptr, *ptr2;
4970 u8 v1, v2, v3, v4, v5, reg, ramtype;
4971 u32 rega, regb, regd;
4972 int i, j, k, index;
4973 static const u8 cs78[3] = { 0xf6, 0x0d, 0x00 };
4974 static const u8 cs76[2] = { 0xa3, 0xfb };
4975 static const u8 cs7b[3] = { 0xc0, 0x11, 0x00 };
4976 static const u8 cs158[8] = {
4977 0x88, 0xaa, 0x48, 0x00, 0x00, 0x00, 0x00, 0x00
4978 };
4979 static const u8 cs160[8] = {
4980 0x44, 0x77, 0x77, 0x00, 0x00, 0x00, 0x00, 0x00
4981 };
4982 static const u8 cs168[8] = {
4983 0x48, 0x78, 0x88, 0x00, 0x00, 0x00, 0x00, 0x00
4984 };
4985 static const u8 cs128[3 * 8] = {
4986 0x90, 0x28, 0x24, 0x00, 0x00, 0x00, 0x00, 0x00,
4987 0x77, 0x44, 0x44, 0x00, 0x00, 0x00, 0x00, 0x00,
4988 0x77, 0x44, 0x44, 0x00, 0x00, 0x00, 0x00, 0x00
4989 };
4990 static const u8 cs148[2 * 8] = {
4991 0x55, 0x55, 0x55, 0x00, 0x00, 0x00, 0x00, 0x00,
4992 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
4993 };
4994 static const u8 cs31a[8 * 4] = {
4995 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
4996 0xaa, 0xaa, 0xaa, 0xaa, 0x00, 0x00, 0x00, 0x00,
4997 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
4998 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
4999 };
5000 static const u8 cs33a[8 * 4] = {
5001 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
5002 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
5003 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
5004 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
5005 };
5006 static const u8 cs45a[8 * 2] = {
5007 0x00, 0x00, 0xa0, 0x00, 0xa0, 0x00, 0x00, 0x00,
5008 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
5009 };
5010 static const u8 cs170[7 * 8] = {
5011 0x54, 0x32, 0x44, 0x00, 0x00, 0x00, 0x00, 0x00,
5012 0x54, 0x43, 0x44, 0x00, 0x00, 0x00, 0x00, 0x00,
5013 0x0a, 0x05, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00,
5014 0x44, 0x34, 0x44, 0x00, 0x00, 0x00, 0x00, 0x00,
5015 0x10, 0x0a, 0x0a, 0x00, 0x00, 0x00, 0x00, 0x00,
5016 0x11, 0x0c, 0x0c, 0x00, 0x00, 0x00, 0x00, 0x00,
5017 0x05, 0x05, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00
5018 };
5019 static const u8 cs1a8[3 * 8] = {
5020 0xf0, 0xf0, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x00,
5021 0x05, 0x02, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00,
5022 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
5023 };
5024 static const u8 cs100[2 * 8] = {
5025 0xc4, 0x04, 0x84, 0x00, 0x00, 0x00, 0x00, 0x00,
5026 0xc4, 0x04, 0x84, 0x00, 0x00, 0x00, 0x00, 0x00
5027 };
5028
5029 /* VGA enable */
5030 reg = inSISREG(SISVGAENABLE) | 0x01;
5031 outSISREG(SISVGAENABLE, reg);
5032
5033 /* Misc */
5034 reg = inSISREG(SISMISCR) | 0x01;
5035 outSISREG(SISMISCW, reg);
5036
5037 /* Unlock SR */
5038 outSISIDXREG(SISSR, 0x05, 0x86);
5039 inSISIDXREG(SISSR, 0x05, reg);
5040 if(reg != 0xa1)
5041 return 0;
5042
5043 /* Clear some regs */
5044 for(i = 0; i < 0x22; i++) {
5045 if(0x06 + i == 0x20) continue;
5046 outSISIDXREG(SISSR, 0x06 + i, 0x00);
5047 }
5048 for(i = 0; i < 0x0b; i++) {
5049 outSISIDXREG(SISSR, 0x31 + i, 0x00);
5050 }
5051 for(i = 0; i < 0x10; i++) {
5052 outSISIDXREG(SISCR, 0x30 + i, 0x00);
5053 }
5054
5055 ptr = cs78;
5056 if(ivideo->haveXGIROM) {
5057 ptr = (const u8 *)&bios[0x78];
5058 }
5059 for(i = 0; i < 3; i++) {
5060 outSISIDXREG(SISSR, 0x23 + i, ptr[i]);
5061 }
5062
5063 ptr = cs76;
5064 if(ivideo->haveXGIROM) {
5065 ptr = (const u8 *)&bios[0x76];
5066 }
5067 for(i = 0; i < 2; i++) {
5068 outSISIDXREG(SISSR, 0x21 + i, ptr[i]);
5069 }
5070
5071 v1 = 0x18; v2 = 0x00;
5072 if(ivideo->haveXGIROM) {
5073 v1 = bios[0x74];
5074 v2 = bios[0x75];
5075 }
5076 outSISIDXREG(SISSR, 0x07, v1);
5077 outSISIDXREG(SISSR, 0x11, 0x0f);
5078 outSISIDXREG(SISSR, 0x1f, v2);
5079 /* PCI linear mode, RelIO enabled, A0000 decoding disabled */
5080 outSISIDXREG(SISSR, 0x20, 0x80 | 0x20 | 0x04);
5081 outSISIDXREG(SISSR, 0x27, 0x74);
5082
5083 ptr = cs7b;
5084 if(ivideo->haveXGIROM) {
5085 ptr = (const u8 *)&bios[0x7b];
5086 }
5087 for(i = 0; i < 3; i++) {
5088 outSISIDXREG(SISSR, 0x31 + i, ptr[i]);
5089 }
5090
5091 if(ivideo->chip == XGI_40) {
5092 if(ivideo->revision_id == 2) {
5093 setSISIDXREG(SISSR, 0x3b, 0x3f, 0xc0);
5094 }
5095 outSISIDXREG(SISCR, 0x7d, 0xfe);
5096 outSISIDXREG(SISCR, 0x7e, 0x0f);
5097 }
5098 if(ivideo->revision_id == 0) { /* 40 *and* 20? */
5099 andSISIDXREG(SISCR, 0x58, 0xd7);
5100 inSISIDXREG(SISCR, 0xcb, reg);
5101 if(reg & 0x20) {
5102 setSISIDXREG(SISCR, 0x58, 0xd7, (reg & 0x10) ? 0x08 : 0x20); /* =0x28 Z7 ? */
5103 }
5104 }
5105
5106 reg = (ivideo->chip == XGI_40) ? 0x20 : 0x00;
5107 setSISIDXREG(SISCR, 0x38, 0x1f, reg);
5108
5109 if(ivideo->chip == XGI_20) {
5110 outSISIDXREG(SISSR, 0x36, 0x70);
5111 } else {
5112 outSISIDXREG(SISVID, 0x00, 0x86);
5113 outSISIDXREG(SISVID, 0x32, 0x00);
5114 outSISIDXREG(SISVID, 0x30, 0x00);
5115 outSISIDXREG(SISVID, 0x32, 0x01);
5116 outSISIDXREG(SISVID, 0x30, 0x00);
5117 andSISIDXREG(SISVID, 0x2f, 0xdf);
5118 andSISIDXREG(SISCAP, 0x00, 0x3f);
5119
5120 outSISIDXREG(SISPART1, 0x2f, 0x01);
5121 outSISIDXREG(SISPART1, 0x00, 0x00);
5122 outSISIDXREG(SISPART1, 0x02, bios[0x7e]);
5123 outSISIDXREG(SISPART1, 0x2e, 0x08);
5124 andSISIDXREG(SISPART1, 0x35, 0x7f);
5125 andSISIDXREG(SISPART1, 0x50, 0xfe);
5126
5127 inSISIDXREG(SISPART4, 0x00, reg);
5128 if(reg == 1 || reg == 2) {
5129 outSISIDXREG(SISPART2, 0x00, 0x1c);
5130 outSISIDXREG(SISPART4, 0x0d, bios[0x7f]);
5131 outSISIDXREG(SISPART4, 0x0e, bios[0x80]);
5132 outSISIDXREG(SISPART4, 0x10, bios[0x81]);
5133 andSISIDXREG(SISPART4, 0x0f, 0x3f);
5134
5135 inSISIDXREG(SISPART4, 0x01, reg);
5136 if((reg & 0xf0) >= 0xb0) {
5137 inSISIDXREG(SISPART4, 0x23, reg);
5138 if(reg & 0x20) reg |= 0x40;
5139 outSISIDXREG(SISPART4, 0x23, reg);
5140 reg = (reg & 0x20) ? 0x02 : 0x00;
5141 setSISIDXREG(SISPART1, 0x1e, 0xfd, reg);
5142 }
5143 }
5144
5145 v1 = bios[0x77];
5146
5147 inSISIDXREG(SISSR, 0x3b, reg);
5148 if(reg & 0x02) {
5149 inSISIDXREG(SISSR, 0x3a, reg);
5150 v2 = (reg & 0x30) >> 3;
5151 if(!(v2 & 0x04)) v2 ^= 0x02;
5152 inSISIDXREG(SISSR, 0x39, reg);
5153 if(reg & 0x80) v2 |= 0x80;
5154 v2 |= 0x01;
5155
Adrian Bunk0959f0c2007-05-08 00:39:50 -07005156 if((mypdev = pci_get_device(PCI_VENDOR_ID_SI, 0x0730, NULL))) {
5157 pci_dev_put(mypdev);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07005158 if(((v2 & 0x06) == 2) || ((v2 & 0x06) == 4))
5159 v2 &= 0xf9;
5160 v2 |= 0x08;
5161 v1 &= 0xfe;
5162 } else {
Adrian Bunk0959f0c2007-05-08 00:39:50 -07005163 mypdev = pci_get_device(PCI_VENDOR_ID_SI, 0x0735, NULL);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07005164 if(!mypdev)
Adrian Bunk0959f0c2007-05-08 00:39:50 -07005165 mypdev = pci_get_device(PCI_VENDOR_ID_SI, 0x0645, NULL);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07005166 if(!mypdev)
Adrian Bunk0959f0c2007-05-08 00:39:50 -07005167 mypdev = pci_get_device(PCI_VENDOR_ID_SI, 0x0650, NULL);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07005168 if(mypdev) {
5169 pci_read_config_dword(mypdev, 0x94, &regd);
5170 regd &= 0xfffffeff;
5171 pci_write_config_dword(mypdev, 0x94, regd);
5172 v1 &= 0xfe;
Adrian Bunk0959f0c2007-05-08 00:39:50 -07005173 pci_dev_put(mypdev);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07005174 } else if(sisfb_find_host_bridge(ivideo, pdev, PCI_VENDOR_ID_SI)) {
5175 v1 &= 0xfe;
5176 } else if(sisfb_find_host_bridge(ivideo, pdev, 0x1106) ||
5177 sisfb_find_host_bridge(ivideo, pdev, 0x1022) ||
5178 sisfb_find_host_bridge(ivideo, pdev, 0x700e) ||
5179 sisfb_find_host_bridge(ivideo, pdev, 0x10de)) {
5180 if((v2 & 0x06) == 4)
5181 v2 ^= 0x06;
5182 v2 |= 0x08;
5183 }
5184 }
5185 setSISIDXREG(SISCR, 0x5f, 0xf0, v2);
5186 }
5187 outSISIDXREG(SISSR, 0x22, v1);
5188
5189 if(ivideo->revision_id == 2) {
5190 inSISIDXREG(SISSR, 0x3b, v1);
5191 inSISIDXREG(SISSR, 0x3a, v2);
5192 regd = bios[0x90 + 3] | (bios[0x90 + 4] << 8);
5193 if( (!(v1 & 0x02)) && (v2 & 0x30) && (regd < 0xcf) )
5194 setSISIDXREG(SISCR, 0x5f, 0xf1, 0x01);
5195
Adrian Bunk0959f0c2007-05-08 00:39:50 -07005196 if((mypdev = pci_get_device(0x10de, 0x01e0, NULL))) {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07005197 /* TODO: set CR5f &0xf1 | 0x01 for version 6570
5198 * of nforce 2 ROM
5199 */
5200 if(0)
5201 setSISIDXREG(SISCR, 0x5f, 0xf1, 0x01);
Adrian Bunk0959f0c2007-05-08 00:39:50 -07005202 pci_dev_put(mypdev);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07005203 }
5204 }
5205
5206 v1 = 0x30;
5207 inSISIDXREG(SISSR, 0x3b, reg);
5208 inSISIDXREG(SISCR, 0x5f, v2);
5209 if((!(reg & 0x02)) && (v2 & 0x0e))
5210 v1 |= 0x08;
5211 outSISIDXREG(SISSR, 0x27, v1);
5212
5213 if(bios[0x64] & 0x01) {
5214 setSISIDXREG(SISCR, 0x5f, 0xf0, bios[0x64]);
5215 }
5216
5217 v1 = bios[0x4f7];
5218 pci_read_config_dword(pdev, 0x50, &regd);
5219 regd = (regd >> 20) & 0x0f;
5220 if(regd == 1) {
5221 v1 &= 0xfc;
5222 orSISIDXREG(SISCR, 0x5f, 0x08);
5223 }
5224 outSISIDXREG(SISCR, 0x48, v1);
5225
5226 setSISIDXREG(SISCR, 0x47, 0x04, bios[0x4f6] & 0xfb);
5227 setSISIDXREG(SISCR, 0x49, 0xf0, bios[0x4f8] & 0x0f);
5228 setSISIDXREG(SISCR, 0x4a, 0x60, bios[0x4f9] & 0x9f);
5229 setSISIDXREG(SISCR, 0x4b, 0x08, bios[0x4fa] & 0xf7);
5230 setSISIDXREG(SISCR, 0x4c, 0x80, bios[0x4fb] & 0x7f);
5231 outSISIDXREG(SISCR, 0x70, bios[0x4fc]);
5232 setSISIDXREG(SISCR, 0x71, 0xf0, bios[0x4fd] & 0x0f);
5233 outSISIDXREG(SISCR, 0x74, 0xd0);
5234 setSISIDXREG(SISCR, 0x74, 0xcf, bios[0x4fe] & 0x30);
5235 setSISIDXREG(SISCR, 0x75, 0xe0, bios[0x4ff] & 0x1f);
5236 setSISIDXREG(SISCR, 0x76, 0xe0, bios[0x500] & 0x1f);
5237 v1 = bios[0x501];
Adrian Bunk0959f0c2007-05-08 00:39:50 -07005238 if((mypdev = pci_get_device(0x8086, 0x2530, NULL))) {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07005239 v1 = 0xf0;
Adrian Bunk0959f0c2007-05-08 00:39:50 -07005240 pci_dev_put(mypdev);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07005241 }
5242 outSISIDXREG(SISCR, 0x77, v1);
5243 }
5244
5245 /* RAM type */
5246
5247 regb = 0; /* ! */
5248
5249 v1 = 0xff;
5250 if(ivideo->haveXGIROM) {
5251 v1 = bios[0x140 + regb];
5252 }
5253 outSISIDXREG(SISCR, 0x6d, v1);
5254
5255 ptr = cs128;
5256 if(ivideo->haveXGIROM) {
5257 ptr = (const u8 *)&bios[0x128];
5258 }
5259 for(i = 0, j = 0; i < 3; i++, j += 8) {
5260 outSISIDXREG(SISCR, 0x68 + i, ptr[j + regb]);
5261 }
5262
5263 ptr = cs31a;
5264 ptr2 = cs33a;
5265 if(ivideo->haveXGIROM) {
5266 index = (ivideo->chip == XGI_20) ? 0x31a : 0x3a6;
5267 ptr = (const u8 *)&bios[index];
5268 ptr2 = (const u8 *)&bios[index + 0x20];
5269 }
5270 for(i = 0; i < 2; i++) {
5271 if(i == 0) {
5272 regd = le32_to_cpu(((u32 *)ptr)[regb]);
5273 rega = 0x6b;
5274 } else {
5275 regd = le32_to_cpu(((u32 *)ptr2)[regb]);
5276 rega = 0x6e;
5277 }
5278 reg = 0x00;
5279 for(j = 0; j < 16; j++) {
5280 reg &= 0xf3;
5281 if(regd & 0x01) reg |= 0x04;
5282 if(regd & 0x02) reg |= 0x08;
5283 regd >>= 2;
5284 outSISIDXREG(SISCR, rega, reg);
5285 inSISIDXREG(SISCR, rega, reg);
5286 inSISIDXREG(SISCR, rega, reg);
5287 reg += 0x10;
5288 }
5289 }
5290
5291 andSISIDXREG(SISCR, 0x6e, 0xfc);
5292
5293 ptr = NULL;
5294 if(ivideo->haveXGIROM) {
5295 index = (ivideo->chip == XGI_20) ? 0x35a : 0x3e6;
5296 ptr = (const u8 *)&bios[index];
5297 }
5298 for(i = 0; i < 4; i++) {
5299 setSISIDXREG(SISCR, 0x6e, 0xfc, i);
5300 reg = 0x00;
5301 for(j = 0; j < 2; j++) {
5302 regd = 0;
5303 if(ptr) {
5304 regd = le32_to_cpu(((u32 *)ptr)[regb * 8]);
5305 ptr += 4;
5306 }
5307 /* reg = 0x00; */
5308 for(k = 0; k < 16; k++) {
5309 reg &= 0xfc;
5310 if(regd & 0x01) reg |= 0x01;
5311 if(regd & 0x02) reg |= 0x02;
5312 regd >>= 2;
5313 outSISIDXREG(SISCR, 0x6f, reg);
5314 inSISIDXREG(SISCR, 0x6f, reg);
5315 inSISIDXREG(SISCR, 0x6f, reg);
5316 reg += 0x08;
5317 }
5318 }
5319 }
5320
5321 ptr = cs148;
5322 if(ivideo->haveXGIROM) {
5323 ptr = (const u8 *)&bios[0x148];
5324 }
5325 for(i = 0, j = 0; i < 2; i++, j += 8) {
5326 outSISIDXREG(SISCR, 0x80 + i, ptr[j + regb]);
5327 }
5328
5329 andSISIDXREG(SISCR, 0x89, 0x8f);
5330
5331 ptr = cs45a;
5332 if(ivideo->haveXGIROM) {
5333 index = (ivideo->chip == XGI_20) ? 0x45a : 0x4e6;
5334 ptr = (const u8 *)&bios[index];
5335 }
5336 regd = le16_to_cpu(((const u16 *)ptr)[regb]);
5337 reg = 0x80;
5338 for(i = 0; i < 5; i++) {
5339 reg &= 0xfc;
5340 if(regd & 0x01) reg |= 0x01;
5341 if(regd & 0x02) reg |= 0x02;
5342 regd >>= 2;
5343 outSISIDXREG(SISCR, 0x89, reg);
5344 inSISIDXREG(SISCR, 0x89, reg);
5345 inSISIDXREG(SISCR, 0x89, reg);
5346 reg += 0x10;
5347 }
5348
5349 v1 = 0xb5; v2 = 0x20; v3 = 0xf0; v4 = 0x13;
5350 if(ivideo->haveXGIROM) {
5351 v1 = bios[0x118 + regb];
5352 v2 = bios[0xf8 + regb];
5353 v3 = bios[0x120 + regb];
5354 v4 = bios[0x1ca];
5355 }
5356 outSISIDXREG(SISCR, 0x45, v1 & 0x0f);
5357 outSISIDXREG(SISCR, 0x99, (v1 >> 4) & 0x07);
5358 orSISIDXREG(SISCR, 0x40, v1 & 0x80);
5359 outSISIDXREG(SISCR, 0x41, v2);
5360
5361 ptr = cs170;
5362 if(ivideo->haveXGIROM) {
5363 ptr = (const u8 *)&bios[0x170];
5364 }
5365 for(i = 0, j = 0; i < 7; i++, j += 8) {
5366 outSISIDXREG(SISCR, 0x90 + i, ptr[j + regb]);
5367 }
5368
5369 outSISIDXREG(SISCR, 0x59, v3);
5370
5371 ptr = cs1a8;
5372 if(ivideo->haveXGIROM) {
5373 ptr = (const u8 *)&bios[0x1a8];
5374 }
5375 for(i = 0, j = 0; i < 3; i++, j += 8) {
5376 outSISIDXREG(SISCR, 0xc3 + i, ptr[j + regb]);
5377 }
5378
5379 ptr = cs100;
5380 if(ivideo->haveXGIROM) {
5381 ptr = (const u8 *)&bios[0x100];
5382 }
5383 for(i = 0, j = 0; i < 2; i++, j += 8) {
5384 outSISIDXREG(SISCR, 0x8a + i, ptr[j + regb]);
5385 }
5386
5387 outSISIDXREG(SISCR, 0xcf, v4);
5388
5389 outSISIDXREG(SISCR, 0x83, 0x09);
5390 outSISIDXREG(SISCR, 0x87, 0x00);
5391
5392 if(ivideo->chip == XGI_40) {
5393 if( (ivideo->revision_id == 1) ||
5394 (ivideo->revision_id == 2) ) {
5395 outSISIDXREG(SISCR, 0x8c, 0x87);
5396 }
5397 }
5398
5399 outSISIDXREG(SISSR, 0x17, 0x00);
5400 outSISIDXREG(SISSR, 0x1a, 0x87);
5401
5402 if(ivideo->chip == XGI_20) {
5403 outSISIDXREG(SISSR, 0x15, 0x00);
5404 outSISIDXREG(SISSR, 0x1c, 0x00);
5405 }
5406
5407 ramtype = 0x00; v1 = 0x10;
5408 if(ivideo->haveXGIROM) {
5409 ramtype = bios[0x62];
5410 v1 = bios[0x1d2];
5411 }
5412 if(!(ramtype & 0x80)) {
5413 if(ivideo->chip == XGI_20) {
5414 outSISIDXREG(SISCR, 0x97, v1);
5415 inSISIDXREG(SISCR, 0x97, reg);
5416 if(reg & 0x10) {
5417 ramtype = (reg & 0x01) << 1;
5418 }
5419 } else {
5420 inSISIDXREG(SISSR, 0x39, reg);
5421 ramtype = reg & 0x02;
5422 if(!(ramtype)) {
5423 inSISIDXREG(SISSR, 0x3a, reg);
5424 ramtype = (reg >> 1) & 0x01;
5425 }
5426 }
5427 }
5428 ramtype &= 0x07;
5429
5430 regb = 0; /* ! */
5431
5432 switch(ramtype) {
5433 case 0:
5434 sisfb_post_xgi_setclocks(ivideo, regb);
5435 if((ivideo->chip == XGI_20) ||
5436 (ivideo->revision_id == 1) ||
5437 (ivideo->revision_id == 2)) {
5438 v1 = cs158[regb]; v2 = cs160[regb]; v3 = cs168[regb];
5439 if(ivideo->haveXGIROM) {
5440 v1 = bios[regb + 0x158];
5441 v2 = bios[regb + 0x160];
5442 v3 = bios[regb + 0x168];
5443 }
5444 outSISIDXREG(SISCR, 0x82, v1);
5445 outSISIDXREG(SISCR, 0x85, v2);
5446 outSISIDXREG(SISCR, 0x86, v3);
5447 } else {
5448 outSISIDXREG(SISCR, 0x82, 0x88);
5449 outSISIDXREG(SISCR, 0x86, 0x00);
5450 inSISIDXREG(SISCR, 0x86, reg);
5451 outSISIDXREG(SISCR, 0x86, 0x88);
5452 inSISIDXREG(SISCR, 0x86, reg);
5453 outSISIDXREG(SISCR, 0x86, bios[regb + 0x168]);
5454 outSISIDXREG(SISCR, 0x82, 0x77);
5455 outSISIDXREG(SISCR, 0x85, 0x00);
5456 inSISIDXREG(SISCR, 0x85, reg);
5457 outSISIDXREG(SISCR, 0x85, 0x88);
5458 inSISIDXREG(SISCR, 0x85, reg);
5459 outSISIDXREG(SISCR, 0x85, bios[regb + 0x160]);
5460 outSISIDXREG(SISCR, 0x82, bios[regb + 0x158]);
5461 }
5462 if(ivideo->chip == XGI_40) {
5463 outSISIDXREG(SISCR, 0x97, 0x00);
5464 }
5465 outSISIDXREG(SISCR, 0x98, 0x01);
5466 outSISIDXREG(SISCR, 0x9a, 0x02);
5467
5468 outSISIDXREG(SISSR, 0x18, 0x01);
5469 if((ivideo->chip == XGI_20) ||
5470 (ivideo->revision_id == 2)) {
5471 outSISIDXREG(SISSR, 0x19, 0x40);
5472 } else {
5473 outSISIDXREG(SISSR, 0x19, 0x20);
5474 }
5475 outSISIDXREG(SISSR, 0x16, 0x00);
5476 outSISIDXREG(SISSR, 0x16, 0x80);
5477 if((ivideo->chip == XGI_20) || (bios[0x1cb] != 0x0c)) {
5478 sisfb_post_xgi_delay(ivideo, 0x43);
5479 sisfb_post_xgi_delay(ivideo, 0x43);
5480 sisfb_post_xgi_delay(ivideo, 0x43);
5481 outSISIDXREG(SISSR, 0x18, 0x00);
5482 if((ivideo->chip == XGI_20) ||
5483 (ivideo->revision_id == 2)) {
5484 outSISIDXREG(SISSR, 0x19, 0x40);
5485 } else {
5486 outSISIDXREG(SISSR, 0x19, 0x20);
5487 }
5488 } else if((ivideo->chip == XGI_40) && (bios[0x1cb] == 0x0c)) {
5489 /* outSISIDXREG(SISSR, 0x16, 0x0c); */ /* ? */
5490 }
5491 outSISIDXREG(SISSR, 0x16, 0x00);
5492 outSISIDXREG(SISSR, 0x16, 0x80);
5493 sisfb_post_xgi_delay(ivideo, 4);
5494 v1 = 0x31; v2 = 0x03; v3 = 0x83; v4 = 0x03; v5 = 0x83;
5495 if(ivideo->haveXGIROM) {
5496 v1 = bios[0xf0];
5497 index = (ivideo->chip == XGI_20) ? 0x4b2 : 0x53e;
5498 v2 = bios[index];
5499 v3 = bios[index + 1];
5500 v4 = bios[index + 2];
5501 v5 = bios[index + 3];
5502 }
5503 outSISIDXREG(SISSR, 0x18, v1);
5504 outSISIDXREG(SISSR, 0x19, ((ivideo->chip == XGI_20) ? 0x02 : 0x01));
5505 outSISIDXREG(SISSR, 0x16, v2);
5506 outSISIDXREG(SISSR, 0x16, v3);
5507 sisfb_post_xgi_delay(ivideo, 0x43);
5508 outSISIDXREG(SISSR, 0x1b, 0x03);
5509 sisfb_post_xgi_delay(ivideo, 0x22);
5510 outSISIDXREG(SISSR, 0x18, v1);
5511 outSISIDXREG(SISSR, 0x19, 0x00);
5512 outSISIDXREG(SISSR, 0x16, v4);
5513 outSISIDXREG(SISSR, 0x16, v5);
5514 outSISIDXREG(SISSR, 0x1b, 0x00);
5515 break;
5516 case 1:
5517 outSISIDXREG(SISCR, 0x82, 0x77);
5518 outSISIDXREG(SISCR, 0x86, 0x00);
5519 inSISIDXREG(SISCR, 0x86, reg);
5520 outSISIDXREG(SISCR, 0x86, 0x88);
5521 inSISIDXREG(SISCR, 0x86, reg);
5522 v1 = cs168[regb]; v2 = cs160[regb]; v3 = cs158[regb];
5523 if(ivideo->haveXGIROM) {
5524 v1 = bios[regb + 0x168];
5525 v2 = bios[regb + 0x160];
5526 v3 = bios[regb + 0x158];
5527 }
5528 outSISIDXREG(SISCR, 0x86, v1);
5529 outSISIDXREG(SISCR, 0x82, 0x77);
5530 outSISIDXREG(SISCR, 0x85, 0x00);
5531 inSISIDXREG(SISCR, 0x85, reg);
5532 outSISIDXREG(SISCR, 0x85, 0x88);
5533 inSISIDXREG(SISCR, 0x85, reg);
5534 outSISIDXREG(SISCR, 0x85, v2);
5535 outSISIDXREG(SISCR, 0x82, v3);
5536 outSISIDXREG(SISCR, 0x98, 0x01);
5537 outSISIDXREG(SISCR, 0x9a, 0x02);
5538
5539 outSISIDXREG(SISSR, 0x28, 0x64);
5540 outSISIDXREG(SISSR, 0x29, 0x63);
5541 sisfb_post_xgi_delay(ivideo, 15);
5542 outSISIDXREG(SISSR, 0x18, 0x00);
5543 outSISIDXREG(SISSR, 0x19, 0x20);
5544 outSISIDXREG(SISSR, 0x16, 0x00);
5545 outSISIDXREG(SISSR, 0x16, 0x80);
5546 outSISIDXREG(SISSR, 0x18, 0xc5);
5547 outSISIDXREG(SISSR, 0x19, 0x23);
5548 outSISIDXREG(SISSR, 0x16, 0x00);
5549 outSISIDXREG(SISSR, 0x16, 0x80);
5550 sisfb_post_xgi_delay(ivideo, 1);
5551 outSISIDXREG(SISCR, 0x97,0x11);
5552 sisfb_post_xgi_setclocks(ivideo, regb);
5553 sisfb_post_xgi_delay(ivideo, 0x46);
5554 outSISIDXREG(SISSR, 0x18, 0xc5);
5555 outSISIDXREG(SISSR, 0x19, 0x23);
5556 outSISIDXREG(SISSR, 0x16, 0x00);
5557 outSISIDXREG(SISSR, 0x16, 0x80);
5558 sisfb_post_xgi_delay(ivideo, 1);
5559 outSISIDXREG(SISSR, 0x1b, 0x04);
5560 sisfb_post_xgi_delay(ivideo, 1);
5561 outSISIDXREG(SISSR, 0x1b, 0x00);
5562 sisfb_post_xgi_delay(ivideo, 1);
5563 v1 = 0x31;
5564 if(ivideo->haveXGIROM) {
5565 v1 = bios[0xf0];
5566 }
5567 outSISIDXREG(SISSR, 0x18, v1);
5568 outSISIDXREG(SISSR, 0x19, 0x06);
5569 outSISIDXREG(SISSR, 0x16, 0x04);
5570 outSISIDXREG(SISSR, 0x16, 0x84);
5571 sisfb_post_xgi_delay(ivideo, 1);
5572 break;
5573 default:
5574 sisfb_post_xgi_setclocks(ivideo, regb);
5575 if((ivideo->chip == XGI_40) &&
5576 ((ivideo->revision_id == 1) ||
5577 (ivideo->revision_id == 2))) {
5578 outSISIDXREG(SISCR, 0x82, bios[regb + 0x158]);
5579 outSISIDXREG(SISCR, 0x85, bios[regb + 0x160]);
5580 outSISIDXREG(SISCR, 0x86, bios[regb + 0x168]);
5581 } else {
5582 outSISIDXREG(SISCR, 0x82, 0x88);
5583 outSISIDXREG(SISCR, 0x86, 0x00);
5584 inSISIDXREG(SISCR, 0x86, reg);
5585 outSISIDXREG(SISCR, 0x86, 0x88);
5586 outSISIDXREG(SISCR, 0x82, 0x77);
5587 outSISIDXREG(SISCR, 0x85, 0x00);
5588 inSISIDXREG(SISCR, 0x85, reg);
5589 outSISIDXREG(SISCR, 0x85, 0x88);
5590 inSISIDXREG(SISCR, 0x85, reg);
5591 v1 = cs160[regb]; v2 = cs158[regb];
5592 if(ivideo->haveXGIROM) {
5593 v1 = bios[regb + 0x160];
5594 v2 = bios[regb + 0x158];
5595 }
5596 outSISIDXREG(SISCR, 0x85, v1);
5597 outSISIDXREG(SISCR, 0x82, v2);
5598 }
5599 if(ivideo->chip == XGI_40) {
5600 outSISIDXREG(SISCR, 0x97, 0x11);
5601 }
5602 if((ivideo->chip == XGI_40) && (ivideo->revision_id == 2)) {
5603 outSISIDXREG(SISCR, 0x98, 0x01);
5604 } else {
5605 outSISIDXREG(SISCR, 0x98, 0x03);
5606 }
5607 outSISIDXREG(SISCR, 0x9a, 0x02);
5608
5609 if(ivideo->chip == XGI_40) {
5610 outSISIDXREG(SISSR, 0x18, 0x01);
5611 } else {
5612 outSISIDXREG(SISSR, 0x18, 0x00);
5613 }
5614 outSISIDXREG(SISSR, 0x19, 0x40);
5615 outSISIDXREG(SISSR, 0x16, 0x00);
5616 outSISIDXREG(SISSR, 0x16, 0x80);
5617 if((ivideo->chip == XGI_40) && (bios[0x1cb] != 0x0c)) {
5618 sisfb_post_xgi_delay(ivideo, 0x43);
5619 sisfb_post_xgi_delay(ivideo, 0x43);
5620 sisfb_post_xgi_delay(ivideo, 0x43);
5621 outSISIDXREG(SISSR, 0x18, 0x00);
5622 outSISIDXREG(SISSR, 0x19, 0x40);
5623 outSISIDXREG(SISSR, 0x16, 0x00);
5624 outSISIDXREG(SISSR, 0x16, 0x80);
5625 }
5626 sisfb_post_xgi_delay(ivideo, 4);
5627 v1 = 0x31;
5628 if(ivideo->haveXGIROM) {
5629 v1 = bios[0xf0];
5630 }
5631 outSISIDXREG(SISSR, 0x18, v1);
5632 outSISIDXREG(SISSR, 0x19, 0x01);
5633 if(ivideo->chip == XGI_40) {
5634 outSISIDXREG(SISSR, 0x16, bios[0x53e]);
5635 outSISIDXREG(SISSR, 0x16, bios[0x53f]);
5636 } else {
5637 outSISIDXREG(SISSR, 0x16, 0x05);
5638 outSISIDXREG(SISSR, 0x16, 0x85);
5639 }
5640 sisfb_post_xgi_delay(ivideo, 0x43);
5641 if(ivideo->chip == XGI_40) {
5642 outSISIDXREG(SISSR, 0x1b, 0x01);
5643 } else {
5644 outSISIDXREG(SISSR, 0x1b, 0x03);
5645 }
5646 sisfb_post_xgi_delay(ivideo, 0x22);
5647 outSISIDXREG(SISSR, 0x18, v1);
5648 outSISIDXREG(SISSR, 0x19, 0x00);
5649 if(ivideo->chip == XGI_40) {
5650 outSISIDXREG(SISSR, 0x16, bios[0x540]);
5651 outSISIDXREG(SISSR, 0x16, bios[0x541]);
5652 } else {
5653 outSISIDXREG(SISSR, 0x16, 0x05);
5654 outSISIDXREG(SISSR, 0x16, 0x85);
5655 }
5656 outSISIDXREG(SISSR, 0x1b, 0x00);
5657 }
5658
5659 regb = 0; /* ! */
5660 v1 = 0x03;
5661 if(ivideo->haveXGIROM) {
5662 v1 = bios[0x110 + regb];
5663 }
5664 outSISIDXREG(SISSR, 0x1b, v1);
5665
5666 /* RAM size */
5667 v1 = 0x00; v2 = 0x00;
5668 if(ivideo->haveXGIROM) {
5669 v1 = bios[0x62];
5670 v2 = bios[0x63];
5671 }
5672 regb = 0; /* ! */
5673 regd = 1 << regb;
5674 if((v1 & 0x40) && (v2 & regd) && ivideo->haveXGIROM) {
5675
5676 outSISIDXREG(SISSR, 0x13, bios[regb + 0xe0]);
5677 outSISIDXREG(SISSR, 0x14, bios[regb + 0xe0 + 8]);
5678
5679 } else {
5680
5681 /* Set default mode, don't clear screen */
Richard Knutssonc30660ea2007-02-12 00:55:06 -08005682 ivideo->SiS_Pr.SiS_UseOEM = false;
5683 SiS_SetEnableDstn(&ivideo->SiS_Pr, false);
5684 SiS_SetEnableFstn(&ivideo->SiS_Pr, false);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07005685 ivideo->curFSTN = ivideo->curDSTN = 0;
5686 ivideo->SiS_Pr.VideoMemorySize = 8 << 20;
5687 SiSSetMode(&ivideo->SiS_Pr, 0x2e | 0x80);
5688
5689 outSISIDXREG(SISSR, 0x05, 0x86);
5690
5691 /* Disable read-cache */
5692 andSISIDXREG(SISSR, 0x21, 0xdf);
5693 sisfb_post_xgi_ramsize(ivideo);
5694 /* Enable read-cache */
5695 orSISIDXREG(SISSR, 0x21, 0x20);
5696
5697 }
5698
5699#if 0
5700 printk(KERN_DEBUG "-----------------\n");
5701 for(i = 0; i < 0xff; i++) {
5702 inSISIDXREG(SISCR, i, reg);
5703 printk(KERN_DEBUG "CR%02x(%x) = 0x%02x\n", i, SISCR, reg);
5704 }
5705 for(i = 0; i < 0x40; i++) {
5706 inSISIDXREG(SISSR, i, reg);
5707 printk(KERN_DEBUG "SR%02x(%x) = 0x%02x\n", i, SISSR, reg);
5708 }
5709 printk(KERN_DEBUG "-----------------\n");
5710#endif
5711
5712 /* Sense CRT1 */
5713 if(ivideo->chip == XGI_20) {
5714 orSISIDXREG(SISCR, 0x32, 0x20);
5715 } else {
5716 inSISIDXREG(SISPART4, 0x00, reg);
5717 if((reg == 1) || (reg == 2)) {
5718 sisfb_sense_crt1(ivideo);
5719 } else {
5720 orSISIDXREG(SISCR, 0x32, 0x20);
5721 }
5722 }
5723
5724 /* Set default mode, don't clear screen */
Richard Knutssonc30660ea2007-02-12 00:55:06 -08005725 ivideo->SiS_Pr.SiS_UseOEM = false;
5726 SiS_SetEnableDstn(&ivideo->SiS_Pr, false);
5727 SiS_SetEnableFstn(&ivideo->SiS_Pr, false);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07005728 ivideo->curFSTN = ivideo->curDSTN = 0;
5729 SiSSetMode(&ivideo->SiS_Pr, 0x2e | 0x80);
5730
5731 outSISIDXREG(SISSR, 0x05, 0x86);
5732
5733 /* Display off */
5734 orSISIDXREG(SISSR, 0x01, 0x20);
5735
5736 /* Save mode number in CR34 */
5737 outSISIDXREG(SISCR, 0x34, 0x2e);
5738
5739 /* Let everyone know what the current mode is */
5740 ivideo->modeprechange = 0x2e;
5741
5742 if(ivideo->chip == XGI_40) {
5743 inSISIDXREG(SISCR, 0xca, reg);
5744 inSISIDXREG(SISCR, 0xcc, v1);
5745 if((reg & 0x10) && (!(v1 & 0x04))) {
5746 printk(KERN_ERR
5747 "sisfb: Please connect power to the card.\n");
5748 return 0;
5749 }
5750 }
5751
5752 return 1;
5753}
5754#endif
5755
5756static int __devinit
5757sisfb_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
5758{
5759 struct sisfb_chip_info *chipinfo = &sisfb_chip_info[ent->driver_data];
5760 struct sis_video_info *ivideo = NULL;
5761 struct fb_info *sis_fb_info = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005762 u16 reg16;
5763 u8 reg;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07005764 int i, ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005765
Thomas Winischhofer544393f2005-09-09 13:04:45 -07005766 if(sisfb_off)
5767 return -ENXIO;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005768
Linus Torvalds1da177e2005-04-16 15:20:36 -07005769 sis_fb_info = framebuffer_alloc(sizeof(*ivideo), &pdev->dev);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07005770 if(!sis_fb_info)
5771 return -ENOMEM;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005772
5773 ivideo = (struct sis_video_info *)sis_fb_info->par;
5774 ivideo->memyselfandi = sis_fb_info;
5775
Thomas Winischhofer544393f2005-09-09 13:04:45 -07005776 ivideo->sisfb_id = SISFB_ID;
5777
Linus Torvalds1da177e2005-04-16 15:20:36 -07005778 if(card_list == NULL) {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07005779 ivideo->cardnumber = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005780 } else {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07005781 struct sis_video_info *countvideo = card_list;
5782 ivideo->cardnumber = 1;
5783 while((countvideo = countvideo->next) != 0)
5784 ivideo->cardnumber++;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005785 }
5786
5787 strncpy(ivideo->myid, chipinfo->chip_name, 30);
5788
5789 ivideo->warncount = 0;
5790 ivideo->chip_id = pdev->device;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07005791 ivideo->chip_vendor = pdev->vendor;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005792 pci_read_config_byte(pdev, PCI_REVISION_ID, &ivideo->revision_id);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07005793 ivideo->SiS_Pr.ChipRevision = ivideo->revision_id;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005794 pci_read_config_word(pdev, PCI_COMMAND, &reg16);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07005795 ivideo->sisvga_enabled = reg16 & 0x01;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005796 ivideo->pcibus = pdev->bus->number;
5797 ivideo->pcislot = PCI_SLOT(pdev->devfn);
5798 ivideo->pcifunc = PCI_FUNC(pdev->devfn);
5799 ivideo->subsysvendor = pdev->subsystem_vendor;
5800 ivideo->subsysdevice = pdev->subsystem_device;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07005801#ifdef SIS_OLD_CONFIG_COMPAT
5802 ivideo->ioctl32registered = 0;
5803#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -07005804
5805#ifndef MODULE
5806 if(sisfb_mode_idx == -1) {
5807 sisfb_get_vga_mode_from_kernel();
5808 }
5809#endif
5810
5811 ivideo->chip = chipinfo->chip;
5812 ivideo->sisvga_engine = chipinfo->vgaengine;
5813 ivideo->hwcursor_size = chipinfo->hwcursor_size;
5814 ivideo->CRT2_write_enable = chipinfo->CRT2_write_enable;
5815 ivideo->mni = chipinfo->mni;
5816
5817 ivideo->detectedpdc = 0xff;
5818 ivideo->detectedpdca = 0xff;
5819 ivideo->detectedlcda = 0xff;
5820
Richard Knutssonc30660ea2007-02-12 00:55:06 -08005821 ivideo->sisfb_thismonitor.datavalid = false;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005822
Thomas Winischhofer544393f2005-09-09 13:04:45 -07005823 ivideo->current_base = 0;
5824
5825 ivideo->engineok = 0;
5826
5827 ivideo->sisfb_was_boot_device = 0;
5828#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,12))
5829 if(pdev->resource[PCI_ROM_RESOURCE].flags & IORESOURCE_ROM_SHADOW) {
5830 if(ivideo->sisvga_enabled)
5831 ivideo->sisfb_was_boot_device = 1;
5832 else {
5833 printk(KERN_DEBUG "sisfb: PCI device is disabled, "
5834 "but marked as boot video device ???\n");
5835 printk(KERN_DEBUG "sisfb: I will not accept this "
5836 "as the primary VGA device\n");
5837 }
5838 }
5839#endif
5840
Linus Torvalds1da177e2005-04-16 15:20:36 -07005841 ivideo->sisfb_parm_mem = sisfb_parm_mem;
5842 ivideo->sisfb_accel = sisfb_accel;
5843 ivideo->sisfb_ypan = sisfb_ypan;
5844 ivideo->sisfb_max = sisfb_max;
5845 ivideo->sisfb_userom = sisfb_userom;
5846 ivideo->sisfb_useoem = sisfb_useoem;
5847 ivideo->sisfb_mode_idx = sisfb_mode_idx;
5848 ivideo->sisfb_parm_rate = sisfb_parm_rate;
5849 ivideo->sisfb_crt1off = sisfb_crt1off;
5850 ivideo->sisfb_forcecrt1 = sisfb_forcecrt1;
5851 ivideo->sisfb_crt2type = sisfb_crt2type;
5852 ivideo->sisfb_crt2flags = sisfb_crt2flags;
5853 /* pdc(a), scalelcd, special timing, lvdshl handled below */
5854 ivideo->sisfb_dstn = sisfb_dstn;
5855 ivideo->sisfb_fstn = sisfb_fstn;
5856 ivideo->sisfb_tvplug = sisfb_tvplug;
5857 ivideo->sisfb_tvstd = sisfb_tvstd;
5858 ivideo->tvxpos = sisfb_tvxposoffset;
5859 ivideo->tvypos = sisfb_tvyposoffset;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005860 ivideo->sisfb_nocrt2rate = sisfb_nocrt2rate;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005861 ivideo->refresh_rate = 0;
5862 if(ivideo->sisfb_parm_rate != -1) {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07005863 ivideo->refresh_rate = ivideo->sisfb_parm_rate;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005864 }
5865
5866 ivideo->SiS_Pr.UsePanelScaler = sisfb_scalelcd;
5867 ivideo->SiS_Pr.CenterScreen = -1;
5868 ivideo->SiS_Pr.SiS_CustomT = sisfb_specialtiming;
5869 ivideo->SiS_Pr.LVDSHL = sisfb_lvdshl;
5870
5871 ivideo->SiS_Pr.SiS_Backup70xx = 0xff;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07005872 ivideo->SiS_Pr.SiS_CHOverScan = -1;
Richard Knutssonc30660ea2007-02-12 00:55:06 -08005873 ivideo->SiS_Pr.SiS_ChSW = false;
5874 ivideo->SiS_Pr.SiS_UseLCDA = false;
5875 ivideo->SiS_Pr.HaveEMI = false;
5876 ivideo->SiS_Pr.HaveEMILCD = false;
5877 ivideo->SiS_Pr.OverruleEMI = false;
5878 ivideo->SiS_Pr.SiS_SensibleSR11 = false;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005879 ivideo->SiS_Pr.SiS_MyCR63 = 0x63;
5880 ivideo->SiS_Pr.PDC = -1;
5881 ivideo->SiS_Pr.PDCA = -1;
Richard Knutssonc30660ea2007-02-12 00:55:06 -08005882 ivideo->SiS_Pr.DDCPortMixup = false;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005883#ifdef CONFIG_FB_SIS_315
5884 if(ivideo->chip >= SIS_330) {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07005885 ivideo->SiS_Pr.SiS_MyCR63 = 0x53;
5886 if(ivideo->chip >= SIS_661) {
Richard Knutssonc30660ea2007-02-12 00:55:06 -08005887 ivideo->SiS_Pr.SiS_SensibleSR11 = true;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07005888 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07005889 }
5890#endif
5891
5892 memcpy(&ivideo->default_var, &my_default_var, sizeof(my_default_var));
5893
5894 pci_set_drvdata(pdev, ivideo);
5895
5896 /* Patch special cases */
5897 if((ivideo->nbridge = sisfb_get_northbridge(ivideo->chip))) {
5898 switch(ivideo->nbridge->device) {
5899#ifdef CONFIG_FB_SIS_300
5900 case PCI_DEVICE_ID_SI_730:
Thomas Winischhofer544393f2005-09-09 13:04:45 -07005901 ivideo->chip = SIS_730;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005902 strcpy(ivideo->myid, "SiS 730");
Thomas Winischhofer544393f2005-09-09 13:04:45 -07005903 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005904#endif
5905#ifdef CONFIG_FB_SIS_315
5906 case PCI_DEVICE_ID_SI_651:
5907 /* ivideo->chip is ok */
5908 strcpy(ivideo->myid, "SiS 651");
5909 break;
5910 case PCI_DEVICE_ID_SI_740:
Thomas Winischhofer544393f2005-09-09 13:04:45 -07005911 ivideo->chip = SIS_740;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005912 strcpy(ivideo->myid, "SiS 740");
5913 break;
5914 case PCI_DEVICE_ID_SI_661:
Thomas Winischhofer544393f2005-09-09 13:04:45 -07005915 ivideo->chip = SIS_661;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005916 strcpy(ivideo->myid, "SiS 661");
5917 break;
5918 case PCI_DEVICE_ID_SI_741:
Thomas Winischhofer544393f2005-09-09 13:04:45 -07005919 ivideo->chip = SIS_741;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005920 strcpy(ivideo->myid, "SiS 741");
5921 break;
5922 case PCI_DEVICE_ID_SI_760:
Thomas Winischhofer544393f2005-09-09 13:04:45 -07005923 ivideo->chip = SIS_760;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005924 strcpy(ivideo->myid, "SiS 760");
5925 break;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07005926 case PCI_DEVICE_ID_SI_761:
5927 ivideo->chip = SIS_761;
5928 strcpy(ivideo->myid, "SiS 761");
5929 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005930#endif
Thomas Winischhofer544393f2005-09-09 13:04:45 -07005931 default:
5932 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005933 }
5934 }
5935
Thomas Winischhofer544393f2005-09-09 13:04:45 -07005936 ivideo->SiS_Pr.ChipType = ivideo->chip;
5937
5938 ivideo->SiS_Pr.ivideo = (void *)ivideo;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005939
5940#ifdef CONFIG_FB_SIS_315
Thomas Winischhofer544393f2005-09-09 13:04:45 -07005941 if((ivideo->SiS_Pr.ChipType == SIS_315PRO) ||
5942 (ivideo->SiS_Pr.ChipType == SIS_315)) {
5943 ivideo->SiS_Pr.ChipType = SIS_315H;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005944 }
5945#endif
5946
Thomas Winischhofer544393f2005-09-09 13:04:45 -07005947 if(!ivideo->sisvga_enabled) {
5948 if(pci_enable_device(pdev)) {
Adrian Bunk0959f0c2007-05-08 00:39:50 -07005949 if(ivideo->nbridge) pci_dev_put(ivideo->nbridge);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07005950 pci_set_drvdata(pdev, NULL);
5951 kfree(sis_fb_info);
5952 return -EIO;
5953 }
5954 }
5955
Linus Torvalds1da177e2005-04-16 15:20:36 -07005956 ivideo->video_base = pci_resource_start(pdev, 0);
5957 ivideo->mmio_base = pci_resource_start(pdev, 1);
5958 ivideo->mmio_size = pci_resource_len(pdev, 1);
5959 ivideo->SiS_Pr.RelIO = pci_resource_start(pdev, 2) + 0x30;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07005960 ivideo->SiS_Pr.IOAddress = ivideo->vga_base = ivideo->SiS_Pr.RelIO;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005961
Thomas Winischhofer544393f2005-09-09 13:04:45 -07005962 SiSRegInit(&ivideo->SiS_Pr, ivideo->SiS_Pr.IOAddress);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005963
5964#ifdef CONFIG_FB_SIS_300
5965 /* Find PCI systems for Chrontel/GPIO communication setup */
5966 if(ivideo->chip == SIS_630) {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07005967 i = 0;
5968 do {
5969 if(mychswtable[i].subsysVendor == ivideo->subsysvendor &&
5970 mychswtable[i].subsysCard == ivideo->subsysdevice) {
Richard Knutssonc30660ea2007-02-12 00:55:06 -08005971 ivideo->SiS_Pr.SiS_ChSW = true;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07005972 printk(KERN_DEBUG "sisfb: Identified [%s %s] "
5973 "requiring Chrontel/GPIO setup\n",
5974 mychswtable[i].vendorName,
5975 mychswtable[i].cardName);
Adrian Bunk0959f0c2007-05-08 00:39:50 -07005976 ivideo->lpcdev = pci_get_device(PCI_VENDOR_ID_SI, 0x0008, NULL);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07005977 break;
5978 }
5979 i++;
5980 } while(mychswtable[i].subsysVendor != 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005981 }
5982#endif
5983
Thomas Winischhofer544393f2005-09-09 13:04:45 -07005984#ifdef CONFIG_FB_SIS_315
5985 if((ivideo->chip == SIS_760) && (ivideo->nbridge)) {
Adrian Bunk0959f0c2007-05-08 00:39:50 -07005986 ivideo->lpcdev = pci_get_slot(ivideo->nbridge->bus, (2 << 3));
Thomas Winischhofer544393f2005-09-09 13:04:45 -07005987 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07005988#endif
Thomas Winischhofer544393f2005-09-09 13:04:45 -07005989
5990 outSISIDXREG(SISSR, 0x05, 0x86);
5991
5992 if( (!ivideo->sisvga_enabled)
5993#if !defined(__i386__) && !defined(__x86_64__)
5994 || (sisfb_resetcard)
5995#endif
5996 ) {
5997 for(i = 0x30; i <= 0x3f; i++) {
5998 outSISIDXREG(SISCR, i, 0x00);
5999 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07006000 }
6001
6002 /* Find out about current video mode */
6003 ivideo->modeprechange = 0x03;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006004 inSISIDXREG(SISCR, 0x34, reg);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006005 if(reg & 0x7f) {
6006 ivideo->modeprechange = reg & 0x7f;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006007 } else if(ivideo->sisvga_enabled) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07006008#if defined(__i386__) || defined(__x86_64__)
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006009 unsigned char SIS_IOTYPE2 *tt = ioremap(0x400, 0x100);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006010 if(tt) {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006011 ivideo->modeprechange = readb(tt + 0x49);
6012 iounmap(tt);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006013 }
6014#endif
6015 }
6016
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006017 /* Search and copy ROM image */
6018 ivideo->bios_abase = NULL;
6019 ivideo->SiS_Pr.VirtualRomBase = NULL;
Richard Knutssonc30660ea2007-02-12 00:55:06 -08006020 ivideo->SiS_Pr.UseROM = false;
6021 ivideo->haveXGIROM = ivideo->SiS_Pr.SiS_XGIROM = false;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006022 if(ivideo->sisfb_userom) {
6023 ivideo->SiS_Pr.VirtualRomBase = sisfb_find_rom(pdev);
6024 ivideo->bios_abase = ivideo->SiS_Pr.VirtualRomBase;
Richard Knutssonc30660ea2007-02-12 00:55:06 -08006025 ivideo->SiS_Pr.UseROM = (bool)(ivideo->SiS_Pr.VirtualRomBase);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006026 printk(KERN_INFO "sisfb: Video ROM %sfound\n",
6027 ivideo->SiS_Pr.UseROM ? "" : "not ");
6028 if((ivideo->SiS_Pr.UseROM) && (ivideo->chip >= XGI_20)) {
Richard Knutssonc30660ea2007-02-12 00:55:06 -08006029 ivideo->SiS_Pr.UseROM = false;
6030 ivideo->haveXGIROM = ivideo->SiS_Pr.SiS_XGIROM = true;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006031 if( (ivideo->revision_id == 2) &&
6032 (!(ivideo->bios_abase[0x1d1] & 0x01)) ) {
Richard Knutssonc30660ea2007-02-12 00:55:06 -08006033 ivideo->SiS_Pr.DDCPortMixup = true;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006034 }
6035 }
6036 } else {
6037 printk(KERN_INFO "sisfb: Video ROM usage disabled\n");
6038 }
6039
6040 /* Find systems for special custom timing */
6041 if(ivideo->SiS_Pr.SiS_CustomT == CUT_NONE) {
6042 sisfb_detect_custom_timing(ivideo);
6043 }
6044
6045 /* POST card in case this has not been done by the BIOS */
6046 if( (!ivideo->sisvga_enabled)
6047#if !defined(__i386__) && !defined(__x86_64__)
6048 || (sisfb_resetcard)
6049#endif
6050 ) {
6051#ifdef CONFIG_FB_SIS_300
6052 if(ivideo->sisvga_engine == SIS_300_VGA) {
6053 if(ivideo->chip == SIS_300) {
6054 sisfb_post_sis300(pdev);
6055 ivideo->sisfb_can_post = 1;
6056 }
6057 }
6058#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -07006059
6060#ifdef CONFIG_FB_SIS_315
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006061 if(ivideo->sisvga_engine == SIS_315_VGA) {
6062 int result = 1;
6063 /* if((ivideo->chip == SIS_315H) ||
Linus Torvalds1da177e2005-04-16 15:20:36 -07006064 (ivideo->chip == SIS_315) ||
6065 (ivideo->chip == SIS_315PRO) ||
6066 (ivideo->chip == SIS_330)) {
6067 sisfb_post_sis315330(pdev);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006068 } else */ if(ivideo->chip == XGI_20) {
6069 result = sisfb_post_xgi(pdev);
6070 ivideo->sisfb_can_post = 1;
6071 } else if((ivideo->chip == XGI_40) && ivideo->haveXGIROM) {
6072 result = sisfb_post_xgi(pdev);
6073 ivideo->sisfb_can_post = 1;
6074 } else {
6075 printk(KERN_INFO "sisfb: Card is not "
6076 "POSTed and sisfb can't do this either.\n");
6077 }
6078 if(!result) {
6079 printk(KERN_ERR "sisfb: Failed to POST card\n");
6080 ret = -ENODEV;
6081 goto error_3;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006082 }
6083 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07006084#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -07006085 }
6086
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006087 ivideo->sisfb_card_posted = 1;
6088
6089 /* Find out about RAM size */
6090 if(sisfb_get_dram_size(ivideo)) {
6091 printk(KERN_INFO "sisfb: Fatal error: Unable to determine VRAM size.\n");
6092 ret = -ENODEV;
6093 goto error_3;
6094 }
6095
6096
6097 /* Enable PCI addressing and MMIO */
Linus Torvalds1da177e2005-04-16 15:20:36 -07006098 if((ivideo->sisfb_mode_idx < 0) ||
6099 ((sisbios_mode[ivideo->sisfb_mode_idx].mode_no[ivideo->mni]) != 0xFF)) {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006100 /* Enable PCI_LINEAR_ADDRESSING and MMIO_ENABLE */
6101 orSISIDXREG(SISSR, IND_SIS_PCI_ADDRESS_SET, (SIS_PCI_ADDR_ENABLE | SIS_MEM_MAP_IO_ENABLE));
6102 /* Enable 2D accelerator engine */
6103 orSISIDXREG(SISSR, IND_SIS_MODULE_ENABLE, SIS_ENABLE_2D);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006104 }
6105
6106 if(sisfb_pdc != 0xff) {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006107 if(ivideo->sisvga_engine == SIS_300_VGA)
6108 sisfb_pdc &= 0x3c;
6109 else
6110 sisfb_pdc &= 0x1f;
6111 ivideo->SiS_Pr.PDC = sisfb_pdc;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006112 }
6113#ifdef CONFIG_FB_SIS_315
6114 if(ivideo->sisvga_engine == SIS_315_VGA) {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006115 if(sisfb_pdca != 0xff)
6116 ivideo->SiS_Pr.PDCA = sisfb_pdca & 0x1f;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006117 }
6118#endif
6119
6120 if(!request_mem_region(ivideo->video_base, ivideo->video_size, "sisfb FB")) {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006121 printk(KERN_ERR "sisfb: Fatal error: Unable to reserve %dMB framebuffer memory\n",
6122 (int)(ivideo->video_size >> 20));
Linus Torvalds1da177e2005-04-16 15:20:36 -07006123 printk(KERN_ERR "sisfb: Is there another framebuffer driver active?\n");
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006124 ret = -ENODEV;
6125 goto error_3;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006126 }
6127
6128 if(!request_mem_region(ivideo->mmio_base, ivideo->mmio_size, "sisfb MMIO")) {
6129 printk(KERN_ERR "sisfb: Fatal error: Unable to reserve MMIO region\n");
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006130 ret = -ENODEV;
6131 goto error_2;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006132 }
6133
6134 ivideo->video_vbase = ioremap(ivideo->video_base, ivideo->video_size);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006135 ivideo->SiS_Pr.VideoMemoryAddress = ivideo->video_vbase;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006136 if(!ivideo->video_vbase) {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006137 printk(KERN_ERR "sisfb: Fatal error: Unable to map framebuffer memory\n");
6138 ret = -ENODEV;
6139 goto error_1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006140 }
6141
6142 ivideo->mmio_vbase = ioremap(ivideo->mmio_base, ivideo->mmio_size);
6143 if(!ivideo->mmio_vbase) {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006144 printk(KERN_ERR "sisfb: Fatal error: Unable to map MMIO region\n");
6145 ret = -ENODEV;
6146error_0: iounmap(ivideo->video_vbase);
6147error_1: release_mem_region(ivideo->video_base, ivideo->video_size);
6148error_2: release_mem_region(ivideo->mmio_base, ivideo->mmio_size);
6149error_3: vfree(ivideo->bios_abase);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006150 if(ivideo->lpcdev)
Adrian Bunk0959f0c2007-05-08 00:39:50 -07006151 pci_dev_put(ivideo->lpcdev);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006152 if(ivideo->nbridge)
Adrian Bunk0959f0c2007-05-08 00:39:50 -07006153 pci_dev_put(ivideo->nbridge);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006154 pci_set_drvdata(pdev, NULL);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006155 if(!ivideo->sisvga_enabled)
6156 pci_disable_device(pdev);
6157 kfree(sis_fb_info);
6158 return ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006159 }
6160
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006161 printk(KERN_INFO "sisfb: Video RAM at 0x%lx, mapped to 0x%lx, size %ldk\n",
6162 ivideo->video_base, (unsigned long)ivideo->video_vbase, ivideo->video_size / 1024);
6163
6164 if(ivideo->video_offset) {
6165 printk(KERN_INFO "sisfb: Viewport offset %ldk\n",
6166 ivideo->video_offset / 1024);
6167 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07006168
6169 printk(KERN_INFO "sisfb: MMIO at 0x%lx, mapped to 0x%lx, size %ldk\n",
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006170 ivideo->mmio_base, (unsigned long)ivideo->mmio_vbase, ivideo->mmio_size / 1024);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006171
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006172
6173 /* Determine the size of the command queue */
6174 if(ivideo->sisvga_engine == SIS_300_VGA) {
6175 ivideo->cmdQueueSize = TURBO_QUEUE_AREA_SIZE;
6176 } else {
6177 if(ivideo->chip == XGI_20) {
6178 ivideo->cmdQueueSize = COMMAND_QUEUE_AREA_SIZE_Z7;
6179 } else {
6180 ivideo->cmdQueueSize = COMMAND_QUEUE_AREA_SIZE;
6181 }
6182 }
6183
6184 /* Engines are no longer initialized here; this is
6185 * now done after the first mode-switch (if the
6186 * submitted var has its acceleration flags set).
6187 */
6188
6189 /* Calculate the base of the (unused) hw cursor */
6190 ivideo->hwcursor_vbase = ivideo->video_vbase
6191 + ivideo->video_size
6192 - ivideo->cmdQueueSize
6193 - ivideo->hwcursor_size;
6194 ivideo->caps |= HW_CURSOR_CAP;
6195
6196 /* Initialize offscreen memory manager */
Linus Torvalds1da177e2005-04-16 15:20:36 -07006197 if((ivideo->havenoheap = sisfb_heap_init(ivideo))) {
6198 printk(KERN_WARNING "sisfb: Failed to initialize offscreen memory heap\n");
6199 }
6200
6201 /* Used for clearing the screen only, therefore respect our mem limit */
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006202 ivideo->SiS_Pr.VideoMemoryAddress += ivideo->video_offset;
6203 ivideo->SiS_Pr.VideoMemorySize = ivideo->sisfb_mem;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006204
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006205 ivideo->mtrr = -1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006206
6207 ivideo->vbflags = 0;
6208 ivideo->lcddefmodeidx = DEFAULT_LCDMODE;
6209 ivideo->tvdefmodeidx = DEFAULT_TVMODE;
6210 ivideo->defmodeidx = DEFAULT_MODE;
6211
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006212 ivideo->newrom = 0;
6213 if(ivideo->chip < XGI_20) {
6214 if(ivideo->bios_abase) {
6215 ivideo->newrom = SiSDetermineROMLayout661(&ivideo->SiS_Pr);
6216 }
6217 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07006218
6219 if((ivideo->sisfb_mode_idx < 0) ||
6220 ((sisbios_mode[ivideo->sisfb_mode_idx].mode_no[ivideo->mni]) != 0xFF)) {
6221
6222 sisfb_sense_crt1(ivideo);
6223
6224 sisfb_get_VB_type(ivideo);
6225
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006226 if(ivideo->vbflags2 & VB2_VIDEOBRIDGE) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07006227 sisfb_detect_VB_connect(ivideo);
6228 }
6229
6230 ivideo->currentvbflags = ivideo->vbflags & (VB_VIDEOBRIDGE | TV_STANDARD);
6231
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006232 /* Decide on which CRT2 device to use */
6233 if(ivideo->vbflags2 & VB2_VIDEOBRIDGE) {
6234 if(ivideo->sisfb_crt2type != -1) {
6235 if((ivideo->sisfb_crt2type == CRT2_LCD) &&
6236 (ivideo->vbflags & CRT2_LCD)) {
6237 ivideo->currentvbflags |= CRT2_LCD;
6238 } else if(ivideo->sisfb_crt2type != CRT2_LCD) {
6239 ivideo->currentvbflags |= ivideo->sisfb_crt2type;
6240 }
6241 } else {
6242 /* Chrontel 700x TV detection often unreliable, therefore
6243 * use a different default order on such machines
6244 */
6245 if((ivideo->sisvga_engine == SIS_300_VGA) &&
6246 (ivideo->vbflags2 & VB2_CHRONTEL)) {
6247 if(ivideo->vbflags & CRT2_LCD)
6248 ivideo->currentvbflags |= CRT2_LCD;
6249 else if(ivideo->vbflags & CRT2_TV)
6250 ivideo->currentvbflags |= CRT2_TV;
6251 else if(ivideo->vbflags & CRT2_VGA)
6252 ivideo->currentvbflags |= CRT2_VGA;
6253 } else {
6254 if(ivideo->vbflags & CRT2_TV)
6255 ivideo->currentvbflags |= CRT2_TV;
6256 else if(ivideo->vbflags & CRT2_LCD)
6257 ivideo->currentvbflags |= CRT2_LCD;
6258 else if(ivideo->vbflags & CRT2_VGA)
6259 ivideo->currentvbflags |= CRT2_VGA;
6260 }
6261 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07006262 }
6263
6264 if(ivideo->vbflags & CRT2_LCD) {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006265 sisfb_detect_lcd_type(ivideo);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006266 }
6267
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006268 sisfb_save_pdc_emi(ivideo);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006269
6270 if(!ivideo->sisfb_crt1off) {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006271 sisfb_handle_ddc(ivideo, &ivideo->sisfb_thismonitor, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006272 } else {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006273 if((ivideo->vbflags2 & VB2_SISTMDSBRIDGE) &&
6274 (ivideo->vbflags & (CRT2_VGA | CRT2_LCD))) {
6275 sisfb_handle_ddc(ivideo, &ivideo->sisfb_thismonitor, 1);
6276 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07006277 }
6278
6279 if(ivideo->sisfb_mode_idx >= 0) {
6280 int bu = ivideo->sisfb_mode_idx;
6281 ivideo->sisfb_mode_idx = sisfb_validate_mode(ivideo,
6282 ivideo->sisfb_mode_idx, ivideo->currentvbflags);
6283 if(bu != ivideo->sisfb_mode_idx) {
6284 printk(KERN_ERR "Mode %dx%dx%d failed validation\n",
6285 sisbios_mode[bu].xres,
6286 sisbios_mode[bu].yres,
6287 sisbios_mode[bu].bpp);
6288 }
6289 }
6290
6291 if(ivideo->sisfb_mode_idx < 0) {
6292 switch(ivideo->currentvbflags & VB_DISPTYPE_DISP2) {
6293 case CRT2_LCD:
6294 ivideo->sisfb_mode_idx = ivideo->lcddefmodeidx;
6295 break;
6296 case CRT2_TV:
6297 ivideo->sisfb_mode_idx = ivideo->tvdefmodeidx;
6298 break;
6299 default:
6300 ivideo->sisfb_mode_idx = ivideo->defmodeidx;
6301 break;
6302 }
6303 }
6304
6305 ivideo->mode_no = sisbios_mode[ivideo->sisfb_mode_idx].mode_no[ivideo->mni];
6306
6307 if(ivideo->refresh_rate != 0) {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006308 sisfb_search_refresh_rate(ivideo, ivideo->refresh_rate,
6309 ivideo->sisfb_mode_idx);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006310 }
6311
6312 if(ivideo->rate_idx == 0) {
6313 ivideo->rate_idx = sisbios_mode[ivideo->sisfb_mode_idx].rate_idx;
6314 ivideo->refresh_rate = 60;
6315 }
6316
6317 if(ivideo->sisfb_thismonitor.datavalid) {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006318 if(!sisfb_verify_rate(ivideo, &ivideo->sisfb_thismonitor,
6319 ivideo->sisfb_mode_idx,
6320 ivideo->rate_idx,
6321 ivideo->refresh_rate)) {
6322 printk(KERN_INFO "sisfb: WARNING: Refresh rate "
6323 "exceeds monitor specs!\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07006324 }
6325 }
6326
6327 ivideo->video_bpp = sisbios_mode[ivideo->sisfb_mode_idx].bpp;
6328 ivideo->video_width = sisbios_mode[ivideo->sisfb_mode_idx].xres;
6329 ivideo->video_height = sisbios_mode[ivideo->sisfb_mode_idx].yres;
6330
6331 sisfb_set_vparms(ivideo);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006332
Linus Torvalds1da177e2005-04-16 15:20:36 -07006333 printk(KERN_INFO "sisfb: Default mode is %dx%dx%d (%dHz)\n",
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006334 ivideo->video_width, ivideo->video_height, ivideo->video_bpp,
Linus Torvalds1da177e2005-04-16 15:20:36 -07006335 ivideo->refresh_rate);
6336
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006337 /* Set up the default var according to chosen default display mode */
Linus Torvalds1da177e2005-04-16 15:20:36 -07006338 ivideo->default_var.xres = ivideo->default_var.xres_virtual = ivideo->video_width;
6339 ivideo->default_var.yres = ivideo->default_var.yres_virtual = ivideo->video_height;
6340 ivideo->default_var.bits_per_pixel = ivideo->video_bpp;
6341
6342 sisfb_bpp_to_var(ivideo, &ivideo->default_var);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006343
Linus Torvalds1da177e2005-04-16 15:20:36 -07006344 ivideo->default_var.pixclock = (u32) (1000000000 /
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006345 sisfb_mode_rate_to_dclock(&ivideo->SiS_Pr, ivideo->mode_no, ivideo->rate_idx));
6346
6347 if(sisfb_mode_rate_to_ddata(&ivideo->SiS_Pr, ivideo->mode_no,
6348 ivideo->rate_idx, &ivideo->default_var)) {
6349 if((ivideo->default_var.vmode & FB_VMODE_MASK) == FB_VMODE_DOUBLE) {
6350 ivideo->default_var.pixclock <<= 1;
6351 }
6352 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07006353
6354 if(ivideo->sisfb_ypan) {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006355 /* Maximize regardless of sisfb_max at startup */
6356 ivideo->default_var.yres_virtual =
6357 sisfb_calc_maxyres(ivideo, &ivideo->default_var);
6358 if(ivideo->default_var.yres_virtual < ivideo->default_var.yres) {
6359 ivideo->default_var.yres_virtual = ivideo->default_var.yres;
6360 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07006361 }
6362
6363 sisfb_calc_pitch(ivideo, &ivideo->default_var);
6364
6365 ivideo->accel = 0;
6366 if(ivideo->sisfb_accel) {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006367 ivideo->accel = -1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006368#ifdef STUPID_ACCELF_TEXT_SHIT
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006369 ivideo->default_var.accel_flags |= FB_ACCELF_TEXT;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006370#endif
6371 }
6372 sisfb_initaccel(ivideo);
6373
6374#if defined(FBINFO_HWACCEL_DISABLED) && defined(FBINFO_HWACCEL_XPAN)
6375 sis_fb_info->flags = FBINFO_DEFAULT |
6376 FBINFO_HWACCEL_YPAN |
6377 FBINFO_HWACCEL_XPAN |
6378 FBINFO_HWACCEL_COPYAREA |
6379 FBINFO_HWACCEL_FILLRECT |
6380 ((ivideo->accel) ? 0 : FBINFO_HWACCEL_DISABLED);
6381#else
6382 sis_fb_info->flags = FBINFO_FLAG_DEFAULT;
6383#endif
6384 sis_fb_info->var = ivideo->default_var;
6385 sis_fb_info->fix = ivideo->sisfb_fix;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006386 sis_fb_info->screen_base = ivideo->video_vbase + ivideo->video_offset;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006387 sis_fb_info->fbops = &sisfb_ops;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006388 sisfb_get_fix(&sis_fb_info->fix, -1, sis_fb_info);
6389 sis_fb_info->pseudo_palette = ivideo->pseudo_palette;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006390
Linus Torvalds1da177e2005-04-16 15:20:36 -07006391 fb_alloc_cmap(&sis_fb_info->cmap, 256 , 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006392
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006393 printk(KERN_DEBUG "sisfb: Initial vbflags 0x%x\n", (int)ivideo->vbflags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006394
6395#ifdef CONFIG_MTRR
6396 ivideo->mtrr = mtrr_add(ivideo->video_base, ivideo->video_size,
6397 MTRR_TYPE_WRCOMB, 1);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006398 if(ivideo->mtrr < 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07006399 printk(KERN_DEBUG "sisfb: Failed to add MTRRs\n");
6400 }
6401#endif
6402
Linus Torvalds1da177e2005-04-16 15:20:36 -07006403 if(register_framebuffer(sis_fb_info) < 0) {
6404 printk(KERN_ERR "sisfb: Fatal error: Failed to register framebuffer\n");
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006405 ret = -EINVAL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006406 iounmap(ivideo->mmio_vbase);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006407 goto error_0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006408 }
6409
6410 ivideo->registered = 1;
6411
6412 /* Enlist us */
6413 ivideo->next = card_list;
6414 card_list = ivideo;
6415
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006416#ifdef SIS_OLD_CONFIG_COMPAT
6417 {
6418 int ret;
6419 /* Our ioctls are all "32/64bit compatible" */
6420 ret = register_ioctl32_conversion(FBIO_ALLOC, NULL);
6421 ret |= register_ioctl32_conversion(FBIO_FREE, NULL);
6422 ret |= register_ioctl32_conversion(FBIOGET_VBLANK, NULL);
6423 ret |= register_ioctl32_conversion(SISFB_GET_INFO_SIZE, NULL);
6424 ret |= register_ioctl32_conversion(SISFB_GET_INFO, NULL);
6425 ret |= register_ioctl32_conversion(SISFB_GET_TVPOSOFFSET, NULL);
6426 ret |= register_ioctl32_conversion(SISFB_SET_TVPOSOFFSET, NULL);
6427 ret |= register_ioctl32_conversion(SISFB_SET_LOCK, NULL);
6428 ret |= register_ioctl32_conversion(SISFB_GET_VBRSTATUS, NULL);
6429 ret |= register_ioctl32_conversion(SISFB_GET_AUTOMAXIMIZE, NULL);
6430 ret |= register_ioctl32_conversion(SISFB_SET_AUTOMAXIMIZE, NULL);
6431 ret |= register_ioctl32_conversion(SISFB_COMMAND, NULL);
6432 if(ret)
6433 printk(KERN_ERR
6434 "sisfb: Error registering ioctl32 translations\n");
6435 else
6436 ivideo->ioctl32registered = 1;
6437 }
6438#endif
6439
Linus Torvalds1da177e2005-04-16 15:20:36 -07006440 printk(KERN_INFO "sisfb: 2D acceleration is %s, y-panning %s\n",
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006441 ivideo->sisfb_accel ? "enabled" : "disabled",
6442 ivideo->sisfb_ypan ?
6443 (ivideo->sisfb_max ? "enabled (auto-max)" :
6444 "enabled (no auto-max)") :
6445 "disabled");
Linus Torvalds1da177e2005-04-16 15:20:36 -07006446
6447
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006448 printk(KERN_INFO "fb%d: %s frame buffer device version %d.%d.%d\n",
Michal Piotrowski43704092006-10-03 01:15:00 -07006449 sis_fb_info->node, ivideo->myid, VER_MAJOR, VER_MINOR, VER_LEVEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006450
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006451 printk(KERN_INFO "sisfb: Copyright (C) 2001-2005 Thomas Winischhofer\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07006452
6453 } /* if mode = "none" */
6454
6455 return 0;
6456}
6457
6458/*****************************************************/
6459/* PCI DEVICE HANDLING */
6460/*****************************************************/
6461
6462static void __devexit sisfb_remove(struct pci_dev *pdev)
6463{
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006464 struct sis_video_info *ivideo = pci_get_drvdata(pdev);
6465 struct fb_info *sis_fb_info = ivideo->memyselfandi;
6466 int registered = ivideo->registered;
6467 int modechanged = ivideo->modechanged;
6468
6469#ifdef SIS_OLD_CONFIG_COMPAT
6470 if(ivideo->ioctl32registered) {
6471 int ret;
6472 ret = unregister_ioctl32_conversion(FBIO_ALLOC);
6473 ret |= unregister_ioctl32_conversion(FBIO_FREE);
6474 ret |= unregister_ioctl32_conversion(FBIOGET_VBLANK);
6475 ret |= unregister_ioctl32_conversion(SISFB_GET_INFO_SIZE);
6476 ret |= unregister_ioctl32_conversion(SISFB_GET_INFO);
6477 ret |= unregister_ioctl32_conversion(SISFB_GET_TVPOSOFFSET);
6478 ret |= unregister_ioctl32_conversion(SISFB_SET_TVPOSOFFSET);
6479 ret |= unregister_ioctl32_conversion(SISFB_SET_LOCK);
6480 ret |= unregister_ioctl32_conversion(SISFB_GET_VBRSTATUS);
6481 ret |= unregister_ioctl32_conversion(SISFB_GET_AUTOMAXIMIZE);
6482 ret |= unregister_ioctl32_conversion(SISFB_SET_AUTOMAXIMIZE);
6483 ret |= unregister_ioctl32_conversion(SISFB_COMMAND);
6484 if(ret)
6485 printk(KERN_ERR
6486 "sisfb: Error unregistering ioctl32 translations\n");
6487 }
6488#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -07006489
6490 /* Unmap */
Linus Torvalds1da177e2005-04-16 15:20:36 -07006491 iounmap(ivideo->mmio_vbase);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006492 iounmap(ivideo->video_vbase);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006493
6494 /* Release mem regions */
6495 release_mem_region(ivideo->video_base, ivideo->video_size);
6496 release_mem_region(ivideo->mmio_base, ivideo->mmio_size);
6497
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006498 vfree(ivideo->bios_abase);
6499
6500 if(ivideo->lpcdev)
Adrian Bunk0959f0c2007-05-08 00:39:50 -07006501 pci_dev_put(ivideo->lpcdev);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006502
6503 if(ivideo->nbridge)
Adrian Bunk0959f0c2007-05-08 00:39:50 -07006504 pci_dev_put(ivideo->nbridge);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006505
Linus Torvalds1da177e2005-04-16 15:20:36 -07006506#ifdef CONFIG_MTRR
6507 /* Release MTRR region */
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006508 if(ivideo->mtrr >= 0)
Linus Torvalds1da177e2005-04-16 15:20:36 -07006509 mtrr_del(ivideo->mtrr, ivideo->video_base, ivideo->video_size);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006510#endif
6511
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006512 pci_set_drvdata(pdev, NULL);
6513
6514 /* If device was disabled when starting, disable
6515 * it when quitting.
6516 */
6517 if(!ivideo->sisvga_enabled)
6518 pci_disable_device(pdev);
6519
Linus Torvalds1da177e2005-04-16 15:20:36 -07006520 /* Unregister the framebuffer */
6521 if(ivideo->registered) {
6522 unregister_framebuffer(sis_fb_info);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006523 framebuffer_release(sis_fb_info);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006524 }
6525
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006526 /* OK, our ivideo is gone for good from here. */
Linus Torvalds1da177e2005-04-16 15:20:36 -07006527
6528 /* TODO: Restore the initial mode
6529 * This sounds easy but is as good as impossible
6530 * on many machines with SiS chip and video bridge
6531 * since text modes are always set up differently
6532 * from machine to machine. Depends on the type
6533 * of integration between chipset and bridge.
6534 */
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006535 if(registered && modechanged)
6536 printk(KERN_INFO
6537 "sisfb: Restoring of text mode not supported yet\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07006538};
6539
6540static struct pci_driver sisfb_driver = {
6541 .name = "sisfb",
6542 .id_table = sisfb_pci_table,
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006543 .probe = sisfb_probe,
Linus Torvalds1da177e2005-04-16 15:20:36 -07006544 .remove = __devexit_p(sisfb_remove)
6545};
6546
6547SISINITSTATIC int __init sisfb_init(void)
6548{
Linus Torvalds1da177e2005-04-16 15:20:36 -07006549#ifndef MODULE
6550 char *options = NULL;
6551
6552 if(fb_get_options("sisfb", &options))
6553 return -ENODEV;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006554
Linus Torvalds1da177e2005-04-16 15:20:36 -07006555 sisfb_setup(options);
6556#endif
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006557 return pci_register_driver(&sisfb_driver);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006558}
6559
Linus Torvalds1da177e2005-04-16 15:20:36 -07006560#ifndef MODULE
6561module_init(sisfb_init);
6562#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -07006563
6564/*****************************************************/
6565/* MODULE */
6566/*****************************************************/
6567
6568#ifdef MODULE
6569
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006570static char *mode = NULL;
6571static int vesa = -1;
6572static unsigned int rate = 0;
6573static unsigned int crt1off = 1;
6574static unsigned int mem = 0;
6575static char *forcecrt2type = NULL;
6576static int forcecrt1 = -1;
6577static int pdc = -1;
6578static int pdc1 = -1;
6579static int noaccel = -1;
6580static int noypan = -1;
6581static int nomax = -1;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006582static int userom = -1;
6583static int useoem = -1;
6584static char *tvstandard = NULL;
6585static int nocrt2rate = 0;
6586static int scalelcd = -1;
6587static char *specialtiming = NULL;
6588static int lvdshl = -1;
6589static int tvxposoffset = 0, tvyposoffset = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006590#if !defined(__i386__) && !defined(__x86_64__)
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006591static int resetcard = 0;
6592static int videoram = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006593#endif
6594
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006595static int __init sisfb_init_module(void)
6596{
6597 sisfb_setdefaultparms();
6598
6599 if(rate)
6600 sisfb_parm_rate = rate;
6601
6602 if((scalelcd == 0) || (scalelcd == 1))
6603 sisfb_scalelcd = scalelcd ^ 1;
6604
6605 /* Need to check crt2 type first for fstn/dstn */
6606
6607 if(forcecrt2type)
6608 sisfb_search_crt2type(forcecrt2type);
6609
6610 if(tvstandard)
6611 sisfb_search_tvstd(tvstandard);
6612
6613 if(mode)
Richard Knutssonc30660ea2007-02-12 00:55:06 -08006614 sisfb_search_mode(mode, false);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006615 else if(vesa != -1)
Richard Knutssonc30660ea2007-02-12 00:55:06 -08006616 sisfb_search_vesamode(vesa, false);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006617
6618 sisfb_crt1off = (crt1off == 0) ? 1 : 0;
6619
6620 sisfb_forcecrt1 = forcecrt1;
6621 if(forcecrt1 == 1)
6622 sisfb_crt1off = 0;
6623 else if(forcecrt1 == 0)
6624 sisfb_crt1off = 1;
6625
6626 if(noaccel == 1)
6627 sisfb_accel = 0;
6628 else if(noaccel == 0)
6629 sisfb_accel = 1;
6630
6631 if(noypan == 1)
6632 sisfb_ypan = 0;
6633 else if(noypan == 0)
6634 sisfb_ypan = 1;
6635
6636 if(nomax == 1)
6637 sisfb_max = 0;
6638 else if(nomax == 0)
6639 sisfb_max = 1;
6640
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006641 if(mem)
6642 sisfb_parm_mem = mem;
6643
6644 if(userom != -1)
6645 sisfb_userom = userom;
6646
6647 if(useoem != -1)
6648 sisfb_useoem = useoem;
6649
6650 if(pdc != -1)
6651 sisfb_pdc = (pdc & 0x7f);
6652
6653 if(pdc1 != -1)
6654 sisfb_pdca = (pdc1 & 0x1f);
6655
6656 sisfb_nocrt2rate = nocrt2rate;
6657
6658 if(specialtiming)
6659 sisfb_search_specialtiming(specialtiming);
6660
6661 if((lvdshl >= 0) && (lvdshl <= 3))
6662 sisfb_lvdshl = lvdshl;
6663
6664 sisfb_tvxposoffset = tvxposoffset;
6665 sisfb_tvyposoffset = tvyposoffset;
6666
6667#if !defined(__i386__) && !defined(__x86_64__)
6668 sisfb_resetcard = (resetcard) ? 1 : 0;
6669 if(videoram)
6670 sisfb_videoram = videoram;
6671#endif
6672
6673 return sisfb_init();
6674}
6675
6676static void __exit sisfb_remove_module(void)
6677{
6678 pci_unregister_driver(&sisfb_driver);
6679 printk(KERN_DEBUG "sisfb: Module unloaded\n");
6680}
6681
6682module_init(sisfb_init_module);
6683module_exit(sisfb_remove_module);
6684
6685MODULE_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 -07006686MODULE_LICENSE("GPL");
6687MODULE_AUTHOR("Thomas Winischhofer <thomas@winischhofer.net>, Others");
6688
Linus Torvalds1da177e2005-04-16 15:20:36 -07006689module_param(mem, int, 0);
6690module_param(noaccel, int, 0);
6691module_param(noypan, int, 0);
6692module_param(nomax, int, 0);
6693module_param(userom, int, 0);
6694module_param(useoem, int, 0);
6695module_param(mode, charp, 0);
6696module_param(vesa, int, 0);
6697module_param(rate, int, 0);
6698module_param(forcecrt1, int, 0);
6699module_param(forcecrt2type, charp, 0);
6700module_param(scalelcd, int, 0);
6701module_param(pdc, int, 0);
6702module_param(pdc1, int, 0);
6703module_param(specialtiming, charp, 0);
6704module_param(lvdshl, int, 0);
6705module_param(tvstandard, charp, 0);
6706module_param(tvxposoffset, int, 0);
6707module_param(tvyposoffset, int, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006708module_param(nocrt2rate, int, 0);
6709#if !defined(__i386__) && !defined(__x86_64__)
6710module_param(resetcard, int, 0);
6711module_param(videoram, int, 0);
6712#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -07006713
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006714MODULE_PARM_DESC(mem,
6715 "\nDetermines the beginning of the video memory heap in KB. This heap is used\n"
6716 "for video RAM management for eg. DRM/DRI. On 300 series, the default depends\n"
6717 "on the amount of video RAM available. If 8MB of video RAM or less is available,\n"
6718 "the heap starts at 4096KB, if between 8 and 16MB are available at 8192KB,\n"
6719 "otherwise at 12288KB. On 315/330/340 series, the heap size is 32KB by default.\n"
6720 "The value is to be specified without 'KB'.\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07006721
6722MODULE_PARM_DESC(noaccel,
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006723 "\nIf set to anything other than 0, 2D acceleration will be disabled.\n"
Linus Torvalds1da177e2005-04-16 15:20:36 -07006724 "(default: 0)\n");
6725
6726MODULE_PARM_DESC(noypan,
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006727 "\nIf set to anything other than 0, y-panning will be disabled and scrolling\n"
6728 "will be performed by redrawing the screen. (default: 0)\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07006729
6730MODULE_PARM_DESC(nomax,
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006731 "\nIf y-panning is enabled, sisfb will by default use the entire available video\n"
Linus Torvalds1da177e2005-04-16 15:20:36 -07006732 "memory for the virtual screen in order to optimize scrolling performance. If\n"
6733 "this is set to anything other than 0, sisfb will not do this and thereby \n"
6734 "enable the user to positively specify a virtual Y size of the screen using\n"
6735 "fbset. (default: 0)\n");
6736
Linus Torvalds1da177e2005-04-16 15:20:36 -07006737MODULE_PARM_DESC(mode,
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006738 "\nSelects the desired default display mode in the format XxYxDepth,\n"
6739 "eg. 1024x768x16. Other formats supported include XxY-Depth and\n"
Linus Torvalds1da177e2005-04-16 15:20:36 -07006740 "XxY-Depth@Rate. If the parameter is only one (decimal or hexadecimal)\n"
6741 "number, it will be interpreted as a VESA mode number. (default: 800x600x8)\n");
6742
6743MODULE_PARM_DESC(vesa,
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006744 "\nSelects the desired default display mode by VESA defined mode number, eg.\n"
6745 "0x117 (default: 0x0103)\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07006746
6747MODULE_PARM_DESC(rate,
6748 "\nSelects the desired vertical refresh rate for CRT1 (external VGA) in Hz.\n"
6749 "If the mode is specified in the format XxY-Depth@Rate, this parameter\n"
6750 "will be ignored (default: 60)\n");
6751
6752MODULE_PARM_DESC(forcecrt1,
6753 "\nNormally, the driver autodetects whether or not CRT1 (external VGA) is \n"
6754 "connected. With this option, the detection can be overridden (1=CRT1 ON,\n"
6755 "0=CRT1 OFF) (default: [autodetected])\n");
6756
6757MODULE_PARM_DESC(forcecrt2type,
6758 "\nIf this option is omitted, the driver autodetects CRT2 output devices, such as\n"
6759 "LCD, TV or secondary VGA. With this option, this autodetection can be\n"
6760 "overridden. Possible parameters are LCD, TV, VGA or NONE. NONE disables CRT2.\n"
6761 "On systems with a SiS video bridge, parameters SVIDEO, COMPOSITE or SCART can\n"
6762 "be used instead of TV to override the TV detection. Furthermore, on systems\n"
6763 "with a SiS video bridge, SVIDEO+COMPOSITE, HIVISION, YPBPR480I, YPBPR480P,\n"
6764 "YPBPR720P and YPBPR1080I are understood. However, whether or not these work\n"
6765 "depends on the very hardware in use. (default: [autodetected])\n");
6766
6767MODULE_PARM_DESC(scalelcd,
6768 "\nSetting this to 1 will force the driver to scale the LCD image to the panel's\n"
6769 "native resolution. Setting it to 0 will disable scaling; LVDS panels will\n"
6770 "show black bars around the image, TMDS panels will probably do the scaling\n"
6771 "themselves. Default: 1 on LVDS panels, 0 on TMDS panels\n");
6772
6773MODULE_PARM_DESC(pdc,
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006774 "\nThis is for manually selecting the LCD panel delay compensation. The driver\n"
Linus Torvalds1da177e2005-04-16 15:20:36 -07006775 "should detect this correctly in most cases; however, sometimes this is not\n"
6776 "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 -07006777 "on a 300 series chipset; 6 on other chipsets. If the problem persists, try\n"
6778 "other values (on 300 series: between 4 and 60 in steps of 4; otherwise: any\n"
6779 "value from 0 to 31). (default: autodetected, if LCD is active during start)\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07006780
6781#ifdef CONFIG_FB_SIS_315
6782MODULE_PARM_DESC(pdc1,
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006783 "\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 -07006784 "series only. (default: autodetected if LCD is in LCD-via-CRT1 mode during\n"
6785 "startup) - Note: currently, this has no effect because LCD-via-CRT1 is not\n"
6786 "implemented yet.\n");
6787#endif
6788
6789MODULE_PARM_DESC(specialtiming,
6790 "\nPlease refer to documentation for more information on this option.\n");
6791
6792MODULE_PARM_DESC(lvdshl,
6793 "\nPlease refer to documentation for more information on this option.\n");
6794
6795MODULE_PARM_DESC(tvstandard,
6796 "\nThis allows overriding the BIOS default for the TV standard. Valid choices are\n"
6797 "pal, ntsc, palm and paln. (default: [auto; pal or ntsc only])\n");
6798
6799MODULE_PARM_DESC(tvxposoffset,
6800 "\nRelocate TV output horizontally. Possible parameters: -32 through 32.\n"
6801 "Default: 0\n");
6802
6803MODULE_PARM_DESC(tvyposoffset,
6804 "\nRelocate TV output vertically. Possible parameters: -32 through 32.\n"
6805 "Default: 0\n");
6806
Linus Torvalds1da177e2005-04-16 15:20:36 -07006807MODULE_PARM_DESC(nocrt2rate,
6808 "\nSetting this to 1 will force the driver to use the default refresh rate for\n"
6809 "CRT2 if CRT2 type is VGA. (default: 0, use same rate as CRT1)\n");
6810
Linus Torvalds1da177e2005-04-16 15:20:36 -07006811#if !defined(__i386__) && !defined(__x86_64__)
6812#ifdef CONFIG_FB_SIS_300
6813MODULE_PARM_DESC(resetcard,
6814 "\nSet this to 1 in order to reset (POST) the card on non-x86 machines where\n"
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006815 "the BIOS did not POST the card (only supported for SiS 300/305 and XGI cards\n"
6816 "currently). Default: 0\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07006817
6818MODULE_PARM_DESC(videoram,
6819 "\nSet this to the amount of video RAM (in kilobyte) the card has. Required on\n"
6820 "some non-x86 architectures where the memory auto detection fails. Only\n"
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006821 "relevant if resetcard is set, too. SiS300/305 only. Default: [auto-detect]\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07006822#endif
6823#endif
6824
Linus Torvalds1da177e2005-04-16 15:20:36 -07006825#endif /* /MODULE */
6826
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006827/* _GPL only for new symbols. */
Linus Torvalds1da177e2005-04-16 15:20:36 -07006828EXPORT_SYMBOL(sis_malloc);
6829EXPORT_SYMBOL(sis_free);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006830EXPORT_SYMBOL_GPL(sis_malloc_new);
6831EXPORT_SYMBOL_GPL(sis_free_new);
6832
Linus Torvalds1da177e2005-04-16 15:20:36 -07006833
6834