xref: /plan9/sys/src/cmd/aux/vga/virge.c (revision 8cf6001e50e647a07ccf484b8e2f9940411befb9)
1 #include <u.h>
2 #include <libc.h>
3 #include <bio.h>
4 
5 #include "pci.h"
6 #include "vga.h"
7 
8 /*
9  * S3 Trio/ViRGE/Savage4
10  * Requires work.
11  */
12 
13 /* on some cards, savage4mem[1] == 8, but i don't know how to tell. -rsc */
14 static uchar savage4mem[] = { 2, 4, 8, 12, 16, 32, 0, 32};
15 static void
snarf(Vga * vga,Ctlr * ctlr)16 snarf(Vga* vga, Ctlr* ctlr)
17 {
18 	int i, id;
19 	char *p;
20 
21 	/*
22 	 * The Trio/ViRGE variants have some extra sequencer registers
23 	 * which need to be unlocked for access.
24 	 */
25 	vgaxo(Seqx, 0x08, 0x06);
26 	s3generic.snarf(vga, ctlr);
27 
28 	for(i = 0x08; i < 0x4F; i++)
29 		vga->sequencer[i] = vgaxi(Seqx, i);
30 	vga->crt[0x2D] = vgaxi(Crtx, 0x2D);
31 	vga->crt[0x2E] = vgaxi(Crtx, 0x2E);
32 	vga->crt[0x2F] = vgaxi(Crtx, 0x2F);
33 	for(i = 0x70; i < 0x99; i++)
34 		vga->crt[i] = vgaxi(Crtx, i);
35 
36 	id = (vga->crt[0x2D]<<8)|vga->crt[0x2E];
37 	switch(id){
38 
39 	default:
40 		trace("Unknown ViRGE/Trio64+ - 0x%4.4uX\n",
41 			(vga->crt[0x2D]<<8)|vga->crt[0x2E]);
42 		/*FALLTHROUGH*/
43 
44 	case 0x8810:				/* Microsoft Virtual PC 2004 */
45 	case 0x8811:				/* Trio64+ */
46 		vga->r[1] = 3;
47 		vga->m[1] = 127;
48 		vga->n[1] = 31;
49 		vga->f[1] = 135000000;
50 		trace("Trio64+\n");
51 		break;
52 
53 	case 0x8812:				/* Aurora64V+ */
54 		vga->r[1] = 3;
55 		vga->m[1] = 127;
56 		vga->n[1] = 63;
57 		vga->f[1] = 135000000;
58 		trace("Aurora64V+\n");
59 		break;
60 
61 	case 0x8901:				/* Trio64V2 */
62 		vga->r[1] = 4;
63 		vga->m[1] = 127;
64 		vga->n[1] = 31;
65 		vga->f[1] = 170000000;
66 		trace("Trio64V2\n");
67 		break;
68 
69 	case 0x5631:				/* ViRGE */
70 		vga->r[1] = 3;
71 		vga->m[1] = 127;
72 		vga->n[1] = 31;
73 		vga->f[1] = 135000000;
74 		vga->apz = 64*1024*1024;
75 		trace("ViRGE\n");
76 		break;
77 
78 	case 0x8A01:				/* ViRGE/[DG]X */
79 		vga->r[1] = 4;
80 		vga->m[1] = 127;
81 		vga->n[1] = 31;
82 		vga->f[1] = 170000000;
83 		trace("ViRGE/[DG]X\n");
84 		break;
85 
86 	case 0x8A10:				/* ViRGE/GX2 */
87 		vga->r[1] = 4;
88 		vga->m[1] = 127;
89 		vga->n[1] = 31;
90 		vga->f[1] = 170000000;
91 		vga->apz = 64*1024*1024;
92 		trace("ViRGE/GX2\n");
93 		/*
94 		 * Memory encoding on the ViRGE/GX2 is different.
95 		 */
96 		switch((vga->crt[0x36]>>6) & 0x03){
97 
98 		case 0x01:
99 			vga->vmz = 4*1024*1024;
100 			break;
101 
102 		case 0x03:
103 			vga->vmz = 2*1024*1024;
104 			break;
105 		}
106 		break;
107 
108 	case 0x883D:				/* ViRGE/VX */
109 		vga->r[1] = 4;
110 		vga->m[1] = 127;
111 		vga->n[1] = 31;
112 		vga->f[1] = 220000000;
113 		vga->apz = 64*1024*1024;
114 		trace("ViRGE/VX\n");
115 		/*
116 		 * Memory encoding on the ViRGE/VX is different.
117 		 */
118 		vga->vmz = (2*(((vga->crt[0x36]>>5) & 0x03)+1)) * 1*1024*1024;
119 		break;
120 
121 	case 0x8C10:				/* Savage MX/MV */
122 	case 0x8C12:				/* Savage4/IX-MV */
123 		vga->r[1] = 4;
124 		vga->m[1] = 127;
125 		vga->n[1] = 127;
126 		vga->f[1] = 135000000;		/* without clock-doubling */
127 		for(i = 0x50; i < 0x70; i++)
128 			vga->sequencer[i] = vgaxi(Seqx, i);
129 		vga->apz = 128*1024*1024;
130 		vga->vmz = savage4mem[vga->crt[0x36]>>5] * 1024 * 1024;
131 		trace("Savage4/IX-MV\n");
132 		break;
133 
134 	case 0x8C2E:				/* SuperSavage/IXC16 */
135 		/*
136 		 * This is all guessed, from the Savage4/IX,
137 		 * inspection of the card (apz), and web pages
138 		 * talking about the chip (f[1]).  It seems to
139 		 * work on the IBM Thinkpad T23.
140 		 *
141 		 * XXX only 1024x768 works, not 1400x1050.
142 		 */
143 		vga->r[1] = 4;
144 		vga->m[1] = 127;
145 		vga->n[1] = 127;
146 		vga->f[1] = 135000000;		/* 300000000 after doubling? */
147 		for(i = 0x50; i < 0x70; i++)
148 			vga->sequencer[i] = vgaxi(Seqx, i);
149 		vga->apz = 64*1024*1024;
150 		vga->vmz = savage4mem[vga->crt[0x36]>>5] * 1024 * 1024;
151 		trace("SuperSavage/IXC16\n");
152 		break;
153 
154 	case 0x8A22:				/* Savage4 */
155 	case 0x8A25:				/* ProSavage PN133 */
156 	case 0x8A26:				/* ProSavage KN133 */
157 	case 0x8D04:				/* ProSavage DDR, K.Okamoto */
158 		vga->r[1] = 4;
159 		vga->m[1] = 511;
160 		vga->n[1] = 127;
161 		vga->f[1] = 300000000;
162 
163 		vga->apz = 128*1024*1024;
164 		vga->vmz = savage4mem[vga->crt[0x36]>>5] * 1024 * 1024;
165 		trace("Savage4\n");
166 		break;
167 	}
168 
169 	/*
170 	 * Work out the part speed-grade from name. Name can have,
171 	 * e.g. '-135' on the end for 135MHz part.
172 	 */
173 	if(p = strrchr(ctlr->name, '-'))
174 		vga->f[1] = strtoul(p+1, 0, 0) * 1000000;
175 
176 	ctlr->flag |= Fsnarf;
177 }
178 
179 static void
options(Vga * vga,Ctlr * ctlr)180 options(Vga *vga, Ctlr* ctlr)
181 {
182 	int id;
183 
184 	id = (vga->crt[0x2D]<<8)|(vga->crt[0x2E]);
185 	switch(id){
186 	case 0x8C2E:				/* SuperSavage/IXC16 */
187 	case 0x8C10:				/* Savage MX/MV */
188 	case 0x8C12:				/* Savage4/IX-MV */
189 	case 0x8A22:				/* Savage4 */
190 	case 0x8A25:				/* ProSavage PN133 */
191 	case 0x8A26:				/* ProSavage KN133 */
192 	case 0x8D04:				/* ProSavabe DDR, K.Okamoto */
193 		/*
194 		 * Round up so stride is multiple of 16.
195 		 */
196 		if(vga->virtx%16)
197 			vga->virtx = (vga->virtx+15)&~15;
198 		break;
199 	}
200 
201 	ctlr->flag |= Hlinear|Hpclk2x8|Henhanced|Foptions;
202 }
203 
204 static void
init(Vga * vga,Ctlr * ctlr)205 init(Vga* vga, Ctlr* ctlr)
206 {
207 	char *p, *val;
208 	Mode *mode;
209 	ulong pclk, x;
210 	int id, noclockset, width;
211 
212 	id = (vga->crt[0x2D]<<8)|vga->crt[0x2E];
213 	mode = vga->mode;
214 
215 	/*
216 	 * double 16bpp horizontal timings on ViRGE/[DG]X
217 	 * leaves overflow bit-fiddling to s3generic.init
218 	 */
219 	if((id == 0x8A01) && ((mode->z+7)/8 == 2)){
220 		resyncinit(vga, ctlr, Uenhanced, 0);
221 		vga->crt[0x00] = ((mode->ht * 2) >> 3) - 5;
222 		vga->crt[0x01] = ((mode->x * 2) >> 3) - 1;
223 		vga->crt[0x02] = ((mode->shb * 2) >> 3) - 1;
224 		x = (mode->ehb * 2) >> 3;
225 		vga->crt[0x03] = 0x80 | (x & 0x1F);
226 		vga->crt[0x04] = (mode->shs * 2) >> 3;
227 		vga->crt[0x05] = ((mode->ehs * 2) >> 3) & 0x1F;
228 		if(x & 0x20)
229 			vga->crt[0x05] |= 0x80;
230 	}
231 	s3generic.init(vga, ctlr);
232 
233 	/*
234 	 * Work out the part speed-grade from name. Name can have,
235 	 * e.g. '-135' on the end for 135MHz part.
236 	 */
237 	noclockset = 0;
238 	if(p = strrchr(ctlr->name, '-'))
239 		vga->f[1] = strtoul(p+1, 0, 0) * 1000000;
240 	pclk = vga->f[1];
241 
242 	if(vga->mode->z > 8)
243 		width = vga->virtx*(vga->mode->z/8);
244 	else
245 		width = vga->virtx*(8/vga->mode->z);
246 
247 	switch(id){
248 
249 	case 0x8810:				/* Microsoft Virtual PC 2004 */
250 	case 0x8811:				/* Trio64+ */
251 		/*
252 		 * Part comes in -135MHz speed grade. In 8-bit mode
253 		 * the maximum DCLK is 80MHz. In 2x8-bit mode the maximum
254 		 * DCLK is 135MHz using the internal clock doubler.
255 		 */
256 		if((ctlr->flag & Hpclk2x8) && vga->mode->z == 8){
257 			if(vga->f[0] > 80000000)
258 				ctlr->flag |= Upclk2x8;
259 		}
260 		else
261 			pclk = 80000000;
262 
263 		vga->crt[0x67] &= ~0xF2;
264 		if(ctlr->flag & Upclk2x8){
265 			vga->sequencer[0x15] |= 0x10;
266 			vga->sequencer[0x18] |= 0x80;
267 			/*
268 			 * There's a little strip of the border
269 			 * appears on the left in resolutions
270 			 * 1280 and above if the 0x02 bit isn't
271 			 * set (when it appears on the right...).
272 			 */
273 			vga->crt[0x67] |= 0x10;
274 		}
275 
276 		/*
277 		 * VLB address latch delay.
278 		 */
279 		if((vga->crt[0x36] & 0x03) == 0x01)
280 			vga->crt[0x58] &= ~0x08;
281 
282 		/*
283 		 * Display memory access control.
284 		 */
285 		vga->crt[0x60] = 0xFF;
286 
287 		if(vga->mode->z > 8)
288 			error("trio64: depth %d not supported\n", vga->mode->z);
289 		break;
290 
291 	case 0x8901:				/* Trio64V2 */
292 		vga->crt[0x90] = 0;
293 		vga->crt[0x91] = 0;
294 		break;
295 	case 0x8A10:				/* ViRGE/GX2 */
296 		vga->crt[0x90] = 0;
297 
298 		vga->crt[0x31] |= 0x08;
299 
300 		vga->crt[0x13] = (width>>3) & 0xFF;
301 		vga->crt[0x51] &= ~0x30;
302 		vga->crt[0x51] |= (width>>7) & 0x30;
303 
304 		/*
305 		 * Increase primary FIFO threshold
306 	 	 * to reduce flicker and tearing.
307 		 */
308 		vga->crt[0x85] = 0x0F;
309 
310 		/*FALLTHROUGH*/
311 	case 0x5631:				/* ViRGE */
312 	case 0x8A01:				/* ViRGE/[DG]X */
313 		if(id == 0x8A01){
314 			x = mode->x * ((mode->z + 7) / 8);
315 			x = (x + 7) / 8;
316 			vga->crt[0x91] = x & 0xFF;
317 			vga->crt[0x90] = (x >> 8) | 0x80;
318 		}
319 	case 0x883D:				/* ViRGE/VX */
320 		vga->crt[0x60] &= 0x0F;
321 		/*FALLTHROUGH*/
322 	case 0x8812:				/* Aurora64V+ */
323 		if(id == 0x8812)		/* Aurora64V+ */
324 			noclockset = 1;
325 		vga->crt[0x65] = 0;
326 		vga->crt[0x66] = 0x89;
327 		vga->crt[0x67] = 0;
328 
329 		if(id == 0x883D){		/* ViRGE/VX */
330 			/*
331 			 * Put the VRAM in 1-cycle EDO mode.
332 			 * If it is not put in this mode, hardware acceleration
333 			 * will leave little turds on the screen when hwfill is used.
334 			 */
335 			vga->crt[0x36] &= ~0x0C;
336 
337 			if(vga->mode->x > 800 && vga->mode->z == 8)
338 				vga->crt[0x67] = 0x10;
339 			else
340 				vga->crt[0x67] = 0;
341 
342 	 		/*
343 			 * Adjustments to the generic settings:
344 			 *	heuristic fiddling.
345 			 *
346 			 * We used to set crt[0x66] to 0x89, but setting it
347 			 * to 0x90 seems to allow us (and more importantly the card)
348 			 * to access more than 2MB of memory.
349 			 */
350 			vga->crt[0x66] = 0x90;
351 			vga->crt[0x58] &= ~0x88;
352 			vga->crt[0x58] |= 0x40;
353 			if(vga->mode->x > 640 && vga->mode->z >= 8)
354 				vga->crt[0x63] |= 0x01;
355 			else
356 				vga->crt[0x63] &= ~0x01;
357 		}
358 
359 		/*
360 		 * The high nibble is the mode; or'ing in 0x02 turns
361 		 * on support for gamma correction via the DACs, but I
362 		 * haven't figured out how to turn on the 8-bit DACs,
363 		 * so gamma correction stays off.
364 		 */
365 		switch(vga->mode->z){
366 		case 1:
367 		case 2:
368 		case 4:
369 		case 8:
370 		default:
371 			vga->crt[0x67] |= 0x00;
372 			break;
373 		case 15:
374 			vga->crt[0x67] |= 0x30;
375 			break;
376 		case 16:
377 			vga->crt[0x67] |= 0x50;
378 			break;
379 		case 24:
380 			if(id == 0x8A10)	/* GX2 has to be different */
381 				vga->crt[0x67] |= 0x70;
382 			else
383 				vga->crt[0x67] |= 0xD0;
384 			break;
385 		case 32:
386 			/*
387 			 * The ViRGE and ViRGE/VX manuals make no mention of
388 			 * 32-bit mode (which the GX/2 calls 24-bit unpacked mode).
389 			 */
390 			if(id != 0x8A10)
391 				error("32-bit mode only supported on the GX/2\n");
392 			vga->crt[0x67] |= 0xD0;
393 			break;
394 		}
395 
396 		/*
397 		 * Set new MMIO method
398 		 */
399 		vga->crt[0x53] &= ~0x18;
400 		vga->crt[0x53] |= 0x08;
401 
402 		break;
403 
404 	case 0x8C2E:				/* SuperSavage/IXC16 (let's try this -rsc) */
405 	case 0x8C10:				/* Savage MX/MV */
406 	case 0x8C12:				/* Savage4/IX-MV */
407 		/*
408 		 * Experience shows the -1 (according to the manual)
409 		 * is incorrect.
410 		 */
411 		x = width/8 /*-1*/;
412 		vga->crt[0x91] = x;
413 		vga->crt[0x90] &= ~0x07;
414 		vga->crt[0x90] |= (x>>8) & 0x07;
415 
416 	case 0x8D04:				/* ProSavage DDR, K.Okamoto */
417 		x = mode->x * ((mode->z + 7) / 8);
418 		x = (x + 7) / 8;
419 		vga->crt[0x91] = x & 0xFF;
420 		vga->crt[0x90] = (x >> 8) | 0x80;
421 
422 		/*FALLTHROUGH*/
423 
424 	case 0x8A22:				/* Savage4 */
425 	case 0x8A25:				/* ProSavage PN133 */
426 	case 0x8A26:				/* ProSavage KN133 */
427 		/*
428 		 * The Savage 4 is frustratingly similar to the
429 		 * ViRGE/GX2, but has enough slight differences
430 		 * to warrant special treatment.  Blog.
431 		 */
432 		vga->crt[0x66] = 0x89;
433 		vga->crt[0x67] = 0;
434 		vga->crt[0x85] = 0x02;
435 		vga->crt[0x31] |= 0x08;
436 
437 		vga->crt[0x13] = (width>>3) & 0xFF;
438 		vga->crt[0x51] &= ~0x30;
439 		vga->crt[0x51] |= (width>>7) & 0x30;
440 
441 		/* pull screen width from GBD for graphics engine. */
442 		vga->crt[0x50] = 0xC1;	/* set color mode */
443 
444 		/*
445 		 * The high nibble is the mode; or'ing in 0x02 turns
446 		 * on support for gamma correction via the DACs, but I
447 		 * haven't figured out how to turn on the 8-bit DACs,
448 		 * so gamma correction stays off.
449 		 */
450 		switch(vga->mode->z){
451 		default:
452 			error("%d-bit mode not supported on savage 4\n", vga->mode->z);
453 		case 8:
454 			vga->crt[0x67] |= 0x00;
455 			vga->crt[0x50] |= 0<<4;
456 			break;
457 		case 15:
458 			vga->crt[0x67] |= 0x20;
459 			vga->crt[0x50] |= 1<<4;
460 			break;
461 		case 16:
462 			vga->crt[0x67] |= 0x40;
463 			vga->crt[0x50] |= 1<<4;
464 			/*
465 			 * Manual says this should be accompanied by setting
466 			 * the clock-doubled modes but this seems to be the
467 			 * right answer.
468 			 * Should check if using doubled modes tidies any of
469 			 * this up.
470 			 */
471 			if(id == 0x8C12 || id == 0x8C2E || id == 0x8C10)
472 				vga->crt[0x67] |= 0x10;
473 			break;
474 		case 32:
475 			vga->crt[0x67] |= 0xD0;
476 			vga->crt[0x50] |= 3<<4;
477 			break;
478 		}
479 		break;
480 	}
481 
482 	/*
483 	 * Clock bits. If the desired video clock is
484 	 * one of the two standard VGA clocks it can just be
485 	 * set using bits <3:2> of vga->misc, otherwise we
486 	 * need to programme the DCLK PLL.
487 	 */
488 	if(val = dbattr(vga->mode->attr, "noclockset")){
489 		 if((noclockset = strtol(val, &p, 0)) == 0 && p == val)
490 			error("%s: invalid 'noclockset' attr\n", ctlr->name);
491 	}
492 	if(vga->f[0] == 0)
493 		vga->f[0] = vga->mode->frequency;
494 	vga->misc &= ~0x0C;
495 	if(vga->f[0] == VgaFreq0){
496 		/* nothing to do */;
497 	}
498 	else if(vga->f[0] == VgaFreq1)
499 		vga->misc |= 0x04;
500 	else if(noclockset){
501 		/*
502 		 * Don't touch the clock on the Aurora64V+
503 		 * and optionally on some others.
504 		 */
505 		vga->misc |= 0x0C;
506 	}
507 	else{
508 		if(vga->f[0] > pclk)
509 			error("%s: invalid pclk - %lud\n",
510 				ctlr->name, vga->f[0]);
511 
512 		trio64clock(vga, ctlr);
513 		switch(id){
514 
515 		case 0x8A10:			/* ViRGE/GX2 */
516 			vga->sequencer[0x12] = (vga->r[0]<<6)|vga->n[0];
517 			if(vga->r[0] & 0x04)
518 				vga->sequencer[0x29] |= 0x01;
519 			else
520 				vga->sequencer[0x29] &= ~0x01;
521 			break;
522 
523 		case 0x8C2E:			/* SuperSavage/IXC16 (let's try this -rsc) */
524 		case 0x8C10:			/* Savage MX/MV */
525 		case 0x8C12:			/* Savage4/IX-MV */
526 		case 0x8A22:			/* Savage4 */
527 		case 0x8A25:			/* ProSavage PN133 */
528 		case 0x8A26:			/* ProSavage KN133 */
529 		case 0x8D04:			/* ProSavage DDR, K.Okamoto */
530 			vga->sequencer[0x12] = (vga->r[0]<<6)|(vga->n[0] & 0x3F);
531 			vga->sequencer[0x39] &= ~0x01;
532 			vga->sequencer[0x29] &= ~0x1C;
533 			if(vga->r[0] & 0x04)
534 				vga->sequencer[0x29] |= (1<<2);
535 			if(vga->m[0] & 0x100)
536 				vga->sequencer[0x29] |= (1<<3);
537 			if(vga->n[0] & 0x40)
538 				vga->sequencer[0x29] |= (1<<4);
539 			break;
540 
541 		default:
542 			vga->sequencer[0x12] = (vga->r[0]<<5)|vga->n[0];
543 			break;
544 		}
545 		vga->sequencer[0x13] = vga->m[0];
546 		vga->misc |= 0x0C;
547 	}
548 
549 	/*
550 	 * Internal clock generator.
551 	 */
552 	vga->sequencer[0x15] &= ~0x31;
553 	vga->sequencer[0x15] |= 0x02;
554 	vga->sequencer[0x18] &= ~0x80;
555 
556 	/*
557 	 * Start display FIFO fetch.
558 	 */
559 	x = (vga->crt[0]+vga->crt[4]+1)/2;
560 	vga->crt[0x3B] = x;
561 	if(x & 0x100)
562 		vga->crt[0x5D] |= 0x40;
563 
564 	/*
565 	 * Display memory access control.
566 	 * Calculation of the M-parameter (Crt54) is
567 	 * memory-system and dot-clock dependent, the
568 	 * values below are guesses from dumping
569 	 * registers.
570 	 * The Savage4 does not document 0x54,
571 	 * but we leave this anyway.
572 	 */
573 	if(vga->mode->x <= 800)
574 		vga->crt[0x54] = 0xE8;
575 	else if(vga->mode->x <= 1024 && id != 0x8C12 && id != 0x8C2E)
576 		vga->crt[0x54] = 0xA8;
577 	else
578 		vga->crt[0x54] = 0x00/*0x48*/;
579 
580 	ctlr->flag |= Finit;
581 }
582 
583 static void
load(Vga * vga,Ctlr * ctlr)584 load(Vga* vga, Ctlr* ctlr)
585 {
586 	int id;
587 	ushort advfunc;
588 
589 	s3generic.load(vga, ctlr);
590 
591 	/*
592 	 * Load the PLL registers if necessary.
593 	 * Not sure if the variable-delay method of setting the
594 	 * PLL will work without a write here to vga->misc,
595 	 * so use the immediate-load method by toggling bit 5
596 	 * of Seq15 if necessary.
597 	 */
598 	vgaxo(Seqx, 0x12, vga->sequencer[0x12]);
599 	vgaxo(Seqx, 0x13, vga->sequencer[0x13]);
600 	id = (vga->crt[0x2D]<<8)|vga->crt[0x2E];
601 	switch(id){
602 	case 0x883D:				/* ViRGE/VX*/
603 		vgaxo(Crtx, 0x36, vga->crt[0x36]);
604 		break;
605 	case 0x8A10:				/* ViRGE/GX2 */
606 		vgaxo(Seqx, 0x29, vga->sequencer[0x29]);
607 		break;
608 	case 0x8C2E:				/* SuperSavage/IXC16 (let's try this -rsc) */
609 	case 0x8C12:				/* Savage4/IX-MV */
610 		vgaxo(Crtx, 0x90, vga->crt[0x90]);
611 		vgaxo(Crtx, 0x91, vga->crt[0x91]);
612 		/*FALLTHROUGH*/
613 	case 0x8A22:				/* Savage4 */
614 	case 0x8A25:				/* ProSavage PN133 */
615 	case 0x8A26:				/* ProSavage KN133 */
616 	case 0x8D04:				/* ProSavage DDR, K.Okamoto */
617 		vgaxo(Seqx, 0x29, vga->sequencer[0x29]);
618 		vgaxo(Seqx, 0x39, vga->sequencer[0x39]);
619 		break;
620 	}
621 	if((vga->misc & 0x0C) == 0x0C)
622 		vgaxo(Seqx, 0x15, vga->sequencer[0x15]|0x20);
623 	vgaxo(Seqx, 0x15, vga->sequencer[0x15]);
624 	vgaxo(Seqx, 0x18, vga->sequencer[0x18]);
625 
626 	vgaxo(Crtx, 0x60, vga->crt[0x60]);
627 	vgaxo(Crtx, 0x63, vga->crt[0x63]);
628 	vgaxo(Crtx, 0x65, vga->crt[0x65]);
629 	vgaxo(Crtx, 0x66, vga->crt[0x66]);
630 	vgaxo(Crtx, 0x67, vga->crt[0x67]);
631 
632 	switch(id){
633 
634 	case 0x8810:				/* Microsoft Virtual PC 2004 */
635 	case 0x8811:				/* Trio64+ */
636 		advfunc = 0x0000;
637 		if(ctlr->flag & Uenhanced)
638 			advfunc = 0x0001;
639 		outportw(0x4AE8, advfunc);
640 		break;
641 	case 0x8901:				/* Trio64V2 */
642 	case 0x8A01:				/* ViRGE/[DG]X */
643 		vgaxo(Crtx, 0x90, vga->crt[0x90]);
644 		vgaxo(Crtx, 0x91, vga->crt[0x91]);
645 		break;
646 	case 0x8A10:				/* ViRGE/GX2 */
647 		vgaxo(Crtx, 0x90, vga->crt[0x90]);
648 		vgaxo(Crtx, 0x31, vga->crt[0x31]);
649 		vgaxo(Crtx, 0x13, vga->crt[0x13]);
650 		vgaxo(Crtx, 0x51, vga->crt[0x51]);
651 		vgaxo(Crtx, 0x85, vga->crt[0x85]);
652 		break;
653 	case 0x8D04:				/* ProSavage DDR, K.Okamoto */
654 		vgaxo(Crtx, 0x90, vga->crt[0x90]);		//K.Okamoto
655 		vgaxo(Crtx, 0x91, vga->crt[0x91]);		//K.Okamoto
656 	case 0x8C2E:				/* SuperSavage/IXC16 (let's try this -rsc) */
657 	case 0x8C12:				/* Savage4/IX-MV */
658 	case 0x8A22:				/* Savage4 */
659 	case 0x8A25:				/* ProSavage PN133 */
660 	case 0x8A26:				/* ProSavage KN133 */
661 		vgaxo(Crtx, 0x31, vga->crt[0x31]);
662 		vgaxo(Crtx, 0x13, vga->crt[0x13]);
663 		vgaxo(Crtx, 0x51, vga->crt[0x51]);
664 		vgaxo(Crtx, 0x85, vga->crt[0x85]);
665 		vgaxo(Crtx, 0x50, vga->crt[0x50]);
666 		break;
667 	}
668 }
669 
670 static void
dump(Vga * vga,Ctlr * ctlr)671 dump(Vga* vga, Ctlr* ctlr)
672 {
673 	int i, id;
674 	ulong dclk, m, n, r;
675 
676 	s3generic.dump(vga, ctlr);
677 	printitem(ctlr->name, "Crt70");
678 	for(i = 0x70; i < 0x99; i++)
679 		printreg(vga->crt[i]);
680 
681 	printitem(ctlr->name, "Seq08");
682 	for(i = 0x08; i < 0x10; i++)
683 		printreg(vga->sequencer[i]);
684 	printitem(ctlr->name, "Seq10");
685 	for(i = 0x10; i < 0x50; i++)
686 		printreg(vga->sequencer[i]);
687 	id = (vga->crt[0x2D]<<8)|vga->crt[0x2E];
688 	switch(id){
689 	default:
690 		break;
691 
692 	case 0x8812:				/* Aurora64V+ */
693 	case 0x8C2E:				/* SuperSavage/IXC16 (let's try this -rsc) */
694 	case 0x8C12:				/* Savage4/IX-MV */
695 		printitem(ctlr->name, "Seq50");
696 		for(i = 0x50; i < 0x70; i++)
697 			printreg(vga->sequencer[i]);
698 		break;
699 	}
700 
701 	printitem(ctlr->name, "Crt2D");
702 	printreg(vga->crt[0x2D]);
703 	printreg(vga->crt[0x2E]);
704 	printreg(vga->crt[0x2F]);
705 
706 	m = vga->sequencer[0x13] & vga->m[1];
707 	n = vga->sequencer[0x12] & vga->n[1];
708 	r = (vga->sequencer[0x12]>>5) & 0x03;
709 
710 	switch(id){
711 	case 0x8812:				/* Aurora64V+ */
712 		r = (vga->sequencer[0x12]>>6) & 0x03;
713 		break;
714 	case 0x8A01:				/* ViRGE/[DG]X */
715 		r = (vga->sequencer[0x12]>>5) & 0x07;
716 		break;
717 	case 0x8A10:				/* ViRGE/GX2 */
718 		r = (vga->sequencer[0x12]>>6) & 0x03;
719 		r |= (vga->sequencer[0x29] & 0x01)<<2;
720 		break;
721 	case 0x8C2E:				/* SuperSavage/IXC16 (let's try this -rsc) */
722 	case 0x8C12:				/* Savage4/IX-MV */
723 	case 0x8A22:				/* Savage4 */
724 	case 0x8A25:				/* ProSavage PN133 */
725 	case 0x8A26:				/* ProSavage KN133 */
726 	case 0x8D04:				/* Prosavage DDR, K.Okamoto */
727 		m = vga->sequencer[0x13] & 0xFF;
728 		if(vga->sequencer[0x29] & (1<<3))
729 			m |= 0x100;
730 		if(vga->sequencer[0x29] & (1<<4))
731 			n |= 0x40;
732 		r = (vga->sequencer[0x12]>>6) & 0x03;
733 		r |= (vga->sequencer[0x29] & (1<<2));
734 		break;
735 	}
736 
737 	dclk = (m+2)*RefFreq;
738 	dclk /= (n+2)*(1<<r);
739 	printitem(ctlr->name, "dclk m n r");
740 	Bprint(&stdout, "%9ld %8ld       - %8ld %8ld\n", dclk, m, n, r);
741 
742 	m = vga->sequencer[0x11] & 0x7F;
743 	n = vga->sequencer[0x10] & 0x1F;
744 	r = (vga->sequencer[0x10]>>5) & 0x03;	/* might be GX/2 specific */
745 	dclk = (m+2)*RefFreq;
746 	dclk /= (n+2)*(1<<r);
747 	printitem(ctlr->name, "mclk m n r");
748 	Bprint(&stdout, "%9ld %8ld       - %8ld %8ld\n", dclk, m, n, r);
749 }
750 
751 Ctlr virge = {
752 	"virge",			/* name */
753 	snarf,				/* snarf */
754 	options,			/* options */
755 	init,				/* init */
756 	load,				/* load */
757 	dump,				/* dump */
758 };
759