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