blob: e8ccace01252afe2dadebcb3a74cce85fe0ae5f1 [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:
Antonino A. Daplas000d5332007-07-17 04:05:44 -07001408 if (regno >= 16)
1409 break;
1410
Linus Torvalds1da177e2005-04-16 15:20:36 -07001411 ((u32 *)(info->pseudo_palette))[regno] =
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001412 (red & 0xf800) |
1413 ((green & 0xfc00) >> 5) |
1414 ((blue & 0xf800) >> 11);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001415 break;
1416 case 32:
Antonino A. Daplas000d5332007-07-17 04:05:44 -07001417 if (regno >= 16)
1418 break;
1419
Linus Torvalds1da177e2005-04-16 15:20:36 -07001420 red >>= 8;
1421 green >>= 8;
1422 blue >>= 8;
1423 ((u32 *)(info->pseudo_palette))[regno] =
1424 (red << 16) | (green << 8) | (blue);
1425 break;
1426 }
1427 return 0;
1428}
1429
1430static int
1431sisfb_set_par(struct fb_info *info)
1432{
1433 int err;
1434
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001435 if((err = sisfb_do_set_var(&info->var, 1, info)))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001436 return err;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001437
Linus Torvalds1da177e2005-04-16 15:20:36 -07001438#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,10)
1439 sisfb_get_fix(&info->fix, info->currcon, info);
1440#else
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001441 sisfb_get_fix(&info->fix, -1, info);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001442#endif
1443 return 0;
1444}
1445
1446static int
1447sisfb_check_var(struct fb_var_screeninfo *var, struct fb_info *info)
1448{
1449 struct sis_video_info *ivideo = (struct sis_video_info *)info->par;
1450 unsigned int htotal = 0, vtotal = 0, myrateindex = 0;
1451 unsigned int drate = 0, hrate = 0, maxyres;
1452 int found_mode = 0;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001453 int refresh_rate, search_idx, tidx;
Richard Knutssonc30660ea2007-02-12 00:55:06 -08001454 bool recalc_clock = false;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001455 u32 pixclock;
1456
1457 htotal = var->left_margin + var->xres + var->right_margin + var->hsync_len;
1458
1459 vtotal = var->upper_margin + var->lower_margin + var->vsync_len;
1460
1461 pixclock = var->pixclock;
1462
1463 if((var->vmode & FB_VMODE_MASK) == FB_VMODE_NONINTERLACED) {
1464 vtotal += var->yres;
1465 vtotal <<= 1;
1466 } else if((var->vmode & FB_VMODE_MASK) == FB_VMODE_DOUBLE) {
1467 vtotal += var->yres;
1468 vtotal <<= 2;
1469 } else if((var->vmode & FB_VMODE_MASK) == FB_VMODE_INTERLACED) {
1470 vtotal += var->yres;
1471 vtotal <<= 1;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001472 } else
1473 vtotal += var->yres;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001474
1475 if(!(htotal) || !(vtotal)) {
1476 SISFAIL("sisfb: no valid timing data");
1477 }
1478
1479 search_idx = 0;
1480 while( (sisbios_mode[search_idx].mode_no[0] != 0) &&
1481 (sisbios_mode[search_idx].xres <= var->xres) ) {
1482 if( (sisbios_mode[search_idx].xres == var->xres) &&
1483 (sisbios_mode[search_idx].yres == var->yres) &&
1484 (sisbios_mode[search_idx].bpp == var->bits_per_pixel)) {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001485 if((tidx = sisfb_validate_mode(ivideo, search_idx,
1486 ivideo->currentvbflags)) > 0) {
1487 found_mode = 1;
1488 search_idx = tidx;
1489 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001490 }
1491 }
1492 search_idx++;
1493 }
1494
1495 if(!found_mode) {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001496 search_idx = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001497 while(sisbios_mode[search_idx].mode_no[0] != 0) {
1498 if( (var->xres <= sisbios_mode[search_idx].xres) &&
1499 (var->yres <= sisbios_mode[search_idx].yres) &&
1500 (var->bits_per_pixel == sisbios_mode[search_idx].bpp) ) {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001501 if((tidx = sisfb_validate_mode(ivideo,search_idx,
1502 ivideo->currentvbflags)) > 0) {
1503 found_mode = 1;
1504 search_idx = tidx;
1505 break;
1506 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001507 }
1508 search_idx++;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001509 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001510 if(found_mode) {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001511 printk(KERN_DEBUG
1512 "sisfb: Adapted from %dx%dx%d to %dx%dx%d\n",
1513 var->xres, var->yres, var->bits_per_pixel,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001514 sisbios_mode[search_idx].xres,
1515 sisbios_mode[search_idx].yres,
1516 var->bits_per_pixel);
1517 var->xres = sisbios_mode[search_idx].xres;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001518 var->yres = sisbios_mode[search_idx].yres;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001519 } else {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001520 printk(KERN_ERR
1521 "sisfb: Failed to find supported mode near %dx%dx%d\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07001522 var->xres, var->yres, var->bits_per_pixel);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001523 return -EINVAL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001524 }
1525 }
1526
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001527 if( ((ivideo->vbflags2 & VB2_LVDS) ||
1528 ((ivideo->vbflags2 & VB2_30xBDH) && (ivideo->currentvbflags & CRT2_LCD))) &&
Linus Torvalds1da177e2005-04-16 15:20:36 -07001529 (var->bits_per_pixel == 8) ) {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001530 /* Slave modes on LVDS and 301B-DH */
1531 refresh_rate = 60;
Richard Knutssonc30660ea2007-02-12 00:55:06 -08001532 recalc_clock = true;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001533 } else if( (ivideo->current_htotal == htotal) &&
1534 (ivideo->current_vtotal == vtotal) &&
1535 (ivideo->current_pixclock == pixclock) ) {
1536 /* x=x & y=y & c=c -> assume depth change */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001537 drate = 1000000000 / pixclock;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001538 hrate = (drate * 1000) / htotal;
1539 refresh_rate = (unsigned int) (hrate * 2 / vtotal);
1540 } else if( ( (ivideo->current_htotal != htotal) ||
1541 (ivideo->current_vtotal != vtotal) ) &&
1542 (ivideo->current_pixclock == var->pixclock) ) {
1543 /* x!=x | y!=y & c=c -> invalid pixclock */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001544 if(ivideo->sisfb_lastrates[sisbios_mode[search_idx].mode_no[ivideo->mni]]) {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001545 refresh_rate =
1546 ivideo->sisfb_lastrates[sisbios_mode[search_idx].mode_no[ivideo->mni]];
Linus Torvalds1da177e2005-04-16 15:20:36 -07001547 } else if(ivideo->sisfb_parm_rate != -1) {
1548 /* Sic, sisfb_parm_rate - want to know originally desired rate here */
1549 refresh_rate = ivideo->sisfb_parm_rate;
1550 } else {
1551 refresh_rate = 60;
1552 }
Richard Knutssonc30660ea2007-02-12 00:55:06 -08001553 recalc_clock = true;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001554 } else if((pixclock) && (htotal) && (vtotal)) {
1555 drate = 1000000000 / pixclock;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001556 hrate = (drate * 1000) / htotal;
1557 refresh_rate = (unsigned int) (hrate * 2 / vtotal);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001558 } else if(ivideo->current_refresh_rate) {
1559 refresh_rate = ivideo->current_refresh_rate;
Richard Knutssonc30660ea2007-02-12 00:55:06 -08001560 recalc_clock = true;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001561 } else {
1562 refresh_rate = 60;
Richard Knutssonc30660ea2007-02-12 00:55:06 -08001563 recalc_clock = true;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001564 }
1565
1566 myrateindex = sisfb_search_refresh_rate(ivideo, refresh_rate, search_idx);
1567
1568 /* Eventually recalculate timing and clock */
1569 if(recalc_clock) {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001570 if(!myrateindex) myrateindex = sisbios_mode[search_idx].rate_idx;
1571 var->pixclock = (u32) (1000000000 / sisfb_mode_rate_to_dclock(&ivideo->SiS_Pr,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001572 sisbios_mode[search_idx].mode_no[ivideo->mni],
1573 myrateindex));
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001574 sisfb_mode_rate_to_ddata(&ivideo->SiS_Pr,
1575 sisbios_mode[search_idx].mode_no[ivideo->mni],
1576 myrateindex, var);
1577 if((var->vmode & FB_VMODE_MASK) == FB_VMODE_DOUBLE) {
1578 var->pixclock <<= 1;
1579 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001580 }
1581
1582 if(ivideo->sisfb_thismonitor.datavalid) {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001583 if(!sisfb_verify_rate(ivideo, &ivideo->sisfb_thismonitor, search_idx,
1584 myrateindex, refresh_rate)) {
1585 printk(KERN_INFO
1586 "sisfb: WARNING: Refresh rate exceeds monitor specs!\n");
1587 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001588 }
1589
1590 /* Adapt RGB settings */
1591 sisfb_bpp_to_var(ivideo, var);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001592
Linus Torvalds1da177e2005-04-16 15:20:36 -07001593 /* Sanity check for offsets */
1594 if(var->xoffset < 0) var->xoffset = 0;
1595 if(var->yoffset < 0) var->yoffset = 0;
1596
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001597 if(var->xres > var->xres_virtual)
1598 var->xres_virtual = var->xres;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001599
1600 if(ivideo->sisfb_ypan) {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001601 maxyres = sisfb_calc_maxyres(ivideo, var);
1602 if(ivideo->sisfb_max) {
1603 var->yres_virtual = maxyres;
1604 } else {
1605 if(var->yres_virtual > maxyres) {
1606 var->yres_virtual = maxyres;
1607 }
1608 }
1609 if(var->yres_virtual <= var->yres) {
1610 var->yres_virtual = var->yres;
1611 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001612 } else {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001613 if(var->yres != var->yres_virtual) {
1614 var->yres_virtual = var->yres;
1615 }
1616 var->xoffset = 0;
1617 var->yoffset = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001618 }
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001619
Linus Torvalds1da177e2005-04-16 15:20:36 -07001620 /* Truncate offsets to maximum if too high */
1621 if(var->xoffset > var->xres_virtual - var->xres) {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001622 var->xoffset = var->xres_virtual - var->xres - 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001623 }
1624
1625 if(var->yoffset > var->yres_virtual - var->yres) {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001626 var->yoffset = var->yres_virtual - var->yres - 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001627 }
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001628
Linus Torvalds1da177e2005-04-16 15:20:36 -07001629 /* Set everything else to 0 */
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001630 var->red.msb_right =
1631 var->green.msb_right =
1632 var->blue.msb_right =
1633 var->transp.offset =
1634 var->transp.length =
1635 var->transp.msb_right = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001636
1637 return 0;
1638}
1639
1640static int
1641sisfb_pan_display(struct fb_var_screeninfo *var, struct fb_info* info)
1642{
1643 struct sis_video_info *ivideo = (struct sis_video_info *)info->par;
1644 int err;
1645
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001646 if(var->xoffset > (var->xres_virtual - var->xres))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001647 return -EINVAL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001648
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001649 if(var->yoffset > (var->yres_virtual - var->yres))
1650 return -EINVAL;
1651
1652 if(var->vmode & FB_VMODE_YWRAP)
1653 return -EINVAL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001654
1655 if(var->xoffset + info->var.xres > info->var.xres_virtual ||
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001656 var->yoffset + info->var.yres > info->var.yres_virtual)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001657 return -EINVAL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001658
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001659 if((err = sisfb_pan_var(ivideo, var)) < 0)
1660 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001661
1662 info->var.xoffset = var->xoffset;
1663 info->var.yoffset = var->yoffset;
1664
1665 return 0;
1666}
1667
1668static int
1669sisfb_blank(int blank, struct fb_info *info)
1670{
1671 struct sis_video_info *ivideo = (struct sis_video_info *)info->par;
1672
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001673 return sisfb_myblank(ivideo, blank);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001674}
1675
Linus Torvalds1da177e2005-04-16 15:20:36 -07001676/* ----------- FBDev related routines for all series ---------- */
1677
Christoph Hellwig67a66802006-01-14 13:21:25 -08001678#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,15)
1679static int sisfb_ioctl(struct fb_info *info, unsigned int cmd,
1680 unsigned long arg)
1681#else
1682static int sisfb_ioctl(struct inode *inode, struct file *file,
1683 unsigned int cmd, unsigned long arg,
1684 struct fb_info *info)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001685#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -07001686{
1687 struct sis_video_info *ivideo = (struct sis_video_info *)info->par;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001688 struct sis_memreq sismemreq;
1689 struct fb_vblank sisvbblank;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001690 u32 gpu32 = 0;
1691#ifndef __user
1692#define __user
1693#endif
1694 u32 __user *argp = (u32 __user *)arg;
1695
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001696 switch(cmd) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001697 case FBIO_ALLOC:
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001698 if(!capable(CAP_SYS_RAWIO))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001699 return -EPERM;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001700
1701 if(copy_from_user(&sismemreq, (void __user *)arg, sizeof(sismemreq)))
1702 return -EFAULT;
1703
Linus Torvalds1da177e2005-04-16 15:20:36 -07001704 sis_malloc(&sismemreq);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001705
Linus Torvalds1da177e2005-04-16 15:20:36 -07001706 if(copy_to_user((void __user *)arg, &sismemreq, sizeof(sismemreq))) {
1707 sis_free((u32)sismemreq.offset);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001708 return -EFAULT;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001709 }
1710 break;
1711
1712 case FBIO_FREE:
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001713 if(!capable(CAP_SYS_RAWIO))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001714 return -EPERM;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001715
1716 if(get_user(gpu32, argp))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001717 return -EFAULT;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001718
Linus Torvalds1da177e2005-04-16 15:20:36 -07001719 sis_free(gpu32);
1720 break;
1721
1722 case FBIOGET_VBLANK:
1723 sisvbblank.count = 0;
1724 sisvbblank.flags = sisfb_setupvbblankflags(ivideo, &sisvbblank.vcount, &sisvbblank.hcount);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001725
1726 if(copy_to_user((void __user *)arg, &sisvbblank, sizeof(sisvbblank)))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001727 return -EFAULT;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001728
Linus Torvalds1da177e2005-04-16 15:20:36 -07001729 break;
1730
1731 case SISFB_GET_INFO_SIZE:
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001732 return put_user(sizeof(struct sisfb_info), argp);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001733
1734 case SISFB_GET_INFO_OLD:
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001735 if(ivideo->warncount++ < 10)
1736 printk(KERN_INFO
1737 "sisfb: Deprecated ioctl call received - update your application!\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001738 case SISFB_GET_INFO: /* For communication with X driver */
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001739 ivideo->sisfb_infoblock.sisfb_id = SISFB_ID;
1740 ivideo->sisfb_infoblock.sisfb_version = VER_MAJOR;
1741 ivideo->sisfb_infoblock.sisfb_revision = VER_MINOR;
1742 ivideo->sisfb_infoblock.sisfb_patchlevel = VER_LEVEL;
1743 ivideo->sisfb_infoblock.chip_id = ivideo->chip_id;
1744 ivideo->sisfb_infoblock.sisfb_pci_vendor = ivideo->chip_vendor;
1745 ivideo->sisfb_infoblock.memory = ivideo->video_size / 1024;
1746 ivideo->sisfb_infoblock.heapstart = ivideo->heapstart / 1024;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001747 if(ivideo->modechanged) {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001748 ivideo->sisfb_infoblock.fbvidmode = ivideo->mode_no;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001749 } else {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001750 ivideo->sisfb_infoblock.fbvidmode = ivideo->modeprechange;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001751 }
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001752 ivideo->sisfb_infoblock.sisfb_caps = ivideo->caps;
1753 ivideo->sisfb_infoblock.sisfb_tqlen = ivideo->cmdQueueSize / 1024;
1754 ivideo->sisfb_infoblock.sisfb_pcibus = ivideo->pcibus;
1755 ivideo->sisfb_infoblock.sisfb_pcislot = ivideo->pcislot;
1756 ivideo->sisfb_infoblock.sisfb_pcifunc = ivideo->pcifunc;
1757 ivideo->sisfb_infoblock.sisfb_lcdpdc = ivideo->detectedpdc;
1758 ivideo->sisfb_infoblock.sisfb_lcdpdca = ivideo->detectedpdca;
1759 ivideo->sisfb_infoblock.sisfb_lcda = ivideo->detectedlcda;
1760 ivideo->sisfb_infoblock.sisfb_vbflags = ivideo->vbflags;
1761 ivideo->sisfb_infoblock.sisfb_currentvbflags = ivideo->currentvbflags;
1762 ivideo->sisfb_infoblock.sisfb_scalelcd = ivideo->SiS_Pr.UsePanelScaler;
1763 ivideo->sisfb_infoblock.sisfb_specialtiming = ivideo->SiS_Pr.SiS_CustomT;
1764 ivideo->sisfb_infoblock.sisfb_haveemi = ivideo->SiS_Pr.HaveEMI ? 1 : 0;
1765 ivideo->sisfb_infoblock.sisfb_haveemilcd = ivideo->SiS_Pr.HaveEMILCD ? 1 : 0;
1766 ivideo->sisfb_infoblock.sisfb_emi30 = ivideo->SiS_Pr.EMI_30;
1767 ivideo->sisfb_infoblock.sisfb_emi31 = ivideo->SiS_Pr.EMI_31;
1768 ivideo->sisfb_infoblock.sisfb_emi32 = ivideo->SiS_Pr.EMI_32;
1769 ivideo->sisfb_infoblock.sisfb_emi33 = ivideo->SiS_Pr.EMI_33;
1770 ivideo->sisfb_infoblock.sisfb_tvxpos = (u16)(ivideo->tvxpos + 32);
1771 ivideo->sisfb_infoblock.sisfb_tvypos = (u16)(ivideo->tvypos + 32);
1772 ivideo->sisfb_infoblock.sisfb_heapsize = ivideo->sisfb_heap_size / 1024;
1773 ivideo->sisfb_infoblock.sisfb_videooffset = ivideo->video_offset;
1774 ivideo->sisfb_infoblock.sisfb_curfstn = ivideo->curFSTN;
1775 ivideo->sisfb_infoblock.sisfb_curdstn = ivideo->curDSTN;
1776 ivideo->sisfb_infoblock.sisfb_vbflags2 = ivideo->vbflags2;
1777 ivideo->sisfb_infoblock.sisfb_can_post = ivideo->sisfb_can_post ? 1 : 0;
1778 ivideo->sisfb_infoblock.sisfb_card_posted = ivideo->sisfb_card_posted ? 1 : 0;
1779 ivideo->sisfb_infoblock.sisfb_was_boot_device = ivideo->sisfb_was_boot_device ? 1 : 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001780
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001781 if(copy_to_user((void __user *)arg, &ivideo->sisfb_infoblock,
1782 sizeof(ivideo->sisfb_infoblock)))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001783 return -EFAULT;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001784
Linus Torvalds1da177e2005-04-16 15:20:36 -07001785 break;
1786
1787 case SISFB_GET_VBRSTATUS_OLD:
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001788 if(ivideo->warncount++ < 10)
1789 printk(KERN_INFO
1790 "sisfb: Deprecated ioctl call received - update your application!\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001791 case SISFB_GET_VBRSTATUS:
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001792 if(sisfb_CheckVBRetrace(ivideo))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001793 return put_user((u32)1, argp);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001794 else
Linus Torvalds1da177e2005-04-16 15:20:36 -07001795 return put_user((u32)0, argp);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001796
1797 case SISFB_GET_AUTOMAXIMIZE_OLD:
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001798 if(ivideo->warncount++ < 10)
1799 printk(KERN_INFO
1800 "sisfb: Deprecated ioctl call received - update your application!\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001801 case SISFB_GET_AUTOMAXIMIZE:
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001802 if(ivideo->sisfb_max)
1803 return put_user((u32)1, argp);
1804 else
1805 return put_user((u32)0, argp);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001806
1807 case SISFB_SET_AUTOMAXIMIZE_OLD:
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001808 if(ivideo->warncount++ < 10)
1809 printk(KERN_INFO
1810 "sisfb: Deprecated ioctl call received - update your application!\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001811 case SISFB_SET_AUTOMAXIMIZE:
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001812 if(get_user(gpu32, argp))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001813 return -EFAULT;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001814
Linus Torvalds1da177e2005-04-16 15:20:36 -07001815 ivideo->sisfb_max = (gpu32) ? 1 : 0;
1816 break;
1817
1818 case SISFB_SET_TVPOSOFFSET:
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001819 if(get_user(gpu32, argp))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001820 return -EFAULT;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001821
Linus Torvalds1da177e2005-04-16 15:20:36 -07001822 sisfb_set_TVxposoffset(ivideo, ((int)(gpu32 >> 16)) - 32);
1823 sisfb_set_TVyposoffset(ivideo, ((int)(gpu32 & 0xffff)) - 32);
1824 break;
1825
1826 case SISFB_GET_TVPOSOFFSET:
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001827 return put_user((u32)(((ivideo->tvxpos+32)<<16)|((ivideo->tvypos+32)&0xffff)),
1828 argp);
1829
1830 case SISFB_COMMAND:
1831 if(copy_from_user(&ivideo->sisfb_command, (void __user *)arg,
1832 sizeof(struct sisfb_cmd)))
1833 return -EFAULT;
1834
1835 sisfb_handle_command(ivideo, &ivideo->sisfb_command);
1836
1837 if(copy_to_user((void __user *)arg, &ivideo->sisfb_command,
1838 sizeof(struct sisfb_cmd)))
1839 return -EFAULT;
1840
1841 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001842
1843 case SISFB_SET_LOCK:
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001844 if(get_user(gpu32, argp))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001845 return -EFAULT;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001846
Linus Torvalds1da177e2005-04-16 15:20:36 -07001847 ivideo->sisfblocked = (gpu32) ? 1 : 0;
1848 break;
1849
1850 default:
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001851#ifdef SIS_NEW_CONFIG_COMPAT
Linus Torvalds1da177e2005-04-16 15:20:36 -07001852 return -ENOIOCTLCMD;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001853#else
1854 return -EINVAL;
1855#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -07001856 }
1857 return 0;
1858}
1859
Linus Torvalds1da177e2005-04-16 15:20:36 -07001860static int
1861sisfb_get_fix(struct fb_fix_screeninfo *fix, int con, struct fb_info *info)
1862{
1863 struct sis_video_info *ivideo = (struct sis_video_info *)info->par;
1864
1865 memset(fix, 0, sizeof(struct fb_fix_screeninfo));
1866
1867 strcpy(fix->id, ivideo->myid);
1868
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001869 fix->smem_start = ivideo->video_base + ivideo->video_offset;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001870 fix->smem_len = ivideo->sisfb_mem;
1871 fix->type = FB_TYPE_PACKED_PIXELS;
1872 fix->type_aux = 0;
1873 fix->visual = (ivideo->video_bpp == 8) ? FB_VISUAL_PSEUDOCOLOR : FB_VISUAL_TRUECOLOR;
1874 fix->xpanstep = 1;
1875 fix->ypanstep = (ivideo->sisfb_ypan) ? 1 : 0;
1876 fix->ywrapstep = 0;
1877 fix->line_length = ivideo->video_linelength;
1878 fix->mmio_start = ivideo->mmio_base;
1879 fix->mmio_len = ivideo->mmio_size;
1880 if(ivideo->sisvga_engine == SIS_300_VGA) {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001881 fix->accel = FB_ACCEL_SIS_GLAMOUR;
1882 } else if((ivideo->chip == SIS_330) ||
1883 (ivideo->chip == SIS_760) ||
1884 (ivideo->chip == SIS_761)) {
1885 fix->accel = FB_ACCEL_SIS_XABRE;
1886 } else if(ivideo->chip == XGI_20) {
1887 fix->accel = FB_ACCEL_XGI_VOLARI_Z;
1888 } else if(ivideo->chip >= XGI_40) {
1889 fix->accel = FB_ACCEL_XGI_VOLARI_V;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001890 } else {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001891 fix->accel = FB_ACCEL_SIS_GLAMOUR_2;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001892 }
1893
1894 return 0;
1895}
1896
1897/* ---------------- fb_ops structures ----------------- */
1898
Linus Torvalds1da177e2005-04-16 15:20:36 -07001899static struct fb_ops sisfb_ops = {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001900 .owner = THIS_MODULE,
1901 .fb_open = sisfb_open,
1902 .fb_release = sisfb_release,
1903 .fb_check_var = sisfb_check_var,
1904 .fb_set_par = sisfb_set_par,
1905 .fb_setcolreg = sisfb_setcolreg,
1906 .fb_pan_display = sisfb_pan_display,
1907 .fb_blank = sisfb_blank,
1908 .fb_fillrect = fbcon_sis_fillrect,
1909 .fb_copyarea = fbcon_sis_copyarea,
1910 .fb_imageblit = cfb_imageblit,
Antonino A. Daplasc465e052005-11-07 01:00:35 -08001911#ifdef CONFIG_FB_SOFT_CURSOR
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001912 .fb_cursor = soft_cursor,
Antonino A. Daplasc465e052005-11-07 01:00:35 -08001913#endif
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001914 .fb_sync = fbcon_sis_sync,
1915#ifdef SIS_NEW_CONFIG_COMPAT
Christoph Hellwig67a66802006-01-14 13:21:25 -08001916 .fb_compat_ioctl= sisfb_ioctl,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001917#endif
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001918 .fb_ioctl = sisfb_ioctl
Linus Torvalds1da177e2005-04-16 15:20:36 -07001919};
Linus Torvalds1da177e2005-04-16 15:20:36 -07001920
1921/* ---------------- Chip generation dependent routines ---------------- */
1922
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001923static struct pci_dev * __devinit
1924sisfb_get_northbridge(int basechipid)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001925{
1926 struct pci_dev *pdev = NULL;
1927 int nbridgenum, nbridgeidx, i;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001928 static const unsigned short nbridgeids[] = {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001929 PCI_DEVICE_ID_SI_540, /* for SiS 540 VGA */
1930 PCI_DEVICE_ID_SI_630, /* for SiS 630/730 VGA */
1931 PCI_DEVICE_ID_SI_730,
1932 PCI_DEVICE_ID_SI_550, /* for SiS 550 VGA */
1933 PCI_DEVICE_ID_SI_650, /* for SiS 650/651/740 VGA */
1934 PCI_DEVICE_ID_SI_651,
1935 PCI_DEVICE_ID_SI_740,
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001936 PCI_DEVICE_ID_SI_661, /* for SiS 661/741/660/760/761 VGA */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001937 PCI_DEVICE_ID_SI_741,
1938 PCI_DEVICE_ID_SI_660,
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001939 PCI_DEVICE_ID_SI_760,
1940 PCI_DEVICE_ID_SI_761
Linus Torvalds1da177e2005-04-16 15:20:36 -07001941 };
1942
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001943 switch(basechipid) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001944#ifdef CONFIG_FB_SIS_300
1945 case SIS_540: nbridgeidx = 0; nbridgenum = 1; break;
1946 case SIS_630: nbridgeidx = 1; nbridgenum = 2; break;
1947#endif
1948#ifdef CONFIG_FB_SIS_315
1949 case SIS_550: nbridgeidx = 3; nbridgenum = 1; break;
1950 case SIS_650: nbridgeidx = 4; nbridgenum = 3; break;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001951 case SIS_660: nbridgeidx = 7; nbridgenum = 5; break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001952#endif
1953 default: return NULL;
1954 }
1955 for(i = 0; i < nbridgenum; i++) {
Adrian Bunk0959f0c2007-05-08 00:39:50 -07001956 if((pdev = pci_get_device(PCI_VENDOR_ID_SI,
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001957 nbridgeids[nbridgeidx+i], NULL)))
1958 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001959 }
1960 return pdev;
1961}
1962
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001963static int __devinit
1964sisfb_get_dram_size(struct sis_video_info *ivideo)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001965{
1966#if defined(CONFIG_FB_SIS_300) || defined(CONFIG_FB_SIS_315)
1967 u8 reg;
1968#endif
1969
1970 ivideo->video_size = 0;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001971 ivideo->UMAsize = ivideo->LFBsize = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001972
1973 switch(ivideo->chip) {
1974#ifdef CONFIG_FB_SIS_300
1975 case SIS_300:
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001976 inSISIDXREG(SISSR, 0x14, reg);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001977 ivideo->video_size = ((reg & 0x3F) + 1) << 20;
1978 break;
1979 case SIS_540:
1980 case SIS_630:
1981 case SIS_730:
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001982 if(!ivideo->nbridge)
1983 return -1;
1984 pci_read_config_byte(ivideo->nbridge, 0x63, &reg);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001985 ivideo->video_size = 1 << (((reg & 0x70) >> 4) + 21);
1986 break;
1987#endif
1988#ifdef CONFIG_FB_SIS_315
1989 case SIS_315H:
1990 case SIS_315PRO:
1991 case SIS_315:
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001992 inSISIDXREG(SISSR, 0x14, reg);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001993 ivideo->video_size = (1 << ((reg & 0xf0) >> 4)) << 20;
1994 switch((reg >> 2) & 0x03) {
1995 case 0x01:
1996 case 0x03:
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001997 ivideo->video_size <<= 1;
1998 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001999 case 0x02:
Thomas Winischhofer544393f2005-09-09 13:04:45 -07002000 ivideo->video_size += (ivideo->video_size/2);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002001 }
Thomas Winischhofer544393f2005-09-09 13:04:45 -07002002 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002003 case SIS_330:
Thomas Winischhofer544393f2005-09-09 13:04:45 -07002004 inSISIDXREG(SISSR, 0x14, reg);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002005 ivideo->video_size = (1 << ((reg & 0xf0) >> 4)) << 20;
2006 if(reg & 0x0c) ivideo->video_size <<= 1;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07002007 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002008 case SIS_550:
2009 case SIS_650:
2010 case SIS_740:
Thomas Winischhofer544393f2005-09-09 13:04:45 -07002011 inSISIDXREG(SISSR, 0x14, reg);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002012 ivideo->video_size = (((reg & 0x3f) + 1) << 2) << 20;
2013 break;
2014 case SIS_661:
2015 case SIS_741:
Thomas Winischhofer544393f2005-09-09 13:04:45 -07002016 inSISIDXREG(SISCR, 0x79, reg);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002017 ivideo->video_size = (1 << ((reg & 0xf0) >> 4)) << 20;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07002018 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002019 case SIS_660:
2020 case SIS_760:
Thomas Winischhofer544393f2005-09-09 13:04:45 -07002021 case SIS_761:
Linus Torvalds1da177e2005-04-16 15:20:36 -07002022 inSISIDXREG(SISCR, 0x79, reg);
2023 reg = (reg & 0xf0) >> 4;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07002024 if(reg) {
2025 ivideo->video_size = (1 << reg) << 20;
2026 ivideo->UMAsize = ivideo->video_size;
2027 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002028 inSISIDXREG(SISCR, 0x78, reg);
2029 reg &= 0x30;
2030 if(reg) {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07002031 if(reg == 0x10) {
2032 ivideo->LFBsize = (32 << 20);
2033 } else {
2034 ivideo->LFBsize = (64 << 20);
2035 }
2036 ivideo->video_size += ivideo->LFBsize;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002037 }
Thomas Winischhofer544393f2005-09-09 13:04:45 -07002038 break;
2039 case SIS_340:
2040 case XGI_20:
2041 case XGI_40:
2042 inSISIDXREG(SISSR, 0x14, reg);
2043 ivideo->video_size = (1 << ((reg & 0xf0) >> 4)) << 20;
2044 if(ivideo->chip != XGI_20) {
2045 reg = (reg & 0x0c) >> 2;
2046 if(ivideo->revision_id == 2) {
2047 if(reg & 0x01) reg = 0x02;
2048 else reg = 0x00;
2049 }
2050 if(reg == 0x02) ivideo->video_size <<= 1;
2051 else if(reg == 0x03) ivideo->video_size <<= 2;
2052 }
2053 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002054#endif
2055 default:
2056 return -1;
2057 }
2058 return 0;
2059}
2060
2061/* -------------- video bridge device detection --------------- */
2062
Thomas Winischhofer544393f2005-09-09 13:04:45 -07002063static void __devinit
2064sisfb_detect_VB_connect(struct sis_video_info *ivideo)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002065{
2066 u8 cr32, temp;
2067
Thomas Winischhofer544393f2005-09-09 13:04:45 -07002068 /* No CRT2 on XGI Z7 */
2069 if(ivideo->chip == XGI_20) {
2070 ivideo->sisfb_crt1off = 0;
2071 return;
2072 }
2073
Linus Torvalds1da177e2005-04-16 15:20:36 -07002074#ifdef CONFIG_FB_SIS_300
2075 if(ivideo->sisvga_engine == SIS_300_VGA) {
2076 inSISIDXREG(SISSR, 0x17, temp);
2077 if((temp & 0x0F) && (ivideo->chip != SIS_300)) {
2078 /* PAL/NTSC is stored on SR16 on such machines */
2079 if(!(ivideo->vbflags & (TV_PAL | TV_NTSC | TV_PALM | TV_PALN))) {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07002080 inSISIDXREG(SISSR, 0x16, temp);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002081 if(temp & 0x20)
2082 ivideo->vbflags |= TV_PAL;
2083 else
2084 ivideo->vbflags |= TV_NTSC;
2085 }
2086 }
2087 }
2088#endif
2089
2090 inSISIDXREG(SISCR, 0x32, cr32);
2091
2092 if(cr32 & SIS_CRT1) {
2093 ivideo->sisfb_crt1off = 0;
2094 } else {
2095 ivideo->sisfb_crt1off = (cr32 & 0xDF) ? 1 : 0;
2096 }
2097
2098 ivideo->vbflags &= ~(CRT2_TV | CRT2_LCD | CRT2_VGA);
2099
2100 if(cr32 & SIS_VB_TV) ivideo->vbflags |= CRT2_TV;
2101 if(cr32 & SIS_VB_LCD) ivideo->vbflags |= CRT2_LCD;
2102 if(cr32 & SIS_VB_CRT2) ivideo->vbflags |= CRT2_VGA;
2103
2104 /* Check given parms for hardware compatibility.
2105 * (Cannot do this in the search_xx routines since we don't
2106 * know what hardware we are running on then)
2107 */
2108
2109 if(ivideo->chip != SIS_550) {
2110 ivideo->sisfb_dstn = ivideo->sisfb_fstn = 0;
2111 }
2112
2113 if(ivideo->sisfb_tvplug != -1) {
2114 if( (ivideo->sisvga_engine != SIS_315_VGA) ||
Thomas Winischhofer544393f2005-09-09 13:04:45 -07002115 (!(ivideo->vbflags2 & VB2_SISYPBPRBRIDGE)) ) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002116 if(ivideo->sisfb_tvplug & TV_YPBPR) {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07002117 ivideo->sisfb_tvplug = -1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002118 printk(KERN_ERR "sisfb: YPbPr not supported\n");
2119 }
2120 }
2121 }
2122 if(ivideo->sisfb_tvplug != -1) {
2123 if( (ivideo->sisvga_engine != SIS_315_VGA) ||
Thomas Winischhofer544393f2005-09-09 13:04:45 -07002124 (!(ivideo->vbflags2 & VB2_SISHIVISIONBRIDGE)) ) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002125 if(ivideo->sisfb_tvplug & TV_HIVISION) {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07002126 ivideo->sisfb_tvplug = -1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002127 printk(KERN_ERR "sisfb: HiVision not supported\n");
2128 }
2129 }
2130 }
2131 if(ivideo->sisfb_tvstd != -1) {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07002132 if( (!(ivideo->vbflags2 & VB2_SISBRIDGE)) &&
2133 (!((ivideo->sisvga_engine == SIS_315_VGA) &&
2134 (ivideo->vbflags2 & VB2_CHRONTEL))) ) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002135 if(ivideo->sisfb_tvstd & (TV_PALN | TV_PALN | TV_NTSCJ)) {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07002136 ivideo->sisfb_tvstd = -1;
2137 printk(KERN_ERR "sisfb: PALM/PALN/NTSCJ not supported\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002138 }
2139 }
2140 }
2141
2142 /* Detect/set TV plug & type */
2143 if(ivideo->sisfb_tvplug != -1) {
2144 ivideo->vbflags |= ivideo->sisfb_tvplug;
2145 } else {
2146 if(cr32 & SIS_VB_YPBPR) ivideo->vbflags |= (TV_YPBPR|TV_YPBPR525I); /* default: 480i */
2147 else if(cr32 & SIS_VB_HIVISION) ivideo->vbflags |= TV_HIVISION;
2148 else if(cr32 & SIS_VB_SCART) ivideo->vbflags |= TV_SCART;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07002149 else {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002150 if(cr32 & SIS_VB_SVIDEO) ivideo->vbflags |= TV_SVIDEO;
2151 if(cr32 & SIS_VB_COMPOSITE) ivideo->vbflags |= TV_AVIDEO;
2152 }
2153 }
2154
2155 if(!(ivideo->vbflags & (TV_YPBPR | TV_HIVISION))) {
2156 if(ivideo->sisfb_tvstd != -1) {
2157 ivideo->vbflags &= ~(TV_NTSC | TV_PAL | TV_PALM | TV_PALN | TV_NTSCJ);
2158 ivideo->vbflags |= ivideo->sisfb_tvstd;
2159 }
2160 if(ivideo->vbflags & TV_SCART) {
2161 ivideo->vbflags &= ~(TV_NTSC | TV_PALM | TV_PALN | TV_NTSCJ);
2162 ivideo->vbflags |= TV_PAL;
2163 }
2164 if(!(ivideo->vbflags & (TV_PAL | TV_NTSC | TV_PALM | TV_PALN | TV_NTSCJ))) {
2165 if(ivideo->sisvga_engine == SIS_300_VGA) {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07002166 inSISIDXREG(SISSR, 0x38, temp);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002167 if(temp & 0x01) ivideo->vbflags |= TV_PAL;
2168 else ivideo->vbflags |= TV_NTSC;
2169 } else if((ivideo->chip <= SIS_315PRO) || (ivideo->chip >= SIS_330)) {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07002170 inSISIDXREG(SISSR, 0x38, temp);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002171 if(temp & 0x01) ivideo->vbflags |= TV_PAL;
2172 else ivideo->vbflags |= TV_NTSC;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07002173 } else {
2174 inSISIDXREG(SISCR, 0x79, temp);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002175 if(temp & 0x20) ivideo->vbflags |= TV_PAL;
2176 else ivideo->vbflags |= TV_NTSC;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07002177 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002178 }
2179 }
2180
2181 /* Copy forceCRT1 option to CRT1off if option is given */
Thomas Winischhofer544393f2005-09-09 13:04:45 -07002182 if(ivideo->sisfb_forcecrt1 != -1) {
2183 ivideo->sisfb_crt1off = (ivideo->sisfb_forcecrt1) ? 0 : 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002184 }
2185}
2186
2187/* ------------------ Sensing routines ------------------ */
2188
Richard Knutssonc30660ea2007-02-12 00:55:06 -08002189static bool __devinit
Thomas Winischhofer544393f2005-09-09 13:04:45 -07002190sisfb_test_DDC1(struct sis_video_info *ivideo)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002191{
2192 unsigned short old;
2193 int count = 48;
2194
2195 old = SiS_ReadDDC1Bit(&ivideo->SiS_Pr);
2196 do {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07002197 if(old != SiS_ReadDDC1Bit(&ivideo->SiS_Pr)) break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002198 } while(count--);
Richard Knutssonc30660ea2007-02-12 00:55:06 -08002199 return (count != -1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002200}
2201
Thomas Winischhofer544393f2005-09-09 13:04:45 -07002202static void __devinit
2203sisfb_sense_crt1(struct sis_video_info *ivideo)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002204{
Richard Knutssonc30660ea2007-02-12 00:55:06 -08002205 bool mustwait = false;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002206 u8 sr1F, cr17;
2207#ifdef CONFIG_FB_SIS_315
2208 u8 cr63=0;
2209#endif
2210 u16 temp = 0xffff;
2211 int i;
2212
2213 inSISIDXREG(SISSR,0x1F,sr1F);
2214 orSISIDXREG(SISSR,0x1F,0x04);
2215 andSISIDXREG(SISSR,0x1F,0x3F);
Richard Knutssonc30660ea2007-02-12 00:55:06 -08002216 if(sr1F & 0xc0) mustwait = true;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002217
2218#ifdef CONFIG_FB_SIS_315
2219 if(ivideo->sisvga_engine == SIS_315_VGA) {
2220 inSISIDXREG(SISCR,ivideo->SiS_Pr.SiS_MyCR63,cr63);
2221 cr63 &= 0x40;
2222 andSISIDXREG(SISCR,ivideo->SiS_Pr.SiS_MyCR63,0xBF);
2223 }
2224#endif
2225
2226 inSISIDXREG(SISCR,0x17,cr17);
2227 cr17 &= 0x80;
2228 if(!cr17) {
2229 orSISIDXREG(SISCR,0x17,0x80);
Richard Knutssonc30660ea2007-02-12 00:55:06 -08002230 mustwait = true;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002231 outSISIDXREG(SISSR, 0x00, 0x01);
2232 outSISIDXREG(SISSR, 0x00, 0x03);
2233 }
2234
2235 if(mustwait) {
2236 for(i=0; i < 10; i++) sisfbwaitretracecrt1(ivideo);
2237 }
2238
2239#ifdef CONFIG_FB_SIS_315
2240 if(ivideo->chip >= SIS_330) {
2241 andSISIDXREG(SISCR,0x32,~0x20);
2242 if(ivideo->chip >= SIS_340) {
2243 outSISIDXREG(SISCR, 0x57, 0x4a);
2244 } else {
2245 outSISIDXREG(SISCR, 0x57, 0x5f);
2246 }
2247 orSISIDXREG(SISCR, 0x53, 0x02);
2248 while((inSISREG(SISINPSTAT)) & 0x01) break;
2249 while(!((inSISREG(SISINPSTAT)) & 0x01)) break;
2250 if((inSISREG(SISMISCW)) & 0x10) temp = 1;
2251 andSISIDXREG(SISCR, 0x53, 0xfd);
2252 andSISIDXREG(SISCR, 0x57, 0x00);
2253 }
2254#endif
2255
2256 if(temp == 0xffff) {
2257 i = 3;
2258 do {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07002259 temp = SiS_HandleDDC(&ivideo->SiS_Pr, ivideo->vbflags,
2260 ivideo->sisvga_engine, 0, 0, NULL, ivideo->vbflags2);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002261 } while(((temp == 0) || (temp == 0xffff)) && i--);
2262
2263 if((temp == 0) || (temp == 0xffff)) {
2264 if(sisfb_test_DDC1(ivideo)) temp = 1;
2265 }
2266 }
2267
2268 if((temp) && (temp != 0xffff)) {
2269 orSISIDXREG(SISCR,0x32,0x20);
2270 }
2271
2272#ifdef CONFIG_FB_SIS_315
2273 if(ivideo->sisvga_engine == SIS_315_VGA) {
2274 setSISIDXREG(SISCR,ivideo->SiS_Pr.SiS_MyCR63,0xBF,cr63);
2275 }
2276#endif
2277
2278 setSISIDXREG(SISCR,0x17,0x7F,cr17);
2279
2280 outSISIDXREG(SISSR,0x1F,sr1F);
2281}
2282
2283/* Determine and detect attached devices on SiS30x */
Thomas Winischhofer544393f2005-09-09 13:04:45 -07002284static void __devinit
2285SiS_SenseLCD(struct sis_video_info *ivideo)
2286{
2287 unsigned char buffer[256];
2288 unsigned short temp, realcrtno, i;
2289 u8 reg, cr37 = 0, paneltype = 0;
2290 u16 xres, yres;
2291
Richard Knutssonc30660ea2007-02-12 00:55:06 -08002292 ivideo->SiS_Pr.PanelSelfDetected = false;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07002293
2294 /* LCD detection only for TMDS bridges */
2295 if(!(ivideo->vbflags2 & VB2_SISTMDSBRIDGE))
2296 return;
2297 if(ivideo->vbflags2 & VB2_30xBDH)
2298 return;
2299
2300 /* If LCD already set up by BIOS, skip it */
2301 inSISIDXREG(SISCR, 0x32, reg);
2302 if(reg & 0x08)
2303 return;
2304
2305 realcrtno = 1;
2306 if(ivideo->SiS_Pr.DDCPortMixup)
2307 realcrtno = 0;
2308
2309 /* Check DDC capabilities */
2310 temp = SiS_HandleDDC(&ivideo->SiS_Pr, ivideo->vbflags, ivideo->sisvga_engine,
2311 realcrtno, 0, &buffer[0], ivideo->vbflags2);
2312
2313 if((!temp) || (temp == 0xffff) || (!(temp & 0x02)))
2314 return;
2315
2316 /* Read DDC data */
2317 i = 3; /* Number of retrys */
2318 do {
2319 temp = SiS_HandleDDC(&ivideo->SiS_Pr, ivideo->vbflags,
2320 ivideo->sisvga_engine, realcrtno, 1,
2321 &buffer[0], ivideo->vbflags2);
2322 } while((temp) && i--);
2323
2324 if(temp)
2325 return;
2326
2327 /* No digital device */
2328 if(!(buffer[0x14] & 0x80))
2329 return;
2330
2331 /* First detailed timing preferred timing? */
2332 if(!(buffer[0x18] & 0x02))
2333 return;
2334
2335 xres = buffer[0x38] | ((buffer[0x3a] & 0xf0) << 4);
2336 yres = buffer[0x3b] | ((buffer[0x3d] & 0xf0) << 4);
2337
2338 switch(xres) {
2339 case 1024:
2340 if(yres == 768)
2341 paneltype = 0x02;
2342 break;
2343 case 1280:
2344 if(yres == 1024)
2345 paneltype = 0x03;
2346 break;
2347 case 1600:
2348 if((yres == 1200) && (ivideo->vbflags2 & VB2_30xC))
2349 paneltype = 0x0b;
2350 break;
2351 }
2352
2353 if(!paneltype)
2354 return;
2355
2356 if(buffer[0x23])
2357 cr37 |= 0x10;
2358
2359 if((buffer[0x47] & 0x18) == 0x18)
2360 cr37 |= ((((buffer[0x47] & 0x06) ^ 0x06) << 5) | 0x20);
2361 else
2362 cr37 |= 0xc0;
2363
2364 outSISIDXREG(SISCR, 0x36, paneltype);
2365 cr37 &= 0xf1;
2366 setSISIDXREG(SISCR, 0x37, 0x0c, cr37);
2367 orSISIDXREG(SISCR, 0x32, 0x08);
2368
Richard Knutssonc30660ea2007-02-12 00:55:06 -08002369 ivideo->SiS_Pr.PanelSelfDetected = true;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07002370}
2371
2372static int __devinit
2373SISDoSense(struct sis_video_info *ivideo, u16 type, u16 test)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002374{
2375 int temp, mytest, result, i, j;
2376
2377 for(j = 0; j < 10; j++) {
2378 result = 0;
2379 for(i = 0; i < 3; i++) {
2380 mytest = test;
2381 outSISIDXREG(SISPART4,0x11,(type & 0x00ff));
2382 temp = (type >> 8) | (mytest & 0x00ff);
2383 setSISIDXREG(SISPART4,0x10,0xe0,temp);
2384 SiS_DDC2Delay(&ivideo->SiS_Pr, 0x1500);
2385 mytest >>= 8;
2386 mytest &= 0x7f;
2387 inSISIDXREG(SISPART4,0x03,temp);
2388 temp ^= 0x0e;
2389 temp &= mytest;
2390 if(temp == mytest) result++;
2391#if 1
2392 outSISIDXREG(SISPART4,0x11,0x00);
2393 andSISIDXREG(SISPART4,0x10,0xe0);
2394 SiS_DDC2Delay(&ivideo->SiS_Pr, 0x1000);
2395#endif
2396 }
2397 if((result == 0) || (result >= 2)) break;
2398 }
Thomas Winischhofer544393f2005-09-09 13:04:45 -07002399 return result;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002400}
2401
Thomas Winischhofer544393f2005-09-09 13:04:45 -07002402static void __devinit
2403SiS_Sense30x(struct sis_video_info *ivideo)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002404{
2405 u8 backupP4_0d,backupP2_00,backupP2_4d,backupSR_1e,biosflag=0;
2406 u16 svhs=0, svhs_c=0;
2407 u16 cvbs=0, cvbs_c=0;
2408 u16 vga2=0, vga2_c=0;
2409 int myflag, result;
2410 char stdstr[] = "sisfb: Detected";
2411 char tvstr[] = "TV connected to";
2412
Thomas Winischhofer544393f2005-09-09 13:04:45 -07002413 if(ivideo->vbflags2 & VB2_301) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002414 svhs = 0x00b9; cvbs = 0x00b3; vga2 = 0x00d1;
2415 inSISIDXREG(SISPART4,0x01,myflag);
2416 if(myflag & 0x04) {
2417 svhs = 0x00dd; cvbs = 0x00ee; vga2 = 0x00fd;
2418 }
Thomas Winischhofer544393f2005-09-09 13:04:45 -07002419 } else if(ivideo->vbflags2 & (VB2_301B | VB2_302B)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002420 svhs = 0x016b; cvbs = 0x0174; vga2 = 0x0190;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07002421 } else if(ivideo->vbflags2 & (VB2_301LV | VB2_302LV)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002422 svhs = 0x0200; cvbs = 0x0100;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07002423 } else if(ivideo->vbflags2 & (VB2_301C | VB2_302ELV | VB2_307T | VB2_307LV)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002424 svhs = 0x016b; cvbs = 0x0110; vga2 = 0x0190;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07002425 } else
2426 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002427
2428 vga2_c = 0x0e08; svhs_c = 0x0404; cvbs_c = 0x0804;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07002429 if(ivideo->vbflags & (VB2_301LV|VB2_302LV|VB2_302ELV|VB2_307LV)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002430 svhs_c = 0x0408; cvbs_c = 0x0808;
2431 }
Thomas Winischhofer544393f2005-09-09 13:04:45 -07002432
Linus Torvalds1da177e2005-04-16 15:20:36 -07002433 biosflag = 2;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07002434 if(ivideo->haveXGIROM) {
2435 biosflag = ivideo->bios_abase[0x58] & 0x03;
2436 } else if(ivideo->newrom) {
2437 if(ivideo->bios_abase[0x5d] & 0x04) biosflag |= 0x01;
2438 } else if(ivideo->sisvga_engine == SIS_300_VGA) {
2439 if(ivideo->bios_abase) {
2440 biosflag = ivideo->bios_abase[0xfe] & 0x03;
2441 }
2442 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002443
2444 if(ivideo->chip == SIS_300) {
2445 inSISIDXREG(SISSR,0x3b,myflag);
2446 if(!(myflag & 0x01)) vga2 = vga2_c = 0;
2447 }
2448
Thomas Winischhofer544393f2005-09-09 13:04:45 -07002449 if(!(ivideo->vbflags2 & VB2_SISVGA2BRIDGE)) {
2450 vga2 = vga2_c = 0;
2451 }
2452
Linus Torvalds1da177e2005-04-16 15:20:36 -07002453 inSISIDXREG(SISSR,0x1e,backupSR_1e);
2454 orSISIDXREG(SISSR,0x1e,0x20);
2455
2456 inSISIDXREG(SISPART4,0x0d,backupP4_0d);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07002457 if(ivideo->vbflags2 & VB2_30xC) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002458 setSISIDXREG(SISPART4,0x0d,~0x07,0x01);
2459 } else {
2460 orSISIDXREG(SISPART4,0x0d,0x04);
2461 }
2462 SiS_DDC2Delay(&ivideo->SiS_Pr, 0x2000);
2463
2464 inSISIDXREG(SISPART2,0x00,backupP2_00);
2465 outSISIDXREG(SISPART2,0x00,((backupP2_00 | 0x1c) & 0xfc));
2466
2467 inSISIDXREG(SISPART2,0x4d,backupP2_4d);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07002468 if(ivideo->vbflags2 & VB2_SISYPBPRBRIDGE) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002469 outSISIDXREG(SISPART2,0x4d,(backupP2_4d & ~0x10));
2470 }
2471
Thomas Winischhofer544393f2005-09-09 13:04:45 -07002472 if(!(ivideo->vbflags2 & VB2_30xCLV)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002473 SISDoSense(ivideo, 0, 0);
2474 }
2475
2476 andSISIDXREG(SISCR, 0x32, ~0x14);
2477
2478 if(vga2_c || vga2) {
2479 if(SISDoSense(ivideo, vga2, vga2_c)) {
2480 if(biosflag & 0x01) {
2481 printk(KERN_INFO "%s %s SCART output\n", stdstr, tvstr);
2482 orSISIDXREG(SISCR, 0x32, 0x04);
2483 } else {
2484 printk(KERN_INFO "%s secondary VGA connection\n", stdstr);
2485 orSISIDXREG(SISCR, 0x32, 0x10);
2486 }
2487 }
2488 }
2489
2490 andSISIDXREG(SISCR, 0x32, 0x3f);
2491
Thomas Winischhofer544393f2005-09-09 13:04:45 -07002492 if(ivideo->vbflags2 & VB2_30xCLV) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002493 orSISIDXREG(SISPART4,0x0d,0x04);
2494 }
2495
Thomas Winischhofer544393f2005-09-09 13:04:45 -07002496 if((ivideo->sisvga_engine == SIS_315_VGA) && (ivideo->vbflags2 & VB2_SISYPBPRBRIDGE)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002497 outSISIDXREG(SISPART2,0x4d,(backupP2_4d | 0x10));
2498 SiS_DDC2Delay(&ivideo->SiS_Pr, 0x2000);
2499 if((result = SISDoSense(ivideo, svhs, 0x0604))) {
2500 if((result = SISDoSense(ivideo, cvbs, 0x0804))) {
2501 printk(KERN_INFO "%s %s YPbPr component output\n", stdstr, tvstr);
2502 orSISIDXREG(SISCR,0x32,0x80);
2503 }
2504 }
2505 outSISIDXREG(SISPART2,0x4d,backupP2_4d);
2506 }
2507
2508 andSISIDXREG(SISCR, 0x32, ~0x03);
2509
2510 if(!(ivideo->vbflags & TV_YPBPR)) {
2511 if((result = SISDoSense(ivideo, svhs, svhs_c))) {
2512 printk(KERN_INFO "%s %s SVIDEO output\n", stdstr, tvstr);
2513 orSISIDXREG(SISCR, 0x32, 0x02);
2514 }
2515 if((biosflag & 0x02) || (!result)) {
2516 if(SISDoSense(ivideo, cvbs, cvbs_c)) {
2517 printk(KERN_INFO "%s %s COMPOSITE output\n", stdstr, tvstr);
2518 orSISIDXREG(SISCR, 0x32, 0x01);
2519 }
2520 }
2521 }
2522
2523 SISDoSense(ivideo, 0, 0);
2524
2525 outSISIDXREG(SISPART2,0x00,backupP2_00);
2526 outSISIDXREG(SISPART4,0x0d,backupP4_0d);
2527 outSISIDXREG(SISSR,0x1e,backupSR_1e);
2528
Thomas Winischhofer544393f2005-09-09 13:04:45 -07002529 if(ivideo->vbflags2 & VB2_30xCLV) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002530 inSISIDXREG(SISPART2,0x00,biosflag);
2531 if(biosflag & 0x20) {
2532 for(myflag = 2; myflag > 0; myflag--) {
2533 biosflag ^= 0x20;
2534 outSISIDXREG(SISPART2,0x00,biosflag);
2535 }
2536 }
2537 }
2538
2539 outSISIDXREG(SISPART2,0x00,backupP2_00);
2540}
2541
2542/* Determine and detect attached TV's on Chrontel */
Thomas Winischhofer544393f2005-09-09 13:04:45 -07002543static void __devinit
2544SiS_SenseCh(struct sis_video_info *ivideo)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002545{
2546#if defined(CONFIG_FB_SIS_300) || defined(CONFIG_FB_SIS_315)
2547 u8 temp1, temp2;
2548 char stdstr[] = "sisfb: Chrontel: Detected TV connected to";
2549#endif
2550#ifdef CONFIG_FB_SIS_300
2551 unsigned char test[3];
2552 int i;
2553#endif
2554
2555 if(ivideo->chip < SIS_315H) {
2556
2557#ifdef CONFIG_FB_SIS_300
2558 ivideo->SiS_Pr.SiS_IF_DEF_CH70xx = 1; /* Chrontel 700x */
2559 SiS_SetChrontelGPIO(&ivideo->SiS_Pr, 0x9c); /* Set general purpose IO for Chrontel communication */
2560 SiS_DDC2Delay(&ivideo->SiS_Pr, 1000);
2561 temp1 = SiS_GetCH700x(&ivideo->SiS_Pr, 0x25);
2562 /* See Chrontel TB31 for explanation */
2563 temp2 = SiS_GetCH700x(&ivideo->SiS_Pr, 0x0e);
2564 if(((temp2 & 0x07) == 0x01) || (temp2 & 0x04)) {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07002565 SiS_SetCH700x(&ivideo->SiS_Pr, 0x0e, 0x0b);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002566 SiS_DDC2Delay(&ivideo->SiS_Pr, 300);
2567 }
2568 temp2 = SiS_GetCH700x(&ivideo->SiS_Pr, 0x25);
2569 if(temp2 != temp1) temp1 = temp2;
2570
2571 if((temp1 >= 0x22) && (temp1 <= 0x50)) {
2572 /* Read power status */
2573 temp1 = SiS_GetCH700x(&ivideo->SiS_Pr, 0x0e);
2574 if((temp1 & 0x03) != 0x03) {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07002575 /* Power all outputs */
2576 SiS_SetCH700x(&ivideo->SiS_Pr, 0x0e,0x0b);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002577 SiS_DDC2Delay(&ivideo->SiS_Pr, 300);
2578 }
2579 /* Sense connected TV devices */
2580 for(i = 0; i < 3; i++) {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07002581 SiS_SetCH700x(&ivideo->SiS_Pr, 0x10, 0x01);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002582 SiS_DDC2Delay(&ivideo->SiS_Pr, 0x96);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07002583 SiS_SetCH700x(&ivideo->SiS_Pr, 0x10, 0x00);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002584 SiS_DDC2Delay(&ivideo->SiS_Pr, 0x96);
2585 temp1 = SiS_GetCH700x(&ivideo->SiS_Pr, 0x10);
2586 if(!(temp1 & 0x08)) test[i] = 0x02;
2587 else if(!(temp1 & 0x02)) test[i] = 0x01;
2588 else test[i] = 0;
2589 SiS_DDC2Delay(&ivideo->SiS_Pr, 0x96);
2590 }
2591
2592 if(test[0] == test[1]) temp1 = test[0];
2593 else if(test[0] == test[2]) temp1 = test[0];
2594 else if(test[1] == test[2]) temp1 = test[1];
2595 else {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07002596 printk(KERN_INFO
Linus Torvalds1da177e2005-04-16 15:20:36 -07002597 "sisfb: TV detection unreliable - test results varied\n");
2598 temp1 = test[2];
2599 }
2600 if(temp1 == 0x02) {
2601 printk(KERN_INFO "%s SVIDEO output\n", stdstr);
2602 ivideo->vbflags |= TV_SVIDEO;
2603 orSISIDXREG(SISCR, 0x32, 0x02);
2604 andSISIDXREG(SISCR, 0x32, ~0x05);
2605 } else if (temp1 == 0x01) {
2606 printk(KERN_INFO "%s CVBS output\n", stdstr);
2607 ivideo->vbflags |= TV_AVIDEO;
2608 orSISIDXREG(SISCR, 0x32, 0x01);
2609 andSISIDXREG(SISCR, 0x32, ~0x06);
2610 } else {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07002611 SiS_SetCH70xxANDOR(&ivideo->SiS_Pr, 0x0e, 0x01, 0xF8);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002612 andSISIDXREG(SISCR, 0x32, ~0x07);
2613 }
2614 } else if(temp1 == 0) {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07002615 SiS_SetCH70xxANDOR(&ivideo->SiS_Pr, 0x0e, 0x01, 0xF8);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002616 andSISIDXREG(SISCR, 0x32, ~0x07);
2617 }
2618 /* Set general purpose IO for Chrontel communication */
2619 SiS_SetChrontelGPIO(&ivideo->SiS_Pr, 0x00);
2620#endif
2621
2622 } else {
2623
2624#ifdef CONFIG_FB_SIS_315
2625 ivideo->SiS_Pr.SiS_IF_DEF_CH70xx = 2; /* Chrontel 7019 */
Thomas Winischhofer544393f2005-09-09 13:04:45 -07002626 temp1 = SiS_GetCH701x(&ivideo->SiS_Pr, 0x49);
2627 SiS_SetCH701x(&ivideo->SiS_Pr, 0x49, 0x20);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002628 SiS_DDC2Delay(&ivideo->SiS_Pr, 0x96);
2629 temp2 = SiS_GetCH701x(&ivideo->SiS_Pr, 0x20);
2630 temp2 |= 0x01;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07002631 SiS_SetCH701x(&ivideo->SiS_Pr, 0x20, temp2);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002632 SiS_DDC2Delay(&ivideo->SiS_Pr, 0x96);
2633 temp2 ^= 0x01;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07002634 SiS_SetCH701x(&ivideo->SiS_Pr, 0x20, temp2);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002635 SiS_DDC2Delay(&ivideo->SiS_Pr, 0x96);
2636 temp2 = SiS_GetCH701x(&ivideo->SiS_Pr, 0x20);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07002637 SiS_SetCH701x(&ivideo->SiS_Pr, 0x49, temp1);
2638 temp1 = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002639 if(temp2 & 0x02) temp1 |= 0x01;
2640 if(temp2 & 0x10) temp1 |= 0x01;
2641 if(temp2 & 0x04) temp1 |= 0x02;
2642 if( (temp1 & 0x01) && (temp1 & 0x02) ) temp1 = 0x04;
2643 switch(temp1) {
2644 case 0x01:
2645 printk(KERN_INFO "%s CVBS output\n", stdstr);
2646 ivideo->vbflags |= TV_AVIDEO;
2647 orSISIDXREG(SISCR, 0x32, 0x01);
2648 andSISIDXREG(SISCR, 0x32, ~0x06);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07002649 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002650 case 0x02:
2651 printk(KERN_INFO "%s SVIDEO output\n", stdstr);
2652 ivideo->vbflags |= TV_SVIDEO;
2653 orSISIDXREG(SISCR, 0x32, 0x02);
2654 andSISIDXREG(SISCR, 0x32, ~0x05);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07002655 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002656 case 0x04:
2657 printk(KERN_INFO "%s SCART output\n", stdstr);
2658 orSISIDXREG(SISCR, 0x32, 0x04);
2659 andSISIDXREG(SISCR, 0x32, ~0x03);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07002660 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002661 default:
2662 andSISIDXREG(SISCR, 0x32, ~0x07);
2663 }
2664#endif
2665 }
2666}
2667
Thomas Winischhofer544393f2005-09-09 13:04:45 -07002668static void __devinit
2669sisfb_get_VB_type(struct sis_video_info *ivideo)
2670{
2671 char stdstr[] = "sisfb: Detected";
2672 char bridgestr[] = "video bridge";
2673 u8 vb_chipid;
2674 u8 reg;
2675
2676 /* No CRT2 on XGI Z7 */
2677 if(ivideo->chip == XGI_20)
2678 return;
2679
2680 inSISIDXREG(SISPART4, 0x00, vb_chipid);
2681 switch(vb_chipid) {
2682 case 0x01:
2683 inSISIDXREG(SISPART4, 0x01, reg);
2684 if(reg < 0xb0) {
2685 ivideo->vbflags |= VB_301; /* Deprecated */
2686 ivideo->vbflags2 |= VB2_301;
2687 printk(KERN_INFO "%s SiS301 %s\n", stdstr, bridgestr);
2688 } else if(reg < 0xc0) {
2689 ivideo->vbflags |= VB_301B; /* Deprecated */
2690 ivideo->vbflags2 |= VB2_301B;
2691 inSISIDXREG(SISPART4,0x23,reg);
2692 if(!(reg & 0x02)) {
2693 ivideo->vbflags |= VB_30xBDH; /* Deprecated */
2694 ivideo->vbflags2 |= VB2_30xBDH;
2695 printk(KERN_INFO "%s SiS301B-DH %s\n", stdstr, bridgestr);
2696 } else {
2697 printk(KERN_INFO "%s SiS301B %s\n", stdstr, bridgestr);
2698 }
2699 } else if(reg < 0xd0) {
2700 ivideo->vbflags |= VB_301C; /* Deprecated */
2701 ivideo->vbflags2 |= VB2_301C;
2702 printk(KERN_INFO "%s SiS301C %s\n", stdstr, bridgestr);
2703 } else if(reg < 0xe0) {
2704 ivideo->vbflags |= VB_301LV; /* Deprecated */
2705 ivideo->vbflags2 |= VB2_301LV;
2706 printk(KERN_INFO "%s SiS301LV %s\n", stdstr, bridgestr);
2707 } else if(reg <= 0xe1) {
2708 inSISIDXREG(SISPART4,0x39,reg);
2709 if(reg == 0xff) {
2710 ivideo->vbflags |= VB_302LV; /* Deprecated */
2711 ivideo->vbflags2 |= VB2_302LV;
2712 printk(KERN_INFO "%s SiS302LV %s\n", stdstr, bridgestr);
2713 } else {
2714 ivideo->vbflags |= VB_301C; /* Deprecated */
2715 ivideo->vbflags2 |= VB2_301C;
2716 printk(KERN_INFO "%s SiS301C(P4) %s\n", stdstr, bridgestr);
2717#if 0
2718 ivideo->vbflags |= VB_302ELV; /* Deprecated */
2719 ivideo->vbflags2 |= VB2_302ELV;
2720 printk(KERN_INFO "%s SiS302ELV %s\n", stdstr, bridgestr);
2721#endif
2722 }
2723 }
2724 break;
2725 case 0x02:
2726 ivideo->vbflags |= VB_302B; /* Deprecated */
2727 ivideo->vbflags2 |= VB2_302B;
2728 printk(KERN_INFO "%s SiS302B %s\n", stdstr, bridgestr);
2729 break;
2730 }
2731
2732 if((!(ivideo->vbflags2 & VB2_VIDEOBRIDGE)) && (ivideo->chip != SIS_300)) {
2733 inSISIDXREG(SISCR, 0x37, reg);
2734 reg &= SIS_EXTERNAL_CHIP_MASK;
2735 reg >>= 1;
2736 if(ivideo->sisvga_engine == SIS_300_VGA) {
2737#ifdef CONFIG_FB_SIS_300
2738 switch(reg) {
2739 case SIS_EXTERNAL_CHIP_LVDS:
2740 ivideo->vbflags |= VB_LVDS; /* Deprecated */
2741 ivideo->vbflags2 |= VB2_LVDS;
2742 break;
2743 case SIS_EXTERNAL_CHIP_TRUMPION:
2744 ivideo->vbflags |= (VB_LVDS | VB_TRUMPION); /* Deprecated */
2745 ivideo->vbflags2 |= (VB2_LVDS | VB2_TRUMPION);
2746 break;
2747 case SIS_EXTERNAL_CHIP_CHRONTEL:
2748 ivideo->vbflags |= VB_CHRONTEL; /* Deprecated */
2749 ivideo->vbflags2 |= VB2_CHRONTEL;
2750 break;
2751 case SIS_EXTERNAL_CHIP_LVDS_CHRONTEL:
2752 ivideo->vbflags |= (VB_LVDS | VB_CHRONTEL); /* Deprecated */
2753 ivideo->vbflags2 |= (VB2_LVDS | VB2_CHRONTEL);
2754 break;
2755 }
2756 if(ivideo->vbflags2 & VB2_CHRONTEL) ivideo->chronteltype = 1;
2757#endif
2758 } else if(ivideo->chip < SIS_661) {
2759#ifdef CONFIG_FB_SIS_315
2760 switch (reg) {
2761 case SIS310_EXTERNAL_CHIP_LVDS:
2762 ivideo->vbflags |= VB_LVDS; /* Deprecated */
2763 ivideo->vbflags2 |= VB2_LVDS;
2764 break;
2765 case SIS310_EXTERNAL_CHIP_LVDS_CHRONTEL:
2766 ivideo->vbflags |= (VB_LVDS | VB_CHRONTEL); /* Deprecated */
2767 ivideo->vbflags2 |= (VB2_LVDS | VB2_CHRONTEL);
2768 break;
2769 }
2770 if(ivideo->vbflags2 & VB2_CHRONTEL) ivideo->chronteltype = 2;
2771#endif
2772 } else if(ivideo->chip >= SIS_661) {
2773#ifdef CONFIG_FB_SIS_315
2774 inSISIDXREG(SISCR, 0x38, reg);
2775 reg >>= 5;
2776 switch(reg) {
2777 case 0x02:
2778 ivideo->vbflags |= VB_LVDS; /* Deprecated */
2779 ivideo->vbflags2 |= VB2_LVDS;
2780 break;
2781 case 0x03:
2782 ivideo->vbflags |= (VB_LVDS | VB_CHRONTEL); /* Deprecated */
2783 ivideo->vbflags2 |= (VB2_LVDS | VB2_CHRONTEL);
2784 break;
2785 case 0x04:
2786 ivideo->vbflags |= (VB_LVDS | VB_CONEXANT); /* Deprecated */
2787 ivideo->vbflags2 |= (VB2_LVDS | VB2_CONEXANT);
2788 break;
2789 }
2790 if(ivideo->vbflags2 & VB2_CHRONTEL) ivideo->chronteltype = 2;
2791#endif
2792 }
2793 if(ivideo->vbflags2 & VB2_LVDS) {
2794 printk(KERN_INFO "%s LVDS transmitter\n", stdstr);
2795 }
2796 if((ivideo->sisvga_engine == SIS_300_VGA) && (ivideo->vbflags2 & VB2_TRUMPION)) {
2797 printk(KERN_INFO "%s Trumpion Zurac LCD scaler\n", stdstr);
2798 }
2799 if(ivideo->vbflags2 & VB2_CHRONTEL) {
2800 printk(KERN_INFO "%s Chrontel TV encoder\n", stdstr);
2801 }
2802 if((ivideo->chip >= SIS_661) && (ivideo->vbflags2 & VB2_CONEXANT)) {
2803 printk(KERN_INFO "%s Conexant external device\n", stdstr);
2804 }
2805 }
2806
2807 if(ivideo->vbflags2 & VB2_SISBRIDGE) {
2808 SiS_SenseLCD(ivideo);
2809 SiS_Sense30x(ivideo);
2810 } else if(ivideo->vbflags2 & VB2_CHRONTEL) {
2811 SiS_SenseCh(ivideo);
2812 }
2813}
2814
2815/* ---------- Engine initialization routines ------------ */
2816
2817static void
2818sisfb_engine_init(struct sis_video_info *ivideo)
2819{
2820
2821 /* Initialize command queue (we use MMIO only) */
2822
2823 /* BEFORE THIS IS CALLED, THE ENGINES *MUST* BE SYNC'ED */
2824
2825 ivideo->caps &= ~(TURBO_QUEUE_CAP |
2826 MMIO_CMD_QUEUE_CAP |
2827 VM_CMD_QUEUE_CAP |
2828 AGP_CMD_QUEUE_CAP);
2829
2830#ifdef CONFIG_FB_SIS_300
2831 if(ivideo->sisvga_engine == SIS_300_VGA) {
2832 u32 tqueue_pos;
2833 u8 tq_state;
2834
2835 tqueue_pos = (ivideo->video_size - ivideo->cmdQueueSize) / (64 * 1024);
2836
2837 inSISIDXREG(SISSR, IND_SIS_TURBOQUEUE_SET, tq_state);
2838 tq_state |= 0xf0;
2839 tq_state &= 0xfc;
2840 tq_state |= (u8)(tqueue_pos >> 8);
2841 outSISIDXREG(SISSR, IND_SIS_TURBOQUEUE_SET, tq_state);
2842
2843 outSISIDXREG(SISSR, IND_SIS_TURBOQUEUE_ADR, (u8)(tqueue_pos & 0xff));
2844
2845 ivideo->caps |= TURBO_QUEUE_CAP;
2846 }
2847#endif
2848
2849#ifdef CONFIG_FB_SIS_315
2850 if(ivideo->sisvga_engine == SIS_315_VGA) {
2851 u32 tempq = 0, templ;
2852 u8 temp;
2853
2854 if(ivideo->chip == XGI_20) {
2855 switch(ivideo->cmdQueueSize) {
2856 case (64 * 1024):
2857 temp = SIS_CMD_QUEUE_SIZE_Z7_64k;
2858 break;
2859 case (128 * 1024):
2860 default:
2861 temp = SIS_CMD_QUEUE_SIZE_Z7_128k;
2862 }
2863 } else {
2864 switch(ivideo->cmdQueueSize) {
2865 case (4 * 1024 * 1024):
2866 temp = SIS_CMD_QUEUE_SIZE_4M;
2867 break;
2868 case (2 * 1024 * 1024):
2869 temp = SIS_CMD_QUEUE_SIZE_2M;
2870 break;
2871 case (1 * 1024 * 1024):
2872 temp = SIS_CMD_QUEUE_SIZE_1M;
2873 break;
2874 default:
2875 case (512 * 1024):
2876 temp = SIS_CMD_QUEUE_SIZE_512k;
2877 }
2878 }
2879
2880 outSISIDXREG(SISSR, IND_SIS_CMDQUEUE_THRESHOLD, COMMAND_QUEUE_THRESHOLD);
2881 outSISIDXREG(SISSR, IND_SIS_CMDQUEUE_SET, SIS_CMD_QUEUE_RESET);
2882
2883 if((ivideo->chip >= XGI_40) && ivideo->modechanged) {
2884 /* Must disable dual pipe on XGI_40. Can't do
2885 * this in MMIO mode, because it requires
2886 * setting/clearing a bit in the MMIO fire trigger
2887 * register.
2888 */
2889 if(!((templ = MMIO_IN32(ivideo->mmio_vbase, 0x8240)) & (1 << 10))) {
2890
2891 MMIO_OUT32(ivideo->mmio_vbase, Q_WRITE_PTR, 0);
2892
2893 outSISIDXREG(SISSR, IND_SIS_CMDQUEUE_SET, (temp | SIS_VRAM_CMDQUEUE_ENABLE));
2894
2895 tempq = MMIO_IN32(ivideo->mmio_vbase, Q_READ_PTR);
2896 MMIO_OUT32(ivideo->mmio_vbase, Q_WRITE_PTR, tempq);
2897
2898 tempq = (u32)(ivideo->video_size - ivideo->cmdQueueSize);
2899 MMIO_OUT32(ivideo->mmio_vbase, Q_BASE_ADDR, tempq);
2900
2901 writel(0x16800000 + 0x8240, ivideo->video_vbase + tempq);
2902 writel(templ | (1 << 10), ivideo->video_vbase + tempq + 4);
2903 writel(0x168F0000, ivideo->video_vbase + tempq + 8);
2904 writel(0x168F0000, ivideo->video_vbase + tempq + 12);
2905
2906 MMIO_OUT32(ivideo->mmio_vbase, Q_WRITE_PTR, (tempq + 16));
2907
2908 sisfb_syncaccel(ivideo);
2909
2910 outSISIDXREG(SISSR, IND_SIS_CMDQUEUE_SET, SIS_CMD_QUEUE_RESET);
2911
2912 }
2913 }
2914
2915 tempq = MMIO_IN32(ivideo->mmio_vbase, MMIO_QUEUE_READPORT);
2916 MMIO_OUT32(ivideo->mmio_vbase, MMIO_QUEUE_WRITEPORT, tempq);
2917
2918 temp |= (SIS_MMIO_CMD_ENABLE | SIS_CMD_AUTO_CORR);
2919 outSISIDXREG(SISSR, IND_SIS_CMDQUEUE_SET, temp);
2920
2921 tempq = (u32)(ivideo->video_size - ivideo->cmdQueueSize);
2922 MMIO_OUT32(ivideo->mmio_vbase, MMIO_QUEUE_PHYBASE, tempq);
2923
2924 ivideo->caps |= MMIO_CMD_QUEUE_CAP;
2925 }
2926#endif
2927
2928 ivideo->engineok = 1;
2929}
2930
2931static void __devinit
2932sisfb_detect_lcd_type(struct sis_video_info *ivideo)
2933{
2934 u8 reg;
2935 int i;
2936
2937 inSISIDXREG(SISCR, 0x36, reg);
2938 reg &= 0x0f;
2939 if(ivideo->sisvga_engine == SIS_300_VGA) {
2940 ivideo->CRT2LCDType = sis300paneltype[reg];
2941 } else if(ivideo->chip >= SIS_661) {
2942 ivideo->CRT2LCDType = sis661paneltype[reg];
2943 } else {
2944 ivideo->CRT2LCDType = sis310paneltype[reg];
2945 if((ivideo->chip == SIS_550) && (sisfb_fstn)) {
2946 if((ivideo->CRT2LCDType != LCD_320x240_2) &&
2947 (ivideo->CRT2LCDType != LCD_320x240_3)) {
2948 ivideo->CRT2LCDType = LCD_320x240;
2949 }
2950 }
2951 }
2952
2953 if(ivideo->CRT2LCDType == LCD_UNKNOWN) {
2954 /* For broken BIOSes: Assume 1024x768, RGB18 */
2955 ivideo->CRT2LCDType = LCD_1024x768;
2956 setSISIDXREG(SISCR,0x36,0xf0,0x02);
2957 setSISIDXREG(SISCR,0x37,0xee,0x01);
2958 printk(KERN_DEBUG "sisfb: Invalid panel ID (%02x), assuming 1024x768, RGB18\n", reg);
2959 }
2960
2961 for(i = 0; i < SIS_LCD_NUMBER; i++) {
2962 if(ivideo->CRT2LCDType == sis_lcd_data[i].lcdtype) {
2963 ivideo->lcdxres = sis_lcd_data[i].xres;
2964 ivideo->lcdyres = sis_lcd_data[i].yres;
2965 ivideo->lcddefmodeidx = sis_lcd_data[i].default_mode_idx;
2966 break;
2967 }
2968 }
2969
2970#ifdef CONFIG_FB_SIS_300
2971 if(ivideo->SiS_Pr.SiS_CustomT == CUT_BARCO1366) {
2972 ivideo->lcdxres = 1360; ivideo->lcdyres = 1024;
2973 ivideo->lcddefmodeidx = DEFAULT_MODE_1360;
2974 } else if(ivideo->SiS_Pr.SiS_CustomT == CUT_PANEL848) {
2975 ivideo->lcdxres = 848; ivideo->lcdyres = 480;
2976 ivideo->lcddefmodeidx = DEFAULT_MODE_848;
2977 } else if(ivideo->SiS_Pr.SiS_CustomT == CUT_PANEL856) {
2978 ivideo->lcdxres = 856; ivideo->lcdyres = 480;
2979 ivideo->lcddefmodeidx = DEFAULT_MODE_856;
2980 }
2981#endif
2982
2983 printk(KERN_DEBUG "sisfb: Detected %dx%d flat panel\n",
2984 ivideo->lcdxres, ivideo->lcdyres);
2985}
2986
2987static void __devinit
2988sisfb_save_pdc_emi(struct sis_video_info *ivideo)
2989{
2990#ifdef CONFIG_FB_SIS_300
2991 /* Save the current PanelDelayCompensation if the LCD is currently used */
2992 if(ivideo->sisvga_engine == SIS_300_VGA) {
2993 if(ivideo->vbflags2 & (VB2_LVDS | VB2_30xBDH)) {
2994 int tmp;
2995 inSISIDXREG(SISCR,0x30,tmp);
2996 if(tmp & 0x20) {
2997 /* Currently on LCD? If yes, read current pdc */
2998 inSISIDXREG(SISPART1,0x13,ivideo->detectedpdc);
2999 ivideo->detectedpdc &= 0x3c;
3000 if(ivideo->SiS_Pr.PDC == -1) {
3001 /* Let option override detection */
3002 ivideo->SiS_Pr.PDC = ivideo->detectedpdc;
3003 }
3004 printk(KERN_INFO "sisfb: Detected LCD PDC 0x%02x\n",
3005 ivideo->detectedpdc);
3006 }
3007 if((ivideo->SiS_Pr.PDC != -1) &&
3008 (ivideo->SiS_Pr.PDC != ivideo->detectedpdc)) {
3009 printk(KERN_INFO "sisfb: Using LCD PDC 0x%02x\n",
3010 ivideo->SiS_Pr.PDC);
3011 }
3012 }
3013 }
3014#endif
3015
3016#ifdef CONFIG_FB_SIS_315
3017 if(ivideo->sisvga_engine == SIS_315_VGA) {
3018
3019 /* Try to find about LCDA */
3020 if(ivideo->vbflags2 & VB2_SISLCDABRIDGE) {
3021 int tmp;
3022 inSISIDXREG(SISPART1,0x13,tmp);
3023 if(tmp & 0x04) {
Richard Knutssonc30660ea2007-02-12 00:55:06 -08003024 ivideo->SiS_Pr.SiS_UseLCDA = true;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003025 ivideo->detectedlcda = 0x03;
3026 }
3027 }
3028
3029 /* Save PDC */
3030 if(ivideo->vbflags2 & VB2_SISLVDSBRIDGE) {
3031 int tmp;
3032 inSISIDXREG(SISCR,0x30,tmp);
3033 if((tmp & 0x20) || (ivideo->detectedlcda != 0xff)) {
3034 /* Currently on LCD? If yes, read current pdc */
3035 u8 pdc;
3036 inSISIDXREG(SISPART1,0x2D,pdc);
3037 ivideo->detectedpdc = (pdc & 0x0f) << 1;
3038 ivideo->detectedpdca = (pdc & 0xf0) >> 3;
3039 inSISIDXREG(SISPART1,0x35,pdc);
3040 ivideo->detectedpdc |= ((pdc >> 7) & 0x01);
3041 inSISIDXREG(SISPART1,0x20,pdc);
3042 ivideo->detectedpdca |= ((pdc >> 6) & 0x01);
3043 if(ivideo->newrom) {
3044 /* New ROM invalidates other PDC resp. */
3045 if(ivideo->detectedlcda != 0xff) {
3046 ivideo->detectedpdc = 0xff;
3047 } else {
3048 ivideo->detectedpdca = 0xff;
3049 }
3050 }
3051 if(ivideo->SiS_Pr.PDC == -1) {
3052 if(ivideo->detectedpdc != 0xff) {
3053 ivideo->SiS_Pr.PDC = ivideo->detectedpdc;
3054 }
3055 }
3056 if(ivideo->SiS_Pr.PDCA == -1) {
3057 if(ivideo->detectedpdca != 0xff) {
3058 ivideo->SiS_Pr.PDCA = ivideo->detectedpdca;
3059 }
3060 }
3061 if(ivideo->detectedpdc != 0xff) {
3062 printk(KERN_INFO
3063 "sisfb: Detected LCD PDC 0x%02x (for LCD=CRT2)\n",
3064 ivideo->detectedpdc);
3065 }
3066 if(ivideo->detectedpdca != 0xff) {
3067 printk(KERN_INFO
3068 "sisfb: Detected LCD PDC1 0x%02x (for LCD=CRT1)\n",
3069 ivideo->detectedpdca);
3070 }
3071 }
3072
3073 /* Save EMI */
3074 if(ivideo->vbflags2 & VB2_SISEMIBRIDGE) {
3075 inSISIDXREG(SISPART4,0x30,ivideo->SiS_Pr.EMI_30);
3076 inSISIDXREG(SISPART4,0x31,ivideo->SiS_Pr.EMI_31);
3077 inSISIDXREG(SISPART4,0x32,ivideo->SiS_Pr.EMI_32);
3078 inSISIDXREG(SISPART4,0x33,ivideo->SiS_Pr.EMI_33);
Richard Knutssonc30660ea2007-02-12 00:55:06 -08003079 ivideo->SiS_Pr.HaveEMI = true;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003080 if((tmp & 0x20) || (ivideo->detectedlcda != 0xff)) {
Richard Knutssonc30660ea2007-02-12 00:55:06 -08003081 ivideo->SiS_Pr.HaveEMILCD = true;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003082 }
3083 }
3084 }
3085
3086 /* Let user override detected PDCs (all bridges) */
3087 if(ivideo->vbflags2 & VB2_30xBLV) {
3088 if((ivideo->SiS_Pr.PDC != -1) &&
3089 (ivideo->SiS_Pr.PDC != ivideo->detectedpdc)) {
3090 printk(KERN_INFO "sisfb: Using LCD PDC 0x%02x (for LCD=CRT2)\n",
3091 ivideo->SiS_Pr.PDC);
3092 }
3093 if((ivideo->SiS_Pr.PDCA != -1) &&
3094 (ivideo->SiS_Pr.PDCA != ivideo->detectedpdca)) {
3095 printk(KERN_INFO "sisfb: Using LCD PDC1 0x%02x (for LCD=CRT1)\n",
3096 ivideo->SiS_Pr.PDCA);
3097 }
3098 }
3099
3100 }
3101#endif
3102}
3103
3104/* -------------------- Memory manager routines ---------------------- */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003105
3106static u32 __devinit
3107sisfb_getheapstart(struct sis_video_info *ivideo)
3108{
3109 u32 ret = ivideo->sisfb_parm_mem * 1024;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003110 u32 maxoffs = ivideo->video_size - ivideo->hwcursor_size - ivideo->cmdQueueSize;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003111 u32 def;
3112
3113 /* Calculate heap start = end of memory for console
3114 *
3115 * CCCCCCCCDDDDDDDDDDDDDDDDDDDDDDDDDDDDHHHHQQQQQQQQQQ
3116 * C = console, D = heap, H = HWCursor, Q = cmd-queue
3117 *
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003118 * On 76x in UMA+LFB mode, the layout is as follows:
3119 * DDDDDDDDDDDCCCCCCCCCCCCCCCCCCCCCCCCHHHHQQQQQQQQQQQ
3120 * where the heap is the entire UMA area, eventually
3121 * into the LFB area if the given mem parameter is
3122 * higher than the size of the UMA memory.
3123 *
Linus Torvalds1da177e2005-04-16 15:20:36 -07003124 * Basically given by "mem" parameter
3125 *
3126 * maximum = videosize - cmd_queue - hwcursor
3127 * (results in a heap of size 0)
3128 * default = SiS 300: depends on videosize
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003129 * SiS 315/330/340/XGI: 32k below max
Linus Torvalds1da177e2005-04-16 15:20:36 -07003130 */
3131
3132 if(ivideo->sisvga_engine == SIS_300_VGA) {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003133 if(ivideo->video_size > 0x1000000) {
3134 def = 0xc00000;
3135 } else if(ivideo->video_size > 0x800000) {
3136 def = 0x800000;
3137 } else {
3138 def = 0x400000;
3139 }
3140 } else if(ivideo->UMAsize && ivideo->LFBsize) {
3141 ret = def = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003142 } else {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003143 def = maxoffs - 0x8000;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003144 }
3145
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003146 /* Use default for secondary card for now (FIXME) */
3147 if((!ret) || (ret > maxoffs) || (ivideo->cardnumber != 0))
3148 ret = def;
3149
3150 return ret;
3151}
3152
3153static u32 __devinit
3154sisfb_getheapsize(struct sis_video_info *ivideo)
3155{
3156 u32 max = ivideo->video_size - ivideo->hwcursor_size - ivideo->cmdQueueSize;
3157 u32 ret = 0;
3158
3159 if(ivideo->UMAsize && ivideo->LFBsize) {
3160 if( (!ivideo->sisfb_parm_mem) ||
3161 ((ivideo->sisfb_parm_mem * 1024) > max) ||
3162 ((max - (ivideo->sisfb_parm_mem * 1024)) < ivideo->UMAsize) ) {
3163 ret = ivideo->UMAsize;
3164 max -= ivideo->UMAsize;
3165 } else {
3166 ret = max - (ivideo->sisfb_parm_mem * 1024);
3167 max = ivideo->sisfb_parm_mem * 1024;
3168 }
3169 ivideo->video_offset = ret;
3170 ivideo->sisfb_mem = max;
3171 } else {
3172 ret = max - ivideo->heapstart;
3173 ivideo->sisfb_mem = ivideo->heapstart;
3174 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003175
3176 return ret;
3177}
3178
3179static int __devinit
3180sisfb_heap_init(struct sis_video_info *ivideo)
3181{
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003182 struct SIS_OH *poh;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003183
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003184 ivideo->video_offset = 0;
3185 if(ivideo->sisfb_parm_mem) {
3186 if( (ivideo->sisfb_parm_mem < (2 * 1024 * 1024)) ||
3187 (ivideo->sisfb_parm_mem > ivideo->video_size) ) {
3188 ivideo->sisfb_parm_mem = 0;
3189 }
3190 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003191
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003192 ivideo->heapstart = sisfb_getheapstart(ivideo);
3193 ivideo->sisfb_heap_size = sisfb_getheapsize(ivideo);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003194
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003195 ivideo->sisfb_heap_start = ivideo->video_vbase + ivideo->heapstart;
3196 ivideo->sisfb_heap_end = ivideo->sisfb_heap_start + ivideo->sisfb_heap_size;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003197
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003198 printk(KERN_INFO "sisfb: Memory heap starting at %dK, size %dK\n",
3199 (int)(ivideo->heapstart / 1024), (int)(ivideo->sisfb_heap_size / 1024));
Linus Torvalds1da177e2005-04-16 15:20:36 -07003200
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003201 ivideo->sisfb_heap.vinfo = ivideo;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003202
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003203 ivideo->sisfb_heap.poha_chain = NULL;
3204 ivideo->sisfb_heap.poh_freelist = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003205
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003206 poh = sisfb_poh_new_node(&ivideo->sisfb_heap);
3207 if(poh == NULL)
3208 return 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003209
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003210 poh->poh_next = &ivideo->sisfb_heap.oh_free;
3211 poh->poh_prev = &ivideo->sisfb_heap.oh_free;
3212 poh->size = ivideo->sisfb_heap_size;
3213 poh->offset = ivideo->heapstart;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003214
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003215 ivideo->sisfb_heap.oh_free.poh_next = poh;
3216 ivideo->sisfb_heap.oh_free.poh_prev = poh;
3217 ivideo->sisfb_heap.oh_free.size = 0;
3218 ivideo->sisfb_heap.max_freesize = poh->size;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003219
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003220 ivideo->sisfb_heap.oh_used.poh_next = &ivideo->sisfb_heap.oh_used;
3221 ivideo->sisfb_heap.oh_used.poh_prev = &ivideo->sisfb_heap.oh_used;
3222 ivideo->sisfb_heap.oh_used.size = SENTINEL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003223
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003224 if(ivideo->cardnumber == 0) {
3225 /* For the first card, make this heap the "global" one
3226 * for old DRM (which could handle only one card)
3227 */
3228 sisfb_heap = &ivideo->sisfb_heap;
3229 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003230
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003231 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003232}
3233
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003234static struct SIS_OH *
3235sisfb_poh_new_node(struct SIS_HEAP *memheap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003236{
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003237 struct SIS_OHALLOC *poha;
3238 struct SIS_OH *poh;
3239 unsigned long cOhs;
3240 int i;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003241
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003242 if(memheap->poh_freelist == NULL) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003243 poha = kmalloc(SIS_OH_ALLOC_SIZE, GFP_KERNEL);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003244 if(!poha)
3245 return NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003246
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003247 poha->poha_next = memheap->poha_chain;
3248 memheap->poha_chain = poha;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003249
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003250 cOhs = (SIS_OH_ALLOC_SIZE - sizeof(struct SIS_OHALLOC)) / sizeof(struct SIS_OH) + 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003251
3252 poh = &poha->aoh[0];
3253 for(i = cOhs - 1; i != 0; i--) {
3254 poh->poh_next = poh + 1;
3255 poh = poh + 1;
3256 }
3257
3258 poh->poh_next = NULL;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003259 memheap->poh_freelist = &poha->aoh[0];
Linus Torvalds1da177e2005-04-16 15:20:36 -07003260 }
3261
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003262 poh = memheap->poh_freelist;
3263 memheap->poh_freelist = poh->poh_next;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003264
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003265 return poh;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003266}
3267
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003268static struct SIS_OH *
3269sisfb_poh_allocate(struct SIS_HEAP *memheap, u32 size)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003270{
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003271 struct SIS_OH *pohThis;
3272 struct SIS_OH *pohRoot;
3273 int bAllocated = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003274
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003275 if(size > memheap->max_freesize) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003276 DPRINTK("sisfb: Can't allocate %dk video memory\n",
3277 (unsigned int) size / 1024);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003278 return NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003279 }
3280
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003281 pohThis = memheap->oh_free.poh_next;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003282
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003283 while(pohThis != &memheap->oh_free) {
3284 if(size <= pohThis->size) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003285 bAllocated = 1;
3286 break;
3287 }
3288 pohThis = pohThis->poh_next;
3289 }
3290
3291 if(!bAllocated) {
3292 DPRINTK("sisfb: Can't allocate %dk video memory\n",
3293 (unsigned int) size / 1024);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003294 return NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003295 }
3296
3297 if(size == pohThis->size) {
3298 pohRoot = pohThis;
3299 sisfb_delete_node(pohThis);
3300 } else {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003301 pohRoot = sisfb_poh_new_node(memheap);
3302 if(pohRoot == NULL)
3303 return NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003304
3305 pohRoot->offset = pohThis->offset;
3306 pohRoot->size = size;
3307
3308 pohThis->offset += size;
3309 pohThis->size -= size;
3310 }
3311
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003312 memheap->max_freesize -= size;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003313
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003314 pohThis = &memheap->oh_used;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003315 sisfb_insert_node(pohThis, pohRoot);
3316
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003317 return pohRoot;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003318}
3319
3320static void
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003321sisfb_delete_node(struct SIS_OH *poh)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003322{
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003323 poh->poh_prev->poh_next = poh->poh_next;
3324 poh->poh_next->poh_prev = poh->poh_prev;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003325}
3326
3327static void
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003328sisfb_insert_node(struct SIS_OH *pohList, struct SIS_OH *poh)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003329{
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003330 struct SIS_OH *pohTemp = pohList->poh_next;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003331
3332 pohList->poh_next = poh;
3333 pohTemp->poh_prev = poh;
3334
3335 poh->poh_prev = pohList;
3336 poh->poh_next = pohTemp;
3337}
3338
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003339static struct SIS_OH *
3340sisfb_poh_free(struct SIS_HEAP *memheap, u32 base)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003341{
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003342 struct SIS_OH *pohThis;
3343 struct SIS_OH *poh_freed;
3344 struct SIS_OH *poh_prev;
3345 struct SIS_OH *poh_next;
3346 u32 ulUpper;
3347 u32 ulLower;
3348 int foundNode = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003349
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003350 poh_freed = memheap->oh_used.poh_next;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003351
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003352 while(poh_freed != &memheap->oh_used) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003353 if(poh_freed->offset == base) {
3354 foundNode = 1;
3355 break;
3356 }
3357
3358 poh_freed = poh_freed->poh_next;
3359 }
3360
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003361 if(!foundNode)
3362 return NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003363
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003364 memheap->max_freesize += poh_freed->size;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003365
3366 poh_prev = poh_next = NULL;
3367 ulUpper = poh_freed->offset + poh_freed->size;
3368 ulLower = poh_freed->offset;
3369
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003370 pohThis = memheap->oh_free.poh_next;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003371
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003372 while(pohThis != &memheap->oh_free) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003373 if(pohThis->offset == ulUpper) {
3374 poh_next = pohThis;
3375 } else if((pohThis->offset + pohThis->size) == ulLower) {
3376 poh_prev = pohThis;
3377 }
3378 pohThis = pohThis->poh_next;
3379 }
3380
3381 sisfb_delete_node(poh_freed);
3382
3383 if(poh_prev && poh_next) {
3384 poh_prev->size += (poh_freed->size + poh_next->size);
3385 sisfb_delete_node(poh_next);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003386 sisfb_free_node(memheap, poh_freed);
3387 sisfb_free_node(memheap, poh_next);
3388 return poh_prev;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003389 }
3390
3391 if(poh_prev) {
3392 poh_prev->size += poh_freed->size;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003393 sisfb_free_node(memheap, poh_freed);
3394 return poh_prev;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003395 }
3396
3397 if(poh_next) {
3398 poh_next->size += poh_freed->size;
3399 poh_next->offset = poh_freed->offset;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003400 sisfb_free_node(memheap, poh_freed);
3401 return poh_next;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003402 }
3403
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003404 sisfb_insert_node(&memheap->oh_free, poh_freed);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003405
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003406 return poh_freed;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003407}
3408
3409static void
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003410sisfb_free_node(struct SIS_HEAP *memheap, struct SIS_OH *poh)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003411{
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003412 if(poh == NULL)
3413 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003414
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003415 poh->poh_next = memheap->poh_freelist;
3416 memheap->poh_freelist = poh;
3417}
3418
3419static void
3420sis_int_malloc(struct sis_video_info *ivideo, struct sis_memreq *req)
3421{
3422 struct SIS_OH *poh = NULL;
3423
3424 if((ivideo) && (ivideo->sisfb_id == SISFB_ID) && (!ivideo->havenoheap))
3425 poh = sisfb_poh_allocate(&ivideo->sisfb_heap, (u32)req->size);
3426
3427 if(poh == NULL) {
3428 req->offset = req->size = 0;
3429 DPRINTK("sisfb: Video RAM allocation failed\n");
3430 } else {
3431 req->offset = poh->offset;
3432 req->size = poh->size;
3433 DPRINTK("sisfb: Video RAM allocation succeeded: 0x%lx\n",
3434 (poh->offset + ivideo->video_vbase));
3435 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003436}
3437
3438void
3439sis_malloc(struct sis_memreq *req)
3440{
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003441 struct sis_video_info *ivideo = sisfb_heap->vinfo;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003442
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003443 if(&ivideo->sisfb_heap == sisfb_heap)
3444 sis_int_malloc(ivideo, req);
3445 else
3446 req->offset = req->size = 0;
3447}
Linus Torvalds1da177e2005-04-16 15:20:36 -07003448
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003449void
3450sis_malloc_new(struct pci_dev *pdev, struct sis_memreq *req)
3451{
3452 struct sis_video_info *ivideo = pci_get_drvdata(pdev);
3453
3454 sis_int_malloc(ivideo, req);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003455}
3456
3457/* sis_free: u32 because "base" is offset inside video ram, can never be >4GB */
3458
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003459static void
3460sis_int_free(struct sis_video_info *ivideo, u32 base)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003461{
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003462 struct SIS_OH *poh;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003463
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003464 if((!ivideo) || (ivideo->sisfb_id != SISFB_ID) || (ivideo->havenoheap))
3465 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003466
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003467 poh = sisfb_poh_free(&ivideo->sisfb_heap, base);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003468
3469 if(poh == NULL) {
3470 DPRINTK("sisfb: sisfb_poh_free() failed at base 0x%x\n",
3471 (unsigned int) base);
3472 }
3473}
3474
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003475void
3476sis_free(u32 base)
3477{
3478 struct sis_video_info *ivideo = sisfb_heap->vinfo;
3479
3480 sis_int_free(ivideo, base);
3481}
3482
3483void
3484sis_free_new(struct pci_dev *pdev, u32 base)
3485{
3486 struct sis_video_info *ivideo = pci_get_drvdata(pdev);
3487
3488 sis_int_free(ivideo, base);
3489}
3490
Linus Torvalds1da177e2005-04-16 15:20:36 -07003491/* --------------------- SetMode routines ------------------------- */
3492
3493static void
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003494sisfb_check_engine_and_sync(struct sis_video_info *ivideo)
3495{
3496 u8 cr30, cr31;
3497
3498 /* Check if MMIO and engines are enabled,
3499 * and sync in case they are. Can't use
3500 * ivideo->accel here, as this might have
3501 * been changed before this is called.
3502 */
3503 inSISIDXREG(SISSR, IND_SIS_PCI_ADDRESS_SET, cr30);
3504 inSISIDXREG(SISSR, IND_SIS_MODULE_ENABLE, cr31);
3505 /* MMIO and 2D/3D engine enabled? */
3506 if((cr30 & SIS_MEM_MAP_IO_ENABLE) && (cr31 & 0x42)) {
3507#ifdef CONFIG_FB_SIS_300
3508 if(ivideo->sisvga_engine == SIS_300_VGA) {
3509 /* Don't care about TurboQueue. It's
3510 * enough to know that the engines
3511 * are enabled
3512 */
3513 sisfb_syncaccel(ivideo);
3514 }
3515#endif
3516#ifdef CONFIG_FB_SIS_315
3517 if(ivideo->sisvga_engine == SIS_315_VGA) {
3518 /* Check that any queue mode is
3519 * enabled, and that the queue
3520 * is not in the state of "reset"
3521 */
3522 inSISIDXREG(SISSR, 0x26, cr30);
3523 if((cr30 & 0xe0) && (!(cr30 & 0x01))) {
3524 sisfb_syncaccel(ivideo);
3525 }
3526 }
3527#endif
3528 }
3529}
3530
3531static void
Linus Torvalds1da177e2005-04-16 15:20:36 -07003532sisfb_pre_setmode(struct sis_video_info *ivideo)
3533{
3534 u8 cr30 = 0, cr31 = 0, cr33 = 0, cr35 = 0, cr38 = 0;
3535 int tvregnum = 0;
3536
3537 ivideo->currentvbflags &= (VB_VIDEOBRIDGE | VB_DISPTYPE_DISP2);
3538
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003539 outSISIDXREG(SISSR, 0x05, 0x86);
3540
Linus Torvalds1da177e2005-04-16 15:20:36 -07003541 inSISIDXREG(SISCR, 0x31, cr31);
3542 cr31 &= ~0x60;
3543 cr31 |= 0x04;
3544
3545 cr33 = ivideo->rate_idx & 0x0F;
3546
3547#ifdef CONFIG_FB_SIS_315
3548 if(ivideo->sisvga_engine == SIS_315_VGA) {
3549 if(ivideo->chip >= SIS_661) {
3550 inSISIDXREG(SISCR, 0x38, cr38);
3551 cr38 &= ~0x07; /* Clear LCDA/DualEdge and YPbPr bits */
3552 } else {
3553 tvregnum = 0x38;
3554 inSISIDXREG(SISCR, tvregnum, cr38);
3555 cr38 &= ~0x3b; /* Clear LCDA/DualEdge and YPbPr bits */
3556 }
3557 }
3558#endif
3559#ifdef CONFIG_FB_SIS_300
3560 if(ivideo->sisvga_engine == SIS_300_VGA) {
3561 tvregnum = 0x35;
3562 inSISIDXREG(SISCR, tvregnum, cr38);
3563 }
3564#endif
3565
Richard Knutssonc30660ea2007-02-12 00:55:06 -08003566 SiS_SetEnableDstn(&ivideo->SiS_Pr, false);
3567 SiS_SetEnableFstn(&ivideo->SiS_Pr, false);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003568 ivideo->curFSTN = ivideo->curDSTN = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003569
3570 switch(ivideo->currentvbflags & VB_DISPTYPE_DISP2) {
3571
3572 case CRT2_TV:
3573 cr38 &= ~0xc0; /* Clear PAL-M / PAL-N bits */
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003574 if((ivideo->vbflags & TV_YPBPR) && (ivideo->vbflags2 & VB2_SISYPBPRBRIDGE)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003575#ifdef CONFIG_FB_SIS_315
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003576 if(ivideo->chip >= SIS_661) {
3577 cr38 |= 0x04;
3578 if(ivideo->vbflags & TV_YPBPR525P) cr35 |= 0x20;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003579 else if(ivideo->vbflags & TV_YPBPR750P) cr35 |= 0x40;
3580 else if(ivideo->vbflags & TV_YPBPR1080I) cr35 |= 0x60;
3581 cr30 |= SIS_SIMULTANEOUS_VIEW_ENABLE;
3582 cr35 &= ~0x01;
3583 ivideo->currentvbflags |= (TV_YPBPR | (ivideo->vbflags & TV_YPBPRALL));
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003584 } else if(ivideo->sisvga_engine == SIS_315_VGA) {
3585 cr30 |= (0x80 | SIS_SIMULTANEOUS_VIEW_ENABLE);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003586 cr38 |= 0x08;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003587 if(ivideo->vbflags & TV_YPBPR525P) cr38 |= 0x10;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003588 else if(ivideo->vbflags & TV_YPBPR750P) cr38 |= 0x20;
3589 else if(ivideo->vbflags & TV_YPBPR1080I) cr38 |= 0x30;
3590 cr31 &= ~0x01;
3591 ivideo->currentvbflags |= (TV_YPBPR | (ivideo->vbflags & TV_YPBPRALL));
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003592 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003593#endif
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003594 } else if((ivideo->vbflags & TV_HIVISION) &&
3595 (ivideo->vbflags2 & VB2_SISHIVISIONBRIDGE)) {
3596 if(ivideo->chip >= SIS_661) {
3597 cr38 |= 0x04;
3598 cr35 |= 0x60;
3599 } else {
3600 cr30 |= 0x80;
3601 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003602 cr30 |= SIS_SIMULTANEOUS_VIEW_ENABLE;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003603 cr31 |= 0x01;
3604 cr35 |= 0x01;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003605 ivideo->currentvbflags |= TV_HIVISION;
3606 } else if(ivideo->vbflags & TV_SCART) {
3607 cr30 = (SIS_VB_OUTPUT_SCART | SIS_SIMULTANEOUS_VIEW_ENABLE);
3608 cr31 |= 0x01;
3609 cr35 |= 0x01;
3610 ivideo->currentvbflags |= TV_SCART;
3611 } else {
3612 if(ivideo->vbflags & TV_SVIDEO) {
3613 cr30 = (SIS_VB_OUTPUT_SVIDEO | SIS_SIMULTANEOUS_VIEW_ENABLE);
3614 ivideo->currentvbflags |= TV_SVIDEO;
3615 }
3616 if(ivideo->vbflags & TV_AVIDEO) {
3617 cr30 = (SIS_VB_OUTPUT_COMPOSITE | SIS_SIMULTANEOUS_VIEW_ENABLE);
3618 ivideo->currentvbflags |= TV_AVIDEO;
3619 }
3620 }
3621 cr31 |= SIS_DRIVER_MODE;
3622
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003623 if(ivideo->vbflags & (TV_AVIDEO | TV_SVIDEO)) {
3624 if(ivideo->vbflags & TV_PAL) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003625 cr31 |= 0x01; cr35 |= 0x01;
3626 ivideo->currentvbflags |= TV_PAL;
3627 if(ivideo->vbflags & TV_PALM) {
3628 cr38 |= 0x40; cr35 |= 0x04;
3629 ivideo->currentvbflags |= TV_PALM;
3630 } else if(ivideo->vbflags & TV_PALN) {
3631 cr38 |= 0x80; cr35 |= 0x08;
3632 ivideo->currentvbflags |= TV_PALN;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003633 }
3634 } else {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003635 cr31 &= ~0x01; cr35 &= ~0x01;
3636 ivideo->currentvbflags |= TV_NTSC;
3637 if(ivideo->vbflags & TV_NTSCJ) {
3638 cr38 |= 0x40; cr35 |= 0x02;
3639 ivideo->currentvbflags |= TV_NTSCJ;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003640 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003641 }
3642 }
3643 break;
3644
3645 case CRT2_LCD:
3646 cr30 = (SIS_VB_OUTPUT_LCD | SIS_SIMULTANEOUS_VIEW_ENABLE);
3647 cr31 |= SIS_DRIVER_MODE;
3648 SiS_SetEnableDstn(&ivideo->SiS_Pr, ivideo->sisfb_dstn);
3649 SiS_SetEnableFstn(&ivideo->SiS_Pr, ivideo->sisfb_fstn);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003650 ivideo->curFSTN = ivideo->sisfb_fstn;
3651 ivideo->curDSTN = ivideo->sisfb_dstn;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003652 break;
3653
3654 case CRT2_VGA:
3655 cr30 = (SIS_VB_OUTPUT_CRT2 | SIS_SIMULTANEOUS_VIEW_ENABLE);
3656 cr31 |= SIS_DRIVER_MODE;
3657 if(ivideo->sisfb_nocrt2rate) {
3658 cr33 |= (sisbios_mode[ivideo->sisfb_mode_idx].rate_idx << 4);
3659 } else {
3660 cr33 |= ((ivideo->rate_idx & 0x0F) << 4);
3661 }
3662 break;
3663
3664 default: /* disable CRT2 */
3665 cr30 = 0x00;
3666 cr31 |= (SIS_DRIVER_MODE | SIS_VB_OUTPUT_DISABLE);
3667 }
3668
3669 outSISIDXREG(SISCR, 0x30, cr30);
3670 outSISIDXREG(SISCR, 0x33, cr33);
3671
3672 if(ivideo->chip >= SIS_661) {
3673#ifdef CONFIG_FB_SIS_315
3674 cr31 &= ~0x01; /* Clear PAL flag (now in CR35) */
3675 setSISIDXREG(SISCR, 0x35, ~0x10, cr35); /* Leave overscan bit alone */
3676 cr38 &= 0x07; /* Use only LCDA and HiVision/YPbPr bits */
3677 setSISIDXREG(SISCR, 0x38, 0xf8, cr38);
3678#endif
3679 } else if(ivideo->chip != SIS_300) {
3680 outSISIDXREG(SISCR, tvregnum, cr38);
3681 }
3682 outSISIDXREG(SISCR, 0x31, cr31);
3683
Linus Torvalds1da177e2005-04-16 15:20:36 -07003684 ivideo->SiS_Pr.SiS_UseOEM = ivideo->sisfb_useoem;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003685
3686 sisfb_check_engine_and_sync(ivideo);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003687}
3688
3689/* Fix SR11 for 661 and later */
3690#ifdef CONFIG_FB_SIS_315
3691static void
3692sisfb_fixup_SR11(struct sis_video_info *ivideo)
3693{
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003694 u8 tmpreg;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003695
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003696 if(ivideo->chip >= SIS_661) {
3697 inSISIDXREG(SISSR,0x11,tmpreg);
3698 if(tmpreg & 0x20) {
3699 inSISIDXREG(SISSR,0x3e,tmpreg);
3700 tmpreg = (tmpreg + 1) & 0xff;
3701 outSISIDXREG(SISSR,0x3e,tmpreg);
3702 inSISIDXREG(SISSR,0x11,tmpreg);
3703 }
3704 if(tmpreg & 0xf0) {
3705 andSISIDXREG(SISSR,0x11,0x0f);
3706 }
3707 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003708}
3709#endif
3710
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003711static void
3712sisfb_set_TVxposoffset(struct sis_video_info *ivideo, int val)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003713{
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003714 if(val > 32) val = 32;
3715 if(val < -32) val = -32;
3716 ivideo->tvxpos = val;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003717
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003718 if(ivideo->sisfblocked) return;
3719 if(!ivideo->modechanged) return;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003720
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003721 if(ivideo->currentvbflags & CRT2_TV) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003722
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003723 if(ivideo->vbflags2 & VB2_CHRONTEL) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003724
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003725 int x = ivideo->tvx;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003726
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003727 switch(ivideo->chronteltype) {
3728 case 1:
3729 x += val;
3730 if(x < 0) x = 0;
3731 outSISIDXREG(SISSR,0x05,0x86);
3732 SiS_SetCH700x(&ivideo->SiS_Pr, 0x0a, (x & 0xff));
3733 SiS_SetCH70xxANDOR(&ivideo->SiS_Pr, 0x08, ((x & 0x0100) >> 7), 0xFD);
3734 break;
3735 case 2:
3736 /* Not supported by hardware */
3737 break;
3738 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003739
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003740 } else if(ivideo->vbflags2 & VB2_SISBRIDGE) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003741
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003742 u8 p2_1f,p2_20,p2_2b,p2_42,p2_43;
3743 unsigned short temp;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003744
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003745 p2_1f = ivideo->p2_1f;
3746 p2_20 = ivideo->p2_20;
3747 p2_2b = ivideo->p2_2b;
3748 p2_42 = ivideo->p2_42;
3749 p2_43 = ivideo->p2_43;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003750
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003751 temp = p2_1f | ((p2_20 & 0xf0) << 4);
3752 temp += (val * 2);
3753 p2_1f = temp & 0xff;
3754 p2_20 = (temp & 0xf00) >> 4;
3755 p2_2b = ((p2_2b & 0x0f) + (val * 2)) & 0x0f;
3756 temp = p2_43 | ((p2_42 & 0xf0) << 4);
3757 temp += (val * 2);
3758 p2_43 = temp & 0xff;
3759 p2_42 = (temp & 0xf00) >> 4;
3760 outSISIDXREG(SISPART2,0x1f,p2_1f);
3761 setSISIDXREG(SISPART2,0x20,0x0F,p2_20);
3762 setSISIDXREG(SISPART2,0x2b,0xF0,p2_2b);
3763 setSISIDXREG(SISPART2,0x42,0x0F,p2_42);
3764 outSISIDXREG(SISPART2,0x43,p2_43);
3765 }
3766 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003767}
3768
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003769static void
3770sisfb_set_TVyposoffset(struct sis_video_info *ivideo, int val)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003771{
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003772 if(val > 32) val = 32;
3773 if(val < -32) val = -32;
3774 ivideo->tvypos = val;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003775
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003776 if(ivideo->sisfblocked) return;
3777 if(!ivideo->modechanged) return;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003778
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003779 if(ivideo->currentvbflags & CRT2_TV) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003780
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003781 if(ivideo->vbflags2 & VB2_CHRONTEL) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003782
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003783 int y = ivideo->tvy;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003784
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003785 switch(ivideo->chronteltype) {
3786 case 1:
3787 y -= val;
3788 if(y < 0) y = 0;
3789 outSISIDXREG(SISSR,0x05,0x86);
3790 SiS_SetCH700x(&ivideo->SiS_Pr, 0x0b, (y & 0xff));
3791 SiS_SetCH70xxANDOR(&ivideo->SiS_Pr, 0x08, ((y & 0x0100) >> 8), 0xFE);
3792 break;
3793 case 2:
3794 /* Not supported by hardware */
3795 break;
3796 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003797
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003798 } else if(ivideo->vbflags2 & VB2_SISBRIDGE) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003799
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003800 char p2_01, p2_02;
3801 val /= 2;
3802 p2_01 = ivideo->p2_01;
3803 p2_02 = ivideo->p2_02;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003804
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003805 p2_01 += val;
3806 p2_02 += val;
3807 if(!(ivideo->currentvbflags & (TV_HIVISION | TV_YPBPR))) {
3808 while((p2_01 <= 0) || (p2_02 <= 0)) {
3809 p2_01 += 2;
3810 p2_02 += 2;
3811 }
3812 }
3813 outSISIDXREG(SISPART2,0x01,p2_01);
3814 outSISIDXREG(SISPART2,0x02,p2_02);
3815 }
3816 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003817}
3818
3819static void
3820sisfb_post_setmode(struct sis_video_info *ivideo)
3821{
Richard Knutssonc30660ea2007-02-12 00:55:06 -08003822 bool crt1isoff = false;
3823 bool doit = true;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003824#if defined(CONFIG_FB_SIS_300) || defined(CONFIG_FB_SIS_315)
3825 u8 reg;
3826#endif
3827#ifdef CONFIG_FB_SIS_315
3828 u8 reg1;
3829#endif
3830
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003831 outSISIDXREG(SISSR, 0x05, 0x86);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003832
3833#ifdef CONFIG_FB_SIS_315
3834 sisfb_fixup_SR11(ivideo);
3835#endif
3836
3837 /* Now we actually HAVE changed the display mode */
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003838 ivideo->modechanged = 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003839
3840 /* We can't switch off CRT1 if bridge is in slave mode */
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003841 if(ivideo->vbflags2 & VB2_VIDEOBRIDGE) {
Richard Knutssonc30660ea2007-02-12 00:55:06 -08003842 if(sisfb_bridgeisslave(ivideo)) doit = false;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003843 } else
3844 ivideo->sisfb_crt1off = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003845
3846#ifdef CONFIG_FB_SIS_300
3847 if(ivideo->sisvga_engine == SIS_300_VGA) {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003848 if((ivideo->sisfb_crt1off) && (doit)) {
Richard Knutssonc30660ea2007-02-12 00:55:06 -08003849 crt1isoff = true;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003850 reg = 0x00;
3851 } else {
Richard Knutssonc30660ea2007-02-12 00:55:06 -08003852 crt1isoff = false;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003853 reg = 0x80;
3854 }
3855 setSISIDXREG(SISCR, 0x17, 0x7f, reg);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003856 }
3857#endif
3858#ifdef CONFIG_FB_SIS_315
3859 if(ivideo->sisvga_engine == SIS_315_VGA) {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003860 if((ivideo->sisfb_crt1off) && (doit)) {
Richard Knutssonc30660ea2007-02-12 00:55:06 -08003861 crt1isoff = true;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003862 reg = 0x40;
3863 reg1 = 0xc0;
3864 } else {
Richard Knutssonc30660ea2007-02-12 00:55:06 -08003865 crt1isoff = false;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003866 reg = 0x00;
3867 reg1 = 0x00;
3868 }
3869 setSISIDXREG(SISCR, ivideo->SiS_Pr.SiS_MyCR63, ~0x40, reg);
3870 setSISIDXREG(SISSR, 0x1f, ~0xc0, reg1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003871 }
3872#endif
3873
3874 if(crt1isoff) {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003875 ivideo->currentvbflags &= ~VB_DISPTYPE_CRT1;
3876 ivideo->currentvbflags |= VB_SINGLE_MODE;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003877 } else {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003878 ivideo->currentvbflags |= VB_DISPTYPE_CRT1;
3879 if(ivideo->currentvbflags & VB_DISPTYPE_CRT2) {
3880 ivideo->currentvbflags |= VB_MIRROR_MODE;
3881 } else {
3882 ivideo->currentvbflags |= VB_SINGLE_MODE;
3883 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003884 }
3885
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003886 andSISIDXREG(SISSR, IND_SIS_RAMDAC_CONTROL, ~0x04);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003887
3888 if(ivideo->currentvbflags & CRT2_TV) {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003889 if(ivideo->vbflags2 & VB2_SISBRIDGE) {
3890 inSISIDXREG(SISPART2,0x1f,ivideo->p2_1f);
3891 inSISIDXREG(SISPART2,0x20,ivideo->p2_20);
3892 inSISIDXREG(SISPART2,0x2b,ivideo->p2_2b);
3893 inSISIDXREG(SISPART2,0x42,ivideo->p2_42);
3894 inSISIDXREG(SISPART2,0x43,ivideo->p2_43);
3895 inSISIDXREG(SISPART2,0x01,ivideo->p2_01);
3896 inSISIDXREG(SISPART2,0x02,ivideo->p2_02);
3897 } else if(ivideo->vbflags2 & VB2_CHRONTEL) {
3898 if(ivideo->chronteltype == 1) {
3899 ivideo->tvx = SiS_GetCH700x(&ivideo->SiS_Pr, 0x0a);
3900 ivideo->tvx |= (((SiS_GetCH700x(&ivideo->SiS_Pr, 0x08) & 0x02) >> 1) << 8);
3901 ivideo->tvy = SiS_GetCH700x(&ivideo->SiS_Pr, 0x0b);
3902 ivideo->tvy |= ((SiS_GetCH700x(&ivideo->SiS_Pr, 0x08) & 0x01) << 8);
3903 }
3904 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003905 }
3906
3907 if(ivideo->tvxpos) {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003908 sisfb_set_TVxposoffset(ivideo, ivideo->tvxpos);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003909 }
3910 if(ivideo->tvypos) {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003911 sisfb_set_TVyposoffset(ivideo, ivideo->tvypos);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003912 }
3913
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003914 /* Eventually sync engines */
3915 sisfb_check_engine_and_sync(ivideo);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003916
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003917 /* (Re-)Initialize chip engines */
3918 if(ivideo->accel) {
3919 sisfb_engine_init(ivideo);
3920 } else {
3921 ivideo->engineok = 0;
3922 }
3923}
Linus Torvalds1da177e2005-04-16 15:20:36 -07003924
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003925static int
3926sisfb_reset_mode(struct sis_video_info *ivideo)
3927{
3928 if(sisfb_set_mode(ivideo, 0))
3929 return 1;
3930
3931 sisfb_set_pitch(ivideo);
3932 sisfb_set_base_CRT1(ivideo, ivideo->current_base);
3933 sisfb_set_base_CRT2(ivideo, ivideo->current_base);
3934
3935 return 0;
3936}
3937
3938static void
3939sisfb_handle_command(struct sis_video_info *ivideo, struct sisfb_cmd *sisfb_command)
3940{
3941 int mycrt1off;
3942
3943 switch(sisfb_command->sisfb_cmd) {
3944 case SISFB_CMD_GETVBFLAGS:
3945 if(!ivideo->modechanged) {
3946 sisfb_command->sisfb_result[0] = SISFB_CMD_ERR_EARLY;
3947 } else {
3948 sisfb_command->sisfb_result[0] = SISFB_CMD_ERR_OK;
3949 sisfb_command->sisfb_result[1] = ivideo->currentvbflags;
3950 sisfb_command->sisfb_result[2] = ivideo->vbflags2;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003951 }
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003952 break;
3953 case SISFB_CMD_SWITCHCRT1:
3954 /* arg[0]: 0 = off, 1 = on, 99 = query */
3955 if(!ivideo->modechanged) {
3956 sisfb_command->sisfb_result[0] = SISFB_CMD_ERR_EARLY;
3957 } else if(sisfb_command->sisfb_arg[0] == 99) {
3958 /* Query */
3959 sisfb_command->sisfb_result[1] = ivideo->sisfb_crt1off ? 0 : 1;
3960 sisfb_command->sisfb_result[0] = SISFB_CMD_ERR_OK;
3961 } else if(ivideo->sisfblocked) {
3962 sisfb_command->sisfb_result[0] = SISFB_CMD_ERR_LOCKED;
3963 } else if((!(ivideo->currentvbflags & CRT2_ENABLE)) &&
3964 (sisfb_command->sisfb_arg[0] == 0)) {
3965 sisfb_command->sisfb_result[0] = SISFB_CMD_ERR_NOCRT2;
3966 } else {
3967 sisfb_command->sisfb_result[0] = SISFB_CMD_ERR_OK;
3968 mycrt1off = sisfb_command->sisfb_arg[0] ? 0 : 1;
3969 if( ((ivideo->currentvbflags & VB_DISPTYPE_CRT1) && mycrt1off) ||
3970 ((!(ivideo->currentvbflags & VB_DISPTYPE_CRT1)) && !mycrt1off) ) {
3971 ivideo->sisfb_crt1off = mycrt1off;
3972 if(sisfb_reset_mode(ivideo)) {
3973 sisfb_command->sisfb_result[0] = SISFB_CMD_ERR_OTHER;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003974 }
3975 }
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003976 sisfb_command->sisfb_result[1] = ivideo->sisfb_crt1off ? 0 : 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003977 }
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003978 break;
3979 /* more to come */
3980 default:
3981 sisfb_command->sisfb_result[0] = SISFB_CMD_ERR_UNKNOWN;
3982 printk(KERN_ERR "sisfb: Unknown command 0x%x\n",
3983 sisfb_command->sisfb_cmd);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003984 }
3985}
3986
3987#ifndef MODULE
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003988SISINITSTATIC int __init
3989sisfb_setup(char *options)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003990{
3991 char *this_opt;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003992
Linus Torvalds1da177e2005-04-16 15:20:36 -07003993 sisfb_setdefaultparms();
3994
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003995 if(!options || !(*options))
Linus Torvalds1da177e2005-04-16 15:20:36 -07003996 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003997
3998 while((this_opt = strsep(&options, ",")) != NULL) {
3999
4000 if(!(*this_opt)) continue;
4001
4002 if(!strnicmp(this_opt, "off", 3)) {
4003 sisfb_off = 1;
4004 } else if(!strnicmp(this_opt, "forcecrt2type:", 14)) {
4005 /* Need to check crt2 type first for fstn/dstn */
4006 sisfb_search_crt2type(this_opt + 14);
4007 } else if(!strnicmp(this_opt, "tvmode:",7)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004008 sisfb_search_tvstd(this_opt + 7);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004009 } else if(!strnicmp(this_opt, "tvstandard:",11)) {
4010 sisfb_search_tvstd(this_opt + 11);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004011 } else if(!strnicmp(this_opt, "mode:", 5)) {
Richard Knutssonc30660ea2007-02-12 00:55:06 -08004012 sisfb_search_mode(this_opt + 5, false);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004013 } else if(!strnicmp(this_opt, "vesa:", 5)) {
Richard Knutssonc30660ea2007-02-12 00:55:06 -08004014 sisfb_search_vesamode(simple_strtoul(this_opt + 5, NULL, 0), false);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004015 } else if(!strnicmp(this_opt, "rate:", 5)) {
4016 sisfb_parm_rate = simple_strtoul(this_opt + 5, NULL, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004017 } else if(!strnicmp(this_opt, "forcecrt1:", 10)) {
4018 sisfb_forcecrt1 = (int)simple_strtoul(this_opt + 10, NULL, 0);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004019 } else if(!strnicmp(this_opt, "mem:",4)) {
4020 sisfb_parm_mem = simple_strtoul(this_opt + 4, NULL, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004021 } else if(!strnicmp(this_opt, "pdc:", 4)) {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004022 sisfb_pdc = simple_strtoul(this_opt + 4, NULL, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004023 } else if(!strnicmp(this_opt, "pdc1:", 5)) {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004024 sisfb_pdca = simple_strtoul(this_opt + 5, NULL, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004025 } else if(!strnicmp(this_opt, "noaccel", 7)) {
4026 sisfb_accel = 0;
4027 } else if(!strnicmp(this_opt, "accel", 5)) {
4028 sisfb_accel = -1;
4029 } else if(!strnicmp(this_opt, "noypan", 6)) {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004030 sisfb_ypan = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004031 } else if(!strnicmp(this_opt, "ypan", 4)) {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004032 sisfb_ypan = -1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004033 } else if(!strnicmp(this_opt, "nomax", 5)) {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004034 sisfb_max = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004035 } else if(!strnicmp(this_opt, "max", 3)) {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004036 sisfb_max = -1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004037 } else if(!strnicmp(this_opt, "userom:", 7)) {
4038 sisfb_userom = (int)simple_strtoul(this_opt + 7, NULL, 0);
4039 } else if(!strnicmp(this_opt, "useoem:", 7)) {
4040 sisfb_useoem = (int)simple_strtoul(this_opt + 7, NULL, 0);
4041 } else if(!strnicmp(this_opt, "nocrt2rate", 10)) {
4042 sisfb_nocrt2rate = 1;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004043 } else if(!strnicmp(this_opt, "scalelcd:", 9)) {
4044 unsigned long temp = 2;
4045 temp = simple_strtoul(this_opt + 9, NULL, 0);
4046 if((temp == 0) || (temp == 1)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004047 sisfb_scalelcd = temp ^ 1;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004048 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004049 } else if(!strnicmp(this_opt, "tvxposoffset:", 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_tvxposoffset = temp;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004054 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004055 } else if(!strnicmp(this_opt, "tvyposoffset:", 13)) {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004056 int temp = 0;
4057 temp = (int)simple_strtol(this_opt + 13, NULL, 0);
4058 if((temp >= -32) && (temp <= 32)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004059 sisfb_tvyposoffset = temp;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004060 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004061 } else if(!strnicmp(this_opt, "specialtiming:", 14)) {
4062 sisfb_search_specialtiming(this_opt + 14);
4063 } else if(!strnicmp(this_opt, "lvdshl:", 7)) {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004064 int temp = 4;
4065 temp = simple_strtoul(this_opt + 7, NULL, 0);
4066 if((temp >= 0) && (temp <= 3)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004067 sisfb_lvdshl = temp;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004068 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004069 } else if(this_opt[0] >= '0' && this_opt[0] <= '9') {
Richard Knutssonc30660ea2007-02-12 00:55:06 -08004070 sisfb_search_mode(this_opt, true);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004071#if !defined(__i386__) && !defined(__x86_64__)
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004072 } else if(!strnicmp(this_opt, "resetcard", 9)) {
4073 sisfb_resetcard = 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004074 } else if(!strnicmp(this_opt, "videoram:", 9)) {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004075 sisfb_videoram = simple_strtoul(this_opt + 9, NULL, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004076#endif
4077 } else {
4078 printk(KERN_INFO "sisfb: Invalid option %s\n", this_opt);
4079 }
4080
4081 }
4082
Linus Torvalds1da177e2005-04-16 15:20:36 -07004083 return 0;
4084}
4085#endif
4086
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004087static int __devinit
4088sisfb_check_rom(SIS_IOTYPE1 *rom_base, struct sis_video_info *ivideo)
4089{
4090 SIS_IOTYPE1 *rom;
4091 int romptr;
4092
4093 if((readb(rom_base) != 0x55) || (readb(rom_base + 1) != 0xaa))
4094 return 0;
4095
4096 romptr = (readb(rom_base + 0x18) | (readb(rom_base + 0x19) << 8));
4097 if(romptr > (0x10000 - 8))
4098 return 0;
4099
4100 rom = rom_base + romptr;
4101
4102 if((readb(rom) != 'P') || (readb(rom + 1) != 'C') ||
4103 (readb(rom + 2) != 'I') || (readb(rom + 3) != 'R'))
4104 return 0;
4105
4106 if((readb(rom + 4) | (readb(rom + 5) << 8)) != ivideo->chip_vendor)
4107 return 0;
4108
4109 if((readb(rom + 6) | (readb(rom + 7) << 8)) != ivideo->chip_id)
4110 return 0;
4111
4112 return 1;
4113}
4114
4115static unsigned char * __devinit
4116sisfb_find_rom(struct pci_dev *pdev)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004117{
4118 struct sis_video_info *ivideo = pci_get_drvdata(pdev);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004119 SIS_IOTYPE1 *rom_base;
4120 unsigned char *myrombase = NULL;
4121 u32 temp;
4122#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,11)
4123 size_t romsize;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004124
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004125 /* First, try the official pci ROM functions (except
4126 * on integrated chipsets which have no ROM).
4127 */
4128
4129 if(!ivideo->nbridge) {
4130
4131 if((rom_base = pci_map_rom(pdev, &romsize))) {
4132
4133 if(sisfb_check_rom(rom_base, ivideo)) {
4134
4135 if((myrombase = vmalloc(65536))) {
4136
4137 /* Work around bug in pci/rom.c: Folks forgot to check
4138 * whether the size retrieved from the BIOS image eventually
4139 * is larger than the mapped size
4140 */
4141 if(pci_resource_len(pdev, PCI_ROM_RESOURCE) < romsize)
4142 romsize = pci_resource_len(pdev, PCI_ROM_RESOURCE);
4143
4144 memcpy_fromio(myrombase, rom_base,
4145 (romsize > 65536) ? 65536 : romsize);
4146 }
4147 }
4148 pci_unmap_rom(pdev, rom_base);
4149 }
4150 }
4151
4152 if(myrombase) return myrombase;
4153#endif
4154
4155 /* Otherwise do it the conventional way. */
Linus Torvalds1da177e2005-04-16 15:20:36 -07004156
4157#if defined(__i386__) || defined(__x86_64__)
4158
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004159 for(temp = 0x000c0000; temp < 0x000f0000; temp += 0x00001000) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004160
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004161 rom_base = ioremap(temp, 65536);
4162 if(!rom_base)
4163 continue;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004164
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004165 if(!sisfb_check_rom(rom_base, ivideo)) {
4166 iounmap(rom_base);
4167 continue;
4168 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004169
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004170 if((myrombase = vmalloc(65536)))
4171 memcpy_fromio(myrombase, rom_base, 65536);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004172
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004173 iounmap(rom_base);
4174 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004175
Linus Torvalds1da177e2005-04-16 15:20:36 -07004176 }
4177
4178#else
4179
4180 pci_read_config_dword(pdev, PCI_ROM_ADDRESS, &temp);
4181 pci_write_config_dword(pdev, PCI_ROM_ADDRESS,
4182 (ivideo->video_base & PCI_ROM_ADDRESS_MASK) | PCI_ROM_ADDRESS_ENABLE);
4183
4184 rom_base = ioremap(ivideo->video_base, 65536);
4185 if(rom_base) {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004186 if(sisfb_check_rom(rom_base, ivideo)) {
4187 if((myrombase = vmalloc(65536)))
4188 memcpy_fromio(myrombase, rom_base, 65536);
4189 }
4190 iounmap(rom_base);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004191 }
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004192
4193 pci_write_config_dword(pdev, PCI_ROM_ADDRESS, temp);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004194
4195#endif
4196
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004197 return myrombase;
4198}
4199
4200static void __devinit
4201sisfb_post_map_vram(struct sis_video_info *ivideo, unsigned int *mapsize,
4202 unsigned int min)
4203{
4204 ivideo->video_vbase = ioremap(ivideo->video_base, (*mapsize));
4205
4206 if(!ivideo->video_vbase) {
4207 printk(KERN_ERR
4208 "sisfb: Unable to map maximum video RAM for size detection\n");
4209 (*mapsize) >>= 1;
4210 while((!(ivideo->video_vbase = ioremap(ivideo->video_base, (*mapsize))))) {
4211 (*mapsize) >>= 1;
4212 if((*mapsize) < (min << 20))
4213 break;
4214 }
4215 if(ivideo->video_vbase) {
4216 printk(KERN_ERR
4217 "sisfb: Video RAM size detection limited to %dMB\n",
4218 (int)((*mapsize) >> 20));
4219 }
4220 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004221}
4222
4223#ifdef CONFIG_FB_SIS_300
4224static int __devinit
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004225sisfb_post_300_buswidth(struct sis_video_info *ivideo)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004226{
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004227 SIS_IOTYPE1 *FBAddress = ivideo->video_vbase;
4228 unsigned short temp;
4229 unsigned char reg;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004230 int i, j;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004231
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004232 andSISIDXREG(SISSR, 0x15, 0xFB);
4233 orSISIDXREG(SISSR, 0x15, 0x04);
4234 outSISIDXREG(SISSR, 0x13, 0x00);
4235 outSISIDXREG(SISSR, 0x14, 0xBF);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004236
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004237 for(i = 0; i < 2; i++) {
4238 temp = 0x1234;
4239 for(j = 0; j < 4; j++) {
4240 writew(temp, FBAddress);
4241 if(readw(FBAddress) == temp)
4242 break;
4243 orSISIDXREG(SISSR, 0x3c, 0x01);
4244 inSISIDXREG(SISSR, 0x05, reg);
4245 inSISIDXREG(SISSR, 0x05, reg);
4246 andSISIDXREG(SISSR, 0x3c, 0xfe);
4247 inSISIDXREG(SISSR, 0x05, reg);
4248 inSISIDXREG(SISSR, 0x05, reg);
4249 temp++;
4250 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004251 }
4252
4253 writel(0x01234567L, FBAddress);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004254 writel(0x456789ABL, (FBAddress + 4));
4255 writel(0x89ABCDEFL, (FBAddress + 8));
4256 writel(0xCDEF0123L, (FBAddress + 12));
4257
4258 inSISIDXREG(SISSR, 0x3b, reg);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004259 if(reg & 0x01) {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004260 if(readl((FBAddress + 12)) == 0xCDEF0123L)
4261 return 4; /* Channel A 128bit */
Linus Torvalds1da177e2005-04-16 15:20:36 -07004262 }
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004263
4264 if(readl((FBAddress + 4)) == 0x456789ABL)
4265 return 2; /* Channel B 64bit */
4266
4267 return 1; /* 32bit */
4268}
4269
4270static int __devinit
4271sisfb_post_300_rwtest(struct sis_video_info *ivideo, int iteration, int buswidth,
4272 int PseudoRankCapacity, int PseudoAdrPinCount,
4273 unsigned int mapsize)
4274{
4275 SIS_IOTYPE1 *FBAddr = ivideo->video_vbase;
4276 unsigned short sr14;
4277 unsigned int k, RankCapacity, PageCapacity, BankNumHigh, BankNumMid;
4278 unsigned int PhysicalAdrOtherPage, PhysicalAdrHigh, PhysicalAdrHalfPage;
4279 static const unsigned short SiS_DRAMType[17][5] = {
4280 {0x0C,0x0A,0x02,0x40,0x39},
4281 {0x0D,0x0A,0x01,0x40,0x48},
4282 {0x0C,0x09,0x02,0x20,0x35},
4283 {0x0D,0x09,0x01,0x20,0x44},
4284 {0x0C,0x08,0x02,0x10,0x31},
4285 {0x0D,0x08,0x01,0x10,0x40},
4286 {0x0C,0x0A,0x01,0x20,0x34},
4287 {0x0C,0x09,0x01,0x08,0x32},
4288 {0x0B,0x08,0x02,0x08,0x21},
4289 {0x0C,0x08,0x01,0x08,0x30},
4290 {0x0A,0x08,0x02,0x04,0x11},
4291 {0x0B,0x0A,0x01,0x10,0x28},
4292 {0x09,0x08,0x02,0x02,0x01},
4293 {0x0B,0x09,0x01,0x08,0x24},
4294 {0x0B,0x08,0x01,0x04,0x20},
4295 {0x0A,0x08,0x01,0x02,0x10},
4296 {0x09,0x08,0x01,0x01,0x00}
4297 };
4298
4299 for(k = 0; k <= 16; k++) {
4300
4301 RankCapacity = buswidth * SiS_DRAMType[k][3];
4302
4303 if(RankCapacity != PseudoRankCapacity)
4304 continue;
4305
4306 if((SiS_DRAMType[k][2] + SiS_DRAMType[k][0]) > PseudoAdrPinCount)
4307 continue;
4308
4309 BankNumHigh = RankCapacity * 16 * iteration - 1;
4310 if(iteration == 3) { /* Rank No */
4311 BankNumMid = RankCapacity * 16 - 1;
4312 } else {
4313 BankNumMid = RankCapacity * 16 * iteration / 2 - 1;
4314 }
4315
4316 PageCapacity = (1 << SiS_DRAMType[k][1]) * buswidth * 4;
4317 PhysicalAdrHigh = BankNumHigh;
4318 PhysicalAdrHalfPage = (PageCapacity / 2 + PhysicalAdrHigh) % PageCapacity;
4319 PhysicalAdrOtherPage = PageCapacity * SiS_DRAMType[k][2] + PhysicalAdrHigh;
4320
4321 andSISIDXREG(SISSR, 0x15, 0xFB); /* Test */
4322 orSISIDXREG(SISSR, 0x15, 0x04); /* Test */
4323 sr14 = (SiS_DRAMType[k][3] * buswidth) - 1;
4324 if(buswidth == 4) sr14 |= 0x80;
4325 else if(buswidth == 2) sr14 |= 0x40;
4326 outSISIDXREG(SISSR, 0x13, SiS_DRAMType[k][4]);
4327 outSISIDXREG(SISSR, 0x14, sr14);
4328
4329 BankNumHigh <<= 16;
4330 BankNumMid <<= 16;
4331
4332 if((BankNumHigh + PhysicalAdrHigh >= mapsize) ||
4333 (BankNumMid + PhysicalAdrHigh >= mapsize) ||
4334 (BankNumHigh + PhysicalAdrHalfPage >= mapsize) ||
4335 (BankNumHigh + PhysicalAdrOtherPage >= mapsize))
4336 continue;
4337
4338 /* Write data */
4339 writew(((unsigned short)PhysicalAdrHigh),
4340 (FBAddr + BankNumHigh + PhysicalAdrHigh));
4341 writew(((unsigned short)BankNumMid),
4342 (FBAddr + BankNumMid + PhysicalAdrHigh));
4343 writew(((unsigned short)PhysicalAdrHalfPage),
4344 (FBAddr + BankNumHigh + PhysicalAdrHalfPage));
4345 writew(((unsigned short)PhysicalAdrOtherPage),
4346 (FBAddr + BankNumHigh + PhysicalAdrOtherPage));
4347
4348 /* Read data */
4349 if(readw(FBAddr + BankNumHigh + PhysicalAdrHigh) == PhysicalAdrHigh)
4350 return 1;
4351 }
4352
4353 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004354}
4355
4356static void __devinit
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004357sisfb_post_300_ramsize(struct pci_dev *pdev, unsigned int mapsize)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004358{
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004359 struct sis_video_info *ivideo = pci_get_drvdata(pdev);
4360 int i, j, buswidth;
4361 int PseudoRankCapacity, PseudoAdrPinCount;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004362
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004363 buswidth = sisfb_post_300_buswidth(ivideo);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004364
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004365 for(i = 6; i >= 0; i--) {
4366 PseudoRankCapacity = 1 << i;
4367 for(j = 4; j >= 1; j--) {
4368 PseudoAdrPinCount = 15 - j;
4369 if((PseudoRankCapacity * j) <= 64) {
4370 if(sisfb_post_300_rwtest(ivideo,
4371 j,
4372 buswidth,
4373 PseudoRankCapacity,
4374 PseudoAdrPinCount,
4375 mapsize))
4376 return;
4377 }
4378 }
4379 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004380}
4381
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004382static void __devinit
4383sisfb_post_sis300(struct pci_dev *pdev)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004384{
4385 struct sis_video_info *ivideo = pci_get_drvdata(pdev);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004386 unsigned char *bios = ivideo->SiS_Pr.VirtualRomBase;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004387 u8 reg, v1, v2, v3, v4, v5, v6, v7, v8;
4388 u16 index, rindex, memtype = 0;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004389 unsigned int mapsize;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004390
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004391 if(!ivideo->SiS_Pr.UseROM)
4392 bios = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004393
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004394 outSISIDXREG(SISSR, 0x05, 0x86);
4395
4396 if(bios) {
4397 if(bios[0x52] & 0x80) {
4398 memtype = bios[0x52];
4399 } else {
4400 inSISIDXREG(SISSR, 0x3a, memtype);
4401 }
4402 memtype &= 0x07;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004403 }
4404
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004405 v3 = 0x80; v6 = 0x80;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004406 if(ivideo->revision_id <= 0x13) {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004407 v1 = 0x44; v2 = 0x42;
4408 v4 = 0x44; v5 = 0x42;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004409 } else {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004410 v1 = 0x68; v2 = 0x43; /* Assume 125Mhz MCLK */
4411 v4 = 0x68; v5 = 0x43; /* Assume 125Mhz ECLK */
4412 if(bios) {
4413 index = memtype * 5;
4414 rindex = index + 0x54;
4415 v1 = bios[rindex++];
4416 v2 = bios[rindex++];
4417 v3 = bios[rindex++];
4418 rindex = index + 0x7c;
4419 v4 = bios[rindex++];
4420 v5 = bios[rindex++];
4421 v6 = bios[rindex++];
4422 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004423 }
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004424 outSISIDXREG(SISSR, 0x28, v1);
4425 outSISIDXREG(SISSR, 0x29, v2);
4426 outSISIDXREG(SISSR, 0x2a, v3);
4427 outSISIDXREG(SISSR, 0x2e, v4);
4428 outSISIDXREG(SISSR, 0x2f, v5);
4429 outSISIDXREG(SISSR, 0x30, v6);
4430
Linus Torvalds1da177e2005-04-16 15:20:36 -07004431 v1 = 0x10;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004432 if(bios)
4433 v1 = bios[0xa4];
4434 outSISIDXREG(SISSR, 0x07, v1); /* DAC speed */
4435
4436 outSISIDXREG(SISSR, 0x11, 0x0f); /* DDC, power save */
4437
Linus Torvalds1da177e2005-04-16 15:20:36 -07004438 v1 = 0x01; v2 = 0x43; v3 = 0x1e; v4 = 0x2a;
4439 v5 = 0x06; v6 = 0x00; v7 = 0x00; v8 = 0x00;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004440 if(bios) {
4441 memtype += 0xa5;
4442 v1 = bios[memtype];
4443 v2 = bios[memtype + 8];
4444 v3 = bios[memtype + 16];
4445 v4 = bios[memtype + 24];
4446 v5 = bios[memtype + 32];
4447 v6 = bios[memtype + 40];
4448 v7 = bios[memtype + 48];
4449 v8 = bios[memtype + 56];
Linus Torvalds1da177e2005-04-16 15:20:36 -07004450 }
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004451 if(ivideo->revision_id >= 0x80)
4452 v3 &= 0xfd;
4453 outSISIDXREG(SISSR, 0x15, v1); /* Ram type (assuming 0, BIOS 0xa5 step 8) */
4454 outSISIDXREG(SISSR, 0x16, v2);
4455 outSISIDXREG(SISSR, 0x17, v3);
4456 outSISIDXREG(SISSR, 0x18, v4);
4457 outSISIDXREG(SISSR, 0x19, v5);
4458 outSISIDXREG(SISSR, 0x1a, v6);
4459 outSISIDXREG(SISSR, 0x1b, v7);
4460 outSISIDXREG(SISSR, 0x1c, v8); /* ---- */
4461 andSISIDXREG(SISSR, 0x15 ,0xfb);
4462 orSISIDXREG(SISSR, 0x15, 0x04);
4463 if(bios) {
4464 if(bios[0x53] & 0x02) {
4465 orSISIDXREG(SISSR, 0x19, 0x20);
4466 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004467 }
4468 v1 = 0x04; /* DAC pedestal (BIOS 0xe5) */
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004469 if(ivideo->revision_id >= 0x80)
4470 v1 |= 0x01;
4471 outSISIDXREG(SISSR, 0x1f, v1);
4472 outSISIDXREG(SISSR, 0x20, 0xa4); /* linear & relocated io & disable a0000 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07004473 v1 = 0xf6; v2 = 0x0d; v3 = 0x00;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004474 if(bios) {
4475 v1 = bios[0xe8];
4476 v2 = bios[0xe9];
4477 v3 = bios[0xea];
Linus Torvalds1da177e2005-04-16 15:20:36 -07004478 }
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004479 outSISIDXREG(SISSR, 0x23, v1);
4480 outSISIDXREG(SISSR, 0x24, v2);
4481 outSISIDXREG(SISSR, 0x25, v3);
4482 outSISIDXREG(SISSR, 0x21, 0x84);
4483 outSISIDXREG(SISSR, 0x22, 0x00);
4484 outSISIDXREG(SISCR, 0x37, 0x00);
4485 orSISIDXREG(SISPART1, 0x24, 0x01); /* unlock crt2 */
4486 outSISIDXREG(SISPART1, 0x00, 0x00);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004487 v1 = 0x40; v2 = 0x11;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004488 if(bios) {
4489 v1 = bios[0xec];
4490 v2 = bios[0xeb];
Linus Torvalds1da177e2005-04-16 15:20:36 -07004491 }
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004492 outSISIDXREG(SISPART1, 0x02, v1);
4493
4494 if(ivideo->revision_id >= 0x80)
4495 v2 &= ~0x01;
4496
4497 inSISIDXREG(SISPART4, 0x00, reg);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004498 if((reg == 1) || (reg == 2)) {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004499 outSISIDXREG(SISCR, 0x37, 0x02);
4500 outSISIDXREG(SISPART2, 0x00, 0x1c);
4501 v4 = 0x00; v5 = 0x00; v6 = 0x10;
4502 if(ivideo->SiS_Pr.UseROM) {
4503 v4 = bios[0xf5];
4504 v5 = bios[0xf6];
4505 v6 = bios[0xf7];
4506 }
4507 outSISIDXREG(SISPART4, 0x0d, v4);
4508 outSISIDXREG(SISPART4, 0x0e, v5);
4509 outSISIDXREG(SISPART4, 0x10, v6);
4510 outSISIDXREG(SISPART4, 0x0f, 0x3f);
4511 inSISIDXREG(SISPART4, 0x01, reg);
4512 if(reg >= 0xb0) {
4513 inSISIDXREG(SISPART4, 0x23, reg);
4514 reg &= 0x20;
4515 reg <<= 1;
4516 outSISIDXREG(SISPART4, 0x23, reg);
4517 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004518 } else {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004519 v2 &= ~0x10;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004520 }
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004521 outSISIDXREG(SISSR, 0x32, v2);
4522
4523 andSISIDXREG(SISPART1, 0x24, 0xfe); /* Lock CRT2 */
4524
4525 inSISIDXREG(SISSR, 0x16, reg);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004526 reg &= 0xc3;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004527 outSISIDXREG(SISCR, 0x35, reg);
4528 outSISIDXREG(SISCR, 0x83, 0x00);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004529#if !defined(__i386__) && !defined(__x86_64__)
4530 if(sisfb_videoram) {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004531 outSISIDXREG(SISSR, 0x13, 0x28); /* ? */
4532 reg = ((sisfb_videoram >> 10) - 1) | 0x40;
4533 outSISIDXREG(SISSR, 0x14, reg);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004534 } else {
4535#endif
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004536 /* Need to map max FB size for finding out about RAM size */
4537 mapsize = 64 << 20;
4538 sisfb_post_map_vram(ivideo, &mapsize, 4);
4539
4540 if(ivideo->video_vbase) {
4541 sisfb_post_300_ramsize(pdev, mapsize);
4542 iounmap(ivideo->video_vbase);
4543 } else {
4544 printk(KERN_DEBUG
4545 "sisfb: Failed to map memory for size detection, assuming 8MB\n");
4546 outSISIDXREG(SISSR, 0x13, 0x28); /* ? */
4547 outSISIDXREG(SISSR, 0x14, 0x47); /* 8MB, 64bit default */
4548 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004549#if !defined(__i386__) && !defined(__x86_64__)
4550 }
4551#endif
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004552 if(bios) {
4553 v1 = bios[0xe6];
4554 v2 = bios[0xe7];
Linus Torvalds1da177e2005-04-16 15:20:36 -07004555 } else {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004556 inSISIDXREG(SISSR, 0x3a, reg);
4557 if((reg & 0x30) == 0x30) {
4558 v1 = 0x04; /* PCI */
4559 v2 = 0x92;
4560 } else {
4561 v1 = 0x14; /* AGP */
4562 v2 = 0xb2;
4563 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004564 }
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004565 outSISIDXREG(SISSR, 0x21, v1);
4566 outSISIDXREG(SISSR, 0x22, v2);
4567
4568 /* Sense CRT1 */
4569 sisfb_sense_crt1(ivideo);
4570
4571 /* Set default mode, don't clear screen */
Richard Knutssonc30660ea2007-02-12 00:55:06 -08004572 ivideo->SiS_Pr.SiS_UseOEM = false;
4573 SiS_SetEnableDstn(&ivideo->SiS_Pr, false);
4574 SiS_SetEnableFstn(&ivideo->SiS_Pr, false);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004575 ivideo->curFSTN = ivideo->curDSTN = 0;
4576 ivideo->SiS_Pr.VideoMemorySize = 8 << 20;
4577 SiSSetMode(&ivideo->SiS_Pr, 0x2e | 0x80);
4578
4579 outSISIDXREG(SISSR, 0x05, 0x86);
4580
4581 /* Display off */
4582 orSISIDXREG(SISSR, 0x01, 0x20);
4583
4584 /* Save mode number in CR34 */
4585 outSISIDXREG(SISCR, 0x34, 0x2e);
4586
4587 /* Let everyone know what the current mode is */
4588 ivideo->modeprechange = 0x2e;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004589}
4590#endif
4591
4592#ifdef CONFIG_FB_SIS_315
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004593#if 0
4594static void __devinit
4595sisfb_post_sis315330(struct pci_dev *pdev)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004596{
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004597 /* TODO */
Linus Torvalds1da177e2005-04-16 15:20:36 -07004598}
4599#endif
4600
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004601static void __devinit
4602sisfb_post_xgi_delay(struct sis_video_info *ivideo, int delay)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004603{
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004604 unsigned int i;
4605 u8 reg;
4606
4607 for(i = 0; i <= (delay * 10 * 36); i++) {
4608 inSISIDXREG(SISSR, 0x05, reg);
4609 reg++;
4610 }
4611}
4612
4613static int __devinit
4614sisfb_find_host_bridge(struct sis_video_info *ivideo, struct pci_dev *mypdev,
4615 unsigned short pcivendor)
4616{
4617 struct pci_dev *pdev = NULL;
4618 unsigned short temp;
4619 int ret = 0;
4620
Adrian Bunk0959f0c2007-05-08 00:39:50 -07004621 while((pdev = pci_get_class(PCI_CLASS_BRIDGE_HOST, pdev))) {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004622 temp = pdev->vendor;
Adrian Bunk0959f0c2007-05-08 00:39:50 -07004623 pci_dev_put(pdev);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004624 if(temp == pcivendor) {
4625 ret = 1;
4626 break;
4627 }
4628 }
4629
4630 return ret;
4631}
4632
4633static int __devinit
4634sisfb_post_xgi_rwtest(struct sis_video_info *ivideo, int starta,
4635 unsigned int enda, unsigned int mapsize)
4636{
4637 unsigned int pos;
4638 int i;
4639
4640 writel(0, ivideo->video_vbase);
4641
4642 for(i = starta; i <= enda; i++) {
4643 pos = 1 << i;
4644 if(pos < mapsize)
4645 writel(pos, ivideo->video_vbase + pos);
4646 }
4647
4648 sisfb_post_xgi_delay(ivideo, 150);
4649
4650 if(readl(ivideo->video_vbase) != 0)
4651 return 0;
4652
4653 for(i = starta; i <= enda; i++) {
4654 pos = 1 << i;
4655 if(pos < mapsize) {
4656 if(readl(ivideo->video_vbase + pos) != pos)
4657 return 0;
4658 } else
4659 return 0;
4660 }
4661
4662 return 1;
4663}
4664
4665static void __devinit
4666sisfb_post_xgi_ramsize(struct sis_video_info *ivideo)
4667{
4668 unsigned int buswidth, ranksize, channelab, mapsize;
4669 int i, j, k, l;
4670 u8 reg, sr14;
4671 static const u8 dramsr13[12 * 5] = {
4672 0x02, 0x0e, 0x0b, 0x80, 0x5d,
4673 0x02, 0x0e, 0x0a, 0x40, 0x59,
4674 0x02, 0x0d, 0x0b, 0x40, 0x4d,
4675 0x02, 0x0e, 0x09, 0x20, 0x55,
4676 0x02, 0x0d, 0x0a, 0x20, 0x49,
4677 0x02, 0x0c, 0x0b, 0x20, 0x3d,
4678 0x02, 0x0e, 0x08, 0x10, 0x51,
4679 0x02, 0x0d, 0x09, 0x10, 0x45,
4680 0x02, 0x0c, 0x0a, 0x10, 0x39,
4681 0x02, 0x0d, 0x08, 0x08, 0x41,
4682 0x02, 0x0c, 0x09, 0x08, 0x35,
4683 0x02, 0x0c, 0x08, 0x04, 0x31
4684 };
4685 static const u8 dramsr13_4[4 * 5] = {
4686 0x02, 0x0d, 0x09, 0x40, 0x45,
4687 0x02, 0x0c, 0x09, 0x20, 0x35,
4688 0x02, 0x0c, 0x08, 0x10, 0x31,
4689 0x02, 0x0b, 0x08, 0x08, 0x21
4690 };
4691
4692 /* Enable linear mode, disable 0xa0000 address decoding */
4693 /* We disable a0000 address decoding, because
4694 * - if running on x86, if the card is disabled, it means
4695 * that another card is in the system. We don't want
4696 * to interphere with that primary card's textmode.
4697 * - if running on non-x86, there usually is no VGA window
4698 * at a0000.
4699 */
4700 orSISIDXREG(SISSR, 0x20, (0x80 | 0x04));
4701
4702 /* Need to map max FB size for finding out about RAM size */
4703 mapsize = 256 << 20;
4704 sisfb_post_map_vram(ivideo, &mapsize, 32);
4705
4706 if(!ivideo->video_vbase) {
4707 printk(KERN_ERR "sisfb: Unable to detect RAM size. Setting default.\n");
4708 outSISIDXREG(SISSR, 0x13, 0x35);
4709 outSISIDXREG(SISSR, 0x14, 0x41);
4710 /* TODO */
4711 return;
4712 }
4713
4714 /* Non-interleaving */
4715 outSISIDXREG(SISSR, 0x15, 0x00);
4716 /* No tiling */
4717 outSISIDXREG(SISSR, 0x1c, 0x00);
4718
4719 if(ivideo->chip == XGI_20) {
4720
4721 channelab = 1;
4722 inSISIDXREG(SISCR, 0x97, reg);
4723 if(!(reg & 0x01)) { /* Single 32/16 */
4724 buswidth = 32;
4725 outSISIDXREG(SISSR, 0x13, 0xb1);
4726 outSISIDXREG(SISSR, 0x14, 0x52);
4727 sisfb_post_xgi_delay(ivideo, 1);
4728 sr14 = 0x02;
4729 if(sisfb_post_xgi_rwtest(ivideo, 23, 24, mapsize))
4730 goto bail_out;
4731
4732 outSISIDXREG(SISSR, 0x13, 0x31);
4733 outSISIDXREG(SISSR, 0x14, 0x42);
4734 sisfb_post_xgi_delay(ivideo, 1);
4735 if(sisfb_post_xgi_rwtest(ivideo, 23, 23, mapsize))
4736 goto bail_out;
4737
4738 buswidth = 16;
4739 outSISIDXREG(SISSR, 0x13, 0xb1);
4740 outSISIDXREG(SISSR, 0x14, 0x41);
4741 sisfb_post_xgi_delay(ivideo, 1);
4742 sr14 = 0x01;
4743 if(sisfb_post_xgi_rwtest(ivideo, 22, 23, mapsize))
4744 goto bail_out;
4745 else
4746 outSISIDXREG(SISSR, 0x13, 0x31);
4747 } else { /* Dual 16/8 */
4748 buswidth = 16;
4749 outSISIDXREG(SISSR, 0x13, 0xb1);
4750 outSISIDXREG(SISSR, 0x14, 0x41);
4751 sisfb_post_xgi_delay(ivideo, 1);
4752 sr14 = 0x01;
4753 if(sisfb_post_xgi_rwtest(ivideo, 22, 23, mapsize))
4754 goto bail_out;
4755
4756 outSISIDXREG(SISSR, 0x13, 0x31);
4757 outSISIDXREG(SISSR, 0x14, 0x31);
4758 sisfb_post_xgi_delay(ivideo, 1);
4759 if(sisfb_post_xgi_rwtest(ivideo, 22, 22, mapsize))
4760 goto bail_out;
4761
4762 buswidth = 8;
4763 outSISIDXREG(SISSR, 0x13, 0xb1);
4764 outSISIDXREG(SISSR, 0x14, 0x30);
4765 sisfb_post_xgi_delay(ivideo, 1);
4766 sr14 = 0x00;
4767 if(sisfb_post_xgi_rwtest(ivideo, 21, 22, mapsize))
4768 goto bail_out;
4769 else
4770 outSISIDXREG(SISSR, 0x13, 0x31);
4771 }
4772
4773 } else { /* XGI_40 */
4774
4775 inSISIDXREG(SISCR, 0x97, reg);
4776 if(!(reg & 0x10)) {
4777 inSISIDXREG(SISSR, 0x39, reg);
4778 reg >>= 1;
4779 }
4780
4781 if(reg & 0x01) { /* DDRII */
4782 buswidth = 32;
4783 if(ivideo->revision_id == 2) {
4784 channelab = 2;
4785 outSISIDXREG(SISSR, 0x13, 0xa1);
4786 outSISIDXREG(SISSR, 0x14, 0x44);
4787 sr14 = 0x04;
4788 sisfb_post_xgi_delay(ivideo, 1);
4789 if(sisfb_post_xgi_rwtest(ivideo, 23, 24, mapsize))
4790 goto bail_out;
4791
4792 outSISIDXREG(SISSR, 0x13, 0x21);
4793 outSISIDXREG(SISSR, 0x14, 0x34);
4794 if(sisfb_post_xgi_rwtest(ivideo, 22, 23, mapsize))
4795 goto bail_out;
4796
4797 channelab = 1;
4798 outSISIDXREG(SISSR, 0x13, 0xa1);
4799 outSISIDXREG(SISSR, 0x14, 0x40);
4800 sr14 = 0x00;
4801 if(sisfb_post_xgi_rwtest(ivideo, 22, 23, mapsize))
4802 goto bail_out;
4803
4804 outSISIDXREG(SISSR, 0x13, 0x21);
4805 outSISIDXREG(SISSR, 0x14, 0x30);
4806 } else {
4807 channelab = 3;
4808 outSISIDXREG(SISSR, 0x13, 0xa1);
4809 outSISIDXREG(SISSR, 0x14, 0x4c);
4810 sr14 = 0x0c;
4811 sisfb_post_xgi_delay(ivideo, 1);
4812 if(sisfb_post_xgi_rwtest(ivideo, 23, 25, mapsize))
4813 goto bail_out;
4814
4815 channelab = 2;
4816 outSISIDXREG(SISSR, 0x14, 0x48);
4817 sisfb_post_xgi_delay(ivideo, 1);
4818 sr14 = 0x08;
4819 if(sisfb_post_xgi_rwtest(ivideo, 23, 24, mapsize))
4820 goto bail_out;
4821
4822 outSISIDXREG(SISSR, 0x13, 0x21);
4823 outSISIDXREG(SISSR, 0x14, 0x3c);
4824 sr14 = 0x0c;
4825
4826 if(sisfb_post_xgi_rwtest(ivideo, 23, 24, mapsize)) {
4827 channelab = 3;
4828 } else {
4829 channelab = 2;
4830 outSISIDXREG(SISSR, 0x14, 0x38);
4831 sr14 = 0x08;
4832 }
4833 }
4834 sisfb_post_xgi_delay(ivideo, 1);
4835
4836 } else { /* DDR */
4837
4838 buswidth = 64;
4839 if(ivideo->revision_id == 2) {
4840 channelab = 1;
4841 outSISIDXREG(SISSR, 0x13, 0xa1);
4842 outSISIDXREG(SISSR, 0x14, 0x52);
4843 sisfb_post_xgi_delay(ivideo, 1);
4844 sr14 = 0x02;
4845 if(sisfb_post_xgi_rwtest(ivideo, 23, 24, mapsize))
4846 goto bail_out;
4847
4848 outSISIDXREG(SISSR, 0x13, 0x21);
4849 outSISIDXREG(SISSR, 0x14, 0x42);
4850 } else {
4851 channelab = 2;
4852 outSISIDXREG(SISSR, 0x13, 0xa1);
4853 outSISIDXREG(SISSR, 0x14, 0x5a);
4854 sisfb_post_xgi_delay(ivideo, 1);
4855 sr14 = 0x0a;
4856 if(sisfb_post_xgi_rwtest(ivideo, 24, 25, mapsize))
4857 goto bail_out;
4858
4859 outSISIDXREG(SISSR, 0x13, 0x21);
4860 outSISIDXREG(SISSR, 0x14, 0x4a);
4861 }
4862 sisfb_post_xgi_delay(ivideo, 1);
4863
4864 }
4865 }
4866
4867bail_out:
4868 setSISIDXREG(SISSR, 0x14, 0xf0, sr14);
4869 sisfb_post_xgi_delay(ivideo, 1);
4870
4871 j = (ivideo->chip == XGI_20) ? 5 : 9;
4872 k = (ivideo->chip == XGI_20) ? 12 : 4;
4873
4874 for(i = 0; i < k; i++) {
4875
4876 reg = (ivideo->chip == XGI_20) ?
4877 dramsr13[(i * 5) + 4] : dramsr13_4[(i * 5) + 4];
4878 setSISIDXREG(SISSR, 0x13, 0x80, reg);
4879 sisfb_post_xgi_delay(ivideo, 50);
4880
4881 ranksize = (ivideo->chip == XGI_20) ?
4882 dramsr13[(i * 5) + 3] : dramsr13_4[(i * 5) + 3];
4883
4884 inSISIDXREG(SISSR, 0x13, reg);
4885 if(reg & 0x80) ranksize <<= 1;
4886
4887 if(ivideo->chip == XGI_20) {
4888 if(buswidth == 16) ranksize <<= 1;
4889 else if(buswidth == 32) ranksize <<= 2;
4890 } else {
4891 if(buswidth == 64) ranksize <<= 1;
4892 }
4893
4894 reg = 0;
4895 l = channelab;
4896 if(l == 3) l = 4;
4897 if((ranksize * l) <= 256) {
4898 while((ranksize >>= 1)) reg += 0x10;
4899 }
4900
4901 if(!reg) continue;
4902
4903 setSISIDXREG(SISSR, 0x14, 0x0f, (reg & 0xf0));
4904 sisfb_post_xgi_delay(ivideo, 1);
4905
4906 if(sisfb_post_xgi_rwtest(ivideo, j, ((reg >> 4) + channelab - 2 + 20), mapsize))
4907 break;
4908 }
4909
4910 iounmap(ivideo->video_vbase);
4911}
4912
4913static void __devinit
4914sisfb_post_xgi_setclocks(struct sis_video_info *ivideo, u8 regb)
4915{
4916 u8 v1, v2, v3;
4917 int index;
4918 static const u8 cs90[8 * 3] = {
4919 0x16, 0x01, 0x01,
4920 0x3e, 0x03, 0x01,
4921 0x7c, 0x08, 0x01,
4922 0x79, 0x06, 0x01,
4923 0x29, 0x01, 0x81,
4924 0x5c, 0x23, 0x01,
4925 0x5c, 0x23, 0x01,
4926 0x5c, 0x23, 0x01
4927 };
4928 static const u8 csb8[8 * 3] = {
4929 0x5c, 0x23, 0x01,
4930 0x29, 0x01, 0x01,
4931 0x7c, 0x08, 0x01,
4932 0x79, 0x06, 0x01,
4933 0x29, 0x01, 0x81,
4934 0x5c, 0x23, 0x01,
4935 0x5c, 0x23, 0x01,
4936 0x5c, 0x23, 0x01
4937 };
4938
4939 regb = 0; /* ! */
4940
4941 index = regb * 3;
4942 v1 = cs90[index]; v2 = cs90[index + 1]; v3 = cs90[index + 2];
4943 if(ivideo->haveXGIROM) {
4944 v1 = ivideo->bios_abase[0x90 + index];
4945 v2 = ivideo->bios_abase[0x90 + index + 1];
4946 v3 = ivideo->bios_abase[0x90 + index + 2];
4947 }
4948 outSISIDXREG(SISSR, 0x28, v1);
4949 outSISIDXREG(SISSR, 0x29, v2);
4950 outSISIDXREG(SISSR, 0x2a, v3);
4951 sisfb_post_xgi_delay(ivideo, 0x43);
4952 sisfb_post_xgi_delay(ivideo, 0x43);
4953 sisfb_post_xgi_delay(ivideo, 0x43);
4954 index = regb * 3;
4955 v1 = csb8[index]; v2 = csb8[index + 1]; v3 = csb8[index + 2];
4956 if(ivideo->haveXGIROM) {
4957 v1 = ivideo->bios_abase[0xb8 + index];
4958 v2 = ivideo->bios_abase[0xb8 + index + 1];
4959 v3 = ivideo->bios_abase[0xb8 + index + 2];
4960 }
4961 outSISIDXREG(SISSR, 0x2e, v1);
4962 outSISIDXREG(SISSR, 0x2f, v2);
4963 outSISIDXREG(SISSR, 0x30, v3);
4964 sisfb_post_xgi_delay(ivideo, 0x43);
4965 sisfb_post_xgi_delay(ivideo, 0x43);
4966 sisfb_post_xgi_delay(ivideo, 0x43);
4967}
4968
4969static int __devinit
4970sisfb_post_xgi(struct pci_dev *pdev)
4971{
4972 struct sis_video_info *ivideo = pci_get_drvdata(pdev);
4973 unsigned char *bios = ivideo->bios_abase;
4974 struct pci_dev *mypdev = NULL;
4975 const u8 *ptr, *ptr2;
4976 u8 v1, v2, v3, v4, v5, reg, ramtype;
4977 u32 rega, regb, regd;
4978 int i, j, k, index;
4979 static const u8 cs78[3] = { 0xf6, 0x0d, 0x00 };
4980 static const u8 cs76[2] = { 0xa3, 0xfb };
4981 static const u8 cs7b[3] = { 0xc0, 0x11, 0x00 };
4982 static const u8 cs158[8] = {
4983 0x88, 0xaa, 0x48, 0x00, 0x00, 0x00, 0x00, 0x00
4984 };
4985 static const u8 cs160[8] = {
4986 0x44, 0x77, 0x77, 0x00, 0x00, 0x00, 0x00, 0x00
4987 };
4988 static const u8 cs168[8] = {
4989 0x48, 0x78, 0x88, 0x00, 0x00, 0x00, 0x00, 0x00
4990 };
4991 static const u8 cs128[3 * 8] = {
4992 0x90, 0x28, 0x24, 0x00, 0x00, 0x00, 0x00, 0x00,
4993 0x77, 0x44, 0x44, 0x00, 0x00, 0x00, 0x00, 0x00,
4994 0x77, 0x44, 0x44, 0x00, 0x00, 0x00, 0x00, 0x00
4995 };
4996 static const u8 cs148[2 * 8] = {
4997 0x55, 0x55, 0x55, 0x00, 0x00, 0x00, 0x00, 0x00,
4998 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
4999 };
5000 static const u8 cs31a[8 * 4] = {
5001 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
5002 0xaa, 0xaa, 0xaa, 0xaa, 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 cs33a[8 * 4] = {
5007 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
5008 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
5009 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
5010 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
5011 };
5012 static const u8 cs45a[8 * 2] = {
5013 0x00, 0x00, 0xa0, 0x00, 0xa0, 0x00, 0x00, 0x00,
5014 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
5015 };
5016 static const u8 cs170[7 * 8] = {
5017 0x54, 0x32, 0x44, 0x00, 0x00, 0x00, 0x00, 0x00,
5018 0x54, 0x43, 0x44, 0x00, 0x00, 0x00, 0x00, 0x00,
5019 0x0a, 0x05, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00,
5020 0x44, 0x34, 0x44, 0x00, 0x00, 0x00, 0x00, 0x00,
5021 0x10, 0x0a, 0x0a, 0x00, 0x00, 0x00, 0x00, 0x00,
5022 0x11, 0x0c, 0x0c, 0x00, 0x00, 0x00, 0x00, 0x00,
5023 0x05, 0x05, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00
5024 };
5025 static const u8 cs1a8[3 * 8] = {
5026 0xf0, 0xf0, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x00,
5027 0x05, 0x02, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00,
5028 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
5029 };
5030 static const u8 cs100[2 * 8] = {
5031 0xc4, 0x04, 0x84, 0x00, 0x00, 0x00, 0x00, 0x00,
5032 0xc4, 0x04, 0x84, 0x00, 0x00, 0x00, 0x00, 0x00
5033 };
5034
5035 /* VGA enable */
5036 reg = inSISREG(SISVGAENABLE) | 0x01;
5037 outSISREG(SISVGAENABLE, reg);
5038
5039 /* Misc */
5040 reg = inSISREG(SISMISCR) | 0x01;
5041 outSISREG(SISMISCW, reg);
5042
5043 /* Unlock SR */
5044 outSISIDXREG(SISSR, 0x05, 0x86);
5045 inSISIDXREG(SISSR, 0x05, reg);
5046 if(reg != 0xa1)
5047 return 0;
5048
5049 /* Clear some regs */
5050 for(i = 0; i < 0x22; i++) {
5051 if(0x06 + i == 0x20) continue;
5052 outSISIDXREG(SISSR, 0x06 + i, 0x00);
5053 }
5054 for(i = 0; i < 0x0b; i++) {
5055 outSISIDXREG(SISSR, 0x31 + i, 0x00);
5056 }
5057 for(i = 0; i < 0x10; i++) {
5058 outSISIDXREG(SISCR, 0x30 + i, 0x00);
5059 }
5060
5061 ptr = cs78;
5062 if(ivideo->haveXGIROM) {
5063 ptr = (const u8 *)&bios[0x78];
5064 }
5065 for(i = 0; i < 3; i++) {
5066 outSISIDXREG(SISSR, 0x23 + i, ptr[i]);
5067 }
5068
5069 ptr = cs76;
5070 if(ivideo->haveXGIROM) {
5071 ptr = (const u8 *)&bios[0x76];
5072 }
5073 for(i = 0; i < 2; i++) {
5074 outSISIDXREG(SISSR, 0x21 + i, ptr[i]);
5075 }
5076
5077 v1 = 0x18; v2 = 0x00;
5078 if(ivideo->haveXGIROM) {
5079 v1 = bios[0x74];
5080 v2 = bios[0x75];
5081 }
5082 outSISIDXREG(SISSR, 0x07, v1);
5083 outSISIDXREG(SISSR, 0x11, 0x0f);
5084 outSISIDXREG(SISSR, 0x1f, v2);
5085 /* PCI linear mode, RelIO enabled, A0000 decoding disabled */
5086 outSISIDXREG(SISSR, 0x20, 0x80 | 0x20 | 0x04);
5087 outSISIDXREG(SISSR, 0x27, 0x74);
5088
5089 ptr = cs7b;
5090 if(ivideo->haveXGIROM) {
5091 ptr = (const u8 *)&bios[0x7b];
5092 }
5093 for(i = 0; i < 3; i++) {
5094 outSISIDXREG(SISSR, 0x31 + i, ptr[i]);
5095 }
5096
5097 if(ivideo->chip == XGI_40) {
5098 if(ivideo->revision_id == 2) {
5099 setSISIDXREG(SISSR, 0x3b, 0x3f, 0xc0);
5100 }
5101 outSISIDXREG(SISCR, 0x7d, 0xfe);
5102 outSISIDXREG(SISCR, 0x7e, 0x0f);
5103 }
5104 if(ivideo->revision_id == 0) { /* 40 *and* 20? */
5105 andSISIDXREG(SISCR, 0x58, 0xd7);
5106 inSISIDXREG(SISCR, 0xcb, reg);
5107 if(reg & 0x20) {
5108 setSISIDXREG(SISCR, 0x58, 0xd7, (reg & 0x10) ? 0x08 : 0x20); /* =0x28 Z7 ? */
5109 }
5110 }
5111
5112 reg = (ivideo->chip == XGI_40) ? 0x20 : 0x00;
5113 setSISIDXREG(SISCR, 0x38, 0x1f, reg);
5114
5115 if(ivideo->chip == XGI_20) {
5116 outSISIDXREG(SISSR, 0x36, 0x70);
5117 } else {
5118 outSISIDXREG(SISVID, 0x00, 0x86);
5119 outSISIDXREG(SISVID, 0x32, 0x00);
5120 outSISIDXREG(SISVID, 0x30, 0x00);
5121 outSISIDXREG(SISVID, 0x32, 0x01);
5122 outSISIDXREG(SISVID, 0x30, 0x00);
5123 andSISIDXREG(SISVID, 0x2f, 0xdf);
5124 andSISIDXREG(SISCAP, 0x00, 0x3f);
5125
5126 outSISIDXREG(SISPART1, 0x2f, 0x01);
5127 outSISIDXREG(SISPART1, 0x00, 0x00);
5128 outSISIDXREG(SISPART1, 0x02, bios[0x7e]);
5129 outSISIDXREG(SISPART1, 0x2e, 0x08);
5130 andSISIDXREG(SISPART1, 0x35, 0x7f);
5131 andSISIDXREG(SISPART1, 0x50, 0xfe);
5132
5133 inSISIDXREG(SISPART4, 0x00, reg);
5134 if(reg == 1 || reg == 2) {
5135 outSISIDXREG(SISPART2, 0x00, 0x1c);
5136 outSISIDXREG(SISPART4, 0x0d, bios[0x7f]);
5137 outSISIDXREG(SISPART4, 0x0e, bios[0x80]);
5138 outSISIDXREG(SISPART4, 0x10, bios[0x81]);
5139 andSISIDXREG(SISPART4, 0x0f, 0x3f);
5140
5141 inSISIDXREG(SISPART4, 0x01, reg);
5142 if((reg & 0xf0) >= 0xb0) {
5143 inSISIDXREG(SISPART4, 0x23, reg);
5144 if(reg & 0x20) reg |= 0x40;
5145 outSISIDXREG(SISPART4, 0x23, reg);
5146 reg = (reg & 0x20) ? 0x02 : 0x00;
5147 setSISIDXREG(SISPART1, 0x1e, 0xfd, reg);
5148 }
5149 }
5150
5151 v1 = bios[0x77];
5152
5153 inSISIDXREG(SISSR, 0x3b, reg);
5154 if(reg & 0x02) {
5155 inSISIDXREG(SISSR, 0x3a, reg);
5156 v2 = (reg & 0x30) >> 3;
5157 if(!(v2 & 0x04)) v2 ^= 0x02;
5158 inSISIDXREG(SISSR, 0x39, reg);
5159 if(reg & 0x80) v2 |= 0x80;
5160 v2 |= 0x01;
5161
Adrian Bunk0959f0c2007-05-08 00:39:50 -07005162 if((mypdev = pci_get_device(PCI_VENDOR_ID_SI, 0x0730, NULL))) {
5163 pci_dev_put(mypdev);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07005164 if(((v2 & 0x06) == 2) || ((v2 & 0x06) == 4))
5165 v2 &= 0xf9;
5166 v2 |= 0x08;
5167 v1 &= 0xfe;
5168 } else {
Adrian Bunk0959f0c2007-05-08 00:39:50 -07005169 mypdev = pci_get_device(PCI_VENDOR_ID_SI, 0x0735, NULL);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07005170 if(!mypdev)
Adrian Bunk0959f0c2007-05-08 00:39:50 -07005171 mypdev = pci_get_device(PCI_VENDOR_ID_SI, 0x0645, NULL);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07005172 if(!mypdev)
Adrian Bunk0959f0c2007-05-08 00:39:50 -07005173 mypdev = pci_get_device(PCI_VENDOR_ID_SI, 0x0650, NULL);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07005174 if(mypdev) {
5175 pci_read_config_dword(mypdev, 0x94, &regd);
5176 regd &= 0xfffffeff;
5177 pci_write_config_dword(mypdev, 0x94, regd);
5178 v1 &= 0xfe;
Adrian Bunk0959f0c2007-05-08 00:39:50 -07005179 pci_dev_put(mypdev);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07005180 } else if(sisfb_find_host_bridge(ivideo, pdev, PCI_VENDOR_ID_SI)) {
5181 v1 &= 0xfe;
5182 } else if(sisfb_find_host_bridge(ivideo, pdev, 0x1106) ||
5183 sisfb_find_host_bridge(ivideo, pdev, 0x1022) ||
5184 sisfb_find_host_bridge(ivideo, pdev, 0x700e) ||
5185 sisfb_find_host_bridge(ivideo, pdev, 0x10de)) {
5186 if((v2 & 0x06) == 4)
5187 v2 ^= 0x06;
5188 v2 |= 0x08;
5189 }
5190 }
5191 setSISIDXREG(SISCR, 0x5f, 0xf0, v2);
5192 }
5193 outSISIDXREG(SISSR, 0x22, v1);
5194
5195 if(ivideo->revision_id == 2) {
5196 inSISIDXREG(SISSR, 0x3b, v1);
5197 inSISIDXREG(SISSR, 0x3a, v2);
5198 regd = bios[0x90 + 3] | (bios[0x90 + 4] << 8);
5199 if( (!(v1 & 0x02)) && (v2 & 0x30) && (regd < 0xcf) )
5200 setSISIDXREG(SISCR, 0x5f, 0xf1, 0x01);
5201
Adrian Bunk0959f0c2007-05-08 00:39:50 -07005202 if((mypdev = pci_get_device(0x10de, 0x01e0, NULL))) {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07005203 /* TODO: set CR5f &0xf1 | 0x01 for version 6570
5204 * of nforce 2 ROM
5205 */
5206 if(0)
5207 setSISIDXREG(SISCR, 0x5f, 0xf1, 0x01);
Adrian Bunk0959f0c2007-05-08 00:39:50 -07005208 pci_dev_put(mypdev);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07005209 }
5210 }
5211
5212 v1 = 0x30;
5213 inSISIDXREG(SISSR, 0x3b, reg);
5214 inSISIDXREG(SISCR, 0x5f, v2);
5215 if((!(reg & 0x02)) && (v2 & 0x0e))
5216 v1 |= 0x08;
5217 outSISIDXREG(SISSR, 0x27, v1);
5218
5219 if(bios[0x64] & 0x01) {
5220 setSISIDXREG(SISCR, 0x5f, 0xf0, bios[0x64]);
5221 }
5222
5223 v1 = bios[0x4f7];
5224 pci_read_config_dword(pdev, 0x50, &regd);
5225 regd = (regd >> 20) & 0x0f;
5226 if(regd == 1) {
5227 v1 &= 0xfc;
5228 orSISIDXREG(SISCR, 0x5f, 0x08);
5229 }
5230 outSISIDXREG(SISCR, 0x48, v1);
5231
5232 setSISIDXREG(SISCR, 0x47, 0x04, bios[0x4f6] & 0xfb);
5233 setSISIDXREG(SISCR, 0x49, 0xf0, bios[0x4f8] & 0x0f);
5234 setSISIDXREG(SISCR, 0x4a, 0x60, bios[0x4f9] & 0x9f);
5235 setSISIDXREG(SISCR, 0x4b, 0x08, bios[0x4fa] & 0xf7);
5236 setSISIDXREG(SISCR, 0x4c, 0x80, bios[0x4fb] & 0x7f);
5237 outSISIDXREG(SISCR, 0x70, bios[0x4fc]);
5238 setSISIDXREG(SISCR, 0x71, 0xf0, bios[0x4fd] & 0x0f);
5239 outSISIDXREG(SISCR, 0x74, 0xd0);
5240 setSISIDXREG(SISCR, 0x74, 0xcf, bios[0x4fe] & 0x30);
5241 setSISIDXREG(SISCR, 0x75, 0xe0, bios[0x4ff] & 0x1f);
5242 setSISIDXREG(SISCR, 0x76, 0xe0, bios[0x500] & 0x1f);
5243 v1 = bios[0x501];
Adrian Bunk0959f0c2007-05-08 00:39:50 -07005244 if((mypdev = pci_get_device(0x8086, 0x2530, NULL))) {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07005245 v1 = 0xf0;
Adrian Bunk0959f0c2007-05-08 00:39:50 -07005246 pci_dev_put(mypdev);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07005247 }
5248 outSISIDXREG(SISCR, 0x77, v1);
5249 }
5250
5251 /* RAM type */
5252
5253 regb = 0; /* ! */
5254
5255 v1 = 0xff;
5256 if(ivideo->haveXGIROM) {
5257 v1 = bios[0x140 + regb];
5258 }
5259 outSISIDXREG(SISCR, 0x6d, v1);
5260
5261 ptr = cs128;
5262 if(ivideo->haveXGIROM) {
5263 ptr = (const u8 *)&bios[0x128];
5264 }
5265 for(i = 0, j = 0; i < 3; i++, j += 8) {
5266 outSISIDXREG(SISCR, 0x68 + i, ptr[j + regb]);
5267 }
5268
5269 ptr = cs31a;
5270 ptr2 = cs33a;
5271 if(ivideo->haveXGIROM) {
5272 index = (ivideo->chip == XGI_20) ? 0x31a : 0x3a6;
5273 ptr = (const u8 *)&bios[index];
5274 ptr2 = (const u8 *)&bios[index + 0x20];
5275 }
5276 for(i = 0; i < 2; i++) {
5277 if(i == 0) {
5278 regd = le32_to_cpu(((u32 *)ptr)[regb]);
5279 rega = 0x6b;
5280 } else {
5281 regd = le32_to_cpu(((u32 *)ptr2)[regb]);
5282 rega = 0x6e;
5283 }
5284 reg = 0x00;
5285 for(j = 0; j < 16; j++) {
5286 reg &= 0xf3;
5287 if(regd & 0x01) reg |= 0x04;
5288 if(regd & 0x02) reg |= 0x08;
5289 regd >>= 2;
5290 outSISIDXREG(SISCR, rega, reg);
5291 inSISIDXREG(SISCR, rega, reg);
5292 inSISIDXREG(SISCR, rega, reg);
5293 reg += 0x10;
5294 }
5295 }
5296
5297 andSISIDXREG(SISCR, 0x6e, 0xfc);
5298
5299 ptr = NULL;
5300 if(ivideo->haveXGIROM) {
5301 index = (ivideo->chip == XGI_20) ? 0x35a : 0x3e6;
5302 ptr = (const u8 *)&bios[index];
5303 }
5304 for(i = 0; i < 4; i++) {
5305 setSISIDXREG(SISCR, 0x6e, 0xfc, i);
5306 reg = 0x00;
5307 for(j = 0; j < 2; j++) {
5308 regd = 0;
5309 if(ptr) {
5310 regd = le32_to_cpu(((u32 *)ptr)[regb * 8]);
5311 ptr += 4;
5312 }
5313 /* reg = 0x00; */
5314 for(k = 0; k < 16; k++) {
5315 reg &= 0xfc;
5316 if(regd & 0x01) reg |= 0x01;
5317 if(regd & 0x02) reg |= 0x02;
5318 regd >>= 2;
5319 outSISIDXREG(SISCR, 0x6f, reg);
5320 inSISIDXREG(SISCR, 0x6f, reg);
5321 inSISIDXREG(SISCR, 0x6f, reg);
5322 reg += 0x08;
5323 }
5324 }
5325 }
5326
5327 ptr = cs148;
5328 if(ivideo->haveXGIROM) {
5329 ptr = (const u8 *)&bios[0x148];
5330 }
5331 for(i = 0, j = 0; i < 2; i++, j += 8) {
5332 outSISIDXREG(SISCR, 0x80 + i, ptr[j + regb]);
5333 }
5334
5335 andSISIDXREG(SISCR, 0x89, 0x8f);
5336
5337 ptr = cs45a;
5338 if(ivideo->haveXGIROM) {
5339 index = (ivideo->chip == XGI_20) ? 0x45a : 0x4e6;
5340 ptr = (const u8 *)&bios[index];
5341 }
5342 regd = le16_to_cpu(((const u16 *)ptr)[regb]);
5343 reg = 0x80;
5344 for(i = 0; i < 5; i++) {
5345 reg &= 0xfc;
5346 if(regd & 0x01) reg |= 0x01;
5347 if(regd & 0x02) reg |= 0x02;
5348 regd >>= 2;
5349 outSISIDXREG(SISCR, 0x89, reg);
5350 inSISIDXREG(SISCR, 0x89, reg);
5351 inSISIDXREG(SISCR, 0x89, reg);
5352 reg += 0x10;
5353 }
5354
5355 v1 = 0xb5; v2 = 0x20; v3 = 0xf0; v4 = 0x13;
5356 if(ivideo->haveXGIROM) {
5357 v1 = bios[0x118 + regb];
5358 v2 = bios[0xf8 + regb];
5359 v3 = bios[0x120 + regb];
5360 v4 = bios[0x1ca];
5361 }
5362 outSISIDXREG(SISCR, 0x45, v1 & 0x0f);
5363 outSISIDXREG(SISCR, 0x99, (v1 >> 4) & 0x07);
5364 orSISIDXREG(SISCR, 0x40, v1 & 0x80);
5365 outSISIDXREG(SISCR, 0x41, v2);
5366
5367 ptr = cs170;
5368 if(ivideo->haveXGIROM) {
5369 ptr = (const u8 *)&bios[0x170];
5370 }
5371 for(i = 0, j = 0; i < 7; i++, j += 8) {
5372 outSISIDXREG(SISCR, 0x90 + i, ptr[j + regb]);
5373 }
5374
5375 outSISIDXREG(SISCR, 0x59, v3);
5376
5377 ptr = cs1a8;
5378 if(ivideo->haveXGIROM) {
5379 ptr = (const u8 *)&bios[0x1a8];
5380 }
5381 for(i = 0, j = 0; i < 3; i++, j += 8) {
5382 outSISIDXREG(SISCR, 0xc3 + i, ptr[j + regb]);
5383 }
5384
5385 ptr = cs100;
5386 if(ivideo->haveXGIROM) {
5387 ptr = (const u8 *)&bios[0x100];
5388 }
5389 for(i = 0, j = 0; i < 2; i++, j += 8) {
5390 outSISIDXREG(SISCR, 0x8a + i, ptr[j + regb]);
5391 }
5392
5393 outSISIDXREG(SISCR, 0xcf, v4);
5394
5395 outSISIDXREG(SISCR, 0x83, 0x09);
5396 outSISIDXREG(SISCR, 0x87, 0x00);
5397
5398 if(ivideo->chip == XGI_40) {
5399 if( (ivideo->revision_id == 1) ||
5400 (ivideo->revision_id == 2) ) {
5401 outSISIDXREG(SISCR, 0x8c, 0x87);
5402 }
5403 }
5404
5405 outSISIDXREG(SISSR, 0x17, 0x00);
5406 outSISIDXREG(SISSR, 0x1a, 0x87);
5407
5408 if(ivideo->chip == XGI_20) {
5409 outSISIDXREG(SISSR, 0x15, 0x00);
5410 outSISIDXREG(SISSR, 0x1c, 0x00);
5411 }
5412
5413 ramtype = 0x00; v1 = 0x10;
5414 if(ivideo->haveXGIROM) {
5415 ramtype = bios[0x62];
5416 v1 = bios[0x1d2];
5417 }
5418 if(!(ramtype & 0x80)) {
5419 if(ivideo->chip == XGI_20) {
5420 outSISIDXREG(SISCR, 0x97, v1);
5421 inSISIDXREG(SISCR, 0x97, reg);
5422 if(reg & 0x10) {
5423 ramtype = (reg & 0x01) << 1;
5424 }
5425 } else {
5426 inSISIDXREG(SISSR, 0x39, reg);
5427 ramtype = reg & 0x02;
5428 if(!(ramtype)) {
5429 inSISIDXREG(SISSR, 0x3a, reg);
5430 ramtype = (reg >> 1) & 0x01;
5431 }
5432 }
5433 }
5434 ramtype &= 0x07;
5435
5436 regb = 0; /* ! */
5437
5438 switch(ramtype) {
5439 case 0:
5440 sisfb_post_xgi_setclocks(ivideo, regb);
5441 if((ivideo->chip == XGI_20) ||
5442 (ivideo->revision_id == 1) ||
5443 (ivideo->revision_id == 2)) {
5444 v1 = cs158[regb]; v2 = cs160[regb]; v3 = cs168[regb];
5445 if(ivideo->haveXGIROM) {
5446 v1 = bios[regb + 0x158];
5447 v2 = bios[regb + 0x160];
5448 v3 = bios[regb + 0x168];
5449 }
5450 outSISIDXREG(SISCR, 0x82, v1);
5451 outSISIDXREG(SISCR, 0x85, v2);
5452 outSISIDXREG(SISCR, 0x86, v3);
5453 } else {
5454 outSISIDXREG(SISCR, 0x82, 0x88);
5455 outSISIDXREG(SISCR, 0x86, 0x00);
5456 inSISIDXREG(SISCR, 0x86, reg);
5457 outSISIDXREG(SISCR, 0x86, 0x88);
5458 inSISIDXREG(SISCR, 0x86, reg);
5459 outSISIDXREG(SISCR, 0x86, bios[regb + 0x168]);
5460 outSISIDXREG(SISCR, 0x82, 0x77);
5461 outSISIDXREG(SISCR, 0x85, 0x00);
5462 inSISIDXREG(SISCR, 0x85, reg);
5463 outSISIDXREG(SISCR, 0x85, 0x88);
5464 inSISIDXREG(SISCR, 0x85, reg);
5465 outSISIDXREG(SISCR, 0x85, bios[regb + 0x160]);
5466 outSISIDXREG(SISCR, 0x82, bios[regb + 0x158]);
5467 }
5468 if(ivideo->chip == XGI_40) {
5469 outSISIDXREG(SISCR, 0x97, 0x00);
5470 }
5471 outSISIDXREG(SISCR, 0x98, 0x01);
5472 outSISIDXREG(SISCR, 0x9a, 0x02);
5473
5474 outSISIDXREG(SISSR, 0x18, 0x01);
5475 if((ivideo->chip == XGI_20) ||
5476 (ivideo->revision_id == 2)) {
5477 outSISIDXREG(SISSR, 0x19, 0x40);
5478 } else {
5479 outSISIDXREG(SISSR, 0x19, 0x20);
5480 }
5481 outSISIDXREG(SISSR, 0x16, 0x00);
5482 outSISIDXREG(SISSR, 0x16, 0x80);
5483 if((ivideo->chip == XGI_20) || (bios[0x1cb] != 0x0c)) {
5484 sisfb_post_xgi_delay(ivideo, 0x43);
5485 sisfb_post_xgi_delay(ivideo, 0x43);
5486 sisfb_post_xgi_delay(ivideo, 0x43);
5487 outSISIDXREG(SISSR, 0x18, 0x00);
5488 if((ivideo->chip == XGI_20) ||
5489 (ivideo->revision_id == 2)) {
5490 outSISIDXREG(SISSR, 0x19, 0x40);
5491 } else {
5492 outSISIDXREG(SISSR, 0x19, 0x20);
5493 }
5494 } else if((ivideo->chip == XGI_40) && (bios[0x1cb] == 0x0c)) {
5495 /* outSISIDXREG(SISSR, 0x16, 0x0c); */ /* ? */
5496 }
5497 outSISIDXREG(SISSR, 0x16, 0x00);
5498 outSISIDXREG(SISSR, 0x16, 0x80);
5499 sisfb_post_xgi_delay(ivideo, 4);
5500 v1 = 0x31; v2 = 0x03; v3 = 0x83; v4 = 0x03; v5 = 0x83;
5501 if(ivideo->haveXGIROM) {
5502 v1 = bios[0xf0];
5503 index = (ivideo->chip == XGI_20) ? 0x4b2 : 0x53e;
5504 v2 = bios[index];
5505 v3 = bios[index + 1];
5506 v4 = bios[index + 2];
5507 v5 = bios[index + 3];
5508 }
5509 outSISIDXREG(SISSR, 0x18, v1);
5510 outSISIDXREG(SISSR, 0x19, ((ivideo->chip == XGI_20) ? 0x02 : 0x01));
5511 outSISIDXREG(SISSR, 0x16, v2);
5512 outSISIDXREG(SISSR, 0x16, v3);
5513 sisfb_post_xgi_delay(ivideo, 0x43);
5514 outSISIDXREG(SISSR, 0x1b, 0x03);
5515 sisfb_post_xgi_delay(ivideo, 0x22);
5516 outSISIDXREG(SISSR, 0x18, v1);
5517 outSISIDXREG(SISSR, 0x19, 0x00);
5518 outSISIDXREG(SISSR, 0x16, v4);
5519 outSISIDXREG(SISSR, 0x16, v5);
5520 outSISIDXREG(SISSR, 0x1b, 0x00);
5521 break;
5522 case 1:
5523 outSISIDXREG(SISCR, 0x82, 0x77);
5524 outSISIDXREG(SISCR, 0x86, 0x00);
5525 inSISIDXREG(SISCR, 0x86, reg);
5526 outSISIDXREG(SISCR, 0x86, 0x88);
5527 inSISIDXREG(SISCR, 0x86, reg);
5528 v1 = cs168[regb]; v2 = cs160[regb]; v3 = cs158[regb];
5529 if(ivideo->haveXGIROM) {
5530 v1 = bios[regb + 0x168];
5531 v2 = bios[regb + 0x160];
5532 v3 = bios[regb + 0x158];
5533 }
5534 outSISIDXREG(SISCR, 0x86, v1);
5535 outSISIDXREG(SISCR, 0x82, 0x77);
5536 outSISIDXREG(SISCR, 0x85, 0x00);
5537 inSISIDXREG(SISCR, 0x85, reg);
5538 outSISIDXREG(SISCR, 0x85, 0x88);
5539 inSISIDXREG(SISCR, 0x85, reg);
5540 outSISIDXREG(SISCR, 0x85, v2);
5541 outSISIDXREG(SISCR, 0x82, v3);
5542 outSISIDXREG(SISCR, 0x98, 0x01);
5543 outSISIDXREG(SISCR, 0x9a, 0x02);
5544
5545 outSISIDXREG(SISSR, 0x28, 0x64);
5546 outSISIDXREG(SISSR, 0x29, 0x63);
5547 sisfb_post_xgi_delay(ivideo, 15);
5548 outSISIDXREG(SISSR, 0x18, 0x00);
5549 outSISIDXREG(SISSR, 0x19, 0x20);
5550 outSISIDXREG(SISSR, 0x16, 0x00);
5551 outSISIDXREG(SISSR, 0x16, 0x80);
5552 outSISIDXREG(SISSR, 0x18, 0xc5);
5553 outSISIDXREG(SISSR, 0x19, 0x23);
5554 outSISIDXREG(SISSR, 0x16, 0x00);
5555 outSISIDXREG(SISSR, 0x16, 0x80);
5556 sisfb_post_xgi_delay(ivideo, 1);
5557 outSISIDXREG(SISCR, 0x97,0x11);
5558 sisfb_post_xgi_setclocks(ivideo, regb);
5559 sisfb_post_xgi_delay(ivideo, 0x46);
5560 outSISIDXREG(SISSR, 0x18, 0xc5);
5561 outSISIDXREG(SISSR, 0x19, 0x23);
5562 outSISIDXREG(SISSR, 0x16, 0x00);
5563 outSISIDXREG(SISSR, 0x16, 0x80);
5564 sisfb_post_xgi_delay(ivideo, 1);
5565 outSISIDXREG(SISSR, 0x1b, 0x04);
5566 sisfb_post_xgi_delay(ivideo, 1);
5567 outSISIDXREG(SISSR, 0x1b, 0x00);
5568 sisfb_post_xgi_delay(ivideo, 1);
5569 v1 = 0x31;
5570 if(ivideo->haveXGIROM) {
5571 v1 = bios[0xf0];
5572 }
5573 outSISIDXREG(SISSR, 0x18, v1);
5574 outSISIDXREG(SISSR, 0x19, 0x06);
5575 outSISIDXREG(SISSR, 0x16, 0x04);
5576 outSISIDXREG(SISSR, 0x16, 0x84);
5577 sisfb_post_xgi_delay(ivideo, 1);
5578 break;
5579 default:
5580 sisfb_post_xgi_setclocks(ivideo, regb);
5581 if((ivideo->chip == XGI_40) &&
5582 ((ivideo->revision_id == 1) ||
5583 (ivideo->revision_id == 2))) {
5584 outSISIDXREG(SISCR, 0x82, bios[regb + 0x158]);
5585 outSISIDXREG(SISCR, 0x85, bios[regb + 0x160]);
5586 outSISIDXREG(SISCR, 0x86, bios[regb + 0x168]);
5587 } else {
5588 outSISIDXREG(SISCR, 0x82, 0x88);
5589 outSISIDXREG(SISCR, 0x86, 0x00);
5590 inSISIDXREG(SISCR, 0x86, reg);
5591 outSISIDXREG(SISCR, 0x86, 0x88);
5592 outSISIDXREG(SISCR, 0x82, 0x77);
5593 outSISIDXREG(SISCR, 0x85, 0x00);
5594 inSISIDXREG(SISCR, 0x85, reg);
5595 outSISIDXREG(SISCR, 0x85, 0x88);
5596 inSISIDXREG(SISCR, 0x85, reg);
5597 v1 = cs160[regb]; v2 = cs158[regb];
5598 if(ivideo->haveXGIROM) {
5599 v1 = bios[regb + 0x160];
5600 v2 = bios[regb + 0x158];
5601 }
5602 outSISIDXREG(SISCR, 0x85, v1);
5603 outSISIDXREG(SISCR, 0x82, v2);
5604 }
5605 if(ivideo->chip == XGI_40) {
5606 outSISIDXREG(SISCR, 0x97, 0x11);
5607 }
5608 if((ivideo->chip == XGI_40) && (ivideo->revision_id == 2)) {
5609 outSISIDXREG(SISCR, 0x98, 0x01);
5610 } else {
5611 outSISIDXREG(SISCR, 0x98, 0x03);
5612 }
5613 outSISIDXREG(SISCR, 0x9a, 0x02);
5614
5615 if(ivideo->chip == XGI_40) {
5616 outSISIDXREG(SISSR, 0x18, 0x01);
5617 } else {
5618 outSISIDXREG(SISSR, 0x18, 0x00);
5619 }
5620 outSISIDXREG(SISSR, 0x19, 0x40);
5621 outSISIDXREG(SISSR, 0x16, 0x00);
5622 outSISIDXREG(SISSR, 0x16, 0x80);
5623 if((ivideo->chip == XGI_40) && (bios[0x1cb] != 0x0c)) {
5624 sisfb_post_xgi_delay(ivideo, 0x43);
5625 sisfb_post_xgi_delay(ivideo, 0x43);
5626 sisfb_post_xgi_delay(ivideo, 0x43);
5627 outSISIDXREG(SISSR, 0x18, 0x00);
5628 outSISIDXREG(SISSR, 0x19, 0x40);
5629 outSISIDXREG(SISSR, 0x16, 0x00);
5630 outSISIDXREG(SISSR, 0x16, 0x80);
5631 }
5632 sisfb_post_xgi_delay(ivideo, 4);
5633 v1 = 0x31;
5634 if(ivideo->haveXGIROM) {
5635 v1 = bios[0xf0];
5636 }
5637 outSISIDXREG(SISSR, 0x18, v1);
5638 outSISIDXREG(SISSR, 0x19, 0x01);
5639 if(ivideo->chip == XGI_40) {
5640 outSISIDXREG(SISSR, 0x16, bios[0x53e]);
5641 outSISIDXREG(SISSR, 0x16, bios[0x53f]);
5642 } else {
5643 outSISIDXREG(SISSR, 0x16, 0x05);
5644 outSISIDXREG(SISSR, 0x16, 0x85);
5645 }
5646 sisfb_post_xgi_delay(ivideo, 0x43);
5647 if(ivideo->chip == XGI_40) {
5648 outSISIDXREG(SISSR, 0x1b, 0x01);
5649 } else {
5650 outSISIDXREG(SISSR, 0x1b, 0x03);
5651 }
5652 sisfb_post_xgi_delay(ivideo, 0x22);
5653 outSISIDXREG(SISSR, 0x18, v1);
5654 outSISIDXREG(SISSR, 0x19, 0x00);
5655 if(ivideo->chip == XGI_40) {
5656 outSISIDXREG(SISSR, 0x16, bios[0x540]);
5657 outSISIDXREG(SISSR, 0x16, bios[0x541]);
5658 } else {
5659 outSISIDXREG(SISSR, 0x16, 0x05);
5660 outSISIDXREG(SISSR, 0x16, 0x85);
5661 }
5662 outSISIDXREG(SISSR, 0x1b, 0x00);
5663 }
5664
5665 regb = 0; /* ! */
5666 v1 = 0x03;
5667 if(ivideo->haveXGIROM) {
5668 v1 = bios[0x110 + regb];
5669 }
5670 outSISIDXREG(SISSR, 0x1b, v1);
5671
5672 /* RAM size */
5673 v1 = 0x00; v2 = 0x00;
5674 if(ivideo->haveXGIROM) {
5675 v1 = bios[0x62];
5676 v2 = bios[0x63];
5677 }
5678 regb = 0; /* ! */
5679 regd = 1 << regb;
5680 if((v1 & 0x40) && (v2 & regd) && ivideo->haveXGIROM) {
5681
5682 outSISIDXREG(SISSR, 0x13, bios[regb + 0xe0]);
5683 outSISIDXREG(SISSR, 0x14, bios[regb + 0xe0 + 8]);
5684
5685 } else {
5686
5687 /* Set default mode, don't clear screen */
Richard Knutssonc30660ea2007-02-12 00:55:06 -08005688 ivideo->SiS_Pr.SiS_UseOEM = false;
5689 SiS_SetEnableDstn(&ivideo->SiS_Pr, false);
5690 SiS_SetEnableFstn(&ivideo->SiS_Pr, false);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07005691 ivideo->curFSTN = ivideo->curDSTN = 0;
5692 ivideo->SiS_Pr.VideoMemorySize = 8 << 20;
5693 SiSSetMode(&ivideo->SiS_Pr, 0x2e | 0x80);
5694
5695 outSISIDXREG(SISSR, 0x05, 0x86);
5696
5697 /* Disable read-cache */
5698 andSISIDXREG(SISSR, 0x21, 0xdf);
5699 sisfb_post_xgi_ramsize(ivideo);
5700 /* Enable read-cache */
5701 orSISIDXREG(SISSR, 0x21, 0x20);
5702
5703 }
5704
5705#if 0
5706 printk(KERN_DEBUG "-----------------\n");
5707 for(i = 0; i < 0xff; i++) {
5708 inSISIDXREG(SISCR, i, reg);
5709 printk(KERN_DEBUG "CR%02x(%x) = 0x%02x\n", i, SISCR, reg);
5710 }
5711 for(i = 0; i < 0x40; i++) {
5712 inSISIDXREG(SISSR, i, reg);
5713 printk(KERN_DEBUG "SR%02x(%x) = 0x%02x\n", i, SISSR, reg);
5714 }
5715 printk(KERN_DEBUG "-----------------\n");
5716#endif
5717
5718 /* Sense CRT1 */
5719 if(ivideo->chip == XGI_20) {
5720 orSISIDXREG(SISCR, 0x32, 0x20);
5721 } else {
5722 inSISIDXREG(SISPART4, 0x00, reg);
5723 if((reg == 1) || (reg == 2)) {
5724 sisfb_sense_crt1(ivideo);
5725 } else {
5726 orSISIDXREG(SISCR, 0x32, 0x20);
5727 }
5728 }
5729
5730 /* Set default mode, don't clear screen */
Richard Knutssonc30660ea2007-02-12 00:55:06 -08005731 ivideo->SiS_Pr.SiS_UseOEM = false;
5732 SiS_SetEnableDstn(&ivideo->SiS_Pr, false);
5733 SiS_SetEnableFstn(&ivideo->SiS_Pr, false);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07005734 ivideo->curFSTN = ivideo->curDSTN = 0;
5735 SiSSetMode(&ivideo->SiS_Pr, 0x2e | 0x80);
5736
5737 outSISIDXREG(SISSR, 0x05, 0x86);
5738
5739 /* Display off */
5740 orSISIDXREG(SISSR, 0x01, 0x20);
5741
5742 /* Save mode number in CR34 */
5743 outSISIDXREG(SISCR, 0x34, 0x2e);
5744
5745 /* Let everyone know what the current mode is */
5746 ivideo->modeprechange = 0x2e;
5747
5748 if(ivideo->chip == XGI_40) {
5749 inSISIDXREG(SISCR, 0xca, reg);
5750 inSISIDXREG(SISCR, 0xcc, v1);
5751 if((reg & 0x10) && (!(v1 & 0x04))) {
5752 printk(KERN_ERR
5753 "sisfb: Please connect power to the card.\n");
5754 return 0;
5755 }
5756 }
5757
5758 return 1;
5759}
5760#endif
5761
5762static int __devinit
5763sisfb_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
5764{
5765 struct sisfb_chip_info *chipinfo = &sisfb_chip_info[ent->driver_data];
5766 struct sis_video_info *ivideo = NULL;
5767 struct fb_info *sis_fb_info = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005768 u16 reg16;
5769 u8 reg;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07005770 int i, ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005771
Thomas Winischhofer544393f2005-09-09 13:04:45 -07005772 if(sisfb_off)
5773 return -ENXIO;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005774
Linus Torvalds1da177e2005-04-16 15:20:36 -07005775 sis_fb_info = framebuffer_alloc(sizeof(*ivideo), &pdev->dev);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07005776 if(!sis_fb_info)
5777 return -ENOMEM;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005778
5779 ivideo = (struct sis_video_info *)sis_fb_info->par;
5780 ivideo->memyselfandi = sis_fb_info;
5781
Thomas Winischhofer544393f2005-09-09 13:04:45 -07005782 ivideo->sisfb_id = SISFB_ID;
5783
Linus Torvalds1da177e2005-04-16 15:20:36 -07005784 if(card_list == NULL) {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07005785 ivideo->cardnumber = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005786 } else {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07005787 struct sis_video_info *countvideo = card_list;
5788 ivideo->cardnumber = 1;
5789 while((countvideo = countvideo->next) != 0)
5790 ivideo->cardnumber++;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005791 }
5792
5793 strncpy(ivideo->myid, chipinfo->chip_name, 30);
5794
5795 ivideo->warncount = 0;
5796 ivideo->chip_id = pdev->device;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07005797 ivideo->chip_vendor = pdev->vendor;
Auke Kok44c10132007-06-08 15:46:36 -07005798 ivideo->revision_id = pdev->revision;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07005799 ivideo->SiS_Pr.ChipRevision = ivideo->revision_id;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005800 pci_read_config_word(pdev, PCI_COMMAND, &reg16);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07005801 ivideo->sisvga_enabled = reg16 & 0x01;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005802 ivideo->pcibus = pdev->bus->number;
5803 ivideo->pcislot = PCI_SLOT(pdev->devfn);
5804 ivideo->pcifunc = PCI_FUNC(pdev->devfn);
5805 ivideo->subsysvendor = pdev->subsystem_vendor;
5806 ivideo->subsysdevice = pdev->subsystem_device;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07005807#ifdef SIS_OLD_CONFIG_COMPAT
5808 ivideo->ioctl32registered = 0;
5809#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -07005810
5811#ifndef MODULE
5812 if(sisfb_mode_idx == -1) {
5813 sisfb_get_vga_mode_from_kernel();
5814 }
5815#endif
5816
5817 ivideo->chip = chipinfo->chip;
5818 ivideo->sisvga_engine = chipinfo->vgaengine;
5819 ivideo->hwcursor_size = chipinfo->hwcursor_size;
5820 ivideo->CRT2_write_enable = chipinfo->CRT2_write_enable;
5821 ivideo->mni = chipinfo->mni;
5822
5823 ivideo->detectedpdc = 0xff;
5824 ivideo->detectedpdca = 0xff;
5825 ivideo->detectedlcda = 0xff;
5826
Richard Knutssonc30660ea2007-02-12 00:55:06 -08005827 ivideo->sisfb_thismonitor.datavalid = false;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005828
Thomas Winischhofer544393f2005-09-09 13:04:45 -07005829 ivideo->current_base = 0;
5830
5831 ivideo->engineok = 0;
5832
5833 ivideo->sisfb_was_boot_device = 0;
5834#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,12))
5835 if(pdev->resource[PCI_ROM_RESOURCE].flags & IORESOURCE_ROM_SHADOW) {
5836 if(ivideo->sisvga_enabled)
5837 ivideo->sisfb_was_boot_device = 1;
5838 else {
5839 printk(KERN_DEBUG "sisfb: PCI device is disabled, "
5840 "but marked as boot video device ???\n");
5841 printk(KERN_DEBUG "sisfb: I will not accept this "
5842 "as the primary VGA device\n");
5843 }
5844 }
5845#endif
5846
Linus Torvalds1da177e2005-04-16 15:20:36 -07005847 ivideo->sisfb_parm_mem = sisfb_parm_mem;
5848 ivideo->sisfb_accel = sisfb_accel;
5849 ivideo->sisfb_ypan = sisfb_ypan;
5850 ivideo->sisfb_max = sisfb_max;
5851 ivideo->sisfb_userom = sisfb_userom;
5852 ivideo->sisfb_useoem = sisfb_useoem;
5853 ivideo->sisfb_mode_idx = sisfb_mode_idx;
5854 ivideo->sisfb_parm_rate = sisfb_parm_rate;
5855 ivideo->sisfb_crt1off = sisfb_crt1off;
5856 ivideo->sisfb_forcecrt1 = sisfb_forcecrt1;
5857 ivideo->sisfb_crt2type = sisfb_crt2type;
5858 ivideo->sisfb_crt2flags = sisfb_crt2flags;
5859 /* pdc(a), scalelcd, special timing, lvdshl handled below */
5860 ivideo->sisfb_dstn = sisfb_dstn;
5861 ivideo->sisfb_fstn = sisfb_fstn;
5862 ivideo->sisfb_tvplug = sisfb_tvplug;
5863 ivideo->sisfb_tvstd = sisfb_tvstd;
5864 ivideo->tvxpos = sisfb_tvxposoffset;
5865 ivideo->tvypos = sisfb_tvyposoffset;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005866 ivideo->sisfb_nocrt2rate = sisfb_nocrt2rate;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005867 ivideo->refresh_rate = 0;
5868 if(ivideo->sisfb_parm_rate != -1) {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07005869 ivideo->refresh_rate = ivideo->sisfb_parm_rate;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005870 }
5871
5872 ivideo->SiS_Pr.UsePanelScaler = sisfb_scalelcd;
5873 ivideo->SiS_Pr.CenterScreen = -1;
5874 ivideo->SiS_Pr.SiS_CustomT = sisfb_specialtiming;
5875 ivideo->SiS_Pr.LVDSHL = sisfb_lvdshl;
5876
5877 ivideo->SiS_Pr.SiS_Backup70xx = 0xff;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07005878 ivideo->SiS_Pr.SiS_CHOverScan = -1;
Richard Knutssonc30660ea2007-02-12 00:55:06 -08005879 ivideo->SiS_Pr.SiS_ChSW = false;
5880 ivideo->SiS_Pr.SiS_UseLCDA = false;
5881 ivideo->SiS_Pr.HaveEMI = false;
5882 ivideo->SiS_Pr.HaveEMILCD = false;
5883 ivideo->SiS_Pr.OverruleEMI = false;
5884 ivideo->SiS_Pr.SiS_SensibleSR11 = false;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005885 ivideo->SiS_Pr.SiS_MyCR63 = 0x63;
5886 ivideo->SiS_Pr.PDC = -1;
5887 ivideo->SiS_Pr.PDCA = -1;
Richard Knutssonc30660ea2007-02-12 00:55:06 -08005888 ivideo->SiS_Pr.DDCPortMixup = false;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005889#ifdef CONFIG_FB_SIS_315
5890 if(ivideo->chip >= SIS_330) {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07005891 ivideo->SiS_Pr.SiS_MyCR63 = 0x53;
5892 if(ivideo->chip >= SIS_661) {
Richard Knutssonc30660ea2007-02-12 00:55:06 -08005893 ivideo->SiS_Pr.SiS_SensibleSR11 = true;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07005894 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07005895 }
5896#endif
5897
5898 memcpy(&ivideo->default_var, &my_default_var, sizeof(my_default_var));
5899
5900 pci_set_drvdata(pdev, ivideo);
5901
5902 /* Patch special cases */
5903 if((ivideo->nbridge = sisfb_get_northbridge(ivideo->chip))) {
5904 switch(ivideo->nbridge->device) {
5905#ifdef CONFIG_FB_SIS_300
5906 case PCI_DEVICE_ID_SI_730:
Thomas Winischhofer544393f2005-09-09 13:04:45 -07005907 ivideo->chip = SIS_730;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005908 strcpy(ivideo->myid, "SiS 730");
Thomas Winischhofer544393f2005-09-09 13:04:45 -07005909 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005910#endif
5911#ifdef CONFIG_FB_SIS_315
5912 case PCI_DEVICE_ID_SI_651:
5913 /* ivideo->chip is ok */
5914 strcpy(ivideo->myid, "SiS 651");
5915 break;
5916 case PCI_DEVICE_ID_SI_740:
Thomas Winischhofer544393f2005-09-09 13:04:45 -07005917 ivideo->chip = SIS_740;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005918 strcpy(ivideo->myid, "SiS 740");
5919 break;
5920 case PCI_DEVICE_ID_SI_661:
Thomas Winischhofer544393f2005-09-09 13:04:45 -07005921 ivideo->chip = SIS_661;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005922 strcpy(ivideo->myid, "SiS 661");
5923 break;
5924 case PCI_DEVICE_ID_SI_741:
Thomas Winischhofer544393f2005-09-09 13:04:45 -07005925 ivideo->chip = SIS_741;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005926 strcpy(ivideo->myid, "SiS 741");
5927 break;
5928 case PCI_DEVICE_ID_SI_760:
Thomas Winischhofer544393f2005-09-09 13:04:45 -07005929 ivideo->chip = SIS_760;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005930 strcpy(ivideo->myid, "SiS 760");
5931 break;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07005932 case PCI_DEVICE_ID_SI_761:
5933 ivideo->chip = SIS_761;
5934 strcpy(ivideo->myid, "SiS 761");
5935 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005936#endif
Thomas Winischhofer544393f2005-09-09 13:04:45 -07005937 default:
5938 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005939 }
5940 }
5941
Thomas Winischhofer544393f2005-09-09 13:04:45 -07005942 ivideo->SiS_Pr.ChipType = ivideo->chip;
5943
5944 ivideo->SiS_Pr.ivideo = (void *)ivideo;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005945
5946#ifdef CONFIG_FB_SIS_315
Thomas Winischhofer544393f2005-09-09 13:04:45 -07005947 if((ivideo->SiS_Pr.ChipType == SIS_315PRO) ||
5948 (ivideo->SiS_Pr.ChipType == SIS_315)) {
5949 ivideo->SiS_Pr.ChipType = SIS_315H;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005950 }
5951#endif
5952
Thomas Winischhofer544393f2005-09-09 13:04:45 -07005953 if(!ivideo->sisvga_enabled) {
5954 if(pci_enable_device(pdev)) {
Adrian Bunk0959f0c2007-05-08 00:39:50 -07005955 if(ivideo->nbridge) pci_dev_put(ivideo->nbridge);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07005956 pci_set_drvdata(pdev, NULL);
5957 kfree(sis_fb_info);
5958 return -EIO;
5959 }
5960 }
5961
Linus Torvalds1da177e2005-04-16 15:20:36 -07005962 ivideo->video_base = pci_resource_start(pdev, 0);
5963 ivideo->mmio_base = pci_resource_start(pdev, 1);
5964 ivideo->mmio_size = pci_resource_len(pdev, 1);
5965 ivideo->SiS_Pr.RelIO = pci_resource_start(pdev, 2) + 0x30;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07005966 ivideo->SiS_Pr.IOAddress = ivideo->vga_base = ivideo->SiS_Pr.RelIO;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005967
Thomas Winischhofer544393f2005-09-09 13:04:45 -07005968 SiSRegInit(&ivideo->SiS_Pr, ivideo->SiS_Pr.IOAddress);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005969
5970#ifdef CONFIG_FB_SIS_300
5971 /* Find PCI systems for Chrontel/GPIO communication setup */
5972 if(ivideo->chip == SIS_630) {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07005973 i = 0;
5974 do {
5975 if(mychswtable[i].subsysVendor == ivideo->subsysvendor &&
5976 mychswtable[i].subsysCard == ivideo->subsysdevice) {
Richard Knutssonc30660ea2007-02-12 00:55:06 -08005977 ivideo->SiS_Pr.SiS_ChSW = true;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07005978 printk(KERN_DEBUG "sisfb: Identified [%s %s] "
5979 "requiring Chrontel/GPIO setup\n",
5980 mychswtable[i].vendorName,
5981 mychswtable[i].cardName);
Adrian Bunk0959f0c2007-05-08 00:39:50 -07005982 ivideo->lpcdev = pci_get_device(PCI_VENDOR_ID_SI, 0x0008, NULL);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07005983 break;
5984 }
5985 i++;
5986 } while(mychswtable[i].subsysVendor != 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005987 }
5988#endif
5989
Thomas Winischhofer544393f2005-09-09 13:04:45 -07005990#ifdef CONFIG_FB_SIS_315
5991 if((ivideo->chip == SIS_760) && (ivideo->nbridge)) {
Adrian Bunk0959f0c2007-05-08 00:39:50 -07005992 ivideo->lpcdev = pci_get_slot(ivideo->nbridge->bus, (2 << 3));
Thomas Winischhofer544393f2005-09-09 13:04:45 -07005993 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07005994#endif
Thomas Winischhofer544393f2005-09-09 13:04:45 -07005995
5996 outSISIDXREG(SISSR, 0x05, 0x86);
5997
5998 if( (!ivideo->sisvga_enabled)
5999#if !defined(__i386__) && !defined(__x86_64__)
6000 || (sisfb_resetcard)
6001#endif
6002 ) {
6003 for(i = 0x30; i <= 0x3f; i++) {
6004 outSISIDXREG(SISCR, i, 0x00);
6005 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07006006 }
6007
6008 /* Find out about current video mode */
6009 ivideo->modeprechange = 0x03;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006010 inSISIDXREG(SISCR, 0x34, reg);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006011 if(reg & 0x7f) {
6012 ivideo->modeprechange = reg & 0x7f;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006013 } else if(ivideo->sisvga_enabled) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07006014#if defined(__i386__) || defined(__x86_64__)
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006015 unsigned char SIS_IOTYPE2 *tt = ioremap(0x400, 0x100);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006016 if(tt) {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006017 ivideo->modeprechange = readb(tt + 0x49);
6018 iounmap(tt);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006019 }
6020#endif
6021 }
6022
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006023 /* Search and copy ROM image */
6024 ivideo->bios_abase = NULL;
6025 ivideo->SiS_Pr.VirtualRomBase = NULL;
Richard Knutssonc30660ea2007-02-12 00:55:06 -08006026 ivideo->SiS_Pr.UseROM = false;
6027 ivideo->haveXGIROM = ivideo->SiS_Pr.SiS_XGIROM = false;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006028 if(ivideo->sisfb_userom) {
6029 ivideo->SiS_Pr.VirtualRomBase = sisfb_find_rom(pdev);
6030 ivideo->bios_abase = ivideo->SiS_Pr.VirtualRomBase;
Richard Knutssonc30660ea2007-02-12 00:55:06 -08006031 ivideo->SiS_Pr.UseROM = (bool)(ivideo->SiS_Pr.VirtualRomBase);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006032 printk(KERN_INFO "sisfb: Video ROM %sfound\n",
6033 ivideo->SiS_Pr.UseROM ? "" : "not ");
6034 if((ivideo->SiS_Pr.UseROM) && (ivideo->chip >= XGI_20)) {
Richard Knutssonc30660ea2007-02-12 00:55:06 -08006035 ivideo->SiS_Pr.UseROM = false;
6036 ivideo->haveXGIROM = ivideo->SiS_Pr.SiS_XGIROM = true;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006037 if( (ivideo->revision_id == 2) &&
6038 (!(ivideo->bios_abase[0x1d1] & 0x01)) ) {
Richard Knutssonc30660ea2007-02-12 00:55:06 -08006039 ivideo->SiS_Pr.DDCPortMixup = true;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006040 }
6041 }
6042 } else {
6043 printk(KERN_INFO "sisfb: Video ROM usage disabled\n");
6044 }
6045
6046 /* Find systems for special custom timing */
6047 if(ivideo->SiS_Pr.SiS_CustomT == CUT_NONE) {
6048 sisfb_detect_custom_timing(ivideo);
6049 }
6050
6051 /* POST card in case this has not been done by the BIOS */
6052 if( (!ivideo->sisvga_enabled)
6053#if !defined(__i386__) && !defined(__x86_64__)
6054 || (sisfb_resetcard)
6055#endif
6056 ) {
6057#ifdef CONFIG_FB_SIS_300
6058 if(ivideo->sisvga_engine == SIS_300_VGA) {
6059 if(ivideo->chip == SIS_300) {
6060 sisfb_post_sis300(pdev);
6061 ivideo->sisfb_can_post = 1;
6062 }
6063 }
6064#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -07006065
6066#ifdef CONFIG_FB_SIS_315
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006067 if(ivideo->sisvga_engine == SIS_315_VGA) {
6068 int result = 1;
6069 /* if((ivideo->chip == SIS_315H) ||
Linus Torvalds1da177e2005-04-16 15:20:36 -07006070 (ivideo->chip == SIS_315) ||
6071 (ivideo->chip == SIS_315PRO) ||
6072 (ivideo->chip == SIS_330)) {
6073 sisfb_post_sis315330(pdev);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006074 } else */ if(ivideo->chip == XGI_20) {
6075 result = sisfb_post_xgi(pdev);
6076 ivideo->sisfb_can_post = 1;
6077 } else if((ivideo->chip == XGI_40) && ivideo->haveXGIROM) {
6078 result = sisfb_post_xgi(pdev);
6079 ivideo->sisfb_can_post = 1;
6080 } else {
6081 printk(KERN_INFO "sisfb: Card is not "
6082 "POSTed and sisfb can't do this either.\n");
6083 }
6084 if(!result) {
6085 printk(KERN_ERR "sisfb: Failed to POST card\n");
6086 ret = -ENODEV;
6087 goto error_3;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006088 }
6089 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07006090#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -07006091 }
6092
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006093 ivideo->sisfb_card_posted = 1;
6094
6095 /* Find out about RAM size */
6096 if(sisfb_get_dram_size(ivideo)) {
6097 printk(KERN_INFO "sisfb: Fatal error: Unable to determine VRAM size.\n");
6098 ret = -ENODEV;
6099 goto error_3;
6100 }
6101
6102
6103 /* Enable PCI addressing and MMIO */
Linus Torvalds1da177e2005-04-16 15:20:36 -07006104 if((ivideo->sisfb_mode_idx < 0) ||
6105 ((sisbios_mode[ivideo->sisfb_mode_idx].mode_no[ivideo->mni]) != 0xFF)) {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006106 /* Enable PCI_LINEAR_ADDRESSING and MMIO_ENABLE */
6107 orSISIDXREG(SISSR, IND_SIS_PCI_ADDRESS_SET, (SIS_PCI_ADDR_ENABLE | SIS_MEM_MAP_IO_ENABLE));
6108 /* Enable 2D accelerator engine */
6109 orSISIDXREG(SISSR, IND_SIS_MODULE_ENABLE, SIS_ENABLE_2D);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006110 }
6111
6112 if(sisfb_pdc != 0xff) {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006113 if(ivideo->sisvga_engine == SIS_300_VGA)
6114 sisfb_pdc &= 0x3c;
6115 else
6116 sisfb_pdc &= 0x1f;
6117 ivideo->SiS_Pr.PDC = sisfb_pdc;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006118 }
6119#ifdef CONFIG_FB_SIS_315
6120 if(ivideo->sisvga_engine == SIS_315_VGA) {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006121 if(sisfb_pdca != 0xff)
6122 ivideo->SiS_Pr.PDCA = sisfb_pdca & 0x1f;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006123 }
6124#endif
6125
6126 if(!request_mem_region(ivideo->video_base, ivideo->video_size, "sisfb FB")) {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006127 printk(KERN_ERR "sisfb: Fatal error: Unable to reserve %dMB framebuffer memory\n",
6128 (int)(ivideo->video_size >> 20));
Linus Torvalds1da177e2005-04-16 15:20:36 -07006129 printk(KERN_ERR "sisfb: Is there another framebuffer driver active?\n");
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006130 ret = -ENODEV;
6131 goto error_3;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006132 }
6133
6134 if(!request_mem_region(ivideo->mmio_base, ivideo->mmio_size, "sisfb MMIO")) {
6135 printk(KERN_ERR "sisfb: Fatal error: Unable to reserve MMIO region\n");
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006136 ret = -ENODEV;
6137 goto error_2;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006138 }
6139
6140 ivideo->video_vbase = ioremap(ivideo->video_base, ivideo->video_size);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006141 ivideo->SiS_Pr.VideoMemoryAddress = ivideo->video_vbase;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006142 if(!ivideo->video_vbase) {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006143 printk(KERN_ERR "sisfb: Fatal error: Unable to map framebuffer memory\n");
6144 ret = -ENODEV;
6145 goto error_1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006146 }
6147
6148 ivideo->mmio_vbase = ioremap(ivideo->mmio_base, ivideo->mmio_size);
6149 if(!ivideo->mmio_vbase) {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006150 printk(KERN_ERR "sisfb: Fatal error: Unable to map MMIO region\n");
6151 ret = -ENODEV;
6152error_0: iounmap(ivideo->video_vbase);
6153error_1: release_mem_region(ivideo->video_base, ivideo->video_size);
6154error_2: release_mem_region(ivideo->mmio_base, ivideo->mmio_size);
6155error_3: vfree(ivideo->bios_abase);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006156 if(ivideo->lpcdev)
Adrian Bunk0959f0c2007-05-08 00:39:50 -07006157 pci_dev_put(ivideo->lpcdev);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006158 if(ivideo->nbridge)
Adrian Bunk0959f0c2007-05-08 00:39:50 -07006159 pci_dev_put(ivideo->nbridge);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006160 pci_set_drvdata(pdev, NULL);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006161 if(!ivideo->sisvga_enabled)
6162 pci_disable_device(pdev);
6163 kfree(sis_fb_info);
6164 return ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006165 }
6166
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006167 printk(KERN_INFO "sisfb: Video RAM at 0x%lx, mapped to 0x%lx, size %ldk\n",
6168 ivideo->video_base, (unsigned long)ivideo->video_vbase, ivideo->video_size / 1024);
6169
6170 if(ivideo->video_offset) {
6171 printk(KERN_INFO "sisfb: Viewport offset %ldk\n",
6172 ivideo->video_offset / 1024);
6173 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07006174
6175 printk(KERN_INFO "sisfb: MMIO at 0x%lx, mapped to 0x%lx, size %ldk\n",
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006176 ivideo->mmio_base, (unsigned long)ivideo->mmio_vbase, ivideo->mmio_size / 1024);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006177
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006178
6179 /* Determine the size of the command queue */
6180 if(ivideo->sisvga_engine == SIS_300_VGA) {
6181 ivideo->cmdQueueSize = TURBO_QUEUE_AREA_SIZE;
6182 } else {
6183 if(ivideo->chip == XGI_20) {
6184 ivideo->cmdQueueSize = COMMAND_QUEUE_AREA_SIZE_Z7;
6185 } else {
6186 ivideo->cmdQueueSize = COMMAND_QUEUE_AREA_SIZE;
6187 }
6188 }
6189
6190 /* Engines are no longer initialized here; this is
6191 * now done after the first mode-switch (if the
6192 * submitted var has its acceleration flags set).
6193 */
6194
6195 /* Calculate the base of the (unused) hw cursor */
6196 ivideo->hwcursor_vbase = ivideo->video_vbase
6197 + ivideo->video_size
6198 - ivideo->cmdQueueSize
6199 - ivideo->hwcursor_size;
6200 ivideo->caps |= HW_CURSOR_CAP;
6201
6202 /* Initialize offscreen memory manager */
Linus Torvalds1da177e2005-04-16 15:20:36 -07006203 if((ivideo->havenoheap = sisfb_heap_init(ivideo))) {
6204 printk(KERN_WARNING "sisfb: Failed to initialize offscreen memory heap\n");
6205 }
6206
6207 /* Used for clearing the screen only, therefore respect our mem limit */
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006208 ivideo->SiS_Pr.VideoMemoryAddress += ivideo->video_offset;
6209 ivideo->SiS_Pr.VideoMemorySize = ivideo->sisfb_mem;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006210
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006211 ivideo->mtrr = -1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006212
6213 ivideo->vbflags = 0;
6214 ivideo->lcddefmodeidx = DEFAULT_LCDMODE;
6215 ivideo->tvdefmodeidx = DEFAULT_TVMODE;
6216 ivideo->defmodeidx = DEFAULT_MODE;
6217
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006218 ivideo->newrom = 0;
6219 if(ivideo->chip < XGI_20) {
6220 if(ivideo->bios_abase) {
6221 ivideo->newrom = SiSDetermineROMLayout661(&ivideo->SiS_Pr);
6222 }
6223 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07006224
6225 if((ivideo->sisfb_mode_idx < 0) ||
6226 ((sisbios_mode[ivideo->sisfb_mode_idx].mode_no[ivideo->mni]) != 0xFF)) {
6227
6228 sisfb_sense_crt1(ivideo);
6229
6230 sisfb_get_VB_type(ivideo);
6231
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006232 if(ivideo->vbflags2 & VB2_VIDEOBRIDGE) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07006233 sisfb_detect_VB_connect(ivideo);
6234 }
6235
6236 ivideo->currentvbflags = ivideo->vbflags & (VB_VIDEOBRIDGE | TV_STANDARD);
6237
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006238 /* Decide on which CRT2 device to use */
6239 if(ivideo->vbflags2 & VB2_VIDEOBRIDGE) {
6240 if(ivideo->sisfb_crt2type != -1) {
6241 if((ivideo->sisfb_crt2type == CRT2_LCD) &&
6242 (ivideo->vbflags & CRT2_LCD)) {
6243 ivideo->currentvbflags |= CRT2_LCD;
6244 } else if(ivideo->sisfb_crt2type != CRT2_LCD) {
6245 ivideo->currentvbflags |= ivideo->sisfb_crt2type;
6246 }
6247 } else {
6248 /* Chrontel 700x TV detection often unreliable, therefore
6249 * use a different default order on such machines
6250 */
6251 if((ivideo->sisvga_engine == SIS_300_VGA) &&
6252 (ivideo->vbflags2 & VB2_CHRONTEL)) {
6253 if(ivideo->vbflags & CRT2_LCD)
6254 ivideo->currentvbflags |= CRT2_LCD;
6255 else if(ivideo->vbflags & CRT2_TV)
6256 ivideo->currentvbflags |= CRT2_TV;
6257 else if(ivideo->vbflags & CRT2_VGA)
6258 ivideo->currentvbflags |= CRT2_VGA;
6259 } else {
6260 if(ivideo->vbflags & CRT2_TV)
6261 ivideo->currentvbflags |= CRT2_TV;
6262 else if(ivideo->vbflags & CRT2_LCD)
6263 ivideo->currentvbflags |= CRT2_LCD;
6264 else if(ivideo->vbflags & CRT2_VGA)
6265 ivideo->currentvbflags |= CRT2_VGA;
6266 }
6267 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07006268 }
6269
6270 if(ivideo->vbflags & CRT2_LCD) {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006271 sisfb_detect_lcd_type(ivideo);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006272 }
6273
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006274 sisfb_save_pdc_emi(ivideo);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006275
6276 if(!ivideo->sisfb_crt1off) {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006277 sisfb_handle_ddc(ivideo, &ivideo->sisfb_thismonitor, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006278 } else {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006279 if((ivideo->vbflags2 & VB2_SISTMDSBRIDGE) &&
6280 (ivideo->vbflags & (CRT2_VGA | CRT2_LCD))) {
6281 sisfb_handle_ddc(ivideo, &ivideo->sisfb_thismonitor, 1);
6282 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07006283 }
6284
6285 if(ivideo->sisfb_mode_idx >= 0) {
6286 int bu = ivideo->sisfb_mode_idx;
6287 ivideo->sisfb_mode_idx = sisfb_validate_mode(ivideo,
6288 ivideo->sisfb_mode_idx, ivideo->currentvbflags);
6289 if(bu != ivideo->sisfb_mode_idx) {
6290 printk(KERN_ERR "Mode %dx%dx%d failed validation\n",
6291 sisbios_mode[bu].xres,
6292 sisbios_mode[bu].yres,
6293 sisbios_mode[bu].bpp);
6294 }
6295 }
6296
6297 if(ivideo->sisfb_mode_idx < 0) {
6298 switch(ivideo->currentvbflags & VB_DISPTYPE_DISP2) {
6299 case CRT2_LCD:
6300 ivideo->sisfb_mode_idx = ivideo->lcddefmodeidx;
6301 break;
6302 case CRT2_TV:
6303 ivideo->sisfb_mode_idx = ivideo->tvdefmodeidx;
6304 break;
6305 default:
6306 ivideo->sisfb_mode_idx = ivideo->defmodeidx;
6307 break;
6308 }
6309 }
6310
6311 ivideo->mode_no = sisbios_mode[ivideo->sisfb_mode_idx].mode_no[ivideo->mni];
6312
6313 if(ivideo->refresh_rate != 0) {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006314 sisfb_search_refresh_rate(ivideo, ivideo->refresh_rate,
6315 ivideo->sisfb_mode_idx);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006316 }
6317
6318 if(ivideo->rate_idx == 0) {
6319 ivideo->rate_idx = sisbios_mode[ivideo->sisfb_mode_idx].rate_idx;
6320 ivideo->refresh_rate = 60;
6321 }
6322
6323 if(ivideo->sisfb_thismonitor.datavalid) {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006324 if(!sisfb_verify_rate(ivideo, &ivideo->sisfb_thismonitor,
6325 ivideo->sisfb_mode_idx,
6326 ivideo->rate_idx,
6327 ivideo->refresh_rate)) {
6328 printk(KERN_INFO "sisfb: WARNING: Refresh rate "
6329 "exceeds monitor specs!\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07006330 }
6331 }
6332
6333 ivideo->video_bpp = sisbios_mode[ivideo->sisfb_mode_idx].bpp;
6334 ivideo->video_width = sisbios_mode[ivideo->sisfb_mode_idx].xres;
6335 ivideo->video_height = sisbios_mode[ivideo->sisfb_mode_idx].yres;
6336
6337 sisfb_set_vparms(ivideo);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006338
Linus Torvalds1da177e2005-04-16 15:20:36 -07006339 printk(KERN_INFO "sisfb: Default mode is %dx%dx%d (%dHz)\n",
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006340 ivideo->video_width, ivideo->video_height, ivideo->video_bpp,
Linus Torvalds1da177e2005-04-16 15:20:36 -07006341 ivideo->refresh_rate);
6342
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006343 /* Set up the default var according to chosen default display mode */
Linus Torvalds1da177e2005-04-16 15:20:36 -07006344 ivideo->default_var.xres = ivideo->default_var.xres_virtual = ivideo->video_width;
6345 ivideo->default_var.yres = ivideo->default_var.yres_virtual = ivideo->video_height;
6346 ivideo->default_var.bits_per_pixel = ivideo->video_bpp;
6347
6348 sisfb_bpp_to_var(ivideo, &ivideo->default_var);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006349
Linus Torvalds1da177e2005-04-16 15:20:36 -07006350 ivideo->default_var.pixclock = (u32) (1000000000 /
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006351 sisfb_mode_rate_to_dclock(&ivideo->SiS_Pr, ivideo->mode_no, ivideo->rate_idx));
6352
6353 if(sisfb_mode_rate_to_ddata(&ivideo->SiS_Pr, ivideo->mode_no,
6354 ivideo->rate_idx, &ivideo->default_var)) {
6355 if((ivideo->default_var.vmode & FB_VMODE_MASK) == FB_VMODE_DOUBLE) {
6356 ivideo->default_var.pixclock <<= 1;
6357 }
6358 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07006359
6360 if(ivideo->sisfb_ypan) {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006361 /* Maximize regardless of sisfb_max at startup */
6362 ivideo->default_var.yres_virtual =
6363 sisfb_calc_maxyres(ivideo, &ivideo->default_var);
6364 if(ivideo->default_var.yres_virtual < ivideo->default_var.yres) {
6365 ivideo->default_var.yres_virtual = ivideo->default_var.yres;
6366 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07006367 }
6368
6369 sisfb_calc_pitch(ivideo, &ivideo->default_var);
6370
6371 ivideo->accel = 0;
6372 if(ivideo->sisfb_accel) {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006373 ivideo->accel = -1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006374#ifdef STUPID_ACCELF_TEXT_SHIT
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006375 ivideo->default_var.accel_flags |= FB_ACCELF_TEXT;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006376#endif
6377 }
6378 sisfb_initaccel(ivideo);
6379
6380#if defined(FBINFO_HWACCEL_DISABLED) && defined(FBINFO_HWACCEL_XPAN)
6381 sis_fb_info->flags = FBINFO_DEFAULT |
6382 FBINFO_HWACCEL_YPAN |
6383 FBINFO_HWACCEL_XPAN |
6384 FBINFO_HWACCEL_COPYAREA |
6385 FBINFO_HWACCEL_FILLRECT |
6386 ((ivideo->accel) ? 0 : FBINFO_HWACCEL_DISABLED);
6387#else
6388 sis_fb_info->flags = FBINFO_FLAG_DEFAULT;
6389#endif
6390 sis_fb_info->var = ivideo->default_var;
6391 sis_fb_info->fix = ivideo->sisfb_fix;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006392 sis_fb_info->screen_base = ivideo->video_vbase + ivideo->video_offset;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006393 sis_fb_info->fbops = &sisfb_ops;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006394 sisfb_get_fix(&sis_fb_info->fix, -1, sis_fb_info);
6395 sis_fb_info->pseudo_palette = ivideo->pseudo_palette;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006396
Linus Torvalds1da177e2005-04-16 15:20:36 -07006397 fb_alloc_cmap(&sis_fb_info->cmap, 256 , 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006398
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006399 printk(KERN_DEBUG "sisfb: Initial vbflags 0x%x\n", (int)ivideo->vbflags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006400
6401#ifdef CONFIG_MTRR
6402 ivideo->mtrr = mtrr_add(ivideo->video_base, ivideo->video_size,
6403 MTRR_TYPE_WRCOMB, 1);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006404 if(ivideo->mtrr < 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07006405 printk(KERN_DEBUG "sisfb: Failed to add MTRRs\n");
6406 }
6407#endif
6408
Linus Torvalds1da177e2005-04-16 15:20:36 -07006409 if(register_framebuffer(sis_fb_info) < 0) {
6410 printk(KERN_ERR "sisfb: Fatal error: Failed to register framebuffer\n");
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006411 ret = -EINVAL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006412 iounmap(ivideo->mmio_vbase);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006413 goto error_0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006414 }
6415
6416 ivideo->registered = 1;
6417
6418 /* Enlist us */
6419 ivideo->next = card_list;
6420 card_list = ivideo;
6421
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006422#ifdef SIS_OLD_CONFIG_COMPAT
6423 {
6424 int ret;
6425 /* Our ioctls are all "32/64bit compatible" */
6426 ret = register_ioctl32_conversion(FBIO_ALLOC, NULL);
6427 ret |= register_ioctl32_conversion(FBIO_FREE, NULL);
6428 ret |= register_ioctl32_conversion(FBIOGET_VBLANK, NULL);
6429 ret |= register_ioctl32_conversion(SISFB_GET_INFO_SIZE, NULL);
6430 ret |= register_ioctl32_conversion(SISFB_GET_INFO, NULL);
6431 ret |= register_ioctl32_conversion(SISFB_GET_TVPOSOFFSET, NULL);
6432 ret |= register_ioctl32_conversion(SISFB_SET_TVPOSOFFSET, NULL);
6433 ret |= register_ioctl32_conversion(SISFB_SET_LOCK, NULL);
6434 ret |= register_ioctl32_conversion(SISFB_GET_VBRSTATUS, NULL);
6435 ret |= register_ioctl32_conversion(SISFB_GET_AUTOMAXIMIZE, NULL);
6436 ret |= register_ioctl32_conversion(SISFB_SET_AUTOMAXIMIZE, NULL);
6437 ret |= register_ioctl32_conversion(SISFB_COMMAND, NULL);
6438 if(ret)
6439 printk(KERN_ERR
6440 "sisfb: Error registering ioctl32 translations\n");
6441 else
6442 ivideo->ioctl32registered = 1;
6443 }
6444#endif
6445
Linus Torvalds1da177e2005-04-16 15:20:36 -07006446 printk(KERN_INFO "sisfb: 2D acceleration is %s, y-panning %s\n",
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006447 ivideo->sisfb_accel ? "enabled" : "disabled",
6448 ivideo->sisfb_ypan ?
6449 (ivideo->sisfb_max ? "enabled (auto-max)" :
6450 "enabled (no auto-max)") :
6451 "disabled");
Linus Torvalds1da177e2005-04-16 15:20:36 -07006452
6453
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006454 printk(KERN_INFO "fb%d: %s frame buffer device version %d.%d.%d\n",
Michal Piotrowski43704092006-10-03 01:15:00 -07006455 sis_fb_info->node, ivideo->myid, VER_MAJOR, VER_MINOR, VER_LEVEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006456
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006457 printk(KERN_INFO "sisfb: Copyright (C) 2001-2005 Thomas Winischhofer\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07006458
6459 } /* if mode = "none" */
6460
6461 return 0;
6462}
6463
6464/*****************************************************/
6465/* PCI DEVICE HANDLING */
6466/*****************************************************/
6467
6468static void __devexit sisfb_remove(struct pci_dev *pdev)
6469{
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006470 struct sis_video_info *ivideo = pci_get_drvdata(pdev);
6471 struct fb_info *sis_fb_info = ivideo->memyselfandi;
6472 int registered = ivideo->registered;
6473 int modechanged = ivideo->modechanged;
6474
6475#ifdef SIS_OLD_CONFIG_COMPAT
6476 if(ivideo->ioctl32registered) {
6477 int ret;
6478 ret = unregister_ioctl32_conversion(FBIO_ALLOC);
6479 ret |= unregister_ioctl32_conversion(FBIO_FREE);
6480 ret |= unregister_ioctl32_conversion(FBIOGET_VBLANK);
6481 ret |= unregister_ioctl32_conversion(SISFB_GET_INFO_SIZE);
6482 ret |= unregister_ioctl32_conversion(SISFB_GET_INFO);
6483 ret |= unregister_ioctl32_conversion(SISFB_GET_TVPOSOFFSET);
6484 ret |= unregister_ioctl32_conversion(SISFB_SET_TVPOSOFFSET);
6485 ret |= unregister_ioctl32_conversion(SISFB_SET_LOCK);
6486 ret |= unregister_ioctl32_conversion(SISFB_GET_VBRSTATUS);
6487 ret |= unregister_ioctl32_conversion(SISFB_GET_AUTOMAXIMIZE);
6488 ret |= unregister_ioctl32_conversion(SISFB_SET_AUTOMAXIMIZE);
6489 ret |= unregister_ioctl32_conversion(SISFB_COMMAND);
6490 if(ret)
6491 printk(KERN_ERR
6492 "sisfb: Error unregistering ioctl32 translations\n");
6493 }
6494#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -07006495
6496 /* Unmap */
Linus Torvalds1da177e2005-04-16 15:20:36 -07006497 iounmap(ivideo->mmio_vbase);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006498 iounmap(ivideo->video_vbase);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006499
6500 /* Release mem regions */
6501 release_mem_region(ivideo->video_base, ivideo->video_size);
6502 release_mem_region(ivideo->mmio_base, ivideo->mmio_size);
6503
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006504 vfree(ivideo->bios_abase);
6505
6506 if(ivideo->lpcdev)
Adrian Bunk0959f0c2007-05-08 00:39:50 -07006507 pci_dev_put(ivideo->lpcdev);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006508
6509 if(ivideo->nbridge)
Adrian Bunk0959f0c2007-05-08 00:39:50 -07006510 pci_dev_put(ivideo->nbridge);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006511
Linus Torvalds1da177e2005-04-16 15:20:36 -07006512#ifdef CONFIG_MTRR
6513 /* Release MTRR region */
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006514 if(ivideo->mtrr >= 0)
Linus Torvalds1da177e2005-04-16 15:20:36 -07006515 mtrr_del(ivideo->mtrr, ivideo->video_base, ivideo->video_size);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006516#endif
6517
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006518 pci_set_drvdata(pdev, NULL);
6519
6520 /* If device was disabled when starting, disable
6521 * it when quitting.
6522 */
6523 if(!ivideo->sisvga_enabled)
6524 pci_disable_device(pdev);
6525
Linus Torvalds1da177e2005-04-16 15:20:36 -07006526 /* Unregister the framebuffer */
6527 if(ivideo->registered) {
6528 unregister_framebuffer(sis_fb_info);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006529 framebuffer_release(sis_fb_info);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006530 }
6531
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006532 /* OK, our ivideo is gone for good from here. */
Linus Torvalds1da177e2005-04-16 15:20:36 -07006533
6534 /* TODO: Restore the initial mode
6535 * This sounds easy but is as good as impossible
6536 * on many machines with SiS chip and video bridge
6537 * since text modes are always set up differently
6538 * from machine to machine. Depends on the type
6539 * of integration between chipset and bridge.
6540 */
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006541 if(registered && modechanged)
6542 printk(KERN_INFO
6543 "sisfb: Restoring of text mode not supported yet\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07006544};
6545
6546static struct pci_driver sisfb_driver = {
6547 .name = "sisfb",
6548 .id_table = sisfb_pci_table,
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006549 .probe = sisfb_probe,
Linus Torvalds1da177e2005-04-16 15:20:36 -07006550 .remove = __devexit_p(sisfb_remove)
6551};
6552
6553SISINITSTATIC int __init sisfb_init(void)
6554{
Linus Torvalds1da177e2005-04-16 15:20:36 -07006555#ifndef MODULE
6556 char *options = NULL;
6557
6558 if(fb_get_options("sisfb", &options))
6559 return -ENODEV;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006560
Linus Torvalds1da177e2005-04-16 15:20:36 -07006561 sisfb_setup(options);
6562#endif
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006563 return pci_register_driver(&sisfb_driver);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006564}
6565
Linus Torvalds1da177e2005-04-16 15:20:36 -07006566#ifndef MODULE
6567module_init(sisfb_init);
6568#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -07006569
6570/*****************************************************/
6571/* MODULE */
6572/*****************************************************/
6573
6574#ifdef MODULE
6575
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006576static char *mode = NULL;
6577static int vesa = -1;
6578static unsigned int rate = 0;
6579static unsigned int crt1off = 1;
6580static unsigned int mem = 0;
6581static char *forcecrt2type = NULL;
6582static int forcecrt1 = -1;
6583static int pdc = -1;
6584static int pdc1 = -1;
6585static int noaccel = -1;
6586static int noypan = -1;
6587static int nomax = -1;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006588static int userom = -1;
6589static int useoem = -1;
6590static char *tvstandard = NULL;
6591static int nocrt2rate = 0;
6592static int scalelcd = -1;
6593static char *specialtiming = NULL;
6594static int lvdshl = -1;
6595static int tvxposoffset = 0, tvyposoffset = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006596#if !defined(__i386__) && !defined(__x86_64__)
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006597static int resetcard = 0;
6598static int videoram = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006599#endif
6600
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006601static int __init sisfb_init_module(void)
6602{
6603 sisfb_setdefaultparms();
6604
6605 if(rate)
6606 sisfb_parm_rate = rate;
6607
6608 if((scalelcd == 0) || (scalelcd == 1))
6609 sisfb_scalelcd = scalelcd ^ 1;
6610
6611 /* Need to check crt2 type first for fstn/dstn */
6612
6613 if(forcecrt2type)
6614 sisfb_search_crt2type(forcecrt2type);
6615
6616 if(tvstandard)
6617 sisfb_search_tvstd(tvstandard);
6618
6619 if(mode)
Richard Knutssonc30660ea2007-02-12 00:55:06 -08006620 sisfb_search_mode(mode, false);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006621 else if(vesa != -1)
Richard Knutssonc30660ea2007-02-12 00:55:06 -08006622 sisfb_search_vesamode(vesa, false);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006623
6624 sisfb_crt1off = (crt1off == 0) ? 1 : 0;
6625
6626 sisfb_forcecrt1 = forcecrt1;
6627 if(forcecrt1 == 1)
6628 sisfb_crt1off = 0;
6629 else if(forcecrt1 == 0)
6630 sisfb_crt1off = 1;
6631
6632 if(noaccel == 1)
6633 sisfb_accel = 0;
6634 else if(noaccel == 0)
6635 sisfb_accel = 1;
6636
6637 if(noypan == 1)
6638 sisfb_ypan = 0;
6639 else if(noypan == 0)
6640 sisfb_ypan = 1;
6641
6642 if(nomax == 1)
6643 sisfb_max = 0;
6644 else if(nomax == 0)
6645 sisfb_max = 1;
6646
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006647 if(mem)
6648 sisfb_parm_mem = mem;
6649
6650 if(userom != -1)
6651 sisfb_userom = userom;
6652
6653 if(useoem != -1)
6654 sisfb_useoem = useoem;
6655
6656 if(pdc != -1)
6657 sisfb_pdc = (pdc & 0x7f);
6658
6659 if(pdc1 != -1)
6660 sisfb_pdca = (pdc1 & 0x1f);
6661
6662 sisfb_nocrt2rate = nocrt2rate;
6663
6664 if(specialtiming)
6665 sisfb_search_specialtiming(specialtiming);
6666
6667 if((lvdshl >= 0) && (lvdshl <= 3))
6668 sisfb_lvdshl = lvdshl;
6669
6670 sisfb_tvxposoffset = tvxposoffset;
6671 sisfb_tvyposoffset = tvyposoffset;
6672
6673#if !defined(__i386__) && !defined(__x86_64__)
6674 sisfb_resetcard = (resetcard) ? 1 : 0;
6675 if(videoram)
6676 sisfb_videoram = videoram;
6677#endif
6678
6679 return sisfb_init();
6680}
6681
6682static void __exit sisfb_remove_module(void)
6683{
6684 pci_unregister_driver(&sisfb_driver);
6685 printk(KERN_DEBUG "sisfb: Module unloaded\n");
6686}
6687
6688module_init(sisfb_init_module);
6689module_exit(sisfb_remove_module);
6690
6691MODULE_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 -07006692MODULE_LICENSE("GPL");
6693MODULE_AUTHOR("Thomas Winischhofer <thomas@winischhofer.net>, Others");
6694
Linus Torvalds1da177e2005-04-16 15:20:36 -07006695module_param(mem, int, 0);
6696module_param(noaccel, int, 0);
6697module_param(noypan, int, 0);
6698module_param(nomax, int, 0);
6699module_param(userom, int, 0);
6700module_param(useoem, int, 0);
6701module_param(mode, charp, 0);
6702module_param(vesa, int, 0);
6703module_param(rate, int, 0);
6704module_param(forcecrt1, int, 0);
6705module_param(forcecrt2type, charp, 0);
6706module_param(scalelcd, int, 0);
6707module_param(pdc, int, 0);
6708module_param(pdc1, int, 0);
6709module_param(specialtiming, charp, 0);
6710module_param(lvdshl, int, 0);
6711module_param(tvstandard, charp, 0);
6712module_param(tvxposoffset, int, 0);
6713module_param(tvyposoffset, int, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006714module_param(nocrt2rate, int, 0);
6715#if !defined(__i386__) && !defined(__x86_64__)
6716module_param(resetcard, int, 0);
6717module_param(videoram, int, 0);
6718#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -07006719
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006720MODULE_PARM_DESC(mem,
6721 "\nDetermines the beginning of the video memory heap in KB. This heap is used\n"
6722 "for video RAM management for eg. DRM/DRI. On 300 series, the default depends\n"
6723 "on the amount of video RAM available. If 8MB of video RAM or less is available,\n"
6724 "the heap starts at 4096KB, if between 8 and 16MB are available at 8192KB,\n"
6725 "otherwise at 12288KB. On 315/330/340 series, the heap size is 32KB by default.\n"
6726 "The value is to be specified without 'KB'.\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07006727
6728MODULE_PARM_DESC(noaccel,
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006729 "\nIf set to anything other than 0, 2D acceleration will be disabled.\n"
Linus Torvalds1da177e2005-04-16 15:20:36 -07006730 "(default: 0)\n");
6731
6732MODULE_PARM_DESC(noypan,
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006733 "\nIf set to anything other than 0, y-panning will be disabled and scrolling\n"
6734 "will be performed by redrawing the screen. (default: 0)\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07006735
6736MODULE_PARM_DESC(nomax,
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006737 "\nIf y-panning is enabled, sisfb will by default use the entire available video\n"
Linus Torvalds1da177e2005-04-16 15:20:36 -07006738 "memory for the virtual screen in order to optimize scrolling performance. If\n"
6739 "this is set to anything other than 0, sisfb will not do this and thereby \n"
6740 "enable the user to positively specify a virtual Y size of the screen using\n"
6741 "fbset. (default: 0)\n");
6742
Linus Torvalds1da177e2005-04-16 15:20:36 -07006743MODULE_PARM_DESC(mode,
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006744 "\nSelects the desired default display mode in the format XxYxDepth,\n"
6745 "eg. 1024x768x16. Other formats supported include XxY-Depth and\n"
Linus Torvalds1da177e2005-04-16 15:20:36 -07006746 "XxY-Depth@Rate. If the parameter is only one (decimal or hexadecimal)\n"
6747 "number, it will be interpreted as a VESA mode number. (default: 800x600x8)\n");
6748
6749MODULE_PARM_DESC(vesa,
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006750 "\nSelects the desired default display mode by VESA defined mode number, eg.\n"
6751 "0x117 (default: 0x0103)\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07006752
6753MODULE_PARM_DESC(rate,
6754 "\nSelects the desired vertical refresh rate for CRT1 (external VGA) in Hz.\n"
6755 "If the mode is specified in the format XxY-Depth@Rate, this parameter\n"
6756 "will be ignored (default: 60)\n");
6757
6758MODULE_PARM_DESC(forcecrt1,
6759 "\nNormally, the driver autodetects whether or not CRT1 (external VGA) is \n"
6760 "connected. With this option, the detection can be overridden (1=CRT1 ON,\n"
6761 "0=CRT1 OFF) (default: [autodetected])\n");
6762
6763MODULE_PARM_DESC(forcecrt2type,
6764 "\nIf this option is omitted, the driver autodetects CRT2 output devices, such as\n"
6765 "LCD, TV or secondary VGA. With this option, this autodetection can be\n"
6766 "overridden. Possible parameters are LCD, TV, VGA or NONE. NONE disables CRT2.\n"
6767 "On systems with a SiS video bridge, parameters SVIDEO, COMPOSITE or SCART can\n"
6768 "be used instead of TV to override the TV detection. Furthermore, on systems\n"
6769 "with a SiS video bridge, SVIDEO+COMPOSITE, HIVISION, YPBPR480I, YPBPR480P,\n"
6770 "YPBPR720P and YPBPR1080I are understood. However, whether or not these work\n"
6771 "depends on the very hardware in use. (default: [autodetected])\n");
6772
6773MODULE_PARM_DESC(scalelcd,
6774 "\nSetting this to 1 will force the driver to scale the LCD image to the panel's\n"
6775 "native resolution. Setting it to 0 will disable scaling; LVDS panels will\n"
6776 "show black bars around the image, TMDS panels will probably do the scaling\n"
6777 "themselves. Default: 1 on LVDS panels, 0 on TMDS panels\n");
6778
6779MODULE_PARM_DESC(pdc,
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006780 "\nThis is for manually selecting the LCD panel delay compensation. The driver\n"
Linus Torvalds1da177e2005-04-16 15:20:36 -07006781 "should detect this correctly in most cases; however, sometimes this is not\n"
6782 "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 -07006783 "on a 300 series chipset; 6 on other chipsets. If the problem persists, try\n"
6784 "other values (on 300 series: between 4 and 60 in steps of 4; otherwise: any\n"
6785 "value from 0 to 31). (default: autodetected, if LCD is active during start)\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07006786
6787#ifdef CONFIG_FB_SIS_315
6788MODULE_PARM_DESC(pdc1,
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006789 "\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 -07006790 "series only. (default: autodetected if LCD is in LCD-via-CRT1 mode during\n"
6791 "startup) - Note: currently, this has no effect because LCD-via-CRT1 is not\n"
6792 "implemented yet.\n");
6793#endif
6794
6795MODULE_PARM_DESC(specialtiming,
6796 "\nPlease refer to documentation for more information on this option.\n");
6797
6798MODULE_PARM_DESC(lvdshl,
6799 "\nPlease refer to documentation for more information on this option.\n");
6800
6801MODULE_PARM_DESC(tvstandard,
6802 "\nThis allows overriding the BIOS default for the TV standard. Valid choices are\n"
6803 "pal, ntsc, palm and paln. (default: [auto; pal or ntsc only])\n");
6804
6805MODULE_PARM_DESC(tvxposoffset,
6806 "\nRelocate TV output horizontally. Possible parameters: -32 through 32.\n"
6807 "Default: 0\n");
6808
6809MODULE_PARM_DESC(tvyposoffset,
6810 "\nRelocate TV output vertically. Possible parameters: -32 through 32.\n"
6811 "Default: 0\n");
6812
Linus Torvalds1da177e2005-04-16 15:20:36 -07006813MODULE_PARM_DESC(nocrt2rate,
6814 "\nSetting this to 1 will force the driver to use the default refresh rate for\n"
6815 "CRT2 if CRT2 type is VGA. (default: 0, use same rate as CRT1)\n");
6816
Linus Torvalds1da177e2005-04-16 15:20:36 -07006817#if !defined(__i386__) && !defined(__x86_64__)
6818#ifdef CONFIG_FB_SIS_300
6819MODULE_PARM_DESC(resetcard,
6820 "\nSet this to 1 in order to reset (POST) the card on non-x86 machines where\n"
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006821 "the BIOS did not POST the card (only supported for SiS 300/305 and XGI cards\n"
6822 "currently). Default: 0\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07006823
6824MODULE_PARM_DESC(videoram,
6825 "\nSet this to the amount of video RAM (in kilobyte) the card has. Required on\n"
6826 "some non-x86 architectures where the memory auto detection fails. Only\n"
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006827 "relevant if resetcard is set, too. SiS300/305 only. Default: [auto-detect]\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07006828#endif
6829#endif
6830
Linus Torvalds1da177e2005-04-16 15:20:36 -07006831#endif /* /MODULE */
6832
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006833/* _GPL only for new symbols. */
Linus Torvalds1da177e2005-04-16 15:20:36 -07006834EXPORT_SYMBOL(sis_malloc);
6835EXPORT_SYMBOL(sis_free);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006836EXPORT_SYMBOL_GPL(sis_malloc_new);
6837EXPORT_SYMBOL_GPL(sis_free_new);
6838
Linus Torvalds1da177e2005-04-16 15:20:36 -07006839
6840