[PATCH] fbdev: savagefb: Driver cleanup
[linux-2.6.git] / drivers / video / savage / savagefb_driver.c
1 /*
2  * linux/drivers/video/savagefb.c -- S3 Savage Framebuffer Driver
3  *
4  * Copyright (c) 2001-2002  Denis Oliver Kropp <dok@directfb.org>
5  *                          Sven Neumann <neo@directfb.org>
6  *
7  *
8  * Card specific code is based on XFree86's savage driver.
9  * Framebuffer framework code is based on code of cyber2000fb and tdfxfb.
10  *
11  * This file is subject to the terms and conditions of the GNU General
12  * Public License.  See the file COPYING in the main directory of this
13  * archive for more details.
14  *
15  * 0.4.0 (neo)
16  *  - hardware accelerated clear and move
17  *
18  * 0.3.2 (dok)
19  *  - wait for vertical retrace before writing to cr67
20  *    at the beginning of savagefb_set_par
21  *  - use synchronization registers cr23 and cr26
22  *
23  * 0.3.1 (dok)
24  *  - reset 3D engine
25  *  - don't return alpha bits for 32bit format
26  *
27  * 0.3.0 (dok)
28  *  - added WaitIdle functions for all Savage types
29  *  - do WaitIdle before mode switching
30  *  - code cleanup
31  *
32  * 0.2.0 (dok)
33  *  - first working version
34  *
35  *
36  * TODO
37  * - clock validations in decode_var
38  *
39  * BUGS
40  * - white margin on bootup
41  *
42  */
43
44 #include <linux/config.h>
45 #include <linux/module.h>
46 #include <linux/kernel.h>
47 #include <linux/errno.h>
48 #include <linux/string.h>
49 #include <linux/mm.h>
50 #include <linux/tty.h>
51 #include <linux/slab.h>
52 #include <linux/delay.h>
53 #include <linux/fb.h>
54 #include <linux/pci.h>
55 #include <linux/init.h>
56 #include <linux/console.h>
57
58 #include <asm/io.h>
59 #include <asm/irq.h>
60 #include <asm/pgtable.h>
61 #include <asm/system.h>
62 #include <asm/uaccess.h>
63
64 #ifdef CONFIG_MTRR
65 #include <asm/mtrr.h>
66 #endif
67
68 #include "savagefb.h"
69
70
71 #define SAVAGEFB_VERSION "0.4.0_2.6"
72
73 /* --------------------------------------------------------------------- */
74
75
76 static char *mode_option __initdata = NULL;
77
78 #ifdef MODULE
79
80 MODULE_AUTHOR("(c) 2001-2002  Denis Oliver Kropp <dok@directfb.org>");
81 MODULE_LICENSE("GPL");
82 MODULE_DESCRIPTION("FBDev driver for S3 Savage PCI/AGP Chips");
83
84 #endif
85
86
87 /* --------------------------------------------------------------------- */
88
89 static void vgaHWSeqReset (struct savagefb_par *par, int start)
90 {
91         if (start)
92                 VGAwSEQ (0x00, 0x01, par);      /* Synchronous Reset */
93         else
94                 VGAwSEQ (0x00, 0x03, par);      /* End Reset */
95 }
96
97 static void vgaHWProtect (struct savagefb_par *par, int on)
98 {
99         unsigned char tmp;
100
101         if (on) {
102                 /*
103                  * Turn off screen and disable sequencer.
104                  */
105                 tmp = VGArSEQ (0x01, par);
106
107                 vgaHWSeqReset (par, 1);         /* start synchronous reset */
108                 VGAwSEQ (0x01, tmp | 0x20, par);/* disable the display */
109
110                 VGAenablePalette(par);
111         } else {
112                 /*
113                  * Reenable sequencer, then turn on screen.
114                  */
115
116                 tmp = VGArSEQ (0x01, par);
117
118                 VGAwSEQ (0x01, tmp & ~0x20, par);/* reenable display */
119                 vgaHWSeqReset (par, 0);         /* clear synchronous reset */
120
121                 VGAdisablePalette(par);
122         }
123 }
124
125 static void vgaHWRestore (struct savagefb_par  *par)
126 {
127         int i;
128
129         VGAwMISC (par->MiscOutReg, par);
130
131         for (i = 1; i < 5; i++)
132                 VGAwSEQ (i, par->Sequencer[i], par);
133
134         /* Ensure CRTC registers 0-7 are unlocked by clearing bit 7 or
135            CRTC[17] */
136         VGAwCR (17, par->CRTC[17] & ~0x80, par);
137
138         for (i = 0; i < 25; i++)
139                 VGAwCR (i, par->CRTC[i], par);
140
141         for (i = 0; i < 9; i++)
142                 VGAwGR (i, par->Graphics[i], par);
143
144         VGAenablePalette(par);
145
146         for (i = 0; i < 21; i++)
147                 VGAwATTR (i, par->Attribute[i], par);
148
149         VGAdisablePalette(par);
150 }
151
152 static void vgaHWInit (struct fb_var_screeninfo *var,
153                        struct savagefb_par            *par,
154                        struct xtimings                *timings)
155 {
156         par->MiscOutReg = 0x23;
157
158         if (!(timings->sync & FB_SYNC_HOR_HIGH_ACT))
159                 par->MiscOutReg |= 0x40;
160
161         if (!(timings->sync & FB_SYNC_VERT_HIGH_ACT))
162                 par->MiscOutReg |= 0x80;
163
164         /*
165          * Time Sequencer
166          */
167         par->Sequencer[0x00] = 0x00;
168         par->Sequencer[0x01] = 0x01;
169         par->Sequencer[0x02] = 0x0F;
170         par->Sequencer[0x03] = 0x00;          /* Font select */
171         par->Sequencer[0x04] = 0x0E;          /* Misc */
172
173         /*
174          * CRTC Controller
175          */
176         par->CRTC[0x00] = (timings->HTotal >> 3) - 5;
177         par->CRTC[0x01] = (timings->HDisplay >> 3) - 1;
178         par->CRTC[0x02] = (timings->HSyncStart >> 3) - 1;
179         par->CRTC[0x03] = (((timings->HSyncEnd >> 3)  - 1) & 0x1f) | 0x80;
180         par->CRTC[0x04] = (timings->HSyncStart >> 3);
181         par->CRTC[0x05] = ((((timings->HSyncEnd >> 3) - 1) & 0x20) << 2) |
182                 (((timings->HSyncEnd >> 3)) & 0x1f);
183         par->CRTC[0x06] = (timings->VTotal - 2) & 0xFF;
184         par->CRTC[0x07] = (((timings->VTotal - 2) & 0x100) >> 8) |
185                 (((timings->VDisplay - 1) & 0x100) >> 7) |
186                 ((timings->VSyncStart & 0x100) >> 6) |
187                 (((timings->VSyncStart - 1) & 0x100) >> 5) |
188                 0x10 |
189                 (((timings->VTotal - 2) & 0x200) >> 4) |
190                 (((timings->VDisplay - 1) & 0x200) >> 3) |
191                 ((timings->VSyncStart & 0x200) >> 2);
192         par->CRTC[0x08] = 0x00;
193         par->CRTC[0x09] = (((timings->VSyncStart - 1) & 0x200) >> 4) | 0x40;
194
195         if (timings->dblscan)
196                 par->CRTC[0x09] |= 0x80;
197
198         par->CRTC[0x0a] = 0x00;
199         par->CRTC[0x0b] = 0x00;
200         par->CRTC[0x0c] = 0x00;
201         par->CRTC[0x0d] = 0x00;
202         par->CRTC[0x0e] = 0x00;
203         par->CRTC[0x0f] = 0x00;
204         par->CRTC[0x10] = timings->VSyncStart & 0xff;
205         par->CRTC[0x11] = (timings->VSyncEnd & 0x0f) | 0x20;
206         par->CRTC[0x12] = (timings->VDisplay - 1) & 0xff;
207         par->CRTC[0x13] = var->xres_virtual >> 4;
208         par->CRTC[0x14] = 0x00;
209         par->CRTC[0x15] = (timings->VSyncStart - 1) & 0xff;
210         par->CRTC[0x16] = (timings->VSyncEnd - 1) & 0xff;
211         par->CRTC[0x17] = 0xc3;
212         par->CRTC[0x18] = 0xff;
213
214         /*
215          * are these unnecessary?
216          * vgaHWHBlankKGA(mode, regp, 0, KGA_FIX_OVERSCAN|KGA_ENABLE_ON_ZERO);
217          * vgaHWVBlankKGA(mode, regp, 0, KGA_FIX_OVERSCAN|KGA_ENABLE_ON_ZERO);
218          */
219
220         /*
221          * Graphics Display Controller
222          */
223         par->Graphics[0x00] = 0x00;
224         par->Graphics[0x01] = 0x00;
225         par->Graphics[0x02] = 0x00;
226         par->Graphics[0x03] = 0x00;
227         par->Graphics[0x04] = 0x00;
228         par->Graphics[0x05] = 0x40;
229         par->Graphics[0x06] = 0x05;   /* only map 64k VGA memory !!!! */
230         par->Graphics[0x07] = 0x0F;
231         par->Graphics[0x08] = 0xFF;
232
233
234         par->Attribute[0x00]  = 0x00; /* standard colormap translation */
235         par->Attribute[0x01]  = 0x01;
236         par->Attribute[0x02]  = 0x02;
237         par->Attribute[0x03]  = 0x03;
238         par->Attribute[0x04]  = 0x04;
239         par->Attribute[0x05]  = 0x05;
240         par->Attribute[0x06]  = 0x06;
241         par->Attribute[0x07]  = 0x07;
242         par->Attribute[0x08]  = 0x08;
243         par->Attribute[0x09]  = 0x09;
244         par->Attribute[0x0a] = 0x0A;
245         par->Attribute[0x0b] = 0x0B;
246         par->Attribute[0x0c] = 0x0C;
247         par->Attribute[0x0d] = 0x0D;
248         par->Attribute[0x0e] = 0x0E;
249         par->Attribute[0x0f] = 0x0F;
250         par->Attribute[0x10] = 0x41;
251         par->Attribute[0x11] = 0xFF;
252         par->Attribute[0x12] = 0x0F;
253         par->Attribute[0x13] = 0x00;
254         par->Attribute[0x14] = 0x00;
255 }
256
257 /* -------------------- Hardware specific routines ------------------------- */
258
259 /*
260  * Hardware Acceleration for SavageFB
261  */
262
263 /* Wait for fifo space */
264 static void
265 savage3D_waitfifo(struct savagefb_par *par, int space)
266 {
267         int slots = MAXFIFO - space;
268
269         while ((savage_in32(0x48C00, par) & 0x0000ffff) > slots);
270 }
271
272 static void
273 savage4_waitfifo(struct savagefb_par *par, int space)
274 {
275         int slots = MAXFIFO - space;
276
277         while ((savage_in32(0x48C60, par) & 0x001fffff) > slots);
278 }
279
280 static void
281 savage2000_waitfifo(struct savagefb_par *par, int space)
282 {
283         int slots = MAXFIFO - space;
284
285         while ((savage_in32(0x48C60, par) & 0x0000ffff) > slots);
286 }
287
288 /* Wait for idle accelerator */
289 static void
290 savage3D_waitidle(struct savagefb_par *par)
291 {
292         while ((savage_in32(0x48C00, par) & 0x0008ffff) != 0x80000);
293 }
294
295 static void
296 savage4_waitidle(struct savagefb_par *par)
297 {
298         while ((savage_in32(0x48C60, par) & 0x00a00000) != 0x00a00000);
299 }
300
301 static void
302 savage2000_waitidle(struct savagefb_par *par)
303 {
304         while ((savage_in32(0x48C60, par) & 0x009fffff));
305 }
306
307
308 static void
309 SavageSetup2DEngine (struct savagefb_par  *par)
310 {
311         unsigned long GlobalBitmapDescriptor;
312
313         GlobalBitmapDescriptor = 1 | 8 | BCI_BD_BW_DISABLE;
314         BCI_BD_SET_BPP (GlobalBitmapDescriptor, par->depth);
315         BCI_BD_SET_STRIDE (GlobalBitmapDescriptor, par->vwidth);
316
317         switch(par->chip) {
318         case S3_SAVAGE3D:
319         case S3_SAVAGE_MX:
320                 /* Disable BCI */
321                 savage_out32(0x48C18, savage_in32(0x48C18, par) & 0x3FF0, par);
322                 /* Setup BCI command overflow buffer */
323                 savage_out32(0x48C14,
324                              (par->cob_offset >> 11) | (par->cob_index << 29),
325                              par);
326                 /* Program shadow status update. */
327                 savage_out32(0x48C10, 0x78207220, par);
328                 savage_out32(0x48C0C, 0, par);
329                 /* Enable BCI and command overflow buffer */
330                 savage_out32(0x48C18, savage_in32(0x48C18, par) | 0x0C, par);
331                 break;
332         case S3_SAVAGE4:
333         case S3_PROSAVAGE:
334         case S3_SUPERSAVAGE:
335                 /* Disable BCI */
336                 savage_out32(0x48C18, savage_in32(0x48C18, par) & 0x3FF0, par);
337                 /* Program shadow status update */
338                 savage_out32(0x48C10, 0x00700040, par);
339                 savage_out32(0x48C0C, 0, par);
340                 /* Enable BCI without the COB */
341                 savage_out32(0x48C18, savage_in32(0x48C18, par) | 0x08, par);
342                 break;
343         case S3_SAVAGE2000:
344                 /* Disable BCI */
345                 savage_out32(0x48C18, 0, par);
346                 /* Setup BCI command overflow buffer */
347                 savage_out32(0x48C18,
348                              (par->cob_offset >> 7) | (par->cob_index),
349                              par);
350                 /* Disable shadow status update */
351                 savage_out32(0x48A30, 0, par);
352                 /* Enable BCI and command overflow buffer */
353                 savage_out32(0x48C18, savage_in32(0x48C18, par) | 0x00280000,
354                              par);
355                 break;
356             default:
357                 break;
358         }
359         /* Turn on 16-bit register access. */
360         vga_out8(0x3d4, 0x31, par);
361         vga_out8(0x3d5, 0x0c, par);
362
363         /* Set stride to use GBD. */
364         vga_out8 (0x3d4, 0x50, par);
365         vga_out8 (0x3d5, vga_in8(0x3d5, par) | 0xC1, par);
366
367         /* Enable 2D engine. */
368         vga_out8 (0x3d4, 0x40, par);
369         vga_out8 (0x3d5, 0x01, par);
370
371         savage_out32 (MONO_PAT_0, ~0, par);
372         savage_out32 (MONO_PAT_1, ~0, par);
373
374         /* Setup plane masks */
375         savage_out32 (0x8128, ~0, par); /* enable all write planes */
376         savage_out32 (0x812C, ~0, par); /* enable all read planes */
377         savage_out16 (0x8134, 0x27, par);
378         savage_out16 (0x8136, 0x07, par);
379
380         /* Now set the GBD */
381         par->bci_ptr = 0;
382         par->SavageWaitFifo (par, 4);
383
384         BCI_SEND( BCI_CMD_SETREG | (1 << 16) | BCI_GBD1 );
385         BCI_SEND( 0 );
386         BCI_SEND( BCI_CMD_SETREG | (1 << 16) | BCI_GBD2 );
387         BCI_SEND( GlobalBitmapDescriptor );
388 }
389
390
391 static void SavageCalcClock(long freq, int min_m, int min_n1, int max_n1,
392                             int min_n2, int max_n2, long freq_min,
393                             long freq_max, unsigned int *mdiv,
394                             unsigned int *ndiv, unsigned int *r)
395 {
396         long diff, best_diff;
397         unsigned int m;
398         unsigned char n1, n2, best_n1=16+2, best_n2=2, best_m=125+2;
399
400         if (freq < freq_min / (1 << max_n2)) {
401                 printk (KERN_ERR "invalid frequency %ld Khz\n", freq);
402                 freq = freq_min / (1 << max_n2);
403         }
404         if (freq > freq_max / (1 << min_n2)) {
405                 printk (KERN_ERR "invalid frequency %ld Khz\n", freq);
406                 freq = freq_max / (1 << min_n2);
407         }
408
409         /* work out suitable timings */
410         best_diff = freq;
411
412         for (n2=min_n2; n2<=max_n2; n2++) {
413                 for (n1=min_n1+2; n1<=max_n1+2; n1++) {
414                         m = (freq * n1 * (1 << n2) + HALF_BASE_FREQ) /
415                                 BASE_FREQ;
416                         if (m < min_m+2 || m > 127+2)
417                                 continue;
418                         if ((m * BASE_FREQ >= freq_min * n1) &&
419                             (m * BASE_FREQ <= freq_max * n1)) {
420                                 diff = freq * (1 << n2) * n1 - BASE_FREQ * m;
421                                 if (diff < 0)
422                                         diff = -diff;
423                                 if (diff < best_diff) {
424                                         best_diff = diff;
425                                         best_m = m;
426                                         best_n1 = n1;
427                                         best_n2 = n2;
428                                 }
429                         }
430                 }
431         }
432
433         *ndiv = best_n1 - 2;
434         *r = best_n2;
435         *mdiv = best_m - 2;
436 }
437
438 static int common_calc_clock(long freq, int min_m, int min_n1, int max_n1,
439                              int min_n2, int max_n2, long freq_min,
440                              long freq_max, unsigned char *mdiv,
441                              unsigned char *ndiv)
442 {
443         long diff, best_diff;
444         unsigned int m;
445         unsigned char n1, n2;
446         unsigned char best_n1 = 16+2, best_n2 = 2, best_m = 125+2;
447
448         best_diff = freq;
449
450         for (n2 = min_n2; n2 <= max_n2; n2++) {
451                 for (n1 = min_n1+2; n1 <= max_n1+2; n1++) {
452                         m = (freq * n1 * (1 << n2) + HALF_BASE_FREQ) /
453                                 BASE_FREQ;
454                         if (m < min_m + 2 || m > 127+2)
455                                 continue;
456                         if((m * BASE_FREQ >= freq_min * n1) &&
457                            (m * BASE_FREQ <= freq_max * n1)) {
458                                 diff = freq * (1 << n2) * n1 - BASE_FREQ * m;
459                                 if(diff < 0)
460                                         diff = -diff;
461                                 if(diff < best_diff) {
462                                         best_diff = diff;
463                                         best_m = m;
464                                         best_n1 = n1;
465                                         best_n2 = n2;
466                                 }
467                         }
468                 }
469         }
470
471         if(max_n1 == 63)
472                 *ndiv = (best_n1 - 2) | (best_n2 << 6);
473         else
474                 *ndiv = (best_n1 - 2) | (best_n2 << 5);
475
476         *mdiv = best_m - 2;
477
478         return 0;
479 }
480
481 #ifdef SAVAGEFB_DEBUG
482 /* This function is used to debug, it prints out the contents of s3 regs */
483
484 static void SavagePrintRegs(void)
485 {
486         unsigned char i;
487         int vgaCRIndex = 0x3d4;
488         int vgaCRReg = 0x3d5;
489
490         printk(KERN_DEBUG "SR    x0 x1 x2 x3 x4 x5 x6 x7 x8 x9 xA xB xC xD xE "
491                "xF" );
492
493         for( i = 0; i < 0x70; i++ ) {
494                 if( !(i % 16) )
495                         printk(KERN_DEBUG "\nSR%xx ", i >> 4 );
496                 vga_out8( 0x3c4, i, par);
497                 printk(KERN_DEBUG " %02x", vga_in8(0x3c5, par) );
498         }
499
500         printk(KERN_DEBUG "\n\nCR    x0 x1 x2 x3 x4 x5 x6 x7 x8 x9 xA xB xC "
501                "xD xE xF" );
502
503         for( i = 0; i < 0xB7; i++ ) {
504                 if( !(i % 16) )
505                         printk(KERN_DEBUG "\nCR%xx ", i >> 4 );
506                 vga_out8( vgaCRIndex, i, par);
507                 printk(KERN_DEBUG " %02x", vga_in8(vgaCRReg, par) );
508         }
509
510         printk(KERN_DEBUG "\n\n");
511 }
512 #endif
513
514 /* --------------------------------------------------------------------- */
515
516 static void savage_get_default_par(struct savagefb_par *par)
517 {
518         unsigned char cr3a, cr53, cr66;
519
520         vga_out16 (0x3d4, 0x4838, par);
521         vga_out16 (0x3d4, 0xa039, par);
522         vga_out16 (0x3c4, 0x0608, par);
523
524         vga_out8 (0x3d4, 0x66, par);
525         cr66 = vga_in8 (0x3d5, par);
526         vga_out8 (0x3d5, cr66 | 0x80, par);
527         vga_out8 (0x3d4, 0x3a, par);
528         cr3a = vga_in8 (0x3d5, par);
529         vga_out8 (0x3d5, cr3a | 0x80, par);
530         vga_out8 (0x3d4, 0x53, par);
531         cr53 = vga_in8 (0x3d5, par);
532         vga_out8 (0x3d5, cr53 & 0x7f, par);
533
534         vga_out8 (0x3d4, 0x66, par);
535         vga_out8 (0x3d5, cr66, par);
536         vga_out8 (0x3d4, 0x3a, par);
537         vga_out8 (0x3d5, cr3a, par);
538
539         vga_out8 (0x3d4, 0x66, par);
540         vga_out8 (0x3d5, cr66, par);
541         vga_out8 (0x3d4, 0x3a, par);
542         vga_out8 (0x3d5, cr3a, par);
543
544         /* unlock extended seq regs */
545         vga_out8 (0x3c4, 0x08, par);
546         par->SR08 = vga_in8 (0x3c5, par);
547         vga_out8 (0x3c5, 0x06, par);
548
549         /* now save all the extended regs we need */
550         vga_out8 (0x3d4, 0x31, par);
551         par->CR31 = vga_in8 (0x3d5, par);
552         vga_out8 (0x3d4, 0x32, par);
553         par->CR32 = vga_in8 (0x3d5, par);
554         vga_out8 (0x3d4, 0x34, par);
555         par->CR34 = vga_in8 (0x3d5, par);
556         vga_out8 (0x3d4, 0x36, par);
557         par->CR36 = vga_in8 (0x3d5, par);
558         vga_out8 (0x3d4, 0x3a, par);
559         par->CR3A = vga_in8 (0x3d5, par);
560         vga_out8 (0x3d4, 0x40, par);
561         par->CR40 = vga_in8 (0x3d5, par);
562         vga_out8 (0x3d4, 0x42, par);
563         par->CR42 = vga_in8 (0x3d5, par);
564         vga_out8 (0x3d4, 0x45, par);
565         par->CR45 = vga_in8 (0x3d5, par);
566         vga_out8 (0x3d4, 0x50, par);
567         par->CR50 = vga_in8 (0x3d5, par);
568         vga_out8 (0x3d4, 0x51, par);
569         par->CR51 = vga_in8 (0x3d5, par);
570         vga_out8 (0x3d4, 0x53, par);
571         par->CR53 = vga_in8 (0x3d5, par);
572         vga_out8 (0x3d4, 0x58, par);
573         par->CR58 = vga_in8 (0x3d5, par);
574         vga_out8 (0x3d4, 0x60, par);
575         par->CR60 = vga_in8 (0x3d5, par);
576         vga_out8 (0x3d4, 0x66, par);
577         par->CR66 = vga_in8 (0x3d5, par);
578         vga_out8 (0x3d4, 0x67, par);
579         par->CR67 = vga_in8 (0x3d5, par);
580         vga_out8 (0x3d4, 0x68, par);
581         par->CR68 = vga_in8 (0x3d5, par);
582         vga_out8 (0x3d4, 0x69, par);
583         par->CR69 = vga_in8 (0x3d5, par);
584         vga_out8 (0x3d4, 0x6f, par);
585         par->CR6F = vga_in8 (0x3d5, par);
586
587         vga_out8 (0x3d4, 0x33, par);
588         par->CR33 = vga_in8 (0x3d5, par);
589         vga_out8 (0x3d4, 0x86, par);
590         par->CR86 = vga_in8 (0x3d5, par);
591         vga_out8 (0x3d4, 0x88, par);
592         par->CR88 = vga_in8 (0x3d5, par);
593         vga_out8 (0x3d4, 0x90, par);
594         par->CR90 = vga_in8 (0x3d5, par);
595         vga_out8 (0x3d4, 0x91, par);
596         par->CR91 = vga_in8 (0x3d5, par);
597         vga_out8 (0x3d4, 0xb0, par);
598         par->CRB0 = vga_in8 (0x3d5, par) | 0x80;
599
600         /* extended mode timing regs */
601         vga_out8 (0x3d4, 0x3b, par);
602         par->CR3B = vga_in8 (0x3d5, par);
603         vga_out8 (0x3d4, 0x3c, par);
604         par->CR3C = vga_in8 (0x3d5, par);
605         vga_out8 (0x3d4, 0x43, par);
606         par->CR43 = vga_in8 (0x3d5, par);
607         vga_out8 (0x3d4, 0x5d, par);
608         par->CR5D = vga_in8 (0x3d5, par);
609         vga_out8 (0x3d4, 0x5e, par);
610         par->CR5E = vga_in8 (0x3d5, par);
611         vga_out8 (0x3d4, 0x65, par);
612         par->CR65 = vga_in8 (0x3d5, par);
613
614         /* save seq extended regs for DCLK PLL programming */
615         vga_out8 (0x3c4, 0x0e, par);
616         par->SR0E = vga_in8 (0x3c5, par);
617         vga_out8 (0x3c4, 0x0f, par);
618         par->SR0F = vga_in8 (0x3c5, par);
619         vga_out8 (0x3c4, 0x10, par);
620         par->SR10 = vga_in8 (0x3c5, par);
621         vga_out8 (0x3c4, 0x11, par);
622         par->SR11 = vga_in8 (0x3c5, par);
623         vga_out8 (0x3c4, 0x12, par);
624         par->SR12 = vga_in8 (0x3c5, par);
625         vga_out8 (0x3c4, 0x13, par);
626         par->SR13 = vga_in8 (0x3c5, par);
627         vga_out8 (0x3c4, 0x29, par);
628         par->SR29 = vga_in8 (0x3c5, par);
629
630         vga_out8 (0x3c4, 0x15, par);
631         par->SR15 = vga_in8 (0x3c5, par);
632         vga_out8 (0x3c4, 0x30, par);
633         par->SR30 = vga_in8 (0x3c5, par);
634         vga_out8 (0x3c4, 0x18, par);
635         par->SR18 = vga_in8 (0x3c5, par);
636
637         /* Save flat panel expansion regsters. */
638         if (par->chip == S3_SAVAGE_MX) {
639                 int i;
640
641                 for (i = 0; i < 8; i++) {
642                         vga_out8 (0x3c4, 0x54+i, par);
643                         par->SR54[i] = vga_in8 (0x3c5, par);
644                 }
645         }
646
647         vga_out8 (0x3d4, 0x66, par);
648         cr66 = vga_in8 (0x3d5, par);
649         vga_out8 (0x3d5, cr66 | 0x80, par);
650         vga_out8 (0x3d4, 0x3a, par);
651         cr3a = vga_in8 (0x3d5, par);
652         vga_out8 (0x3d5, cr3a | 0x80, par);
653
654         /* now save MIU regs */
655         if (par->chip != S3_SAVAGE_MX) {
656                 par->MMPR0 = savage_in32(FIFO_CONTROL_REG, par);
657                 par->MMPR1 = savage_in32(MIU_CONTROL_REG, par);
658                 par->MMPR2 = savage_in32(STREAMS_TIMEOUT_REG, par);
659                 par->MMPR3 = savage_in32(MISC_TIMEOUT_REG, par);
660         }
661
662         vga_out8 (0x3d4, 0x3a, par);
663         vga_out8 (0x3d5, cr3a, par);
664         vga_out8 (0x3d4, 0x66, par);
665         vga_out8 (0x3d5, cr66, par);
666 }
667
668 static void savage_update_var(struct fb_var_screeninfo *var, struct fb_videomode *modedb)
669 {
670         var->xres = var->xres_virtual = modedb->xres;
671         var->yres = modedb->yres;
672         if (var->yres_virtual < var->yres)
673             var->yres_virtual = var->yres;
674         var->xoffset = var->yoffset = 0;
675         var->pixclock = modedb->pixclock;
676         var->left_margin = modedb->left_margin;
677         var->right_margin = modedb->right_margin;
678         var->upper_margin = modedb->upper_margin;
679         var->lower_margin = modedb->lower_margin;
680         var->hsync_len = modedb->hsync_len;
681         var->vsync_len = modedb->vsync_len;
682         var->sync = modedb->sync;
683         var->vmode = modedb->vmode;
684 }
685
686 static int savagefb_check_var (struct fb_var_screeninfo   *var,
687                                struct fb_info *info)
688 {
689         struct savagefb_par *par = info->par;
690         int memlen, vramlen, mode_valid = 0;
691
692         DBG("savagefb_check_var");
693
694         var->transp.offset = 0;
695         var->transp.length = 0;
696         switch (var->bits_per_pixel) {
697         case 8:
698                 var->red.offset = var->green.offset =
699                         var->blue.offset = 0;
700                 var->red.length = var->green.length =
701                         var->blue.length = var->bits_per_pixel;
702                 break;
703         case 16:
704                 var->red.offset = 11;
705                 var->red.length = 5;
706                 var->green.offset = 5;
707                 var->green.length = 6;
708                 var->blue.offset = 0;
709                 var->blue.length = 5;
710                 break;
711         case 32:
712                 var->transp.offset = 24;
713                 var->transp.length = 8;
714                 var->red.offset = 16;
715                 var->red.length = 8;
716                 var->green.offset = 8;
717                 var->green.length = 8;
718                 var->blue.offset = 0;
719                 var->blue.length = 8;
720                 break;
721
722         default:
723                 return -EINVAL;
724         }
725
726         if (!info->monspecs.hfmax || !info->monspecs.vfmax ||
727             !info->monspecs.dclkmax || !fb_validate_mode(var, info))
728                 mode_valid = 1;
729
730         /* calculate modeline if supported by monitor */
731         if (!mode_valid && info->monspecs.gtf) {
732                 if (!fb_get_mode(FB_MAXTIMINGS, 0, var, info))
733                         mode_valid = 1;
734         }
735
736         if (!mode_valid) {
737                 struct fb_videomode *mode;
738
739                 mode = fb_find_best_mode(var, &info->modelist);
740                 if (mode) {
741                         savage_update_var(var, mode);
742                         mode_valid = 1;
743                 }
744         }
745
746         if (!mode_valid && info->monspecs.modedb_len)
747                 return -EINVAL;
748
749         /* Is the mode larger than the LCD panel? */
750         if (par->SavagePanelWidth &&
751             (var->xres > par->SavagePanelWidth ||
752              var->yres > par->SavagePanelHeight)) {
753                 printk (KERN_INFO "Mode (%dx%d) larger than the LCD panel "
754                         "(%dx%d)\n", var->xres,  var->yres,
755                         par->SavagePanelWidth,
756                         par->SavagePanelHeight);
757                 return -1;
758         }
759
760         if (var->yres_virtual < var->yres)
761                 var->yres_virtual = var->yres;
762         if (var->xres_virtual < var->xres)
763                 var->xres_virtual = var->xres;
764
765         vramlen = info->fix.smem_len;
766
767         memlen = var->xres_virtual * var->bits_per_pixel *
768                 var->yres_virtual / 8;
769         if (memlen > vramlen) {
770                 var->yres_virtual = vramlen * 8 /
771                         (var->xres_virtual * var->bits_per_pixel);
772                 memlen = var->xres_virtual * var->bits_per_pixel *
773                         var->yres_virtual / 8;
774         }
775
776         /* we must round yres/xres down, we already rounded y/xres_virtual up
777            if it was possible. We should return -EINVAL, but I disagree */
778         if (var->yres_virtual < var->yres)
779                 var->yres = var->yres_virtual;
780         if (var->xres_virtual < var->xres)
781                 var->xres = var->xres_virtual;
782         if (var->xoffset + var->xres > var->xres_virtual)
783                 var->xoffset = var->xres_virtual - var->xres;
784         if (var->yoffset + var->yres > var->yres_virtual)
785                 var->yoffset = var->yres_virtual - var->yres;
786
787         return 0;
788 }
789
790
791 static int savagefb_decode_var (struct fb_var_screeninfo   *var,
792                                 struct savagefb_par        *par)
793 {
794         struct xtimings timings;
795         int width, dclk, i, j; /*, refresh; */
796         unsigned int m, n, r;
797         unsigned char tmp = 0;
798         unsigned int pixclock = var->pixclock;
799
800         DBG("savagefb_decode_var");
801
802         memset (&timings, 0, sizeof(timings));
803
804         if (!pixclock) pixclock = 10000;        /* 10ns = 100MHz */
805         timings.Clock = 1000000000 / pixclock;
806         if (timings.Clock < 1) timings.Clock = 1;
807         timings.dblscan = var->vmode & FB_VMODE_DOUBLE;
808         timings.interlaced = var->vmode & FB_VMODE_INTERLACED;
809         timings.HDisplay = var->xres;
810         timings.HSyncStart = timings.HDisplay + var->right_margin;
811         timings.HSyncEnd = timings.HSyncStart + var->hsync_len;
812         timings.HTotal = timings.HSyncEnd + var->left_margin;
813         timings.VDisplay = var->yres;
814         timings.VSyncStart = timings.VDisplay + var->lower_margin;
815         timings.VSyncEnd = timings.VSyncStart + var->vsync_len;
816         timings.VTotal = timings.VSyncEnd + var->upper_margin;
817         timings.sync = var->sync;
818
819
820         par->depth  = var->bits_per_pixel;
821         par->vwidth = var->xres_virtual;
822
823         if (var->bits_per_pixel == 16  &&  par->chip == S3_SAVAGE3D) {
824                 timings.HDisplay *= 2;
825                 timings.HSyncStart *= 2;
826                 timings.HSyncEnd *= 2;
827                 timings.HTotal *= 2;
828         }
829
830         /*
831          * This will allocate the datastructure and initialize all of the
832          * generic VGA registers.
833          */
834         vgaHWInit (var, par, &timings);
835
836         /* We need to set CR67 whether or not we use the BIOS. */
837
838         dclk = timings.Clock;
839         par->CR67 = 0x00;
840
841         switch( var->bits_per_pixel ) {
842         case 8:
843                 if( (par->chip == S3_SAVAGE2000) && (dclk >= 230000) )
844                         par->CR67 = 0x10;       /* 8bpp, 2 pixels/clock */
845                 else
846                         par->CR67 = 0x00;       /* 8bpp, 1 pixel/clock */
847                 break;
848         case 15:
849                 if ( S3_SAVAGE_MOBILE_SERIES(par->chip) ||
850                      ((par->chip == S3_SAVAGE2000) && (dclk >= 230000)) )
851                         par->CR67 = 0x30;       /* 15bpp, 2 pixel/clock */
852                 else
853                         par->CR67 = 0x20;       /* 15bpp, 1 pixels/clock */
854                 break;
855         case 16:
856                 if( S3_SAVAGE_MOBILE_SERIES(par->chip) ||
857                     ((par->chip == S3_SAVAGE2000) && (dclk >= 230000)) )
858                         par->CR67 = 0x50;       /* 16bpp, 2 pixel/clock */
859                 else
860                         par->CR67 = 0x40;       /* 16bpp, 1 pixels/clock */
861                 break;
862         case 24:
863                 par->CR67 = 0x70;
864                 break;
865         case 32:
866                 par->CR67 = 0xd0;
867                 break;
868         }
869
870         /*
871          * Either BIOS use is disabled, or we failed to find a suitable
872          * match.  Fall back to traditional register-crunching.
873          */
874
875         vga_out8 (0x3d4, 0x3a, par);
876         tmp = vga_in8 (0x3d5, par);
877         if (1 /*FIXME:psav->pci_burst*/)
878                 par->CR3A = (tmp & 0x7f) | 0x15;
879         else
880                 par->CR3A = tmp | 0x95;
881
882         par->CR53 = 0x00;
883         par->CR31 = 0x8c;
884         par->CR66 = 0x89;
885
886         vga_out8 (0x3d4, 0x58, par);
887         par->CR58 = vga_in8 (0x3d5, par) & 0x80;
888         par->CR58 |= 0x13;
889
890         par->SR15 = 0x03 | 0x80;
891         par->SR18 = 0x00;
892         par->CR43 = par->CR45 = par->CR65 = 0x00;
893
894         vga_out8 (0x3d4, 0x40, par);
895         par->CR40 = vga_in8 (0x3d5, par) & ~0x01;
896
897         par->MMPR0 = 0x010400;
898         par->MMPR1 = 0x00;
899         par->MMPR2 = 0x0808;
900         par->MMPR3 = 0x08080810;
901
902         SavageCalcClock (dclk, 1, 1, 127, 0, 4, 180000, 360000, &m, &n, &r);
903         /* m = 107; n = 4; r = 2; */
904
905         if (par->MCLK <= 0) {
906                 par->SR10 = 255;
907                 par->SR11 = 255;
908         } else {
909                 common_calc_clock (par->MCLK, 1, 1, 31, 0, 3, 135000, 270000,
910                                    &par->SR11, &par->SR10);
911                 /*      par->SR10 = 80; // MCLK == 286000 */
912                 /*      par->SR11 = 125; */
913         }
914
915         par->SR12 = (r << 6) | (n & 0x3f);
916         par->SR13 = m & 0xff;
917         par->SR29 = (r & 4) | (m & 0x100) >> 5 | (n & 0x40) >> 2;
918
919         if (var->bits_per_pixel < 24)
920                 par->MMPR0 -= 0x8000;
921         else
922                 par->MMPR0 -= 0x4000;
923
924         if (timings.interlaced)
925                 par->CR42 = 0x20;
926         else
927                 par->CR42 = 0x00;
928
929         par->CR34 = 0x10; /* display fifo */
930
931         i = ((((timings.HTotal >> 3) - 5) & 0x100) >> 8) |
932                 ((((timings.HDisplay >> 3) - 1) & 0x100) >> 7) |
933                 ((((timings.HSyncStart >> 3) - 1) & 0x100) >> 6) |
934                 ((timings.HSyncStart & 0x800) >> 7);
935
936         if ((timings.HSyncEnd >> 3) - (timings.HSyncStart >> 3) > 64)
937                 i |= 0x08;
938         if ((timings.HSyncEnd >> 3) - (timings.HSyncStart >> 3) > 32)
939                 i |= 0x20;
940
941         j = (par->CRTC[0] + ((i & 0x01) << 8) +
942              par->CRTC[4] + ((i & 0x10) << 4) + 1) / 2;
943
944         if (j - (par->CRTC[4] + ((i & 0x10) << 4)) < 4) {
945                 if (par->CRTC[4] + ((i & 0x10) << 4) + 4 <=
946                     par->CRTC[0] + ((i & 0x01) << 8))
947                         j = par->CRTC[4] + ((i & 0x10) << 4) + 4;
948                 else
949                         j = par->CRTC[0] + ((i & 0x01) << 8) + 1;
950         }
951
952         par->CR3B = j & 0xff;
953         i |= (j & 0x100) >> 2;
954         par->CR3C = (par->CRTC[0] + ((i & 0x01) << 8)) / 2;
955         par->CR5D = i;
956         par->CR5E = (((timings.VTotal - 2) & 0x400) >> 10) |
957                 (((timings.VDisplay - 1) & 0x400) >> 9) |
958                 (((timings.VSyncStart) & 0x400) >> 8) |
959                 (((timings.VSyncStart) & 0x400) >> 6) | 0x40;
960         width = (var->xres_virtual * ((var->bits_per_pixel+7) / 8)) >> 3;
961         par->CR91 = par->CRTC[19] = 0xff & width;
962         par->CR51 = (0x300 & width) >> 4;
963         par->CR90 = 0x80 | (width >> 8);
964         par->MiscOutReg |= 0x0c;
965
966         /* Set frame buffer description. */
967
968         if (var->bits_per_pixel <= 8)
969                 par->CR50 = 0;
970         else if (var->bits_per_pixel <= 16)
971                 par->CR50 = 0x10;
972         else
973                 par->CR50 = 0x30;
974
975         if (var->xres_virtual <= 640)
976                 par->CR50 |= 0x40;
977         else if (var->xres_virtual == 800)
978                 par->CR50 |= 0x80;
979         else if (var->xres_virtual == 1024)
980                 par->CR50 |= 0x00;
981         else if (var->xres_virtual == 1152)
982                 par->CR50 |= 0x01;
983         else if (var->xres_virtual == 1280)
984                 par->CR50 |= 0xc0;
985         else if (var->xres_virtual == 1600)
986                 par->CR50 |= 0x81;
987         else
988                 par->CR50 |= 0xc1;      /* Use GBD */
989
990         if( par->chip == S3_SAVAGE2000 )
991                 par->CR33 = 0x08;
992         else
993                 par->CR33 = 0x20;
994
995         par->CRTC[0x17] = 0xeb;
996
997         par->CR67 |= 1;
998
999         vga_out8(0x3d4, 0x36, par);
1000         par->CR36 = vga_in8 (0x3d5, par);
1001         vga_out8 (0x3d4, 0x68, par);
1002         par->CR68 = vga_in8 (0x3d5, par);
1003         par->CR69 = 0;
1004         vga_out8 (0x3d4, 0x6f, par);
1005         par->CR6F = vga_in8 (0x3d5, par);
1006         vga_out8 (0x3d4, 0x86, par);
1007         par->CR86 = vga_in8 (0x3d5, par);
1008         vga_out8 (0x3d4, 0x88, par);
1009         par->CR88 = vga_in8 (0x3d5, par) | 0x08;
1010         vga_out8 (0x3d4, 0xb0, par);
1011         par->CRB0 = vga_in8 (0x3d5, par) | 0x80;
1012
1013         return 0;
1014 }
1015
1016 /* --------------------------------------------------------------------- */
1017
1018 /*
1019  *    Set a single color register. Return != 0 for invalid regno.
1020  */
1021 static int savagefb_setcolreg(unsigned        regno,
1022                               unsigned        red,
1023                               unsigned        green,
1024                               unsigned        blue,
1025                               unsigned        transp,
1026                               struct fb_info *info)
1027 {
1028         struct savagefb_par *par = info->par;
1029
1030         if (regno >= NR_PALETTE)
1031                 return -EINVAL;
1032
1033         par->palette[regno].red    = red;
1034         par->palette[regno].green  = green;
1035         par->palette[regno].blue   = blue;
1036         par->palette[regno].transp = transp;
1037
1038         switch (info->var.bits_per_pixel) {
1039         case 8:
1040                 vga_out8 (0x3c8, regno, par);
1041
1042                 vga_out8 (0x3c9, red   >> 10, par);
1043                 vga_out8 (0x3c9, green >> 10, par);
1044                 vga_out8 (0x3c9, blue  >> 10, par);
1045                 break;
1046
1047         case 16:
1048                 if (regno < 16)
1049                         ((u32 *)info->pseudo_palette)[regno] =
1050                                 ((red   & 0xf800)      ) |
1051                                 ((green & 0xfc00) >>  5) |
1052                                 ((blue  & 0xf800) >> 11);
1053                 break;
1054
1055         case 24:
1056                 if (regno < 16)
1057                         ((u32 *)info->pseudo_palette)[regno] =
1058                                 ((red    & 0xff00) <<  8) |
1059                                 ((green  & 0xff00)      ) |
1060                                 ((blue   & 0xff00) >>  8);
1061                 break;
1062         case 32:
1063                 if (regno < 16)
1064                         ((u32 *)info->pseudo_palette)[regno] =
1065                                 ((transp & 0xff00) << 16) |
1066                                 ((red    & 0xff00) <<  8) |
1067                                 ((green  & 0xff00)      ) |
1068                                 ((blue   & 0xff00) >>  8);
1069                 break;
1070
1071         default:
1072                 return 1;
1073         }
1074
1075         return 0;
1076 }
1077
1078 static void savagefb_set_par_int (struct savagefb_par  *par)
1079 {
1080         unsigned char tmp, cr3a, cr66, cr67;
1081
1082         DBG ("savagefb_set_par_int");
1083
1084         par->SavageWaitIdle (par);
1085
1086         vga_out8 (0x3c2, 0x23, par);
1087
1088         vga_out16 (0x3d4, 0x4838, par);
1089         vga_out16 (0x3d4, 0xa539, par);
1090         vga_out16 (0x3c4, 0x0608, par);
1091
1092         vgaHWProtect (par, 1);
1093
1094         /*
1095          * Some Savage/MX and /IX systems go nuts when trying to exit the
1096          * server after WindowMaker has displayed a gradient background.  I
1097          * haven't been able to find what causes it, but a non-destructive
1098          * switch to mode 3 here seems to eliminate the issue.
1099          */
1100
1101         VerticalRetraceWait(par);
1102         vga_out8 (0x3d4, 0x67, par);
1103         cr67 = vga_in8 (0x3d5, par);
1104         vga_out8 (0x3d5, cr67/*par->CR67*/ & ~0x0c, par); /* no STREAMS yet */
1105
1106         vga_out8 (0x3d4, 0x23, par);
1107         vga_out8 (0x3d5, 0x00, par);
1108         vga_out8 (0x3d4, 0x26, par);
1109         vga_out8 (0x3d5, 0x00, par);
1110
1111         /* restore extended regs */
1112         vga_out8 (0x3d4, 0x66, par);
1113         vga_out8 (0x3d5, par->CR66, par);
1114         vga_out8 (0x3d4, 0x3a, par);
1115         vga_out8 (0x3d5, par->CR3A, par);
1116         vga_out8 (0x3d4, 0x31, par);
1117         vga_out8 (0x3d5, par->CR31, par);
1118         vga_out8 (0x3d4, 0x32, par);
1119         vga_out8 (0x3d5, par->CR32, par);
1120         vga_out8 (0x3d4, 0x58, par);
1121         vga_out8 (0x3d5, par->CR58, par);
1122         vga_out8 (0x3d4, 0x53, par);
1123         vga_out8 (0x3d5, par->CR53 & 0x7f, par);
1124
1125         vga_out16 (0x3c4, 0x0608, par);
1126
1127         /* Restore DCLK registers. */
1128
1129         vga_out8 (0x3c4, 0x0e, par);
1130         vga_out8 (0x3c5, par->SR0E, par);
1131         vga_out8 (0x3c4, 0x0f, par);
1132         vga_out8 (0x3c5, par->SR0F, par);
1133         vga_out8 (0x3c4, 0x29, par);
1134         vga_out8 (0x3c5, par->SR29, par);
1135         vga_out8 (0x3c4, 0x15, par);
1136         vga_out8 (0x3c5, par->SR15, par);
1137
1138         /* Restore flat panel expansion regsters. */
1139         if( par->chip == S3_SAVAGE_MX ) {
1140                 int i;
1141
1142                 for( i = 0; i < 8; i++ ) {
1143                         vga_out8 (0x3c4, 0x54+i, par);
1144                         vga_out8 (0x3c5, par->SR54[i], par);
1145                 }
1146         }
1147
1148         vgaHWRestore (par);
1149
1150         /* extended mode timing registers */
1151         vga_out8 (0x3d4, 0x53, par);
1152         vga_out8 (0x3d5, par->CR53, par);
1153         vga_out8 (0x3d4, 0x5d, par);
1154         vga_out8 (0x3d5, par->CR5D, par);
1155         vga_out8 (0x3d4, 0x5e, par);
1156         vga_out8 (0x3d5, par->CR5E, par);
1157         vga_out8 (0x3d4, 0x3b, par);
1158         vga_out8 (0x3d5, par->CR3B, par);
1159         vga_out8 (0x3d4, 0x3c, par);
1160         vga_out8 (0x3d5, par->CR3C, par);
1161         vga_out8 (0x3d4, 0x43, par);
1162         vga_out8 (0x3d5, par->CR43, par);
1163         vga_out8 (0x3d4, 0x65, par);
1164         vga_out8 (0x3d5, par->CR65, par);
1165
1166         /* restore the desired video mode with cr67 */
1167         vga_out8 (0x3d4, 0x67, par);
1168         /* following part not present in X11 driver */
1169         cr67 = vga_in8 (0x3d5, par) & 0xf;
1170         vga_out8 (0x3d5, 0x50 | cr67, par);
1171         udelay (10000);
1172         vga_out8 (0x3d4, 0x67, par);
1173         /* end of part */
1174         vga_out8 (0x3d5, par->CR67 & ~0x0c, par);
1175
1176         /* other mode timing and extended regs */
1177         vga_out8 (0x3d4, 0x34, par);
1178         vga_out8 (0x3d5, par->CR34, par);
1179         vga_out8 (0x3d4, 0x40, par);
1180         vga_out8 (0x3d5, par->CR40, par);
1181         vga_out8 (0x3d4, 0x42, par);
1182         vga_out8 (0x3d5, par->CR42, par);
1183         vga_out8 (0x3d4, 0x45, par);
1184         vga_out8 (0x3d5, par->CR45, par);
1185         vga_out8 (0x3d4, 0x50, par);
1186         vga_out8 (0x3d5, par->CR50, par);
1187         vga_out8 (0x3d4, 0x51, par);
1188         vga_out8 (0x3d5, par->CR51, par);
1189
1190         /* memory timings */
1191         vga_out8 (0x3d4, 0x36, par);
1192         vga_out8 (0x3d5, par->CR36, par);
1193         vga_out8 (0x3d4, 0x60, par);
1194         vga_out8 (0x3d5, par->CR60, par);
1195         vga_out8 (0x3d4, 0x68, par);
1196         vga_out8 (0x3d5, par->CR68, par);
1197         vga_out8 (0x3d4, 0x69, par);
1198         vga_out8 (0x3d5, par->CR69, par);
1199         vga_out8 (0x3d4, 0x6f, par);
1200         vga_out8 (0x3d5, par->CR6F, par);
1201
1202         vga_out8 (0x3d4, 0x33, par);
1203         vga_out8 (0x3d5, par->CR33, par);
1204         vga_out8 (0x3d4, 0x86, par);
1205         vga_out8 (0x3d5, par->CR86, par);
1206         vga_out8 (0x3d4, 0x88, par);
1207         vga_out8 (0x3d5, par->CR88, par);
1208         vga_out8 (0x3d4, 0x90, par);
1209         vga_out8 (0x3d5, par->CR90, par);
1210         vga_out8 (0x3d4, 0x91, par);
1211         vga_out8 (0x3d5, par->CR91, par);
1212
1213         if (par->chip == S3_SAVAGE4) {
1214                 vga_out8 (0x3d4, 0xb0, par);
1215                 vga_out8 (0x3d5, par->CRB0, par);
1216         }
1217
1218         vga_out8 (0x3d4, 0x32, par);
1219         vga_out8 (0x3d5, par->CR32, par);
1220
1221         /* unlock extended seq regs */
1222         vga_out8 (0x3c4, 0x08, par);
1223         vga_out8 (0x3c5, 0x06, par);
1224
1225         /* Restore extended sequencer regs for MCLK. SR10 == 255 indicates
1226          * that we should leave the default SR10 and SR11 values there.
1227          */
1228         if (par->SR10 != 255) {
1229                 vga_out8 (0x3c4, 0x10, par);
1230                 vga_out8 (0x3c5, par->SR10, par);
1231                 vga_out8 (0x3c4, 0x11, par);
1232                 vga_out8 (0x3c5, par->SR11, par);
1233         }
1234
1235         /* restore extended seq regs for dclk */
1236         vga_out8 (0x3c4, 0x0e, par);
1237         vga_out8 (0x3c5, par->SR0E, par);
1238         vga_out8 (0x3c4, 0x0f, par);
1239         vga_out8 (0x3c5, par->SR0F, par);
1240         vga_out8 (0x3c4, 0x12, par);
1241         vga_out8 (0x3c5, par->SR12, par);
1242         vga_out8 (0x3c4, 0x13, par);
1243         vga_out8 (0x3c5, par->SR13, par);
1244         vga_out8 (0x3c4, 0x29, par);
1245         vga_out8 (0x3c5, par->SR29, par);
1246
1247         vga_out8 (0x3c4, 0x18, par);
1248         vga_out8 (0x3c5, par->SR18, par);
1249
1250         /* load new m, n pll values for dclk & mclk */
1251         vga_out8 (0x3c4, 0x15, par);
1252         tmp = vga_in8 (0x3c5, par) & ~0x21;
1253
1254         vga_out8 (0x3c5, tmp | 0x03, par);
1255         vga_out8 (0x3c5, tmp | 0x23, par);
1256         vga_out8 (0x3c5, tmp | 0x03, par);
1257         vga_out8 (0x3c5, par->SR15, par);
1258         udelay (100);
1259
1260         vga_out8 (0x3c4, 0x30, par);
1261         vga_out8 (0x3c5, par->SR30, par);
1262         vga_out8 (0x3c4, 0x08, par);
1263         vga_out8 (0x3c5, par->SR08, par);
1264
1265         /* now write out cr67 in full, possibly starting STREAMS */
1266         VerticalRetraceWait(par);
1267         vga_out8 (0x3d4, 0x67, par);
1268         vga_out8 (0x3d5, par->CR67, par);
1269
1270         vga_out8 (0x3d4, 0x66, par);
1271         cr66 = vga_in8 (0x3d5, par);
1272         vga_out8 (0x3d5, cr66 | 0x80, par);
1273         vga_out8 (0x3d4, 0x3a, par);
1274         cr3a = vga_in8 (0x3d5, par);
1275         vga_out8 (0x3d5, cr3a | 0x80, par);
1276
1277         if (par->chip != S3_SAVAGE_MX) {
1278                 VerticalRetraceWait(par);
1279                 savage_out32 (FIFO_CONTROL_REG, par->MMPR0, par);
1280                 par->SavageWaitIdle (par);
1281                 savage_out32 (MIU_CONTROL_REG, par->MMPR1, par);
1282                 par->SavageWaitIdle (par);
1283                 savage_out32 (STREAMS_TIMEOUT_REG, par->MMPR2, par);
1284                 par->SavageWaitIdle (par);
1285                 savage_out32 (MISC_TIMEOUT_REG, par->MMPR3, par);
1286         }
1287
1288         vga_out8 (0x3d4, 0x66, par);
1289         vga_out8 (0x3d5, cr66, par);
1290         vga_out8 (0x3d4, 0x3a, par);
1291         vga_out8 (0x3d5, cr3a, par);
1292
1293         SavageSetup2DEngine (par);
1294         vgaHWProtect (par, 0);
1295 }
1296
1297 static void savagefb_update_start (struct savagefb_par      *par,
1298                                    struct fb_var_screeninfo *var)
1299 {
1300         int base;
1301
1302         base = ((var->yoffset * var->xres_virtual + (var->xoffset & ~1))
1303                 * ((var->bits_per_pixel+7) / 8)) >> 2;
1304
1305         /* now program the start address registers */
1306         vga_out16(0x3d4, (base & 0x00ff00) | 0x0c, par);
1307         vga_out16(0x3d4, ((base & 0x00ff) << 8) | 0x0d, par);
1308         vga_out8 (0x3d4, 0x69, par);
1309         vga_out8 (0x3d5, (base & 0x7f0000) >> 16, par);
1310 }
1311
1312
1313 static void savagefb_set_fix(struct fb_info *info)
1314 {
1315         info->fix.line_length = info->var.xres_virtual *
1316                 info->var.bits_per_pixel / 8;
1317
1318         if (info->var.bits_per_pixel == 8) {
1319                 info->fix.visual      = FB_VISUAL_PSEUDOCOLOR;
1320                 info->fix.xpanstep    = 4;
1321         } else {
1322                 info->fix.visual      = FB_VISUAL_TRUECOLOR;
1323                 info->fix.xpanstep    = 2;
1324         }
1325
1326 }
1327
1328 #if defined(CONFIG_FB_SAVAGE_ACCEL)
1329 static void savagefb_set_clip(struct fb_info *info)
1330 {
1331     struct savagefb_par *par = info->par;
1332     int cmd;
1333
1334     cmd = BCI_CMD_NOP | BCI_CMD_CLIP_NEW;
1335     par->bci_ptr = 0;
1336     par->SavageWaitFifo(par,3);
1337     BCI_SEND(cmd);
1338     BCI_SEND(BCI_CLIP_TL(0, 0));
1339     BCI_SEND(BCI_CLIP_BR(0xfff, 0xfff));
1340 }
1341 #endif
1342
1343 static int savagefb_set_par (struct fb_info *info)
1344 {
1345         struct savagefb_par *par = info->par;
1346         struct fb_var_screeninfo *var = &info->var;
1347         int err;
1348
1349         DBG("savagefb_set_par");
1350         err = savagefb_decode_var (var, par);
1351         if (err)
1352                 return err;
1353
1354         if (par->dacSpeedBpp <= 0) {
1355                 if (var->bits_per_pixel > 24)
1356                         par->dacSpeedBpp = par->clock[3];
1357                 else if (var->bits_per_pixel >= 24)
1358                         par->dacSpeedBpp = par->clock[2];
1359                 else if ((var->bits_per_pixel > 8) && (var->bits_per_pixel < 24))
1360                         par->dacSpeedBpp = par->clock[1];
1361                 else if (var->bits_per_pixel <= 8)
1362                         par->dacSpeedBpp = par->clock[0];
1363         }
1364
1365         /* Set ramdac limits */
1366         par->maxClock = par->dacSpeedBpp;
1367         par->minClock = 10000;
1368
1369         savagefb_set_par_int (par);
1370         fb_set_cmap (&info->cmap, info);
1371         savagefb_set_fix(info);
1372         savagefb_set_clip(info);
1373
1374         SavagePrintRegs();
1375         return 0;
1376 }
1377
1378 /*
1379  *    Pan or Wrap the Display
1380  */
1381 static int savagefb_pan_display (struct fb_var_screeninfo *var,
1382                                  struct fb_info           *info)
1383 {
1384         struct savagefb_par *par = info->par;
1385         u_int y_bottom;
1386
1387         y_bottom = var->yoffset;
1388
1389         if (!(var->vmode & FB_VMODE_YWRAP))
1390                 y_bottom += var->yres;
1391
1392         if (var->xoffset > (var->xres_virtual - var->xres))
1393                 return -EINVAL;
1394         if (y_bottom > info->var.yres_virtual)
1395                 return -EINVAL;
1396
1397         savagefb_update_start (par, var);
1398
1399         info->var.xoffset = var->xoffset;
1400         info->var.yoffset = var->yoffset;
1401
1402         if (var->vmode & FB_VMODE_YWRAP)
1403                 info->var.vmode |= FB_VMODE_YWRAP;
1404         else
1405                 info->var.vmode &= ~FB_VMODE_YWRAP;
1406
1407         return 0;
1408 }
1409
1410 static int savagefb_blank(int blank, struct fb_info *info)
1411 {
1412         struct savagefb_par *par = info->par;
1413         u8 sr8 = 0, srd = 0;
1414
1415         if (par->display_type == DISP_CRT) {
1416                 vga_out8(0x3c4, 0x08, par);
1417                 sr8 = vga_in8(0x3c5, par);
1418                 sr8 |= 0x06;
1419                 vga_out8(0x3c5, sr8, par);
1420                 vga_out8(0x3c4, 0x0d, par);
1421                 srd = vga_in8(0x3c5, par);
1422                 srd &= 0x03;
1423
1424                 switch (blank) {
1425                 case FB_BLANK_UNBLANK:
1426                 case FB_BLANK_NORMAL:
1427                         break;
1428                 case FB_BLANK_VSYNC_SUSPEND:
1429                         srd |= 0x10;
1430                         break;
1431                 case FB_BLANK_HSYNC_SUSPEND:
1432                         srd |= 0x40;
1433                         break;
1434                 case FB_BLANK_POWERDOWN:
1435                         srd |= 0x50;
1436                         break;
1437                 }
1438
1439                 vga_out8(0x3c4, 0x0d, par);
1440                 vga_out8(0x3c5, srd, par);
1441         }
1442
1443         if (par->display_type == DISP_LCD ||
1444             par->display_type == DISP_DFP) {
1445                 switch(blank) {
1446                 case FB_BLANK_UNBLANK:
1447                 case FB_BLANK_NORMAL:
1448                         vga_out8(0x3c4, 0x31, par); /* SR31 bit 4 - FP enable */
1449                         vga_out8(0x3c5, vga_in8(0x3c5, par) | 0x10, par);
1450                         break;
1451                 case FB_BLANK_VSYNC_SUSPEND:
1452                 case FB_BLANK_HSYNC_SUSPEND:
1453                 case FB_BLANK_POWERDOWN:
1454                         vga_out8(0x3c4, 0x31, par); /* SR31 bit 4 - FP enable */
1455                         vga_out8(0x3c5, vga_in8(0x3c5, par) & ~0x10, par);
1456                         break;
1457                 }
1458         }
1459
1460         return (blank == FB_BLANK_NORMAL) ? 1 : 0;
1461 }
1462
1463 static struct fb_ops savagefb_ops = {
1464         .owner          = THIS_MODULE,
1465         .fb_check_var   = savagefb_check_var,
1466         .fb_set_par     = savagefb_set_par,
1467         .fb_setcolreg   = savagefb_setcolreg,
1468         .fb_pan_display = savagefb_pan_display,
1469         .fb_blank       = savagefb_blank,
1470 #if defined(CONFIG_FB_SAVAGE_ACCEL)
1471         .fb_fillrect    = savagefb_fillrect,
1472         .fb_copyarea    = savagefb_copyarea,
1473         .fb_imageblit   = savagefb_imageblit,
1474         .fb_sync        = savagefb_sync,
1475 #else
1476         .fb_fillrect    = cfb_fillrect,
1477         .fb_copyarea    = cfb_copyarea,
1478         .fb_imageblit   = cfb_imageblit,
1479 #endif
1480 };
1481
1482 /* --------------------------------------------------------------------- */
1483
1484 static struct fb_var_screeninfo __devinitdata savagefb_var800x600x8 = {
1485         .accel_flags =  FB_ACCELF_TEXT,
1486         .xres =         800,
1487         .yres =         600,
1488         .xres_virtual =  800,
1489         .yres_virtual =  600,
1490         .bits_per_pixel = 8,
1491         .pixclock =     25000,
1492         .left_margin =  88,
1493         .right_margin = 40,
1494         .upper_margin = 23,
1495         .lower_margin = 1,
1496         .hsync_len =    128,
1497         .vsync_len =    4,
1498         .sync =         FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,
1499         .vmode =        FB_VMODE_NONINTERLACED
1500 };
1501
1502 static void savage_enable_mmio (struct savagefb_par *par)
1503 {
1504         unsigned char val;
1505
1506         DBG ("savage_enable_mmio\n");
1507
1508         val = vga_in8 (0x3c3, par);
1509         vga_out8 (0x3c3, val | 0x01, par);
1510         val = vga_in8 (0x3cc, par);
1511         vga_out8 (0x3c2, val | 0x01, par);
1512
1513         if (par->chip >= S3_SAVAGE4) {
1514                 vga_out8 (0x3d4, 0x40, par);
1515                 val = vga_in8 (0x3d5, par);
1516                 vga_out8 (0x3d5, val | 1, par);
1517         }
1518 }
1519
1520
1521 static void savage_disable_mmio (struct savagefb_par *par)
1522 {
1523         unsigned char val;
1524
1525         DBG ("savage_disable_mmio\n");
1526
1527         if(par->chip >= S3_SAVAGE4 ) {
1528                 vga_out8 (0x3d4, 0x40, par);
1529                 val = vga_in8 (0x3d5, par);
1530                 vga_out8 (0x3d5, val | 1, par);
1531         }
1532 }
1533
1534
1535 static int __devinit savage_map_mmio (struct fb_info *info)
1536 {
1537         struct savagefb_par *par = info->par;
1538         DBG ("savage_map_mmio");
1539
1540         if (S3_SAVAGE3D_SERIES (par->chip))
1541                 par->mmio.pbase = pci_resource_start (par->pcidev, 0) +
1542                         SAVAGE_NEWMMIO_REGBASE_S3;
1543         else
1544                 par->mmio.pbase = pci_resource_start (par->pcidev, 0) +
1545                         SAVAGE_NEWMMIO_REGBASE_S4;
1546
1547         par->mmio.len = SAVAGE_NEWMMIO_REGSIZE;
1548
1549         par->mmio.vbase = ioremap (par->mmio.pbase, par->mmio.len);
1550         if (!par->mmio.vbase) {
1551                 printk ("savagefb: unable to map memory mapped IO\n");
1552                 return -ENOMEM;
1553         } else
1554                 printk (KERN_INFO "savagefb: mapped io at %p\n",
1555                         par->mmio.vbase);
1556
1557         info->fix.mmio_start = par->mmio.pbase;
1558         info->fix.mmio_len   = par->mmio.len;
1559
1560         par->bci_base = (u32 __iomem *)(par->mmio.vbase + BCI_BUFFER_OFFSET);
1561         par->bci_ptr  = 0;
1562
1563         savage_enable_mmio (par);
1564
1565         return 0;
1566 }
1567
1568 static void __devinit savage_unmap_mmio (struct fb_info *info)
1569 {
1570         struct savagefb_par *par = info->par;
1571         DBG ("savage_unmap_mmio");
1572
1573         savage_disable_mmio(par);
1574
1575         if (par->mmio.vbase) {
1576                 iounmap(par->mmio.vbase);
1577                 par->mmio.vbase = NULL;
1578         }
1579 }
1580
1581 static int __devinit savage_map_video (struct fb_info *info,
1582                                        int video_len)
1583 {
1584         struct savagefb_par *par = info->par;
1585         int resource;
1586
1587         DBG("savage_map_video");
1588
1589         if (S3_SAVAGE3D_SERIES (par->chip))
1590                 resource = 0;
1591         else
1592                 resource = 1;
1593
1594         par->video.pbase = pci_resource_start (par->pcidev, resource);
1595         par->video.len   = video_len;
1596         par->video.vbase = ioremap (par->video.pbase, par->video.len);
1597
1598         if (!par->video.vbase) {
1599                 printk ("savagefb: unable to map screen memory\n");
1600                 return -ENOMEM;
1601         } else
1602                 printk (KERN_INFO "savagefb: mapped framebuffer at %p, "
1603                         "pbase == %x\n", par->video.vbase, par->video.pbase);
1604
1605         info->fix.smem_start = par->video.pbase;
1606         info->fix.smem_len   = par->video.len - par->cob_size;
1607         info->screen_base    = par->video.vbase;
1608
1609 #ifdef CONFIG_MTRR
1610         par->video.mtrr = mtrr_add (par->video.pbase, video_len,
1611                                      MTRR_TYPE_WRCOMB, 1);
1612 #endif
1613
1614         /* Clear framebuffer, it's all white in memory after boot */
1615         memset_io (par->video.vbase, 0, par->video.len);
1616
1617         return 0;
1618 }
1619
1620 static void __devinit savage_unmap_video (struct fb_info *info)
1621 {
1622         struct savagefb_par *par = info->par;
1623
1624         DBG("savage_unmap_video");
1625
1626         if (par->video.vbase) {
1627 #ifdef CONFIG_MTRR
1628                 mtrr_del (par->video.mtrr, par->video.pbase, par->video.len);
1629 #endif
1630
1631                 iounmap (par->video.vbase);
1632                 par->video.vbase = NULL;
1633                 info->screen_base = NULL;
1634         }
1635 }
1636
1637 static int __devinit savage_init_hw (struct savagefb_par *par)
1638 {
1639         unsigned char config1, m, n, n1, n2, sr8, cr3f, cr66 = 0, tmp;
1640
1641         static unsigned char RamSavage3D[] = { 8, 4, 4, 2 };
1642         static unsigned char RamSavage4[] =  { 2, 4, 8, 12, 16, 32, 64, 32 };
1643         static unsigned char RamSavageMX[] = { 2, 8, 4, 16, 8, 16, 4, 16 };
1644         static unsigned char RamSavageNB[] = { 0, 2, 4, 8, 16, 32, 2, 2 };
1645         int videoRam, videoRambytes, dvi;
1646
1647         DBG("savage_init_hw");
1648
1649         /* unprotect CRTC[0-7] */
1650         vga_out8(0x3d4, 0x11, par);
1651         tmp = vga_in8(0x3d5, par);
1652         vga_out8(0x3d5, tmp & 0x7f, par);
1653
1654         /* unlock extended regs */
1655         vga_out16(0x3d4, 0x4838, par);
1656         vga_out16(0x3d4, 0xa039, par);
1657         vga_out16(0x3c4, 0x0608, par);
1658
1659         vga_out8(0x3d4, 0x40, par);
1660         tmp = vga_in8(0x3d5, par);
1661         vga_out8(0x3d5, tmp & ~0x01, par);
1662
1663         /* unlock sys regs */
1664         vga_out8(0x3d4, 0x38, par);
1665         vga_out8(0x3d5, 0x48, par);
1666
1667         /* Unlock system registers. */
1668         vga_out16(0x3d4, 0x4838, par);
1669
1670         /* Next go on to detect amount of installed ram */
1671
1672         vga_out8(0x3d4, 0x36, par);            /* for register CR36 (CONFG_REG1), */
1673         config1 = vga_in8(0x3d5, par);    /* get amount of vram installed */
1674
1675         /* Compute the amount of video memory and offscreen memory. */
1676
1677         switch  (par->chip) {
1678         case S3_SAVAGE3D:
1679                 videoRam = RamSavage3D[ (config1 & 0xC0) >> 6 ] * 1024;
1680                 break;
1681
1682         case S3_SAVAGE4:
1683                 /*
1684                  * The Savage4 has one ugly special case to consider.  On
1685                  * systems with 4 banks of 2Mx32 SDRAM, the BIOS says 4MB
1686                  * when it really means 8MB.  Why do it the same when you
1687                  * can do it different...
1688                  */
1689                 vga_out8(0x3d4, 0x68, par);     /* memory control 1 */
1690                 if( (vga_in8(0x3d5, par) & 0xC0) == (0x01 << 6) )
1691                         RamSavage4[1] = 8;
1692
1693                 /*FALLTHROUGH*/
1694
1695         case S3_SAVAGE2000:
1696                 videoRam = RamSavage4[ (config1 & 0xE0) >> 5 ] * 1024;
1697                 break;
1698
1699         case S3_SAVAGE_MX:
1700         case S3_SUPERSAVAGE:
1701                 videoRam = RamSavageMX[ (config1 & 0x0E) >> 1 ] * 1024;
1702                 break;
1703
1704         case S3_PROSAVAGE:
1705                 videoRam = RamSavageNB[ (config1 & 0xE0) >> 5 ] * 1024;
1706                 break;
1707
1708         default:
1709                 /* How did we get here? */
1710                 videoRam = 0;
1711                 break;
1712         }
1713
1714         videoRambytes = videoRam * 1024;
1715
1716         printk (KERN_INFO "savagefb: probed videoram:  %dk\n", videoRam);
1717
1718         /* reset graphics engine to avoid memory corruption */
1719         vga_out8 (0x3d4, 0x66, par);
1720         cr66 = vga_in8 (0x3d5, par);
1721         vga_out8 (0x3d5, cr66 | 0x02, par);
1722         udelay (10000);
1723
1724         vga_out8 (0x3d4, 0x66, par);
1725         vga_out8 (0x3d5, cr66 & ~0x02, par);    /* clear reset flag */
1726         udelay (10000);
1727
1728
1729         /*
1730          * reset memory interface, 3D engine, AGP master, PCI master,
1731          * master engine unit, motion compensation/LPB
1732          */
1733         vga_out8 (0x3d4, 0x3f, par);
1734         cr3f = vga_in8 (0x3d5, par);
1735         vga_out8 (0x3d5, cr3f | 0x08, par);
1736         udelay (10000);
1737
1738         vga_out8 (0x3d4, 0x3f, par);
1739         vga_out8 (0x3d5, cr3f & ~0x08, par);    /* clear reset flags */
1740         udelay (10000);
1741
1742         /* Savage ramdac speeds */
1743         par->numClocks = 4;
1744         par->clock[0] = 250000;
1745         par->clock[1] = 250000;
1746         par->clock[2] = 220000;
1747         par->clock[3] = 220000;
1748
1749         /* detect current mclk */
1750         vga_out8(0x3c4, 0x08, par);
1751         sr8 = vga_in8(0x3c5, par);
1752         vga_out8(0x3c5, 0x06, par);
1753         vga_out8(0x3c4, 0x10, par);
1754         n = vga_in8(0x3c5, par);
1755         vga_out8(0x3c4, 0x11, par);
1756         m = vga_in8(0x3c5, par);
1757         vga_out8(0x3c4, 0x08, par);
1758         vga_out8(0x3c5, sr8, par);
1759         m &= 0x7f;
1760         n1 = n & 0x1f;
1761         n2 = (n >> 5) & 0x03;
1762         par->MCLK = ((1431818 * (m+2)) / (n1+2) / (1 << n2) + 50) / 100;
1763         printk (KERN_INFO "savagefb: Detected current MCLK value of %d kHz\n",
1764                 par->MCLK);
1765
1766         /* check for DVI/flat panel */
1767         dvi = 0;
1768
1769         if (par->chip == S3_SAVAGE4) {
1770                 unsigned char sr30 = 0x00;
1771
1772                 vga_out8(0x3c4, 0x30, par);
1773                 /* clear bit 1 */
1774                 vga_out8(0x3c5, vga_in8(0x3c5, par) & ~0x02, par);
1775                 sr30 = vga_in8(0x3c5, par);
1776                 if (sr30 & 0x02 /*0x04 */) {
1777                         dvi = 1;
1778                         printk("savagefb: Digital Flat Panel Detected\n");
1779                 }
1780         }
1781
1782         if (S3_SAVAGE_MOBILE_SERIES(par->chip) && !par->crtonly)
1783                 par->display_type = DISP_LCD;
1784         else if (dvi || (par->chip == S3_SAVAGE4 && par->dvi))
1785                 par->display_type = DISP_DFP;
1786         else
1787                 par->display_type = DISP_CRT;
1788
1789         /* Check LCD panel parrmation */
1790
1791         if (par->display_type == DISP_LCD) {
1792                 unsigned char cr6b = VGArCR( 0x6b, par);
1793
1794                 int panelX = (VGArSEQ (0x61, par) +
1795                               ((VGArSEQ (0x66, par) & 0x02) << 7) + 1) * 8;
1796                 int panelY = (VGArSEQ (0x69, par) +
1797                               ((VGArSEQ (0x6e, par) & 0x70) << 4) + 1);
1798
1799                 char * sTechnology = "Unknown";
1800
1801                 /* OK, I admit it.  I don't know how to limit the max dot clock
1802                  * for LCD panels of various sizes.  I thought I copied the
1803                  * formula from the BIOS, but many users have parrmed me of
1804                  * my folly.
1805                  *
1806                  * Instead, I'll abandon any attempt to automatically limit the
1807                  * clock, and add an LCDClock option to XF86Config.  Some day,
1808                  * I should come back to this.
1809                  */
1810
1811                 enum ACTIVE_DISPLAYS { /* These are the bits in CR6B */
1812                         ActiveCRT = 0x01,
1813                         ActiveLCD = 0x02,
1814                         ActiveTV = 0x04,
1815                         ActiveCRT2 = 0x20,
1816                         ActiveDUO = 0x80
1817                 };
1818
1819                 if ((VGArSEQ (0x39, par) & 0x03) == 0) {
1820                         sTechnology = "TFT";
1821                 } else if ((VGArSEQ (0x30, par) & 0x01) == 0) {
1822                         sTechnology = "DSTN";
1823                 } else  {
1824                         sTechnology = "STN";
1825                 }
1826
1827                 printk (KERN_INFO "savagefb: %dx%d %s LCD panel detected %s\n",
1828                         panelX, panelY, sTechnology,
1829                         cr6b & ActiveLCD ? "and active" : "but not active");
1830
1831                 if( cr6b & ActiveLCD )  {
1832                         /*
1833                          * If the LCD is active and panel expansion is enabled,
1834                          * we probably want to kill the HW cursor.
1835                          */
1836
1837                         printk (KERN_INFO "savagefb: Limiting video mode to "
1838                                 "%dx%d\n", panelX, panelY );
1839
1840                         par->SavagePanelWidth = panelX;
1841                         par->SavagePanelHeight = panelY;
1842
1843                 } else
1844                         par->display_type = DISP_CRT;
1845         }
1846
1847         savage_get_default_par (par);
1848
1849         if( S3_SAVAGE4_SERIES(par->chip) ) {
1850                 /*
1851                  * The Savage4 and ProSavage have COB coherency bugs which
1852                  * render the buffer useless.  We disable it.
1853                  */
1854                 par->cob_index = 2;
1855                 par->cob_size = 0x8000 << par->cob_index;
1856                 par->cob_offset = videoRambytes;
1857         } else {
1858                 /* We use 128kB for the COB on all chips. */
1859
1860                 par->cob_index  = 7;
1861                 par->cob_size   = 0x400 << par->cob_index;
1862                 par->cob_offset = videoRambytes - par->cob_size;
1863         }
1864
1865         return videoRambytes;
1866 }
1867
1868 static int __devinit savage_init_fb_info (struct fb_info *info,
1869                                           struct pci_dev *dev,
1870                                           const struct pci_device_id *id)
1871 {
1872         struct savagefb_par *par = info->par;
1873         int err = 0;
1874
1875         par->pcidev  = dev;
1876
1877         info->fix.type     = FB_TYPE_PACKED_PIXELS;
1878         info->fix.type_aux         = 0;
1879         info->fix.ypanstep         = 1;
1880         info->fix.ywrapstep   = 0;
1881         info->fix.accel       = id->driver_data;
1882
1883         switch (info->fix.accel) {
1884         case FB_ACCEL_SUPERSAVAGE:
1885                 par->chip = S3_SUPERSAVAGE;
1886                 snprintf (info->fix.id, 16, "SuperSavage");
1887                 break;
1888         case FB_ACCEL_SAVAGE4:
1889                 par->chip = S3_SAVAGE4;
1890                 snprintf (info->fix.id, 16, "Savage4");
1891                 break;
1892         case FB_ACCEL_SAVAGE3D:
1893                 par->chip = S3_SAVAGE3D;
1894                 snprintf (info->fix.id, 16, "Savage3D");
1895                 break;
1896         case FB_ACCEL_SAVAGE3D_MV:
1897                 par->chip = S3_SAVAGE3D;
1898                 snprintf (info->fix.id, 16, "Savage3D-MV");
1899                 break;
1900         case FB_ACCEL_SAVAGE2000:
1901                 par->chip = S3_SAVAGE2000;
1902                 snprintf (info->fix.id, 16, "Savage2000");
1903                 break;
1904         case FB_ACCEL_SAVAGE_MX_MV:
1905                 par->chip = S3_SAVAGE_MX;
1906                 snprintf (info->fix.id, 16, "Savage/MX-MV");
1907                 break;
1908         case FB_ACCEL_SAVAGE_MX:
1909                 par->chip = S3_SAVAGE_MX;
1910                 snprintf (info->fix.id, 16, "Savage/MX");
1911                 break;
1912         case FB_ACCEL_SAVAGE_IX_MV:
1913                 par->chip = S3_SAVAGE_MX;
1914                 snprintf (info->fix.id, 16, "Savage/IX-MV");
1915                 break;
1916         case FB_ACCEL_SAVAGE_IX:
1917                 par->chip = S3_SAVAGE_MX;
1918                 snprintf (info->fix.id, 16, "Savage/IX");
1919                 break;
1920         case FB_ACCEL_PROSAVAGE_PM:
1921                 par->chip = S3_PROSAVAGE;
1922                 snprintf (info->fix.id, 16, "ProSavagePM");
1923                 break;
1924         case FB_ACCEL_PROSAVAGE_KM:
1925                 par->chip = S3_PROSAVAGE;
1926                 snprintf (info->fix.id, 16, "ProSavageKM");
1927                 break;
1928         case FB_ACCEL_S3TWISTER_P:
1929                 par->chip = S3_PROSAVAGE;
1930                 snprintf (info->fix.id, 16, "TwisterP");
1931                 break;
1932         case FB_ACCEL_S3TWISTER_K:
1933                 par->chip = S3_PROSAVAGE;
1934                 snprintf (info->fix.id, 16, "TwisterK");
1935                 break;
1936         case FB_ACCEL_PROSAVAGE_DDR:
1937                 par->chip = S3_PROSAVAGE;
1938                 snprintf (info->fix.id, 16, "ProSavageDDR");
1939                 break;
1940         case FB_ACCEL_PROSAVAGE_DDRK:
1941                 par->chip = S3_PROSAVAGE;
1942                 snprintf (info->fix.id, 16, "ProSavage8");
1943                 break;
1944         }
1945
1946         if (S3_SAVAGE3D_SERIES(par->chip)) {
1947                 par->SavageWaitIdle = savage3D_waitidle;
1948                 par->SavageWaitFifo = savage3D_waitfifo;
1949         } else if (S3_SAVAGE4_SERIES(par->chip) ||
1950                    S3_SUPERSAVAGE == par->chip) {
1951                 par->SavageWaitIdle = savage4_waitidle;
1952                 par->SavageWaitFifo = savage4_waitfifo;
1953         } else {
1954                 par->SavageWaitIdle = savage2000_waitidle;
1955                 par->SavageWaitFifo = savage2000_waitfifo;
1956         }
1957
1958         info->var.nonstd      = 0;
1959         info->var.activate    = FB_ACTIVATE_NOW;
1960         info->var.width       = -1;
1961         info->var.height      = -1;
1962         info->var.accel_flags = 0;
1963
1964         info->fbops          = &savagefb_ops;
1965         info->flags          = FBINFO_DEFAULT |
1966                                FBINFO_HWACCEL_YPAN |
1967                                FBINFO_HWACCEL_XPAN;
1968
1969         info->pseudo_palette = par->pseudo_palette;
1970
1971 #if defined(CONFIG_FB_SAVAGE_ACCEL)
1972         /* FIFO size + padding for commands */
1973         info->pixmap.addr = kmalloc(8*1024, GFP_KERNEL);
1974
1975         err = -ENOMEM;
1976         if (info->pixmap.addr) {
1977                 memset(info->pixmap.addr, 0, 8*1024);
1978                 info->pixmap.size = 8*1024;
1979                 info->pixmap.scan_align = 4;
1980                 info->pixmap.buf_align = 4;
1981                 info->pixmap.access_align = 32;
1982
1983                 err = fb_alloc_cmap (&info->cmap, NR_PALETTE, 0);
1984                 if (!err)
1985                 info->flags |= FBINFO_HWACCEL_COPYAREA |
1986                                FBINFO_HWACCEL_FILLRECT |
1987                                FBINFO_HWACCEL_IMAGEBLIT;
1988         }
1989 #endif
1990         return err;
1991 }
1992
1993 /* --------------------------------------------------------------------- */
1994
1995 static int __devinit savagefb_probe (struct pci_dev* dev,
1996                                      const struct pci_device_id* id)
1997 {
1998         struct fb_info *info;
1999         struct savagefb_par *par;
2000         u_int h_sync, v_sync;
2001         int err, lpitch;
2002         int video_len;
2003
2004         DBG("savagefb_probe");
2005         SavagePrintRegs();
2006
2007         info = framebuffer_alloc(sizeof(struct savagefb_par), &dev->dev);
2008         if (!info)
2009                 return -ENOMEM;
2010         par = info->par;
2011         err = pci_enable_device(dev);
2012         if (err)
2013                 goto failed_enable;
2014
2015         if ((err = pci_request_regions(dev, "savagefb"))) {
2016                 printk(KERN_ERR "cannot request PCI regions\n");
2017                 goto failed_enable;
2018         }
2019
2020         err = -ENOMEM;
2021
2022         if ((err = savage_init_fb_info(info, dev, id)))
2023                 goto failed_init;
2024
2025         err = savage_map_mmio(info);
2026         if (err)
2027                 goto failed_mmio;
2028
2029         video_len = savage_init_hw(par);
2030         /* FIXME: cant be negative */
2031         if (video_len < 0) {
2032                 err = video_len;
2033                 goto failed_mmio;
2034         }
2035
2036         err = savage_map_video(info, video_len);
2037         if (err)
2038                 goto failed_video;
2039
2040         INIT_LIST_HEAD(&info->modelist);
2041 #if defined(CONFIG_FB_SAVAGE_I2C)
2042         savagefb_create_i2c_busses(info);
2043         savagefb_probe_i2c_connector(info, &par->edid);
2044         kfree(par->edid);
2045         fb_edid_to_monspecs(par->edid, &info->monspecs);
2046         fb_videomode_to_modelist(info->monspecs.modedb,
2047                                  info->monspecs.modedb_len,
2048                                  &info->modelist);
2049 #endif
2050         info->var = savagefb_var800x600x8;
2051
2052         if (mode_option) {
2053                 fb_find_mode(&info->var, info, mode_option,
2054                              info->monspecs.modedb, info->monspecs.modedb_len,
2055                              NULL, 8);
2056         } else if (info->monspecs.modedb != NULL) {
2057                 struct fb_videomode *modedb;
2058
2059                 modedb = fb_find_best_display(&info->monspecs,
2060                                               &info->modelist);
2061                 savage_update_var(&info->var, modedb);
2062         }
2063
2064         /* maximize virtual vertical length */
2065         lpitch = info->var.xres_virtual*((info->var.bits_per_pixel + 7) >> 3);
2066         info->var.yres_virtual = info->fix.smem_len/lpitch;
2067
2068         if (info->var.yres_virtual < info->var.yres)
2069                 goto failed;
2070
2071 #if defined(CONFIG_FB_SAVAGE_ACCEL)
2072         /*
2073          * The clipping coordinates are masked with 0xFFF, so limit our
2074          * virtual resolutions to these sizes.
2075          */
2076         if (info->var.yres_virtual > 0x1000)
2077                 info->var.yres_virtual = 0x1000;
2078
2079         if (info->var.xres_virtual > 0x1000)
2080                 info->var.xres_virtual = 0x1000;
2081 #endif
2082         savagefb_check_var(&info->var, info);
2083         savagefb_set_fix(info);
2084
2085         /*
2086          * Calculate the hsync and vsync frequencies.  Note that
2087          * we split the 1e12 constant up so that we can preserve
2088          * the precision and fit the results into 32-bit registers.
2089          *  (1953125000 * 512 = 1e12)
2090          */
2091         h_sync = 1953125000 / info->var.pixclock;
2092         h_sync = h_sync * 512 / (info->var.xres + info->var.left_margin +
2093                                  info->var.right_margin +
2094                                  info->var.hsync_len);
2095         v_sync = h_sync / (info->var.yres + info->var.upper_margin +
2096                            info->var.lower_margin + info->var.vsync_len);
2097
2098         printk(KERN_INFO "savagefb v" SAVAGEFB_VERSION ": "
2099                "%dkB VRAM, using %dx%d, %d.%03dkHz, %dHz\n",
2100                info->fix.smem_len >> 10,
2101                info->var.xres, info->var.yres,
2102                h_sync / 1000, h_sync % 1000, v_sync);
2103
2104
2105         fb_destroy_modedb(info->monspecs.modedb);
2106         info->monspecs.modedb = NULL;
2107
2108         err = register_framebuffer (info);
2109         if (err < 0)
2110                 goto failed;
2111
2112         printk (KERN_INFO "fb: S3 %s frame buffer device\n",
2113                 info->fix.id);
2114
2115         /*
2116          * Our driver data
2117          */
2118         pci_set_drvdata(dev, info);
2119
2120         return 0;
2121
2122  failed:
2123 #ifdef CONFIG_FB_SAVAGE_I2C
2124         savagefb_delete_i2c_busses(info);
2125 #endif
2126         fb_alloc_cmap (&info->cmap, 0, 0);
2127         savage_unmap_video(info);
2128  failed_video:
2129         savage_unmap_mmio (info);
2130  failed_mmio:
2131         kfree(info->pixmap.addr);
2132  failed_init:
2133         pci_release_regions(dev);
2134  failed_enable:
2135         framebuffer_release(info);
2136
2137         return err;
2138 }
2139
2140 static void __devexit savagefb_remove (struct pci_dev *dev)
2141 {
2142         struct fb_info *info = pci_get_drvdata(dev);
2143
2144         DBG("savagefb_remove");
2145
2146         if (info) {
2147                 /*
2148                  * If unregister_framebuffer fails, then
2149                  * we will be leaving hooks that could cause
2150                  * oopsen laying around.
2151                  */
2152                 if (unregister_framebuffer (info))
2153                         printk (KERN_WARNING "savagefb: danger danger! "
2154                                 "Oopsen imminent!\n");
2155
2156 #ifdef CONFIG_FB_SAVAGE_I2C
2157                 savagefb_delete_i2c_busses(info);
2158 #endif
2159                 fb_alloc_cmap (&info->cmap, 0, 0);
2160                 savage_unmap_video (info);
2161                 savage_unmap_mmio (info);
2162                 kfree(info->pixmap.addr);
2163                 pci_release_regions(dev);
2164                 framebuffer_release(info);
2165
2166                 /*
2167                  * Ensure that the driver data is no longer
2168                  * valid.
2169                  */
2170                 pci_set_drvdata(dev, NULL);
2171         }
2172 }
2173
2174 static int savagefb_suspend (struct pci_dev* dev, pm_message_t state)
2175 {
2176         struct fb_info *info = pci_get_drvdata(dev);
2177         struct savagefb_par *par = info->par;
2178
2179         DBG("savagefb_suspend");
2180
2181
2182         par->pm_state = state.event;
2183
2184         /*
2185          * For PM_EVENT_FREEZE, do not power down so the console
2186          * can remain active.
2187          */
2188         if (state.event == PM_EVENT_FREEZE) {
2189                 dev->dev.power.power_state = state;
2190                 return 0;
2191         }
2192
2193         acquire_console_sem();
2194         fb_set_suspend(info, 1);
2195
2196         if (info->fbops->fb_sync)
2197                 info->fbops->fb_sync(info);
2198
2199         savagefb_blank(FB_BLANK_POWERDOWN, info);
2200         savage_disable_mmio(par);
2201         pci_save_state(dev);
2202         pci_disable_device(dev);
2203         pci_set_power_state(dev, pci_choose_state(dev, state));
2204         release_console_sem();
2205
2206         return 0;
2207 }
2208
2209 static int savagefb_resume (struct pci_dev* dev)
2210 {
2211         struct fb_info *info = pci_get_drvdata(dev);
2212         struct savagefb_par *par = info->par;
2213         int cur_state = par->pm_state;
2214
2215         DBG("savage_resume");
2216
2217         par->pm_state = PM_EVENT_ON;
2218
2219         /*
2220          * The adapter was not powered down coming back from a
2221          * PM_EVENT_FREEZE.
2222          */
2223         if (cur_state == PM_EVENT_FREEZE) {
2224                 pci_set_power_state(dev, PCI_D0);
2225                 return 0;
2226         }
2227
2228         acquire_console_sem();
2229
2230         pci_set_power_state(dev, PCI_D0);
2231         pci_restore_state(dev);
2232
2233         if(pci_enable_device(dev))
2234                 DBG("err");
2235
2236         pci_set_master(dev);
2237         savage_enable_mmio(par);
2238         savage_init_hw(par);
2239         savagefb_set_par (info);
2240         savagefb_blank(FB_BLANK_UNBLANK, info);
2241         fb_set_suspend (info, 0);
2242         release_console_sem();
2243
2244         return 0;
2245 }
2246
2247
2248 static struct pci_device_id savagefb_devices[] __devinitdata = {
2249         {PCI_VENDOR_ID_S3, PCI_CHIP_SUPSAV_MX128,
2250          PCI_ANY_ID, PCI_ANY_ID, 0, 0, FB_ACCEL_SUPERSAVAGE},
2251
2252         {PCI_VENDOR_ID_S3, PCI_CHIP_SUPSAV_MX64,
2253          PCI_ANY_ID, PCI_ANY_ID, 0, 0, FB_ACCEL_SUPERSAVAGE},
2254
2255         {PCI_VENDOR_ID_S3, PCI_CHIP_SUPSAV_MX64C,
2256          PCI_ANY_ID, PCI_ANY_ID, 0, 0, FB_ACCEL_SUPERSAVAGE},
2257
2258         {PCI_VENDOR_ID_S3, PCI_CHIP_SUPSAV_IX128SDR,
2259          PCI_ANY_ID, PCI_ANY_ID, 0, 0, FB_ACCEL_SUPERSAVAGE},
2260
2261         {PCI_VENDOR_ID_S3, PCI_CHIP_SUPSAV_IX128DDR,
2262          PCI_ANY_ID, PCI_ANY_ID, 0, 0, FB_ACCEL_SUPERSAVAGE},
2263
2264         {PCI_VENDOR_ID_S3, PCI_CHIP_SUPSAV_IX64SDR,
2265          PCI_ANY_ID, PCI_ANY_ID, 0, 0, FB_ACCEL_SUPERSAVAGE},
2266
2267         {PCI_VENDOR_ID_S3, PCI_CHIP_SUPSAV_IX64DDR,
2268          PCI_ANY_ID, PCI_ANY_ID, 0, 0, FB_ACCEL_SUPERSAVAGE},
2269
2270         {PCI_VENDOR_ID_S3, PCI_CHIP_SUPSAV_IXCSDR,
2271          PCI_ANY_ID, PCI_ANY_ID, 0, 0, FB_ACCEL_SUPERSAVAGE},
2272
2273         {PCI_VENDOR_ID_S3, PCI_CHIP_SUPSAV_IXCDDR,
2274          PCI_ANY_ID, PCI_ANY_ID, 0, 0, FB_ACCEL_SUPERSAVAGE},
2275
2276         {PCI_VENDOR_ID_S3, PCI_CHIP_SAVAGE4,
2277          PCI_ANY_ID, PCI_ANY_ID, 0, 0, FB_ACCEL_SAVAGE4},
2278
2279         {PCI_VENDOR_ID_S3, PCI_CHIP_SAVAGE3D,
2280          PCI_ANY_ID, PCI_ANY_ID, 0, 0, FB_ACCEL_SAVAGE3D},
2281
2282         {PCI_VENDOR_ID_S3, PCI_CHIP_SAVAGE3D_MV,
2283          PCI_ANY_ID, PCI_ANY_ID, 0, 0, FB_ACCEL_SAVAGE3D_MV},
2284
2285         {PCI_VENDOR_ID_S3, PCI_CHIP_SAVAGE2000,
2286          PCI_ANY_ID, PCI_ANY_ID, 0, 0, FB_ACCEL_SAVAGE2000},
2287
2288         {PCI_VENDOR_ID_S3, PCI_CHIP_SAVAGE_MX_MV,
2289          PCI_ANY_ID, PCI_ANY_ID, 0, 0, FB_ACCEL_SAVAGE_MX_MV},
2290
2291         {PCI_VENDOR_ID_S3, PCI_CHIP_SAVAGE_MX,
2292          PCI_ANY_ID, PCI_ANY_ID, 0, 0, FB_ACCEL_SAVAGE_MX},
2293
2294         {PCI_VENDOR_ID_S3, PCI_CHIP_SAVAGE_IX_MV,
2295          PCI_ANY_ID, PCI_ANY_ID, 0, 0, FB_ACCEL_SAVAGE_IX_MV},
2296
2297         {PCI_VENDOR_ID_S3, PCI_CHIP_SAVAGE_IX,
2298          PCI_ANY_ID, PCI_ANY_ID, 0, 0, FB_ACCEL_SAVAGE_IX},
2299
2300         {PCI_VENDOR_ID_S3, PCI_CHIP_PROSAVAGE_PM,
2301          PCI_ANY_ID, PCI_ANY_ID, 0, 0, FB_ACCEL_PROSAVAGE_PM},
2302
2303         {PCI_VENDOR_ID_S3, PCI_CHIP_PROSAVAGE_KM,
2304          PCI_ANY_ID, PCI_ANY_ID, 0, 0, FB_ACCEL_PROSAVAGE_KM},
2305
2306         {PCI_VENDOR_ID_S3, PCI_CHIP_S3TWISTER_P,
2307          PCI_ANY_ID, PCI_ANY_ID, 0, 0, FB_ACCEL_S3TWISTER_P},
2308
2309         {PCI_VENDOR_ID_S3, PCI_CHIP_S3TWISTER_K,
2310          PCI_ANY_ID, PCI_ANY_ID, 0, 0, FB_ACCEL_S3TWISTER_K},
2311
2312         {PCI_VENDOR_ID_S3, PCI_CHIP_PROSAVAGE_DDR,
2313          PCI_ANY_ID, PCI_ANY_ID, 0, 0, FB_ACCEL_PROSAVAGE_DDR},
2314
2315         {PCI_VENDOR_ID_S3, PCI_CHIP_PROSAVAGE_DDRK,
2316          PCI_ANY_ID, PCI_ANY_ID, 0, 0, FB_ACCEL_PROSAVAGE_DDRK},
2317
2318         {0, 0, 0, 0, 0, 0, 0}
2319 };
2320
2321 MODULE_DEVICE_TABLE(pci, savagefb_devices);
2322
2323 static struct pci_driver savagefb_driver = {
2324         .name =     "savagefb",
2325         .id_table = savagefb_devices,
2326         .probe =    savagefb_probe,
2327         .suspend =  savagefb_suspend,
2328         .resume =   savagefb_resume,
2329         .remove =   __devexit_p(savagefb_remove)
2330 };
2331
2332 /* **************************** exit-time only **************************** */
2333
2334 static void __exit savage_done (void)
2335 {
2336         DBG("savage_done");
2337         pci_unregister_driver (&savagefb_driver);
2338 }
2339
2340
2341 /* ************************* init in-kernel code ************************** */
2342
2343 static int __init savagefb_setup(char *options)
2344 {
2345 #ifndef MODULE
2346         char *this_opt;
2347
2348         if (!options || !*options)
2349                 return 0;
2350
2351         while ((this_opt = strsep(&options, ",")) != NULL) {
2352                 mode_option = this_opt;
2353         }
2354 #endif /* !MODULE */
2355         return 0;
2356 }
2357
2358 static int __init savagefb_init(void)
2359 {
2360         char *option;
2361
2362         DBG("savagefb_init");
2363
2364         if (fb_get_options("savagefb", &option))
2365                 return -ENODEV;
2366
2367         savagefb_setup(option);
2368         return pci_register_driver (&savagefb_driver);
2369
2370 }
2371
2372 module_init(savagefb_init);
2373 module_exit(savage_done);
2374
2375 module_param(mode_option, charp, 0);
2376 MODULE_PARM_DESC(mode_option, "Specify initial video mode");