blob: a7a48db64ce20d0cdad34635da4848bc0410dec1 [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
Aaro Koskinen1f8e6ee2010-11-19 21:58:50 +000063#if !defined(CONFIG_FB_SIS_300) && !defined(CONFIG_FB_SIS_315)
64#warning Neither CONFIG_FB_SIS_300 nor CONFIG_FB_SIS_315 is set
65#warning sisfb will not work!
66#endif
67
Thomas Winischhofer544393f2005-09-09 13:04:45 -070068static void sisfb_handle_command(struct sis_video_info *ivideo,
69 struct sisfb_cmd *sisfb_command);
70
Linus Torvalds1da177e2005-04-16 15:20:36 -070071/* ------------------ Internal helper routines ----------------- */
72
73static void __init
74sisfb_setdefaultparms(void)
75{
Thomas Winischhofer544393f2005-09-09 13:04:45 -070076 sisfb_off = 0;
77 sisfb_parm_mem = 0;
78 sisfb_accel = -1;
79 sisfb_ypan = -1;
80 sisfb_max = -1;
81 sisfb_userom = -1;
82 sisfb_useoem = -1;
Thomas Winischhofer544393f2005-09-09 13:04:45 -070083 sisfb_mode_idx = -1;
Thomas Winischhofer544393f2005-09-09 13:04:45 -070084 sisfb_parm_rate = -1;
85 sisfb_crt1off = 0;
86 sisfb_forcecrt1 = -1;
87 sisfb_crt2type = -1;
88 sisfb_crt2flags = 0;
89 sisfb_pdc = 0xff;
90 sisfb_pdca = 0xff;
91 sisfb_scalelcd = -1;
Linus Torvalds1da177e2005-04-16 15:20:36 -070092 sisfb_specialtiming = CUT_NONE;
Thomas Winischhofer544393f2005-09-09 13:04:45 -070093 sisfb_lvdshl = -1;
94 sisfb_dstn = 0;
95 sisfb_fstn = 0;
96 sisfb_tvplug = -1;
97 sisfb_tvstd = -1;
98 sisfb_tvxposoffset = 0;
99 sisfb_tvyposoffset = 0;
100 sisfb_nocrt2rate = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700101#if !defined(__i386__) && !defined(__x86_64__)
Thomas Winischhofer544393f2005-09-09 13:04:45 -0700102 sisfb_resetcard = 0;
103 sisfb_videoram = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700104#endif
105}
106
Thomas Winischhofer544393f2005-09-09 13:04:45 -0700107/* ------------- Parameter parsing -------------- */
108
Linus Torvalds1da177e2005-04-16 15:20:36 -0700109static void __devinit
Richard Knutssonc30660ea2007-02-12 00:55:06 -0800110sisfb_search_vesamode(unsigned int vesamode, bool quiet)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700111{
112 int i = 0, j = 0;
113
Thomas Winischhofer544393f2005-09-09 13:04:45 -0700114 /* We don't know the hardware specs yet and there is no ivideo */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700115
116 if(vesamode == 0) {
Thomas Winischhofer544393f2005-09-09 13:04:45 -0700117 if(!quiet)
118 printk(KERN_ERR "sisfb: Invalid mode. Using default.\n");
119
Linus Torvalds1da177e2005-04-16 15:20:36 -0700120 sisfb_mode_idx = DEFAULT_MODE;
Michal Piotrowski43704092006-10-03 01:15:00 -0700121
Linus Torvalds1da177e2005-04-16 15:20:36 -0700122 return;
123 }
124
125 vesamode &= 0x1dff; /* Clean VESA mode number from other flags */
126
127 while(sisbios_mode[i++].mode_no[0] != 0) {
128 if( (sisbios_mode[i-1].vesa_mode_no_1 == vesamode) ||
129 (sisbios_mode[i-1].vesa_mode_no_2 == vesamode) ) {
Thomas Winischhofer544393f2005-09-09 13:04:45 -0700130 if(sisfb_fstn) {
131 if(sisbios_mode[i-1].mode_no[1] == 0x50 ||
132 sisbios_mode[i-1].mode_no[1] == 0x56 ||
133 sisbios_mode[i-1].mode_no[1] == 0x53)
134 continue;
135 } else {
136 if(sisbios_mode[i-1].mode_no[1] == 0x5a ||
137 sisbios_mode[i-1].mode_no[1] == 0x5b)
138 continue;
139 }
140 sisfb_mode_idx = i - 1;
141 j = 1;
142 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700143 }
144 }
Thomas Winischhofer544393f2005-09-09 13:04:45 -0700145 if((!j) && !quiet)
146 printk(KERN_ERR "sisfb: Invalid VESA mode 0x%x'\n", vesamode);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700147}
148
Thomas Winischhofer544393f2005-09-09 13:04:45 -0700149static void __devinit
Richard Knutssonc30660ea2007-02-12 00:55:06 -0800150sisfb_search_mode(char *name, bool quiet)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700151{
Linus Torvalds1da177e2005-04-16 15:20:36 -0700152 unsigned int j = 0, xres = 0, yres = 0, depth = 0, rate = 0;
Thomas Winischhofer544393f2005-09-09 13:04:45 -0700153 int i = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700154 char strbuf[16], strbuf1[20];
155 char *nameptr = name;
156
Thomas Winischhofer544393f2005-09-09 13:04:45 -0700157 /* We don't know the hardware specs yet and there is no ivideo */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700158
159 if(name == NULL) {
Thomas Winischhofer544393f2005-09-09 13:04:45 -0700160 if(!quiet)
161 printk(KERN_ERR "sisfb: Internal error, using default mode.\n");
162
163 sisfb_mode_idx = DEFAULT_MODE;
164 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700165 }
166
Thomas Winischhofer544393f2005-09-09 13:04:45 -0700167 if(!strnicmp(name, sisbios_mode[MODE_INDEX_NONE].name, strlen(name))) {
168 if(!quiet)
169 printk(KERN_ERR "sisfb: Mode 'none' not supported anymore. Using default.\n");
170
171 sisfb_mode_idx = DEFAULT_MODE;
172 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700173 }
Michal Piotrowski43704092006-10-03 01:15:00 -0700174
Linus Torvalds1da177e2005-04-16 15:20:36 -0700175 if(strlen(name) <= 19) {
Thomas Winischhofer544393f2005-09-09 13:04:45 -0700176 strcpy(strbuf1, name);
177 for(i = 0; i < strlen(strbuf1); i++) {
178 if(strbuf1[i] < '0' || strbuf1[i] > '9') strbuf1[i] = ' ';
179 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700180
Thomas Winischhofer544393f2005-09-09 13:04:45 -0700181 /* This does some fuzzy mode naming detection */
182 if(sscanf(strbuf1, "%u %u %u %u", &xres, &yres, &depth, &rate) == 4) {
183 if((rate <= 32) || (depth > 32)) {
184 j = rate; rate = depth; depth = j;
185 }
186 sprintf(strbuf, "%ux%ux%u", xres, yres, depth);
187 nameptr = strbuf;
188 sisfb_parm_rate = rate;
189 } else if(sscanf(strbuf1, "%u %u %u", &xres, &yres, &depth) == 3) {
190 sprintf(strbuf, "%ux%ux%u", xres, yres, depth);
191 nameptr = strbuf;
192 } else {
193 xres = 0;
194 if((sscanf(strbuf1, "%u %u", &xres, &yres) == 2) && (xres != 0)) {
195 sprintf(strbuf, "%ux%ux8", xres, yres);
196 nameptr = strbuf;
197 } else {
198 sisfb_search_vesamode(simple_strtoul(name, NULL, 0), quiet);
199 return;
200 }
201 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700202 }
203
204 i = 0; j = 0;
205 while(sisbios_mode[i].mode_no[0] != 0) {
206 if(!strnicmp(nameptr, sisbios_mode[i++].name, strlen(nameptr))) {
Thomas Winischhofer544393f2005-09-09 13:04:45 -0700207 if(sisfb_fstn) {
208 if(sisbios_mode[i-1].mode_no[1] == 0x50 ||
209 sisbios_mode[i-1].mode_no[1] == 0x56 ||
210 sisbios_mode[i-1].mode_no[1] == 0x53)
211 continue;
212 } else {
213 if(sisbios_mode[i-1].mode_no[1] == 0x5a ||
214 sisbios_mode[i-1].mode_no[1] == 0x5b)
215 continue;
216 }
217 sisfb_mode_idx = i - 1;
218 j = 1;
219 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700220 }
221 }
Thomas Winischhofer544393f2005-09-09 13:04:45 -0700222
223 if((!j) && !quiet)
224 printk(KERN_ERR "sisfb: Invalid mode '%s'\n", nameptr);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700225}
226
227#ifndef MODULE
228static void __devinit
229sisfb_get_vga_mode_from_kernel(void)
230{
Adrian Bunk31c5cdb2006-06-26 00:26:28 -0700231#ifdef CONFIG_X86
Thomas Winischhofer544393f2005-09-09 13:04:45 -0700232 char mymode[32];
Linus Torvalds1da177e2005-04-16 15:20:36 -0700233 int mydepth = screen_info.lfb_depth;
234
235 if(screen_info.orig_video_isVGA != VIDEO_TYPE_VLFB) return;
236
237 if( (screen_info.lfb_width >= 320) && (screen_info.lfb_width <= 2048) &&
238 (screen_info.lfb_height >= 200) && (screen_info.lfb_height <= 1536) &&
239 (mydepth >= 8) && (mydepth <= 32) ) {
240
Thomas Winischhofer544393f2005-09-09 13:04:45 -0700241 if(mydepth == 24) mydepth = 32;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700242
Thomas Winischhofer544393f2005-09-09 13:04:45 -0700243 sprintf(mymode, "%ux%ux%u", screen_info.lfb_width,
244 screen_info.lfb_height,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700245 mydepth);
246
Thomas Winischhofer544393f2005-09-09 13:04:45 -0700247 printk(KERN_DEBUG
248 "sisfb: Using vga mode %s pre-set by kernel as default\n",
249 mymode);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700250
Richard Knutssonc30660ea2007-02-12 00:55:06 -0800251 sisfb_search_mode(mymode, true);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700252 }
253#endif
254 return;
255}
256#endif
257
258static void __init
259sisfb_search_crt2type(const char *name)
260{
261 int i = 0;
262
Thomas Winischhofer544393f2005-09-09 13:04:45 -0700263 /* We don't know the hardware specs yet and there is no ivideo */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700264
265 if(name == NULL) return;
266
267 while(sis_crt2type[i].type_no != -1) {
Thomas Winischhofer544393f2005-09-09 13:04:45 -0700268 if(!strnicmp(name, sis_crt2type[i].name, strlen(sis_crt2type[i].name))) {
269 sisfb_crt2type = sis_crt2type[i].type_no;
270 sisfb_tvplug = sis_crt2type[i].tvplug_no;
271 sisfb_crt2flags = sis_crt2type[i].flags;
272 break;
273 }
274 i++;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700275 }
276
277 sisfb_dstn = (sisfb_crt2flags & FL_550_DSTN) ? 1 : 0;
278 sisfb_fstn = (sisfb_crt2flags & FL_550_FSTN) ? 1 : 0;
279
Thomas Winischhofer544393f2005-09-09 13:04:45 -0700280 if(sisfb_crt2type < 0)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700281 printk(KERN_ERR "sisfb: Invalid CRT2 type: %s\n", name);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700282}
283
284static void __init
285sisfb_search_tvstd(const char *name)
286{
287 int i = 0;
288
Thomas Winischhofer544393f2005-09-09 13:04:45 -0700289 /* We don't know the hardware specs yet and there is no ivideo */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700290
Thomas Winischhofer544393f2005-09-09 13:04:45 -0700291 if(name == NULL)
292 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700293
294 while(sis_tvtype[i].type_no != -1) {
Thomas Winischhofer544393f2005-09-09 13:04:45 -0700295 if(!strnicmp(name, sis_tvtype[i].name, strlen(sis_tvtype[i].name))) {
296 sisfb_tvstd = sis_tvtype[i].type_no;
297 break;
298 }
299 i++;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700300 }
301}
302
303static void __init
304sisfb_search_specialtiming(const char *name)
305{
306 int i = 0;
Richard Knutssonc30660ea2007-02-12 00:55:06 -0800307 bool found = false;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700308
Thomas Winischhofer544393f2005-09-09 13:04:45 -0700309 /* We don't know the hardware specs yet and there is no ivideo */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700310
Thomas Winischhofer544393f2005-09-09 13:04:45 -0700311 if(name == NULL)
312 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700313
314 if(!strnicmp(name, "none", 4)) {
Thomas Winischhofer544393f2005-09-09 13:04:45 -0700315 sisfb_specialtiming = CUT_FORCENONE;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700316 printk(KERN_DEBUG "sisfb: Special timing disabled\n");
317 } else {
Thomas Winischhofer544393f2005-09-09 13:04:45 -0700318 while(mycustomttable[i].chipID != 0) {
319 if(!strnicmp(name,mycustomttable[i].optionName,
320 strlen(mycustomttable[i].optionName))) {
321 sisfb_specialtiming = mycustomttable[i].SpecialID;
Richard Knutssonc30660ea2007-02-12 00:55:06 -0800322 found = true;
Thomas Winischhofer544393f2005-09-09 13:04:45 -0700323 printk(KERN_INFO "sisfb: Special timing for %s %s forced (\"%s\")\n",
324 mycustomttable[i].vendorName,
325 mycustomttable[i].cardName,
326 mycustomttable[i].optionName);
327 break;
328 }
329 i++;
330 }
331 if(!found) {
332 printk(KERN_WARNING "sisfb: Invalid SpecialTiming parameter, valid are:");
333 printk(KERN_WARNING "\t\"none\" (to disable special timings)\n");
334 i = 0;
335 while(mycustomttable[i].chipID != 0) {
336 printk(KERN_WARNING "\t\"%s\" (for %s %s)\n",
337 mycustomttable[i].optionName,
338 mycustomttable[i].vendorName,
339 mycustomttable[i].cardName);
340 i++;
341 }
342 }
343 }
344}
345
346/* ----------- Various detection routines ----------- */
347
348static void __devinit
349sisfb_detect_custom_timing(struct sis_video_info *ivideo)
350{
351 unsigned char *biosver = NULL;
352 unsigned char *biosdate = NULL;
Richard Knutssonc30660ea2007-02-12 00:55:06 -0800353 bool footprint;
Thomas Winischhofer544393f2005-09-09 13:04:45 -0700354 u32 chksum = 0;
355 int i, j;
356
357 if(ivideo->SiS_Pr.UseROM) {
358 biosver = ivideo->SiS_Pr.VirtualRomBase + 0x06;
359 biosdate = ivideo->SiS_Pr.VirtualRomBase + 0x2c;
360 for(i = 0; i < 32768; i++)
361 chksum += ivideo->SiS_Pr.VirtualRomBase[i];
362 }
363
364 i = 0;
365 do {
366 if( (mycustomttable[i].chipID == ivideo->chip) &&
367 ((!strlen(mycustomttable[i].biosversion)) ||
368 (ivideo->SiS_Pr.UseROM &&
369 (!strncmp(mycustomttable[i].biosversion, biosver,
370 strlen(mycustomttable[i].biosversion))))) &&
371 ((!strlen(mycustomttable[i].biosdate)) ||
372 (ivideo->SiS_Pr.UseROM &&
373 (!strncmp(mycustomttable[i].biosdate, biosdate,
374 strlen(mycustomttable[i].biosdate))))) &&
375 ((!mycustomttable[i].bioschksum) ||
376 (ivideo->SiS_Pr.UseROM &&
377 (mycustomttable[i].bioschksum == chksum))) &&
378 (mycustomttable[i].pcisubsysvendor == ivideo->subsysvendor) &&
379 (mycustomttable[i].pcisubsyscard == ivideo->subsysdevice) ) {
Richard Knutssonc30660ea2007-02-12 00:55:06 -0800380 footprint = true;
Thomas Winischhofer544393f2005-09-09 13:04:45 -0700381 for(j = 0; j < 5; j++) {
382 if(mycustomttable[i].biosFootprintAddr[j]) {
383 if(ivideo->SiS_Pr.UseROM) {
384 if(ivideo->SiS_Pr.VirtualRomBase[mycustomttable[i].biosFootprintAddr[j]] !=
385 mycustomttable[i].biosFootprintData[j]) {
Richard Knutssonc30660ea2007-02-12 00:55:06 -0800386 footprint = false;
Thomas Winischhofer544393f2005-09-09 13:04:45 -0700387 }
388 } else
Richard Knutssonc30660ea2007-02-12 00:55:06 -0800389 footprint = false;
Thomas Winischhofer544393f2005-09-09 13:04:45 -0700390 }
391 }
392 if(footprint) {
393 ivideo->SiS_Pr.SiS_CustomT = mycustomttable[i].SpecialID;
394 printk(KERN_DEBUG "sisfb: Identified [%s %s], special timing applies\n",
395 mycustomttable[i].vendorName,
396 mycustomttable[i].cardName);
397 printk(KERN_DEBUG "sisfb: [specialtiming parameter name: %s]\n",
398 mycustomttable[i].optionName);
399 break;
400 }
401 }
402 i++;
403 } while(mycustomttable[i].chipID);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700404}
405
Richard Knutssonc30660ea2007-02-12 00:55:06 -0800406static bool __devinit
Linus Torvalds1da177e2005-04-16 15:20:36 -0700407sisfb_interpret_edid(struct sisfb_monitor *monitor, u8 *buffer)
408{
409 int i, j, xres, yres, refresh, index;
410 u32 emodes;
411
412 if(buffer[0] != 0x00 || buffer[1] != 0xff ||
413 buffer[2] != 0xff || buffer[3] != 0xff ||
414 buffer[4] != 0xff || buffer[5] != 0xff ||
415 buffer[6] != 0xff || buffer[7] != 0x00) {
Thomas Winischhofer544393f2005-09-09 13:04:45 -0700416 printk(KERN_DEBUG "sisfb: Bad EDID header\n");
Richard Knutssonc30660ea2007-02-12 00:55:06 -0800417 return false;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700418 }
419
420 if(buffer[0x12] != 0x01) {
Thomas Winischhofer544393f2005-09-09 13:04:45 -0700421 printk(KERN_INFO "sisfb: EDID version %d not supported\n",
422 buffer[0x12]);
Richard Knutssonc30660ea2007-02-12 00:55:06 -0800423 return false;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700424 }
425
426 monitor->feature = buffer[0x18];
427
Alexey Dobriyaneaa0ff12008-02-06 01:36:06 -0800428 if(!(buffer[0x14] & 0x80)) {
Thomas Winischhofer544393f2005-09-09 13:04:45 -0700429 if(!(buffer[0x14] & 0x08)) {
430 printk(KERN_INFO
431 "sisfb: WARNING: Monitor does not support separate syncs\n");
432 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700433 }
434
435 if(buffer[0x13] >= 0x01) {
436 /* EDID V1 rev 1 and 2: Search for monitor descriptor
437 * to extract ranges
438 */
439 j = 0x36;
440 for(i=0; i<4; i++) {
441 if(buffer[j] == 0x00 && buffer[j + 1] == 0x00 &&
Thomas Winischhofer544393f2005-09-09 13:04:45 -0700442 buffer[j + 2] == 0x00 && buffer[j + 3] == 0xfd &&
Linus Torvalds1da177e2005-04-16 15:20:36 -0700443 buffer[j + 4] == 0x00) {
444 monitor->hmin = buffer[j + 7];
445 monitor->hmax = buffer[j + 8];
446 monitor->vmin = buffer[j + 5];
447 monitor->vmax = buffer[j + 6];
448 monitor->dclockmax = buffer[j + 9] * 10 * 1000;
Richard Knutssonc30660ea2007-02-12 00:55:06 -0800449 monitor->datavalid = true;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700450 break;
451 }
452 j += 18;
453 }
454 }
455
456 if(!monitor->datavalid) {
457 /* Otherwise: Get a range from the list of supported
458 * Estabished Timings. This is not entirely accurate,
459 * because fixed frequency monitors are not supported
460 * that way.
461 */
462 monitor->hmin = 65535; monitor->hmax = 0;
463 monitor->vmin = 65535; monitor->vmax = 0;
464 monitor->dclockmax = 0;
465 emodes = buffer[0x23] | (buffer[0x24] << 8) | (buffer[0x25] << 16);
466 for(i = 0; i < 13; i++) {
467 if(emodes & sisfb_ddcsmodes[i].mask) {
Thomas Winischhofer544393f2005-09-09 13:04:45 -0700468 if(monitor->hmin > sisfb_ddcsmodes[i].h) monitor->hmin = sisfb_ddcsmodes[i].h;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700469 if(monitor->hmax < sisfb_ddcsmodes[i].h) monitor->hmax = sisfb_ddcsmodes[i].h + 1;
470 if(monitor->vmin > sisfb_ddcsmodes[i].v) monitor->vmin = sisfb_ddcsmodes[i].v;
471 if(monitor->vmax < sisfb_ddcsmodes[i].v) monitor->vmax = sisfb_ddcsmodes[i].v;
472 if(monitor->dclockmax < sisfb_ddcsmodes[i].d) monitor->dclockmax = sisfb_ddcsmodes[i].d;
473 }
474 }
475 index = 0x26;
476 for(i = 0; i < 8; i++) {
477 xres = (buffer[index] + 31) * 8;
478 switch(buffer[index + 1] & 0xc0) {
Thomas Winischhofer544393f2005-09-09 13:04:45 -0700479 case 0xc0: yres = (xres * 9) / 16; break;
480 case 0x80: yres = (xres * 4) / 5; break;
481 case 0x40: yres = (xres * 3) / 4; break;
482 default: yres = xres; break;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700483 }
484 refresh = (buffer[index + 1] & 0x3f) + 60;
485 if((xres >= 640) && (yres >= 480)) {
Thomas Winischhofer544393f2005-09-09 13:04:45 -0700486 for(j = 0; j < 8; j++) {
487 if((xres == sisfb_ddcfmodes[j].x) &&
488 (yres == sisfb_ddcfmodes[j].y) &&
Linus Torvalds1da177e2005-04-16 15:20:36 -0700489 (refresh == sisfb_ddcfmodes[j].v)) {
490 if(monitor->hmin > sisfb_ddcfmodes[j].h) monitor->hmin = sisfb_ddcfmodes[j].h;
491 if(monitor->hmax < sisfb_ddcfmodes[j].h) monitor->hmax = sisfb_ddcfmodes[j].h + 1;
492 if(monitor->vmin > sisfb_ddcsmodes[j].v) monitor->vmin = sisfb_ddcsmodes[j].v;
493 if(monitor->vmax < sisfb_ddcsmodes[j].v) monitor->vmax = sisfb_ddcsmodes[j].v;
Thomas Winischhofer544393f2005-09-09 13:04:45 -0700494 if(monitor->dclockmax < sisfb_ddcsmodes[j].d) monitor->dclockmax = sisfb_ddcsmodes[j].d;
495 }
496 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700497 }
498 index += 2;
Thomas Winischhofer544393f2005-09-09 13:04:45 -0700499 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700500 if((monitor->hmin <= monitor->hmax) && (monitor->vmin <= monitor->vmax)) {
Richard Knutssonc30660ea2007-02-12 00:55:06 -0800501 monitor->datavalid = true;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700502 }
503 }
504
Thomas Winischhofer544393f2005-09-09 13:04:45 -0700505 return monitor->datavalid;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700506}
507
508static void __devinit
509sisfb_handle_ddc(struct sis_video_info *ivideo, struct sisfb_monitor *monitor, int crtno)
510{
Thomas Winischhofer544393f2005-09-09 13:04:45 -0700511 unsigned short temp, i, realcrtno = crtno;
512 unsigned char buffer[256];
Linus Torvalds1da177e2005-04-16 15:20:36 -0700513
Richard Knutssonc30660ea2007-02-12 00:55:06 -0800514 monitor->datavalid = false;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700515
516 if(crtno) {
Thomas Winischhofer544393f2005-09-09 13:04:45 -0700517 if(ivideo->vbflags & CRT2_LCD) realcrtno = 1;
518 else if(ivideo->vbflags & CRT2_VGA) realcrtno = 2;
519 else return;
520 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700521
Thomas Winischhofer544393f2005-09-09 13:04:45 -0700522 if((ivideo->sisfb_crt1off) && (!crtno))
523 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700524
Thomas Winischhofer544393f2005-09-09 13:04:45 -0700525 temp = SiS_HandleDDC(&ivideo->SiS_Pr, ivideo->vbflags, ivideo->sisvga_engine,
526 realcrtno, 0, &buffer[0], ivideo->vbflags2);
527 if((!temp) || (temp == 0xffff)) {
528 printk(KERN_INFO "sisfb: CRT%d DDC probing failed\n", crtno + 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700529 return;
Thomas Winischhofer544393f2005-09-09 13:04:45 -0700530 } else {
531 printk(KERN_INFO "sisfb: CRT%d DDC supported\n", crtno + 1);
532 printk(KERN_INFO "sisfb: CRT%d DDC level: %s%s%s%s\n",
533 crtno + 1,
534 (temp & 0x1a) ? "" : "[none of the supported]",
535 (temp & 0x02) ? "2 " : "",
536 (temp & 0x08) ? "D&P" : "",
537 (temp & 0x10) ? "FPDI-2" : "");
538 if(temp & 0x02) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700539 i = 3; /* Number of retrys */
540 do {
Thomas Winischhofer544393f2005-09-09 13:04:45 -0700541 temp = SiS_HandleDDC(&ivideo->SiS_Pr, ivideo->vbflags, ivideo->sisvga_engine,
542 realcrtno, 1, &buffer[0], ivideo->vbflags2);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700543 } while((temp) && i--);
Thomas Winischhofer544393f2005-09-09 13:04:45 -0700544 if(!temp) {
545 if(sisfb_interpret_edid(monitor, &buffer[0])) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700546 printk(KERN_INFO "sisfb: Monitor range H %d-%dKHz, V %d-%dHz, Max. dotclock %dMHz\n",
Thomas Winischhofer544393f2005-09-09 13:04:45 -0700547 monitor->hmin, monitor->hmax, monitor->vmin, monitor->vmax,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700548 monitor->dclockmax / 1000);
549 } else {
Thomas Winischhofer544393f2005-09-09 13:04:45 -0700550 printk(KERN_INFO "sisfb: CRT%d DDC EDID corrupt\n", crtno + 1);
551 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700552 } else {
Thomas Winischhofer544393f2005-09-09 13:04:45 -0700553 printk(KERN_INFO "sisfb: CRT%d DDC reading failed\n", crtno + 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700554 }
555 } else {
556 printk(KERN_INFO "sisfb: VESA D&P and FPDI-2 not supported yet\n");
557 }
558 }
559}
560
Thomas Winischhofer544393f2005-09-09 13:04:45 -0700561/* -------------- Mode validation --------------- */
562
Richard Knutssonc30660ea2007-02-12 00:55:06 -0800563static bool
Linus Torvalds1da177e2005-04-16 15:20:36 -0700564sisfb_verify_rate(struct sis_video_info *ivideo, struct sisfb_monitor *monitor,
565 int mode_idx, int rate_idx, int rate)
566{
567 int htotal, vtotal;
568 unsigned int dclock, hsync;
569
Thomas Winischhofer544393f2005-09-09 13:04:45 -0700570 if(!monitor->datavalid)
Richard Knutssonc30660ea2007-02-12 00:55:06 -0800571 return true;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700572
Thomas Winischhofer544393f2005-09-09 13:04:45 -0700573 if(mode_idx < 0)
Richard Knutssonc30660ea2007-02-12 00:55:06 -0800574 return false;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700575
576 /* Skip for 320x200, 320x240, 640x400 */
Thomas Winischhofer544393f2005-09-09 13:04:45 -0700577 switch(sisbios_mode[mode_idx].mode_no[ivideo->mni]) {
578 case 0x59:
579 case 0x41:
580 case 0x4f:
581 case 0x50:
582 case 0x56:
583 case 0x53:
584 case 0x2f:
585 case 0x5d:
586 case 0x5e:
Richard Knutssonc30660ea2007-02-12 00:55:06 -0800587 return true;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700588#ifdef CONFIG_FB_SIS_315
589 case 0x5a:
590 case 0x5b:
Richard Knutssonc30660ea2007-02-12 00:55:06 -0800591 if(ivideo->sisvga_engine == SIS_315_VGA) return true;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700592#endif
Thomas Winischhofer544393f2005-09-09 13:04:45 -0700593 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700594
Thomas Winischhofer544393f2005-09-09 13:04:45 -0700595 if(rate < (monitor->vmin - 1))
Richard Knutssonc30660ea2007-02-12 00:55:06 -0800596 return false;
Thomas Winischhofer544393f2005-09-09 13:04:45 -0700597 if(rate > (monitor->vmax + 1))
Richard Knutssonc30660ea2007-02-12 00:55:06 -0800598 return false;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700599
Thomas Winischhofer544393f2005-09-09 13:04:45 -0700600 if(sisfb_gettotalfrommode(&ivideo->SiS_Pr,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700601 sisbios_mode[mode_idx].mode_no[ivideo->mni],
Thomas Winischhofer544393f2005-09-09 13:04:45 -0700602 &htotal, &vtotal, rate_idx)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700603 dclock = (htotal * vtotal * rate) / 1000;
Thomas Winischhofer544393f2005-09-09 13:04:45 -0700604 if(dclock > (monitor->dclockmax + 1000))
Richard Knutssonc30660ea2007-02-12 00:55:06 -0800605 return false;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700606 hsync = dclock / htotal;
Thomas Winischhofer544393f2005-09-09 13:04:45 -0700607 if(hsync < (monitor->hmin - 1))
Richard Knutssonc30660ea2007-02-12 00:55:06 -0800608 return false;
Thomas Winischhofer544393f2005-09-09 13:04:45 -0700609 if(hsync > (monitor->hmax + 1))
Richard Knutssonc30660ea2007-02-12 00:55:06 -0800610 return false;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700611 } else {
Richard Knutssonc30660ea2007-02-12 00:55:06 -0800612 return false;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700613 }
Richard Knutssonc30660ea2007-02-12 00:55:06 -0800614 return true;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700615}
616
617static int
618sisfb_validate_mode(struct sis_video_info *ivideo, int myindex, u32 vbflags)
619{
Thomas Winischhofer544393f2005-09-09 13:04:45 -0700620 u16 xres=0, yres, myres;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700621
622#ifdef CONFIG_FB_SIS_300
Thomas Winischhofer544393f2005-09-09 13:04:45 -0700623 if(ivideo->sisvga_engine == SIS_300_VGA) {
624 if(!(sisbios_mode[myindex].chipset & MD_SIS300))
625 return -1 ;
626 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700627#endif
628#ifdef CONFIG_FB_SIS_315
Thomas Winischhofer544393f2005-09-09 13:04:45 -0700629 if(ivideo->sisvga_engine == SIS_315_VGA) {
630 if(!(sisbios_mode[myindex].chipset & MD_SIS315))
631 return -1;
632 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700633#endif
634
Thomas Winischhofer544393f2005-09-09 13:04:45 -0700635 myres = sisbios_mode[myindex].yres;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700636
Thomas Winischhofer544393f2005-09-09 13:04:45 -0700637 switch(vbflags & VB_DISPTYPE_DISP2) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700638
Thomas Winischhofer544393f2005-09-09 13:04:45 -0700639 case CRT2_LCD:
640 xres = ivideo->lcdxres; yres = ivideo->lcdyres;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700641
Thomas Winischhofer544393f2005-09-09 13:04:45 -0700642 if((ivideo->SiS_Pr.SiS_CustomT != CUT_PANEL848) &&
643 (ivideo->SiS_Pr.SiS_CustomT != CUT_PANEL856)) {
644 if(sisbios_mode[myindex].xres > xres)
645 return -1;
646 if(myres > yres)
647 return -1;
648 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700649
Thomas Winischhofer544393f2005-09-09 13:04:45 -0700650 if(ivideo->sisfb_fstn) {
651 if(sisbios_mode[myindex].xres == 320) {
652 if(myres == 240) {
653 switch(sisbios_mode[myindex].mode_no[1]) {
654 case 0x50: myindex = MODE_FSTN_8; break;
655 case 0x56: myindex = MODE_FSTN_16; break;
656 case 0x53: return -1;
657 }
658 }
659 }
660 }
661
662 if(SiS_GetModeID_LCD(ivideo->sisvga_engine, vbflags, sisbios_mode[myindex].xres,
663 sisbios_mode[myindex].yres, 0, ivideo->sisfb_fstn,
664 ivideo->SiS_Pr.SiS_CustomT, xres, yres, ivideo->vbflags2) < 0x14) {
665 return -1;
666 }
667 break;
668
669 case CRT2_TV:
670 if(SiS_GetModeID_TV(ivideo->sisvga_engine, vbflags, sisbios_mode[myindex].xres,
671 sisbios_mode[myindex].yres, 0, ivideo->vbflags2) < 0x14) {
672 return -1;
673 }
674 break;
675
676 case CRT2_VGA:
677 if(SiS_GetModeID_VGA2(ivideo->sisvga_engine, vbflags, sisbios_mode[myindex].xres,
678 sisbios_mode[myindex].yres, 0, ivideo->vbflags2) < 0x14) {
679 return -1;
680 }
681 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700682 }
683
Thomas Winischhofer544393f2005-09-09 13:04:45 -0700684 return myindex;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700685}
686
687static u8
688sisfb_search_refresh_rate(struct sis_video_info *ivideo, unsigned int rate, int mode_idx)
689{
Linus Torvalds1da177e2005-04-16 15:20:36 -0700690 int i = 0;
Thomas Winischhofer544393f2005-09-09 13:04:45 -0700691 u16 xres = sisbios_mode[mode_idx].xres;
692 u16 yres = sisbios_mode[mode_idx].yres;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700693
694 ivideo->rate_idx = 0;
695 while((sisfb_vrate[i].idx != 0) && (sisfb_vrate[i].xres <= xres)) {
696 if((sisfb_vrate[i].xres == xres) && (sisfb_vrate[i].yres == yres)) {
697 if(sisfb_vrate[i].refresh == rate) {
698 ivideo->rate_idx = sisfb_vrate[i].idx;
699 break;
700 } else if(sisfb_vrate[i].refresh > rate) {
701 if((sisfb_vrate[i].refresh - rate) <= 3) {
702 DPRINTK("sisfb: Adjusting rate from %d up to %d\n",
703 rate, sisfb_vrate[i].refresh);
704 ivideo->rate_idx = sisfb_vrate[i].idx;
705 ivideo->refresh_rate = sisfb_vrate[i].refresh;
Roel Kluind63870d2009-09-22 16:47:07 -0700706 } else if((sisfb_vrate[i].idx != 1) &&
707 ((rate - sisfb_vrate[i-1].refresh) <= 2)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700708 DPRINTK("sisfb: Adjusting rate from %d down to %d\n",
709 rate, sisfb_vrate[i-1].refresh);
710 ivideo->rate_idx = sisfb_vrate[i-1].idx;
711 ivideo->refresh_rate = sisfb_vrate[i-1].refresh;
Thomas Winischhofer544393f2005-09-09 13:04:45 -0700712 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700713 break;
714 } else if((rate - sisfb_vrate[i].refresh) <= 2) {
715 DPRINTK("sisfb: Adjusting rate from %d down to %d\n",
716 rate, sisfb_vrate[i].refresh);
Thomas Winischhofer544393f2005-09-09 13:04:45 -0700717 ivideo->rate_idx = sisfb_vrate[i].idx;
718 break;
719 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700720 }
721 i++;
722 }
723 if(ivideo->rate_idx > 0) {
724 return ivideo->rate_idx;
725 } else {
726 printk(KERN_INFO "sisfb: Unsupported rate %d for %dx%d\n",
727 rate, xres, yres);
728 return 0;
729 }
730}
731
Richard Knutssonc30660ea2007-02-12 00:55:06 -0800732static bool
Linus Torvalds1da177e2005-04-16 15:20:36 -0700733sisfb_bridgeisslave(struct sis_video_info *ivideo)
734{
Thomas Winischhofer544393f2005-09-09 13:04:45 -0700735 unsigned char P1_00;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700736
Thomas Winischhofer544393f2005-09-09 13:04:45 -0700737 if(!(ivideo->vbflags2 & VB2_VIDEOBRIDGE))
Richard Knutssonc30660ea2007-02-12 00:55:06 -0800738 return false;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700739
Aaro Koskinene57d4132010-12-20 23:50:16 +0200740 P1_00 = SiS_GetReg(SISPART1, 0x00);
Thomas Winischhofer544393f2005-09-09 13:04:45 -0700741 if( ((ivideo->sisvga_engine == SIS_300_VGA) && (P1_00 & 0xa0) == 0x20) ||
742 ((ivideo->sisvga_engine == SIS_315_VGA) && (P1_00 & 0x50) == 0x10) ) {
Richard Knutssonc30660ea2007-02-12 00:55:06 -0800743 return true;
Thomas Winischhofer544393f2005-09-09 13:04:45 -0700744 } else {
Richard Knutssonc30660ea2007-02-12 00:55:06 -0800745 return false;
Thomas Winischhofer544393f2005-09-09 13:04:45 -0700746 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700747}
748
Richard Knutssonc30660ea2007-02-12 00:55:06 -0800749static bool
Linus Torvalds1da177e2005-04-16 15:20:36 -0700750sisfballowretracecrt1(struct sis_video_info *ivideo)
751{
Thomas Winischhofer544393f2005-09-09 13:04:45 -0700752 u8 temp;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700753
Aaro Koskinene57d4132010-12-20 23:50:16 +0200754 temp = SiS_GetReg(SISCR, 0x17);
Thomas Winischhofer544393f2005-09-09 13:04:45 -0700755 if(!(temp & 0x80))
Richard Knutssonc30660ea2007-02-12 00:55:06 -0800756 return false;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700757
Aaro Koskinene57d4132010-12-20 23:50:16 +0200758 temp = SiS_GetReg(SISSR, 0x1f);
Thomas Winischhofer544393f2005-09-09 13:04:45 -0700759 if(temp & 0xc0)
Richard Knutssonc30660ea2007-02-12 00:55:06 -0800760 return false;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700761
Richard Knutssonc30660ea2007-02-12 00:55:06 -0800762 return true;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700763}
764
Richard Knutssonc30660ea2007-02-12 00:55:06 -0800765static bool
Linus Torvalds1da177e2005-04-16 15:20:36 -0700766sisfbcheckvretracecrt1(struct sis_video_info *ivideo)
767{
Thomas Winischhofer544393f2005-09-09 13:04:45 -0700768 if(!sisfballowretracecrt1(ivideo))
Richard Knutssonc30660ea2007-02-12 00:55:06 -0800769 return false;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700770
Aaro Koskinen1e1687d2010-12-20 23:50:14 +0200771 if (SiS_GetRegByte(SISINPSTAT) & 0x08)
Richard Knutssonc30660ea2007-02-12 00:55:06 -0800772 return true;
Thomas Winischhofer544393f2005-09-09 13:04:45 -0700773 else
Richard Knutssonc30660ea2007-02-12 00:55:06 -0800774 return false;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700775}
776
777static void
778sisfbwaitretracecrt1(struct sis_video_info *ivideo)
779{
Thomas Winischhofer544393f2005-09-09 13:04:45 -0700780 int watchdog;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700781
Thomas Winischhofer544393f2005-09-09 13:04:45 -0700782 if(!sisfballowretracecrt1(ivideo))
783 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700784
Thomas Winischhofer544393f2005-09-09 13:04:45 -0700785 watchdog = 65536;
Aaro Koskinen1e1687d2010-12-20 23:50:14 +0200786 while ((!(SiS_GetRegByte(SISINPSTAT) & 0x08)) && --watchdog);
Thomas Winischhofer544393f2005-09-09 13:04:45 -0700787 watchdog = 65536;
Aaro Koskinen1e1687d2010-12-20 23:50:14 +0200788 while ((SiS_GetRegByte(SISINPSTAT) & 0x08) && --watchdog);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700789}
790
Richard Knutssonc30660ea2007-02-12 00:55:06 -0800791static bool
Linus Torvalds1da177e2005-04-16 15:20:36 -0700792sisfbcheckvretracecrt2(struct sis_video_info *ivideo)
793{
Thomas Winischhofer544393f2005-09-09 13:04:45 -0700794 unsigned char temp, reg;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700795
Thomas Winischhofer544393f2005-09-09 13:04:45 -0700796 switch(ivideo->sisvga_engine) {
797 case SIS_300_VGA: reg = 0x25; break;
798 case SIS_315_VGA: reg = 0x30; break;
Richard Knutssonc30660ea2007-02-12 00:55:06 -0800799 default: return false;
Thomas Winischhofer544393f2005-09-09 13:04:45 -0700800 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700801
Aaro Koskinene57d4132010-12-20 23:50:16 +0200802 temp = SiS_GetReg(SISPART1, reg);
Thomas Winischhofer544393f2005-09-09 13:04:45 -0700803 if(temp & 0x02)
Richard Knutssonc30660ea2007-02-12 00:55:06 -0800804 return true;
Thomas Winischhofer544393f2005-09-09 13:04:45 -0700805 else
Richard Knutssonc30660ea2007-02-12 00:55:06 -0800806 return false;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700807}
808
Richard Knutssonc30660ea2007-02-12 00:55:06 -0800809static bool
Linus Torvalds1da177e2005-04-16 15:20:36 -0700810sisfb_CheckVBRetrace(struct sis_video_info *ivideo)
811{
Thomas Winischhofer544393f2005-09-09 13:04:45 -0700812 if(ivideo->currentvbflags & VB_DISPTYPE_DISP2) {
813 if(!sisfb_bridgeisslave(ivideo)) {
814 return sisfbcheckvretracecrt2(ivideo);
815 }
816 }
817 return sisfbcheckvretracecrt1(ivideo);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700818}
819
820static u32
821sisfb_setupvbblankflags(struct sis_video_info *ivideo, u32 *vcount, u32 *hcount)
822{
Thomas Winischhofer544393f2005-09-09 13:04:45 -0700823 u8 idx, reg1, reg2, reg3, reg4;
824 u32 ret = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700825
Thomas Winischhofer544393f2005-09-09 13:04:45 -0700826 (*vcount) = (*hcount) = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700827
Thomas Winischhofer544393f2005-09-09 13:04:45 -0700828 if((ivideo->currentvbflags & VB_DISPTYPE_DISP2) && (!(sisfb_bridgeisslave(ivideo)))) {
829
830 ret |= (FB_VBLANK_HAVE_VSYNC |
831 FB_VBLANK_HAVE_HBLANK |
832 FB_VBLANK_HAVE_VBLANK |
833 FB_VBLANK_HAVE_VCOUNT |
834 FB_VBLANK_HAVE_HCOUNT);
835 switch(ivideo->sisvga_engine) {
836 case SIS_300_VGA: idx = 0x25; break;
837 default:
838 case SIS_315_VGA: idx = 0x30; break;
839 }
Aaro Koskinene57d4132010-12-20 23:50:16 +0200840 reg1 = SiS_GetReg(SISPART1, (idx+0)); /* 30 */
841 reg2 = SiS_GetReg(SISPART1, (idx+1)); /* 31 */
842 reg3 = SiS_GetReg(SISPART1, (idx+2)); /* 32 */
843 reg4 = SiS_GetReg(SISPART1, (idx+3)); /* 33 */
Thomas Winischhofer544393f2005-09-09 13:04:45 -0700844 if(reg1 & 0x01) ret |= FB_VBLANK_VBLANKING;
845 if(reg1 & 0x02) ret |= FB_VBLANK_VSYNCING;
846 if(reg4 & 0x80) ret |= FB_VBLANK_HBLANKING;
847 (*vcount) = reg3 | ((reg4 & 0x70) << 4);
848 (*hcount) = reg2 | ((reg4 & 0x0f) << 8);
849
850 } else if(sisfballowretracecrt1(ivideo)) {
851
852 ret |= (FB_VBLANK_HAVE_VSYNC |
853 FB_VBLANK_HAVE_VBLANK |
854 FB_VBLANK_HAVE_VCOUNT |
855 FB_VBLANK_HAVE_HCOUNT);
Aaro Koskinen1e1687d2010-12-20 23:50:14 +0200856 reg1 = SiS_GetRegByte(SISINPSTAT);
Thomas Winischhofer544393f2005-09-09 13:04:45 -0700857 if(reg1 & 0x08) ret |= FB_VBLANK_VSYNCING;
858 if(reg1 & 0x01) ret |= FB_VBLANK_VBLANKING;
Aaro Koskinene57d4132010-12-20 23:50:16 +0200859 reg1 = SiS_GetReg(SISCR, 0x20);
860 reg1 = SiS_GetReg(SISCR, 0x1b);
861 reg2 = SiS_GetReg(SISCR, 0x1c);
862 reg3 = SiS_GetReg(SISCR, 0x1d);
Thomas Winischhofer544393f2005-09-09 13:04:45 -0700863 (*vcount) = reg2 | ((reg3 & 0x07) << 8);
864 (*hcount) = (reg1 | ((reg3 & 0x10) << 4)) << 3;
865 }
866
867 return ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700868}
869
870static int
871sisfb_myblank(struct sis_video_info *ivideo, int blank)
872{
Thomas Winischhofer544393f2005-09-09 13:04:45 -0700873 u8 sr01, sr11, sr1f, cr63=0, p2_0, p1_13;
Richard Knutssonc30660ea2007-02-12 00:55:06 -0800874 bool backlight = true;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700875
Thomas Winischhofer544393f2005-09-09 13:04:45 -0700876 switch(blank) {
877 case FB_BLANK_UNBLANK: /* on */
878 sr01 = 0x00;
879 sr11 = 0x00;
880 sr1f = 0x00;
881 cr63 = 0x00;
882 p2_0 = 0x20;
883 p1_13 = 0x00;
Richard Knutssonc30660ea2007-02-12 00:55:06 -0800884 backlight = true;
Thomas Winischhofer544393f2005-09-09 13:04:45 -0700885 break;
886 case FB_BLANK_NORMAL: /* blank */
887 sr01 = 0x20;
888 sr11 = 0x00;
889 sr1f = 0x00;
890 cr63 = 0x00;
891 p2_0 = 0x20;
892 p1_13 = 0x00;
Richard Knutssonc30660ea2007-02-12 00:55:06 -0800893 backlight = true;
Thomas Winischhofer544393f2005-09-09 13:04:45 -0700894 break;
895 case FB_BLANK_VSYNC_SUSPEND: /* no vsync */
896 sr01 = 0x20;
897 sr11 = 0x08;
898 sr1f = 0x80;
899 cr63 = 0x40;
900 p2_0 = 0x40;
901 p1_13 = 0x80;
Richard Knutssonc30660ea2007-02-12 00:55:06 -0800902 backlight = false;
Thomas Winischhofer544393f2005-09-09 13:04:45 -0700903 break;
904 case FB_BLANK_HSYNC_SUSPEND: /* no hsync */
905 sr01 = 0x20;
906 sr11 = 0x08;
907 sr1f = 0x40;
908 cr63 = 0x40;
909 p2_0 = 0x80;
910 p1_13 = 0x40;
Richard Knutssonc30660ea2007-02-12 00:55:06 -0800911 backlight = false;
Thomas Winischhofer544393f2005-09-09 13:04:45 -0700912 break;
913 case FB_BLANK_POWERDOWN: /* off */
914 sr01 = 0x20;
915 sr11 = 0x08;
916 sr1f = 0xc0;
917 cr63 = 0x40;
918 p2_0 = 0xc0;
919 p1_13 = 0xc0;
Richard Knutssonc30660ea2007-02-12 00:55:06 -0800920 backlight = false;
Thomas Winischhofer544393f2005-09-09 13:04:45 -0700921 break;
922 default:
923 return 1;
924 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700925
Thomas Winischhofer544393f2005-09-09 13:04:45 -0700926 if(ivideo->currentvbflags & VB_DISPTYPE_CRT1) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700927
Thomas Winischhofer544393f2005-09-09 13:04:45 -0700928 if( (!ivideo->sisfb_thismonitor.datavalid) ||
929 ((ivideo->sisfb_thismonitor.datavalid) &&
930 (ivideo->sisfb_thismonitor.feature & 0xe0))) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700931
Thomas Winischhofer544393f2005-09-09 13:04:45 -0700932 if(ivideo->sisvga_engine == SIS_315_VGA) {
Aaro Koskinenad78adb2010-12-20 23:50:20 +0200933 SiS_SetRegANDOR(SISCR, ivideo->SiS_Pr.SiS_MyCR63, 0xbf, cr63);
Thomas Winischhofer544393f2005-09-09 13:04:45 -0700934 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700935
Thomas Winischhofer544393f2005-09-09 13:04:45 -0700936 if(!(sisfb_bridgeisslave(ivideo))) {
Aaro Koskinenad78adb2010-12-20 23:50:20 +0200937 SiS_SetRegANDOR(SISSR, 0x01, ~0x20, sr01);
938 SiS_SetRegANDOR(SISSR, 0x1f, 0x3f, sr1f);
Thomas Winischhofer544393f2005-09-09 13:04:45 -0700939 }
940 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700941
Thomas Winischhofer544393f2005-09-09 13:04:45 -0700942 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700943
Thomas Winischhofer544393f2005-09-09 13:04:45 -0700944 if(ivideo->currentvbflags & CRT2_LCD) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700945
Thomas Winischhofer544393f2005-09-09 13:04:45 -0700946 if(ivideo->vbflags2 & VB2_SISLVDSBRIDGE) {
947 if(backlight) {
948 SiS_SiS30xBLOn(&ivideo->SiS_Pr);
949 } else {
950 SiS_SiS30xBLOff(&ivideo->SiS_Pr);
951 }
952 } else if(ivideo->sisvga_engine == SIS_315_VGA) {
953#ifdef CONFIG_FB_SIS_315
954 if(ivideo->vbflags2 & VB2_CHRONTEL) {
955 if(backlight) {
956 SiS_Chrontel701xBLOn(&ivideo->SiS_Pr);
957 } else {
958 SiS_Chrontel701xBLOff(&ivideo->SiS_Pr);
959 }
960 }
961#endif
962 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700963
Thomas Winischhofer544393f2005-09-09 13:04:45 -0700964 if(((ivideo->sisvga_engine == SIS_300_VGA) &&
965 (ivideo->vbflags2 & (VB2_301|VB2_30xBDH|VB2_LVDS))) ||
966 ((ivideo->sisvga_engine == SIS_315_VGA) &&
967 ((ivideo->vbflags2 & (VB2_LVDS | VB2_CHRONTEL)) == VB2_LVDS))) {
Aaro Koskinenad78adb2010-12-20 23:50:20 +0200968 SiS_SetRegANDOR(SISSR, 0x11, ~0x0c, sr11);
Thomas Winischhofer544393f2005-09-09 13:04:45 -0700969 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700970
Thomas Winischhofer544393f2005-09-09 13:04:45 -0700971 if(ivideo->sisvga_engine == SIS_300_VGA) {
972 if((ivideo->vbflags2 & VB2_30xB) &&
973 (!(ivideo->vbflags2 & VB2_30xBDH))) {
Aaro Koskinenad78adb2010-12-20 23:50:20 +0200974 SiS_SetRegANDOR(SISPART1, 0x13, 0x3f, p1_13);
Thomas Winischhofer544393f2005-09-09 13:04:45 -0700975 }
976 } else if(ivideo->sisvga_engine == SIS_315_VGA) {
977 if((ivideo->vbflags2 & VB2_30xB) &&
978 (!(ivideo->vbflags2 & VB2_30xBDH))) {
Aaro Koskinenad78adb2010-12-20 23:50:20 +0200979 SiS_SetRegANDOR(SISPART2, 0x00, 0x1f, p2_0);
Thomas Winischhofer544393f2005-09-09 13:04:45 -0700980 }
981 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700982
Thomas Winischhofer544393f2005-09-09 13:04:45 -0700983 } else if(ivideo->currentvbflags & CRT2_VGA) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700984
Thomas Winischhofer544393f2005-09-09 13:04:45 -0700985 if(ivideo->vbflags2 & VB2_30xB) {
Aaro Koskinenad78adb2010-12-20 23:50:20 +0200986 SiS_SetRegANDOR(SISPART2, 0x00, 0x1f, p2_0);
Thomas Winischhofer544393f2005-09-09 13:04:45 -0700987 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700988
Thomas Winischhofer544393f2005-09-09 13:04:45 -0700989 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700990
Thomas Winischhofer544393f2005-09-09 13:04:45 -0700991 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700992}
993
Thomas Winischhofer544393f2005-09-09 13:04:45 -0700994/* ------------- Callbacks from init.c/init301.c -------------- */
995
996#ifdef CONFIG_FB_SIS_300
997unsigned int
998sisfb_read_nbridge_pci_dword(struct SiS_Private *SiS_Pr, int reg)
999{
1000 struct sis_video_info *ivideo = (struct sis_video_info *)SiS_Pr->ivideo;
1001 u32 val = 0;
1002
1003 pci_read_config_dword(ivideo->nbridge, reg, &val);
1004 return (unsigned int)val;
1005}
1006
1007void
1008sisfb_write_nbridge_pci_dword(struct SiS_Private *SiS_Pr, int reg, unsigned int val)
1009{
1010 struct sis_video_info *ivideo = (struct sis_video_info *)SiS_Pr->ivideo;
1011
1012 pci_write_config_dword(ivideo->nbridge, reg, (u32)val);
1013}
1014
1015unsigned int
1016sisfb_read_lpc_pci_dword(struct SiS_Private *SiS_Pr, int reg)
1017{
1018 struct sis_video_info *ivideo = (struct sis_video_info *)SiS_Pr->ivideo;
1019 u32 val = 0;
1020
1021 if(!ivideo->lpcdev) return 0;
1022
1023 pci_read_config_dword(ivideo->lpcdev, reg, &val);
1024 return (unsigned int)val;
1025}
1026#endif
1027
1028#ifdef CONFIG_FB_SIS_315
1029void
1030sisfb_write_nbridge_pci_byte(struct SiS_Private *SiS_Pr, int reg, unsigned char val)
1031{
1032 struct sis_video_info *ivideo = (struct sis_video_info *)SiS_Pr->ivideo;
1033
1034 pci_write_config_byte(ivideo->nbridge, reg, (u8)val);
1035}
1036
1037unsigned int
1038sisfb_read_mio_pci_word(struct SiS_Private *SiS_Pr, int reg)
1039{
1040 struct sis_video_info *ivideo = (struct sis_video_info *)SiS_Pr->ivideo;
1041 u16 val = 0;
1042
1043 if(!ivideo->lpcdev) return 0;
1044
1045 pci_read_config_word(ivideo->lpcdev, reg, &val);
1046 return (unsigned int)val;
1047}
1048#endif
1049
Linus Torvalds1da177e2005-04-16 15:20:36 -07001050/* ----------- FBDev related routines for all series ----------- */
1051
1052static int
1053sisfb_get_cmap_len(const struct fb_var_screeninfo *var)
1054{
1055 return (var->bits_per_pixel == 8) ? 256 : 16;
1056}
1057
1058static void
1059sisfb_set_vparms(struct sis_video_info *ivideo)
1060{
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001061 switch(ivideo->video_bpp) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001062 case 8:
1063 ivideo->DstColor = 0x0000;
1064 ivideo->SiS310_AccelDepth = 0x00000000;
1065 ivideo->video_cmap_len = 256;
1066 break;
1067 case 16:
1068 ivideo->DstColor = 0x8000;
1069 ivideo->SiS310_AccelDepth = 0x00010000;
1070 ivideo->video_cmap_len = 16;
1071 break;
1072 case 32:
1073 ivideo->DstColor = 0xC000;
1074 ivideo->SiS310_AccelDepth = 0x00020000;
1075 ivideo->video_cmap_len = 16;
1076 break;
1077 default:
1078 ivideo->video_cmap_len = 16;
1079 printk(KERN_ERR "sisfb: Unsupported depth %d", ivideo->video_bpp);
1080 ivideo->accel = 0;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001081 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001082}
1083
1084static int
1085sisfb_calc_maxyres(struct sis_video_info *ivideo, struct fb_var_screeninfo *var)
1086{
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001087 int maxyres = ivideo->sisfb_mem / (var->xres_virtual * (var->bits_per_pixel >> 3));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001088
1089 if(maxyres > 32767) maxyres = 32767;
1090
1091 return maxyres;
1092}
1093
1094static void
1095sisfb_calc_pitch(struct sis_video_info *ivideo, struct fb_var_screeninfo *var)
1096{
1097 ivideo->video_linelength = var->xres_virtual * (var->bits_per_pixel >> 3);
1098 ivideo->scrnpitchCRT1 = ivideo->video_linelength;
1099 if(!(ivideo->currentvbflags & CRT1_LCDA)) {
1100 if((var->vmode & FB_VMODE_MASK) == FB_VMODE_INTERLACED) {
1101 ivideo->scrnpitchCRT1 <<= 1;
1102 }
1103 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001104}
1105
1106static void
1107sisfb_set_pitch(struct sis_video_info *ivideo)
1108{
Richard Knutssonc30660ea2007-02-12 00:55:06 -08001109 bool isslavemode = false;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001110 unsigned short HDisplay1 = ivideo->scrnpitchCRT1 >> 3;
1111 unsigned short HDisplay2 = ivideo->video_linelength >> 3;
1112
Richard Knutssonc30660ea2007-02-12 00:55:06 -08001113 if(sisfb_bridgeisslave(ivideo)) isslavemode = true;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001114
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001115 /* We need to set pitch for CRT1 if bridge is in slave mode, too */
1116 if((ivideo->currentvbflags & VB_DISPTYPE_DISP1) || (isslavemode)) {
Aaro Koskinen44b751b2010-12-20 23:50:17 +02001117 SiS_SetReg(SISCR, 0x13, (HDisplay1 & 0xFF));
Aaro Koskinenad78adb2010-12-20 23:50:20 +02001118 SiS_SetRegANDOR(SISSR, 0x0E, 0xF0, (HDisplay1 >> 8));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001119 }
1120
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001121 /* We must not set the pitch for CRT2 if bridge is in slave mode */
1122 if((ivideo->currentvbflags & VB_DISPTYPE_DISP2) && (!isslavemode)) {
Aaro Koskinen27799d62010-12-20 23:50:18 +02001123 SiS_SetRegOR(SISPART1, ivideo->CRT2_write_enable, 0x01);
Aaro Koskinen44b751b2010-12-20 23:50:17 +02001124 SiS_SetReg(SISPART1, 0x07, (HDisplay2 & 0xFF));
Aaro Koskinenad78adb2010-12-20 23:50:20 +02001125 SiS_SetRegANDOR(SISPART1, 0x09, 0xF0, (HDisplay2 >> 8));
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001126 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001127}
1128
1129static void
1130sisfb_bpp_to_var(struct sis_video_info *ivideo, struct fb_var_screeninfo *var)
1131{
1132 ivideo->video_cmap_len = sisfb_get_cmap_len(var);
1133
1134 switch(var->bits_per_pixel) {
1135 case 8:
1136 var->red.offset = var->green.offset = var->blue.offset = 0;
Michal Januszewski811a2012009-04-13 14:39:52 -07001137 var->red.length = var->green.length = var->blue.length = 8;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001138 break;
1139 case 16:
1140 var->red.offset = 11;
1141 var->red.length = 5;
1142 var->green.offset = 5;
1143 var->green.length = 6;
1144 var->blue.offset = 0;
1145 var->blue.length = 5;
1146 var->transp.offset = 0;
1147 var->transp.length = 0;
1148 break;
1149 case 32:
1150 var->red.offset = 16;
1151 var->red.length = 8;
1152 var->green.offset = 8;
1153 var->green.length = 8;
1154 var->blue.offset = 0;
1155 var->blue.length = 8;
1156 var->transp.offset = 24;
1157 var->transp.length = 8;
1158 break;
1159 }
1160}
1161
1162static int
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001163sisfb_set_mode(struct sis_video_info *ivideo, int clrscrn)
1164{
1165 unsigned short modeno = ivideo->mode_no;
1166
1167 /* >=2.6.12's fbcon clears the screen anyway */
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001168 modeno |= 0x80;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001169
Aaro Koskinen44b751b2010-12-20 23:50:17 +02001170 SiS_SetReg(SISSR, IND_SIS_PASSWORD, SIS_PASSWORD);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001171
1172 sisfb_pre_setmode(ivideo);
1173
Richard Knutssonc30660ea2007-02-12 00:55:06 -08001174 if(!SiSSetMode(&ivideo->SiS_Pr, modeno)) {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001175 printk(KERN_ERR "sisfb: Setting mode[0x%x] failed\n", ivideo->mode_no);
1176 return -EINVAL;
1177 }
1178
Aaro Koskinen44b751b2010-12-20 23:50:17 +02001179 SiS_SetReg(SISSR, IND_SIS_PASSWORD, SIS_PASSWORD);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001180
1181 sisfb_post_setmode(ivideo);
1182
1183 return 0;
1184}
1185
1186
1187static int
Linus Torvalds1da177e2005-04-16 15:20:36 -07001188sisfb_do_set_var(struct fb_var_screeninfo *var, int isactive, struct fb_info *info)
1189{
1190 struct sis_video_info *ivideo = (struct sis_video_info *)info->par;
1191 unsigned int htotal = 0, vtotal = 0;
1192 unsigned int drate = 0, hrate = 0;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001193 int found_mode = 0, ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001194 int old_mode;
1195 u32 pixclock;
1196
1197 htotal = var->left_margin + var->xres + var->right_margin + var->hsync_len;
1198
1199 vtotal = var->upper_margin + var->lower_margin + var->vsync_len;
1200
1201 pixclock = var->pixclock;
1202
1203 if((var->vmode & FB_VMODE_MASK) == FB_VMODE_NONINTERLACED) {
1204 vtotal += var->yres;
1205 vtotal <<= 1;
1206 } else if((var->vmode & FB_VMODE_MASK) == FB_VMODE_DOUBLE) {
1207 vtotal += var->yres;
1208 vtotal <<= 2;
1209 } else if((var->vmode & FB_VMODE_MASK) == FB_VMODE_INTERLACED) {
1210 vtotal += var->yres;
1211 vtotal <<= 1;
1212 } else vtotal += var->yres;
1213
1214 if(!(htotal) || !(vtotal)) {
1215 DPRINTK("sisfb: Invalid 'var' information\n");
1216 return -EINVAL;
1217 }
1218
1219 if(pixclock && htotal && vtotal) {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001220 drate = 1000000000 / pixclock;
1221 hrate = (drate * 1000) / htotal;
1222 ivideo->refresh_rate = (unsigned int) (hrate * 2 / vtotal);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001223 } else {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001224 ivideo->refresh_rate = 60;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001225 }
1226
1227 old_mode = ivideo->sisfb_mode_idx;
1228 ivideo->sisfb_mode_idx = 0;
1229
1230 while( (sisbios_mode[ivideo->sisfb_mode_idx].mode_no[0] != 0) &&
1231 (sisbios_mode[ivideo->sisfb_mode_idx].xres <= var->xres) ) {
1232 if( (sisbios_mode[ivideo->sisfb_mode_idx].xres == var->xres) &&
1233 (sisbios_mode[ivideo->sisfb_mode_idx].yres == var->yres) &&
1234 (sisbios_mode[ivideo->sisfb_mode_idx].bpp == var->bits_per_pixel)) {
1235 ivideo->mode_no = sisbios_mode[ivideo->sisfb_mode_idx].mode_no[ivideo->mni];
1236 found_mode = 1;
1237 break;
1238 }
1239 ivideo->sisfb_mode_idx++;
1240 }
1241
1242 if(found_mode) {
1243 ivideo->sisfb_mode_idx = sisfb_validate_mode(ivideo,
1244 ivideo->sisfb_mode_idx, ivideo->currentvbflags);
1245 } else {
1246 ivideo->sisfb_mode_idx = -1;
1247 }
1248
1249 if(ivideo->sisfb_mode_idx < 0) {
1250 printk(KERN_ERR "sisfb: Mode %dx%dx%d not supported\n", var->xres,
1251 var->yres, var->bits_per_pixel);
1252 ivideo->sisfb_mode_idx = old_mode;
1253 return -EINVAL;
1254 }
1255
Adrian Bunka9e60e52007-11-14 16:59:02 -08001256 ivideo->mode_no = sisbios_mode[ivideo->sisfb_mode_idx].mode_no[ivideo->mni];
1257
Linus Torvalds1da177e2005-04-16 15:20:36 -07001258 if(sisfb_search_refresh_rate(ivideo, ivideo->refresh_rate, ivideo->sisfb_mode_idx) == 0) {
1259 ivideo->rate_idx = sisbios_mode[ivideo->sisfb_mode_idx].rate_idx;
1260 ivideo->refresh_rate = 60;
1261 }
1262
Linus Torvalds1da177e2005-04-16 15:20:36 -07001263 if(isactive) {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001264 /* If acceleration to be used? Need to know
1265 * before pre/post_set_mode()
1266 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001267 ivideo->accel = 0;
1268#if defined(FBINFO_HWACCEL_DISABLED) && defined(FBINFO_HWACCEL_XPAN)
1269#ifdef STUPID_ACCELF_TEXT_SHIT
1270 if(var->accel_flags & FB_ACCELF_TEXT) {
1271 info->flags &= ~FBINFO_HWACCEL_DISABLED;
1272 } else {
1273 info->flags |= FBINFO_HWACCEL_DISABLED;
1274 }
1275#endif
1276 if(!(info->flags & FBINFO_HWACCEL_DISABLED)) ivideo->accel = -1;
1277#else
1278 if(var->accel_flags & FB_ACCELF_TEXT) ivideo->accel = -1;
1279#endif
1280
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001281 if((ret = sisfb_set_mode(ivideo, 1))) {
1282 return ret;
1283 }
1284
1285 ivideo->video_bpp = sisbios_mode[ivideo->sisfb_mode_idx].bpp;
1286 ivideo->video_width = sisbios_mode[ivideo->sisfb_mode_idx].xres;
1287 ivideo->video_height = sisbios_mode[ivideo->sisfb_mode_idx].yres;
1288
1289 sisfb_calc_pitch(ivideo, var);
1290 sisfb_set_pitch(ivideo);
1291
Linus Torvalds1da177e2005-04-16 15:20:36 -07001292 sisfb_set_vparms(ivideo);
1293
1294 ivideo->current_width = ivideo->video_width;
1295 ivideo->current_height = ivideo->video_height;
1296 ivideo->current_bpp = ivideo->video_bpp;
1297 ivideo->current_htotal = htotal;
1298 ivideo->current_vtotal = vtotal;
1299 ivideo->current_linelength = ivideo->video_linelength;
1300 ivideo->current_pixclock = var->pixclock;
1301 ivideo->current_refresh_rate = ivideo->refresh_rate;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001302 ivideo->sisfb_lastrates[ivideo->mode_no] = ivideo->refresh_rate;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001303 }
1304
1305 return 0;
1306}
1307
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001308static void
1309sisfb_set_base_CRT1(struct sis_video_info *ivideo, unsigned int base)
1310{
Aaro Koskinen44b751b2010-12-20 23:50:17 +02001311 SiS_SetReg(SISSR, IND_SIS_PASSWORD, SIS_PASSWORD);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001312
Aaro Koskinen44b751b2010-12-20 23:50:17 +02001313 SiS_SetReg(SISCR, 0x0D, base & 0xFF);
1314 SiS_SetReg(SISCR, 0x0C, (base >> 8) & 0xFF);
1315 SiS_SetReg(SISSR, 0x0D, (base >> 16) & 0xFF);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001316 if(ivideo->sisvga_engine == SIS_315_VGA) {
Aaro Koskinenad78adb2010-12-20 23:50:20 +02001317 SiS_SetRegANDOR(SISSR, 0x37, 0xFE, (base >> 24) & 0x01);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001318 }
1319}
1320
1321static void
1322sisfb_set_base_CRT2(struct sis_video_info *ivideo, unsigned int base)
1323{
1324 if(ivideo->currentvbflags & VB_DISPTYPE_DISP2) {
Aaro Koskinen27799d62010-12-20 23:50:18 +02001325 SiS_SetRegOR(SISPART1, ivideo->CRT2_write_enable, 0x01);
Aaro Koskinen44b751b2010-12-20 23:50:17 +02001326 SiS_SetReg(SISPART1, 0x06, (base & 0xFF));
1327 SiS_SetReg(SISPART1, 0x05, ((base >> 8) & 0xFF));
1328 SiS_SetReg(SISPART1, 0x04, ((base >> 16) & 0xFF));
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001329 if(ivideo->sisvga_engine == SIS_315_VGA) {
Aaro Koskinenad78adb2010-12-20 23:50:20 +02001330 SiS_SetRegANDOR(SISPART1, 0x02, 0x7F, ((base >> 24) & 0x01) << 7);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001331 }
1332 }
1333}
1334
Linus Torvalds1da177e2005-04-16 15:20:36 -07001335static int
Laurent Pinchart8e42a962011-05-25 11:34:52 +02001336sisfb_pan_var(struct sis_video_info *ivideo, struct fb_info *info,
1337 struct fb_var_screeninfo *var)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001338{
Laurent Pinchart8e42a962011-05-25 11:34:52 +02001339 ivideo->current_base = var->yoffset * info->var.xres_virtual
1340 + var->xoffset;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001341
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001342 /* calculate base bpp dep. */
Laurent Pinchart8e42a962011-05-25 11:34:52 +02001343 switch (info->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:
Aaro Koskinen63e13f82010-12-20 23:50:15 +02001386 SiS_SetRegByte(SISDACA, regno);
1387 SiS_SetRegByte(SISDACD, (red >> 10));
1388 SiS_SetRegByte(SISDACD, (green >> 10));
1389 SiS_SetRegByte(SISDACD, (blue >> 10));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001390 if(ivideo->currentvbflags & VB_DISPTYPE_DISP2) {
Aaro Koskinen63e13f82010-12-20 23:50:15 +02001391 SiS_SetRegByte(SISDAC2A, regno);
1392 SiS_SetRegByte(SISDAC2D, (red >> 8));
1393 SiS_SetRegByte(SISDAC2D, (green >> 8));
1394 SiS_SetRegByte(SISDAC2D, (blue >> 8));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001395 }
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
Laurent Pinchart8e42a962011-05-25 11:34:52 +02001633 if (var->vmode & FB_VMODE_YWRAP)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001634 return -EINVAL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001635
Laurent Pinchart8e42a962011-05-25 11:34:52 +02001636 if (var->xoffset + info->var.xres > info->var.xres_virtual ||
1637 var->yoffset + info->var.yres > info->var.yres_virtual)
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001638 return -EINVAL;
1639
Laurent Pinchart8e42a962011-05-25 11:34:52 +02001640 err = sisfb_pan_var(ivideo, info, var);
1641 if (err < 0)
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001642 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001643
1644 info->var.xoffset = var->xoffset;
1645 info->var.yoffset = var->yoffset;
1646
1647 return 0;
1648}
1649
1650static int
1651sisfb_blank(int blank, struct fb_info *info)
1652{
1653 struct sis_video_info *ivideo = (struct sis_video_info *)info->par;
1654
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001655 return sisfb_myblank(ivideo, blank);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001656}
1657
Linus Torvalds1da177e2005-04-16 15:20:36 -07001658/* ----------- FBDev related routines for all series ---------- */
1659
Christoph Hellwig67a66802006-01-14 13:21:25 -08001660static int sisfb_ioctl(struct fb_info *info, unsigned int cmd,
1661 unsigned long arg)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001662{
1663 struct sis_video_info *ivideo = (struct sis_video_info *)info->par;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001664 struct sis_memreq sismemreq;
1665 struct fb_vblank sisvbblank;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001666 u32 gpu32 = 0;
1667#ifndef __user
1668#define __user
1669#endif
1670 u32 __user *argp = (u32 __user *)arg;
1671
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001672 switch(cmd) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001673 case FBIO_ALLOC:
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001674 if(!capable(CAP_SYS_RAWIO))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001675 return -EPERM;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001676
1677 if(copy_from_user(&sismemreq, (void __user *)arg, sizeof(sismemreq)))
1678 return -EFAULT;
1679
Linus Torvalds1da177e2005-04-16 15:20:36 -07001680 sis_malloc(&sismemreq);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001681
Linus Torvalds1da177e2005-04-16 15:20:36 -07001682 if(copy_to_user((void __user *)arg, &sismemreq, sizeof(sismemreq))) {
1683 sis_free((u32)sismemreq.offset);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001684 return -EFAULT;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001685 }
1686 break;
1687
1688 case FBIO_FREE:
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001689 if(!capable(CAP_SYS_RAWIO))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001690 return -EPERM;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001691
1692 if(get_user(gpu32, argp))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001693 return -EFAULT;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001694
Linus Torvalds1da177e2005-04-16 15:20:36 -07001695 sis_free(gpu32);
1696 break;
1697
1698 case FBIOGET_VBLANK:
Dan Rosenbergfd02db92010-09-22 13:05:09 -07001699
1700 memset(&sisvbblank, 0, sizeof(struct fb_vblank));
1701
Linus Torvalds1da177e2005-04-16 15:20:36 -07001702 sisvbblank.count = 0;
1703 sisvbblank.flags = sisfb_setupvbblankflags(ivideo, &sisvbblank.vcount, &sisvbblank.hcount);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001704
1705 if(copy_to_user((void __user *)arg, &sisvbblank, sizeof(sisvbblank)))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001706 return -EFAULT;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001707
Linus Torvalds1da177e2005-04-16 15:20:36 -07001708 break;
1709
1710 case SISFB_GET_INFO_SIZE:
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001711 return put_user(sizeof(struct sisfb_info), argp);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001712
1713 case SISFB_GET_INFO_OLD:
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001714 if(ivideo->warncount++ < 10)
1715 printk(KERN_INFO
1716 "sisfb: Deprecated ioctl call received - update your application!\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001717 case SISFB_GET_INFO: /* For communication with X driver */
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001718 ivideo->sisfb_infoblock.sisfb_id = SISFB_ID;
1719 ivideo->sisfb_infoblock.sisfb_version = VER_MAJOR;
1720 ivideo->sisfb_infoblock.sisfb_revision = VER_MINOR;
1721 ivideo->sisfb_infoblock.sisfb_patchlevel = VER_LEVEL;
1722 ivideo->sisfb_infoblock.chip_id = ivideo->chip_id;
1723 ivideo->sisfb_infoblock.sisfb_pci_vendor = ivideo->chip_vendor;
1724 ivideo->sisfb_infoblock.memory = ivideo->video_size / 1024;
1725 ivideo->sisfb_infoblock.heapstart = ivideo->heapstart / 1024;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001726 if(ivideo->modechanged) {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001727 ivideo->sisfb_infoblock.fbvidmode = ivideo->mode_no;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001728 } else {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001729 ivideo->sisfb_infoblock.fbvidmode = ivideo->modeprechange;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001730 }
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001731 ivideo->sisfb_infoblock.sisfb_caps = ivideo->caps;
1732 ivideo->sisfb_infoblock.sisfb_tqlen = ivideo->cmdQueueSize / 1024;
1733 ivideo->sisfb_infoblock.sisfb_pcibus = ivideo->pcibus;
1734 ivideo->sisfb_infoblock.sisfb_pcislot = ivideo->pcislot;
1735 ivideo->sisfb_infoblock.sisfb_pcifunc = ivideo->pcifunc;
1736 ivideo->sisfb_infoblock.sisfb_lcdpdc = ivideo->detectedpdc;
1737 ivideo->sisfb_infoblock.sisfb_lcdpdca = ivideo->detectedpdca;
1738 ivideo->sisfb_infoblock.sisfb_lcda = ivideo->detectedlcda;
1739 ivideo->sisfb_infoblock.sisfb_vbflags = ivideo->vbflags;
1740 ivideo->sisfb_infoblock.sisfb_currentvbflags = ivideo->currentvbflags;
1741 ivideo->sisfb_infoblock.sisfb_scalelcd = ivideo->SiS_Pr.UsePanelScaler;
1742 ivideo->sisfb_infoblock.sisfb_specialtiming = ivideo->SiS_Pr.SiS_CustomT;
1743 ivideo->sisfb_infoblock.sisfb_haveemi = ivideo->SiS_Pr.HaveEMI ? 1 : 0;
1744 ivideo->sisfb_infoblock.sisfb_haveemilcd = ivideo->SiS_Pr.HaveEMILCD ? 1 : 0;
1745 ivideo->sisfb_infoblock.sisfb_emi30 = ivideo->SiS_Pr.EMI_30;
1746 ivideo->sisfb_infoblock.sisfb_emi31 = ivideo->SiS_Pr.EMI_31;
1747 ivideo->sisfb_infoblock.sisfb_emi32 = ivideo->SiS_Pr.EMI_32;
1748 ivideo->sisfb_infoblock.sisfb_emi33 = ivideo->SiS_Pr.EMI_33;
1749 ivideo->sisfb_infoblock.sisfb_tvxpos = (u16)(ivideo->tvxpos + 32);
1750 ivideo->sisfb_infoblock.sisfb_tvypos = (u16)(ivideo->tvypos + 32);
1751 ivideo->sisfb_infoblock.sisfb_heapsize = ivideo->sisfb_heap_size / 1024;
1752 ivideo->sisfb_infoblock.sisfb_videooffset = ivideo->video_offset;
1753 ivideo->sisfb_infoblock.sisfb_curfstn = ivideo->curFSTN;
1754 ivideo->sisfb_infoblock.sisfb_curdstn = ivideo->curDSTN;
1755 ivideo->sisfb_infoblock.sisfb_vbflags2 = ivideo->vbflags2;
1756 ivideo->sisfb_infoblock.sisfb_can_post = ivideo->sisfb_can_post ? 1 : 0;
1757 ivideo->sisfb_infoblock.sisfb_card_posted = ivideo->sisfb_card_posted ? 1 : 0;
1758 ivideo->sisfb_infoblock.sisfb_was_boot_device = ivideo->sisfb_was_boot_device ? 1 : 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001759
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001760 if(copy_to_user((void __user *)arg, &ivideo->sisfb_infoblock,
1761 sizeof(ivideo->sisfb_infoblock)))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001762 return -EFAULT;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001763
Linus Torvalds1da177e2005-04-16 15:20:36 -07001764 break;
1765
1766 case SISFB_GET_VBRSTATUS_OLD:
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001767 if(ivideo->warncount++ < 10)
1768 printk(KERN_INFO
1769 "sisfb: Deprecated ioctl call received - update your application!\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001770 case SISFB_GET_VBRSTATUS:
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001771 if(sisfb_CheckVBRetrace(ivideo))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001772 return put_user((u32)1, argp);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001773 else
Linus Torvalds1da177e2005-04-16 15:20:36 -07001774 return put_user((u32)0, argp);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001775
1776 case SISFB_GET_AUTOMAXIMIZE_OLD:
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001777 if(ivideo->warncount++ < 10)
1778 printk(KERN_INFO
1779 "sisfb: Deprecated ioctl call received - update your application!\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001780 case SISFB_GET_AUTOMAXIMIZE:
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001781 if(ivideo->sisfb_max)
1782 return put_user((u32)1, argp);
1783 else
1784 return put_user((u32)0, argp);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001785
1786 case SISFB_SET_AUTOMAXIMIZE_OLD:
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001787 if(ivideo->warncount++ < 10)
1788 printk(KERN_INFO
1789 "sisfb: Deprecated ioctl call received - update your application!\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001790 case SISFB_SET_AUTOMAXIMIZE:
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001791 if(get_user(gpu32, argp))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001792 return -EFAULT;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001793
Linus Torvalds1da177e2005-04-16 15:20:36 -07001794 ivideo->sisfb_max = (gpu32) ? 1 : 0;
1795 break;
1796
1797 case SISFB_SET_TVPOSOFFSET:
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001798 if(get_user(gpu32, argp))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001799 return -EFAULT;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001800
Linus Torvalds1da177e2005-04-16 15:20:36 -07001801 sisfb_set_TVxposoffset(ivideo, ((int)(gpu32 >> 16)) - 32);
1802 sisfb_set_TVyposoffset(ivideo, ((int)(gpu32 & 0xffff)) - 32);
1803 break;
1804
1805 case SISFB_GET_TVPOSOFFSET:
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001806 return put_user((u32)(((ivideo->tvxpos+32)<<16)|((ivideo->tvypos+32)&0xffff)),
1807 argp);
1808
1809 case SISFB_COMMAND:
1810 if(copy_from_user(&ivideo->sisfb_command, (void __user *)arg,
1811 sizeof(struct sisfb_cmd)))
1812 return -EFAULT;
1813
1814 sisfb_handle_command(ivideo, &ivideo->sisfb_command);
1815
1816 if(copy_to_user((void __user *)arg, &ivideo->sisfb_command,
1817 sizeof(struct sisfb_cmd)))
1818 return -EFAULT;
1819
1820 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001821
1822 case SISFB_SET_LOCK:
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001823 if(get_user(gpu32, argp))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001824 return -EFAULT;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001825
Linus Torvalds1da177e2005-04-16 15:20:36 -07001826 ivideo->sisfblocked = (gpu32) ? 1 : 0;
1827 break;
1828
1829 default:
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001830#ifdef SIS_NEW_CONFIG_COMPAT
Linus Torvalds1da177e2005-04-16 15:20:36 -07001831 return -ENOIOCTLCMD;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001832#else
1833 return -EINVAL;
1834#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -07001835 }
1836 return 0;
1837}
1838
Linus Torvalds1da177e2005-04-16 15:20:36 -07001839static int
1840sisfb_get_fix(struct fb_fix_screeninfo *fix, int con, struct fb_info *info)
1841{
1842 struct sis_video_info *ivideo = (struct sis_video_info *)info->par;
1843
1844 memset(fix, 0, sizeof(struct fb_fix_screeninfo));
1845
Dan Carpenterdbd536b2010-05-24 14:33:53 -07001846 strlcpy(fix->id, ivideo->myid, sizeof(fix->id));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001847
Krzysztof Helt537a1bf2009-06-30 11:41:29 -07001848 mutex_lock(&info->mm_lock);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001849 fix->smem_start = ivideo->video_base + ivideo->video_offset;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001850 fix->smem_len = ivideo->sisfb_mem;
Krzysztof Helt537a1bf2009-06-30 11:41:29 -07001851 mutex_unlock(&info->mm_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001852 fix->type = FB_TYPE_PACKED_PIXELS;
1853 fix->type_aux = 0;
1854 fix->visual = (ivideo->video_bpp == 8) ? FB_VISUAL_PSEUDOCOLOR : FB_VISUAL_TRUECOLOR;
1855 fix->xpanstep = 1;
1856 fix->ypanstep = (ivideo->sisfb_ypan) ? 1 : 0;
1857 fix->ywrapstep = 0;
1858 fix->line_length = ivideo->video_linelength;
1859 fix->mmio_start = ivideo->mmio_base;
1860 fix->mmio_len = ivideo->mmio_size;
1861 if(ivideo->sisvga_engine == SIS_300_VGA) {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001862 fix->accel = FB_ACCEL_SIS_GLAMOUR;
1863 } else if((ivideo->chip == SIS_330) ||
1864 (ivideo->chip == SIS_760) ||
1865 (ivideo->chip == SIS_761)) {
1866 fix->accel = FB_ACCEL_SIS_XABRE;
1867 } else if(ivideo->chip == XGI_20) {
1868 fix->accel = FB_ACCEL_XGI_VOLARI_Z;
1869 } else if(ivideo->chip >= XGI_40) {
1870 fix->accel = FB_ACCEL_XGI_VOLARI_V;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001871 } else {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001872 fix->accel = FB_ACCEL_SIS_GLAMOUR_2;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001873 }
1874
1875 return 0;
1876}
1877
1878/* ---------------- fb_ops structures ----------------- */
1879
Linus Torvalds1da177e2005-04-16 15:20:36 -07001880static struct fb_ops sisfb_ops = {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001881 .owner = THIS_MODULE,
1882 .fb_open = sisfb_open,
1883 .fb_release = sisfb_release,
1884 .fb_check_var = sisfb_check_var,
1885 .fb_set_par = sisfb_set_par,
1886 .fb_setcolreg = sisfb_setcolreg,
1887 .fb_pan_display = sisfb_pan_display,
1888 .fb_blank = sisfb_blank,
1889 .fb_fillrect = fbcon_sis_fillrect,
1890 .fb_copyarea = fbcon_sis_copyarea,
1891 .fb_imageblit = cfb_imageblit,
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001892 .fb_sync = fbcon_sis_sync,
1893#ifdef SIS_NEW_CONFIG_COMPAT
Christoph Hellwig67a66802006-01-14 13:21:25 -08001894 .fb_compat_ioctl= sisfb_ioctl,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001895#endif
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001896 .fb_ioctl = sisfb_ioctl
Linus Torvalds1da177e2005-04-16 15:20:36 -07001897};
Linus Torvalds1da177e2005-04-16 15:20:36 -07001898
1899/* ---------------- Chip generation dependent routines ---------------- */
1900
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001901static struct pci_dev * __devinit
1902sisfb_get_northbridge(int basechipid)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001903{
1904 struct pci_dev *pdev = NULL;
1905 int nbridgenum, nbridgeidx, i;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001906 static const unsigned short nbridgeids[] = {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001907 PCI_DEVICE_ID_SI_540, /* for SiS 540 VGA */
1908 PCI_DEVICE_ID_SI_630, /* for SiS 630/730 VGA */
1909 PCI_DEVICE_ID_SI_730,
1910 PCI_DEVICE_ID_SI_550, /* for SiS 550 VGA */
1911 PCI_DEVICE_ID_SI_650, /* for SiS 650/651/740 VGA */
1912 PCI_DEVICE_ID_SI_651,
1913 PCI_DEVICE_ID_SI_740,
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001914 PCI_DEVICE_ID_SI_661, /* for SiS 661/741/660/760/761 VGA */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001915 PCI_DEVICE_ID_SI_741,
1916 PCI_DEVICE_ID_SI_660,
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001917 PCI_DEVICE_ID_SI_760,
1918 PCI_DEVICE_ID_SI_761
Linus Torvalds1da177e2005-04-16 15:20:36 -07001919 };
1920
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001921 switch(basechipid) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001922#ifdef CONFIG_FB_SIS_300
1923 case SIS_540: nbridgeidx = 0; nbridgenum = 1; break;
1924 case SIS_630: nbridgeidx = 1; nbridgenum = 2; break;
1925#endif
1926#ifdef CONFIG_FB_SIS_315
1927 case SIS_550: nbridgeidx = 3; nbridgenum = 1; break;
1928 case SIS_650: nbridgeidx = 4; nbridgenum = 3; break;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001929 case SIS_660: nbridgeidx = 7; nbridgenum = 5; break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001930#endif
1931 default: return NULL;
1932 }
1933 for(i = 0; i < nbridgenum; i++) {
Adrian Bunk0959f0c2007-05-08 00:39:50 -07001934 if((pdev = pci_get_device(PCI_VENDOR_ID_SI,
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001935 nbridgeids[nbridgeidx+i], NULL)))
1936 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001937 }
1938 return pdev;
1939}
1940
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001941static int __devinit
1942sisfb_get_dram_size(struct sis_video_info *ivideo)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001943{
1944#if defined(CONFIG_FB_SIS_300) || defined(CONFIG_FB_SIS_315)
1945 u8 reg;
1946#endif
1947
1948 ivideo->video_size = 0;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001949 ivideo->UMAsize = ivideo->LFBsize = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001950
1951 switch(ivideo->chip) {
1952#ifdef CONFIG_FB_SIS_300
1953 case SIS_300:
Aaro Koskinene57d4132010-12-20 23:50:16 +02001954 reg = SiS_GetReg(SISSR, 0x14);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001955 ivideo->video_size = ((reg & 0x3F) + 1) << 20;
1956 break;
1957 case SIS_540:
1958 case SIS_630:
1959 case SIS_730:
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001960 if(!ivideo->nbridge)
1961 return -1;
1962 pci_read_config_byte(ivideo->nbridge, 0x63, &reg);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001963 ivideo->video_size = 1 << (((reg & 0x70) >> 4) + 21);
1964 break;
1965#endif
1966#ifdef CONFIG_FB_SIS_315
1967 case SIS_315H:
1968 case SIS_315PRO:
1969 case SIS_315:
Aaro Koskinene57d4132010-12-20 23:50:16 +02001970 reg = SiS_GetReg(SISSR, 0x14);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001971 ivideo->video_size = (1 << ((reg & 0xf0) >> 4)) << 20;
1972 switch((reg >> 2) & 0x03) {
1973 case 0x01:
1974 case 0x03:
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001975 ivideo->video_size <<= 1;
1976 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001977 case 0x02:
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001978 ivideo->video_size += (ivideo->video_size/2);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001979 }
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001980 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001981 case SIS_330:
Aaro Koskinene57d4132010-12-20 23:50:16 +02001982 reg = SiS_GetReg(SISSR, 0x14);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001983 ivideo->video_size = (1 << ((reg & 0xf0) >> 4)) << 20;
1984 if(reg & 0x0c) ivideo->video_size <<= 1;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001985 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001986 case SIS_550:
1987 case SIS_650:
1988 case SIS_740:
Aaro Koskinene57d4132010-12-20 23:50:16 +02001989 reg = SiS_GetReg(SISSR, 0x14);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001990 ivideo->video_size = (((reg & 0x3f) + 1) << 2) << 20;
1991 break;
1992 case SIS_661:
1993 case SIS_741:
Aaro Koskinene57d4132010-12-20 23:50:16 +02001994 reg = SiS_GetReg(SISCR, 0x79);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001995 ivideo->video_size = (1 << ((reg & 0xf0) >> 4)) << 20;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001996 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001997 case SIS_660:
1998 case SIS_760:
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001999 case SIS_761:
Aaro Koskinene57d4132010-12-20 23:50:16 +02002000 reg = SiS_GetReg(SISCR, 0x79);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002001 reg = (reg & 0xf0) >> 4;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07002002 if(reg) {
2003 ivideo->video_size = (1 << reg) << 20;
2004 ivideo->UMAsize = ivideo->video_size;
2005 }
Aaro Koskinene57d4132010-12-20 23:50:16 +02002006 reg = SiS_GetReg(SISCR, 0x78);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002007 reg &= 0x30;
2008 if(reg) {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07002009 if(reg == 0x10) {
2010 ivideo->LFBsize = (32 << 20);
2011 } else {
2012 ivideo->LFBsize = (64 << 20);
2013 }
2014 ivideo->video_size += ivideo->LFBsize;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002015 }
Thomas Winischhofer544393f2005-09-09 13:04:45 -07002016 break;
2017 case SIS_340:
2018 case XGI_20:
2019 case XGI_40:
Aaro Koskinene57d4132010-12-20 23:50:16 +02002020 reg = SiS_GetReg(SISSR, 0x14);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07002021 ivideo->video_size = (1 << ((reg & 0xf0) >> 4)) << 20;
2022 if(ivideo->chip != XGI_20) {
2023 reg = (reg & 0x0c) >> 2;
2024 if(ivideo->revision_id == 2) {
2025 if(reg & 0x01) reg = 0x02;
2026 else reg = 0x00;
2027 }
2028 if(reg == 0x02) ivideo->video_size <<= 1;
2029 else if(reg == 0x03) ivideo->video_size <<= 2;
2030 }
2031 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002032#endif
2033 default:
2034 return -1;
2035 }
2036 return 0;
2037}
2038
2039/* -------------- video bridge device detection --------------- */
2040
Thomas Winischhofer544393f2005-09-09 13:04:45 -07002041static void __devinit
2042sisfb_detect_VB_connect(struct sis_video_info *ivideo)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002043{
2044 u8 cr32, temp;
2045
Thomas Winischhofer544393f2005-09-09 13:04:45 -07002046 /* No CRT2 on XGI Z7 */
2047 if(ivideo->chip == XGI_20) {
2048 ivideo->sisfb_crt1off = 0;
2049 return;
2050 }
2051
Linus Torvalds1da177e2005-04-16 15:20:36 -07002052#ifdef CONFIG_FB_SIS_300
2053 if(ivideo->sisvga_engine == SIS_300_VGA) {
Aaro Koskinene57d4132010-12-20 23:50:16 +02002054 temp = SiS_GetReg(SISSR, 0x17);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002055 if((temp & 0x0F) && (ivideo->chip != SIS_300)) {
2056 /* PAL/NTSC is stored on SR16 on such machines */
2057 if(!(ivideo->vbflags & (TV_PAL | TV_NTSC | TV_PALM | TV_PALN))) {
Aaro Koskinene57d4132010-12-20 23:50:16 +02002058 temp = SiS_GetReg(SISSR, 0x16);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002059 if(temp & 0x20)
2060 ivideo->vbflags |= TV_PAL;
2061 else
2062 ivideo->vbflags |= TV_NTSC;
2063 }
2064 }
2065 }
2066#endif
2067
Aaro Koskinene57d4132010-12-20 23:50:16 +02002068 cr32 = SiS_GetReg(SISCR, 0x32);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002069
2070 if(cr32 & SIS_CRT1) {
2071 ivideo->sisfb_crt1off = 0;
2072 } else {
2073 ivideo->sisfb_crt1off = (cr32 & 0xDF) ? 1 : 0;
2074 }
2075
2076 ivideo->vbflags &= ~(CRT2_TV | CRT2_LCD | CRT2_VGA);
2077
2078 if(cr32 & SIS_VB_TV) ivideo->vbflags |= CRT2_TV;
2079 if(cr32 & SIS_VB_LCD) ivideo->vbflags |= CRT2_LCD;
2080 if(cr32 & SIS_VB_CRT2) ivideo->vbflags |= CRT2_VGA;
2081
2082 /* Check given parms for hardware compatibility.
2083 * (Cannot do this in the search_xx routines since we don't
2084 * know what hardware we are running on then)
2085 */
2086
2087 if(ivideo->chip != SIS_550) {
2088 ivideo->sisfb_dstn = ivideo->sisfb_fstn = 0;
2089 }
2090
2091 if(ivideo->sisfb_tvplug != -1) {
2092 if( (ivideo->sisvga_engine != SIS_315_VGA) ||
Thomas Winischhofer544393f2005-09-09 13:04:45 -07002093 (!(ivideo->vbflags2 & VB2_SISYPBPRBRIDGE)) ) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002094 if(ivideo->sisfb_tvplug & TV_YPBPR) {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07002095 ivideo->sisfb_tvplug = -1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002096 printk(KERN_ERR "sisfb: YPbPr not supported\n");
2097 }
2098 }
2099 }
2100 if(ivideo->sisfb_tvplug != -1) {
2101 if( (ivideo->sisvga_engine != SIS_315_VGA) ||
Thomas Winischhofer544393f2005-09-09 13:04:45 -07002102 (!(ivideo->vbflags2 & VB2_SISHIVISIONBRIDGE)) ) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002103 if(ivideo->sisfb_tvplug & TV_HIVISION) {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07002104 ivideo->sisfb_tvplug = -1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002105 printk(KERN_ERR "sisfb: HiVision not supported\n");
2106 }
2107 }
2108 }
2109 if(ivideo->sisfb_tvstd != -1) {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07002110 if( (!(ivideo->vbflags2 & VB2_SISBRIDGE)) &&
2111 (!((ivideo->sisvga_engine == SIS_315_VGA) &&
2112 (ivideo->vbflags2 & VB2_CHRONTEL))) ) {
Roel Kluin5ab94812009-12-15 16:46:23 -08002113 if(ivideo->sisfb_tvstd & (TV_PALM | TV_PALN | TV_NTSCJ)) {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07002114 ivideo->sisfb_tvstd = -1;
2115 printk(KERN_ERR "sisfb: PALM/PALN/NTSCJ not supported\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002116 }
2117 }
2118 }
2119
2120 /* Detect/set TV plug & type */
2121 if(ivideo->sisfb_tvplug != -1) {
2122 ivideo->vbflags |= ivideo->sisfb_tvplug;
2123 } else {
2124 if(cr32 & SIS_VB_YPBPR) ivideo->vbflags |= (TV_YPBPR|TV_YPBPR525I); /* default: 480i */
2125 else if(cr32 & SIS_VB_HIVISION) ivideo->vbflags |= TV_HIVISION;
2126 else if(cr32 & SIS_VB_SCART) ivideo->vbflags |= TV_SCART;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07002127 else {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002128 if(cr32 & SIS_VB_SVIDEO) ivideo->vbflags |= TV_SVIDEO;
2129 if(cr32 & SIS_VB_COMPOSITE) ivideo->vbflags |= TV_AVIDEO;
2130 }
2131 }
2132
2133 if(!(ivideo->vbflags & (TV_YPBPR | TV_HIVISION))) {
2134 if(ivideo->sisfb_tvstd != -1) {
2135 ivideo->vbflags &= ~(TV_NTSC | TV_PAL | TV_PALM | TV_PALN | TV_NTSCJ);
2136 ivideo->vbflags |= ivideo->sisfb_tvstd;
2137 }
2138 if(ivideo->vbflags & TV_SCART) {
2139 ivideo->vbflags &= ~(TV_NTSC | TV_PALM | TV_PALN | TV_NTSCJ);
2140 ivideo->vbflags |= TV_PAL;
2141 }
2142 if(!(ivideo->vbflags & (TV_PAL | TV_NTSC | TV_PALM | TV_PALN | TV_NTSCJ))) {
2143 if(ivideo->sisvga_engine == SIS_300_VGA) {
Aaro Koskinene57d4132010-12-20 23:50:16 +02002144 temp = SiS_GetReg(SISSR, 0x38);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002145 if(temp & 0x01) ivideo->vbflags |= TV_PAL;
2146 else ivideo->vbflags |= TV_NTSC;
2147 } else if((ivideo->chip <= SIS_315PRO) || (ivideo->chip >= SIS_330)) {
Aaro Koskinene57d4132010-12-20 23:50:16 +02002148 temp = SiS_GetReg(SISSR, 0x38);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002149 if(temp & 0x01) ivideo->vbflags |= TV_PAL;
2150 else ivideo->vbflags |= TV_NTSC;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07002151 } else {
Aaro Koskinene57d4132010-12-20 23:50:16 +02002152 temp = SiS_GetReg(SISCR, 0x79);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002153 if(temp & 0x20) ivideo->vbflags |= TV_PAL;
2154 else ivideo->vbflags |= TV_NTSC;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07002155 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002156 }
2157 }
2158
2159 /* Copy forceCRT1 option to CRT1off if option is given */
Thomas Winischhofer544393f2005-09-09 13:04:45 -07002160 if(ivideo->sisfb_forcecrt1 != -1) {
2161 ivideo->sisfb_crt1off = (ivideo->sisfb_forcecrt1) ? 0 : 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002162 }
2163}
2164
2165/* ------------------ Sensing routines ------------------ */
2166
Richard Knutssonc30660ea2007-02-12 00:55:06 -08002167static bool __devinit
Thomas Winischhofer544393f2005-09-09 13:04:45 -07002168sisfb_test_DDC1(struct sis_video_info *ivideo)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002169{
2170 unsigned short old;
2171 int count = 48;
2172
2173 old = SiS_ReadDDC1Bit(&ivideo->SiS_Pr);
2174 do {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07002175 if(old != SiS_ReadDDC1Bit(&ivideo->SiS_Pr)) break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002176 } while(count--);
Richard Knutssonc30660ea2007-02-12 00:55:06 -08002177 return (count != -1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002178}
2179
Thomas Winischhofer544393f2005-09-09 13:04:45 -07002180static void __devinit
2181sisfb_sense_crt1(struct sis_video_info *ivideo)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002182{
Richard Knutssonc30660ea2007-02-12 00:55:06 -08002183 bool mustwait = false;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002184 u8 sr1F, cr17;
2185#ifdef CONFIG_FB_SIS_315
2186 u8 cr63=0;
2187#endif
2188 u16 temp = 0xffff;
2189 int i;
2190
Aaro Koskinene57d4132010-12-20 23:50:16 +02002191 sr1F = SiS_GetReg(SISSR, 0x1F);
Aaro Koskinen27799d62010-12-20 23:50:18 +02002192 SiS_SetRegOR(SISSR, 0x1F, 0x04);
Aaro Koskinen667a8b42010-12-20 23:50:19 +02002193 SiS_SetRegAND(SISSR, 0x1F, 0x3F);
Richard Knutssonc30660ea2007-02-12 00:55:06 -08002194 if(sr1F & 0xc0) mustwait = true;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002195
2196#ifdef CONFIG_FB_SIS_315
2197 if(ivideo->sisvga_engine == SIS_315_VGA) {
Aaro Koskinene57d4132010-12-20 23:50:16 +02002198 cr63 = SiS_GetReg(SISCR, ivideo->SiS_Pr.SiS_MyCR63);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002199 cr63 &= 0x40;
Aaro Koskinen667a8b42010-12-20 23:50:19 +02002200 SiS_SetRegAND(SISCR, ivideo->SiS_Pr.SiS_MyCR63, 0xBF);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002201 }
2202#endif
2203
Aaro Koskinene57d4132010-12-20 23:50:16 +02002204 cr17 = SiS_GetReg(SISCR, 0x17);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002205 cr17 &= 0x80;
2206 if(!cr17) {
Aaro Koskinen27799d62010-12-20 23:50:18 +02002207 SiS_SetRegOR(SISCR, 0x17, 0x80);
Richard Knutssonc30660ea2007-02-12 00:55:06 -08002208 mustwait = true;
Aaro Koskinen44b751b2010-12-20 23:50:17 +02002209 SiS_SetReg(SISSR, 0x00, 0x01);
2210 SiS_SetReg(SISSR, 0x00, 0x03);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002211 }
2212
2213 if(mustwait) {
2214 for(i=0; i < 10; i++) sisfbwaitretracecrt1(ivideo);
2215 }
2216
2217#ifdef CONFIG_FB_SIS_315
2218 if(ivideo->chip >= SIS_330) {
Aaro Koskinen667a8b42010-12-20 23:50:19 +02002219 SiS_SetRegAND(SISCR, 0x32, ~0x20);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002220 if(ivideo->chip >= SIS_340) {
Aaro Koskinen44b751b2010-12-20 23:50:17 +02002221 SiS_SetReg(SISCR, 0x57, 0x4a);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002222 } else {
Aaro Koskinen44b751b2010-12-20 23:50:17 +02002223 SiS_SetReg(SISCR, 0x57, 0x5f);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002224 }
Aaro Koskinen27799d62010-12-20 23:50:18 +02002225 SiS_SetRegOR(SISCR, 0x53, 0x02);
Aaro Koskinen1e1687d2010-12-20 23:50:14 +02002226 while ((SiS_GetRegByte(SISINPSTAT)) & 0x01) break;
2227 while (!((SiS_GetRegByte(SISINPSTAT)) & 0x01)) break;
2228 if ((SiS_GetRegByte(SISMISCW)) & 0x10) temp = 1;
Aaro Koskinen667a8b42010-12-20 23:50:19 +02002229 SiS_SetRegAND(SISCR, 0x53, 0xfd);
2230 SiS_SetRegAND(SISCR, 0x57, 0x00);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002231 }
2232#endif
2233
2234 if(temp == 0xffff) {
2235 i = 3;
2236 do {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07002237 temp = SiS_HandleDDC(&ivideo->SiS_Pr, ivideo->vbflags,
2238 ivideo->sisvga_engine, 0, 0, NULL, ivideo->vbflags2);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002239 } while(((temp == 0) || (temp == 0xffff)) && i--);
2240
2241 if((temp == 0) || (temp == 0xffff)) {
2242 if(sisfb_test_DDC1(ivideo)) temp = 1;
2243 }
2244 }
2245
2246 if((temp) && (temp != 0xffff)) {
Aaro Koskinen27799d62010-12-20 23:50:18 +02002247 SiS_SetRegOR(SISCR, 0x32, 0x20);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002248 }
2249
2250#ifdef CONFIG_FB_SIS_315
2251 if(ivideo->sisvga_engine == SIS_315_VGA) {
Aaro Koskinenad78adb2010-12-20 23:50:20 +02002252 SiS_SetRegANDOR(SISCR, ivideo->SiS_Pr.SiS_MyCR63, 0xBF, cr63);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002253 }
2254#endif
2255
Aaro Koskinenad78adb2010-12-20 23:50:20 +02002256 SiS_SetRegANDOR(SISCR, 0x17, 0x7F, cr17);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002257
Aaro Koskinen44b751b2010-12-20 23:50:17 +02002258 SiS_SetReg(SISSR, 0x1F, sr1F);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002259}
2260
2261/* Determine and detect attached devices on SiS30x */
Thomas Winischhofer544393f2005-09-09 13:04:45 -07002262static void __devinit
2263SiS_SenseLCD(struct sis_video_info *ivideo)
2264{
2265 unsigned char buffer[256];
2266 unsigned short temp, realcrtno, i;
2267 u8 reg, cr37 = 0, paneltype = 0;
2268 u16 xres, yres;
2269
Richard Knutssonc30660ea2007-02-12 00:55:06 -08002270 ivideo->SiS_Pr.PanelSelfDetected = false;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07002271
2272 /* LCD detection only for TMDS bridges */
2273 if(!(ivideo->vbflags2 & VB2_SISTMDSBRIDGE))
2274 return;
2275 if(ivideo->vbflags2 & VB2_30xBDH)
2276 return;
2277
2278 /* If LCD already set up by BIOS, skip it */
Aaro Koskinene57d4132010-12-20 23:50:16 +02002279 reg = SiS_GetReg(SISCR, 0x32);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07002280 if(reg & 0x08)
2281 return;
2282
2283 realcrtno = 1;
2284 if(ivideo->SiS_Pr.DDCPortMixup)
2285 realcrtno = 0;
2286
2287 /* Check DDC capabilities */
2288 temp = SiS_HandleDDC(&ivideo->SiS_Pr, ivideo->vbflags, ivideo->sisvga_engine,
2289 realcrtno, 0, &buffer[0], ivideo->vbflags2);
2290
2291 if((!temp) || (temp == 0xffff) || (!(temp & 0x02)))
2292 return;
2293
2294 /* Read DDC data */
2295 i = 3; /* Number of retrys */
2296 do {
2297 temp = SiS_HandleDDC(&ivideo->SiS_Pr, ivideo->vbflags,
2298 ivideo->sisvga_engine, realcrtno, 1,
2299 &buffer[0], ivideo->vbflags2);
2300 } while((temp) && i--);
2301
2302 if(temp)
2303 return;
2304
2305 /* No digital device */
2306 if(!(buffer[0x14] & 0x80))
2307 return;
2308
2309 /* First detailed timing preferred timing? */
2310 if(!(buffer[0x18] & 0x02))
2311 return;
2312
2313 xres = buffer[0x38] | ((buffer[0x3a] & 0xf0) << 4);
2314 yres = buffer[0x3b] | ((buffer[0x3d] & 0xf0) << 4);
2315
2316 switch(xres) {
2317 case 1024:
2318 if(yres == 768)
2319 paneltype = 0x02;
2320 break;
2321 case 1280:
2322 if(yres == 1024)
2323 paneltype = 0x03;
2324 break;
2325 case 1600:
2326 if((yres == 1200) && (ivideo->vbflags2 & VB2_30xC))
2327 paneltype = 0x0b;
2328 break;
2329 }
2330
2331 if(!paneltype)
2332 return;
2333
2334 if(buffer[0x23])
2335 cr37 |= 0x10;
2336
2337 if((buffer[0x47] & 0x18) == 0x18)
2338 cr37 |= ((((buffer[0x47] & 0x06) ^ 0x06) << 5) | 0x20);
2339 else
2340 cr37 |= 0xc0;
2341
Aaro Koskinen44b751b2010-12-20 23:50:17 +02002342 SiS_SetReg(SISCR, 0x36, paneltype);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07002343 cr37 &= 0xf1;
Aaro Koskinenad78adb2010-12-20 23:50:20 +02002344 SiS_SetRegANDOR(SISCR, 0x37, 0x0c, cr37);
Aaro Koskinen27799d62010-12-20 23:50:18 +02002345 SiS_SetRegOR(SISCR, 0x32, 0x08);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07002346
Richard Knutssonc30660ea2007-02-12 00:55:06 -08002347 ivideo->SiS_Pr.PanelSelfDetected = true;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07002348}
2349
2350static int __devinit
2351SISDoSense(struct sis_video_info *ivideo, u16 type, u16 test)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002352{
2353 int temp, mytest, result, i, j;
2354
2355 for(j = 0; j < 10; j++) {
2356 result = 0;
2357 for(i = 0; i < 3; i++) {
2358 mytest = test;
Aaro Koskinen44b751b2010-12-20 23:50:17 +02002359 SiS_SetReg(SISPART4, 0x11, (type & 0x00ff));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002360 temp = (type >> 8) | (mytest & 0x00ff);
Aaro Koskinenad78adb2010-12-20 23:50:20 +02002361 SiS_SetRegANDOR(SISPART4, 0x10, 0xe0, temp);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002362 SiS_DDC2Delay(&ivideo->SiS_Pr, 0x1500);
2363 mytest >>= 8;
2364 mytest &= 0x7f;
Aaro Koskinene57d4132010-12-20 23:50:16 +02002365 temp = SiS_GetReg(SISPART4, 0x03);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002366 temp ^= 0x0e;
2367 temp &= mytest;
2368 if(temp == mytest) result++;
2369#if 1
Aaro Koskinen44b751b2010-12-20 23:50:17 +02002370 SiS_SetReg(SISPART4, 0x11, 0x00);
Aaro Koskinen667a8b42010-12-20 23:50:19 +02002371 SiS_SetRegAND(SISPART4, 0x10, 0xe0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002372 SiS_DDC2Delay(&ivideo->SiS_Pr, 0x1000);
2373#endif
2374 }
2375 if((result == 0) || (result >= 2)) break;
2376 }
Thomas Winischhofer544393f2005-09-09 13:04:45 -07002377 return result;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002378}
2379
Thomas Winischhofer544393f2005-09-09 13:04:45 -07002380static void __devinit
2381SiS_Sense30x(struct sis_video_info *ivideo)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002382{
2383 u8 backupP4_0d,backupP2_00,backupP2_4d,backupSR_1e,biosflag=0;
2384 u16 svhs=0, svhs_c=0;
2385 u16 cvbs=0, cvbs_c=0;
2386 u16 vga2=0, vga2_c=0;
2387 int myflag, result;
2388 char stdstr[] = "sisfb: Detected";
2389 char tvstr[] = "TV connected to";
2390
Thomas Winischhofer544393f2005-09-09 13:04:45 -07002391 if(ivideo->vbflags2 & VB2_301) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002392 svhs = 0x00b9; cvbs = 0x00b3; vga2 = 0x00d1;
Aaro Koskinene57d4132010-12-20 23:50:16 +02002393 myflag = SiS_GetReg(SISPART4, 0x01);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002394 if(myflag & 0x04) {
2395 svhs = 0x00dd; cvbs = 0x00ee; vga2 = 0x00fd;
2396 }
Thomas Winischhofer544393f2005-09-09 13:04:45 -07002397 } else if(ivideo->vbflags2 & (VB2_301B | VB2_302B)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002398 svhs = 0x016b; cvbs = 0x0174; vga2 = 0x0190;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07002399 } else if(ivideo->vbflags2 & (VB2_301LV | VB2_302LV)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002400 svhs = 0x0200; cvbs = 0x0100;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07002401 } else if(ivideo->vbflags2 & (VB2_301C | VB2_302ELV | VB2_307T | VB2_307LV)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002402 svhs = 0x016b; cvbs = 0x0110; vga2 = 0x0190;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07002403 } else
2404 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002405
2406 vga2_c = 0x0e08; svhs_c = 0x0404; cvbs_c = 0x0804;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07002407 if(ivideo->vbflags & (VB2_301LV|VB2_302LV|VB2_302ELV|VB2_307LV)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002408 svhs_c = 0x0408; cvbs_c = 0x0808;
2409 }
Thomas Winischhofer544393f2005-09-09 13:04:45 -07002410
Linus Torvalds1da177e2005-04-16 15:20:36 -07002411 biosflag = 2;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07002412 if(ivideo->haveXGIROM) {
2413 biosflag = ivideo->bios_abase[0x58] & 0x03;
2414 } else if(ivideo->newrom) {
2415 if(ivideo->bios_abase[0x5d] & 0x04) biosflag |= 0x01;
2416 } else if(ivideo->sisvga_engine == SIS_300_VGA) {
2417 if(ivideo->bios_abase) {
2418 biosflag = ivideo->bios_abase[0xfe] & 0x03;
2419 }
2420 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002421
2422 if(ivideo->chip == SIS_300) {
Aaro Koskinene57d4132010-12-20 23:50:16 +02002423 myflag = SiS_GetReg(SISSR, 0x3b);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002424 if(!(myflag & 0x01)) vga2 = vga2_c = 0;
2425 }
2426
Thomas Winischhofer544393f2005-09-09 13:04:45 -07002427 if(!(ivideo->vbflags2 & VB2_SISVGA2BRIDGE)) {
2428 vga2 = vga2_c = 0;
2429 }
2430
Aaro Koskinene57d4132010-12-20 23:50:16 +02002431 backupSR_1e = SiS_GetReg(SISSR, 0x1e);
Aaro Koskinen27799d62010-12-20 23:50:18 +02002432 SiS_SetRegOR(SISSR, 0x1e, 0x20);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002433
Aaro Koskinene57d4132010-12-20 23:50:16 +02002434 backupP4_0d = SiS_GetReg(SISPART4, 0x0d);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07002435 if(ivideo->vbflags2 & VB2_30xC) {
Aaro Koskinenad78adb2010-12-20 23:50:20 +02002436 SiS_SetRegANDOR(SISPART4, 0x0d, ~0x07, 0x01);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002437 } else {
Aaro Koskinen27799d62010-12-20 23:50:18 +02002438 SiS_SetRegOR(SISPART4, 0x0d, 0x04);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002439 }
2440 SiS_DDC2Delay(&ivideo->SiS_Pr, 0x2000);
2441
Aaro Koskinene57d4132010-12-20 23:50:16 +02002442 backupP2_00 = SiS_GetReg(SISPART2, 0x00);
Aaro Koskinen44b751b2010-12-20 23:50:17 +02002443 SiS_SetReg(SISPART2, 0x00, ((backupP2_00 | 0x1c) & 0xfc));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002444
Aaro Koskinene57d4132010-12-20 23:50:16 +02002445 backupP2_4d = SiS_GetReg(SISPART2, 0x4d);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07002446 if(ivideo->vbflags2 & VB2_SISYPBPRBRIDGE) {
Aaro Koskinen44b751b2010-12-20 23:50:17 +02002447 SiS_SetReg(SISPART2, 0x4d, (backupP2_4d & ~0x10));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002448 }
2449
Thomas Winischhofer544393f2005-09-09 13:04:45 -07002450 if(!(ivideo->vbflags2 & VB2_30xCLV)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002451 SISDoSense(ivideo, 0, 0);
2452 }
2453
Aaro Koskinen667a8b42010-12-20 23:50:19 +02002454 SiS_SetRegAND(SISCR, 0x32, ~0x14);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002455
2456 if(vga2_c || vga2) {
2457 if(SISDoSense(ivideo, vga2, vga2_c)) {
2458 if(biosflag & 0x01) {
2459 printk(KERN_INFO "%s %s SCART output\n", stdstr, tvstr);
Aaro Koskinen27799d62010-12-20 23:50:18 +02002460 SiS_SetRegOR(SISCR, 0x32, 0x04);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002461 } else {
2462 printk(KERN_INFO "%s secondary VGA connection\n", stdstr);
Aaro Koskinen27799d62010-12-20 23:50:18 +02002463 SiS_SetRegOR(SISCR, 0x32, 0x10);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002464 }
2465 }
2466 }
2467
Aaro Koskinen667a8b42010-12-20 23:50:19 +02002468 SiS_SetRegAND(SISCR, 0x32, 0x3f);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002469
Thomas Winischhofer544393f2005-09-09 13:04:45 -07002470 if(ivideo->vbflags2 & VB2_30xCLV) {
Aaro Koskinen27799d62010-12-20 23:50:18 +02002471 SiS_SetRegOR(SISPART4, 0x0d, 0x04);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002472 }
2473
Thomas Winischhofer544393f2005-09-09 13:04:45 -07002474 if((ivideo->sisvga_engine == SIS_315_VGA) && (ivideo->vbflags2 & VB2_SISYPBPRBRIDGE)) {
Aaro Koskinen44b751b2010-12-20 23:50:17 +02002475 SiS_SetReg(SISPART2, 0x4d, (backupP2_4d | 0x10));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002476 SiS_DDC2Delay(&ivideo->SiS_Pr, 0x2000);
2477 if((result = SISDoSense(ivideo, svhs, 0x0604))) {
2478 if((result = SISDoSense(ivideo, cvbs, 0x0804))) {
2479 printk(KERN_INFO "%s %s YPbPr component output\n", stdstr, tvstr);
Aaro Koskinen27799d62010-12-20 23:50:18 +02002480 SiS_SetRegOR(SISCR, 0x32, 0x80);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002481 }
2482 }
Aaro Koskinen44b751b2010-12-20 23:50:17 +02002483 SiS_SetReg(SISPART2, 0x4d, backupP2_4d);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002484 }
2485
Aaro Koskinen667a8b42010-12-20 23:50:19 +02002486 SiS_SetRegAND(SISCR, 0x32, ~0x03);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002487
2488 if(!(ivideo->vbflags & TV_YPBPR)) {
2489 if((result = SISDoSense(ivideo, svhs, svhs_c))) {
2490 printk(KERN_INFO "%s %s SVIDEO output\n", stdstr, tvstr);
Aaro Koskinen27799d62010-12-20 23:50:18 +02002491 SiS_SetRegOR(SISCR, 0x32, 0x02);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002492 }
2493 if((biosflag & 0x02) || (!result)) {
2494 if(SISDoSense(ivideo, cvbs, cvbs_c)) {
2495 printk(KERN_INFO "%s %s COMPOSITE output\n", stdstr, tvstr);
Aaro Koskinen27799d62010-12-20 23:50:18 +02002496 SiS_SetRegOR(SISCR, 0x32, 0x01);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002497 }
2498 }
2499 }
2500
2501 SISDoSense(ivideo, 0, 0);
2502
Aaro Koskinen44b751b2010-12-20 23:50:17 +02002503 SiS_SetReg(SISPART2, 0x00, backupP2_00);
2504 SiS_SetReg(SISPART4, 0x0d, backupP4_0d);
2505 SiS_SetReg(SISSR, 0x1e, backupSR_1e);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002506
Thomas Winischhofer544393f2005-09-09 13:04:45 -07002507 if(ivideo->vbflags2 & VB2_30xCLV) {
Aaro Koskinene57d4132010-12-20 23:50:16 +02002508 biosflag = SiS_GetReg(SISPART2, 0x00);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002509 if(biosflag & 0x20) {
2510 for(myflag = 2; myflag > 0; myflag--) {
2511 biosflag ^= 0x20;
Aaro Koskinen44b751b2010-12-20 23:50:17 +02002512 SiS_SetReg(SISPART2, 0x00, biosflag);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002513 }
2514 }
2515 }
2516
Aaro Koskinen44b751b2010-12-20 23:50:17 +02002517 SiS_SetReg(SISPART2, 0x00, backupP2_00);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002518}
2519
2520/* Determine and detect attached TV's on Chrontel */
Thomas Winischhofer544393f2005-09-09 13:04:45 -07002521static void __devinit
2522SiS_SenseCh(struct sis_video_info *ivideo)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002523{
2524#if defined(CONFIG_FB_SIS_300) || defined(CONFIG_FB_SIS_315)
2525 u8 temp1, temp2;
2526 char stdstr[] = "sisfb: Chrontel: Detected TV connected to";
2527#endif
2528#ifdef CONFIG_FB_SIS_300
2529 unsigned char test[3];
2530 int i;
2531#endif
2532
2533 if(ivideo->chip < SIS_315H) {
2534
2535#ifdef CONFIG_FB_SIS_300
2536 ivideo->SiS_Pr.SiS_IF_DEF_CH70xx = 1; /* Chrontel 700x */
2537 SiS_SetChrontelGPIO(&ivideo->SiS_Pr, 0x9c); /* Set general purpose IO for Chrontel communication */
2538 SiS_DDC2Delay(&ivideo->SiS_Pr, 1000);
2539 temp1 = SiS_GetCH700x(&ivideo->SiS_Pr, 0x25);
2540 /* See Chrontel TB31 for explanation */
2541 temp2 = SiS_GetCH700x(&ivideo->SiS_Pr, 0x0e);
2542 if(((temp2 & 0x07) == 0x01) || (temp2 & 0x04)) {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07002543 SiS_SetCH700x(&ivideo->SiS_Pr, 0x0e, 0x0b);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002544 SiS_DDC2Delay(&ivideo->SiS_Pr, 300);
2545 }
2546 temp2 = SiS_GetCH700x(&ivideo->SiS_Pr, 0x25);
2547 if(temp2 != temp1) temp1 = temp2;
2548
2549 if((temp1 >= 0x22) && (temp1 <= 0x50)) {
2550 /* Read power status */
2551 temp1 = SiS_GetCH700x(&ivideo->SiS_Pr, 0x0e);
2552 if((temp1 & 0x03) != 0x03) {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07002553 /* Power all outputs */
2554 SiS_SetCH700x(&ivideo->SiS_Pr, 0x0e,0x0b);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002555 SiS_DDC2Delay(&ivideo->SiS_Pr, 300);
2556 }
2557 /* Sense connected TV devices */
2558 for(i = 0; i < 3; i++) {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07002559 SiS_SetCH700x(&ivideo->SiS_Pr, 0x10, 0x01);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002560 SiS_DDC2Delay(&ivideo->SiS_Pr, 0x96);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07002561 SiS_SetCH700x(&ivideo->SiS_Pr, 0x10, 0x00);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002562 SiS_DDC2Delay(&ivideo->SiS_Pr, 0x96);
2563 temp1 = SiS_GetCH700x(&ivideo->SiS_Pr, 0x10);
2564 if(!(temp1 & 0x08)) test[i] = 0x02;
2565 else if(!(temp1 & 0x02)) test[i] = 0x01;
2566 else test[i] = 0;
2567 SiS_DDC2Delay(&ivideo->SiS_Pr, 0x96);
2568 }
2569
2570 if(test[0] == test[1]) temp1 = test[0];
2571 else if(test[0] == test[2]) temp1 = test[0];
2572 else if(test[1] == test[2]) temp1 = test[1];
2573 else {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07002574 printk(KERN_INFO
Linus Torvalds1da177e2005-04-16 15:20:36 -07002575 "sisfb: TV detection unreliable - test results varied\n");
2576 temp1 = test[2];
2577 }
2578 if(temp1 == 0x02) {
2579 printk(KERN_INFO "%s SVIDEO output\n", stdstr);
2580 ivideo->vbflags |= TV_SVIDEO;
Aaro Koskinen27799d62010-12-20 23:50:18 +02002581 SiS_SetRegOR(SISCR, 0x32, 0x02);
Aaro Koskinen667a8b42010-12-20 23:50:19 +02002582 SiS_SetRegAND(SISCR, 0x32, ~0x05);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002583 } else if (temp1 == 0x01) {
2584 printk(KERN_INFO "%s CVBS output\n", stdstr);
2585 ivideo->vbflags |= TV_AVIDEO;
Aaro Koskinen27799d62010-12-20 23:50:18 +02002586 SiS_SetRegOR(SISCR, 0x32, 0x01);
Aaro Koskinen667a8b42010-12-20 23:50:19 +02002587 SiS_SetRegAND(SISCR, 0x32, ~0x06);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002588 } else {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07002589 SiS_SetCH70xxANDOR(&ivideo->SiS_Pr, 0x0e, 0x01, 0xF8);
Aaro Koskinen667a8b42010-12-20 23:50:19 +02002590 SiS_SetRegAND(SISCR, 0x32, ~0x07);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002591 }
2592 } else if(temp1 == 0) {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07002593 SiS_SetCH70xxANDOR(&ivideo->SiS_Pr, 0x0e, 0x01, 0xF8);
Aaro Koskinen667a8b42010-12-20 23:50:19 +02002594 SiS_SetRegAND(SISCR, 0x32, ~0x07);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002595 }
2596 /* Set general purpose IO for Chrontel communication */
2597 SiS_SetChrontelGPIO(&ivideo->SiS_Pr, 0x00);
2598#endif
2599
2600 } else {
2601
2602#ifdef CONFIG_FB_SIS_315
2603 ivideo->SiS_Pr.SiS_IF_DEF_CH70xx = 2; /* Chrontel 7019 */
Thomas Winischhofer544393f2005-09-09 13:04:45 -07002604 temp1 = SiS_GetCH701x(&ivideo->SiS_Pr, 0x49);
2605 SiS_SetCH701x(&ivideo->SiS_Pr, 0x49, 0x20);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002606 SiS_DDC2Delay(&ivideo->SiS_Pr, 0x96);
2607 temp2 = SiS_GetCH701x(&ivideo->SiS_Pr, 0x20);
2608 temp2 |= 0x01;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07002609 SiS_SetCH701x(&ivideo->SiS_Pr, 0x20, temp2);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002610 SiS_DDC2Delay(&ivideo->SiS_Pr, 0x96);
2611 temp2 ^= 0x01;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07002612 SiS_SetCH701x(&ivideo->SiS_Pr, 0x20, temp2);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002613 SiS_DDC2Delay(&ivideo->SiS_Pr, 0x96);
2614 temp2 = SiS_GetCH701x(&ivideo->SiS_Pr, 0x20);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07002615 SiS_SetCH701x(&ivideo->SiS_Pr, 0x49, temp1);
2616 temp1 = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002617 if(temp2 & 0x02) temp1 |= 0x01;
2618 if(temp2 & 0x10) temp1 |= 0x01;
2619 if(temp2 & 0x04) temp1 |= 0x02;
2620 if( (temp1 & 0x01) && (temp1 & 0x02) ) temp1 = 0x04;
2621 switch(temp1) {
2622 case 0x01:
2623 printk(KERN_INFO "%s CVBS output\n", stdstr);
2624 ivideo->vbflags |= TV_AVIDEO;
Aaro Koskinen27799d62010-12-20 23:50:18 +02002625 SiS_SetRegOR(SISCR, 0x32, 0x01);
Aaro Koskinen667a8b42010-12-20 23:50:19 +02002626 SiS_SetRegAND(SISCR, 0x32, ~0x06);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07002627 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002628 case 0x02:
2629 printk(KERN_INFO "%s SVIDEO output\n", stdstr);
2630 ivideo->vbflags |= TV_SVIDEO;
Aaro Koskinen27799d62010-12-20 23:50:18 +02002631 SiS_SetRegOR(SISCR, 0x32, 0x02);
Aaro Koskinen667a8b42010-12-20 23:50:19 +02002632 SiS_SetRegAND(SISCR, 0x32, ~0x05);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07002633 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002634 case 0x04:
2635 printk(KERN_INFO "%s SCART output\n", stdstr);
Aaro Koskinen27799d62010-12-20 23:50:18 +02002636 SiS_SetRegOR(SISCR, 0x32, 0x04);
Aaro Koskinen667a8b42010-12-20 23:50:19 +02002637 SiS_SetRegAND(SISCR, 0x32, ~0x03);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07002638 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002639 default:
Aaro Koskinen667a8b42010-12-20 23:50:19 +02002640 SiS_SetRegAND(SISCR, 0x32, ~0x07);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002641 }
2642#endif
2643 }
2644}
2645
Thomas Winischhofer544393f2005-09-09 13:04:45 -07002646static void __devinit
2647sisfb_get_VB_type(struct sis_video_info *ivideo)
2648{
2649 char stdstr[] = "sisfb: Detected";
2650 char bridgestr[] = "video bridge";
2651 u8 vb_chipid;
2652 u8 reg;
2653
2654 /* No CRT2 on XGI Z7 */
2655 if(ivideo->chip == XGI_20)
2656 return;
2657
Aaro Koskinene57d4132010-12-20 23:50:16 +02002658 vb_chipid = SiS_GetReg(SISPART4, 0x00);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07002659 switch(vb_chipid) {
2660 case 0x01:
Aaro Koskinene57d4132010-12-20 23:50:16 +02002661 reg = SiS_GetReg(SISPART4, 0x01);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07002662 if(reg < 0xb0) {
2663 ivideo->vbflags |= VB_301; /* Deprecated */
2664 ivideo->vbflags2 |= VB2_301;
2665 printk(KERN_INFO "%s SiS301 %s\n", stdstr, bridgestr);
2666 } else if(reg < 0xc0) {
2667 ivideo->vbflags |= VB_301B; /* Deprecated */
2668 ivideo->vbflags2 |= VB2_301B;
Aaro Koskinene57d4132010-12-20 23:50:16 +02002669 reg = SiS_GetReg(SISPART4, 0x23);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07002670 if(!(reg & 0x02)) {
2671 ivideo->vbflags |= VB_30xBDH; /* Deprecated */
2672 ivideo->vbflags2 |= VB2_30xBDH;
2673 printk(KERN_INFO "%s SiS301B-DH %s\n", stdstr, bridgestr);
2674 } else {
2675 printk(KERN_INFO "%s SiS301B %s\n", stdstr, bridgestr);
2676 }
2677 } else if(reg < 0xd0) {
2678 ivideo->vbflags |= VB_301C; /* Deprecated */
2679 ivideo->vbflags2 |= VB2_301C;
2680 printk(KERN_INFO "%s SiS301C %s\n", stdstr, bridgestr);
2681 } else if(reg < 0xe0) {
2682 ivideo->vbflags |= VB_301LV; /* Deprecated */
2683 ivideo->vbflags2 |= VB2_301LV;
2684 printk(KERN_INFO "%s SiS301LV %s\n", stdstr, bridgestr);
2685 } else if(reg <= 0xe1) {
Aaro Koskinene57d4132010-12-20 23:50:16 +02002686 reg = SiS_GetReg(SISPART4, 0x39);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07002687 if(reg == 0xff) {
2688 ivideo->vbflags |= VB_302LV; /* Deprecated */
2689 ivideo->vbflags2 |= VB2_302LV;
2690 printk(KERN_INFO "%s SiS302LV %s\n", stdstr, bridgestr);
2691 } else {
2692 ivideo->vbflags |= VB_301C; /* Deprecated */
2693 ivideo->vbflags2 |= VB2_301C;
2694 printk(KERN_INFO "%s SiS301C(P4) %s\n", stdstr, bridgestr);
2695#if 0
2696 ivideo->vbflags |= VB_302ELV; /* Deprecated */
2697 ivideo->vbflags2 |= VB2_302ELV;
2698 printk(KERN_INFO "%s SiS302ELV %s\n", stdstr, bridgestr);
2699#endif
2700 }
2701 }
2702 break;
2703 case 0x02:
2704 ivideo->vbflags |= VB_302B; /* Deprecated */
2705 ivideo->vbflags2 |= VB2_302B;
2706 printk(KERN_INFO "%s SiS302B %s\n", stdstr, bridgestr);
2707 break;
2708 }
2709
2710 if((!(ivideo->vbflags2 & VB2_VIDEOBRIDGE)) && (ivideo->chip != SIS_300)) {
Aaro Koskinene57d4132010-12-20 23:50:16 +02002711 reg = SiS_GetReg(SISCR, 0x37);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07002712 reg &= SIS_EXTERNAL_CHIP_MASK;
2713 reg >>= 1;
2714 if(ivideo->sisvga_engine == SIS_300_VGA) {
2715#ifdef CONFIG_FB_SIS_300
2716 switch(reg) {
2717 case SIS_EXTERNAL_CHIP_LVDS:
2718 ivideo->vbflags |= VB_LVDS; /* Deprecated */
2719 ivideo->vbflags2 |= VB2_LVDS;
2720 break;
2721 case SIS_EXTERNAL_CHIP_TRUMPION:
2722 ivideo->vbflags |= (VB_LVDS | VB_TRUMPION); /* Deprecated */
2723 ivideo->vbflags2 |= (VB2_LVDS | VB2_TRUMPION);
2724 break;
2725 case SIS_EXTERNAL_CHIP_CHRONTEL:
2726 ivideo->vbflags |= VB_CHRONTEL; /* Deprecated */
2727 ivideo->vbflags2 |= VB2_CHRONTEL;
2728 break;
2729 case SIS_EXTERNAL_CHIP_LVDS_CHRONTEL:
2730 ivideo->vbflags |= (VB_LVDS | VB_CHRONTEL); /* Deprecated */
2731 ivideo->vbflags2 |= (VB2_LVDS | VB2_CHRONTEL);
2732 break;
2733 }
2734 if(ivideo->vbflags2 & VB2_CHRONTEL) ivideo->chronteltype = 1;
2735#endif
2736 } else if(ivideo->chip < SIS_661) {
2737#ifdef CONFIG_FB_SIS_315
2738 switch (reg) {
2739 case SIS310_EXTERNAL_CHIP_LVDS:
2740 ivideo->vbflags |= VB_LVDS; /* Deprecated */
2741 ivideo->vbflags2 |= VB2_LVDS;
2742 break;
2743 case SIS310_EXTERNAL_CHIP_LVDS_CHRONTEL:
2744 ivideo->vbflags |= (VB_LVDS | VB_CHRONTEL); /* Deprecated */
2745 ivideo->vbflags2 |= (VB2_LVDS | VB2_CHRONTEL);
2746 break;
2747 }
2748 if(ivideo->vbflags2 & VB2_CHRONTEL) ivideo->chronteltype = 2;
2749#endif
2750 } else if(ivideo->chip >= SIS_661) {
2751#ifdef CONFIG_FB_SIS_315
Aaro Koskinene57d4132010-12-20 23:50:16 +02002752 reg = SiS_GetReg(SISCR, 0x38);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07002753 reg >>= 5;
2754 switch(reg) {
2755 case 0x02:
2756 ivideo->vbflags |= VB_LVDS; /* Deprecated */
2757 ivideo->vbflags2 |= VB2_LVDS;
2758 break;
2759 case 0x03:
2760 ivideo->vbflags |= (VB_LVDS | VB_CHRONTEL); /* Deprecated */
2761 ivideo->vbflags2 |= (VB2_LVDS | VB2_CHRONTEL);
2762 break;
2763 case 0x04:
2764 ivideo->vbflags |= (VB_LVDS | VB_CONEXANT); /* Deprecated */
2765 ivideo->vbflags2 |= (VB2_LVDS | VB2_CONEXANT);
2766 break;
2767 }
2768 if(ivideo->vbflags2 & VB2_CHRONTEL) ivideo->chronteltype = 2;
2769#endif
2770 }
2771 if(ivideo->vbflags2 & VB2_LVDS) {
2772 printk(KERN_INFO "%s LVDS transmitter\n", stdstr);
2773 }
2774 if((ivideo->sisvga_engine == SIS_300_VGA) && (ivideo->vbflags2 & VB2_TRUMPION)) {
2775 printk(KERN_INFO "%s Trumpion Zurac LCD scaler\n", stdstr);
2776 }
2777 if(ivideo->vbflags2 & VB2_CHRONTEL) {
2778 printk(KERN_INFO "%s Chrontel TV encoder\n", stdstr);
2779 }
2780 if((ivideo->chip >= SIS_661) && (ivideo->vbflags2 & VB2_CONEXANT)) {
2781 printk(KERN_INFO "%s Conexant external device\n", stdstr);
2782 }
2783 }
2784
2785 if(ivideo->vbflags2 & VB2_SISBRIDGE) {
2786 SiS_SenseLCD(ivideo);
2787 SiS_Sense30x(ivideo);
2788 } else if(ivideo->vbflags2 & VB2_CHRONTEL) {
2789 SiS_SenseCh(ivideo);
2790 }
2791}
2792
2793/* ---------- Engine initialization routines ------------ */
2794
2795static void
2796sisfb_engine_init(struct sis_video_info *ivideo)
2797{
2798
2799 /* Initialize command queue (we use MMIO only) */
2800
2801 /* BEFORE THIS IS CALLED, THE ENGINES *MUST* BE SYNC'ED */
2802
2803 ivideo->caps &= ~(TURBO_QUEUE_CAP |
2804 MMIO_CMD_QUEUE_CAP |
2805 VM_CMD_QUEUE_CAP |
2806 AGP_CMD_QUEUE_CAP);
2807
2808#ifdef CONFIG_FB_SIS_300
2809 if(ivideo->sisvga_engine == SIS_300_VGA) {
2810 u32 tqueue_pos;
2811 u8 tq_state;
2812
2813 tqueue_pos = (ivideo->video_size - ivideo->cmdQueueSize) / (64 * 1024);
2814
Aaro Koskinene57d4132010-12-20 23:50:16 +02002815 tq_state = SiS_GetReg(SISSR, IND_SIS_TURBOQUEUE_SET);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07002816 tq_state |= 0xf0;
2817 tq_state &= 0xfc;
2818 tq_state |= (u8)(tqueue_pos >> 8);
Aaro Koskinen44b751b2010-12-20 23:50:17 +02002819 SiS_SetReg(SISSR, IND_SIS_TURBOQUEUE_SET, tq_state);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07002820
Aaro Koskinen44b751b2010-12-20 23:50:17 +02002821 SiS_SetReg(SISSR, IND_SIS_TURBOQUEUE_ADR, (u8)(tqueue_pos & 0xff));
Thomas Winischhofer544393f2005-09-09 13:04:45 -07002822
2823 ivideo->caps |= TURBO_QUEUE_CAP;
2824 }
2825#endif
2826
2827#ifdef CONFIG_FB_SIS_315
2828 if(ivideo->sisvga_engine == SIS_315_VGA) {
2829 u32 tempq = 0, templ;
2830 u8 temp;
2831
2832 if(ivideo->chip == XGI_20) {
2833 switch(ivideo->cmdQueueSize) {
2834 case (64 * 1024):
2835 temp = SIS_CMD_QUEUE_SIZE_Z7_64k;
2836 break;
2837 case (128 * 1024):
2838 default:
2839 temp = SIS_CMD_QUEUE_SIZE_Z7_128k;
2840 }
2841 } else {
2842 switch(ivideo->cmdQueueSize) {
2843 case (4 * 1024 * 1024):
2844 temp = SIS_CMD_QUEUE_SIZE_4M;
2845 break;
2846 case (2 * 1024 * 1024):
2847 temp = SIS_CMD_QUEUE_SIZE_2M;
2848 break;
2849 case (1 * 1024 * 1024):
2850 temp = SIS_CMD_QUEUE_SIZE_1M;
2851 break;
2852 default:
2853 case (512 * 1024):
2854 temp = SIS_CMD_QUEUE_SIZE_512k;
2855 }
2856 }
2857
Aaro Koskinen44b751b2010-12-20 23:50:17 +02002858 SiS_SetReg(SISSR, IND_SIS_CMDQUEUE_THRESHOLD, COMMAND_QUEUE_THRESHOLD);
2859 SiS_SetReg(SISSR, IND_SIS_CMDQUEUE_SET, SIS_CMD_QUEUE_RESET);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07002860
2861 if((ivideo->chip >= XGI_40) && ivideo->modechanged) {
2862 /* Must disable dual pipe on XGI_40. Can't do
2863 * this in MMIO mode, because it requires
2864 * setting/clearing a bit in the MMIO fire trigger
2865 * register.
2866 */
2867 if(!((templ = MMIO_IN32(ivideo->mmio_vbase, 0x8240)) & (1 << 10))) {
2868
2869 MMIO_OUT32(ivideo->mmio_vbase, Q_WRITE_PTR, 0);
2870
Aaro Koskinen44b751b2010-12-20 23:50:17 +02002871 SiS_SetReg(SISSR, IND_SIS_CMDQUEUE_SET, (temp | SIS_VRAM_CMDQUEUE_ENABLE));
Thomas Winischhofer544393f2005-09-09 13:04:45 -07002872
2873 tempq = MMIO_IN32(ivideo->mmio_vbase, Q_READ_PTR);
2874 MMIO_OUT32(ivideo->mmio_vbase, Q_WRITE_PTR, tempq);
2875
2876 tempq = (u32)(ivideo->video_size - ivideo->cmdQueueSize);
2877 MMIO_OUT32(ivideo->mmio_vbase, Q_BASE_ADDR, tempq);
2878
2879 writel(0x16800000 + 0x8240, ivideo->video_vbase + tempq);
2880 writel(templ | (1 << 10), ivideo->video_vbase + tempq + 4);
2881 writel(0x168F0000, ivideo->video_vbase + tempq + 8);
2882 writel(0x168F0000, ivideo->video_vbase + tempq + 12);
2883
2884 MMIO_OUT32(ivideo->mmio_vbase, Q_WRITE_PTR, (tempq + 16));
2885
2886 sisfb_syncaccel(ivideo);
2887
Aaro Koskinen44b751b2010-12-20 23:50:17 +02002888 SiS_SetReg(SISSR, IND_SIS_CMDQUEUE_SET, SIS_CMD_QUEUE_RESET);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07002889
2890 }
2891 }
2892
2893 tempq = MMIO_IN32(ivideo->mmio_vbase, MMIO_QUEUE_READPORT);
2894 MMIO_OUT32(ivideo->mmio_vbase, MMIO_QUEUE_WRITEPORT, tempq);
2895
2896 temp |= (SIS_MMIO_CMD_ENABLE | SIS_CMD_AUTO_CORR);
Aaro Koskinen44b751b2010-12-20 23:50:17 +02002897 SiS_SetReg(SISSR, IND_SIS_CMDQUEUE_SET, temp);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07002898
2899 tempq = (u32)(ivideo->video_size - ivideo->cmdQueueSize);
2900 MMIO_OUT32(ivideo->mmio_vbase, MMIO_QUEUE_PHYBASE, tempq);
2901
2902 ivideo->caps |= MMIO_CMD_QUEUE_CAP;
2903 }
2904#endif
2905
2906 ivideo->engineok = 1;
2907}
2908
2909static void __devinit
2910sisfb_detect_lcd_type(struct sis_video_info *ivideo)
2911{
2912 u8 reg;
2913 int i;
2914
Aaro Koskinene57d4132010-12-20 23:50:16 +02002915 reg = SiS_GetReg(SISCR, 0x36);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07002916 reg &= 0x0f;
2917 if(ivideo->sisvga_engine == SIS_300_VGA) {
2918 ivideo->CRT2LCDType = sis300paneltype[reg];
2919 } else if(ivideo->chip >= SIS_661) {
2920 ivideo->CRT2LCDType = sis661paneltype[reg];
2921 } else {
2922 ivideo->CRT2LCDType = sis310paneltype[reg];
2923 if((ivideo->chip == SIS_550) && (sisfb_fstn)) {
2924 if((ivideo->CRT2LCDType != LCD_320x240_2) &&
2925 (ivideo->CRT2LCDType != LCD_320x240_3)) {
2926 ivideo->CRT2LCDType = LCD_320x240;
2927 }
2928 }
2929 }
2930
2931 if(ivideo->CRT2LCDType == LCD_UNKNOWN) {
2932 /* For broken BIOSes: Assume 1024x768, RGB18 */
2933 ivideo->CRT2LCDType = LCD_1024x768;
Aaro Koskinenad78adb2010-12-20 23:50:20 +02002934 SiS_SetRegANDOR(SISCR, 0x36, 0xf0, 0x02);
2935 SiS_SetRegANDOR(SISCR, 0x37, 0xee, 0x01);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07002936 printk(KERN_DEBUG "sisfb: Invalid panel ID (%02x), assuming 1024x768, RGB18\n", reg);
2937 }
2938
2939 for(i = 0; i < SIS_LCD_NUMBER; i++) {
2940 if(ivideo->CRT2LCDType == sis_lcd_data[i].lcdtype) {
2941 ivideo->lcdxres = sis_lcd_data[i].xres;
2942 ivideo->lcdyres = sis_lcd_data[i].yres;
2943 ivideo->lcddefmodeidx = sis_lcd_data[i].default_mode_idx;
2944 break;
2945 }
2946 }
2947
2948#ifdef CONFIG_FB_SIS_300
2949 if(ivideo->SiS_Pr.SiS_CustomT == CUT_BARCO1366) {
2950 ivideo->lcdxres = 1360; ivideo->lcdyres = 1024;
2951 ivideo->lcddefmodeidx = DEFAULT_MODE_1360;
2952 } else if(ivideo->SiS_Pr.SiS_CustomT == CUT_PANEL848) {
2953 ivideo->lcdxres = 848; ivideo->lcdyres = 480;
2954 ivideo->lcddefmodeidx = DEFAULT_MODE_848;
2955 } else if(ivideo->SiS_Pr.SiS_CustomT == CUT_PANEL856) {
2956 ivideo->lcdxres = 856; ivideo->lcdyres = 480;
2957 ivideo->lcddefmodeidx = DEFAULT_MODE_856;
2958 }
2959#endif
2960
2961 printk(KERN_DEBUG "sisfb: Detected %dx%d flat panel\n",
2962 ivideo->lcdxres, ivideo->lcdyres);
2963}
2964
2965static void __devinit
2966sisfb_save_pdc_emi(struct sis_video_info *ivideo)
2967{
2968#ifdef CONFIG_FB_SIS_300
2969 /* Save the current PanelDelayCompensation if the LCD is currently used */
2970 if(ivideo->sisvga_engine == SIS_300_VGA) {
2971 if(ivideo->vbflags2 & (VB2_LVDS | VB2_30xBDH)) {
2972 int tmp;
Aaro Koskinene57d4132010-12-20 23:50:16 +02002973 tmp = SiS_GetReg(SISCR, 0x30);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07002974 if(tmp & 0x20) {
2975 /* Currently on LCD? If yes, read current pdc */
Aaro Koskinene57d4132010-12-20 23:50:16 +02002976 ivideo->detectedpdc = SiS_GetReg(SISPART1, 0x13);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07002977 ivideo->detectedpdc &= 0x3c;
2978 if(ivideo->SiS_Pr.PDC == -1) {
2979 /* Let option override detection */
2980 ivideo->SiS_Pr.PDC = ivideo->detectedpdc;
2981 }
2982 printk(KERN_INFO "sisfb: Detected LCD PDC 0x%02x\n",
2983 ivideo->detectedpdc);
2984 }
2985 if((ivideo->SiS_Pr.PDC != -1) &&
2986 (ivideo->SiS_Pr.PDC != ivideo->detectedpdc)) {
2987 printk(KERN_INFO "sisfb: Using LCD PDC 0x%02x\n",
2988 ivideo->SiS_Pr.PDC);
2989 }
2990 }
2991 }
2992#endif
2993
2994#ifdef CONFIG_FB_SIS_315
2995 if(ivideo->sisvga_engine == SIS_315_VGA) {
2996
2997 /* Try to find about LCDA */
2998 if(ivideo->vbflags2 & VB2_SISLCDABRIDGE) {
2999 int tmp;
Aaro Koskinene57d4132010-12-20 23:50:16 +02003000 tmp = SiS_GetReg(SISPART1, 0x13);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003001 if(tmp & 0x04) {
Richard Knutssonc30660ea2007-02-12 00:55:06 -08003002 ivideo->SiS_Pr.SiS_UseLCDA = true;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003003 ivideo->detectedlcda = 0x03;
3004 }
3005 }
3006
3007 /* Save PDC */
3008 if(ivideo->vbflags2 & VB2_SISLVDSBRIDGE) {
3009 int tmp;
Aaro Koskinene57d4132010-12-20 23:50:16 +02003010 tmp = SiS_GetReg(SISCR, 0x30);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003011 if((tmp & 0x20) || (ivideo->detectedlcda != 0xff)) {
3012 /* Currently on LCD? If yes, read current pdc */
3013 u8 pdc;
Aaro Koskinene57d4132010-12-20 23:50:16 +02003014 pdc = SiS_GetReg(SISPART1, 0x2D);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003015 ivideo->detectedpdc = (pdc & 0x0f) << 1;
3016 ivideo->detectedpdca = (pdc & 0xf0) >> 3;
Aaro Koskinene57d4132010-12-20 23:50:16 +02003017 pdc = SiS_GetReg(SISPART1, 0x35);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003018 ivideo->detectedpdc |= ((pdc >> 7) & 0x01);
Aaro Koskinene57d4132010-12-20 23:50:16 +02003019 pdc = SiS_GetReg(SISPART1, 0x20);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003020 ivideo->detectedpdca |= ((pdc >> 6) & 0x01);
3021 if(ivideo->newrom) {
3022 /* New ROM invalidates other PDC resp. */
3023 if(ivideo->detectedlcda != 0xff) {
3024 ivideo->detectedpdc = 0xff;
3025 } else {
3026 ivideo->detectedpdca = 0xff;
3027 }
3028 }
3029 if(ivideo->SiS_Pr.PDC == -1) {
3030 if(ivideo->detectedpdc != 0xff) {
3031 ivideo->SiS_Pr.PDC = ivideo->detectedpdc;
3032 }
3033 }
3034 if(ivideo->SiS_Pr.PDCA == -1) {
3035 if(ivideo->detectedpdca != 0xff) {
3036 ivideo->SiS_Pr.PDCA = ivideo->detectedpdca;
3037 }
3038 }
3039 if(ivideo->detectedpdc != 0xff) {
3040 printk(KERN_INFO
3041 "sisfb: Detected LCD PDC 0x%02x (for LCD=CRT2)\n",
3042 ivideo->detectedpdc);
3043 }
3044 if(ivideo->detectedpdca != 0xff) {
3045 printk(KERN_INFO
3046 "sisfb: Detected LCD PDC1 0x%02x (for LCD=CRT1)\n",
3047 ivideo->detectedpdca);
3048 }
3049 }
3050
3051 /* Save EMI */
3052 if(ivideo->vbflags2 & VB2_SISEMIBRIDGE) {
Aaro Koskinene57d4132010-12-20 23:50:16 +02003053 ivideo->SiS_Pr.EMI_30 = SiS_GetReg(SISPART4, 0x30);
3054 ivideo->SiS_Pr.EMI_31 = SiS_GetReg(SISPART4, 0x31);
3055 ivideo->SiS_Pr.EMI_32 = SiS_GetReg(SISPART4, 0x32);
3056 ivideo->SiS_Pr.EMI_33 = SiS_GetReg(SISPART4, 0x33);
Richard Knutssonc30660ea2007-02-12 00:55:06 -08003057 ivideo->SiS_Pr.HaveEMI = true;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003058 if((tmp & 0x20) || (ivideo->detectedlcda != 0xff)) {
Richard Knutssonc30660ea2007-02-12 00:55:06 -08003059 ivideo->SiS_Pr.HaveEMILCD = true;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003060 }
3061 }
3062 }
3063
3064 /* Let user override detected PDCs (all bridges) */
3065 if(ivideo->vbflags2 & VB2_30xBLV) {
3066 if((ivideo->SiS_Pr.PDC != -1) &&
3067 (ivideo->SiS_Pr.PDC != ivideo->detectedpdc)) {
3068 printk(KERN_INFO "sisfb: Using LCD PDC 0x%02x (for LCD=CRT2)\n",
3069 ivideo->SiS_Pr.PDC);
3070 }
3071 if((ivideo->SiS_Pr.PDCA != -1) &&
3072 (ivideo->SiS_Pr.PDCA != ivideo->detectedpdca)) {
3073 printk(KERN_INFO "sisfb: Using LCD PDC1 0x%02x (for LCD=CRT1)\n",
3074 ivideo->SiS_Pr.PDCA);
3075 }
3076 }
3077
3078 }
3079#endif
3080}
3081
3082/* -------------------- Memory manager routines ---------------------- */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003083
3084static u32 __devinit
3085sisfb_getheapstart(struct sis_video_info *ivideo)
3086{
3087 u32 ret = ivideo->sisfb_parm_mem * 1024;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003088 u32 maxoffs = ivideo->video_size - ivideo->hwcursor_size - ivideo->cmdQueueSize;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003089 u32 def;
3090
3091 /* Calculate heap start = end of memory for console
3092 *
3093 * CCCCCCCCDDDDDDDDDDDDDDDDDDDDDDDDDDDDHHHHQQQQQQQQQQ
3094 * C = console, D = heap, H = HWCursor, Q = cmd-queue
3095 *
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003096 * On 76x in UMA+LFB mode, the layout is as follows:
3097 * DDDDDDDDDDDCCCCCCCCCCCCCCCCCCCCCCCCHHHHQQQQQQQQQQQ
3098 * where the heap is the entire UMA area, eventually
3099 * into the LFB area if the given mem parameter is
3100 * higher than the size of the UMA memory.
3101 *
Linus Torvalds1da177e2005-04-16 15:20:36 -07003102 * Basically given by "mem" parameter
3103 *
3104 * maximum = videosize - cmd_queue - hwcursor
3105 * (results in a heap of size 0)
3106 * default = SiS 300: depends on videosize
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003107 * SiS 315/330/340/XGI: 32k below max
Linus Torvalds1da177e2005-04-16 15:20:36 -07003108 */
3109
3110 if(ivideo->sisvga_engine == SIS_300_VGA) {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003111 if(ivideo->video_size > 0x1000000) {
3112 def = 0xc00000;
3113 } else if(ivideo->video_size > 0x800000) {
3114 def = 0x800000;
3115 } else {
3116 def = 0x400000;
3117 }
3118 } else if(ivideo->UMAsize && ivideo->LFBsize) {
3119 ret = def = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003120 } else {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003121 def = maxoffs - 0x8000;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003122 }
3123
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003124 /* Use default for secondary card for now (FIXME) */
3125 if((!ret) || (ret > maxoffs) || (ivideo->cardnumber != 0))
3126 ret = def;
3127
3128 return ret;
3129}
3130
3131static u32 __devinit
3132sisfb_getheapsize(struct sis_video_info *ivideo)
3133{
3134 u32 max = ivideo->video_size - ivideo->hwcursor_size - ivideo->cmdQueueSize;
3135 u32 ret = 0;
3136
3137 if(ivideo->UMAsize && ivideo->LFBsize) {
3138 if( (!ivideo->sisfb_parm_mem) ||
3139 ((ivideo->sisfb_parm_mem * 1024) > max) ||
3140 ((max - (ivideo->sisfb_parm_mem * 1024)) < ivideo->UMAsize) ) {
3141 ret = ivideo->UMAsize;
3142 max -= ivideo->UMAsize;
3143 } else {
3144 ret = max - (ivideo->sisfb_parm_mem * 1024);
3145 max = ivideo->sisfb_parm_mem * 1024;
3146 }
3147 ivideo->video_offset = ret;
3148 ivideo->sisfb_mem = max;
3149 } else {
3150 ret = max - ivideo->heapstart;
3151 ivideo->sisfb_mem = ivideo->heapstart;
3152 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003153
3154 return ret;
3155}
3156
3157static int __devinit
3158sisfb_heap_init(struct sis_video_info *ivideo)
3159{
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003160 struct SIS_OH *poh;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003161
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003162 ivideo->video_offset = 0;
3163 if(ivideo->sisfb_parm_mem) {
3164 if( (ivideo->sisfb_parm_mem < (2 * 1024 * 1024)) ||
3165 (ivideo->sisfb_parm_mem > ivideo->video_size) ) {
3166 ivideo->sisfb_parm_mem = 0;
3167 }
3168 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003169
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003170 ivideo->heapstart = sisfb_getheapstart(ivideo);
3171 ivideo->sisfb_heap_size = sisfb_getheapsize(ivideo);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003172
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003173 ivideo->sisfb_heap_start = ivideo->video_vbase + ivideo->heapstart;
3174 ivideo->sisfb_heap_end = ivideo->sisfb_heap_start + ivideo->sisfb_heap_size;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003175
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003176 printk(KERN_INFO "sisfb: Memory heap starting at %dK, size %dK\n",
3177 (int)(ivideo->heapstart / 1024), (int)(ivideo->sisfb_heap_size / 1024));
Linus Torvalds1da177e2005-04-16 15:20:36 -07003178
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003179 ivideo->sisfb_heap.vinfo = ivideo;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003180
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003181 ivideo->sisfb_heap.poha_chain = NULL;
3182 ivideo->sisfb_heap.poh_freelist = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003183
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003184 poh = sisfb_poh_new_node(&ivideo->sisfb_heap);
3185 if(poh == NULL)
3186 return 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003187
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003188 poh->poh_next = &ivideo->sisfb_heap.oh_free;
3189 poh->poh_prev = &ivideo->sisfb_heap.oh_free;
3190 poh->size = ivideo->sisfb_heap_size;
3191 poh->offset = ivideo->heapstart;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003192
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003193 ivideo->sisfb_heap.oh_free.poh_next = poh;
3194 ivideo->sisfb_heap.oh_free.poh_prev = poh;
3195 ivideo->sisfb_heap.oh_free.size = 0;
3196 ivideo->sisfb_heap.max_freesize = poh->size;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003197
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003198 ivideo->sisfb_heap.oh_used.poh_next = &ivideo->sisfb_heap.oh_used;
3199 ivideo->sisfb_heap.oh_used.poh_prev = &ivideo->sisfb_heap.oh_used;
3200 ivideo->sisfb_heap.oh_used.size = SENTINEL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003201
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003202 if(ivideo->cardnumber == 0) {
3203 /* For the first card, make this heap the "global" one
3204 * for old DRM (which could handle only one card)
3205 */
3206 sisfb_heap = &ivideo->sisfb_heap;
3207 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003208
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003209 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003210}
3211
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003212static struct SIS_OH *
3213sisfb_poh_new_node(struct SIS_HEAP *memheap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003214{
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003215 struct SIS_OHALLOC *poha;
3216 struct SIS_OH *poh;
3217 unsigned long cOhs;
3218 int i;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003219
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003220 if(memheap->poh_freelist == NULL) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003221 poha = kmalloc(SIS_OH_ALLOC_SIZE, GFP_KERNEL);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003222 if(!poha)
3223 return NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003224
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003225 poha->poha_next = memheap->poha_chain;
3226 memheap->poha_chain = poha;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003227
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003228 cOhs = (SIS_OH_ALLOC_SIZE - sizeof(struct SIS_OHALLOC)) / sizeof(struct SIS_OH) + 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003229
3230 poh = &poha->aoh[0];
3231 for(i = cOhs - 1; i != 0; i--) {
3232 poh->poh_next = poh + 1;
3233 poh = poh + 1;
3234 }
3235
3236 poh->poh_next = NULL;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003237 memheap->poh_freelist = &poha->aoh[0];
Linus Torvalds1da177e2005-04-16 15:20:36 -07003238 }
3239
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003240 poh = memheap->poh_freelist;
3241 memheap->poh_freelist = poh->poh_next;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003242
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003243 return poh;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003244}
3245
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003246static struct SIS_OH *
3247sisfb_poh_allocate(struct SIS_HEAP *memheap, u32 size)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003248{
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003249 struct SIS_OH *pohThis;
3250 struct SIS_OH *pohRoot;
3251 int bAllocated = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003252
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003253 if(size > memheap->max_freesize) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003254 DPRINTK("sisfb: Can't allocate %dk video memory\n",
3255 (unsigned int) size / 1024);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003256 return NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003257 }
3258
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003259 pohThis = memheap->oh_free.poh_next;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003260
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003261 while(pohThis != &memheap->oh_free) {
3262 if(size <= pohThis->size) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003263 bAllocated = 1;
3264 break;
3265 }
3266 pohThis = pohThis->poh_next;
3267 }
3268
3269 if(!bAllocated) {
3270 DPRINTK("sisfb: Can't allocate %dk video memory\n",
3271 (unsigned int) size / 1024);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003272 return NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003273 }
3274
3275 if(size == pohThis->size) {
3276 pohRoot = pohThis;
3277 sisfb_delete_node(pohThis);
3278 } else {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003279 pohRoot = sisfb_poh_new_node(memheap);
3280 if(pohRoot == NULL)
3281 return NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003282
3283 pohRoot->offset = pohThis->offset;
3284 pohRoot->size = size;
3285
3286 pohThis->offset += size;
3287 pohThis->size -= size;
3288 }
3289
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003290 memheap->max_freesize -= size;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003291
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003292 pohThis = &memheap->oh_used;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003293 sisfb_insert_node(pohThis, pohRoot);
3294
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003295 return pohRoot;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003296}
3297
3298static void
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003299sisfb_delete_node(struct SIS_OH *poh)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003300{
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003301 poh->poh_prev->poh_next = poh->poh_next;
3302 poh->poh_next->poh_prev = poh->poh_prev;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003303}
3304
3305static void
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003306sisfb_insert_node(struct SIS_OH *pohList, struct SIS_OH *poh)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003307{
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003308 struct SIS_OH *pohTemp = pohList->poh_next;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003309
3310 pohList->poh_next = poh;
3311 pohTemp->poh_prev = poh;
3312
3313 poh->poh_prev = pohList;
3314 poh->poh_next = pohTemp;
3315}
3316
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003317static struct SIS_OH *
3318sisfb_poh_free(struct SIS_HEAP *memheap, u32 base)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003319{
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003320 struct SIS_OH *pohThis;
3321 struct SIS_OH *poh_freed;
3322 struct SIS_OH *poh_prev;
3323 struct SIS_OH *poh_next;
3324 u32 ulUpper;
3325 u32 ulLower;
3326 int foundNode = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003327
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003328 poh_freed = memheap->oh_used.poh_next;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003329
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003330 while(poh_freed != &memheap->oh_used) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003331 if(poh_freed->offset == base) {
3332 foundNode = 1;
3333 break;
3334 }
3335
3336 poh_freed = poh_freed->poh_next;
3337 }
3338
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003339 if(!foundNode)
3340 return NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003341
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003342 memheap->max_freesize += poh_freed->size;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003343
3344 poh_prev = poh_next = NULL;
3345 ulUpper = poh_freed->offset + poh_freed->size;
3346 ulLower = poh_freed->offset;
3347
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003348 pohThis = memheap->oh_free.poh_next;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003349
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003350 while(pohThis != &memheap->oh_free) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003351 if(pohThis->offset == ulUpper) {
3352 poh_next = pohThis;
3353 } else if((pohThis->offset + pohThis->size) == ulLower) {
3354 poh_prev = pohThis;
3355 }
3356 pohThis = pohThis->poh_next;
3357 }
3358
3359 sisfb_delete_node(poh_freed);
3360
3361 if(poh_prev && poh_next) {
3362 poh_prev->size += (poh_freed->size + poh_next->size);
3363 sisfb_delete_node(poh_next);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003364 sisfb_free_node(memheap, poh_freed);
3365 sisfb_free_node(memheap, poh_next);
3366 return poh_prev;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003367 }
3368
3369 if(poh_prev) {
3370 poh_prev->size += poh_freed->size;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003371 sisfb_free_node(memheap, poh_freed);
3372 return poh_prev;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003373 }
3374
3375 if(poh_next) {
3376 poh_next->size += poh_freed->size;
3377 poh_next->offset = poh_freed->offset;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003378 sisfb_free_node(memheap, poh_freed);
3379 return poh_next;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003380 }
3381
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003382 sisfb_insert_node(&memheap->oh_free, poh_freed);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003383
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003384 return poh_freed;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003385}
3386
3387static void
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003388sisfb_free_node(struct SIS_HEAP *memheap, struct SIS_OH *poh)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003389{
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003390 if(poh == NULL)
3391 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003392
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003393 poh->poh_next = memheap->poh_freelist;
3394 memheap->poh_freelist = poh;
3395}
3396
3397static void
3398sis_int_malloc(struct sis_video_info *ivideo, struct sis_memreq *req)
3399{
3400 struct SIS_OH *poh = NULL;
3401
3402 if((ivideo) && (ivideo->sisfb_id == SISFB_ID) && (!ivideo->havenoheap))
3403 poh = sisfb_poh_allocate(&ivideo->sisfb_heap, (u32)req->size);
3404
3405 if(poh == NULL) {
3406 req->offset = req->size = 0;
3407 DPRINTK("sisfb: Video RAM allocation failed\n");
3408 } else {
3409 req->offset = poh->offset;
3410 req->size = poh->size;
3411 DPRINTK("sisfb: Video RAM allocation succeeded: 0x%lx\n",
3412 (poh->offset + ivideo->video_vbase));
3413 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003414}
3415
3416void
3417sis_malloc(struct sis_memreq *req)
3418{
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003419 struct sis_video_info *ivideo = sisfb_heap->vinfo;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003420
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003421 if(&ivideo->sisfb_heap == sisfb_heap)
3422 sis_int_malloc(ivideo, req);
3423 else
3424 req->offset = req->size = 0;
3425}
Linus Torvalds1da177e2005-04-16 15:20:36 -07003426
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003427void
3428sis_malloc_new(struct pci_dev *pdev, struct sis_memreq *req)
3429{
3430 struct sis_video_info *ivideo = pci_get_drvdata(pdev);
3431
3432 sis_int_malloc(ivideo, req);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003433}
3434
3435/* sis_free: u32 because "base" is offset inside video ram, can never be >4GB */
3436
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003437static void
3438sis_int_free(struct sis_video_info *ivideo, u32 base)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003439{
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003440 struct SIS_OH *poh;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003441
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003442 if((!ivideo) || (ivideo->sisfb_id != SISFB_ID) || (ivideo->havenoheap))
3443 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003444
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003445 poh = sisfb_poh_free(&ivideo->sisfb_heap, base);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003446
3447 if(poh == NULL) {
3448 DPRINTK("sisfb: sisfb_poh_free() failed at base 0x%x\n",
3449 (unsigned int) base);
3450 }
3451}
3452
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003453void
3454sis_free(u32 base)
3455{
3456 struct sis_video_info *ivideo = sisfb_heap->vinfo;
3457
3458 sis_int_free(ivideo, base);
3459}
3460
3461void
3462sis_free_new(struct pci_dev *pdev, u32 base)
3463{
3464 struct sis_video_info *ivideo = pci_get_drvdata(pdev);
3465
3466 sis_int_free(ivideo, base);
3467}
3468
Linus Torvalds1da177e2005-04-16 15:20:36 -07003469/* --------------------- SetMode routines ------------------------- */
3470
3471static void
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003472sisfb_check_engine_and_sync(struct sis_video_info *ivideo)
3473{
3474 u8 cr30, cr31;
3475
3476 /* Check if MMIO and engines are enabled,
3477 * and sync in case they are. Can't use
3478 * ivideo->accel here, as this might have
3479 * been changed before this is called.
3480 */
Aaro Koskinene57d4132010-12-20 23:50:16 +02003481 cr30 = SiS_GetReg(SISSR, IND_SIS_PCI_ADDRESS_SET);
3482 cr31 = SiS_GetReg(SISSR, IND_SIS_MODULE_ENABLE);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003483 /* MMIO and 2D/3D engine enabled? */
3484 if((cr30 & SIS_MEM_MAP_IO_ENABLE) && (cr31 & 0x42)) {
3485#ifdef CONFIG_FB_SIS_300
3486 if(ivideo->sisvga_engine == SIS_300_VGA) {
3487 /* Don't care about TurboQueue. It's
3488 * enough to know that the engines
3489 * are enabled
3490 */
3491 sisfb_syncaccel(ivideo);
3492 }
3493#endif
3494#ifdef CONFIG_FB_SIS_315
3495 if(ivideo->sisvga_engine == SIS_315_VGA) {
3496 /* Check that any queue mode is
3497 * enabled, and that the queue
3498 * is not in the state of "reset"
3499 */
Aaro Koskinene57d4132010-12-20 23:50:16 +02003500 cr30 = SiS_GetReg(SISSR, 0x26);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003501 if((cr30 & 0xe0) && (!(cr30 & 0x01))) {
3502 sisfb_syncaccel(ivideo);
3503 }
3504 }
3505#endif
3506 }
3507}
3508
3509static void
Linus Torvalds1da177e2005-04-16 15:20:36 -07003510sisfb_pre_setmode(struct sis_video_info *ivideo)
3511{
3512 u8 cr30 = 0, cr31 = 0, cr33 = 0, cr35 = 0, cr38 = 0;
3513 int tvregnum = 0;
3514
3515 ivideo->currentvbflags &= (VB_VIDEOBRIDGE | VB_DISPTYPE_DISP2);
3516
Aaro Koskinen44b751b2010-12-20 23:50:17 +02003517 SiS_SetReg(SISSR, 0x05, 0x86);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003518
Aaro Koskinene57d4132010-12-20 23:50:16 +02003519 cr31 = SiS_GetReg(SISCR, 0x31);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003520 cr31 &= ~0x60;
3521 cr31 |= 0x04;
3522
3523 cr33 = ivideo->rate_idx & 0x0F;
3524
3525#ifdef CONFIG_FB_SIS_315
3526 if(ivideo->sisvga_engine == SIS_315_VGA) {
3527 if(ivideo->chip >= SIS_661) {
Aaro Koskinene57d4132010-12-20 23:50:16 +02003528 cr38 = SiS_GetReg(SISCR, 0x38);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003529 cr38 &= ~0x07; /* Clear LCDA/DualEdge and YPbPr bits */
3530 } else {
3531 tvregnum = 0x38;
Aaro Koskinene57d4132010-12-20 23:50:16 +02003532 cr38 = SiS_GetReg(SISCR, tvregnum);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003533 cr38 &= ~0x3b; /* Clear LCDA/DualEdge and YPbPr bits */
3534 }
3535 }
3536#endif
3537#ifdef CONFIG_FB_SIS_300
3538 if(ivideo->sisvga_engine == SIS_300_VGA) {
3539 tvregnum = 0x35;
Aaro Koskinene57d4132010-12-20 23:50:16 +02003540 cr38 = SiS_GetReg(SISCR, tvregnum);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003541 }
3542#endif
3543
Richard Knutssonc30660ea2007-02-12 00:55:06 -08003544 SiS_SetEnableDstn(&ivideo->SiS_Pr, false);
3545 SiS_SetEnableFstn(&ivideo->SiS_Pr, false);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003546 ivideo->curFSTN = ivideo->curDSTN = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003547
3548 switch(ivideo->currentvbflags & VB_DISPTYPE_DISP2) {
3549
3550 case CRT2_TV:
3551 cr38 &= ~0xc0; /* Clear PAL-M / PAL-N bits */
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003552 if((ivideo->vbflags & TV_YPBPR) && (ivideo->vbflags2 & VB2_SISYPBPRBRIDGE)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003553#ifdef CONFIG_FB_SIS_315
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003554 if(ivideo->chip >= SIS_661) {
3555 cr38 |= 0x04;
3556 if(ivideo->vbflags & TV_YPBPR525P) cr35 |= 0x20;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003557 else if(ivideo->vbflags & TV_YPBPR750P) cr35 |= 0x40;
3558 else if(ivideo->vbflags & TV_YPBPR1080I) cr35 |= 0x60;
3559 cr30 |= SIS_SIMULTANEOUS_VIEW_ENABLE;
3560 cr35 &= ~0x01;
3561 ivideo->currentvbflags |= (TV_YPBPR | (ivideo->vbflags & TV_YPBPRALL));
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003562 } else if(ivideo->sisvga_engine == SIS_315_VGA) {
3563 cr30 |= (0x80 | SIS_SIMULTANEOUS_VIEW_ENABLE);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003564 cr38 |= 0x08;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003565 if(ivideo->vbflags & TV_YPBPR525P) cr38 |= 0x10;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003566 else if(ivideo->vbflags & TV_YPBPR750P) cr38 |= 0x20;
3567 else if(ivideo->vbflags & TV_YPBPR1080I) cr38 |= 0x30;
3568 cr31 &= ~0x01;
3569 ivideo->currentvbflags |= (TV_YPBPR | (ivideo->vbflags & TV_YPBPRALL));
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003570 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003571#endif
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003572 } else if((ivideo->vbflags & TV_HIVISION) &&
3573 (ivideo->vbflags2 & VB2_SISHIVISIONBRIDGE)) {
3574 if(ivideo->chip >= SIS_661) {
3575 cr38 |= 0x04;
3576 cr35 |= 0x60;
3577 } else {
3578 cr30 |= 0x80;
3579 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003580 cr30 |= SIS_SIMULTANEOUS_VIEW_ENABLE;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003581 cr31 |= 0x01;
3582 cr35 |= 0x01;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003583 ivideo->currentvbflags |= TV_HIVISION;
3584 } else if(ivideo->vbflags & TV_SCART) {
3585 cr30 = (SIS_VB_OUTPUT_SCART | SIS_SIMULTANEOUS_VIEW_ENABLE);
3586 cr31 |= 0x01;
3587 cr35 |= 0x01;
3588 ivideo->currentvbflags |= TV_SCART;
3589 } else {
3590 if(ivideo->vbflags & TV_SVIDEO) {
3591 cr30 = (SIS_VB_OUTPUT_SVIDEO | SIS_SIMULTANEOUS_VIEW_ENABLE);
3592 ivideo->currentvbflags |= TV_SVIDEO;
3593 }
3594 if(ivideo->vbflags & TV_AVIDEO) {
3595 cr30 = (SIS_VB_OUTPUT_COMPOSITE | SIS_SIMULTANEOUS_VIEW_ENABLE);
3596 ivideo->currentvbflags |= TV_AVIDEO;
3597 }
3598 }
3599 cr31 |= SIS_DRIVER_MODE;
3600
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003601 if(ivideo->vbflags & (TV_AVIDEO | TV_SVIDEO)) {
3602 if(ivideo->vbflags & TV_PAL) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003603 cr31 |= 0x01; cr35 |= 0x01;
3604 ivideo->currentvbflags |= TV_PAL;
3605 if(ivideo->vbflags & TV_PALM) {
3606 cr38 |= 0x40; cr35 |= 0x04;
3607 ivideo->currentvbflags |= TV_PALM;
3608 } else if(ivideo->vbflags & TV_PALN) {
3609 cr38 |= 0x80; cr35 |= 0x08;
3610 ivideo->currentvbflags |= TV_PALN;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003611 }
3612 } else {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003613 cr31 &= ~0x01; cr35 &= ~0x01;
3614 ivideo->currentvbflags |= TV_NTSC;
3615 if(ivideo->vbflags & TV_NTSCJ) {
3616 cr38 |= 0x40; cr35 |= 0x02;
3617 ivideo->currentvbflags |= TV_NTSCJ;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003618 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003619 }
3620 }
3621 break;
3622
3623 case CRT2_LCD:
3624 cr30 = (SIS_VB_OUTPUT_LCD | SIS_SIMULTANEOUS_VIEW_ENABLE);
3625 cr31 |= SIS_DRIVER_MODE;
3626 SiS_SetEnableDstn(&ivideo->SiS_Pr, ivideo->sisfb_dstn);
3627 SiS_SetEnableFstn(&ivideo->SiS_Pr, ivideo->sisfb_fstn);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003628 ivideo->curFSTN = ivideo->sisfb_fstn;
3629 ivideo->curDSTN = ivideo->sisfb_dstn;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003630 break;
3631
3632 case CRT2_VGA:
3633 cr30 = (SIS_VB_OUTPUT_CRT2 | SIS_SIMULTANEOUS_VIEW_ENABLE);
3634 cr31 |= SIS_DRIVER_MODE;
3635 if(ivideo->sisfb_nocrt2rate) {
3636 cr33 |= (sisbios_mode[ivideo->sisfb_mode_idx].rate_idx << 4);
3637 } else {
3638 cr33 |= ((ivideo->rate_idx & 0x0F) << 4);
3639 }
3640 break;
3641
3642 default: /* disable CRT2 */
3643 cr30 = 0x00;
3644 cr31 |= (SIS_DRIVER_MODE | SIS_VB_OUTPUT_DISABLE);
3645 }
3646
Aaro Koskinen44b751b2010-12-20 23:50:17 +02003647 SiS_SetReg(SISCR, 0x30, cr30);
3648 SiS_SetReg(SISCR, 0x33, cr33);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003649
3650 if(ivideo->chip >= SIS_661) {
3651#ifdef CONFIG_FB_SIS_315
3652 cr31 &= ~0x01; /* Clear PAL flag (now in CR35) */
Aaro Koskinenad78adb2010-12-20 23:50:20 +02003653 SiS_SetRegANDOR(SISCR, 0x35, ~0x10, cr35); /* Leave overscan bit alone */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003654 cr38 &= 0x07; /* Use only LCDA and HiVision/YPbPr bits */
Aaro Koskinenad78adb2010-12-20 23:50:20 +02003655 SiS_SetRegANDOR(SISCR, 0x38, 0xf8, cr38);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003656#endif
3657 } else if(ivideo->chip != SIS_300) {
Aaro Koskinen44b751b2010-12-20 23:50:17 +02003658 SiS_SetReg(SISCR, tvregnum, cr38);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003659 }
Aaro Koskinen44b751b2010-12-20 23:50:17 +02003660 SiS_SetReg(SISCR, 0x31, cr31);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003661
Linus Torvalds1da177e2005-04-16 15:20:36 -07003662 ivideo->SiS_Pr.SiS_UseOEM = ivideo->sisfb_useoem;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003663
3664 sisfb_check_engine_and_sync(ivideo);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003665}
3666
3667/* Fix SR11 for 661 and later */
3668#ifdef CONFIG_FB_SIS_315
3669static void
3670sisfb_fixup_SR11(struct sis_video_info *ivideo)
3671{
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003672 u8 tmpreg;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003673
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003674 if(ivideo->chip >= SIS_661) {
Aaro Koskinene57d4132010-12-20 23:50:16 +02003675 tmpreg = SiS_GetReg(SISSR, 0x11);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003676 if(tmpreg & 0x20) {
Aaro Koskinene57d4132010-12-20 23:50:16 +02003677 tmpreg = SiS_GetReg(SISSR, 0x3e);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003678 tmpreg = (tmpreg + 1) & 0xff;
Aaro Koskinen44b751b2010-12-20 23:50:17 +02003679 SiS_SetReg(SISSR, 0x3e, tmpreg);
Aaro Koskinene57d4132010-12-20 23:50:16 +02003680 tmpreg = SiS_GetReg(SISSR, 0x11);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003681 }
3682 if(tmpreg & 0xf0) {
Aaro Koskinen667a8b42010-12-20 23:50:19 +02003683 SiS_SetRegAND(SISSR, 0x11, 0x0f);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003684 }
3685 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003686}
3687#endif
3688
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003689static void
3690sisfb_set_TVxposoffset(struct sis_video_info *ivideo, int val)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003691{
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003692 if(val > 32) val = 32;
3693 if(val < -32) val = -32;
3694 ivideo->tvxpos = val;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003695
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003696 if(ivideo->sisfblocked) return;
3697 if(!ivideo->modechanged) return;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003698
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003699 if(ivideo->currentvbflags & CRT2_TV) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003700
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003701 if(ivideo->vbflags2 & VB2_CHRONTEL) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003702
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003703 int x = ivideo->tvx;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003704
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003705 switch(ivideo->chronteltype) {
3706 case 1:
3707 x += val;
3708 if(x < 0) x = 0;
Aaro Koskinen44b751b2010-12-20 23:50:17 +02003709 SiS_SetReg(SISSR, 0x05, 0x86);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003710 SiS_SetCH700x(&ivideo->SiS_Pr, 0x0a, (x & 0xff));
3711 SiS_SetCH70xxANDOR(&ivideo->SiS_Pr, 0x08, ((x & 0x0100) >> 7), 0xFD);
3712 break;
3713 case 2:
3714 /* Not supported by hardware */
3715 break;
3716 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003717
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003718 } else if(ivideo->vbflags2 & VB2_SISBRIDGE) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003719
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003720 u8 p2_1f,p2_20,p2_2b,p2_42,p2_43;
3721 unsigned short temp;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003722
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003723 p2_1f = ivideo->p2_1f;
3724 p2_20 = ivideo->p2_20;
3725 p2_2b = ivideo->p2_2b;
3726 p2_42 = ivideo->p2_42;
3727 p2_43 = ivideo->p2_43;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003728
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003729 temp = p2_1f | ((p2_20 & 0xf0) << 4);
3730 temp += (val * 2);
3731 p2_1f = temp & 0xff;
3732 p2_20 = (temp & 0xf00) >> 4;
3733 p2_2b = ((p2_2b & 0x0f) + (val * 2)) & 0x0f;
3734 temp = p2_43 | ((p2_42 & 0xf0) << 4);
3735 temp += (val * 2);
3736 p2_43 = temp & 0xff;
3737 p2_42 = (temp & 0xf00) >> 4;
Aaro Koskinen44b751b2010-12-20 23:50:17 +02003738 SiS_SetReg(SISPART2, 0x1f, p2_1f);
Aaro Koskinenad78adb2010-12-20 23:50:20 +02003739 SiS_SetRegANDOR(SISPART2, 0x20, 0x0F, p2_20);
3740 SiS_SetRegANDOR(SISPART2, 0x2b, 0xF0, p2_2b);
3741 SiS_SetRegANDOR(SISPART2, 0x42, 0x0F, p2_42);
Aaro Koskinen44b751b2010-12-20 23:50:17 +02003742 SiS_SetReg(SISPART2, 0x43, p2_43);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003743 }
3744 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003745}
3746
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003747static void
3748sisfb_set_TVyposoffset(struct sis_video_info *ivideo, int val)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003749{
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003750 if(val > 32) val = 32;
3751 if(val < -32) val = -32;
3752 ivideo->tvypos = val;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003753
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003754 if(ivideo->sisfblocked) return;
3755 if(!ivideo->modechanged) return;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003756
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003757 if(ivideo->currentvbflags & CRT2_TV) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003758
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003759 if(ivideo->vbflags2 & VB2_CHRONTEL) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003760
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003761 int y = ivideo->tvy;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003762
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003763 switch(ivideo->chronteltype) {
3764 case 1:
3765 y -= val;
3766 if(y < 0) y = 0;
Aaro Koskinen44b751b2010-12-20 23:50:17 +02003767 SiS_SetReg(SISSR, 0x05, 0x86);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003768 SiS_SetCH700x(&ivideo->SiS_Pr, 0x0b, (y & 0xff));
3769 SiS_SetCH70xxANDOR(&ivideo->SiS_Pr, 0x08, ((y & 0x0100) >> 8), 0xFE);
3770 break;
3771 case 2:
3772 /* Not supported by hardware */
3773 break;
3774 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003775
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003776 } else if(ivideo->vbflags2 & VB2_SISBRIDGE) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003777
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003778 char p2_01, p2_02;
3779 val /= 2;
3780 p2_01 = ivideo->p2_01;
3781 p2_02 = ivideo->p2_02;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003782
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003783 p2_01 += val;
3784 p2_02 += val;
3785 if(!(ivideo->currentvbflags & (TV_HIVISION | TV_YPBPR))) {
3786 while((p2_01 <= 0) || (p2_02 <= 0)) {
3787 p2_01 += 2;
3788 p2_02 += 2;
3789 }
3790 }
Aaro Koskinen44b751b2010-12-20 23:50:17 +02003791 SiS_SetReg(SISPART2, 0x01, p2_01);
3792 SiS_SetReg(SISPART2, 0x02, p2_02);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003793 }
3794 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003795}
3796
3797static void
3798sisfb_post_setmode(struct sis_video_info *ivideo)
3799{
Richard Knutssonc30660ea2007-02-12 00:55:06 -08003800 bool crt1isoff = false;
3801 bool doit = true;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003802#if defined(CONFIG_FB_SIS_300) || defined(CONFIG_FB_SIS_315)
3803 u8 reg;
3804#endif
3805#ifdef CONFIG_FB_SIS_315
3806 u8 reg1;
3807#endif
3808
Aaro Koskinen44b751b2010-12-20 23:50:17 +02003809 SiS_SetReg(SISSR, 0x05, 0x86);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003810
3811#ifdef CONFIG_FB_SIS_315
3812 sisfb_fixup_SR11(ivideo);
3813#endif
3814
3815 /* Now we actually HAVE changed the display mode */
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003816 ivideo->modechanged = 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003817
3818 /* We can't switch off CRT1 if bridge is in slave mode */
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003819 if(ivideo->vbflags2 & VB2_VIDEOBRIDGE) {
Richard Knutssonc30660ea2007-02-12 00:55:06 -08003820 if(sisfb_bridgeisslave(ivideo)) doit = false;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003821 } else
3822 ivideo->sisfb_crt1off = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003823
3824#ifdef CONFIG_FB_SIS_300
3825 if(ivideo->sisvga_engine == SIS_300_VGA) {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003826 if((ivideo->sisfb_crt1off) && (doit)) {
Richard Knutssonc30660ea2007-02-12 00:55:06 -08003827 crt1isoff = true;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003828 reg = 0x00;
3829 } else {
Richard Knutssonc30660ea2007-02-12 00:55:06 -08003830 crt1isoff = false;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003831 reg = 0x80;
3832 }
Aaro Koskinenad78adb2010-12-20 23:50:20 +02003833 SiS_SetRegANDOR(SISCR, 0x17, 0x7f, reg);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003834 }
3835#endif
3836#ifdef CONFIG_FB_SIS_315
3837 if(ivideo->sisvga_engine == SIS_315_VGA) {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003838 if((ivideo->sisfb_crt1off) && (doit)) {
Richard Knutssonc30660ea2007-02-12 00:55:06 -08003839 crt1isoff = true;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003840 reg = 0x40;
3841 reg1 = 0xc0;
3842 } else {
Richard Knutssonc30660ea2007-02-12 00:55:06 -08003843 crt1isoff = false;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003844 reg = 0x00;
3845 reg1 = 0x00;
3846 }
Aaro Koskinenad78adb2010-12-20 23:50:20 +02003847 SiS_SetRegANDOR(SISCR, ivideo->SiS_Pr.SiS_MyCR63, ~0x40, reg);
Aaro Koskinen17d6ce12010-12-20 23:50:22 +02003848 SiS_SetRegANDOR(SISSR, 0x1f, 0x3f, reg1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003849 }
3850#endif
3851
3852 if(crt1isoff) {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003853 ivideo->currentvbflags &= ~VB_DISPTYPE_CRT1;
3854 ivideo->currentvbflags |= VB_SINGLE_MODE;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003855 } else {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003856 ivideo->currentvbflags |= VB_DISPTYPE_CRT1;
3857 if(ivideo->currentvbflags & VB_DISPTYPE_CRT2) {
3858 ivideo->currentvbflags |= VB_MIRROR_MODE;
3859 } else {
3860 ivideo->currentvbflags |= VB_SINGLE_MODE;
3861 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003862 }
3863
Aaro Koskinen667a8b42010-12-20 23:50:19 +02003864 SiS_SetRegAND(SISSR, IND_SIS_RAMDAC_CONTROL, ~0x04);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003865
3866 if(ivideo->currentvbflags & CRT2_TV) {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003867 if(ivideo->vbflags2 & VB2_SISBRIDGE) {
Aaro Koskinene57d4132010-12-20 23:50:16 +02003868 ivideo->p2_1f = SiS_GetReg(SISPART2, 0x1f);
3869 ivideo->p2_20 = SiS_GetReg(SISPART2, 0x20);
3870 ivideo->p2_2b = SiS_GetReg(SISPART2, 0x2b);
3871 ivideo->p2_42 = SiS_GetReg(SISPART2, 0x42);
3872 ivideo->p2_43 = SiS_GetReg(SISPART2, 0x43);
3873 ivideo->p2_01 = SiS_GetReg(SISPART2, 0x01);
3874 ivideo->p2_02 = SiS_GetReg(SISPART2, 0x02);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003875 } else if(ivideo->vbflags2 & VB2_CHRONTEL) {
3876 if(ivideo->chronteltype == 1) {
3877 ivideo->tvx = SiS_GetCH700x(&ivideo->SiS_Pr, 0x0a);
3878 ivideo->tvx |= (((SiS_GetCH700x(&ivideo->SiS_Pr, 0x08) & 0x02) >> 1) << 8);
3879 ivideo->tvy = SiS_GetCH700x(&ivideo->SiS_Pr, 0x0b);
3880 ivideo->tvy |= ((SiS_GetCH700x(&ivideo->SiS_Pr, 0x08) & 0x01) << 8);
3881 }
3882 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003883 }
3884
3885 if(ivideo->tvxpos) {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003886 sisfb_set_TVxposoffset(ivideo, ivideo->tvxpos);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003887 }
3888 if(ivideo->tvypos) {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003889 sisfb_set_TVyposoffset(ivideo, ivideo->tvypos);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003890 }
3891
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003892 /* Eventually sync engines */
3893 sisfb_check_engine_and_sync(ivideo);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003894
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003895 /* (Re-)Initialize chip engines */
3896 if(ivideo->accel) {
3897 sisfb_engine_init(ivideo);
3898 } else {
3899 ivideo->engineok = 0;
3900 }
3901}
Linus Torvalds1da177e2005-04-16 15:20:36 -07003902
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003903static int
3904sisfb_reset_mode(struct sis_video_info *ivideo)
3905{
3906 if(sisfb_set_mode(ivideo, 0))
3907 return 1;
3908
3909 sisfb_set_pitch(ivideo);
3910 sisfb_set_base_CRT1(ivideo, ivideo->current_base);
3911 sisfb_set_base_CRT2(ivideo, ivideo->current_base);
3912
3913 return 0;
3914}
3915
3916static void
3917sisfb_handle_command(struct sis_video_info *ivideo, struct sisfb_cmd *sisfb_command)
3918{
3919 int mycrt1off;
3920
3921 switch(sisfb_command->sisfb_cmd) {
3922 case SISFB_CMD_GETVBFLAGS:
3923 if(!ivideo->modechanged) {
3924 sisfb_command->sisfb_result[0] = SISFB_CMD_ERR_EARLY;
3925 } else {
3926 sisfb_command->sisfb_result[0] = SISFB_CMD_ERR_OK;
3927 sisfb_command->sisfb_result[1] = ivideo->currentvbflags;
3928 sisfb_command->sisfb_result[2] = ivideo->vbflags2;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003929 }
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003930 break;
3931 case SISFB_CMD_SWITCHCRT1:
3932 /* arg[0]: 0 = off, 1 = on, 99 = query */
3933 if(!ivideo->modechanged) {
3934 sisfb_command->sisfb_result[0] = SISFB_CMD_ERR_EARLY;
3935 } else if(sisfb_command->sisfb_arg[0] == 99) {
3936 /* Query */
3937 sisfb_command->sisfb_result[1] = ivideo->sisfb_crt1off ? 0 : 1;
3938 sisfb_command->sisfb_result[0] = SISFB_CMD_ERR_OK;
3939 } else if(ivideo->sisfblocked) {
3940 sisfb_command->sisfb_result[0] = SISFB_CMD_ERR_LOCKED;
3941 } else if((!(ivideo->currentvbflags & CRT2_ENABLE)) &&
3942 (sisfb_command->sisfb_arg[0] == 0)) {
3943 sisfb_command->sisfb_result[0] = SISFB_CMD_ERR_NOCRT2;
3944 } else {
3945 sisfb_command->sisfb_result[0] = SISFB_CMD_ERR_OK;
3946 mycrt1off = sisfb_command->sisfb_arg[0] ? 0 : 1;
3947 if( ((ivideo->currentvbflags & VB_DISPTYPE_CRT1) && mycrt1off) ||
3948 ((!(ivideo->currentvbflags & VB_DISPTYPE_CRT1)) && !mycrt1off) ) {
3949 ivideo->sisfb_crt1off = mycrt1off;
3950 if(sisfb_reset_mode(ivideo)) {
3951 sisfb_command->sisfb_result[0] = SISFB_CMD_ERR_OTHER;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003952 }
3953 }
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003954 sisfb_command->sisfb_result[1] = ivideo->sisfb_crt1off ? 0 : 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003955 }
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003956 break;
3957 /* more to come */
3958 default:
3959 sisfb_command->sisfb_result[0] = SISFB_CMD_ERR_UNKNOWN;
3960 printk(KERN_ERR "sisfb: Unknown command 0x%x\n",
3961 sisfb_command->sisfb_cmd);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003962 }
3963}
3964
3965#ifndef MODULE
Adrian Bunk14aefd12008-07-23 21:31:12 -07003966static int __init sisfb_setup(char *options)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003967{
3968 char *this_opt;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003969
Linus Torvalds1da177e2005-04-16 15:20:36 -07003970 sisfb_setdefaultparms();
3971
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003972 if(!options || !(*options))
Linus Torvalds1da177e2005-04-16 15:20:36 -07003973 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003974
3975 while((this_opt = strsep(&options, ",")) != NULL) {
3976
3977 if(!(*this_opt)) continue;
3978
3979 if(!strnicmp(this_opt, "off", 3)) {
3980 sisfb_off = 1;
3981 } else if(!strnicmp(this_opt, "forcecrt2type:", 14)) {
3982 /* Need to check crt2 type first for fstn/dstn */
3983 sisfb_search_crt2type(this_opt + 14);
3984 } else if(!strnicmp(this_opt, "tvmode:",7)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003985 sisfb_search_tvstd(this_opt + 7);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003986 } else if(!strnicmp(this_opt, "tvstandard:",11)) {
3987 sisfb_search_tvstd(this_opt + 11);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003988 } else if(!strnicmp(this_opt, "mode:", 5)) {
Richard Knutssonc30660ea2007-02-12 00:55:06 -08003989 sisfb_search_mode(this_opt + 5, false);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003990 } else if(!strnicmp(this_opt, "vesa:", 5)) {
Richard Knutssonc30660ea2007-02-12 00:55:06 -08003991 sisfb_search_vesamode(simple_strtoul(this_opt + 5, NULL, 0), false);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003992 } else if(!strnicmp(this_opt, "rate:", 5)) {
3993 sisfb_parm_rate = simple_strtoul(this_opt + 5, NULL, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003994 } else if(!strnicmp(this_opt, "forcecrt1:", 10)) {
3995 sisfb_forcecrt1 = (int)simple_strtoul(this_opt + 10, NULL, 0);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003996 } else if(!strnicmp(this_opt, "mem:",4)) {
3997 sisfb_parm_mem = simple_strtoul(this_opt + 4, NULL, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003998 } else if(!strnicmp(this_opt, "pdc:", 4)) {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003999 sisfb_pdc = simple_strtoul(this_opt + 4, NULL, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004000 } else if(!strnicmp(this_opt, "pdc1:", 5)) {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004001 sisfb_pdca = simple_strtoul(this_opt + 5, NULL, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004002 } else if(!strnicmp(this_opt, "noaccel", 7)) {
4003 sisfb_accel = 0;
4004 } else if(!strnicmp(this_opt, "accel", 5)) {
4005 sisfb_accel = -1;
4006 } else if(!strnicmp(this_opt, "noypan", 6)) {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004007 sisfb_ypan = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004008 } else if(!strnicmp(this_opt, "ypan", 4)) {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004009 sisfb_ypan = -1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004010 } else if(!strnicmp(this_opt, "nomax", 5)) {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004011 sisfb_max = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004012 } else if(!strnicmp(this_opt, "max", 3)) {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004013 sisfb_max = -1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004014 } else if(!strnicmp(this_opt, "userom:", 7)) {
4015 sisfb_userom = (int)simple_strtoul(this_opt + 7, NULL, 0);
4016 } else if(!strnicmp(this_opt, "useoem:", 7)) {
4017 sisfb_useoem = (int)simple_strtoul(this_opt + 7, NULL, 0);
4018 } else if(!strnicmp(this_opt, "nocrt2rate", 10)) {
4019 sisfb_nocrt2rate = 1;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004020 } else if(!strnicmp(this_opt, "scalelcd:", 9)) {
4021 unsigned long temp = 2;
4022 temp = simple_strtoul(this_opt + 9, NULL, 0);
4023 if((temp == 0) || (temp == 1)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004024 sisfb_scalelcd = temp ^ 1;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004025 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004026 } else if(!strnicmp(this_opt, "tvxposoffset:", 13)) {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004027 int temp = 0;
4028 temp = (int)simple_strtol(this_opt + 13, NULL, 0);
4029 if((temp >= -32) && (temp <= 32)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004030 sisfb_tvxposoffset = temp;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004031 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004032 } else if(!strnicmp(this_opt, "tvyposoffset:", 13)) {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004033 int temp = 0;
4034 temp = (int)simple_strtol(this_opt + 13, NULL, 0);
4035 if((temp >= -32) && (temp <= 32)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004036 sisfb_tvyposoffset = temp;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004037 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004038 } else if(!strnicmp(this_opt, "specialtiming:", 14)) {
4039 sisfb_search_specialtiming(this_opt + 14);
4040 } else if(!strnicmp(this_opt, "lvdshl:", 7)) {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004041 int temp = 4;
4042 temp = simple_strtoul(this_opt + 7, NULL, 0);
4043 if((temp >= 0) && (temp <= 3)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004044 sisfb_lvdshl = temp;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004045 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004046 } else if(this_opt[0] >= '0' && this_opt[0] <= '9') {
Richard Knutssonc30660ea2007-02-12 00:55:06 -08004047 sisfb_search_mode(this_opt, true);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004048#if !defined(__i386__) && !defined(__x86_64__)
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004049 } else if(!strnicmp(this_opt, "resetcard", 9)) {
4050 sisfb_resetcard = 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004051 } else if(!strnicmp(this_opt, "videoram:", 9)) {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004052 sisfb_videoram = simple_strtoul(this_opt + 9, NULL, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004053#endif
4054 } else {
4055 printk(KERN_INFO "sisfb: Invalid option %s\n", this_opt);
4056 }
4057
4058 }
4059
Linus Torvalds1da177e2005-04-16 15:20:36 -07004060 return 0;
4061}
4062#endif
4063
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004064static int __devinit
Adrian Bunk14aefd12008-07-23 21:31:12 -07004065sisfb_check_rom(void __iomem *rom_base, struct sis_video_info *ivideo)
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004066{
Adrian Bunk14aefd12008-07-23 21:31:12 -07004067 void __iomem *rom;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004068 int romptr;
4069
4070 if((readb(rom_base) != 0x55) || (readb(rom_base + 1) != 0xaa))
4071 return 0;
4072
4073 romptr = (readb(rom_base + 0x18) | (readb(rom_base + 0x19) << 8));
4074 if(romptr > (0x10000 - 8))
4075 return 0;
4076
4077 rom = rom_base + romptr;
4078
4079 if((readb(rom) != 'P') || (readb(rom + 1) != 'C') ||
4080 (readb(rom + 2) != 'I') || (readb(rom + 3) != 'R'))
4081 return 0;
4082
4083 if((readb(rom + 4) | (readb(rom + 5) << 8)) != ivideo->chip_vendor)
4084 return 0;
4085
4086 if((readb(rom + 6) | (readb(rom + 7) << 8)) != ivideo->chip_id)
4087 return 0;
4088
4089 return 1;
4090}
4091
4092static unsigned char * __devinit
4093sisfb_find_rom(struct pci_dev *pdev)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004094{
4095 struct sis_video_info *ivideo = pci_get_drvdata(pdev);
Adrian Bunk14aefd12008-07-23 21:31:12 -07004096 void __iomem *rom_base;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004097 unsigned char *myrombase = NULL;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004098 size_t romsize;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004099
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004100 /* First, try the official pci ROM functions (except
4101 * on integrated chipsets which have no ROM).
4102 */
4103
4104 if(!ivideo->nbridge) {
4105
4106 if((rom_base = pci_map_rom(pdev, &romsize))) {
4107
4108 if(sisfb_check_rom(rom_base, ivideo)) {
4109
4110 if((myrombase = vmalloc(65536))) {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004111 memcpy_fromio(myrombase, rom_base,
4112 (romsize > 65536) ? 65536 : romsize);
4113 }
4114 }
4115 pci_unmap_rom(pdev, rom_base);
4116 }
4117 }
4118
4119 if(myrombase) return myrombase;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004120
4121 /* Otherwise do it the conventional way. */
Linus Torvalds1da177e2005-04-16 15:20:36 -07004122
4123#if defined(__i386__) || defined(__x86_64__)
Aaro Koskinen679c4892010-12-20 23:50:10 +02004124 {
4125 u32 temp;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004126
Aaro Koskinen679c4892010-12-20 23:50:10 +02004127 for (temp = 0x000c0000; temp < 0x000f0000; temp += 0x00001000) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004128
Aaro Koskinen679c4892010-12-20 23:50:10 +02004129 rom_base = ioremap(temp, 65536);
4130 if (!rom_base)
4131 continue;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004132
Aaro Koskinen679c4892010-12-20 23:50:10 +02004133 if (!sisfb_check_rom(rom_base, ivideo)) {
4134 iounmap(rom_base);
4135 continue;
4136 }
4137
4138 if ((myrombase = vmalloc(65536)))
4139 memcpy_fromio(myrombase, rom_base, 65536);
4140
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004141 iounmap(rom_base);
Aaro Koskinen679c4892010-12-20 23:50:10 +02004142 break;
4143
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004144 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004145
Aaro Koskinen679c4892010-12-20 23:50:10 +02004146 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004147#endif
4148
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004149 return myrombase;
4150}
4151
4152static void __devinit
4153sisfb_post_map_vram(struct sis_video_info *ivideo, unsigned int *mapsize,
4154 unsigned int min)
4155{
Aaro Koskinen32ed3032010-11-10 13:04:19 +02004156 if (*mapsize < (min << 20))
4157 return;
4158
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004159 ivideo->video_vbase = ioremap(ivideo->video_base, (*mapsize));
4160
4161 if(!ivideo->video_vbase) {
4162 printk(KERN_ERR
4163 "sisfb: Unable to map maximum video RAM for size detection\n");
4164 (*mapsize) >>= 1;
4165 while((!(ivideo->video_vbase = ioremap(ivideo->video_base, (*mapsize))))) {
4166 (*mapsize) >>= 1;
4167 if((*mapsize) < (min << 20))
4168 break;
4169 }
4170 if(ivideo->video_vbase) {
4171 printk(KERN_ERR
4172 "sisfb: Video RAM size detection limited to %dMB\n",
4173 (int)((*mapsize) >> 20));
4174 }
4175 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004176}
4177
4178#ifdef CONFIG_FB_SIS_300
4179static int __devinit
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004180sisfb_post_300_buswidth(struct sis_video_info *ivideo)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004181{
Adrian Bunk14aefd12008-07-23 21:31:12 -07004182 void __iomem *FBAddress = ivideo->video_vbase;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004183 unsigned short temp;
4184 unsigned char reg;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004185 int i, j;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004186
Aaro Koskinen667a8b42010-12-20 23:50:19 +02004187 SiS_SetRegAND(SISSR, 0x15, 0xFB);
Aaro Koskinen27799d62010-12-20 23:50:18 +02004188 SiS_SetRegOR(SISSR, 0x15, 0x04);
Aaro Koskinen44b751b2010-12-20 23:50:17 +02004189 SiS_SetReg(SISSR, 0x13, 0x00);
4190 SiS_SetReg(SISSR, 0x14, 0xBF);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004191
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004192 for(i = 0; i < 2; i++) {
4193 temp = 0x1234;
4194 for(j = 0; j < 4; j++) {
4195 writew(temp, FBAddress);
4196 if(readw(FBAddress) == temp)
4197 break;
Aaro Koskinen27799d62010-12-20 23:50:18 +02004198 SiS_SetRegOR(SISSR, 0x3c, 0x01);
Aaro Koskinene57d4132010-12-20 23:50:16 +02004199 reg = SiS_GetReg(SISSR, 0x05);
4200 reg = SiS_GetReg(SISSR, 0x05);
Aaro Koskinen667a8b42010-12-20 23:50:19 +02004201 SiS_SetRegAND(SISSR, 0x3c, 0xfe);
Aaro Koskinene57d4132010-12-20 23:50:16 +02004202 reg = SiS_GetReg(SISSR, 0x05);
4203 reg = SiS_GetReg(SISSR, 0x05);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004204 temp++;
4205 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004206 }
4207
4208 writel(0x01234567L, FBAddress);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004209 writel(0x456789ABL, (FBAddress + 4));
4210 writel(0x89ABCDEFL, (FBAddress + 8));
4211 writel(0xCDEF0123L, (FBAddress + 12));
4212
Aaro Koskinene57d4132010-12-20 23:50:16 +02004213 reg = SiS_GetReg(SISSR, 0x3b);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004214 if(reg & 0x01) {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004215 if(readl((FBAddress + 12)) == 0xCDEF0123L)
4216 return 4; /* Channel A 128bit */
Linus Torvalds1da177e2005-04-16 15:20:36 -07004217 }
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004218
4219 if(readl((FBAddress + 4)) == 0x456789ABL)
4220 return 2; /* Channel B 64bit */
4221
4222 return 1; /* 32bit */
4223}
4224
Peter Huewec1f58f12012-05-04 00:14:55 +02004225static const unsigned short __devinitconst SiS_DRAMType[17][5] = {
4226 {0x0C,0x0A,0x02,0x40,0x39},
4227 {0x0D,0x0A,0x01,0x40,0x48},
4228 {0x0C,0x09,0x02,0x20,0x35},
4229 {0x0D,0x09,0x01,0x20,0x44},
4230 {0x0C,0x08,0x02,0x10,0x31},
4231 {0x0D,0x08,0x01,0x10,0x40},
4232 {0x0C,0x0A,0x01,0x20,0x34},
4233 {0x0C,0x09,0x01,0x08,0x32},
4234 {0x0B,0x08,0x02,0x08,0x21},
4235 {0x0C,0x08,0x01,0x08,0x30},
4236 {0x0A,0x08,0x02,0x04,0x11},
4237 {0x0B,0x0A,0x01,0x10,0x28},
4238 {0x09,0x08,0x02,0x02,0x01},
4239 {0x0B,0x09,0x01,0x08,0x24},
4240 {0x0B,0x08,0x01,0x04,0x20},
4241 {0x0A,0x08,0x01,0x02,0x10},
4242 {0x09,0x08,0x01,0x01,0x00}
4243};
4244
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004245static int __devinit
4246sisfb_post_300_rwtest(struct sis_video_info *ivideo, int iteration, int buswidth,
4247 int PseudoRankCapacity, int PseudoAdrPinCount,
4248 unsigned int mapsize)
4249{
Adrian Bunk14aefd12008-07-23 21:31:12 -07004250 void __iomem *FBAddr = ivideo->video_vbase;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004251 unsigned short sr14;
4252 unsigned int k, RankCapacity, PageCapacity, BankNumHigh, BankNumMid;
4253 unsigned int PhysicalAdrOtherPage, PhysicalAdrHigh, PhysicalAdrHalfPage;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004254
Peter Huewec1f58f12012-05-04 00:14:55 +02004255 for(k = 0; k < ARRAY_SIZE(SiS_DRAMType); k++) {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004256
4257 RankCapacity = buswidth * SiS_DRAMType[k][3];
4258
4259 if(RankCapacity != PseudoRankCapacity)
4260 continue;
4261
4262 if((SiS_DRAMType[k][2] + SiS_DRAMType[k][0]) > PseudoAdrPinCount)
4263 continue;
4264
4265 BankNumHigh = RankCapacity * 16 * iteration - 1;
4266 if(iteration == 3) { /* Rank No */
4267 BankNumMid = RankCapacity * 16 - 1;
4268 } else {
4269 BankNumMid = RankCapacity * 16 * iteration / 2 - 1;
4270 }
4271
4272 PageCapacity = (1 << SiS_DRAMType[k][1]) * buswidth * 4;
4273 PhysicalAdrHigh = BankNumHigh;
4274 PhysicalAdrHalfPage = (PageCapacity / 2 + PhysicalAdrHigh) % PageCapacity;
4275 PhysicalAdrOtherPage = PageCapacity * SiS_DRAMType[k][2] + PhysicalAdrHigh;
4276
Aaro Koskinen667a8b42010-12-20 23:50:19 +02004277 SiS_SetRegAND(SISSR, 0x15, 0xFB); /* Test */
Aaro Koskinen27799d62010-12-20 23:50:18 +02004278 SiS_SetRegOR(SISSR, 0x15, 0x04); /* Test */
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004279 sr14 = (SiS_DRAMType[k][3] * buswidth) - 1;
4280 if(buswidth == 4) sr14 |= 0x80;
4281 else if(buswidth == 2) sr14 |= 0x40;
Aaro Koskinen44b751b2010-12-20 23:50:17 +02004282 SiS_SetReg(SISSR, 0x13, SiS_DRAMType[k][4]);
4283 SiS_SetReg(SISSR, 0x14, sr14);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004284
4285 BankNumHigh <<= 16;
4286 BankNumMid <<= 16;
4287
4288 if((BankNumHigh + PhysicalAdrHigh >= mapsize) ||
4289 (BankNumMid + PhysicalAdrHigh >= mapsize) ||
4290 (BankNumHigh + PhysicalAdrHalfPage >= mapsize) ||
4291 (BankNumHigh + PhysicalAdrOtherPage >= mapsize))
4292 continue;
4293
4294 /* Write data */
4295 writew(((unsigned short)PhysicalAdrHigh),
4296 (FBAddr + BankNumHigh + PhysicalAdrHigh));
4297 writew(((unsigned short)BankNumMid),
4298 (FBAddr + BankNumMid + PhysicalAdrHigh));
4299 writew(((unsigned short)PhysicalAdrHalfPage),
4300 (FBAddr + BankNumHigh + PhysicalAdrHalfPage));
4301 writew(((unsigned short)PhysicalAdrOtherPage),
4302 (FBAddr + BankNumHigh + PhysicalAdrOtherPage));
4303
4304 /* Read data */
4305 if(readw(FBAddr + BankNumHigh + PhysicalAdrHigh) == PhysicalAdrHigh)
4306 return 1;
4307 }
4308
4309 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004310}
4311
4312static void __devinit
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004313sisfb_post_300_ramsize(struct pci_dev *pdev, unsigned int mapsize)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004314{
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004315 struct sis_video_info *ivideo = pci_get_drvdata(pdev);
4316 int i, j, buswidth;
4317 int PseudoRankCapacity, PseudoAdrPinCount;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004318
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004319 buswidth = sisfb_post_300_buswidth(ivideo);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004320
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004321 for(i = 6; i >= 0; i--) {
4322 PseudoRankCapacity = 1 << i;
4323 for(j = 4; j >= 1; j--) {
4324 PseudoAdrPinCount = 15 - j;
4325 if((PseudoRankCapacity * j) <= 64) {
4326 if(sisfb_post_300_rwtest(ivideo,
4327 j,
4328 buswidth,
4329 PseudoRankCapacity,
4330 PseudoAdrPinCount,
4331 mapsize))
4332 return;
4333 }
4334 }
4335 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004336}
4337
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004338static void __devinit
4339sisfb_post_sis300(struct pci_dev *pdev)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004340{
4341 struct sis_video_info *ivideo = pci_get_drvdata(pdev);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004342 unsigned char *bios = ivideo->SiS_Pr.VirtualRomBase;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004343 u8 reg, v1, v2, v3, v4, v5, v6, v7, v8;
4344 u16 index, rindex, memtype = 0;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004345 unsigned int mapsize;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004346
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004347 if(!ivideo->SiS_Pr.UseROM)
4348 bios = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004349
Aaro Koskinen44b751b2010-12-20 23:50:17 +02004350 SiS_SetReg(SISSR, 0x05, 0x86);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004351
4352 if(bios) {
4353 if(bios[0x52] & 0x80) {
4354 memtype = bios[0x52];
4355 } else {
Aaro Koskinene57d4132010-12-20 23:50:16 +02004356 memtype = SiS_GetReg(SISSR, 0x3a);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004357 }
4358 memtype &= 0x07;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004359 }
4360
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004361 v3 = 0x80; v6 = 0x80;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004362 if(ivideo->revision_id <= 0x13) {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004363 v1 = 0x44; v2 = 0x42;
4364 v4 = 0x44; v5 = 0x42;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004365 } else {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004366 v1 = 0x68; v2 = 0x43; /* Assume 125Mhz MCLK */
4367 v4 = 0x68; v5 = 0x43; /* Assume 125Mhz ECLK */
4368 if(bios) {
4369 index = memtype * 5;
4370 rindex = index + 0x54;
4371 v1 = bios[rindex++];
4372 v2 = bios[rindex++];
4373 v3 = bios[rindex++];
4374 rindex = index + 0x7c;
4375 v4 = bios[rindex++];
4376 v5 = bios[rindex++];
4377 v6 = bios[rindex++];
4378 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004379 }
Aaro Koskinen44b751b2010-12-20 23:50:17 +02004380 SiS_SetReg(SISSR, 0x28, v1);
4381 SiS_SetReg(SISSR, 0x29, v2);
4382 SiS_SetReg(SISSR, 0x2a, v3);
4383 SiS_SetReg(SISSR, 0x2e, v4);
4384 SiS_SetReg(SISSR, 0x2f, v5);
4385 SiS_SetReg(SISSR, 0x30, v6);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004386
Linus Torvalds1da177e2005-04-16 15:20:36 -07004387 v1 = 0x10;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004388 if(bios)
4389 v1 = bios[0xa4];
Aaro Koskinen44b751b2010-12-20 23:50:17 +02004390 SiS_SetReg(SISSR, 0x07, v1); /* DAC speed */
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004391
Aaro Koskinen44b751b2010-12-20 23:50:17 +02004392 SiS_SetReg(SISSR, 0x11, 0x0f); /* DDC, power save */
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004393
Linus Torvalds1da177e2005-04-16 15:20:36 -07004394 v1 = 0x01; v2 = 0x43; v3 = 0x1e; v4 = 0x2a;
4395 v5 = 0x06; v6 = 0x00; v7 = 0x00; v8 = 0x00;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004396 if(bios) {
4397 memtype += 0xa5;
4398 v1 = bios[memtype];
4399 v2 = bios[memtype + 8];
4400 v3 = bios[memtype + 16];
4401 v4 = bios[memtype + 24];
4402 v5 = bios[memtype + 32];
4403 v6 = bios[memtype + 40];
4404 v7 = bios[memtype + 48];
4405 v8 = bios[memtype + 56];
Linus Torvalds1da177e2005-04-16 15:20:36 -07004406 }
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004407 if(ivideo->revision_id >= 0x80)
4408 v3 &= 0xfd;
Aaro Koskinen44b751b2010-12-20 23:50:17 +02004409 SiS_SetReg(SISSR, 0x15, v1); /* Ram type (assuming 0, BIOS 0xa5 step 8) */
4410 SiS_SetReg(SISSR, 0x16, v2);
4411 SiS_SetReg(SISSR, 0x17, v3);
4412 SiS_SetReg(SISSR, 0x18, v4);
4413 SiS_SetReg(SISSR, 0x19, v5);
4414 SiS_SetReg(SISSR, 0x1a, v6);
4415 SiS_SetReg(SISSR, 0x1b, v7);
4416 SiS_SetReg(SISSR, 0x1c, v8); /* ---- */
Aaro Koskinen667a8b42010-12-20 23:50:19 +02004417 SiS_SetRegAND(SISSR, 0x15, 0xfb);
Aaro Koskinen27799d62010-12-20 23:50:18 +02004418 SiS_SetRegOR(SISSR, 0x15, 0x04);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004419 if(bios) {
4420 if(bios[0x53] & 0x02) {
Aaro Koskinen27799d62010-12-20 23:50:18 +02004421 SiS_SetRegOR(SISSR, 0x19, 0x20);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004422 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004423 }
4424 v1 = 0x04; /* DAC pedestal (BIOS 0xe5) */
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004425 if(ivideo->revision_id >= 0x80)
4426 v1 |= 0x01;
Aaro Koskinen44b751b2010-12-20 23:50:17 +02004427 SiS_SetReg(SISSR, 0x1f, v1);
4428 SiS_SetReg(SISSR, 0x20, 0xa4); /* linear & relocated io & disable a0000 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07004429 v1 = 0xf6; v2 = 0x0d; v3 = 0x00;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004430 if(bios) {
4431 v1 = bios[0xe8];
4432 v2 = bios[0xe9];
4433 v3 = bios[0xea];
Linus Torvalds1da177e2005-04-16 15:20:36 -07004434 }
Aaro Koskinen44b751b2010-12-20 23:50:17 +02004435 SiS_SetReg(SISSR, 0x23, v1);
4436 SiS_SetReg(SISSR, 0x24, v2);
4437 SiS_SetReg(SISSR, 0x25, v3);
4438 SiS_SetReg(SISSR, 0x21, 0x84);
4439 SiS_SetReg(SISSR, 0x22, 0x00);
4440 SiS_SetReg(SISCR, 0x37, 0x00);
Aaro Koskinen27799d62010-12-20 23:50:18 +02004441 SiS_SetRegOR(SISPART1, 0x24, 0x01); /* unlock crt2 */
Aaro Koskinen44b751b2010-12-20 23:50:17 +02004442 SiS_SetReg(SISPART1, 0x00, 0x00);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004443 v1 = 0x40; v2 = 0x11;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004444 if(bios) {
4445 v1 = bios[0xec];
4446 v2 = bios[0xeb];
Linus Torvalds1da177e2005-04-16 15:20:36 -07004447 }
Aaro Koskinen44b751b2010-12-20 23:50:17 +02004448 SiS_SetReg(SISPART1, 0x02, v1);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004449
4450 if(ivideo->revision_id >= 0x80)
4451 v2 &= ~0x01;
4452
Aaro Koskinene57d4132010-12-20 23:50:16 +02004453 reg = SiS_GetReg(SISPART4, 0x00);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004454 if((reg == 1) || (reg == 2)) {
Aaro Koskinen44b751b2010-12-20 23:50:17 +02004455 SiS_SetReg(SISCR, 0x37, 0x02);
4456 SiS_SetReg(SISPART2, 0x00, 0x1c);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004457 v4 = 0x00; v5 = 0x00; v6 = 0x10;
4458 if(ivideo->SiS_Pr.UseROM) {
4459 v4 = bios[0xf5];
4460 v5 = bios[0xf6];
4461 v6 = bios[0xf7];
4462 }
Aaro Koskinen44b751b2010-12-20 23:50:17 +02004463 SiS_SetReg(SISPART4, 0x0d, v4);
4464 SiS_SetReg(SISPART4, 0x0e, v5);
4465 SiS_SetReg(SISPART4, 0x10, v6);
4466 SiS_SetReg(SISPART4, 0x0f, 0x3f);
Aaro Koskinene57d4132010-12-20 23:50:16 +02004467 reg = SiS_GetReg(SISPART4, 0x01);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004468 if(reg >= 0xb0) {
Aaro Koskinene57d4132010-12-20 23:50:16 +02004469 reg = SiS_GetReg(SISPART4, 0x23);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004470 reg &= 0x20;
4471 reg <<= 1;
Aaro Koskinen44b751b2010-12-20 23:50:17 +02004472 SiS_SetReg(SISPART4, 0x23, reg);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004473 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004474 } else {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004475 v2 &= ~0x10;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004476 }
Aaro Koskinen44b751b2010-12-20 23:50:17 +02004477 SiS_SetReg(SISSR, 0x32, v2);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004478
Aaro Koskinen667a8b42010-12-20 23:50:19 +02004479 SiS_SetRegAND(SISPART1, 0x24, 0xfe); /* Lock CRT2 */
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004480
Aaro Koskinene57d4132010-12-20 23:50:16 +02004481 reg = SiS_GetReg(SISSR, 0x16);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004482 reg &= 0xc3;
Aaro Koskinen44b751b2010-12-20 23:50:17 +02004483 SiS_SetReg(SISCR, 0x35, reg);
4484 SiS_SetReg(SISCR, 0x83, 0x00);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004485#if !defined(__i386__) && !defined(__x86_64__)
4486 if(sisfb_videoram) {
Aaro Koskinen44b751b2010-12-20 23:50:17 +02004487 SiS_SetReg(SISSR, 0x13, 0x28); /* ? */
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004488 reg = ((sisfb_videoram >> 10) - 1) | 0x40;
Aaro Koskinen44b751b2010-12-20 23:50:17 +02004489 SiS_SetReg(SISSR, 0x14, reg);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004490 } else {
4491#endif
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004492 /* Need to map max FB size for finding out about RAM size */
Aaro Koskinen32ed3032010-11-10 13:04:19 +02004493 mapsize = ivideo->video_size;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004494 sisfb_post_map_vram(ivideo, &mapsize, 4);
4495
4496 if(ivideo->video_vbase) {
4497 sisfb_post_300_ramsize(pdev, mapsize);
4498 iounmap(ivideo->video_vbase);
4499 } else {
4500 printk(KERN_DEBUG
4501 "sisfb: Failed to map memory for size detection, assuming 8MB\n");
Aaro Koskinen44b751b2010-12-20 23:50:17 +02004502 SiS_SetReg(SISSR, 0x13, 0x28); /* ? */
4503 SiS_SetReg(SISSR, 0x14, 0x47); /* 8MB, 64bit default */
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004504 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004505#if !defined(__i386__) && !defined(__x86_64__)
4506 }
4507#endif
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004508 if(bios) {
4509 v1 = bios[0xe6];
4510 v2 = bios[0xe7];
Linus Torvalds1da177e2005-04-16 15:20:36 -07004511 } else {
Aaro Koskinene57d4132010-12-20 23:50:16 +02004512 reg = SiS_GetReg(SISSR, 0x3a);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004513 if((reg & 0x30) == 0x30) {
4514 v1 = 0x04; /* PCI */
4515 v2 = 0x92;
4516 } else {
4517 v1 = 0x14; /* AGP */
4518 v2 = 0xb2;
4519 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004520 }
Aaro Koskinen44b751b2010-12-20 23:50:17 +02004521 SiS_SetReg(SISSR, 0x21, v1);
4522 SiS_SetReg(SISSR, 0x22, v2);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004523
4524 /* Sense CRT1 */
4525 sisfb_sense_crt1(ivideo);
4526
4527 /* Set default mode, don't clear screen */
Richard Knutssonc30660ea2007-02-12 00:55:06 -08004528 ivideo->SiS_Pr.SiS_UseOEM = false;
4529 SiS_SetEnableDstn(&ivideo->SiS_Pr, false);
4530 SiS_SetEnableFstn(&ivideo->SiS_Pr, false);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004531 ivideo->curFSTN = ivideo->curDSTN = 0;
4532 ivideo->SiS_Pr.VideoMemorySize = 8 << 20;
4533 SiSSetMode(&ivideo->SiS_Pr, 0x2e | 0x80);
4534
Aaro Koskinen44b751b2010-12-20 23:50:17 +02004535 SiS_SetReg(SISSR, 0x05, 0x86);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004536
4537 /* Display off */
Aaro Koskinen27799d62010-12-20 23:50:18 +02004538 SiS_SetRegOR(SISSR, 0x01, 0x20);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004539
4540 /* Save mode number in CR34 */
Aaro Koskinen44b751b2010-12-20 23:50:17 +02004541 SiS_SetReg(SISCR, 0x34, 0x2e);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004542
4543 /* Let everyone know what the current mode is */
4544 ivideo->modeprechange = 0x2e;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004545}
4546#endif
4547
4548#ifdef CONFIG_FB_SIS_315
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004549#if 0
4550static void __devinit
4551sisfb_post_sis315330(struct pci_dev *pdev)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004552{
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004553 /* TODO */
Linus Torvalds1da177e2005-04-16 15:20:36 -07004554}
4555#endif
4556
Aaro Koskinen929c9722011-02-13 22:11:25 +00004557static inline int sisfb_xgi_is21(struct sis_video_info *ivideo)
4558{
4559 return ivideo->chip_real_id == XGI_21;
4560}
4561
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004562static void __devinit
4563sisfb_post_xgi_delay(struct sis_video_info *ivideo, int delay)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004564{
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004565 unsigned int i;
4566 u8 reg;
4567
4568 for(i = 0; i <= (delay * 10 * 36); i++) {
Aaro Koskinene57d4132010-12-20 23:50:16 +02004569 reg = SiS_GetReg(SISSR, 0x05);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004570 reg++;
4571 }
4572}
4573
4574static int __devinit
4575sisfb_find_host_bridge(struct sis_video_info *ivideo, struct pci_dev *mypdev,
4576 unsigned short pcivendor)
4577{
4578 struct pci_dev *pdev = NULL;
4579 unsigned short temp;
4580 int ret = 0;
4581
Adrian Bunk0959f0c2007-05-08 00:39:50 -07004582 while((pdev = pci_get_class(PCI_CLASS_BRIDGE_HOST, pdev))) {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004583 temp = pdev->vendor;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004584 if(temp == pcivendor) {
4585 ret = 1;
Julia Lawallea237a62008-02-06 01:39:07 -08004586 pci_dev_put(pdev);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004587 break;
4588 }
4589 }
4590
4591 return ret;
4592}
4593
4594static int __devinit
4595sisfb_post_xgi_rwtest(struct sis_video_info *ivideo, int starta,
4596 unsigned int enda, unsigned int mapsize)
4597{
4598 unsigned int pos;
4599 int i;
4600
4601 writel(0, ivideo->video_vbase);
4602
4603 for(i = starta; i <= enda; i++) {
4604 pos = 1 << i;
4605 if(pos < mapsize)
4606 writel(pos, ivideo->video_vbase + pos);
4607 }
4608
4609 sisfb_post_xgi_delay(ivideo, 150);
4610
4611 if(readl(ivideo->video_vbase) != 0)
4612 return 0;
4613
4614 for(i = starta; i <= enda; i++) {
4615 pos = 1 << i;
4616 if(pos < mapsize) {
4617 if(readl(ivideo->video_vbase + pos) != pos)
4618 return 0;
4619 } else
4620 return 0;
4621 }
4622
4623 return 1;
4624}
4625
Aaro Koskinen83ea0f12011-02-13 22:11:23 +00004626static int __devinit
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004627sisfb_post_xgi_ramsize(struct sis_video_info *ivideo)
4628{
4629 unsigned int buswidth, ranksize, channelab, mapsize;
Aaro Koskinen83ea0f12011-02-13 22:11:23 +00004630 int i, j, k, l, status;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004631 u8 reg, sr14;
4632 static const u8 dramsr13[12 * 5] = {
4633 0x02, 0x0e, 0x0b, 0x80, 0x5d,
4634 0x02, 0x0e, 0x0a, 0x40, 0x59,
4635 0x02, 0x0d, 0x0b, 0x40, 0x4d,
4636 0x02, 0x0e, 0x09, 0x20, 0x55,
4637 0x02, 0x0d, 0x0a, 0x20, 0x49,
4638 0x02, 0x0c, 0x0b, 0x20, 0x3d,
4639 0x02, 0x0e, 0x08, 0x10, 0x51,
4640 0x02, 0x0d, 0x09, 0x10, 0x45,
4641 0x02, 0x0c, 0x0a, 0x10, 0x39,
4642 0x02, 0x0d, 0x08, 0x08, 0x41,
4643 0x02, 0x0c, 0x09, 0x08, 0x35,
4644 0x02, 0x0c, 0x08, 0x04, 0x31
4645 };
4646 static const u8 dramsr13_4[4 * 5] = {
4647 0x02, 0x0d, 0x09, 0x40, 0x45,
4648 0x02, 0x0c, 0x09, 0x20, 0x35,
4649 0x02, 0x0c, 0x08, 0x10, 0x31,
4650 0x02, 0x0b, 0x08, 0x08, 0x21
4651 };
4652
4653 /* Enable linear mode, disable 0xa0000 address decoding */
4654 /* We disable a0000 address decoding, because
4655 * - if running on x86, if the card is disabled, it means
4656 * that another card is in the system. We don't want
4657 * to interphere with that primary card's textmode.
4658 * - if running on non-x86, there usually is no VGA window
4659 * at a0000.
4660 */
Aaro Koskinen27799d62010-12-20 23:50:18 +02004661 SiS_SetRegOR(SISSR, 0x20, (0x80 | 0x04));
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004662
4663 /* Need to map max FB size for finding out about RAM size */
Aaro Koskinen32ed3032010-11-10 13:04:19 +02004664 mapsize = ivideo->video_size;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004665 sisfb_post_map_vram(ivideo, &mapsize, 32);
4666
4667 if(!ivideo->video_vbase) {
4668 printk(KERN_ERR "sisfb: Unable to detect RAM size. Setting default.\n");
Aaro Koskinen44b751b2010-12-20 23:50:17 +02004669 SiS_SetReg(SISSR, 0x13, 0x35);
4670 SiS_SetReg(SISSR, 0x14, 0x41);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004671 /* TODO */
Aaro Koskinen83ea0f12011-02-13 22:11:23 +00004672 return -ENOMEM;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004673 }
4674
4675 /* Non-interleaving */
Aaro Koskinen44b751b2010-12-20 23:50:17 +02004676 SiS_SetReg(SISSR, 0x15, 0x00);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004677 /* No tiling */
Aaro Koskinen44b751b2010-12-20 23:50:17 +02004678 SiS_SetReg(SISSR, 0x1c, 0x00);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004679
4680 if(ivideo->chip == XGI_20) {
4681
4682 channelab = 1;
Aaro Koskinene57d4132010-12-20 23:50:16 +02004683 reg = SiS_GetReg(SISCR, 0x97);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004684 if(!(reg & 0x01)) { /* Single 32/16 */
4685 buswidth = 32;
Aaro Koskinen44b751b2010-12-20 23:50:17 +02004686 SiS_SetReg(SISSR, 0x13, 0xb1);
4687 SiS_SetReg(SISSR, 0x14, 0x52);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004688 sisfb_post_xgi_delay(ivideo, 1);
4689 sr14 = 0x02;
4690 if(sisfb_post_xgi_rwtest(ivideo, 23, 24, mapsize))
4691 goto bail_out;
4692
Aaro Koskinen44b751b2010-12-20 23:50:17 +02004693 SiS_SetReg(SISSR, 0x13, 0x31);
4694 SiS_SetReg(SISSR, 0x14, 0x42);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004695 sisfb_post_xgi_delay(ivideo, 1);
4696 if(sisfb_post_xgi_rwtest(ivideo, 23, 23, mapsize))
4697 goto bail_out;
4698
4699 buswidth = 16;
Aaro Koskinen44b751b2010-12-20 23:50:17 +02004700 SiS_SetReg(SISSR, 0x13, 0xb1);
4701 SiS_SetReg(SISSR, 0x14, 0x41);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004702 sisfb_post_xgi_delay(ivideo, 1);
4703 sr14 = 0x01;
4704 if(sisfb_post_xgi_rwtest(ivideo, 22, 23, mapsize))
4705 goto bail_out;
4706 else
Aaro Koskinen44b751b2010-12-20 23:50:17 +02004707 SiS_SetReg(SISSR, 0x13, 0x31);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004708 } else { /* Dual 16/8 */
4709 buswidth = 16;
Aaro Koskinen44b751b2010-12-20 23:50:17 +02004710 SiS_SetReg(SISSR, 0x13, 0xb1);
4711 SiS_SetReg(SISSR, 0x14, 0x41);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004712 sisfb_post_xgi_delay(ivideo, 1);
4713 sr14 = 0x01;
4714 if(sisfb_post_xgi_rwtest(ivideo, 22, 23, mapsize))
4715 goto bail_out;
4716
Aaro Koskinen44b751b2010-12-20 23:50:17 +02004717 SiS_SetReg(SISSR, 0x13, 0x31);
4718 SiS_SetReg(SISSR, 0x14, 0x31);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004719 sisfb_post_xgi_delay(ivideo, 1);
4720 if(sisfb_post_xgi_rwtest(ivideo, 22, 22, mapsize))
4721 goto bail_out;
4722
4723 buswidth = 8;
Aaro Koskinen44b751b2010-12-20 23:50:17 +02004724 SiS_SetReg(SISSR, 0x13, 0xb1);
4725 SiS_SetReg(SISSR, 0x14, 0x30);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004726 sisfb_post_xgi_delay(ivideo, 1);
4727 sr14 = 0x00;
4728 if(sisfb_post_xgi_rwtest(ivideo, 21, 22, mapsize))
4729 goto bail_out;
4730 else
Aaro Koskinen44b751b2010-12-20 23:50:17 +02004731 SiS_SetReg(SISSR, 0x13, 0x31);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004732 }
4733
4734 } else { /* XGI_40 */
4735
Aaro Koskinene57d4132010-12-20 23:50:16 +02004736 reg = SiS_GetReg(SISCR, 0x97);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004737 if(!(reg & 0x10)) {
Aaro Koskinene57d4132010-12-20 23:50:16 +02004738 reg = SiS_GetReg(SISSR, 0x39);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004739 reg >>= 1;
4740 }
4741
4742 if(reg & 0x01) { /* DDRII */
4743 buswidth = 32;
4744 if(ivideo->revision_id == 2) {
4745 channelab = 2;
Aaro Koskinen44b751b2010-12-20 23:50:17 +02004746 SiS_SetReg(SISSR, 0x13, 0xa1);
4747 SiS_SetReg(SISSR, 0x14, 0x44);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004748 sr14 = 0x04;
4749 sisfb_post_xgi_delay(ivideo, 1);
4750 if(sisfb_post_xgi_rwtest(ivideo, 23, 24, mapsize))
4751 goto bail_out;
4752
Aaro Koskinen44b751b2010-12-20 23:50:17 +02004753 SiS_SetReg(SISSR, 0x13, 0x21);
4754 SiS_SetReg(SISSR, 0x14, 0x34);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004755 if(sisfb_post_xgi_rwtest(ivideo, 22, 23, mapsize))
4756 goto bail_out;
4757
4758 channelab = 1;
Aaro Koskinen44b751b2010-12-20 23:50:17 +02004759 SiS_SetReg(SISSR, 0x13, 0xa1);
4760 SiS_SetReg(SISSR, 0x14, 0x40);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004761 sr14 = 0x00;
4762 if(sisfb_post_xgi_rwtest(ivideo, 22, 23, mapsize))
4763 goto bail_out;
4764
Aaro Koskinen44b751b2010-12-20 23:50:17 +02004765 SiS_SetReg(SISSR, 0x13, 0x21);
4766 SiS_SetReg(SISSR, 0x14, 0x30);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004767 } else {
4768 channelab = 3;
Aaro Koskinen44b751b2010-12-20 23:50:17 +02004769 SiS_SetReg(SISSR, 0x13, 0xa1);
4770 SiS_SetReg(SISSR, 0x14, 0x4c);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004771 sr14 = 0x0c;
4772 sisfb_post_xgi_delay(ivideo, 1);
4773 if(sisfb_post_xgi_rwtest(ivideo, 23, 25, mapsize))
4774 goto bail_out;
4775
4776 channelab = 2;
Aaro Koskinen44b751b2010-12-20 23:50:17 +02004777 SiS_SetReg(SISSR, 0x14, 0x48);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004778 sisfb_post_xgi_delay(ivideo, 1);
4779 sr14 = 0x08;
4780 if(sisfb_post_xgi_rwtest(ivideo, 23, 24, mapsize))
4781 goto bail_out;
4782
Aaro Koskinen44b751b2010-12-20 23:50:17 +02004783 SiS_SetReg(SISSR, 0x13, 0x21);
4784 SiS_SetReg(SISSR, 0x14, 0x3c);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004785 sr14 = 0x0c;
4786
4787 if(sisfb_post_xgi_rwtest(ivideo, 23, 24, mapsize)) {
4788 channelab = 3;
4789 } else {
4790 channelab = 2;
Aaro Koskinen44b751b2010-12-20 23:50:17 +02004791 SiS_SetReg(SISSR, 0x14, 0x38);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004792 sr14 = 0x08;
4793 }
4794 }
4795 sisfb_post_xgi_delay(ivideo, 1);
4796
4797 } else { /* DDR */
4798
4799 buswidth = 64;
4800 if(ivideo->revision_id == 2) {
4801 channelab = 1;
Aaro Koskinen44b751b2010-12-20 23:50:17 +02004802 SiS_SetReg(SISSR, 0x13, 0xa1);
4803 SiS_SetReg(SISSR, 0x14, 0x52);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004804 sisfb_post_xgi_delay(ivideo, 1);
4805 sr14 = 0x02;
4806 if(sisfb_post_xgi_rwtest(ivideo, 23, 24, mapsize))
4807 goto bail_out;
4808
Aaro Koskinen44b751b2010-12-20 23:50:17 +02004809 SiS_SetReg(SISSR, 0x13, 0x21);
4810 SiS_SetReg(SISSR, 0x14, 0x42);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004811 } else {
4812 channelab = 2;
Aaro Koskinen44b751b2010-12-20 23:50:17 +02004813 SiS_SetReg(SISSR, 0x13, 0xa1);
4814 SiS_SetReg(SISSR, 0x14, 0x5a);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004815 sisfb_post_xgi_delay(ivideo, 1);
4816 sr14 = 0x0a;
4817 if(sisfb_post_xgi_rwtest(ivideo, 24, 25, mapsize))
4818 goto bail_out;
4819
Aaro Koskinen44b751b2010-12-20 23:50:17 +02004820 SiS_SetReg(SISSR, 0x13, 0x21);
4821 SiS_SetReg(SISSR, 0x14, 0x4a);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004822 }
4823 sisfb_post_xgi_delay(ivideo, 1);
4824
4825 }
4826 }
4827
4828bail_out:
Aaro Koskinenad78adb2010-12-20 23:50:20 +02004829 SiS_SetRegANDOR(SISSR, 0x14, 0xf0, sr14);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004830 sisfb_post_xgi_delay(ivideo, 1);
4831
4832 j = (ivideo->chip == XGI_20) ? 5 : 9;
4833 k = (ivideo->chip == XGI_20) ? 12 : 4;
Aaro Koskinen83ea0f12011-02-13 22:11:23 +00004834 status = -EIO;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004835
4836 for(i = 0; i < k; i++) {
4837
4838 reg = (ivideo->chip == XGI_20) ?
4839 dramsr13[(i * 5) + 4] : dramsr13_4[(i * 5) + 4];
Aaro Koskinenad78adb2010-12-20 23:50:20 +02004840 SiS_SetRegANDOR(SISSR, 0x13, 0x80, reg);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004841 sisfb_post_xgi_delay(ivideo, 50);
4842
4843 ranksize = (ivideo->chip == XGI_20) ?
4844 dramsr13[(i * 5) + 3] : dramsr13_4[(i * 5) + 3];
4845
Aaro Koskinene57d4132010-12-20 23:50:16 +02004846 reg = SiS_GetReg(SISSR, 0x13);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004847 if(reg & 0x80) ranksize <<= 1;
4848
4849 if(ivideo->chip == XGI_20) {
4850 if(buswidth == 16) ranksize <<= 1;
4851 else if(buswidth == 32) ranksize <<= 2;
4852 } else {
4853 if(buswidth == 64) ranksize <<= 1;
4854 }
4855
4856 reg = 0;
4857 l = channelab;
4858 if(l == 3) l = 4;
4859 if((ranksize * l) <= 256) {
4860 while((ranksize >>= 1)) reg += 0x10;
4861 }
4862
4863 if(!reg) continue;
4864
Aaro Koskinenad78adb2010-12-20 23:50:20 +02004865 SiS_SetRegANDOR(SISSR, 0x14, 0x0f, (reg & 0xf0));
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004866 sisfb_post_xgi_delay(ivideo, 1);
4867
Aaro Koskinen83ea0f12011-02-13 22:11:23 +00004868 if (sisfb_post_xgi_rwtest(ivideo, j, ((reg >> 4) + channelab - 2 + 20), mapsize)) {
4869 status = 0;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004870 break;
Aaro Koskinen83ea0f12011-02-13 22:11:23 +00004871 }
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004872 }
4873
4874 iounmap(ivideo->video_vbase);
Aaro Koskinen83ea0f12011-02-13 22:11:23 +00004875
4876 return status;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004877}
4878
4879static void __devinit
4880sisfb_post_xgi_setclocks(struct sis_video_info *ivideo, u8 regb)
4881{
4882 u8 v1, v2, v3;
4883 int index;
4884 static const u8 cs90[8 * 3] = {
4885 0x16, 0x01, 0x01,
4886 0x3e, 0x03, 0x01,
4887 0x7c, 0x08, 0x01,
4888 0x79, 0x06, 0x01,
4889 0x29, 0x01, 0x81,
4890 0x5c, 0x23, 0x01,
4891 0x5c, 0x23, 0x01,
4892 0x5c, 0x23, 0x01
4893 };
4894 static const u8 csb8[8 * 3] = {
4895 0x5c, 0x23, 0x01,
4896 0x29, 0x01, 0x01,
4897 0x7c, 0x08, 0x01,
4898 0x79, 0x06, 0x01,
4899 0x29, 0x01, 0x81,
4900 0x5c, 0x23, 0x01,
4901 0x5c, 0x23, 0x01,
4902 0x5c, 0x23, 0x01
4903 };
4904
4905 regb = 0; /* ! */
4906
4907 index = regb * 3;
4908 v1 = cs90[index]; v2 = cs90[index + 1]; v3 = cs90[index + 2];
4909 if(ivideo->haveXGIROM) {
4910 v1 = ivideo->bios_abase[0x90 + index];
4911 v2 = ivideo->bios_abase[0x90 + index + 1];
4912 v3 = ivideo->bios_abase[0x90 + index + 2];
4913 }
Aaro Koskinen44b751b2010-12-20 23:50:17 +02004914 SiS_SetReg(SISSR, 0x28, v1);
4915 SiS_SetReg(SISSR, 0x29, v2);
4916 SiS_SetReg(SISSR, 0x2a, v3);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004917 sisfb_post_xgi_delay(ivideo, 0x43);
4918 sisfb_post_xgi_delay(ivideo, 0x43);
4919 sisfb_post_xgi_delay(ivideo, 0x43);
4920 index = regb * 3;
4921 v1 = csb8[index]; v2 = csb8[index + 1]; v3 = csb8[index + 2];
4922 if(ivideo->haveXGIROM) {
4923 v1 = ivideo->bios_abase[0xb8 + index];
4924 v2 = ivideo->bios_abase[0xb8 + index + 1];
4925 v3 = ivideo->bios_abase[0xb8 + index + 2];
4926 }
Aaro Koskinen44b751b2010-12-20 23:50:17 +02004927 SiS_SetReg(SISSR, 0x2e, v1);
4928 SiS_SetReg(SISSR, 0x2f, v2);
4929 SiS_SetReg(SISSR, 0x30, v3);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004930 sisfb_post_xgi_delay(ivideo, 0x43);
4931 sisfb_post_xgi_delay(ivideo, 0x43);
4932 sisfb_post_xgi_delay(ivideo, 0x43);
4933}
4934
Aaro Koskinenc9982d52011-02-13 22:11:27 +00004935static void __devinit
4936sisfb_post_xgi_ddr2_mrs_default(struct sis_video_info *ivideo, u8 regb)
4937{
4938 unsigned char *bios = ivideo->bios_abase;
4939 u8 v1;
4940
4941 SiS_SetReg(SISSR, 0x28, 0x64);
4942 SiS_SetReg(SISSR, 0x29, 0x63);
4943 sisfb_post_xgi_delay(ivideo, 15);
4944 SiS_SetReg(SISSR, 0x18, 0x00);
4945 SiS_SetReg(SISSR, 0x19, 0x20);
4946 SiS_SetReg(SISSR, 0x16, 0x00);
4947 SiS_SetReg(SISSR, 0x16, 0x80);
4948 SiS_SetReg(SISSR, 0x18, 0xc5);
4949 SiS_SetReg(SISSR, 0x19, 0x23);
4950 SiS_SetReg(SISSR, 0x16, 0x00);
4951 SiS_SetReg(SISSR, 0x16, 0x80);
4952 sisfb_post_xgi_delay(ivideo, 1);
4953 SiS_SetReg(SISCR, 0x97, 0x11);
4954 sisfb_post_xgi_setclocks(ivideo, regb);
4955 sisfb_post_xgi_delay(ivideo, 0x46);
4956 SiS_SetReg(SISSR, 0x18, 0xc5);
4957 SiS_SetReg(SISSR, 0x19, 0x23);
4958 SiS_SetReg(SISSR, 0x16, 0x00);
4959 SiS_SetReg(SISSR, 0x16, 0x80);
4960 sisfb_post_xgi_delay(ivideo, 1);
4961 SiS_SetReg(SISSR, 0x1b, 0x04);
4962 sisfb_post_xgi_delay(ivideo, 1);
4963 SiS_SetReg(SISSR, 0x1b, 0x00);
4964 sisfb_post_xgi_delay(ivideo, 1);
4965 v1 = 0x31;
4966 if (ivideo->haveXGIROM) {
4967 v1 = bios[0xf0];
4968 }
4969 SiS_SetReg(SISSR, 0x18, v1);
4970 SiS_SetReg(SISSR, 0x19, 0x06);
4971 SiS_SetReg(SISSR, 0x16, 0x04);
4972 SiS_SetReg(SISSR, 0x16, 0x84);
4973 sisfb_post_xgi_delay(ivideo, 1);
4974}
4975
4976static void __devinit
Aaro Koskinen42dea9032011-02-13 22:11:28 +00004977sisfb_post_xgi_ddr2_mrs_xg21(struct sis_video_info *ivideo)
4978{
4979 sisfb_post_xgi_setclocks(ivideo, 1);
4980
4981 SiS_SetReg(SISCR, 0x97, 0x11);
4982 sisfb_post_xgi_delay(ivideo, 0x46);
4983
4984 SiS_SetReg(SISSR, 0x18, 0x00); /* EMRS2 */
4985 SiS_SetReg(SISSR, 0x19, 0x80);
4986 SiS_SetReg(SISSR, 0x16, 0x05);
4987 SiS_SetReg(SISSR, 0x16, 0x85);
4988
4989 SiS_SetReg(SISSR, 0x18, 0x00); /* EMRS3 */
4990 SiS_SetReg(SISSR, 0x19, 0xc0);
4991 SiS_SetReg(SISSR, 0x16, 0x05);
4992 SiS_SetReg(SISSR, 0x16, 0x85);
4993
4994 SiS_SetReg(SISSR, 0x18, 0x00); /* EMRS1 */
4995 SiS_SetReg(SISSR, 0x19, 0x40);
4996 SiS_SetReg(SISSR, 0x16, 0x05);
4997 SiS_SetReg(SISSR, 0x16, 0x85);
4998
4999 SiS_SetReg(SISSR, 0x18, 0x42); /* MRS1 */
5000 SiS_SetReg(SISSR, 0x19, 0x02);
5001 SiS_SetReg(SISSR, 0x16, 0x05);
5002 SiS_SetReg(SISSR, 0x16, 0x85);
5003 sisfb_post_xgi_delay(ivideo, 1);
5004
5005 SiS_SetReg(SISSR, 0x1b, 0x04);
5006 sisfb_post_xgi_delay(ivideo, 1);
5007
5008 SiS_SetReg(SISSR, 0x1b, 0x00);
5009 sisfb_post_xgi_delay(ivideo, 1);
5010
5011 SiS_SetReg(SISSR, 0x18, 0x42); /* MRS1 */
5012 SiS_SetReg(SISSR, 0x19, 0x00);
5013 SiS_SetReg(SISSR, 0x16, 0x05);
5014 SiS_SetReg(SISSR, 0x16, 0x85);
5015 sisfb_post_xgi_delay(ivideo, 1);
5016}
5017
5018static void __devinit
Aaro Koskinenc9982d52011-02-13 22:11:27 +00005019sisfb_post_xgi_ddr2(struct sis_video_info *ivideo, u8 regb)
5020{
5021 unsigned char *bios = ivideo->bios_abase;
5022 static const u8 cs158[8] = {
5023 0x88, 0xaa, 0x48, 0x00, 0x00, 0x00, 0x00, 0x00
5024 };
5025 static const u8 cs160[8] = {
5026 0x44, 0x77, 0x77, 0x00, 0x00, 0x00, 0x00, 0x00
5027 };
5028 static const u8 cs168[8] = {
5029 0x48, 0x78, 0x88, 0x00, 0x00, 0x00, 0x00, 0x00
5030 };
5031 u8 reg;
5032 u8 v1;
5033 u8 v2;
5034 u8 v3;
5035
Aaro Koskinen42dea9032011-02-13 22:11:28 +00005036 SiS_SetReg(SISCR, 0xb0, 0x80); /* DDR2 dual frequency mode */
Aaro Koskinenc9982d52011-02-13 22:11:27 +00005037 SiS_SetReg(SISCR, 0x82, 0x77);
5038 SiS_SetReg(SISCR, 0x86, 0x00);
5039 reg = SiS_GetReg(SISCR, 0x86);
5040 SiS_SetReg(SISCR, 0x86, 0x88);
5041 reg = SiS_GetReg(SISCR, 0x86);
5042 v1 = cs168[regb]; v2 = cs160[regb]; v3 = cs158[regb];
5043 if (ivideo->haveXGIROM) {
5044 v1 = bios[regb + 0x168];
5045 v2 = bios[regb + 0x160];
5046 v3 = bios[regb + 0x158];
5047 }
5048 SiS_SetReg(SISCR, 0x86, v1);
5049 SiS_SetReg(SISCR, 0x82, 0x77);
5050 SiS_SetReg(SISCR, 0x85, 0x00);
5051 reg = SiS_GetReg(SISCR, 0x85);
5052 SiS_SetReg(SISCR, 0x85, 0x88);
5053 reg = SiS_GetReg(SISCR, 0x85);
5054 SiS_SetReg(SISCR, 0x85, v2);
5055 SiS_SetReg(SISCR, 0x82, v3);
5056 SiS_SetReg(SISCR, 0x98, 0x01);
5057 SiS_SetReg(SISCR, 0x9a, 0x02);
Aaro Koskinen42dea9032011-02-13 22:11:28 +00005058 if (sisfb_xgi_is21(ivideo))
5059 sisfb_post_xgi_ddr2_mrs_xg21(ivideo);
5060 else
5061 sisfb_post_xgi_ddr2_mrs_default(ivideo, regb);
Aaro Koskinenc9982d52011-02-13 22:11:27 +00005062}
5063
Aaro Koskinen74de5f42011-02-13 22:11:24 +00005064static u8 __devinit
5065sisfb_post_xgi_ramtype(struct sis_video_info *ivideo)
5066{
5067 unsigned char *bios = ivideo->bios_abase;
5068 u8 ramtype;
5069 u8 reg;
5070 u8 v1;
5071
5072 ramtype = 0x00; v1 = 0x10;
5073 if (ivideo->haveXGIROM) {
5074 ramtype = bios[0x62];
5075 v1 = bios[0x1d2];
5076 }
5077 if (!(ramtype & 0x80)) {
Aaro Koskinen5e8700b2011-02-13 22:11:26 +00005078 if (sisfb_xgi_is21(ivideo)) {
5079 SiS_SetRegAND(SISCR, 0xb4, 0xfd); /* GPIO control */
5080 SiS_SetRegOR(SISCR, 0x4a, 0x80); /* GPIOH EN */
5081 reg = SiS_GetReg(SISCR, 0x48);
5082 SiS_SetRegOR(SISCR, 0xb4, 0x02);
5083 ramtype = reg & 0x01; /* GPIOH */
5084 } else if (ivideo->chip == XGI_20) {
Aaro Koskinen74de5f42011-02-13 22:11:24 +00005085 SiS_SetReg(SISCR, 0x97, v1);
5086 reg = SiS_GetReg(SISCR, 0x97);
5087 if (reg & 0x10) {
5088 ramtype = (reg & 0x01) << 1;
5089 }
5090 } else {
5091 reg = SiS_GetReg(SISSR, 0x39);
5092 ramtype = reg & 0x02;
5093 if (!(ramtype)) {
5094 reg = SiS_GetReg(SISSR, 0x3a);
5095 ramtype = (reg >> 1) & 0x01;
5096 }
5097 }
5098 }
5099 ramtype &= 0x07;
5100
5101 return ramtype;
5102}
5103
Thomas Winischhofer544393f2005-09-09 13:04:45 -07005104static int __devinit
5105sisfb_post_xgi(struct pci_dev *pdev)
5106{
5107 struct sis_video_info *ivideo = pci_get_drvdata(pdev);
5108 unsigned char *bios = ivideo->bios_abase;
5109 struct pci_dev *mypdev = NULL;
5110 const u8 *ptr, *ptr2;
5111 u8 v1, v2, v3, v4, v5, reg, ramtype;
5112 u32 rega, regb, regd;
5113 int i, j, k, index;
5114 static const u8 cs78[3] = { 0xf6, 0x0d, 0x00 };
5115 static const u8 cs76[2] = { 0xa3, 0xfb };
5116 static const u8 cs7b[3] = { 0xc0, 0x11, 0x00 };
5117 static const u8 cs158[8] = {
5118 0x88, 0xaa, 0x48, 0x00, 0x00, 0x00, 0x00, 0x00
5119 };
5120 static const u8 cs160[8] = {
5121 0x44, 0x77, 0x77, 0x00, 0x00, 0x00, 0x00, 0x00
5122 };
5123 static const u8 cs168[8] = {
5124 0x48, 0x78, 0x88, 0x00, 0x00, 0x00, 0x00, 0x00
5125 };
5126 static const u8 cs128[3 * 8] = {
5127 0x90, 0x28, 0x24, 0x00, 0x00, 0x00, 0x00, 0x00,
5128 0x77, 0x44, 0x44, 0x00, 0x00, 0x00, 0x00, 0x00,
5129 0x77, 0x44, 0x44, 0x00, 0x00, 0x00, 0x00, 0x00
5130 };
5131 static const u8 cs148[2 * 8] = {
5132 0x55, 0x55, 0x55, 0x00, 0x00, 0x00, 0x00, 0x00,
5133 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
5134 };
5135 static const u8 cs31a[8 * 4] = {
5136 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
5137 0xaa, 0xaa, 0xaa, 0xaa, 0x00, 0x00, 0x00, 0x00,
5138 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
5139 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
5140 };
5141 static const u8 cs33a[8 * 4] = {
5142 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
5143 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
5144 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
5145 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
5146 };
5147 static const u8 cs45a[8 * 2] = {
5148 0x00, 0x00, 0xa0, 0x00, 0xa0, 0x00, 0x00, 0x00,
5149 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
5150 };
5151 static const u8 cs170[7 * 8] = {
5152 0x54, 0x32, 0x44, 0x00, 0x00, 0x00, 0x00, 0x00,
5153 0x54, 0x43, 0x44, 0x00, 0x00, 0x00, 0x00, 0x00,
5154 0x0a, 0x05, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00,
5155 0x44, 0x34, 0x44, 0x00, 0x00, 0x00, 0x00, 0x00,
5156 0x10, 0x0a, 0x0a, 0x00, 0x00, 0x00, 0x00, 0x00,
5157 0x11, 0x0c, 0x0c, 0x00, 0x00, 0x00, 0x00, 0x00,
5158 0x05, 0x05, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00
5159 };
5160 static const u8 cs1a8[3 * 8] = {
5161 0xf0, 0xf0, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x00,
5162 0x05, 0x02, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00,
5163 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
5164 };
5165 static const u8 cs100[2 * 8] = {
5166 0xc4, 0x04, 0x84, 0x00, 0x00, 0x00, 0x00, 0x00,
5167 0xc4, 0x04, 0x84, 0x00, 0x00, 0x00, 0x00, 0x00
5168 };
5169
5170 /* VGA enable */
Aaro Koskinen1e1687d2010-12-20 23:50:14 +02005171 reg = SiS_GetRegByte(SISVGAENABLE) | 0x01;
Aaro Koskinen63e13f82010-12-20 23:50:15 +02005172 SiS_SetRegByte(SISVGAENABLE, reg);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07005173
5174 /* Misc */
Aaro Koskinen1e1687d2010-12-20 23:50:14 +02005175 reg = SiS_GetRegByte(SISMISCR) | 0x01;
Aaro Koskinen63e13f82010-12-20 23:50:15 +02005176 SiS_SetRegByte(SISMISCW, reg);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07005177
5178 /* Unlock SR */
Aaro Koskinen44b751b2010-12-20 23:50:17 +02005179 SiS_SetReg(SISSR, 0x05, 0x86);
Aaro Koskinene57d4132010-12-20 23:50:16 +02005180 reg = SiS_GetReg(SISSR, 0x05);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07005181 if(reg != 0xa1)
5182 return 0;
5183
5184 /* Clear some regs */
5185 for(i = 0; i < 0x22; i++) {
5186 if(0x06 + i == 0x20) continue;
Aaro Koskinen44b751b2010-12-20 23:50:17 +02005187 SiS_SetReg(SISSR, 0x06 + i, 0x00);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07005188 }
5189 for(i = 0; i < 0x0b; i++) {
Aaro Koskinen44b751b2010-12-20 23:50:17 +02005190 SiS_SetReg(SISSR, 0x31 + i, 0x00);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07005191 }
5192 for(i = 0; i < 0x10; i++) {
Aaro Koskinen44b751b2010-12-20 23:50:17 +02005193 SiS_SetReg(SISCR, 0x30 + i, 0x00);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07005194 }
5195
5196 ptr = cs78;
5197 if(ivideo->haveXGIROM) {
5198 ptr = (const u8 *)&bios[0x78];
5199 }
5200 for(i = 0; i < 3; i++) {
Aaro Koskinen44b751b2010-12-20 23:50:17 +02005201 SiS_SetReg(SISSR, 0x23 + i, ptr[i]);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07005202 }
5203
5204 ptr = cs76;
5205 if(ivideo->haveXGIROM) {
5206 ptr = (const u8 *)&bios[0x76];
5207 }
5208 for(i = 0; i < 2; i++) {
Aaro Koskinen44b751b2010-12-20 23:50:17 +02005209 SiS_SetReg(SISSR, 0x21 + i, ptr[i]);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07005210 }
5211
5212 v1 = 0x18; v2 = 0x00;
5213 if(ivideo->haveXGIROM) {
5214 v1 = bios[0x74];
5215 v2 = bios[0x75];
5216 }
Aaro Koskinen44b751b2010-12-20 23:50:17 +02005217 SiS_SetReg(SISSR, 0x07, v1);
5218 SiS_SetReg(SISSR, 0x11, 0x0f);
5219 SiS_SetReg(SISSR, 0x1f, v2);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07005220 /* PCI linear mode, RelIO enabled, A0000 decoding disabled */
Aaro Koskinen44b751b2010-12-20 23:50:17 +02005221 SiS_SetReg(SISSR, 0x20, 0x80 | 0x20 | 0x04);
5222 SiS_SetReg(SISSR, 0x27, 0x74);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07005223
5224 ptr = cs7b;
5225 if(ivideo->haveXGIROM) {
5226 ptr = (const u8 *)&bios[0x7b];
5227 }
5228 for(i = 0; i < 3; i++) {
Aaro Koskinen44b751b2010-12-20 23:50:17 +02005229 SiS_SetReg(SISSR, 0x31 + i, ptr[i]);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07005230 }
5231
5232 if(ivideo->chip == XGI_40) {
5233 if(ivideo->revision_id == 2) {
Aaro Koskinenad78adb2010-12-20 23:50:20 +02005234 SiS_SetRegANDOR(SISSR, 0x3b, 0x3f, 0xc0);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07005235 }
Aaro Koskinen44b751b2010-12-20 23:50:17 +02005236 SiS_SetReg(SISCR, 0x7d, 0xfe);
5237 SiS_SetReg(SISCR, 0x7e, 0x0f);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07005238 }
5239 if(ivideo->revision_id == 0) { /* 40 *and* 20? */
Aaro Koskinen667a8b42010-12-20 23:50:19 +02005240 SiS_SetRegAND(SISCR, 0x58, 0xd7);
Aaro Koskinene57d4132010-12-20 23:50:16 +02005241 reg = SiS_GetReg(SISCR, 0xcb);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07005242 if(reg & 0x20) {
Aaro Koskinenad78adb2010-12-20 23:50:20 +02005243 SiS_SetRegANDOR(SISCR, 0x58, 0xd7, (reg & 0x10) ? 0x08 : 0x20); /* =0x28 Z7 ? */
Thomas Winischhofer544393f2005-09-09 13:04:45 -07005244 }
5245 }
5246
5247 reg = (ivideo->chip == XGI_40) ? 0x20 : 0x00;
Aaro Koskinenad78adb2010-12-20 23:50:20 +02005248 SiS_SetRegANDOR(SISCR, 0x38, 0x1f, reg);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07005249
5250 if(ivideo->chip == XGI_20) {
Aaro Koskinen44b751b2010-12-20 23:50:17 +02005251 SiS_SetReg(SISSR, 0x36, 0x70);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07005252 } else {
Aaro Koskinen44b751b2010-12-20 23:50:17 +02005253 SiS_SetReg(SISVID, 0x00, 0x86);
5254 SiS_SetReg(SISVID, 0x32, 0x00);
5255 SiS_SetReg(SISVID, 0x30, 0x00);
5256 SiS_SetReg(SISVID, 0x32, 0x01);
5257 SiS_SetReg(SISVID, 0x30, 0x00);
Aaro Koskinen667a8b42010-12-20 23:50:19 +02005258 SiS_SetRegAND(SISVID, 0x2f, 0xdf);
5259 SiS_SetRegAND(SISCAP, 0x00, 0x3f);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07005260
Aaro Koskinen44b751b2010-12-20 23:50:17 +02005261 SiS_SetReg(SISPART1, 0x2f, 0x01);
5262 SiS_SetReg(SISPART1, 0x00, 0x00);
5263 SiS_SetReg(SISPART1, 0x02, bios[0x7e]);
5264 SiS_SetReg(SISPART1, 0x2e, 0x08);
Aaro Koskinen667a8b42010-12-20 23:50:19 +02005265 SiS_SetRegAND(SISPART1, 0x35, 0x7f);
5266 SiS_SetRegAND(SISPART1, 0x50, 0xfe);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07005267
Aaro Koskinene57d4132010-12-20 23:50:16 +02005268 reg = SiS_GetReg(SISPART4, 0x00);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07005269 if(reg == 1 || reg == 2) {
Aaro Koskinen44b751b2010-12-20 23:50:17 +02005270 SiS_SetReg(SISPART2, 0x00, 0x1c);
5271 SiS_SetReg(SISPART4, 0x0d, bios[0x7f]);
5272 SiS_SetReg(SISPART4, 0x0e, bios[0x80]);
5273 SiS_SetReg(SISPART4, 0x10, bios[0x81]);
Aaro Koskinen667a8b42010-12-20 23:50:19 +02005274 SiS_SetRegAND(SISPART4, 0x0f, 0x3f);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07005275
Aaro Koskinene57d4132010-12-20 23:50:16 +02005276 reg = SiS_GetReg(SISPART4, 0x01);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07005277 if((reg & 0xf0) >= 0xb0) {
Aaro Koskinene57d4132010-12-20 23:50:16 +02005278 reg = SiS_GetReg(SISPART4, 0x23);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07005279 if(reg & 0x20) reg |= 0x40;
Aaro Koskinen44b751b2010-12-20 23:50:17 +02005280 SiS_SetReg(SISPART4, 0x23, reg);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07005281 reg = (reg & 0x20) ? 0x02 : 0x00;
Aaro Koskinenad78adb2010-12-20 23:50:20 +02005282 SiS_SetRegANDOR(SISPART1, 0x1e, 0xfd, reg);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07005283 }
5284 }
5285
5286 v1 = bios[0x77];
5287
Aaro Koskinene57d4132010-12-20 23:50:16 +02005288 reg = SiS_GetReg(SISSR, 0x3b);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07005289 if(reg & 0x02) {
Aaro Koskinene57d4132010-12-20 23:50:16 +02005290 reg = SiS_GetReg(SISSR, 0x3a);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07005291 v2 = (reg & 0x30) >> 3;
5292 if(!(v2 & 0x04)) v2 ^= 0x02;
Aaro Koskinene57d4132010-12-20 23:50:16 +02005293 reg = SiS_GetReg(SISSR, 0x39);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07005294 if(reg & 0x80) v2 |= 0x80;
5295 v2 |= 0x01;
5296
Adrian Bunk0959f0c2007-05-08 00:39:50 -07005297 if((mypdev = pci_get_device(PCI_VENDOR_ID_SI, 0x0730, NULL))) {
5298 pci_dev_put(mypdev);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07005299 if(((v2 & 0x06) == 2) || ((v2 & 0x06) == 4))
5300 v2 &= 0xf9;
5301 v2 |= 0x08;
5302 v1 &= 0xfe;
5303 } else {
Adrian Bunk0959f0c2007-05-08 00:39:50 -07005304 mypdev = pci_get_device(PCI_VENDOR_ID_SI, 0x0735, NULL);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07005305 if(!mypdev)
Adrian Bunk0959f0c2007-05-08 00:39:50 -07005306 mypdev = pci_get_device(PCI_VENDOR_ID_SI, 0x0645, NULL);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07005307 if(!mypdev)
Adrian Bunk0959f0c2007-05-08 00:39:50 -07005308 mypdev = pci_get_device(PCI_VENDOR_ID_SI, 0x0650, NULL);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07005309 if(mypdev) {
5310 pci_read_config_dword(mypdev, 0x94, &regd);
5311 regd &= 0xfffffeff;
5312 pci_write_config_dword(mypdev, 0x94, regd);
5313 v1 &= 0xfe;
Adrian Bunk0959f0c2007-05-08 00:39:50 -07005314 pci_dev_put(mypdev);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07005315 } else if(sisfb_find_host_bridge(ivideo, pdev, PCI_VENDOR_ID_SI)) {
5316 v1 &= 0xfe;
5317 } else if(sisfb_find_host_bridge(ivideo, pdev, 0x1106) ||
5318 sisfb_find_host_bridge(ivideo, pdev, 0x1022) ||
5319 sisfb_find_host_bridge(ivideo, pdev, 0x700e) ||
5320 sisfb_find_host_bridge(ivideo, pdev, 0x10de)) {
5321 if((v2 & 0x06) == 4)
5322 v2 ^= 0x06;
5323 v2 |= 0x08;
5324 }
5325 }
Aaro Koskinenad78adb2010-12-20 23:50:20 +02005326 SiS_SetRegANDOR(SISCR, 0x5f, 0xf0, v2);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07005327 }
Aaro Koskinen44b751b2010-12-20 23:50:17 +02005328 SiS_SetReg(SISSR, 0x22, v1);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07005329
5330 if(ivideo->revision_id == 2) {
Aaro Koskinene57d4132010-12-20 23:50:16 +02005331 v1 = SiS_GetReg(SISSR, 0x3b);
5332 v2 = SiS_GetReg(SISSR, 0x3a);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07005333 regd = bios[0x90 + 3] | (bios[0x90 + 4] << 8);
5334 if( (!(v1 & 0x02)) && (v2 & 0x30) && (regd < 0xcf) )
Aaro Koskinenad78adb2010-12-20 23:50:20 +02005335 SiS_SetRegANDOR(SISCR, 0x5f, 0xf1, 0x01);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07005336
Adrian Bunk0959f0c2007-05-08 00:39:50 -07005337 if((mypdev = pci_get_device(0x10de, 0x01e0, NULL))) {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07005338 /* TODO: set CR5f &0xf1 | 0x01 for version 6570
5339 * of nforce 2 ROM
5340 */
5341 if(0)
Aaro Koskinenad78adb2010-12-20 23:50:20 +02005342 SiS_SetRegANDOR(SISCR, 0x5f, 0xf1, 0x01);
Adrian Bunk0959f0c2007-05-08 00:39:50 -07005343 pci_dev_put(mypdev);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07005344 }
5345 }
5346
5347 v1 = 0x30;
Aaro Koskinene57d4132010-12-20 23:50:16 +02005348 reg = SiS_GetReg(SISSR, 0x3b);
5349 v2 = SiS_GetReg(SISCR, 0x5f);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07005350 if((!(reg & 0x02)) && (v2 & 0x0e))
5351 v1 |= 0x08;
Aaro Koskinen44b751b2010-12-20 23:50:17 +02005352 SiS_SetReg(SISSR, 0x27, v1);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07005353
5354 if(bios[0x64] & 0x01) {
Aaro Koskinenad78adb2010-12-20 23:50:20 +02005355 SiS_SetRegANDOR(SISCR, 0x5f, 0xf0, bios[0x64]);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07005356 }
5357
5358 v1 = bios[0x4f7];
5359 pci_read_config_dword(pdev, 0x50, &regd);
5360 regd = (regd >> 20) & 0x0f;
5361 if(regd == 1) {
5362 v1 &= 0xfc;
Aaro Koskinen27799d62010-12-20 23:50:18 +02005363 SiS_SetRegOR(SISCR, 0x5f, 0x08);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07005364 }
Aaro Koskinen44b751b2010-12-20 23:50:17 +02005365 SiS_SetReg(SISCR, 0x48, v1);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07005366
Aaro Koskinenad78adb2010-12-20 23:50:20 +02005367 SiS_SetRegANDOR(SISCR, 0x47, 0x04, bios[0x4f6] & 0xfb);
5368 SiS_SetRegANDOR(SISCR, 0x49, 0xf0, bios[0x4f8] & 0x0f);
5369 SiS_SetRegANDOR(SISCR, 0x4a, 0x60, bios[0x4f9] & 0x9f);
5370 SiS_SetRegANDOR(SISCR, 0x4b, 0x08, bios[0x4fa] & 0xf7);
5371 SiS_SetRegANDOR(SISCR, 0x4c, 0x80, bios[0x4fb] & 0x7f);
Aaro Koskinen44b751b2010-12-20 23:50:17 +02005372 SiS_SetReg(SISCR, 0x70, bios[0x4fc]);
Aaro Koskinenad78adb2010-12-20 23:50:20 +02005373 SiS_SetRegANDOR(SISCR, 0x71, 0xf0, bios[0x4fd] & 0x0f);
Aaro Koskinen44b751b2010-12-20 23:50:17 +02005374 SiS_SetReg(SISCR, 0x74, 0xd0);
Aaro Koskinenad78adb2010-12-20 23:50:20 +02005375 SiS_SetRegANDOR(SISCR, 0x74, 0xcf, bios[0x4fe] & 0x30);
5376 SiS_SetRegANDOR(SISCR, 0x75, 0xe0, bios[0x4ff] & 0x1f);
5377 SiS_SetRegANDOR(SISCR, 0x76, 0xe0, bios[0x500] & 0x1f);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07005378 v1 = bios[0x501];
Adrian Bunk0959f0c2007-05-08 00:39:50 -07005379 if((mypdev = pci_get_device(0x8086, 0x2530, NULL))) {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07005380 v1 = 0xf0;
Adrian Bunk0959f0c2007-05-08 00:39:50 -07005381 pci_dev_put(mypdev);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07005382 }
Aaro Koskinen44b751b2010-12-20 23:50:17 +02005383 SiS_SetReg(SISCR, 0x77, v1);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07005384 }
5385
Aaro Koskinen42dea9032011-02-13 22:11:28 +00005386 /* RAM type:
5387 *
5388 * 0 == DDR1, 1 == DDR2, 2..7 == reserved?
5389 *
5390 * The code seems to written so that regb should equal ramtype,
5391 * however, so far it has been hardcoded to 0. Enable other values only
5392 * on XGI Z9, as it passes the POST, and add a warning for others.
5393 */
5394 ramtype = sisfb_post_xgi_ramtype(ivideo);
5395 if (!sisfb_xgi_is21(ivideo) && ramtype) {
5396 dev_warn(&pdev->dev,
5397 "RAM type something else than expected: %d\n",
5398 ramtype);
5399 regb = 0;
5400 } else {
5401 regb = ramtype;
5402 }
Thomas Winischhofer544393f2005-09-09 13:04:45 -07005403
5404 v1 = 0xff;
5405 if(ivideo->haveXGIROM) {
5406 v1 = bios[0x140 + regb];
5407 }
Aaro Koskinen44b751b2010-12-20 23:50:17 +02005408 SiS_SetReg(SISCR, 0x6d, v1);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07005409
5410 ptr = cs128;
5411 if(ivideo->haveXGIROM) {
5412 ptr = (const u8 *)&bios[0x128];
5413 }
5414 for(i = 0, j = 0; i < 3; i++, j += 8) {
Aaro Koskinen44b751b2010-12-20 23:50:17 +02005415 SiS_SetReg(SISCR, 0x68 + i, ptr[j + regb]);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07005416 }
5417
5418 ptr = cs31a;
5419 ptr2 = cs33a;
5420 if(ivideo->haveXGIROM) {
5421 index = (ivideo->chip == XGI_20) ? 0x31a : 0x3a6;
5422 ptr = (const u8 *)&bios[index];
5423 ptr2 = (const u8 *)&bios[index + 0x20];
5424 }
5425 for(i = 0; i < 2; i++) {
5426 if(i == 0) {
5427 regd = le32_to_cpu(((u32 *)ptr)[regb]);
5428 rega = 0x6b;
5429 } else {
5430 regd = le32_to_cpu(((u32 *)ptr2)[regb]);
5431 rega = 0x6e;
5432 }
5433 reg = 0x00;
5434 for(j = 0; j < 16; j++) {
5435 reg &= 0xf3;
5436 if(regd & 0x01) reg |= 0x04;
5437 if(regd & 0x02) reg |= 0x08;
5438 regd >>= 2;
Aaro Koskinen44b751b2010-12-20 23:50:17 +02005439 SiS_SetReg(SISCR, rega, reg);
Aaro Koskinene57d4132010-12-20 23:50:16 +02005440 reg = SiS_GetReg(SISCR, rega);
5441 reg = SiS_GetReg(SISCR, rega);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07005442 reg += 0x10;
5443 }
5444 }
5445
Aaro Koskinen667a8b42010-12-20 23:50:19 +02005446 SiS_SetRegAND(SISCR, 0x6e, 0xfc);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07005447
5448 ptr = NULL;
5449 if(ivideo->haveXGIROM) {
5450 index = (ivideo->chip == XGI_20) ? 0x35a : 0x3e6;
5451 ptr = (const u8 *)&bios[index];
5452 }
5453 for(i = 0; i < 4; i++) {
Aaro Koskinenad78adb2010-12-20 23:50:20 +02005454 SiS_SetRegANDOR(SISCR, 0x6e, 0xfc, i);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07005455 reg = 0x00;
5456 for(j = 0; j < 2; j++) {
5457 regd = 0;
5458 if(ptr) {
5459 regd = le32_to_cpu(((u32 *)ptr)[regb * 8]);
5460 ptr += 4;
5461 }
5462 /* reg = 0x00; */
5463 for(k = 0; k < 16; k++) {
5464 reg &= 0xfc;
5465 if(regd & 0x01) reg |= 0x01;
5466 if(regd & 0x02) reg |= 0x02;
5467 regd >>= 2;
Aaro Koskinen44b751b2010-12-20 23:50:17 +02005468 SiS_SetReg(SISCR, 0x6f, reg);
Aaro Koskinene57d4132010-12-20 23:50:16 +02005469 reg = SiS_GetReg(SISCR, 0x6f);
5470 reg = SiS_GetReg(SISCR, 0x6f);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07005471 reg += 0x08;
5472 }
5473 }
5474 }
5475
5476 ptr = cs148;
5477 if(ivideo->haveXGIROM) {
5478 ptr = (const u8 *)&bios[0x148];
5479 }
5480 for(i = 0, j = 0; i < 2; i++, j += 8) {
Aaro Koskinen44b751b2010-12-20 23:50:17 +02005481 SiS_SetReg(SISCR, 0x80 + i, ptr[j + regb]);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07005482 }
5483
Aaro Koskinen667a8b42010-12-20 23:50:19 +02005484 SiS_SetRegAND(SISCR, 0x89, 0x8f);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07005485
5486 ptr = cs45a;
5487 if(ivideo->haveXGIROM) {
5488 index = (ivideo->chip == XGI_20) ? 0x45a : 0x4e6;
5489 ptr = (const u8 *)&bios[index];
5490 }
5491 regd = le16_to_cpu(((const u16 *)ptr)[regb]);
5492 reg = 0x80;
5493 for(i = 0; i < 5; i++) {
5494 reg &= 0xfc;
5495 if(regd & 0x01) reg |= 0x01;
5496 if(regd & 0x02) reg |= 0x02;
5497 regd >>= 2;
Aaro Koskinen44b751b2010-12-20 23:50:17 +02005498 SiS_SetReg(SISCR, 0x89, reg);
Aaro Koskinene57d4132010-12-20 23:50:16 +02005499 reg = SiS_GetReg(SISCR, 0x89);
5500 reg = SiS_GetReg(SISCR, 0x89);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07005501 reg += 0x10;
5502 }
5503
5504 v1 = 0xb5; v2 = 0x20; v3 = 0xf0; v4 = 0x13;
5505 if(ivideo->haveXGIROM) {
5506 v1 = bios[0x118 + regb];
5507 v2 = bios[0xf8 + regb];
5508 v3 = bios[0x120 + regb];
5509 v4 = bios[0x1ca];
5510 }
Aaro Koskinen44b751b2010-12-20 23:50:17 +02005511 SiS_SetReg(SISCR, 0x45, v1 & 0x0f);
5512 SiS_SetReg(SISCR, 0x99, (v1 >> 4) & 0x07);
Aaro Koskinen27799d62010-12-20 23:50:18 +02005513 SiS_SetRegOR(SISCR, 0x40, v1 & 0x80);
Aaro Koskinen44b751b2010-12-20 23:50:17 +02005514 SiS_SetReg(SISCR, 0x41, v2);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07005515
5516 ptr = cs170;
5517 if(ivideo->haveXGIROM) {
5518 ptr = (const u8 *)&bios[0x170];
5519 }
5520 for(i = 0, j = 0; i < 7; i++, j += 8) {
Aaro Koskinen44b751b2010-12-20 23:50:17 +02005521 SiS_SetReg(SISCR, 0x90 + i, ptr[j + regb]);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07005522 }
5523
Aaro Koskinen44b751b2010-12-20 23:50:17 +02005524 SiS_SetReg(SISCR, 0x59, v3);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07005525
5526 ptr = cs1a8;
5527 if(ivideo->haveXGIROM) {
5528 ptr = (const u8 *)&bios[0x1a8];
5529 }
5530 for(i = 0, j = 0; i < 3; i++, j += 8) {
Aaro Koskinen44b751b2010-12-20 23:50:17 +02005531 SiS_SetReg(SISCR, 0xc3 + i, ptr[j + regb]);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07005532 }
5533
5534 ptr = cs100;
5535 if(ivideo->haveXGIROM) {
5536 ptr = (const u8 *)&bios[0x100];
5537 }
5538 for(i = 0, j = 0; i < 2; i++, j += 8) {
Aaro Koskinen44b751b2010-12-20 23:50:17 +02005539 SiS_SetReg(SISCR, 0x8a + i, ptr[j + regb]);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07005540 }
5541
Aaro Koskinen44b751b2010-12-20 23:50:17 +02005542 SiS_SetReg(SISCR, 0xcf, v4);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07005543
Aaro Koskinen44b751b2010-12-20 23:50:17 +02005544 SiS_SetReg(SISCR, 0x83, 0x09);
5545 SiS_SetReg(SISCR, 0x87, 0x00);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07005546
5547 if(ivideo->chip == XGI_40) {
5548 if( (ivideo->revision_id == 1) ||
5549 (ivideo->revision_id == 2) ) {
Aaro Koskinen44b751b2010-12-20 23:50:17 +02005550 SiS_SetReg(SISCR, 0x8c, 0x87);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07005551 }
5552 }
5553
Aaro Koskinen42dea9032011-02-13 22:11:28 +00005554 if (regb == 1)
5555 SiS_SetReg(SISSR, 0x17, 0x80); /* DDR2 */
5556 else
5557 SiS_SetReg(SISSR, 0x17, 0x00); /* DDR1 */
Aaro Koskinen44b751b2010-12-20 23:50:17 +02005558 SiS_SetReg(SISSR, 0x1a, 0x87);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07005559
5560 if(ivideo->chip == XGI_20) {
Aaro Koskinen44b751b2010-12-20 23:50:17 +02005561 SiS_SetReg(SISSR, 0x15, 0x00);
5562 SiS_SetReg(SISSR, 0x1c, 0x00);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07005563 }
5564
Thomas Winischhofer544393f2005-09-09 13:04:45 -07005565 switch(ramtype) {
5566 case 0:
5567 sisfb_post_xgi_setclocks(ivideo, regb);
5568 if((ivideo->chip == XGI_20) ||
5569 (ivideo->revision_id == 1) ||
5570 (ivideo->revision_id == 2)) {
5571 v1 = cs158[regb]; v2 = cs160[regb]; v3 = cs168[regb];
5572 if(ivideo->haveXGIROM) {
5573 v1 = bios[regb + 0x158];
5574 v2 = bios[regb + 0x160];
5575 v3 = bios[regb + 0x168];
5576 }
Aaro Koskinen44b751b2010-12-20 23:50:17 +02005577 SiS_SetReg(SISCR, 0x82, v1);
5578 SiS_SetReg(SISCR, 0x85, v2);
5579 SiS_SetReg(SISCR, 0x86, v3);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07005580 } else {
Aaro Koskinen44b751b2010-12-20 23:50:17 +02005581 SiS_SetReg(SISCR, 0x82, 0x88);
5582 SiS_SetReg(SISCR, 0x86, 0x00);
Aaro Koskinene57d4132010-12-20 23:50:16 +02005583 reg = SiS_GetReg(SISCR, 0x86);
Aaro Koskinen44b751b2010-12-20 23:50:17 +02005584 SiS_SetReg(SISCR, 0x86, 0x88);
Aaro Koskinene57d4132010-12-20 23:50:16 +02005585 reg = SiS_GetReg(SISCR, 0x86);
Aaro Koskinen44b751b2010-12-20 23:50:17 +02005586 SiS_SetReg(SISCR, 0x86, bios[regb + 0x168]);
5587 SiS_SetReg(SISCR, 0x82, 0x77);
5588 SiS_SetReg(SISCR, 0x85, 0x00);
Aaro Koskinene57d4132010-12-20 23:50:16 +02005589 reg = SiS_GetReg(SISCR, 0x85);
Aaro Koskinen44b751b2010-12-20 23:50:17 +02005590 SiS_SetReg(SISCR, 0x85, 0x88);
Aaro Koskinene57d4132010-12-20 23:50:16 +02005591 reg = SiS_GetReg(SISCR, 0x85);
Aaro Koskinen44b751b2010-12-20 23:50:17 +02005592 SiS_SetReg(SISCR, 0x85, bios[regb + 0x160]);
5593 SiS_SetReg(SISCR, 0x82, bios[regb + 0x158]);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07005594 }
5595 if(ivideo->chip == XGI_40) {
Aaro Koskinen44b751b2010-12-20 23:50:17 +02005596 SiS_SetReg(SISCR, 0x97, 0x00);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07005597 }
Aaro Koskinen44b751b2010-12-20 23:50:17 +02005598 SiS_SetReg(SISCR, 0x98, 0x01);
5599 SiS_SetReg(SISCR, 0x9a, 0x02);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07005600
Aaro Koskinen44b751b2010-12-20 23:50:17 +02005601 SiS_SetReg(SISSR, 0x18, 0x01);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07005602 if((ivideo->chip == XGI_20) ||
5603 (ivideo->revision_id == 2)) {
Aaro Koskinen44b751b2010-12-20 23:50:17 +02005604 SiS_SetReg(SISSR, 0x19, 0x40);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07005605 } else {
Aaro Koskinen44b751b2010-12-20 23:50:17 +02005606 SiS_SetReg(SISSR, 0x19, 0x20);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07005607 }
Aaro Koskinen44b751b2010-12-20 23:50:17 +02005608 SiS_SetReg(SISSR, 0x16, 0x00);
5609 SiS_SetReg(SISSR, 0x16, 0x80);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07005610 if((ivideo->chip == XGI_20) || (bios[0x1cb] != 0x0c)) {
5611 sisfb_post_xgi_delay(ivideo, 0x43);
5612 sisfb_post_xgi_delay(ivideo, 0x43);
5613 sisfb_post_xgi_delay(ivideo, 0x43);
Aaro Koskinen44b751b2010-12-20 23:50:17 +02005614 SiS_SetReg(SISSR, 0x18, 0x00);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07005615 if((ivideo->chip == XGI_20) ||
5616 (ivideo->revision_id == 2)) {
Aaro Koskinen44b751b2010-12-20 23:50:17 +02005617 SiS_SetReg(SISSR, 0x19, 0x40);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07005618 } else {
Aaro Koskinen44b751b2010-12-20 23:50:17 +02005619 SiS_SetReg(SISSR, 0x19, 0x20);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07005620 }
5621 } else if((ivideo->chip == XGI_40) && (bios[0x1cb] == 0x0c)) {
Aaro Koskinen44b751b2010-12-20 23:50:17 +02005622 /* SiS_SetReg(SISSR, 0x16, 0x0c); */ /* ? */
Thomas Winischhofer544393f2005-09-09 13:04:45 -07005623 }
Aaro Koskinen44b751b2010-12-20 23:50:17 +02005624 SiS_SetReg(SISSR, 0x16, 0x00);
5625 SiS_SetReg(SISSR, 0x16, 0x80);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07005626 sisfb_post_xgi_delay(ivideo, 4);
5627 v1 = 0x31; v2 = 0x03; v3 = 0x83; v4 = 0x03; v5 = 0x83;
5628 if(ivideo->haveXGIROM) {
5629 v1 = bios[0xf0];
5630 index = (ivideo->chip == XGI_20) ? 0x4b2 : 0x53e;
5631 v2 = bios[index];
5632 v3 = bios[index + 1];
5633 v4 = bios[index + 2];
5634 v5 = bios[index + 3];
5635 }
Aaro Koskinen44b751b2010-12-20 23:50:17 +02005636 SiS_SetReg(SISSR, 0x18, v1);
5637 SiS_SetReg(SISSR, 0x19, ((ivideo->chip == XGI_20) ? 0x02 : 0x01));
5638 SiS_SetReg(SISSR, 0x16, v2);
5639 SiS_SetReg(SISSR, 0x16, v3);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07005640 sisfb_post_xgi_delay(ivideo, 0x43);
Aaro Koskinen44b751b2010-12-20 23:50:17 +02005641 SiS_SetReg(SISSR, 0x1b, 0x03);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07005642 sisfb_post_xgi_delay(ivideo, 0x22);
Aaro Koskinen44b751b2010-12-20 23:50:17 +02005643 SiS_SetReg(SISSR, 0x18, v1);
5644 SiS_SetReg(SISSR, 0x19, 0x00);
5645 SiS_SetReg(SISSR, 0x16, v4);
5646 SiS_SetReg(SISSR, 0x16, v5);
5647 SiS_SetReg(SISSR, 0x1b, 0x00);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07005648 break;
5649 case 1:
Aaro Koskinenc9982d52011-02-13 22:11:27 +00005650 sisfb_post_xgi_ddr2(ivideo, regb);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07005651 break;
5652 default:
5653 sisfb_post_xgi_setclocks(ivideo, regb);
5654 if((ivideo->chip == XGI_40) &&
5655 ((ivideo->revision_id == 1) ||
5656 (ivideo->revision_id == 2))) {
Aaro Koskinen44b751b2010-12-20 23:50:17 +02005657 SiS_SetReg(SISCR, 0x82, bios[regb + 0x158]);
5658 SiS_SetReg(SISCR, 0x85, bios[regb + 0x160]);
5659 SiS_SetReg(SISCR, 0x86, bios[regb + 0x168]);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07005660 } else {
Aaro Koskinen44b751b2010-12-20 23:50:17 +02005661 SiS_SetReg(SISCR, 0x82, 0x88);
5662 SiS_SetReg(SISCR, 0x86, 0x00);
Aaro Koskinene57d4132010-12-20 23:50:16 +02005663 reg = SiS_GetReg(SISCR, 0x86);
Aaro Koskinen44b751b2010-12-20 23:50:17 +02005664 SiS_SetReg(SISCR, 0x86, 0x88);
5665 SiS_SetReg(SISCR, 0x82, 0x77);
5666 SiS_SetReg(SISCR, 0x85, 0x00);
Aaro Koskinene57d4132010-12-20 23:50:16 +02005667 reg = SiS_GetReg(SISCR, 0x85);
Aaro Koskinen44b751b2010-12-20 23:50:17 +02005668 SiS_SetReg(SISCR, 0x85, 0x88);
Aaro Koskinene57d4132010-12-20 23:50:16 +02005669 reg = SiS_GetReg(SISCR, 0x85);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07005670 v1 = cs160[regb]; v2 = cs158[regb];
5671 if(ivideo->haveXGIROM) {
5672 v1 = bios[regb + 0x160];
5673 v2 = bios[regb + 0x158];
5674 }
Aaro Koskinen44b751b2010-12-20 23:50:17 +02005675 SiS_SetReg(SISCR, 0x85, v1);
5676 SiS_SetReg(SISCR, 0x82, v2);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07005677 }
5678 if(ivideo->chip == XGI_40) {
Aaro Koskinen44b751b2010-12-20 23:50:17 +02005679 SiS_SetReg(SISCR, 0x97, 0x11);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07005680 }
5681 if((ivideo->chip == XGI_40) && (ivideo->revision_id == 2)) {
Aaro Koskinen44b751b2010-12-20 23:50:17 +02005682 SiS_SetReg(SISCR, 0x98, 0x01);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07005683 } else {
Aaro Koskinen44b751b2010-12-20 23:50:17 +02005684 SiS_SetReg(SISCR, 0x98, 0x03);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07005685 }
Aaro Koskinen44b751b2010-12-20 23:50:17 +02005686 SiS_SetReg(SISCR, 0x9a, 0x02);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07005687
5688 if(ivideo->chip == XGI_40) {
Aaro Koskinen44b751b2010-12-20 23:50:17 +02005689 SiS_SetReg(SISSR, 0x18, 0x01);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07005690 } else {
Aaro Koskinen44b751b2010-12-20 23:50:17 +02005691 SiS_SetReg(SISSR, 0x18, 0x00);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07005692 }
Aaro Koskinen44b751b2010-12-20 23:50:17 +02005693 SiS_SetReg(SISSR, 0x19, 0x40);
5694 SiS_SetReg(SISSR, 0x16, 0x00);
5695 SiS_SetReg(SISSR, 0x16, 0x80);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07005696 if((ivideo->chip == XGI_40) && (bios[0x1cb] != 0x0c)) {
5697 sisfb_post_xgi_delay(ivideo, 0x43);
5698 sisfb_post_xgi_delay(ivideo, 0x43);
5699 sisfb_post_xgi_delay(ivideo, 0x43);
Aaro Koskinen44b751b2010-12-20 23:50:17 +02005700 SiS_SetReg(SISSR, 0x18, 0x00);
5701 SiS_SetReg(SISSR, 0x19, 0x40);
5702 SiS_SetReg(SISSR, 0x16, 0x00);
5703 SiS_SetReg(SISSR, 0x16, 0x80);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07005704 }
5705 sisfb_post_xgi_delay(ivideo, 4);
5706 v1 = 0x31;
5707 if(ivideo->haveXGIROM) {
5708 v1 = bios[0xf0];
5709 }
Aaro Koskinen44b751b2010-12-20 23:50:17 +02005710 SiS_SetReg(SISSR, 0x18, v1);
5711 SiS_SetReg(SISSR, 0x19, 0x01);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07005712 if(ivideo->chip == XGI_40) {
Aaro Koskinen44b751b2010-12-20 23:50:17 +02005713 SiS_SetReg(SISSR, 0x16, bios[0x53e]);
5714 SiS_SetReg(SISSR, 0x16, bios[0x53f]);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07005715 } else {
Aaro Koskinen44b751b2010-12-20 23:50:17 +02005716 SiS_SetReg(SISSR, 0x16, 0x05);
5717 SiS_SetReg(SISSR, 0x16, 0x85);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07005718 }
5719 sisfb_post_xgi_delay(ivideo, 0x43);
5720 if(ivideo->chip == XGI_40) {
Aaro Koskinen44b751b2010-12-20 23:50:17 +02005721 SiS_SetReg(SISSR, 0x1b, 0x01);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07005722 } else {
Aaro Koskinen44b751b2010-12-20 23:50:17 +02005723 SiS_SetReg(SISSR, 0x1b, 0x03);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07005724 }
5725 sisfb_post_xgi_delay(ivideo, 0x22);
Aaro Koskinen44b751b2010-12-20 23:50:17 +02005726 SiS_SetReg(SISSR, 0x18, v1);
5727 SiS_SetReg(SISSR, 0x19, 0x00);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07005728 if(ivideo->chip == XGI_40) {
Aaro Koskinen44b751b2010-12-20 23:50:17 +02005729 SiS_SetReg(SISSR, 0x16, bios[0x540]);
5730 SiS_SetReg(SISSR, 0x16, bios[0x541]);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07005731 } else {
Aaro Koskinen44b751b2010-12-20 23:50:17 +02005732 SiS_SetReg(SISSR, 0x16, 0x05);
5733 SiS_SetReg(SISSR, 0x16, 0x85);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07005734 }
Aaro Koskinen44b751b2010-12-20 23:50:17 +02005735 SiS_SetReg(SISSR, 0x1b, 0x00);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07005736 }
5737
5738 regb = 0; /* ! */
5739 v1 = 0x03;
5740 if(ivideo->haveXGIROM) {
5741 v1 = bios[0x110 + regb];
5742 }
Aaro Koskinen44b751b2010-12-20 23:50:17 +02005743 SiS_SetReg(SISSR, 0x1b, v1);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07005744
5745 /* RAM size */
5746 v1 = 0x00; v2 = 0x00;
5747 if(ivideo->haveXGIROM) {
5748 v1 = bios[0x62];
5749 v2 = bios[0x63];
5750 }
5751 regb = 0; /* ! */
5752 regd = 1 << regb;
5753 if((v1 & 0x40) && (v2 & regd) && ivideo->haveXGIROM) {
5754
Aaro Koskinen44b751b2010-12-20 23:50:17 +02005755 SiS_SetReg(SISSR, 0x13, bios[regb + 0xe0]);
5756 SiS_SetReg(SISSR, 0x14, bios[regb + 0xe0 + 8]);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07005757
5758 } else {
Aaro Koskinen83ea0f12011-02-13 22:11:23 +00005759 int err;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07005760
5761 /* Set default mode, don't clear screen */
Richard Knutssonc30660ea2007-02-12 00:55:06 -08005762 ivideo->SiS_Pr.SiS_UseOEM = false;
5763 SiS_SetEnableDstn(&ivideo->SiS_Pr, false);
5764 SiS_SetEnableFstn(&ivideo->SiS_Pr, false);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07005765 ivideo->curFSTN = ivideo->curDSTN = 0;
5766 ivideo->SiS_Pr.VideoMemorySize = 8 << 20;
5767 SiSSetMode(&ivideo->SiS_Pr, 0x2e | 0x80);
5768
Aaro Koskinen44b751b2010-12-20 23:50:17 +02005769 SiS_SetReg(SISSR, 0x05, 0x86);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07005770
5771 /* Disable read-cache */
Aaro Koskinen667a8b42010-12-20 23:50:19 +02005772 SiS_SetRegAND(SISSR, 0x21, 0xdf);
Aaro Koskinen83ea0f12011-02-13 22:11:23 +00005773 err = sisfb_post_xgi_ramsize(ivideo);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07005774 /* Enable read-cache */
Aaro Koskinen27799d62010-12-20 23:50:18 +02005775 SiS_SetRegOR(SISSR, 0x21, 0x20);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07005776
Aaro Koskinen83ea0f12011-02-13 22:11:23 +00005777 if (err) {
5778 dev_err(&pdev->dev,
5779 "%s: RAM size detection failed: %d\n",
5780 __func__, err);
5781 return 0;
5782 }
Thomas Winischhofer544393f2005-09-09 13:04:45 -07005783 }
5784
5785#if 0
5786 printk(KERN_DEBUG "-----------------\n");
5787 for(i = 0; i < 0xff; i++) {
Aaro Koskinene57d4132010-12-20 23:50:16 +02005788 reg = SiS_GetReg(SISCR, i);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07005789 printk(KERN_DEBUG "CR%02x(%x) = 0x%02x\n", i, SISCR, reg);
5790 }
5791 for(i = 0; i < 0x40; i++) {
Aaro Koskinene57d4132010-12-20 23:50:16 +02005792 reg = SiS_GetReg(SISSR, i);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07005793 printk(KERN_DEBUG "SR%02x(%x) = 0x%02x\n", i, SISSR, reg);
5794 }
5795 printk(KERN_DEBUG "-----------------\n");
5796#endif
5797
5798 /* Sense CRT1 */
5799 if(ivideo->chip == XGI_20) {
Aaro Koskinen27799d62010-12-20 23:50:18 +02005800 SiS_SetRegOR(SISCR, 0x32, 0x20);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07005801 } else {
Aaro Koskinene57d4132010-12-20 23:50:16 +02005802 reg = SiS_GetReg(SISPART4, 0x00);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07005803 if((reg == 1) || (reg == 2)) {
5804 sisfb_sense_crt1(ivideo);
5805 } else {
Aaro Koskinen27799d62010-12-20 23:50:18 +02005806 SiS_SetRegOR(SISCR, 0x32, 0x20);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07005807 }
5808 }
5809
5810 /* Set default mode, don't clear screen */
Richard Knutssonc30660ea2007-02-12 00:55:06 -08005811 ivideo->SiS_Pr.SiS_UseOEM = false;
5812 SiS_SetEnableDstn(&ivideo->SiS_Pr, false);
5813 SiS_SetEnableFstn(&ivideo->SiS_Pr, false);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07005814 ivideo->curFSTN = ivideo->curDSTN = 0;
5815 SiSSetMode(&ivideo->SiS_Pr, 0x2e | 0x80);
5816
Aaro Koskinen44b751b2010-12-20 23:50:17 +02005817 SiS_SetReg(SISSR, 0x05, 0x86);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07005818
5819 /* Display off */
Aaro Koskinen27799d62010-12-20 23:50:18 +02005820 SiS_SetRegOR(SISSR, 0x01, 0x20);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07005821
5822 /* Save mode number in CR34 */
Aaro Koskinen44b751b2010-12-20 23:50:17 +02005823 SiS_SetReg(SISCR, 0x34, 0x2e);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07005824
5825 /* Let everyone know what the current mode is */
5826 ivideo->modeprechange = 0x2e;
5827
5828 if(ivideo->chip == XGI_40) {
Aaro Koskinene57d4132010-12-20 23:50:16 +02005829 reg = SiS_GetReg(SISCR, 0xca);
5830 v1 = SiS_GetReg(SISCR, 0xcc);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07005831 if((reg & 0x10) && (!(v1 & 0x04))) {
5832 printk(KERN_ERR
5833 "sisfb: Please connect power to the card.\n");
5834 return 0;
5835 }
5836 }
5837
5838 return 1;
5839}
5840#endif
5841
5842static int __devinit
5843sisfb_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
5844{
5845 struct sisfb_chip_info *chipinfo = &sisfb_chip_info[ent->driver_data];
5846 struct sis_video_info *ivideo = NULL;
5847 struct fb_info *sis_fb_info = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005848 u16 reg16;
5849 u8 reg;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07005850 int i, ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005851
Thomas Winischhofer544393f2005-09-09 13:04:45 -07005852 if(sisfb_off)
5853 return -ENXIO;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005854
Linus Torvalds1da177e2005-04-16 15:20:36 -07005855 sis_fb_info = framebuffer_alloc(sizeof(*ivideo), &pdev->dev);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07005856 if(!sis_fb_info)
5857 return -ENOMEM;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005858
5859 ivideo = (struct sis_video_info *)sis_fb_info->par;
5860 ivideo->memyselfandi = sis_fb_info;
5861
Thomas Winischhofer544393f2005-09-09 13:04:45 -07005862 ivideo->sisfb_id = SISFB_ID;
5863
Linus Torvalds1da177e2005-04-16 15:20:36 -07005864 if(card_list == NULL) {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07005865 ivideo->cardnumber = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005866 } else {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07005867 struct sis_video_info *countvideo = card_list;
5868 ivideo->cardnumber = 1;
Harvey Harrison5e2daeb2008-05-22 15:45:08 -07005869 while((countvideo = countvideo->next) != NULL)
Thomas Winischhofer544393f2005-09-09 13:04:45 -07005870 ivideo->cardnumber++;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005871 }
5872
5873 strncpy(ivideo->myid, chipinfo->chip_name, 30);
5874
5875 ivideo->warncount = 0;
5876 ivideo->chip_id = pdev->device;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07005877 ivideo->chip_vendor = pdev->vendor;
Auke Kok44c10132007-06-08 15:46:36 -07005878 ivideo->revision_id = pdev->revision;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07005879 ivideo->SiS_Pr.ChipRevision = ivideo->revision_id;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005880 pci_read_config_word(pdev, PCI_COMMAND, &reg16);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07005881 ivideo->sisvga_enabled = reg16 & 0x01;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005882 ivideo->pcibus = pdev->bus->number;
5883 ivideo->pcislot = PCI_SLOT(pdev->devfn);
5884 ivideo->pcifunc = PCI_FUNC(pdev->devfn);
5885 ivideo->subsysvendor = pdev->subsystem_vendor;
5886 ivideo->subsysdevice = pdev->subsystem_device;
5887
5888#ifndef MODULE
5889 if(sisfb_mode_idx == -1) {
5890 sisfb_get_vga_mode_from_kernel();
5891 }
5892#endif
5893
5894 ivideo->chip = chipinfo->chip;
Aaro Koskinen929c9722011-02-13 22:11:25 +00005895 ivideo->chip_real_id = chipinfo->chip;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005896 ivideo->sisvga_engine = chipinfo->vgaengine;
5897 ivideo->hwcursor_size = chipinfo->hwcursor_size;
5898 ivideo->CRT2_write_enable = chipinfo->CRT2_write_enable;
5899 ivideo->mni = chipinfo->mni;
5900
5901 ivideo->detectedpdc = 0xff;
5902 ivideo->detectedpdca = 0xff;
5903 ivideo->detectedlcda = 0xff;
5904
Richard Knutssonc30660ea2007-02-12 00:55:06 -08005905 ivideo->sisfb_thismonitor.datavalid = false;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005906
Thomas Winischhofer544393f2005-09-09 13:04:45 -07005907 ivideo->current_base = 0;
5908
5909 ivideo->engineok = 0;
5910
5911 ivideo->sisfb_was_boot_device = 0;
Adrian Bunk14aefd12008-07-23 21:31:12 -07005912
Thomas Winischhofer544393f2005-09-09 13:04:45 -07005913 if(pdev->resource[PCI_ROM_RESOURCE].flags & IORESOURCE_ROM_SHADOW) {
5914 if(ivideo->sisvga_enabled)
5915 ivideo->sisfb_was_boot_device = 1;
5916 else {
5917 printk(KERN_DEBUG "sisfb: PCI device is disabled, "
5918 "but marked as boot video device ???\n");
5919 printk(KERN_DEBUG "sisfb: I will not accept this "
5920 "as the primary VGA device\n");
5921 }
5922 }
Thomas Winischhofer544393f2005-09-09 13:04:45 -07005923
Linus Torvalds1da177e2005-04-16 15:20:36 -07005924 ivideo->sisfb_parm_mem = sisfb_parm_mem;
5925 ivideo->sisfb_accel = sisfb_accel;
5926 ivideo->sisfb_ypan = sisfb_ypan;
5927 ivideo->sisfb_max = sisfb_max;
5928 ivideo->sisfb_userom = sisfb_userom;
5929 ivideo->sisfb_useoem = sisfb_useoem;
5930 ivideo->sisfb_mode_idx = sisfb_mode_idx;
5931 ivideo->sisfb_parm_rate = sisfb_parm_rate;
5932 ivideo->sisfb_crt1off = sisfb_crt1off;
5933 ivideo->sisfb_forcecrt1 = sisfb_forcecrt1;
5934 ivideo->sisfb_crt2type = sisfb_crt2type;
5935 ivideo->sisfb_crt2flags = sisfb_crt2flags;
5936 /* pdc(a), scalelcd, special timing, lvdshl handled below */
5937 ivideo->sisfb_dstn = sisfb_dstn;
5938 ivideo->sisfb_fstn = sisfb_fstn;
5939 ivideo->sisfb_tvplug = sisfb_tvplug;
5940 ivideo->sisfb_tvstd = sisfb_tvstd;
5941 ivideo->tvxpos = sisfb_tvxposoffset;
5942 ivideo->tvypos = sisfb_tvyposoffset;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005943 ivideo->sisfb_nocrt2rate = sisfb_nocrt2rate;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005944 ivideo->refresh_rate = 0;
5945 if(ivideo->sisfb_parm_rate != -1) {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07005946 ivideo->refresh_rate = ivideo->sisfb_parm_rate;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005947 }
5948
5949 ivideo->SiS_Pr.UsePanelScaler = sisfb_scalelcd;
5950 ivideo->SiS_Pr.CenterScreen = -1;
5951 ivideo->SiS_Pr.SiS_CustomT = sisfb_specialtiming;
5952 ivideo->SiS_Pr.LVDSHL = sisfb_lvdshl;
5953
5954 ivideo->SiS_Pr.SiS_Backup70xx = 0xff;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07005955 ivideo->SiS_Pr.SiS_CHOverScan = -1;
Richard Knutssonc30660ea2007-02-12 00:55:06 -08005956 ivideo->SiS_Pr.SiS_ChSW = false;
5957 ivideo->SiS_Pr.SiS_UseLCDA = false;
5958 ivideo->SiS_Pr.HaveEMI = false;
5959 ivideo->SiS_Pr.HaveEMILCD = false;
5960 ivideo->SiS_Pr.OverruleEMI = false;
5961 ivideo->SiS_Pr.SiS_SensibleSR11 = false;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005962 ivideo->SiS_Pr.SiS_MyCR63 = 0x63;
5963 ivideo->SiS_Pr.PDC = -1;
5964 ivideo->SiS_Pr.PDCA = -1;
Richard Knutssonc30660ea2007-02-12 00:55:06 -08005965 ivideo->SiS_Pr.DDCPortMixup = false;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005966#ifdef CONFIG_FB_SIS_315
5967 if(ivideo->chip >= SIS_330) {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07005968 ivideo->SiS_Pr.SiS_MyCR63 = 0x53;
5969 if(ivideo->chip >= SIS_661) {
Richard Knutssonc30660ea2007-02-12 00:55:06 -08005970 ivideo->SiS_Pr.SiS_SensibleSR11 = true;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07005971 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07005972 }
5973#endif
5974
5975 memcpy(&ivideo->default_var, &my_default_var, sizeof(my_default_var));
5976
5977 pci_set_drvdata(pdev, ivideo);
5978
5979 /* Patch special cases */
5980 if((ivideo->nbridge = sisfb_get_northbridge(ivideo->chip))) {
5981 switch(ivideo->nbridge->device) {
5982#ifdef CONFIG_FB_SIS_300
5983 case PCI_DEVICE_ID_SI_730:
Thomas Winischhofer544393f2005-09-09 13:04:45 -07005984 ivideo->chip = SIS_730;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005985 strcpy(ivideo->myid, "SiS 730");
Thomas Winischhofer544393f2005-09-09 13:04:45 -07005986 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005987#endif
5988#ifdef CONFIG_FB_SIS_315
5989 case PCI_DEVICE_ID_SI_651:
5990 /* ivideo->chip is ok */
5991 strcpy(ivideo->myid, "SiS 651");
5992 break;
5993 case PCI_DEVICE_ID_SI_740:
Thomas Winischhofer544393f2005-09-09 13:04:45 -07005994 ivideo->chip = SIS_740;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005995 strcpy(ivideo->myid, "SiS 740");
5996 break;
5997 case PCI_DEVICE_ID_SI_661:
Thomas Winischhofer544393f2005-09-09 13:04:45 -07005998 ivideo->chip = SIS_661;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005999 strcpy(ivideo->myid, "SiS 661");
6000 break;
6001 case PCI_DEVICE_ID_SI_741:
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006002 ivideo->chip = SIS_741;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006003 strcpy(ivideo->myid, "SiS 741");
6004 break;
6005 case PCI_DEVICE_ID_SI_760:
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006006 ivideo->chip = SIS_760;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006007 strcpy(ivideo->myid, "SiS 760");
6008 break;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006009 case PCI_DEVICE_ID_SI_761:
6010 ivideo->chip = SIS_761;
6011 strcpy(ivideo->myid, "SiS 761");
6012 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006013#endif
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006014 default:
6015 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006016 }
6017 }
6018
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006019 ivideo->SiS_Pr.ChipType = ivideo->chip;
6020
6021 ivideo->SiS_Pr.ivideo = (void *)ivideo;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006022
6023#ifdef CONFIG_FB_SIS_315
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006024 if((ivideo->SiS_Pr.ChipType == SIS_315PRO) ||
6025 (ivideo->SiS_Pr.ChipType == SIS_315)) {
6026 ivideo->SiS_Pr.ChipType = SIS_315H;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006027 }
6028#endif
6029
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006030 if(!ivideo->sisvga_enabled) {
6031 if(pci_enable_device(pdev)) {
Adrian Bunk0959f0c2007-05-08 00:39:50 -07006032 if(ivideo->nbridge) pci_dev_put(ivideo->nbridge);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006033 pci_set_drvdata(pdev, NULL);
Krzysztof Helt491bcc92009-06-16 15:34:36 -07006034 framebuffer_release(sis_fb_info);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006035 return -EIO;
6036 }
6037 }
6038
Linus Torvalds1da177e2005-04-16 15:20:36 -07006039 ivideo->video_base = pci_resource_start(pdev, 0);
Aaro Koskinen32ed3032010-11-10 13:04:19 +02006040 ivideo->video_size = pci_resource_len(pdev, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006041 ivideo->mmio_base = pci_resource_start(pdev, 1);
6042 ivideo->mmio_size = pci_resource_len(pdev, 1);
6043 ivideo->SiS_Pr.RelIO = pci_resource_start(pdev, 2) + 0x30;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006044 ivideo->SiS_Pr.IOAddress = ivideo->vga_base = ivideo->SiS_Pr.RelIO;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006045
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006046 SiSRegInit(&ivideo->SiS_Pr, ivideo->SiS_Pr.IOAddress);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006047
6048#ifdef CONFIG_FB_SIS_300
6049 /* Find PCI systems for Chrontel/GPIO communication setup */
6050 if(ivideo->chip == SIS_630) {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006051 i = 0;
6052 do {
6053 if(mychswtable[i].subsysVendor == ivideo->subsysvendor &&
6054 mychswtable[i].subsysCard == ivideo->subsysdevice) {
Richard Knutssonc30660ea2007-02-12 00:55:06 -08006055 ivideo->SiS_Pr.SiS_ChSW = true;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006056 printk(KERN_DEBUG "sisfb: Identified [%s %s] "
6057 "requiring Chrontel/GPIO setup\n",
6058 mychswtable[i].vendorName,
6059 mychswtable[i].cardName);
Adrian Bunk0959f0c2007-05-08 00:39:50 -07006060 ivideo->lpcdev = pci_get_device(PCI_VENDOR_ID_SI, 0x0008, NULL);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006061 break;
6062 }
6063 i++;
6064 } while(mychswtable[i].subsysVendor != 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006065 }
6066#endif
6067
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006068#ifdef CONFIG_FB_SIS_315
6069 if((ivideo->chip == SIS_760) && (ivideo->nbridge)) {
Adrian Bunk0959f0c2007-05-08 00:39:50 -07006070 ivideo->lpcdev = pci_get_slot(ivideo->nbridge->bus, (2 << 3));
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006071 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07006072#endif
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006073
Aaro Koskinen44b751b2010-12-20 23:50:17 +02006074 SiS_SetReg(SISSR, 0x05, 0x86);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006075
6076 if( (!ivideo->sisvga_enabled)
6077#if !defined(__i386__) && !defined(__x86_64__)
6078 || (sisfb_resetcard)
6079#endif
6080 ) {
6081 for(i = 0x30; i <= 0x3f; i++) {
Aaro Koskinen44b751b2010-12-20 23:50:17 +02006082 SiS_SetReg(SISCR, i, 0x00);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006083 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07006084 }
6085
6086 /* Find out about current video mode */
6087 ivideo->modeprechange = 0x03;
Aaro Koskinene57d4132010-12-20 23:50:16 +02006088 reg = SiS_GetReg(SISCR, 0x34);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006089 if(reg & 0x7f) {
6090 ivideo->modeprechange = reg & 0x7f;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006091 } else if(ivideo->sisvga_enabled) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07006092#if defined(__i386__) || defined(__x86_64__)
Adrian Bunk14aefd12008-07-23 21:31:12 -07006093 unsigned char __iomem *tt = ioremap(0x400, 0x100);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006094 if(tt) {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006095 ivideo->modeprechange = readb(tt + 0x49);
6096 iounmap(tt);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006097 }
6098#endif
6099 }
6100
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006101 /* Search and copy ROM image */
6102 ivideo->bios_abase = NULL;
6103 ivideo->SiS_Pr.VirtualRomBase = NULL;
Richard Knutssonc30660ea2007-02-12 00:55:06 -08006104 ivideo->SiS_Pr.UseROM = false;
6105 ivideo->haveXGIROM = ivideo->SiS_Pr.SiS_XGIROM = false;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006106 if(ivideo->sisfb_userom) {
6107 ivideo->SiS_Pr.VirtualRomBase = sisfb_find_rom(pdev);
6108 ivideo->bios_abase = ivideo->SiS_Pr.VirtualRomBase;
Richard Knutssonc30660ea2007-02-12 00:55:06 -08006109 ivideo->SiS_Pr.UseROM = (bool)(ivideo->SiS_Pr.VirtualRomBase);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006110 printk(KERN_INFO "sisfb: Video ROM %sfound\n",
6111 ivideo->SiS_Pr.UseROM ? "" : "not ");
6112 if((ivideo->SiS_Pr.UseROM) && (ivideo->chip >= XGI_20)) {
Richard Knutssonc30660ea2007-02-12 00:55:06 -08006113 ivideo->SiS_Pr.UseROM = false;
6114 ivideo->haveXGIROM = ivideo->SiS_Pr.SiS_XGIROM = true;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006115 if( (ivideo->revision_id == 2) &&
6116 (!(ivideo->bios_abase[0x1d1] & 0x01)) ) {
Richard Knutssonc30660ea2007-02-12 00:55:06 -08006117 ivideo->SiS_Pr.DDCPortMixup = true;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006118 }
6119 }
6120 } else {
6121 printk(KERN_INFO "sisfb: Video ROM usage disabled\n");
6122 }
6123
6124 /* Find systems for special custom timing */
6125 if(ivideo->SiS_Pr.SiS_CustomT == CUT_NONE) {
6126 sisfb_detect_custom_timing(ivideo);
6127 }
6128
Aaro Koskinen929c9722011-02-13 22:11:25 +00006129#ifdef CONFIG_FB_SIS_315
6130 if (ivideo->chip == XGI_20) {
6131 /* Check if our Z7 chip is actually Z9 */
6132 SiS_SetRegOR(SISCR, 0x4a, 0x40); /* GPIOG EN */
6133 reg = SiS_GetReg(SISCR, 0x48);
6134 if (reg & 0x02) { /* GPIOG */
6135 ivideo->chip_real_id = XGI_21;
6136 dev_info(&pdev->dev, "Z9 detected\n");
6137 }
6138 }
6139#endif
6140
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006141 /* POST card in case this has not been done by the BIOS */
6142 if( (!ivideo->sisvga_enabled)
6143#if !defined(__i386__) && !defined(__x86_64__)
6144 || (sisfb_resetcard)
6145#endif
6146 ) {
6147#ifdef CONFIG_FB_SIS_300
6148 if(ivideo->sisvga_engine == SIS_300_VGA) {
6149 if(ivideo->chip == SIS_300) {
6150 sisfb_post_sis300(pdev);
6151 ivideo->sisfb_can_post = 1;
6152 }
6153 }
6154#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -07006155
6156#ifdef CONFIG_FB_SIS_315
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006157 if(ivideo->sisvga_engine == SIS_315_VGA) {
6158 int result = 1;
6159 /* if((ivideo->chip == SIS_315H) ||
Linus Torvalds1da177e2005-04-16 15:20:36 -07006160 (ivideo->chip == SIS_315) ||
6161 (ivideo->chip == SIS_315PRO) ||
6162 (ivideo->chip == SIS_330)) {
6163 sisfb_post_sis315330(pdev);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006164 } else */ if(ivideo->chip == XGI_20) {
6165 result = sisfb_post_xgi(pdev);
6166 ivideo->sisfb_can_post = 1;
6167 } else if((ivideo->chip == XGI_40) && ivideo->haveXGIROM) {
6168 result = sisfb_post_xgi(pdev);
6169 ivideo->sisfb_can_post = 1;
6170 } else {
6171 printk(KERN_INFO "sisfb: Card is not "
6172 "POSTed and sisfb can't do this either.\n");
6173 }
6174 if(!result) {
6175 printk(KERN_ERR "sisfb: Failed to POST card\n");
6176 ret = -ENODEV;
6177 goto error_3;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006178 }
6179 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07006180#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -07006181 }
6182
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006183 ivideo->sisfb_card_posted = 1;
6184
6185 /* Find out about RAM size */
6186 if(sisfb_get_dram_size(ivideo)) {
6187 printk(KERN_INFO "sisfb: Fatal error: Unable to determine VRAM size.\n");
6188 ret = -ENODEV;
6189 goto error_3;
6190 }
6191
6192
6193 /* Enable PCI addressing and MMIO */
Linus Torvalds1da177e2005-04-16 15:20:36 -07006194 if((ivideo->sisfb_mode_idx < 0) ||
6195 ((sisbios_mode[ivideo->sisfb_mode_idx].mode_no[ivideo->mni]) != 0xFF)) {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006196 /* Enable PCI_LINEAR_ADDRESSING and MMIO_ENABLE */
Aaro Koskinen27799d62010-12-20 23:50:18 +02006197 SiS_SetRegOR(SISSR, IND_SIS_PCI_ADDRESS_SET, (SIS_PCI_ADDR_ENABLE | SIS_MEM_MAP_IO_ENABLE));
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006198 /* Enable 2D accelerator engine */
Aaro Koskinen27799d62010-12-20 23:50:18 +02006199 SiS_SetRegOR(SISSR, IND_SIS_MODULE_ENABLE, SIS_ENABLE_2D);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006200 }
6201
6202 if(sisfb_pdc != 0xff) {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006203 if(ivideo->sisvga_engine == SIS_300_VGA)
6204 sisfb_pdc &= 0x3c;
6205 else
6206 sisfb_pdc &= 0x1f;
6207 ivideo->SiS_Pr.PDC = sisfb_pdc;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006208 }
6209#ifdef CONFIG_FB_SIS_315
6210 if(ivideo->sisvga_engine == SIS_315_VGA) {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006211 if(sisfb_pdca != 0xff)
6212 ivideo->SiS_Pr.PDCA = sisfb_pdca & 0x1f;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006213 }
6214#endif
6215
6216 if(!request_mem_region(ivideo->video_base, ivideo->video_size, "sisfb FB")) {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006217 printk(KERN_ERR "sisfb: Fatal error: Unable to reserve %dMB framebuffer memory\n",
6218 (int)(ivideo->video_size >> 20));
Linus Torvalds1da177e2005-04-16 15:20:36 -07006219 printk(KERN_ERR "sisfb: Is there another framebuffer driver active?\n");
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006220 ret = -ENODEV;
6221 goto error_3;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006222 }
6223
6224 if(!request_mem_region(ivideo->mmio_base, ivideo->mmio_size, "sisfb MMIO")) {
6225 printk(KERN_ERR "sisfb: Fatal error: Unable to reserve MMIO region\n");
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006226 ret = -ENODEV;
6227 goto error_2;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006228 }
6229
6230 ivideo->video_vbase = ioremap(ivideo->video_base, ivideo->video_size);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006231 ivideo->SiS_Pr.VideoMemoryAddress = ivideo->video_vbase;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006232 if(!ivideo->video_vbase) {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006233 printk(KERN_ERR "sisfb: Fatal error: Unable to map framebuffer memory\n");
6234 ret = -ENODEV;
6235 goto error_1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006236 }
6237
6238 ivideo->mmio_vbase = ioremap(ivideo->mmio_base, ivideo->mmio_size);
6239 if(!ivideo->mmio_vbase) {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006240 printk(KERN_ERR "sisfb: Fatal error: Unable to map MMIO region\n");
6241 ret = -ENODEV;
6242error_0: iounmap(ivideo->video_vbase);
6243error_1: release_mem_region(ivideo->video_base, ivideo->video_size);
6244error_2: release_mem_region(ivideo->mmio_base, ivideo->mmio_size);
6245error_3: vfree(ivideo->bios_abase);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006246 if(ivideo->lpcdev)
Adrian Bunk0959f0c2007-05-08 00:39:50 -07006247 pci_dev_put(ivideo->lpcdev);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006248 if(ivideo->nbridge)
Adrian Bunk0959f0c2007-05-08 00:39:50 -07006249 pci_dev_put(ivideo->nbridge);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006250 pci_set_drvdata(pdev, NULL);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006251 if(!ivideo->sisvga_enabled)
6252 pci_disable_device(pdev);
Krzysztof Helt491bcc92009-06-16 15:34:36 -07006253 framebuffer_release(sis_fb_info);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006254 return ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006255 }
6256
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006257 printk(KERN_INFO "sisfb: Video RAM at 0x%lx, mapped to 0x%lx, size %ldk\n",
6258 ivideo->video_base, (unsigned long)ivideo->video_vbase, ivideo->video_size / 1024);
6259
6260 if(ivideo->video_offset) {
6261 printk(KERN_INFO "sisfb: Viewport offset %ldk\n",
6262 ivideo->video_offset / 1024);
6263 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07006264
6265 printk(KERN_INFO "sisfb: MMIO at 0x%lx, mapped to 0x%lx, size %ldk\n",
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006266 ivideo->mmio_base, (unsigned long)ivideo->mmio_vbase, ivideo->mmio_size / 1024);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006267
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006268
6269 /* Determine the size of the command queue */
6270 if(ivideo->sisvga_engine == SIS_300_VGA) {
6271 ivideo->cmdQueueSize = TURBO_QUEUE_AREA_SIZE;
6272 } else {
6273 if(ivideo->chip == XGI_20) {
6274 ivideo->cmdQueueSize = COMMAND_QUEUE_AREA_SIZE_Z7;
6275 } else {
6276 ivideo->cmdQueueSize = COMMAND_QUEUE_AREA_SIZE;
6277 }
6278 }
6279
6280 /* Engines are no longer initialized here; this is
6281 * now done after the first mode-switch (if the
6282 * submitted var has its acceleration flags set).
6283 */
6284
6285 /* Calculate the base of the (unused) hw cursor */
6286 ivideo->hwcursor_vbase = ivideo->video_vbase
6287 + ivideo->video_size
6288 - ivideo->cmdQueueSize
6289 - ivideo->hwcursor_size;
6290 ivideo->caps |= HW_CURSOR_CAP;
6291
6292 /* Initialize offscreen memory manager */
Linus Torvalds1da177e2005-04-16 15:20:36 -07006293 if((ivideo->havenoheap = sisfb_heap_init(ivideo))) {
6294 printk(KERN_WARNING "sisfb: Failed to initialize offscreen memory heap\n");
6295 }
6296
6297 /* Used for clearing the screen only, therefore respect our mem limit */
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006298 ivideo->SiS_Pr.VideoMemoryAddress += ivideo->video_offset;
6299 ivideo->SiS_Pr.VideoMemorySize = ivideo->sisfb_mem;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006300
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006301 ivideo->mtrr = -1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006302
6303 ivideo->vbflags = 0;
6304 ivideo->lcddefmodeidx = DEFAULT_LCDMODE;
6305 ivideo->tvdefmodeidx = DEFAULT_TVMODE;
6306 ivideo->defmodeidx = DEFAULT_MODE;
6307
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006308 ivideo->newrom = 0;
6309 if(ivideo->chip < XGI_20) {
6310 if(ivideo->bios_abase) {
6311 ivideo->newrom = SiSDetermineROMLayout661(&ivideo->SiS_Pr);
6312 }
6313 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07006314
6315 if((ivideo->sisfb_mode_idx < 0) ||
6316 ((sisbios_mode[ivideo->sisfb_mode_idx].mode_no[ivideo->mni]) != 0xFF)) {
6317
6318 sisfb_sense_crt1(ivideo);
6319
6320 sisfb_get_VB_type(ivideo);
6321
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006322 if(ivideo->vbflags2 & VB2_VIDEOBRIDGE) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07006323 sisfb_detect_VB_connect(ivideo);
6324 }
6325
6326 ivideo->currentvbflags = ivideo->vbflags & (VB_VIDEOBRIDGE | TV_STANDARD);
6327
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006328 /* Decide on which CRT2 device to use */
6329 if(ivideo->vbflags2 & VB2_VIDEOBRIDGE) {
6330 if(ivideo->sisfb_crt2type != -1) {
6331 if((ivideo->sisfb_crt2type == CRT2_LCD) &&
6332 (ivideo->vbflags & CRT2_LCD)) {
6333 ivideo->currentvbflags |= CRT2_LCD;
6334 } else if(ivideo->sisfb_crt2type != CRT2_LCD) {
6335 ivideo->currentvbflags |= ivideo->sisfb_crt2type;
6336 }
6337 } else {
6338 /* Chrontel 700x TV detection often unreliable, therefore
6339 * use a different default order on such machines
6340 */
6341 if((ivideo->sisvga_engine == SIS_300_VGA) &&
6342 (ivideo->vbflags2 & VB2_CHRONTEL)) {
6343 if(ivideo->vbflags & CRT2_LCD)
6344 ivideo->currentvbflags |= CRT2_LCD;
6345 else if(ivideo->vbflags & CRT2_TV)
6346 ivideo->currentvbflags |= CRT2_TV;
6347 else if(ivideo->vbflags & CRT2_VGA)
6348 ivideo->currentvbflags |= CRT2_VGA;
6349 } else {
6350 if(ivideo->vbflags & CRT2_TV)
6351 ivideo->currentvbflags |= CRT2_TV;
6352 else if(ivideo->vbflags & CRT2_LCD)
6353 ivideo->currentvbflags |= CRT2_LCD;
6354 else if(ivideo->vbflags & CRT2_VGA)
6355 ivideo->currentvbflags |= CRT2_VGA;
6356 }
6357 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07006358 }
6359
6360 if(ivideo->vbflags & CRT2_LCD) {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006361 sisfb_detect_lcd_type(ivideo);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006362 }
6363
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006364 sisfb_save_pdc_emi(ivideo);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006365
6366 if(!ivideo->sisfb_crt1off) {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006367 sisfb_handle_ddc(ivideo, &ivideo->sisfb_thismonitor, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006368 } else {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006369 if((ivideo->vbflags2 & VB2_SISTMDSBRIDGE) &&
6370 (ivideo->vbflags & (CRT2_VGA | CRT2_LCD))) {
6371 sisfb_handle_ddc(ivideo, &ivideo->sisfb_thismonitor, 1);
6372 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07006373 }
6374
6375 if(ivideo->sisfb_mode_idx >= 0) {
6376 int bu = ivideo->sisfb_mode_idx;
6377 ivideo->sisfb_mode_idx = sisfb_validate_mode(ivideo,
6378 ivideo->sisfb_mode_idx, ivideo->currentvbflags);
6379 if(bu != ivideo->sisfb_mode_idx) {
6380 printk(KERN_ERR "Mode %dx%dx%d failed validation\n",
6381 sisbios_mode[bu].xres,
6382 sisbios_mode[bu].yres,
6383 sisbios_mode[bu].bpp);
6384 }
6385 }
6386
6387 if(ivideo->sisfb_mode_idx < 0) {
6388 switch(ivideo->currentvbflags & VB_DISPTYPE_DISP2) {
6389 case CRT2_LCD:
6390 ivideo->sisfb_mode_idx = ivideo->lcddefmodeidx;
6391 break;
6392 case CRT2_TV:
6393 ivideo->sisfb_mode_idx = ivideo->tvdefmodeidx;
6394 break;
6395 default:
6396 ivideo->sisfb_mode_idx = ivideo->defmodeidx;
6397 break;
6398 }
6399 }
6400
6401 ivideo->mode_no = sisbios_mode[ivideo->sisfb_mode_idx].mode_no[ivideo->mni];
6402
6403 if(ivideo->refresh_rate != 0) {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006404 sisfb_search_refresh_rate(ivideo, ivideo->refresh_rate,
6405 ivideo->sisfb_mode_idx);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006406 }
6407
6408 if(ivideo->rate_idx == 0) {
6409 ivideo->rate_idx = sisbios_mode[ivideo->sisfb_mode_idx].rate_idx;
6410 ivideo->refresh_rate = 60;
6411 }
6412
6413 if(ivideo->sisfb_thismonitor.datavalid) {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006414 if(!sisfb_verify_rate(ivideo, &ivideo->sisfb_thismonitor,
6415 ivideo->sisfb_mode_idx,
6416 ivideo->rate_idx,
6417 ivideo->refresh_rate)) {
6418 printk(KERN_INFO "sisfb: WARNING: Refresh rate "
6419 "exceeds monitor specs!\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07006420 }
6421 }
6422
6423 ivideo->video_bpp = sisbios_mode[ivideo->sisfb_mode_idx].bpp;
6424 ivideo->video_width = sisbios_mode[ivideo->sisfb_mode_idx].xres;
6425 ivideo->video_height = sisbios_mode[ivideo->sisfb_mode_idx].yres;
6426
6427 sisfb_set_vparms(ivideo);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006428
Linus Torvalds1da177e2005-04-16 15:20:36 -07006429 printk(KERN_INFO "sisfb: Default mode is %dx%dx%d (%dHz)\n",
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006430 ivideo->video_width, ivideo->video_height, ivideo->video_bpp,
Linus Torvalds1da177e2005-04-16 15:20:36 -07006431 ivideo->refresh_rate);
6432
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006433 /* Set up the default var according to chosen default display mode */
Linus Torvalds1da177e2005-04-16 15:20:36 -07006434 ivideo->default_var.xres = ivideo->default_var.xres_virtual = ivideo->video_width;
6435 ivideo->default_var.yres = ivideo->default_var.yres_virtual = ivideo->video_height;
6436 ivideo->default_var.bits_per_pixel = ivideo->video_bpp;
6437
6438 sisfb_bpp_to_var(ivideo, &ivideo->default_var);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006439
Linus Torvalds1da177e2005-04-16 15:20:36 -07006440 ivideo->default_var.pixclock = (u32) (1000000000 /
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006441 sisfb_mode_rate_to_dclock(&ivideo->SiS_Pr, ivideo->mode_no, ivideo->rate_idx));
6442
6443 if(sisfb_mode_rate_to_ddata(&ivideo->SiS_Pr, ivideo->mode_no,
6444 ivideo->rate_idx, &ivideo->default_var)) {
6445 if((ivideo->default_var.vmode & FB_VMODE_MASK) == FB_VMODE_DOUBLE) {
6446 ivideo->default_var.pixclock <<= 1;
6447 }
6448 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07006449
6450 if(ivideo->sisfb_ypan) {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006451 /* Maximize regardless of sisfb_max at startup */
6452 ivideo->default_var.yres_virtual =
6453 sisfb_calc_maxyres(ivideo, &ivideo->default_var);
6454 if(ivideo->default_var.yres_virtual < ivideo->default_var.yres) {
6455 ivideo->default_var.yres_virtual = ivideo->default_var.yres;
6456 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07006457 }
6458
6459 sisfb_calc_pitch(ivideo, &ivideo->default_var);
6460
6461 ivideo->accel = 0;
6462 if(ivideo->sisfb_accel) {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006463 ivideo->accel = -1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006464#ifdef STUPID_ACCELF_TEXT_SHIT
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006465 ivideo->default_var.accel_flags |= FB_ACCELF_TEXT;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006466#endif
6467 }
6468 sisfb_initaccel(ivideo);
6469
6470#if defined(FBINFO_HWACCEL_DISABLED) && defined(FBINFO_HWACCEL_XPAN)
6471 sis_fb_info->flags = FBINFO_DEFAULT |
6472 FBINFO_HWACCEL_YPAN |
6473 FBINFO_HWACCEL_XPAN |
6474 FBINFO_HWACCEL_COPYAREA |
6475 FBINFO_HWACCEL_FILLRECT |
6476 ((ivideo->accel) ? 0 : FBINFO_HWACCEL_DISABLED);
6477#else
6478 sis_fb_info->flags = FBINFO_FLAG_DEFAULT;
6479#endif
6480 sis_fb_info->var = ivideo->default_var;
6481 sis_fb_info->fix = ivideo->sisfb_fix;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006482 sis_fb_info->screen_base = ivideo->video_vbase + ivideo->video_offset;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006483 sis_fb_info->fbops = &sisfb_ops;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006484 sis_fb_info->pseudo_palette = ivideo->pseudo_palette;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006485
Linus Torvalds1da177e2005-04-16 15:20:36 -07006486 fb_alloc_cmap(&sis_fb_info->cmap, 256 , 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006487
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006488 printk(KERN_DEBUG "sisfb: Initial vbflags 0x%x\n", (int)ivideo->vbflags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006489
6490#ifdef CONFIG_MTRR
6491 ivideo->mtrr = mtrr_add(ivideo->video_base, ivideo->video_size,
6492 MTRR_TYPE_WRCOMB, 1);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006493 if(ivideo->mtrr < 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07006494 printk(KERN_DEBUG "sisfb: Failed to add MTRRs\n");
6495 }
6496#endif
6497
Linus Torvalds1da177e2005-04-16 15:20:36 -07006498 if(register_framebuffer(sis_fb_info) < 0) {
6499 printk(KERN_ERR "sisfb: Fatal error: Failed to register framebuffer\n");
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006500 ret = -EINVAL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006501 iounmap(ivideo->mmio_vbase);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006502 goto error_0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006503 }
6504
6505 ivideo->registered = 1;
6506
6507 /* Enlist us */
6508 ivideo->next = card_list;
6509 card_list = ivideo;
6510
6511 printk(KERN_INFO "sisfb: 2D acceleration is %s, y-panning %s\n",
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006512 ivideo->sisfb_accel ? "enabled" : "disabled",
6513 ivideo->sisfb_ypan ?
6514 (ivideo->sisfb_max ? "enabled (auto-max)" :
6515 "enabled (no auto-max)") :
6516 "disabled");
Linus Torvalds1da177e2005-04-16 15:20:36 -07006517
6518
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006519 printk(KERN_INFO "fb%d: %s frame buffer device version %d.%d.%d\n",
Michal Piotrowski43704092006-10-03 01:15:00 -07006520 sis_fb_info->node, ivideo->myid, VER_MAJOR, VER_MINOR, VER_LEVEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006521
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006522 printk(KERN_INFO "sisfb: Copyright (C) 2001-2005 Thomas Winischhofer\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07006523
6524 } /* if mode = "none" */
6525
6526 return 0;
6527}
6528
6529/*****************************************************/
6530/* PCI DEVICE HANDLING */
6531/*****************************************************/
6532
6533static void __devexit sisfb_remove(struct pci_dev *pdev)
6534{
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006535 struct sis_video_info *ivideo = pci_get_drvdata(pdev);
6536 struct fb_info *sis_fb_info = ivideo->memyselfandi;
6537 int registered = ivideo->registered;
6538 int modechanged = ivideo->modechanged;
6539
Linus Torvalds1da177e2005-04-16 15:20:36 -07006540 /* Unmap */
Linus Torvalds1da177e2005-04-16 15:20:36 -07006541 iounmap(ivideo->mmio_vbase);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006542 iounmap(ivideo->video_vbase);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006543
6544 /* Release mem regions */
6545 release_mem_region(ivideo->video_base, ivideo->video_size);
6546 release_mem_region(ivideo->mmio_base, ivideo->mmio_size);
6547
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006548 vfree(ivideo->bios_abase);
6549
6550 if(ivideo->lpcdev)
Adrian Bunk0959f0c2007-05-08 00:39:50 -07006551 pci_dev_put(ivideo->lpcdev);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006552
6553 if(ivideo->nbridge)
Adrian Bunk0959f0c2007-05-08 00:39:50 -07006554 pci_dev_put(ivideo->nbridge);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006555
Linus Torvalds1da177e2005-04-16 15:20:36 -07006556#ifdef CONFIG_MTRR
6557 /* Release MTRR region */
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006558 if(ivideo->mtrr >= 0)
Linus Torvalds1da177e2005-04-16 15:20:36 -07006559 mtrr_del(ivideo->mtrr, ivideo->video_base, ivideo->video_size);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006560#endif
6561
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006562 pci_set_drvdata(pdev, NULL);
6563
6564 /* If device was disabled when starting, disable
6565 * it when quitting.
6566 */
6567 if(!ivideo->sisvga_enabled)
6568 pci_disable_device(pdev);
6569
Linus Torvalds1da177e2005-04-16 15:20:36 -07006570 /* Unregister the framebuffer */
6571 if(ivideo->registered) {
6572 unregister_framebuffer(sis_fb_info);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006573 framebuffer_release(sis_fb_info);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006574 }
6575
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006576 /* OK, our ivideo is gone for good from here. */
Linus Torvalds1da177e2005-04-16 15:20:36 -07006577
6578 /* TODO: Restore the initial mode
6579 * This sounds easy but is as good as impossible
6580 * on many machines with SiS chip and video bridge
6581 * since text modes are always set up differently
6582 * from machine to machine. Depends on the type
6583 * of integration between chipset and bridge.
6584 */
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006585 if(registered && modechanged)
6586 printk(KERN_INFO
6587 "sisfb: Restoring of text mode not supported yet\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07006588};
6589
6590static struct pci_driver sisfb_driver = {
6591 .name = "sisfb",
6592 .id_table = sisfb_pci_table,
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006593 .probe = sisfb_probe,
Linus Torvalds1da177e2005-04-16 15:20:36 -07006594 .remove = __devexit_p(sisfb_remove)
6595};
6596
Adrian Bunk14aefd12008-07-23 21:31:12 -07006597static int __init sisfb_init(void)
Linus Torvalds1da177e2005-04-16 15:20:36 -07006598{
Linus Torvalds1da177e2005-04-16 15:20:36 -07006599#ifndef MODULE
6600 char *options = NULL;
6601
6602 if(fb_get_options("sisfb", &options))
6603 return -ENODEV;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006604
Linus Torvalds1da177e2005-04-16 15:20:36 -07006605 sisfb_setup(options);
6606#endif
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006607 return pci_register_driver(&sisfb_driver);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006608}
6609
Linus Torvalds1da177e2005-04-16 15:20:36 -07006610#ifndef MODULE
6611module_init(sisfb_init);
6612#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -07006613
6614/*****************************************************/
6615/* MODULE */
6616/*****************************************************/
6617
6618#ifdef MODULE
6619
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006620static char *mode = NULL;
6621static int vesa = -1;
6622static unsigned int rate = 0;
6623static unsigned int crt1off = 1;
6624static unsigned int mem = 0;
6625static char *forcecrt2type = NULL;
6626static int forcecrt1 = -1;
6627static int pdc = -1;
6628static int pdc1 = -1;
6629static int noaccel = -1;
6630static int noypan = -1;
6631static int nomax = -1;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006632static int userom = -1;
6633static int useoem = -1;
6634static char *tvstandard = NULL;
6635static int nocrt2rate = 0;
6636static int scalelcd = -1;
6637static char *specialtiming = NULL;
6638static int lvdshl = -1;
6639static int tvxposoffset = 0, tvyposoffset = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006640#if !defined(__i386__) && !defined(__x86_64__)
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006641static int resetcard = 0;
6642static int videoram = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006643#endif
6644
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006645static int __init sisfb_init_module(void)
6646{
6647 sisfb_setdefaultparms();
6648
6649 if(rate)
6650 sisfb_parm_rate = rate;
6651
6652 if((scalelcd == 0) || (scalelcd == 1))
6653 sisfb_scalelcd = scalelcd ^ 1;
6654
6655 /* Need to check crt2 type first for fstn/dstn */
6656
6657 if(forcecrt2type)
6658 sisfb_search_crt2type(forcecrt2type);
6659
6660 if(tvstandard)
6661 sisfb_search_tvstd(tvstandard);
6662
6663 if(mode)
Richard Knutssonc30660ea2007-02-12 00:55:06 -08006664 sisfb_search_mode(mode, false);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006665 else if(vesa != -1)
Richard Knutssonc30660ea2007-02-12 00:55:06 -08006666 sisfb_search_vesamode(vesa, false);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006667
6668 sisfb_crt1off = (crt1off == 0) ? 1 : 0;
6669
6670 sisfb_forcecrt1 = forcecrt1;
6671 if(forcecrt1 == 1)
6672 sisfb_crt1off = 0;
6673 else if(forcecrt1 == 0)
6674 sisfb_crt1off = 1;
6675
6676 if(noaccel == 1)
6677 sisfb_accel = 0;
6678 else if(noaccel == 0)
6679 sisfb_accel = 1;
6680
6681 if(noypan == 1)
6682 sisfb_ypan = 0;
6683 else if(noypan == 0)
6684 sisfb_ypan = 1;
6685
6686 if(nomax == 1)
6687 sisfb_max = 0;
6688 else if(nomax == 0)
6689 sisfb_max = 1;
6690
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006691 if(mem)
6692 sisfb_parm_mem = mem;
6693
6694 if(userom != -1)
6695 sisfb_userom = userom;
6696
6697 if(useoem != -1)
6698 sisfb_useoem = useoem;
6699
6700 if(pdc != -1)
6701 sisfb_pdc = (pdc & 0x7f);
6702
6703 if(pdc1 != -1)
6704 sisfb_pdca = (pdc1 & 0x1f);
6705
6706 sisfb_nocrt2rate = nocrt2rate;
6707
6708 if(specialtiming)
6709 sisfb_search_specialtiming(specialtiming);
6710
6711 if((lvdshl >= 0) && (lvdshl <= 3))
6712 sisfb_lvdshl = lvdshl;
6713
6714 sisfb_tvxposoffset = tvxposoffset;
6715 sisfb_tvyposoffset = tvyposoffset;
6716
6717#if !defined(__i386__) && !defined(__x86_64__)
6718 sisfb_resetcard = (resetcard) ? 1 : 0;
6719 if(videoram)
6720 sisfb_videoram = videoram;
6721#endif
6722
6723 return sisfb_init();
6724}
6725
6726static void __exit sisfb_remove_module(void)
6727{
6728 pci_unregister_driver(&sisfb_driver);
6729 printk(KERN_DEBUG "sisfb: Module unloaded\n");
6730}
6731
6732module_init(sisfb_init_module);
6733module_exit(sisfb_remove_module);
6734
6735MODULE_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 -07006736MODULE_LICENSE("GPL");
6737MODULE_AUTHOR("Thomas Winischhofer <thomas@winischhofer.net>, Others");
6738
Linus Torvalds1da177e2005-04-16 15:20:36 -07006739module_param(mem, int, 0);
6740module_param(noaccel, int, 0);
6741module_param(noypan, int, 0);
6742module_param(nomax, int, 0);
6743module_param(userom, int, 0);
6744module_param(useoem, int, 0);
6745module_param(mode, charp, 0);
6746module_param(vesa, int, 0);
6747module_param(rate, int, 0);
6748module_param(forcecrt1, int, 0);
6749module_param(forcecrt2type, charp, 0);
6750module_param(scalelcd, int, 0);
6751module_param(pdc, int, 0);
6752module_param(pdc1, int, 0);
6753module_param(specialtiming, charp, 0);
6754module_param(lvdshl, int, 0);
6755module_param(tvstandard, charp, 0);
6756module_param(tvxposoffset, int, 0);
6757module_param(tvyposoffset, int, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006758module_param(nocrt2rate, int, 0);
6759#if !defined(__i386__) && !defined(__x86_64__)
6760module_param(resetcard, int, 0);
6761module_param(videoram, int, 0);
6762#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -07006763
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006764MODULE_PARM_DESC(mem,
6765 "\nDetermines the beginning of the video memory heap in KB. This heap is used\n"
6766 "for video RAM management for eg. DRM/DRI. On 300 series, the default depends\n"
6767 "on the amount of video RAM available. If 8MB of video RAM or less is available,\n"
6768 "the heap starts at 4096KB, if between 8 and 16MB are available at 8192KB,\n"
6769 "otherwise at 12288KB. On 315/330/340 series, the heap size is 32KB by default.\n"
6770 "The value is to be specified without 'KB'.\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07006771
6772MODULE_PARM_DESC(noaccel,
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006773 "\nIf set to anything other than 0, 2D acceleration will be disabled.\n"
Linus Torvalds1da177e2005-04-16 15:20:36 -07006774 "(default: 0)\n");
6775
6776MODULE_PARM_DESC(noypan,
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006777 "\nIf set to anything other than 0, y-panning will be disabled and scrolling\n"
6778 "will be performed by redrawing the screen. (default: 0)\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07006779
6780MODULE_PARM_DESC(nomax,
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006781 "\nIf y-panning is enabled, sisfb will by default use the entire available video\n"
Linus Torvalds1da177e2005-04-16 15:20:36 -07006782 "memory for the virtual screen in order to optimize scrolling performance. If\n"
6783 "this is set to anything other than 0, sisfb will not do this and thereby \n"
6784 "enable the user to positively specify a virtual Y size of the screen using\n"
6785 "fbset. (default: 0)\n");
6786
Linus Torvalds1da177e2005-04-16 15:20:36 -07006787MODULE_PARM_DESC(mode,
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006788 "\nSelects the desired default display mode in the format XxYxDepth,\n"
6789 "eg. 1024x768x16. Other formats supported include XxY-Depth and\n"
Linus Torvalds1da177e2005-04-16 15:20:36 -07006790 "XxY-Depth@Rate. If the parameter is only one (decimal or hexadecimal)\n"
6791 "number, it will be interpreted as a VESA mode number. (default: 800x600x8)\n");
6792
6793MODULE_PARM_DESC(vesa,
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006794 "\nSelects the desired default display mode by VESA defined mode number, eg.\n"
6795 "0x117 (default: 0x0103)\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07006796
6797MODULE_PARM_DESC(rate,
6798 "\nSelects the desired vertical refresh rate for CRT1 (external VGA) in Hz.\n"
6799 "If the mode is specified in the format XxY-Depth@Rate, this parameter\n"
6800 "will be ignored (default: 60)\n");
6801
6802MODULE_PARM_DESC(forcecrt1,
6803 "\nNormally, the driver autodetects whether or not CRT1 (external VGA) is \n"
6804 "connected. With this option, the detection can be overridden (1=CRT1 ON,\n"
6805 "0=CRT1 OFF) (default: [autodetected])\n");
6806
6807MODULE_PARM_DESC(forcecrt2type,
6808 "\nIf this option is omitted, the driver autodetects CRT2 output devices, such as\n"
6809 "LCD, TV or secondary VGA. With this option, this autodetection can be\n"
6810 "overridden. Possible parameters are LCD, TV, VGA or NONE. NONE disables CRT2.\n"
6811 "On systems with a SiS video bridge, parameters SVIDEO, COMPOSITE or SCART can\n"
6812 "be used instead of TV to override the TV detection. Furthermore, on systems\n"
6813 "with a SiS video bridge, SVIDEO+COMPOSITE, HIVISION, YPBPR480I, YPBPR480P,\n"
6814 "YPBPR720P and YPBPR1080I are understood. However, whether or not these work\n"
6815 "depends on the very hardware in use. (default: [autodetected])\n");
6816
6817MODULE_PARM_DESC(scalelcd,
6818 "\nSetting this to 1 will force the driver to scale the LCD image to the panel's\n"
6819 "native resolution. Setting it to 0 will disable scaling; LVDS panels will\n"
6820 "show black bars around the image, TMDS panels will probably do the scaling\n"
6821 "themselves. Default: 1 on LVDS panels, 0 on TMDS panels\n");
6822
6823MODULE_PARM_DESC(pdc,
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006824 "\nThis is for manually selecting the LCD panel delay compensation. The driver\n"
Linus Torvalds1da177e2005-04-16 15:20:36 -07006825 "should detect this correctly in most cases; however, sometimes this is not\n"
6826 "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 -07006827 "on a 300 series chipset; 6 on other chipsets. If the problem persists, try\n"
6828 "other values (on 300 series: between 4 and 60 in steps of 4; otherwise: any\n"
6829 "value from 0 to 31). (default: autodetected, if LCD is active during start)\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07006830
6831#ifdef CONFIG_FB_SIS_315
6832MODULE_PARM_DESC(pdc1,
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006833 "\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 -07006834 "series only. (default: autodetected if LCD is in LCD-via-CRT1 mode during\n"
6835 "startup) - Note: currently, this has no effect because LCD-via-CRT1 is not\n"
6836 "implemented yet.\n");
6837#endif
6838
6839MODULE_PARM_DESC(specialtiming,
6840 "\nPlease refer to documentation for more information on this option.\n");
6841
6842MODULE_PARM_DESC(lvdshl,
6843 "\nPlease refer to documentation for more information on this option.\n");
6844
6845MODULE_PARM_DESC(tvstandard,
6846 "\nThis allows overriding the BIOS default for the TV standard. Valid choices are\n"
6847 "pal, ntsc, palm and paln. (default: [auto; pal or ntsc only])\n");
6848
6849MODULE_PARM_DESC(tvxposoffset,
6850 "\nRelocate TV output horizontally. Possible parameters: -32 through 32.\n"
6851 "Default: 0\n");
6852
6853MODULE_PARM_DESC(tvyposoffset,
6854 "\nRelocate TV output vertically. Possible parameters: -32 through 32.\n"
6855 "Default: 0\n");
6856
Linus Torvalds1da177e2005-04-16 15:20:36 -07006857MODULE_PARM_DESC(nocrt2rate,
6858 "\nSetting this to 1 will force the driver to use the default refresh rate for\n"
6859 "CRT2 if CRT2 type is VGA. (default: 0, use same rate as CRT1)\n");
6860
Linus Torvalds1da177e2005-04-16 15:20:36 -07006861#if !defined(__i386__) && !defined(__x86_64__)
6862#ifdef CONFIG_FB_SIS_300
6863MODULE_PARM_DESC(resetcard,
6864 "\nSet this to 1 in order to reset (POST) the card on non-x86 machines where\n"
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006865 "the BIOS did not POST the card (only supported for SiS 300/305 and XGI cards\n"
6866 "currently). Default: 0\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07006867
6868MODULE_PARM_DESC(videoram,
6869 "\nSet this to the amount of video RAM (in kilobyte) the card has. Required on\n"
6870 "some non-x86 architectures where the memory auto detection fails. Only\n"
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006871 "relevant if resetcard is set, too. SiS300/305 only. Default: [auto-detect]\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07006872#endif
6873#endif
6874
Linus Torvalds1da177e2005-04-16 15:20:36 -07006875#endif /* /MODULE */
6876
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006877/* _GPL only for new symbols. */
Linus Torvalds1da177e2005-04-16 15:20:36 -07006878EXPORT_SYMBOL(sis_malloc);
6879EXPORT_SYMBOL(sis_free);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006880EXPORT_SYMBOL_GPL(sis_malloc_new);
6881EXPORT_SYMBOL_GPL(sis_free_new);
6882
Linus Torvalds1da177e2005-04-16 15:20:36 -07006883
6884