blob: a531a0f7cdf2d7ba27e0f44b8028efa0307d7ab2 [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:
1704 sisvbblank.count = 0;
1705 sisvbblank.flags = sisfb_setupvbblankflags(ivideo, &sisvbblank.vcount, &sisvbblank.hcount);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001706
1707 if(copy_to_user((void __user *)arg, &sisvbblank, sizeof(sisvbblank)))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001708 return -EFAULT;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001709
Linus Torvalds1da177e2005-04-16 15:20:36 -07001710 break;
1711
1712 case SISFB_GET_INFO_SIZE:
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001713 return put_user(sizeof(struct sisfb_info), argp);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001714
1715 case SISFB_GET_INFO_OLD:
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001716 if(ivideo->warncount++ < 10)
1717 printk(KERN_INFO
1718 "sisfb: Deprecated ioctl call received - update your application!\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001719 case SISFB_GET_INFO: /* For communication with X driver */
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001720 ivideo->sisfb_infoblock.sisfb_id = SISFB_ID;
1721 ivideo->sisfb_infoblock.sisfb_version = VER_MAJOR;
1722 ivideo->sisfb_infoblock.sisfb_revision = VER_MINOR;
1723 ivideo->sisfb_infoblock.sisfb_patchlevel = VER_LEVEL;
1724 ivideo->sisfb_infoblock.chip_id = ivideo->chip_id;
1725 ivideo->sisfb_infoblock.sisfb_pci_vendor = ivideo->chip_vendor;
1726 ivideo->sisfb_infoblock.memory = ivideo->video_size / 1024;
1727 ivideo->sisfb_infoblock.heapstart = ivideo->heapstart / 1024;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001728 if(ivideo->modechanged) {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001729 ivideo->sisfb_infoblock.fbvidmode = ivideo->mode_no;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001730 } else {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001731 ivideo->sisfb_infoblock.fbvidmode = ivideo->modeprechange;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001732 }
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001733 ivideo->sisfb_infoblock.sisfb_caps = ivideo->caps;
1734 ivideo->sisfb_infoblock.sisfb_tqlen = ivideo->cmdQueueSize / 1024;
1735 ivideo->sisfb_infoblock.sisfb_pcibus = ivideo->pcibus;
1736 ivideo->sisfb_infoblock.sisfb_pcislot = ivideo->pcislot;
1737 ivideo->sisfb_infoblock.sisfb_pcifunc = ivideo->pcifunc;
1738 ivideo->sisfb_infoblock.sisfb_lcdpdc = ivideo->detectedpdc;
1739 ivideo->sisfb_infoblock.sisfb_lcdpdca = ivideo->detectedpdca;
1740 ivideo->sisfb_infoblock.sisfb_lcda = ivideo->detectedlcda;
1741 ivideo->sisfb_infoblock.sisfb_vbflags = ivideo->vbflags;
1742 ivideo->sisfb_infoblock.sisfb_currentvbflags = ivideo->currentvbflags;
1743 ivideo->sisfb_infoblock.sisfb_scalelcd = ivideo->SiS_Pr.UsePanelScaler;
1744 ivideo->sisfb_infoblock.sisfb_specialtiming = ivideo->SiS_Pr.SiS_CustomT;
1745 ivideo->sisfb_infoblock.sisfb_haveemi = ivideo->SiS_Pr.HaveEMI ? 1 : 0;
1746 ivideo->sisfb_infoblock.sisfb_haveemilcd = ivideo->SiS_Pr.HaveEMILCD ? 1 : 0;
1747 ivideo->sisfb_infoblock.sisfb_emi30 = ivideo->SiS_Pr.EMI_30;
1748 ivideo->sisfb_infoblock.sisfb_emi31 = ivideo->SiS_Pr.EMI_31;
1749 ivideo->sisfb_infoblock.sisfb_emi32 = ivideo->SiS_Pr.EMI_32;
1750 ivideo->sisfb_infoblock.sisfb_emi33 = ivideo->SiS_Pr.EMI_33;
1751 ivideo->sisfb_infoblock.sisfb_tvxpos = (u16)(ivideo->tvxpos + 32);
1752 ivideo->sisfb_infoblock.sisfb_tvypos = (u16)(ivideo->tvypos + 32);
1753 ivideo->sisfb_infoblock.sisfb_heapsize = ivideo->sisfb_heap_size / 1024;
1754 ivideo->sisfb_infoblock.sisfb_videooffset = ivideo->video_offset;
1755 ivideo->sisfb_infoblock.sisfb_curfstn = ivideo->curFSTN;
1756 ivideo->sisfb_infoblock.sisfb_curdstn = ivideo->curDSTN;
1757 ivideo->sisfb_infoblock.sisfb_vbflags2 = ivideo->vbflags2;
1758 ivideo->sisfb_infoblock.sisfb_can_post = ivideo->sisfb_can_post ? 1 : 0;
1759 ivideo->sisfb_infoblock.sisfb_card_posted = ivideo->sisfb_card_posted ? 1 : 0;
1760 ivideo->sisfb_infoblock.sisfb_was_boot_device = ivideo->sisfb_was_boot_device ? 1 : 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001761
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001762 if(copy_to_user((void __user *)arg, &ivideo->sisfb_infoblock,
1763 sizeof(ivideo->sisfb_infoblock)))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001764 return -EFAULT;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001765
Linus Torvalds1da177e2005-04-16 15:20:36 -07001766 break;
1767
1768 case SISFB_GET_VBRSTATUS_OLD:
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001769 if(ivideo->warncount++ < 10)
1770 printk(KERN_INFO
1771 "sisfb: Deprecated ioctl call received - update your application!\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001772 case SISFB_GET_VBRSTATUS:
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001773 if(sisfb_CheckVBRetrace(ivideo))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001774 return put_user((u32)1, argp);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001775 else
Linus Torvalds1da177e2005-04-16 15:20:36 -07001776 return put_user((u32)0, argp);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001777
1778 case SISFB_GET_AUTOMAXIMIZE_OLD:
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001779 if(ivideo->warncount++ < 10)
1780 printk(KERN_INFO
1781 "sisfb: Deprecated ioctl call received - update your application!\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001782 case SISFB_GET_AUTOMAXIMIZE:
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001783 if(ivideo->sisfb_max)
1784 return put_user((u32)1, argp);
1785 else
1786 return put_user((u32)0, argp);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001787
1788 case SISFB_SET_AUTOMAXIMIZE_OLD:
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001789 if(ivideo->warncount++ < 10)
1790 printk(KERN_INFO
1791 "sisfb: Deprecated ioctl call received - update your application!\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001792 case SISFB_SET_AUTOMAXIMIZE:
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001793 if(get_user(gpu32, argp))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001794 return -EFAULT;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001795
Linus Torvalds1da177e2005-04-16 15:20:36 -07001796 ivideo->sisfb_max = (gpu32) ? 1 : 0;
1797 break;
1798
1799 case SISFB_SET_TVPOSOFFSET:
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001800 if(get_user(gpu32, argp))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001801 return -EFAULT;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001802
Linus Torvalds1da177e2005-04-16 15:20:36 -07001803 sisfb_set_TVxposoffset(ivideo, ((int)(gpu32 >> 16)) - 32);
1804 sisfb_set_TVyposoffset(ivideo, ((int)(gpu32 & 0xffff)) - 32);
1805 break;
1806
1807 case SISFB_GET_TVPOSOFFSET:
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001808 return put_user((u32)(((ivideo->tvxpos+32)<<16)|((ivideo->tvypos+32)&0xffff)),
1809 argp);
1810
1811 case SISFB_COMMAND:
1812 if(copy_from_user(&ivideo->sisfb_command, (void __user *)arg,
1813 sizeof(struct sisfb_cmd)))
1814 return -EFAULT;
1815
1816 sisfb_handle_command(ivideo, &ivideo->sisfb_command);
1817
1818 if(copy_to_user((void __user *)arg, &ivideo->sisfb_command,
1819 sizeof(struct sisfb_cmd)))
1820 return -EFAULT;
1821
1822 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001823
1824 case SISFB_SET_LOCK:
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001825 if(get_user(gpu32, argp))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001826 return -EFAULT;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001827
Linus Torvalds1da177e2005-04-16 15:20:36 -07001828 ivideo->sisfblocked = (gpu32) ? 1 : 0;
1829 break;
1830
1831 default:
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001832#ifdef SIS_NEW_CONFIG_COMPAT
Linus Torvalds1da177e2005-04-16 15:20:36 -07001833 return -ENOIOCTLCMD;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001834#else
1835 return -EINVAL;
1836#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -07001837 }
1838 return 0;
1839}
1840
Linus Torvalds1da177e2005-04-16 15:20:36 -07001841static int
1842sisfb_get_fix(struct fb_fix_screeninfo *fix, int con, struct fb_info *info)
1843{
1844 struct sis_video_info *ivideo = (struct sis_video_info *)info->par;
1845
1846 memset(fix, 0, sizeof(struct fb_fix_screeninfo));
1847
1848 strcpy(fix->id, ivideo->myid);
1849
Krzysztof Helt537a1bf2009-06-30 11:41:29 -07001850 mutex_lock(&info->mm_lock);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001851 fix->smem_start = ivideo->video_base + ivideo->video_offset;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001852 fix->smem_len = ivideo->sisfb_mem;
Krzysztof Helt537a1bf2009-06-30 11:41:29 -07001853 mutex_unlock(&info->mm_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001854 fix->type = FB_TYPE_PACKED_PIXELS;
1855 fix->type_aux = 0;
1856 fix->visual = (ivideo->video_bpp == 8) ? FB_VISUAL_PSEUDOCOLOR : FB_VISUAL_TRUECOLOR;
1857 fix->xpanstep = 1;
1858 fix->ypanstep = (ivideo->sisfb_ypan) ? 1 : 0;
1859 fix->ywrapstep = 0;
1860 fix->line_length = ivideo->video_linelength;
1861 fix->mmio_start = ivideo->mmio_base;
1862 fix->mmio_len = ivideo->mmio_size;
1863 if(ivideo->sisvga_engine == SIS_300_VGA) {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001864 fix->accel = FB_ACCEL_SIS_GLAMOUR;
1865 } else if((ivideo->chip == SIS_330) ||
1866 (ivideo->chip == SIS_760) ||
1867 (ivideo->chip == SIS_761)) {
1868 fix->accel = FB_ACCEL_SIS_XABRE;
1869 } else if(ivideo->chip == XGI_20) {
1870 fix->accel = FB_ACCEL_XGI_VOLARI_Z;
1871 } else if(ivideo->chip >= XGI_40) {
1872 fix->accel = FB_ACCEL_XGI_VOLARI_V;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001873 } else {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001874 fix->accel = FB_ACCEL_SIS_GLAMOUR_2;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001875 }
1876
1877 return 0;
1878}
1879
1880/* ---------------- fb_ops structures ----------------- */
1881
Linus Torvalds1da177e2005-04-16 15:20:36 -07001882static struct fb_ops sisfb_ops = {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001883 .owner = THIS_MODULE,
1884 .fb_open = sisfb_open,
1885 .fb_release = sisfb_release,
1886 .fb_check_var = sisfb_check_var,
1887 .fb_set_par = sisfb_set_par,
1888 .fb_setcolreg = sisfb_setcolreg,
1889 .fb_pan_display = sisfb_pan_display,
1890 .fb_blank = sisfb_blank,
1891 .fb_fillrect = fbcon_sis_fillrect,
1892 .fb_copyarea = fbcon_sis_copyarea,
1893 .fb_imageblit = cfb_imageblit,
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001894 .fb_sync = fbcon_sis_sync,
1895#ifdef SIS_NEW_CONFIG_COMPAT
Christoph Hellwig67a66802006-01-14 13:21:25 -08001896 .fb_compat_ioctl= sisfb_ioctl,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001897#endif
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001898 .fb_ioctl = sisfb_ioctl
Linus Torvalds1da177e2005-04-16 15:20:36 -07001899};
Linus Torvalds1da177e2005-04-16 15:20:36 -07001900
1901/* ---------------- Chip generation dependent routines ---------------- */
1902
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001903static struct pci_dev * __devinit
1904sisfb_get_northbridge(int basechipid)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001905{
1906 struct pci_dev *pdev = NULL;
1907 int nbridgenum, nbridgeidx, i;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001908 static const unsigned short nbridgeids[] = {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001909 PCI_DEVICE_ID_SI_540, /* for SiS 540 VGA */
1910 PCI_DEVICE_ID_SI_630, /* for SiS 630/730 VGA */
1911 PCI_DEVICE_ID_SI_730,
1912 PCI_DEVICE_ID_SI_550, /* for SiS 550 VGA */
1913 PCI_DEVICE_ID_SI_650, /* for SiS 650/651/740 VGA */
1914 PCI_DEVICE_ID_SI_651,
1915 PCI_DEVICE_ID_SI_740,
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001916 PCI_DEVICE_ID_SI_661, /* for SiS 661/741/660/760/761 VGA */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001917 PCI_DEVICE_ID_SI_741,
1918 PCI_DEVICE_ID_SI_660,
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001919 PCI_DEVICE_ID_SI_760,
1920 PCI_DEVICE_ID_SI_761
Linus Torvalds1da177e2005-04-16 15:20:36 -07001921 };
1922
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001923 switch(basechipid) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001924#ifdef CONFIG_FB_SIS_300
1925 case SIS_540: nbridgeidx = 0; nbridgenum = 1; break;
1926 case SIS_630: nbridgeidx = 1; nbridgenum = 2; break;
1927#endif
1928#ifdef CONFIG_FB_SIS_315
1929 case SIS_550: nbridgeidx = 3; nbridgenum = 1; break;
1930 case SIS_650: nbridgeidx = 4; nbridgenum = 3; break;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001931 case SIS_660: nbridgeidx = 7; nbridgenum = 5; break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001932#endif
1933 default: return NULL;
1934 }
1935 for(i = 0; i < nbridgenum; i++) {
Adrian Bunk0959f0c2007-05-08 00:39:50 -07001936 if((pdev = pci_get_device(PCI_VENDOR_ID_SI,
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001937 nbridgeids[nbridgeidx+i], NULL)))
1938 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001939 }
1940 return pdev;
1941}
1942
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001943static int __devinit
1944sisfb_get_dram_size(struct sis_video_info *ivideo)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001945{
1946#if defined(CONFIG_FB_SIS_300) || defined(CONFIG_FB_SIS_315)
1947 u8 reg;
1948#endif
1949
1950 ivideo->video_size = 0;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001951 ivideo->UMAsize = ivideo->LFBsize = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001952
1953 switch(ivideo->chip) {
1954#ifdef CONFIG_FB_SIS_300
1955 case SIS_300:
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001956 inSISIDXREG(SISSR, 0x14, reg);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001957 ivideo->video_size = ((reg & 0x3F) + 1) << 20;
1958 break;
1959 case SIS_540:
1960 case SIS_630:
1961 case SIS_730:
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001962 if(!ivideo->nbridge)
1963 return -1;
1964 pci_read_config_byte(ivideo->nbridge, 0x63, &reg);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001965 ivideo->video_size = 1 << (((reg & 0x70) >> 4) + 21);
1966 break;
1967#endif
1968#ifdef CONFIG_FB_SIS_315
1969 case SIS_315H:
1970 case SIS_315PRO:
1971 case SIS_315:
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001972 inSISIDXREG(SISSR, 0x14, reg);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001973 ivideo->video_size = (1 << ((reg & 0xf0) >> 4)) << 20;
1974 switch((reg >> 2) & 0x03) {
1975 case 0x01:
1976 case 0x03:
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001977 ivideo->video_size <<= 1;
1978 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001979 case 0x02:
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001980 ivideo->video_size += (ivideo->video_size/2);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001981 }
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001982 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001983 case SIS_330:
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001984 inSISIDXREG(SISSR, 0x14, reg);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001985 ivideo->video_size = (1 << ((reg & 0xf0) >> 4)) << 20;
1986 if(reg & 0x0c) ivideo->video_size <<= 1;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001987 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001988 case SIS_550:
1989 case SIS_650:
1990 case SIS_740:
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001991 inSISIDXREG(SISSR, 0x14, reg);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001992 ivideo->video_size = (((reg & 0x3f) + 1) << 2) << 20;
1993 break;
1994 case SIS_661:
1995 case SIS_741:
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001996 inSISIDXREG(SISCR, 0x79, reg);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001997 ivideo->video_size = (1 << ((reg & 0xf0) >> 4)) << 20;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001998 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001999 case SIS_660:
2000 case SIS_760:
Thomas Winischhofer544393f2005-09-09 13:04:45 -07002001 case SIS_761:
Linus Torvalds1da177e2005-04-16 15:20:36 -07002002 inSISIDXREG(SISCR, 0x79, reg);
2003 reg = (reg & 0xf0) >> 4;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07002004 if(reg) {
2005 ivideo->video_size = (1 << reg) << 20;
2006 ivideo->UMAsize = ivideo->video_size;
2007 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002008 inSISIDXREG(SISCR, 0x78, reg);
2009 reg &= 0x30;
2010 if(reg) {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07002011 if(reg == 0x10) {
2012 ivideo->LFBsize = (32 << 20);
2013 } else {
2014 ivideo->LFBsize = (64 << 20);
2015 }
2016 ivideo->video_size += ivideo->LFBsize;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002017 }
Thomas Winischhofer544393f2005-09-09 13:04:45 -07002018 break;
2019 case SIS_340:
2020 case XGI_20:
2021 case XGI_40:
2022 inSISIDXREG(SISSR, 0x14, reg);
2023 ivideo->video_size = (1 << ((reg & 0xf0) >> 4)) << 20;
2024 if(ivideo->chip != XGI_20) {
2025 reg = (reg & 0x0c) >> 2;
2026 if(ivideo->revision_id == 2) {
2027 if(reg & 0x01) reg = 0x02;
2028 else reg = 0x00;
2029 }
2030 if(reg == 0x02) ivideo->video_size <<= 1;
2031 else if(reg == 0x03) ivideo->video_size <<= 2;
2032 }
2033 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002034#endif
2035 default:
2036 return -1;
2037 }
2038 return 0;
2039}
2040
2041/* -------------- video bridge device detection --------------- */
2042
Thomas Winischhofer544393f2005-09-09 13:04:45 -07002043static void __devinit
2044sisfb_detect_VB_connect(struct sis_video_info *ivideo)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002045{
2046 u8 cr32, temp;
2047
Thomas Winischhofer544393f2005-09-09 13:04:45 -07002048 /* No CRT2 on XGI Z7 */
2049 if(ivideo->chip == XGI_20) {
2050 ivideo->sisfb_crt1off = 0;
2051 return;
2052 }
2053
Linus Torvalds1da177e2005-04-16 15:20:36 -07002054#ifdef CONFIG_FB_SIS_300
2055 if(ivideo->sisvga_engine == SIS_300_VGA) {
2056 inSISIDXREG(SISSR, 0x17, temp);
2057 if((temp & 0x0F) && (ivideo->chip != SIS_300)) {
2058 /* PAL/NTSC is stored on SR16 on such machines */
2059 if(!(ivideo->vbflags & (TV_PAL | TV_NTSC | TV_PALM | TV_PALN))) {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07002060 inSISIDXREG(SISSR, 0x16, temp);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002061 if(temp & 0x20)
2062 ivideo->vbflags |= TV_PAL;
2063 else
2064 ivideo->vbflags |= TV_NTSC;
2065 }
2066 }
2067 }
2068#endif
2069
2070 inSISIDXREG(SISCR, 0x32, cr32);
2071
2072 if(cr32 & SIS_CRT1) {
2073 ivideo->sisfb_crt1off = 0;
2074 } else {
2075 ivideo->sisfb_crt1off = (cr32 & 0xDF) ? 1 : 0;
2076 }
2077
2078 ivideo->vbflags &= ~(CRT2_TV | CRT2_LCD | CRT2_VGA);
2079
2080 if(cr32 & SIS_VB_TV) ivideo->vbflags |= CRT2_TV;
2081 if(cr32 & SIS_VB_LCD) ivideo->vbflags |= CRT2_LCD;
2082 if(cr32 & SIS_VB_CRT2) ivideo->vbflags |= CRT2_VGA;
2083
2084 /* Check given parms for hardware compatibility.
2085 * (Cannot do this in the search_xx routines since we don't
2086 * know what hardware we are running on then)
2087 */
2088
2089 if(ivideo->chip != SIS_550) {
2090 ivideo->sisfb_dstn = ivideo->sisfb_fstn = 0;
2091 }
2092
2093 if(ivideo->sisfb_tvplug != -1) {
2094 if( (ivideo->sisvga_engine != SIS_315_VGA) ||
Thomas Winischhofer544393f2005-09-09 13:04:45 -07002095 (!(ivideo->vbflags2 & VB2_SISYPBPRBRIDGE)) ) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002096 if(ivideo->sisfb_tvplug & TV_YPBPR) {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07002097 ivideo->sisfb_tvplug = -1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002098 printk(KERN_ERR "sisfb: YPbPr not supported\n");
2099 }
2100 }
2101 }
2102 if(ivideo->sisfb_tvplug != -1) {
2103 if( (ivideo->sisvga_engine != SIS_315_VGA) ||
Thomas Winischhofer544393f2005-09-09 13:04:45 -07002104 (!(ivideo->vbflags2 & VB2_SISHIVISIONBRIDGE)) ) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002105 if(ivideo->sisfb_tvplug & TV_HIVISION) {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07002106 ivideo->sisfb_tvplug = -1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002107 printk(KERN_ERR "sisfb: HiVision not supported\n");
2108 }
2109 }
2110 }
2111 if(ivideo->sisfb_tvstd != -1) {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07002112 if( (!(ivideo->vbflags2 & VB2_SISBRIDGE)) &&
2113 (!((ivideo->sisvga_engine == SIS_315_VGA) &&
2114 (ivideo->vbflags2 & VB2_CHRONTEL))) ) {
Roel Kluin5ab94812009-12-15 16:46:23 -08002115 if(ivideo->sisfb_tvstd & (TV_PALM | TV_PALN | TV_NTSCJ)) {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07002116 ivideo->sisfb_tvstd = -1;
2117 printk(KERN_ERR "sisfb: PALM/PALN/NTSCJ not supported\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002118 }
2119 }
2120 }
2121
2122 /* Detect/set TV plug & type */
2123 if(ivideo->sisfb_tvplug != -1) {
2124 ivideo->vbflags |= ivideo->sisfb_tvplug;
2125 } else {
2126 if(cr32 & SIS_VB_YPBPR) ivideo->vbflags |= (TV_YPBPR|TV_YPBPR525I); /* default: 480i */
2127 else if(cr32 & SIS_VB_HIVISION) ivideo->vbflags |= TV_HIVISION;
2128 else if(cr32 & SIS_VB_SCART) ivideo->vbflags |= TV_SCART;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07002129 else {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002130 if(cr32 & SIS_VB_SVIDEO) ivideo->vbflags |= TV_SVIDEO;
2131 if(cr32 & SIS_VB_COMPOSITE) ivideo->vbflags |= TV_AVIDEO;
2132 }
2133 }
2134
2135 if(!(ivideo->vbflags & (TV_YPBPR | TV_HIVISION))) {
2136 if(ivideo->sisfb_tvstd != -1) {
2137 ivideo->vbflags &= ~(TV_NTSC | TV_PAL | TV_PALM | TV_PALN | TV_NTSCJ);
2138 ivideo->vbflags |= ivideo->sisfb_tvstd;
2139 }
2140 if(ivideo->vbflags & TV_SCART) {
2141 ivideo->vbflags &= ~(TV_NTSC | TV_PALM | TV_PALN | TV_NTSCJ);
2142 ivideo->vbflags |= TV_PAL;
2143 }
2144 if(!(ivideo->vbflags & (TV_PAL | TV_NTSC | TV_PALM | TV_PALN | TV_NTSCJ))) {
2145 if(ivideo->sisvga_engine == SIS_300_VGA) {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07002146 inSISIDXREG(SISSR, 0x38, temp);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002147 if(temp & 0x01) ivideo->vbflags |= TV_PAL;
2148 else ivideo->vbflags |= TV_NTSC;
2149 } else if((ivideo->chip <= SIS_315PRO) || (ivideo->chip >= SIS_330)) {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07002150 inSISIDXREG(SISSR, 0x38, temp);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002151 if(temp & 0x01) ivideo->vbflags |= TV_PAL;
2152 else ivideo->vbflags |= TV_NTSC;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07002153 } else {
2154 inSISIDXREG(SISCR, 0x79, temp);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002155 if(temp & 0x20) ivideo->vbflags |= TV_PAL;
2156 else ivideo->vbflags |= TV_NTSC;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07002157 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002158 }
2159 }
2160
2161 /* Copy forceCRT1 option to CRT1off if option is given */
Thomas Winischhofer544393f2005-09-09 13:04:45 -07002162 if(ivideo->sisfb_forcecrt1 != -1) {
2163 ivideo->sisfb_crt1off = (ivideo->sisfb_forcecrt1) ? 0 : 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002164 }
2165}
2166
2167/* ------------------ Sensing routines ------------------ */
2168
Richard Knutssonc30660ea2007-02-12 00:55:06 -08002169static bool __devinit
Thomas Winischhofer544393f2005-09-09 13:04:45 -07002170sisfb_test_DDC1(struct sis_video_info *ivideo)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002171{
2172 unsigned short old;
2173 int count = 48;
2174
2175 old = SiS_ReadDDC1Bit(&ivideo->SiS_Pr);
2176 do {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07002177 if(old != SiS_ReadDDC1Bit(&ivideo->SiS_Pr)) break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002178 } while(count--);
Richard Knutssonc30660ea2007-02-12 00:55:06 -08002179 return (count != -1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002180}
2181
Thomas Winischhofer544393f2005-09-09 13:04:45 -07002182static void __devinit
2183sisfb_sense_crt1(struct sis_video_info *ivideo)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002184{
Richard Knutssonc30660ea2007-02-12 00:55:06 -08002185 bool mustwait = false;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002186 u8 sr1F, cr17;
2187#ifdef CONFIG_FB_SIS_315
2188 u8 cr63=0;
2189#endif
2190 u16 temp = 0xffff;
2191 int i;
2192
2193 inSISIDXREG(SISSR,0x1F,sr1F);
2194 orSISIDXREG(SISSR,0x1F,0x04);
2195 andSISIDXREG(SISSR,0x1F,0x3F);
Richard Knutssonc30660ea2007-02-12 00:55:06 -08002196 if(sr1F & 0xc0) mustwait = true;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002197
2198#ifdef CONFIG_FB_SIS_315
2199 if(ivideo->sisvga_engine == SIS_315_VGA) {
2200 inSISIDXREG(SISCR,ivideo->SiS_Pr.SiS_MyCR63,cr63);
2201 cr63 &= 0x40;
2202 andSISIDXREG(SISCR,ivideo->SiS_Pr.SiS_MyCR63,0xBF);
2203 }
2204#endif
2205
2206 inSISIDXREG(SISCR,0x17,cr17);
2207 cr17 &= 0x80;
2208 if(!cr17) {
2209 orSISIDXREG(SISCR,0x17,0x80);
Richard Knutssonc30660ea2007-02-12 00:55:06 -08002210 mustwait = true;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002211 outSISIDXREG(SISSR, 0x00, 0x01);
2212 outSISIDXREG(SISSR, 0x00, 0x03);
2213 }
2214
2215 if(mustwait) {
2216 for(i=0; i < 10; i++) sisfbwaitretracecrt1(ivideo);
2217 }
2218
2219#ifdef CONFIG_FB_SIS_315
2220 if(ivideo->chip >= SIS_330) {
2221 andSISIDXREG(SISCR,0x32,~0x20);
2222 if(ivideo->chip >= SIS_340) {
2223 outSISIDXREG(SISCR, 0x57, 0x4a);
2224 } else {
2225 outSISIDXREG(SISCR, 0x57, 0x5f);
2226 }
2227 orSISIDXREG(SISCR, 0x53, 0x02);
2228 while((inSISREG(SISINPSTAT)) & 0x01) break;
2229 while(!((inSISREG(SISINPSTAT)) & 0x01)) break;
2230 if((inSISREG(SISMISCW)) & 0x10) temp = 1;
2231 andSISIDXREG(SISCR, 0x53, 0xfd);
2232 andSISIDXREG(SISCR, 0x57, 0x00);
2233 }
2234#endif
2235
2236 if(temp == 0xffff) {
2237 i = 3;
2238 do {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07002239 temp = SiS_HandleDDC(&ivideo->SiS_Pr, ivideo->vbflags,
2240 ivideo->sisvga_engine, 0, 0, NULL, ivideo->vbflags2);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002241 } while(((temp == 0) || (temp == 0xffff)) && i--);
2242
2243 if((temp == 0) || (temp == 0xffff)) {
2244 if(sisfb_test_DDC1(ivideo)) temp = 1;
2245 }
2246 }
2247
2248 if((temp) && (temp != 0xffff)) {
2249 orSISIDXREG(SISCR,0x32,0x20);
2250 }
2251
2252#ifdef CONFIG_FB_SIS_315
2253 if(ivideo->sisvga_engine == SIS_315_VGA) {
2254 setSISIDXREG(SISCR,ivideo->SiS_Pr.SiS_MyCR63,0xBF,cr63);
2255 }
2256#endif
2257
2258 setSISIDXREG(SISCR,0x17,0x7F,cr17);
2259
2260 outSISIDXREG(SISSR,0x1F,sr1F);
2261}
2262
2263/* Determine and detect attached devices on SiS30x */
Thomas Winischhofer544393f2005-09-09 13:04:45 -07002264static void __devinit
2265SiS_SenseLCD(struct sis_video_info *ivideo)
2266{
2267 unsigned char buffer[256];
2268 unsigned short temp, realcrtno, i;
2269 u8 reg, cr37 = 0, paneltype = 0;
2270 u16 xres, yres;
2271
Richard Knutssonc30660ea2007-02-12 00:55:06 -08002272 ivideo->SiS_Pr.PanelSelfDetected = false;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07002273
2274 /* LCD detection only for TMDS bridges */
2275 if(!(ivideo->vbflags2 & VB2_SISTMDSBRIDGE))
2276 return;
2277 if(ivideo->vbflags2 & VB2_30xBDH)
2278 return;
2279
2280 /* If LCD already set up by BIOS, skip it */
2281 inSISIDXREG(SISCR, 0x32, reg);
2282 if(reg & 0x08)
2283 return;
2284
2285 realcrtno = 1;
2286 if(ivideo->SiS_Pr.DDCPortMixup)
2287 realcrtno = 0;
2288
2289 /* Check DDC capabilities */
2290 temp = SiS_HandleDDC(&ivideo->SiS_Pr, ivideo->vbflags, ivideo->sisvga_engine,
2291 realcrtno, 0, &buffer[0], ivideo->vbflags2);
2292
2293 if((!temp) || (temp == 0xffff) || (!(temp & 0x02)))
2294 return;
2295
2296 /* Read DDC data */
2297 i = 3; /* Number of retrys */
2298 do {
2299 temp = SiS_HandleDDC(&ivideo->SiS_Pr, ivideo->vbflags,
2300 ivideo->sisvga_engine, realcrtno, 1,
2301 &buffer[0], ivideo->vbflags2);
2302 } while((temp) && i--);
2303
2304 if(temp)
2305 return;
2306
2307 /* No digital device */
2308 if(!(buffer[0x14] & 0x80))
2309 return;
2310
2311 /* First detailed timing preferred timing? */
2312 if(!(buffer[0x18] & 0x02))
2313 return;
2314
2315 xres = buffer[0x38] | ((buffer[0x3a] & 0xf0) << 4);
2316 yres = buffer[0x3b] | ((buffer[0x3d] & 0xf0) << 4);
2317
2318 switch(xres) {
2319 case 1024:
2320 if(yres == 768)
2321 paneltype = 0x02;
2322 break;
2323 case 1280:
2324 if(yres == 1024)
2325 paneltype = 0x03;
2326 break;
2327 case 1600:
2328 if((yres == 1200) && (ivideo->vbflags2 & VB2_30xC))
2329 paneltype = 0x0b;
2330 break;
2331 }
2332
2333 if(!paneltype)
2334 return;
2335
2336 if(buffer[0x23])
2337 cr37 |= 0x10;
2338
2339 if((buffer[0x47] & 0x18) == 0x18)
2340 cr37 |= ((((buffer[0x47] & 0x06) ^ 0x06) << 5) | 0x20);
2341 else
2342 cr37 |= 0xc0;
2343
2344 outSISIDXREG(SISCR, 0x36, paneltype);
2345 cr37 &= 0xf1;
2346 setSISIDXREG(SISCR, 0x37, 0x0c, cr37);
2347 orSISIDXREG(SISCR, 0x32, 0x08);
2348
Richard Knutssonc30660ea2007-02-12 00:55:06 -08002349 ivideo->SiS_Pr.PanelSelfDetected = true;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07002350}
2351
2352static int __devinit
2353SISDoSense(struct sis_video_info *ivideo, u16 type, u16 test)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002354{
2355 int temp, mytest, result, i, j;
2356
2357 for(j = 0; j < 10; j++) {
2358 result = 0;
2359 for(i = 0; i < 3; i++) {
2360 mytest = test;
2361 outSISIDXREG(SISPART4,0x11,(type & 0x00ff));
2362 temp = (type >> 8) | (mytest & 0x00ff);
2363 setSISIDXREG(SISPART4,0x10,0xe0,temp);
2364 SiS_DDC2Delay(&ivideo->SiS_Pr, 0x1500);
2365 mytest >>= 8;
2366 mytest &= 0x7f;
2367 inSISIDXREG(SISPART4,0x03,temp);
2368 temp ^= 0x0e;
2369 temp &= mytest;
2370 if(temp == mytest) result++;
2371#if 1
2372 outSISIDXREG(SISPART4,0x11,0x00);
2373 andSISIDXREG(SISPART4,0x10,0xe0);
2374 SiS_DDC2Delay(&ivideo->SiS_Pr, 0x1000);
2375#endif
2376 }
2377 if((result == 0) || (result >= 2)) break;
2378 }
Thomas Winischhofer544393f2005-09-09 13:04:45 -07002379 return result;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002380}
2381
Thomas Winischhofer544393f2005-09-09 13:04:45 -07002382static void __devinit
2383SiS_Sense30x(struct sis_video_info *ivideo)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002384{
2385 u8 backupP4_0d,backupP2_00,backupP2_4d,backupSR_1e,biosflag=0;
2386 u16 svhs=0, svhs_c=0;
2387 u16 cvbs=0, cvbs_c=0;
2388 u16 vga2=0, vga2_c=0;
2389 int myflag, result;
2390 char stdstr[] = "sisfb: Detected";
2391 char tvstr[] = "TV connected to";
2392
Thomas Winischhofer544393f2005-09-09 13:04:45 -07002393 if(ivideo->vbflags2 & VB2_301) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002394 svhs = 0x00b9; cvbs = 0x00b3; vga2 = 0x00d1;
2395 inSISIDXREG(SISPART4,0x01,myflag);
2396 if(myflag & 0x04) {
2397 svhs = 0x00dd; cvbs = 0x00ee; vga2 = 0x00fd;
2398 }
Thomas Winischhofer544393f2005-09-09 13:04:45 -07002399 } else if(ivideo->vbflags2 & (VB2_301B | VB2_302B)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002400 svhs = 0x016b; cvbs = 0x0174; vga2 = 0x0190;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07002401 } else if(ivideo->vbflags2 & (VB2_301LV | VB2_302LV)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002402 svhs = 0x0200; cvbs = 0x0100;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07002403 } else if(ivideo->vbflags2 & (VB2_301C | VB2_302ELV | VB2_307T | VB2_307LV)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002404 svhs = 0x016b; cvbs = 0x0110; vga2 = 0x0190;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07002405 } else
2406 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002407
2408 vga2_c = 0x0e08; svhs_c = 0x0404; cvbs_c = 0x0804;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07002409 if(ivideo->vbflags & (VB2_301LV|VB2_302LV|VB2_302ELV|VB2_307LV)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002410 svhs_c = 0x0408; cvbs_c = 0x0808;
2411 }
Thomas Winischhofer544393f2005-09-09 13:04:45 -07002412
Linus Torvalds1da177e2005-04-16 15:20:36 -07002413 biosflag = 2;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07002414 if(ivideo->haveXGIROM) {
2415 biosflag = ivideo->bios_abase[0x58] & 0x03;
2416 } else if(ivideo->newrom) {
2417 if(ivideo->bios_abase[0x5d] & 0x04) biosflag |= 0x01;
2418 } else if(ivideo->sisvga_engine == SIS_300_VGA) {
2419 if(ivideo->bios_abase) {
2420 biosflag = ivideo->bios_abase[0xfe] & 0x03;
2421 }
2422 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002423
2424 if(ivideo->chip == SIS_300) {
2425 inSISIDXREG(SISSR,0x3b,myflag);
2426 if(!(myflag & 0x01)) vga2 = vga2_c = 0;
2427 }
2428
Thomas Winischhofer544393f2005-09-09 13:04:45 -07002429 if(!(ivideo->vbflags2 & VB2_SISVGA2BRIDGE)) {
2430 vga2 = vga2_c = 0;
2431 }
2432
Linus Torvalds1da177e2005-04-16 15:20:36 -07002433 inSISIDXREG(SISSR,0x1e,backupSR_1e);
2434 orSISIDXREG(SISSR,0x1e,0x20);
2435
2436 inSISIDXREG(SISPART4,0x0d,backupP4_0d);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07002437 if(ivideo->vbflags2 & VB2_30xC) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002438 setSISIDXREG(SISPART4,0x0d,~0x07,0x01);
2439 } else {
2440 orSISIDXREG(SISPART4,0x0d,0x04);
2441 }
2442 SiS_DDC2Delay(&ivideo->SiS_Pr, 0x2000);
2443
2444 inSISIDXREG(SISPART2,0x00,backupP2_00);
2445 outSISIDXREG(SISPART2,0x00,((backupP2_00 | 0x1c) & 0xfc));
2446
2447 inSISIDXREG(SISPART2,0x4d,backupP2_4d);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07002448 if(ivideo->vbflags2 & VB2_SISYPBPRBRIDGE) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002449 outSISIDXREG(SISPART2,0x4d,(backupP2_4d & ~0x10));
2450 }
2451
Thomas Winischhofer544393f2005-09-09 13:04:45 -07002452 if(!(ivideo->vbflags2 & VB2_30xCLV)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002453 SISDoSense(ivideo, 0, 0);
2454 }
2455
2456 andSISIDXREG(SISCR, 0x32, ~0x14);
2457
2458 if(vga2_c || vga2) {
2459 if(SISDoSense(ivideo, vga2, vga2_c)) {
2460 if(biosflag & 0x01) {
2461 printk(KERN_INFO "%s %s SCART output\n", stdstr, tvstr);
2462 orSISIDXREG(SISCR, 0x32, 0x04);
2463 } else {
2464 printk(KERN_INFO "%s secondary VGA connection\n", stdstr);
2465 orSISIDXREG(SISCR, 0x32, 0x10);
2466 }
2467 }
2468 }
2469
2470 andSISIDXREG(SISCR, 0x32, 0x3f);
2471
Thomas Winischhofer544393f2005-09-09 13:04:45 -07002472 if(ivideo->vbflags2 & VB2_30xCLV) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002473 orSISIDXREG(SISPART4,0x0d,0x04);
2474 }
2475
Thomas Winischhofer544393f2005-09-09 13:04:45 -07002476 if((ivideo->sisvga_engine == SIS_315_VGA) && (ivideo->vbflags2 & VB2_SISYPBPRBRIDGE)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002477 outSISIDXREG(SISPART2,0x4d,(backupP2_4d | 0x10));
2478 SiS_DDC2Delay(&ivideo->SiS_Pr, 0x2000);
2479 if((result = SISDoSense(ivideo, svhs, 0x0604))) {
2480 if((result = SISDoSense(ivideo, cvbs, 0x0804))) {
2481 printk(KERN_INFO "%s %s YPbPr component output\n", stdstr, tvstr);
2482 orSISIDXREG(SISCR,0x32,0x80);
2483 }
2484 }
2485 outSISIDXREG(SISPART2,0x4d,backupP2_4d);
2486 }
2487
2488 andSISIDXREG(SISCR, 0x32, ~0x03);
2489
2490 if(!(ivideo->vbflags & TV_YPBPR)) {
2491 if((result = SISDoSense(ivideo, svhs, svhs_c))) {
2492 printk(KERN_INFO "%s %s SVIDEO output\n", stdstr, tvstr);
2493 orSISIDXREG(SISCR, 0x32, 0x02);
2494 }
2495 if((biosflag & 0x02) || (!result)) {
2496 if(SISDoSense(ivideo, cvbs, cvbs_c)) {
2497 printk(KERN_INFO "%s %s COMPOSITE output\n", stdstr, tvstr);
2498 orSISIDXREG(SISCR, 0x32, 0x01);
2499 }
2500 }
2501 }
2502
2503 SISDoSense(ivideo, 0, 0);
2504
2505 outSISIDXREG(SISPART2,0x00,backupP2_00);
2506 outSISIDXREG(SISPART4,0x0d,backupP4_0d);
2507 outSISIDXREG(SISSR,0x1e,backupSR_1e);
2508
Thomas Winischhofer544393f2005-09-09 13:04:45 -07002509 if(ivideo->vbflags2 & VB2_30xCLV) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002510 inSISIDXREG(SISPART2,0x00,biosflag);
2511 if(biosflag & 0x20) {
2512 for(myflag = 2; myflag > 0; myflag--) {
2513 biosflag ^= 0x20;
2514 outSISIDXREG(SISPART2,0x00,biosflag);
2515 }
2516 }
2517 }
2518
2519 outSISIDXREG(SISPART2,0x00,backupP2_00);
2520}
2521
2522/* Determine and detect attached TV's on Chrontel */
Thomas Winischhofer544393f2005-09-09 13:04:45 -07002523static void __devinit
2524SiS_SenseCh(struct sis_video_info *ivideo)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002525{
2526#if defined(CONFIG_FB_SIS_300) || defined(CONFIG_FB_SIS_315)
2527 u8 temp1, temp2;
2528 char stdstr[] = "sisfb: Chrontel: Detected TV connected to";
2529#endif
2530#ifdef CONFIG_FB_SIS_300
2531 unsigned char test[3];
2532 int i;
2533#endif
2534
2535 if(ivideo->chip < SIS_315H) {
2536
2537#ifdef CONFIG_FB_SIS_300
2538 ivideo->SiS_Pr.SiS_IF_DEF_CH70xx = 1; /* Chrontel 700x */
2539 SiS_SetChrontelGPIO(&ivideo->SiS_Pr, 0x9c); /* Set general purpose IO for Chrontel communication */
2540 SiS_DDC2Delay(&ivideo->SiS_Pr, 1000);
2541 temp1 = SiS_GetCH700x(&ivideo->SiS_Pr, 0x25);
2542 /* See Chrontel TB31 for explanation */
2543 temp2 = SiS_GetCH700x(&ivideo->SiS_Pr, 0x0e);
2544 if(((temp2 & 0x07) == 0x01) || (temp2 & 0x04)) {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07002545 SiS_SetCH700x(&ivideo->SiS_Pr, 0x0e, 0x0b);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002546 SiS_DDC2Delay(&ivideo->SiS_Pr, 300);
2547 }
2548 temp2 = SiS_GetCH700x(&ivideo->SiS_Pr, 0x25);
2549 if(temp2 != temp1) temp1 = temp2;
2550
2551 if((temp1 >= 0x22) && (temp1 <= 0x50)) {
2552 /* Read power status */
2553 temp1 = SiS_GetCH700x(&ivideo->SiS_Pr, 0x0e);
2554 if((temp1 & 0x03) != 0x03) {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07002555 /* Power all outputs */
2556 SiS_SetCH700x(&ivideo->SiS_Pr, 0x0e,0x0b);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002557 SiS_DDC2Delay(&ivideo->SiS_Pr, 300);
2558 }
2559 /* Sense connected TV devices */
2560 for(i = 0; i < 3; i++) {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07002561 SiS_SetCH700x(&ivideo->SiS_Pr, 0x10, 0x01);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002562 SiS_DDC2Delay(&ivideo->SiS_Pr, 0x96);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07002563 SiS_SetCH700x(&ivideo->SiS_Pr, 0x10, 0x00);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002564 SiS_DDC2Delay(&ivideo->SiS_Pr, 0x96);
2565 temp1 = SiS_GetCH700x(&ivideo->SiS_Pr, 0x10);
2566 if(!(temp1 & 0x08)) test[i] = 0x02;
2567 else if(!(temp1 & 0x02)) test[i] = 0x01;
2568 else test[i] = 0;
2569 SiS_DDC2Delay(&ivideo->SiS_Pr, 0x96);
2570 }
2571
2572 if(test[0] == test[1]) temp1 = test[0];
2573 else if(test[0] == test[2]) temp1 = test[0];
2574 else if(test[1] == test[2]) temp1 = test[1];
2575 else {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07002576 printk(KERN_INFO
Linus Torvalds1da177e2005-04-16 15:20:36 -07002577 "sisfb: TV detection unreliable - test results varied\n");
2578 temp1 = test[2];
2579 }
2580 if(temp1 == 0x02) {
2581 printk(KERN_INFO "%s SVIDEO output\n", stdstr);
2582 ivideo->vbflags |= TV_SVIDEO;
2583 orSISIDXREG(SISCR, 0x32, 0x02);
2584 andSISIDXREG(SISCR, 0x32, ~0x05);
2585 } else if (temp1 == 0x01) {
2586 printk(KERN_INFO "%s CVBS output\n", stdstr);
2587 ivideo->vbflags |= TV_AVIDEO;
2588 orSISIDXREG(SISCR, 0x32, 0x01);
2589 andSISIDXREG(SISCR, 0x32, ~0x06);
2590 } else {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07002591 SiS_SetCH70xxANDOR(&ivideo->SiS_Pr, 0x0e, 0x01, 0xF8);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002592 andSISIDXREG(SISCR, 0x32, ~0x07);
2593 }
2594 } else if(temp1 == 0) {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07002595 SiS_SetCH70xxANDOR(&ivideo->SiS_Pr, 0x0e, 0x01, 0xF8);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002596 andSISIDXREG(SISCR, 0x32, ~0x07);
2597 }
2598 /* Set general purpose IO for Chrontel communication */
2599 SiS_SetChrontelGPIO(&ivideo->SiS_Pr, 0x00);
2600#endif
2601
2602 } else {
2603
2604#ifdef CONFIG_FB_SIS_315
2605 ivideo->SiS_Pr.SiS_IF_DEF_CH70xx = 2; /* Chrontel 7019 */
Thomas Winischhofer544393f2005-09-09 13:04:45 -07002606 temp1 = SiS_GetCH701x(&ivideo->SiS_Pr, 0x49);
2607 SiS_SetCH701x(&ivideo->SiS_Pr, 0x49, 0x20);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002608 SiS_DDC2Delay(&ivideo->SiS_Pr, 0x96);
2609 temp2 = SiS_GetCH701x(&ivideo->SiS_Pr, 0x20);
2610 temp2 |= 0x01;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07002611 SiS_SetCH701x(&ivideo->SiS_Pr, 0x20, temp2);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002612 SiS_DDC2Delay(&ivideo->SiS_Pr, 0x96);
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 = SiS_GetCH701x(&ivideo->SiS_Pr, 0x20);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07002617 SiS_SetCH701x(&ivideo->SiS_Pr, 0x49, temp1);
2618 temp1 = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002619 if(temp2 & 0x02) temp1 |= 0x01;
2620 if(temp2 & 0x10) temp1 |= 0x01;
2621 if(temp2 & 0x04) temp1 |= 0x02;
2622 if( (temp1 & 0x01) && (temp1 & 0x02) ) temp1 = 0x04;
2623 switch(temp1) {
2624 case 0x01:
2625 printk(KERN_INFO "%s CVBS output\n", stdstr);
2626 ivideo->vbflags |= TV_AVIDEO;
2627 orSISIDXREG(SISCR, 0x32, 0x01);
2628 andSISIDXREG(SISCR, 0x32, ~0x06);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07002629 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002630 case 0x02:
2631 printk(KERN_INFO "%s SVIDEO output\n", stdstr);
2632 ivideo->vbflags |= TV_SVIDEO;
2633 orSISIDXREG(SISCR, 0x32, 0x02);
2634 andSISIDXREG(SISCR, 0x32, ~0x05);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07002635 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002636 case 0x04:
2637 printk(KERN_INFO "%s SCART output\n", stdstr);
2638 orSISIDXREG(SISCR, 0x32, 0x04);
2639 andSISIDXREG(SISCR, 0x32, ~0x03);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07002640 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002641 default:
2642 andSISIDXREG(SISCR, 0x32, ~0x07);
2643 }
2644#endif
2645 }
2646}
2647
Thomas Winischhofer544393f2005-09-09 13:04:45 -07002648static void __devinit
2649sisfb_get_VB_type(struct sis_video_info *ivideo)
2650{
2651 char stdstr[] = "sisfb: Detected";
2652 char bridgestr[] = "video bridge";
2653 u8 vb_chipid;
2654 u8 reg;
2655
2656 /* No CRT2 on XGI Z7 */
2657 if(ivideo->chip == XGI_20)
2658 return;
2659
2660 inSISIDXREG(SISPART4, 0x00, vb_chipid);
2661 switch(vb_chipid) {
2662 case 0x01:
2663 inSISIDXREG(SISPART4, 0x01, reg);
2664 if(reg < 0xb0) {
2665 ivideo->vbflags |= VB_301; /* Deprecated */
2666 ivideo->vbflags2 |= VB2_301;
2667 printk(KERN_INFO "%s SiS301 %s\n", stdstr, bridgestr);
2668 } else if(reg < 0xc0) {
2669 ivideo->vbflags |= VB_301B; /* Deprecated */
2670 ivideo->vbflags2 |= VB2_301B;
2671 inSISIDXREG(SISPART4,0x23,reg);
2672 if(!(reg & 0x02)) {
2673 ivideo->vbflags |= VB_30xBDH; /* Deprecated */
2674 ivideo->vbflags2 |= VB2_30xBDH;
2675 printk(KERN_INFO "%s SiS301B-DH %s\n", stdstr, bridgestr);
2676 } else {
2677 printk(KERN_INFO "%s SiS301B %s\n", stdstr, bridgestr);
2678 }
2679 } else if(reg < 0xd0) {
2680 ivideo->vbflags |= VB_301C; /* Deprecated */
2681 ivideo->vbflags2 |= VB2_301C;
2682 printk(KERN_INFO "%s SiS301C %s\n", stdstr, bridgestr);
2683 } else if(reg < 0xe0) {
2684 ivideo->vbflags |= VB_301LV; /* Deprecated */
2685 ivideo->vbflags2 |= VB2_301LV;
2686 printk(KERN_INFO "%s SiS301LV %s\n", stdstr, bridgestr);
2687 } else if(reg <= 0xe1) {
2688 inSISIDXREG(SISPART4,0x39,reg);
2689 if(reg == 0xff) {
2690 ivideo->vbflags |= VB_302LV; /* Deprecated */
2691 ivideo->vbflags2 |= VB2_302LV;
2692 printk(KERN_INFO "%s SiS302LV %s\n", stdstr, bridgestr);
2693 } else {
2694 ivideo->vbflags |= VB_301C; /* Deprecated */
2695 ivideo->vbflags2 |= VB2_301C;
2696 printk(KERN_INFO "%s SiS301C(P4) %s\n", stdstr, bridgestr);
2697#if 0
2698 ivideo->vbflags |= VB_302ELV; /* Deprecated */
2699 ivideo->vbflags2 |= VB2_302ELV;
2700 printk(KERN_INFO "%s SiS302ELV %s\n", stdstr, bridgestr);
2701#endif
2702 }
2703 }
2704 break;
2705 case 0x02:
2706 ivideo->vbflags |= VB_302B; /* Deprecated */
2707 ivideo->vbflags2 |= VB2_302B;
2708 printk(KERN_INFO "%s SiS302B %s\n", stdstr, bridgestr);
2709 break;
2710 }
2711
2712 if((!(ivideo->vbflags2 & VB2_VIDEOBRIDGE)) && (ivideo->chip != SIS_300)) {
2713 inSISIDXREG(SISCR, 0x37, reg);
2714 reg &= SIS_EXTERNAL_CHIP_MASK;
2715 reg >>= 1;
2716 if(ivideo->sisvga_engine == SIS_300_VGA) {
2717#ifdef CONFIG_FB_SIS_300
2718 switch(reg) {
2719 case SIS_EXTERNAL_CHIP_LVDS:
2720 ivideo->vbflags |= VB_LVDS; /* Deprecated */
2721 ivideo->vbflags2 |= VB2_LVDS;
2722 break;
2723 case SIS_EXTERNAL_CHIP_TRUMPION:
2724 ivideo->vbflags |= (VB_LVDS | VB_TRUMPION); /* Deprecated */
2725 ivideo->vbflags2 |= (VB2_LVDS | VB2_TRUMPION);
2726 break;
2727 case SIS_EXTERNAL_CHIP_CHRONTEL:
2728 ivideo->vbflags |= VB_CHRONTEL; /* Deprecated */
2729 ivideo->vbflags2 |= VB2_CHRONTEL;
2730 break;
2731 case SIS_EXTERNAL_CHIP_LVDS_CHRONTEL:
2732 ivideo->vbflags |= (VB_LVDS | VB_CHRONTEL); /* Deprecated */
2733 ivideo->vbflags2 |= (VB2_LVDS | VB2_CHRONTEL);
2734 break;
2735 }
2736 if(ivideo->vbflags2 & VB2_CHRONTEL) ivideo->chronteltype = 1;
2737#endif
2738 } else if(ivideo->chip < SIS_661) {
2739#ifdef CONFIG_FB_SIS_315
2740 switch (reg) {
2741 case SIS310_EXTERNAL_CHIP_LVDS:
2742 ivideo->vbflags |= VB_LVDS; /* Deprecated */
2743 ivideo->vbflags2 |= VB2_LVDS;
2744 break;
2745 case SIS310_EXTERNAL_CHIP_LVDS_CHRONTEL:
2746 ivideo->vbflags |= (VB_LVDS | VB_CHRONTEL); /* Deprecated */
2747 ivideo->vbflags2 |= (VB2_LVDS | VB2_CHRONTEL);
2748 break;
2749 }
2750 if(ivideo->vbflags2 & VB2_CHRONTEL) ivideo->chronteltype = 2;
2751#endif
2752 } else if(ivideo->chip >= SIS_661) {
2753#ifdef CONFIG_FB_SIS_315
2754 inSISIDXREG(SISCR, 0x38, reg);
2755 reg >>= 5;
2756 switch(reg) {
2757 case 0x02:
2758 ivideo->vbflags |= VB_LVDS; /* Deprecated */
2759 ivideo->vbflags2 |= VB2_LVDS;
2760 break;
2761 case 0x03:
2762 ivideo->vbflags |= (VB_LVDS | VB_CHRONTEL); /* Deprecated */
2763 ivideo->vbflags2 |= (VB2_LVDS | VB2_CHRONTEL);
2764 break;
2765 case 0x04:
2766 ivideo->vbflags |= (VB_LVDS | VB_CONEXANT); /* Deprecated */
2767 ivideo->vbflags2 |= (VB2_LVDS | VB2_CONEXANT);
2768 break;
2769 }
2770 if(ivideo->vbflags2 & VB2_CHRONTEL) ivideo->chronteltype = 2;
2771#endif
2772 }
2773 if(ivideo->vbflags2 & VB2_LVDS) {
2774 printk(KERN_INFO "%s LVDS transmitter\n", stdstr);
2775 }
2776 if((ivideo->sisvga_engine == SIS_300_VGA) && (ivideo->vbflags2 & VB2_TRUMPION)) {
2777 printk(KERN_INFO "%s Trumpion Zurac LCD scaler\n", stdstr);
2778 }
2779 if(ivideo->vbflags2 & VB2_CHRONTEL) {
2780 printk(KERN_INFO "%s Chrontel TV encoder\n", stdstr);
2781 }
2782 if((ivideo->chip >= SIS_661) && (ivideo->vbflags2 & VB2_CONEXANT)) {
2783 printk(KERN_INFO "%s Conexant external device\n", stdstr);
2784 }
2785 }
2786
2787 if(ivideo->vbflags2 & VB2_SISBRIDGE) {
2788 SiS_SenseLCD(ivideo);
2789 SiS_Sense30x(ivideo);
2790 } else if(ivideo->vbflags2 & VB2_CHRONTEL) {
2791 SiS_SenseCh(ivideo);
2792 }
2793}
2794
2795/* ---------- Engine initialization routines ------------ */
2796
2797static void
2798sisfb_engine_init(struct sis_video_info *ivideo)
2799{
2800
2801 /* Initialize command queue (we use MMIO only) */
2802
2803 /* BEFORE THIS IS CALLED, THE ENGINES *MUST* BE SYNC'ED */
2804
2805 ivideo->caps &= ~(TURBO_QUEUE_CAP |
2806 MMIO_CMD_QUEUE_CAP |
2807 VM_CMD_QUEUE_CAP |
2808 AGP_CMD_QUEUE_CAP);
2809
2810#ifdef CONFIG_FB_SIS_300
2811 if(ivideo->sisvga_engine == SIS_300_VGA) {
2812 u32 tqueue_pos;
2813 u8 tq_state;
2814
2815 tqueue_pos = (ivideo->video_size - ivideo->cmdQueueSize) / (64 * 1024);
2816
2817 inSISIDXREG(SISSR, IND_SIS_TURBOQUEUE_SET, tq_state);
2818 tq_state |= 0xf0;
2819 tq_state &= 0xfc;
2820 tq_state |= (u8)(tqueue_pos >> 8);
2821 outSISIDXREG(SISSR, IND_SIS_TURBOQUEUE_SET, tq_state);
2822
2823 outSISIDXREG(SISSR, IND_SIS_TURBOQUEUE_ADR, (u8)(tqueue_pos & 0xff));
2824
2825 ivideo->caps |= TURBO_QUEUE_CAP;
2826 }
2827#endif
2828
2829#ifdef CONFIG_FB_SIS_315
2830 if(ivideo->sisvga_engine == SIS_315_VGA) {
2831 u32 tempq = 0, templ;
2832 u8 temp;
2833
2834 if(ivideo->chip == XGI_20) {
2835 switch(ivideo->cmdQueueSize) {
2836 case (64 * 1024):
2837 temp = SIS_CMD_QUEUE_SIZE_Z7_64k;
2838 break;
2839 case (128 * 1024):
2840 default:
2841 temp = SIS_CMD_QUEUE_SIZE_Z7_128k;
2842 }
2843 } else {
2844 switch(ivideo->cmdQueueSize) {
2845 case (4 * 1024 * 1024):
2846 temp = SIS_CMD_QUEUE_SIZE_4M;
2847 break;
2848 case (2 * 1024 * 1024):
2849 temp = SIS_CMD_QUEUE_SIZE_2M;
2850 break;
2851 case (1 * 1024 * 1024):
2852 temp = SIS_CMD_QUEUE_SIZE_1M;
2853 break;
2854 default:
2855 case (512 * 1024):
2856 temp = SIS_CMD_QUEUE_SIZE_512k;
2857 }
2858 }
2859
2860 outSISIDXREG(SISSR, IND_SIS_CMDQUEUE_THRESHOLD, COMMAND_QUEUE_THRESHOLD);
2861 outSISIDXREG(SISSR, IND_SIS_CMDQUEUE_SET, SIS_CMD_QUEUE_RESET);
2862
2863 if((ivideo->chip >= XGI_40) && ivideo->modechanged) {
2864 /* Must disable dual pipe on XGI_40. Can't do
2865 * this in MMIO mode, because it requires
2866 * setting/clearing a bit in the MMIO fire trigger
2867 * register.
2868 */
2869 if(!((templ = MMIO_IN32(ivideo->mmio_vbase, 0x8240)) & (1 << 10))) {
2870
2871 MMIO_OUT32(ivideo->mmio_vbase, Q_WRITE_PTR, 0);
2872
2873 outSISIDXREG(SISSR, IND_SIS_CMDQUEUE_SET, (temp | SIS_VRAM_CMDQUEUE_ENABLE));
2874
2875 tempq = MMIO_IN32(ivideo->mmio_vbase, Q_READ_PTR);
2876 MMIO_OUT32(ivideo->mmio_vbase, Q_WRITE_PTR, tempq);
2877
2878 tempq = (u32)(ivideo->video_size - ivideo->cmdQueueSize);
2879 MMIO_OUT32(ivideo->mmio_vbase, Q_BASE_ADDR, tempq);
2880
2881 writel(0x16800000 + 0x8240, ivideo->video_vbase + tempq);
2882 writel(templ | (1 << 10), ivideo->video_vbase + tempq + 4);
2883 writel(0x168F0000, ivideo->video_vbase + tempq + 8);
2884 writel(0x168F0000, ivideo->video_vbase + tempq + 12);
2885
2886 MMIO_OUT32(ivideo->mmio_vbase, Q_WRITE_PTR, (tempq + 16));
2887
2888 sisfb_syncaccel(ivideo);
2889
2890 outSISIDXREG(SISSR, IND_SIS_CMDQUEUE_SET, SIS_CMD_QUEUE_RESET);
2891
2892 }
2893 }
2894
2895 tempq = MMIO_IN32(ivideo->mmio_vbase, MMIO_QUEUE_READPORT);
2896 MMIO_OUT32(ivideo->mmio_vbase, MMIO_QUEUE_WRITEPORT, tempq);
2897
2898 temp |= (SIS_MMIO_CMD_ENABLE | SIS_CMD_AUTO_CORR);
2899 outSISIDXREG(SISSR, IND_SIS_CMDQUEUE_SET, temp);
2900
2901 tempq = (u32)(ivideo->video_size - ivideo->cmdQueueSize);
2902 MMIO_OUT32(ivideo->mmio_vbase, MMIO_QUEUE_PHYBASE, tempq);
2903
2904 ivideo->caps |= MMIO_CMD_QUEUE_CAP;
2905 }
2906#endif
2907
2908 ivideo->engineok = 1;
2909}
2910
2911static void __devinit
2912sisfb_detect_lcd_type(struct sis_video_info *ivideo)
2913{
2914 u8 reg;
2915 int i;
2916
2917 inSISIDXREG(SISCR, 0x36, reg);
2918 reg &= 0x0f;
2919 if(ivideo->sisvga_engine == SIS_300_VGA) {
2920 ivideo->CRT2LCDType = sis300paneltype[reg];
2921 } else if(ivideo->chip >= SIS_661) {
2922 ivideo->CRT2LCDType = sis661paneltype[reg];
2923 } else {
2924 ivideo->CRT2LCDType = sis310paneltype[reg];
2925 if((ivideo->chip == SIS_550) && (sisfb_fstn)) {
2926 if((ivideo->CRT2LCDType != LCD_320x240_2) &&
2927 (ivideo->CRT2LCDType != LCD_320x240_3)) {
2928 ivideo->CRT2LCDType = LCD_320x240;
2929 }
2930 }
2931 }
2932
2933 if(ivideo->CRT2LCDType == LCD_UNKNOWN) {
2934 /* For broken BIOSes: Assume 1024x768, RGB18 */
2935 ivideo->CRT2LCDType = LCD_1024x768;
2936 setSISIDXREG(SISCR,0x36,0xf0,0x02);
2937 setSISIDXREG(SISCR,0x37,0xee,0x01);
2938 printk(KERN_DEBUG "sisfb: Invalid panel ID (%02x), assuming 1024x768, RGB18\n", reg);
2939 }
2940
2941 for(i = 0; i < SIS_LCD_NUMBER; i++) {
2942 if(ivideo->CRT2LCDType == sis_lcd_data[i].lcdtype) {
2943 ivideo->lcdxres = sis_lcd_data[i].xres;
2944 ivideo->lcdyres = sis_lcd_data[i].yres;
2945 ivideo->lcddefmodeidx = sis_lcd_data[i].default_mode_idx;
2946 break;
2947 }
2948 }
2949
2950#ifdef CONFIG_FB_SIS_300
2951 if(ivideo->SiS_Pr.SiS_CustomT == CUT_BARCO1366) {
2952 ivideo->lcdxres = 1360; ivideo->lcdyres = 1024;
2953 ivideo->lcddefmodeidx = DEFAULT_MODE_1360;
2954 } else if(ivideo->SiS_Pr.SiS_CustomT == CUT_PANEL848) {
2955 ivideo->lcdxres = 848; ivideo->lcdyres = 480;
2956 ivideo->lcddefmodeidx = DEFAULT_MODE_848;
2957 } else if(ivideo->SiS_Pr.SiS_CustomT == CUT_PANEL856) {
2958 ivideo->lcdxres = 856; ivideo->lcdyres = 480;
2959 ivideo->lcddefmodeidx = DEFAULT_MODE_856;
2960 }
2961#endif
2962
2963 printk(KERN_DEBUG "sisfb: Detected %dx%d flat panel\n",
2964 ivideo->lcdxres, ivideo->lcdyres);
2965}
2966
2967static void __devinit
2968sisfb_save_pdc_emi(struct sis_video_info *ivideo)
2969{
2970#ifdef CONFIG_FB_SIS_300
2971 /* Save the current PanelDelayCompensation if the LCD is currently used */
2972 if(ivideo->sisvga_engine == SIS_300_VGA) {
2973 if(ivideo->vbflags2 & (VB2_LVDS | VB2_30xBDH)) {
2974 int tmp;
2975 inSISIDXREG(SISCR,0x30,tmp);
2976 if(tmp & 0x20) {
2977 /* Currently on LCD? If yes, read current pdc */
2978 inSISIDXREG(SISPART1,0x13,ivideo->detectedpdc);
2979 ivideo->detectedpdc &= 0x3c;
2980 if(ivideo->SiS_Pr.PDC == -1) {
2981 /* Let option override detection */
2982 ivideo->SiS_Pr.PDC = ivideo->detectedpdc;
2983 }
2984 printk(KERN_INFO "sisfb: Detected LCD PDC 0x%02x\n",
2985 ivideo->detectedpdc);
2986 }
2987 if((ivideo->SiS_Pr.PDC != -1) &&
2988 (ivideo->SiS_Pr.PDC != ivideo->detectedpdc)) {
2989 printk(KERN_INFO "sisfb: Using LCD PDC 0x%02x\n",
2990 ivideo->SiS_Pr.PDC);
2991 }
2992 }
2993 }
2994#endif
2995
2996#ifdef CONFIG_FB_SIS_315
2997 if(ivideo->sisvga_engine == SIS_315_VGA) {
2998
2999 /* Try to find about LCDA */
3000 if(ivideo->vbflags2 & VB2_SISLCDABRIDGE) {
3001 int tmp;
3002 inSISIDXREG(SISPART1,0x13,tmp);
3003 if(tmp & 0x04) {
Richard Knutssonc30660ea2007-02-12 00:55:06 -08003004 ivideo->SiS_Pr.SiS_UseLCDA = true;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003005 ivideo->detectedlcda = 0x03;
3006 }
3007 }
3008
3009 /* Save PDC */
3010 if(ivideo->vbflags2 & VB2_SISLVDSBRIDGE) {
3011 int tmp;
3012 inSISIDXREG(SISCR,0x30,tmp);
3013 if((tmp & 0x20) || (ivideo->detectedlcda != 0xff)) {
3014 /* Currently on LCD? If yes, read current pdc */
3015 u8 pdc;
3016 inSISIDXREG(SISPART1,0x2D,pdc);
3017 ivideo->detectedpdc = (pdc & 0x0f) << 1;
3018 ivideo->detectedpdca = (pdc & 0xf0) >> 3;
3019 inSISIDXREG(SISPART1,0x35,pdc);
3020 ivideo->detectedpdc |= ((pdc >> 7) & 0x01);
3021 inSISIDXREG(SISPART1,0x20,pdc);
3022 ivideo->detectedpdca |= ((pdc >> 6) & 0x01);
3023 if(ivideo->newrom) {
3024 /* New ROM invalidates other PDC resp. */
3025 if(ivideo->detectedlcda != 0xff) {
3026 ivideo->detectedpdc = 0xff;
3027 } else {
3028 ivideo->detectedpdca = 0xff;
3029 }
3030 }
3031 if(ivideo->SiS_Pr.PDC == -1) {
3032 if(ivideo->detectedpdc != 0xff) {
3033 ivideo->SiS_Pr.PDC = ivideo->detectedpdc;
3034 }
3035 }
3036 if(ivideo->SiS_Pr.PDCA == -1) {
3037 if(ivideo->detectedpdca != 0xff) {
3038 ivideo->SiS_Pr.PDCA = ivideo->detectedpdca;
3039 }
3040 }
3041 if(ivideo->detectedpdc != 0xff) {
3042 printk(KERN_INFO
3043 "sisfb: Detected LCD PDC 0x%02x (for LCD=CRT2)\n",
3044 ivideo->detectedpdc);
3045 }
3046 if(ivideo->detectedpdca != 0xff) {
3047 printk(KERN_INFO
3048 "sisfb: Detected LCD PDC1 0x%02x (for LCD=CRT1)\n",
3049 ivideo->detectedpdca);
3050 }
3051 }
3052
3053 /* Save EMI */
3054 if(ivideo->vbflags2 & VB2_SISEMIBRIDGE) {
3055 inSISIDXREG(SISPART4,0x30,ivideo->SiS_Pr.EMI_30);
3056 inSISIDXREG(SISPART4,0x31,ivideo->SiS_Pr.EMI_31);
3057 inSISIDXREG(SISPART4,0x32,ivideo->SiS_Pr.EMI_32);
3058 inSISIDXREG(SISPART4,0x33,ivideo->SiS_Pr.EMI_33);
Richard Knutssonc30660ea2007-02-12 00:55:06 -08003059 ivideo->SiS_Pr.HaveEMI = true;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003060 if((tmp & 0x20) || (ivideo->detectedlcda != 0xff)) {
Richard Knutssonc30660ea2007-02-12 00:55:06 -08003061 ivideo->SiS_Pr.HaveEMILCD = true;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003062 }
3063 }
3064 }
3065
3066 /* Let user override detected PDCs (all bridges) */
3067 if(ivideo->vbflags2 & VB2_30xBLV) {
3068 if((ivideo->SiS_Pr.PDC != -1) &&
3069 (ivideo->SiS_Pr.PDC != ivideo->detectedpdc)) {
3070 printk(KERN_INFO "sisfb: Using LCD PDC 0x%02x (for LCD=CRT2)\n",
3071 ivideo->SiS_Pr.PDC);
3072 }
3073 if((ivideo->SiS_Pr.PDCA != -1) &&
3074 (ivideo->SiS_Pr.PDCA != ivideo->detectedpdca)) {
3075 printk(KERN_INFO "sisfb: Using LCD PDC1 0x%02x (for LCD=CRT1)\n",
3076 ivideo->SiS_Pr.PDCA);
3077 }
3078 }
3079
3080 }
3081#endif
3082}
3083
3084/* -------------------- Memory manager routines ---------------------- */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003085
3086static u32 __devinit
3087sisfb_getheapstart(struct sis_video_info *ivideo)
3088{
3089 u32 ret = ivideo->sisfb_parm_mem * 1024;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003090 u32 maxoffs = ivideo->video_size - ivideo->hwcursor_size - ivideo->cmdQueueSize;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003091 u32 def;
3092
3093 /* Calculate heap start = end of memory for console
3094 *
3095 * CCCCCCCCDDDDDDDDDDDDDDDDDDDDDDDDDDDDHHHHQQQQQQQQQQ
3096 * C = console, D = heap, H = HWCursor, Q = cmd-queue
3097 *
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003098 * On 76x in UMA+LFB mode, the layout is as follows:
3099 * DDDDDDDDDDDCCCCCCCCCCCCCCCCCCCCCCCCHHHHQQQQQQQQQQQ
3100 * where the heap is the entire UMA area, eventually
3101 * into the LFB area if the given mem parameter is
3102 * higher than the size of the UMA memory.
3103 *
Linus Torvalds1da177e2005-04-16 15:20:36 -07003104 * Basically given by "mem" parameter
3105 *
3106 * maximum = videosize - cmd_queue - hwcursor
3107 * (results in a heap of size 0)
3108 * default = SiS 300: depends on videosize
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003109 * SiS 315/330/340/XGI: 32k below max
Linus Torvalds1da177e2005-04-16 15:20:36 -07003110 */
3111
3112 if(ivideo->sisvga_engine == SIS_300_VGA) {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003113 if(ivideo->video_size > 0x1000000) {
3114 def = 0xc00000;
3115 } else if(ivideo->video_size > 0x800000) {
3116 def = 0x800000;
3117 } else {
3118 def = 0x400000;
3119 }
3120 } else if(ivideo->UMAsize && ivideo->LFBsize) {
3121 ret = def = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003122 } else {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003123 def = maxoffs - 0x8000;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003124 }
3125
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003126 /* Use default for secondary card for now (FIXME) */
3127 if((!ret) || (ret > maxoffs) || (ivideo->cardnumber != 0))
3128 ret = def;
3129
3130 return ret;
3131}
3132
3133static u32 __devinit
3134sisfb_getheapsize(struct sis_video_info *ivideo)
3135{
3136 u32 max = ivideo->video_size - ivideo->hwcursor_size - ivideo->cmdQueueSize;
3137 u32 ret = 0;
3138
3139 if(ivideo->UMAsize && ivideo->LFBsize) {
3140 if( (!ivideo->sisfb_parm_mem) ||
3141 ((ivideo->sisfb_parm_mem * 1024) > max) ||
3142 ((max - (ivideo->sisfb_parm_mem * 1024)) < ivideo->UMAsize) ) {
3143 ret = ivideo->UMAsize;
3144 max -= ivideo->UMAsize;
3145 } else {
3146 ret = max - (ivideo->sisfb_parm_mem * 1024);
3147 max = ivideo->sisfb_parm_mem * 1024;
3148 }
3149 ivideo->video_offset = ret;
3150 ivideo->sisfb_mem = max;
3151 } else {
3152 ret = max - ivideo->heapstart;
3153 ivideo->sisfb_mem = ivideo->heapstart;
3154 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003155
3156 return ret;
3157}
3158
3159static int __devinit
3160sisfb_heap_init(struct sis_video_info *ivideo)
3161{
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003162 struct SIS_OH *poh;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003163
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003164 ivideo->video_offset = 0;
3165 if(ivideo->sisfb_parm_mem) {
3166 if( (ivideo->sisfb_parm_mem < (2 * 1024 * 1024)) ||
3167 (ivideo->sisfb_parm_mem > ivideo->video_size) ) {
3168 ivideo->sisfb_parm_mem = 0;
3169 }
3170 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003171
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003172 ivideo->heapstart = sisfb_getheapstart(ivideo);
3173 ivideo->sisfb_heap_size = sisfb_getheapsize(ivideo);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003174
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003175 ivideo->sisfb_heap_start = ivideo->video_vbase + ivideo->heapstart;
3176 ivideo->sisfb_heap_end = ivideo->sisfb_heap_start + ivideo->sisfb_heap_size;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003177
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003178 printk(KERN_INFO "sisfb: Memory heap starting at %dK, size %dK\n",
3179 (int)(ivideo->heapstart / 1024), (int)(ivideo->sisfb_heap_size / 1024));
Linus Torvalds1da177e2005-04-16 15:20:36 -07003180
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003181 ivideo->sisfb_heap.vinfo = ivideo;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003182
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003183 ivideo->sisfb_heap.poha_chain = NULL;
3184 ivideo->sisfb_heap.poh_freelist = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003185
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003186 poh = sisfb_poh_new_node(&ivideo->sisfb_heap);
3187 if(poh == NULL)
3188 return 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003189
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003190 poh->poh_next = &ivideo->sisfb_heap.oh_free;
3191 poh->poh_prev = &ivideo->sisfb_heap.oh_free;
3192 poh->size = ivideo->sisfb_heap_size;
3193 poh->offset = ivideo->heapstart;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003194
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003195 ivideo->sisfb_heap.oh_free.poh_next = poh;
3196 ivideo->sisfb_heap.oh_free.poh_prev = poh;
3197 ivideo->sisfb_heap.oh_free.size = 0;
3198 ivideo->sisfb_heap.max_freesize = poh->size;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003199
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003200 ivideo->sisfb_heap.oh_used.poh_next = &ivideo->sisfb_heap.oh_used;
3201 ivideo->sisfb_heap.oh_used.poh_prev = &ivideo->sisfb_heap.oh_used;
3202 ivideo->sisfb_heap.oh_used.size = SENTINEL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003203
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003204 if(ivideo->cardnumber == 0) {
3205 /* For the first card, make this heap the "global" one
3206 * for old DRM (which could handle only one card)
3207 */
3208 sisfb_heap = &ivideo->sisfb_heap;
3209 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003210
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003211 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003212}
3213
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003214static struct SIS_OH *
3215sisfb_poh_new_node(struct SIS_HEAP *memheap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003216{
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003217 struct SIS_OHALLOC *poha;
3218 struct SIS_OH *poh;
3219 unsigned long cOhs;
3220 int i;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003221
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003222 if(memheap->poh_freelist == NULL) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003223 poha = kmalloc(SIS_OH_ALLOC_SIZE, GFP_KERNEL);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003224 if(!poha)
3225 return NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003226
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003227 poha->poha_next = memheap->poha_chain;
3228 memheap->poha_chain = poha;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003229
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003230 cOhs = (SIS_OH_ALLOC_SIZE - sizeof(struct SIS_OHALLOC)) / sizeof(struct SIS_OH) + 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003231
3232 poh = &poha->aoh[0];
3233 for(i = cOhs - 1; i != 0; i--) {
3234 poh->poh_next = poh + 1;
3235 poh = poh + 1;
3236 }
3237
3238 poh->poh_next = NULL;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003239 memheap->poh_freelist = &poha->aoh[0];
Linus Torvalds1da177e2005-04-16 15:20:36 -07003240 }
3241
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003242 poh = memheap->poh_freelist;
3243 memheap->poh_freelist = poh->poh_next;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003244
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003245 return poh;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003246}
3247
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003248static struct SIS_OH *
3249sisfb_poh_allocate(struct SIS_HEAP *memheap, u32 size)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003250{
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003251 struct SIS_OH *pohThis;
3252 struct SIS_OH *pohRoot;
3253 int bAllocated = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003254
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003255 if(size > memheap->max_freesize) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003256 DPRINTK("sisfb: Can't allocate %dk video memory\n",
3257 (unsigned int) size / 1024);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003258 return NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003259 }
3260
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003261 pohThis = memheap->oh_free.poh_next;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003262
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003263 while(pohThis != &memheap->oh_free) {
3264 if(size <= pohThis->size) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003265 bAllocated = 1;
3266 break;
3267 }
3268 pohThis = pohThis->poh_next;
3269 }
3270
3271 if(!bAllocated) {
3272 DPRINTK("sisfb: Can't allocate %dk video memory\n",
3273 (unsigned int) size / 1024);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003274 return NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003275 }
3276
3277 if(size == pohThis->size) {
3278 pohRoot = pohThis;
3279 sisfb_delete_node(pohThis);
3280 } else {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003281 pohRoot = sisfb_poh_new_node(memheap);
3282 if(pohRoot == NULL)
3283 return NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003284
3285 pohRoot->offset = pohThis->offset;
3286 pohRoot->size = size;
3287
3288 pohThis->offset += size;
3289 pohThis->size -= size;
3290 }
3291
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003292 memheap->max_freesize -= size;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003293
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003294 pohThis = &memheap->oh_used;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003295 sisfb_insert_node(pohThis, pohRoot);
3296
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003297 return pohRoot;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003298}
3299
3300static void
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003301sisfb_delete_node(struct SIS_OH *poh)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003302{
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003303 poh->poh_prev->poh_next = poh->poh_next;
3304 poh->poh_next->poh_prev = poh->poh_prev;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003305}
3306
3307static void
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003308sisfb_insert_node(struct SIS_OH *pohList, struct SIS_OH *poh)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003309{
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003310 struct SIS_OH *pohTemp = pohList->poh_next;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003311
3312 pohList->poh_next = poh;
3313 pohTemp->poh_prev = poh;
3314
3315 poh->poh_prev = pohList;
3316 poh->poh_next = pohTemp;
3317}
3318
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003319static struct SIS_OH *
3320sisfb_poh_free(struct SIS_HEAP *memheap, u32 base)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003321{
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003322 struct SIS_OH *pohThis;
3323 struct SIS_OH *poh_freed;
3324 struct SIS_OH *poh_prev;
3325 struct SIS_OH *poh_next;
3326 u32 ulUpper;
3327 u32 ulLower;
3328 int foundNode = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003329
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003330 poh_freed = memheap->oh_used.poh_next;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003331
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003332 while(poh_freed != &memheap->oh_used) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003333 if(poh_freed->offset == base) {
3334 foundNode = 1;
3335 break;
3336 }
3337
3338 poh_freed = poh_freed->poh_next;
3339 }
3340
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003341 if(!foundNode)
3342 return NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003343
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003344 memheap->max_freesize += poh_freed->size;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003345
3346 poh_prev = poh_next = NULL;
3347 ulUpper = poh_freed->offset + poh_freed->size;
3348 ulLower = poh_freed->offset;
3349
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003350 pohThis = memheap->oh_free.poh_next;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003351
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003352 while(pohThis != &memheap->oh_free) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003353 if(pohThis->offset == ulUpper) {
3354 poh_next = pohThis;
3355 } else if((pohThis->offset + pohThis->size) == ulLower) {
3356 poh_prev = pohThis;
3357 }
3358 pohThis = pohThis->poh_next;
3359 }
3360
3361 sisfb_delete_node(poh_freed);
3362
3363 if(poh_prev && poh_next) {
3364 poh_prev->size += (poh_freed->size + poh_next->size);
3365 sisfb_delete_node(poh_next);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003366 sisfb_free_node(memheap, poh_freed);
3367 sisfb_free_node(memheap, poh_next);
3368 return poh_prev;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003369 }
3370
3371 if(poh_prev) {
3372 poh_prev->size += poh_freed->size;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003373 sisfb_free_node(memheap, poh_freed);
3374 return poh_prev;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003375 }
3376
3377 if(poh_next) {
3378 poh_next->size += poh_freed->size;
3379 poh_next->offset = poh_freed->offset;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003380 sisfb_free_node(memheap, poh_freed);
3381 return poh_next;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003382 }
3383
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003384 sisfb_insert_node(&memheap->oh_free, poh_freed);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003385
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003386 return poh_freed;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003387}
3388
3389static void
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003390sisfb_free_node(struct SIS_HEAP *memheap, struct SIS_OH *poh)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003391{
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003392 if(poh == NULL)
3393 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003394
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003395 poh->poh_next = memheap->poh_freelist;
3396 memheap->poh_freelist = poh;
3397}
3398
3399static void
3400sis_int_malloc(struct sis_video_info *ivideo, struct sis_memreq *req)
3401{
3402 struct SIS_OH *poh = NULL;
3403
3404 if((ivideo) && (ivideo->sisfb_id == SISFB_ID) && (!ivideo->havenoheap))
3405 poh = sisfb_poh_allocate(&ivideo->sisfb_heap, (u32)req->size);
3406
3407 if(poh == NULL) {
3408 req->offset = req->size = 0;
3409 DPRINTK("sisfb: Video RAM allocation failed\n");
3410 } else {
3411 req->offset = poh->offset;
3412 req->size = poh->size;
3413 DPRINTK("sisfb: Video RAM allocation succeeded: 0x%lx\n",
3414 (poh->offset + ivideo->video_vbase));
3415 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003416}
3417
3418void
3419sis_malloc(struct sis_memreq *req)
3420{
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003421 struct sis_video_info *ivideo = sisfb_heap->vinfo;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003422
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003423 if(&ivideo->sisfb_heap == sisfb_heap)
3424 sis_int_malloc(ivideo, req);
3425 else
3426 req->offset = req->size = 0;
3427}
Linus Torvalds1da177e2005-04-16 15:20:36 -07003428
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003429void
3430sis_malloc_new(struct pci_dev *pdev, struct sis_memreq *req)
3431{
3432 struct sis_video_info *ivideo = pci_get_drvdata(pdev);
3433
3434 sis_int_malloc(ivideo, req);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003435}
3436
3437/* sis_free: u32 because "base" is offset inside video ram, can never be >4GB */
3438
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003439static void
3440sis_int_free(struct sis_video_info *ivideo, u32 base)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003441{
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003442 struct SIS_OH *poh;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003443
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003444 if((!ivideo) || (ivideo->sisfb_id != SISFB_ID) || (ivideo->havenoheap))
3445 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003446
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003447 poh = sisfb_poh_free(&ivideo->sisfb_heap, base);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003448
3449 if(poh == NULL) {
3450 DPRINTK("sisfb: sisfb_poh_free() failed at base 0x%x\n",
3451 (unsigned int) base);
3452 }
3453}
3454
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003455void
3456sis_free(u32 base)
3457{
3458 struct sis_video_info *ivideo = sisfb_heap->vinfo;
3459
3460 sis_int_free(ivideo, base);
3461}
3462
3463void
3464sis_free_new(struct pci_dev *pdev, u32 base)
3465{
3466 struct sis_video_info *ivideo = pci_get_drvdata(pdev);
3467
3468 sis_int_free(ivideo, base);
3469}
3470
Linus Torvalds1da177e2005-04-16 15:20:36 -07003471/* --------------------- SetMode routines ------------------------- */
3472
3473static void
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003474sisfb_check_engine_and_sync(struct sis_video_info *ivideo)
3475{
3476 u8 cr30, cr31;
3477
3478 /* Check if MMIO and engines are enabled,
3479 * and sync in case they are. Can't use
3480 * ivideo->accel here, as this might have
3481 * been changed before this is called.
3482 */
3483 inSISIDXREG(SISSR, IND_SIS_PCI_ADDRESS_SET, cr30);
3484 inSISIDXREG(SISSR, IND_SIS_MODULE_ENABLE, cr31);
3485 /* MMIO and 2D/3D engine enabled? */
3486 if((cr30 & SIS_MEM_MAP_IO_ENABLE) && (cr31 & 0x42)) {
3487#ifdef CONFIG_FB_SIS_300
3488 if(ivideo->sisvga_engine == SIS_300_VGA) {
3489 /* Don't care about TurboQueue. It's
3490 * enough to know that the engines
3491 * are enabled
3492 */
3493 sisfb_syncaccel(ivideo);
3494 }
3495#endif
3496#ifdef CONFIG_FB_SIS_315
3497 if(ivideo->sisvga_engine == SIS_315_VGA) {
3498 /* Check that any queue mode is
3499 * enabled, and that the queue
3500 * is not in the state of "reset"
3501 */
3502 inSISIDXREG(SISSR, 0x26, cr30);
3503 if((cr30 & 0xe0) && (!(cr30 & 0x01))) {
3504 sisfb_syncaccel(ivideo);
3505 }
3506 }
3507#endif
3508 }
3509}
3510
3511static void
Linus Torvalds1da177e2005-04-16 15:20:36 -07003512sisfb_pre_setmode(struct sis_video_info *ivideo)
3513{
3514 u8 cr30 = 0, cr31 = 0, cr33 = 0, cr35 = 0, cr38 = 0;
3515 int tvregnum = 0;
3516
3517 ivideo->currentvbflags &= (VB_VIDEOBRIDGE | VB_DISPTYPE_DISP2);
3518
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003519 outSISIDXREG(SISSR, 0x05, 0x86);
3520
Linus Torvalds1da177e2005-04-16 15:20:36 -07003521 inSISIDXREG(SISCR, 0x31, cr31);
3522 cr31 &= ~0x60;
3523 cr31 |= 0x04;
3524
3525 cr33 = ivideo->rate_idx & 0x0F;
3526
3527#ifdef CONFIG_FB_SIS_315
3528 if(ivideo->sisvga_engine == SIS_315_VGA) {
3529 if(ivideo->chip >= SIS_661) {
3530 inSISIDXREG(SISCR, 0x38, cr38);
3531 cr38 &= ~0x07; /* Clear LCDA/DualEdge and YPbPr bits */
3532 } else {
3533 tvregnum = 0x38;
3534 inSISIDXREG(SISCR, tvregnum, cr38);
3535 cr38 &= ~0x3b; /* Clear LCDA/DualEdge and YPbPr bits */
3536 }
3537 }
3538#endif
3539#ifdef CONFIG_FB_SIS_300
3540 if(ivideo->sisvga_engine == SIS_300_VGA) {
3541 tvregnum = 0x35;
3542 inSISIDXREG(SISCR, tvregnum, cr38);
3543 }
3544#endif
3545
Richard Knutssonc30660ea2007-02-12 00:55:06 -08003546 SiS_SetEnableDstn(&ivideo->SiS_Pr, false);
3547 SiS_SetEnableFstn(&ivideo->SiS_Pr, false);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003548 ivideo->curFSTN = ivideo->curDSTN = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003549
3550 switch(ivideo->currentvbflags & VB_DISPTYPE_DISP2) {
3551
3552 case CRT2_TV:
3553 cr38 &= ~0xc0; /* Clear PAL-M / PAL-N bits */
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003554 if((ivideo->vbflags & TV_YPBPR) && (ivideo->vbflags2 & VB2_SISYPBPRBRIDGE)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003555#ifdef CONFIG_FB_SIS_315
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003556 if(ivideo->chip >= SIS_661) {
3557 cr38 |= 0x04;
3558 if(ivideo->vbflags & TV_YPBPR525P) cr35 |= 0x20;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003559 else if(ivideo->vbflags & TV_YPBPR750P) cr35 |= 0x40;
3560 else if(ivideo->vbflags & TV_YPBPR1080I) cr35 |= 0x60;
3561 cr30 |= SIS_SIMULTANEOUS_VIEW_ENABLE;
3562 cr35 &= ~0x01;
3563 ivideo->currentvbflags |= (TV_YPBPR | (ivideo->vbflags & TV_YPBPRALL));
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003564 } else if(ivideo->sisvga_engine == SIS_315_VGA) {
3565 cr30 |= (0x80 | SIS_SIMULTANEOUS_VIEW_ENABLE);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003566 cr38 |= 0x08;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003567 if(ivideo->vbflags & TV_YPBPR525P) cr38 |= 0x10;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003568 else if(ivideo->vbflags & TV_YPBPR750P) cr38 |= 0x20;
3569 else if(ivideo->vbflags & TV_YPBPR1080I) cr38 |= 0x30;
3570 cr31 &= ~0x01;
3571 ivideo->currentvbflags |= (TV_YPBPR | (ivideo->vbflags & TV_YPBPRALL));
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003572 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003573#endif
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003574 } else if((ivideo->vbflags & TV_HIVISION) &&
3575 (ivideo->vbflags2 & VB2_SISHIVISIONBRIDGE)) {
3576 if(ivideo->chip >= SIS_661) {
3577 cr38 |= 0x04;
3578 cr35 |= 0x60;
3579 } else {
3580 cr30 |= 0x80;
3581 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003582 cr30 |= SIS_SIMULTANEOUS_VIEW_ENABLE;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003583 cr31 |= 0x01;
3584 cr35 |= 0x01;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003585 ivideo->currentvbflags |= TV_HIVISION;
3586 } else if(ivideo->vbflags & TV_SCART) {
3587 cr30 = (SIS_VB_OUTPUT_SCART | SIS_SIMULTANEOUS_VIEW_ENABLE);
3588 cr31 |= 0x01;
3589 cr35 |= 0x01;
3590 ivideo->currentvbflags |= TV_SCART;
3591 } else {
3592 if(ivideo->vbflags & TV_SVIDEO) {
3593 cr30 = (SIS_VB_OUTPUT_SVIDEO | SIS_SIMULTANEOUS_VIEW_ENABLE);
3594 ivideo->currentvbflags |= TV_SVIDEO;
3595 }
3596 if(ivideo->vbflags & TV_AVIDEO) {
3597 cr30 = (SIS_VB_OUTPUT_COMPOSITE | SIS_SIMULTANEOUS_VIEW_ENABLE);
3598 ivideo->currentvbflags |= TV_AVIDEO;
3599 }
3600 }
3601 cr31 |= SIS_DRIVER_MODE;
3602
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003603 if(ivideo->vbflags & (TV_AVIDEO | TV_SVIDEO)) {
3604 if(ivideo->vbflags & TV_PAL) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003605 cr31 |= 0x01; cr35 |= 0x01;
3606 ivideo->currentvbflags |= TV_PAL;
3607 if(ivideo->vbflags & TV_PALM) {
3608 cr38 |= 0x40; cr35 |= 0x04;
3609 ivideo->currentvbflags |= TV_PALM;
3610 } else if(ivideo->vbflags & TV_PALN) {
3611 cr38 |= 0x80; cr35 |= 0x08;
3612 ivideo->currentvbflags |= TV_PALN;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003613 }
3614 } else {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003615 cr31 &= ~0x01; cr35 &= ~0x01;
3616 ivideo->currentvbflags |= TV_NTSC;
3617 if(ivideo->vbflags & TV_NTSCJ) {
3618 cr38 |= 0x40; cr35 |= 0x02;
3619 ivideo->currentvbflags |= TV_NTSCJ;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003620 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003621 }
3622 }
3623 break;
3624
3625 case CRT2_LCD:
3626 cr30 = (SIS_VB_OUTPUT_LCD | SIS_SIMULTANEOUS_VIEW_ENABLE);
3627 cr31 |= SIS_DRIVER_MODE;
3628 SiS_SetEnableDstn(&ivideo->SiS_Pr, ivideo->sisfb_dstn);
3629 SiS_SetEnableFstn(&ivideo->SiS_Pr, ivideo->sisfb_fstn);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003630 ivideo->curFSTN = ivideo->sisfb_fstn;
3631 ivideo->curDSTN = ivideo->sisfb_dstn;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003632 break;
3633
3634 case CRT2_VGA:
3635 cr30 = (SIS_VB_OUTPUT_CRT2 | SIS_SIMULTANEOUS_VIEW_ENABLE);
3636 cr31 |= SIS_DRIVER_MODE;
3637 if(ivideo->sisfb_nocrt2rate) {
3638 cr33 |= (sisbios_mode[ivideo->sisfb_mode_idx].rate_idx << 4);
3639 } else {
3640 cr33 |= ((ivideo->rate_idx & 0x0F) << 4);
3641 }
3642 break;
3643
3644 default: /* disable CRT2 */
3645 cr30 = 0x00;
3646 cr31 |= (SIS_DRIVER_MODE | SIS_VB_OUTPUT_DISABLE);
3647 }
3648
3649 outSISIDXREG(SISCR, 0x30, cr30);
3650 outSISIDXREG(SISCR, 0x33, cr33);
3651
3652 if(ivideo->chip >= SIS_661) {
3653#ifdef CONFIG_FB_SIS_315
3654 cr31 &= ~0x01; /* Clear PAL flag (now in CR35) */
3655 setSISIDXREG(SISCR, 0x35, ~0x10, cr35); /* Leave overscan bit alone */
3656 cr38 &= 0x07; /* Use only LCDA and HiVision/YPbPr bits */
3657 setSISIDXREG(SISCR, 0x38, 0xf8, cr38);
3658#endif
3659 } else if(ivideo->chip != SIS_300) {
3660 outSISIDXREG(SISCR, tvregnum, cr38);
3661 }
3662 outSISIDXREG(SISCR, 0x31, cr31);
3663
Linus Torvalds1da177e2005-04-16 15:20:36 -07003664 ivideo->SiS_Pr.SiS_UseOEM = ivideo->sisfb_useoem;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003665
3666 sisfb_check_engine_and_sync(ivideo);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003667}
3668
3669/* Fix SR11 for 661 and later */
3670#ifdef CONFIG_FB_SIS_315
3671static void
3672sisfb_fixup_SR11(struct sis_video_info *ivideo)
3673{
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003674 u8 tmpreg;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003675
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003676 if(ivideo->chip >= SIS_661) {
3677 inSISIDXREG(SISSR,0x11,tmpreg);
3678 if(tmpreg & 0x20) {
3679 inSISIDXREG(SISSR,0x3e,tmpreg);
3680 tmpreg = (tmpreg + 1) & 0xff;
3681 outSISIDXREG(SISSR,0x3e,tmpreg);
3682 inSISIDXREG(SISSR,0x11,tmpreg);
3683 }
3684 if(tmpreg & 0xf0) {
3685 andSISIDXREG(SISSR,0x11,0x0f);
3686 }
3687 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003688}
3689#endif
3690
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003691static void
3692sisfb_set_TVxposoffset(struct sis_video_info *ivideo, int val)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003693{
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003694 if(val > 32) val = 32;
3695 if(val < -32) val = -32;
3696 ivideo->tvxpos = val;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003697
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003698 if(ivideo->sisfblocked) return;
3699 if(!ivideo->modechanged) return;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003700
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003701 if(ivideo->currentvbflags & CRT2_TV) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003702
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003703 if(ivideo->vbflags2 & VB2_CHRONTEL) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003704
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003705 int x = ivideo->tvx;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003706
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003707 switch(ivideo->chronteltype) {
3708 case 1:
3709 x += val;
3710 if(x < 0) x = 0;
3711 outSISIDXREG(SISSR,0x05,0x86);
3712 SiS_SetCH700x(&ivideo->SiS_Pr, 0x0a, (x & 0xff));
3713 SiS_SetCH70xxANDOR(&ivideo->SiS_Pr, 0x08, ((x & 0x0100) >> 7), 0xFD);
3714 break;
3715 case 2:
3716 /* Not supported by hardware */
3717 break;
3718 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003719
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003720 } else if(ivideo->vbflags2 & VB2_SISBRIDGE) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003721
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003722 u8 p2_1f,p2_20,p2_2b,p2_42,p2_43;
3723 unsigned short temp;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003724
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003725 p2_1f = ivideo->p2_1f;
3726 p2_20 = ivideo->p2_20;
3727 p2_2b = ivideo->p2_2b;
3728 p2_42 = ivideo->p2_42;
3729 p2_43 = ivideo->p2_43;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003730
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003731 temp = p2_1f | ((p2_20 & 0xf0) << 4);
3732 temp += (val * 2);
3733 p2_1f = temp & 0xff;
3734 p2_20 = (temp & 0xf00) >> 4;
3735 p2_2b = ((p2_2b & 0x0f) + (val * 2)) & 0x0f;
3736 temp = p2_43 | ((p2_42 & 0xf0) << 4);
3737 temp += (val * 2);
3738 p2_43 = temp & 0xff;
3739 p2_42 = (temp & 0xf00) >> 4;
3740 outSISIDXREG(SISPART2,0x1f,p2_1f);
3741 setSISIDXREG(SISPART2,0x20,0x0F,p2_20);
3742 setSISIDXREG(SISPART2,0x2b,0xF0,p2_2b);
3743 setSISIDXREG(SISPART2,0x42,0x0F,p2_42);
3744 outSISIDXREG(SISPART2,0x43,p2_43);
3745 }
3746 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003747}
3748
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003749static void
3750sisfb_set_TVyposoffset(struct sis_video_info *ivideo, int val)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003751{
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003752 if(val > 32) val = 32;
3753 if(val < -32) val = -32;
3754 ivideo->tvypos = val;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003755
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003756 if(ivideo->sisfblocked) return;
3757 if(!ivideo->modechanged) return;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003758
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003759 if(ivideo->currentvbflags & CRT2_TV) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003760
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003761 if(ivideo->vbflags2 & VB2_CHRONTEL) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003762
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003763 int y = ivideo->tvy;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003764
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003765 switch(ivideo->chronteltype) {
3766 case 1:
3767 y -= val;
3768 if(y < 0) y = 0;
3769 outSISIDXREG(SISSR,0x05,0x86);
3770 SiS_SetCH700x(&ivideo->SiS_Pr, 0x0b, (y & 0xff));
3771 SiS_SetCH70xxANDOR(&ivideo->SiS_Pr, 0x08, ((y & 0x0100) >> 8), 0xFE);
3772 break;
3773 case 2:
3774 /* Not supported by hardware */
3775 break;
3776 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003777
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003778 } else if(ivideo->vbflags2 & VB2_SISBRIDGE) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003779
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003780 char p2_01, p2_02;
3781 val /= 2;
3782 p2_01 = ivideo->p2_01;
3783 p2_02 = ivideo->p2_02;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003784
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003785 p2_01 += val;
3786 p2_02 += val;
3787 if(!(ivideo->currentvbflags & (TV_HIVISION | TV_YPBPR))) {
3788 while((p2_01 <= 0) || (p2_02 <= 0)) {
3789 p2_01 += 2;
3790 p2_02 += 2;
3791 }
3792 }
3793 outSISIDXREG(SISPART2,0x01,p2_01);
3794 outSISIDXREG(SISPART2,0x02,p2_02);
3795 }
3796 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003797}
3798
3799static void
3800sisfb_post_setmode(struct sis_video_info *ivideo)
3801{
Richard Knutssonc30660ea2007-02-12 00:55:06 -08003802 bool crt1isoff = false;
3803 bool doit = true;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003804#if defined(CONFIG_FB_SIS_300) || defined(CONFIG_FB_SIS_315)
3805 u8 reg;
3806#endif
3807#ifdef CONFIG_FB_SIS_315
3808 u8 reg1;
3809#endif
3810
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003811 outSISIDXREG(SISSR, 0x05, 0x86);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003812
3813#ifdef CONFIG_FB_SIS_315
3814 sisfb_fixup_SR11(ivideo);
3815#endif
3816
3817 /* Now we actually HAVE changed the display mode */
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003818 ivideo->modechanged = 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003819
3820 /* We can't switch off CRT1 if bridge is in slave mode */
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003821 if(ivideo->vbflags2 & VB2_VIDEOBRIDGE) {
Richard Knutssonc30660ea2007-02-12 00:55:06 -08003822 if(sisfb_bridgeisslave(ivideo)) doit = false;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003823 } else
3824 ivideo->sisfb_crt1off = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003825
3826#ifdef CONFIG_FB_SIS_300
3827 if(ivideo->sisvga_engine == SIS_300_VGA) {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003828 if((ivideo->sisfb_crt1off) && (doit)) {
Richard Knutssonc30660ea2007-02-12 00:55:06 -08003829 crt1isoff = true;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003830 reg = 0x00;
3831 } else {
Richard Knutssonc30660ea2007-02-12 00:55:06 -08003832 crt1isoff = false;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003833 reg = 0x80;
3834 }
3835 setSISIDXREG(SISCR, 0x17, 0x7f, reg);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003836 }
3837#endif
3838#ifdef CONFIG_FB_SIS_315
3839 if(ivideo->sisvga_engine == SIS_315_VGA) {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003840 if((ivideo->sisfb_crt1off) && (doit)) {
Richard Knutssonc30660ea2007-02-12 00:55:06 -08003841 crt1isoff = true;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003842 reg = 0x40;
3843 reg1 = 0xc0;
3844 } else {
Richard Knutssonc30660ea2007-02-12 00:55:06 -08003845 crt1isoff = false;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003846 reg = 0x00;
3847 reg1 = 0x00;
3848 }
3849 setSISIDXREG(SISCR, ivideo->SiS_Pr.SiS_MyCR63, ~0x40, reg);
3850 setSISIDXREG(SISSR, 0x1f, ~0xc0, reg1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003851 }
3852#endif
3853
3854 if(crt1isoff) {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003855 ivideo->currentvbflags &= ~VB_DISPTYPE_CRT1;
3856 ivideo->currentvbflags |= VB_SINGLE_MODE;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003857 } else {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003858 ivideo->currentvbflags |= VB_DISPTYPE_CRT1;
3859 if(ivideo->currentvbflags & VB_DISPTYPE_CRT2) {
3860 ivideo->currentvbflags |= VB_MIRROR_MODE;
3861 } else {
3862 ivideo->currentvbflags |= VB_SINGLE_MODE;
3863 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003864 }
3865
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003866 andSISIDXREG(SISSR, IND_SIS_RAMDAC_CONTROL, ~0x04);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003867
3868 if(ivideo->currentvbflags & CRT2_TV) {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003869 if(ivideo->vbflags2 & VB2_SISBRIDGE) {
3870 inSISIDXREG(SISPART2,0x1f,ivideo->p2_1f);
3871 inSISIDXREG(SISPART2,0x20,ivideo->p2_20);
3872 inSISIDXREG(SISPART2,0x2b,ivideo->p2_2b);
3873 inSISIDXREG(SISPART2,0x42,ivideo->p2_42);
3874 inSISIDXREG(SISPART2,0x43,ivideo->p2_43);
3875 inSISIDXREG(SISPART2,0x01,ivideo->p2_01);
3876 inSISIDXREG(SISPART2,0x02,ivideo->p2_02);
3877 } else if(ivideo->vbflags2 & VB2_CHRONTEL) {
3878 if(ivideo->chronteltype == 1) {
3879 ivideo->tvx = SiS_GetCH700x(&ivideo->SiS_Pr, 0x0a);
3880 ivideo->tvx |= (((SiS_GetCH700x(&ivideo->SiS_Pr, 0x08) & 0x02) >> 1) << 8);
3881 ivideo->tvy = SiS_GetCH700x(&ivideo->SiS_Pr, 0x0b);
3882 ivideo->tvy |= ((SiS_GetCH700x(&ivideo->SiS_Pr, 0x08) & 0x01) << 8);
3883 }
3884 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003885 }
3886
3887 if(ivideo->tvxpos) {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003888 sisfb_set_TVxposoffset(ivideo, ivideo->tvxpos);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003889 }
3890 if(ivideo->tvypos) {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003891 sisfb_set_TVyposoffset(ivideo, ivideo->tvypos);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003892 }
3893
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003894 /* Eventually sync engines */
3895 sisfb_check_engine_and_sync(ivideo);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003896
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003897 /* (Re-)Initialize chip engines */
3898 if(ivideo->accel) {
3899 sisfb_engine_init(ivideo);
3900 } else {
3901 ivideo->engineok = 0;
3902 }
3903}
Linus Torvalds1da177e2005-04-16 15:20:36 -07003904
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003905static int
3906sisfb_reset_mode(struct sis_video_info *ivideo)
3907{
3908 if(sisfb_set_mode(ivideo, 0))
3909 return 1;
3910
3911 sisfb_set_pitch(ivideo);
3912 sisfb_set_base_CRT1(ivideo, ivideo->current_base);
3913 sisfb_set_base_CRT2(ivideo, ivideo->current_base);
3914
3915 return 0;
3916}
3917
3918static void
3919sisfb_handle_command(struct sis_video_info *ivideo, struct sisfb_cmd *sisfb_command)
3920{
3921 int mycrt1off;
3922
3923 switch(sisfb_command->sisfb_cmd) {
3924 case SISFB_CMD_GETVBFLAGS:
3925 if(!ivideo->modechanged) {
3926 sisfb_command->sisfb_result[0] = SISFB_CMD_ERR_EARLY;
3927 } else {
3928 sisfb_command->sisfb_result[0] = SISFB_CMD_ERR_OK;
3929 sisfb_command->sisfb_result[1] = ivideo->currentvbflags;
3930 sisfb_command->sisfb_result[2] = ivideo->vbflags2;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003931 }
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003932 break;
3933 case SISFB_CMD_SWITCHCRT1:
3934 /* arg[0]: 0 = off, 1 = on, 99 = query */
3935 if(!ivideo->modechanged) {
3936 sisfb_command->sisfb_result[0] = SISFB_CMD_ERR_EARLY;
3937 } else if(sisfb_command->sisfb_arg[0] == 99) {
3938 /* Query */
3939 sisfb_command->sisfb_result[1] = ivideo->sisfb_crt1off ? 0 : 1;
3940 sisfb_command->sisfb_result[0] = SISFB_CMD_ERR_OK;
3941 } else if(ivideo->sisfblocked) {
3942 sisfb_command->sisfb_result[0] = SISFB_CMD_ERR_LOCKED;
3943 } else if((!(ivideo->currentvbflags & CRT2_ENABLE)) &&
3944 (sisfb_command->sisfb_arg[0] == 0)) {
3945 sisfb_command->sisfb_result[0] = SISFB_CMD_ERR_NOCRT2;
3946 } else {
3947 sisfb_command->sisfb_result[0] = SISFB_CMD_ERR_OK;
3948 mycrt1off = sisfb_command->sisfb_arg[0] ? 0 : 1;
3949 if( ((ivideo->currentvbflags & VB_DISPTYPE_CRT1) && mycrt1off) ||
3950 ((!(ivideo->currentvbflags & VB_DISPTYPE_CRT1)) && !mycrt1off) ) {
3951 ivideo->sisfb_crt1off = mycrt1off;
3952 if(sisfb_reset_mode(ivideo)) {
3953 sisfb_command->sisfb_result[0] = SISFB_CMD_ERR_OTHER;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003954 }
3955 }
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003956 sisfb_command->sisfb_result[1] = ivideo->sisfb_crt1off ? 0 : 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003957 }
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003958 break;
3959 /* more to come */
3960 default:
3961 sisfb_command->sisfb_result[0] = SISFB_CMD_ERR_UNKNOWN;
3962 printk(KERN_ERR "sisfb: Unknown command 0x%x\n",
3963 sisfb_command->sisfb_cmd);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003964 }
3965}
3966
3967#ifndef MODULE
Adrian Bunk14aefd12008-07-23 21:31:12 -07003968static int __init sisfb_setup(char *options)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003969{
3970 char *this_opt;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003971
Linus Torvalds1da177e2005-04-16 15:20:36 -07003972 sisfb_setdefaultparms();
3973
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003974 if(!options || !(*options))
Linus Torvalds1da177e2005-04-16 15:20:36 -07003975 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003976
3977 while((this_opt = strsep(&options, ",")) != NULL) {
3978
3979 if(!(*this_opt)) continue;
3980
3981 if(!strnicmp(this_opt, "off", 3)) {
3982 sisfb_off = 1;
3983 } else if(!strnicmp(this_opt, "forcecrt2type:", 14)) {
3984 /* Need to check crt2 type first for fstn/dstn */
3985 sisfb_search_crt2type(this_opt + 14);
3986 } else if(!strnicmp(this_opt, "tvmode:",7)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003987 sisfb_search_tvstd(this_opt + 7);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003988 } else if(!strnicmp(this_opt, "tvstandard:",11)) {
3989 sisfb_search_tvstd(this_opt + 11);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003990 } else if(!strnicmp(this_opt, "mode:", 5)) {
Richard Knutssonc30660ea2007-02-12 00:55:06 -08003991 sisfb_search_mode(this_opt + 5, false);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003992 } else if(!strnicmp(this_opt, "vesa:", 5)) {
Richard Knutssonc30660ea2007-02-12 00:55:06 -08003993 sisfb_search_vesamode(simple_strtoul(this_opt + 5, NULL, 0), false);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003994 } else if(!strnicmp(this_opt, "rate:", 5)) {
3995 sisfb_parm_rate = simple_strtoul(this_opt + 5, NULL, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003996 } else if(!strnicmp(this_opt, "forcecrt1:", 10)) {
3997 sisfb_forcecrt1 = (int)simple_strtoul(this_opt + 10, NULL, 0);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003998 } else if(!strnicmp(this_opt, "mem:",4)) {
3999 sisfb_parm_mem = simple_strtoul(this_opt + 4, NULL, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004000 } else if(!strnicmp(this_opt, "pdc:", 4)) {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004001 sisfb_pdc = simple_strtoul(this_opt + 4, NULL, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004002 } else if(!strnicmp(this_opt, "pdc1:", 5)) {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004003 sisfb_pdca = simple_strtoul(this_opt + 5, NULL, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004004 } else if(!strnicmp(this_opt, "noaccel", 7)) {
4005 sisfb_accel = 0;
4006 } else if(!strnicmp(this_opt, "accel", 5)) {
4007 sisfb_accel = -1;
4008 } else if(!strnicmp(this_opt, "noypan", 6)) {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004009 sisfb_ypan = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004010 } else if(!strnicmp(this_opt, "ypan", 4)) {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004011 sisfb_ypan = -1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004012 } else if(!strnicmp(this_opt, "nomax", 5)) {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004013 sisfb_max = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004014 } else if(!strnicmp(this_opt, "max", 3)) {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004015 sisfb_max = -1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004016 } else if(!strnicmp(this_opt, "userom:", 7)) {
4017 sisfb_userom = (int)simple_strtoul(this_opt + 7, NULL, 0);
4018 } else if(!strnicmp(this_opt, "useoem:", 7)) {
4019 sisfb_useoem = (int)simple_strtoul(this_opt + 7, NULL, 0);
4020 } else if(!strnicmp(this_opt, "nocrt2rate", 10)) {
4021 sisfb_nocrt2rate = 1;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004022 } else if(!strnicmp(this_opt, "scalelcd:", 9)) {
4023 unsigned long temp = 2;
4024 temp = simple_strtoul(this_opt + 9, NULL, 0);
4025 if((temp == 0) || (temp == 1)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004026 sisfb_scalelcd = temp ^ 1;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004027 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004028 } else if(!strnicmp(this_opt, "tvxposoffset:", 13)) {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004029 int temp = 0;
4030 temp = (int)simple_strtol(this_opt + 13, NULL, 0);
4031 if((temp >= -32) && (temp <= 32)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004032 sisfb_tvxposoffset = temp;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004033 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004034 } else if(!strnicmp(this_opt, "tvyposoffset:", 13)) {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004035 int temp = 0;
4036 temp = (int)simple_strtol(this_opt + 13, NULL, 0);
4037 if((temp >= -32) && (temp <= 32)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004038 sisfb_tvyposoffset = temp;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004039 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004040 } else if(!strnicmp(this_opt, "specialtiming:", 14)) {
4041 sisfb_search_specialtiming(this_opt + 14);
4042 } else if(!strnicmp(this_opt, "lvdshl:", 7)) {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004043 int temp = 4;
4044 temp = simple_strtoul(this_opt + 7, NULL, 0);
4045 if((temp >= 0) && (temp <= 3)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004046 sisfb_lvdshl = temp;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004047 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004048 } else if(this_opt[0] >= '0' && this_opt[0] <= '9') {
Richard Knutssonc30660ea2007-02-12 00:55:06 -08004049 sisfb_search_mode(this_opt, true);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004050#if !defined(__i386__) && !defined(__x86_64__)
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004051 } else if(!strnicmp(this_opt, "resetcard", 9)) {
4052 sisfb_resetcard = 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004053 } else if(!strnicmp(this_opt, "videoram:", 9)) {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004054 sisfb_videoram = simple_strtoul(this_opt + 9, NULL, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004055#endif
4056 } else {
4057 printk(KERN_INFO "sisfb: Invalid option %s\n", this_opt);
4058 }
4059
4060 }
4061
Linus Torvalds1da177e2005-04-16 15:20:36 -07004062 return 0;
4063}
4064#endif
4065
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004066static int __devinit
Adrian Bunk14aefd12008-07-23 21:31:12 -07004067sisfb_check_rom(void __iomem *rom_base, struct sis_video_info *ivideo)
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004068{
Adrian Bunk14aefd12008-07-23 21:31:12 -07004069 void __iomem *rom;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004070 int romptr;
4071
4072 if((readb(rom_base) != 0x55) || (readb(rom_base + 1) != 0xaa))
4073 return 0;
4074
4075 romptr = (readb(rom_base + 0x18) | (readb(rom_base + 0x19) << 8));
4076 if(romptr > (0x10000 - 8))
4077 return 0;
4078
4079 rom = rom_base + romptr;
4080
4081 if((readb(rom) != 'P') || (readb(rom + 1) != 'C') ||
4082 (readb(rom + 2) != 'I') || (readb(rom + 3) != 'R'))
4083 return 0;
4084
4085 if((readb(rom + 4) | (readb(rom + 5) << 8)) != ivideo->chip_vendor)
4086 return 0;
4087
4088 if((readb(rom + 6) | (readb(rom + 7) << 8)) != ivideo->chip_id)
4089 return 0;
4090
4091 return 1;
4092}
4093
4094static unsigned char * __devinit
4095sisfb_find_rom(struct pci_dev *pdev)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004096{
4097 struct sis_video_info *ivideo = pci_get_drvdata(pdev);
Adrian Bunk14aefd12008-07-23 21:31:12 -07004098 void __iomem *rom_base;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004099 unsigned char *myrombase = NULL;
4100 u32 temp;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004101 size_t romsize;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004102
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004103 /* First, try the official pci ROM functions (except
4104 * on integrated chipsets which have no ROM).
4105 */
4106
4107 if(!ivideo->nbridge) {
4108
4109 if((rom_base = pci_map_rom(pdev, &romsize))) {
4110
4111 if(sisfb_check_rom(rom_base, ivideo)) {
4112
4113 if((myrombase = vmalloc(65536))) {
4114
4115 /* Work around bug in pci/rom.c: Folks forgot to check
4116 * whether the size retrieved from the BIOS image eventually
4117 * is larger than the mapped size
4118 */
4119 if(pci_resource_len(pdev, PCI_ROM_RESOURCE) < romsize)
4120 romsize = pci_resource_len(pdev, PCI_ROM_RESOURCE);
4121
4122 memcpy_fromio(myrombase, rom_base,
4123 (romsize > 65536) ? 65536 : romsize);
4124 }
4125 }
4126 pci_unmap_rom(pdev, rom_base);
4127 }
4128 }
4129
4130 if(myrombase) return myrombase;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004131
4132 /* Otherwise do it the conventional way. */
Linus Torvalds1da177e2005-04-16 15:20:36 -07004133
4134#if defined(__i386__) || defined(__x86_64__)
4135
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004136 for(temp = 0x000c0000; temp < 0x000f0000; temp += 0x00001000) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004137
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004138 rom_base = ioremap(temp, 65536);
4139 if(!rom_base)
4140 continue;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004141
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004142 if(!sisfb_check_rom(rom_base, ivideo)) {
4143 iounmap(rom_base);
4144 continue;
4145 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004146
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004147 if((myrombase = vmalloc(65536)))
4148 memcpy_fromio(myrombase, rom_base, 65536);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004149
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004150 iounmap(rom_base);
4151 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004152
Linus Torvalds1da177e2005-04-16 15:20:36 -07004153 }
4154
4155#else
4156
4157 pci_read_config_dword(pdev, PCI_ROM_ADDRESS, &temp);
4158 pci_write_config_dword(pdev, PCI_ROM_ADDRESS,
4159 (ivideo->video_base & PCI_ROM_ADDRESS_MASK) | PCI_ROM_ADDRESS_ENABLE);
4160
4161 rom_base = ioremap(ivideo->video_base, 65536);
4162 if(rom_base) {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004163 if(sisfb_check_rom(rom_base, ivideo)) {
4164 if((myrombase = vmalloc(65536)))
4165 memcpy_fromio(myrombase, rom_base, 65536);
4166 }
4167 iounmap(rom_base);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004168 }
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004169
4170 pci_write_config_dword(pdev, PCI_ROM_ADDRESS, temp);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004171
4172#endif
4173
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004174 return myrombase;
4175}
4176
4177static void __devinit
4178sisfb_post_map_vram(struct sis_video_info *ivideo, unsigned int *mapsize,
4179 unsigned int min)
4180{
4181 ivideo->video_vbase = ioremap(ivideo->video_base, (*mapsize));
4182
4183 if(!ivideo->video_vbase) {
4184 printk(KERN_ERR
4185 "sisfb: Unable to map maximum video RAM for size detection\n");
4186 (*mapsize) >>= 1;
4187 while((!(ivideo->video_vbase = ioremap(ivideo->video_base, (*mapsize))))) {
4188 (*mapsize) >>= 1;
4189 if((*mapsize) < (min << 20))
4190 break;
4191 }
4192 if(ivideo->video_vbase) {
4193 printk(KERN_ERR
4194 "sisfb: Video RAM size detection limited to %dMB\n",
4195 (int)((*mapsize) >> 20));
4196 }
4197 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004198}
4199
4200#ifdef CONFIG_FB_SIS_300
4201static int __devinit
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004202sisfb_post_300_buswidth(struct sis_video_info *ivideo)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004203{
Adrian Bunk14aefd12008-07-23 21:31:12 -07004204 void __iomem *FBAddress = ivideo->video_vbase;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004205 unsigned short temp;
4206 unsigned char reg;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004207 int i, j;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004208
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004209 andSISIDXREG(SISSR, 0x15, 0xFB);
4210 orSISIDXREG(SISSR, 0x15, 0x04);
4211 outSISIDXREG(SISSR, 0x13, 0x00);
4212 outSISIDXREG(SISSR, 0x14, 0xBF);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004213
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004214 for(i = 0; i < 2; i++) {
4215 temp = 0x1234;
4216 for(j = 0; j < 4; j++) {
4217 writew(temp, FBAddress);
4218 if(readw(FBAddress) == temp)
4219 break;
4220 orSISIDXREG(SISSR, 0x3c, 0x01);
4221 inSISIDXREG(SISSR, 0x05, reg);
4222 inSISIDXREG(SISSR, 0x05, reg);
4223 andSISIDXREG(SISSR, 0x3c, 0xfe);
4224 inSISIDXREG(SISSR, 0x05, reg);
4225 inSISIDXREG(SISSR, 0x05, reg);
4226 temp++;
4227 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004228 }
4229
4230 writel(0x01234567L, FBAddress);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004231 writel(0x456789ABL, (FBAddress + 4));
4232 writel(0x89ABCDEFL, (FBAddress + 8));
4233 writel(0xCDEF0123L, (FBAddress + 12));
4234
4235 inSISIDXREG(SISSR, 0x3b, reg);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004236 if(reg & 0x01) {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004237 if(readl((FBAddress + 12)) == 0xCDEF0123L)
4238 return 4; /* Channel A 128bit */
Linus Torvalds1da177e2005-04-16 15:20:36 -07004239 }
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004240
4241 if(readl((FBAddress + 4)) == 0x456789ABL)
4242 return 2; /* Channel B 64bit */
4243
4244 return 1; /* 32bit */
4245}
4246
4247static int __devinit
4248sisfb_post_300_rwtest(struct sis_video_info *ivideo, int iteration, int buswidth,
4249 int PseudoRankCapacity, int PseudoAdrPinCount,
4250 unsigned int mapsize)
4251{
Adrian Bunk14aefd12008-07-23 21:31:12 -07004252 void __iomem *FBAddr = ivideo->video_vbase;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004253 unsigned short sr14;
4254 unsigned int k, RankCapacity, PageCapacity, BankNumHigh, BankNumMid;
4255 unsigned int PhysicalAdrOtherPage, PhysicalAdrHigh, PhysicalAdrHalfPage;
4256 static const unsigned short SiS_DRAMType[17][5] = {
4257 {0x0C,0x0A,0x02,0x40,0x39},
4258 {0x0D,0x0A,0x01,0x40,0x48},
4259 {0x0C,0x09,0x02,0x20,0x35},
4260 {0x0D,0x09,0x01,0x20,0x44},
4261 {0x0C,0x08,0x02,0x10,0x31},
4262 {0x0D,0x08,0x01,0x10,0x40},
4263 {0x0C,0x0A,0x01,0x20,0x34},
4264 {0x0C,0x09,0x01,0x08,0x32},
4265 {0x0B,0x08,0x02,0x08,0x21},
4266 {0x0C,0x08,0x01,0x08,0x30},
4267 {0x0A,0x08,0x02,0x04,0x11},
4268 {0x0B,0x0A,0x01,0x10,0x28},
4269 {0x09,0x08,0x02,0x02,0x01},
4270 {0x0B,0x09,0x01,0x08,0x24},
4271 {0x0B,0x08,0x01,0x04,0x20},
4272 {0x0A,0x08,0x01,0x02,0x10},
4273 {0x09,0x08,0x01,0x01,0x00}
4274 };
4275
4276 for(k = 0; k <= 16; k++) {
4277
4278 RankCapacity = buswidth * SiS_DRAMType[k][3];
4279
4280 if(RankCapacity != PseudoRankCapacity)
4281 continue;
4282
4283 if((SiS_DRAMType[k][2] + SiS_DRAMType[k][0]) > PseudoAdrPinCount)
4284 continue;
4285
4286 BankNumHigh = RankCapacity * 16 * iteration - 1;
4287 if(iteration == 3) { /* Rank No */
4288 BankNumMid = RankCapacity * 16 - 1;
4289 } else {
4290 BankNumMid = RankCapacity * 16 * iteration / 2 - 1;
4291 }
4292
4293 PageCapacity = (1 << SiS_DRAMType[k][1]) * buswidth * 4;
4294 PhysicalAdrHigh = BankNumHigh;
4295 PhysicalAdrHalfPage = (PageCapacity / 2 + PhysicalAdrHigh) % PageCapacity;
4296 PhysicalAdrOtherPage = PageCapacity * SiS_DRAMType[k][2] + PhysicalAdrHigh;
4297
4298 andSISIDXREG(SISSR, 0x15, 0xFB); /* Test */
4299 orSISIDXREG(SISSR, 0x15, 0x04); /* Test */
4300 sr14 = (SiS_DRAMType[k][3] * buswidth) - 1;
4301 if(buswidth == 4) sr14 |= 0x80;
4302 else if(buswidth == 2) sr14 |= 0x40;
4303 outSISIDXREG(SISSR, 0x13, SiS_DRAMType[k][4]);
4304 outSISIDXREG(SISSR, 0x14, sr14);
4305
4306 BankNumHigh <<= 16;
4307 BankNumMid <<= 16;
4308
4309 if((BankNumHigh + PhysicalAdrHigh >= mapsize) ||
4310 (BankNumMid + PhysicalAdrHigh >= mapsize) ||
4311 (BankNumHigh + PhysicalAdrHalfPage >= mapsize) ||
4312 (BankNumHigh + PhysicalAdrOtherPage >= mapsize))
4313 continue;
4314
4315 /* Write data */
4316 writew(((unsigned short)PhysicalAdrHigh),
4317 (FBAddr + BankNumHigh + PhysicalAdrHigh));
4318 writew(((unsigned short)BankNumMid),
4319 (FBAddr + BankNumMid + PhysicalAdrHigh));
4320 writew(((unsigned short)PhysicalAdrHalfPage),
4321 (FBAddr + BankNumHigh + PhysicalAdrHalfPage));
4322 writew(((unsigned short)PhysicalAdrOtherPage),
4323 (FBAddr + BankNumHigh + PhysicalAdrOtherPage));
4324
4325 /* Read data */
4326 if(readw(FBAddr + BankNumHigh + PhysicalAdrHigh) == PhysicalAdrHigh)
4327 return 1;
4328 }
4329
4330 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004331}
4332
4333static void __devinit
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004334sisfb_post_300_ramsize(struct pci_dev *pdev, unsigned int mapsize)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004335{
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004336 struct sis_video_info *ivideo = pci_get_drvdata(pdev);
4337 int i, j, buswidth;
4338 int PseudoRankCapacity, PseudoAdrPinCount;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004339
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004340 buswidth = sisfb_post_300_buswidth(ivideo);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004341
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004342 for(i = 6; i >= 0; i--) {
4343 PseudoRankCapacity = 1 << i;
4344 for(j = 4; j >= 1; j--) {
4345 PseudoAdrPinCount = 15 - j;
4346 if((PseudoRankCapacity * j) <= 64) {
4347 if(sisfb_post_300_rwtest(ivideo,
4348 j,
4349 buswidth,
4350 PseudoRankCapacity,
4351 PseudoAdrPinCount,
4352 mapsize))
4353 return;
4354 }
4355 }
4356 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004357}
4358
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004359static void __devinit
4360sisfb_post_sis300(struct pci_dev *pdev)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004361{
4362 struct sis_video_info *ivideo = pci_get_drvdata(pdev);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004363 unsigned char *bios = ivideo->SiS_Pr.VirtualRomBase;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004364 u8 reg, v1, v2, v3, v4, v5, v6, v7, v8;
4365 u16 index, rindex, memtype = 0;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004366 unsigned int mapsize;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004367
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004368 if(!ivideo->SiS_Pr.UseROM)
4369 bios = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004370
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004371 outSISIDXREG(SISSR, 0x05, 0x86);
4372
4373 if(bios) {
4374 if(bios[0x52] & 0x80) {
4375 memtype = bios[0x52];
4376 } else {
4377 inSISIDXREG(SISSR, 0x3a, memtype);
4378 }
4379 memtype &= 0x07;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004380 }
4381
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004382 v3 = 0x80; v6 = 0x80;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004383 if(ivideo->revision_id <= 0x13) {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004384 v1 = 0x44; v2 = 0x42;
4385 v4 = 0x44; v5 = 0x42;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004386 } else {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004387 v1 = 0x68; v2 = 0x43; /* Assume 125Mhz MCLK */
4388 v4 = 0x68; v5 = 0x43; /* Assume 125Mhz ECLK */
4389 if(bios) {
4390 index = memtype * 5;
4391 rindex = index + 0x54;
4392 v1 = bios[rindex++];
4393 v2 = bios[rindex++];
4394 v3 = bios[rindex++];
4395 rindex = index + 0x7c;
4396 v4 = bios[rindex++];
4397 v5 = bios[rindex++];
4398 v6 = bios[rindex++];
4399 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004400 }
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004401 outSISIDXREG(SISSR, 0x28, v1);
4402 outSISIDXREG(SISSR, 0x29, v2);
4403 outSISIDXREG(SISSR, 0x2a, v3);
4404 outSISIDXREG(SISSR, 0x2e, v4);
4405 outSISIDXREG(SISSR, 0x2f, v5);
4406 outSISIDXREG(SISSR, 0x30, v6);
4407
Linus Torvalds1da177e2005-04-16 15:20:36 -07004408 v1 = 0x10;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004409 if(bios)
4410 v1 = bios[0xa4];
4411 outSISIDXREG(SISSR, 0x07, v1); /* DAC speed */
4412
4413 outSISIDXREG(SISSR, 0x11, 0x0f); /* DDC, power save */
4414
Linus Torvalds1da177e2005-04-16 15:20:36 -07004415 v1 = 0x01; v2 = 0x43; v3 = 0x1e; v4 = 0x2a;
4416 v5 = 0x06; v6 = 0x00; v7 = 0x00; v8 = 0x00;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004417 if(bios) {
4418 memtype += 0xa5;
4419 v1 = bios[memtype];
4420 v2 = bios[memtype + 8];
4421 v3 = bios[memtype + 16];
4422 v4 = bios[memtype + 24];
4423 v5 = bios[memtype + 32];
4424 v6 = bios[memtype + 40];
4425 v7 = bios[memtype + 48];
4426 v8 = bios[memtype + 56];
Linus Torvalds1da177e2005-04-16 15:20:36 -07004427 }
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004428 if(ivideo->revision_id >= 0x80)
4429 v3 &= 0xfd;
4430 outSISIDXREG(SISSR, 0x15, v1); /* Ram type (assuming 0, BIOS 0xa5 step 8) */
4431 outSISIDXREG(SISSR, 0x16, v2);
4432 outSISIDXREG(SISSR, 0x17, v3);
4433 outSISIDXREG(SISSR, 0x18, v4);
4434 outSISIDXREG(SISSR, 0x19, v5);
4435 outSISIDXREG(SISSR, 0x1a, v6);
4436 outSISIDXREG(SISSR, 0x1b, v7);
4437 outSISIDXREG(SISSR, 0x1c, v8); /* ---- */
4438 andSISIDXREG(SISSR, 0x15 ,0xfb);
4439 orSISIDXREG(SISSR, 0x15, 0x04);
4440 if(bios) {
4441 if(bios[0x53] & 0x02) {
4442 orSISIDXREG(SISSR, 0x19, 0x20);
4443 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004444 }
4445 v1 = 0x04; /* DAC pedestal (BIOS 0xe5) */
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004446 if(ivideo->revision_id >= 0x80)
4447 v1 |= 0x01;
4448 outSISIDXREG(SISSR, 0x1f, v1);
4449 outSISIDXREG(SISSR, 0x20, 0xa4); /* linear & relocated io & disable a0000 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07004450 v1 = 0xf6; v2 = 0x0d; v3 = 0x00;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004451 if(bios) {
4452 v1 = bios[0xe8];
4453 v2 = bios[0xe9];
4454 v3 = bios[0xea];
Linus Torvalds1da177e2005-04-16 15:20:36 -07004455 }
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004456 outSISIDXREG(SISSR, 0x23, v1);
4457 outSISIDXREG(SISSR, 0x24, v2);
4458 outSISIDXREG(SISSR, 0x25, v3);
4459 outSISIDXREG(SISSR, 0x21, 0x84);
4460 outSISIDXREG(SISSR, 0x22, 0x00);
4461 outSISIDXREG(SISCR, 0x37, 0x00);
4462 orSISIDXREG(SISPART1, 0x24, 0x01); /* unlock crt2 */
4463 outSISIDXREG(SISPART1, 0x00, 0x00);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004464 v1 = 0x40; v2 = 0x11;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004465 if(bios) {
4466 v1 = bios[0xec];
4467 v2 = bios[0xeb];
Linus Torvalds1da177e2005-04-16 15:20:36 -07004468 }
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004469 outSISIDXREG(SISPART1, 0x02, v1);
4470
4471 if(ivideo->revision_id >= 0x80)
4472 v2 &= ~0x01;
4473
4474 inSISIDXREG(SISPART4, 0x00, reg);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004475 if((reg == 1) || (reg == 2)) {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004476 outSISIDXREG(SISCR, 0x37, 0x02);
4477 outSISIDXREG(SISPART2, 0x00, 0x1c);
4478 v4 = 0x00; v5 = 0x00; v6 = 0x10;
4479 if(ivideo->SiS_Pr.UseROM) {
4480 v4 = bios[0xf5];
4481 v5 = bios[0xf6];
4482 v6 = bios[0xf7];
4483 }
4484 outSISIDXREG(SISPART4, 0x0d, v4);
4485 outSISIDXREG(SISPART4, 0x0e, v5);
4486 outSISIDXREG(SISPART4, 0x10, v6);
4487 outSISIDXREG(SISPART4, 0x0f, 0x3f);
4488 inSISIDXREG(SISPART4, 0x01, reg);
4489 if(reg >= 0xb0) {
4490 inSISIDXREG(SISPART4, 0x23, reg);
4491 reg &= 0x20;
4492 reg <<= 1;
4493 outSISIDXREG(SISPART4, 0x23, reg);
4494 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004495 } else {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004496 v2 &= ~0x10;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004497 }
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004498 outSISIDXREG(SISSR, 0x32, v2);
4499
4500 andSISIDXREG(SISPART1, 0x24, 0xfe); /* Lock CRT2 */
4501
4502 inSISIDXREG(SISSR, 0x16, reg);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004503 reg &= 0xc3;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004504 outSISIDXREG(SISCR, 0x35, reg);
4505 outSISIDXREG(SISCR, 0x83, 0x00);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004506#if !defined(__i386__) && !defined(__x86_64__)
4507 if(sisfb_videoram) {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004508 outSISIDXREG(SISSR, 0x13, 0x28); /* ? */
4509 reg = ((sisfb_videoram >> 10) - 1) | 0x40;
4510 outSISIDXREG(SISSR, 0x14, reg);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004511 } else {
4512#endif
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004513 /* Need to map max FB size for finding out about RAM size */
4514 mapsize = 64 << 20;
4515 sisfb_post_map_vram(ivideo, &mapsize, 4);
4516
4517 if(ivideo->video_vbase) {
4518 sisfb_post_300_ramsize(pdev, mapsize);
4519 iounmap(ivideo->video_vbase);
4520 } else {
4521 printk(KERN_DEBUG
4522 "sisfb: Failed to map memory for size detection, assuming 8MB\n");
4523 outSISIDXREG(SISSR, 0x13, 0x28); /* ? */
4524 outSISIDXREG(SISSR, 0x14, 0x47); /* 8MB, 64bit default */
4525 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004526#if !defined(__i386__) && !defined(__x86_64__)
4527 }
4528#endif
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004529 if(bios) {
4530 v1 = bios[0xe6];
4531 v2 = bios[0xe7];
Linus Torvalds1da177e2005-04-16 15:20:36 -07004532 } else {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004533 inSISIDXREG(SISSR, 0x3a, reg);
4534 if((reg & 0x30) == 0x30) {
4535 v1 = 0x04; /* PCI */
4536 v2 = 0x92;
4537 } else {
4538 v1 = 0x14; /* AGP */
4539 v2 = 0xb2;
4540 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004541 }
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004542 outSISIDXREG(SISSR, 0x21, v1);
4543 outSISIDXREG(SISSR, 0x22, v2);
4544
4545 /* Sense CRT1 */
4546 sisfb_sense_crt1(ivideo);
4547
4548 /* Set default mode, don't clear screen */
Richard Knutssonc30660ea2007-02-12 00:55:06 -08004549 ivideo->SiS_Pr.SiS_UseOEM = false;
4550 SiS_SetEnableDstn(&ivideo->SiS_Pr, false);
4551 SiS_SetEnableFstn(&ivideo->SiS_Pr, false);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004552 ivideo->curFSTN = ivideo->curDSTN = 0;
4553 ivideo->SiS_Pr.VideoMemorySize = 8 << 20;
4554 SiSSetMode(&ivideo->SiS_Pr, 0x2e | 0x80);
4555
4556 outSISIDXREG(SISSR, 0x05, 0x86);
4557
4558 /* Display off */
4559 orSISIDXREG(SISSR, 0x01, 0x20);
4560
4561 /* Save mode number in CR34 */
4562 outSISIDXREG(SISCR, 0x34, 0x2e);
4563
4564 /* Let everyone know what the current mode is */
4565 ivideo->modeprechange = 0x2e;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004566}
4567#endif
4568
4569#ifdef CONFIG_FB_SIS_315
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004570#if 0
4571static void __devinit
4572sisfb_post_sis315330(struct pci_dev *pdev)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004573{
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004574 /* TODO */
Linus Torvalds1da177e2005-04-16 15:20:36 -07004575}
4576#endif
4577
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004578static void __devinit
4579sisfb_post_xgi_delay(struct sis_video_info *ivideo, int delay)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004580{
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004581 unsigned int i;
4582 u8 reg;
4583
4584 for(i = 0; i <= (delay * 10 * 36); i++) {
4585 inSISIDXREG(SISSR, 0x05, reg);
4586 reg++;
4587 }
4588}
4589
4590static int __devinit
4591sisfb_find_host_bridge(struct sis_video_info *ivideo, struct pci_dev *mypdev,
4592 unsigned short pcivendor)
4593{
4594 struct pci_dev *pdev = NULL;
4595 unsigned short temp;
4596 int ret = 0;
4597
Adrian Bunk0959f0c2007-05-08 00:39:50 -07004598 while((pdev = pci_get_class(PCI_CLASS_BRIDGE_HOST, pdev))) {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004599 temp = pdev->vendor;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004600 if(temp == pcivendor) {
4601 ret = 1;
Julia Lawallea237a62008-02-06 01:39:07 -08004602 pci_dev_put(pdev);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004603 break;
4604 }
4605 }
4606
4607 return ret;
4608}
4609
4610static int __devinit
4611sisfb_post_xgi_rwtest(struct sis_video_info *ivideo, int starta,
4612 unsigned int enda, unsigned int mapsize)
4613{
4614 unsigned int pos;
4615 int i;
4616
4617 writel(0, ivideo->video_vbase);
4618
4619 for(i = starta; i <= enda; i++) {
4620 pos = 1 << i;
4621 if(pos < mapsize)
4622 writel(pos, ivideo->video_vbase + pos);
4623 }
4624
4625 sisfb_post_xgi_delay(ivideo, 150);
4626
4627 if(readl(ivideo->video_vbase) != 0)
4628 return 0;
4629
4630 for(i = starta; i <= enda; i++) {
4631 pos = 1 << i;
4632 if(pos < mapsize) {
4633 if(readl(ivideo->video_vbase + pos) != pos)
4634 return 0;
4635 } else
4636 return 0;
4637 }
4638
4639 return 1;
4640}
4641
4642static void __devinit
4643sisfb_post_xgi_ramsize(struct sis_video_info *ivideo)
4644{
4645 unsigned int buswidth, ranksize, channelab, mapsize;
4646 int i, j, k, l;
4647 u8 reg, sr14;
4648 static const u8 dramsr13[12 * 5] = {
4649 0x02, 0x0e, 0x0b, 0x80, 0x5d,
4650 0x02, 0x0e, 0x0a, 0x40, 0x59,
4651 0x02, 0x0d, 0x0b, 0x40, 0x4d,
4652 0x02, 0x0e, 0x09, 0x20, 0x55,
4653 0x02, 0x0d, 0x0a, 0x20, 0x49,
4654 0x02, 0x0c, 0x0b, 0x20, 0x3d,
4655 0x02, 0x0e, 0x08, 0x10, 0x51,
4656 0x02, 0x0d, 0x09, 0x10, 0x45,
4657 0x02, 0x0c, 0x0a, 0x10, 0x39,
4658 0x02, 0x0d, 0x08, 0x08, 0x41,
4659 0x02, 0x0c, 0x09, 0x08, 0x35,
4660 0x02, 0x0c, 0x08, 0x04, 0x31
4661 };
4662 static const u8 dramsr13_4[4 * 5] = {
4663 0x02, 0x0d, 0x09, 0x40, 0x45,
4664 0x02, 0x0c, 0x09, 0x20, 0x35,
4665 0x02, 0x0c, 0x08, 0x10, 0x31,
4666 0x02, 0x0b, 0x08, 0x08, 0x21
4667 };
4668
4669 /* Enable linear mode, disable 0xa0000 address decoding */
4670 /* We disable a0000 address decoding, because
4671 * - if running on x86, if the card is disabled, it means
4672 * that another card is in the system. We don't want
4673 * to interphere with that primary card's textmode.
4674 * - if running on non-x86, there usually is no VGA window
4675 * at a0000.
4676 */
4677 orSISIDXREG(SISSR, 0x20, (0x80 | 0x04));
4678
4679 /* Need to map max FB size for finding out about RAM size */
4680 mapsize = 256 << 20;
4681 sisfb_post_map_vram(ivideo, &mapsize, 32);
4682
4683 if(!ivideo->video_vbase) {
4684 printk(KERN_ERR "sisfb: Unable to detect RAM size. Setting default.\n");
4685 outSISIDXREG(SISSR, 0x13, 0x35);
4686 outSISIDXREG(SISSR, 0x14, 0x41);
4687 /* TODO */
4688 return;
4689 }
4690
4691 /* Non-interleaving */
4692 outSISIDXREG(SISSR, 0x15, 0x00);
4693 /* No tiling */
4694 outSISIDXREG(SISSR, 0x1c, 0x00);
4695
4696 if(ivideo->chip == XGI_20) {
4697
4698 channelab = 1;
4699 inSISIDXREG(SISCR, 0x97, reg);
4700 if(!(reg & 0x01)) { /* Single 32/16 */
4701 buswidth = 32;
4702 outSISIDXREG(SISSR, 0x13, 0xb1);
4703 outSISIDXREG(SISSR, 0x14, 0x52);
4704 sisfb_post_xgi_delay(ivideo, 1);
4705 sr14 = 0x02;
4706 if(sisfb_post_xgi_rwtest(ivideo, 23, 24, mapsize))
4707 goto bail_out;
4708
4709 outSISIDXREG(SISSR, 0x13, 0x31);
4710 outSISIDXREG(SISSR, 0x14, 0x42);
4711 sisfb_post_xgi_delay(ivideo, 1);
4712 if(sisfb_post_xgi_rwtest(ivideo, 23, 23, mapsize))
4713 goto bail_out;
4714
4715 buswidth = 16;
4716 outSISIDXREG(SISSR, 0x13, 0xb1);
4717 outSISIDXREG(SISSR, 0x14, 0x41);
4718 sisfb_post_xgi_delay(ivideo, 1);
4719 sr14 = 0x01;
4720 if(sisfb_post_xgi_rwtest(ivideo, 22, 23, mapsize))
4721 goto bail_out;
4722 else
4723 outSISIDXREG(SISSR, 0x13, 0x31);
4724 } else { /* Dual 16/8 */
4725 buswidth = 16;
4726 outSISIDXREG(SISSR, 0x13, 0xb1);
4727 outSISIDXREG(SISSR, 0x14, 0x41);
4728 sisfb_post_xgi_delay(ivideo, 1);
4729 sr14 = 0x01;
4730 if(sisfb_post_xgi_rwtest(ivideo, 22, 23, mapsize))
4731 goto bail_out;
4732
4733 outSISIDXREG(SISSR, 0x13, 0x31);
4734 outSISIDXREG(SISSR, 0x14, 0x31);
4735 sisfb_post_xgi_delay(ivideo, 1);
4736 if(sisfb_post_xgi_rwtest(ivideo, 22, 22, mapsize))
4737 goto bail_out;
4738
4739 buswidth = 8;
4740 outSISIDXREG(SISSR, 0x13, 0xb1);
4741 outSISIDXREG(SISSR, 0x14, 0x30);
4742 sisfb_post_xgi_delay(ivideo, 1);
4743 sr14 = 0x00;
4744 if(sisfb_post_xgi_rwtest(ivideo, 21, 22, mapsize))
4745 goto bail_out;
4746 else
4747 outSISIDXREG(SISSR, 0x13, 0x31);
4748 }
4749
4750 } else { /* XGI_40 */
4751
4752 inSISIDXREG(SISCR, 0x97, reg);
4753 if(!(reg & 0x10)) {
4754 inSISIDXREG(SISSR, 0x39, reg);
4755 reg >>= 1;
4756 }
4757
4758 if(reg & 0x01) { /* DDRII */
4759 buswidth = 32;
4760 if(ivideo->revision_id == 2) {
4761 channelab = 2;
4762 outSISIDXREG(SISSR, 0x13, 0xa1);
4763 outSISIDXREG(SISSR, 0x14, 0x44);
4764 sr14 = 0x04;
4765 sisfb_post_xgi_delay(ivideo, 1);
4766 if(sisfb_post_xgi_rwtest(ivideo, 23, 24, mapsize))
4767 goto bail_out;
4768
4769 outSISIDXREG(SISSR, 0x13, 0x21);
4770 outSISIDXREG(SISSR, 0x14, 0x34);
4771 if(sisfb_post_xgi_rwtest(ivideo, 22, 23, mapsize))
4772 goto bail_out;
4773
4774 channelab = 1;
4775 outSISIDXREG(SISSR, 0x13, 0xa1);
4776 outSISIDXREG(SISSR, 0x14, 0x40);
4777 sr14 = 0x00;
4778 if(sisfb_post_xgi_rwtest(ivideo, 22, 23, mapsize))
4779 goto bail_out;
4780
4781 outSISIDXREG(SISSR, 0x13, 0x21);
4782 outSISIDXREG(SISSR, 0x14, 0x30);
4783 } else {
4784 channelab = 3;
4785 outSISIDXREG(SISSR, 0x13, 0xa1);
4786 outSISIDXREG(SISSR, 0x14, 0x4c);
4787 sr14 = 0x0c;
4788 sisfb_post_xgi_delay(ivideo, 1);
4789 if(sisfb_post_xgi_rwtest(ivideo, 23, 25, mapsize))
4790 goto bail_out;
4791
4792 channelab = 2;
4793 outSISIDXREG(SISSR, 0x14, 0x48);
4794 sisfb_post_xgi_delay(ivideo, 1);
4795 sr14 = 0x08;
4796 if(sisfb_post_xgi_rwtest(ivideo, 23, 24, mapsize))
4797 goto bail_out;
4798
4799 outSISIDXREG(SISSR, 0x13, 0x21);
4800 outSISIDXREG(SISSR, 0x14, 0x3c);
4801 sr14 = 0x0c;
4802
4803 if(sisfb_post_xgi_rwtest(ivideo, 23, 24, mapsize)) {
4804 channelab = 3;
4805 } else {
4806 channelab = 2;
4807 outSISIDXREG(SISSR, 0x14, 0x38);
4808 sr14 = 0x08;
4809 }
4810 }
4811 sisfb_post_xgi_delay(ivideo, 1);
4812
4813 } else { /* DDR */
4814
4815 buswidth = 64;
4816 if(ivideo->revision_id == 2) {
4817 channelab = 1;
4818 outSISIDXREG(SISSR, 0x13, 0xa1);
4819 outSISIDXREG(SISSR, 0x14, 0x52);
4820 sisfb_post_xgi_delay(ivideo, 1);
4821 sr14 = 0x02;
4822 if(sisfb_post_xgi_rwtest(ivideo, 23, 24, mapsize))
4823 goto bail_out;
4824
4825 outSISIDXREG(SISSR, 0x13, 0x21);
4826 outSISIDXREG(SISSR, 0x14, 0x42);
4827 } else {
4828 channelab = 2;
4829 outSISIDXREG(SISSR, 0x13, 0xa1);
4830 outSISIDXREG(SISSR, 0x14, 0x5a);
4831 sisfb_post_xgi_delay(ivideo, 1);
4832 sr14 = 0x0a;
4833 if(sisfb_post_xgi_rwtest(ivideo, 24, 25, mapsize))
4834 goto bail_out;
4835
4836 outSISIDXREG(SISSR, 0x13, 0x21);
4837 outSISIDXREG(SISSR, 0x14, 0x4a);
4838 }
4839 sisfb_post_xgi_delay(ivideo, 1);
4840
4841 }
4842 }
4843
4844bail_out:
4845 setSISIDXREG(SISSR, 0x14, 0xf0, sr14);
4846 sisfb_post_xgi_delay(ivideo, 1);
4847
4848 j = (ivideo->chip == XGI_20) ? 5 : 9;
4849 k = (ivideo->chip == XGI_20) ? 12 : 4;
4850
4851 for(i = 0; i < k; i++) {
4852
4853 reg = (ivideo->chip == XGI_20) ?
4854 dramsr13[(i * 5) + 4] : dramsr13_4[(i * 5) + 4];
4855 setSISIDXREG(SISSR, 0x13, 0x80, reg);
4856 sisfb_post_xgi_delay(ivideo, 50);
4857
4858 ranksize = (ivideo->chip == XGI_20) ?
4859 dramsr13[(i * 5) + 3] : dramsr13_4[(i * 5) + 3];
4860
4861 inSISIDXREG(SISSR, 0x13, reg);
4862 if(reg & 0x80) ranksize <<= 1;
4863
4864 if(ivideo->chip == XGI_20) {
4865 if(buswidth == 16) ranksize <<= 1;
4866 else if(buswidth == 32) ranksize <<= 2;
4867 } else {
4868 if(buswidth == 64) ranksize <<= 1;
4869 }
4870
4871 reg = 0;
4872 l = channelab;
4873 if(l == 3) l = 4;
4874 if((ranksize * l) <= 256) {
4875 while((ranksize >>= 1)) reg += 0x10;
4876 }
4877
4878 if(!reg) continue;
4879
4880 setSISIDXREG(SISSR, 0x14, 0x0f, (reg & 0xf0));
4881 sisfb_post_xgi_delay(ivideo, 1);
4882
4883 if(sisfb_post_xgi_rwtest(ivideo, j, ((reg >> 4) + channelab - 2 + 20), mapsize))
4884 break;
4885 }
4886
4887 iounmap(ivideo->video_vbase);
4888}
4889
4890static void __devinit
4891sisfb_post_xgi_setclocks(struct sis_video_info *ivideo, u8 regb)
4892{
4893 u8 v1, v2, v3;
4894 int index;
4895 static const u8 cs90[8 * 3] = {
4896 0x16, 0x01, 0x01,
4897 0x3e, 0x03, 0x01,
4898 0x7c, 0x08, 0x01,
4899 0x79, 0x06, 0x01,
4900 0x29, 0x01, 0x81,
4901 0x5c, 0x23, 0x01,
4902 0x5c, 0x23, 0x01,
4903 0x5c, 0x23, 0x01
4904 };
4905 static const u8 csb8[8 * 3] = {
4906 0x5c, 0x23, 0x01,
4907 0x29, 0x01, 0x01,
4908 0x7c, 0x08, 0x01,
4909 0x79, 0x06, 0x01,
4910 0x29, 0x01, 0x81,
4911 0x5c, 0x23, 0x01,
4912 0x5c, 0x23, 0x01,
4913 0x5c, 0x23, 0x01
4914 };
4915
4916 regb = 0; /* ! */
4917
4918 index = regb * 3;
4919 v1 = cs90[index]; v2 = cs90[index + 1]; v3 = cs90[index + 2];
4920 if(ivideo->haveXGIROM) {
4921 v1 = ivideo->bios_abase[0x90 + index];
4922 v2 = ivideo->bios_abase[0x90 + index + 1];
4923 v3 = ivideo->bios_abase[0x90 + index + 2];
4924 }
4925 outSISIDXREG(SISSR, 0x28, v1);
4926 outSISIDXREG(SISSR, 0x29, v2);
4927 outSISIDXREG(SISSR, 0x2a, v3);
4928 sisfb_post_xgi_delay(ivideo, 0x43);
4929 sisfb_post_xgi_delay(ivideo, 0x43);
4930 sisfb_post_xgi_delay(ivideo, 0x43);
4931 index = regb * 3;
4932 v1 = csb8[index]; v2 = csb8[index + 1]; v3 = csb8[index + 2];
4933 if(ivideo->haveXGIROM) {
4934 v1 = ivideo->bios_abase[0xb8 + index];
4935 v2 = ivideo->bios_abase[0xb8 + index + 1];
4936 v3 = ivideo->bios_abase[0xb8 + index + 2];
4937 }
4938 outSISIDXREG(SISSR, 0x2e, v1);
4939 outSISIDXREG(SISSR, 0x2f, v2);
4940 outSISIDXREG(SISSR, 0x30, v3);
4941 sisfb_post_xgi_delay(ivideo, 0x43);
4942 sisfb_post_xgi_delay(ivideo, 0x43);
4943 sisfb_post_xgi_delay(ivideo, 0x43);
4944}
4945
4946static int __devinit
4947sisfb_post_xgi(struct pci_dev *pdev)
4948{
4949 struct sis_video_info *ivideo = pci_get_drvdata(pdev);
4950 unsigned char *bios = ivideo->bios_abase;
4951 struct pci_dev *mypdev = NULL;
4952 const u8 *ptr, *ptr2;
4953 u8 v1, v2, v3, v4, v5, reg, ramtype;
4954 u32 rega, regb, regd;
4955 int i, j, k, index;
4956 static const u8 cs78[3] = { 0xf6, 0x0d, 0x00 };
4957 static const u8 cs76[2] = { 0xa3, 0xfb };
4958 static const u8 cs7b[3] = { 0xc0, 0x11, 0x00 };
4959 static const u8 cs158[8] = {
4960 0x88, 0xaa, 0x48, 0x00, 0x00, 0x00, 0x00, 0x00
4961 };
4962 static const u8 cs160[8] = {
4963 0x44, 0x77, 0x77, 0x00, 0x00, 0x00, 0x00, 0x00
4964 };
4965 static const u8 cs168[8] = {
4966 0x48, 0x78, 0x88, 0x00, 0x00, 0x00, 0x00, 0x00
4967 };
4968 static const u8 cs128[3 * 8] = {
4969 0x90, 0x28, 0x24, 0x00, 0x00, 0x00, 0x00, 0x00,
4970 0x77, 0x44, 0x44, 0x00, 0x00, 0x00, 0x00, 0x00,
4971 0x77, 0x44, 0x44, 0x00, 0x00, 0x00, 0x00, 0x00
4972 };
4973 static const u8 cs148[2 * 8] = {
4974 0x55, 0x55, 0x55, 0x00, 0x00, 0x00, 0x00, 0x00,
4975 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
4976 };
4977 static const u8 cs31a[8 * 4] = {
4978 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
4979 0xaa, 0xaa, 0xaa, 0xaa, 0x00, 0x00, 0x00, 0x00,
4980 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
4981 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
4982 };
4983 static const u8 cs33a[8 * 4] = {
4984 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
4985 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
4986 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
4987 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
4988 };
4989 static const u8 cs45a[8 * 2] = {
4990 0x00, 0x00, 0xa0, 0x00, 0xa0, 0x00, 0x00, 0x00,
4991 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
4992 };
4993 static const u8 cs170[7 * 8] = {
4994 0x54, 0x32, 0x44, 0x00, 0x00, 0x00, 0x00, 0x00,
4995 0x54, 0x43, 0x44, 0x00, 0x00, 0x00, 0x00, 0x00,
4996 0x0a, 0x05, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00,
4997 0x44, 0x34, 0x44, 0x00, 0x00, 0x00, 0x00, 0x00,
4998 0x10, 0x0a, 0x0a, 0x00, 0x00, 0x00, 0x00, 0x00,
4999 0x11, 0x0c, 0x0c, 0x00, 0x00, 0x00, 0x00, 0x00,
5000 0x05, 0x05, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00
5001 };
5002 static const u8 cs1a8[3 * 8] = {
5003 0xf0, 0xf0, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x00,
5004 0x05, 0x02, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00,
5005 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
5006 };
5007 static const u8 cs100[2 * 8] = {
5008 0xc4, 0x04, 0x84, 0x00, 0x00, 0x00, 0x00, 0x00,
5009 0xc4, 0x04, 0x84, 0x00, 0x00, 0x00, 0x00, 0x00
5010 };
5011
5012 /* VGA enable */
5013 reg = inSISREG(SISVGAENABLE) | 0x01;
5014 outSISREG(SISVGAENABLE, reg);
5015
5016 /* Misc */
5017 reg = inSISREG(SISMISCR) | 0x01;
5018 outSISREG(SISMISCW, reg);
5019
5020 /* Unlock SR */
5021 outSISIDXREG(SISSR, 0x05, 0x86);
5022 inSISIDXREG(SISSR, 0x05, reg);
5023 if(reg != 0xa1)
5024 return 0;
5025
5026 /* Clear some regs */
5027 for(i = 0; i < 0x22; i++) {
5028 if(0x06 + i == 0x20) continue;
5029 outSISIDXREG(SISSR, 0x06 + i, 0x00);
5030 }
5031 for(i = 0; i < 0x0b; i++) {
5032 outSISIDXREG(SISSR, 0x31 + i, 0x00);
5033 }
5034 for(i = 0; i < 0x10; i++) {
5035 outSISIDXREG(SISCR, 0x30 + i, 0x00);
5036 }
5037
5038 ptr = cs78;
5039 if(ivideo->haveXGIROM) {
5040 ptr = (const u8 *)&bios[0x78];
5041 }
5042 for(i = 0; i < 3; i++) {
5043 outSISIDXREG(SISSR, 0x23 + i, ptr[i]);
5044 }
5045
5046 ptr = cs76;
5047 if(ivideo->haveXGIROM) {
5048 ptr = (const u8 *)&bios[0x76];
5049 }
5050 for(i = 0; i < 2; i++) {
5051 outSISIDXREG(SISSR, 0x21 + i, ptr[i]);
5052 }
5053
5054 v1 = 0x18; v2 = 0x00;
5055 if(ivideo->haveXGIROM) {
5056 v1 = bios[0x74];
5057 v2 = bios[0x75];
5058 }
5059 outSISIDXREG(SISSR, 0x07, v1);
5060 outSISIDXREG(SISSR, 0x11, 0x0f);
5061 outSISIDXREG(SISSR, 0x1f, v2);
5062 /* PCI linear mode, RelIO enabled, A0000 decoding disabled */
5063 outSISIDXREG(SISSR, 0x20, 0x80 | 0x20 | 0x04);
5064 outSISIDXREG(SISSR, 0x27, 0x74);
5065
5066 ptr = cs7b;
5067 if(ivideo->haveXGIROM) {
5068 ptr = (const u8 *)&bios[0x7b];
5069 }
5070 for(i = 0; i < 3; i++) {
5071 outSISIDXREG(SISSR, 0x31 + i, ptr[i]);
5072 }
5073
5074 if(ivideo->chip == XGI_40) {
5075 if(ivideo->revision_id == 2) {
5076 setSISIDXREG(SISSR, 0x3b, 0x3f, 0xc0);
5077 }
5078 outSISIDXREG(SISCR, 0x7d, 0xfe);
5079 outSISIDXREG(SISCR, 0x7e, 0x0f);
5080 }
5081 if(ivideo->revision_id == 0) { /* 40 *and* 20? */
5082 andSISIDXREG(SISCR, 0x58, 0xd7);
5083 inSISIDXREG(SISCR, 0xcb, reg);
5084 if(reg & 0x20) {
5085 setSISIDXREG(SISCR, 0x58, 0xd7, (reg & 0x10) ? 0x08 : 0x20); /* =0x28 Z7 ? */
5086 }
5087 }
5088
5089 reg = (ivideo->chip == XGI_40) ? 0x20 : 0x00;
5090 setSISIDXREG(SISCR, 0x38, 0x1f, reg);
5091
5092 if(ivideo->chip == XGI_20) {
5093 outSISIDXREG(SISSR, 0x36, 0x70);
5094 } else {
5095 outSISIDXREG(SISVID, 0x00, 0x86);
5096 outSISIDXREG(SISVID, 0x32, 0x00);
5097 outSISIDXREG(SISVID, 0x30, 0x00);
5098 outSISIDXREG(SISVID, 0x32, 0x01);
5099 outSISIDXREG(SISVID, 0x30, 0x00);
5100 andSISIDXREG(SISVID, 0x2f, 0xdf);
5101 andSISIDXREG(SISCAP, 0x00, 0x3f);
5102
5103 outSISIDXREG(SISPART1, 0x2f, 0x01);
5104 outSISIDXREG(SISPART1, 0x00, 0x00);
5105 outSISIDXREG(SISPART1, 0x02, bios[0x7e]);
5106 outSISIDXREG(SISPART1, 0x2e, 0x08);
5107 andSISIDXREG(SISPART1, 0x35, 0x7f);
5108 andSISIDXREG(SISPART1, 0x50, 0xfe);
5109
5110 inSISIDXREG(SISPART4, 0x00, reg);
5111 if(reg == 1 || reg == 2) {
5112 outSISIDXREG(SISPART2, 0x00, 0x1c);
5113 outSISIDXREG(SISPART4, 0x0d, bios[0x7f]);
5114 outSISIDXREG(SISPART4, 0x0e, bios[0x80]);
5115 outSISIDXREG(SISPART4, 0x10, bios[0x81]);
5116 andSISIDXREG(SISPART4, 0x0f, 0x3f);
5117
5118 inSISIDXREG(SISPART4, 0x01, reg);
5119 if((reg & 0xf0) >= 0xb0) {
5120 inSISIDXREG(SISPART4, 0x23, reg);
5121 if(reg & 0x20) reg |= 0x40;
5122 outSISIDXREG(SISPART4, 0x23, reg);
5123 reg = (reg & 0x20) ? 0x02 : 0x00;
5124 setSISIDXREG(SISPART1, 0x1e, 0xfd, reg);
5125 }
5126 }
5127
5128 v1 = bios[0x77];
5129
5130 inSISIDXREG(SISSR, 0x3b, reg);
5131 if(reg & 0x02) {
5132 inSISIDXREG(SISSR, 0x3a, reg);
5133 v2 = (reg & 0x30) >> 3;
5134 if(!(v2 & 0x04)) v2 ^= 0x02;
5135 inSISIDXREG(SISSR, 0x39, reg);
5136 if(reg & 0x80) v2 |= 0x80;
5137 v2 |= 0x01;
5138
Adrian Bunk0959f0c2007-05-08 00:39:50 -07005139 if((mypdev = pci_get_device(PCI_VENDOR_ID_SI, 0x0730, NULL))) {
5140 pci_dev_put(mypdev);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07005141 if(((v2 & 0x06) == 2) || ((v2 & 0x06) == 4))
5142 v2 &= 0xf9;
5143 v2 |= 0x08;
5144 v1 &= 0xfe;
5145 } else {
Adrian Bunk0959f0c2007-05-08 00:39:50 -07005146 mypdev = pci_get_device(PCI_VENDOR_ID_SI, 0x0735, NULL);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07005147 if(!mypdev)
Adrian Bunk0959f0c2007-05-08 00:39:50 -07005148 mypdev = pci_get_device(PCI_VENDOR_ID_SI, 0x0645, NULL);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07005149 if(!mypdev)
Adrian Bunk0959f0c2007-05-08 00:39:50 -07005150 mypdev = pci_get_device(PCI_VENDOR_ID_SI, 0x0650, NULL);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07005151 if(mypdev) {
5152 pci_read_config_dword(mypdev, 0x94, &regd);
5153 regd &= 0xfffffeff;
5154 pci_write_config_dword(mypdev, 0x94, regd);
5155 v1 &= 0xfe;
Adrian Bunk0959f0c2007-05-08 00:39:50 -07005156 pci_dev_put(mypdev);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07005157 } else if(sisfb_find_host_bridge(ivideo, pdev, PCI_VENDOR_ID_SI)) {
5158 v1 &= 0xfe;
5159 } else if(sisfb_find_host_bridge(ivideo, pdev, 0x1106) ||
5160 sisfb_find_host_bridge(ivideo, pdev, 0x1022) ||
5161 sisfb_find_host_bridge(ivideo, pdev, 0x700e) ||
5162 sisfb_find_host_bridge(ivideo, pdev, 0x10de)) {
5163 if((v2 & 0x06) == 4)
5164 v2 ^= 0x06;
5165 v2 |= 0x08;
5166 }
5167 }
5168 setSISIDXREG(SISCR, 0x5f, 0xf0, v2);
5169 }
5170 outSISIDXREG(SISSR, 0x22, v1);
5171
5172 if(ivideo->revision_id == 2) {
5173 inSISIDXREG(SISSR, 0x3b, v1);
5174 inSISIDXREG(SISSR, 0x3a, v2);
5175 regd = bios[0x90 + 3] | (bios[0x90 + 4] << 8);
5176 if( (!(v1 & 0x02)) && (v2 & 0x30) && (regd < 0xcf) )
5177 setSISIDXREG(SISCR, 0x5f, 0xf1, 0x01);
5178
Adrian Bunk0959f0c2007-05-08 00:39:50 -07005179 if((mypdev = pci_get_device(0x10de, 0x01e0, NULL))) {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07005180 /* TODO: set CR5f &0xf1 | 0x01 for version 6570
5181 * of nforce 2 ROM
5182 */
5183 if(0)
5184 setSISIDXREG(SISCR, 0x5f, 0xf1, 0x01);
Adrian Bunk0959f0c2007-05-08 00:39:50 -07005185 pci_dev_put(mypdev);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07005186 }
5187 }
5188
5189 v1 = 0x30;
5190 inSISIDXREG(SISSR, 0x3b, reg);
5191 inSISIDXREG(SISCR, 0x5f, v2);
5192 if((!(reg & 0x02)) && (v2 & 0x0e))
5193 v1 |= 0x08;
5194 outSISIDXREG(SISSR, 0x27, v1);
5195
5196 if(bios[0x64] & 0x01) {
5197 setSISIDXREG(SISCR, 0x5f, 0xf0, bios[0x64]);
5198 }
5199
5200 v1 = bios[0x4f7];
5201 pci_read_config_dword(pdev, 0x50, &regd);
5202 regd = (regd >> 20) & 0x0f;
5203 if(regd == 1) {
5204 v1 &= 0xfc;
5205 orSISIDXREG(SISCR, 0x5f, 0x08);
5206 }
5207 outSISIDXREG(SISCR, 0x48, v1);
5208
5209 setSISIDXREG(SISCR, 0x47, 0x04, bios[0x4f6] & 0xfb);
5210 setSISIDXREG(SISCR, 0x49, 0xf0, bios[0x4f8] & 0x0f);
5211 setSISIDXREG(SISCR, 0x4a, 0x60, bios[0x4f9] & 0x9f);
5212 setSISIDXREG(SISCR, 0x4b, 0x08, bios[0x4fa] & 0xf7);
5213 setSISIDXREG(SISCR, 0x4c, 0x80, bios[0x4fb] & 0x7f);
5214 outSISIDXREG(SISCR, 0x70, bios[0x4fc]);
5215 setSISIDXREG(SISCR, 0x71, 0xf0, bios[0x4fd] & 0x0f);
5216 outSISIDXREG(SISCR, 0x74, 0xd0);
5217 setSISIDXREG(SISCR, 0x74, 0xcf, bios[0x4fe] & 0x30);
5218 setSISIDXREG(SISCR, 0x75, 0xe0, bios[0x4ff] & 0x1f);
5219 setSISIDXREG(SISCR, 0x76, 0xe0, bios[0x500] & 0x1f);
5220 v1 = bios[0x501];
Adrian Bunk0959f0c2007-05-08 00:39:50 -07005221 if((mypdev = pci_get_device(0x8086, 0x2530, NULL))) {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07005222 v1 = 0xf0;
Adrian Bunk0959f0c2007-05-08 00:39:50 -07005223 pci_dev_put(mypdev);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07005224 }
5225 outSISIDXREG(SISCR, 0x77, v1);
5226 }
5227
5228 /* RAM type */
5229
5230 regb = 0; /* ! */
5231
5232 v1 = 0xff;
5233 if(ivideo->haveXGIROM) {
5234 v1 = bios[0x140 + regb];
5235 }
5236 outSISIDXREG(SISCR, 0x6d, v1);
5237
5238 ptr = cs128;
5239 if(ivideo->haveXGIROM) {
5240 ptr = (const u8 *)&bios[0x128];
5241 }
5242 for(i = 0, j = 0; i < 3; i++, j += 8) {
5243 outSISIDXREG(SISCR, 0x68 + i, ptr[j + regb]);
5244 }
5245
5246 ptr = cs31a;
5247 ptr2 = cs33a;
5248 if(ivideo->haveXGIROM) {
5249 index = (ivideo->chip == XGI_20) ? 0x31a : 0x3a6;
5250 ptr = (const u8 *)&bios[index];
5251 ptr2 = (const u8 *)&bios[index + 0x20];
5252 }
5253 for(i = 0; i < 2; i++) {
5254 if(i == 0) {
5255 regd = le32_to_cpu(((u32 *)ptr)[regb]);
5256 rega = 0x6b;
5257 } else {
5258 regd = le32_to_cpu(((u32 *)ptr2)[regb]);
5259 rega = 0x6e;
5260 }
5261 reg = 0x00;
5262 for(j = 0; j < 16; j++) {
5263 reg &= 0xf3;
5264 if(regd & 0x01) reg |= 0x04;
5265 if(regd & 0x02) reg |= 0x08;
5266 regd >>= 2;
5267 outSISIDXREG(SISCR, rega, reg);
5268 inSISIDXREG(SISCR, rega, reg);
5269 inSISIDXREG(SISCR, rega, reg);
5270 reg += 0x10;
5271 }
5272 }
5273
5274 andSISIDXREG(SISCR, 0x6e, 0xfc);
5275
5276 ptr = NULL;
5277 if(ivideo->haveXGIROM) {
5278 index = (ivideo->chip == XGI_20) ? 0x35a : 0x3e6;
5279 ptr = (const u8 *)&bios[index];
5280 }
5281 for(i = 0; i < 4; i++) {
5282 setSISIDXREG(SISCR, 0x6e, 0xfc, i);
5283 reg = 0x00;
5284 for(j = 0; j < 2; j++) {
5285 regd = 0;
5286 if(ptr) {
5287 regd = le32_to_cpu(((u32 *)ptr)[regb * 8]);
5288 ptr += 4;
5289 }
5290 /* reg = 0x00; */
5291 for(k = 0; k < 16; k++) {
5292 reg &= 0xfc;
5293 if(regd & 0x01) reg |= 0x01;
5294 if(regd & 0x02) reg |= 0x02;
5295 regd >>= 2;
5296 outSISIDXREG(SISCR, 0x6f, reg);
5297 inSISIDXREG(SISCR, 0x6f, reg);
5298 inSISIDXREG(SISCR, 0x6f, reg);
5299 reg += 0x08;
5300 }
5301 }
5302 }
5303
5304 ptr = cs148;
5305 if(ivideo->haveXGIROM) {
5306 ptr = (const u8 *)&bios[0x148];
5307 }
5308 for(i = 0, j = 0; i < 2; i++, j += 8) {
5309 outSISIDXREG(SISCR, 0x80 + i, ptr[j + regb]);
5310 }
5311
5312 andSISIDXREG(SISCR, 0x89, 0x8f);
5313
5314 ptr = cs45a;
5315 if(ivideo->haveXGIROM) {
5316 index = (ivideo->chip == XGI_20) ? 0x45a : 0x4e6;
5317 ptr = (const u8 *)&bios[index];
5318 }
5319 regd = le16_to_cpu(((const u16 *)ptr)[regb]);
5320 reg = 0x80;
5321 for(i = 0; i < 5; i++) {
5322 reg &= 0xfc;
5323 if(regd & 0x01) reg |= 0x01;
5324 if(regd & 0x02) reg |= 0x02;
5325 regd >>= 2;
5326 outSISIDXREG(SISCR, 0x89, reg);
5327 inSISIDXREG(SISCR, 0x89, reg);
5328 inSISIDXREG(SISCR, 0x89, reg);
5329 reg += 0x10;
5330 }
5331
5332 v1 = 0xb5; v2 = 0x20; v3 = 0xf0; v4 = 0x13;
5333 if(ivideo->haveXGIROM) {
5334 v1 = bios[0x118 + regb];
5335 v2 = bios[0xf8 + regb];
5336 v3 = bios[0x120 + regb];
5337 v4 = bios[0x1ca];
5338 }
5339 outSISIDXREG(SISCR, 0x45, v1 & 0x0f);
5340 outSISIDXREG(SISCR, 0x99, (v1 >> 4) & 0x07);
5341 orSISIDXREG(SISCR, 0x40, v1 & 0x80);
5342 outSISIDXREG(SISCR, 0x41, v2);
5343
5344 ptr = cs170;
5345 if(ivideo->haveXGIROM) {
5346 ptr = (const u8 *)&bios[0x170];
5347 }
5348 for(i = 0, j = 0; i < 7; i++, j += 8) {
5349 outSISIDXREG(SISCR, 0x90 + i, ptr[j + regb]);
5350 }
5351
5352 outSISIDXREG(SISCR, 0x59, v3);
5353
5354 ptr = cs1a8;
5355 if(ivideo->haveXGIROM) {
5356 ptr = (const u8 *)&bios[0x1a8];
5357 }
5358 for(i = 0, j = 0; i < 3; i++, j += 8) {
5359 outSISIDXREG(SISCR, 0xc3 + i, ptr[j + regb]);
5360 }
5361
5362 ptr = cs100;
5363 if(ivideo->haveXGIROM) {
5364 ptr = (const u8 *)&bios[0x100];
5365 }
5366 for(i = 0, j = 0; i < 2; i++, j += 8) {
5367 outSISIDXREG(SISCR, 0x8a + i, ptr[j + regb]);
5368 }
5369
5370 outSISIDXREG(SISCR, 0xcf, v4);
5371
5372 outSISIDXREG(SISCR, 0x83, 0x09);
5373 outSISIDXREG(SISCR, 0x87, 0x00);
5374
5375 if(ivideo->chip == XGI_40) {
5376 if( (ivideo->revision_id == 1) ||
5377 (ivideo->revision_id == 2) ) {
5378 outSISIDXREG(SISCR, 0x8c, 0x87);
5379 }
5380 }
5381
5382 outSISIDXREG(SISSR, 0x17, 0x00);
5383 outSISIDXREG(SISSR, 0x1a, 0x87);
5384
5385 if(ivideo->chip == XGI_20) {
5386 outSISIDXREG(SISSR, 0x15, 0x00);
5387 outSISIDXREG(SISSR, 0x1c, 0x00);
5388 }
5389
5390 ramtype = 0x00; v1 = 0x10;
5391 if(ivideo->haveXGIROM) {
5392 ramtype = bios[0x62];
5393 v1 = bios[0x1d2];
5394 }
5395 if(!(ramtype & 0x80)) {
5396 if(ivideo->chip == XGI_20) {
5397 outSISIDXREG(SISCR, 0x97, v1);
5398 inSISIDXREG(SISCR, 0x97, reg);
5399 if(reg & 0x10) {
5400 ramtype = (reg & 0x01) << 1;
5401 }
5402 } else {
5403 inSISIDXREG(SISSR, 0x39, reg);
5404 ramtype = reg & 0x02;
5405 if(!(ramtype)) {
5406 inSISIDXREG(SISSR, 0x3a, reg);
5407 ramtype = (reg >> 1) & 0x01;
5408 }
5409 }
5410 }
5411 ramtype &= 0x07;
5412
5413 regb = 0; /* ! */
5414
5415 switch(ramtype) {
5416 case 0:
5417 sisfb_post_xgi_setclocks(ivideo, regb);
5418 if((ivideo->chip == XGI_20) ||
5419 (ivideo->revision_id == 1) ||
5420 (ivideo->revision_id == 2)) {
5421 v1 = cs158[regb]; v2 = cs160[regb]; v3 = cs168[regb];
5422 if(ivideo->haveXGIROM) {
5423 v1 = bios[regb + 0x158];
5424 v2 = bios[regb + 0x160];
5425 v3 = bios[regb + 0x168];
5426 }
5427 outSISIDXREG(SISCR, 0x82, v1);
5428 outSISIDXREG(SISCR, 0x85, v2);
5429 outSISIDXREG(SISCR, 0x86, v3);
5430 } else {
5431 outSISIDXREG(SISCR, 0x82, 0x88);
5432 outSISIDXREG(SISCR, 0x86, 0x00);
5433 inSISIDXREG(SISCR, 0x86, reg);
5434 outSISIDXREG(SISCR, 0x86, 0x88);
5435 inSISIDXREG(SISCR, 0x86, reg);
5436 outSISIDXREG(SISCR, 0x86, bios[regb + 0x168]);
5437 outSISIDXREG(SISCR, 0x82, 0x77);
5438 outSISIDXREG(SISCR, 0x85, 0x00);
5439 inSISIDXREG(SISCR, 0x85, reg);
5440 outSISIDXREG(SISCR, 0x85, 0x88);
5441 inSISIDXREG(SISCR, 0x85, reg);
5442 outSISIDXREG(SISCR, 0x85, bios[regb + 0x160]);
5443 outSISIDXREG(SISCR, 0x82, bios[regb + 0x158]);
5444 }
5445 if(ivideo->chip == XGI_40) {
5446 outSISIDXREG(SISCR, 0x97, 0x00);
5447 }
5448 outSISIDXREG(SISCR, 0x98, 0x01);
5449 outSISIDXREG(SISCR, 0x9a, 0x02);
5450
5451 outSISIDXREG(SISSR, 0x18, 0x01);
5452 if((ivideo->chip == XGI_20) ||
5453 (ivideo->revision_id == 2)) {
5454 outSISIDXREG(SISSR, 0x19, 0x40);
5455 } else {
5456 outSISIDXREG(SISSR, 0x19, 0x20);
5457 }
5458 outSISIDXREG(SISSR, 0x16, 0x00);
5459 outSISIDXREG(SISSR, 0x16, 0x80);
5460 if((ivideo->chip == XGI_20) || (bios[0x1cb] != 0x0c)) {
5461 sisfb_post_xgi_delay(ivideo, 0x43);
5462 sisfb_post_xgi_delay(ivideo, 0x43);
5463 sisfb_post_xgi_delay(ivideo, 0x43);
5464 outSISIDXREG(SISSR, 0x18, 0x00);
5465 if((ivideo->chip == XGI_20) ||
5466 (ivideo->revision_id == 2)) {
5467 outSISIDXREG(SISSR, 0x19, 0x40);
5468 } else {
5469 outSISIDXREG(SISSR, 0x19, 0x20);
5470 }
5471 } else if((ivideo->chip == XGI_40) && (bios[0x1cb] == 0x0c)) {
5472 /* outSISIDXREG(SISSR, 0x16, 0x0c); */ /* ? */
5473 }
5474 outSISIDXREG(SISSR, 0x16, 0x00);
5475 outSISIDXREG(SISSR, 0x16, 0x80);
5476 sisfb_post_xgi_delay(ivideo, 4);
5477 v1 = 0x31; v2 = 0x03; v3 = 0x83; v4 = 0x03; v5 = 0x83;
5478 if(ivideo->haveXGIROM) {
5479 v1 = bios[0xf0];
5480 index = (ivideo->chip == XGI_20) ? 0x4b2 : 0x53e;
5481 v2 = bios[index];
5482 v3 = bios[index + 1];
5483 v4 = bios[index + 2];
5484 v5 = bios[index + 3];
5485 }
5486 outSISIDXREG(SISSR, 0x18, v1);
5487 outSISIDXREG(SISSR, 0x19, ((ivideo->chip == XGI_20) ? 0x02 : 0x01));
5488 outSISIDXREG(SISSR, 0x16, v2);
5489 outSISIDXREG(SISSR, 0x16, v3);
5490 sisfb_post_xgi_delay(ivideo, 0x43);
5491 outSISIDXREG(SISSR, 0x1b, 0x03);
5492 sisfb_post_xgi_delay(ivideo, 0x22);
5493 outSISIDXREG(SISSR, 0x18, v1);
5494 outSISIDXREG(SISSR, 0x19, 0x00);
5495 outSISIDXREG(SISSR, 0x16, v4);
5496 outSISIDXREG(SISSR, 0x16, v5);
5497 outSISIDXREG(SISSR, 0x1b, 0x00);
5498 break;
5499 case 1:
5500 outSISIDXREG(SISCR, 0x82, 0x77);
5501 outSISIDXREG(SISCR, 0x86, 0x00);
5502 inSISIDXREG(SISCR, 0x86, reg);
5503 outSISIDXREG(SISCR, 0x86, 0x88);
5504 inSISIDXREG(SISCR, 0x86, reg);
5505 v1 = cs168[regb]; v2 = cs160[regb]; v3 = cs158[regb];
5506 if(ivideo->haveXGIROM) {
5507 v1 = bios[regb + 0x168];
5508 v2 = bios[regb + 0x160];
5509 v3 = bios[regb + 0x158];
5510 }
5511 outSISIDXREG(SISCR, 0x86, v1);
5512 outSISIDXREG(SISCR, 0x82, 0x77);
5513 outSISIDXREG(SISCR, 0x85, 0x00);
5514 inSISIDXREG(SISCR, 0x85, reg);
5515 outSISIDXREG(SISCR, 0x85, 0x88);
5516 inSISIDXREG(SISCR, 0x85, reg);
5517 outSISIDXREG(SISCR, 0x85, v2);
5518 outSISIDXREG(SISCR, 0x82, v3);
5519 outSISIDXREG(SISCR, 0x98, 0x01);
5520 outSISIDXREG(SISCR, 0x9a, 0x02);
5521
5522 outSISIDXREG(SISSR, 0x28, 0x64);
5523 outSISIDXREG(SISSR, 0x29, 0x63);
5524 sisfb_post_xgi_delay(ivideo, 15);
5525 outSISIDXREG(SISSR, 0x18, 0x00);
5526 outSISIDXREG(SISSR, 0x19, 0x20);
5527 outSISIDXREG(SISSR, 0x16, 0x00);
5528 outSISIDXREG(SISSR, 0x16, 0x80);
5529 outSISIDXREG(SISSR, 0x18, 0xc5);
5530 outSISIDXREG(SISSR, 0x19, 0x23);
5531 outSISIDXREG(SISSR, 0x16, 0x00);
5532 outSISIDXREG(SISSR, 0x16, 0x80);
5533 sisfb_post_xgi_delay(ivideo, 1);
5534 outSISIDXREG(SISCR, 0x97,0x11);
5535 sisfb_post_xgi_setclocks(ivideo, regb);
5536 sisfb_post_xgi_delay(ivideo, 0x46);
5537 outSISIDXREG(SISSR, 0x18, 0xc5);
5538 outSISIDXREG(SISSR, 0x19, 0x23);
5539 outSISIDXREG(SISSR, 0x16, 0x00);
5540 outSISIDXREG(SISSR, 0x16, 0x80);
5541 sisfb_post_xgi_delay(ivideo, 1);
5542 outSISIDXREG(SISSR, 0x1b, 0x04);
5543 sisfb_post_xgi_delay(ivideo, 1);
5544 outSISIDXREG(SISSR, 0x1b, 0x00);
5545 sisfb_post_xgi_delay(ivideo, 1);
5546 v1 = 0x31;
5547 if(ivideo->haveXGIROM) {
5548 v1 = bios[0xf0];
5549 }
5550 outSISIDXREG(SISSR, 0x18, v1);
5551 outSISIDXREG(SISSR, 0x19, 0x06);
5552 outSISIDXREG(SISSR, 0x16, 0x04);
5553 outSISIDXREG(SISSR, 0x16, 0x84);
5554 sisfb_post_xgi_delay(ivideo, 1);
5555 break;
5556 default:
5557 sisfb_post_xgi_setclocks(ivideo, regb);
5558 if((ivideo->chip == XGI_40) &&
5559 ((ivideo->revision_id == 1) ||
5560 (ivideo->revision_id == 2))) {
5561 outSISIDXREG(SISCR, 0x82, bios[regb + 0x158]);
5562 outSISIDXREG(SISCR, 0x85, bios[regb + 0x160]);
5563 outSISIDXREG(SISCR, 0x86, bios[regb + 0x168]);
5564 } else {
5565 outSISIDXREG(SISCR, 0x82, 0x88);
5566 outSISIDXREG(SISCR, 0x86, 0x00);
5567 inSISIDXREG(SISCR, 0x86, reg);
5568 outSISIDXREG(SISCR, 0x86, 0x88);
5569 outSISIDXREG(SISCR, 0x82, 0x77);
5570 outSISIDXREG(SISCR, 0x85, 0x00);
5571 inSISIDXREG(SISCR, 0x85, reg);
5572 outSISIDXREG(SISCR, 0x85, 0x88);
5573 inSISIDXREG(SISCR, 0x85, reg);
5574 v1 = cs160[regb]; v2 = cs158[regb];
5575 if(ivideo->haveXGIROM) {
5576 v1 = bios[regb + 0x160];
5577 v2 = bios[regb + 0x158];
5578 }
5579 outSISIDXREG(SISCR, 0x85, v1);
5580 outSISIDXREG(SISCR, 0x82, v2);
5581 }
5582 if(ivideo->chip == XGI_40) {
5583 outSISIDXREG(SISCR, 0x97, 0x11);
5584 }
5585 if((ivideo->chip == XGI_40) && (ivideo->revision_id == 2)) {
5586 outSISIDXREG(SISCR, 0x98, 0x01);
5587 } else {
5588 outSISIDXREG(SISCR, 0x98, 0x03);
5589 }
5590 outSISIDXREG(SISCR, 0x9a, 0x02);
5591
5592 if(ivideo->chip == XGI_40) {
5593 outSISIDXREG(SISSR, 0x18, 0x01);
5594 } else {
5595 outSISIDXREG(SISSR, 0x18, 0x00);
5596 }
5597 outSISIDXREG(SISSR, 0x19, 0x40);
5598 outSISIDXREG(SISSR, 0x16, 0x00);
5599 outSISIDXREG(SISSR, 0x16, 0x80);
5600 if((ivideo->chip == XGI_40) && (bios[0x1cb] != 0x0c)) {
5601 sisfb_post_xgi_delay(ivideo, 0x43);
5602 sisfb_post_xgi_delay(ivideo, 0x43);
5603 sisfb_post_xgi_delay(ivideo, 0x43);
5604 outSISIDXREG(SISSR, 0x18, 0x00);
5605 outSISIDXREG(SISSR, 0x19, 0x40);
5606 outSISIDXREG(SISSR, 0x16, 0x00);
5607 outSISIDXREG(SISSR, 0x16, 0x80);
5608 }
5609 sisfb_post_xgi_delay(ivideo, 4);
5610 v1 = 0x31;
5611 if(ivideo->haveXGIROM) {
5612 v1 = bios[0xf0];
5613 }
5614 outSISIDXREG(SISSR, 0x18, v1);
5615 outSISIDXREG(SISSR, 0x19, 0x01);
5616 if(ivideo->chip == XGI_40) {
5617 outSISIDXREG(SISSR, 0x16, bios[0x53e]);
5618 outSISIDXREG(SISSR, 0x16, bios[0x53f]);
5619 } else {
5620 outSISIDXREG(SISSR, 0x16, 0x05);
5621 outSISIDXREG(SISSR, 0x16, 0x85);
5622 }
5623 sisfb_post_xgi_delay(ivideo, 0x43);
5624 if(ivideo->chip == XGI_40) {
5625 outSISIDXREG(SISSR, 0x1b, 0x01);
5626 } else {
5627 outSISIDXREG(SISSR, 0x1b, 0x03);
5628 }
5629 sisfb_post_xgi_delay(ivideo, 0x22);
5630 outSISIDXREG(SISSR, 0x18, v1);
5631 outSISIDXREG(SISSR, 0x19, 0x00);
5632 if(ivideo->chip == XGI_40) {
5633 outSISIDXREG(SISSR, 0x16, bios[0x540]);
5634 outSISIDXREG(SISSR, 0x16, bios[0x541]);
5635 } else {
5636 outSISIDXREG(SISSR, 0x16, 0x05);
5637 outSISIDXREG(SISSR, 0x16, 0x85);
5638 }
5639 outSISIDXREG(SISSR, 0x1b, 0x00);
5640 }
5641
5642 regb = 0; /* ! */
5643 v1 = 0x03;
5644 if(ivideo->haveXGIROM) {
5645 v1 = bios[0x110 + regb];
5646 }
5647 outSISIDXREG(SISSR, 0x1b, v1);
5648
5649 /* RAM size */
5650 v1 = 0x00; v2 = 0x00;
5651 if(ivideo->haveXGIROM) {
5652 v1 = bios[0x62];
5653 v2 = bios[0x63];
5654 }
5655 regb = 0; /* ! */
5656 regd = 1 << regb;
5657 if((v1 & 0x40) && (v2 & regd) && ivideo->haveXGIROM) {
5658
5659 outSISIDXREG(SISSR, 0x13, bios[regb + 0xe0]);
5660 outSISIDXREG(SISSR, 0x14, bios[regb + 0xe0 + 8]);
5661
5662 } else {
5663
5664 /* Set default mode, don't clear screen */
Richard Knutssonc30660ea2007-02-12 00:55:06 -08005665 ivideo->SiS_Pr.SiS_UseOEM = false;
5666 SiS_SetEnableDstn(&ivideo->SiS_Pr, false);
5667 SiS_SetEnableFstn(&ivideo->SiS_Pr, false);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07005668 ivideo->curFSTN = ivideo->curDSTN = 0;
5669 ivideo->SiS_Pr.VideoMemorySize = 8 << 20;
5670 SiSSetMode(&ivideo->SiS_Pr, 0x2e | 0x80);
5671
5672 outSISIDXREG(SISSR, 0x05, 0x86);
5673
5674 /* Disable read-cache */
5675 andSISIDXREG(SISSR, 0x21, 0xdf);
5676 sisfb_post_xgi_ramsize(ivideo);
5677 /* Enable read-cache */
5678 orSISIDXREG(SISSR, 0x21, 0x20);
5679
5680 }
5681
5682#if 0
5683 printk(KERN_DEBUG "-----------------\n");
5684 for(i = 0; i < 0xff; i++) {
5685 inSISIDXREG(SISCR, i, reg);
5686 printk(KERN_DEBUG "CR%02x(%x) = 0x%02x\n", i, SISCR, reg);
5687 }
5688 for(i = 0; i < 0x40; i++) {
5689 inSISIDXREG(SISSR, i, reg);
5690 printk(KERN_DEBUG "SR%02x(%x) = 0x%02x\n", i, SISSR, reg);
5691 }
5692 printk(KERN_DEBUG "-----------------\n");
5693#endif
5694
5695 /* Sense CRT1 */
5696 if(ivideo->chip == XGI_20) {
5697 orSISIDXREG(SISCR, 0x32, 0x20);
5698 } else {
5699 inSISIDXREG(SISPART4, 0x00, reg);
5700 if((reg == 1) || (reg == 2)) {
5701 sisfb_sense_crt1(ivideo);
5702 } else {
5703 orSISIDXREG(SISCR, 0x32, 0x20);
5704 }
5705 }
5706
5707 /* Set default mode, don't clear screen */
Richard Knutssonc30660ea2007-02-12 00:55:06 -08005708 ivideo->SiS_Pr.SiS_UseOEM = false;
5709 SiS_SetEnableDstn(&ivideo->SiS_Pr, false);
5710 SiS_SetEnableFstn(&ivideo->SiS_Pr, false);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07005711 ivideo->curFSTN = ivideo->curDSTN = 0;
5712 SiSSetMode(&ivideo->SiS_Pr, 0x2e | 0x80);
5713
5714 outSISIDXREG(SISSR, 0x05, 0x86);
5715
5716 /* Display off */
5717 orSISIDXREG(SISSR, 0x01, 0x20);
5718
5719 /* Save mode number in CR34 */
5720 outSISIDXREG(SISCR, 0x34, 0x2e);
5721
5722 /* Let everyone know what the current mode is */
5723 ivideo->modeprechange = 0x2e;
5724
5725 if(ivideo->chip == XGI_40) {
5726 inSISIDXREG(SISCR, 0xca, reg);
5727 inSISIDXREG(SISCR, 0xcc, v1);
5728 if((reg & 0x10) && (!(v1 & 0x04))) {
5729 printk(KERN_ERR
5730 "sisfb: Please connect power to the card.\n");
5731 return 0;
5732 }
5733 }
5734
5735 return 1;
5736}
5737#endif
5738
5739static int __devinit
5740sisfb_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
5741{
5742 struct sisfb_chip_info *chipinfo = &sisfb_chip_info[ent->driver_data];
5743 struct sis_video_info *ivideo = NULL;
5744 struct fb_info *sis_fb_info = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005745 u16 reg16;
5746 u8 reg;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07005747 int i, ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005748
Thomas Winischhofer544393f2005-09-09 13:04:45 -07005749 if(sisfb_off)
5750 return -ENXIO;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005751
Linus Torvalds1da177e2005-04-16 15:20:36 -07005752 sis_fb_info = framebuffer_alloc(sizeof(*ivideo), &pdev->dev);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07005753 if(!sis_fb_info)
5754 return -ENOMEM;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005755
5756 ivideo = (struct sis_video_info *)sis_fb_info->par;
5757 ivideo->memyselfandi = sis_fb_info;
5758
Thomas Winischhofer544393f2005-09-09 13:04:45 -07005759 ivideo->sisfb_id = SISFB_ID;
5760
Linus Torvalds1da177e2005-04-16 15:20:36 -07005761 if(card_list == NULL) {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07005762 ivideo->cardnumber = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005763 } else {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07005764 struct sis_video_info *countvideo = card_list;
5765 ivideo->cardnumber = 1;
Harvey Harrison5e2daeb2008-05-22 15:45:08 -07005766 while((countvideo = countvideo->next) != NULL)
Thomas Winischhofer544393f2005-09-09 13:04:45 -07005767 ivideo->cardnumber++;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005768 }
5769
5770 strncpy(ivideo->myid, chipinfo->chip_name, 30);
5771
5772 ivideo->warncount = 0;
5773 ivideo->chip_id = pdev->device;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07005774 ivideo->chip_vendor = pdev->vendor;
Auke Kok44c10132007-06-08 15:46:36 -07005775 ivideo->revision_id = pdev->revision;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07005776 ivideo->SiS_Pr.ChipRevision = ivideo->revision_id;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005777 pci_read_config_word(pdev, PCI_COMMAND, &reg16);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07005778 ivideo->sisvga_enabled = reg16 & 0x01;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005779 ivideo->pcibus = pdev->bus->number;
5780 ivideo->pcislot = PCI_SLOT(pdev->devfn);
5781 ivideo->pcifunc = PCI_FUNC(pdev->devfn);
5782 ivideo->subsysvendor = pdev->subsystem_vendor;
5783 ivideo->subsysdevice = pdev->subsystem_device;
5784
5785#ifndef MODULE
5786 if(sisfb_mode_idx == -1) {
5787 sisfb_get_vga_mode_from_kernel();
5788 }
5789#endif
5790
5791 ivideo->chip = chipinfo->chip;
5792 ivideo->sisvga_engine = chipinfo->vgaengine;
5793 ivideo->hwcursor_size = chipinfo->hwcursor_size;
5794 ivideo->CRT2_write_enable = chipinfo->CRT2_write_enable;
5795 ivideo->mni = chipinfo->mni;
5796
5797 ivideo->detectedpdc = 0xff;
5798 ivideo->detectedpdca = 0xff;
5799 ivideo->detectedlcda = 0xff;
5800
Richard Knutssonc30660ea2007-02-12 00:55:06 -08005801 ivideo->sisfb_thismonitor.datavalid = false;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005802
Thomas Winischhofer544393f2005-09-09 13:04:45 -07005803 ivideo->current_base = 0;
5804
5805 ivideo->engineok = 0;
5806
5807 ivideo->sisfb_was_boot_device = 0;
Adrian Bunk14aefd12008-07-23 21:31:12 -07005808
Thomas Winischhofer544393f2005-09-09 13:04:45 -07005809 if(pdev->resource[PCI_ROM_RESOURCE].flags & IORESOURCE_ROM_SHADOW) {
5810 if(ivideo->sisvga_enabled)
5811 ivideo->sisfb_was_boot_device = 1;
5812 else {
5813 printk(KERN_DEBUG "sisfb: PCI device is disabled, "
5814 "but marked as boot video device ???\n");
5815 printk(KERN_DEBUG "sisfb: I will not accept this "
5816 "as the primary VGA device\n");
5817 }
5818 }
Thomas Winischhofer544393f2005-09-09 13:04:45 -07005819
Linus Torvalds1da177e2005-04-16 15:20:36 -07005820 ivideo->sisfb_parm_mem = sisfb_parm_mem;
5821 ivideo->sisfb_accel = sisfb_accel;
5822 ivideo->sisfb_ypan = sisfb_ypan;
5823 ivideo->sisfb_max = sisfb_max;
5824 ivideo->sisfb_userom = sisfb_userom;
5825 ivideo->sisfb_useoem = sisfb_useoem;
5826 ivideo->sisfb_mode_idx = sisfb_mode_idx;
5827 ivideo->sisfb_parm_rate = sisfb_parm_rate;
5828 ivideo->sisfb_crt1off = sisfb_crt1off;
5829 ivideo->sisfb_forcecrt1 = sisfb_forcecrt1;
5830 ivideo->sisfb_crt2type = sisfb_crt2type;
5831 ivideo->sisfb_crt2flags = sisfb_crt2flags;
5832 /* pdc(a), scalelcd, special timing, lvdshl handled below */
5833 ivideo->sisfb_dstn = sisfb_dstn;
5834 ivideo->sisfb_fstn = sisfb_fstn;
5835 ivideo->sisfb_tvplug = sisfb_tvplug;
5836 ivideo->sisfb_tvstd = sisfb_tvstd;
5837 ivideo->tvxpos = sisfb_tvxposoffset;
5838 ivideo->tvypos = sisfb_tvyposoffset;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005839 ivideo->sisfb_nocrt2rate = sisfb_nocrt2rate;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005840 ivideo->refresh_rate = 0;
5841 if(ivideo->sisfb_parm_rate != -1) {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07005842 ivideo->refresh_rate = ivideo->sisfb_parm_rate;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005843 }
5844
5845 ivideo->SiS_Pr.UsePanelScaler = sisfb_scalelcd;
5846 ivideo->SiS_Pr.CenterScreen = -1;
5847 ivideo->SiS_Pr.SiS_CustomT = sisfb_specialtiming;
5848 ivideo->SiS_Pr.LVDSHL = sisfb_lvdshl;
5849
5850 ivideo->SiS_Pr.SiS_Backup70xx = 0xff;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07005851 ivideo->SiS_Pr.SiS_CHOverScan = -1;
Richard Knutssonc30660ea2007-02-12 00:55:06 -08005852 ivideo->SiS_Pr.SiS_ChSW = false;
5853 ivideo->SiS_Pr.SiS_UseLCDA = false;
5854 ivideo->SiS_Pr.HaveEMI = false;
5855 ivideo->SiS_Pr.HaveEMILCD = false;
5856 ivideo->SiS_Pr.OverruleEMI = false;
5857 ivideo->SiS_Pr.SiS_SensibleSR11 = false;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005858 ivideo->SiS_Pr.SiS_MyCR63 = 0x63;
5859 ivideo->SiS_Pr.PDC = -1;
5860 ivideo->SiS_Pr.PDCA = -1;
Richard Knutssonc30660ea2007-02-12 00:55:06 -08005861 ivideo->SiS_Pr.DDCPortMixup = false;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005862#ifdef CONFIG_FB_SIS_315
5863 if(ivideo->chip >= SIS_330) {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07005864 ivideo->SiS_Pr.SiS_MyCR63 = 0x53;
5865 if(ivideo->chip >= SIS_661) {
Richard Knutssonc30660ea2007-02-12 00:55:06 -08005866 ivideo->SiS_Pr.SiS_SensibleSR11 = true;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07005867 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07005868 }
5869#endif
5870
5871 memcpy(&ivideo->default_var, &my_default_var, sizeof(my_default_var));
5872
5873 pci_set_drvdata(pdev, ivideo);
5874
5875 /* Patch special cases */
5876 if((ivideo->nbridge = sisfb_get_northbridge(ivideo->chip))) {
5877 switch(ivideo->nbridge->device) {
5878#ifdef CONFIG_FB_SIS_300
5879 case PCI_DEVICE_ID_SI_730:
Thomas Winischhofer544393f2005-09-09 13:04:45 -07005880 ivideo->chip = SIS_730;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005881 strcpy(ivideo->myid, "SiS 730");
Thomas Winischhofer544393f2005-09-09 13:04:45 -07005882 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005883#endif
5884#ifdef CONFIG_FB_SIS_315
5885 case PCI_DEVICE_ID_SI_651:
5886 /* ivideo->chip is ok */
5887 strcpy(ivideo->myid, "SiS 651");
5888 break;
5889 case PCI_DEVICE_ID_SI_740:
Thomas Winischhofer544393f2005-09-09 13:04:45 -07005890 ivideo->chip = SIS_740;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005891 strcpy(ivideo->myid, "SiS 740");
5892 break;
5893 case PCI_DEVICE_ID_SI_661:
Thomas Winischhofer544393f2005-09-09 13:04:45 -07005894 ivideo->chip = SIS_661;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005895 strcpy(ivideo->myid, "SiS 661");
5896 break;
5897 case PCI_DEVICE_ID_SI_741:
Thomas Winischhofer544393f2005-09-09 13:04:45 -07005898 ivideo->chip = SIS_741;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005899 strcpy(ivideo->myid, "SiS 741");
5900 break;
5901 case PCI_DEVICE_ID_SI_760:
Thomas Winischhofer544393f2005-09-09 13:04:45 -07005902 ivideo->chip = SIS_760;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005903 strcpy(ivideo->myid, "SiS 760");
5904 break;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07005905 case PCI_DEVICE_ID_SI_761:
5906 ivideo->chip = SIS_761;
5907 strcpy(ivideo->myid, "SiS 761");
5908 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005909#endif
Thomas Winischhofer544393f2005-09-09 13:04:45 -07005910 default:
5911 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005912 }
5913 }
5914
Thomas Winischhofer544393f2005-09-09 13:04:45 -07005915 ivideo->SiS_Pr.ChipType = ivideo->chip;
5916
5917 ivideo->SiS_Pr.ivideo = (void *)ivideo;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005918
5919#ifdef CONFIG_FB_SIS_315
Thomas Winischhofer544393f2005-09-09 13:04:45 -07005920 if((ivideo->SiS_Pr.ChipType == SIS_315PRO) ||
5921 (ivideo->SiS_Pr.ChipType == SIS_315)) {
5922 ivideo->SiS_Pr.ChipType = SIS_315H;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005923 }
5924#endif
5925
Thomas Winischhofer544393f2005-09-09 13:04:45 -07005926 if(!ivideo->sisvga_enabled) {
5927 if(pci_enable_device(pdev)) {
Adrian Bunk0959f0c2007-05-08 00:39:50 -07005928 if(ivideo->nbridge) pci_dev_put(ivideo->nbridge);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07005929 pci_set_drvdata(pdev, NULL);
Krzysztof Helt491bcc92009-06-16 15:34:36 -07005930 framebuffer_release(sis_fb_info);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07005931 return -EIO;
5932 }
5933 }
5934
Linus Torvalds1da177e2005-04-16 15:20:36 -07005935 ivideo->video_base = pci_resource_start(pdev, 0);
5936 ivideo->mmio_base = pci_resource_start(pdev, 1);
5937 ivideo->mmio_size = pci_resource_len(pdev, 1);
5938 ivideo->SiS_Pr.RelIO = pci_resource_start(pdev, 2) + 0x30;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07005939 ivideo->SiS_Pr.IOAddress = ivideo->vga_base = ivideo->SiS_Pr.RelIO;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005940
Thomas Winischhofer544393f2005-09-09 13:04:45 -07005941 SiSRegInit(&ivideo->SiS_Pr, ivideo->SiS_Pr.IOAddress);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005942
5943#ifdef CONFIG_FB_SIS_300
5944 /* Find PCI systems for Chrontel/GPIO communication setup */
5945 if(ivideo->chip == SIS_630) {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07005946 i = 0;
5947 do {
5948 if(mychswtable[i].subsysVendor == ivideo->subsysvendor &&
5949 mychswtable[i].subsysCard == ivideo->subsysdevice) {
Richard Knutssonc30660ea2007-02-12 00:55:06 -08005950 ivideo->SiS_Pr.SiS_ChSW = true;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07005951 printk(KERN_DEBUG "sisfb: Identified [%s %s] "
5952 "requiring Chrontel/GPIO setup\n",
5953 mychswtable[i].vendorName,
5954 mychswtable[i].cardName);
Adrian Bunk0959f0c2007-05-08 00:39:50 -07005955 ivideo->lpcdev = pci_get_device(PCI_VENDOR_ID_SI, 0x0008, NULL);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07005956 break;
5957 }
5958 i++;
5959 } while(mychswtable[i].subsysVendor != 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005960 }
5961#endif
5962
Thomas Winischhofer544393f2005-09-09 13:04:45 -07005963#ifdef CONFIG_FB_SIS_315
5964 if((ivideo->chip == SIS_760) && (ivideo->nbridge)) {
Adrian Bunk0959f0c2007-05-08 00:39:50 -07005965 ivideo->lpcdev = pci_get_slot(ivideo->nbridge->bus, (2 << 3));
Thomas Winischhofer544393f2005-09-09 13:04:45 -07005966 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07005967#endif
Thomas Winischhofer544393f2005-09-09 13:04:45 -07005968
5969 outSISIDXREG(SISSR, 0x05, 0x86);
5970
5971 if( (!ivideo->sisvga_enabled)
5972#if !defined(__i386__) && !defined(__x86_64__)
5973 || (sisfb_resetcard)
5974#endif
5975 ) {
5976 for(i = 0x30; i <= 0x3f; i++) {
5977 outSISIDXREG(SISCR, i, 0x00);
5978 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07005979 }
5980
5981 /* Find out about current video mode */
5982 ivideo->modeprechange = 0x03;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07005983 inSISIDXREG(SISCR, 0x34, reg);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005984 if(reg & 0x7f) {
5985 ivideo->modeprechange = reg & 0x7f;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07005986 } else if(ivideo->sisvga_enabled) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07005987#if defined(__i386__) || defined(__x86_64__)
Adrian Bunk14aefd12008-07-23 21:31:12 -07005988 unsigned char __iomem *tt = ioremap(0x400, 0x100);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005989 if(tt) {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07005990 ivideo->modeprechange = readb(tt + 0x49);
5991 iounmap(tt);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005992 }
5993#endif
5994 }
5995
Thomas Winischhofer544393f2005-09-09 13:04:45 -07005996 /* Search and copy ROM image */
5997 ivideo->bios_abase = NULL;
5998 ivideo->SiS_Pr.VirtualRomBase = NULL;
Richard Knutssonc30660ea2007-02-12 00:55:06 -08005999 ivideo->SiS_Pr.UseROM = false;
6000 ivideo->haveXGIROM = ivideo->SiS_Pr.SiS_XGIROM = false;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006001 if(ivideo->sisfb_userom) {
6002 ivideo->SiS_Pr.VirtualRomBase = sisfb_find_rom(pdev);
6003 ivideo->bios_abase = ivideo->SiS_Pr.VirtualRomBase;
Richard Knutssonc30660ea2007-02-12 00:55:06 -08006004 ivideo->SiS_Pr.UseROM = (bool)(ivideo->SiS_Pr.VirtualRomBase);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006005 printk(KERN_INFO "sisfb: Video ROM %sfound\n",
6006 ivideo->SiS_Pr.UseROM ? "" : "not ");
6007 if((ivideo->SiS_Pr.UseROM) && (ivideo->chip >= XGI_20)) {
Richard Knutssonc30660ea2007-02-12 00:55:06 -08006008 ivideo->SiS_Pr.UseROM = false;
6009 ivideo->haveXGIROM = ivideo->SiS_Pr.SiS_XGIROM = true;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006010 if( (ivideo->revision_id == 2) &&
6011 (!(ivideo->bios_abase[0x1d1] & 0x01)) ) {
Richard Knutssonc30660ea2007-02-12 00:55:06 -08006012 ivideo->SiS_Pr.DDCPortMixup = true;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006013 }
6014 }
6015 } else {
6016 printk(KERN_INFO "sisfb: Video ROM usage disabled\n");
6017 }
6018
6019 /* Find systems for special custom timing */
6020 if(ivideo->SiS_Pr.SiS_CustomT == CUT_NONE) {
6021 sisfb_detect_custom_timing(ivideo);
6022 }
6023
6024 /* POST card in case this has not been done by the BIOS */
6025 if( (!ivideo->sisvga_enabled)
6026#if !defined(__i386__) && !defined(__x86_64__)
6027 || (sisfb_resetcard)
6028#endif
6029 ) {
6030#ifdef CONFIG_FB_SIS_300
6031 if(ivideo->sisvga_engine == SIS_300_VGA) {
6032 if(ivideo->chip == SIS_300) {
6033 sisfb_post_sis300(pdev);
6034 ivideo->sisfb_can_post = 1;
6035 }
6036 }
6037#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -07006038
6039#ifdef CONFIG_FB_SIS_315
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006040 if(ivideo->sisvga_engine == SIS_315_VGA) {
6041 int result = 1;
6042 /* if((ivideo->chip == SIS_315H) ||
Linus Torvalds1da177e2005-04-16 15:20:36 -07006043 (ivideo->chip == SIS_315) ||
6044 (ivideo->chip == SIS_315PRO) ||
6045 (ivideo->chip == SIS_330)) {
6046 sisfb_post_sis315330(pdev);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006047 } else */ if(ivideo->chip == XGI_20) {
6048 result = sisfb_post_xgi(pdev);
6049 ivideo->sisfb_can_post = 1;
6050 } else if((ivideo->chip == XGI_40) && ivideo->haveXGIROM) {
6051 result = sisfb_post_xgi(pdev);
6052 ivideo->sisfb_can_post = 1;
6053 } else {
6054 printk(KERN_INFO "sisfb: Card is not "
6055 "POSTed and sisfb can't do this either.\n");
6056 }
6057 if(!result) {
6058 printk(KERN_ERR "sisfb: Failed to POST card\n");
6059 ret = -ENODEV;
6060 goto error_3;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006061 }
6062 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07006063#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -07006064 }
6065
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006066 ivideo->sisfb_card_posted = 1;
6067
6068 /* Find out about RAM size */
6069 if(sisfb_get_dram_size(ivideo)) {
6070 printk(KERN_INFO "sisfb: Fatal error: Unable to determine VRAM size.\n");
6071 ret = -ENODEV;
6072 goto error_3;
6073 }
6074
6075
6076 /* Enable PCI addressing and MMIO */
Linus Torvalds1da177e2005-04-16 15:20:36 -07006077 if((ivideo->sisfb_mode_idx < 0) ||
6078 ((sisbios_mode[ivideo->sisfb_mode_idx].mode_no[ivideo->mni]) != 0xFF)) {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006079 /* Enable PCI_LINEAR_ADDRESSING and MMIO_ENABLE */
6080 orSISIDXREG(SISSR, IND_SIS_PCI_ADDRESS_SET, (SIS_PCI_ADDR_ENABLE | SIS_MEM_MAP_IO_ENABLE));
6081 /* Enable 2D accelerator engine */
6082 orSISIDXREG(SISSR, IND_SIS_MODULE_ENABLE, SIS_ENABLE_2D);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006083 }
6084
6085 if(sisfb_pdc != 0xff) {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006086 if(ivideo->sisvga_engine == SIS_300_VGA)
6087 sisfb_pdc &= 0x3c;
6088 else
6089 sisfb_pdc &= 0x1f;
6090 ivideo->SiS_Pr.PDC = sisfb_pdc;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006091 }
6092#ifdef CONFIG_FB_SIS_315
6093 if(ivideo->sisvga_engine == SIS_315_VGA) {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006094 if(sisfb_pdca != 0xff)
6095 ivideo->SiS_Pr.PDCA = sisfb_pdca & 0x1f;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006096 }
6097#endif
6098
6099 if(!request_mem_region(ivideo->video_base, ivideo->video_size, "sisfb FB")) {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006100 printk(KERN_ERR "sisfb: Fatal error: Unable to reserve %dMB framebuffer memory\n",
6101 (int)(ivideo->video_size >> 20));
Linus Torvalds1da177e2005-04-16 15:20:36 -07006102 printk(KERN_ERR "sisfb: Is there another framebuffer driver active?\n");
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006103 ret = -ENODEV;
6104 goto error_3;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006105 }
6106
6107 if(!request_mem_region(ivideo->mmio_base, ivideo->mmio_size, "sisfb MMIO")) {
6108 printk(KERN_ERR "sisfb: Fatal error: Unable to reserve MMIO region\n");
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006109 ret = -ENODEV;
6110 goto error_2;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006111 }
6112
6113 ivideo->video_vbase = ioremap(ivideo->video_base, ivideo->video_size);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006114 ivideo->SiS_Pr.VideoMemoryAddress = ivideo->video_vbase;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006115 if(!ivideo->video_vbase) {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006116 printk(KERN_ERR "sisfb: Fatal error: Unable to map framebuffer memory\n");
6117 ret = -ENODEV;
6118 goto error_1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006119 }
6120
6121 ivideo->mmio_vbase = ioremap(ivideo->mmio_base, ivideo->mmio_size);
6122 if(!ivideo->mmio_vbase) {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006123 printk(KERN_ERR "sisfb: Fatal error: Unable to map MMIO region\n");
6124 ret = -ENODEV;
6125error_0: iounmap(ivideo->video_vbase);
6126error_1: release_mem_region(ivideo->video_base, ivideo->video_size);
6127error_2: release_mem_region(ivideo->mmio_base, ivideo->mmio_size);
6128error_3: vfree(ivideo->bios_abase);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006129 if(ivideo->lpcdev)
Adrian Bunk0959f0c2007-05-08 00:39:50 -07006130 pci_dev_put(ivideo->lpcdev);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006131 if(ivideo->nbridge)
Adrian Bunk0959f0c2007-05-08 00:39:50 -07006132 pci_dev_put(ivideo->nbridge);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006133 pci_set_drvdata(pdev, NULL);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006134 if(!ivideo->sisvga_enabled)
6135 pci_disable_device(pdev);
Krzysztof Helt491bcc92009-06-16 15:34:36 -07006136 framebuffer_release(sis_fb_info);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006137 return ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006138 }
6139
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006140 printk(KERN_INFO "sisfb: Video RAM at 0x%lx, mapped to 0x%lx, size %ldk\n",
6141 ivideo->video_base, (unsigned long)ivideo->video_vbase, ivideo->video_size / 1024);
6142
6143 if(ivideo->video_offset) {
6144 printk(KERN_INFO "sisfb: Viewport offset %ldk\n",
6145 ivideo->video_offset / 1024);
6146 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07006147
6148 printk(KERN_INFO "sisfb: MMIO at 0x%lx, mapped to 0x%lx, size %ldk\n",
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006149 ivideo->mmio_base, (unsigned long)ivideo->mmio_vbase, ivideo->mmio_size / 1024);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006150
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006151
6152 /* Determine the size of the command queue */
6153 if(ivideo->sisvga_engine == SIS_300_VGA) {
6154 ivideo->cmdQueueSize = TURBO_QUEUE_AREA_SIZE;
6155 } else {
6156 if(ivideo->chip == XGI_20) {
6157 ivideo->cmdQueueSize = COMMAND_QUEUE_AREA_SIZE_Z7;
6158 } else {
6159 ivideo->cmdQueueSize = COMMAND_QUEUE_AREA_SIZE;
6160 }
6161 }
6162
6163 /* Engines are no longer initialized here; this is
6164 * now done after the first mode-switch (if the
6165 * submitted var has its acceleration flags set).
6166 */
6167
6168 /* Calculate the base of the (unused) hw cursor */
6169 ivideo->hwcursor_vbase = ivideo->video_vbase
6170 + ivideo->video_size
6171 - ivideo->cmdQueueSize
6172 - ivideo->hwcursor_size;
6173 ivideo->caps |= HW_CURSOR_CAP;
6174
6175 /* Initialize offscreen memory manager */
Linus Torvalds1da177e2005-04-16 15:20:36 -07006176 if((ivideo->havenoheap = sisfb_heap_init(ivideo))) {
6177 printk(KERN_WARNING "sisfb: Failed to initialize offscreen memory heap\n");
6178 }
6179
6180 /* Used for clearing the screen only, therefore respect our mem limit */
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006181 ivideo->SiS_Pr.VideoMemoryAddress += ivideo->video_offset;
6182 ivideo->SiS_Pr.VideoMemorySize = ivideo->sisfb_mem;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006183
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006184 ivideo->mtrr = -1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006185
6186 ivideo->vbflags = 0;
6187 ivideo->lcddefmodeidx = DEFAULT_LCDMODE;
6188 ivideo->tvdefmodeidx = DEFAULT_TVMODE;
6189 ivideo->defmodeidx = DEFAULT_MODE;
6190
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006191 ivideo->newrom = 0;
6192 if(ivideo->chip < XGI_20) {
6193 if(ivideo->bios_abase) {
6194 ivideo->newrom = SiSDetermineROMLayout661(&ivideo->SiS_Pr);
6195 }
6196 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07006197
6198 if((ivideo->sisfb_mode_idx < 0) ||
6199 ((sisbios_mode[ivideo->sisfb_mode_idx].mode_no[ivideo->mni]) != 0xFF)) {
6200
6201 sisfb_sense_crt1(ivideo);
6202
6203 sisfb_get_VB_type(ivideo);
6204
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006205 if(ivideo->vbflags2 & VB2_VIDEOBRIDGE) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07006206 sisfb_detect_VB_connect(ivideo);
6207 }
6208
6209 ivideo->currentvbflags = ivideo->vbflags & (VB_VIDEOBRIDGE | TV_STANDARD);
6210
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006211 /* Decide on which CRT2 device to use */
6212 if(ivideo->vbflags2 & VB2_VIDEOBRIDGE) {
6213 if(ivideo->sisfb_crt2type != -1) {
6214 if((ivideo->sisfb_crt2type == CRT2_LCD) &&
6215 (ivideo->vbflags & CRT2_LCD)) {
6216 ivideo->currentvbflags |= CRT2_LCD;
6217 } else if(ivideo->sisfb_crt2type != CRT2_LCD) {
6218 ivideo->currentvbflags |= ivideo->sisfb_crt2type;
6219 }
6220 } else {
6221 /* Chrontel 700x TV detection often unreliable, therefore
6222 * use a different default order on such machines
6223 */
6224 if((ivideo->sisvga_engine == SIS_300_VGA) &&
6225 (ivideo->vbflags2 & VB2_CHRONTEL)) {
6226 if(ivideo->vbflags & CRT2_LCD)
6227 ivideo->currentvbflags |= CRT2_LCD;
6228 else if(ivideo->vbflags & CRT2_TV)
6229 ivideo->currentvbflags |= CRT2_TV;
6230 else if(ivideo->vbflags & CRT2_VGA)
6231 ivideo->currentvbflags |= CRT2_VGA;
6232 } else {
6233 if(ivideo->vbflags & CRT2_TV)
6234 ivideo->currentvbflags |= CRT2_TV;
6235 else if(ivideo->vbflags & CRT2_LCD)
6236 ivideo->currentvbflags |= CRT2_LCD;
6237 else if(ivideo->vbflags & CRT2_VGA)
6238 ivideo->currentvbflags |= CRT2_VGA;
6239 }
6240 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07006241 }
6242
6243 if(ivideo->vbflags & CRT2_LCD) {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006244 sisfb_detect_lcd_type(ivideo);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006245 }
6246
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006247 sisfb_save_pdc_emi(ivideo);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006248
6249 if(!ivideo->sisfb_crt1off) {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006250 sisfb_handle_ddc(ivideo, &ivideo->sisfb_thismonitor, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006251 } else {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006252 if((ivideo->vbflags2 & VB2_SISTMDSBRIDGE) &&
6253 (ivideo->vbflags & (CRT2_VGA | CRT2_LCD))) {
6254 sisfb_handle_ddc(ivideo, &ivideo->sisfb_thismonitor, 1);
6255 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07006256 }
6257
6258 if(ivideo->sisfb_mode_idx >= 0) {
6259 int bu = ivideo->sisfb_mode_idx;
6260 ivideo->sisfb_mode_idx = sisfb_validate_mode(ivideo,
6261 ivideo->sisfb_mode_idx, ivideo->currentvbflags);
6262 if(bu != ivideo->sisfb_mode_idx) {
6263 printk(KERN_ERR "Mode %dx%dx%d failed validation\n",
6264 sisbios_mode[bu].xres,
6265 sisbios_mode[bu].yres,
6266 sisbios_mode[bu].bpp);
6267 }
6268 }
6269
6270 if(ivideo->sisfb_mode_idx < 0) {
6271 switch(ivideo->currentvbflags & VB_DISPTYPE_DISP2) {
6272 case CRT2_LCD:
6273 ivideo->sisfb_mode_idx = ivideo->lcddefmodeidx;
6274 break;
6275 case CRT2_TV:
6276 ivideo->sisfb_mode_idx = ivideo->tvdefmodeidx;
6277 break;
6278 default:
6279 ivideo->sisfb_mode_idx = ivideo->defmodeidx;
6280 break;
6281 }
6282 }
6283
6284 ivideo->mode_no = sisbios_mode[ivideo->sisfb_mode_idx].mode_no[ivideo->mni];
6285
6286 if(ivideo->refresh_rate != 0) {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006287 sisfb_search_refresh_rate(ivideo, ivideo->refresh_rate,
6288 ivideo->sisfb_mode_idx);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006289 }
6290
6291 if(ivideo->rate_idx == 0) {
6292 ivideo->rate_idx = sisbios_mode[ivideo->sisfb_mode_idx].rate_idx;
6293 ivideo->refresh_rate = 60;
6294 }
6295
6296 if(ivideo->sisfb_thismonitor.datavalid) {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006297 if(!sisfb_verify_rate(ivideo, &ivideo->sisfb_thismonitor,
6298 ivideo->sisfb_mode_idx,
6299 ivideo->rate_idx,
6300 ivideo->refresh_rate)) {
6301 printk(KERN_INFO "sisfb: WARNING: Refresh rate "
6302 "exceeds monitor specs!\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07006303 }
6304 }
6305
6306 ivideo->video_bpp = sisbios_mode[ivideo->sisfb_mode_idx].bpp;
6307 ivideo->video_width = sisbios_mode[ivideo->sisfb_mode_idx].xres;
6308 ivideo->video_height = sisbios_mode[ivideo->sisfb_mode_idx].yres;
6309
6310 sisfb_set_vparms(ivideo);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006311
Linus Torvalds1da177e2005-04-16 15:20:36 -07006312 printk(KERN_INFO "sisfb: Default mode is %dx%dx%d (%dHz)\n",
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006313 ivideo->video_width, ivideo->video_height, ivideo->video_bpp,
Linus Torvalds1da177e2005-04-16 15:20:36 -07006314 ivideo->refresh_rate);
6315
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006316 /* Set up the default var according to chosen default display mode */
Linus Torvalds1da177e2005-04-16 15:20:36 -07006317 ivideo->default_var.xres = ivideo->default_var.xres_virtual = ivideo->video_width;
6318 ivideo->default_var.yres = ivideo->default_var.yres_virtual = ivideo->video_height;
6319 ivideo->default_var.bits_per_pixel = ivideo->video_bpp;
6320
6321 sisfb_bpp_to_var(ivideo, &ivideo->default_var);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006322
Linus Torvalds1da177e2005-04-16 15:20:36 -07006323 ivideo->default_var.pixclock = (u32) (1000000000 /
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006324 sisfb_mode_rate_to_dclock(&ivideo->SiS_Pr, ivideo->mode_no, ivideo->rate_idx));
6325
6326 if(sisfb_mode_rate_to_ddata(&ivideo->SiS_Pr, ivideo->mode_no,
6327 ivideo->rate_idx, &ivideo->default_var)) {
6328 if((ivideo->default_var.vmode & FB_VMODE_MASK) == FB_VMODE_DOUBLE) {
6329 ivideo->default_var.pixclock <<= 1;
6330 }
6331 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07006332
6333 if(ivideo->sisfb_ypan) {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006334 /* Maximize regardless of sisfb_max at startup */
6335 ivideo->default_var.yres_virtual =
6336 sisfb_calc_maxyres(ivideo, &ivideo->default_var);
6337 if(ivideo->default_var.yres_virtual < ivideo->default_var.yres) {
6338 ivideo->default_var.yres_virtual = ivideo->default_var.yres;
6339 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07006340 }
6341
6342 sisfb_calc_pitch(ivideo, &ivideo->default_var);
6343
6344 ivideo->accel = 0;
6345 if(ivideo->sisfb_accel) {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006346 ivideo->accel = -1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006347#ifdef STUPID_ACCELF_TEXT_SHIT
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006348 ivideo->default_var.accel_flags |= FB_ACCELF_TEXT;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006349#endif
6350 }
6351 sisfb_initaccel(ivideo);
6352
6353#if defined(FBINFO_HWACCEL_DISABLED) && defined(FBINFO_HWACCEL_XPAN)
6354 sis_fb_info->flags = FBINFO_DEFAULT |
6355 FBINFO_HWACCEL_YPAN |
6356 FBINFO_HWACCEL_XPAN |
6357 FBINFO_HWACCEL_COPYAREA |
6358 FBINFO_HWACCEL_FILLRECT |
6359 ((ivideo->accel) ? 0 : FBINFO_HWACCEL_DISABLED);
6360#else
6361 sis_fb_info->flags = FBINFO_FLAG_DEFAULT;
6362#endif
6363 sis_fb_info->var = ivideo->default_var;
6364 sis_fb_info->fix = ivideo->sisfb_fix;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006365 sis_fb_info->screen_base = ivideo->video_vbase + ivideo->video_offset;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006366 sis_fb_info->fbops = &sisfb_ops;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006367 sis_fb_info->pseudo_palette = ivideo->pseudo_palette;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006368
Linus Torvalds1da177e2005-04-16 15:20:36 -07006369 fb_alloc_cmap(&sis_fb_info->cmap, 256 , 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006370
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006371 printk(KERN_DEBUG "sisfb: Initial vbflags 0x%x\n", (int)ivideo->vbflags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006372
6373#ifdef CONFIG_MTRR
6374 ivideo->mtrr = mtrr_add(ivideo->video_base, ivideo->video_size,
6375 MTRR_TYPE_WRCOMB, 1);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006376 if(ivideo->mtrr < 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07006377 printk(KERN_DEBUG "sisfb: Failed to add MTRRs\n");
6378 }
6379#endif
6380
Linus Torvalds1da177e2005-04-16 15:20:36 -07006381 if(register_framebuffer(sis_fb_info) < 0) {
6382 printk(KERN_ERR "sisfb: Fatal error: Failed to register framebuffer\n");
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006383 ret = -EINVAL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006384 iounmap(ivideo->mmio_vbase);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006385 goto error_0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006386 }
6387
6388 ivideo->registered = 1;
6389
6390 /* Enlist us */
6391 ivideo->next = card_list;
6392 card_list = ivideo;
6393
6394 printk(KERN_INFO "sisfb: 2D acceleration is %s, y-panning %s\n",
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006395 ivideo->sisfb_accel ? "enabled" : "disabled",
6396 ivideo->sisfb_ypan ?
6397 (ivideo->sisfb_max ? "enabled (auto-max)" :
6398 "enabled (no auto-max)") :
6399 "disabled");
Linus Torvalds1da177e2005-04-16 15:20:36 -07006400
6401
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006402 printk(KERN_INFO "fb%d: %s frame buffer device version %d.%d.%d\n",
Michal Piotrowski43704092006-10-03 01:15:00 -07006403 sis_fb_info->node, ivideo->myid, VER_MAJOR, VER_MINOR, VER_LEVEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006404
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006405 printk(KERN_INFO "sisfb: Copyright (C) 2001-2005 Thomas Winischhofer\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07006406
6407 } /* if mode = "none" */
6408
6409 return 0;
6410}
6411
6412/*****************************************************/
6413/* PCI DEVICE HANDLING */
6414/*****************************************************/
6415
6416static void __devexit sisfb_remove(struct pci_dev *pdev)
6417{
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006418 struct sis_video_info *ivideo = pci_get_drvdata(pdev);
6419 struct fb_info *sis_fb_info = ivideo->memyselfandi;
6420 int registered = ivideo->registered;
6421 int modechanged = ivideo->modechanged;
6422
Linus Torvalds1da177e2005-04-16 15:20:36 -07006423 /* Unmap */
Linus Torvalds1da177e2005-04-16 15:20:36 -07006424 iounmap(ivideo->mmio_vbase);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006425 iounmap(ivideo->video_vbase);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006426
6427 /* Release mem regions */
6428 release_mem_region(ivideo->video_base, ivideo->video_size);
6429 release_mem_region(ivideo->mmio_base, ivideo->mmio_size);
6430
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006431 vfree(ivideo->bios_abase);
6432
6433 if(ivideo->lpcdev)
Adrian Bunk0959f0c2007-05-08 00:39:50 -07006434 pci_dev_put(ivideo->lpcdev);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006435
6436 if(ivideo->nbridge)
Adrian Bunk0959f0c2007-05-08 00:39:50 -07006437 pci_dev_put(ivideo->nbridge);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006438
Linus Torvalds1da177e2005-04-16 15:20:36 -07006439#ifdef CONFIG_MTRR
6440 /* Release MTRR region */
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006441 if(ivideo->mtrr >= 0)
Linus Torvalds1da177e2005-04-16 15:20:36 -07006442 mtrr_del(ivideo->mtrr, ivideo->video_base, ivideo->video_size);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006443#endif
6444
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006445 pci_set_drvdata(pdev, NULL);
6446
6447 /* If device was disabled when starting, disable
6448 * it when quitting.
6449 */
6450 if(!ivideo->sisvga_enabled)
6451 pci_disable_device(pdev);
6452
Linus Torvalds1da177e2005-04-16 15:20:36 -07006453 /* Unregister the framebuffer */
6454 if(ivideo->registered) {
6455 unregister_framebuffer(sis_fb_info);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006456 framebuffer_release(sis_fb_info);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006457 }
6458
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006459 /* OK, our ivideo is gone for good from here. */
Linus Torvalds1da177e2005-04-16 15:20:36 -07006460
6461 /* TODO: Restore the initial mode
6462 * This sounds easy but is as good as impossible
6463 * on many machines with SiS chip and video bridge
6464 * since text modes are always set up differently
6465 * from machine to machine. Depends on the type
6466 * of integration between chipset and bridge.
6467 */
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006468 if(registered && modechanged)
6469 printk(KERN_INFO
6470 "sisfb: Restoring of text mode not supported yet\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07006471};
6472
6473static struct pci_driver sisfb_driver = {
6474 .name = "sisfb",
6475 .id_table = sisfb_pci_table,
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006476 .probe = sisfb_probe,
Linus Torvalds1da177e2005-04-16 15:20:36 -07006477 .remove = __devexit_p(sisfb_remove)
6478};
6479
Adrian Bunk14aefd12008-07-23 21:31:12 -07006480static int __init sisfb_init(void)
Linus Torvalds1da177e2005-04-16 15:20:36 -07006481{
Linus Torvalds1da177e2005-04-16 15:20:36 -07006482#ifndef MODULE
6483 char *options = NULL;
6484
6485 if(fb_get_options("sisfb", &options))
6486 return -ENODEV;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006487
Linus Torvalds1da177e2005-04-16 15:20:36 -07006488 sisfb_setup(options);
6489#endif
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006490 return pci_register_driver(&sisfb_driver);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006491}
6492
Linus Torvalds1da177e2005-04-16 15:20:36 -07006493#ifndef MODULE
6494module_init(sisfb_init);
6495#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -07006496
6497/*****************************************************/
6498/* MODULE */
6499/*****************************************************/
6500
6501#ifdef MODULE
6502
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006503static char *mode = NULL;
6504static int vesa = -1;
6505static unsigned int rate = 0;
6506static unsigned int crt1off = 1;
6507static unsigned int mem = 0;
6508static char *forcecrt2type = NULL;
6509static int forcecrt1 = -1;
6510static int pdc = -1;
6511static int pdc1 = -1;
6512static int noaccel = -1;
6513static int noypan = -1;
6514static int nomax = -1;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006515static int userom = -1;
6516static int useoem = -1;
6517static char *tvstandard = NULL;
6518static int nocrt2rate = 0;
6519static int scalelcd = -1;
6520static char *specialtiming = NULL;
6521static int lvdshl = -1;
6522static int tvxposoffset = 0, tvyposoffset = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006523#if !defined(__i386__) && !defined(__x86_64__)
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006524static int resetcard = 0;
6525static int videoram = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006526#endif
6527
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006528static int __init sisfb_init_module(void)
6529{
6530 sisfb_setdefaultparms();
6531
6532 if(rate)
6533 sisfb_parm_rate = rate;
6534
6535 if((scalelcd == 0) || (scalelcd == 1))
6536 sisfb_scalelcd = scalelcd ^ 1;
6537
6538 /* Need to check crt2 type first for fstn/dstn */
6539
6540 if(forcecrt2type)
6541 sisfb_search_crt2type(forcecrt2type);
6542
6543 if(tvstandard)
6544 sisfb_search_tvstd(tvstandard);
6545
6546 if(mode)
Richard Knutssonc30660ea2007-02-12 00:55:06 -08006547 sisfb_search_mode(mode, false);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006548 else if(vesa != -1)
Richard Knutssonc30660ea2007-02-12 00:55:06 -08006549 sisfb_search_vesamode(vesa, false);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006550
6551 sisfb_crt1off = (crt1off == 0) ? 1 : 0;
6552
6553 sisfb_forcecrt1 = forcecrt1;
6554 if(forcecrt1 == 1)
6555 sisfb_crt1off = 0;
6556 else if(forcecrt1 == 0)
6557 sisfb_crt1off = 1;
6558
6559 if(noaccel == 1)
6560 sisfb_accel = 0;
6561 else if(noaccel == 0)
6562 sisfb_accel = 1;
6563
6564 if(noypan == 1)
6565 sisfb_ypan = 0;
6566 else if(noypan == 0)
6567 sisfb_ypan = 1;
6568
6569 if(nomax == 1)
6570 sisfb_max = 0;
6571 else if(nomax == 0)
6572 sisfb_max = 1;
6573
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006574 if(mem)
6575 sisfb_parm_mem = mem;
6576
6577 if(userom != -1)
6578 sisfb_userom = userom;
6579
6580 if(useoem != -1)
6581 sisfb_useoem = useoem;
6582
6583 if(pdc != -1)
6584 sisfb_pdc = (pdc & 0x7f);
6585
6586 if(pdc1 != -1)
6587 sisfb_pdca = (pdc1 & 0x1f);
6588
6589 sisfb_nocrt2rate = nocrt2rate;
6590
6591 if(specialtiming)
6592 sisfb_search_specialtiming(specialtiming);
6593
6594 if((lvdshl >= 0) && (lvdshl <= 3))
6595 sisfb_lvdshl = lvdshl;
6596
6597 sisfb_tvxposoffset = tvxposoffset;
6598 sisfb_tvyposoffset = tvyposoffset;
6599
6600#if !defined(__i386__) && !defined(__x86_64__)
6601 sisfb_resetcard = (resetcard) ? 1 : 0;
6602 if(videoram)
6603 sisfb_videoram = videoram;
6604#endif
6605
6606 return sisfb_init();
6607}
6608
6609static void __exit sisfb_remove_module(void)
6610{
6611 pci_unregister_driver(&sisfb_driver);
6612 printk(KERN_DEBUG "sisfb: Module unloaded\n");
6613}
6614
6615module_init(sisfb_init_module);
6616module_exit(sisfb_remove_module);
6617
6618MODULE_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 -07006619MODULE_LICENSE("GPL");
6620MODULE_AUTHOR("Thomas Winischhofer <thomas@winischhofer.net>, Others");
6621
Linus Torvalds1da177e2005-04-16 15:20:36 -07006622module_param(mem, int, 0);
6623module_param(noaccel, int, 0);
6624module_param(noypan, int, 0);
6625module_param(nomax, int, 0);
6626module_param(userom, int, 0);
6627module_param(useoem, int, 0);
6628module_param(mode, charp, 0);
6629module_param(vesa, int, 0);
6630module_param(rate, int, 0);
6631module_param(forcecrt1, int, 0);
6632module_param(forcecrt2type, charp, 0);
6633module_param(scalelcd, int, 0);
6634module_param(pdc, int, 0);
6635module_param(pdc1, int, 0);
6636module_param(specialtiming, charp, 0);
6637module_param(lvdshl, int, 0);
6638module_param(tvstandard, charp, 0);
6639module_param(tvxposoffset, int, 0);
6640module_param(tvyposoffset, int, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006641module_param(nocrt2rate, int, 0);
6642#if !defined(__i386__) && !defined(__x86_64__)
6643module_param(resetcard, int, 0);
6644module_param(videoram, int, 0);
6645#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -07006646
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006647MODULE_PARM_DESC(mem,
6648 "\nDetermines the beginning of the video memory heap in KB. This heap is used\n"
6649 "for video RAM management for eg. DRM/DRI. On 300 series, the default depends\n"
6650 "on the amount of video RAM available. If 8MB of video RAM or less is available,\n"
6651 "the heap starts at 4096KB, if between 8 and 16MB are available at 8192KB,\n"
6652 "otherwise at 12288KB. On 315/330/340 series, the heap size is 32KB by default.\n"
6653 "The value is to be specified without 'KB'.\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07006654
6655MODULE_PARM_DESC(noaccel,
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006656 "\nIf set to anything other than 0, 2D acceleration will be disabled.\n"
Linus Torvalds1da177e2005-04-16 15:20:36 -07006657 "(default: 0)\n");
6658
6659MODULE_PARM_DESC(noypan,
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006660 "\nIf set to anything other than 0, y-panning will be disabled and scrolling\n"
6661 "will be performed by redrawing the screen. (default: 0)\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07006662
6663MODULE_PARM_DESC(nomax,
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006664 "\nIf y-panning is enabled, sisfb will by default use the entire available video\n"
Linus Torvalds1da177e2005-04-16 15:20:36 -07006665 "memory for the virtual screen in order to optimize scrolling performance. If\n"
6666 "this is set to anything other than 0, sisfb will not do this and thereby \n"
6667 "enable the user to positively specify a virtual Y size of the screen using\n"
6668 "fbset. (default: 0)\n");
6669
Linus Torvalds1da177e2005-04-16 15:20:36 -07006670MODULE_PARM_DESC(mode,
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006671 "\nSelects the desired default display mode in the format XxYxDepth,\n"
6672 "eg. 1024x768x16. Other formats supported include XxY-Depth and\n"
Linus Torvalds1da177e2005-04-16 15:20:36 -07006673 "XxY-Depth@Rate. If the parameter is only one (decimal or hexadecimal)\n"
6674 "number, it will be interpreted as a VESA mode number. (default: 800x600x8)\n");
6675
6676MODULE_PARM_DESC(vesa,
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006677 "\nSelects the desired default display mode by VESA defined mode number, eg.\n"
6678 "0x117 (default: 0x0103)\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07006679
6680MODULE_PARM_DESC(rate,
6681 "\nSelects the desired vertical refresh rate for CRT1 (external VGA) in Hz.\n"
6682 "If the mode is specified in the format XxY-Depth@Rate, this parameter\n"
6683 "will be ignored (default: 60)\n");
6684
6685MODULE_PARM_DESC(forcecrt1,
6686 "\nNormally, the driver autodetects whether or not CRT1 (external VGA) is \n"
6687 "connected. With this option, the detection can be overridden (1=CRT1 ON,\n"
6688 "0=CRT1 OFF) (default: [autodetected])\n");
6689
6690MODULE_PARM_DESC(forcecrt2type,
6691 "\nIf this option is omitted, the driver autodetects CRT2 output devices, such as\n"
6692 "LCD, TV or secondary VGA. With this option, this autodetection can be\n"
6693 "overridden. Possible parameters are LCD, TV, VGA or NONE. NONE disables CRT2.\n"
6694 "On systems with a SiS video bridge, parameters SVIDEO, COMPOSITE or SCART can\n"
6695 "be used instead of TV to override the TV detection. Furthermore, on systems\n"
6696 "with a SiS video bridge, SVIDEO+COMPOSITE, HIVISION, YPBPR480I, YPBPR480P,\n"
6697 "YPBPR720P and YPBPR1080I are understood. However, whether or not these work\n"
6698 "depends on the very hardware in use. (default: [autodetected])\n");
6699
6700MODULE_PARM_DESC(scalelcd,
6701 "\nSetting this to 1 will force the driver to scale the LCD image to the panel's\n"
6702 "native resolution. Setting it to 0 will disable scaling; LVDS panels will\n"
6703 "show black bars around the image, TMDS panels will probably do the scaling\n"
6704 "themselves. Default: 1 on LVDS panels, 0 on TMDS panels\n");
6705
6706MODULE_PARM_DESC(pdc,
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006707 "\nThis is for manually selecting the LCD panel delay compensation. The driver\n"
Linus Torvalds1da177e2005-04-16 15:20:36 -07006708 "should detect this correctly in most cases; however, sometimes this is not\n"
6709 "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 -07006710 "on a 300 series chipset; 6 on other chipsets. If the problem persists, try\n"
6711 "other values (on 300 series: between 4 and 60 in steps of 4; otherwise: any\n"
6712 "value from 0 to 31). (default: autodetected, if LCD is active during start)\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07006713
6714#ifdef CONFIG_FB_SIS_315
6715MODULE_PARM_DESC(pdc1,
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006716 "\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 -07006717 "series only. (default: autodetected if LCD is in LCD-via-CRT1 mode during\n"
6718 "startup) - Note: currently, this has no effect because LCD-via-CRT1 is not\n"
6719 "implemented yet.\n");
6720#endif
6721
6722MODULE_PARM_DESC(specialtiming,
6723 "\nPlease refer to documentation for more information on this option.\n");
6724
6725MODULE_PARM_DESC(lvdshl,
6726 "\nPlease refer to documentation for more information on this option.\n");
6727
6728MODULE_PARM_DESC(tvstandard,
6729 "\nThis allows overriding the BIOS default for the TV standard. Valid choices are\n"
6730 "pal, ntsc, palm and paln. (default: [auto; pal or ntsc only])\n");
6731
6732MODULE_PARM_DESC(tvxposoffset,
6733 "\nRelocate TV output horizontally. Possible parameters: -32 through 32.\n"
6734 "Default: 0\n");
6735
6736MODULE_PARM_DESC(tvyposoffset,
6737 "\nRelocate TV output vertically. Possible parameters: -32 through 32.\n"
6738 "Default: 0\n");
6739
Linus Torvalds1da177e2005-04-16 15:20:36 -07006740MODULE_PARM_DESC(nocrt2rate,
6741 "\nSetting this to 1 will force the driver to use the default refresh rate for\n"
6742 "CRT2 if CRT2 type is VGA. (default: 0, use same rate as CRT1)\n");
6743
Linus Torvalds1da177e2005-04-16 15:20:36 -07006744#if !defined(__i386__) && !defined(__x86_64__)
6745#ifdef CONFIG_FB_SIS_300
6746MODULE_PARM_DESC(resetcard,
6747 "\nSet this to 1 in order to reset (POST) the card on non-x86 machines where\n"
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006748 "the BIOS did not POST the card (only supported for SiS 300/305 and XGI cards\n"
6749 "currently). Default: 0\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07006750
6751MODULE_PARM_DESC(videoram,
6752 "\nSet this to the amount of video RAM (in kilobyte) the card has. Required on\n"
6753 "some non-x86 architectures where the memory auto detection fails. Only\n"
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006754 "relevant if resetcard is set, too. SiS300/305 only. Default: [auto-detect]\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07006755#endif
6756#endif
6757
Linus Torvalds1da177e2005-04-16 15:20:36 -07006758#endif /* /MODULE */
6759
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006760/* _GPL only for new symbols. */
Linus Torvalds1da177e2005-04-16 15:20:36 -07006761EXPORT_SYMBOL(sis_malloc);
6762EXPORT_SYMBOL(sis_free);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006763EXPORT_SYMBOL_GPL(sis_malloc_new);
6764EXPORT_SYMBOL_GPL(sis_free_new);
6765
Linus Torvalds1da177e2005-04-16 15:20:36 -07006766
6767