treewide: Use fallthrough pseudo-keyword
[linux-block.git] / drivers / video / fbdev / sis / sis_main.c
CommitLineData
5e0f8ad0 1// SPDX-License-Identifier: GPL-2.0-or-later
1da177e4 2/*
544393fe
TW
3 * SiS 300/540/630[S]/730[S],
4 * SiS 315[E|PRO]/550/[M]65x/[M]66x[F|M|G]X/[M]74x[GX]/330/[M]76x[GX],
5 * XGI V3XT/V5/V8, Z7
1da177e4
LT
6 * frame buffer driver for Linux kernels >= 2.4.14 and >=2.6.3
7 *
544393fe 8 * Copyright (C) 2001-2005 Thomas Winischhofer, Vienna, Austria.
1da177e4 9 *
544393fe 10 * Author: Thomas Winischhofer <thomas@winischhofer.net>
1da177e4
LT
11 *
12 * Author of (practically wiped) code base:
13 * SiS (www.sis.com)
544393fe 14 * Copyright (C) 1999 Silicon Integrated Systems, Inc.
1da177e4
LT
15 *
16 * See http://www.winischhofer.net/ for more information and updates
17 *
18 * Originally based on the VBE 2.0 compliant graphic boards framebuffer driver,
19 * which is (c) 1998 Gerd Knorr <kraxel@goldbach.in-berlin.de>
1da177e4
LT
20 */
21
1da177e4 22#include <linux/module.h>
1da177e4 23#include <linux/moduleparam.h>
1da177e4 24#include <linux/kernel.h>
1da177e4
LT
25#include <linux/spinlock.h>
26#include <linux/errno.h>
27#include <linux/string.h>
28#include <linux/mm.h>
a8f340e3 29#include <linux/screen_info.h>
1da177e4 30#include <linux/slab.h>
1da177e4 31#include <linux/fb.h>
1da177e4 32#include <linux/selection.h>
1da177e4
LT
33#include <linux/ioport.h>
34#include <linux/init.h>
35#include <linux/pci.h>
36#include <linux/vmalloc.h>
1da177e4
LT
37#include <linux/capability.h>
38#include <linux/fs.h>
39#include <linux/types.h>
84902b7a 40#include <linux/uaccess.h>
1da177e4 41#include <asm/io.h>
1da177e4 42
1da177e4
LT
43#include "sis.h"
44#include "sis_main.h"
5908986e 45#include "init301.h"
1da177e4 46
1f8e6eee
AK
47#if !defined(CONFIG_FB_SIS_300) && !defined(CONFIG_FB_SIS_315)
48#warning Neither CONFIG_FB_SIS_300 nor CONFIG_FB_SIS_315 is set
49#warning sisfb will not work!
50#endif
51
5908986e
AB
52/* ---------------------- Prototypes ------------------------- */
53
54/* Interface used by the world */
55#ifndef MODULE
56static int sisfb_setup(char *options);
57#endif
58
59/* Interface to the low level console driver */
60static int sisfb_init(void);
61
62/* fbdev routines */
63static int sisfb_get_fix(struct fb_fix_screeninfo *fix, int con,
64 struct fb_info *info);
65
66static int sisfb_ioctl(struct fb_info *info, unsigned int cmd,
67 unsigned long arg);
68static int sisfb_set_par(struct fb_info *info);
69static int sisfb_blank(int blank,
70 struct fb_info *info);
71
544393fe
TW
72static void sisfb_handle_command(struct sis_video_info *ivideo,
73 struct sisfb_cmd *sisfb_command);
74
5908986e
AB
75static void sisfb_search_mode(char *name, bool quiet);
76static int sisfb_validate_mode(struct sis_video_info *ivideo, int modeindex, u32 vbflags);
77static u8 sisfb_search_refresh_rate(struct sis_video_info *ivideo, unsigned int rate,
78 int index);
79static int sisfb_setcolreg(unsigned regno, unsigned red, unsigned green,
80 unsigned blue, unsigned transp,
81 struct fb_info *fb_info);
82static int sisfb_do_set_var(struct fb_var_screeninfo *var, int isactive,
83 struct fb_info *info);
84static void sisfb_pre_setmode(struct sis_video_info *ivideo);
85static void sisfb_post_setmode(struct sis_video_info *ivideo);
86static bool sisfb_CheckVBRetrace(struct sis_video_info *ivideo);
87static bool sisfbcheckvretracecrt2(struct sis_video_info *ivideo);
88static bool sisfbcheckvretracecrt1(struct sis_video_info *ivideo);
89static bool sisfb_bridgeisslave(struct sis_video_info *ivideo);
90static void sisfb_detect_VB_connect(struct sis_video_info *ivideo);
91static void sisfb_get_VB_type(struct sis_video_info *ivideo);
92static void sisfb_set_TVxposoffset(struct sis_video_info *ivideo, int val);
93static void sisfb_set_TVyposoffset(struct sis_video_info *ivideo, int val);
94
95/* Internal heap routines */
96static int sisfb_heap_init(struct sis_video_info *ivideo);
97static struct SIS_OH * sisfb_poh_new_node(struct SIS_HEAP *memheap);
98static struct SIS_OH * sisfb_poh_allocate(struct SIS_HEAP *memheap, u32 size);
99static void sisfb_delete_node(struct SIS_OH *poh);
100static void sisfb_insert_node(struct SIS_OH *pohList, struct SIS_OH *poh);
101static struct SIS_OH * sisfb_poh_free(struct SIS_HEAP *memheap, u32 base);
102static void sisfb_free_node(struct SIS_HEAP *memheap, struct SIS_OH *poh);
103
104
1da177e4
LT
105/* ------------------ Internal helper routines ----------------- */
106
107static void __init
108sisfb_setdefaultparms(void)
109{
544393fe
TW
110 sisfb_off = 0;
111 sisfb_parm_mem = 0;
112 sisfb_accel = -1;
113 sisfb_ypan = -1;
114 sisfb_max = -1;
115 sisfb_userom = -1;
116 sisfb_useoem = -1;
544393fe 117 sisfb_mode_idx = -1;
544393fe
TW
118 sisfb_parm_rate = -1;
119 sisfb_crt1off = 0;
120 sisfb_forcecrt1 = -1;
121 sisfb_crt2type = -1;
122 sisfb_crt2flags = 0;
123 sisfb_pdc = 0xff;
124 sisfb_pdca = 0xff;
125 sisfb_scalelcd = -1;
1da177e4 126 sisfb_specialtiming = CUT_NONE;
544393fe
TW
127 sisfb_lvdshl = -1;
128 sisfb_dstn = 0;
129 sisfb_fstn = 0;
130 sisfb_tvplug = -1;
131 sisfb_tvstd = -1;
132 sisfb_tvxposoffset = 0;
133 sisfb_tvyposoffset = 0;
134 sisfb_nocrt2rate = 0;
1da177e4 135#if !defined(__i386__) && !defined(__x86_64__)
544393fe
TW
136 sisfb_resetcard = 0;
137 sisfb_videoram = 0;
1da177e4
LT
138#endif
139}
140
544393fe
TW
141/* ------------- Parameter parsing -------------- */
142
48c68c4f 143static void sisfb_search_vesamode(unsigned int vesamode, bool quiet)
1da177e4
LT
144{
145 int i = 0, j = 0;
146
544393fe 147 /* We don't know the hardware specs yet and there is no ivideo */
1da177e4
LT
148
149 if(vesamode == 0) {
544393fe
TW
150 if(!quiet)
151 printk(KERN_ERR "sisfb: Invalid mode. Using default.\n");
152
1da177e4 153 sisfb_mode_idx = DEFAULT_MODE;
4370409a 154
1da177e4
LT
155 return;
156 }
157
158 vesamode &= 0x1dff; /* Clean VESA mode number from other flags */
159
160 while(sisbios_mode[i++].mode_no[0] != 0) {
161 if( (sisbios_mode[i-1].vesa_mode_no_1 == vesamode) ||
162 (sisbios_mode[i-1].vesa_mode_no_2 == vesamode) ) {
544393fe
TW
163 if(sisfb_fstn) {
164 if(sisbios_mode[i-1].mode_no[1] == 0x50 ||
165 sisbios_mode[i-1].mode_no[1] == 0x56 ||
166 sisbios_mode[i-1].mode_no[1] == 0x53)
167 continue;
168 } else {
169 if(sisbios_mode[i-1].mode_no[1] == 0x5a ||
170 sisbios_mode[i-1].mode_no[1] == 0x5b)
171 continue;
172 }
173 sisfb_mode_idx = i - 1;
174 j = 1;
175 break;
1da177e4
LT
176 }
177 }
544393fe
TW
178 if((!j) && !quiet)
179 printk(KERN_ERR "sisfb: Invalid VESA mode 0x%x'\n", vesamode);
1da177e4
LT
180}
181
48c68c4f 182static void sisfb_search_mode(char *name, bool quiet)
1da177e4 183{
1da177e4 184 unsigned int j = 0, xres = 0, yres = 0, depth = 0, rate = 0;
544393fe 185 int i = 0;
1da177e4
LT
186 char strbuf[16], strbuf1[20];
187 char *nameptr = name;
188
544393fe 189 /* We don't know the hardware specs yet and there is no ivideo */
1da177e4
LT
190
191 if(name == NULL) {
544393fe
TW
192 if(!quiet)
193 printk(KERN_ERR "sisfb: Internal error, using default mode.\n");
194
195 sisfb_mode_idx = DEFAULT_MODE;
196 return;
1da177e4
LT
197 }
198
c4dd0869 199 if(!strncasecmp(name, sisbios_mode[MODE_INDEX_NONE].name, strlen(name))) {
544393fe
TW
200 if(!quiet)
201 printk(KERN_ERR "sisfb: Mode 'none' not supported anymore. Using default.\n");
202
203 sisfb_mode_idx = DEFAULT_MODE;
204 return;
1da177e4 205 }
4370409a 206
1da177e4 207 if(strlen(name) <= 19) {
544393fe
TW
208 strcpy(strbuf1, name);
209 for(i = 0; i < strlen(strbuf1); i++) {
210 if(strbuf1[i] < '0' || strbuf1[i] > '9') strbuf1[i] = ' ';
211 }
1da177e4 212
544393fe
TW
213 /* This does some fuzzy mode naming detection */
214 if(sscanf(strbuf1, "%u %u %u %u", &xres, &yres, &depth, &rate) == 4) {
215 if((rate <= 32) || (depth > 32)) {
216 j = rate; rate = depth; depth = j;
217 }
218 sprintf(strbuf, "%ux%ux%u", xres, yres, depth);
219 nameptr = strbuf;
220 sisfb_parm_rate = rate;
221 } else if(sscanf(strbuf1, "%u %u %u", &xres, &yres, &depth) == 3) {
222 sprintf(strbuf, "%ux%ux%u", xres, yres, depth);
223 nameptr = strbuf;
224 } else {
225 xres = 0;
226 if((sscanf(strbuf1, "%u %u", &xres, &yres) == 2) && (xres != 0)) {
227 sprintf(strbuf, "%ux%ux8", xres, yres);
228 nameptr = strbuf;
229 } else {
230 sisfb_search_vesamode(simple_strtoul(name, NULL, 0), quiet);
231 return;
232 }
233 }
1da177e4
LT
234 }
235
236 i = 0; j = 0;
237 while(sisbios_mode[i].mode_no[0] != 0) {
c4dd0869 238 if(!strncasecmp(nameptr, sisbios_mode[i++].name, strlen(nameptr))) {
544393fe
TW
239 if(sisfb_fstn) {
240 if(sisbios_mode[i-1].mode_no[1] == 0x50 ||
241 sisbios_mode[i-1].mode_no[1] == 0x56 ||
242 sisbios_mode[i-1].mode_no[1] == 0x53)
243 continue;
244 } else {
245 if(sisbios_mode[i-1].mode_no[1] == 0x5a ||
246 sisbios_mode[i-1].mode_no[1] == 0x5b)
247 continue;
248 }
249 sisfb_mode_idx = i - 1;
250 j = 1;
251 break;
252 }
253 }
254
255 if((!j) && !quiet)
256 printk(KERN_ERR "sisfb: Invalid mode '%s'\n", nameptr);
1da177e4
LT
257}
258
259#ifndef MODULE
48c68c4f 260static void sisfb_get_vga_mode_from_kernel(void)
1da177e4 261{
31c5cdba 262#ifdef CONFIG_X86
544393fe 263 char mymode[32];
1da177e4
LT
264 int mydepth = screen_info.lfb_depth;
265
266 if(screen_info.orig_video_isVGA != VIDEO_TYPE_VLFB) return;
267
268 if( (screen_info.lfb_width >= 320) && (screen_info.lfb_width <= 2048) &&
269 (screen_info.lfb_height >= 200) && (screen_info.lfb_height <= 1536) &&
270 (mydepth >= 8) && (mydepth <= 32) ) {
271
544393fe 272 if(mydepth == 24) mydepth = 32;
1da177e4 273
544393fe
TW
274 sprintf(mymode, "%ux%ux%u", screen_info.lfb_width,
275 screen_info.lfb_height,
1da177e4
LT
276 mydepth);
277
544393fe
TW
278 printk(KERN_DEBUG
279 "sisfb: Using vga mode %s pre-set by kernel as default\n",
280 mymode);
1da177e4 281
c30660ea 282 sisfb_search_mode(mymode, true);
1da177e4
LT
283 }
284#endif
285 return;
286}
287#endif
288
289static void __init
290sisfb_search_crt2type(const char *name)
291{
292 int i = 0;
293
544393fe 294 /* We don't know the hardware specs yet and there is no ivideo */
1da177e4
LT
295
296 if(name == NULL) return;
297
298 while(sis_crt2type[i].type_no != -1) {
c4dd0869 299 if(!strncasecmp(name, sis_crt2type[i].name, strlen(sis_crt2type[i].name))) {
544393fe
TW
300 sisfb_crt2type = sis_crt2type[i].type_no;
301 sisfb_tvplug = sis_crt2type[i].tvplug_no;
302 sisfb_crt2flags = sis_crt2type[i].flags;
303 break;
304 }
305 i++;
1da177e4
LT
306 }
307
308 sisfb_dstn = (sisfb_crt2flags & FL_550_DSTN) ? 1 : 0;
309 sisfb_fstn = (sisfb_crt2flags & FL_550_FSTN) ? 1 : 0;
310
544393fe 311 if(sisfb_crt2type < 0)
1da177e4 312 printk(KERN_ERR "sisfb: Invalid CRT2 type: %s\n", name);
1da177e4
LT
313}
314
315static void __init
316sisfb_search_tvstd(const char *name)
317{
318 int i = 0;
319
544393fe 320 /* We don't know the hardware specs yet and there is no ivideo */
1da177e4 321
544393fe
TW
322 if(name == NULL)
323 return;
1da177e4
LT
324
325 while(sis_tvtype[i].type_no != -1) {
c4dd0869 326 if(!strncasecmp(name, sis_tvtype[i].name, strlen(sis_tvtype[i].name))) {
544393fe
TW
327 sisfb_tvstd = sis_tvtype[i].type_no;
328 break;
329 }
330 i++;
1da177e4
LT
331 }
332}
333
334static void __init
335sisfb_search_specialtiming(const char *name)
336{
337 int i = 0;
c30660ea 338 bool found = false;
1da177e4 339
544393fe 340 /* We don't know the hardware specs yet and there is no ivideo */
1da177e4 341
544393fe
TW
342 if(name == NULL)
343 return;
1da177e4 344
c4dd0869 345 if(!strncasecmp(name, "none", 4)) {
544393fe 346 sisfb_specialtiming = CUT_FORCENONE;
1da177e4
LT
347 printk(KERN_DEBUG "sisfb: Special timing disabled\n");
348 } else {
544393fe 349 while(mycustomttable[i].chipID != 0) {
c4dd0869 350 if(!strncasecmp(name,mycustomttable[i].optionName,
544393fe
TW
351 strlen(mycustomttable[i].optionName))) {
352 sisfb_specialtiming = mycustomttable[i].SpecialID;
c30660ea 353 found = true;
544393fe
TW
354 printk(KERN_INFO "sisfb: Special timing for %s %s forced (\"%s\")\n",
355 mycustomttable[i].vendorName,
356 mycustomttable[i].cardName,
357 mycustomttable[i].optionName);
358 break;
359 }
360 i++;
361 }
362 if(!found) {
363 printk(KERN_WARNING "sisfb: Invalid SpecialTiming parameter, valid are:");
364 printk(KERN_WARNING "\t\"none\" (to disable special timings)\n");
365 i = 0;
366 while(mycustomttable[i].chipID != 0) {
367 printk(KERN_WARNING "\t\"%s\" (for %s %s)\n",
368 mycustomttable[i].optionName,
369 mycustomttable[i].vendorName,
370 mycustomttable[i].cardName);
371 i++;
372 }
373 }
374 }
375}
376
377/* ----------- Various detection routines ----------- */
378
48c68c4f 379static void sisfb_detect_custom_timing(struct sis_video_info *ivideo)
544393fe
TW
380{
381 unsigned char *biosver = NULL;
382 unsigned char *biosdate = NULL;
c30660ea 383 bool footprint;
544393fe
TW
384 u32 chksum = 0;
385 int i, j;
386
387 if(ivideo->SiS_Pr.UseROM) {
388 biosver = ivideo->SiS_Pr.VirtualRomBase + 0x06;
389 biosdate = ivideo->SiS_Pr.VirtualRomBase + 0x2c;
390 for(i = 0; i < 32768; i++)
391 chksum += ivideo->SiS_Pr.VirtualRomBase[i];
392 }
393
394 i = 0;
395 do {
396 if( (mycustomttable[i].chipID == ivideo->chip) &&
397 ((!strlen(mycustomttable[i].biosversion)) ||
398 (ivideo->SiS_Pr.UseROM &&
399 (!strncmp(mycustomttable[i].biosversion, biosver,
400 strlen(mycustomttable[i].biosversion))))) &&
401 ((!strlen(mycustomttable[i].biosdate)) ||
402 (ivideo->SiS_Pr.UseROM &&
403 (!strncmp(mycustomttable[i].biosdate, biosdate,
404 strlen(mycustomttable[i].biosdate))))) &&
405 ((!mycustomttable[i].bioschksum) ||
406 (ivideo->SiS_Pr.UseROM &&
407 (mycustomttable[i].bioschksum == chksum))) &&
408 (mycustomttable[i].pcisubsysvendor == ivideo->subsysvendor) &&
409 (mycustomttable[i].pcisubsyscard == ivideo->subsysdevice) ) {
c30660ea 410 footprint = true;
544393fe
TW
411 for(j = 0; j < 5; j++) {
412 if(mycustomttable[i].biosFootprintAddr[j]) {
413 if(ivideo->SiS_Pr.UseROM) {
414 if(ivideo->SiS_Pr.VirtualRomBase[mycustomttable[i].biosFootprintAddr[j]] !=
415 mycustomttable[i].biosFootprintData[j]) {
c30660ea 416 footprint = false;
544393fe
TW
417 }
418 } else
c30660ea 419 footprint = false;
544393fe
TW
420 }
421 }
422 if(footprint) {
423 ivideo->SiS_Pr.SiS_CustomT = mycustomttable[i].SpecialID;
424 printk(KERN_DEBUG "sisfb: Identified [%s %s], special timing applies\n",
425 mycustomttable[i].vendorName,
426 mycustomttable[i].cardName);
427 printk(KERN_DEBUG "sisfb: [specialtiming parameter name: %s]\n",
428 mycustomttable[i].optionName);
429 break;
430 }
431 }
432 i++;
433 } while(mycustomttable[i].chipID);
1da177e4
LT
434}
435
48c68c4f 436static bool sisfb_interpret_edid(struct sisfb_monitor *monitor, u8 *buffer)
1da177e4
LT
437{
438 int i, j, xres, yres, refresh, index;
439 u32 emodes;
440
441 if(buffer[0] != 0x00 || buffer[1] != 0xff ||
442 buffer[2] != 0xff || buffer[3] != 0xff ||
443 buffer[4] != 0xff || buffer[5] != 0xff ||
444 buffer[6] != 0xff || buffer[7] != 0x00) {
544393fe 445 printk(KERN_DEBUG "sisfb: Bad EDID header\n");
c30660ea 446 return false;
1da177e4
LT
447 }
448
449 if(buffer[0x12] != 0x01) {
544393fe
TW
450 printk(KERN_INFO "sisfb: EDID version %d not supported\n",
451 buffer[0x12]);
c30660ea 452 return false;
1da177e4
LT
453 }
454
455 monitor->feature = buffer[0x18];
456
eaa0ff15 457 if(!(buffer[0x14] & 0x80)) {
544393fe
TW
458 if(!(buffer[0x14] & 0x08)) {
459 printk(KERN_INFO
460 "sisfb: WARNING: Monitor does not support separate syncs\n");
461 }
1da177e4
LT
462 }
463
464 if(buffer[0x13] >= 0x01) {
465 /* EDID V1 rev 1 and 2: Search for monitor descriptor
466 * to extract ranges
467 */
468 j = 0x36;
469 for(i=0; i<4; i++) {
470 if(buffer[j] == 0x00 && buffer[j + 1] == 0x00 &&
544393fe 471 buffer[j + 2] == 0x00 && buffer[j + 3] == 0xfd &&
1da177e4
LT
472 buffer[j + 4] == 0x00) {
473 monitor->hmin = buffer[j + 7];
474 monitor->hmax = buffer[j + 8];
475 monitor->vmin = buffer[j + 5];
476 monitor->vmax = buffer[j + 6];
477 monitor->dclockmax = buffer[j + 9] * 10 * 1000;
c30660ea 478 monitor->datavalid = true;
1da177e4
LT
479 break;
480 }
481 j += 18;
482 }
483 }
484
485 if(!monitor->datavalid) {
486 /* Otherwise: Get a range from the list of supported
487 * Estabished Timings. This is not entirely accurate,
488 * because fixed frequency monitors are not supported
489 * that way.
490 */
491 monitor->hmin = 65535; monitor->hmax = 0;
492 monitor->vmin = 65535; monitor->vmax = 0;
493 monitor->dclockmax = 0;
494 emodes = buffer[0x23] | (buffer[0x24] << 8) | (buffer[0x25] << 16);
495 for(i = 0; i < 13; i++) {
496 if(emodes & sisfb_ddcsmodes[i].mask) {
544393fe 497 if(monitor->hmin > sisfb_ddcsmodes[i].h) monitor->hmin = sisfb_ddcsmodes[i].h;
1da177e4
LT
498 if(monitor->hmax < sisfb_ddcsmodes[i].h) monitor->hmax = sisfb_ddcsmodes[i].h + 1;
499 if(monitor->vmin > sisfb_ddcsmodes[i].v) monitor->vmin = sisfb_ddcsmodes[i].v;
500 if(monitor->vmax < sisfb_ddcsmodes[i].v) monitor->vmax = sisfb_ddcsmodes[i].v;
501 if(monitor->dclockmax < sisfb_ddcsmodes[i].d) monitor->dclockmax = sisfb_ddcsmodes[i].d;
502 }
503 }
504 index = 0x26;
505 for(i = 0; i < 8; i++) {
506 xres = (buffer[index] + 31) * 8;
507 switch(buffer[index + 1] & 0xc0) {
544393fe
TW
508 case 0xc0: yres = (xres * 9) / 16; break;
509 case 0x80: yres = (xres * 4) / 5; break;
510 case 0x40: yres = (xres * 3) / 4; break;
511 default: yres = xres; break;
1da177e4
LT
512 }
513 refresh = (buffer[index + 1] & 0x3f) + 60;
514 if((xres >= 640) && (yres >= 480)) {
544393fe
TW
515 for(j = 0; j < 8; j++) {
516 if((xres == sisfb_ddcfmodes[j].x) &&
517 (yres == sisfb_ddcfmodes[j].y) &&
1da177e4
LT
518 (refresh == sisfb_ddcfmodes[j].v)) {
519 if(monitor->hmin > sisfb_ddcfmodes[j].h) monitor->hmin = sisfb_ddcfmodes[j].h;
520 if(monitor->hmax < sisfb_ddcfmodes[j].h) monitor->hmax = sisfb_ddcfmodes[j].h + 1;
521 if(monitor->vmin > sisfb_ddcsmodes[j].v) monitor->vmin = sisfb_ddcsmodes[j].v;
522 if(monitor->vmax < sisfb_ddcsmodes[j].v) monitor->vmax = sisfb_ddcsmodes[j].v;
544393fe
TW
523 if(monitor->dclockmax < sisfb_ddcsmodes[j].d) monitor->dclockmax = sisfb_ddcsmodes[j].d;
524 }
525 }
1da177e4
LT
526 }
527 index += 2;
544393fe 528 }
1da177e4 529 if((monitor->hmin <= monitor->hmax) && (monitor->vmin <= monitor->vmax)) {
c30660ea 530 monitor->datavalid = true;
1da177e4
LT
531 }
532 }
533
544393fe 534 return monitor->datavalid;
1da177e4
LT
535}
536
48c68c4f
GKH
537static void sisfb_handle_ddc(struct sis_video_info *ivideo,
538 struct sisfb_monitor *monitor, int crtno)
1da177e4 539{
544393fe
TW
540 unsigned short temp, i, realcrtno = crtno;
541 unsigned char buffer[256];
1da177e4 542
c30660ea 543 monitor->datavalid = false;
1da177e4
LT
544
545 if(crtno) {
544393fe
TW
546 if(ivideo->vbflags & CRT2_LCD) realcrtno = 1;
547 else if(ivideo->vbflags & CRT2_VGA) realcrtno = 2;
548 else return;
549 }
1da177e4 550
544393fe
TW
551 if((ivideo->sisfb_crt1off) && (!crtno))
552 return;
1da177e4 553
544393fe
TW
554 temp = SiS_HandleDDC(&ivideo->SiS_Pr, ivideo->vbflags, ivideo->sisvga_engine,
555 realcrtno, 0, &buffer[0], ivideo->vbflags2);
556 if((!temp) || (temp == 0xffff)) {
557 printk(KERN_INFO "sisfb: CRT%d DDC probing failed\n", crtno + 1);
1da177e4 558 return;
544393fe
TW
559 } else {
560 printk(KERN_INFO "sisfb: CRT%d DDC supported\n", crtno + 1);
561 printk(KERN_INFO "sisfb: CRT%d DDC level: %s%s%s%s\n",
562 crtno + 1,
563 (temp & 0x1a) ? "" : "[none of the supported]",
564 (temp & 0x02) ? "2 " : "",
565 (temp & 0x08) ? "D&P" : "",
566 (temp & 0x10) ? "FPDI-2" : "");
567 if(temp & 0x02) {
1da177e4
LT
568 i = 3; /* Number of retrys */
569 do {
544393fe
TW
570 temp = SiS_HandleDDC(&ivideo->SiS_Pr, ivideo->vbflags, ivideo->sisvga_engine,
571 realcrtno, 1, &buffer[0], ivideo->vbflags2);
1da177e4 572 } while((temp) && i--);
544393fe
TW
573 if(!temp) {
574 if(sisfb_interpret_edid(monitor, &buffer[0])) {
1da177e4 575 printk(KERN_INFO "sisfb: Monitor range H %d-%dKHz, V %d-%dHz, Max. dotclock %dMHz\n",
544393fe 576 monitor->hmin, monitor->hmax, monitor->vmin, monitor->vmax,
1da177e4
LT
577 monitor->dclockmax / 1000);
578 } else {
544393fe
TW
579 printk(KERN_INFO "sisfb: CRT%d DDC EDID corrupt\n", crtno + 1);
580 }
1da177e4 581 } else {
544393fe 582 printk(KERN_INFO "sisfb: CRT%d DDC reading failed\n", crtno + 1);
1da177e4
LT
583 }
584 } else {
585 printk(KERN_INFO "sisfb: VESA D&P and FPDI-2 not supported yet\n");
586 }
587 }
588}
589
544393fe
TW
590/* -------------- Mode validation --------------- */
591
c30660ea 592static bool
1da177e4
LT
593sisfb_verify_rate(struct sis_video_info *ivideo, struct sisfb_monitor *monitor,
594 int mode_idx, int rate_idx, int rate)
595{
596 int htotal, vtotal;
597 unsigned int dclock, hsync;
598
544393fe 599 if(!monitor->datavalid)
c30660ea 600 return true;
1da177e4 601
544393fe 602 if(mode_idx < 0)
c30660ea 603 return false;
1da177e4
LT
604
605 /* Skip for 320x200, 320x240, 640x400 */
544393fe
TW
606 switch(sisbios_mode[mode_idx].mode_no[ivideo->mni]) {
607 case 0x59:
608 case 0x41:
609 case 0x4f:
610 case 0x50:
611 case 0x56:
612 case 0x53:
613 case 0x2f:
614 case 0x5d:
615 case 0x5e:
c30660ea 616 return true;
1da177e4
LT
617#ifdef CONFIG_FB_SIS_315
618 case 0x5a:
619 case 0x5b:
c30660ea 620 if(ivideo->sisvga_engine == SIS_315_VGA) return true;
1da177e4 621#endif
544393fe 622 }
1da177e4 623
544393fe 624 if(rate < (monitor->vmin - 1))
c30660ea 625 return false;
544393fe 626 if(rate > (monitor->vmax + 1))
c30660ea 627 return false;
1da177e4 628
544393fe 629 if(sisfb_gettotalfrommode(&ivideo->SiS_Pr,
1da177e4 630 sisbios_mode[mode_idx].mode_no[ivideo->mni],
544393fe 631 &htotal, &vtotal, rate_idx)) {
1da177e4 632 dclock = (htotal * vtotal * rate) / 1000;
544393fe 633 if(dclock > (monitor->dclockmax + 1000))
c30660ea 634 return false;
1da177e4 635 hsync = dclock / htotal;
544393fe 636 if(hsync < (monitor->hmin - 1))
c30660ea 637 return false;
544393fe 638 if(hsync > (monitor->hmax + 1))
c30660ea 639 return false;
1da177e4 640 } else {
c30660ea 641 return false;
1da177e4 642 }
c30660ea 643 return true;
1da177e4
LT
644}
645
646static int
647sisfb_validate_mode(struct sis_video_info *ivideo, int myindex, u32 vbflags)
648{
544393fe 649 u16 xres=0, yres, myres;
1da177e4
LT
650
651#ifdef CONFIG_FB_SIS_300
544393fe
TW
652 if(ivideo->sisvga_engine == SIS_300_VGA) {
653 if(!(sisbios_mode[myindex].chipset & MD_SIS300))
654 return -1 ;
655 }
1da177e4
LT
656#endif
657#ifdef CONFIG_FB_SIS_315
544393fe
TW
658 if(ivideo->sisvga_engine == SIS_315_VGA) {
659 if(!(sisbios_mode[myindex].chipset & MD_SIS315))
660 return -1;
661 }
1da177e4
LT
662#endif
663
544393fe 664 myres = sisbios_mode[myindex].yres;
1da177e4 665
544393fe 666 switch(vbflags & VB_DISPTYPE_DISP2) {
1da177e4 667
544393fe
TW
668 case CRT2_LCD:
669 xres = ivideo->lcdxres; yres = ivideo->lcdyres;
1da177e4 670
544393fe
TW
671 if((ivideo->SiS_Pr.SiS_CustomT != CUT_PANEL848) &&
672 (ivideo->SiS_Pr.SiS_CustomT != CUT_PANEL856)) {
673 if(sisbios_mode[myindex].xres > xres)
674 return -1;
675 if(myres > yres)
676 return -1;
677 }
1da177e4 678
544393fe
TW
679 if(ivideo->sisfb_fstn) {
680 if(sisbios_mode[myindex].xres == 320) {
681 if(myres == 240) {
682 switch(sisbios_mode[myindex].mode_no[1]) {
683 case 0x50: myindex = MODE_FSTN_8; break;
684 case 0x56: myindex = MODE_FSTN_16; break;
685 case 0x53: return -1;
686 }
687 }
688 }
689 }
1da177e4 690
544393fe
TW
691 if(SiS_GetModeID_LCD(ivideo->sisvga_engine, vbflags, sisbios_mode[myindex].xres,
692 sisbios_mode[myindex].yres, 0, ivideo->sisfb_fstn,
693 ivideo->SiS_Pr.SiS_CustomT, xres, yres, ivideo->vbflags2) < 0x14) {
694 return -1;
695 }
696 break;
1da177e4 697
544393fe
TW
698 case CRT2_TV:
699 if(SiS_GetModeID_TV(ivideo->sisvga_engine, vbflags, sisbios_mode[myindex].xres,
700 sisbios_mode[myindex].yres, 0, ivideo->vbflags2) < 0x14) {
701 return -1;
702 }
703 break;
1da177e4 704
544393fe
TW
705 case CRT2_VGA:
706 if(SiS_GetModeID_VGA2(ivideo->sisvga_engine, vbflags, sisbios_mode[myindex].xres,
707 sisbios_mode[myindex].yres, 0, ivideo->vbflags2) < 0x14) {
708 return -1;
709 }
710 break;
1da177e4 711 }
1da177e4 712
544393fe 713 return myindex;
1da177e4
LT
714}
715
716static u8
717sisfb_search_refresh_rate(struct sis_video_info *ivideo, unsigned int rate, int mode_idx)
718{
1da177e4 719 int i = 0;
544393fe
TW
720 u16 xres = sisbios_mode[mode_idx].xres;
721 u16 yres = sisbios_mode[mode_idx].yres;
1da177e4
LT
722
723 ivideo->rate_idx = 0;
724 while((sisfb_vrate[i].idx != 0) && (sisfb_vrate[i].xres <= xres)) {
725 if((sisfb_vrate[i].xres == xres) && (sisfb_vrate[i].yres == yres)) {
726 if(sisfb_vrate[i].refresh == rate) {
727 ivideo->rate_idx = sisfb_vrate[i].idx;
728 break;
729 } else if(sisfb_vrate[i].refresh > rate) {
730 if((sisfb_vrate[i].refresh - rate) <= 3) {
731 DPRINTK("sisfb: Adjusting rate from %d up to %d\n",
732 rate, sisfb_vrate[i].refresh);
733 ivideo->rate_idx = sisfb_vrate[i].idx;
734 ivideo->refresh_rate = sisfb_vrate[i].refresh;
d63870db
RK
735 } else if((sisfb_vrate[i].idx != 1) &&
736 ((rate - sisfb_vrate[i-1].refresh) <= 2)) {
1da177e4
LT
737 DPRINTK("sisfb: Adjusting rate from %d down to %d\n",
738 rate, sisfb_vrate[i-1].refresh);
739 ivideo->rate_idx = sisfb_vrate[i-1].idx;
740 ivideo->refresh_rate = sisfb_vrate[i-1].refresh;
544393fe 741 }
1da177e4
LT
742 break;
743 } else if((rate - sisfb_vrate[i].refresh) <= 2) {
744 DPRINTK("sisfb: Adjusting rate from %d down to %d\n",
745 rate, sisfb_vrate[i].refresh);
544393fe
TW
746 ivideo->rate_idx = sisfb_vrate[i].idx;
747 break;
748 }
1da177e4
LT
749 }
750 i++;
751 }
752 if(ivideo->rate_idx > 0) {
753 return ivideo->rate_idx;
754 } else {
755 printk(KERN_INFO "sisfb: Unsupported rate %d for %dx%d\n",
756 rate, xres, yres);
757 return 0;
758 }
759}
760
c30660ea 761static bool
1da177e4
LT
762sisfb_bridgeisslave(struct sis_video_info *ivideo)
763{
544393fe 764 unsigned char P1_00;
1da177e4 765
544393fe 766 if(!(ivideo->vbflags2 & VB2_VIDEOBRIDGE))
c30660ea 767 return false;
1da177e4 768
e57d4136 769 P1_00 = SiS_GetReg(SISPART1, 0x00);
544393fe
TW
770 if( ((ivideo->sisvga_engine == SIS_300_VGA) && (P1_00 & 0xa0) == 0x20) ||
771 ((ivideo->sisvga_engine == SIS_315_VGA) && (P1_00 & 0x50) == 0x10) ) {
c30660ea 772 return true;
544393fe 773 } else {
c30660ea 774 return false;
544393fe 775 }
1da177e4
LT
776}
777
c30660ea 778static bool
1da177e4
LT
779sisfballowretracecrt1(struct sis_video_info *ivideo)
780{
544393fe 781 u8 temp;
1da177e4 782
e57d4136 783 temp = SiS_GetReg(SISCR, 0x17);
544393fe 784 if(!(temp & 0x80))
c30660ea 785 return false;
1da177e4 786
e57d4136 787 temp = SiS_GetReg(SISSR, 0x1f);
544393fe 788 if(temp & 0xc0)
c30660ea 789 return false;
1da177e4 790
c30660ea 791 return true;
1da177e4
LT
792}
793
c30660ea 794static bool
1da177e4
LT
795sisfbcheckvretracecrt1(struct sis_video_info *ivideo)
796{
544393fe 797 if(!sisfballowretracecrt1(ivideo))
c30660ea 798 return false;
1da177e4 799
1e1687d7 800 if (SiS_GetRegByte(SISINPSTAT) & 0x08)
c30660ea 801 return true;
544393fe 802 else
c30660ea 803 return false;
1da177e4
LT
804}
805
806static void
807sisfbwaitretracecrt1(struct sis_video_info *ivideo)
808{
544393fe 809 int watchdog;
1da177e4 810
544393fe
TW
811 if(!sisfballowretracecrt1(ivideo))
812 return;
1da177e4 813
544393fe 814 watchdog = 65536;
1e1687d7 815 while ((!(SiS_GetRegByte(SISINPSTAT) & 0x08)) && --watchdog);
544393fe 816 watchdog = 65536;
1e1687d7 817 while ((SiS_GetRegByte(SISINPSTAT) & 0x08) && --watchdog);
1da177e4
LT
818}
819
c30660ea 820static bool
1da177e4
LT
821sisfbcheckvretracecrt2(struct sis_video_info *ivideo)
822{
544393fe 823 unsigned char temp, reg;
1da177e4 824
544393fe
TW
825 switch(ivideo->sisvga_engine) {
826 case SIS_300_VGA: reg = 0x25; break;
827 case SIS_315_VGA: reg = 0x30; break;
c30660ea 828 default: return false;
544393fe 829 }
1da177e4 830
e57d4136 831 temp = SiS_GetReg(SISPART1, reg);
544393fe 832 if(temp & 0x02)
c30660ea 833 return true;
544393fe 834 else
c30660ea 835 return false;
1da177e4
LT
836}
837
c30660ea 838static bool
1da177e4
LT
839sisfb_CheckVBRetrace(struct sis_video_info *ivideo)
840{
544393fe
TW
841 if(ivideo->currentvbflags & VB_DISPTYPE_DISP2) {
842 if(!sisfb_bridgeisslave(ivideo)) {
843 return sisfbcheckvretracecrt2(ivideo);
844 }
845 }
846 return sisfbcheckvretracecrt1(ivideo);
1da177e4
LT
847}
848
849static u32
850sisfb_setupvbblankflags(struct sis_video_info *ivideo, u32 *vcount, u32 *hcount)
851{
544393fe
TW
852 u8 idx, reg1, reg2, reg3, reg4;
853 u32 ret = 0;
854
855 (*vcount) = (*hcount) = 0;
856
857 if((ivideo->currentvbflags & VB_DISPTYPE_DISP2) && (!(sisfb_bridgeisslave(ivideo)))) {
858
859 ret |= (FB_VBLANK_HAVE_VSYNC |
860 FB_VBLANK_HAVE_HBLANK |
861 FB_VBLANK_HAVE_VBLANK |
862 FB_VBLANK_HAVE_VCOUNT |
863 FB_VBLANK_HAVE_HCOUNT);
864 switch(ivideo->sisvga_engine) {
865 case SIS_300_VGA: idx = 0x25; break;
866 default:
867 case SIS_315_VGA: idx = 0x30; break;
868 }
e57d4136
AK
869 reg1 = SiS_GetReg(SISPART1, (idx+0)); /* 30 */
870 reg2 = SiS_GetReg(SISPART1, (idx+1)); /* 31 */
871 reg3 = SiS_GetReg(SISPART1, (idx+2)); /* 32 */
872 reg4 = SiS_GetReg(SISPART1, (idx+3)); /* 33 */
544393fe
TW
873 if(reg1 & 0x01) ret |= FB_VBLANK_VBLANKING;
874 if(reg1 & 0x02) ret |= FB_VBLANK_VSYNCING;
875 if(reg4 & 0x80) ret |= FB_VBLANK_HBLANKING;
876 (*vcount) = reg3 | ((reg4 & 0x70) << 4);
877 (*hcount) = reg2 | ((reg4 & 0x0f) << 8);
878
879 } else if(sisfballowretracecrt1(ivideo)) {
880
881 ret |= (FB_VBLANK_HAVE_VSYNC |
882 FB_VBLANK_HAVE_VBLANK |
883 FB_VBLANK_HAVE_VCOUNT |
884 FB_VBLANK_HAVE_HCOUNT);
1e1687d7 885 reg1 = SiS_GetRegByte(SISINPSTAT);
544393fe
TW
886 if(reg1 & 0x08) ret |= FB_VBLANK_VSYNCING;
887 if(reg1 & 0x01) ret |= FB_VBLANK_VBLANKING;
e57d4136
AK
888 reg1 = SiS_GetReg(SISCR, 0x20);
889 reg1 = SiS_GetReg(SISCR, 0x1b);
890 reg2 = SiS_GetReg(SISCR, 0x1c);
891 reg3 = SiS_GetReg(SISCR, 0x1d);
544393fe
TW
892 (*vcount) = reg2 | ((reg3 & 0x07) << 8);
893 (*hcount) = (reg1 | ((reg3 & 0x10) << 4)) << 3;
894 }
895
896 return ret;
1da177e4
LT
897}
898
899static int
900sisfb_myblank(struct sis_video_info *ivideo, int blank)
901{
544393fe 902 u8 sr01, sr11, sr1f, cr63=0, p2_0, p1_13;
c30660ea 903 bool backlight = true;
544393fe
TW
904
905 switch(blank) {
906 case FB_BLANK_UNBLANK: /* on */
907 sr01 = 0x00;
908 sr11 = 0x00;
909 sr1f = 0x00;
910 cr63 = 0x00;
911 p2_0 = 0x20;
912 p1_13 = 0x00;
c30660ea 913 backlight = true;
544393fe
TW
914 break;
915 case FB_BLANK_NORMAL: /* blank */
916 sr01 = 0x20;
917 sr11 = 0x00;
918 sr1f = 0x00;
919 cr63 = 0x00;
920 p2_0 = 0x20;
921 p1_13 = 0x00;
c30660ea 922 backlight = true;
544393fe
TW
923 break;
924 case FB_BLANK_VSYNC_SUSPEND: /* no vsync */
925 sr01 = 0x20;
926 sr11 = 0x08;
927 sr1f = 0x80;
928 cr63 = 0x40;
929 p2_0 = 0x40;
930 p1_13 = 0x80;
c30660ea 931 backlight = false;
544393fe
TW
932 break;
933 case FB_BLANK_HSYNC_SUSPEND: /* no hsync */
934 sr01 = 0x20;
935 sr11 = 0x08;
936 sr1f = 0x40;
937 cr63 = 0x40;
938 p2_0 = 0x80;
939 p1_13 = 0x40;
c30660ea 940 backlight = false;
544393fe
TW
941 break;
942 case FB_BLANK_POWERDOWN: /* off */
943 sr01 = 0x20;
944 sr11 = 0x08;
945 sr1f = 0xc0;
946 cr63 = 0x40;
947 p2_0 = 0xc0;
948 p1_13 = 0xc0;
c30660ea 949 backlight = false;
544393fe
TW
950 break;
951 default:
952 return 1;
953 }
954
955 if(ivideo->currentvbflags & VB_DISPTYPE_CRT1) {
956
957 if( (!ivideo->sisfb_thismonitor.datavalid) ||
958 ((ivideo->sisfb_thismonitor.datavalid) &&
959 (ivideo->sisfb_thismonitor.feature & 0xe0))) {
960
961 if(ivideo->sisvga_engine == SIS_315_VGA) {
ad78adb4 962 SiS_SetRegANDOR(SISCR, ivideo->SiS_Pr.SiS_MyCR63, 0xbf, cr63);
544393fe
TW
963 }
964
965 if(!(sisfb_bridgeisslave(ivideo))) {
ad78adb4
AK
966 SiS_SetRegANDOR(SISSR, 0x01, ~0x20, sr01);
967 SiS_SetRegANDOR(SISSR, 0x1f, 0x3f, sr1f);
544393fe
TW
968 }
969 }
970
971 }
972
973 if(ivideo->currentvbflags & CRT2_LCD) {
974
975 if(ivideo->vbflags2 & VB2_SISLVDSBRIDGE) {
976 if(backlight) {
977 SiS_SiS30xBLOn(&ivideo->SiS_Pr);
978 } else {
979 SiS_SiS30xBLOff(&ivideo->SiS_Pr);
980 }
981 } else if(ivideo->sisvga_engine == SIS_315_VGA) {
982#ifdef CONFIG_FB_SIS_315
983 if(ivideo->vbflags2 & VB2_CHRONTEL) {
984 if(backlight) {
985 SiS_Chrontel701xBLOn(&ivideo->SiS_Pr);
986 } else {
987 SiS_Chrontel701xBLOff(&ivideo->SiS_Pr);
988 }
989 }
990#endif
991 }
992
993 if(((ivideo->sisvga_engine == SIS_300_VGA) &&
994 (ivideo->vbflags2 & (VB2_301|VB2_30xBDH|VB2_LVDS))) ||
995 ((ivideo->sisvga_engine == SIS_315_VGA) &&
996 ((ivideo->vbflags2 & (VB2_LVDS | VB2_CHRONTEL)) == VB2_LVDS))) {
ad78adb4 997 SiS_SetRegANDOR(SISSR, 0x11, ~0x0c, sr11);
544393fe
TW
998 }
999
1000 if(ivideo->sisvga_engine == SIS_300_VGA) {
1001 if((ivideo->vbflags2 & VB2_30xB) &&
1002 (!(ivideo->vbflags2 & VB2_30xBDH))) {
ad78adb4 1003 SiS_SetRegANDOR(SISPART1, 0x13, 0x3f, p1_13);
544393fe
TW
1004 }
1005 } else if(ivideo->sisvga_engine == SIS_315_VGA) {
1006 if((ivideo->vbflags2 & VB2_30xB) &&
1007 (!(ivideo->vbflags2 & VB2_30xBDH))) {
ad78adb4 1008 SiS_SetRegANDOR(SISPART2, 0x00, 0x1f, p2_0);
544393fe
TW
1009 }
1010 }
1011
1012 } else if(ivideo->currentvbflags & CRT2_VGA) {
1013
1014 if(ivideo->vbflags2 & VB2_30xB) {
ad78adb4 1015 SiS_SetRegANDOR(SISPART2, 0x00, 0x1f, p2_0);
544393fe
TW
1016 }
1017
1018 }
1019
1020 return 0;
1021}
1022
1023/* ------------- Callbacks from init.c/init301.c -------------- */
1024
1025#ifdef CONFIG_FB_SIS_300
1026unsigned int
1027sisfb_read_nbridge_pci_dword(struct SiS_Private *SiS_Pr, int reg)
1028{
1029 struct sis_video_info *ivideo = (struct sis_video_info *)SiS_Pr->ivideo;
1030 u32 val = 0;
1031
1032 pci_read_config_dword(ivideo->nbridge, reg, &val);
1033 return (unsigned int)val;
1034}
1035
1036void
1037sisfb_write_nbridge_pci_dword(struct SiS_Private *SiS_Pr, int reg, unsigned int val)
1038{
1039 struct sis_video_info *ivideo = (struct sis_video_info *)SiS_Pr->ivideo;
1040
1041 pci_write_config_dword(ivideo->nbridge, reg, (u32)val);
1042}
1043
1044unsigned int
1045sisfb_read_lpc_pci_dword(struct SiS_Private *SiS_Pr, int reg)
1046{
1047 struct sis_video_info *ivideo = (struct sis_video_info *)SiS_Pr->ivideo;
1048 u32 val = 0;
1049
1050 if(!ivideo->lpcdev) return 0;
1051
1052 pci_read_config_dword(ivideo->lpcdev, reg, &val);
1053 return (unsigned int)val;
1054}
1055#endif
1056
1057#ifdef CONFIG_FB_SIS_315
1058void
1059sisfb_write_nbridge_pci_byte(struct SiS_Private *SiS_Pr, int reg, unsigned char val)
1060{
1061 struct sis_video_info *ivideo = (struct sis_video_info *)SiS_Pr->ivideo;
1062
1063 pci_write_config_byte(ivideo->nbridge, reg, (u8)val);
1da177e4
LT
1064}
1065
544393fe
TW
1066unsigned int
1067sisfb_read_mio_pci_word(struct SiS_Private *SiS_Pr, int reg)
1068{
1069 struct sis_video_info *ivideo = (struct sis_video_info *)SiS_Pr->ivideo;
1070 u16 val = 0;
1071
1072 if(!ivideo->lpcdev) return 0;
1073
1074 pci_read_config_word(ivideo->lpcdev, reg, &val);
1075 return (unsigned int)val;
1076}
1077#endif
1078
1da177e4
LT
1079/* ----------- FBDev related routines for all series ----------- */
1080
1081static int
1082sisfb_get_cmap_len(const struct fb_var_screeninfo *var)
1083{
1084 return (var->bits_per_pixel == 8) ? 256 : 16;
1085}
1086
1087static void
1088sisfb_set_vparms(struct sis_video_info *ivideo)
1089{
544393fe 1090 switch(ivideo->video_bpp) {
1da177e4
LT
1091 case 8:
1092 ivideo->DstColor = 0x0000;
1093 ivideo->SiS310_AccelDepth = 0x00000000;
1094 ivideo->video_cmap_len = 256;
1095 break;
1096 case 16:
1097 ivideo->DstColor = 0x8000;
1098 ivideo->SiS310_AccelDepth = 0x00010000;
1099 ivideo->video_cmap_len = 16;
1100 break;
1101 case 32:
1102 ivideo->DstColor = 0xC000;
1103 ivideo->SiS310_AccelDepth = 0x00020000;
1104 ivideo->video_cmap_len = 16;
1105 break;
1106 default:
1107 ivideo->video_cmap_len = 16;
1108 printk(KERN_ERR "sisfb: Unsupported depth %d", ivideo->video_bpp);
1109 ivideo->accel = 0;
544393fe 1110 }
1da177e4
LT
1111}
1112
1113static int
1114sisfb_calc_maxyres(struct sis_video_info *ivideo, struct fb_var_screeninfo *var)
1115{
544393fe 1116 int maxyres = ivideo->sisfb_mem / (var->xres_virtual * (var->bits_per_pixel >> 3));
1da177e4
LT
1117
1118 if(maxyres > 32767) maxyres = 32767;
1119
1120 return maxyres;
1121}
1122
1123static void
1124sisfb_calc_pitch(struct sis_video_info *ivideo, struct fb_var_screeninfo *var)
1125{
1126 ivideo->video_linelength = var->xres_virtual * (var->bits_per_pixel >> 3);
1127 ivideo->scrnpitchCRT1 = ivideo->video_linelength;
1128 if(!(ivideo->currentvbflags & CRT1_LCDA)) {
1129 if((var->vmode & FB_VMODE_MASK) == FB_VMODE_INTERLACED) {
1130 ivideo->scrnpitchCRT1 <<= 1;
1131 }
1132 }
1da177e4
LT
1133}
1134
1135static void
1136sisfb_set_pitch(struct sis_video_info *ivideo)
1137{
c30660ea 1138 bool isslavemode = false;
1da177e4
LT
1139 unsigned short HDisplay1 = ivideo->scrnpitchCRT1 >> 3;
1140 unsigned short HDisplay2 = ivideo->video_linelength >> 3;
1141
c30660ea 1142 if(sisfb_bridgeisslave(ivideo)) isslavemode = true;
1da177e4 1143
544393fe
TW
1144 /* We need to set pitch for CRT1 if bridge is in slave mode, too */
1145 if((ivideo->currentvbflags & VB_DISPTYPE_DISP1) || (isslavemode)) {
44b751bb 1146 SiS_SetReg(SISCR, 0x13, (HDisplay1 & 0xFF));
ad78adb4 1147 SiS_SetRegANDOR(SISSR, 0x0E, 0xF0, (HDisplay1 >> 8));
1da177e4
LT
1148 }
1149
544393fe
TW
1150 /* We must not set the pitch for CRT2 if bridge is in slave mode */
1151 if((ivideo->currentvbflags & VB_DISPTYPE_DISP2) && (!isslavemode)) {
27799d6c 1152 SiS_SetRegOR(SISPART1, ivideo->CRT2_write_enable, 0x01);
44b751bb 1153 SiS_SetReg(SISPART1, 0x07, (HDisplay2 & 0xFF));
ad78adb4 1154 SiS_SetRegANDOR(SISPART1, 0x09, 0xF0, (HDisplay2 >> 8));
544393fe 1155 }
1da177e4
LT
1156}
1157
1158static void
1159sisfb_bpp_to_var(struct sis_video_info *ivideo, struct fb_var_screeninfo *var)
1160{
1161 ivideo->video_cmap_len = sisfb_get_cmap_len(var);
1162
1163 switch(var->bits_per_pixel) {
1164 case 8:
1165 var->red.offset = var->green.offset = var->blue.offset = 0;
811a2013 1166 var->red.length = var->green.length = var->blue.length = 8;
1da177e4
LT
1167 break;
1168 case 16:
1169 var->red.offset = 11;
1170 var->red.length = 5;
1171 var->green.offset = 5;
1172 var->green.length = 6;
1173 var->blue.offset = 0;
1174 var->blue.length = 5;
1175 var->transp.offset = 0;
1176 var->transp.length = 0;
1177 break;
1178 case 32:
1179 var->red.offset = 16;
1180 var->red.length = 8;
1181 var->green.offset = 8;
1182 var->green.length = 8;
1183 var->blue.offset = 0;
1184 var->blue.length = 8;
1185 var->transp.offset = 24;
1186 var->transp.length = 8;
1187 break;
1188 }
1189}
1190
544393fe
TW
1191static int
1192sisfb_set_mode(struct sis_video_info *ivideo, int clrscrn)
1193{
1194 unsigned short modeno = ivideo->mode_no;
1195
1196 /* >=2.6.12's fbcon clears the screen anyway */
544393fe 1197 modeno |= 0x80;
544393fe 1198
44b751bb 1199 SiS_SetReg(SISSR, IND_SIS_PASSWORD, SIS_PASSWORD);
544393fe
TW
1200
1201 sisfb_pre_setmode(ivideo);
1202
c30660ea 1203 if(!SiSSetMode(&ivideo->SiS_Pr, modeno)) {
544393fe
TW
1204 printk(KERN_ERR "sisfb: Setting mode[0x%x] failed\n", ivideo->mode_no);
1205 return -EINVAL;
1206 }
1207
44b751bb 1208 SiS_SetReg(SISSR, IND_SIS_PASSWORD, SIS_PASSWORD);
544393fe
TW
1209
1210 sisfb_post_setmode(ivideo);
1211
1212 return 0;
1213}
1214
1215
1da177e4
LT
1216static int
1217sisfb_do_set_var(struct fb_var_screeninfo *var, int isactive, struct fb_info *info)
1218{
1219 struct sis_video_info *ivideo = (struct sis_video_info *)info->par;
1220 unsigned int htotal = 0, vtotal = 0;
1221 unsigned int drate = 0, hrate = 0;
544393fe 1222 int found_mode = 0, ret;
1da177e4
LT
1223 int old_mode;
1224 u32 pixclock;
1225
1226 htotal = var->left_margin + var->xres + var->right_margin + var->hsync_len;
1227
1228 vtotal = var->upper_margin + var->lower_margin + var->vsync_len;
1229
1230 pixclock = var->pixclock;
1231
1232 if((var->vmode & FB_VMODE_MASK) == FB_VMODE_NONINTERLACED) {
1233 vtotal += var->yres;
1234 vtotal <<= 1;
1235 } else if((var->vmode & FB_VMODE_MASK) == FB_VMODE_DOUBLE) {
1236 vtotal += var->yres;
1237 vtotal <<= 2;
1238 } else if((var->vmode & FB_VMODE_MASK) == FB_VMODE_INTERLACED) {
1239 vtotal += var->yres;
1240 vtotal <<= 1;
1241 } else vtotal += var->yres;
1242
1243 if(!(htotal) || !(vtotal)) {
1244 DPRINTK("sisfb: Invalid 'var' information\n");
1245 return -EINVAL;
1246 }
1247
1248 if(pixclock && htotal && vtotal) {
544393fe
TW
1249 drate = 1000000000 / pixclock;
1250 hrate = (drate * 1000) / htotal;
1251 ivideo->refresh_rate = (unsigned int) (hrate * 2 / vtotal);
1da177e4 1252 } else {
544393fe 1253 ivideo->refresh_rate = 60;
1da177e4
LT
1254 }
1255
1256 old_mode = ivideo->sisfb_mode_idx;
1257 ivideo->sisfb_mode_idx = 0;
1258
1259 while( (sisbios_mode[ivideo->sisfb_mode_idx].mode_no[0] != 0) &&
1260 (sisbios_mode[ivideo->sisfb_mode_idx].xres <= var->xres) ) {
1261 if( (sisbios_mode[ivideo->sisfb_mode_idx].xres == var->xres) &&
1262 (sisbios_mode[ivideo->sisfb_mode_idx].yres == var->yres) &&
1263 (sisbios_mode[ivideo->sisfb_mode_idx].bpp == var->bits_per_pixel)) {
1264 ivideo->mode_no = sisbios_mode[ivideo->sisfb_mode_idx].mode_no[ivideo->mni];
1265 found_mode = 1;
1266 break;
1267 }
1268 ivideo->sisfb_mode_idx++;
1269 }
1270
1271 if(found_mode) {
1272 ivideo->sisfb_mode_idx = sisfb_validate_mode(ivideo,
1273 ivideo->sisfb_mode_idx, ivideo->currentvbflags);
1274 } else {
1275 ivideo->sisfb_mode_idx = -1;
1276 }
1277
1278 if(ivideo->sisfb_mode_idx < 0) {
1279 printk(KERN_ERR "sisfb: Mode %dx%dx%d not supported\n", var->xres,
1280 var->yres, var->bits_per_pixel);
1281 ivideo->sisfb_mode_idx = old_mode;
1282 return -EINVAL;
1283 }
1284
a9e60e5c
AB
1285 ivideo->mode_no = sisbios_mode[ivideo->sisfb_mode_idx].mode_no[ivideo->mni];
1286
1da177e4
LT
1287 if(sisfb_search_refresh_rate(ivideo, ivideo->refresh_rate, ivideo->sisfb_mode_idx) == 0) {
1288 ivideo->rate_idx = sisbios_mode[ivideo->sisfb_mode_idx].rate_idx;
1289 ivideo->refresh_rate = 60;
1290 }
1291
1da177e4 1292 if(isactive) {
544393fe
TW
1293 /* If acceleration to be used? Need to know
1294 * before pre/post_set_mode()
1295 */
1da177e4
LT
1296 ivideo->accel = 0;
1297#if defined(FBINFO_HWACCEL_DISABLED) && defined(FBINFO_HWACCEL_XPAN)
1298#ifdef STUPID_ACCELF_TEXT_SHIT
1299 if(var->accel_flags & FB_ACCELF_TEXT) {
1300 info->flags &= ~FBINFO_HWACCEL_DISABLED;
1301 } else {
1302 info->flags |= FBINFO_HWACCEL_DISABLED;
1303 }
1304#endif
1305 if(!(info->flags & FBINFO_HWACCEL_DISABLED)) ivideo->accel = -1;
1306#else
1307 if(var->accel_flags & FB_ACCELF_TEXT) ivideo->accel = -1;
1308#endif
1309
544393fe
TW
1310 if((ret = sisfb_set_mode(ivideo, 1))) {
1311 return ret;
1312 }
1313
1314 ivideo->video_bpp = sisbios_mode[ivideo->sisfb_mode_idx].bpp;
1315 ivideo->video_width = sisbios_mode[ivideo->sisfb_mode_idx].xres;
1316 ivideo->video_height = sisbios_mode[ivideo->sisfb_mode_idx].yres;
1317
1318 sisfb_calc_pitch(ivideo, var);
1319 sisfb_set_pitch(ivideo);
1320
1da177e4
LT
1321 sisfb_set_vparms(ivideo);
1322
1323 ivideo->current_width = ivideo->video_width;
1324 ivideo->current_height = ivideo->video_height;
1325 ivideo->current_bpp = ivideo->video_bpp;
1326 ivideo->current_htotal = htotal;
1327 ivideo->current_vtotal = vtotal;
1328 ivideo->current_linelength = ivideo->video_linelength;
1329 ivideo->current_pixclock = var->pixclock;
1330 ivideo->current_refresh_rate = ivideo->refresh_rate;
544393fe 1331 ivideo->sisfb_lastrates[ivideo->mode_no] = ivideo->refresh_rate;
1da177e4
LT
1332 }
1333
1334 return 0;
1335}
1336
544393fe
TW
1337static void
1338sisfb_set_base_CRT1(struct sis_video_info *ivideo, unsigned int base)
1da177e4 1339{
44b751bb 1340 SiS_SetReg(SISSR, IND_SIS_PASSWORD, SIS_PASSWORD);
1da177e4 1341
44b751bb
AK
1342 SiS_SetReg(SISCR, 0x0D, base & 0xFF);
1343 SiS_SetReg(SISCR, 0x0C, (base >> 8) & 0xFF);
1344 SiS_SetReg(SISSR, 0x0D, (base >> 16) & 0xFF);
1da177e4 1345 if(ivideo->sisvga_engine == SIS_315_VGA) {
ad78adb4 1346 SiS_SetRegANDOR(SISSR, 0x37, 0xFE, (base >> 24) & 0x01);
1da177e4 1347 }
544393fe
TW
1348}
1349
1350static void
1351sisfb_set_base_CRT2(struct sis_video_info *ivideo, unsigned int base)
1352{
1353 if(ivideo->currentvbflags & VB_DISPTYPE_DISP2) {
27799d6c 1354 SiS_SetRegOR(SISPART1, ivideo->CRT2_write_enable, 0x01);
44b751bb
AK
1355 SiS_SetReg(SISPART1, 0x06, (base & 0xFF));
1356 SiS_SetReg(SISPART1, 0x05, ((base >> 8) & 0xFF));
1357 SiS_SetReg(SISPART1, 0x04, ((base >> 16) & 0xFF));
1da177e4 1358 if(ivideo->sisvga_engine == SIS_315_VGA) {
ad78adb4 1359 SiS_SetRegANDOR(SISPART1, 0x02, 0x7F, ((base >> 24) & 0x01) << 7);
1da177e4 1360 }
544393fe 1361 }
1da177e4
LT
1362}
1363
544393fe 1364static int
8e42a962
LP
1365sisfb_pan_var(struct sis_video_info *ivideo, struct fb_info *info,
1366 struct fb_var_screeninfo *var)
1da177e4 1367{
8e42a962
LP
1368 ivideo->current_base = var->yoffset * info->var.xres_virtual
1369 + var->xoffset;
1da177e4 1370
544393fe 1371 /* calculate base bpp dep. */
8e42a962 1372 switch (info->var.bits_per_pixel) {
544393fe 1373 case 32:
1da177e4 1374 break;
544393fe
TW
1375 case 16:
1376 ivideo->current_base >>= 1;
1da177e4 1377 break;
544393fe
TW
1378 case 8:
1379 default:
1380 ivideo->current_base >>= 2;
1da177e4
LT
1381 break;
1382 }
1383
544393fe 1384 ivideo->current_base += (ivideo->video_offset >> 2);
1da177e4 1385
544393fe
TW
1386 sisfb_set_base_CRT1(ivideo, ivideo->current_base);
1387 sisfb_set_base_CRT2(ivideo, ivideo->current_base);
1da177e4 1388
544393fe
TW
1389 return 0;
1390}
1da177e4 1391
544393fe
TW
1392static int
1393sisfb_open(struct fb_info *info, int user)
1394{
1395 return 0;
1da177e4
LT
1396}
1397
1398static int
544393fe 1399sisfb_release(struct fb_info *info, int user)
1da177e4 1400{
1da177e4
LT
1401 return 0;
1402}
1403
1404static int
1405sisfb_setcolreg(unsigned regno, unsigned red, unsigned green, unsigned blue,
544393fe 1406 unsigned transp, struct fb_info *info)
1da177e4
LT
1407{
1408 struct sis_video_info *ivideo = (struct sis_video_info *)info->par;
1409
544393fe
TW
1410 if(regno >= sisfb_get_cmap_len(&info->var))
1411 return 1;
1da177e4 1412
544393fe 1413 switch(info->var.bits_per_pixel) {
1da177e4 1414 case 8:
63e13f8e
AK
1415 SiS_SetRegByte(SISDACA, regno);
1416 SiS_SetRegByte(SISDACD, (red >> 10));
1417 SiS_SetRegByte(SISDACD, (green >> 10));
1418 SiS_SetRegByte(SISDACD, (blue >> 10));
1da177e4 1419 if(ivideo->currentvbflags & VB_DISPTYPE_DISP2) {
63e13f8e
AK
1420 SiS_SetRegByte(SISDAC2A, regno);
1421 SiS_SetRegByte(SISDAC2D, (red >> 8));
1422 SiS_SetRegByte(SISDAC2D, (green >> 8));
1423 SiS_SetRegByte(SISDAC2D, (blue >> 8));
1da177e4
LT
1424 }
1425 break;
1da177e4 1426 case 16:
000d5335
AD
1427 if (regno >= 16)
1428 break;
1429
544393fe
TW
1430 ((u32 *)(info->pseudo_palette))[regno] =
1431 (red & 0xf800) |
1432 ((green & 0xfc00) >> 5) |
1433 ((blue & 0xf800) >> 11);
1da177e4 1434 break;
1da177e4 1435 case 32:
000d5335
AD
1436 if (regno >= 16)
1437 break;
1438
544393fe 1439 red >>= 8;
1da177e4 1440 green >>= 8;
544393fe
TW
1441 blue >>= 8;
1442 ((u32 *)(info->pseudo_palette))[regno] =
1443 (red << 16) | (green << 8) | (blue);
1da177e4 1444 break;
1da177e4 1445 }
1da177e4
LT
1446 return 0;
1447}
1448
1da177e4 1449static int
544393fe 1450sisfb_set_par(struct fb_info *info)
1da177e4 1451{
544393fe 1452 int err;
1da177e4 1453
544393fe
TW
1454 if((err = sisfb_do_set_var(&info->var, 1, info)))
1455 return err;
1da177e4 1456
544393fe 1457 sisfb_get_fix(&info->fix, -1, info);
14aefd1b 1458
1da177e4
LT
1459 return 0;
1460}
1461
1462static int
544393fe 1463sisfb_check_var(struct fb_var_screeninfo *var, struct fb_info *info)
1da177e4
LT
1464{
1465 struct sis_video_info *ivideo = (struct sis_video_info *)info->par;
544393fe
TW
1466 unsigned int htotal = 0, vtotal = 0, myrateindex = 0;
1467 unsigned int drate = 0, hrate = 0, maxyres;
1468 int found_mode = 0;
1469 int refresh_rate, search_idx, tidx;
c30660ea 1470 bool recalc_clock = false;
544393fe 1471 u32 pixclock;
1da177e4 1472
544393fe 1473 htotal = var->left_margin + var->xres + var->right_margin + var->hsync_len;
1da177e4 1474
544393fe 1475 vtotal = var->upper_margin + var->lower_margin + var->vsync_len;
1da177e4 1476
544393fe 1477 pixclock = var->pixclock;
1da177e4 1478
544393fe
TW
1479 if((var->vmode & FB_VMODE_MASK) == FB_VMODE_NONINTERLACED) {
1480 vtotal += var->yres;
1481 vtotal <<= 1;
1482 } else if((var->vmode & FB_VMODE_MASK) == FB_VMODE_DOUBLE) {
1483 vtotal += var->yres;
1484 vtotal <<= 2;
1485 } else if((var->vmode & FB_VMODE_MASK) == FB_VMODE_INTERLACED) {
1486 vtotal += var->yres;
1487 vtotal <<= 1;
1488 } else
1489 vtotal += var->yres;
1da177e4 1490
544393fe
TW
1491 if(!(htotal) || !(vtotal)) {
1492 SISFAIL("sisfb: no valid timing data");
1da177e4
LT
1493 }
1494
544393fe
TW
1495 search_idx = 0;
1496 while( (sisbios_mode[search_idx].mode_no[0] != 0) &&
1497 (sisbios_mode[search_idx].xres <= var->xres) ) {
1498 if( (sisbios_mode[search_idx].xres == var->xres) &&
1499 (sisbios_mode[search_idx].yres == var->yres) &&
1500 (sisbios_mode[search_idx].bpp == var->bits_per_pixel)) {
1501 if((tidx = sisfb_validate_mode(ivideo, search_idx,
1502 ivideo->currentvbflags)) > 0) {
1503 found_mode = 1;
1504 search_idx = tidx;
1505 break;
1506 }
1507 }
1508 search_idx++;
1da177e4
LT
1509 }
1510
544393fe
TW
1511 if(!found_mode) {
1512 search_idx = 0;
1513 while(sisbios_mode[search_idx].mode_no[0] != 0) {
1514 if( (var->xres <= sisbios_mode[search_idx].xres) &&
1515 (var->yres <= sisbios_mode[search_idx].yres) &&
1516 (var->bits_per_pixel == sisbios_mode[search_idx].bpp) ) {
1517 if((tidx = sisfb_validate_mode(ivideo,search_idx,
1518 ivideo->currentvbflags)) > 0) {
1519 found_mode = 1;
1520 search_idx = tidx;
1521 break;
1522 }
1523 }
1524 search_idx++;
1525 }
1526 if(found_mode) {
1527 printk(KERN_DEBUG
1528 "sisfb: Adapted from %dx%dx%d to %dx%dx%d\n",
1529 var->xres, var->yres, var->bits_per_pixel,
1530 sisbios_mode[search_idx].xres,
1531 sisbios_mode[search_idx].yres,
1532 var->bits_per_pixel);
1533 var->xres = sisbios_mode[search_idx].xres;
1534 var->yres = sisbios_mode[search_idx].yres;
1535 } else {
1536 printk(KERN_ERR
1537 "sisfb: Failed to find supported mode near %dx%dx%d\n",
1538 var->xres, var->yres, var->bits_per_pixel);
1539 return -EINVAL;
1540 }
1541 }
1da177e4 1542
544393fe
TW
1543 if( ((ivideo->vbflags2 & VB2_LVDS) ||
1544 ((ivideo->vbflags2 & VB2_30xBDH) && (ivideo->currentvbflags & CRT2_LCD))) &&
1545 (var->bits_per_pixel == 8) ) {
1546 /* Slave modes on LVDS and 301B-DH */
1547 refresh_rate = 60;
c30660ea 1548 recalc_clock = true;
544393fe
TW
1549 } else if( (ivideo->current_htotal == htotal) &&
1550 (ivideo->current_vtotal == vtotal) &&
1551 (ivideo->current_pixclock == pixclock) ) {
1552 /* x=x & y=y & c=c -> assume depth change */
1553 drate = 1000000000 / pixclock;
1554 hrate = (drate * 1000) / htotal;
1555 refresh_rate = (unsigned int) (hrate * 2 / vtotal);
1556 } else if( ( (ivideo->current_htotal != htotal) ||
1557 (ivideo->current_vtotal != vtotal) ) &&
1558 (ivideo->current_pixclock == var->pixclock) ) {
1559 /* x!=x | y!=y & c=c -> invalid pixclock */
1560 if(ivideo->sisfb_lastrates[sisbios_mode[search_idx].mode_no[ivideo->mni]]) {
1561 refresh_rate =
1562 ivideo->sisfb_lastrates[sisbios_mode[search_idx].mode_no[ivideo->mni]];
1563 } else if(ivideo->sisfb_parm_rate != -1) {
1564 /* Sic, sisfb_parm_rate - want to know originally desired rate here */
1565 refresh_rate = ivideo->sisfb_parm_rate;
1566 } else {
1567 refresh_rate = 60;
1568 }
c30660ea 1569 recalc_clock = true;
544393fe
TW
1570 } else if((pixclock) && (htotal) && (vtotal)) {
1571 drate = 1000000000 / pixclock;
1572 hrate = (drate * 1000) / htotal;
1573 refresh_rate = (unsigned int) (hrate * 2 / vtotal);
1574 } else if(ivideo->current_refresh_rate) {
1575 refresh_rate = ivideo->current_refresh_rate;
c30660ea 1576 recalc_clock = true;
544393fe
TW
1577 } else {
1578 refresh_rate = 60;
c30660ea 1579 recalc_clock = true;
544393fe 1580 }
1da177e4 1581
544393fe 1582 myrateindex = sisfb_search_refresh_rate(ivideo, refresh_rate, search_idx);
1da177e4 1583
544393fe
TW
1584 /* Eventually recalculate timing and clock */
1585 if(recalc_clock) {
1586 if(!myrateindex) myrateindex = sisbios_mode[search_idx].rate_idx;
1587 var->pixclock = (u32) (1000000000 / sisfb_mode_rate_to_dclock(&ivideo->SiS_Pr,
1588 sisbios_mode[search_idx].mode_no[ivideo->mni],
1589 myrateindex));
1590 sisfb_mode_rate_to_ddata(&ivideo->SiS_Pr,
1591 sisbios_mode[search_idx].mode_no[ivideo->mni],
1592 myrateindex, var);
1593 if((var->vmode & FB_VMODE_MASK) == FB_VMODE_DOUBLE) {
1594 var->pixclock <<= 1;
1595 }
1596 }
1da177e4 1597
544393fe
TW
1598 if(ivideo->sisfb_thismonitor.datavalid) {
1599 if(!sisfb_verify_rate(ivideo, &ivideo->sisfb_thismonitor, search_idx,
1600 myrateindex, refresh_rate)) {
1601 printk(KERN_INFO
1602 "sisfb: WARNING: Refresh rate exceeds monitor specs!\n");
1603 }
1604 }
1da177e4 1605
544393fe
TW
1606 /* Adapt RGB settings */
1607 sisfb_bpp_to_var(ivideo, var);
1da177e4 1608
544393fe
TW
1609 if(var->xres > var->xres_virtual)
1610 var->xres_virtual = var->xres;
1da177e4 1611
544393fe
TW
1612 if(ivideo->sisfb_ypan) {
1613 maxyres = sisfb_calc_maxyres(ivideo, var);
1614 if(ivideo->sisfb_max) {
1615 var->yres_virtual = maxyres;
1da177e4 1616 } else {
544393fe
TW
1617 if(var->yres_virtual > maxyres) {
1618 var->yres_virtual = maxyres;
1619 }
1da177e4 1620 }
544393fe
TW
1621 if(var->yres_virtual <= var->yres) {
1622 var->yres_virtual = var->yres;
1da177e4 1623 }
1da177e4 1624 } else {
544393fe
TW
1625 if(var->yres != var->yres_virtual) {
1626 var->yres_virtual = var->yres;
1627 }
1628 var->xoffset = 0;
1629 var->yoffset = 0;
1da177e4
LT
1630 }
1631
1da177e4
LT
1632 /* Truncate offsets to maximum if too high */
1633 if(var->xoffset > var->xres_virtual - var->xres) {
544393fe 1634 var->xoffset = var->xres_virtual - var->xres - 1;
1da177e4
LT
1635 }
1636
1637 if(var->yoffset > var->yres_virtual - var->yres) {
544393fe 1638 var->yoffset = var->yres_virtual - var->yres - 1;
1da177e4 1639 }
544393fe 1640
1da177e4 1641 /* Set everything else to 0 */
544393fe
TW
1642 var->red.msb_right =
1643 var->green.msb_right =
1644 var->blue.msb_right =
1645 var->transp.offset =
1646 var->transp.length =
1647 var->transp.msb_right = 0;
1da177e4
LT
1648
1649 return 0;
1650}
1651
1652static int
1653sisfb_pan_display(struct fb_var_screeninfo *var, struct fb_info* info)
1654{
1655 struct sis_video_info *ivideo = (struct sis_video_info *)info->par;
1656 int err;
1657
8e42a962 1658 if (var->vmode & FB_VMODE_YWRAP)
544393fe 1659 return -EINVAL;
1da177e4 1660
8e42a962
LP
1661 if (var->xoffset + info->var.xres > info->var.xres_virtual ||
1662 var->yoffset + info->var.yres > info->var.yres_virtual)
1da177e4 1663 return -EINVAL;
1da177e4 1664
8e42a962
LP
1665 err = sisfb_pan_var(ivideo, info, var);
1666 if (err < 0)
544393fe 1667 return err;
1da177e4
LT
1668
1669 info->var.xoffset = var->xoffset;
1670 info->var.yoffset = var->yoffset;
1671
1672 return 0;
1673}
1674
1675static int
1676sisfb_blank(int blank, struct fb_info *info)
1677{
1678 struct sis_video_info *ivideo = (struct sis_video_info *)info->par;
1679
544393fe 1680 return sisfb_myblank(ivideo, blank);
1da177e4
LT
1681}
1682
1da177e4
LT
1683/* ----------- FBDev related routines for all series ---------- */
1684
67a6680d
CH
1685static int sisfb_ioctl(struct fb_info *info, unsigned int cmd,
1686 unsigned long arg)
1da177e4
LT
1687{
1688 struct sis_video_info *ivideo = (struct sis_video_info *)info->par;
544393fe
TW
1689 struct sis_memreq sismemreq;
1690 struct fb_vblank sisvbblank;
1da177e4
LT
1691 u32 gpu32 = 0;
1692#ifndef __user
1693#define __user
1694#endif
1695 u32 __user *argp = (u32 __user *)arg;
1696
544393fe 1697 switch(cmd) {
1da177e4 1698 case FBIO_ALLOC:
544393fe 1699 if(!capable(CAP_SYS_RAWIO))
1da177e4 1700 return -EPERM;
544393fe
TW
1701
1702 if(copy_from_user(&sismemreq, (void __user *)arg, sizeof(sismemreq)))
1703 return -EFAULT;
1704
1da177e4 1705 sis_malloc(&sismemreq);
544393fe 1706
1da177e4
LT
1707 if(copy_to_user((void __user *)arg, &sismemreq, sizeof(sismemreq))) {
1708 sis_free((u32)sismemreq.offset);
544393fe 1709 return -EFAULT;
1da177e4
LT
1710 }
1711 break;
1712
1713 case FBIO_FREE:
544393fe 1714 if(!capable(CAP_SYS_RAWIO))
1da177e4 1715 return -EPERM;
544393fe
TW
1716
1717 if(get_user(gpu32, argp))
1da177e4 1718 return -EFAULT;
544393fe 1719
1da177e4
LT
1720 sis_free(gpu32);
1721 break;
1722
1723 case FBIOGET_VBLANK:
fd02db9d
DR
1724
1725 memset(&sisvbblank, 0, sizeof(struct fb_vblank));
1726
1da177e4
LT
1727 sisvbblank.count = 0;
1728 sisvbblank.flags = sisfb_setupvbblankflags(ivideo, &sisvbblank.vcount, &sisvbblank.hcount);
544393fe
TW
1729
1730 if(copy_to_user((void __user *)arg, &sisvbblank, sizeof(sisvbblank)))
1da177e4 1731 return -EFAULT;
544393fe 1732
1da177e4
LT
1733 break;
1734
1735 case SISFB_GET_INFO_SIZE:
544393fe 1736 return put_user(sizeof(struct sisfb_info), argp);
1da177e4
LT
1737
1738 case SISFB_GET_INFO_OLD:
544393fe
TW
1739 if(ivideo->warncount++ < 10)
1740 printk(KERN_INFO
1741 "sisfb: Deprecated ioctl call received - update your application!\n");
df561f66 1742 fallthrough;
1da177e4 1743 case SISFB_GET_INFO: /* For communication with X driver */
544393fe
TW
1744 ivideo->sisfb_infoblock.sisfb_id = SISFB_ID;
1745 ivideo->sisfb_infoblock.sisfb_version = VER_MAJOR;
1746 ivideo->sisfb_infoblock.sisfb_revision = VER_MINOR;
1747 ivideo->sisfb_infoblock.sisfb_patchlevel = VER_LEVEL;
1748 ivideo->sisfb_infoblock.chip_id = ivideo->chip_id;
1749 ivideo->sisfb_infoblock.sisfb_pci_vendor = ivideo->chip_vendor;
1750 ivideo->sisfb_infoblock.memory = ivideo->video_size / 1024;
1751 ivideo->sisfb_infoblock.heapstart = ivideo->heapstart / 1024;
1da177e4 1752 if(ivideo->modechanged) {
544393fe 1753 ivideo->sisfb_infoblock.fbvidmode = ivideo->mode_no;
1da177e4 1754 } else {
544393fe 1755 ivideo->sisfb_infoblock.fbvidmode = ivideo->modeprechange;
1da177e4 1756 }
544393fe
TW
1757 ivideo->sisfb_infoblock.sisfb_caps = ivideo->caps;
1758 ivideo->sisfb_infoblock.sisfb_tqlen = ivideo->cmdQueueSize / 1024;
1759 ivideo->sisfb_infoblock.sisfb_pcibus = ivideo->pcibus;
1760 ivideo->sisfb_infoblock.sisfb_pcislot = ivideo->pcislot;
1761 ivideo->sisfb_infoblock.sisfb_pcifunc = ivideo->pcifunc;
1762 ivideo->sisfb_infoblock.sisfb_lcdpdc = ivideo->detectedpdc;
1763 ivideo->sisfb_infoblock.sisfb_lcdpdca = ivideo->detectedpdca;
1764 ivideo->sisfb_infoblock.sisfb_lcda = ivideo->detectedlcda;
1765 ivideo->sisfb_infoblock.sisfb_vbflags = ivideo->vbflags;
1766 ivideo->sisfb_infoblock.sisfb_currentvbflags = ivideo->currentvbflags;
1767 ivideo->sisfb_infoblock.sisfb_scalelcd = ivideo->SiS_Pr.UsePanelScaler;
1768 ivideo->sisfb_infoblock.sisfb_specialtiming = ivideo->SiS_Pr.SiS_CustomT;
1769 ivideo->sisfb_infoblock.sisfb_haveemi = ivideo->SiS_Pr.HaveEMI ? 1 : 0;
1770 ivideo->sisfb_infoblock.sisfb_haveemilcd = ivideo->SiS_Pr.HaveEMILCD ? 1 : 0;
1771 ivideo->sisfb_infoblock.sisfb_emi30 = ivideo->SiS_Pr.EMI_30;
1772 ivideo->sisfb_infoblock.sisfb_emi31 = ivideo->SiS_Pr.EMI_31;
1773 ivideo->sisfb_infoblock.sisfb_emi32 = ivideo->SiS_Pr.EMI_32;
1774 ivideo->sisfb_infoblock.sisfb_emi33 = ivideo->SiS_Pr.EMI_33;
1775 ivideo->sisfb_infoblock.sisfb_tvxpos = (u16)(ivideo->tvxpos + 32);
1776 ivideo->sisfb_infoblock.sisfb_tvypos = (u16)(ivideo->tvypos + 32);
1777 ivideo->sisfb_infoblock.sisfb_heapsize = ivideo->sisfb_heap_size / 1024;
1778 ivideo->sisfb_infoblock.sisfb_videooffset = ivideo->video_offset;
1779 ivideo->sisfb_infoblock.sisfb_curfstn = ivideo->curFSTN;
1780 ivideo->sisfb_infoblock.sisfb_curdstn = ivideo->curDSTN;
1781 ivideo->sisfb_infoblock.sisfb_vbflags2 = ivideo->vbflags2;
1782 ivideo->sisfb_infoblock.sisfb_can_post = ivideo->sisfb_can_post ? 1 : 0;
1783 ivideo->sisfb_infoblock.sisfb_card_posted = ivideo->sisfb_card_posted ? 1 : 0;
1784 ivideo->sisfb_infoblock.sisfb_was_boot_device = ivideo->sisfb_was_boot_device ? 1 : 0;
1785
1786 if(copy_to_user((void __user *)arg, &ivideo->sisfb_infoblock,
1787 sizeof(ivideo->sisfb_infoblock)))
1788 return -EFAULT;
1789
1da177e4
LT
1790 break;
1791
1792 case SISFB_GET_VBRSTATUS_OLD:
544393fe
TW
1793 if(ivideo->warncount++ < 10)
1794 printk(KERN_INFO
1795 "sisfb: Deprecated ioctl call received - update your application!\n");
df561f66 1796 fallthrough;
1da177e4 1797 case SISFB_GET_VBRSTATUS:
544393fe 1798 if(sisfb_CheckVBRetrace(ivideo))
1da177e4 1799 return put_user((u32)1, argp);
544393fe 1800 else
1da177e4 1801 return put_user((u32)0, argp);
1da177e4
LT
1802
1803 case SISFB_GET_AUTOMAXIMIZE_OLD:
544393fe
TW
1804 if(ivideo->warncount++ < 10)
1805 printk(KERN_INFO
1806 "sisfb: Deprecated ioctl call received - update your application!\n");
df561f66 1807 fallthrough;
1da177e4 1808 case SISFB_GET_AUTOMAXIMIZE:
544393fe
TW
1809 if(ivideo->sisfb_max)
1810 return put_user((u32)1, argp);
1811 else
1812 return put_user((u32)0, argp);
1da177e4
LT
1813
1814 case SISFB_SET_AUTOMAXIMIZE_OLD:
544393fe
TW
1815 if(ivideo->warncount++ < 10)
1816 printk(KERN_INFO
1817 "sisfb: Deprecated ioctl call received - update your application!\n");
df561f66 1818 fallthrough;
1da177e4 1819 case SISFB_SET_AUTOMAXIMIZE:
544393fe 1820 if(get_user(gpu32, argp))
1da177e4 1821 return -EFAULT;
544393fe 1822
1da177e4
LT
1823 ivideo->sisfb_max = (gpu32) ? 1 : 0;
1824 break;
1825
1826 case SISFB_SET_TVPOSOFFSET:
544393fe 1827 if(get_user(gpu32, argp))
1da177e4 1828 return -EFAULT;
544393fe 1829
1da177e4
LT
1830 sisfb_set_TVxposoffset(ivideo, ((int)(gpu32 >> 16)) - 32);
1831 sisfb_set_TVyposoffset(ivideo, ((int)(gpu32 & 0xffff)) - 32);
1832 break;
1833
1834 case SISFB_GET_TVPOSOFFSET:
544393fe
TW
1835 return put_user((u32)(((ivideo->tvxpos+32)<<16)|((ivideo->tvypos+32)&0xffff)),
1836 argp);
1837
1838 case SISFB_COMMAND:
1839 if(copy_from_user(&ivideo->sisfb_command, (void __user *)arg,
1840 sizeof(struct sisfb_cmd)))
1841 return -EFAULT;
1842
1843 sisfb_handle_command(ivideo, &ivideo->sisfb_command);
1844
1845 if(copy_to_user((void __user *)arg, &ivideo->sisfb_command,
1846 sizeof(struct sisfb_cmd)))
1847 return -EFAULT;
1848
1849 break;
1da177e4
LT
1850
1851 case SISFB_SET_LOCK:
544393fe 1852 if(get_user(gpu32, argp))
1da177e4 1853 return -EFAULT;
544393fe 1854
1da177e4
LT
1855 ivideo->sisfblocked = (gpu32) ? 1 : 0;
1856 break;
1857
1858 default:
544393fe 1859#ifdef SIS_NEW_CONFIG_COMPAT
1da177e4 1860 return -ENOIOCTLCMD;
544393fe
TW
1861#else
1862 return -EINVAL;
1863#endif
1da177e4
LT
1864 }
1865 return 0;
1866}
1867
1da177e4
LT
1868static int
1869sisfb_get_fix(struct fb_fix_screeninfo *fix, int con, struct fb_info *info)
1870{
1871 struct sis_video_info *ivideo = (struct sis_video_info *)info->par;
1872
1873 memset(fix, 0, sizeof(struct fb_fix_screeninfo));
1874
dbd536bf 1875 strlcpy(fix->id, ivideo->myid, sizeof(fix->id));
1da177e4 1876
537a1bf0 1877 mutex_lock(&info->mm_lock);
544393fe 1878 fix->smem_start = ivideo->video_base + ivideo->video_offset;
1da177e4 1879 fix->smem_len = ivideo->sisfb_mem;
537a1bf0 1880 mutex_unlock(&info->mm_lock);
1da177e4
LT
1881 fix->type = FB_TYPE_PACKED_PIXELS;
1882 fix->type_aux = 0;
1883 fix->visual = (ivideo->video_bpp == 8) ? FB_VISUAL_PSEUDOCOLOR : FB_VISUAL_TRUECOLOR;
1884 fix->xpanstep = 1;
1885 fix->ypanstep = (ivideo->sisfb_ypan) ? 1 : 0;
1886 fix->ywrapstep = 0;
1887 fix->line_length = ivideo->video_linelength;
1888 fix->mmio_start = ivideo->mmio_base;
1889 fix->mmio_len = ivideo->mmio_size;
1890 if(ivideo->sisvga_engine == SIS_300_VGA) {
544393fe
TW
1891 fix->accel = FB_ACCEL_SIS_GLAMOUR;
1892 } else if((ivideo->chip == SIS_330) ||
1893 (ivideo->chip == SIS_760) ||
1894 (ivideo->chip == SIS_761)) {
1895 fix->accel = FB_ACCEL_SIS_XABRE;
1896 } else if(ivideo->chip == XGI_20) {
1897 fix->accel = FB_ACCEL_XGI_VOLARI_Z;
1898 } else if(ivideo->chip >= XGI_40) {
1899 fix->accel = FB_ACCEL_XGI_VOLARI_V;
1da177e4 1900 } else {
544393fe 1901 fix->accel = FB_ACCEL_SIS_GLAMOUR_2;
1da177e4
LT
1902 }
1903
1904 return 0;
1905}
1906
1907/* ---------------- fb_ops structures ----------------- */
1908
8a48ac33 1909static const struct fb_ops sisfb_ops = {
544393fe
TW
1910 .owner = THIS_MODULE,
1911 .fb_open = sisfb_open,
1912 .fb_release = sisfb_release,
1913 .fb_check_var = sisfb_check_var,
1914 .fb_set_par = sisfb_set_par,
1915 .fb_setcolreg = sisfb_setcolreg,
1916 .fb_pan_display = sisfb_pan_display,
1917 .fb_blank = sisfb_blank,
1918 .fb_fillrect = fbcon_sis_fillrect,
1919 .fb_copyarea = fbcon_sis_copyarea,
1920 .fb_imageblit = cfb_imageblit,
544393fe
TW
1921 .fb_sync = fbcon_sis_sync,
1922#ifdef SIS_NEW_CONFIG_COMPAT
67a6680d 1923 .fb_compat_ioctl= sisfb_ioctl,
1da177e4 1924#endif
544393fe 1925 .fb_ioctl = sisfb_ioctl
1da177e4 1926};
1da177e4
LT
1927
1928/* ---------------- Chip generation dependent routines ---------------- */
1929
48c68c4f 1930static struct pci_dev *sisfb_get_northbridge(int basechipid)
1da177e4
LT
1931{
1932 struct pci_dev *pdev = NULL;
1933 int nbridgenum, nbridgeidx, i;
544393fe 1934 static const unsigned short nbridgeids[] = {
1da177e4
LT
1935 PCI_DEVICE_ID_SI_540, /* for SiS 540 VGA */
1936 PCI_DEVICE_ID_SI_630, /* for SiS 630/730 VGA */
1937 PCI_DEVICE_ID_SI_730,
1938 PCI_DEVICE_ID_SI_550, /* for SiS 550 VGA */
1939 PCI_DEVICE_ID_SI_650, /* for SiS 650/651/740 VGA */
1940 PCI_DEVICE_ID_SI_651,
1941 PCI_DEVICE_ID_SI_740,
544393fe 1942 PCI_DEVICE_ID_SI_661, /* for SiS 661/741/660/760/761 VGA */
1da177e4
LT
1943 PCI_DEVICE_ID_SI_741,
1944 PCI_DEVICE_ID_SI_660,
544393fe
TW
1945 PCI_DEVICE_ID_SI_760,
1946 PCI_DEVICE_ID_SI_761
1da177e4
LT
1947 };
1948
544393fe 1949 switch(basechipid) {
1da177e4
LT
1950#ifdef CONFIG_FB_SIS_300
1951 case SIS_540: nbridgeidx = 0; nbridgenum = 1; break;
1952 case SIS_630: nbridgeidx = 1; nbridgenum = 2; break;
1953#endif
1954#ifdef CONFIG_FB_SIS_315
1955 case SIS_550: nbridgeidx = 3; nbridgenum = 1; break;
1956 case SIS_650: nbridgeidx = 4; nbridgenum = 3; break;
544393fe 1957 case SIS_660: nbridgeidx = 7; nbridgenum = 5; break;
1da177e4
LT
1958#endif
1959 default: return NULL;
1960 }
1961 for(i = 0; i < nbridgenum; i++) {
0959f0ca 1962 if((pdev = pci_get_device(PCI_VENDOR_ID_SI,
544393fe
TW
1963 nbridgeids[nbridgeidx+i], NULL)))
1964 break;
1da177e4
LT
1965 }
1966 return pdev;
1967}
1968
48c68c4f 1969static int sisfb_get_dram_size(struct sis_video_info *ivideo)
1da177e4
LT
1970{
1971#if defined(CONFIG_FB_SIS_300) || defined(CONFIG_FB_SIS_315)
1972 u8 reg;
1973#endif
1974
1975 ivideo->video_size = 0;
544393fe 1976 ivideo->UMAsize = ivideo->LFBsize = 0;
1da177e4
LT
1977
1978 switch(ivideo->chip) {
1979#ifdef CONFIG_FB_SIS_300
1980 case SIS_300:
e57d4136 1981 reg = SiS_GetReg(SISSR, 0x14);
1da177e4
LT
1982 ivideo->video_size = ((reg & 0x3F) + 1) << 20;
1983 break;
1984 case SIS_540:
1985 case SIS_630:
1986 case SIS_730:
544393fe
TW
1987 if(!ivideo->nbridge)
1988 return -1;
1989 pci_read_config_byte(ivideo->nbridge, 0x63, &reg);
1da177e4
LT
1990 ivideo->video_size = 1 << (((reg & 0x70) >> 4) + 21);
1991 break;
1992#endif
1993#ifdef CONFIG_FB_SIS_315
1994 case SIS_315H:
1995 case SIS_315PRO:
1996 case SIS_315:
e57d4136 1997 reg = SiS_GetReg(SISSR, 0x14);
1da177e4
LT
1998 ivideo->video_size = (1 << ((reg & 0xf0) >> 4)) << 20;
1999 switch((reg >> 2) & 0x03) {
2000 case 0x01:
2001 case 0x03:
544393fe
TW
2002 ivideo->video_size <<= 1;
2003 break;
1da177e4 2004 case 0x02:
544393fe 2005 ivideo->video_size += (ivideo->video_size/2);
1da177e4 2006 }
544393fe 2007 break;
1da177e4 2008 case SIS_330:
e57d4136 2009 reg = SiS_GetReg(SISSR, 0x14);
1da177e4
LT
2010 ivideo->video_size = (1 << ((reg & 0xf0) >> 4)) << 20;
2011 if(reg & 0x0c) ivideo->video_size <<= 1;
544393fe 2012 break;
1da177e4
LT
2013 case SIS_550:
2014 case SIS_650:
2015 case SIS_740:
e57d4136 2016 reg = SiS_GetReg(SISSR, 0x14);
1da177e4
LT
2017 ivideo->video_size = (((reg & 0x3f) + 1) << 2) << 20;
2018 break;
2019 case SIS_661:
2020 case SIS_741:
e57d4136 2021 reg = SiS_GetReg(SISCR, 0x79);
1da177e4 2022 ivideo->video_size = (1 << ((reg & 0xf0) >> 4)) << 20;
544393fe 2023 break;
1da177e4
LT
2024 case SIS_660:
2025 case SIS_760:
544393fe 2026 case SIS_761:
e57d4136 2027 reg = SiS_GetReg(SISCR, 0x79);
1da177e4 2028 reg = (reg & 0xf0) >> 4;
544393fe
TW
2029 if(reg) {
2030 ivideo->video_size = (1 << reg) << 20;
2031 ivideo->UMAsize = ivideo->video_size;
2032 }
e57d4136 2033 reg = SiS_GetReg(SISCR, 0x78);
1da177e4
LT
2034 reg &= 0x30;
2035 if(reg) {
544393fe
TW
2036 if(reg == 0x10) {
2037 ivideo->LFBsize = (32 << 20);
2038 } else {
2039 ivideo->LFBsize = (64 << 20);
2040 }
2041 ivideo->video_size += ivideo->LFBsize;
2042 }
2043 break;
2044 case SIS_340:
2045 case XGI_20:
2046 case XGI_40:
e57d4136 2047 reg = SiS_GetReg(SISSR, 0x14);
544393fe
TW
2048 ivideo->video_size = (1 << ((reg & 0xf0) >> 4)) << 20;
2049 if(ivideo->chip != XGI_20) {
2050 reg = (reg & 0x0c) >> 2;
2051 if(ivideo->revision_id == 2) {
2052 if(reg & 0x01) reg = 0x02;
2053 else reg = 0x00;
2054 }
2055 if(reg == 0x02) ivideo->video_size <<= 1;
2056 else if(reg == 0x03) ivideo->video_size <<= 2;
1da177e4 2057 }
544393fe 2058 break;
1da177e4
LT
2059#endif
2060 default:
2061 return -1;
2062 }
2063 return 0;
2064}
2065
2066/* -------------- video bridge device detection --------------- */
2067
48c68c4f 2068static void sisfb_detect_VB_connect(struct sis_video_info *ivideo)
1da177e4
LT
2069{
2070 u8 cr32, temp;
2071
544393fe
TW
2072 /* No CRT2 on XGI Z7 */
2073 if(ivideo->chip == XGI_20) {
2074 ivideo->sisfb_crt1off = 0;
2075 return;
2076 }
2077
1da177e4
LT
2078#ifdef CONFIG_FB_SIS_300
2079 if(ivideo->sisvga_engine == SIS_300_VGA) {
e57d4136 2080 temp = SiS_GetReg(SISSR, 0x17);
1da177e4
LT
2081 if((temp & 0x0F) && (ivideo->chip != SIS_300)) {
2082 /* PAL/NTSC is stored on SR16 on such machines */
2083 if(!(ivideo->vbflags & (TV_PAL | TV_NTSC | TV_PALM | TV_PALN))) {
e57d4136 2084 temp = SiS_GetReg(SISSR, 0x16);
1da177e4
LT
2085 if(temp & 0x20)
2086 ivideo->vbflags |= TV_PAL;
2087 else
2088 ivideo->vbflags |= TV_NTSC;
2089 }
2090 }
2091 }
2092#endif
2093
e57d4136 2094 cr32 = SiS_GetReg(SISCR, 0x32);
1da177e4
LT
2095
2096 if(cr32 & SIS_CRT1) {
2097 ivideo->sisfb_crt1off = 0;
2098 } else {
2099 ivideo->sisfb_crt1off = (cr32 & 0xDF) ? 1 : 0;
2100 }
2101
2102 ivideo->vbflags &= ~(CRT2_TV | CRT2_LCD | CRT2_VGA);
2103
2104 if(cr32 & SIS_VB_TV) ivideo->vbflags |= CRT2_TV;
2105 if(cr32 & SIS_VB_LCD) ivideo->vbflags |= CRT2_LCD;
2106 if(cr32 & SIS_VB_CRT2) ivideo->vbflags |= CRT2_VGA;
2107
2108 /* Check given parms for hardware compatibility.
2109 * (Cannot do this in the search_xx routines since we don't
2110 * know what hardware we are running on then)
2111 */
2112
2113 if(ivideo->chip != SIS_550) {
2114 ivideo->sisfb_dstn = ivideo->sisfb_fstn = 0;
2115 }
2116
2117 if(ivideo->sisfb_tvplug != -1) {
2118 if( (ivideo->sisvga_engine != SIS_315_VGA) ||
544393fe 2119 (!(ivideo->vbflags2 & VB2_SISYPBPRBRIDGE)) ) {
1da177e4 2120 if(ivideo->sisfb_tvplug & TV_YPBPR) {
544393fe 2121 ivideo->sisfb_tvplug = -1;
1da177e4
LT
2122 printk(KERN_ERR "sisfb: YPbPr not supported\n");
2123 }
2124 }
2125 }
2126 if(ivideo->sisfb_tvplug != -1) {
2127 if( (ivideo->sisvga_engine != SIS_315_VGA) ||
544393fe 2128 (!(ivideo->vbflags2 & VB2_SISHIVISIONBRIDGE)) ) {
1da177e4 2129 if(ivideo->sisfb_tvplug & TV_HIVISION) {
544393fe 2130 ivideo->sisfb_tvplug = -1;
1da177e4
LT
2131 printk(KERN_ERR "sisfb: HiVision not supported\n");
2132 }
2133 }
2134 }
2135 if(ivideo->sisfb_tvstd != -1) {
544393fe
TW
2136 if( (!(ivideo->vbflags2 & VB2_SISBRIDGE)) &&
2137 (!((ivideo->sisvga_engine == SIS_315_VGA) &&
2138 (ivideo->vbflags2 & VB2_CHRONTEL))) ) {
5ab94815 2139 if(ivideo->sisfb_tvstd & (TV_PALM | TV_PALN | TV_NTSCJ)) {
544393fe
TW
2140 ivideo->sisfb_tvstd = -1;
2141 printk(KERN_ERR "sisfb: PALM/PALN/NTSCJ not supported\n");
1da177e4
LT
2142 }
2143 }
2144 }
2145
2146 /* Detect/set TV plug & type */
2147 if(ivideo->sisfb_tvplug != -1) {
2148 ivideo->vbflags |= ivideo->sisfb_tvplug;
2149 } else {
2150 if(cr32 & SIS_VB_YPBPR) ivideo->vbflags |= (TV_YPBPR|TV_YPBPR525I); /* default: 480i */
2151 else if(cr32 & SIS_VB_HIVISION) ivideo->vbflags |= TV_HIVISION;
2152 else if(cr32 & SIS_VB_SCART) ivideo->vbflags |= TV_SCART;
544393fe 2153 else {
1da177e4
LT
2154 if(cr32 & SIS_VB_SVIDEO) ivideo->vbflags |= TV_SVIDEO;
2155 if(cr32 & SIS_VB_COMPOSITE) ivideo->vbflags |= TV_AVIDEO;
2156 }
2157 }
2158
2159 if(!(ivideo->vbflags & (TV_YPBPR | TV_HIVISION))) {
2160 if(ivideo->sisfb_tvstd != -1) {
2161 ivideo->vbflags &= ~(TV_NTSC | TV_PAL | TV_PALM | TV_PALN | TV_NTSCJ);
2162 ivideo->vbflags |= ivideo->sisfb_tvstd;
2163 }
2164 if(ivideo->vbflags & TV_SCART) {
2165 ivideo->vbflags &= ~(TV_NTSC | TV_PALM | TV_PALN | TV_NTSCJ);
2166 ivideo->vbflags |= TV_PAL;
2167 }
2168 if(!(ivideo->vbflags & (TV_PAL | TV_NTSC | TV_PALM | TV_PALN | TV_NTSCJ))) {
2169 if(ivideo->sisvga_engine == SIS_300_VGA) {
e57d4136 2170 temp = SiS_GetReg(SISSR, 0x38);
1da177e4
LT
2171 if(temp & 0x01) ivideo->vbflags |= TV_PAL;
2172 else ivideo->vbflags |= TV_NTSC;
2173 } else if((ivideo->chip <= SIS_315PRO) || (ivideo->chip >= SIS_330)) {
e57d4136 2174 temp = SiS_GetReg(SISSR, 0x38);
1da177e4
LT
2175 if(temp & 0x01) ivideo->vbflags |= TV_PAL;
2176 else ivideo->vbflags |= TV_NTSC;
544393fe 2177 } else {
e57d4136 2178 temp = SiS_GetReg(SISCR, 0x79);
1da177e4
LT
2179 if(temp & 0x20) ivideo->vbflags |= TV_PAL;
2180 else ivideo->vbflags |= TV_NTSC;
544393fe 2181 }
1da177e4
LT
2182 }
2183 }
2184
2185 /* Copy forceCRT1 option to CRT1off if option is given */
544393fe
TW
2186 if(ivideo->sisfb_forcecrt1 != -1) {
2187 ivideo->sisfb_crt1off = (ivideo->sisfb_forcecrt1) ? 0 : 1;
1da177e4
LT
2188 }
2189}
2190
2191/* ------------------ Sensing routines ------------------ */
2192
48c68c4f 2193static bool sisfb_test_DDC1(struct sis_video_info *ivideo)
1da177e4
LT
2194{
2195 unsigned short old;
2196 int count = 48;
2197
2198 old = SiS_ReadDDC1Bit(&ivideo->SiS_Pr);
2199 do {
544393fe 2200 if(old != SiS_ReadDDC1Bit(&ivideo->SiS_Pr)) break;
1da177e4 2201 } while(count--);
c30660ea 2202 return (count != -1);
1da177e4
LT
2203}
2204
48c68c4f 2205static void sisfb_sense_crt1(struct sis_video_info *ivideo)
1da177e4 2206{
c30660ea 2207 bool mustwait = false;
1da177e4
LT
2208 u8 sr1F, cr17;
2209#ifdef CONFIG_FB_SIS_315
2210 u8 cr63=0;
2211#endif
2212 u16 temp = 0xffff;
2213 int i;
2214
e57d4136 2215 sr1F = SiS_GetReg(SISSR, 0x1F);
27799d6c 2216 SiS_SetRegOR(SISSR, 0x1F, 0x04);
667a8b41 2217 SiS_SetRegAND(SISSR, 0x1F, 0x3F);
c30660ea 2218 if(sr1F & 0xc0) mustwait = true;
1da177e4
LT
2219
2220#ifdef CONFIG_FB_SIS_315
2221 if(ivideo->sisvga_engine == SIS_315_VGA) {
e57d4136 2222 cr63 = SiS_GetReg(SISCR, ivideo->SiS_Pr.SiS_MyCR63);
1da177e4 2223 cr63 &= 0x40;
667a8b41 2224 SiS_SetRegAND(SISCR, ivideo->SiS_Pr.SiS_MyCR63, 0xBF);
1da177e4
LT
2225 }
2226#endif
2227
e57d4136 2228 cr17 = SiS_GetReg(SISCR, 0x17);
1da177e4
LT
2229 cr17 &= 0x80;
2230 if(!cr17) {
27799d6c 2231 SiS_SetRegOR(SISCR, 0x17, 0x80);
c30660ea 2232 mustwait = true;
44b751bb
AK
2233 SiS_SetReg(SISSR, 0x00, 0x01);
2234 SiS_SetReg(SISSR, 0x00, 0x03);
1da177e4
LT
2235 }
2236
2237 if(mustwait) {
2238 for(i=0; i < 10; i++) sisfbwaitretracecrt1(ivideo);
2239 }
2240
2241#ifdef CONFIG_FB_SIS_315
2242 if(ivideo->chip >= SIS_330) {
667a8b41 2243 SiS_SetRegAND(SISCR, 0x32, ~0x20);
1da177e4 2244 if(ivideo->chip >= SIS_340) {
44b751bb 2245 SiS_SetReg(SISCR, 0x57, 0x4a);
1da177e4 2246 } else {
44b751bb 2247 SiS_SetReg(SISCR, 0x57, 0x5f);
1da177e4 2248 }
27799d6c 2249 SiS_SetRegOR(SISCR, 0x53, 0x02);
1e1687d7
AK
2250 while ((SiS_GetRegByte(SISINPSTAT)) & 0x01) break;
2251 while (!((SiS_GetRegByte(SISINPSTAT)) & 0x01)) break;
2252 if ((SiS_GetRegByte(SISMISCW)) & 0x10) temp = 1;
667a8b41
AK
2253 SiS_SetRegAND(SISCR, 0x53, 0xfd);
2254 SiS_SetRegAND(SISCR, 0x57, 0x00);
1da177e4
LT
2255 }
2256#endif
2257
2258 if(temp == 0xffff) {
2259 i = 3;
2260 do {
544393fe
TW
2261 temp = SiS_HandleDDC(&ivideo->SiS_Pr, ivideo->vbflags,
2262 ivideo->sisvga_engine, 0, 0, NULL, ivideo->vbflags2);
1da177e4
LT
2263 } while(((temp == 0) || (temp == 0xffff)) && i--);
2264
2265 if((temp == 0) || (temp == 0xffff)) {
2266 if(sisfb_test_DDC1(ivideo)) temp = 1;
2267 }
2268 }
2269
2270 if((temp) && (temp != 0xffff)) {
27799d6c 2271 SiS_SetRegOR(SISCR, 0x32, 0x20);
1da177e4
LT
2272 }
2273
2274#ifdef CONFIG_FB_SIS_315
2275 if(ivideo->sisvga_engine == SIS_315_VGA) {
ad78adb4 2276 SiS_SetRegANDOR(SISCR, ivideo->SiS_Pr.SiS_MyCR63, 0xBF, cr63);
1da177e4
LT
2277 }
2278#endif
2279
ad78adb4 2280 SiS_SetRegANDOR(SISCR, 0x17, 0x7F, cr17);
1da177e4 2281
44b751bb 2282 SiS_SetReg(SISSR, 0x1F, sr1F);
1da177e4
LT
2283}
2284
2285/* Determine and detect attached devices on SiS30x */
48c68c4f 2286static void SiS_SenseLCD(struct sis_video_info *ivideo)
544393fe
TW
2287{
2288 unsigned char buffer[256];
2289 unsigned short temp, realcrtno, i;
2290 u8 reg, cr37 = 0, paneltype = 0;
2291 u16 xres, yres;
2292
c30660ea 2293 ivideo->SiS_Pr.PanelSelfDetected = false;
544393fe
TW
2294
2295 /* LCD detection only for TMDS bridges */
2296 if(!(ivideo->vbflags2 & VB2_SISTMDSBRIDGE))
2297 return;
2298 if(ivideo->vbflags2 & VB2_30xBDH)
2299 return;
2300
2301 /* If LCD already set up by BIOS, skip it */
e57d4136 2302 reg = SiS_GetReg(SISCR, 0x32);
544393fe
TW
2303 if(reg & 0x08)
2304 return;
2305
2306 realcrtno = 1;
2307 if(ivideo->SiS_Pr.DDCPortMixup)
2308 realcrtno = 0;
2309
2310 /* Check DDC capabilities */
2311 temp = SiS_HandleDDC(&ivideo->SiS_Pr, ivideo->vbflags, ivideo->sisvga_engine,
2312 realcrtno, 0, &buffer[0], ivideo->vbflags2);
2313
2314 if((!temp) || (temp == 0xffff) || (!(temp & 0x02)))
2315 return;
2316
2317 /* Read DDC data */
2318 i = 3; /* Number of retrys */
2319 do {
2320 temp = SiS_HandleDDC(&ivideo->SiS_Pr, ivideo->vbflags,
2321 ivideo->sisvga_engine, realcrtno, 1,
2322 &buffer[0], ivideo->vbflags2);
2323 } while((temp) && i--);
2324
2325 if(temp)
2326 return;
2327
2328 /* No digital device */
2329 if(!(buffer[0x14] & 0x80))
2330 return;
2331
2332 /* First detailed timing preferred timing? */
2333 if(!(buffer[0x18] & 0x02))
2334 return;
2335
2336 xres = buffer[0x38] | ((buffer[0x3a] & 0xf0) << 4);
2337 yres = buffer[0x3b] | ((buffer[0x3d] & 0xf0) << 4);
2338
2339 switch(xres) {
2340 case 1024:
2341 if(yres == 768)
2342 paneltype = 0x02;
2343 break;
2344 case 1280:
2345 if(yres == 1024)
2346 paneltype = 0x03;
2347 break;
2348 case 1600:
2349 if((yres == 1200) && (ivideo->vbflags2 & VB2_30xC))
2350 paneltype = 0x0b;
2351 break;
2352 }
2353
2354 if(!paneltype)
2355 return;
2356
2357 if(buffer[0x23])
2358 cr37 |= 0x10;
2359
2360 if((buffer[0x47] & 0x18) == 0x18)
2361 cr37 |= ((((buffer[0x47] & 0x06) ^ 0x06) << 5) | 0x20);
2362 else
2363 cr37 |= 0xc0;
2364
44b751bb 2365 SiS_SetReg(SISCR, 0x36, paneltype);
544393fe 2366 cr37 &= 0xf1;
ad78adb4 2367 SiS_SetRegANDOR(SISCR, 0x37, 0x0c, cr37);
27799d6c 2368 SiS_SetRegOR(SISCR, 0x32, 0x08);
544393fe 2369
c30660ea 2370 ivideo->SiS_Pr.PanelSelfDetected = true;
544393fe
TW
2371}
2372
48c68c4f 2373static int SISDoSense(struct sis_video_info *ivideo, u16 type, u16 test)
1da177e4
LT
2374{
2375 int temp, mytest, result, i, j;
2376
2377 for(j = 0; j < 10; j++) {
2378 result = 0;
2379 for(i = 0; i < 3; i++) {
2380 mytest = test;
44b751bb 2381 SiS_SetReg(SISPART4, 0x11, (type & 0x00ff));
1da177e4 2382 temp = (type >> 8) | (mytest & 0x00ff);
ad78adb4 2383 SiS_SetRegANDOR(SISPART4, 0x10, 0xe0, temp);
1da177e4
LT
2384 SiS_DDC2Delay(&ivideo->SiS_Pr, 0x1500);
2385 mytest >>= 8;
2386 mytest &= 0x7f;
e57d4136 2387 temp = SiS_GetReg(SISPART4, 0x03);
1da177e4
LT
2388 temp ^= 0x0e;
2389 temp &= mytest;
2390 if(temp == mytest) result++;
2391#if 1
44b751bb 2392 SiS_SetReg(SISPART4, 0x11, 0x00);
667a8b41 2393 SiS_SetRegAND(SISPART4, 0x10, 0xe0);
1da177e4
LT
2394 SiS_DDC2Delay(&ivideo->SiS_Pr, 0x1000);
2395#endif
2396 }
2397 if((result == 0) || (result >= 2)) break;
2398 }
544393fe 2399 return result;
1da177e4
LT
2400}
2401
48c68c4f 2402static void SiS_Sense30x(struct sis_video_info *ivideo)
1da177e4
LT
2403{
2404 u8 backupP4_0d,backupP2_00,backupP2_4d,backupSR_1e,biosflag=0;
2405 u16 svhs=0, svhs_c=0;
2406 u16 cvbs=0, cvbs_c=0;
2407 u16 vga2=0, vga2_c=0;
2408 int myflag, result;
2409 char stdstr[] = "sisfb: Detected";
2410 char tvstr[] = "TV connected to";
2411
544393fe 2412 if(ivideo->vbflags2 & VB2_301) {
1da177e4 2413 svhs = 0x00b9; cvbs = 0x00b3; vga2 = 0x00d1;
e57d4136 2414 myflag = SiS_GetReg(SISPART4, 0x01);
1da177e4
LT
2415 if(myflag & 0x04) {
2416 svhs = 0x00dd; cvbs = 0x00ee; vga2 = 0x00fd;
2417 }
544393fe 2418 } else if(ivideo->vbflags2 & (VB2_301B | VB2_302B)) {
1da177e4 2419 svhs = 0x016b; cvbs = 0x0174; vga2 = 0x0190;
544393fe 2420 } else if(ivideo->vbflags2 & (VB2_301LV | VB2_302LV)) {
1da177e4 2421 svhs = 0x0200; cvbs = 0x0100;
544393fe 2422 } else if(ivideo->vbflags2 & (VB2_301C | VB2_302ELV | VB2_307T | VB2_307LV)) {
1da177e4 2423 svhs = 0x016b; cvbs = 0x0110; vga2 = 0x0190;
544393fe
TW
2424 } else
2425 return;
1da177e4
LT
2426
2427 vga2_c = 0x0e08; svhs_c = 0x0404; cvbs_c = 0x0804;
544393fe 2428 if(ivideo->vbflags & (VB2_301LV|VB2_302LV|VB2_302ELV|VB2_307LV)) {
1da177e4
LT
2429 svhs_c = 0x0408; cvbs_c = 0x0808;
2430 }
544393fe 2431
1da177e4 2432 biosflag = 2;
544393fe
TW
2433 if(ivideo->haveXGIROM) {
2434 biosflag = ivideo->bios_abase[0x58] & 0x03;
2435 } else if(ivideo->newrom) {
2436 if(ivideo->bios_abase[0x5d] & 0x04) biosflag |= 0x01;
2437 } else if(ivideo->sisvga_engine == SIS_300_VGA) {
2438 if(ivideo->bios_abase) {
2439 biosflag = ivideo->bios_abase[0xfe] & 0x03;
2440 }
2441 }
1da177e4
LT
2442
2443 if(ivideo->chip == SIS_300) {
e57d4136 2444 myflag = SiS_GetReg(SISSR, 0x3b);
1da177e4
LT
2445 if(!(myflag & 0x01)) vga2 = vga2_c = 0;
2446 }
2447
544393fe
TW
2448 if(!(ivideo->vbflags2 & VB2_SISVGA2BRIDGE)) {
2449 vga2 = vga2_c = 0;
2450 }
2451
e57d4136 2452 backupSR_1e = SiS_GetReg(SISSR, 0x1e);
27799d6c 2453 SiS_SetRegOR(SISSR, 0x1e, 0x20);
1da177e4 2454
e57d4136 2455 backupP4_0d = SiS_GetReg(SISPART4, 0x0d);
544393fe 2456 if(ivideo->vbflags2 & VB2_30xC) {
ad78adb4 2457 SiS_SetRegANDOR(SISPART4, 0x0d, ~0x07, 0x01);
1da177e4 2458 } else {
27799d6c 2459 SiS_SetRegOR(SISPART4, 0x0d, 0x04);
1da177e4
LT
2460 }
2461 SiS_DDC2Delay(&ivideo->SiS_Pr, 0x2000);
2462
e57d4136 2463 backupP2_00 = SiS_GetReg(SISPART2, 0x00);
44b751bb 2464 SiS_SetReg(SISPART2, 0x00, ((backupP2_00 | 0x1c) & 0xfc));
1da177e4 2465
e57d4136 2466 backupP2_4d = SiS_GetReg(SISPART2, 0x4d);
544393fe 2467 if(ivideo->vbflags2 & VB2_SISYPBPRBRIDGE) {
44b751bb 2468 SiS_SetReg(SISPART2, 0x4d, (backupP2_4d & ~0x10));
1da177e4
LT
2469 }
2470
544393fe 2471 if(!(ivideo->vbflags2 & VB2_30xCLV)) {
1da177e4
LT
2472 SISDoSense(ivideo, 0, 0);
2473 }
2474
667a8b41 2475 SiS_SetRegAND(SISCR, 0x32, ~0x14);
1da177e4
LT
2476
2477 if(vga2_c || vga2) {
2478 if(SISDoSense(ivideo, vga2, vga2_c)) {
2479 if(biosflag & 0x01) {
2480 printk(KERN_INFO "%s %s SCART output\n", stdstr, tvstr);
27799d6c 2481 SiS_SetRegOR(SISCR, 0x32, 0x04);
1da177e4
LT
2482 } else {
2483 printk(KERN_INFO "%s secondary VGA connection\n", stdstr);
27799d6c 2484 SiS_SetRegOR(SISCR, 0x32, 0x10);
1da177e4
LT
2485 }
2486 }
2487 }
2488
667a8b41 2489 SiS_SetRegAND(SISCR, 0x32, 0x3f);
1da177e4 2490
544393fe 2491 if(ivideo->vbflags2 & VB2_30xCLV) {
27799d6c 2492 SiS_SetRegOR(SISPART4, 0x0d, 0x04);
1da177e4
LT
2493 }
2494
544393fe 2495 if((ivideo->sisvga_engine == SIS_315_VGA) && (ivideo->vbflags2 & VB2_SISYPBPRBRIDGE)) {
44b751bb 2496 SiS_SetReg(SISPART2, 0x4d, (backupP2_4d | 0x10));
1da177e4
LT
2497 SiS_DDC2Delay(&ivideo->SiS_Pr, 0x2000);
2498 if((result = SISDoSense(ivideo, svhs, 0x0604))) {
2499 if((result = SISDoSense(ivideo, cvbs, 0x0804))) {
2500 printk(KERN_INFO "%s %s YPbPr component output\n", stdstr, tvstr);
27799d6c 2501 SiS_SetRegOR(SISCR, 0x32, 0x80);
1da177e4
LT
2502 }
2503 }
44b751bb 2504 SiS_SetReg(SISPART2, 0x4d, backupP2_4d);
1da177e4
LT
2505 }
2506
667a8b41 2507 SiS_SetRegAND(SISCR, 0x32, ~0x03);
1da177e4
LT
2508
2509 if(!(ivideo->vbflags & TV_YPBPR)) {
2510 if((result = SISDoSense(ivideo, svhs, svhs_c))) {
2511 printk(KERN_INFO "%s %s SVIDEO output\n", stdstr, tvstr);
27799d6c 2512 SiS_SetRegOR(SISCR, 0x32, 0x02);
1da177e4
LT
2513 }
2514 if((biosflag & 0x02) || (!result)) {
2515 if(SISDoSense(ivideo, cvbs, cvbs_c)) {
2516 printk(KERN_INFO "%s %s COMPOSITE output\n", stdstr, tvstr);
27799d6c 2517 SiS_SetRegOR(SISCR, 0x32, 0x01);
1da177e4
LT
2518 }
2519 }
2520 }
2521
2522 SISDoSense(ivideo, 0, 0);
2523
44b751bb
AK
2524 SiS_SetReg(SISPART2, 0x00, backupP2_00);
2525 SiS_SetReg(SISPART4, 0x0d, backupP4_0d);
2526 SiS_SetReg(SISSR, 0x1e, backupSR_1e);
1da177e4 2527
544393fe 2528 if(ivideo->vbflags2 & VB2_30xCLV) {
e57d4136 2529 biosflag = SiS_GetReg(SISPART2, 0x00);
1da177e4
LT
2530 if(biosflag & 0x20) {
2531 for(myflag = 2; myflag > 0; myflag--) {
2532 biosflag ^= 0x20;
44b751bb 2533 SiS_SetReg(SISPART2, 0x00, biosflag);
1da177e4
LT
2534 }
2535 }
2536 }
2537
44b751bb 2538 SiS_SetReg(SISPART2, 0x00, backupP2_00);
1da177e4
LT
2539}
2540
2541/* Determine and detect attached TV's on Chrontel */
48c68c4f 2542static void SiS_SenseCh(struct sis_video_info *ivideo)
1da177e4
LT
2543{
2544#if defined(CONFIG_FB_SIS_300) || defined(CONFIG_FB_SIS_315)
2545 u8 temp1, temp2;
2546 char stdstr[] = "sisfb: Chrontel: Detected TV connected to";
2547#endif
2548#ifdef CONFIG_FB_SIS_300
2549 unsigned char test[3];
2550 int i;
2551#endif
2552
2553 if(ivideo->chip < SIS_315H) {
2554
2555#ifdef CONFIG_FB_SIS_300
2556 ivideo->SiS_Pr.SiS_IF_DEF_CH70xx = 1; /* Chrontel 700x */
2557 SiS_SetChrontelGPIO(&ivideo->SiS_Pr, 0x9c); /* Set general purpose IO for Chrontel communication */
2558 SiS_DDC2Delay(&ivideo->SiS_Pr, 1000);
2559 temp1 = SiS_GetCH700x(&ivideo->SiS_Pr, 0x25);
2560 /* See Chrontel TB31 for explanation */
2561 temp2 = SiS_GetCH700x(&ivideo->SiS_Pr, 0x0e);
2562 if(((temp2 & 0x07) == 0x01) || (temp2 & 0x04)) {
544393fe 2563 SiS_SetCH700x(&ivideo->SiS_Pr, 0x0e, 0x0b);
1da177e4
LT
2564 SiS_DDC2Delay(&ivideo->SiS_Pr, 300);
2565 }
2566 temp2 = SiS_GetCH700x(&ivideo->SiS_Pr, 0x25);
2567 if(temp2 != temp1) temp1 = temp2;
2568
2569 if((temp1 >= 0x22) && (temp1 <= 0x50)) {
2570 /* Read power status */
2571 temp1 = SiS_GetCH700x(&ivideo->SiS_Pr, 0x0e);
2572 if((temp1 & 0x03) != 0x03) {
544393fe
TW
2573 /* Power all outputs */
2574 SiS_SetCH700x(&ivideo->SiS_Pr, 0x0e,0x0b);
1da177e4
LT
2575 SiS_DDC2Delay(&ivideo->SiS_Pr, 300);
2576 }
2577 /* Sense connected TV devices */
2578 for(i = 0; i < 3; i++) {
544393fe 2579 SiS_SetCH700x(&ivideo->SiS_Pr, 0x10, 0x01);
1da177e4 2580 SiS_DDC2Delay(&ivideo->SiS_Pr, 0x96);
544393fe 2581 SiS_SetCH700x(&ivideo->SiS_Pr, 0x10, 0x00);
1da177e4
LT
2582 SiS_DDC2Delay(&ivideo->SiS_Pr, 0x96);
2583 temp1 = SiS_GetCH700x(&ivideo->SiS_Pr, 0x10);
2584 if(!(temp1 & 0x08)) test[i] = 0x02;
2585 else if(!(temp1 & 0x02)) test[i] = 0x01;
2586 else test[i] = 0;
2587 SiS_DDC2Delay(&ivideo->SiS_Pr, 0x96);
2588 }
2589
2590 if(test[0] == test[1]) temp1 = test[0];
2591 else if(test[0] == test[2]) temp1 = test[0];
2592 else if(test[1] == test[2]) temp1 = test[1];
2593 else {
544393fe 2594 printk(KERN_INFO
1da177e4
LT
2595 "sisfb: TV detection unreliable - test results varied\n");
2596 temp1 = test[2];
2597 }
2598 if(temp1 == 0x02) {
2599 printk(KERN_INFO "%s SVIDEO output\n", stdstr);
2600 ivideo->vbflags |= TV_SVIDEO;
27799d6c 2601 SiS_SetRegOR(SISCR, 0x32, 0x02);
667a8b41 2602 SiS_SetRegAND(SISCR, 0x32, ~0x05);
1da177e4
LT
2603 } else if (temp1 == 0x01) {
2604 printk(KERN_INFO "%s CVBS output\n", stdstr);
2605 ivideo->vbflags |= TV_AVIDEO;
27799d6c 2606 SiS_SetRegOR(SISCR, 0x32, 0x01);
667a8b41 2607 SiS_SetRegAND(SISCR, 0x32, ~0x06);
1da177e4 2608 } else {
544393fe 2609 SiS_SetCH70xxANDOR(&ivideo->SiS_Pr, 0x0e, 0x01, 0xF8);
667a8b41 2610 SiS_SetRegAND(SISCR, 0x32, ~0x07);
1da177e4
LT
2611 }
2612 } else if(temp1 == 0) {
544393fe 2613 SiS_SetCH70xxANDOR(&ivideo->SiS_Pr, 0x0e, 0x01, 0xF8);
667a8b41 2614 SiS_SetRegAND(SISCR, 0x32, ~0x07);
1da177e4
LT
2615 }
2616 /* Set general purpose IO for Chrontel communication */
2617 SiS_SetChrontelGPIO(&ivideo->SiS_Pr, 0x00);
2618#endif
2619
2620 } else {
2621
2622#ifdef CONFIG_FB_SIS_315
2623 ivideo->SiS_Pr.SiS_IF_DEF_CH70xx = 2; /* Chrontel 7019 */
544393fe
TW
2624 temp1 = SiS_GetCH701x(&ivideo->SiS_Pr, 0x49);
2625 SiS_SetCH701x(&ivideo->SiS_Pr, 0x49, 0x20);
1da177e4
LT
2626 SiS_DDC2Delay(&ivideo->SiS_Pr, 0x96);
2627 temp2 = SiS_GetCH701x(&ivideo->SiS_Pr, 0x20);
2628 temp2 |= 0x01;
544393fe 2629 SiS_SetCH701x(&ivideo->SiS_Pr, 0x20, temp2);
1da177e4
LT
2630 SiS_DDC2Delay(&ivideo->SiS_Pr, 0x96);
2631 temp2 ^= 0x01;
544393fe 2632 SiS_SetCH701x(&ivideo->SiS_Pr, 0x20, temp2);
1da177e4
LT
2633 SiS_DDC2Delay(&ivideo->SiS_Pr, 0x96);
2634 temp2 = SiS_GetCH701x(&ivideo->SiS_Pr, 0x20);
544393fe
TW
2635 SiS_SetCH701x(&ivideo->SiS_Pr, 0x49, temp1);
2636 temp1 = 0;
1da177e4
LT
2637 if(temp2 & 0x02) temp1 |= 0x01;
2638 if(temp2 & 0x10) temp1 |= 0x01;
2639 if(temp2 & 0x04) temp1 |= 0x02;
2640 if( (temp1 & 0x01) && (temp1 & 0x02) ) temp1 = 0x04;
2641 switch(temp1) {
2642 case 0x01:
2643 printk(KERN_INFO "%s CVBS output\n", stdstr);
2644 ivideo->vbflags |= TV_AVIDEO;
27799d6c 2645 SiS_SetRegOR(SISCR, 0x32, 0x01);
667a8b41 2646 SiS_SetRegAND(SISCR, 0x32, ~0x06);
544393fe 2647 break;
1da177e4
LT
2648 case 0x02:
2649 printk(KERN_INFO "%s SVIDEO output\n", stdstr);
2650 ivideo->vbflags |= TV_SVIDEO;
27799d6c 2651 SiS_SetRegOR(SISCR, 0x32, 0x02);
667a8b41 2652 SiS_SetRegAND(SISCR, 0x32, ~0x05);
544393fe 2653 break;
1da177e4
LT
2654 case 0x04:
2655 printk(KERN_INFO "%s SCART output\n", stdstr);
27799d6c 2656 SiS_SetRegOR(SISCR, 0x32, 0x04);
667a8b41 2657 SiS_SetRegAND(SISCR, 0x32, ~0x03);
544393fe 2658 break;
1da177e4 2659 default:
667a8b41 2660 SiS_SetRegAND(SISCR, 0x32, ~0x07);
1da177e4
LT
2661 }
2662#endif
2663 }
2664}
2665
48c68c4f 2666static void sisfb_get_VB_type(struct sis_video_info *ivideo)
1da177e4 2667{
544393fe
TW
2668 char stdstr[] = "sisfb: Detected";
2669 char bridgestr[] = "video bridge";
2670 u8 vb_chipid;
2671 u8 reg;
1da177e4 2672
544393fe
TW
2673 /* No CRT2 on XGI Z7 */
2674 if(ivideo->chip == XGI_20)
2675 return;
1da177e4 2676
e57d4136 2677 vb_chipid = SiS_GetReg(SISPART4, 0x00);
544393fe
TW
2678 switch(vb_chipid) {
2679 case 0x01:
e57d4136 2680 reg = SiS_GetReg(SISPART4, 0x01);
544393fe
TW
2681 if(reg < 0xb0) {
2682 ivideo->vbflags |= VB_301; /* Deprecated */
2683 ivideo->vbflags2 |= VB2_301;
2684 printk(KERN_INFO "%s SiS301 %s\n", stdstr, bridgestr);
2685 } else if(reg < 0xc0) {
2686 ivideo->vbflags |= VB_301B; /* Deprecated */
2687 ivideo->vbflags2 |= VB2_301B;
e57d4136 2688 reg = SiS_GetReg(SISPART4, 0x23);
544393fe
TW
2689 if(!(reg & 0x02)) {
2690 ivideo->vbflags |= VB_30xBDH; /* Deprecated */
2691 ivideo->vbflags2 |= VB2_30xBDH;
2692 printk(KERN_INFO "%s SiS301B-DH %s\n", stdstr, bridgestr);
2693 } else {
2694 printk(KERN_INFO "%s SiS301B %s\n", stdstr, bridgestr);
2695 }
2696 } else if(reg < 0xd0) {
2697 ivideo->vbflags |= VB_301C; /* Deprecated */
2698 ivideo->vbflags2 |= VB2_301C;
2699 printk(KERN_INFO "%s SiS301C %s\n", stdstr, bridgestr);
2700 } else if(reg < 0xe0) {
2701 ivideo->vbflags |= VB_301LV; /* Deprecated */
2702 ivideo->vbflags2 |= VB2_301LV;
2703 printk(KERN_INFO "%s SiS301LV %s\n", stdstr, bridgestr);
2704 } else if(reg <= 0xe1) {
e57d4136 2705 reg = SiS_GetReg(SISPART4, 0x39);
544393fe
TW
2706 if(reg == 0xff) {
2707 ivideo->vbflags |= VB_302LV; /* Deprecated */
2708 ivideo->vbflags2 |= VB2_302LV;
2709 printk(KERN_INFO "%s SiS302LV %s\n", stdstr, bridgestr);
2710 } else {
2711 ivideo->vbflags |= VB_301C; /* Deprecated */
2712 ivideo->vbflags2 |= VB2_301C;
2713 printk(KERN_INFO "%s SiS301C(P4) %s\n", stdstr, bridgestr);
2714#if 0
2715 ivideo->vbflags |= VB_302ELV; /* Deprecated */
2716 ivideo->vbflags2 |= VB2_302ELV;
2717 printk(KERN_INFO "%s SiS302ELV %s\n", stdstr, bridgestr);
2718#endif
2719 }
2720 }
2721 break;
2722 case 0x02:
2723 ivideo->vbflags |= VB_302B; /* Deprecated */
2724 ivideo->vbflags2 |= VB2_302B;
2725 printk(KERN_INFO "%s SiS302B %s\n", stdstr, bridgestr);
2726 break;
1da177e4
LT
2727 }
2728
544393fe 2729 if((!(ivideo->vbflags2 & VB2_VIDEOBRIDGE)) && (ivideo->chip != SIS_300)) {
e57d4136 2730 reg = SiS_GetReg(SISCR, 0x37);
544393fe
TW
2731 reg &= SIS_EXTERNAL_CHIP_MASK;
2732 reg >>= 1;
2733 if(ivideo->sisvga_engine == SIS_300_VGA) {
2734#ifdef CONFIG_FB_SIS_300
2735 switch(reg) {
2736 case SIS_EXTERNAL_CHIP_LVDS:
2737 ivideo->vbflags |= VB_LVDS; /* Deprecated */
2738 ivideo->vbflags2 |= VB2_LVDS;
2739 break;
2740 case SIS_EXTERNAL_CHIP_TRUMPION:
2741 ivideo->vbflags |= (VB_LVDS | VB_TRUMPION); /* Deprecated */
2742 ivideo->vbflags2 |= (VB2_LVDS | VB2_TRUMPION);
2743 break;
2744 case SIS_EXTERNAL_CHIP_CHRONTEL:
2745 ivideo->vbflags |= VB_CHRONTEL; /* Deprecated */
2746 ivideo->vbflags2 |= VB2_CHRONTEL;
2747 break;
2748 case SIS_EXTERNAL_CHIP_LVDS_CHRONTEL:
2749 ivideo->vbflags |= (VB_LVDS | VB_CHRONTEL); /* Deprecated */
2750 ivideo->vbflags2 |= (VB2_LVDS | VB2_CHRONTEL);
2751 break;
2752 }
2753 if(ivideo->vbflags2 & VB2_CHRONTEL) ivideo->chronteltype = 1;
2754#endif
2755 } else if(ivideo->chip < SIS_661) {
2756#ifdef CONFIG_FB_SIS_315
2757 switch (reg) {
2758 case SIS310_EXTERNAL_CHIP_LVDS:
2759 ivideo->vbflags |= VB_LVDS; /* Deprecated */
2760 ivideo->vbflags2 |= VB2_LVDS;
2761 break;
2762 case SIS310_EXTERNAL_CHIP_LVDS_CHRONTEL:
2763 ivideo->vbflags |= (VB_LVDS | VB_CHRONTEL); /* Deprecated */
2764 ivideo->vbflags2 |= (VB2_LVDS | VB2_CHRONTEL);
2765 break;
2766 }
2767 if(ivideo->vbflags2 & VB2_CHRONTEL) ivideo->chronteltype = 2;
2768#endif
2769 } else if(ivideo->chip >= SIS_661) {
2770#ifdef CONFIG_FB_SIS_315
e57d4136 2771 reg = SiS_GetReg(SISCR, 0x38);
544393fe
TW
2772 reg >>= 5;
2773 switch(reg) {
2774 case 0x02:
2775 ivideo->vbflags |= VB_LVDS; /* Deprecated */
2776 ivideo->vbflags2 |= VB2_LVDS;
2777 break;
2778 case 0x03:
2779 ivideo->vbflags |= (VB_LVDS | VB_CHRONTEL); /* Deprecated */
2780 ivideo->vbflags2 |= (VB2_LVDS | VB2_CHRONTEL);
2781 break;
2782 case 0x04:
2783 ivideo->vbflags |= (VB_LVDS | VB_CONEXANT); /* Deprecated */
2784 ivideo->vbflags2 |= (VB2_LVDS | VB2_CONEXANT);
2785 break;
2786 }
2787 if(ivideo->vbflags2 & VB2_CHRONTEL) ivideo->chronteltype = 2;
2788#endif
2789 }
2790 if(ivideo->vbflags2 & VB2_LVDS) {
2791 printk(KERN_INFO "%s LVDS transmitter\n", stdstr);
2792 }
2793 if((ivideo->sisvga_engine == SIS_300_VGA) && (ivideo->vbflags2 & VB2_TRUMPION)) {
2794 printk(KERN_INFO "%s Trumpion Zurac LCD scaler\n", stdstr);
2795 }
2796 if(ivideo->vbflags2 & VB2_CHRONTEL) {
2797 printk(KERN_INFO "%s Chrontel TV encoder\n", stdstr);
2798 }
2799 if((ivideo->chip >= SIS_661) && (ivideo->vbflags2 & VB2_CONEXANT)) {
2800 printk(KERN_INFO "%s Conexant external device\n", stdstr);
2801 }
2802 }
2803
2804 if(ivideo->vbflags2 & VB2_SISBRIDGE) {
2805 SiS_SenseLCD(ivideo);
2806 SiS_Sense30x(ivideo);
2807 } else if(ivideo->vbflags2 & VB2_CHRONTEL) {
2808 SiS_SenseCh(ivideo);
2809 }
2810}
2811
2812/* ---------- Engine initialization routines ------------ */
2813
2814static void
2815sisfb_engine_init(struct sis_video_info *ivideo)
1da177e4 2816{
1da177e4 2817
544393fe 2818 /* Initialize command queue (we use MMIO only) */
1da177e4 2819
544393fe 2820 /* BEFORE THIS IS CALLED, THE ENGINES *MUST* BE SYNC'ED */
1da177e4 2821
544393fe
TW
2822 ivideo->caps &= ~(TURBO_QUEUE_CAP |
2823 MMIO_CMD_QUEUE_CAP |
2824 VM_CMD_QUEUE_CAP |
2825 AGP_CMD_QUEUE_CAP);
2826
2827#ifdef CONFIG_FB_SIS_300
2828 if(ivideo->sisvga_engine == SIS_300_VGA) {
2829 u32 tqueue_pos;
2830 u8 tq_state;
2831
2832 tqueue_pos = (ivideo->video_size - ivideo->cmdQueueSize) / (64 * 1024);
2833
e57d4136 2834 tq_state = SiS_GetReg(SISSR, IND_SIS_TURBOQUEUE_SET);
544393fe
TW
2835 tq_state |= 0xf0;
2836 tq_state &= 0xfc;
2837 tq_state |= (u8)(tqueue_pos >> 8);
44b751bb 2838 SiS_SetReg(SISSR, IND_SIS_TURBOQUEUE_SET, tq_state);
544393fe 2839
44b751bb 2840 SiS_SetReg(SISSR, IND_SIS_TURBOQUEUE_ADR, (u8)(tqueue_pos & 0xff));
544393fe
TW
2841
2842 ivideo->caps |= TURBO_QUEUE_CAP;
2843 }
2844#endif
1da177e4
LT
2845
2846#ifdef CONFIG_FB_SIS_315
544393fe
TW
2847 if(ivideo->sisvga_engine == SIS_315_VGA) {
2848 u32 tempq = 0, templ;
2849 u8 temp;
2850
2851 if(ivideo->chip == XGI_20) {
2852 switch(ivideo->cmdQueueSize) {
2853 case (64 * 1024):
2854 temp = SIS_CMD_QUEUE_SIZE_Z7_64k;
2855 break;
2856 case (128 * 1024):
2857 default:
2858 temp = SIS_CMD_QUEUE_SIZE_Z7_128k;
2859 }
2860 } else {
2861 switch(ivideo->cmdQueueSize) {
2862 case (4 * 1024 * 1024):
2863 temp = SIS_CMD_QUEUE_SIZE_4M;
2864 break;
2865 case (2 * 1024 * 1024):
2866 temp = SIS_CMD_QUEUE_SIZE_2M;
2867 break;
2868 case (1 * 1024 * 1024):
2869 temp = SIS_CMD_QUEUE_SIZE_1M;
2870 break;
2871 default:
2872 case (512 * 1024):
2873 temp = SIS_CMD_QUEUE_SIZE_512k;
2874 }
2875 }
2876
44b751bb
AK
2877 SiS_SetReg(SISSR, IND_SIS_CMDQUEUE_THRESHOLD, COMMAND_QUEUE_THRESHOLD);
2878 SiS_SetReg(SISSR, IND_SIS_CMDQUEUE_SET, SIS_CMD_QUEUE_RESET);
544393fe
TW
2879
2880 if((ivideo->chip >= XGI_40) && ivideo->modechanged) {
2881 /* Must disable dual pipe on XGI_40. Can't do
2882 * this in MMIO mode, because it requires
2883 * setting/clearing a bit in the MMIO fire trigger
2884 * register.
2885 */
2886 if(!((templ = MMIO_IN32(ivideo->mmio_vbase, 0x8240)) & (1 << 10))) {
2887
2888 MMIO_OUT32(ivideo->mmio_vbase, Q_WRITE_PTR, 0);
2889
44b751bb 2890 SiS_SetReg(SISSR, IND_SIS_CMDQUEUE_SET, (temp | SIS_VRAM_CMDQUEUE_ENABLE));
544393fe
TW
2891
2892 tempq = MMIO_IN32(ivideo->mmio_vbase, Q_READ_PTR);
2893 MMIO_OUT32(ivideo->mmio_vbase, Q_WRITE_PTR, tempq);
1da177e4 2894
544393fe
TW
2895 tempq = (u32)(ivideo->video_size - ivideo->cmdQueueSize);
2896 MMIO_OUT32(ivideo->mmio_vbase, Q_BASE_ADDR, tempq);
1da177e4 2897
544393fe
TW
2898 writel(0x16800000 + 0x8240, ivideo->video_vbase + tempq);
2899 writel(templ | (1 << 10), ivideo->video_vbase + tempq + 4);
2900 writel(0x168F0000, ivideo->video_vbase + tempq + 8);
2901 writel(0x168F0000, ivideo->video_vbase + tempq + 12);
2902
2903 MMIO_OUT32(ivideo->mmio_vbase, Q_WRITE_PTR, (tempq + 16));
2904
2905 sisfb_syncaccel(ivideo);
2906
44b751bb 2907 SiS_SetReg(SISSR, IND_SIS_CMDQUEUE_SET, SIS_CMD_QUEUE_RESET);
544393fe
TW
2908
2909 }
2910 }
2911
2912 tempq = MMIO_IN32(ivideo->mmio_vbase, MMIO_QUEUE_READPORT);
2913 MMIO_OUT32(ivideo->mmio_vbase, MMIO_QUEUE_WRITEPORT, tempq);
2914
2915 temp |= (SIS_MMIO_CMD_ENABLE | SIS_CMD_AUTO_CORR);
44b751bb 2916 SiS_SetReg(SISSR, IND_SIS_CMDQUEUE_SET, temp);
544393fe
TW
2917
2918 tempq = (u32)(ivideo->video_size - ivideo->cmdQueueSize);
2919 MMIO_OUT32(ivideo->mmio_vbase, MMIO_QUEUE_PHYBASE, tempq);
2920
2921 ivideo->caps |= MMIO_CMD_QUEUE_CAP;
2922 }
2923#endif
2924
2925 ivideo->engineok = 1;
2926}
2927
48c68c4f 2928static void sisfb_detect_lcd_type(struct sis_video_info *ivideo)
544393fe
TW
2929{
2930 u8 reg;
2931 int i;
1da177e4 2932
e57d4136 2933 reg = SiS_GetReg(SISCR, 0x36);
544393fe
TW
2934 reg &= 0x0f;
2935 if(ivideo->sisvga_engine == SIS_300_VGA) {
2936 ivideo->CRT2LCDType = sis300paneltype[reg];
2937 } else if(ivideo->chip >= SIS_661) {
2938 ivideo->CRT2LCDType = sis661paneltype[reg];
2939 } else {
2940 ivideo->CRT2LCDType = sis310paneltype[reg];
2941 if((ivideo->chip == SIS_550) && (sisfb_fstn)) {
2942 if((ivideo->CRT2LCDType != LCD_320x240_2) &&
2943 (ivideo->CRT2LCDType != LCD_320x240_3)) {
2944 ivideo->CRT2LCDType = LCD_320x240;
2945 }
2946 }
2947 }
1da177e4 2948
544393fe
TW
2949 if(ivideo->CRT2LCDType == LCD_UNKNOWN) {
2950 /* For broken BIOSes: Assume 1024x768, RGB18 */
2951 ivideo->CRT2LCDType = LCD_1024x768;
ad78adb4
AK
2952 SiS_SetRegANDOR(SISCR, 0x36, 0xf0, 0x02);
2953 SiS_SetRegANDOR(SISCR, 0x37, 0xee, 0x01);
544393fe
TW
2954 printk(KERN_DEBUG "sisfb: Invalid panel ID (%02x), assuming 1024x768, RGB18\n", reg);
2955 }
1da177e4 2956
544393fe
TW
2957 for(i = 0; i < SIS_LCD_NUMBER; i++) {
2958 if(ivideo->CRT2LCDType == sis_lcd_data[i].lcdtype) {
2959 ivideo->lcdxres = sis_lcd_data[i].xres;
2960 ivideo->lcdyres = sis_lcd_data[i].yres;
2961 ivideo->lcddefmodeidx = sis_lcd_data[i].default_mode_idx;
2962 break;
2963 }
2964 }
1da177e4 2965
544393fe
TW
2966#ifdef CONFIG_FB_SIS_300
2967 if(ivideo->SiS_Pr.SiS_CustomT == CUT_BARCO1366) {
2968 ivideo->lcdxres = 1360; ivideo->lcdyres = 1024;
2969 ivideo->lcddefmodeidx = DEFAULT_MODE_1360;
2970 } else if(ivideo->SiS_Pr.SiS_CustomT == CUT_PANEL848) {
2971 ivideo->lcdxres = 848; ivideo->lcdyres = 480;
2972 ivideo->lcddefmodeidx = DEFAULT_MODE_848;
2973 } else if(ivideo->SiS_Pr.SiS_CustomT == CUT_PANEL856) {
2974 ivideo->lcdxres = 856; ivideo->lcdyres = 480;
2975 ivideo->lcddefmodeidx = DEFAULT_MODE_856;
2976 }
1da177e4
LT
2977#endif
2978
544393fe
TW
2979 printk(KERN_DEBUG "sisfb: Detected %dx%d flat panel\n",
2980 ivideo->lcdxres, ivideo->lcdyres);
2981}
2982
48c68c4f 2983static void sisfb_save_pdc_emi(struct sis_video_info *ivideo)
544393fe 2984{
1da177e4 2985#ifdef CONFIG_FB_SIS_300
544393fe
TW
2986 /* Save the current PanelDelayCompensation if the LCD is currently used */
2987 if(ivideo->sisvga_engine == SIS_300_VGA) {
2988 if(ivideo->vbflags2 & (VB2_LVDS | VB2_30xBDH)) {
2989 int tmp;
e57d4136 2990 tmp = SiS_GetReg(SISCR, 0x30);
544393fe
TW
2991 if(tmp & 0x20) {
2992 /* Currently on LCD? If yes, read current pdc */
e57d4136 2993 ivideo->detectedpdc = SiS_GetReg(SISPART1, 0x13);
544393fe
TW
2994 ivideo->detectedpdc &= 0x3c;
2995 if(ivideo->SiS_Pr.PDC == -1) {
2996 /* Let option override detection */
2997 ivideo->SiS_Pr.PDC = ivideo->detectedpdc;
2998 }
2999 printk(KERN_INFO "sisfb: Detected LCD PDC 0x%02x\n",
3000 ivideo->detectedpdc);
3001 }
3002 if((ivideo->SiS_Pr.PDC != -1) &&
3003 (ivideo->SiS_Pr.PDC != ivideo->detectedpdc)) {
3004 printk(KERN_INFO "sisfb: Using LCD PDC 0x%02x\n",
3005 ivideo->SiS_Pr.PDC);
3006 }
3007 }
3008 }
3009#endif
3010
3011#ifdef CONFIG_FB_SIS_315
3012 if(ivideo->sisvga_engine == SIS_315_VGA) {
1da177e4 3013
544393fe
TW
3014 /* Try to find about LCDA */
3015 if(ivideo->vbflags2 & VB2_SISLCDABRIDGE) {
3016 int tmp;
e57d4136 3017 tmp = SiS_GetReg(SISPART1, 0x13);
544393fe 3018 if(tmp & 0x04) {
c30660ea 3019 ivideo->SiS_Pr.SiS_UseLCDA = true;
544393fe
TW
3020 ivideo->detectedlcda = 0x03;
3021 }
3022 }
1da177e4 3023
544393fe
TW
3024 /* Save PDC */
3025 if(ivideo->vbflags2 & VB2_SISLVDSBRIDGE) {
3026 int tmp;
e57d4136 3027 tmp = SiS_GetReg(SISCR, 0x30);
544393fe
TW
3028 if((tmp & 0x20) || (ivideo->detectedlcda != 0xff)) {
3029 /* Currently on LCD? If yes, read current pdc */
3030 u8 pdc;
e57d4136 3031 pdc = SiS_GetReg(SISPART1, 0x2D);
544393fe
TW
3032 ivideo->detectedpdc = (pdc & 0x0f) << 1;
3033 ivideo->detectedpdca = (pdc & 0xf0) >> 3;
e57d4136 3034 pdc = SiS_GetReg(SISPART1, 0x35);
544393fe 3035 ivideo->detectedpdc |= ((pdc >> 7) & 0x01);
e57d4136 3036 pdc = SiS_GetReg(SISPART1, 0x20);
544393fe
TW
3037 ivideo->detectedpdca |= ((pdc >> 6) & 0x01);
3038 if(ivideo->newrom) {
3039 /* New ROM invalidates other PDC resp. */
3040 if(ivideo->detectedlcda != 0xff) {
3041 ivideo->detectedpdc = 0xff;
3042 } else {
3043 ivideo->detectedpdca = 0xff;
3044 }
3045 }
3046 if(ivideo->SiS_Pr.PDC == -1) {
3047 if(ivideo->detectedpdc != 0xff) {
3048 ivideo->SiS_Pr.PDC = ivideo->detectedpdc;
3049 }
3050 }
3051 if(ivideo->SiS_Pr.PDCA == -1) {
3052 if(ivideo->detectedpdca != 0xff) {
3053 ivideo->SiS_Pr.PDCA = ivideo->detectedpdca;
3054 }
3055 }
3056 if(ivideo->detectedpdc != 0xff) {
3057 printk(KERN_INFO
3058 "sisfb: Detected LCD PDC 0x%02x (for LCD=CRT2)\n",
3059 ivideo->detectedpdc);
3060 }
3061 if(ivideo->detectedpdca != 0xff) {
3062 printk(KERN_INFO
3063 "sisfb: Detected LCD PDC1 0x%02x (for LCD=CRT1)\n",
3064 ivideo->detectedpdca);
3065 }
3066 }
1da177e4 3067
544393fe
TW
3068 /* Save EMI */
3069 if(ivideo->vbflags2 & VB2_SISEMIBRIDGE) {
e57d4136
AK
3070 ivideo->SiS_Pr.EMI_30 = SiS_GetReg(SISPART4, 0x30);
3071 ivideo->SiS_Pr.EMI_31 = SiS_GetReg(SISPART4, 0x31);
3072 ivideo->SiS_Pr.EMI_32 = SiS_GetReg(SISPART4, 0x32);
3073 ivideo->SiS_Pr.EMI_33 = SiS_GetReg(SISPART4, 0x33);
c30660ea 3074 ivideo->SiS_Pr.HaveEMI = true;
544393fe 3075 if((tmp & 0x20) || (ivideo->detectedlcda != 0xff)) {
c30660ea 3076 ivideo->SiS_Pr.HaveEMILCD = true;
544393fe
TW
3077 }
3078 }
3079 }
1da177e4 3080
544393fe
TW
3081 /* Let user override detected PDCs (all bridges) */
3082 if(ivideo->vbflags2 & VB2_30xBLV) {
3083 if((ivideo->SiS_Pr.PDC != -1) &&
3084 (ivideo->SiS_Pr.PDC != ivideo->detectedpdc)) {
3085 printk(KERN_INFO "sisfb: Using LCD PDC 0x%02x (for LCD=CRT2)\n",
3086 ivideo->SiS_Pr.PDC);
3087 }
3088 if((ivideo->SiS_Pr.PDCA != -1) &&
3089 (ivideo->SiS_Pr.PDCA != ivideo->detectedpdca)) {
3090 printk(KERN_INFO "sisfb: Using LCD PDC1 0x%02x (for LCD=CRT1)\n",
3091 ivideo->SiS_Pr.PDCA);
3092 }
3093 }
1da177e4 3094
544393fe 3095 }
1da177e4 3096#endif
544393fe
TW
3097}
3098
3099/* -------------------- Memory manager routines ---------------------- */
3100
48c68c4f 3101static u32 sisfb_getheapstart(struct sis_video_info *ivideo)
544393fe
TW
3102{
3103 u32 ret = ivideo->sisfb_parm_mem * 1024;
3104 u32 maxoffs = ivideo->video_size - ivideo->hwcursor_size - ivideo->cmdQueueSize;
3105 u32 def;
3106
3107 /* Calculate heap start = end of memory for console
3108 *
3109 * CCCCCCCCDDDDDDDDDDDDDDDDDDDDDDDDDDDDHHHHQQQQQQQQQQ
3110 * C = console, D = heap, H = HWCursor, Q = cmd-queue
3111 *
3112 * On 76x in UMA+LFB mode, the layout is as follows:
3113 * DDDDDDDDDDDCCCCCCCCCCCCCCCCCCCCCCCCHHHHQQQQQQQQQQQ
3114 * where the heap is the entire UMA area, eventually
3115 * into the LFB area if the given mem parameter is
3116 * higher than the size of the UMA memory.
3117 *
3118 * Basically given by "mem" parameter
3119 *
3120 * maximum = videosize - cmd_queue - hwcursor
3121 * (results in a heap of size 0)
3122 * default = SiS 300: depends on videosize
3123 * SiS 315/330/340/XGI: 32k below max
3124 */
3125
3126 if(ivideo->sisvga_engine == SIS_300_VGA) {
3127 if(ivideo->video_size > 0x1000000) {
3128 def = 0xc00000;
3129 } else if(ivideo->video_size > 0x800000) {
3130 def = 0x800000;
3131 } else {
3132 def = 0x400000;
3133 }
3134 } else if(ivideo->UMAsize && ivideo->LFBsize) {
3135 ret = def = 0;
3136 } else {
3137 def = maxoffs - 0x8000;
3138 }
3139
3140 /* Use default for secondary card for now (FIXME) */
3141 if((!ret) || (ret > maxoffs) || (ivideo->cardnumber != 0))
3142 ret = def;
3143
3144 return ret;
3145}
3146
48c68c4f 3147static u32 sisfb_getheapsize(struct sis_video_info *ivideo)
544393fe
TW
3148{
3149 u32 max = ivideo->video_size - ivideo->hwcursor_size - ivideo->cmdQueueSize;
3150 u32 ret = 0;
3151
3152 if(ivideo->UMAsize && ivideo->LFBsize) {
3153 if( (!ivideo->sisfb_parm_mem) ||
3154 ((ivideo->sisfb_parm_mem * 1024) > max) ||
3155 ((max - (ivideo->sisfb_parm_mem * 1024)) < ivideo->UMAsize) ) {
3156 ret = ivideo->UMAsize;
3157 max -= ivideo->UMAsize;
3158 } else {
3159 ret = max - (ivideo->sisfb_parm_mem * 1024);
3160 max = ivideo->sisfb_parm_mem * 1024;
3161 }
3162 ivideo->video_offset = ret;
3163 ivideo->sisfb_mem = max;
3164 } else {
3165 ret = max - ivideo->heapstart;
3166 ivideo->sisfb_mem = ivideo->heapstart;
3167 }
1da177e4 3168
544393fe
TW
3169 return ret;
3170}
1da177e4 3171
48c68c4f 3172static int sisfb_heap_init(struct sis_video_info *ivideo)
544393fe
TW
3173{
3174 struct SIS_OH *poh;
1da177e4 3175
544393fe
TW
3176 ivideo->video_offset = 0;
3177 if(ivideo->sisfb_parm_mem) {
3178 if( (ivideo->sisfb_parm_mem < (2 * 1024 * 1024)) ||
3179 (ivideo->sisfb_parm_mem > ivideo->video_size) ) {
3180 ivideo->sisfb_parm_mem = 0;
3181 }
3182 }
1da177e4 3183
544393fe
TW
3184 ivideo->heapstart = sisfb_getheapstart(ivideo);
3185 ivideo->sisfb_heap_size = sisfb_getheapsize(ivideo);
1da177e4 3186
544393fe
TW
3187 ivideo->sisfb_heap_start = ivideo->video_vbase + ivideo->heapstart;
3188 ivideo->sisfb_heap_end = ivideo->sisfb_heap_start + ivideo->sisfb_heap_size;
1da177e4 3189
544393fe
TW
3190 printk(KERN_INFO "sisfb: Memory heap starting at %dK, size %dK\n",
3191 (int)(ivideo->heapstart / 1024), (int)(ivideo->sisfb_heap_size / 1024));
1da177e4 3192
544393fe 3193 ivideo->sisfb_heap.vinfo = ivideo;
1da177e4 3194
544393fe
TW
3195 ivideo->sisfb_heap.poha_chain = NULL;
3196 ivideo->sisfb_heap.poh_freelist = NULL;
1da177e4 3197
544393fe
TW
3198 poh = sisfb_poh_new_node(&ivideo->sisfb_heap);
3199 if(poh == NULL)
3200 return 1;
1da177e4 3201
544393fe
TW
3202 poh->poh_next = &ivideo->sisfb_heap.oh_free;
3203 poh->poh_prev = &ivideo->sisfb_heap.oh_free;
3204 poh->size = ivideo->sisfb_heap_size;
3205 poh->offset = ivideo->heapstart;
1da177e4 3206
544393fe
TW
3207 ivideo->sisfb_heap.oh_free.poh_next = poh;
3208 ivideo->sisfb_heap.oh_free.poh_prev = poh;
3209 ivideo->sisfb_heap.oh_free.size = 0;
3210 ivideo->sisfb_heap.max_freesize = poh->size;
1da177e4 3211
544393fe
TW
3212 ivideo->sisfb_heap.oh_used.poh_next = &ivideo->sisfb_heap.oh_used;
3213 ivideo->sisfb_heap.oh_used.poh_prev = &ivideo->sisfb_heap.oh_used;
3214 ivideo->sisfb_heap.oh_used.size = SENTINEL;
1da177e4 3215
544393fe
TW
3216 if(ivideo->cardnumber == 0) {
3217 /* For the first card, make this heap the "global" one
3218 * for old DRM (which could handle only one card)
3219 */
3220 sisfb_heap = &ivideo->sisfb_heap;
3221 }
1da177e4 3222
544393fe 3223 return 0;
1da177e4
LT
3224}
3225
544393fe
TW
3226static struct SIS_OH *
3227sisfb_poh_new_node(struct SIS_HEAP *memheap)
1da177e4 3228{
544393fe
TW
3229 struct SIS_OHALLOC *poha;
3230 struct SIS_OH *poh;
3231 unsigned long cOhs;
3232 int i;
1da177e4 3233
544393fe 3234 if(memheap->poh_freelist == NULL) {
1da177e4 3235 poha = kmalloc(SIS_OH_ALLOC_SIZE, GFP_KERNEL);
544393fe
TW
3236 if(!poha)
3237 return NULL;
1da177e4 3238
544393fe
TW
3239 poha->poha_next = memheap->poha_chain;
3240 memheap->poha_chain = poha;
1da177e4 3241
544393fe 3242 cOhs = (SIS_OH_ALLOC_SIZE - sizeof(struct SIS_OHALLOC)) / sizeof(struct SIS_OH) + 1;
1da177e4
LT
3243
3244 poh = &poha->aoh[0];
3245 for(i = cOhs - 1; i != 0; i--) {
3246 poh->poh_next = poh + 1;
3247 poh = poh + 1;
3248 }
3249
3250 poh->poh_next = NULL;
544393fe 3251 memheap->poh_freelist = &poha->aoh[0];
1da177e4
LT
3252 }
3253
544393fe
TW
3254 poh = memheap->poh_freelist;
3255 memheap->poh_freelist = poh->poh_next;
1da177e4 3256
544393fe 3257 return poh;
1da177e4
LT
3258}
3259
544393fe
TW
3260static struct SIS_OH *
3261sisfb_poh_allocate(struct SIS_HEAP *memheap, u32 size)
1da177e4 3262{
544393fe
TW
3263 struct SIS_OH *pohThis;
3264 struct SIS_OH *pohRoot;
3265 int bAllocated = 0;
1da177e4 3266
544393fe 3267 if(size > memheap->max_freesize) {
1da177e4
LT
3268 DPRINTK("sisfb: Can't allocate %dk video memory\n",
3269 (unsigned int) size / 1024);
544393fe 3270 return NULL;
1da177e4
LT
3271 }
3272
544393fe 3273 pohThis = memheap->oh_free.poh_next;
1da177e4 3274
544393fe
TW
3275 while(pohThis != &memheap->oh_free) {
3276 if(size <= pohThis->size) {
1da177e4
LT
3277 bAllocated = 1;
3278 break;
3279 }
3280 pohThis = pohThis->poh_next;
3281 }
3282
3283 if(!bAllocated) {
3284 DPRINTK("sisfb: Can't allocate %dk video memory\n",
3285 (unsigned int) size / 1024);
544393fe 3286 return NULL;
1da177e4
LT
3287 }
3288
3289 if(size == pohThis->size) {
3290 pohRoot = pohThis;
3291 sisfb_delete_node(pohThis);
3292 } else {
544393fe
TW
3293 pohRoot = sisfb_poh_new_node(memheap);
3294 if(pohRoot == NULL)
3295 return NULL;
1da177e4
LT
3296
3297 pohRoot->offset = pohThis->offset;
3298 pohRoot->size = size;
3299
3300 pohThis->offset += size;
3301 pohThis->size -= size;
3302 }
3303
544393fe 3304 memheap->max_freesize -= size;
1da177e4 3305
544393fe 3306 pohThis = &memheap->oh_used;
1da177e4
LT
3307 sisfb_insert_node(pohThis, pohRoot);
3308
544393fe 3309 return pohRoot;
1da177e4
LT
3310}
3311
3312static void
544393fe 3313sisfb_delete_node(struct SIS_OH *poh)
1da177e4 3314{
544393fe
TW
3315 poh->poh_prev->poh_next = poh->poh_next;
3316 poh->poh_next->poh_prev = poh->poh_prev;
1da177e4
LT
3317}
3318
3319static void
544393fe 3320sisfb_insert_node(struct SIS_OH *pohList, struct SIS_OH *poh)
1da177e4 3321{
544393fe 3322 struct SIS_OH *pohTemp = pohList->poh_next;
1da177e4
LT
3323
3324 pohList->poh_next = poh;
3325 pohTemp->poh_prev = poh;
3326
3327 poh->poh_prev = pohList;
3328 poh->poh_next = pohTemp;
3329}
3330
544393fe
TW
3331static struct SIS_OH *
3332sisfb_poh_free(struct SIS_HEAP *memheap, u32 base)
1da177e4 3333{
544393fe
TW
3334 struct SIS_OH *pohThis;
3335 struct SIS_OH *poh_freed;
3336 struct SIS_OH *poh_prev;
3337 struct SIS_OH *poh_next;
3338 u32 ulUpper;
3339 u32 ulLower;
3340 int foundNode = 0;
1da177e4 3341
544393fe 3342 poh_freed = memheap->oh_used.poh_next;
1da177e4 3343
544393fe 3344 while(poh_freed != &memheap->oh_used) {
1da177e4
LT
3345 if(poh_freed->offset == base) {
3346 foundNode = 1;
3347 break;
3348 }
3349
3350 poh_freed = poh_freed->poh_next;
3351 }
3352
544393fe
TW
3353 if(!foundNode)
3354 return NULL;
1da177e4 3355
544393fe 3356 memheap->max_freesize += poh_freed->size;
1da177e4
LT
3357
3358 poh_prev = poh_next = NULL;
3359 ulUpper = poh_freed->offset + poh_freed->size;
3360 ulLower = poh_freed->offset;
3361
544393fe 3362 pohThis = memheap->oh_free.poh_next;
1da177e4 3363
544393fe 3364 while(pohThis != &memheap->oh_free) {
1da177e4
LT
3365 if(pohThis->offset == ulUpper) {
3366 poh_next = pohThis;
3367 } else if((pohThis->offset + pohThis->size) == ulLower) {
3368 poh_prev = pohThis;
3369 }
3370 pohThis = pohThis->poh_next;
3371 }
3372
3373 sisfb_delete_node(poh_freed);
3374
3375 if(poh_prev && poh_next) {
3376 poh_prev->size += (poh_freed->size + poh_next->size);
3377 sisfb_delete_node(poh_next);
544393fe
TW
3378 sisfb_free_node(memheap, poh_freed);
3379 sisfb_free_node(memheap, poh_next);
3380 return poh_prev;
1da177e4
LT
3381 }
3382
3383 if(poh_prev) {
3384 poh_prev->size += poh_freed->size;
544393fe
TW
3385 sisfb_free_node(memheap, poh_freed);
3386 return poh_prev;
1da177e4
LT
3387 }
3388
3389 if(poh_next) {
3390 poh_next->size += poh_freed->size;
3391 poh_next->offset = poh_freed->offset;
544393fe
TW
3392 sisfb_free_node(memheap, poh_freed);
3393 return poh_next;
1da177e4
LT
3394 }
3395
544393fe 3396 sisfb_insert_node(&memheap->oh_free, poh_freed);
1da177e4 3397
544393fe 3398 return poh_freed;
1da177e4
LT
3399}
3400
3401static void
544393fe 3402sisfb_free_node(struct SIS_HEAP *memheap, struct SIS_OH *poh)
1da177e4 3403{
544393fe
TW
3404 if(poh == NULL)
3405 return;
1da177e4 3406
544393fe
TW
3407 poh->poh_next = memheap->poh_freelist;
3408 memheap->poh_freelist = poh;
1da177e4
LT
3409}
3410
544393fe
TW
3411static void
3412sis_int_malloc(struct sis_video_info *ivideo, struct sis_memreq *req)
1da177e4 3413{
544393fe 3414 struct SIS_OH *poh = NULL;
1da177e4 3415
544393fe
TW
3416 if((ivideo) && (ivideo->sisfb_id == SISFB_ID) && (!ivideo->havenoheap))
3417 poh = sisfb_poh_allocate(&ivideo->sisfb_heap, (u32)req->size);
1da177e4
LT
3418
3419 if(poh == NULL) {
544393fe
TW
3420 req->offset = req->size = 0;
3421 DPRINTK("sisfb: Video RAM allocation failed\n");
1da177e4 3422 } else {
544393fe
TW
3423 req->offset = poh->offset;
3424 req->size = poh->size;
3425 DPRINTK("sisfb: Video RAM allocation succeeded: 0x%lx\n",
3426 (poh->offset + ivideo->video_vbase));
1da177e4
LT
3427 }
3428}
3429
544393fe
TW
3430void
3431sis_malloc(struct sis_memreq *req)
3432{
3433 struct sis_video_info *ivideo = sisfb_heap->vinfo;
3434
3435 if(&ivideo->sisfb_heap == sisfb_heap)
3436 sis_int_malloc(ivideo, req);
3437 else
3438 req->offset = req->size = 0;
3439}
1da177e4
LT
3440
3441void
544393fe
TW
3442sis_malloc_new(struct pci_dev *pdev, struct sis_memreq *req)
3443{
3444 struct sis_video_info *ivideo = pci_get_drvdata(pdev);
3445
3446 sis_int_malloc(ivideo, req);
3447}
3448
3449/* sis_free: u32 because "base" is offset inside video ram, can never be >4GB */
3450
3451static void
3452sis_int_free(struct sis_video_info *ivideo, u32 base)
1da177e4 3453{
544393fe 3454 struct SIS_OH *poh;
1da177e4 3455
544393fe
TW
3456 if((!ivideo) || (ivideo->sisfb_id != SISFB_ID) || (ivideo->havenoheap))
3457 return;
1da177e4 3458
544393fe 3459 poh = sisfb_poh_free(&ivideo->sisfb_heap, base);
1da177e4
LT
3460
3461 if(poh == NULL) {
3462 DPRINTK("sisfb: sisfb_poh_free() failed at base 0x%x\n",
3463 (unsigned int) base);
3464 }
3465}
3466
544393fe
TW
3467void
3468sis_free(u32 base)
3469{
3470 struct sis_video_info *ivideo = sisfb_heap->vinfo;
3471
3472 sis_int_free(ivideo, base);
3473}
3474
3475void
3476sis_free_new(struct pci_dev *pdev, u32 base)
3477{
3478 struct sis_video_info *ivideo = pci_get_drvdata(pdev);
3479
3480 sis_int_free(ivideo, base);
3481}
3482
1da177e4
LT
3483/* --------------------- SetMode routines ------------------------- */
3484
544393fe
TW
3485static void
3486sisfb_check_engine_and_sync(struct sis_video_info *ivideo)
3487{
3488 u8 cr30, cr31;
3489
3490 /* Check if MMIO and engines are enabled,
3491 * and sync in case they are. Can't use
3492 * ivideo->accel here, as this might have
3493 * been changed before this is called.
3494 */
e57d4136
AK
3495 cr30 = SiS_GetReg(SISSR, IND_SIS_PCI_ADDRESS_SET);
3496 cr31 = SiS_GetReg(SISSR, IND_SIS_MODULE_ENABLE);
544393fe
TW
3497 /* MMIO and 2D/3D engine enabled? */
3498 if((cr30 & SIS_MEM_MAP_IO_ENABLE) && (cr31 & 0x42)) {
3499#ifdef CONFIG_FB_SIS_300
3500 if(ivideo->sisvga_engine == SIS_300_VGA) {
3501 /* Don't care about TurboQueue. It's
3502 * enough to know that the engines
3503 * are enabled
3504 */
3505 sisfb_syncaccel(ivideo);
3506 }
3507#endif
3508#ifdef CONFIG_FB_SIS_315
3509 if(ivideo->sisvga_engine == SIS_315_VGA) {
3510 /* Check that any queue mode is
3511 * enabled, and that the queue
3512 * is not in the state of "reset"
3513 */
e57d4136 3514 cr30 = SiS_GetReg(SISSR, 0x26);
544393fe
TW
3515 if((cr30 & 0xe0) && (!(cr30 & 0x01))) {
3516 sisfb_syncaccel(ivideo);
3517 }
3518 }
3519#endif
3520 }
3521}
3522
1da177e4
LT
3523static void
3524sisfb_pre_setmode(struct sis_video_info *ivideo)
3525{
3526 u8 cr30 = 0, cr31 = 0, cr33 = 0, cr35 = 0, cr38 = 0;
3527 int tvregnum = 0;
3528
3529 ivideo->currentvbflags &= (VB_VIDEOBRIDGE | VB_DISPTYPE_DISP2);
3530
44b751bb 3531 SiS_SetReg(SISSR, 0x05, 0x86);
544393fe 3532
e57d4136 3533 cr31 = SiS_GetReg(SISCR, 0x31);
1da177e4
LT
3534 cr31 &= ~0x60;
3535 cr31 |= 0x04;
3536
3537 cr33 = ivideo->rate_idx & 0x0F;
3538
3539#ifdef CONFIG_FB_SIS_315
3540 if(ivideo->sisvga_engine == SIS_315_VGA) {
3541 if(ivideo->chip >= SIS_661) {
e57d4136 3542 cr38 = SiS_GetReg(SISCR, 0x38);
1da177e4
LT
3543 cr38 &= ~0x07; /* Clear LCDA/DualEdge and YPbPr bits */
3544 } else {
3545 tvregnum = 0x38;
e57d4136 3546 cr38 = SiS_GetReg(SISCR, tvregnum);
1da177e4
LT
3547 cr38 &= ~0x3b; /* Clear LCDA/DualEdge and YPbPr bits */
3548 }
3549 }
3550#endif
3551#ifdef CONFIG_FB_SIS_300
3552 if(ivideo->sisvga_engine == SIS_300_VGA) {
3553 tvregnum = 0x35;
e57d4136 3554 cr38 = SiS_GetReg(SISCR, tvregnum);
1da177e4
LT
3555 }
3556#endif
3557
c30660ea
RK
3558 SiS_SetEnableDstn(&ivideo->SiS_Pr, false);
3559 SiS_SetEnableFstn(&ivideo->SiS_Pr, false);
544393fe 3560 ivideo->curFSTN = ivideo->curDSTN = 0;
1da177e4
LT
3561
3562 switch(ivideo->currentvbflags & VB_DISPTYPE_DISP2) {
3563
3564 case CRT2_TV:
3565 cr38 &= ~0xc0; /* Clear PAL-M / PAL-N bits */
544393fe 3566 if((ivideo->vbflags & TV_YPBPR) && (ivideo->vbflags2 & VB2_SISYPBPRBRIDGE)) {
1da177e4 3567#ifdef CONFIG_FB_SIS_315
544393fe
TW
3568 if(ivideo->chip >= SIS_661) {
3569 cr38 |= 0x04;
3570 if(ivideo->vbflags & TV_YPBPR525P) cr35 |= 0x20;
1da177e4
LT
3571 else if(ivideo->vbflags & TV_YPBPR750P) cr35 |= 0x40;
3572 else if(ivideo->vbflags & TV_YPBPR1080I) cr35 |= 0x60;
3573 cr30 |= SIS_SIMULTANEOUS_VIEW_ENABLE;
3574 cr35 &= ~0x01;
3575 ivideo->currentvbflags |= (TV_YPBPR | (ivideo->vbflags & TV_YPBPRALL));
544393fe
TW
3576 } else if(ivideo->sisvga_engine == SIS_315_VGA) {
3577 cr30 |= (0x80 | SIS_SIMULTANEOUS_VIEW_ENABLE);
1da177e4 3578 cr38 |= 0x08;
544393fe 3579 if(ivideo->vbflags & TV_YPBPR525P) cr38 |= 0x10;
1da177e4
LT
3580 else if(ivideo->vbflags & TV_YPBPR750P) cr38 |= 0x20;
3581 else if(ivideo->vbflags & TV_YPBPR1080I) cr38 |= 0x30;
3582 cr31 &= ~0x01;
3583 ivideo->currentvbflags |= (TV_YPBPR | (ivideo->vbflags & TV_YPBPRALL));
544393fe
TW
3584 }
3585#endif
3586 } else if((ivideo->vbflags & TV_HIVISION) &&
3587 (ivideo->vbflags2 & VB2_SISHIVISIONBRIDGE)) {
3588 if(ivideo->chip >= SIS_661) {
3589 cr38 |= 0x04;
3590 cr35 |= 0x60;
3591 } else {
3592 cr30 |= 0x80;
3593 }
1da177e4 3594 cr30 |= SIS_SIMULTANEOUS_VIEW_ENABLE;
544393fe
TW
3595 cr31 |= 0x01;
3596 cr35 |= 0x01;
1da177e4
LT
3597 ivideo->currentvbflags |= TV_HIVISION;
3598 } else if(ivideo->vbflags & TV_SCART) {
3599 cr30 = (SIS_VB_OUTPUT_SCART | SIS_SIMULTANEOUS_VIEW_ENABLE);
3600 cr31 |= 0x01;
3601 cr35 |= 0x01;
3602 ivideo->currentvbflags |= TV_SCART;
3603 } else {
3604 if(ivideo->vbflags & TV_SVIDEO) {
3605 cr30 = (SIS_VB_OUTPUT_SVIDEO | SIS_SIMULTANEOUS_VIEW_ENABLE);
3606 ivideo->currentvbflags |= TV_SVIDEO;
3607 }
3608 if(ivideo->vbflags & TV_AVIDEO) {
3609 cr30 = (SIS_VB_OUTPUT_COMPOSITE | SIS_SIMULTANEOUS_VIEW_ENABLE);
3610 ivideo->currentvbflags |= TV_AVIDEO;
3611 }
3612 }
3613 cr31 |= SIS_DRIVER_MODE;
3614
544393fe
TW
3615 if(ivideo->vbflags & (TV_AVIDEO | TV_SVIDEO)) {
3616 if(ivideo->vbflags & TV_PAL) {
1da177e4
LT
3617 cr31 |= 0x01; cr35 |= 0x01;
3618 ivideo->currentvbflags |= TV_PAL;
3619 if(ivideo->vbflags & TV_PALM) {
3620 cr38 |= 0x40; cr35 |= 0x04;
3621 ivideo->currentvbflags |= TV_PALM;
3622 } else if(ivideo->vbflags & TV_PALN) {
3623 cr38 |= 0x80; cr35 |= 0x08;
3624 ivideo->currentvbflags |= TV_PALN;
544393fe
TW
3625 }
3626 } else {
1da177e4
LT
3627 cr31 &= ~0x01; cr35 &= ~0x01;
3628 ivideo->currentvbflags |= TV_NTSC;
3629 if(ivideo->vbflags & TV_NTSCJ) {
3630 cr38 |= 0x40; cr35 |= 0x02;
3631 ivideo->currentvbflags |= TV_NTSCJ;
544393fe 3632 }
1da177e4
LT
3633 }
3634 }
3635 break;
3636
3637 case CRT2_LCD:
3638 cr30 = (SIS_VB_OUTPUT_LCD | SIS_SIMULTANEOUS_VIEW_ENABLE);
3639 cr31 |= SIS_DRIVER_MODE;
3640 SiS_SetEnableDstn(&ivideo->SiS_Pr, ivideo->sisfb_dstn);
3641 SiS_SetEnableFstn(&ivideo->SiS_Pr, ivideo->sisfb_fstn);
544393fe
TW
3642 ivideo->curFSTN = ivideo->sisfb_fstn;
3643 ivideo->curDSTN = ivideo->sisfb_dstn;
1da177e4
LT
3644 break;
3645
3646 case CRT2_VGA:
3647 cr30 = (SIS_VB_OUTPUT_CRT2 | SIS_SIMULTANEOUS_VIEW_ENABLE);
3648 cr31 |= SIS_DRIVER_MODE;
3649 if(ivideo->sisfb_nocrt2rate) {
3650 cr33 |= (sisbios_mode[ivideo->sisfb_mode_idx].rate_idx << 4);
3651 } else {
3652 cr33 |= ((ivideo->rate_idx & 0x0F) << 4);
3653 }
3654 break;
3655
3656 default: /* disable CRT2 */
3657 cr30 = 0x00;
3658 cr31 |= (SIS_DRIVER_MODE | SIS_VB_OUTPUT_DISABLE);
3659 }
3660
44b751bb
AK
3661 SiS_SetReg(SISCR, 0x30, cr30);
3662 SiS_SetReg(SISCR, 0x33, cr33);
1da177e4
LT
3663
3664 if(ivideo->chip >= SIS_661) {
3665#ifdef CONFIG_FB_SIS_315
3666 cr31 &= ~0x01; /* Clear PAL flag (now in CR35) */
ad78adb4 3667 SiS_SetRegANDOR(SISCR, 0x35, ~0x10, cr35); /* Leave overscan bit alone */
1da177e4 3668 cr38 &= 0x07; /* Use only LCDA and HiVision/YPbPr bits */
ad78adb4 3669 SiS_SetRegANDOR(SISCR, 0x38, 0xf8, cr38);
1da177e4
LT
3670#endif
3671 } else if(ivideo->chip != SIS_300) {
44b751bb 3672 SiS_SetReg(SISCR, tvregnum, cr38);
1da177e4 3673 }
44b751bb 3674 SiS_SetReg(SISCR, 0x31, cr31);
1da177e4 3675
1da177e4 3676 ivideo->SiS_Pr.SiS_UseOEM = ivideo->sisfb_useoem;
544393fe
TW
3677
3678 sisfb_check_engine_and_sync(ivideo);
1da177e4
LT
3679}
3680
3681/* Fix SR11 for 661 and later */
3682#ifdef CONFIG_FB_SIS_315
3683static void
3684sisfb_fixup_SR11(struct sis_video_info *ivideo)
3685{
544393fe
TW
3686 u8 tmpreg;
3687
3688 if(ivideo->chip >= SIS_661) {
e57d4136 3689 tmpreg = SiS_GetReg(SISSR, 0x11);
544393fe 3690 if(tmpreg & 0x20) {
e57d4136 3691 tmpreg = SiS_GetReg(SISSR, 0x3e);
544393fe 3692 tmpreg = (tmpreg + 1) & 0xff;
44b751bb 3693 SiS_SetReg(SISSR, 0x3e, tmpreg);
e57d4136 3694 tmpreg = SiS_GetReg(SISSR, 0x11);
544393fe
TW
3695 }
3696 if(tmpreg & 0xf0) {
667a8b41 3697 SiS_SetRegAND(SISSR, 0x11, 0x0f);
544393fe
TW
3698 }
3699 }
1da177e4
LT
3700}
3701#endif
3702
544393fe
TW
3703static void
3704sisfb_set_TVxposoffset(struct sis_video_info *ivideo, int val)
1da177e4 3705{
544393fe
TW
3706 if(val > 32) val = 32;
3707 if(val < -32) val = -32;
3708 ivideo->tvxpos = val;
1da177e4 3709
544393fe
TW
3710 if(ivideo->sisfblocked) return;
3711 if(!ivideo->modechanged) return;
1da177e4 3712
544393fe 3713 if(ivideo->currentvbflags & CRT2_TV) {
1da177e4 3714
544393fe 3715 if(ivideo->vbflags2 & VB2_CHRONTEL) {
1da177e4 3716
544393fe 3717 int x = ivideo->tvx;
1da177e4 3718
544393fe
TW
3719 switch(ivideo->chronteltype) {
3720 case 1:
3721 x += val;
3722 if(x < 0) x = 0;
44b751bb 3723 SiS_SetReg(SISSR, 0x05, 0x86);
544393fe
TW
3724 SiS_SetCH700x(&ivideo->SiS_Pr, 0x0a, (x & 0xff));
3725 SiS_SetCH70xxANDOR(&ivideo->SiS_Pr, 0x08, ((x & 0x0100) >> 7), 0xFD);
3726 break;
3727 case 2:
3728 /* Not supported by hardware */
3729 break;
3730 }
3731
3732 } else if(ivideo->vbflags2 & VB2_SISBRIDGE) {
3733
3734 u8 p2_1f,p2_20,p2_2b,p2_42,p2_43;
3735 unsigned short temp;
3736
3737 p2_1f = ivideo->p2_1f;
3738 p2_20 = ivideo->p2_20;
3739 p2_2b = ivideo->p2_2b;
3740 p2_42 = ivideo->p2_42;
3741 p2_43 = ivideo->p2_43;
3742
3743 temp = p2_1f | ((p2_20 & 0xf0) << 4);
3744 temp += (val * 2);
3745 p2_1f = temp & 0xff;
3746 p2_20 = (temp & 0xf00) >> 4;
3747 p2_2b = ((p2_2b & 0x0f) + (val * 2)) & 0x0f;
3748 temp = p2_43 | ((p2_42 & 0xf0) << 4);
3749 temp += (val * 2);
3750 p2_43 = temp & 0xff;
3751 p2_42 = (temp & 0xf00) >> 4;
44b751bb 3752 SiS_SetReg(SISPART2, 0x1f, p2_1f);
ad78adb4
AK
3753 SiS_SetRegANDOR(SISPART2, 0x20, 0x0F, p2_20);
3754 SiS_SetRegANDOR(SISPART2, 0x2b, 0xF0, p2_2b);
3755 SiS_SetRegANDOR(SISPART2, 0x42, 0x0F, p2_42);
44b751bb 3756 SiS_SetReg(SISPART2, 0x43, p2_43);
544393fe
TW
3757 }
3758 }
1da177e4
LT
3759}
3760
544393fe
TW
3761static void
3762sisfb_set_TVyposoffset(struct sis_video_info *ivideo, int val)
1da177e4 3763{
544393fe
TW
3764 if(val > 32) val = 32;
3765 if(val < -32) val = -32;
3766 ivideo->tvypos = val;
3767
3768 if(ivideo->sisfblocked) return;
3769 if(!ivideo->modechanged) return;
3770
3771 if(ivideo->currentvbflags & CRT2_TV) {
3772
3773 if(ivideo->vbflags2 & VB2_CHRONTEL) {
3774
3775 int y = ivideo->tvy;
3776
3777 switch(ivideo->chronteltype) {
3778 case 1:
3779 y -= val;
3780 if(y < 0) y = 0;
44b751bb 3781 SiS_SetReg(SISSR, 0x05, 0x86);
544393fe
TW
3782 SiS_SetCH700x(&ivideo->SiS_Pr, 0x0b, (y & 0xff));
3783 SiS_SetCH70xxANDOR(&ivideo->SiS_Pr, 0x08, ((y & 0x0100) >> 8), 0xFE);
3784 break;
3785 case 2:
3786 /* Not supported by hardware */
3787 break;
3788 }
3789
3790 } else if(ivideo->vbflags2 & VB2_SISBRIDGE) {
3791
3792 char p2_01, p2_02;
3793 val /= 2;
3794 p2_01 = ivideo->p2_01;
3795 p2_02 = ivideo->p2_02;
3796
3797 p2_01 += val;
3798 p2_02 += val;
3799 if(!(ivideo->currentvbflags & (TV_HIVISION | TV_YPBPR))) {
3800 while((p2_01 <= 0) || (p2_02 <= 0)) {
3801 p2_01 += 2;
3802 p2_02 += 2;
3803 }
3804 }
44b751bb
AK
3805 SiS_SetReg(SISPART2, 0x01, p2_01);
3806 SiS_SetReg(SISPART2, 0x02, p2_02);
544393fe
TW
3807 }
3808 }
1da177e4
LT
3809}
3810
3811static void
3812sisfb_post_setmode(struct sis_video_info *ivideo)
3813{
c30660ea
RK
3814 bool crt1isoff = false;
3815 bool doit = true;
1da177e4
LT
3816#if defined(CONFIG_FB_SIS_300) || defined(CONFIG_FB_SIS_315)
3817 u8 reg;
3818#endif
3819#ifdef CONFIG_FB_SIS_315
3820 u8 reg1;
3821#endif
3822
44b751bb 3823 SiS_SetReg(SISSR, 0x05, 0x86);
1da177e4
LT
3824
3825#ifdef CONFIG_FB_SIS_315
3826 sisfb_fixup_SR11(ivideo);
3827#endif
3828
3829 /* Now we actually HAVE changed the display mode */
544393fe 3830 ivideo->modechanged = 1;
1da177e4
LT
3831
3832 /* We can't switch off CRT1 if bridge is in slave mode */
544393fe 3833 if(ivideo->vbflags2 & VB2_VIDEOBRIDGE) {
c30660ea 3834 if(sisfb_bridgeisslave(ivideo)) doit = false;
544393fe
TW
3835 } else
3836 ivideo->sisfb_crt1off = 0;
1da177e4
LT
3837
3838#ifdef CONFIG_FB_SIS_300
3839 if(ivideo->sisvga_engine == SIS_300_VGA) {
544393fe 3840 if((ivideo->sisfb_crt1off) && (doit)) {
c30660ea 3841 crt1isoff = true;
544393fe
TW
3842 reg = 0x00;
3843 } else {
c30660ea 3844 crt1isoff = false;
544393fe
TW
3845 reg = 0x80;
3846 }
ad78adb4 3847 SiS_SetRegANDOR(SISCR, 0x17, 0x7f, reg);
1da177e4
LT
3848 }
3849#endif
3850#ifdef CONFIG_FB_SIS_315
3851 if(ivideo->sisvga_engine == SIS_315_VGA) {
544393fe 3852 if((ivideo->sisfb_crt1off) && (doit)) {
c30660ea 3853 crt1isoff = true;
544393fe
TW
3854 reg = 0x40;
3855 reg1 = 0xc0;
3856 } else {
c30660ea 3857 crt1isoff = false;
544393fe
TW
3858 reg = 0x00;
3859 reg1 = 0x00;
3860 }
ad78adb4 3861 SiS_SetRegANDOR(SISCR, ivideo->SiS_Pr.SiS_MyCR63, ~0x40, reg);
17d6ce11 3862 SiS_SetRegANDOR(SISSR, 0x1f, 0x3f, reg1);
1da177e4
LT
3863 }
3864#endif
3865
3866 if(crt1isoff) {
544393fe
TW
3867 ivideo->currentvbflags &= ~VB_DISPTYPE_CRT1;
3868 ivideo->currentvbflags |= VB_SINGLE_MODE;
1da177e4 3869 } else {
544393fe
TW
3870 ivideo->currentvbflags |= VB_DISPTYPE_CRT1;
3871 if(ivideo->currentvbflags & VB_DISPTYPE_CRT2) {
3872 ivideo->currentvbflags |= VB_MIRROR_MODE;
3873 } else {
3874 ivideo->currentvbflags |= VB_SINGLE_MODE;
3875 }
1da177e4
LT
3876 }
3877
667a8b41 3878 SiS_SetRegAND(SISSR, IND_SIS_RAMDAC_CONTROL, ~0x04);
1da177e4
LT
3879
3880 if(ivideo->currentvbflags & CRT2_TV) {
544393fe 3881 if(ivideo->vbflags2 & VB2_SISBRIDGE) {
e57d4136
AK
3882 ivideo->p2_1f = SiS_GetReg(SISPART2, 0x1f);
3883 ivideo->p2_20 = SiS_GetReg(SISPART2, 0x20);
3884 ivideo->p2_2b = SiS_GetReg(SISPART2, 0x2b);
3885 ivideo->p2_42 = SiS_GetReg(SISPART2, 0x42);
3886 ivideo->p2_43 = SiS_GetReg(SISPART2, 0x43);
3887 ivideo->p2_01 = SiS_GetReg(SISPART2, 0x01);
3888 ivideo->p2_02 = SiS_GetReg(SISPART2, 0x02);
544393fe
TW
3889 } else if(ivideo->vbflags2 & VB2_CHRONTEL) {
3890 if(ivideo->chronteltype == 1) {
3891 ivideo->tvx = SiS_GetCH700x(&ivideo->SiS_Pr, 0x0a);
3892 ivideo->tvx |= (((SiS_GetCH700x(&ivideo->SiS_Pr, 0x08) & 0x02) >> 1) << 8);
3893 ivideo->tvy = SiS_GetCH700x(&ivideo->SiS_Pr, 0x0b);
3894 ivideo->tvy |= ((SiS_GetCH700x(&ivideo->SiS_Pr, 0x08) & 0x01) << 8);
3895 }
3896 }
1da177e4
LT
3897 }
3898
3899 if(ivideo->tvxpos) {
544393fe 3900 sisfb_set_TVxposoffset(ivideo, ivideo->tvxpos);
1da177e4
LT
3901 }
3902 if(ivideo->tvypos) {
544393fe 3903 sisfb_set_TVyposoffset(ivideo, ivideo->tvypos);
1da177e4
LT
3904 }
3905
544393fe
TW
3906 /* Eventually sync engines */
3907 sisfb_check_engine_and_sync(ivideo);
1da177e4 3908
544393fe
TW
3909 /* (Re-)Initialize chip engines */
3910 if(ivideo->accel) {
3911 sisfb_engine_init(ivideo);
3912 } else {
3913 ivideo->engineok = 0;
3914 }
3915}
1da177e4 3916
544393fe
TW
3917static int
3918sisfb_reset_mode(struct sis_video_info *ivideo)
3919{
3920 if(sisfb_set_mode(ivideo, 0))
3921 return 1;
1da177e4 3922
544393fe
TW
3923 sisfb_set_pitch(ivideo);
3924 sisfb_set_base_CRT1(ivideo, ivideo->current_base);
3925 sisfb_set_base_CRT2(ivideo, ivideo->current_base);
1da177e4 3926
544393fe
TW
3927 return 0;
3928}
3929
3930static void
3931sisfb_handle_command(struct sis_video_info *ivideo, struct sisfb_cmd *sisfb_command)
3932{
3933 int mycrt1off;
1da177e4 3934
544393fe
TW
3935 switch(sisfb_command->sisfb_cmd) {
3936 case SISFB_CMD_GETVBFLAGS:
3937 if(!ivideo->modechanged) {
3938 sisfb_command->sisfb_result[0] = SISFB_CMD_ERR_EARLY;
3939 } else {
3940 sisfb_command->sisfb_result[0] = SISFB_CMD_ERR_OK;
3941 sisfb_command->sisfb_result[1] = ivideo->currentvbflags;
3942 sisfb_command->sisfb_result[2] = ivideo->vbflags2;
3943 }
3944 break;
3945 case SISFB_CMD_SWITCHCRT1:
3946 /* arg[0]: 0 = off, 1 = on, 99 = query */
3947 if(!ivideo->modechanged) {
3948 sisfb_command->sisfb_result[0] = SISFB_CMD_ERR_EARLY;
3949 } else if(sisfb_command->sisfb_arg[0] == 99) {
3950 /* Query */
3951 sisfb_command->sisfb_result[1] = ivideo->sisfb_crt1off ? 0 : 1;
3952 sisfb_command->sisfb_result[0] = SISFB_CMD_ERR_OK;
3953 } else if(ivideo->sisfblocked) {
3954 sisfb_command->sisfb_result[0] = SISFB_CMD_ERR_LOCKED;
3955 } else if((!(ivideo->currentvbflags & CRT2_ENABLE)) &&
3956 (sisfb_command->sisfb_arg[0] == 0)) {
3957 sisfb_command->sisfb_result[0] = SISFB_CMD_ERR_NOCRT2;
3958 } else {
3959 sisfb_command->sisfb_result[0] = SISFB_CMD_ERR_OK;
3960 mycrt1off = sisfb_command->sisfb_arg[0] ? 0 : 1;
3961 if( ((ivideo->currentvbflags & VB_DISPTYPE_CRT1) && mycrt1off) ||
3962 ((!(ivideo->currentvbflags & VB_DISPTYPE_CRT1)) && !mycrt1off) ) {
3963 ivideo->sisfb_crt1off = mycrt1off;
3964 if(sisfb_reset_mode(ivideo)) {
3965 sisfb_command->sisfb_result[0] = SISFB_CMD_ERR_OTHER;
1da177e4
LT
3966 }
3967 }
544393fe 3968 sisfb_command->sisfb_result[1] = ivideo->sisfb_crt1off ? 0 : 1;
1da177e4 3969 }
544393fe
TW
3970 break;
3971 /* more to come */
3972 default:
3973 sisfb_command->sisfb_result[0] = SISFB_CMD_ERR_UNKNOWN;
3974 printk(KERN_ERR "sisfb: Unknown command 0x%x\n",
3975 sisfb_command->sisfb_cmd);
1da177e4
LT
3976 }
3977}
3978
3979#ifndef MODULE
14aefd1b 3980static int __init sisfb_setup(char *options)
1da177e4
LT
3981{
3982 char *this_opt;
1da177e4 3983
544393fe 3984 sisfb_setdefaultparms();
1da177e4 3985
544393fe 3986 if(!options || !(*options))
1da177e4 3987 return 0;
1da177e4
LT
3988
3989 while((this_opt = strsep(&options, ",")) != NULL) {
3990
3991 if(!(*this_opt)) continue;
3992
c4dd0869 3993 if(!strncasecmp(this_opt, "off", 3)) {
1da177e4 3994 sisfb_off = 1;
c4dd0869 3995 } else if(!strncasecmp(this_opt, "forcecrt2type:", 14)) {
1da177e4
LT
3996 /* Need to check crt2 type first for fstn/dstn */
3997 sisfb_search_crt2type(this_opt + 14);
c4dd0869 3998 } else if(!strncasecmp(this_opt, "tvmode:",7)) {
1da177e4 3999 sisfb_search_tvstd(this_opt + 7);
c4dd0869 4000 } else if(!strncasecmp(this_opt, "tvstandard:",11)) {
544393fe 4001 sisfb_search_tvstd(this_opt + 11);
c4dd0869 4002 } else if(!strncasecmp(this_opt, "mode:", 5)) {
c30660ea 4003 sisfb_search_mode(this_opt + 5, false);
c4dd0869 4004 } else if(!strncasecmp(this_opt, "vesa:", 5)) {
c30660ea 4005 sisfb_search_vesamode(simple_strtoul(this_opt + 5, NULL, 0), false);
c4dd0869 4006 } else if(!strncasecmp(this_opt, "rate:", 5)) {
1da177e4 4007 sisfb_parm_rate = simple_strtoul(this_opt + 5, NULL, 0);
c4dd0869 4008 } else if(!strncasecmp(this_opt, "forcecrt1:", 10)) {
1da177e4 4009 sisfb_forcecrt1 = (int)simple_strtoul(this_opt + 10, NULL, 0);
c4dd0869 4010 } else if(!strncasecmp(this_opt, "mem:",4)) {
544393fe 4011 sisfb_parm_mem = simple_strtoul(this_opt + 4, NULL, 0);
c4dd0869 4012 } else if(!strncasecmp(this_opt, "pdc:", 4)) {
544393fe 4013 sisfb_pdc = simple_strtoul(this_opt + 4, NULL, 0);
c4dd0869 4014 } else if(!strncasecmp(this_opt, "pdc1:", 5)) {
544393fe 4015 sisfb_pdca = simple_strtoul(this_opt + 5, NULL, 0);
c4dd0869 4016 } else if(!strncasecmp(this_opt, "noaccel", 7)) {
1da177e4 4017 sisfb_accel = 0;
c4dd0869 4018 } else if(!strncasecmp(this_opt, "accel", 5)) {
1da177e4 4019 sisfb_accel = -1;
c4dd0869 4020 } else if(!strncasecmp(this_opt, "noypan", 6)) {
544393fe 4021 sisfb_ypan = 0;
c4dd0869 4022 } else if(!strncasecmp(this_opt, "ypan", 4)) {
544393fe 4023 sisfb_ypan = -1;
c4dd0869 4024 } else if(!strncasecmp(this_opt, "nomax", 5)) {
544393fe 4025 sisfb_max = 0;
c4dd0869 4026 } else if(!strncasecmp(this_opt, "max", 3)) {
544393fe 4027 sisfb_max = -1;
c4dd0869 4028 } else if(!strncasecmp(this_opt, "userom:", 7)) {
1da177e4 4029 sisfb_userom = (int)simple_strtoul(this_opt + 7, NULL, 0);
c4dd0869 4030 } else if(!strncasecmp(this_opt, "useoem:", 7)) {
1da177e4 4031 sisfb_useoem = (int)simple_strtoul(this_opt + 7, NULL, 0);
c4dd0869 4032 } else if(!strncasecmp(this_opt, "nocrt2rate", 10)) {
1da177e4 4033 sisfb_nocrt2rate = 1;
c4dd0869 4034 } else if(!strncasecmp(this_opt, "scalelcd:", 9)) {
544393fe
TW
4035 unsigned long temp = 2;
4036 temp = simple_strtoul(this_opt + 9, NULL, 0);
4037 if((temp == 0) || (temp == 1)) {
1da177e4 4038 sisfb_scalelcd = temp ^ 1;
544393fe 4039 }
c4dd0869 4040 } else if(!strncasecmp(this_opt, "tvxposoffset:", 13)) {
544393fe
TW
4041 int temp = 0;
4042 temp = (int)simple_strtol(this_opt + 13, NULL, 0);
4043 if((temp >= -32) && (temp <= 32)) {
1da177e4 4044 sisfb_tvxposoffset = temp;
544393fe 4045 }
c4dd0869 4046 } else if(!strncasecmp(this_opt, "tvyposoffset:", 13)) {
544393fe
TW
4047 int temp = 0;
4048 temp = (int)simple_strtol(this_opt + 13, NULL, 0);
4049 if((temp >= -32) && (temp <= 32)) {
1da177e4 4050 sisfb_tvyposoffset = temp;
544393fe 4051 }
c4dd0869 4052 } else if(!strncasecmp(this_opt, "specialtiming:", 14)) {
1da177e4 4053 sisfb_search_specialtiming(this_opt + 14);
c4dd0869 4054 } else if(!strncasecmp(this_opt, "lvdshl:", 7)) {
544393fe
TW
4055 int temp = 4;
4056 temp = simple_strtoul(this_opt + 7, NULL, 0);
4057 if((temp >= 0) && (temp <= 3)) {
1da177e4 4058 sisfb_lvdshl = temp;
544393fe 4059 }
1da177e4 4060 } else if(this_opt[0] >= '0' && this_opt[0] <= '9') {
c30660ea 4061 sisfb_search_mode(this_opt, true);
1da177e4 4062#if !defined(__i386__) && !defined(__x86_64__)
c4dd0869 4063 } else if(!strncasecmp(this_opt, "resetcard", 9)) {
544393fe 4064 sisfb_resetcard = 1;
c4dd0869 4065 } else if(!strncasecmp(this_opt, "videoram:", 9)) {
544393fe 4066 sisfb_videoram = simple_strtoul(this_opt + 9, NULL, 0);
1da177e4
LT
4067#endif
4068 } else {
4069 printk(KERN_INFO "sisfb: Invalid option %s\n", this_opt);
4070 }
4071
4072 }
4073
544393fe
TW
4074 return 0;
4075}
4076#endif
4077
48c68c4f
GKH
4078static int sisfb_check_rom(void __iomem *rom_base,
4079 struct sis_video_info *ivideo)
544393fe 4080{
14aefd1b 4081 void __iomem *rom;
544393fe
TW
4082 int romptr;
4083
4084 if((readb(rom_base) != 0x55) || (readb(rom_base + 1) != 0xaa))
4085 return 0;
4086
4087 romptr = (readb(rom_base + 0x18) | (readb(rom_base + 0x19) << 8));
4088 if(romptr > (0x10000 - 8))
4089 return 0;
4090
4091 rom = rom_base + romptr;
4092
4093 if((readb(rom) != 'P') || (readb(rom + 1) != 'C') ||
4094 (readb(rom + 2) != 'I') || (readb(rom + 3) != 'R'))
4095 return 0;
4096
4097 if((readb(rom + 4) | (readb(rom + 5) << 8)) != ivideo->chip_vendor)
4098 return 0;
4099
4100 if((readb(rom + 6) | (readb(rom + 7) << 8)) != ivideo->chip_id)
4101 return 0;
4102
4103 return 1;
4104}
4105
48c68c4f 4106static unsigned char *sisfb_find_rom(struct pci_dev *pdev)
544393fe
TW
4107{
4108 struct sis_video_info *ivideo = pci_get_drvdata(pdev);
14aefd1b 4109 void __iomem *rom_base;
544393fe 4110 unsigned char *myrombase = NULL;
544393fe
TW
4111 size_t romsize;
4112
4113 /* First, try the official pci ROM functions (except
4114 * on integrated chipsets which have no ROM).
4115 */
4116
4117 if(!ivideo->nbridge) {
4118
4119 if((rom_base = pci_map_rom(pdev, &romsize))) {
4120
4121 if(sisfb_check_rom(rom_base, ivideo)) {
4122
4123 if((myrombase = vmalloc(65536))) {
544393fe
TW
4124 memcpy_fromio(myrombase, rom_base,
4125 (romsize > 65536) ? 65536 : romsize);
4126 }
4127 }
4128 pci_unmap_rom(pdev, rom_base);
4129 }
4130 }
4131
4132 if(myrombase) return myrombase;
544393fe
TW
4133
4134 /* Otherwise do it the conventional way. */
4135
4136#if defined(__i386__) || defined(__x86_64__)
679c489f
AK
4137 {
4138 u32 temp;
544393fe 4139
679c489f 4140 for (temp = 0x000c0000; temp < 0x000f0000; temp += 0x00001000) {
544393fe 4141
679c489f
AK
4142 rom_base = ioremap(temp, 65536);
4143 if (!rom_base)
4144 continue;
544393fe 4145
679c489f
AK
4146 if (!sisfb_check_rom(rom_base, ivideo)) {
4147 iounmap(rom_base);
4148 continue;
4149 }
544393fe 4150
679c489f
AK
4151 if ((myrombase = vmalloc(65536)))
4152 memcpy_fromio(myrombase, rom_base, 65536);
544393fe 4153
679c489f
AK
4154 iounmap(rom_base);
4155 break;
544393fe 4156
679c489f 4157 }
544393fe 4158
679c489f 4159 }
544393fe
TW
4160#endif
4161
4162 return myrombase;
4163}
4164
48c68c4f
GKH
4165static void sisfb_post_map_vram(struct sis_video_info *ivideo,
4166 unsigned int *mapsize, unsigned int min)
544393fe 4167{
32ed3036
AK
4168 if (*mapsize < (min << 20))
4169 return;
4170
2cff6406 4171 ivideo->video_vbase = ioremap_wc(ivideo->video_base, (*mapsize));
544393fe
TW
4172
4173 if(!ivideo->video_vbase) {
4174 printk(KERN_ERR
4175 "sisfb: Unable to map maximum video RAM for size detection\n");
4176 (*mapsize) >>= 1;
2cff6406 4177 while((!(ivideo->video_vbase = ioremap_wc(ivideo->video_base, (*mapsize))))) {
544393fe
TW
4178 (*mapsize) >>= 1;
4179 if((*mapsize) < (min << 20))
4180 break;
4181 }
4182 if(ivideo->video_vbase) {
4183 printk(KERN_ERR
4184 "sisfb: Video RAM size detection limited to %dMB\n",
4185 (int)((*mapsize) >> 20));
4186 }
4187 }
4188}
4189
4190#ifdef CONFIG_FB_SIS_300
48c68c4f 4191static int sisfb_post_300_buswidth(struct sis_video_info *ivideo)
544393fe 4192{
14aefd1b 4193 void __iomem *FBAddress = ivideo->video_vbase;
544393fe
TW
4194 unsigned short temp;
4195 unsigned char reg;
4196 int i, j;
4197
667a8b41 4198 SiS_SetRegAND(SISSR, 0x15, 0xFB);
27799d6c 4199 SiS_SetRegOR(SISSR, 0x15, 0x04);
44b751bb
AK
4200 SiS_SetReg(SISSR, 0x13, 0x00);
4201 SiS_SetReg(SISSR, 0x14, 0xBF);
544393fe
TW
4202
4203 for(i = 0; i < 2; i++) {
4204 temp = 0x1234;
4205 for(j = 0; j < 4; j++) {
4206 writew(temp, FBAddress);
4207 if(readw(FBAddress) == temp)
4208 break;
27799d6c 4209 SiS_SetRegOR(SISSR, 0x3c, 0x01);
e57d4136
AK
4210 reg = SiS_GetReg(SISSR, 0x05);
4211 reg = SiS_GetReg(SISSR, 0x05);
667a8b41 4212 SiS_SetRegAND(SISSR, 0x3c, 0xfe);
e57d4136
AK
4213 reg = SiS_GetReg(SISSR, 0x05);
4214 reg = SiS_GetReg(SISSR, 0x05);
544393fe
TW
4215 temp++;
4216 }
4217 }
4218
4219 writel(0x01234567L, FBAddress);
4220 writel(0x456789ABL, (FBAddress + 4));
4221 writel(0x89ABCDEFL, (FBAddress + 8));
4222 writel(0xCDEF0123L, (FBAddress + 12));
4223
e57d4136 4224 reg = SiS_GetReg(SISSR, 0x3b);
544393fe
TW
4225 if(reg & 0x01) {
4226 if(readl((FBAddress + 12)) == 0xCDEF0123L)
4227 return 4; /* Channel A 128bit */
4228 }
4229
4230 if(readl((FBAddress + 4)) == 0x456789ABL)
4231 return 2; /* Channel B 64bit */
4232
4233 return 1; /* 32bit */
4234}
4235
48c68c4f 4236static const unsigned short SiS_DRAMType[17][5] = {
c1f58f1e
PH
4237 {0x0C,0x0A,0x02,0x40,0x39},
4238 {0x0D,0x0A,0x01,0x40,0x48},
4239 {0x0C,0x09,0x02,0x20,0x35},
4240 {0x0D,0x09,0x01,0x20,0x44},
4241 {0x0C,0x08,0x02,0x10,0x31},
4242 {0x0D,0x08,0x01,0x10,0x40},
4243 {0x0C,0x0A,0x01,0x20,0x34},
4244 {0x0C,0x09,0x01,0x08,0x32},
4245 {0x0B,0x08,0x02,0x08,0x21},
4246 {0x0C,0x08,0x01,0x08,0x30},
4247 {0x0A,0x08,0x02,0x04,0x11},
4248 {0x0B,0x0A,0x01,0x10,0x28},
4249 {0x09,0x08,0x02,0x02,0x01},
4250 {0x0B,0x09,0x01,0x08,0x24},
4251 {0x0B,0x08,0x01,0x04,0x20},
4252 {0x0A,0x08,0x01,0x02,0x10},
4253 {0x09,0x08,0x01,0x01,0x00}
4254};
4255
48c68c4f
GKH
4256static int sisfb_post_300_rwtest(struct sis_video_info *ivideo, int iteration,
4257 int buswidth, int PseudoRankCapacity,
4258 int PseudoAdrPinCount, unsigned int mapsize)
544393fe 4259{
14aefd1b 4260 void __iomem *FBAddr = ivideo->video_vbase;
544393fe
TW
4261 unsigned short sr14;
4262 unsigned int k, RankCapacity, PageCapacity, BankNumHigh, BankNumMid;
4263 unsigned int PhysicalAdrOtherPage, PhysicalAdrHigh, PhysicalAdrHalfPage;
544393fe 4264
c1f58f1e 4265 for(k = 0; k < ARRAY_SIZE(SiS_DRAMType); k++) {
544393fe
TW
4266
4267 RankCapacity = buswidth * SiS_DRAMType[k][3];
4268
4269 if(RankCapacity != PseudoRankCapacity)
4270 continue;
4271
4272 if((SiS_DRAMType[k][2] + SiS_DRAMType[k][0]) > PseudoAdrPinCount)
4273 continue;
4274
4275 BankNumHigh = RankCapacity * 16 * iteration - 1;
4276 if(iteration == 3) { /* Rank No */
4277 BankNumMid = RankCapacity * 16 - 1;
4278 } else {
4279 BankNumMid = RankCapacity * 16 * iteration / 2 - 1;
4280 }
4281
4282 PageCapacity = (1 << SiS_DRAMType[k][1]) * buswidth * 4;
4283 PhysicalAdrHigh = BankNumHigh;
4284 PhysicalAdrHalfPage = (PageCapacity / 2 + PhysicalAdrHigh) % PageCapacity;
4285 PhysicalAdrOtherPage = PageCapacity * SiS_DRAMType[k][2] + PhysicalAdrHigh;
4286
667a8b41 4287 SiS_SetRegAND(SISSR, 0x15, 0xFB); /* Test */
27799d6c 4288 SiS_SetRegOR(SISSR, 0x15, 0x04); /* Test */
544393fe
TW
4289 sr14 = (SiS_DRAMType[k][3] * buswidth) - 1;
4290 if(buswidth == 4) sr14 |= 0x80;
4291 else if(buswidth == 2) sr14 |= 0x40;
44b751bb
AK
4292 SiS_SetReg(SISSR, 0x13, SiS_DRAMType[k][4]);
4293 SiS_SetReg(SISSR, 0x14, sr14);
544393fe
TW
4294
4295 BankNumHigh <<= 16;
4296 BankNumMid <<= 16;
4297
4298 if((BankNumHigh + PhysicalAdrHigh >= mapsize) ||
4299 (BankNumMid + PhysicalAdrHigh >= mapsize) ||
4300 (BankNumHigh + PhysicalAdrHalfPage >= mapsize) ||
4301 (BankNumHigh + PhysicalAdrOtherPage >= mapsize))
4302 continue;
4303
4304 /* Write data */
4305 writew(((unsigned short)PhysicalAdrHigh),
4306 (FBAddr + BankNumHigh + PhysicalAdrHigh));
4307 writew(((unsigned short)BankNumMid),
4308 (FBAddr + BankNumMid + PhysicalAdrHigh));
4309 writew(((unsigned short)PhysicalAdrHalfPage),
4310 (FBAddr + BankNumHigh + PhysicalAdrHalfPage));
4311 writew(((unsigned short)PhysicalAdrOtherPage),
4312 (FBAddr + BankNumHigh + PhysicalAdrOtherPage));
4313
4314 /* Read data */
4315 if(readw(FBAddr + BankNumHigh + PhysicalAdrHigh) == PhysicalAdrHigh)
4316 return 1;
4317 }
4318
4319 return 0;
4320}
4321
48c68c4f 4322static void sisfb_post_300_ramsize(struct pci_dev *pdev, unsigned int mapsize)
544393fe
TW
4323{
4324 struct sis_video_info *ivideo = pci_get_drvdata(pdev);
4325 int i, j, buswidth;
4326 int PseudoRankCapacity, PseudoAdrPinCount;
4327
4328 buswidth = sisfb_post_300_buswidth(ivideo);
4329
4330 for(i = 6; i >= 0; i--) {
4331 PseudoRankCapacity = 1 << i;
4332 for(j = 4; j >= 1; j--) {
4333 PseudoAdrPinCount = 15 - j;
4334 if((PseudoRankCapacity * j) <= 64) {
4335 if(sisfb_post_300_rwtest(ivideo,
4336 j,
4337 buswidth,
4338 PseudoRankCapacity,
4339 PseudoAdrPinCount,
4340 mapsize))
4341 return;
4342 }
4343 }
4344 }
4345}
4346
48c68c4f 4347static void sisfb_post_sis300(struct pci_dev *pdev)
544393fe
TW
4348{
4349 struct sis_video_info *ivideo = pci_get_drvdata(pdev);
4350 unsigned char *bios = ivideo->SiS_Pr.VirtualRomBase;
4351 u8 reg, v1, v2, v3, v4, v5, v6, v7, v8;
4352 u16 index, rindex, memtype = 0;
4353 unsigned int mapsize;
4354
4355 if(!ivideo->SiS_Pr.UseROM)
4356 bios = NULL;
4357
44b751bb 4358 SiS_SetReg(SISSR, 0x05, 0x86);
544393fe
TW
4359
4360 if(bios) {
4361 if(bios[0x52] & 0x80) {
4362 memtype = bios[0x52];
4363 } else {
e57d4136 4364 memtype = SiS_GetReg(SISSR, 0x3a);
544393fe
TW
4365 }
4366 memtype &= 0x07;
4367 }
4368
4369 v3 = 0x80; v6 = 0x80;
4370 if(ivideo->revision_id <= 0x13) {
4371 v1 = 0x44; v2 = 0x42;
4372 v4 = 0x44; v5 = 0x42;
4373 } else {
4374 v1 = 0x68; v2 = 0x43; /* Assume 125Mhz MCLK */
4375 v4 = 0x68; v5 = 0x43; /* Assume 125Mhz ECLK */
4376 if(bios) {
4377 index = memtype * 5;
4378 rindex = index + 0x54;
4379 v1 = bios[rindex++];
4380 v2 = bios[rindex++];
4381 v3 = bios[rindex++];
4382 rindex = index + 0x7c;
4383 v4 = bios[rindex++];
4384 v5 = bios[rindex++];
4385 v6 = bios[rindex++];
4386 }
4387 }
44b751bb
AK
4388 SiS_SetReg(SISSR, 0x28, v1);
4389 SiS_SetReg(SISSR, 0x29, v2);
4390 SiS_SetReg(SISSR, 0x2a, v3);
4391 SiS_SetReg(SISSR, 0x2e, v4);
4392 SiS_SetReg(SISSR, 0x2f, v5);
4393 SiS_SetReg(SISSR, 0x30, v6);
544393fe
TW
4394
4395 v1 = 0x10;
4396 if(bios)
4397 v1 = bios[0xa4];
44b751bb 4398 SiS_SetReg(SISSR, 0x07, v1); /* DAC speed */
544393fe 4399
44b751bb 4400 SiS_SetReg(SISSR, 0x11, 0x0f); /* DDC, power save */
544393fe
TW
4401
4402 v1 = 0x01; v2 = 0x43; v3 = 0x1e; v4 = 0x2a;
4403 v5 = 0x06; v6 = 0x00; v7 = 0x00; v8 = 0x00;
4404 if(bios) {
4405 memtype += 0xa5;
4406 v1 = bios[memtype];
4407 v2 = bios[memtype + 8];
4408 v3 = bios[memtype + 16];
4409 v4 = bios[memtype + 24];
4410 v5 = bios[memtype + 32];
4411 v6 = bios[memtype + 40];
4412 v7 = bios[memtype + 48];
4413 v8 = bios[memtype + 56];
4414 }
4415 if(ivideo->revision_id >= 0x80)
4416 v3 &= 0xfd;
44b751bb
AK
4417 SiS_SetReg(SISSR, 0x15, v1); /* Ram type (assuming 0, BIOS 0xa5 step 8) */
4418 SiS_SetReg(SISSR, 0x16, v2);
4419 SiS_SetReg(SISSR, 0x17, v3);
4420 SiS_SetReg(SISSR, 0x18, v4);
4421 SiS_SetReg(SISSR, 0x19, v5);
4422 SiS_SetReg(SISSR, 0x1a, v6);
4423 SiS_SetReg(SISSR, 0x1b, v7);
4424 SiS_SetReg(SISSR, 0x1c, v8); /* ---- */
667a8b41 4425 SiS_SetRegAND(SISSR, 0x15, 0xfb);
27799d6c 4426 SiS_SetRegOR(SISSR, 0x15, 0x04);
544393fe
TW
4427 if(bios) {
4428 if(bios[0x53] & 0x02) {
27799d6c 4429 SiS_SetRegOR(SISSR, 0x19, 0x20);
544393fe
TW
4430 }
4431 }
4432 v1 = 0x04; /* DAC pedestal (BIOS 0xe5) */
4433 if(ivideo->revision_id >= 0x80)
4434 v1 |= 0x01;
44b751bb
AK
4435 SiS_SetReg(SISSR, 0x1f, v1);
4436 SiS_SetReg(SISSR, 0x20, 0xa4); /* linear & relocated io & disable a0000 */
544393fe
TW
4437 v1 = 0xf6; v2 = 0x0d; v3 = 0x00;
4438 if(bios) {
4439 v1 = bios[0xe8];
4440 v2 = bios[0xe9];
4441 v3 = bios[0xea];
4442 }
44b751bb
AK
4443 SiS_SetReg(SISSR, 0x23, v1);
4444 SiS_SetReg(SISSR, 0x24, v2);
4445 SiS_SetReg(SISSR, 0x25, v3);
4446 SiS_SetReg(SISSR, 0x21, 0x84);
4447 SiS_SetReg(SISSR, 0x22, 0x00);
4448 SiS_SetReg(SISCR, 0x37, 0x00);
27799d6c 4449 SiS_SetRegOR(SISPART1, 0x24, 0x01); /* unlock crt2 */
44b751bb 4450 SiS_SetReg(SISPART1, 0x00, 0x00);
544393fe
TW
4451 v1 = 0x40; v2 = 0x11;
4452 if(bios) {
4453 v1 = bios[0xec];
4454 v2 = bios[0xeb];
4455 }
44b751bb 4456 SiS_SetReg(SISPART1, 0x02, v1);
544393fe
TW
4457
4458 if(ivideo->revision_id >= 0x80)
4459 v2 &= ~0x01;
4460
e57d4136 4461 reg = SiS_GetReg(SISPART4, 0x00);
544393fe 4462 if((reg == 1) || (reg == 2)) {
44b751bb
AK
4463 SiS_SetReg(SISCR, 0x37, 0x02);
4464 SiS_SetReg(SISPART2, 0x00, 0x1c);
544393fe
TW
4465 v4 = 0x00; v5 = 0x00; v6 = 0x10;
4466 if(ivideo->SiS_Pr.UseROM) {
4467 v4 = bios[0xf5];
4468 v5 = bios[0xf6];
4469 v6 = bios[0xf7];
4470 }
44b751bb
AK
4471 SiS_SetReg(SISPART4, 0x0d, v4);
4472 SiS_SetReg(SISPART4, 0x0e, v5);
4473 SiS_SetReg(SISPART4, 0x10, v6);
4474 SiS_SetReg(SISPART4, 0x0f, 0x3f);
e57d4136 4475 reg = SiS_GetReg(SISPART4, 0x01);
544393fe 4476 if(reg >= 0xb0) {
e57d4136 4477 reg = SiS_GetReg(SISPART4, 0x23);
544393fe
TW
4478 reg &= 0x20;
4479 reg <<= 1;
44b751bb 4480 SiS_SetReg(SISPART4, 0x23, reg);
544393fe
TW
4481 }
4482 } else {
4483 v2 &= ~0x10;
4484 }
44b751bb 4485 SiS_SetReg(SISSR, 0x32, v2);
544393fe 4486
667a8b41 4487 SiS_SetRegAND(SISPART1, 0x24, 0xfe); /* Lock CRT2 */
544393fe 4488
e57d4136 4489 reg = SiS_GetReg(SISSR, 0x16);
544393fe 4490 reg &= 0xc3;
44b751bb
AK
4491 SiS_SetReg(SISCR, 0x35, reg);
4492 SiS_SetReg(SISCR, 0x83, 0x00);
544393fe
TW
4493#if !defined(__i386__) && !defined(__x86_64__)
4494 if(sisfb_videoram) {
44b751bb 4495 SiS_SetReg(SISSR, 0x13, 0x28); /* ? */
544393fe 4496 reg = ((sisfb_videoram >> 10) - 1) | 0x40;
44b751bb 4497 SiS_SetReg(SISSR, 0x14, reg);
544393fe
TW
4498 } else {
4499#endif
4500 /* Need to map max FB size for finding out about RAM size */
32ed3036 4501 mapsize = ivideo->video_size;
544393fe
TW
4502 sisfb_post_map_vram(ivideo, &mapsize, 4);
4503
4504 if(ivideo->video_vbase) {
4505 sisfb_post_300_ramsize(pdev, mapsize);
4506 iounmap(ivideo->video_vbase);
4507 } else {
4508 printk(KERN_DEBUG
4509 "sisfb: Failed to map memory for size detection, assuming 8MB\n");
44b751bb
AK
4510 SiS_SetReg(SISSR, 0x13, 0x28); /* ? */
4511 SiS_SetReg(SISSR, 0x14, 0x47); /* 8MB, 64bit default */
544393fe
TW
4512 }
4513#if !defined(__i386__) && !defined(__x86_64__)
4514 }
4515#endif
4516 if(bios) {
4517 v1 = bios[0xe6];
4518 v2 = bios[0xe7];
4519 } else {
e57d4136 4520 reg = SiS_GetReg(SISSR, 0x3a);
544393fe
TW
4521 if((reg & 0x30) == 0x30) {
4522 v1 = 0x04; /* PCI */
4523 v2 = 0x92;
4524 } else {
4525 v1 = 0x14; /* AGP */
4526 v2 = 0xb2;
4527 }
4528 }
44b751bb
AK
4529 SiS_SetReg(SISSR, 0x21, v1);
4530 SiS_SetReg(SISSR, 0x22, v2);
544393fe
TW
4531
4532 /* Sense CRT1 */
4533 sisfb_sense_crt1(ivideo);
4534
4535 /* Set default mode, don't clear screen */
c30660ea
RK
4536 ivideo->SiS_Pr.SiS_UseOEM = false;
4537 SiS_SetEnableDstn(&ivideo->SiS_Pr, false);
4538 SiS_SetEnableFstn(&ivideo->SiS_Pr, false);
544393fe
TW
4539 ivideo->curFSTN = ivideo->curDSTN = 0;
4540 ivideo->SiS_Pr.VideoMemorySize = 8 << 20;
4541 SiSSetMode(&ivideo->SiS_Pr, 0x2e | 0x80);
4542
44b751bb 4543 SiS_SetReg(SISSR, 0x05, 0x86);
544393fe
TW
4544
4545 /* Display off */
27799d6c 4546 SiS_SetRegOR(SISSR, 0x01, 0x20);
544393fe
TW
4547
4548 /* Save mode number in CR34 */
44b751bb 4549 SiS_SetReg(SISCR, 0x34, 0x2e);
544393fe
TW
4550
4551 /* Let everyone know what the current mode is */
4552 ivideo->modeprechange = 0x2e;
4553}
4554#endif
4555
4556#ifdef CONFIG_FB_SIS_315
4557#if 0
48c68c4f 4558static void sisfb_post_sis315330(struct pci_dev *pdev)
544393fe
TW
4559{
4560 /* TODO */
4561}
4562#endif
4563
929c972e
AK
4564static inline int sisfb_xgi_is21(struct sis_video_info *ivideo)
4565{
4566 return ivideo->chip_real_id == XGI_21;
4567}
4568
48c68c4f 4569static void sisfb_post_xgi_delay(struct sis_video_info *ivideo, int delay)
544393fe
TW
4570{
4571 unsigned int i;
4572 u8 reg;
4573
4574 for(i = 0; i <= (delay * 10 * 36); i++) {
e57d4136 4575 reg = SiS_GetReg(SISSR, 0x05);
544393fe
TW
4576 reg++;
4577 }
4578}
4579
48c68c4f
GKH
4580static int sisfb_find_host_bridge(struct sis_video_info *ivideo,
4581 struct pci_dev *mypdev,
4582 unsigned short pcivendor)
544393fe
TW
4583{
4584 struct pci_dev *pdev = NULL;
4585 unsigned short temp;
4586 int ret = 0;
4587
0959f0ca 4588 while((pdev = pci_get_class(PCI_CLASS_BRIDGE_HOST, pdev))) {
544393fe 4589 temp = pdev->vendor;
544393fe
TW
4590 if(temp == pcivendor) {
4591 ret = 1;
ea237a6a 4592 pci_dev_put(pdev);
544393fe
TW
4593 break;
4594 }
4595 }
4596
4597 return ret;
4598}
4599
48c68c4f
GKH
4600static int sisfb_post_xgi_rwtest(struct sis_video_info *ivideo, int starta,
4601 unsigned int enda, unsigned int mapsize)
544393fe
TW
4602{
4603 unsigned int pos;
4604 int i;
4605
4606 writel(0, ivideo->video_vbase);
4607
4608 for(i = starta; i <= enda; i++) {
4609 pos = 1 << i;
4610 if(pos < mapsize)
4611 writel(pos, ivideo->video_vbase + pos);
4612 }
4613
4614 sisfb_post_xgi_delay(ivideo, 150);
4615
4616 if(readl(ivideo->video_vbase) != 0)
4617 return 0;
4618
4619 for(i = starta; i <= enda; i++) {
4620 pos = 1 << i;
4621 if(pos < mapsize) {
4622 if(readl(ivideo->video_vbase + pos) != pos)
4623 return 0;
4624 } else
4625 return 0;
4626 }
4627
4628 return 1;
4629}
4630
48c68c4f 4631static int sisfb_post_xgi_ramsize(struct sis_video_info *ivideo)
544393fe
TW
4632{
4633 unsigned int buswidth, ranksize, channelab, mapsize;
83ea0f16 4634 int i, j, k, l, status;
544393fe
TW
4635 u8 reg, sr14;
4636 static const u8 dramsr13[12 * 5] = {
4637 0x02, 0x0e, 0x0b, 0x80, 0x5d,
4638 0x02, 0x0e, 0x0a, 0x40, 0x59,
4639 0x02, 0x0d, 0x0b, 0x40, 0x4d,
4640 0x02, 0x0e, 0x09, 0x20, 0x55,
4641 0x02, 0x0d, 0x0a, 0x20, 0x49,
4642 0x02, 0x0c, 0x0b, 0x20, 0x3d,
4643 0x02, 0x0e, 0x08, 0x10, 0x51,
4644 0x02, 0x0d, 0x09, 0x10, 0x45,
4645 0x02, 0x0c, 0x0a, 0x10, 0x39,
4646 0x02, 0x0d, 0x08, 0x08, 0x41,
4647 0x02, 0x0c, 0x09, 0x08, 0x35,
4648 0x02, 0x0c, 0x08, 0x04, 0x31
4649 };
4650 static const u8 dramsr13_4[4 * 5] = {
4651 0x02, 0x0d, 0x09, 0x40, 0x45,
4652 0x02, 0x0c, 0x09, 0x20, 0x35,
4653 0x02, 0x0c, 0x08, 0x10, 0x31,
4654 0x02, 0x0b, 0x08, 0x08, 0x21
4655 };
4656
4657 /* Enable linear mode, disable 0xa0000 address decoding */
4658 /* We disable a0000 address decoding, because
4659 * - if running on x86, if the card is disabled, it means
4660 * that another card is in the system. We don't want
4661 * to interphere with that primary card's textmode.
4662 * - if running on non-x86, there usually is no VGA window
4663 * at a0000.
4664 */
27799d6c 4665 SiS_SetRegOR(SISSR, 0x20, (0x80 | 0x04));
544393fe
TW
4666
4667 /* Need to map max FB size for finding out about RAM size */
32ed3036 4668 mapsize = ivideo->video_size;
544393fe
TW
4669 sisfb_post_map_vram(ivideo, &mapsize, 32);
4670
4671 if(!ivideo->video_vbase) {
4672 printk(KERN_ERR "sisfb: Unable to detect RAM size. Setting default.\n");
44b751bb
AK
4673 SiS_SetReg(SISSR, 0x13, 0x35);
4674 SiS_SetReg(SISSR, 0x14, 0x41);
544393fe 4675 /* TODO */
83ea0f16 4676 return -ENOMEM;
544393fe
TW
4677 }
4678
4679 /* Non-interleaving */
44b751bb 4680 SiS_SetReg(SISSR, 0x15, 0x00);
544393fe 4681 /* No tiling */
44b751bb 4682 SiS_SetReg(SISSR, 0x1c, 0x00);
544393fe
TW
4683
4684 if(ivideo->chip == XGI_20) {
4685
4686 channelab = 1;
e57d4136 4687 reg = SiS_GetReg(SISCR, 0x97);
544393fe
TW
4688 if(!(reg & 0x01)) { /* Single 32/16 */
4689 buswidth = 32;
44b751bb
AK
4690 SiS_SetReg(SISSR, 0x13, 0xb1);
4691 SiS_SetReg(SISSR, 0x14, 0x52);
544393fe
TW
4692 sisfb_post_xgi_delay(ivideo, 1);
4693 sr14 = 0x02;
4694 if(sisfb_post_xgi_rwtest(ivideo, 23, 24, mapsize))
4695 goto bail_out;
4696
44b751bb
AK
4697 SiS_SetReg(SISSR, 0x13, 0x31);
4698 SiS_SetReg(SISSR, 0x14, 0x42);
544393fe
TW
4699 sisfb_post_xgi_delay(ivideo, 1);
4700 if(sisfb_post_xgi_rwtest(ivideo, 23, 23, mapsize))
4701 goto bail_out;
4702
4703 buswidth = 16;
44b751bb
AK
4704 SiS_SetReg(SISSR, 0x13, 0xb1);
4705 SiS_SetReg(SISSR, 0x14, 0x41);
544393fe
TW
4706 sisfb_post_xgi_delay(ivideo, 1);
4707 sr14 = 0x01;
4708 if(sisfb_post_xgi_rwtest(ivideo, 22, 23, mapsize))
4709 goto bail_out;
4710 else
44b751bb 4711 SiS_SetReg(SISSR, 0x13, 0x31);
544393fe
TW
4712 } else { /* Dual 16/8 */
4713 buswidth = 16;
44b751bb
AK
4714 SiS_SetReg(SISSR, 0x13, 0xb1);
4715 SiS_SetReg(SISSR, 0x14, 0x41);
544393fe
TW
4716 sisfb_post_xgi_delay(ivideo, 1);
4717 sr14 = 0x01;
4718 if(sisfb_post_xgi_rwtest(ivideo, 22, 23, mapsize))
4719 goto bail_out;
4720
44b751bb
AK
4721 SiS_SetReg(SISSR, 0x13, 0x31);
4722 SiS_SetReg(SISSR, 0x14, 0x31);
544393fe
TW
4723 sisfb_post_xgi_delay(ivideo, 1);
4724 if(sisfb_post_xgi_rwtest(ivideo, 22, 22, mapsize))
4725 goto bail_out;
4726
4727 buswidth = 8;
44b751bb
AK
4728 SiS_SetReg(SISSR, 0x13, 0xb1);
4729 SiS_SetReg(SISSR, 0x14, 0x30);
544393fe
TW
4730 sisfb_post_xgi_delay(ivideo, 1);
4731 sr14 = 0x00;
4732 if(sisfb_post_xgi_rwtest(ivideo, 21, 22, mapsize))
4733 goto bail_out;
4734 else
44b751bb 4735 SiS_SetReg(SISSR, 0x13, 0x31);
544393fe
TW
4736 }
4737
4738 } else { /* XGI_40 */
4739
e57d4136 4740 reg = SiS_GetReg(SISCR, 0x97);
544393fe 4741 if(!(reg & 0x10)) {
e57d4136 4742 reg = SiS_GetReg(SISSR, 0x39);
544393fe
TW
4743 reg >>= 1;
4744 }
4745
4746 if(reg & 0x01) { /* DDRII */
4747 buswidth = 32;
4748 if(ivideo->revision_id == 2) {
4749 channelab = 2;
44b751bb
AK
4750 SiS_SetReg(SISSR, 0x13, 0xa1);
4751 SiS_SetReg(SISSR, 0x14, 0x44);
544393fe
TW
4752 sr14 = 0x04;
4753 sisfb_post_xgi_delay(ivideo, 1);
4754 if(sisfb_post_xgi_rwtest(ivideo, 23, 24, mapsize))
4755 goto bail_out;
4756
44b751bb
AK
4757 SiS_SetReg(SISSR, 0x13, 0x21);
4758 SiS_SetReg(SISSR, 0x14, 0x34);
544393fe
TW
4759 if(sisfb_post_xgi_rwtest(ivideo, 22, 23, mapsize))
4760 goto bail_out;
4761
4762 channelab = 1;
44b751bb
AK
4763 SiS_SetReg(SISSR, 0x13, 0xa1);
4764 SiS_SetReg(SISSR, 0x14, 0x40);
544393fe
TW
4765 sr14 = 0x00;
4766 if(sisfb_post_xgi_rwtest(ivideo, 22, 23, mapsize))
4767 goto bail_out;
4768
44b751bb
AK
4769 SiS_SetReg(SISSR, 0x13, 0x21);
4770 SiS_SetReg(SISSR, 0x14, 0x30);
544393fe
TW
4771 } else {
4772 channelab = 3;
44b751bb
AK
4773 SiS_SetReg(SISSR, 0x13, 0xa1);
4774 SiS_SetReg(SISSR, 0x14, 0x4c);
544393fe
TW
4775 sr14 = 0x0c;
4776 sisfb_post_xgi_delay(ivideo, 1);
4777 if(sisfb_post_xgi_rwtest(ivideo, 23, 25, mapsize))
4778 goto bail_out;
4779
4780 channelab = 2;
44b751bb 4781 SiS_SetReg(SISSR, 0x14, 0x48);
544393fe
TW
4782 sisfb_post_xgi_delay(ivideo, 1);
4783 sr14 = 0x08;
4784 if(sisfb_post_xgi_rwtest(ivideo, 23, 24, mapsize))
4785 goto bail_out;
4786
44b751bb
AK
4787 SiS_SetReg(SISSR, 0x13, 0x21);
4788 SiS_SetReg(SISSR, 0x14, 0x3c);
544393fe
TW
4789 sr14 = 0x0c;
4790
4791 if(sisfb_post_xgi_rwtest(ivideo, 23, 24, mapsize)) {
4792 channelab = 3;
4793 } else {
4794 channelab = 2;
44b751bb 4795 SiS_SetReg(SISSR, 0x14, 0x38);
544393fe
TW
4796 sr14 = 0x08;
4797 }
4798 }
4799 sisfb_post_xgi_delay(ivideo, 1);
4800
4801 } else { /* DDR */
4802
4803 buswidth = 64;
4804 if(ivideo->revision_id == 2) {
4805 channelab = 1;
44b751bb
AK
4806 SiS_SetReg(SISSR, 0x13, 0xa1);
4807 SiS_SetReg(SISSR, 0x14, 0x52);
544393fe
TW
4808 sisfb_post_xgi_delay(ivideo, 1);
4809 sr14 = 0x02;
4810 if(sisfb_post_xgi_rwtest(ivideo, 23, 24, mapsize))
4811 goto bail_out;
4812
44b751bb
AK
4813 SiS_SetReg(SISSR, 0x13, 0x21);
4814 SiS_SetReg(SISSR, 0x14, 0x42);
544393fe
TW
4815 } else {
4816 channelab = 2;
44b751bb
AK
4817 SiS_SetReg(SISSR, 0x13, 0xa1);
4818 SiS_SetReg(SISSR, 0x14, 0x5a);
544393fe
TW
4819 sisfb_post_xgi_delay(ivideo, 1);
4820 sr14 = 0x0a;
4821 if(sisfb_post_xgi_rwtest(ivideo, 24, 25, mapsize))
4822 goto bail_out;
4823
44b751bb
AK
4824 SiS_SetReg(SISSR, 0x13, 0x21);
4825 SiS_SetReg(SISSR, 0x14, 0x4a);
544393fe
TW
4826 }
4827 sisfb_post_xgi_delay(ivideo, 1);
4828
4829 }
4830 }
4831
4832bail_out:
ad78adb4 4833 SiS_SetRegANDOR(SISSR, 0x14, 0xf0, sr14);
544393fe
TW
4834 sisfb_post_xgi_delay(ivideo, 1);
4835
4836 j = (ivideo->chip == XGI_20) ? 5 : 9;
4837 k = (ivideo->chip == XGI_20) ? 12 : 4;
83ea0f16 4838 status = -EIO;
544393fe
TW
4839
4840 for(i = 0; i < k; i++) {
4841
4842 reg = (ivideo->chip == XGI_20) ?
4843 dramsr13[(i * 5) + 4] : dramsr13_4[(i * 5) + 4];
ad78adb4 4844 SiS_SetRegANDOR(SISSR, 0x13, 0x80, reg);
544393fe
TW
4845 sisfb_post_xgi_delay(ivideo, 50);
4846
4847 ranksize = (ivideo->chip == XGI_20) ?
4848 dramsr13[(i * 5) + 3] : dramsr13_4[(i * 5) + 3];
4849
e57d4136 4850 reg = SiS_GetReg(SISSR, 0x13);
544393fe
TW
4851 if(reg & 0x80) ranksize <<= 1;
4852
4853 if(ivideo->chip == XGI_20) {
4854 if(buswidth == 16) ranksize <<= 1;
4855 else if(buswidth == 32) ranksize <<= 2;
4856 } else {
4857 if(buswidth == 64) ranksize <<= 1;
4858 }
4859
4860 reg = 0;
4861 l = channelab;
4862 if(l == 3) l = 4;
4863 if((ranksize * l) <= 256) {
4864 while((ranksize >>= 1)) reg += 0x10;
4865 }
4866
4867 if(!reg) continue;
4868
ad78adb4 4869 SiS_SetRegANDOR(SISSR, 0x14, 0x0f, (reg & 0xf0));
544393fe
TW
4870 sisfb_post_xgi_delay(ivideo, 1);
4871
83ea0f16
AK
4872 if (sisfb_post_xgi_rwtest(ivideo, j, ((reg >> 4) + channelab - 2 + 20), mapsize)) {
4873 status = 0;
544393fe 4874 break;
83ea0f16 4875 }
544393fe
TW
4876 }
4877
4878 iounmap(ivideo->video_vbase);
83ea0f16
AK
4879
4880 return status;
544393fe 4881}
1da177e4 4882
48c68c4f 4883static void sisfb_post_xgi_setclocks(struct sis_video_info *ivideo, u8 regb)
544393fe
TW
4884{
4885 u8 v1, v2, v3;
4886 int index;
4887 static const u8 cs90[8 * 3] = {
4888 0x16, 0x01, 0x01,
4889 0x3e, 0x03, 0x01,
4890 0x7c, 0x08, 0x01,
4891 0x79, 0x06, 0x01,
4892 0x29, 0x01, 0x81,
4893 0x5c, 0x23, 0x01,
4894 0x5c, 0x23, 0x01,
4895 0x5c, 0x23, 0x01
4896 };
4897 static const u8 csb8[8 * 3] = {
4898 0x5c, 0x23, 0x01,
4899 0x29, 0x01, 0x01,
4900 0x7c, 0x08, 0x01,
4901 0x79, 0x06, 0x01,
4902 0x29, 0x01, 0x81,
4903 0x5c, 0x23, 0x01,
4904 0x5c, 0x23, 0x01,
4905 0x5c, 0x23, 0x01
4906 };
1da177e4 4907
544393fe
TW
4908 regb = 0; /* ! */
4909
4910 index = regb * 3;
4911 v1 = cs90[index]; v2 = cs90[index + 1]; v3 = cs90[index + 2];
4912 if(ivideo->haveXGIROM) {
4913 v1 = ivideo->bios_abase[0x90 + index];
4914 v2 = ivideo->bios_abase[0x90 + index + 1];
4915 v3 = ivideo->bios_abase[0x90 + index + 2];
4916 }
44b751bb
AK
4917 SiS_SetReg(SISSR, 0x28, v1);
4918 SiS_SetReg(SISSR, 0x29, v2);
4919 SiS_SetReg(SISSR, 0x2a, v3);
544393fe
TW
4920 sisfb_post_xgi_delay(ivideo, 0x43);
4921 sisfb_post_xgi_delay(ivideo, 0x43);
4922 sisfb_post_xgi_delay(ivideo, 0x43);
4923 index = regb * 3;
4924 v1 = csb8[index]; v2 = csb8[index + 1]; v3 = csb8[index + 2];
4925 if(ivideo->haveXGIROM) {
4926 v1 = ivideo->bios_abase[0xb8 + index];
4927 v2 = ivideo->bios_abase[0xb8 + index + 1];
4928 v3 = ivideo->bios_abase[0xb8 + index + 2];
4929 }
44b751bb
AK
4930 SiS_SetReg(SISSR, 0x2e, v1);
4931 SiS_SetReg(SISSR, 0x2f, v2);
4932 SiS_SetReg(SISSR, 0x30, v3);
544393fe
TW
4933 sisfb_post_xgi_delay(ivideo, 0x43);
4934 sisfb_post_xgi_delay(ivideo, 0x43);
4935 sisfb_post_xgi_delay(ivideo, 0x43);
1da177e4 4936}
1da177e4 4937
48c68c4f
GKH
4938static void sisfb_post_xgi_ddr2_mrs_default(struct sis_video_info *ivideo,
4939 u8 regb)
c9982d59
AK
4940{
4941 unsigned char *bios = ivideo->bios_abase;
4942 u8 v1;
4943
4944 SiS_SetReg(SISSR, 0x28, 0x64);
4945 SiS_SetReg(SISSR, 0x29, 0x63);
4946 sisfb_post_xgi_delay(ivideo, 15);
4947 SiS_SetReg(SISSR, 0x18, 0x00);
4948 SiS_SetReg(SISSR, 0x19, 0x20);
4949 SiS_SetReg(SISSR, 0x16, 0x00);
4950 SiS_SetReg(SISSR, 0x16, 0x80);
4951 SiS_SetReg(SISSR, 0x18, 0xc5);
4952 SiS_SetReg(SISSR, 0x19, 0x23);
4953 SiS_SetReg(SISSR, 0x16, 0x00);
4954 SiS_SetReg(SISSR, 0x16, 0x80);
4955 sisfb_post_xgi_delay(ivideo, 1);
4956 SiS_SetReg(SISCR, 0x97, 0x11);
4957 sisfb_post_xgi_setclocks(ivideo, regb);
4958 sisfb_post_xgi_delay(ivideo, 0x46);
4959 SiS_SetReg(SISSR, 0x18, 0xc5);
4960 SiS_SetReg(SISSR, 0x19, 0x23);
4961 SiS_SetReg(SISSR, 0x16, 0x00);
4962 SiS_SetReg(SISSR, 0x16, 0x80);
4963 sisfb_post_xgi_delay(ivideo, 1);
4964 SiS_SetReg(SISSR, 0x1b, 0x04);
4965 sisfb_post_xgi_delay(ivideo, 1);
4966 SiS_SetReg(SISSR, 0x1b, 0x00);
4967 sisfb_post_xgi_delay(ivideo, 1);
4968 v1 = 0x31;
4969 if (ivideo->haveXGIROM) {
4970 v1 = bios[0xf0];
4971 }
4972 SiS_SetReg(SISSR, 0x18, v1);
4973 SiS_SetReg(SISSR, 0x19, 0x06);
4974 SiS_SetReg(SISSR, 0x16, 0x04);
4975 SiS_SetReg(SISSR, 0x16, 0x84);
4976 sisfb_post_xgi_delay(ivideo, 1);
4977}
4978
48c68c4f 4979static void sisfb_post_xgi_ddr2_mrs_xg21(struct sis_video_info *ivideo)
42dea903
AK
4980{
4981 sisfb_post_xgi_setclocks(ivideo, 1);
4982
4983 SiS_SetReg(SISCR, 0x97, 0x11);
4984 sisfb_post_xgi_delay(ivideo, 0x46);
4985
4986 SiS_SetReg(SISSR, 0x18, 0x00); /* EMRS2 */
4987 SiS_SetReg(SISSR, 0x19, 0x80);
4988 SiS_SetReg(SISSR, 0x16, 0x05);
4989 SiS_SetReg(SISSR, 0x16, 0x85);
4990
4991 SiS_SetReg(SISSR, 0x18, 0x00); /* EMRS3 */
4992 SiS_SetReg(SISSR, 0x19, 0xc0);
4993 SiS_SetReg(SISSR, 0x16, 0x05);
4994 SiS_SetReg(SISSR, 0x16, 0x85);
4995
4996 SiS_SetReg(SISSR, 0x18, 0x00); /* EMRS1 */
4997 SiS_SetReg(SISSR, 0x19, 0x40);
4998 SiS_SetReg(SISSR, 0x16, 0x05);
4999 SiS_SetReg(SISSR, 0x16, 0x85);
5000
5001 SiS_SetReg(SISSR, 0x18, 0x42); /* MRS1 */
5002 SiS_SetReg(SISSR, 0x19, 0x02);
5003 SiS_SetReg(SISSR, 0x16, 0x05);
5004 SiS_SetReg(SISSR, 0x16, 0x85);
5005 sisfb_post_xgi_delay(ivideo, 1);
5006
5007 SiS_SetReg(SISSR, 0x1b, 0x04);
5008 sisfb_post_xgi_delay(ivideo, 1);
5009
5010 SiS_SetReg(SISSR, 0x1b, 0x00);
5011 sisfb_post_xgi_delay(ivideo, 1);
5012
5013 SiS_SetReg(SISSR, 0x18, 0x42); /* MRS1 */
5014 SiS_SetReg(SISSR, 0x19, 0x00);
5015 SiS_SetReg(SISSR, 0x16, 0x05);
5016 SiS_SetReg(SISSR, 0x16, 0x85);
5017 sisfb_post_xgi_delay(ivideo, 1);
5018}
5019
48c68c4f 5020static void sisfb_post_xgi_ddr2(struct sis_video_info *ivideo, u8 regb)
c9982d59
AK
5021{
5022 unsigned char *bios = ivideo->bios_abase;
5023 static const u8 cs158[8] = {
5024 0x88, 0xaa, 0x48, 0x00, 0x00, 0x00, 0x00, 0x00
5025 };
5026 static const u8 cs160[8] = {
5027 0x44, 0x77, 0x77, 0x00, 0x00, 0x00, 0x00, 0x00
5028 };
5029 static const u8 cs168[8] = {
5030 0x48, 0x78, 0x88, 0x00, 0x00, 0x00, 0x00, 0x00
5031 };
5032 u8 reg;
5033 u8 v1;
5034 u8 v2;
5035 u8 v3;
5036
42dea903 5037 SiS_SetReg(SISCR, 0xb0, 0x80); /* DDR2 dual frequency mode */
c9982d59
AK
5038 SiS_SetReg(SISCR, 0x82, 0x77);
5039 SiS_SetReg(SISCR, 0x86, 0x00);
5040 reg = SiS_GetReg(SISCR, 0x86);
5041 SiS_SetReg(SISCR, 0x86, 0x88);
5042 reg = SiS_GetReg(SISCR, 0x86);
5043 v1 = cs168[regb]; v2 = cs160[regb]; v3 = cs158[regb];
5044 if (ivideo->haveXGIROM) {
5045 v1 = bios[regb + 0x168];
5046 v2 = bios[regb + 0x160];
5047 v3 = bios[regb + 0x158];
5048 }
5049 SiS_SetReg(SISCR, 0x86, v1);
5050 SiS_SetReg(SISCR, 0x82, 0x77);
5051 SiS_SetReg(SISCR, 0x85, 0x00);
5052 reg = SiS_GetReg(SISCR, 0x85);
5053 SiS_SetReg(SISCR, 0x85, 0x88);
5054 reg = SiS_GetReg(SISCR, 0x85);
5055 SiS_SetReg(SISCR, 0x85, v2);
5056 SiS_SetReg(SISCR, 0x82, v3);
5057 SiS_SetReg(SISCR, 0x98, 0x01);
5058 SiS_SetReg(SISCR, 0x9a, 0x02);
42dea903
AK
5059 if (sisfb_xgi_is21(ivideo))
5060 sisfb_post_xgi_ddr2_mrs_xg21(ivideo);
5061 else
5062 sisfb_post_xgi_ddr2_mrs_default(ivideo, regb);
c9982d59
AK
5063}
5064
48c68c4f 5065static u8 sisfb_post_xgi_ramtype(struct sis_video_info *ivideo)
74de5f4e
AK
5066{
5067 unsigned char *bios = ivideo->bios_abase;
5068 u8 ramtype;
5069 u8 reg;
5070 u8 v1;
5071
5072 ramtype = 0x00; v1 = 0x10;
5073 if (ivideo->haveXGIROM) {
5074 ramtype = bios[0x62];
5075 v1 = bios[0x1d2];
5076 }
5077 if (!(ramtype & 0x80)) {
5e8700bf
AK
5078 if (sisfb_xgi_is21(ivideo)) {
5079 SiS_SetRegAND(SISCR, 0xb4, 0xfd); /* GPIO control */
5080 SiS_SetRegOR(SISCR, 0x4a, 0x80); /* GPIOH EN */
5081 reg = SiS_GetReg(SISCR, 0x48);
5082 SiS_SetRegOR(SISCR, 0xb4, 0x02);
5083 ramtype = reg & 0x01; /* GPIOH */
5084 } else if (ivideo->chip == XGI_20) {
74de5f4e
AK
5085 SiS_SetReg(SISCR, 0x97, v1);
5086 reg = SiS_GetReg(SISCR, 0x97);
5087 if (reg & 0x10) {
5088 ramtype = (reg & 0x01) << 1;
5089 }
5090 } else {
5091 reg = SiS_GetReg(SISSR, 0x39);
5092 ramtype = reg & 0x02;
5093 if (!(ramtype)) {
5094 reg = SiS_GetReg(SISSR, 0x3a);
5095 ramtype = (reg >> 1) & 0x01;
5096 }
5097 }
5098 }
5099 ramtype &= 0x07;
5100
5101 return ramtype;
5102}
5103
48c68c4f 5104static int sisfb_post_xgi(struct pci_dev *pdev)
1da177e4
LT
5105{
5106 struct sis_video_info *ivideo = pci_get_drvdata(pdev);
544393fe
TW
5107 unsigned char *bios = ivideo->bios_abase;
5108 struct pci_dev *mypdev = NULL;
5109 const u8 *ptr, *ptr2;
5110 u8 v1, v2, v3, v4, v5, reg, ramtype;
5111 u32 rega, regb, regd;
5112 int i, j, k, index;
5113 static const u8 cs78[3] = { 0xf6, 0x0d, 0x00 };
5114 static const u8 cs76[2] = { 0xa3, 0xfb };
5115 static const u8 cs7b[3] = { 0xc0, 0x11, 0x00 };
5116 static const u8 cs158[8] = {
5117 0x88, 0xaa, 0x48, 0x00, 0x00, 0x00, 0x00, 0x00
5118 };
5119 static const u8 cs160[8] = {
5120 0x44, 0x77, 0x77, 0x00, 0x00, 0x00, 0x00, 0x00
5121 };
5122 static const u8 cs168[8] = {
5123 0x48, 0x78, 0x88, 0x00, 0x00, 0x00, 0x00, 0x00
5124 };
5125 static const u8 cs128[3 * 8] = {
5126 0x90, 0x28, 0x24, 0x00, 0x00, 0x00, 0x00, 0x00,
5127 0x77, 0x44, 0x44, 0x00, 0x00, 0x00, 0x00, 0x00,
5128 0x77, 0x44, 0x44, 0x00, 0x00, 0x00, 0x00, 0x00
5129 };
5130 static const u8 cs148[2 * 8] = {
5131 0x55, 0x55, 0x55, 0x00, 0x00, 0x00, 0x00, 0x00,
5132 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
5133 };
5134 static const u8 cs31a[8 * 4] = {
5135 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
5136 0xaa, 0xaa, 0xaa, 0xaa, 0x00, 0x00, 0x00, 0x00,
5137 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
5138 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
5139 };
5140 static const u8 cs33a[8 * 4] = {
5141 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
5142 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
5143 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
5144 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
5145 };
5146 static const u8 cs45a[8 * 2] = {
5147 0x00, 0x00, 0xa0, 0x00, 0xa0, 0x00, 0x00, 0x00,
5148 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
5149 };
5150 static const u8 cs170[7 * 8] = {
5151 0x54, 0x32, 0x44, 0x00, 0x00, 0x00, 0x00, 0x00,
5152 0x54, 0x43, 0x44, 0x00, 0x00, 0x00, 0x00, 0x00,
5153 0x0a, 0x05, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00,
5154 0x44, 0x34, 0x44, 0x00, 0x00, 0x00, 0x00, 0x00,
5155 0x10, 0x0a, 0x0a, 0x00, 0x00, 0x00, 0x00, 0x00,
5156 0x11, 0x0c, 0x0c, 0x00, 0x00, 0x00, 0x00, 0x00,
5157 0x05, 0x05, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00
5158 };
5159 static const u8 cs1a8[3 * 8] = {
5160 0xf0, 0xf0, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x00,
5161 0x05, 0x02, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00,
5162 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
5163 };
5164 static const u8 cs100[2 * 8] = {
5165 0xc4, 0x04, 0x84, 0x00, 0x00, 0x00, 0x00, 0x00,
5166 0xc4, 0x04, 0x84, 0x00, 0x00, 0x00, 0x00, 0x00
5167 };
1da177e4 5168
544393fe 5169 /* VGA enable */
1e1687d7 5170 reg = SiS_GetRegByte(SISVGAENABLE) | 0x01;
63e13f8e 5171 SiS_SetRegByte(SISVGAENABLE, reg);
1da177e4 5172
544393fe 5173 /* Misc */
1e1687d7 5174 reg = SiS_GetRegByte(SISMISCR) | 0x01;
63e13f8e 5175 SiS_SetRegByte(SISMISCW, reg);
1da177e4 5176
544393fe 5177 /* Unlock SR */
44b751bb 5178 SiS_SetReg(SISSR, 0x05, 0x86);
e57d4136 5179 reg = SiS_GetReg(SISSR, 0x05);
544393fe
TW
5180 if(reg != 0xa1)
5181 return 0;
1da177e4 5182
544393fe
TW
5183 /* Clear some regs */
5184 for(i = 0; i < 0x22; i++) {
5185 if(0x06 + i == 0x20) continue;
44b751bb 5186 SiS_SetReg(SISSR, 0x06 + i, 0x00);
544393fe
TW
5187 }
5188 for(i = 0; i < 0x0b; i++) {
44b751bb 5189 SiS_SetReg(SISSR, 0x31 + i, 0x00);
544393fe
TW
5190 }
5191 for(i = 0; i < 0x10; i++) {
44b751bb 5192 SiS_SetReg(SISCR, 0x30 + i, 0x00);
544393fe 5193 }
1da177e4 5194
544393fe
TW
5195 ptr = cs78;
5196 if(ivideo->haveXGIROM) {
5197 ptr = (const u8 *)&bios[0x78];
5198 }
5199 for(i = 0; i < 3; i++) {
44b751bb 5200 SiS_SetReg(SISSR, 0x23 + i, ptr[i]);
544393fe 5201 }
1da177e4 5202
544393fe
TW
5203 ptr = cs76;
5204 if(ivideo->haveXGIROM) {
5205 ptr = (const u8 *)&bios[0x76];
5206 }
5207 for(i = 0; i < 2; i++) {
44b751bb 5208 SiS_SetReg(SISSR, 0x21 + i, ptr[i]);
544393fe 5209 }
1da177e4 5210
544393fe
TW
5211 v1 = 0x18; v2 = 0x00;
5212 if(ivideo->haveXGIROM) {
5213 v1 = bios[0x74];
5214 v2 = bios[0x75];
5215 }
44b751bb
AK
5216 SiS_SetReg(SISSR, 0x07, v1);
5217 SiS_SetReg(SISSR, 0x11, 0x0f);
5218 SiS_SetReg(SISSR, 0x1f, v2);
544393fe 5219 /* PCI linear mode, RelIO enabled, A0000 decoding disabled */
44b751bb
AK
5220 SiS_SetReg(SISSR, 0x20, 0x80 | 0x20 | 0x04);
5221 SiS_SetReg(SISSR, 0x27, 0x74);
1da177e4 5222
544393fe
TW
5223 ptr = cs7b;
5224 if(ivideo->haveXGIROM) {
5225 ptr = (const u8 *)&bios[0x7b];
5226 }
5227 for(i = 0; i < 3; i++) {
44b751bb 5228 SiS_SetReg(SISSR, 0x31 + i, ptr[i]);
544393fe 5229 }
1da177e4 5230
544393fe
TW
5231 if(ivideo->chip == XGI_40) {
5232 if(ivideo->revision_id == 2) {
ad78adb4 5233 SiS_SetRegANDOR(SISSR, 0x3b, 0x3f, 0xc0);
544393fe 5234 }
44b751bb
AK
5235 SiS_SetReg(SISCR, 0x7d, 0xfe);
5236 SiS_SetReg(SISCR, 0x7e, 0x0f);
544393fe
TW
5237 }
5238 if(ivideo->revision_id == 0) { /* 40 *and* 20? */
667a8b41 5239 SiS_SetRegAND(SISCR, 0x58, 0xd7);
e57d4136 5240 reg = SiS_GetReg(SISCR, 0xcb);
544393fe 5241 if(reg & 0x20) {
ad78adb4 5242 SiS_SetRegANDOR(SISCR, 0x58, 0xd7, (reg & 0x10) ? 0x08 : 0x20); /* =0x28 Z7 ? */
544393fe
TW
5243 }
5244 }
1da177e4 5245
544393fe 5246 reg = (ivideo->chip == XGI_40) ? 0x20 : 0x00;
ad78adb4 5247 SiS_SetRegANDOR(SISCR, 0x38, 0x1f, reg);
1da177e4 5248
544393fe 5249 if(ivideo->chip == XGI_20) {
44b751bb 5250 SiS_SetReg(SISSR, 0x36, 0x70);
544393fe 5251 } else {
44b751bb
AK
5252 SiS_SetReg(SISVID, 0x00, 0x86);
5253 SiS_SetReg(SISVID, 0x32, 0x00);
5254 SiS_SetReg(SISVID, 0x30, 0x00);
5255 SiS_SetReg(SISVID, 0x32, 0x01);
5256 SiS_SetReg(SISVID, 0x30, 0x00);
667a8b41
AK
5257 SiS_SetRegAND(SISVID, 0x2f, 0xdf);
5258 SiS_SetRegAND(SISCAP, 0x00, 0x3f);
544393fe 5259
44b751bb
AK
5260 SiS_SetReg(SISPART1, 0x2f, 0x01);
5261 SiS_SetReg(SISPART1, 0x00, 0x00);
5262 SiS_SetReg(SISPART1, 0x02, bios[0x7e]);
5263 SiS_SetReg(SISPART1, 0x2e, 0x08);
667a8b41
AK
5264 SiS_SetRegAND(SISPART1, 0x35, 0x7f);
5265 SiS_SetRegAND(SISPART1, 0x50, 0xfe);
544393fe 5266
e57d4136 5267 reg = SiS_GetReg(SISPART4, 0x00);
544393fe 5268 if(reg == 1 || reg == 2) {
44b751bb
AK
5269 SiS_SetReg(SISPART2, 0x00, 0x1c);
5270 SiS_SetReg(SISPART4, 0x0d, bios[0x7f]);
5271 SiS_SetReg(SISPART4, 0x0e, bios[0x80]);
5272 SiS_SetReg(SISPART4, 0x10, bios[0x81]);
667a8b41 5273 SiS_SetRegAND(SISPART4, 0x0f, 0x3f);
544393fe 5274
e57d4136 5275 reg = SiS_GetReg(SISPART4, 0x01);
544393fe 5276 if((reg & 0xf0) >= 0xb0) {
e57d4136 5277 reg = SiS_GetReg(SISPART4, 0x23);
544393fe 5278 if(reg & 0x20) reg |= 0x40;
44b751bb 5279 SiS_SetReg(SISPART4, 0x23, reg);
544393fe 5280 reg = (reg & 0x20) ? 0x02 : 0x00;
ad78adb4 5281 SiS_SetRegANDOR(SISPART1, 0x1e, 0xfd, reg);
544393fe
TW
5282 }
5283 }
1da177e4 5284
544393fe
TW
5285 v1 = bios[0x77];
5286
e57d4136 5287 reg = SiS_GetReg(SISSR, 0x3b);
544393fe 5288 if(reg & 0x02) {
e57d4136 5289 reg = SiS_GetReg(SISSR, 0x3a);
544393fe
TW
5290 v2 = (reg & 0x30) >> 3;
5291 if(!(v2 & 0x04)) v2 ^= 0x02;
e57d4136 5292 reg = SiS_GetReg(SISSR, 0x39);
544393fe
TW
5293 if(reg & 0x80) v2 |= 0x80;
5294 v2 |= 0x01;
5295
0959f0ca
AB
5296 if((mypdev = pci_get_device(PCI_VENDOR_ID_SI, 0x0730, NULL))) {
5297 pci_dev_put(mypdev);
544393fe
TW
5298 if(((v2 & 0x06) == 2) || ((v2 & 0x06) == 4))
5299 v2 &= 0xf9;
5300 v2 |= 0x08;
5301 v1 &= 0xfe;
5302 } else {
0959f0ca 5303 mypdev = pci_get_device(PCI_VENDOR_ID_SI, 0x0735, NULL);
544393fe 5304 if(!mypdev)
0959f0ca 5305 mypdev = pci_get_device(PCI_VENDOR_ID_SI, 0x0645, NULL);
544393fe 5306 if(!mypdev)
0959f0ca 5307 mypdev = pci_get_device(PCI_VENDOR_ID_SI, 0x0650, NULL);
544393fe
TW
5308 if(mypdev) {
5309 pci_read_config_dword(mypdev, 0x94, &regd);
5310 regd &= 0xfffffeff;
5311 pci_write_config_dword(mypdev, 0x94, regd);
5312 v1 &= 0xfe;
0959f0ca 5313 pci_dev_put(mypdev);
544393fe
TW
5314 } else if(sisfb_find_host_bridge(ivideo, pdev, PCI_VENDOR_ID_SI)) {
5315 v1 &= 0xfe;
5316 } else if(sisfb_find_host_bridge(ivideo, pdev, 0x1106) ||
5317 sisfb_find_host_bridge(ivideo, pdev, 0x1022) ||
5318 sisfb_find_host_bridge(ivideo, pdev, 0x700e) ||
5319 sisfb_find_host_bridge(ivideo, pdev, 0x10de)) {
5320 if((v2 & 0x06) == 4)
5321 v2 ^= 0x06;
5322 v2 |= 0x08;
5323 }
5324 }
ad78adb4 5325 SiS_SetRegANDOR(SISCR, 0x5f, 0xf0, v2);
544393fe 5326 }
44b751bb 5327 SiS_SetReg(SISSR, 0x22, v1);
544393fe
TW
5328
5329 if(ivideo->revision_id == 2) {
e57d4136
AK
5330 v1 = SiS_GetReg(SISSR, 0x3b);
5331 v2 = SiS_GetReg(SISSR, 0x3a);
544393fe
TW
5332 regd = bios[0x90 + 3] | (bios[0x90 + 4] << 8);
5333 if( (!(v1 & 0x02)) && (v2 & 0x30) && (regd < 0xcf) )
ad78adb4 5334 SiS_SetRegANDOR(SISCR, 0x5f, 0xf1, 0x01);
544393fe 5335
0959f0ca 5336 if((mypdev = pci_get_device(0x10de, 0x01e0, NULL))) {
544393fe
TW
5337 /* TODO: set CR5f &0xf1 | 0x01 for version 6570
5338 * of nforce 2 ROM
5339 */
5340 if(0)
ad78adb4 5341 SiS_SetRegANDOR(SISCR, 0x5f, 0xf1, 0x01);
0959f0ca 5342 pci_dev_put(mypdev);
544393fe
TW
5343 }
5344 }
1da177e4 5345
544393fe 5346 v1 = 0x30;
e57d4136
AK
5347 reg = SiS_GetReg(SISSR, 0x3b);
5348 v2 = SiS_GetReg(SISCR, 0x5f);
544393fe
TW
5349 if((!(reg & 0x02)) && (v2 & 0x0e))
5350 v1 |= 0x08;
44b751bb 5351 SiS_SetReg(SISSR, 0x27, v1);
1da177e4 5352
544393fe 5353 if(bios[0x64] & 0x01) {
ad78adb4 5354 SiS_SetRegANDOR(SISCR, 0x5f, 0xf0, bios[0x64]);
544393fe
TW
5355 }
5356
5357 v1 = bios[0x4f7];
5358 pci_read_config_dword(pdev, 0x50, &regd);
5359 regd = (regd >> 20) & 0x0f;
5360 if(regd == 1) {
5361 v1 &= 0xfc;
27799d6c 5362 SiS_SetRegOR(SISCR, 0x5f, 0x08);
544393fe 5363 }
44b751bb 5364 SiS_SetReg(SISCR, 0x48, v1);
544393fe 5365
ad78adb4
AK
5366 SiS_SetRegANDOR(SISCR, 0x47, 0x04, bios[0x4f6] & 0xfb);
5367 SiS_SetRegANDOR(SISCR, 0x49, 0xf0, bios[0x4f8] & 0x0f);
5368 SiS_SetRegANDOR(SISCR, 0x4a, 0x60, bios[0x4f9] & 0x9f);
5369 SiS_SetRegANDOR(SISCR, 0x4b, 0x08, bios[0x4fa] & 0xf7);
5370 SiS_SetRegANDOR(SISCR, 0x4c, 0x80, bios[0x4fb] & 0x7f);
44b751bb 5371 SiS_SetReg(SISCR, 0x70, bios[0x4fc]);
ad78adb4 5372 SiS_SetRegANDOR(SISCR, 0x71, 0xf0, bios[0x4fd] & 0x0f);
44b751bb 5373 SiS_SetReg(SISCR, 0x74, 0xd0);
ad78adb4
AK
5374 SiS_SetRegANDOR(SISCR, 0x74, 0xcf, bios[0x4fe] & 0x30);
5375 SiS_SetRegANDOR(SISCR, 0x75, 0xe0, bios[0x4ff] & 0x1f);
5376 SiS_SetRegANDOR(SISCR, 0x76, 0xe0, bios[0x500] & 0x1f);
544393fe 5377 v1 = bios[0x501];
0959f0ca 5378 if((mypdev = pci_get_device(0x8086, 0x2530, NULL))) {
544393fe 5379 v1 = 0xf0;
0959f0ca 5380 pci_dev_put(mypdev);
544393fe 5381 }
44b751bb 5382 SiS_SetReg(SISCR, 0x77, v1);
1da177e4 5383 }
1da177e4 5384
42dea903
AK
5385 /* RAM type:
5386 *
5387 * 0 == DDR1, 1 == DDR2, 2..7 == reserved?
5388 *
5389 * The code seems to written so that regb should equal ramtype,
5390 * however, so far it has been hardcoded to 0. Enable other values only
5391 * on XGI Z9, as it passes the POST, and add a warning for others.
5392 */
5393 ramtype = sisfb_post_xgi_ramtype(ivideo);
5394 if (!sisfb_xgi_is21(ivideo) && ramtype) {
5395 dev_warn(&pdev->dev,
5396 "RAM type something else than expected: %d\n",
5397 ramtype);
5398 regb = 0;
5399 } else {
5400 regb = ramtype;
5401 }
1da177e4 5402
544393fe
TW
5403 v1 = 0xff;
5404 if(ivideo->haveXGIROM) {
5405 v1 = bios[0x140 + regb];
1da177e4 5406 }
44b751bb 5407 SiS_SetReg(SISCR, 0x6d, v1);
1da177e4 5408
544393fe
TW
5409 ptr = cs128;
5410 if(ivideo->haveXGIROM) {
5411 ptr = (const u8 *)&bios[0x128];
1da177e4 5412 }
544393fe 5413 for(i = 0, j = 0; i < 3; i++, j += 8) {
44b751bb 5414 SiS_SetReg(SISCR, 0x68 + i, ptr[j + regb]);
1da177e4
LT
5415 }
5416
544393fe
TW
5417 ptr = cs31a;
5418 ptr2 = cs33a;
5419 if(ivideo->haveXGIROM) {
5420 index = (ivideo->chip == XGI_20) ? 0x31a : 0x3a6;
5421 ptr = (const u8 *)&bios[index];
5422 ptr2 = (const u8 *)&bios[index + 0x20];
1da177e4 5423 }
544393fe
TW
5424 for(i = 0; i < 2; i++) {
5425 if(i == 0) {
5426 regd = le32_to_cpu(((u32 *)ptr)[regb]);
5427 rega = 0x6b;
5428 } else {
5429 regd = le32_to_cpu(((u32 *)ptr2)[regb]);
5430 rega = 0x6e;
5431 }
5432 reg = 0x00;
5433 for(j = 0; j < 16; j++) {
5434 reg &= 0xf3;
5435 if(regd & 0x01) reg |= 0x04;
5436 if(regd & 0x02) reg |= 0x08;
5437 regd >>= 2;
44b751bb 5438 SiS_SetReg(SISCR, rega, reg);
e57d4136
AK
5439 reg = SiS_GetReg(SISCR, rega);
5440 reg = SiS_GetReg(SISCR, rega);
544393fe
TW
5441 reg += 0x10;
5442 }
1da177e4 5443 }
544393fe 5444
667a8b41 5445 SiS_SetRegAND(SISCR, 0x6e, 0xfc);
544393fe
TW
5446
5447 ptr = NULL;
5448 if(ivideo->haveXGIROM) {
5449 index = (ivideo->chip == XGI_20) ? 0x35a : 0x3e6;
5450 ptr = (const u8 *)&bios[index];
1da177e4 5451 }
544393fe 5452 for(i = 0; i < 4; i++) {
ad78adb4 5453 SiS_SetRegANDOR(SISCR, 0x6e, 0xfc, i);
544393fe
TW
5454 reg = 0x00;
5455 for(j = 0; j < 2; j++) {
5456 regd = 0;
5457 if(ptr) {
5458 regd = le32_to_cpu(((u32 *)ptr)[regb * 8]);
5459 ptr += 4;
5460 }
5461 /* reg = 0x00; */
5462 for(k = 0; k < 16; k++) {
5463 reg &= 0xfc;
5464 if(regd & 0x01) reg |= 0x01;
5465 if(regd & 0x02) reg |= 0x02;
5466 regd >>= 2;
44b751bb 5467 SiS_SetReg(SISCR, 0x6f, reg);
e57d4136
AK
5468 reg = SiS_GetReg(SISCR, 0x6f);
5469 reg = SiS_GetReg(SISCR, 0x6f);
544393fe
TW
5470 reg += 0x08;
5471 }
5472 }
1da177e4 5473 }
544393fe
TW
5474
5475 ptr = cs148;
5476 if(ivideo->haveXGIROM) {
5477 ptr = (const u8 *)&bios[0x148];
1da177e4 5478 }
544393fe 5479 for(i = 0, j = 0; i < 2; i++, j += 8) {
44b751bb 5480 SiS_SetReg(SISCR, 0x80 + i, ptr[j + regb]);
1da177e4 5481 }
1da177e4 5482
667a8b41 5483 SiS_SetRegAND(SISCR, 0x89, 0x8f);
1da177e4 5484
544393fe
TW
5485 ptr = cs45a;
5486 if(ivideo->haveXGIROM) {
5487 index = (ivideo->chip == XGI_20) ? 0x45a : 0x4e6;
5488 ptr = (const u8 *)&bios[index];
5489 }
5490 regd = le16_to_cpu(((const u16 *)ptr)[regb]);
5491 reg = 0x80;
5492 for(i = 0; i < 5; i++) {
5493 reg &= 0xfc;
5494 if(regd & 0x01) reg |= 0x01;
5495 if(regd & 0x02) reg |= 0x02;
5496 regd >>= 2;
44b751bb 5497 SiS_SetReg(SISCR, 0x89, reg);
e57d4136
AK
5498 reg = SiS_GetReg(SISCR, 0x89);
5499 reg = SiS_GetReg(SISCR, 0x89);
544393fe
TW
5500 reg += 0x10;
5501 }
1da177e4 5502
544393fe
TW
5503 v1 = 0xb5; v2 = 0x20; v3 = 0xf0; v4 = 0x13;
5504 if(ivideo->haveXGIROM) {
5505 v1 = bios[0x118 + regb];
5506 v2 = bios[0xf8 + regb];
5507 v3 = bios[0x120 + regb];
5508 v4 = bios[0x1ca];
1da177e4 5509 }
44b751bb
AK
5510 SiS_SetReg(SISCR, 0x45, v1 & 0x0f);
5511 SiS_SetReg(SISCR, 0x99, (v1 >> 4) & 0x07);
27799d6c 5512 SiS_SetRegOR(SISCR, 0x40, v1 & 0x80);
44b751bb 5513 SiS_SetReg(SISCR, 0x41, v2);
544393fe
TW
5514
5515 ptr = cs170;
5516 if(ivideo->haveXGIROM) {
5517 ptr = (const u8 *)&bios[0x170];
1da177e4 5518 }
544393fe 5519 for(i = 0, j = 0; i < 7; i++, j += 8) {
44b751bb 5520 SiS_SetReg(SISCR, 0x90 + i, ptr[j + regb]);
1da177e4
LT
5521 }
5522
44b751bb 5523 SiS_SetReg(SISCR, 0x59, v3);
544393fe
TW
5524
5525 ptr = cs1a8;
5526 if(ivideo->haveXGIROM) {
5527 ptr = (const u8 *)&bios[0x1a8];
5528 }
5529 for(i = 0, j = 0; i < 3; i++, j += 8) {
44b751bb 5530 SiS_SetReg(SISCR, 0xc3 + i, ptr[j + regb]);
1da177e4 5531 }
1da177e4 5532
544393fe
TW
5533 ptr = cs100;
5534 if(ivideo->haveXGIROM) {
5535 ptr = (const u8 *)&bios[0x100];
5536 }
5537 for(i = 0, j = 0; i < 2; i++, j += 8) {
44b751bb 5538 SiS_SetReg(SISCR, 0x8a + i, ptr[j + regb]);
544393fe 5539 }
1da177e4 5540
44b751bb 5541 SiS_SetReg(SISCR, 0xcf, v4);
1da177e4 5542
44b751bb
AK
5543 SiS_SetReg(SISCR, 0x83, 0x09);
5544 SiS_SetReg(SISCR, 0x87, 0x00);
1da177e4 5545
544393fe
TW
5546 if(ivideo->chip == XGI_40) {
5547 if( (ivideo->revision_id == 1) ||
5548 (ivideo->revision_id == 2) ) {
44b751bb 5549 SiS_SetReg(SISCR, 0x8c, 0x87);
544393fe
TW
5550 }
5551 }
1da177e4 5552
42dea903
AK
5553 if (regb == 1)
5554 SiS_SetReg(SISSR, 0x17, 0x80); /* DDR2 */
5555 else
5556 SiS_SetReg(SISSR, 0x17, 0x00); /* DDR1 */
44b751bb 5557 SiS_SetReg(SISSR, 0x1a, 0x87);
1da177e4 5558
544393fe 5559 if(ivideo->chip == XGI_20) {
44b751bb
AK
5560 SiS_SetReg(SISSR, 0x15, 0x00);
5561 SiS_SetReg(SISSR, 0x1c, 0x00);
1da177e4
LT
5562 }
5563
544393fe
TW
5564 switch(ramtype) {
5565 case 0:
5566 sisfb_post_xgi_setclocks(ivideo, regb);
5567 if((ivideo->chip == XGI_20) ||
5568 (ivideo->revision_id == 1) ||
5569 (ivideo->revision_id == 2)) {
5570 v1 = cs158[regb]; v2 = cs160[regb]; v3 = cs168[regb];
5571 if(ivideo->haveXGIROM) {
5572 v1 = bios[regb + 0x158];
5573 v2 = bios[regb + 0x160];
5574 v3 = bios[regb + 0x168];
5575 }
44b751bb
AK
5576 SiS_SetReg(SISCR, 0x82, v1);
5577 SiS_SetReg(SISCR, 0x85, v2);
5578 SiS_SetReg(SISCR, 0x86, v3);
544393fe 5579 } else {
44b751bb
AK
5580 SiS_SetReg(SISCR, 0x82, 0x88);
5581 SiS_SetReg(SISCR, 0x86, 0x00);
e57d4136 5582 reg = SiS_GetReg(SISCR, 0x86);
44b751bb 5583 SiS_SetReg(SISCR, 0x86, 0x88);
e57d4136 5584 reg = SiS_GetReg(SISCR, 0x86);
44b751bb
AK
5585 SiS_SetReg(SISCR, 0x86, bios[regb + 0x168]);
5586 SiS_SetReg(SISCR, 0x82, 0x77);
5587 SiS_SetReg(SISCR, 0x85, 0x00);
e57d4136 5588 reg = SiS_GetReg(SISCR, 0x85);
44b751bb 5589 SiS_SetReg(SISCR, 0x85, 0x88);
e57d4136 5590 reg = SiS_GetReg(SISCR, 0x85);
44b751bb
AK
5591 SiS_SetReg(SISCR, 0x85, bios[regb + 0x160]);
5592 SiS_SetReg(SISCR, 0x82, bios[regb + 0x158]);
544393fe
TW
5593 }
5594 if(ivideo->chip == XGI_40) {
44b751bb 5595 SiS_SetReg(SISCR, 0x97, 0x00);
544393fe 5596 }
44b751bb
AK
5597 SiS_SetReg(SISCR, 0x98, 0x01);
5598 SiS_SetReg(SISCR, 0x9a, 0x02);
1da177e4 5599
44b751bb 5600 SiS_SetReg(SISSR, 0x18, 0x01);
544393fe
TW
5601 if((ivideo->chip == XGI_20) ||
5602 (ivideo->revision_id == 2)) {
44b751bb 5603 SiS_SetReg(SISSR, 0x19, 0x40);
544393fe 5604 } else {
44b751bb 5605 SiS_SetReg(SISSR, 0x19, 0x20);
544393fe 5606 }
44b751bb
AK
5607 SiS_SetReg(SISSR, 0x16, 0x00);
5608 SiS_SetReg(SISSR, 0x16, 0x80);
544393fe
TW
5609 if((ivideo->chip == XGI_20) || (bios[0x1cb] != 0x0c)) {
5610 sisfb_post_xgi_delay(ivideo, 0x43);
5611 sisfb_post_xgi_delay(ivideo, 0x43);
5612 sisfb_post_xgi_delay(ivideo, 0x43);
44b751bb 5613 SiS_SetReg(SISSR, 0x18, 0x00);
544393fe
TW
5614 if((ivideo->chip == XGI_20) ||
5615 (ivideo->revision_id == 2)) {
44b751bb 5616 SiS_SetReg(SISSR, 0x19, 0x40);
544393fe 5617 } else {
44b751bb 5618 SiS_SetReg(SISSR, 0x19, 0x20);
544393fe
TW
5619 }
5620 } else if((ivideo->chip == XGI_40) && (bios[0x1cb] == 0x0c)) {
44b751bb 5621 /* SiS_SetReg(SISSR, 0x16, 0x0c); */ /* ? */
544393fe 5622 }
44b751bb
AK
5623 SiS_SetReg(SISSR, 0x16, 0x00);
5624 SiS_SetReg(SISSR, 0x16, 0x80);
544393fe
TW
5625 sisfb_post_xgi_delay(ivideo, 4);
5626 v1 = 0x31; v2 = 0x03; v3 = 0x83; v4 = 0x03; v5 = 0x83;
5627 if(ivideo->haveXGIROM) {
5628 v1 = bios[0xf0];
5629 index = (ivideo->chip == XGI_20) ? 0x4b2 : 0x53e;
5630 v2 = bios[index];
5631 v3 = bios[index + 1];
5632 v4 = bios[index + 2];
5633 v5 = bios[index + 3];
5634 }
44b751bb
AK
5635 SiS_SetReg(SISSR, 0x18, v1);
5636 SiS_SetReg(SISSR, 0x19, ((ivideo->chip == XGI_20) ? 0x02 : 0x01));
5637 SiS_SetReg(SISSR, 0x16, v2);
5638 SiS_SetReg(SISSR, 0x16, v3);
544393fe 5639 sisfb_post_xgi_delay(ivideo, 0x43);
44b751bb 5640 SiS_SetReg(SISSR, 0x1b, 0x03);
544393fe 5641 sisfb_post_xgi_delay(ivideo, 0x22);
44b751bb
AK
5642 SiS_SetReg(SISSR, 0x18, v1);
5643 SiS_SetReg(SISSR, 0x19, 0x00);
5644 SiS_SetReg(SISSR, 0x16, v4);
5645 SiS_SetReg(SISSR, 0x16, v5);
5646 SiS_SetReg(SISSR, 0x1b, 0x00);
544393fe
TW
5647 break;
5648 case 1:
c9982d59 5649 sisfb_post_xgi_ddr2(ivideo, regb);
544393fe
TW
5650 break;
5651 default:
5652 sisfb_post_xgi_setclocks(ivideo, regb);
5653 if((ivideo->chip == XGI_40) &&
5654 ((ivideo->revision_id == 1) ||
5655 (ivideo->revision_id == 2))) {
44b751bb
AK
5656 SiS_SetReg(SISCR, 0x82, bios[regb + 0x158]);
5657 SiS_SetReg(SISCR, 0x85, bios[regb + 0x160]);
5658 SiS_SetReg(SISCR, 0x86, bios[regb + 0x168]);
544393fe 5659 } else {
44b751bb
AK
5660 SiS_SetReg(SISCR, 0x82, 0x88);
5661 SiS_SetReg(SISCR, 0x86, 0x00);
e57d4136 5662 reg = SiS_GetReg(SISCR, 0x86);
44b751bb
AK
5663 SiS_SetReg(SISCR, 0x86, 0x88);
5664 SiS_SetReg(SISCR, 0x82, 0x77);
5665 SiS_SetReg(SISCR, 0x85, 0x00);
e57d4136 5666 reg = SiS_GetReg(SISCR, 0x85);
44b751bb 5667 SiS_SetReg(SISCR, 0x85, 0x88);
e57d4136 5668 reg = SiS_GetReg(SISCR, 0x85);
544393fe
TW
5669 v1 = cs160[regb]; v2 = cs158[regb];
5670 if(ivideo->haveXGIROM) {
5671 v1 = bios[regb + 0x160];
5672 v2 = bios[regb + 0x158];
5673 }
44b751bb
AK
5674 SiS_SetReg(SISCR, 0x85, v1);
5675 SiS_SetReg(SISCR, 0x82, v2);
544393fe
TW
5676 }
5677 if(ivideo->chip == XGI_40) {
44b751bb 5678 SiS_SetReg(SISCR, 0x97, 0x11);
544393fe
TW
5679 }
5680 if((ivideo->chip == XGI_40) && (ivideo->revision_id == 2)) {
44b751bb 5681 SiS_SetReg(SISCR, 0x98, 0x01);
544393fe 5682 } else {
44b751bb 5683 SiS_SetReg(SISCR, 0x98, 0x03);
544393fe 5684 }
44b751bb 5685 SiS_SetReg(SISCR, 0x9a, 0x02);
1da177e4 5686
544393fe 5687 if(ivideo->chip == XGI_40) {
44b751bb 5688 SiS_SetReg(SISSR, 0x18, 0x01);
544393fe 5689 } else {
44b751bb 5690 SiS_SetReg(SISSR, 0x18, 0x00);
544393fe 5691 }
44b751bb
AK
5692 SiS_SetReg(SISSR, 0x19, 0x40);
5693 SiS_SetReg(SISSR, 0x16, 0x00);
5694 SiS_SetReg(SISSR, 0x16, 0x80);
544393fe
TW
5695 if((ivideo->chip == XGI_40) && (bios[0x1cb] != 0x0c)) {
5696 sisfb_post_xgi_delay(ivideo, 0x43);
5697 sisfb_post_xgi_delay(ivideo, 0x43);
5698 sisfb_post_xgi_delay(ivideo, 0x43);
44b751bb
AK
5699 SiS_SetReg(SISSR, 0x18, 0x00);
5700 SiS_SetReg(SISSR, 0x19, 0x40);
5701 SiS_SetReg(SISSR, 0x16, 0x00);
5702 SiS_SetReg(SISSR, 0x16, 0x80);
544393fe
TW
5703 }
5704 sisfb_post_xgi_delay(ivideo, 4);
5705 v1 = 0x31;
5706 if(ivideo->haveXGIROM) {
5707 v1 = bios[0xf0];
5708 }
44b751bb
AK
5709 SiS_SetReg(SISSR, 0x18, v1);
5710 SiS_SetReg(SISSR, 0x19, 0x01);
544393fe 5711 if(ivideo->chip == XGI_40) {
44b751bb
AK
5712 SiS_SetReg(SISSR, 0x16, bios[0x53e]);
5713 SiS_SetReg(SISSR, 0x16, bios[0x53f]);
544393fe 5714 } else {
44b751bb
AK
5715 SiS_SetReg(SISSR, 0x16, 0x05);
5716 SiS_SetReg(SISSR, 0x16, 0x85);
544393fe
TW
5717 }
5718 sisfb_post_xgi_delay(ivideo, 0x43);
5719 if(ivideo->chip == XGI_40) {
44b751bb 5720 SiS_SetReg(SISSR, 0x1b, 0x01);
544393fe 5721 } else {
44b751bb 5722 SiS_SetReg(SISSR, 0x1b, 0x03);
544393fe
TW
5723 }
5724 sisfb_post_xgi_delay(ivideo, 0x22);
44b751bb
AK
5725 SiS_SetReg(SISSR, 0x18, v1);
5726 SiS_SetReg(SISSR, 0x19, 0x00);
544393fe 5727 if(ivideo->chip == XGI_40) {
44b751bb
AK
5728 SiS_SetReg(SISSR, 0x16, bios[0x540]);
5729 SiS_SetReg(SISSR, 0x16, bios[0x541]);
544393fe 5730 } else {
44b751bb
AK
5731 SiS_SetReg(SISSR, 0x16, 0x05);
5732 SiS_SetReg(SISSR, 0x16, 0x85);
544393fe 5733 }
44b751bb 5734 SiS_SetReg(SISSR, 0x1b, 0x00);
1da177e4 5735 }
1da177e4 5736
544393fe
TW
5737 regb = 0; /* ! */
5738 v1 = 0x03;
5739 if(ivideo->haveXGIROM) {
5740 v1 = bios[0x110 + regb];
1da177e4 5741 }
44b751bb 5742 SiS_SetReg(SISSR, 0x1b, v1);
1da177e4 5743
544393fe
TW
5744 /* RAM size */
5745 v1 = 0x00; v2 = 0x00;
5746 if(ivideo->haveXGIROM) {
5747 v1 = bios[0x62];
5748 v2 = bios[0x63];
1da177e4 5749 }
544393fe
TW
5750 regb = 0; /* ! */
5751 regd = 1 << regb;
5752 if((v1 & 0x40) && (v2 & regd) && ivideo->haveXGIROM) {
1da177e4 5753
44b751bb
AK
5754 SiS_SetReg(SISSR, 0x13, bios[regb + 0xe0]);
5755 SiS_SetReg(SISSR, 0x14, bios[regb + 0xe0 + 8]);
1da177e4 5756
544393fe 5757 } else {
83ea0f16 5758 int err;
1da177e4 5759
544393fe 5760 /* Set default mode, don't clear screen */
c30660ea
RK
5761 ivideo->SiS_Pr.SiS_UseOEM = false;
5762 SiS_SetEnableDstn(&ivideo->SiS_Pr, false);
5763 SiS_SetEnableFstn(&ivideo->SiS_Pr, false);
544393fe
TW
5764 ivideo->curFSTN = ivideo->curDSTN = 0;
5765 ivideo->SiS_Pr.VideoMemorySize = 8 << 20;
5766 SiSSetMode(&ivideo->SiS_Pr, 0x2e | 0x80);
1da177e4 5767
44b751bb 5768 SiS_SetReg(SISSR, 0x05, 0x86);
1da177e4 5769
544393fe 5770 /* Disable read-cache */
667a8b41 5771 SiS_SetRegAND(SISSR, 0x21, 0xdf);
83ea0f16 5772 err = sisfb_post_xgi_ramsize(ivideo);
544393fe 5773 /* Enable read-cache */
27799d6c 5774 SiS_SetRegOR(SISSR, 0x21, 0x20);
1da177e4 5775
83ea0f16
AK
5776 if (err) {
5777 dev_err(&pdev->dev,
5778 "%s: RAM size detection failed: %d\n",
5779 __func__, err);
5780 return 0;
5781 }
544393fe 5782 }
1da177e4 5783
544393fe
TW
5784#if 0
5785 printk(KERN_DEBUG "-----------------\n");
5786 for(i = 0; i < 0xff; i++) {
e57d4136 5787 reg = SiS_GetReg(SISCR, i);
544393fe
TW
5788 printk(KERN_DEBUG "CR%02x(%x) = 0x%02x\n", i, SISCR, reg);
5789 }
5790 for(i = 0; i < 0x40; i++) {
e57d4136 5791 reg = SiS_GetReg(SISSR, i);
544393fe
TW
5792 printk(KERN_DEBUG "SR%02x(%x) = 0x%02x\n", i, SISSR, reg);
5793 }
5794 printk(KERN_DEBUG "-----------------\n");
5795#endif
1da177e4 5796
544393fe
TW
5797 /* Sense CRT1 */
5798 if(ivideo->chip == XGI_20) {
27799d6c 5799 SiS_SetRegOR(SISCR, 0x32, 0x20);
1da177e4 5800 } else {
e57d4136 5801 reg = SiS_GetReg(SISPART4, 0x00);
544393fe
TW
5802 if((reg == 1) || (reg == 2)) {
5803 sisfb_sense_crt1(ivideo);
5804 } else {
27799d6c 5805 SiS_SetRegOR(SISCR, 0x32, 0x20);
544393fe 5806 }
1da177e4
LT
5807 }
5808
544393fe 5809 /* Set default mode, don't clear screen */
c30660ea
RK
5810 ivideo->SiS_Pr.SiS_UseOEM = false;
5811 SiS_SetEnableDstn(&ivideo->SiS_Pr, false);
5812 SiS_SetEnableFstn(&ivideo->SiS_Pr, false);
544393fe
TW
5813 ivideo->curFSTN = ivideo->curDSTN = 0;
5814 SiSSetMode(&ivideo->SiS_Pr, 0x2e | 0x80);
5815
44b751bb 5816 SiS_SetReg(SISSR, 0x05, 0x86);
544393fe
TW
5817
5818 /* Display off */
27799d6c 5819 SiS_SetRegOR(SISSR, 0x01, 0x20);
544393fe
TW
5820
5821 /* Save mode number in CR34 */
44b751bb 5822 SiS_SetReg(SISCR, 0x34, 0x2e);
544393fe
TW
5823
5824 /* Let everyone know what the current mode is */
5825 ivideo->modeprechange = 0x2e;
5826
5827 if(ivideo->chip == XGI_40) {
e57d4136
AK
5828 reg = SiS_GetReg(SISCR, 0xca);
5829 v1 = SiS_GetReg(SISCR, 0xcc);
544393fe
TW
5830 if((reg & 0x10) && (!(v1 & 0x04))) {
5831 printk(KERN_ERR
5832 "sisfb: Please connect power to the card.\n");
5833 return 0;
5834 }
1da177e4 5835 }
1da177e4 5836
544393fe 5837 return 1;
1da177e4
LT
5838}
5839#endif
5840
48c68c4f 5841static int sisfb_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
1da177e4 5842{
544393fe
TW
5843 struct sisfb_chip_info *chipinfo = &sisfb_chip_info[ent->driver_data];
5844 struct sis_video_info *ivideo = NULL;
5845 struct fb_info *sis_fb_info = NULL;
1da177e4
LT
5846 u16 reg16;
5847 u8 reg;
544393fe 5848 int i, ret;
1da177e4 5849
544393fe
TW
5850 if(sisfb_off)
5851 return -ENXIO;
1da177e4 5852
1da177e4 5853 sis_fb_info = framebuffer_alloc(sizeof(*ivideo), &pdev->dev);
544393fe
TW
5854 if(!sis_fb_info)
5855 return -ENOMEM;
1da177e4
LT
5856
5857 ivideo = (struct sis_video_info *)sis_fb_info->par;
5858 ivideo->memyselfandi = sis_fb_info;
5859
544393fe
TW
5860 ivideo->sisfb_id = SISFB_ID;
5861
1da177e4 5862 if(card_list == NULL) {
544393fe 5863 ivideo->cardnumber = 0;
1da177e4 5864 } else {
544393fe
TW
5865 struct sis_video_info *countvideo = card_list;
5866 ivideo->cardnumber = 1;
5e2daeb3 5867 while((countvideo = countvideo->next) != NULL)
544393fe 5868 ivideo->cardnumber++;
1da177e4
LT
5869 }
5870
b232e94d 5871 strlcpy(ivideo->myid, chipinfo->chip_name, sizeof(ivideo->myid));
1da177e4
LT
5872
5873 ivideo->warncount = 0;
5874 ivideo->chip_id = pdev->device;
544393fe 5875 ivideo->chip_vendor = pdev->vendor;
44c10138 5876 ivideo->revision_id = pdev->revision;
544393fe 5877 ivideo->SiS_Pr.ChipRevision = ivideo->revision_id;
1da177e4 5878 pci_read_config_word(pdev, PCI_COMMAND, &reg16);
544393fe 5879 ivideo->sisvga_enabled = reg16 & 0x01;
1da177e4
LT
5880 ivideo->pcibus = pdev->bus->number;
5881 ivideo->pcislot = PCI_SLOT(pdev->devfn);
5882 ivideo->pcifunc = PCI_FUNC(pdev->devfn);
5883 ivideo->subsysvendor = pdev->subsystem_vendor;
5884 ivideo->subsysdevice = pdev->subsystem_device;
5885
5886#ifndef MODULE
5887 if(sisfb_mode_idx == -1) {
5888 sisfb_get_vga_mode_from_kernel();
5889 }
5890#endif
5891
5892 ivideo->chip = chipinfo->chip;
929c972e 5893 ivideo->chip_real_id = chipinfo->chip;
1da177e4
LT
5894 ivideo->sisvga_engine = chipinfo->vgaengine;
5895 ivideo->hwcursor_size = chipinfo->hwcursor_size;
5896 ivideo->CRT2_write_enable = chipinfo->CRT2_write_enable;
5897 ivideo->mni = chipinfo->mni;
5898
5899 ivideo->detectedpdc = 0xff;
5900 ivideo->detectedpdca = 0xff;
5901 ivideo->detectedlcda = 0xff;
5902
c30660ea 5903 ivideo->sisfb_thismonitor.datavalid = false;
1da177e4 5904
544393fe
TW
5905 ivideo->current_base = 0;
5906
5907 ivideo->engineok = 0;
5908
5909 ivideo->sisfb_was_boot_device = 0;
14aefd1b 5910
544393fe
TW
5911 if(pdev->resource[PCI_ROM_RESOURCE].flags & IORESOURCE_ROM_SHADOW) {
5912 if(ivideo->sisvga_enabled)
5913 ivideo->sisfb_was_boot_device = 1;
5914 else {
5915 printk(KERN_DEBUG "sisfb: PCI device is disabled, "
5916 "but marked as boot video device ???\n");
5917 printk(KERN_DEBUG "sisfb: I will not accept this "
5918 "as the primary VGA device\n");
5919 }
5920 }
544393fe 5921
1da177e4
LT
5922 ivideo->sisfb_parm_mem = sisfb_parm_mem;
5923 ivideo->sisfb_accel = sisfb_accel;
5924 ivideo->sisfb_ypan = sisfb_ypan;
5925 ivideo->sisfb_max = sisfb_max;
5926 ivideo->sisfb_userom = sisfb_userom;
5927 ivideo->sisfb_useoem = sisfb_useoem;
5928 ivideo->sisfb_mode_idx = sisfb_mode_idx;
5929 ivideo->sisfb_parm_rate = sisfb_parm_rate;
5930 ivideo->sisfb_crt1off = sisfb_crt1off;
5931 ivideo->sisfb_forcecrt1 = sisfb_forcecrt1;
5932 ivideo->sisfb_crt2type = sisfb_crt2type;
5933 ivideo->sisfb_crt2flags = sisfb_crt2flags;
5934 /* pdc(a), scalelcd, special timing, lvdshl handled below */
5935 ivideo->sisfb_dstn = sisfb_dstn;
5936 ivideo->sisfb_fstn = sisfb_fstn;
5937 ivideo->sisfb_tvplug = sisfb_tvplug;
5938 ivideo->sisfb_tvstd = sisfb_tvstd;
5939 ivideo->tvxpos = sisfb_tvxposoffset;
5940 ivideo->tvypos = sisfb_tvyposoffset;
1da177e4 5941 ivideo->sisfb_nocrt2rate = sisfb_nocrt2rate;
1da177e4
LT
5942 ivideo->refresh_rate = 0;
5943 if(ivideo->sisfb_parm_rate != -1) {
544393fe 5944 ivideo->refresh_rate = ivideo->sisfb_parm_rate;
1da177e4
LT
5945 }
5946
5947 ivideo->SiS_Pr.UsePanelScaler = sisfb_scalelcd;
5948 ivideo->SiS_Pr.CenterScreen = -1;
5949 ivideo->SiS_Pr.SiS_CustomT = sisfb_specialtiming;
5950 ivideo->SiS_Pr.LVDSHL = sisfb_lvdshl;
5951
5952 ivideo->SiS_Pr.SiS_Backup70xx = 0xff;
544393fe 5953 ivideo->SiS_Pr.SiS_CHOverScan = -1;
c30660ea
RK
5954 ivideo->SiS_Pr.SiS_ChSW = false;
5955 ivideo->SiS_Pr.SiS_UseLCDA = false;
5956 ivideo->SiS_Pr.HaveEMI = false;
5957 ivideo->SiS_Pr.HaveEMILCD = false;
5958 ivideo->SiS_Pr.OverruleEMI = false;
5959 ivideo->SiS_Pr.SiS_SensibleSR11 = false;
1da177e4
LT
5960 ivideo->SiS_Pr.SiS_MyCR63 = 0x63;
5961 ivideo->SiS_Pr.PDC = -1;
5962 ivideo->SiS_Pr.PDCA = -1;
c30660ea 5963 ivideo->SiS_Pr.DDCPortMixup = false;
1da177e4
LT
5964#ifdef CONFIG_FB_SIS_315
5965 if(ivideo->chip >= SIS_330) {
544393fe
TW
5966 ivideo->SiS_Pr.SiS_MyCR63 = 0x53;
5967 if(ivideo->chip >= SIS_661) {
c30660ea 5968 ivideo->SiS_Pr.SiS_SensibleSR11 = true;
544393fe 5969 }
1da177e4
LT
5970 }
5971#endif
5972
5973 memcpy(&ivideo->default_var, &my_default_var, sizeof(my_default_var));
5974
5975 pci_set_drvdata(pdev, ivideo);
5976
5977 /* Patch special cases */
5978 if((ivideo->nbridge = sisfb_get_northbridge(ivideo->chip))) {
5979 switch(ivideo->nbridge->device) {
5980#ifdef CONFIG_FB_SIS_300
5981 case PCI_DEVICE_ID_SI_730:
544393fe 5982 ivideo->chip = SIS_730;
1da177e4 5983 strcpy(ivideo->myid, "SiS 730");
544393fe 5984 break;
1da177e4
LT
5985#endif
5986#ifdef CONFIG_FB_SIS_315
5987 case PCI_DEVICE_ID_SI_651:
5988 /* ivideo->chip is ok */
5989 strcpy(ivideo->myid, "SiS 651");
5990 break;
5991 case PCI_DEVICE_ID_SI_740:
544393fe 5992 ivideo->chip = SIS_740;
1da177e4
LT
5993 strcpy(ivideo->myid, "SiS 740");
5994 break;
5995 case PCI_DEVICE_ID_SI_661:
544393fe 5996 ivideo->chip = SIS_661;
1da177e4
LT
5997 strcpy(ivideo->myid, "SiS 661");
5998 break;
5999 case PCI_DEVICE_ID_SI_741:
544393fe 6000 ivideo->chip = SIS_741;
1da177e4
LT
6001 strcpy(ivideo->myid, "SiS 741");
6002 break;
6003 case PCI_DEVICE_ID_SI_760:
544393fe 6004 ivideo->chip = SIS_760;
1da177e4
LT
6005 strcpy(ivideo->myid, "SiS 760");
6006 break;
544393fe
TW
6007 case PCI_DEVICE_ID_SI_761:
6008 ivideo->chip = SIS_761;
6009 strcpy(ivideo->myid, "SiS 761");
6010 break;
1da177e4 6011#endif
544393fe
TW
6012 default:
6013 break;
1da177e4
LT
6014 }
6015 }
6016
544393fe
TW
6017 ivideo->SiS_Pr.ChipType = ivideo->chip;
6018
6019 ivideo->SiS_Pr.ivideo = (void *)ivideo;
1da177e4
LT
6020
6021#ifdef CONFIG_FB_SIS_315
544393fe
TW
6022 if((ivideo->SiS_Pr.ChipType == SIS_315PRO) ||
6023 (ivideo->SiS_Pr.ChipType == SIS_315)) {
6024 ivideo->SiS_Pr.ChipType = SIS_315H;
1da177e4
LT
6025 }
6026#endif
6027
544393fe
TW
6028 if(!ivideo->sisvga_enabled) {
6029 if(pci_enable_device(pdev)) {
6049a7a2 6030 pci_dev_put(ivideo->nbridge);
491bcc9b 6031 framebuffer_release(sis_fb_info);
544393fe
TW
6032 return -EIO;
6033 }
6034 }
6035
1da177e4 6036 ivideo->video_base = pci_resource_start(pdev, 0);
32ed3036 6037 ivideo->video_size = pci_resource_len(pdev, 0);
1da177e4
LT
6038 ivideo->mmio_base = pci_resource_start(pdev, 1);
6039 ivideo->mmio_size = pci_resource_len(pdev, 1);
544393fe
TW
6040 ivideo->SiS_Pr.RelIO = pci_resource_start(pdev, 2) + 0x30;
6041 ivideo->SiS_Pr.IOAddress = ivideo->vga_base = ivideo->SiS_Pr.RelIO;
1da177e4 6042
544393fe 6043 SiSRegInit(&ivideo->SiS_Pr, ivideo->SiS_Pr.IOAddress);
1da177e4
LT
6044
6045#ifdef CONFIG_FB_SIS_300
6046 /* Find PCI systems for Chrontel/GPIO communication setup */
6047 if(ivideo->chip == SIS_630) {
544393fe
TW
6048 i = 0;
6049 do {
6050 if(mychswtable[i].subsysVendor == ivideo->subsysvendor &&
6051 mychswtable[i].subsysCard == ivideo->subsysdevice) {
c30660ea 6052 ivideo->SiS_Pr.SiS_ChSW = true;
544393fe
TW
6053 printk(KERN_DEBUG "sisfb: Identified [%s %s] "
6054 "requiring Chrontel/GPIO setup\n",
6055 mychswtable[i].vendorName,
6056 mychswtable[i].cardName);
0959f0ca 6057 ivideo->lpcdev = pci_get_device(PCI_VENDOR_ID_SI, 0x0008, NULL);
544393fe
TW
6058 break;
6059 }
6060 i++;
6061 } while(mychswtable[i].subsysVendor != 0);
6062 }
6063#endif
6064
6065#ifdef CONFIG_FB_SIS_315
6066 if((ivideo->chip == SIS_760) && (ivideo->nbridge)) {
0959f0ca 6067 ivideo->lpcdev = pci_get_slot(ivideo->nbridge->bus, (2 << 3));
1da177e4
LT
6068 }
6069#endif
6070
44b751bb 6071 SiS_SetReg(SISSR, 0x05, 0x86);
1da177e4 6072
544393fe 6073 if( (!ivideo->sisvga_enabled)
1da177e4 6074#if !defined(__i386__) && !defined(__x86_64__)
544393fe 6075 || (sisfb_resetcard)
1da177e4 6076#endif
544393fe
TW
6077 ) {
6078 for(i = 0x30; i <= 0x3f; i++) {
44b751bb 6079 SiS_SetReg(SISCR, i, 0x00);
544393fe 6080 }
1da177e4
LT
6081 }
6082
6083 /* Find out about current video mode */
6084 ivideo->modeprechange = 0x03;
e57d4136 6085 reg = SiS_GetReg(SISCR, 0x34);
1da177e4
LT
6086 if(reg & 0x7f) {
6087 ivideo->modeprechange = reg & 0x7f;
544393fe 6088 } else if(ivideo->sisvga_enabled) {
1da177e4 6089#if defined(__i386__) || defined(__x86_64__)
14aefd1b 6090 unsigned char __iomem *tt = ioremap(0x400, 0x100);
1da177e4 6091 if(tt) {
544393fe
TW
6092 ivideo->modeprechange = readb(tt + 0x49);
6093 iounmap(tt);
1da177e4
LT
6094 }
6095#endif
6096 }
6097
544393fe 6098 /* Search and copy ROM image */
1da177e4 6099 ivideo->bios_abase = NULL;
544393fe 6100 ivideo->SiS_Pr.VirtualRomBase = NULL;
c30660ea
RK
6101 ivideo->SiS_Pr.UseROM = false;
6102 ivideo->haveXGIROM = ivideo->SiS_Pr.SiS_XGIROM = false;
1da177e4 6103 if(ivideo->sisfb_userom) {
544393fe
TW
6104 ivideo->SiS_Pr.VirtualRomBase = sisfb_find_rom(pdev);
6105 ivideo->bios_abase = ivideo->SiS_Pr.VirtualRomBase;
c30660ea 6106 ivideo->SiS_Pr.UseROM = (bool)(ivideo->SiS_Pr.VirtualRomBase);
544393fe
TW
6107 printk(KERN_INFO "sisfb: Video ROM %sfound\n",
6108 ivideo->SiS_Pr.UseROM ? "" : "not ");
6109 if((ivideo->SiS_Pr.UseROM) && (ivideo->chip >= XGI_20)) {
c30660ea
RK
6110 ivideo->SiS_Pr.UseROM = false;
6111 ivideo->haveXGIROM = ivideo->SiS_Pr.SiS_XGIROM = true;
544393fe
TW
6112 if( (ivideo->revision_id == 2) &&
6113 (!(ivideo->bios_abase[0x1d1] & 0x01)) ) {
c30660ea 6114 ivideo->SiS_Pr.DDCPortMixup = true;
544393fe
TW
6115 }
6116 }
1da177e4 6117 } else {
544393fe 6118 printk(KERN_INFO "sisfb: Video ROM usage disabled\n");
1da177e4
LT
6119 }
6120
544393fe 6121 /* Find systems for special custom timing */
1da177e4 6122 if(ivideo->SiS_Pr.SiS_CustomT == CUT_NONE) {
544393fe 6123 sisfb_detect_custom_timing(ivideo);
1da177e4
LT
6124 }
6125
929c972e
AK
6126#ifdef CONFIG_FB_SIS_315
6127 if (ivideo->chip == XGI_20) {
6128 /* Check if our Z7 chip is actually Z9 */
6129 SiS_SetRegOR(SISCR, 0x4a, 0x40); /* GPIOG EN */
6130 reg = SiS_GetReg(SISCR, 0x48);
6131 if (reg & 0x02) { /* GPIOG */
6132 ivideo->chip_real_id = XGI_21;
6133 dev_info(&pdev->dev, "Z9 detected\n");
6134 }
6135 }
6136#endif
6137
544393fe
TW
6138 /* POST card in case this has not been done by the BIOS */
6139 if( (!ivideo->sisvga_enabled)
1da177e4 6140#if !defined(__i386__) && !defined(__x86_64__)
544393fe 6141 || (sisfb_resetcard)
1da177e4 6142#endif
544393fe
TW
6143 ) {
6144#ifdef CONFIG_FB_SIS_300
6145 if(ivideo->sisvga_engine == SIS_300_VGA) {
1da177e4
LT
6146 if(ivideo->chip == SIS_300) {
6147 sisfb_post_sis300(pdev);
544393fe 6148 ivideo->sisfb_can_post = 1;
1da177e4
LT
6149 }
6150 }
1da177e4
LT
6151#endif
6152
6153#ifdef CONFIG_FB_SIS_315
544393fe
TW
6154 if(ivideo->sisvga_engine == SIS_315_VGA) {
6155 int result = 1;
6156 /* if((ivideo->chip == SIS_315H) ||
1da177e4
LT
6157 (ivideo->chip == SIS_315) ||
6158 (ivideo->chip == SIS_315PRO) ||
6159 (ivideo->chip == SIS_330)) {
6160 sisfb_post_sis315330(pdev);
544393fe
TW
6161 } else */ if(ivideo->chip == XGI_20) {
6162 result = sisfb_post_xgi(pdev);
6163 ivideo->sisfb_can_post = 1;
6164 } else if((ivideo->chip == XGI_40) && ivideo->haveXGIROM) {
6165 result = sisfb_post_xgi(pdev);
6166 ivideo->sisfb_can_post = 1;
6167 } else {
6168 printk(KERN_INFO "sisfb: Card is not "
6169 "POSTed and sisfb can't do this either.\n");
6170 }
6171 if(!result) {
6172 printk(KERN_ERR "sisfb: Failed to POST card\n");
6173 ret = -ENODEV;
6174 goto error_3;
1da177e4
LT
6175 }
6176 }
1da177e4 6177#endif
544393fe 6178 }
1da177e4 6179
544393fe
TW
6180 ivideo->sisfb_card_posted = 1;
6181
6182 /* Find out about RAM size */
1da177e4 6183 if(sisfb_get_dram_size(ivideo)) {
544393fe
TW
6184 printk(KERN_INFO "sisfb: Fatal error: Unable to determine VRAM size.\n");
6185 ret = -ENODEV;
6186 goto error_3;
1da177e4
LT
6187 }
6188
544393fe
TW
6189
6190 /* Enable PCI addressing and MMIO */
1da177e4
LT
6191 if((ivideo->sisfb_mode_idx < 0) ||
6192 ((sisbios_mode[ivideo->sisfb_mode_idx].mode_no[ivideo->mni]) != 0xFF)) {
544393fe 6193 /* Enable PCI_LINEAR_ADDRESSING and MMIO_ENABLE */
27799d6c 6194 SiS_SetRegOR(SISSR, IND_SIS_PCI_ADDRESS_SET, (SIS_PCI_ADDR_ENABLE | SIS_MEM_MAP_IO_ENABLE));
544393fe 6195 /* Enable 2D accelerator engine */
27799d6c 6196 SiS_SetRegOR(SISSR, IND_SIS_MODULE_ENABLE, SIS_ENABLE_2D);
1da177e4
LT
6197 }
6198
6199 if(sisfb_pdc != 0xff) {
544393fe
TW
6200 if(ivideo->sisvga_engine == SIS_300_VGA)
6201 sisfb_pdc &= 0x3c;
6202 else
6203 sisfb_pdc &= 0x1f;
6204 ivideo->SiS_Pr.PDC = sisfb_pdc;
1da177e4
LT
6205 }
6206#ifdef CONFIG_FB_SIS_315
6207 if(ivideo->sisvga_engine == SIS_315_VGA) {
544393fe
TW
6208 if(sisfb_pdca != 0xff)
6209 ivideo->SiS_Pr.PDCA = sisfb_pdca & 0x1f;
1da177e4
LT
6210 }
6211#endif
6212
6213 if(!request_mem_region(ivideo->video_base, ivideo->video_size, "sisfb FB")) {
544393fe
TW
6214 printk(KERN_ERR "sisfb: Fatal error: Unable to reserve %dMB framebuffer memory\n",
6215 (int)(ivideo->video_size >> 20));
1da177e4 6216 printk(KERN_ERR "sisfb: Is there another framebuffer driver active?\n");
544393fe
TW
6217 ret = -ENODEV;
6218 goto error_3;
1da177e4
LT
6219 }
6220
6221 if(!request_mem_region(ivideo->mmio_base, ivideo->mmio_size, "sisfb MMIO")) {
6222 printk(KERN_ERR "sisfb: Fatal error: Unable to reserve MMIO region\n");
544393fe
TW
6223 ret = -ENODEV;
6224 goto error_2;
1da177e4
LT
6225 }
6226
2cff6406 6227 ivideo->video_vbase = ioremap_wc(ivideo->video_base, ivideo->video_size);
544393fe 6228 ivideo->SiS_Pr.VideoMemoryAddress = ivideo->video_vbase;
1da177e4 6229 if(!ivideo->video_vbase) {
544393fe
TW
6230 printk(KERN_ERR "sisfb: Fatal error: Unable to map framebuffer memory\n");
6231 ret = -ENODEV;
6232 goto error_1;
1da177e4
LT
6233 }
6234
6235 ivideo->mmio_vbase = ioremap(ivideo->mmio_base, ivideo->mmio_size);
6236 if(!ivideo->mmio_vbase) {
544393fe
TW
6237 printk(KERN_ERR "sisfb: Fatal error: Unable to map MMIO region\n");
6238 ret = -ENODEV;
6239error_0: iounmap(ivideo->video_vbase);
6240error_1: release_mem_region(ivideo->video_base, ivideo->video_size);
6241error_2: release_mem_region(ivideo->mmio_base, ivideo->mmio_size);
6242error_3: vfree(ivideo->bios_abase);
6049a7a2
ME
6243 pci_dev_put(ivideo->lpcdev);
6244 pci_dev_put(ivideo->nbridge);
544393fe
TW
6245 if(!ivideo->sisvga_enabled)
6246 pci_disable_device(pdev);
491bcc9b 6247 framebuffer_release(sis_fb_info);
544393fe 6248 return ret;
1da177e4
LT
6249 }
6250
544393fe
TW
6251 printk(KERN_INFO "sisfb: Video RAM at 0x%lx, mapped to 0x%lx, size %ldk\n",
6252 ivideo->video_base, (unsigned long)ivideo->video_vbase, ivideo->video_size / 1024);
6253
6254 if(ivideo->video_offset) {
6255 printk(KERN_INFO "sisfb: Viewport offset %ldk\n",
6256 ivideo->video_offset / 1024);
6257 }
1da177e4
LT
6258
6259 printk(KERN_INFO "sisfb: MMIO at 0x%lx, mapped to 0x%lx, size %ldk\n",
544393fe
TW
6260 ivideo->mmio_base, (unsigned long)ivideo->mmio_vbase, ivideo->mmio_size / 1024);
6261
6262
6263 /* Determine the size of the command queue */
6264 if(ivideo->sisvga_engine == SIS_300_VGA) {
6265 ivideo->cmdQueueSize = TURBO_QUEUE_AREA_SIZE;
6266 } else {
6267 if(ivideo->chip == XGI_20) {
6268 ivideo->cmdQueueSize = COMMAND_QUEUE_AREA_SIZE_Z7;
6269 } else {
6270 ivideo->cmdQueueSize = COMMAND_QUEUE_AREA_SIZE;
6271 }
6272 }
1da177e4 6273
544393fe
TW
6274 /* Engines are no longer initialized here; this is
6275 * now done after the first mode-switch (if the
6276 * submitted var has its acceleration flags set).
6277 */
6278
6279 /* Calculate the base of the (unused) hw cursor */
6280 ivideo->hwcursor_vbase = ivideo->video_vbase
6281 + ivideo->video_size
6282 - ivideo->cmdQueueSize
6283 - ivideo->hwcursor_size;
6284 ivideo->caps |= HW_CURSOR_CAP;
6285
6286 /* Initialize offscreen memory manager */
1da177e4
LT
6287 if((ivideo->havenoheap = sisfb_heap_init(ivideo))) {
6288 printk(KERN_WARNING "sisfb: Failed to initialize offscreen memory heap\n");
6289 }
6290
6291 /* Used for clearing the screen only, therefore respect our mem limit */
544393fe
TW
6292 ivideo->SiS_Pr.VideoMemoryAddress += ivideo->video_offset;
6293 ivideo->SiS_Pr.VideoMemorySize = ivideo->sisfb_mem;
1da177e4 6294
1da177e4
LT
6295 ivideo->vbflags = 0;
6296 ivideo->lcddefmodeidx = DEFAULT_LCDMODE;
6297 ivideo->tvdefmodeidx = DEFAULT_TVMODE;
6298 ivideo->defmodeidx = DEFAULT_MODE;
6299
544393fe
TW
6300 ivideo->newrom = 0;
6301 if(ivideo->chip < XGI_20) {
6302 if(ivideo->bios_abase) {
6303 ivideo->newrom = SiSDetermineROMLayout661(&ivideo->SiS_Pr);
6304 }
6305 }
1da177e4
LT
6306
6307 if((ivideo->sisfb_mode_idx < 0) ||
6308 ((sisbios_mode[ivideo->sisfb_mode_idx].mode_no[ivideo->mni]) != 0xFF)) {
6309
6310 sisfb_sense_crt1(ivideo);
6311
6312 sisfb_get_VB_type(ivideo);
6313
544393fe 6314 if(ivideo->vbflags2 & VB2_VIDEOBRIDGE) {
1da177e4
LT
6315 sisfb_detect_VB_connect(ivideo);
6316 }
6317
6318 ivideo->currentvbflags = ivideo->vbflags & (VB_VIDEOBRIDGE | TV_STANDARD);
6319
544393fe
TW
6320 /* Decide on which CRT2 device to use */
6321 if(ivideo->vbflags2 & VB2_VIDEOBRIDGE) {
6322 if(ivideo->sisfb_crt2type != -1) {
6323 if((ivideo->sisfb_crt2type == CRT2_LCD) &&
6324 (ivideo->vbflags & CRT2_LCD)) {
6325 ivideo->currentvbflags |= CRT2_LCD;
6326 } else if(ivideo->sisfb_crt2type != CRT2_LCD) {
6327 ivideo->currentvbflags |= ivideo->sisfb_crt2type;
6328 }
6329 } else {
6330 /* Chrontel 700x TV detection often unreliable, therefore
6331 * use a different default order on such machines
6332 */
6333 if((ivideo->sisvga_engine == SIS_300_VGA) &&
6334 (ivideo->vbflags2 & VB2_CHRONTEL)) {
6335 if(ivideo->vbflags & CRT2_LCD)
6336 ivideo->currentvbflags |= CRT2_LCD;
6337 else if(ivideo->vbflags & CRT2_TV)
6338 ivideo->currentvbflags |= CRT2_TV;
6339 else if(ivideo->vbflags & CRT2_VGA)
6340 ivideo->currentvbflags |= CRT2_VGA;
6341 } else {
6342 if(ivideo->vbflags & CRT2_TV)
6343 ivideo->currentvbflags |= CRT2_TV;
6344 else if(ivideo->vbflags & CRT2_LCD)
6345 ivideo->currentvbflags |= CRT2_LCD;
6346 else if(ivideo->vbflags & CRT2_VGA)
6347 ivideo->currentvbflags |= CRT2_VGA;
6348 }
6349 }
1da177e4
LT
6350 }
6351
6352 if(ivideo->vbflags & CRT2_LCD) {
544393fe 6353 sisfb_detect_lcd_type(ivideo);
1da177e4 6354 }
1da177e4 6355
544393fe 6356 sisfb_save_pdc_emi(ivideo);
1da177e4
LT
6357
6358 if(!ivideo->sisfb_crt1off) {
544393fe 6359 sisfb_handle_ddc(ivideo, &ivideo->sisfb_thismonitor, 0);
1da177e4 6360 } else {
544393fe
TW
6361 if((ivideo->vbflags2 & VB2_SISTMDSBRIDGE) &&
6362 (ivideo->vbflags & (CRT2_VGA | CRT2_LCD))) {
6363 sisfb_handle_ddc(ivideo, &ivideo->sisfb_thismonitor, 1);
6364 }
1da177e4
LT
6365 }
6366
6367 if(ivideo->sisfb_mode_idx >= 0) {
6368 int bu = ivideo->sisfb_mode_idx;
6369 ivideo->sisfb_mode_idx = sisfb_validate_mode(ivideo,
6370 ivideo->sisfb_mode_idx, ivideo->currentvbflags);
6371 if(bu != ivideo->sisfb_mode_idx) {
6372 printk(KERN_ERR "Mode %dx%dx%d failed validation\n",
6373 sisbios_mode[bu].xres,
6374 sisbios_mode[bu].yres,
6375 sisbios_mode[bu].bpp);
6376 }
6377 }
6378
6379 if(ivideo->sisfb_mode_idx < 0) {
6380 switch(ivideo->currentvbflags & VB_DISPTYPE_DISP2) {
6381 case CRT2_LCD:
6382 ivideo->sisfb_mode_idx = ivideo->lcddefmodeidx;
6383 break;
6384 case CRT2_TV:
6385 ivideo->sisfb_mode_idx = ivideo->tvdefmodeidx;
6386 break;
6387 default:
6388 ivideo->sisfb_mode_idx = ivideo->defmodeidx;
6389 break;
6390 }
6391 }
6392
6393 ivideo->mode_no = sisbios_mode[ivideo->sisfb_mode_idx].mode_no[ivideo->mni];
6394
6395 if(ivideo->refresh_rate != 0) {
544393fe
TW
6396 sisfb_search_refresh_rate(ivideo, ivideo->refresh_rate,
6397 ivideo->sisfb_mode_idx);
1da177e4
LT
6398 }
6399
6400 if(ivideo->rate_idx == 0) {
6401 ivideo->rate_idx = sisbios_mode[ivideo->sisfb_mode_idx].rate_idx;
6402 ivideo->refresh_rate = 60;
6403 }
6404
6405 if(ivideo->sisfb_thismonitor.datavalid) {
544393fe
TW
6406 if(!sisfb_verify_rate(ivideo, &ivideo->sisfb_thismonitor,
6407 ivideo->sisfb_mode_idx,
6408 ivideo->rate_idx,
6409 ivideo->refresh_rate)) {
6410 printk(KERN_INFO "sisfb: WARNING: Refresh rate "
6411 "exceeds monitor specs!\n");
1da177e4
LT
6412 }
6413 }
6414
6415 ivideo->video_bpp = sisbios_mode[ivideo->sisfb_mode_idx].bpp;
6416 ivideo->video_width = sisbios_mode[ivideo->sisfb_mode_idx].xres;
6417 ivideo->video_height = sisbios_mode[ivideo->sisfb_mode_idx].yres;
6418
6419 sisfb_set_vparms(ivideo);
1da177e4 6420
1da177e4 6421 printk(KERN_INFO "sisfb: Default mode is %dx%dx%d (%dHz)\n",
544393fe 6422 ivideo->video_width, ivideo->video_height, ivideo->video_bpp,
1da177e4
LT
6423 ivideo->refresh_rate);
6424
544393fe 6425 /* Set up the default var according to chosen default display mode */
1da177e4
LT
6426 ivideo->default_var.xres = ivideo->default_var.xres_virtual = ivideo->video_width;
6427 ivideo->default_var.yres = ivideo->default_var.yres_virtual = ivideo->video_height;
6428 ivideo->default_var.bits_per_pixel = ivideo->video_bpp;
6429
6430 sisfb_bpp_to_var(ivideo, &ivideo->default_var);
544393fe 6431
1da177e4 6432 ivideo->default_var.pixclock = (u32) (1000000000 /
544393fe
TW
6433 sisfb_mode_rate_to_dclock(&ivideo->SiS_Pr, ivideo->mode_no, ivideo->rate_idx));
6434
6435 if(sisfb_mode_rate_to_ddata(&ivideo->SiS_Pr, ivideo->mode_no,
6436 ivideo->rate_idx, &ivideo->default_var)) {
6437 if((ivideo->default_var.vmode & FB_VMODE_MASK) == FB_VMODE_DOUBLE) {
6438 ivideo->default_var.pixclock <<= 1;
6439 }
6440 }
1da177e4
LT
6441
6442 if(ivideo->sisfb_ypan) {
544393fe
TW
6443 /* Maximize regardless of sisfb_max at startup */
6444 ivideo->default_var.yres_virtual =
6445 sisfb_calc_maxyres(ivideo, &ivideo->default_var);
6446 if(ivideo->default_var.yres_virtual < ivideo->default_var.yres) {
6447 ivideo->default_var.yres_virtual = ivideo->default_var.yres;
6448 }
1da177e4
LT
6449 }
6450
6451 sisfb_calc_pitch(ivideo, &ivideo->default_var);
6452
6453 ivideo->accel = 0;
6454 if(ivideo->sisfb_accel) {
544393fe 6455 ivideo->accel = -1;
1da177e4 6456#ifdef STUPID_ACCELF_TEXT_SHIT
544393fe 6457 ivideo->default_var.accel_flags |= FB_ACCELF_TEXT;
1da177e4
LT
6458#endif
6459 }
6460 sisfb_initaccel(ivideo);
6461
6462#if defined(FBINFO_HWACCEL_DISABLED) && defined(FBINFO_HWACCEL_XPAN)
6463 sis_fb_info->flags = FBINFO_DEFAULT |
6464 FBINFO_HWACCEL_YPAN |
6465 FBINFO_HWACCEL_XPAN |
6466 FBINFO_HWACCEL_COPYAREA |
6467 FBINFO_HWACCEL_FILLRECT |
6468 ((ivideo->accel) ? 0 : FBINFO_HWACCEL_DISABLED);
6469#else
6470 sis_fb_info->flags = FBINFO_FLAG_DEFAULT;
6471#endif
6472 sis_fb_info->var = ivideo->default_var;
6473 sis_fb_info->fix = ivideo->sisfb_fix;
544393fe 6474 sis_fb_info->screen_base = ivideo->video_vbase + ivideo->video_offset;
1da177e4 6475 sis_fb_info->fbops = &sisfb_ops;
1da177e4 6476 sis_fb_info->pseudo_palette = ivideo->pseudo_palette;
544393fe 6477
1da177e4 6478 fb_alloc_cmap(&sis_fb_info->cmap, 256 , 0);
1da177e4 6479
544393fe 6480 printk(KERN_DEBUG "sisfb: Initial vbflags 0x%x\n", (int)ivideo->vbflags);
1da177e4 6481
2cff6406
LR
6482 ivideo->wc_cookie = arch_phys_wc_add(ivideo->video_base,
6483 ivideo->video_size);
1da177e4
LT
6484 if(register_framebuffer(sis_fb_info) < 0) {
6485 printk(KERN_ERR "sisfb: Fatal error: Failed to register framebuffer\n");
544393fe 6486 ret = -EINVAL;
1da177e4 6487 iounmap(ivideo->mmio_vbase);
544393fe 6488 goto error_0;
1da177e4
LT
6489 }
6490
6491 ivideo->registered = 1;
6492
6493 /* Enlist us */
6494 ivideo->next = card_list;
6495 card_list = ivideo;
6496
6497 printk(KERN_INFO "sisfb: 2D acceleration is %s, y-panning %s\n",
544393fe
TW
6498 ivideo->sisfb_accel ? "enabled" : "disabled",
6499 ivideo->sisfb_ypan ?
6500 (ivideo->sisfb_max ? "enabled (auto-max)" :
6501 "enabled (no auto-max)") :
6502 "disabled");
1da177e4
LT
6503
6504
31b6780c
JP
6505 fb_info(sis_fb_info, "%s frame buffer device version %d.%d.%d\n",
6506 ivideo->myid, VER_MAJOR, VER_MINOR, VER_LEVEL);
1da177e4 6507
544393fe 6508 printk(KERN_INFO "sisfb: Copyright (C) 2001-2005 Thomas Winischhofer\n");
1da177e4
LT
6509
6510 } /* if mode = "none" */
6511
6512 return 0;
6513}
6514
6515/*****************************************************/
6516/* PCI DEVICE HANDLING */
6517/*****************************************************/
6518
48c68c4f 6519static void sisfb_remove(struct pci_dev *pdev)
1da177e4 6520{
544393fe
TW
6521 struct sis_video_info *ivideo = pci_get_drvdata(pdev);
6522 struct fb_info *sis_fb_info = ivideo->memyselfandi;
6523 int registered = ivideo->registered;
6524 int modechanged = ivideo->modechanged;
6525
1da177e4 6526 /* Unmap */
1da177e4 6527 iounmap(ivideo->mmio_vbase);
544393fe 6528 iounmap(ivideo->video_vbase);
1da177e4
LT
6529
6530 /* Release mem regions */
6531 release_mem_region(ivideo->video_base, ivideo->video_size);
6532 release_mem_region(ivideo->mmio_base, ivideo->mmio_size);
6533
544393fe
TW
6534 vfree(ivideo->bios_abase);
6535
6049a7a2 6536 pci_dev_put(ivideo->lpcdev);
544393fe 6537
6049a7a2 6538 pci_dev_put(ivideo->nbridge);
544393fe 6539
2cff6406 6540 arch_phys_wc_del(ivideo->wc_cookie);
1da177e4 6541
544393fe
TW
6542 /* If device was disabled when starting, disable
6543 * it when quitting.
6544 */
6545 if(!ivideo->sisvga_enabled)
6546 pci_disable_device(pdev);
6547
1da177e4
LT
6548 /* Unregister the framebuffer */
6549 if(ivideo->registered) {
6550 unregister_framebuffer(sis_fb_info);
1da177e4 6551 framebuffer_release(sis_fb_info);
1da177e4
LT
6552 }
6553
544393fe 6554 /* OK, our ivideo is gone for good from here. */
1da177e4
LT
6555
6556 /* TODO: Restore the initial mode
6557 * This sounds easy but is as good as impossible
6558 * on many machines with SiS chip and video bridge
6559 * since text modes are always set up differently
6560 * from machine to machine. Depends on the type
6561 * of integration between chipset and bridge.
6562 */
544393fe
TW
6563 if(registered && modechanged)
6564 printk(KERN_INFO
6565 "sisfb: Restoring of text mode not supported yet\n");
1da177e4
LT
6566};
6567
6568static struct pci_driver sisfb_driver = {
6569 .name = "sisfb",
6570 .id_table = sisfb_pci_table,
544393fe 6571 .probe = sisfb_probe,
48c68c4f 6572 .remove = sisfb_remove,
1da177e4
LT
6573};
6574
14aefd1b 6575static int __init sisfb_init(void)
1da177e4 6576{
1da177e4
LT
6577#ifndef MODULE
6578 char *options = NULL;
6579
6580 if(fb_get_options("sisfb", &options))
6581 return -ENODEV;
544393fe 6582
1da177e4 6583 sisfb_setup(options);
1da177e4 6584#endif
544393fe 6585 return pci_register_driver(&sisfb_driver);
1da177e4
LT
6586}
6587
1da177e4
LT
6588#ifndef MODULE
6589module_init(sisfb_init);
6590#endif
1da177e4
LT
6591
6592/*****************************************************/
6593/* MODULE */
6594/*****************************************************/
6595
6596#ifdef MODULE
6597
544393fe
TW
6598static char *mode = NULL;
6599static int vesa = -1;
6600static unsigned int rate = 0;
6601static unsigned int crt1off = 1;
6602static unsigned int mem = 0;
6603static char *forcecrt2type = NULL;
6604static int forcecrt1 = -1;
6605static int pdc = -1;
6606static int pdc1 = -1;
6607static int noaccel = -1;
6608static int noypan = -1;
6609static int nomax = -1;
544393fe
TW
6610static int userom = -1;
6611static int useoem = -1;
6612static char *tvstandard = NULL;
6613static int nocrt2rate = 0;
6614static int scalelcd = -1;
6615static char *specialtiming = NULL;
6616static int lvdshl = -1;
6617static int tvxposoffset = 0, tvyposoffset = 0;
6618#if !defined(__i386__) && !defined(__x86_64__)
6619static int resetcard = 0;
6620static int videoram = 0;
6621#endif
6622
6623static int __init sisfb_init_module(void)
6624{
6625 sisfb_setdefaultparms();
6626
6627 if(rate)
6628 sisfb_parm_rate = rate;
6629
6630 if((scalelcd == 0) || (scalelcd == 1))
6631 sisfb_scalelcd = scalelcd ^ 1;
6632
6633 /* Need to check crt2 type first for fstn/dstn */
6634
6635 if(forcecrt2type)
6636 sisfb_search_crt2type(forcecrt2type);
6637
6638 if(tvstandard)
6639 sisfb_search_tvstd(tvstandard);
6640
6641 if(mode)
c30660ea 6642 sisfb_search_mode(mode, false);
544393fe 6643 else if(vesa != -1)
c30660ea 6644 sisfb_search_vesamode(vesa, false);
544393fe
TW
6645
6646 sisfb_crt1off = (crt1off == 0) ? 1 : 0;
6647
6648 sisfb_forcecrt1 = forcecrt1;
6649 if(forcecrt1 == 1)
6650 sisfb_crt1off = 0;
6651 else if(forcecrt1 == 0)
6652 sisfb_crt1off = 1;
6653
6654 if(noaccel == 1)
6655 sisfb_accel = 0;
6656 else if(noaccel == 0)
6657 sisfb_accel = 1;
6658
6659 if(noypan == 1)
6660 sisfb_ypan = 0;
6661 else if(noypan == 0)
6662 sisfb_ypan = 1;
6663
6664 if(nomax == 1)
6665 sisfb_max = 0;
6666 else if(nomax == 0)
6667 sisfb_max = 1;
6668
544393fe
TW
6669 if(mem)
6670 sisfb_parm_mem = mem;
6671
6672 if(userom != -1)
6673 sisfb_userom = userom;
6674
6675 if(useoem != -1)
6676 sisfb_useoem = useoem;
6677
6678 if(pdc != -1)
6679 sisfb_pdc = (pdc & 0x7f);
6680
6681 if(pdc1 != -1)
6682 sisfb_pdca = (pdc1 & 0x1f);
6683
6684 sisfb_nocrt2rate = nocrt2rate;
6685
6686 if(specialtiming)
6687 sisfb_search_specialtiming(specialtiming);
6688
6689 if((lvdshl >= 0) && (lvdshl <= 3))
6690 sisfb_lvdshl = lvdshl;
6691
6692 sisfb_tvxposoffset = tvxposoffset;
6693 sisfb_tvyposoffset = tvyposoffset;
6694
1da177e4 6695#if !defined(__i386__) && !defined(__x86_64__)
544393fe
TW
6696 sisfb_resetcard = (resetcard) ? 1 : 0;
6697 if(videoram)
6698 sisfb_videoram = videoram;
1da177e4
LT
6699#endif
6700
544393fe
TW
6701 return sisfb_init();
6702}
6703
6704static void __exit sisfb_remove_module(void)
6705{
6706 pci_unregister_driver(&sisfb_driver);
6707 printk(KERN_DEBUG "sisfb: Module unloaded\n");
6708}
6709
6710module_init(sisfb_init_module);
6711module_exit(sisfb_remove_module);
6712
6713MODULE_DESCRIPTION("SiS 300/540/630/730/315/55x/65x/661/74x/330/76x/34x, XGI V3XT/V5/V8/Z7 framebuffer device driver");
1da177e4
LT
6714MODULE_LICENSE("GPL");
6715MODULE_AUTHOR("Thomas Winischhofer <thomas@winischhofer.net>, Others");
6716
1da177e4
LT
6717module_param(mem, int, 0);
6718module_param(noaccel, int, 0);
6719module_param(noypan, int, 0);
6720module_param(nomax, int, 0);
6721module_param(userom, int, 0);
6722module_param(useoem, int, 0);
6723module_param(mode, charp, 0);
6724module_param(vesa, int, 0);
6725module_param(rate, int, 0);
6726module_param(forcecrt1, int, 0);
6727module_param(forcecrt2type, charp, 0);
6728module_param(scalelcd, int, 0);
6729module_param(pdc, int, 0);
6730module_param(pdc1, int, 0);
6731module_param(specialtiming, charp, 0);
6732module_param(lvdshl, int, 0);
6733module_param(tvstandard, charp, 0);
6734module_param(tvxposoffset, int, 0);
6735module_param(tvyposoffset, int, 0);
1da177e4
LT
6736module_param(nocrt2rate, int, 0);
6737#if !defined(__i386__) && !defined(__x86_64__)
6738module_param(resetcard, int, 0);
6739module_param(videoram, int, 0);
6740#endif
1da177e4 6741
544393fe
TW
6742MODULE_PARM_DESC(mem,
6743 "\nDetermines the beginning of the video memory heap in KB. This heap is used\n"
6744 "for video RAM management for eg. DRM/DRI. On 300 series, the default depends\n"
6745 "on the amount of video RAM available. If 8MB of video RAM or less is available,\n"
6746 "the heap starts at 4096KB, if between 8 and 16MB are available at 8192KB,\n"
6747 "otherwise at 12288KB. On 315/330/340 series, the heap size is 32KB by default.\n"
6748 "The value is to be specified without 'KB'.\n");
1da177e4
LT
6749
6750MODULE_PARM_DESC(noaccel,
544393fe 6751 "\nIf set to anything other than 0, 2D acceleration will be disabled.\n"
1da177e4
LT
6752 "(default: 0)\n");
6753
6754MODULE_PARM_DESC(noypan,
544393fe
TW
6755 "\nIf set to anything other than 0, y-panning will be disabled and scrolling\n"
6756 "will be performed by redrawing the screen. (default: 0)\n");
1da177e4
LT
6757
6758MODULE_PARM_DESC(nomax,
544393fe 6759 "\nIf y-panning is enabled, sisfb will by default use the entire available video\n"
1da177e4
LT
6760 "memory for the virtual screen in order to optimize scrolling performance. If\n"
6761 "this is set to anything other than 0, sisfb will not do this and thereby \n"
6762 "enable the user to positively specify a virtual Y size of the screen using\n"
6763 "fbset. (default: 0)\n");
6764
1da177e4 6765MODULE_PARM_DESC(mode,
544393fe
TW
6766 "\nSelects the desired default display mode in the format XxYxDepth,\n"
6767 "eg. 1024x768x16. Other formats supported include XxY-Depth and\n"
1da177e4
LT
6768 "XxY-Depth@Rate. If the parameter is only one (decimal or hexadecimal)\n"
6769 "number, it will be interpreted as a VESA mode number. (default: 800x600x8)\n");
6770
6771MODULE_PARM_DESC(vesa,
544393fe
TW
6772 "\nSelects the desired default display mode by VESA defined mode number, eg.\n"
6773 "0x117 (default: 0x0103)\n");
1da177e4
LT
6774
6775MODULE_PARM_DESC(rate,
6776 "\nSelects the desired vertical refresh rate for CRT1 (external VGA) in Hz.\n"
6777 "If the mode is specified in the format XxY-Depth@Rate, this parameter\n"
6778 "will be ignored (default: 60)\n");
6779
6780MODULE_PARM_DESC(forcecrt1,
6781 "\nNormally, the driver autodetects whether or not CRT1 (external VGA) is \n"
6782 "connected. With this option, the detection can be overridden (1=CRT1 ON,\n"
6783 "0=CRT1 OFF) (default: [autodetected])\n");
6784
6785MODULE_PARM_DESC(forcecrt2type,
6786 "\nIf this option is omitted, the driver autodetects CRT2 output devices, such as\n"
6787 "LCD, TV or secondary VGA. With this option, this autodetection can be\n"
6788 "overridden. Possible parameters are LCD, TV, VGA or NONE. NONE disables CRT2.\n"
6789 "On systems with a SiS video bridge, parameters SVIDEO, COMPOSITE or SCART can\n"
6790 "be used instead of TV to override the TV detection. Furthermore, on systems\n"
6791 "with a SiS video bridge, SVIDEO+COMPOSITE, HIVISION, YPBPR480I, YPBPR480P,\n"
6792 "YPBPR720P and YPBPR1080I are understood. However, whether or not these work\n"
6793 "depends on the very hardware in use. (default: [autodetected])\n");
6794
6795MODULE_PARM_DESC(scalelcd,
6796 "\nSetting this to 1 will force the driver to scale the LCD image to the panel's\n"
6797 "native resolution. Setting it to 0 will disable scaling; LVDS panels will\n"
6798 "show black bars around the image, TMDS panels will probably do the scaling\n"
6799 "themselves. Default: 1 on LVDS panels, 0 on TMDS panels\n");
6800
6801MODULE_PARM_DESC(pdc,
544393fe 6802 "\nThis is for manually selecting the LCD panel delay compensation. The driver\n"
1da177e4
LT
6803 "should detect this correctly in most cases; however, sometimes this is not\n"
6804 "possible. If you see 'small waves' on the LCD, try setting this to 4, 32 or 24\n"
544393fe
TW
6805 "on a 300 series chipset; 6 on other chipsets. If the problem persists, try\n"
6806 "other values (on 300 series: between 4 and 60 in steps of 4; otherwise: any\n"
6807 "value from 0 to 31). (default: autodetected, if LCD is active during start)\n");
1da177e4
LT
6808
6809#ifdef CONFIG_FB_SIS_315
6810MODULE_PARM_DESC(pdc1,
544393fe 6811 "\nThis is same as pdc, but for LCD-via CRT1. Hence, this is for the 315/330/340\n"
1da177e4
LT
6812 "series only. (default: autodetected if LCD is in LCD-via-CRT1 mode during\n"
6813 "startup) - Note: currently, this has no effect because LCD-via-CRT1 is not\n"
6814 "implemented yet.\n");
6815#endif
6816
6817MODULE_PARM_DESC(specialtiming,
6818 "\nPlease refer to documentation for more information on this option.\n");
6819
6820MODULE_PARM_DESC(lvdshl,
6821 "\nPlease refer to documentation for more information on this option.\n");
6822
6823MODULE_PARM_DESC(tvstandard,
6824 "\nThis allows overriding the BIOS default for the TV standard. Valid choices are\n"
6825 "pal, ntsc, palm and paln. (default: [auto; pal or ntsc only])\n");
6826
6827MODULE_PARM_DESC(tvxposoffset,
6828 "\nRelocate TV output horizontally. Possible parameters: -32 through 32.\n"
6829 "Default: 0\n");
6830
6831MODULE_PARM_DESC(tvyposoffset,
6832 "\nRelocate TV output vertically. Possible parameters: -32 through 32.\n"
6833 "Default: 0\n");
6834
1da177e4
LT
6835MODULE_PARM_DESC(nocrt2rate,
6836 "\nSetting this to 1 will force the driver to use the default refresh rate for\n"
6837 "CRT2 if CRT2 type is VGA. (default: 0, use same rate as CRT1)\n");
6838
1da177e4
LT
6839#if !defined(__i386__) && !defined(__x86_64__)
6840#ifdef CONFIG_FB_SIS_300
6841MODULE_PARM_DESC(resetcard,
6842 "\nSet this to 1 in order to reset (POST) the card on non-x86 machines where\n"
544393fe
TW
6843 "the BIOS did not POST the card (only supported for SiS 300/305 and XGI cards\n"
6844 "currently). Default: 0\n");
1da177e4
LT
6845
6846MODULE_PARM_DESC(videoram,
6847 "\nSet this to the amount of video RAM (in kilobyte) the card has. Required on\n"
6848 "some non-x86 architectures where the memory auto detection fails. Only\n"
544393fe 6849 "relevant if resetcard is set, too. SiS300/305 only. Default: [auto-detect]\n");
1da177e4 6850#endif
1da177e4
LT
6851#endif
6852
1da177e4
LT
6853#endif /* /MODULE */
6854
544393fe 6855/* _GPL only for new symbols. */
1da177e4
LT
6856EXPORT_SYMBOL(sis_malloc);
6857EXPORT_SYMBOL(sis_free);
544393fe
TW
6858EXPORT_SYMBOL_GPL(sis_malloc_new);
6859EXPORT_SYMBOL_GPL(sis_free_new);
6860
1da177e4
LT
6861
6862