blob: b52f8e4ef1fdbe3cd19c70d4fb282d15f5b99f85 [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 Knutssonc30660ea2007-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 Knutssonc30660ea2007-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 Knutssonc30660ea2007-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 Knutssonc30660ea2007-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 Knutssonc30660ea2007-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 Knutssonc30660ea2007-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 Knutssonc30660ea2007-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 Knutssonc30660ea2007-02-12 00:55:06 -0800381 footprint = false;
Thomas Winischhofer544393f2005-09-09 13:04:45 -0700382 }
383 } else
Richard Knutssonc30660ea2007-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 Knutssonc30660ea2007-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 Knutssonc30660ea2007-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 Knutssonc30660ea2007-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 Knutssonc30660ea2007-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 Knutssonc30660ea2007-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 Knutssonc30660ea2007-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 Knutssonc30660ea2007-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 Knutssonc30660ea2007-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 Knutssonc30660ea2007-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 Knutssonc30660ea2007-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 Knutssonc30660ea2007-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 Knutssonc30660ea2007-02-12 00:55:06 -0800591 return false;
Thomas Winischhofer544393f2005-09-09 13:04:45 -0700592 if(rate > (monitor->vmax + 1))
Richard Knutssonc30660ea2007-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 Knutssonc30660ea2007-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 Knutssonc30660ea2007-02-12 00:55:06 -0800603 return false;
Thomas Winischhofer544393f2005-09-09 13:04:45 -0700604 if(hsync > (monitor->hmax + 1))
Richard Knutssonc30660ea2007-02-12 00:55:06 -0800605 return false;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700606 } else {
Richard Knutssonc30660ea2007-02-12 00:55:06 -0800607 return false;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700608 }
Richard Knutssonc30660ea2007-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;
Roel Kluind63870d2009-09-22 16:47:07 -0700701 } else if((sisfb_vrate[i].idx != 1) &&
702 ((rate - sisfb_vrate[i-1].refresh) <= 2)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700703 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 Knutssonc30660ea2007-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 Knutssonc30660ea2007-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 Knutssonc30660ea2007-02-12 00:55:06 -0800738 return true;
Thomas Winischhofer544393f2005-09-09 13:04:45 -0700739 } else {
Richard Knutssonc30660ea2007-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 Knutssonc30660ea2007-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 Knutssonc30660ea2007-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 Knutssonc30660ea2007-02-12 00:55:06 -0800755 return false;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700756
Richard Knutssonc30660ea2007-02-12 00:55:06 -0800757 return true;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700758}
759
Richard Knutssonc30660ea2007-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 Knutssonc30660ea2007-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 Knutssonc30660ea2007-02-12 00:55:06 -0800767 return true;
Thomas Winischhofer544393f2005-09-09 13:04:45 -0700768 else
Richard Knutssonc30660ea2007-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 Knutssonc30660ea2007-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 Knutssonc30660ea2007-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 Knutssonc30660ea2007-02-12 00:55:06 -0800799 return true;
Thomas Winischhofer544393f2005-09-09 13:04:45 -0700800 else
Richard Knutssonc30660ea2007-02-12 00:55:06 -0800801 return false;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700802}
803
Richard Knutssonc30660ea2007-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 Knutssonc30660ea2007-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 Knutssonc30660ea2007-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 Knutssonc30660ea2007-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 Knutssonc30660ea2007-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 Knutssonc30660ea2007-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 Knutssonc30660ea2007-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 Knutssonc30660ea2007-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 Knutssonc30660ea2007-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;
Michal Januszewski811a2012009-04-13 14:39:52 -07001132 var->red.length = var->green.length = var->blue.length = 8;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001133 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 Knutssonc30660ea2007-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 Knutssonc30660ea2007-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 Knutssonc30660ea2007-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 Knutssonc30660ea2007-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 Knutssonc30660ea2007-02-12 00:55:06 -08001547 recalc_clock = true;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001548 } else {
1549 refresh_rate = 60;
Richard Knutssonc30660ea2007-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:
Dan Rosenbergfd02db92010-09-22 13:05:09 -07001704
1705 memset(&sisvbblank, 0, sizeof(struct fb_vblank));
1706
Linus Torvalds1da177e2005-04-16 15:20:36 -07001707 sisvbblank.count = 0;
1708 sisvbblank.flags = sisfb_setupvbblankflags(ivideo, &sisvbblank.vcount, &sisvbblank.hcount);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001709
1710 if(copy_to_user((void __user *)arg, &sisvbblank, sizeof(sisvbblank)))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001711 return -EFAULT;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001712
Linus Torvalds1da177e2005-04-16 15:20:36 -07001713 break;
1714
1715 case SISFB_GET_INFO_SIZE:
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001716 return put_user(sizeof(struct sisfb_info), argp);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001717
1718 case SISFB_GET_INFO_OLD:
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001719 if(ivideo->warncount++ < 10)
1720 printk(KERN_INFO
1721 "sisfb: Deprecated ioctl call received - update your application!\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001722 case SISFB_GET_INFO: /* For communication with X driver */
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001723 ivideo->sisfb_infoblock.sisfb_id = SISFB_ID;
1724 ivideo->sisfb_infoblock.sisfb_version = VER_MAJOR;
1725 ivideo->sisfb_infoblock.sisfb_revision = VER_MINOR;
1726 ivideo->sisfb_infoblock.sisfb_patchlevel = VER_LEVEL;
1727 ivideo->sisfb_infoblock.chip_id = ivideo->chip_id;
1728 ivideo->sisfb_infoblock.sisfb_pci_vendor = ivideo->chip_vendor;
1729 ivideo->sisfb_infoblock.memory = ivideo->video_size / 1024;
1730 ivideo->sisfb_infoblock.heapstart = ivideo->heapstart / 1024;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001731 if(ivideo->modechanged) {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001732 ivideo->sisfb_infoblock.fbvidmode = ivideo->mode_no;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001733 } else {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001734 ivideo->sisfb_infoblock.fbvidmode = ivideo->modeprechange;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001735 }
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001736 ivideo->sisfb_infoblock.sisfb_caps = ivideo->caps;
1737 ivideo->sisfb_infoblock.sisfb_tqlen = ivideo->cmdQueueSize / 1024;
1738 ivideo->sisfb_infoblock.sisfb_pcibus = ivideo->pcibus;
1739 ivideo->sisfb_infoblock.sisfb_pcislot = ivideo->pcislot;
1740 ivideo->sisfb_infoblock.sisfb_pcifunc = ivideo->pcifunc;
1741 ivideo->sisfb_infoblock.sisfb_lcdpdc = ivideo->detectedpdc;
1742 ivideo->sisfb_infoblock.sisfb_lcdpdca = ivideo->detectedpdca;
1743 ivideo->sisfb_infoblock.sisfb_lcda = ivideo->detectedlcda;
1744 ivideo->sisfb_infoblock.sisfb_vbflags = ivideo->vbflags;
1745 ivideo->sisfb_infoblock.sisfb_currentvbflags = ivideo->currentvbflags;
1746 ivideo->sisfb_infoblock.sisfb_scalelcd = ivideo->SiS_Pr.UsePanelScaler;
1747 ivideo->sisfb_infoblock.sisfb_specialtiming = ivideo->SiS_Pr.SiS_CustomT;
1748 ivideo->sisfb_infoblock.sisfb_haveemi = ivideo->SiS_Pr.HaveEMI ? 1 : 0;
1749 ivideo->sisfb_infoblock.sisfb_haveemilcd = ivideo->SiS_Pr.HaveEMILCD ? 1 : 0;
1750 ivideo->sisfb_infoblock.sisfb_emi30 = ivideo->SiS_Pr.EMI_30;
1751 ivideo->sisfb_infoblock.sisfb_emi31 = ivideo->SiS_Pr.EMI_31;
1752 ivideo->sisfb_infoblock.sisfb_emi32 = ivideo->SiS_Pr.EMI_32;
1753 ivideo->sisfb_infoblock.sisfb_emi33 = ivideo->SiS_Pr.EMI_33;
1754 ivideo->sisfb_infoblock.sisfb_tvxpos = (u16)(ivideo->tvxpos + 32);
1755 ivideo->sisfb_infoblock.sisfb_tvypos = (u16)(ivideo->tvypos + 32);
1756 ivideo->sisfb_infoblock.sisfb_heapsize = ivideo->sisfb_heap_size / 1024;
1757 ivideo->sisfb_infoblock.sisfb_videooffset = ivideo->video_offset;
1758 ivideo->sisfb_infoblock.sisfb_curfstn = ivideo->curFSTN;
1759 ivideo->sisfb_infoblock.sisfb_curdstn = ivideo->curDSTN;
1760 ivideo->sisfb_infoblock.sisfb_vbflags2 = ivideo->vbflags2;
1761 ivideo->sisfb_infoblock.sisfb_can_post = ivideo->sisfb_can_post ? 1 : 0;
1762 ivideo->sisfb_infoblock.sisfb_card_posted = ivideo->sisfb_card_posted ? 1 : 0;
1763 ivideo->sisfb_infoblock.sisfb_was_boot_device = ivideo->sisfb_was_boot_device ? 1 : 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001764
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001765 if(copy_to_user((void __user *)arg, &ivideo->sisfb_infoblock,
1766 sizeof(ivideo->sisfb_infoblock)))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001767 return -EFAULT;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001768
Linus Torvalds1da177e2005-04-16 15:20:36 -07001769 break;
1770
1771 case SISFB_GET_VBRSTATUS_OLD:
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001772 if(ivideo->warncount++ < 10)
1773 printk(KERN_INFO
1774 "sisfb: Deprecated ioctl call received - update your application!\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001775 case SISFB_GET_VBRSTATUS:
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001776 if(sisfb_CheckVBRetrace(ivideo))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001777 return put_user((u32)1, argp);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001778 else
Linus Torvalds1da177e2005-04-16 15:20:36 -07001779 return put_user((u32)0, argp);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001780
1781 case SISFB_GET_AUTOMAXIMIZE_OLD:
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001782 if(ivideo->warncount++ < 10)
1783 printk(KERN_INFO
1784 "sisfb: Deprecated ioctl call received - update your application!\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001785 case SISFB_GET_AUTOMAXIMIZE:
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001786 if(ivideo->sisfb_max)
1787 return put_user((u32)1, argp);
1788 else
1789 return put_user((u32)0, argp);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001790
1791 case SISFB_SET_AUTOMAXIMIZE_OLD:
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001792 if(ivideo->warncount++ < 10)
1793 printk(KERN_INFO
1794 "sisfb: Deprecated ioctl call received - update your application!\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001795 case SISFB_SET_AUTOMAXIMIZE:
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001796 if(get_user(gpu32, argp))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001797 return -EFAULT;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001798
Linus Torvalds1da177e2005-04-16 15:20:36 -07001799 ivideo->sisfb_max = (gpu32) ? 1 : 0;
1800 break;
1801
1802 case SISFB_SET_TVPOSOFFSET:
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001803 if(get_user(gpu32, argp))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001804 return -EFAULT;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001805
Linus Torvalds1da177e2005-04-16 15:20:36 -07001806 sisfb_set_TVxposoffset(ivideo, ((int)(gpu32 >> 16)) - 32);
1807 sisfb_set_TVyposoffset(ivideo, ((int)(gpu32 & 0xffff)) - 32);
1808 break;
1809
1810 case SISFB_GET_TVPOSOFFSET:
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001811 return put_user((u32)(((ivideo->tvxpos+32)<<16)|((ivideo->tvypos+32)&0xffff)),
1812 argp);
1813
1814 case SISFB_COMMAND:
1815 if(copy_from_user(&ivideo->sisfb_command, (void __user *)arg,
1816 sizeof(struct sisfb_cmd)))
1817 return -EFAULT;
1818
1819 sisfb_handle_command(ivideo, &ivideo->sisfb_command);
1820
1821 if(copy_to_user((void __user *)arg, &ivideo->sisfb_command,
1822 sizeof(struct sisfb_cmd)))
1823 return -EFAULT;
1824
1825 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001826
1827 case SISFB_SET_LOCK:
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001828 if(get_user(gpu32, argp))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001829 return -EFAULT;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001830
Linus Torvalds1da177e2005-04-16 15:20:36 -07001831 ivideo->sisfblocked = (gpu32) ? 1 : 0;
1832 break;
1833
1834 default:
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001835#ifdef SIS_NEW_CONFIG_COMPAT
Linus Torvalds1da177e2005-04-16 15:20:36 -07001836 return -ENOIOCTLCMD;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001837#else
1838 return -EINVAL;
1839#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -07001840 }
1841 return 0;
1842}
1843
Linus Torvalds1da177e2005-04-16 15:20:36 -07001844static int
1845sisfb_get_fix(struct fb_fix_screeninfo *fix, int con, struct fb_info *info)
1846{
1847 struct sis_video_info *ivideo = (struct sis_video_info *)info->par;
1848
1849 memset(fix, 0, sizeof(struct fb_fix_screeninfo));
1850
Dan Carpenterdbd536b2010-05-24 14:33:53 -07001851 strlcpy(fix->id, ivideo->myid, sizeof(fix->id));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001852
Krzysztof Helt537a1bf2009-06-30 11:41:29 -07001853 mutex_lock(&info->mm_lock);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001854 fix->smem_start = ivideo->video_base + ivideo->video_offset;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001855 fix->smem_len = ivideo->sisfb_mem;
Krzysztof Helt537a1bf2009-06-30 11:41:29 -07001856 mutex_unlock(&info->mm_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001857 fix->type = FB_TYPE_PACKED_PIXELS;
1858 fix->type_aux = 0;
1859 fix->visual = (ivideo->video_bpp == 8) ? FB_VISUAL_PSEUDOCOLOR : FB_VISUAL_TRUECOLOR;
1860 fix->xpanstep = 1;
1861 fix->ypanstep = (ivideo->sisfb_ypan) ? 1 : 0;
1862 fix->ywrapstep = 0;
1863 fix->line_length = ivideo->video_linelength;
1864 fix->mmio_start = ivideo->mmio_base;
1865 fix->mmio_len = ivideo->mmio_size;
1866 if(ivideo->sisvga_engine == SIS_300_VGA) {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001867 fix->accel = FB_ACCEL_SIS_GLAMOUR;
1868 } else if((ivideo->chip == SIS_330) ||
1869 (ivideo->chip == SIS_760) ||
1870 (ivideo->chip == SIS_761)) {
1871 fix->accel = FB_ACCEL_SIS_XABRE;
1872 } else if(ivideo->chip == XGI_20) {
1873 fix->accel = FB_ACCEL_XGI_VOLARI_Z;
1874 } else if(ivideo->chip >= XGI_40) {
1875 fix->accel = FB_ACCEL_XGI_VOLARI_V;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001876 } else {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001877 fix->accel = FB_ACCEL_SIS_GLAMOUR_2;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001878 }
1879
1880 return 0;
1881}
1882
1883/* ---------------- fb_ops structures ----------------- */
1884
Linus Torvalds1da177e2005-04-16 15:20:36 -07001885static struct fb_ops sisfb_ops = {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001886 .owner = THIS_MODULE,
1887 .fb_open = sisfb_open,
1888 .fb_release = sisfb_release,
1889 .fb_check_var = sisfb_check_var,
1890 .fb_set_par = sisfb_set_par,
1891 .fb_setcolreg = sisfb_setcolreg,
1892 .fb_pan_display = sisfb_pan_display,
1893 .fb_blank = sisfb_blank,
1894 .fb_fillrect = fbcon_sis_fillrect,
1895 .fb_copyarea = fbcon_sis_copyarea,
1896 .fb_imageblit = cfb_imageblit,
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001897 .fb_sync = fbcon_sis_sync,
1898#ifdef SIS_NEW_CONFIG_COMPAT
Christoph Hellwig67a66802006-01-14 13:21:25 -08001899 .fb_compat_ioctl= sisfb_ioctl,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001900#endif
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001901 .fb_ioctl = sisfb_ioctl
Linus Torvalds1da177e2005-04-16 15:20:36 -07001902};
Linus Torvalds1da177e2005-04-16 15:20:36 -07001903
1904/* ---------------- Chip generation dependent routines ---------------- */
1905
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001906static struct pci_dev * __devinit
1907sisfb_get_northbridge(int basechipid)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001908{
1909 struct pci_dev *pdev = NULL;
1910 int nbridgenum, nbridgeidx, i;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001911 static const unsigned short nbridgeids[] = {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001912 PCI_DEVICE_ID_SI_540, /* for SiS 540 VGA */
1913 PCI_DEVICE_ID_SI_630, /* for SiS 630/730 VGA */
1914 PCI_DEVICE_ID_SI_730,
1915 PCI_DEVICE_ID_SI_550, /* for SiS 550 VGA */
1916 PCI_DEVICE_ID_SI_650, /* for SiS 650/651/740 VGA */
1917 PCI_DEVICE_ID_SI_651,
1918 PCI_DEVICE_ID_SI_740,
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001919 PCI_DEVICE_ID_SI_661, /* for SiS 661/741/660/760/761 VGA */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001920 PCI_DEVICE_ID_SI_741,
1921 PCI_DEVICE_ID_SI_660,
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001922 PCI_DEVICE_ID_SI_760,
1923 PCI_DEVICE_ID_SI_761
Linus Torvalds1da177e2005-04-16 15:20:36 -07001924 };
1925
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001926 switch(basechipid) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001927#ifdef CONFIG_FB_SIS_300
1928 case SIS_540: nbridgeidx = 0; nbridgenum = 1; break;
1929 case SIS_630: nbridgeidx = 1; nbridgenum = 2; break;
1930#endif
1931#ifdef CONFIG_FB_SIS_315
1932 case SIS_550: nbridgeidx = 3; nbridgenum = 1; break;
1933 case SIS_650: nbridgeidx = 4; nbridgenum = 3; break;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001934 case SIS_660: nbridgeidx = 7; nbridgenum = 5; break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001935#endif
1936 default: return NULL;
1937 }
1938 for(i = 0; i < nbridgenum; i++) {
Adrian Bunk0959f0c2007-05-08 00:39:50 -07001939 if((pdev = pci_get_device(PCI_VENDOR_ID_SI,
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001940 nbridgeids[nbridgeidx+i], NULL)))
1941 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001942 }
1943 return pdev;
1944}
1945
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001946static int __devinit
1947sisfb_get_dram_size(struct sis_video_info *ivideo)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001948{
1949#if defined(CONFIG_FB_SIS_300) || defined(CONFIG_FB_SIS_315)
1950 u8 reg;
1951#endif
1952
1953 ivideo->video_size = 0;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001954 ivideo->UMAsize = ivideo->LFBsize = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001955
1956 switch(ivideo->chip) {
1957#ifdef CONFIG_FB_SIS_300
1958 case SIS_300:
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001959 inSISIDXREG(SISSR, 0x14, reg);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001960 ivideo->video_size = ((reg & 0x3F) + 1) << 20;
1961 break;
1962 case SIS_540:
1963 case SIS_630:
1964 case SIS_730:
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001965 if(!ivideo->nbridge)
1966 return -1;
1967 pci_read_config_byte(ivideo->nbridge, 0x63, &reg);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001968 ivideo->video_size = 1 << (((reg & 0x70) >> 4) + 21);
1969 break;
1970#endif
1971#ifdef CONFIG_FB_SIS_315
1972 case SIS_315H:
1973 case SIS_315PRO:
1974 case SIS_315:
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001975 inSISIDXREG(SISSR, 0x14, reg);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001976 ivideo->video_size = (1 << ((reg & 0xf0) >> 4)) << 20;
1977 switch((reg >> 2) & 0x03) {
1978 case 0x01:
1979 case 0x03:
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001980 ivideo->video_size <<= 1;
1981 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001982 case 0x02:
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001983 ivideo->video_size += (ivideo->video_size/2);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001984 }
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001985 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001986 case SIS_330:
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001987 inSISIDXREG(SISSR, 0x14, reg);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001988 ivideo->video_size = (1 << ((reg & 0xf0) >> 4)) << 20;
1989 if(reg & 0x0c) ivideo->video_size <<= 1;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001990 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001991 case SIS_550:
1992 case SIS_650:
1993 case SIS_740:
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001994 inSISIDXREG(SISSR, 0x14, reg);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001995 ivideo->video_size = (((reg & 0x3f) + 1) << 2) << 20;
1996 break;
1997 case SIS_661:
1998 case SIS_741:
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001999 inSISIDXREG(SISCR, 0x79, reg);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002000 ivideo->video_size = (1 << ((reg & 0xf0) >> 4)) << 20;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07002001 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002002 case SIS_660:
2003 case SIS_760:
Thomas Winischhofer544393f2005-09-09 13:04:45 -07002004 case SIS_761:
Linus Torvalds1da177e2005-04-16 15:20:36 -07002005 inSISIDXREG(SISCR, 0x79, reg);
2006 reg = (reg & 0xf0) >> 4;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07002007 if(reg) {
2008 ivideo->video_size = (1 << reg) << 20;
2009 ivideo->UMAsize = ivideo->video_size;
2010 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002011 inSISIDXREG(SISCR, 0x78, reg);
2012 reg &= 0x30;
2013 if(reg) {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07002014 if(reg == 0x10) {
2015 ivideo->LFBsize = (32 << 20);
2016 } else {
2017 ivideo->LFBsize = (64 << 20);
2018 }
2019 ivideo->video_size += ivideo->LFBsize;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002020 }
Thomas Winischhofer544393f2005-09-09 13:04:45 -07002021 break;
2022 case SIS_340:
2023 case XGI_20:
2024 case XGI_40:
2025 inSISIDXREG(SISSR, 0x14, reg);
2026 ivideo->video_size = (1 << ((reg & 0xf0) >> 4)) << 20;
2027 if(ivideo->chip != XGI_20) {
2028 reg = (reg & 0x0c) >> 2;
2029 if(ivideo->revision_id == 2) {
2030 if(reg & 0x01) reg = 0x02;
2031 else reg = 0x00;
2032 }
2033 if(reg == 0x02) ivideo->video_size <<= 1;
2034 else if(reg == 0x03) ivideo->video_size <<= 2;
2035 }
2036 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002037#endif
2038 default:
2039 return -1;
2040 }
2041 return 0;
2042}
2043
2044/* -------------- video bridge device detection --------------- */
2045
Thomas Winischhofer544393f2005-09-09 13:04:45 -07002046static void __devinit
2047sisfb_detect_VB_connect(struct sis_video_info *ivideo)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002048{
2049 u8 cr32, temp;
2050
Thomas Winischhofer544393f2005-09-09 13:04:45 -07002051 /* No CRT2 on XGI Z7 */
2052 if(ivideo->chip == XGI_20) {
2053 ivideo->sisfb_crt1off = 0;
2054 return;
2055 }
2056
Linus Torvalds1da177e2005-04-16 15:20:36 -07002057#ifdef CONFIG_FB_SIS_300
2058 if(ivideo->sisvga_engine == SIS_300_VGA) {
2059 inSISIDXREG(SISSR, 0x17, temp);
2060 if((temp & 0x0F) && (ivideo->chip != SIS_300)) {
2061 /* PAL/NTSC is stored on SR16 on such machines */
2062 if(!(ivideo->vbflags & (TV_PAL | TV_NTSC | TV_PALM | TV_PALN))) {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07002063 inSISIDXREG(SISSR, 0x16, temp);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002064 if(temp & 0x20)
2065 ivideo->vbflags |= TV_PAL;
2066 else
2067 ivideo->vbflags |= TV_NTSC;
2068 }
2069 }
2070 }
2071#endif
2072
2073 inSISIDXREG(SISCR, 0x32, cr32);
2074
2075 if(cr32 & SIS_CRT1) {
2076 ivideo->sisfb_crt1off = 0;
2077 } else {
2078 ivideo->sisfb_crt1off = (cr32 & 0xDF) ? 1 : 0;
2079 }
2080
2081 ivideo->vbflags &= ~(CRT2_TV | CRT2_LCD | CRT2_VGA);
2082
2083 if(cr32 & SIS_VB_TV) ivideo->vbflags |= CRT2_TV;
2084 if(cr32 & SIS_VB_LCD) ivideo->vbflags |= CRT2_LCD;
2085 if(cr32 & SIS_VB_CRT2) ivideo->vbflags |= CRT2_VGA;
2086
2087 /* Check given parms for hardware compatibility.
2088 * (Cannot do this in the search_xx routines since we don't
2089 * know what hardware we are running on then)
2090 */
2091
2092 if(ivideo->chip != SIS_550) {
2093 ivideo->sisfb_dstn = ivideo->sisfb_fstn = 0;
2094 }
2095
2096 if(ivideo->sisfb_tvplug != -1) {
2097 if( (ivideo->sisvga_engine != SIS_315_VGA) ||
Thomas Winischhofer544393f2005-09-09 13:04:45 -07002098 (!(ivideo->vbflags2 & VB2_SISYPBPRBRIDGE)) ) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002099 if(ivideo->sisfb_tvplug & TV_YPBPR) {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07002100 ivideo->sisfb_tvplug = -1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002101 printk(KERN_ERR "sisfb: YPbPr not supported\n");
2102 }
2103 }
2104 }
2105 if(ivideo->sisfb_tvplug != -1) {
2106 if( (ivideo->sisvga_engine != SIS_315_VGA) ||
Thomas Winischhofer544393f2005-09-09 13:04:45 -07002107 (!(ivideo->vbflags2 & VB2_SISHIVISIONBRIDGE)) ) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002108 if(ivideo->sisfb_tvplug & TV_HIVISION) {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07002109 ivideo->sisfb_tvplug = -1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002110 printk(KERN_ERR "sisfb: HiVision not supported\n");
2111 }
2112 }
2113 }
2114 if(ivideo->sisfb_tvstd != -1) {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07002115 if( (!(ivideo->vbflags2 & VB2_SISBRIDGE)) &&
2116 (!((ivideo->sisvga_engine == SIS_315_VGA) &&
2117 (ivideo->vbflags2 & VB2_CHRONTEL))) ) {
Roel Kluin5ab94812009-12-15 16:46:23 -08002118 if(ivideo->sisfb_tvstd & (TV_PALM | TV_PALN | TV_NTSCJ)) {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07002119 ivideo->sisfb_tvstd = -1;
2120 printk(KERN_ERR "sisfb: PALM/PALN/NTSCJ not supported\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002121 }
2122 }
2123 }
2124
2125 /* Detect/set TV plug & type */
2126 if(ivideo->sisfb_tvplug != -1) {
2127 ivideo->vbflags |= ivideo->sisfb_tvplug;
2128 } else {
2129 if(cr32 & SIS_VB_YPBPR) ivideo->vbflags |= (TV_YPBPR|TV_YPBPR525I); /* default: 480i */
2130 else if(cr32 & SIS_VB_HIVISION) ivideo->vbflags |= TV_HIVISION;
2131 else if(cr32 & SIS_VB_SCART) ivideo->vbflags |= TV_SCART;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07002132 else {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002133 if(cr32 & SIS_VB_SVIDEO) ivideo->vbflags |= TV_SVIDEO;
2134 if(cr32 & SIS_VB_COMPOSITE) ivideo->vbflags |= TV_AVIDEO;
2135 }
2136 }
2137
2138 if(!(ivideo->vbflags & (TV_YPBPR | TV_HIVISION))) {
2139 if(ivideo->sisfb_tvstd != -1) {
2140 ivideo->vbflags &= ~(TV_NTSC | TV_PAL | TV_PALM | TV_PALN | TV_NTSCJ);
2141 ivideo->vbflags |= ivideo->sisfb_tvstd;
2142 }
2143 if(ivideo->vbflags & TV_SCART) {
2144 ivideo->vbflags &= ~(TV_NTSC | TV_PALM | TV_PALN | TV_NTSCJ);
2145 ivideo->vbflags |= TV_PAL;
2146 }
2147 if(!(ivideo->vbflags & (TV_PAL | TV_NTSC | TV_PALM | TV_PALN | TV_NTSCJ))) {
2148 if(ivideo->sisvga_engine == SIS_300_VGA) {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07002149 inSISIDXREG(SISSR, 0x38, temp);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002150 if(temp & 0x01) ivideo->vbflags |= TV_PAL;
2151 else ivideo->vbflags |= TV_NTSC;
2152 } else if((ivideo->chip <= SIS_315PRO) || (ivideo->chip >= SIS_330)) {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07002153 inSISIDXREG(SISSR, 0x38, temp);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002154 if(temp & 0x01) ivideo->vbflags |= TV_PAL;
2155 else ivideo->vbflags |= TV_NTSC;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07002156 } else {
2157 inSISIDXREG(SISCR, 0x79, temp);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002158 if(temp & 0x20) ivideo->vbflags |= TV_PAL;
2159 else ivideo->vbflags |= TV_NTSC;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07002160 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002161 }
2162 }
2163
2164 /* Copy forceCRT1 option to CRT1off if option is given */
Thomas Winischhofer544393f2005-09-09 13:04:45 -07002165 if(ivideo->sisfb_forcecrt1 != -1) {
2166 ivideo->sisfb_crt1off = (ivideo->sisfb_forcecrt1) ? 0 : 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002167 }
2168}
2169
2170/* ------------------ Sensing routines ------------------ */
2171
Richard Knutssonc30660ea2007-02-12 00:55:06 -08002172static bool __devinit
Thomas Winischhofer544393f2005-09-09 13:04:45 -07002173sisfb_test_DDC1(struct sis_video_info *ivideo)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002174{
2175 unsigned short old;
2176 int count = 48;
2177
2178 old = SiS_ReadDDC1Bit(&ivideo->SiS_Pr);
2179 do {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07002180 if(old != SiS_ReadDDC1Bit(&ivideo->SiS_Pr)) break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002181 } while(count--);
Richard Knutssonc30660ea2007-02-12 00:55:06 -08002182 return (count != -1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002183}
2184
Thomas Winischhofer544393f2005-09-09 13:04:45 -07002185static void __devinit
2186sisfb_sense_crt1(struct sis_video_info *ivideo)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002187{
Richard Knutssonc30660ea2007-02-12 00:55:06 -08002188 bool mustwait = false;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002189 u8 sr1F, cr17;
2190#ifdef CONFIG_FB_SIS_315
2191 u8 cr63=0;
2192#endif
2193 u16 temp = 0xffff;
2194 int i;
2195
2196 inSISIDXREG(SISSR,0x1F,sr1F);
2197 orSISIDXREG(SISSR,0x1F,0x04);
2198 andSISIDXREG(SISSR,0x1F,0x3F);
Richard Knutssonc30660ea2007-02-12 00:55:06 -08002199 if(sr1F & 0xc0) mustwait = true;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002200
2201#ifdef CONFIG_FB_SIS_315
2202 if(ivideo->sisvga_engine == SIS_315_VGA) {
2203 inSISIDXREG(SISCR,ivideo->SiS_Pr.SiS_MyCR63,cr63);
2204 cr63 &= 0x40;
2205 andSISIDXREG(SISCR,ivideo->SiS_Pr.SiS_MyCR63,0xBF);
2206 }
2207#endif
2208
2209 inSISIDXREG(SISCR,0x17,cr17);
2210 cr17 &= 0x80;
2211 if(!cr17) {
2212 orSISIDXREG(SISCR,0x17,0x80);
Richard Knutssonc30660ea2007-02-12 00:55:06 -08002213 mustwait = true;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002214 outSISIDXREG(SISSR, 0x00, 0x01);
2215 outSISIDXREG(SISSR, 0x00, 0x03);
2216 }
2217
2218 if(mustwait) {
2219 for(i=0; i < 10; i++) sisfbwaitretracecrt1(ivideo);
2220 }
2221
2222#ifdef CONFIG_FB_SIS_315
2223 if(ivideo->chip >= SIS_330) {
2224 andSISIDXREG(SISCR,0x32,~0x20);
2225 if(ivideo->chip >= SIS_340) {
2226 outSISIDXREG(SISCR, 0x57, 0x4a);
2227 } else {
2228 outSISIDXREG(SISCR, 0x57, 0x5f);
2229 }
2230 orSISIDXREG(SISCR, 0x53, 0x02);
2231 while((inSISREG(SISINPSTAT)) & 0x01) break;
2232 while(!((inSISREG(SISINPSTAT)) & 0x01)) break;
2233 if((inSISREG(SISMISCW)) & 0x10) temp = 1;
2234 andSISIDXREG(SISCR, 0x53, 0xfd);
2235 andSISIDXREG(SISCR, 0x57, 0x00);
2236 }
2237#endif
2238
2239 if(temp == 0xffff) {
2240 i = 3;
2241 do {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07002242 temp = SiS_HandleDDC(&ivideo->SiS_Pr, ivideo->vbflags,
2243 ivideo->sisvga_engine, 0, 0, NULL, ivideo->vbflags2);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002244 } while(((temp == 0) || (temp == 0xffff)) && i--);
2245
2246 if((temp == 0) || (temp == 0xffff)) {
2247 if(sisfb_test_DDC1(ivideo)) temp = 1;
2248 }
2249 }
2250
2251 if((temp) && (temp != 0xffff)) {
2252 orSISIDXREG(SISCR,0x32,0x20);
2253 }
2254
2255#ifdef CONFIG_FB_SIS_315
2256 if(ivideo->sisvga_engine == SIS_315_VGA) {
2257 setSISIDXREG(SISCR,ivideo->SiS_Pr.SiS_MyCR63,0xBF,cr63);
2258 }
2259#endif
2260
2261 setSISIDXREG(SISCR,0x17,0x7F,cr17);
2262
2263 outSISIDXREG(SISSR,0x1F,sr1F);
2264}
2265
2266/* Determine and detect attached devices on SiS30x */
Thomas Winischhofer544393f2005-09-09 13:04:45 -07002267static void __devinit
2268SiS_SenseLCD(struct sis_video_info *ivideo)
2269{
2270 unsigned char buffer[256];
2271 unsigned short temp, realcrtno, i;
2272 u8 reg, cr37 = 0, paneltype = 0;
2273 u16 xres, yres;
2274
Richard Knutssonc30660ea2007-02-12 00:55:06 -08002275 ivideo->SiS_Pr.PanelSelfDetected = false;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07002276
2277 /* LCD detection only for TMDS bridges */
2278 if(!(ivideo->vbflags2 & VB2_SISTMDSBRIDGE))
2279 return;
2280 if(ivideo->vbflags2 & VB2_30xBDH)
2281 return;
2282
2283 /* If LCD already set up by BIOS, skip it */
2284 inSISIDXREG(SISCR, 0x32, reg);
2285 if(reg & 0x08)
2286 return;
2287
2288 realcrtno = 1;
2289 if(ivideo->SiS_Pr.DDCPortMixup)
2290 realcrtno = 0;
2291
2292 /* Check DDC capabilities */
2293 temp = SiS_HandleDDC(&ivideo->SiS_Pr, ivideo->vbflags, ivideo->sisvga_engine,
2294 realcrtno, 0, &buffer[0], ivideo->vbflags2);
2295
2296 if((!temp) || (temp == 0xffff) || (!(temp & 0x02)))
2297 return;
2298
2299 /* Read DDC data */
2300 i = 3; /* Number of retrys */
2301 do {
2302 temp = SiS_HandleDDC(&ivideo->SiS_Pr, ivideo->vbflags,
2303 ivideo->sisvga_engine, realcrtno, 1,
2304 &buffer[0], ivideo->vbflags2);
2305 } while((temp) && i--);
2306
2307 if(temp)
2308 return;
2309
2310 /* No digital device */
2311 if(!(buffer[0x14] & 0x80))
2312 return;
2313
2314 /* First detailed timing preferred timing? */
2315 if(!(buffer[0x18] & 0x02))
2316 return;
2317
2318 xres = buffer[0x38] | ((buffer[0x3a] & 0xf0) << 4);
2319 yres = buffer[0x3b] | ((buffer[0x3d] & 0xf0) << 4);
2320
2321 switch(xres) {
2322 case 1024:
2323 if(yres == 768)
2324 paneltype = 0x02;
2325 break;
2326 case 1280:
2327 if(yres == 1024)
2328 paneltype = 0x03;
2329 break;
2330 case 1600:
2331 if((yres == 1200) && (ivideo->vbflags2 & VB2_30xC))
2332 paneltype = 0x0b;
2333 break;
2334 }
2335
2336 if(!paneltype)
2337 return;
2338
2339 if(buffer[0x23])
2340 cr37 |= 0x10;
2341
2342 if((buffer[0x47] & 0x18) == 0x18)
2343 cr37 |= ((((buffer[0x47] & 0x06) ^ 0x06) << 5) | 0x20);
2344 else
2345 cr37 |= 0xc0;
2346
2347 outSISIDXREG(SISCR, 0x36, paneltype);
2348 cr37 &= 0xf1;
2349 setSISIDXREG(SISCR, 0x37, 0x0c, cr37);
2350 orSISIDXREG(SISCR, 0x32, 0x08);
2351
Richard Knutssonc30660ea2007-02-12 00:55:06 -08002352 ivideo->SiS_Pr.PanelSelfDetected = true;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07002353}
2354
2355static int __devinit
2356SISDoSense(struct sis_video_info *ivideo, u16 type, u16 test)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002357{
2358 int temp, mytest, result, i, j;
2359
2360 for(j = 0; j < 10; j++) {
2361 result = 0;
2362 for(i = 0; i < 3; i++) {
2363 mytest = test;
2364 outSISIDXREG(SISPART4,0x11,(type & 0x00ff));
2365 temp = (type >> 8) | (mytest & 0x00ff);
2366 setSISIDXREG(SISPART4,0x10,0xe0,temp);
2367 SiS_DDC2Delay(&ivideo->SiS_Pr, 0x1500);
2368 mytest >>= 8;
2369 mytest &= 0x7f;
2370 inSISIDXREG(SISPART4,0x03,temp);
2371 temp ^= 0x0e;
2372 temp &= mytest;
2373 if(temp == mytest) result++;
2374#if 1
2375 outSISIDXREG(SISPART4,0x11,0x00);
2376 andSISIDXREG(SISPART4,0x10,0xe0);
2377 SiS_DDC2Delay(&ivideo->SiS_Pr, 0x1000);
2378#endif
2379 }
2380 if((result == 0) || (result >= 2)) break;
2381 }
Thomas Winischhofer544393f2005-09-09 13:04:45 -07002382 return result;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002383}
2384
Thomas Winischhofer544393f2005-09-09 13:04:45 -07002385static void __devinit
2386SiS_Sense30x(struct sis_video_info *ivideo)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002387{
2388 u8 backupP4_0d,backupP2_00,backupP2_4d,backupSR_1e,biosflag=0;
2389 u16 svhs=0, svhs_c=0;
2390 u16 cvbs=0, cvbs_c=0;
2391 u16 vga2=0, vga2_c=0;
2392 int myflag, result;
2393 char stdstr[] = "sisfb: Detected";
2394 char tvstr[] = "TV connected to";
2395
Thomas Winischhofer544393f2005-09-09 13:04:45 -07002396 if(ivideo->vbflags2 & VB2_301) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002397 svhs = 0x00b9; cvbs = 0x00b3; vga2 = 0x00d1;
2398 inSISIDXREG(SISPART4,0x01,myflag);
2399 if(myflag & 0x04) {
2400 svhs = 0x00dd; cvbs = 0x00ee; vga2 = 0x00fd;
2401 }
Thomas Winischhofer544393f2005-09-09 13:04:45 -07002402 } else if(ivideo->vbflags2 & (VB2_301B | VB2_302B)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002403 svhs = 0x016b; cvbs = 0x0174; vga2 = 0x0190;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07002404 } else if(ivideo->vbflags2 & (VB2_301LV | VB2_302LV)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002405 svhs = 0x0200; cvbs = 0x0100;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07002406 } else if(ivideo->vbflags2 & (VB2_301C | VB2_302ELV | VB2_307T | VB2_307LV)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002407 svhs = 0x016b; cvbs = 0x0110; vga2 = 0x0190;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07002408 } else
2409 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002410
2411 vga2_c = 0x0e08; svhs_c = 0x0404; cvbs_c = 0x0804;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07002412 if(ivideo->vbflags & (VB2_301LV|VB2_302LV|VB2_302ELV|VB2_307LV)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002413 svhs_c = 0x0408; cvbs_c = 0x0808;
2414 }
Thomas Winischhofer544393f2005-09-09 13:04:45 -07002415
Linus Torvalds1da177e2005-04-16 15:20:36 -07002416 biosflag = 2;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07002417 if(ivideo->haveXGIROM) {
2418 biosflag = ivideo->bios_abase[0x58] & 0x03;
2419 } else if(ivideo->newrom) {
2420 if(ivideo->bios_abase[0x5d] & 0x04) biosflag |= 0x01;
2421 } else if(ivideo->sisvga_engine == SIS_300_VGA) {
2422 if(ivideo->bios_abase) {
2423 biosflag = ivideo->bios_abase[0xfe] & 0x03;
2424 }
2425 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002426
2427 if(ivideo->chip == SIS_300) {
2428 inSISIDXREG(SISSR,0x3b,myflag);
2429 if(!(myflag & 0x01)) vga2 = vga2_c = 0;
2430 }
2431
Thomas Winischhofer544393f2005-09-09 13:04:45 -07002432 if(!(ivideo->vbflags2 & VB2_SISVGA2BRIDGE)) {
2433 vga2 = vga2_c = 0;
2434 }
2435
Linus Torvalds1da177e2005-04-16 15:20:36 -07002436 inSISIDXREG(SISSR,0x1e,backupSR_1e);
2437 orSISIDXREG(SISSR,0x1e,0x20);
2438
2439 inSISIDXREG(SISPART4,0x0d,backupP4_0d);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07002440 if(ivideo->vbflags2 & VB2_30xC) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002441 setSISIDXREG(SISPART4,0x0d,~0x07,0x01);
2442 } else {
2443 orSISIDXREG(SISPART4,0x0d,0x04);
2444 }
2445 SiS_DDC2Delay(&ivideo->SiS_Pr, 0x2000);
2446
2447 inSISIDXREG(SISPART2,0x00,backupP2_00);
2448 outSISIDXREG(SISPART2,0x00,((backupP2_00 | 0x1c) & 0xfc));
2449
2450 inSISIDXREG(SISPART2,0x4d,backupP2_4d);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07002451 if(ivideo->vbflags2 & VB2_SISYPBPRBRIDGE) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002452 outSISIDXREG(SISPART2,0x4d,(backupP2_4d & ~0x10));
2453 }
2454
Thomas Winischhofer544393f2005-09-09 13:04:45 -07002455 if(!(ivideo->vbflags2 & VB2_30xCLV)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002456 SISDoSense(ivideo, 0, 0);
2457 }
2458
2459 andSISIDXREG(SISCR, 0x32, ~0x14);
2460
2461 if(vga2_c || vga2) {
2462 if(SISDoSense(ivideo, vga2, vga2_c)) {
2463 if(biosflag & 0x01) {
2464 printk(KERN_INFO "%s %s SCART output\n", stdstr, tvstr);
2465 orSISIDXREG(SISCR, 0x32, 0x04);
2466 } else {
2467 printk(KERN_INFO "%s secondary VGA connection\n", stdstr);
2468 orSISIDXREG(SISCR, 0x32, 0x10);
2469 }
2470 }
2471 }
2472
2473 andSISIDXREG(SISCR, 0x32, 0x3f);
2474
Thomas Winischhofer544393f2005-09-09 13:04:45 -07002475 if(ivideo->vbflags2 & VB2_30xCLV) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002476 orSISIDXREG(SISPART4,0x0d,0x04);
2477 }
2478
Thomas Winischhofer544393f2005-09-09 13:04:45 -07002479 if((ivideo->sisvga_engine == SIS_315_VGA) && (ivideo->vbflags2 & VB2_SISYPBPRBRIDGE)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002480 outSISIDXREG(SISPART2,0x4d,(backupP2_4d | 0x10));
2481 SiS_DDC2Delay(&ivideo->SiS_Pr, 0x2000);
2482 if((result = SISDoSense(ivideo, svhs, 0x0604))) {
2483 if((result = SISDoSense(ivideo, cvbs, 0x0804))) {
2484 printk(KERN_INFO "%s %s YPbPr component output\n", stdstr, tvstr);
2485 orSISIDXREG(SISCR,0x32,0x80);
2486 }
2487 }
2488 outSISIDXREG(SISPART2,0x4d,backupP2_4d);
2489 }
2490
2491 andSISIDXREG(SISCR, 0x32, ~0x03);
2492
2493 if(!(ivideo->vbflags & TV_YPBPR)) {
2494 if((result = SISDoSense(ivideo, svhs, svhs_c))) {
2495 printk(KERN_INFO "%s %s SVIDEO output\n", stdstr, tvstr);
2496 orSISIDXREG(SISCR, 0x32, 0x02);
2497 }
2498 if((biosflag & 0x02) || (!result)) {
2499 if(SISDoSense(ivideo, cvbs, cvbs_c)) {
2500 printk(KERN_INFO "%s %s COMPOSITE output\n", stdstr, tvstr);
2501 orSISIDXREG(SISCR, 0x32, 0x01);
2502 }
2503 }
2504 }
2505
2506 SISDoSense(ivideo, 0, 0);
2507
2508 outSISIDXREG(SISPART2,0x00,backupP2_00);
2509 outSISIDXREG(SISPART4,0x0d,backupP4_0d);
2510 outSISIDXREG(SISSR,0x1e,backupSR_1e);
2511
Thomas Winischhofer544393f2005-09-09 13:04:45 -07002512 if(ivideo->vbflags2 & VB2_30xCLV) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002513 inSISIDXREG(SISPART2,0x00,biosflag);
2514 if(biosflag & 0x20) {
2515 for(myflag = 2; myflag > 0; myflag--) {
2516 biosflag ^= 0x20;
2517 outSISIDXREG(SISPART2,0x00,biosflag);
2518 }
2519 }
2520 }
2521
2522 outSISIDXREG(SISPART2,0x00,backupP2_00);
2523}
2524
2525/* Determine and detect attached TV's on Chrontel */
Thomas Winischhofer544393f2005-09-09 13:04:45 -07002526static void __devinit
2527SiS_SenseCh(struct sis_video_info *ivideo)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002528{
2529#if defined(CONFIG_FB_SIS_300) || defined(CONFIG_FB_SIS_315)
2530 u8 temp1, temp2;
2531 char stdstr[] = "sisfb: Chrontel: Detected TV connected to";
2532#endif
2533#ifdef CONFIG_FB_SIS_300
2534 unsigned char test[3];
2535 int i;
2536#endif
2537
2538 if(ivideo->chip < SIS_315H) {
2539
2540#ifdef CONFIG_FB_SIS_300
2541 ivideo->SiS_Pr.SiS_IF_DEF_CH70xx = 1; /* Chrontel 700x */
2542 SiS_SetChrontelGPIO(&ivideo->SiS_Pr, 0x9c); /* Set general purpose IO for Chrontel communication */
2543 SiS_DDC2Delay(&ivideo->SiS_Pr, 1000);
2544 temp1 = SiS_GetCH700x(&ivideo->SiS_Pr, 0x25);
2545 /* See Chrontel TB31 for explanation */
2546 temp2 = SiS_GetCH700x(&ivideo->SiS_Pr, 0x0e);
2547 if(((temp2 & 0x07) == 0x01) || (temp2 & 0x04)) {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07002548 SiS_SetCH700x(&ivideo->SiS_Pr, 0x0e, 0x0b);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002549 SiS_DDC2Delay(&ivideo->SiS_Pr, 300);
2550 }
2551 temp2 = SiS_GetCH700x(&ivideo->SiS_Pr, 0x25);
2552 if(temp2 != temp1) temp1 = temp2;
2553
2554 if((temp1 >= 0x22) && (temp1 <= 0x50)) {
2555 /* Read power status */
2556 temp1 = SiS_GetCH700x(&ivideo->SiS_Pr, 0x0e);
2557 if((temp1 & 0x03) != 0x03) {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07002558 /* Power all outputs */
2559 SiS_SetCH700x(&ivideo->SiS_Pr, 0x0e,0x0b);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002560 SiS_DDC2Delay(&ivideo->SiS_Pr, 300);
2561 }
2562 /* Sense connected TV devices */
2563 for(i = 0; i < 3; i++) {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07002564 SiS_SetCH700x(&ivideo->SiS_Pr, 0x10, 0x01);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002565 SiS_DDC2Delay(&ivideo->SiS_Pr, 0x96);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07002566 SiS_SetCH700x(&ivideo->SiS_Pr, 0x10, 0x00);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002567 SiS_DDC2Delay(&ivideo->SiS_Pr, 0x96);
2568 temp1 = SiS_GetCH700x(&ivideo->SiS_Pr, 0x10);
2569 if(!(temp1 & 0x08)) test[i] = 0x02;
2570 else if(!(temp1 & 0x02)) test[i] = 0x01;
2571 else test[i] = 0;
2572 SiS_DDC2Delay(&ivideo->SiS_Pr, 0x96);
2573 }
2574
2575 if(test[0] == test[1]) temp1 = test[0];
2576 else if(test[0] == test[2]) temp1 = test[0];
2577 else if(test[1] == test[2]) temp1 = test[1];
2578 else {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07002579 printk(KERN_INFO
Linus Torvalds1da177e2005-04-16 15:20:36 -07002580 "sisfb: TV detection unreliable - test results varied\n");
2581 temp1 = test[2];
2582 }
2583 if(temp1 == 0x02) {
2584 printk(KERN_INFO "%s SVIDEO output\n", stdstr);
2585 ivideo->vbflags |= TV_SVIDEO;
2586 orSISIDXREG(SISCR, 0x32, 0x02);
2587 andSISIDXREG(SISCR, 0x32, ~0x05);
2588 } else if (temp1 == 0x01) {
2589 printk(KERN_INFO "%s CVBS output\n", stdstr);
2590 ivideo->vbflags |= TV_AVIDEO;
2591 orSISIDXREG(SISCR, 0x32, 0x01);
2592 andSISIDXREG(SISCR, 0x32, ~0x06);
2593 } else {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07002594 SiS_SetCH70xxANDOR(&ivideo->SiS_Pr, 0x0e, 0x01, 0xF8);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002595 andSISIDXREG(SISCR, 0x32, ~0x07);
2596 }
2597 } else if(temp1 == 0) {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07002598 SiS_SetCH70xxANDOR(&ivideo->SiS_Pr, 0x0e, 0x01, 0xF8);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002599 andSISIDXREG(SISCR, 0x32, ~0x07);
2600 }
2601 /* Set general purpose IO for Chrontel communication */
2602 SiS_SetChrontelGPIO(&ivideo->SiS_Pr, 0x00);
2603#endif
2604
2605 } else {
2606
2607#ifdef CONFIG_FB_SIS_315
2608 ivideo->SiS_Pr.SiS_IF_DEF_CH70xx = 2; /* Chrontel 7019 */
Thomas Winischhofer544393f2005-09-09 13:04:45 -07002609 temp1 = SiS_GetCH701x(&ivideo->SiS_Pr, 0x49);
2610 SiS_SetCH701x(&ivideo->SiS_Pr, 0x49, 0x20);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002611 SiS_DDC2Delay(&ivideo->SiS_Pr, 0x96);
2612 temp2 = SiS_GetCH701x(&ivideo->SiS_Pr, 0x20);
2613 temp2 |= 0x01;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07002614 SiS_SetCH701x(&ivideo->SiS_Pr, 0x20, temp2);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002615 SiS_DDC2Delay(&ivideo->SiS_Pr, 0x96);
2616 temp2 ^= 0x01;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07002617 SiS_SetCH701x(&ivideo->SiS_Pr, 0x20, temp2);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002618 SiS_DDC2Delay(&ivideo->SiS_Pr, 0x96);
2619 temp2 = SiS_GetCH701x(&ivideo->SiS_Pr, 0x20);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07002620 SiS_SetCH701x(&ivideo->SiS_Pr, 0x49, temp1);
2621 temp1 = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002622 if(temp2 & 0x02) temp1 |= 0x01;
2623 if(temp2 & 0x10) temp1 |= 0x01;
2624 if(temp2 & 0x04) temp1 |= 0x02;
2625 if( (temp1 & 0x01) && (temp1 & 0x02) ) temp1 = 0x04;
2626 switch(temp1) {
2627 case 0x01:
2628 printk(KERN_INFO "%s CVBS output\n", stdstr);
2629 ivideo->vbflags |= TV_AVIDEO;
2630 orSISIDXREG(SISCR, 0x32, 0x01);
2631 andSISIDXREG(SISCR, 0x32, ~0x06);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07002632 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002633 case 0x02:
2634 printk(KERN_INFO "%s SVIDEO output\n", stdstr);
2635 ivideo->vbflags |= TV_SVIDEO;
2636 orSISIDXREG(SISCR, 0x32, 0x02);
2637 andSISIDXREG(SISCR, 0x32, ~0x05);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07002638 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002639 case 0x04:
2640 printk(KERN_INFO "%s SCART output\n", stdstr);
2641 orSISIDXREG(SISCR, 0x32, 0x04);
2642 andSISIDXREG(SISCR, 0x32, ~0x03);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07002643 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002644 default:
2645 andSISIDXREG(SISCR, 0x32, ~0x07);
2646 }
2647#endif
2648 }
2649}
2650
Thomas Winischhofer544393f2005-09-09 13:04:45 -07002651static void __devinit
2652sisfb_get_VB_type(struct sis_video_info *ivideo)
2653{
2654 char stdstr[] = "sisfb: Detected";
2655 char bridgestr[] = "video bridge";
2656 u8 vb_chipid;
2657 u8 reg;
2658
2659 /* No CRT2 on XGI Z7 */
2660 if(ivideo->chip == XGI_20)
2661 return;
2662
2663 inSISIDXREG(SISPART4, 0x00, vb_chipid);
2664 switch(vb_chipid) {
2665 case 0x01:
2666 inSISIDXREG(SISPART4, 0x01, reg);
2667 if(reg < 0xb0) {
2668 ivideo->vbflags |= VB_301; /* Deprecated */
2669 ivideo->vbflags2 |= VB2_301;
2670 printk(KERN_INFO "%s SiS301 %s\n", stdstr, bridgestr);
2671 } else if(reg < 0xc0) {
2672 ivideo->vbflags |= VB_301B; /* Deprecated */
2673 ivideo->vbflags2 |= VB2_301B;
2674 inSISIDXREG(SISPART4,0x23,reg);
2675 if(!(reg & 0x02)) {
2676 ivideo->vbflags |= VB_30xBDH; /* Deprecated */
2677 ivideo->vbflags2 |= VB2_30xBDH;
2678 printk(KERN_INFO "%s SiS301B-DH %s\n", stdstr, bridgestr);
2679 } else {
2680 printk(KERN_INFO "%s SiS301B %s\n", stdstr, bridgestr);
2681 }
2682 } else if(reg < 0xd0) {
2683 ivideo->vbflags |= VB_301C; /* Deprecated */
2684 ivideo->vbflags2 |= VB2_301C;
2685 printk(KERN_INFO "%s SiS301C %s\n", stdstr, bridgestr);
2686 } else if(reg < 0xe0) {
2687 ivideo->vbflags |= VB_301LV; /* Deprecated */
2688 ivideo->vbflags2 |= VB2_301LV;
2689 printk(KERN_INFO "%s SiS301LV %s\n", stdstr, bridgestr);
2690 } else if(reg <= 0xe1) {
2691 inSISIDXREG(SISPART4,0x39,reg);
2692 if(reg == 0xff) {
2693 ivideo->vbflags |= VB_302LV; /* Deprecated */
2694 ivideo->vbflags2 |= VB2_302LV;
2695 printk(KERN_INFO "%s SiS302LV %s\n", stdstr, bridgestr);
2696 } else {
2697 ivideo->vbflags |= VB_301C; /* Deprecated */
2698 ivideo->vbflags2 |= VB2_301C;
2699 printk(KERN_INFO "%s SiS301C(P4) %s\n", stdstr, bridgestr);
2700#if 0
2701 ivideo->vbflags |= VB_302ELV; /* Deprecated */
2702 ivideo->vbflags2 |= VB2_302ELV;
2703 printk(KERN_INFO "%s SiS302ELV %s\n", stdstr, bridgestr);
2704#endif
2705 }
2706 }
2707 break;
2708 case 0x02:
2709 ivideo->vbflags |= VB_302B; /* Deprecated */
2710 ivideo->vbflags2 |= VB2_302B;
2711 printk(KERN_INFO "%s SiS302B %s\n", stdstr, bridgestr);
2712 break;
2713 }
2714
2715 if((!(ivideo->vbflags2 & VB2_VIDEOBRIDGE)) && (ivideo->chip != SIS_300)) {
2716 inSISIDXREG(SISCR, 0x37, reg);
2717 reg &= SIS_EXTERNAL_CHIP_MASK;
2718 reg >>= 1;
2719 if(ivideo->sisvga_engine == SIS_300_VGA) {
2720#ifdef CONFIG_FB_SIS_300
2721 switch(reg) {
2722 case SIS_EXTERNAL_CHIP_LVDS:
2723 ivideo->vbflags |= VB_LVDS; /* Deprecated */
2724 ivideo->vbflags2 |= VB2_LVDS;
2725 break;
2726 case SIS_EXTERNAL_CHIP_TRUMPION:
2727 ivideo->vbflags |= (VB_LVDS | VB_TRUMPION); /* Deprecated */
2728 ivideo->vbflags2 |= (VB2_LVDS | VB2_TRUMPION);
2729 break;
2730 case SIS_EXTERNAL_CHIP_CHRONTEL:
2731 ivideo->vbflags |= VB_CHRONTEL; /* Deprecated */
2732 ivideo->vbflags2 |= VB2_CHRONTEL;
2733 break;
2734 case SIS_EXTERNAL_CHIP_LVDS_CHRONTEL:
2735 ivideo->vbflags |= (VB_LVDS | VB_CHRONTEL); /* Deprecated */
2736 ivideo->vbflags2 |= (VB2_LVDS | VB2_CHRONTEL);
2737 break;
2738 }
2739 if(ivideo->vbflags2 & VB2_CHRONTEL) ivideo->chronteltype = 1;
2740#endif
2741 } else if(ivideo->chip < SIS_661) {
2742#ifdef CONFIG_FB_SIS_315
2743 switch (reg) {
2744 case SIS310_EXTERNAL_CHIP_LVDS:
2745 ivideo->vbflags |= VB_LVDS; /* Deprecated */
2746 ivideo->vbflags2 |= VB2_LVDS;
2747 break;
2748 case SIS310_EXTERNAL_CHIP_LVDS_CHRONTEL:
2749 ivideo->vbflags |= (VB_LVDS | VB_CHRONTEL); /* Deprecated */
2750 ivideo->vbflags2 |= (VB2_LVDS | VB2_CHRONTEL);
2751 break;
2752 }
2753 if(ivideo->vbflags2 & VB2_CHRONTEL) ivideo->chronteltype = 2;
2754#endif
2755 } else if(ivideo->chip >= SIS_661) {
2756#ifdef CONFIG_FB_SIS_315
2757 inSISIDXREG(SISCR, 0x38, reg);
2758 reg >>= 5;
2759 switch(reg) {
2760 case 0x02:
2761 ivideo->vbflags |= VB_LVDS; /* Deprecated */
2762 ivideo->vbflags2 |= VB2_LVDS;
2763 break;
2764 case 0x03:
2765 ivideo->vbflags |= (VB_LVDS | VB_CHRONTEL); /* Deprecated */
2766 ivideo->vbflags2 |= (VB2_LVDS | VB2_CHRONTEL);
2767 break;
2768 case 0x04:
2769 ivideo->vbflags |= (VB_LVDS | VB_CONEXANT); /* Deprecated */
2770 ivideo->vbflags2 |= (VB2_LVDS | VB2_CONEXANT);
2771 break;
2772 }
2773 if(ivideo->vbflags2 & VB2_CHRONTEL) ivideo->chronteltype = 2;
2774#endif
2775 }
2776 if(ivideo->vbflags2 & VB2_LVDS) {
2777 printk(KERN_INFO "%s LVDS transmitter\n", stdstr);
2778 }
2779 if((ivideo->sisvga_engine == SIS_300_VGA) && (ivideo->vbflags2 & VB2_TRUMPION)) {
2780 printk(KERN_INFO "%s Trumpion Zurac LCD scaler\n", stdstr);
2781 }
2782 if(ivideo->vbflags2 & VB2_CHRONTEL) {
2783 printk(KERN_INFO "%s Chrontel TV encoder\n", stdstr);
2784 }
2785 if((ivideo->chip >= SIS_661) && (ivideo->vbflags2 & VB2_CONEXANT)) {
2786 printk(KERN_INFO "%s Conexant external device\n", stdstr);
2787 }
2788 }
2789
2790 if(ivideo->vbflags2 & VB2_SISBRIDGE) {
2791 SiS_SenseLCD(ivideo);
2792 SiS_Sense30x(ivideo);
2793 } else if(ivideo->vbflags2 & VB2_CHRONTEL) {
2794 SiS_SenseCh(ivideo);
2795 }
2796}
2797
2798/* ---------- Engine initialization routines ------------ */
2799
2800static void
2801sisfb_engine_init(struct sis_video_info *ivideo)
2802{
2803
2804 /* Initialize command queue (we use MMIO only) */
2805
2806 /* BEFORE THIS IS CALLED, THE ENGINES *MUST* BE SYNC'ED */
2807
2808 ivideo->caps &= ~(TURBO_QUEUE_CAP |
2809 MMIO_CMD_QUEUE_CAP |
2810 VM_CMD_QUEUE_CAP |
2811 AGP_CMD_QUEUE_CAP);
2812
2813#ifdef CONFIG_FB_SIS_300
2814 if(ivideo->sisvga_engine == SIS_300_VGA) {
2815 u32 tqueue_pos;
2816 u8 tq_state;
2817
2818 tqueue_pos = (ivideo->video_size - ivideo->cmdQueueSize) / (64 * 1024);
2819
2820 inSISIDXREG(SISSR, IND_SIS_TURBOQUEUE_SET, tq_state);
2821 tq_state |= 0xf0;
2822 tq_state &= 0xfc;
2823 tq_state |= (u8)(tqueue_pos >> 8);
2824 outSISIDXREG(SISSR, IND_SIS_TURBOQUEUE_SET, tq_state);
2825
2826 outSISIDXREG(SISSR, IND_SIS_TURBOQUEUE_ADR, (u8)(tqueue_pos & 0xff));
2827
2828 ivideo->caps |= TURBO_QUEUE_CAP;
2829 }
2830#endif
2831
2832#ifdef CONFIG_FB_SIS_315
2833 if(ivideo->sisvga_engine == SIS_315_VGA) {
2834 u32 tempq = 0, templ;
2835 u8 temp;
2836
2837 if(ivideo->chip == XGI_20) {
2838 switch(ivideo->cmdQueueSize) {
2839 case (64 * 1024):
2840 temp = SIS_CMD_QUEUE_SIZE_Z7_64k;
2841 break;
2842 case (128 * 1024):
2843 default:
2844 temp = SIS_CMD_QUEUE_SIZE_Z7_128k;
2845 }
2846 } else {
2847 switch(ivideo->cmdQueueSize) {
2848 case (4 * 1024 * 1024):
2849 temp = SIS_CMD_QUEUE_SIZE_4M;
2850 break;
2851 case (2 * 1024 * 1024):
2852 temp = SIS_CMD_QUEUE_SIZE_2M;
2853 break;
2854 case (1 * 1024 * 1024):
2855 temp = SIS_CMD_QUEUE_SIZE_1M;
2856 break;
2857 default:
2858 case (512 * 1024):
2859 temp = SIS_CMD_QUEUE_SIZE_512k;
2860 }
2861 }
2862
2863 outSISIDXREG(SISSR, IND_SIS_CMDQUEUE_THRESHOLD, COMMAND_QUEUE_THRESHOLD);
2864 outSISIDXREG(SISSR, IND_SIS_CMDQUEUE_SET, SIS_CMD_QUEUE_RESET);
2865
2866 if((ivideo->chip >= XGI_40) && ivideo->modechanged) {
2867 /* Must disable dual pipe on XGI_40. Can't do
2868 * this in MMIO mode, because it requires
2869 * setting/clearing a bit in the MMIO fire trigger
2870 * register.
2871 */
2872 if(!((templ = MMIO_IN32(ivideo->mmio_vbase, 0x8240)) & (1 << 10))) {
2873
2874 MMIO_OUT32(ivideo->mmio_vbase, Q_WRITE_PTR, 0);
2875
2876 outSISIDXREG(SISSR, IND_SIS_CMDQUEUE_SET, (temp | SIS_VRAM_CMDQUEUE_ENABLE));
2877
2878 tempq = MMIO_IN32(ivideo->mmio_vbase, Q_READ_PTR);
2879 MMIO_OUT32(ivideo->mmio_vbase, Q_WRITE_PTR, tempq);
2880
2881 tempq = (u32)(ivideo->video_size - ivideo->cmdQueueSize);
2882 MMIO_OUT32(ivideo->mmio_vbase, Q_BASE_ADDR, tempq);
2883
2884 writel(0x16800000 + 0x8240, ivideo->video_vbase + tempq);
2885 writel(templ | (1 << 10), ivideo->video_vbase + tempq + 4);
2886 writel(0x168F0000, ivideo->video_vbase + tempq + 8);
2887 writel(0x168F0000, ivideo->video_vbase + tempq + 12);
2888
2889 MMIO_OUT32(ivideo->mmio_vbase, Q_WRITE_PTR, (tempq + 16));
2890
2891 sisfb_syncaccel(ivideo);
2892
2893 outSISIDXREG(SISSR, IND_SIS_CMDQUEUE_SET, SIS_CMD_QUEUE_RESET);
2894
2895 }
2896 }
2897
2898 tempq = MMIO_IN32(ivideo->mmio_vbase, MMIO_QUEUE_READPORT);
2899 MMIO_OUT32(ivideo->mmio_vbase, MMIO_QUEUE_WRITEPORT, tempq);
2900
2901 temp |= (SIS_MMIO_CMD_ENABLE | SIS_CMD_AUTO_CORR);
2902 outSISIDXREG(SISSR, IND_SIS_CMDQUEUE_SET, temp);
2903
2904 tempq = (u32)(ivideo->video_size - ivideo->cmdQueueSize);
2905 MMIO_OUT32(ivideo->mmio_vbase, MMIO_QUEUE_PHYBASE, tempq);
2906
2907 ivideo->caps |= MMIO_CMD_QUEUE_CAP;
2908 }
2909#endif
2910
2911 ivideo->engineok = 1;
2912}
2913
2914static void __devinit
2915sisfb_detect_lcd_type(struct sis_video_info *ivideo)
2916{
2917 u8 reg;
2918 int i;
2919
2920 inSISIDXREG(SISCR, 0x36, reg);
2921 reg &= 0x0f;
2922 if(ivideo->sisvga_engine == SIS_300_VGA) {
2923 ivideo->CRT2LCDType = sis300paneltype[reg];
2924 } else if(ivideo->chip >= SIS_661) {
2925 ivideo->CRT2LCDType = sis661paneltype[reg];
2926 } else {
2927 ivideo->CRT2LCDType = sis310paneltype[reg];
2928 if((ivideo->chip == SIS_550) && (sisfb_fstn)) {
2929 if((ivideo->CRT2LCDType != LCD_320x240_2) &&
2930 (ivideo->CRT2LCDType != LCD_320x240_3)) {
2931 ivideo->CRT2LCDType = LCD_320x240;
2932 }
2933 }
2934 }
2935
2936 if(ivideo->CRT2LCDType == LCD_UNKNOWN) {
2937 /* For broken BIOSes: Assume 1024x768, RGB18 */
2938 ivideo->CRT2LCDType = LCD_1024x768;
2939 setSISIDXREG(SISCR,0x36,0xf0,0x02);
2940 setSISIDXREG(SISCR,0x37,0xee,0x01);
2941 printk(KERN_DEBUG "sisfb: Invalid panel ID (%02x), assuming 1024x768, RGB18\n", reg);
2942 }
2943
2944 for(i = 0; i < SIS_LCD_NUMBER; i++) {
2945 if(ivideo->CRT2LCDType == sis_lcd_data[i].lcdtype) {
2946 ivideo->lcdxres = sis_lcd_data[i].xres;
2947 ivideo->lcdyres = sis_lcd_data[i].yres;
2948 ivideo->lcddefmodeidx = sis_lcd_data[i].default_mode_idx;
2949 break;
2950 }
2951 }
2952
2953#ifdef CONFIG_FB_SIS_300
2954 if(ivideo->SiS_Pr.SiS_CustomT == CUT_BARCO1366) {
2955 ivideo->lcdxres = 1360; ivideo->lcdyres = 1024;
2956 ivideo->lcddefmodeidx = DEFAULT_MODE_1360;
2957 } else if(ivideo->SiS_Pr.SiS_CustomT == CUT_PANEL848) {
2958 ivideo->lcdxres = 848; ivideo->lcdyres = 480;
2959 ivideo->lcddefmodeidx = DEFAULT_MODE_848;
2960 } else if(ivideo->SiS_Pr.SiS_CustomT == CUT_PANEL856) {
2961 ivideo->lcdxres = 856; ivideo->lcdyres = 480;
2962 ivideo->lcddefmodeidx = DEFAULT_MODE_856;
2963 }
2964#endif
2965
2966 printk(KERN_DEBUG "sisfb: Detected %dx%d flat panel\n",
2967 ivideo->lcdxres, ivideo->lcdyres);
2968}
2969
2970static void __devinit
2971sisfb_save_pdc_emi(struct sis_video_info *ivideo)
2972{
2973#ifdef CONFIG_FB_SIS_300
2974 /* Save the current PanelDelayCompensation if the LCD is currently used */
2975 if(ivideo->sisvga_engine == SIS_300_VGA) {
2976 if(ivideo->vbflags2 & (VB2_LVDS | VB2_30xBDH)) {
2977 int tmp;
2978 inSISIDXREG(SISCR,0x30,tmp);
2979 if(tmp & 0x20) {
2980 /* Currently on LCD? If yes, read current pdc */
2981 inSISIDXREG(SISPART1,0x13,ivideo->detectedpdc);
2982 ivideo->detectedpdc &= 0x3c;
2983 if(ivideo->SiS_Pr.PDC == -1) {
2984 /* Let option override detection */
2985 ivideo->SiS_Pr.PDC = ivideo->detectedpdc;
2986 }
2987 printk(KERN_INFO "sisfb: Detected LCD PDC 0x%02x\n",
2988 ivideo->detectedpdc);
2989 }
2990 if((ivideo->SiS_Pr.PDC != -1) &&
2991 (ivideo->SiS_Pr.PDC != ivideo->detectedpdc)) {
2992 printk(KERN_INFO "sisfb: Using LCD PDC 0x%02x\n",
2993 ivideo->SiS_Pr.PDC);
2994 }
2995 }
2996 }
2997#endif
2998
2999#ifdef CONFIG_FB_SIS_315
3000 if(ivideo->sisvga_engine == SIS_315_VGA) {
3001
3002 /* Try to find about LCDA */
3003 if(ivideo->vbflags2 & VB2_SISLCDABRIDGE) {
3004 int tmp;
3005 inSISIDXREG(SISPART1,0x13,tmp);
3006 if(tmp & 0x04) {
Richard Knutssonc30660ea2007-02-12 00:55:06 -08003007 ivideo->SiS_Pr.SiS_UseLCDA = true;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003008 ivideo->detectedlcda = 0x03;
3009 }
3010 }
3011
3012 /* Save PDC */
3013 if(ivideo->vbflags2 & VB2_SISLVDSBRIDGE) {
3014 int tmp;
3015 inSISIDXREG(SISCR,0x30,tmp);
3016 if((tmp & 0x20) || (ivideo->detectedlcda != 0xff)) {
3017 /* Currently on LCD? If yes, read current pdc */
3018 u8 pdc;
3019 inSISIDXREG(SISPART1,0x2D,pdc);
3020 ivideo->detectedpdc = (pdc & 0x0f) << 1;
3021 ivideo->detectedpdca = (pdc & 0xf0) >> 3;
3022 inSISIDXREG(SISPART1,0x35,pdc);
3023 ivideo->detectedpdc |= ((pdc >> 7) & 0x01);
3024 inSISIDXREG(SISPART1,0x20,pdc);
3025 ivideo->detectedpdca |= ((pdc >> 6) & 0x01);
3026 if(ivideo->newrom) {
3027 /* New ROM invalidates other PDC resp. */
3028 if(ivideo->detectedlcda != 0xff) {
3029 ivideo->detectedpdc = 0xff;
3030 } else {
3031 ivideo->detectedpdca = 0xff;
3032 }
3033 }
3034 if(ivideo->SiS_Pr.PDC == -1) {
3035 if(ivideo->detectedpdc != 0xff) {
3036 ivideo->SiS_Pr.PDC = ivideo->detectedpdc;
3037 }
3038 }
3039 if(ivideo->SiS_Pr.PDCA == -1) {
3040 if(ivideo->detectedpdca != 0xff) {
3041 ivideo->SiS_Pr.PDCA = ivideo->detectedpdca;
3042 }
3043 }
3044 if(ivideo->detectedpdc != 0xff) {
3045 printk(KERN_INFO
3046 "sisfb: Detected LCD PDC 0x%02x (for LCD=CRT2)\n",
3047 ivideo->detectedpdc);
3048 }
3049 if(ivideo->detectedpdca != 0xff) {
3050 printk(KERN_INFO
3051 "sisfb: Detected LCD PDC1 0x%02x (for LCD=CRT1)\n",
3052 ivideo->detectedpdca);
3053 }
3054 }
3055
3056 /* Save EMI */
3057 if(ivideo->vbflags2 & VB2_SISEMIBRIDGE) {
3058 inSISIDXREG(SISPART4,0x30,ivideo->SiS_Pr.EMI_30);
3059 inSISIDXREG(SISPART4,0x31,ivideo->SiS_Pr.EMI_31);
3060 inSISIDXREG(SISPART4,0x32,ivideo->SiS_Pr.EMI_32);
3061 inSISIDXREG(SISPART4,0x33,ivideo->SiS_Pr.EMI_33);
Richard Knutssonc30660ea2007-02-12 00:55:06 -08003062 ivideo->SiS_Pr.HaveEMI = true;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003063 if((tmp & 0x20) || (ivideo->detectedlcda != 0xff)) {
Richard Knutssonc30660ea2007-02-12 00:55:06 -08003064 ivideo->SiS_Pr.HaveEMILCD = true;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003065 }
3066 }
3067 }
3068
3069 /* Let user override detected PDCs (all bridges) */
3070 if(ivideo->vbflags2 & VB2_30xBLV) {
3071 if((ivideo->SiS_Pr.PDC != -1) &&
3072 (ivideo->SiS_Pr.PDC != ivideo->detectedpdc)) {
3073 printk(KERN_INFO "sisfb: Using LCD PDC 0x%02x (for LCD=CRT2)\n",
3074 ivideo->SiS_Pr.PDC);
3075 }
3076 if((ivideo->SiS_Pr.PDCA != -1) &&
3077 (ivideo->SiS_Pr.PDCA != ivideo->detectedpdca)) {
3078 printk(KERN_INFO "sisfb: Using LCD PDC1 0x%02x (for LCD=CRT1)\n",
3079 ivideo->SiS_Pr.PDCA);
3080 }
3081 }
3082
3083 }
3084#endif
3085}
3086
3087/* -------------------- Memory manager routines ---------------------- */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003088
3089static u32 __devinit
3090sisfb_getheapstart(struct sis_video_info *ivideo)
3091{
3092 u32 ret = ivideo->sisfb_parm_mem * 1024;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003093 u32 maxoffs = ivideo->video_size - ivideo->hwcursor_size - ivideo->cmdQueueSize;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003094 u32 def;
3095
3096 /* Calculate heap start = end of memory for console
3097 *
3098 * CCCCCCCCDDDDDDDDDDDDDDDDDDDDDDDDDDDDHHHHQQQQQQQQQQ
3099 * C = console, D = heap, H = HWCursor, Q = cmd-queue
3100 *
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003101 * On 76x in UMA+LFB mode, the layout is as follows:
3102 * DDDDDDDDDDDCCCCCCCCCCCCCCCCCCCCCCCCHHHHQQQQQQQQQQQ
3103 * where the heap is the entire UMA area, eventually
3104 * into the LFB area if the given mem parameter is
3105 * higher than the size of the UMA memory.
3106 *
Linus Torvalds1da177e2005-04-16 15:20:36 -07003107 * Basically given by "mem" parameter
3108 *
3109 * maximum = videosize - cmd_queue - hwcursor
3110 * (results in a heap of size 0)
3111 * default = SiS 300: depends on videosize
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003112 * SiS 315/330/340/XGI: 32k below max
Linus Torvalds1da177e2005-04-16 15:20:36 -07003113 */
3114
3115 if(ivideo->sisvga_engine == SIS_300_VGA) {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003116 if(ivideo->video_size > 0x1000000) {
3117 def = 0xc00000;
3118 } else if(ivideo->video_size > 0x800000) {
3119 def = 0x800000;
3120 } else {
3121 def = 0x400000;
3122 }
3123 } else if(ivideo->UMAsize && ivideo->LFBsize) {
3124 ret = def = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003125 } else {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003126 def = maxoffs - 0x8000;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003127 }
3128
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003129 /* Use default for secondary card for now (FIXME) */
3130 if((!ret) || (ret > maxoffs) || (ivideo->cardnumber != 0))
3131 ret = def;
3132
3133 return ret;
3134}
3135
3136static u32 __devinit
3137sisfb_getheapsize(struct sis_video_info *ivideo)
3138{
3139 u32 max = ivideo->video_size - ivideo->hwcursor_size - ivideo->cmdQueueSize;
3140 u32 ret = 0;
3141
3142 if(ivideo->UMAsize && ivideo->LFBsize) {
3143 if( (!ivideo->sisfb_parm_mem) ||
3144 ((ivideo->sisfb_parm_mem * 1024) > max) ||
3145 ((max - (ivideo->sisfb_parm_mem * 1024)) < ivideo->UMAsize) ) {
3146 ret = ivideo->UMAsize;
3147 max -= ivideo->UMAsize;
3148 } else {
3149 ret = max - (ivideo->sisfb_parm_mem * 1024);
3150 max = ivideo->sisfb_parm_mem * 1024;
3151 }
3152 ivideo->video_offset = ret;
3153 ivideo->sisfb_mem = max;
3154 } else {
3155 ret = max - ivideo->heapstart;
3156 ivideo->sisfb_mem = ivideo->heapstart;
3157 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003158
3159 return ret;
3160}
3161
3162static int __devinit
3163sisfb_heap_init(struct sis_video_info *ivideo)
3164{
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003165 struct SIS_OH *poh;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003166
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003167 ivideo->video_offset = 0;
3168 if(ivideo->sisfb_parm_mem) {
3169 if( (ivideo->sisfb_parm_mem < (2 * 1024 * 1024)) ||
3170 (ivideo->sisfb_parm_mem > ivideo->video_size) ) {
3171 ivideo->sisfb_parm_mem = 0;
3172 }
3173 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003174
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003175 ivideo->heapstart = sisfb_getheapstart(ivideo);
3176 ivideo->sisfb_heap_size = sisfb_getheapsize(ivideo);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003177
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003178 ivideo->sisfb_heap_start = ivideo->video_vbase + ivideo->heapstart;
3179 ivideo->sisfb_heap_end = ivideo->sisfb_heap_start + ivideo->sisfb_heap_size;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003180
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003181 printk(KERN_INFO "sisfb: Memory heap starting at %dK, size %dK\n",
3182 (int)(ivideo->heapstart / 1024), (int)(ivideo->sisfb_heap_size / 1024));
Linus Torvalds1da177e2005-04-16 15:20:36 -07003183
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003184 ivideo->sisfb_heap.vinfo = ivideo;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003185
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003186 ivideo->sisfb_heap.poha_chain = NULL;
3187 ivideo->sisfb_heap.poh_freelist = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003188
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003189 poh = sisfb_poh_new_node(&ivideo->sisfb_heap);
3190 if(poh == NULL)
3191 return 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003192
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003193 poh->poh_next = &ivideo->sisfb_heap.oh_free;
3194 poh->poh_prev = &ivideo->sisfb_heap.oh_free;
3195 poh->size = ivideo->sisfb_heap_size;
3196 poh->offset = ivideo->heapstart;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003197
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003198 ivideo->sisfb_heap.oh_free.poh_next = poh;
3199 ivideo->sisfb_heap.oh_free.poh_prev = poh;
3200 ivideo->sisfb_heap.oh_free.size = 0;
3201 ivideo->sisfb_heap.max_freesize = poh->size;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003202
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003203 ivideo->sisfb_heap.oh_used.poh_next = &ivideo->sisfb_heap.oh_used;
3204 ivideo->sisfb_heap.oh_used.poh_prev = &ivideo->sisfb_heap.oh_used;
3205 ivideo->sisfb_heap.oh_used.size = SENTINEL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003206
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003207 if(ivideo->cardnumber == 0) {
3208 /* For the first card, make this heap the "global" one
3209 * for old DRM (which could handle only one card)
3210 */
3211 sisfb_heap = &ivideo->sisfb_heap;
3212 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003213
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003214 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003215}
3216
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003217static struct SIS_OH *
3218sisfb_poh_new_node(struct SIS_HEAP *memheap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003219{
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003220 struct SIS_OHALLOC *poha;
3221 struct SIS_OH *poh;
3222 unsigned long cOhs;
3223 int i;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003224
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003225 if(memheap->poh_freelist == NULL) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003226 poha = kmalloc(SIS_OH_ALLOC_SIZE, GFP_KERNEL);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003227 if(!poha)
3228 return NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003229
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003230 poha->poha_next = memheap->poha_chain;
3231 memheap->poha_chain = poha;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003232
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003233 cOhs = (SIS_OH_ALLOC_SIZE - sizeof(struct SIS_OHALLOC)) / sizeof(struct SIS_OH) + 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003234
3235 poh = &poha->aoh[0];
3236 for(i = cOhs - 1; i != 0; i--) {
3237 poh->poh_next = poh + 1;
3238 poh = poh + 1;
3239 }
3240
3241 poh->poh_next = NULL;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003242 memheap->poh_freelist = &poha->aoh[0];
Linus Torvalds1da177e2005-04-16 15:20:36 -07003243 }
3244
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003245 poh = memheap->poh_freelist;
3246 memheap->poh_freelist = poh->poh_next;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003247
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003248 return poh;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003249}
3250
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003251static struct SIS_OH *
3252sisfb_poh_allocate(struct SIS_HEAP *memheap, u32 size)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003253{
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003254 struct SIS_OH *pohThis;
3255 struct SIS_OH *pohRoot;
3256 int bAllocated = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003257
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003258 if(size > memheap->max_freesize) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003259 DPRINTK("sisfb: Can't allocate %dk video memory\n",
3260 (unsigned int) size / 1024);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003261 return NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003262 }
3263
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003264 pohThis = memheap->oh_free.poh_next;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003265
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003266 while(pohThis != &memheap->oh_free) {
3267 if(size <= pohThis->size) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003268 bAllocated = 1;
3269 break;
3270 }
3271 pohThis = pohThis->poh_next;
3272 }
3273
3274 if(!bAllocated) {
3275 DPRINTK("sisfb: Can't allocate %dk video memory\n",
3276 (unsigned int) size / 1024);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003277 return NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003278 }
3279
3280 if(size == pohThis->size) {
3281 pohRoot = pohThis;
3282 sisfb_delete_node(pohThis);
3283 } else {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003284 pohRoot = sisfb_poh_new_node(memheap);
3285 if(pohRoot == NULL)
3286 return NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003287
3288 pohRoot->offset = pohThis->offset;
3289 pohRoot->size = size;
3290
3291 pohThis->offset += size;
3292 pohThis->size -= size;
3293 }
3294
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003295 memheap->max_freesize -= size;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003296
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003297 pohThis = &memheap->oh_used;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003298 sisfb_insert_node(pohThis, pohRoot);
3299
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003300 return pohRoot;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003301}
3302
3303static void
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003304sisfb_delete_node(struct SIS_OH *poh)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003305{
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003306 poh->poh_prev->poh_next = poh->poh_next;
3307 poh->poh_next->poh_prev = poh->poh_prev;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003308}
3309
3310static void
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003311sisfb_insert_node(struct SIS_OH *pohList, struct SIS_OH *poh)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003312{
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003313 struct SIS_OH *pohTemp = pohList->poh_next;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003314
3315 pohList->poh_next = poh;
3316 pohTemp->poh_prev = poh;
3317
3318 poh->poh_prev = pohList;
3319 poh->poh_next = pohTemp;
3320}
3321
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003322static struct SIS_OH *
3323sisfb_poh_free(struct SIS_HEAP *memheap, u32 base)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003324{
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003325 struct SIS_OH *pohThis;
3326 struct SIS_OH *poh_freed;
3327 struct SIS_OH *poh_prev;
3328 struct SIS_OH *poh_next;
3329 u32 ulUpper;
3330 u32 ulLower;
3331 int foundNode = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003332
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003333 poh_freed = memheap->oh_used.poh_next;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003334
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003335 while(poh_freed != &memheap->oh_used) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003336 if(poh_freed->offset == base) {
3337 foundNode = 1;
3338 break;
3339 }
3340
3341 poh_freed = poh_freed->poh_next;
3342 }
3343
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003344 if(!foundNode)
3345 return NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003346
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003347 memheap->max_freesize += poh_freed->size;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003348
3349 poh_prev = poh_next = NULL;
3350 ulUpper = poh_freed->offset + poh_freed->size;
3351 ulLower = poh_freed->offset;
3352
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003353 pohThis = memheap->oh_free.poh_next;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003354
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003355 while(pohThis != &memheap->oh_free) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003356 if(pohThis->offset == ulUpper) {
3357 poh_next = pohThis;
3358 } else if((pohThis->offset + pohThis->size) == ulLower) {
3359 poh_prev = pohThis;
3360 }
3361 pohThis = pohThis->poh_next;
3362 }
3363
3364 sisfb_delete_node(poh_freed);
3365
3366 if(poh_prev && poh_next) {
3367 poh_prev->size += (poh_freed->size + poh_next->size);
3368 sisfb_delete_node(poh_next);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003369 sisfb_free_node(memheap, poh_freed);
3370 sisfb_free_node(memheap, poh_next);
3371 return poh_prev;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003372 }
3373
3374 if(poh_prev) {
3375 poh_prev->size += poh_freed->size;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003376 sisfb_free_node(memheap, poh_freed);
3377 return poh_prev;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003378 }
3379
3380 if(poh_next) {
3381 poh_next->size += poh_freed->size;
3382 poh_next->offset = poh_freed->offset;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003383 sisfb_free_node(memheap, poh_freed);
3384 return poh_next;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003385 }
3386
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003387 sisfb_insert_node(&memheap->oh_free, poh_freed);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003388
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003389 return poh_freed;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003390}
3391
3392static void
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003393sisfb_free_node(struct SIS_HEAP *memheap, struct SIS_OH *poh)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003394{
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003395 if(poh == NULL)
3396 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003397
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003398 poh->poh_next = memheap->poh_freelist;
3399 memheap->poh_freelist = poh;
3400}
3401
3402static void
3403sis_int_malloc(struct sis_video_info *ivideo, struct sis_memreq *req)
3404{
3405 struct SIS_OH *poh = NULL;
3406
3407 if((ivideo) && (ivideo->sisfb_id == SISFB_ID) && (!ivideo->havenoheap))
3408 poh = sisfb_poh_allocate(&ivideo->sisfb_heap, (u32)req->size);
3409
3410 if(poh == NULL) {
3411 req->offset = req->size = 0;
3412 DPRINTK("sisfb: Video RAM allocation failed\n");
3413 } else {
3414 req->offset = poh->offset;
3415 req->size = poh->size;
3416 DPRINTK("sisfb: Video RAM allocation succeeded: 0x%lx\n",
3417 (poh->offset + ivideo->video_vbase));
3418 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003419}
3420
3421void
3422sis_malloc(struct sis_memreq *req)
3423{
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003424 struct sis_video_info *ivideo = sisfb_heap->vinfo;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003425
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003426 if(&ivideo->sisfb_heap == sisfb_heap)
3427 sis_int_malloc(ivideo, req);
3428 else
3429 req->offset = req->size = 0;
3430}
Linus Torvalds1da177e2005-04-16 15:20:36 -07003431
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003432void
3433sis_malloc_new(struct pci_dev *pdev, struct sis_memreq *req)
3434{
3435 struct sis_video_info *ivideo = pci_get_drvdata(pdev);
3436
3437 sis_int_malloc(ivideo, req);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003438}
3439
3440/* sis_free: u32 because "base" is offset inside video ram, can never be >4GB */
3441
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003442static void
3443sis_int_free(struct sis_video_info *ivideo, u32 base)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003444{
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003445 struct SIS_OH *poh;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003446
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003447 if((!ivideo) || (ivideo->sisfb_id != SISFB_ID) || (ivideo->havenoheap))
3448 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003449
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003450 poh = sisfb_poh_free(&ivideo->sisfb_heap, base);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003451
3452 if(poh == NULL) {
3453 DPRINTK("sisfb: sisfb_poh_free() failed at base 0x%x\n",
3454 (unsigned int) base);
3455 }
3456}
3457
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003458void
3459sis_free(u32 base)
3460{
3461 struct sis_video_info *ivideo = sisfb_heap->vinfo;
3462
3463 sis_int_free(ivideo, base);
3464}
3465
3466void
3467sis_free_new(struct pci_dev *pdev, u32 base)
3468{
3469 struct sis_video_info *ivideo = pci_get_drvdata(pdev);
3470
3471 sis_int_free(ivideo, base);
3472}
3473
Linus Torvalds1da177e2005-04-16 15:20:36 -07003474/* --------------------- SetMode routines ------------------------- */
3475
3476static void
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003477sisfb_check_engine_and_sync(struct sis_video_info *ivideo)
3478{
3479 u8 cr30, cr31;
3480
3481 /* Check if MMIO and engines are enabled,
3482 * and sync in case they are. Can't use
3483 * ivideo->accel here, as this might have
3484 * been changed before this is called.
3485 */
3486 inSISIDXREG(SISSR, IND_SIS_PCI_ADDRESS_SET, cr30);
3487 inSISIDXREG(SISSR, IND_SIS_MODULE_ENABLE, cr31);
3488 /* MMIO and 2D/3D engine enabled? */
3489 if((cr30 & SIS_MEM_MAP_IO_ENABLE) && (cr31 & 0x42)) {
3490#ifdef CONFIG_FB_SIS_300
3491 if(ivideo->sisvga_engine == SIS_300_VGA) {
3492 /* Don't care about TurboQueue. It's
3493 * enough to know that the engines
3494 * are enabled
3495 */
3496 sisfb_syncaccel(ivideo);
3497 }
3498#endif
3499#ifdef CONFIG_FB_SIS_315
3500 if(ivideo->sisvga_engine == SIS_315_VGA) {
3501 /* Check that any queue mode is
3502 * enabled, and that the queue
3503 * is not in the state of "reset"
3504 */
3505 inSISIDXREG(SISSR, 0x26, cr30);
3506 if((cr30 & 0xe0) && (!(cr30 & 0x01))) {
3507 sisfb_syncaccel(ivideo);
3508 }
3509 }
3510#endif
3511 }
3512}
3513
3514static void
Linus Torvalds1da177e2005-04-16 15:20:36 -07003515sisfb_pre_setmode(struct sis_video_info *ivideo)
3516{
3517 u8 cr30 = 0, cr31 = 0, cr33 = 0, cr35 = 0, cr38 = 0;
3518 int tvregnum = 0;
3519
3520 ivideo->currentvbflags &= (VB_VIDEOBRIDGE | VB_DISPTYPE_DISP2);
3521
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003522 outSISIDXREG(SISSR, 0x05, 0x86);
3523
Linus Torvalds1da177e2005-04-16 15:20:36 -07003524 inSISIDXREG(SISCR, 0x31, cr31);
3525 cr31 &= ~0x60;
3526 cr31 |= 0x04;
3527
3528 cr33 = ivideo->rate_idx & 0x0F;
3529
3530#ifdef CONFIG_FB_SIS_315
3531 if(ivideo->sisvga_engine == SIS_315_VGA) {
3532 if(ivideo->chip >= SIS_661) {
3533 inSISIDXREG(SISCR, 0x38, cr38);
3534 cr38 &= ~0x07; /* Clear LCDA/DualEdge and YPbPr bits */
3535 } else {
3536 tvregnum = 0x38;
3537 inSISIDXREG(SISCR, tvregnum, cr38);
3538 cr38 &= ~0x3b; /* Clear LCDA/DualEdge and YPbPr bits */
3539 }
3540 }
3541#endif
3542#ifdef CONFIG_FB_SIS_300
3543 if(ivideo->sisvga_engine == SIS_300_VGA) {
3544 tvregnum = 0x35;
3545 inSISIDXREG(SISCR, tvregnum, cr38);
3546 }
3547#endif
3548
Richard Knutssonc30660ea2007-02-12 00:55:06 -08003549 SiS_SetEnableDstn(&ivideo->SiS_Pr, false);
3550 SiS_SetEnableFstn(&ivideo->SiS_Pr, false);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003551 ivideo->curFSTN = ivideo->curDSTN = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003552
3553 switch(ivideo->currentvbflags & VB_DISPTYPE_DISP2) {
3554
3555 case CRT2_TV:
3556 cr38 &= ~0xc0; /* Clear PAL-M / PAL-N bits */
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003557 if((ivideo->vbflags & TV_YPBPR) && (ivideo->vbflags2 & VB2_SISYPBPRBRIDGE)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003558#ifdef CONFIG_FB_SIS_315
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003559 if(ivideo->chip >= SIS_661) {
3560 cr38 |= 0x04;
3561 if(ivideo->vbflags & TV_YPBPR525P) cr35 |= 0x20;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003562 else if(ivideo->vbflags & TV_YPBPR750P) cr35 |= 0x40;
3563 else if(ivideo->vbflags & TV_YPBPR1080I) cr35 |= 0x60;
3564 cr30 |= SIS_SIMULTANEOUS_VIEW_ENABLE;
3565 cr35 &= ~0x01;
3566 ivideo->currentvbflags |= (TV_YPBPR | (ivideo->vbflags & TV_YPBPRALL));
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003567 } else if(ivideo->sisvga_engine == SIS_315_VGA) {
3568 cr30 |= (0x80 | SIS_SIMULTANEOUS_VIEW_ENABLE);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003569 cr38 |= 0x08;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003570 if(ivideo->vbflags & TV_YPBPR525P) cr38 |= 0x10;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003571 else if(ivideo->vbflags & TV_YPBPR750P) cr38 |= 0x20;
3572 else if(ivideo->vbflags & TV_YPBPR1080I) cr38 |= 0x30;
3573 cr31 &= ~0x01;
3574 ivideo->currentvbflags |= (TV_YPBPR | (ivideo->vbflags & TV_YPBPRALL));
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003575 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003576#endif
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003577 } else if((ivideo->vbflags & TV_HIVISION) &&
3578 (ivideo->vbflags2 & VB2_SISHIVISIONBRIDGE)) {
3579 if(ivideo->chip >= SIS_661) {
3580 cr38 |= 0x04;
3581 cr35 |= 0x60;
3582 } else {
3583 cr30 |= 0x80;
3584 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003585 cr30 |= SIS_SIMULTANEOUS_VIEW_ENABLE;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003586 cr31 |= 0x01;
3587 cr35 |= 0x01;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003588 ivideo->currentvbflags |= TV_HIVISION;
3589 } else if(ivideo->vbflags & TV_SCART) {
3590 cr30 = (SIS_VB_OUTPUT_SCART | SIS_SIMULTANEOUS_VIEW_ENABLE);
3591 cr31 |= 0x01;
3592 cr35 |= 0x01;
3593 ivideo->currentvbflags |= TV_SCART;
3594 } else {
3595 if(ivideo->vbflags & TV_SVIDEO) {
3596 cr30 = (SIS_VB_OUTPUT_SVIDEO | SIS_SIMULTANEOUS_VIEW_ENABLE);
3597 ivideo->currentvbflags |= TV_SVIDEO;
3598 }
3599 if(ivideo->vbflags & TV_AVIDEO) {
3600 cr30 = (SIS_VB_OUTPUT_COMPOSITE | SIS_SIMULTANEOUS_VIEW_ENABLE);
3601 ivideo->currentvbflags |= TV_AVIDEO;
3602 }
3603 }
3604 cr31 |= SIS_DRIVER_MODE;
3605
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003606 if(ivideo->vbflags & (TV_AVIDEO | TV_SVIDEO)) {
3607 if(ivideo->vbflags & TV_PAL) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003608 cr31 |= 0x01; cr35 |= 0x01;
3609 ivideo->currentvbflags |= TV_PAL;
3610 if(ivideo->vbflags & TV_PALM) {
3611 cr38 |= 0x40; cr35 |= 0x04;
3612 ivideo->currentvbflags |= TV_PALM;
3613 } else if(ivideo->vbflags & TV_PALN) {
3614 cr38 |= 0x80; cr35 |= 0x08;
3615 ivideo->currentvbflags |= TV_PALN;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003616 }
3617 } else {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003618 cr31 &= ~0x01; cr35 &= ~0x01;
3619 ivideo->currentvbflags |= TV_NTSC;
3620 if(ivideo->vbflags & TV_NTSCJ) {
3621 cr38 |= 0x40; cr35 |= 0x02;
3622 ivideo->currentvbflags |= TV_NTSCJ;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003623 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003624 }
3625 }
3626 break;
3627
3628 case CRT2_LCD:
3629 cr30 = (SIS_VB_OUTPUT_LCD | SIS_SIMULTANEOUS_VIEW_ENABLE);
3630 cr31 |= SIS_DRIVER_MODE;
3631 SiS_SetEnableDstn(&ivideo->SiS_Pr, ivideo->sisfb_dstn);
3632 SiS_SetEnableFstn(&ivideo->SiS_Pr, ivideo->sisfb_fstn);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003633 ivideo->curFSTN = ivideo->sisfb_fstn;
3634 ivideo->curDSTN = ivideo->sisfb_dstn;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003635 break;
3636
3637 case CRT2_VGA:
3638 cr30 = (SIS_VB_OUTPUT_CRT2 | SIS_SIMULTANEOUS_VIEW_ENABLE);
3639 cr31 |= SIS_DRIVER_MODE;
3640 if(ivideo->sisfb_nocrt2rate) {
3641 cr33 |= (sisbios_mode[ivideo->sisfb_mode_idx].rate_idx << 4);
3642 } else {
3643 cr33 |= ((ivideo->rate_idx & 0x0F) << 4);
3644 }
3645 break;
3646
3647 default: /* disable CRT2 */
3648 cr30 = 0x00;
3649 cr31 |= (SIS_DRIVER_MODE | SIS_VB_OUTPUT_DISABLE);
3650 }
3651
3652 outSISIDXREG(SISCR, 0x30, cr30);
3653 outSISIDXREG(SISCR, 0x33, cr33);
3654
3655 if(ivideo->chip >= SIS_661) {
3656#ifdef CONFIG_FB_SIS_315
3657 cr31 &= ~0x01; /* Clear PAL flag (now in CR35) */
3658 setSISIDXREG(SISCR, 0x35, ~0x10, cr35); /* Leave overscan bit alone */
3659 cr38 &= 0x07; /* Use only LCDA and HiVision/YPbPr bits */
3660 setSISIDXREG(SISCR, 0x38, 0xf8, cr38);
3661#endif
3662 } else if(ivideo->chip != SIS_300) {
3663 outSISIDXREG(SISCR, tvregnum, cr38);
3664 }
3665 outSISIDXREG(SISCR, 0x31, cr31);
3666
Linus Torvalds1da177e2005-04-16 15:20:36 -07003667 ivideo->SiS_Pr.SiS_UseOEM = ivideo->sisfb_useoem;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003668
3669 sisfb_check_engine_and_sync(ivideo);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003670}
3671
3672/* Fix SR11 for 661 and later */
3673#ifdef CONFIG_FB_SIS_315
3674static void
3675sisfb_fixup_SR11(struct sis_video_info *ivideo)
3676{
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003677 u8 tmpreg;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003678
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003679 if(ivideo->chip >= SIS_661) {
3680 inSISIDXREG(SISSR,0x11,tmpreg);
3681 if(tmpreg & 0x20) {
3682 inSISIDXREG(SISSR,0x3e,tmpreg);
3683 tmpreg = (tmpreg + 1) & 0xff;
3684 outSISIDXREG(SISSR,0x3e,tmpreg);
3685 inSISIDXREG(SISSR,0x11,tmpreg);
3686 }
3687 if(tmpreg & 0xf0) {
3688 andSISIDXREG(SISSR,0x11,0x0f);
3689 }
3690 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003691}
3692#endif
3693
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003694static void
3695sisfb_set_TVxposoffset(struct sis_video_info *ivideo, int val)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003696{
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003697 if(val > 32) val = 32;
3698 if(val < -32) val = -32;
3699 ivideo->tvxpos = val;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003700
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003701 if(ivideo->sisfblocked) return;
3702 if(!ivideo->modechanged) return;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003703
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003704 if(ivideo->currentvbflags & CRT2_TV) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003705
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003706 if(ivideo->vbflags2 & VB2_CHRONTEL) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003707
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003708 int x = ivideo->tvx;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003709
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003710 switch(ivideo->chronteltype) {
3711 case 1:
3712 x += val;
3713 if(x < 0) x = 0;
3714 outSISIDXREG(SISSR,0x05,0x86);
3715 SiS_SetCH700x(&ivideo->SiS_Pr, 0x0a, (x & 0xff));
3716 SiS_SetCH70xxANDOR(&ivideo->SiS_Pr, 0x08, ((x & 0x0100) >> 7), 0xFD);
3717 break;
3718 case 2:
3719 /* Not supported by hardware */
3720 break;
3721 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003722
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003723 } else if(ivideo->vbflags2 & VB2_SISBRIDGE) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003724
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003725 u8 p2_1f,p2_20,p2_2b,p2_42,p2_43;
3726 unsigned short temp;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003727
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003728 p2_1f = ivideo->p2_1f;
3729 p2_20 = ivideo->p2_20;
3730 p2_2b = ivideo->p2_2b;
3731 p2_42 = ivideo->p2_42;
3732 p2_43 = ivideo->p2_43;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003733
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003734 temp = p2_1f | ((p2_20 & 0xf0) << 4);
3735 temp += (val * 2);
3736 p2_1f = temp & 0xff;
3737 p2_20 = (temp & 0xf00) >> 4;
3738 p2_2b = ((p2_2b & 0x0f) + (val * 2)) & 0x0f;
3739 temp = p2_43 | ((p2_42 & 0xf0) << 4);
3740 temp += (val * 2);
3741 p2_43 = temp & 0xff;
3742 p2_42 = (temp & 0xf00) >> 4;
3743 outSISIDXREG(SISPART2,0x1f,p2_1f);
3744 setSISIDXREG(SISPART2,0x20,0x0F,p2_20);
3745 setSISIDXREG(SISPART2,0x2b,0xF0,p2_2b);
3746 setSISIDXREG(SISPART2,0x42,0x0F,p2_42);
3747 outSISIDXREG(SISPART2,0x43,p2_43);
3748 }
3749 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003750}
3751
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003752static void
3753sisfb_set_TVyposoffset(struct sis_video_info *ivideo, int val)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003754{
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003755 if(val > 32) val = 32;
3756 if(val < -32) val = -32;
3757 ivideo->tvypos = val;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003758
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003759 if(ivideo->sisfblocked) return;
3760 if(!ivideo->modechanged) return;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003761
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003762 if(ivideo->currentvbflags & CRT2_TV) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003763
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003764 if(ivideo->vbflags2 & VB2_CHRONTEL) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003765
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003766 int y = ivideo->tvy;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003767
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003768 switch(ivideo->chronteltype) {
3769 case 1:
3770 y -= val;
3771 if(y < 0) y = 0;
3772 outSISIDXREG(SISSR,0x05,0x86);
3773 SiS_SetCH700x(&ivideo->SiS_Pr, 0x0b, (y & 0xff));
3774 SiS_SetCH70xxANDOR(&ivideo->SiS_Pr, 0x08, ((y & 0x0100) >> 8), 0xFE);
3775 break;
3776 case 2:
3777 /* Not supported by hardware */
3778 break;
3779 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003780
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003781 } else if(ivideo->vbflags2 & VB2_SISBRIDGE) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003782
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003783 char p2_01, p2_02;
3784 val /= 2;
3785 p2_01 = ivideo->p2_01;
3786 p2_02 = ivideo->p2_02;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003787
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003788 p2_01 += val;
3789 p2_02 += val;
3790 if(!(ivideo->currentvbflags & (TV_HIVISION | TV_YPBPR))) {
3791 while((p2_01 <= 0) || (p2_02 <= 0)) {
3792 p2_01 += 2;
3793 p2_02 += 2;
3794 }
3795 }
3796 outSISIDXREG(SISPART2,0x01,p2_01);
3797 outSISIDXREG(SISPART2,0x02,p2_02);
3798 }
3799 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003800}
3801
3802static void
3803sisfb_post_setmode(struct sis_video_info *ivideo)
3804{
Richard Knutssonc30660ea2007-02-12 00:55:06 -08003805 bool crt1isoff = false;
3806 bool doit = true;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003807#if defined(CONFIG_FB_SIS_300) || defined(CONFIG_FB_SIS_315)
3808 u8 reg;
3809#endif
3810#ifdef CONFIG_FB_SIS_315
3811 u8 reg1;
3812#endif
3813
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003814 outSISIDXREG(SISSR, 0x05, 0x86);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003815
3816#ifdef CONFIG_FB_SIS_315
3817 sisfb_fixup_SR11(ivideo);
3818#endif
3819
3820 /* Now we actually HAVE changed the display mode */
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003821 ivideo->modechanged = 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003822
3823 /* We can't switch off CRT1 if bridge is in slave mode */
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003824 if(ivideo->vbflags2 & VB2_VIDEOBRIDGE) {
Richard Knutssonc30660ea2007-02-12 00:55:06 -08003825 if(sisfb_bridgeisslave(ivideo)) doit = false;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003826 } else
3827 ivideo->sisfb_crt1off = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003828
3829#ifdef CONFIG_FB_SIS_300
3830 if(ivideo->sisvga_engine == SIS_300_VGA) {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003831 if((ivideo->sisfb_crt1off) && (doit)) {
Richard Knutssonc30660ea2007-02-12 00:55:06 -08003832 crt1isoff = true;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003833 reg = 0x00;
3834 } else {
Richard Knutssonc30660ea2007-02-12 00:55:06 -08003835 crt1isoff = false;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003836 reg = 0x80;
3837 }
3838 setSISIDXREG(SISCR, 0x17, 0x7f, reg);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003839 }
3840#endif
3841#ifdef CONFIG_FB_SIS_315
3842 if(ivideo->sisvga_engine == SIS_315_VGA) {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003843 if((ivideo->sisfb_crt1off) && (doit)) {
Richard Knutssonc30660ea2007-02-12 00:55:06 -08003844 crt1isoff = true;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003845 reg = 0x40;
3846 reg1 = 0xc0;
3847 } else {
Richard Knutssonc30660ea2007-02-12 00:55:06 -08003848 crt1isoff = false;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003849 reg = 0x00;
3850 reg1 = 0x00;
3851 }
3852 setSISIDXREG(SISCR, ivideo->SiS_Pr.SiS_MyCR63, ~0x40, reg);
3853 setSISIDXREG(SISSR, 0x1f, ~0xc0, reg1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003854 }
3855#endif
3856
3857 if(crt1isoff) {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003858 ivideo->currentvbflags &= ~VB_DISPTYPE_CRT1;
3859 ivideo->currentvbflags |= VB_SINGLE_MODE;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003860 } else {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003861 ivideo->currentvbflags |= VB_DISPTYPE_CRT1;
3862 if(ivideo->currentvbflags & VB_DISPTYPE_CRT2) {
3863 ivideo->currentvbflags |= VB_MIRROR_MODE;
3864 } else {
3865 ivideo->currentvbflags |= VB_SINGLE_MODE;
3866 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003867 }
3868
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003869 andSISIDXREG(SISSR, IND_SIS_RAMDAC_CONTROL, ~0x04);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003870
3871 if(ivideo->currentvbflags & CRT2_TV) {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003872 if(ivideo->vbflags2 & VB2_SISBRIDGE) {
3873 inSISIDXREG(SISPART2,0x1f,ivideo->p2_1f);
3874 inSISIDXREG(SISPART2,0x20,ivideo->p2_20);
3875 inSISIDXREG(SISPART2,0x2b,ivideo->p2_2b);
3876 inSISIDXREG(SISPART2,0x42,ivideo->p2_42);
3877 inSISIDXREG(SISPART2,0x43,ivideo->p2_43);
3878 inSISIDXREG(SISPART2,0x01,ivideo->p2_01);
3879 inSISIDXREG(SISPART2,0x02,ivideo->p2_02);
3880 } else if(ivideo->vbflags2 & VB2_CHRONTEL) {
3881 if(ivideo->chronteltype == 1) {
3882 ivideo->tvx = SiS_GetCH700x(&ivideo->SiS_Pr, 0x0a);
3883 ivideo->tvx |= (((SiS_GetCH700x(&ivideo->SiS_Pr, 0x08) & 0x02) >> 1) << 8);
3884 ivideo->tvy = SiS_GetCH700x(&ivideo->SiS_Pr, 0x0b);
3885 ivideo->tvy |= ((SiS_GetCH700x(&ivideo->SiS_Pr, 0x08) & 0x01) << 8);
3886 }
3887 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003888 }
3889
3890 if(ivideo->tvxpos) {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003891 sisfb_set_TVxposoffset(ivideo, ivideo->tvxpos);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003892 }
3893 if(ivideo->tvypos) {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003894 sisfb_set_TVyposoffset(ivideo, ivideo->tvypos);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003895 }
3896
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003897 /* Eventually sync engines */
3898 sisfb_check_engine_and_sync(ivideo);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003899
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003900 /* (Re-)Initialize chip engines */
3901 if(ivideo->accel) {
3902 sisfb_engine_init(ivideo);
3903 } else {
3904 ivideo->engineok = 0;
3905 }
3906}
Linus Torvalds1da177e2005-04-16 15:20:36 -07003907
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003908static int
3909sisfb_reset_mode(struct sis_video_info *ivideo)
3910{
3911 if(sisfb_set_mode(ivideo, 0))
3912 return 1;
3913
3914 sisfb_set_pitch(ivideo);
3915 sisfb_set_base_CRT1(ivideo, ivideo->current_base);
3916 sisfb_set_base_CRT2(ivideo, ivideo->current_base);
3917
3918 return 0;
3919}
3920
3921static void
3922sisfb_handle_command(struct sis_video_info *ivideo, struct sisfb_cmd *sisfb_command)
3923{
3924 int mycrt1off;
3925
3926 switch(sisfb_command->sisfb_cmd) {
3927 case SISFB_CMD_GETVBFLAGS:
3928 if(!ivideo->modechanged) {
3929 sisfb_command->sisfb_result[0] = SISFB_CMD_ERR_EARLY;
3930 } else {
3931 sisfb_command->sisfb_result[0] = SISFB_CMD_ERR_OK;
3932 sisfb_command->sisfb_result[1] = ivideo->currentvbflags;
3933 sisfb_command->sisfb_result[2] = ivideo->vbflags2;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003934 }
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003935 break;
3936 case SISFB_CMD_SWITCHCRT1:
3937 /* arg[0]: 0 = off, 1 = on, 99 = query */
3938 if(!ivideo->modechanged) {
3939 sisfb_command->sisfb_result[0] = SISFB_CMD_ERR_EARLY;
3940 } else if(sisfb_command->sisfb_arg[0] == 99) {
3941 /* Query */
3942 sisfb_command->sisfb_result[1] = ivideo->sisfb_crt1off ? 0 : 1;
3943 sisfb_command->sisfb_result[0] = SISFB_CMD_ERR_OK;
3944 } else if(ivideo->sisfblocked) {
3945 sisfb_command->sisfb_result[0] = SISFB_CMD_ERR_LOCKED;
3946 } else if((!(ivideo->currentvbflags & CRT2_ENABLE)) &&
3947 (sisfb_command->sisfb_arg[0] == 0)) {
3948 sisfb_command->sisfb_result[0] = SISFB_CMD_ERR_NOCRT2;
3949 } else {
3950 sisfb_command->sisfb_result[0] = SISFB_CMD_ERR_OK;
3951 mycrt1off = sisfb_command->sisfb_arg[0] ? 0 : 1;
3952 if( ((ivideo->currentvbflags & VB_DISPTYPE_CRT1) && mycrt1off) ||
3953 ((!(ivideo->currentvbflags & VB_DISPTYPE_CRT1)) && !mycrt1off) ) {
3954 ivideo->sisfb_crt1off = mycrt1off;
3955 if(sisfb_reset_mode(ivideo)) {
3956 sisfb_command->sisfb_result[0] = SISFB_CMD_ERR_OTHER;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003957 }
3958 }
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003959 sisfb_command->sisfb_result[1] = ivideo->sisfb_crt1off ? 0 : 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003960 }
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003961 break;
3962 /* more to come */
3963 default:
3964 sisfb_command->sisfb_result[0] = SISFB_CMD_ERR_UNKNOWN;
3965 printk(KERN_ERR "sisfb: Unknown command 0x%x\n",
3966 sisfb_command->sisfb_cmd);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003967 }
3968}
3969
3970#ifndef MODULE
Adrian Bunk14aefd12008-07-23 21:31:12 -07003971static int __init sisfb_setup(char *options)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003972{
3973 char *this_opt;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003974
Linus Torvalds1da177e2005-04-16 15:20:36 -07003975 sisfb_setdefaultparms();
3976
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003977 if(!options || !(*options))
Linus Torvalds1da177e2005-04-16 15:20:36 -07003978 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003979
3980 while((this_opt = strsep(&options, ",")) != NULL) {
3981
3982 if(!(*this_opt)) continue;
3983
3984 if(!strnicmp(this_opt, "off", 3)) {
3985 sisfb_off = 1;
3986 } else if(!strnicmp(this_opt, "forcecrt2type:", 14)) {
3987 /* Need to check crt2 type first for fstn/dstn */
3988 sisfb_search_crt2type(this_opt + 14);
3989 } else if(!strnicmp(this_opt, "tvmode:",7)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003990 sisfb_search_tvstd(this_opt + 7);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003991 } else if(!strnicmp(this_opt, "tvstandard:",11)) {
3992 sisfb_search_tvstd(this_opt + 11);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003993 } else if(!strnicmp(this_opt, "mode:", 5)) {
Richard Knutssonc30660ea2007-02-12 00:55:06 -08003994 sisfb_search_mode(this_opt + 5, false);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003995 } else if(!strnicmp(this_opt, "vesa:", 5)) {
Richard Knutssonc30660ea2007-02-12 00:55:06 -08003996 sisfb_search_vesamode(simple_strtoul(this_opt + 5, NULL, 0), false);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003997 } else if(!strnicmp(this_opt, "rate:", 5)) {
3998 sisfb_parm_rate = simple_strtoul(this_opt + 5, NULL, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003999 } else if(!strnicmp(this_opt, "forcecrt1:", 10)) {
4000 sisfb_forcecrt1 = (int)simple_strtoul(this_opt + 10, NULL, 0);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004001 } else if(!strnicmp(this_opt, "mem:",4)) {
4002 sisfb_parm_mem = simple_strtoul(this_opt + 4, NULL, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004003 } else if(!strnicmp(this_opt, "pdc:", 4)) {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004004 sisfb_pdc = simple_strtoul(this_opt + 4, NULL, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004005 } else if(!strnicmp(this_opt, "pdc1:", 5)) {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004006 sisfb_pdca = simple_strtoul(this_opt + 5, NULL, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004007 } else if(!strnicmp(this_opt, "noaccel", 7)) {
4008 sisfb_accel = 0;
4009 } else if(!strnicmp(this_opt, "accel", 5)) {
4010 sisfb_accel = -1;
4011 } else if(!strnicmp(this_opt, "noypan", 6)) {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004012 sisfb_ypan = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004013 } else if(!strnicmp(this_opt, "ypan", 4)) {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004014 sisfb_ypan = -1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004015 } else if(!strnicmp(this_opt, "nomax", 5)) {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004016 sisfb_max = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004017 } else if(!strnicmp(this_opt, "max", 3)) {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004018 sisfb_max = -1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004019 } else if(!strnicmp(this_opt, "userom:", 7)) {
4020 sisfb_userom = (int)simple_strtoul(this_opt + 7, NULL, 0);
4021 } else if(!strnicmp(this_opt, "useoem:", 7)) {
4022 sisfb_useoem = (int)simple_strtoul(this_opt + 7, NULL, 0);
4023 } else if(!strnicmp(this_opt, "nocrt2rate", 10)) {
4024 sisfb_nocrt2rate = 1;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004025 } else if(!strnicmp(this_opt, "scalelcd:", 9)) {
4026 unsigned long temp = 2;
4027 temp = simple_strtoul(this_opt + 9, NULL, 0);
4028 if((temp == 0) || (temp == 1)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004029 sisfb_scalelcd = temp ^ 1;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004030 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004031 } else if(!strnicmp(this_opt, "tvxposoffset:", 13)) {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004032 int temp = 0;
4033 temp = (int)simple_strtol(this_opt + 13, NULL, 0);
4034 if((temp >= -32) && (temp <= 32)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004035 sisfb_tvxposoffset = temp;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004036 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004037 } else if(!strnicmp(this_opt, "tvyposoffset:", 13)) {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004038 int temp = 0;
4039 temp = (int)simple_strtol(this_opt + 13, NULL, 0);
4040 if((temp >= -32) && (temp <= 32)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004041 sisfb_tvyposoffset = temp;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004042 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004043 } else if(!strnicmp(this_opt, "specialtiming:", 14)) {
4044 sisfb_search_specialtiming(this_opt + 14);
4045 } else if(!strnicmp(this_opt, "lvdshl:", 7)) {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004046 int temp = 4;
4047 temp = simple_strtoul(this_opt + 7, NULL, 0);
4048 if((temp >= 0) && (temp <= 3)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004049 sisfb_lvdshl = temp;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004050 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004051 } else if(this_opt[0] >= '0' && this_opt[0] <= '9') {
Richard Knutssonc30660ea2007-02-12 00:55:06 -08004052 sisfb_search_mode(this_opt, true);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004053#if !defined(__i386__) && !defined(__x86_64__)
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004054 } else if(!strnicmp(this_opt, "resetcard", 9)) {
4055 sisfb_resetcard = 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004056 } else if(!strnicmp(this_opt, "videoram:", 9)) {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004057 sisfb_videoram = simple_strtoul(this_opt + 9, NULL, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004058#endif
4059 } else {
4060 printk(KERN_INFO "sisfb: Invalid option %s\n", this_opt);
4061 }
4062
4063 }
4064
Linus Torvalds1da177e2005-04-16 15:20:36 -07004065 return 0;
4066}
4067#endif
4068
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004069static int __devinit
Adrian Bunk14aefd12008-07-23 21:31:12 -07004070sisfb_check_rom(void __iomem *rom_base, struct sis_video_info *ivideo)
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004071{
Adrian Bunk14aefd12008-07-23 21:31:12 -07004072 void __iomem *rom;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004073 int romptr;
4074
4075 if((readb(rom_base) != 0x55) || (readb(rom_base + 1) != 0xaa))
4076 return 0;
4077
4078 romptr = (readb(rom_base + 0x18) | (readb(rom_base + 0x19) << 8));
4079 if(romptr > (0x10000 - 8))
4080 return 0;
4081
4082 rom = rom_base + romptr;
4083
4084 if((readb(rom) != 'P') || (readb(rom + 1) != 'C') ||
4085 (readb(rom + 2) != 'I') || (readb(rom + 3) != 'R'))
4086 return 0;
4087
4088 if((readb(rom + 4) | (readb(rom + 5) << 8)) != ivideo->chip_vendor)
4089 return 0;
4090
4091 if((readb(rom + 6) | (readb(rom + 7) << 8)) != ivideo->chip_id)
4092 return 0;
4093
4094 return 1;
4095}
4096
4097static unsigned char * __devinit
4098sisfb_find_rom(struct pci_dev *pdev)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004099{
4100 struct sis_video_info *ivideo = pci_get_drvdata(pdev);
Adrian Bunk14aefd12008-07-23 21:31:12 -07004101 void __iomem *rom_base;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004102 unsigned char *myrombase = NULL;
4103 u32 temp;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004104 size_t romsize;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004105
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004106 /* First, try the official pci ROM functions (except
4107 * on integrated chipsets which have no ROM).
4108 */
4109
4110 if(!ivideo->nbridge) {
4111
4112 if((rom_base = pci_map_rom(pdev, &romsize))) {
4113
4114 if(sisfb_check_rom(rom_base, ivideo)) {
4115
4116 if((myrombase = vmalloc(65536))) {
4117
4118 /* Work around bug in pci/rom.c: Folks forgot to check
4119 * whether the size retrieved from the BIOS image eventually
4120 * is larger than the mapped size
4121 */
4122 if(pci_resource_len(pdev, PCI_ROM_RESOURCE) < romsize)
4123 romsize = pci_resource_len(pdev, PCI_ROM_RESOURCE);
4124
4125 memcpy_fromio(myrombase, rom_base,
4126 (romsize > 65536) ? 65536 : romsize);
4127 }
4128 }
4129 pci_unmap_rom(pdev, rom_base);
4130 }
4131 }
4132
4133 if(myrombase) return myrombase;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004134
4135 /* Otherwise do it the conventional way. */
Linus Torvalds1da177e2005-04-16 15:20:36 -07004136
4137#if defined(__i386__) || defined(__x86_64__)
4138
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004139 for(temp = 0x000c0000; temp < 0x000f0000; temp += 0x00001000) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004140
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004141 rom_base = ioremap(temp, 65536);
4142 if(!rom_base)
4143 continue;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004144
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004145 if(!sisfb_check_rom(rom_base, ivideo)) {
4146 iounmap(rom_base);
4147 continue;
4148 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004149
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004150 if((myrombase = vmalloc(65536)))
4151 memcpy_fromio(myrombase, rom_base, 65536);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004152
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004153 iounmap(rom_base);
4154 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004155
Linus Torvalds1da177e2005-04-16 15:20:36 -07004156 }
4157
4158#else
4159
4160 pci_read_config_dword(pdev, PCI_ROM_ADDRESS, &temp);
4161 pci_write_config_dword(pdev, PCI_ROM_ADDRESS,
4162 (ivideo->video_base & PCI_ROM_ADDRESS_MASK) | PCI_ROM_ADDRESS_ENABLE);
4163
4164 rom_base = ioremap(ivideo->video_base, 65536);
4165 if(rom_base) {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004166 if(sisfb_check_rom(rom_base, ivideo)) {
4167 if((myrombase = vmalloc(65536)))
4168 memcpy_fromio(myrombase, rom_base, 65536);
4169 }
4170 iounmap(rom_base);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004171 }
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004172
4173 pci_write_config_dword(pdev, PCI_ROM_ADDRESS, temp);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004174
4175#endif
4176
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004177 return myrombase;
4178}
4179
4180static void __devinit
4181sisfb_post_map_vram(struct sis_video_info *ivideo, unsigned int *mapsize,
4182 unsigned int min)
4183{
4184 ivideo->video_vbase = ioremap(ivideo->video_base, (*mapsize));
4185
4186 if(!ivideo->video_vbase) {
4187 printk(KERN_ERR
4188 "sisfb: Unable to map maximum video RAM for size detection\n");
4189 (*mapsize) >>= 1;
4190 while((!(ivideo->video_vbase = ioremap(ivideo->video_base, (*mapsize))))) {
4191 (*mapsize) >>= 1;
4192 if((*mapsize) < (min << 20))
4193 break;
4194 }
4195 if(ivideo->video_vbase) {
4196 printk(KERN_ERR
4197 "sisfb: Video RAM size detection limited to %dMB\n",
4198 (int)((*mapsize) >> 20));
4199 }
4200 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004201}
4202
4203#ifdef CONFIG_FB_SIS_300
4204static int __devinit
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004205sisfb_post_300_buswidth(struct sis_video_info *ivideo)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004206{
Adrian Bunk14aefd12008-07-23 21:31:12 -07004207 void __iomem *FBAddress = ivideo->video_vbase;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004208 unsigned short temp;
4209 unsigned char reg;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004210 int i, j;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004211
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004212 andSISIDXREG(SISSR, 0x15, 0xFB);
4213 orSISIDXREG(SISSR, 0x15, 0x04);
4214 outSISIDXREG(SISSR, 0x13, 0x00);
4215 outSISIDXREG(SISSR, 0x14, 0xBF);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004216
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004217 for(i = 0; i < 2; i++) {
4218 temp = 0x1234;
4219 for(j = 0; j < 4; j++) {
4220 writew(temp, FBAddress);
4221 if(readw(FBAddress) == temp)
4222 break;
4223 orSISIDXREG(SISSR, 0x3c, 0x01);
4224 inSISIDXREG(SISSR, 0x05, reg);
4225 inSISIDXREG(SISSR, 0x05, reg);
4226 andSISIDXREG(SISSR, 0x3c, 0xfe);
4227 inSISIDXREG(SISSR, 0x05, reg);
4228 inSISIDXREG(SISSR, 0x05, reg);
4229 temp++;
4230 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004231 }
4232
4233 writel(0x01234567L, FBAddress);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004234 writel(0x456789ABL, (FBAddress + 4));
4235 writel(0x89ABCDEFL, (FBAddress + 8));
4236 writel(0xCDEF0123L, (FBAddress + 12));
4237
4238 inSISIDXREG(SISSR, 0x3b, reg);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004239 if(reg & 0x01) {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004240 if(readl((FBAddress + 12)) == 0xCDEF0123L)
4241 return 4; /* Channel A 128bit */
Linus Torvalds1da177e2005-04-16 15:20:36 -07004242 }
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004243
4244 if(readl((FBAddress + 4)) == 0x456789ABL)
4245 return 2; /* Channel B 64bit */
4246
4247 return 1; /* 32bit */
4248}
4249
4250static int __devinit
4251sisfb_post_300_rwtest(struct sis_video_info *ivideo, int iteration, int buswidth,
4252 int PseudoRankCapacity, int PseudoAdrPinCount,
4253 unsigned int mapsize)
4254{
Adrian Bunk14aefd12008-07-23 21:31:12 -07004255 void __iomem *FBAddr = ivideo->video_vbase;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004256 unsigned short sr14;
4257 unsigned int k, RankCapacity, PageCapacity, BankNumHigh, BankNumMid;
4258 unsigned int PhysicalAdrOtherPage, PhysicalAdrHigh, PhysicalAdrHalfPage;
4259 static const unsigned short SiS_DRAMType[17][5] = {
4260 {0x0C,0x0A,0x02,0x40,0x39},
4261 {0x0D,0x0A,0x01,0x40,0x48},
4262 {0x0C,0x09,0x02,0x20,0x35},
4263 {0x0D,0x09,0x01,0x20,0x44},
4264 {0x0C,0x08,0x02,0x10,0x31},
4265 {0x0D,0x08,0x01,0x10,0x40},
4266 {0x0C,0x0A,0x01,0x20,0x34},
4267 {0x0C,0x09,0x01,0x08,0x32},
4268 {0x0B,0x08,0x02,0x08,0x21},
4269 {0x0C,0x08,0x01,0x08,0x30},
4270 {0x0A,0x08,0x02,0x04,0x11},
4271 {0x0B,0x0A,0x01,0x10,0x28},
4272 {0x09,0x08,0x02,0x02,0x01},
4273 {0x0B,0x09,0x01,0x08,0x24},
4274 {0x0B,0x08,0x01,0x04,0x20},
4275 {0x0A,0x08,0x01,0x02,0x10},
4276 {0x09,0x08,0x01,0x01,0x00}
4277 };
4278
4279 for(k = 0; k <= 16; k++) {
4280
4281 RankCapacity = buswidth * SiS_DRAMType[k][3];
4282
4283 if(RankCapacity != PseudoRankCapacity)
4284 continue;
4285
4286 if((SiS_DRAMType[k][2] + SiS_DRAMType[k][0]) > PseudoAdrPinCount)
4287 continue;
4288
4289 BankNumHigh = RankCapacity * 16 * iteration - 1;
4290 if(iteration == 3) { /* Rank No */
4291 BankNumMid = RankCapacity * 16 - 1;
4292 } else {
4293 BankNumMid = RankCapacity * 16 * iteration / 2 - 1;
4294 }
4295
4296 PageCapacity = (1 << SiS_DRAMType[k][1]) * buswidth * 4;
4297 PhysicalAdrHigh = BankNumHigh;
4298 PhysicalAdrHalfPage = (PageCapacity / 2 + PhysicalAdrHigh) % PageCapacity;
4299 PhysicalAdrOtherPage = PageCapacity * SiS_DRAMType[k][2] + PhysicalAdrHigh;
4300
4301 andSISIDXREG(SISSR, 0x15, 0xFB); /* Test */
4302 orSISIDXREG(SISSR, 0x15, 0x04); /* Test */
4303 sr14 = (SiS_DRAMType[k][3] * buswidth) - 1;
4304 if(buswidth == 4) sr14 |= 0x80;
4305 else if(buswidth == 2) sr14 |= 0x40;
4306 outSISIDXREG(SISSR, 0x13, SiS_DRAMType[k][4]);
4307 outSISIDXREG(SISSR, 0x14, sr14);
4308
4309 BankNumHigh <<= 16;
4310 BankNumMid <<= 16;
4311
4312 if((BankNumHigh + PhysicalAdrHigh >= mapsize) ||
4313 (BankNumMid + PhysicalAdrHigh >= mapsize) ||
4314 (BankNumHigh + PhysicalAdrHalfPage >= mapsize) ||
4315 (BankNumHigh + PhysicalAdrOtherPage >= mapsize))
4316 continue;
4317
4318 /* Write data */
4319 writew(((unsigned short)PhysicalAdrHigh),
4320 (FBAddr + BankNumHigh + PhysicalAdrHigh));
4321 writew(((unsigned short)BankNumMid),
4322 (FBAddr + BankNumMid + PhysicalAdrHigh));
4323 writew(((unsigned short)PhysicalAdrHalfPage),
4324 (FBAddr + BankNumHigh + PhysicalAdrHalfPage));
4325 writew(((unsigned short)PhysicalAdrOtherPage),
4326 (FBAddr + BankNumHigh + PhysicalAdrOtherPage));
4327
4328 /* Read data */
4329 if(readw(FBAddr + BankNumHigh + PhysicalAdrHigh) == PhysicalAdrHigh)
4330 return 1;
4331 }
4332
4333 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004334}
4335
4336static void __devinit
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004337sisfb_post_300_ramsize(struct pci_dev *pdev, unsigned int mapsize)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004338{
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004339 struct sis_video_info *ivideo = pci_get_drvdata(pdev);
4340 int i, j, buswidth;
4341 int PseudoRankCapacity, PseudoAdrPinCount;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004342
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004343 buswidth = sisfb_post_300_buswidth(ivideo);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004344
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004345 for(i = 6; i >= 0; i--) {
4346 PseudoRankCapacity = 1 << i;
4347 for(j = 4; j >= 1; j--) {
4348 PseudoAdrPinCount = 15 - j;
4349 if((PseudoRankCapacity * j) <= 64) {
4350 if(sisfb_post_300_rwtest(ivideo,
4351 j,
4352 buswidth,
4353 PseudoRankCapacity,
4354 PseudoAdrPinCount,
4355 mapsize))
4356 return;
4357 }
4358 }
4359 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004360}
4361
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004362static void __devinit
4363sisfb_post_sis300(struct pci_dev *pdev)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004364{
4365 struct sis_video_info *ivideo = pci_get_drvdata(pdev);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004366 unsigned char *bios = ivideo->SiS_Pr.VirtualRomBase;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004367 u8 reg, v1, v2, v3, v4, v5, v6, v7, v8;
4368 u16 index, rindex, memtype = 0;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004369 unsigned int mapsize;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004370
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004371 if(!ivideo->SiS_Pr.UseROM)
4372 bios = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004373
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004374 outSISIDXREG(SISSR, 0x05, 0x86);
4375
4376 if(bios) {
4377 if(bios[0x52] & 0x80) {
4378 memtype = bios[0x52];
4379 } else {
4380 inSISIDXREG(SISSR, 0x3a, memtype);
4381 }
4382 memtype &= 0x07;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004383 }
4384
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004385 v3 = 0x80; v6 = 0x80;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004386 if(ivideo->revision_id <= 0x13) {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004387 v1 = 0x44; v2 = 0x42;
4388 v4 = 0x44; v5 = 0x42;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004389 } else {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004390 v1 = 0x68; v2 = 0x43; /* Assume 125Mhz MCLK */
4391 v4 = 0x68; v5 = 0x43; /* Assume 125Mhz ECLK */
4392 if(bios) {
4393 index = memtype * 5;
4394 rindex = index + 0x54;
4395 v1 = bios[rindex++];
4396 v2 = bios[rindex++];
4397 v3 = bios[rindex++];
4398 rindex = index + 0x7c;
4399 v4 = bios[rindex++];
4400 v5 = bios[rindex++];
4401 v6 = bios[rindex++];
4402 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004403 }
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004404 outSISIDXREG(SISSR, 0x28, v1);
4405 outSISIDXREG(SISSR, 0x29, v2);
4406 outSISIDXREG(SISSR, 0x2a, v3);
4407 outSISIDXREG(SISSR, 0x2e, v4);
4408 outSISIDXREG(SISSR, 0x2f, v5);
4409 outSISIDXREG(SISSR, 0x30, v6);
4410
Linus Torvalds1da177e2005-04-16 15:20:36 -07004411 v1 = 0x10;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004412 if(bios)
4413 v1 = bios[0xa4];
4414 outSISIDXREG(SISSR, 0x07, v1); /* DAC speed */
4415
4416 outSISIDXREG(SISSR, 0x11, 0x0f); /* DDC, power save */
4417
Linus Torvalds1da177e2005-04-16 15:20:36 -07004418 v1 = 0x01; v2 = 0x43; v3 = 0x1e; v4 = 0x2a;
4419 v5 = 0x06; v6 = 0x00; v7 = 0x00; v8 = 0x00;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004420 if(bios) {
4421 memtype += 0xa5;
4422 v1 = bios[memtype];
4423 v2 = bios[memtype + 8];
4424 v3 = bios[memtype + 16];
4425 v4 = bios[memtype + 24];
4426 v5 = bios[memtype + 32];
4427 v6 = bios[memtype + 40];
4428 v7 = bios[memtype + 48];
4429 v8 = bios[memtype + 56];
Linus Torvalds1da177e2005-04-16 15:20:36 -07004430 }
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004431 if(ivideo->revision_id >= 0x80)
4432 v3 &= 0xfd;
4433 outSISIDXREG(SISSR, 0x15, v1); /* Ram type (assuming 0, BIOS 0xa5 step 8) */
4434 outSISIDXREG(SISSR, 0x16, v2);
4435 outSISIDXREG(SISSR, 0x17, v3);
4436 outSISIDXREG(SISSR, 0x18, v4);
4437 outSISIDXREG(SISSR, 0x19, v5);
4438 outSISIDXREG(SISSR, 0x1a, v6);
4439 outSISIDXREG(SISSR, 0x1b, v7);
4440 outSISIDXREG(SISSR, 0x1c, v8); /* ---- */
4441 andSISIDXREG(SISSR, 0x15 ,0xfb);
4442 orSISIDXREG(SISSR, 0x15, 0x04);
4443 if(bios) {
4444 if(bios[0x53] & 0x02) {
4445 orSISIDXREG(SISSR, 0x19, 0x20);
4446 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004447 }
4448 v1 = 0x04; /* DAC pedestal (BIOS 0xe5) */
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004449 if(ivideo->revision_id >= 0x80)
4450 v1 |= 0x01;
4451 outSISIDXREG(SISSR, 0x1f, v1);
4452 outSISIDXREG(SISSR, 0x20, 0xa4); /* linear & relocated io & disable a0000 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07004453 v1 = 0xf6; v2 = 0x0d; v3 = 0x00;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004454 if(bios) {
4455 v1 = bios[0xe8];
4456 v2 = bios[0xe9];
4457 v3 = bios[0xea];
Linus Torvalds1da177e2005-04-16 15:20:36 -07004458 }
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004459 outSISIDXREG(SISSR, 0x23, v1);
4460 outSISIDXREG(SISSR, 0x24, v2);
4461 outSISIDXREG(SISSR, 0x25, v3);
4462 outSISIDXREG(SISSR, 0x21, 0x84);
4463 outSISIDXREG(SISSR, 0x22, 0x00);
4464 outSISIDXREG(SISCR, 0x37, 0x00);
4465 orSISIDXREG(SISPART1, 0x24, 0x01); /* unlock crt2 */
4466 outSISIDXREG(SISPART1, 0x00, 0x00);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004467 v1 = 0x40; v2 = 0x11;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004468 if(bios) {
4469 v1 = bios[0xec];
4470 v2 = bios[0xeb];
Linus Torvalds1da177e2005-04-16 15:20:36 -07004471 }
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004472 outSISIDXREG(SISPART1, 0x02, v1);
4473
4474 if(ivideo->revision_id >= 0x80)
4475 v2 &= ~0x01;
4476
4477 inSISIDXREG(SISPART4, 0x00, reg);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004478 if((reg == 1) || (reg == 2)) {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004479 outSISIDXREG(SISCR, 0x37, 0x02);
4480 outSISIDXREG(SISPART2, 0x00, 0x1c);
4481 v4 = 0x00; v5 = 0x00; v6 = 0x10;
4482 if(ivideo->SiS_Pr.UseROM) {
4483 v4 = bios[0xf5];
4484 v5 = bios[0xf6];
4485 v6 = bios[0xf7];
4486 }
4487 outSISIDXREG(SISPART4, 0x0d, v4);
4488 outSISIDXREG(SISPART4, 0x0e, v5);
4489 outSISIDXREG(SISPART4, 0x10, v6);
4490 outSISIDXREG(SISPART4, 0x0f, 0x3f);
4491 inSISIDXREG(SISPART4, 0x01, reg);
4492 if(reg >= 0xb0) {
4493 inSISIDXREG(SISPART4, 0x23, reg);
4494 reg &= 0x20;
4495 reg <<= 1;
4496 outSISIDXREG(SISPART4, 0x23, reg);
4497 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004498 } else {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004499 v2 &= ~0x10;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004500 }
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004501 outSISIDXREG(SISSR, 0x32, v2);
4502
4503 andSISIDXREG(SISPART1, 0x24, 0xfe); /* Lock CRT2 */
4504
4505 inSISIDXREG(SISSR, 0x16, reg);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004506 reg &= 0xc3;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004507 outSISIDXREG(SISCR, 0x35, reg);
4508 outSISIDXREG(SISCR, 0x83, 0x00);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004509#if !defined(__i386__) && !defined(__x86_64__)
4510 if(sisfb_videoram) {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004511 outSISIDXREG(SISSR, 0x13, 0x28); /* ? */
4512 reg = ((sisfb_videoram >> 10) - 1) | 0x40;
4513 outSISIDXREG(SISSR, 0x14, reg);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004514 } else {
4515#endif
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004516 /* Need to map max FB size for finding out about RAM size */
4517 mapsize = 64 << 20;
4518 sisfb_post_map_vram(ivideo, &mapsize, 4);
4519
4520 if(ivideo->video_vbase) {
4521 sisfb_post_300_ramsize(pdev, mapsize);
4522 iounmap(ivideo->video_vbase);
4523 } else {
4524 printk(KERN_DEBUG
4525 "sisfb: Failed to map memory for size detection, assuming 8MB\n");
4526 outSISIDXREG(SISSR, 0x13, 0x28); /* ? */
4527 outSISIDXREG(SISSR, 0x14, 0x47); /* 8MB, 64bit default */
4528 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004529#if !defined(__i386__) && !defined(__x86_64__)
4530 }
4531#endif
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004532 if(bios) {
4533 v1 = bios[0xe6];
4534 v2 = bios[0xe7];
Linus Torvalds1da177e2005-04-16 15:20:36 -07004535 } else {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004536 inSISIDXREG(SISSR, 0x3a, reg);
4537 if((reg & 0x30) == 0x30) {
4538 v1 = 0x04; /* PCI */
4539 v2 = 0x92;
4540 } else {
4541 v1 = 0x14; /* AGP */
4542 v2 = 0xb2;
4543 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004544 }
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004545 outSISIDXREG(SISSR, 0x21, v1);
4546 outSISIDXREG(SISSR, 0x22, v2);
4547
4548 /* Sense CRT1 */
4549 sisfb_sense_crt1(ivideo);
4550
4551 /* Set default mode, don't clear screen */
Richard Knutssonc30660ea2007-02-12 00:55:06 -08004552 ivideo->SiS_Pr.SiS_UseOEM = false;
4553 SiS_SetEnableDstn(&ivideo->SiS_Pr, false);
4554 SiS_SetEnableFstn(&ivideo->SiS_Pr, false);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004555 ivideo->curFSTN = ivideo->curDSTN = 0;
4556 ivideo->SiS_Pr.VideoMemorySize = 8 << 20;
4557 SiSSetMode(&ivideo->SiS_Pr, 0x2e | 0x80);
4558
4559 outSISIDXREG(SISSR, 0x05, 0x86);
4560
4561 /* Display off */
4562 orSISIDXREG(SISSR, 0x01, 0x20);
4563
4564 /* Save mode number in CR34 */
4565 outSISIDXREG(SISCR, 0x34, 0x2e);
4566
4567 /* Let everyone know what the current mode is */
4568 ivideo->modeprechange = 0x2e;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004569}
4570#endif
4571
4572#ifdef CONFIG_FB_SIS_315
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004573#if 0
4574static void __devinit
4575sisfb_post_sis315330(struct pci_dev *pdev)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004576{
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004577 /* TODO */
Linus Torvalds1da177e2005-04-16 15:20:36 -07004578}
4579#endif
4580
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004581static void __devinit
4582sisfb_post_xgi_delay(struct sis_video_info *ivideo, int delay)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004583{
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004584 unsigned int i;
4585 u8 reg;
4586
4587 for(i = 0; i <= (delay * 10 * 36); i++) {
4588 inSISIDXREG(SISSR, 0x05, reg);
4589 reg++;
4590 }
4591}
4592
4593static int __devinit
4594sisfb_find_host_bridge(struct sis_video_info *ivideo, struct pci_dev *mypdev,
4595 unsigned short pcivendor)
4596{
4597 struct pci_dev *pdev = NULL;
4598 unsigned short temp;
4599 int ret = 0;
4600
Adrian Bunk0959f0c2007-05-08 00:39:50 -07004601 while((pdev = pci_get_class(PCI_CLASS_BRIDGE_HOST, pdev))) {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004602 temp = pdev->vendor;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004603 if(temp == pcivendor) {
4604 ret = 1;
Julia Lawallea237a62008-02-06 01:39:07 -08004605 pci_dev_put(pdev);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004606 break;
4607 }
4608 }
4609
4610 return ret;
4611}
4612
4613static int __devinit
4614sisfb_post_xgi_rwtest(struct sis_video_info *ivideo, int starta,
4615 unsigned int enda, unsigned int mapsize)
4616{
4617 unsigned int pos;
4618 int i;
4619
4620 writel(0, ivideo->video_vbase);
4621
4622 for(i = starta; i <= enda; i++) {
4623 pos = 1 << i;
4624 if(pos < mapsize)
4625 writel(pos, ivideo->video_vbase + pos);
4626 }
4627
4628 sisfb_post_xgi_delay(ivideo, 150);
4629
4630 if(readl(ivideo->video_vbase) != 0)
4631 return 0;
4632
4633 for(i = starta; i <= enda; i++) {
4634 pos = 1 << i;
4635 if(pos < mapsize) {
4636 if(readl(ivideo->video_vbase + pos) != pos)
4637 return 0;
4638 } else
4639 return 0;
4640 }
4641
4642 return 1;
4643}
4644
4645static void __devinit
4646sisfb_post_xgi_ramsize(struct sis_video_info *ivideo)
4647{
4648 unsigned int buswidth, ranksize, channelab, mapsize;
4649 int i, j, k, l;
4650 u8 reg, sr14;
4651 static const u8 dramsr13[12 * 5] = {
4652 0x02, 0x0e, 0x0b, 0x80, 0x5d,
4653 0x02, 0x0e, 0x0a, 0x40, 0x59,
4654 0x02, 0x0d, 0x0b, 0x40, 0x4d,
4655 0x02, 0x0e, 0x09, 0x20, 0x55,
4656 0x02, 0x0d, 0x0a, 0x20, 0x49,
4657 0x02, 0x0c, 0x0b, 0x20, 0x3d,
4658 0x02, 0x0e, 0x08, 0x10, 0x51,
4659 0x02, 0x0d, 0x09, 0x10, 0x45,
4660 0x02, 0x0c, 0x0a, 0x10, 0x39,
4661 0x02, 0x0d, 0x08, 0x08, 0x41,
4662 0x02, 0x0c, 0x09, 0x08, 0x35,
4663 0x02, 0x0c, 0x08, 0x04, 0x31
4664 };
4665 static const u8 dramsr13_4[4 * 5] = {
4666 0x02, 0x0d, 0x09, 0x40, 0x45,
4667 0x02, 0x0c, 0x09, 0x20, 0x35,
4668 0x02, 0x0c, 0x08, 0x10, 0x31,
4669 0x02, 0x0b, 0x08, 0x08, 0x21
4670 };
4671
4672 /* Enable linear mode, disable 0xa0000 address decoding */
4673 /* We disable a0000 address decoding, because
4674 * - if running on x86, if the card is disabled, it means
4675 * that another card is in the system. We don't want
4676 * to interphere with that primary card's textmode.
4677 * - if running on non-x86, there usually is no VGA window
4678 * at a0000.
4679 */
4680 orSISIDXREG(SISSR, 0x20, (0x80 | 0x04));
4681
4682 /* Need to map max FB size for finding out about RAM size */
4683 mapsize = 256 << 20;
4684 sisfb_post_map_vram(ivideo, &mapsize, 32);
4685
4686 if(!ivideo->video_vbase) {
4687 printk(KERN_ERR "sisfb: Unable to detect RAM size. Setting default.\n");
4688 outSISIDXREG(SISSR, 0x13, 0x35);
4689 outSISIDXREG(SISSR, 0x14, 0x41);
4690 /* TODO */
4691 return;
4692 }
4693
4694 /* Non-interleaving */
4695 outSISIDXREG(SISSR, 0x15, 0x00);
4696 /* No tiling */
4697 outSISIDXREG(SISSR, 0x1c, 0x00);
4698
4699 if(ivideo->chip == XGI_20) {
4700
4701 channelab = 1;
4702 inSISIDXREG(SISCR, 0x97, reg);
4703 if(!(reg & 0x01)) { /* Single 32/16 */
4704 buswidth = 32;
4705 outSISIDXREG(SISSR, 0x13, 0xb1);
4706 outSISIDXREG(SISSR, 0x14, 0x52);
4707 sisfb_post_xgi_delay(ivideo, 1);
4708 sr14 = 0x02;
4709 if(sisfb_post_xgi_rwtest(ivideo, 23, 24, mapsize))
4710 goto bail_out;
4711
4712 outSISIDXREG(SISSR, 0x13, 0x31);
4713 outSISIDXREG(SISSR, 0x14, 0x42);
4714 sisfb_post_xgi_delay(ivideo, 1);
4715 if(sisfb_post_xgi_rwtest(ivideo, 23, 23, mapsize))
4716 goto bail_out;
4717
4718 buswidth = 16;
4719 outSISIDXREG(SISSR, 0x13, 0xb1);
4720 outSISIDXREG(SISSR, 0x14, 0x41);
4721 sisfb_post_xgi_delay(ivideo, 1);
4722 sr14 = 0x01;
4723 if(sisfb_post_xgi_rwtest(ivideo, 22, 23, mapsize))
4724 goto bail_out;
4725 else
4726 outSISIDXREG(SISSR, 0x13, 0x31);
4727 } else { /* Dual 16/8 */
4728 buswidth = 16;
4729 outSISIDXREG(SISSR, 0x13, 0xb1);
4730 outSISIDXREG(SISSR, 0x14, 0x41);
4731 sisfb_post_xgi_delay(ivideo, 1);
4732 sr14 = 0x01;
4733 if(sisfb_post_xgi_rwtest(ivideo, 22, 23, mapsize))
4734 goto bail_out;
4735
4736 outSISIDXREG(SISSR, 0x13, 0x31);
4737 outSISIDXREG(SISSR, 0x14, 0x31);
4738 sisfb_post_xgi_delay(ivideo, 1);
4739 if(sisfb_post_xgi_rwtest(ivideo, 22, 22, mapsize))
4740 goto bail_out;
4741
4742 buswidth = 8;
4743 outSISIDXREG(SISSR, 0x13, 0xb1);
4744 outSISIDXREG(SISSR, 0x14, 0x30);
4745 sisfb_post_xgi_delay(ivideo, 1);
4746 sr14 = 0x00;
4747 if(sisfb_post_xgi_rwtest(ivideo, 21, 22, mapsize))
4748 goto bail_out;
4749 else
4750 outSISIDXREG(SISSR, 0x13, 0x31);
4751 }
4752
4753 } else { /* XGI_40 */
4754
4755 inSISIDXREG(SISCR, 0x97, reg);
4756 if(!(reg & 0x10)) {
4757 inSISIDXREG(SISSR, 0x39, reg);
4758 reg >>= 1;
4759 }
4760
4761 if(reg & 0x01) { /* DDRII */
4762 buswidth = 32;
4763 if(ivideo->revision_id == 2) {
4764 channelab = 2;
4765 outSISIDXREG(SISSR, 0x13, 0xa1);
4766 outSISIDXREG(SISSR, 0x14, 0x44);
4767 sr14 = 0x04;
4768 sisfb_post_xgi_delay(ivideo, 1);
4769 if(sisfb_post_xgi_rwtest(ivideo, 23, 24, mapsize))
4770 goto bail_out;
4771
4772 outSISIDXREG(SISSR, 0x13, 0x21);
4773 outSISIDXREG(SISSR, 0x14, 0x34);
4774 if(sisfb_post_xgi_rwtest(ivideo, 22, 23, mapsize))
4775 goto bail_out;
4776
4777 channelab = 1;
4778 outSISIDXREG(SISSR, 0x13, 0xa1);
4779 outSISIDXREG(SISSR, 0x14, 0x40);
4780 sr14 = 0x00;
4781 if(sisfb_post_xgi_rwtest(ivideo, 22, 23, mapsize))
4782 goto bail_out;
4783
4784 outSISIDXREG(SISSR, 0x13, 0x21);
4785 outSISIDXREG(SISSR, 0x14, 0x30);
4786 } else {
4787 channelab = 3;
4788 outSISIDXREG(SISSR, 0x13, 0xa1);
4789 outSISIDXREG(SISSR, 0x14, 0x4c);
4790 sr14 = 0x0c;
4791 sisfb_post_xgi_delay(ivideo, 1);
4792 if(sisfb_post_xgi_rwtest(ivideo, 23, 25, mapsize))
4793 goto bail_out;
4794
4795 channelab = 2;
4796 outSISIDXREG(SISSR, 0x14, 0x48);
4797 sisfb_post_xgi_delay(ivideo, 1);
4798 sr14 = 0x08;
4799 if(sisfb_post_xgi_rwtest(ivideo, 23, 24, mapsize))
4800 goto bail_out;
4801
4802 outSISIDXREG(SISSR, 0x13, 0x21);
4803 outSISIDXREG(SISSR, 0x14, 0x3c);
4804 sr14 = 0x0c;
4805
4806 if(sisfb_post_xgi_rwtest(ivideo, 23, 24, mapsize)) {
4807 channelab = 3;
4808 } else {
4809 channelab = 2;
4810 outSISIDXREG(SISSR, 0x14, 0x38);
4811 sr14 = 0x08;
4812 }
4813 }
4814 sisfb_post_xgi_delay(ivideo, 1);
4815
4816 } else { /* DDR */
4817
4818 buswidth = 64;
4819 if(ivideo->revision_id == 2) {
4820 channelab = 1;
4821 outSISIDXREG(SISSR, 0x13, 0xa1);
4822 outSISIDXREG(SISSR, 0x14, 0x52);
4823 sisfb_post_xgi_delay(ivideo, 1);
4824 sr14 = 0x02;
4825 if(sisfb_post_xgi_rwtest(ivideo, 23, 24, mapsize))
4826 goto bail_out;
4827
4828 outSISIDXREG(SISSR, 0x13, 0x21);
4829 outSISIDXREG(SISSR, 0x14, 0x42);
4830 } else {
4831 channelab = 2;
4832 outSISIDXREG(SISSR, 0x13, 0xa1);
4833 outSISIDXREG(SISSR, 0x14, 0x5a);
4834 sisfb_post_xgi_delay(ivideo, 1);
4835 sr14 = 0x0a;
4836 if(sisfb_post_xgi_rwtest(ivideo, 24, 25, mapsize))
4837 goto bail_out;
4838
4839 outSISIDXREG(SISSR, 0x13, 0x21);
4840 outSISIDXREG(SISSR, 0x14, 0x4a);
4841 }
4842 sisfb_post_xgi_delay(ivideo, 1);
4843
4844 }
4845 }
4846
4847bail_out:
4848 setSISIDXREG(SISSR, 0x14, 0xf0, sr14);
4849 sisfb_post_xgi_delay(ivideo, 1);
4850
4851 j = (ivideo->chip == XGI_20) ? 5 : 9;
4852 k = (ivideo->chip == XGI_20) ? 12 : 4;
4853
4854 for(i = 0; i < k; i++) {
4855
4856 reg = (ivideo->chip == XGI_20) ?
4857 dramsr13[(i * 5) + 4] : dramsr13_4[(i * 5) + 4];
4858 setSISIDXREG(SISSR, 0x13, 0x80, reg);
4859 sisfb_post_xgi_delay(ivideo, 50);
4860
4861 ranksize = (ivideo->chip == XGI_20) ?
4862 dramsr13[(i * 5) + 3] : dramsr13_4[(i * 5) + 3];
4863
4864 inSISIDXREG(SISSR, 0x13, reg);
4865 if(reg & 0x80) ranksize <<= 1;
4866
4867 if(ivideo->chip == XGI_20) {
4868 if(buswidth == 16) ranksize <<= 1;
4869 else if(buswidth == 32) ranksize <<= 2;
4870 } else {
4871 if(buswidth == 64) ranksize <<= 1;
4872 }
4873
4874 reg = 0;
4875 l = channelab;
4876 if(l == 3) l = 4;
4877 if((ranksize * l) <= 256) {
4878 while((ranksize >>= 1)) reg += 0x10;
4879 }
4880
4881 if(!reg) continue;
4882
4883 setSISIDXREG(SISSR, 0x14, 0x0f, (reg & 0xf0));
4884 sisfb_post_xgi_delay(ivideo, 1);
4885
4886 if(sisfb_post_xgi_rwtest(ivideo, j, ((reg >> 4) + channelab - 2 + 20), mapsize))
4887 break;
4888 }
4889
4890 iounmap(ivideo->video_vbase);
4891}
4892
4893static void __devinit
4894sisfb_post_xgi_setclocks(struct sis_video_info *ivideo, u8 regb)
4895{
4896 u8 v1, v2, v3;
4897 int index;
4898 static const u8 cs90[8 * 3] = {
4899 0x16, 0x01, 0x01,
4900 0x3e, 0x03, 0x01,
4901 0x7c, 0x08, 0x01,
4902 0x79, 0x06, 0x01,
4903 0x29, 0x01, 0x81,
4904 0x5c, 0x23, 0x01,
4905 0x5c, 0x23, 0x01,
4906 0x5c, 0x23, 0x01
4907 };
4908 static const u8 csb8[8 * 3] = {
4909 0x5c, 0x23, 0x01,
4910 0x29, 0x01, 0x01,
4911 0x7c, 0x08, 0x01,
4912 0x79, 0x06, 0x01,
4913 0x29, 0x01, 0x81,
4914 0x5c, 0x23, 0x01,
4915 0x5c, 0x23, 0x01,
4916 0x5c, 0x23, 0x01
4917 };
4918
4919 regb = 0; /* ! */
4920
4921 index = regb * 3;
4922 v1 = cs90[index]; v2 = cs90[index + 1]; v3 = cs90[index + 2];
4923 if(ivideo->haveXGIROM) {
4924 v1 = ivideo->bios_abase[0x90 + index];
4925 v2 = ivideo->bios_abase[0x90 + index + 1];
4926 v3 = ivideo->bios_abase[0x90 + index + 2];
4927 }
4928 outSISIDXREG(SISSR, 0x28, v1);
4929 outSISIDXREG(SISSR, 0x29, v2);
4930 outSISIDXREG(SISSR, 0x2a, v3);
4931 sisfb_post_xgi_delay(ivideo, 0x43);
4932 sisfb_post_xgi_delay(ivideo, 0x43);
4933 sisfb_post_xgi_delay(ivideo, 0x43);
4934 index = regb * 3;
4935 v1 = csb8[index]; v2 = csb8[index + 1]; v3 = csb8[index + 2];
4936 if(ivideo->haveXGIROM) {
4937 v1 = ivideo->bios_abase[0xb8 + index];
4938 v2 = ivideo->bios_abase[0xb8 + index + 1];
4939 v3 = ivideo->bios_abase[0xb8 + index + 2];
4940 }
4941 outSISIDXREG(SISSR, 0x2e, v1);
4942 outSISIDXREG(SISSR, 0x2f, v2);
4943 outSISIDXREG(SISSR, 0x30, v3);
4944 sisfb_post_xgi_delay(ivideo, 0x43);
4945 sisfb_post_xgi_delay(ivideo, 0x43);
4946 sisfb_post_xgi_delay(ivideo, 0x43);
4947}
4948
4949static int __devinit
4950sisfb_post_xgi(struct pci_dev *pdev)
4951{
4952 struct sis_video_info *ivideo = pci_get_drvdata(pdev);
4953 unsigned char *bios = ivideo->bios_abase;
4954 struct pci_dev *mypdev = NULL;
4955 const u8 *ptr, *ptr2;
4956 u8 v1, v2, v3, v4, v5, reg, ramtype;
4957 u32 rega, regb, regd;
4958 int i, j, k, index;
4959 static const u8 cs78[3] = { 0xf6, 0x0d, 0x00 };
4960 static const u8 cs76[2] = { 0xa3, 0xfb };
4961 static const u8 cs7b[3] = { 0xc0, 0x11, 0x00 };
4962 static const u8 cs158[8] = {
4963 0x88, 0xaa, 0x48, 0x00, 0x00, 0x00, 0x00, 0x00
4964 };
4965 static const u8 cs160[8] = {
4966 0x44, 0x77, 0x77, 0x00, 0x00, 0x00, 0x00, 0x00
4967 };
4968 static const u8 cs168[8] = {
4969 0x48, 0x78, 0x88, 0x00, 0x00, 0x00, 0x00, 0x00
4970 };
4971 static const u8 cs128[3 * 8] = {
4972 0x90, 0x28, 0x24, 0x00, 0x00, 0x00, 0x00, 0x00,
4973 0x77, 0x44, 0x44, 0x00, 0x00, 0x00, 0x00, 0x00,
4974 0x77, 0x44, 0x44, 0x00, 0x00, 0x00, 0x00, 0x00
4975 };
4976 static const u8 cs148[2 * 8] = {
4977 0x55, 0x55, 0x55, 0x00, 0x00, 0x00, 0x00, 0x00,
4978 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
4979 };
4980 static const u8 cs31a[8 * 4] = {
4981 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
4982 0xaa, 0xaa, 0xaa, 0xaa, 0x00, 0x00, 0x00, 0x00,
4983 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
4984 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
4985 };
4986 static const u8 cs33a[8 * 4] = {
4987 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
4988 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
4989 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
4990 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
4991 };
4992 static const u8 cs45a[8 * 2] = {
4993 0x00, 0x00, 0xa0, 0x00, 0xa0, 0x00, 0x00, 0x00,
4994 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
4995 };
4996 static const u8 cs170[7 * 8] = {
4997 0x54, 0x32, 0x44, 0x00, 0x00, 0x00, 0x00, 0x00,
4998 0x54, 0x43, 0x44, 0x00, 0x00, 0x00, 0x00, 0x00,
4999 0x0a, 0x05, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00,
5000 0x44, 0x34, 0x44, 0x00, 0x00, 0x00, 0x00, 0x00,
5001 0x10, 0x0a, 0x0a, 0x00, 0x00, 0x00, 0x00, 0x00,
5002 0x11, 0x0c, 0x0c, 0x00, 0x00, 0x00, 0x00, 0x00,
5003 0x05, 0x05, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00
5004 };
5005 static const u8 cs1a8[3 * 8] = {
5006 0xf0, 0xf0, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x00,
5007 0x05, 0x02, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00,
5008 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
5009 };
5010 static const u8 cs100[2 * 8] = {
5011 0xc4, 0x04, 0x84, 0x00, 0x00, 0x00, 0x00, 0x00,
5012 0xc4, 0x04, 0x84, 0x00, 0x00, 0x00, 0x00, 0x00
5013 };
5014
5015 /* VGA enable */
5016 reg = inSISREG(SISVGAENABLE) | 0x01;
5017 outSISREG(SISVGAENABLE, reg);
5018
5019 /* Misc */
5020 reg = inSISREG(SISMISCR) | 0x01;
5021 outSISREG(SISMISCW, reg);
5022
5023 /* Unlock SR */
5024 outSISIDXREG(SISSR, 0x05, 0x86);
5025 inSISIDXREG(SISSR, 0x05, reg);
5026 if(reg != 0xa1)
5027 return 0;
5028
5029 /* Clear some regs */
5030 for(i = 0; i < 0x22; i++) {
5031 if(0x06 + i == 0x20) continue;
5032 outSISIDXREG(SISSR, 0x06 + i, 0x00);
5033 }
5034 for(i = 0; i < 0x0b; i++) {
5035 outSISIDXREG(SISSR, 0x31 + i, 0x00);
5036 }
5037 for(i = 0; i < 0x10; i++) {
5038 outSISIDXREG(SISCR, 0x30 + i, 0x00);
5039 }
5040
5041 ptr = cs78;
5042 if(ivideo->haveXGIROM) {
5043 ptr = (const u8 *)&bios[0x78];
5044 }
5045 for(i = 0; i < 3; i++) {
5046 outSISIDXREG(SISSR, 0x23 + i, ptr[i]);
5047 }
5048
5049 ptr = cs76;
5050 if(ivideo->haveXGIROM) {
5051 ptr = (const u8 *)&bios[0x76];
5052 }
5053 for(i = 0; i < 2; i++) {
5054 outSISIDXREG(SISSR, 0x21 + i, ptr[i]);
5055 }
5056
5057 v1 = 0x18; v2 = 0x00;
5058 if(ivideo->haveXGIROM) {
5059 v1 = bios[0x74];
5060 v2 = bios[0x75];
5061 }
5062 outSISIDXREG(SISSR, 0x07, v1);
5063 outSISIDXREG(SISSR, 0x11, 0x0f);
5064 outSISIDXREG(SISSR, 0x1f, v2);
5065 /* PCI linear mode, RelIO enabled, A0000 decoding disabled */
5066 outSISIDXREG(SISSR, 0x20, 0x80 | 0x20 | 0x04);
5067 outSISIDXREG(SISSR, 0x27, 0x74);
5068
5069 ptr = cs7b;
5070 if(ivideo->haveXGIROM) {
5071 ptr = (const u8 *)&bios[0x7b];
5072 }
5073 for(i = 0; i < 3; i++) {
5074 outSISIDXREG(SISSR, 0x31 + i, ptr[i]);
5075 }
5076
5077 if(ivideo->chip == XGI_40) {
5078 if(ivideo->revision_id == 2) {
5079 setSISIDXREG(SISSR, 0x3b, 0x3f, 0xc0);
5080 }
5081 outSISIDXREG(SISCR, 0x7d, 0xfe);
5082 outSISIDXREG(SISCR, 0x7e, 0x0f);
5083 }
5084 if(ivideo->revision_id == 0) { /* 40 *and* 20? */
5085 andSISIDXREG(SISCR, 0x58, 0xd7);
5086 inSISIDXREG(SISCR, 0xcb, reg);
5087 if(reg & 0x20) {
5088 setSISIDXREG(SISCR, 0x58, 0xd7, (reg & 0x10) ? 0x08 : 0x20); /* =0x28 Z7 ? */
5089 }
5090 }
5091
5092 reg = (ivideo->chip == XGI_40) ? 0x20 : 0x00;
5093 setSISIDXREG(SISCR, 0x38, 0x1f, reg);
5094
5095 if(ivideo->chip == XGI_20) {
5096 outSISIDXREG(SISSR, 0x36, 0x70);
5097 } else {
5098 outSISIDXREG(SISVID, 0x00, 0x86);
5099 outSISIDXREG(SISVID, 0x32, 0x00);
5100 outSISIDXREG(SISVID, 0x30, 0x00);
5101 outSISIDXREG(SISVID, 0x32, 0x01);
5102 outSISIDXREG(SISVID, 0x30, 0x00);
5103 andSISIDXREG(SISVID, 0x2f, 0xdf);
5104 andSISIDXREG(SISCAP, 0x00, 0x3f);
5105
5106 outSISIDXREG(SISPART1, 0x2f, 0x01);
5107 outSISIDXREG(SISPART1, 0x00, 0x00);
5108 outSISIDXREG(SISPART1, 0x02, bios[0x7e]);
5109 outSISIDXREG(SISPART1, 0x2e, 0x08);
5110 andSISIDXREG(SISPART1, 0x35, 0x7f);
5111 andSISIDXREG(SISPART1, 0x50, 0xfe);
5112
5113 inSISIDXREG(SISPART4, 0x00, reg);
5114 if(reg == 1 || reg == 2) {
5115 outSISIDXREG(SISPART2, 0x00, 0x1c);
5116 outSISIDXREG(SISPART4, 0x0d, bios[0x7f]);
5117 outSISIDXREG(SISPART4, 0x0e, bios[0x80]);
5118 outSISIDXREG(SISPART4, 0x10, bios[0x81]);
5119 andSISIDXREG(SISPART4, 0x0f, 0x3f);
5120
5121 inSISIDXREG(SISPART4, 0x01, reg);
5122 if((reg & 0xf0) >= 0xb0) {
5123 inSISIDXREG(SISPART4, 0x23, reg);
5124 if(reg & 0x20) reg |= 0x40;
5125 outSISIDXREG(SISPART4, 0x23, reg);
5126 reg = (reg & 0x20) ? 0x02 : 0x00;
5127 setSISIDXREG(SISPART1, 0x1e, 0xfd, reg);
5128 }
5129 }
5130
5131 v1 = bios[0x77];
5132
5133 inSISIDXREG(SISSR, 0x3b, reg);
5134 if(reg & 0x02) {
5135 inSISIDXREG(SISSR, 0x3a, reg);
5136 v2 = (reg & 0x30) >> 3;
5137 if(!(v2 & 0x04)) v2 ^= 0x02;
5138 inSISIDXREG(SISSR, 0x39, reg);
5139 if(reg & 0x80) v2 |= 0x80;
5140 v2 |= 0x01;
5141
Adrian Bunk0959f0c2007-05-08 00:39:50 -07005142 if((mypdev = pci_get_device(PCI_VENDOR_ID_SI, 0x0730, NULL))) {
5143 pci_dev_put(mypdev);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07005144 if(((v2 & 0x06) == 2) || ((v2 & 0x06) == 4))
5145 v2 &= 0xf9;
5146 v2 |= 0x08;
5147 v1 &= 0xfe;
5148 } else {
Adrian Bunk0959f0c2007-05-08 00:39:50 -07005149 mypdev = pci_get_device(PCI_VENDOR_ID_SI, 0x0735, 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, 0x0645, NULL);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07005152 if(!mypdev)
Adrian Bunk0959f0c2007-05-08 00:39:50 -07005153 mypdev = pci_get_device(PCI_VENDOR_ID_SI, 0x0650, NULL);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07005154 if(mypdev) {
5155 pci_read_config_dword(mypdev, 0x94, &regd);
5156 regd &= 0xfffffeff;
5157 pci_write_config_dword(mypdev, 0x94, regd);
5158 v1 &= 0xfe;
Adrian Bunk0959f0c2007-05-08 00:39:50 -07005159 pci_dev_put(mypdev);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07005160 } else if(sisfb_find_host_bridge(ivideo, pdev, PCI_VENDOR_ID_SI)) {
5161 v1 &= 0xfe;
5162 } else if(sisfb_find_host_bridge(ivideo, pdev, 0x1106) ||
5163 sisfb_find_host_bridge(ivideo, pdev, 0x1022) ||
5164 sisfb_find_host_bridge(ivideo, pdev, 0x700e) ||
5165 sisfb_find_host_bridge(ivideo, pdev, 0x10de)) {
5166 if((v2 & 0x06) == 4)
5167 v2 ^= 0x06;
5168 v2 |= 0x08;
5169 }
5170 }
5171 setSISIDXREG(SISCR, 0x5f, 0xf0, v2);
5172 }
5173 outSISIDXREG(SISSR, 0x22, v1);
5174
5175 if(ivideo->revision_id == 2) {
5176 inSISIDXREG(SISSR, 0x3b, v1);
5177 inSISIDXREG(SISSR, 0x3a, v2);
5178 regd = bios[0x90 + 3] | (bios[0x90 + 4] << 8);
5179 if( (!(v1 & 0x02)) && (v2 & 0x30) && (regd < 0xcf) )
5180 setSISIDXREG(SISCR, 0x5f, 0xf1, 0x01);
5181
Adrian Bunk0959f0c2007-05-08 00:39:50 -07005182 if((mypdev = pci_get_device(0x10de, 0x01e0, NULL))) {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07005183 /* TODO: set CR5f &0xf1 | 0x01 for version 6570
5184 * of nforce 2 ROM
5185 */
5186 if(0)
5187 setSISIDXREG(SISCR, 0x5f, 0xf1, 0x01);
Adrian Bunk0959f0c2007-05-08 00:39:50 -07005188 pci_dev_put(mypdev);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07005189 }
5190 }
5191
5192 v1 = 0x30;
5193 inSISIDXREG(SISSR, 0x3b, reg);
5194 inSISIDXREG(SISCR, 0x5f, v2);
5195 if((!(reg & 0x02)) && (v2 & 0x0e))
5196 v1 |= 0x08;
5197 outSISIDXREG(SISSR, 0x27, v1);
5198
5199 if(bios[0x64] & 0x01) {
5200 setSISIDXREG(SISCR, 0x5f, 0xf0, bios[0x64]);
5201 }
5202
5203 v1 = bios[0x4f7];
5204 pci_read_config_dword(pdev, 0x50, &regd);
5205 regd = (regd >> 20) & 0x0f;
5206 if(regd == 1) {
5207 v1 &= 0xfc;
5208 orSISIDXREG(SISCR, 0x5f, 0x08);
5209 }
5210 outSISIDXREG(SISCR, 0x48, v1);
5211
5212 setSISIDXREG(SISCR, 0x47, 0x04, bios[0x4f6] & 0xfb);
5213 setSISIDXREG(SISCR, 0x49, 0xf0, bios[0x4f8] & 0x0f);
5214 setSISIDXREG(SISCR, 0x4a, 0x60, bios[0x4f9] & 0x9f);
5215 setSISIDXREG(SISCR, 0x4b, 0x08, bios[0x4fa] & 0xf7);
5216 setSISIDXREG(SISCR, 0x4c, 0x80, bios[0x4fb] & 0x7f);
5217 outSISIDXREG(SISCR, 0x70, bios[0x4fc]);
5218 setSISIDXREG(SISCR, 0x71, 0xf0, bios[0x4fd] & 0x0f);
5219 outSISIDXREG(SISCR, 0x74, 0xd0);
5220 setSISIDXREG(SISCR, 0x74, 0xcf, bios[0x4fe] & 0x30);
5221 setSISIDXREG(SISCR, 0x75, 0xe0, bios[0x4ff] & 0x1f);
5222 setSISIDXREG(SISCR, 0x76, 0xe0, bios[0x500] & 0x1f);
5223 v1 = bios[0x501];
Adrian Bunk0959f0c2007-05-08 00:39:50 -07005224 if((mypdev = pci_get_device(0x8086, 0x2530, NULL))) {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07005225 v1 = 0xf0;
Adrian Bunk0959f0c2007-05-08 00:39:50 -07005226 pci_dev_put(mypdev);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07005227 }
5228 outSISIDXREG(SISCR, 0x77, v1);
5229 }
5230
5231 /* RAM type */
5232
5233 regb = 0; /* ! */
5234
5235 v1 = 0xff;
5236 if(ivideo->haveXGIROM) {
5237 v1 = bios[0x140 + regb];
5238 }
5239 outSISIDXREG(SISCR, 0x6d, v1);
5240
5241 ptr = cs128;
5242 if(ivideo->haveXGIROM) {
5243 ptr = (const u8 *)&bios[0x128];
5244 }
5245 for(i = 0, j = 0; i < 3; i++, j += 8) {
5246 outSISIDXREG(SISCR, 0x68 + i, ptr[j + regb]);
5247 }
5248
5249 ptr = cs31a;
5250 ptr2 = cs33a;
5251 if(ivideo->haveXGIROM) {
5252 index = (ivideo->chip == XGI_20) ? 0x31a : 0x3a6;
5253 ptr = (const u8 *)&bios[index];
5254 ptr2 = (const u8 *)&bios[index + 0x20];
5255 }
5256 for(i = 0; i < 2; i++) {
5257 if(i == 0) {
5258 regd = le32_to_cpu(((u32 *)ptr)[regb]);
5259 rega = 0x6b;
5260 } else {
5261 regd = le32_to_cpu(((u32 *)ptr2)[regb]);
5262 rega = 0x6e;
5263 }
5264 reg = 0x00;
5265 for(j = 0; j < 16; j++) {
5266 reg &= 0xf3;
5267 if(regd & 0x01) reg |= 0x04;
5268 if(regd & 0x02) reg |= 0x08;
5269 regd >>= 2;
5270 outSISIDXREG(SISCR, rega, reg);
5271 inSISIDXREG(SISCR, rega, reg);
5272 inSISIDXREG(SISCR, rega, reg);
5273 reg += 0x10;
5274 }
5275 }
5276
5277 andSISIDXREG(SISCR, 0x6e, 0xfc);
5278
5279 ptr = NULL;
5280 if(ivideo->haveXGIROM) {
5281 index = (ivideo->chip == XGI_20) ? 0x35a : 0x3e6;
5282 ptr = (const u8 *)&bios[index];
5283 }
5284 for(i = 0; i < 4; i++) {
5285 setSISIDXREG(SISCR, 0x6e, 0xfc, i);
5286 reg = 0x00;
5287 for(j = 0; j < 2; j++) {
5288 regd = 0;
5289 if(ptr) {
5290 regd = le32_to_cpu(((u32 *)ptr)[regb * 8]);
5291 ptr += 4;
5292 }
5293 /* reg = 0x00; */
5294 for(k = 0; k < 16; k++) {
5295 reg &= 0xfc;
5296 if(regd & 0x01) reg |= 0x01;
5297 if(regd & 0x02) reg |= 0x02;
5298 regd >>= 2;
5299 outSISIDXREG(SISCR, 0x6f, reg);
5300 inSISIDXREG(SISCR, 0x6f, reg);
5301 inSISIDXREG(SISCR, 0x6f, reg);
5302 reg += 0x08;
5303 }
5304 }
5305 }
5306
5307 ptr = cs148;
5308 if(ivideo->haveXGIROM) {
5309 ptr = (const u8 *)&bios[0x148];
5310 }
5311 for(i = 0, j = 0; i < 2; i++, j += 8) {
5312 outSISIDXREG(SISCR, 0x80 + i, ptr[j + regb]);
5313 }
5314
5315 andSISIDXREG(SISCR, 0x89, 0x8f);
5316
5317 ptr = cs45a;
5318 if(ivideo->haveXGIROM) {
5319 index = (ivideo->chip == XGI_20) ? 0x45a : 0x4e6;
5320 ptr = (const u8 *)&bios[index];
5321 }
5322 regd = le16_to_cpu(((const u16 *)ptr)[regb]);
5323 reg = 0x80;
5324 for(i = 0; i < 5; i++) {
5325 reg &= 0xfc;
5326 if(regd & 0x01) reg |= 0x01;
5327 if(regd & 0x02) reg |= 0x02;
5328 regd >>= 2;
5329 outSISIDXREG(SISCR, 0x89, reg);
5330 inSISIDXREG(SISCR, 0x89, reg);
5331 inSISIDXREG(SISCR, 0x89, reg);
5332 reg += 0x10;
5333 }
5334
5335 v1 = 0xb5; v2 = 0x20; v3 = 0xf0; v4 = 0x13;
5336 if(ivideo->haveXGIROM) {
5337 v1 = bios[0x118 + regb];
5338 v2 = bios[0xf8 + regb];
5339 v3 = bios[0x120 + regb];
5340 v4 = bios[0x1ca];
5341 }
5342 outSISIDXREG(SISCR, 0x45, v1 & 0x0f);
5343 outSISIDXREG(SISCR, 0x99, (v1 >> 4) & 0x07);
5344 orSISIDXREG(SISCR, 0x40, v1 & 0x80);
5345 outSISIDXREG(SISCR, 0x41, v2);
5346
5347 ptr = cs170;
5348 if(ivideo->haveXGIROM) {
5349 ptr = (const u8 *)&bios[0x170];
5350 }
5351 for(i = 0, j = 0; i < 7; i++, j += 8) {
5352 outSISIDXREG(SISCR, 0x90 + i, ptr[j + regb]);
5353 }
5354
5355 outSISIDXREG(SISCR, 0x59, v3);
5356
5357 ptr = cs1a8;
5358 if(ivideo->haveXGIROM) {
5359 ptr = (const u8 *)&bios[0x1a8];
5360 }
5361 for(i = 0, j = 0; i < 3; i++, j += 8) {
5362 outSISIDXREG(SISCR, 0xc3 + i, ptr[j + regb]);
5363 }
5364
5365 ptr = cs100;
5366 if(ivideo->haveXGIROM) {
5367 ptr = (const u8 *)&bios[0x100];
5368 }
5369 for(i = 0, j = 0; i < 2; i++, j += 8) {
5370 outSISIDXREG(SISCR, 0x8a + i, ptr[j + regb]);
5371 }
5372
5373 outSISIDXREG(SISCR, 0xcf, v4);
5374
5375 outSISIDXREG(SISCR, 0x83, 0x09);
5376 outSISIDXREG(SISCR, 0x87, 0x00);
5377
5378 if(ivideo->chip == XGI_40) {
5379 if( (ivideo->revision_id == 1) ||
5380 (ivideo->revision_id == 2) ) {
5381 outSISIDXREG(SISCR, 0x8c, 0x87);
5382 }
5383 }
5384
5385 outSISIDXREG(SISSR, 0x17, 0x00);
5386 outSISIDXREG(SISSR, 0x1a, 0x87);
5387
5388 if(ivideo->chip == XGI_20) {
5389 outSISIDXREG(SISSR, 0x15, 0x00);
5390 outSISIDXREG(SISSR, 0x1c, 0x00);
5391 }
5392
5393 ramtype = 0x00; v1 = 0x10;
5394 if(ivideo->haveXGIROM) {
5395 ramtype = bios[0x62];
5396 v1 = bios[0x1d2];
5397 }
5398 if(!(ramtype & 0x80)) {
5399 if(ivideo->chip == XGI_20) {
5400 outSISIDXREG(SISCR, 0x97, v1);
5401 inSISIDXREG(SISCR, 0x97, reg);
5402 if(reg & 0x10) {
5403 ramtype = (reg & 0x01) << 1;
5404 }
5405 } else {
5406 inSISIDXREG(SISSR, 0x39, reg);
5407 ramtype = reg & 0x02;
5408 if(!(ramtype)) {
5409 inSISIDXREG(SISSR, 0x3a, reg);
5410 ramtype = (reg >> 1) & 0x01;
5411 }
5412 }
5413 }
5414 ramtype &= 0x07;
5415
5416 regb = 0; /* ! */
5417
5418 switch(ramtype) {
5419 case 0:
5420 sisfb_post_xgi_setclocks(ivideo, regb);
5421 if((ivideo->chip == XGI_20) ||
5422 (ivideo->revision_id == 1) ||
5423 (ivideo->revision_id == 2)) {
5424 v1 = cs158[regb]; v2 = cs160[regb]; v3 = cs168[regb];
5425 if(ivideo->haveXGIROM) {
5426 v1 = bios[regb + 0x158];
5427 v2 = bios[regb + 0x160];
5428 v3 = bios[regb + 0x168];
5429 }
5430 outSISIDXREG(SISCR, 0x82, v1);
5431 outSISIDXREG(SISCR, 0x85, v2);
5432 outSISIDXREG(SISCR, 0x86, v3);
5433 } else {
5434 outSISIDXREG(SISCR, 0x82, 0x88);
5435 outSISIDXREG(SISCR, 0x86, 0x00);
5436 inSISIDXREG(SISCR, 0x86, reg);
5437 outSISIDXREG(SISCR, 0x86, 0x88);
5438 inSISIDXREG(SISCR, 0x86, reg);
5439 outSISIDXREG(SISCR, 0x86, bios[regb + 0x168]);
5440 outSISIDXREG(SISCR, 0x82, 0x77);
5441 outSISIDXREG(SISCR, 0x85, 0x00);
5442 inSISIDXREG(SISCR, 0x85, reg);
5443 outSISIDXREG(SISCR, 0x85, 0x88);
5444 inSISIDXREG(SISCR, 0x85, reg);
5445 outSISIDXREG(SISCR, 0x85, bios[regb + 0x160]);
5446 outSISIDXREG(SISCR, 0x82, bios[regb + 0x158]);
5447 }
5448 if(ivideo->chip == XGI_40) {
5449 outSISIDXREG(SISCR, 0x97, 0x00);
5450 }
5451 outSISIDXREG(SISCR, 0x98, 0x01);
5452 outSISIDXREG(SISCR, 0x9a, 0x02);
5453
5454 outSISIDXREG(SISSR, 0x18, 0x01);
5455 if((ivideo->chip == XGI_20) ||
5456 (ivideo->revision_id == 2)) {
5457 outSISIDXREG(SISSR, 0x19, 0x40);
5458 } else {
5459 outSISIDXREG(SISSR, 0x19, 0x20);
5460 }
5461 outSISIDXREG(SISSR, 0x16, 0x00);
5462 outSISIDXREG(SISSR, 0x16, 0x80);
5463 if((ivideo->chip == XGI_20) || (bios[0x1cb] != 0x0c)) {
5464 sisfb_post_xgi_delay(ivideo, 0x43);
5465 sisfb_post_xgi_delay(ivideo, 0x43);
5466 sisfb_post_xgi_delay(ivideo, 0x43);
5467 outSISIDXREG(SISSR, 0x18, 0x00);
5468 if((ivideo->chip == XGI_20) ||
5469 (ivideo->revision_id == 2)) {
5470 outSISIDXREG(SISSR, 0x19, 0x40);
5471 } else {
5472 outSISIDXREG(SISSR, 0x19, 0x20);
5473 }
5474 } else if((ivideo->chip == XGI_40) && (bios[0x1cb] == 0x0c)) {
5475 /* outSISIDXREG(SISSR, 0x16, 0x0c); */ /* ? */
5476 }
5477 outSISIDXREG(SISSR, 0x16, 0x00);
5478 outSISIDXREG(SISSR, 0x16, 0x80);
5479 sisfb_post_xgi_delay(ivideo, 4);
5480 v1 = 0x31; v2 = 0x03; v3 = 0x83; v4 = 0x03; v5 = 0x83;
5481 if(ivideo->haveXGIROM) {
5482 v1 = bios[0xf0];
5483 index = (ivideo->chip == XGI_20) ? 0x4b2 : 0x53e;
5484 v2 = bios[index];
5485 v3 = bios[index + 1];
5486 v4 = bios[index + 2];
5487 v5 = bios[index + 3];
5488 }
5489 outSISIDXREG(SISSR, 0x18, v1);
5490 outSISIDXREG(SISSR, 0x19, ((ivideo->chip == XGI_20) ? 0x02 : 0x01));
5491 outSISIDXREG(SISSR, 0x16, v2);
5492 outSISIDXREG(SISSR, 0x16, v3);
5493 sisfb_post_xgi_delay(ivideo, 0x43);
5494 outSISIDXREG(SISSR, 0x1b, 0x03);
5495 sisfb_post_xgi_delay(ivideo, 0x22);
5496 outSISIDXREG(SISSR, 0x18, v1);
5497 outSISIDXREG(SISSR, 0x19, 0x00);
5498 outSISIDXREG(SISSR, 0x16, v4);
5499 outSISIDXREG(SISSR, 0x16, v5);
5500 outSISIDXREG(SISSR, 0x1b, 0x00);
5501 break;
5502 case 1:
5503 outSISIDXREG(SISCR, 0x82, 0x77);
5504 outSISIDXREG(SISCR, 0x86, 0x00);
5505 inSISIDXREG(SISCR, 0x86, reg);
5506 outSISIDXREG(SISCR, 0x86, 0x88);
5507 inSISIDXREG(SISCR, 0x86, reg);
5508 v1 = cs168[regb]; v2 = cs160[regb]; v3 = cs158[regb];
5509 if(ivideo->haveXGIROM) {
5510 v1 = bios[regb + 0x168];
5511 v2 = bios[regb + 0x160];
5512 v3 = bios[regb + 0x158];
5513 }
5514 outSISIDXREG(SISCR, 0x86, v1);
5515 outSISIDXREG(SISCR, 0x82, 0x77);
5516 outSISIDXREG(SISCR, 0x85, 0x00);
5517 inSISIDXREG(SISCR, 0x85, reg);
5518 outSISIDXREG(SISCR, 0x85, 0x88);
5519 inSISIDXREG(SISCR, 0x85, reg);
5520 outSISIDXREG(SISCR, 0x85, v2);
5521 outSISIDXREG(SISCR, 0x82, v3);
5522 outSISIDXREG(SISCR, 0x98, 0x01);
5523 outSISIDXREG(SISCR, 0x9a, 0x02);
5524
5525 outSISIDXREG(SISSR, 0x28, 0x64);
5526 outSISIDXREG(SISSR, 0x29, 0x63);
5527 sisfb_post_xgi_delay(ivideo, 15);
5528 outSISIDXREG(SISSR, 0x18, 0x00);
5529 outSISIDXREG(SISSR, 0x19, 0x20);
5530 outSISIDXREG(SISSR, 0x16, 0x00);
5531 outSISIDXREG(SISSR, 0x16, 0x80);
5532 outSISIDXREG(SISSR, 0x18, 0xc5);
5533 outSISIDXREG(SISSR, 0x19, 0x23);
5534 outSISIDXREG(SISSR, 0x16, 0x00);
5535 outSISIDXREG(SISSR, 0x16, 0x80);
5536 sisfb_post_xgi_delay(ivideo, 1);
5537 outSISIDXREG(SISCR, 0x97,0x11);
5538 sisfb_post_xgi_setclocks(ivideo, regb);
5539 sisfb_post_xgi_delay(ivideo, 0x46);
5540 outSISIDXREG(SISSR, 0x18, 0xc5);
5541 outSISIDXREG(SISSR, 0x19, 0x23);
5542 outSISIDXREG(SISSR, 0x16, 0x00);
5543 outSISIDXREG(SISSR, 0x16, 0x80);
5544 sisfb_post_xgi_delay(ivideo, 1);
5545 outSISIDXREG(SISSR, 0x1b, 0x04);
5546 sisfb_post_xgi_delay(ivideo, 1);
5547 outSISIDXREG(SISSR, 0x1b, 0x00);
5548 sisfb_post_xgi_delay(ivideo, 1);
5549 v1 = 0x31;
5550 if(ivideo->haveXGIROM) {
5551 v1 = bios[0xf0];
5552 }
5553 outSISIDXREG(SISSR, 0x18, v1);
5554 outSISIDXREG(SISSR, 0x19, 0x06);
5555 outSISIDXREG(SISSR, 0x16, 0x04);
5556 outSISIDXREG(SISSR, 0x16, 0x84);
5557 sisfb_post_xgi_delay(ivideo, 1);
5558 break;
5559 default:
5560 sisfb_post_xgi_setclocks(ivideo, regb);
5561 if((ivideo->chip == XGI_40) &&
5562 ((ivideo->revision_id == 1) ||
5563 (ivideo->revision_id == 2))) {
5564 outSISIDXREG(SISCR, 0x82, bios[regb + 0x158]);
5565 outSISIDXREG(SISCR, 0x85, bios[regb + 0x160]);
5566 outSISIDXREG(SISCR, 0x86, bios[regb + 0x168]);
5567 } else {
5568 outSISIDXREG(SISCR, 0x82, 0x88);
5569 outSISIDXREG(SISCR, 0x86, 0x00);
5570 inSISIDXREG(SISCR, 0x86, reg);
5571 outSISIDXREG(SISCR, 0x86, 0x88);
5572 outSISIDXREG(SISCR, 0x82, 0x77);
5573 outSISIDXREG(SISCR, 0x85, 0x00);
5574 inSISIDXREG(SISCR, 0x85, reg);
5575 outSISIDXREG(SISCR, 0x85, 0x88);
5576 inSISIDXREG(SISCR, 0x85, reg);
5577 v1 = cs160[regb]; v2 = cs158[regb];
5578 if(ivideo->haveXGIROM) {
5579 v1 = bios[regb + 0x160];
5580 v2 = bios[regb + 0x158];
5581 }
5582 outSISIDXREG(SISCR, 0x85, v1);
5583 outSISIDXREG(SISCR, 0x82, v2);
5584 }
5585 if(ivideo->chip == XGI_40) {
5586 outSISIDXREG(SISCR, 0x97, 0x11);
5587 }
5588 if((ivideo->chip == XGI_40) && (ivideo->revision_id == 2)) {
5589 outSISIDXREG(SISCR, 0x98, 0x01);
5590 } else {
5591 outSISIDXREG(SISCR, 0x98, 0x03);
5592 }
5593 outSISIDXREG(SISCR, 0x9a, 0x02);
5594
5595 if(ivideo->chip == XGI_40) {
5596 outSISIDXREG(SISSR, 0x18, 0x01);
5597 } else {
5598 outSISIDXREG(SISSR, 0x18, 0x00);
5599 }
5600 outSISIDXREG(SISSR, 0x19, 0x40);
5601 outSISIDXREG(SISSR, 0x16, 0x00);
5602 outSISIDXREG(SISSR, 0x16, 0x80);
5603 if((ivideo->chip == XGI_40) && (bios[0x1cb] != 0x0c)) {
5604 sisfb_post_xgi_delay(ivideo, 0x43);
5605 sisfb_post_xgi_delay(ivideo, 0x43);
5606 sisfb_post_xgi_delay(ivideo, 0x43);
5607 outSISIDXREG(SISSR, 0x18, 0x00);
5608 outSISIDXREG(SISSR, 0x19, 0x40);
5609 outSISIDXREG(SISSR, 0x16, 0x00);
5610 outSISIDXREG(SISSR, 0x16, 0x80);
5611 }
5612 sisfb_post_xgi_delay(ivideo, 4);
5613 v1 = 0x31;
5614 if(ivideo->haveXGIROM) {
5615 v1 = bios[0xf0];
5616 }
5617 outSISIDXREG(SISSR, 0x18, v1);
5618 outSISIDXREG(SISSR, 0x19, 0x01);
5619 if(ivideo->chip == XGI_40) {
5620 outSISIDXREG(SISSR, 0x16, bios[0x53e]);
5621 outSISIDXREG(SISSR, 0x16, bios[0x53f]);
5622 } else {
5623 outSISIDXREG(SISSR, 0x16, 0x05);
5624 outSISIDXREG(SISSR, 0x16, 0x85);
5625 }
5626 sisfb_post_xgi_delay(ivideo, 0x43);
5627 if(ivideo->chip == XGI_40) {
5628 outSISIDXREG(SISSR, 0x1b, 0x01);
5629 } else {
5630 outSISIDXREG(SISSR, 0x1b, 0x03);
5631 }
5632 sisfb_post_xgi_delay(ivideo, 0x22);
5633 outSISIDXREG(SISSR, 0x18, v1);
5634 outSISIDXREG(SISSR, 0x19, 0x00);
5635 if(ivideo->chip == XGI_40) {
5636 outSISIDXREG(SISSR, 0x16, bios[0x540]);
5637 outSISIDXREG(SISSR, 0x16, bios[0x541]);
5638 } else {
5639 outSISIDXREG(SISSR, 0x16, 0x05);
5640 outSISIDXREG(SISSR, 0x16, 0x85);
5641 }
5642 outSISIDXREG(SISSR, 0x1b, 0x00);
5643 }
5644
5645 regb = 0; /* ! */
5646 v1 = 0x03;
5647 if(ivideo->haveXGIROM) {
5648 v1 = bios[0x110 + regb];
5649 }
5650 outSISIDXREG(SISSR, 0x1b, v1);
5651
5652 /* RAM size */
5653 v1 = 0x00; v2 = 0x00;
5654 if(ivideo->haveXGIROM) {
5655 v1 = bios[0x62];
5656 v2 = bios[0x63];
5657 }
5658 regb = 0; /* ! */
5659 regd = 1 << regb;
5660 if((v1 & 0x40) && (v2 & regd) && ivideo->haveXGIROM) {
5661
5662 outSISIDXREG(SISSR, 0x13, bios[regb + 0xe0]);
5663 outSISIDXREG(SISSR, 0x14, bios[regb + 0xe0 + 8]);
5664
5665 } else {
5666
5667 /* Set default mode, don't clear screen */
Richard Knutssonc30660ea2007-02-12 00:55:06 -08005668 ivideo->SiS_Pr.SiS_UseOEM = false;
5669 SiS_SetEnableDstn(&ivideo->SiS_Pr, false);
5670 SiS_SetEnableFstn(&ivideo->SiS_Pr, false);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07005671 ivideo->curFSTN = ivideo->curDSTN = 0;
5672 ivideo->SiS_Pr.VideoMemorySize = 8 << 20;
5673 SiSSetMode(&ivideo->SiS_Pr, 0x2e | 0x80);
5674
5675 outSISIDXREG(SISSR, 0x05, 0x86);
5676
5677 /* Disable read-cache */
5678 andSISIDXREG(SISSR, 0x21, 0xdf);
5679 sisfb_post_xgi_ramsize(ivideo);
5680 /* Enable read-cache */
5681 orSISIDXREG(SISSR, 0x21, 0x20);
5682
5683 }
5684
5685#if 0
5686 printk(KERN_DEBUG "-----------------\n");
5687 for(i = 0; i < 0xff; i++) {
5688 inSISIDXREG(SISCR, i, reg);
5689 printk(KERN_DEBUG "CR%02x(%x) = 0x%02x\n", i, SISCR, reg);
5690 }
5691 for(i = 0; i < 0x40; i++) {
5692 inSISIDXREG(SISSR, i, reg);
5693 printk(KERN_DEBUG "SR%02x(%x) = 0x%02x\n", i, SISSR, reg);
5694 }
5695 printk(KERN_DEBUG "-----------------\n");
5696#endif
5697
5698 /* Sense CRT1 */
5699 if(ivideo->chip == XGI_20) {
5700 orSISIDXREG(SISCR, 0x32, 0x20);
5701 } else {
5702 inSISIDXREG(SISPART4, 0x00, reg);
5703 if((reg == 1) || (reg == 2)) {
5704 sisfb_sense_crt1(ivideo);
5705 } else {
5706 orSISIDXREG(SISCR, 0x32, 0x20);
5707 }
5708 }
5709
5710 /* Set default mode, don't clear screen */
Richard Knutssonc30660ea2007-02-12 00:55:06 -08005711 ivideo->SiS_Pr.SiS_UseOEM = false;
5712 SiS_SetEnableDstn(&ivideo->SiS_Pr, false);
5713 SiS_SetEnableFstn(&ivideo->SiS_Pr, false);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07005714 ivideo->curFSTN = ivideo->curDSTN = 0;
5715 SiSSetMode(&ivideo->SiS_Pr, 0x2e | 0x80);
5716
5717 outSISIDXREG(SISSR, 0x05, 0x86);
5718
5719 /* Display off */
5720 orSISIDXREG(SISSR, 0x01, 0x20);
5721
5722 /* Save mode number in CR34 */
5723 outSISIDXREG(SISCR, 0x34, 0x2e);
5724
5725 /* Let everyone know what the current mode is */
5726 ivideo->modeprechange = 0x2e;
5727
5728 if(ivideo->chip == XGI_40) {
5729 inSISIDXREG(SISCR, 0xca, reg);
5730 inSISIDXREG(SISCR, 0xcc, v1);
5731 if((reg & 0x10) && (!(v1 & 0x04))) {
5732 printk(KERN_ERR
5733 "sisfb: Please connect power to the card.\n");
5734 return 0;
5735 }
5736 }
5737
5738 return 1;
5739}
5740#endif
5741
5742static int __devinit
5743sisfb_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
5744{
5745 struct sisfb_chip_info *chipinfo = &sisfb_chip_info[ent->driver_data];
5746 struct sis_video_info *ivideo = NULL;
5747 struct fb_info *sis_fb_info = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005748 u16 reg16;
5749 u8 reg;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07005750 int i, ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005751
Thomas Winischhofer544393f2005-09-09 13:04:45 -07005752 if(sisfb_off)
5753 return -ENXIO;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005754
Linus Torvalds1da177e2005-04-16 15:20:36 -07005755 sis_fb_info = framebuffer_alloc(sizeof(*ivideo), &pdev->dev);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07005756 if(!sis_fb_info)
5757 return -ENOMEM;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005758
5759 ivideo = (struct sis_video_info *)sis_fb_info->par;
5760 ivideo->memyselfandi = sis_fb_info;
5761
Thomas Winischhofer544393f2005-09-09 13:04:45 -07005762 ivideo->sisfb_id = SISFB_ID;
5763
Linus Torvalds1da177e2005-04-16 15:20:36 -07005764 if(card_list == NULL) {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07005765 ivideo->cardnumber = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005766 } else {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07005767 struct sis_video_info *countvideo = card_list;
5768 ivideo->cardnumber = 1;
Harvey Harrison5e2daeb2008-05-22 15:45:08 -07005769 while((countvideo = countvideo->next) != NULL)
Thomas Winischhofer544393f2005-09-09 13:04:45 -07005770 ivideo->cardnumber++;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005771 }
5772
5773 strncpy(ivideo->myid, chipinfo->chip_name, 30);
5774
5775 ivideo->warncount = 0;
5776 ivideo->chip_id = pdev->device;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07005777 ivideo->chip_vendor = pdev->vendor;
Auke Kok44c10132007-06-08 15:46:36 -07005778 ivideo->revision_id = pdev->revision;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07005779 ivideo->SiS_Pr.ChipRevision = ivideo->revision_id;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005780 pci_read_config_word(pdev, PCI_COMMAND, &reg16);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07005781 ivideo->sisvga_enabled = reg16 & 0x01;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005782 ivideo->pcibus = pdev->bus->number;
5783 ivideo->pcislot = PCI_SLOT(pdev->devfn);
5784 ivideo->pcifunc = PCI_FUNC(pdev->devfn);
5785 ivideo->subsysvendor = pdev->subsystem_vendor;
5786 ivideo->subsysdevice = pdev->subsystem_device;
5787
5788#ifndef MODULE
5789 if(sisfb_mode_idx == -1) {
5790 sisfb_get_vga_mode_from_kernel();
5791 }
5792#endif
5793
5794 ivideo->chip = chipinfo->chip;
5795 ivideo->sisvga_engine = chipinfo->vgaengine;
5796 ivideo->hwcursor_size = chipinfo->hwcursor_size;
5797 ivideo->CRT2_write_enable = chipinfo->CRT2_write_enable;
5798 ivideo->mni = chipinfo->mni;
5799
5800 ivideo->detectedpdc = 0xff;
5801 ivideo->detectedpdca = 0xff;
5802 ivideo->detectedlcda = 0xff;
5803
Richard Knutssonc30660ea2007-02-12 00:55:06 -08005804 ivideo->sisfb_thismonitor.datavalid = false;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005805
Thomas Winischhofer544393f2005-09-09 13:04:45 -07005806 ivideo->current_base = 0;
5807
5808 ivideo->engineok = 0;
5809
5810 ivideo->sisfb_was_boot_device = 0;
Adrian Bunk14aefd12008-07-23 21:31:12 -07005811
Thomas Winischhofer544393f2005-09-09 13:04:45 -07005812 if(pdev->resource[PCI_ROM_RESOURCE].flags & IORESOURCE_ROM_SHADOW) {
5813 if(ivideo->sisvga_enabled)
5814 ivideo->sisfb_was_boot_device = 1;
5815 else {
5816 printk(KERN_DEBUG "sisfb: PCI device is disabled, "
5817 "but marked as boot video device ???\n");
5818 printk(KERN_DEBUG "sisfb: I will not accept this "
5819 "as the primary VGA device\n");
5820 }
5821 }
Thomas Winischhofer544393f2005-09-09 13:04:45 -07005822
Linus Torvalds1da177e2005-04-16 15:20:36 -07005823 ivideo->sisfb_parm_mem = sisfb_parm_mem;
5824 ivideo->sisfb_accel = sisfb_accel;
5825 ivideo->sisfb_ypan = sisfb_ypan;
5826 ivideo->sisfb_max = sisfb_max;
5827 ivideo->sisfb_userom = sisfb_userom;
5828 ivideo->sisfb_useoem = sisfb_useoem;
5829 ivideo->sisfb_mode_idx = sisfb_mode_idx;
5830 ivideo->sisfb_parm_rate = sisfb_parm_rate;
5831 ivideo->sisfb_crt1off = sisfb_crt1off;
5832 ivideo->sisfb_forcecrt1 = sisfb_forcecrt1;
5833 ivideo->sisfb_crt2type = sisfb_crt2type;
5834 ivideo->sisfb_crt2flags = sisfb_crt2flags;
5835 /* pdc(a), scalelcd, special timing, lvdshl handled below */
5836 ivideo->sisfb_dstn = sisfb_dstn;
5837 ivideo->sisfb_fstn = sisfb_fstn;
5838 ivideo->sisfb_tvplug = sisfb_tvplug;
5839 ivideo->sisfb_tvstd = sisfb_tvstd;
5840 ivideo->tvxpos = sisfb_tvxposoffset;
5841 ivideo->tvypos = sisfb_tvyposoffset;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005842 ivideo->sisfb_nocrt2rate = sisfb_nocrt2rate;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005843 ivideo->refresh_rate = 0;
5844 if(ivideo->sisfb_parm_rate != -1) {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07005845 ivideo->refresh_rate = ivideo->sisfb_parm_rate;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005846 }
5847
5848 ivideo->SiS_Pr.UsePanelScaler = sisfb_scalelcd;
5849 ivideo->SiS_Pr.CenterScreen = -1;
5850 ivideo->SiS_Pr.SiS_CustomT = sisfb_specialtiming;
5851 ivideo->SiS_Pr.LVDSHL = sisfb_lvdshl;
5852
5853 ivideo->SiS_Pr.SiS_Backup70xx = 0xff;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07005854 ivideo->SiS_Pr.SiS_CHOverScan = -1;
Richard Knutssonc30660ea2007-02-12 00:55:06 -08005855 ivideo->SiS_Pr.SiS_ChSW = false;
5856 ivideo->SiS_Pr.SiS_UseLCDA = false;
5857 ivideo->SiS_Pr.HaveEMI = false;
5858 ivideo->SiS_Pr.HaveEMILCD = false;
5859 ivideo->SiS_Pr.OverruleEMI = false;
5860 ivideo->SiS_Pr.SiS_SensibleSR11 = false;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005861 ivideo->SiS_Pr.SiS_MyCR63 = 0x63;
5862 ivideo->SiS_Pr.PDC = -1;
5863 ivideo->SiS_Pr.PDCA = -1;
Richard Knutssonc30660ea2007-02-12 00:55:06 -08005864 ivideo->SiS_Pr.DDCPortMixup = false;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005865#ifdef CONFIG_FB_SIS_315
5866 if(ivideo->chip >= SIS_330) {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07005867 ivideo->SiS_Pr.SiS_MyCR63 = 0x53;
5868 if(ivideo->chip >= SIS_661) {
Richard Knutssonc30660ea2007-02-12 00:55:06 -08005869 ivideo->SiS_Pr.SiS_SensibleSR11 = true;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07005870 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07005871 }
5872#endif
5873
5874 memcpy(&ivideo->default_var, &my_default_var, sizeof(my_default_var));
5875
5876 pci_set_drvdata(pdev, ivideo);
5877
5878 /* Patch special cases */
5879 if((ivideo->nbridge = sisfb_get_northbridge(ivideo->chip))) {
5880 switch(ivideo->nbridge->device) {
5881#ifdef CONFIG_FB_SIS_300
5882 case PCI_DEVICE_ID_SI_730:
Thomas Winischhofer544393f2005-09-09 13:04:45 -07005883 ivideo->chip = SIS_730;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005884 strcpy(ivideo->myid, "SiS 730");
Thomas Winischhofer544393f2005-09-09 13:04:45 -07005885 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005886#endif
5887#ifdef CONFIG_FB_SIS_315
5888 case PCI_DEVICE_ID_SI_651:
5889 /* ivideo->chip is ok */
5890 strcpy(ivideo->myid, "SiS 651");
5891 break;
5892 case PCI_DEVICE_ID_SI_740:
Thomas Winischhofer544393f2005-09-09 13:04:45 -07005893 ivideo->chip = SIS_740;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005894 strcpy(ivideo->myid, "SiS 740");
5895 break;
5896 case PCI_DEVICE_ID_SI_661:
Thomas Winischhofer544393f2005-09-09 13:04:45 -07005897 ivideo->chip = SIS_661;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005898 strcpy(ivideo->myid, "SiS 661");
5899 break;
5900 case PCI_DEVICE_ID_SI_741:
Thomas Winischhofer544393f2005-09-09 13:04:45 -07005901 ivideo->chip = SIS_741;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005902 strcpy(ivideo->myid, "SiS 741");
5903 break;
5904 case PCI_DEVICE_ID_SI_760:
Thomas Winischhofer544393f2005-09-09 13:04:45 -07005905 ivideo->chip = SIS_760;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005906 strcpy(ivideo->myid, "SiS 760");
5907 break;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07005908 case PCI_DEVICE_ID_SI_761:
5909 ivideo->chip = SIS_761;
5910 strcpy(ivideo->myid, "SiS 761");
5911 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005912#endif
Thomas Winischhofer544393f2005-09-09 13:04:45 -07005913 default:
5914 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005915 }
5916 }
5917
Thomas Winischhofer544393f2005-09-09 13:04:45 -07005918 ivideo->SiS_Pr.ChipType = ivideo->chip;
5919
5920 ivideo->SiS_Pr.ivideo = (void *)ivideo;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005921
5922#ifdef CONFIG_FB_SIS_315
Thomas Winischhofer544393f2005-09-09 13:04:45 -07005923 if((ivideo->SiS_Pr.ChipType == SIS_315PRO) ||
5924 (ivideo->SiS_Pr.ChipType == SIS_315)) {
5925 ivideo->SiS_Pr.ChipType = SIS_315H;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005926 }
5927#endif
5928
Thomas Winischhofer544393f2005-09-09 13:04:45 -07005929 if(!ivideo->sisvga_enabled) {
5930 if(pci_enable_device(pdev)) {
Adrian Bunk0959f0c2007-05-08 00:39:50 -07005931 if(ivideo->nbridge) pci_dev_put(ivideo->nbridge);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07005932 pci_set_drvdata(pdev, NULL);
Krzysztof Helt491bcc92009-06-16 15:34:36 -07005933 framebuffer_release(sis_fb_info);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07005934 return -EIO;
5935 }
5936 }
5937
Linus Torvalds1da177e2005-04-16 15:20:36 -07005938 ivideo->video_base = pci_resource_start(pdev, 0);
5939 ivideo->mmio_base = pci_resource_start(pdev, 1);
5940 ivideo->mmio_size = pci_resource_len(pdev, 1);
5941 ivideo->SiS_Pr.RelIO = pci_resource_start(pdev, 2) + 0x30;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07005942 ivideo->SiS_Pr.IOAddress = ivideo->vga_base = ivideo->SiS_Pr.RelIO;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005943
Thomas Winischhofer544393f2005-09-09 13:04:45 -07005944 SiSRegInit(&ivideo->SiS_Pr, ivideo->SiS_Pr.IOAddress);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005945
5946#ifdef CONFIG_FB_SIS_300
5947 /* Find PCI systems for Chrontel/GPIO communication setup */
5948 if(ivideo->chip == SIS_630) {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07005949 i = 0;
5950 do {
5951 if(mychswtable[i].subsysVendor == ivideo->subsysvendor &&
5952 mychswtable[i].subsysCard == ivideo->subsysdevice) {
Richard Knutssonc30660ea2007-02-12 00:55:06 -08005953 ivideo->SiS_Pr.SiS_ChSW = true;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07005954 printk(KERN_DEBUG "sisfb: Identified [%s %s] "
5955 "requiring Chrontel/GPIO setup\n",
5956 mychswtable[i].vendorName,
5957 mychswtable[i].cardName);
Adrian Bunk0959f0c2007-05-08 00:39:50 -07005958 ivideo->lpcdev = pci_get_device(PCI_VENDOR_ID_SI, 0x0008, NULL);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07005959 break;
5960 }
5961 i++;
5962 } while(mychswtable[i].subsysVendor != 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005963 }
5964#endif
5965
Thomas Winischhofer544393f2005-09-09 13:04:45 -07005966#ifdef CONFIG_FB_SIS_315
5967 if((ivideo->chip == SIS_760) && (ivideo->nbridge)) {
Adrian Bunk0959f0c2007-05-08 00:39:50 -07005968 ivideo->lpcdev = pci_get_slot(ivideo->nbridge->bus, (2 << 3));
Thomas Winischhofer544393f2005-09-09 13:04:45 -07005969 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07005970#endif
Thomas Winischhofer544393f2005-09-09 13:04:45 -07005971
5972 outSISIDXREG(SISSR, 0x05, 0x86);
5973
5974 if( (!ivideo->sisvga_enabled)
5975#if !defined(__i386__) && !defined(__x86_64__)
5976 || (sisfb_resetcard)
5977#endif
5978 ) {
5979 for(i = 0x30; i <= 0x3f; i++) {
5980 outSISIDXREG(SISCR, i, 0x00);
5981 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07005982 }
5983
5984 /* Find out about current video mode */
5985 ivideo->modeprechange = 0x03;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07005986 inSISIDXREG(SISCR, 0x34, reg);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005987 if(reg & 0x7f) {
5988 ivideo->modeprechange = reg & 0x7f;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07005989 } else if(ivideo->sisvga_enabled) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07005990#if defined(__i386__) || defined(__x86_64__)
Adrian Bunk14aefd12008-07-23 21:31:12 -07005991 unsigned char __iomem *tt = ioremap(0x400, 0x100);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005992 if(tt) {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07005993 ivideo->modeprechange = readb(tt + 0x49);
5994 iounmap(tt);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005995 }
5996#endif
5997 }
5998
Thomas Winischhofer544393f2005-09-09 13:04:45 -07005999 /* Search and copy ROM image */
6000 ivideo->bios_abase = NULL;
6001 ivideo->SiS_Pr.VirtualRomBase = NULL;
Richard Knutssonc30660ea2007-02-12 00:55:06 -08006002 ivideo->SiS_Pr.UseROM = false;
6003 ivideo->haveXGIROM = ivideo->SiS_Pr.SiS_XGIROM = false;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006004 if(ivideo->sisfb_userom) {
6005 ivideo->SiS_Pr.VirtualRomBase = sisfb_find_rom(pdev);
6006 ivideo->bios_abase = ivideo->SiS_Pr.VirtualRomBase;
Richard Knutssonc30660ea2007-02-12 00:55:06 -08006007 ivideo->SiS_Pr.UseROM = (bool)(ivideo->SiS_Pr.VirtualRomBase);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006008 printk(KERN_INFO "sisfb: Video ROM %sfound\n",
6009 ivideo->SiS_Pr.UseROM ? "" : "not ");
6010 if((ivideo->SiS_Pr.UseROM) && (ivideo->chip >= XGI_20)) {
Richard Knutssonc30660ea2007-02-12 00:55:06 -08006011 ivideo->SiS_Pr.UseROM = false;
6012 ivideo->haveXGIROM = ivideo->SiS_Pr.SiS_XGIROM = true;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006013 if( (ivideo->revision_id == 2) &&
6014 (!(ivideo->bios_abase[0x1d1] & 0x01)) ) {
Richard Knutssonc30660ea2007-02-12 00:55:06 -08006015 ivideo->SiS_Pr.DDCPortMixup = true;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006016 }
6017 }
6018 } else {
6019 printk(KERN_INFO "sisfb: Video ROM usage disabled\n");
6020 }
6021
6022 /* Find systems for special custom timing */
6023 if(ivideo->SiS_Pr.SiS_CustomT == CUT_NONE) {
6024 sisfb_detect_custom_timing(ivideo);
6025 }
6026
6027 /* POST card in case this has not been done by the BIOS */
6028 if( (!ivideo->sisvga_enabled)
6029#if !defined(__i386__) && !defined(__x86_64__)
6030 || (sisfb_resetcard)
6031#endif
6032 ) {
6033#ifdef CONFIG_FB_SIS_300
6034 if(ivideo->sisvga_engine == SIS_300_VGA) {
6035 if(ivideo->chip == SIS_300) {
6036 sisfb_post_sis300(pdev);
6037 ivideo->sisfb_can_post = 1;
6038 }
6039 }
6040#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -07006041
6042#ifdef CONFIG_FB_SIS_315
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006043 if(ivideo->sisvga_engine == SIS_315_VGA) {
6044 int result = 1;
6045 /* if((ivideo->chip == SIS_315H) ||
Linus Torvalds1da177e2005-04-16 15:20:36 -07006046 (ivideo->chip == SIS_315) ||
6047 (ivideo->chip == SIS_315PRO) ||
6048 (ivideo->chip == SIS_330)) {
6049 sisfb_post_sis315330(pdev);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006050 } else */ if(ivideo->chip == XGI_20) {
6051 result = sisfb_post_xgi(pdev);
6052 ivideo->sisfb_can_post = 1;
6053 } else if((ivideo->chip == XGI_40) && ivideo->haveXGIROM) {
6054 result = sisfb_post_xgi(pdev);
6055 ivideo->sisfb_can_post = 1;
6056 } else {
6057 printk(KERN_INFO "sisfb: Card is not "
6058 "POSTed and sisfb can't do this either.\n");
6059 }
6060 if(!result) {
6061 printk(KERN_ERR "sisfb: Failed to POST card\n");
6062 ret = -ENODEV;
6063 goto error_3;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006064 }
6065 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07006066#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -07006067 }
6068
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006069 ivideo->sisfb_card_posted = 1;
6070
6071 /* Find out about RAM size */
6072 if(sisfb_get_dram_size(ivideo)) {
6073 printk(KERN_INFO "sisfb: Fatal error: Unable to determine VRAM size.\n");
6074 ret = -ENODEV;
6075 goto error_3;
6076 }
6077
6078
6079 /* Enable PCI addressing and MMIO */
Linus Torvalds1da177e2005-04-16 15:20:36 -07006080 if((ivideo->sisfb_mode_idx < 0) ||
6081 ((sisbios_mode[ivideo->sisfb_mode_idx].mode_no[ivideo->mni]) != 0xFF)) {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006082 /* Enable PCI_LINEAR_ADDRESSING and MMIO_ENABLE */
6083 orSISIDXREG(SISSR, IND_SIS_PCI_ADDRESS_SET, (SIS_PCI_ADDR_ENABLE | SIS_MEM_MAP_IO_ENABLE));
6084 /* Enable 2D accelerator engine */
6085 orSISIDXREG(SISSR, IND_SIS_MODULE_ENABLE, SIS_ENABLE_2D);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006086 }
6087
6088 if(sisfb_pdc != 0xff) {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006089 if(ivideo->sisvga_engine == SIS_300_VGA)
6090 sisfb_pdc &= 0x3c;
6091 else
6092 sisfb_pdc &= 0x1f;
6093 ivideo->SiS_Pr.PDC = sisfb_pdc;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006094 }
6095#ifdef CONFIG_FB_SIS_315
6096 if(ivideo->sisvga_engine == SIS_315_VGA) {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006097 if(sisfb_pdca != 0xff)
6098 ivideo->SiS_Pr.PDCA = sisfb_pdca & 0x1f;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006099 }
6100#endif
6101
6102 if(!request_mem_region(ivideo->video_base, ivideo->video_size, "sisfb FB")) {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006103 printk(KERN_ERR "sisfb: Fatal error: Unable to reserve %dMB framebuffer memory\n",
6104 (int)(ivideo->video_size >> 20));
Linus Torvalds1da177e2005-04-16 15:20:36 -07006105 printk(KERN_ERR "sisfb: Is there another framebuffer driver active?\n");
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006106 ret = -ENODEV;
6107 goto error_3;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006108 }
6109
6110 if(!request_mem_region(ivideo->mmio_base, ivideo->mmio_size, "sisfb MMIO")) {
6111 printk(KERN_ERR "sisfb: Fatal error: Unable to reserve MMIO region\n");
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006112 ret = -ENODEV;
6113 goto error_2;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006114 }
6115
6116 ivideo->video_vbase = ioremap(ivideo->video_base, ivideo->video_size);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006117 ivideo->SiS_Pr.VideoMemoryAddress = ivideo->video_vbase;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006118 if(!ivideo->video_vbase) {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006119 printk(KERN_ERR "sisfb: Fatal error: Unable to map framebuffer memory\n");
6120 ret = -ENODEV;
6121 goto error_1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006122 }
6123
6124 ivideo->mmio_vbase = ioremap(ivideo->mmio_base, ivideo->mmio_size);
6125 if(!ivideo->mmio_vbase) {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006126 printk(KERN_ERR "sisfb: Fatal error: Unable to map MMIO region\n");
6127 ret = -ENODEV;
6128error_0: iounmap(ivideo->video_vbase);
6129error_1: release_mem_region(ivideo->video_base, ivideo->video_size);
6130error_2: release_mem_region(ivideo->mmio_base, ivideo->mmio_size);
6131error_3: vfree(ivideo->bios_abase);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006132 if(ivideo->lpcdev)
Adrian Bunk0959f0c2007-05-08 00:39:50 -07006133 pci_dev_put(ivideo->lpcdev);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006134 if(ivideo->nbridge)
Adrian Bunk0959f0c2007-05-08 00:39:50 -07006135 pci_dev_put(ivideo->nbridge);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006136 pci_set_drvdata(pdev, NULL);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006137 if(!ivideo->sisvga_enabled)
6138 pci_disable_device(pdev);
Krzysztof Helt491bcc92009-06-16 15:34:36 -07006139 framebuffer_release(sis_fb_info);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006140 return ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006141 }
6142
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006143 printk(KERN_INFO "sisfb: Video RAM at 0x%lx, mapped to 0x%lx, size %ldk\n",
6144 ivideo->video_base, (unsigned long)ivideo->video_vbase, ivideo->video_size / 1024);
6145
6146 if(ivideo->video_offset) {
6147 printk(KERN_INFO "sisfb: Viewport offset %ldk\n",
6148 ivideo->video_offset / 1024);
6149 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07006150
6151 printk(KERN_INFO "sisfb: MMIO at 0x%lx, mapped to 0x%lx, size %ldk\n",
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006152 ivideo->mmio_base, (unsigned long)ivideo->mmio_vbase, ivideo->mmio_size / 1024);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006153
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006154
6155 /* Determine the size of the command queue */
6156 if(ivideo->sisvga_engine == SIS_300_VGA) {
6157 ivideo->cmdQueueSize = TURBO_QUEUE_AREA_SIZE;
6158 } else {
6159 if(ivideo->chip == XGI_20) {
6160 ivideo->cmdQueueSize = COMMAND_QUEUE_AREA_SIZE_Z7;
6161 } else {
6162 ivideo->cmdQueueSize = COMMAND_QUEUE_AREA_SIZE;
6163 }
6164 }
6165
6166 /* Engines are no longer initialized here; this is
6167 * now done after the first mode-switch (if the
6168 * submitted var has its acceleration flags set).
6169 */
6170
6171 /* Calculate the base of the (unused) hw cursor */
6172 ivideo->hwcursor_vbase = ivideo->video_vbase
6173 + ivideo->video_size
6174 - ivideo->cmdQueueSize
6175 - ivideo->hwcursor_size;
6176 ivideo->caps |= HW_CURSOR_CAP;
6177
6178 /* Initialize offscreen memory manager */
Linus Torvalds1da177e2005-04-16 15:20:36 -07006179 if((ivideo->havenoheap = sisfb_heap_init(ivideo))) {
6180 printk(KERN_WARNING "sisfb: Failed to initialize offscreen memory heap\n");
6181 }
6182
6183 /* Used for clearing the screen only, therefore respect our mem limit */
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006184 ivideo->SiS_Pr.VideoMemoryAddress += ivideo->video_offset;
6185 ivideo->SiS_Pr.VideoMemorySize = ivideo->sisfb_mem;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006186
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006187 ivideo->mtrr = -1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006188
6189 ivideo->vbflags = 0;
6190 ivideo->lcddefmodeidx = DEFAULT_LCDMODE;
6191 ivideo->tvdefmodeidx = DEFAULT_TVMODE;
6192 ivideo->defmodeidx = DEFAULT_MODE;
6193
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006194 ivideo->newrom = 0;
6195 if(ivideo->chip < XGI_20) {
6196 if(ivideo->bios_abase) {
6197 ivideo->newrom = SiSDetermineROMLayout661(&ivideo->SiS_Pr);
6198 }
6199 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07006200
6201 if((ivideo->sisfb_mode_idx < 0) ||
6202 ((sisbios_mode[ivideo->sisfb_mode_idx].mode_no[ivideo->mni]) != 0xFF)) {
6203
6204 sisfb_sense_crt1(ivideo);
6205
6206 sisfb_get_VB_type(ivideo);
6207
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006208 if(ivideo->vbflags2 & VB2_VIDEOBRIDGE) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07006209 sisfb_detect_VB_connect(ivideo);
6210 }
6211
6212 ivideo->currentvbflags = ivideo->vbflags & (VB_VIDEOBRIDGE | TV_STANDARD);
6213
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006214 /* Decide on which CRT2 device to use */
6215 if(ivideo->vbflags2 & VB2_VIDEOBRIDGE) {
6216 if(ivideo->sisfb_crt2type != -1) {
6217 if((ivideo->sisfb_crt2type == CRT2_LCD) &&
6218 (ivideo->vbflags & CRT2_LCD)) {
6219 ivideo->currentvbflags |= CRT2_LCD;
6220 } else if(ivideo->sisfb_crt2type != CRT2_LCD) {
6221 ivideo->currentvbflags |= ivideo->sisfb_crt2type;
6222 }
6223 } else {
6224 /* Chrontel 700x TV detection often unreliable, therefore
6225 * use a different default order on such machines
6226 */
6227 if((ivideo->sisvga_engine == SIS_300_VGA) &&
6228 (ivideo->vbflags2 & VB2_CHRONTEL)) {
6229 if(ivideo->vbflags & CRT2_LCD)
6230 ivideo->currentvbflags |= CRT2_LCD;
6231 else if(ivideo->vbflags & CRT2_TV)
6232 ivideo->currentvbflags |= CRT2_TV;
6233 else if(ivideo->vbflags & CRT2_VGA)
6234 ivideo->currentvbflags |= CRT2_VGA;
6235 } else {
6236 if(ivideo->vbflags & CRT2_TV)
6237 ivideo->currentvbflags |= CRT2_TV;
6238 else if(ivideo->vbflags & CRT2_LCD)
6239 ivideo->currentvbflags |= CRT2_LCD;
6240 else if(ivideo->vbflags & CRT2_VGA)
6241 ivideo->currentvbflags |= CRT2_VGA;
6242 }
6243 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07006244 }
6245
6246 if(ivideo->vbflags & CRT2_LCD) {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006247 sisfb_detect_lcd_type(ivideo);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006248 }
6249
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006250 sisfb_save_pdc_emi(ivideo);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006251
6252 if(!ivideo->sisfb_crt1off) {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006253 sisfb_handle_ddc(ivideo, &ivideo->sisfb_thismonitor, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006254 } else {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006255 if((ivideo->vbflags2 & VB2_SISTMDSBRIDGE) &&
6256 (ivideo->vbflags & (CRT2_VGA | CRT2_LCD))) {
6257 sisfb_handle_ddc(ivideo, &ivideo->sisfb_thismonitor, 1);
6258 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07006259 }
6260
6261 if(ivideo->sisfb_mode_idx >= 0) {
6262 int bu = ivideo->sisfb_mode_idx;
6263 ivideo->sisfb_mode_idx = sisfb_validate_mode(ivideo,
6264 ivideo->sisfb_mode_idx, ivideo->currentvbflags);
6265 if(bu != ivideo->sisfb_mode_idx) {
6266 printk(KERN_ERR "Mode %dx%dx%d failed validation\n",
6267 sisbios_mode[bu].xres,
6268 sisbios_mode[bu].yres,
6269 sisbios_mode[bu].bpp);
6270 }
6271 }
6272
6273 if(ivideo->sisfb_mode_idx < 0) {
6274 switch(ivideo->currentvbflags & VB_DISPTYPE_DISP2) {
6275 case CRT2_LCD:
6276 ivideo->sisfb_mode_idx = ivideo->lcddefmodeidx;
6277 break;
6278 case CRT2_TV:
6279 ivideo->sisfb_mode_idx = ivideo->tvdefmodeidx;
6280 break;
6281 default:
6282 ivideo->sisfb_mode_idx = ivideo->defmodeidx;
6283 break;
6284 }
6285 }
6286
6287 ivideo->mode_no = sisbios_mode[ivideo->sisfb_mode_idx].mode_no[ivideo->mni];
6288
6289 if(ivideo->refresh_rate != 0) {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006290 sisfb_search_refresh_rate(ivideo, ivideo->refresh_rate,
6291 ivideo->sisfb_mode_idx);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006292 }
6293
6294 if(ivideo->rate_idx == 0) {
6295 ivideo->rate_idx = sisbios_mode[ivideo->sisfb_mode_idx].rate_idx;
6296 ivideo->refresh_rate = 60;
6297 }
6298
6299 if(ivideo->sisfb_thismonitor.datavalid) {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006300 if(!sisfb_verify_rate(ivideo, &ivideo->sisfb_thismonitor,
6301 ivideo->sisfb_mode_idx,
6302 ivideo->rate_idx,
6303 ivideo->refresh_rate)) {
6304 printk(KERN_INFO "sisfb: WARNING: Refresh rate "
6305 "exceeds monitor specs!\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07006306 }
6307 }
6308
6309 ivideo->video_bpp = sisbios_mode[ivideo->sisfb_mode_idx].bpp;
6310 ivideo->video_width = sisbios_mode[ivideo->sisfb_mode_idx].xres;
6311 ivideo->video_height = sisbios_mode[ivideo->sisfb_mode_idx].yres;
6312
6313 sisfb_set_vparms(ivideo);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006314
Linus Torvalds1da177e2005-04-16 15:20:36 -07006315 printk(KERN_INFO "sisfb: Default mode is %dx%dx%d (%dHz)\n",
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006316 ivideo->video_width, ivideo->video_height, ivideo->video_bpp,
Linus Torvalds1da177e2005-04-16 15:20:36 -07006317 ivideo->refresh_rate);
6318
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006319 /* Set up the default var according to chosen default display mode */
Linus Torvalds1da177e2005-04-16 15:20:36 -07006320 ivideo->default_var.xres = ivideo->default_var.xres_virtual = ivideo->video_width;
6321 ivideo->default_var.yres = ivideo->default_var.yres_virtual = ivideo->video_height;
6322 ivideo->default_var.bits_per_pixel = ivideo->video_bpp;
6323
6324 sisfb_bpp_to_var(ivideo, &ivideo->default_var);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006325
Linus Torvalds1da177e2005-04-16 15:20:36 -07006326 ivideo->default_var.pixclock = (u32) (1000000000 /
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006327 sisfb_mode_rate_to_dclock(&ivideo->SiS_Pr, ivideo->mode_no, ivideo->rate_idx));
6328
6329 if(sisfb_mode_rate_to_ddata(&ivideo->SiS_Pr, ivideo->mode_no,
6330 ivideo->rate_idx, &ivideo->default_var)) {
6331 if((ivideo->default_var.vmode & FB_VMODE_MASK) == FB_VMODE_DOUBLE) {
6332 ivideo->default_var.pixclock <<= 1;
6333 }
6334 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07006335
6336 if(ivideo->sisfb_ypan) {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006337 /* Maximize regardless of sisfb_max at startup */
6338 ivideo->default_var.yres_virtual =
6339 sisfb_calc_maxyres(ivideo, &ivideo->default_var);
6340 if(ivideo->default_var.yres_virtual < ivideo->default_var.yres) {
6341 ivideo->default_var.yres_virtual = ivideo->default_var.yres;
6342 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07006343 }
6344
6345 sisfb_calc_pitch(ivideo, &ivideo->default_var);
6346
6347 ivideo->accel = 0;
6348 if(ivideo->sisfb_accel) {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006349 ivideo->accel = -1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006350#ifdef STUPID_ACCELF_TEXT_SHIT
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006351 ivideo->default_var.accel_flags |= FB_ACCELF_TEXT;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006352#endif
6353 }
6354 sisfb_initaccel(ivideo);
6355
6356#if defined(FBINFO_HWACCEL_DISABLED) && defined(FBINFO_HWACCEL_XPAN)
6357 sis_fb_info->flags = FBINFO_DEFAULT |
6358 FBINFO_HWACCEL_YPAN |
6359 FBINFO_HWACCEL_XPAN |
6360 FBINFO_HWACCEL_COPYAREA |
6361 FBINFO_HWACCEL_FILLRECT |
6362 ((ivideo->accel) ? 0 : FBINFO_HWACCEL_DISABLED);
6363#else
6364 sis_fb_info->flags = FBINFO_FLAG_DEFAULT;
6365#endif
6366 sis_fb_info->var = ivideo->default_var;
6367 sis_fb_info->fix = ivideo->sisfb_fix;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006368 sis_fb_info->screen_base = ivideo->video_vbase + ivideo->video_offset;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006369 sis_fb_info->fbops = &sisfb_ops;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006370 sis_fb_info->pseudo_palette = ivideo->pseudo_palette;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006371
Linus Torvalds1da177e2005-04-16 15:20:36 -07006372 fb_alloc_cmap(&sis_fb_info->cmap, 256 , 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006373
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006374 printk(KERN_DEBUG "sisfb: Initial vbflags 0x%x\n", (int)ivideo->vbflags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006375
6376#ifdef CONFIG_MTRR
6377 ivideo->mtrr = mtrr_add(ivideo->video_base, ivideo->video_size,
6378 MTRR_TYPE_WRCOMB, 1);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006379 if(ivideo->mtrr < 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07006380 printk(KERN_DEBUG "sisfb: Failed to add MTRRs\n");
6381 }
6382#endif
6383
Linus Torvalds1da177e2005-04-16 15:20:36 -07006384 if(register_framebuffer(sis_fb_info) < 0) {
6385 printk(KERN_ERR "sisfb: Fatal error: Failed to register framebuffer\n");
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006386 ret = -EINVAL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006387 iounmap(ivideo->mmio_vbase);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006388 goto error_0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006389 }
6390
6391 ivideo->registered = 1;
6392
6393 /* Enlist us */
6394 ivideo->next = card_list;
6395 card_list = ivideo;
6396
6397 printk(KERN_INFO "sisfb: 2D acceleration is %s, y-panning %s\n",
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006398 ivideo->sisfb_accel ? "enabled" : "disabled",
6399 ivideo->sisfb_ypan ?
6400 (ivideo->sisfb_max ? "enabled (auto-max)" :
6401 "enabled (no auto-max)") :
6402 "disabled");
Linus Torvalds1da177e2005-04-16 15:20:36 -07006403
6404
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006405 printk(KERN_INFO "fb%d: %s frame buffer device version %d.%d.%d\n",
Michal Piotrowski43704092006-10-03 01:15:00 -07006406 sis_fb_info->node, ivideo->myid, VER_MAJOR, VER_MINOR, VER_LEVEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006407
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006408 printk(KERN_INFO "sisfb: Copyright (C) 2001-2005 Thomas Winischhofer\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07006409
6410 } /* if mode = "none" */
6411
6412 return 0;
6413}
6414
6415/*****************************************************/
6416/* PCI DEVICE HANDLING */
6417/*****************************************************/
6418
6419static void __devexit sisfb_remove(struct pci_dev *pdev)
6420{
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006421 struct sis_video_info *ivideo = pci_get_drvdata(pdev);
6422 struct fb_info *sis_fb_info = ivideo->memyselfandi;
6423 int registered = ivideo->registered;
6424 int modechanged = ivideo->modechanged;
6425
Linus Torvalds1da177e2005-04-16 15:20:36 -07006426 /* Unmap */
Linus Torvalds1da177e2005-04-16 15:20:36 -07006427 iounmap(ivideo->mmio_vbase);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006428 iounmap(ivideo->video_vbase);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006429
6430 /* Release mem regions */
6431 release_mem_region(ivideo->video_base, ivideo->video_size);
6432 release_mem_region(ivideo->mmio_base, ivideo->mmio_size);
6433
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006434 vfree(ivideo->bios_abase);
6435
6436 if(ivideo->lpcdev)
Adrian Bunk0959f0c2007-05-08 00:39:50 -07006437 pci_dev_put(ivideo->lpcdev);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006438
6439 if(ivideo->nbridge)
Adrian Bunk0959f0c2007-05-08 00:39:50 -07006440 pci_dev_put(ivideo->nbridge);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006441
Linus Torvalds1da177e2005-04-16 15:20:36 -07006442#ifdef CONFIG_MTRR
6443 /* Release MTRR region */
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006444 if(ivideo->mtrr >= 0)
Linus Torvalds1da177e2005-04-16 15:20:36 -07006445 mtrr_del(ivideo->mtrr, ivideo->video_base, ivideo->video_size);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006446#endif
6447
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006448 pci_set_drvdata(pdev, NULL);
6449
6450 /* If device was disabled when starting, disable
6451 * it when quitting.
6452 */
6453 if(!ivideo->sisvga_enabled)
6454 pci_disable_device(pdev);
6455
Linus Torvalds1da177e2005-04-16 15:20:36 -07006456 /* Unregister the framebuffer */
6457 if(ivideo->registered) {
6458 unregister_framebuffer(sis_fb_info);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006459 framebuffer_release(sis_fb_info);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006460 }
6461
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006462 /* OK, our ivideo is gone for good from here. */
Linus Torvalds1da177e2005-04-16 15:20:36 -07006463
6464 /* TODO: Restore the initial mode
6465 * This sounds easy but is as good as impossible
6466 * on many machines with SiS chip and video bridge
6467 * since text modes are always set up differently
6468 * from machine to machine. Depends on the type
6469 * of integration between chipset and bridge.
6470 */
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006471 if(registered && modechanged)
6472 printk(KERN_INFO
6473 "sisfb: Restoring of text mode not supported yet\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07006474};
6475
6476static struct pci_driver sisfb_driver = {
6477 .name = "sisfb",
6478 .id_table = sisfb_pci_table,
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006479 .probe = sisfb_probe,
Linus Torvalds1da177e2005-04-16 15:20:36 -07006480 .remove = __devexit_p(sisfb_remove)
6481};
6482
Adrian Bunk14aefd12008-07-23 21:31:12 -07006483static int __init sisfb_init(void)
Linus Torvalds1da177e2005-04-16 15:20:36 -07006484{
Linus Torvalds1da177e2005-04-16 15:20:36 -07006485#ifndef MODULE
6486 char *options = NULL;
6487
6488 if(fb_get_options("sisfb", &options))
6489 return -ENODEV;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006490
Linus Torvalds1da177e2005-04-16 15:20:36 -07006491 sisfb_setup(options);
6492#endif
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006493 return pci_register_driver(&sisfb_driver);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006494}
6495
Linus Torvalds1da177e2005-04-16 15:20:36 -07006496#ifndef MODULE
6497module_init(sisfb_init);
6498#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -07006499
6500/*****************************************************/
6501/* MODULE */
6502/*****************************************************/
6503
6504#ifdef MODULE
6505
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006506static char *mode = NULL;
6507static int vesa = -1;
6508static unsigned int rate = 0;
6509static unsigned int crt1off = 1;
6510static unsigned int mem = 0;
6511static char *forcecrt2type = NULL;
6512static int forcecrt1 = -1;
6513static int pdc = -1;
6514static int pdc1 = -1;
6515static int noaccel = -1;
6516static int noypan = -1;
6517static int nomax = -1;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006518static int userom = -1;
6519static int useoem = -1;
6520static char *tvstandard = NULL;
6521static int nocrt2rate = 0;
6522static int scalelcd = -1;
6523static char *specialtiming = NULL;
6524static int lvdshl = -1;
6525static int tvxposoffset = 0, tvyposoffset = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006526#if !defined(__i386__) && !defined(__x86_64__)
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006527static int resetcard = 0;
6528static int videoram = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006529#endif
6530
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006531static int __init sisfb_init_module(void)
6532{
6533 sisfb_setdefaultparms();
6534
6535 if(rate)
6536 sisfb_parm_rate = rate;
6537
6538 if((scalelcd == 0) || (scalelcd == 1))
6539 sisfb_scalelcd = scalelcd ^ 1;
6540
6541 /* Need to check crt2 type first for fstn/dstn */
6542
6543 if(forcecrt2type)
6544 sisfb_search_crt2type(forcecrt2type);
6545
6546 if(tvstandard)
6547 sisfb_search_tvstd(tvstandard);
6548
6549 if(mode)
Richard Knutssonc30660ea2007-02-12 00:55:06 -08006550 sisfb_search_mode(mode, false);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006551 else if(vesa != -1)
Richard Knutssonc30660ea2007-02-12 00:55:06 -08006552 sisfb_search_vesamode(vesa, false);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006553
6554 sisfb_crt1off = (crt1off == 0) ? 1 : 0;
6555
6556 sisfb_forcecrt1 = forcecrt1;
6557 if(forcecrt1 == 1)
6558 sisfb_crt1off = 0;
6559 else if(forcecrt1 == 0)
6560 sisfb_crt1off = 1;
6561
6562 if(noaccel == 1)
6563 sisfb_accel = 0;
6564 else if(noaccel == 0)
6565 sisfb_accel = 1;
6566
6567 if(noypan == 1)
6568 sisfb_ypan = 0;
6569 else if(noypan == 0)
6570 sisfb_ypan = 1;
6571
6572 if(nomax == 1)
6573 sisfb_max = 0;
6574 else if(nomax == 0)
6575 sisfb_max = 1;
6576
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006577 if(mem)
6578 sisfb_parm_mem = mem;
6579
6580 if(userom != -1)
6581 sisfb_userom = userom;
6582
6583 if(useoem != -1)
6584 sisfb_useoem = useoem;
6585
6586 if(pdc != -1)
6587 sisfb_pdc = (pdc & 0x7f);
6588
6589 if(pdc1 != -1)
6590 sisfb_pdca = (pdc1 & 0x1f);
6591
6592 sisfb_nocrt2rate = nocrt2rate;
6593
6594 if(specialtiming)
6595 sisfb_search_specialtiming(specialtiming);
6596
6597 if((lvdshl >= 0) && (lvdshl <= 3))
6598 sisfb_lvdshl = lvdshl;
6599
6600 sisfb_tvxposoffset = tvxposoffset;
6601 sisfb_tvyposoffset = tvyposoffset;
6602
6603#if !defined(__i386__) && !defined(__x86_64__)
6604 sisfb_resetcard = (resetcard) ? 1 : 0;
6605 if(videoram)
6606 sisfb_videoram = videoram;
6607#endif
6608
6609 return sisfb_init();
6610}
6611
6612static void __exit sisfb_remove_module(void)
6613{
6614 pci_unregister_driver(&sisfb_driver);
6615 printk(KERN_DEBUG "sisfb: Module unloaded\n");
6616}
6617
6618module_init(sisfb_init_module);
6619module_exit(sisfb_remove_module);
6620
6621MODULE_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 -07006622MODULE_LICENSE("GPL");
6623MODULE_AUTHOR("Thomas Winischhofer <thomas@winischhofer.net>, Others");
6624
Linus Torvalds1da177e2005-04-16 15:20:36 -07006625module_param(mem, int, 0);
6626module_param(noaccel, int, 0);
6627module_param(noypan, int, 0);
6628module_param(nomax, int, 0);
6629module_param(userom, int, 0);
6630module_param(useoem, int, 0);
6631module_param(mode, charp, 0);
6632module_param(vesa, int, 0);
6633module_param(rate, int, 0);
6634module_param(forcecrt1, int, 0);
6635module_param(forcecrt2type, charp, 0);
6636module_param(scalelcd, int, 0);
6637module_param(pdc, int, 0);
6638module_param(pdc1, int, 0);
6639module_param(specialtiming, charp, 0);
6640module_param(lvdshl, int, 0);
6641module_param(tvstandard, charp, 0);
6642module_param(tvxposoffset, int, 0);
6643module_param(tvyposoffset, int, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006644module_param(nocrt2rate, int, 0);
6645#if !defined(__i386__) && !defined(__x86_64__)
6646module_param(resetcard, int, 0);
6647module_param(videoram, int, 0);
6648#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -07006649
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006650MODULE_PARM_DESC(mem,
6651 "\nDetermines the beginning of the video memory heap in KB. This heap is used\n"
6652 "for video RAM management for eg. DRM/DRI. On 300 series, the default depends\n"
6653 "on the amount of video RAM available. If 8MB of video RAM or less is available,\n"
6654 "the heap starts at 4096KB, if between 8 and 16MB are available at 8192KB,\n"
6655 "otherwise at 12288KB. On 315/330/340 series, the heap size is 32KB by default.\n"
6656 "The value is to be specified without 'KB'.\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07006657
6658MODULE_PARM_DESC(noaccel,
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006659 "\nIf set to anything other than 0, 2D acceleration will be disabled.\n"
Linus Torvalds1da177e2005-04-16 15:20:36 -07006660 "(default: 0)\n");
6661
6662MODULE_PARM_DESC(noypan,
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006663 "\nIf set to anything other than 0, y-panning will be disabled and scrolling\n"
6664 "will be performed by redrawing the screen. (default: 0)\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07006665
6666MODULE_PARM_DESC(nomax,
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006667 "\nIf y-panning is enabled, sisfb will by default use the entire available video\n"
Linus Torvalds1da177e2005-04-16 15:20:36 -07006668 "memory for the virtual screen in order to optimize scrolling performance. If\n"
6669 "this is set to anything other than 0, sisfb will not do this and thereby \n"
6670 "enable the user to positively specify a virtual Y size of the screen using\n"
6671 "fbset. (default: 0)\n");
6672
Linus Torvalds1da177e2005-04-16 15:20:36 -07006673MODULE_PARM_DESC(mode,
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006674 "\nSelects the desired default display mode in the format XxYxDepth,\n"
6675 "eg. 1024x768x16. Other formats supported include XxY-Depth and\n"
Linus Torvalds1da177e2005-04-16 15:20:36 -07006676 "XxY-Depth@Rate. If the parameter is only one (decimal or hexadecimal)\n"
6677 "number, it will be interpreted as a VESA mode number. (default: 800x600x8)\n");
6678
6679MODULE_PARM_DESC(vesa,
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006680 "\nSelects the desired default display mode by VESA defined mode number, eg.\n"
6681 "0x117 (default: 0x0103)\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07006682
6683MODULE_PARM_DESC(rate,
6684 "\nSelects the desired vertical refresh rate for CRT1 (external VGA) in Hz.\n"
6685 "If the mode is specified in the format XxY-Depth@Rate, this parameter\n"
6686 "will be ignored (default: 60)\n");
6687
6688MODULE_PARM_DESC(forcecrt1,
6689 "\nNormally, the driver autodetects whether or not CRT1 (external VGA) is \n"
6690 "connected. With this option, the detection can be overridden (1=CRT1 ON,\n"
6691 "0=CRT1 OFF) (default: [autodetected])\n");
6692
6693MODULE_PARM_DESC(forcecrt2type,
6694 "\nIf this option is omitted, the driver autodetects CRT2 output devices, such as\n"
6695 "LCD, TV or secondary VGA. With this option, this autodetection can be\n"
6696 "overridden. Possible parameters are LCD, TV, VGA or NONE. NONE disables CRT2.\n"
6697 "On systems with a SiS video bridge, parameters SVIDEO, COMPOSITE or SCART can\n"
6698 "be used instead of TV to override the TV detection. Furthermore, on systems\n"
6699 "with a SiS video bridge, SVIDEO+COMPOSITE, HIVISION, YPBPR480I, YPBPR480P,\n"
6700 "YPBPR720P and YPBPR1080I are understood. However, whether or not these work\n"
6701 "depends on the very hardware in use. (default: [autodetected])\n");
6702
6703MODULE_PARM_DESC(scalelcd,
6704 "\nSetting this to 1 will force the driver to scale the LCD image to the panel's\n"
6705 "native resolution. Setting it to 0 will disable scaling; LVDS panels will\n"
6706 "show black bars around the image, TMDS panels will probably do the scaling\n"
6707 "themselves. Default: 1 on LVDS panels, 0 on TMDS panels\n");
6708
6709MODULE_PARM_DESC(pdc,
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006710 "\nThis is for manually selecting the LCD panel delay compensation. The driver\n"
Linus Torvalds1da177e2005-04-16 15:20:36 -07006711 "should detect this correctly in most cases; however, sometimes this is not\n"
6712 "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 -07006713 "on a 300 series chipset; 6 on other chipsets. If the problem persists, try\n"
6714 "other values (on 300 series: between 4 and 60 in steps of 4; otherwise: any\n"
6715 "value from 0 to 31). (default: autodetected, if LCD is active during start)\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07006716
6717#ifdef CONFIG_FB_SIS_315
6718MODULE_PARM_DESC(pdc1,
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006719 "\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 -07006720 "series only. (default: autodetected if LCD is in LCD-via-CRT1 mode during\n"
6721 "startup) - Note: currently, this has no effect because LCD-via-CRT1 is not\n"
6722 "implemented yet.\n");
6723#endif
6724
6725MODULE_PARM_DESC(specialtiming,
6726 "\nPlease refer to documentation for more information on this option.\n");
6727
6728MODULE_PARM_DESC(lvdshl,
6729 "\nPlease refer to documentation for more information on this option.\n");
6730
6731MODULE_PARM_DESC(tvstandard,
6732 "\nThis allows overriding the BIOS default for the TV standard. Valid choices are\n"
6733 "pal, ntsc, palm and paln. (default: [auto; pal or ntsc only])\n");
6734
6735MODULE_PARM_DESC(tvxposoffset,
6736 "\nRelocate TV output horizontally. Possible parameters: -32 through 32.\n"
6737 "Default: 0\n");
6738
6739MODULE_PARM_DESC(tvyposoffset,
6740 "\nRelocate TV output vertically. Possible parameters: -32 through 32.\n"
6741 "Default: 0\n");
6742
Linus Torvalds1da177e2005-04-16 15:20:36 -07006743MODULE_PARM_DESC(nocrt2rate,
6744 "\nSetting this to 1 will force the driver to use the default refresh rate for\n"
6745 "CRT2 if CRT2 type is VGA. (default: 0, use same rate as CRT1)\n");
6746
Linus Torvalds1da177e2005-04-16 15:20:36 -07006747#if !defined(__i386__) && !defined(__x86_64__)
6748#ifdef CONFIG_FB_SIS_300
6749MODULE_PARM_DESC(resetcard,
6750 "\nSet this to 1 in order to reset (POST) the card on non-x86 machines where\n"
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006751 "the BIOS did not POST the card (only supported for SiS 300/305 and XGI cards\n"
6752 "currently). Default: 0\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07006753
6754MODULE_PARM_DESC(videoram,
6755 "\nSet this to the amount of video RAM (in kilobyte) the card has. Required on\n"
6756 "some non-x86 architectures where the memory auto detection fails. Only\n"
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006757 "relevant if resetcard is set, too. SiS300/305 only. Default: [auto-detect]\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07006758#endif
6759#endif
6760
Linus Torvalds1da177e2005-04-16 15:20:36 -07006761#endif /* /MODULE */
6762
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006763/* _GPL only for new symbols. */
Linus Torvalds1da177e2005-04-16 15:20:36 -07006764EXPORT_SYMBOL(sis_malloc);
6765EXPORT_SYMBOL(sis_free);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006766EXPORT_SYMBOL_GPL(sis_malloc_new);
6767EXPORT_SYMBOL_GPL(sis_free_new);
6768
Linus Torvalds1da177e2005-04-16 15:20:36 -07006769
6770