]> git.proxmox.com Git - mirror_ubuntu-hirsute-kernel.git/blame - drivers/staging/xgifb/XGI_main_26.c
staging/xgifb: simplify vga I/O ports handling
[mirror_ubuntu-hirsute-kernel.git] / drivers / staging / xgifb / XGI_main_26.c
CommitLineData
d7636e0b 1/*
2 * XG20, XG21, XG40, XG42 frame buffer device
3 * for Linux kernels 2.5.x, 2.6.x
4 * Base on TW's sis fbdev code.
5 */
6
96c66042
SH
7#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
8
b654f878 9/* #include <linux/config.h> */
d7636e0b 10#include <linux/module.h>
11#include <linux/moduleparam.h>
12#include <linux/kernel.h>
13#include <linux/spinlock.h>
14#include <linux/errno.h>
15#include <linux/string.h>
16#include <linux/mm.h>
17#include <linux/tty.h>
18#include <linux/slab.h>
19#include <linux/delay.h>
20#include <linux/fb.h>
21#include <linux/console.h>
22#include <linux/selection.h>
23#include <linux/ioport.h>
24#include <linux/init.h>
25#include <linux/pci.h>
d7636e0b 26#include <linux/vt_kern.h>
27#include <linux/capability.h>
28#include <linux/fs.h>
29#include <linux/types.h>
30#include <linux/proc_fs.h>
d7636e0b 31
a12c27c5 32#include <linux/io.h>
d7636e0b 33#ifdef CONFIG_MTRR
34#include <asm/mtrr.h>
35#endif
36
37#include "XGIfb.h"
38#include "vgatypes.h"
39#include "XGI_main.h"
d542af50 40#include "vb_init.h"
d7636e0b 41#include "vb_util.h"
d542af50 42#include "vb_setmode.h"
d7636e0b 43
d7636e0b 44#define Index_CR_GPIO_Reg1 0x48
d7636e0b 45#define Index_CR_GPIO_Reg3 0x4a
46
47#define GPIOG_EN (1<<6)
d7636e0b 48#define GPIOG_READ (1<<1)
d7636e0b 49
2d2c880f 50static char *forcecrt2type;
dfbdf805 51static char *mode;
c3228308 52static int vesa = -1;
7548a83e 53static unsigned int refresh_rate;
dfbdf805 54
d7636e0b 55/* -------------------- Macro definitions ---------------------------- */
56
57#undef XGIFBDEBUG
58
59#ifdef XGIFBDEBUG
4a6b1518 60#define DPRINTK(fmt, args...) pr_debug("%s: " fmt, __func__ , ## args)
d7636e0b 61#else
62#define DPRINTK(fmt, args...)
63#endif
64
65#ifdef XGIFBDEBUG
66static void dumpVGAReg(void)
67{
b654f878
PS
68 u8 i, reg;
69
b6e2dc39 70 xgifb_reg_set(XGISR, 0x05, 0x86);
b654f878 71 /*
b6e2dc39
AK
72 xgifb_reg_set(XGISR, 0x08, 0x4f);
73 xgifb_reg_set(XGISR, 0x0f, 0x20);
74 xgifb_reg_set(XGISR, 0x11, 0x4f);
75 xgifb_reg_set(XGISR, 0x13, 0x45);
76 xgifb_reg_set(XGISR, 0x14, 0x51);
77 xgifb_reg_set(XGISR, 0x1e, 0x41);
78 xgifb_reg_set(XGISR, 0x1f, 0x0);
79 xgifb_reg_set(XGISR, 0x20, 0xa1);
80 xgifb_reg_set(XGISR, 0x22, 0xfb);
81 xgifb_reg_set(XGISR, 0x26, 0x22);
82 xgifb_reg_set(XGISR, 0x3e, 0x07);
b654f878
PS
83 */
84
b6e2dc39
AK
85 /* xgifb_reg_set(XGICR, 0x19, 0x00); */
86 /* xgifb_reg_set(XGICR, 0x1a, 0x3C); */
87 /* xgifb_reg_set(XGICR, 0x22, 0xff); */
88 /* xgifb_reg_set(XGICR, 0x3D, 0x10); */
b654f878 89
b6e2dc39 90 /* xgifb_reg_set(XGICR, 0x4a, 0xf3); */
b654f878 91
b6e2dc39
AK
92 /* xgifb_reg_set(XGICR, 0x57, 0x0); */
93 /* xgifb_reg_set(XGICR, 0x7a, 0x2c); */
b654f878 94
b6e2dc39
AK
95 /* xgifb_reg_set(XGICR, 0x82, 0xcc); */
96 /* xgifb_reg_set(XGICR, 0x8c, 0x0); */
b654f878 97 /*
b6e2dc39
AK
98 xgifb_reg_set(XGICR, 0x99, 0x1);
99 xgifb_reg_set(XGICR, 0x41, 0x40);
b654f878
PS
100 */
101
102 for (i = 0; i < 0x4f; i++) {
7e119b75 103 reg = xgifb_reg_get(XGISR, i);
b654f878
PS
104 printk("\no 3c4 %x", i);
105 printk("\ni 3c5 => %x", reg);
106 }
107
108 for (i = 0; i < 0xF0; i++) {
7e119b75 109 reg = xgifb_reg_get(XGICR, i);
b654f878
PS
110 printk("\no 3d4 %x", i);
111 printk("\ni 3d5 => %x", reg);
112 }
113 /*
b6e2dc39 114 xgifb_reg_set(XGIPART1,0x2F,1);
b654f878 115 for (i=1; i < 0x50; i++) {
7e119b75 116 reg = xgifb_reg_get(XGIPART1, i);
b654f878
PS
117 printk("\no d004 %x", i);
118 printk("\ni d005 => %x", reg);
119 }
120
121 for (i=0; i < 0x50; i++) {
7e119b75 122 reg = xgifb_reg_get(XGIPART2, i);
b654f878
PS
123 printk("\no d010 %x", i);
124 printk("\ni d011 => %x", reg);
125 }
126 for (i=0; i < 0x50; i++) {
7e119b75 127 reg = xgifb_reg_get(XGIPART3, i);
b654f878
PS
128 printk("\no d012 %x",i);
129 printk("\ni d013 => %x",reg);
130 }
131 for (i=0; i < 0x50; i++) {
7e119b75 132 reg = xgifb_reg_get(XGIPART4, i);
b654f878
PS
133 printk("\no d014 %x",i);
134 printk("\ni d015 => %x",reg);
135 }
136 */
d7636e0b 137}
138#else
b654f878
PS
139static inline void dumpVGAReg(void)
140{
141}
d7636e0b 142#endif
143
d7636e0b 144#if 1
145#define DEBUGPRN(x)
146#else
4a6b1518 147#define DEBUGPRN(x) pr_info(x "\n");
d7636e0b 148#endif
149
d7636e0b 150/* --------------- Hardware Access Routines -------------------------- */
151
b654f878
PS
152static int XGIfb_mode_rate_to_dclock(struct vb_device_info *XGI_Pr,
153 struct xgi_hw_device_info *HwDeviceExtension,
154 unsigned char modeno, unsigned char rateindex)
d7636e0b 155{
b654f878
PS
156 unsigned short ModeNo = modeno;
157 unsigned short ModeIdIndex = 0, ClockIndex = 0;
158 unsigned short RefreshRateTableIndex = 0;
d7636e0b 159
b654f878
PS
160 /* unsigned long temp = 0; */
161 int Clock;
b654f878 162 InitTo330Pointer(HwDeviceExtension->jChipType, XGI_Pr);
d7636e0b 163
b654f878
PS
164 RefreshRateTableIndex = XGI_GetRatePtrCRT2(HwDeviceExtension, ModeNo,
165 ModeIdIndex, XGI_Pr);
d7636e0b 166
b654f878
PS
167 /*
168 temp = XGI_SearchModeID(ModeNo , &ModeIdIndex, XGI_Pr) ;
169 if (!temp) {
170 printk(KERN_ERR "Could not find mode %x\n", ModeNo);
171 return 65000;
172 }
d7636e0b 173
b654f878
PS
174 RefreshRateTableIndex = XGI_Pr->EModeIDTable[ModeIdIndex].REFindex;
175 RefreshRateTableIndex += (rateindex - 1);
d7636e0b 176
b654f878
PS
177 */
178 ClockIndex = XGI_Pr->RefIndex[RefreshRateTableIndex].Ext_CRTVCLK;
b654f878
PS
179
180 Clock = XGI_Pr->VCLKData[ClockIndex].CLOCK * 1000;
d7636e0b 181
b654f878 182 return Clock;
d7636e0b 183}
184
b654f878
PS
185static int XGIfb_mode_rate_to_ddata(struct vb_device_info *XGI_Pr,
186 struct xgi_hw_device_info *HwDeviceExtension,
187 unsigned char modeno, unsigned char rateindex,
188 u32 *left_margin, u32 *right_margin, u32 *upper_margin,
189 u32 *lower_margin, u32 *hsync_len, u32 *vsync_len, u32 *sync,
190 u32 *vmode)
d7636e0b 191{
b654f878
PS
192 unsigned short ModeNo = modeno;
193 unsigned short ModeIdIndex = 0, index = 0;
194 unsigned short RefreshRateTableIndex = 0;
195
196 unsigned short VRE, VBE, VRS, VBS, VDE, VT;
197 unsigned short HRE, HBE, HRS, HBS, HDE, HT;
198 unsigned char sr_data, cr_data, cr_data2;
199 unsigned long cr_data3;
200 int A, B, C, D, E, F, temp, j;
b654f878
PS
201 InitTo330Pointer(HwDeviceExtension->jChipType, XGI_Pr);
202 RefreshRateTableIndex = XGI_GetRatePtrCRT2(HwDeviceExtension, ModeNo,
203 ModeIdIndex, XGI_Pr);
204 /*
205 temp = XGI_SearchModeID(ModeNo, &ModeIdIndex, XGI_Pr);
206 if (!temp)
207 return 0;
d7636e0b 208
b654f878
PS
209 RefreshRateTableIndex = XGI_Pr->EModeIDTable[ModeIdIndex].REFindex;
210 RefreshRateTableIndex += (rateindex - 1);
211 */
212 index = XGI_Pr->RefIndex[RefreshRateTableIndex].Ext_CRT1CRTC;
d7636e0b 213
b654f878 214 sr_data = XGI_Pr->XGINEWUB_CRT1Table[index].CR[5];
d7636e0b 215
b654f878 216 cr_data = XGI_Pr->XGINEWUB_CRT1Table[index].CR[0];
d7636e0b 217
b654f878
PS
218 /* Horizontal total */
219 HT = (cr_data & 0xff) | ((unsigned short) (sr_data & 0x03) << 8);
220 A = HT + 5;
d7636e0b 221
b654f878
PS
222 /*
223 cr_data = XGI_Pr->XGINEWUB_CRT1Table[index].CR[1];
d7636e0b 224
b654f878
PS
225 Horizontal display enable end
226 HDE = (cr_data & 0xff) | ((unsigned short) (sr_data & 0x0C) << 6);
227 */
228 HDE = (XGI_Pr->RefIndex[RefreshRateTableIndex].XRes >> 3) - 1;
229 E = HDE + 1;
d7636e0b 230
b654f878 231 cr_data = XGI_Pr->XGINEWUB_CRT1Table[index].CR[3];
d7636e0b 232
b654f878
PS
233 /* Horizontal retrace (=sync) start */
234 HRS = (cr_data & 0xff) | ((unsigned short) (sr_data & 0xC0) << 2);
235 F = HRS - E - 3;
d7636e0b 236
b654f878 237 cr_data = XGI_Pr->XGINEWUB_CRT1Table[index].CR[1];
d7636e0b 238
b654f878
PS
239 /* Horizontal blank start */
240 HBS = (cr_data & 0xff) | ((unsigned short) (sr_data & 0x30) << 4);
d7636e0b 241
b654f878 242 sr_data = XGI_Pr->XGINEWUB_CRT1Table[index].CR[6];
d7636e0b 243
b654f878 244 cr_data = XGI_Pr->XGINEWUB_CRT1Table[index].CR[2];
d7636e0b 245
b654f878 246 cr_data2 = XGI_Pr->XGINEWUB_CRT1Table[index].CR[4];
d7636e0b 247
b654f878
PS
248 /* Horizontal blank end */
249 HBE = (cr_data & 0x1f) | ((unsigned short) (cr_data2 & 0x80) >> 2)
250 | ((unsigned short) (sr_data & 0x03) << 6);
d7636e0b 251
b654f878
PS
252 /* Horizontal retrace (=sync) end */
253 HRE = (cr_data2 & 0x1f) | ((sr_data & 0x04) << 3);
d7636e0b 254
b654f878
PS
255 temp = HBE - ((E - 1) & 255);
256 B = (temp > 0) ? temp : (temp + 256);
d7636e0b 257
b654f878
PS
258 temp = HRE - ((E + F + 3) & 63);
259 C = (temp > 0) ? temp : (temp + 64);
d7636e0b 260
b654f878 261 D = B - F - C;
d7636e0b 262
b654f878
PS
263 *left_margin = D * 8;
264 *right_margin = F * 8;
265 *hsync_len = C * 8;
d7636e0b 266
b654f878 267 sr_data = XGI_Pr->XGINEWUB_CRT1Table[index].CR[14];
d7636e0b 268
b654f878 269 cr_data = XGI_Pr->XGINEWUB_CRT1Table[index].CR[8];
d7636e0b 270
b654f878 271 cr_data2 = XGI_Pr->XGINEWUB_CRT1Table[index].CR[9];
d7636e0b 272
b654f878
PS
273 /* Vertical total */
274 VT = (cr_data & 0xFF) | ((unsigned short) (cr_data2 & 0x01) << 8)
275 | ((unsigned short) (cr_data2 & 0x20) << 4)
276 | ((unsigned short) (sr_data & 0x01) << 10);
277 A = VT + 2;
d7636e0b 278
b654f878 279 /* cr_data = XGI_Pr->XGINEWUB_CRT1Table[index].CR[10]; */
d7636e0b 280
b654f878
PS
281 /* Vertical display enable end */
282 /*
283 VDE = (cr_data & 0xff) |
284 ((unsigned short) (cr_data2 & 0x02) << 7) |
285 ((unsigned short) (cr_data2 & 0x40) << 3) |
286 ((unsigned short) (sr_data & 0x02) << 9);
287 */
288 VDE = XGI_Pr->RefIndex[RefreshRateTableIndex].YRes - 1;
289 E = VDE + 1;
d7636e0b 290
b654f878 291 cr_data = XGI_Pr->XGINEWUB_CRT1Table[index].CR[10];
d7636e0b 292
b654f878
PS
293 /* Vertical retrace (=sync) start */
294 VRS = (cr_data & 0xff) | ((unsigned short) (cr_data2 & 0x04) << 6)
295 | ((unsigned short) (cr_data2 & 0x80) << 2)
296 | ((unsigned short) (sr_data & 0x08) << 7);
297 F = VRS + 1 - E;
d7636e0b 298
b654f878 299 cr_data = XGI_Pr->XGINEWUB_CRT1Table[index].CR[12];
d7636e0b 300
b654f878 301 cr_data3 = (XGI_Pr->XGINEWUB_CRT1Table[index].CR[14] & 0x80) << 5;
d7636e0b 302
b654f878
PS
303 /* Vertical blank start */
304 VBS = (cr_data & 0xff) | ((unsigned short) (cr_data2 & 0x08) << 5)
305 | ((unsigned short) (cr_data3 & 0x20) << 4)
306 | ((unsigned short) (sr_data & 0x04) << 8);
d7636e0b 307
b654f878 308 cr_data = XGI_Pr->XGINEWUB_CRT1Table[index].CR[13];
d7636e0b 309
b654f878
PS
310 /* Vertical blank end */
311 VBE = (cr_data & 0xff) | ((unsigned short) (sr_data & 0x10) << 4);
312 temp = VBE - ((E - 1) & 511);
313 B = (temp > 0) ? temp : (temp + 512);
d7636e0b 314
b654f878 315 cr_data = XGI_Pr->XGINEWUB_CRT1Table[index].CR[11];
d7636e0b 316
b654f878
PS
317 /* Vertical retrace (=sync) end */
318 VRE = (cr_data & 0x0f) | ((sr_data & 0x20) >> 1);
319 temp = VRE - ((E + F - 1) & 31);
320 C = (temp > 0) ? temp : (temp + 32);
d7636e0b 321
b654f878 322 D = B - F - C;
d7636e0b 323
b654f878
PS
324 *upper_margin = D;
325 *lower_margin = F;
326 *vsync_len = C;
d7636e0b 327
b654f878
PS
328 if (XGI_Pr->RefIndex[RefreshRateTableIndex].Ext_InfoFlag & 0x8000)
329 *sync &= ~FB_SYNC_VERT_HIGH_ACT;
330 else
331 *sync |= FB_SYNC_VERT_HIGH_ACT;
d7636e0b 332
b654f878
PS
333 if (XGI_Pr->RefIndex[RefreshRateTableIndex].Ext_InfoFlag & 0x4000)
334 *sync &= ~FB_SYNC_HOR_HIGH_ACT;
335 else
336 *sync |= FB_SYNC_HOR_HIGH_ACT;
d7636e0b 337
b654f878
PS
338 *vmode = FB_VMODE_NONINTERLACED;
339 if (XGI_Pr->RefIndex[RefreshRateTableIndex].Ext_InfoFlag & 0x0080)
340 *vmode = FB_VMODE_INTERLACED;
341 else {
342 j = 0;
343 while (XGI_Pr->EModeIDTable[j].Ext_ModeID != 0xff) {
a12c27c5
KT
344 if (XGI_Pr->EModeIDTable[j].Ext_ModeID ==
345 XGI_Pr->RefIndex[RefreshRateTableIndex].ModeID) {
346 if (XGI_Pr->EModeIDTable[j].Ext_ModeFlag &
347 DoubleScanMode) {
b654f878
PS
348 *vmode = FB_VMODE_DOUBLE;
349 }
350 break;
351 }
352 j++;
353 }
354 }
d7636e0b 355
b654f878
PS
356 return 1;
357}
d7636e0b 358
8922967e 359static void XGIRegInit(struct vb_device_info *XGI_Pr, unsigned long BaseAddr)
d7636e0b 360{
b654f878
PS
361 XGI_Pr->P3c4 = BaseAddr + 0x14;
362 XGI_Pr->P3d4 = BaseAddr + 0x24;
363 XGI_Pr->P3c0 = BaseAddr + 0x10;
364 XGI_Pr->P3ce = BaseAddr + 0x1e;
365 XGI_Pr->P3c2 = BaseAddr + 0x12;
366 XGI_Pr->P3ca = BaseAddr + 0x1a;
367 XGI_Pr->P3c6 = BaseAddr + 0x16;
368 XGI_Pr->P3c7 = BaseAddr + 0x17;
369 XGI_Pr->P3c8 = BaseAddr + 0x18;
370 XGI_Pr->P3c9 = BaseAddr + 0x19;
371 XGI_Pr->P3da = BaseAddr + 0x2A;
a12c27c5 372 /* Digital video interface registers (LCD) */
6896b94e 373 XGI_Pr->Part1Port = BaseAddr + SIS_CRT2_PORT_04;
a12c27c5 374 /* 301 TV Encoder registers */
6896b94e 375 XGI_Pr->Part2Port = BaseAddr + SIS_CRT2_PORT_10;
a12c27c5 376 /* 301 Macrovision registers */
6896b94e 377 XGI_Pr->Part3Port = BaseAddr + SIS_CRT2_PORT_12;
a12c27c5 378 /* 301 VGA2 (and LCD) registers */
6896b94e 379 XGI_Pr->Part4Port = BaseAddr + SIS_CRT2_PORT_14;
a12c27c5 380 /* 301 palette address port registers */
6896b94e 381 XGI_Pr->Part5Port = BaseAddr + SIS_CRT2_PORT_14 + 2;
d7636e0b 382
383}
384
d7636e0b 385/* ------------------ Internal helper routines ----------------- */
386
fab04b97 387static int XGIfb_GetXG21DefaultLVDSModeIdx(struct xgifb_video_info *xgifb_info)
c4fa7dfe
AK
388{
389
390 int found_mode = 0;
391 int XGIfb_mode_idx = 0;
392
393 found_mode = 0;
394 while ((XGIbios_mode[XGIfb_mode_idx].mode_no != 0)
395 && (XGIbios_mode[XGIfb_mode_idx].xres
fab04b97 396 <= xgifb_info->lvds_data.LVDSHDE)) {
c4fa7dfe 397 if ((XGIbios_mode[XGIfb_mode_idx].xres
fab04b97 398 == xgifb_info->lvds_data.LVDSHDE)
c4fa7dfe 399 && (XGIbios_mode[XGIfb_mode_idx].yres
fab04b97 400 == xgifb_info->lvds_data.LVDSVDE)
c4fa7dfe 401 && (XGIbios_mode[XGIfb_mode_idx].bpp == 8)) {
c4fa7dfe
AK
402 found_mode = 1;
403 break;
404 }
405 XGIfb_mode_idx++;
406 }
407 if (!found_mode)
de736dbb 408 XGIfb_mode_idx = -1;
c4fa7dfe
AK
409
410 return XGIfb_mode_idx;
411}
412
ccf265ad
AK
413static void XGIfb_search_mode(struct xgifb_video_info *xgifb_info,
414 const char *name)
d7636e0b 415{
416 int i = 0, j = 0, l;
417
b654f878 418 while (XGIbios_mode[i].mode_no != 0) {
d7636e0b 419 l = min(strlen(name), strlen(XGIbios_mode[i].name));
420 if (!strncmp(name, XGIbios_mode[i].name, l)) {
ccf265ad 421 xgifb_info->mode_idx = i;
d7636e0b 422 j = 1;
423 break;
424 }
425 i++;
426 }
b654f878 427 if (!j)
4a6b1518 428 pr_info("Invalid mode '%s'\n", name);
d7636e0b 429}
430
ccf265ad
AK
431static void XGIfb_search_vesamode(struct xgifb_video_info *xgifb_info,
432 unsigned int vesamode)
d7636e0b 433{
434 int i = 0, j = 0;
435
c3228308
AK
436 if (vesamode == 0)
437 goto invalid;
d7636e0b 438
b654f878 439 vesamode &= 0x1dff; /* Clean VESA mode number from other flags */
d7636e0b 440
b654f878 441 while (XGIbios_mode[i].mode_no != 0) {
a12c27c5
KT
442 if ((XGIbios_mode[i].vesa_mode_no_1 == vesamode) ||
443 (XGIbios_mode[i].vesa_mode_no_2 == vesamode)) {
ccf265ad 444 xgifb_info->mode_idx = i;
d7636e0b 445 j = 1;
446 break;
447 }
448 i++;
449 }
c3228308
AK
450
451invalid:
b654f878 452 if (!j)
4a6b1518 453 pr_info("Invalid VESA mode 0x%x'\n", vesamode);
d7636e0b 454}
455
fd26d420 456static int XGIfb_validate_mode(struct xgifb_video_info *xgifb_info, int myindex)
d7636e0b 457{
b654f878 458 u16 xres, yres;
fd26d420 459 struct xgi_hw_device_info *hw_info = &xgifb_info->hw_info;
b654f878 460
fd26d420 461 if (xgifb_info->chip == XG21) {
289ea524 462 if (xgifb_info->display2 == XGIFB_DISP_LCD) {
fab04b97
AK
463 xres = xgifb_info->lvds_data.LVDSHDE;
464 yres = xgifb_info->lvds_data.LVDSVDE;
b654f878
PS
465 if (XGIbios_mode[myindex].xres > xres)
466 return -1;
467 if (XGIbios_mode[myindex].yres > yres)
468 return -1;
a12c27c5
KT
469 if ((XGIbios_mode[myindex].xres < xres) &&
470 (XGIbios_mode[myindex].yres < yres)) {
b654f878
PS
471 if (XGIbios_mode[myindex].bpp > 8)
472 return -1;
473 }
474
475 }
476 return myindex;
477
d7636e0b 478 }
b654f878
PS
479
480 /* FIXME: for now, all is valid on XG27 */
fd26d420 481 if (xgifb_info->chip == XG27)
b654f878
PS
482 return myindex;
483
484 if (!(XGIbios_mode[myindex].chipset & MD_XGI315))
485 return -1;
486
289ea524
AK
487 switch (xgifb_info->display2) {
488 case XGIFB_DISP_LCD:
c62f2e46 489 switch (hw_info->ulCRT2LCDType) {
b654f878
PS
490 case LCD_640x480:
491 xres = 640;
492 yres = 480;
d7636e0b 493 break;
b654f878
PS
494 case LCD_800x600:
495 xres = 800;
496 yres = 600;
d7636e0b 497 break;
b654f878
PS
498 case LCD_1024x600:
499 xres = 1024;
500 yres = 600;
d7636e0b 501 break;
b654f878
PS
502 case LCD_1024x768:
503 xres = 1024;
504 yres = 768;
d7636e0b 505 break;
b654f878
PS
506 case LCD_1152x768:
507 xres = 1152;
508 yres = 768;
d7636e0b 509 break;
b654f878
PS
510 case LCD_1280x960:
511 xres = 1280;
512 yres = 960;
d7636e0b 513 break;
b654f878
PS
514 case LCD_1280x768:
515 xres = 1280;
516 yres = 768;
d7636e0b 517 break;
b654f878
PS
518 case LCD_1280x1024:
519 xres = 1280;
520 yres = 1024;
d7636e0b 521 break;
b654f878
PS
522 case LCD_1400x1050:
523 xres = 1400;
524 yres = 1050;
d7636e0b 525 break;
b654f878
PS
526 case LCD_1600x1200:
527 xres = 1600;
528 yres = 1200;
529 break;
b654f878
PS
530 default:
531 xres = 0;
532 yres = 0;
533 break;
534 }
535 if (XGIbios_mode[myindex].xres > xres)
536 return -1;
537 if (XGIbios_mode[myindex].yres > yres)
538 return -1;
c62f2e46
AK
539 if ((hw_info->ulExternalChip == 0x01) || /* LVDS */
540 (hw_info->ulExternalChip == 0x05)) { /* LVDS+Chrontel */
b654f878
PS
541 switch (XGIbios_mode[myindex].xres) {
542 case 512:
543 if (XGIbios_mode[myindex].yres != 512)
544 return -1;
c62f2e46 545 if (hw_info->ulCRT2LCDType == LCD_1024x600)
b654f878
PS
546 return -1;
547 break;
548 case 640:
549 if ((XGIbios_mode[myindex].yres != 400)
550 && (XGIbios_mode[myindex].yres
551 != 480))
552 return -1;
553 break;
554 case 800:
555 if (XGIbios_mode[myindex].yres != 600)
556 return -1;
557 break;
558 case 1024:
a12c27c5
KT
559 if ((XGIbios_mode[myindex].yres != 600) &&
560 (XGIbios_mode[myindex].yres != 768))
b654f878 561 return -1;
a12c27c5 562 if ((XGIbios_mode[myindex].yres == 600) &&
c62f2e46 563 (hw_info->ulCRT2LCDType != LCD_1024x600))
b654f878
PS
564 return -1;
565 break;
566 case 1152:
567 if ((XGIbios_mode[myindex].yres) != 768)
568 return -1;
c62f2e46 569 if (hw_info->ulCRT2LCDType != LCD_1152x768)
b654f878
PS
570 return -1;
571 break;
572 case 1280:
a12c27c5
KT
573 if ((XGIbios_mode[myindex].yres != 768) &&
574 (XGIbios_mode[myindex].yres != 1024))
b654f878 575 return -1;
a12c27c5 576 if ((XGIbios_mode[myindex].yres == 768) &&
c62f2e46 577 (hw_info->ulCRT2LCDType != LCD_1280x768))
b654f878
PS
578 return -1;
579 break;
580 case 1400:
581 if (XGIbios_mode[myindex].yres != 1050)
582 return -1;
583 break;
584 case 1600:
585 if (XGIbios_mode[myindex].yres != 1200)
586 return -1;
587 break;
588 default:
589 return -1;
d7636e0b 590 }
b654f878
PS
591 } else {
592 switch (XGIbios_mode[myindex].xres) {
593 case 512:
594 if (XGIbios_mode[myindex].yres != 512)
595 return -1;
596 break;
597 case 640:
a12c27c5
KT
598 if ((XGIbios_mode[myindex].yres != 400) &&
599 (XGIbios_mode[myindex].yres != 480))
b654f878
PS
600 return -1;
601 break;
602 case 800:
603 if (XGIbios_mode[myindex].yres != 600)
604 return -1;
605 break;
606 case 1024:
607 if (XGIbios_mode[myindex].yres != 768)
608 return -1;
609 break;
610 case 1280:
a12c27c5
KT
611 if ((XGIbios_mode[myindex].yres != 960) &&
612 (XGIbios_mode[myindex].yres != 1024))
b654f878
PS
613 return -1;
614 if (XGIbios_mode[myindex].yres == 960) {
c62f2e46 615 if (hw_info->ulCRT2LCDType ==
a12c27c5 616 LCD_1400x1050)
b654f878
PS
617 return -1;
618 }
619 break;
620 case 1400:
621 if (XGIbios_mode[myindex].yres != 1050)
622 return -1;
623 break;
624 case 1600:
625 if (XGIbios_mode[myindex].yres != 1200)
626 return -1;
627 break;
628 default:
629 return -1;
d7636e0b 630 }
631 }
d7636e0b 632 break;
289ea524 633 case XGIFB_DISP_TV:
b654f878
PS
634 switch (XGIbios_mode[myindex].xres) {
635 case 512:
636 case 640:
637 case 800:
638 break;
639 case 720:
fd26d420 640 if (xgifb_info->TV_type == TVMODE_NTSC) {
b654f878
PS
641 if (XGIbios_mode[myindex].yres != 480)
642 return -1;
fd26d420 643 } else if (xgifb_info->TV_type == TVMODE_PAL) {
b654f878
PS
644 if (XGIbios_mode[myindex].yres != 576)
645 return -1;
d7636e0b 646 }
b654f878 647 /* TW: LVDS/CHRONTEL does not support 720 */
fd26d420
AK
648 if (xgifb_info->hasVB == HASVB_LVDS_CHRONTEL ||
649 xgifb_info->hasVB == HASVB_CHRONTEL) {
b654f878
PS
650 return -1;
651 }
652 break;
653 case 1024:
fd26d420 654 if (xgifb_info->TV_type == TVMODE_NTSC) {
b654f878
PS
655 if (XGIbios_mode[myindex].bpp == 32)
656 return -1;
657 }
b654f878
PS
658 break;
659 default:
660 return -1;
d7636e0b 661 }
662 break;
289ea524 663 case XGIFB_DISP_CRT:
b654f878
PS
664 if (XGIbios_mode[myindex].xres > 1280)
665 return -1;
666 break;
289ea524
AK
667 case XGIFB_DISP_NONE:
668 break;
d7636e0b 669 }
b654f878 670 return myindex;
d7636e0b 671
672}
673
674static void XGIfb_search_crt2type(const char *name)
675{
676 int i = 0;
677
b654f878 678 if (name == NULL)
d7636e0b 679 return;
680
b654f878 681 while (XGI_crt2type[i].type_no != -1) {
d7636e0b 682 if (!strcmp(name, XGI_crt2type[i].name)) {
683 XGIfb_crt2type = XGI_crt2type[i].type_no;
684 XGIfb_tvplug = XGI_crt2type[i].tvplug_no;
685 break;
686 }
687 i++;
688 }
b654f878 689 if (XGIfb_crt2type < 0)
4a6b1518 690 pr_info("Invalid CRT2 type: %s\n", name);
d7636e0b 691}
692
fd26d420
AK
693static u8 XGIfb_search_refresh_rate(struct xgifb_video_info *xgifb_info,
694 unsigned int rate)
d7636e0b 695{
696 u16 xres, yres;
697 int i = 0;
698
ccf265ad
AK
699 xres = XGIbios_mode[xgifb_info->mode_idx].xres;
700 yres = XGIbios_mode[xgifb_info->mode_idx].yres;
d7636e0b 701
5aa55d9f 702 xgifb_info->rate_idx = 0;
d7636e0b 703 while ((XGIfb_vrate[i].idx != 0) && (XGIfb_vrate[i].xres <= xres)) {
a12c27c5
KT
704 if ((XGIfb_vrate[i].xres == xres) &&
705 (XGIfb_vrate[i].yres == yres)) {
d7636e0b 706 if (XGIfb_vrate[i].refresh == rate) {
5aa55d9f 707 xgifb_info->rate_idx = XGIfb_vrate[i].idx;
d7636e0b 708 break;
709 } else if (XGIfb_vrate[i].refresh > rate) {
710 if ((XGIfb_vrate[i].refresh - rate) <= 3) {
711 DPRINTK("XGIfb: Adjusting rate from %d up to %d\n",
a12c27c5 712 rate, XGIfb_vrate[i].refresh);
5aa55d9f
AK
713 xgifb_info->rate_idx =
714 XGIfb_vrate[i].idx;
fd26d420 715 xgifb_info->refresh_rate =
a12c27c5 716 XGIfb_vrate[i].refresh;
b654f878
PS
717 } else if (((rate - XGIfb_vrate[i - 1].refresh)
718 <= 2) && (XGIfb_vrate[i].idx
719 != 1)) {
d7636e0b 720 DPRINTK("XGIfb: Adjusting rate from %d down to %d\n",
a12c27c5 721 rate, XGIfb_vrate[i-1].refresh);
5aa55d9f
AK
722 xgifb_info->rate_idx =
723 XGIfb_vrate[i - 1].idx;
fd26d420 724 xgifb_info->refresh_rate =
a12c27c5 725 XGIfb_vrate[i - 1].refresh;
d7636e0b 726 }
727 break;
b654f878 728 } else if ((rate - XGIfb_vrate[i].refresh) <= 2) {
d7636e0b 729 DPRINTK("XGIfb: Adjusting rate from %d down to %d\n",
a12c27c5 730 rate, XGIfb_vrate[i].refresh);
5aa55d9f 731 xgifb_info->rate_idx = XGIfb_vrate[i].idx;
b654f878
PS
732 break;
733 }
d7636e0b 734 }
735 i++;
736 }
5aa55d9f
AK
737 if (xgifb_info->rate_idx > 0) {
738 return xgifb_info->rate_idx;
d7636e0b 739 } else {
4a6b1518 740 pr_info("Unsupported rate %d for %dx%d\n",
a12c27c5 741 rate, xres, yres);
d7636e0b 742 return 0;
743 }
744}
745
746static void XGIfb_search_tvstd(const char *name)
747{
748 int i = 0;
749
b654f878 750 if (name == NULL)
d7636e0b 751 return;
752
753 while (XGI_tvtype[i].type_no != -1) {
754 if (!strcmp(name, XGI_tvtype[i].name)) {
755 XGIfb_tvmode = XGI_tvtype[i].type_no;
756 break;
757 }
758 i++;
759 }
760}
761
d7636e0b 762/* ----------- FBDev related routines for all series ----------- */
763
fd26d420
AK
764static void XGIfb_bpp_to_var(struct xgifb_video_info *xgifb_info,
765 struct fb_var_screeninfo *var)
d7636e0b 766{
b654f878
PS
767 switch (var->bits_per_pixel) {
768 case 8:
769 var->red.offset = var->green.offset = var->blue.offset = 0;
d7636e0b 770 var->red.length = var->green.length = var->blue.length = 6;
fd26d420 771 xgifb_info->video_cmap_len = 256;
d7636e0b 772 break;
b654f878 773 case 16:
d7636e0b 774 var->red.offset = 11;
775 var->red.length = 5;
776 var->green.offset = 5;
777 var->green.length = 6;
778 var->blue.offset = 0;
779 var->blue.length = 5;
780 var->transp.offset = 0;
781 var->transp.length = 0;
fd26d420 782 xgifb_info->video_cmap_len = 16;
d7636e0b 783 break;
b654f878 784 case 32:
d7636e0b 785 var->red.offset = 16;
786 var->red.length = 8;
787 var->green.offset = 8;
788 var->green.length = 8;
789 var->blue.offset = 0;
790 var->blue.length = 8;
791 var->transp.offset = 24;
792 var->transp.length = 8;
fd26d420 793 xgifb_info->video_cmap_len = 16;
d7636e0b 794 break;
795 }
796}
797
c4fa7dfe 798/* --------------------- SetMode routines ------------------------- */
d7636e0b 799
fd26d420 800static void XGIfb_pre_setmode(struct xgifb_video_info *xgifb_info)
c4fa7dfe
AK
801{
802 u8 cr30 = 0, cr31 = 0;
d7636e0b 803
c4fa7dfe
AK
804 cr31 = xgifb_reg_get(XGICR, 0x31);
805 cr31 &= ~0x60;
d7636e0b 806
289ea524
AK
807 switch (xgifb_info->display2) {
808 case XGIFB_DISP_CRT:
fc39dcb7
PH
809 cr30 = (SIS_VB_OUTPUT_CRT2 | SIS_SIMULTANEOUS_VIEW_ENABLE);
810 cr31 |= SIS_DRIVER_MODE;
c4fa7dfe 811 break;
289ea524 812 case XGIFB_DISP_LCD:
fc39dcb7
PH
813 cr30 = (SIS_VB_OUTPUT_LCD | SIS_SIMULTANEOUS_VIEW_ENABLE);
814 cr31 |= SIS_DRIVER_MODE;
c4fa7dfe 815 break;
289ea524 816 case XGIFB_DISP_TV:
fd26d420 817 if (xgifb_info->TV_type == TVMODE_HIVISION)
fc39dcb7
PH
818 cr30 = (SIS_VB_OUTPUT_HIVISION
819 | SIS_SIMULTANEOUS_VIEW_ENABLE);
fd26d420 820 else if (xgifb_info->TV_plug == TVPLUG_SVIDEO)
fc39dcb7
PH
821 cr30 = (SIS_VB_OUTPUT_SVIDEO
822 | SIS_SIMULTANEOUS_VIEW_ENABLE);
fd26d420 823 else if (xgifb_info->TV_plug == TVPLUG_COMPOSITE)
fc39dcb7
PH
824 cr30 = (SIS_VB_OUTPUT_COMPOSITE
825 | SIS_SIMULTANEOUS_VIEW_ENABLE);
fd26d420 826 else if (xgifb_info->TV_plug == TVPLUG_SCART)
fc39dcb7
PH
827 cr30 = (SIS_VB_OUTPUT_SCART
828 | SIS_SIMULTANEOUS_VIEW_ENABLE);
829 cr31 |= SIS_DRIVER_MODE;
d7636e0b 830
fd26d420 831 if (XGIfb_tvmode == 1 || xgifb_info->TV_type == TVMODE_PAL)
c4fa7dfe
AK
832 cr31 |= 0x01;
833 else
834 cr31 &= ~0x01;
835 break;
836 default: /* disable CRT2 */
837 cr30 = 0x00;
fc39dcb7 838 cr31 |= (SIS_DRIVER_MODE | SIS_VB_OUTPUT_DISABLE);
d7636e0b 839 }
840
c4fa7dfe
AK
841 xgifb_reg_set(XGICR, IND_XGI_SCRATCH_REG_CR30, cr30);
842 xgifb_reg_set(XGICR, IND_XGI_SCRATCH_REG_CR31, cr31);
5aa55d9f
AK
843 xgifb_reg_set(XGICR, IND_XGI_SCRATCH_REG_CR33,
844 (xgifb_info->rate_idx & 0x0F));
c4fa7dfe 845}
d7636e0b 846
fd26d420 847static void XGIfb_post_setmode(struct xgifb_video_info *xgifb_info)
c4fa7dfe
AK
848{
849 u8 reg;
850 unsigned char doit = 1;
851 /*
fc39dcb7 852 xgifb_reg_set(XGISR,IND_SIS_PASSWORD,SIS_PASSWORD);
c4fa7dfe
AK
853 xgifb_reg_set(XGICR, 0x13, 0x00);
854 xgifb_reg_and_or(XGISR,0x0E, 0xF0, 0x01);
855 *test*
856 */
fd26d420 857 if (xgifb_info->video_bpp == 8) {
a12c27c5
KT
858 /* TW: We can't switch off CRT1 on LVDS/Chrontel
859 * in 8bpp Modes */
fd26d420
AK
860 if ((xgifb_info->hasVB == HASVB_LVDS) ||
861 (xgifb_info->hasVB == HASVB_LVDS_CHRONTEL)) {
c4fa7dfe
AK
862 doit = 0;
863 }
a12c27c5
KT
864 /* TW: We can't switch off CRT1 on 301B-DH
865 * in 8bpp Modes if using LCD */
289ea524 866 if (xgifb_info->display2 == XGIFB_DISP_LCD)
c4fa7dfe 867 doit = 0;
d7636e0b 868 }
869
c4fa7dfe 870 /* TW: We can't switch off CRT1 if bridge is in slave mode */
fd26d420 871 if (xgifb_info->hasVB != HASVB_NONE) {
c4fa7dfe 872 reg = xgifb_reg_get(XGIPART1, 0x00);
d7636e0b 873
c4fa7dfe
AK
874 if ((reg & 0x50) == 0x10)
875 doit = 0;
d7636e0b 876
c4fa7dfe
AK
877 } else {
878 XGIfb_crt1off = 0;
d7636e0b 879 }
880
c4fa7dfe
AK
881 reg = xgifb_reg_get(XGICR, 0x17);
882 if ((XGIfb_crt1off) && (doit))
883 reg &= ~0x80;
d7636e0b 884 else
c4fa7dfe
AK
885 reg |= 0x80;
886 xgifb_reg_set(XGICR, 0x17, reg);
d7636e0b 887
fc39dcb7 888 xgifb_reg_and(XGISR, IND_SIS_RAMDAC_CONTROL, ~0x04);
d7636e0b 889
289ea524
AK
890 if (xgifb_info->display2 == XGIFB_DISP_TV &&
891 xgifb_info->hasVB == HASVB_301) {
d7636e0b 892
c4fa7dfe 893 reg = xgifb_reg_get(XGIPART4, 0x01);
d7636e0b 894
c4fa7dfe 895 if (reg < 0xB0) { /* Set filter for XGI301 */
84a6c46e
AK
896 int filter_tb;
897
fd26d420 898 switch (xgifb_info->video_width) {
c4fa7dfe 899 case 320:
fd26d420 900 filter_tb = (xgifb_info->TV_type ==
a12c27c5 901 TVMODE_NTSC) ? 4 : 12;
c4fa7dfe
AK
902 break;
903 case 640:
fd26d420 904 filter_tb = (xgifb_info->TV_type ==
a12c27c5 905 TVMODE_NTSC) ? 5 : 13;
c4fa7dfe
AK
906 break;
907 case 720:
fd26d420 908 filter_tb = (xgifb_info->TV_type ==
a12c27c5 909 TVMODE_NTSC) ? 6 : 14;
c4fa7dfe
AK
910 break;
911 case 800:
fd26d420 912 filter_tb = (xgifb_info->TV_type ==
a12c27c5 913 TVMODE_NTSC) ? 7 : 15;
c4fa7dfe
AK
914 break;
915 default:
84a6c46e 916 filter_tb = 0;
c4fa7dfe
AK
917 filter = -1;
918 break;
919 }
39f10bf1 920 xgifb_reg_or(XGIPART1,
fc39dcb7 921 SIS_CRT2_WENABLE_315,
39f10bf1 922 0x01);
d7636e0b 923
fd26d420 924 if (xgifb_info->TV_type == TVMODE_NTSC) {
d7636e0b 925
c4fa7dfe 926 xgifb_reg_and(XGIPART2, 0x3a, 0x1f);
d7636e0b 927
fd26d420 928 if (xgifb_info->TV_plug == TVPLUG_SVIDEO) {
c4fa7dfe
AK
929
930 xgifb_reg_and(XGIPART2, 0x30, 0xdf);
931
fd26d420 932 } else if (xgifb_info->TV_plug
c4fa7dfe
AK
933 == TVPLUG_COMPOSITE) {
934
935 xgifb_reg_or(XGIPART2, 0x30, 0x20);
936
fd26d420 937 switch (xgifb_info->video_width) {
c4fa7dfe 938 case 640:
a12c27c5
KT
939 xgifb_reg_set(XGIPART2,
940 0x35,
941 0xEB);
942 xgifb_reg_set(XGIPART2,
943 0x36,
944 0x04);
945 xgifb_reg_set(XGIPART2,
946 0x37,
947 0x25);
948 xgifb_reg_set(XGIPART2,
949 0x38,
950 0x18);
c4fa7dfe
AK
951 break;
952 case 720:
a12c27c5
KT
953 xgifb_reg_set(XGIPART2,
954 0x35,
955 0xEE);
956 xgifb_reg_set(XGIPART2,
957 0x36,
958 0x0C);
959 xgifb_reg_set(XGIPART2,
960 0x37,
961 0x22);
962 xgifb_reg_set(XGIPART2,
963 0x38,
964 0x08);
c4fa7dfe
AK
965 break;
966 case 800:
a12c27c5
KT
967 xgifb_reg_set(XGIPART2,
968 0x35,
969 0xEB);
970 xgifb_reg_set(XGIPART2,
971 0x36,
972 0x15);
973 xgifb_reg_set(XGIPART2,
974 0x37,
975 0x25);
976 xgifb_reg_set(XGIPART2,
977 0x38,
978 0xF6);
c4fa7dfe
AK
979 break;
980 }
981 }
982
fd26d420 983 } else if (xgifb_info->TV_type == TVMODE_PAL) {
c4fa7dfe
AK
984
985 xgifb_reg_and(XGIPART2, 0x3A, 0x1F);
986
fd26d420 987 if (xgifb_info->TV_plug == TVPLUG_SVIDEO) {
c4fa7dfe
AK
988
989 xgifb_reg_and(XGIPART2, 0x30, 0xDF);
990
fd26d420 991 } else if (xgifb_info->TV_plug
c4fa7dfe
AK
992 == TVPLUG_COMPOSITE) {
993
994 xgifb_reg_or(XGIPART2, 0x30, 0x20);
995
fd26d420 996 switch (xgifb_info->video_width) {
c4fa7dfe 997 case 640:
a12c27c5
KT
998 xgifb_reg_set(XGIPART2,
999 0x35,
1000 0xF1);
1001 xgifb_reg_set(XGIPART2,
1002 0x36,
1003 0xF7);
1004 xgifb_reg_set(XGIPART2,
1005 0x37,
1006 0x1F);
1007 xgifb_reg_set(XGIPART2,
1008 0x38,
1009 0x32);
c4fa7dfe
AK
1010 break;
1011 case 720:
a12c27c5
KT
1012 xgifb_reg_set(XGIPART2,
1013 0x35,
1014 0xF3);
1015 xgifb_reg_set(XGIPART2,
1016 0x36,
1017 0x00);
1018 xgifb_reg_set(XGIPART2,
1019 0x37,
1020 0x1D);
1021 xgifb_reg_set(XGIPART2,
1022 0x38,
1023 0x20);
c4fa7dfe
AK
1024 break;
1025 case 800:
a12c27c5
KT
1026 xgifb_reg_set(XGIPART2,
1027 0x35,
1028 0xFC);
1029 xgifb_reg_set(XGIPART2,
1030 0x36,
1031 0xFB);
1032 xgifb_reg_set(XGIPART2,
1033 0x37,
1034 0x14);
1035 xgifb_reg_set(XGIPART2,
1036 0x38,
1037 0x2A);
c4fa7dfe
AK
1038 break;
1039 }
1040 }
1041 }
1042
1043 if ((filter >= 0) && (filter <= 7)) {
a12c27c5
KT
1044 DPRINTK("FilterTable[%d]-%d: %02x %02x %02x %02x\n",
1045 filter_tb, filter,
1046 XGI_TV_filter[filter_tb].
1047 filter[filter][0],
1048 XGI_TV_filter[filter_tb].
1049 filter[filter][1],
1050 XGI_TV_filter[filter_tb].
1051 filter[filter][2],
1052 XGI_TV_filter[filter_tb].
1053 filter[filter][3]
c4fa7dfe
AK
1054 );
1055 xgifb_reg_set(
a12c27c5
KT
1056 XGIPART2,
1057 0x35,
1058 (XGI_TV_filter[filter_tb].
1059 filter[filter][0]));
c4fa7dfe 1060 xgifb_reg_set(
a12c27c5
KT
1061 XGIPART2,
1062 0x36,
1063 (XGI_TV_filter[filter_tb].
1064 filter[filter][1]));
c4fa7dfe 1065 xgifb_reg_set(
a12c27c5
KT
1066 XGIPART2,
1067 0x37,
1068 (XGI_TV_filter[filter_tb].
1069 filter[filter][2]));
c4fa7dfe 1070 xgifb_reg_set(
a12c27c5
KT
1071 XGIPART2,
1072 0x38,
1073 (XGI_TV_filter[filter_tb].
1074 filter[filter][3]));
c4fa7dfe 1075 }
c4fa7dfe 1076 }
c4fa7dfe 1077 }
c4fa7dfe
AK
1078}
1079
1080static int XGIfb_do_set_var(struct fb_var_screeninfo *var, int isactive,
1081 struct fb_info *info)
1082{
fd26d420
AK
1083 struct xgifb_video_info *xgifb_info = info->par;
1084 struct xgi_hw_device_info *hw_info = &xgifb_info->hw_info;
c4fa7dfe
AK
1085 unsigned int htotal = var->left_margin + var->xres + var->right_margin
1086 + var->hsync_len;
1087 unsigned int vtotal = var->upper_margin + var->yres + var->lower_margin
1088 + var->vsync_len;
1089#if defined(__powerpc__)
ef23b210 1090 u8 cr_data;
c4fa7dfe
AK
1091#endif
1092 unsigned int drate = 0, hrate = 0;
1093 int found_mode = 0;
1094 int old_mode;
1095 /* unsigned char reg, reg1; */
1096
1097 DEBUGPRN("Inside do_set_var");
1098 /* printk(KERN_DEBUG "XGIfb:var->yres=%d, var->upper_margin=%d, var->lower_margin=%d, var->vsync_len=%d\n", var->yres, var->upper_margin, var->lower_margin, var->vsync_len); */
1099
1100 info->var.xres_virtual = var->xres_virtual;
1101 info->var.yres_virtual = var->yres_virtual;
1102 info->var.bits_per_pixel = var->bits_per_pixel;
1103
1104 if ((var->vmode & FB_VMODE_MASK) == FB_VMODE_NONINTERLACED)
1105 vtotal <<= 1;
1106 else if ((var->vmode & FB_VMODE_MASK) == FB_VMODE_DOUBLE)
1107 vtotal <<= 2;
1108 else if ((var->vmode & FB_VMODE_MASK) == FB_VMODE_INTERLACED) {
1109 /* vtotal <<= 1; */
1110 /* var->yres <<= 1; */
1111 }
1112
1113 if (!htotal || !vtotal) {
1114 DPRINTK("XGIfb: Invalid 'var' information\n");
1115 return -EINVAL;
4a6b1518 1116 } pr_debug("var->pixclock=%d, htotal=%d, vtotal=%d\n",
c4fa7dfe
AK
1117 var->pixclock, htotal, vtotal);
1118
1119 if (var->pixclock && htotal && vtotal) {
1120 drate = 1000000000 / var->pixclock;
1121 hrate = (drate * 1000) / htotal;
fd26d420 1122 xgifb_info->refresh_rate = (unsigned int) (hrate * 2
c4fa7dfe
AK
1123 / vtotal);
1124 } else {
fd26d420 1125 xgifb_info->refresh_rate = 60;
c4fa7dfe
AK
1126 }
1127
4a6b1518 1128 pr_debug("Change mode to %dx%dx%d-%dHz\n",
a12c27c5
KT
1129 var->xres,
1130 var->yres,
1131 var->bits_per_pixel,
fd26d420 1132 xgifb_info->refresh_rate);
c4fa7dfe 1133
ccf265ad
AK
1134 old_mode = xgifb_info->mode_idx;
1135 xgifb_info->mode_idx = 0;
c4fa7dfe 1136
ccf265ad
AK
1137 while ((XGIbios_mode[xgifb_info->mode_idx].mode_no != 0) &&
1138 (XGIbios_mode[xgifb_info->mode_idx].xres <= var->xres)) {
1139 if ((XGIbios_mode[xgifb_info->mode_idx].xres == var->xres) &&
1140 (XGIbios_mode[xgifb_info->mode_idx].yres == var->yres) &&
1141 (XGIbios_mode[xgifb_info->mode_idx].bpp
c4fa7dfe 1142 == var->bits_per_pixel)) {
c4fa7dfe
AK
1143 found_mode = 1;
1144 break;
1145 }
ccf265ad 1146 xgifb_info->mode_idx++;
c4fa7dfe
AK
1147 }
1148
1149 if (found_mode)
ccf265ad
AK
1150 xgifb_info->mode_idx = XGIfb_validate_mode(xgifb_info,
1151 xgifb_info->mode_idx);
c4fa7dfe 1152 else
ccf265ad 1153 xgifb_info->mode_idx = -1;
c4fa7dfe 1154
ccf265ad 1155 if (xgifb_info->mode_idx < 0) {
4a6b1518 1156 pr_err("Mode %dx%dx%d not supported\n",
a12c27c5 1157 var->xres, var->yres, var->bits_per_pixel);
ccf265ad 1158 xgifb_info->mode_idx = old_mode;
c4fa7dfe
AK
1159 return -EINVAL;
1160 }
1161
fd26d420
AK
1162 if (XGIfb_search_refresh_rate(xgifb_info,
1163 xgifb_info->refresh_rate) == 0) {
5aa55d9f
AK
1164 xgifb_info->rate_idx =
1165 XGIbios_mode[xgifb_info->mode_idx].rate_idx;
fd26d420 1166 xgifb_info->refresh_rate = 60;
c4fa7dfe
AK
1167 }
1168
1169 if (isactive) {
1170
fd26d420 1171 XGIfb_pre_setmode(xgifb_info);
fab04b97 1172 if (XGISetModeNew(xgifb_info, hw_info,
ccf265ad
AK
1173 XGIbios_mode[xgifb_info->mode_idx].mode_no)
1174 == 0) {
4a6b1518 1175 pr_err("Setting mode[0x%x] failed\n",
ccf265ad 1176 XGIbios_mode[xgifb_info->mode_idx].mode_no);
c4fa7dfe
AK
1177 return -EINVAL;
1178 }
1179 info->fix.line_length = ((info->var.xres_virtual
1180 * info->var.bits_per_pixel) >> 6);
1181
fc39dcb7 1182 xgifb_reg_set(XGISR, IND_SIS_PASSWORD, SIS_PASSWORD);
c4fa7dfe
AK
1183
1184 xgifb_reg_set(XGICR, 0x13, (info->fix.line_length & 0x00ff));
a12c27c5
KT
1185 xgifb_reg_set(XGISR,
1186 0x0E,
1187 (info->fix.line_length & 0xff00) >> 8);
c4fa7dfe 1188
fd26d420 1189 XGIfb_post_setmode(xgifb_info);
c4fa7dfe
AK
1190
1191 DPRINTK("XGIfb: Set new mode: %dx%dx%d-%d\n",
ccf265ad
AK
1192 XGIbios_mode[xgifb_info->mode_idx].xres,
1193 XGIbios_mode[xgifb_info->mode_idx].yres,
1194 XGIbios_mode[xgifb_info->mode_idx].bpp,
fd26d420
AK
1195 xgifb_info->refresh_rate);
1196
ccf265ad 1197 xgifb_info->video_bpp = XGIbios_mode[xgifb_info->mode_idx].bpp;
fd26d420 1198 xgifb_info->video_vwidth = info->var.xres_virtual;
ccf265ad
AK
1199 xgifb_info->video_width =
1200 XGIbios_mode[xgifb_info->mode_idx].xres;
fd26d420 1201 xgifb_info->video_vheight = info->var.yres_virtual;
ccf265ad
AK
1202 xgifb_info->video_height =
1203 XGIbios_mode[xgifb_info->mode_idx].yres;
fd26d420
AK
1204 xgifb_info->org_x = xgifb_info->org_y = 0;
1205 xgifb_info->video_linelength = info->var.xres_virtual
1206 * (xgifb_info->video_bpp >> 3);
1207 switch (xgifb_info->video_bpp) {
c4fa7dfe 1208 case 8:
fd26d420
AK
1209 xgifb_info->DstColor = 0x0000;
1210 xgifb_info->XGI310_AccelDepth = 0x00000000;
1211 xgifb_info->video_cmap_len = 256;
c4fa7dfe
AK
1212#if defined(__powerpc__)
1213 cr_data = xgifb_reg_get(XGICR, 0x4D);
1214 xgifb_reg_set(XGICR, 0x4D, (cr_data & 0xE0));
1215#endif
1216 break;
1217 case 16:
fd26d420
AK
1218 xgifb_info->DstColor = 0x8000;
1219 xgifb_info->XGI310_AccelDepth = 0x00010000;
d7636e0b 1220#if defined(__powerpc__)
7e119b75 1221 cr_data = xgifb_reg_get(XGICR, 0x4D);
b6e2dc39 1222 xgifb_reg_set(XGICR, 0x4D, ((cr_data & 0xE0) | 0x0B));
d7636e0b 1223#endif
fd26d420 1224 xgifb_info->video_cmap_len = 16;
b654f878
PS
1225 break;
1226 case 32:
fd26d420
AK
1227 xgifb_info->DstColor = 0xC000;
1228 xgifb_info->XGI310_AccelDepth = 0x00020000;
1229 xgifb_info->video_cmap_len = 16;
d7636e0b 1230#if defined(__powerpc__)
7e119b75 1231 cr_data = xgifb_reg_get(XGICR, 0x4D);
b6e2dc39 1232 xgifb_reg_set(XGICR, 0x4D, ((cr_data & 0xE0) | 0x15));
d7636e0b 1233#endif
b654f878
PS
1234 break;
1235 default:
fd26d420 1236 xgifb_info->video_cmap_len = 16;
4a6b1518 1237 pr_err("Unsupported depth %d",
fd26d420 1238 xgifb_info->video_bpp);
b654f878
PS
1239 break;
1240 }
d7636e0b 1241 }
fd26d420 1242 XGIfb_bpp_to_var(xgifb_info, var); /*update ARGB info*/
d7636e0b 1243 DEBUGPRN("End of do_set_var");
1244
1245 dumpVGAReg();
1246 return 0;
1247}
1248
0d5c6ca3 1249static int XGIfb_pan_var(struct fb_var_screeninfo *var, struct fb_info *info)
d7636e0b 1250{
acff987d 1251 struct xgifb_video_info *xgifb_info = info->par;
d7636e0b 1252 unsigned int base;
1253
b654f878 1254 /* printk("Inside pan_var"); */
d7636e0b 1255
0d5c6ca3 1256 base = var->yoffset * info->var.xres_virtual + var->xoffset;
d7636e0b 1257
b654f878 1258 /* calculate base bpp dep. */
0d5c6ca3 1259 switch (info->var.bits_per_pixel) {
b654f878
PS
1260 case 16:
1261 base >>= 1;
1262 break;
d7636e0b 1263 case 32:
b654f878 1264 break;
d7636e0b 1265 case 8:
b654f878
PS
1266 default:
1267 base >>= 2;
1268 break;
1269 }
d7636e0b 1270
fc39dcb7 1271 xgifb_reg_set(XGISR, IND_SIS_PASSWORD, SIS_PASSWORD);
d7636e0b 1272
b6e2dc39
AK
1273 xgifb_reg_set(XGICR, 0x0D, base & 0xFF);
1274 xgifb_reg_set(XGICR, 0x0C, (base >> 8) & 0xFF);
1275 xgifb_reg_set(XGISR, 0x0D, (base >> 16) & 0xFF);
1276 xgifb_reg_set(XGISR, 0x37, (base >> 24) & 0x03);
65283d42 1277 xgifb_reg_and_or(XGISR, 0x37, 0xDF, (base >> 21) & 0x04);
d7636e0b 1278
289ea524 1279 if (xgifb_info->display2 != XGIFB_DISP_NONE) {
fc39dcb7 1280 xgifb_reg_or(XGIPART1, SIS_CRT2_WENABLE_315, 0x01);
b6e2dc39
AK
1281 xgifb_reg_set(XGIPART1, 0x06, (base & 0xFF));
1282 xgifb_reg_set(XGIPART1, 0x05, ((base >> 8) & 0xFF));
1283 xgifb_reg_set(XGIPART1, 0x04, ((base >> 16) & 0xFF));
a12c27c5
KT
1284 xgifb_reg_and_or(XGIPART1,
1285 0x02,
1286 0x7F,
1287 ((base >> 24) & 0x01) << 7);
b654f878
PS
1288 }
1289 /* printk("End of pan_var"); */
d7636e0b 1290 return 0;
1291}
d7636e0b 1292
d7636e0b 1293static int XGIfb_open(struct fb_info *info, int user)
1294{
b654f878 1295 return 0;
d7636e0b 1296}
1297
1298static int XGIfb_release(struct fb_info *info, int user)
1299{
b654f878 1300 return 0;
d7636e0b 1301}
1302
1303static int XGIfb_get_cmap_len(const struct fb_var_screeninfo *var)
1304{
1305 int rc = 16;
1306
b654f878 1307 switch (var->bits_per_pixel) {
d7636e0b 1308 case 8:
1309 rc = 256;
1310 break;
1311 case 16:
1312 rc = 16;
1313 break;
1314 case 32:
1315 rc = 16;
1316 break;
1317 }
1318 return rc;
1319}
1320
b654f878
PS
1321static int XGIfb_setcolreg(unsigned regno, unsigned red, unsigned green,
1322 unsigned blue, unsigned transp, struct fb_info *info)
d7636e0b 1323{
fd26d420
AK
1324 struct xgifb_video_info *xgifb_info = info->par;
1325
d7636e0b 1326 if (regno >= XGIfb_get_cmap_len(&info->var))
1327 return 1;
1328
1329 switch (info->var.bits_per_pixel) {
1330 case 8:
e3d5ceb0
AK
1331 outb(regno, XGIDACA);
1332 outb((red >> 10), XGIDACD);
1333 outb((green >> 10), XGIDACD);
1334 outb((blue >> 10), XGIDACD);
289ea524 1335 if (xgifb_info->display2 != XGIFB_DISP_NONE) {
e3d5ceb0
AK
1336 outb(regno, XGIDAC2A);
1337 outb((red >> 8), XGIDAC2D);
1338 outb((green >> 8), XGIDAC2D);
1339 outb((blue >> 8), XGIDAC2D);
d7636e0b 1340 }
1341 break;
1342 case 16:
b654f878
PS
1343 ((u32 *) (info->pseudo_palette))[regno] = ((red & 0xf800))
1344 | ((green & 0xfc00) >> 5) | ((blue & 0xf800)
1345 >> 11);
d7636e0b 1346 break;
1347 case 32:
1348 red >>= 8;
1349 green >>= 8;
1350 blue >>= 8;
b654f878
PS
1351 ((u32 *) (info->pseudo_palette))[regno] = (red << 16) | (green
1352 << 8) | (blue);
d7636e0b 1353 break;
1354 }
1355 return 0;
1356}
1357
c4fa7dfe
AK
1358/* ----------- FBDev related routines for all series ---------- */
1359
1360static int XGIfb_get_fix(struct fb_fix_screeninfo *fix, int con,
1361 struct fb_info *info)
1362{
fd26d420
AK
1363 struct xgifb_video_info *xgifb_info = info->par;
1364
c4fa7dfe
AK
1365 DEBUGPRN("inside get_fix");
1366 memset(fix, 0, sizeof(struct fb_fix_screeninfo));
1367
fd26d420 1368 fix->smem_start = xgifb_info->video_base;
c4fa7dfe 1369
fd26d420 1370 fix->smem_len = xgifb_info->video_size;
c4fa7dfe 1371
de351ba6 1372 fix->type = FB_TYPE_PACKED_PIXELS;
c4fa7dfe 1373 fix->type_aux = 0;
fd26d420 1374 if (xgifb_info->video_bpp == 8)
c4fa7dfe
AK
1375 fix->visual = FB_VISUAL_PSEUDOCOLOR;
1376 else
1377 fix->visual = FB_VISUAL_DIRECTCOLOR;
1378 fix->xpanstep = 0;
c4fa7dfe
AK
1379 if (XGIfb_ypan)
1380 fix->ypanstep = 1;
c4fa7dfe 1381 fix->ywrapstep = 0;
fd26d420
AK
1382 fix->line_length = xgifb_info->video_linelength;
1383 fix->mmio_start = xgifb_info->mmio_base;
1384 fix->mmio_len = xgifb_info->mmio_size;
fc39dcb7 1385 fix->accel = FB_ACCEL_SIS_XABRE;
c4fa7dfe
AK
1386
1387 DEBUGPRN("end of get_fix");
1388 return 0;
1389}
1390
d7636e0b 1391static int XGIfb_set_par(struct fb_info *info)
1392{
1393 int err;
1394
b654f878
PS
1395 /* printk("XGIfb: inside set_par\n"); */
1396 err = XGIfb_do_set_var(&info->var, 1, info);
1397 if (err)
d7636e0b 1398 return err;
d7636e0b 1399 XGIfb_get_fix(&info->fix, -1, info);
b654f878 1400 /* printk("XGIfb: end of set_par\n"); */
d7636e0b 1401 return 0;
1402}
1403
b654f878 1404static int XGIfb_check_var(struct fb_var_screeninfo *var, struct fb_info *info)
d7636e0b 1405{
fd26d420 1406 struct xgifb_video_info *xgifb_info = info->par;
b654f878
PS
1407 unsigned int htotal = var->left_margin + var->xres + var->right_margin
1408 + var->hsync_len;
d7636e0b 1409 unsigned int vtotal = 0;
1410 unsigned int drate = 0, hrate = 0;
1411 int found_mode = 0;
1412 int refresh_rate, search_idx;
1413
1414 DEBUGPRN("Inside check_var");
1415
b654f878
PS
1416 if ((var->vmode & FB_VMODE_MASK) == FB_VMODE_NONINTERLACED) {
1417 vtotal = var->upper_margin + var->yres + var->lower_margin
1418 + var->vsync_len;
d7636e0b 1419 vtotal <<= 1;
b654f878
PS
1420 } else if ((var->vmode & FB_VMODE_MASK) == FB_VMODE_DOUBLE) {
1421 vtotal = var->upper_margin + var->yres + var->lower_margin
1422 + var->vsync_len;
d7636e0b 1423 vtotal <<= 2;
b654f878
PS
1424 } else if ((var->vmode & FB_VMODE_MASK) == FB_VMODE_INTERLACED) {
1425 vtotal = var->upper_margin + (var->yres / 2)
1426 + var->lower_margin + var->vsync_len;
1427 } else
1428 vtotal = var->upper_margin + var->yres + var->lower_margin
1429 + var->vsync_len;
d7636e0b 1430
b654f878 1431 if (!(htotal) || !(vtotal))
d7636e0b 1432 XGIFAIL("XGIfb: no valid timing data");
d7636e0b 1433
b654f878
PS
1434 if (var->pixclock && htotal && vtotal) {
1435 drate = 1000000000 / var->pixclock;
1436 hrate = (drate * 1000) / htotal;
fd26d420 1437 xgifb_info->refresh_rate =
a12c27c5 1438 (unsigned int) (hrate * 2 / vtotal);
4a6b1518 1439 pr_debug(
b654f878
PS
1440 "%s: pixclock = %d ,htotal=%d, vtotal=%d\n"
1441 "%s: drate=%d, hrate=%d, refresh_rate=%d\n",
1442 __func__, var->pixclock, htotal, vtotal,
fd26d420 1443 __func__, drate, hrate, xgifb_info->refresh_rate);
b654f878 1444 } else {
fd26d420 1445 xgifb_info->refresh_rate = 60;
b654f878 1446 }
d7636e0b 1447
b654f878
PS
1448 /*
1449 if ((var->pixclock) && (htotal)) {
1450 drate = 1E12 / var->pixclock;
1451 hrate = drate / htotal;
1452 refresh_rate = (unsigned int) (hrate / vtotal * 2 + 0.5);
1453 } else {
1454 refresh_rate = 60;
1455 }
1456 */
d7636e0b 1457 /* TW: Calculation wrong for 1024x600 - force it to 60Hz */
b654f878
PS
1458 if ((var->xres == 1024) && (var->yres == 600))
1459 refresh_rate = 60;
d7636e0b 1460
1461 search_idx = 0;
b654f878
PS
1462 while ((XGIbios_mode[search_idx].mode_no != 0) &&
1463 (XGIbios_mode[search_idx].xres <= var->xres)) {
1464 if ((XGIbios_mode[search_idx].xres == var->xres) &&
1465 (XGIbios_mode[search_idx].yres == var->yres) &&
1466 (XGIbios_mode[search_idx].bpp == var->bits_per_pixel)) {
fd26d420 1467 if (XGIfb_validate_mode(xgifb_info, search_idx) > 0) {
b654f878
PS
1468 found_mode = 1;
1469 break;
1470 }
1471 }
d7636e0b 1472 search_idx++;
1473 }
1474
b654f878 1475 if (!found_mode) {
d7636e0b 1476
4a6b1518 1477 pr_err("%dx%dx%d is no valid mode\n",
d7636e0b 1478 var->xres, var->yres, var->bits_per_pixel);
b654f878
PS
1479 search_idx = 0;
1480 while (XGIbios_mode[search_idx].mode_no != 0) {
b654f878 1481 if ((var->xres <= XGIbios_mode[search_idx].xres) &&
a12c27c5
KT
1482 (var->yres <= XGIbios_mode[search_idx].yres) &&
1483 (var->bits_per_pixel ==
1484 XGIbios_mode[search_idx].bpp)) {
fd26d420
AK
1485 if (XGIfb_validate_mode(xgifb_info,
1486 search_idx) > 0) {
b654f878
PS
1487 found_mode = 1;
1488 break;
1489 }
1490 }
1491 search_idx++;
1492 }
1493 if (found_mode) {
d7636e0b 1494 var->xres = XGIbios_mode[search_idx].xres;
b654f878 1495 var->yres = XGIbios_mode[search_idx].yres;
4a6b1518 1496 pr_debug("Adapted to mode %dx%dx%d\n",
b654f878 1497 var->xres, var->yres, var->bits_per_pixel);
d7636e0b 1498
1499 } else {
4a6b1518 1500 pr_err("Failed to find similar mode to %dx%dx%d\n",
d7636e0b 1501 var->xres, var->yres, var->bits_per_pixel);
b654f878 1502 return -EINVAL;
d7636e0b 1503 }
1504 }
1505
1506 /* TW: TODO: Check the refresh rate */
1507
1508 /* Adapt RGB settings */
fd26d420 1509 XGIfb_bpp_to_var(xgifb_info, var);
d7636e0b 1510
1511 /* Sanity check for offsets */
1512 if (var->xoffset < 0)
1513 var->xoffset = 0;
1514 if (var->yoffset < 0)
1515 var->yoffset = 0;
1516
b654f878
PS
1517 if (!XGIfb_ypan) {
1518 if (var->xres != var->xres_virtual)
1519 var->xres_virtual = var->xres;
1520 if (var->yres != var->yres_virtual)
d7636e0b 1521 var->yres_virtual = var->yres;
b654f878
PS
1522 } /* else { */
1523 /* TW: Now patch yres_virtual if we use panning */
1524 /* May I do this? */
fd26d420 1525 /* var->yres_virtual = xgifb_info->heapstart /
a12c27c5 1526 (var->xres * (var->bits_per_pixel >> 3)); */
b654f878
PS
1527 /* if (var->yres_virtual <= var->yres) { */
1528 /* TW: Paranoia check */
1529 /* var->yres_virtual = var->yres; */
1530 /* } */
1531 /* } */
d7636e0b 1532
1533 /* Truncate offsets to maximum if too high */
1534 if (var->xoffset > var->xres_virtual - var->xres)
1535 var->xoffset = var->xres_virtual - var->xres - 1;
1536
1537 if (var->yoffset > var->yres_virtual - var->yres)
1538 var->yoffset = var->yres_virtual - var->yres - 1;
1539
1540 /* Set everything else to 0 */
1541 var->red.msb_right =
b654f878
PS
1542 var->green.msb_right =
1543 var->blue.msb_right =
1544 var->transp.offset = var->transp.length = var->transp.msb_right = 0;
d7636e0b 1545
1546 DEBUGPRN("end of check_var");
1547 return 0;
1548}
1549
b654f878
PS
1550static int XGIfb_pan_display(struct fb_var_screeninfo *var,
1551 struct fb_info *info)
d7636e0b 1552{
1553 int err;
1554
b654f878 1555 /* printk("\nInside pan_display:\n"); */
d7636e0b 1556
0d5c6ca3 1557 if (var->xoffset > (info->var.xres_virtual - info->var.xres))
d7636e0b 1558 return -EINVAL;
0d5c6ca3 1559 if (var->yoffset > (info->var.yres_virtual - info->var.yres))
d7636e0b 1560 return -EINVAL;
1561
1562 if (var->vmode & FB_VMODE_YWRAP) {
b654f878
PS
1563 if (var->yoffset < 0 || var->yoffset >= info->var.yres_virtual
1564 || var->xoffset)
1565 return -EINVAL;
d7636e0b 1566 } else {
b654f878
PS
1567 if (var->xoffset + info->var.xres > info->var.xres_virtual
1568 || var->yoffset + info->var.yres
1569 > info->var.yres_virtual)
d7636e0b 1570 return -EINVAL;
1571 }
0d5c6ca3 1572 err = XGIfb_pan_var(var, info);
b654f878
PS
1573 if (err < 0)
1574 return err;
d7636e0b 1575
1576 info->var.xoffset = var->xoffset;
1577 info->var.yoffset = var->yoffset;
1578 if (var->vmode & FB_VMODE_YWRAP)
1579 info->var.vmode |= FB_VMODE_YWRAP;
1580 else
1581 info->var.vmode &= ~FB_VMODE_YWRAP;
1582
b654f878 1583 /* printk("End of pan_display\n"); */
d7636e0b 1584 return 0;
1585}
d7636e0b 1586
d7636e0b 1587static int XGIfb_blank(int blank, struct fb_info *info)
1588{
f2df8c09 1589 struct xgifb_video_info *xgifb_info = info->par;
d7636e0b 1590 u8 reg;
1591
7e119b75 1592 reg = xgifb_reg_get(XGICR, 0x17);
d7636e0b 1593
b654f878 1594 if (blank > 0)
d7636e0b 1595 reg &= 0x7f;
1596 else
1597 reg |= 0x80;
1598
b6e2dc39
AK
1599 xgifb_reg_set(XGICR, 0x17, reg);
1600 xgifb_reg_set(XGISR, 0x00, 0x01); /* Synchronous Reset */
1601 xgifb_reg_set(XGISR, 0x00, 0x03); /* End Reset */
b654f878 1602 return 0;
d7636e0b 1603}
1604
d7636e0b 1605static struct fb_ops XGIfb_ops = {
b654f878
PS
1606 .owner = THIS_MODULE,
1607 .fb_open = XGIfb_open,
1608 .fb_release = XGIfb_release,
d7636e0b 1609 .fb_check_var = XGIfb_check_var,
b654f878 1610 .fb_set_par = XGIfb_set_par,
d7636e0b 1611 .fb_setcolreg = XGIfb_setcolreg,
b654f878 1612 .fb_pan_display = XGIfb_pan_display,
b654f878 1613 .fb_blank = XGIfb_blank,
1b402967 1614 .fb_fillrect = cfb_fillrect,
85c3c562 1615 .fb_copyarea = cfb_copyarea,
d7636e0b 1616 .fb_imageblit = cfb_imageblit,
b654f878 1617 /* .fb_mmap = XGIfb_mmap, */
d7636e0b 1618};
1619
1620/* ---------------- Chip generation dependent routines ---------------- */
1621
d7636e0b 1622/* for XGI 315/550/650/740/330 */
1623
fd26d420 1624static int XGIfb_get_dram_size(struct xgifb_video_info *xgifb_info)
d7636e0b 1625{
1626
b654f878
PS
1627 u8 ChannelNum, tmp;
1628 u8 reg = 0;
d7636e0b 1629
1630 /* xorg driver sets 32MB * 1 channel */
fd26d420 1631 if (xgifb_info->chip == XG27)
fc39dcb7 1632 xgifb_reg_set(XGISR, IND_SIS_DRAM_SIZE, 0x51);
d7636e0b 1633
fc39dcb7 1634 reg = xgifb_reg_get(XGISR, IND_SIS_DRAM_SIZE);
b654f878
PS
1635 switch ((reg & XGI_DRAM_SIZE_MASK) >> 4) {
1636 case XGI_DRAM_SIZE_1MB:
fd26d420 1637 xgifb_info->video_size = 0x100000;
b654f878
PS
1638 break;
1639 case XGI_DRAM_SIZE_2MB:
fd26d420 1640 xgifb_info->video_size = 0x200000;
b654f878
PS
1641 break;
1642 case XGI_DRAM_SIZE_4MB:
fd26d420 1643 xgifb_info->video_size = 0x400000;
b654f878
PS
1644 break;
1645 case XGI_DRAM_SIZE_8MB:
fd26d420 1646 xgifb_info->video_size = 0x800000;
b654f878
PS
1647 break;
1648 case XGI_DRAM_SIZE_16MB:
fd26d420 1649 xgifb_info->video_size = 0x1000000;
b654f878
PS
1650 break;
1651 case XGI_DRAM_SIZE_32MB:
fd26d420 1652 xgifb_info->video_size = 0x2000000;
b654f878
PS
1653 break;
1654 case XGI_DRAM_SIZE_64MB:
fd26d420 1655 xgifb_info->video_size = 0x4000000;
b654f878
PS
1656 break;
1657 case XGI_DRAM_SIZE_128MB:
fd26d420 1658 xgifb_info->video_size = 0x8000000;
b654f878
PS
1659 break;
1660 case XGI_DRAM_SIZE_256MB:
fd26d420 1661 xgifb_info->video_size = 0x10000000;
b654f878
PS
1662 break;
1663 default:
1664 return -1;
1665 }
d7636e0b 1666
b654f878 1667 tmp = (reg & 0x0c) >> 2;
fd26d420 1668 switch (xgifb_info->chip) {
b654f878
PS
1669 case XG20:
1670 case XG21:
1671 case XG27:
1672 ChannelNum = 1;
1673 break;
d7636e0b 1674
b654f878
PS
1675 case XG42:
1676 if (reg & 0x04)
1677 ChannelNum = 2;
1678 else
1679 ChannelNum = 1;
1680 break;
d7636e0b 1681
b654f878
PS
1682 case XG45:
1683 if (tmp == 1)
1684 ChannelNum = 2;
1685 else if (tmp == 2)
1686 ChannelNum = 3;
1687 else if (tmp == 3)
1688 ChannelNum = 4;
1689 else
1690 ChannelNum = 1;
1691 break;
d7636e0b 1692
b654f878
PS
1693 case XG40:
1694 default:
1695 if (tmp == 2)
1696 ChannelNum = 2;
1697 else if (tmp == 3)
1698 ChannelNum = 3;
1699 else
1700 ChannelNum = 1;
1701 break;
1702 }
1703
fd26d420 1704 xgifb_info->video_size = xgifb_info->video_size * ChannelNum;
b654f878 1705 /* PLiad fixed for benchmarking and fb set */
fd26d420
AK
1706 /* xgifb_info->video_size = 0x200000; */ /* 1024x768x16 */
1707 /* xgifb_info->video_size = 0x1000000; */ /* benchmark */
b654f878 1708
4a6b1518 1709 pr_info("SR14=%x DramSzie %x ChannelNum %x\n",
a12c27c5 1710 reg,
fd26d420 1711 xgifb_info->video_size, ChannelNum);
b654f878 1712 return 0;
d7636e0b 1713
1714}
1715
fd26d420 1716static void XGIfb_detect_VB(struct xgifb_video_info *xgifb_info)
d7636e0b 1717{
b654f878 1718 u8 cr32, temp = 0;
d7636e0b 1719
fd26d420 1720 xgifb_info->TV_plug = xgifb_info->TV_type = 0;
d7636e0b 1721
fd26d420 1722 switch (xgifb_info->hasVB) {
b654f878
PS
1723 case HASVB_LVDS_CHRONTEL:
1724 case HASVB_CHRONTEL:
1725 break;
1726 case HASVB_301:
1727 case HASVB_302:
1728 /* XGI_Sense30x(); */ /* Yi-Lin TV Sense? */
1729 break;
d7636e0b 1730 }
1731
7e119b75 1732 cr32 = xgifb_reg_get(XGICR, IND_XGI_SCRATCH_REG_CR32);
d7636e0b 1733
fc39dcb7 1734 if ((cr32 & SIS_CRT1) && !XGIfb_crt1off)
d7636e0b 1735 XGIfb_crt1off = 0;
1736 else {
1737 if (cr32 & 0x5F)
1738 XGIfb_crt1off = 1;
1739 else
1740 XGIfb_crt1off = 0;
1741 }
1742
25aa75f1 1743 if (!xgifb_info->display2_force) {
fc39dcb7 1744 if (cr32 & SIS_VB_TV)
25aa75f1 1745 xgifb_info->display2 = XGIFB_DISP_TV;
fc39dcb7 1746 else if (cr32 & SIS_VB_LCD)
25aa75f1 1747 xgifb_info->display2 = XGIFB_DISP_LCD;
fc39dcb7 1748 else if (cr32 & SIS_VB_CRT2)
25aa75f1
AK
1749 xgifb_info->display2 = XGIFB_DISP_CRT;
1750 else
1751 xgifb_info->display2 = XGIFB_DISP_NONE;
1752 }
d7636e0b 1753
b654f878 1754 if (XGIfb_tvplug != -1)
d7636e0b 1755 /* PR/TW: Override with option */
fd26d420 1756 xgifb_info->TV_plug = XGIfb_tvplug;
fc39dcb7 1757 else if (cr32 & SIS_VB_HIVISION) {
fd26d420
AK
1758 xgifb_info->TV_type = TVMODE_HIVISION;
1759 xgifb_info->TV_plug = TVPLUG_SVIDEO;
fc39dcb7 1760 } else if (cr32 & SIS_VB_SVIDEO)
fd26d420 1761 xgifb_info->TV_plug = TVPLUG_SVIDEO;
fc39dcb7 1762 else if (cr32 & SIS_VB_COMPOSITE)
fd26d420 1763 xgifb_info->TV_plug = TVPLUG_COMPOSITE;
fc39dcb7 1764 else if (cr32 & SIS_VB_SCART)
fd26d420 1765 xgifb_info->TV_plug = TVPLUG_SCART;
d7636e0b 1766
fd26d420 1767 if (xgifb_info->TV_type == 0) {
7e119b75 1768 temp = xgifb_reg_get(XGICR, 0x38);
ebe7846d 1769 if (temp & 0x10)
fd26d420 1770 xgifb_info->TV_type = TVMODE_PAL;
ebe7846d 1771 else
fd26d420 1772 xgifb_info->TV_type = TVMODE_NTSC;
d7636e0b 1773 }
1774
1775 /* TW: Copy forceCRT1 option to CRT1off if option is given */
b654f878
PS
1776 if (XGIfb_forcecrt1 != -1) {
1777 if (XGIfb_forcecrt1)
1778 XGIfb_crt1off = 0;
1779 else
1780 XGIfb_crt1off = 1;
1781 }
d7636e0b 1782}
1783
fd26d420 1784static int XGIfb_has_VB(struct xgifb_video_info *xgifb_info)
d7636e0b 1785{
1786 u8 vb_chipid;
1787
7e119b75 1788 vb_chipid = xgifb_reg_get(XGIPART4, 0x00);
d7636e0b 1789 switch (vb_chipid) {
b654f878 1790 case 0x01:
fd26d420 1791 xgifb_info->hasVB = HASVB_301;
d7636e0b 1792 break;
b654f878 1793 case 0x02:
fd26d420 1794 xgifb_info->hasVB = HASVB_302;
d7636e0b 1795 break;
b654f878 1796 default:
fd26d420 1797 xgifb_info->hasVB = HASVB_NONE;
dda08c59 1798 return 0;
d7636e0b 1799 }
dda08c59 1800 return 1;
d7636e0b 1801}
1802
fd26d420 1803static void XGIfb_get_VB_type(struct xgifb_video_info *xgifb_info)
c4fa7dfe
AK
1804{
1805 u8 reg;
1806
fd26d420 1807 if (!XGIfb_has_VB(xgifb_info)) {
c4fa7dfe 1808 reg = xgifb_reg_get(XGICR, IND_XGI_SCRATCH_REG_CR37);
fc39dcb7
PH
1809 switch ((reg & SIS_EXTERNAL_CHIP_MASK) >> 1) {
1810 case SIS_EXTERNAL_CHIP_LVDS:
fd26d420 1811 xgifb_info->hasVB = HASVB_LVDS;
c4fa7dfe 1812 break;
fc39dcb7 1813 case SIS_EXTERNAL_CHIP_LVDS_CHRONTEL:
fd26d420 1814 xgifb_info->hasVB = HASVB_LVDS_CHRONTEL;
c4fa7dfe
AK
1815 break;
1816 default:
1817 break;
1818 }
1819 }
1820}
1821
d27c6bc9
AK
1822static int __init xgifb_optval(char *fullopt, int validx)
1823{
1824 unsigned long lres;
1825
1826 if (kstrtoul(fullopt + validx, 0, &lres) < 0 || lres > INT_MAX) {
1827 pr_err("xgifb: invalid value for option: %s\n", fullopt);
1828 return 0;
1829 }
1830 return lres;
1831}
1832
032abf7b 1833static int __init XGIfb_setup(char *options)
d7636e0b 1834{
1835 char *this_opt;
1836
d7636e0b 1837 if (!options || !*options)
1838 return 0;
1839
79bea04c
AK
1840 pr_info("xgifb: options: %s\n", options);
1841
b654f878 1842 while ((this_opt = strsep(&options, ",")) != NULL) {
d7636e0b 1843
b654f878
PS
1844 if (!*this_opt)
1845 continue;
d7636e0b 1846
1847 if (!strncmp(this_opt, "mode:", 5)) {
dfbdf805 1848 mode = this_opt + 5;
d7636e0b 1849 } else if (!strncmp(this_opt, "vesa:", 5)) {
dfbdf805 1850 vesa = xgifb_optval(this_opt, 5);
d7636e0b 1851 } else if (!strncmp(this_opt, "vrate:", 6)) {
7548a83e 1852 refresh_rate = xgifb_optval(this_opt, 6);
d7636e0b 1853 } else if (!strncmp(this_opt, "rate:", 5)) {
7548a83e 1854 refresh_rate = xgifb_optval(this_opt, 5);
d7636e0b 1855 } else if (!strncmp(this_opt, "crt1off", 7)) {
1856 XGIfb_crt1off = 1;
1857 } else if (!strncmp(this_opt, "filter:", 7)) {
d27c6bc9 1858 filter = xgifb_optval(this_opt, 7);
d7636e0b 1859 } else if (!strncmp(this_opt, "forcecrt2type:", 14)) {
1860 XGIfb_search_crt2type(this_opt + 14);
1861 } else if (!strncmp(this_opt, "forcecrt1:", 10)) {
d27c6bc9 1862 XGIfb_forcecrt1 = xgifb_optval(this_opt, 10);
b654f878
PS
1863 } else if (!strncmp(this_opt, "tvmode:", 7)) {
1864 XGIfb_search_tvstd(this_opt + 7);
1865 } else if (!strncmp(this_opt, "tvstandard:", 11)) {
d7636e0b 1866 XGIfb_search_tvstd(this_opt + 7);
b654f878 1867 } else if (!strncmp(this_opt, "dstn", 4)) {
d7636e0b 1868 enable_dstn = 1;
1869 /* TW: DSTN overrules forcecrt2type */
289ea524 1870 XGIfb_crt2type = XGIFB_DISP_LCD;
d7636e0b 1871 } else if (!strncmp(this_opt, "noypan", 6)) {
b654f878 1872 XGIfb_ypan = 0;
d7636e0b 1873 } else {
dfbdf805 1874 mode = this_opt;
d7636e0b 1875 }
d7636e0b 1876 }
d7636e0b 1877 return 0;
1878}
d7636e0b 1879
8922967e 1880static int __devinit xgifb_probe(struct pci_dev *pdev,
b654f878 1881 const struct pci_device_id *ent)
d7636e0b 1882{
b654f878
PS
1883 u8 reg, reg1;
1884 u8 CR48, CR38;
bb292234 1885 int ret;
19c1e88e 1886 struct fb_info *fb_info;
fcbdda90
AK
1887 struct xgifb_video_info *xgifb_info;
1888 struct xgi_hw_device_info *hw_info;
bb292234 1889
fcbdda90 1890 fb_info = framebuffer_alloc(sizeof(*xgifb_info), &pdev->dev);
b654f878
PS
1891 if (!fb_info)
1892 return -ENOMEM;
1893
fcbdda90
AK
1894 xgifb_info = fb_info->par;
1895 hw_info = &xgifb_info->hw_info;
fd26d420
AK
1896 xgifb_info->fb_info = fb_info;
1897 xgifb_info->chip_id = pdev->device;
a12c27c5
KT
1898 pci_read_config_byte(pdev,
1899 PCI_REVISION_ID,
fd26d420
AK
1900 &xgifb_info->revision_id);
1901 hw_info->jChipRevision = xgifb_info->revision_id;
1902
1903 xgifb_info->pcibus = pdev->bus->number;
1904 xgifb_info->pcislot = PCI_SLOT(pdev->devfn);
1905 xgifb_info->pcifunc = PCI_FUNC(pdev->devfn);
1906 xgifb_info->subsysvendor = pdev->subsystem_vendor;
1907 xgifb_info->subsysdevice = pdev->subsystem_device;
1908
1909 xgifb_info->video_base = pci_resource_start(pdev, 0);
1910 xgifb_info->mmio_base = pci_resource_start(pdev, 1);
1911 xgifb_info->mmio_size = pci_resource_len(pdev, 1);
1912 xgifb_info->vga_base = pci_resource_start(pdev, 2) + 0x30;
4a6b1518 1913 pr_info("Relocate IO address: %lx [%08lx]\n",
f2df8c09 1914 (unsigned long)pci_resource_start(pdev, 2),
30b76816 1915 xgifb_info->vga_base);
b654f878 1916
bb292234
AK
1917 if (pci_enable_device(pdev)) {
1918 ret = -EIO;
1919 goto error;
1920 }
b654f878 1921
25aa75f1
AK
1922 if (XGIfb_crt2type != -1) {
1923 xgifb_info->display2 = XGIfb_crt2type;
1924 xgifb_info->display2_force = true;
1925 }
1926
9a801f25 1927 XGIRegInit(&xgifb_info->dev_info, xgifb_info->vga_base);
b654f878 1928
fc39dcb7
PH
1929 xgifb_reg_set(XGISR, IND_SIS_PASSWORD, SIS_PASSWORD);
1930 reg1 = xgifb_reg_get(XGISR, IND_SIS_PASSWORD);
b654f878
PS
1931
1932 if (reg1 != 0xa1) { /*I/O error */
4a6b1518 1933 pr_err("I/O error!!!");
bb292234
AK
1934 ret = -EIO;
1935 goto error;
b654f878 1936 }
d7636e0b 1937
fd26d420 1938 switch (xgifb_info->chip_id) {
fc39dcb7 1939 case PCI_DEVICE_ID_XGI_20:
e67f4d4d 1940 xgifb_reg_or(XGICR, Index_CR_GPIO_Reg3, GPIOG_EN);
7e119b75 1941 CR48 = xgifb_reg_get(XGICR, Index_CR_GPIO_Reg1);
d7636e0b 1942 if (CR48&GPIOG_READ)
fd26d420 1943 xgifb_info->chip = XG21;
d7636e0b 1944 else
fd26d420 1945 xgifb_info->chip = XG20;
d7636e0b 1946 break;
fc39dcb7 1947 case PCI_DEVICE_ID_XGI_40:
fd26d420 1948 xgifb_info->chip = XG40;
d7636e0b 1949 break;
fc39dcb7 1950 case PCI_DEVICE_ID_XGI_41:
fd26d420 1951 xgifb_info->chip = XG41;
d7636e0b 1952 break;
fc39dcb7 1953 case PCI_DEVICE_ID_XGI_42:
fd26d420 1954 xgifb_info->chip = XG42;
d7636e0b 1955 break;
fc39dcb7 1956 case PCI_DEVICE_ID_XGI_27:
fd26d420 1957 xgifb_info->chip = XG27;
d7636e0b 1958 break;
b654f878 1959 default:
bb292234
AK
1960 ret = -ENODEV;
1961 goto error;
d7636e0b 1962 }
1963
4a6b1518 1964 pr_info("chipid = %x\n", xgifb_info->chip);
fd26d420 1965 hw_info->jChipType = xgifb_info->chip;
d7636e0b 1966
fd26d420 1967 if (XGIfb_get_dram_size(xgifb_info)) {
4a6b1518 1968 pr_err("Fatal error: Unable to determine RAM size.\n");
bb292234
AK
1969 ret = -ENODEV;
1970 goto error;
b654f878 1971 }
d7636e0b 1972
e1521a16
AK
1973 /* Enable PCI_LINEAR_ADDRESSING and MMIO_ENABLE */
1974 xgifb_reg_or(XGISR,
fc39dcb7
PH
1975 IND_SIS_PCI_ADDRESS_SET,
1976 (SIS_PCI_ADDR_ENABLE | SIS_MEM_MAP_IO_ENABLE));
e1521a16 1977 /* Enable 2D accelerator engine */
fc39dcb7 1978 xgifb_reg_or(XGISR, IND_SIS_MODULE_ENABLE, SIS_ENABLE_2D);
d7636e0b 1979
fd26d420 1980 hw_info->ulVideoMemorySize = xgifb_info->video_size;
d7636e0b 1981
fd26d420
AK
1982 if (!request_mem_region(xgifb_info->video_base,
1983 xgifb_info->video_size,
a12c27c5 1984 "XGIfb FB")) {
4a6b1518 1985 pr_err("unable request memory size %x\n",
fd26d420 1986 xgifb_info->video_size);
4a6b1518
SH
1987 pr_err("Fatal error: Unable to reserve frame buffer memory\n");
1988 pr_err("Is there another framebuffer driver active?\n");
bb292234
AK
1989 ret = -ENODEV;
1990 goto error;
d7636e0b 1991 }
d7636e0b 1992
fd26d420
AK
1993 if (!request_mem_region(xgifb_info->mmio_base,
1994 xgifb_info->mmio_size,
1b3909e5 1995 "XGIfb MMIO")) {
4a6b1518 1996 pr_err("Fatal error: Unable to reserve MMIO region\n");
bb292234 1997 ret = -ENODEV;
5c0ef2ac 1998 goto error_0;
b654f878 1999 }
d7636e0b 2000
fd26d420
AK
2001 xgifb_info->video_vbase = hw_info->pjVideoMemoryAddress =
2002 ioremap(xgifb_info->video_base, xgifb_info->video_size);
2003 xgifb_info->mmio_vbase = ioremap(xgifb_info->mmio_base,
2004 xgifb_info->mmio_size);
d7636e0b 2005
4a6b1518 2006 pr_info("Framebuffer at 0x%lx, mapped to 0x%p, size %dk\n",
fd26d420
AK
2007 xgifb_info->video_base,
2008 xgifb_info->video_vbase,
2009 xgifb_info->video_size / 1024);
d7636e0b 2010
4a6b1518 2011 pr_info("MMIO at 0x%lx, mapped to 0x%p, size %ldk\n",
fd26d420
AK
2012 xgifb_info->mmio_base, xgifb_info->mmio_vbase,
2013 xgifb_info->mmio_size / 1024);
4a6b1518 2014
fcbdda90 2015 pci_set_drvdata(pdev, xgifb_info);
4a6b1518
SH
2016 if (!XGIInitNew(pdev))
2017 pr_err("XGIInitNew() failed!\n");
b654f878 2018
fd26d420 2019 xgifb_info->mtrr = (unsigned int) 0;
b654f878 2020
fd26d420
AK
2021 xgifb_info->hasVB = HASVB_NONE;
2022 if ((xgifb_info->chip == XG20) ||
2023 (xgifb_info->chip == XG27)) {
2024 xgifb_info->hasVB = HASVB_NONE;
2025 } else if (xgifb_info->chip == XG21) {
e1521a16 2026 CR38 = xgifb_reg_get(XGICR, 0x38);
cae9a7be 2027 if ((CR38&0xE0) == 0xC0)
289ea524 2028 xgifb_info->display2 = XGIFB_DISP_LCD;
cae9a7be 2029 else if ((CR38&0xE0) == 0x60)
fd26d420 2030 xgifb_info->hasVB = HASVB_CHRONTEL;
cae9a7be 2031 else
fd26d420 2032 xgifb_info->hasVB = HASVB_NONE;
e1521a16 2033 } else {
fd26d420 2034 XGIfb_get_VB_type(xgifb_info);
e1521a16 2035 }
d7636e0b 2036
c62f2e46 2037 hw_info->ujVBChipID = VB_CHIP_UNKNOWN;
d7636e0b 2038
c62f2e46 2039 hw_info->ulExternalChip = 0;
d7636e0b 2040
fd26d420 2041 switch (xgifb_info->hasVB) {
e1521a16
AK
2042 case HASVB_301:
2043 reg = xgifb_reg_get(XGIPART4, 0x01);
2044 if (reg >= 0xE0) {
c62f2e46 2045 hw_info->ujVBChipID = VB_CHIP_302LV;
4a6b1518 2046 pr_info("XGI302LV bridge detected (revision 0x%02x)\n", reg);
e1521a16 2047 } else if (reg >= 0xD0) {
c62f2e46 2048 hw_info->ujVBChipID = VB_CHIP_301LV;
4a6b1518 2049 pr_info("XGI301LV bridge detected (revision 0x%02x)\n", reg);
d7636e0b 2050 }
e1521a16 2051 /* else if (reg >= 0xB0) {
c62f2e46 2052 hw_info->ujVBChipID = VB_CHIP_301B;
e1521a16
AK
2053 reg1 = xgifb_reg_get(XGIPART4, 0x23);
2054 printk("XGIfb: XGI301B bridge detected\n");
2055 } */
2056 else {
c62f2e46 2057 hw_info->ujVBChipID = VB_CHIP_301;
4a6b1518 2058 pr_info("XGI301 bridge detected\n");
e1521a16
AK
2059 }
2060 break;
2061 case HASVB_302:
2062 reg = xgifb_reg_get(XGIPART4, 0x01);
2063 if (reg >= 0xE0) {
c62f2e46 2064 hw_info->ujVBChipID = VB_CHIP_302LV;
4a6b1518 2065 pr_info("XGI302LV bridge detected (revision 0x%02x)\n", reg);
e1521a16 2066 } else if (reg >= 0xD0) {
c62f2e46 2067 hw_info->ujVBChipID = VB_CHIP_301LV;
4a6b1518 2068 pr_info("XGI302LV bridge detected (revision 0x%02x)\n", reg);
e1521a16
AK
2069 } else if (reg >= 0xB0) {
2070 reg1 = xgifb_reg_get(XGIPART4, 0x23);
d7636e0b 2071
c62f2e46 2072 hw_info->ujVBChipID = VB_CHIP_302B;
d7636e0b 2073
d7636e0b 2074 } else {
c62f2e46 2075 hw_info->ujVBChipID = VB_CHIP_302;
4a6b1518 2076 pr_info("XGI302 bridge detected\n");
d7636e0b 2077 }
e1521a16
AK
2078 break;
2079 case HASVB_LVDS:
c62f2e46 2080 hw_info->ulExternalChip = 0x1;
4a6b1518 2081 pr_info("LVDS transmitter detected\n");
e1521a16
AK
2082 break;
2083 case HASVB_TRUMPION:
c62f2e46 2084 hw_info->ulExternalChip = 0x2;
4a6b1518 2085 pr_info("Trumpion Zurac LVDS scaler detected\n");
e1521a16
AK
2086 break;
2087 case HASVB_CHRONTEL:
c62f2e46 2088 hw_info->ulExternalChip = 0x4;
4a6b1518 2089 pr_info("Chrontel TV encoder detected\n");
e1521a16
AK
2090 break;
2091 case HASVB_LVDS_CHRONTEL:
c62f2e46 2092 hw_info->ulExternalChip = 0x5;
4a6b1518 2093 pr_info("LVDS transmitter and Chrontel TV encoder detected\n");
e1521a16
AK
2094 break;
2095 default:
4a6b1518 2096 pr_info("No or unknown bridge type detected\n");
e1521a16
AK
2097 break;
2098 }
d7636e0b 2099
fd26d420
AK
2100 if (xgifb_info->hasVB != HASVB_NONE)
2101 XGIfb_detect_VB(xgifb_info);
25aa75f1
AK
2102 else if (xgifb_info->chip != XG21)
2103 xgifb_info->display2 = XGIFB_DISP_NONE;
b654f878 2104
289ea524 2105 if (xgifb_info->display2 == XGIFB_DISP_LCD) {
e1521a16
AK
2106 if (!enable_dstn) {
2107 reg = xgifb_reg_get(XGICR, IND_XGI_LCD_PANEL);
2108 reg &= 0x0f;
c62f2e46 2109 hw_info->ulCRT2LCDType = XGI310paneltype[reg];
d7636e0b 2110 }
e1521a16 2111 }
d7636e0b 2112
c62f2e46
AK
2113 if ((hw_info->ujVBChipID == VB_CHIP_302B) ||
2114 (hw_info->ujVBChipID == VB_CHIP_301LV) ||
2115 (hw_info->ujVBChipID == VB_CHIP_302LV)) {
e1521a16
AK
2116 int tmp;
2117 tmp = xgifb_reg_get(XGICR, 0x34);
2118 if (tmp <= 0x13) {
2119 /* Currently on LCDA?
2120 *(Some BIOSes leave CR38) */
2121 tmp = xgifb_reg_get(XGICR, 0x38);
2122 if ((tmp & 0x03) == 0x03) {
2123 /* XGI_Pr.XGI_UseLCDA = 1; */
2124 } else {
a12c27c5 2125 /* Currently on LCDA?
e1521a16
AK
2126 *(Some newer BIOSes set D0 in CR35) */
2127 tmp = xgifb_reg_get(XGICR, 0x35);
2128 if (tmp & 0x01) {
b654f878
PS
2129 /* XGI_Pr.XGI_UseLCDA = 1; */
2130 } else {
e1521a16
AK
2131 tmp = xgifb_reg_get(XGICR,
2132 0x30);
2133 if (tmp & 0x20) {
2134 tmp = xgifb_reg_get(
2135 XGIPART1, 0x13);
b654f878
PS
2136 }
2137 }
2138 }
b654f878 2139 }
d7636e0b 2140
e1521a16 2141 }
d7636e0b 2142
ccf265ad
AK
2143 xgifb_info->mode_idx = -1;
2144
dfbdf805 2145 if (mode)
ccf265ad 2146 XGIfb_search_mode(xgifb_info, mode);
dfbdf805 2147 else if (vesa != -1)
ccf265ad 2148 XGIfb_search_vesamode(xgifb_info, vesa);
dfbdf805 2149
ccf265ad
AK
2150 if (xgifb_info->mode_idx >= 0)
2151 xgifb_info->mode_idx =
2152 XGIfb_validate_mode(xgifb_info, xgifb_info->mode_idx);
d7636e0b 2153
ccf265ad 2154 if (xgifb_info->mode_idx < 0) {
289ea524 2155 if (xgifb_info->display2 == XGIFB_DISP_LCD &&
fd26d420 2156 xgifb_info->chip == XG21)
ccf265ad 2157 xgifb_info->mode_idx =
fab04b97 2158 XGIfb_GetXG21DefaultLVDSModeIdx(xgifb_info);
c8bec1f0 2159 else
ccf265ad 2160 xgifb_info->mode_idx = DEFAULT_MODE;
e1521a16 2161 }
d7636e0b 2162
ccf265ad 2163 if (xgifb_info->mode_idx < 0) {
de736dbb
AK
2164 dev_err(&pdev->dev, "no supported video mode found\n");
2165 goto error_1;
2166 }
2167
e1521a16 2168 /* yilin set default refresh rate */
fd26d420
AK
2169 xgifb_info->refresh_rate = refresh_rate;
2170 if (xgifb_info->refresh_rate == 0)
2171 xgifb_info->refresh_rate = 60;
2172 if (XGIfb_search_refresh_rate(xgifb_info,
2173 xgifb_info->refresh_rate) == 0) {
5aa55d9f
AK
2174 xgifb_info->rate_idx =
2175 XGIbios_mode[xgifb_info->mode_idx].rate_idx;
fd26d420 2176 xgifb_info->refresh_rate = 60;
e1521a16
AK
2177 }
2178
ccf265ad 2179 xgifb_info->video_bpp = XGIbios_mode[xgifb_info->mode_idx].bpp;
fd26d420
AK
2180 xgifb_info->video_vwidth =
2181 xgifb_info->video_width =
ccf265ad 2182 XGIbios_mode[xgifb_info->mode_idx].xres;
fd26d420
AK
2183 xgifb_info->video_vheight =
2184 xgifb_info->video_height =
ccf265ad 2185 XGIbios_mode[xgifb_info->mode_idx].yres;
fd26d420
AK
2186 xgifb_info->org_x = xgifb_info->org_y = 0;
2187 xgifb_info->video_linelength =
2188 xgifb_info->video_width *
2189 (xgifb_info->video_bpp >> 3);
2190 switch (xgifb_info->video_bpp) {
e1521a16 2191 case 8:
fd26d420
AK
2192 xgifb_info->DstColor = 0x0000;
2193 xgifb_info->XGI310_AccelDepth = 0x00000000;
2194 xgifb_info->video_cmap_len = 256;
e1521a16
AK
2195 break;
2196 case 16:
fd26d420
AK
2197 xgifb_info->DstColor = 0x8000;
2198 xgifb_info->XGI310_AccelDepth = 0x00010000;
2199 xgifb_info->video_cmap_len = 16;
e1521a16
AK
2200 break;
2201 case 32:
fd26d420
AK
2202 xgifb_info->DstColor = 0xC000;
2203 xgifb_info->XGI310_AccelDepth = 0x00020000;
2204 xgifb_info->video_cmap_len = 16;
e1521a16
AK
2205 break;
2206 default:
fd26d420 2207 xgifb_info->video_cmap_len = 16;
4a6b1518 2208 pr_info("Unsupported depth %d\n",
fd26d420 2209 xgifb_info->video_bpp);
e1521a16
AK
2210 break;
2211 }
2212
4a6b1518 2213 pr_info("Default mode is %dx%dx%d (%dHz)\n",
fd26d420
AK
2214 xgifb_info->video_width,
2215 xgifb_info->video_height,
2216 xgifb_info->video_bpp,
2217 xgifb_info->refresh_rate);
e1521a16 2218
e9865d47
AK
2219 fb_info->var.red.length = 8;
2220 fb_info->var.green.length = 8;
2221 fb_info->var.blue.length = 8;
2222 fb_info->var.activate = FB_ACTIVATE_NOW;
2223 fb_info->var.height = -1;
2224 fb_info->var.width = -1;
2225 fb_info->var.vmode = FB_VMODE_NONINTERLACED;
2226 fb_info->var.xres = xgifb_info->video_width;
2227 fb_info->var.xres_virtual = xgifb_info->video_width;
2228 fb_info->var.yres = xgifb_info->video_height;
2229 fb_info->var.yres_virtual = xgifb_info->video_height;
2230 fb_info->var.bits_per_pixel = xgifb_info->video_bpp;
2231
2232 XGIfb_bpp_to_var(xgifb_info, &fb_info->var);
2233
2234 fb_info->var.pixclock = (u32) (1000000000 /
f2df8c09
AK
2235 XGIfb_mode_rate_to_dclock(&xgifb_info->dev_info,
2236 hw_info,
ccf265ad 2237 XGIbios_mode[xgifb_info->mode_idx].mode_no,
5aa55d9f 2238 xgifb_info->rate_idx));
e1521a16 2239
f2df8c09 2240 if (XGIfb_mode_rate_to_ddata(&xgifb_info->dev_info, hw_info,
5aa55d9f
AK
2241 XGIbios_mode[xgifb_info->mode_idx].mode_no,
2242 xgifb_info->rate_idx,
e9865d47
AK
2243 &fb_info->var.left_margin,
2244 &fb_info->var.right_margin,
2245 &fb_info->var.upper_margin,
2246 &fb_info->var.lower_margin,
2247 &fb_info->var.hsync_len,
2248 &fb_info->var.vsync_len,
2249 &fb_info->var.sync,
2250 &fb_info->var.vmode)) {
2251
2252 if ((fb_info->var.vmode & FB_VMODE_MASK) ==
e1521a16 2253 FB_VMODE_INTERLACED) {
e9865d47
AK
2254 fb_info->var.yres <<= 1;
2255 fb_info->var.yres_virtual <<= 1;
2256 } else if ((fb_info->var.vmode & FB_VMODE_MASK) ==
e1521a16 2257 FB_VMODE_DOUBLE) {
e9865d47
AK
2258 fb_info->var.pixclock >>= 1;
2259 fb_info->var.yres >>= 1;
2260 fb_info->var.yres_virtual >>= 1;
b654f878 2261 }
d7636e0b 2262
e1521a16
AK
2263 }
2264
c11d0ef3
AK
2265 strncpy(fb_info->fix.id, "XGI", sizeof(fb_info->fix.id) - 1);
2266 fb_info->fix.type = FB_TYPE_PACKED_PIXELS;
2267 fb_info->fix.xpanstep = 1;
2268 fb_info->fix.ypanstep = 1;
2269
e1521a16 2270 fb_info->flags = FBINFO_FLAG_DEFAULT;
fd26d420 2271 fb_info->screen_base = xgifb_info->video_vbase;
e1521a16
AK
2272 fb_info->fbops = &XGIfb_ops;
2273 XGIfb_get_fix(&fb_info->fix, -1, fb_info);
76cabaa4 2274 fb_info->pseudo_palette = xgifb_info->pseudo_palette;
d7636e0b 2275
e1521a16 2276 fb_alloc_cmap(&fb_info->cmap, 256 , 0);
d7636e0b 2277
d7636e0b 2278#ifdef CONFIG_MTRR
fd26d420
AK
2279 xgifb_info->mtrr = mtrr_add(xgifb_info->video_base,
2280 xgifb_info->video_size, MTRR_TYPE_WRCOMB, 1);
2281 if (xgifb_info->mtrr >= 0)
15ebe6c6 2282 dev_info(&pdev->dev, "added MTRR\n");
d7636e0b 2283#endif
2284
e1521a16
AK
2285 if (register_framebuffer(fb_info) < 0) {
2286 ret = -EINVAL;
3028474c 2287 goto error_mtrr;
e1521a16 2288 }
d7636e0b 2289
d7636e0b 2290 dumpVGAReg();
2291
2292 return 0;
bb292234 2293
3028474c
AK
2294error_mtrr:
2295#ifdef CONFIG_MTRR
fd26d420
AK
2296 if (xgifb_info->mtrr >= 0)
2297 mtrr_del(xgifb_info->mtrr, xgifb_info->video_base,
2298 xgifb_info->video_size);
3028474c 2299#endif /* CONFIG_MTRR */
5c0ef2ac 2300error_1:
fd26d420
AK
2301 iounmap(xgifb_info->mmio_vbase);
2302 iounmap(xgifb_info->video_vbase);
2303 release_mem_region(xgifb_info->mmio_base, xgifb_info->mmio_size);
5c0ef2ac 2304error_0:
fd26d420 2305 release_mem_region(xgifb_info->video_base, xgifb_info->video_size);
bb292234
AK
2306error:
2307 framebuffer_release(fb_info);
2308 return ret;
d7636e0b 2309}
2310
d7636e0b 2311/*****************************************************/
2312/* PCI DEVICE HANDLING */
2313/*****************************************************/
2314
2315static void __devexit xgifb_remove(struct pci_dev *pdev)
2316{
ab886ff8 2317 struct xgifb_video_info *xgifb_info = pci_get_drvdata(pdev);
19c1e88e 2318 struct fb_info *fb_info = xgifb_info->fb_info;
54301b5c 2319
b654f878 2320 unregister_framebuffer(fb_info);
3028474c 2321#ifdef CONFIG_MTRR
54301b5c
AK
2322 if (xgifb_info->mtrr >= 0)
2323 mtrr_del(xgifb_info->mtrr, xgifb_info->video_base,
2324 xgifb_info->video_size);
3028474c 2325#endif /* CONFIG_MTRR */
54301b5c
AK
2326 iounmap(xgifb_info->mmio_vbase);
2327 iounmap(xgifb_info->video_vbase);
2328 release_mem_region(xgifb_info->mmio_base, xgifb_info->mmio_size);
2329 release_mem_region(xgifb_info->video_base, xgifb_info->video_size);
b654f878 2330 framebuffer_release(fb_info);
d7636e0b 2331 pci_set_drvdata(pdev, NULL);
45dcfaf1 2332}
d7636e0b 2333
2334static struct pci_driver xgifb_driver = {
b654f878
PS
2335 .name = "xgifb",
2336 .id_table = xgifb_pci_table,
2337 .probe = xgifb_probe,
2338 .remove = __devexit_p(xgifb_remove)
d7636e0b 2339};
2340
032abf7b 2341static int __init xgifb_init(void)
d7636e0b 2342{
d7636e0b 2343 char *option = NULL;
2344
2d2c880f
AK
2345 if (forcecrt2type != NULL)
2346 XGIfb_search_crt2type(forcecrt2type);
d7636e0b 2347 if (fb_get_options("xgifb", &option))
2348 return -ENODEV;
2349 XGIfb_setup(option);
328f55ba 2350
b654f878 2351 return pci_register_driver(&xgifb_driver);
d7636e0b 2352}
2353
d7636e0b 2354module_init(xgifb_init);
d7636e0b 2355
2356/*****************************************************/
2357/* MODULE */
2358/*****************************************************/
2359
2360#ifdef MODULE
2361
d7636e0b 2362MODULE_DESCRIPTION("Z7 Z9 Z9S Z11 framebuffer device driver");
2363MODULE_LICENSE("GPL");
2364MODULE_AUTHOR("XGITECH , Others");
2365
d7636e0b 2366module_param(mode, charp, 0);
2367module_param(vesa, int, 0);
d7636e0b 2368module_param(filter, int, 0);
2d2c880f
AK
2369module_param(forcecrt2type, charp, 0);
2370
2371MODULE_PARM_DESC(forcecrt2type,
2372 "\nForce the second display output type. Possible values are NONE,\n"
2373 "LCD, TV, VGA, SVIDEO or COMPOSITE.\n");
d7636e0b 2374
d7636e0b 2375MODULE_PARM_DESC(mode,
47c92d5f
AK
2376 "\nSelects the desired default display mode in the format XxYxDepth,\n"
2377 "eg. 1024x768x16.\n");
d7636e0b 2378
2379MODULE_PARM_DESC(vesa,
47c92d5f
AK
2380 "\nSelects the desired default display mode by VESA mode number, eg.\n"
2381 "0x117.\n");
d7636e0b 2382
d7636e0b 2383MODULE_PARM_DESC(filter,
b654f878
PS
2384 "\nSelects TV flicker filter type (only for systems with a SiS301 video bridge).\n"
2385 "(Possible values 0-7, default: [no filter])\n");
d7636e0b 2386
d7636e0b 2387static void __exit xgifb_remove_module(void)
2388{
2389 pci_unregister_driver(&xgifb_driver);
4a6b1518 2390 pr_debug("Module unloaded\n");
d7636e0b 2391}
2392
d7636e0b 2393module_exit(xgifb_remove_module);
2394
b654f878 2395#endif /* /MODULE */