1 /*
2 Matrox G200/G400/G450 chipset driver
3
4 Based on the XFree86 driver.
5
6 Tested only on a G450.
7
8 TODO: SDRAM, reference frequency checking.
9
10 */
11
12 #include <stdlib.h>
13 #include <stdio.h>
14 #include <string.h>
15 #include <unistd.h>
16 #include "vga.h"
17 #include "libvga.h"
18 #include "driver.h"
19 #include "timing.h"
20 #include "vgaregs.h"
21 #include "interface.h"
22 #include "accel.h"
23 #include "vgapci.h"
24
25 #define SKREG_SAVE(i) (VGA_TOTAL_REGS+i)
26 #define G400_TOTAL_REGS (VGA_TOTAL_REGS + 0x50 + 9 + 12)
27
__svgalib_outpal(int i,int r,int g,int b)28 static void __svgalib_outpal(int i, int r, int g, int b)
29 {
30
31 outb(PEL_IW,i);
32 outb(PEL_D,r);
33 outb(PEL_D,g);
34 outb(PEL_D,b);
35 }
36
37 enum { ID_G100 = 0, ID_G200, ID_G400, ID_G450 };
38
39 static int g400_init(int, int, int);
40 static void g400_unlock(void);
41 static void g400_lock(void);
42
43 void __svgalib_g400accel_init(AccelSpecs * accelspecs, int bpp, int width_in_pixels);
44
45 static int g400_memory, id;
46 static int g400_is_linear, g400_linear_base, g400_mmio_base;
47
48 static int HasSDRAM;
49
50 static CardSpecs *cardspecs;
51
g400_inExt(int i)52 static int g400_inExt(int i) {
53 *(MMIO_POINTER + 0x1fde) = i;
54 return *(MMIO_POINTER + 0x1fdf);
55 }
56
g400_outExt(int i,int d)57 static void g400_outExt(int i, int d) {
58 *(unsigned short *)(MMIO_POINTER + 0x1fde) = (d<<8) | i;
59 }
60
g400_inDAC(int i)61 static int g400_inDAC(int i) {
62 *(MMIO_POINTER + 0x3c00) = i;
63 return *(MMIO_POINTER + 0x3c0a);
64 }
65
g400_outDAC(int i,int d)66 static void g400_outDAC(int i, int d) {
67 *(MMIO_POINTER + 0x3c00) = i;
68 *(MMIO_POINTER + 0x3c0a) = d;
69 }
70
g400_setpage(int page)71 static void g400_setpage(int page)
72 {
73 g400_outExt(4,page);
74 }
75
__svgalib_g400_inlinearmode(void)76 static int __svgalib_g400_inlinearmode(void)
77 {
78 return g400_is_linear;
79 }
80
81 /* Fill in chipset specific mode information */
82
g400_getmodeinfo(int mode,vga_modeinfo * modeinfo)83 static void g400_getmodeinfo(int mode, vga_modeinfo *modeinfo)
84 {
85
86 if(modeinfo->colors==16)return;
87
88 modeinfo->maxpixels = g400_memory*1024/modeinfo->bytesperpixel;
89 modeinfo->maxlogicalwidth = 8184;
90 modeinfo->startaddressrange = g400_memory * 1024 - 1;
91 modeinfo->haveblit = 0;
92 modeinfo->flags &= ~HAVE_RWPAGE;
93
94 if (modeinfo->bytesperpixel >= 1) {
95 if(g400_linear_base)modeinfo->flags |= CAPABLE_LINEAR;
96 if (__svgalib_g400_inlinearmode())
97 modeinfo->flags |= IS_LINEAR;
98 }
99 }
100
101 /* Read and save chipset-specific registers */
102
103 #define PCI_CONF_ADDR 0xcf8
104 #define PCI_CONF_DATA 0xcfc
105
g400_saveregs(unsigned char regs[])106 static int g400_saveregs(unsigned char regs[])
107 {
108 int i;
109
110 g400_unlock();
111
112 outl (PCI_CONF_ADDR, 0x80010000 + 0x40);
113 *(unsigned int *)(regs + VGA_TOTAL_REGS + 0x50 + 9 + 0 ) = inl (PCI_CONF_DATA);
114 outl (PCI_CONF_ADDR, 0x80010000 + 0x50);
115 *(unsigned int *)(regs + VGA_TOTAL_REGS + 0x50 + 9 + 4 ) = inl (PCI_CONF_DATA);
116 outl (PCI_CONF_ADDR, 0x80010000 + 0x54);
117 *(unsigned int *)(regs + VGA_TOTAL_REGS + 0x50 + 9 + 8 ) = inl (PCI_CONF_DATA);
118
119 for(i=0;i<0x50;i++) regs[VGA_TOTAL_REGS + i]=g400_inDAC(i);
120 for(i=0;i<9;i++) regs[VGA_TOTAL_REGS + 0x50 + i]=g400_inExt(i);
121
122 return G400_TOTAL_REGS - VGA_TOTAL_REGS;
123 }
124
125 /* Set chipset-specific registers */
126
g400_setregs(const unsigned char regs[],int mode)127 static void g400_setregs(const unsigned char regs[], int mode)
128 {
129 int i;
130
131 g400_unlock();
132 for(i=0;i<0x50;i++) {
133 #if 0
134 if( (i> 0x03) && (i!=0x07) && (i!=0x0b) && (i!=0x0f) &&
135 (i< 0x13) && (i> 0x17) && (i!=0x1b) && (i!=0x1c) &&
136 (i< 0x1f) && (i> 0x29) && (i< 0x30) && (i> 0x37) &&
137 (i!=0x39) && (i!=0x3b) && (i!=0x3f) && (i!=0x41) &&
138 (i!=0x43) && (i!=0x47) && (i!=0x4b)
139 )
140 #endif
141 g400_outDAC(i,regs[VGA_TOTAL_REGS + i]);
142 }
143
144 outl (PCI_CONF_ADDR, 0x80010000 + 0x40);
145 outl(PCI_CONF_DATA, *(unsigned int *)(regs + VGA_TOTAL_REGS + 0x50 + 9 ));
146 outl (PCI_CONF_ADDR, 0x80010000 + 0x50);
147 outl(PCI_CONF_DATA, *(unsigned int *)(regs + VGA_TOTAL_REGS + 0x50 + 9 + 4 ));
148 outl (PCI_CONF_ADDR, 0x80010000 + 0x54);
149 outl(PCI_CONF_DATA, *(unsigned int *)(regs + VGA_TOTAL_REGS + 0x50 + 9 + 8 ));
150
151 for(i=0;i<9;i++) g400_outExt(i, regs[VGA_TOTAL_REGS + 0x50 + i]);
152
153 }
154
155
156 /* Return nonzero if mode is available */
157
g400_modeavailable(int mode)158 static int g400_modeavailable(int mode)
159 {
160 struct info *info;
161 ModeTiming *modetiming;
162 ModeInfo *modeinfo;
163
164 if (IS_IN_STANDARD_VGA_DRIVER(mode))
165 return __svgalib_vga_driverspecs.modeavailable(mode);
166
167 info = &__svgalib_infotable[mode];
168 if (g400_memory * 1024 < info->ydim * info->xbytes)
169 return 0;
170
171 modeinfo = __svgalib_createModeInfoStructureForSvgalibMode(mode);
172
173 modetiming = malloc(sizeof(ModeTiming));
174
175 if (__svgalib_getmodetiming(modetiming, modeinfo, cardspecs)) {
176 free(modetiming);
177 free(modeinfo);
178 return 0;
179 }
180
181 free(modetiming);
182 free(modeinfo);
183 return SVGADRV;
184 }
185
186 #define MGA_MIN_VCO_FREQ 120000
187 #define MGA_MAX_VCO_FREQ 250000
188 #define MGA_MAX_PCLK_FREQ 250000
189 #define MGA_MAX_MCLK_FREQ 100000
190 #define MGA_REF_FREQ 27050.0
191 #define MGA_ALT_REF_FREQ 14318.0
192 #define MGA_FEED_DIV_MIN 8
193 #define MGA_FEED_DIV_MAX 127
194 #define MGA_IN_DIV_MIN 1
195 #define MGA_IN_DIV_MAX 30
196 #define MGA_ALT_IN_DIV_MAX 6
197 #define MGA_POST_DIV_MIN 0
198 #define MGA_POST_DIV_MAX 3
199
200 static double
MGACalcClock(long f_out,long f_max,int * m,int * n,int * p,int * s)201 MGACalcClock ( long f_out, long f_max, int *m, int *n, int *p, int *s )
202 {
203 int best_m=0, best_n=0;
204 double f_pll, f_vco;
205 double m_err, calc_f, base_freq;
206 int mga_in_div_max;
207 static double ref = 0.0;
208
209 switch(id) {
210 case ID_G400:
211 case ID_G450:
212 ref = MGA_REF_FREQ;
213 mga_in_div_max = MGA_IN_DIV_MAX;
214 mga_in_div_max = MGA_ALT_IN_DIV_MAX; /* 31 should be allowed,
215 but does not work. */
216 break;
217 case ID_G200:
218 ref = MGA_ALT_REF_FREQ;
219 mga_in_div_max = MGA_ALT_IN_DIV_MAX;
220 break;
221 default:
222 ref = MGA_ALT_REF_FREQ;
223 mga_in_div_max = MGA_ALT_IN_DIV_MAX;
224 break;
225 }
226
227 /* Make sure that f_min <= f_out <= f_max */
228 if ( f_out < ( MGA_MIN_VCO_FREQ / 8))
229 f_out = MGA_MIN_VCO_FREQ / 8;
230
231 if ( f_out > f_max )
232 f_out = f_max;
233
234 /*
235 * f_pll = f_vco / (2^p)
236 * Choose p so that MGA_MIN_VCO_FREQ <= f_vco <= MGA_MAX_VCO_FREQ
237 * we don't have to bother checking for this maximum limit.
238 */
239 f_vco = ( double ) f_out;
240 for ( *p = 0; *p < MGA_POST_DIV_MAX && f_vco < MGA_MIN_VCO_FREQ;
241 ( *p )++ )
242 f_vco *= 2.0;
243
244 /* Initial value of calc_f for the loop */
245 calc_f = 0;
246
247 base_freq = ref / ( 1 << *p );
248
249 /* Initial amount of error for frequency maximum */
250 m_err = f_out;
251
252 /* Search for the different values of ( *m ) */
253 for ( *m = MGA_IN_DIV_MIN ;
254 *m < mga_in_div_max ; ( *m )++ )
255 {
256 /* see values of ( *n ) which we can't use */
257 for ( *n = MGA_FEED_DIV_MIN;
258 *n <= MGA_FEED_DIV_MAX; ( *n )++ )
259 {
260 calc_f = (base_freq * (*n)) / *m ;
261
262 /*
263 * Pick the closest frequency.
264 */
265 if (abs( calc_f - f_out ) < m_err ) {
266 m_err = abs(calc_f - f_out);
267 best_m = *m;
268 best_n = *n;
269 }
270 }
271 }
272
273 /* Now all the calculations can be completed */
274 f_vco = ref * best_n / best_m;
275
276 /* Adjustments for filtering pll feed back */
277 switch(id) {
278 case ID_G450:
279 *s=0;
280 break;
281 case ID_G400:
282 if ( (50000.0 <= f_vco)
283 && (f_vco < 110000.0) )
284 *s = 0;
285 if ( (110000.0 <= f_vco)
286 && (f_vco < 170000.0) )
287 *s = 1;
288 if ( (170000.0 <= f_vco)
289 && (f_vco < 240000.0) )
290 *s = 2;
291 if ( (240000.0 <= f_vco)
292 && (f_vco < 310000.0) )
293 *s = 3;
294 break;
295 case ID_G200:
296 if ( (50000.0 <= f_vco)
297 && (f_vco < 100000.0) )
298 *s = 0;
299 if ( (100000.0 <= f_vco)
300 && (f_vco < 140000.0) )
301 *s = 1;
302 if ( (140000.0 <= f_vco)
303 && (f_vco < 180000.0) )
304 *s = 2;
305 if ( (180000.0 <= f_vco)
306 && (f_vco < 250000.0) )
307 *s = 3;
308 break;
309 }
310
311 f_pll = f_vco / ( 1 << *p );
312
313 *m = best_m - 1;
314 *n = best_n - 1;
315 *p = ( 1 << *p ) - 1 ;
316
317 return f_pll;
318 }
319
320
321 /*
322 * MGASetPCLK - Set the pixel (PCLK) and loop (LCLK) clocks.
323 *
324 * PARAMETERS
325 * f_pll IN Pixel clock PLL frequencly in kHz.
326 */
327 static void
MGASetPCLK(long f_out,unsigned char * initDAC)328 MGASetPCLK( long f_out, unsigned char *initDAC )
329 {
330 /* Pixel clock values */
331 int m, n, p, s;
332
333 /* The actual frequency output by the clock */
334 double f_pll;
335 long f_max;
336
337 /* Get the maximum pixel clock frequency from the BIOS,
338 * or from a reasonable default
339 */
340 if ( 0 )
341 f_max = (/*MGABios2.PclkMax+*/100) * 1000; /* [ajv - scale it] */
342 else
343 f_max = MGA_MAX_PCLK_FREQ;
344
345 /* Do the calculations for m, n, and p */
346 f_pll = MGACalcClock( f_out, f_max, &m, &n, &p , &s);
347
348 /* Values for the pixel clock PLL registers */
349 if((id == ID_G450) && (p==3))p=2;
350
351 initDAC[ 0x4c ] = ( m & 0x1f );
352 initDAC[ 0x4d ] = ( n & 0x7f );
353 initDAC[ 0x4e ] = ( (p & 0x07) | ((s & 0x3) << 3) );
354 }
355
g400_initializemode(unsigned char * moderegs,ModeTiming * modetiming,ModeInfo * modeinfo,int mode)356 static void g400_initializemode(unsigned char *moderegs,
357 ModeTiming * modetiming, ModeInfo * modeinfo, int mode)
358 {
359 static unsigned char initDAC[] = {
360 /* 0x00: */ 0, 0, 0, 0, 0, 0, 0x00, 0,
361 /* 0x08: */ 0, 0, 0, 0, 0, 0, 0, 0,
362 /* 0x08: */ 0, 0, 0, 0, 0, 0, 0, 0,
363 /* 0x18: */ 0x03, 0, 0x09, 0xFF, 0xBF, 0x20, 0x1F, 0x20,
364 /* 0x20: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
365 /* 0x28: */ 0x00, 0x00, 0x00, 0x77, 0x04, 0x2D, 0x19, 0x40,
366 /* 0x30: */ 0x00, 0xB0, 0x00, 0xC2, 0x34, 0x14, 0x02, 0x83,
367 /* 0x38: */ 0x00, 0x93, 0x00, 0x77, 0x71, 0xDB, 0x02, 0x3A,
368 /* 0x40: */ 0, 0, 0, 0, 0, 0, 0, 0,
369 /* 0x48: */ 0, 0, 0, 0, 0, 0, 0, 0
370 };
371
372 int hd, hs, he, ht, vd, vs, ve, vt, wd;
373 int i;
374 int weight555 = 0;
375 int MGABppShft = 0;
376
377 __svgalib_setup_VGA_registers(moderegs, modetiming, modeinfo);
378
379 switch(modeinfo->bitsPerPixel)
380 {
381 case 8:
382 initDAC[ 0x19 ] = 0;
383 initDAC[ 0x1e ] &= ~8;
384 MGABppShft=0;
385 break;
386 case 16:
387 initDAC[ 0x19 ] = 2;
388 MGABppShft=1;
389 if ( modeinfo->greenWeight==5 ) {
390 weight555 = 1;
391 initDAC[ 0x19 ] = 1;
392 }
393 break;
394 case 24:
395 MGABppShft=0;
396 initDAC[ 0x19 ] = 3;
397 break;
398 case 32:
399 MGABppShft=2;
400 initDAC[ 0x19 ] = 7;
401 break;
402 }
403
404 /*
405 * Here all of the other fields of 'newVS' get filled in.
406 */
407 hd = (modetiming->CrtcHDisplay >> 3) - 1;
408 hs = (modetiming->CrtcHSyncStart >> 3) - 1;
409 he = (modetiming->CrtcHSyncEnd >> 3) - 1;
410 ht = (modetiming->CrtcHTotal >> 3) - 1;
411 vd = modetiming->CrtcVDisplay - 1;
412 vs = modetiming->CrtcVSyncStart - 1;
413 ve = modetiming->CrtcVSyncEnd - 1;
414 vt = modetiming->CrtcVTotal - 2;
415
416 /* HTOTAL & 0xF equal to 0xE in 8bpp or 0x4 in 24bpp causes strange
417 * vertical stripes
418 */
419 if((ht & 0x0F) == 0x0E || (ht & 0x0F) == 0x04)
420 ht++;
421
422 if (modeinfo->bitsPerPixel == 24)
423 wd = (modeinfo->width * 3) >> (4 - MGABppShft);
424 else
425 wd = modeinfo->width >> (4 - MGABppShft);
426
427 moderegs[VGA_TOTAL_REGS + 0x50 + 0] = 0;
428 moderegs[VGA_TOTAL_REGS + 0x50 + 5] = 0;
429
430 if (modetiming->flags & INTERLACED)
431 {
432 moderegs[VGA_TOTAL_REGS + 0x50 + 0] = 0x80;
433 moderegs[VGA_TOTAL_REGS + 0x50 + 5] = (hs + he - ht) >> 1;
434 wd <<= 1;
435 vt &= 0xFFFE;
436 }
437
438 moderegs[VGA_TOTAL_REGS + 0x50 + 0] |= (wd & 0x300) >> 4;
439 moderegs[VGA_TOTAL_REGS + 0x50 + 1] = (((ht - 4) & 0x100) >> 8) |
440 ((hd & 0x100) >> 7) |
441 ((hs & 0x100) >> 6) |
442 (ht & 0x40);
443 moderegs[VGA_TOTAL_REGS + 0x50 + 2] = ((vt & 0x400) >> 10) |
444 ((vt & 0x800) >> 10) |
445 ((vd & 0x400) >> 8) |
446 ((vd & 0x400) >> 7) |
447 ((vd & 0x800) >> 7) |
448 ((vs & 0x400) >> 5) |
449 ((vs & 0x800) >> 5);
450 if (modeinfo->bitsPerPixel == 24)
451 moderegs[VGA_TOTAL_REGS + 0x50 + 3] = (((1 << MGABppShft) * 3) - 1) | 0x80;
452 else
453 moderegs[VGA_TOTAL_REGS + 0x50 + 3] = ((1 << MGABppShft) - 1) | 0x80;
454
455 moderegs[VGA_TOTAL_REGS + 0x50 + 3] &= 0xE7; /* ajv - bits 4-5 MUST be 0 or bad karma happens */
456
457 moderegs[VGA_TOTAL_REGS + 0x50 + 4] = 0;
458
459 moderegs[0] = ht - 4;
460 moderegs[1] = hd;
461 moderegs[2] = hd;
462 moderegs[3] = (ht & 0x1F) | 0x80;
463 moderegs[4] = hs;
464 moderegs[5] = ((ht & 0x20) << 2) | (he & 0x1F);
465 moderegs[6] = vt & 0xFF;
466 moderegs[7] = ((vt & 0x100) >> 8 ) |
467 ((vd & 0x100) >> 7 ) |
468 ((vs & 0x100) >> 6 ) |
469 ((vd & 0x100) >> 5 ) |
470 0x10 |
471 ((vt & 0x200) >> 4 ) |
472 ((vd & 0x200) >> 3 ) |
473 ((vs & 0x200) >> 2 );
474 moderegs[9] = ((vd & 0x200) >> 4) | 0x40;
475 moderegs[16] = vs & 0xFF;
476 moderegs[17] = (ve & 0x0F) | 0x20;
477 moderegs[18] = vd & 0xFF;
478 moderegs[19] = wd & 0xFF;
479 moderegs[21] = vd & 0xFF;
480 moderegs[22] = (vt + 1) & 0xFF;
481
482 if (modetiming->flags & DOUBLESCAN)
483 moderegs[9] |= 0x80;
484
485 moderegs[59] |= 0x0C;
486
487 switch(id) {
488 case ID_G200:
489 initDAC[ 0x2c ] = 0x04;
490 initDAC[ 0x2d ] = 0x2d;
491 initDAC[ 0x2e ] = 0x19;
492 if(HasSDRAM)
493 *(unsigned int *)(moderegs + VGA_TOTAL_REGS + 0x50 + 9 + 0) = 0x40499121;
494 else *(unsigned int *)(moderegs + VGA_TOTAL_REGS + 0x50 + 9 + 0) = 0x4049cd21;
495 *(unsigned int *)(moderegs + VGA_TOTAL_REGS + 0x50 + 9 + 4) = 0x00008000;
496 *(unsigned int *)(moderegs + VGA_TOTAL_REGS + 0x50 + 9 + 8) = 0x0190a421;
497 break;
498 case ID_G400:
499 case ID_G450:
500 initDAC[ 0x2c ] = 0x05;
501 initDAC[ 0x2d ] = 0x23;
502 initDAC[ 0x2e ] = 0x40;
503 *(unsigned int *)(moderegs + VGA_TOTAL_REGS + 0x50 + 9 + 0) = 0x40341160;
504 *(unsigned int *)(moderegs + VGA_TOTAL_REGS + 0x50 + 9 + 4) = 0x01003000;
505 *(unsigned int *)(moderegs + VGA_TOTAL_REGS + 0x50 + 9 + 8) = 0x0190a421;
506 if(!HasSDRAM)
507 *(unsigned int *)(moderegs + VGA_TOTAL_REGS + 0x50 + 9 + 0) |= (1 << 14);
508 break;
509 }
510
511 MGASetPCLK( modetiming->pixelClock , initDAC);
512
513 for (i = 0; i < sizeof(initDAC); i++)
514 {
515 moderegs[VGA_TOTAL_REGS + i] = initDAC[i];
516 }
517
518 return ;
519 }
520
521
g400_setmode(int mode,int prv_mode)522 static int g400_setmode(int mode, int prv_mode)
523 {
524 unsigned char *moderegs;
525 ModeTiming *modetiming;
526 ModeInfo *modeinfo;
527 int i;
528
529 if (IS_IN_STANDARD_VGA_DRIVER(mode)) {
530 return __svgalib_vga_driverspecs.setmode(mode, prv_mode);
531 }
532 if (!g400_modeavailable(mode))
533 return 1;
534
535 modeinfo = __svgalib_createModeInfoStructureForSvgalibMode(mode);
536
537 modetiming = malloc(sizeof(ModeTiming));
538 if (__svgalib_getmodetiming(modetiming, modeinfo, cardspecs)) {
539 free(modetiming);
540 free(modeinfo);
541 return 1;
542 }
543
544 moderegs = malloc(G400_TOTAL_REGS);
545
546 g400_initializemode(moderegs, modetiming, modeinfo, mode);
547 free(modetiming);
548
549 __svgalib_setregs(moderegs); /* Set standard regs. */
550
551 g400_setregs(moderegs, mode); /* Set extended regs. */
552
553 if(mode>=G640x480x256)
554 switch(modeinfo->bitsPerPixel) {
555 case 16:
556 for(i=0;i<256;i++) __svgalib_outpal(i,i<<3,i<<(8-modeinfo->greenWeight),i<<3);
557 break;
558 case 24:
559 case 32:
560 for(i=0;i<256;i++) __svgalib_outpal(i,i,i,i);
561 break;
562 }
563
564 free(moderegs);
565
566 __svgalib_InitializeAcceleratorInterface(modeinfo);
567
568 free(modeinfo);
569 return 0;
570 }
571
572
573 /* Unlock chipset-specific registers */
574
g400_unlock(void)575 static void g400_unlock(void)
576 {
577 __svgalib_outcrtc(0x11, __svgalib_incrtc(0x11) &0x7f);
578 g400_outExt(3, g400_inExt(3) & 0x7f);
579 }
580
g400_lock(void)581 static void g400_lock(void)
582 {
583 __svgalib_outcrtc(0x11, __svgalib_incrtc(0x11)&0x7f);
584 g400_outExt(3, g400_inExt(3) | 0x80);
585 }
586
587
588 #define VENDOR_ID 0x102b
589
590 /* Indentify chipset, initialize and return non-zero if detected */
591
g400_test(void)592 static int g400_test(void)
593 {
594 int found, id;
595 unsigned long buf[64];
596
597 found=__svgalib_pci_find_vendor_vga(VENDOR_ID,buf,0);
598
599 if(found) return 0;
600
601 id=(buf[0]>>16)&0xffff;
602
603 if((id==0x520)||(id==0x521)||(id==0x525)||(id==0x1000)||(id==0x1001)){
604 g400_init(0,0,0);
605 return 1;
606 };
607 return 0;
608 }
609
610
611 /* Set display start address (not for 16 color modes) */
612
g400_setdisplaystart(int address)613 static void g400_setdisplaystart(int address)
614 {
615 address=address >> 2;
616 __svgalib_outcrtc(0x0c, (address & 0xFF00)>>8);
617 __svgalib_outcrtc(0x0d, address & 0x00FF);
618 g400_outExt(0, (g400_inExt(0)&0xb0) | ((address&0xf0000)>>16) | ((address&0x100000)>>14));
619 }
620
621
622 /* Set logical scanline length (usually multiple of 8) */
623
g400_setlogicalwidth(int width)624 static void g400_setlogicalwidth(int width)
625 {
626 int offset = width >> 3;
627
628 __svgalib_outcrtc(0x13,offset&0xff);
629 g400_outExt(0,(g400_inExt(0)&0xcf) | ((offset&0x300)>>4));
630 }
631
g400_linear(int op,int param)632 static int g400_linear(int op, int param)
633 {
634 if (op==LINEAR_ENABLE){g400_is_linear=1; return 0;};
635 if (op==LINEAR_DISABLE){g400_is_linear=0; return 0;};
636 if (op==LINEAR_QUERY_BASE) return g400_linear_base;
637 if (op == LINEAR_QUERY_RANGE || op == LINEAR_QUERY_GRANULARITY) return 0; /* No granularity or range. */
638 else return -1; /* Unknown function. */
639 }
640
g400_match_programmable_clock(int clock)641 static int g400_match_programmable_clock(int clock)
642 {
643 return clock ;
644 }
645
g400_map_clock(int bpp,int clock)646 static int g400_map_clock(int bpp, int clock)
647 {
648 return clock ;
649 }
650
g400_map_horizontal_crtc(int bpp,int pixelclock,int htiming)651 static int g400_map_horizontal_crtc(int bpp, int pixelclock, int htiming)
652 {
653 return htiming;
654 }
655
656 /* Function table (exported) */
657
658 DriverSpecs __svgalib_g400_driverspecs =
659 {
660 g400_saveregs,
661 g400_setregs,
662 g400_unlock,
663 g400_lock,
664 g400_test,
665 g400_init,
666 g400_setpage,
667 NULL,
668 NULL,
669 g400_setmode,
670 g400_modeavailable,
671 g400_setdisplaystart,
672 g400_setlogicalwidth,
673 g400_getmodeinfo,
674 0, /* old blit funcs */
675 0,
676 0,
677 0,
678 0,
679 0, /* ext_set */
680 0, /* accel */
681 g400_linear,
682 0, /* accelspecs, filled in during init. */
683 NULL, /* Emulation */
684 };
685
686 /* Initialize chipset (called after detection) */
687
g400_init(int force,int par1,int par2)688 static int g400_init(int force, int par1, int par2)
689 {
690 unsigned long buf[64];
691 int found=0;
692 int pci_id;
693 char *ids[]={"G100", "G200", "G400", "G450"};
694
695 if (force) {
696 g400_memory = par1;
697 } else {
698
699 };
700
701 iopl(3); /* Why is it needed? */
702
703 found=__svgalib_pci_find_vendor_vga(VENDOR_ID,buf,0);
704
705 if(found) {
706 printf("Error: Must use Matrox driver, but no card found\n");
707 exit(1);
708 }
709
710 pci_id=(buf[0]>>16)&0xffff;
711
712 switch(pci_id) {
713 case 0x525:
714 if((buf[11]&0xffff0000) == 0x07c00000)
715 id = ID_G450; else id = ID_G400;
716 break;
717 case 0x520:
718 case 0x521:
719 id = ID_G400;
720 break;
721 default:
722 id = ID_G100;
723 }
724
725 g400_linear_base = buf[4]&0xffffff00;
726 g400_mmio_base = buf[5]&0xffffff00;
727
728 /* those need to be fixed */
729 g400_memory = 8192;
730 HasSDRAM=(buf[0x10]&(1<<14))?0:1;
731
732 if (__svgalib_driver_report) {
733 printf("Using Matrox %s driver, %iKB S%cRAM.\n",ids[id],
734 g400_memory, HasSDRAM?'D':'G');
735 };
736
737 cardspecs = malloc(sizeof(CardSpecs));
738 cardspecs->videoMemory = g400_memory;
739 cardspecs->maxPixelClock4bpp = 75000;
740 switch(id) {
741 default:
742 cardspecs->maxPixelClock8bpp = 250000;
743 cardspecs->maxPixelClock16bpp = 250000;
744 cardspecs->maxPixelClock24bpp = 250000;
745 cardspecs->maxPixelClock32bpp = 250000;
746 break;
747 }
748 cardspecs->flags = INTERLACE_DIVIDE_VERT | CLOCK_PROGRAMMABLE;
749 cardspecs->maxHorizontalCrtc = 4095;
750 cardspecs->maxPixelClock4bpp = 0;
751 cardspecs->nClocks =0;
752 cardspecs->mapClock = g400_map_clock;
753 cardspecs->mapHorizontalCrtc = g400_map_horizontal_crtc;
754 cardspecs->matchProgrammableClock=g400_match_programmable_clock;
755 __svgalib_driverspecs = &__svgalib_g400_driverspecs;
756 __svgalib_banked_mem_base=0xa0000;
757 __svgalib_banked_mem_size=0x10000;
758 __svgalib_linear_mem_base=g400_linear_base;
759 __svgalib_linear_mem_size=g400_memory*0x400;
760 __svgalib_mmio_base=g400_mmio_base;
761 __svgalib_mmio_size=16384;
762 return 0;
763 }
764