blob: 22ad028bf123c2ca4bf9030049fea40f5910fc38 [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
Greg Kroah-Hartman48c68c42012-12-21 13:07:39 -0800109static void sisfb_search_vesamode(unsigned int vesamode, bool quiet)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700110{
111 int i = 0, j = 0;
112
Thomas Winischhofer544393f2005-09-09 13:04:45 -0700113 /* We don't know the hardware specs yet and there is no ivideo */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700114
115 if(vesamode == 0) {
Thomas Winischhofer544393f2005-09-09 13:04:45 -0700116 if(!quiet)
117 printk(KERN_ERR "sisfb: Invalid mode. Using default.\n");
118
Linus Torvalds1da177e2005-04-16 15:20:36 -0700119 sisfb_mode_idx = DEFAULT_MODE;
Michal Piotrowski43704092006-10-03 01:15:00 -0700120
Linus Torvalds1da177e2005-04-16 15:20:36 -0700121 return;
122 }
123
124 vesamode &= 0x1dff; /* Clean VESA mode number from other flags */
125
126 while(sisbios_mode[i++].mode_no[0] != 0) {
127 if( (sisbios_mode[i-1].vesa_mode_no_1 == vesamode) ||
128 (sisbios_mode[i-1].vesa_mode_no_2 == vesamode) ) {
Thomas Winischhofer544393f2005-09-09 13:04:45 -0700129 if(sisfb_fstn) {
130 if(sisbios_mode[i-1].mode_no[1] == 0x50 ||
131 sisbios_mode[i-1].mode_no[1] == 0x56 ||
132 sisbios_mode[i-1].mode_no[1] == 0x53)
133 continue;
134 } else {
135 if(sisbios_mode[i-1].mode_no[1] == 0x5a ||
136 sisbios_mode[i-1].mode_no[1] == 0x5b)
137 continue;
138 }
139 sisfb_mode_idx = i - 1;
140 j = 1;
141 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700142 }
143 }
Thomas Winischhofer544393f2005-09-09 13:04:45 -0700144 if((!j) && !quiet)
145 printk(KERN_ERR "sisfb: Invalid VESA mode 0x%x'\n", vesamode);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700146}
147
Greg Kroah-Hartman48c68c42012-12-21 13:07:39 -0800148static void sisfb_search_mode(char *name, bool quiet)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700149{
Linus Torvalds1da177e2005-04-16 15:20:36 -0700150 unsigned int j = 0, xres = 0, yres = 0, depth = 0, rate = 0;
Thomas Winischhofer544393f2005-09-09 13:04:45 -0700151 int i = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700152 char strbuf[16], strbuf1[20];
153 char *nameptr = name;
154
Thomas Winischhofer544393f2005-09-09 13:04:45 -0700155 /* We don't know the hardware specs yet and there is no ivideo */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700156
157 if(name == NULL) {
Thomas Winischhofer544393f2005-09-09 13:04:45 -0700158 if(!quiet)
159 printk(KERN_ERR "sisfb: Internal error, using default mode.\n");
160
161 sisfb_mode_idx = DEFAULT_MODE;
162 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700163 }
164
Thomas Winischhofer544393f2005-09-09 13:04:45 -0700165 if(!strnicmp(name, sisbios_mode[MODE_INDEX_NONE].name, strlen(name))) {
166 if(!quiet)
167 printk(KERN_ERR "sisfb: Mode 'none' not supported anymore. Using default.\n");
168
169 sisfb_mode_idx = DEFAULT_MODE;
170 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700171 }
Michal Piotrowski43704092006-10-03 01:15:00 -0700172
Linus Torvalds1da177e2005-04-16 15:20:36 -0700173 if(strlen(name) <= 19) {
Thomas Winischhofer544393f2005-09-09 13:04:45 -0700174 strcpy(strbuf1, name);
175 for(i = 0; i < strlen(strbuf1); i++) {
176 if(strbuf1[i] < '0' || strbuf1[i] > '9') strbuf1[i] = ' ';
177 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700178
Thomas Winischhofer544393f2005-09-09 13:04:45 -0700179 /* This does some fuzzy mode naming detection */
180 if(sscanf(strbuf1, "%u %u %u %u", &xres, &yres, &depth, &rate) == 4) {
181 if((rate <= 32) || (depth > 32)) {
182 j = rate; rate = depth; depth = j;
183 }
184 sprintf(strbuf, "%ux%ux%u", xres, yres, depth);
185 nameptr = strbuf;
186 sisfb_parm_rate = rate;
187 } else if(sscanf(strbuf1, "%u %u %u", &xres, &yres, &depth) == 3) {
188 sprintf(strbuf, "%ux%ux%u", xres, yres, depth);
189 nameptr = strbuf;
190 } else {
191 xres = 0;
192 if((sscanf(strbuf1, "%u %u", &xres, &yres) == 2) && (xres != 0)) {
193 sprintf(strbuf, "%ux%ux8", xres, yres);
194 nameptr = strbuf;
195 } else {
196 sisfb_search_vesamode(simple_strtoul(name, NULL, 0), quiet);
197 return;
198 }
199 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700200 }
201
202 i = 0; j = 0;
203 while(sisbios_mode[i].mode_no[0] != 0) {
204 if(!strnicmp(nameptr, sisbios_mode[i++].name, strlen(nameptr))) {
Thomas Winischhofer544393f2005-09-09 13:04:45 -0700205 if(sisfb_fstn) {
206 if(sisbios_mode[i-1].mode_no[1] == 0x50 ||
207 sisbios_mode[i-1].mode_no[1] == 0x56 ||
208 sisbios_mode[i-1].mode_no[1] == 0x53)
209 continue;
210 } else {
211 if(sisbios_mode[i-1].mode_no[1] == 0x5a ||
212 sisbios_mode[i-1].mode_no[1] == 0x5b)
213 continue;
214 }
215 sisfb_mode_idx = i - 1;
216 j = 1;
217 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700218 }
219 }
Thomas Winischhofer544393f2005-09-09 13:04:45 -0700220
221 if((!j) && !quiet)
222 printk(KERN_ERR "sisfb: Invalid mode '%s'\n", nameptr);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700223}
224
225#ifndef MODULE
Greg Kroah-Hartman48c68c42012-12-21 13:07:39 -0800226static void sisfb_get_vga_mode_from_kernel(void)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700227{
Adrian Bunk31c5cdb2006-06-26 00:26:28 -0700228#ifdef CONFIG_X86
Thomas Winischhofer544393f2005-09-09 13:04:45 -0700229 char mymode[32];
Linus Torvalds1da177e2005-04-16 15:20:36 -0700230 int mydepth = screen_info.lfb_depth;
231
232 if(screen_info.orig_video_isVGA != VIDEO_TYPE_VLFB) return;
233
234 if( (screen_info.lfb_width >= 320) && (screen_info.lfb_width <= 2048) &&
235 (screen_info.lfb_height >= 200) && (screen_info.lfb_height <= 1536) &&
236 (mydepth >= 8) && (mydepth <= 32) ) {
237
Thomas Winischhofer544393f2005-09-09 13:04:45 -0700238 if(mydepth == 24) mydepth = 32;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700239
Thomas Winischhofer544393f2005-09-09 13:04:45 -0700240 sprintf(mymode, "%ux%ux%u", screen_info.lfb_width,
241 screen_info.lfb_height,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700242 mydepth);
243
Thomas Winischhofer544393f2005-09-09 13:04:45 -0700244 printk(KERN_DEBUG
245 "sisfb: Using vga mode %s pre-set by kernel as default\n",
246 mymode);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700247
Richard Knutssonc30660ea2007-02-12 00:55:06 -0800248 sisfb_search_mode(mymode, true);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700249 }
250#endif
251 return;
252}
253#endif
254
255static void __init
256sisfb_search_crt2type(const char *name)
257{
258 int i = 0;
259
Thomas Winischhofer544393f2005-09-09 13:04:45 -0700260 /* We don't know the hardware specs yet and there is no ivideo */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700261
262 if(name == NULL) return;
263
264 while(sis_crt2type[i].type_no != -1) {
Thomas Winischhofer544393f2005-09-09 13:04:45 -0700265 if(!strnicmp(name, sis_crt2type[i].name, strlen(sis_crt2type[i].name))) {
266 sisfb_crt2type = sis_crt2type[i].type_no;
267 sisfb_tvplug = sis_crt2type[i].tvplug_no;
268 sisfb_crt2flags = sis_crt2type[i].flags;
269 break;
270 }
271 i++;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700272 }
273
274 sisfb_dstn = (sisfb_crt2flags & FL_550_DSTN) ? 1 : 0;
275 sisfb_fstn = (sisfb_crt2flags & FL_550_FSTN) ? 1 : 0;
276
Thomas Winischhofer544393f2005-09-09 13:04:45 -0700277 if(sisfb_crt2type < 0)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700278 printk(KERN_ERR "sisfb: Invalid CRT2 type: %s\n", name);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700279}
280
281static void __init
282sisfb_search_tvstd(const char *name)
283{
284 int i = 0;
285
Thomas Winischhofer544393f2005-09-09 13:04:45 -0700286 /* We don't know the hardware specs yet and there is no ivideo */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700287
Thomas Winischhofer544393f2005-09-09 13:04:45 -0700288 if(name == NULL)
289 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700290
291 while(sis_tvtype[i].type_no != -1) {
Thomas Winischhofer544393f2005-09-09 13:04:45 -0700292 if(!strnicmp(name, sis_tvtype[i].name, strlen(sis_tvtype[i].name))) {
293 sisfb_tvstd = sis_tvtype[i].type_no;
294 break;
295 }
296 i++;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700297 }
298}
299
300static void __init
301sisfb_search_specialtiming(const char *name)
302{
303 int i = 0;
Richard Knutssonc30660ea2007-02-12 00:55:06 -0800304 bool found = false;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700305
Thomas Winischhofer544393f2005-09-09 13:04:45 -0700306 /* We don't know the hardware specs yet and there is no ivideo */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700307
Thomas Winischhofer544393f2005-09-09 13:04:45 -0700308 if(name == NULL)
309 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700310
311 if(!strnicmp(name, "none", 4)) {
Thomas Winischhofer544393f2005-09-09 13:04:45 -0700312 sisfb_specialtiming = CUT_FORCENONE;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700313 printk(KERN_DEBUG "sisfb: Special timing disabled\n");
314 } else {
Thomas Winischhofer544393f2005-09-09 13:04:45 -0700315 while(mycustomttable[i].chipID != 0) {
316 if(!strnicmp(name,mycustomttable[i].optionName,
317 strlen(mycustomttable[i].optionName))) {
318 sisfb_specialtiming = mycustomttable[i].SpecialID;
Richard Knutssonc30660ea2007-02-12 00:55:06 -0800319 found = true;
Thomas Winischhofer544393f2005-09-09 13:04:45 -0700320 printk(KERN_INFO "sisfb: Special timing for %s %s forced (\"%s\")\n",
321 mycustomttable[i].vendorName,
322 mycustomttable[i].cardName,
323 mycustomttable[i].optionName);
324 break;
325 }
326 i++;
327 }
328 if(!found) {
329 printk(KERN_WARNING "sisfb: Invalid SpecialTiming parameter, valid are:");
330 printk(KERN_WARNING "\t\"none\" (to disable special timings)\n");
331 i = 0;
332 while(mycustomttable[i].chipID != 0) {
333 printk(KERN_WARNING "\t\"%s\" (for %s %s)\n",
334 mycustomttable[i].optionName,
335 mycustomttable[i].vendorName,
336 mycustomttable[i].cardName);
337 i++;
338 }
339 }
340 }
341}
342
343/* ----------- Various detection routines ----------- */
344
Greg Kroah-Hartman48c68c42012-12-21 13:07:39 -0800345static void sisfb_detect_custom_timing(struct sis_video_info *ivideo)
Thomas Winischhofer544393f2005-09-09 13:04:45 -0700346{
347 unsigned char *biosver = NULL;
348 unsigned char *biosdate = NULL;
Richard Knutssonc30660ea2007-02-12 00:55:06 -0800349 bool footprint;
Thomas Winischhofer544393f2005-09-09 13:04:45 -0700350 u32 chksum = 0;
351 int i, j;
352
353 if(ivideo->SiS_Pr.UseROM) {
354 biosver = ivideo->SiS_Pr.VirtualRomBase + 0x06;
355 biosdate = ivideo->SiS_Pr.VirtualRomBase + 0x2c;
356 for(i = 0; i < 32768; i++)
357 chksum += ivideo->SiS_Pr.VirtualRomBase[i];
358 }
359
360 i = 0;
361 do {
362 if( (mycustomttable[i].chipID == ivideo->chip) &&
363 ((!strlen(mycustomttable[i].biosversion)) ||
364 (ivideo->SiS_Pr.UseROM &&
365 (!strncmp(mycustomttable[i].biosversion, biosver,
366 strlen(mycustomttable[i].biosversion))))) &&
367 ((!strlen(mycustomttable[i].biosdate)) ||
368 (ivideo->SiS_Pr.UseROM &&
369 (!strncmp(mycustomttable[i].biosdate, biosdate,
370 strlen(mycustomttable[i].biosdate))))) &&
371 ((!mycustomttable[i].bioschksum) ||
372 (ivideo->SiS_Pr.UseROM &&
373 (mycustomttable[i].bioschksum == chksum))) &&
374 (mycustomttable[i].pcisubsysvendor == ivideo->subsysvendor) &&
375 (mycustomttable[i].pcisubsyscard == ivideo->subsysdevice) ) {
Richard Knutssonc30660ea2007-02-12 00:55:06 -0800376 footprint = true;
Thomas Winischhofer544393f2005-09-09 13:04:45 -0700377 for(j = 0; j < 5; j++) {
378 if(mycustomttable[i].biosFootprintAddr[j]) {
379 if(ivideo->SiS_Pr.UseROM) {
380 if(ivideo->SiS_Pr.VirtualRomBase[mycustomttable[i].biosFootprintAddr[j]] !=
381 mycustomttable[i].biosFootprintData[j]) {
Richard Knutssonc30660ea2007-02-12 00:55:06 -0800382 footprint = false;
Thomas Winischhofer544393f2005-09-09 13:04:45 -0700383 }
384 } else
Richard Knutssonc30660ea2007-02-12 00:55:06 -0800385 footprint = false;
Thomas Winischhofer544393f2005-09-09 13:04:45 -0700386 }
387 }
388 if(footprint) {
389 ivideo->SiS_Pr.SiS_CustomT = mycustomttable[i].SpecialID;
390 printk(KERN_DEBUG "sisfb: Identified [%s %s], special timing applies\n",
391 mycustomttable[i].vendorName,
392 mycustomttable[i].cardName);
393 printk(KERN_DEBUG "sisfb: [specialtiming parameter name: %s]\n",
394 mycustomttable[i].optionName);
395 break;
396 }
397 }
398 i++;
399 } while(mycustomttable[i].chipID);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700400}
401
Greg Kroah-Hartman48c68c42012-12-21 13:07:39 -0800402static bool sisfb_interpret_edid(struct sisfb_monitor *monitor, u8 *buffer)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700403{
404 int i, j, xres, yres, refresh, index;
405 u32 emodes;
406
407 if(buffer[0] != 0x00 || buffer[1] != 0xff ||
408 buffer[2] != 0xff || buffer[3] != 0xff ||
409 buffer[4] != 0xff || buffer[5] != 0xff ||
410 buffer[6] != 0xff || buffer[7] != 0x00) {
Thomas Winischhofer544393f2005-09-09 13:04:45 -0700411 printk(KERN_DEBUG "sisfb: Bad EDID header\n");
Richard Knutssonc30660ea2007-02-12 00:55:06 -0800412 return false;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700413 }
414
415 if(buffer[0x12] != 0x01) {
Thomas Winischhofer544393f2005-09-09 13:04:45 -0700416 printk(KERN_INFO "sisfb: EDID version %d not supported\n",
417 buffer[0x12]);
Richard Knutssonc30660ea2007-02-12 00:55:06 -0800418 return false;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700419 }
420
421 monitor->feature = buffer[0x18];
422
Alexey Dobriyaneaa0ff12008-02-06 01:36:06 -0800423 if(!(buffer[0x14] & 0x80)) {
Thomas Winischhofer544393f2005-09-09 13:04:45 -0700424 if(!(buffer[0x14] & 0x08)) {
425 printk(KERN_INFO
426 "sisfb: WARNING: Monitor does not support separate syncs\n");
427 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700428 }
429
430 if(buffer[0x13] >= 0x01) {
431 /* EDID V1 rev 1 and 2: Search for monitor descriptor
432 * to extract ranges
433 */
434 j = 0x36;
435 for(i=0; i<4; i++) {
436 if(buffer[j] == 0x00 && buffer[j + 1] == 0x00 &&
Thomas Winischhofer544393f2005-09-09 13:04:45 -0700437 buffer[j + 2] == 0x00 && buffer[j + 3] == 0xfd &&
Linus Torvalds1da177e2005-04-16 15:20:36 -0700438 buffer[j + 4] == 0x00) {
439 monitor->hmin = buffer[j + 7];
440 monitor->hmax = buffer[j + 8];
441 monitor->vmin = buffer[j + 5];
442 monitor->vmax = buffer[j + 6];
443 monitor->dclockmax = buffer[j + 9] * 10 * 1000;
Richard Knutssonc30660ea2007-02-12 00:55:06 -0800444 monitor->datavalid = true;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700445 break;
446 }
447 j += 18;
448 }
449 }
450
451 if(!monitor->datavalid) {
452 /* Otherwise: Get a range from the list of supported
453 * Estabished Timings. This is not entirely accurate,
454 * because fixed frequency monitors are not supported
455 * that way.
456 */
457 monitor->hmin = 65535; monitor->hmax = 0;
458 monitor->vmin = 65535; monitor->vmax = 0;
459 monitor->dclockmax = 0;
460 emodes = buffer[0x23] | (buffer[0x24] << 8) | (buffer[0x25] << 16);
461 for(i = 0; i < 13; i++) {
462 if(emodes & sisfb_ddcsmodes[i].mask) {
Thomas Winischhofer544393f2005-09-09 13:04:45 -0700463 if(monitor->hmin > sisfb_ddcsmodes[i].h) monitor->hmin = sisfb_ddcsmodes[i].h;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700464 if(monitor->hmax < sisfb_ddcsmodes[i].h) monitor->hmax = sisfb_ddcsmodes[i].h + 1;
465 if(monitor->vmin > sisfb_ddcsmodes[i].v) monitor->vmin = sisfb_ddcsmodes[i].v;
466 if(monitor->vmax < sisfb_ddcsmodes[i].v) monitor->vmax = sisfb_ddcsmodes[i].v;
467 if(monitor->dclockmax < sisfb_ddcsmodes[i].d) monitor->dclockmax = sisfb_ddcsmodes[i].d;
468 }
469 }
470 index = 0x26;
471 for(i = 0; i < 8; i++) {
472 xres = (buffer[index] + 31) * 8;
473 switch(buffer[index + 1] & 0xc0) {
Thomas Winischhofer544393f2005-09-09 13:04:45 -0700474 case 0xc0: yres = (xres * 9) / 16; break;
475 case 0x80: yres = (xres * 4) / 5; break;
476 case 0x40: yres = (xres * 3) / 4; break;
477 default: yres = xres; break;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700478 }
479 refresh = (buffer[index + 1] & 0x3f) + 60;
480 if((xres >= 640) && (yres >= 480)) {
Thomas Winischhofer544393f2005-09-09 13:04:45 -0700481 for(j = 0; j < 8; j++) {
482 if((xres == sisfb_ddcfmodes[j].x) &&
483 (yres == sisfb_ddcfmodes[j].y) &&
Linus Torvalds1da177e2005-04-16 15:20:36 -0700484 (refresh == sisfb_ddcfmodes[j].v)) {
485 if(monitor->hmin > sisfb_ddcfmodes[j].h) monitor->hmin = sisfb_ddcfmodes[j].h;
486 if(monitor->hmax < sisfb_ddcfmodes[j].h) monitor->hmax = sisfb_ddcfmodes[j].h + 1;
487 if(monitor->vmin > sisfb_ddcsmodes[j].v) monitor->vmin = sisfb_ddcsmodes[j].v;
488 if(monitor->vmax < sisfb_ddcsmodes[j].v) monitor->vmax = sisfb_ddcsmodes[j].v;
Thomas Winischhofer544393f2005-09-09 13:04:45 -0700489 if(monitor->dclockmax < sisfb_ddcsmodes[j].d) monitor->dclockmax = sisfb_ddcsmodes[j].d;
490 }
491 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700492 }
493 index += 2;
Thomas Winischhofer544393f2005-09-09 13:04:45 -0700494 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700495 if((monitor->hmin <= monitor->hmax) && (monitor->vmin <= monitor->vmax)) {
Richard Knutssonc30660ea2007-02-12 00:55:06 -0800496 monitor->datavalid = true;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700497 }
498 }
499
Thomas Winischhofer544393f2005-09-09 13:04:45 -0700500 return monitor->datavalid;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700501}
502
Greg Kroah-Hartman48c68c42012-12-21 13:07:39 -0800503static void sisfb_handle_ddc(struct sis_video_info *ivideo,
504 struct sisfb_monitor *monitor, int crtno)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700505{
Thomas Winischhofer544393f2005-09-09 13:04:45 -0700506 unsigned short temp, i, realcrtno = crtno;
507 unsigned char buffer[256];
Linus Torvalds1da177e2005-04-16 15:20:36 -0700508
Richard Knutssonc30660ea2007-02-12 00:55:06 -0800509 monitor->datavalid = false;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700510
511 if(crtno) {
Thomas Winischhofer544393f2005-09-09 13:04:45 -0700512 if(ivideo->vbflags & CRT2_LCD) realcrtno = 1;
513 else if(ivideo->vbflags & CRT2_VGA) realcrtno = 2;
514 else return;
515 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700516
Thomas Winischhofer544393f2005-09-09 13:04:45 -0700517 if((ivideo->sisfb_crt1off) && (!crtno))
518 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700519
Thomas Winischhofer544393f2005-09-09 13:04:45 -0700520 temp = SiS_HandleDDC(&ivideo->SiS_Pr, ivideo->vbflags, ivideo->sisvga_engine,
521 realcrtno, 0, &buffer[0], ivideo->vbflags2);
522 if((!temp) || (temp == 0xffff)) {
523 printk(KERN_INFO "sisfb: CRT%d DDC probing failed\n", crtno + 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700524 return;
Thomas Winischhofer544393f2005-09-09 13:04:45 -0700525 } else {
526 printk(KERN_INFO "sisfb: CRT%d DDC supported\n", crtno + 1);
527 printk(KERN_INFO "sisfb: CRT%d DDC level: %s%s%s%s\n",
528 crtno + 1,
529 (temp & 0x1a) ? "" : "[none of the supported]",
530 (temp & 0x02) ? "2 " : "",
531 (temp & 0x08) ? "D&P" : "",
532 (temp & 0x10) ? "FPDI-2" : "");
533 if(temp & 0x02) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700534 i = 3; /* Number of retrys */
535 do {
Thomas Winischhofer544393f2005-09-09 13:04:45 -0700536 temp = SiS_HandleDDC(&ivideo->SiS_Pr, ivideo->vbflags, ivideo->sisvga_engine,
537 realcrtno, 1, &buffer[0], ivideo->vbflags2);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700538 } while((temp) && i--);
Thomas Winischhofer544393f2005-09-09 13:04:45 -0700539 if(!temp) {
540 if(sisfb_interpret_edid(monitor, &buffer[0])) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700541 printk(KERN_INFO "sisfb: Monitor range H %d-%dKHz, V %d-%dHz, Max. dotclock %dMHz\n",
Thomas Winischhofer544393f2005-09-09 13:04:45 -0700542 monitor->hmin, monitor->hmax, monitor->vmin, monitor->vmax,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700543 monitor->dclockmax / 1000);
544 } else {
Thomas Winischhofer544393f2005-09-09 13:04:45 -0700545 printk(KERN_INFO "sisfb: CRT%d DDC EDID corrupt\n", crtno + 1);
546 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700547 } else {
Thomas Winischhofer544393f2005-09-09 13:04:45 -0700548 printk(KERN_INFO "sisfb: CRT%d DDC reading failed\n", crtno + 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700549 }
550 } else {
551 printk(KERN_INFO "sisfb: VESA D&P and FPDI-2 not supported yet\n");
552 }
553 }
554}
555
Thomas Winischhofer544393f2005-09-09 13:04:45 -0700556/* -------------- Mode validation --------------- */
557
Richard Knutssonc30660ea2007-02-12 00:55:06 -0800558static bool
Linus Torvalds1da177e2005-04-16 15:20:36 -0700559sisfb_verify_rate(struct sis_video_info *ivideo, struct sisfb_monitor *monitor,
560 int mode_idx, int rate_idx, int rate)
561{
562 int htotal, vtotal;
563 unsigned int dclock, hsync;
564
Thomas Winischhofer544393f2005-09-09 13:04:45 -0700565 if(!monitor->datavalid)
Richard Knutssonc30660ea2007-02-12 00:55:06 -0800566 return true;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700567
Thomas Winischhofer544393f2005-09-09 13:04:45 -0700568 if(mode_idx < 0)
Richard Knutssonc30660ea2007-02-12 00:55:06 -0800569 return false;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700570
571 /* Skip for 320x200, 320x240, 640x400 */
Thomas Winischhofer544393f2005-09-09 13:04:45 -0700572 switch(sisbios_mode[mode_idx].mode_no[ivideo->mni]) {
573 case 0x59:
574 case 0x41:
575 case 0x4f:
576 case 0x50:
577 case 0x56:
578 case 0x53:
579 case 0x2f:
580 case 0x5d:
581 case 0x5e:
Richard Knutssonc30660ea2007-02-12 00:55:06 -0800582 return true;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700583#ifdef CONFIG_FB_SIS_315
584 case 0x5a:
585 case 0x5b:
Richard Knutssonc30660ea2007-02-12 00:55:06 -0800586 if(ivideo->sisvga_engine == SIS_315_VGA) return true;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700587#endif
Thomas Winischhofer544393f2005-09-09 13:04:45 -0700588 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700589
Thomas Winischhofer544393f2005-09-09 13:04:45 -0700590 if(rate < (monitor->vmin - 1))
Richard Knutssonc30660ea2007-02-12 00:55:06 -0800591 return false;
Thomas Winischhofer544393f2005-09-09 13:04:45 -0700592 if(rate > (monitor->vmax + 1))
Richard Knutssonc30660ea2007-02-12 00:55:06 -0800593 return false;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700594
Thomas Winischhofer544393f2005-09-09 13:04:45 -0700595 if(sisfb_gettotalfrommode(&ivideo->SiS_Pr,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700596 sisbios_mode[mode_idx].mode_no[ivideo->mni],
Thomas Winischhofer544393f2005-09-09 13:04:45 -0700597 &htotal, &vtotal, rate_idx)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700598 dclock = (htotal * vtotal * rate) / 1000;
Thomas Winischhofer544393f2005-09-09 13:04:45 -0700599 if(dclock > (monitor->dclockmax + 1000))
Richard Knutssonc30660ea2007-02-12 00:55:06 -0800600 return false;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700601 hsync = dclock / htotal;
Thomas Winischhofer544393f2005-09-09 13:04:45 -0700602 if(hsync < (monitor->hmin - 1))
Richard Knutssonc30660ea2007-02-12 00:55:06 -0800603 return false;
Thomas Winischhofer544393f2005-09-09 13:04:45 -0700604 if(hsync > (monitor->hmax + 1))
Richard Knutssonc30660ea2007-02-12 00:55:06 -0800605 return false;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700606 } else {
Richard Knutssonc30660ea2007-02-12 00:55:06 -0800607 return false;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700608 }
Richard Knutssonc30660ea2007-02-12 00:55:06 -0800609 return true;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700610}
611
612static int
613sisfb_validate_mode(struct sis_video_info *ivideo, int myindex, u32 vbflags)
614{
Thomas Winischhofer544393f2005-09-09 13:04:45 -0700615 u16 xres=0, yres, myres;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700616
617#ifdef CONFIG_FB_SIS_300
Thomas Winischhofer544393f2005-09-09 13:04:45 -0700618 if(ivideo->sisvga_engine == SIS_300_VGA) {
619 if(!(sisbios_mode[myindex].chipset & MD_SIS300))
620 return -1 ;
621 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700622#endif
623#ifdef CONFIG_FB_SIS_315
Thomas Winischhofer544393f2005-09-09 13:04:45 -0700624 if(ivideo->sisvga_engine == SIS_315_VGA) {
625 if(!(sisbios_mode[myindex].chipset & MD_SIS315))
626 return -1;
627 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700628#endif
629
Thomas Winischhofer544393f2005-09-09 13:04:45 -0700630 myres = sisbios_mode[myindex].yres;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700631
Thomas Winischhofer544393f2005-09-09 13:04:45 -0700632 switch(vbflags & VB_DISPTYPE_DISP2) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700633
Thomas Winischhofer544393f2005-09-09 13:04:45 -0700634 case CRT2_LCD:
635 xres = ivideo->lcdxres; yres = ivideo->lcdyres;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700636
Thomas Winischhofer544393f2005-09-09 13:04:45 -0700637 if((ivideo->SiS_Pr.SiS_CustomT != CUT_PANEL848) &&
638 (ivideo->SiS_Pr.SiS_CustomT != CUT_PANEL856)) {
639 if(sisbios_mode[myindex].xres > xres)
640 return -1;
641 if(myres > yres)
642 return -1;
643 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700644
Thomas Winischhofer544393f2005-09-09 13:04:45 -0700645 if(ivideo->sisfb_fstn) {
646 if(sisbios_mode[myindex].xres == 320) {
647 if(myres == 240) {
648 switch(sisbios_mode[myindex].mode_no[1]) {
649 case 0x50: myindex = MODE_FSTN_8; break;
650 case 0x56: myindex = MODE_FSTN_16; break;
651 case 0x53: return -1;
652 }
653 }
654 }
655 }
656
657 if(SiS_GetModeID_LCD(ivideo->sisvga_engine, vbflags, sisbios_mode[myindex].xres,
658 sisbios_mode[myindex].yres, 0, ivideo->sisfb_fstn,
659 ivideo->SiS_Pr.SiS_CustomT, xres, yres, ivideo->vbflags2) < 0x14) {
660 return -1;
661 }
662 break;
663
664 case CRT2_TV:
665 if(SiS_GetModeID_TV(ivideo->sisvga_engine, vbflags, sisbios_mode[myindex].xres,
666 sisbios_mode[myindex].yres, 0, ivideo->vbflags2) < 0x14) {
667 return -1;
668 }
669 break;
670
671 case CRT2_VGA:
672 if(SiS_GetModeID_VGA2(ivideo->sisvga_engine, vbflags, sisbios_mode[myindex].xres,
673 sisbios_mode[myindex].yres, 0, ivideo->vbflags2) < 0x14) {
674 return -1;
675 }
676 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700677 }
678
Thomas Winischhofer544393f2005-09-09 13:04:45 -0700679 return myindex;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700680}
681
682static u8
683sisfb_search_refresh_rate(struct sis_video_info *ivideo, unsigned int rate, int mode_idx)
684{
Linus Torvalds1da177e2005-04-16 15:20:36 -0700685 int i = 0;
Thomas Winischhofer544393f2005-09-09 13:04:45 -0700686 u16 xres = sisbios_mode[mode_idx].xres;
687 u16 yres = sisbios_mode[mode_idx].yres;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700688
689 ivideo->rate_idx = 0;
690 while((sisfb_vrate[i].idx != 0) && (sisfb_vrate[i].xres <= xres)) {
691 if((sisfb_vrate[i].xres == xres) && (sisfb_vrate[i].yres == yres)) {
692 if(sisfb_vrate[i].refresh == rate) {
693 ivideo->rate_idx = sisfb_vrate[i].idx;
694 break;
695 } else if(sisfb_vrate[i].refresh > rate) {
696 if((sisfb_vrate[i].refresh - rate) <= 3) {
697 DPRINTK("sisfb: Adjusting rate from %d up to %d\n",
698 rate, sisfb_vrate[i].refresh);
699 ivideo->rate_idx = sisfb_vrate[i].idx;
700 ivideo->refresh_rate = sisfb_vrate[i].refresh;
Roel Kluind63870d2009-09-22 16:47:07 -0700701 } else if((sisfb_vrate[i].idx != 1) &&
702 ((rate - sisfb_vrate[i-1].refresh) <= 2)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700703 DPRINTK("sisfb: Adjusting rate from %d down to %d\n",
704 rate, sisfb_vrate[i-1].refresh);
705 ivideo->rate_idx = sisfb_vrate[i-1].idx;
706 ivideo->refresh_rate = sisfb_vrate[i-1].refresh;
Thomas Winischhofer544393f2005-09-09 13:04:45 -0700707 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700708 break;
709 } else if((rate - sisfb_vrate[i].refresh) <= 2) {
710 DPRINTK("sisfb: Adjusting rate from %d down to %d\n",
711 rate, sisfb_vrate[i].refresh);
Thomas Winischhofer544393f2005-09-09 13:04:45 -0700712 ivideo->rate_idx = sisfb_vrate[i].idx;
713 break;
714 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700715 }
716 i++;
717 }
718 if(ivideo->rate_idx > 0) {
719 return ivideo->rate_idx;
720 } else {
721 printk(KERN_INFO "sisfb: Unsupported rate %d for %dx%d\n",
722 rate, xres, yres);
723 return 0;
724 }
725}
726
Richard Knutssonc30660ea2007-02-12 00:55:06 -0800727static bool
Linus Torvalds1da177e2005-04-16 15:20:36 -0700728sisfb_bridgeisslave(struct sis_video_info *ivideo)
729{
Thomas Winischhofer544393f2005-09-09 13:04:45 -0700730 unsigned char P1_00;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700731
Thomas Winischhofer544393f2005-09-09 13:04:45 -0700732 if(!(ivideo->vbflags2 & VB2_VIDEOBRIDGE))
Richard Knutssonc30660ea2007-02-12 00:55:06 -0800733 return false;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700734
Aaro Koskinene57d4132010-12-20 23:50:16 +0200735 P1_00 = SiS_GetReg(SISPART1, 0x00);
Thomas Winischhofer544393f2005-09-09 13:04:45 -0700736 if( ((ivideo->sisvga_engine == SIS_300_VGA) && (P1_00 & 0xa0) == 0x20) ||
737 ((ivideo->sisvga_engine == SIS_315_VGA) && (P1_00 & 0x50) == 0x10) ) {
Richard Knutssonc30660ea2007-02-12 00:55:06 -0800738 return true;
Thomas Winischhofer544393f2005-09-09 13:04:45 -0700739 } else {
Richard Knutssonc30660ea2007-02-12 00:55:06 -0800740 return false;
Thomas Winischhofer544393f2005-09-09 13:04:45 -0700741 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700742}
743
Richard Knutssonc30660ea2007-02-12 00:55:06 -0800744static bool
Linus Torvalds1da177e2005-04-16 15:20:36 -0700745sisfballowretracecrt1(struct sis_video_info *ivideo)
746{
Thomas Winischhofer544393f2005-09-09 13:04:45 -0700747 u8 temp;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700748
Aaro Koskinene57d4132010-12-20 23:50:16 +0200749 temp = SiS_GetReg(SISCR, 0x17);
Thomas Winischhofer544393f2005-09-09 13:04:45 -0700750 if(!(temp & 0x80))
Richard Knutssonc30660ea2007-02-12 00:55:06 -0800751 return false;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700752
Aaro Koskinene57d4132010-12-20 23:50:16 +0200753 temp = SiS_GetReg(SISSR, 0x1f);
Thomas Winischhofer544393f2005-09-09 13:04:45 -0700754 if(temp & 0xc0)
Richard Knutssonc30660ea2007-02-12 00:55:06 -0800755 return false;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700756
Richard Knutssonc30660ea2007-02-12 00:55:06 -0800757 return true;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700758}
759
Richard Knutssonc30660ea2007-02-12 00:55:06 -0800760static bool
Linus Torvalds1da177e2005-04-16 15:20:36 -0700761sisfbcheckvretracecrt1(struct sis_video_info *ivideo)
762{
Thomas Winischhofer544393f2005-09-09 13:04:45 -0700763 if(!sisfballowretracecrt1(ivideo))
Richard Knutssonc30660ea2007-02-12 00:55:06 -0800764 return false;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700765
Aaro Koskinen1e1687d2010-12-20 23:50:14 +0200766 if (SiS_GetRegByte(SISINPSTAT) & 0x08)
Richard Knutssonc30660ea2007-02-12 00:55:06 -0800767 return true;
Thomas Winischhofer544393f2005-09-09 13:04:45 -0700768 else
Richard Knutssonc30660ea2007-02-12 00:55:06 -0800769 return false;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700770}
771
772static void
773sisfbwaitretracecrt1(struct sis_video_info *ivideo)
774{
Thomas Winischhofer544393f2005-09-09 13:04:45 -0700775 int watchdog;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700776
Thomas Winischhofer544393f2005-09-09 13:04:45 -0700777 if(!sisfballowretracecrt1(ivideo))
778 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700779
Thomas Winischhofer544393f2005-09-09 13:04:45 -0700780 watchdog = 65536;
Aaro Koskinen1e1687d2010-12-20 23:50:14 +0200781 while ((!(SiS_GetRegByte(SISINPSTAT) & 0x08)) && --watchdog);
Thomas Winischhofer544393f2005-09-09 13:04:45 -0700782 watchdog = 65536;
Aaro Koskinen1e1687d2010-12-20 23:50:14 +0200783 while ((SiS_GetRegByte(SISINPSTAT) & 0x08) && --watchdog);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700784}
785
Richard Knutssonc30660ea2007-02-12 00:55:06 -0800786static bool
Linus Torvalds1da177e2005-04-16 15:20:36 -0700787sisfbcheckvretracecrt2(struct sis_video_info *ivideo)
788{
Thomas Winischhofer544393f2005-09-09 13:04:45 -0700789 unsigned char temp, reg;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700790
Thomas Winischhofer544393f2005-09-09 13:04:45 -0700791 switch(ivideo->sisvga_engine) {
792 case SIS_300_VGA: reg = 0x25; break;
793 case SIS_315_VGA: reg = 0x30; break;
Richard Knutssonc30660ea2007-02-12 00:55:06 -0800794 default: return false;
Thomas Winischhofer544393f2005-09-09 13:04:45 -0700795 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700796
Aaro Koskinene57d4132010-12-20 23:50:16 +0200797 temp = SiS_GetReg(SISPART1, reg);
Thomas Winischhofer544393f2005-09-09 13:04:45 -0700798 if(temp & 0x02)
Richard Knutssonc30660ea2007-02-12 00:55:06 -0800799 return true;
Thomas Winischhofer544393f2005-09-09 13:04:45 -0700800 else
Richard Knutssonc30660ea2007-02-12 00:55:06 -0800801 return false;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700802}
803
Richard Knutssonc30660ea2007-02-12 00:55:06 -0800804static bool
Linus Torvalds1da177e2005-04-16 15:20:36 -0700805sisfb_CheckVBRetrace(struct sis_video_info *ivideo)
806{
Thomas Winischhofer544393f2005-09-09 13:04:45 -0700807 if(ivideo->currentvbflags & VB_DISPTYPE_DISP2) {
808 if(!sisfb_bridgeisslave(ivideo)) {
809 return sisfbcheckvretracecrt2(ivideo);
810 }
811 }
812 return sisfbcheckvretracecrt1(ivideo);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700813}
814
815static u32
816sisfb_setupvbblankflags(struct sis_video_info *ivideo, u32 *vcount, u32 *hcount)
817{
Thomas Winischhofer544393f2005-09-09 13:04:45 -0700818 u8 idx, reg1, reg2, reg3, reg4;
819 u32 ret = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700820
Thomas Winischhofer544393f2005-09-09 13:04:45 -0700821 (*vcount) = (*hcount) = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700822
Thomas Winischhofer544393f2005-09-09 13:04:45 -0700823 if((ivideo->currentvbflags & VB_DISPTYPE_DISP2) && (!(sisfb_bridgeisslave(ivideo)))) {
824
825 ret |= (FB_VBLANK_HAVE_VSYNC |
826 FB_VBLANK_HAVE_HBLANK |
827 FB_VBLANK_HAVE_VBLANK |
828 FB_VBLANK_HAVE_VCOUNT |
829 FB_VBLANK_HAVE_HCOUNT);
830 switch(ivideo->sisvga_engine) {
831 case SIS_300_VGA: idx = 0x25; break;
832 default:
833 case SIS_315_VGA: idx = 0x30; break;
834 }
Aaro Koskinene57d4132010-12-20 23:50:16 +0200835 reg1 = SiS_GetReg(SISPART1, (idx+0)); /* 30 */
836 reg2 = SiS_GetReg(SISPART1, (idx+1)); /* 31 */
837 reg3 = SiS_GetReg(SISPART1, (idx+2)); /* 32 */
838 reg4 = SiS_GetReg(SISPART1, (idx+3)); /* 33 */
Thomas Winischhofer544393f2005-09-09 13:04:45 -0700839 if(reg1 & 0x01) ret |= FB_VBLANK_VBLANKING;
840 if(reg1 & 0x02) ret |= FB_VBLANK_VSYNCING;
841 if(reg4 & 0x80) ret |= FB_VBLANK_HBLANKING;
842 (*vcount) = reg3 | ((reg4 & 0x70) << 4);
843 (*hcount) = reg2 | ((reg4 & 0x0f) << 8);
844
845 } else if(sisfballowretracecrt1(ivideo)) {
846
847 ret |= (FB_VBLANK_HAVE_VSYNC |
848 FB_VBLANK_HAVE_VBLANK |
849 FB_VBLANK_HAVE_VCOUNT |
850 FB_VBLANK_HAVE_HCOUNT);
Aaro Koskinen1e1687d2010-12-20 23:50:14 +0200851 reg1 = SiS_GetRegByte(SISINPSTAT);
Thomas Winischhofer544393f2005-09-09 13:04:45 -0700852 if(reg1 & 0x08) ret |= FB_VBLANK_VSYNCING;
853 if(reg1 & 0x01) ret |= FB_VBLANK_VBLANKING;
Aaro Koskinene57d4132010-12-20 23:50:16 +0200854 reg1 = SiS_GetReg(SISCR, 0x20);
855 reg1 = SiS_GetReg(SISCR, 0x1b);
856 reg2 = SiS_GetReg(SISCR, 0x1c);
857 reg3 = SiS_GetReg(SISCR, 0x1d);
Thomas Winischhofer544393f2005-09-09 13:04:45 -0700858 (*vcount) = reg2 | ((reg3 & 0x07) << 8);
859 (*hcount) = (reg1 | ((reg3 & 0x10) << 4)) << 3;
860 }
861
862 return ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700863}
864
865static int
866sisfb_myblank(struct sis_video_info *ivideo, int blank)
867{
Thomas Winischhofer544393f2005-09-09 13:04:45 -0700868 u8 sr01, sr11, sr1f, cr63=0, p2_0, p1_13;
Richard Knutssonc30660ea2007-02-12 00:55:06 -0800869 bool backlight = true;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700870
Thomas Winischhofer544393f2005-09-09 13:04:45 -0700871 switch(blank) {
872 case FB_BLANK_UNBLANK: /* on */
873 sr01 = 0x00;
874 sr11 = 0x00;
875 sr1f = 0x00;
876 cr63 = 0x00;
877 p2_0 = 0x20;
878 p1_13 = 0x00;
Richard Knutssonc30660ea2007-02-12 00:55:06 -0800879 backlight = true;
Thomas Winischhofer544393f2005-09-09 13:04:45 -0700880 break;
881 case FB_BLANK_NORMAL: /* blank */
882 sr01 = 0x20;
883 sr11 = 0x00;
884 sr1f = 0x00;
885 cr63 = 0x00;
886 p2_0 = 0x20;
887 p1_13 = 0x00;
Richard Knutssonc30660ea2007-02-12 00:55:06 -0800888 backlight = true;
Thomas Winischhofer544393f2005-09-09 13:04:45 -0700889 break;
890 case FB_BLANK_VSYNC_SUSPEND: /* no vsync */
891 sr01 = 0x20;
892 sr11 = 0x08;
893 sr1f = 0x80;
894 cr63 = 0x40;
895 p2_0 = 0x40;
896 p1_13 = 0x80;
Richard Knutssonc30660ea2007-02-12 00:55:06 -0800897 backlight = false;
Thomas Winischhofer544393f2005-09-09 13:04:45 -0700898 break;
899 case FB_BLANK_HSYNC_SUSPEND: /* no hsync */
900 sr01 = 0x20;
901 sr11 = 0x08;
902 sr1f = 0x40;
903 cr63 = 0x40;
904 p2_0 = 0x80;
905 p1_13 = 0x40;
Richard Knutssonc30660ea2007-02-12 00:55:06 -0800906 backlight = false;
Thomas Winischhofer544393f2005-09-09 13:04:45 -0700907 break;
908 case FB_BLANK_POWERDOWN: /* off */
909 sr01 = 0x20;
910 sr11 = 0x08;
911 sr1f = 0xc0;
912 cr63 = 0x40;
913 p2_0 = 0xc0;
914 p1_13 = 0xc0;
Richard Knutssonc30660ea2007-02-12 00:55:06 -0800915 backlight = false;
Thomas Winischhofer544393f2005-09-09 13:04:45 -0700916 break;
917 default:
918 return 1;
919 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700920
Thomas Winischhofer544393f2005-09-09 13:04:45 -0700921 if(ivideo->currentvbflags & VB_DISPTYPE_CRT1) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700922
Thomas Winischhofer544393f2005-09-09 13:04:45 -0700923 if( (!ivideo->sisfb_thismonitor.datavalid) ||
924 ((ivideo->sisfb_thismonitor.datavalid) &&
925 (ivideo->sisfb_thismonitor.feature & 0xe0))) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700926
Thomas Winischhofer544393f2005-09-09 13:04:45 -0700927 if(ivideo->sisvga_engine == SIS_315_VGA) {
Aaro Koskinenad78adb2010-12-20 23:50:20 +0200928 SiS_SetRegANDOR(SISCR, ivideo->SiS_Pr.SiS_MyCR63, 0xbf, cr63);
Thomas Winischhofer544393f2005-09-09 13:04:45 -0700929 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700930
Thomas Winischhofer544393f2005-09-09 13:04:45 -0700931 if(!(sisfb_bridgeisslave(ivideo))) {
Aaro Koskinenad78adb2010-12-20 23:50:20 +0200932 SiS_SetRegANDOR(SISSR, 0x01, ~0x20, sr01);
933 SiS_SetRegANDOR(SISSR, 0x1f, 0x3f, sr1f);
Thomas Winischhofer544393f2005-09-09 13:04:45 -0700934 }
935 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700936
Thomas Winischhofer544393f2005-09-09 13:04:45 -0700937 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700938
Thomas Winischhofer544393f2005-09-09 13:04:45 -0700939 if(ivideo->currentvbflags & CRT2_LCD) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700940
Thomas Winischhofer544393f2005-09-09 13:04:45 -0700941 if(ivideo->vbflags2 & VB2_SISLVDSBRIDGE) {
942 if(backlight) {
943 SiS_SiS30xBLOn(&ivideo->SiS_Pr);
944 } else {
945 SiS_SiS30xBLOff(&ivideo->SiS_Pr);
946 }
947 } else if(ivideo->sisvga_engine == SIS_315_VGA) {
948#ifdef CONFIG_FB_SIS_315
949 if(ivideo->vbflags2 & VB2_CHRONTEL) {
950 if(backlight) {
951 SiS_Chrontel701xBLOn(&ivideo->SiS_Pr);
952 } else {
953 SiS_Chrontel701xBLOff(&ivideo->SiS_Pr);
954 }
955 }
956#endif
957 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700958
Thomas Winischhofer544393f2005-09-09 13:04:45 -0700959 if(((ivideo->sisvga_engine == SIS_300_VGA) &&
960 (ivideo->vbflags2 & (VB2_301|VB2_30xBDH|VB2_LVDS))) ||
961 ((ivideo->sisvga_engine == SIS_315_VGA) &&
962 ((ivideo->vbflags2 & (VB2_LVDS | VB2_CHRONTEL)) == VB2_LVDS))) {
Aaro Koskinenad78adb2010-12-20 23:50:20 +0200963 SiS_SetRegANDOR(SISSR, 0x11, ~0x0c, sr11);
Thomas Winischhofer544393f2005-09-09 13:04:45 -0700964 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700965
Thomas Winischhofer544393f2005-09-09 13:04:45 -0700966 if(ivideo->sisvga_engine == SIS_300_VGA) {
967 if((ivideo->vbflags2 & VB2_30xB) &&
968 (!(ivideo->vbflags2 & VB2_30xBDH))) {
Aaro Koskinenad78adb2010-12-20 23:50:20 +0200969 SiS_SetRegANDOR(SISPART1, 0x13, 0x3f, p1_13);
Thomas Winischhofer544393f2005-09-09 13:04:45 -0700970 }
971 } else if(ivideo->sisvga_engine == SIS_315_VGA) {
972 if((ivideo->vbflags2 & VB2_30xB) &&
973 (!(ivideo->vbflags2 & VB2_30xBDH))) {
Aaro Koskinenad78adb2010-12-20 23:50:20 +0200974 SiS_SetRegANDOR(SISPART2, 0x00, 0x1f, p2_0);
Thomas Winischhofer544393f2005-09-09 13:04:45 -0700975 }
976 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700977
Thomas Winischhofer544393f2005-09-09 13:04:45 -0700978 } else if(ivideo->currentvbflags & CRT2_VGA) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700979
Thomas Winischhofer544393f2005-09-09 13:04:45 -0700980 if(ivideo->vbflags2 & VB2_30xB) {
Aaro Koskinenad78adb2010-12-20 23:50:20 +0200981 SiS_SetRegANDOR(SISPART2, 0x00, 0x1f, p2_0);
Thomas Winischhofer544393f2005-09-09 13:04:45 -0700982 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700983
Thomas Winischhofer544393f2005-09-09 13:04:45 -0700984 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700985
Thomas Winischhofer544393f2005-09-09 13:04:45 -0700986 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700987}
988
Thomas Winischhofer544393f2005-09-09 13:04:45 -0700989/* ------------- Callbacks from init.c/init301.c -------------- */
990
991#ifdef CONFIG_FB_SIS_300
992unsigned int
993sisfb_read_nbridge_pci_dword(struct SiS_Private *SiS_Pr, int reg)
994{
995 struct sis_video_info *ivideo = (struct sis_video_info *)SiS_Pr->ivideo;
996 u32 val = 0;
997
998 pci_read_config_dword(ivideo->nbridge, reg, &val);
999 return (unsigned int)val;
1000}
1001
1002void
1003sisfb_write_nbridge_pci_dword(struct SiS_Private *SiS_Pr, int reg, unsigned int val)
1004{
1005 struct sis_video_info *ivideo = (struct sis_video_info *)SiS_Pr->ivideo;
1006
1007 pci_write_config_dword(ivideo->nbridge, reg, (u32)val);
1008}
1009
1010unsigned int
1011sisfb_read_lpc_pci_dword(struct SiS_Private *SiS_Pr, int reg)
1012{
1013 struct sis_video_info *ivideo = (struct sis_video_info *)SiS_Pr->ivideo;
1014 u32 val = 0;
1015
1016 if(!ivideo->lpcdev) return 0;
1017
1018 pci_read_config_dword(ivideo->lpcdev, reg, &val);
1019 return (unsigned int)val;
1020}
1021#endif
1022
1023#ifdef CONFIG_FB_SIS_315
1024void
1025sisfb_write_nbridge_pci_byte(struct SiS_Private *SiS_Pr, int reg, unsigned char val)
1026{
1027 struct sis_video_info *ivideo = (struct sis_video_info *)SiS_Pr->ivideo;
1028
1029 pci_write_config_byte(ivideo->nbridge, reg, (u8)val);
1030}
1031
1032unsigned int
1033sisfb_read_mio_pci_word(struct SiS_Private *SiS_Pr, int reg)
1034{
1035 struct sis_video_info *ivideo = (struct sis_video_info *)SiS_Pr->ivideo;
1036 u16 val = 0;
1037
1038 if(!ivideo->lpcdev) return 0;
1039
1040 pci_read_config_word(ivideo->lpcdev, reg, &val);
1041 return (unsigned int)val;
1042}
1043#endif
1044
Linus Torvalds1da177e2005-04-16 15:20:36 -07001045/* ----------- FBDev related routines for all series ----------- */
1046
1047static int
1048sisfb_get_cmap_len(const struct fb_var_screeninfo *var)
1049{
1050 return (var->bits_per_pixel == 8) ? 256 : 16;
1051}
1052
1053static void
1054sisfb_set_vparms(struct sis_video_info *ivideo)
1055{
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001056 switch(ivideo->video_bpp) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001057 case 8:
1058 ivideo->DstColor = 0x0000;
1059 ivideo->SiS310_AccelDepth = 0x00000000;
1060 ivideo->video_cmap_len = 256;
1061 break;
1062 case 16:
1063 ivideo->DstColor = 0x8000;
1064 ivideo->SiS310_AccelDepth = 0x00010000;
1065 ivideo->video_cmap_len = 16;
1066 break;
1067 case 32:
1068 ivideo->DstColor = 0xC000;
1069 ivideo->SiS310_AccelDepth = 0x00020000;
1070 ivideo->video_cmap_len = 16;
1071 break;
1072 default:
1073 ivideo->video_cmap_len = 16;
1074 printk(KERN_ERR "sisfb: Unsupported depth %d", ivideo->video_bpp);
1075 ivideo->accel = 0;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001076 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001077}
1078
1079static int
1080sisfb_calc_maxyres(struct sis_video_info *ivideo, struct fb_var_screeninfo *var)
1081{
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001082 int maxyres = ivideo->sisfb_mem / (var->xres_virtual * (var->bits_per_pixel >> 3));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001083
1084 if(maxyres > 32767) maxyres = 32767;
1085
1086 return maxyres;
1087}
1088
1089static void
1090sisfb_calc_pitch(struct sis_video_info *ivideo, struct fb_var_screeninfo *var)
1091{
1092 ivideo->video_linelength = var->xres_virtual * (var->bits_per_pixel >> 3);
1093 ivideo->scrnpitchCRT1 = ivideo->video_linelength;
1094 if(!(ivideo->currentvbflags & CRT1_LCDA)) {
1095 if((var->vmode & FB_VMODE_MASK) == FB_VMODE_INTERLACED) {
1096 ivideo->scrnpitchCRT1 <<= 1;
1097 }
1098 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001099}
1100
1101static void
1102sisfb_set_pitch(struct sis_video_info *ivideo)
1103{
Richard Knutssonc30660ea2007-02-12 00:55:06 -08001104 bool isslavemode = false;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001105 unsigned short HDisplay1 = ivideo->scrnpitchCRT1 >> 3;
1106 unsigned short HDisplay2 = ivideo->video_linelength >> 3;
1107
Richard Knutssonc30660ea2007-02-12 00:55:06 -08001108 if(sisfb_bridgeisslave(ivideo)) isslavemode = true;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001109
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001110 /* We need to set pitch for CRT1 if bridge is in slave mode, too */
1111 if((ivideo->currentvbflags & VB_DISPTYPE_DISP1) || (isslavemode)) {
Aaro Koskinen44b751b2010-12-20 23:50:17 +02001112 SiS_SetReg(SISCR, 0x13, (HDisplay1 & 0xFF));
Aaro Koskinenad78adb2010-12-20 23:50:20 +02001113 SiS_SetRegANDOR(SISSR, 0x0E, 0xF0, (HDisplay1 >> 8));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001114 }
1115
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001116 /* We must not set the pitch for CRT2 if bridge is in slave mode */
1117 if((ivideo->currentvbflags & VB_DISPTYPE_DISP2) && (!isslavemode)) {
Aaro Koskinen27799d62010-12-20 23:50:18 +02001118 SiS_SetRegOR(SISPART1, ivideo->CRT2_write_enable, 0x01);
Aaro Koskinen44b751b2010-12-20 23:50:17 +02001119 SiS_SetReg(SISPART1, 0x07, (HDisplay2 & 0xFF));
Aaro Koskinenad78adb2010-12-20 23:50:20 +02001120 SiS_SetRegANDOR(SISPART1, 0x09, 0xF0, (HDisplay2 >> 8));
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001121 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001122}
1123
1124static void
1125sisfb_bpp_to_var(struct sis_video_info *ivideo, struct fb_var_screeninfo *var)
1126{
1127 ivideo->video_cmap_len = sisfb_get_cmap_len(var);
1128
1129 switch(var->bits_per_pixel) {
1130 case 8:
1131 var->red.offset = var->green.offset = var->blue.offset = 0;
Michal Januszewski811a2012009-04-13 14:39:52 -07001132 var->red.length = var->green.length = var->blue.length = 8;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001133 break;
1134 case 16:
1135 var->red.offset = 11;
1136 var->red.length = 5;
1137 var->green.offset = 5;
1138 var->green.length = 6;
1139 var->blue.offset = 0;
1140 var->blue.length = 5;
1141 var->transp.offset = 0;
1142 var->transp.length = 0;
1143 break;
1144 case 32:
1145 var->red.offset = 16;
1146 var->red.length = 8;
1147 var->green.offset = 8;
1148 var->green.length = 8;
1149 var->blue.offset = 0;
1150 var->blue.length = 8;
1151 var->transp.offset = 24;
1152 var->transp.length = 8;
1153 break;
1154 }
1155}
1156
1157static int
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001158sisfb_set_mode(struct sis_video_info *ivideo, int clrscrn)
1159{
1160 unsigned short modeno = ivideo->mode_no;
1161
1162 /* >=2.6.12's fbcon clears the screen anyway */
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001163 modeno |= 0x80;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001164
Aaro Koskinen44b751b2010-12-20 23:50:17 +02001165 SiS_SetReg(SISSR, IND_SIS_PASSWORD, SIS_PASSWORD);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001166
1167 sisfb_pre_setmode(ivideo);
1168
Richard Knutssonc30660ea2007-02-12 00:55:06 -08001169 if(!SiSSetMode(&ivideo->SiS_Pr, modeno)) {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001170 printk(KERN_ERR "sisfb: Setting mode[0x%x] failed\n", ivideo->mode_no);
1171 return -EINVAL;
1172 }
1173
Aaro Koskinen44b751b2010-12-20 23:50:17 +02001174 SiS_SetReg(SISSR, IND_SIS_PASSWORD, SIS_PASSWORD);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001175
1176 sisfb_post_setmode(ivideo);
1177
1178 return 0;
1179}
1180
1181
1182static int
Linus Torvalds1da177e2005-04-16 15:20:36 -07001183sisfb_do_set_var(struct fb_var_screeninfo *var, int isactive, struct fb_info *info)
1184{
1185 struct sis_video_info *ivideo = (struct sis_video_info *)info->par;
1186 unsigned int htotal = 0, vtotal = 0;
1187 unsigned int drate = 0, hrate = 0;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001188 int found_mode = 0, ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001189 int old_mode;
1190 u32 pixclock;
1191
1192 htotal = var->left_margin + var->xres + var->right_margin + var->hsync_len;
1193
1194 vtotal = var->upper_margin + var->lower_margin + var->vsync_len;
1195
1196 pixclock = var->pixclock;
1197
1198 if((var->vmode & FB_VMODE_MASK) == FB_VMODE_NONINTERLACED) {
1199 vtotal += var->yres;
1200 vtotal <<= 1;
1201 } else if((var->vmode & FB_VMODE_MASK) == FB_VMODE_DOUBLE) {
1202 vtotal += var->yres;
1203 vtotal <<= 2;
1204 } else if((var->vmode & FB_VMODE_MASK) == FB_VMODE_INTERLACED) {
1205 vtotal += var->yres;
1206 vtotal <<= 1;
1207 } else vtotal += var->yres;
1208
1209 if(!(htotal) || !(vtotal)) {
1210 DPRINTK("sisfb: Invalid 'var' information\n");
1211 return -EINVAL;
1212 }
1213
1214 if(pixclock && htotal && vtotal) {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001215 drate = 1000000000 / pixclock;
1216 hrate = (drate * 1000) / htotal;
1217 ivideo->refresh_rate = (unsigned int) (hrate * 2 / vtotal);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001218 } else {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001219 ivideo->refresh_rate = 60;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001220 }
1221
1222 old_mode = ivideo->sisfb_mode_idx;
1223 ivideo->sisfb_mode_idx = 0;
1224
1225 while( (sisbios_mode[ivideo->sisfb_mode_idx].mode_no[0] != 0) &&
1226 (sisbios_mode[ivideo->sisfb_mode_idx].xres <= var->xres) ) {
1227 if( (sisbios_mode[ivideo->sisfb_mode_idx].xres == var->xres) &&
1228 (sisbios_mode[ivideo->sisfb_mode_idx].yres == var->yres) &&
1229 (sisbios_mode[ivideo->sisfb_mode_idx].bpp == var->bits_per_pixel)) {
1230 ivideo->mode_no = sisbios_mode[ivideo->sisfb_mode_idx].mode_no[ivideo->mni];
1231 found_mode = 1;
1232 break;
1233 }
1234 ivideo->sisfb_mode_idx++;
1235 }
1236
1237 if(found_mode) {
1238 ivideo->sisfb_mode_idx = sisfb_validate_mode(ivideo,
1239 ivideo->sisfb_mode_idx, ivideo->currentvbflags);
1240 } else {
1241 ivideo->sisfb_mode_idx = -1;
1242 }
1243
1244 if(ivideo->sisfb_mode_idx < 0) {
1245 printk(KERN_ERR "sisfb: Mode %dx%dx%d not supported\n", var->xres,
1246 var->yres, var->bits_per_pixel);
1247 ivideo->sisfb_mode_idx = old_mode;
1248 return -EINVAL;
1249 }
1250
Adrian Bunka9e60e52007-11-14 16:59:02 -08001251 ivideo->mode_no = sisbios_mode[ivideo->sisfb_mode_idx].mode_no[ivideo->mni];
1252
Linus Torvalds1da177e2005-04-16 15:20:36 -07001253 if(sisfb_search_refresh_rate(ivideo, ivideo->refresh_rate, ivideo->sisfb_mode_idx) == 0) {
1254 ivideo->rate_idx = sisbios_mode[ivideo->sisfb_mode_idx].rate_idx;
1255 ivideo->refresh_rate = 60;
1256 }
1257
Linus Torvalds1da177e2005-04-16 15:20:36 -07001258 if(isactive) {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001259 /* If acceleration to be used? Need to know
1260 * before pre/post_set_mode()
1261 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001262 ivideo->accel = 0;
1263#if defined(FBINFO_HWACCEL_DISABLED) && defined(FBINFO_HWACCEL_XPAN)
1264#ifdef STUPID_ACCELF_TEXT_SHIT
1265 if(var->accel_flags & FB_ACCELF_TEXT) {
1266 info->flags &= ~FBINFO_HWACCEL_DISABLED;
1267 } else {
1268 info->flags |= FBINFO_HWACCEL_DISABLED;
1269 }
1270#endif
1271 if(!(info->flags & FBINFO_HWACCEL_DISABLED)) ivideo->accel = -1;
1272#else
1273 if(var->accel_flags & FB_ACCELF_TEXT) ivideo->accel = -1;
1274#endif
1275
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001276 if((ret = sisfb_set_mode(ivideo, 1))) {
1277 return ret;
1278 }
1279
1280 ivideo->video_bpp = sisbios_mode[ivideo->sisfb_mode_idx].bpp;
1281 ivideo->video_width = sisbios_mode[ivideo->sisfb_mode_idx].xres;
1282 ivideo->video_height = sisbios_mode[ivideo->sisfb_mode_idx].yres;
1283
1284 sisfb_calc_pitch(ivideo, var);
1285 sisfb_set_pitch(ivideo);
1286
Linus Torvalds1da177e2005-04-16 15:20:36 -07001287 sisfb_set_vparms(ivideo);
1288
1289 ivideo->current_width = ivideo->video_width;
1290 ivideo->current_height = ivideo->video_height;
1291 ivideo->current_bpp = ivideo->video_bpp;
1292 ivideo->current_htotal = htotal;
1293 ivideo->current_vtotal = vtotal;
1294 ivideo->current_linelength = ivideo->video_linelength;
1295 ivideo->current_pixclock = var->pixclock;
1296 ivideo->current_refresh_rate = ivideo->refresh_rate;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001297 ivideo->sisfb_lastrates[ivideo->mode_no] = ivideo->refresh_rate;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001298 }
1299
1300 return 0;
1301}
1302
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001303static void
1304sisfb_set_base_CRT1(struct sis_video_info *ivideo, unsigned int base)
1305{
Aaro Koskinen44b751b2010-12-20 23:50:17 +02001306 SiS_SetReg(SISSR, IND_SIS_PASSWORD, SIS_PASSWORD);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001307
Aaro Koskinen44b751b2010-12-20 23:50:17 +02001308 SiS_SetReg(SISCR, 0x0D, base & 0xFF);
1309 SiS_SetReg(SISCR, 0x0C, (base >> 8) & 0xFF);
1310 SiS_SetReg(SISSR, 0x0D, (base >> 16) & 0xFF);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001311 if(ivideo->sisvga_engine == SIS_315_VGA) {
Aaro Koskinenad78adb2010-12-20 23:50:20 +02001312 SiS_SetRegANDOR(SISSR, 0x37, 0xFE, (base >> 24) & 0x01);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001313 }
1314}
1315
1316static void
1317sisfb_set_base_CRT2(struct sis_video_info *ivideo, unsigned int base)
1318{
1319 if(ivideo->currentvbflags & VB_DISPTYPE_DISP2) {
Aaro Koskinen27799d62010-12-20 23:50:18 +02001320 SiS_SetRegOR(SISPART1, ivideo->CRT2_write_enable, 0x01);
Aaro Koskinen44b751b2010-12-20 23:50:17 +02001321 SiS_SetReg(SISPART1, 0x06, (base & 0xFF));
1322 SiS_SetReg(SISPART1, 0x05, ((base >> 8) & 0xFF));
1323 SiS_SetReg(SISPART1, 0x04, ((base >> 16) & 0xFF));
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001324 if(ivideo->sisvga_engine == SIS_315_VGA) {
Aaro Koskinenad78adb2010-12-20 23:50:20 +02001325 SiS_SetRegANDOR(SISPART1, 0x02, 0x7F, ((base >> 24) & 0x01) << 7);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001326 }
1327 }
1328}
1329
Linus Torvalds1da177e2005-04-16 15:20:36 -07001330static int
Laurent Pinchart8e42a962011-05-25 11:34:52 +02001331sisfb_pan_var(struct sis_video_info *ivideo, struct fb_info *info,
1332 struct fb_var_screeninfo *var)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001333{
Laurent Pinchart8e42a962011-05-25 11:34:52 +02001334 ivideo->current_base = var->yoffset * info->var.xres_virtual
1335 + var->xoffset;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001336
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001337 /* calculate base bpp dep. */
Laurent Pinchart8e42a962011-05-25 11:34:52 +02001338 switch (info->var.bits_per_pixel) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001339 case 32:
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001340 break;
1341 case 16:
1342 ivideo->current_base >>= 1;
1343 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001344 case 8:
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001345 default:
1346 ivideo->current_base >>= 2;
1347 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001348 }
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001349
1350 ivideo->current_base += (ivideo->video_offset >> 2);
1351
1352 sisfb_set_base_CRT1(ivideo, ivideo->current_base);
1353 sisfb_set_base_CRT2(ivideo, ivideo->current_base);
1354
Linus Torvalds1da177e2005-04-16 15:20:36 -07001355 return 0;
1356}
1357
Linus Torvalds1da177e2005-04-16 15:20:36 -07001358static int
1359sisfb_open(struct fb_info *info, int user)
1360{
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001361 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001362}
1363
1364static int
1365sisfb_release(struct fb_info *info, int user)
1366{
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001367 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001368}
1369
1370static int
1371sisfb_setcolreg(unsigned regno, unsigned red, unsigned green, unsigned blue,
1372 unsigned transp, struct fb_info *info)
1373{
1374 struct sis_video_info *ivideo = (struct sis_video_info *)info->par;
1375
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001376 if(regno >= sisfb_get_cmap_len(&info->var))
1377 return 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001378
1379 switch(info->var.bits_per_pixel) {
1380 case 8:
Aaro Koskinen63e13f82010-12-20 23:50:15 +02001381 SiS_SetRegByte(SISDACA, regno);
1382 SiS_SetRegByte(SISDACD, (red >> 10));
1383 SiS_SetRegByte(SISDACD, (green >> 10));
1384 SiS_SetRegByte(SISDACD, (blue >> 10));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001385 if(ivideo->currentvbflags & VB_DISPTYPE_DISP2) {
Aaro Koskinen63e13f82010-12-20 23:50:15 +02001386 SiS_SetRegByte(SISDAC2A, regno);
1387 SiS_SetRegByte(SISDAC2D, (red >> 8));
1388 SiS_SetRegByte(SISDAC2D, (green >> 8));
1389 SiS_SetRegByte(SISDAC2D, (blue >> 8));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001390 }
1391 break;
1392 case 16:
Antonino A. Daplas000d5332007-07-17 04:05:44 -07001393 if (regno >= 16)
1394 break;
1395
Linus Torvalds1da177e2005-04-16 15:20:36 -07001396 ((u32 *)(info->pseudo_palette))[regno] =
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001397 (red & 0xf800) |
1398 ((green & 0xfc00) >> 5) |
1399 ((blue & 0xf800) >> 11);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001400 break;
1401 case 32:
Antonino A. Daplas000d5332007-07-17 04:05:44 -07001402 if (regno >= 16)
1403 break;
1404
Linus Torvalds1da177e2005-04-16 15:20:36 -07001405 red >>= 8;
1406 green >>= 8;
1407 blue >>= 8;
1408 ((u32 *)(info->pseudo_palette))[regno] =
1409 (red << 16) | (green << 8) | (blue);
1410 break;
1411 }
1412 return 0;
1413}
1414
1415static int
1416sisfb_set_par(struct fb_info *info)
1417{
1418 int err;
1419
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001420 if((err = sisfb_do_set_var(&info->var, 1, info)))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001421 return err;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001422
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001423 sisfb_get_fix(&info->fix, -1, info);
Adrian Bunk14aefd12008-07-23 21:31:12 -07001424
Linus Torvalds1da177e2005-04-16 15:20:36 -07001425 return 0;
1426}
1427
1428static int
1429sisfb_check_var(struct fb_var_screeninfo *var, struct fb_info *info)
1430{
1431 struct sis_video_info *ivideo = (struct sis_video_info *)info->par;
1432 unsigned int htotal = 0, vtotal = 0, myrateindex = 0;
1433 unsigned int drate = 0, hrate = 0, maxyres;
1434 int found_mode = 0;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001435 int refresh_rate, search_idx, tidx;
Richard Knutssonc30660ea2007-02-12 00:55:06 -08001436 bool recalc_clock = false;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001437 u32 pixclock;
1438
1439 htotal = var->left_margin + var->xres + var->right_margin + var->hsync_len;
1440
1441 vtotal = var->upper_margin + var->lower_margin + var->vsync_len;
1442
1443 pixclock = var->pixclock;
1444
1445 if((var->vmode & FB_VMODE_MASK) == FB_VMODE_NONINTERLACED) {
1446 vtotal += var->yres;
1447 vtotal <<= 1;
1448 } else if((var->vmode & FB_VMODE_MASK) == FB_VMODE_DOUBLE) {
1449 vtotal += var->yres;
1450 vtotal <<= 2;
1451 } else if((var->vmode & FB_VMODE_MASK) == FB_VMODE_INTERLACED) {
1452 vtotal += var->yres;
1453 vtotal <<= 1;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001454 } else
1455 vtotal += var->yres;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001456
1457 if(!(htotal) || !(vtotal)) {
1458 SISFAIL("sisfb: no valid timing data");
1459 }
1460
1461 search_idx = 0;
1462 while( (sisbios_mode[search_idx].mode_no[0] != 0) &&
1463 (sisbios_mode[search_idx].xres <= var->xres) ) {
1464 if( (sisbios_mode[search_idx].xres == var->xres) &&
1465 (sisbios_mode[search_idx].yres == var->yres) &&
1466 (sisbios_mode[search_idx].bpp == var->bits_per_pixel)) {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001467 if((tidx = sisfb_validate_mode(ivideo, search_idx,
1468 ivideo->currentvbflags)) > 0) {
1469 found_mode = 1;
1470 search_idx = tidx;
1471 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001472 }
1473 }
1474 search_idx++;
1475 }
1476
1477 if(!found_mode) {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001478 search_idx = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001479 while(sisbios_mode[search_idx].mode_no[0] != 0) {
1480 if( (var->xres <= sisbios_mode[search_idx].xres) &&
1481 (var->yres <= sisbios_mode[search_idx].yres) &&
1482 (var->bits_per_pixel == sisbios_mode[search_idx].bpp) ) {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001483 if((tidx = sisfb_validate_mode(ivideo,search_idx,
1484 ivideo->currentvbflags)) > 0) {
1485 found_mode = 1;
1486 search_idx = tidx;
1487 break;
1488 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001489 }
1490 search_idx++;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001491 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001492 if(found_mode) {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001493 printk(KERN_DEBUG
1494 "sisfb: Adapted from %dx%dx%d to %dx%dx%d\n",
1495 var->xres, var->yres, var->bits_per_pixel,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001496 sisbios_mode[search_idx].xres,
1497 sisbios_mode[search_idx].yres,
1498 var->bits_per_pixel);
1499 var->xres = sisbios_mode[search_idx].xres;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001500 var->yres = sisbios_mode[search_idx].yres;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001501 } else {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001502 printk(KERN_ERR
1503 "sisfb: Failed to find supported mode near %dx%dx%d\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07001504 var->xres, var->yres, var->bits_per_pixel);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001505 return -EINVAL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001506 }
1507 }
1508
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001509 if( ((ivideo->vbflags2 & VB2_LVDS) ||
1510 ((ivideo->vbflags2 & VB2_30xBDH) && (ivideo->currentvbflags & CRT2_LCD))) &&
Linus Torvalds1da177e2005-04-16 15:20:36 -07001511 (var->bits_per_pixel == 8) ) {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001512 /* Slave modes on LVDS and 301B-DH */
1513 refresh_rate = 60;
Richard Knutssonc30660ea2007-02-12 00:55:06 -08001514 recalc_clock = true;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001515 } else if( (ivideo->current_htotal == htotal) &&
1516 (ivideo->current_vtotal == vtotal) &&
1517 (ivideo->current_pixclock == pixclock) ) {
1518 /* x=x & y=y & c=c -> assume depth change */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001519 drate = 1000000000 / pixclock;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001520 hrate = (drate * 1000) / htotal;
1521 refresh_rate = (unsigned int) (hrate * 2 / vtotal);
1522 } else if( ( (ivideo->current_htotal != htotal) ||
1523 (ivideo->current_vtotal != vtotal) ) &&
1524 (ivideo->current_pixclock == var->pixclock) ) {
1525 /* x!=x | y!=y & c=c -> invalid pixclock */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001526 if(ivideo->sisfb_lastrates[sisbios_mode[search_idx].mode_no[ivideo->mni]]) {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001527 refresh_rate =
1528 ivideo->sisfb_lastrates[sisbios_mode[search_idx].mode_no[ivideo->mni]];
Linus Torvalds1da177e2005-04-16 15:20:36 -07001529 } else if(ivideo->sisfb_parm_rate != -1) {
1530 /* Sic, sisfb_parm_rate - want to know originally desired rate here */
1531 refresh_rate = ivideo->sisfb_parm_rate;
1532 } else {
1533 refresh_rate = 60;
1534 }
Richard Knutssonc30660ea2007-02-12 00:55:06 -08001535 recalc_clock = true;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001536 } else if((pixclock) && (htotal) && (vtotal)) {
1537 drate = 1000000000 / pixclock;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001538 hrate = (drate * 1000) / htotal;
1539 refresh_rate = (unsigned int) (hrate * 2 / vtotal);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001540 } else if(ivideo->current_refresh_rate) {
1541 refresh_rate = ivideo->current_refresh_rate;
Richard Knutssonc30660ea2007-02-12 00:55:06 -08001542 recalc_clock = true;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001543 } else {
1544 refresh_rate = 60;
Richard Knutssonc30660ea2007-02-12 00:55:06 -08001545 recalc_clock = true;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001546 }
1547
1548 myrateindex = sisfb_search_refresh_rate(ivideo, refresh_rate, search_idx);
1549
1550 /* Eventually recalculate timing and clock */
1551 if(recalc_clock) {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001552 if(!myrateindex) myrateindex = sisbios_mode[search_idx].rate_idx;
1553 var->pixclock = (u32) (1000000000 / sisfb_mode_rate_to_dclock(&ivideo->SiS_Pr,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001554 sisbios_mode[search_idx].mode_no[ivideo->mni],
1555 myrateindex));
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001556 sisfb_mode_rate_to_ddata(&ivideo->SiS_Pr,
1557 sisbios_mode[search_idx].mode_no[ivideo->mni],
1558 myrateindex, var);
1559 if((var->vmode & FB_VMODE_MASK) == FB_VMODE_DOUBLE) {
1560 var->pixclock <<= 1;
1561 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001562 }
1563
1564 if(ivideo->sisfb_thismonitor.datavalid) {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001565 if(!sisfb_verify_rate(ivideo, &ivideo->sisfb_thismonitor, search_idx,
1566 myrateindex, refresh_rate)) {
1567 printk(KERN_INFO
1568 "sisfb: WARNING: Refresh rate exceeds monitor specs!\n");
1569 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001570 }
1571
1572 /* Adapt RGB settings */
1573 sisfb_bpp_to_var(ivideo, var);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001574
Linus Torvalds1da177e2005-04-16 15:20:36 -07001575 /* Sanity check for offsets */
1576 if(var->xoffset < 0) var->xoffset = 0;
1577 if(var->yoffset < 0) var->yoffset = 0;
1578
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001579 if(var->xres > var->xres_virtual)
1580 var->xres_virtual = var->xres;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001581
1582 if(ivideo->sisfb_ypan) {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001583 maxyres = sisfb_calc_maxyres(ivideo, var);
1584 if(ivideo->sisfb_max) {
1585 var->yres_virtual = maxyres;
1586 } else {
1587 if(var->yres_virtual > maxyres) {
1588 var->yres_virtual = maxyres;
1589 }
1590 }
1591 if(var->yres_virtual <= var->yres) {
1592 var->yres_virtual = var->yres;
1593 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001594 } else {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001595 if(var->yres != var->yres_virtual) {
1596 var->yres_virtual = var->yres;
1597 }
1598 var->xoffset = 0;
1599 var->yoffset = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001600 }
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001601
Linus Torvalds1da177e2005-04-16 15:20:36 -07001602 /* Truncate offsets to maximum if too high */
1603 if(var->xoffset > var->xres_virtual - var->xres) {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001604 var->xoffset = var->xres_virtual - var->xres - 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001605 }
1606
1607 if(var->yoffset > var->yres_virtual - var->yres) {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001608 var->yoffset = var->yres_virtual - var->yres - 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001609 }
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001610
Linus Torvalds1da177e2005-04-16 15:20:36 -07001611 /* Set everything else to 0 */
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001612 var->red.msb_right =
1613 var->green.msb_right =
1614 var->blue.msb_right =
1615 var->transp.offset =
1616 var->transp.length =
1617 var->transp.msb_right = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001618
1619 return 0;
1620}
1621
1622static int
1623sisfb_pan_display(struct fb_var_screeninfo *var, struct fb_info* info)
1624{
1625 struct sis_video_info *ivideo = (struct sis_video_info *)info->par;
1626 int err;
1627
Laurent Pinchart8e42a962011-05-25 11:34:52 +02001628 if (var->vmode & FB_VMODE_YWRAP)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001629 return -EINVAL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001630
Laurent Pinchart8e42a962011-05-25 11:34:52 +02001631 if (var->xoffset + info->var.xres > info->var.xres_virtual ||
1632 var->yoffset + info->var.yres > info->var.yres_virtual)
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001633 return -EINVAL;
1634
Laurent Pinchart8e42a962011-05-25 11:34:52 +02001635 err = sisfb_pan_var(ivideo, info, var);
1636 if (err < 0)
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001637 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001638
1639 info->var.xoffset = var->xoffset;
1640 info->var.yoffset = var->yoffset;
1641
1642 return 0;
1643}
1644
1645static int
1646sisfb_blank(int blank, struct fb_info *info)
1647{
1648 struct sis_video_info *ivideo = (struct sis_video_info *)info->par;
1649
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001650 return sisfb_myblank(ivideo, blank);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001651}
1652
Linus Torvalds1da177e2005-04-16 15:20:36 -07001653/* ----------- FBDev related routines for all series ---------- */
1654
Christoph Hellwig67a66802006-01-14 13:21:25 -08001655static int sisfb_ioctl(struct fb_info *info, unsigned int cmd,
1656 unsigned long arg)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001657{
1658 struct sis_video_info *ivideo = (struct sis_video_info *)info->par;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001659 struct sis_memreq sismemreq;
1660 struct fb_vblank sisvbblank;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001661 u32 gpu32 = 0;
1662#ifndef __user
1663#define __user
1664#endif
1665 u32 __user *argp = (u32 __user *)arg;
1666
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001667 switch(cmd) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001668 case FBIO_ALLOC:
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001669 if(!capable(CAP_SYS_RAWIO))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001670 return -EPERM;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001671
1672 if(copy_from_user(&sismemreq, (void __user *)arg, sizeof(sismemreq)))
1673 return -EFAULT;
1674
Linus Torvalds1da177e2005-04-16 15:20:36 -07001675 sis_malloc(&sismemreq);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001676
Linus Torvalds1da177e2005-04-16 15:20:36 -07001677 if(copy_to_user((void __user *)arg, &sismemreq, sizeof(sismemreq))) {
1678 sis_free((u32)sismemreq.offset);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001679 return -EFAULT;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001680 }
1681 break;
1682
1683 case FBIO_FREE:
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(get_user(gpu32, argp))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001688 return -EFAULT;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001689
Linus Torvalds1da177e2005-04-16 15:20:36 -07001690 sis_free(gpu32);
1691 break;
1692
1693 case FBIOGET_VBLANK:
Dan Rosenbergfd02db92010-09-22 13:05:09 -07001694
1695 memset(&sisvbblank, 0, sizeof(struct fb_vblank));
1696
Linus Torvalds1da177e2005-04-16 15:20:36 -07001697 sisvbblank.count = 0;
1698 sisvbblank.flags = sisfb_setupvbblankflags(ivideo, &sisvbblank.vcount, &sisvbblank.hcount);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001699
1700 if(copy_to_user((void __user *)arg, &sisvbblank, sizeof(sisvbblank)))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001701 return -EFAULT;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001702
Linus Torvalds1da177e2005-04-16 15:20:36 -07001703 break;
1704
1705 case SISFB_GET_INFO_SIZE:
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001706 return put_user(sizeof(struct sisfb_info), argp);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001707
1708 case SISFB_GET_INFO_OLD:
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001709 if(ivideo->warncount++ < 10)
1710 printk(KERN_INFO
1711 "sisfb: Deprecated ioctl call received - update your application!\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001712 case SISFB_GET_INFO: /* For communication with X driver */
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001713 ivideo->sisfb_infoblock.sisfb_id = SISFB_ID;
1714 ivideo->sisfb_infoblock.sisfb_version = VER_MAJOR;
1715 ivideo->sisfb_infoblock.sisfb_revision = VER_MINOR;
1716 ivideo->sisfb_infoblock.sisfb_patchlevel = VER_LEVEL;
1717 ivideo->sisfb_infoblock.chip_id = ivideo->chip_id;
1718 ivideo->sisfb_infoblock.sisfb_pci_vendor = ivideo->chip_vendor;
1719 ivideo->sisfb_infoblock.memory = ivideo->video_size / 1024;
1720 ivideo->sisfb_infoblock.heapstart = ivideo->heapstart / 1024;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001721 if(ivideo->modechanged) {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001722 ivideo->sisfb_infoblock.fbvidmode = ivideo->mode_no;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001723 } else {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001724 ivideo->sisfb_infoblock.fbvidmode = ivideo->modeprechange;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001725 }
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001726 ivideo->sisfb_infoblock.sisfb_caps = ivideo->caps;
1727 ivideo->sisfb_infoblock.sisfb_tqlen = ivideo->cmdQueueSize / 1024;
1728 ivideo->sisfb_infoblock.sisfb_pcibus = ivideo->pcibus;
1729 ivideo->sisfb_infoblock.sisfb_pcislot = ivideo->pcislot;
1730 ivideo->sisfb_infoblock.sisfb_pcifunc = ivideo->pcifunc;
1731 ivideo->sisfb_infoblock.sisfb_lcdpdc = ivideo->detectedpdc;
1732 ivideo->sisfb_infoblock.sisfb_lcdpdca = ivideo->detectedpdca;
1733 ivideo->sisfb_infoblock.sisfb_lcda = ivideo->detectedlcda;
1734 ivideo->sisfb_infoblock.sisfb_vbflags = ivideo->vbflags;
1735 ivideo->sisfb_infoblock.sisfb_currentvbflags = ivideo->currentvbflags;
1736 ivideo->sisfb_infoblock.sisfb_scalelcd = ivideo->SiS_Pr.UsePanelScaler;
1737 ivideo->sisfb_infoblock.sisfb_specialtiming = ivideo->SiS_Pr.SiS_CustomT;
1738 ivideo->sisfb_infoblock.sisfb_haveemi = ivideo->SiS_Pr.HaveEMI ? 1 : 0;
1739 ivideo->sisfb_infoblock.sisfb_haveemilcd = ivideo->SiS_Pr.HaveEMILCD ? 1 : 0;
1740 ivideo->sisfb_infoblock.sisfb_emi30 = ivideo->SiS_Pr.EMI_30;
1741 ivideo->sisfb_infoblock.sisfb_emi31 = ivideo->SiS_Pr.EMI_31;
1742 ivideo->sisfb_infoblock.sisfb_emi32 = ivideo->SiS_Pr.EMI_32;
1743 ivideo->sisfb_infoblock.sisfb_emi33 = ivideo->SiS_Pr.EMI_33;
1744 ivideo->sisfb_infoblock.sisfb_tvxpos = (u16)(ivideo->tvxpos + 32);
1745 ivideo->sisfb_infoblock.sisfb_tvypos = (u16)(ivideo->tvypos + 32);
1746 ivideo->sisfb_infoblock.sisfb_heapsize = ivideo->sisfb_heap_size / 1024;
1747 ivideo->sisfb_infoblock.sisfb_videooffset = ivideo->video_offset;
1748 ivideo->sisfb_infoblock.sisfb_curfstn = ivideo->curFSTN;
1749 ivideo->sisfb_infoblock.sisfb_curdstn = ivideo->curDSTN;
1750 ivideo->sisfb_infoblock.sisfb_vbflags2 = ivideo->vbflags2;
1751 ivideo->sisfb_infoblock.sisfb_can_post = ivideo->sisfb_can_post ? 1 : 0;
1752 ivideo->sisfb_infoblock.sisfb_card_posted = ivideo->sisfb_card_posted ? 1 : 0;
1753 ivideo->sisfb_infoblock.sisfb_was_boot_device = ivideo->sisfb_was_boot_device ? 1 : 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001754
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001755 if(copy_to_user((void __user *)arg, &ivideo->sisfb_infoblock,
1756 sizeof(ivideo->sisfb_infoblock)))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001757 return -EFAULT;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001758
Linus Torvalds1da177e2005-04-16 15:20:36 -07001759 break;
1760
1761 case SISFB_GET_VBRSTATUS_OLD:
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001762 if(ivideo->warncount++ < 10)
1763 printk(KERN_INFO
1764 "sisfb: Deprecated ioctl call received - update your application!\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001765 case SISFB_GET_VBRSTATUS:
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001766 if(sisfb_CheckVBRetrace(ivideo))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001767 return put_user((u32)1, argp);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001768 else
Linus Torvalds1da177e2005-04-16 15:20:36 -07001769 return put_user((u32)0, argp);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001770
1771 case SISFB_GET_AUTOMAXIMIZE_OLD:
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001772 if(ivideo->warncount++ < 10)
1773 printk(KERN_INFO
1774 "sisfb: Deprecated ioctl call received - update your application!\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001775 case SISFB_GET_AUTOMAXIMIZE:
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001776 if(ivideo->sisfb_max)
1777 return put_user((u32)1, argp);
1778 else
1779 return put_user((u32)0, argp);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001780
1781 case SISFB_SET_AUTOMAXIMIZE_OLD:
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001782 if(ivideo->warncount++ < 10)
1783 printk(KERN_INFO
1784 "sisfb: Deprecated ioctl call received - update your application!\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001785 case SISFB_SET_AUTOMAXIMIZE:
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001786 if(get_user(gpu32, argp))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001787 return -EFAULT;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001788
Linus Torvalds1da177e2005-04-16 15:20:36 -07001789 ivideo->sisfb_max = (gpu32) ? 1 : 0;
1790 break;
1791
1792 case SISFB_SET_TVPOSOFFSET:
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001793 if(get_user(gpu32, argp))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001794 return -EFAULT;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001795
Linus Torvalds1da177e2005-04-16 15:20:36 -07001796 sisfb_set_TVxposoffset(ivideo, ((int)(gpu32 >> 16)) - 32);
1797 sisfb_set_TVyposoffset(ivideo, ((int)(gpu32 & 0xffff)) - 32);
1798 break;
1799
1800 case SISFB_GET_TVPOSOFFSET:
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001801 return put_user((u32)(((ivideo->tvxpos+32)<<16)|((ivideo->tvypos+32)&0xffff)),
1802 argp);
1803
1804 case SISFB_COMMAND:
1805 if(copy_from_user(&ivideo->sisfb_command, (void __user *)arg,
1806 sizeof(struct sisfb_cmd)))
1807 return -EFAULT;
1808
1809 sisfb_handle_command(ivideo, &ivideo->sisfb_command);
1810
1811 if(copy_to_user((void __user *)arg, &ivideo->sisfb_command,
1812 sizeof(struct sisfb_cmd)))
1813 return -EFAULT;
1814
1815 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001816
1817 case SISFB_SET_LOCK:
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001818 if(get_user(gpu32, argp))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001819 return -EFAULT;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001820
Linus Torvalds1da177e2005-04-16 15:20:36 -07001821 ivideo->sisfblocked = (gpu32) ? 1 : 0;
1822 break;
1823
1824 default:
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001825#ifdef SIS_NEW_CONFIG_COMPAT
Linus Torvalds1da177e2005-04-16 15:20:36 -07001826 return -ENOIOCTLCMD;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001827#else
1828 return -EINVAL;
1829#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -07001830 }
1831 return 0;
1832}
1833
Linus Torvalds1da177e2005-04-16 15:20:36 -07001834static int
1835sisfb_get_fix(struct fb_fix_screeninfo *fix, int con, struct fb_info *info)
1836{
1837 struct sis_video_info *ivideo = (struct sis_video_info *)info->par;
1838
1839 memset(fix, 0, sizeof(struct fb_fix_screeninfo));
1840
Dan Carpenterdbd536b2010-05-24 14:33:53 -07001841 strlcpy(fix->id, ivideo->myid, sizeof(fix->id));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001842
Krzysztof Helt537a1bf2009-06-30 11:41:29 -07001843 mutex_lock(&info->mm_lock);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001844 fix->smem_start = ivideo->video_base + ivideo->video_offset;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001845 fix->smem_len = ivideo->sisfb_mem;
Krzysztof Helt537a1bf2009-06-30 11:41:29 -07001846 mutex_unlock(&info->mm_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001847 fix->type = FB_TYPE_PACKED_PIXELS;
1848 fix->type_aux = 0;
1849 fix->visual = (ivideo->video_bpp == 8) ? FB_VISUAL_PSEUDOCOLOR : FB_VISUAL_TRUECOLOR;
1850 fix->xpanstep = 1;
1851 fix->ypanstep = (ivideo->sisfb_ypan) ? 1 : 0;
1852 fix->ywrapstep = 0;
1853 fix->line_length = ivideo->video_linelength;
1854 fix->mmio_start = ivideo->mmio_base;
1855 fix->mmio_len = ivideo->mmio_size;
1856 if(ivideo->sisvga_engine == SIS_300_VGA) {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001857 fix->accel = FB_ACCEL_SIS_GLAMOUR;
1858 } else if((ivideo->chip == SIS_330) ||
1859 (ivideo->chip == SIS_760) ||
1860 (ivideo->chip == SIS_761)) {
1861 fix->accel = FB_ACCEL_SIS_XABRE;
1862 } else if(ivideo->chip == XGI_20) {
1863 fix->accel = FB_ACCEL_XGI_VOLARI_Z;
1864 } else if(ivideo->chip >= XGI_40) {
1865 fix->accel = FB_ACCEL_XGI_VOLARI_V;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001866 } else {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001867 fix->accel = FB_ACCEL_SIS_GLAMOUR_2;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001868 }
1869
1870 return 0;
1871}
1872
1873/* ---------------- fb_ops structures ----------------- */
1874
Linus Torvalds1da177e2005-04-16 15:20:36 -07001875static struct fb_ops sisfb_ops = {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001876 .owner = THIS_MODULE,
1877 .fb_open = sisfb_open,
1878 .fb_release = sisfb_release,
1879 .fb_check_var = sisfb_check_var,
1880 .fb_set_par = sisfb_set_par,
1881 .fb_setcolreg = sisfb_setcolreg,
1882 .fb_pan_display = sisfb_pan_display,
1883 .fb_blank = sisfb_blank,
1884 .fb_fillrect = fbcon_sis_fillrect,
1885 .fb_copyarea = fbcon_sis_copyarea,
1886 .fb_imageblit = cfb_imageblit,
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001887 .fb_sync = fbcon_sis_sync,
1888#ifdef SIS_NEW_CONFIG_COMPAT
Christoph Hellwig67a66802006-01-14 13:21:25 -08001889 .fb_compat_ioctl= sisfb_ioctl,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001890#endif
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001891 .fb_ioctl = sisfb_ioctl
Linus Torvalds1da177e2005-04-16 15:20:36 -07001892};
Linus Torvalds1da177e2005-04-16 15:20:36 -07001893
1894/* ---------------- Chip generation dependent routines ---------------- */
1895
Greg Kroah-Hartman48c68c42012-12-21 13:07:39 -08001896static struct pci_dev *sisfb_get_northbridge(int basechipid)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001897{
1898 struct pci_dev *pdev = NULL;
1899 int nbridgenum, nbridgeidx, i;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001900 static const unsigned short nbridgeids[] = {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001901 PCI_DEVICE_ID_SI_540, /* for SiS 540 VGA */
1902 PCI_DEVICE_ID_SI_630, /* for SiS 630/730 VGA */
1903 PCI_DEVICE_ID_SI_730,
1904 PCI_DEVICE_ID_SI_550, /* for SiS 550 VGA */
1905 PCI_DEVICE_ID_SI_650, /* for SiS 650/651/740 VGA */
1906 PCI_DEVICE_ID_SI_651,
1907 PCI_DEVICE_ID_SI_740,
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001908 PCI_DEVICE_ID_SI_661, /* for SiS 661/741/660/760/761 VGA */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001909 PCI_DEVICE_ID_SI_741,
1910 PCI_DEVICE_ID_SI_660,
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001911 PCI_DEVICE_ID_SI_760,
1912 PCI_DEVICE_ID_SI_761
Linus Torvalds1da177e2005-04-16 15:20:36 -07001913 };
1914
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001915 switch(basechipid) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001916#ifdef CONFIG_FB_SIS_300
1917 case SIS_540: nbridgeidx = 0; nbridgenum = 1; break;
1918 case SIS_630: nbridgeidx = 1; nbridgenum = 2; break;
1919#endif
1920#ifdef CONFIG_FB_SIS_315
1921 case SIS_550: nbridgeidx = 3; nbridgenum = 1; break;
1922 case SIS_650: nbridgeidx = 4; nbridgenum = 3; break;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001923 case SIS_660: nbridgeidx = 7; nbridgenum = 5; break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001924#endif
1925 default: return NULL;
1926 }
1927 for(i = 0; i < nbridgenum; i++) {
Adrian Bunk0959f0c2007-05-08 00:39:50 -07001928 if((pdev = pci_get_device(PCI_VENDOR_ID_SI,
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001929 nbridgeids[nbridgeidx+i], NULL)))
1930 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001931 }
1932 return pdev;
1933}
1934
Greg Kroah-Hartman48c68c42012-12-21 13:07:39 -08001935static int sisfb_get_dram_size(struct sis_video_info *ivideo)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001936{
1937#if defined(CONFIG_FB_SIS_300) || defined(CONFIG_FB_SIS_315)
1938 u8 reg;
1939#endif
1940
1941 ivideo->video_size = 0;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001942 ivideo->UMAsize = ivideo->LFBsize = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001943
1944 switch(ivideo->chip) {
1945#ifdef CONFIG_FB_SIS_300
1946 case SIS_300:
Aaro Koskinene57d4132010-12-20 23:50:16 +02001947 reg = SiS_GetReg(SISSR, 0x14);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001948 ivideo->video_size = ((reg & 0x3F) + 1) << 20;
1949 break;
1950 case SIS_540:
1951 case SIS_630:
1952 case SIS_730:
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001953 if(!ivideo->nbridge)
1954 return -1;
1955 pci_read_config_byte(ivideo->nbridge, 0x63, &reg);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001956 ivideo->video_size = 1 << (((reg & 0x70) >> 4) + 21);
1957 break;
1958#endif
1959#ifdef CONFIG_FB_SIS_315
1960 case SIS_315H:
1961 case SIS_315PRO:
1962 case SIS_315:
Aaro Koskinene57d4132010-12-20 23:50:16 +02001963 reg = SiS_GetReg(SISSR, 0x14);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001964 ivideo->video_size = (1 << ((reg & 0xf0) >> 4)) << 20;
1965 switch((reg >> 2) & 0x03) {
1966 case 0x01:
1967 case 0x03:
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001968 ivideo->video_size <<= 1;
1969 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001970 case 0x02:
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001971 ivideo->video_size += (ivideo->video_size/2);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001972 }
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001973 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001974 case SIS_330:
Aaro Koskinene57d4132010-12-20 23:50:16 +02001975 reg = SiS_GetReg(SISSR, 0x14);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001976 ivideo->video_size = (1 << ((reg & 0xf0) >> 4)) << 20;
1977 if(reg & 0x0c) ivideo->video_size <<= 1;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001978 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001979 case SIS_550:
1980 case SIS_650:
1981 case SIS_740:
Aaro Koskinene57d4132010-12-20 23:50:16 +02001982 reg = SiS_GetReg(SISSR, 0x14);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001983 ivideo->video_size = (((reg & 0x3f) + 1) << 2) << 20;
1984 break;
1985 case SIS_661:
1986 case SIS_741:
Aaro Koskinene57d4132010-12-20 23:50:16 +02001987 reg = SiS_GetReg(SISCR, 0x79);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001988 ivideo->video_size = (1 << ((reg & 0xf0) >> 4)) << 20;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001989 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001990 case SIS_660:
1991 case SIS_760:
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001992 case SIS_761:
Aaro Koskinene57d4132010-12-20 23:50:16 +02001993 reg = SiS_GetReg(SISCR, 0x79);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001994 reg = (reg & 0xf0) >> 4;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07001995 if(reg) {
1996 ivideo->video_size = (1 << reg) << 20;
1997 ivideo->UMAsize = ivideo->video_size;
1998 }
Aaro Koskinene57d4132010-12-20 23:50:16 +02001999 reg = SiS_GetReg(SISCR, 0x78);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002000 reg &= 0x30;
2001 if(reg) {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07002002 if(reg == 0x10) {
2003 ivideo->LFBsize = (32 << 20);
2004 } else {
2005 ivideo->LFBsize = (64 << 20);
2006 }
2007 ivideo->video_size += ivideo->LFBsize;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002008 }
Thomas Winischhofer544393f2005-09-09 13:04:45 -07002009 break;
2010 case SIS_340:
2011 case XGI_20:
2012 case XGI_40:
Aaro Koskinene57d4132010-12-20 23:50:16 +02002013 reg = SiS_GetReg(SISSR, 0x14);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07002014 ivideo->video_size = (1 << ((reg & 0xf0) >> 4)) << 20;
2015 if(ivideo->chip != XGI_20) {
2016 reg = (reg & 0x0c) >> 2;
2017 if(ivideo->revision_id == 2) {
2018 if(reg & 0x01) reg = 0x02;
2019 else reg = 0x00;
2020 }
2021 if(reg == 0x02) ivideo->video_size <<= 1;
2022 else if(reg == 0x03) ivideo->video_size <<= 2;
2023 }
2024 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002025#endif
2026 default:
2027 return -1;
2028 }
2029 return 0;
2030}
2031
2032/* -------------- video bridge device detection --------------- */
2033
Greg Kroah-Hartman48c68c42012-12-21 13:07:39 -08002034static void sisfb_detect_VB_connect(struct sis_video_info *ivideo)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002035{
2036 u8 cr32, temp;
2037
Thomas Winischhofer544393f2005-09-09 13:04:45 -07002038 /* No CRT2 on XGI Z7 */
2039 if(ivideo->chip == XGI_20) {
2040 ivideo->sisfb_crt1off = 0;
2041 return;
2042 }
2043
Linus Torvalds1da177e2005-04-16 15:20:36 -07002044#ifdef CONFIG_FB_SIS_300
2045 if(ivideo->sisvga_engine == SIS_300_VGA) {
Aaro Koskinene57d4132010-12-20 23:50:16 +02002046 temp = SiS_GetReg(SISSR, 0x17);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002047 if((temp & 0x0F) && (ivideo->chip != SIS_300)) {
2048 /* PAL/NTSC is stored on SR16 on such machines */
2049 if(!(ivideo->vbflags & (TV_PAL | TV_NTSC | TV_PALM | TV_PALN))) {
Aaro Koskinene57d4132010-12-20 23:50:16 +02002050 temp = SiS_GetReg(SISSR, 0x16);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002051 if(temp & 0x20)
2052 ivideo->vbflags |= TV_PAL;
2053 else
2054 ivideo->vbflags |= TV_NTSC;
2055 }
2056 }
2057 }
2058#endif
2059
Aaro Koskinene57d4132010-12-20 23:50:16 +02002060 cr32 = SiS_GetReg(SISCR, 0x32);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002061
2062 if(cr32 & SIS_CRT1) {
2063 ivideo->sisfb_crt1off = 0;
2064 } else {
2065 ivideo->sisfb_crt1off = (cr32 & 0xDF) ? 1 : 0;
2066 }
2067
2068 ivideo->vbflags &= ~(CRT2_TV | CRT2_LCD | CRT2_VGA);
2069
2070 if(cr32 & SIS_VB_TV) ivideo->vbflags |= CRT2_TV;
2071 if(cr32 & SIS_VB_LCD) ivideo->vbflags |= CRT2_LCD;
2072 if(cr32 & SIS_VB_CRT2) ivideo->vbflags |= CRT2_VGA;
2073
2074 /* Check given parms for hardware compatibility.
2075 * (Cannot do this in the search_xx routines since we don't
2076 * know what hardware we are running on then)
2077 */
2078
2079 if(ivideo->chip != SIS_550) {
2080 ivideo->sisfb_dstn = ivideo->sisfb_fstn = 0;
2081 }
2082
2083 if(ivideo->sisfb_tvplug != -1) {
2084 if( (ivideo->sisvga_engine != SIS_315_VGA) ||
Thomas Winischhofer544393f2005-09-09 13:04:45 -07002085 (!(ivideo->vbflags2 & VB2_SISYPBPRBRIDGE)) ) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002086 if(ivideo->sisfb_tvplug & TV_YPBPR) {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07002087 ivideo->sisfb_tvplug = -1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002088 printk(KERN_ERR "sisfb: YPbPr not supported\n");
2089 }
2090 }
2091 }
2092 if(ivideo->sisfb_tvplug != -1) {
2093 if( (ivideo->sisvga_engine != SIS_315_VGA) ||
Thomas Winischhofer544393f2005-09-09 13:04:45 -07002094 (!(ivideo->vbflags2 & VB2_SISHIVISIONBRIDGE)) ) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002095 if(ivideo->sisfb_tvplug & TV_HIVISION) {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07002096 ivideo->sisfb_tvplug = -1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002097 printk(KERN_ERR "sisfb: HiVision not supported\n");
2098 }
2099 }
2100 }
2101 if(ivideo->sisfb_tvstd != -1) {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07002102 if( (!(ivideo->vbflags2 & VB2_SISBRIDGE)) &&
2103 (!((ivideo->sisvga_engine == SIS_315_VGA) &&
2104 (ivideo->vbflags2 & VB2_CHRONTEL))) ) {
Roel Kluin5ab94812009-12-15 16:46:23 -08002105 if(ivideo->sisfb_tvstd & (TV_PALM | TV_PALN | TV_NTSCJ)) {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07002106 ivideo->sisfb_tvstd = -1;
2107 printk(KERN_ERR "sisfb: PALM/PALN/NTSCJ not supported\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002108 }
2109 }
2110 }
2111
2112 /* Detect/set TV plug & type */
2113 if(ivideo->sisfb_tvplug != -1) {
2114 ivideo->vbflags |= ivideo->sisfb_tvplug;
2115 } else {
2116 if(cr32 & SIS_VB_YPBPR) ivideo->vbflags |= (TV_YPBPR|TV_YPBPR525I); /* default: 480i */
2117 else if(cr32 & SIS_VB_HIVISION) ivideo->vbflags |= TV_HIVISION;
2118 else if(cr32 & SIS_VB_SCART) ivideo->vbflags |= TV_SCART;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07002119 else {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002120 if(cr32 & SIS_VB_SVIDEO) ivideo->vbflags |= TV_SVIDEO;
2121 if(cr32 & SIS_VB_COMPOSITE) ivideo->vbflags |= TV_AVIDEO;
2122 }
2123 }
2124
2125 if(!(ivideo->vbflags & (TV_YPBPR | TV_HIVISION))) {
2126 if(ivideo->sisfb_tvstd != -1) {
2127 ivideo->vbflags &= ~(TV_NTSC | TV_PAL | TV_PALM | TV_PALN | TV_NTSCJ);
2128 ivideo->vbflags |= ivideo->sisfb_tvstd;
2129 }
2130 if(ivideo->vbflags & TV_SCART) {
2131 ivideo->vbflags &= ~(TV_NTSC | TV_PALM | TV_PALN | TV_NTSCJ);
2132 ivideo->vbflags |= TV_PAL;
2133 }
2134 if(!(ivideo->vbflags & (TV_PAL | TV_NTSC | TV_PALM | TV_PALN | TV_NTSCJ))) {
2135 if(ivideo->sisvga_engine == SIS_300_VGA) {
Aaro Koskinene57d4132010-12-20 23:50:16 +02002136 temp = SiS_GetReg(SISSR, 0x38);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002137 if(temp & 0x01) ivideo->vbflags |= TV_PAL;
2138 else ivideo->vbflags |= TV_NTSC;
2139 } else if((ivideo->chip <= SIS_315PRO) || (ivideo->chip >= SIS_330)) {
Aaro Koskinene57d4132010-12-20 23:50:16 +02002140 temp = SiS_GetReg(SISSR, 0x38);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002141 if(temp & 0x01) ivideo->vbflags |= TV_PAL;
2142 else ivideo->vbflags |= TV_NTSC;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07002143 } else {
Aaro Koskinene57d4132010-12-20 23:50:16 +02002144 temp = SiS_GetReg(SISCR, 0x79);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002145 if(temp & 0x20) ivideo->vbflags |= TV_PAL;
2146 else ivideo->vbflags |= TV_NTSC;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07002147 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002148 }
2149 }
2150
2151 /* Copy forceCRT1 option to CRT1off if option is given */
Thomas Winischhofer544393f2005-09-09 13:04:45 -07002152 if(ivideo->sisfb_forcecrt1 != -1) {
2153 ivideo->sisfb_crt1off = (ivideo->sisfb_forcecrt1) ? 0 : 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002154 }
2155}
2156
2157/* ------------------ Sensing routines ------------------ */
2158
Greg Kroah-Hartman48c68c42012-12-21 13:07:39 -08002159static bool sisfb_test_DDC1(struct sis_video_info *ivideo)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002160{
2161 unsigned short old;
2162 int count = 48;
2163
2164 old = SiS_ReadDDC1Bit(&ivideo->SiS_Pr);
2165 do {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07002166 if(old != SiS_ReadDDC1Bit(&ivideo->SiS_Pr)) break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002167 } while(count--);
Richard Knutssonc30660ea2007-02-12 00:55:06 -08002168 return (count != -1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002169}
2170
Greg Kroah-Hartman48c68c42012-12-21 13:07:39 -08002171static void sisfb_sense_crt1(struct sis_video_info *ivideo)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002172{
Richard Knutssonc30660ea2007-02-12 00:55:06 -08002173 bool mustwait = false;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002174 u8 sr1F, cr17;
2175#ifdef CONFIG_FB_SIS_315
2176 u8 cr63=0;
2177#endif
2178 u16 temp = 0xffff;
2179 int i;
2180
Aaro Koskinene57d4132010-12-20 23:50:16 +02002181 sr1F = SiS_GetReg(SISSR, 0x1F);
Aaro Koskinen27799d62010-12-20 23:50:18 +02002182 SiS_SetRegOR(SISSR, 0x1F, 0x04);
Aaro Koskinen667a8b42010-12-20 23:50:19 +02002183 SiS_SetRegAND(SISSR, 0x1F, 0x3F);
Richard Knutssonc30660ea2007-02-12 00:55:06 -08002184 if(sr1F & 0xc0) mustwait = true;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002185
2186#ifdef CONFIG_FB_SIS_315
2187 if(ivideo->sisvga_engine == SIS_315_VGA) {
Aaro Koskinene57d4132010-12-20 23:50:16 +02002188 cr63 = SiS_GetReg(SISCR, ivideo->SiS_Pr.SiS_MyCR63);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002189 cr63 &= 0x40;
Aaro Koskinen667a8b42010-12-20 23:50:19 +02002190 SiS_SetRegAND(SISCR, ivideo->SiS_Pr.SiS_MyCR63, 0xBF);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002191 }
2192#endif
2193
Aaro Koskinene57d4132010-12-20 23:50:16 +02002194 cr17 = SiS_GetReg(SISCR, 0x17);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002195 cr17 &= 0x80;
2196 if(!cr17) {
Aaro Koskinen27799d62010-12-20 23:50:18 +02002197 SiS_SetRegOR(SISCR, 0x17, 0x80);
Richard Knutssonc30660ea2007-02-12 00:55:06 -08002198 mustwait = true;
Aaro Koskinen44b751b2010-12-20 23:50:17 +02002199 SiS_SetReg(SISSR, 0x00, 0x01);
2200 SiS_SetReg(SISSR, 0x00, 0x03);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002201 }
2202
2203 if(mustwait) {
2204 for(i=0; i < 10; i++) sisfbwaitretracecrt1(ivideo);
2205 }
2206
2207#ifdef CONFIG_FB_SIS_315
2208 if(ivideo->chip >= SIS_330) {
Aaro Koskinen667a8b42010-12-20 23:50:19 +02002209 SiS_SetRegAND(SISCR, 0x32, ~0x20);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002210 if(ivideo->chip >= SIS_340) {
Aaro Koskinen44b751b2010-12-20 23:50:17 +02002211 SiS_SetReg(SISCR, 0x57, 0x4a);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002212 } else {
Aaro Koskinen44b751b2010-12-20 23:50:17 +02002213 SiS_SetReg(SISCR, 0x57, 0x5f);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002214 }
Aaro Koskinen27799d62010-12-20 23:50:18 +02002215 SiS_SetRegOR(SISCR, 0x53, 0x02);
Aaro Koskinen1e1687d2010-12-20 23:50:14 +02002216 while ((SiS_GetRegByte(SISINPSTAT)) & 0x01) break;
2217 while (!((SiS_GetRegByte(SISINPSTAT)) & 0x01)) break;
2218 if ((SiS_GetRegByte(SISMISCW)) & 0x10) temp = 1;
Aaro Koskinen667a8b42010-12-20 23:50:19 +02002219 SiS_SetRegAND(SISCR, 0x53, 0xfd);
2220 SiS_SetRegAND(SISCR, 0x57, 0x00);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002221 }
2222#endif
2223
2224 if(temp == 0xffff) {
2225 i = 3;
2226 do {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07002227 temp = SiS_HandleDDC(&ivideo->SiS_Pr, ivideo->vbflags,
2228 ivideo->sisvga_engine, 0, 0, NULL, ivideo->vbflags2);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002229 } while(((temp == 0) || (temp == 0xffff)) && i--);
2230
2231 if((temp == 0) || (temp == 0xffff)) {
2232 if(sisfb_test_DDC1(ivideo)) temp = 1;
2233 }
2234 }
2235
2236 if((temp) && (temp != 0xffff)) {
Aaro Koskinen27799d62010-12-20 23:50:18 +02002237 SiS_SetRegOR(SISCR, 0x32, 0x20);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002238 }
2239
2240#ifdef CONFIG_FB_SIS_315
2241 if(ivideo->sisvga_engine == SIS_315_VGA) {
Aaro Koskinenad78adb2010-12-20 23:50:20 +02002242 SiS_SetRegANDOR(SISCR, ivideo->SiS_Pr.SiS_MyCR63, 0xBF, cr63);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002243 }
2244#endif
2245
Aaro Koskinenad78adb2010-12-20 23:50:20 +02002246 SiS_SetRegANDOR(SISCR, 0x17, 0x7F, cr17);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002247
Aaro Koskinen44b751b2010-12-20 23:50:17 +02002248 SiS_SetReg(SISSR, 0x1F, sr1F);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002249}
2250
2251/* Determine and detect attached devices on SiS30x */
Greg Kroah-Hartman48c68c42012-12-21 13:07:39 -08002252static void SiS_SenseLCD(struct sis_video_info *ivideo)
Thomas Winischhofer544393f2005-09-09 13:04:45 -07002253{
2254 unsigned char buffer[256];
2255 unsigned short temp, realcrtno, i;
2256 u8 reg, cr37 = 0, paneltype = 0;
2257 u16 xres, yres;
2258
Richard Knutssonc30660ea2007-02-12 00:55:06 -08002259 ivideo->SiS_Pr.PanelSelfDetected = false;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07002260
2261 /* LCD detection only for TMDS bridges */
2262 if(!(ivideo->vbflags2 & VB2_SISTMDSBRIDGE))
2263 return;
2264 if(ivideo->vbflags2 & VB2_30xBDH)
2265 return;
2266
2267 /* If LCD already set up by BIOS, skip it */
Aaro Koskinene57d4132010-12-20 23:50:16 +02002268 reg = SiS_GetReg(SISCR, 0x32);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07002269 if(reg & 0x08)
2270 return;
2271
2272 realcrtno = 1;
2273 if(ivideo->SiS_Pr.DDCPortMixup)
2274 realcrtno = 0;
2275
2276 /* Check DDC capabilities */
2277 temp = SiS_HandleDDC(&ivideo->SiS_Pr, ivideo->vbflags, ivideo->sisvga_engine,
2278 realcrtno, 0, &buffer[0], ivideo->vbflags2);
2279
2280 if((!temp) || (temp == 0xffff) || (!(temp & 0x02)))
2281 return;
2282
2283 /* Read DDC data */
2284 i = 3; /* Number of retrys */
2285 do {
2286 temp = SiS_HandleDDC(&ivideo->SiS_Pr, ivideo->vbflags,
2287 ivideo->sisvga_engine, realcrtno, 1,
2288 &buffer[0], ivideo->vbflags2);
2289 } while((temp) && i--);
2290
2291 if(temp)
2292 return;
2293
2294 /* No digital device */
2295 if(!(buffer[0x14] & 0x80))
2296 return;
2297
2298 /* First detailed timing preferred timing? */
2299 if(!(buffer[0x18] & 0x02))
2300 return;
2301
2302 xres = buffer[0x38] | ((buffer[0x3a] & 0xf0) << 4);
2303 yres = buffer[0x3b] | ((buffer[0x3d] & 0xf0) << 4);
2304
2305 switch(xres) {
2306 case 1024:
2307 if(yres == 768)
2308 paneltype = 0x02;
2309 break;
2310 case 1280:
2311 if(yres == 1024)
2312 paneltype = 0x03;
2313 break;
2314 case 1600:
2315 if((yres == 1200) && (ivideo->vbflags2 & VB2_30xC))
2316 paneltype = 0x0b;
2317 break;
2318 }
2319
2320 if(!paneltype)
2321 return;
2322
2323 if(buffer[0x23])
2324 cr37 |= 0x10;
2325
2326 if((buffer[0x47] & 0x18) == 0x18)
2327 cr37 |= ((((buffer[0x47] & 0x06) ^ 0x06) << 5) | 0x20);
2328 else
2329 cr37 |= 0xc0;
2330
Aaro Koskinen44b751b2010-12-20 23:50:17 +02002331 SiS_SetReg(SISCR, 0x36, paneltype);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07002332 cr37 &= 0xf1;
Aaro Koskinenad78adb2010-12-20 23:50:20 +02002333 SiS_SetRegANDOR(SISCR, 0x37, 0x0c, cr37);
Aaro Koskinen27799d62010-12-20 23:50:18 +02002334 SiS_SetRegOR(SISCR, 0x32, 0x08);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07002335
Richard Knutssonc30660ea2007-02-12 00:55:06 -08002336 ivideo->SiS_Pr.PanelSelfDetected = true;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07002337}
2338
Greg Kroah-Hartman48c68c42012-12-21 13:07:39 -08002339static int SISDoSense(struct sis_video_info *ivideo, u16 type, u16 test)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002340{
2341 int temp, mytest, result, i, j;
2342
2343 for(j = 0; j < 10; j++) {
2344 result = 0;
2345 for(i = 0; i < 3; i++) {
2346 mytest = test;
Aaro Koskinen44b751b2010-12-20 23:50:17 +02002347 SiS_SetReg(SISPART4, 0x11, (type & 0x00ff));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002348 temp = (type >> 8) | (mytest & 0x00ff);
Aaro Koskinenad78adb2010-12-20 23:50:20 +02002349 SiS_SetRegANDOR(SISPART4, 0x10, 0xe0, temp);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002350 SiS_DDC2Delay(&ivideo->SiS_Pr, 0x1500);
2351 mytest >>= 8;
2352 mytest &= 0x7f;
Aaro Koskinene57d4132010-12-20 23:50:16 +02002353 temp = SiS_GetReg(SISPART4, 0x03);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002354 temp ^= 0x0e;
2355 temp &= mytest;
2356 if(temp == mytest) result++;
2357#if 1
Aaro Koskinen44b751b2010-12-20 23:50:17 +02002358 SiS_SetReg(SISPART4, 0x11, 0x00);
Aaro Koskinen667a8b42010-12-20 23:50:19 +02002359 SiS_SetRegAND(SISPART4, 0x10, 0xe0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002360 SiS_DDC2Delay(&ivideo->SiS_Pr, 0x1000);
2361#endif
2362 }
2363 if((result == 0) || (result >= 2)) break;
2364 }
Thomas Winischhofer544393f2005-09-09 13:04:45 -07002365 return result;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002366}
2367
Greg Kroah-Hartman48c68c42012-12-21 13:07:39 -08002368static void SiS_Sense30x(struct sis_video_info *ivideo)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002369{
2370 u8 backupP4_0d,backupP2_00,backupP2_4d,backupSR_1e,biosflag=0;
2371 u16 svhs=0, svhs_c=0;
2372 u16 cvbs=0, cvbs_c=0;
2373 u16 vga2=0, vga2_c=0;
2374 int myflag, result;
2375 char stdstr[] = "sisfb: Detected";
2376 char tvstr[] = "TV connected to";
2377
Thomas Winischhofer544393f2005-09-09 13:04:45 -07002378 if(ivideo->vbflags2 & VB2_301) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002379 svhs = 0x00b9; cvbs = 0x00b3; vga2 = 0x00d1;
Aaro Koskinene57d4132010-12-20 23:50:16 +02002380 myflag = SiS_GetReg(SISPART4, 0x01);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002381 if(myflag & 0x04) {
2382 svhs = 0x00dd; cvbs = 0x00ee; vga2 = 0x00fd;
2383 }
Thomas Winischhofer544393f2005-09-09 13:04:45 -07002384 } else if(ivideo->vbflags2 & (VB2_301B | VB2_302B)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002385 svhs = 0x016b; cvbs = 0x0174; vga2 = 0x0190;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07002386 } else if(ivideo->vbflags2 & (VB2_301LV | VB2_302LV)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002387 svhs = 0x0200; cvbs = 0x0100;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07002388 } else if(ivideo->vbflags2 & (VB2_301C | VB2_302ELV | VB2_307T | VB2_307LV)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002389 svhs = 0x016b; cvbs = 0x0110; vga2 = 0x0190;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07002390 } else
2391 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002392
2393 vga2_c = 0x0e08; svhs_c = 0x0404; cvbs_c = 0x0804;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07002394 if(ivideo->vbflags & (VB2_301LV|VB2_302LV|VB2_302ELV|VB2_307LV)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002395 svhs_c = 0x0408; cvbs_c = 0x0808;
2396 }
Thomas Winischhofer544393f2005-09-09 13:04:45 -07002397
Linus Torvalds1da177e2005-04-16 15:20:36 -07002398 biosflag = 2;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07002399 if(ivideo->haveXGIROM) {
2400 biosflag = ivideo->bios_abase[0x58] & 0x03;
2401 } else if(ivideo->newrom) {
2402 if(ivideo->bios_abase[0x5d] & 0x04) biosflag |= 0x01;
2403 } else if(ivideo->sisvga_engine == SIS_300_VGA) {
2404 if(ivideo->bios_abase) {
2405 biosflag = ivideo->bios_abase[0xfe] & 0x03;
2406 }
2407 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002408
2409 if(ivideo->chip == SIS_300) {
Aaro Koskinene57d4132010-12-20 23:50:16 +02002410 myflag = SiS_GetReg(SISSR, 0x3b);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002411 if(!(myflag & 0x01)) vga2 = vga2_c = 0;
2412 }
2413
Thomas Winischhofer544393f2005-09-09 13:04:45 -07002414 if(!(ivideo->vbflags2 & VB2_SISVGA2BRIDGE)) {
2415 vga2 = vga2_c = 0;
2416 }
2417
Aaro Koskinene57d4132010-12-20 23:50:16 +02002418 backupSR_1e = SiS_GetReg(SISSR, 0x1e);
Aaro Koskinen27799d62010-12-20 23:50:18 +02002419 SiS_SetRegOR(SISSR, 0x1e, 0x20);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002420
Aaro Koskinene57d4132010-12-20 23:50:16 +02002421 backupP4_0d = SiS_GetReg(SISPART4, 0x0d);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07002422 if(ivideo->vbflags2 & VB2_30xC) {
Aaro Koskinenad78adb2010-12-20 23:50:20 +02002423 SiS_SetRegANDOR(SISPART4, 0x0d, ~0x07, 0x01);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002424 } else {
Aaro Koskinen27799d62010-12-20 23:50:18 +02002425 SiS_SetRegOR(SISPART4, 0x0d, 0x04);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002426 }
2427 SiS_DDC2Delay(&ivideo->SiS_Pr, 0x2000);
2428
Aaro Koskinene57d4132010-12-20 23:50:16 +02002429 backupP2_00 = SiS_GetReg(SISPART2, 0x00);
Aaro Koskinen44b751b2010-12-20 23:50:17 +02002430 SiS_SetReg(SISPART2, 0x00, ((backupP2_00 | 0x1c) & 0xfc));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002431
Aaro Koskinene57d4132010-12-20 23:50:16 +02002432 backupP2_4d = SiS_GetReg(SISPART2, 0x4d);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07002433 if(ivideo->vbflags2 & VB2_SISYPBPRBRIDGE) {
Aaro Koskinen44b751b2010-12-20 23:50:17 +02002434 SiS_SetReg(SISPART2, 0x4d, (backupP2_4d & ~0x10));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002435 }
2436
Thomas Winischhofer544393f2005-09-09 13:04:45 -07002437 if(!(ivideo->vbflags2 & VB2_30xCLV)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002438 SISDoSense(ivideo, 0, 0);
2439 }
2440
Aaro Koskinen667a8b42010-12-20 23:50:19 +02002441 SiS_SetRegAND(SISCR, 0x32, ~0x14);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002442
2443 if(vga2_c || vga2) {
2444 if(SISDoSense(ivideo, vga2, vga2_c)) {
2445 if(biosflag & 0x01) {
2446 printk(KERN_INFO "%s %s SCART output\n", stdstr, tvstr);
Aaro Koskinen27799d62010-12-20 23:50:18 +02002447 SiS_SetRegOR(SISCR, 0x32, 0x04);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002448 } else {
2449 printk(KERN_INFO "%s secondary VGA connection\n", stdstr);
Aaro Koskinen27799d62010-12-20 23:50:18 +02002450 SiS_SetRegOR(SISCR, 0x32, 0x10);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002451 }
2452 }
2453 }
2454
Aaro Koskinen667a8b42010-12-20 23:50:19 +02002455 SiS_SetRegAND(SISCR, 0x32, 0x3f);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002456
Thomas Winischhofer544393f2005-09-09 13:04:45 -07002457 if(ivideo->vbflags2 & VB2_30xCLV) {
Aaro Koskinen27799d62010-12-20 23:50:18 +02002458 SiS_SetRegOR(SISPART4, 0x0d, 0x04);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002459 }
2460
Thomas Winischhofer544393f2005-09-09 13:04:45 -07002461 if((ivideo->sisvga_engine == SIS_315_VGA) && (ivideo->vbflags2 & VB2_SISYPBPRBRIDGE)) {
Aaro Koskinen44b751b2010-12-20 23:50:17 +02002462 SiS_SetReg(SISPART2, 0x4d, (backupP2_4d | 0x10));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002463 SiS_DDC2Delay(&ivideo->SiS_Pr, 0x2000);
2464 if((result = SISDoSense(ivideo, svhs, 0x0604))) {
2465 if((result = SISDoSense(ivideo, cvbs, 0x0804))) {
2466 printk(KERN_INFO "%s %s YPbPr component output\n", stdstr, tvstr);
Aaro Koskinen27799d62010-12-20 23:50:18 +02002467 SiS_SetRegOR(SISCR, 0x32, 0x80);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002468 }
2469 }
Aaro Koskinen44b751b2010-12-20 23:50:17 +02002470 SiS_SetReg(SISPART2, 0x4d, backupP2_4d);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002471 }
2472
Aaro Koskinen667a8b42010-12-20 23:50:19 +02002473 SiS_SetRegAND(SISCR, 0x32, ~0x03);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002474
2475 if(!(ivideo->vbflags & TV_YPBPR)) {
2476 if((result = SISDoSense(ivideo, svhs, svhs_c))) {
2477 printk(KERN_INFO "%s %s SVIDEO output\n", stdstr, tvstr);
Aaro Koskinen27799d62010-12-20 23:50:18 +02002478 SiS_SetRegOR(SISCR, 0x32, 0x02);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002479 }
2480 if((biosflag & 0x02) || (!result)) {
2481 if(SISDoSense(ivideo, cvbs, cvbs_c)) {
2482 printk(KERN_INFO "%s %s COMPOSITE output\n", stdstr, tvstr);
Aaro Koskinen27799d62010-12-20 23:50:18 +02002483 SiS_SetRegOR(SISCR, 0x32, 0x01);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002484 }
2485 }
2486 }
2487
2488 SISDoSense(ivideo, 0, 0);
2489
Aaro Koskinen44b751b2010-12-20 23:50:17 +02002490 SiS_SetReg(SISPART2, 0x00, backupP2_00);
2491 SiS_SetReg(SISPART4, 0x0d, backupP4_0d);
2492 SiS_SetReg(SISSR, 0x1e, backupSR_1e);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002493
Thomas Winischhofer544393f2005-09-09 13:04:45 -07002494 if(ivideo->vbflags2 & VB2_30xCLV) {
Aaro Koskinene57d4132010-12-20 23:50:16 +02002495 biosflag = SiS_GetReg(SISPART2, 0x00);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002496 if(biosflag & 0x20) {
2497 for(myflag = 2; myflag > 0; myflag--) {
2498 biosflag ^= 0x20;
Aaro Koskinen44b751b2010-12-20 23:50:17 +02002499 SiS_SetReg(SISPART2, 0x00, biosflag);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002500 }
2501 }
2502 }
2503
Aaro Koskinen44b751b2010-12-20 23:50:17 +02002504 SiS_SetReg(SISPART2, 0x00, backupP2_00);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002505}
2506
2507/* Determine and detect attached TV's on Chrontel */
Greg Kroah-Hartman48c68c42012-12-21 13:07:39 -08002508static void SiS_SenseCh(struct sis_video_info *ivideo)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002509{
2510#if defined(CONFIG_FB_SIS_300) || defined(CONFIG_FB_SIS_315)
2511 u8 temp1, temp2;
2512 char stdstr[] = "sisfb: Chrontel: Detected TV connected to";
2513#endif
2514#ifdef CONFIG_FB_SIS_300
2515 unsigned char test[3];
2516 int i;
2517#endif
2518
2519 if(ivideo->chip < SIS_315H) {
2520
2521#ifdef CONFIG_FB_SIS_300
2522 ivideo->SiS_Pr.SiS_IF_DEF_CH70xx = 1; /* Chrontel 700x */
2523 SiS_SetChrontelGPIO(&ivideo->SiS_Pr, 0x9c); /* Set general purpose IO for Chrontel communication */
2524 SiS_DDC2Delay(&ivideo->SiS_Pr, 1000);
2525 temp1 = SiS_GetCH700x(&ivideo->SiS_Pr, 0x25);
2526 /* See Chrontel TB31 for explanation */
2527 temp2 = SiS_GetCH700x(&ivideo->SiS_Pr, 0x0e);
2528 if(((temp2 & 0x07) == 0x01) || (temp2 & 0x04)) {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07002529 SiS_SetCH700x(&ivideo->SiS_Pr, 0x0e, 0x0b);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002530 SiS_DDC2Delay(&ivideo->SiS_Pr, 300);
2531 }
2532 temp2 = SiS_GetCH700x(&ivideo->SiS_Pr, 0x25);
2533 if(temp2 != temp1) temp1 = temp2;
2534
2535 if((temp1 >= 0x22) && (temp1 <= 0x50)) {
2536 /* Read power status */
2537 temp1 = SiS_GetCH700x(&ivideo->SiS_Pr, 0x0e);
2538 if((temp1 & 0x03) != 0x03) {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07002539 /* Power all outputs */
2540 SiS_SetCH700x(&ivideo->SiS_Pr, 0x0e,0x0b);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002541 SiS_DDC2Delay(&ivideo->SiS_Pr, 300);
2542 }
2543 /* Sense connected TV devices */
2544 for(i = 0; i < 3; i++) {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07002545 SiS_SetCH700x(&ivideo->SiS_Pr, 0x10, 0x01);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002546 SiS_DDC2Delay(&ivideo->SiS_Pr, 0x96);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07002547 SiS_SetCH700x(&ivideo->SiS_Pr, 0x10, 0x00);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002548 SiS_DDC2Delay(&ivideo->SiS_Pr, 0x96);
2549 temp1 = SiS_GetCH700x(&ivideo->SiS_Pr, 0x10);
2550 if(!(temp1 & 0x08)) test[i] = 0x02;
2551 else if(!(temp1 & 0x02)) test[i] = 0x01;
2552 else test[i] = 0;
2553 SiS_DDC2Delay(&ivideo->SiS_Pr, 0x96);
2554 }
2555
2556 if(test[0] == test[1]) temp1 = test[0];
2557 else if(test[0] == test[2]) temp1 = test[0];
2558 else if(test[1] == test[2]) temp1 = test[1];
2559 else {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07002560 printk(KERN_INFO
Linus Torvalds1da177e2005-04-16 15:20:36 -07002561 "sisfb: TV detection unreliable - test results varied\n");
2562 temp1 = test[2];
2563 }
2564 if(temp1 == 0x02) {
2565 printk(KERN_INFO "%s SVIDEO output\n", stdstr);
2566 ivideo->vbflags |= TV_SVIDEO;
Aaro Koskinen27799d62010-12-20 23:50:18 +02002567 SiS_SetRegOR(SISCR, 0x32, 0x02);
Aaro Koskinen667a8b42010-12-20 23:50:19 +02002568 SiS_SetRegAND(SISCR, 0x32, ~0x05);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002569 } else if (temp1 == 0x01) {
2570 printk(KERN_INFO "%s CVBS output\n", stdstr);
2571 ivideo->vbflags |= TV_AVIDEO;
Aaro Koskinen27799d62010-12-20 23:50:18 +02002572 SiS_SetRegOR(SISCR, 0x32, 0x01);
Aaro Koskinen667a8b42010-12-20 23:50:19 +02002573 SiS_SetRegAND(SISCR, 0x32, ~0x06);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002574 } else {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07002575 SiS_SetCH70xxANDOR(&ivideo->SiS_Pr, 0x0e, 0x01, 0xF8);
Aaro Koskinen667a8b42010-12-20 23:50:19 +02002576 SiS_SetRegAND(SISCR, 0x32, ~0x07);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002577 }
2578 } else if(temp1 == 0) {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07002579 SiS_SetCH70xxANDOR(&ivideo->SiS_Pr, 0x0e, 0x01, 0xF8);
Aaro Koskinen667a8b42010-12-20 23:50:19 +02002580 SiS_SetRegAND(SISCR, 0x32, ~0x07);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002581 }
2582 /* Set general purpose IO for Chrontel communication */
2583 SiS_SetChrontelGPIO(&ivideo->SiS_Pr, 0x00);
2584#endif
2585
2586 } else {
2587
2588#ifdef CONFIG_FB_SIS_315
2589 ivideo->SiS_Pr.SiS_IF_DEF_CH70xx = 2; /* Chrontel 7019 */
Thomas Winischhofer544393f2005-09-09 13:04:45 -07002590 temp1 = SiS_GetCH701x(&ivideo->SiS_Pr, 0x49);
2591 SiS_SetCH701x(&ivideo->SiS_Pr, 0x49, 0x20);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002592 SiS_DDC2Delay(&ivideo->SiS_Pr, 0x96);
2593 temp2 = SiS_GetCH701x(&ivideo->SiS_Pr, 0x20);
2594 temp2 |= 0x01;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07002595 SiS_SetCH701x(&ivideo->SiS_Pr, 0x20, temp2);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002596 SiS_DDC2Delay(&ivideo->SiS_Pr, 0x96);
2597 temp2 ^= 0x01;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07002598 SiS_SetCH701x(&ivideo->SiS_Pr, 0x20, temp2);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002599 SiS_DDC2Delay(&ivideo->SiS_Pr, 0x96);
2600 temp2 = SiS_GetCH701x(&ivideo->SiS_Pr, 0x20);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07002601 SiS_SetCH701x(&ivideo->SiS_Pr, 0x49, temp1);
2602 temp1 = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002603 if(temp2 & 0x02) temp1 |= 0x01;
2604 if(temp2 & 0x10) temp1 |= 0x01;
2605 if(temp2 & 0x04) temp1 |= 0x02;
2606 if( (temp1 & 0x01) && (temp1 & 0x02) ) temp1 = 0x04;
2607 switch(temp1) {
2608 case 0x01:
2609 printk(KERN_INFO "%s CVBS output\n", stdstr);
2610 ivideo->vbflags |= TV_AVIDEO;
Aaro Koskinen27799d62010-12-20 23:50:18 +02002611 SiS_SetRegOR(SISCR, 0x32, 0x01);
Aaro Koskinen667a8b42010-12-20 23:50:19 +02002612 SiS_SetRegAND(SISCR, 0x32, ~0x06);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07002613 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002614 case 0x02:
2615 printk(KERN_INFO "%s SVIDEO output\n", stdstr);
2616 ivideo->vbflags |= TV_SVIDEO;
Aaro Koskinen27799d62010-12-20 23:50:18 +02002617 SiS_SetRegOR(SISCR, 0x32, 0x02);
Aaro Koskinen667a8b42010-12-20 23:50:19 +02002618 SiS_SetRegAND(SISCR, 0x32, ~0x05);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07002619 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002620 case 0x04:
2621 printk(KERN_INFO "%s SCART output\n", stdstr);
Aaro Koskinen27799d62010-12-20 23:50:18 +02002622 SiS_SetRegOR(SISCR, 0x32, 0x04);
Aaro Koskinen667a8b42010-12-20 23:50:19 +02002623 SiS_SetRegAND(SISCR, 0x32, ~0x03);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07002624 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002625 default:
Aaro Koskinen667a8b42010-12-20 23:50:19 +02002626 SiS_SetRegAND(SISCR, 0x32, ~0x07);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002627 }
2628#endif
2629 }
2630}
2631
Greg Kroah-Hartman48c68c42012-12-21 13:07:39 -08002632static void sisfb_get_VB_type(struct sis_video_info *ivideo)
Thomas Winischhofer544393f2005-09-09 13:04:45 -07002633{
2634 char stdstr[] = "sisfb: Detected";
2635 char bridgestr[] = "video bridge";
2636 u8 vb_chipid;
2637 u8 reg;
2638
2639 /* No CRT2 on XGI Z7 */
2640 if(ivideo->chip == XGI_20)
2641 return;
2642
Aaro Koskinene57d4132010-12-20 23:50:16 +02002643 vb_chipid = SiS_GetReg(SISPART4, 0x00);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07002644 switch(vb_chipid) {
2645 case 0x01:
Aaro Koskinene57d4132010-12-20 23:50:16 +02002646 reg = SiS_GetReg(SISPART4, 0x01);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07002647 if(reg < 0xb0) {
2648 ivideo->vbflags |= VB_301; /* Deprecated */
2649 ivideo->vbflags2 |= VB2_301;
2650 printk(KERN_INFO "%s SiS301 %s\n", stdstr, bridgestr);
2651 } else if(reg < 0xc0) {
2652 ivideo->vbflags |= VB_301B; /* Deprecated */
2653 ivideo->vbflags2 |= VB2_301B;
Aaro Koskinene57d4132010-12-20 23:50:16 +02002654 reg = SiS_GetReg(SISPART4, 0x23);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07002655 if(!(reg & 0x02)) {
2656 ivideo->vbflags |= VB_30xBDH; /* Deprecated */
2657 ivideo->vbflags2 |= VB2_30xBDH;
2658 printk(KERN_INFO "%s SiS301B-DH %s\n", stdstr, bridgestr);
2659 } else {
2660 printk(KERN_INFO "%s SiS301B %s\n", stdstr, bridgestr);
2661 }
2662 } else if(reg < 0xd0) {
2663 ivideo->vbflags |= VB_301C; /* Deprecated */
2664 ivideo->vbflags2 |= VB2_301C;
2665 printk(KERN_INFO "%s SiS301C %s\n", stdstr, bridgestr);
2666 } else if(reg < 0xe0) {
2667 ivideo->vbflags |= VB_301LV; /* Deprecated */
2668 ivideo->vbflags2 |= VB2_301LV;
2669 printk(KERN_INFO "%s SiS301LV %s\n", stdstr, bridgestr);
2670 } else if(reg <= 0xe1) {
Aaro Koskinene57d4132010-12-20 23:50:16 +02002671 reg = SiS_GetReg(SISPART4, 0x39);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07002672 if(reg == 0xff) {
2673 ivideo->vbflags |= VB_302LV; /* Deprecated */
2674 ivideo->vbflags2 |= VB2_302LV;
2675 printk(KERN_INFO "%s SiS302LV %s\n", stdstr, bridgestr);
2676 } else {
2677 ivideo->vbflags |= VB_301C; /* Deprecated */
2678 ivideo->vbflags2 |= VB2_301C;
2679 printk(KERN_INFO "%s SiS301C(P4) %s\n", stdstr, bridgestr);
2680#if 0
2681 ivideo->vbflags |= VB_302ELV; /* Deprecated */
2682 ivideo->vbflags2 |= VB2_302ELV;
2683 printk(KERN_INFO "%s SiS302ELV %s\n", stdstr, bridgestr);
2684#endif
2685 }
2686 }
2687 break;
2688 case 0x02:
2689 ivideo->vbflags |= VB_302B; /* Deprecated */
2690 ivideo->vbflags2 |= VB2_302B;
2691 printk(KERN_INFO "%s SiS302B %s\n", stdstr, bridgestr);
2692 break;
2693 }
2694
2695 if((!(ivideo->vbflags2 & VB2_VIDEOBRIDGE)) && (ivideo->chip != SIS_300)) {
Aaro Koskinene57d4132010-12-20 23:50:16 +02002696 reg = SiS_GetReg(SISCR, 0x37);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07002697 reg &= SIS_EXTERNAL_CHIP_MASK;
2698 reg >>= 1;
2699 if(ivideo->sisvga_engine == SIS_300_VGA) {
2700#ifdef CONFIG_FB_SIS_300
2701 switch(reg) {
2702 case SIS_EXTERNAL_CHIP_LVDS:
2703 ivideo->vbflags |= VB_LVDS; /* Deprecated */
2704 ivideo->vbflags2 |= VB2_LVDS;
2705 break;
2706 case SIS_EXTERNAL_CHIP_TRUMPION:
2707 ivideo->vbflags |= (VB_LVDS | VB_TRUMPION); /* Deprecated */
2708 ivideo->vbflags2 |= (VB2_LVDS | VB2_TRUMPION);
2709 break;
2710 case SIS_EXTERNAL_CHIP_CHRONTEL:
2711 ivideo->vbflags |= VB_CHRONTEL; /* Deprecated */
2712 ivideo->vbflags2 |= VB2_CHRONTEL;
2713 break;
2714 case SIS_EXTERNAL_CHIP_LVDS_CHRONTEL:
2715 ivideo->vbflags |= (VB_LVDS | VB_CHRONTEL); /* Deprecated */
2716 ivideo->vbflags2 |= (VB2_LVDS | VB2_CHRONTEL);
2717 break;
2718 }
2719 if(ivideo->vbflags2 & VB2_CHRONTEL) ivideo->chronteltype = 1;
2720#endif
2721 } else if(ivideo->chip < SIS_661) {
2722#ifdef CONFIG_FB_SIS_315
2723 switch (reg) {
2724 case SIS310_EXTERNAL_CHIP_LVDS:
2725 ivideo->vbflags |= VB_LVDS; /* Deprecated */
2726 ivideo->vbflags2 |= VB2_LVDS;
2727 break;
2728 case SIS310_EXTERNAL_CHIP_LVDS_CHRONTEL:
2729 ivideo->vbflags |= (VB_LVDS | VB_CHRONTEL); /* Deprecated */
2730 ivideo->vbflags2 |= (VB2_LVDS | VB2_CHRONTEL);
2731 break;
2732 }
2733 if(ivideo->vbflags2 & VB2_CHRONTEL) ivideo->chronteltype = 2;
2734#endif
2735 } else if(ivideo->chip >= SIS_661) {
2736#ifdef CONFIG_FB_SIS_315
Aaro Koskinene57d4132010-12-20 23:50:16 +02002737 reg = SiS_GetReg(SISCR, 0x38);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07002738 reg >>= 5;
2739 switch(reg) {
2740 case 0x02:
2741 ivideo->vbflags |= VB_LVDS; /* Deprecated */
2742 ivideo->vbflags2 |= VB2_LVDS;
2743 break;
2744 case 0x03:
2745 ivideo->vbflags |= (VB_LVDS | VB_CHRONTEL); /* Deprecated */
2746 ivideo->vbflags2 |= (VB2_LVDS | VB2_CHRONTEL);
2747 break;
2748 case 0x04:
2749 ivideo->vbflags |= (VB_LVDS | VB_CONEXANT); /* Deprecated */
2750 ivideo->vbflags2 |= (VB2_LVDS | VB2_CONEXANT);
2751 break;
2752 }
2753 if(ivideo->vbflags2 & VB2_CHRONTEL) ivideo->chronteltype = 2;
2754#endif
2755 }
2756 if(ivideo->vbflags2 & VB2_LVDS) {
2757 printk(KERN_INFO "%s LVDS transmitter\n", stdstr);
2758 }
2759 if((ivideo->sisvga_engine == SIS_300_VGA) && (ivideo->vbflags2 & VB2_TRUMPION)) {
2760 printk(KERN_INFO "%s Trumpion Zurac LCD scaler\n", stdstr);
2761 }
2762 if(ivideo->vbflags2 & VB2_CHRONTEL) {
2763 printk(KERN_INFO "%s Chrontel TV encoder\n", stdstr);
2764 }
2765 if((ivideo->chip >= SIS_661) && (ivideo->vbflags2 & VB2_CONEXANT)) {
2766 printk(KERN_INFO "%s Conexant external device\n", stdstr);
2767 }
2768 }
2769
2770 if(ivideo->vbflags2 & VB2_SISBRIDGE) {
2771 SiS_SenseLCD(ivideo);
2772 SiS_Sense30x(ivideo);
2773 } else if(ivideo->vbflags2 & VB2_CHRONTEL) {
2774 SiS_SenseCh(ivideo);
2775 }
2776}
2777
2778/* ---------- Engine initialization routines ------------ */
2779
2780static void
2781sisfb_engine_init(struct sis_video_info *ivideo)
2782{
2783
2784 /* Initialize command queue (we use MMIO only) */
2785
2786 /* BEFORE THIS IS CALLED, THE ENGINES *MUST* BE SYNC'ED */
2787
2788 ivideo->caps &= ~(TURBO_QUEUE_CAP |
2789 MMIO_CMD_QUEUE_CAP |
2790 VM_CMD_QUEUE_CAP |
2791 AGP_CMD_QUEUE_CAP);
2792
2793#ifdef CONFIG_FB_SIS_300
2794 if(ivideo->sisvga_engine == SIS_300_VGA) {
2795 u32 tqueue_pos;
2796 u8 tq_state;
2797
2798 tqueue_pos = (ivideo->video_size - ivideo->cmdQueueSize) / (64 * 1024);
2799
Aaro Koskinene57d4132010-12-20 23:50:16 +02002800 tq_state = SiS_GetReg(SISSR, IND_SIS_TURBOQUEUE_SET);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07002801 tq_state |= 0xf0;
2802 tq_state &= 0xfc;
2803 tq_state |= (u8)(tqueue_pos >> 8);
Aaro Koskinen44b751b2010-12-20 23:50:17 +02002804 SiS_SetReg(SISSR, IND_SIS_TURBOQUEUE_SET, tq_state);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07002805
Aaro Koskinen44b751b2010-12-20 23:50:17 +02002806 SiS_SetReg(SISSR, IND_SIS_TURBOQUEUE_ADR, (u8)(tqueue_pos & 0xff));
Thomas Winischhofer544393f2005-09-09 13:04:45 -07002807
2808 ivideo->caps |= TURBO_QUEUE_CAP;
2809 }
2810#endif
2811
2812#ifdef CONFIG_FB_SIS_315
2813 if(ivideo->sisvga_engine == SIS_315_VGA) {
2814 u32 tempq = 0, templ;
2815 u8 temp;
2816
2817 if(ivideo->chip == XGI_20) {
2818 switch(ivideo->cmdQueueSize) {
2819 case (64 * 1024):
2820 temp = SIS_CMD_QUEUE_SIZE_Z7_64k;
2821 break;
2822 case (128 * 1024):
2823 default:
2824 temp = SIS_CMD_QUEUE_SIZE_Z7_128k;
2825 }
2826 } else {
2827 switch(ivideo->cmdQueueSize) {
2828 case (4 * 1024 * 1024):
2829 temp = SIS_CMD_QUEUE_SIZE_4M;
2830 break;
2831 case (2 * 1024 * 1024):
2832 temp = SIS_CMD_QUEUE_SIZE_2M;
2833 break;
2834 case (1 * 1024 * 1024):
2835 temp = SIS_CMD_QUEUE_SIZE_1M;
2836 break;
2837 default:
2838 case (512 * 1024):
2839 temp = SIS_CMD_QUEUE_SIZE_512k;
2840 }
2841 }
2842
Aaro Koskinen44b751b2010-12-20 23:50:17 +02002843 SiS_SetReg(SISSR, IND_SIS_CMDQUEUE_THRESHOLD, COMMAND_QUEUE_THRESHOLD);
2844 SiS_SetReg(SISSR, IND_SIS_CMDQUEUE_SET, SIS_CMD_QUEUE_RESET);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07002845
2846 if((ivideo->chip >= XGI_40) && ivideo->modechanged) {
2847 /* Must disable dual pipe on XGI_40. Can't do
2848 * this in MMIO mode, because it requires
2849 * setting/clearing a bit in the MMIO fire trigger
2850 * register.
2851 */
2852 if(!((templ = MMIO_IN32(ivideo->mmio_vbase, 0x8240)) & (1 << 10))) {
2853
2854 MMIO_OUT32(ivideo->mmio_vbase, Q_WRITE_PTR, 0);
2855
Aaro Koskinen44b751b2010-12-20 23:50:17 +02002856 SiS_SetReg(SISSR, IND_SIS_CMDQUEUE_SET, (temp | SIS_VRAM_CMDQUEUE_ENABLE));
Thomas Winischhofer544393f2005-09-09 13:04:45 -07002857
2858 tempq = MMIO_IN32(ivideo->mmio_vbase, Q_READ_PTR);
2859 MMIO_OUT32(ivideo->mmio_vbase, Q_WRITE_PTR, tempq);
2860
2861 tempq = (u32)(ivideo->video_size - ivideo->cmdQueueSize);
2862 MMIO_OUT32(ivideo->mmio_vbase, Q_BASE_ADDR, tempq);
2863
2864 writel(0x16800000 + 0x8240, ivideo->video_vbase + tempq);
2865 writel(templ | (1 << 10), ivideo->video_vbase + tempq + 4);
2866 writel(0x168F0000, ivideo->video_vbase + tempq + 8);
2867 writel(0x168F0000, ivideo->video_vbase + tempq + 12);
2868
2869 MMIO_OUT32(ivideo->mmio_vbase, Q_WRITE_PTR, (tempq + 16));
2870
2871 sisfb_syncaccel(ivideo);
2872
Aaro Koskinen44b751b2010-12-20 23:50:17 +02002873 SiS_SetReg(SISSR, IND_SIS_CMDQUEUE_SET, SIS_CMD_QUEUE_RESET);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07002874
2875 }
2876 }
2877
2878 tempq = MMIO_IN32(ivideo->mmio_vbase, MMIO_QUEUE_READPORT);
2879 MMIO_OUT32(ivideo->mmio_vbase, MMIO_QUEUE_WRITEPORT, tempq);
2880
2881 temp |= (SIS_MMIO_CMD_ENABLE | SIS_CMD_AUTO_CORR);
Aaro Koskinen44b751b2010-12-20 23:50:17 +02002882 SiS_SetReg(SISSR, IND_SIS_CMDQUEUE_SET, temp);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07002883
2884 tempq = (u32)(ivideo->video_size - ivideo->cmdQueueSize);
2885 MMIO_OUT32(ivideo->mmio_vbase, MMIO_QUEUE_PHYBASE, tempq);
2886
2887 ivideo->caps |= MMIO_CMD_QUEUE_CAP;
2888 }
2889#endif
2890
2891 ivideo->engineok = 1;
2892}
2893
Greg Kroah-Hartman48c68c42012-12-21 13:07:39 -08002894static void sisfb_detect_lcd_type(struct sis_video_info *ivideo)
Thomas Winischhofer544393f2005-09-09 13:04:45 -07002895{
2896 u8 reg;
2897 int i;
2898
Aaro Koskinene57d4132010-12-20 23:50:16 +02002899 reg = SiS_GetReg(SISCR, 0x36);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07002900 reg &= 0x0f;
2901 if(ivideo->sisvga_engine == SIS_300_VGA) {
2902 ivideo->CRT2LCDType = sis300paneltype[reg];
2903 } else if(ivideo->chip >= SIS_661) {
2904 ivideo->CRT2LCDType = sis661paneltype[reg];
2905 } else {
2906 ivideo->CRT2LCDType = sis310paneltype[reg];
2907 if((ivideo->chip == SIS_550) && (sisfb_fstn)) {
2908 if((ivideo->CRT2LCDType != LCD_320x240_2) &&
2909 (ivideo->CRT2LCDType != LCD_320x240_3)) {
2910 ivideo->CRT2LCDType = LCD_320x240;
2911 }
2912 }
2913 }
2914
2915 if(ivideo->CRT2LCDType == LCD_UNKNOWN) {
2916 /* For broken BIOSes: Assume 1024x768, RGB18 */
2917 ivideo->CRT2LCDType = LCD_1024x768;
Aaro Koskinenad78adb2010-12-20 23:50:20 +02002918 SiS_SetRegANDOR(SISCR, 0x36, 0xf0, 0x02);
2919 SiS_SetRegANDOR(SISCR, 0x37, 0xee, 0x01);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07002920 printk(KERN_DEBUG "sisfb: Invalid panel ID (%02x), assuming 1024x768, RGB18\n", reg);
2921 }
2922
2923 for(i = 0; i < SIS_LCD_NUMBER; i++) {
2924 if(ivideo->CRT2LCDType == sis_lcd_data[i].lcdtype) {
2925 ivideo->lcdxres = sis_lcd_data[i].xres;
2926 ivideo->lcdyres = sis_lcd_data[i].yres;
2927 ivideo->lcddefmodeidx = sis_lcd_data[i].default_mode_idx;
2928 break;
2929 }
2930 }
2931
2932#ifdef CONFIG_FB_SIS_300
2933 if(ivideo->SiS_Pr.SiS_CustomT == CUT_BARCO1366) {
2934 ivideo->lcdxres = 1360; ivideo->lcdyres = 1024;
2935 ivideo->lcddefmodeidx = DEFAULT_MODE_1360;
2936 } else if(ivideo->SiS_Pr.SiS_CustomT == CUT_PANEL848) {
2937 ivideo->lcdxres = 848; ivideo->lcdyres = 480;
2938 ivideo->lcddefmodeidx = DEFAULT_MODE_848;
2939 } else if(ivideo->SiS_Pr.SiS_CustomT == CUT_PANEL856) {
2940 ivideo->lcdxres = 856; ivideo->lcdyres = 480;
2941 ivideo->lcddefmodeidx = DEFAULT_MODE_856;
2942 }
2943#endif
2944
2945 printk(KERN_DEBUG "sisfb: Detected %dx%d flat panel\n",
2946 ivideo->lcdxres, ivideo->lcdyres);
2947}
2948
Greg Kroah-Hartman48c68c42012-12-21 13:07:39 -08002949static void sisfb_save_pdc_emi(struct sis_video_info *ivideo)
Thomas Winischhofer544393f2005-09-09 13:04:45 -07002950{
2951#ifdef CONFIG_FB_SIS_300
2952 /* Save the current PanelDelayCompensation if the LCD is currently used */
2953 if(ivideo->sisvga_engine == SIS_300_VGA) {
2954 if(ivideo->vbflags2 & (VB2_LVDS | VB2_30xBDH)) {
2955 int tmp;
Aaro Koskinene57d4132010-12-20 23:50:16 +02002956 tmp = SiS_GetReg(SISCR, 0x30);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07002957 if(tmp & 0x20) {
2958 /* Currently on LCD? If yes, read current pdc */
Aaro Koskinene57d4132010-12-20 23:50:16 +02002959 ivideo->detectedpdc = SiS_GetReg(SISPART1, 0x13);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07002960 ivideo->detectedpdc &= 0x3c;
2961 if(ivideo->SiS_Pr.PDC == -1) {
2962 /* Let option override detection */
2963 ivideo->SiS_Pr.PDC = ivideo->detectedpdc;
2964 }
2965 printk(KERN_INFO "sisfb: Detected LCD PDC 0x%02x\n",
2966 ivideo->detectedpdc);
2967 }
2968 if((ivideo->SiS_Pr.PDC != -1) &&
2969 (ivideo->SiS_Pr.PDC != ivideo->detectedpdc)) {
2970 printk(KERN_INFO "sisfb: Using LCD PDC 0x%02x\n",
2971 ivideo->SiS_Pr.PDC);
2972 }
2973 }
2974 }
2975#endif
2976
2977#ifdef CONFIG_FB_SIS_315
2978 if(ivideo->sisvga_engine == SIS_315_VGA) {
2979
2980 /* Try to find about LCDA */
2981 if(ivideo->vbflags2 & VB2_SISLCDABRIDGE) {
2982 int tmp;
Aaro Koskinene57d4132010-12-20 23:50:16 +02002983 tmp = SiS_GetReg(SISPART1, 0x13);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07002984 if(tmp & 0x04) {
Richard Knutssonc30660ea2007-02-12 00:55:06 -08002985 ivideo->SiS_Pr.SiS_UseLCDA = true;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07002986 ivideo->detectedlcda = 0x03;
2987 }
2988 }
2989
2990 /* Save PDC */
2991 if(ivideo->vbflags2 & VB2_SISLVDSBRIDGE) {
2992 int tmp;
Aaro Koskinene57d4132010-12-20 23:50:16 +02002993 tmp = SiS_GetReg(SISCR, 0x30);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07002994 if((tmp & 0x20) || (ivideo->detectedlcda != 0xff)) {
2995 /* Currently on LCD? If yes, read current pdc */
2996 u8 pdc;
Aaro Koskinene57d4132010-12-20 23:50:16 +02002997 pdc = SiS_GetReg(SISPART1, 0x2D);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07002998 ivideo->detectedpdc = (pdc & 0x0f) << 1;
2999 ivideo->detectedpdca = (pdc & 0xf0) >> 3;
Aaro Koskinene57d4132010-12-20 23:50:16 +02003000 pdc = SiS_GetReg(SISPART1, 0x35);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003001 ivideo->detectedpdc |= ((pdc >> 7) & 0x01);
Aaro Koskinene57d4132010-12-20 23:50:16 +02003002 pdc = SiS_GetReg(SISPART1, 0x20);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003003 ivideo->detectedpdca |= ((pdc >> 6) & 0x01);
3004 if(ivideo->newrom) {
3005 /* New ROM invalidates other PDC resp. */
3006 if(ivideo->detectedlcda != 0xff) {
3007 ivideo->detectedpdc = 0xff;
3008 } else {
3009 ivideo->detectedpdca = 0xff;
3010 }
3011 }
3012 if(ivideo->SiS_Pr.PDC == -1) {
3013 if(ivideo->detectedpdc != 0xff) {
3014 ivideo->SiS_Pr.PDC = ivideo->detectedpdc;
3015 }
3016 }
3017 if(ivideo->SiS_Pr.PDCA == -1) {
3018 if(ivideo->detectedpdca != 0xff) {
3019 ivideo->SiS_Pr.PDCA = ivideo->detectedpdca;
3020 }
3021 }
3022 if(ivideo->detectedpdc != 0xff) {
3023 printk(KERN_INFO
3024 "sisfb: Detected LCD PDC 0x%02x (for LCD=CRT2)\n",
3025 ivideo->detectedpdc);
3026 }
3027 if(ivideo->detectedpdca != 0xff) {
3028 printk(KERN_INFO
3029 "sisfb: Detected LCD PDC1 0x%02x (for LCD=CRT1)\n",
3030 ivideo->detectedpdca);
3031 }
3032 }
3033
3034 /* Save EMI */
3035 if(ivideo->vbflags2 & VB2_SISEMIBRIDGE) {
Aaro Koskinene57d4132010-12-20 23:50:16 +02003036 ivideo->SiS_Pr.EMI_30 = SiS_GetReg(SISPART4, 0x30);
3037 ivideo->SiS_Pr.EMI_31 = SiS_GetReg(SISPART4, 0x31);
3038 ivideo->SiS_Pr.EMI_32 = SiS_GetReg(SISPART4, 0x32);
3039 ivideo->SiS_Pr.EMI_33 = SiS_GetReg(SISPART4, 0x33);
Richard Knutssonc30660ea2007-02-12 00:55:06 -08003040 ivideo->SiS_Pr.HaveEMI = true;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003041 if((tmp & 0x20) || (ivideo->detectedlcda != 0xff)) {
Richard Knutssonc30660ea2007-02-12 00:55:06 -08003042 ivideo->SiS_Pr.HaveEMILCD = true;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003043 }
3044 }
3045 }
3046
3047 /* Let user override detected PDCs (all bridges) */
3048 if(ivideo->vbflags2 & VB2_30xBLV) {
3049 if((ivideo->SiS_Pr.PDC != -1) &&
3050 (ivideo->SiS_Pr.PDC != ivideo->detectedpdc)) {
3051 printk(KERN_INFO "sisfb: Using LCD PDC 0x%02x (for LCD=CRT2)\n",
3052 ivideo->SiS_Pr.PDC);
3053 }
3054 if((ivideo->SiS_Pr.PDCA != -1) &&
3055 (ivideo->SiS_Pr.PDCA != ivideo->detectedpdca)) {
3056 printk(KERN_INFO "sisfb: Using LCD PDC1 0x%02x (for LCD=CRT1)\n",
3057 ivideo->SiS_Pr.PDCA);
3058 }
3059 }
3060
3061 }
3062#endif
3063}
3064
3065/* -------------------- Memory manager routines ---------------------- */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003066
Greg Kroah-Hartman48c68c42012-12-21 13:07:39 -08003067static u32 sisfb_getheapstart(struct sis_video_info *ivideo)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003068{
3069 u32 ret = ivideo->sisfb_parm_mem * 1024;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003070 u32 maxoffs = ivideo->video_size - ivideo->hwcursor_size - ivideo->cmdQueueSize;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003071 u32 def;
3072
3073 /* Calculate heap start = end of memory for console
3074 *
3075 * CCCCCCCCDDDDDDDDDDDDDDDDDDDDDDDDDDDDHHHHQQQQQQQQQQ
3076 * C = console, D = heap, H = HWCursor, Q = cmd-queue
3077 *
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003078 * On 76x in UMA+LFB mode, the layout is as follows:
3079 * DDDDDDDDDDDCCCCCCCCCCCCCCCCCCCCCCCCHHHHQQQQQQQQQQQ
3080 * where the heap is the entire UMA area, eventually
3081 * into the LFB area if the given mem parameter is
3082 * higher than the size of the UMA memory.
3083 *
Linus Torvalds1da177e2005-04-16 15:20:36 -07003084 * Basically given by "mem" parameter
3085 *
3086 * maximum = videosize - cmd_queue - hwcursor
3087 * (results in a heap of size 0)
3088 * default = SiS 300: depends on videosize
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003089 * SiS 315/330/340/XGI: 32k below max
Linus Torvalds1da177e2005-04-16 15:20:36 -07003090 */
3091
3092 if(ivideo->sisvga_engine == SIS_300_VGA) {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003093 if(ivideo->video_size > 0x1000000) {
3094 def = 0xc00000;
3095 } else if(ivideo->video_size > 0x800000) {
3096 def = 0x800000;
3097 } else {
3098 def = 0x400000;
3099 }
3100 } else if(ivideo->UMAsize && ivideo->LFBsize) {
3101 ret = def = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003102 } else {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003103 def = maxoffs - 0x8000;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003104 }
3105
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003106 /* Use default for secondary card for now (FIXME) */
3107 if((!ret) || (ret > maxoffs) || (ivideo->cardnumber != 0))
3108 ret = def;
3109
3110 return ret;
3111}
3112
Greg Kroah-Hartman48c68c42012-12-21 13:07:39 -08003113static u32 sisfb_getheapsize(struct sis_video_info *ivideo)
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003114{
3115 u32 max = ivideo->video_size - ivideo->hwcursor_size - ivideo->cmdQueueSize;
3116 u32 ret = 0;
3117
3118 if(ivideo->UMAsize && ivideo->LFBsize) {
3119 if( (!ivideo->sisfb_parm_mem) ||
3120 ((ivideo->sisfb_parm_mem * 1024) > max) ||
3121 ((max - (ivideo->sisfb_parm_mem * 1024)) < ivideo->UMAsize) ) {
3122 ret = ivideo->UMAsize;
3123 max -= ivideo->UMAsize;
3124 } else {
3125 ret = max - (ivideo->sisfb_parm_mem * 1024);
3126 max = ivideo->sisfb_parm_mem * 1024;
3127 }
3128 ivideo->video_offset = ret;
3129 ivideo->sisfb_mem = max;
3130 } else {
3131 ret = max - ivideo->heapstart;
3132 ivideo->sisfb_mem = ivideo->heapstart;
3133 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003134
3135 return ret;
3136}
3137
Greg Kroah-Hartman48c68c42012-12-21 13:07:39 -08003138static int sisfb_heap_init(struct sis_video_info *ivideo)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003139{
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003140 struct SIS_OH *poh;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003141
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003142 ivideo->video_offset = 0;
3143 if(ivideo->sisfb_parm_mem) {
3144 if( (ivideo->sisfb_parm_mem < (2 * 1024 * 1024)) ||
3145 (ivideo->sisfb_parm_mem > ivideo->video_size) ) {
3146 ivideo->sisfb_parm_mem = 0;
3147 }
3148 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003149
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003150 ivideo->heapstart = sisfb_getheapstart(ivideo);
3151 ivideo->sisfb_heap_size = sisfb_getheapsize(ivideo);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003152
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003153 ivideo->sisfb_heap_start = ivideo->video_vbase + ivideo->heapstart;
3154 ivideo->sisfb_heap_end = ivideo->sisfb_heap_start + ivideo->sisfb_heap_size;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003155
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003156 printk(KERN_INFO "sisfb: Memory heap starting at %dK, size %dK\n",
3157 (int)(ivideo->heapstart / 1024), (int)(ivideo->sisfb_heap_size / 1024));
Linus Torvalds1da177e2005-04-16 15:20:36 -07003158
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003159 ivideo->sisfb_heap.vinfo = ivideo;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003160
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003161 ivideo->sisfb_heap.poha_chain = NULL;
3162 ivideo->sisfb_heap.poh_freelist = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003163
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003164 poh = sisfb_poh_new_node(&ivideo->sisfb_heap);
3165 if(poh == NULL)
3166 return 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003167
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003168 poh->poh_next = &ivideo->sisfb_heap.oh_free;
3169 poh->poh_prev = &ivideo->sisfb_heap.oh_free;
3170 poh->size = ivideo->sisfb_heap_size;
3171 poh->offset = ivideo->heapstart;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003172
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003173 ivideo->sisfb_heap.oh_free.poh_next = poh;
3174 ivideo->sisfb_heap.oh_free.poh_prev = poh;
3175 ivideo->sisfb_heap.oh_free.size = 0;
3176 ivideo->sisfb_heap.max_freesize = poh->size;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003177
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003178 ivideo->sisfb_heap.oh_used.poh_next = &ivideo->sisfb_heap.oh_used;
3179 ivideo->sisfb_heap.oh_used.poh_prev = &ivideo->sisfb_heap.oh_used;
3180 ivideo->sisfb_heap.oh_used.size = SENTINEL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003181
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003182 if(ivideo->cardnumber == 0) {
3183 /* For the first card, make this heap the "global" one
3184 * for old DRM (which could handle only one card)
3185 */
3186 sisfb_heap = &ivideo->sisfb_heap;
3187 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003188
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003189 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003190}
3191
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003192static struct SIS_OH *
3193sisfb_poh_new_node(struct SIS_HEAP *memheap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003194{
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003195 struct SIS_OHALLOC *poha;
3196 struct SIS_OH *poh;
3197 unsigned long cOhs;
3198 int i;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003199
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003200 if(memheap->poh_freelist == NULL) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003201 poha = kmalloc(SIS_OH_ALLOC_SIZE, GFP_KERNEL);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003202 if(!poha)
3203 return NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003204
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003205 poha->poha_next = memheap->poha_chain;
3206 memheap->poha_chain = poha;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003207
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003208 cOhs = (SIS_OH_ALLOC_SIZE - sizeof(struct SIS_OHALLOC)) / sizeof(struct SIS_OH) + 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003209
3210 poh = &poha->aoh[0];
3211 for(i = cOhs - 1; i != 0; i--) {
3212 poh->poh_next = poh + 1;
3213 poh = poh + 1;
3214 }
3215
3216 poh->poh_next = NULL;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003217 memheap->poh_freelist = &poha->aoh[0];
Linus Torvalds1da177e2005-04-16 15:20:36 -07003218 }
3219
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003220 poh = memheap->poh_freelist;
3221 memheap->poh_freelist = poh->poh_next;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003222
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003223 return poh;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003224}
3225
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003226static struct SIS_OH *
3227sisfb_poh_allocate(struct SIS_HEAP *memheap, u32 size)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003228{
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003229 struct SIS_OH *pohThis;
3230 struct SIS_OH *pohRoot;
3231 int bAllocated = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003232
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003233 if(size > memheap->max_freesize) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003234 DPRINTK("sisfb: Can't allocate %dk video memory\n",
3235 (unsigned int) size / 1024);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003236 return NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003237 }
3238
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003239 pohThis = memheap->oh_free.poh_next;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003240
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003241 while(pohThis != &memheap->oh_free) {
3242 if(size <= pohThis->size) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003243 bAllocated = 1;
3244 break;
3245 }
3246 pohThis = pohThis->poh_next;
3247 }
3248
3249 if(!bAllocated) {
3250 DPRINTK("sisfb: Can't allocate %dk video memory\n",
3251 (unsigned int) size / 1024);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003252 return NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003253 }
3254
3255 if(size == pohThis->size) {
3256 pohRoot = pohThis;
3257 sisfb_delete_node(pohThis);
3258 } else {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003259 pohRoot = sisfb_poh_new_node(memheap);
3260 if(pohRoot == NULL)
3261 return NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003262
3263 pohRoot->offset = pohThis->offset;
3264 pohRoot->size = size;
3265
3266 pohThis->offset += size;
3267 pohThis->size -= size;
3268 }
3269
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003270 memheap->max_freesize -= size;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003271
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003272 pohThis = &memheap->oh_used;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003273 sisfb_insert_node(pohThis, pohRoot);
3274
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003275 return pohRoot;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003276}
3277
3278static void
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003279sisfb_delete_node(struct SIS_OH *poh)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003280{
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003281 poh->poh_prev->poh_next = poh->poh_next;
3282 poh->poh_next->poh_prev = poh->poh_prev;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003283}
3284
3285static void
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003286sisfb_insert_node(struct SIS_OH *pohList, struct SIS_OH *poh)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003287{
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003288 struct SIS_OH *pohTemp = pohList->poh_next;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003289
3290 pohList->poh_next = poh;
3291 pohTemp->poh_prev = poh;
3292
3293 poh->poh_prev = pohList;
3294 poh->poh_next = pohTemp;
3295}
3296
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003297static struct SIS_OH *
3298sisfb_poh_free(struct SIS_HEAP *memheap, u32 base)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003299{
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003300 struct SIS_OH *pohThis;
3301 struct SIS_OH *poh_freed;
3302 struct SIS_OH *poh_prev;
3303 struct SIS_OH *poh_next;
3304 u32 ulUpper;
3305 u32 ulLower;
3306 int foundNode = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003307
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003308 poh_freed = memheap->oh_used.poh_next;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003309
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003310 while(poh_freed != &memheap->oh_used) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003311 if(poh_freed->offset == base) {
3312 foundNode = 1;
3313 break;
3314 }
3315
3316 poh_freed = poh_freed->poh_next;
3317 }
3318
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003319 if(!foundNode)
3320 return NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003321
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003322 memheap->max_freesize += poh_freed->size;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003323
3324 poh_prev = poh_next = NULL;
3325 ulUpper = poh_freed->offset + poh_freed->size;
3326 ulLower = poh_freed->offset;
3327
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003328 pohThis = memheap->oh_free.poh_next;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003329
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003330 while(pohThis != &memheap->oh_free) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003331 if(pohThis->offset == ulUpper) {
3332 poh_next = pohThis;
3333 } else if((pohThis->offset + pohThis->size) == ulLower) {
3334 poh_prev = pohThis;
3335 }
3336 pohThis = pohThis->poh_next;
3337 }
3338
3339 sisfb_delete_node(poh_freed);
3340
3341 if(poh_prev && poh_next) {
3342 poh_prev->size += (poh_freed->size + poh_next->size);
3343 sisfb_delete_node(poh_next);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003344 sisfb_free_node(memheap, poh_freed);
3345 sisfb_free_node(memheap, poh_next);
3346 return poh_prev;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003347 }
3348
3349 if(poh_prev) {
3350 poh_prev->size += poh_freed->size;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003351 sisfb_free_node(memheap, poh_freed);
3352 return poh_prev;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003353 }
3354
3355 if(poh_next) {
3356 poh_next->size += poh_freed->size;
3357 poh_next->offset = poh_freed->offset;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003358 sisfb_free_node(memheap, poh_freed);
3359 return poh_next;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003360 }
3361
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003362 sisfb_insert_node(&memheap->oh_free, poh_freed);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003363
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003364 return poh_freed;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003365}
3366
3367static void
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003368sisfb_free_node(struct SIS_HEAP *memheap, struct SIS_OH *poh)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003369{
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003370 if(poh == NULL)
3371 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003372
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003373 poh->poh_next = memheap->poh_freelist;
3374 memheap->poh_freelist = poh;
3375}
3376
3377static void
3378sis_int_malloc(struct sis_video_info *ivideo, struct sis_memreq *req)
3379{
3380 struct SIS_OH *poh = NULL;
3381
3382 if((ivideo) && (ivideo->sisfb_id == SISFB_ID) && (!ivideo->havenoheap))
3383 poh = sisfb_poh_allocate(&ivideo->sisfb_heap, (u32)req->size);
3384
3385 if(poh == NULL) {
3386 req->offset = req->size = 0;
3387 DPRINTK("sisfb: Video RAM allocation failed\n");
3388 } else {
3389 req->offset = poh->offset;
3390 req->size = poh->size;
3391 DPRINTK("sisfb: Video RAM allocation succeeded: 0x%lx\n",
3392 (poh->offset + ivideo->video_vbase));
3393 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003394}
3395
3396void
3397sis_malloc(struct sis_memreq *req)
3398{
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003399 struct sis_video_info *ivideo = sisfb_heap->vinfo;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003400
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003401 if(&ivideo->sisfb_heap == sisfb_heap)
3402 sis_int_malloc(ivideo, req);
3403 else
3404 req->offset = req->size = 0;
3405}
Linus Torvalds1da177e2005-04-16 15:20:36 -07003406
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003407void
3408sis_malloc_new(struct pci_dev *pdev, struct sis_memreq *req)
3409{
3410 struct sis_video_info *ivideo = pci_get_drvdata(pdev);
3411
3412 sis_int_malloc(ivideo, req);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003413}
3414
3415/* sis_free: u32 because "base" is offset inside video ram, can never be >4GB */
3416
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003417static void
3418sis_int_free(struct sis_video_info *ivideo, u32 base)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003419{
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003420 struct SIS_OH *poh;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003421
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003422 if((!ivideo) || (ivideo->sisfb_id != SISFB_ID) || (ivideo->havenoheap))
3423 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003424
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003425 poh = sisfb_poh_free(&ivideo->sisfb_heap, base);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003426
3427 if(poh == NULL) {
3428 DPRINTK("sisfb: sisfb_poh_free() failed at base 0x%x\n",
3429 (unsigned int) base);
3430 }
3431}
3432
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003433void
3434sis_free(u32 base)
3435{
3436 struct sis_video_info *ivideo = sisfb_heap->vinfo;
3437
3438 sis_int_free(ivideo, base);
3439}
3440
3441void
3442sis_free_new(struct pci_dev *pdev, u32 base)
3443{
3444 struct sis_video_info *ivideo = pci_get_drvdata(pdev);
3445
3446 sis_int_free(ivideo, base);
3447}
3448
Linus Torvalds1da177e2005-04-16 15:20:36 -07003449/* --------------------- SetMode routines ------------------------- */
3450
3451static void
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003452sisfb_check_engine_and_sync(struct sis_video_info *ivideo)
3453{
3454 u8 cr30, cr31;
3455
3456 /* Check if MMIO and engines are enabled,
3457 * and sync in case they are. Can't use
3458 * ivideo->accel here, as this might have
3459 * been changed before this is called.
3460 */
Aaro Koskinene57d4132010-12-20 23:50:16 +02003461 cr30 = SiS_GetReg(SISSR, IND_SIS_PCI_ADDRESS_SET);
3462 cr31 = SiS_GetReg(SISSR, IND_SIS_MODULE_ENABLE);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003463 /* MMIO and 2D/3D engine enabled? */
3464 if((cr30 & SIS_MEM_MAP_IO_ENABLE) && (cr31 & 0x42)) {
3465#ifdef CONFIG_FB_SIS_300
3466 if(ivideo->sisvga_engine == SIS_300_VGA) {
3467 /* Don't care about TurboQueue. It's
3468 * enough to know that the engines
3469 * are enabled
3470 */
3471 sisfb_syncaccel(ivideo);
3472 }
3473#endif
3474#ifdef CONFIG_FB_SIS_315
3475 if(ivideo->sisvga_engine == SIS_315_VGA) {
3476 /* Check that any queue mode is
3477 * enabled, and that the queue
3478 * is not in the state of "reset"
3479 */
Aaro Koskinene57d4132010-12-20 23:50:16 +02003480 cr30 = SiS_GetReg(SISSR, 0x26);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003481 if((cr30 & 0xe0) && (!(cr30 & 0x01))) {
3482 sisfb_syncaccel(ivideo);
3483 }
3484 }
3485#endif
3486 }
3487}
3488
3489static void
Linus Torvalds1da177e2005-04-16 15:20:36 -07003490sisfb_pre_setmode(struct sis_video_info *ivideo)
3491{
3492 u8 cr30 = 0, cr31 = 0, cr33 = 0, cr35 = 0, cr38 = 0;
3493 int tvregnum = 0;
3494
3495 ivideo->currentvbflags &= (VB_VIDEOBRIDGE | VB_DISPTYPE_DISP2);
3496
Aaro Koskinen44b751b2010-12-20 23:50:17 +02003497 SiS_SetReg(SISSR, 0x05, 0x86);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003498
Aaro Koskinene57d4132010-12-20 23:50:16 +02003499 cr31 = SiS_GetReg(SISCR, 0x31);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003500 cr31 &= ~0x60;
3501 cr31 |= 0x04;
3502
3503 cr33 = ivideo->rate_idx & 0x0F;
3504
3505#ifdef CONFIG_FB_SIS_315
3506 if(ivideo->sisvga_engine == SIS_315_VGA) {
3507 if(ivideo->chip >= SIS_661) {
Aaro Koskinene57d4132010-12-20 23:50:16 +02003508 cr38 = SiS_GetReg(SISCR, 0x38);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003509 cr38 &= ~0x07; /* Clear LCDA/DualEdge and YPbPr bits */
3510 } else {
3511 tvregnum = 0x38;
Aaro Koskinene57d4132010-12-20 23:50:16 +02003512 cr38 = SiS_GetReg(SISCR, tvregnum);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003513 cr38 &= ~0x3b; /* Clear LCDA/DualEdge and YPbPr bits */
3514 }
3515 }
3516#endif
3517#ifdef CONFIG_FB_SIS_300
3518 if(ivideo->sisvga_engine == SIS_300_VGA) {
3519 tvregnum = 0x35;
Aaro Koskinene57d4132010-12-20 23:50:16 +02003520 cr38 = SiS_GetReg(SISCR, tvregnum);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003521 }
3522#endif
3523
Richard Knutssonc30660ea2007-02-12 00:55:06 -08003524 SiS_SetEnableDstn(&ivideo->SiS_Pr, false);
3525 SiS_SetEnableFstn(&ivideo->SiS_Pr, false);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003526 ivideo->curFSTN = ivideo->curDSTN = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003527
3528 switch(ivideo->currentvbflags & VB_DISPTYPE_DISP2) {
3529
3530 case CRT2_TV:
3531 cr38 &= ~0xc0; /* Clear PAL-M / PAL-N bits */
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003532 if((ivideo->vbflags & TV_YPBPR) && (ivideo->vbflags2 & VB2_SISYPBPRBRIDGE)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003533#ifdef CONFIG_FB_SIS_315
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003534 if(ivideo->chip >= SIS_661) {
3535 cr38 |= 0x04;
3536 if(ivideo->vbflags & TV_YPBPR525P) cr35 |= 0x20;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003537 else if(ivideo->vbflags & TV_YPBPR750P) cr35 |= 0x40;
3538 else if(ivideo->vbflags & TV_YPBPR1080I) cr35 |= 0x60;
3539 cr30 |= SIS_SIMULTANEOUS_VIEW_ENABLE;
3540 cr35 &= ~0x01;
3541 ivideo->currentvbflags |= (TV_YPBPR | (ivideo->vbflags & TV_YPBPRALL));
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003542 } else if(ivideo->sisvga_engine == SIS_315_VGA) {
3543 cr30 |= (0x80 | SIS_SIMULTANEOUS_VIEW_ENABLE);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003544 cr38 |= 0x08;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003545 if(ivideo->vbflags & TV_YPBPR525P) cr38 |= 0x10;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003546 else if(ivideo->vbflags & TV_YPBPR750P) cr38 |= 0x20;
3547 else if(ivideo->vbflags & TV_YPBPR1080I) cr38 |= 0x30;
3548 cr31 &= ~0x01;
3549 ivideo->currentvbflags |= (TV_YPBPR | (ivideo->vbflags & TV_YPBPRALL));
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003550 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003551#endif
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003552 } else if((ivideo->vbflags & TV_HIVISION) &&
3553 (ivideo->vbflags2 & VB2_SISHIVISIONBRIDGE)) {
3554 if(ivideo->chip >= SIS_661) {
3555 cr38 |= 0x04;
3556 cr35 |= 0x60;
3557 } else {
3558 cr30 |= 0x80;
3559 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003560 cr30 |= SIS_SIMULTANEOUS_VIEW_ENABLE;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003561 cr31 |= 0x01;
3562 cr35 |= 0x01;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003563 ivideo->currentvbflags |= TV_HIVISION;
3564 } else if(ivideo->vbflags & TV_SCART) {
3565 cr30 = (SIS_VB_OUTPUT_SCART | SIS_SIMULTANEOUS_VIEW_ENABLE);
3566 cr31 |= 0x01;
3567 cr35 |= 0x01;
3568 ivideo->currentvbflags |= TV_SCART;
3569 } else {
3570 if(ivideo->vbflags & TV_SVIDEO) {
3571 cr30 = (SIS_VB_OUTPUT_SVIDEO | SIS_SIMULTANEOUS_VIEW_ENABLE);
3572 ivideo->currentvbflags |= TV_SVIDEO;
3573 }
3574 if(ivideo->vbflags & TV_AVIDEO) {
3575 cr30 = (SIS_VB_OUTPUT_COMPOSITE | SIS_SIMULTANEOUS_VIEW_ENABLE);
3576 ivideo->currentvbflags |= TV_AVIDEO;
3577 }
3578 }
3579 cr31 |= SIS_DRIVER_MODE;
3580
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003581 if(ivideo->vbflags & (TV_AVIDEO | TV_SVIDEO)) {
3582 if(ivideo->vbflags & TV_PAL) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003583 cr31 |= 0x01; cr35 |= 0x01;
3584 ivideo->currentvbflags |= TV_PAL;
3585 if(ivideo->vbflags & TV_PALM) {
3586 cr38 |= 0x40; cr35 |= 0x04;
3587 ivideo->currentvbflags |= TV_PALM;
3588 } else if(ivideo->vbflags & TV_PALN) {
3589 cr38 |= 0x80; cr35 |= 0x08;
3590 ivideo->currentvbflags |= TV_PALN;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003591 }
3592 } else {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003593 cr31 &= ~0x01; cr35 &= ~0x01;
3594 ivideo->currentvbflags |= TV_NTSC;
3595 if(ivideo->vbflags & TV_NTSCJ) {
3596 cr38 |= 0x40; cr35 |= 0x02;
3597 ivideo->currentvbflags |= TV_NTSCJ;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003598 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003599 }
3600 }
3601 break;
3602
3603 case CRT2_LCD:
3604 cr30 = (SIS_VB_OUTPUT_LCD | SIS_SIMULTANEOUS_VIEW_ENABLE);
3605 cr31 |= SIS_DRIVER_MODE;
3606 SiS_SetEnableDstn(&ivideo->SiS_Pr, ivideo->sisfb_dstn);
3607 SiS_SetEnableFstn(&ivideo->SiS_Pr, ivideo->sisfb_fstn);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003608 ivideo->curFSTN = ivideo->sisfb_fstn;
3609 ivideo->curDSTN = ivideo->sisfb_dstn;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003610 break;
3611
3612 case CRT2_VGA:
3613 cr30 = (SIS_VB_OUTPUT_CRT2 | SIS_SIMULTANEOUS_VIEW_ENABLE);
3614 cr31 |= SIS_DRIVER_MODE;
3615 if(ivideo->sisfb_nocrt2rate) {
3616 cr33 |= (sisbios_mode[ivideo->sisfb_mode_idx].rate_idx << 4);
3617 } else {
3618 cr33 |= ((ivideo->rate_idx & 0x0F) << 4);
3619 }
3620 break;
3621
3622 default: /* disable CRT2 */
3623 cr30 = 0x00;
3624 cr31 |= (SIS_DRIVER_MODE | SIS_VB_OUTPUT_DISABLE);
3625 }
3626
Aaro Koskinen44b751b2010-12-20 23:50:17 +02003627 SiS_SetReg(SISCR, 0x30, cr30);
3628 SiS_SetReg(SISCR, 0x33, cr33);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003629
3630 if(ivideo->chip >= SIS_661) {
3631#ifdef CONFIG_FB_SIS_315
3632 cr31 &= ~0x01; /* Clear PAL flag (now in CR35) */
Aaro Koskinenad78adb2010-12-20 23:50:20 +02003633 SiS_SetRegANDOR(SISCR, 0x35, ~0x10, cr35); /* Leave overscan bit alone */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003634 cr38 &= 0x07; /* Use only LCDA and HiVision/YPbPr bits */
Aaro Koskinenad78adb2010-12-20 23:50:20 +02003635 SiS_SetRegANDOR(SISCR, 0x38, 0xf8, cr38);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003636#endif
3637 } else if(ivideo->chip != SIS_300) {
Aaro Koskinen44b751b2010-12-20 23:50:17 +02003638 SiS_SetReg(SISCR, tvregnum, cr38);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003639 }
Aaro Koskinen44b751b2010-12-20 23:50:17 +02003640 SiS_SetReg(SISCR, 0x31, cr31);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003641
Linus Torvalds1da177e2005-04-16 15:20:36 -07003642 ivideo->SiS_Pr.SiS_UseOEM = ivideo->sisfb_useoem;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003643
3644 sisfb_check_engine_and_sync(ivideo);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003645}
3646
3647/* Fix SR11 for 661 and later */
3648#ifdef CONFIG_FB_SIS_315
3649static void
3650sisfb_fixup_SR11(struct sis_video_info *ivideo)
3651{
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003652 u8 tmpreg;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003653
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003654 if(ivideo->chip >= SIS_661) {
Aaro Koskinene57d4132010-12-20 23:50:16 +02003655 tmpreg = SiS_GetReg(SISSR, 0x11);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003656 if(tmpreg & 0x20) {
Aaro Koskinene57d4132010-12-20 23:50:16 +02003657 tmpreg = SiS_GetReg(SISSR, 0x3e);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003658 tmpreg = (tmpreg + 1) & 0xff;
Aaro Koskinen44b751b2010-12-20 23:50:17 +02003659 SiS_SetReg(SISSR, 0x3e, tmpreg);
Aaro Koskinene57d4132010-12-20 23:50:16 +02003660 tmpreg = SiS_GetReg(SISSR, 0x11);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003661 }
3662 if(tmpreg & 0xf0) {
Aaro Koskinen667a8b42010-12-20 23:50:19 +02003663 SiS_SetRegAND(SISSR, 0x11, 0x0f);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003664 }
3665 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003666}
3667#endif
3668
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003669static void
3670sisfb_set_TVxposoffset(struct sis_video_info *ivideo, int val)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003671{
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003672 if(val > 32) val = 32;
3673 if(val < -32) val = -32;
3674 ivideo->tvxpos = val;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003675
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003676 if(ivideo->sisfblocked) return;
3677 if(!ivideo->modechanged) return;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003678
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003679 if(ivideo->currentvbflags & CRT2_TV) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003680
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003681 if(ivideo->vbflags2 & VB2_CHRONTEL) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003682
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003683 int x = ivideo->tvx;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003684
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003685 switch(ivideo->chronteltype) {
3686 case 1:
3687 x += val;
3688 if(x < 0) x = 0;
Aaro Koskinen44b751b2010-12-20 23:50:17 +02003689 SiS_SetReg(SISSR, 0x05, 0x86);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003690 SiS_SetCH700x(&ivideo->SiS_Pr, 0x0a, (x & 0xff));
3691 SiS_SetCH70xxANDOR(&ivideo->SiS_Pr, 0x08, ((x & 0x0100) >> 7), 0xFD);
3692 break;
3693 case 2:
3694 /* Not supported by hardware */
3695 break;
3696 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003697
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003698 } else if(ivideo->vbflags2 & VB2_SISBRIDGE) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003699
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003700 u8 p2_1f,p2_20,p2_2b,p2_42,p2_43;
3701 unsigned short temp;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003702
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003703 p2_1f = ivideo->p2_1f;
3704 p2_20 = ivideo->p2_20;
3705 p2_2b = ivideo->p2_2b;
3706 p2_42 = ivideo->p2_42;
3707 p2_43 = ivideo->p2_43;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003708
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003709 temp = p2_1f | ((p2_20 & 0xf0) << 4);
3710 temp += (val * 2);
3711 p2_1f = temp & 0xff;
3712 p2_20 = (temp & 0xf00) >> 4;
3713 p2_2b = ((p2_2b & 0x0f) + (val * 2)) & 0x0f;
3714 temp = p2_43 | ((p2_42 & 0xf0) << 4);
3715 temp += (val * 2);
3716 p2_43 = temp & 0xff;
3717 p2_42 = (temp & 0xf00) >> 4;
Aaro Koskinen44b751b2010-12-20 23:50:17 +02003718 SiS_SetReg(SISPART2, 0x1f, p2_1f);
Aaro Koskinenad78adb2010-12-20 23:50:20 +02003719 SiS_SetRegANDOR(SISPART2, 0x20, 0x0F, p2_20);
3720 SiS_SetRegANDOR(SISPART2, 0x2b, 0xF0, p2_2b);
3721 SiS_SetRegANDOR(SISPART2, 0x42, 0x0F, p2_42);
Aaro Koskinen44b751b2010-12-20 23:50:17 +02003722 SiS_SetReg(SISPART2, 0x43, p2_43);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003723 }
3724 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003725}
3726
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003727static void
3728sisfb_set_TVyposoffset(struct sis_video_info *ivideo, int val)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003729{
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003730 if(val > 32) val = 32;
3731 if(val < -32) val = -32;
3732 ivideo->tvypos = val;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003733
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003734 if(ivideo->sisfblocked) return;
3735 if(!ivideo->modechanged) return;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003736
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003737 if(ivideo->currentvbflags & CRT2_TV) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003738
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003739 if(ivideo->vbflags2 & VB2_CHRONTEL) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003740
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003741 int y = ivideo->tvy;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003742
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003743 switch(ivideo->chronteltype) {
3744 case 1:
3745 y -= val;
3746 if(y < 0) y = 0;
Aaro Koskinen44b751b2010-12-20 23:50:17 +02003747 SiS_SetReg(SISSR, 0x05, 0x86);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003748 SiS_SetCH700x(&ivideo->SiS_Pr, 0x0b, (y & 0xff));
3749 SiS_SetCH70xxANDOR(&ivideo->SiS_Pr, 0x08, ((y & 0x0100) >> 8), 0xFE);
3750 break;
3751 case 2:
3752 /* Not supported by hardware */
3753 break;
3754 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003755
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003756 } else if(ivideo->vbflags2 & VB2_SISBRIDGE) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003757
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003758 char p2_01, p2_02;
3759 val /= 2;
3760 p2_01 = ivideo->p2_01;
3761 p2_02 = ivideo->p2_02;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003762
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003763 p2_01 += val;
3764 p2_02 += val;
3765 if(!(ivideo->currentvbflags & (TV_HIVISION | TV_YPBPR))) {
3766 while((p2_01 <= 0) || (p2_02 <= 0)) {
3767 p2_01 += 2;
3768 p2_02 += 2;
3769 }
3770 }
Aaro Koskinen44b751b2010-12-20 23:50:17 +02003771 SiS_SetReg(SISPART2, 0x01, p2_01);
3772 SiS_SetReg(SISPART2, 0x02, p2_02);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003773 }
3774 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003775}
3776
3777static void
3778sisfb_post_setmode(struct sis_video_info *ivideo)
3779{
Richard Knutssonc30660ea2007-02-12 00:55:06 -08003780 bool crt1isoff = false;
3781 bool doit = true;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003782#if defined(CONFIG_FB_SIS_300) || defined(CONFIG_FB_SIS_315)
3783 u8 reg;
3784#endif
3785#ifdef CONFIG_FB_SIS_315
3786 u8 reg1;
3787#endif
3788
Aaro Koskinen44b751b2010-12-20 23:50:17 +02003789 SiS_SetReg(SISSR, 0x05, 0x86);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003790
3791#ifdef CONFIG_FB_SIS_315
3792 sisfb_fixup_SR11(ivideo);
3793#endif
3794
3795 /* Now we actually HAVE changed the display mode */
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003796 ivideo->modechanged = 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003797
3798 /* We can't switch off CRT1 if bridge is in slave mode */
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003799 if(ivideo->vbflags2 & VB2_VIDEOBRIDGE) {
Richard Knutssonc30660ea2007-02-12 00:55:06 -08003800 if(sisfb_bridgeisslave(ivideo)) doit = false;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003801 } else
3802 ivideo->sisfb_crt1off = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003803
3804#ifdef CONFIG_FB_SIS_300
3805 if(ivideo->sisvga_engine == SIS_300_VGA) {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003806 if((ivideo->sisfb_crt1off) && (doit)) {
Richard Knutssonc30660ea2007-02-12 00:55:06 -08003807 crt1isoff = true;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003808 reg = 0x00;
3809 } else {
Richard Knutssonc30660ea2007-02-12 00:55:06 -08003810 crt1isoff = false;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003811 reg = 0x80;
3812 }
Aaro Koskinenad78adb2010-12-20 23:50:20 +02003813 SiS_SetRegANDOR(SISCR, 0x17, 0x7f, reg);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003814 }
3815#endif
3816#ifdef CONFIG_FB_SIS_315
3817 if(ivideo->sisvga_engine == SIS_315_VGA) {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003818 if((ivideo->sisfb_crt1off) && (doit)) {
Richard Knutssonc30660ea2007-02-12 00:55:06 -08003819 crt1isoff = true;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003820 reg = 0x40;
3821 reg1 = 0xc0;
3822 } else {
Richard Knutssonc30660ea2007-02-12 00:55:06 -08003823 crt1isoff = false;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003824 reg = 0x00;
3825 reg1 = 0x00;
3826 }
Aaro Koskinenad78adb2010-12-20 23:50:20 +02003827 SiS_SetRegANDOR(SISCR, ivideo->SiS_Pr.SiS_MyCR63, ~0x40, reg);
Aaro Koskinen17d6ce12010-12-20 23:50:22 +02003828 SiS_SetRegANDOR(SISSR, 0x1f, 0x3f, reg1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003829 }
3830#endif
3831
3832 if(crt1isoff) {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003833 ivideo->currentvbflags &= ~VB_DISPTYPE_CRT1;
3834 ivideo->currentvbflags |= VB_SINGLE_MODE;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003835 } else {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003836 ivideo->currentvbflags |= VB_DISPTYPE_CRT1;
3837 if(ivideo->currentvbflags & VB_DISPTYPE_CRT2) {
3838 ivideo->currentvbflags |= VB_MIRROR_MODE;
3839 } else {
3840 ivideo->currentvbflags |= VB_SINGLE_MODE;
3841 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003842 }
3843
Aaro Koskinen667a8b42010-12-20 23:50:19 +02003844 SiS_SetRegAND(SISSR, IND_SIS_RAMDAC_CONTROL, ~0x04);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003845
3846 if(ivideo->currentvbflags & CRT2_TV) {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003847 if(ivideo->vbflags2 & VB2_SISBRIDGE) {
Aaro Koskinene57d4132010-12-20 23:50:16 +02003848 ivideo->p2_1f = SiS_GetReg(SISPART2, 0x1f);
3849 ivideo->p2_20 = SiS_GetReg(SISPART2, 0x20);
3850 ivideo->p2_2b = SiS_GetReg(SISPART2, 0x2b);
3851 ivideo->p2_42 = SiS_GetReg(SISPART2, 0x42);
3852 ivideo->p2_43 = SiS_GetReg(SISPART2, 0x43);
3853 ivideo->p2_01 = SiS_GetReg(SISPART2, 0x01);
3854 ivideo->p2_02 = SiS_GetReg(SISPART2, 0x02);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003855 } else if(ivideo->vbflags2 & VB2_CHRONTEL) {
3856 if(ivideo->chronteltype == 1) {
3857 ivideo->tvx = SiS_GetCH700x(&ivideo->SiS_Pr, 0x0a);
3858 ivideo->tvx |= (((SiS_GetCH700x(&ivideo->SiS_Pr, 0x08) & 0x02) >> 1) << 8);
3859 ivideo->tvy = SiS_GetCH700x(&ivideo->SiS_Pr, 0x0b);
3860 ivideo->tvy |= ((SiS_GetCH700x(&ivideo->SiS_Pr, 0x08) & 0x01) << 8);
3861 }
3862 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003863 }
3864
3865 if(ivideo->tvxpos) {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003866 sisfb_set_TVxposoffset(ivideo, ivideo->tvxpos);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003867 }
3868 if(ivideo->tvypos) {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003869 sisfb_set_TVyposoffset(ivideo, ivideo->tvypos);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003870 }
3871
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003872 /* Eventually sync engines */
3873 sisfb_check_engine_and_sync(ivideo);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003874
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003875 /* (Re-)Initialize chip engines */
3876 if(ivideo->accel) {
3877 sisfb_engine_init(ivideo);
3878 } else {
3879 ivideo->engineok = 0;
3880 }
3881}
Linus Torvalds1da177e2005-04-16 15:20:36 -07003882
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003883static int
3884sisfb_reset_mode(struct sis_video_info *ivideo)
3885{
3886 if(sisfb_set_mode(ivideo, 0))
3887 return 1;
3888
3889 sisfb_set_pitch(ivideo);
3890 sisfb_set_base_CRT1(ivideo, ivideo->current_base);
3891 sisfb_set_base_CRT2(ivideo, ivideo->current_base);
3892
3893 return 0;
3894}
3895
3896static void
3897sisfb_handle_command(struct sis_video_info *ivideo, struct sisfb_cmd *sisfb_command)
3898{
3899 int mycrt1off;
3900
3901 switch(sisfb_command->sisfb_cmd) {
3902 case SISFB_CMD_GETVBFLAGS:
3903 if(!ivideo->modechanged) {
3904 sisfb_command->sisfb_result[0] = SISFB_CMD_ERR_EARLY;
3905 } else {
3906 sisfb_command->sisfb_result[0] = SISFB_CMD_ERR_OK;
3907 sisfb_command->sisfb_result[1] = ivideo->currentvbflags;
3908 sisfb_command->sisfb_result[2] = ivideo->vbflags2;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003909 }
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003910 break;
3911 case SISFB_CMD_SWITCHCRT1:
3912 /* arg[0]: 0 = off, 1 = on, 99 = query */
3913 if(!ivideo->modechanged) {
3914 sisfb_command->sisfb_result[0] = SISFB_CMD_ERR_EARLY;
3915 } else if(sisfb_command->sisfb_arg[0] == 99) {
3916 /* Query */
3917 sisfb_command->sisfb_result[1] = ivideo->sisfb_crt1off ? 0 : 1;
3918 sisfb_command->sisfb_result[0] = SISFB_CMD_ERR_OK;
3919 } else if(ivideo->sisfblocked) {
3920 sisfb_command->sisfb_result[0] = SISFB_CMD_ERR_LOCKED;
3921 } else if((!(ivideo->currentvbflags & CRT2_ENABLE)) &&
3922 (sisfb_command->sisfb_arg[0] == 0)) {
3923 sisfb_command->sisfb_result[0] = SISFB_CMD_ERR_NOCRT2;
3924 } else {
3925 sisfb_command->sisfb_result[0] = SISFB_CMD_ERR_OK;
3926 mycrt1off = sisfb_command->sisfb_arg[0] ? 0 : 1;
3927 if( ((ivideo->currentvbflags & VB_DISPTYPE_CRT1) && mycrt1off) ||
3928 ((!(ivideo->currentvbflags & VB_DISPTYPE_CRT1)) && !mycrt1off) ) {
3929 ivideo->sisfb_crt1off = mycrt1off;
3930 if(sisfb_reset_mode(ivideo)) {
3931 sisfb_command->sisfb_result[0] = SISFB_CMD_ERR_OTHER;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003932 }
3933 }
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003934 sisfb_command->sisfb_result[1] = ivideo->sisfb_crt1off ? 0 : 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003935 }
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003936 break;
3937 /* more to come */
3938 default:
3939 sisfb_command->sisfb_result[0] = SISFB_CMD_ERR_UNKNOWN;
3940 printk(KERN_ERR "sisfb: Unknown command 0x%x\n",
3941 sisfb_command->sisfb_cmd);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003942 }
3943}
3944
3945#ifndef MODULE
Adrian Bunk14aefd12008-07-23 21:31:12 -07003946static int __init sisfb_setup(char *options)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003947{
3948 char *this_opt;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003949
Linus Torvalds1da177e2005-04-16 15:20:36 -07003950 sisfb_setdefaultparms();
3951
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003952 if(!options || !(*options))
Linus Torvalds1da177e2005-04-16 15:20:36 -07003953 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003954
3955 while((this_opt = strsep(&options, ",")) != NULL) {
3956
3957 if(!(*this_opt)) continue;
3958
3959 if(!strnicmp(this_opt, "off", 3)) {
3960 sisfb_off = 1;
3961 } else if(!strnicmp(this_opt, "forcecrt2type:", 14)) {
3962 /* Need to check crt2 type first for fstn/dstn */
3963 sisfb_search_crt2type(this_opt + 14);
3964 } else if(!strnicmp(this_opt, "tvmode:",7)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003965 sisfb_search_tvstd(this_opt + 7);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003966 } else if(!strnicmp(this_opt, "tvstandard:",11)) {
3967 sisfb_search_tvstd(this_opt + 11);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003968 } else if(!strnicmp(this_opt, "mode:", 5)) {
Richard Knutssonc30660ea2007-02-12 00:55:06 -08003969 sisfb_search_mode(this_opt + 5, false);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003970 } else if(!strnicmp(this_opt, "vesa:", 5)) {
Richard Knutssonc30660ea2007-02-12 00:55:06 -08003971 sisfb_search_vesamode(simple_strtoul(this_opt + 5, NULL, 0), false);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003972 } else if(!strnicmp(this_opt, "rate:", 5)) {
3973 sisfb_parm_rate = simple_strtoul(this_opt + 5, NULL, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003974 } else if(!strnicmp(this_opt, "forcecrt1:", 10)) {
3975 sisfb_forcecrt1 = (int)simple_strtoul(this_opt + 10, NULL, 0);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003976 } else if(!strnicmp(this_opt, "mem:",4)) {
3977 sisfb_parm_mem = simple_strtoul(this_opt + 4, NULL, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003978 } else if(!strnicmp(this_opt, "pdc:", 4)) {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003979 sisfb_pdc = simple_strtoul(this_opt + 4, NULL, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003980 } else if(!strnicmp(this_opt, "pdc1:", 5)) {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003981 sisfb_pdca = simple_strtoul(this_opt + 5, NULL, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003982 } else if(!strnicmp(this_opt, "noaccel", 7)) {
3983 sisfb_accel = 0;
3984 } else if(!strnicmp(this_opt, "accel", 5)) {
3985 sisfb_accel = -1;
3986 } else if(!strnicmp(this_opt, "noypan", 6)) {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003987 sisfb_ypan = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003988 } else if(!strnicmp(this_opt, "ypan", 4)) {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003989 sisfb_ypan = -1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003990 } else if(!strnicmp(this_opt, "nomax", 5)) {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003991 sisfb_max = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003992 } else if(!strnicmp(this_opt, "max", 3)) {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07003993 sisfb_max = -1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003994 } else if(!strnicmp(this_opt, "userom:", 7)) {
3995 sisfb_userom = (int)simple_strtoul(this_opt + 7, NULL, 0);
3996 } else if(!strnicmp(this_opt, "useoem:", 7)) {
3997 sisfb_useoem = (int)simple_strtoul(this_opt + 7, NULL, 0);
3998 } else if(!strnicmp(this_opt, "nocrt2rate", 10)) {
3999 sisfb_nocrt2rate = 1;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004000 } else if(!strnicmp(this_opt, "scalelcd:", 9)) {
4001 unsigned long temp = 2;
4002 temp = simple_strtoul(this_opt + 9, NULL, 0);
4003 if((temp == 0) || (temp == 1)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004004 sisfb_scalelcd = temp ^ 1;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004005 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004006 } else if(!strnicmp(this_opt, "tvxposoffset:", 13)) {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004007 int temp = 0;
4008 temp = (int)simple_strtol(this_opt + 13, NULL, 0);
4009 if((temp >= -32) && (temp <= 32)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004010 sisfb_tvxposoffset = temp;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004011 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004012 } else if(!strnicmp(this_opt, "tvyposoffset:", 13)) {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004013 int temp = 0;
4014 temp = (int)simple_strtol(this_opt + 13, NULL, 0);
4015 if((temp >= -32) && (temp <= 32)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004016 sisfb_tvyposoffset = temp;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004017 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004018 } else if(!strnicmp(this_opt, "specialtiming:", 14)) {
4019 sisfb_search_specialtiming(this_opt + 14);
4020 } else if(!strnicmp(this_opt, "lvdshl:", 7)) {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004021 int temp = 4;
4022 temp = simple_strtoul(this_opt + 7, NULL, 0);
4023 if((temp >= 0) && (temp <= 3)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004024 sisfb_lvdshl = temp;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004025 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004026 } else if(this_opt[0] >= '0' && this_opt[0] <= '9') {
Richard Knutssonc30660ea2007-02-12 00:55:06 -08004027 sisfb_search_mode(this_opt, true);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004028#if !defined(__i386__) && !defined(__x86_64__)
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004029 } else if(!strnicmp(this_opt, "resetcard", 9)) {
4030 sisfb_resetcard = 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004031 } else if(!strnicmp(this_opt, "videoram:", 9)) {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004032 sisfb_videoram = simple_strtoul(this_opt + 9, NULL, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004033#endif
4034 } else {
4035 printk(KERN_INFO "sisfb: Invalid option %s\n", this_opt);
4036 }
4037
4038 }
4039
Linus Torvalds1da177e2005-04-16 15:20:36 -07004040 return 0;
4041}
4042#endif
4043
Greg Kroah-Hartman48c68c42012-12-21 13:07:39 -08004044static int sisfb_check_rom(void __iomem *rom_base,
4045 struct sis_video_info *ivideo)
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004046{
Adrian Bunk14aefd12008-07-23 21:31:12 -07004047 void __iomem *rom;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004048 int romptr;
4049
4050 if((readb(rom_base) != 0x55) || (readb(rom_base + 1) != 0xaa))
4051 return 0;
4052
4053 romptr = (readb(rom_base + 0x18) | (readb(rom_base + 0x19) << 8));
4054 if(romptr > (0x10000 - 8))
4055 return 0;
4056
4057 rom = rom_base + romptr;
4058
4059 if((readb(rom) != 'P') || (readb(rom + 1) != 'C') ||
4060 (readb(rom + 2) != 'I') || (readb(rom + 3) != 'R'))
4061 return 0;
4062
4063 if((readb(rom + 4) | (readb(rom + 5) << 8)) != ivideo->chip_vendor)
4064 return 0;
4065
4066 if((readb(rom + 6) | (readb(rom + 7) << 8)) != ivideo->chip_id)
4067 return 0;
4068
4069 return 1;
4070}
4071
Greg Kroah-Hartman48c68c42012-12-21 13:07:39 -08004072static unsigned char *sisfb_find_rom(struct pci_dev *pdev)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004073{
4074 struct sis_video_info *ivideo = pci_get_drvdata(pdev);
Adrian Bunk14aefd12008-07-23 21:31:12 -07004075 void __iomem *rom_base;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004076 unsigned char *myrombase = NULL;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004077 size_t romsize;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004078
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004079 /* First, try the official pci ROM functions (except
4080 * on integrated chipsets which have no ROM).
4081 */
4082
4083 if(!ivideo->nbridge) {
4084
4085 if((rom_base = pci_map_rom(pdev, &romsize))) {
4086
4087 if(sisfb_check_rom(rom_base, ivideo)) {
4088
4089 if((myrombase = vmalloc(65536))) {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004090 memcpy_fromio(myrombase, rom_base,
4091 (romsize > 65536) ? 65536 : romsize);
4092 }
4093 }
4094 pci_unmap_rom(pdev, rom_base);
4095 }
4096 }
4097
4098 if(myrombase) return myrombase;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004099
4100 /* Otherwise do it the conventional way. */
Linus Torvalds1da177e2005-04-16 15:20:36 -07004101
4102#if defined(__i386__) || defined(__x86_64__)
Aaro Koskinen679c4892010-12-20 23:50:10 +02004103 {
4104 u32 temp;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004105
Aaro Koskinen679c4892010-12-20 23:50:10 +02004106 for (temp = 0x000c0000; temp < 0x000f0000; temp += 0x00001000) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004107
Aaro Koskinen679c4892010-12-20 23:50:10 +02004108 rom_base = ioremap(temp, 65536);
4109 if (!rom_base)
4110 continue;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004111
Aaro Koskinen679c4892010-12-20 23:50:10 +02004112 if (!sisfb_check_rom(rom_base, ivideo)) {
4113 iounmap(rom_base);
4114 continue;
4115 }
4116
4117 if ((myrombase = vmalloc(65536)))
4118 memcpy_fromio(myrombase, rom_base, 65536);
4119
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004120 iounmap(rom_base);
Aaro Koskinen679c4892010-12-20 23:50:10 +02004121 break;
4122
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004123 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004124
Aaro Koskinen679c4892010-12-20 23:50:10 +02004125 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004126#endif
4127
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004128 return myrombase;
4129}
4130
Greg Kroah-Hartman48c68c42012-12-21 13:07:39 -08004131static void sisfb_post_map_vram(struct sis_video_info *ivideo,
4132 unsigned int *mapsize, unsigned int min)
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004133{
Aaro Koskinen32ed3032010-11-10 13:04:19 +02004134 if (*mapsize < (min << 20))
4135 return;
4136
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004137 ivideo->video_vbase = ioremap(ivideo->video_base, (*mapsize));
4138
4139 if(!ivideo->video_vbase) {
4140 printk(KERN_ERR
4141 "sisfb: Unable to map maximum video RAM for size detection\n");
4142 (*mapsize) >>= 1;
4143 while((!(ivideo->video_vbase = ioremap(ivideo->video_base, (*mapsize))))) {
4144 (*mapsize) >>= 1;
4145 if((*mapsize) < (min << 20))
4146 break;
4147 }
4148 if(ivideo->video_vbase) {
4149 printk(KERN_ERR
4150 "sisfb: Video RAM size detection limited to %dMB\n",
4151 (int)((*mapsize) >> 20));
4152 }
4153 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004154}
4155
4156#ifdef CONFIG_FB_SIS_300
Greg Kroah-Hartman48c68c42012-12-21 13:07:39 -08004157static int sisfb_post_300_buswidth(struct sis_video_info *ivideo)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004158{
Adrian Bunk14aefd12008-07-23 21:31:12 -07004159 void __iomem *FBAddress = ivideo->video_vbase;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004160 unsigned short temp;
4161 unsigned char reg;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004162 int i, j;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004163
Aaro Koskinen667a8b42010-12-20 23:50:19 +02004164 SiS_SetRegAND(SISSR, 0x15, 0xFB);
Aaro Koskinen27799d62010-12-20 23:50:18 +02004165 SiS_SetRegOR(SISSR, 0x15, 0x04);
Aaro Koskinen44b751b2010-12-20 23:50:17 +02004166 SiS_SetReg(SISSR, 0x13, 0x00);
4167 SiS_SetReg(SISSR, 0x14, 0xBF);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004168
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004169 for(i = 0; i < 2; i++) {
4170 temp = 0x1234;
4171 for(j = 0; j < 4; j++) {
4172 writew(temp, FBAddress);
4173 if(readw(FBAddress) == temp)
4174 break;
Aaro Koskinen27799d62010-12-20 23:50:18 +02004175 SiS_SetRegOR(SISSR, 0x3c, 0x01);
Aaro Koskinene57d4132010-12-20 23:50:16 +02004176 reg = SiS_GetReg(SISSR, 0x05);
4177 reg = SiS_GetReg(SISSR, 0x05);
Aaro Koskinen667a8b42010-12-20 23:50:19 +02004178 SiS_SetRegAND(SISSR, 0x3c, 0xfe);
Aaro Koskinene57d4132010-12-20 23:50:16 +02004179 reg = SiS_GetReg(SISSR, 0x05);
4180 reg = SiS_GetReg(SISSR, 0x05);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004181 temp++;
4182 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004183 }
4184
4185 writel(0x01234567L, FBAddress);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004186 writel(0x456789ABL, (FBAddress + 4));
4187 writel(0x89ABCDEFL, (FBAddress + 8));
4188 writel(0xCDEF0123L, (FBAddress + 12));
4189
Aaro Koskinene57d4132010-12-20 23:50:16 +02004190 reg = SiS_GetReg(SISSR, 0x3b);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004191 if(reg & 0x01) {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004192 if(readl((FBAddress + 12)) == 0xCDEF0123L)
4193 return 4; /* Channel A 128bit */
Linus Torvalds1da177e2005-04-16 15:20:36 -07004194 }
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004195
4196 if(readl((FBAddress + 4)) == 0x456789ABL)
4197 return 2; /* Channel B 64bit */
4198
4199 return 1; /* 32bit */
4200}
4201
Greg Kroah-Hartman48c68c42012-12-21 13:07:39 -08004202static const unsigned short SiS_DRAMType[17][5] = {
Peter Huewec1f58f12012-05-04 00:14:55 +02004203 {0x0C,0x0A,0x02,0x40,0x39},
4204 {0x0D,0x0A,0x01,0x40,0x48},
4205 {0x0C,0x09,0x02,0x20,0x35},
4206 {0x0D,0x09,0x01,0x20,0x44},
4207 {0x0C,0x08,0x02,0x10,0x31},
4208 {0x0D,0x08,0x01,0x10,0x40},
4209 {0x0C,0x0A,0x01,0x20,0x34},
4210 {0x0C,0x09,0x01,0x08,0x32},
4211 {0x0B,0x08,0x02,0x08,0x21},
4212 {0x0C,0x08,0x01,0x08,0x30},
4213 {0x0A,0x08,0x02,0x04,0x11},
4214 {0x0B,0x0A,0x01,0x10,0x28},
4215 {0x09,0x08,0x02,0x02,0x01},
4216 {0x0B,0x09,0x01,0x08,0x24},
4217 {0x0B,0x08,0x01,0x04,0x20},
4218 {0x0A,0x08,0x01,0x02,0x10},
4219 {0x09,0x08,0x01,0x01,0x00}
4220};
4221
Greg Kroah-Hartman48c68c42012-12-21 13:07:39 -08004222static int sisfb_post_300_rwtest(struct sis_video_info *ivideo, int iteration,
4223 int buswidth, int PseudoRankCapacity,
4224 int PseudoAdrPinCount, unsigned int mapsize)
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004225{
Adrian Bunk14aefd12008-07-23 21:31:12 -07004226 void __iomem *FBAddr = ivideo->video_vbase;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004227 unsigned short sr14;
4228 unsigned int k, RankCapacity, PageCapacity, BankNumHigh, BankNumMid;
4229 unsigned int PhysicalAdrOtherPage, PhysicalAdrHigh, PhysicalAdrHalfPage;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004230
Peter Huewec1f58f12012-05-04 00:14:55 +02004231 for(k = 0; k < ARRAY_SIZE(SiS_DRAMType); k++) {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004232
4233 RankCapacity = buswidth * SiS_DRAMType[k][3];
4234
4235 if(RankCapacity != PseudoRankCapacity)
4236 continue;
4237
4238 if((SiS_DRAMType[k][2] + SiS_DRAMType[k][0]) > PseudoAdrPinCount)
4239 continue;
4240
4241 BankNumHigh = RankCapacity * 16 * iteration - 1;
4242 if(iteration == 3) { /* Rank No */
4243 BankNumMid = RankCapacity * 16 - 1;
4244 } else {
4245 BankNumMid = RankCapacity * 16 * iteration / 2 - 1;
4246 }
4247
4248 PageCapacity = (1 << SiS_DRAMType[k][1]) * buswidth * 4;
4249 PhysicalAdrHigh = BankNumHigh;
4250 PhysicalAdrHalfPage = (PageCapacity / 2 + PhysicalAdrHigh) % PageCapacity;
4251 PhysicalAdrOtherPage = PageCapacity * SiS_DRAMType[k][2] + PhysicalAdrHigh;
4252
Aaro Koskinen667a8b42010-12-20 23:50:19 +02004253 SiS_SetRegAND(SISSR, 0x15, 0xFB); /* Test */
Aaro Koskinen27799d62010-12-20 23:50:18 +02004254 SiS_SetRegOR(SISSR, 0x15, 0x04); /* Test */
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004255 sr14 = (SiS_DRAMType[k][3] * buswidth) - 1;
4256 if(buswidth == 4) sr14 |= 0x80;
4257 else if(buswidth == 2) sr14 |= 0x40;
Aaro Koskinen44b751b2010-12-20 23:50:17 +02004258 SiS_SetReg(SISSR, 0x13, SiS_DRAMType[k][4]);
4259 SiS_SetReg(SISSR, 0x14, sr14);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004260
4261 BankNumHigh <<= 16;
4262 BankNumMid <<= 16;
4263
4264 if((BankNumHigh + PhysicalAdrHigh >= mapsize) ||
4265 (BankNumMid + PhysicalAdrHigh >= mapsize) ||
4266 (BankNumHigh + PhysicalAdrHalfPage >= mapsize) ||
4267 (BankNumHigh + PhysicalAdrOtherPage >= mapsize))
4268 continue;
4269
4270 /* Write data */
4271 writew(((unsigned short)PhysicalAdrHigh),
4272 (FBAddr + BankNumHigh + PhysicalAdrHigh));
4273 writew(((unsigned short)BankNumMid),
4274 (FBAddr + BankNumMid + PhysicalAdrHigh));
4275 writew(((unsigned short)PhysicalAdrHalfPage),
4276 (FBAddr + BankNumHigh + PhysicalAdrHalfPage));
4277 writew(((unsigned short)PhysicalAdrOtherPage),
4278 (FBAddr + BankNumHigh + PhysicalAdrOtherPage));
4279
4280 /* Read data */
4281 if(readw(FBAddr + BankNumHigh + PhysicalAdrHigh) == PhysicalAdrHigh)
4282 return 1;
4283 }
4284
4285 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004286}
4287
Greg Kroah-Hartman48c68c42012-12-21 13:07:39 -08004288static void sisfb_post_300_ramsize(struct pci_dev *pdev, unsigned int mapsize)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004289{
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004290 struct sis_video_info *ivideo = pci_get_drvdata(pdev);
4291 int i, j, buswidth;
4292 int PseudoRankCapacity, PseudoAdrPinCount;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004293
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004294 buswidth = sisfb_post_300_buswidth(ivideo);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004295
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004296 for(i = 6; i >= 0; i--) {
4297 PseudoRankCapacity = 1 << i;
4298 for(j = 4; j >= 1; j--) {
4299 PseudoAdrPinCount = 15 - j;
4300 if((PseudoRankCapacity * j) <= 64) {
4301 if(sisfb_post_300_rwtest(ivideo,
4302 j,
4303 buswidth,
4304 PseudoRankCapacity,
4305 PseudoAdrPinCount,
4306 mapsize))
4307 return;
4308 }
4309 }
4310 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004311}
4312
Greg Kroah-Hartman48c68c42012-12-21 13:07:39 -08004313static void sisfb_post_sis300(struct pci_dev *pdev)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004314{
4315 struct sis_video_info *ivideo = pci_get_drvdata(pdev);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004316 unsigned char *bios = ivideo->SiS_Pr.VirtualRomBase;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004317 u8 reg, v1, v2, v3, v4, v5, v6, v7, v8;
4318 u16 index, rindex, memtype = 0;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004319 unsigned int mapsize;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004320
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004321 if(!ivideo->SiS_Pr.UseROM)
4322 bios = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004323
Aaro Koskinen44b751b2010-12-20 23:50:17 +02004324 SiS_SetReg(SISSR, 0x05, 0x86);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004325
4326 if(bios) {
4327 if(bios[0x52] & 0x80) {
4328 memtype = bios[0x52];
4329 } else {
Aaro Koskinene57d4132010-12-20 23:50:16 +02004330 memtype = SiS_GetReg(SISSR, 0x3a);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004331 }
4332 memtype &= 0x07;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004333 }
4334
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004335 v3 = 0x80; v6 = 0x80;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004336 if(ivideo->revision_id <= 0x13) {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004337 v1 = 0x44; v2 = 0x42;
4338 v4 = 0x44; v5 = 0x42;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004339 } else {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004340 v1 = 0x68; v2 = 0x43; /* Assume 125Mhz MCLK */
4341 v4 = 0x68; v5 = 0x43; /* Assume 125Mhz ECLK */
4342 if(bios) {
4343 index = memtype * 5;
4344 rindex = index + 0x54;
4345 v1 = bios[rindex++];
4346 v2 = bios[rindex++];
4347 v3 = bios[rindex++];
4348 rindex = index + 0x7c;
4349 v4 = bios[rindex++];
4350 v5 = bios[rindex++];
4351 v6 = bios[rindex++];
4352 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004353 }
Aaro Koskinen44b751b2010-12-20 23:50:17 +02004354 SiS_SetReg(SISSR, 0x28, v1);
4355 SiS_SetReg(SISSR, 0x29, v2);
4356 SiS_SetReg(SISSR, 0x2a, v3);
4357 SiS_SetReg(SISSR, 0x2e, v4);
4358 SiS_SetReg(SISSR, 0x2f, v5);
4359 SiS_SetReg(SISSR, 0x30, v6);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004360
Linus Torvalds1da177e2005-04-16 15:20:36 -07004361 v1 = 0x10;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004362 if(bios)
4363 v1 = bios[0xa4];
Aaro Koskinen44b751b2010-12-20 23:50:17 +02004364 SiS_SetReg(SISSR, 0x07, v1); /* DAC speed */
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004365
Aaro Koskinen44b751b2010-12-20 23:50:17 +02004366 SiS_SetReg(SISSR, 0x11, 0x0f); /* DDC, power save */
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004367
Linus Torvalds1da177e2005-04-16 15:20:36 -07004368 v1 = 0x01; v2 = 0x43; v3 = 0x1e; v4 = 0x2a;
4369 v5 = 0x06; v6 = 0x00; v7 = 0x00; v8 = 0x00;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004370 if(bios) {
4371 memtype += 0xa5;
4372 v1 = bios[memtype];
4373 v2 = bios[memtype + 8];
4374 v3 = bios[memtype + 16];
4375 v4 = bios[memtype + 24];
4376 v5 = bios[memtype + 32];
4377 v6 = bios[memtype + 40];
4378 v7 = bios[memtype + 48];
4379 v8 = bios[memtype + 56];
Linus Torvalds1da177e2005-04-16 15:20:36 -07004380 }
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004381 if(ivideo->revision_id >= 0x80)
4382 v3 &= 0xfd;
Aaro Koskinen44b751b2010-12-20 23:50:17 +02004383 SiS_SetReg(SISSR, 0x15, v1); /* Ram type (assuming 0, BIOS 0xa5 step 8) */
4384 SiS_SetReg(SISSR, 0x16, v2);
4385 SiS_SetReg(SISSR, 0x17, v3);
4386 SiS_SetReg(SISSR, 0x18, v4);
4387 SiS_SetReg(SISSR, 0x19, v5);
4388 SiS_SetReg(SISSR, 0x1a, v6);
4389 SiS_SetReg(SISSR, 0x1b, v7);
4390 SiS_SetReg(SISSR, 0x1c, v8); /* ---- */
Aaro Koskinen667a8b42010-12-20 23:50:19 +02004391 SiS_SetRegAND(SISSR, 0x15, 0xfb);
Aaro Koskinen27799d62010-12-20 23:50:18 +02004392 SiS_SetRegOR(SISSR, 0x15, 0x04);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004393 if(bios) {
4394 if(bios[0x53] & 0x02) {
Aaro Koskinen27799d62010-12-20 23:50:18 +02004395 SiS_SetRegOR(SISSR, 0x19, 0x20);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004396 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004397 }
4398 v1 = 0x04; /* DAC pedestal (BIOS 0xe5) */
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004399 if(ivideo->revision_id >= 0x80)
4400 v1 |= 0x01;
Aaro Koskinen44b751b2010-12-20 23:50:17 +02004401 SiS_SetReg(SISSR, 0x1f, v1);
4402 SiS_SetReg(SISSR, 0x20, 0xa4); /* linear & relocated io & disable a0000 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07004403 v1 = 0xf6; v2 = 0x0d; v3 = 0x00;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004404 if(bios) {
4405 v1 = bios[0xe8];
4406 v2 = bios[0xe9];
4407 v3 = bios[0xea];
Linus Torvalds1da177e2005-04-16 15:20:36 -07004408 }
Aaro Koskinen44b751b2010-12-20 23:50:17 +02004409 SiS_SetReg(SISSR, 0x23, v1);
4410 SiS_SetReg(SISSR, 0x24, v2);
4411 SiS_SetReg(SISSR, 0x25, v3);
4412 SiS_SetReg(SISSR, 0x21, 0x84);
4413 SiS_SetReg(SISSR, 0x22, 0x00);
4414 SiS_SetReg(SISCR, 0x37, 0x00);
Aaro Koskinen27799d62010-12-20 23:50:18 +02004415 SiS_SetRegOR(SISPART1, 0x24, 0x01); /* unlock crt2 */
Aaro Koskinen44b751b2010-12-20 23:50:17 +02004416 SiS_SetReg(SISPART1, 0x00, 0x00);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004417 v1 = 0x40; v2 = 0x11;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004418 if(bios) {
4419 v1 = bios[0xec];
4420 v2 = bios[0xeb];
Linus Torvalds1da177e2005-04-16 15:20:36 -07004421 }
Aaro Koskinen44b751b2010-12-20 23:50:17 +02004422 SiS_SetReg(SISPART1, 0x02, v1);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004423
4424 if(ivideo->revision_id >= 0x80)
4425 v2 &= ~0x01;
4426
Aaro Koskinene57d4132010-12-20 23:50:16 +02004427 reg = SiS_GetReg(SISPART4, 0x00);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004428 if((reg == 1) || (reg == 2)) {
Aaro Koskinen44b751b2010-12-20 23:50:17 +02004429 SiS_SetReg(SISCR, 0x37, 0x02);
4430 SiS_SetReg(SISPART2, 0x00, 0x1c);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004431 v4 = 0x00; v5 = 0x00; v6 = 0x10;
4432 if(ivideo->SiS_Pr.UseROM) {
4433 v4 = bios[0xf5];
4434 v5 = bios[0xf6];
4435 v6 = bios[0xf7];
4436 }
Aaro Koskinen44b751b2010-12-20 23:50:17 +02004437 SiS_SetReg(SISPART4, 0x0d, v4);
4438 SiS_SetReg(SISPART4, 0x0e, v5);
4439 SiS_SetReg(SISPART4, 0x10, v6);
4440 SiS_SetReg(SISPART4, 0x0f, 0x3f);
Aaro Koskinene57d4132010-12-20 23:50:16 +02004441 reg = SiS_GetReg(SISPART4, 0x01);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004442 if(reg >= 0xb0) {
Aaro Koskinene57d4132010-12-20 23:50:16 +02004443 reg = SiS_GetReg(SISPART4, 0x23);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004444 reg &= 0x20;
4445 reg <<= 1;
Aaro Koskinen44b751b2010-12-20 23:50:17 +02004446 SiS_SetReg(SISPART4, 0x23, reg);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004447 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004448 } else {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004449 v2 &= ~0x10;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004450 }
Aaro Koskinen44b751b2010-12-20 23:50:17 +02004451 SiS_SetReg(SISSR, 0x32, v2);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004452
Aaro Koskinen667a8b42010-12-20 23:50:19 +02004453 SiS_SetRegAND(SISPART1, 0x24, 0xfe); /* Lock CRT2 */
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004454
Aaro Koskinene57d4132010-12-20 23:50:16 +02004455 reg = SiS_GetReg(SISSR, 0x16);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004456 reg &= 0xc3;
Aaro Koskinen44b751b2010-12-20 23:50:17 +02004457 SiS_SetReg(SISCR, 0x35, reg);
4458 SiS_SetReg(SISCR, 0x83, 0x00);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004459#if !defined(__i386__) && !defined(__x86_64__)
4460 if(sisfb_videoram) {
Aaro Koskinen44b751b2010-12-20 23:50:17 +02004461 SiS_SetReg(SISSR, 0x13, 0x28); /* ? */
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004462 reg = ((sisfb_videoram >> 10) - 1) | 0x40;
Aaro Koskinen44b751b2010-12-20 23:50:17 +02004463 SiS_SetReg(SISSR, 0x14, reg);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004464 } else {
4465#endif
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004466 /* Need to map max FB size for finding out about RAM size */
Aaro Koskinen32ed3032010-11-10 13:04:19 +02004467 mapsize = ivideo->video_size;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004468 sisfb_post_map_vram(ivideo, &mapsize, 4);
4469
4470 if(ivideo->video_vbase) {
4471 sisfb_post_300_ramsize(pdev, mapsize);
4472 iounmap(ivideo->video_vbase);
4473 } else {
4474 printk(KERN_DEBUG
4475 "sisfb: Failed to map memory for size detection, assuming 8MB\n");
Aaro Koskinen44b751b2010-12-20 23:50:17 +02004476 SiS_SetReg(SISSR, 0x13, 0x28); /* ? */
4477 SiS_SetReg(SISSR, 0x14, 0x47); /* 8MB, 64bit default */
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004478 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004479#if !defined(__i386__) && !defined(__x86_64__)
4480 }
4481#endif
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004482 if(bios) {
4483 v1 = bios[0xe6];
4484 v2 = bios[0xe7];
Linus Torvalds1da177e2005-04-16 15:20:36 -07004485 } else {
Aaro Koskinene57d4132010-12-20 23:50:16 +02004486 reg = SiS_GetReg(SISSR, 0x3a);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004487 if((reg & 0x30) == 0x30) {
4488 v1 = 0x04; /* PCI */
4489 v2 = 0x92;
4490 } else {
4491 v1 = 0x14; /* AGP */
4492 v2 = 0xb2;
4493 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004494 }
Aaro Koskinen44b751b2010-12-20 23:50:17 +02004495 SiS_SetReg(SISSR, 0x21, v1);
4496 SiS_SetReg(SISSR, 0x22, v2);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004497
4498 /* Sense CRT1 */
4499 sisfb_sense_crt1(ivideo);
4500
4501 /* Set default mode, don't clear screen */
Richard Knutssonc30660ea2007-02-12 00:55:06 -08004502 ivideo->SiS_Pr.SiS_UseOEM = false;
4503 SiS_SetEnableDstn(&ivideo->SiS_Pr, false);
4504 SiS_SetEnableFstn(&ivideo->SiS_Pr, false);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004505 ivideo->curFSTN = ivideo->curDSTN = 0;
4506 ivideo->SiS_Pr.VideoMemorySize = 8 << 20;
4507 SiSSetMode(&ivideo->SiS_Pr, 0x2e | 0x80);
4508
Aaro Koskinen44b751b2010-12-20 23:50:17 +02004509 SiS_SetReg(SISSR, 0x05, 0x86);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004510
4511 /* Display off */
Aaro Koskinen27799d62010-12-20 23:50:18 +02004512 SiS_SetRegOR(SISSR, 0x01, 0x20);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004513
4514 /* Save mode number in CR34 */
Aaro Koskinen44b751b2010-12-20 23:50:17 +02004515 SiS_SetReg(SISCR, 0x34, 0x2e);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004516
4517 /* Let everyone know what the current mode is */
4518 ivideo->modeprechange = 0x2e;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004519}
4520#endif
4521
4522#ifdef CONFIG_FB_SIS_315
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004523#if 0
Greg Kroah-Hartman48c68c42012-12-21 13:07:39 -08004524static void sisfb_post_sis315330(struct pci_dev *pdev)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004525{
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004526 /* TODO */
Linus Torvalds1da177e2005-04-16 15:20:36 -07004527}
4528#endif
4529
Aaro Koskinen929c9722011-02-13 22:11:25 +00004530static inline int sisfb_xgi_is21(struct sis_video_info *ivideo)
4531{
4532 return ivideo->chip_real_id == XGI_21;
4533}
4534
Greg Kroah-Hartman48c68c42012-12-21 13:07:39 -08004535static void sisfb_post_xgi_delay(struct sis_video_info *ivideo, int delay)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004536{
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004537 unsigned int i;
4538 u8 reg;
4539
4540 for(i = 0; i <= (delay * 10 * 36); i++) {
Aaro Koskinene57d4132010-12-20 23:50:16 +02004541 reg = SiS_GetReg(SISSR, 0x05);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004542 reg++;
4543 }
4544}
4545
Greg Kroah-Hartman48c68c42012-12-21 13:07:39 -08004546static int sisfb_find_host_bridge(struct sis_video_info *ivideo,
4547 struct pci_dev *mypdev,
4548 unsigned short pcivendor)
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004549{
4550 struct pci_dev *pdev = NULL;
4551 unsigned short temp;
4552 int ret = 0;
4553
Adrian Bunk0959f0c2007-05-08 00:39:50 -07004554 while((pdev = pci_get_class(PCI_CLASS_BRIDGE_HOST, pdev))) {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004555 temp = pdev->vendor;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004556 if(temp == pcivendor) {
4557 ret = 1;
Julia Lawallea237a62008-02-06 01:39:07 -08004558 pci_dev_put(pdev);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004559 break;
4560 }
4561 }
4562
4563 return ret;
4564}
4565
Greg Kroah-Hartman48c68c42012-12-21 13:07:39 -08004566static int sisfb_post_xgi_rwtest(struct sis_video_info *ivideo, int starta,
4567 unsigned int enda, unsigned int mapsize)
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004568{
4569 unsigned int pos;
4570 int i;
4571
4572 writel(0, ivideo->video_vbase);
4573
4574 for(i = starta; i <= enda; i++) {
4575 pos = 1 << i;
4576 if(pos < mapsize)
4577 writel(pos, ivideo->video_vbase + pos);
4578 }
4579
4580 sisfb_post_xgi_delay(ivideo, 150);
4581
4582 if(readl(ivideo->video_vbase) != 0)
4583 return 0;
4584
4585 for(i = starta; i <= enda; i++) {
4586 pos = 1 << i;
4587 if(pos < mapsize) {
4588 if(readl(ivideo->video_vbase + pos) != pos)
4589 return 0;
4590 } else
4591 return 0;
4592 }
4593
4594 return 1;
4595}
4596
Greg Kroah-Hartman48c68c42012-12-21 13:07:39 -08004597static int sisfb_post_xgi_ramsize(struct sis_video_info *ivideo)
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004598{
4599 unsigned int buswidth, ranksize, channelab, mapsize;
Aaro Koskinen83ea0f12011-02-13 22:11:23 +00004600 int i, j, k, l, status;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004601 u8 reg, sr14;
4602 static const u8 dramsr13[12 * 5] = {
4603 0x02, 0x0e, 0x0b, 0x80, 0x5d,
4604 0x02, 0x0e, 0x0a, 0x40, 0x59,
4605 0x02, 0x0d, 0x0b, 0x40, 0x4d,
4606 0x02, 0x0e, 0x09, 0x20, 0x55,
4607 0x02, 0x0d, 0x0a, 0x20, 0x49,
4608 0x02, 0x0c, 0x0b, 0x20, 0x3d,
4609 0x02, 0x0e, 0x08, 0x10, 0x51,
4610 0x02, 0x0d, 0x09, 0x10, 0x45,
4611 0x02, 0x0c, 0x0a, 0x10, 0x39,
4612 0x02, 0x0d, 0x08, 0x08, 0x41,
4613 0x02, 0x0c, 0x09, 0x08, 0x35,
4614 0x02, 0x0c, 0x08, 0x04, 0x31
4615 };
4616 static const u8 dramsr13_4[4 * 5] = {
4617 0x02, 0x0d, 0x09, 0x40, 0x45,
4618 0x02, 0x0c, 0x09, 0x20, 0x35,
4619 0x02, 0x0c, 0x08, 0x10, 0x31,
4620 0x02, 0x0b, 0x08, 0x08, 0x21
4621 };
4622
4623 /* Enable linear mode, disable 0xa0000 address decoding */
4624 /* We disable a0000 address decoding, because
4625 * - if running on x86, if the card is disabled, it means
4626 * that another card is in the system. We don't want
4627 * to interphere with that primary card's textmode.
4628 * - if running on non-x86, there usually is no VGA window
4629 * at a0000.
4630 */
Aaro Koskinen27799d62010-12-20 23:50:18 +02004631 SiS_SetRegOR(SISSR, 0x20, (0x80 | 0x04));
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004632
4633 /* Need to map max FB size for finding out about RAM size */
Aaro Koskinen32ed3032010-11-10 13:04:19 +02004634 mapsize = ivideo->video_size;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004635 sisfb_post_map_vram(ivideo, &mapsize, 32);
4636
4637 if(!ivideo->video_vbase) {
4638 printk(KERN_ERR "sisfb: Unable to detect RAM size. Setting default.\n");
Aaro Koskinen44b751b2010-12-20 23:50:17 +02004639 SiS_SetReg(SISSR, 0x13, 0x35);
4640 SiS_SetReg(SISSR, 0x14, 0x41);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004641 /* TODO */
Aaro Koskinen83ea0f12011-02-13 22:11:23 +00004642 return -ENOMEM;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004643 }
4644
4645 /* Non-interleaving */
Aaro Koskinen44b751b2010-12-20 23:50:17 +02004646 SiS_SetReg(SISSR, 0x15, 0x00);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004647 /* No tiling */
Aaro Koskinen44b751b2010-12-20 23:50:17 +02004648 SiS_SetReg(SISSR, 0x1c, 0x00);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004649
4650 if(ivideo->chip == XGI_20) {
4651
4652 channelab = 1;
Aaro Koskinene57d4132010-12-20 23:50:16 +02004653 reg = SiS_GetReg(SISCR, 0x97);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004654 if(!(reg & 0x01)) { /* Single 32/16 */
4655 buswidth = 32;
Aaro Koskinen44b751b2010-12-20 23:50:17 +02004656 SiS_SetReg(SISSR, 0x13, 0xb1);
4657 SiS_SetReg(SISSR, 0x14, 0x52);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004658 sisfb_post_xgi_delay(ivideo, 1);
4659 sr14 = 0x02;
4660 if(sisfb_post_xgi_rwtest(ivideo, 23, 24, mapsize))
4661 goto bail_out;
4662
Aaro Koskinen44b751b2010-12-20 23:50:17 +02004663 SiS_SetReg(SISSR, 0x13, 0x31);
4664 SiS_SetReg(SISSR, 0x14, 0x42);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004665 sisfb_post_xgi_delay(ivideo, 1);
4666 if(sisfb_post_xgi_rwtest(ivideo, 23, 23, mapsize))
4667 goto bail_out;
4668
4669 buswidth = 16;
Aaro Koskinen44b751b2010-12-20 23:50:17 +02004670 SiS_SetReg(SISSR, 0x13, 0xb1);
4671 SiS_SetReg(SISSR, 0x14, 0x41);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004672 sisfb_post_xgi_delay(ivideo, 1);
4673 sr14 = 0x01;
4674 if(sisfb_post_xgi_rwtest(ivideo, 22, 23, mapsize))
4675 goto bail_out;
4676 else
Aaro Koskinen44b751b2010-12-20 23:50:17 +02004677 SiS_SetReg(SISSR, 0x13, 0x31);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004678 } else { /* Dual 16/8 */
4679 buswidth = 16;
Aaro Koskinen44b751b2010-12-20 23:50:17 +02004680 SiS_SetReg(SISSR, 0x13, 0xb1);
4681 SiS_SetReg(SISSR, 0x14, 0x41);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004682 sisfb_post_xgi_delay(ivideo, 1);
4683 sr14 = 0x01;
4684 if(sisfb_post_xgi_rwtest(ivideo, 22, 23, mapsize))
4685 goto bail_out;
4686
Aaro Koskinen44b751b2010-12-20 23:50:17 +02004687 SiS_SetReg(SISSR, 0x13, 0x31);
4688 SiS_SetReg(SISSR, 0x14, 0x31);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004689 sisfb_post_xgi_delay(ivideo, 1);
4690 if(sisfb_post_xgi_rwtest(ivideo, 22, 22, mapsize))
4691 goto bail_out;
4692
4693 buswidth = 8;
Aaro Koskinen44b751b2010-12-20 23:50:17 +02004694 SiS_SetReg(SISSR, 0x13, 0xb1);
4695 SiS_SetReg(SISSR, 0x14, 0x30);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004696 sisfb_post_xgi_delay(ivideo, 1);
4697 sr14 = 0x00;
4698 if(sisfb_post_xgi_rwtest(ivideo, 21, 22, mapsize))
4699 goto bail_out;
4700 else
Aaro Koskinen44b751b2010-12-20 23:50:17 +02004701 SiS_SetReg(SISSR, 0x13, 0x31);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004702 }
4703
4704 } else { /* XGI_40 */
4705
Aaro Koskinene57d4132010-12-20 23:50:16 +02004706 reg = SiS_GetReg(SISCR, 0x97);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004707 if(!(reg & 0x10)) {
Aaro Koskinene57d4132010-12-20 23:50:16 +02004708 reg = SiS_GetReg(SISSR, 0x39);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004709 reg >>= 1;
4710 }
4711
4712 if(reg & 0x01) { /* DDRII */
4713 buswidth = 32;
4714 if(ivideo->revision_id == 2) {
4715 channelab = 2;
Aaro Koskinen44b751b2010-12-20 23:50:17 +02004716 SiS_SetReg(SISSR, 0x13, 0xa1);
4717 SiS_SetReg(SISSR, 0x14, 0x44);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004718 sr14 = 0x04;
4719 sisfb_post_xgi_delay(ivideo, 1);
4720 if(sisfb_post_xgi_rwtest(ivideo, 23, 24, mapsize))
4721 goto bail_out;
4722
Aaro Koskinen44b751b2010-12-20 23:50:17 +02004723 SiS_SetReg(SISSR, 0x13, 0x21);
4724 SiS_SetReg(SISSR, 0x14, 0x34);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004725 if(sisfb_post_xgi_rwtest(ivideo, 22, 23, mapsize))
4726 goto bail_out;
4727
4728 channelab = 1;
Aaro Koskinen44b751b2010-12-20 23:50:17 +02004729 SiS_SetReg(SISSR, 0x13, 0xa1);
4730 SiS_SetReg(SISSR, 0x14, 0x40);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004731 sr14 = 0x00;
4732 if(sisfb_post_xgi_rwtest(ivideo, 22, 23, mapsize))
4733 goto bail_out;
4734
Aaro Koskinen44b751b2010-12-20 23:50:17 +02004735 SiS_SetReg(SISSR, 0x13, 0x21);
4736 SiS_SetReg(SISSR, 0x14, 0x30);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004737 } else {
4738 channelab = 3;
Aaro Koskinen44b751b2010-12-20 23:50:17 +02004739 SiS_SetReg(SISSR, 0x13, 0xa1);
4740 SiS_SetReg(SISSR, 0x14, 0x4c);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004741 sr14 = 0x0c;
4742 sisfb_post_xgi_delay(ivideo, 1);
4743 if(sisfb_post_xgi_rwtest(ivideo, 23, 25, mapsize))
4744 goto bail_out;
4745
4746 channelab = 2;
Aaro Koskinen44b751b2010-12-20 23:50:17 +02004747 SiS_SetReg(SISSR, 0x14, 0x48);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004748 sisfb_post_xgi_delay(ivideo, 1);
4749 sr14 = 0x08;
4750 if(sisfb_post_xgi_rwtest(ivideo, 23, 24, mapsize))
4751 goto bail_out;
4752
Aaro Koskinen44b751b2010-12-20 23:50:17 +02004753 SiS_SetReg(SISSR, 0x13, 0x21);
4754 SiS_SetReg(SISSR, 0x14, 0x3c);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004755 sr14 = 0x0c;
4756
4757 if(sisfb_post_xgi_rwtest(ivideo, 23, 24, mapsize)) {
4758 channelab = 3;
4759 } else {
4760 channelab = 2;
Aaro Koskinen44b751b2010-12-20 23:50:17 +02004761 SiS_SetReg(SISSR, 0x14, 0x38);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004762 sr14 = 0x08;
4763 }
4764 }
4765 sisfb_post_xgi_delay(ivideo, 1);
4766
4767 } else { /* DDR */
4768
4769 buswidth = 64;
4770 if(ivideo->revision_id == 2) {
4771 channelab = 1;
Aaro Koskinen44b751b2010-12-20 23:50:17 +02004772 SiS_SetReg(SISSR, 0x13, 0xa1);
4773 SiS_SetReg(SISSR, 0x14, 0x52);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004774 sisfb_post_xgi_delay(ivideo, 1);
4775 sr14 = 0x02;
4776 if(sisfb_post_xgi_rwtest(ivideo, 23, 24, mapsize))
4777 goto bail_out;
4778
Aaro Koskinen44b751b2010-12-20 23:50:17 +02004779 SiS_SetReg(SISSR, 0x13, 0x21);
4780 SiS_SetReg(SISSR, 0x14, 0x42);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004781 } else {
4782 channelab = 2;
Aaro Koskinen44b751b2010-12-20 23:50:17 +02004783 SiS_SetReg(SISSR, 0x13, 0xa1);
4784 SiS_SetReg(SISSR, 0x14, 0x5a);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004785 sisfb_post_xgi_delay(ivideo, 1);
4786 sr14 = 0x0a;
4787 if(sisfb_post_xgi_rwtest(ivideo, 24, 25, mapsize))
4788 goto bail_out;
4789
Aaro Koskinen44b751b2010-12-20 23:50:17 +02004790 SiS_SetReg(SISSR, 0x13, 0x21);
4791 SiS_SetReg(SISSR, 0x14, 0x4a);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004792 }
4793 sisfb_post_xgi_delay(ivideo, 1);
4794
4795 }
4796 }
4797
4798bail_out:
Aaro Koskinenad78adb2010-12-20 23:50:20 +02004799 SiS_SetRegANDOR(SISSR, 0x14, 0xf0, sr14);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004800 sisfb_post_xgi_delay(ivideo, 1);
4801
4802 j = (ivideo->chip == XGI_20) ? 5 : 9;
4803 k = (ivideo->chip == XGI_20) ? 12 : 4;
Aaro Koskinen83ea0f12011-02-13 22:11:23 +00004804 status = -EIO;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004805
4806 for(i = 0; i < k; i++) {
4807
4808 reg = (ivideo->chip == XGI_20) ?
4809 dramsr13[(i * 5) + 4] : dramsr13_4[(i * 5) + 4];
Aaro Koskinenad78adb2010-12-20 23:50:20 +02004810 SiS_SetRegANDOR(SISSR, 0x13, 0x80, reg);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004811 sisfb_post_xgi_delay(ivideo, 50);
4812
4813 ranksize = (ivideo->chip == XGI_20) ?
4814 dramsr13[(i * 5) + 3] : dramsr13_4[(i * 5) + 3];
4815
Aaro Koskinene57d4132010-12-20 23:50:16 +02004816 reg = SiS_GetReg(SISSR, 0x13);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004817 if(reg & 0x80) ranksize <<= 1;
4818
4819 if(ivideo->chip == XGI_20) {
4820 if(buswidth == 16) ranksize <<= 1;
4821 else if(buswidth == 32) ranksize <<= 2;
4822 } else {
4823 if(buswidth == 64) ranksize <<= 1;
4824 }
4825
4826 reg = 0;
4827 l = channelab;
4828 if(l == 3) l = 4;
4829 if((ranksize * l) <= 256) {
4830 while((ranksize >>= 1)) reg += 0x10;
4831 }
4832
4833 if(!reg) continue;
4834
Aaro Koskinenad78adb2010-12-20 23:50:20 +02004835 SiS_SetRegANDOR(SISSR, 0x14, 0x0f, (reg & 0xf0));
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004836 sisfb_post_xgi_delay(ivideo, 1);
4837
Aaro Koskinen83ea0f12011-02-13 22:11:23 +00004838 if (sisfb_post_xgi_rwtest(ivideo, j, ((reg >> 4) + channelab - 2 + 20), mapsize)) {
4839 status = 0;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004840 break;
Aaro Koskinen83ea0f12011-02-13 22:11:23 +00004841 }
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004842 }
4843
4844 iounmap(ivideo->video_vbase);
Aaro Koskinen83ea0f12011-02-13 22:11:23 +00004845
4846 return status;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004847}
4848
Greg Kroah-Hartman48c68c42012-12-21 13:07:39 -08004849static void sisfb_post_xgi_setclocks(struct sis_video_info *ivideo, u8 regb)
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004850{
4851 u8 v1, v2, v3;
4852 int index;
4853 static const u8 cs90[8 * 3] = {
4854 0x16, 0x01, 0x01,
4855 0x3e, 0x03, 0x01,
4856 0x7c, 0x08, 0x01,
4857 0x79, 0x06, 0x01,
4858 0x29, 0x01, 0x81,
4859 0x5c, 0x23, 0x01,
4860 0x5c, 0x23, 0x01,
4861 0x5c, 0x23, 0x01
4862 };
4863 static const u8 csb8[8 * 3] = {
4864 0x5c, 0x23, 0x01,
4865 0x29, 0x01, 0x01,
4866 0x7c, 0x08, 0x01,
4867 0x79, 0x06, 0x01,
4868 0x29, 0x01, 0x81,
4869 0x5c, 0x23, 0x01,
4870 0x5c, 0x23, 0x01,
4871 0x5c, 0x23, 0x01
4872 };
4873
4874 regb = 0; /* ! */
4875
4876 index = regb * 3;
4877 v1 = cs90[index]; v2 = cs90[index + 1]; v3 = cs90[index + 2];
4878 if(ivideo->haveXGIROM) {
4879 v1 = ivideo->bios_abase[0x90 + index];
4880 v2 = ivideo->bios_abase[0x90 + index + 1];
4881 v3 = ivideo->bios_abase[0x90 + index + 2];
4882 }
Aaro Koskinen44b751b2010-12-20 23:50:17 +02004883 SiS_SetReg(SISSR, 0x28, v1);
4884 SiS_SetReg(SISSR, 0x29, v2);
4885 SiS_SetReg(SISSR, 0x2a, v3);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004886 sisfb_post_xgi_delay(ivideo, 0x43);
4887 sisfb_post_xgi_delay(ivideo, 0x43);
4888 sisfb_post_xgi_delay(ivideo, 0x43);
4889 index = regb * 3;
4890 v1 = csb8[index]; v2 = csb8[index + 1]; v3 = csb8[index + 2];
4891 if(ivideo->haveXGIROM) {
4892 v1 = ivideo->bios_abase[0xb8 + index];
4893 v2 = ivideo->bios_abase[0xb8 + index + 1];
4894 v3 = ivideo->bios_abase[0xb8 + index + 2];
4895 }
Aaro Koskinen44b751b2010-12-20 23:50:17 +02004896 SiS_SetReg(SISSR, 0x2e, v1);
4897 SiS_SetReg(SISSR, 0x2f, v2);
4898 SiS_SetReg(SISSR, 0x30, v3);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07004899 sisfb_post_xgi_delay(ivideo, 0x43);
4900 sisfb_post_xgi_delay(ivideo, 0x43);
4901 sisfb_post_xgi_delay(ivideo, 0x43);
4902}
4903
Greg Kroah-Hartman48c68c42012-12-21 13:07:39 -08004904static void sisfb_post_xgi_ddr2_mrs_default(struct sis_video_info *ivideo,
4905 u8 regb)
Aaro Koskinenc9982d52011-02-13 22:11:27 +00004906{
4907 unsigned char *bios = ivideo->bios_abase;
4908 u8 v1;
4909
4910 SiS_SetReg(SISSR, 0x28, 0x64);
4911 SiS_SetReg(SISSR, 0x29, 0x63);
4912 sisfb_post_xgi_delay(ivideo, 15);
4913 SiS_SetReg(SISSR, 0x18, 0x00);
4914 SiS_SetReg(SISSR, 0x19, 0x20);
4915 SiS_SetReg(SISSR, 0x16, 0x00);
4916 SiS_SetReg(SISSR, 0x16, 0x80);
4917 SiS_SetReg(SISSR, 0x18, 0xc5);
4918 SiS_SetReg(SISSR, 0x19, 0x23);
4919 SiS_SetReg(SISSR, 0x16, 0x00);
4920 SiS_SetReg(SISSR, 0x16, 0x80);
4921 sisfb_post_xgi_delay(ivideo, 1);
4922 SiS_SetReg(SISCR, 0x97, 0x11);
4923 sisfb_post_xgi_setclocks(ivideo, regb);
4924 sisfb_post_xgi_delay(ivideo, 0x46);
4925 SiS_SetReg(SISSR, 0x18, 0xc5);
4926 SiS_SetReg(SISSR, 0x19, 0x23);
4927 SiS_SetReg(SISSR, 0x16, 0x00);
4928 SiS_SetReg(SISSR, 0x16, 0x80);
4929 sisfb_post_xgi_delay(ivideo, 1);
4930 SiS_SetReg(SISSR, 0x1b, 0x04);
4931 sisfb_post_xgi_delay(ivideo, 1);
4932 SiS_SetReg(SISSR, 0x1b, 0x00);
4933 sisfb_post_xgi_delay(ivideo, 1);
4934 v1 = 0x31;
4935 if (ivideo->haveXGIROM) {
4936 v1 = bios[0xf0];
4937 }
4938 SiS_SetReg(SISSR, 0x18, v1);
4939 SiS_SetReg(SISSR, 0x19, 0x06);
4940 SiS_SetReg(SISSR, 0x16, 0x04);
4941 SiS_SetReg(SISSR, 0x16, 0x84);
4942 sisfb_post_xgi_delay(ivideo, 1);
4943}
4944
Greg Kroah-Hartman48c68c42012-12-21 13:07:39 -08004945static void sisfb_post_xgi_ddr2_mrs_xg21(struct sis_video_info *ivideo)
Aaro Koskinen42dea9032011-02-13 22:11:28 +00004946{
4947 sisfb_post_xgi_setclocks(ivideo, 1);
4948
4949 SiS_SetReg(SISCR, 0x97, 0x11);
4950 sisfb_post_xgi_delay(ivideo, 0x46);
4951
4952 SiS_SetReg(SISSR, 0x18, 0x00); /* EMRS2 */
4953 SiS_SetReg(SISSR, 0x19, 0x80);
4954 SiS_SetReg(SISSR, 0x16, 0x05);
4955 SiS_SetReg(SISSR, 0x16, 0x85);
4956
4957 SiS_SetReg(SISSR, 0x18, 0x00); /* EMRS3 */
4958 SiS_SetReg(SISSR, 0x19, 0xc0);
4959 SiS_SetReg(SISSR, 0x16, 0x05);
4960 SiS_SetReg(SISSR, 0x16, 0x85);
4961
4962 SiS_SetReg(SISSR, 0x18, 0x00); /* EMRS1 */
4963 SiS_SetReg(SISSR, 0x19, 0x40);
4964 SiS_SetReg(SISSR, 0x16, 0x05);
4965 SiS_SetReg(SISSR, 0x16, 0x85);
4966
4967 SiS_SetReg(SISSR, 0x18, 0x42); /* MRS1 */
4968 SiS_SetReg(SISSR, 0x19, 0x02);
4969 SiS_SetReg(SISSR, 0x16, 0x05);
4970 SiS_SetReg(SISSR, 0x16, 0x85);
4971 sisfb_post_xgi_delay(ivideo, 1);
4972
4973 SiS_SetReg(SISSR, 0x1b, 0x04);
4974 sisfb_post_xgi_delay(ivideo, 1);
4975
4976 SiS_SetReg(SISSR, 0x1b, 0x00);
4977 sisfb_post_xgi_delay(ivideo, 1);
4978
4979 SiS_SetReg(SISSR, 0x18, 0x42); /* MRS1 */
4980 SiS_SetReg(SISSR, 0x19, 0x00);
4981 SiS_SetReg(SISSR, 0x16, 0x05);
4982 SiS_SetReg(SISSR, 0x16, 0x85);
4983 sisfb_post_xgi_delay(ivideo, 1);
4984}
4985
Greg Kroah-Hartman48c68c42012-12-21 13:07:39 -08004986static void sisfb_post_xgi_ddr2(struct sis_video_info *ivideo, u8 regb)
Aaro Koskinenc9982d52011-02-13 22:11:27 +00004987{
4988 unsigned char *bios = ivideo->bios_abase;
4989 static const u8 cs158[8] = {
4990 0x88, 0xaa, 0x48, 0x00, 0x00, 0x00, 0x00, 0x00
4991 };
4992 static const u8 cs160[8] = {
4993 0x44, 0x77, 0x77, 0x00, 0x00, 0x00, 0x00, 0x00
4994 };
4995 static const u8 cs168[8] = {
4996 0x48, 0x78, 0x88, 0x00, 0x00, 0x00, 0x00, 0x00
4997 };
4998 u8 reg;
4999 u8 v1;
5000 u8 v2;
5001 u8 v3;
5002
Aaro Koskinen42dea9032011-02-13 22:11:28 +00005003 SiS_SetReg(SISCR, 0xb0, 0x80); /* DDR2 dual frequency mode */
Aaro Koskinenc9982d52011-02-13 22:11:27 +00005004 SiS_SetReg(SISCR, 0x82, 0x77);
5005 SiS_SetReg(SISCR, 0x86, 0x00);
5006 reg = SiS_GetReg(SISCR, 0x86);
5007 SiS_SetReg(SISCR, 0x86, 0x88);
5008 reg = SiS_GetReg(SISCR, 0x86);
5009 v1 = cs168[regb]; v2 = cs160[regb]; v3 = cs158[regb];
5010 if (ivideo->haveXGIROM) {
5011 v1 = bios[regb + 0x168];
5012 v2 = bios[regb + 0x160];
5013 v3 = bios[regb + 0x158];
5014 }
5015 SiS_SetReg(SISCR, 0x86, v1);
5016 SiS_SetReg(SISCR, 0x82, 0x77);
5017 SiS_SetReg(SISCR, 0x85, 0x00);
5018 reg = SiS_GetReg(SISCR, 0x85);
5019 SiS_SetReg(SISCR, 0x85, 0x88);
5020 reg = SiS_GetReg(SISCR, 0x85);
5021 SiS_SetReg(SISCR, 0x85, v2);
5022 SiS_SetReg(SISCR, 0x82, v3);
5023 SiS_SetReg(SISCR, 0x98, 0x01);
5024 SiS_SetReg(SISCR, 0x9a, 0x02);
Aaro Koskinen42dea9032011-02-13 22:11:28 +00005025 if (sisfb_xgi_is21(ivideo))
5026 sisfb_post_xgi_ddr2_mrs_xg21(ivideo);
5027 else
5028 sisfb_post_xgi_ddr2_mrs_default(ivideo, regb);
Aaro Koskinenc9982d52011-02-13 22:11:27 +00005029}
5030
Greg Kroah-Hartman48c68c42012-12-21 13:07:39 -08005031static u8 sisfb_post_xgi_ramtype(struct sis_video_info *ivideo)
Aaro Koskinen74de5f42011-02-13 22:11:24 +00005032{
5033 unsigned char *bios = ivideo->bios_abase;
5034 u8 ramtype;
5035 u8 reg;
5036 u8 v1;
5037
5038 ramtype = 0x00; v1 = 0x10;
5039 if (ivideo->haveXGIROM) {
5040 ramtype = bios[0x62];
5041 v1 = bios[0x1d2];
5042 }
5043 if (!(ramtype & 0x80)) {
Aaro Koskinen5e8700b2011-02-13 22:11:26 +00005044 if (sisfb_xgi_is21(ivideo)) {
5045 SiS_SetRegAND(SISCR, 0xb4, 0xfd); /* GPIO control */
5046 SiS_SetRegOR(SISCR, 0x4a, 0x80); /* GPIOH EN */
5047 reg = SiS_GetReg(SISCR, 0x48);
5048 SiS_SetRegOR(SISCR, 0xb4, 0x02);
5049 ramtype = reg & 0x01; /* GPIOH */
5050 } else if (ivideo->chip == XGI_20) {
Aaro Koskinen74de5f42011-02-13 22:11:24 +00005051 SiS_SetReg(SISCR, 0x97, v1);
5052 reg = SiS_GetReg(SISCR, 0x97);
5053 if (reg & 0x10) {
5054 ramtype = (reg & 0x01) << 1;
5055 }
5056 } else {
5057 reg = SiS_GetReg(SISSR, 0x39);
5058 ramtype = reg & 0x02;
5059 if (!(ramtype)) {
5060 reg = SiS_GetReg(SISSR, 0x3a);
5061 ramtype = (reg >> 1) & 0x01;
5062 }
5063 }
5064 }
5065 ramtype &= 0x07;
5066
5067 return ramtype;
5068}
5069
Greg Kroah-Hartman48c68c42012-12-21 13:07:39 -08005070static int sisfb_post_xgi(struct pci_dev *pdev)
Thomas Winischhofer544393f2005-09-09 13:04:45 -07005071{
5072 struct sis_video_info *ivideo = pci_get_drvdata(pdev);
5073 unsigned char *bios = ivideo->bios_abase;
5074 struct pci_dev *mypdev = NULL;
5075 const u8 *ptr, *ptr2;
5076 u8 v1, v2, v3, v4, v5, reg, ramtype;
5077 u32 rega, regb, regd;
5078 int i, j, k, index;
5079 static const u8 cs78[3] = { 0xf6, 0x0d, 0x00 };
5080 static const u8 cs76[2] = { 0xa3, 0xfb };
5081 static const u8 cs7b[3] = { 0xc0, 0x11, 0x00 };
5082 static const u8 cs158[8] = {
5083 0x88, 0xaa, 0x48, 0x00, 0x00, 0x00, 0x00, 0x00
5084 };
5085 static const u8 cs160[8] = {
5086 0x44, 0x77, 0x77, 0x00, 0x00, 0x00, 0x00, 0x00
5087 };
5088 static const u8 cs168[8] = {
5089 0x48, 0x78, 0x88, 0x00, 0x00, 0x00, 0x00, 0x00
5090 };
5091 static const u8 cs128[3 * 8] = {
5092 0x90, 0x28, 0x24, 0x00, 0x00, 0x00, 0x00, 0x00,
5093 0x77, 0x44, 0x44, 0x00, 0x00, 0x00, 0x00, 0x00,
5094 0x77, 0x44, 0x44, 0x00, 0x00, 0x00, 0x00, 0x00
5095 };
5096 static const u8 cs148[2 * 8] = {
5097 0x55, 0x55, 0x55, 0x00, 0x00, 0x00, 0x00, 0x00,
5098 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
5099 };
5100 static const u8 cs31a[8 * 4] = {
5101 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
5102 0xaa, 0xaa, 0xaa, 0xaa, 0x00, 0x00, 0x00, 0x00,
5103 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
5104 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
5105 };
5106 static const u8 cs33a[8 * 4] = {
5107 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
5108 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
5109 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
5110 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
5111 };
5112 static const u8 cs45a[8 * 2] = {
5113 0x00, 0x00, 0xa0, 0x00, 0xa0, 0x00, 0x00, 0x00,
5114 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
5115 };
5116 static const u8 cs170[7 * 8] = {
5117 0x54, 0x32, 0x44, 0x00, 0x00, 0x00, 0x00, 0x00,
5118 0x54, 0x43, 0x44, 0x00, 0x00, 0x00, 0x00, 0x00,
5119 0x0a, 0x05, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00,
5120 0x44, 0x34, 0x44, 0x00, 0x00, 0x00, 0x00, 0x00,
5121 0x10, 0x0a, 0x0a, 0x00, 0x00, 0x00, 0x00, 0x00,
5122 0x11, 0x0c, 0x0c, 0x00, 0x00, 0x00, 0x00, 0x00,
5123 0x05, 0x05, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00
5124 };
5125 static const u8 cs1a8[3 * 8] = {
5126 0xf0, 0xf0, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x00,
5127 0x05, 0x02, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00,
5128 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
5129 };
5130 static const u8 cs100[2 * 8] = {
5131 0xc4, 0x04, 0x84, 0x00, 0x00, 0x00, 0x00, 0x00,
5132 0xc4, 0x04, 0x84, 0x00, 0x00, 0x00, 0x00, 0x00
5133 };
5134
5135 /* VGA enable */
Aaro Koskinen1e1687d2010-12-20 23:50:14 +02005136 reg = SiS_GetRegByte(SISVGAENABLE) | 0x01;
Aaro Koskinen63e13f82010-12-20 23:50:15 +02005137 SiS_SetRegByte(SISVGAENABLE, reg);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07005138
5139 /* Misc */
Aaro Koskinen1e1687d2010-12-20 23:50:14 +02005140 reg = SiS_GetRegByte(SISMISCR) | 0x01;
Aaro Koskinen63e13f82010-12-20 23:50:15 +02005141 SiS_SetRegByte(SISMISCW, reg);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07005142
5143 /* Unlock SR */
Aaro Koskinen44b751b2010-12-20 23:50:17 +02005144 SiS_SetReg(SISSR, 0x05, 0x86);
Aaro Koskinene57d4132010-12-20 23:50:16 +02005145 reg = SiS_GetReg(SISSR, 0x05);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07005146 if(reg != 0xa1)
5147 return 0;
5148
5149 /* Clear some regs */
5150 for(i = 0; i < 0x22; i++) {
5151 if(0x06 + i == 0x20) continue;
Aaro Koskinen44b751b2010-12-20 23:50:17 +02005152 SiS_SetReg(SISSR, 0x06 + i, 0x00);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07005153 }
5154 for(i = 0; i < 0x0b; i++) {
Aaro Koskinen44b751b2010-12-20 23:50:17 +02005155 SiS_SetReg(SISSR, 0x31 + i, 0x00);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07005156 }
5157 for(i = 0; i < 0x10; i++) {
Aaro Koskinen44b751b2010-12-20 23:50:17 +02005158 SiS_SetReg(SISCR, 0x30 + i, 0x00);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07005159 }
5160
5161 ptr = cs78;
5162 if(ivideo->haveXGIROM) {
5163 ptr = (const u8 *)&bios[0x78];
5164 }
5165 for(i = 0; i < 3; i++) {
Aaro Koskinen44b751b2010-12-20 23:50:17 +02005166 SiS_SetReg(SISSR, 0x23 + i, ptr[i]);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07005167 }
5168
5169 ptr = cs76;
5170 if(ivideo->haveXGIROM) {
5171 ptr = (const u8 *)&bios[0x76];
5172 }
5173 for(i = 0; i < 2; i++) {
Aaro Koskinen44b751b2010-12-20 23:50:17 +02005174 SiS_SetReg(SISSR, 0x21 + i, ptr[i]);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07005175 }
5176
5177 v1 = 0x18; v2 = 0x00;
5178 if(ivideo->haveXGIROM) {
5179 v1 = bios[0x74];
5180 v2 = bios[0x75];
5181 }
Aaro Koskinen44b751b2010-12-20 23:50:17 +02005182 SiS_SetReg(SISSR, 0x07, v1);
5183 SiS_SetReg(SISSR, 0x11, 0x0f);
5184 SiS_SetReg(SISSR, 0x1f, v2);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07005185 /* PCI linear mode, RelIO enabled, A0000 decoding disabled */
Aaro Koskinen44b751b2010-12-20 23:50:17 +02005186 SiS_SetReg(SISSR, 0x20, 0x80 | 0x20 | 0x04);
5187 SiS_SetReg(SISSR, 0x27, 0x74);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07005188
5189 ptr = cs7b;
5190 if(ivideo->haveXGIROM) {
5191 ptr = (const u8 *)&bios[0x7b];
5192 }
5193 for(i = 0; i < 3; i++) {
Aaro Koskinen44b751b2010-12-20 23:50:17 +02005194 SiS_SetReg(SISSR, 0x31 + i, ptr[i]);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07005195 }
5196
5197 if(ivideo->chip == XGI_40) {
5198 if(ivideo->revision_id == 2) {
Aaro Koskinenad78adb2010-12-20 23:50:20 +02005199 SiS_SetRegANDOR(SISSR, 0x3b, 0x3f, 0xc0);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07005200 }
Aaro Koskinen44b751b2010-12-20 23:50:17 +02005201 SiS_SetReg(SISCR, 0x7d, 0xfe);
5202 SiS_SetReg(SISCR, 0x7e, 0x0f);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07005203 }
5204 if(ivideo->revision_id == 0) { /* 40 *and* 20? */
Aaro Koskinen667a8b42010-12-20 23:50:19 +02005205 SiS_SetRegAND(SISCR, 0x58, 0xd7);
Aaro Koskinene57d4132010-12-20 23:50:16 +02005206 reg = SiS_GetReg(SISCR, 0xcb);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07005207 if(reg & 0x20) {
Aaro Koskinenad78adb2010-12-20 23:50:20 +02005208 SiS_SetRegANDOR(SISCR, 0x58, 0xd7, (reg & 0x10) ? 0x08 : 0x20); /* =0x28 Z7 ? */
Thomas Winischhofer544393f2005-09-09 13:04:45 -07005209 }
5210 }
5211
5212 reg = (ivideo->chip == XGI_40) ? 0x20 : 0x00;
Aaro Koskinenad78adb2010-12-20 23:50:20 +02005213 SiS_SetRegANDOR(SISCR, 0x38, 0x1f, reg);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07005214
5215 if(ivideo->chip == XGI_20) {
Aaro Koskinen44b751b2010-12-20 23:50:17 +02005216 SiS_SetReg(SISSR, 0x36, 0x70);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07005217 } else {
Aaro Koskinen44b751b2010-12-20 23:50:17 +02005218 SiS_SetReg(SISVID, 0x00, 0x86);
5219 SiS_SetReg(SISVID, 0x32, 0x00);
5220 SiS_SetReg(SISVID, 0x30, 0x00);
5221 SiS_SetReg(SISVID, 0x32, 0x01);
5222 SiS_SetReg(SISVID, 0x30, 0x00);
Aaro Koskinen667a8b42010-12-20 23:50:19 +02005223 SiS_SetRegAND(SISVID, 0x2f, 0xdf);
5224 SiS_SetRegAND(SISCAP, 0x00, 0x3f);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07005225
Aaro Koskinen44b751b2010-12-20 23:50:17 +02005226 SiS_SetReg(SISPART1, 0x2f, 0x01);
5227 SiS_SetReg(SISPART1, 0x00, 0x00);
5228 SiS_SetReg(SISPART1, 0x02, bios[0x7e]);
5229 SiS_SetReg(SISPART1, 0x2e, 0x08);
Aaro Koskinen667a8b42010-12-20 23:50:19 +02005230 SiS_SetRegAND(SISPART1, 0x35, 0x7f);
5231 SiS_SetRegAND(SISPART1, 0x50, 0xfe);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07005232
Aaro Koskinene57d4132010-12-20 23:50:16 +02005233 reg = SiS_GetReg(SISPART4, 0x00);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07005234 if(reg == 1 || reg == 2) {
Aaro Koskinen44b751b2010-12-20 23:50:17 +02005235 SiS_SetReg(SISPART2, 0x00, 0x1c);
5236 SiS_SetReg(SISPART4, 0x0d, bios[0x7f]);
5237 SiS_SetReg(SISPART4, 0x0e, bios[0x80]);
5238 SiS_SetReg(SISPART4, 0x10, bios[0x81]);
Aaro Koskinen667a8b42010-12-20 23:50:19 +02005239 SiS_SetRegAND(SISPART4, 0x0f, 0x3f);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07005240
Aaro Koskinene57d4132010-12-20 23:50:16 +02005241 reg = SiS_GetReg(SISPART4, 0x01);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07005242 if((reg & 0xf0) >= 0xb0) {
Aaro Koskinene57d4132010-12-20 23:50:16 +02005243 reg = SiS_GetReg(SISPART4, 0x23);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07005244 if(reg & 0x20) reg |= 0x40;
Aaro Koskinen44b751b2010-12-20 23:50:17 +02005245 SiS_SetReg(SISPART4, 0x23, reg);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07005246 reg = (reg & 0x20) ? 0x02 : 0x00;
Aaro Koskinenad78adb2010-12-20 23:50:20 +02005247 SiS_SetRegANDOR(SISPART1, 0x1e, 0xfd, reg);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07005248 }
5249 }
5250
5251 v1 = bios[0x77];
5252
Aaro Koskinene57d4132010-12-20 23:50:16 +02005253 reg = SiS_GetReg(SISSR, 0x3b);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07005254 if(reg & 0x02) {
Aaro Koskinene57d4132010-12-20 23:50:16 +02005255 reg = SiS_GetReg(SISSR, 0x3a);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07005256 v2 = (reg & 0x30) >> 3;
5257 if(!(v2 & 0x04)) v2 ^= 0x02;
Aaro Koskinene57d4132010-12-20 23:50:16 +02005258 reg = SiS_GetReg(SISSR, 0x39);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07005259 if(reg & 0x80) v2 |= 0x80;
5260 v2 |= 0x01;
5261
Adrian Bunk0959f0c2007-05-08 00:39:50 -07005262 if((mypdev = pci_get_device(PCI_VENDOR_ID_SI, 0x0730, NULL))) {
5263 pci_dev_put(mypdev);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07005264 if(((v2 & 0x06) == 2) || ((v2 & 0x06) == 4))
5265 v2 &= 0xf9;
5266 v2 |= 0x08;
5267 v1 &= 0xfe;
5268 } else {
Adrian Bunk0959f0c2007-05-08 00:39:50 -07005269 mypdev = pci_get_device(PCI_VENDOR_ID_SI, 0x0735, NULL);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07005270 if(!mypdev)
Adrian Bunk0959f0c2007-05-08 00:39:50 -07005271 mypdev = pci_get_device(PCI_VENDOR_ID_SI, 0x0645, NULL);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07005272 if(!mypdev)
Adrian Bunk0959f0c2007-05-08 00:39:50 -07005273 mypdev = pci_get_device(PCI_VENDOR_ID_SI, 0x0650, NULL);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07005274 if(mypdev) {
5275 pci_read_config_dword(mypdev, 0x94, &regd);
5276 regd &= 0xfffffeff;
5277 pci_write_config_dword(mypdev, 0x94, regd);
5278 v1 &= 0xfe;
Adrian Bunk0959f0c2007-05-08 00:39:50 -07005279 pci_dev_put(mypdev);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07005280 } else if(sisfb_find_host_bridge(ivideo, pdev, PCI_VENDOR_ID_SI)) {
5281 v1 &= 0xfe;
5282 } else if(sisfb_find_host_bridge(ivideo, pdev, 0x1106) ||
5283 sisfb_find_host_bridge(ivideo, pdev, 0x1022) ||
5284 sisfb_find_host_bridge(ivideo, pdev, 0x700e) ||
5285 sisfb_find_host_bridge(ivideo, pdev, 0x10de)) {
5286 if((v2 & 0x06) == 4)
5287 v2 ^= 0x06;
5288 v2 |= 0x08;
5289 }
5290 }
Aaro Koskinenad78adb2010-12-20 23:50:20 +02005291 SiS_SetRegANDOR(SISCR, 0x5f, 0xf0, v2);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07005292 }
Aaro Koskinen44b751b2010-12-20 23:50:17 +02005293 SiS_SetReg(SISSR, 0x22, v1);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07005294
5295 if(ivideo->revision_id == 2) {
Aaro Koskinene57d4132010-12-20 23:50:16 +02005296 v1 = SiS_GetReg(SISSR, 0x3b);
5297 v2 = SiS_GetReg(SISSR, 0x3a);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07005298 regd = bios[0x90 + 3] | (bios[0x90 + 4] << 8);
5299 if( (!(v1 & 0x02)) && (v2 & 0x30) && (regd < 0xcf) )
Aaro Koskinenad78adb2010-12-20 23:50:20 +02005300 SiS_SetRegANDOR(SISCR, 0x5f, 0xf1, 0x01);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07005301
Adrian Bunk0959f0c2007-05-08 00:39:50 -07005302 if((mypdev = pci_get_device(0x10de, 0x01e0, NULL))) {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07005303 /* TODO: set CR5f &0xf1 | 0x01 for version 6570
5304 * of nforce 2 ROM
5305 */
5306 if(0)
Aaro Koskinenad78adb2010-12-20 23:50:20 +02005307 SiS_SetRegANDOR(SISCR, 0x5f, 0xf1, 0x01);
Adrian Bunk0959f0c2007-05-08 00:39:50 -07005308 pci_dev_put(mypdev);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07005309 }
5310 }
5311
5312 v1 = 0x30;
Aaro Koskinene57d4132010-12-20 23:50:16 +02005313 reg = SiS_GetReg(SISSR, 0x3b);
5314 v2 = SiS_GetReg(SISCR, 0x5f);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07005315 if((!(reg & 0x02)) && (v2 & 0x0e))
5316 v1 |= 0x08;
Aaro Koskinen44b751b2010-12-20 23:50:17 +02005317 SiS_SetReg(SISSR, 0x27, v1);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07005318
5319 if(bios[0x64] & 0x01) {
Aaro Koskinenad78adb2010-12-20 23:50:20 +02005320 SiS_SetRegANDOR(SISCR, 0x5f, 0xf0, bios[0x64]);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07005321 }
5322
5323 v1 = bios[0x4f7];
5324 pci_read_config_dword(pdev, 0x50, &regd);
5325 regd = (regd >> 20) & 0x0f;
5326 if(regd == 1) {
5327 v1 &= 0xfc;
Aaro Koskinen27799d62010-12-20 23:50:18 +02005328 SiS_SetRegOR(SISCR, 0x5f, 0x08);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07005329 }
Aaro Koskinen44b751b2010-12-20 23:50:17 +02005330 SiS_SetReg(SISCR, 0x48, v1);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07005331
Aaro Koskinenad78adb2010-12-20 23:50:20 +02005332 SiS_SetRegANDOR(SISCR, 0x47, 0x04, bios[0x4f6] & 0xfb);
5333 SiS_SetRegANDOR(SISCR, 0x49, 0xf0, bios[0x4f8] & 0x0f);
5334 SiS_SetRegANDOR(SISCR, 0x4a, 0x60, bios[0x4f9] & 0x9f);
5335 SiS_SetRegANDOR(SISCR, 0x4b, 0x08, bios[0x4fa] & 0xf7);
5336 SiS_SetRegANDOR(SISCR, 0x4c, 0x80, bios[0x4fb] & 0x7f);
Aaro Koskinen44b751b2010-12-20 23:50:17 +02005337 SiS_SetReg(SISCR, 0x70, bios[0x4fc]);
Aaro Koskinenad78adb2010-12-20 23:50:20 +02005338 SiS_SetRegANDOR(SISCR, 0x71, 0xf0, bios[0x4fd] & 0x0f);
Aaro Koskinen44b751b2010-12-20 23:50:17 +02005339 SiS_SetReg(SISCR, 0x74, 0xd0);
Aaro Koskinenad78adb2010-12-20 23:50:20 +02005340 SiS_SetRegANDOR(SISCR, 0x74, 0xcf, bios[0x4fe] & 0x30);
5341 SiS_SetRegANDOR(SISCR, 0x75, 0xe0, bios[0x4ff] & 0x1f);
5342 SiS_SetRegANDOR(SISCR, 0x76, 0xe0, bios[0x500] & 0x1f);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07005343 v1 = bios[0x501];
Adrian Bunk0959f0c2007-05-08 00:39:50 -07005344 if((mypdev = pci_get_device(0x8086, 0x2530, NULL))) {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07005345 v1 = 0xf0;
Adrian Bunk0959f0c2007-05-08 00:39:50 -07005346 pci_dev_put(mypdev);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07005347 }
Aaro Koskinen44b751b2010-12-20 23:50:17 +02005348 SiS_SetReg(SISCR, 0x77, v1);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07005349 }
5350
Aaro Koskinen42dea9032011-02-13 22:11:28 +00005351 /* RAM type:
5352 *
5353 * 0 == DDR1, 1 == DDR2, 2..7 == reserved?
5354 *
5355 * The code seems to written so that regb should equal ramtype,
5356 * however, so far it has been hardcoded to 0. Enable other values only
5357 * on XGI Z9, as it passes the POST, and add a warning for others.
5358 */
5359 ramtype = sisfb_post_xgi_ramtype(ivideo);
5360 if (!sisfb_xgi_is21(ivideo) && ramtype) {
5361 dev_warn(&pdev->dev,
5362 "RAM type something else than expected: %d\n",
5363 ramtype);
5364 regb = 0;
5365 } else {
5366 regb = ramtype;
5367 }
Thomas Winischhofer544393f2005-09-09 13:04:45 -07005368
5369 v1 = 0xff;
5370 if(ivideo->haveXGIROM) {
5371 v1 = bios[0x140 + regb];
5372 }
Aaro Koskinen44b751b2010-12-20 23:50:17 +02005373 SiS_SetReg(SISCR, 0x6d, v1);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07005374
5375 ptr = cs128;
5376 if(ivideo->haveXGIROM) {
5377 ptr = (const u8 *)&bios[0x128];
5378 }
5379 for(i = 0, j = 0; i < 3; i++, j += 8) {
Aaro Koskinen44b751b2010-12-20 23:50:17 +02005380 SiS_SetReg(SISCR, 0x68 + i, ptr[j + regb]);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07005381 }
5382
5383 ptr = cs31a;
5384 ptr2 = cs33a;
5385 if(ivideo->haveXGIROM) {
5386 index = (ivideo->chip == XGI_20) ? 0x31a : 0x3a6;
5387 ptr = (const u8 *)&bios[index];
5388 ptr2 = (const u8 *)&bios[index + 0x20];
5389 }
5390 for(i = 0; i < 2; i++) {
5391 if(i == 0) {
5392 regd = le32_to_cpu(((u32 *)ptr)[regb]);
5393 rega = 0x6b;
5394 } else {
5395 regd = le32_to_cpu(((u32 *)ptr2)[regb]);
5396 rega = 0x6e;
5397 }
5398 reg = 0x00;
5399 for(j = 0; j < 16; j++) {
5400 reg &= 0xf3;
5401 if(regd & 0x01) reg |= 0x04;
5402 if(regd & 0x02) reg |= 0x08;
5403 regd >>= 2;
Aaro Koskinen44b751b2010-12-20 23:50:17 +02005404 SiS_SetReg(SISCR, rega, reg);
Aaro Koskinene57d4132010-12-20 23:50:16 +02005405 reg = SiS_GetReg(SISCR, rega);
5406 reg = SiS_GetReg(SISCR, rega);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07005407 reg += 0x10;
5408 }
5409 }
5410
Aaro Koskinen667a8b42010-12-20 23:50:19 +02005411 SiS_SetRegAND(SISCR, 0x6e, 0xfc);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07005412
5413 ptr = NULL;
5414 if(ivideo->haveXGIROM) {
5415 index = (ivideo->chip == XGI_20) ? 0x35a : 0x3e6;
5416 ptr = (const u8 *)&bios[index];
5417 }
5418 for(i = 0; i < 4; i++) {
Aaro Koskinenad78adb2010-12-20 23:50:20 +02005419 SiS_SetRegANDOR(SISCR, 0x6e, 0xfc, i);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07005420 reg = 0x00;
5421 for(j = 0; j < 2; j++) {
5422 regd = 0;
5423 if(ptr) {
5424 regd = le32_to_cpu(((u32 *)ptr)[regb * 8]);
5425 ptr += 4;
5426 }
5427 /* reg = 0x00; */
5428 for(k = 0; k < 16; k++) {
5429 reg &= 0xfc;
5430 if(regd & 0x01) reg |= 0x01;
5431 if(regd & 0x02) reg |= 0x02;
5432 regd >>= 2;
Aaro Koskinen44b751b2010-12-20 23:50:17 +02005433 SiS_SetReg(SISCR, 0x6f, reg);
Aaro Koskinene57d4132010-12-20 23:50:16 +02005434 reg = SiS_GetReg(SISCR, 0x6f);
5435 reg = SiS_GetReg(SISCR, 0x6f);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07005436 reg += 0x08;
5437 }
5438 }
5439 }
5440
5441 ptr = cs148;
5442 if(ivideo->haveXGIROM) {
5443 ptr = (const u8 *)&bios[0x148];
5444 }
5445 for(i = 0, j = 0; i < 2; i++, j += 8) {
Aaro Koskinen44b751b2010-12-20 23:50:17 +02005446 SiS_SetReg(SISCR, 0x80 + i, ptr[j + regb]);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07005447 }
5448
Aaro Koskinen667a8b42010-12-20 23:50:19 +02005449 SiS_SetRegAND(SISCR, 0x89, 0x8f);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07005450
5451 ptr = cs45a;
5452 if(ivideo->haveXGIROM) {
5453 index = (ivideo->chip == XGI_20) ? 0x45a : 0x4e6;
5454 ptr = (const u8 *)&bios[index];
5455 }
5456 regd = le16_to_cpu(((const u16 *)ptr)[regb]);
5457 reg = 0x80;
5458 for(i = 0; i < 5; i++) {
5459 reg &= 0xfc;
5460 if(regd & 0x01) reg |= 0x01;
5461 if(regd & 0x02) reg |= 0x02;
5462 regd >>= 2;
Aaro Koskinen44b751b2010-12-20 23:50:17 +02005463 SiS_SetReg(SISCR, 0x89, reg);
Aaro Koskinene57d4132010-12-20 23:50:16 +02005464 reg = SiS_GetReg(SISCR, 0x89);
5465 reg = SiS_GetReg(SISCR, 0x89);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07005466 reg += 0x10;
5467 }
5468
5469 v1 = 0xb5; v2 = 0x20; v3 = 0xf0; v4 = 0x13;
5470 if(ivideo->haveXGIROM) {
5471 v1 = bios[0x118 + regb];
5472 v2 = bios[0xf8 + regb];
5473 v3 = bios[0x120 + regb];
5474 v4 = bios[0x1ca];
5475 }
Aaro Koskinen44b751b2010-12-20 23:50:17 +02005476 SiS_SetReg(SISCR, 0x45, v1 & 0x0f);
5477 SiS_SetReg(SISCR, 0x99, (v1 >> 4) & 0x07);
Aaro Koskinen27799d62010-12-20 23:50:18 +02005478 SiS_SetRegOR(SISCR, 0x40, v1 & 0x80);
Aaro Koskinen44b751b2010-12-20 23:50:17 +02005479 SiS_SetReg(SISCR, 0x41, v2);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07005480
5481 ptr = cs170;
5482 if(ivideo->haveXGIROM) {
5483 ptr = (const u8 *)&bios[0x170];
5484 }
5485 for(i = 0, j = 0; i < 7; i++, j += 8) {
Aaro Koskinen44b751b2010-12-20 23:50:17 +02005486 SiS_SetReg(SISCR, 0x90 + i, ptr[j + regb]);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07005487 }
5488
Aaro Koskinen44b751b2010-12-20 23:50:17 +02005489 SiS_SetReg(SISCR, 0x59, v3);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07005490
5491 ptr = cs1a8;
5492 if(ivideo->haveXGIROM) {
5493 ptr = (const u8 *)&bios[0x1a8];
5494 }
5495 for(i = 0, j = 0; i < 3; i++, j += 8) {
Aaro Koskinen44b751b2010-12-20 23:50:17 +02005496 SiS_SetReg(SISCR, 0xc3 + i, ptr[j + regb]);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07005497 }
5498
5499 ptr = cs100;
5500 if(ivideo->haveXGIROM) {
5501 ptr = (const u8 *)&bios[0x100];
5502 }
5503 for(i = 0, j = 0; i < 2; i++, j += 8) {
Aaro Koskinen44b751b2010-12-20 23:50:17 +02005504 SiS_SetReg(SISCR, 0x8a + i, ptr[j + regb]);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07005505 }
5506
Aaro Koskinen44b751b2010-12-20 23:50:17 +02005507 SiS_SetReg(SISCR, 0xcf, v4);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07005508
Aaro Koskinen44b751b2010-12-20 23:50:17 +02005509 SiS_SetReg(SISCR, 0x83, 0x09);
5510 SiS_SetReg(SISCR, 0x87, 0x00);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07005511
5512 if(ivideo->chip == XGI_40) {
5513 if( (ivideo->revision_id == 1) ||
5514 (ivideo->revision_id == 2) ) {
Aaro Koskinen44b751b2010-12-20 23:50:17 +02005515 SiS_SetReg(SISCR, 0x8c, 0x87);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07005516 }
5517 }
5518
Aaro Koskinen42dea9032011-02-13 22:11:28 +00005519 if (regb == 1)
5520 SiS_SetReg(SISSR, 0x17, 0x80); /* DDR2 */
5521 else
5522 SiS_SetReg(SISSR, 0x17, 0x00); /* DDR1 */
Aaro Koskinen44b751b2010-12-20 23:50:17 +02005523 SiS_SetReg(SISSR, 0x1a, 0x87);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07005524
5525 if(ivideo->chip == XGI_20) {
Aaro Koskinen44b751b2010-12-20 23:50:17 +02005526 SiS_SetReg(SISSR, 0x15, 0x00);
5527 SiS_SetReg(SISSR, 0x1c, 0x00);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07005528 }
5529
Thomas Winischhofer544393f2005-09-09 13:04:45 -07005530 switch(ramtype) {
5531 case 0:
5532 sisfb_post_xgi_setclocks(ivideo, regb);
5533 if((ivideo->chip == XGI_20) ||
5534 (ivideo->revision_id == 1) ||
5535 (ivideo->revision_id == 2)) {
5536 v1 = cs158[regb]; v2 = cs160[regb]; v3 = cs168[regb];
5537 if(ivideo->haveXGIROM) {
5538 v1 = bios[regb + 0x158];
5539 v2 = bios[regb + 0x160];
5540 v3 = bios[regb + 0x168];
5541 }
Aaro Koskinen44b751b2010-12-20 23:50:17 +02005542 SiS_SetReg(SISCR, 0x82, v1);
5543 SiS_SetReg(SISCR, 0x85, v2);
5544 SiS_SetReg(SISCR, 0x86, v3);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07005545 } else {
Aaro Koskinen44b751b2010-12-20 23:50:17 +02005546 SiS_SetReg(SISCR, 0x82, 0x88);
5547 SiS_SetReg(SISCR, 0x86, 0x00);
Aaro Koskinene57d4132010-12-20 23:50:16 +02005548 reg = SiS_GetReg(SISCR, 0x86);
Aaro Koskinen44b751b2010-12-20 23:50:17 +02005549 SiS_SetReg(SISCR, 0x86, 0x88);
Aaro Koskinene57d4132010-12-20 23:50:16 +02005550 reg = SiS_GetReg(SISCR, 0x86);
Aaro Koskinen44b751b2010-12-20 23:50:17 +02005551 SiS_SetReg(SISCR, 0x86, bios[regb + 0x168]);
5552 SiS_SetReg(SISCR, 0x82, 0x77);
5553 SiS_SetReg(SISCR, 0x85, 0x00);
Aaro Koskinene57d4132010-12-20 23:50:16 +02005554 reg = SiS_GetReg(SISCR, 0x85);
Aaro Koskinen44b751b2010-12-20 23:50:17 +02005555 SiS_SetReg(SISCR, 0x85, 0x88);
Aaro Koskinene57d4132010-12-20 23:50:16 +02005556 reg = SiS_GetReg(SISCR, 0x85);
Aaro Koskinen44b751b2010-12-20 23:50:17 +02005557 SiS_SetReg(SISCR, 0x85, bios[regb + 0x160]);
5558 SiS_SetReg(SISCR, 0x82, bios[regb + 0x158]);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07005559 }
5560 if(ivideo->chip == XGI_40) {
Aaro Koskinen44b751b2010-12-20 23:50:17 +02005561 SiS_SetReg(SISCR, 0x97, 0x00);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07005562 }
Aaro Koskinen44b751b2010-12-20 23:50:17 +02005563 SiS_SetReg(SISCR, 0x98, 0x01);
5564 SiS_SetReg(SISCR, 0x9a, 0x02);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07005565
Aaro Koskinen44b751b2010-12-20 23:50:17 +02005566 SiS_SetReg(SISSR, 0x18, 0x01);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07005567 if((ivideo->chip == XGI_20) ||
5568 (ivideo->revision_id == 2)) {
Aaro Koskinen44b751b2010-12-20 23:50:17 +02005569 SiS_SetReg(SISSR, 0x19, 0x40);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07005570 } else {
Aaro Koskinen44b751b2010-12-20 23:50:17 +02005571 SiS_SetReg(SISSR, 0x19, 0x20);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07005572 }
Aaro Koskinen44b751b2010-12-20 23:50:17 +02005573 SiS_SetReg(SISSR, 0x16, 0x00);
5574 SiS_SetReg(SISSR, 0x16, 0x80);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07005575 if((ivideo->chip == XGI_20) || (bios[0x1cb] != 0x0c)) {
5576 sisfb_post_xgi_delay(ivideo, 0x43);
5577 sisfb_post_xgi_delay(ivideo, 0x43);
5578 sisfb_post_xgi_delay(ivideo, 0x43);
Aaro Koskinen44b751b2010-12-20 23:50:17 +02005579 SiS_SetReg(SISSR, 0x18, 0x00);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07005580 if((ivideo->chip == XGI_20) ||
5581 (ivideo->revision_id == 2)) {
Aaro Koskinen44b751b2010-12-20 23:50:17 +02005582 SiS_SetReg(SISSR, 0x19, 0x40);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07005583 } else {
Aaro Koskinen44b751b2010-12-20 23:50:17 +02005584 SiS_SetReg(SISSR, 0x19, 0x20);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07005585 }
5586 } else if((ivideo->chip == XGI_40) && (bios[0x1cb] == 0x0c)) {
Aaro Koskinen44b751b2010-12-20 23:50:17 +02005587 /* SiS_SetReg(SISSR, 0x16, 0x0c); */ /* ? */
Thomas Winischhofer544393f2005-09-09 13:04:45 -07005588 }
Aaro Koskinen44b751b2010-12-20 23:50:17 +02005589 SiS_SetReg(SISSR, 0x16, 0x00);
5590 SiS_SetReg(SISSR, 0x16, 0x80);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07005591 sisfb_post_xgi_delay(ivideo, 4);
5592 v1 = 0x31; v2 = 0x03; v3 = 0x83; v4 = 0x03; v5 = 0x83;
5593 if(ivideo->haveXGIROM) {
5594 v1 = bios[0xf0];
5595 index = (ivideo->chip == XGI_20) ? 0x4b2 : 0x53e;
5596 v2 = bios[index];
5597 v3 = bios[index + 1];
5598 v4 = bios[index + 2];
5599 v5 = bios[index + 3];
5600 }
Aaro Koskinen44b751b2010-12-20 23:50:17 +02005601 SiS_SetReg(SISSR, 0x18, v1);
5602 SiS_SetReg(SISSR, 0x19, ((ivideo->chip == XGI_20) ? 0x02 : 0x01));
5603 SiS_SetReg(SISSR, 0x16, v2);
5604 SiS_SetReg(SISSR, 0x16, v3);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07005605 sisfb_post_xgi_delay(ivideo, 0x43);
Aaro Koskinen44b751b2010-12-20 23:50:17 +02005606 SiS_SetReg(SISSR, 0x1b, 0x03);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07005607 sisfb_post_xgi_delay(ivideo, 0x22);
Aaro Koskinen44b751b2010-12-20 23:50:17 +02005608 SiS_SetReg(SISSR, 0x18, v1);
5609 SiS_SetReg(SISSR, 0x19, 0x00);
5610 SiS_SetReg(SISSR, 0x16, v4);
5611 SiS_SetReg(SISSR, 0x16, v5);
5612 SiS_SetReg(SISSR, 0x1b, 0x00);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07005613 break;
5614 case 1:
Aaro Koskinenc9982d52011-02-13 22:11:27 +00005615 sisfb_post_xgi_ddr2(ivideo, regb);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07005616 break;
5617 default:
5618 sisfb_post_xgi_setclocks(ivideo, regb);
5619 if((ivideo->chip == XGI_40) &&
5620 ((ivideo->revision_id == 1) ||
5621 (ivideo->revision_id == 2))) {
Aaro Koskinen44b751b2010-12-20 23:50:17 +02005622 SiS_SetReg(SISCR, 0x82, bios[regb + 0x158]);
5623 SiS_SetReg(SISCR, 0x85, bios[regb + 0x160]);
5624 SiS_SetReg(SISCR, 0x86, bios[regb + 0x168]);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07005625 } else {
Aaro Koskinen44b751b2010-12-20 23:50:17 +02005626 SiS_SetReg(SISCR, 0x82, 0x88);
5627 SiS_SetReg(SISCR, 0x86, 0x00);
Aaro Koskinene57d4132010-12-20 23:50:16 +02005628 reg = SiS_GetReg(SISCR, 0x86);
Aaro Koskinen44b751b2010-12-20 23:50:17 +02005629 SiS_SetReg(SISCR, 0x86, 0x88);
5630 SiS_SetReg(SISCR, 0x82, 0x77);
5631 SiS_SetReg(SISCR, 0x85, 0x00);
Aaro Koskinene57d4132010-12-20 23:50:16 +02005632 reg = SiS_GetReg(SISCR, 0x85);
Aaro Koskinen44b751b2010-12-20 23:50:17 +02005633 SiS_SetReg(SISCR, 0x85, 0x88);
Aaro Koskinene57d4132010-12-20 23:50:16 +02005634 reg = SiS_GetReg(SISCR, 0x85);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07005635 v1 = cs160[regb]; v2 = cs158[regb];
5636 if(ivideo->haveXGIROM) {
5637 v1 = bios[regb + 0x160];
5638 v2 = bios[regb + 0x158];
5639 }
Aaro Koskinen44b751b2010-12-20 23:50:17 +02005640 SiS_SetReg(SISCR, 0x85, v1);
5641 SiS_SetReg(SISCR, 0x82, v2);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07005642 }
5643 if(ivideo->chip == XGI_40) {
Aaro Koskinen44b751b2010-12-20 23:50:17 +02005644 SiS_SetReg(SISCR, 0x97, 0x11);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07005645 }
5646 if((ivideo->chip == XGI_40) && (ivideo->revision_id == 2)) {
Aaro Koskinen44b751b2010-12-20 23:50:17 +02005647 SiS_SetReg(SISCR, 0x98, 0x01);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07005648 } else {
Aaro Koskinen44b751b2010-12-20 23:50:17 +02005649 SiS_SetReg(SISCR, 0x98, 0x03);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07005650 }
Aaro Koskinen44b751b2010-12-20 23:50:17 +02005651 SiS_SetReg(SISCR, 0x9a, 0x02);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07005652
5653 if(ivideo->chip == XGI_40) {
Aaro Koskinen44b751b2010-12-20 23:50:17 +02005654 SiS_SetReg(SISSR, 0x18, 0x01);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07005655 } else {
Aaro Koskinen44b751b2010-12-20 23:50:17 +02005656 SiS_SetReg(SISSR, 0x18, 0x00);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07005657 }
Aaro Koskinen44b751b2010-12-20 23:50:17 +02005658 SiS_SetReg(SISSR, 0x19, 0x40);
5659 SiS_SetReg(SISSR, 0x16, 0x00);
5660 SiS_SetReg(SISSR, 0x16, 0x80);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07005661 if((ivideo->chip == XGI_40) && (bios[0x1cb] != 0x0c)) {
5662 sisfb_post_xgi_delay(ivideo, 0x43);
5663 sisfb_post_xgi_delay(ivideo, 0x43);
5664 sisfb_post_xgi_delay(ivideo, 0x43);
Aaro Koskinen44b751b2010-12-20 23:50:17 +02005665 SiS_SetReg(SISSR, 0x18, 0x00);
5666 SiS_SetReg(SISSR, 0x19, 0x40);
5667 SiS_SetReg(SISSR, 0x16, 0x00);
5668 SiS_SetReg(SISSR, 0x16, 0x80);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07005669 }
5670 sisfb_post_xgi_delay(ivideo, 4);
5671 v1 = 0x31;
5672 if(ivideo->haveXGIROM) {
5673 v1 = bios[0xf0];
5674 }
Aaro Koskinen44b751b2010-12-20 23:50:17 +02005675 SiS_SetReg(SISSR, 0x18, v1);
5676 SiS_SetReg(SISSR, 0x19, 0x01);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07005677 if(ivideo->chip == XGI_40) {
Aaro Koskinen44b751b2010-12-20 23:50:17 +02005678 SiS_SetReg(SISSR, 0x16, bios[0x53e]);
5679 SiS_SetReg(SISSR, 0x16, bios[0x53f]);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07005680 } else {
Aaro Koskinen44b751b2010-12-20 23:50:17 +02005681 SiS_SetReg(SISSR, 0x16, 0x05);
5682 SiS_SetReg(SISSR, 0x16, 0x85);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07005683 }
5684 sisfb_post_xgi_delay(ivideo, 0x43);
5685 if(ivideo->chip == XGI_40) {
Aaro Koskinen44b751b2010-12-20 23:50:17 +02005686 SiS_SetReg(SISSR, 0x1b, 0x01);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07005687 } else {
Aaro Koskinen44b751b2010-12-20 23:50:17 +02005688 SiS_SetReg(SISSR, 0x1b, 0x03);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07005689 }
5690 sisfb_post_xgi_delay(ivideo, 0x22);
Aaro Koskinen44b751b2010-12-20 23:50:17 +02005691 SiS_SetReg(SISSR, 0x18, v1);
5692 SiS_SetReg(SISSR, 0x19, 0x00);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07005693 if(ivideo->chip == XGI_40) {
Aaro Koskinen44b751b2010-12-20 23:50:17 +02005694 SiS_SetReg(SISSR, 0x16, bios[0x540]);
5695 SiS_SetReg(SISSR, 0x16, bios[0x541]);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07005696 } else {
Aaro Koskinen44b751b2010-12-20 23:50:17 +02005697 SiS_SetReg(SISSR, 0x16, 0x05);
5698 SiS_SetReg(SISSR, 0x16, 0x85);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07005699 }
Aaro Koskinen44b751b2010-12-20 23:50:17 +02005700 SiS_SetReg(SISSR, 0x1b, 0x00);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07005701 }
5702
5703 regb = 0; /* ! */
5704 v1 = 0x03;
5705 if(ivideo->haveXGIROM) {
5706 v1 = bios[0x110 + regb];
5707 }
Aaro Koskinen44b751b2010-12-20 23:50:17 +02005708 SiS_SetReg(SISSR, 0x1b, v1);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07005709
5710 /* RAM size */
5711 v1 = 0x00; v2 = 0x00;
5712 if(ivideo->haveXGIROM) {
5713 v1 = bios[0x62];
5714 v2 = bios[0x63];
5715 }
5716 regb = 0; /* ! */
5717 regd = 1 << regb;
5718 if((v1 & 0x40) && (v2 & regd) && ivideo->haveXGIROM) {
5719
Aaro Koskinen44b751b2010-12-20 23:50:17 +02005720 SiS_SetReg(SISSR, 0x13, bios[regb + 0xe0]);
5721 SiS_SetReg(SISSR, 0x14, bios[regb + 0xe0 + 8]);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07005722
5723 } else {
Aaro Koskinen83ea0f12011-02-13 22:11:23 +00005724 int err;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07005725
5726 /* Set default mode, don't clear screen */
Richard Knutssonc30660ea2007-02-12 00:55:06 -08005727 ivideo->SiS_Pr.SiS_UseOEM = false;
5728 SiS_SetEnableDstn(&ivideo->SiS_Pr, false);
5729 SiS_SetEnableFstn(&ivideo->SiS_Pr, false);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07005730 ivideo->curFSTN = ivideo->curDSTN = 0;
5731 ivideo->SiS_Pr.VideoMemorySize = 8 << 20;
5732 SiSSetMode(&ivideo->SiS_Pr, 0x2e | 0x80);
5733
Aaro Koskinen44b751b2010-12-20 23:50:17 +02005734 SiS_SetReg(SISSR, 0x05, 0x86);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07005735
5736 /* Disable read-cache */
Aaro Koskinen667a8b42010-12-20 23:50:19 +02005737 SiS_SetRegAND(SISSR, 0x21, 0xdf);
Aaro Koskinen83ea0f12011-02-13 22:11:23 +00005738 err = sisfb_post_xgi_ramsize(ivideo);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07005739 /* Enable read-cache */
Aaro Koskinen27799d62010-12-20 23:50:18 +02005740 SiS_SetRegOR(SISSR, 0x21, 0x20);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07005741
Aaro Koskinen83ea0f12011-02-13 22:11:23 +00005742 if (err) {
5743 dev_err(&pdev->dev,
5744 "%s: RAM size detection failed: %d\n",
5745 __func__, err);
5746 return 0;
5747 }
Thomas Winischhofer544393f2005-09-09 13:04:45 -07005748 }
5749
5750#if 0
5751 printk(KERN_DEBUG "-----------------\n");
5752 for(i = 0; i < 0xff; i++) {
Aaro Koskinene57d4132010-12-20 23:50:16 +02005753 reg = SiS_GetReg(SISCR, i);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07005754 printk(KERN_DEBUG "CR%02x(%x) = 0x%02x\n", i, SISCR, reg);
5755 }
5756 for(i = 0; i < 0x40; i++) {
Aaro Koskinene57d4132010-12-20 23:50:16 +02005757 reg = SiS_GetReg(SISSR, i);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07005758 printk(KERN_DEBUG "SR%02x(%x) = 0x%02x\n", i, SISSR, reg);
5759 }
5760 printk(KERN_DEBUG "-----------------\n");
5761#endif
5762
5763 /* Sense CRT1 */
5764 if(ivideo->chip == XGI_20) {
Aaro Koskinen27799d62010-12-20 23:50:18 +02005765 SiS_SetRegOR(SISCR, 0x32, 0x20);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07005766 } else {
Aaro Koskinene57d4132010-12-20 23:50:16 +02005767 reg = SiS_GetReg(SISPART4, 0x00);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07005768 if((reg == 1) || (reg == 2)) {
5769 sisfb_sense_crt1(ivideo);
5770 } else {
Aaro Koskinen27799d62010-12-20 23:50:18 +02005771 SiS_SetRegOR(SISCR, 0x32, 0x20);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07005772 }
5773 }
5774
5775 /* Set default mode, don't clear screen */
Richard Knutssonc30660ea2007-02-12 00:55:06 -08005776 ivideo->SiS_Pr.SiS_UseOEM = false;
5777 SiS_SetEnableDstn(&ivideo->SiS_Pr, false);
5778 SiS_SetEnableFstn(&ivideo->SiS_Pr, false);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07005779 ivideo->curFSTN = ivideo->curDSTN = 0;
5780 SiSSetMode(&ivideo->SiS_Pr, 0x2e | 0x80);
5781
Aaro Koskinen44b751b2010-12-20 23:50:17 +02005782 SiS_SetReg(SISSR, 0x05, 0x86);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07005783
5784 /* Display off */
Aaro Koskinen27799d62010-12-20 23:50:18 +02005785 SiS_SetRegOR(SISSR, 0x01, 0x20);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07005786
5787 /* Save mode number in CR34 */
Aaro Koskinen44b751b2010-12-20 23:50:17 +02005788 SiS_SetReg(SISCR, 0x34, 0x2e);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07005789
5790 /* Let everyone know what the current mode is */
5791 ivideo->modeprechange = 0x2e;
5792
5793 if(ivideo->chip == XGI_40) {
Aaro Koskinene57d4132010-12-20 23:50:16 +02005794 reg = SiS_GetReg(SISCR, 0xca);
5795 v1 = SiS_GetReg(SISCR, 0xcc);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07005796 if((reg & 0x10) && (!(v1 & 0x04))) {
5797 printk(KERN_ERR
5798 "sisfb: Please connect power to the card.\n");
5799 return 0;
5800 }
5801 }
5802
5803 return 1;
5804}
5805#endif
5806
Greg Kroah-Hartman48c68c42012-12-21 13:07:39 -08005807static int sisfb_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
Thomas Winischhofer544393f2005-09-09 13:04:45 -07005808{
5809 struct sisfb_chip_info *chipinfo = &sisfb_chip_info[ent->driver_data];
5810 struct sis_video_info *ivideo = NULL;
5811 struct fb_info *sis_fb_info = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005812 u16 reg16;
5813 u8 reg;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07005814 int i, ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005815
Thomas Winischhofer544393f2005-09-09 13:04:45 -07005816 if(sisfb_off)
5817 return -ENXIO;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005818
Linus Torvalds1da177e2005-04-16 15:20:36 -07005819 sis_fb_info = framebuffer_alloc(sizeof(*ivideo), &pdev->dev);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07005820 if(!sis_fb_info)
5821 return -ENOMEM;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005822
5823 ivideo = (struct sis_video_info *)sis_fb_info->par;
5824 ivideo->memyselfandi = sis_fb_info;
5825
Thomas Winischhofer544393f2005-09-09 13:04:45 -07005826 ivideo->sisfb_id = SISFB_ID;
5827
Linus Torvalds1da177e2005-04-16 15:20:36 -07005828 if(card_list == NULL) {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07005829 ivideo->cardnumber = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005830 } else {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07005831 struct sis_video_info *countvideo = card_list;
5832 ivideo->cardnumber = 1;
Harvey Harrison5e2daeb2008-05-22 15:45:08 -07005833 while((countvideo = countvideo->next) != NULL)
Thomas Winischhofer544393f2005-09-09 13:04:45 -07005834 ivideo->cardnumber++;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005835 }
5836
5837 strncpy(ivideo->myid, chipinfo->chip_name, 30);
5838
5839 ivideo->warncount = 0;
5840 ivideo->chip_id = pdev->device;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07005841 ivideo->chip_vendor = pdev->vendor;
Auke Kok44c10132007-06-08 15:46:36 -07005842 ivideo->revision_id = pdev->revision;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07005843 ivideo->SiS_Pr.ChipRevision = ivideo->revision_id;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005844 pci_read_config_word(pdev, PCI_COMMAND, &reg16);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07005845 ivideo->sisvga_enabled = reg16 & 0x01;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005846 ivideo->pcibus = pdev->bus->number;
5847 ivideo->pcislot = PCI_SLOT(pdev->devfn);
5848 ivideo->pcifunc = PCI_FUNC(pdev->devfn);
5849 ivideo->subsysvendor = pdev->subsystem_vendor;
5850 ivideo->subsysdevice = pdev->subsystem_device;
5851
5852#ifndef MODULE
5853 if(sisfb_mode_idx == -1) {
5854 sisfb_get_vga_mode_from_kernel();
5855 }
5856#endif
5857
5858 ivideo->chip = chipinfo->chip;
Aaro Koskinen929c9722011-02-13 22:11:25 +00005859 ivideo->chip_real_id = chipinfo->chip;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005860 ivideo->sisvga_engine = chipinfo->vgaengine;
5861 ivideo->hwcursor_size = chipinfo->hwcursor_size;
5862 ivideo->CRT2_write_enable = chipinfo->CRT2_write_enable;
5863 ivideo->mni = chipinfo->mni;
5864
5865 ivideo->detectedpdc = 0xff;
5866 ivideo->detectedpdca = 0xff;
5867 ivideo->detectedlcda = 0xff;
5868
Richard Knutssonc30660ea2007-02-12 00:55:06 -08005869 ivideo->sisfb_thismonitor.datavalid = false;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005870
Thomas Winischhofer544393f2005-09-09 13:04:45 -07005871 ivideo->current_base = 0;
5872
5873 ivideo->engineok = 0;
5874
5875 ivideo->sisfb_was_boot_device = 0;
Adrian Bunk14aefd12008-07-23 21:31:12 -07005876
Thomas Winischhofer544393f2005-09-09 13:04:45 -07005877 if(pdev->resource[PCI_ROM_RESOURCE].flags & IORESOURCE_ROM_SHADOW) {
5878 if(ivideo->sisvga_enabled)
5879 ivideo->sisfb_was_boot_device = 1;
5880 else {
5881 printk(KERN_DEBUG "sisfb: PCI device is disabled, "
5882 "but marked as boot video device ???\n");
5883 printk(KERN_DEBUG "sisfb: I will not accept this "
5884 "as the primary VGA device\n");
5885 }
5886 }
Thomas Winischhofer544393f2005-09-09 13:04:45 -07005887
Linus Torvalds1da177e2005-04-16 15:20:36 -07005888 ivideo->sisfb_parm_mem = sisfb_parm_mem;
5889 ivideo->sisfb_accel = sisfb_accel;
5890 ivideo->sisfb_ypan = sisfb_ypan;
5891 ivideo->sisfb_max = sisfb_max;
5892 ivideo->sisfb_userom = sisfb_userom;
5893 ivideo->sisfb_useoem = sisfb_useoem;
5894 ivideo->sisfb_mode_idx = sisfb_mode_idx;
5895 ivideo->sisfb_parm_rate = sisfb_parm_rate;
5896 ivideo->sisfb_crt1off = sisfb_crt1off;
5897 ivideo->sisfb_forcecrt1 = sisfb_forcecrt1;
5898 ivideo->sisfb_crt2type = sisfb_crt2type;
5899 ivideo->sisfb_crt2flags = sisfb_crt2flags;
5900 /* pdc(a), scalelcd, special timing, lvdshl handled below */
5901 ivideo->sisfb_dstn = sisfb_dstn;
5902 ivideo->sisfb_fstn = sisfb_fstn;
5903 ivideo->sisfb_tvplug = sisfb_tvplug;
5904 ivideo->sisfb_tvstd = sisfb_tvstd;
5905 ivideo->tvxpos = sisfb_tvxposoffset;
5906 ivideo->tvypos = sisfb_tvyposoffset;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005907 ivideo->sisfb_nocrt2rate = sisfb_nocrt2rate;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005908 ivideo->refresh_rate = 0;
5909 if(ivideo->sisfb_parm_rate != -1) {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07005910 ivideo->refresh_rate = ivideo->sisfb_parm_rate;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005911 }
5912
5913 ivideo->SiS_Pr.UsePanelScaler = sisfb_scalelcd;
5914 ivideo->SiS_Pr.CenterScreen = -1;
5915 ivideo->SiS_Pr.SiS_CustomT = sisfb_specialtiming;
5916 ivideo->SiS_Pr.LVDSHL = sisfb_lvdshl;
5917
5918 ivideo->SiS_Pr.SiS_Backup70xx = 0xff;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07005919 ivideo->SiS_Pr.SiS_CHOverScan = -1;
Richard Knutssonc30660ea2007-02-12 00:55:06 -08005920 ivideo->SiS_Pr.SiS_ChSW = false;
5921 ivideo->SiS_Pr.SiS_UseLCDA = false;
5922 ivideo->SiS_Pr.HaveEMI = false;
5923 ivideo->SiS_Pr.HaveEMILCD = false;
5924 ivideo->SiS_Pr.OverruleEMI = false;
5925 ivideo->SiS_Pr.SiS_SensibleSR11 = false;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005926 ivideo->SiS_Pr.SiS_MyCR63 = 0x63;
5927 ivideo->SiS_Pr.PDC = -1;
5928 ivideo->SiS_Pr.PDCA = -1;
Richard Knutssonc30660ea2007-02-12 00:55:06 -08005929 ivideo->SiS_Pr.DDCPortMixup = false;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005930#ifdef CONFIG_FB_SIS_315
5931 if(ivideo->chip >= SIS_330) {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07005932 ivideo->SiS_Pr.SiS_MyCR63 = 0x53;
5933 if(ivideo->chip >= SIS_661) {
Richard Knutssonc30660ea2007-02-12 00:55:06 -08005934 ivideo->SiS_Pr.SiS_SensibleSR11 = true;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07005935 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07005936 }
5937#endif
5938
5939 memcpy(&ivideo->default_var, &my_default_var, sizeof(my_default_var));
5940
5941 pci_set_drvdata(pdev, ivideo);
5942
5943 /* Patch special cases */
5944 if((ivideo->nbridge = sisfb_get_northbridge(ivideo->chip))) {
5945 switch(ivideo->nbridge->device) {
5946#ifdef CONFIG_FB_SIS_300
5947 case PCI_DEVICE_ID_SI_730:
Thomas Winischhofer544393f2005-09-09 13:04:45 -07005948 ivideo->chip = SIS_730;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005949 strcpy(ivideo->myid, "SiS 730");
Thomas Winischhofer544393f2005-09-09 13:04:45 -07005950 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005951#endif
5952#ifdef CONFIG_FB_SIS_315
5953 case PCI_DEVICE_ID_SI_651:
5954 /* ivideo->chip is ok */
5955 strcpy(ivideo->myid, "SiS 651");
5956 break;
5957 case PCI_DEVICE_ID_SI_740:
Thomas Winischhofer544393f2005-09-09 13:04:45 -07005958 ivideo->chip = SIS_740;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005959 strcpy(ivideo->myid, "SiS 740");
5960 break;
5961 case PCI_DEVICE_ID_SI_661:
Thomas Winischhofer544393f2005-09-09 13:04:45 -07005962 ivideo->chip = SIS_661;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005963 strcpy(ivideo->myid, "SiS 661");
5964 break;
5965 case PCI_DEVICE_ID_SI_741:
Thomas Winischhofer544393f2005-09-09 13:04:45 -07005966 ivideo->chip = SIS_741;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005967 strcpy(ivideo->myid, "SiS 741");
5968 break;
5969 case PCI_DEVICE_ID_SI_760:
Thomas Winischhofer544393f2005-09-09 13:04:45 -07005970 ivideo->chip = SIS_760;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005971 strcpy(ivideo->myid, "SiS 760");
5972 break;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07005973 case PCI_DEVICE_ID_SI_761:
5974 ivideo->chip = SIS_761;
5975 strcpy(ivideo->myid, "SiS 761");
5976 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005977#endif
Thomas Winischhofer544393f2005-09-09 13:04:45 -07005978 default:
5979 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005980 }
5981 }
5982
Thomas Winischhofer544393f2005-09-09 13:04:45 -07005983 ivideo->SiS_Pr.ChipType = ivideo->chip;
5984
5985 ivideo->SiS_Pr.ivideo = (void *)ivideo;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005986
5987#ifdef CONFIG_FB_SIS_315
Thomas Winischhofer544393f2005-09-09 13:04:45 -07005988 if((ivideo->SiS_Pr.ChipType == SIS_315PRO) ||
5989 (ivideo->SiS_Pr.ChipType == SIS_315)) {
5990 ivideo->SiS_Pr.ChipType = SIS_315H;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005991 }
5992#endif
5993
Thomas Winischhofer544393f2005-09-09 13:04:45 -07005994 if(!ivideo->sisvga_enabled) {
5995 if(pci_enable_device(pdev)) {
Adrian Bunk0959f0c2007-05-08 00:39:50 -07005996 if(ivideo->nbridge) pci_dev_put(ivideo->nbridge);
Krzysztof Helt491bcc92009-06-16 15:34:36 -07005997 framebuffer_release(sis_fb_info);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07005998 return -EIO;
5999 }
6000 }
6001
Linus Torvalds1da177e2005-04-16 15:20:36 -07006002 ivideo->video_base = pci_resource_start(pdev, 0);
Aaro Koskinen32ed3032010-11-10 13:04:19 +02006003 ivideo->video_size = pci_resource_len(pdev, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006004 ivideo->mmio_base = pci_resource_start(pdev, 1);
6005 ivideo->mmio_size = pci_resource_len(pdev, 1);
6006 ivideo->SiS_Pr.RelIO = pci_resource_start(pdev, 2) + 0x30;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006007 ivideo->SiS_Pr.IOAddress = ivideo->vga_base = ivideo->SiS_Pr.RelIO;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006008
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006009 SiSRegInit(&ivideo->SiS_Pr, ivideo->SiS_Pr.IOAddress);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006010
6011#ifdef CONFIG_FB_SIS_300
6012 /* Find PCI systems for Chrontel/GPIO communication setup */
6013 if(ivideo->chip == SIS_630) {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006014 i = 0;
6015 do {
6016 if(mychswtable[i].subsysVendor == ivideo->subsysvendor &&
6017 mychswtable[i].subsysCard == ivideo->subsysdevice) {
Richard Knutssonc30660ea2007-02-12 00:55:06 -08006018 ivideo->SiS_Pr.SiS_ChSW = true;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006019 printk(KERN_DEBUG "sisfb: Identified [%s %s] "
6020 "requiring Chrontel/GPIO setup\n",
6021 mychswtable[i].vendorName,
6022 mychswtable[i].cardName);
Adrian Bunk0959f0c2007-05-08 00:39:50 -07006023 ivideo->lpcdev = pci_get_device(PCI_VENDOR_ID_SI, 0x0008, NULL);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006024 break;
6025 }
6026 i++;
6027 } while(mychswtable[i].subsysVendor != 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006028 }
6029#endif
6030
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006031#ifdef CONFIG_FB_SIS_315
6032 if((ivideo->chip == SIS_760) && (ivideo->nbridge)) {
Adrian Bunk0959f0c2007-05-08 00:39:50 -07006033 ivideo->lpcdev = pci_get_slot(ivideo->nbridge->bus, (2 << 3));
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006034 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07006035#endif
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006036
Aaro Koskinen44b751b2010-12-20 23:50:17 +02006037 SiS_SetReg(SISSR, 0x05, 0x86);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006038
6039 if( (!ivideo->sisvga_enabled)
6040#if !defined(__i386__) && !defined(__x86_64__)
6041 || (sisfb_resetcard)
6042#endif
6043 ) {
6044 for(i = 0x30; i <= 0x3f; i++) {
Aaro Koskinen44b751b2010-12-20 23:50:17 +02006045 SiS_SetReg(SISCR, i, 0x00);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006046 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07006047 }
6048
6049 /* Find out about current video mode */
6050 ivideo->modeprechange = 0x03;
Aaro Koskinene57d4132010-12-20 23:50:16 +02006051 reg = SiS_GetReg(SISCR, 0x34);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006052 if(reg & 0x7f) {
6053 ivideo->modeprechange = reg & 0x7f;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006054 } else if(ivideo->sisvga_enabled) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07006055#if defined(__i386__) || defined(__x86_64__)
Adrian Bunk14aefd12008-07-23 21:31:12 -07006056 unsigned char __iomem *tt = ioremap(0x400, 0x100);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006057 if(tt) {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006058 ivideo->modeprechange = readb(tt + 0x49);
6059 iounmap(tt);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006060 }
6061#endif
6062 }
6063
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006064 /* Search and copy ROM image */
6065 ivideo->bios_abase = NULL;
6066 ivideo->SiS_Pr.VirtualRomBase = NULL;
Richard Knutssonc30660ea2007-02-12 00:55:06 -08006067 ivideo->SiS_Pr.UseROM = false;
6068 ivideo->haveXGIROM = ivideo->SiS_Pr.SiS_XGIROM = false;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006069 if(ivideo->sisfb_userom) {
6070 ivideo->SiS_Pr.VirtualRomBase = sisfb_find_rom(pdev);
6071 ivideo->bios_abase = ivideo->SiS_Pr.VirtualRomBase;
Richard Knutssonc30660ea2007-02-12 00:55:06 -08006072 ivideo->SiS_Pr.UseROM = (bool)(ivideo->SiS_Pr.VirtualRomBase);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006073 printk(KERN_INFO "sisfb: Video ROM %sfound\n",
6074 ivideo->SiS_Pr.UseROM ? "" : "not ");
6075 if((ivideo->SiS_Pr.UseROM) && (ivideo->chip >= XGI_20)) {
Richard Knutssonc30660ea2007-02-12 00:55:06 -08006076 ivideo->SiS_Pr.UseROM = false;
6077 ivideo->haveXGIROM = ivideo->SiS_Pr.SiS_XGIROM = true;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006078 if( (ivideo->revision_id == 2) &&
6079 (!(ivideo->bios_abase[0x1d1] & 0x01)) ) {
Richard Knutssonc30660ea2007-02-12 00:55:06 -08006080 ivideo->SiS_Pr.DDCPortMixup = true;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006081 }
6082 }
6083 } else {
6084 printk(KERN_INFO "sisfb: Video ROM usage disabled\n");
6085 }
6086
6087 /* Find systems for special custom timing */
6088 if(ivideo->SiS_Pr.SiS_CustomT == CUT_NONE) {
6089 sisfb_detect_custom_timing(ivideo);
6090 }
6091
Aaro Koskinen929c9722011-02-13 22:11:25 +00006092#ifdef CONFIG_FB_SIS_315
6093 if (ivideo->chip == XGI_20) {
6094 /* Check if our Z7 chip is actually Z9 */
6095 SiS_SetRegOR(SISCR, 0x4a, 0x40); /* GPIOG EN */
6096 reg = SiS_GetReg(SISCR, 0x48);
6097 if (reg & 0x02) { /* GPIOG */
6098 ivideo->chip_real_id = XGI_21;
6099 dev_info(&pdev->dev, "Z9 detected\n");
6100 }
6101 }
6102#endif
6103
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006104 /* POST card in case this has not been done by the BIOS */
6105 if( (!ivideo->sisvga_enabled)
6106#if !defined(__i386__) && !defined(__x86_64__)
6107 || (sisfb_resetcard)
6108#endif
6109 ) {
6110#ifdef CONFIG_FB_SIS_300
6111 if(ivideo->sisvga_engine == SIS_300_VGA) {
6112 if(ivideo->chip == SIS_300) {
6113 sisfb_post_sis300(pdev);
6114 ivideo->sisfb_can_post = 1;
6115 }
6116 }
6117#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -07006118
6119#ifdef CONFIG_FB_SIS_315
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006120 if(ivideo->sisvga_engine == SIS_315_VGA) {
6121 int result = 1;
6122 /* if((ivideo->chip == SIS_315H) ||
Linus Torvalds1da177e2005-04-16 15:20:36 -07006123 (ivideo->chip == SIS_315) ||
6124 (ivideo->chip == SIS_315PRO) ||
6125 (ivideo->chip == SIS_330)) {
6126 sisfb_post_sis315330(pdev);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006127 } else */ if(ivideo->chip == XGI_20) {
6128 result = sisfb_post_xgi(pdev);
6129 ivideo->sisfb_can_post = 1;
6130 } else if((ivideo->chip == XGI_40) && ivideo->haveXGIROM) {
6131 result = sisfb_post_xgi(pdev);
6132 ivideo->sisfb_can_post = 1;
6133 } else {
6134 printk(KERN_INFO "sisfb: Card is not "
6135 "POSTed and sisfb can't do this either.\n");
6136 }
6137 if(!result) {
6138 printk(KERN_ERR "sisfb: Failed to POST card\n");
6139 ret = -ENODEV;
6140 goto error_3;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006141 }
6142 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07006143#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -07006144 }
6145
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006146 ivideo->sisfb_card_posted = 1;
6147
6148 /* Find out about RAM size */
6149 if(sisfb_get_dram_size(ivideo)) {
6150 printk(KERN_INFO "sisfb: Fatal error: Unable to determine VRAM size.\n");
6151 ret = -ENODEV;
6152 goto error_3;
6153 }
6154
6155
6156 /* Enable PCI addressing and MMIO */
Linus Torvalds1da177e2005-04-16 15:20:36 -07006157 if((ivideo->sisfb_mode_idx < 0) ||
6158 ((sisbios_mode[ivideo->sisfb_mode_idx].mode_no[ivideo->mni]) != 0xFF)) {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006159 /* Enable PCI_LINEAR_ADDRESSING and MMIO_ENABLE */
Aaro Koskinen27799d62010-12-20 23:50:18 +02006160 SiS_SetRegOR(SISSR, IND_SIS_PCI_ADDRESS_SET, (SIS_PCI_ADDR_ENABLE | SIS_MEM_MAP_IO_ENABLE));
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006161 /* Enable 2D accelerator engine */
Aaro Koskinen27799d62010-12-20 23:50:18 +02006162 SiS_SetRegOR(SISSR, IND_SIS_MODULE_ENABLE, SIS_ENABLE_2D);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006163 }
6164
6165 if(sisfb_pdc != 0xff) {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006166 if(ivideo->sisvga_engine == SIS_300_VGA)
6167 sisfb_pdc &= 0x3c;
6168 else
6169 sisfb_pdc &= 0x1f;
6170 ivideo->SiS_Pr.PDC = sisfb_pdc;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006171 }
6172#ifdef CONFIG_FB_SIS_315
6173 if(ivideo->sisvga_engine == SIS_315_VGA) {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006174 if(sisfb_pdca != 0xff)
6175 ivideo->SiS_Pr.PDCA = sisfb_pdca & 0x1f;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006176 }
6177#endif
6178
6179 if(!request_mem_region(ivideo->video_base, ivideo->video_size, "sisfb FB")) {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006180 printk(KERN_ERR "sisfb: Fatal error: Unable to reserve %dMB framebuffer memory\n",
6181 (int)(ivideo->video_size >> 20));
Linus Torvalds1da177e2005-04-16 15:20:36 -07006182 printk(KERN_ERR "sisfb: Is there another framebuffer driver active?\n");
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006183 ret = -ENODEV;
6184 goto error_3;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006185 }
6186
6187 if(!request_mem_region(ivideo->mmio_base, ivideo->mmio_size, "sisfb MMIO")) {
6188 printk(KERN_ERR "sisfb: Fatal error: Unable to reserve MMIO region\n");
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006189 ret = -ENODEV;
6190 goto error_2;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006191 }
6192
6193 ivideo->video_vbase = ioremap(ivideo->video_base, ivideo->video_size);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006194 ivideo->SiS_Pr.VideoMemoryAddress = ivideo->video_vbase;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006195 if(!ivideo->video_vbase) {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006196 printk(KERN_ERR "sisfb: Fatal error: Unable to map framebuffer memory\n");
6197 ret = -ENODEV;
6198 goto error_1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006199 }
6200
6201 ivideo->mmio_vbase = ioremap(ivideo->mmio_base, ivideo->mmio_size);
6202 if(!ivideo->mmio_vbase) {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006203 printk(KERN_ERR "sisfb: Fatal error: Unable to map MMIO region\n");
6204 ret = -ENODEV;
6205error_0: iounmap(ivideo->video_vbase);
6206error_1: release_mem_region(ivideo->video_base, ivideo->video_size);
6207error_2: release_mem_region(ivideo->mmio_base, ivideo->mmio_size);
6208error_3: vfree(ivideo->bios_abase);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006209 if(ivideo->lpcdev)
Adrian Bunk0959f0c2007-05-08 00:39:50 -07006210 pci_dev_put(ivideo->lpcdev);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006211 if(ivideo->nbridge)
Adrian Bunk0959f0c2007-05-08 00:39:50 -07006212 pci_dev_put(ivideo->nbridge);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006213 if(!ivideo->sisvga_enabled)
6214 pci_disable_device(pdev);
Krzysztof Helt491bcc92009-06-16 15:34:36 -07006215 framebuffer_release(sis_fb_info);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006216 return ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006217 }
6218
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006219 printk(KERN_INFO "sisfb: Video RAM at 0x%lx, mapped to 0x%lx, size %ldk\n",
6220 ivideo->video_base, (unsigned long)ivideo->video_vbase, ivideo->video_size / 1024);
6221
6222 if(ivideo->video_offset) {
6223 printk(KERN_INFO "sisfb: Viewport offset %ldk\n",
6224 ivideo->video_offset / 1024);
6225 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07006226
6227 printk(KERN_INFO "sisfb: MMIO at 0x%lx, mapped to 0x%lx, size %ldk\n",
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006228 ivideo->mmio_base, (unsigned long)ivideo->mmio_vbase, ivideo->mmio_size / 1024);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006229
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006230
6231 /* Determine the size of the command queue */
6232 if(ivideo->sisvga_engine == SIS_300_VGA) {
6233 ivideo->cmdQueueSize = TURBO_QUEUE_AREA_SIZE;
6234 } else {
6235 if(ivideo->chip == XGI_20) {
6236 ivideo->cmdQueueSize = COMMAND_QUEUE_AREA_SIZE_Z7;
6237 } else {
6238 ivideo->cmdQueueSize = COMMAND_QUEUE_AREA_SIZE;
6239 }
6240 }
6241
6242 /* Engines are no longer initialized here; this is
6243 * now done after the first mode-switch (if the
6244 * submitted var has its acceleration flags set).
6245 */
6246
6247 /* Calculate the base of the (unused) hw cursor */
6248 ivideo->hwcursor_vbase = ivideo->video_vbase
6249 + ivideo->video_size
6250 - ivideo->cmdQueueSize
6251 - ivideo->hwcursor_size;
6252 ivideo->caps |= HW_CURSOR_CAP;
6253
6254 /* Initialize offscreen memory manager */
Linus Torvalds1da177e2005-04-16 15:20:36 -07006255 if((ivideo->havenoheap = sisfb_heap_init(ivideo))) {
6256 printk(KERN_WARNING "sisfb: Failed to initialize offscreen memory heap\n");
6257 }
6258
6259 /* Used for clearing the screen only, therefore respect our mem limit */
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006260 ivideo->SiS_Pr.VideoMemoryAddress += ivideo->video_offset;
6261 ivideo->SiS_Pr.VideoMemorySize = ivideo->sisfb_mem;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006262
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006263 ivideo->mtrr = -1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006264
6265 ivideo->vbflags = 0;
6266 ivideo->lcddefmodeidx = DEFAULT_LCDMODE;
6267 ivideo->tvdefmodeidx = DEFAULT_TVMODE;
6268 ivideo->defmodeidx = DEFAULT_MODE;
6269
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006270 ivideo->newrom = 0;
6271 if(ivideo->chip < XGI_20) {
6272 if(ivideo->bios_abase) {
6273 ivideo->newrom = SiSDetermineROMLayout661(&ivideo->SiS_Pr);
6274 }
6275 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07006276
6277 if((ivideo->sisfb_mode_idx < 0) ||
6278 ((sisbios_mode[ivideo->sisfb_mode_idx].mode_no[ivideo->mni]) != 0xFF)) {
6279
6280 sisfb_sense_crt1(ivideo);
6281
6282 sisfb_get_VB_type(ivideo);
6283
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006284 if(ivideo->vbflags2 & VB2_VIDEOBRIDGE) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07006285 sisfb_detect_VB_connect(ivideo);
6286 }
6287
6288 ivideo->currentvbflags = ivideo->vbflags & (VB_VIDEOBRIDGE | TV_STANDARD);
6289
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006290 /* Decide on which CRT2 device to use */
6291 if(ivideo->vbflags2 & VB2_VIDEOBRIDGE) {
6292 if(ivideo->sisfb_crt2type != -1) {
6293 if((ivideo->sisfb_crt2type == CRT2_LCD) &&
6294 (ivideo->vbflags & CRT2_LCD)) {
6295 ivideo->currentvbflags |= CRT2_LCD;
6296 } else if(ivideo->sisfb_crt2type != CRT2_LCD) {
6297 ivideo->currentvbflags |= ivideo->sisfb_crt2type;
6298 }
6299 } else {
6300 /* Chrontel 700x TV detection often unreliable, therefore
6301 * use a different default order on such machines
6302 */
6303 if((ivideo->sisvga_engine == SIS_300_VGA) &&
6304 (ivideo->vbflags2 & VB2_CHRONTEL)) {
6305 if(ivideo->vbflags & CRT2_LCD)
6306 ivideo->currentvbflags |= CRT2_LCD;
6307 else if(ivideo->vbflags & CRT2_TV)
6308 ivideo->currentvbflags |= CRT2_TV;
6309 else if(ivideo->vbflags & CRT2_VGA)
6310 ivideo->currentvbflags |= CRT2_VGA;
6311 } else {
6312 if(ivideo->vbflags & CRT2_TV)
6313 ivideo->currentvbflags |= CRT2_TV;
6314 else if(ivideo->vbflags & CRT2_LCD)
6315 ivideo->currentvbflags |= CRT2_LCD;
6316 else if(ivideo->vbflags & CRT2_VGA)
6317 ivideo->currentvbflags |= CRT2_VGA;
6318 }
6319 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07006320 }
6321
6322 if(ivideo->vbflags & CRT2_LCD) {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006323 sisfb_detect_lcd_type(ivideo);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006324 }
6325
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006326 sisfb_save_pdc_emi(ivideo);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006327
6328 if(!ivideo->sisfb_crt1off) {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006329 sisfb_handle_ddc(ivideo, &ivideo->sisfb_thismonitor, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006330 } else {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006331 if((ivideo->vbflags2 & VB2_SISTMDSBRIDGE) &&
6332 (ivideo->vbflags & (CRT2_VGA | CRT2_LCD))) {
6333 sisfb_handle_ddc(ivideo, &ivideo->sisfb_thismonitor, 1);
6334 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07006335 }
6336
6337 if(ivideo->sisfb_mode_idx >= 0) {
6338 int bu = ivideo->sisfb_mode_idx;
6339 ivideo->sisfb_mode_idx = sisfb_validate_mode(ivideo,
6340 ivideo->sisfb_mode_idx, ivideo->currentvbflags);
6341 if(bu != ivideo->sisfb_mode_idx) {
6342 printk(KERN_ERR "Mode %dx%dx%d failed validation\n",
6343 sisbios_mode[bu].xres,
6344 sisbios_mode[bu].yres,
6345 sisbios_mode[bu].bpp);
6346 }
6347 }
6348
6349 if(ivideo->sisfb_mode_idx < 0) {
6350 switch(ivideo->currentvbflags & VB_DISPTYPE_DISP2) {
6351 case CRT2_LCD:
6352 ivideo->sisfb_mode_idx = ivideo->lcddefmodeidx;
6353 break;
6354 case CRT2_TV:
6355 ivideo->sisfb_mode_idx = ivideo->tvdefmodeidx;
6356 break;
6357 default:
6358 ivideo->sisfb_mode_idx = ivideo->defmodeidx;
6359 break;
6360 }
6361 }
6362
6363 ivideo->mode_no = sisbios_mode[ivideo->sisfb_mode_idx].mode_no[ivideo->mni];
6364
6365 if(ivideo->refresh_rate != 0) {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006366 sisfb_search_refresh_rate(ivideo, ivideo->refresh_rate,
6367 ivideo->sisfb_mode_idx);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006368 }
6369
6370 if(ivideo->rate_idx == 0) {
6371 ivideo->rate_idx = sisbios_mode[ivideo->sisfb_mode_idx].rate_idx;
6372 ivideo->refresh_rate = 60;
6373 }
6374
6375 if(ivideo->sisfb_thismonitor.datavalid) {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006376 if(!sisfb_verify_rate(ivideo, &ivideo->sisfb_thismonitor,
6377 ivideo->sisfb_mode_idx,
6378 ivideo->rate_idx,
6379 ivideo->refresh_rate)) {
6380 printk(KERN_INFO "sisfb: WARNING: Refresh rate "
6381 "exceeds monitor specs!\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07006382 }
6383 }
6384
6385 ivideo->video_bpp = sisbios_mode[ivideo->sisfb_mode_idx].bpp;
6386 ivideo->video_width = sisbios_mode[ivideo->sisfb_mode_idx].xres;
6387 ivideo->video_height = sisbios_mode[ivideo->sisfb_mode_idx].yres;
6388
6389 sisfb_set_vparms(ivideo);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006390
Linus Torvalds1da177e2005-04-16 15:20:36 -07006391 printk(KERN_INFO "sisfb: Default mode is %dx%dx%d (%dHz)\n",
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006392 ivideo->video_width, ivideo->video_height, ivideo->video_bpp,
Linus Torvalds1da177e2005-04-16 15:20:36 -07006393 ivideo->refresh_rate);
6394
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006395 /* Set up the default var according to chosen default display mode */
Linus Torvalds1da177e2005-04-16 15:20:36 -07006396 ivideo->default_var.xres = ivideo->default_var.xres_virtual = ivideo->video_width;
6397 ivideo->default_var.yres = ivideo->default_var.yres_virtual = ivideo->video_height;
6398 ivideo->default_var.bits_per_pixel = ivideo->video_bpp;
6399
6400 sisfb_bpp_to_var(ivideo, &ivideo->default_var);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006401
Linus Torvalds1da177e2005-04-16 15:20:36 -07006402 ivideo->default_var.pixclock = (u32) (1000000000 /
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006403 sisfb_mode_rate_to_dclock(&ivideo->SiS_Pr, ivideo->mode_no, ivideo->rate_idx));
6404
6405 if(sisfb_mode_rate_to_ddata(&ivideo->SiS_Pr, ivideo->mode_no,
6406 ivideo->rate_idx, &ivideo->default_var)) {
6407 if((ivideo->default_var.vmode & FB_VMODE_MASK) == FB_VMODE_DOUBLE) {
6408 ivideo->default_var.pixclock <<= 1;
6409 }
6410 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07006411
6412 if(ivideo->sisfb_ypan) {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006413 /* Maximize regardless of sisfb_max at startup */
6414 ivideo->default_var.yres_virtual =
6415 sisfb_calc_maxyres(ivideo, &ivideo->default_var);
6416 if(ivideo->default_var.yres_virtual < ivideo->default_var.yres) {
6417 ivideo->default_var.yres_virtual = ivideo->default_var.yres;
6418 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07006419 }
6420
6421 sisfb_calc_pitch(ivideo, &ivideo->default_var);
6422
6423 ivideo->accel = 0;
6424 if(ivideo->sisfb_accel) {
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006425 ivideo->accel = -1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006426#ifdef STUPID_ACCELF_TEXT_SHIT
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006427 ivideo->default_var.accel_flags |= FB_ACCELF_TEXT;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006428#endif
6429 }
6430 sisfb_initaccel(ivideo);
6431
6432#if defined(FBINFO_HWACCEL_DISABLED) && defined(FBINFO_HWACCEL_XPAN)
6433 sis_fb_info->flags = FBINFO_DEFAULT |
6434 FBINFO_HWACCEL_YPAN |
6435 FBINFO_HWACCEL_XPAN |
6436 FBINFO_HWACCEL_COPYAREA |
6437 FBINFO_HWACCEL_FILLRECT |
6438 ((ivideo->accel) ? 0 : FBINFO_HWACCEL_DISABLED);
6439#else
6440 sis_fb_info->flags = FBINFO_FLAG_DEFAULT;
6441#endif
6442 sis_fb_info->var = ivideo->default_var;
6443 sis_fb_info->fix = ivideo->sisfb_fix;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006444 sis_fb_info->screen_base = ivideo->video_vbase + ivideo->video_offset;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006445 sis_fb_info->fbops = &sisfb_ops;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006446 sis_fb_info->pseudo_palette = ivideo->pseudo_palette;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006447
Linus Torvalds1da177e2005-04-16 15:20:36 -07006448 fb_alloc_cmap(&sis_fb_info->cmap, 256 , 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006449
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006450 printk(KERN_DEBUG "sisfb: Initial vbflags 0x%x\n", (int)ivideo->vbflags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006451
6452#ifdef CONFIG_MTRR
6453 ivideo->mtrr = mtrr_add(ivideo->video_base, ivideo->video_size,
6454 MTRR_TYPE_WRCOMB, 1);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006455 if(ivideo->mtrr < 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07006456 printk(KERN_DEBUG "sisfb: Failed to add MTRRs\n");
6457 }
6458#endif
6459
Linus Torvalds1da177e2005-04-16 15:20:36 -07006460 if(register_framebuffer(sis_fb_info) < 0) {
6461 printk(KERN_ERR "sisfb: Fatal error: Failed to register framebuffer\n");
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006462 ret = -EINVAL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006463 iounmap(ivideo->mmio_vbase);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006464 goto error_0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006465 }
6466
6467 ivideo->registered = 1;
6468
6469 /* Enlist us */
6470 ivideo->next = card_list;
6471 card_list = ivideo;
6472
6473 printk(KERN_INFO "sisfb: 2D acceleration is %s, y-panning %s\n",
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006474 ivideo->sisfb_accel ? "enabled" : "disabled",
6475 ivideo->sisfb_ypan ?
6476 (ivideo->sisfb_max ? "enabled (auto-max)" :
6477 "enabled (no auto-max)") :
6478 "disabled");
Linus Torvalds1da177e2005-04-16 15:20:36 -07006479
6480
Joe Perches31b67802013-09-19 18:35:55 -07006481 fb_info(sis_fb_info, "%s frame buffer device version %d.%d.%d\n",
6482 ivideo->myid, VER_MAJOR, VER_MINOR, VER_LEVEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006483
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006484 printk(KERN_INFO "sisfb: Copyright (C) 2001-2005 Thomas Winischhofer\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07006485
6486 } /* if mode = "none" */
6487
6488 return 0;
6489}
6490
6491/*****************************************************/
6492/* PCI DEVICE HANDLING */
6493/*****************************************************/
6494
Greg Kroah-Hartman48c68c42012-12-21 13:07:39 -08006495static void sisfb_remove(struct pci_dev *pdev)
Linus Torvalds1da177e2005-04-16 15:20:36 -07006496{
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006497 struct sis_video_info *ivideo = pci_get_drvdata(pdev);
6498 struct fb_info *sis_fb_info = ivideo->memyselfandi;
6499 int registered = ivideo->registered;
6500 int modechanged = ivideo->modechanged;
6501
Linus Torvalds1da177e2005-04-16 15:20:36 -07006502 /* Unmap */
Linus Torvalds1da177e2005-04-16 15:20:36 -07006503 iounmap(ivideo->mmio_vbase);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006504 iounmap(ivideo->video_vbase);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006505
6506 /* Release mem regions */
6507 release_mem_region(ivideo->video_base, ivideo->video_size);
6508 release_mem_region(ivideo->mmio_base, ivideo->mmio_size);
6509
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006510 vfree(ivideo->bios_abase);
6511
6512 if(ivideo->lpcdev)
Adrian Bunk0959f0c2007-05-08 00:39:50 -07006513 pci_dev_put(ivideo->lpcdev);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006514
6515 if(ivideo->nbridge)
Adrian Bunk0959f0c2007-05-08 00:39:50 -07006516 pci_dev_put(ivideo->nbridge);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006517
Linus Torvalds1da177e2005-04-16 15:20:36 -07006518#ifdef CONFIG_MTRR
6519 /* Release MTRR region */
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006520 if(ivideo->mtrr >= 0)
Linus Torvalds1da177e2005-04-16 15:20:36 -07006521 mtrr_del(ivideo->mtrr, ivideo->video_base, ivideo->video_size);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006522#endif
6523
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006524 /* If device was disabled when starting, disable
6525 * it when quitting.
6526 */
6527 if(!ivideo->sisvga_enabled)
6528 pci_disable_device(pdev);
6529
Linus Torvalds1da177e2005-04-16 15:20:36 -07006530 /* Unregister the framebuffer */
6531 if(ivideo->registered) {
6532 unregister_framebuffer(sis_fb_info);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006533 framebuffer_release(sis_fb_info);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006534 }
6535
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006536 /* OK, our ivideo is gone for good from here. */
Linus Torvalds1da177e2005-04-16 15:20:36 -07006537
6538 /* TODO: Restore the initial mode
6539 * This sounds easy but is as good as impossible
6540 * on many machines with SiS chip and video bridge
6541 * since text modes are always set up differently
6542 * from machine to machine. Depends on the type
6543 * of integration between chipset and bridge.
6544 */
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006545 if(registered && modechanged)
6546 printk(KERN_INFO
6547 "sisfb: Restoring of text mode not supported yet\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07006548};
6549
6550static struct pci_driver sisfb_driver = {
6551 .name = "sisfb",
6552 .id_table = sisfb_pci_table,
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006553 .probe = sisfb_probe,
Greg Kroah-Hartman48c68c42012-12-21 13:07:39 -08006554 .remove = sisfb_remove,
Linus Torvalds1da177e2005-04-16 15:20:36 -07006555};
6556
Adrian Bunk14aefd12008-07-23 21:31:12 -07006557static int __init sisfb_init(void)
Linus Torvalds1da177e2005-04-16 15:20:36 -07006558{
Linus Torvalds1da177e2005-04-16 15:20:36 -07006559#ifndef MODULE
6560 char *options = NULL;
6561
6562 if(fb_get_options("sisfb", &options))
6563 return -ENODEV;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006564
Linus Torvalds1da177e2005-04-16 15:20:36 -07006565 sisfb_setup(options);
6566#endif
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006567 return pci_register_driver(&sisfb_driver);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006568}
6569
Linus Torvalds1da177e2005-04-16 15:20:36 -07006570#ifndef MODULE
6571module_init(sisfb_init);
6572#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -07006573
6574/*****************************************************/
6575/* MODULE */
6576/*****************************************************/
6577
6578#ifdef MODULE
6579
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006580static char *mode = NULL;
6581static int vesa = -1;
6582static unsigned int rate = 0;
6583static unsigned int crt1off = 1;
6584static unsigned int mem = 0;
6585static char *forcecrt2type = NULL;
6586static int forcecrt1 = -1;
6587static int pdc = -1;
6588static int pdc1 = -1;
6589static int noaccel = -1;
6590static int noypan = -1;
6591static int nomax = -1;
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006592static int userom = -1;
6593static int useoem = -1;
6594static char *tvstandard = NULL;
6595static int nocrt2rate = 0;
6596static int scalelcd = -1;
6597static char *specialtiming = NULL;
6598static int lvdshl = -1;
6599static int tvxposoffset = 0, tvyposoffset = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006600#if !defined(__i386__) && !defined(__x86_64__)
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006601static int resetcard = 0;
6602static int videoram = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006603#endif
6604
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006605static int __init sisfb_init_module(void)
6606{
6607 sisfb_setdefaultparms();
6608
6609 if(rate)
6610 sisfb_parm_rate = rate;
6611
6612 if((scalelcd == 0) || (scalelcd == 1))
6613 sisfb_scalelcd = scalelcd ^ 1;
6614
6615 /* Need to check crt2 type first for fstn/dstn */
6616
6617 if(forcecrt2type)
6618 sisfb_search_crt2type(forcecrt2type);
6619
6620 if(tvstandard)
6621 sisfb_search_tvstd(tvstandard);
6622
6623 if(mode)
Richard Knutssonc30660ea2007-02-12 00:55:06 -08006624 sisfb_search_mode(mode, false);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006625 else if(vesa != -1)
Richard Knutssonc30660ea2007-02-12 00:55:06 -08006626 sisfb_search_vesamode(vesa, false);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006627
6628 sisfb_crt1off = (crt1off == 0) ? 1 : 0;
6629
6630 sisfb_forcecrt1 = forcecrt1;
6631 if(forcecrt1 == 1)
6632 sisfb_crt1off = 0;
6633 else if(forcecrt1 == 0)
6634 sisfb_crt1off = 1;
6635
6636 if(noaccel == 1)
6637 sisfb_accel = 0;
6638 else if(noaccel == 0)
6639 sisfb_accel = 1;
6640
6641 if(noypan == 1)
6642 sisfb_ypan = 0;
6643 else if(noypan == 0)
6644 sisfb_ypan = 1;
6645
6646 if(nomax == 1)
6647 sisfb_max = 0;
6648 else if(nomax == 0)
6649 sisfb_max = 1;
6650
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006651 if(mem)
6652 sisfb_parm_mem = mem;
6653
6654 if(userom != -1)
6655 sisfb_userom = userom;
6656
6657 if(useoem != -1)
6658 sisfb_useoem = useoem;
6659
6660 if(pdc != -1)
6661 sisfb_pdc = (pdc & 0x7f);
6662
6663 if(pdc1 != -1)
6664 sisfb_pdca = (pdc1 & 0x1f);
6665
6666 sisfb_nocrt2rate = nocrt2rate;
6667
6668 if(specialtiming)
6669 sisfb_search_specialtiming(specialtiming);
6670
6671 if((lvdshl >= 0) && (lvdshl <= 3))
6672 sisfb_lvdshl = lvdshl;
6673
6674 sisfb_tvxposoffset = tvxposoffset;
6675 sisfb_tvyposoffset = tvyposoffset;
6676
6677#if !defined(__i386__) && !defined(__x86_64__)
6678 sisfb_resetcard = (resetcard) ? 1 : 0;
6679 if(videoram)
6680 sisfb_videoram = videoram;
6681#endif
6682
6683 return sisfb_init();
6684}
6685
6686static void __exit sisfb_remove_module(void)
6687{
6688 pci_unregister_driver(&sisfb_driver);
6689 printk(KERN_DEBUG "sisfb: Module unloaded\n");
6690}
6691
6692module_init(sisfb_init_module);
6693module_exit(sisfb_remove_module);
6694
6695MODULE_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 -07006696MODULE_LICENSE("GPL");
6697MODULE_AUTHOR("Thomas Winischhofer <thomas@winischhofer.net>, Others");
6698
Linus Torvalds1da177e2005-04-16 15:20:36 -07006699module_param(mem, int, 0);
6700module_param(noaccel, int, 0);
6701module_param(noypan, int, 0);
6702module_param(nomax, int, 0);
6703module_param(userom, int, 0);
6704module_param(useoem, int, 0);
6705module_param(mode, charp, 0);
6706module_param(vesa, int, 0);
6707module_param(rate, int, 0);
6708module_param(forcecrt1, int, 0);
6709module_param(forcecrt2type, charp, 0);
6710module_param(scalelcd, int, 0);
6711module_param(pdc, int, 0);
6712module_param(pdc1, int, 0);
6713module_param(specialtiming, charp, 0);
6714module_param(lvdshl, int, 0);
6715module_param(tvstandard, charp, 0);
6716module_param(tvxposoffset, int, 0);
6717module_param(tvyposoffset, int, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006718module_param(nocrt2rate, int, 0);
6719#if !defined(__i386__) && !defined(__x86_64__)
6720module_param(resetcard, int, 0);
6721module_param(videoram, int, 0);
6722#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -07006723
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006724MODULE_PARM_DESC(mem,
6725 "\nDetermines the beginning of the video memory heap in KB. This heap is used\n"
6726 "for video RAM management for eg. DRM/DRI. On 300 series, the default depends\n"
6727 "on the amount of video RAM available. If 8MB of video RAM or less is available,\n"
6728 "the heap starts at 4096KB, if between 8 and 16MB are available at 8192KB,\n"
6729 "otherwise at 12288KB. On 315/330/340 series, the heap size is 32KB by default.\n"
6730 "The value is to be specified without 'KB'.\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07006731
6732MODULE_PARM_DESC(noaccel,
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006733 "\nIf set to anything other than 0, 2D acceleration will be disabled.\n"
Linus Torvalds1da177e2005-04-16 15:20:36 -07006734 "(default: 0)\n");
6735
6736MODULE_PARM_DESC(noypan,
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006737 "\nIf set to anything other than 0, y-panning will be disabled and scrolling\n"
6738 "will be performed by redrawing the screen. (default: 0)\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07006739
6740MODULE_PARM_DESC(nomax,
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006741 "\nIf y-panning is enabled, sisfb will by default use the entire available video\n"
Linus Torvalds1da177e2005-04-16 15:20:36 -07006742 "memory for the virtual screen in order to optimize scrolling performance. If\n"
6743 "this is set to anything other than 0, sisfb will not do this and thereby \n"
6744 "enable the user to positively specify a virtual Y size of the screen using\n"
6745 "fbset. (default: 0)\n");
6746
Linus Torvalds1da177e2005-04-16 15:20:36 -07006747MODULE_PARM_DESC(mode,
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006748 "\nSelects the desired default display mode in the format XxYxDepth,\n"
6749 "eg. 1024x768x16. Other formats supported include XxY-Depth and\n"
Linus Torvalds1da177e2005-04-16 15:20:36 -07006750 "XxY-Depth@Rate. If the parameter is only one (decimal or hexadecimal)\n"
6751 "number, it will be interpreted as a VESA mode number. (default: 800x600x8)\n");
6752
6753MODULE_PARM_DESC(vesa,
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006754 "\nSelects the desired default display mode by VESA defined mode number, eg.\n"
6755 "0x117 (default: 0x0103)\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07006756
6757MODULE_PARM_DESC(rate,
6758 "\nSelects the desired vertical refresh rate for CRT1 (external VGA) in Hz.\n"
6759 "If the mode is specified in the format XxY-Depth@Rate, this parameter\n"
6760 "will be ignored (default: 60)\n");
6761
6762MODULE_PARM_DESC(forcecrt1,
6763 "\nNormally, the driver autodetects whether or not CRT1 (external VGA) is \n"
6764 "connected. With this option, the detection can be overridden (1=CRT1 ON,\n"
6765 "0=CRT1 OFF) (default: [autodetected])\n");
6766
6767MODULE_PARM_DESC(forcecrt2type,
6768 "\nIf this option is omitted, the driver autodetects CRT2 output devices, such as\n"
6769 "LCD, TV or secondary VGA. With this option, this autodetection can be\n"
6770 "overridden. Possible parameters are LCD, TV, VGA or NONE. NONE disables CRT2.\n"
6771 "On systems with a SiS video bridge, parameters SVIDEO, COMPOSITE or SCART can\n"
6772 "be used instead of TV to override the TV detection. Furthermore, on systems\n"
6773 "with a SiS video bridge, SVIDEO+COMPOSITE, HIVISION, YPBPR480I, YPBPR480P,\n"
6774 "YPBPR720P and YPBPR1080I are understood. However, whether or not these work\n"
6775 "depends on the very hardware in use. (default: [autodetected])\n");
6776
6777MODULE_PARM_DESC(scalelcd,
6778 "\nSetting this to 1 will force the driver to scale the LCD image to the panel's\n"
6779 "native resolution. Setting it to 0 will disable scaling; LVDS panels will\n"
6780 "show black bars around the image, TMDS panels will probably do the scaling\n"
6781 "themselves. Default: 1 on LVDS panels, 0 on TMDS panels\n");
6782
6783MODULE_PARM_DESC(pdc,
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006784 "\nThis is for manually selecting the LCD panel delay compensation. The driver\n"
Linus Torvalds1da177e2005-04-16 15:20:36 -07006785 "should detect this correctly in most cases; however, sometimes this is not\n"
6786 "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 -07006787 "on a 300 series chipset; 6 on other chipsets. If the problem persists, try\n"
6788 "other values (on 300 series: between 4 and 60 in steps of 4; otherwise: any\n"
6789 "value from 0 to 31). (default: autodetected, if LCD is active during start)\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07006790
6791#ifdef CONFIG_FB_SIS_315
6792MODULE_PARM_DESC(pdc1,
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006793 "\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 -07006794 "series only. (default: autodetected if LCD is in LCD-via-CRT1 mode during\n"
6795 "startup) - Note: currently, this has no effect because LCD-via-CRT1 is not\n"
6796 "implemented yet.\n");
6797#endif
6798
6799MODULE_PARM_DESC(specialtiming,
6800 "\nPlease refer to documentation for more information on this option.\n");
6801
6802MODULE_PARM_DESC(lvdshl,
6803 "\nPlease refer to documentation for more information on this option.\n");
6804
6805MODULE_PARM_DESC(tvstandard,
6806 "\nThis allows overriding the BIOS default for the TV standard. Valid choices are\n"
6807 "pal, ntsc, palm and paln. (default: [auto; pal or ntsc only])\n");
6808
6809MODULE_PARM_DESC(tvxposoffset,
6810 "\nRelocate TV output horizontally. Possible parameters: -32 through 32.\n"
6811 "Default: 0\n");
6812
6813MODULE_PARM_DESC(tvyposoffset,
6814 "\nRelocate TV output vertically. Possible parameters: -32 through 32.\n"
6815 "Default: 0\n");
6816
Linus Torvalds1da177e2005-04-16 15:20:36 -07006817MODULE_PARM_DESC(nocrt2rate,
6818 "\nSetting this to 1 will force the driver to use the default refresh rate for\n"
6819 "CRT2 if CRT2 type is VGA. (default: 0, use same rate as CRT1)\n");
6820
Linus Torvalds1da177e2005-04-16 15:20:36 -07006821#if !defined(__i386__) && !defined(__x86_64__)
6822#ifdef CONFIG_FB_SIS_300
6823MODULE_PARM_DESC(resetcard,
6824 "\nSet this to 1 in order to reset (POST) the card on non-x86 machines where\n"
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006825 "the BIOS did not POST the card (only supported for SiS 300/305 and XGI cards\n"
6826 "currently). Default: 0\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07006827
6828MODULE_PARM_DESC(videoram,
6829 "\nSet this to the amount of video RAM (in kilobyte) the card has. Required on\n"
6830 "some non-x86 architectures where the memory auto detection fails. Only\n"
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006831 "relevant if resetcard is set, too. SiS300/305 only. Default: [auto-detect]\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07006832#endif
6833#endif
6834
Linus Torvalds1da177e2005-04-16 15:20:36 -07006835#endif /* /MODULE */
6836
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006837/* _GPL only for new symbols. */
Linus Torvalds1da177e2005-04-16 15:20:36 -07006838EXPORT_SYMBOL(sis_malloc);
6839EXPORT_SYMBOL(sis_free);
Thomas Winischhofer544393f2005-09-09 13:04:45 -07006840EXPORT_SYMBOL_GPL(sis_malloc_new);
6841EXPORT_SYMBOL_GPL(sis_free_new);
6842
Linus Torvalds1da177e2005-04-16 15:20:36 -07006843
6844