blob: 346d6458cf76a64ef3a96af133e810c2d8c19505 [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/module.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070037#include <linux/moduleparam.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070038#include <linux/kernel.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070039#include <linux/spinlock.h>
40#include <linux/errno.h>
41#include <linux/string.h>
42#include <linux/mm.h>
Jon Smirla8f340e2006-07-10 04:44:12 -070043#include <linux/screen_info.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070044#include <linux/slab.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070045#include <linux/fb.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070046#include <linux/selection.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070047#include <linux/ioport.h>
48#include <linux/init.h>
49#include <linux/pci.h>
50#include <linux/vmalloc.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070051#include <linux/capability.h>
52#include <linux/fs.h>
53#include <linux/types.h>
Krzysztof Helt84902b72007-10-16 01:29:04 -070054#include <linux/uaccess.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070055#include <asm/io.h>
56#ifdef CONFIG_MTRR
57#include <asm/mtrr.h>
58#endif
59
Linus Torvalds1da177e2005-04-16 15:20:36 -070060#include "sis.h"
61#include "sis_main.h"
62
Thomas Winischhofer544393f2005-09-09 13:04:45 -070063static void sisfb_handle_command(struct sis_video_info *ivideo,
64 struct sisfb_cmd *sisfb_command);
65
Linus Torvalds1da177e2005-04-16 15:20:36 -070066/* ------------------ Internal helper routines ----------------- */
67
68static void __init
69sisfb_setdefaultparms(void)
70{
Thomas Winischhofer544393f2005-09-09 13:04:45 -070071 sisfb_off = 0;
72 sisfb_parm_mem = 0;
73 sisfb_accel = -1;
74 sisfb_ypan = -1;
75 sisfb_max = -1;
76 sisfb_userom = -1;
77 sisfb_useoem = -1;
Thomas Winischhofer544393f2005-09-09 13:04:45 -070078 sisfb_mode_idx = -1;
Thomas Winischhofer544393f2005-09-09 13:04:45 -070079 sisfb_parm_rate = -1;
80 sisfb_crt1off = 0;
81 sisfb_forcecrt1 = -1;
82 sisfb_crt2type = -1;
83 sisfb_crt2flags = 0;
84 sisfb_pdc = 0xff;
85 sisfb_pdca = 0xff;
86 sisfb_scalelcd = -1;
Linus Torvalds1da177e2005-04-16 15:20:36 -070087 sisfb_specialtiming = CUT_NONE;
Thomas Winischhofer544393f2005-09-09 13:04:45 -070088 sisfb_lvdshl = -1;
89 sisfb_dstn = 0;
90 sisfb_fstn = 0;
91 sisfb_tvplug = -1;
92 sisfb_tvstd = -1;
93 sisfb_tvxposoffset = 0;
94 sisfb_tvyposoffset = 0;
95 sisfb_nocrt2rate = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -070096#if !defined(__i386__) && !defined(__x86_64__)
Thomas Winischhofer544393f2005-09-09 13:04:45 -070097 sisfb_resetcard = 0;
98 sisfb_videoram = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -070099#endif
100}
101
Thomas Winischhofer544393f2005-09-09 13:04:45 -0700102/* ------------- Parameter parsing -------------- */
103
Linus Torvalds1da177e2005-04-16 15:20:36 -0700104static void __devinit
Richard Knutssonc30660e2007-02-12 00:55:06 -0800105sisfb_search_vesamode(unsigned int vesamode, bool quiet)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700106{
107 int i = 0, j = 0;
108
Thomas Winischhofer544393f2005-09-09 13:04:45 -0700109 /* We don't know the hardware specs yet and there is no ivideo */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700110
111 if(vesamode == 0) {
Thomas Winischhofer544393f2005-09-09 13:04:45 -0700112 if(!quiet)
113 printk(KERN_ERR "sisfb: Invalid mode. Using default.\n");
114
Linus Torvalds1da177e2005-04-16 15:20:36 -0700115 sisfb_mode_idx = DEFAULT_MODE;
Michal Piotrowski43704092006-10-03 01:15:00 -0700116
Linus Torvalds1da177e2005-04-16 15:20:36 -0700117 return;
118 }
119
120 vesamode &= 0x1dff; /* Clean VESA mode number from other flags */
121
122 while(sisbios_mode[i++].mode_no[0] != 0) {
123 if( (sisbios_mode[i-1].vesa_mode_no_1 == vesamode) ||
124 (sisbios_mode[i-1].vesa_mode_no_2 == vesamode) ) {
Thomas Winischhofer544393f2005-09-09 13:04:45 -0700125 if(sisfb_fstn) {
126 if(sisbios_mode[i-1].mode_no[1] == 0x50 ||
127 sisbios_mode[i-1].mode_no[1] == 0x56 ||
128 sisbios_mode[i-1].mode_no[1] == 0x53)
129 continue;
130 } else {
131 if(sisbios_mode[i-1].mode_no[1] == 0x5a ||
132 sisbios_mode[i-1].mode_no[1] == 0x5b)
133 continue;
134 }
135 sisfb_mode_idx = i - 1;
136 j = 1;
137 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700138 }
139 }
Thomas Winischhofer544393f2005-09-09 13:04:45 -0700140 if((!j) && !quiet)
141 printk(KERN_ERR "sisfb: Invalid VESA mode 0x%x'\n", vesamode);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700142}
143
Thomas Winischhofer544393f2005-09-09 13:04:45 -0700144static void __devinit
Richard Knutssonc30660e2007-02-12 00:55:06 -0800145sisfb_search_mode(char *name, bool quiet)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700146{
Linus Torvalds1da177e2005-04-16 15:20:36 -0700147 unsigned int j = 0, xres = 0, yres = 0, depth = 0, rate = 0;
Thomas Winischhofer544393f2005-09-09 13:04:45 -0700148 int i = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700149 char strbuf[16], strbuf1[20];
150 char *nameptr = name;
151
Thomas Winischhofer544393f2005-09-09 13:04:45 -0700152 /* We don't know the hardware specs yet and there is no ivideo */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700153
154 if(name == NULL) {
Thomas Winischhofer544393f2005-09-09 13:04:45 -0700155 if(!quiet)
156 printk(KERN_ERR "sisfb: Internal error, using default mode.\n");
157
158 sisfb_mode_idx = DEFAULT_MODE;
159 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700160 }
161
Thomas Winischhofer544393f2005-09-09 13:04:45 -0700162 if(!strnicmp(name, sisbios_mode[MODE_INDEX_NONE].name, strlen(name))) {
163 if(!quiet)
164 printk(KERN_ERR "sisfb: Mode 'none' not supported anymore. Using default.\n");
165
166 sisfb_mode_idx = DEFAULT_MODE;
167 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700168 }
Michal Piotrowski43704092006-10-03 01:15:00 -0700169
Linus Torvalds1da177e2005-04-16 15:20:36 -0700170 if(strlen(name) <= 19) {
Thomas Winischhofer544393f2005-09-09 13:04:45 -0700171 strcpy(strbuf1, name);
172 for(i = 0; i < strlen(strbuf1); i++) {
173 if(strbuf1[i] < '0' || strbuf1[i] > '9') strbuf1[i] = ' ';
174 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700175
Thomas Winischhofer544393f2005-09-09 13:04:45 -0700176 /* This does some fuzzy mode naming detection */
177 if(sscanf(strbuf1, "%u %u %u %u", &xres, &yres, &depth, &rate) == 4) {
178 if((rate <= 32) || (depth > 32)) {
179 j = rate; rate = depth; depth = j;
180 }
181 sprintf(strbuf, "%ux%ux%u", xres, yres, depth);
182 nameptr = strbuf;
183 sisfb_parm_rate = rate;
184 } else if(sscanf(strbuf1, "%u %u %u", &xres, &yres, &depth) == 3) {
185 sprintf(strbuf, "%ux%ux%u", xres, yres, depth);
186 nameptr = strbuf;
187 } else {
188 xres = 0;
189 if((sscanf(strbuf1, "%u %u", &xres, &yres) == 2) && (xres != 0)) {
190 sprintf(strbuf, "%ux%ux8", xres, yres);
191 nameptr = strbuf;
192 } else {
193 sisfb_search_vesamode(simple_strtoul(name, NULL, 0), quiet);
194 return;
195 }
196 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700197 }
198
199 i = 0; j = 0;
200 while(sisbios_mode[i].mode_no[0] != 0) {
201 if(!strnicmp(nameptr, sisbios_mode[i++].name, strlen(nameptr))) {
Thomas Winischhofer544393f2005-09-09 13:04:45 -0700202 if(sisfb_fstn) {
203 if(sisbios_mode[i-1].mode_no[1] == 0x50 ||
204 sisbios_mode[i-1].mode_no[1] == 0x56 ||
205 sisbios_mode[i-1].mode_no[1] == 0x53)
206 continue;
207 } else {
208 if(sisbios_mode[i-1].mode_no[1] == 0x5a ||
209 sisbios_mode[i-1].mode_no[1] == 0x5b)
210 continue;
211 }
212 sisfb_mode_idx = i - 1;
213 j = 1;
214 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700215 }
216 }
Thomas Winischhofer544393f2005-09-09 13:04:45 -0700217
218 if((!j) && !quiet)
219 printk(KERN_ERR "sisfb: Invalid mode '%s'\n", nameptr);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700220}
221
222#ifndef MODULE
223static void __devinit
224sisfb_get_vga_mode_from_kernel(void)
225{
Adrian Bunk31c5cdb2006-06-26 00:26:28 -0700226#ifdef CONFIG_X86
Thomas Winischhofer544393f2005-09-09 13:04:45 -0700227 char mymode[32];
Linus Torvalds1da177e2005-04-16 15:20:36 -0700228 int mydepth = screen_info.lfb_depth;
229
230 if(screen_info.orig_video_isVGA != VIDEO_TYPE_VLFB) return;
231
232 if( (screen_info.lfb_width >= 320) && (screen_info.lfb_width <= 2048) &&
233 (screen_info.lfb_height >= 200) && (screen_info.lfb_height <= 1536) &&
234 (mydepth >= 8) && (mydepth <= 32) ) {
235
Thomas Winischhofer544393f2005-09-09 13:04:45 -0700236 if(mydepth == 24) mydepth = 32;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700237
Thomas Winischhofer544393f2005-09-09 13:04:45 -0700238 sprintf(mymode, "%ux%ux%u", screen_info.lfb_width,
239 screen_info.lfb_height,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700240 mydepth);
241
Thomas Winischhofer544393f2005-09-09 13:04:45 -0700242 printk(KERN_DEBUG
243 "sisfb: Using vga mode %s pre-set by kernel as default\n",
244 mymode);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700245
Richard Knutssonc30660e2007-02-12 00:55:06 -0800246 sisfb_search_mode(mymode, true);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700247 }
248#endif
249 return;
250}
251#endif
252
253static void __init
254sisfb_search_crt2type(const char *name)
255{
256 int i = 0;
257
Thomas Winischhofer544393f2005-09-09 13:04:45 -0700258 /* We don't know the hardware specs yet and there is no ivideo */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700259
260 if(name == NULL) return;
261
262 while(sis_crt2type[i].type_no != -1) {
Thomas Winischhofer544393f2005-09-09 13:04:45 -0700263 if(!strnicmp(name, sis_crt2type[i].name, strlen(sis_crt2type[i].name))) {
264 sisfb_crt2type = sis_crt2type[i].type_no;
265 sisfb_tvplug = sis_crt2type[i].tvplug_no;
266 sisfb_crt2flags = sis_crt2type[i].flags;
267 break;
268 }
269 i++;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700270 }
271
272 sisfb_dstn = (sisfb_crt2flags & FL_550_DSTN) ? 1 : 0;
273 sisfb_fstn = (sisfb_crt2flags & FL_550_FSTN) ? 1 : 0;
274
Thomas Winischhofer544393f2005-09-09 13:04:45 -0700275 if(sisfb_crt2type < 0)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700276 printk(KERN_ERR "sisfb: Invalid CRT2 type: %s\n", name);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700277}
278
279static void __init
280sisfb_search_tvstd(const char *name)
281{
282 int i = 0;
283
Thomas Winischhofer544393f2005-09-09 13:04:45 -0700284 /* We don't know the hardware specs yet and there is no ivideo */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700285
Thomas Winischhofer544393f2005-09-09 13:04:45 -0700286 if(name == NULL)
287 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700288
289 while(sis_tvtype[i].type_no != -1) {
Thomas Winischhofer544393f2005-09-09 13:04:45 -0700290 if(!strnicmp(name, sis_tvtype[i].name, strlen(sis_tvtype[i].name))) {
291 sisfb_tvstd = sis_tvtype[i].type_no;
292 break;
293 }
294 i++;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700295 }
296}
297
298static void __init
299sisfb_search_specialtiming(const char *name)
300{
301 int i = 0;
Richard Knutssonc30660e2007-02-12 00:55:06 -0800302 bool found = false;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700303
Thomas Winischhofer544393f2005-09-09 13:04:45 -0700304 /* We don't know the hardware specs yet and there is no ivideo */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700305
Thomas Winischhofer544393f2005-09-09 13:04:45 -0700306 if(name == NULL)
307 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700308
309 if(!strnicmp(name, "none", 4)) {
Thomas Winischhofer544393f2005-09-09 13:04:45 -0700310 sisfb_specialtiming = CUT_FORCENONE;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700311 printk(KERN_DEBUG "sisfb: Special timing disabled\n");
312 } else {
Thomas Winischhofer544393f2005-09-09 13:04:45 -0700313 while(mycustomttable[i].chipID != 0) {
314 if(!strnicmp(name,mycustomttable[i].optionName,
315 strlen(mycustomttable[i].optionName))) {
316 sisfb_specialtiming = mycustomttable[i].SpecialID;
Richard Knutssonc30660e2007-02-12 00:55:06 -0800317 found = true;
Thomas Winischhofer544393f2005-09-09 13:04:45 -0700318 printk(KERN_INFO "sisfb: Special timing for %s %s forced (\"%s\")\n",
319 mycustomttable[i].vendorName,
320 mycustomttable[i].cardName,
321 mycustomttable[i].optionName);
322 break;
323 }
324 i++;
325 }
326 if(!found) {
327 printk(KERN_WARNING "sisfb: Invalid SpecialTiming parameter, valid are:");
328 printk(KERN_WARNING "\t\"none\" (to disable special timings)\n");
329 i = 0;
330 while(mycustomttable[i].chipID != 0) {
331 printk(KERN_WARNING "\t\"%s\" (for %s %s)\n",
332 mycustomttable[i].optionName,
333 mycustomttable[i].vendorName,
334 mycustomttable[i].cardName);
335 i++;
336 }
337 }
338 }
339}
340
341/* ----------- Various detection routines ----------- */
342
343static void __devinit
344sisfb_detect_custom_timing(struct sis_video_info *ivideo)
345{
346 unsigned char *biosver = NULL;
347 unsigned char *biosdate = NULL;
Richard Knutssonc30660e2007-02-12 00:55:06 -0800348 bool footprint;
Thomas Winischhofer544393f2005-09-09 13:04:45 -0700349 u32 chksum = 0;
350 int i, j;
351
352 if(ivideo->SiS_Pr.UseROM) {
353 biosver = ivideo->SiS_Pr.VirtualRomBase + 0x06;
354 biosdate = ivideo->SiS_Pr.VirtualRomBase + 0x2c;
355 for(i = 0; i < 32768; i++)
356 chksum += ivideo->SiS_Pr.VirtualRomBase[i];
357 }
358
359 i = 0;
360 do {
361 if( (mycustomttable[i].chipID == ivideo->chip) &&
362 ((!strlen(mycustomttable[i].biosversion)) ||
363 (ivideo->SiS_Pr.UseROM &&
364 (!strncmp(mycustomttable[i].biosversion, biosver,
365 strlen(mycustomttable[i].biosversion))))) &&
366 ((!strlen(mycustomttable[i].biosdate)) ||
367 (ivideo->SiS_Pr.UseROM &&
368 (!strncmp(mycustomttable[i].biosdate, biosdate,
369 strlen(mycustomttable[i].biosdate))))) &&
370 ((!mycustomttable[i].bioschksum) ||
371 (ivideo->SiS_Pr.UseROM &&
372 (mycustomttable[i].bioschksum == chksum))) &&
373 (mycustomttable[i].pcisubsysvendor == ivideo->subsysvendor) &&
374 (mycustomttable[i].pcisubsyscard == ivideo->subsysdevice) ) {
Richard Knutssonc30660e2007-02-12 00:55:06 -0800375 footprint = true;
Thomas Winischhofer544393f2005-09-09 13:04:45 -0700376 for(j = 0; j < 5; j++) {
377 if(mycustomttable[i].biosFootprintAddr[j]) {
378 if(ivideo->SiS_Pr.UseROM) {
379 if(ivideo->SiS_Pr.VirtualRomBase[mycustomttable[i].biosFootprintAddr[j]] !=
380 mycustomttable[i].biosFootprintData[j]) {
Richard Knutssonc30660e2007-02-12 00:55:06 -0800381 footprint = false;
Thomas Winischhofer544393f2005-09-09 13:04:45 -0700382 }
383 } else
Richard Knutssonc30660e2007-02-12 00:55:06 -0800384 footprint = false;
Thomas Winischhofer544393f2005-09-09 13:04:45 -0700385 }
386 }
387 if(footprint) {
388 ivideo->SiS_Pr.SiS_CustomT = mycustomttable[i].SpecialID;
389 printk(KERN_DEBUG "sisfb: Identified [%s %s], special timing applies\n",
390 mycustomttable[i].vendorName,
391 mycustomttable[i].cardName);
392 printk(KERN_DEBUG "sisfb: [specialtiming parameter name: %s]\n",
393 mycustomttable[i].optionName);
394 break;
395 }
396 }
397 i++;
398 } while(mycustomttable[i].chipID);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700399}
400
Richard Knutssonc30660e2007-02-12 00:55:06 -0800401static bool __devinit
Linus Torvalds1da177e2005-04-16 15:20:36 -0700402sisfb_interpret_edid(struct sisfb_monitor *monitor, u8 *buffer)
403{
404 int i, j, xres, yres, refresh, index;
405 u32 emodes;
406
407 if(buffer[0] != 0x00 || buffer[1] != 0xff ||
408 buffer[2] != 0xff || buffer[3] != 0xff ||
409 buffer[4] != 0xff || buffer[5] != 0xff ||
410 buffer[6] != 0xff || buffer[7] != 0x00) {
Thomas Winischhofer544393f2005-09-09 13:04:45 -0700411 printk(KERN_DEBUG "sisfb: Bad EDID header\n");
Richard Knutssonc30660e2007-02-12 00:55:06 -0800412 return false;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700413 }
414
415 if(buffer[0x12] != 0x01) {
Thomas Winischhofer544393f2005-09-09 13:04:45 -0700416 printk(KERN_INFO "sisfb: EDID version %d not supported\n",
417 buffer[0x12]);
Richard Knutssonc30660e2007-02-12 00:55:06 -0800418 return false;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700419 }
420
421 monitor->feature = buffer[0x18];
422
Alexey Dobriyaneaa0ff12008-02-06 01:36:06 -0800423 if(!(buffer[0x14] & 0x80)) {
Thomas Winischhofer544393f2005-09-09 13:04:45 -0700424 if(!(buffer[0x14] & 0x08)) {
425 printk(KERN_INFO
426 "sisfb: WARNING: Monitor does not support separate syncs\n");
427 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700428 }
429
430 if(buffer[0x13] >= 0x01) {
431 /* EDID V1 rev 1 and 2: Search for monitor descriptor
432 * to extract ranges
433 */
434 j = 0x36;
435 for(i=0; i<4; i++) {
436 if(buffer[j] == 0x00 && buffer[j + 1] == 0x00 &&
Thomas Winischhofer544393f2005-09-09 13:04:45 -0700437 buffer[j + 2] == 0x00 && buffer[j + 3] == 0xfd &&
Linus Torvalds1da177e2005-04-16 15:20:36 -0700438 buffer[j + 4] == 0x00) {
439 monitor->hmin = buffer[j + 7];
440 monitor->hmax = buffer[j + 8];
441 monitor->vmin = buffer[j + 5];
442 monitor->vmax = buffer[j + 6];
443 monitor->dclockmax = buffer[j + 9] * 10 * 1000;
Richard Knutssonc30660e2007-02-12 00:55:06 -0800444 monitor->datavalid = true;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700445 break;
446 }
447 j += 18;
448 }
449 }
450
451 if(!monitor->datavalid) {
452 /* Otherwise: Get a range from the list of supported
453 * Estabished Timings. This is not entirely accurate,
454 * because fixed frequency monitors are not supported
455 * that way.
456 */
457 monitor->hmin = 65535; monitor->hmax = 0;
458 monitor->vmin = 65535; monitor->vmax = 0;
459 monitor->dclockmax = 0;
460 emodes = buffer[0x23] | (buffer[0x24] << 8) | (buffer[0x25] << 16);
461 for(i = 0; i < 13; i++) {
462 if(emodes & sisfb_ddcsmodes[i].mask) {
Thomas Winischhofer544393f2005-09-09 13:04:45 -0700463 if(monitor->hmin > sisfb_ddcsmodes[i].h) monitor->hmin = sisfb_ddcsmodes[i].h;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700464 if(monitor->hmax < sisfb_ddcsmodes[i].h) monitor->hmax = sisfb_ddcsmodes[i].h + 1;
465 if(monitor->vmin > sisfb_ddcsmodes[i].v) monitor->vmin = sisfb_ddcsmodes[i].v;
466 if(monitor->vmax < sisfb_ddcsmodes[i].v) monitor->vmax = sisfb_ddcsmodes[i].v;
467 if(monitor->dclockmax < sisfb_ddcsmodes[i].d) monitor->dclockmax = sisfb_ddcsmodes[i].d;
468 }
469 }
470 index = 0x26;
471 for(i = 0; i < 8; i++) {
472 xres = (buffer[index] + 31) * 8;
473 switch(buffer[index + 1] & 0xc0) {
Thomas Winischhofer544393f2005-09-09 13:04:45 -0700474 case 0xc0: yres = (xres * 9) / 16; break;
475 case 0x80: yres = (xres * 4) / 5; break;
476 case 0x40: yres = (xres * 3) / 4; break;
477 default: yres = xres; break;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700478 }
479 refresh = (buffer[index + 1] & 0x3f) + 60;
480 if((xres >= 640) && (yres >= 480)) {
Thomas Winischhofer544393f2005-09-09 13:04:45 -0700481 for(j = 0; j < 8; j++) {
482 if((xres == sisfb_ddcfmodes[j].x) &&
483 (yres == sisfb_ddcfmodes[j].y) &&
Linus Torvalds1da177e2005-04-16 15:20:36 -0700484 (refresh == sisfb_ddcfmodes[j].v)) {
485 if(monitor->hmin > sisfb_ddcfmodes[j].h) monitor->hmin = sisfb_ddcfmodes[j].h;
486 if(monitor->hmax < sisfb_ddcfmodes[j].h) monitor->hmax = sisfb_ddcfmodes[j].h + 1;
487 if(monitor->vmin > sisfb_ddcsmodes[j].v) monitor->vmin = sisfb_ddcsmodes[j].v;
488 if(monitor->vmax < sisfb_ddcsmodes[j].v) monitor->vmax = sisfb_ddcsmodes[j].v;
Thomas Winischhofer544393f2005-09-09 13:04:45 -0700489 if(monitor->dclockmax < sisfb_ddcsmodes[j].d) monitor->dclockmax = sisfb_ddcsmodes[j].d;
490 }
491 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700492 }
493 index += 2;
Thomas Winischhofer544393f2005-09-09 13:04:45 -0700494 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700495 if((monitor->hmin <= monitor->hmax) && (monitor->vmin <= monitor->vmax)) {
Richard Knutssonc30660e2007-02-12 00:55:06 -0800496 monitor->datavalid = true;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700497 }
498 }
499
Thomas Winischhofer544393f2005-09-09 13:04:45 -0700500 return monitor->datavalid;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700501}
502
503static void __devinit
504sisfb_handle_ddc(struct sis_video_info *ivideo, struct sisfb_monitor *monitor, int crtno)
505{
Thomas Winischhofer544393f2005-09-09 13:04:45 -0700506 unsigned short temp, i, realcrtno = crtno;
507 unsigned char buffer[256];
Linus Torvalds1da177e2005-04-16 15:20:36 -0700508
Richard Knutssonc30660e2007-02-12 00:55:06 -0800509 monitor->datavalid = false;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700510
511 if(crtno) {
Thomas Winischhofer544393f2005-09-09 13:04:45 -0700512 if(ivideo->vbflags & CRT2_LCD) realcrtno = 1;
513 else if(ivideo->vbflags & CRT2_VGA) realcrtno = 2;
514 else return;
515 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700516
Thomas Winischhofer544393f2005-09-09 13:04:45 -0700517 if((ivideo->sisfb_crt1off) && (!crtno))
518 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700519
Thomas Winischhofer544393f2005-09-09 13:04:45 -0700520 temp = SiS_HandleDDC(&ivideo->SiS_Pr, ivideo->vbflags, ivideo->sisvga_engine,
521 realcrtno, 0, &buffer[0], ivideo->vbflags2);
522 if((!temp) || (temp == 0xffff)) {
523 printk(KERN_INFO "sisfb: CRT%d DDC probing failed\n", crtno + 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700524 return;
Thomas Winischhofer544393f2005-09-09 13:04:45 -0700525 } else {
526 printk(KERN_INFO "sisfb: CRT%d DDC supported\n", crtno + 1);
527 printk(KERN_INFO "sisfb: CRT%d DDC level: %s%s%s%s\n",
528 crtno + 1,
529 (temp & 0x1a) ? "" : "[none of the supported]",
530 (temp & 0x02) ? "2 " : "",
531 (temp & 0x08) ? "D&P" : "",
532 (temp & 0x10) ? "FPDI-2" : "");
533 if(temp & 0x02) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700534 i = 3; /* Number of retrys */
535 do {
Thomas Winischhofer544393f2005-09-09 13:04:45 -0700536 temp = SiS_HandleDDC(&ivideo->SiS_Pr, ivideo->vbflags, ivideo->sisvga_engine,
537 realcrtno, 1, &buffer[0], ivideo->vbflags2);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700538 } while((temp) && i--);
Thomas Winischhofer544393f2005-09-09 13:04:45 -0700539 if(!temp) {
540 if(sisfb_interpret_edid(monitor, &buffer[0])) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700541 printk(KERN_INFO "sisfb: Monitor range H %d-%dKHz, V %d-%dHz, Max. dotclock %dMHz\n",
Thomas Winischhofer544393f2005-09-09 13:04:45 -0700542 monitor->hmin, monitor->hmax, monitor->vmin, monitor->vmax,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700543 monitor->dclockmax / 1000);
544 } else {
Thomas Winischhofer544393f2005-09-09 13:04:45 -0700545 printk(KERN_INFO "sisfb: CRT%d DDC EDID corrupt\n", crtno + 1);
546 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700547 } else {
Thomas Winischhofer544393f2005-09-09 13:04:45 -0700548 printk(KERN_INFO "sisfb: CRT%d DDC reading failed\n", crtno + 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700549 }
550 } else {
551 printk(KERN_INFO "sisfb: VESA D&P and FPDI-2 not supported yet\n");
552 }
553 }
554}
555
Thomas Winischhofer544393f2005-09-09 13:04:45 -0700556/* -------------- Mode validation --------------- */
557
Richard Knutssonc30660e2007-02-12 00:55:06 -0800558static bool
Linus Torvalds1da177e2005-04-16 15:20:36 -0700559sisfb_verify_rate(struct sis_video_info *ivideo, struct sisfb_monitor *monitor,
560 int mode_idx, int rate_idx, int rate)
561{
562 int htotal, vtotal;
563 unsigned int dclock, hsync;
564
Thomas Winischhofer544393f2005-09-09 13:04:45 -0700565 if(!monitor->datavalid)
Richard Knutssonc30660e2007-02-12 00:55:06 -0800566 return true;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700567
Thomas Winischhofer544393f2005-09-09 13:04:45 -0700568 if(mode_idx < 0)
Richard Knutssonc30660e2007-02-12 00:55:06 -0800569 return false;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700570
571 /* Skip for 320x200, 320x240, 640x400 */
Thomas Winischhofer544393f2005-09-09 13:04:45 -0700572 switch(sisbios_mode[mode_idx].mode_no[ivideo->mni]) {
573 case 0x59:
574 case 0x41:
575 case 0x4f:
576 case 0x50:
577 case 0x56:
578 case 0x53:
579 case 0x2f:
580 case 0x5d:
581 case 0x5e:
Richard Knutssonc30660e2007-02-12 00:55:06 -0800582 return true;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700583#ifdef CONFIG_FB_SIS_315
584 case 0x5a:
585 case 0x5b:
Richard Knutssonc30660e2007-02-12 00:55:06 -0800586 if(ivideo->sisvga_engine == SIS_315_VGA) return true;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700587#endif
Thomas Winischhofer544393f2005-09-09 13:04:45 -0700588 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700589
Thomas Winischhofer544393f2005-09-09 13:04:45 -0700590 if(rate < (monitor->vmin - 1))
Richard Knutssonc30660e2007-02-12 00:55:06 -0800591 return false;
Thomas Winischhofer544393f2005-09-09 13:04:45 -0700592 if(rate > (monitor->vmax + 1))
Richard Knutssonc30660e2007-02-12 00:55:06 -0800593 return false;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700594
Thomas Winischhofer544393f2005-09-09 13:04:45 -0700595 if(sisfb_gettotalfrommode(&ivideo->SiS_Pr,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700596 sisbios_mode[mode_idx].mode_no[ivideo->mni],
Thomas Winischhofer544393f2005-09-09 13:04:45 -0700597 &htotal, &vtotal, rate_idx)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700598 dclock = (htotal * vtotal * rate) / 1000;
Thomas Winischhofer544393f2005-09-09 13:04:45 -0700599 if(dclock > (monitor->dclockmax + 1000))
Richard Knutssonc30660e2007-02-12 00:55:06 -0800600 return false;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700601 hsync = dclock / htotal;
Thomas Winischhofer544393f2005-09-09 13:04:45 -0700602 if(hsync < (monitor->hmin - 1))
Richard Knutssonc30660e2007-02-12 00:55:06 -0800603 return false;
Thomas Winischhofer544393f2005-09-09 13:04:45 -0700604 if(hsync > (monitor->hmax + 1))
Richard Knutssonc30660e2007-02-12 00:55:06 -0800605 return false;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700606 } else {
Richard Knutssonc30660e2007-02-12 00:55:06 -0800607 return false;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700608 }
Richard Knutssonc30660e2007-02-12 00:55:06 -0800609 return true;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700610}
611
612static int
613sisfb_validate_mode(struct sis_video_info *ivideo, int myindex, u32 vbflags)
614{
Thomas Winischhofer544393f2005-09-09 13:04:45 -0700615 u16 xres=0, yres, myres;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700616
617#ifdef CONFIG_FB_SIS_300
Thomas Winischhofer544393f2005-09-09 13:04:45 -0700618 if(ivideo->sisvga_engine == SIS_300_VGA) {
619 if(!(sisbios_mode[myindex].chipset & MD_SIS300))
620 return -1 ;
621 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700622#endif
623#ifdef CONFIG_FB_SIS_315
Thomas Winischhofer544393f2005-09-09 13:04:45 -0700624 if(ivideo->sisvga_engine == SIS_315_VGA) {
625 if(!(sisbios_mode[myindex].chipset & MD_SIS315))
626 return -1;
627 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700628#endif
629
Thomas Winischhofer544393f2005-09-09 13:04:45 -0700630 myres = sisbios_mode[myindex].yres;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700631
Thomas Winischhofer544393f2005-09-09 13:04:45 -0700632 switch(vbflags & VB_DISPTYPE_DISP2) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700633
Thomas Winischhofer544393f2005-09-09 13:04:45 -0700634 case CRT2_LCD:
635 xres = ivideo->lcdxres; yres = ivideo->lcdyres;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700636
Thomas Winischhofer544393f2005-09-09 13:04:45 -0700637 if((ivideo->SiS_Pr.SiS_CustomT != CUT_PANEL848) &&
638 (ivideo->SiS_Pr.SiS_CustomT != CUT_PANEL856)) {
639 if(sisbios_mode[myindex].xres > xres)
640 return -1;
641 if(myres > yres)
642 return -1;
643 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700644
Thomas Winischhofer544393f2005-09-09 13:04:45 -0700645 if(ivideo->sisfb_fstn) {
646 if(sisbios_mode[myindex].xres == 320) {
647 if(myres == 240) {
648 switch(sisbios_mode[myindex].mode_no[1]) {
649 case 0x50: myindex = MODE_FSTN_8; break;
650 case 0x56: myindex = MODE_FSTN_16; break;
651 case 0x53: return -1;
652 }
653 }
654 }
655 }
656
657 if(SiS_GetModeID_LCD(ivideo->sisvga_engine, vbflags, sisbios_mode[myindex].xres,
658 sisbios_mode[myindex].yres, 0, ivideo->sisfb_fstn,
659 ivideo->SiS_Pr.SiS_CustomT, xres, yres, ivideo->vbflags2) < 0x14) {
660 return -1;
661 }
662 break;
663
664 case CRT2_TV:
665 if(SiS_GetModeID_TV(ivideo->sisvga_engine, vbflags, sisbios_mode[myindex].xres,
666 sisbios_mode[myindex].yres, 0, ivideo->vbflags2) < 0x14) {
667 return -1;
668 }
669 break;
670
671 case CRT2_VGA:
672 if(SiS_GetModeID_VGA2(ivideo->sisvga_engine, vbflags, sisbios_mode[myindex].xres,
673 sisbios_mode[myindex].yres, 0, ivideo->vbflags2) < 0x14) {
674 return -1;
675 }
676 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700677 }
678
Thomas Winischhofer544393f2005-09-09 13:04:45 -0700679 return myindex;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700680}
681
682static u8
683sisfb_search_refresh_rate(struct sis_video_info *ivideo, unsigned int rate, int mode_idx)
684{
Linus Torvalds1da177e2005-04-16 15:20:36 -0700685 int i = 0;
Thomas Winischhofer544393f2005-09-09 13:04:45 -0700686 u16 xres = sisbios_mode[mode_idx].xres;
687 u16 yres = sisbios_mode[mode_idx].yres;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700688
689 ivideo->rate_idx = 0;
690 while((sisfb_vrate[i].idx != 0) && (sisfb_vrate[i].xres <= xres)) {
691 if((sisfb_vrate[i].xres == xres) && (sisfb_vrate[i].yres == yres)) {
692 if(sisfb_vrate[i].refresh == rate) {
693 ivideo->rate_idx = sisfb_vrate[i].idx;
694 break;
695 } else if(sisfb_vrate[i].refresh > rate) {
696 if((sisfb_vrate[i].refresh - rate) <= 3) {
697 DPRINTK("sisfb: Adjusting rate from %d up to %d\n",
698 rate, sisfb_vrate[i].refresh);
699 ivideo->rate_idx = sisfb_vrate[i].idx;
700 ivideo->refresh_rate = sisfb_vrate[i].refresh;
701 } else if(((rate - sisfb_vrate[i-1].refresh) <= 2)
702 && (sisfb_vrate[i].idx != 1)) {
703 DPRINTK("sisfb: Adjusting rate from %d down to %d\n",
704 rate, sisfb_vrate[i-1].refresh);
705 ivideo->rate_idx = sisfb_vrate[i-1].idx;
706 ivideo->refresh_rate = sisfb_vrate[i-1].refresh;
Thomas Winischhofer544393f2005-09-09 13:04:45 -0700707 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700708 break;
709 } else if((rate - sisfb_vrate[i].refresh) <= 2) {
710 DPRINTK("sisfb: Adjusting rate from %d down to %d\n",
711 rate, sisfb_vrate[i].refresh);
Thomas Winischhofer544393f2005-09-09 13:04:45 -0700712 ivideo->rate_idx = sisfb_vrate[i].idx;
713 break;
714 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700715 }
716 i++;
717 }
718 if(ivideo->rate_idx > 0) {
719 return ivideo->rate_idx;
720 } else {
721 printk(KERN_INFO "sisfb: Unsupported rate %d for %dx%d\n",
722 rate, xres, yres);
723 return 0;
724 }
725}
726
Richard Knutssonc30660e2007-02-12 00:55:06 -0800727static bool
Linus Torvalds1da177e2005-04-16 15:20:36 -0700728sisfb_bridgeisslave(struct sis_video_info *ivideo)
729{
Thomas Winischhofer544393f2005-09-09 13:04:45 -0700730 unsigned char P1_00;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700731
Thomas Winischhofer544393f2005-09-09 13:04:45 -0700732 if(!(ivideo->vbflags2 & VB2_VIDEOBRIDGE))
Richard Knutssonc30660e2007-02-12 00:55:06 -0800733 return false;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700734
Thomas Winischhofer544393f2005-09-09 13:04:45 -0700735 inSISIDXREG(SISPART1,0x00,P1_00);
736 if( ((ivideo->sisvga_engine == SIS_300_VGA) && (P1_00 & 0xa0) == 0x20) ||
737 ((ivideo->sisvga_engine == SIS_315_VGA) && (P1_00 & 0x50) == 0x10) ) {
Richard Knutssonc30660e2007-02-12 00:55:06 -0800738 return true;
Thomas Winischhofer544393f2005-09-09 13:04:45 -0700739 } else {
Richard Knutssonc30660e2007-02-12 00:55:06 -0800740 return false;
Thomas Winischhofer544393f2005-09-09 13:04:45 -0700741 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700742}
743
Richard Knutssonc30660e2007-02-12 00:55:06 -0800744static bool
Linus Torvalds1da177e2005-04-16 15:20:36 -0700745sisfballowretracecrt1(struct sis_video_info *ivideo)
746{
Thomas Winischhofer544393f2005-09-09 13:04:45 -0700747 u8 temp;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700748
Thomas Winischhofer544393f2005-09-09 13:04:45 -0700749 inSISIDXREG(SISCR,0x17,temp);
750 if(!(temp & 0x80))
Richard Knutssonc30660e2007-02-12 00:55:06 -0800751 return false;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700752
Thomas Winischhofer544393f2005-09-09 13:04:45 -0700753 inSISIDXREG(SISSR,0x1f,temp);
754 if(temp & 0xc0)
Richard Knutssonc30660e2007-02-12 00:55:06 -0800755 return false;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700756
Richard Knutssonc30660e2007-02-12 00:55:06 -0800757 return true;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700758}
759
Richard Knutssonc30660e2007-02-12 00:55:06 -0800760static bool
Linus Torvalds1da177e2005-04-16 15:20:36 -0700761sisfbcheckvretracecrt1(struct sis_video_info *ivideo)
762{
Thomas Winischhofer544393f2005-09-09 13:04:45 -0700763 if(!sisfballowretracecrt1(ivideo))
Richard Knutssonc30660e2007-02-12 00:55:06 -0800764 return false;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700765
Thomas Winischhofer544393f2005-09-09 13:04:45 -0700766 if(inSISREG(SISINPSTAT) & 0x08)
Richard Knutssonc30660e2007-02-12 00:55:06 -0800767 return true;
Thomas Winischhofer544393f2005-09-09 13:04:45 -0700768 else
Richard Knutssonc30660e2007-02-12 00:55:06 -0800769 return false;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700770}
771
772static void
773sisfbwaitretracecrt1(struct sis_video_info *ivideo)
774{
Thomas Winischhofer544393f2005-09-09 13:04:45 -0700775 int watchdog;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700776
Thomas Winischhofer544393f2005-09-09 13:04:45 -0700777 if(!sisfballowretracecrt1(ivideo))
778 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700779
Thomas Winischhofer544393f2005-09-09 13:04:45 -0700780 watchdog = 65536;
781 while((!(inSISREG(SISINPSTAT) & 0x08)) && --watchdog);
782 watchdog = 65536;
783 while((inSISREG(SISINPSTAT) & 0x08) && --watchdog);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700784}
785
Richard Knutssonc30660e2007-02-12 00:55:06 -0800786static bool
Linus Torvalds1da177e2005-04-16 15:20:36 -0700787sisfbcheckvretracecrt2(struct sis_video_info *ivideo)
788{
Thomas Winischhofer544393f2005-09-09 13:04:45 -0700789 unsigned char temp, reg;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700790
Thomas Winischhofer544393f2005-09-09 13:04:45 -0700791 switch(ivideo->sisvga_engine) {
792 case SIS_300_VGA: reg = 0x25; break;
793 case SIS_315_VGA: reg = 0x30; break;
Richard Knutssonc30660e2007-02-12 00:55:06 -0800794 default: return false;
Thomas Winischhofer544393f2005-09-09 13:04:45 -0700795 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700796
Thomas Winischhofer544393f2005-09-09 13:04:45 -0700797 inSISIDXREG(SISPART1, reg, temp);
798 if(temp & 0x02)
Richard Knutssonc30660e2007-02-12 00:55:06 -0800799 return true;
Thomas Winischhofer544393f2005-09-09 13:04:45 -0700800 else
Richard Knutssonc30660e2007-02-12 00:55:06 -0800801 return false;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700802}
803
Richard Knutssonc30660e2007-02-12 00:55:06 -0800804static bool
Linus Torvalds1da177e2005-04-16 15:20:36 -0700805sisfb_CheckVBRetrace(struct sis_video_info *ivideo)
806{
Thomas Winischhofer544393f2005-09-09 13:04:45 -0700807 if(ivideo->currentvbflags & VB_DISPTYPE_DISP2) {
808 if(!sisfb_bridgeisslave(ivideo)) {
809 return sisfbcheckvretracecrt2(ivideo);
810 }
811 }
812 return sisfbcheckvretracecrt1(ivideo);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700813}
814
815static u32
816sisfb_setupvbblankflags(struct sis_video_info *ivideo, u32 *vcount, u32 *hcount)
817{
Thomas Winischhofer544393f2005-09-09 13:04:45 -0700818 u8 idx, reg1, reg2, reg3, reg4;
819 u32 ret = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700820
Thomas Winischhofer544393f2005-09-09 13:04:45 -0700821 (*vcount) = (*hcount) = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700822
Thomas Winischhofer544393f2005-09-09 13:04:45 -0700823 if((ivideo->currentvbflags & VB_DISPTYPE_DISP2) && (!(sisfb_bridgeisslave(ivideo)))) {
824
825 ret |= (FB_VBLANK_HAVE_VSYNC |
826 FB_VBLANK_HAVE_HBLANK |
827 FB_VBLANK_HAVE_VBLANK |
828 FB_VBLANK_HAVE_VCOUNT |
829 FB_VBLANK_HAVE_HCOUNT);
830 switch(ivideo->sisvga_engine) {
831 case SIS_300_VGA: idx = 0x25; break;
832 default:
833 case SIS_315_VGA: idx = 0x30; break;
834 }
835 inSISIDXREG(SISPART1,(idx+0),reg1); /* 30 */
836 inSISIDXREG(SISPART1,(idx+1),reg2); /* 31 */
837 inSISIDXREG(SISPART1,(idx+2),reg3); /* 32 */
838 inSISIDXREG(SISPART1,(idx+3),reg4); /* 33 */
839 if(reg1 & 0x01) ret |= FB_VBLANK_VBLANKING;
840 if(reg1 & 0x02) ret |= FB_VBLANK_VSYNCING;
841 if(reg4 & 0x80) ret |= FB_VBLANK_HBLANKING;
842 (*vcount) = reg3 | ((reg4 & 0x70) << 4);
843 (*hcount) = reg2 | ((reg4 & 0x0f) << 8);
844
845 } else if(sisfballowretracecrt1(ivideo)) {
846
847 ret |= (FB_VBLANK_HAVE_VSYNC |
848 FB_VBLANK_HAVE_VBLANK |
849 FB_VBLANK_HAVE_VCOUNT |
850 FB_VBLANK_HAVE_HCOUNT);
851 reg1 = inSISREG(SISINPSTAT);
852 if(reg1 & 0x08) ret |= FB_VBLANK_VSYNCING;
853 if(reg1 & 0x01) ret |= FB_VBLANK_VBLANKING;
854 inSISIDXREG(SISCR,0x20,reg1);
855 inSISIDXREG(SISCR,0x1b,reg1);
856 inSISIDXREG(SISCR,0x1c,reg2);
857 inSISIDXREG(SISCR,0x1d,reg3);
858 (*vcount) = reg2 | ((reg3 & 0x07) << 8);
859 (*hcount) = (reg1 | ((reg3 & 0x10) << 4)) << 3;
860 }
861
862 return ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700863}
864
865static int
866sisfb_myblank(struct sis_video_info *ivideo, int blank)
867{
Thomas Winischhofer544393f2005-09-09 13:04:45 -0700868 u8 sr01, sr11, sr1f, cr63=0, p2_0, p1_13;
Richard Knutssonc30660e2007-02-12 00:55:06 -0800869 bool backlight = true;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700870
Thomas Winischhofer544393f2005-09-09 13:04:45 -0700871 switch(blank) {
872 case FB_BLANK_UNBLANK: /* on */
873 sr01 = 0x00;
874 sr11 = 0x00;
875 sr1f = 0x00;
876 cr63 = 0x00;
877 p2_0 = 0x20;
878 p1_13 = 0x00;
Richard Knutssonc30660e2007-02-12 00:55:06 -0800879 backlight = true;
Thomas Winischhofer544393f2005-09-09 13:04:45 -0700880 break;
881 case FB_BLANK_NORMAL: /* blank */
882 sr01 = 0x20;
883 sr11 = 0x00;
884 sr1f = 0x00;
885 cr63 = 0x00;
886 p2_0 = 0x20;
887 p1_13 = 0x00;
Richard Knutssonc30660e2007-02-12 00:55:06 -0800888 backlight = true;
Thomas Winischhofer544393f2005-09-09 13:04:45 -0700889 break;
890 case FB_BLANK_VSYNC_SUSPEND: /* no vsync */
891 sr01 = 0x20;
892 sr11 = 0x08;
893 sr1f = 0x80;
894 cr63 = 0x40;
895 p2_0 = 0x40;
896 p1_13 = 0x80;
Richard Knutssonc30660e2007-02-12 00:55:06 -0800897 backlight = false;
Thomas Winischhofer544393f2005-09-09 13:04:45 -0700898 break;
899 case FB_BLANK_HSYNC_SUSPEND: /* no hsync */
900 sr01 = 0x20;
901 sr11 = 0x08;
902 sr1f = 0x40;
903 cr63 = 0x40;
904 p2_0 = 0x80;
905 p1_13 = 0x40;
Richard Knutssonc30660e2007-02-12 00:55:06 -0800906 backlight = false;
Thomas Winischhofer544393f2005-09-09 13:04:45 -0700907 break;
908 case FB_BLANK_POWERDOWN: /* off */
909 sr01 = 0x20;
910 sr11 = 0x08;
911 sr1f = 0xc0;
912 cr63 = 0x40;
913 p2_0 = 0xc0;
914 p1_13 = 0xc0;
Richard Knutssonc30660e2007-02-12 00:55:06 -0800915 backlight = false;
Thomas Winischhofer544393f2005-09-09 13:04:45 -0700916 break;
917 default:
918 return 1;
919 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700920
Thomas Winischhofer544393f2005-09-09 13:04:45 -0700921 if(ivideo->currentvbflags & VB_DISPTYPE_CRT1) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700922
Thomas Winischhofer544393f2005-09-09 13:04:45 -0700923 if( (!ivideo->sisfb_thismonitor.datavalid) ||
924 ((ivideo->sisfb_thismonitor.datavalid) &&
925 (ivideo->sisfb_thismonitor.feature & 0xe0))) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700926
Thomas Winischhofer544393f2005-09-09 13:04:45 -0700927 if(ivideo->sisvga_engine == SIS_315_VGA) {
928 setSISIDXREG(SISCR, ivideo->SiS_Pr.SiS_MyCR63, 0xbf, cr63);
929 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700930
Thomas Winischhofer544393f2005-09-09 13:04:45 -0700931 if(!(sisfb_bridgeisslave(ivideo))) {
932 setSISIDXREG(SISSR, 0x01, ~0x20, sr01);
933 setSISIDXREG(SISSR, 0x1f, 0x3f, sr1f);
934 }
935 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700936
Thomas Winischhofer544393f2005-09-09 13:04:45 -0700937 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700938
Thomas Winischhofer544393f2005-09-09 13:04:45 -0700939 if(ivideo->currentvbflags & CRT2_LCD) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700940
Thomas Winischhofer544393f2005-09-09 13:04:45 -0700941 if(ivideo->vbflags2 & VB2_SISLVDSBRIDGE) {
942 if(backlight) {
943 SiS_SiS30xBLOn(&ivideo->SiS_Pr);
944 } else {
945 SiS_SiS30xBLOff(&ivideo->SiS_Pr);
946 }
947 } else if(ivideo->sisvga_engine == SIS_315_VGA) {
948#ifdef CONFIG_FB_SIS_315
949 if(ivideo->vbflags2 & VB2_CHRONTEL) {
950 if(backlight) {
951 SiS_Chrontel701xBLOn(&ivideo->SiS_Pr);
952 } else {
953 SiS_Chrontel701xBLOff(&ivideo->SiS_Pr);
954 }
955 }
956#endif
957 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700958
Thomas Winischhofer544393f2005-09-09 13:04:45 -0700959 if(((ivideo->sisvga_engine == SIS_300_VGA) &&
960 (ivideo->vbflags2 & (VB2_301|VB2_30xBDH|VB2_LVDS))) ||
961 ((ivideo->sisvga_engine == SIS_315_VGA) &&
962 ((ivideo->vbflags2 & (VB2_LVDS | VB2_CHRONTEL)) == VB2_LVDS))) {
963 setSISIDXREG(SISSR, 0x11, ~0x0c, sr11);
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 if((ivideo->vbflags2 & VB2_30xB) &&
968 (!(ivideo->vbflags2 & VB2_30xBDH))) {
969 setSISIDXREG(SISPART1, 0x13, 0x3f, p1_13);
970 }
971 } else if(ivideo->sisvga_engine == SIS_315_VGA) {
972 if((ivideo->vbflags2 & VB2_30xB) &&
973 (!(ivideo->vbflags2 & VB2_30xBDH))) {
974 setSISIDXREG(SISPART2, 0x00, 0x1f, p2_0);
975 }
976 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700977
Thomas Winischhofer544393f2005-09-09 13:04:45 -0700978 } else if(ivideo->currentvbflags & CRT2_VGA) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700979
Thomas Winischhofer544393f2005-09-09 13:04:45 -0700980 if(ivideo->vbflags2 & VB2_30xB) {
981 setSISIDXREG(SISPART2, 0x00, 0x1f, p2_0);
982 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700983
Thomas Winischhofer544393f2005-09-09 13:04:45 -0700984 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700985
Thomas Winischhofer544393f2005-09-09 13:04:45 -0700986 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700987}
988
Thomas Winischhofer544393f2005-09-09 13:04:45 -0700989/* ------------- Callbacks from init.c/init301.c -------------- */
990
991#ifdef CONFIG_FB_SIS_300
992unsigned int
993sisfb_read_nbridge_pci_dword(struct SiS_Private *SiS_Pr, int reg)
994{
995 struct sis_video_info *ivideo = (struct sis_video_info *)SiS_Pr->ivideo;
996 u32 val = 0;
997
998 pci_read_config_dword(ivideo->nbridge, reg, &val);
999 return (unsigned int)val;
1000}
1001
1002void
1003sisfb_write_nbridge_pci_dword(struct SiS_Private *SiS_Pr, int reg, unsigned int val)
1004{
1005 struct sis_video_info *ivideo = (struct sis_video_info *)SiS_Pr->ivideo;
1006
1007 pci_write_config_dword(ivideo->nbridge, reg, (u32)val);
1008}
1009
1010unsigned int
1011sisfb_read_lpc_pci_dword(struct SiS_Private *SiS_Pr, int reg)
1012{
1013 struct sis_video_info *ivideo = (struct sis_video_info *)SiS_Pr->ivideo;
1014 u32 val = 0;
1015
1016 if(!ivideo->lpcdev) return 0;
1017
1018 pci_read_config_dword(ivideo->lpcdev, reg, &val);
1019 return (unsigned int)val;
1020}
1021#endif
1022
1023#ifdef CONFIG_FB_SIS_315
1024void
1025sisfb_write_nbridge_pci_byte(struct SiS_Private *SiS_Pr, int reg, unsigned char val)
1026{
1027 struct sis_video_info *ivideo = (struct sis_video_info *)SiS_Pr->ivideo;
1028
1029 pci_write_config_byte(ivideo->nbridge, reg, (u8)val);
1030}
1031
1032unsigned int
1033sisfb_read_mio_pci_word(struct SiS_Private *SiS_Pr, int reg)
1034{
1035 struct sis_video_info *ivideo = (struct sis_video_info *)SiS_Pr->ivideo;
1036 u16 val = 0;
1037
1038 if(!ivideo->lpcdev) return 0;
1039
1040 pci_read_config_word(ivideo->lpcdev, reg, &val);
1041 return (unsigned int)val;
1042}
1043#endif
1044
Linus Torvalds1da177e2005-04-16 15:20:36 -07001045/* ----------- FBDev related routines for all series ----------- */
1046
1047static int
1048sisfb_get_cmap_len(const struct fb_var_screeninfo *var)
1049{
1050 return (var->bits_per_pixel == 8) ? 256 : 16;
1051}
1052
1053static void
1054sisfb_set_vparms(struct sis_video_info *ivideo)
1055{
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001056 switch(ivideo->video_bpp) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001057 case 8:
1058 ivideo->DstColor = 0x0000;
1059 ivideo->SiS310_AccelDepth = 0x00000000;
1060 ivideo->video_cmap_len = 256;
1061 break;
1062 case 16:
1063 ivideo->DstColor = 0x8000;
1064 ivideo->SiS310_AccelDepth = 0x00010000;
1065 ivideo->video_cmap_len = 16;
1066 break;
1067 case 32:
1068 ivideo->DstColor = 0xC000;
1069 ivideo->SiS310_AccelDepth = 0x00020000;
1070 ivideo->video_cmap_len = 16;
1071 break;
1072 default:
1073 ivideo->video_cmap_len = 16;
1074 printk(KERN_ERR "sisfb: Unsupported depth %d", ivideo->video_bpp);
1075 ivideo->accel = 0;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001076 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001077}
1078
1079static int
1080sisfb_calc_maxyres(struct sis_video_info *ivideo, struct fb_var_screeninfo *var)
1081{
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001082 int maxyres = ivideo->sisfb_mem / (var->xres_virtual * (var->bits_per_pixel >> 3));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001083
1084 if(maxyres > 32767) maxyres = 32767;
1085
1086 return maxyres;
1087}
1088
1089static void
1090sisfb_calc_pitch(struct sis_video_info *ivideo, struct fb_var_screeninfo *var)
1091{
1092 ivideo->video_linelength = var->xres_virtual * (var->bits_per_pixel >> 3);
1093 ivideo->scrnpitchCRT1 = ivideo->video_linelength;
1094 if(!(ivideo->currentvbflags & CRT1_LCDA)) {
1095 if((var->vmode & FB_VMODE_MASK) == FB_VMODE_INTERLACED) {
1096 ivideo->scrnpitchCRT1 <<= 1;
1097 }
1098 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001099}
1100
1101static void
1102sisfb_set_pitch(struct sis_video_info *ivideo)
1103{
Richard Knutssonc30660e2007-02-12 00:55:06 -08001104 bool isslavemode = false;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001105 unsigned short HDisplay1 = ivideo->scrnpitchCRT1 >> 3;
1106 unsigned short HDisplay2 = ivideo->video_linelength >> 3;
1107
Richard Knutssonc30660e2007-02-12 00:55:06 -08001108 if(sisfb_bridgeisslave(ivideo)) isslavemode = true;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001109
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001110 /* We need to set pitch for CRT1 if bridge is in slave mode, too */
1111 if((ivideo->currentvbflags & VB_DISPTYPE_DISP1) || (isslavemode)) {
1112 outSISIDXREG(SISCR,0x13,(HDisplay1 & 0xFF));
1113 setSISIDXREG(SISSR,0x0E,0xF0,(HDisplay1 >> 8));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001114 }
1115
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001116 /* We must not set the pitch for CRT2 if bridge is in slave mode */
1117 if((ivideo->currentvbflags & VB_DISPTYPE_DISP2) && (!isslavemode)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001118 orSISIDXREG(SISPART1,ivideo->CRT2_write_enable,0x01);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001119 outSISIDXREG(SISPART1,0x07,(HDisplay2 & 0xFF));
1120 setSISIDXREG(SISPART1,0x09,0xF0,(HDisplay2 >> 8));
1121 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001122}
1123
1124static void
1125sisfb_bpp_to_var(struct sis_video_info *ivideo, struct fb_var_screeninfo *var)
1126{
1127 ivideo->video_cmap_len = sisfb_get_cmap_len(var);
1128
1129 switch(var->bits_per_pixel) {
1130 case 8:
1131 var->red.offset = var->green.offset = var->blue.offset = 0;
1132 var->red.length = var->green.length = var->blue.length = 6;
1133 break;
1134 case 16:
1135 var->red.offset = 11;
1136 var->red.length = 5;
1137 var->green.offset = 5;
1138 var->green.length = 6;
1139 var->blue.offset = 0;
1140 var->blue.length = 5;
1141 var->transp.offset = 0;
1142 var->transp.length = 0;
1143 break;
1144 case 32:
1145 var->red.offset = 16;
1146 var->red.length = 8;
1147 var->green.offset = 8;
1148 var->green.length = 8;
1149 var->blue.offset = 0;
1150 var->blue.length = 8;
1151 var->transp.offset = 24;
1152 var->transp.length = 8;
1153 break;
1154 }
1155}
1156
1157static int
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001158sisfb_set_mode(struct sis_video_info *ivideo, int clrscrn)
1159{
1160 unsigned short modeno = ivideo->mode_no;
1161
1162 /* >=2.6.12's fbcon clears the screen anyway */
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001163 modeno |= 0x80;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001164
1165 outSISIDXREG(SISSR, IND_SIS_PASSWORD, SIS_PASSWORD);
1166
1167 sisfb_pre_setmode(ivideo);
1168
Richard Knutssonc30660e2007-02-12 00:55:06 -08001169 if(!SiSSetMode(&ivideo->SiS_Pr, modeno)) {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001170 printk(KERN_ERR "sisfb: Setting mode[0x%x] failed\n", ivideo->mode_no);
1171 return -EINVAL;
1172 }
1173
1174 outSISIDXREG(SISSR, IND_SIS_PASSWORD, SIS_PASSWORD);
1175
1176 sisfb_post_setmode(ivideo);
1177
1178 return 0;
1179}
1180
1181
1182static int
Linus Torvalds1da177e2005-04-16 15:20:36 -07001183sisfb_do_set_var(struct fb_var_screeninfo *var, int isactive, struct fb_info *info)
1184{
1185 struct sis_video_info *ivideo = (struct sis_video_info *)info->par;
1186 unsigned int htotal = 0, vtotal = 0;
1187 unsigned int drate = 0, hrate = 0;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001188 int found_mode = 0, ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001189 int old_mode;
1190 u32 pixclock;
1191
1192 htotal = var->left_margin + var->xres + var->right_margin + var->hsync_len;
1193
1194 vtotal = var->upper_margin + var->lower_margin + var->vsync_len;
1195
1196 pixclock = var->pixclock;
1197
1198 if((var->vmode & FB_VMODE_MASK) == FB_VMODE_NONINTERLACED) {
1199 vtotal += var->yres;
1200 vtotal <<= 1;
1201 } else if((var->vmode & FB_VMODE_MASK) == FB_VMODE_DOUBLE) {
1202 vtotal += var->yres;
1203 vtotal <<= 2;
1204 } else if((var->vmode & FB_VMODE_MASK) == FB_VMODE_INTERLACED) {
1205 vtotal += var->yres;
1206 vtotal <<= 1;
1207 } else vtotal += var->yres;
1208
1209 if(!(htotal) || !(vtotal)) {
1210 DPRINTK("sisfb: Invalid 'var' information\n");
1211 return -EINVAL;
1212 }
1213
1214 if(pixclock && htotal && vtotal) {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001215 drate = 1000000000 / pixclock;
1216 hrate = (drate * 1000) / htotal;
1217 ivideo->refresh_rate = (unsigned int) (hrate * 2 / vtotal);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001218 } else {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001219 ivideo->refresh_rate = 60;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001220 }
1221
1222 old_mode = ivideo->sisfb_mode_idx;
1223 ivideo->sisfb_mode_idx = 0;
1224
1225 while( (sisbios_mode[ivideo->sisfb_mode_idx].mode_no[0] != 0) &&
1226 (sisbios_mode[ivideo->sisfb_mode_idx].xres <= var->xres) ) {
1227 if( (sisbios_mode[ivideo->sisfb_mode_idx].xres == var->xres) &&
1228 (sisbios_mode[ivideo->sisfb_mode_idx].yres == var->yres) &&
1229 (sisbios_mode[ivideo->sisfb_mode_idx].bpp == var->bits_per_pixel)) {
1230 ivideo->mode_no = sisbios_mode[ivideo->sisfb_mode_idx].mode_no[ivideo->mni];
1231 found_mode = 1;
1232 break;
1233 }
1234 ivideo->sisfb_mode_idx++;
1235 }
1236
1237 if(found_mode) {
1238 ivideo->sisfb_mode_idx = sisfb_validate_mode(ivideo,
1239 ivideo->sisfb_mode_idx, ivideo->currentvbflags);
1240 } else {
1241 ivideo->sisfb_mode_idx = -1;
1242 }
1243
1244 if(ivideo->sisfb_mode_idx < 0) {
1245 printk(KERN_ERR "sisfb: Mode %dx%dx%d not supported\n", var->xres,
1246 var->yres, var->bits_per_pixel);
1247 ivideo->sisfb_mode_idx = old_mode;
1248 return -EINVAL;
1249 }
1250
Adrian Bunka9e60e52007-11-14 16:59:02 -08001251 ivideo->mode_no = sisbios_mode[ivideo->sisfb_mode_idx].mode_no[ivideo->mni];
1252
Linus Torvalds1da177e2005-04-16 15:20:36 -07001253 if(sisfb_search_refresh_rate(ivideo, ivideo->refresh_rate, ivideo->sisfb_mode_idx) == 0) {
1254 ivideo->rate_idx = sisbios_mode[ivideo->sisfb_mode_idx].rate_idx;
1255 ivideo->refresh_rate = 60;
1256 }
1257
Linus Torvalds1da177e2005-04-16 15:20:36 -07001258 if(isactive) {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001259 /* If acceleration to be used? Need to know
1260 * before pre/post_set_mode()
1261 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001262 ivideo->accel = 0;
1263#if defined(FBINFO_HWACCEL_DISABLED) && defined(FBINFO_HWACCEL_XPAN)
1264#ifdef STUPID_ACCELF_TEXT_SHIT
1265 if(var->accel_flags & FB_ACCELF_TEXT) {
1266 info->flags &= ~FBINFO_HWACCEL_DISABLED;
1267 } else {
1268 info->flags |= FBINFO_HWACCEL_DISABLED;
1269 }
1270#endif
1271 if(!(info->flags & FBINFO_HWACCEL_DISABLED)) ivideo->accel = -1;
1272#else
1273 if(var->accel_flags & FB_ACCELF_TEXT) ivideo->accel = -1;
1274#endif
1275
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001276 if((ret = sisfb_set_mode(ivideo, 1))) {
1277 return ret;
1278 }
1279
1280 ivideo->video_bpp = sisbios_mode[ivideo->sisfb_mode_idx].bpp;
1281 ivideo->video_width = sisbios_mode[ivideo->sisfb_mode_idx].xres;
1282 ivideo->video_height = sisbios_mode[ivideo->sisfb_mode_idx].yres;
1283
1284 sisfb_calc_pitch(ivideo, var);
1285 sisfb_set_pitch(ivideo);
1286
Linus Torvalds1da177e2005-04-16 15:20:36 -07001287 sisfb_set_vparms(ivideo);
1288
1289 ivideo->current_width = ivideo->video_width;
1290 ivideo->current_height = ivideo->video_height;
1291 ivideo->current_bpp = ivideo->video_bpp;
1292 ivideo->current_htotal = htotal;
1293 ivideo->current_vtotal = vtotal;
1294 ivideo->current_linelength = ivideo->video_linelength;
1295 ivideo->current_pixclock = var->pixclock;
1296 ivideo->current_refresh_rate = ivideo->refresh_rate;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001297 ivideo->sisfb_lastrates[ivideo->mode_no] = ivideo->refresh_rate;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001298 }
1299
1300 return 0;
1301}
1302
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001303static void
1304sisfb_set_base_CRT1(struct sis_video_info *ivideo, unsigned int base)
1305{
1306 outSISIDXREG(SISSR, IND_SIS_PASSWORD, SIS_PASSWORD);
1307
1308 outSISIDXREG(SISCR, 0x0D, base & 0xFF);
1309 outSISIDXREG(SISCR, 0x0C, (base >> 8) & 0xFF);
1310 outSISIDXREG(SISSR, 0x0D, (base >> 16) & 0xFF);
1311 if(ivideo->sisvga_engine == SIS_315_VGA) {
1312 setSISIDXREG(SISSR, 0x37, 0xFE, (base >> 24) & 0x01);
1313 }
1314}
1315
1316static void
1317sisfb_set_base_CRT2(struct sis_video_info *ivideo, unsigned int base)
1318{
1319 if(ivideo->currentvbflags & VB_DISPTYPE_DISP2) {
1320 orSISIDXREG(SISPART1, ivideo->CRT2_write_enable, 0x01);
1321 outSISIDXREG(SISPART1, 0x06, (base & 0xFF));
1322 outSISIDXREG(SISPART1, 0x05, ((base >> 8) & 0xFF));
1323 outSISIDXREG(SISPART1, 0x04, ((base >> 16) & 0xFF));
1324 if(ivideo->sisvga_engine == SIS_315_VGA) {
1325 setSISIDXREG(SISPART1, 0x02, 0x7F, ((base >> 24) & 0x01) << 7);
1326 }
1327 }
1328}
1329
Linus Torvalds1da177e2005-04-16 15:20:36 -07001330static int
1331sisfb_pan_var(struct sis_video_info *ivideo, struct fb_var_screeninfo *var)
1332{
Linus Torvalds1da177e2005-04-16 15:20:36 -07001333 if(var->xoffset > (var->xres_virtual - var->xres)) {
1334 return -EINVAL;
1335 }
1336 if(var->yoffset > (var->yres_virtual - var->yres)) {
1337 return -EINVAL;
1338 }
1339
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001340 ivideo->current_base = (var->yoffset * var->xres_virtual) + var->xoffset;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001341
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001342 /* calculate base bpp dep. */
1343 switch(var->bits_per_pixel) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001344 case 32:
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001345 break;
1346 case 16:
1347 ivideo->current_base >>= 1;
1348 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001349 case 8:
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001350 default:
1351 ivideo->current_base >>= 2;
1352 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001353 }
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001354
1355 ivideo->current_base += (ivideo->video_offset >> 2);
1356
1357 sisfb_set_base_CRT1(ivideo, ivideo->current_base);
1358 sisfb_set_base_CRT2(ivideo, ivideo->current_base);
1359
Linus Torvalds1da177e2005-04-16 15:20:36 -07001360 return 0;
1361}
1362
Linus Torvalds1da177e2005-04-16 15:20:36 -07001363static int
1364sisfb_open(struct fb_info *info, int user)
1365{
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001366 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001367}
1368
1369static int
1370sisfb_release(struct fb_info *info, int user)
1371{
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001372 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001373}
1374
1375static int
1376sisfb_setcolreg(unsigned regno, unsigned red, unsigned green, unsigned blue,
1377 unsigned transp, struct fb_info *info)
1378{
1379 struct sis_video_info *ivideo = (struct sis_video_info *)info->par;
1380
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001381 if(regno >= sisfb_get_cmap_len(&info->var))
1382 return 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001383
1384 switch(info->var.bits_per_pixel) {
1385 case 8:
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001386 outSISREG(SISDACA, regno);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001387 outSISREG(SISDACD, (red >> 10));
1388 outSISREG(SISDACD, (green >> 10));
1389 outSISREG(SISDACD, (blue >> 10));
1390 if(ivideo->currentvbflags & VB_DISPTYPE_DISP2) {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001391 outSISREG(SISDAC2A, regno);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001392 outSISREG(SISDAC2D, (red >> 8));
1393 outSISREG(SISDAC2D, (green >> 8));
1394 outSISREG(SISDAC2D, (blue >> 8));
1395 }
1396 break;
1397 case 16:
Antonino A. Daplas000d5332007-07-17 04:05:44 -07001398 if (regno >= 16)
1399 break;
1400
Linus Torvalds1da177e2005-04-16 15:20:36 -07001401 ((u32 *)(info->pseudo_palette))[regno] =
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001402 (red & 0xf800) |
1403 ((green & 0xfc00) >> 5) |
1404 ((blue & 0xf800) >> 11);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001405 break;
1406 case 32:
Antonino A. Daplas000d5332007-07-17 04:05:44 -07001407 if (regno >= 16)
1408 break;
1409
Linus Torvalds1da177e2005-04-16 15:20:36 -07001410 red >>= 8;
1411 green >>= 8;
1412 blue >>= 8;
1413 ((u32 *)(info->pseudo_palette))[regno] =
1414 (red << 16) | (green << 8) | (blue);
1415 break;
1416 }
1417 return 0;
1418}
1419
1420static int
1421sisfb_set_par(struct fb_info *info)
1422{
1423 int err;
1424
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001425 if((err = sisfb_do_set_var(&info->var, 1, info)))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001426 return err;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001427
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001428 sisfb_get_fix(&info->fix, -1, info);
Adrian Bunk14aefd12008-07-23 21:31:12 -07001429
Linus Torvalds1da177e2005-04-16 15:20:36 -07001430 return 0;
1431}
1432
1433static int
1434sisfb_check_var(struct fb_var_screeninfo *var, struct fb_info *info)
1435{
1436 struct sis_video_info *ivideo = (struct sis_video_info *)info->par;
1437 unsigned int htotal = 0, vtotal = 0, myrateindex = 0;
1438 unsigned int drate = 0, hrate = 0, maxyres;
1439 int found_mode = 0;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001440 int refresh_rate, search_idx, tidx;
Richard Knutssonc30660e2007-02-12 00:55:06 -08001441 bool recalc_clock = false;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001442 u32 pixclock;
1443
1444 htotal = var->left_margin + var->xres + var->right_margin + var->hsync_len;
1445
1446 vtotal = var->upper_margin + var->lower_margin + var->vsync_len;
1447
1448 pixclock = var->pixclock;
1449
1450 if((var->vmode & FB_VMODE_MASK) == FB_VMODE_NONINTERLACED) {
1451 vtotal += var->yres;
1452 vtotal <<= 1;
1453 } else if((var->vmode & FB_VMODE_MASK) == FB_VMODE_DOUBLE) {
1454 vtotal += var->yres;
1455 vtotal <<= 2;
1456 } else if((var->vmode & FB_VMODE_MASK) == FB_VMODE_INTERLACED) {
1457 vtotal += var->yres;
1458 vtotal <<= 1;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001459 } else
1460 vtotal += var->yres;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001461
1462 if(!(htotal) || !(vtotal)) {
1463 SISFAIL("sisfb: no valid timing data");
1464 }
1465
1466 search_idx = 0;
1467 while( (sisbios_mode[search_idx].mode_no[0] != 0) &&
1468 (sisbios_mode[search_idx].xres <= var->xres) ) {
1469 if( (sisbios_mode[search_idx].xres == var->xres) &&
1470 (sisbios_mode[search_idx].yres == var->yres) &&
1471 (sisbios_mode[search_idx].bpp == var->bits_per_pixel)) {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001472 if((tidx = sisfb_validate_mode(ivideo, search_idx,
1473 ivideo->currentvbflags)) > 0) {
1474 found_mode = 1;
1475 search_idx = tidx;
1476 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001477 }
1478 }
1479 search_idx++;
1480 }
1481
1482 if(!found_mode) {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001483 search_idx = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001484 while(sisbios_mode[search_idx].mode_no[0] != 0) {
1485 if( (var->xres <= sisbios_mode[search_idx].xres) &&
1486 (var->yres <= sisbios_mode[search_idx].yres) &&
1487 (var->bits_per_pixel == sisbios_mode[search_idx].bpp) ) {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001488 if((tidx = sisfb_validate_mode(ivideo,search_idx,
1489 ivideo->currentvbflags)) > 0) {
1490 found_mode = 1;
1491 search_idx = tidx;
1492 break;
1493 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001494 }
1495 search_idx++;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001496 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001497 if(found_mode) {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001498 printk(KERN_DEBUG
1499 "sisfb: Adapted from %dx%dx%d to %dx%dx%d\n",
1500 var->xres, var->yres, var->bits_per_pixel,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001501 sisbios_mode[search_idx].xres,
1502 sisbios_mode[search_idx].yres,
1503 var->bits_per_pixel);
1504 var->xres = sisbios_mode[search_idx].xres;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001505 var->yres = sisbios_mode[search_idx].yres;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001506 } else {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001507 printk(KERN_ERR
1508 "sisfb: Failed to find supported mode near %dx%dx%d\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07001509 var->xres, var->yres, var->bits_per_pixel);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001510 return -EINVAL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001511 }
1512 }
1513
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001514 if( ((ivideo->vbflags2 & VB2_LVDS) ||
1515 ((ivideo->vbflags2 & VB2_30xBDH) && (ivideo->currentvbflags & CRT2_LCD))) &&
Linus Torvalds1da177e2005-04-16 15:20:36 -07001516 (var->bits_per_pixel == 8) ) {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001517 /* Slave modes on LVDS and 301B-DH */
1518 refresh_rate = 60;
Richard Knutssonc30660e2007-02-12 00:55:06 -08001519 recalc_clock = true;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001520 } else if( (ivideo->current_htotal == htotal) &&
1521 (ivideo->current_vtotal == vtotal) &&
1522 (ivideo->current_pixclock == pixclock) ) {
1523 /* x=x & y=y & c=c -> assume depth change */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001524 drate = 1000000000 / pixclock;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001525 hrate = (drate * 1000) / htotal;
1526 refresh_rate = (unsigned int) (hrate * 2 / vtotal);
1527 } else if( ( (ivideo->current_htotal != htotal) ||
1528 (ivideo->current_vtotal != vtotal) ) &&
1529 (ivideo->current_pixclock == var->pixclock) ) {
1530 /* x!=x | y!=y & c=c -> invalid pixclock */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001531 if(ivideo->sisfb_lastrates[sisbios_mode[search_idx].mode_no[ivideo->mni]]) {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001532 refresh_rate =
1533 ivideo->sisfb_lastrates[sisbios_mode[search_idx].mode_no[ivideo->mni]];
Linus Torvalds1da177e2005-04-16 15:20:36 -07001534 } else if(ivideo->sisfb_parm_rate != -1) {
1535 /* Sic, sisfb_parm_rate - want to know originally desired rate here */
1536 refresh_rate = ivideo->sisfb_parm_rate;
1537 } else {
1538 refresh_rate = 60;
1539 }
Richard Knutssonc30660e2007-02-12 00:55:06 -08001540 recalc_clock = true;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001541 } else if((pixclock) && (htotal) && (vtotal)) {
1542 drate = 1000000000 / pixclock;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001543 hrate = (drate * 1000) / htotal;
1544 refresh_rate = (unsigned int) (hrate * 2 / vtotal);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001545 } else if(ivideo->current_refresh_rate) {
1546 refresh_rate = ivideo->current_refresh_rate;
Richard Knutssonc30660e2007-02-12 00:55:06 -08001547 recalc_clock = true;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001548 } else {
1549 refresh_rate = 60;
Richard Knutssonc30660e2007-02-12 00:55:06 -08001550 recalc_clock = true;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001551 }
1552
1553 myrateindex = sisfb_search_refresh_rate(ivideo, refresh_rate, search_idx);
1554
1555 /* Eventually recalculate timing and clock */
1556 if(recalc_clock) {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001557 if(!myrateindex) myrateindex = sisbios_mode[search_idx].rate_idx;
1558 var->pixclock = (u32) (1000000000 / sisfb_mode_rate_to_dclock(&ivideo->SiS_Pr,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001559 sisbios_mode[search_idx].mode_no[ivideo->mni],
1560 myrateindex));
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001561 sisfb_mode_rate_to_ddata(&ivideo->SiS_Pr,
1562 sisbios_mode[search_idx].mode_no[ivideo->mni],
1563 myrateindex, var);
1564 if((var->vmode & FB_VMODE_MASK) == FB_VMODE_DOUBLE) {
1565 var->pixclock <<= 1;
1566 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001567 }
1568
1569 if(ivideo->sisfb_thismonitor.datavalid) {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001570 if(!sisfb_verify_rate(ivideo, &ivideo->sisfb_thismonitor, search_idx,
1571 myrateindex, refresh_rate)) {
1572 printk(KERN_INFO
1573 "sisfb: WARNING: Refresh rate exceeds monitor specs!\n");
1574 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001575 }
1576
1577 /* Adapt RGB settings */
1578 sisfb_bpp_to_var(ivideo, var);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001579
Linus Torvalds1da177e2005-04-16 15:20:36 -07001580 /* Sanity check for offsets */
1581 if(var->xoffset < 0) var->xoffset = 0;
1582 if(var->yoffset < 0) var->yoffset = 0;
1583
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001584 if(var->xres > var->xres_virtual)
1585 var->xres_virtual = var->xres;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001586
1587 if(ivideo->sisfb_ypan) {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001588 maxyres = sisfb_calc_maxyres(ivideo, var);
1589 if(ivideo->sisfb_max) {
1590 var->yres_virtual = maxyres;
1591 } else {
1592 if(var->yres_virtual > maxyres) {
1593 var->yres_virtual = maxyres;
1594 }
1595 }
1596 if(var->yres_virtual <= var->yres) {
1597 var->yres_virtual = var->yres;
1598 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001599 } else {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001600 if(var->yres != var->yres_virtual) {
1601 var->yres_virtual = var->yres;
1602 }
1603 var->xoffset = 0;
1604 var->yoffset = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001605 }
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001606
Linus Torvalds1da177e2005-04-16 15:20:36 -07001607 /* Truncate offsets to maximum if too high */
1608 if(var->xoffset > var->xres_virtual - var->xres) {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001609 var->xoffset = var->xres_virtual - var->xres - 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001610 }
1611
1612 if(var->yoffset > var->yres_virtual - var->yres) {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001613 var->yoffset = var->yres_virtual - var->yres - 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001614 }
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001615
Linus Torvalds1da177e2005-04-16 15:20:36 -07001616 /* Set everything else to 0 */
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001617 var->red.msb_right =
1618 var->green.msb_right =
1619 var->blue.msb_right =
1620 var->transp.offset =
1621 var->transp.length =
1622 var->transp.msb_right = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001623
1624 return 0;
1625}
1626
1627static int
1628sisfb_pan_display(struct fb_var_screeninfo *var, struct fb_info* info)
1629{
1630 struct sis_video_info *ivideo = (struct sis_video_info *)info->par;
1631 int err;
1632
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001633 if(var->xoffset > (var->xres_virtual - var->xres))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001634 return -EINVAL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001635
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001636 if(var->yoffset > (var->yres_virtual - var->yres))
1637 return -EINVAL;
1638
1639 if(var->vmode & FB_VMODE_YWRAP)
1640 return -EINVAL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001641
1642 if(var->xoffset + info->var.xres > info->var.xres_virtual ||
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001643 var->yoffset + info->var.yres > info->var.yres_virtual)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001644 return -EINVAL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001645
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001646 if((err = sisfb_pan_var(ivideo, var)) < 0)
1647 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001648
1649 info->var.xoffset = var->xoffset;
1650 info->var.yoffset = var->yoffset;
1651
1652 return 0;
1653}
1654
1655static int
1656sisfb_blank(int blank, struct fb_info *info)
1657{
1658 struct sis_video_info *ivideo = (struct sis_video_info *)info->par;
1659
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001660 return sisfb_myblank(ivideo, blank);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001661}
1662
Linus Torvalds1da177e2005-04-16 15:20:36 -07001663/* ----------- FBDev related routines for all series ---------- */
1664
Christoph Hellwig67a66802006-01-14 13:21:25 -08001665static int sisfb_ioctl(struct fb_info *info, unsigned int cmd,
1666 unsigned long arg)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001667{
1668 struct sis_video_info *ivideo = (struct sis_video_info *)info->par;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001669 struct sis_memreq sismemreq;
1670 struct fb_vblank sisvbblank;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001671 u32 gpu32 = 0;
1672#ifndef __user
1673#define __user
1674#endif
1675 u32 __user *argp = (u32 __user *)arg;
1676
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001677 switch(cmd) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001678 case FBIO_ALLOC:
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001679 if(!capable(CAP_SYS_RAWIO))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001680 return -EPERM;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001681
1682 if(copy_from_user(&sismemreq, (void __user *)arg, sizeof(sismemreq)))
1683 return -EFAULT;
1684
Linus Torvalds1da177e2005-04-16 15:20:36 -07001685 sis_malloc(&sismemreq);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001686
Linus Torvalds1da177e2005-04-16 15:20:36 -07001687 if(copy_to_user((void __user *)arg, &sismemreq, sizeof(sismemreq))) {
1688 sis_free((u32)sismemreq.offset);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001689 return -EFAULT;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001690 }
1691 break;
1692
1693 case FBIO_FREE:
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001694 if(!capable(CAP_SYS_RAWIO))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001695 return -EPERM;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001696
1697 if(get_user(gpu32, argp))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001698 return -EFAULT;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001699
Linus Torvalds1da177e2005-04-16 15:20:36 -07001700 sis_free(gpu32);
1701 break;
1702
1703 case FBIOGET_VBLANK:
1704 sisvbblank.count = 0;
1705 sisvbblank.flags = sisfb_setupvbblankflags(ivideo, &sisvbblank.vcount, &sisvbblank.hcount);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001706
1707 if(copy_to_user((void __user *)arg, &sisvbblank, sizeof(sisvbblank)))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001708 return -EFAULT;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001709
Linus Torvalds1da177e2005-04-16 15:20:36 -07001710 break;
1711
1712 case SISFB_GET_INFO_SIZE:
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001713 return put_user(sizeof(struct sisfb_info), argp);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001714
1715 case SISFB_GET_INFO_OLD:
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001716 if(ivideo->warncount++ < 10)
1717 printk(KERN_INFO
1718 "sisfb: Deprecated ioctl call received - update your application!\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001719 case SISFB_GET_INFO: /* For communication with X driver */
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001720 ivideo->sisfb_infoblock.sisfb_id = SISFB_ID;
1721 ivideo->sisfb_infoblock.sisfb_version = VER_MAJOR;
1722 ivideo->sisfb_infoblock.sisfb_revision = VER_MINOR;
1723 ivideo->sisfb_infoblock.sisfb_patchlevel = VER_LEVEL;
1724 ivideo->sisfb_infoblock.chip_id = ivideo->chip_id;
1725 ivideo->sisfb_infoblock.sisfb_pci_vendor = ivideo->chip_vendor;
1726 ivideo->sisfb_infoblock.memory = ivideo->video_size / 1024;
1727 ivideo->sisfb_infoblock.heapstart = ivideo->heapstart / 1024;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001728 if(ivideo->modechanged) {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001729 ivideo->sisfb_infoblock.fbvidmode = ivideo->mode_no;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001730 } else {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001731 ivideo->sisfb_infoblock.fbvidmode = ivideo->modeprechange;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001732 }
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001733 ivideo->sisfb_infoblock.sisfb_caps = ivideo->caps;
1734 ivideo->sisfb_infoblock.sisfb_tqlen = ivideo->cmdQueueSize / 1024;
1735 ivideo->sisfb_infoblock.sisfb_pcibus = ivideo->pcibus;
1736 ivideo->sisfb_infoblock.sisfb_pcislot = ivideo->pcislot;
1737 ivideo->sisfb_infoblock.sisfb_pcifunc = ivideo->pcifunc;
1738 ivideo->sisfb_infoblock.sisfb_lcdpdc = ivideo->detectedpdc;
1739 ivideo->sisfb_infoblock.sisfb_lcdpdca = ivideo->detectedpdca;
1740 ivideo->sisfb_infoblock.sisfb_lcda = ivideo->detectedlcda;
1741 ivideo->sisfb_infoblock.sisfb_vbflags = ivideo->vbflags;
1742 ivideo->sisfb_infoblock.sisfb_currentvbflags = ivideo->currentvbflags;
1743 ivideo->sisfb_infoblock.sisfb_scalelcd = ivideo->SiS_Pr.UsePanelScaler;
1744 ivideo->sisfb_infoblock.sisfb_specialtiming = ivideo->SiS_Pr.SiS_CustomT;
1745 ivideo->sisfb_infoblock.sisfb_haveemi = ivideo->SiS_Pr.HaveEMI ? 1 : 0;
1746 ivideo->sisfb_infoblock.sisfb_haveemilcd = ivideo->SiS_Pr.HaveEMILCD ? 1 : 0;
1747 ivideo->sisfb_infoblock.sisfb_emi30 = ivideo->SiS_Pr.EMI_30;
1748 ivideo->sisfb_infoblock.sisfb_emi31 = ivideo->SiS_Pr.EMI_31;
1749 ivideo->sisfb_infoblock.sisfb_emi32 = ivideo->SiS_Pr.EMI_32;
1750 ivideo->sisfb_infoblock.sisfb_emi33 = ivideo->SiS_Pr.EMI_33;
1751 ivideo->sisfb_infoblock.sisfb_tvxpos = (u16)(ivideo->tvxpos + 32);
1752 ivideo->sisfb_infoblock.sisfb_tvypos = (u16)(ivideo->tvypos + 32);
1753 ivideo->sisfb_infoblock.sisfb_heapsize = ivideo->sisfb_heap_size / 1024;
1754 ivideo->sisfb_infoblock.sisfb_videooffset = ivideo->video_offset;
1755 ivideo->sisfb_infoblock.sisfb_curfstn = ivideo->curFSTN;
1756 ivideo->sisfb_infoblock.sisfb_curdstn = ivideo->curDSTN;
1757 ivideo->sisfb_infoblock.sisfb_vbflags2 = ivideo->vbflags2;
1758 ivideo->sisfb_infoblock.sisfb_can_post = ivideo->sisfb_can_post ? 1 : 0;
1759 ivideo->sisfb_infoblock.sisfb_card_posted = ivideo->sisfb_card_posted ? 1 : 0;
1760 ivideo->sisfb_infoblock.sisfb_was_boot_device = ivideo->sisfb_was_boot_device ? 1 : 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001761
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001762 if(copy_to_user((void __user *)arg, &ivideo->sisfb_infoblock,
1763 sizeof(ivideo->sisfb_infoblock)))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001764 return -EFAULT;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001765
Linus Torvalds1da177e2005-04-16 15:20:36 -07001766 break;
1767
1768 case SISFB_GET_VBRSTATUS_OLD:
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001769 if(ivideo->warncount++ < 10)
1770 printk(KERN_INFO
1771 "sisfb: Deprecated ioctl call received - update your application!\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001772 case SISFB_GET_VBRSTATUS:
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001773 if(sisfb_CheckVBRetrace(ivideo))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001774 return put_user((u32)1, argp);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001775 else
Linus Torvalds1da177e2005-04-16 15:20:36 -07001776 return put_user((u32)0, argp);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001777
1778 case SISFB_GET_AUTOMAXIMIZE_OLD:
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001779 if(ivideo->warncount++ < 10)
1780 printk(KERN_INFO
1781 "sisfb: Deprecated ioctl call received - update your application!\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001782 case SISFB_GET_AUTOMAXIMIZE:
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001783 if(ivideo->sisfb_max)
1784 return put_user((u32)1, argp);
1785 else
1786 return put_user((u32)0, argp);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001787
1788 case SISFB_SET_AUTOMAXIMIZE_OLD:
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001789 if(ivideo->warncount++ < 10)
1790 printk(KERN_INFO
1791 "sisfb: Deprecated ioctl call received - update your application!\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001792 case SISFB_SET_AUTOMAXIMIZE:
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001793 if(get_user(gpu32, argp))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001794 return -EFAULT;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001795
Linus Torvalds1da177e2005-04-16 15:20:36 -07001796 ivideo->sisfb_max = (gpu32) ? 1 : 0;
1797 break;
1798
1799 case SISFB_SET_TVPOSOFFSET:
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001800 if(get_user(gpu32, argp))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001801 return -EFAULT;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001802
Linus Torvalds1da177e2005-04-16 15:20:36 -07001803 sisfb_set_TVxposoffset(ivideo, ((int)(gpu32 >> 16)) - 32);
1804 sisfb_set_TVyposoffset(ivideo, ((int)(gpu32 & 0xffff)) - 32);
1805 break;
1806
1807 case SISFB_GET_TVPOSOFFSET:
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001808 return put_user((u32)(((ivideo->tvxpos+32)<<16)|((ivideo->tvypos+32)&0xffff)),
1809 argp);
1810
1811 case SISFB_COMMAND:
1812 if(copy_from_user(&ivideo->sisfb_command, (void __user *)arg,
1813 sizeof(struct sisfb_cmd)))
1814 return -EFAULT;
1815
1816 sisfb_handle_command(ivideo, &ivideo->sisfb_command);
1817
1818 if(copy_to_user((void __user *)arg, &ivideo->sisfb_command,
1819 sizeof(struct sisfb_cmd)))
1820 return -EFAULT;
1821
1822 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001823
1824 case SISFB_SET_LOCK:
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001825 if(get_user(gpu32, argp))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001826 return -EFAULT;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001827
Linus Torvalds1da177e2005-04-16 15:20:36 -07001828 ivideo->sisfblocked = (gpu32) ? 1 : 0;
1829 break;
1830
1831 default:
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001832#ifdef SIS_NEW_CONFIG_COMPAT
Linus Torvalds1da177e2005-04-16 15:20:36 -07001833 return -ENOIOCTLCMD;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001834#else
1835 return -EINVAL;
1836#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -07001837 }
1838 return 0;
1839}
1840
Linus Torvalds1da177e2005-04-16 15:20:36 -07001841static int
1842sisfb_get_fix(struct fb_fix_screeninfo *fix, int con, struct fb_info *info)
1843{
1844 struct sis_video_info *ivideo = (struct sis_video_info *)info->par;
1845
1846 memset(fix, 0, sizeof(struct fb_fix_screeninfo));
1847
1848 strcpy(fix->id, ivideo->myid);
1849
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001850 fix->smem_start = ivideo->video_base + ivideo->video_offset;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001851 fix->smem_len = ivideo->sisfb_mem;
1852 fix->type = FB_TYPE_PACKED_PIXELS;
1853 fix->type_aux = 0;
1854 fix->visual = (ivideo->video_bpp == 8) ? FB_VISUAL_PSEUDOCOLOR : FB_VISUAL_TRUECOLOR;
1855 fix->xpanstep = 1;
1856 fix->ypanstep = (ivideo->sisfb_ypan) ? 1 : 0;
1857 fix->ywrapstep = 0;
1858 fix->line_length = ivideo->video_linelength;
1859 fix->mmio_start = ivideo->mmio_base;
1860 fix->mmio_len = ivideo->mmio_size;
1861 if(ivideo->sisvga_engine == SIS_300_VGA) {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001862 fix->accel = FB_ACCEL_SIS_GLAMOUR;
1863 } else if((ivideo->chip == SIS_330) ||
1864 (ivideo->chip == SIS_760) ||
1865 (ivideo->chip == SIS_761)) {
1866 fix->accel = FB_ACCEL_SIS_XABRE;
1867 } else if(ivideo->chip == XGI_20) {
1868 fix->accel = FB_ACCEL_XGI_VOLARI_Z;
1869 } else if(ivideo->chip >= XGI_40) {
1870 fix->accel = FB_ACCEL_XGI_VOLARI_V;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001871 } else {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001872 fix->accel = FB_ACCEL_SIS_GLAMOUR_2;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001873 }
1874
1875 return 0;
1876}
1877
1878/* ---------------- fb_ops structures ----------------- */
1879
Linus Torvalds1da177e2005-04-16 15:20:36 -07001880static struct fb_ops sisfb_ops = {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001881 .owner = THIS_MODULE,
1882 .fb_open = sisfb_open,
1883 .fb_release = sisfb_release,
1884 .fb_check_var = sisfb_check_var,
1885 .fb_set_par = sisfb_set_par,
1886 .fb_setcolreg = sisfb_setcolreg,
1887 .fb_pan_display = sisfb_pan_display,
1888 .fb_blank = sisfb_blank,
1889 .fb_fillrect = fbcon_sis_fillrect,
1890 .fb_copyarea = fbcon_sis_copyarea,
1891 .fb_imageblit = cfb_imageblit,
Antonino A. Daplasc465e052005-11-07 01:00:35 -08001892#ifdef CONFIG_FB_SOFT_CURSOR
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001893 .fb_cursor = soft_cursor,
Antonino A. Daplasc465e052005-11-07 01:00:35 -08001894#endif
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001895 .fb_sync = fbcon_sis_sync,
1896#ifdef SIS_NEW_CONFIG_COMPAT
Christoph Hellwig67a66802006-01-14 13:21:25 -08001897 .fb_compat_ioctl= sisfb_ioctl,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001898#endif
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001899 .fb_ioctl = sisfb_ioctl
Linus Torvalds1da177e2005-04-16 15:20:36 -07001900};
Linus Torvalds1da177e2005-04-16 15:20:36 -07001901
1902/* ---------------- Chip generation dependent routines ---------------- */
1903
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001904static struct pci_dev * __devinit
1905sisfb_get_northbridge(int basechipid)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001906{
1907 struct pci_dev *pdev = NULL;
1908 int nbridgenum, nbridgeidx, i;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001909 static const unsigned short nbridgeids[] = {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001910 PCI_DEVICE_ID_SI_540, /* for SiS 540 VGA */
1911 PCI_DEVICE_ID_SI_630, /* for SiS 630/730 VGA */
1912 PCI_DEVICE_ID_SI_730,
1913 PCI_DEVICE_ID_SI_550, /* for SiS 550 VGA */
1914 PCI_DEVICE_ID_SI_650, /* for SiS 650/651/740 VGA */
1915 PCI_DEVICE_ID_SI_651,
1916 PCI_DEVICE_ID_SI_740,
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001917 PCI_DEVICE_ID_SI_661, /* for SiS 661/741/660/760/761 VGA */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001918 PCI_DEVICE_ID_SI_741,
1919 PCI_DEVICE_ID_SI_660,
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001920 PCI_DEVICE_ID_SI_760,
1921 PCI_DEVICE_ID_SI_761
Linus Torvalds1da177e2005-04-16 15:20:36 -07001922 };
1923
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001924 switch(basechipid) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001925#ifdef CONFIG_FB_SIS_300
1926 case SIS_540: nbridgeidx = 0; nbridgenum = 1; break;
1927 case SIS_630: nbridgeidx = 1; nbridgenum = 2; break;
1928#endif
1929#ifdef CONFIG_FB_SIS_315
1930 case SIS_550: nbridgeidx = 3; nbridgenum = 1; break;
1931 case SIS_650: nbridgeidx = 4; nbridgenum = 3; break;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001932 case SIS_660: nbridgeidx = 7; nbridgenum = 5; break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001933#endif
1934 default: return NULL;
1935 }
1936 for(i = 0; i < nbridgenum; i++) {
Adrian Bunk0959f0c2007-05-08 00:39:50 -07001937 if((pdev = pci_get_device(PCI_VENDOR_ID_SI,
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001938 nbridgeids[nbridgeidx+i], NULL)))
1939 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001940 }
1941 return pdev;
1942}
1943
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001944static int __devinit
1945sisfb_get_dram_size(struct sis_video_info *ivideo)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001946{
1947#if defined(CONFIG_FB_SIS_300) || defined(CONFIG_FB_SIS_315)
1948 u8 reg;
1949#endif
1950
1951 ivideo->video_size = 0;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001952 ivideo->UMAsize = ivideo->LFBsize = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001953
1954 switch(ivideo->chip) {
1955#ifdef CONFIG_FB_SIS_300
1956 case SIS_300:
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001957 inSISIDXREG(SISSR, 0x14, reg);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001958 ivideo->video_size = ((reg & 0x3F) + 1) << 20;
1959 break;
1960 case SIS_540:
1961 case SIS_630:
1962 case SIS_730:
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001963 if(!ivideo->nbridge)
1964 return -1;
1965 pci_read_config_byte(ivideo->nbridge, 0x63, &reg);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001966 ivideo->video_size = 1 << (((reg & 0x70) >> 4) + 21);
1967 break;
1968#endif
1969#ifdef CONFIG_FB_SIS_315
1970 case SIS_315H:
1971 case SIS_315PRO:
1972 case SIS_315:
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001973 inSISIDXREG(SISSR, 0x14, reg);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001974 ivideo->video_size = (1 << ((reg & 0xf0) >> 4)) << 20;
1975 switch((reg >> 2) & 0x03) {
1976 case 0x01:
1977 case 0x03:
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001978 ivideo->video_size <<= 1;
1979 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001980 case 0x02:
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001981 ivideo->video_size += (ivideo->video_size/2);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001982 }
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001983 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001984 case SIS_330:
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001985 inSISIDXREG(SISSR, 0x14, reg);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001986 ivideo->video_size = (1 << ((reg & 0xf0) >> 4)) << 20;
1987 if(reg & 0x0c) ivideo->video_size <<= 1;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001988 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001989 case SIS_550:
1990 case SIS_650:
1991 case SIS_740:
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001992 inSISIDXREG(SISSR, 0x14, reg);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001993 ivideo->video_size = (((reg & 0x3f) + 1) << 2) << 20;
1994 break;
1995 case SIS_661:
1996 case SIS_741:
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001997 inSISIDXREG(SISCR, 0x79, reg);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001998 ivideo->video_size = (1 << ((reg & 0xf0) >> 4)) << 20;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001999 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002000 case SIS_660:
2001 case SIS_760:
Thomas Winischhofer544393f2005-09-09 13:04:45 -07002002 case SIS_761:
Linus Torvalds1da177e2005-04-16 15:20:36 -07002003 inSISIDXREG(SISCR, 0x79, reg);
2004 reg = (reg & 0xf0) >> 4;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07002005 if(reg) {
2006 ivideo->video_size = (1 << reg) << 20;
2007 ivideo->UMAsize = ivideo->video_size;
2008 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002009 inSISIDXREG(SISCR, 0x78, reg);
2010 reg &= 0x30;
2011 if(reg) {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07002012 if(reg == 0x10) {
2013 ivideo->LFBsize = (32 << 20);
2014 } else {
2015 ivideo->LFBsize = (64 << 20);
2016 }
2017 ivideo->video_size += ivideo->LFBsize;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002018 }
Thomas Winischhofer544393f2005-09-09 13:04:45 -07002019 break;
2020 case SIS_340:
2021 case XGI_20:
2022 case XGI_40:
2023 inSISIDXREG(SISSR, 0x14, reg);
2024 ivideo->video_size = (1 << ((reg & 0xf0) >> 4)) << 20;
2025 if(ivideo->chip != XGI_20) {
2026 reg = (reg & 0x0c) >> 2;
2027 if(ivideo->revision_id == 2) {
2028 if(reg & 0x01) reg = 0x02;
2029 else reg = 0x00;
2030 }
2031 if(reg == 0x02) ivideo->video_size <<= 1;
2032 else if(reg == 0x03) ivideo->video_size <<= 2;
2033 }
2034 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002035#endif
2036 default:
2037 return -1;
2038 }
2039 return 0;
2040}
2041
2042/* -------------- video bridge device detection --------------- */
2043
Thomas Winischhofer544393f2005-09-09 13:04:45 -07002044static void __devinit
2045sisfb_detect_VB_connect(struct sis_video_info *ivideo)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002046{
2047 u8 cr32, temp;
2048
Thomas Winischhofer544393f2005-09-09 13:04:45 -07002049 /* No CRT2 on XGI Z7 */
2050 if(ivideo->chip == XGI_20) {
2051 ivideo->sisfb_crt1off = 0;
2052 return;
2053 }
2054
Linus Torvalds1da177e2005-04-16 15:20:36 -07002055#ifdef CONFIG_FB_SIS_300
2056 if(ivideo->sisvga_engine == SIS_300_VGA) {
2057 inSISIDXREG(SISSR, 0x17, temp);
2058 if((temp & 0x0F) && (ivideo->chip != SIS_300)) {
2059 /* PAL/NTSC is stored on SR16 on such machines */
2060 if(!(ivideo->vbflags & (TV_PAL | TV_NTSC | TV_PALM | TV_PALN))) {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07002061 inSISIDXREG(SISSR, 0x16, temp);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002062 if(temp & 0x20)
2063 ivideo->vbflags |= TV_PAL;
2064 else
2065 ivideo->vbflags |= TV_NTSC;
2066 }
2067 }
2068 }
2069#endif
2070
2071 inSISIDXREG(SISCR, 0x32, cr32);
2072
2073 if(cr32 & SIS_CRT1) {
2074 ivideo->sisfb_crt1off = 0;
2075 } else {
2076 ivideo->sisfb_crt1off = (cr32 & 0xDF) ? 1 : 0;
2077 }
2078
2079 ivideo->vbflags &= ~(CRT2_TV | CRT2_LCD | CRT2_VGA);
2080
2081 if(cr32 & SIS_VB_TV) ivideo->vbflags |= CRT2_TV;
2082 if(cr32 & SIS_VB_LCD) ivideo->vbflags |= CRT2_LCD;
2083 if(cr32 & SIS_VB_CRT2) ivideo->vbflags |= CRT2_VGA;
2084
2085 /* Check given parms for hardware compatibility.
2086 * (Cannot do this in the search_xx routines since we don't
2087 * know what hardware we are running on then)
2088 */
2089
2090 if(ivideo->chip != SIS_550) {
2091 ivideo->sisfb_dstn = ivideo->sisfb_fstn = 0;
2092 }
2093
2094 if(ivideo->sisfb_tvplug != -1) {
2095 if( (ivideo->sisvga_engine != SIS_315_VGA) ||
Thomas Winischhofer544393f2005-09-09 13:04:45 -07002096 (!(ivideo->vbflags2 & VB2_SISYPBPRBRIDGE)) ) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002097 if(ivideo->sisfb_tvplug & TV_YPBPR) {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07002098 ivideo->sisfb_tvplug = -1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002099 printk(KERN_ERR "sisfb: YPbPr not supported\n");
2100 }
2101 }
2102 }
2103 if(ivideo->sisfb_tvplug != -1) {
2104 if( (ivideo->sisvga_engine != SIS_315_VGA) ||
Thomas Winischhofer544393f2005-09-09 13:04:45 -07002105 (!(ivideo->vbflags2 & VB2_SISHIVISIONBRIDGE)) ) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002106 if(ivideo->sisfb_tvplug & TV_HIVISION) {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07002107 ivideo->sisfb_tvplug = -1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002108 printk(KERN_ERR "sisfb: HiVision not supported\n");
2109 }
2110 }
2111 }
2112 if(ivideo->sisfb_tvstd != -1) {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07002113 if( (!(ivideo->vbflags2 & VB2_SISBRIDGE)) &&
2114 (!((ivideo->sisvga_engine == SIS_315_VGA) &&
2115 (ivideo->vbflags2 & VB2_CHRONTEL))) ) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002116 if(ivideo->sisfb_tvstd & (TV_PALN | TV_PALN | TV_NTSCJ)) {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07002117 ivideo->sisfb_tvstd = -1;
2118 printk(KERN_ERR "sisfb: PALM/PALN/NTSCJ not supported\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002119 }
2120 }
2121 }
2122
2123 /* Detect/set TV plug & type */
2124 if(ivideo->sisfb_tvplug != -1) {
2125 ivideo->vbflags |= ivideo->sisfb_tvplug;
2126 } else {
2127 if(cr32 & SIS_VB_YPBPR) ivideo->vbflags |= (TV_YPBPR|TV_YPBPR525I); /* default: 480i */
2128 else if(cr32 & SIS_VB_HIVISION) ivideo->vbflags |= TV_HIVISION;
2129 else if(cr32 & SIS_VB_SCART) ivideo->vbflags |= TV_SCART;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07002130 else {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002131 if(cr32 & SIS_VB_SVIDEO) ivideo->vbflags |= TV_SVIDEO;
2132 if(cr32 & SIS_VB_COMPOSITE) ivideo->vbflags |= TV_AVIDEO;
2133 }
2134 }
2135
2136 if(!(ivideo->vbflags & (TV_YPBPR | TV_HIVISION))) {
2137 if(ivideo->sisfb_tvstd != -1) {
2138 ivideo->vbflags &= ~(TV_NTSC | TV_PAL | TV_PALM | TV_PALN | TV_NTSCJ);
2139 ivideo->vbflags |= ivideo->sisfb_tvstd;
2140 }
2141 if(ivideo->vbflags & TV_SCART) {
2142 ivideo->vbflags &= ~(TV_NTSC | TV_PALM | TV_PALN | TV_NTSCJ);
2143 ivideo->vbflags |= TV_PAL;
2144 }
2145 if(!(ivideo->vbflags & (TV_PAL | TV_NTSC | TV_PALM | TV_PALN | TV_NTSCJ))) {
2146 if(ivideo->sisvga_engine == SIS_300_VGA) {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07002147 inSISIDXREG(SISSR, 0x38, temp);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002148 if(temp & 0x01) ivideo->vbflags |= TV_PAL;
2149 else ivideo->vbflags |= TV_NTSC;
2150 } else if((ivideo->chip <= SIS_315PRO) || (ivideo->chip >= SIS_330)) {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07002151 inSISIDXREG(SISSR, 0x38, temp);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002152 if(temp & 0x01) ivideo->vbflags |= TV_PAL;
2153 else ivideo->vbflags |= TV_NTSC;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07002154 } else {
2155 inSISIDXREG(SISCR, 0x79, temp);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002156 if(temp & 0x20) ivideo->vbflags |= TV_PAL;
2157 else ivideo->vbflags |= TV_NTSC;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07002158 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002159 }
2160 }
2161
2162 /* Copy forceCRT1 option to CRT1off if option is given */
Thomas Winischhofer544393f2005-09-09 13:04:45 -07002163 if(ivideo->sisfb_forcecrt1 != -1) {
2164 ivideo->sisfb_crt1off = (ivideo->sisfb_forcecrt1) ? 0 : 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002165 }
2166}
2167
2168/* ------------------ Sensing routines ------------------ */
2169
Richard Knutssonc30660e2007-02-12 00:55:06 -08002170static bool __devinit
Thomas Winischhofer544393f2005-09-09 13:04:45 -07002171sisfb_test_DDC1(struct sis_video_info *ivideo)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002172{
2173 unsigned short old;
2174 int count = 48;
2175
2176 old = SiS_ReadDDC1Bit(&ivideo->SiS_Pr);
2177 do {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07002178 if(old != SiS_ReadDDC1Bit(&ivideo->SiS_Pr)) break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002179 } while(count--);
Richard Knutssonc30660e2007-02-12 00:55:06 -08002180 return (count != -1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002181}
2182
Thomas Winischhofer544393f2005-09-09 13:04:45 -07002183static void __devinit
2184sisfb_sense_crt1(struct sis_video_info *ivideo)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002185{
Richard Knutssonc30660e2007-02-12 00:55:06 -08002186 bool mustwait = false;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002187 u8 sr1F, cr17;
2188#ifdef CONFIG_FB_SIS_315
2189 u8 cr63=0;
2190#endif
2191 u16 temp = 0xffff;
2192 int i;
2193
2194 inSISIDXREG(SISSR,0x1F,sr1F);
2195 orSISIDXREG(SISSR,0x1F,0x04);
2196 andSISIDXREG(SISSR,0x1F,0x3F);
Richard Knutssonc30660e2007-02-12 00:55:06 -08002197 if(sr1F & 0xc0) mustwait = true;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002198
2199#ifdef CONFIG_FB_SIS_315
2200 if(ivideo->sisvga_engine == SIS_315_VGA) {
2201 inSISIDXREG(SISCR,ivideo->SiS_Pr.SiS_MyCR63,cr63);
2202 cr63 &= 0x40;
2203 andSISIDXREG(SISCR,ivideo->SiS_Pr.SiS_MyCR63,0xBF);
2204 }
2205#endif
2206
2207 inSISIDXREG(SISCR,0x17,cr17);
2208 cr17 &= 0x80;
2209 if(!cr17) {
2210 orSISIDXREG(SISCR,0x17,0x80);
Richard Knutssonc30660e2007-02-12 00:55:06 -08002211 mustwait = true;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002212 outSISIDXREG(SISSR, 0x00, 0x01);
2213 outSISIDXREG(SISSR, 0x00, 0x03);
2214 }
2215
2216 if(mustwait) {
2217 for(i=0; i < 10; i++) sisfbwaitretracecrt1(ivideo);
2218 }
2219
2220#ifdef CONFIG_FB_SIS_315
2221 if(ivideo->chip >= SIS_330) {
2222 andSISIDXREG(SISCR,0x32,~0x20);
2223 if(ivideo->chip >= SIS_340) {
2224 outSISIDXREG(SISCR, 0x57, 0x4a);
2225 } else {
2226 outSISIDXREG(SISCR, 0x57, 0x5f);
2227 }
2228 orSISIDXREG(SISCR, 0x53, 0x02);
2229 while((inSISREG(SISINPSTAT)) & 0x01) break;
2230 while(!((inSISREG(SISINPSTAT)) & 0x01)) break;
2231 if((inSISREG(SISMISCW)) & 0x10) temp = 1;
2232 andSISIDXREG(SISCR, 0x53, 0xfd);
2233 andSISIDXREG(SISCR, 0x57, 0x00);
2234 }
2235#endif
2236
2237 if(temp == 0xffff) {
2238 i = 3;
2239 do {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07002240 temp = SiS_HandleDDC(&ivideo->SiS_Pr, ivideo->vbflags,
2241 ivideo->sisvga_engine, 0, 0, NULL, ivideo->vbflags2);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002242 } while(((temp == 0) || (temp == 0xffff)) && i--);
2243
2244 if((temp == 0) || (temp == 0xffff)) {
2245 if(sisfb_test_DDC1(ivideo)) temp = 1;
2246 }
2247 }
2248
2249 if((temp) && (temp != 0xffff)) {
2250 orSISIDXREG(SISCR,0x32,0x20);
2251 }
2252
2253#ifdef CONFIG_FB_SIS_315
2254 if(ivideo->sisvga_engine == SIS_315_VGA) {
2255 setSISIDXREG(SISCR,ivideo->SiS_Pr.SiS_MyCR63,0xBF,cr63);
2256 }
2257#endif
2258
2259 setSISIDXREG(SISCR,0x17,0x7F,cr17);
2260
2261 outSISIDXREG(SISSR,0x1F,sr1F);
2262}
2263
2264/* Determine and detect attached devices on SiS30x */
Thomas Winischhofer544393f2005-09-09 13:04:45 -07002265static void __devinit
2266SiS_SenseLCD(struct sis_video_info *ivideo)
2267{
2268 unsigned char buffer[256];
2269 unsigned short temp, realcrtno, i;
2270 u8 reg, cr37 = 0, paneltype = 0;
2271 u16 xres, yres;
2272
Richard Knutssonc30660e2007-02-12 00:55:06 -08002273 ivideo->SiS_Pr.PanelSelfDetected = false;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07002274
2275 /* LCD detection only for TMDS bridges */
2276 if(!(ivideo->vbflags2 & VB2_SISTMDSBRIDGE))
2277 return;
2278 if(ivideo->vbflags2 & VB2_30xBDH)
2279 return;
2280
2281 /* If LCD already set up by BIOS, skip it */
2282 inSISIDXREG(SISCR, 0x32, reg);
2283 if(reg & 0x08)
2284 return;
2285
2286 realcrtno = 1;
2287 if(ivideo->SiS_Pr.DDCPortMixup)
2288 realcrtno = 0;
2289
2290 /* Check DDC capabilities */
2291 temp = SiS_HandleDDC(&ivideo->SiS_Pr, ivideo->vbflags, ivideo->sisvga_engine,
2292 realcrtno, 0, &buffer[0], ivideo->vbflags2);
2293
2294 if((!temp) || (temp == 0xffff) || (!(temp & 0x02)))
2295 return;
2296
2297 /* Read DDC data */
2298 i = 3; /* Number of retrys */
2299 do {
2300 temp = SiS_HandleDDC(&ivideo->SiS_Pr, ivideo->vbflags,
2301 ivideo->sisvga_engine, realcrtno, 1,
2302 &buffer[0], ivideo->vbflags2);
2303 } while((temp) && i--);
2304
2305 if(temp)
2306 return;
2307
2308 /* No digital device */
2309 if(!(buffer[0x14] & 0x80))
2310 return;
2311
2312 /* First detailed timing preferred timing? */
2313 if(!(buffer[0x18] & 0x02))
2314 return;
2315
2316 xres = buffer[0x38] | ((buffer[0x3a] & 0xf0) << 4);
2317 yres = buffer[0x3b] | ((buffer[0x3d] & 0xf0) << 4);
2318
2319 switch(xres) {
2320 case 1024:
2321 if(yres == 768)
2322 paneltype = 0x02;
2323 break;
2324 case 1280:
2325 if(yres == 1024)
2326 paneltype = 0x03;
2327 break;
2328 case 1600:
2329 if((yres == 1200) && (ivideo->vbflags2 & VB2_30xC))
2330 paneltype = 0x0b;
2331 break;
2332 }
2333
2334 if(!paneltype)
2335 return;
2336
2337 if(buffer[0x23])
2338 cr37 |= 0x10;
2339
2340 if((buffer[0x47] & 0x18) == 0x18)
2341 cr37 |= ((((buffer[0x47] & 0x06) ^ 0x06) << 5) | 0x20);
2342 else
2343 cr37 |= 0xc0;
2344
2345 outSISIDXREG(SISCR, 0x36, paneltype);
2346 cr37 &= 0xf1;
2347 setSISIDXREG(SISCR, 0x37, 0x0c, cr37);
2348 orSISIDXREG(SISCR, 0x32, 0x08);
2349
Richard Knutssonc30660e2007-02-12 00:55:06 -08002350 ivideo->SiS_Pr.PanelSelfDetected = true;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07002351}
2352
2353static int __devinit
2354SISDoSense(struct sis_video_info *ivideo, u16 type, u16 test)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002355{
2356 int temp, mytest, result, i, j;
2357
2358 for(j = 0; j < 10; j++) {
2359 result = 0;
2360 for(i = 0; i < 3; i++) {
2361 mytest = test;
2362 outSISIDXREG(SISPART4,0x11,(type & 0x00ff));
2363 temp = (type >> 8) | (mytest & 0x00ff);
2364 setSISIDXREG(SISPART4,0x10,0xe0,temp);
2365 SiS_DDC2Delay(&ivideo->SiS_Pr, 0x1500);
2366 mytest >>= 8;
2367 mytest &= 0x7f;
2368 inSISIDXREG(SISPART4,0x03,temp);
2369 temp ^= 0x0e;
2370 temp &= mytest;
2371 if(temp == mytest) result++;
2372#if 1
2373 outSISIDXREG(SISPART4,0x11,0x00);
2374 andSISIDXREG(SISPART4,0x10,0xe0);
2375 SiS_DDC2Delay(&ivideo->SiS_Pr, 0x1000);
2376#endif
2377 }
2378 if((result == 0) || (result >= 2)) break;
2379 }
Thomas Winischhofer544393f2005-09-09 13:04:45 -07002380 return result;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002381}
2382
Thomas Winischhofer544393f2005-09-09 13:04:45 -07002383static void __devinit
2384SiS_Sense30x(struct sis_video_info *ivideo)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002385{
2386 u8 backupP4_0d,backupP2_00,backupP2_4d,backupSR_1e,biosflag=0;
2387 u16 svhs=0, svhs_c=0;
2388 u16 cvbs=0, cvbs_c=0;
2389 u16 vga2=0, vga2_c=0;
2390 int myflag, result;
2391 char stdstr[] = "sisfb: Detected";
2392 char tvstr[] = "TV connected to";
2393
Thomas Winischhofer544393f2005-09-09 13:04:45 -07002394 if(ivideo->vbflags2 & VB2_301) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002395 svhs = 0x00b9; cvbs = 0x00b3; vga2 = 0x00d1;
2396 inSISIDXREG(SISPART4,0x01,myflag);
2397 if(myflag & 0x04) {
2398 svhs = 0x00dd; cvbs = 0x00ee; vga2 = 0x00fd;
2399 }
Thomas Winischhofer544393f2005-09-09 13:04:45 -07002400 } else if(ivideo->vbflags2 & (VB2_301B | VB2_302B)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002401 svhs = 0x016b; cvbs = 0x0174; vga2 = 0x0190;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07002402 } else if(ivideo->vbflags2 & (VB2_301LV | VB2_302LV)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002403 svhs = 0x0200; cvbs = 0x0100;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07002404 } else if(ivideo->vbflags2 & (VB2_301C | VB2_302ELV | VB2_307T | VB2_307LV)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002405 svhs = 0x016b; cvbs = 0x0110; vga2 = 0x0190;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07002406 } else
2407 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002408
2409 vga2_c = 0x0e08; svhs_c = 0x0404; cvbs_c = 0x0804;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07002410 if(ivideo->vbflags & (VB2_301LV|VB2_302LV|VB2_302ELV|VB2_307LV)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002411 svhs_c = 0x0408; cvbs_c = 0x0808;
2412 }
Thomas Winischhofer544393f2005-09-09 13:04:45 -07002413
Linus Torvalds1da177e2005-04-16 15:20:36 -07002414 biosflag = 2;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07002415 if(ivideo->haveXGIROM) {
2416 biosflag = ivideo->bios_abase[0x58] & 0x03;
2417 } else if(ivideo->newrom) {
2418 if(ivideo->bios_abase[0x5d] & 0x04) biosflag |= 0x01;
2419 } else if(ivideo->sisvga_engine == SIS_300_VGA) {
2420 if(ivideo->bios_abase) {
2421 biosflag = ivideo->bios_abase[0xfe] & 0x03;
2422 }
2423 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002424
2425 if(ivideo->chip == SIS_300) {
2426 inSISIDXREG(SISSR,0x3b,myflag);
2427 if(!(myflag & 0x01)) vga2 = vga2_c = 0;
2428 }
2429
Thomas Winischhofer544393f2005-09-09 13:04:45 -07002430 if(!(ivideo->vbflags2 & VB2_SISVGA2BRIDGE)) {
2431 vga2 = vga2_c = 0;
2432 }
2433
Linus Torvalds1da177e2005-04-16 15:20:36 -07002434 inSISIDXREG(SISSR,0x1e,backupSR_1e);
2435 orSISIDXREG(SISSR,0x1e,0x20);
2436
2437 inSISIDXREG(SISPART4,0x0d,backupP4_0d);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07002438 if(ivideo->vbflags2 & VB2_30xC) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002439 setSISIDXREG(SISPART4,0x0d,~0x07,0x01);
2440 } else {
2441 orSISIDXREG(SISPART4,0x0d,0x04);
2442 }
2443 SiS_DDC2Delay(&ivideo->SiS_Pr, 0x2000);
2444
2445 inSISIDXREG(SISPART2,0x00,backupP2_00);
2446 outSISIDXREG(SISPART2,0x00,((backupP2_00 | 0x1c) & 0xfc));
2447
2448 inSISIDXREG(SISPART2,0x4d,backupP2_4d);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07002449 if(ivideo->vbflags2 & VB2_SISYPBPRBRIDGE) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002450 outSISIDXREG(SISPART2,0x4d,(backupP2_4d & ~0x10));
2451 }
2452
Thomas Winischhofer544393f2005-09-09 13:04:45 -07002453 if(!(ivideo->vbflags2 & VB2_30xCLV)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002454 SISDoSense(ivideo, 0, 0);
2455 }
2456
2457 andSISIDXREG(SISCR, 0x32, ~0x14);
2458
2459 if(vga2_c || vga2) {
2460 if(SISDoSense(ivideo, vga2, vga2_c)) {
2461 if(biosflag & 0x01) {
2462 printk(KERN_INFO "%s %s SCART output\n", stdstr, tvstr);
2463 orSISIDXREG(SISCR, 0x32, 0x04);
2464 } else {
2465 printk(KERN_INFO "%s secondary VGA connection\n", stdstr);
2466 orSISIDXREG(SISCR, 0x32, 0x10);
2467 }
2468 }
2469 }
2470
2471 andSISIDXREG(SISCR, 0x32, 0x3f);
2472
Thomas Winischhofer544393f2005-09-09 13:04:45 -07002473 if(ivideo->vbflags2 & VB2_30xCLV) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002474 orSISIDXREG(SISPART4,0x0d,0x04);
2475 }
2476
Thomas Winischhofer544393f2005-09-09 13:04:45 -07002477 if((ivideo->sisvga_engine == SIS_315_VGA) && (ivideo->vbflags2 & VB2_SISYPBPRBRIDGE)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002478 outSISIDXREG(SISPART2,0x4d,(backupP2_4d | 0x10));
2479 SiS_DDC2Delay(&ivideo->SiS_Pr, 0x2000);
2480 if((result = SISDoSense(ivideo, svhs, 0x0604))) {
2481 if((result = SISDoSense(ivideo, cvbs, 0x0804))) {
2482 printk(KERN_INFO "%s %s YPbPr component output\n", stdstr, tvstr);
2483 orSISIDXREG(SISCR,0x32,0x80);
2484 }
2485 }
2486 outSISIDXREG(SISPART2,0x4d,backupP2_4d);
2487 }
2488
2489 andSISIDXREG(SISCR, 0x32, ~0x03);
2490
2491 if(!(ivideo->vbflags & TV_YPBPR)) {
2492 if((result = SISDoSense(ivideo, svhs, svhs_c))) {
2493 printk(KERN_INFO "%s %s SVIDEO output\n", stdstr, tvstr);
2494 orSISIDXREG(SISCR, 0x32, 0x02);
2495 }
2496 if((biosflag & 0x02) || (!result)) {
2497 if(SISDoSense(ivideo, cvbs, cvbs_c)) {
2498 printk(KERN_INFO "%s %s COMPOSITE output\n", stdstr, tvstr);
2499 orSISIDXREG(SISCR, 0x32, 0x01);
2500 }
2501 }
2502 }
2503
2504 SISDoSense(ivideo, 0, 0);
2505
2506 outSISIDXREG(SISPART2,0x00,backupP2_00);
2507 outSISIDXREG(SISPART4,0x0d,backupP4_0d);
2508 outSISIDXREG(SISSR,0x1e,backupSR_1e);
2509
Thomas Winischhofer544393f2005-09-09 13:04:45 -07002510 if(ivideo->vbflags2 & VB2_30xCLV) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002511 inSISIDXREG(SISPART2,0x00,biosflag);
2512 if(biosflag & 0x20) {
2513 for(myflag = 2; myflag > 0; myflag--) {
2514 biosflag ^= 0x20;
2515 outSISIDXREG(SISPART2,0x00,biosflag);
2516 }
2517 }
2518 }
2519
2520 outSISIDXREG(SISPART2,0x00,backupP2_00);
2521}
2522
2523/* Determine and detect attached TV's on Chrontel */
Thomas Winischhofer544393f2005-09-09 13:04:45 -07002524static void __devinit
2525SiS_SenseCh(struct sis_video_info *ivideo)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002526{
2527#if defined(CONFIG_FB_SIS_300) || defined(CONFIG_FB_SIS_315)
2528 u8 temp1, temp2;
2529 char stdstr[] = "sisfb: Chrontel: Detected TV connected to";
2530#endif
2531#ifdef CONFIG_FB_SIS_300
2532 unsigned char test[3];
2533 int i;
2534#endif
2535
2536 if(ivideo->chip < SIS_315H) {
2537
2538#ifdef CONFIG_FB_SIS_300
2539 ivideo->SiS_Pr.SiS_IF_DEF_CH70xx = 1; /* Chrontel 700x */
2540 SiS_SetChrontelGPIO(&ivideo->SiS_Pr, 0x9c); /* Set general purpose IO for Chrontel communication */
2541 SiS_DDC2Delay(&ivideo->SiS_Pr, 1000);
2542 temp1 = SiS_GetCH700x(&ivideo->SiS_Pr, 0x25);
2543 /* See Chrontel TB31 for explanation */
2544 temp2 = SiS_GetCH700x(&ivideo->SiS_Pr, 0x0e);
2545 if(((temp2 & 0x07) == 0x01) || (temp2 & 0x04)) {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07002546 SiS_SetCH700x(&ivideo->SiS_Pr, 0x0e, 0x0b);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002547 SiS_DDC2Delay(&ivideo->SiS_Pr, 300);
2548 }
2549 temp2 = SiS_GetCH700x(&ivideo->SiS_Pr, 0x25);
2550 if(temp2 != temp1) temp1 = temp2;
2551
2552 if((temp1 >= 0x22) && (temp1 <= 0x50)) {
2553 /* Read power status */
2554 temp1 = SiS_GetCH700x(&ivideo->SiS_Pr, 0x0e);
2555 if((temp1 & 0x03) != 0x03) {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07002556 /* Power all outputs */
2557 SiS_SetCH700x(&ivideo->SiS_Pr, 0x0e,0x0b);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002558 SiS_DDC2Delay(&ivideo->SiS_Pr, 300);
2559 }
2560 /* Sense connected TV devices */
2561 for(i = 0; i < 3; i++) {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07002562 SiS_SetCH700x(&ivideo->SiS_Pr, 0x10, 0x01);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002563 SiS_DDC2Delay(&ivideo->SiS_Pr, 0x96);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07002564 SiS_SetCH700x(&ivideo->SiS_Pr, 0x10, 0x00);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002565 SiS_DDC2Delay(&ivideo->SiS_Pr, 0x96);
2566 temp1 = SiS_GetCH700x(&ivideo->SiS_Pr, 0x10);
2567 if(!(temp1 & 0x08)) test[i] = 0x02;
2568 else if(!(temp1 & 0x02)) test[i] = 0x01;
2569 else test[i] = 0;
2570 SiS_DDC2Delay(&ivideo->SiS_Pr, 0x96);
2571 }
2572
2573 if(test[0] == test[1]) temp1 = test[0];
2574 else if(test[0] == test[2]) temp1 = test[0];
2575 else if(test[1] == test[2]) temp1 = test[1];
2576 else {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07002577 printk(KERN_INFO
Linus Torvalds1da177e2005-04-16 15:20:36 -07002578 "sisfb: TV detection unreliable - test results varied\n");
2579 temp1 = test[2];
2580 }
2581 if(temp1 == 0x02) {
2582 printk(KERN_INFO "%s SVIDEO output\n", stdstr);
2583 ivideo->vbflags |= TV_SVIDEO;
2584 orSISIDXREG(SISCR, 0x32, 0x02);
2585 andSISIDXREG(SISCR, 0x32, ~0x05);
2586 } else if (temp1 == 0x01) {
2587 printk(KERN_INFO "%s CVBS output\n", stdstr);
2588 ivideo->vbflags |= TV_AVIDEO;
2589 orSISIDXREG(SISCR, 0x32, 0x01);
2590 andSISIDXREG(SISCR, 0x32, ~0x06);
2591 } else {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07002592 SiS_SetCH70xxANDOR(&ivideo->SiS_Pr, 0x0e, 0x01, 0xF8);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002593 andSISIDXREG(SISCR, 0x32, ~0x07);
2594 }
2595 } else if(temp1 == 0) {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07002596 SiS_SetCH70xxANDOR(&ivideo->SiS_Pr, 0x0e, 0x01, 0xF8);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002597 andSISIDXREG(SISCR, 0x32, ~0x07);
2598 }
2599 /* Set general purpose IO for Chrontel communication */
2600 SiS_SetChrontelGPIO(&ivideo->SiS_Pr, 0x00);
2601#endif
2602
2603 } else {
2604
2605#ifdef CONFIG_FB_SIS_315
2606 ivideo->SiS_Pr.SiS_IF_DEF_CH70xx = 2; /* Chrontel 7019 */
Thomas Winischhofer544393f2005-09-09 13:04:45 -07002607 temp1 = SiS_GetCH701x(&ivideo->SiS_Pr, 0x49);
2608 SiS_SetCH701x(&ivideo->SiS_Pr, 0x49, 0x20);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002609 SiS_DDC2Delay(&ivideo->SiS_Pr, 0x96);
2610 temp2 = SiS_GetCH701x(&ivideo->SiS_Pr, 0x20);
2611 temp2 |= 0x01;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07002612 SiS_SetCH701x(&ivideo->SiS_Pr, 0x20, temp2);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002613 SiS_DDC2Delay(&ivideo->SiS_Pr, 0x96);
2614 temp2 ^= 0x01;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07002615 SiS_SetCH701x(&ivideo->SiS_Pr, 0x20, temp2);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002616 SiS_DDC2Delay(&ivideo->SiS_Pr, 0x96);
2617 temp2 = SiS_GetCH701x(&ivideo->SiS_Pr, 0x20);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07002618 SiS_SetCH701x(&ivideo->SiS_Pr, 0x49, temp1);
2619 temp1 = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002620 if(temp2 & 0x02) temp1 |= 0x01;
2621 if(temp2 & 0x10) temp1 |= 0x01;
2622 if(temp2 & 0x04) temp1 |= 0x02;
2623 if( (temp1 & 0x01) && (temp1 & 0x02) ) temp1 = 0x04;
2624 switch(temp1) {
2625 case 0x01:
2626 printk(KERN_INFO "%s CVBS output\n", stdstr);
2627 ivideo->vbflags |= TV_AVIDEO;
2628 orSISIDXREG(SISCR, 0x32, 0x01);
2629 andSISIDXREG(SISCR, 0x32, ~0x06);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07002630 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002631 case 0x02:
2632 printk(KERN_INFO "%s SVIDEO output\n", stdstr);
2633 ivideo->vbflags |= TV_SVIDEO;
2634 orSISIDXREG(SISCR, 0x32, 0x02);
2635 andSISIDXREG(SISCR, 0x32, ~0x05);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07002636 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002637 case 0x04:
2638 printk(KERN_INFO "%s SCART output\n", stdstr);
2639 orSISIDXREG(SISCR, 0x32, 0x04);
2640 andSISIDXREG(SISCR, 0x32, ~0x03);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07002641 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002642 default:
2643 andSISIDXREG(SISCR, 0x32, ~0x07);
2644 }
2645#endif
2646 }
2647}
2648
Thomas Winischhofer544393f2005-09-09 13:04:45 -07002649static void __devinit
2650sisfb_get_VB_type(struct sis_video_info *ivideo)
2651{
2652 char stdstr[] = "sisfb: Detected";
2653 char bridgestr[] = "video bridge";
2654 u8 vb_chipid;
2655 u8 reg;
2656
2657 /* No CRT2 on XGI Z7 */
2658 if(ivideo->chip == XGI_20)
2659 return;
2660
2661 inSISIDXREG(SISPART4, 0x00, vb_chipid);
2662 switch(vb_chipid) {
2663 case 0x01:
2664 inSISIDXREG(SISPART4, 0x01, reg);
2665 if(reg < 0xb0) {
2666 ivideo->vbflags |= VB_301; /* Deprecated */
2667 ivideo->vbflags2 |= VB2_301;
2668 printk(KERN_INFO "%s SiS301 %s\n", stdstr, bridgestr);
2669 } else if(reg < 0xc0) {
2670 ivideo->vbflags |= VB_301B; /* Deprecated */
2671 ivideo->vbflags2 |= VB2_301B;
2672 inSISIDXREG(SISPART4,0x23,reg);
2673 if(!(reg & 0x02)) {
2674 ivideo->vbflags |= VB_30xBDH; /* Deprecated */
2675 ivideo->vbflags2 |= VB2_30xBDH;
2676 printk(KERN_INFO "%s SiS301B-DH %s\n", stdstr, bridgestr);
2677 } else {
2678 printk(KERN_INFO "%s SiS301B %s\n", stdstr, bridgestr);
2679 }
2680 } else if(reg < 0xd0) {
2681 ivideo->vbflags |= VB_301C; /* Deprecated */
2682 ivideo->vbflags2 |= VB2_301C;
2683 printk(KERN_INFO "%s SiS301C %s\n", stdstr, bridgestr);
2684 } else if(reg < 0xe0) {
2685 ivideo->vbflags |= VB_301LV; /* Deprecated */
2686 ivideo->vbflags2 |= VB2_301LV;
2687 printk(KERN_INFO "%s SiS301LV %s\n", stdstr, bridgestr);
2688 } else if(reg <= 0xe1) {
2689 inSISIDXREG(SISPART4,0x39,reg);
2690 if(reg == 0xff) {
2691 ivideo->vbflags |= VB_302LV; /* Deprecated */
2692 ivideo->vbflags2 |= VB2_302LV;
2693 printk(KERN_INFO "%s SiS302LV %s\n", stdstr, bridgestr);
2694 } else {
2695 ivideo->vbflags |= VB_301C; /* Deprecated */
2696 ivideo->vbflags2 |= VB2_301C;
2697 printk(KERN_INFO "%s SiS301C(P4) %s\n", stdstr, bridgestr);
2698#if 0
2699 ivideo->vbflags |= VB_302ELV; /* Deprecated */
2700 ivideo->vbflags2 |= VB2_302ELV;
2701 printk(KERN_INFO "%s SiS302ELV %s\n", stdstr, bridgestr);
2702#endif
2703 }
2704 }
2705 break;
2706 case 0x02:
2707 ivideo->vbflags |= VB_302B; /* Deprecated */
2708 ivideo->vbflags2 |= VB2_302B;
2709 printk(KERN_INFO "%s SiS302B %s\n", stdstr, bridgestr);
2710 break;
2711 }
2712
2713 if((!(ivideo->vbflags2 & VB2_VIDEOBRIDGE)) && (ivideo->chip != SIS_300)) {
2714 inSISIDXREG(SISCR, 0x37, reg);
2715 reg &= SIS_EXTERNAL_CHIP_MASK;
2716 reg >>= 1;
2717 if(ivideo->sisvga_engine == SIS_300_VGA) {
2718#ifdef CONFIG_FB_SIS_300
2719 switch(reg) {
2720 case SIS_EXTERNAL_CHIP_LVDS:
2721 ivideo->vbflags |= VB_LVDS; /* Deprecated */
2722 ivideo->vbflags2 |= VB2_LVDS;
2723 break;
2724 case SIS_EXTERNAL_CHIP_TRUMPION:
2725 ivideo->vbflags |= (VB_LVDS | VB_TRUMPION); /* Deprecated */
2726 ivideo->vbflags2 |= (VB2_LVDS | VB2_TRUMPION);
2727 break;
2728 case SIS_EXTERNAL_CHIP_CHRONTEL:
2729 ivideo->vbflags |= VB_CHRONTEL; /* Deprecated */
2730 ivideo->vbflags2 |= VB2_CHRONTEL;
2731 break;
2732 case SIS_EXTERNAL_CHIP_LVDS_CHRONTEL:
2733 ivideo->vbflags |= (VB_LVDS | VB_CHRONTEL); /* Deprecated */
2734 ivideo->vbflags2 |= (VB2_LVDS | VB2_CHRONTEL);
2735 break;
2736 }
2737 if(ivideo->vbflags2 & VB2_CHRONTEL) ivideo->chronteltype = 1;
2738#endif
2739 } else if(ivideo->chip < SIS_661) {
2740#ifdef CONFIG_FB_SIS_315
2741 switch (reg) {
2742 case SIS310_EXTERNAL_CHIP_LVDS:
2743 ivideo->vbflags |= VB_LVDS; /* Deprecated */
2744 ivideo->vbflags2 |= VB2_LVDS;
2745 break;
2746 case SIS310_EXTERNAL_CHIP_LVDS_CHRONTEL:
2747 ivideo->vbflags |= (VB_LVDS | VB_CHRONTEL); /* Deprecated */
2748 ivideo->vbflags2 |= (VB2_LVDS | VB2_CHRONTEL);
2749 break;
2750 }
2751 if(ivideo->vbflags2 & VB2_CHRONTEL) ivideo->chronteltype = 2;
2752#endif
2753 } else if(ivideo->chip >= SIS_661) {
2754#ifdef CONFIG_FB_SIS_315
2755 inSISIDXREG(SISCR, 0x38, reg);
2756 reg >>= 5;
2757 switch(reg) {
2758 case 0x02:
2759 ivideo->vbflags |= VB_LVDS; /* Deprecated */
2760 ivideo->vbflags2 |= VB2_LVDS;
2761 break;
2762 case 0x03:
2763 ivideo->vbflags |= (VB_LVDS | VB_CHRONTEL); /* Deprecated */
2764 ivideo->vbflags2 |= (VB2_LVDS | VB2_CHRONTEL);
2765 break;
2766 case 0x04:
2767 ivideo->vbflags |= (VB_LVDS | VB_CONEXANT); /* Deprecated */
2768 ivideo->vbflags2 |= (VB2_LVDS | VB2_CONEXANT);
2769 break;
2770 }
2771 if(ivideo->vbflags2 & VB2_CHRONTEL) ivideo->chronteltype = 2;
2772#endif
2773 }
2774 if(ivideo->vbflags2 & VB2_LVDS) {
2775 printk(KERN_INFO "%s LVDS transmitter\n", stdstr);
2776 }
2777 if((ivideo->sisvga_engine == SIS_300_VGA) && (ivideo->vbflags2 & VB2_TRUMPION)) {
2778 printk(KERN_INFO "%s Trumpion Zurac LCD scaler\n", stdstr);
2779 }
2780 if(ivideo->vbflags2 & VB2_CHRONTEL) {
2781 printk(KERN_INFO "%s Chrontel TV encoder\n", stdstr);
2782 }
2783 if((ivideo->chip >= SIS_661) && (ivideo->vbflags2 & VB2_CONEXANT)) {
2784 printk(KERN_INFO "%s Conexant external device\n", stdstr);
2785 }
2786 }
2787
2788 if(ivideo->vbflags2 & VB2_SISBRIDGE) {
2789 SiS_SenseLCD(ivideo);
2790 SiS_Sense30x(ivideo);
2791 } else if(ivideo->vbflags2 & VB2_CHRONTEL) {
2792 SiS_SenseCh(ivideo);
2793 }
2794}
2795
2796/* ---------- Engine initialization routines ------------ */
2797
2798static void
2799sisfb_engine_init(struct sis_video_info *ivideo)
2800{
2801
2802 /* Initialize command queue (we use MMIO only) */
2803
2804 /* BEFORE THIS IS CALLED, THE ENGINES *MUST* BE SYNC'ED */
2805
2806 ivideo->caps &= ~(TURBO_QUEUE_CAP |
2807 MMIO_CMD_QUEUE_CAP |
2808 VM_CMD_QUEUE_CAP |
2809 AGP_CMD_QUEUE_CAP);
2810
2811#ifdef CONFIG_FB_SIS_300
2812 if(ivideo->sisvga_engine == SIS_300_VGA) {
2813 u32 tqueue_pos;
2814 u8 tq_state;
2815
2816 tqueue_pos = (ivideo->video_size - ivideo->cmdQueueSize) / (64 * 1024);
2817
2818 inSISIDXREG(SISSR, IND_SIS_TURBOQUEUE_SET, tq_state);
2819 tq_state |= 0xf0;
2820 tq_state &= 0xfc;
2821 tq_state |= (u8)(tqueue_pos >> 8);
2822 outSISIDXREG(SISSR, IND_SIS_TURBOQUEUE_SET, tq_state);
2823
2824 outSISIDXREG(SISSR, IND_SIS_TURBOQUEUE_ADR, (u8)(tqueue_pos & 0xff));
2825
2826 ivideo->caps |= TURBO_QUEUE_CAP;
2827 }
2828#endif
2829
2830#ifdef CONFIG_FB_SIS_315
2831 if(ivideo->sisvga_engine == SIS_315_VGA) {
2832 u32 tempq = 0, templ;
2833 u8 temp;
2834
2835 if(ivideo->chip == XGI_20) {
2836 switch(ivideo->cmdQueueSize) {
2837 case (64 * 1024):
2838 temp = SIS_CMD_QUEUE_SIZE_Z7_64k;
2839 break;
2840 case (128 * 1024):
2841 default:
2842 temp = SIS_CMD_QUEUE_SIZE_Z7_128k;
2843 }
2844 } else {
2845 switch(ivideo->cmdQueueSize) {
2846 case (4 * 1024 * 1024):
2847 temp = SIS_CMD_QUEUE_SIZE_4M;
2848 break;
2849 case (2 * 1024 * 1024):
2850 temp = SIS_CMD_QUEUE_SIZE_2M;
2851 break;
2852 case (1 * 1024 * 1024):
2853 temp = SIS_CMD_QUEUE_SIZE_1M;
2854 break;
2855 default:
2856 case (512 * 1024):
2857 temp = SIS_CMD_QUEUE_SIZE_512k;
2858 }
2859 }
2860
2861 outSISIDXREG(SISSR, IND_SIS_CMDQUEUE_THRESHOLD, COMMAND_QUEUE_THRESHOLD);
2862 outSISIDXREG(SISSR, IND_SIS_CMDQUEUE_SET, SIS_CMD_QUEUE_RESET);
2863
2864 if((ivideo->chip >= XGI_40) && ivideo->modechanged) {
2865 /* Must disable dual pipe on XGI_40. Can't do
2866 * this in MMIO mode, because it requires
2867 * setting/clearing a bit in the MMIO fire trigger
2868 * register.
2869 */
2870 if(!((templ = MMIO_IN32(ivideo->mmio_vbase, 0x8240)) & (1 << 10))) {
2871
2872 MMIO_OUT32(ivideo->mmio_vbase, Q_WRITE_PTR, 0);
2873
2874 outSISIDXREG(SISSR, IND_SIS_CMDQUEUE_SET, (temp | SIS_VRAM_CMDQUEUE_ENABLE));
2875
2876 tempq = MMIO_IN32(ivideo->mmio_vbase, Q_READ_PTR);
2877 MMIO_OUT32(ivideo->mmio_vbase, Q_WRITE_PTR, tempq);
2878
2879 tempq = (u32)(ivideo->video_size - ivideo->cmdQueueSize);
2880 MMIO_OUT32(ivideo->mmio_vbase, Q_BASE_ADDR, tempq);
2881
2882 writel(0x16800000 + 0x8240, ivideo->video_vbase + tempq);
2883 writel(templ | (1 << 10), ivideo->video_vbase + tempq + 4);
2884 writel(0x168F0000, ivideo->video_vbase + tempq + 8);
2885 writel(0x168F0000, ivideo->video_vbase + tempq + 12);
2886
2887 MMIO_OUT32(ivideo->mmio_vbase, Q_WRITE_PTR, (tempq + 16));
2888
2889 sisfb_syncaccel(ivideo);
2890
2891 outSISIDXREG(SISSR, IND_SIS_CMDQUEUE_SET, SIS_CMD_QUEUE_RESET);
2892
2893 }
2894 }
2895
2896 tempq = MMIO_IN32(ivideo->mmio_vbase, MMIO_QUEUE_READPORT);
2897 MMIO_OUT32(ivideo->mmio_vbase, MMIO_QUEUE_WRITEPORT, tempq);
2898
2899 temp |= (SIS_MMIO_CMD_ENABLE | SIS_CMD_AUTO_CORR);
2900 outSISIDXREG(SISSR, IND_SIS_CMDQUEUE_SET, temp);
2901
2902 tempq = (u32)(ivideo->video_size - ivideo->cmdQueueSize);
2903 MMIO_OUT32(ivideo->mmio_vbase, MMIO_QUEUE_PHYBASE, tempq);
2904
2905 ivideo->caps |= MMIO_CMD_QUEUE_CAP;
2906 }
2907#endif
2908
2909 ivideo->engineok = 1;
2910}
2911
2912static void __devinit
2913sisfb_detect_lcd_type(struct sis_video_info *ivideo)
2914{
2915 u8 reg;
2916 int i;
2917
2918 inSISIDXREG(SISCR, 0x36, reg);
2919 reg &= 0x0f;
2920 if(ivideo->sisvga_engine == SIS_300_VGA) {
2921 ivideo->CRT2LCDType = sis300paneltype[reg];
2922 } else if(ivideo->chip >= SIS_661) {
2923 ivideo->CRT2LCDType = sis661paneltype[reg];
2924 } else {
2925 ivideo->CRT2LCDType = sis310paneltype[reg];
2926 if((ivideo->chip == SIS_550) && (sisfb_fstn)) {
2927 if((ivideo->CRT2LCDType != LCD_320x240_2) &&
2928 (ivideo->CRT2LCDType != LCD_320x240_3)) {
2929 ivideo->CRT2LCDType = LCD_320x240;
2930 }
2931 }
2932 }
2933
2934 if(ivideo->CRT2LCDType == LCD_UNKNOWN) {
2935 /* For broken BIOSes: Assume 1024x768, RGB18 */
2936 ivideo->CRT2LCDType = LCD_1024x768;
2937 setSISIDXREG(SISCR,0x36,0xf0,0x02);
2938 setSISIDXREG(SISCR,0x37,0xee,0x01);
2939 printk(KERN_DEBUG "sisfb: Invalid panel ID (%02x), assuming 1024x768, RGB18\n", reg);
2940 }
2941
2942 for(i = 0; i < SIS_LCD_NUMBER; i++) {
2943 if(ivideo->CRT2LCDType == sis_lcd_data[i].lcdtype) {
2944 ivideo->lcdxres = sis_lcd_data[i].xres;
2945 ivideo->lcdyres = sis_lcd_data[i].yres;
2946 ivideo->lcddefmodeidx = sis_lcd_data[i].default_mode_idx;
2947 break;
2948 }
2949 }
2950
2951#ifdef CONFIG_FB_SIS_300
2952 if(ivideo->SiS_Pr.SiS_CustomT == CUT_BARCO1366) {
2953 ivideo->lcdxres = 1360; ivideo->lcdyres = 1024;
2954 ivideo->lcddefmodeidx = DEFAULT_MODE_1360;
2955 } else if(ivideo->SiS_Pr.SiS_CustomT == CUT_PANEL848) {
2956 ivideo->lcdxres = 848; ivideo->lcdyres = 480;
2957 ivideo->lcddefmodeidx = DEFAULT_MODE_848;
2958 } else if(ivideo->SiS_Pr.SiS_CustomT == CUT_PANEL856) {
2959 ivideo->lcdxres = 856; ivideo->lcdyres = 480;
2960 ivideo->lcddefmodeidx = DEFAULT_MODE_856;
2961 }
2962#endif
2963
2964 printk(KERN_DEBUG "sisfb: Detected %dx%d flat panel\n",
2965 ivideo->lcdxres, ivideo->lcdyres);
2966}
2967
2968static void __devinit
2969sisfb_save_pdc_emi(struct sis_video_info *ivideo)
2970{
2971#ifdef CONFIG_FB_SIS_300
2972 /* Save the current PanelDelayCompensation if the LCD is currently used */
2973 if(ivideo->sisvga_engine == SIS_300_VGA) {
2974 if(ivideo->vbflags2 & (VB2_LVDS | VB2_30xBDH)) {
2975 int tmp;
2976 inSISIDXREG(SISCR,0x30,tmp);
2977 if(tmp & 0x20) {
2978 /* Currently on LCD? If yes, read current pdc */
2979 inSISIDXREG(SISPART1,0x13,ivideo->detectedpdc);
2980 ivideo->detectedpdc &= 0x3c;
2981 if(ivideo->SiS_Pr.PDC == -1) {
2982 /* Let option override detection */
2983 ivideo->SiS_Pr.PDC = ivideo->detectedpdc;
2984 }
2985 printk(KERN_INFO "sisfb: Detected LCD PDC 0x%02x\n",
2986 ivideo->detectedpdc);
2987 }
2988 if((ivideo->SiS_Pr.PDC != -1) &&
2989 (ivideo->SiS_Pr.PDC != ivideo->detectedpdc)) {
2990 printk(KERN_INFO "sisfb: Using LCD PDC 0x%02x\n",
2991 ivideo->SiS_Pr.PDC);
2992 }
2993 }
2994 }
2995#endif
2996
2997#ifdef CONFIG_FB_SIS_315
2998 if(ivideo->sisvga_engine == SIS_315_VGA) {
2999
3000 /* Try to find about LCDA */
3001 if(ivideo->vbflags2 & VB2_SISLCDABRIDGE) {
3002 int tmp;
3003 inSISIDXREG(SISPART1,0x13,tmp);
3004 if(tmp & 0x04) {
Richard Knutssonc30660e2007-02-12 00:55:06 -08003005 ivideo->SiS_Pr.SiS_UseLCDA = true;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003006 ivideo->detectedlcda = 0x03;
3007 }
3008 }
3009
3010 /* Save PDC */
3011 if(ivideo->vbflags2 & VB2_SISLVDSBRIDGE) {
3012 int tmp;
3013 inSISIDXREG(SISCR,0x30,tmp);
3014 if((tmp & 0x20) || (ivideo->detectedlcda != 0xff)) {
3015 /* Currently on LCD? If yes, read current pdc */
3016 u8 pdc;
3017 inSISIDXREG(SISPART1,0x2D,pdc);
3018 ivideo->detectedpdc = (pdc & 0x0f) << 1;
3019 ivideo->detectedpdca = (pdc & 0xf0) >> 3;
3020 inSISIDXREG(SISPART1,0x35,pdc);
3021 ivideo->detectedpdc |= ((pdc >> 7) & 0x01);
3022 inSISIDXREG(SISPART1,0x20,pdc);
3023 ivideo->detectedpdca |= ((pdc >> 6) & 0x01);
3024 if(ivideo->newrom) {
3025 /* New ROM invalidates other PDC resp. */
3026 if(ivideo->detectedlcda != 0xff) {
3027 ivideo->detectedpdc = 0xff;
3028 } else {
3029 ivideo->detectedpdca = 0xff;
3030 }
3031 }
3032 if(ivideo->SiS_Pr.PDC == -1) {
3033 if(ivideo->detectedpdc != 0xff) {
3034 ivideo->SiS_Pr.PDC = ivideo->detectedpdc;
3035 }
3036 }
3037 if(ivideo->SiS_Pr.PDCA == -1) {
3038 if(ivideo->detectedpdca != 0xff) {
3039 ivideo->SiS_Pr.PDCA = ivideo->detectedpdca;
3040 }
3041 }
3042 if(ivideo->detectedpdc != 0xff) {
3043 printk(KERN_INFO
3044 "sisfb: Detected LCD PDC 0x%02x (for LCD=CRT2)\n",
3045 ivideo->detectedpdc);
3046 }
3047 if(ivideo->detectedpdca != 0xff) {
3048 printk(KERN_INFO
3049 "sisfb: Detected LCD PDC1 0x%02x (for LCD=CRT1)\n",
3050 ivideo->detectedpdca);
3051 }
3052 }
3053
3054 /* Save EMI */
3055 if(ivideo->vbflags2 & VB2_SISEMIBRIDGE) {
3056 inSISIDXREG(SISPART4,0x30,ivideo->SiS_Pr.EMI_30);
3057 inSISIDXREG(SISPART4,0x31,ivideo->SiS_Pr.EMI_31);
3058 inSISIDXREG(SISPART4,0x32,ivideo->SiS_Pr.EMI_32);
3059 inSISIDXREG(SISPART4,0x33,ivideo->SiS_Pr.EMI_33);
Richard Knutssonc30660e2007-02-12 00:55:06 -08003060 ivideo->SiS_Pr.HaveEMI = true;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003061 if((tmp & 0x20) || (ivideo->detectedlcda != 0xff)) {
Richard Knutssonc30660e2007-02-12 00:55:06 -08003062 ivideo->SiS_Pr.HaveEMILCD = true;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003063 }
3064 }
3065 }
3066
3067 /* Let user override detected PDCs (all bridges) */
3068 if(ivideo->vbflags2 & VB2_30xBLV) {
3069 if((ivideo->SiS_Pr.PDC != -1) &&
3070 (ivideo->SiS_Pr.PDC != ivideo->detectedpdc)) {
3071 printk(KERN_INFO "sisfb: Using LCD PDC 0x%02x (for LCD=CRT2)\n",
3072 ivideo->SiS_Pr.PDC);
3073 }
3074 if((ivideo->SiS_Pr.PDCA != -1) &&
3075 (ivideo->SiS_Pr.PDCA != ivideo->detectedpdca)) {
3076 printk(KERN_INFO "sisfb: Using LCD PDC1 0x%02x (for LCD=CRT1)\n",
3077 ivideo->SiS_Pr.PDCA);
3078 }
3079 }
3080
3081 }
3082#endif
3083}
3084
3085/* -------------------- Memory manager routines ---------------------- */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003086
3087static u32 __devinit
3088sisfb_getheapstart(struct sis_video_info *ivideo)
3089{
3090 u32 ret = ivideo->sisfb_parm_mem * 1024;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003091 u32 maxoffs = ivideo->video_size - ivideo->hwcursor_size - ivideo->cmdQueueSize;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003092 u32 def;
3093
3094 /* Calculate heap start = end of memory for console
3095 *
3096 * CCCCCCCCDDDDDDDDDDDDDDDDDDDDDDDDDDDDHHHHQQQQQQQQQQ
3097 * C = console, D = heap, H = HWCursor, Q = cmd-queue
3098 *
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003099 * On 76x in UMA+LFB mode, the layout is as follows:
3100 * DDDDDDDDDDDCCCCCCCCCCCCCCCCCCCCCCCCHHHHQQQQQQQQQQQ
3101 * where the heap is the entire UMA area, eventually
3102 * into the LFB area if the given mem parameter is
3103 * higher than the size of the UMA memory.
3104 *
Linus Torvalds1da177e2005-04-16 15:20:36 -07003105 * Basically given by "mem" parameter
3106 *
3107 * maximum = videosize - cmd_queue - hwcursor
3108 * (results in a heap of size 0)
3109 * default = SiS 300: depends on videosize
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003110 * SiS 315/330/340/XGI: 32k below max
Linus Torvalds1da177e2005-04-16 15:20:36 -07003111 */
3112
3113 if(ivideo->sisvga_engine == SIS_300_VGA) {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003114 if(ivideo->video_size > 0x1000000) {
3115 def = 0xc00000;
3116 } else if(ivideo->video_size > 0x800000) {
3117 def = 0x800000;
3118 } else {
3119 def = 0x400000;
3120 }
3121 } else if(ivideo->UMAsize && ivideo->LFBsize) {
3122 ret = def = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003123 } else {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003124 def = maxoffs - 0x8000;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003125 }
3126
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003127 /* Use default for secondary card for now (FIXME) */
3128 if((!ret) || (ret > maxoffs) || (ivideo->cardnumber != 0))
3129 ret = def;
3130
3131 return ret;
3132}
3133
3134static u32 __devinit
3135sisfb_getheapsize(struct sis_video_info *ivideo)
3136{
3137 u32 max = ivideo->video_size - ivideo->hwcursor_size - ivideo->cmdQueueSize;
3138 u32 ret = 0;
3139
3140 if(ivideo->UMAsize && ivideo->LFBsize) {
3141 if( (!ivideo->sisfb_parm_mem) ||
3142 ((ivideo->sisfb_parm_mem * 1024) > max) ||
3143 ((max - (ivideo->sisfb_parm_mem * 1024)) < ivideo->UMAsize) ) {
3144 ret = ivideo->UMAsize;
3145 max -= ivideo->UMAsize;
3146 } else {
3147 ret = max - (ivideo->sisfb_parm_mem * 1024);
3148 max = ivideo->sisfb_parm_mem * 1024;
3149 }
3150 ivideo->video_offset = ret;
3151 ivideo->sisfb_mem = max;
3152 } else {
3153 ret = max - ivideo->heapstart;
3154 ivideo->sisfb_mem = ivideo->heapstart;
3155 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003156
3157 return ret;
3158}
3159
3160static int __devinit
3161sisfb_heap_init(struct sis_video_info *ivideo)
3162{
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003163 struct SIS_OH *poh;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003164
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003165 ivideo->video_offset = 0;
3166 if(ivideo->sisfb_parm_mem) {
3167 if( (ivideo->sisfb_parm_mem < (2 * 1024 * 1024)) ||
3168 (ivideo->sisfb_parm_mem > ivideo->video_size) ) {
3169 ivideo->sisfb_parm_mem = 0;
3170 }
3171 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003172
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003173 ivideo->heapstart = sisfb_getheapstart(ivideo);
3174 ivideo->sisfb_heap_size = sisfb_getheapsize(ivideo);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003175
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003176 ivideo->sisfb_heap_start = ivideo->video_vbase + ivideo->heapstart;
3177 ivideo->sisfb_heap_end = ivideo->sisfb_heap_start + ivideo->sisfb_heap_size;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003178
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003179 printk(KERN_INFO "sisfb: Memory heap starting at %dK, size %dK\n",
3180 (int)(ivideo->heapstart / 1024), (int)(ivideo->sisfb_heap_size / 1024));
Linus Torvalds1da177e2005-04-16 15:20:36 -07003181
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003182 ivideo->sisfb_heap.vinfo = ivideo;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003183
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003184 ivideo->sisfb_heap.poha_chain = NULL;
3185 ivideo->sisfb_heap.poh_freelist = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003186
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003187 poh = sisfb_poh_new_node(&ivideo->sisfb_heap);
3188 if(poh == NULL)
3189 return 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003190
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003191 poh->poh_next = &ivideo->sisfb_heap.oh_free;
3192 poh->poh_prev = &ivideo->sisfb_heap.oh_free;
3193 poh->size = ivideo->sisfb_heap_size;
3194 poh->offset = ivideo->heapstart;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003195
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003196 ivideo->sisfb_heap.oh_free.poh_next = poh;
3197 ivideo->sisfb_heap.oh_free.poh_prev = poh;
3198 ivideo->sisfb_heap.oh_free.size = 0;
3199 ivideo->sisfb_heap.max_freesize = poh->size;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003200
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003201 ivideo->sisfb_heap.oh_used.poh_next = &ivideo->sisfb_heap.oh_used;
3202 ivideo->sisfb_heap.oh_used.poh_prev = &ivideo->sisfb_heap.oh_used;
3203 ivideo->sisfb_heap.oh_used.size = SENTINEL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003204
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003205 if(ivideo->cardnumber == 0) {
3206 /* For the first card, make this heap the "global" one
3207 * for old DRM (which could handle only one card)
3208 */
3209 sisfb_heap = &ivideo->sisfb_heap;
3210 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003211
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003212 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003213}
3214
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003215static struct SIS_OH *
3216sisfb_poh_new_node(struct SIS_HEAP *memheap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003217{
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003218 struct SIS_OHALLOC *poha;
3219 struct SIS_OH *poh;
3220 unsigned long cOhs;
3221 int i;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003222
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003223 if(memheap->poh_freelist == NULL) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003224 poha = kmalloc(SIS_OH_ALLOC_SIZE, GFP_KERNEL);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003225 if(!poha)
3226 return NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003227
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003228 poha->poha_next = memheap->poha_chain;
3229 memheap->poha_chain = poha;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003230
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003231 cOhs = (SIS_OH_ALLOC_SIZE - sizeof(struct SIS_OHALLOC)) / sizeof(struct SIS_OH) + 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003232
3233 poh = &poha->aoh[0];
3234 for(i = cOhs - 1; i != 0; i--) {
3235 poh->poh_next = poh + 1;
3236 poh = poh + 1;
3237 }
3238
3239 poh->poh_next = NULL;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003240 memheap->poh_freelist = &poha->aoh[0];
Linus Torvalds1da177e2005-04-16 15:20:36 -07003241 }
3242
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003243 poh = memheap->poh_freelist;
3244 memheap->poh_freelist = poh->poh_next;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003245
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003246 return poh;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003247}
3248
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003249static struct SIS_OH *
3250sisfb_poh_allocate(struct SIS_HEAP *memheap, u32 size)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003251{
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003252 struct SIS_OH *pohThis;
3253 struct SIS_OH *pohRoot;
3254 int bAllocated = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003255
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003256 if(size > memheap->max_freesize) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003257 DPRINTK("sisfb: Can't allocate %dk video memory\n",
3258 (unsigned int) size / 1024);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003259 return NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003260 }
3261
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003262 pohThis = memheap->oh_free.poh_next;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003263
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003264 while(pohThis != &memheap->oh_free) {
3265 if(size <= pohThis->size) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003266 bAllocated = 1;
3267 break;
3268 }
3269 pohThis = pohThis->poh_next;
3270 }
3271
3272 if(!bAllocated) {
3273 DPRINTK("sisfb: Can't allocate %dk video memory\n",
3274 (unsigned int) size / 1024);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003275 return NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003276 }
3277
3278 if(size == pohThis->size) {
3279 pohRoot = pohThis;
3280 sisfb_delete_node(pohThis);
3281 } else {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003282 pohRoot = sisfb_poh_new_node(memheap);
3283 if(pohRoot == NULL)
3284 return NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003285
3286 pohRoot->offset = pohThis->offset;
3287 pohRoot->size = size;
3288
3289 pohThis->offset += size;
3290 pohThis->size -= size;
3291 }
3292
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003293 memheap->max_freesize -= size;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003294
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003295 pohThis = &memheap->oh_used;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003296 sisfb_insert_node(pohThis, pohRoot);
3297
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003298 return pohRoot;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003299}
3300
3301static void
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003302sisfb_delete_node(struct SIS_OH *poh)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003303{
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003304 poh->poh_prev->poh_next = poh->poh_next;
3305 poh->poh_next->poh_prev = poh->poh_prev;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003306}
3307
3308static void
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003309sisfb_insert_node(struct SIS_OH *pohList, struct SIS_OH *poh)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003310{
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003311 struct SIS_OH *pohTemp = pohList->poh_next;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003312
3313 pohList->poh_next = poh;
3314 pohTemp->poh_prev = poh;
3315
3316 poh->poh_prev = pohList;
3317 poh->poh_next = pohTemp;
3318}
3319
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003320static struct SIS_OH *
3321sisfb_poh_free(struct SIS_HEAP *memheap, u32 base)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003322{
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003323 struct SIS_OH *pohThis;
3324 struct SIS_OH *poh_freed;
3325 struct SIS_OH *poh_prev;
3326 struct SIS_OH *poh_next;
3327 u32 ulUpper;
3328 u32 ulLower;
3329 int foundNode = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003330
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003331 poh_freed = memheap->oh_used.poh_next;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003332
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003333 while(poh_freed != &memheap->oh_used) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003334 if(poh_freed->offset == base) {
3335 foundNode = 1;
3336 break;
3337 }
3338
3339 poh_freed = poh_freed->poh_next;
3340 }
3341
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003342 if(!foundNode)
3343 return NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003344
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003345 memheap->max_freesize += poh_freed->size;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003346
3347 poh_prev = poh_next = NULL;
3348 ulUpper = poh_freed->offset + poh_freed->size;
3349 ulLower = poh_freed->offset;
3350
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003351 pohThis = memheap->oh_free.poh_next;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003352
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003353 while(pohThis != &memheap->oh_free) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003354 if(pohThis->offset == ulUpper) {
3355 poh_next = pohThis;
3356 } else if((pohThis->offset + pohThis->size) == ulLower) {
3357 poh_prev = pohThis;
3358 }
3359 pohThis = pohThis->poh_next;
3360 }
3361
3362 sisfb_delete_node(poh_freed);
3363
3364 if(poh_prev && poh_next) {
3365 poh_prev->size += (poh_freed->size + poh_next->size);
3366 sisfb_delete_node(poh_next);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003367 sisfb_free_node(memheap, poh_freed);
3368 sisfb_free_node(memheap, poh_next);
3369 return poh_prev;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003370 }
3371
3372 if(poh_prev) {
3373 poh_prev->size += poh_freed->size;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003374 sisfb_free_node(memheap, poh_freed);
3375 return poh_prev;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003376 }
3377
3378 if(poh_next) {
3379 poh_next->size += poh_freed->size;
3380 poh_next->offset = poh_freed->offset;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003381 sisfb_free_node(memheap, poh_freed);
3382 return poh_next;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003383 }
3384
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003385 sisfb_insert_node(&memheap->oh_free, poh_freed);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003386
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003387 return poh_freed;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003388}
3389
3390static void
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003391sisfb_free_node(struct SIS_HEAP *memheap, struct SIS_OH *poh)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003392{
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003393 if(poh == NULL)
3394 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003395
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003396 poh->poh_next = memheap->poh_freelist;
3397 memheap->poh_freelist = poh;
3398}
3399
3400static void
3401sis_int_malloc(struct sis_video_info *ivideo, struct sis_memreq *req)
3402{
3403 struct SIS_OH *poh = NULL;
3404
3405 if((ivideo) && (ivideo->sisfb_id == SISFB_ID) && (!ivideo->havenoheap))
3406 poh = sisfb_poh_allocate(&ivideo->sisfb_heap, (u32)req->size);
3407
3408 if(poh == NULL) {
3409 req->offset = req->size = 0;
3410 DPRINTK("sisfb: Video RAM allocation failed\n");
3411 } else {
3412 req->offset = poh->offset;
3413 req->size = poh->size;
3414 DPRINTK("sisfb: Video RAM allocation succeeded: 0x%lx\n",
3415 (poh->offset + ivideo->video_vbase));
3416 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003417}
3418
3419void
3420sis_malloc(struct sis_memreq *req)
3421{
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003422 struct sis_video_info *ivideo = sisfb_heap->vinfo;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003423
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003424 if(&ivideo->sisfb_heap == sisfb_heap)
3425 sis_int_malloc(ivideo, req);
3426 else
3427 req->offset = req->size = 0;
3428}
Linus Torvalds1da177e2005-04-16 15:20:36 -07003429
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003430void
3431sis_malloc_new(struct pci_dev *pdev, struct sis_memreq *req)
3432{
3433 struct sis_video_info *ivideo = pci_get_drvdata(pdev);
3434
3435 sis_int_malloc(ivideo, req);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003436}
3437
3438/* sis_free: u32 because "base" is offset inside video ram, can never be >4GB */
3439
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003440static void
3441sis_int_free(struct sis_video_info *ivideo, u32 base)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003442{
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003443 struct SIS_OH *poh;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003444
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003445 if((!ivideo) || (ivideo->sisfb_id != SISFB_ID) || (ivideo->havenoheap))
3446 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003447
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003448 poh = sisfb_poh_free(&ivideo->sisfb_heap, base);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003449
3450 if(poh == NULL) {
3451 DPRINTK("sisfb: sisfb_poh_free() failed at base 0x%x\n",
3452 (unsigned int) base);
3453 }
3454}
3455
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003456void
3457sis_free(u32 base)
3458{
3459 struct sis_video_info *ivideo = sisfb_heap->vinfo;
3460
3461 sis_int_free(ivideo, base);
3462}
3463
3464void
3465sis_free_new(struct pci_dev *pdev, u32 base)
3466{
3467 struct sis_video_info *ivideo = pci_get_drvdata(pdev);
3468
3469 sis_int_free(ivideo, base);
3470}
3471
Linus Torvalds1da177e2005-04-16 15:20:36 -07003472/* --------------------- SetMode routines ------------------------- */
3473
3474static void
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003475sisfb_check_engine_and_sync(struct sis_video_info *ivideo)
3476{
3477 u8 cr30, cr31;
3478
3479 /* Check if MMIO and engines are enabled,
3480 * and sync in case they are. Can't use
3481 * ivideo->accel here, as this might have
3482 * been changed before this is called.
3483 */
3484 inSISIDXREG(SISSR, IND_SIS_PCI_ADDRESS_SET, cr30);
3485 inSISIDXREG(SISSR, IND_SIS_MODULE_ENABLE, cr31);
3486 /* MMIO and 2D/3D engine enabled? */
3487 if((cr30 & SIS_MEM_MAP_IO_ENABLE) && (cr31 & 0x42)) {
3488#ifdef CONFIG_FB_SIS_300
3489 if(ivideo->sisvga_engine == SIS_300_VGA) {
3490 /* Don't care about TurboQueue. It's
3491 * enough to know that the engines
3492 * are enabled
3493 */
3494 sisfb_syncaccel(ivideo);
3495 }
3496#endif
3497#ifdef CONFIG_FB_SIS_315
3498 if(ivideo->sisvga_engine == SIS_315_VGA) {
3499 /* Check that any queue mode is
3500 * enabled, and that the queue
3501 * is not in the state of "reset"
3502 */
3503 inSISIDXREG(SISSR, 0x26, cr30);
3504 if((cr30 & 0xe0) && (!(cr30 & 0x01))) {
3505 sisfb_syncaccel(ivideo);
3506 }
3507 }
3508#endif
3509 }
3510}
3511
3512static void
Linus Torvalds1da177e2005-04-16 15:20:36 -07003513sisfb_pre_setmode(struct sis_video_info *ivideo)
3514{
3515 u8 cr30 = 0, cr31 = 0, cr33 = 0, cr35 = 0, cr38 = 0;
3516 int tvregnum = 0;
3517
3518 ivideo->currentvbflags &= (VB_VIDEOBRIDGE | VB_DISPTYPE_DISP2);
3519
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003520 outSISIDXREG(SISSR, 0x05, 0x86);
3521
Linus Torvalds1da177e2005-04-16 15:20:36 -07003522 inSISIDXREG(SISCR, 0x31, cr31);
3523 cr31 &= ~0x60;
3524 cr31 |= 0x04;
3525
3526 cr33 = ivideo->rate_idx & 0x0F;
3527
3528#ifdef CONFIG_FB_SIS_315
3529 if(ivideo->sisvga_engine == SIS_315_VGA) {
3530 if(ivideo->chip >= SIS_661) {
3531 inSISIDXREG(SISCR, 0x38, cr38);
3532 cr38 &= ~0x07; /* Clear LCDA/DualEdge and YPbPr bits */
3533 } else {
3534 tvregnum = 0x38;
3535 inSISIDXREG(SISCR, tvregnum, cr38);
3536 cr38 &= ~0x3b; /* Clear LCDA/DualEdge and YPbPr bits */
3537 }
3538 }
3539#endif
3540#ifdef CONFIG_FB_SIS_300
3541 if(ivideo->sisvga_engine == SIS_300_VGA) {
3542 tvregnum = 0x35;
3543 inSISIDXREG(SISCR, tvregnum, cr38);
3544 }
3545#endif
3546
Richard Knutssonc30660e2007-02-12 00:55:06 -08003547 SiS_SetEnableDstn(&ivideo->SiS_Pr, false);
3548 SiS_SetEnableFstn(&ivideo->SiS_Pr, false);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003549 ivideo->curFSTN = ivideo->curDSTN = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003550
3551 switch(ivideo->currentvbflags & VB_DISPTYPE_DISP2) {
3552
3553 case CRT2_TV:
3554 cr38 &= ~0xc0; /* Clear PAL-M / PAL-N bits */
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003555 if((ivideo->vbflags & TV_YPBPR) && (ivideo->vbflags2 & VB2_SISYPBPRBRIDGE)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003556#ifdef CONFIG_FB_SIS_315
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003557 if(ivideo->chip >= SIS_661) {
3558 cr38 |= 0x04;
3559 if(ivideo->vbflags & TV_YPBPR525P) cr35 |= 0x20;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003560 else if(ivideo->vbflags & TV_YPBPR750P) cr35 |= 0x40;
3561 else if(ivideo->vbflags & TV_YPBPR1080I) cr35 |= 0x60;
3562 cr30 |= SIS_SIMULTANEOUS_VIEW_ENABLE;
3563 cr35 &= ~0x01;
3564 ivideo->currentvbflags |= (TV_YPBPR | (ivideo->vbflags & TV_YPBPRALL));
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003565 } else if(ivideo->sisvga_engine == SIS_315_VGA) {
3566 cr30 |= (0x80 | SIS_SIMULTANEOUS_VIEW_ENABLE);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003567 cr38 |= 0x08;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003568 if(ivideo->vbflags & TV_YPBPR525P) cr38 |= 0x10;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003569 else if(ivideo->vbflags & TV_YPBPR750P) cr38 |= 0x20;
3570 else if(ivideo->vbflags & TV_YPBPR1080I) cr38 |= 0x30;
3571 cr31 &= ~0x01;
3572 ivideo->currentvbflags |= (TV_YPBPR | (ivideo->vbflags & TV_YPBPRALL));
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003573 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003574#endif
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003575 } else if((ivideo->vbflags & TV_HIVISION) &&
3576 (ivideo->vbflags2 & VB2_SISHIVISIONBRIDGE)) {
3577 if(ivideo->chip >= SIS_661) {
3578 cr38 |= 0x04;
3579 cr35 |= 0x60;
3580 } else {
3581 cr30 |= 0x80;
3582 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003583 cr30 |= SIS_SIMULTANEOUS_VIEW_ENABLE;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003584 cr31 |= 0x01;
3585 cr35 |= 0x01;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003586 ivideo->currentvbflags |= TV_HIVISION;
3587 } else if(ivideo->vbflags & TV_SCART) {
3588 cr30 = (SIS_VB_OUTPUT_SCART | SIS_SIMULTANEOUS_VIEW_ENABLE);
3589 cr31 |= 0x01;
3590 cr35 |= 0x01;
3591 ivideo->currentvbflags |= TV_SCART;
3592 } else {
3593 if(ivideo->vbflags & TV_SVIDEO) {
3594 cr30 = (SIS_VB_OUTPUT_SVIDEO | SIS_SIMULTANEOUS_VIEW_ENABLE);
3595 ivideo->currentvbflags |= TV_SVIDEO;
3596 }
3597 if(ivideo->vbflags & TV_AVIDEO) {
3598 cr30 = (SIS_VB_OUTPUT_COMPOSITE | SIS_SIMULTANEOUS_VIEW_ENABLE);
3599 ivideo->currentvbflags |= TV_AVIDEO;
3600 }
3601 }
3602 cr31 |= SIS_DRIVER_MODE;
3603
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003604 if(ivideo->vbflags & (TV_AVIDEO | TV_SVIDEO)) {
3605 if(ivideo->vbflags & TV_PAL) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003606 cr31 |= 0x01; cr35 |= 0x01;
3607 ivideo->currentvbflags |= TV_PAL;
3608 if(ivideo->vbflags & TV_PALM) {
3609 cr38 |= 0x40; cr35 |= 0x04;
3610 ivideo->currentvbflags |= TV_PALM;
3611 } else if(ivideo->vbflags & TV_PALN) {
3612 cr38 |= 0x80; cr35 |= 0x08;
3613 ivideo->currentvbflags |= TV_PALN;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003614 }
3615 } else {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003616 cr31 &= ~0x01; cr35 &= ~0x01;
3617 ivideo->currentvbflags |= TV_NTSC;
3618 if(ivideo->vbflags & TV_NTSCJ) {
3619 cr38 |= 0x40; cr35 |= 0x02;
3620 ivideo->currentvbflags |= TV_NTSCJ;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003621 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003622 }
3623 }
3624 break;
3625
3626 case CRT2_LCD:
3627 cr30 = (SIS_VB_OUTPUT_LCD | SIS_SIMULTANEOUS_VIEW_ENABLE);
3628 cr31 |= SIS_DRIVER_MODE;
3629 SiS_SetEnableDstn(&ivideo->SiS_Pr, ivideo->sisfb_dstn);
3630 SiS_SetEnableFstn(&ivideo->SiS_Pr, ivideo->sisfb_fstn);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003631 ivideo->curFSTN = ivideo->sisfb_fstn;
3632 ivideo->curDSTN = ivideo->sisfb_dstn;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003633 break;
3634
3635 case CRT2_VGA:
3636 cr30 = (SIS_VB_OUTPUT_CRT2 | SIS_SIMULTANEOUS_VIEW_ENABLE);
3637 cr31 |= SIS_DRIVER_MODE;
3638 if(ivideo->sisfb_nocrt2rate) {
3639 cr33 |= (sisbios_mode[ivideo->sisfb_mode_idx].rate_idx << 4);
3640 } else {
3641 cr33 |= ((ivideo->rate_idx & 0x0F) << 4);
3642 }
3643 break;
3644
3645 default: /* disable CRT2 */
3646 cr30 = 0x00;
3647 cr31 |= (SIS_DRIVER_MODE | SIS_VB_OUTPUT_DISABLE);
3648 }
3649
3650 outSISIDXREG(SISCR, 0x30, cr30);
3651 outSISIDXREG(SISCR, 0x33, cr33);
3652
3653 if(ivideo->chip >= SIS_661) {
3654#ifdef CONFIG_FB_SIS_315
3655 cr31 &= ~0x01; /* Clear PAL flag (now in CR35) */
3656 setSISIDXREG(SISCR, 0x35, ~0x10, cr35); /* Leave overscan bit alone */
3657 cr38 &= 0x07; /* Use only LCDA and HiVision/YPbPr bits */
3658 setSISIDXREG(SISCR, 0x38, 0xf8, cr38);
3659#endif
3660 } else if(ivideo->chip != SIS_300) {
3661 outSISIDXREG(SISCR, tvregnum, cr38);
3662 }
3663 outSISIDXREG(SISCR, 0x31, cr31);
3664
Linus Torvalds1da177e2005-04-16 15:20:36 -07003665 ivideo->SiS_Pr.SiS_UseOEM = ivideo->sisfb_useoem;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003666
3667 sisfb_check_engine_and_sync(ivideo);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003668}
3669
3670/* Fix SR11 for 661 and later */
3671#ifdef CONFIG_FB_SIS_315
3672static void
3673sisfb_fixup_SR11(struct sis_video_info *ivideo)
3674{
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003675 u8 tmpreg;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003676
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003677 if(ivideo->chip >= SIS_661) {
3678 inSISIDXREG(SISSR,0x11,tmpreg);
3679 if(tmpreg & 0x20) {
3680 inSISIDXREG(SISSR,0x3e,tmpreg);
3681 tmpreg = (tmpreg + 1) & 0xff;
3682 outSISIDXREG(SISSR,0x3e,tmpreg);
3683 inSISIDXREG(SISSR,0x11,tmpreg);
3684 }
3685 if(tmpreg & 0xf0) {
3686 andSISIDXREG(SISSR,0x11,0x0f);
3687 }
3688 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003689}
3690#endif
3691
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003692static void
3693sisfb_set_TVxposoffset(struct sis_video_info *ivideo, int val)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003694{
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003695 if(val > 32) val = 32;
3696 if(val < -32) val = -32;
3697 ivideo->tvxpos = val;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003698
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003699 if(ivideo->sisfblocked) return;
3700 if(!ivideo->modechanged) return;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003701
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003702 if(ivideo->currentvbflags & CRT2_TV) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003703
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003704 if(ivideo->vbflags2 & VB2_CHRONTEL) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003705
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003706 int x = ivideo->tvx;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003707
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003708 switch(ivideo->chronteltype) {
3709 case 1:
3710 x += val;
3711 if(x < 0) x = 0;
3712 outSISIDXREG(SISSR,0x05,0x86);
3713 SiS_SetCH700x(&ivideo->SiS_Pr, 0x0a, (x & 0xff));
3714 SiS_SetCH70xxANDOR(&ivideo->SiS_Pr, 0x08, ((x & 0x0100) >> 7), 0xFD);
3715 break;
3716 case 2:
3717 /* Not supported by hardware */
3718 break;
3719 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003720
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003721 } else if(ivideo->vbflags2 & VB2_SISBRIDGE) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003722
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003723 u8 p2_1f,p2_20,p2_2b,p2_42,p2_43;
3724 unsigned short temp;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003725
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003726 p2_1f = ivideo->p2_1f;
3727 p2_20 = ivideo->p2_20;
3728 p2_2b = ivideo->p2_2b;
3729 p2_42 = ivideo->p2_42;
3730 p2_43 = ivideo->p2_43;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003731
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003732 temp = p2_1f | ((p2_20 & 0xf0) << 4);
3733 temp += (val * 2);
3734 p2_1f = temp & 0xff;
3735 p2_20 = (temp & 0xf00) >> 4;
3736 p2_2b = ((p2_2b & 0x0f) + (val * 2)) & 0x0f;
3737 temp = p2_43 | ((p2_42 & 0xf0) << 4);
3738 temp += (val * 2);
3739 p2_43 = temp & 0xff;
3740 p2_42 = (temp & 0xf00) >> 4;
3741 outSISIDXREG(SISPART2,0x1f,p2_1f);
3742 setSISIDXREG(SISPART2,0x20,0x0F,p2_20);
3743 setSISIDXREG(SISPART2,0x2b,0xF0,p2_2b);
3744 setSISIDXREG(SISPART2,0x42,0x0F,p2_42);
3745 outSISIDXREG(SISPART2,0x43,p2_43);
3746 }
3747 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003748}
3749
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003750static void
3751sisfb_set_TVyposoffset(struct sis_video_info *ivideo, int val)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003752{
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003753 if(val > 32) val = 32;
3754 if(val < -32) val = -32;
3755 ivideo->tvypos = val;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003756
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003757 if(ivideo->sisfblocked) return;
3758 if(!ivideo->modechanged) return;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003759
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003760 if(ivideo->currentvbflags & CRT2_TV) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003761
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003762 if(ivideo->vbflags2 & VB2_CHRONTEL) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003763
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003764 int y = ivideo->tvy;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003765
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003766 switch(ivideo->chronteltype) {
3767 case 1:
3768 y -= val;
3769 if(y < 0) y = 0;
3770 outSISIDXREG(SISSR,0x05,0x86);
3771 SiS_SetCH700x(&ivideo->SiS_Pr, 0x0b, (y & 0xff));
3772 SiS_SetCH70xxANDOR(&ivideo->SiS_Pr, 0x08, ((y & 0x0100) >> 8), 0xFE);
3773 break;
3774 case 2:
3775 /* Not supported by hardware */
3776 break;
3777 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003778
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003779 } else if(ivideo->vbflags2 & VB2_SISBRIDGE) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003780
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003781 char p2_01, p2_02;
3782 val /= 2;
3783 p2_01 = ivideo->p2_01;
3784 p2_02 = ivideo->p2_02;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003785
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003786 p2_01 += val;
3787 p2_02 += val;
3788 if(!(ivideo->currentvbflags & (TV_HIVISION | TV_YPBPR))) {
3789 while((p2_01 <= 0) || (p2_02 <= 0)) {
3790 p2_01 += 2;
3791 p2_02 += 2;
3792 }
3793 }
3794 outSISIDXREG(SISPART2,0x01,p2_01);
3795 outSISIDXREG(SISPART2,0x02,p2_02);
3796 }
3797 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003798}
3799
3800static void
3801sisfb_post_setmode(struct sis_video_info *ivideo)
3802{
Richard Knutssonc30660e2007-02-12 00:55:06 -08003803 bool crt1isoff = false;
3804 bool doit = true;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003805#if defined(CONFIG_FB_SIS_300) || defined(CONFIG_FB_SIS_315)
3806 u8 reg;
3807#endif
3808#ifdef CONFIG_FB_SIS_315
3809 u8 reg1;
3810#endif
3811
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003812 outSISIDXREG(SISSR, 0x05, 0x86);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003813
3814#ifdef CONFIG_FB_SIS_315
3815 sisfb_fixup_SR11(ivideo);
3816#endif
3817
3818 /* Now we actually HAVE changed the display mode */
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003819 ivideo->modechanged = 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003820
3821 /* We can't switch off CRT1 if bridge is in slave mode */
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003822 if(ivideo->vbflags2 & VB2_VIDEOBRIDGE) {
Richard Knutssonc30660e2007-02-12 00:55:06 -08003823 if(sisfb_bridgeisslave(ivideo)) doit = false;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003824 } else
3825 ivideo->sisfb_crt1off = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003826
3827#ifdef CONFIG_FB_SIS_300
3828 if(ivideo->sisvga_engine == SIS_300_VGA) {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003829 if((ivideo->sisfb_crt1off) && (doit)) {
Richard Knutssonc30660e2007-02-12 00:55:06 -08003830 crt1isoff = true;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003831 reg = 0x00;
3832 } else {
Richard Knutssonc30660e2007-02-12 00:55:06 -08003833 crt1isoff = false;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003834 reg = 0x80;
3835 }
3836 setSISIDXREG(SISCR, 0x17, 0x7f, reg);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003837 }
3838#endif
3839#ifdef CONFIG_FB_SIS_315
3840 if(ivideo->sisvga_engine == SIS_315_VGA) {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003841 if((ivideo->sisfb_crt1off) && (doit)) {
Richard Knutssonc30660e2007-02-12 00:55:06 -08003842 crt1isoff = true;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003843 reg = 0x40;
3844 reg1 = 0xc0;
3845 } else {
Richard Knutssonc30660e2007-02-12 00:55:06 -08003846 crt1isoff = false;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003847 reg = 0x00;
3848 reg1 = 0x00;
3849 }
3850 setSISIDXREG(SISCR, ivideo->SiS_Pr.SiS_MyCR63, ~0x40, reg);
3851 setSISIDXREG(SISSR, 0x1f, ~0xc0, reg1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003852 }
3853#endif
3854
3855 if(crt1isoff) {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003856 ivideo->currentvbflags &= ~VB_DISPTYPE_CRT1;
3857 ivideo->currentvbflags |= VB_SINGLE_MODE;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003858 } else {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003859 ivideo->currentvbflags |= VB_DISPTYPE_CRT1;
3860 if(ivideo->currentvbflags & VB_DISPTYPE_CRT2) {
3861 ivideo->currentvbflags |= VB_MIRROR_MODE;
3862 } else {
3863 ivideo->currentvbflags |= VB_SINGLE_MODE;
3864 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003865 }
3866
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003867 andSISIDXREG(SISSR, IND_SIS_RAMDAC_CONTROL, ~0x04);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003868
3869 if(ivideo->currentvbflags & CRT2_TV) {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003870 if(ivideo->vbflags2 & VB2_SISBRIDGE) {
3871 inSISIDXREG(SISPART2,0x1f,ivideo->p2_1f);
3872 inSISIDXREG(SISPART2,0x20,ivideo->p2_20);
3873 inSISIDXREG(SISPART2,0x2b,ivideo->p2_2b);
3874 inSISIDXREG(SISPART2,0x42,ivideo->p2_42);
3875 inSISIDXREG(SISPART2,0x43,ivideo->p2_43);
3876 inSISIDXREG(SISPART2,0x01,ivideo->p2_01);
3877 inSISIDXREG(SISPART2,0x02,ivideo->p2_02);
3878 } else if(ivideo->vbflags2 & VB2_CHRONTEL) {
3879 if(ivideo->chronteltype == 1) {
3880 ivideo->tvx = SiS_GetCH700x(&ivideo->SiS_Pr, 0x0a);
3881 ivideo->tvx |= (((SiS_GetCH700x(&ivideo->SiS_Pr, 0x08) & 0x02) >> 1) << 8);
3882 ivideo->tvy = SiS_GetCH700x(&ivideo->SiS_Pr, 0x0b);
3883 ivideo->tvy |= ((SiS_GetCH700x(&ivideo->SiS_Pr, 0x08) & 0x01) << 8);
3884 }
3885 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003886 }
3887
3888 if(ivideo->tvxpos) {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003889 sisfb_set_TVxposoffset(ivideo, ivideo->tvxpos);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003890 }
3891 if(ivideo->tvypos) {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003892 sisfb_set_TVyposoffset(ivideo, ivideo->tvypos);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003893 }
3894
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003895 /* Eventually sync engines */
3896 sisfb_check_engine_and_sync(ivideo);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003897
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003898 /* (Re-)Initialize chip engines */
3899 if(ivideo->accel) {
3900 sisfb_engine_init(ivideo);
3901 } else {
3902 ivideo->engineok = 0;
3903 }
3904}
Linus Torvalds1da177e2005-04-16 15:20:36 -07003905
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003906static int
3907sisfb_reset_mode(struct sis_video_info *ivideo)
3908{
3909 if(sisfb_set_mode(ivideo, 0))
3910 return 1;
3911
3912 sisfb_set_pitch(ivideo);
3913 sisfb_set_base_CRT1(ivideo, ivideo->current_base);
3914 sisfb_set_base_CRT2(ivideo, ivideo->current_base);
3915
3916 return 0;
3917}
3918
3919static void
3920sisfb_handle_command(struct sis_video_info *ivideo, struct sisfb_cmd *sisfb_command)
3921{
3922 int mycrt1off;
3923
3924 switch(sisfb_command->sisfb_cmd) {
3925 case SISFB_CMD_GETVBFLAGS:
3926 if(!ivideo->modechanged) {
3927 sisfb_command->sisfb_result[0] = SISFB_CMD_ERR_EARLY;
3928 } else {
3929 sisfb_command->sisfb_result[0] = SISFB_CMD_ERR_OK;
3930 sisfb_command->sisfb_result[1] = ivideo->currentvbflags;
3931 sisfb_command->sisfb_result[2] = ivideo->vbflags2;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003932 }
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003933 break;
3934 case SISFB_CMD_SWITCHCRT1:
3935 /* arg[0]: 0 = off, 1 = on, 99 = query */
3936 if(!ivideo->modechanged) {
3937 sisfb_command->sisfb_result[0] = SISFB_CMD_ERR_EARLY;
3938 } else if(sisfb_command->sisfb_arg[0] == 99) {
3939 /* Query */
3940 sisfb_command->sisfb_result[1] = ivideo->sisfb_crt1off ? 0 : 1;
3941 sisfb_command->sisfb_result[0] = SISFB_CMD_ERR_OK;
3942 } else if(ivideo->sisfblocked) {
3943 sisfb_command->sisfb_result[0] = SISFB_CMD_ERR_LOCKED;
3944 } else if((!(ivideo->currentvbflags & CRT2_ENABLE)) &&
3945 (sisfb_command->sisfb_arg[0] == 0)) {
3946 sisfb_command->sisfb_result[0] = SISFB_CMD_ERR_NOCRT2;
3947 } else {
3948 sisfb_command->sisfb_result[0] = SISFB_CMD_ERR_OK;
3949 mycrt1off = sisfb_command->sisfb_arg[0] ? 0 : 1;
3950 if( ((ivideo->currentvbflags & VB_DISPTYPE_CRT1) && mycrt1off) ||
3951 ((!(ivideo->currentvbflags & VB_DISPTYPE_CRT1)) && !mycrt1off) ) {
3952 ivideo->sisfb_crt1off = mycrt1off;
3953 if(sisfb_reset_mode(ivideo)) {
3954 sisfb_command->sisfb_result[0] = SISFB_CMD_ERR_OTHER;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003955 }
3956 }
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003957 sisfb_command->sisfb_result[1] = ivideo->sisfb_crt1off ? 0 : 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003958 }
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003959 break;
3960 /* more to come */
3961 default:
3962 sisfb_command->sisfb_result[0] = SISFB_CMD_ERR_UNKNOWN;
3963 printk(KERN_ERR "sisfb: Unknown command 0x%x\n",
3964 sisfb_command->sisfb_cmd);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003965 }
3966}
3967
3968#ifndef MODULE
Adrian Bunk14aefd12008-07-23 21:31:12 -07003969static int __init sisfb_setup(char *options)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003970{
3971 char *this_opt;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003972
Linus Torvalds1da177e2005-04-16 15:20:36 -07003973 sisfb_setdefaultparms();
3974
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003975 if(!options || !(*options))
Linus Torvalds1da177e2005-04-16 15:20:36 -07003976 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003977
3978 while((this_opt = strsep(&options, ",")) != NULL) {
3979
3980 if(!(*this_opt)) continue;
3981
3982 if(!strnicmp(this_opt, "off", 3)) {
3983 sisfb_off = 1;
3984 } else if(!strnicmp(this_opt, "forcecrt2type:", 14)) {
3985 /* Need to check crt2 type first for fstn/dstn */
3986 sisfb_search_crt2type(this_opt + 14);
3987 } else if(!strnicmp(this_opt, "tvmode:",7)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003988 sisfb_search_tvstd(this_opt + 7);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003989 } else if(!strnicmp(this_opt, "tvstandard:",11)) {
3990 sisfb_search_tvstd(this_opt + 11);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003991 } else if(!strnicmp(this_opt, "mode:", 5)) {
Richard Knutssonc30660e2007-02-12 00:55:06 -08003992 sisfb_search_mode(this_opt + 5, false);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003993 } else if(!strnicmp(this_opt, "vesa:", 5)) {
Richard Knutssonc30660e2007-02-12 00:55:06 -08003994 sisfb_search_vesamode(simple_strtoul(this_opt + 5, NULL, 0), false);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003995 } else if(!strnicmp(this_opt, "rate:", 5)) {
3996 sisfb_parm_rate = simple_strtoul(this_opt + 5, NULL, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003997 } else if(!strnicmp(this_opt, "forcecrt1:", 10)) {
3998 sisfb_forcecrt1 = (int)simple_strtoul(this_opt + 10, NULL, 0);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003999 } else if(!strnicmp(this_opt, "mem:",4)) {
4000 sisfb_parm_mem = simple_strtoul(this_opt + 4, NULL, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004001 } else if(!strnicmp(this_opt, "pdc:", 4)) {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004002 sisfb_pdc = simple_strtoul(this_opt + 4, NULL, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004003 } else if(!strnicmp(this_opt, "pdc1:", 5)) {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004004 sisfb_pdca = simple_strtoul(this_opt + 5, NULL, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004005 } else if(!strnicmp(this_opt, "noaccel", 7)) {
4006 sisfb_accel = 0;
4007 } else if(!strnicmp(this_opt, "accel", 5)) {
4008 sisfb_accel = -1;
4009 } else if(!strnicmp(this_opt, "noypan", 6)) {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004010 sisfb_ypan = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004011 } else if(!strnicmp(this_opt, "ypan", 4)) {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004012 sisfb_ypan = -1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004013 } else if(!strnicmp(this_opt, "nomax", 5)) {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004014 sisfb_max = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004015 } else if(!strnicmp(this_opt, "max", 3)) {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004016 sisfb_max = -1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004017 } else if(!strnicmp(this_opt, "userom:", 7)) {
4018 sisfb_userom = (int)simple_strtoul(this_opt + 7, NULL, 0);
4019 } else if(!strnicmp(this_opt, "useoem:", 7)) {
4020 sisfb_useoem = (int)simple_strtoul(this_opt + 7, NULL, 0);
4021 } else if(!strnicmp(this_opt, "nocrt2rate", 10)) {
4022 sisfb_nocrt2rate = 1;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004023 } else if(!strnicmp(this_opt, "scalelcd:", 9)) {
4024 unsigned long temp = 2;
4025 temp = simple_strtoul(this_opt + 9, NULL, 0);
4026 if((temp == 0) || (temp == 1)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004027 sisfb_scalelcd = temp ^ 1;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004028 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004029 } else if(!strnicmp(this_opt, "tvxposoffset:", 13)) {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004030 int temp = 0;
4031 temp = (int)simple_strtol(this_opt + 13, NULL, 0);
4032 if((temp >= -32) && (temp <= 32)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004033 sisfb_tvxposoffset = temp;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004034 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004035 } else if(!strnicmp(this_opt, "tvyposoffset:", 13)) {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004036 int temp = 0;
4037 temp = (int)simple_strtol(this_opt + 13, NULL, 0);
4038 if((temp >= -32) && (temp <= 32)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004039 sisfb_tvyposoffset = temp;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004040 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004041 } else if(!strnicmp(this_opt, "specialtiming:", 14)) {
4042 sisfb_search_specialtiming(this_opt + 14);
4043 } else if(!strnicmp(this_opt, "lvdshl:", 7)) {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004044 int temp = 4;
4045 temp = simple_strtoul(this_opt + 7, NULL, 0);
4046 if((temp >= 0) && (temp <= 3)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004047 sisfb_lvdshl = temp;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004048 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004049 } else if(this_opt[0] >= '0' && this_opt[0] <= '9') {
Richard Knutssonc30660e2007-02-12 00:55:06 -08004050 sisfb_search_mode(this_opt, true);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004051#if !defined(__i386__) && !defined(__x86_64__)
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004052 } else if(!strnicmp(this_opt, "resetcard", 9)) {
4053 sisfb_resetcard = 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004054 } else if(!strnicmp(this_opt, "videoram:", 9)) {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004055 sisfb_videoram = simple_strtoul(this_opt + 9, NULL, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004056#endif
4057 } else {
4058 printk(KERN_INFO "sisfb: Invalid option %s\n", this_opt);
4059 }
4060
4061 }
4062
Linus Torvalds1da177e2005-04-16 15:20:36 -07004063 return 0;
4064}
4065#endif
4066
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004067static int __devinit
Adrian Bunk14aefd12008-07-23 21:31:12 -07004068sisfb_check_rom(void __iomem *rom_base, struct sis_video_info *ivideo)
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004069{
Adrian Bunk14aefd12008-07-23 21:31:12 -07004070 void __iomem *rom;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004071 int romptr;
4072
4073 if((readb(rom_base) != 0x55) || (readb(rom_base + 1) != 0xaa))
4074 return 0;
4075
4076 romptr = (readb(rom_base + 0x18) | (readb(rom_base + 0x19) << 8));
4077 if(romptr > (0x10000 - 8))
4078 return 0;
4079
4080 rom = rom_base + romptr;
4081
4082 if((readb(rom) != 'P') || (readb(rom + 1) != 'C') ||
4083 (readb(rom + 2) != 'I') || (readb(rom + 3) != 'R'))
4084 return 0;
4085
4086 if((readb(rom + 4) | (readb(rom + 5) << 8)) != ivideo->chip_vendor)
4087 return 0;
4088
4089 if((readb(rom + 6) | (readb(rom + 7) << 8)) != ivideo->chip_id)
4090 return 0;
4091
4092 return 1;
4093}
4094
4095static unsigned char * __devinit
4096sisfb_find_rom(struct pci_dev *pdev)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004097{
4098 struct sis_video_info *ivideo = pci_get_drvdata(pdev);
Adrian Bunk14aefd12008-07-23 21:31:12 -07004099 void __iomem *rom_base;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004100 unsigned char *myrombase = NULL;
4101 u32 temp;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004102 size_t romsize;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004103
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004104 /* First, try the official pci ROM functions (except
4105 * on integrated chipsets which have no ROM).
4106 */
4107
4108 if(!ivideo->nbridge) {
4109
4110 if((rom_base = pci_map_rom(pdev, &romsize))) {
4111
4112 if(sisfb_check_rom(rom_base, ivideo)) {
4113
4114 if((myrombase = vmalloc(65536))) {
4115
4116 /* Work around bug in pci/rom.c: Folks forgot to check
4117 * whether the size retrieved from the BIOS image eventually
4118 * is larger than the mapped size
4119 */
4120 if(pci_resource_len(pdev, PCI_ROM_RESOURCE) < romsize)
4121 romsize = pci_resource_len(pdev, PCI_ROM_RESOURCE);
4122
4123 memcpy_fromio(myrombase, rom_base,
4124 (romsize > 65536) ? 65536 : romsize);
4125 }
4126 }
4127 pci_unmap_rom(pdev, rom_base);
4128 }
4129 }
4130
4131 if(myrombase) return myrombase;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004132
4133 /* Otherwise do it the conventional way. */
Linus Torvalds1da177e2005-04-16 15:20:36 -07004134
4135#if defined(__i386__) || defined(__x86_64__)
4136
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004137 for(temp = 0x000c0000; temp < 0x000f0000; temp += 0x00001000) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004138
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004139 rom_base = ioremap(temp, 65536);
4140 if(!rom_base)
4141 continue;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004142
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004143 if(!sisfb_check_rom(rom_base, ivideo)) {
4144 iounmap(rom_base);
4145 continue;
4146 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004147
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004148 if((myrombase = vmalloc(65536)))
4149 memcpy_fromio(myrombase, rom_base, 65536);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004150
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004151 iounmap(rom_base);
4152 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004153
Linus Torvalds1da177e2005-04-16 15:20:36 -07004154 }
4155
4156#else
4157
4158 pci_read_config_dword(pdev, PCI_ROM_ADDRESS, &temp);
4159 pci_write_config_dword(pdev, PCI_ROM_ADDRESS,
4160 (ivideo->video_base & PCI_ROM_ADDRESS_MASK) | PCI_ROM_ADDRESS_ENABLE);
4161
4162 rom_base = ioremap(ivideo->video_base, 65536);
4163 if(rom_base) {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004164 if(sisfb_check_rom(rom_base, ivideo)) {
4165 if((myrombase = vmalloc(65536)))
4166 memcpy_fromio(myrombase, rom_base, 65536);
4167 }
4168 iounmap(rom_base);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004169 }
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004170
4171 pci_write_config_dword(pdev, PCI_ROM_ADDRESS, temp);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004172
4173#endif
4174
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004175 return myrombase;
4176}
4177
4178static void __devinit
4179sisfb_post_map_vram(struct sis_video_info *ivideo, unsigned int *mapsize,
4180 unsigned int min)
4181{
4182 ivideo->video_vbase = ioremap(ivideo->video_base, (*mapsize));
4183
4184 if(!ivideo->video_vbase) {
4185 printk(KERN_ERR
4186 "sisfb: Unable to map maximum video RAM for size detection\n");
4187 (*mapsize) >>= 1;
4188 while((!(ivideo->video_vbase = ioremap(ivideo->video_base, (*mapsize))))) {
4189 (*mapsize) >>= 1;
4190 if((*mapsize) < (min << 20))
4191 break;
4192 }
4193 if(ivideo->video_vbase) {
4194 printk(KERN_ERR
4195 "sisfb: Video RAM size detection limited to %dMB\n",
4196 (int)((*mapsize) >> 20));
4197 }
4198 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004199}
4200
4201#ifdef CONFIG_FB_SIS_300
4202static int __devinit
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004203sisfb_post_300_buswidth(struct sis_video_info *ivideo)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004204{
Adrian Bunk14aefd12008-07-23 21:31:12 -07004205 void __iomem *FBAddress = ivideo->video_vbase;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004206 unsigned short temp;
4207 unsigned char reg;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004208 int i, j;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004209
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004210 andSISIDXREG(SISSR, 0x15, 0xFB);
4211 orSISIDXREG(SISSR, 0x15, 0x04);
4212 outSISIDXREG(SISSR, 0x13, 0x00);
4213 outSISIDXREG(SISSR, 0x14, 0xBF);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004214
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004215 for(i = 0; i < 2; i++) {
4216 temp = 0x1234;
4217 for(j = 0; j < 4; j++) {
4218 writew(temp, FBAddress);
4219 if(readw(FBAddress) == temp)
4220 break;
4221 orSISIDXREG(SISSR, 0x3c, 0x01);
4222 inSISIDXREG(SISSR, 0x05, reg);
4223 inSISIDXREG(SISSR, 0x05, reg);
4224 andSISIDXREG(SISSR, 0x3c, 0xfe);
4225 inSISIDXREG(SISSR, 0x05, reg);
4226 inSISIDXREG(SISSR, 0x05, reg);
4227 temp++;
4228 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004229 }
4230
4231 writel(0x01234567L, FBAddress);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004232 writel(0x456789ABL, (FBAddress + 4));
4233 writel(0x89ABCDEFL, (FBAddress + 8));
4234 writel(0xCDEF0123L, (FBAddress + 12));
4235
4236 inSISIDXREG(SISSR, 0x3b, reg);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004237 if(reg & 0x01) {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004238 if(readl((FBAddress + 12)) == 0xCDEF0123L)
4239 return 4; /* Channel A 128bit */
Linus Torvalds1da177e2005-04-16 15:20:36 -07004240 }
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004241
4242 if(readl((FBAddress + 4)) == 0x456789ABL)
4243 return 2; /* Channel B 64bit */
4244
4245 return 1; /* 32bit */
4246}
4247
4248static int __devinit
4249sisfb_post_300_rwtest(struct sis_video_info *ivideo, int iteration, int buswidth,
4250 int PseudoRankCapacity, int PseudoAdrPinCount,
4251 unsigned int mapsize)
4252{
Adrian Bunk14aefd12008-07-23 21:31:12 -07004253 void __iomem *FBAddr = ivideo->video_vbase;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004254 unsigned short sr14;
4255 unsigned int k, RankCapacity, PageCapacity, BankNumHigh, BankNumMid;
4256 unsigned int PhysicalAdrOtherPage, PhysicalAdrHigh, PhysicalAdrHalfPage;
4257 static const unsigned short SiS_DRAMType[17][5] = {
4258 {0x0C,0x0A,0x02,0x40,0x39},
4259 {0x0D,0x0A,0x01,0x40,0x48},
4260 {0x0C,0x09,0x02,0x20,0x35},
4261 {0x0D,0x09,0x01,0x20,0x44},
4262 {0x0C,0x08,0x02,0x10,0x31},
4263 {0x0D,0x08,0x01,0x10,0x40},
4264 {0x0C,0x0A,0x01,0x20,0x34},
4265 {0x0C,0x09,0x01,0x08,0x32},
4266 {0x0B,0x08,0x02,0x08,0x21},
4267 {0x0C,0x08,0x01,0x08,0x30},
4268 {0x0A,0x08,0x02,0x04,0x11},
4269 {0x0B,0x0A,0x01,0x10,0x28},
4270 {0x09,0x08,0x02,0x02,0x01},
4271 {0x0B,0x09,0x01,0x08,0x24},
4272 {0x0B,0x08,0x01,0x04,0x20},
4273 {0x0A,0x08,0x01,0x02,0x10},
4274 {0x09,0x08,0x01,0x01,0x00}
4275 };
4276
4277 for(k = 0; k <= 16; k++) {
4278
4279 RankCapacity = buswidth * SiS_DRAMType[k][3];
4280
4281 if(RankCapacity != PseudoRankCapacity)
4282 continue;
4283
4284 if((SiS_DRAMType[k][2] + SiS_DRAMType[k][0]) > PseudoAdrPinCount)
4285 continue;
4286
4287 BankNumHigh = RankCapacity * 16 * iteration - 1;
4288 if(iteration == 3) { /* Rank No */
4289 BankNumMid = RankCapacity * 16 - 1;
4290 } else {
4291 BankNumMid = RankCapacity * 16 * iteration / 2 - 1;
4292 }
4293
4294 PageCapacity = (1 << SiS_DRAMType[k][1]) * buswidth * 4;
4295 PhysicalAdrHigh = BankNumHigh;
4296 PhysicalAdrHalfPage = (PageCapacity / 2 + PhysicalAdrHigh) % PageCapacity;
4297 PhysicalAdrOtherPage = PageCapacity * SiS_DRAMType[k][2] + PhysicalAdrHigh;
4298
4299 andSISIDXREG(SISSR, 0x15, 0xFB); /* Test */
4300 orSISIDXREG(SISSR, 0x15, 0x04); /* Test */
4301 sr14 = (SiS_DRAMType[k][3] * buswidth) - 1;
4302 if(buswidth == 4) sr14 |= 0x80;
4303 else if(buswidth == 2) sr14 |= 0x40;
4304 outSISIDXREG(SISSR, 0x13, SiS_DRAMType[k][4]);
4305 outSISIDXREG(SISSR, 0x14, sr14);
4306
4307 BankNumHigh <<= 16;
4308 BankNumMid <<= 16;
4309
4310 if((BankNumHigh + PhysicalAdrHigh >= mapsize) ||
4311 (BankNumMid + PhysicalAdrHigh >= mapsize) ||
4312 (BankNumHigh + PhysicalAdrHalfPage >= mapsize) ||
4313 (BankNumHigh + PhysicalAdrOtherPage >= mapsize))
4314 continue;
4315
4316 /* Write data */
4317 writew(((unsigned short)PhysicalAdrHigh),
4318 (FBAddr + BankNumHigh + PhysicalAdrHigh));
4319 writew(((unsigned short)BankNumMid),
4320 (FBAddr + BankNumMid + PhysicalAdrHigh));
4321 writew(((unsigned short)PhysicalAdrHalfPage),
4322 (FBAddr + BankNumHigh + PhysicalAdrHalfPage));
4323 writew(((unsigned short)PhysicalAdrOtherPage),
4324 (FBAddr + BankNumHigh + PhysicalAdrOtherPage));
4325
4326 /* Read data */
4327 if(readw(FBAddr + BankNumHigh + PhysicalAdrHigh) == PhysicalAdrHigh)
4328 return 1;
4329 }
4330
4331 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004332}
4333
4334static void __devinit
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004335sisfb_post_300_ramsize(struct pci_dev *pdev, unsigned int mapsize)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004336{
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004337 struct sis_video_info *ivideo = pci_get_drvdata(pdev);
4338 int i, j, buswidth;
4339 int PseudoRankCapacity, PseudoAdrPinCount;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004340
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004341 buswidth = sisfb_post_300_buswidth(ivideo);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004342
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004343 for(i = 6; i >= 0; i--) {
4344 PseudoRankCapacity = 1 << i;
4345 for(j = 4; j >= 1; j--) {
4346 PseudoAdrPinCount = 15 - j;
4347 if((PseudoRankCapacity * j) <= 64) {
4348 if(sisfb_post_300_rwtest(ivideo,
4349 j,
4350 buswidth,
4351 PseudoRankCapacity,
4352 PseudoAdrPinCount,
4353 mapsize))
4354 return;
4355 }
4356 }
4357 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004358}
4359
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004360static void __devinit
4361sisfb_post_sis300(struct pci_dev *pdev)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004362{
4363 struct sis_video_info *ivideo = pci_get_drvdata(pdev);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004364 unsigned char *bios = ivideo->SiS_Pr.VirtualRomBase;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004365 u8 reg, v1, v2, v3, v4, v5, v6, v7, v8;
4366 u16 index, rindex, memtype = 0;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004367 unsigned int mapsize;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004368
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004369 if(!ivideo->SiS_Pr.UseROM)
4370 bios = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004371
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004372 outSISIDXREG(SISSR, 0x05, 0x86);
4373
4374 if(bios) {
4375 if(bios[0x52] & 0x80) {
4376 memtype = bios[0x52];
4377 } else {
4378 inSISIDXREG(SISSR, 0x3a, memtype);
4379 }
4380 memtype &= 0x07;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004381 }
4382
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004383 v3 = 0x80; v6 = 0x80;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004384 if(ivideo->revision_id <= 0x13) {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004385 v1 = 0x44; v2 = 0x42;
4386 v4 = 0x44; v5 = 0x42;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004387 } else {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004388 v1 = 0x68; v2 = 0x43; /* Assume 125Mhz MCLK */
4389 v4 = 0x68; v5 = 0x43; /* Assume 125Mhz ECLK */
4390 if(bios) {
4391 index = memtype * 5;
4392 rindex = index + 0x54;
4393 v1 = bios[rindex++];
4394 v2 = bios[rindex++];
4395 v3 = bios[rindex++];
4396 rindex = index + 0x7c;
4397 v4 = bios[rindex++];
4398 v5 = bios[rindex++];
4399 v6 = bios[rindex++];
4400 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004401 }
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004402 outSISIDXREG(SISSR, 0x28, v1);
4403 outSISIDXREG(SISSR, 0x29, v2);
4404 outSISIDXREG(SISSR, 0x2a, v3);
4405 outSISIDXREG(SISSR, 0x2e, v4);
4406 outSISIDXREG(SISSR, 0x2f, v5);
4407 outSISIDXREG(SISSR, 0x30, v6);
4408
Linus Torvalds1da177e2005-04-16 15:20:36 -07004409 v1 = 0x10;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004410 if(bios)
4411 v1 = bios[0xa4];
4412 outSISIDXREG(SISSR, 0x07, v1); /* DAC speed */
4413
4414 outSISIDXREG(SISSR, 0x11, 0x0f); /* DDC, power save */
4415
Linus Torvalds1da177e2005-04-16 15:20:36 -07004416 v1 = 0x01; v2 = 0x43; v3 = 0x1e; v4 = 0x2a;
4417 v5 = 0x06; v6 = 0x00; v7 = 0x00; v8 = 0x00;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004418 if(bios) {
4419 memtype += 0xa5;
4420 v1 = bios[memtype];
4421 v2 = bios[memtype + 8];
4422 v3 = bios[memtype + 16];
4423 v4 = bios[memtype + 24];
4424 v5 = bios[memtype + 32];
4425 v6 = bios[memtype + 40];
4426 v7 = bios[memtype + 48];
4427 v8 = bios[memtype + 56];
Linus Torvalds1da177e2005-04-16 15:20:36 -07004428 }
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004429 if(ivideo->revision_id >= 0x80)
4430 v3 &= 0xfd;
4431 outSISIDXREG(SISSR, 0x15, v1); /* Ram type (assuming 0, BIOS 0xa5 step 8) */
4432 outSISIDXREG(SISSR, 0x16, v2);
4433 outSISIDXREG(SISSR, 0x17, v3);
4434 outSISIDXREG(SISSR, 0x18, v4);
4435 outSISIDXREG(SISSR, 0x19, v5);
4436 outSISIDXREG(SISSR, 0x1a, v6);
4437 outSISIDXREG(SISSR, 0x1b, v7);
4438 outSISIDXREG(SISSR, 0x1c, v8); /* ---- */
4439 andSISIDXREG(SISSR, 0x15 ,0xfb);
4440 orSISIDXREG(SISSR, 0x15, 0x04);
4441 if(bios) {
4442 if(bios[0x53] & 0x02) {
4443 orSISIDXREG(SISSR, 0x19, 0x20);
4444 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004445 }
4446 v1 = 0x04; /* DAC pedestal (BIOS 0xe5) */
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004447 if(ivideo->revision_id >= 0x80)
4448 v1 |= 0x01;
4449 outSISIDXREG(SISSR, 0x1f, v1);
4450 outSISIDXREG(SISSR, 0x20, 0xa4); /* linear & relocated io & disable a0000 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07004451 v1 = 0xf6; v2 = 0x0d; v3 = 0x00;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004452 if(bios) {
4453 v1 = bios[0xe8];
4454 v2 = bios[0xe9];
4455 v3 = bios[0xea];
Linus Torvalds1da177e2005-04-16 15:20:36 -07004456 }
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004457 outSISIDXREG(SISSR, 0x23, v1);
4458 outSISIDXREG(SISSR, 0x24, v2);
4459 outSISIDXREG(SISSR, 0x25, v3);
4460 outSISIDXREG(SISSR, 0x21, 0x84);
4461 outSISIDXREG(SISSR, 0x22, 0x00);
4462 outSISIDXREG(SISCR, 0x37, 0x00);
4463 orSISIDXREG(SISPART1, 0x24, 0x01); /* unlock crt2 */
4464 outSISIDXREG(SISPART1, 0x00, 0x00);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004465 v1 = 0x40; v2 = 0x11;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004466 if(bios) {
4467 v1 = bios[0xec];
4468 v2 = bios[0xeb];
Linus Torvalds1da177e2005-04-16 15:20:36 -07004469 }
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004470 outSISIDXREG(SISPART1, 0x02, v1);
4471
4472 if(ivideo->revision_id >= 0x80)
4473 v2 &= ~0x01;
4474
4475 inSISIDXREG(SISPART4, 0x00, reg);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004476 if((reg == 1) || (reg == 2)) {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004477 outSISIDXREG(SISCR, 0x37, 0x02);
4478 outSISIDXREG(SISPART2, 0x00, 0x1c);
4479 v4 = 0x00; v5 = 0x00; v6 = 0x10;
4480 if(ivideo->SiS_Pr.UseROM) {
4481 v4 = bios[0xf5];
4482 v5 = bios[0xf6];
4483 v6 = bios[0xf7];
4484 }
4485 outSISIDXREG(SISPART4, 0x0d, v4);
4486 outSISIDXREG(SISPART4, 0x0e, v5);
4487 outSISIDXREG(SISPART4, 0x10, v6);
4488 outSISIDXREG(SISPART4, 0x0f, 0x3f);
4489 inSISIDXREG(SISPART4, 0x01, reg);
4490 if(reg >= 0xb0) {
4491 inSISIDXREG(SISPART4, 0x23, reg);
4492 reg &= 0x20;
4493 reg <<= 1;
4494 outSISIDXREG(SISPART4, 0x23, reg);
4495 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004496 } else {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004497 v2 &= ~0x10;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004498 }
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004499 outSISIDXREG(SISSR, 0x32, v2);
4500
4501 andSISIDXREG(SISPART1, 0x24, 0xfe); /* Lock CRT2 */
4502
4503 inSISIDXREG(SISSR, 0x16, reg);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004504 reg &= 0xc3;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004505 outSISIDXREG(SISCR, 0x35, reg);
4506 outSISIDXREG(SISCR, 0x83, 0x00);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004507#if !defined(__i386__) && !defined(__x86_64__)
4508 if(sisfb_videoram) {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004509 outSISIDXREG(SISSR, 0x13, 0x28); /* ? */
4510 reg = ((sisfb_videoram >> 10) - 1) | 0x40;
4511 outSISIDXREG(SISSR, 0x14, reg);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004512 } else {
4513#endif
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004514 /* Need to map max FB size for finding out about RAM size */
4515 mapsize = 64 << 20;
4516 sisfb_post_map_vram(ivideo, &mapsize, 4);
4517
4518 if(ivideo->video_vbase) {
4519 sisfb_post_300_ramsize(pdev, mapsize);
4520 iounmap(ivideo->video_vbase);
4521 } else {
4522 printk(KERN_DEBUG
4523 "sisfb: Failed to map memory for size detection, assuming 8MB\n");
4524 outSISIDXREG(SISSR, 0x13, 0x28); /* ? */
4525 outSISIDXREG(SISSR, 0x14, 0x47); /* 8MB, 64bit default */
4526 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004527#if !defined(__i386__) && !defined(__x86_64__)
4528 }
4529#endif
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004530 if(bios) {
4531 v1 = bios[0xe6];
4532 v2 = bios[0xe7];
Linus Torvalds1da177e2005-04-16 15:20:36 -07004533 } else {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004534 inSISIDXREG(SISSR, 0x3a, reg);
4535 if((reg & 0x30) == 0x30) {
4536 v1 = 0x04; /* PCI */
4537 v2 = 0x92;
4538 } else {
4539 v1 = 0x14; /* AGP */
4540 v2 = 0xb2;
4541 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004542 }
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004543 outSISIDXREG(SISSR, 0x21, v1);
4544 outSISIDXREG(SISSR, 0x22, v2);
4545
4546 /* Sense CRT1 */
4547 sisfb_sense_crt1(ivideo);
4548
4549 /* Set default mode, don't clear screen */
Richard Knutssonc30660e2007-02-12 00:55:06 -08004550 ivideo->SiS_Pr.SiS_UseOEM = false;
4551 SiS_SetEnableDstn(&ivideo->SiS_Pr, false);
4552 SiS_SetEnableFstn(&ivideo->SiS_Pr, false);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004553 ivideo->curFSTN = ivideo->curDSTN = 0;
4554 ivideo->SiS_Pr.VideoMemorySize = 8 << 20;
4555 SiSSetMode(&ivideo->SiS_Pr, 0x2e | 0x80);
4556
4557 outSISIDXREG(SISSR, 0x05, 0x86);
4558
4559 /* Display off */
4560 orSISIDXREG(SISSR, 0x01, 0x20);
4561
4562 /* Save mode number in CR34 */
4563 outSISIDXREG(SISCR, 0x34, 0x2e);
4564
4565 /* Let everyone know what the current mode is */
4566 ivideo->modeprechange = 0x2e;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004567}
4568#endif
4569
4570#ifdef CONFIG_FB_SIS_315
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004571#if 0
4572static void __devinit
4573sisfb_post_sis315330(struct pci_dev *pdev)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004574{
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004575 /* TODO */
Linus Torvalds1da177e2005-04-16 15:20:36 -07004576}
4577#endif
4578
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004579static void __devinit
4580sisfb_post_xgi_delay(struct sis_video_info *ivideo, int delay)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004581{
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004582 unsigned int i;
4583 u8 reg;
4584
4585 for(i = 0; i <= (delay * 10 * 36); i++) {
4586 inSISIDXREG(SISSR, 0x05, reg);
4587 reg++;
4588 }
4589}
4590
4591static int __devinit
4592sisfb_find_host_bridge(struct sis_video_info *ivideo, struct pci_dev *mypdev,
4593 unsigned short pcivendor)
4594{
4595 struct pci_dev *pdev = NULL;
4596 unsigned short temp;
4597 int ret = 0;
4598
Adrian Bunk0959f0c2007-05-08 00:39:50 -07004599 while((pdev = pci_get_class(PCI_CLASS_BRIDGE_HOST, pdev))) {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004600 temp = pdev->vendor;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004601 if(temp == pcivendor) {
4602 ret = 1;
Julia Lawallea237a62008-02-06 01:39:07 -08004603 pci_dev_put(pdev);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004604 break;
4605 }
4606 }
4607
4608 return ret;
4609}
4610
4611static int __devinit
4612sisfb_post_xgi_rwtest(struct sis_video_info *ivideo, int starta,
4613 unsigned int enda, unsigned int mapsize)
4614{
4615 unsigned int pos;
4616 int i;
4617
4618 writel(0, ivideo->video_vbase);
4619
4620 for(i = starta; i <= enda; i++) {
4621 pos = 1 << i;
4622 if(pos < mapsize)
4623 writel(pos, ivideo->video_vbase + pos);
4624 }
4625
4626 sisfb_post_xgi_delay(ivideo, 150);
4627
4628 if(readl(ivideo->video_vbase) != 0)
4629 return 0;
4630
4631 for(i = starta; i <= enda; i++) {
4632 pos = 1 << i;
4633 if(pos < mapsize) {
4634 if(readl(ivideo->video_vbase + pos) != pos)
4635 return 0;
4636 } else
4637 return 0;
4638 }
4639
4640 return 1;
4641}
4642
4643static void __devinit
4644sisfb_post_xgi_ramsize(struct sis_video_info *ivideo)
4645{
4646 unsigned int buswidth, ranksize, channelab, mapsize;
4647 int i, j, k, l;
4648 u8 reg, sr14;
4649 static const u8 dramsr13[12 * 5] = {
4650 0x02, 0x0e, 0x0b, 0x80, 0x5d,
4651 0x02, 0x0e, 0x0a, 0x40, 0x59,
4652 0x02, 0x0d, 0x0b, 0x40, 0x4d,
4653 0x02, 0x0e, 0x09, 0x20, 0x55,
4654 0x02, 0x0d, 0x0a, 0x20, 0x49,
4655 0x02, 0x0c, 0x0b, 0x20, 0x3d,
4656 0x02, 0x0e, 0x08, 0x10, 0x51,
4657 0x02, 0x0d, 0x09, 0x10, 0x45,
4658 0x02, 0x0c, 0x0a, 0x10, 0x39,
4659 0x02, 0x0d, 0x08, 0x08, 0x41,
4660 0x02, 0x0c, 0x09, 0x08, 0x35,
4661 0x02, 0x0c, 0x08, 0x04, 0x31
4662 };
4663 static const u8 dramsr13_4[4 * 5] = {
4664 0x02, 0x0d, 0x09, 0x40, 0x45,
4665 0x02, 0x0c, 0x09, 0x20, 0x35,
4666 0x02, 0x0c, 0x08, 0x10, 0x31,
4667 0x02, 0x0b, 0x08, 0x08, 0x21
4668 };
4669
4670 /* Enable linear mode, disable 0xa0000 address decoding */
4671 /* We disable a0000 address decoding, because
4672 * - if running on x86, if the card is disabled, it means
4673 * that another card is in the system. We don't want
4674 * to interphere with that primary card's textmode.
4675 * - if running on non-x86, there usually is no VGA window
4676 * at a0000.
4677 */
4678 orSISIDXREG(SISSR, 0x20, (0x80 | 0x04));
4679
4680 /* Need to map max FB size for finding out about RAM size */
4681 mapsize = 256 << 20;
4682 sisfb_post_map_vram(ivideo, &mapsize, 32);
4683
4684 if(!ivideo->video_vbase) {
4685 printk(KERN_ERR "sisfb: Unable to detect RAM size. Setting default.\n");
4686 outSISIDXREG(SISSR, 0x13, 0x35);
4687 outSISIDXREG(SISSR, 0x14, 0x41);
4688 /* TODO */
4689 return;
4690 }
4691
4692 /* Non-interleaving */
4693 outSISIDXREG(SISSR, 0x15, 0x00);
4694 /* No tiling */
4695 outSISIDXREG(SISSR, 0x1c, 0x00);
4696
4697 if(ivideo->chip == XGI_20) {
4698
4699 channelab = 1;
4700 inSISIDXREG(SISCR, 0x97, reg);
4701 if(!(reg & 0x01)) { /* Single 32/16 */
4702 buswidth = 32;
4703 outSISIDXREG(SISSR, 0x13, 0xb1);
4704 outSISIDXREG(SISSR, 0x14, 0x52);
4705 sisfb_post_xgi_delay(ivideo, 1);
4706 sr14 = 0x02;
4707 if(sisfb_post_xgi_rwtest(ivideo, 23, 24, mapsize))
4708 goto bail_out;
4709
4710 outSISIDXREG(SISSR, 0x13, 0x31);
4711 outSISIDXREG(SISSR, 0x14, 0x42);
4712 sisfb_post_xgi_delay(ivideo, 1);
4713 if(sisfb_post_xgi_rwtest(ivideo, 23, 23, mapsize))
4714 goto bail_out;
4715
4716 buswidth = 16;
4717 outSISIDXREG(SISSR, 0x13, 0xb1);
4718 outSISIDXREG(SISSR, 0x14, 0x41);
4719 sisfb_post_xgi_delay(ivideo, 1);
4720 sr14 = 0x01;
4721 if(sisfb_post_xgi_rwtest(ivideo, 22, 23, mapsize))
4722 goto bail_out;
4723 else
4724 outSISIDXREG(SISSR, 0x13, 0x31);
4725 } else { /* Dual 16/8 */
4726 buswidth = 16;
4727 outSISIDXREG(SISSR, 0x13, 0xb1);
4728 outSISIDXREG(SISSR, 0x14, 0x41);
4729 sisfb_post_xgi_delay(ivideo, 1);
4730 sr14 = 0x01;
4731 if(sisfb_post_xgi_rwtest(ivideo, 22, 23, mapsize))
4732 goto bail_out;
4733
4734 outSISIDXREG(SISSR, 0x13, 0x31);
4735 outSISIDXREG(SISSR, 0x14, 0x31);
4736 sisfb_post_xgi_delay(ivideo, 1);
4737 if(sisfb_post_xgi_rwtest(ivideo, 22, 22, mapsize))
4738 goto bail_out;
4739
4740 buswidth = 8;
4741 outSISIDXREG(SISSR, 0x13, 0xb1);
4742 outSISIDXREG(SISSR, 0x14, 0x30);
4743 sisfb_post_xgi_delay(ivideo, 1);
4744 sr14 = 0x00;
4745 if(sisfb_post_xgi_rwtest(ivideo, 21, 22, mapsize))
4746 goto bail_out;
4747 else
4748 outSISIDXREG(SISSR, 0x13, 0x31);
4749 }
4750
4751 } else { /* XGI_40 */
4752
4753 inSISIDXREG(SISCR, 0x97, reg);
4754 if(!(reg & 0x10)) {
4755 inSISIDXREG(SISSR, 0x39, reg);
4756 reg >>= 1;
4757 }
4758
4759 if(reg & 0x01) { /* DDRII */
4760 buswidth = 32;
4761 if(ivideo->revision_id == 2) {
4762 channelab = 2;
4763 outSISIDXREG(SISSR, 0x13, 0xa1);
4764 outSISIDXREG(SISSR, 0x14, 0x44);
4765 sr14 = 0x04;
4766 sisfb_post_xgi_delay(ivideo, 1);
4767 if(sisfb_post_xgi_rwtest(ivideo, 23, 24, mapsize))
4768 goto bail_out;
4769
4770 outSISIDXREG(SISSR, 0x13, 0x21);
4771 outSISIDXREG(SISSR, 0x14, 0x34);
4772 if(sisfb_post_xgi_rwtest(ivideo, 22, 23, mapsize))
4773 goto bail_out;
4774
4775 channelab = 1;
4776 outSISIDXREG(SISSR, 0x13, 0xa1);
4777 outSISIDXREG(SISSR, 0x14, 0x40);
4778 sr14 = 0x00;
4779 if(sisfb_post_xgi_rwtest(ivideo, 22, 23, mapsize))
4780 goto bail_out;
4781
4782 outSISIDXREG(SISSR, 0x13, 0x21);
4783 outSISIDXREG(SISSR, 0x14, 0x30);
4784 } else {
4785 channelab = 3;
4786 outSISIDXREG(SISSR, 0x13, 0xa1);
4787 outSISIDXREG(SISSR, 0x14, 0x4c);
4788 sr14 = 0x0c;
4789 sisfb_post_xgi_delay(ivideo, 1);
4790 if(sisfb_post_xgi_rwtest(ivideo, 23, 25, mapsize))
4791 goto bail_out;
4792
4793 channelab = 2;
4794 outSISIDXREG(SISSR, 0x14, 0x48);
4795 sisfb_post_xgi_delay(ivideo, 1);
4796 sr14 = 0x08;
4797 if(sisfb_post_xgi_rwtest(ivideo, 23, 24, mapsize))
4798 goto bail_out;
4799
4800 outSISIDXREG(SISSR, 0x13, 0x21);
4801 outSISIDXREG(SISSR, 0x14, 0x3c);
4802 sr14 = 0x0c;
4803
4804 if(sisfb_post_xgi_rwtest(ivideo, 23, 24, mapsize)) {
4805 channelab = 3;
4806 } else {
4807 channelab = 2;
4808 outSISIDXREG(SISSR, 0x14, 0x38);
4809 sr14 = 0x08;
4810 }
4811 }
4812 sisfb_post_xgi_delay(ivideo, 1);
4813
4814 } else { /* DDR */
4815
4816 buswidth = 64;
4817 if(ivideo->revision_id == 2) {
4818 channelab = 1;
4819 outSISIDXREG(SISSR, 0x13, 0xa1);
4820 outSISIDXREG(SISSR, 0x14, 0x52);
4821 sisfb_post_xgi_delay(ivideo, 1);
4822 sr14 = 0x02;
4823 if(sisfb_post_xgi_rwtest(ivideo, 23, 24, mapsize))
4824 goto bail_out;
4825
4826 outSISIDXREG(SISSR, 0x13, 0x21);
4827 outSISIDXREG(SISSR, 0x14, 0x42);
4828 } else {
4829 channelab = 2;
4830 outSISIDXREG(SISSR, 0x13, 0xa1);
4831 outSISIDXREG(SISSR, 0x14, 0x5a);
4832 sisfb_post_xgi_delay(ivideo, 1);
4833 sr14 = 0x0a;
4834 if(sisfb_post_xgi_rwtest(ivideo, 24, 25, mapsize))
4835 goto bail_out;
4836
4837 outSISIDXREG(SISSR, 0x13, 0x21);
4838 outSISIDXREG(SISSR, 0x14, 0x4a);
4839 }
4840 sisfb_post_xgi_delay(ivideo, 1);
4841
4842 }
4843 }
4844
4845bail_out:
4846 setSISIDXREG(SISSR, 0x14, 0xf0, sr14);
4847 sisfb_post_xgi_delay(ivideo, 1);
4848
4849 j = (ivideo->chip == XGI_20) ? 5 : 9;
4850 k = (ivideo->chip == XGI_20) ? 12 : 4;
4851
4852 for(i = 0; i < k; i++) {
4853
4854 reg = (ivideo->chip == XGI_20) ?
4855 dramsr13[(i * 5) + 4] : dramsr13_4[(i * 5) + 4];
4856 setSISIDXREG(SISSR, 0x13, 0x80, reg);
4857 sisfb_post_xgi_delay(ivideo, 50);
4858
4859 ranksize = (ivideo->chip == XGI_20) ?
4860 dramsr13[(i * 5) + 3] : dramsr13_4[(i * 5) + 3];
4861
4862 inSISIDXREG(SISSR, 0x13, reg);
4863 if(reg & 0x80) ranksize <<= 1;
4864
4865 if(ivideo->chip == XGI_20) {
4866 if(buswidth == 16) ranksize <<= 1;
4867 else if(buswidth == 32) ranksize <<= 2;
4868 } else {
4869 if(buswidth == 64) ranksize <<= 1;
4870 }
4871
4872 reg = 0;
4873 l = channelab;
4874 if(l == 3) l = 4;
4875 if((ranksize * l) <= 256) {
4876 while((ranksize >>= 1)) reg += 0x10;
4877 }
4878
4879 if(!reg) continue;
4880
4881 setSISIDXREG(SISSR, 0x14, 0x0f, (reg & 0xf0));
4882 sisfb_post_xgi_delay(ivideo, 1);
4883
4884 if(sisfb_post_xgi_rwtest(ivideo, j, ((reg >> 4) + channelab - 2 + 20), mapsize))
4885 break;
4886 }
4887
4888 iounmap(ivideo->video_vbase);
4889}
4890
4891static void __devinit
4892sisfb_post_xgi_setclocks(struct sis_video_info *ivideo, u8 regb)
4893{
4894 u8 v1, v2, v3;
4895 int index;
4896 static const u8 cs90[8 * 3] = {
4897 0x16, 0x01, 0x01,
4898 0x3e, 0x03, 0x01,
4899 0x7c, 0x08, 0x01,
4900 0x79, 0x06, 0x01,
4901 0x29, 0x01, 0x81,
4902 0x5c, 0x23, 0x01,
4903 0x5c, 0x23, 0x01,
4904 0x5c, 0x23, 0x01
4905 };
4906 static const u8 csb8[8 * 3] = {
4907 0x5c, 0x23, 0x01,
4908 0x29, 0x01, 0x01,
4909 0x7c, 0x08, 0x01,
4910 0x79, 0x06, 0x01,
4911 0x29, 0x01, 0x81,
4912 0x5c, 0x23, 0x01,
4913 0x5c, 0x23, 0x01,
4914 0x5c, 0x23, 0x01
4915 };
4916
4917 regb = 0; /* ! */
4918
4919 index = regb * 3;
4920 v1 = cs90[index]; v2 = cs90[index + 1]; v3 = cs90[index + 2];
4921 if(ivideo->haveXGIROM) {
4922 v1 = ivideo->bios_abase[0x90 + index];
4923 v2 = ivideo->bios_abase[0x90 + index + 1];
4924 v3 = ivideo->bios_abase[0x90 + index + 2];
4925 }
4926 outSISIDXREG(SISSR, 0x28, v1);
4927 outSISIDXREG(SISSR, 0x29, v2);
4928 outSISIDXREG(SISSR, 0x2a, v3);
4929 sisfb_post_xgi_delay(ivideo, 0x43);
4930 sisfb_post_xgi_delay(ivideo, 0x43);
4931 sisfb_post_xgi_delay(ivideo, 0x43);
4932 index = regb * 3;
4933 v1 = csb8[index]; v2 = csb8[index + 1]; v3 = csb8[index + 2];
4934 if(ivideo->haveXGIROM) {
4935 v1 = ivideo->bios_abase[0xb8 + index];
4936 v2 = ivideo->bios_abase[0xb8 + index + 1];
4937 v3 = ivideo->bios_abase[0xb8 + index + 2];
4938 }
4939 outSISIDXREG(SISSR, 0x2e, v1);
4940 outSISIDXREG(SISSR, 0x2f, v2);
4941 outSISIDXREG(SISSR, 0x30, v3);
4942 sisfb_post_xgi_delay(ivideo, 0x43);
4943 sisfb_post_xgi_delay(ivideo, 0x43);
4944 sisfb_post_xgi_delay(ivideo, 0x43);
4945}
4946
4947static int __devinit
4948sisfb_post_xgi(struct pci_dev *pdev)
4949{
4950 struct sis_video_info *ivideo = pci_get_drvdata(pdev);
4951 unsigned char *bios = ivideo->bios_abase;
4952 struct pci_dev *mypdev = NULL;
4953 const u8 *ptr, *ptr2;
4954 u8 v1, v2, v3, v4, v5, reg, ramtype;
4955 u32 rega, regb, regd;
4956 int i, j, k, index;
4957 static const u8 cs78[3] = { 0xf6, 0x0d, 0x00 };
4958 static const u8 cs76[2] = { 0xa3, 0xfb };
4959 static const u8 cs7b[3] = { 0xc0, 0x11, 0x00 };
4960 static const u8 cs158[8] = {
4961 0x88, 0xaa, 0x48, 0x00, 0x00, 0x00, 0x00, 0x00
4962 };
4963 static const u8 cs160[8] = {
4964 0x44, 0x77, 0x77, 0x00, 0x00, 0x00, 0x00, 0x00
4965 };
4966 static const u8 cs168[8] = {
4967 0x48, 0x78, 0x88, 0x00, 0x00, 0x00, 0x00, 0x00
4968 };
4969 static const u8 cs128[3 * 8] = {
4970 0x90, 0x28, 0x24, 0x00, 0x00, 0x00, 0x00, 0x00,
4971 0x77, 0x44, 0x44, 0x00, 0x00, 0x00, 0x00, 0x00,
4972 0x77, 0x44, 0x44, 0x00, 0x00, 0x00, 0x00, 0x00
4973 };
4974 static const u8 cs148[2 * 8] = {
4975 0x55, 0x55, 0x55, 0x00, 0x00, 0x00, 0x00, 0x00,
4976 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
4977 };
4978 static const u8 cs31a[8 * 4] = {
4979 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
4980 0xaa, 0xaa, 0xaa, 0xaa, 0x00, 0x00, 0x00, 0x00,
4981 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
4982 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
4983 };
4984 static const u8 cs33a[8 * 4] = {
4985 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
4986 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
4987 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
4988 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
4989 };
4990 static const u8 cs45a[8 * 2] = {
4991 0x00, 0x00, 0xa0, 0x00, 0xa0, 0x00, 0x00, 0x00,
4992 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
4993 };
4994 static const u8 cs170[7 * 8] = {
4995 0x54, 0x32, 0x44, 0x00, 0x00, 0x00, 0x00, 0x00,
4996 0x54, 0x43, 0x44, 0x00, 0x00, 0x00, 0x00, 0x00,
4997 0x0a, 0x05, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00,
4998 0x44, 0x34, 0x44, 0x00, 0x00, 0x00, 0x00, 0x00,
4999 0x10, 0x0a, 0x0a, 0x00, 0x00, 0x00, 0x00, 0x00,
5000 0x11, 0x0c, 0x0c, 0x00, 0x00, 0x00, 0x00, 0x00,
5001 0x05, 0x05, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00
5002 };
5003 static const u8 cs1a8[3 * 8] = {
5004 0xf0, 0xf0, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x00,
5005 0x05, 0x02, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00,
5006 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
5007 };
5008 static const u8 cs100[2 * 8] = {
5009 0xc4, 0x04, 0x84, 0x00, 0x00, 0x00, 0x00, 0x00,
5010 0xc4, 0x04, 0x84, 0x00, 0x00, 0x00, 0x00, 0x00
5011 };
5012
5013 /* VGA enable */
5014 reg = inSISREG(SISVGAENABLE) | 0x01;
5015 outSISREG(SISVGAENABLE, reg);
5016
5017 /* Misc */
5018 reg = inSISREG(SISMISCR) | 0x01;
5019 outSISREG(SISMISCW, reg);
5020
5021 /* Unlock SR */
5022 outSISIDXREG(SISSR, 0x05, 0x86);
5023 inSISIDXREG(SISSR, 0x05, reg);
5024 if(reg != 0xa1)
5025 return 0;
5026
5027 /* Clear some regs */
5028 for(i = 0; i < 0x22; i++) {
5029 if(0x06 + i == 0x20) continue;
5030 outSISIDXREG(SISSR, 0x06 + i, 0x00);
5031 }
5032 for(i = 0; i < 0x0b; i++) {
5033 outSISIDXREG(SISSR, 0x31 + i, 0x00);
5034 }
5035 for(i = 0; i < 0x10; i++) {
5036 outSISIDXREG(SISCR, 0x30 + i, 0x00);
5037 }
5038
5039 ptr = cs78;
5040 if(ivideo->haveXGIROM) {
5041 ptr = (const u8 *)&bios[0x78];
5042 }
5043 for(i = 0; i < 3; i++) {
5044 outSISIDXREG(SISSR, 0x23 + i, ptr[i]);
5045 }
5046
5047 ptr = cs76;
5048 if(ivideo->haveXGIROM) {
5049 ptr = (const u8 *)&bios[0x76];
5050 }
5051 for(i = 0; i < 2; i++) {
5052 outSISIDXREG(SISSR, 0x21 + i, ptr[i]);
5053 }
5054
5055 v1 = 0x18; v2 = 0x00;
5056 if(ivideo->haveXGIROM) {
5057 v1 = bios[0x74];
5058 v2 = bios[0x75];
5059 }
5060 outSISIDXREG(SISSR, 0x07, v1);
5061 outSISIDXREG(SISSR, 0x11, 0x0f);
5062 outSISIDXREG(SISSR, 0x1f, v2);
5063 /* PCI linear mode, RelIO enabled, A0000 decoding disabled */
5064 outSISIDXREG(SISSR, 0x20, 0x80 | 0x20 | 0x04);
5065 outSISIDXREG(SISSR, 0x27, 0x74);
5066
5067 ptr = cs7b;
5068 if(ivideo->haveXGIROM) {
5069 ptr = (const u8 *)&bios[0x7b];
5070 }
5071 for(i = 0; i < 3; i++) {
5072 outSISIDXREG(SISSR, 0x31 + i, ptr[i]);
5073 }
5074
5075 if(ivideo->chip == XGI_40) {
5076 if(ivideo->revision_id == 2) {
5077 setSISIDXREG(SISSR, 0x3b, 0x3f, 0xc0);
5078 }
5079 outSISIDXREG(SISCR, 0x7d, 0xfe);
5080 outSISIDXREG(SISCR, 0x7e, 0x0f);
5081 }
5082 if(ivideo->revision_id == 0) { /* 40 *and* 20? */
5083 andSISIDXREG(SISCR, 0x58, 0xd7);
5084 inSISIDXREG(SISCR, 0xcb, reg);
5085 if(reg & 0x20) {
5086 setSISIDXREG(SISCR, 0x58, 0xd7, (reg & 0x10) ? 0x08 : 0x20); /* =0x28 Z7 ? */
5087 }
5088 }
5089
5090 reg = (ivideo->chip == XGI_40) ? 0x20 : 0x00;
5091 setSISIDXREG(SISCR, 0x38, 0x1f, reg);
5092
5093 if(ivideo->chip == XGI_20) {
5094 outSISIDXREG(SISSR, 0x36, 0x70);
5095 } else {
5096 outSISIDXREG(SISVID, 0x00, 0x86);
5097 outSISIDXREG(SISVID, 0x32, 0x00);
5098 outSISIDXREG(SISVID, 0x30, 0x00);
5099 outSISIDXREG(SISVID, 0x32, 0x01);
5100 outSISIDXREG(SISVID, 0x30, 0x00);
5101 andSISIDXREG(SISVID, 0x2f, 0xdf);
5102 andSISIDXREG(SISCAP, 0x00, 0x3f);
5103
5104 outSISIDXREG(SISPART1, 0x2f, 0x01);
5105 outSISIDXREG(SISPART1, 0x00, 0x00);
5106 outSISIDXREG(SISPART1, 0x02, bios[0x7e]);
5107 outSISIDXREG(SISPART1, 0x2e, 0x08);
5108 andSISIDXREG(SISPART1, 0x35, 0x7f);
5109 andSISIDXREG(SISPART1, 0x50, 0xfe);
5110
5111 inSISIDXREG(SISPART4, 0x00, reg);
5112 if(reg == 1 || reg == 2) {
5113 outSISIDXREG(SISPART2, 0x00, 0x1c);
5114 outSISIDXREG(SISPART4, 0x0d, bios[0x7f]);
5115 outSISIDXREG(SISPART4, 0x0e, bios[0x80]);
5116 outSISIDXREG(SISPART4, 0x10, bios[0x81]);
5117 andSISIDXREG(SISPART4, 0x0f, 0x3f);
5118
5119 inSISIDXREG(SISPART4, 0x01, reg);
5120 if((reg & 0xf0) >= 0xb0) {
5121 inSISIDXREG(SISPART4, 0x23, reg);
5122 if(reg & 0x20) reg |= 0x40;
5123 outSISIDXREG(SISPART4, 0x23, reg);
5124 reg = (reg & 0x20) ? 0x02 : 0x00;
5125 setSISIDXREG(SISPART1, 0x1e, 0xfd, reg);
5126 }
5127 }
5128
5129 v1 = bios[0x77];
5130
5131 inSISIDXREG(SISSR, 0x3b, reg);
5132 if(reg & 0x02) {
5133 inSISIDXREG(SISSR, 0x3a, reg);
5134 v2 = (reg & 0x30) >> 3;
5135 if(!(v2 & 0x04)) v2 ^= 0x02;
5136 inSISIDXREG(SISSR, 0x39, reg);
5137 if(reg & 0x80) v2 |= 0x80;
5138 v2 |= 0x01;
5139
Adrian Bunk0959f0c2007-05-08 00:39:50 -07005140 if((mypdev = pci_get_device(PCI_VENDOR_ID_SI, 0x0730, NULL))) {
5141 pci_dev_put(mypdev);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07005142 if(((v2 & 0x06) == 2) || ((v2 & 0x06) == 4))
5143 v2 &= 0xf9;
5144 v2 |= 0x08;
5145 v1 &= 0xfe;
5146 } else {
Adrian Bunk0959f0c2007-05-08 00:39:50 -07005147 mypdev = pci_get_device(PCI_VENDOR_ID_SI, 0x0735, NULL);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07005148 if(!mypdev)
Adrian Bunk0959f0c2007-05-08 00:39:50 -07005149 mypdev = pci_get_device(PCI_VENDOR_ID_SI, 0x0645, NULL);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07005150 if(!mypdev)
Adrian Bunk0959f0c2007-05-08 00:39:50 -07005151 mypdev = pci_get_device(PCI_VENDOR_ID_SI, 0x0650, NULL);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07005152 if(mypdev) {
5153 pci_read_config_dword(mypdev, 0x94, &regd);
5154 regd &= 0xfffffeff;
5155 pci_write_config_dword(mypdev, 0x94, regd);
5156 v1 &= 0xfe;
Adrian Bunk0959f0c2007-05-08 00:39:50 -07005157 pci_dev_put(mypdev);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07005158 } else if(sisfb_find_host_bridge(ivideo, pdev, PCI_VENDOR_ID_SI)) {
5159 v1 &= 0xfe;
5160 } else if(sisfb_find_host_bridge(ivideo, pdev, 0x1106) ||
5161 sisfb_find_host_bridge(ivideo, pdev, 0x1022) ||
5162 sisfb_find_host_bridge(ivideo, pdev, 0x700e) ||
5163 sisfb_find_host_bridge(ivideo, pdev, 0x10de)) {
5164 if((v2 & 0x06) == 4)
5165 v2 ^= 0x06;
5166 v2 |= 0x08;
5167 }
5168 }
5169 setSISIDXREG(SISCR, 0x5f, 0xf0, v2);
5170 }
5171 outSISIDXREG(SISSR, 0x22, v1);
5172
5173 if(ivideo->revision_id == 2) {
5174 inSISIDXREG(SISSR, 0x3b, v1);
5175 inSISIDXREG(SISSR, 0x3a, v2);
5176 regd = bios[0x90 + 3] | (bios[0x90 + 4] << 8);
5177 if( (!(v1 & 0x02)) && (v2 & 0x30) && (regd < 0xcf) )
5178 setSISIDXREG(SISCR, 0x5f, 0xf1, 0x01);
5179
Adrian Bunk0959f0c2007-05-08 00:39:50 -07005180 if((mypdev = pci_get_device(0x10de, 0x01e0, NULL))) {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07005181 /* TODO: set CR5f &0xf1 | 0x01 for version 6570
5182 * of nforce 2 ROM
5183 */
5184 if(0)
5185 setSISIDXREG(SISCR, 0x5f, 0xf1, 0x01);
Adrian Bunk0959f0c2007-05-08 00:39:50 -07005186 pci_dev_put(mypdev);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07005187 }
5188 }
5189
5190 v1 = 0x30;
5191 inSISIDXREG(SISSR, 0x3b, reg);
5192 inSISIDXREG(SISCR, 0x5f, v2);
5193 if((!(reg & 0x02)) && (v2 & 0x0e))
5194 v1 |= 0x08;
5195 outSISIDXREG(SISSR, 0x27, v1);
5196
5197 if(bios[0x64] & 0x01) {
5198 setSISIDXREG(SISCR, 0x5f, 0xf0, bios[0x64]);
5199 }
5200
5201 v1 = bios[0x4f7];
5202 pci_read_config_dword(pdev, 0x50, &regd);
5203 regd = (regd >> 20) & 0x0f;
5204 if(regd == 1) {
5205 v1 &= 0xfc;
5206 orSISIDXREG(SISCR, 0x5f, 0x08);
5207 }
5208 outSISIDXREG(SISCR, 0x48, v1);
5209
5210 setSISIDXREG(SISCR, 0x47, 0x04, bios[0x4f6] & 0xfb);
5211 setSISIDXREG(SISCR, 0x49, 0xf0, bios[0x4f8] & 0x0f);
5212 setSISIDXREG(SISCR, 0x4a, 0x60, bios[0x4f9] & 0x9f);
5213 setSISIDXREG(SISCR, 0x4b, 0x08, bios[0x4fa] & 0xf7);
5214 setSISIDXREG(SISCR, 0x4c, 0x80, bios[0x4fb] & 0x7f);
5215 outSISIDXREG(SISCR, 0x70, bios[0x4fc]);
5216 setSISIDXREG(SISCR, 0x71, 0xf0, bios[0x4fd] & 0x0f);
5217 outSISIDXREG(SISCR, 0x74, 0xd0);
5218 setSISIDXREG(SISCR, 0x74, 0xcf, bios[0x4fe] & 0x30);
5219 setSISIDXREG(SISCR, 0x75, 0xe0, bios[0x4ff] & 0x1f);
5220 setSISIDXREG(SISCR, 0x76, 0xe0, bios[0x500] & 0x1f);
5221 v1 = bios[0x501];
Adrian Bunk0959f0c2007-05-08 00:39:50 -07005222 if((mypdev = pci_get_device(0x8086, 0x2530, NULL))) {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07005223 v1 = 0xf0;
Adrian Bunk0959f0c2007-05-08 00:39:50 -07005224 pci_dev_put(mypdev);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07005225 }
5226 outSISIDXREG(SISCR, 0x77, v1);
5227 }
5228
5229 /* RAM type */
5230
5231 regb = 0; /* ! */
5232
5233 v1 = 0xff;
5234 if(ivideo->haveXGIROM) {
5235 v1 = bios[0x140 + regb];
5236 }
5237 outSISIDXREG(SISCR, 0x6d, v1);
5238
5239 ptr = cs128;
5240 if(ivideo->haveXGIROM) {
5241 ptr = (const u8 *)&bios[0x128];
5242 }
5243 for(i = 0, j = 0; i < 3; i++, j += 8) {
5244 outSISIDXREG(SISCR, 0x68 + i, ptr[j + regb]);
5245 }
5246
5247 ptr = cs31a;
5248 ptr2 = cs33a;
5249 if(ivideo->haveXGIROM) {
5250 index = (ivideo->chip == XGI_20) ? 0x31a : 0x3a6;
5251 ptr = (const u8 *)&bios[index];
5252 ptr2 = (const u8 *)&bios[index + 0x20];
5253 }
5254 for(i = 0; i < 2; i++) {
5255 if(i == 0) {
5256 regd = le32_to_cpu(((u32 *)ptr)[regb]);
5257 rega = 0x6b;
5258 } else {
5259 regd = le32_to_cpu(((u32 *)ptr2)[regb]);
5260 rega = 0x6e;
5261 }
5262 reg = 0x00;
5263 for(j = 0; j < 16; j++) {
5264 reg &= 0xf3;
5265 if(regd & 0x01) reg |= 0x04;
5266 if(regd & 0x02) reg |= 0x08;
5267 regd >>= 2;
5268 outSISIDXREG(SISCR, rega, reg);
5269 inSISIDXREG(SISCR, rega, reg);
5270 inSISIDXREG(SISCR, rega, reg);
5271 reg += 0x10;
5272 }
5273 }
5274
5275 andSISIDXREG(SISCR, 0x6e, 0xfc);
5276
5277 ptr = NULL;
5278 if(ivideo->haveXGIROM) {
5279 index = (ivideo->chip == XGI_20) ? 0x35a : 0x3e6;
5280 ptr = (const u8 *)&bios[index];
5281 }
5282 for(i = 0; i < 4; i++) {
5283 setSISIDXREG(SISCR, 0x6e, 0xfc, i);
5284 reg = 0x00;
5285 for(j = 0; j < 2; j++) {
5286 regd = 0;
5287 if(ptr) {
5288 regd = le32_to_cpu(((u32 *)ptr)[regb * 8]);
5289 ptr += 4;
5290 }
5291 /* reg = 0x00; */
5292 for(k = 0; k < 16; k++) {
5293 reg &= 0xfc;
5294 if(regd & 0x01) reg |= 0x01;
5295 if(regd & 0x02) reg |= 0x02;
5296 regd >>= 2;
5297 outSISIDXREG(SISCR, 0x6f, reg);
5298 inSISIDXREG(SISCR, 0x6f, reg);
5299 inSISIDXREG(SISCR, 0x6f, reg);
5300 reg += 0x08;
5301 }
5302 }
5303 }
5304
5305 ptr = cs148;
5306 if(ivideo->haveXGIROM) {
5307 ptr = (const u8 *)&bios[0x148];
5308 }
5309 for(i = 0, j = 0; i < 2; i++, j += 8) {
5310 outSISIDXREG(SISCR, 0x80 + i, ptr[j + regb]);
5311 }
5312
5313 andSISIDXREG(SISCR, 0x89, 0x8f);
5314
5315 ptr = cs45a;
5316 if(ivideo->haveXGIROM) {
5317 index = (ivideo->chip == XGI_20) ? 0x45a : 0x4e6;
5318 ptr = (const u8 *)&bios[index];
5319 }
5320 regd = le16_to_cpu(((const u16 *)ptr)[regb]);
5321 reg = 0x80;
5322 for(i = 0; i < 5; i++) {
5323 reg &= 0xfc;
5324 if(regd & 0x01) reg |= 0x01;
5325 if(regd & 0x02) reg |= 0x02;
5326 regd >>= 2;
5327 outSISIDXREG(SISCR, 0x89, reg);
5328 inSISIDXREG(SISCR, 0x89, reg);
5329 inSISIDXREG(SISCR, 0x89, reg);
5330 reg += 0x10;
5331 }
5332
5333 v1 = 0xb5; v2 = 0x20; v3 = 0xf0; v4 = 0x13;
5334 if(ivideo->haveXGIROM) {
5335 v1 = bios[0x118 + regb];
5336 v2 = bios[0xf8 + regb];
5337 v3 = bios[0x120 + regb];
5338 v4 = bios[0x1ca];
5339 }
5340 outSISIDXREG(SISCR, 0x45, v1 & 0x0f);
5341 outSISIDXREG(SISCR, 0x99, (v1 >> 4) & 0x07);
5342 orSISIDXREG(SISCR, 0x40, v1 & 0x80);
5343 outSISIDXREG(SISCR, 0x41, v2);
5344
5345 ptr = cs170;
5346 if(ivideo->haveXGIROM) {
5347 ptr = (const u8 *)&bios[0x170];
5348 }
5349 for(i = 0, j = 0; i < 7; i++, j += 8) {
5350 outSISIDXREG(SISCR, 0x90 + i, ptr[j + regb]);
5351 }
5352
5353 outSISIDXREG(SISCR, 0x59, v3);
5354
5355 ptr = cs1a8;
5356 if(ivideo->haveXGIROM) {
5357 ptr = (const u8 *)&bios[0x1a8];
5358 }
5359 for(i = 0, j = 0; i < 3; i++, j += 8) {
5360 outSISIDXREG(SISCR, 0xc3 + i, ptr[j + regb]);
5361 }
5362
5363 ptr = cs100;
5364 if(ivideo->haveXGIROM) {
5365 ptr = (const u8 *)&bios[0x100];
5366 }
5367 for(i = 0, j = 0; i < 2; i++, j += 8) {
5368 outSISIDXREG(SISCR, 0x8a + i, ptr[j + regb]);
5369 }
5370
5371 outSISIDXREG(SISCR, 0xcf, v4);
5372
5373 outSISIDXREG(SISCR, 0x83, 0x09);
5374 outSISIDXREG(SISCR, 0x87, 0x00);
5375
5376 if(ivideo->chip == XGI_40) {
5377 if( (ivideo->revision_id == 1) ||
5378 (ivideo->revision_id == 2) ) {
5379 outSISIDXREG(SISCR, 0x8c, 0x87);
5380 }
5381 }
5382
5383 outSISIDXREG(SISSR, 0x17, 0x00);
5384 outSISIDXREG(SISSR, 0x1a, 0x87);
5385
5386 if(ivideo->chip == XGI_20) {
5387 outSISIDXREG(SISSR, 0x15, 0x00);
5388 outSISIDXREG(SISSR, 0x1c, 0x00);
5389 }
5390
5391 ramtype = 0x00; v1 = 0x10;
5392 if(ivideo->haveXGIROM) {
5393 ramtype = bios[0x62];
5394 v1 = bios[0x1d2];
5395 }
5396 if(!(ramtype & 0x80)) {
5397 if(ivideo->chip == XGI_20) {
5398 outSISIDXREG(SISCR, 0x97, v1);
5399 inSISIDXREG(SISCR, 0x97, reg);
5400 if(reg & 0x10) {
5401 ramtype = (reg & 0x01) << 1;
5402 }
5403 } else {
5404 inSISIDXREG(SISSR, 0x39, reg);
5405 ramtype = reg & 0x02;
5406 if(!(ramtype)) {
5407 inSISIDXREG(SISSR, 0x3a, reg);
5408 ramtype = (reg >> 1) & 0x01;
5409 }
5410 }
5411 }
5412 ramtype &= 0x07;
5413
5414 regb = 0; /* ! */
5415
5416 switch(ramtype) {
5417 case 0:
5418 sisfb_post_xgi_setclocks(ivideo, regb);
5419 if((ivideo->chip == XGI_20) ||
5420 (ivideo->revision_id == 1) ||
5421 (ivideo->revision_id == 2)) {
5422 v1 = cs158[regb]; v2 = cs160[regb]; v3 = cs168[regb];
5423 if(ivideo->haveXGIROM) {
5424 v1 = bios[regb + 0x158];
5425 v2 = bios[regb + 0x160];
5426 v3 = bios[regb + 0x168];
5427 }
5428 outSISIDXREG(SISCR, 0x82, v1);
5429 outSISIDXREG(SISCR, 0x85, v2);
5430 outSISIDXREG(SISCR, 0x86, v3);
5431 } else {
5432 outSISIDXREG(SISCR, 0x82, 0x88);
5433 outSISIDXREG(SISCR, 0x86, 0x00);
5434 inSISIDXREG(SISCR, 0x86, reg);
5435 outSISIDXREG(SISCR, 0x86, 0x88);
5436 inSISIDXREG(SISCR, 0x86, reg);
5437 outSISIDXREG(SISCR, 0x86, bios[regb + 0x168]);
5438 outSISIDXREG(SISCR, 0x82, 0x77);
5439 outSISIDXREG(SISCR, 0x85, 0x00);
5440 inSISIDXREG(SISCR, 0x85, reg);
5441 outSISIDXREG(SISCR, 0x85, 0x88);
5442 inSISIDXREG(SISCR, 0x85, reg);
5443 outSISIDXREG(SISCR, 0x85, bios[regb + 0x160]);
5444 outSISIDXREG(SISCR, 0x82, bios[regb + 0x158]);
5445 }
5446 if(ivideo->chip == XGI_40) {
5447 outSISIDXREG(SISCR, 0x97, 0x00);
5448 }
5449 outSISIDXREG(SISCR, 0x98, 0x01);
5450 outSISIDXREG(SISCR, 0x9a, 0x02);
5451
5452 outSISIDXREG(SISSR, 0x18, 0x01);
5453 if((ivideo->chip == XGI_20) ||
5454 (ivideo->revision_id == 2)) {
5455 outSISIDXREG(SISSR, 0x19, 0x40);
5456 } else {
5457 outSISIDXREG(SISSR, 0x19, 0x20);
5458 }
5459 outSISIDXREG(SISSR, 0x16, 0x00);
5460 outSISIDXREG(SISSR, 0x16, 0x80);
5461 if((ivideo->chip == XGI_20) || (bios[0x1cb] != 0x0c)) {
5462 sisfb_post_xgi_delay(ivideo, 0x43);
5463 sisfb_post_xgi_delay(ivideo, 0x43);
5464 sisfb_post_xgi_delay(ivideo, 0x43);
5465 outSISIDXREG(SISSR, 0x18, 0x00);
5466 if((ivideo->chip == XGI_20) ||
5467 (ivideo->revision_id == 2)) {
5468 outSISIDXREG(SISSR, 0x19, 0x40);
5469 } else {
5470 outSISIDXREG(SISSR, 0x19, 0x20);
5471 }
5472 } else if((ivideo->chip == XGI_40) && (bios[0x1cb] == 0x0c)) {
5473 /* outSISIDXREG(SISSR, 0x16, 0x0c); */ /* ? */
5474 }
5475 outSISIDXREG(SISSR, 0x16, 0x00);
5476 outSISIDXREG(SISSR, 0x16, 0x80);
5477 sisfb_post_xgi_delay(ivideo, 4);
5478 v1 = 0x31; v2 = 0x03; v3 = 0x83; v4 = 0x03; v5 = 0x83;
5479 if(ivideo->haveXGIROM) {
5480 v1 = bios[0xf0];
5481 index = (ivideo->chip == XGI_20) ? 0x4b2 : 0x53e;
5482 v2 = bios[index];
5483 v3 = bios[index + 1];
5484 v4 = bios[index + 2];
5485 v5 = bios[index + 3];
5486 }
5487 outSISIDXREG(SISSR, 0x18, v1);
5488 outSISIDXREG(SISSR, 0x19, ((ivideo->chip == XGI_20) ? 0x02 : 0x01));
5489 outSISIDXREG(SISSR, 0x16, v2);
5490 outSISIDXREG(SISSR, 0x16, v3);
5491 sisfb_post_xgi_delay(ivideo, 0x43);
5492 outSISIDXREG(SISSR, 0x1b, 0x03);
5493 sisfb_post_xgi_delay(ivideo, 0x22);
5494 outSISIDXREG(SISSR, 0x18, v1);
5495 outSISIDXREG(SISSR, 0x19, 0x00);
5496 outSISIDXREG(SISSR, 0x16, v4);
5497 outSISIDXREG(SISSR, 0x16, v5);
5498 outSISIDXREG(SISSR, 0x1b, 0x00);
5499 break;
5500 case 1:
5501 outSISIDXREG(SISCR, 0x82, 0x77);
5502 outSISIDXREG(SISCR, 0x86, 0x00);
5503 inSISIDXREG(SISCR, 0x86, reg);
5504 outSISIDXREG(SISCR, 0x86, 0x88);
5505 inSISIDXREG(SISCR, 0x86, reg);
5506 v1 = cs168[regb]; v2 = cs160[regb]; v3 = cs158[regb];
5507 if(ivideo->haveXGIROM) {
5508 v1 = bios[regb + 0x168];
5509 v2 = bios[regb + 0x160];
5510 v3 = bios[regb + 0x158];
5511 }
5512 outSISIDXREG(SISCR, 0x86, v1);
5513 outSISIDXREG(SISCR, 0x82, 0x77);
5514 outSISIDXREG(SISCR, 0x85, 0x00);
5515 inSISIDXREG(SISCR, 0x85, reg);
5516 outSISIDXREG(SISCR, 0x85, 0x88);
5517 inSISIDXREG(SISCR, 0x85, reg);
5518 outSISIDXREG(SISCR, 0x85, v2);
5519 outSISIDXREG(SISCR, 0x82, v3);
5520 outSISIDXREG(SISCR, 0x98, 0x01);
5521 outSISIDXREG(SISCR, 0x9a, 0x02);
5522
5523 outSISIDXREG(SISSR, 0x28, 0x64);
5524 outSISIDXREG(SISSR, 0x29, 0x63);
5525 sisfb_post_xgi_delay(ivideo, 15);
5526 outSISIDXREG(SISSR, 0x18, 0x00);
5527 outSISIDXREG(SISSR, 0x19, 0x20);
5528 outSISIDXREG(SISSR, 0x16, 0x00);
5529 outSISIDXREG(SISSR, 0x16, 0x80);
5530 outSISIDXREG(SISSR, 0x18, 0xc5);
5531 outSISIDXREG(SISSR, 0x19, 0x23);
5532 outSISIDXREG(SISSR, 0x16, 0x00);
5533 outSISIDXREG(SISSR, 0x16, 0x80);
5534 sisfb_post_xgi_delay(ivideo, 1);
5535 outSISIDXREG(SISCR, 0x97,0x11);
5536 sisfb_post_xgi_setclocks(ivideo, regb);
5537 sisfb_post_xgi_delay(ivideo, 0x46);
5538 outSISIDXREG(SISSR, 0x18, 0xc5);
5539 outSISIDXREG(SISSR, 0x19, 0x23);
5540 outSISIDXREG(SISSR, 0x16, 0x00);
5541 outSISIDXREG(SISSR, 0x16, 0x80);
5542 sisfb_post_xgi_delay(ivideo, 1);
5543 outSISIDXREG(SISSR, 0x1b, 0x04);
5544 sisfb_post_xgi_delay(ivideo, 1);
5545 outSISIDXREG(SISSR, 0x1b, 0x00);
5546 sisfb_post_xgi_delay(ivideo, 1);
5547 v1 = 0x31;
5548 if(ivideo->haveXGIROM) {
5549 v1 = bios[0xf0];
5550 }
5551 outSISIDXREG(SISSR, 0x18, v1);
5552 outSISIDXREG(SISSR, 0x19, 0x06);
5553 outSISIDXREG(SISSR, 0x16, 0x04);
5554 outSISIDXREG(SISSR, 0x16, 0x84);
5555 sisfb_post_xgi_delay(ivideo, 1);
5556 break;
5557 default:
5558 sisfb_post_xgi_setclocks(ivideo, regb);
5559 if((ivideo->chip == XGI_40) &&
5560 ((ivideo->revision_id == 1) ||
5561 (ivideo->revision_id == 2))) {
5562 outSISIDXREG(SISCR, 0x82, bios[regb + 0x158]);
5563 outSISIDXREG(SISCR, 0x85, bios[regb + 0x160]);
5564 outSISIDXREG(SISCR, 0x86, bios[regb + 0x168]);
5565 } else {
5566 outSISIDXREG(SISCR, 0x82, 0x88);
5567 outSISIDXREG(SISCR, 0x86, 0x00);
5568 inSISIDXREG(SISCR, 0x86, reg);
5569 outSISIDXREG(SISCR, 0x86, 0x88);
5570 outSISIDXREG(SISCR, 0x82, 0x77);
5571 outSISIDXREG(SISCR, 0x85, 0x00);
5572 inSISIDXREG(SISCR, 0x85, reg);
5573 outSISIDXREG(SISCR, 0x85, 0x88);
5574 inSISIDXREG(SISCR, 0x85, reg);
5575 v1 = cs160[regb]; v2 = cs158[regb];
5576 if(ivideo->haveXGIROM) {
5577 v1 = bios[regb + 0x160];
5578 v2 = bios[regb + 0x158];
5579 }
5580 outSISIDXREG(SISCR, 0x85, v1);
5581 outSISIDXREG(SISCR, 0x82, v2);
5582 }
5583 if(ivideo->chip == XGI_40) {
5584 outSISIDXREG(SISCR, 0x97, 0x11);
5585 }
5586 if((ivideo->chip == XGI_40) && (ivideo->revision_id == 2)) {
5587 outSISIDXREG(SISCR, 0x98, 0x01);
5588 } else {
5589 outSISIDXREG(SISCR, 0x98, 0x03);
5590 }
5591 outSISIDXREG(SISCR, 0x9a, 0x02);
5592
5593 if(ivideo->chip == XGI_40) {
5594 outSISIDXREG(SISSR, 0x18, 0x01);
5595 } else {
5596 outSISIDXREG(SISSR, 0x18, 0x00);
5597 }
5598 outSISIDXREG(SISSR, 0x19, 0x40);
5599 outSISIDXREG(SISSR, 0x16, 0x00);
5600 outSISIDXREG(SISSR, 0x16, 0x80);
5601 if((ivideo->chip == XGI_40) && (bios[0x1cb] != 0x0c)) {
5602 sisfb_post_xgi_delay(ivideo, 0x43);
5603 sisfb_post_xgi_delay(ivideo, 0x43);
5604 sisfb_post_xgi_delay(ivideo, 0x43);
5605 outSISIDXREG(SISSR, 0x18, 0x00);
5606 outSISIDXREG(SISSR, 0x19, 0x40);
5607 outSISIDXREG(SISSR, 0x16, 0x00);
5608 outSISIDXREG(SISSR, 0x16, 0x80);
5609 }
5610 sisfb_post_xgi_delay(ivideo, 4);
5611 v1 = 0x31;
5612 if(ivideo->haveXGIROM) {
5613 v1 = bios[0xf0];
5614 }
5615 outSISIDXREG(SISSR, 0x18, v1);
5616 outSISIDXREG(SISSR, 0x19, 0x01);
5617 if(ivideo->chip == XGI_40) {
5618 outSISIDXREG(SISSR, 0x16, bios[0x53e]);
5619 outSISIDXREG(SISSR, 0x16, bios[0x53f]);
5620 } else {
5621 outSISIDXREG(SISSR, 0x16, 0x05);
5622 outSISIDXREG(SISSR, 0x16, 0x85);
5623 }
5624 sisfb_post_xgi_delay(ivideo, 0x43);
5625 if(ivideo->chip == XGI_40) {
5626 outSISIDXREG(SISSR, 0x1b, 0x01);
5627 } else {
5628 outSISIDXREG(SISSR, 0x1b, 0x03);
5629 }
5630 sisfb_post_xgi_delay(ivideo, 0x22);
5631 outSISIDXREG(SISSR, 0x18, v1);
5632 outSISIDXREG(SISSR, 0x19, 0x00);
5633 if(ivideo->chip == XGI_40) {
5634 outSISIDXREG(SISSR, 0x16, bios[0x540]);
5635 outSISIDXREG(SISSR, 0x16, bios[0x541]);
5636 } else {
5637 outSISIDXREG(SISSR, 0x16, 0x05);
5638 outSISIDXREG(SISSR, 0x16, 0x85);
5639 }
5640 outSISIDXREG(SISSR, 0x1b, 0x00);
5641 }
5642
5643 regb = 0; /* ! */
5644 v1 = 0x03;
5645 if(ivideo->haveXGIROM) {
5646 v1 = bios[0x110 + regb];
5647 }
5648 outSISIDXREG(SISSR, 0x1b, v1);
5649
5650 /* RAM size */
5651 v1 = 0x00; v2 = 0x00;
5652 if(ivideo->haveXGIROM) {
5653 v1 = bios[0x62];
5654 v2 = bios[0x63];
5655 }
5656 regb = 0; /* ! */
5657 regd = 1 << regb;
5658 if((v1 & 0x40) && (v2 & regd) && ivideo->haveXGIROM) {
5659
5660 outSISIDXREG(SISSR, 0x13, bios[regb + 0xe0]);
5661 outSISIDXREG(SISSR, 0x14, bios[regb + 0xe0 + 8]);
5662
5663 } else {
5664
5665 /* Set default mode, don't clear screen */
Richard Knutssonc30660e2007-02-12 00:55:06 -08005666 ivideo->SiS_Pr.SiS_UseOEM = false;
5667 SiS_SetEnableDstn(&ivideo->SiS_Pr, false);
5668 SiS_SetEnableFstn(&ivideo->SiS_Pr, false);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07005669 ivideo->curFSTN = ivideo->curDSTN = 0;
5670 ivideo->SiS_Pr.VideoMemorySize = 8 << 20;
5671 SiSSetMode(&ivideo->SiS_Pr, 0x2e | 0x80);
5672
5673 outSISIDXREG(SISSR, 0x05, 0x86);
5674
5675 /* Disable read-cache */
5676 andSISIDXREG(SISSR, 0x21, 0xdf);
5677 sisfb_post_xgi_ramsize(ivideo);
5678 /* Enable read-cache */
5679 orSISIDXREG(SISSR, 0x21, 0x20);
5680
5681 }
5682
5683#if 0
5684 printk(KERN_DEBUG "-----------------\n");
5685 for(i = 0; i < 0xff; i++) {
5686 inSISIDXREG(SISCR, i, reg);
5687 printk(KERN_DEBUG "CR%02x(%x) = 0x%02x\n", i, SISCR, reg);
5688 }
5689 for(i = 0; i < 0x40; i++) {
5690 inSISIDXREG(SISSR, i, reg);
5691 printk(KERN_DEBUG "SR%02x(%x) = 0x%02x\n", i, SISSR, reg);
5692 }
5693 printk(KERN_DEBUG "-----------------\n");
5694#endif
5695
5696 /* Sense CRT1 */
5697 if(ivideo->chip == XGI_20) {
5698 orSISIDXREG(SISCR, 0x32, 0x20);
5699 } else {
5700 inSISIDXREG(SISPART4, 0x00, reg);
5701 if((reg == 1) || (reg == 2)) {
5702 sisfb_sense_crt1(ivideo);
5703 } else {
5704 orSISIDXREG(SISCR, 0x32, 0x20);
5705 }
5706 }
5707
5708 /* Set default mode, don't clear screen */
Richard Knutssonc30660e2007-02-12 00:55:06 -08005709 ivideo->SiS_Pr.SiS_UseOEM = false;
5710 SiS_SetEnableDstn(&ivideo->SiS_Pr, false);
5711 SiS_SetEnableFstn(&ivideo->SiS_Pr, false);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07005712 ivideo->curFSTN = ivideo->curDSTN = 0;
5713 SiSSetMode(&ivideo->SiS_Pr, 0x2e | 0x80);
5714
5715 outSISIDXREG(SISSR, 0x05, 0x86);
5716
5717 /* Display off */
5718 orSISIDXREG(SISSR, 0x01, 0x20);
5719
5720 /* Save mode number in CR34 */
5721 outSISIDXREG(SISCR, 0x34, 0x2e);
5722
5723 /* Let everyone know what the current mode is */
5724 ivideo->modeprechange = 0x2e;
5725
5726 if(ivideo->chip == XGI_40) {
5727 inSISIDXREG(SISCR, 0xca, reg);
5728 inSISIDXREG(SISCR, 0xcc, v1);
5729 if((reg & 0x10) && (!(v1 & 0x04))) {
5730 printk(KERN_ERR
5731 "sisfb: Please connect power to the card.\n");
5732 return 0;
5733 }
5734 }
5735
5736 return 1;
5737}
5738#endif
5739
5740static int __devinit
5741sisfb_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
5742{
5743 struct sisfb_chip_info *chipinfo = &sisfb_chip_info[ent->driver_data];
5744 struct sis_video_info *ivideo = NULL;
5745 struct fb_info *sis_fb_info = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005746 u16 reg16;
5747 u8 reg;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07005748 int i, ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005749
Thomas Winischhofer544393f2005-09-09 13:04:45 -07005750 if(sisfb_off)
5751 return -ENXIO;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005752
Linus Torvalds1da177e2005-04-16 15:20:36 -07005753 sis_fb_info = framebuffer_alloc(sizeof(*ivideo), &pdev->dev);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07005754 if(!sis_fb_info)
5755 return -ENOMEM;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005756
5757 ivideo = (struct sis_video_info *)sis_fb_info->par;
5758 ivideo->memyselfandi = sis_fb_info;
5759
Thomas Winischhofer544393f2005-09-09 13:04:45 -07005760 ivideo->sisfb_id = SISFB_ID;
5761
Linus Torvalds1da177e2005-04-16 15:20:36 -07005762 if(card_list == NULL) {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07005763 ivideo->cardnumber = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005764 } else {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07005765 struct sis_video_info *countvideo = card_list;
5766 ivideo->cardnumber = 1;
Harvey Harrison5e2daeb2008-05-22 15:45:08 -07005767 while((countvideo = countvideo->next) != NULL)
Thomas Winischhofer544393f2005-09-09 13:04:45 -07005768 ivideo->cardnumber++;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005769 }
5770
5771 strncpy(ivideo->myid, chipinfo->chip_name, 30);
5772
5773 ivideo->warncount = 0;
5774 ivideo->chip_id = pdev->device;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07005775 ivideo->chip_vendor = pdev->vendor;
Auke Kok44c10132007-06-08 15:46:36 -07005776 ivideo->revision_id = pdev->revision;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07005777 ivideo->SiS_Pr.ChipRevision = ivideo->revision_id;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005778 pci_read_config_word(pdev, PCI_COMMAND, &reg16);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07005779 ivideo->sisvga_enabled = reg16 & 0x01;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005780 ivideo->pcibus = pdev->bus->number;
5781 ivideo->pcislot = PCI_SLOT(pdev->devfn);
5782 ivideo->pcifunc = PCI_FUNC(pdev->devfn);
5783 ivideo->subsysvendor = pdev->subsystem_vendor;
5784 ivideo->subsysdevice = pdev->subsystem_device;
5785
5786#ifndef MODULE
5787 if(sisfb_mode_idx == -1) {
5788 sisfb_get_vga_mode_from_kernel();
5789 }
5790#endif
5791
5792 ivideo->chip = chipinfo->chip;
5793 ivideo->sisvga_engine = chipinfo->vgaengine;
5794 ivideo->hwcursor_size = chipinfo->hwcursor_size;
5795 ivideo->CRT2_write_enable = chipinfo->CRT2_write_enable;
5796 ivideo->mni = chipinfo->mni;
5797
5798 ivideo->detectedpdc = 0xff;
5799 ivideo->detectedpdca = 0xff;
5800 ivideo->detectedlcda = 0xff;
5801
Richard Knutssonc30660e2007-02-12 00:55:06 -08005802 ivideo->sisfb_thismonitor.datavalid = false;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005803
Thomas Winischhofer544393f2005-09-09 13:04:45 -07005804 ivideo->current_base = 0;
5805
5806 ivideo->engineok = 0;
5807
5808 ivideo->sisfb_was_boot_device = 0;
Adrian Bunk14aefd12008-07-23 21:31:12 -07005809
Thomas Winischhofer544393f2005-09-09 13:04:45 -07005810 if(pdev->resource[PCI_ROM_RESOURCE].flags & IORESOURCE_ROM_SHADOW) {
5811 if(ivideo->sisvga_enabled)
5812 ivideo->sisfb_was_boot_device = 1;
5813 else {
5814 printk(KERN_DEBUG "sisfb: PCI device is disabled, "
5815 "but marked as boot video device ???\n");
5816 printk(KERN_DEBUG "sisfb: I will not accept this "
5817 "as the primary VGA device\n");
5818 }
5819 }
Thomas Winischhofer544393f2005-09-09 13:04:45 -07005820
Linus Torvalds1da177e2005-04-16 15:20:36 -07005821 ivideo->sisfb_parm_mem = sisfb_parm_mem;
5822 ivideo->sisfb_accel = sisfb_accel;
5823 ivideo->sisfb_ypan = sisfb_ypan;
5824 ivideo->sisfb_max = sisfb_max;
5825 ivideo->sisfb_userom = sisfb_userom;
5826 ivideo->sisfb_useoem = sisfb_useoem;
5827 ivideo->sisfb_mode_idx = sisfb_mode_idx;
5828 ivideo->sisfb_parm_rate = sisfb_parm_rate;
5829 ivideo->sisfb_crt1off = sisfb_crt1off;
5830 ivideo->sisfb_forcecrt1 = sisfb_forcecrt1;
5831 ivideo->sisfb_crt2type = sisfb_crt2type;
5832 ivideo->sisfb_crt2flags = sisfb_crt2flags;
5833 /* pdc(a), scalelcd, special timing, lvdshl handled below */
5834 ivideo->sisfb_dstn = sisfb_dstn;
5835 ivideo->sisfb_fstn = sisfb_fstn;
5836 ivideo->sisfb_tvplug = sisfb_tvplug;
5837 ivideo->sisfb_tvstd = sisfb_tvstd;
5838 ivideo->tvxpos = sisfb_tvxposoffset;
5839 ivideo->tvypos = sisfb_tvyposoffset;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005840 ivideo->sisfb_nocrt2rate = sisfb_nocrt2rate;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005841 ivideo->refresh_rate = 0;
5842 if(ivideo->sisfb_parm_rate != -1) {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07005843 ivideo->refresh_rate = ivideo->sisfb_parm_rate;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005844 }
5845
5846 ivideo->SiS_Pr.UsePanelScaler = sisfb_scalelcd;
5847 ivideo->SiS_Pr.CenterScreen = -1;
5848 ivideo->SiS_Pr.SiS_CustomT = sisfb_specialtiming;
5849 ivideo->SiS_Pr.LVDSHL = sisfb_lvdshl;
5850
5851 ivideo->SiS_Pr.SiS_Backup70xx = 0xff;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07005852 ivideo->SiS_Pr.SiS_CHOverScan = -1;
Richard Knutssonc30660e2007-02-12 00:55:06 -08005853 ivideo->SiS_Pr.SiS_ChSW = false;
5854 ivideo->SiS_Pr.SiS_UseLCDA = false;
5855 ivideo->SiS_Pr.HaveEMI = false;
5856 ivideo->SiS_Pr.HaveEMILCD = false;
5857 ivideo->SiS_Pr.OverruleEMI = false;
5858 ivideo->SiS_Pr.SiS_SensibleSR11 = false;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005859 ivideo->SiS_Pr.SiS_MyCR63 = 0x63;
5860 ivideo->SiS_Pr.PDC = -1;
5861 ivideo->SiS_Pr.PDCA = -1;
Richard Knutssonc30660e2007-02-12 00:55:06 -08005862 ivideo->SiS_Pr.DDCPortMixup = false;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005863#ifdef CONFIG_FB_SIS_315
5864 if(ivideo->chip >= SIS_330) {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07005865 ivideo->SiS_Pr.SiS_MyCR63 = 0x53;
5866 if(ivideo->chip >= SIS_661) {
Richard Knutssonc30660e2007-02-12 00:55:06 -08005867 ivideo->SiS_Pr.SiS_SensibleSR11 = true;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07005868 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07005869 }
5870#endif
5871
5872 memcpy(&ivideo->default_var, &my_default_var, sizeof(my_default_var));
5873
5874 pci_set_drvdata(pdev, ivideo);
5875
5876 /* Patch special cases */
5877 if((ivideo->nbridge = sisfb_get_northbridge(ivideo->chip))) {
5878 switch(ivideo->nbridge->device) {
5879#ifdef CONFIG_FB_SIS_300
5880 case PCI_DEVICE_ID_SI_730:
Thomas Winischhofer544393f2005-09-09 13:04:45 -07005881 ivideo->chip = SIS_730;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005882 strcpy(ivideo->myid, "SiS 730");
Thomas Winischhofer544393f2005-09-09 13:04:45 -07005883 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005884#endif
5885#ifdef CONFIG_FB_SIS_315
5886 case PCI_DEVICE_ID_SI_651:
5887 /* ivideo->chip is ok */
5888 strcpy(ivideo->myid, "SiS 651");
5889 break;
5890 case PCI_DEVICE_ID_SI_740:
Thomas Winischhofer544393f2005-09-09 13:04:45 -07005891 ivideo->chip = SIS_740;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005892 strcpy(ivideo->myid, "SiS 740");
5893 break;
5894 case PCI_DEVICE_ID_SI_661:
Thomas Winischhofer544393f2005-09-09 13:04:45 -07005895 ivideo->chip = SIS_661;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005896 strcpy(ivideo->myid, "SiS 661");
5897 break;
5898 case PCI_DEVICE_ID_SI_741:
Thomas Winischhofer544393f2005-09-09 13:04:45 -07005899 ivideo->chip = SIS_741;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005900 strcpy(ivideo->myid, "SiS 741");
5901 break;
5902 case PCI_DEVICE_ID_SI_760:
Thomas Winischhofer544393f2005-09-09 13:04:45 -07005903 ivideo->chip = SIS_760;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005904 strcpy(ivideo->myid, "SiS 760");
5905 break;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07005906 case PCI_DEVICE_ID_SI_761:
5907 ivideo->chip = SIS_761;
5908 strcpy(ivideo->myid, "SiS 761");
5909 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005910#endif
Thomas Winischhofer544393f2005-09-09 13:04:45 -07005911 default:
5912 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005913 }
5914 }
5915
Thomas Winischhofer544393f2005-09-09 13:04:45 -07005916 ivideo->SiS_Pr.ChipType = ivideo->chip;
5917
5918 ivideo->SiS_Pr.ivideo = (void *)ivideo;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005919
5920#ifdef CONFIG_FB_SIS_315
Thomas Winischhofer544393f2005-09-09 13:04:45 -07005921 if((ivideo->SiS_Pr.ChipType == SIS_315PRO) ||
5922 (ivideo->SiS_Pr.ChipType == SIS_315)) {
5923 ivideo->SiS_Pr.ChipType = SIS_315H;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005924 }
5925#endif
5926
Thomas Winischhofer544393f2005-09-09 13:04:45 -07005927 if(!ivideo->sisvga_enabled) {
5928 if(pci_enable_device(pdev)) {
Adrian Bunk0959f0c2007-05-08 00:39:50 -07005929 if(ivideo->nbridge) pci_dev_put(ivideo->nbridge);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07005930 pci_set_drvdata(pdev, NULL);
5931 kfree(sis_fb_info);
5932 return -EIO;
5933 }
5934 }
5935
Linus Torvalds1da177e2005-04-16 15:20:36 -07005936 ivideo->video_base = pci_resource_start(pdev, 0);
5937 ivideo->mmio_base = pci_resource_start(pdev, 1);
5938 ivideo->mmio_size = pci_resource_len(pdev, 1);
5939 ivideo->SiS_Pr.RelIO = pci_resource_start(pdev, 2) + 0x30;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07005940 ivideo->SiS_Pr.IOAddress = ivideo->vga_base = ivideo->SiS_Pr.RelIO;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005941
Thomas Winischhofer544393f2005-09-09 13:04:45 -07005942 SiSRegInit(&ivideo->SiS_Pr, ivideo->SiS_Pr.IOAddress);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005943
5944#ifdef CONFIG_FB_SIS_300
5945 /* Find PCI systems for Chrontel/GPIO communication setup */
5946 if(ivideo->chip == SIS_630) {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07005947 i = 0;
5948 do {
5949 if(mychswtable[i].subsysVendor == ivideo->subsysvendor &&
5950 mychswtable[i].subsysCard == ivideo->subsysdevice) {
Richard Knutssonc30660e2007-02-12 00:55:06 -08005951 ivideo->SiS_Pr.SiS_ChSW = true;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07005952 printk(KERN_DEBUG "sisfb: Identified [%s %s] "
5953 "requiring Chrontel/GPIO setup\n",
5954 mychswtable[i].vendorName,
5955 mychswtable[i].cardName);
Adrian Bunk0959f0c2007-05-08 00:39:50 -07005956 ivideo->lpcdev = pci_get_device(PCI_VENDOR_ID_SI, 0x0008, NULL);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07005957 break;
5958 }
5959 i++;
5960 } while(mychswtable[i].subsysVendor != 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005961 }
5962#endif
5963
Thomas Winischhofer544393f2005-09-09 13:04:45 -07005964#ifdef CONFIG_FB_SIS_315
5965 if((ivideo->chip == SIS_760) && (ivideo->nbridge)) {
Adrian Bunk0959f0c2007-05-08 00:39:50 -07005966 ivideo->lpcdev = pci_get_slot(ivideo->nbridge->bus, (2 << 3));
Thomas Winischhofer544393f2005-09-09 13:04:45 -07005967 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07005968#endif
Thomas Winischhofer544393f2005-09-09 13:04:45 -07005969
5970 outSISIDXREG(SISSR, 0x05, 0x86);
5971
5972 if( (!ivideo->sisvga_enabled)
5973#if !defined(__i386__) && !defined(__x86_64__)
5974 || (sisfb_resetcard)
5975#endif
5976 ) {
5977 for(i = 0x30; i <= 0x3f; i++) {
5978 outSISIDXREG(SISCR, i, 0x00);
5979 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07005980 }
5981
5982 /* Find out about current video mode */
5983 ivideo->modeprechange = 0x03;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07005984 inSISIDXREG(SISCR, 0x34, reg);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005985 if(reg & 0x7f) {
5986 ivideo->modeprechange = reg & 0x7f;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07005987 } else if(ivideo->sisvga_enabled) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07005988#if defined(__i386__) || defined(__x86_64__)
Adrian Bunk14aefd12008-07-23 21:31:12 -07005989 unsigned char __iomem *tt = ioremap(0x400, 0x100);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005990 if(tt) {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07005991 ivideo->modeprechange = readb(tt + 0x49);
5992 iounmap(tt);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005993 }
5994#endif
5995 }
5996
Thomas Winischhofer544393f2005-09-09 13:04:45 -07005997 /* Search and copy ROM image */
5998 ivideo->bios_abase = NULL;
5999 ivideo->SiS_Pr.VirtualRomBase = NULL;
Richard Knutssonc30660e2007-02-12 00:55:06 -08006000 ivideo->SiS_Pr.UseROM = false;
6001 ivideo->haveXGIROM = ivideo->SiS_Pr.SiS_XGIROM = false;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006002 if(ivideo->sisfb_userom) {
6003 ivideo->SiS_Pr.VirtualRomBase = sisfb_find_rom(pdev);
6004 ivideo->bios_abase = ivideo->SiS_Pr.VirtualRomBase;
Richard Knutssonc30660e2007-02-12 00:55:06 -08006005 ivideo->SiS_Pr.UseROM = (bool)(ivideo->SiS_Pr.VirtualRomBase);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006006 printk(KERN_INFO "sisfb: Video ROM %sfound\n",
6007 ivideo->SiS_Pr.UseROM ? "" : "not ");
6008 if((ivideo->SiS_Pr.UseROM) && (ivideo->chip >= XGI_20)) {
Richard Knutssonc30660e2007-02-12 00:55:06 -08006009 ivideo->SiS_Pr.UseROM = false;
6010 ivideo->haveXGIROM = ivideo->SiS_Pr.SiS_XGIROM = true;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006011 if( (ivideo->revision_id == 2) &&
6012 (!(ivideo->bios_abase[0x1d1] & 0x01)) ) {
Richard Knutssonc30660e2007-02-12 00:55:06 -08006013 ivideo->SiS_Pr.DDCPortMixup = true;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006014 }
6015 }
6016 } else {
6017 printk(KERN_INFO "sisfb: Video ROM usage disabled\n");
6018 }
6019
6020 /* Find systems for special custom timing */
6021 if(ivideo->SiS_Pr.SiS_CustomT == CUT_NONE) {
6022 sisfb_detect_custom_timing(ivideo);
6023 }
6024
6025 /* POST card in case this has not been done by the BIOS */
6026 if( (!ivideo->sisvga_enabled)
6027#if !defined(__i386__) && !defined(__x86_64__)
6028 || (sisfb_resetcard)
6029#endif
6030 ) {
6031#ifdef CONFIG_FB_SIS_300
6032 if(ivideo->sisvga_engine == SIS_300_VGA) {
6033 if(ivideo->chip == SIS_300) {
6034 sisfb_post_sis300(pdev);
6035 ivideo->sisfb_can_post = 1;
6036 }
6037 }
6038#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -07006039
6040#ifdef CONFIG_FB_SIS_315
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006041 if(ivideo->sisvga_engine == SIS_315_VGA) {
6042 int result = 1;
6043 /* if((ivideo->chip == SIS_315H) ||
Linus Torvalds1da177e2005-04-16 15:20:36 -07006044 (ivideo->chip == SIS_315) ||
6045 (ivideo->chip == SIS_315PRO) ||
6046 (ivideo->chip == SIS_330)) {
6047 sisfb_post_sis315330(pdev);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006048 } else */ if(ivideo->chip == XGI_20) {
6049 result = sisfb_post_xgi(pdev);
6050 ivideo->sisfb_can_post = 1;
6051 } else if((ivideo->chip == XGI_40) && ivideo->haveXGIROM) {
6052 result = sisfb_post_xgi(pdev);
6053 ivideo->sisfb_can_post = 1;
6054 } else {
6055 printk(KERN_INFO "sisfb: Card is not "
6056 "POSTed and sisfb can't do this either.\n");
6057 }
6058 if(!result) {
6059 printk(KERN_ERR "sisfb: Failed to POST card\n");
6060 ret = -ENODEV;
6061 goto error_3;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006062 }
6063 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07006064#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -07006065 }
6066
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006067 ivideo->sisfb_card_posted = 1;
6068
6069 /* Find out about RAM size */
6070 if(sisfb_get_dram_size(ivideo)) {
6071 printk(KERN_INFO "sisfb: Fatal error: Unable to determine VRAM size.\n");
6072 ret = -ENODEV;
6073 goto error_3;
6074 }
6075
6076
6077 /* Enable PCI addressing and MMIO */
Linus Torvalds1da177e2005-04-16 15:20:36 -07006078 if((ivideo->sisfb_mode_idx < 0) ||
6079 ((sisbios_mode[ivideo->sisfb_mode_idx].mode_no[ivideo->mni]) != 0xFF)) {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006080 /* Enable PCI_LINEAR_ADDRESSING and MMIO_ENABLE */
6081 orSISIDXREG(SISSR, IND_SIS_PCI_ADDRESS_SET, (SIS_PCI_ADDR_ENABLE | SIS_MEM_MAP_IO_ENABLE));
6082 /* Enable 2D accelerator engine */
6083 orSISIDXREG(SISSR, IND_SIS_MODULE_ENABLE, SIS_ENABLE_2D);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006084 }
6085
6086 if(sisfb_pdc != 0xff) {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006087 if(ivideo->sisvga_engine == SIS_300_VGA)
6088 sisfb_pdc &= 0x3c;
6089 else
6090 sisfb_pdc &= 0x1f;
6091 ivideo->SiS_Pr.PDC = sisfb_pdc;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006092 }
6093#ifdef CONFIG_FB_SIS_315
6094 if(ivideo->sisvga_engine == SIS_315_VGA) {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006095 if(sisfb_pdca != 0xff)
6096 ivideo->SiS_Pr.PDCA = sisfb_pdca & 0x1f;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006097 }
6098#endif
6099
6100 if(!request_mem_region(ivideo->video_base, ivideo->video_size, "sisfb FB")) {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006101 printk(KERN_ERR "sisfb: Fatal error: Unable to reserve %dMB framebuffer memory\n",
6102 (int)(ivideo->video_size >> 20));
Linus Torvalds1da177e2005-04-16 15:20:36 -07006103 printk(KERN_ERR "sisfb: Is there another framebuffer driver active?\n");
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006104 ret = -ENODEV;
6105 goto error_3;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006106 }
6107
6108 if(!request_mem_region(ivideo->mmio_base, ivideo->mmio_size, "sisfb MMIO")) {
6109 printk(KERN_ERR "sisfb: Fatal error: Unable to reserve MMIO region\n");
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006110 ret = -ENODEV;
6111 goto error_2;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006112 }
6113
6114 ivideo->video_vbase = ioremap(ivideo->video_base, ivideo->video_size);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006115 ivideo->SiS_Pr.VideoMemoryAddress = ivideo->video_vbase;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006116 if(!ivideo->video_vbase) {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006117 printk(KERN_ERR "sisfb: Fatal error: Unable to map framebuffer memory\n");
6118 ret = -ENODEV;
6119 goto error_1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006120 }
6121
6122 ivideo->mmio_vbase = ioremap(ivideo->mmio_base, ivideo->mmio_size);
6123 if(!ivideo->mmio_vbase) {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006124 printk(KERN_ERR "sisfb: Fatal error: Unable to map MMIO region\n");
6125 ret = -ENODEV;
6126error_0: iounmap(ivideo->video_vbase);
6127error_1: release_mem_region(ivideo->video_base, ivideo->video_size);
6128error_2: release_mem_region(ivideo->mmio_base, ivideo->mmio_size);
6129error_3: vfree(ivideo->bios_abase);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006130 if(ivideo->lpcdev)
Adrian Bunk0959f0c2007-05-08 00:39:50 -07006131 pci_dev_put(ivideo->lpcdev);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006132 if(ivideo->nbridge)
Adrian Bunk0959f0c2007-05-08 00:39:50 -07006133 pci_dev_put(ivideo->nbridge);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006134 pci_set_drvdata(pdev, NULL);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006135 if(!ivideo->sisvga_enabled)
6136 pci_disable_device(pdev);
6137 kfree(sis_fb_info);
6138 return ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006139 }
6140
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006141 printk(KERN_INFO "sisfb: Video RAM at 0x%lx, mapped to 0x%lx, size %ldk\n",
6142 ivideo->video_base, (unsigned long)ivideo->video_vbase, ivideo->video_size / 1024);
6143
6144 if(ivideo->video_offset) {
6145 printk(KERN_INFO "sisfb: Viewport offset %ldk\n",
6146 ivideo->video_offset / 1024);
6147 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07006148
6149 printk(KERN_INFO "sisfb: MMIO at 0x%lx, mapped to 0x%lx, size %ldk\n",
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006150 ivideo->mmio_base, (unsigned long)ivideo->mmio_vbase, ivideo->mmio_size / 1024);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006151
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006152
6153 /* Determine the size of the command queue */
6154 if(ivideo->sisvga_engine == SIS_300_VGA) {
6155 ivideo->cmdQueueSize = TURBO_QUEUE_AREA_SIZE;
6156 } else {
6157 if(ivideo->chip == XGI_20) {
6158 ivideo->cmdQueueSize = COMMAND_QUEUE_AREA_SIZE_Z7;
6159 } else {
6160 ivideo->cmdQueueSize = COMMAND_QUEUE_AREA_SIZE;
6161 }
6162 }
6163
6164 /* Engines are no longer initialized here; this is
6165 * now done after the first mode-switch (if the
6166 * submitted var has its acceleration flags set).
6167 */
6168
6169 /* Calculate the base of the (unused) hw cursor */
6170 ivideo->hwcursor_vbase = ivideo->video_vbase
6171 + ivideo->video_size
6172 - ivideo->cmdQueueSize
6173 - ivideo->hwcursor_size;
6174 ivideo->caps |= HW_CURSOR_CAP;
6175
6176 /* Initialize offscreen memory manager */
Linus Torvalds1da177e2005-04-16 15:20:36 -07006177 if((ivideo->havenoheap = sisfb_heap_init(ivideo))) {
6178 printk(KERN_WARNING "sisfb: Failed to initialize offscreen memory heap\n");
6179 }
6180
6181 /* Used for clearing the screen only, therefore respect our mem limit */
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006182 ivideo->SiS_Pr.VideoMemoryAddress += ivideo->video_offset;
6183 ivideo->SiS_Pr.VideoMemorySize = ivideo->sisfb_mem;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006184
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006185 ivideo->mtrr = -1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006186
6187 ivideo->vbflags = 0;
6188 ivideo->lcddefmodeidx = DEFAULT_LCDMODE;
6189 ivideo->tvdefmodeidx = DEFAULT_TVMODE;
6190 ivideo->defmodeidx = DEFAULT_MODE;
6191
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006192 ivideo->newrom = 0;
6193 if(ivideo->chip < XGI_20) {
6194 if(ivideo->bios_abase) {
6195 ivideo->newrom = SiSDetermineROMLayout661(&ivideo->SiS_Pr);
6196 }
6197 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07006198
6199 if((ivideo->sisfb_mode_idx < 0) ||
6200 ((sisbios_mode[ivideo->sisfb_mode_idx].mode_no[ivideo->mni]) != 0xFF)) {
6201
6202 sisfb_sense_crt1(ivideo);
6203
6204 sisfb_get_VB_type(ivideo);
6205
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006206 if(ivideo->vbflags2 & VB2_VIDEOBRIDGE) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07006207 sisfb_detect_VB_connect(ivideo);
6208 }
6209
6210 ivideo->currentvbflags = ivideo->vbflags & (VB_VIDEOBRIDGE | TV_STANDARD);
6211
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006212 /* Decide on which CRT2 device to use */
6213 if(ivideo->vbflags2 & VB2_VIDEOBRIDGE) {
6214 if(ivideo->sisfb_crt2type != -1) {
6215 if((ivideo->sisfb_crt2type == CRT2_LCD) &&
6216 (ivideo->vbflags & CRT2_LCD)) {
6217 ivideo->currentvbflags |= CRT2_LCD;
6218 } else if(ivideo->sisfb_crt2type != CRT2_LCD) {
6219 ivideo->currentvbflags |= ivideo->sisfb_crt2type;
6220 }
6221 } else {
6222 /* Chrontel 700x TV detection often unreliable, therefore
6223 * use a different default order on such machines
6224 */
6225 if((ivideo->sisvga_engine == SIS_300_VGA) &&
6226 (ivideo->vbflags2 & VB2_CHRONTEL)) {
6227 if(ivideo->vbflags & CRT2_LCD)
6228 ivideo->currentvbflags |= CRT2_LCD;
6229 else if(ivideo->vbflags & CRT2_TV)
6230 ivideo->currentvbflags |= CRT2_TV;
6231 else if(ivideo->vbflags & CRT2_VGA)
6232 ivideo->currentvbflags |= CRT2_VGA;
6233 } else {
6234 if(ivideo->vbflags & CRT2_TV)
6235 ivideo->currentvbflags |= CRT2_TV;
6236 else if(ivideo->vbflags & CRT2_LCD)
6237 ivideo->currentvbflags |= CRT2_LCD;
6238 else if(ivideo->vbflags & CRT2_VGA)
6239 ivideo->currentvbflags |= CRT2_VGA;
6240 }
6241 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07006242 }
6243
6244 if(ivideo->vbflags & CRT2_LCD) {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006245 sisfb_detect_lcd_type(ivideo);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006246 }
6247
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006248 sisfb_save_pdc_emi(ivideo);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006249
6250 if(!ivideo->sisfb_crt1off) {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006251 sisfb_handle_ddc(ivideo, &ivideo->sisfb_thismonitor, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006252 } else {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006253 if((ivideo->vbflags2 & VB2_SISTMDSBRIDGE) &&
6254 (ivideo->vbflags & (CRT2_VGA | CRT2_LCD))) {
6255 sisfb_handle_ddc(ivideo, &ivideo->sisfb_thismonitor, 1);
6256 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07006257 }
6258
6259 if(ivideo->sisfb_mode_idx >= 0) {
6260 int bu = ivideo->sisfb_mode_idx;
6261 ivideo->sisfb_mode_idx = sisfb_validate_mode(ivideo,
6262 ivideo->sisfb_mode_idx, ivideo->currentvbflags);
6263 if(bu != ivideo->sisfb_mode_idx) {
6264 printk(KERN_ERR "Mode %dx%dx%d failed validation\n",
6265 sisbios_mode[bu].xres,
6266 sisbios_mode[bu].yres,
6267 sisbios_mode[bu].bpp);
6268 }
6269 }
6270
6271 if(ivideo->sisfb_mode_idx < 0) {
6272 switch(ivideo->currentvbflags & VB_DISPTYPE_DISP2) {
6273 case CRT2_LCD:
6274 ivideo->sisfb_mode_idx = ivideo->lcddefmodeidx;
6275 break;
6276 case CRT2_TV:
6277 ivideo->sisfb_mode_idx = ivideo->tvdefmodeidx;
6278 break;
6279 default:
6280 ivideo->sisfb_mode_idx = ivideo->defmodeidx;
6281 break;
6282 }
6283 }
6284
6285 ivideo->mode_no = sisbios_mode[ivideo->sisfb_mode_idx].mode_no[ivideo->mni];
6286
6287 if(ivideo->refresh_rate != 0) {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006288 sisfb_search_refresh_rate(ivideo, ivideo->refresh_rate,
6289 ivideo->sisfb_mode_idx);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006290 }
6291
6292 if(ivideo->rate_idx == 0) {
6293 ivideo->rate_idx = sisbios_mode[ivideo->sisfb_mode_idx].rate_idx;
6294 ivideo->refresh_rate = 60;
6295 }
6296
6297 if(ivideo->sisfb_thismonitor.datavalid) {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006298 if(!sisfb_verify_rate(ivideo, &ivideo->sisfb_thismonitor,
6299 ivideo->sisfb_mode_idx,
6300 ivideo->rate_idx,
6301 ivideo->refresh_rate)) {
6302 printk(KERN_INFO "sisfb: WARNING: Refresh rate "
6303 "exceeds monitor specs!\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07006304 }
6305 }
6306
6307 ivideo->video_bpp = sisbios_mode[ivideo->sisfb_mode_idx].bpp;
6308 ivideo->video_width = sisbios_mode[ivideo->sisfb_mode_idx].xres;
6309 ivideo->video_height = sisbios_mode[ivideo->sisfb_mode_idx].yres;
6310
6311 sisfb_set_vparms(ivideo);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006312
Linus Torvalds1da177e2005-04-16 15:20:36 -07006313 printk(KERN_INFO "sisfb: Default mode is %dx%dx%d (%dHz)\n",
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006314 ivideo->video_width, ivideo->video_height, ivideo->video_bpp,
Linus Torvalds1da177e2005-04-16 15:20:36 -07006315 ivideo->refresh_rate);
6316
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006317 /* Set up the default var according to chosen default display mode */
Linus Torvalds1da177e2005-04-16 15:20:36 -07006318 ivideo->default_var.xres = ivideo->default_var.xres_virtual = ivideo->video_width;
6319 ivideo->default_var.yres = ivideo->default_var.yres_virtual = ivideo->video_height;
6320 ivideo->default_var.bits_per_pixel = ivideo->video_bpp;
6321
6322 sisfb_bpp_to_var(ivideo, &ivideo->default_var);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006323
Linus Torvalds1da177e2005-04-16 15:20:36 -07006324 ivideo->default_var.pixclock = (u32) (1000000000 /
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006325 sisfb_mode_rate_to_dclock(&ivideo->SiS_Pr, ivideo->mode_no, ivideo->rate_idx));
6326
6327 if(sisfb_mode_rate_to_ddata(&ivideo->SiS_Pr, ivideo->mode_no,
6328 ivideo->rate_idx, &ivideo->default_var)) {
6329 if((ivideo->default_var.vmode & FB_VMODE_MASK) == FB_VMODE_DOUBLE) {
6330 ivideo->default_var.pixclock <<= 1;
6331 }
6332 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07006333
6334 if(ivideo->sisfb_ypan) {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006335 /* Maximize regardless of sisfb_max at startup */
6336 ivideo->default_var.yres_virtual =
6337 sisfb_calc_maxyres(ivideo, &ivideo->default_var);
6338 if(ivideo->default_var.yres_virtual < ivideo->default_var.yres) {
6339 ivideo->default_var.yres_virtual = ivideo->default_var.yres;
6340 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07006341 }
6342
6343 sisfb_calc_pitch(ivideo, &ivideo->default_var);
6344
6345 ivideo->accel = 0;
6346 if(ivideo->sisfb_accel) {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006347 ivideo->accel = -1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006348#ifdef STUPID_ACCELF_TEXT_SHIT
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006349 ivideo->default_var.accel_flags |= FB_ACCELF_TEXT;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006350#endif
6351 }
6352 sisfb_initaccel(ivideo);
6353
6354#if defined(FBINFO_HWACCEL_DISABLED) && defined(FBINFO_HWACCEL_XPAN)
6355 sis_fb_info->flags = FBINFO_DEFAULT |
6356 FBINFO_HWACCEL_YPAN |
6357 FBINFO_HWACCEL_XPAN |
6358 FBINFO_HWACCEL_COPYAREA |
6359 FBINFO_HWACCEL_FILLRECT |
6360 ((ivideo->accel) ? 0 : FBINFO_HWACCEL_DISABLED);
6361#else
6362 sis_fb_info->flags = FBINFO_FLAG_DEFAULT;
6363#endif
6364 sis_fb_info->var = ivideo->default_var;
6365 sis_fb_info->fix = ivideo->sisfb_fix;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006366 sis_fb_info->screen_base = ivideo->video_vbase + ivideo->video_offset;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006367 sis_fb_info->fbops = &sisfb_ops;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006368 sisfb_get_fix(&sis_fb_info->fix, -1, sis_fb_info);
6369 sis_fb_info->pseudo_palette = ivideo->pseudo_palette;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006370
Linus Torvalds1da177e2005-04-16 15:20:36 -07006371 fb_alloc_cmap(&sis_fb_info->cmap, 256 , 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006372
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006373 printk(KERN_DEBUG "sisfb: Initial vbflags 0x%x\n", (int)ivideo->vbflags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006374
6375#ifdef CONFIG_MTRR
6376 ivideo->mtrr = mtrr_add(ivideo->video_base, ivideo->video_size,
6377 MTRR_TYPE_WRCOMB, 1);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006378 if(ivideo->mtrr < 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07006379 printk(KERN_DEBUG "sisfb: Failed to add MTRRs\n");
6380 }
6381#endif
6382
Linus Torvalds1da177e2005-04-16 15:20:36 -07006383 if(register_framebuffer(sis_fb_info) < 0) {
6384 printk(KERN_ERR "sisfb: Fatal error: Failed to register framebuffer\n");
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006385 ret = -EINVAL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006386 iounmap(ivideo->mmio_vbase);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006387 goto error_0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006388 }
6389
6390 ivideo->registered = 1;
6391
6392 /* Enlist us */
6393 ivideo->next = card_list;
6394 card_list = ivideo;
6395
6396 printk(KERN_INFO "sisfb: 2D acceleration is %s, y-panning %s\n",
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006397 ivideo->sisfb_accel ? "enabled" : "disabled",
6398 ivideo->sisfb_ypan ?
6399 (ivideo->sisfb_max ? "enabled (auto-max)" :
6400 "enabled (no auto-max)") :
6401 "disabled");
Linus Torvalds1da177e2005-04-16 15:20:36 -07006402
6403
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006404 printk(KERN_INFO "fb%d: %s frame buffer device version %d.%d.%d\n",
Michal Piotrowski43704092006-10-03 01:15:00 -07006405 sis_fb_info->node, ivideo->myid, VER_MAJOR, VER_MINOR, VER_LEVEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006406
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006407 printk(KERN_INFO "sisfb: Copyright (C) 2001-2005 Thomas Winischhofer\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07006408
6409 } /* if mode = "none" */
6410
6411 return 0;
6412}
6413
6414/*****************************************************/
6415/* PCI DEVICE HANDLING */
6416/*****************************************************/
6417
6418static void __devexit sisfb_remove(struct pci_dev *pdev)
6419{
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006420 struct sis_video_info *ivideo = pci_get_drvdata(pdev);
6421 struct fb_info *sis_fb_info = ivideo->memyselfandi;
6422 int registered = ivideo->registered;
6423 int modechanged = ivideo->modechanged;
6424
Linus Torvalds1da177e2005-04-16 15:20:36 -07006425 /* Unmap */
Linus Torvalds1da177e2005-04-16 15:20:36 -07006426 iounmap(ivideo->mmio_vbase);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006427 iounmap(ivideo->video_vbase);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006428
6429 /* Release mem regions */
6430 release_mem_region(ivideo->video_base, ivideo->video_size);
6431 release_mem_region(ivideo->mmio_base, ivideo->mmio_size);
6432
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006433 vfree(ivideo->bios_abase);
6434
6435 if(ivideo->lpcdev)
Adrian Bunk0959f0c2007-05-08 00:39:50 -07006436 pci_dev_put(ivideo->lpcdev);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006437
6438 if(ivideo->nbridge)
Adrian Bunk0959f0c2007-05-08 00:39:50 -07006439 pci_dev_put(ivideo->nbridge);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006440
Linus Torvalds1da177e2005-04-16 15:20:36 -07006441#ifdef CONFIG_MTRR
6442 /* Release MTRR region */
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006443 if(ivideo->mtrr >= 0)
Linus Torvalds1da177e2005-04-16 15:20:36 -07006444 mtrr_del(ivideo->mtrr, ivideo->video_base, ivideo->video_size);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006445#endif
6446
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006447 pci_set_drvdata(pdev, NULL);
6448
6449 /* If device was disabled when starting, disable
6450 * it when quitting.
6451 */
6452 if(!ivideo->sisvga_enabled)
6453 pci_disable_device(pdev);
6454
Linus Torvalds1da177e2005-04-16 15:20:36 -07006455 /* Unregister the framebuffer */
6456 if(ivideo->registered) {
6457 unregister_framebuffer(sis_fb_info);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006458 framebuffer_release(sis_fb_info);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006459 }
6460
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006461 /* OK, our ivideo is gone for good from here. */
Linus Torvalds1da177e2005-04-16 15:20:36 -07006462
6463 /* TODO: Restore the initial mode
6464 * This sounds easy but is as good as impossible
6465 * on many machines with SiS chip and video bridge
6466 * since text modes are always set up differently
6467 * from machine to machine. Depends on the type
6468 * of integration between chipset and bridge.
6469 */
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006470 if(registered && modechanged)
6471 printk(KERN_INFO
6472 "sisfb: Restoring of text mode not supported yet\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07006473};
6474
6475static struct pci_driver sisfb_driver = {
6476 .name = "sisfb",
6477 .id_table = sisfb_pci_table,
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006478 .probe = sisfb_probe,
Linus Torvalds1da177e2005-04-16 15:20:36 -07006479 .remove = __devexit_p(sisfb_remove)
6480};
6481
Adrian Bunk14aefd12008-07-23 21:31:12 -07006482static int __init sisfb_init(void)
Linus Torvalds1da177e2005-04-16 15:20:36 -07006483{
Linus Torvalds1da177e2005-04-16 15:20:36 -07006484#ifndef MODULE
6485 char *options = NULL;
6486
6487 if(fb_get_options("sisfb", &options))
6488 return -ENODEV;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006489
Linus Torvalds1da177e2005-04-16 15:20:36 -07006490 sisfb_setup(options);
6491#endif
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006492 return pci_register_driver(&sisfb_driver);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006493}
6494
Linus Torvalds1da177e2005-04-16 15:20:36 -07006495#ifndef MODULE
6496module_init(sisfb_init);
6497#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -07006498
6499/*****************************************************/
6500/* MODULE */
6501/*****************************************************/
6502
6503#ifdef MODULE
6504
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006505static char *mode = NULL;
6506static int vesa = -1;
6507static unsigned int rate = 0;
6508static unsigned int crt1off = 1;
6509static unsigned int mem = 0;
6510static char *forcecrt2type = NULL;
6511static int forcecrt1 = -1;
6512static int pdc = -1;
6513static int pdc1 = -1;
6514static int noaccel = -1;
6515static int noypan = -1;
6516static int nomax = -1;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006517static int userom = -1;
6518static int useoem = -1;
6519static char *tvstandard = NULL;
6520static int nocrt2rate = 0;
6521static int scalelcd = -1;
6522static char *specialtiming = NULL;
6523static int lvdshl = -1;
6524static int tvxposoffset = 0, tvyposoffset = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006525#if !defined(__i386__) && !defined(__x86_64__)
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006526static int resetcard = 0;
6527static int videoram = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006528#endif
6529
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006530static int __init sisfb_init_module(void)
6531{
6532 sisfb_setdefaultparms();
6533
6534 if(rate)
6535 sisfb_parm_rate = rate;
6536
6537 if((scalelcd == 0) || (scalelcd == 1))
6538 sisfb_scalelcd = scalelcd ^ 1;
6539
6540 /* Need to check crt2 type first for fstn/dstn */
6541
6542 if(forcecrt2type)
6543 sisfb_search_crt2type(forcecrt2type);
6544
6545 if(tvstandard)
6546 sisfb_search_tvstd(tvstandard);
6547
6548 if(mode)
Richard Knutssonc30660e2007-02-12 00:55:06 -08006549 sisfb_search_mode(mode, false);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006550 else if(vesa != -1)
Richard Knutssonc30660e2007-02-12 00:55:06 -08006551 sisfb_search_vesamode(vesa, false);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006552
6553 sisfb_crt1off = (crt1off == 0) ? 1 : 0;
6554
6555 sisfb_forcecrt1 = forcecrt1;
6556 if(forcecrt1 == 1)
6557 sisfb_crt1off = 0;
6558 else if(forcecrt1 == 0)
6559 sisfb_crt1off = 1;
6560
6561 if(noaccel == 1)
6562 sisfb_accel = 0;
6563 else if(noaccel == 0)
6564 sisfb_accel = 1;
6565
6566 if(noypan == 1)
6567 sisfb_ypan = 0;
6568 else if(noypan == 0)
6569 sisfb_ypan = 1;
6570
6571 if(nomax == 1)
6572 sisfb_max = 0;
6573 else if(nomax == 0)
6574 sisfb_max = 1;
6575
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006576 if(mem)
6577 sisfb_parm_mem = mem;
6578
6579 if(userom != -1)
6580 sisfb_userom = userom;
6581
6582 if(useoem != -1)
6583 sisfb_useoem = useoem;
6584
6585 if(pdc != -1)
6586 sisfb_pdc = (pdc & 0x7f);
6587
6588 if(pdc1 != -1)
6589 sisfb_pdca = (pdc1 & 0x1f);
6590
6591 sisfb_nocrt2rate = nocrt2rate;
6592
6593 if(specialtiming)
6594 sisfb_search_specialtiming(specialtiming);
6595
6596 if((lvdshl >= 0) && (lvdshl <= 3))
6597 sisfb_lvdshl = lvdshl;
6598
6599 sisfb_tvxposoffset = tvxposoffset;
6600 sisfb_tvyposoffset = tvyposoffset;
6601
6602#if !defined(__i386__) && !defined(__x86_64__)
6603 sisfb_resetcard = (resetcard) ? 1 : 0;
6604 if(videoram)
6605 sisfb_videoram = videoram;
6606#endif
6607
6608 return sisfb_init();
6609}
6610
6611static void __exit sisfb_remove_module(void)
6612{
6613 pci_unregister_driver(&sisfb_driver);
6614 printk(KERN_DEBUG "sisfb: Module unloaded\n");
6615}
6616
6617module_init(sisfb_init_module);
6618module_exit(sisfb_remove_module);
6619
6620MODULE_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 -07006621MODULE_LICENSE("GPL");
6622MODULE_AUTHOR("Thomas Winischhofer <thomas@winischhofer.net>, Others");
6623
Linus Torvalds1da177e2005-04-16 15:20:36 -07006624module_param(mem, int, 0);
6625module_param(noaccel, int, 0);
6626module_param(noypan, int, 0);
6627module_param(nomax, int, 0);
6628module_param(userom, int, 0);
6629module_param(useoem, int, 0);
6630module_param(mode, charp, 0);
6631module_param(vesa, int, 0);
6632module_param(rate, int, 0);
6633module_param(forcecrt1, int, 0);
6634module_param(forcecrt2type, charp, 0);
6635module_param(scalelcd, int, 0);
6636module_param(pdc, int, 0);
6637module_param(pdc1, int, 0);
6638module_param(specialtiming, charp, 0);
6639module_param(lvdshl, int, 0);
6640module_param(tvstandard, charp, 0);
6641module_param(tvxposoffset, int, 0);
6642module_param(tvyposoffset, int, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006643module_param(nocrt2rate, int, 0);
6644#if !defined(__i386__) && !defined(__x86_64__)
6645module_param(resetcard, int, 0);
6646module_param(videoram, int, 0);
6647#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -07006648
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006649MODULE_PARM_DESC(mem,
6650 "\nDetermines the beginning of the video memory heap in KB. This heap is used\n"
6651 "for video RAM management for eg. DRM/DRI. On 300 series, the default depends\n"
6652 "on the amount of video RAM available. If 8MB of video RAM or less is available,\n"
6653 "the heap starts at 4096KB, if between 8 and 16MB are available at 8192KB,\n"
6654 "otherwise at 12288KB. On 315/330/340 series, the heap size is 32KB by default.\n"
6655 "The value is to be specified without 'KB'.\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07006656
6657MODULE_PARM_DESC(noaccel,
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006658 "\nIf set to anything other than 0, 2D acceleration will be disabled.\n"
Linus Torvalds1da177e2005-04-16 15:20:36 -07006659 "(default: 0)\n");
6660
6661MODULE_PARM_DESC(noypan,
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006662 "\nIf set to anything other than 0, y-panning will be disabled and scrolling\n"
6663 "will be performed by redrawing the screen. (default: 0)\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07006664
6665MODULE_PARM_DESC(nomax,
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006666 "\nIf y-panning is enabled, sisfb will by default use the entire available video\n"
Linus Torvalds1da177e2005-04-16 15:20:36 -07006667 "memory for the virtual screen in order to optimize scrolling performance. If\n"
6668 "this is set to anything other than 0, sisfb will not do this and thereby \n"
6669 "enable the user to positively specify a virtual Y size of the screen using\n"
6670 "fbset. (default: 0)\n");
6671
Linus Torvalds1da177e2005-04-16 15:20:36 -07006672MODULE_PARM_DESC(mode,
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006673 "\nSelects the desired default display mode in the format XxYxDepth,\n"
6674 "eg. 1024x768x16. Other formats supported include XxY-Depth and\n"
Linus Torvalds1da177e2005-04-16 15:20:36 -07006675 "XxY-Depth@Rate. If the parameter is only one (decimal or hexadecimal)\n"
6676 "number, it will be interpreted as a VESA mode number. (default: 800x600x8)\n");
6677
6678MODULE_PARM_DESC(vesa,
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006679 "\nSelects the desired default display mode by VESA defined mode number, eg.\n"
6680 "0x117 (default: 0x0103)\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07006681
6682MODULE_PARM_DESC(rate,
6683 "\nSelects the desired vertical refresh rate for CRT1 (external VGA) in Hz.\n"
6684 "If the mode is specified in the format XxY-Depth@Rate, this parameter\n"
6685 "will be ignored (default: 60)\n");
6686
6687MODULE_PARM_DESC(forcecrt1,
6688 "\nNormally, the driver autodetects whether or not CRT1 (external VGA) is \n"
6689 "connected. With this option, the detection can be overridden (1=CRT1 ON,\n"
6690 "0=CRT1 OFF) (default: [autodetected])\n");
6691
6692MODULE_PARM_DESC(forcecrt2type,
6693 "\nIf this option is omitted, the driver autodetects CRT2 output devices, such as\n"
6694 "LCD, TV or secondary VGA. With this option, this autodetection can be\n"
6695 "overridden. Possible parameters are LCD, TV, VGA or NONE. NONE disables CRT2.\n"
6696 "On systems with a SiS video bridge, parameters SVIDEO, COMPOSITE or SCART can\n"
6697 "be used instead of TV to override the TV detection. Furthermore, on systems\n"
6698 "with a SiS video bridge, SVIDEO+COMPOSITE, HIVISION, YPBPR480I, YPBPR480P,\n"
6699 "YPBPR720P and YPBPR1080I are understood. However, whether or not these work\n"
6700 "depends on the very hardware in use. (default: [autodetected])\n");
6701
6702MODULE_PARM_DESC(scalelcd,
6703 "\nSetting this to 1 will force the driver to scale the LCD image to the panel's\n"
6704 "native resolution. Setting it to 0 will disable scaling; LVDS panels will\n"
6705 "show black bars around the image, TMDS panels will probably do the scaling\n"
6706 "themselves. Default: 1 on LVDS panels, 0 on TMDS panels\n");
6707
6708MODULE_PARM_DESC(pdc,
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006709 "\nThis is for manually selecting the LCD panel delay compensation. The driver\n"
Linus Torvalds1da177e2005-04-16 15:20:36 -07006710 "should detect this correctly in most cases; however, sometimes this is not\n"
6711 "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 -07006712 "on a 300 series chipset; 6 on other chipsets. If the problem persists, try\n"
6713 "other values (on 300 series: between 4 and 60 in steps of 4; otherwise: any\n"
6714 "value from 0 to 31). (default: autodetected, if LCD is active during start)\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07006715
6716#ifdef CONFIG_FB_SIS_315
6717MODULE_PARM_DESC(pdc1,
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006718 "\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 -07006719 "series only. (default: autodetected if LCD is in LCD-via-CRT1 mode during\n"
6720 "startup) - Note: currently, this has no effect because LCD-via-CRT1 is not\n"
6721 "implemented yet.\n");
6722#endif
6723
6724MODULE_PARM_DESC(specialtiming,
6725 "\nPlease refer to documentation for more information on this option.\n");
6726
6727MODULE_PARM_DESC(lvdshl,
6728 "\nPlease refer to documentation for more information on this option.\n");
6729
6730MODULE_PARM_DESC(tvstandard,
6731 "\nThis allows overriding the BIOS default for the TV standard. Valid choices are\n"
6732 "pal, ntsc, palm and paln. (default: [auto; pal or ntsc only])\n");
6733
6734MODULE_PARM_DESC(tvxposoffset,
6735 "\nRelocate TV output horizontally. Possible parameters: -32 through 32.\n"
6736 "Default: 0\n");
6737
6738MODULE_PARM_DESC(tvyposoffset,
6739 "\nRelocate TV output vertically. Possible parameters: -32 through 32.\n"
6740 "Default: 0\n");
6741
Linus Torvalds1da177e2005-04-16 15:20:36 -07006742MODULE_PARM_DESC(nocrt2rate,
6743 "\nSetting this to 1 will force the driver to use the default refresh rate for\n"
6744 "CRT2 if CRT2 type is VGA. (default: 0, use same rate as CRT1)\n");
6745
Linus Torvalds1da177e2005-04-16 15:20:36 -07006746#if !defined(__i386__) && !defined(__x86_64__)
6747#ifdef CONFIG_FB_SIS_300
6748MODULE_PARM_DESC(resetcard,
6749 "\nSet this to 1 in order to reset (POST) the card on non-x86 machines where\n"
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006750 "the BIOS did not POST the card (only supported for SiS 300/305 and XGI cards\n"
6751 "currently). Default: 0\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07006752
6753MODULE_PARM_DESC(videoram,
6754 "\nSet this to the amount of video RAM (in kilobyte) the card has. Required on\n"
6755 "some non-x86 architectures where the memory auto detection fails. Only\n"
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006756 "relevant if resetcard is set, too. SiS300/305 only. Default: [auto-detect]\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07006757#endif
6758#endif
6759
Linus Torvalds1da177e2005-04-16 15:20:36 -07006760#endif /* /MODULE */
6761
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006762/* _GPL only for new symbols. */
Linus Torvalds1da177e2005-04-16 15:20:36 -07006763EXPORT_SYMBOL(sis_malloc);
6764EXPORT_SYMBOL(sis_free);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006765EXPORT_SYMBOL_GPL(sis_malloc_new);
6766EXPORT_SYMBOL_GPL(sis_free_new);
6767
Linus Torvalds1da177e2005-04-16 15:20:36 -07006768
6769