blob: 75259845933deb53ab030a2067bb52e69259f673 [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
1336sisfb_pan_var(struct sis_video_info *ivideo, struct fb_var_screeninfo *var)
1337{
Linus Torvalds1da177e2005-04-16 15:20:36 -07001338 if(var->xoffset > (var->xres_virtual - var->xres)) {
1339 return -EINVAL;
1340 }
1341 if(var->yoffset > (var->yres_virtual - var->yres)) {
1342 return -EINVAL;
1343 }
1344
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001345 ivideo->current_base = (var->yoffset * var->xres_virtual) + var->xoffset;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001346
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001347 /* calculate base bpp dep. */
1348 switch(var->bits_per_pixel) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001349 case 32:
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001350 break;
1351 case 16:
1352 ivideo->current_base >>= 1;
1353 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001354 case 8:
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001355 default:
1356 ivideo->current_base >>= 2;
1357 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001358 }
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001359
1360 ivideo->current_base += (ivideo->video_offset >> 2);
1361
1362 sisfb_set_base_CRT1(ivideo, ivideo->current_base);
1363 sisfb_set_base_CRT2(ivideo, ivideo->current_base);
1364
Linus Torvalds1da177e2005-04-16 15:20:36 -07001365 return 0;
1366}
1367
Linus Torvalds1da177e2005-04-16 15:20:36 -07001368static int
1369sisfb_open(struct fb_info *info, int user)
1370{
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001371 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001372}
1373
1374static int
1375sisfb_release(struct fb_info *info, int user)
1376{
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001377 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001378}
1379
1380static int
1381sisfb_setcolreg(unsigned regno, unsigned red, unsigned green, unsigned blue,
1382 unsigned transp, struct fb_info *info)
1383{
1384 struct sis_video_info *ivideo = (struct sis_video_info *)info->par;
1385
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001386 if(regno >= sisfb_get_cmap_len(&info->var))
1387 return 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001388
1389 switch(info->var.bits_per_pixel) {
1390 case 8:
Aaro Koskinen63e13f82010-12-20 23:50:15 +02001391 SiS_SetRegByte(SISDACA, regno);
1392 SiS_SetRegByte(SISDACD, (red >> 10));
1393 SiS_SetRegByte(SISDACD, (green >> 10));
1394 SiS_SetRegByte(SISDACD, (blue >> 10));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001395 if(ivideo->currentvbflags & VB_DISPTYPE_DISP2) {
Aaro Koskinen63e13f82010-12-20 23:50:15 +02001396 SiS_SetRegByte(SISDAC2A, regno);
1397 SiS_SetRegByte(SISDAC2D, (red >> 8));
1398 SiS_SetRegByte(SISDAC2D, (green >> 8));
1399 SiS_SetRegByte(SISDAC2D, (blue >> 8));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001400 }
1401 break;
1402 case 16:
Antonino A. Daplas000d5332007-07-17 04:05:44 -07001403 if (regno >= 16)
1404 break;
1405
Linus Torvalds1da177e2005-04-16 15:20:36 -07001406 ((u32 *)(info->pseudo_palette))[regno] =
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001407 (red & 0xf800) |
1408 ((green & 0xfc00) >> 5) |
1409 ((blue & 0xf800) >> 11);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001410 break;
1411 case 32:
Antonino A. Daplas000d5332007-07-17 04:05:44 -07001412 if (regno >= 16)
1413 break;
1414
Linus Torvalds1da177e2005-04-16 15:20:36 -07001415 red >>= 8;
1416 green >>= 8;
1417 blue >>= 8;
1418 ((u32 *)(info->pseudo_palette))[regno] =
1419 (red << 16) | (green << 8) | (blue);
1420 break;
1421 }
1422 return 0;
1423}
1424
1425static int
1426sisfb_set_par(struct fb_info *info)
1427{
1428 int err;
1429
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001430 if((err = sisfb_do_set_var(&info->var, 1, info)))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001431 return err;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001432
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001433 sisfb_get_fix(&info->fix, -1, info);
Adrian Bunk14aefd12008-07-23 21:31:12 -07001434
Linus Torvalds1da177e2005-04-16 15:20:36 -07001435 return 0;
1436}
1437
1438static int
1439sisfb_check_var(struct fb_var_screeninfo *var, struct fb_info *info)
1440{
1441 struct sis_video_info *ivideo = (struct sis_video_info *)info->par;
1442 unsigned int htotal = 0, vtotal = 0, myrateindex = 0;
1443 unsigned int drate = 0, hrate = 0, maxyres;
1444 int found_mode = 0;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001445 int refresh_rate, search_idx, tidx;
Richard Knutssonc30660ea2007-02-12 00:55:06 -08001446 bool recalc_clock = false;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001447 u32 pixclock;
1448
1449 htotal = var->left_margin + var->xres + var->right_margin + var->hsync_len;
1450
1451 vtotal = var->upper_margin + var->lower_margin + var->vsync_len;
1452
1453 pixclock = var->pixclock;
1454
1455 if((var->vmode & FB_VMODE_MASK) == FB_VMODE_NONINTERLACED) {
1456 vtotal += var->yres;
1457 vtotal <<= 1;
1458 } else if((var->vmode & FB_VMODE_MASK) == FB_VMODE_DOUBLE) {
1459 vtotal += var->yres;
1460 vtotal <<= 2;
1461 } else if((var->vmode & FB_VMODE_MASK) == FB_VMODE_INTERLACED) {
1462 vtotal += var->yres;
1463 vtotal <<= 1;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001464 } else
1465 vtotal += var->yres;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001466
1467 if(!(htotal) || !(vtotal)) {
1468 SISFAIL("sisfb: no valid timing data");
1469 }
1470
1471 search_idx = 0;
1472 while( (sisbios_mode[search_idx].mode_no[0] != 0) &&
1473 (sisbios_mode[search_idx].xres <= var->xres) ) {
1474 if( (sisbios_mode[search_idx].xres == var->xres) &&
1475 (sisbios_mode[search_idx].yres == var->yres) &&
1476 (sisbios_mode[search_idx].bpp == var->bits_per_pixel)) {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001477 if((tidx = sisfb_validate_mode(ivideo, search_idx,
1478 ivideo->currentvbflags)) > 0) {
1479 found_mode = 1;
1480 search_idx = tidx;
1481 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001482 }
1483 }
1484 search_idx++;
1485 }
1486
1487 if(!found_mode) {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001488 search_idx = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001489 while(sisbios_mode[search_idx].mode_no[0] != 0) {
1490 if( (var->xres <= sisbios_mode[search_idx].xres) &&
1491 (var->yres <= sisbios_mode[search_idx].yres) &&
1492 (var->bits_per_pixel == sisbios_mode[search_idx].bpp) ) {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001493 if((tidx = sisfb_validate_mode(ivideo,search_idx,
1494 ivideo->currentvbflags)) > 0) {
1495 found_mode = 1;
1496 search_idx = tidx;
1497 break;
1498 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001499 }
1500 search_idx++;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001501 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001502 if(found_mode) {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001503 printk(KERN_DEBUG
1504 "sisfb: Adapted from %dx%dx%d to %dx%dx%d\n",
1505 var->xres, var->yres, var->bits_per_pixel,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001506 sisbios_mode[search_idx].xres,
1507 sisbios_mode[search_idx].yres,
1508 var->bits_per_pixel);
1509 var->xres = sisbios_mode[search_idx].xres;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001510 var->yres = sisbios_mode[search_idx].yres;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001511 } else {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001512 printk(KERN_ERR
1513 "sisfb: Failed to find supported mode near %dx%dx%d\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07001514 var->xres, var->yres, var->bits_per_pixel);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001515 return -EINVAL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001516 }
1517 }
1518
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001519 if( ((ivideo->vbflags2 & VB2_LVDS) ||
1520 ((ivideo->vbflags2 & VB2_30xBDH) && (ivideo->currentvbflags & CRT2_LCD))) &&
Linus Torvalds1da177e2005-04-16 15:20:36 -07001521 (var->bits_per_pixel == 8) ) {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001522 /* Slave modes on LVDS and 301B-DH */
1523 refresh_rate = 60;
Richard Knutssonc30660ea2007-02-12 00:55:06 -08001524 recalc_clock = true;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001525 } else if( (ivideo->current_htotal == htotal) &&
1526 (ivideo->current_vtotal == vtotal) &&
1527 (ivideo->current_pixclock == pixclock) ) {
1528 /* x=x & y=y & c=c -> assume depth change */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001529 drate = 1000000000 / pixclock;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001530 hrate = (drate * 1000) / htotal;
1531 refresh_rate = (unsigned int) (hrate * 2 / vtotal);
1532 } else if( ( (ivideo->current_htotal != htotal) ||
1533 (ivideo->current_vtotal != vtotal) ) &&
1534 (ivideo->current_pixclock == var->pixclock) ) {
1535 /* x!=x | y!=y & c=c -> invalid pixclock */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001536 if(ivideo->sisfb_lastrates[sisbios_mode[search_idx].mode_no[ivideo->mni]]) {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001537 refresh_rate =
1538 ivideo->sisfb_lastrates[sisbios_mode[search_idx].mode_no[ivideo->mni]];
Linus Torvalds1da177e2005-04-16 15:20:36 -07001539 } else if(ivideo->sisfb_parm_rate != -1) {
1540 /* Sic, sisfb_parm_rate - want to know originally desired rate here */
1541 refresh_rate = ivideo->sisfb_parm_rate;
1542 } else {
1543 refresh_rate = 60;
1544 }
Richard Knutssonc30660ea2007-02-12 00:55:06 -08001545 recalc_clock = true;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001546 } else if((pixclock) && (htotal) && (vtotal)) {
1547 drate = 1000000000 / pixclock;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001548 hrate = (drate * 1000) / htotal;
1549 refresh_rate = (unsigned int) (hrate * 2 / vtotal);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001550 } else if(ivideo->current_refresh_rate) {
1551 refresh_rate = ivideo->current_refresh_rate;
Richard Knutssonc30660ea2007-02-12 00:55:06 -08001552 recalc_clock = true;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001553 } else {
1554 refresh_rate = 60;
Richard Knutssonc30660ea2007-02-12 00:55:06 -08001555 recalc_clock = true;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001556 }
1557
1558 myrateindex = sisfb_search_refresh_rate(ivideo, refresh_rate, search_idx);
1559
1560 /* Eventually recalculate timing and clock */
1561 if(recalc_clock) {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001562 if(!myrateindex) myrateindex = sisbios_mode[search_idx].rate_idx;
1563 var->pixclock = (u32) (1000000000 / sisfb_mode_rate_to_dclock(&ivideo->SiS_Pr,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001564 sisbios_mode[search_idx].mode_no[ivideo->mni],
1565 myrateindex));
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001566 sisfb_mode_rate_to_ddata(&ivideo->SiS_Pr,
1567 sisbios_mode[search_idx].mode_no[ivideo->mni],
1568 myrateindex, var);
1569 if((var->vmode & FB_VMODE_MASK) == FB_VMODE_DOUBLE) {
1570 var->pixclock <<= 1;
1571 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001572 }
1573
1574 if(ivideo->sisfb_thismonitor.datavalid) {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001575 if(!sisfb_verify_rate(ivideo, &ivideo->sisfb_thismonitor, search_idx,
1576 myrateindex, refresh_rate)) {
1577 printk(KERN_INFO
1578 "sisfb: WARNING: Refresh rate exceeds monitor specs!\n");
1579 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001580 }
1581
1582 /* Adapt RGB settings */
1583 sisfb_bpp_to_var(ivideo, var);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001584
Linus Torvalds1da177e2005-04-16 15:20:36 -07001585 /* Sanity check for offsets */
1586 if(var->xoffset < 0) var->xoffset = 0;
1587 if(var->yoffset < 0) var->yoffset = 0;
1588
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001589 if(var->xres > var->xres_virtual)
1590 var->xres_virtual = var->xres;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001591
1592 if(ivideo->sisfb_ypan) {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001593 maxyres = sisfb_calc_maxyres(ivideo, var);
1594 if(ivideo->sisfb_max) {
1595 var->yres_virtual = maxyres;
1596 } else {
1597 if(var->yres_virtual > maxyres) {
1598 var->yres_virtual = maxyres;
1599 }
1600 }
1601 if(var->yres_virtual <= var->yres) {
1602 var->yres_virtual = var->yres;
1603 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001604 } else {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001605 if(var->yres != var->yres_virtual) {
1606 var->yres_virtual = var->yres;
1607 }
1608 var->xoffset = 0;
1609 var->yoffset = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001610 }
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001611
Linus Torvalds1da177e2005-04-16 15:20:36 -07001612 /* Truncate offsets to maximum if too high */
1613 if(var->xoffset > var->xres_virtual - var->xres) {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001614 var->xoffset = var->xres_virtual - var->xres - 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001615 }
1616
1617 if(var->yoffset > var->yres_virtual - var->yres) {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001618 var->yoffset = var->yres_virtual - var->yres - 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001619 }
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001620
Linus Torvalds1da177e2005-04-16 15:20:36 -07001621 /* Set everything else to 0 */
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001622 var->red.msb_right =
1623 var->green.msb_right =
1624 var->blue.msb_right =
1625 var->transp.offset =
1626 var->transp.length =
1627 var->transp.msb_right = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001628
1629 return 0;
1630}
1631
1632static int
1633sisfb_pan_display(struct fb_var_screeninfo *var, struct fb_info* info)
1634{
1635 struct sis_video_info *ivideo = (struct sis_video_info *)info->par;
1636 int err;
1637
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001638 if(var->xoffset > (var->xres_virtual - var->xres))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001639 return -EINVAL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001640
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001641 if(var->yoffset > (var->yres_virtual - var->yres))
1642 return -EINVAL;
1643
1644 if(var->vmode & FB_VMODE_YWRAP)
1645 return -EINVAL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001646
1647 if(var->xoffset + info->var.xres > info->var.xres_virtual ||
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001648 var->yoffset + info->var.yres > info->var.yres_virtual)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001649 return -EINVAL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001650
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001651 if((err = sisfb_pan_var(ivideo, var)) < 0)
1652 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001653
1654 info->var.xoffset = var->xoffset;
1655 info->var.yoffset = var->yoffset;
1656
1657 return 0;
1658}
1659
1660static int
1661sisfb_blank(int blank, struct fb_info *info)
1662{
1663 struct sis_video_info *ivideo = (struct sis_video_info *)info->par;
1664
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001665 return sisfb_myblank(ivideo, blank);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001666}
1667
Linus Torvalds1da177e2005-04-16 15:20:36 -07001668/* ----------- FBDev related routines for all series ---------- */
1669
Christoph Hellwig67a66802006-01-14 13:21:25 -08001670static int sisfb_ioctl(struct fb_info *info, unsigned int cmd,
1671 unsigned long arg)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001672{
1673 struct sis_video_info *ivideo = (struct sis_video_info *)info->par;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001674 struct sis_memreq sismemreq;
1675 struct fb_vblank sisvbblank;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001676 u32 gpu32 = 0;
1677#ifndef __user
1678#define __user
1679#endif
1680 u32 __user *argp = (u32 __user *)arg;
1681
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001682 switch(cmd) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001683 case FBIO_ALLOC:
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001684 if(!capable(CAP_SYS_RAWIO))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001685 return -EPERM;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001686
1687 if(copy_from_user(&sismemreq, (void __user *)arg, sizeof(sismemreq)))
1688 return -EFAULT;
1689
Linus Torvalds1da177e2005-04-16 15:20:36 -07001690 sis_malloc(&sismemreq);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001691
Linus Torvalds1da177e2005-04-16 15:20:36 -07001692 if(copy_to_user((void __user *)arg, &sismemreq, sizeof(sismemreq))) {
1693 sis_free((u32)sismemreq.offset);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001694 return -EFAULT;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001695 }
1696 break;
1697
1698 case FBIO_FREE:
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001699 if(!capable(CAP_SYS_RAWIO))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001700 return -EPERM;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001701
1702 if(get_user(gpu32, argp))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001703 return -EFAULT;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001704
Linus Torvalds1da177e2005-04-16 15:20:36 -07001705 sis_free(gpu32);
1706 break;
1707
1708 case FBIOGET_VBLANK:
Dan Rosenbergfd02db92010-09-22 13:05:09 -07001709
1710 memset(&sisvbblank, 0, sizeof(struct fb_vblank));
1711
Linus Torvalds1da177e2005-04-16 15:20:36 -07001712 sisvbblank.count = 0;
1713 sisvbblank.flags = sisfb_setupvbblankflags(ivideo, &sisvbblank.vcount, &sisvbblank.hcount);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001714
1715 if(copy_to_user((void __user *)arg, &sisvbblank, sizeof(sisvbblank)))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001716 return -EFAULT;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001717
Linus Torvalds1da177e2005-04-16 15:20:36 -07001718 break;
1719
1720 case SISFB_GET_INFO_SIZE:
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001721 return put_user(sizeof(struct sisfb_info), argp);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001722
1723 case SISFB_GET_INFO_OLD:
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001724 if(ivideo->warncount++ < 10)
1725 printk(KERN_INFO
1726 "sisfb: Deprecated ioctl call received - update your application!\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001727 case SISFB_GET_INFO: /* For communication with X driver */
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001728 ivideo->sisfb_infoblock.sisfb_id = SISFB_ID;
1729 ivideo->sisfb_infoblock.sisfb_version = VER_MAJOR;
1730 ivideo->sisfb_infoblock.sisfb_revision = VER_MINOR;
1731 ivideo->sisfb_infoblock.sisfb_patchlevel = VER_LEVEL;
1732 ivideo->sisfb_infoblock.chip_id = ivideo->chip_id;
1733 ivideo->sisfb_infoblock.sisfb_pci_vendor = ivideo->chip_vendor;
1734 ivideo->sisfb_infoblock.memory = ivideo->video_size / 1024;
1735 ivideo->sisfb_infoblock.heapstart = ivideo->heapstart / 1024;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001736 if(ivideo->modechanged) {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001737 ivideo->sisfb_infoblock.fbvidmode = ivideo->mode_no;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001738 } else {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001739 ivideo->sisfb_infoblock.fbvidmode = ivideo->modeprechange;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001740 }
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001741 ivideo->sisfb_infoblock.sisfb_caps = ivideo->caps;
1742 ivideo->sisfb_infoblock.sisfb_tqlen = ivideo->cmdQueueSize / 1024;
1743 ivideo->sisfb_infoblock.sisfb_pcibus = ivideo->pcibus;
1744 ivideo->sisfb_infoblock.sisfb_pcislot = ivideo->pcislot;
1745 ivideo->sisfb_infoblock.sisfb_pcifunc = ivideo->pcifunc;
1746 ivideo->sisfb_infoblock.sisfb_lcdpdc = ivideo->detectedpdc;
1747 ivideo->sisfb_infoblock.sisfb_lcdpdca = ivideo->detectedpdca;
1748 ivideo->sisfb_infoblock.sisfb_lcda = ivideo->detectedlcda;
1749 ivideo->sisfb_infoblock.sisfb_vbflags = ivideo->vbflags;
1750 ivideo->sisfb_infoblock.sisfb_currentvbflags = ivideo->currentvbflags;
1751 ivideo->sisfb_infoblock.sisfb_scalelcd = ivideo->SiS_Pr.UsePanelScaler;
1752 ivideo->sisfb_infoblock.sisfb_specialtiming = ivideo->SiS_Pr.SiS_CustomT;
1753 ivideo->sisfb_infoblock.sisfb_haveemi = ivideo->SiS_Pr.HaveEMI ? 1 : 0;
1754 ivideo->sisfb_infoblock.sisfb_haveemilcd = ivideo->SiS_Pr.HaveEMILCD ? 1 : 0;
1755 ivideo->sisfb_infoblock.sisfb_emi30 = ivideo->SiS_Pr.EMI_30;
1756 ivideo->sisfb_infoblock.sisfb_emi31 = ivideo->SiS_Pr.EMI_31;
1757 ivideo->sisfb_infoblock.sisfb_emi32 = ivideo->SiS_Pr.EMI_32;
1758 ivideo->sisfb_infoblock.sisfb_emi33 = ivideo->SiS_Pr.EMI_33;
1759 ivideo->sisfb_infoblock.sisfb_tvxpos = (u16)(ivideo->tvxpos + 32);
1760 ivideo->sisfb_infoblock.sisfb_tvypos = (u16)(ivideo->tvypos + 32);
1761 ivideo->sisfb_infoblock.sisfb_heapsize = ivideo->sisfb_heap_size / 1024;
1762 ivideo->sisfb_infoblock.sisfb_videooffset = ivideo->video_offset;
1763 ivideo->sisfb_infoblock.sisfb_curfstn = ivideo->curFSTN;
1764 ivideo->sisfb_infoblock.sisfb_curdstn = ivideo->curDSTN;
1765 ivideo->sisfb_infoblock.sisfb_vbflags2 = ivideo->vbflags2;
1766 ivideo->sisfb_infoblock.sisfb_can_post = ivideo->sisfb_can_post ? 1 : 0;
1767 ivideo->sisfb_infoblock.sisfb_card_posted = ivideo->sisfb_card_posted ? 1 : 0;
1768 ivideo->sisfb_infoblock.sisfb_was_boot_device = ivideo->sisfb_was_boot_device ? 1 : 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001769
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001770 if(copy_to_user((void __user *)arg, &ivideo->sisfb_infoblock,
1771 sizeof(ivideo->sisfb_infoblock)))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001772 return -EFAULT;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001773
Linus Torvalds1da177e2005-04-16 15:20:36 -07001774 break;
1775
1776 case SISFB_GET_VBRSTATUS_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_VBRSTATUS:
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001781 if(sisfb_CheckVBRetrace(ivideo))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001782 return put_user((u32)1, argp);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001783 else
Linus Torvalds1da177e2005-04-16 15:20:36 -07001784 return put_user((u32)0, argp);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001785
1786 case SISFB_GET_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_GET_AUTOMAXIMIZE:
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001791 if(ivideo->sisfb_max)
1792 return put_user((u32)1, argp);
1793 else
1794 return put_user((u32)0, argp);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001795
1796 case SISFB_SET_AUTOMAXIMIZE_OLD:
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001797 if(ivideo->warncount++ < 10)
1798 printk(KERN_INFO
1799 "sisfb: Deprecated ioctl call received - update your application!\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001800 case SISFB_SET_AUTOMAXIMIZE:
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001801 if(get_user(gpu32, argp))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001802 return -EFAULT;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001803
Linus Torvalds1da177e2005-04-16 15:20:36 -07001804 ivideo->sisfb_max = (gpu32) ? 1 : 0;
1805 break;
1806
1807 case SISFB_SET_TVPOSOFFSET:
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001808 if(get_user(gpu32, argp))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001809 return -EFAULT;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001810
Linus Torvalds1da177e2005-04-16 15:20:36 -07001811 sisfb_set_TVxposoffset(ivideo, ((int)(gpu32 >> 16)) - 32);
1812 sisfb_set_TVyposoffset(ivideo, ((int)(gpu32 & 0xffff)) - 32);
1813 break;
1814
1815 case SISFB_GET_TVPOSOFFSET:
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001816 return put_user((u32)(((ivideo->tvxpos+32)<<16)|((ivideo->tvypos+32)&0xffff)),
1817 argp);
1818
1819 case SISFB_COMMAND:
1820 if(copy_from_user(&ivideo->sisfb_command, (void __user *)arg,
1821 sizeof(struct sisfb_cmd)))
1822 return -EFAULT;
1823
1824 sisfb_handle_command(ivideo, &ivideo->sisfb_command);
1825
1826 if(copy_to_user((void __user *)arg, &ivideo->sisfb_command,
1827 sizeof(struct sisfb_cmd)))
1828 return -EFAULT;
1829
1830 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001831
1832 case SISFB_SET_LOCK:
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001833 if(get_user(gpu32, argp))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001834 return -EFAULT;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001835
Linus Torvalds1da177e2005-04-16 15:20:36 -07001836 ivideo->sisfblocked = (gpu32) ? 1 : 0;
1837 break;
1838
1839 default:
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001840#ifdef SIS_NEW_CONFIG_COMPAT
Linus Torvalds1da177e2005-04-16 15:20:36 -07001841 return -ENOIOCTLCMD;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001842#else
1843 return -EINVAL;
1844#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -07001845 }
1846 return 0;
1847}
1848
Linus Torvalds1da177e2005-04-16 15:20:36 -07001849static int
1850sisfb_get_fix(struct fb_fix_screeninfo *fix, int con, struct fb_info *info)
1851{
1852 struct sis_video_info *ivideo = (struct sis_video_info *)info->par;
1853
1854 memset(fix, 0, sizeof(struct fb_fix_screeninfo));
1855
Dan Carpenterdbd536b2010-05-24 14:33:53 -07001856 strlcpy(fix->id, ivideo->myid, sizeof(fix->id));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001857
Krzysztof Helt537a1bf2009-06-30 11:41:29 -07001858 mutex_lock(&info->mm_lock);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001859 fix->smem_start = ivideo->video_base + ivideo->video_offset;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001860 fix->smem_len = ivideo->sisfb_mem;
Krzysztof Helt537a1bf2009-06-30 11:41:29 -07001861 mutex_unlock(&info->mm_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001862 fix->type = FB_TYPE_PACKED_PIXELS;
1863 fix->type_aux = 0;
1864 fix->visual = (ivideo->video_bpp == 8) ? FB_VISUAL_PSEUDOCOLOR : FB_VISUAL_TRUECOLOR;
1865 fix->xpanstep = 1;
1866 fix->ypanstep = (ivideo->sisfb_ypan) ? 1 : 0;
1867 fix->ywrapstep = 0;
1868 fix->line_length = ivideo->video_linelength;
1869 fix->mmio_start = ivideo->mmio_base;
1870 fix->mmio_len = ivideo->mmio_size;
1871 if(ivideo->sisvga_engine == SIS_300_VGA) {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001872 fix->accel = FB_ACCEL_SIS_GLAMOUR;
1873 } else if((ivideo->chip == SIS_330) ||
1874 (ivideo->chip == SIS_760) ||
1875 (ivideo->chip == SIS_761)) {
1876 fix->accel = FB_ACCEL_SIS_XABRE;
1877 } else if(ivideo->chip == XGI_20) {
1878 fix->accel = FB_ACCEL_XGI_VOLARI_Z;
1879 } else if(ivideo->chip >= XGI_40) {
1880 fix->accel = FB_ACCEL_XGI_VOLARI_V;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001881 } else {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001882 fix->accel = FB_ACCEL_SIS_GLAMOUR_2;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001883 }
1884
1885 return 0;
1886}
1887
1888/* ---------------- fb_ops structures ----------------- */
1889
Linus Torvalds1da177e2005-04-16 15:20:36 -07001890static struct fb_ops sisfb_ops = {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001891 .owner = THIS_MODULE,
1892 .fb_open = sisfb_open,
1893 .fb_release = sisfb_release,
1894 .fb_check_var = sisfb_check_var,
1895 .fb_set_par = sisfb_set_par,
1896 .fb_setcolreg = sisfb_setcolreg,
1897 .fb_pan_display = sisfb_pan_display,
1898 .fb_blank = sisfb_blank,
1899 .fb_fillrect = fbcon_sis_fillrect,
1900 .fb_copyarea = fbcon_sis_copyarea,
1901 .fb_imageblit = cfb_imageblit,
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001902 .fb_sync = fbcon_sis_sync,
1903#ifdef SIS_NEW_CONFIG_COMPAT
Christoph Hellwig67a66802006-01-14 13:21:25 -08001904 .fb_compat_ioctl= sisfb_ioctl,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001905#endif
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001906 .fb_ioctl = sisfb_ioctl
Linus Torvalds1da177e2005-04-16 15:20:36 -07001907};
Linus Torvalds1da177e2005-04-16 15:20:36 -07001908
1909/* ---------------- Chip generation dependent routines ---------------- */
1910
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001911static struct pci_dev * __devinit
1912sisfb_get_northbridge(int basechipid)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001913{
1914 struct pci_dev *pdev = NULL;
1915 int nbridgenum, nbridgeidx, i;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001916 static const unsigned short nbridgeids[] = {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001917 PCI_DEVICE_ID_SI_540, /* for SiS 540 VGA */
1918 PCI_DEVICE_ID_SI_630, /* for SiS 630/730 VGA */
1919 PCI_DEVICE_ID_SI_730,
1920 PCI_DEVICE_ID_SI_550, /* for SiS 550 VGA */
1921 PCI_DEVICE_ID_SI_650, /* for SiS 650/651/740 VGA */
1922 PCI_DEVICE_ID_SI_651,
1923 PCI_DEVICE_ID_SI_740,
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001924 PCI_DEVICE_ID_SI_661, /* for SiS 661/741/660/760/761 VGA */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001925 PCI_DEVICE_ID_SI_741,
1926 PCI_DEVICE_ID_SI_660,
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001927 PCI_DEVICE_ID_SI_760,
1928 PCI_DEVICE_ID_SI_761
Linus Torvalds1da177e2005-04-16 15:20:36 -07001929 };
1930
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001931 switch(basechipid) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001932#ifdef CONFIG_FB_SIS_300
1933 case SIS_540: nbridgeidx = 0; nbridgenum = 1; break;
1934 case SIS_630: nbridgeidx = 1; nbridgenum = 2; break;
1935#endif
1936#ifdef CONFIG_FB_SIS_315
1937 case SIS_550: nbridgeidx = 3; nbridgenum = 1; break;
1938 case SIS_650: nbridgeidx = 4; nbridgenum = 3; break;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001939 case SIS_660: nbridgeidx = 7; nbridgenum = 5; break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001940#endif
1941 default: return NULL;
1942 }
1943 for(i = 0; i < nbridgenum; i++) {
Adrian Bunk0959f0c2007-05-08 00:39:50 -07001944 if((pdev = pci_get_device(PCI_VENDOR_ID_SI,
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001945 nbridgeids[nbridgeidx+i], NULL)))
1946 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001947 }
1948 return pdev;
1949}
1950
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001951static int __devinit
1952sisfb_get_dram_size(struct sis_video_info *ivideo)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001953{
1954#if defined(CONFIG_FB_SIS_300) || defined(CONFIG_FB_SIS_315)
1955 u8 reg;
1956#endif
1957
1958 ivideo->video_size = 0;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001959 ivideo->UMAsize = ivideo->LFBsize = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001960
1961 switch(ivideo->chip) {
1962#ifdef CONFIG_FB_SIS_300
1963 case SIS_300:
Aaro Koskinene57d4132010-12-20 23:50:16 +02001964 reg = SiS_GetReg(SISSR, 0x14);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001965 ivideo->video_size = ((reg & 0x3F) + 1) << 20;
1966 break;
1967 case SIS_540:
1968 case SIS_630:
1969 case SIS_730:
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001970 if(!ivideo->nbridge)
1971 return -1;
1972 pci_read_config_byte(ivideo->nbridge, 0x63, &reg);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001973 ivideo->video_size = 1 << (((reg & 0x70) >> 4) + 21);
1974 break;
1975#endif
1976#ifdef CONFIG_FB_SIS_315
1977 case SIS_315H:
1978 case SIS_315PRO:
1979 case SIS_315:
Aaro Koskinene57d4132010-12-20 23:50:16 +02001980 reg = SiS_GetReg(SISSR, 0x14);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001981 ivideo->video_size = (1 << ((reg & 0xf0) >> 4)) << 20;
1982 switch((reg >> 2) & 0x03) {
1983 case 0x01:
1984 case 0x03:
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001985 ivideo->video_size <<= 1;
1986 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001987 case 0x02:
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001988 ivideo->video_size += (ivideo->video_size/2);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001989 }
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001990 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001991 case SIS_330:
Aaro Koskinene57d4132010-12-20 23:50:16 +02001992 reg = SiS_GetReg(SISSR, 0x14);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001993 ivideo->video_size = (1 << ((reg & 0xf0) >> 4)) << 20;
1994 if(reg & 0x0c) ivideo->video_size <<= 1;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001995 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001996 case SIS_550:
1997 case SIS_650:
1998 case SIS_740:
Aaro Koskinene57d4132010-12-20 23:50:16 +02001999 reg = SiS_GetReg(SISSR, 0x14);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002000 ivideo->video_size = (((reg & 0x3f) + 1) << 2) << 20;
2001 break;
2002 case SIS_661:
2003 case SIS_741:
Aaro Koskinene57d4132010-12-20 23:50:16 +02002004 reg = SiS_GetReg(SISCR, 0x79);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002005 ivideo->video_size = (1 << ((reg & 0xf0) >> 4)) << 20;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07002006 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002007 case SIS_660:
2008 case SIS_760:
Thomas Winischhofer544393f2005-09-09 13:04:45 -07002009 case SIS_761:
Aaro Koskinene57d4132010-12-20 23:50:16 +02002010 reg = SiS_GetReg(SISCR, 0x79);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002011 reg = (reg & 0xf0) >> 4;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07002012 if(reg) {
2013 ivideo->video_size = (1 << reg) << 20;
2014 ivideo->UMAsize = ivideo->video_size;
2015 }
Aaro Koskinene57d4132010-12-20 23:50:16 +02002016 reg = SiS_GetReg(SISCR, 0x78);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002017 reg &= 0x30;
2018 if(reg) {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07002019 if(reg == 0x10) {
2020 ivideo->LFBsize = (32 << 20);
2021 } else {
2022 ivideo->LFBsize = (64 << 20);
2023 }
2024 ivideo->video_size += ivideo->LFBsize;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002025 }
Thomas Winischhofer544393f2005-09-09 13:04:45 -07002026 break;
2027 case SIS_340:
2028 case XGI_20:
2029 case XGI_40:
Aaro Koskinene57d4132010-12-20 23:50:16 +02002030 reg = SiS_GetReg(SISSR, 0x14);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07002031 ivideo->video_size = (1 << ((reg & 0xf0) >> 4)) << 20;
2032 if(ivideo->chip != XGI_20) {
2033 reg = (reg & 0x0c) >> 2;
2034 if(ivideo->revision_id == 2) {
2035 if(reg & 0x01) reg = 0x02;
2036 else reg = 0x00;
2037 }
2038 if(reg == 0x02) ivideo->video_size <<= 1;
2039 else if(reg == 0x03) ivideo->video_size <<= 2;
2040 }
2041 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002042#endif
2043 default:
2044 return -1;
2045 }
2046 return 0;
2047}
2048
2049/* -------------- video bridge device detection --------------- */
2050
Thomas Winischhofer544393f2005-09-09 13:04:45 -07002051static void __devinit
2052sisfb_detect_VB_connect(struct sis_video_info *ivideo)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002053{
2054 u8 cr32, temp;
2055
Thomas Winischhofer544393f2005-09-09 13:04:45 -07002056 /* No CRT2 on XGI Z7 */
2057 if(ivideo->chip == XGI_20) {
2058 ivideo->sisfb_crt1off = 0;
2059 return;
2060 }
2061
Linus Torvalds1da177e2005-04-16 15:20:36 -07002062#ifdef CONFIG_FB_SIS_300
2063 if(ivideo->sisvga_engine == SIS_300_VGA) {
Aaro Koskinene57d4132010-12-20 23:50:16 +02002064 temp = SiS_GetReg(SISSR, 0x17);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002065 if((temp & 0x0F) && (ivideo->chip != SIS_300)) {
2066 /* PAL/NTSC is stored on SR16 on such machines */
2067 if(!(ivideo->vbflags & (TV_PAL | TV_NTSC | TV_PALM | TV_PALN))) {
Aaro Koskinene57d4132010-12-20 23:50:16 +02002068 temp = SiS_GetReg(SISSR, 0x16);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002069 if(temp & 0x20)
2070 ivideo->vbflags |= TV_PAL;
2071 else
2072 ivideo->vbflags |= TV_NTSC;
2073 }
2074 }
2075 }
2076#endif
2077
Aaro Koskinene57d4132010-12-20 23:50:16 +02002078 cr32 = SiS_GetReg(SISCR, 0x32);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002079
2080 if(cr32 & SIS_CRT1) {
2081 ivideo->sisfb_crt1off = 0;
2082 } else {
2083 ivideo->sisfb_crt1off = (cr32 & 0xDF) ? 1 : 0;
2084 }
2085
2086 ivideo->vbflags &= ~(CRT2_TV | CRT2_LCD | CRT2_VGA);
2087
2088 if(cr32 & SIS_VB_TV) ivideo->vbflags |= CRT2_TV;
2089 if(cr32 & SIS_VB_LCD) ivideo->vbflags |= CRT2_LCD;
2090 if(cr32 & SIS_VB_CRT2) ivideo->vbflags |= CRT2_VGA;
2091
2092 /* Check given parms for hardware compatibility.
2093 * (Cannot do this in the search_xx routines since we don't
2094 * know what hardware we are running on then)
2095 */
2096
2097 if(ivideo->chip != SIS_550) {
2098 ivideo->sisfb_dstn = ivideo->sisfb_fstn = 0;
2099 }
2100
2101 if(ivideo->sisfb_tvplug != -1) {
2102 if( (ivideo->sisvga_engine != SIS_315_VGA) ||
Thomas Winischhofer544393f2005-09-09 13:04:45 -07002103 (!(ivideo->vbflags2 & VB2_SISYPBPRBRIDGE)) ) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002104 if(ivideo->sisfb_tvplug & TV_YPBPR) {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07002105 ivideo->sisfb_tvplug = -1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002106 printk(KERN_ERR "sisfb: YPbPr not supported\n");
2107 }
2108 }
2109 }
2110 if(ivideo->sisfb_tvplug != -1) {
2111 if( (ivideo->sisvga_engine != SIS_315_VGA) ||
Thomas Winischhofer544393f2005-09-09 13:04:45 -07002112 (!(ivideo->vbflags2 & VB2_SISHIVISIONBRIDGE)) ) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002113 if(ivideo->sisfb_tvplug & TV_HIVISION) {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07002114 ivideo->sisfb_tvplug = -1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002115 printk(KERN_ERR "sisfb: HiVision not supported\n");
2116 }
2117 }
2118 }
2119 if(ivideo->sisfb_tvstd != -1) {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07002120 if( (!(ivideo->vbflags2 & VB2_SISBRIDGE)) &&
2121 (!((ivideo->sisvga_engine == SIS_315_VGA) &&
2122 (ivideo->vbflags2 & VB2_CHRONTEL))) ) {
Roel Kluin5ab94812009-12-15 16:46:23 -08002123 if(ivideo->sisfb_tvstd & (TV_PALM | TV_PALN | TV_NTSCJ)) {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07002124 ivideo->sisfb_tvstd = -1;
2125 printk(KERN_ERR "sisfb: PALM/PALN/NTSCJ not supported\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002126 }
2127 }
2128 }
2129
2130 /* Detect/set TV plug & type */
2131 if(ivideo->sisfb_tvplug != -1) {
2132 ivideo->vbflags |= ivideo->sisfb_tvplug;
2133 } else {
2134 if(cr32 & SIS_VB_YPBPR) ivideo->vbflags |= (TV_YPBPR|TV_YPBPR525I); /* default: 480i */
2135 else if(cr32 & SIS_VB_HIVISION) ivideo->vbflags |= TV_HIVISION;
2136 else if(cr32 & SIS_VB_SCART) ivideo->vbflags |= TV_SCART;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07002137 else {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002138 if(cr32 & SIS_VB_SVIDEO) ivideo->vbflags |= TV_SVIDEO;
2139 if(cr32 & SIS_VB_COMPOSITE) ivideo->vbflags |= TV_AVIDEO;
2140 }
2141 }
2142
2143 if(!(ivideo->vbflags & (TV_YPBPR | TV_HIVISION))) {
2144 if(ivideo->sisfb_tvstd != -1) {
2145 ivideo->vbflags &= ~(TV_NTSC | TV_PAL | TV_PALM | TV_PALN | TV_NTSCJ);
2146 ivideo->vbflags |= ivideo->sisfb_tvstd;
2147 }
2148 if(ivideo->vbflags & TV_SCART) {
2149 ivideo->vbflags &= ~(TV_NTSC | TV_PALM | TV_PALN | TV_NTSCJ);
2150 ivideo->vbflags |= TV_PAL;
2151 }
2152 if(!(ivideo->vbflags & (TV_PAL | TV_NTSC | TV_PALM | TV_PALN | TV_NTSCJ))) {
2153 if(ivideo->sisvga_engine == SIS_300_VGA) {
Aaro Koskinene57d4132010-12-20 23:50:16 +02002154 temp = SiS_GetReg(SISSR, 0x38);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002155 if(temp & 0x01) ivideo->vbflags |= TV_PAL;
2156 else ivideo->vbflags |= TV_NTSC;
2157 } else if((ivideo->chip <= SIS_315PRO) || (ivideo->chip >= SIS_330)) {
Aaro Koskinene57d4132010-12-20 23:50:16 +02002158 temp = SiS_GetReg(SISSR, 0x38);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002159 if(temp & 0x01) ivideo->vbflags |= TV_PAL;
2160 else ivideo->vbflags |= TV_NTSC;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07002161 } else {
Aaro Koskinene57d4132010-12-20 23:50:16 +02002162 temp = SiS_GetReg(SISCR, 0x79);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002163 if(temp & 0x20) ivideo->vbflags |= TV_PAL;
2164 else ivideo->vbflags |= TV_NTSC;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07002165 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002166 }
2167 }
2168
2169 /* Copy forceCRT1 option to CRT1off if option is given */
Thomas Winischhofer544393f2005-09-09 13:04:45 -07002170 if(ivideo->sisfb_forcecrt1 != -1) {
2171 ivideo->sisfb_crt1off = (ivideo->sisfb_forcecrt1) ? 0 : 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002172 }
2173}
2174
2175/* ------------------ Sensing routines ------------------ */
2176
Richard Knutssonc30660ea2007-02-12 00:55:06 -08002177static bool __devinit
Thomas Winischhofer544393f2005-09-09 13:04:45 -07002178sisfb_test_DDC1(struct sis_video_info *ivideo)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002179{
2180 unsigned short old;
2181 int count = 48;
2182
2183 old = SiS_ReadDDC1Bit(&ivideo->SiS_Pr);
2184 do {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07002185 if(old != SiS_ReadDDC1Bit(&ivideo->SiS_Pr)) break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002186 } while(count--);
Richard Knutssonc30660ea2007-02-12 00:55:06 -08002187 return (count != -1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002188}
2189
Thomas Winischhofer544393f2005-09-09 13:04:45 -07002190static void __devinit
2191sisfb_sense_crt1(struct sis_video_info *ivideo)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002192{
Richard Knutssonc30660ea2007-02-12 00:55:06 -08002193 bool mustwait = false;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002194 u8 sr1F, cr17;
2195#ifdef CONFIG_FB_SIS_315
2196 u8 cr63=0;
2197#endif
2198 u16 temp = 0xffff;
2199 int i;
2200
Aaro Koskinene57d4132010-12-20 23:50:16 +02002201 sr1F = SiS_GetReg(SISSR, 0x1F);
Aaro Koskinen27799d62010-12-20 23:50:18 +02002202 SiS_SetRegOR(SISSR, 0x1F, 0x04);
Aaro Koskinen667a8b42010-12-20 23:50:19 +02002203 SiS_SetRegAND(SISSR, 0x1F, 0x3F);
Richard Knutssonc30660ea2007-02-12 00:55:06 -08002204 if(sr1F & 0xc0) mustwait = true;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002205
2206#ifdef CONFIG_FB_SIS_315
2207 if(ivideo->sisvga_engine == SIS_315_VGA) {
Aaro Koskinene57d4132010-12-20 23:50:16 +02002208 cr63 = SiS_GetReg(SISCR, ivideo->SiS_Pr.SiS_MyCR63);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002209 cr63 &= 0x40;
Aaro Koskinen667a8b42010-12-20 23:50:19 +02002210 SiS_SetRegAND(SISCR, ivideo->SiS_Pr.SiS_MyCR63, 0xBF);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002211 }
2212#endif
2213
Aaro Koskinene57d4132010-12-20 23:50:16 +02002214 cr17 = SiS_GetReg(SISCR, 0x17);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002215 cr17 &= 0x80;
2216 if(!cr17) {
Aaro Koskinen27799d62010-12-20 23:50:18 +02002217 SiS_SetRegOR(SISCR, 0x17, 0x80);
Richard Knutssonc30660ea2007-02-12 00:55:06 -08002218 mustwait = true;
Aaro Koskinen44b751b2010-12-20 23:50:17 +02002219 SiS_SetReg(SISSR, 0x00, 0x01);
2220 SiS_SetReg(SISSR, 0x00, 0x03);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002221 }
2222
2223 if(mustwait) {
2224 for(i=0; i < 10; i++) sisfbwaitretracecrt1(ivideo);
2225 }
2226
2227#ifdef CONFIG_FB_SIS_315
2228 if(ivideo->chip >= SIS_330) {
Aaro Koskinen667a8b42010-12-20 23:50:19 +02002229 SiS_SetRegAND(SISCR, 0x32, ~0x20);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002230 if(ivideo->chip >= SIS_340) {
Aaro Koskinen44b751b2010-12-20 23:50:17 +02002231 SiS_SetReg(SISCR, 0x57, 0x4a);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002232 } else {
Aaro Koskinen44b751b2010-12-20 23:50:17 +02002233 SiS_SetReg(SISCR, 0x57, 0x5f);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002234 }
Aaro Koskinen27799d62010-12-20 23:50:18 +02002235 SiS_SetRegOR(SISCR, 0x53, 0x02);
Aaro Koskinen1e1687d2010-12-20 23:50:14 +02002236 while ((SiS_GetRegByte(SISINPSTAT)) & 0x01) break;
2237 while (!((SiS_GetRegByte(SISINPSTAT)) & 0x01)) break;
2238 if ((SiS_GetRegByte(SISMISCW)) & 0x10) temp = 1;
Aaro Koskinen667a8b42010-12-20 23:50:19 +02002239 SiS_SetRegAND(SISCR, 0x53, 0xfd);
2240 SiS_SetRegAND(SISCR, 0x57, 0x00);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002241 }
2242#endif
2243
2244 if(temp == 0xffff) {
2245 i = 3;
2246 do {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07002247 temp = SiS_HandleDDC(&ivideo->SiS_Pr, ivideo->vbflags,
2248 ivideo->sisvga_engine, 0, 0, NULL, ivideo->vbflags2);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002249 } while(((temp == 0) || (temp == 0xffff)) && i--);
2250
2251 if((temp == 0) || (temp == 0xffff)) {
2252 if(sisfb_test_DDC1(ivideo)) temp = 1;
2253 }
2254 }
2255
2256 if((temp) && (temp != 0xffff)) {
Aaro Koskinen27799d62010-12-20 23:50:18 +02002257 SiS_SetRegOR(SISCR, 0x32, 0x20);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002258 }
2259
2260#ifdef CONFIG_FB_SIS_315
2261 if(ivideo->sisvga_engine == SIS_315_VGA) {
Aaro Koskinenad78adb2010-12-20 23:50:20 +02002262 SiS_SetRegANDOR(SISCR, ivideo->SiS_Pr.SiS_MyCR63, 0xBF, cr63);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002263 }
2264#endif
2265
Aaro Koskinenad78adb2010-12-20 23:50:20 +02002266 SiS_SetRegANDOR(SISCR, 0x17, 0x7F, cr17);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002267
Aaro Koskinen44b751b2010-12-20 23:50:17 +02002268 SiS_SetReg(SISSR, 0x1F, sr1F);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002269}
2270
2271/* Determine and detect attached devices on SiS30x */
Thomas Winischhofer544393f2005-09-09 13:04:45 -07002272static void __devinit
2273SiS_SenseLCD(struct sis_video_info *ivideo)
2274{
2275 unsigned char buffer[256];
2276 unsigned short temp, realcrtno, i;
2277 u8 reg, cr37 = 0, paneltype = 0;
2278 u16 xres, yres;
2279
Richard Knutssonc30660ea2007-02-12 00:55:06 -08002280 ivideo->SiS_Pr.PanelSelfDetected = false;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07002281
2282 /* LCD detection only for TMDS bridges */
2283 if(!(ivideo->vbflags2 & VB2_SISTMDSBRIDGE))
2284 return;
2285 if(ivideo->vbflags2 & VB2_30xBDH)
2286 return;
2287
2288 /* If LCD already set up by BIOS, skip it */
Aaro Koskinene57d4132010-12-20 23:50:16 +02002289 reg = SiS_GetReg(SISCR, 0x32);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07002290 if(reg & 0x08)
2291 return;
2292
2293 realcrtno = 1;
2294 if(ivideo->SiS_Pr.DDCPortMixup)
2295 realcrtno = 0;
2296
2297 /* Check DDC capabilities */
2298 temp = SiS_HandleDDC(&ivideo->SiS_Pr, ivideo->vbflags, ivideo->sisvga_engine,
2299 realcrtno, 0, &buffer[0], ivideo->vbflags2);
2300
2301 if((!temp) || (temp == 0xffff) || (!(temp & 0x02)))
2302 return;
2303
2304 /* Read DDC data */
2305 i = 3; /* Number of retrys */
2306 do {
2307 temp = SiS_HandleDDC(&ivideo->SiS_Pr, ivideo->vbflags,
2308 ivideo->sisvga_engine, realcrtno, 1,
2309 &buffer[0], ivideo->vbflags2);
2310 } while((temp) && i--);
2311
2312 if(temp)
2313 return;
2314
2315 /* No digital device */
2316 if(!(buffer[0x14] & 0x80))
2317 return;
2318
2319 /* First detailed timing preferred timing? */
2320 if(!(buffer[0x18] & 0x02))
2321 return;
2322
2323 xres = buffer[0x38] | ((buffer[0x3a] & 0xf0) << 4);
2324 yres = buffer[0x3b] | ((buffer[0x3d] & 0xf0) << 4);
2325
2326 switch(xres) {
2327 case 1024:
2328 if(yres == 768)
2329 paneltype = 0x02;
2330 break;
2331 case 1280:
2332 if(yres == 1024)
2333 paneltype = 0x03;
2334 break;
2335 case 1600:
2336 if((yres == 1200) && (ivideo->vbflags2 & VB2_30xC))
2337 paneltype = 0x0b;
2338 break;
2339 }
2340
2341 if(!paneltype)
2342 return;
2343
2344 if(buffer[0x23])
2345 cr37 |= 0x10;
2346
2347 if((buffer[0x47] & 0x18) == 0x18)
2348 cr37 |= ((((buffer[0x47] & 0x06) ^ 0x06) << 5) | 0x20);
2349 else
2350 cr37 |= 0xc0;
2351
Aaro Koskinen44b751b2010-12-20 23:50:17 +02002352 SiS_SetReg(SISCR, 0x36, paneltype);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07002353 cr37 &= 0xf1;
Aaro Koskinenad78adb2010-12-20 23:50:20 +02002354 SiS_SetRegANDOR(SISCR, 0x37, 0x0c, cr37);
Aaro Koskinen27799d62010-12-20 23:50:18 +02002355 SiS_SetRegOR(SISCR, 0x32, 0x08);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07002356
Richard Knutssonc30660ea2007-02-12 00:55:06 -08002357 ivideo->SiS_Pr.PanelSelfDetected = true;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07002358}
2359
2360static int __devinit
2361SISDoSense(struct sis_video_info *ivideo, u16 type, u16 test)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002362{
2363 int temp, mytest, result, i, j;
2364
2365 for(j = 0; j < 10; j++) {
2366 result = 0;
2367 for(i = 0; i < 3; i++) {
2368 mytest = test;
Aaro Koskinen44b751b2010-12-20 23:50:17 +02002369 SiS_SetReg(SISPART4, 0x11, (type & 0x00ff));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002370 temp = (type >> 8) | (mytest & 0x00ff);
Aaro Koskinenad78adb2010-12-20 23:50:20 +02002371 SiS_SetRegANDOR(SISPART4, 0x10, 0xe0, temp);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002372 SiS_DDC2Delay(&ivideo->SiS_Pr, 0x1500);
2373 mytest >>= 8;
2374 mytest &= 0x7f;
Aaro Koskinene57d4132010-12-20 23:50:16 +02002375 temp = SiS_GetReg(SISPART4, 0x03);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002376 temp ^= 0x0e;
2377 temp &= mytest;
2378 if(temp == mytest) result++;
2379#if 1
Aaro Koskinen44b751b2010-12-20 23:50:17 +02002380 SiS_SetReg(SISPART4, 0x11, 0x00);
Aaro Koskinen667a8b42010-12-20 23:50:19 +02002381 SiS_SetRegAND(SISPART4, 0x10, 0xe0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002382 SiS_DDC2Delay(&ivideo->SiS_Pr, 0x1000);
2383#endif
2384 }
2385 if((result == 0) || (result >= 2)) break;
2386 }
Thomas Winischhofer544393f2005-09-09 13:04:45 -07002387 return result;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002388}
2389
Thomas Winischhofer544393f2005-09-09 13:04:45 -07002390static void __devinit
2391SiS_Sense30x(struct sis_video_info *ivideo)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002392{
2393 u8 backupP4_0d,backupP2_00,backupP2_4d,backupSR_1e,biosflag=0;
2394 u16 svhs=0, svhs_c=0;
2395 u16 cvbs=0, cvbs_c=0;
2396 u16 vga2=0, vga2_c=0;
2397 int myflag, result;
2398 char stdstr[] = "sisfb: Detected";
2399 char tvstr[] = "TV connected to";
2400
Thomas Winischhofer544393f2005-09-09 13:04:45 -07002401 if(ivideo->vbflags2 & VB2_301) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002402 svhs = 0x00b9; cvbs = 0x00b3; vga2 = 0x00d1;
Aaro Koskinene57d4132010-12-20 23:50:16 +02002403 myflag = SiS_GetReg(SISPART4, 0x01);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002404 if(myflag & 0x04) {
2405 svhs = 0x00dd; cvbs = 0x00ee; vga2 = 0x00fd;
2406 }
Thomas Winischhofer544393f2005-09-09 13:04:45 -07002407 } else if(ivideo->vbflags2 & (VB2_301B | VB2_302B)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002408 svhs = 0x016b; cvbs = 0x0174; vga2 = 0x0190;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07002409 } else if(ivideo->vbflags2 & (VB2_301LV | VB2_302LV)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002410 svhs = 0x0200; cvbs = 0x0100;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07002411 } else if(ivideo->vbflags2 & (VB2_301C | VB2_302ELV | VB2_307T | VB2_307LV)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002412 svhs = 0x016b; cvbs = 0x0110; vga2 = 0x0190;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07002413 } else
2414 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002415
2416 vga2_c = 0x0e08; svhs_c = 0x0404; cvbs_c = 0x0804;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07002417 if(ivideo->vbflags & (VB2_301LV|VB2_302LV|VB2_302ELV|VB2_307LV)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002418 svhs_c = 0x0408; cvbs_c = 0x0808;
2419 }
Thomas Winischhofer544393f2005-09-09 13:04:45 -07002420
Linus Torvalds1da177e2005-04-16 15:20:36 -07002421 biosflag = 2;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07002422 if(ivideo->haveXGIROM) {
2423 biosflag = ivideo->bios_abase[0x58] & 0x03;
2424 } else if(ivideo->newrom) {
2425 if(ivideo->bios_abase[0x5d] & 0x04) biosflag |= 0x01;
2426 } else if(ivideo->sisvga_engine == SIS_300_VGA) {
2427 if(ivideo->bios_abase) {
2428 biosflag = ivideo->bios_abase[0xfe] & 0x03;
2429 }
2430 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002431
2432 if(ivideo->chip == SIS_300) {
Aaro Koskinene57d4132010-12-20 23:50:16 +02002433 myflag = SiS_GetReg(SISSR, 0x3b);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002434 if(!(myflag & 0x01)) vga2 = vga2_c = 0;
2435 }
2436
Thomas Winischhofer544393f2005-09-09 13:04:45 -07002437 if(!(ivideo->vbflags2 & VB2_SISVGA2BRIDGE)) {
2438 vga2 = vga2_c = 0;
2439 }
2440
Aaro Koskinene57d4132010-12-20 23:50:16 +02002441 backupSR_1e = SiS_GetReg(SISSR, 0x1e);
Aaro Koskinen27799d62010-12-20 23:50:18 +02002442 SiS_SetRegOR(SISSR, 0x1e, 0x20);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002443
Aaro Koskinene57d4132010-12-20 23:50:16 +02002444 backupP4_0d = SiS_GetReg(SISPART4, 0x0d);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07002445 if(ivideo->vbflags2 & VB2_30xC) {
Aaro Koskinenad78adb2010-12-20 23:50:20 +02002446 SiS_SetRegANDOR(SISPART4, 0x0d, ~0x07, 0x01);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002447 } else {
Aaro Koskinen27799d62010-12-20 23:50:18 +02002448 SiS_SetRegOR(SISPART4, 0x0d, 0x04);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002449 }
2450 SiS_DDC2Delay(&ivideo->SiS_Pr, 0x2000);
2451
Aaro Koskinene57d4132010-12-20 23:50:16 +02002452 backupP2_00 = SiS_GetReg(SISPART2, 0x00);
Aaro Koskinen44b751b2010-12-20 23:50:17 +02002453 SiS_SetReg(SISPART2, 0x00, ((backupP2_00 | 0x1c) & 0xfc));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002454
Aaro Koskinene57d4132010-12-20 23:50:16 +02002455 backupP2_4d = SiS_GetReg(SISPART2, 0x4d);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07002456 if(ivideo->vbflags2 & VB2_SISYPBPRBRIDGE) {
Aaro Koskinen44b751b2010-12-20 23:50:17 +02002457 SiS_SetReg(SISPART2, 0x4d, (backupP2_4d & ~0x10));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002458 }
2459
Thomas Winischhofer544393f2005-09-09 13:04:45 -07002460 if(!(ivideo->vbflags2 & VB2_30xCLV)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002461 SISDoSense(ivideo, 0, 0);
2462 }
2463
Aaro Koskinen667a8b42010-12-20 23:50:19 +02002464 SiS_SetRegAND(SISCR, 0x32, ~0x14);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002465
2466 if(vga2_c || vga2) {
2467 if(SISDoSense(ivideo, vga2, vga2_c)) {
2468 if(biosflag & 0x01) {
2469 printk(KERN_INFO "%s %s SCART output\n", stdstr, tvstr);
Aaro Koskinen27799d62010-12-20 23:50:18 +02002470 SiS_SetRegOR(SISCR, 0x32, 0x04);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002471 } else {
2472 printk(KERN_INFO "%s secondary VGA connection\n", stdstr);
Aaro Koskinen27799d62010-12-20 23:50:18 +02002473 SiS_SetRegOR(SISCR, 0x32, 0x10);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002474 }
2475 }
2476 }
2477
Aaro Koskinen667a8b42010-12-20 23:50:19 +02002478 SiS_SetRegAND(SISCR, 0x32, 0x3f);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002479
Thomas Winischhofer544393f2005-09-09 13:04:45 -07002480 if(ivideo->vbflags2 & VB2_30xCLV) {
Aaro Koskinen27799d62010-12-20 23:50:18 +02002481 SiS_SetRegOR(SISPART4, 0x0d, 0x04);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002482 }
2483
Thomas Winischhofer544393f2005-09-09 13:04:45 -07002484 if((ivideo->sisvga_engine == SIS_315_VGA) && (ivideo->vbflags2 & VB2_SISYPBPRBRIDGE)) {
Aaro Koskinen44b751b2010-12-20 23:50:17 +02002485 SiS_SetReg(SISPART2, 0x4d, (backupP2_4d | 0x10));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002486 SiS_DDC2Delay(&ivideo->SiS_Pr, 0x2000);
2487 if((result = SISDoSense(ivideo, svhs, 0x0604))) {
2488 if((result = SISDoSense(ivideo, cvbs, 0x0804))) {
2489 printk(KERN_INFO "%s %s YPbPr component output\n", stdstr, tvstr);
Aaro Koskinen27799d62010-12-20 23:50:18 +02002490 SiS_SetRegOR(SISCR, 0x32, 0x80);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002491 }
2492 }
Aaro Koskinen44b751b2010-12-20 23:50:17 +02002493 SiS_SetReg(SISPART2, 0x4d, backupP2_4d);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002494 }
2495
Aaro Koskinen667a8b42010-12-20 23:50:19 +02002496 SiS_SetRegAND(SISCR, 0x32, ~0x03);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002497
2498 if(!(ivideo->vbflags & TV_YPBPR)) {
2499 if((result = SISDoSense(ivideo, svhs, svhs_c))) {
2500 printk(KERN_INFO "%s %s SVIDEO output\n", stdstr, tvstr);
Aaro Koskinen27799d62010-12-20 23:50:18 +02002501 SiS_SetRegOR(SISCR, 0x32, 0x02);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002502 }
2503 if((biosflag & 0x02) || (!result)) {
2504 if(SISDoSense(ivideo, cvbs, cvbs_c)) {
2505 printk(KERN_INFO "%s %s COMPOSITE output\n", stdstr, tvstr);
Aaro Koskinen27799d62010-12-20 23:50:18 +02002506 SiS_SetRegOR(SISCR, 0x32, 0x01);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002507 }
2508 }
2509 }
2510
2511 SISDoSense(ivideo, 0, 0);
2512
Aaro Koskinen44b751b2010-12-20 23:50:17 +02002513 SiS_SetReg(SISPART2, 0x00, backupP2_00);
2514 SiS_SetReg(SISPART4, 0x0d, backupP4_0d);
2515 SiS_SetReg(SISSR, 0x1e, backupSR_1e);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002516
Thomas Winischhofer544393f2005-09-09 13:04:45 -07002517 if(ivideo->vbflags2 & VB2_30xCLV) {
Aaro Koskinene57d4132010-12-20 23:50:16 +02002518 biosflag = SiS_GetReg(SISPART2, 0x00);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002519 if(biosflag & 0x20) {
2520 for(myflag = 2; myflag > 0; myflag--) {
2521 biosflag ^= 0x20;
Aaro Koskinen44b751b2010-12-20 23:50:17 +02002522 SiS_SetReg(SISPART2, 0x00, biosflag);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002523 }
2524 }
2525 }
2526
Aaro Koskinen44b751b2010-12-20 23:50:17 +02002527 SiS_SetReg(SISPART2, 0x00, backupP2_00);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002528}
2529
2530/* Determine and detect attached TV's on Chrontel */
Thomas Winischhofer544393f2005-09-09 13:04:45 -07002531static void __devinit
2532SiS_SenseCh(struct sis_video_info *ivideo)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002533{
2534#if defined(CONFIG_FB_SIS_300) || defined(CONFIG_FB_SIS_315)
2535 u8 temp1, temp2;
2536 char stdstr[] = "sisfb: Chrontel: Detected TV connected to";
2537#endif
2538#ifdef CONFIG_FB_SIS_300
2539 unsigned char test[3];
2540 int i;
2541#endif
2542
2543 if(ivideo->chip < SIS_315H) {
2544
2545#ifdef CONFIG_FB_SIS_300
2546 ivideo->SiS_Pr.SiS_IF_DEF_CH70xx = 1; /* Chrontel 700x */
2547 SiS_SetChrontelGPIO(&ivideo->SiS_Pr, 0x9c); /* Set general purpose IO for Chrontel communication */
2548 SiS_DDC2Delay(&ivideo->SiS_Pr, 1000);
2549 temp1 = SiS_GetCH700x(&ivideo->SiS_Pr, 0x25);
2550 /* See Chrontel TB31 for explanation */
2551 temp2 = SiS_GetCH700x(&ivideo->SiS_Pr, 0x0e);
2552 if(((temp2 & 0x07) == 0x01) || (temp2 & 0x04)) {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07002553 SiS_SetCH700x(&ivideo->SiS_Pr, 0x0e, 0x0b);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002554 SiS_DDC2Delay(&ivideo->SiS_Pr, 300);
2555 }
2556 temp2 = SiS_GetCH700x(&ivideo->SiS_Pr, 0x25);
2557 if(temp2 != temp1) temp1 = temp2;
2558
2559 if((temp1 >= 0x22) && (temp1 <= 0x50)) {
2560 /* Read power status */
2561 temp1 = SiS_GetCH700x(&ivideo->SiS_Pr, 0x0e);
2562 if((temp1 & 0x03) != 0x03) {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07002563 /* Power all outputs */
2564 SiS_SetCH700x(&ivideo->SiS_Pr, 0x0e,0x0b);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002565 SiS_DDC2Delay(&ivideo->SiS_Pr, 300);
2566 }
2567 /* Sense connected TV devices */
2568 for(i = 0; i < 3; i++) {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07002569 SiS_SetCH700x(&ivideo->SiS_Pr, 0x10, 0x01);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002570 SiS_DDC2Delay(&ivideo->SiS_Pr, 0x96);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07002571 SiS_SetCH700x(&ivideo->SiS_Pr, 0x10, 0x00);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002572 SiS_DDC2Delay(&ivideo->SiS_Pr, 0x96);
2573 temp1 = SiS_GetCH700x(&ivideo->SiS_Pr, 0x10);
2574 if(!(temp1 & 0x08)) test[i] = 0x02;
2575 else if(!(temp1 & 0x02)) test[i] = 0x01;
2576 else test[i] = 0;
2577 SiS_DDC2Delay(&ivideo->SiS_Pr, 0x96);
2578 }
2579
2580 if(test[0] == test[1]) temp1 = test[0];
2581 else if(test[0] == test[2]) temp1 = test[0];
2582 else if(test[1] == test[2]) temp1 = test[1];
2583 else {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07002584 printk(KERN_INFO
Linus Torvalds1da177e2005-04-16 15:20:36 -07002585 "sisfb: TV detection unreliable - test results varied\n");
2586 temp1 = test[2];
2587 }
2588 if(temp1 == 0x02) {
2589 printk(KERN_INFO "%s SVIDEO output\n", stdstr);
2590 ivideo->vbflags |= TV_SVIDEO;
Aaro Koskinen27799d62010-12-20 23:50:18 +02002591 SiS_SetRegOR(SISCR, 0x32, 0x02);
Aaro Koskinen667a8b42010-12-20 23:50:19 +02002592 SiS_SetRegAND(SISCR, 0x32, ~0x05);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002593 } else if (temp1 == 0x01) {
2594 printk(KERN_INFO "%s CVBS output\n", stdstr);
2595 ivideo->vbflags |= TV_AVIDEO;
Aaro Koskinen27799d62010-12-20 23:50:18 +02002596 SiS_SetRegOR(SISCR, 0x32, 0x01);
Aaro Koskinen667a8b42010-12-20 23:50:19 +02002597 SiS_SetRegAND(SISCR, 0x32, ~0x06);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002598 } else {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07002599 SiS_SetCH70xxANDOR(&ivideo->SiS_Pr, 0x0e, 0x01, 0xF8);
Aaro Koskinen667a8b42010-12-20 23:50:19 +02002600 SiS_SetRegAND(SISCR, 0x32, ~0x07);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002601 }
2602 } else if(temp1 == 0) {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07002603 SiS_SetCH70xxANDOR(&ivideo->SiS_Pr, 0x0e, 0x01, 0xF8);
Aaro Koskinen667a8b42010-12-20 23:50:19 +02002604 SiS_SetRegAND(SISCR, 0x32, ~0x07);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002605 }
2606 /* Set general purpose IO for Chrontel communication */
2607 SiS_SetChrontelGPIO(&ivideo->SiS_Pr, 0x00);
2608#endif
2609
2610 } else {
2611
2612#ifdef CONFIG_FB_SIS_315
2613 ivideo->SiS_Pr.SiS_IF_DEF_CH70xx = 2; /* Chrontel 7019 */
Thomas Winischhofer544393f2005-09-09 13:04:45 -07002614 temp1 = SiS_GetCH701x(&ivideo->SiS_Pr, 0x49);
2615 SiS_SetCH701x(&ivideo->SiS_Pr, 0x49, 0x20);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002616 SiS_DDC2Delay(&ivideo->SiS_Pr, 0x96);
2617 temp2 = SiS_GetCH701x(&ivideo->SiS_Pr, 0x20);
2618 temp2 |= 0x01;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07002619 SiS_SetCH701x(&ivideo->SiS_Pr, 0x20, temp2);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002620 SiS_DDC2Delay(&ivideo->SiS_Pr, 0x96);
2621 temp2 ^= 0x01;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07002622 SiS_SetCH701x(&ivideo->SiS_Pr, 0x20, temp2);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002623 SiS_DDC2Delay(&ivideo->SiS_Pr, 0x96);
2624 temp2 = SiS_GetCH701x(&ivideo->SiS_Pr, 0x20);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07002625 SiS_SetCH701x(&ivideo->SiS_Pr, 0x49, temp1);
2626 temp1 = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002627 if(temp2 & 0x02) temp1 |= 0x01;
2628 if(temp2 & 0x10) temp1 |= 0x01;
2629 if(temp2 & 0x04) temp1 |= 0x02;
2630 if( (temp1 & 0x01) && (temp1 & 0x02) ) temp1 = 0x04;
2631 switch(temp1) {
2632 case 0x01:
2633 printk(KERN_INFO "%s CVBS output\n", stdstr);
2634 ivideo->vbflags |= TV_AVIDEO;
Aaro Koskinen27799d62010-12-20 23:50:18 +02002635 SiS_SetRegOR(SISCR, 0x32, 0x01);
Aaro Koskinen667a8b42010-12-20 23:50:19 +02002636 SiS_SetRegAND(SISCR, 0x32, ~0x06);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07002637 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002638 case 0x02:
2639 printk(KERN_INFO "%s SVIDEO output\n", stdstr);
2640 ivideo->vbflags |= TV_SVIDEO;
Aaro Koskinen27799d62010-12-20 23:50:18 +02002641 SiS_SetRegOR(SISCR, 0x32, 0x02);
Aaro Koskinen667a8b42010-12-20 23:50:19 +02002642 SiS_SetRegAND(SISCR, 0x32, ~0x05);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07002643 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002644 case 0x04:
2645 printk(KERN_INFO "%s SCART output\n", stdstr);
Aaro Koskinen27799d62010-12-20 23:50:18 +02002646 SiS_SetRegOR(SISCR, 0x32, 0x04);
Aaro Koskinen667a8b42010-12-20 23:50:19 +02002647 SiS_SetRegAND(SISCR, 0x32, ~0x03);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07002648 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002649 default:
Aaro Koskinen667a8b42010-12-20 23:50:19 +02002650 SiS_SetRegAND(SISCR, 0x32, ~0x07);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002651 }
2652#endif
2653 }
2654}
2655
Thomas Winischhofer544393f2005-09-09 13:04:45 -07002656static void __devinit
2657sisfb_get_VB_type(struct sis_video_info *ivideo)
2658{
2659 char stdstr[] = "sisfb: Detected";
2660 char bridgestr[] = "video bridge";
2661 u8 vb_chipid;
2662 u8 reg;
2663
2664 /* No CRT2 on XGI Z7 */
2665 if(ivideo->chip == XGI_20)
2666 return;
2667
Aaro Koskinene57d4132010-12-20 23:50:16 +02002668 vb_chipid = SiS_GetReg(SISPART4, 0x00);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07002669 switch(vb_chipid) {
2670 case 0x01:
Aaro Koskinene57d4132010-12-20 23:50:16 +02002671 reg = SiS_GetReg(SISPART4, 0x01);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07002672 if(reg < 0xb0) {
2673 ivideo->vbflags |= VB_301; /* Deprecated */
2674 ivideo->vbflags2 |= VB2_301;
2675 printk(KERN_INFO "%s SiS301 %s\n", stdstr, bridgestr);
2676 } else if(reg < 0xc0) {
2677 ivideo->vbflags |= VB_301B; /* Deprecated */
2678 ivideo->vbflags2 |= VB2_301B;
Aaro Koskinene57d4132010-12-20 23:50:16 +02002679 reg = SiS_GetReg(SISPART4, 0x23);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07002680 if(!(reg & 0x02)) {
2681 ivideo->vbflags |= VB_30xBDH; /* Deprecated */
2682 ivideo->vbflags2 |= VB2_30xBDH;
2683 printk(KERN_INFO "%s SiS301B-DH %s\n", stdstr, bridgestr);
2684 } else {
2685 printk(KERN_INFO "%s SiS301B %s\n", stdstr, bridgestr);
2686 }
2687 } else if(reg < 0xd0) {
2688 ivideo->vbflags |= VB_301C; /* Deprecated */
2689 ivideo->vbflags2 |= VB2_301C;
2690 printk(KERN_INFO "%s SiS301C %s\n", stdstr, bridgestr);
2691 } else if(reg < 0xe0) {
2692 ivideo->vbflags |= VB_301LV; /* Deprecated */
2693 ivideo->vbflags2 |= VB2_301LV;
2694 printk(KERN_INFO "%s SiS301LV %s\n", stdstr, bridgestr);
2695 } else if(reg <= 0xe1) {
Aaro Koskinene57d4132010-12-20 23:50:16 +02002696 reg = SiS_GetReg(SISPART4, 0x39);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07002697 if(reg == 0xff) {
2698 ivideo->vbflags |= VB_302LV; /* Deprecated */
2699 ivideo->vbflags2 |= VB2_302LV;
2700 printk(KERN_INFO "%s SiS302LV %s\n", stdstr, bridgestr);
2701 } else {
2702 ivideo->vbflags |= VB_301C; /* Deprecated */
2703 ivideo->vbflags2 |= VB2_301C;
2704 printk(KERN_INFO "%s SiS301C(P4) %s\n", stdstr, bridgestr);
2705#if 0
2706 ivideo->vbflags |= VB_302ELV; /* Deprecated */
2707 ivideo->vbflags2 |= VB2_302ELV;
2708 printk(KERN_INFO "%s SiS302ELV %s\n", stdstr, bridgestr);
2709#endif
2710 }
2711 }
2712 break;
2713 case 0x02:
2714 ivideo->vbflags |= VB_302B; /* Deprecated */
2715 ivideo->vbflags2 |= VB2_302B;
2716 printk(KERN_INFO "%s SiS302B %s\n", stdstr, bridgestr);
2717 break;
2718 }
2719
2720 if((!(ivideo->vbflags2 & VB2_VIDEOBRIDGE)) && (ivideo->chip != SIS_300)) {
Aaro Koskinene57d4132010-12-20 23:50:16 +02002721 reg = SiS_GetReg(SISCR, 0x37);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07002722 reg &= SIS_EXTERNAL_CHIP_MASK;
2723 reg >>= 1;
2724 if(ivideo->sisvga_engine == SIS_300_VGA) {
2725#ifdef CONFIG_FB_SIS_300
2726 switch(reg) {
2727 case SIS_EXTERNAL_CHIP_LVDS:
2728 ivideo->vbflags |= VB_LVDS; /* Deprecated */
2729 ivideo->vbflags2 |= VB2_LVDS;
2730 break;
2731 case SIS_EXTERNAL_CHIP_TRUMPION:
2732 ivideo->vbflags |= (VB_LVDS | VB_TRUMPION); /* Deprecated */
2733 ivideo->vbflags2 |= (VB2_LVDS | VB2_TRUMPION);
2734 break;
2735 case SIS_EXTERNAL_CHIP_CHRONTEL:
2736 ivideo->vbflags |= VB_CHRONTEL; /* Deprecated */
2737 ivideo->vbflags2 |= VB2_CHRONTEL;
2738 break;
2739 case SIS_EXTERNAL_CHIP_LVDS_CHRONTEL:
2740 ivideo->vbflags |= (VB_LVDS | VB_CHRONTEL); /* Deprecated */
2741 ivideo->vbflags2 |= (VB2_LVDS | VB2_CHRONTEL);
2742 break;
2743 }
2744 if(ivideo->vbflags2 & VB2_CHRONTEL) ivideo->chronteltype = 1;
2745#endif
2746 } else if(ivideo->chip < SIS_661) {
2747#ifdef CONFIG_FB_SIS_315
2748 switch (reg) {
2749 case SIS310_EXTERNAL_CHIP_LVDS:
2750 ivideo->vbflags |= VB_LVDS; /* Deprecated */
2751 ivideo->vbflags2 |= VB2_LVDS;
2752 break;
2753 case SIS310_EXTERNAL_CHIP_LVDS_CHRONTEL:
2754 ivideo->vbflags |= (VB_LVDS | VB_CHRONTEL); /* Deprecated */
2755 ivideo->vbflags2 |= (VB2_LVDS | VB2_CHRONTEL);
2756 break;
2757 }
2758 if(ivideo->vbflags2 & VB2_CHRONTEL) ivideo->chronteltype = 2;
2759#endif
2760 } else if(ivideo->chip >= SIS_661) {
2761#ifdef CONFIG_FB_SIS_315
Aaro Koskinene57d4132010-12-20 23:50:16 +02002762 reg = SiS_GetReg(SISCR, 0x38);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07002763 reg >>= 5;
2764 switch(reg) {
2765 case 0x02:
2766 ivideo->vbflags |= VB_LVDS; /* Deprecated */
2767 ivideo->vbflags2 |= VB2_LVDS;
2768 break;
2769 case 0x03:
2770 ivideo->vbflags |= (VB_LVDS | VB_CHRONTEL); /* Deprecated */
2771 ivideo->vbflags2 |= (VB2_LVDS | VB2_CHRONTEL);
2772 break;
2773 case 0x04:
2774 ivideo->vbflags |= (VB_LVDS | VB_CONEXANT); /* Deprecated */
2775 ivideo->vbflags2 |= (VB2_LVDS | VB2_CONEXANT);
2776 break;
2777 }
2778 if(ivideo->vbflags2 & VB2_CHRONTEL) ivideo->chronteltype = 2;
2779#endif
2780 }
2781 if(ivideo->vbflags2 & VB2_LVDS) {
2782 printk(KERN_INFO "%s LVDS transmitter\n", stdstr);
2783 }
2784 if((ivideo->sisvga_engine == SIS_300_VGA) && (ivideo->vbflags2 & VB2_TRUMPION)) {
2785 printk(KERN_INFO "%s Trumpion Zurac LCD scaler\n", stdstr);
2786 }
2787 if(ivideo->vbflags2 & VB2_CHRONTEL) {
2788 printk(KERN_INFO "%s Chrontel TV encoder\n", stdstr);
2789 }
2790 if((ivideo->chip >= SIS_661) && (ivideo->vbflags2 & VB2_CONEXANT)) {
2791 printk(KERN_INFO "%s Conexant external device\n", stdstr);
2792 }
2793 }
2794
2795 if(ivideo->vbflags2 & VB2_SISBRIDGE) {
2796 SiS_SenseLCD(ivideo);
2797 SiS_Sense30x(ivideo);
2798 } else if(ivideo->vbflags2 & VB2_CHRONTEL) {
2799 SiS_SenseCh(ivideo);
2800 }
2801}
2802
2803/* ---------- Engine initialization routines ------------ */
2804
2805static void
2806sisfb_engine_init(struct sis_video_info *ivideo)
2807{
2808
2809 /* Initialize command queue (we use MMIO only) */
2810
2811 /* BEFORE THIS IS CALLED, THE ENGINES *MUST* BE SYNC'ED */
2812
2813 ivideo->caps &= ~(TURBO_QUEUE_CAP |
2814 MMIO_CMD_QUEUE_CAP |
2815 VM_CMD_QUEUE_CAP |
2816 AGP_CMD_QUEUE_CAP);
2817
2818#ifdef CONFIG_FB_SIS_300
2819 if(ivideo->sisvga_engine == SIS_300_VGA) {
2820 u32 tqueue_pos;
2821 u8 tq_state;
2822
2823 tqueue_pos = (ivideo->video_size - ivideo->cmdQueueSize) / (64 * 1024);
2824
Aaro Koskinene57d4132010-12-20 23:50:16 +02002825 tq_state = SiS_GetReg(SISSR, IND_SIS_TURBOQUEUE_SET);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07002826 tq_state |= 0xf0;
2827 tq_state &= 0xfc;
2828 tq_state |= (u8)(tqueue_pos >> 8);
Aaro Koskinen44b751b2010-12-20 23:50:17 +02002829 SiS_SetReg(SISSR, IND_SIS_TURBOQUEUE_SET, tq_state);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07002830
Aaro Koskinen44b751b2010-12-20 23:50:17 +02002831 SiS_SetReg(SISSR, IND_SIS_TURBOQUEUE_ADR, (u8)(tqueue_pos & 0xff));
Thomas Winischhofer544393f2005-09-09 13:04:45 -07002832
2833 ivideo->caps |= TURBO_QUEUE_CAP;
2834 }
2835#endif
2836
2837#ifdef CONFIG_FB_SIS_315
2838 if(ivideo->sisvga_engine == SIS_315_VGA) {
2839 u32 tempq = 0, templ;
2840 u8 temp;
2841
2842 if(ivideo->chip == XGI_20) {
2843 switch(ivideo->cmdQueueSize) {
2844 case (64 * 1024):
2845 temp = SIS_CMD_QUEUE_SIZE_Z7_64k;
2846 break;
2847 case (128 * 1024):
2848 default:
2849 temp = SIS_CMD_QUEUE_SIZE_Z7_128k;
2850 }
2851 } else {
2852 switch(ivideo->cmdQueueSize) {
2853 case (4 * 1024 * 1024):
2854 temp = SIS_CMD_QUEUE_SIZE_4M;
2855 break;
2856 case (2 * 1024 * 1024):
2857 temp = SIS_CMD_QUEUE_SIZE_2M;
2858 break;
2859 case (1 * 1024 * 1024):
2860 temp = SIS_CMD_QUEUE_SIZE_1M;
2861 break;
2862 default:
2863 case (512 * 1024):
2864 temp = SIS_CMD_QUEUE_SIZE_512k;
2865 }
2866 }
2867
Aaro Koskinen44b751b2010-12-20 23:50:17 +02002868 SiS_SetReg(SISSR, IND_SIS_CMDQUEUE_THRESHOLD, COMMAND_QUEUE_THRESHOLD);
2869 SiS_SetReg(SISSR, IND_SIS_CMDQUEUE_SET, SIS_CMD_QUEUE_RESET);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07002870
2871 if((ivideo->chip >= XGI_40) && ivideo->modechanged) {
2872 /* Must disable dual pipe on XGI_40. Can't do
2873 * this in MMIO mode, because it requires
2874 * setting/clearing a bit in the MMIO fire trigger
2875 * register.
2876 */
2877 if(!((templ = MMIO_IN32(ivideo->mmio_vbase, 0x8240)) & (1 << 10))) {
2878
2879 MMIO_OUT32(ivideo->mmio_vbase, Q_WRITE_PTR, 0);
2880
Aaro Koskinen44b751b2010-12-20 23:50:17 +02002881 SiS_SetReg(SISSR, IND_SIS_CMDQUEUE_SET, (temp | SIS_VRAM_CMDQUEUE_ENABLE));
Thomas Winischhofer544393f2005-09-09 13:04:45 -07002882
2883 tempq = MMIO_IN32(ivideo->mmio_vbase, Q_READ_PTR);
2884 MMIO_OUT32(ivideo->mmio_vbase, Q_WRITE_PTR, tempq);
2885
2886 tempq = (u32)(ivideo->video_size - ivideo->cmdQueueSize);
2887 MMIO_OUT32(ivideo->mmio_vbase, Q_BASE_ADDR, tempq);
2888
2889 writel(0x16800000 + 0x8240, ivideo->video_vbase + tempq);
2890 writel(templ | (1 << 10), ivideo->video_vbase + tempq + 4);
2891 writel(0x168F0000, ivideo->video_vbase + tempq + 8);
2892 writel(0x168F0000, ivideo->video_vbase + tempq + 12);
2893
2894 MMIO_OUT32(ivideo->mmio_vbase, Q_WRITE_PTR, (tempq + 16));
2895
2896 sisfb_syncaccel(ivideo);
2897
Aaro Koskinen44b751b2010-12-20 23:50:17 +02002898 SiS_SetReg(SISSR, IND_SIS_CMDQUEUE_SET, SIS_CMD_QUEUE_RESET);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07002899
2900 }
2901 }
2902
2903 tempq = MMIO_IN32(ivideo->mmio_vbase, MMIO_QUEUE_READPORT);
2904 MMIO_OUT32(ivideo->mmio_vbase, MMIO_QUEUE_WRITEPORT, tempq);
2905
2906 temp |= (SIS_MMIO_CMD_ENABLE | SIS_CMD_AUTO_CORR);
Aaro Koskinen44b751b2010-12-20 23:50:17 +02002907 SiS_SetReg(SISSR, IND_SIS_CMDQUEUE_SET, temp);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07002908
2909 tempq = (u32)(ivideo->video_size - ivideo->cmdQueueSize);
2910 MMIO_OUT32(ivideo->mmio_vbase, MMIO_QUEUE_PHYBASE, tempq);
2911
2912 ivideo->caps |= MMIO_CMD_QUEUE_CAP;
2913 }
2914#endif
2915
2916 ivideo->engineok = 1;
2917}
2918
2919static void __devinit
2920sisfb_detect_lcd_type(struct sis_video_info *ivideo)
2921{
2922 u8 reg;
2923 int i;
2924
Aaro Koskinene57d4132010-12-20 23:50:16 +02002925 reg = SiS_GetReg(SISCR, 0x36);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07002926 reg &= 0x0f;
2927 if(ivideo->sisvga_engine == SIS_300_VGA) {
2928 ivideo->CRT2LCDType = sis300paneltype[reg];
2929 } else if(ivideo->chip >= SIS_661) {
2930 ivideo->CRT2LCDType = sis661paneltype[reg];
2931 } else {
2932 ivideo->CRT2LCDType = sis310paneltype[reg];
2933 if((ivideo->chip == SIS_550) && (sisfb_fstn)) {
2934 if((ivideo->CRT2LCDType != LCD_320x240_2) &&
2935 (ivideo->CRT2LCDType != LCD_320x240_3)) {
2936 ivideo->CRT2LCDType = LCD_320x240;
2937 }
2938 }
2939 }
2940
2941 if(ivideo->CRT2LCDType == LCD_UNKNOWN) {
2942 /* For broken BIOSes: Assume 1024x768, RGB18 */
2943 ivideo->CRT2LCDType = LCD_1024x768;
Aaro Koskinenad78adb2010-12-20 23:50:20 +02002944 SiS_SetRegANDOR(SISCR, 0x36, 0xf0, 0x02);
2945 SiS_SetRegANDOR(SISCR, 0x37, 0xee, 0x01);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07002946 printk(KERN_DEBUG "sisfb: Invalid panel ID (%02x), assuming 1024x768, RGB18\n", reg);
2947 }
2948
2949 for(i = 0; i < SIS_LCD_NUMBER; i++) {
2950 if(ivideo->CRT2LCDType == sis_lcd_data[i].lcdtype) {
2951 ivideo->lcdxres = sis_lcd_data[i].xres;
2952 ivideo->lcdyres = sis_lcd_data[i].yres;
2953 ivideo->lcddefmodeidx = sis_lcd_data[i].default_mode_idx;
2954 break;
2955 }
2956 }
2957
2958#ifdef CONFIG_FB_SIS_300
2959 if(ivideo->SiS_Pr.SiS_CustomT == CUT_BARCO1366) {
2960 ivideo->lcdxres = 1360; ivideo->lcdyres = 1024;
2961 ivideo->lcddefmodeidx = DEFAULT_MODE_1360;
2962 } else if(ivideo->SiS_Pr.SiS_CustomT == CUT_PANEL848) {
2963 ivideo->lcdxres = 848; ivideo->lcdyres = 480;
2964 ivideo->lcddefmodeidx = DEFAULT_MODE_848;
2965 } else if(ivideo->SiS_Pr.SiS_CustomT == CUT_PANEL856) {
2966 ivideo->lcdxres = 856; ivideo->lcdyres = 480;
2967 ivideo->lcddefmodeidx = DEFAULT_MODE_856;
2968 }
2969#endif
2970
2971 printk(KERN_DEBUG "sisfb: Detected %dx%d flat panel\n",
2972 ivideo->lcdxres, ivideo->lcdyres);
2973}
2974
2975static void __devinit
2976sisfb_save_pdc_emi(struct sis_video_info *ivideo)
2977{
2978#ifdef CONFIG_FB_SIS_300
2979 /* Save the current PanelDelayCompensation if the LCD is currently used */
2980 if(ivideo->sisvga_engine == SIS_300_VGA) {
2981 if(ivideo->vbflags2 & (VB2_LVDS | VB2_30xBDH)) {
2982 int tmp;
Aaro Koskinene57d4132010-12-20 23:50:16 +02002983 tmp = SiS_GetReg(SISCR, 0x30);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07002984 if(tmp & 0x20) {
2985 /* Currently on LCD? If yes, read current pdc */
Aaro Koskinene57d4132010-12-20 23:50:16 +02002986 ivideo->detectedpdc = SiS_GetReg(SISPART1, 0x13);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07002987 ivideo->detectedpdc &= 0x3c;
2988 if(ivideo->SiS_Pr.PDC == -1) {
2989 /* Let option override detection */
2990 ivideo->SiS_Pr.PDC = ivideo->detectedpdc;
2991 }
2992 printk(KERN_INFO "sisfb: Detected LCD PDC 0x%02x\n",
2993 ivideo->detectedpdc);
2994 }
2995 if((ivideo->SiS_Pr.PDC != -1) &&
2996 (ivideo->SiS_Pr.PDC != ivideo->detectedpdc)) {
2997 printk(KERN_INFO "sisfb: Using LCD PDC 0x%02x\n",
2998 ivideo->SiS_Pr.PDC);
2999 }
3000 }
3001 }
3002#endif
3003
3004#ifdef CONFIG_FB_SIS_315
3005 if(ivideo->sisvga_engine == SIS_315_VGA) {
3006
3007 /* Try to find about LCDA */
3008 if(ivideo->vbflags2 & VB2_SISLCDABRIDGE) {
3009 int tmp;
Aaro Koskinene57d4132010-12-20 23:50:16 +02003010 tmp = SiS_GetReg(SISPART1, 0x13);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003011 if(tmp & 0x04) {
Richard Knutssonc30660ea2007-02-12 00:55:06 -08003012 ivideo->SiS_Pr.SiS_UseLCDA = true;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003013 ivideo->detectedlcda = 0x03;
3014 }
3015 }
3016
3017 /* Save PDC */
3018 if(ivideo->vbflags2 & VB2_SISLVDSBRIDGE) {
3019 int tmp;
Aaro Koskinene57d4132010-12-20 23:50:16 +02003020 tmp = SiS_GetReg(SISCR, 0x30);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003021 if((tmp & 0x20) || (ivideo->detectedlcda != 0xff)) {
3022 /* Currently on LCD? If yes, read current pdc */
3023 u8 pdc;
Aaro Koskinene57d4132010-12-20 23:50:16 +02003024 pdc = SiS_GetReg(SISPART1, 0x2D);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003025 ivideo->detectedpdc = (pdc & 0x0f) << 1;
3026 ivideo->detectedpdca = (pdc & 0xf0) >> 3;
Aaro Koskinene57d4132010-12-20 23:50:16 +02003027 pdc = SiS_GetReg(SISPART1, 0x35);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003028 ivideo->detectedpdc |= ((pdc >> 7) & 0x01);
Aaro Koskinene57d4132010-12-20 23:50:16 +02003029 pdc = SiS_GetReg(SISPART1, 0x20);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003030 ivideo->detectedpdca |= ((pdc >> 6) & 0x01);
3031 if(ivideo->newrom) {
3032 /* New ROM invalidates other PDC resp. */
3033 if(ivideo->detectedlcda != 0xff) {
3034 ivideo->detectedpdc = 0xff;
3035 } else {
3036 ivideo->detectedpdca = 0xff;
3037 }
3038 }
3039 if(ivideo->SiS_Pr.PDC == -1) {
3040 if(ivideo->detectedpdc != 0xff) {
3041 ivideo->SiS_Pr.PDC = ivideo->detectedpdc;
3042 }
3043 }
3044 if(ivideo->SiS_Pr.PDCA == -1) {
3045 if(ivideo->detectedpdca != 0xff) {
3046 ivideo->SiS_Pr.PDCA = ivideo->detectedpdca;
3047 }
3048 }
3049 if(ivideo->detectedpdc != 0xff) {
3050 printk(KERN_INFO
3051 "sisfb: Detected LCD PDC 0x%02x (for LCD=CRT2)\n",
3052 ivideo->detectedpdc);
3053 }
3054 if(ivideo->detectedpdca != 0xff) {
3055 printk(KERN_INFO
3056 "sisfb: Detected LCD PDC1 0x%02x (for LCD=CRT1)\n",
3057 ivideo->detectedpdca);
3058 }
3059 }
3060
3061 /* Save EMI */
3062 if(ivideo->vbflags2 & VB2_SISEMIBRIDGE) {
Aaro Koskinene57d4132010-12-20 23:50:16 +02003063 ivideo->SiS_Pr.EMI_30 = SiS_GetReg(SISPART4, 0x30);
3064 ivideo->SiS_Pr.EMI_31 = SiS_GetReg(SISPART4, 0x31);
3065 ivideo->SiS_Pr.EMI_32 = SiS_GetReg(SISPART4, 0x32);
3066 ivideo->SiS_Pr.EMI_33 = SiS_GetReg(SISPART4, 0x33);
Richard Knutssonc30660ea2007-02-12 00:55:06 -08003067 ivideo->SiS_Pr.HaveEMI = true;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003068 if((tmp & 0x20) || (ivideo->detectedlcda != 0xff)) {
Richard Knutssonc30660ea2007-02-12 00:55:06 -08003069 ivideo->SiS_Pr.HaveEMILCD = true;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003070 }
3071 }
3072 }
3073
3074 /* Let user override detected PDCs (all bridges) */
3075 if(ivideo->vbflags2 & VB2_30xBLV) {
3076 if((ivideo->SiS_Pr.PDC != -1) &&
3077 (ivideo->SiS_Pr.PDC != ivideo->detectedpdc)) {
3078 printk(KERN_INFO "sisfb: Using LCD PDC 0x%02x (for LCD=CRT2)\n",
3079 ivideo->SiS_Pr.PDC);
3080 }
3081 if((ivideo->SiS_Pr.PDCA != -1) &&
3082 (ivideo->SiS_Pr.PDCA != ivideo->detectedpdca)) {
3083 printk(KERN_INFO "sisfb: Using LCD PDC1 0x%02x (for LCD=CRT1)\n",
3084 ivideo->SiS_Pr.PDCA);
3085 }
3086 }
3087
3088 }
3089#endif
3090}
3091
3092/* -------------------- Memory manager routines ---------------------- */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003093
3094static u32 __devinit
3095sisfb_getheapstart(struct sis_video_info *ivideo)
3096{
3097 u32 ret = ivideo->sisfb_parm_mem * 1024;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003098 u32 maxoffs = ivideo->video_size - ivideo->hwcursor_size - ivideo->cmdQueueSize;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003099 u32 def;
3100
3101 /* Calculate heap start = end of memory for console
3102 *
3103 * CCCCCCCCDDDDDDDDDDDDDDDDDDDDDDDDDDDDHHHHQQQQQQQQQQ
3104 * C = console, D = heap, H = HWCursor, Q = cmd-queue
3105 *
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003106 * On 76x in UMA+LFB mode, the layout is as follows:
3107 * DDDDDDDDDDDCCCCCCCCCCCCCCCCCCCCCCCCHHHHQQQQQQQQQQQ
3108 * where the heap is the entire UMA area, eventually
3109 * into the LFB area if the given mem parameter is
3110 * higher than the size of the UMA memory.
3111 *
Linus Torvalds1da177e2005-04-16 15:20:36 -07003112 * Basically given by "mem" parameter
3113 *
3114 * maximum = videosize - cmd_queue - hwcursor
3115 * (results in a heap of size 0)
3116 * default = SiS 300: depends on videosize
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003117 * SiS 315/330/340/XGI: 32k below max
Linus Torvalds1da177e2005-04-16 15:20:36 -07003118 */
3119
3120 if(ivideo->sisvga_engine == SIS_300_VGA) {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003121 if(ivideo->video_size > 0x1000000) {
3122 def = 0xc00000;
3123 } else if(ivideo->video_size > 0x800000) {
3124 def = 0x800000;
3125 } else {
3126 def = 0x400000;
3127 }
3128 } else if(ivideo->UMAsize && ivideo->LFBsize) {
3129 ret = def = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003130 } else {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003131 def = maxoffs - 0x8000;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003132 }
3133
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003134 /* Use default for secondary card for now (FIXME) */
3135 if((!ret) || (ret > maxoffs) || (ivideo->cardnumber != 0))
3136 ret = def;
3137
3138 return ret;
3139}
3140
3141static u32 __devinit
3142sisfb_getheapsize(struct sis_video_info *ivideo)
3143{
3144 u32 max = ivideo->video_size - ivideo->hwcursor_size - ivideo->cmdQueueSize;
3145 u32 ret = 0;
3146
3147 if(ivideo->UMAsize && ivideo->LFBsize) {
3148 if( (!ivideo->sisfb_parm_mem) ||
3149 ((ivideo->sisfb_parm_mem * 1024) > max) ||
3150 ((max - (ivideo->sisfb_parm_mem * 1024)) < ivideo->UMAsize) ) {
3151 ret = ivideo->UMAsize;
3152 max -= ivideo->UMAsize;
3153 } else {
3154 ret = max - (ivideo->sisfb_parm_mem * 1024);
3155 max = ivideo->sisfb_parm_mem * 1024;
3156 }
3157 ivideo->video_offset = ret;
3158 ivideo->sisfb_mem = max;
3159 } else {
3160 ret = max - ivideo->heapstart;
3161 ivideo->sisfb_mem = ivideo->heapstart;
3162 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003163
3164 return ret;
3165}
3166
3167static int __devinit
3168sisfb_heap_init(struct sis_video_info *ivideo)
3169{
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003170 struct SIS_OH *poh;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003171
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003172 ivideo->video_offset = 0;
3173 if(ivideo->sisfb_parm_mem) {
3174 if( (ivideo->sisfb_parm_mem < (2 * 1024 * 1024)) ||
3175 (ivideo->sisfb_parm_mem > ivideo->video_size) ) {
3176 ivideo->sisfb_parm_mem = 0;
3177 }
3178 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003179
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003180 ivideo->heapstart = sisfb_getheapstart(ivideo);
3181 ivideo->sisfb_heap_size = sisfb_getheapsize(ivideo);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003182
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003183 ivideo->sisfb_heap_start = ivideo->video_vbase + ivideo->heapstart;
3184 ivideo->sisfb_heap_end = ivideo->sisfb_heap_start + ivideo->sisfb_heap_size;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003185
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003186 printk(KERN_INFO "sisfb: Memory heap starting at %dK, size %dK\n",
3187 (int)(ivideo->heapstart / 1024), (int)(ivideo->sisfb_heap_size / 1024));
Linus Torvalds1da177e2005-04-16 15:20:36 -07003188
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003189 ivideo->sisfb_heap.vinfo = ivideo;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003190
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003191 ivideo->sisfb_heap.poha_chain = NULL;
3192 ivideo->sisfb_heap.poh_freelist = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003193
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003194 poh = sisfb_poh_new_node(&ivideo->sisfb_heap);
3195 if(poh == NULL)
3196 return 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003197
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003198 poh->poh_next = &ivideo->sisfb_heap.oh_free;
3199 poh->poh_prev = &ivideo->sisfb_heap.oh_free;
3200 poh->size = ivideo->sisfb_heap_size;
3201 poh->offset = ivideo->heapstart;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003202
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003203 ivideo->sisfb_heap.oh_free.poh_next = poh;
3204 ivideo->sisfb_heap.oh_free.poh_prev = poh;
3205 ivideo->sisfb_heap.oh_free.size = 0;
3206 ivideo->sisfb_heap.max_freesize = poh->size;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003207
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003208 ivideo->sisfb_heap.oh_used.poh_next = &ivideo->sisfb_heap.oh_used;
3209 ivideo->sisfb_heap.oh_used.poh_prev = &ivideo->sisfb_heap.oh_used;
3210 ivideo->sisfb_heap.oh_used.size = SENTINEL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003211
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003212 if(ivideo->cardnumber == 0) {
3213 /* For the first card, make this heap the "global" one
3214 * for old DRM (which could handle only one card)
3215 */
3216 sisfb_heap = &ivideo->sisfb_heap;
3217 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003218
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003219 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003220}
3221
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003222static struct SIS_OH *
3223sisfb_poh_new_node(struct SIS_HEAP *memheap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003224{
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003225 struct SIS_OHALLOC *poha;
3226 struct SIS_OH *poh;
3227 unsigned long cOhs;
3228 int i;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003229
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003230 if(memheap->poh_freelist == NULL) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003231 poha = kmalloc(SIS_OH_ALLOC_SIZE, GFP_KERNEL);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003232 if(!poha)
3233 return NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003234
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003235 poha->poha_next = memheap->poha_chain;
3236 memheap->poha_chain = poha;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003237
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003238 cOhs = (SIS_OH_ALLOC_SIZE - sizeof(struct SIS_OHALLOC)) / sizeof(struct SIS_OH) + 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003239
3240 poh = &poha->aoh[0];
3241 for(i = cOhs - 1; i != 0; i--) {
3242 poh->poh_next = poh + 1;
3243 poh = poh + 1;
3244 }
3245
3246 poh->poh_next = NULL;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003247 memheap->poh_freelist = &poha->aoh[0];
Linus Torvalds1da177e2005-04-16 15:20:36 -07003248 }
3249
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003250 poh = memheap->poh_freelist;
3251 memheap->poh_freelist = poh->poh_next;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003252
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003253 return poh;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003254}
3255
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003256static struct SIS_OH *
3257sisfb_poh_allocate(struct SIS_HEAP *memheap, u32 size)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003258{
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003259 struct SIS_OH *pohThis;
3260 struct SIS_OH *pohRoot;
3261 int bAllocated = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003262
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003263 if(size > memheap->max_freesize) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003264 DPRINTK("sisfb: Can't allocate %dk video memory\n",
3265 (unsigned int) size / 1024);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003266 return NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003267 }
3268
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003269 pohThis = memheap->oh_free.poh_next;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003270
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003271 while(pohThis != &memheap->oh_free) {
3272 if(size <= pohThis->size) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003273 bAllocated = 1;
3274 break;
3275 }
3276 pohThis = pohThis->poh_next;
3277 }
3278
3279 if(!bAllocated) {
3280 DPRINTK("sisfb: Can't allocate %dk video memory\n",
3281 (unsigned int) size / 1024);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003282 return NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003283 }
3284
3285 if(size == pohThis->size) {
3286 pohRoot = pohThis;
3287 sisfb_delete_node(pohThis);
3288 } else {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003289 pohRoot = sisfb_poh_new_node(memheap);
3290 if(pohRoot == NULL)
3291 return NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003292
3293 pohRoot->offset = pohThis->offset;
3294 pohRoot->size = size;
3295
3296 pohThis->offset += size;
3297 pohThis->size -= size;
3298 }
3299
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003300 memheap->max_freesize -= size;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003301
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003302 pohThis = &memheap->oh_used;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003303 sisfb_insert_node(pohThis, pohRoot);
3304
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003305 return pohRoot;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003306}
3307
3308static void
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003309sisfb_delete_node(struct SIS_OH *poh)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003310{
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003311 poh->poh_prev->poh_next = poh->poh_next;
3312 poh->poh_next->poh_prev = poh->poh_prev;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003313}
3314
3315static void
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003316sisfb_insert_node(struct SIS_OH *pohList, struct SIS_OH *poh)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003317{
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003318 struct SIS_OH *pohTemp = pohList->poh_next;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003319
3320 pohList->poh_next = poh;
3321 pohTemp->poh_prev = poh;
3322
3323 poh->poh_prev = pohList;
3324 poh->poh_next = pohTemp;
3325}
3326
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003327static struct SIS_OH *
3328sisfb_poh_free(struct SIS_HEAP *memheap, u32 base)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003329{
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003330 struct SIS_OH *pohThis;
3331 struct SIS_OH *poh_freed;
3332 struct SIS_OH *poh_prev;
3333 struct SIS_OH *poh_next;
3334 u32 ulUpper;
3335 u32 ulLower;
3336 int foundNode = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003337
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003338 poh_freed = memheap->oh_used.poh_next;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003339
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003340 while(poh_freed != &memheap->oh_used) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003341 if(poh_freed->offset == base) {
3342 foundNode = 1;
3343 break;
3344 }
3345
3346 poh_freed = poh_freed->poh_next;
3347 }
3348
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003349 if(!foundNode)
3350 return NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003351
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003352 memheap->max_freesize += poh_freed->size;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003353
3354 poh_prev = poh_next = NULL;
3355 ulUpper = poh_freed->offset + poh_freed->size;
3356 ulLower = poh_freed->offset;
3357
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003358 pohThis = memheap->oh_free.poh_next;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003359
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003360 while(pohThis != &memheap->oh_free) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003361 if(pohThis->offset == ulUpper) {
3362 poh_next = pohThis;
3363 } else if((pohThis->offset + pohThis->size) == ulLower) {
3364 poh_prev = pohThis;
3365 }
3366 pohThis = pohThis->poh_next;
3367 }
3368
3369 sisfb_delete_node(poh_freed);
3370
3371 if(poh_prev && poh_next) {
3372 poh_prev->size += (poh_freed->size + poh_next->size);
3373 sisfb_delete_node(poh_next);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003374 sisfb_free_node(memheap, poh_freed);
3375 sisfb_free_node(memheap, poh_next);
3376 return poh_prev;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003377 }
3378
3379 if(poh_prev) {
3380 poh_prev->size += poh_freed->size;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003381 sisfb_free_node(memheap, poh_freed);
3382 return poh_prev;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003383 }
3384
3385 if(poh_next) {
3386 poh_next->size += poh_freed->size;
3387 poh_next->offset = poh_freed->offset;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003388 sisfb_free_node(memheap, poh_freed);
3389 return poh_next;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003390 }
3391
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003392 sisfb_insert_node(&memheap->oh_free, poh_freed);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003393
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003394 return poh_freed;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003395}
3396
3397static void
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003398sisfb_free_node(struct SIS_HEAP *memheap, struct SIS_OH *poh)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003399{
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003400 if(poh == NULL)
3401 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003402
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003403 poh->poh_next = memheap->poh_freelist;
3404 memheap->poh_freelist = poh;
3405}
3406
3407static void
3408sis_int_malloc(struct sis_video_info *ivideo, struct sis_memreq *req)
3409{
3410 struct SIS_OH *poh = NULL;
3411
3412 if((ivideo) && (ivideo->sisfb_id == SISFB_ID) && (!ivideo->havenoheap))
3413 poh = sisfb_poh_allocate(&ivideo->sisfb_heap, (u32)req->size);
3414
3415 if(poh == NULL) {
3416 req->offset = req->size = 0;
3417 DPRINTK("sisfb: Video RAM allocation failed\n");
3418 } else {
3419 req->offset = poh->offset;
3420 req->size = poh->size;
3421 DPRINTK("sisfb: Video RAM allocation succeeded: 0x%lx\n",
3422 (poh->offset + ivideo->video_vbase));
3423 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003424}
3425
3426void
3427sis_malloc(struct sis_memreq *req)
3428{
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003429 struct sis_video_info *ivideo = sisfb_heap->vinfo;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003430
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003431 if(&ivideo->sisfb_heap == sisfb_heap)
3432 sis_int_malloc(ivideo, req);
3433 else
3434 req->offset = req->size = 0;
3435}
Linus Torvalds1da177e2005-04-16 15:20:36 -07003436
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003437void
3438sis_malloc_new(struct pci_dev *pdev, struct sis_memreq *req)
3439{
3440 struct sis_video_info *ivideo = pci_get_drvdata(pdev);
3441
3442 sis_int_malloc(ivideo, req);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003443}
3444
3445/* sis_free: u32 because "base" is offset inside video ram, can never be >4GB */
3446
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003447static void
3448sis_int_free(struct sis_video_info *ivideo, u32 base)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003449{
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003450 struct SIS_OH *poh;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003451
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003452 if((!ivideo) || (ivideo->sisfb_id != SISFB_ID) || (ivideo->havenoheap))
3453 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003454
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003455 poh = sisfb_poh_free(&ivideo->sisfb_heap, base);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003456
3457 if(poh == NULL) {
3458 DPRINTK("sisfb: sisfb_poh_free() failed at base 0x%x\n",
3459 (unsigned int) base);
3460 }
3461}
3462
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003463void
3464sis_free(u32 base)
3465{
3466 struct sis_video_info *ivideo = sisfb_heap->vinfo;
3467
3468 sis_int_free(ivideo, base);
3469}
3470
3471void
3472sis_free_new(struct pci_dev *pdev, u32 base)
3473{
3474 struct sis_video_info *ivideo = pci_get_drvdata(pdev);
3475
3476 sis_int_free(ivideo, base);
3477}
3478
Linus Torvalds1da177e2005-04-16 15:20:36 -07003479/* --------------------- SetMode routines ------------------------- */
3480
3481static void
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003482sisfb_check_engine_and_sync(struct sis_video_info *ivideo)
3483{
3484 u8 cr30, cr31;
3485
3486 /* Check if MMIO and engines are enabled,
3487 * and sync in case they are. Can't use
3488 * ivideo->accel here, as this might have
3489 * been changed before this is called.
3490 */
Aaro Koskinene57d4132010-12-20 23:50:16 +02003491 cr30 = SiS_GetReg(SISSR, IND_SIS_PCI_ADDRESS_SET);
3492 cr31 = SiS_GetReg(SISSR, IND_SIS_MODULE_ENABLE);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003493 /* MMIO and 2D/3D engine enabled? */
3494 if((cr30 & SIS_MEM_MAP_IO_ENABLE) && (cr31 & 0x42)) {
3495#ifdef CONFIG_FB_SIS_300
3496 if(ivideo->sisvga_engine == SIS_300_VGA) {
3497 /* Don't care about TurboQueue. It's
3498 * enough to know that the engines
3499 * are enabled
3500 */
3501 sisfb_syncaccel(ivideo);
3502 }
3503#endif
3504#ifdef CONFIG_FB_SIS_315
3505 if(ivideo->sisvga_engine == SIS_315_VGA) {
3506 /* Check that any queue mode is
3507 * enabled, and that the queue
3508 * is not in the state of "reset"
3509 */
Aaro Koskinene57d4132010-12-20 23:50:16 +02003510 cr30 = SiS_GetReg(SISSR, 0x26);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003511 if((cr30 & 0xe0) && (!(cr30 & 0x01))) {
3512 sisfb_syncaccel(ivideo);
3513 }
3514 }
3515#endif
3516 }
3517}
3518
3519static void
Linus Torvalds1da177e2005-04-16 15:20:36 -07003520sisfb_pre_setmode(struct sis_video_info *ivideo)
3521{
3522 u8 cr30 = 0, cr31 = 0, cr33 = 0, cr35 = 0, cr38 = 0;
3523 int tvregnum = 0;
3524
3525 ivideo->currentvbflags &= (VB_VIDEOBRIDGE | VB_DISPTYPE_DISP2);
3526
Aaro Koskinen44b751b2010-12-20 23:50:17 +02003527 SiS_SetReg(SISSR, 0x05, 0x86);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003528
Aaro Koskinene57d4132010-12-20 23:50:16 +02003529 cr31 = SiS_GetReg(SISCR, 0x31);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003530 cr31 &= ~0x60;
3531 cr31 |= 0x04;
3532
3533 cr33 = ivideo->rate_idx & 0x0F;
3534
3535#ifdef CONFIG_FB_SIS_315
3536 if(ivideo->sisvga_engine == SIS_315_VGA) {
3537 if(ivideo->chip >= SIS_661) {
Aaro Koskinene57d4132010-12-20 23:50:16 +02003538 cr38 = SiS_GetReg(SISCR, 0x38);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003539 cr38 &= ~0x07; /* Clear LCDA/DualEdge and YPbPr bits */
3540 } else {
3541 tvregnum = 0x38;
Aaro Koskinene57d4132010-12-20 23:50:16 +02003542 cr38 = SiS_GetReg(SISCR, tvregnum);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003543 cr38 &= ~0x3b; /* Clear LCDA/DualEdge and YPbPr bits */
3544 }
3545 }
3546#endif
3547#ifdef CONFIG_FB_SIS_300
3548 if(ivideo->sisvga_engine == SIS_300_VGA) {
3549 tvregnum = 0x35;
Aaro Koskinene57d4132010-12-20 23:50:16 +02003550 cr38 = SiS_GetReg(SISCR, tvregnum);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003551 }
3552#endif
3553
Richard Knutssonc30660ea2007-02-12 00:55:06 -08003554 SiS_SetEnableDstn(&ivideo->SiS_Pr, false);
3555 SiS_SetEnableFstn(&ivideo->SiS_Pr, false);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003556 ivideo->curFSTN = ivideo->curDSTN = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003557
3558 switch(ivideo->currentvbflags & VB_DISPTYPE_DISP2) {
3559
3560 case CRT2_TV:
3561 cr38 &= ~0xc0; /* Clear PAL-M / PAL-N bits */
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003562 if((ivideo->vbflags & TV_YPBPR) && (ivideo->vbflags2 & VB2_SISYPBPRBRIDGE)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003563#ifdef CONFIG_FB_SIS_315
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003564 if(ivideo->chip >= SIS_661) {
3565 cr38 |= 0x04;
3566 if(ivideo->vbflags & TV_YPBPR525P) cr35 |= 0x20;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003567 else if(ivideo->vbflags & TV_YPBPR750P) cr35 |= 0x40;
3568 else if(ivideo->vbflags & TV_YPBPR1080I) cr35 |= 0x60;
3569 cr30 |= SIS_SIMULTANEOUS_VIEW_ENABLE;
3570 cr35 &= ~0x01;
3571 ivideo->currentvbflags |= (TV_YPBPR | (ivideo->vbflags & TV_YPBPRALL));
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003572 } else if(ivideo->sisvga_engine == SIS_315_VGA) {
3573 cr30 |= (0x80 | SIS_SIMULTANEOUS_VIEW_ENABLE);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003574 cr38 |= 0x08;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003575 if(ivideo->vbflags & TV_YPBPR525P) cr38 |= 0x10;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003576 else if(ivideo->vbflags & TV_YPBPR750P) cr38 |= 0x20;
3577 else if(ivideo->vbflags & TV_YPBPR1080I) cr38 |= 0x30;
3578 cr31 &= ~0x01;
3579 ivideo->currentvbflags |= (TV_YPBPR | (ivideo->vbflags & TV_YPBPRALL));
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003580 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003581#endif
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003582 } else if((ivideo->vbflags & TV_HIVISION) &&
3583 (ivideo->vbflags2 & VB2_SISHIVISIONBRIDGE)) {
3584 if(ivideo->chip >= SIS_661) {
3585 cr38 |= 0x04;
3586 cr35 |= 0x60;
3587 } else {
3588 cr30 |= 0x80;
3589 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003590 cr30 |= SIS_SIMULTANEOUS_VIEW_ENABLE;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003591 cr31 |= 0x01;
3592 cr35 |= 0x01;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003593 ivideo->currentvbflags |= TV_HIVISION;
3594 } else if(ivideo->vbflags & TV_SCART) {
3595 cr30 = (SIS_VB_OUTPUT_SCART | SIS_SIMULTANEOUS_VIEW_ENABLE);
3596 cr31 |= 0x01;
3597 cr35 |= 0x01;
3598 ivideo->currentvbflags |= TV_SCART;
3599 } else {
3600 if(ivideo->vbflags & TV_SVIDEO) {
3601 cr30 = (SIS_VB_OUTPUT_SVIDEO | SIS_SIMULTANEOUS_VIEW_ENABLE);
3602 ivideo->currentvbflags |= TV_SVIDEO;
3603 }
3604 if(ivideo->vbflags & TV_AVIDEO) {
3605 cr30 = (SIS_VB_OUTPUT_COMPOSITE | SIS_SIMULTANEOUS_VIEW_ENABLE);
3606 ivideo->currentvbflags |= TV_AVIDEO;
3607 }
3608 }
3609 cr31 |= SIS_DRIVER_MODE;
3610
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003611 if(ivideo->vbflags & (TV_AVIDEO | TV_SVIDEO)) {
3612 if(ivideo->vbflags & TV_PAL) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003613 cr31 |= 0x01; cr35 |= 0x01;
3614 ivideo->currentvbflags |= TV_PAL;
3615 if(ivideo->vbflags & TV_PALM) {
3616 cr38 |= 0x40; cr35 |= 0x04;
3617 ivideo->currentvbflags |= TV_PALM;
3618 } else if(ivideo->vbflags & TV_PALN) {
3619 cr38 |= 0x80; cr35 |= 0x08;
3620 ivideo->currentvbflags |= TV_PALN;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003621 }
3622 } else {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003623 cr31 &= ~0x01; cr35 &= ~0x01;
3624 ivideo->currentvbflags |= TV_NTSC;
3625 if(ivideo->vbflags & TV_NTSCJ) {
3626 cr38 |= 0x40; cr35 |= 0x02;
3627 ivideo->currentvbflags |= TV_NTSCJ;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003628 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003629 }
3630 }
3631 break;
3632
3633 case CRT2_LCD:
3634 cr30 = (SIS_VB_OUTPUT_LCD | SIS_SIMULTANEOUS_VIEW_ENABLE);
3635 cr31 |= SIS_DRIVER_MODE;
3636 SiS_SetEnableDstn(&ivideo->SiS_Pr, ivideo->sisfb_dstn);
3637 SiS_SetEnableFstn(&ivideo->SiS_Pr, ivideo->sisfb_fstn);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003638 ivideo->curFSTN = ivideo->sisfb_fstn;
3639 ivideo->curDSTN = ivideo->sisfb_dstn;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003640 break;
3641
3642 case CRT2_VGA:
3643 cr30 = (SIS_VB_OUTPUT_CRT2 | SIS_SIMULTANEOUS_VIEW_ENABLE);
3644 cr31 |= SIS_DRIVER_MODE;
3645 if(ivideo->sisfb_nocrt2rate) {
3646 cr33 |= (sisbios_mode[ivideo->sisfb_mode_idx].rate_idx << 4);
3647 } else {
3648 cr33 |= ((ivideo->rate_idx & 0x0F) << 4);
3649 }
3650 break;
3651
3652 default: /* disable CRT2 */
3653 cr30 = 0x00;
3654 cr31 |= (SIS_DRIVER_MODE | SIS_VB_OUTPUT_DISABLE);
3655 }
3656
Aaro Koskinen44b751b2010-12-20 23:50:17 +02003657 SiS_SetReg(SISCR, 0x30, cr30);
3658 SiS_SetReg(SISCR, 0x33, cr33);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003659
3660 if(ivideo->chip >= SIS_661) {
3661#ifdef CONFIG_FB_SIS_315
3662 cr31 &= ~0x01; /* Clear PAL flag (now in CR35) */
Aaro Koskinenad78adb2010-12-20 23:50:20 +02003663 SiS_SetRegANDOR(SISCR, 0x35, ~0x10, cr35); /* Leave overscan bit alone */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003664 cr38 &= 0x07; /* Use only LCDA and HiVision/YPbPr bits */
Aaro Koskinenad78adb2010-12-20 23:50:20 +02003665 SiS_SetRegANDOR(SISCR, 0x38, 0xf8, cr38);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003666#endif
3667 } else if(ivideo->chip != SIS_300) {
Aaro Koskinen44b751b2010-12-20 23:50:17 +02003668 SiS_SetReg(SISCR, tvregnum, cr38);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003669 }
Aaro Koskinen44b751b2010-12-20 23:50:17 +02003670 SiS_SetReg(SISCR, 0x31, cr31);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003671
Linus Torvalds1da177e2005-04-16 15:20:36 -07003672 ivideo->SiS_Pr.SiS_UseOEM = ivideo->sisfb_useoem;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003673
3674 sisfb_check_engine_and_sync(ivideo);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003675}
3676
3677/* Fix SR11 for 661 and later */
3678#ifdef CONFIG_FB_SIS_315
3679static void
3680sisfb_fixup_SR11(struct sis_video_info *ivideo)
3681{
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003682 u8 tmpreg;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003683
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003684 if(ivideo->chip >= SIS_661) {
Aaro Koskinene57d4132010-12-20 23:50:16 +02003685 tmpreg = SiS_GetReg(SISSR, 0x11);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003686 if(tmpreg & 0x20) {
Aaro Koskinene57d4132010-12-20 23:50:16 +02003687 tmpreg = SiS_GetReg(SISSR, 0x3e);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003688 tmpreg = (tmpreg + 1) & 0xff;
Aaro Koskinen44b751b2010-12-20 23:50:17 +02003689 SiS_SetReg(SISSR, 0x3e, tmpreg);
Aaro Koskinene57d4132010-12-20 23:50:16 +02003690 tmpreg = SiS_GetReg(SISSR, 0x11);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003691 }
3692 if(tmpreg & 0xf0) {
Aaro Koskinen667a8b42010-12-20 23:50:19 +02003693 SiS_SetRegAND(SISSR, 0x11, 0x0f);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003694 }
3695 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003696}
3697#endif
3698
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003699static void
3700sisfb_set_TVxposoffset(struct sis_video_info *ivideo, int val)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003701{
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003702 if(val > 32) val = 32;
3703 if(val < -32) val = -32;
3704 ivideo->tvxpos = val;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003705
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003706 if(ivideo->sisfblocked) return;
3707 if(!ivideo->modechanged) return;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003708
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003709 if(ivideo->currentvbflags & CRT2_TV) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003710
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003711 if(ivideo->vbflags2 & VB2_CHRONTEL) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003712
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003713 int x = ivideo->tvx;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003714
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003715 switch(ivideo->chronteltype) {
3716 case 1:
3717 x += val;
3718 if(x < 0) x = 0;
Aaro Koskinen44b751b2010-12-20 23:50:17 +02003719 SiS_SetReg(SISSR, 0x05, 0x86);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003720 SiS_SetCH700x(&ivideo->SiS_Pr, 0x0a, (x & 0xff));
3721 SiS_SetCH70xxANDOR(&ivideo->SiS_Pr, 0x08, ((x & 0x0100) >> 7), 0xFD);
3722 break;
3723 case 2:
3724 /* Not supported by hardware */
3725 break;
3726 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003727
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003728 } else if(ivideo->vbflags2 & VB2_SISBRIDGE) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003729
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003730 u8 p2_1f,p2_20,p2_2b,p2_42,p2_43;
3731 unsigned short temp;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003732
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003733 p2_1f = ivideo->p2_1f;
3734 p2_20 = ivideo->p2_20;
3735 p2_2b = ivideo->p2_2b;
3736 p2_42 = ivideo->p2_42;
3737 p2_43 = ivideo->p2_43;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003738
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003739 temp = p2_1f | ((p2_20 & 0xf0) << 4);
3740 temp += (val * 2);
3741 p2_1f = temp & 0xff;
3742 p2_20 = (temp & 0xf00) >> 4;
3743 p2_2b = ((p2_2b & 0x0f) + (val * 2)) & 0x0f;
3744 temp = p2_43 | ((p2_42 & 0xf0) << 4);
3745 temp += (val * 2);
3746 p2_43 = temp & 0xff;
3747 p2_42 = (temp & 0xf00) >> 4;
Aaro Koskinen44b751b2010-12-20 23:50:17 +02003748 SiS_SetReg(SISPART2, 0x1f, p2_1f);
Aaro Koskinenad78adb2010-12-20 23:50:20 +02003749 SiS_SetRegANDOR(SISPART2, 0x20, 0x0F, p2_20);
3750 SiS_SetRegANDOR(SISPART2, 0x2b, 0xF0, p2_2b);
3751 SiS_SetRegANDOR(SISPART2, 0x42, 0x0F, p2_42);
Aaro Koskinen44b751b2010-12-20 23:50:17 +02003752 SiS_SetReg(SISPART2, 0x43, p2_43);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003753 }
3754 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003755}
3756
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003757static void
3758sisfb_set_TVyposoffset(struct sis_video_info *ivideo, int val)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003759{
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003760 if(val > 32) val = 32;
3761 if(val < -32) val = -32;
3762 ivideo->tvypos = val;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003763
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003764 if(ivideo->sisfblocked) return;
3765 if(!ivideo->modechanged) return;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003766
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003767 if(ivideo->currentvbflags & CRT2_TV) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003768
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003769 if(ivideo->vbflags2 & VB2_CHRONTEL) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003770
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003771 int y = ivideo->tvy;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003772
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003773 switch(ivideo->chronteltype) {
3774 case 1:
3775 y -= val;
3776 if(y < 0) y = 0;
Aaro Koskinen44b751b2010-12-20 23:50:17 +02003777 SiS_SetReg(SISSR, 0x05, 0x86);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003778 SiS_SetCH700x(&ivideo->SiS_Pr, 0x0b, (y & 0xff));
3779 SiS_SetCH70xxANDOR(&ivideo->SiS_Pr, 0x08, ((y & 0x0100) >> 8), 0xFE);
3780 break;
3781 case 2:
3782 /* Not supported by hardware */
3783 break;
3784 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003785
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003786 } else if(ivideo->vbflags2 & VB2_SISBRIDGE) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003787
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003788 char p2_01, p2_02;
3789 val /= 2;
3790 p2_01 = ivideo->p2_01;
3791 p2_02 = ivideo->p2_02;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003792
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003793 p2_01 += val;
3794 p2_02 += val;
3795 if(!(ivideo->currentvbflags & (TV_HIVISION | TV_YPBPR))) {
3796 while((p2_01 <= 0) || (p2_02 <= 0)) {
3797 p2_01 += 2;
3798 p2_02 += 2;
3799 }
3800 }
Aaro Koskinen44b751b2010-12-20 23:50:17 +02003801 SiS_SetReg(SISPART2, 0x01, p2_01);
3802 SiS_SetReg(SISPART2, 0x02, p2_02);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003803 }
3804 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003805}
3806
3807static void
3808sisfb_post_setmode(struct sis_video_info *ivideo)
3809{
Richard Knutssonc30660ea2007-02-12 00:55:06 -08003810 bool crt1isoff = false;
3811 bool doit = true;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003812#if defined(CONFIG_FB_SIS_300) || defined(CONFIG_FB_SIS_315)
3813 u8 reg;
3814#endif
3815#ifdef CONFIG_FB_SIS_315
3816 u8 reg1;
3817#endif
3818
Aaro Koskinen44b751b2010-12-20 23:50:17 +02003819 SiS_SetReg(SISSR, 0x05, 0x86);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003820
3821#ifdef CONFIG_FB_SIS_315
3822 sisfb_fixup_SR11(ivideo);
3823#endif
3824
3825 /* Now we actually HAVE changed the display mode */
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003826 ivideo->modechanged = 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003827
3828 /* We can't switch off CRT1 if bridge is in slave mode */
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003829 if(ivideo->vbflags2 & VB2_VIDEOBRIDGE) {
Richard Knutssonc30660ea2007-02-12 00:55:06 -08003830 if(sisfb_bridgeisslave(ivideo)) doit = false;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003831 } else
3832 ivideo->sisfb_crt1off = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003833
3834#ifdef CONFIG_FB_SIS_300
3835 if(ivideo->sisvga_engine == SIS_300_VGA) {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003836 if((ivideo->sisfb_crt1off) && (doit)) {
Richard Knutssonc30660ea2007-02-12 00:55:06 -08003837 crt1isoff = true;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003838 reg = 0x00;
3839 } else {
Richard Knutssonc30660ea2007-02-12 00:55:06 -08003840 crt1isoff = false;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003841 reg = 0x80;
3842 }
Aaro Koskinenad78adb2010-12-20 23:50:20 +02003843 SiS_SetRegANDOR(SISCR, 0x17, 0x7f, reg);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003844 }
3845#endif
3846#ifdef CONFIG_FB_SIS_315
3847 if(ivideo->sisvga_engine == SIS_315_VGA) {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003848 if((ivideo->sisfb_crt1off) && (doit)) {
Richard Knutssonc30660ea2007-02-12 00:55:06 -08003849 crt1isoff = true;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003850 reg = 0x40;
3851 reg1 = 0xc0;
3852 } else {
Richard Knutssonc30660ea2007-02-12 00:55:06 -08003853 crt1isoff = false;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003854 reg = 0x00;
3855 reg1 = 0x00;
3856 }
Aaro Koskinenad78adb2010-12-20 23:50:20 +02003857 SiS_SetRegANDOR(SISCR, ivideo->SiS_Pr.SiS_MyCR63, ~0x40, reg);
Aaro Koskinen17d6ce12010-12-20 23:50:22 +02003858 SiS_SetRegANDOR(SISSR, 0x1f, 0x3f, reg1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003859 }
3860#endif
3861
3862 if(crt1isoff) {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003863 ivideo->currentvbflags &= ~VB_DISPTYPE_CRT1;
3864 ivideo->currentvbflags |= VB_SINGLE_MODE;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003865 } else {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003866 ivideo->currentvbflags |= VB_DISPTYPE_CRT1;
3867 if(ivideo->currentvbflags & VB_DISPTYPE_CRT2) {
3868 ivideo->currentvbflags |= VB_MIRROR_MODE;
3869 } else {
3870 ivideo->currentvbflags |= VB_SINGLE_MODE;
3871 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003872 }
3873
Aaro Koskinen667a8b42010-12-20 23:50:19 +02003874 SiS_SetRegAND(SISSR, IND_SIS_RAMDAC_CONTROL, ~0x04);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003875
3876 if(ivideo->currentvbflags & CRT2_TV) {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003877 if(ivideo->vbflags2 & VB2_SISBRIDGE) {
Aaro Koskinene57d4132010-12-20 23:50:16 +02003878 ivideo->p2_1f = SiS_GetReg(SISPART2, 0x1f);
3879 ivideo->p2_20 = SiS_GetReg(SISPART2, 0x20);
3880 ivideo->p2_2b = SiS_GetReg(SISPART2, 0x2b);
3881 ivideo->p2_42 = SiS_GetReg(SISPART2, 0x42);
3882 ivideo->p2_43 = SiS_GetReg(SISPART2, 0x43);
3883 ivideo->p2_01 = SiS_GetReg(SISPART2, 0x01);
3884 ivideo->p2_02 = SiS_GetReg(SISPART2, 0x02);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003885 } else if(ivideo->vbflags2 & VB2_CHRONTEL) {
3886 if(ivideo->chronteltype == 1) {
3887 ivideo->tvx = SiS_GetCH700x(&ivideo->SiS_Pr, 0x0a);
3888 ivideo->tvx |= (((SiS_GetCH700x(&ivideo->SiS_Pr, 0x08) & 0x02) >> 1) << 8);
3889 ivideo->tvy = SiS_GetCH700x(&ivideo->SiS_Pr, 0x0b);
3890 ivideo->tvy |= ((SiS_GetCH700x(&ivideo->SiS_Pr, 0x08) & 0x01) << 8);
3891 }
3892 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003893 }
3894
3895 if(ivideo->tvxpos) {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003896 sisfb_set_TVxposoffset(ivideo, ivideo->tvxpos);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003897 }
3898 if(ivideo->tvypos) {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003899 sisfb_set_TVyposoffset(ivideo, ivideo->tvypos);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003900 }
3901
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003902 /* Eventually sync engines */
3903 sisfb_check_engine_and_sync(ivideo);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003904
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003905 /* (Re-)Initialize chip engines */
3906 if(ivideo->accel) {
3907 sisfb_engine_init(ivideo);
3908 } else {
3909 ivideo->engineok = 0;
3910 }
3911}
Linus Torvalds1da177e2005-04-16 15:20:36 -07003912
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003913static int
3914sisfb_reset_mode(struct sis_video_info *ivideo)
3915{
3916 if(sisfb_set_mode(ivideo, 0))
3917 return 1;
3918
3919 sisfb_set_pitch(ivideo);
3920 sisfb_set_base_CRT1(ivideo, ivideo->current_base);
3921 sisfb_set_base_CRT2(ivideo, ivideo->current_base);
3922
3923 return 0;
3924}
3925
3926static void
3927sisfb_handle_command(struct sis_video_info *ivideo, struct sisfb_cmd *sisfb_command)
3928{
3929 int mycrt1off;
3930
3931 switch(sisfb_command->sisfb_cmd) {
3932 case SISFB_CMD_GETVBFLAGS:
3933 if(!ivideo->modechanged) {
3934 sisfb_command->sisfb_result[0] = SISFB_CMD_ERR_EARLY;
3935 } else {
3936 sisfb_command->sisfb_result[0] = SISFB_CMD_ERR_OK;
3937 sisfb_command->sisfb_result[1] = ivideo->currentvbflags;
3938 sisfb_command->sisfb_result[2] = ivideo->vbflags2;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003939 }
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003940 break;
3941 case SISFB_CMD_SWITCHCRT1:
3942 /* arg[0]: 0 = off, 1 = on, 99 = query */
3943 if(!ivideo->modechanged) {
3944 sisfb_command->sisfb_result[0] = SISFB_CMD_ERR_EARLY;
3945 } else if(sisfb_command->sisfb_arg[0] == 99) {
3946 /* Query */
3947 sisfb_command->sisfb_result[1] = ivideo->sisfb_crt1off ? 0 : 1;
3948 sisfb_command->sisfb_result[0] = SISFB_CMD_ERR_OK;
3949 } else if(ivideo->sisfblocked) {
3950 sisfb_command->sisfb_result[0] = SISFB_CMD_ERR_LOCKED;
3951 } else if((!(ivideo->currentvbflags & CRT2_ENABLE)) &&
3952 (sisfb_command->sisfb_arg[0] == 0)) {
3953 sisfb_command->sisfb_result[0] = SISFB_CMD_ERR_NOCRT2;
3954 } else {
3955 sisfb_command->sisfb_result[0] = SISFB_CMD_ERR_OK;
3956 mycrt1off = sisfb_command->sisfb_arg[0] ? 0 : 1;
3957 if( ((ivideo->currentvbflags & VB_DISPTYPE_CRT1) && mycrt1off) ||
3958 ((!(ivideo->currentvbflags & VB_DISPTYPE_CRT1)) && !mycrt1off) ) {
3959 ivideo->sisfb_crt1off = mycrt1off;
3960 if(sisfb_reset_mode(ivideo)) {
3961 sisfb_command->sisfb_result[0] = SISFB_CMD_ERR_OTHER;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003962 }
3963 }
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003964 sisfb_command->sisfb_result[1] = ivideo->sisfb_crt1off ? 0 : 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003965 }
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003966 break;
3967 /* more to come */
3968 default:
3969 sisfb_command->sisfb_result[0] = SISFB_CMD_ERR_UNKNOWN;
3970 printk(KERN_ERR "sisfb: Unknown command 0x%x\n",
3971 sisfb_command->sisfb_cmd);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003972 }
3973}
3974
3975#ifndef MODULE
Adrian Bunk14aefd12008-07-23 21:31:12 -07003976static int __init sisfb_setup(char *options)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003977{
3978 char *this_opt;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003979
Linus Torvalds1da177e2005-04-16 15:20:36 -07003980 sisfb_setdefaultparms();
3981
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003982 if(!options || !(*options))
Linus Torvalds1da177e2005-04-16 15:20:36 -07003983 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003984
3985 while((this_opt = strsep(&options, ",")) != NULL) {
3986
3987 if(!(*this_opt)) continue;
3988
3989 if(!strnicmp(this_opt, "off", 3)) {
3990 sisfb_off = 1;
3991 } else if(!strnicmp(this_opt, "forcecrt2type:", 14)) {
3992 /* Need to check crt2 type first for fstn/dstn */
3993 sisfb_search_crt2type(this_opt + 14);
3994 } else if(!strnicmp(this_opt, "tvmode:",7)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003995 sisfb_search_tvstd(this_opt + 7);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003996 } else if(!strnicmp(this_opt, "tvstandard:",11)) {
3997 sisfb_search_tvstd(this_opt + 11);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003998 } else if(!strnicmp(this_opt, "mode:", 5)) {
Richard Knutssonc30660ea2007-02-12 00:55:06 -08003999 sisfb_search_mode(this_opt + 5, false);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004000 } else if(!strnicmp(this_opt, "vesa:", 5)) {
Richard Knutssonc30660ea2007-02-12 00:55:06 -08004001 sisfb_search_vesamode(simple_strtoul(this_opt + 5, NULL, 0), false);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004002 } else if(!strnicmp(this_opt, "rate:", 5)) {
4003 sisfb_parm_rate = simple_strtoul(this_opt + 5, NULL, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004004 } else if(!strnicmp(this_opt, "forcecrt1:", 10)) {
4005 sisfb_forcecrt1 = (int)simple_strtoul(this_opt + 10, NULL, 0);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004006 } else if(!strnicmp(this_opt, "mem:",4)) {
4007 sisfb_parm_mem = simple_strtoul(this_opt + 4, NULL, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004008 } else if(!strnicmp(this_opt, "pdc:", 4)) {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004009 sisfb_pdc = simple_strtoul(this_opt + 4, NULL, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004010 } else if(!strnicmp(this_opt, "pdc1:", 5)) {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004011 sisfb_pdca = simple_strtoul(this_opt + 5, NULL, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004012 } else if(!strnicmp(this_opt, "noaccel", 7)) {
4013 sisfb_accel = 0;
4014 } else if(!strnicmp(this_opt, "accel", 5)) {
4015 sisfb_accel = -1;
4016 } else if(!strnicmp(this_opt, "noypan", 6)) {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004017 sisfb_ypan = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004018 } else if(!strnicmp(this_opt, "ypan", 4)) {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004019 sisfb_ypan = -1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004020 } else if(!strnicmp(this_opt, "nomax", 5)) {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004021 sisfb_max = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004022 } else if(!strnicmp(this_opt, "max", 3)) {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004023 sisfb_max = -1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004024 } else if(!strnicmp(this_opt, "userom:", 7)) {
4025 sisfb_userom = (int)simple_strtoul(this_opt + 7, NULL, 0);
4026 } else if(!strnicmp(this_opt, "useoem:", 7)) {
4027 sisfb_useoem = (int)simple_strtoul(this_opt + 7, NULL, 0);
4028 } else if(!strnicmp(this_opt, "nocrt2rate", 10)) {
4029 sisfb_nocrt2rate = 1;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004030 } else if(!strnicmp(this_opt, "scalelcd:", 9)) {
4031 unsigned long temp = 2;
4032 temp = simple_strtoul(this_opt + 9, NULL, 0);
4033 if((temp == 0) || (temp == 1)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004034 sisfb_scalelcd = temp ^ 1;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004035 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004036 } else if(!strnicmp(this_opt, "tvxposoffset:", 13)) {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004037 int temp = 0;
4038 temp = (int)simple_strtol(this_opt + 13, NULL, 0);
4039 if((temp >= -32) && (temp <= 32)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004040 sisfb_tvxposoffset = temp;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004041 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004042 } else if(!strnicmp(this_opt, "tvyposoffset:", 13)) {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004043 int temp = 0;
4044 temp = (int)simple_strtol(this_opt + 13, NULL, 0);
4045 if((temp >= -32) && (temp <= 32)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004046 sisfb_tvyposoffset = temp;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004047 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004048 } else if(!strnicmp(this_opt, "specialtiming:", 14)) {
4049 sisfb_search_specialtiming(this_opt + 14);
4050 } else if(!strnicmp(this_opt, "lvdshl:", 7)) {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004051 int temp = 4;
4052 temp = simple_strtoul(this_opt + 7, NULL, 0);
4053 if((temp >= 0) && (temp <= 3)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004054 sisfb_lvdshl = temp;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004055 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004056 } else if(this_opt[0] >= '0' && this_opt[0] <= '9') {
Richard Knutssonc30660ea2007-02-12 00:55:06 -08004057 sisfb_search_mode(this_opt, true);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004058#if !defined(__i386__) && !defined(__x86_64__)
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004059 } else if(!strnicmp(this_opt, "resetcard", 9)) {
4060 sisfb_resetcard = 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004061 } else if(!strnicmp(this_opt, "videoram:", 9)) {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004062 sisfb_videoram = simple_strtoul(this_opt + 9, NULL, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004063#endif
4064 } else {
4065 printk(KERN_INFO "sisfb: Invalid option %s\n", this_opt);
4066 }
4067
4068 }
4069
Linus Torvalds1da177e2005-04-16 15:20:36 -07004070 return 0;
4071}
4072#endif
4073
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004074static int __devinit
Adrian Bunk14aefd12008-07-23 21:31:12 -07004075sisfb_check_rom(void __iomem *rom_base, struct sis_video_info *ivideo)
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004076{
Adrian Bunk14aefd12008-07-23 21:31:12 -07004077 void __iomem *rom;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004078 int romptr;
4079
4080 if((readb(rom_base) != 0x55) || (readb(rom_base + 1) != 0xaa))
4081 return 0;
4082
4083 romptr = (readb(rom_base + 0x18) | (readb(rom_base + 0x19) << 8));
4084 if(romptr > (0x10000 - 8))
4085 return 0;
4086
4087 rom = rom_base + romptr;
4088
4089 if((readb(rom) != 'P') || (readb(rom + 1) != 'C') ||
4090 (readb(rom + 2) != 'I') || (readb(rom + 3) != 'R'))
4091 return 0;
4092
4093 if((readb(rom + 4) | (readb(rom + 5) << 8)) != ivideo->chip_vendor)
4094 return 0;
4095
4096 if((readb(rom + 6) | (readb(rom + 7) << 8)) != ivideo->chip_id)
4097 return 0;
4098
4099 return 1;
4100}
4101
4102static unsigned char * __devinit
4103sisfb_find_rom(struct pci_dev *pdev)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004104{
4105 struct sis_video_info *ivideo = pci_get_drvdata(pdev);
Adrian Bunk14aefd12008-07-23 21:31:12 -07004106 void __iomem *rom_base;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004107 unsigned char *myrombase = NULL;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004108 size_t romsize;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004109
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004110 /* First, try the official pci ROM functions (except
4111 * on integrated chipsets which have no ROM).
4112 */
4113
4114 if(!ivideo->nbridge) {
4115
4116 if((rom_base = pci_map_rom(pdev, &romsize))) {
4117
4118 if(sisfb_check_rom(rom_base, ivideo)) {
4119
4120 if((myrombase = vmalloc(65536))) {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004121 memcpy_fromio(myrombase, rom_base,
4122 (romsize > 65536) ? 65536 : romsize);
4123 }
4124 }
4125 pci_unmap_rom(pdev, rom_base);
4126 }
4127 }
4128
4129 if(myrombase) return myrombase;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004130
4131 /* Otherwise do it the conventional way. */
Linus Torvalds1da177e2005-04-16 15:20:36 -07004132
4133#if defined(__i386__) || defined(__x86_64__)
Aaro Koskinen679c4892010-12-20 23:50:10 +02004134 {
4135 u32 temp;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004136
Aaro Koskinen679c4892010-12-20 23:50:10 +02004137 for (temp = 0x000c0000; temp < 0x000f0000; temp += 0x00001000) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004138
Aaro Koskinen679c4892010-12-20 23:50:10 +02004139 rom_base = ioremap(temp, 65536);
4140 if (!rom_base)
4141 continue;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004142
Aaro Koskinen679c4892010-12-20 23:50:10 +02004143 if (!sisfb_check_rom(rom_base, ivideo)) {
4144 iounmap(rom_base);
4145 continue;
4146 }
4147
4148 if ((myrombase = vmalloc(65536)))
4149 memcpy_fromio(myrombase, rom_base, 65536);
4150
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004151 iounmap(rom_base);
Aaro Koskinen679c4892010-12-20 23:50:10 +02004152 break;
4153
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004154 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004155
Aaro Koskinen679c4892010-12-20 23:50:10 +02004156 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004157#endif
4158
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004159 return myrombase;
4160}
4161
4162static void __devinit
4163sisfb_post_map_vram(struct sis_video_info *ivideo, unsigned int *mapsize,
4164 unsigned int min)
4165{
Aaro Koskinen32ed3032010-11-10 13:04:19 +02004166 if (*mapsize < (min << 20))
4167 return;
4168
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004169 ivideo->video_vbase = ioremap(ivideo->video_base, (*mapsize));
4170
4171 if(!ivideo->video_vbase) {
4172 printk(KERN_ERR
4173 "sisfb: Unable to map maximum video RAM for size detection\n");
4174 (*mapsize) >>= 1;
4175 while((!(ivideo->video_vbase = ioremap(ivideo->video_base, (*mapsize))))) {
4176 (*mapsize) >>= 1;
4177 if((*mapsize) < (min << 20))
4178 break;
4179 }
4180 if(ivideo->video_vbase) {
4181 printk(KERN_ERR
4182 "sisfb: Video RAM size detection limited to %dMB\n",
4183 (int)((*mapsize) >> 20));
4184 }
4185 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004186}
4187
4188#ifdef CONFIG_FB_SIS_300
4189static int __devinit
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004190sisfb_post_300_buswidth(struct sis_video_info *ivideo)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004191{
Adrian Bunk14aefd12008-07-23 21:31:12 -07004192 void __iomem *FBAddress = ivideo->video_vbase;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004193 unsigned short temp;
4194 unsigned char reg;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004195 int i, j;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004196
Aaro Koskinen667a8b42010-12-20 23:50:19 +02004197 SiS_SetRegAND(SISSR, 0x15, 0xFB);
Aaro Koskinen27799d62010-12-20 23:50:18 +02004198 SiS_SetRegOR(SISSR, 0x15, 0x04);
Aaro Koskinen44b751b2010-12-20 23:50:17 +02004199 SiS_SetReg(SISSR, 0x13, 0x00);
4200 SiS_SetReg(SISSR, 0x14, 0xBF);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004201
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004202 for(i = 0; i < 2; i++) {
4203 temp = 0x1234;
4204 for(j = 0; j < 4; j++) {
4205 writew(temp, FBAddress);
4206 if(readw(FBAddress) == temp)
4207 break;
Aaro Koskinen27799d62010-12-20 23:50:18 +02004208 SiS_SetRegOR(SISSR, 0x3c, 0x01);
Aaro Koskinene57d4132010-12-20 23:50:16 +02004209 reg = SiS_GetReg(SISSR, 0x05);
4210 reg = SiS_GetReg(SISSR, 0x05);
Aaro Koskinen667a8b42010-12-20 23:50:19 +02004211 SiS_SetRegAND(SISSR, 0x3c, 0xfe);
Aaro Koskinene57d4132010-12-20 23:50:16 +02004212 reg = SiS_GetReg(SISSR, 0x05);
4213 reg = SiS_GetReg(SISSR, 0x05);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004214 temp++;
4215 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004216 }
4217
4218 writel(0x01234567L, FBAddress);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004219 writel(0x456789ABL, (FBAddress + 4));
4220 writel(0x89ABCDEFL, (FBAddress + 8));
4221 writel(0xCDEF0123L, (FBAddress + 12));
4222
Aaro Koskinene57d4132010-12-20 23:50:16 +02004223 reg = SiS_GetReg(SISSR, 0x3b);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004224 if(reg & 0x01) {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004225 if(readl((FBAddress + 12)) == 0xCDEF0123L)
4226 return 4; /* Channel A 128bit */
Linus Torvalds1da177e2005-04-16 15:20:36 -07004227 }
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004228
4229 if(readl((FBAddress + 4)) == 0x456789ABL)
4230 return 2; /* Channel B 64bit */
4231
4232 return 1; /* 32bit */
4233}
4234
4235static int __devinit
4236sisfb_post_300_rwtest(struct sis_video_info *ivideo, int iteration, int buswidth,
4237 int PseudoRankCapacity, int PseudoAdrPinCount,
4238 unsigned int mapsize)
4239{
Adrian Bunk14aefd12008-07-23 21:31:12 -07004240 void __iomem *FBAddr = ivideo->video_vbase;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004241 unsigned short sr14;
4242 unsigned int k, RankCapacity, PageCapacity, BankNumHigh, BankNumMid;
4243 unsigned int PhysicalAdrOtherPage, PhysicalAdrHigh, PhysicalAdrHalfPage;
4244 static const unsigned short SiS_DRAMType[17][5] = {
4245 {0x0C,0x0A,0x02,0x40,0x39},
4246 {0x0D,0x0A,0x01,0x40,0x48},
4247 {0x0C,0x09,0x02,0x20,0x35},
4248 {0x0D,0x09,0x01,0x20,0x44},
4249 {0x0C,0x08,0x02,0x10,0x31},
4250 {0x0D,0x08,0x01,0x10,0x40},
4251 {0x0C,0x0A,0x01,0x20,0x34},
4252 {0x0C,0x09,0x01,0x08,0x32},
4253 {0x0B,0x08,0x02,0x08,0x21},
4254 {0x0C,0x08,0x01,0x08,0x30},
4255 {0x0A,0x08,0x02,0x04,0x11},
4256 {0x0B,0x0A,0x01,0x10,0x28},
4257 {0x09,0x08,0x02,0x02,0x01},
4258 {0x0B,0x09,0x01,0x08,0x24},
4259 {0x0B,0x08,0x01,0x04,0x20},
4260 {0x0A,0x08,0x01,0x02,0x10},
4261 {0x09,0x08,0x01,0x01,0x00}
4262 };
4263
4264 for(k = 0; k <= 16; k++) {
4265
4266 RankCapacity = buswidth * SiS_DRAMType[k][3];
4267
4268 if(RankCapacity != PseudoRankCapacity)
4269 continue;
4270
4271 if((SiS_DRAMType[k][2] + SiS_DRAMType[k][0]) > PseudoAdrPinCount)
4272 continue;
4273
4274 BankNumHigh = RankCapacity * 16 * iteration - 1;
4275 if(iteration == 3) { /* Rank No */
4276 BankNumMid = RankCapacity * 16 - 1;
4277 } else {
4278 BankNumMid = RankCapacity * 16 * iteration / 2 - 1;
4279 }
4280
4281 PageCapacity = (1 << SiS_DRAMType[k][1]) * buswidth * 4;
4282 PhysicalAdrHigh = BankNumHigh;
4283 PhysicalAdrHalfPage = (PageCapacity / 2 + PhysicalAdrHigh) % PageCapacity;
4284 PhysicalAdrOtherPage = PageCapacity * SiS_DRAMType[k][2] + PhysicalAdrHigh;
4285
Aaro Koskinen667a8b42010-12-20 23:50:19 +02004286 SiS_SetRegAND(SISSR, 0x15, 0xFB); /* Test */
Aaro Koskinen27799d62010-12-20 23:50:18 +02004287 SiS_SetRegOR(SISSR, 0x15, 0x04); /* Test */
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004288 sr14 = (SiS_DRAMType[k][3] * buswidth) - 1;
4289 if(buswidth == 4) sr14 |= 0x80;
4290 else if(buswidth == 2) sr14 |= 0x40;
Aaro Koskinen44b751b2010-12-20 23:50:17 +02004291 SiS_SetReg(SISSR, 0x13, SiS_DRAMType[k][4]);
4292 SiS_SetReg(SISSR, 0x14, sr14);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004293
4294 BankNumHigh <<= 16;
4295 BankNumMid <<= 16;
4296
4297 if((BankNumHigh + PhysicalAdrHigh >= mapsize) ||
4298 (BankNumMid + PhysicalAdrHigh >= mapsize) ||
4299 (BankNumHigh + PhysicalAdrHalfPage >= mapsize) ||
4300 (BankNumHigh + PhysicalAdrOtherPage >= mapsize))
4301 continue;
4302
4303 /* Write data */
4304 writew(((unsigned short)PhysicalAdrHigh),
4305 (FBAddr + BankNumHigh + PhysicalAdrHigh));
4306 writew(((unsigned short)BankNumMid),
4307 (FBAddr + BankNumMid + PhysicalAdrHigh));
4308 writew(((unsigned short)PhysicalAdrHalfPage),
4309 (FBAddr + BankNumHigh + PhysicalAdrHalfPage));
4310 writew(((unsigned short)PhysicalAdrOtherPage),
4311 (FBAddr + BankNumHigh + PhysicalAdrOtherPage));
4312
4313 /* Read data */
4314 if(readw(FBAddr + BankNumHigh + PhysicalAdrHigh) == PhysicalAdrHigh)
4315 return 1;
4316 }
4317
4318 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004319}
4320
4321static void __devinit
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004322sisfb_post_300_ramsize(struct pci_dev *pdev, unsigned int mapsize)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004323{
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004324 struct sis_video_info *ivideo = pci_get_drvdata(pdev);
4325 int i, j, buswidth;
4326 int PseudoRankCapacity, PseudoAdrPinCount;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004327
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004328 buswidth = sisfb_post_300_buswidth(ivideo);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004329
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004330 for(i = 6; i >= 0; i--) {
4331 PseudoRankCapacity = 1 << i;
4332 for(j = 4; j >= 1; j--) {
4333 PseudoAdrPinCount = 15 - j;
4334 if((PseudoRankCapacity * j) <= 64) {
4335 if(sisfb_post_300_rwtest(ivideo,
4336 j,
4337 buswidth,
4338 PseudoRankCapacity,
4339 PseudoAdrPinCount,
4340 mapsize))
4341 return;
4342 }
4343 }
4344 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004345}
4346
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004347static void __devinit
4348sisfb_post_sis300(struct pci_dev *pdev)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004349{
4350 struct sis_video_info *ivideo = pci_get_drvdata(pdev);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004351 unsigned char *bios = ivideo->SiS_Pr.VirtualRomBase;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004352 u8 reg, v1, v2, v3, v4, v5, v6, v7, v8;
4353 u16 index, rindex, memtype = 0;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004354 unsigned int mapsize;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004355
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004356 if(!ivideo->SiS_Pr.UseROM)
4357 bios = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004358
Aaro Koskinen44b751b2010-12-20 23:50:17 +02004359 SiS_SetReg(SISSR, 0x05, 0x86);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004360
4361 if(bios) {
4362 if(bios[0x52] & 0x80) {
4363 memtype = bios[0x52];
4364 } else {
Aaro Koskinene57d4132010-12-20 23:50:16 +02004365 memtype = SiS_GetReg(SISSR, 0x3a);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004366 }
4367 memtype &= 0x07;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004368 }
4369
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004370 v3 = 0x80; v6 = 0x80;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004371 if(ivideo->revision_id <= 0x13) {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004372 v1 = 0x44; v2 = 0x42;
4373 v4 = 0x44; v5 = 0x42;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004374 } else {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004375 v1 = 0x68; v2 = 0x43; /* Assume 125Mhz MCLK */
4376 v4 = 0x68; v5 = 0x43; /* Assume 125Mhz ECLK */
4377 if(bios) {
4378 index = memtype * 5;
4379 rindex = index + 0x54;
4380 v1 = bios[rindex++];
4381 v2 = bios[rindex++];
4382 v3 = bios[rindex++];
4383 rindex = index + 0x7c;
4384 v4 = bios[rindex++];
4385 v5 = bios[rindex++];
4386 v6 = bios[rindex++];
4387 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004388 }
Aaro Koskinen44b751b2010-12-20 23:50:17 +02004389 SiS_SetReg(SISSR, 0x28, v1);
4390 SiS_SetReg(SISSR, 0x29, v2);
4391 SiS_SetReg(SISSR, 0x2a, v3);
4392 SiS_SetReg(SISSR, 0x2e, v4);
4393 SiS_SetReg(SISSR, 0x2f, v5);
4394 SiS_SetReg(SISSR, 0x30, v6);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004395
Linus Torvalds1da177e2005-04-16 15:20:36 -07004396 v1 = 0x10;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004397 if(bios)
4398 v1 = bios[0xa4];
Aaro Koskinen44b751b2010-12-20 23:50:17 +02004399 SiS_SetReg(SISSR, 0x07, v1); /* DAC speed */
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004400
Aaro Koskinen44b751b2010-12-20 23:50:17 +02004401 SiS_SetReg(SISSR, 0x11, 0x0f); /* DDC, power save */
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004402
Linus Torvalds1da177e2005-04-16 15:20:36 -07004403 v1 = 0x01; v2 = 0x43; v3 = 0x1e; v4 = 0x2a;
4404 v5 = 0x06; v6 = 0x00; v7 = 0x00; v8 = 0x00;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004405 if(bios) {
4406 memtype += 0xa5;
4407 v1 = bios[memtype];
4408 v2 = bios[memtype + 8];
4409 v3 = bios[memtype + 16];
4410 v4 = bios[memtype + 24];
4411 v5 = bios[memtype + 32];
4412 v6 = bios[memtype + 40];
4413 v7 = bios[memtype + 48];
4414 v8 = bios[memtype + 56];
Linus Torvalds1da177e2005-04-16 15:20:36 -07004415 }
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004416 if(ivideo->revision_id >= 0x80)
4417 v3 &= 0xfd;
Aaro Koskinen44b751b2010-12-20 23:50:17 +02004418 SiS_SetReg(SISSR, 0x15, v1); /* Ram type (assuming 0, BIOS 0xa5 step 8) */
4419 SiS_SetReg(SISSR, 0x16, v2);
4420 SiS_SetReg(SISSR, 0x17, v3);
4421 SiS_SetReg(SISSR, 0x18, v4);
4422 SiS_SetReg(SISSR, 0x19, v5);
4423 SiS_SetReg(SISSR, 0x1a, v6);
4424 SiS_SetReg(SISSR, 0x1b, v7);
4425 SiS_SetReg(SISSR, 0x1c, v8); /* ---- */
Aaro Koskinen667a8b42010-12-20 23:50:19 +02004426 SiS_SetRegAND(SISSR, 0x15, 0xfb);
Aaro Koskinen27799d62010-12-20 23:50:18 +02004427 SiS_SetRegOR(SISSR, 0x15, 0x04);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004428 if(bios) {
4429 if(bios[0x53] & 0x02) {
Aaro Koskinen27799d62010-12-20 23:50:18 +02004430 SiS_SetRegOR(SISSR, 0x19, 0x20);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004431 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004432 }
4433 v1 = 0x04; /* DAC pedestal (BIOS 0xe5) */
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004434 if(ivideo->revision_id >= 0x80)
4435 v1 |= 0x01;
Aaro Koskinen44b751b2010-12-20 23:50:17 +02004436 SiS_SetReg(SISSR, 0x1f, v1);
4437 SiS_SetReg(SISSR, 0x20, 0xa4); /* linear & relocated io & disable a0000 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07004438 v1 = 0xf6; v2 = 0x0d; v3 = 0x00;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004439 if(bios) {
4440 v1 = bios[0xe8];
4441 v2 = bios[0xe9];
4442 v3 = bios[0xea];
Linus Torvalds1da177e2005-04-16 15:20:36 -07004443 }
Aaro Koskinen44b751b2010-12-20 23:50:17 +02004444 SiS_SetReg(SISSR, 0x23, v1);
4445 SiS_SetReg(SISSR, 0x24, v2);
4446 SiS_SetReg(SISSR, 0x25, v3);
4447 SiS_SetReg(SISSR, 0x21, 0x84);
4448 SiS_SetReg(SISSR, 0x22, 0x00);
4449 SiS_SetReg(SISCR, 0x37, 0x00);
Aaro Koskinen27799d62010-12-20 23:50:18 +02004450 SiS_SetRegOR(SISPART1, 0x24, 0x01); /* unlock crt2 */
Aaro Koskinen44b751b2010-12-20 23:50:17 +02004451 SiS_SetReg(SISPART1, 0x00, 0x00);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004452 v1 = 0x40; v2 = 0x11;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004453 if(bios) {
4454 v1 = bios[0xec];
4455 v2 = bios[0xeb];
Linus Torvalds1da177e2005-04-16 15:20:36 -07004456 }
Aaro Koskinen44b751b2010-12-20 23:50:17 +02004457 SiS_SetReg(SISPART1, 0x02, v1);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004458
4459 if(ivideo->revision_id >= 0x80)
4460 v2 &= ~0x01;
4461
Aaro Koskinene57d4132010-12-20 23:50:16 +02004462 reg = SiS_GetReg(SISPART4, 0x00);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004463 if((reg == 1) || (reg == 2)) {
Aaro Koskinen44b751b2010-12-20 23:50:17 +02004464 SiS_SetReg(SISCR, 0x37, 0x02);
4465 SiS_SetReg(SISPART2, 0x00, 0x1c);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004466 v4 = 0x00; v5 = 0x00; v6 = 0x10;
4467 if(ivideo->SiS_Pr.UseROM) {
4468 v4 = bios[0xf5];
4469 v5 = bios[0xf6];
4470 v6 = bios[0xf7];
4471 }
Aaro Koskinen44b751b2010-12-20 23:50:17 +02004472 SiS_SetReg(SISPART4, 0x0d, v4);
4473 SiS_SetReg(SISPART4, 0x0e, v5);
4474 SiS_SetReg(SISPART4, 0x10, v6);
4475 SiS_SetReg(SISPART4, 0x0f, 0x3f);
Aaro Koskinene57d4132010-12-20 23:50:16 +02004476 reg = SiS_GetReg(SISPART4, 0x01);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004477 if(reg >= 0xb0) {
Aaro Koskinene57d4132010-12-20 23:50:16 +02004478 reg = SiS_GetReg(SISPART4, 0x23);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004479 reg &= 0x20;
4480 reg <<= 1;
Aaro Koskinen44b751b2010-12-20 23:50:17 +02004481 SiS_SetReg(SISPART4, 0x23, reg);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004482 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004483 } else {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004484 v2 &= ~0x10;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004485 }
Aaro Koskinen44b751b2010-12-20 23:50:17 +02004486 SiS_SetReg(SISSR, 0x32, v2);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004487
Aaro Koskinen667a8b42010-12-20 23:50:19 +02004488 SiS_SetRegAND(SISPART1, 0x24, 0xfe); /* Lock CRT2 */
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004489
Aaro Koskinene57d4132010-12-20 23:50:16 +02004490 reg = SiS_GetReg(SISSR, 0x16);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004491 reg &= 0xc3;
Aaro Koskinen44b751b2010-12-20 23:50:17 +02004492 SiS_SetReg(SISCR, 0x35, reg);
4493 SiS_SetReg(SISCR, 0x83, 0x00);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004494#if !defined(__i386__) && !defined(__x86_64__)
4495 if(sisfb_videoram) {
Aaro Koskinen44b751b2010-12-20 23:50:17 +02004496 SiS_SetReg(SISSR, 0x13, 0x28); /* ? */
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004497 reg = ((sisfb_videoram >> 10) - 1) | 0x40;
Aaro Koskinen44b751b2010-12-20 23:50:17 +02004498 SiS_SetReg(SISSR, 0x14, reg);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004499 } else {
4500#endif
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004501 /* Need to map max FB size for finding out about RAM size */
Aaro Koskinen32ed3032010-11-10 13:04:19 +02004502 mapsize = ivideo->video_size;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004503 sisfb_post_map_vram(ivideo, &mapsize, 4);
4504
4505 if(ivideo->video_vbase) {
4506 sisfb_post_300_ramsize(pdev, mapsize);
4507 iounmap(ivideo->video_vbase);
4508 } else {
4509 printk(KERN_DEBUG
4510 "sisfb: Failed to map memory for size detection, assuming 8MB\n");
Aaro Koskinen44b751b2010-12-20 23:50:17 +02004511 SiS_SetReg(SISSR, 0x13, 0x28); /* ? */
4512 SiS_SetReg(SISSR, 0x14, 0x47); /* 8MB, 64bit default */
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004513 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004514#if !defined(__i386__) && !defined(__x86_64__)
4515 }
4516#endif
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004517 if(bios) {
4518 v1 = bios[0xe6];
4519 v2 = bios[0xe7];
Linus Torvalds1da177e2005-04-16 15:20:36 -07004520 } else {
Aaro Koskinene57d4132010-12-20 23:50:16 +02004521 reg = SiS_GetReg(SISSR, 0x3a);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004522 if((reg & 0x30) == 0x30) {
4523 v1 = 0x04; /* PCI */
4524 v2 = 0x92;
4525 } else {
4526 v1 = 0x14; /* AGP */
4527 v2 = 0xb2;
4528 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004529 }
Aaro Koskinen44b751b2010-12-20 23:50:17 +02004530 SiS_SetReg(SISSR, 0x21, v1);
4531 SiS_SetReg(SISSR, 0x22, v2);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004532
4533 /* Sense CRT1 */
4534 sisfb_sense_crt1(ivideo);
4535
4536 /* Set default mode, don't clear screen */
Richard Knutssonc30660ea2007-02-12 00:55:06 -08004537 ivideo->SiS_Pr.SiS_UseOEM = false;
4538 SiS_SetEnableDstn(&ivideo->SiS_Pr, false);
4539 SiS_SetEnableFstn(&ivideo->SiS_Pr, false);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004540 ivideo->curFSTN = ivideo->curDSTN = 0;
4541 ivideo->SiS_Pr.VideoMemorySize = 8 << 20;
4542 SiSSetMode(&ivideo->SiS_Pr, 0x2e | 0x80);
4543
Aaro Koskinen44b751b2010-12-20 23:50:17 +02004544 SiS_SetReg(SISSR, 0x05, 0x86);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004545
4546 /* Display off */
Aaro Koskinen27799d62010-12-20 23:50:18 +02004547 SiS_SetRegOR(SISSR, 0x01, 0x20);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004548
4549 /* Save mode number in CR34 */
Aaro Koskinen44b751b2010-12-20 23:50:17 +02004550 SiS_SetReg(SISCR, 0x34, 0x2e);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004551
4552 /* Let everyone know what the current mode is */
4553 ivideo->modeprechange = 0x2e;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004554}
4555#endif
4556
4557#ifdef CONFIG_FB_SIS_315
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004558#if 0
4559static void __devinit
4560sisfb_post_sis315330(struct pci_dev *pdev)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004561{
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004562 /* TODO */
Linus Torvalds1da177e2005-04-16 15:20:36 -07004563}
4564#endif
4565
Aaro Koskinen929c9722011-02-13 22:11:25 +00004566static inline int sisfb_xgi_is21(struct sis_video_info *ivideo)
4567{
4568 return ivideo->chip_real_id == XGI_21;
4569}
4570
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004571static void __devinit
4572sisfb_post_xgi_delay(struct sis_video_info *ivideo, int delay)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004573{
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004574 unsigned int i;
4575 u8 reg;
4576
4577 for(i = 0; i <= (delay * 10 * 36); i++) {
Aaro Koskinene57d4132010-12-20 23:50:16 +02004578 reg = SiS_GetReg(SISSR, 0x05);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004579 reg++;
4580 }
4581}
4582
4583static int __devinit
4584sisfb_find_host_bridge(struct sis_video_info *ivideo, struct pci_dev *mypdev,
4585 unsigned short pcivendor)
4586{
4587 struct pci_dev *pdev = NULL;
4588 unsigned short temp;
4589 int ret = 0;
4590
Adrian Bunk0959f0c2007-05-08 00:39:50 -07004591 while((pdev = pci_get_class(PCI_CLASS_BRIDGE_HOST, pdev))) {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004592 temp = pdev->vendor;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004593 if(temp == pcivendor) {
4594 ret = 1;
Julia Lawallea237a62008-02-06 01:39:07 -08004595 pci_dev_put(pdev);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004596 break;
4597 }
4598 }
4599
4600 return ret;
4601}
4602
4603static int __devinit
4604sisfb_post_xgi_rwtest(struct sis_video_info *ivideo, int starta,
4605 unsigned int enda, unsigned int mapsize)
4606{
4607 unsigned int pos;
4608 int i;
4609
4610 writel(0, ivideo->video_vbase);
4611
4612 for(i = starta; i <= enda; i++) {
4613 pos = 1 << i;
4614 if(pos < mapsize)
4615 writel(pos, ivideo->video_vbase + pos);
4616 }
4617
4618 sisfb_post_xgi_delay(ivideo, 150);
4619
4620 if(readl(ivideo->video_vbase) != 0)
4621 return 0;
4622
4623 for(i = starta; i <= enda; i++) {
4624 pos = 1 << i;
4625 if(pos < mapsize) {
4626 if(readl(ivideo->video_vbase + pos) != pos)
4627 return 0;
4628 } else
4629 return 0;
4630 }
4631
4632 return 1;
4633}
4634
Aaro Koskinen83ea0f12011-02-13 22:11:23 +00004635static int __devinit
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004636sisfb_post_xgi_ramsize(struct sis_video_info *ivideo)
4637{
4638 unsigned int buswidth, ranksize, channelab, mapsize;
Aaro Koskinen83ea0f12011-02-13 22:11:23 +00004639 int i, j, k, l, status;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004640 u8 reg, sr14;
4641 static const u8 dramsr13[12 * 5] = {
4642 0x02, 0x0e, 0x0b, 0x80, 0x5d,
4643 0x02, 0x0e, 0x0a, 0x40, 0x59,
4644 0x02, 0x0d, 0x0b, 0x40, 0x4d,
4645 0x02, 0x0e, 0x09, 0x20, 0x55,
4646 0x02, 0x0d, 0x0a, 0x20, 0x49,
4647 0x02, 0x0c, 0x0b, 0x20, 0x3d,
4648 0x02, 0x0e, 0x08, 0x10, 0x51,
4649 0x02, 0x0d, 0x09, 0x10, 0x45,
4650 0x02, 0x0c, 0x0a, 0x10, 0x39,
4651 0x02, 0x0d, 0x08, 0x08, 0x41,
4652 0x02, 0x0c, 0x09, 0x08, 0x35,
4653 0x02, 0x0c, 0x08, 0x04, 0x31
4654 };
4655 static const u8 dramsr13_4[4 * 5] = {
4656 0x02, 0x0d, 0x09, 0x40, 0x45,
4657 0x02, 0x0c, 0x09, 0x20, 0x35,
4658 0x02, 0x0c, 0x08, 0x10, 0x31,
4659 0x02, 0x0b, 0x08, 0x08, 0x21
4660 };
4661
4662 /* Enable linear mode, disable 0xa0000 address decoding */
4663 /* We disable a0000 address decoding, because
4664 * - if running on x86, if the card is disabled, it means
4665 * that another card is in the system. We don't want
4666 * to interphere with that primary card's textmode.
4667 * - if running on non-x86, there usually is no VGA window
4668 * at a0000.
4669 */
Aaro Koskinen27799d62010-12-20 23:50:18 +02004670 SiS_SetRegOR(SISSR, 0x20, (0x80 | 0x04));
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004671
4672 /* Need to map max FB size for finding out about RAM size */
Aaro Koskinen32ed3032010-11-10 13:04:19 +02004673 mapsize = ivideo->video_size;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004674 sisfb_post_map_vram(ivideo, &mapsize, 32);
4675
4676 if(!ivideo->video_vbase) {
4677 printk(KERN_ERR "sisfb: Unable to detect RAM size. Setting default.\n");
Aaro Koskinen44b751b2010-12-20 23:50:17 +02004678 SiS_SetReg(SISSR, 0x13, 0x35);
4679 SiS_SetReg(SISSR, 0x14, 0x41);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004680 /* TODO */
Aaro Koskinen83ea0f12011-02-13 22:11:23 +00004681 return -ENOMEM;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004682 }
4683
4684 /* Non-interleaving */
Aaro Koskinen44b751b2010-12-20 23:50:17 +02004685 SiS_SetReg(SISSR, 0x15, 0x00);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004686 /* No tiling */
Aaro Koskinen44b751b2010-12-20 23:50:17 +02004687 SiS_SetReg(SISSR, 0x1c, 0x00);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004688
4689 if(ivideo->chip == XGI_20) {
4690
4691 channelab = 1;
Aaro Koskinene57d4132010-12-20 23:50:16 +02004692 reg = SiS_GetReg(SISCR, 0x97);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004693 if(!(reg & 0x01)) { /* Single 32/16 */
4694 buswidth = 32;
Aaro Koskinen44b751b2010-12-20 23:50:17 +02004695 SiS_SetReg(SISSR, 0x13, 0xb1);
4696 SiS_SetReg(SISSR, 0x14, 0x52);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004697 sisfb_post_xgi_delay(ivideo, 1);
4698 sr14 = 0x02;
4699 if(sisfb_post_xgi_rwtest(ivideo, 23, 24, mapsize))
4700 goto bail_out;
4701
Aaro Koskinen44b751b2010-12-20 23:50:17 +02004702 SiS_SetReg(SISSR, 0x13, 0x31);
4703 SiS_SetReg(SISSR, 0x14, 0x42);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004704 sisfb_post_xgi_delay(ivideo, 1);
4705 if(sisfb_post_xgi_rwtest(ivideo, 23, 23, mapsize))
4706 goto bail_out;
4707
4708 buswidth = 16;
Aaro Koskinen44b751b2010-12-20 23:50:17 +02004709 SiS_SetReg(SISSR, 0x13, 0xb1);
4710 SiS_SetReg(SISSR, 0x14, 0x41);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004711 sisfb_post_xgi_delay(ivideo, 1);
4712 sr14 = 0x01;
4713 if(sisfb_post_xgi_rwtest(ivideo, 22, 23, mapsize))
4714 goto bail_out;
4715 else
Aaro Koskinen44b751b2010-12-20 23:50:17 +02004716 SiS_SetReg(SISSR, 0x13, 0x31);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004717 } else { /* Dual 16/8 */
4718 buswidth = 16;
Aaro Koskinen44b751b2010-12-20 23:50:17 +02004719 SiS_SetReg(SISSR, 0x13, 0xb1);
4720 SiS_SetReg(SISSR, 0x14, 0x41);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004721 sisfb_post_xgi_delay(ivideo, 1);
4722 sr14 = 0x01;
4723 if(sisfb_post_xgi_rwtest(ivideo, 22, 23, mapsize))
4724 goto bail_out;
4725
Aaro Koskinen44b751b2010-12-20 23:50:17 +02004726 SiS_SetReg(SISSR, 0x13, 0x31);
4727 SiS_SetReg(SISSR, 0x14, 0x31);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004728 sisfb_post_xgi_delay(ivideo, 1);
4729 if(sisfb_post_xgi_rwtest(ivideo, 22, 22, mapsize))
4730 goto bail_out;
4731
4732 buswidth = 8;
Aaro Koskinen44b751b2010-12-20 23:50:17 +02004733 SiS_SetReg(SISSR, 0x13, 0xb1);
4734 SiS_SetReg(SISSR, 0x14, 0x30);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004735 sisfb_post_xgi_delay(ivideo, 1);
4736 sr14 = 0x00;
4737 if(sisfb_post_xgi_rwtest(ivideo, 21, 22, mapsize))
4738 goto bail_out;
4739 else
Aaro Koskinen44b751b2010-12-20 23:50:17 +02004740 SiS_SetReg(SISSR, 0x13, 0x31);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004741 }
4742
4743 } else { /* XGI_40 */
4744
Aaro Koskinene57d4132010-12-20 23:50:16 +02004745 reg = SiS_GetReg(SISCR, 0x97);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004746 if(!(reg & 0x10)) {
Aaro Koskinene57d4132010-12-20 23:50:16 +02004747 reg = SiS_GetReg(SISSR, 0x39);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004748 reg >>= 1;
4749 }
4750
4751 if(reg & 0x01) { /* DDRII */
4752 buswidth = 32;
4753 if(ivideo->revision_id == 2) {
4754 channelab = 2;
Aaro Koskinen44b751b2010-12-20 23:50:17 +02004755 SiS_SetReg(SISSR, 0x13, 0xa1);
4756 SiS_SetReg(SISSR, 0x14, 0x44);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004757 sr14 = 0x04;
4758 sisfb_post_xgi_delay(ivideo, 1);
4759 if(sisfb_post_xgi_rwtest(ivideo, 23, 24, mapsize))
4760 goto bail_out;
4761
Aaro Koskinen44b751b2010-12-20 23:50:17 +02004762 SiS_SetReg(SISSR, 0x13, 0x21);
4763 SiS_SetReg(SISSR, 0x14, 0x34);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004764 if(sisfb_post_xgi_rwtest(ivideo, 22, 23, mapsize))
4765 goto bail_out;
4766
4767 channelab = 1;
Aaro Koskinen44b751b2010-12-20 23:50:17 +02004768 SiS_SetReg(SISSR, 0x13, 0xa1);
4769 SiS_SetReg(SISSR, 0x14, 0x40);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004770 sr14 = 0x00;
4771 if(sisfb_post_xgi_rwtest(ivideo, 22, 23, mapsize))
4772 goto bail_out;
4773
Aaro Koskinen44b751b2010-12-20 23:50:17 +02004774 SiS_SetReg(SISSR, 0x13, 0x21);
4775 SiS_SetReg(SISSR, 0x14, 0x30);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004776 } else {
4777 channelab = 3;
Aaro Koskinen44b751b2010-12-20 23:50:17 +02004778 SiS_SetReg(SISSR, 0x13, 0xa1);
4779 SiS_SetReg(SISSR, 0x14, 0x4c);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004780 sr14 = 0x0c;
4781 sisfb_post_xgi_delay(ivideo, 1);
4782 if(sisfb_post_xgi_rwtest(ivideo, 23, 25, mapsize))
4783 goto bail_out;
4784
4785 channelab = 2;
Aaro Koskinen44b751b2010-12-20 23:50:17 +02004786 SiS_SetReg(SISSR, 0x14, 0x48);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004787 sisfb_post_xgi_delay(ivideo, 1);
4788 sr14 = 0x08;
4789 if(sisfb_post_xgi_rwtest(ivideo, 23, 24, mapsize))
4790 goto bail_out;
4791
Aaro Koskinen44b751b2010-12-20 23:50:17 +02004792 SiS_SetReg(SISSR, 0x13, 0x21);
4793 SiS_SetReg(SISSR, 0x14, 0x3c);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004794 sr14 = 0x0c;
4795
4796 if(sisfb_post_xgi_rwtest(ivideo, 23, 24, mapsize)) {
4797 channelab = 3;
4798 } else {
4799 channelab = 2;
Aaro Koskinen44b751b2010-12-20 23:50:17 +02004800 SiS_SetReg(SISSR, 0x14, 0x38);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004801 sr14 = 0x08;
4802 }
4803 }
4804 sisfb_post_xgi_delay(ivideo, 1);
4805
4806 } else { /* DDR */
4807
4808 buswidth = 64;
4809 if(ivideo->revision_id == 2) {
4810 channelab = 1;
Aaro Koskinen44b751b2010-12-20 23:50:17 +02004811 SiS_SetReg(SISSR, 0x13, 0xa1);
4812 SiS_SetReg(SISSR, 0x14, 0x52);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004813 sisfb_post_xgi_delay(ivideo, 1);
4814 sr14 = 0x02;
4815 if(sisfb_post_xgi_rwtest(ivideo, 23, 24, mapsize))
4816 goto bail_out;
4817
Aaro Koskinen44b751b2010-12-20 23:50:17 +02004818 SiS_SetReg(SISSR, 0x13, 0x21);
4819 SiS_SetReg(SISSR, 0x14, 0x42);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004820 } else {
4821 channelab = 2;
Aaro Koskinen44b751b2010-12-20 23:50:17 +02004822 SiS_SetReg(SISSR, 0x13, 0xa1);
4823 SiS_SetReg(SISSR, 0x14, 0x5a);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004824 sisfb_post_xgi_delay(ivideo, 1);
4825 sr14 = 0x0a;
4826 if(sisfb_post_xgi_rwtest(ivideo, 24, 25, mapsize))
4827 goto bail_out;
4828
Aaro Koskinen44b751b2010-12-20 23:50:17 +02004829 SiS_SetReg(SISSR, 0x13, 0x21);
4830 SiS_SetReg(SISSR, 0x14, 0x4a);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004831 }
4832 sisfb_post_xgi_delay(ivideo, 1);
4833
4834 }
4835 }
4836
4837bail_out:
Aaro Koskinenad78adb2010-12-20 23:50:20 +02004838 SiS_SetRegANDOR(SISSR, 0x14, 0xf0, sr14);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004839 sisfb_post_xgi_delay(ivideo, 1);
4840
4841 j = (ivideo->chip == XGI_20) ? 5 : 9;
4842 k = (ivideo->chip == XGI_20) ? 12 : 4;
Aaro Koskinen83ea0f12011-02-13 22:11:23 +00004843 status = -EIO;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004844
4845 for(i = 0; i < k; i++) {
4846
4847 reg = (ivideo->chip == XGI_20) ?
4848 dramsr13[(i * 5) + 4] : dramsr13_4[(i * 5) + 4];
Aaro Koskinenad78adb2010-12-20 23:50:20 +02004849 SiS_SetRegANDOR(SISSR, 0x13, 0x80, reg);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004850 sisfb_post_xgi_delay(ivideo, 50);
4851
4852 ranksize = (ivideo->chip == XGI_20) ?
4853 dramsr13[(i * 5) + 3] : dramsr13_4[(i * 5) + 3];
4854
Aaro Koskinene57d4132010-12-20 23:50:16 +02004855 reg = SiS_GetReg(SISSR, 0x13);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004856 if(reg & 0x80) ranksize <<= 1;
4857
4858 if(ivideo->chip == XGI_20) {
4859 if(buswidth == 16) ranksize <<= 1;
4860 else if(buswidth == 32) ranksize <<= 2;
4861 } else {
4862 if(buswidth == 64) ranksize <<= 1;
4863 }
4864
4865 reg = 0;
4866 l = channelab;
4867 if(l == 3) l = 4;
4868 if((ranksize * l) <= 256) {
4869 while((ranksize >>= 1)) reg += 0x10;
4870 }
4871
4872 if(!reg) continue;
4873
Aaro Koskinenad78adb2010-12-20 23:50:20 +02004874 SiS_SetRegANDOR(SISSR, 0x14, 0x0f, (reg & 0xf0));
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004875 sisfb_post_xgi_delay(ivideo, 1);
4876
Aaro Koskinen83ea0f12011-02-13 22:11:23 +00004877 if (sisfb_post_xgi_rwtest(ivideo, j, ((reg >> 4) + channelab - 2 + 20), mapsize)) {
4878 status = 0;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004879 break;
Aaro Koskinen83ea0f12011-02-13 22:11:23 +00004880 }
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004881 }
4882
4883 iounmap(ivideo->video_vbase);
Aaro Koskinen83ea0f12011-02-13 22:11:23 +00004884
4885 return status;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004886}
4887
4888static void __devinit
4889sisfb_post_xgi_setclocks(struct sis_video_info *ivideo, u8 regb)
4890{
4891 u8 v1, v2, v3;
4892 int index;
4893 static const u8 cs90[8 * 3] = {
4894 0x16, 0x01, 0x01,
4895 0x3e, 0x03, 0x01,
4896 0x7c, 0x08, 0x01,
4897 0x79, 0x06, 0x01,
4898 0x29, 0x01, 0x81,
4899 0x5c, 0x23, 0x01,
4900 0x5c, 0x23, 0x01,
4901 0x5c, 0x23, 0x01
4902 };
4903 static const u8 csb8[8 * 3] = {
4904 0x5c, 0x23, 0x01,
4905 0x29, 0x01, 0x01,
4906 0x7c, 0x08, 0x01,
4907 0x79, 0x06, 0x01,
4908 0x29, 0x01, 0x81,
4909 0x5c, 0x23, 0x01,
4910 0x5c, 0x23, 0x01,
4911 0x5c, 0x23, 0x01
4912 };
4913
4914 regb = 0; /* ! */
4915
4916 index = regb * 3;
4917 v1 = cs90[index]; v2 = cs90[index + 1]; v3 = cs90[index + 2];
4918 if(ivideo->haveXGIROM) {
4919 v1 = ivideo->bios_abase[0x90 + index];
4920 v2 = ivideo->bios_abase[0x90 + index + 1];
4921 v3 = ivideo->bios_abase[0x90 + index + 2];
4922 }
Aaro Koskinen44b751b2010-12-20 23:50:17 +02004923 SiS_SetReg(SISSR, 0x28, v1);
4924 SiS_SetReg(SISSR, 0x29, v2);
4925 SiS_SetReg(SISSR, 0x2a, v3);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004926 sisfb_post_xgi_delay(ivideo, 0x43);
4927 sisfb_post_xgi_delay(ivideo, 0x43);
4928 sisfb_post_xgi_delay(ivideo, 0x43);
4929 index = regb * 3;
4930 v1 = csb8[index]; v2 = csb8[index + 1]; v3 = csb8[index + 2];
4931 if(ivideo->haveXGIROM) {
4932 v1 = ivideo->bios_abase[0xb8 + index];
4933 v2 = ivideo->bios_abase[0xb8 + index + 1];
4934 v3 = ivideo->bios_abase[0xb8 + index + 2];
4935 }
Aaro Koskinen44b751b2010-12-20 23:50:17 +02004936 SiS_SetReg(SISSR, 0x2e, v1);
4937 SiS_SetReg(SISSR, 0x2f, v2);
4938 SiS_SetReg(SISSR, 0x30, v3);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004939 sisfb_post_xgi_delay(ivideo, 0x43);
4940 sisfb_post_xgi_delay(ivideo, 0x43);
4941 sisfb_post_xgi_delay(ivideo, 0x43);
4942}
4943
Aaro Koskinenc9982d52011-02-13 22:11:27 +00004944static void __devinit
4945sisfb_post_xgi_ddr2_mrs_default(struct sis_video_info *ivideo, u8 regb)
4946{
4947 unsigned char *bios = ivideo->bios_abase;
4948 u8 v1;
4949
4950 SiS_SetReg(SISSR, 0x28, 0x64);
4951 SiS_SetReg(SISSR, 0x29, 0x63);
4952 sisfb_post_xgi_delay(ivideo, 15);
4953 SiS_SetReg(SISSR, 0x18, 0x00);
4954 SiS_SetReg(SISSR, 0x19, 0x20);
4955 SiS_SetReg(SISSR, 0x16, 0x00);
4956 SiS_SetReg(SISSR, 0x16, 0x80);
4957 SiS_SetReg(SISSR, 0x18, 0xc5);
4958 SiS_SetReg(SISSR, 0x19, 0x23);
4959 SiS_SetReg(SISSR, 0x16, 0x00);
4960 SiS_SetReg(SISSR, 0x16, 0x80);
4961 sisfb_post_xgi_delay(ivideo, 1);
4962 SiS_SetReg(SISCR, 0x97, 0x11);
4963 sisfb_post_xgi_setclocks(ivideo, regb);
4964 sisfb_post_xgi_delay(ivideo, 0x46);
4965 SiS_SetReg(SISSR, 0x18, 0xc5);
4966 SiS_SetReg(SISSR, 0x19, 0x23);
4967 SiS_SetReg(SISSR, 0x16, 0x00);
4968 SiS_SetReg(SISSR, 0x16, 0x80);
4969 sisfb_post_xgi_delay(ivideo, 1);
4970 SiS_SetReg(SISSR, 0x1b, 0x04);
4971 sisfb_post_xgi_delay(ivideo, 1);
4972 SiS_SetReg(SISSR, 0x1b, 0x00);
4973 sisfb_post_xgi_delay(ivideo, 1);
4974 v1 = 0x31;
4975 if (ivideo->haveXGIROM) {
4976 v1 = bios[0xf0];
4977 }
4978 SiS_SetReg(SISSR, 0x18, v1);
4979 SiS_SetReg(SISSR, 0x19, 0x06);
4980 SiS_SetReg(SISSR, 0x16, 0x04);
4981 SiS_SetReg(SISSR, 0x16, 0x84);
4982 sisfb_post_xgi_delay(ivideo, 1);
4983}
4984
4985static void __devinit
Aaro Koskinen42dea9032011-02-13 22:11:28 +00004986sisfb_post_xgi_ddr2_mrs_xg21(struct sis_video_info *ivideo)
4987{
4988 sisfb_post_xgi_setclocks(ivideo, 1);
4989
4990 SiS_SetReg(SISCR, 0x97, 0x11);
4991 sisfb_post_xgi_delay(ivideo, 0x46);
4992
4993 SiS_SetReg(SISSR, 0x18, 0x00); /* EMRS2 */
4994 SiS_SetReg(SISSR, 0x19, 0x80);
4995 SiS_SetReg(SISSR, 0x16, 0x05);
4996 SiS_SetReg(SISSR, 0x16, 0x85);
4997
4998 SiS_SetReg(SISSR, 0x18, 0x00); /* EMRS3 */
4999 SiS_SetReg(SISSR, 0x19, 0xc0);
5000 SiS_SetReg(SISSR, 0x16, 0x05);
5001 SiS_SetReg(SISSR, 0x16, 0x85);
5002
5003 SiS_SetReg(SISSR, 0x18, 0x00); /* EMRS1 */
5004 SiS_SetReg(SISSR, 0x19, 0x40);
5005 SiS_SetReg(SISSR, 0x16, 0x05);
5006 SiS_SetReg(SISSR, 0x16, 0x85);
5007
5008 SiS_SetReg(SISSR, 0x18, 0x42); /* MRS1 */
5009 SiS_SetReg(SISSR, 0x19, 0x02);
5010 SiS_SetReg(SISSR, 0x16, 0x05);
5011 SiS_SetReg(SISSR, 0x16, 0x85);
5012 sisfb_post_xgi_delay(ivideo, 1);
5013
5014 SiS_SetReg(SISSR, 0x1b, 0x04);
5015 sisfb_post_xgi_delay(ivideo, 1);
5016
5017 SiS_SetReg(SISSR, 0x1b, 0x00);
5018 sisfb_post_xgi_delay(ivideo, 1);
5019
5020 SiS_SetReg(SISSR, 0x18, 0x42); /* MRS1 */
5021 SiS_SetReg(SISSR, 0x19, 0x00);
5022 SiS_SetReg(SISSR, 0x16, 0x05);
5023 SiS_SetReg(SISSR, 0x16, 0x85);
5024 sisfb_post_xgi_delay(ivideo, 1);
5025}
5026
5027static void __devinit
Aaro Koskinenc9982d52011-02-13 22:11:27 +00005028sisfb_post_xgi_ddr2(struct sis_video_info *ivideo, u8 regb)
5029{
5030 unsigned char *bios = ivideo->bios_abase;
5031 static const u8 cs158[8] = {
5032 0x88, 0xaa, 0x48, 0x00, 0x00, 0x00, 0x00, 0x00
5033 };
5034 static const u8 cs160[8] = {
5035 0x44, 0x77, 0x77, 0x00, 0x00, 0x00, 0x00, 0x00
5036 };
5037 static const u8 cs168[8] = {
5038 0x48, 0x78, 0x88, 0x00, 0x00, 0x00, 0x00, 0x00
5039 };
5040 u8 reg;
5041 u8 v1;
5042 u8 v2;
5043 u8 v3;
5044
Aaro Koskinen42dea9032011-02-13 22:11:28 +00005045 SiS_SetReg(SISCR, 0xb0, 0x80); /* DDR2 dual frequency mode */
Aaro Koskinenc9982d52011-02-13 22:11:27 +00005046 SiS_SetReg(SISCR, 0x82, 0x77);
5047 SiS_SetReg(SISCR, 0x86, 0x00);
5048 reg = SiS_GetReg(SISCR, 0x86);
5049 SiS_SetReg(SISCR, 0x86, 0x88);
5050 reg = SiS_GetReg(SISCR, 0x86);
5051 v1 = cs168[regb]; v2 = cs160[regb]; v3 = cs158[regb];
5052 if (ivideo->haveXGIROM) {
5053 v1 = bios[regb + 0x168];
5054 v2 = bios[regb + 0x160];
5055 v3 = bios[regb + 0x158];
5056 }
5057 SiS_SetReg(SISCR, 0x86, v1);
5058 SiS_SetReg(SISCR, 0x82, 0x77);
5059 SiS_SetReg(SISCR, 0x85, 0x00);
5060 reg = SiS_GetReg(SISCR, 0x85);
5061 SiS_SetReg(SISCR, 0x85, 0x88);
5062 reg = SiS_GetReg(SISCR, 0x85);
5063 SiS_SetReg(SISCR, 0x85, v2);
5064 SiS_SetReg(SISCR, 0x82, v3);
5065 SiS_SetReg(SISCR, 0x98, 0x01);
5066 SiS_SetReg(SISCR, 0x9a, 0x02);
Aaro Koskinen42dea9032011-02-13 22:11:28 +00005067 if (sisfb_xgi_is21(ivideo))
5068 sisfb_post_xgi_ddr2_mrs_xg21(ivideo);
5069 else
5070 sisfb_post_xgi_ddr2_mrs_default(ivideo, regb);
Aaro Koskinenc9982d52011-02-13 22:11:27 +00005071}
5072
Aaro Koskinen74de5f42011-02-13 22:11:24 +00005073static u8 __devinit
5074sisfb_post_xgi_ramtype(struct sis_video_info *ivideo)
5075{
5076 unsigned char *bios = ivideo->bios_abase;
5077 u8 ramtype;
5078 u8 reg;
5079 u8 v1;
5080
5081 ramtype = 0x00; v1 = 0x10;
5082 if (ivideo->haveXGIROM) {
5083 ramtype = bios[0x62];
5084 v1 = bios[0x1d2];
5085 }
5086 if (!(ramtype & 0x80)) {
Aaro Koskinen5e8700b2011-02-13 22:11:26 +00005087 if (sisfb_xgi_is21(ivideo)) {
5088 SiS_SetRegAND(SISCR, 0xb4, 0xfd); /* GPIO control */
5089 SiS_SetRegOR(SISCR, 0x4a, 0x80); /* GPIOH EN */
5090 reg = SiS_GetReg(SISCR, 0x48);
5091 SiS_SetRegOR(SISCR, 0xb4, 0x02);
5092 ramtype = reg & 0x01; /* GPIOH */
5093 } else if (ivideo->chip == XGI_20) {
Aaro Koskinen74de5f42011-02-13 22:11:24 +00005094 SiS_SetReg(SISCR, 0x97, v1);
5095 reg = SiS_GetReg(SISCR, 0x97);
5096 if (reg & 0x10) {
5097 ramtype = (reg & 0x01) << 1;
5098 }
5099 } else {
5100 reg = SiS_GetReg(SISSR, 0x39);
5101 ramtype = reg & 0x02;
5102 if (!(ramtype)) {
5103 reg = SiS_GetReg(SISSR, 0x3a);
5104 ramtype = (reg >> 1) & 0x01;
5105 }
5106 }
5107 }
5108 ramtype &= 0x07;
5109
5110 return ramtype;
5111}
5112
Thomas Winischhofer544393f2005-09-09 13:04:45 -07005113static int __devinit
5114sisfb_post_xgi(struct pci_dev *pdev)
5115{
5116 struct sis_video_info *ivideo = pci_get_drvdata(pdev);
5117 unsigned char *bios = ivideo->bios_abase;
5118 struct pci_dev *mypdev = NULL;
5119 const u8 *ptr, *ptr2;
5120 u8 v1, v2, v3, v4, v5, reg, ramtype;
5121 u32 rega, regb, regd;
5122 int i, j, k, index;
5123 static const u8 cs78[3] = { 0xf6, 0x0d, 0x00 };
5124 static const u8 cs76[2] = { 0xa3, 0xfb };
5125 static const u8 cs7b[3] = { 0xc0, 0x11, 0x00 };
5126 static const u8 cs158[8] = {
5127 0x88, 0xaa, 0x48, 0x00, 0x00, 0x00, 0x00, 0x00
5128 };
5129 static const u8 cs160[8] = {
5130 0x44, 0x77, 0x77, 0x00, 0x00, 0x00, 0x00, 0x00
5131 };
5132 static const u8 cs168[8] = {
5133 0x48, 0x78, 0x88, 0x00, 0x00, 0x00, 0x00, 0x00
5134 };
5135 static const u8 cs128[3 * 8] = {
5136 0x90, 0x28, 0x24, 0x00, 0x00, 0x00, 0x00, 0x00,
5137 0x77, 0x44, 0x44, 0x00, 0x00, 0x00, 0x00, 0x00,
5138 0x77, 0x44, 0x44, 0x00, 0x00, 0x00, 0x00, 0x00
5139 };
5140 static const u8 cs148[2 * 8] = {
5141 0x55, 0x55, 0x55, 0x00, 0x00, 0x00, 0x00, 0x00,
5142 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
5143 };
5144 static const u8 cs31a[8 * 4] = {
5145 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
5146 0xaa, 0xaa, 0xaa, 0xaa, 0x00, 0x00, 0x00, 0x00,
5147 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
5148 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
5149 };
5150 static const u8 cs33a[8 * 4] = {
5151 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
5152 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
5153 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
5154 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
5155 };
5156 static const u8 cs45a[8 * 2] = {
5157 0x00, 0x00, 0xa0, 0x00, 0xa0, 0x00, 0x00, 0x00,
5158 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
5159 };
5160 static const u8 cs170[7 * 8] = {
5161 0x54, 0x32, 0x44, 0x00, 0x00, 0x00, 0x00, 0x00,
5162 0x54, 0x43, 0x44, 0x00, 0x00, 0x00, 0x00, 0x00,
5163 0x0a, 0x05, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00,
5164 0x44, 0x34, 0x44, 0x00, 0x00, 0x00, 0x00, 0x00,
5165 0x10, 0x0a, 0x0a, 0x00, 0x00, 0x00, 0x00, 0x00,
5166 0x11, 0x0c, 0x0c, 0x00, 0x00, 0x00, 0x00, 0x00,
5167 0x05, 0x05, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00
5168 };
5169 static const u8 cs1a8[3 * 8] = {
5170 0xf0, 0xf0, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x00,
5171 0x05, 0x02, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00,
5172 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
5173 };
5174 static const u8 cs100[2 * 8] = {
5175 0xc4, 0x04, 0x84, 0x00, 0x00, 0x00, 0x00, 0x00,
5176 0xc4, 0x04, 0x84, 0x00, 0x00, 0x00, 0x00, 0x00
5177 };
5178
5179 /* VGA enable */
Aaro Koskinen1e1687d2010-12-20 23:50:14 +02005180 reg = SiS_GetRegByte(SISVGAENABLE) | 0x01;
Aaro Koskinen63e13f82010-12-20 23:50:15 +02005181 SiS_SetRegByte(SISVGAENABLE, reg);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07005182
5183 /* Misc */
Aaro Koskinen1e1687d2010-12-20 23:50:14 +02005184 reg = SiS_GetRegByte(SISMISCR) | 0x01;
Aaro Koskinen63e13f82010-12-20 23:50:15 +02005185 SiS_SetRegByte(SISMISCW, reg);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07005186
5187 /* Unlock SR */
Aaro Koskinen44b751b2010-12-20 23:50:17 +02005188 SiS_SetReg(SISSR, 0x05, 0x86);
Aaro Koskinene57d4132010-12-20 23:50:16 +02005189 reg = SiS_GetReg(SISSR, 0x05);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07005190 if(reg != 0xa1)
5191 return 0;
5192
5193 /* Clear some regs */
5194 for(i = 0; i < 0x22; i++) {
5195 if(0x06 + i == 0x20) continue;
Aaro Koskinen44b751b2010-12-20 23:50:17 +02005196 SiS_SetReg(SISSR, 0x06 + i, 0x00);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07005197 }
5198 for(i = 0; i < 0x0b; i++) {
Aaro Koskinen44b751b2010-12-20 23:50:17 +02005199 SiS_SetReg(SISSR, 0x31 + i, 0x00);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07005200 }
5201 for(i = 0; i < 0x10; i++) {
Aaro Koskinen44b751b2010-12-20 23:50:17 +02005202 SiS_SetReg(SISCR, 0x30 + i, 0x00);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07005203 }
5204
5205 ptr = cs78;
5206 if(ivideo->haveXGIROM) {
5207 ptr = (const u8 *)&bios[0x78];
5208 }
5209 for(i = 0; i < 3; i++) {
Aaro Koskinen44b751b2010-12-20 23:50:17 +02005210 SiS_SetReg(SISSR, 0x23 + i, ptr[i]);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07005211 }
5212
5213 ptr = cs76;
5214 if(ivideo->haveXGIROM) {
5215 ptr = (const u8 *)&bios[0x76];
5216 }
5217 for(i = 0; i < 2; i++) {
Aaro Koskinen44b751b2010-12-20 23:50:17 +02005218 SiS_SetReg(SISSR, 0x21 + i, ptr[i]);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07005219 }
5220
5221 v1 = 0x18; v2 = 0x00;
5222 if(ivideo->haveXGIROM) {
5223 v1 = bios[0x74];
5224 v2 = bios[0x75];
5225 }
Aaro Koskinen44b751b2010-12-20 23:50:17 +02005226 SiS_SetReg(SISSR, 0x07, v1);
5227 SiS_SetReg(SISSR, 0x11, 0x0f);
5228 SiS_SetReg(SISSR, 0x1f, v2);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07005229 /* PCI linear mode, RelIO enabled, A0000 decoding disabled */
Aaro Koskinen44b751b2010-12-20 23:50:17 +02005230 SiS_SetReg(SISSR, 0x20, 0x80 | 0x20 | 0x04);
5231 SiS_SetReg(SISSR, 0x27, 0x74);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07005232
5233 ptr = cs7b;
5234 if(ivideo->haveXGIROM) {
5235 ptr = (const u8 *)&bios[0x7b];
5236 }
5237 for(i = 0; i < 3; i++) {
Aaro Koskinen44b751b2010-12-20 23:50:17 +02005238 SiS_SetReg(SISSR, 0x31 + i, ptr[i]);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07005239 }
5240
5241 if(ivideo->chip == XGI_40) {
5242 if(ivideo->revision_id == 2) {
Aaro Koskinenad78adb2010-12-20 23:50:20 +02005243 SiS_SetRegANDOR(SISSR, 0x3b, 0x3f, 0xc0);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07005244 }
Aaro Koskinen44b751b2010-12-20 23:50:17 +02005245 SiS_SetReg(SISCR, 0x7d, 0xfe);
5246 SiS_SetReg(SISCR, 0x7e, 0x0f);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07005247 }
5248 if(ivideo->revision_id == 0) { /* 40 *and* 20? */
Aaro Koskinen667a8b42010-12-20 23:50:19 +02005249 SiS_SetRegAND(SISCR, 0x58, 0xd7);
Aaro Koskinene57d4132010-12-20 23:50:16 +02005250 reg = SiS_GetReg(SISCR, 0xcb);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07005251 if(reg & 0x20) {
Aaro Koskinenad78adb2010-12-20 23:50:20 +02005252 SiS_SetRegANDOR(SISCR, 0x58, 0xd7, (reg & 0x10) ? 0x08 : 0x20); /* =0x28 Z7 ? */
Thomas Winischhofer544393f2005-09-09 13:04:45 -07005253 }
5254 }
5255
5256 reg = (ivideo->chip == XGI_40) ? 0x20 : 0x00;
Aaro Koskinenad78adb2010-12-20 23:50:20 +02005257 SiS_SetRegANDOR(SISCR, 0x38, 0x1f, reg);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07005258
5259 if(ivideo->chip == XGI_20) {
Aaro Koskinen44b751b2010-12-20 23:50:17 +02005260 SiS_SetReg(SISSR, 0x36, 0x70);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07005261 } else {
Aaro Koskinen44b751b2010-12-20 23:50:17 +02005262 SiS_SetReg(SISVID, 0x00, 0x86);
5263 SiS_SetReg(SISVID, 0x32, 0x00);
5264 SiS_SetReg(SISVID, 0x30, 0x00);
5265 SiS_SetReg(SISVID, 0x32, 0x01);
5266 SiS_SetReg(SISVID, 0x30, 0x00);
Aaro Koskinen667a8b42010-12-20 23:50:19 +02005267 SiS_SetRegAND(SISVID, 0x2f, 0xdf);
5268 SiS_SetRegAND(SISCAP, 0x00, 0x3f);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07005269
Aaro Koskinen44b751b2010-12-20 23:50:17 +02005270 SiS_SetReg(SISPART1, 0x2f, 0x01);
5271 SiS_SetReg(SISPART1, 0x00, 0x00);
5272 SiS_SetReg(SISPART1, 0x02, bios[0x7e]);
5273 SiS_SetReg(SISPART1, 0x2e, 0x08);
Aaro Koskinen667a8b42010-12-20 23:50:19 +02005274 SiS_SetRegAND(SISPART1, 0x35, 0x7f);
5275 SiS_SetRegAND(SISPART1, 0x50, 0xfe);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07005276
Aaro Koskinene57d4132010-12-20 23:50:16 +02005277 reg = SiS_GetReg(SISPART4, 0x00);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07005278 if(reg == 1 || reg == 2) {
Aaro Koskinen44b751b2010-12-20 23:50:17 +02005279 SiS_SetReg(SISPART2, 0x00, 0x1c);
5280 SiS_SetReg(SISPART4, 0x0d, bios[0x7f]);
5281 SiS_SetReg(SISPART4, 0x0e, bios[0x80]);
5282 SiS_SetReg(SISPART4, 0x10, bios[0x81]);
Aaro Koskinen667a8b42010-12-20 23:50:19 +02005283 SiS_SetRegAND(SISPART4, 0x0f, 0x3f);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07005284
Aaro Koskinene57d4132010-12-20 23:50:16 +02005285 reg = SiS_GetReg(SISPART4, 0x01);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07005286 if((reg & 0xf0) >= 0xb0) {
Aaro Koskinene57d4132010-12-20 23:50:16 +02005287 reg = SiS_GetReg(SISPART4, 0x23);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07005288 if(reg & 0x20) reg |= 0x40;
Aaro Koskinen44b751b2010-12-20 23:50:17 +02005289 SiS_SetReg(SISPART4, 0x23, reg);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07005290 reg = (reg & 0x20) ? 0x02 : 0x00;
Aaro Koskinenad78adb2010-12-20 23:50:20 +02005291 SiS_SetRegANDOR(SISPART1, 0x1e, 0xfd, reg);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07005292 }
5293 }
5294
5295 v1 = bios[0x77];
5296
Aaro Koskinene57d4132010-12-20 23:50:16 +02005297 reg = SiS_GetReg(SISSR, 0x3b);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07005298 if(reg & 0x02) {
Aaro Koskinene57d4132010-12-20 23:50:16 +02005299 reg = SiS_GetReg(SISSR, 0x3a);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07005300 v2 = (reg & 0x30) >> 3;
5301 if(!(v2 & 0x04)) v2 ^= 0x02;
Aaro Koskinene57d4132010-12-20 23:50:16 +02005302 reg = SiS_GetReg(SISSR, 0x39);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07005303 if(reg & 0x80) v2 |= 0x80;
5304 v2 |= 0x01;
5305
Adrian Bunk0959f0c2007-05-08 00:39:50 -07005306 if((mypdev = pci_get_device(PCI_VENDOR_ID_SI, 0x0730, NULL))) {
5307 pci_dev_put(mypdev);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07005308 if(((v2 & 0x06) == 2) || ((v2 & 0x06) == 4))
5309 v2 &= 0xf9;
5310 v2 |= 0x08;
5311 v1 &= 0xfe;
5312 } else {
Adrian Bunk0959f0c2007-05-08 00:39:50 -07005313 mypdev = pci_get_device(PCI_VENDOR_ID_SI, 0x0735, NULL);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07005314 if(!mypdev)
Adrian Bunk0959f0c2007-05-08 00:39:50 -07005315 mypdev = pci_get_device(PCI_VENDOR_ID_SI, 0x0645, NULL);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07005316 if(!mypdev)
Adrian Bunk0959f0c2007-05-08 00:39:50 -07005317 mypdev = pci_get_device(PCI_VENDOR_ID_SI, 0x0650, NULL);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07005318 if(mypdev) {
5319 pci_read_config_dword(mypdev, 0x94, &regd);
5320 regd &= 0xfffffeff;
5321 pci_write_config_dword(mypdev, 0x94, regd);
5322 v1 &= 0xfe;
Adrian Bunk0959f0c2007-05-08 00:39:50 -07005323 pci_dev_put(mypdev);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07005324 } else if(sisfb_find_host_bridge(ivideo, pdev, PCI_VENDOR_ID_SI)) {
5325 v1 &= 0xfe;
5326 } else if(sisfb_find_host_bridge(ivideo, pdev, 0x1106) ||
5327 sisfb_find_host_bridge(ivideo, pdev, 0x1022) ||
5328 sisfb_find_host_bridge(ivideo, pdev, 0x700e) ||
5329 sisfb_find_host_bridge(ivideo, pdev, 0x10de)) {
5330 if((v2 & 0x06) == 4)
5331 v2 ^= 0x06;
5332 v2 |= 0x08;
5333 }
5334 }
Aaro Koskinenad78adb2010-12-20 23:50:20 +02005335 SiS_SetRegANDOR(SISCR, 0x5f, 0xf0, v2);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07005336 }
Aaro Koskinen44b751b2010-12-20 23:50:17 +02005337 SiS_SetReg(SISSR, 0x22, v1);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07005338
5339 if(ivideo->revision_id == 2) {
Aaro Koskinene57d4132010-12-20 23:50:16 +02005340 v1 = SiS_GetReg(SISSR, 0x3b);
5341 v2 = SiS_GetReg(SISSR, 0x3a);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07005342 regd = bios[0x90 + 3] | (bios[0x90 + 4] << 8);
5343 if( (!(v1 & 0x02)) && (v2 & 0x30) && (regd < 0xcf) )
Aaro Koskinenad78adb2010-12-20 23:50:20 +02005344 SiS_SetRegANDOR(SISCR, 0x5f, 0xf1, 0x01);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07005345
Adrian Bunk0959f0c2007-05-08 00:39:50 -07005346 if((mypdev = pci_get_device(0x10de, 0x01e0, NULL))) {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07005347 /* TODO: set CR5f &0xf1 | 0x01 for version 6570
5348 * of nforce 2 ROM
5349 */
5350 if(0)
Aaro Koskinenad78adb2010-12-20 23:50:20 +02005351 SiS_SetRegANDOR(SISCR, 0x5f, 0xf1, 0x01);
Adrian Bunk0959f0c2007-05-08 00:39:50 -07005352 pci_dev_put(mypdev);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07005353 }
5354 }
5355
5356 v1 = 0x30;
Aaro Koskinene57d4132010-12-20 23:50:16 +02005357 reg = SiS_GetReg(SISSR, 0x3b);
5358 v2 = SiS_GetReg(SISCR, 0x5f);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07005359 if((!(reg & 0x02)) && (v2 & 0x0e))
5360 v1 |= 0x08;
Aaro Koskinen44b751b2010-12-20 23:50:17 +02005361 SiS_SetReg(SISSR, 0x27, v1);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07005362
5363 if(bios[0x64] & 0x01) {
Aaro Koskinenad78adb2010-12-20 23:50:20 +02005364 SiS_SetRegANDOR(SISCR, 0x5f, 0xf0, bios[0x64]);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07005365 }
5366
5367 v1 = bios[0x4f7];
5368 pci_read_config_dword(pdev, 0x50, &regd);
5369 regd = (regd >> 20) & 0x0f;
5370 if(regd == 1) {
5371 v1 &= 0xfc;
Aaro Koskinen27799d62010-12-20 23:50:18 +02005372 SiS_SetRegOR(SISCR, 0x5f, 0x08);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07005373 }
Aaro Koskinen44b751b2010-12-20 23:50:17 +02005374 SiS_SetReg(SISCR, 0x48, v1);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07005375
Aaro Koskinenad78adb2010-12-20 23:50:20 +02005376 SiS_SetRegANDOR(SISCR, 0x47, 0x04, bios[0x4f6] & 0xfb);
5377 SiS_SetRegANDOR(SISCR, 0x49, 0xf0, bios[0x4f8] & 0x0f);
5378 SiS_SetRegANDOR(SISCR, 0x4a, 0x60, bios[0x4f9] & 0x9f);
5379 SiS_SetRegANDOR(SISCR, 0x4b, 0x08, bios[0x4fa] & 0xf7);
5380 SiS_SetRegANDOR(SISCR, 0x4c, 0x80, bios[0x4fb] & 0x7f);
Aaro Koskinen44b751b2010-12-20 23:50:17 +02005381 SiS_SetReg(SISCR, 0x70, bios[0x4fc]);
Aaro Koskinenad78adb2010-12-20 23:50:20 +02005382 SiS_SetRegANDOR(SISCR, 0x71, 0xf0, bios[0x4fd] & 0x0f);
Aaro Koskinen44b751b2010-12-20 23:50:17 +02005383 SiS_SetReg(SISCR, 0x74, 0xd0);
Aaro Koskinenad78adb2010-12-20 23:50:20 +02005384 SiS_SetRegANDOR(SISCR, 0x74, 0xcf, bios[0x4fe] & 0x30);
5385 SiS_SetRegANDOR(SISCR, 0x75, 0xe0, bios[0x4ff] & 0x1f);
5386 SiS_SetRegANDOR(SISCR, 0x76, 0xe0, bios[0x500] & 0x1f);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07005387 v1 = bios[0x501];
Adrian Bunk0959f0c2007-05-08 00:39:50 -07005388 if((mypdev = pci_get_device(0x8086, 0x2530, NULL))) {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07005389 v1 = 0xf0;
Adrian Bunk0959f0c2007-05-08 00:39:50 -07005390 pci_dev_put(mypdev);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07005391 }
Aaro Koskinen44b751b2010-12-20 23:50:17 +02005392 SiS_SetReg(SISCR, 0x77, v1);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07005393 }
5394
Aaro Koskinen42dea9032011-02-13 22:11:28 +00005395 /* RAM type:
5396 *
5397 * 0 == DDR1, 1 == DDR2, 2..7 == reserved?
5398 *
5399 * The code seems to written so that regb should equal ramtype,
5400 * however, so far it has been hardcoded to 0. Enable other values only
5401 * on XGI Z9, as it passes the POST, and add a warning for others.
5402 */
5403 ramtype = sisfb_post_xgi_ramtype(ivideo);
5404 if (!sisfb_xgi_is21(ivideo) && ramtype) {
5405 dev_warn(&pdev->dev,
5406 "RAM type something else than expected: %d\n",
5407 ramtype);
5408 regb = 0;
5409 } else {
5410 regb = ramtype;
5411 }
Thomas Winischhofer544393f2005-09-09 13:04:45 -07005412
5413 v1 = 0xff;
5414 if(ivideo->haveXGIROM) {
5415 v1 = bios[0x140 + regb];
5416 }
Aaro Koskinen44b751b2010-12-20 23:50:17 +02005417 SiS_SetReg(SISCR, 0x6d, v1);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07005418
5419 ptr = cs128;
5420 if(ivideo->haveXGIROM) {
5421 ptr = (const u8 *)&bios[0x128];
5422 }
5423 for(i = 0, j = 0; i < 3; i++, j += 8) {
Aaro Koskinen44b751b2010-12-20 23:50:17 +02005424 SiS_SetReg(SISCR, 0x68 + i, ptr[j + regb]);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07005425 }
5426
5427 ptr = cs31a;
5428 ptr2 = cs33a;
5429 if(ivideo->haveXGIROM) {
5430 index = (ivideo->chip == XGI_20) ? 0x31a : 0x3a6;
5431 ptr = (const u8 *)&bios[index];
5432 ptr2 = (const u8 *)&bios[index + 0x20];
5433 }
5434 for(i = 0; i < 2; i++) {
5435 if(i == 0) {
5436 regd = le32_to_cpu(((u32 *)ptr)[regb]);
5437 rega = 0x6b;
5438 } else {
5439 regd = le32_to_cpu(((u32 *)ptr2)[regb]);
5440 rega = 0x6e;
5441 }
5442 reg = 0x00;
5443 for(j = 0; j < 16; j++) {
5444 reg &= 0xf3;
5445 if(regd & 0x01) reg |= 0x04;
5446 if(regd & 0x02) reg |= 0x08;
5447 regd >>= 2;
Aaro Koskinen44b751b2010-12-20 23:50:17 +02005448 SiS_SetReg(SISCR, rega, reg);
Aaro Koskinene57d4132010-12-20 23:50:16 +02005449 reg = SiS_GetReg(SISCR, rega);
5450 reg = SiS_GetReg(SISCR, rega);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07005451 reg += 0x10;
5452 }
5453 }
5454
Aaro Koskinen667a8b42010-12-20 23:50:19 +02005455 SiS_SetRegAND(SISCR, 0x6e, 0xfc);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07005456
5457 ptr = NULL;
5458 if(ivideo->haveXGIROM) {
5459 index = (ivideo->chip == XGI_20) ? 0x35a : 0x3e6;
5460 ptr = (const u8 *)&bios[index];
5461 }
5462 for(i = 0; i < 4; i++) {
Aaro Koskinenad78adb2010-12-20 23:50:20 +02005463 SiS_SetRegANDOR(SISCR, 0x6e, 0xfc, i);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07005464 reg = 0x00;
5465 for(j = 0; j < 2; j++) {
5466 regd = 0;
5467 if(ptr) {
5468 regd = le32_to_cpu(((u32 *)ptr)[regb * 8]);
5469 ptr += 4;
5470 }
5471 /* reg = 0x00; */
5472 for(k = 0; k < 16; k++) {
5473 reg &= 0xfc;
5474 if(regd & 0x01) reg |= 0x01;
5475 if(regd & 0x02) reg |= 0x02;
5476 regd >>= 2;
Aaro Koskinen44b751b2010-12-20 23:50:17 +02005477 SiS_SetReg(SISCR, 0x6f, reg);
Aaro Koskinene57d4132010-12-20 23:50:16 +02005478 reg = SiS_GetReg(SISCR, 0x6f);
5479 reg = SiS_GetReg(SISCR, 0x6f);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07005480 reg += 0x08;
5481 }
5482 }
5483 }
5484
5485 ptr = cs148;
5486 if(ivideo->haveXGIROM) {
5487 ptr = (const u8 *)&bios[0x148];
5488 }
5489 for(i = 0, j = 0; i < 2; i++, j += 8) {
Aaro Koskinen44b751b2010-12-20 23:50:17 +02005490 SiS_SetReg(SISCR, 0x80 + i, ptr[j + regb]);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07005491 }
5492
Aaro Koskinen667a8b42010-12-20 23:50:19 +02005493 SiS_SetRegAND(SISCR, 0x89, 0x8f);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07005494
5495 ptr = cs45a;
5496 if(ivideo->haveXGIROM) {
5497 index = (ivideo->chip == XGI_20) ? 0x45a : 0x4e6;
5498 ptr = (const u8 *)&bios[index];
5499 }
5500 regd = le16_to_cpu(((const u16 *)ptr)[regb]);
5501 reg = 0x80;
5502 for(i = 0; i < 5; i++) {
5503 reg &= 0xfc;
5504 if(regd & 0x01) reg |= 0x01;
5505 if(regd & 0x02) reg |= 0x02;
5506 regd >>= 2;
Aaro Koskinen44b751b2010-12-20 23:50:17 +02005507 SiS_SetReg(SISCR, 0x89, reg);
Aaro Koskinene57d4132010-12-20 23:50:16 +02005508 reg = SiS_GetReg(SISCR, 0x89);
5509 reg = SiS_GetReg(SISCR, 0x89);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07005510 reg += 0x10;
5511 }
5512
5513 v1 = 0xb5; v2 = 0x20; v3 = 0xf0; v4 = 0x13;
5514 if(ivideo->haveXGIROM) {
5515 v1 = bios[0x118 + regb];
5516 v2 = bios[0xf8 + regb];
5517 v3 = bios[0x120 + regb];
5518 v4 = bios[0x1ca];
5519 }
Aaro Koskinen44b751b2010-12-20 23:50:17 +02005520 SiS_SetReg(SISCR, 0x45, v1 & 0x0f);
5521 SiS_SetReg(SISCR, 0x99, (v1 >> 4) & 0x07);
Aaro Koskinen27799d62010-12-20 23:50:18 +02005522 SiS_SetRegOR(SISCR, 0x40, v1 & 0x80);
Aaro Koskinen44b751b2010-12-20 23:50:17 +02005523 SiS_SetReg(SISCR, 0x41, v2);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07005524
5525 ptr = cs170;
5526 if(ivideo->haveXGIROM) {
5527 ptr = (const u8 *)&bios[0x170];
5528 }
5529 for(i = 0, j = 0; i < 7; i++, j += 8) {
Aaro Koskinen44b751b2010-12-20 23:50:17 +02005530 SiS_SetReg(SISCR, 0x90 + i, ptr[j + regb]);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07005531 }
5532
Aaro Koskinen44b751b2010-12-20 23:50:17 +02005533 SiS_SetReg(SISCR, 0x59, v3);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07005534
5535 ptr = cs1a8;
5536 if(ivideo->haveXGIROM) {
5537 ptr = (const u8 *)&bios[0x1a8];
5538 }
5539 for(i = 0, j = 0; i < 3; i++, j += 8) {
Aaro Koskinen44b751b2010-12-20 23:50:17 +02005540 SiS_SetReg(SISCR, 0xc3 + i, ptr[j + regb]);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07005541 }
5542
5543 ptr = cs100;
5544 if(ivideo->haveXGIROM) {
5545 ptr = (const u8 *)&bios[0x100];
5546 }
5547 for(i = 0, j = 0; i < 2; i++, j += 8) {
Aaro Koskinen44b751b2010-12-20 23:50:17 +02005548 SiS_SetReg(SISCR, 0x8a + i, ptr[j + regb]);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07005549 }
5550
Aaro Koskinen44b751b2010-12-20 23:50:17 +02005551 SiS_SetReg(SISCR, 0xcf, v4);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07005552
Aaro Koskinen44b751b2010-12-20 23:50:17 +02005553 SiS_SetReg(SISCR, 0x83, 0x09);
5554 SiS_SetReg(SISCR, 0x87, 0x00);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07005555
5556 if(ivideo->chip == XGI_40) {
5557 if( (ivideo->revision_id == 1) ||
5558 (ivideo->revision_id == 2) ) {
Aaro Koskinen44b751b2010-12-20 23:50:17 +02005559 SiS_SetReg(SISCR, 0x8c, 0x87);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07005560 }
5561 }
5562
Aaro Koskinen42dea9032011-02-13 22:11:28 +00005563 if (regb == 1)
5564 SiS_SetReg(SISSR, 0x17, 0x80); /* DDR2 */
5565 else
5566 SiS_SetReg(SISSR, 0x17, 0x00); /* DDR1 */
Aaro Koskinen44b751b2010-12-20 23:50:17 +02005567 SiS_SetReg(SISSR, 0x1a, 0x87);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07005568
5569 if(ivideo->chip == XGI_20) {
Aaro Koskinen44b751b2010-12-20 23:50:17 +02005570 SiS_SetReg(SISSR, 0x15, 0x00);
5571 SiS_SetReg(SISSR, 0x1c, 0x00);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07005572 }
5573
Thomas Winischhofer544393f2005-09-09 13:04:45 -07005574 switch(ramtype) {
5575 case 0:
5576 sisfb_post_xgi_setclocks(ivideo, regb);
5577 if((ivideo->chip == XGI_20) ||
5578 (ivideo->revision_id == 1) ||
5579 (ivideo->revision_id == 2)) {
5580 v1 = cs158[regb]; v2 = cs160[regb]; v3 = cs168[regb];
5581 if(ivideo->haveXGIROM) {
5582 v1 = bios[regb + 0x158];
5583 v2 = bios[regb + 0x160];
5584 v3 = bios[regb + 0x168];
5585 }
Aaro Koskinen44b751b2010-12-20 23:50:17 +02005586 SiS_SetReg(SISCR, 0x82, v1);
5587 SiS_SetReg(SISCR, 0x85, v2);
5588 SiS_SetReg(SISCR, 0x86, v3);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07005589 } else {
Aaro Koskinen44b751b2010-12-20 23:50:17 +02005590 SiS_SetReg(SISCR, 0x82, 0x88);
5591 SiS_SetReg(SISCR, 0x86, 0x00);
Aaro Koskinene57d4132010-12-20 23:50:16 +02005592 reg = SiS_GetReg(SISCR, 0x86);
Aaro Koskinen44b751b2010-12-20 23:50:17 +02005593 SiS_SetReg(SISCR, 0x86, 0x88);
Aaro Koskinene57d4132010-12-20 23:50:16 +02005594 reg = SiS_GetReg(SISCR, 0x86);
Aaro Koskinen44b751b2010-12-20 23:50:17 +02005595 SiS_SetReg(SISCR, 0x86, bios[regb + 0x168]);
5596 SiS_SetReg(SISCR, 0x82, 0x77);
5597 SiS_SetReg(SISCR, 0x85, 0x00);
Aaro Koskinene57d4132010-12-20 23:50:16 +02005598 reg = SiS_GetReg(SISCR, 0x85);
Aaro Koskinen44b751b2010-12-20 23:50:17 +02005599 SiS_SetReg(SISCR, 0x85, 0x88);
Aaro Koskinene57d4132010-12-20 23:50:16 +02005600 reg = SiS_GetReg(SISCR, 0x85);
Aaro Koskinen44b751b2010-12-20 23:50:17 +02005601 SiS_SetReg(SISCR, 0x85, bios[regb + 0x160]);
5602 SiS_SetReg(SISCR, 0x82, bios[regb + 0x158]);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07005603 }
5604 if(ivideo->chip == XGI_40) {
Aaro Koskinen44b751b2010-12-20 23:50:17 +02005605 SiS_SetReg(SISCR, 0x97, 0x00);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07005606 }
Aaro Koskinen44b751b2010-12-20 23:50:17 +02005607 SiS_SetReg(SISCR, 0x98, 0x01);
5608 SiS_SetReg(SISCR, 0x9a, 0x02);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07005609
Aaro Koskinen44b751b2010-12-20 23:50:17 +02005610 SiS_SetReg(SISSR, 0x18, 0x01);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07005611 if((ivideo->chip == XGI_20) ||
5612 (ivideo->revision_id == 2)) {
Aaro Koskinen44b751b2010-12-20 23:50:17 +02005613 SiS_SetReg(SISSR, 0x19, 0x40);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07005614 } else {
Aaro Koskinen44b751b2010-12-20 23:50:17 +02005615 SiS_SetReg(SISSR, 0x19, 0x20);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07005616 }
Aaro Koskinen44b751b2010-12-20 23:50:17 +02005617 SiS_SetReg(SISSR, 0x16, 0x00);
5618 SiS_SetReg(SISSR, 0x16, 0x80);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07005619 if((ivideo->chip == XGI_20) || (bios[0x1cb] != 0x0c)) {
5620 sisfb_post_xgi_delay(ivideo, 0x43);
5621 sisfb_post_xgi_delay(ivideo, 0x43);
5622 sisfb_post_xgi_delay(ivideo, 0x43);
Aaro Koskinen44b751b2010-12-20 23:50:17 +02005623 SiS_SetReg(SISSR, 0x18, 0x00);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07005624 if((ivideo->chip == XGI_20) ||
5625 (ivideo->revision_id == 2)) {
Aaro Koskinen44b751b2010-12-20 23:50:17 +02005626 SiS_SetReg(SISSR, 0x19, 0x40);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07005627 } else {
Aaro Koskinen44b751b2010-12-20 23:50:17 +02005628 SiS_SetReg(SISSR, 0x19, 0x20);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07005629 }
5630 } else if((ivideo->chip == XGI_40) && (bios[0x1cb] == 0x0c)) {
Aaro Koskinen44b751b2010-12-20 23:50:17 +02005631 /* SiS_SetReg(SISSR, 0x16, 0x0c); */ /* ? */
Thomas Winischhofer544393f2005-09-09 13:04:45 -07005632 }
Aaro Koskinen44b751b2010-12-20 23:50:17 +02005633 SiS_SetReg(SISSR, 0x16, 0x00);
5634 SiS_SetReg(SISSR, 0x16, 0x80);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07005635 sisfb_post_xgi_delay(ivideo, 4);
5636 v1 = 0x31; v2 = 0x03; v3 = 0x83; v4 = 0x03; v5 = 0x83;
5637 if(ivideo->haveXGIROM) {
5638 v1 = bios[0xf0];
5639 index = (ivideo->chip == XGI_20) ? 0x4b2 : 0x53e;
5640 v2 = bios[index];
5641 v3 = bios[index + 1];
5642 v4 = bios[index + 2];
5643 v5 = bios[index + 3];
5644 }
Aaro Koskinen44b751b2010-12-20 23:50:17 +02005645 SiS_SetReg(SISSR, 0x18, v1);
5646 SiS_SetReg(SISSR, 0x19, ((ivideo->chip == XGI_20) ? 0x02 : 0x01));
5647 SiS_SetReg(SISSR, 0x16, v2);
5648 SiS_SetReg(SISSR, 0x16, v3);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07005649 sisfb_post_xgi_delay(ivideo, 0x43);
Aaro Koskinen44b751b2010-12-20 23:50:17 +02005650 SiS_SetReg(SISSR, 0x1b, 0x03);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07005651 sisfb_post_xgi_delay(ivideo, 0x22);
Aaro Koskinen44b751b2010-12-20 23:50:17 +02005652 SiS_SetReg(SISSR, 0x18, v1);
5653 SiS_SetReg(SISSR, 0x19, 0x00);
5654 SiS_SetReg(SISSR, 0x16, v4);
5655 SiS_SetReg(SISSR, 0x16, v5);
5656 SiS_SetReg(SISSR, 0x1b, 0x00);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07005657 break;
5658 case 1:
Aaro Koskinenc9982d52011-02-13 22:11:27 +00005659 sisfb_post_xgi_ddr2(ivideo, regb);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07005660 break;
5661 default:
5662 sisfb_post_xgi_setclocks(ivideo, regb);
5663 if((ivideo->chip == XGI_40) &&
5664 ((ivideo->revision_id == 1) ||
5665 (ivideo->revision_id == 2))) {
Aaro Koskinen44b751b2010-12-20 23:50:17 +02005666 SiS_SetReg(SISCR, 0x82, bios[regb + 0x158]);
5667 SiS_SetReg(SISCR, 0x85, bios[regb + 0x160]);
5668 SiS_SetReg(SISCR, 0x86, bios[regb + 0x168]);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07005669 } else {
Aaro Koskinen44b751b2010-12-20 23:50:17 +02005670 SiS_SetReg(SISCR, 0x82, 0x88);
5671 SiS_SetReg(SISCR, 0x86, 0x00);
Aaro Koskinene57d4132010-12-20 23:50:16 +02005672 reg = SiS_GetReg(SISCR, 0x86);
Aaro Koskinen44b751b2010-12-20 23:50:17 +02005673 SiS_SetReg(SISCR, 0x86, 0x88);
5674 SiS_SetReg(SISCR, 0x82, 0x77);
5675 SiS_SetReg(SISCR, 0x85, 0x00);
Aaro Koskinene57d4132010-12-20 23:50:16 +02005676 reg = SiS_GetReg(SISCR, 0x85);
Aaro Koskinen44b751b2010-12-20 23:50:17 +02005677 SiS_SetReg(SISCR, 0x85, 0x88);
Aaro Koskinene57d4132010-12-20 23:50:16 +02005678 reg = SiS_GetReg(SISCR, 0x85);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07005679 v1 = cs160[regb]; v2 = cs158[regb];
5680 if(ivideo->haveXGIROM) {
5681 v1 = bios[regb + 0x160];
5682 v2 = bios[regb + 0x158];
5683 }
Aaro Koskinen44b751b2010-12-20 23:50:17 +02005684 SiS_SetReg(SISCR, 0x85, v1);
5685 SiS_SetReg(SISCR, 0x82, v2);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07005686 }
5687 if(ivideo->chip == XGI_40) {
Aaro Koskinen44b751b2010-12-20 23:50:17 +02005688 SiS_SetReg(SISCR, 0x97, 0x11);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07005689 }
5690 if((ivideo->chip == XGI_40) && (ivideo->revision_id == 2)) {
Aaro Koskinen44b751b2010-12-20 23:50:17 +02005691 SiS_SetReg(SISCR, 0x98, 0x01);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07005692 } else {
Aaro Koskinen44b751b2010-12-20 23:50:17 +02005693 SiS_SetReg(SISCR, 0x98, 0x03);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07005694 }
Aaro Koskinen44b751b2010-12-20 23:50:17 +02005695 SiS_SetReg(SISCR, 0x9a, 0x02);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07005696
5697 if(ivideo->chip == XGI_40) {
Aaro Koskinen44b751b2010-12-20 23:50:17 +02005698 SiS_SetReg(SISSR, 0x18, 0x01);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07005699 } else {
Aaro Koskinen44b751b2010-12-20 23:50:17 +02005700 SiS_SetReg(SISSR, 0x18, 0x00);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07005701 }
Aaro Koskinen44b751b2010-12-20 23:50:17 +02005702 SiS_SetReg(SISSR, 0x19, 0x40);
5703 SiS_SetReg(SISSR, 0x16, 0x00);
5704 SiS_SetReg(SISSR, 0x16, 0x80);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07005705 if((ivideo->chip == XGI_40) && (bios[0x1cb] != 0x0c)) {
5706 sisfb_post_xgi_delay(ivideo, 0x43);
5707 sisfb_post_xgi_delay(ivideo, 0x43);
5708 sisfb_post_xgi_delay(ivideo, 0x43);
Aaro Koskinen44b751b2010-12-20 23:50:17 +02005709 SiS_SetReg(SISSR, 0x18, 0x00);
5710 SiS_SetReg(SISSR, 0x19, 0x40);
5711 SiS_SetReg(SISSR, 0x16, 0x00);
5712 SiS_SetReg(SISSR, 0x16, 0x80);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07005713 }
5714 sisfb_post_xgi_delay(ivideo, 4);
5715 v1 = 0x31;
5716 if(ivideo->haveXGIROM) {
5717 v1 = bios[0xf0];
5718 }
Aaro Koskinen44b751b2010-12-20 23:50:17 +02005719 SiS_SetReg(SISSR, 0x18, v1);
5720 SiS_SetReg(SISSR, 0x19, 0x01);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07005721 if(ivideo->chip == XGI_40) {
Aaro Koskinen44b751b2010-12-20 23:50:17 +02005722 SiS_SetReg(SISSR, 0x16, bios[0x53e]);
5723 SiS_SetReg(SISSR, 0x16, bios[0x53f]);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07005724 } else {
Aaro Koskinen44b751b2010-12-20 23:50:17 +02005725 SiS_SetReg(SISSR, 0x16, 0x05);
5726 SiS_SetReg(SISSR, 0x16, 0x85);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07005727 }
5728 sisfb_post_xgi_delay(ivideo, 0x43);
5729 if(ivideo->chip == XGI_40) {
Aaro Koskinen44b751b2010-12-20 23:50:17 +02005730 SiS_SetReg(SISSR, 0x1b, 0x01);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07005731 } else {
Aaro Koskinen44b751b2010-12-20 23:50:17 +02005732 SiS_SetReg(SISSR, 0x1b, 0x03);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07005733 }
5734 sisfb_post_xgi_delay(ivideo, 0x22);
Aaro Koskinen44b751b2010-12-20 23:50:17 +02005735 SiS_SetReg(SISSR, 0x18, v1);
5736 SiS_SetReg(SISSR, 0x19, 0x00);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07005737 if(ivideo->chip == XGI_40) {
Aaro Koskinen44b751b2010-12-20 23:50:17 +02005738 SiS_SetReg(SISSR, 0x16, bios[0x540]);
5739 SiS_SetReg(SISSR, 0x16, bios[0x541]);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07005740 } else {
Aaro Koskinen44b751b2010-12-20 23:50:17 +02005741 SiS_SetReg(SISSR, 0x16, 0x05);
5742 SiS_SetReg(SISSR, 0x16, 0x85);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07005743 }
Aaro Koskinen44b751b2010-12-20 23:50:17 +02005744 SiS_SetReg(SISSR, 0x1b, 0x00);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07005745 }
5746
5747 regb = 0; /* ! */
5748 v1 = 0x03;
5749 if(ivideo->haveXGIROM) {
5750 v1 = bios[0x110 + regb];
5751 }
Aaro Koskinen44b751b2010-12-20 23:50:17 +02005752 SiS_SetReg(SISSR, 0x1b, v1);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07005753
5754 /* RAM size */
5755 v1 = 0x00; v2 = 0x00;
5756 if(ivideo->haveXGIROM) {
5757 v1 = bios[0x62];
5758 v2 = bios[0x63];
5759 }
5760 regb = 0; /* ! */
5761 regd = 1 << regb;
5762 if((v1 & 0x40) && (v2 & regd) && ivideo->haveXGIROM) {
5763
Aaro Koskinen44b751b2010-12-20 23:50:17 +02005764 SiS_SetReg(SISSR, 0x13, bios[regb + 0xe0]);
5765 SiS_SetReg(SISSR, 0x14, bios[regb + 0xe0 + 8]);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07005766
5767 } else {
Aaro Koskinen83ea0f12011-02-13 22:11:23 +00005768 int err;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07005769
5770 /* Set default mode, don't clear screen */
Richard Knutssonc30660ea2007-02-12 00:55:06 -08005771 ivideo->SiS_Pr.SiS_UseOEM = false;
5772 SiS_SetEnableDstn(&ivideo->SiS_Pr, false);
5773 SiS_SetEnableFstn(&ivideo->SiS_Pr, false);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07005774 ivideo->curFSTN = ivideo->curDSTN = 0;
5775 ivideo->SiS_Pr.VideoMemorySize = 8 << 20;
5776 SiSSetMode(&ivideo->SiS_Pr, 0x2e | 0x80);
5777
Aaro Koskinen44b751b2010-12-20 23:50:17 +02005778 SiS_SetReg(SISSR, 0x05, 0x86);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07005779
5780 /* Disable read-cache */
Aaro Koskinen667a8b42010-12-20 23:50:19 +02005781 SiS_SetRegAND(SISSR, 0x21, 0xdf);
Aaro Koskinen83ea0f12011-02-13 22:11:23 +00005782 err = sisfb_post_xgi_ramsize(ivideo);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07005783 /* Enable read-cache */
Aaro Koskinen27799d62010-12-20 23:50:18 +02005784 SiS_SetRegOR(SISSR, 0x21, 0x20);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07005785
Aaro Koskinen83ea0f12011-02-13 22:11:23 +00005786 if (err) {
5787 dev_err(&pdev->dev,
5788 "%s: RAM size detection failed: %d\n",
5789 __func__, err);
5790 return 0;
5791 }
Thomas Winischhofer544393f2005-09-09 13:04:45 -07005792 }
5793
5794#if 0
5795 printk(KERN_DEBUG "-----------------\n");
5796 for(i = 0; i < 0xff; i++) {
Aaro Koskinene57d4132010-12-20 23:50:16 +02005797 reg = SiS_GetReg(SISCR, i);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07005798 printk(KERN_DEBUG "CR%02x(%x) = 0x%02x\n", i, SISCR, reg);
5799 }
5800 for(i = 0; i < 0x40; i++) {
Aaro Koskinene57d4132010-12-20 23:50:16 +02005801 reg = SiS_GetReg(SISSR, i);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07005802 printk(KERN_DEBUG "SR%02x(%x) = 0x%02x\n", i, SISSR, reg);
5803 }
5804 printk(KERN_DEBUG "-----------------\n");
5805#endif
5806
5807 /* Sense CRT1 */
5808 if(ivideo->chip == XGI_20) {
Aaro Koskinen27799d62010-12-20 23:50:18 +02005809 SiS_SetRegOR(SISCR, 0x32, 0x20);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07005810 } else {
Aaro Koskinene57d4132010-12-20 23:50:16 +02005811 reg = SiS_GetReg(SISPART4, 0x00);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07005812 if((reg == 1) || (reg == 2)) {
5813 sisfb_sense_crt1(ivideo);
5814 } else {
Aaro Koskinen27799d62010-12-20 23:50:18 +02005815 SiS_SetRegOR(SISCR, 0x32, 0x20);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07005816 }
5817 }
5818
5819 /* Set default mode, don't clear screen */
Richard Knutssonc30660ea2007-02-12 00:55:06 -08005820 ivideo->SiS_Pr.SiS_UseOEM = false;
5821 SiS_SetEnableDstn(&ivideo->SiS_Pr, false);
5822 SiS_SetEnableFstn(&ivideo->SiS_Pr, false);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07005823 ivideo->curFSTN = ivideo->curDSTN = 0;
5824 SiSSetMode(&ivideo->SiS_Pr, 0x2e | 0x80);
5825
Aaro Koskinen44b751b2010-12-20 23:50:17 +02005826 SiS_SetReg(SISSR, 0x05, 0x86);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07005827
5828 /* Display off */
Aaro Koskinen27799d62010-12-20 23:50:18 +02005829 SiS_SetRegOR(SISSR, 0x01, 0x20);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07005830
5831 /* Save mode number in CR34 */
Aaro Koskinen44b751b2010-12-20 23:50:17 +02005832 SiS_SetReg(SISCR, 0x34, 0x2e);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07005833
5834 /* Let everyone know what the current mode is */
5835 ivideo->modeprechange = 0x2e;
5836
5837 if(ivideo->chip == XGI_40) {
Aaro Koskinene57d4132010-12-20 23:50:16 +02005838 reg = SiS_GetReg(SISCR, 0xca);
5839 v1 = SiS_GetReg(SISCR, 0xcc);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07005840 if((reg & 0x10) && (!(v1 & 0x04))) {
5841 printk(KERN_ERR
5842 "sisfb: Please connect power to the card.\n");
5843 return 0;
5844 }
5845 }
5846
5847 return 1;
5848}
5849#endif
5850
5851static int __devinit
5852sisfb_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
5853{
5854 struct sisfb_chip_info *chipinfo = &sisfb_chip_info[ent->driver_data];
5855 struct sis_video_info *ivideo = NULL;
5856 struct fb_info *sis_fb_info = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005857 u16 reg16;
5858 u8 reg;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07005859 int i, ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005860
Thomas Winischhofer544393f2005-09-09 13:04:45 -07005861 if(sisfb_off)
5862 return -ENXIO;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005863
Linus Torvalds1da177e2005-04-16 15:20:36 -07005864 sis_fb_info = framebuffer_alloc(sizeof(*ivideo), &pdev->dev);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07005865 if(!sis_fb_info)
5866 return -ENOMEM;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005867
5868 ivideo = (struct sis_video_info *)sis_fb_info->par;
5869 ivideo->memyselfandi = sis_fb_info;
5870
Thomas Winischhofer544393f2005-09-09 13:04:45 -07005871 ivideo->sisfb_id = SISFB_ID;
5872
Linus Torvalds1da177e2005-04-16 15:20:36 -07005873 if(card_list == NULL) {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07005874 ivideo->cardnumber = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005875 } else {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07005876 struct sis_video_info *countvideo = card_list;
5877 ivideo->cardnumber = 1;
Harvey Harrison5e2daeb2008-05-22 15:45:08 -07005878 while((countvideo = countvideo->next) != NULL)
Thomas Winischhofer544393f2005-09-09 13:04:45 -07005879 ivideo->cardnumber++;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005880 }
5881
5882 strncpy(ivideo->myid, chipinfo->chip_name, 30);
5883
5884 ivideo->warncount = 0;
5885 ivideo->chip_id = pdev->device;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07005886 ivideo->chip_vendor = pdev->vendor;
Auke Kok44c10132007-06-08 15:46:36 -07005887 ivideo->revision_id = pdev->revision;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07005888 ivideo->SiS_Pr.ChipRevision = ivideo->revision_id;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005889 pci_read_config_word(pdev, PCI_COMMAND, &reg16);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07005890 ivideo->sisvga_enabled = reg16 & 0x01;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005891 ivideo->pcibus = pdev->bus->number;
5892 ivideo->pcislot = PCI_SLOT(pdev->devfn);
5893 ivideo->pcifunc = PCI_FUNC(pdev->devfn);
5894 ivideo->subsysvendor = pdev->subsystem_vendor;
5895 ivideo->subsysdevice = pdev->subsystem_device;
5896
5897#ifndef MODULE
5898 if(sisfb_mode_idx == -1) {
5899 sisfb_get_vga_mode_from_kernel();
5900 }
5901#endif
5902
5903 ivideo->chip = chipinfo->chip;
Aaro Koskinen929c9722011-02-13 22:11:25 +00005904 ivideo->chip_real_id = chipinfo->chip;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005905 ivideo->sisvga_engine = chipinfo->vgaengine;
5906 ivideo->hwcursor_size = chipinfo->hwcursor_size;
5907 ivideo->CRT2_write_enable = chipinfo->CRT2_write_enable;
5908 ivideo->mni = chipinfo->mni;
5909
5910 ivideo->detectedpdc = 0xff;
5911 ivideo->detectedpdca = 0xff;
5912 ivideo->detectedlcda = 0xff;
5913
Richard Knutssonc30660ea2007-02-12 00:55:06 -08005914 ivideo->sisfb_thismonitor.datavalid = false;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005915
Thomas Winischhofer544393f2005-09-09 13:04:45 -07005916 ivideo->current_base = 0;
5917
5918 ivideo->engineok = 0;
5919
5920 ivideo->sisfb_was_boot_device = 0;
Adrian Bunk14aefd12008-07-23 21:31:12 -07005921
Thomas Winischhofer544393f2005-09-09 13:04:45 -07005922 if(pdev->resource[PCI_ROM_RESOURCE].flags & IORESOURCE_ROM_SHADOW) {
5923 if(ivideo->sisvga_enabled)
5924 ivideo->sisfb_was_boot_device = 1;
5925 else {
5926 printk(KERN_DEBUG "sisfb: PCI device is disabled, "
5927 "but marked as boot video device ???\n");
5928 printk(KERN_DEBUG "sisfb: I will not accept this "
5929 "as the primary VGA device\n");
5930 }
5931 }
Thomas Winischhofer544393f2005-09-09 13:04:45 -07005932
Linus Torvalds1da177e2005-04-16 15:20:36 -07005933 ivideo->sisfb_parm_mem = sisfb_parm_mem;
5934 ivideo->sisfb_accel = sisfb_accel;
5935 ivideo->sisfb_ypan = sisfb_ypan;
5936 ivideo->sisfb_max = sisfb_max;
5937 ivideo->sisfb_userom = sisfb_userom;
5938 ivideo->sisfb_useoem = sisfb_useoem;
5939 ivideo->sisfb_mode_idx = sisfb_mode_idx;
5940 ivideo->sisfb_parm_rate = sisfb_parm_rate;
5941 ivideo->sisfb_crt1off = sisfb_crt1off;
5942 ivideo->sisfb_forcecrt1 = sisfb_forcecrt1;
5943 ivideo->sisfb_crt2type = sisfb_crt2type;
5944 ivideo->sisfb_crt2flags = sisfb_crt2flags;
5945 /* pdc(a), scalelcd, special timing, lvdshl handled below */
5946 ivideo->sisfb_dstn = sisfb_dstn;
5947 ivideo->sisfb_fstn = sisfb_fstn;
5948 ivideo->sisfb_tvplug = sisfb_tvplug;
5949 ivideo->sisfb_tvstd = sisfb_tvstd;
5950 ivideo->tvxpos = sisfb_tvxposoffset;
5951 ivideo->tvypos = sisfb_tvyposoffset;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005952 ivideo->sisfb_nocrt2rate = sisfb_nocrt2rate;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005953 ivideo->refresh_rate = 0;
5954 if(ivideo->sisfb_parm_rate != -1) {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07005955 ivideo->refresh_rate = ivideo->sisfb_parm_rate;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005956 }
5957
5958 ivideo->SiS_Pr.UsePanelScaler = sisfb_scalelcd;
5959 ivideo->SiS_Pr.CenterScreen = -1;
5960 ivideo->SiS_Pr.SiS_CustomT = sisfb_specialtiming;
5961 ivideo->SiS_Pr.LVDSHL = sisfb_lvdshl;
5962
5963 ivideo->SiS_Pr.SiS_Backup70xx = 0xff;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07005964 ivideo->SiS_Pr.SiS_CHOverScan = -1;
Richard Knutssonc30660ea2007-02-12 00:55:06 -08005965 ivideo->SiS_Pr.SiS_ChSW = false;
5966 ivideo->SiS_Pr.SiS_UseLCDA = false;
5967 ivideo->SiS_Pr.HaveEMI = false;
5968 ivideo->SiS_Pr.HaveEMILCD = false;
5969 ivideo->SiS_Pr.OverruleEMI = false;
5970 ivideo->SiS_Pr.SiS_SensibleSR11 = false;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005971 ivideo->SiS_Pr.SiS_MyCR63 = 0x63;
5972 ivideo->SiS_Pr.PDC = -1;
5973 ivideo->SiS_Pr.PDCA = -1;
Richard Knutssonc30660ea2007-02-12 00:55:06 -08005974 ivideo->SiS_Pr.DDCPortMixup = false;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005975#ifdef CONFIG_FB_SIS_315
5976 if(ivideo->chip >= SIS_330) {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07005977 ivideo->SiS_Pr.SiS_MyCR63 = 0x53;
5978 if(ivideo->chip >= SIS_661) {
Richard Knutssonc30660ea2007-02-12 00:55:06 -08005979 ivideo->SiS_Pr.SiS_SensibleSR11 = true;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07005980 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07005981 }
5982#endif
5983
5984 memcpy(&ivideo->default_var, &my_default_var, sizeof(my_default_var));
5985
5986 pci_set_drvdata(pdev, ivideo);
5987
5988 /* Patch special cases */
5989 if((ivideo->nbridge = sisfb_get_northbridge(ivideo->chip))) {
5990 switch(ivideo->nbridge->device) {
5991#ifdef CONFIG_FB_SIS_300
5992 case PCI_DEVICE_ID_SI_730:
Thomas Winischhofer544393f2005-09-09 13:04:45 -07005993 ivideo->chip = SIS_730;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005994 strcpy(ivideo->myid, "SiS 730");
Thomas Winischhofer544393f2005-09-09 13:04:45 -07005995 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005996#endif
5997#ifdef CONFIG_FB_SIS_315
5998 case PCI_DEVICE_ID_SI_651:
5999 /* ivideo->chip is ok */
6000 strcpy(ivideo->myid, "SiS 651");
6001 break;
6002 case PCI_DEVICE_ID_SI_740:
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006003 ivideo->chip = SIS_740;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006004 strcpy(ivideo->myid, "SiS 740");
6005 break;
6006 case PCI_DEVICE_ID_SI_661:
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006007 ivideo->chip = SIS_661;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006008 strcpy(ivideo->myid, "SiS 661");
6009 break;
6010 case PCI_DEVICE_ID_SI_741:
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006011 ivideo->chip = SIS_741;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006012 strcpy(ivideo->myid, "SiS 741");
6013 break;
6014 case PCI_DEVICE_ID_SI_760:
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006015 ivideo->chip = SIS_760;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006016 strcpy(ivideo->myid, "SiS 760");
6017 break;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006018 case PCI_DEVICE_ID_SI_761:
6019 ivideo->chip = SIS_761;
6020 strcpy(ivideo->myid, "SiS 761");
6021 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006022#endif
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006023 default:
6024 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006025 }
6026 }
6027
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006028 ivideo->SiS_Pr.ChipType = ivideo->chip;
6029
6030 ivideo->SiS_Pr.ivideo = (void *)ivideo;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006031
6032#ifdef CONFIG_FB_SIS_315
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006033 if((ivideo->SiS_Pr.ChipType == SIS_315PRO) ||
6034 (ivideo->SiS_Pr.ChipType == SIS_315)) {
6035 ivideo->SiS_Pr.ChipType = SIS_315H;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006036 }
6037#endif
6038
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006039 if(!ivideo->sisvga_enabled) {
6040 if(pci_enable_device(pdev)) {
Adrian Bunk0959f0c2007-05-08 00:39:50 -07006041 if(ivideo->nbridge) pci_dev_put(ivideo->nbridge);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006042 pci_set_drvdata(pdev, NULL);
Krzysztof Helt491bcc92009-06-16 15:34:36 -07006043 framebuffer_release(sis_fb_info);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006044 return -EIO;
6045 }
6046 }
6047
Linus Torvalds1da177e2005-04-16 15:20:36 -07006048 ivideo->video_base = pci_resource_start(pdev, 0);
Aaro Koskinen32ed3032010-11-10 13:04:19 +02006049 ivideo->video_size = pci_resource_len(pdev, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006050 ivideo->mmio_base = pci_resource_start(pdev, 1);
6051 ivideo->mmio_size = pci_resource_len(pdev, 1);
6052 ivideo->SiS_Pr.RelIO = pci_resource_start(pdev, 2) + 0x30;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006053 ivideo->SiS_Pr.IOAddress = ivideo->vga_base = ivideo->SiS_Pr.RelIO;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006054
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006055 SiSRegInit(&ivideo->SiS_Pr, ivideo->SiS_Pr.IOAddress);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006056
6057#ifdef CONFIG_FB_SIS_300
6058 /* Find PCI systems for Chrontel/GPIO communication setup */
6059 if(ivideo->chip == SIS_630) {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006060 i = 0;
6061 do {
6062 if(mychswtable[i].subsysVendor == ivideo->subsysvendor &&
6063 mychswtable[i].subsysCard == ivideo->subsysdevice) {
Richard Knutssonc30660ea2007-02-12 00:55:06 -08006064 ivideo->SiS_Pr.SiS_ChSW = true;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006065 printk(KERN_DEBUG "sisfb: Identified [%s %s] "
6066 "requiring Chrontel/GPIO setup\n",
6067 mychswtable[i].vendorName,
6068 mychswtable[i].cardName);
Adrian Bunk0959f0c2007-05-08 00:39:50 -07006069 ivideo->lpcdev = pci_get_device(PCI_VENDOR_ID_SI, 0x0008, NULL);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006070 break;
6071 }
6072 i++;
6073 } while(mychswtable[i].subsysVendor != 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006074 }
6075#endif
6076
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006077#ifdef CONFIG_FB_SIS_315
6078 if((ivideo->chip == SIS_760) && (ivideo->nbridge)) {
Adrian Bunk0959f0c2007-05-08 00:39:50 -07006079 ivideo->lpcdev = pci_get_slot(ivideo->nbridge->bus, (2 << 3));
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006080 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07006081#endif
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006082
Aaro Koskinen44b751b2010-12-20 23:50:17 +02006083 SiS_SetReg(SISSR, 0x05, 0x86);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006084
6085 if( (!ivideo->sisvga_enabled)
6086#if !defined(__i386__) && !defined(__x86_64__)
6087 || (sisfb_resetcard)
6088#endif
6089 ) {
6090 for(i = 0x30; i <= 0x3f; i++) {
Aaro Koskinen44b751b2010-12-20 23:50:17 +02006091 SiS_SetReg(SISCR, i, 0x00);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006092 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07006093 }
6094
6095 /* Find out about current video mode */
6096 ivideo->modeprechange = 0x03;
Aaro Koskinene57d4132010-12-20 23:50:16 +02006097 reg = SiS_GetReg(SISCR, 0x34);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006098 if(reg & 0x7f) {
6099 ivideo->modeprechange = reg & 0x7f;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006100 } else if(ivideo->sisvga_enabled) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07006101#if defined(__i386__) || defined(__x86_64__)
Adrian Bunk14aefd12008-07-23 21:31:12 -07006102 unsigned char __iomem *tt = ioremap(0x400, 0x100);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006103 if(tt) {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006104 ivideo->modeprechange = readb(tt + 0x49);
6105 iounmap(tt);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006106 }
6107#endif
6108 }
6109
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006110 /* Search and copy ROM image */
6111 ivideo->bios_abase = NULL;
6112 ivideo->SiS_Pr.VirtualRomBase = NULL;
Richard Knutssonc30660ea2007-02-12 00:55:06 -08006113 ivideo->SiS_Pr.UseROM = false;
6114 ivideo->haveXGIROM = ivideo->SiS_Pr.SiS_XGIROM = false;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006115 if(ivideo->sisfb_userom) {
6116 ivideo->SiS_Pr.VirtualRomBase = sisfb_find_rom(pdev);
6117 ivideo->bios_abase = ivideo->SiS_Pr.VirtualRomBase;
Richard Knutssonc30660ea2007-02-12 00:55:06 -08006118 ivideo->SiS_Pr.UseROM = (bool)(ivideo->SiS_Pr.VirtualRomBase);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006119 printk(KERN_INFO "sisfb: Video ROM %sfound\n",
6120 ivideo->SiS_Pr.UseROM ? "" : "not ");
6121 if((ivideo->SiS_Pr.UseROM) && (ivideo->chip >= XGI_20)) {
Richard Knutssonc30660ea2007-02-12 00:55:06 -08006122 ivideo->SiS_Pr.UseROM = false;
6123 ivideo->haveXGIROM = ivideo->SiS_Pr.SiS_XGIROM = true;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006124 if( (ivideo->revision_id == 2) &&
6125 (!(ivideo->bios_abase[0x1d1] & 0x01)) ) {
Richard Knutssonc30660ea2007-02-12 00:55:06 -08006126 ivideo->SiS_Pr.DDCPortMixup = true;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006127 }
6128 }
6129 } else {
6130 printk(KERN_INFO "sisfb: Video ROM usage disabled\n");
6131 }
6132
6133 /* Find systems for special custom timing */
6134 if(ivideo->SiS_Pr.SiS_CustomT == CUT_NONE) {
6135 sisfb_detect_custom_timing(ivideo);
6136 }
6137
Aaro Koskinen929c9722011-02-13 22:11:25 +00006138#ifdef CONFIG_FB_SIS_315
6139 if (ivideo->chip == XGI_20) {
6140 /* Check if our Z7 chip is actually Z9 */
6141 SiS_SetRegOR(SISCR, 0x4a, 0x40); /* GPIOG EN */
6142 reg = SiS_GetReg(SISCR, 0x48);
6143 if (reg & 0x02) { /* GPIOG */
6144 ivideo->chip_real_id = XGI_21;
6145 dev_info(&pdev->dev, "Z9 detected\n");
6146 }
6147 }
6148#endif
6149
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006150 /* POST card in case this has not been done by the BIOS */
6151 if( (!ivideo->sisvga_enabled)
6152#if !defined(__i386__) && !defined(__x86_64__)
6153 || (sisfb_resetcard)
6154#endif
6155 ) {
6156#ifdef CONFIG_FB_SIS_300
6157 if(ivideo->sisvga_engine == SIS_300_VGA) {
6158 if(ivideo->chip == SIS_300) {
6159 sisfb_post_sis300(pdev);
6160 ivideo->sisfb_can_post = 1;
6161 }
6162 }
6163#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -07006164
6165#ifdef CONFIG_FB_SIS_315
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006166 if(ivideo->sisvga_engine == SIS_315_VGA) {
6167 int result = 1;
6168 /* if((ivideo->chip == SIS_315H) ||
Linus Torvalds1da177e2005-04-16 15:20:36 -07006169 (ivideo->chip == SIS_315) ||
6170 (ivideo->chip == SIS_315PRO) ||
6171 (ivideo->chip == SIS_330)) {
6172 sisfb_post_sis315330(pdev);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006173 } else */ if(ivideo->chip == XGI_20) {
6174 result = sisfb_post_xgi(pdev);
6175 ivideo->sisfb_can_post = 1;
6176 } else if((ivideo->chip == XGI_40) && ivideo->haveXGIROM) {
6177 result = sisfb_post_xgi(pdev);
6178 ivideo->sisfb_can_post = 1;
6179 } else {
6180 printk(KERN_INFO "sisfb: Card is not "
6181 "POSTed and sisfb can't do this either.\n");
6182 }
6183 if(!result) {
6184 printk(KERN_ERR "sisfb: Failed to POST card\n");
6185 ret = -ENODEV;
6186 goto error_3;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006187 }
6188 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07006189#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -07006190 }
6191
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006192 ivideo->sisfb_card_posted = 1;
6193
6194 /* Find out about RAM size */
6195 if(sisfb_get_dram_size(ivideo)) {
6196 printk(KERN_INFO "sisfb: Fatal error: Unable to determine VRAM size.\n");
6197 ret = -ENODEV;
6198 goto error_3;
6199 }
6200
6201
6202 /* Enable PCI addressing and MMIO */
Linus Torvalds1da177e2005-04-16 15:20:36 -07006203 if((ivideo->sisfb_mode_idx < 0) ||
6204 ((sisbios_mode[ivideo->sisfb_mode_idx].mode_no[ivideo->mni]) != 0xFF)) {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006205 /* Enable PCI_LINEAR_ADDRESSING and MMIO_ENABLE */
Aaro Koskinen27799d62010-12-20 23:50:18 +02006206 SiS_SetRegOR(SISSR, IND_SIS_PCI_ADDRESS_SET, (SIS_PCI_ADDR_ENABLE | SIS_MEM_MAP_IO_ENABLE));
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006207 /* Enable 2D accelerator engine */
Aaro Koskinen27799d62010-12-20 23:50:18 +02006208 SiS_SetRegOR(SISSR, IND_SIS_MODULE_ENABLE, SIS_ENABLE_2D);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006209 }
6210
6211 if(sisfb_pdc != 0xff) {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006212 if(ivideo->sisvga_engine == SIS_300_VGA)
6213 sisfb_pdc &= 0x3c;
6214 else
6215 sisfb_pdc &= 0x1f;
6216 ivideo->SiS_Pr.PDC = sisfb_pdc;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006217 }
6218#ifdef CONFIG_FB_SIS_315
6219 if(ivideo->sisvga_engine == SIS_315_VGA) {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006220 if(sisfb_pdca != 0xff)
6221 ivideo->SiS_Pr.PDCA = sisfb_pdca & 0x1f;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006222 }
6223#endif
6224
6225 if(!request_mem_region(ivideo->video_base, ivideo->video_size, "sisfb FB")) {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006226 printk(KERN_ERR "sisfb: Fatal error: Unable to reserve %dMB framebuffer memory\n",
6227 (int)(ivideo->video_size >> 20));
Linus Torvalds1da177e2005-04-16 15:20:36 -07006228 printk(KERN_ERR "sisfb: Is there another framebuffer driver active?\n");
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006229 ret = -ENODEV;
6230 goto error_3;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006231 }
6232
6233 if(!request_mem_region(ivideo->mmio_base, ivideo->mmio_size, "sisfb MMIO")) {
6234 printk(KERN_ERR "sisfb: Fatal error: Unable to reserve MMIO region\n");
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006235 ret = -ENODEV;
6236 goto error_2;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006237 }
6238
6239 ivideo->video_vbase = ioremap(ivideo->video_base, ivideo->video_size);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006240 ivideo->SiS_Pr.VideoMemoryAddress = ivideo->video_vbase;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006241 if(!ivideo->video_vbase) {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006242 printk(KERN_ERR "sisfb: Fatal error: Unable to map framebuffer memory\n");
6243 ret = -ENODEV;
6244 goto error_1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006245 }
6246
6247 ivideo->mmio_vbase = ioremap(ivideo->mmio_base, ivideo->mmio_size);
6248 if(!ivideo->mmio_vbase) {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006249 printk(KERN_ERR "sisfb: Fatal error: Unable to map MMIO region\n");
6250 ret = -ENODEV;
6251error_0: iounmap(ivideo->video_vbase);
6252error_1: release_mem_region(ivideo->video_base, ivideo->video_size);
6253error_2: release_mem_region(ivideo->mmio_base, ivideo->mmio_size);
6254error_3: vfree(ivideo->bios_abase);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006255 if(ivideo->lpcdev)
Adrian Bunk0959f0c2007-05-08 00:39:50 -07006256 pci_dev_put(ivideo->lpcdev);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006257 if(ivideo->nbridge)
Adrian Bunk0959f0c2007-05-08 00:39:50 -07006258 pci_dev_put(ivideo->nbridge);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006259 pci_set_drvdata(pdev, NULL);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006260 if(!ivideo->sisvga_enabled)
6261 pci_disable_device(pdev);
Krzysztof Helt491bcc92009-06-16 15:34:36 -07006262 framebuffer_release(sis_fb_info);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006263 return ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006264 }
6265
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006266 printk(KERN_INFO "sisfb: Video RAM at 0x%lx, mapped to 0x%lx, size %ldk\n",
6267 ivideo->video_base, (unsigned long)ivideo->video_vbase, ivideo->video_size / 1024);
6268
6269 if(ivideo->video_offset) {
6270 printk(KERN_INFO "sisfb: Viewport offset %ldk\n",
6271 ivideo->video_offset / 1024);
6272 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07006273
6274 printk(KERN_INFO "sisfb: MMIO at 0x%lx, mapped to 0x%lx, size %ldk\n",
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006275 ivideo->mmio_base, (unsigned long)ivideo->mmio_vbase, ivideo->mmio_size / 1024);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006276
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006277
6278 /* Determine the size of the command queue */
6279 if(ivideo->sisvga_engine == SIS_300_VGA) {
6280 ivideo->cmdQueueSize = TURBO_QUEUE_AREA_SIZE;
6281 } else {
6282 if(ivideo->chip == XGI_20) {
6283 ivideo->cmdQueueSize = COMMAND_QUEUE_AREA_SIZE_Z7;
6284 } else {
6285 ivideo->cmdQueueSize = COMMAND_QUEUE_AREA_SIZE;
6286 }
6287 }
6288
6289 /* Engines are no longer initialized here; this is
6290 * now done after the first mode-switch (if the
6291 * submitted var has its acceleration flags set).
6292 */
6293
6294 /* Calculate the base of the (unused) hw cursor */
6295 ivideo->hwcursor_vbase = ivideo->video_vbase
6296 + ivideo->video_size
6297 - ivideo->cmdQueueSize
6298 - ivideo->hwcursor_size;
6299 ivideo->caps |= HW_CURSOR_CAP;
6300
6301 /* Initialize offscreen memory manager */
Linus Torvalds1da177e2005-04-16 15:20:36 -07006302 if((ivideo->havenoheap = sisfb_heap_init(ivideo))) {
6303 printk(KERN_WARNING "sisfb: Failed to initialize offscreen memory heap\n");
6304 }
6305
6306 /* Used for clearing the screen only, therefore respect our mem limit */
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006307 ivideo->SiS_Pr.VideoMemoryAddress += ivideo->video_offset;
6308 ivideo->SiS_Pr.VideoMemorySize = ivideo->sisfb_mem;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006309
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006310 ivideo->mtrr = -1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006311
6312 ivideo->vbflags = 0;
6313 ivideo->lcddefmodeidx = DEFAULT_LCDMODE;
6314 ivideo->tvdefmodeidx = DEFAULT_TVMODE;
6315 ivideo->defmodeidx = DEFAULT_MODE;
6316
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006317 ivideo->newrom = 0;
6318 if(ivideo->chip < XGI_20) {
6319 if(ivideo->bios_abase) {
6320 ivideo->newrom = SiSDetermineROMLayout661(&ivideo->SiS_Pr);
6321 }
6322 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07006323
6324 if((ivideo->sisfb_mode_idx < 0) ||
6325 ((sisbios_mode[ivideo->sisfb_mode_idx].mode_no[ivideo->mni]) != 0xFF)) {
6326
6327 sisfb_sense_crt1(ivideo);
6328
6329 sisfb_get_VB_type(ivideo);
6330
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006331 if(ivideo->vbflags2 & VB2_VIDEOBRIDGE) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07006332 sisfb_detect_VB_connect(ivideo);
6333 }
6334
6335 ivideo->currentvbflags = ivideo->vbflags & (VB_VIDEOBRIDGE | TV_STANDARD);
6336
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006337 /* Decide on which CRT2 device to use */
6338 if(ivideo->vbflags2 & VB2_VIDEOBRIDGE) {
6339 if(ivideo->sisfb_crt2type != -1) {
6340 if((ivideo->sisfb_crt2type == CRT2_LCD) &&
6341 (ivideo->vbflags & CRT2_LCD)) {
6342 ivideo->currentvbflags |= CRT2_LCD;
6343 } else if(ivideo->sisfb_crt2type != CRT2_LCD) {
6344 ivideo->currentvbflags |= ivideo->sisfb_crt2type;
6345 }
6346 } else {
6347 /* Chrontel 700x TV detection often unreliable, therefore
6348 * use a different default order on such machines
6349 */
6350 if((ivideo->sisvga_engine == SIS_300_VGA) &&
6351 (ivideo->vbflags2 & VB2_CHRONTEL)) {
6352 if(ivideo->vbflags & CRT2_LCD)
6353 ivideo->currentvbflags |= CRT2_LCD;
6354 else if(ivideo->vbflags & CRT2_TV)
6355 ivideo->currentvbflags |= CRT2_TV;
6356 else if(ivideo->vbflags & CRT2_VGA)
6357 ivideo->currentvbflags |= CRT2_VGA;
6358 } else {
6359 if(ivideo->vbflags & CRT2_TV)
6360 ivideo->currentvbflags |= CRT2_TV;
6361 else if(ivideo->vbflags & CRT2_LCD)
6362 ivideo->currentvbflags |= CRT2_LCD;
6363 else if(ivideo->vbflags & CRT2_VGA)
6364 ivideo->currentvbflags |= CRT2_VGA;
6365 }
6366 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07006367 }
6368
6369 if(ivideo->vbflags & CRT2_LCD) {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006370 sisfb_detect_lcd_type(ivideo);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006371 }
6372
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006373 sisfb_save_pdc_emi(ivideo);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006374
6375 if(!ivideo->sisfb_crt1off) {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006376 sisfb_handle_ddc(ivideo, &ivideo->sisfb_thismonitor, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006377 } else {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006378 if((ivideo->vbflags2 & VB2_SISTMDSBRIDGE) &&
6379 (ivideo->vbflags & (CRT2_VGA | CRT2_LCD))) {
6380 sisfb_handle_ddc(ivideo, &ivideo->sisfb_thismonitor, 1);
6381 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07006382 }
6383
6384 if(ivideo->sisfb_mode_idx >= 0) {
6385 int bu = ivideo->sisfb_mode_idx;
6386 ivideo->sisfb_mode_idx = sisfb_validate_mode(ivideo,
6387 ivideo->sisfb_mode_idx, ivideo->currentvbflags);
6388 if(bu != ivideo->sisfb_mode_idx) {
6389 printk(KERN_ERR "Mode %dx%dx%d failed validation\n",
6390 sisbios_mode[bu].xres,
6391 sisbios_mode[bu].yres,
6392 sisbios_mode[bu].bpp);
6393 }
6394 }
6395
6396 if(ivideo->sisfb_mode_idx < 0) {
6397 switch(ivideo->currentvbflags & VB_DISPTYPE_DISP2) {
6398 case CRT2_LCD:
6399 ivideo->sisfb_mode_idx = ivideo->lcddefmodeidx;
6400 break;
6401 case CRT2_TV:
6402 ivideo->sisfb_mode_idx = ivideo->tvdefmodeidx;
6403 break;
6404 default:
6405 ivideo->sisfb_mode_idx = ivideo->defmodeidx;
6406 break;
6407 }
6408 }
6409
6410 ivideo->mode_no = sisbios_mode[ivideo->sisfb_mode_idx].mode_no[ivideo->mni];
6411
6412 if(ivideo->refresh_rate != 0) {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006413 sisfb_search_refresh_rate(ivideo, ivideo->refresh_rate,
6414 ivideo->sisfb_mode_idx);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006415 }
6416
6417 if(ivideo->rate_idx == 0) {
6418 ivideo->rate_idx = sisbios_mode[ivideo->sisfb_mode_idx].rate_idx;
6419 ivideo->refresh_rate = 60;
6420 }
6421
6422 if(ivideo->sisfb_thismonitor.datavalid) {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006423 if(!sisfb_verify_rate(ivideo, &ivideo->sisfb_thismonitor,
6424 ivideo->sisfb_mode_idx,
6425 ivideo->rate_idx,
6426 ivideo->refresh_rate)) {
6427 printk(KERN_INFO "sisfb: WARNING: Refresh rate "
6428 "exceeds monitor specs!\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07006429 }
6430 }
6431
6432 ivideo->video_bpp = sisbios_mode[ivideo->sisfb_mode_idx].bpp;
6433 ivideo->video_width = sisbios_mode[ivideo->sisfb_mode_idx].xres;
6434 ivideo->video_height = sisbios_mode[ivideo->sisfb_mode_idx].yres;
6435
6436 sisfb_set_vparms(ivideo);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006437
Linus Torvalds1da177e2005-04-16 15:20:36 -07006438 printk(KERN_INFO "sisfb: Default mode is %dx%dx%d (%dHz)\n",
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006439 ivideo->video_width, ivideo->video_height, ivideo->video_bpp,
Linus Torvalds1da177e2005-04-16 15:20:36 -07006440 ivideo->refresh_rate);
6441
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006442 /* Set up the default var according to chosen default display mode */
Linus Torvalds1da177e2005-04-16 15:20:36 -07006443 ivideo->default_var.xres = ivideo->default_var.xres_virtual = ivideo->video_width;
6444 ivideo->default_var.yres = ivideo->default_var.yres_virtual = ivideo->video_height;
6445 ivideo->default_var.bits_per_pixel = ivideo->video_bpp;
6446
6447 sisfb_bpp_to_var(ivideo, &ivideo->default_var);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006448
Linus Torvalds1da177e2005-04-16 15:20:36 -07006449 ivideo->default_var.pixclock = (u32) (1000000000 /
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006450 sisfb_mode_rate_to_dclock(&ivideo->SiS_Pr, ivideo->mode_no, ivideo->rate_idx));
6451
6452 if(sisfb_mode_rate_to_ddata(&ivideo->SiS_Pr, ivideo->mode_no,
6453 ivideo->rate_idx, &ivideo->default_var)) {
6454 if((ivideo->default_var.vmode & FB_VMODE_MASK) == FB_VMODE_DOUBLE) {
6455 ivideo->default_var.pixclock <<= 1;
6456 }
6457 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07006458
6459 if(ivideo->sisfb_ypan) {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006460 /* Maximize regardless of sisfb_max at startup */
6461 ivideo->default_var.yres_virtual =
6462 sisfb_calc_maxyres(ivideo, &ivideo->default_var);
6463 if(ivideo->default_var.yres_virtual < ivideo->default_var.yres) {
6464 ivideo->default_var.yres_virtual = ivideo->default_var.yres;
6465 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07006466 }
6467
6468 sisfb_calc_pitch(ivideo, &ivideo->default_var);
6469
6470 ivideo->accel = 0;
6471 if(ivideo->sisfb_accel) {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006472 ivideo->accel = -1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006473#ifdef STUPID_ACCELF_TEXT_SHIT
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006474 ivideo->default_var.accel_flags |= FB_ACCELF_TEXT;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006475#endif
6476 }
6477 sisfb_initaccel(ivideo);
6478
6479#if defined(FBINFO_HWACCEL_DISABLED) && defined(FBINFO_HWACCEL_XPAN)
6480 sis_fb_info->flags = FBINFO_DEFAULT |
6481 FBINFO_HWACCEL_YPAN |
6482 FBINFO_HWACCEL_XPAN |
6483 FBINFO_HWACCEL_COPYAREA |
6484 FBINFO_HWACCEL_FILLRECT |
6485 ((ivideo->accel) ? 0 : FBINFO_HWACCEL_DISABLED);
6486#else
6487 sis_fb_info->flags = FBINFO_FLAG_DEFAULT;
6488#endif
6489 sis_fb_info->var = ivideo->default_var;
6490 sis_fb_info->fix = ivideo->sisfb_fix;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006491 sis_fb_info->screen_base = ivideo->video_vbase + ivideo->video_offset;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006492 sis_fb_info->fbops = &sisfb_ops;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006493 sis_fb_info->pseudo_palette = ivideo->pseudo_palette;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006494
Linus Torvalds1da177e2005-04-16 15:20:36 -07006495 fb_alloc_cmap(&sis_fb_info->cmap, 256 , 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006496
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006497 printk(KERN_DEBUG "sisfb: Initial vbflags 0x%x\n", (int)ivideo->vbflags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006498
6499#ifdef CONFIG_MTRR
6500 ivideo->mtrr = mtrr_add(ivideo->video_base, ivideo->video_size,
6501 MTRR_TYPE_WRCOMB, 1);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006502 if(ivideo->mtrr < 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07006503 printk(KERN_DEBUG "sisfb: Failed to add MTRRs\n");
6504 }
6505#endif
6506
Linus Torvalds1da177e2005-04-16 15:20:36 -07006507 if(register_framebuffer(sis_fb_info) < 0) {
6508 printk(KERN_ERR "sisfb: Fatal error: Failed to register framebuffer\n");
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006509 ret = -EINVAL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006510 iounmap(ivideo->mmio_vbase);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006511 goto error_0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006512 }
6513
6514 ivideo->registered = 1;
6515
6516 /* Enlist us */
6517 ivideo->next = card_list;
6518 card_list = ivideo;
6519
6520 printk(KERN_INFO "sisfb: 2D acceleration is %s, y-panning %s\n",
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006521 ivideo->sisfb_accel ? "enabled" : "disabled",
6522 ivideo->sisfb_ypan ?
6523 (ivideo->sisfb_max ? "enabled (auto-max)" :
6524 "enabled (no auto-max)") :
6525 "disabled");
Linus Torvalds1da177e2005-04-16 15:20:36 -07006526
6527
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006528 printk(KERN_INFO "fb%d: %s frame buffer device version %d.%d.%d\n",
Michal Piotrowski43704092006-10-03 01:15:00 -07006529 sis_fb_info->node, ivideo->myid, VER_MAJOR, VER_MINOR, VER_LEVEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006530
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006531 printk(KERN_INFO "sisfb: Copyright (C) 2001-2005 Thomas Winischhofer\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07006532
6533 } /* if mode = "none" */
6534
6535 return 0;
6536}
6537
6538/*****************************************************/
6539/* PCI DEVICE HANDLING */
6540/*****************************************************/
6541
6542static void __devexit sisfb_remove(struct pci_dev *pdev)
6543{
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006544 struct sis_video_info *ivideo = pci_get_drvdata(pdev);
6545 struct fb_info *sis_fb_info = ivideo->memyselfandi;
6546 int registered = ivideo->registered;
6547 int modechanged = ivideo->modechanged;
6548
Linus Torvalds1da177e2005-04-16 15:20:36 -07006549 /* Unmap */
Linus Torvalds1da177e2005-04-16 15:20:36 -07006550 iounmap(ivideo->mmio_vbase);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006551 iounmap(ivideo->video_vbase);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006552
6553 /* Release mem regions */
6554 release_mem_region(ivideo->video_base, ivideo->video_size);
6555 release_mem_region(ivideo->mmio_base, ivideo->mmio_size);
6556
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006557 vfree(ivideo->bios_abase);
6558
6559 if(ivideo->lpcdev)
Adrian Bunk0959f0c2007-05-08 00:39:50 -07006560 pci_dev_put(ivideo->lpcdev);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006561
6562 if(ivideo->nbridge)
Adrian Bunk0959f0c2007-05-08 00:39:50 -07006563 pci_dev_put(ivideo->nbridge);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006564
Linus Torvalds1da177e2005-04-16 15:20:36 -07006565#ifdef CONFIG_MTRR
6566 /* Release MTRR region */
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006567 if(ivideo->mtrr >= 0)
Linus Torvalds1da177e2005-04-16 15:20:36 -07006568 mtrr_del(ivideo->mtrr, ivideo->video_base, ivideo->video_size);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006569#endif
6570
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006571 pci_set_drvdata(pdev, NULL);
6572
6573 /* If device was disabled when starting, disable
6574 * it when quitting.
6575 */
6576 if(!ivideo->sisvga_enabled)
6577 pci_disable_device(pdev);
6578
Linus Torvalds1da177e2005-04-16 15:20:36 -07006579 /* Unregister the framebuffer */
6580 if(ivideo->registered) {
6581 unregister_framebuffer(sis_fb_info);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006582 framebuffer_release(sis_fb_info);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006583 }
6584
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006585 /* OK, our ivideo is gone for good from here. */
Linus Torvalds1da177e2005-04-16 15:20:36 -07006586
6587 /* TODO: Restore the initial mode
6588 * This sounds easy but is as good as impossible
6589 * on many machines with SiS chip and video bridge
6590 * since text modes are always set up differently
6591 * from machine to machine. Depends on the type
6592 * of integration between chipset and bridge.
6593 */
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006594 if(registered && modechanged)
6595 printk(KERN_INFO
6596 "sisfb: Restoring of text mode not supported yet\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07006597};
6598
6599static struct pci_driver sisfb_driver = {
6600 .name = "sisfb",
6601 .id_table = sisfb_pci_table,
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006602 .probe = sisfb_probe,
Linus Torvalds1da177e2005-04-16 15:20:36 -07006603 .remove = __devexit_p(sisfb_remove)
6604};
6605
Adrian Bunk14aefd12008-07-23 21:31:12 -07006606static int __init sisfb_init(void)
Linus Torvalds1da177e2005-04-16 15:20:36 -07006607{
Linus Torvalds1da177e2005-04-16 15:20:36 -07006608#ifndef MODULE
6609 char *options = NULL;
6610
6611 if(fb_get_options("sisfb", &options))
6612 return -ENODEV;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006613
Linus Torvalds1da177e2005-04-16 15:20:36 -07006614 sisfb_setup(options);
6615#endif
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006616 return pci_register_driver(&sisfb_driver);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006617}
6618
Linus Torvalds1da177e2005-04-16 15:20:36 -07006619#ifndef MODULE
6620module_init(sisfb_init);
6621#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -07006622
6623/*****************************************************/
6624/* MODULE */
6625/*****************************************************/
6626
6627#ifdef MODULE
6628
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006629static char *mode = NULL;
6630static int vesa = -1;
6631static unsigned int rate = 0;
6632static unsigned int crt1off = 1;
6633static unsigned int mem = 0;
6634static char *forcecrt2type = NULL;
6635static int forcecrt1 = -1;
6636static int pdc = -1;
6637static int pdc1 = -1;
6638static int noaccel = -1;
6639static int noypan = -1;
6640static int nomax = -1;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006641static int userom = -1;
6642static int useoem = -1;
6643static char *tvstandard = NULL;
6644static int nocrt2rate = 0;
6645static int scalelcd = -1;
6646static char *specialtiming = NULL;
6647static int lvdshl = -1;
6648static int tvxposoffset = 0, tvyposoffset = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006649#if !defined(__i386__) && !defined(__x86_64__)
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006650static int resetcard = 0;
6651static int videoram = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006652#endif
6653
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006654static int __init sisfb_init_module(void)
6655{
6656 sisfb_setdefaultparms();
6657
6658 if(rate)
6659 sisfb_parm_rate = rate;
6660
6661 if((scalelcd == 0) || (scalelcd == 1))
6662 sisfb_scalelcd = scalelcd ^ 1;
6663
6664 /* Need to check crt2 type first for fstn/dstn */
6665
6666 if(forcecrt2type)
6667 sisfb_search_crt2type(forcecrt2type);
6668
6669 if(tvstandard)
6670 sisfb_search_tvstd(tvstandard);
6671
6672 if(mode)
Richard Knutssonc30660ea2007-02-12 00:55:06 -08006673 sisfb_search_mode(mode, false);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006674 else if(vesa != -1)
Richard Knutssonc30660ea2007-02-12 00:55:06 -08006675 sisfb_search_vesamode(vesa, false);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006676
6677 sisfb_crt1off = (crt1off == 0) ? 1 : 0;
6678
6679 sisfb_forcecrt1 = forcecrt1;
6680 if(forcecrt1 == 1)
6681 sisfb_crt1off = 0;
6682 else if(forcecrt1 == 0)
6683 sisfb_crt1off = 1;
6684
6685 if(noaccel == 1)
6686 sisfb_accel = 0;
6687 else if(noaccel == 0)
6688 sisfb_accel = 1;
6689
6690 if(noypan == 1)
6691 sisfb_ypan = 0;
6692 else if(noypan == 0)
6693 sisfb_ypan = 1;
6694
6695 if(nomax == 1)
6696 sisfb_max = 0;
6697 else if(nomax == 0)
6698 sisfb_max = 1;
6699
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006700 if(mem)
6701 sisfb_parm_mem = mem;
6702
6703 if(userom != -1)
6704 sisfb_userom = userom;
6705
6706 if(useoem != -1)
6707 sisfb_useoem = useoem;
6708
6709 if(pdc != -1)
6710 sisfb_pdc = (pdc & 0x7f);
6711
6712 if(pdc1 != -1)
6713 sisfb_pdca = (pdc1 & 0x1f);
6714
6715 sisfb_nocrt2rate = nocrt2rate;
6716
6717 if(specialtiming)
6718 sisfb_search_specialtiming(specialtiming);
6719
6720 if((lvdshl >= 0) && (lvdshl <= 3))
6721 sisfb_lvdshl = lvdshl;
6722
6723 sisfb_tvxposoffset = tvxposoffset;
6724 sisfb_tvyposoffset = tvyposoffset;
6725
6726#if !defined(__i386__) && !defined(__x86_64__)
6727 sisfb_resetcard = (resetcard) ? 1 : 0;
6728 if(videoram)
6729 sisfb_videoram = videoram;
6730#endif
6731
6732 return sisfb_init();
6733}
6734
6735static void __exit sisfb_remove_module(void)
6736{
6737 pci_unregister_driver(&sisfb_driver);
6738 printk(KERN_DEBUG "sisfb: Module unloaded\n");
6739}
6740
6741module_init(sisfb_init_module);
6742module_exit(sisfb_remove_module);
6743
6744MODULE_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 -07006745MODULE_LICENSE("GPL");
6746MODULE_AUTHOR("Thomas Winischhofer <thomas@winischhofer.net>, Others");
6747
Linus Torvalds1da177e2005-04-16 15:20:36 -07006748module_param(mem, int, 0);
6749module_param(noaccel, int, 0);
6750module_param(noypan, int, 0);
6751module_param(nomax, int, 0);
6752module_param(userom, int, 0);
6753module_param(useoem, int, 0);
6754module_param(mode, charp, 0);
6755module_param(vesa, int, 0);
6756module_param(rate, int, 0);
6757module_param(forcecrt1, int, 0);
6758module_param(forcecrt2type, charp, 0);
6759module_param(scalelcd, int, 0);
6760module_param(pdc, int, 0);
6761module_param(pdc1, int, 0);
6762module_param(specialtiming, charp, 0);
6763module_param(lvdshl, int, 0);
6764module_param(tvstandard, charp, 0);
6765module_param(tvxposoffset, int, 0);
6766module_param(tvyposoffset, int, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006767module_param(nocrt2rate, int, 0);
6768#if !defined(__i386__) && !defined(__x86_64__)
6769module_param(resetcard, int, 0);
6770module_param(videoram, int, 0);
6771#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -07006772
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006773MODULE_PARM_DESC(mem,
6774 "\nDetermines the beginning of the video memory heap in KB. This heap is used\n"
6775 "for video RAM management for eg. DRM/DRI. On 300 series, the default depends\n"
6776 "on the amount of video RAM available. If 8MB of video RAM or less is available,\n"
6777 "the heap starts at 4096KB, if between 8 and 16MB are available at 8192KB,\n"
6778 "otherwise at 12288KB. On 315/330/340 series, the heap size is 32KB by default.\n"
6779 "The value is to be specified without 'KB'.\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07006780
6781MODULE_PARM_DESC(noaccel,
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006782 "\nIf set to anything other than 0, 2D acceleration will be disabled.\n"
Linus Torvalds1da177e2005-04-16 15:20:36 -07006783 "(default: 0)\n");
6784
6785MODULE_PARM_DESC(noypan,
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006786 "\nIf set to anything other than 0, y-panning will be disabled and scrolling\n"
6787 "will be performed by redrawing the screen. (default: 0)\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07006788
6789MODULE_PARM_DESC(nomax,
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006790 "\nIf y-panning is enabled, sisfb will by default use the entire available video\n"
Linus Torvalds1da177e2005-04-16 15:20:36 -07006791 "memory for the virtual screen in order to optimize scrolling performance. If\n"
6792 "this is set to anything other than 0, sisfb will not do this and thereby \n"
6793 "enable the user to positively specify a virtual Y size of the screen using\n"
6794 "fbset. (default: 0)\n");
6795
Linus Torvalds1da177e2005-04-16 15:20:36 -07006796MODULE_PARM_DESC(mode,
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006797 "\nSelects the desired default display mode in the format XxYxDepth,\n"
6798 "eg. 1024x768x16. Other formats supported include XxY-Depth and\n"
Linus Torvalds1da177e2005-04-16 15:20:36 -07006799 "XxY-Depth@Rate. If the parameter is only one (decimal or hexadecimal)\n"
6800 "number, it will be interpreted as a VESA mode number. (default: 800x600x8)\n");
6801
6802MODULE_PARM_DESC(vesa,
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006803 "\nSelects the desired default display mode by VESA defined mode number, eg.\n"
6804 "0x117 (default: 0x0103)\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07006805
6806MODULE_PARM_DESC(rate,
6807 "\nSelects the desired vertical refresh rate for CRT1 (external VGA) in Hz.\n"
6808 "If the mode is specified in the format XxY-Depth@Rate, this parameter\n"
6809 "will be ignored (default: 60)\n");
6810
6811MODULE_PARM_DESC(forcecrt1,
6812 "\nNormally, the driver autodetects whether or not CRT1 (external VGA) is \n"
6813 "connected. With this option, the detection can be overridden (1=CRT1 ON,\n"
6814 "0=CRT1 OFF) (default: [autodetected])\n");
6815
6816MODULE_PARM_DESC(forcecrt2type,
6817 "\nIf this option is omitted, the driver autodetects CRT2 output devices, such as\n"
6818 "LCD, TV or secondary VGA. With this option, this autodetection can be\n"
6819 "overridden. Possible parameters are LCD, TV, VGA or NONE. NONE disables CRT2.\n"
6820 "On systems with a SiS video bridge, parameters SVIDEO, COMPOSITE or SCART can\n"
6821 "be used instead of TV to override the TV detection. Furthermore, on systems\n"
6822 "with a SiS video bridge, SVIDEO+COMPOSITE, HIVISION, YPBPR480I, YPBPR480P,\n"
6823 "YPBPR720P and YPBPR1080I are understood. However, whether or not these work\n"
6824 "depends on the very hardware in use. (default: [autodetected])\n");
6825
6826MODULE_PARM_DESC(scalelcd,
6827 "\nSetting this to 1 will force the driver to scale the LCD image to the panel's\n"
6828 "native resolution. Setting it to 0 will disable scaling; LVDS panels will\n"
6829 "show black bars around the image, TMDS panels will probably do the scaling\n"
6830 "themselves. Default: 1 on LVDS panels, 0 on TMDS panels\n");
6831
6832MODULE_PARM_DESC(pdc,
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006833 "\nThis is for manually selecting the LCD panel delay compensation. The driver\n"
Linus Torvalds1da177e2005-04-16 15:20:36 -07006834 "should detect this correctly in most cases; however, sometimes this is not\n"
6835 "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 -07006836 "on a 300 series chipset; 6 on other chipsets. If the problem persists, try\n"
6837 "other values (on 300 series: between 4 and 60 in steps of 4; otherwise: any\n"
6838 "value from 0 to 31). (default: autodetected, if LCD is active during start)\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07006839
6840#ifdef CONFIG_FB_SIS_315
6841MODULE_PARM_DESC(pdc1,
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006842 "\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 -07006843 "series only. (default: autodetected if LCD is in LCD-via-CRT1 mode during\n"
6844 "startup) - Note: currently, this has no effect because LCD-via-CRT1 is not\n"
6845 "implemented yet.\n");
6846#endif
6847
6848MODULE_PARM_DESC(specialtiming,
6849 "\nPlease refer to documentation for more information on this option.\n");
6850
6851MODULE_PARM_DESC(lvdshl,
6852 "\nPlease refer to documentation for more information on this option.\n");
6853
6854MODULE_PARM_DESC(tvstandard,
6855 "\nThis allows overriding the BIOS default for the TV standard. Valid choices are\n"
6856 "pal, ntsc, palm and paln. (default: [auto; pal or ntsc only])\n");
6857
6858MODULE_PARM_DESC(tvxposoffset,
6859 "\nRelocate TV output horizontally. Possible parameters: -32 through 32.\n"
6860 "Default: 0\n");
6861
6862MODULE_PARM_DESC(tvyposoffset,
6863 "\nRelocate TV output vertically. Possible parameters: -32 through 32.\n"
6864 "Default: 0\n");
6865
Linus Torvalds1da177e2005-04-16 15:20:36 -07006866MODULE_PARM_DESC(nocrt2rate,
6867 "\nSetting this to 1 will force the driver to use the default refresh rate for\n"
6868 "CRT2 if CRT2 type is VGA. (default: 0, use same rate as CRT1)\n");
6869
Linus Torvalds1da177e2005-04-16 15:20:36 -07006870#if !defined(__i386__) && !defined(__x86_64__)
6871#ifdef CONFIG_FB_SIS_300
6872MODULE_PARM_DESC(resetcard,
6873 "\nSet this to 1 in order to reset (POST) the card on non-x86 machines where\n"
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006874 "the BIOS did not POST the card (only supported for SiS 300/305 and XGI cards\n"
6875 "currently). Default: 0\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07006876
6877MODULE_PARM_DESC(videoram,
6878 "\nSet this to the amount of video RAM (in kilobyte) the card has. Required on\n"
6879 "some non-x86 architectures where the memory auto detection fails. Only\n"
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006880 "relevant if resetcard is set, too. SiS300/305 only. Default: [auto-detect]\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07006881#endif
6882#endif
6883
Linus Torvalds1da177e2005-04-16 15:20:36 -07006884#endif /* /MODULE */
6885
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006886/* _GPL only for new symbols. */
Linus Torvalds1da177e2005-04-16 15:20:36 -07006887EXPORT_SYMBOL(sis_malloc);
6888EXPORT_SYMBOL(sis_free);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006889EXPORT_SYMBOL_GPL(sis_malloc_new);
6890EXPORT_SYMBOL_GPL(sis_free_new);
6891
Linus Torvalds1da177e2005-04-16 15:20:36 -07006892
6893