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