xref: /plan9/sys/src/cmd/aux/vga/trio64.c (revision 9a747e4fd48b9f4522c70c07e8f882a15030f964)
17dd7cddfSDavid du Colombier #include <u.h>
27dd7cddfSDavid du Colombier #include <libc.h>
37dd7cddfSDavid du Colombier #include <bio.h>
47dd7cddfSDavid du Colombier 
5*9a747e4fSDavid du Colombier #include "pci.h"
67dd7cddfSDavid du Colombier #include "vga.h"
77dd7cddfSDavid du Colombier 
87dd7cddfSDavid du Colombier /*
97dd7cddfSDavid du Colombier  * S3 Trio64.
107dd7cddfSDavid du Colombier  */
117dd7cddfSDavid du Colombier static void
snarf(Vga * vga,Ctlr * ctlr)127dd7cddfSDavid du Colombier snarf(Vga* vga, Ctlr* ctlr)
137dd7cddfSDavid du Colombier {
147dd7cddfSDavid du Colombier 	int i;
157dd7cddfSDavid du Colombier 
167dd7cddfSDavid du Colombier 	/*
177dd7cddfSDavid du Colombier 	 * The Trio has some extra sequencer registers which
187dd7cddfSDavid du Colombier 	 * need to be unlocked for access.
197dd7cddfSDavid du Colombier 	 */
207dd7cddfSDavid du Colombier 	vgaxo(Seqx, 0x08, 0x06);
217dd7cddfSDavid du Colombier 	for(i = 0x08; i < 0x19; i++)
227dd7cddfSDavid du Colombier 		vga->sequencer[i] = vgaxi(Seqx, i);
237dd7cddfSDavid du Colombier 	vga->crt[0x2D] = vgaxi(Crtx, 0x2D);
247dd7cddfSDavid du Colombier 	vga->crt[0x2E] = vgaxi(Crtx, 0x2E);
257dd7cddfSDavid du Colombier 	vga->crt[0x2F] = vgaxi(Crtx, 0x2F);
267dd7cddfSDavid du Colombier 
277dd7cddfSDavid du Colombier 	s3generic.snarf(vga, ctlr);
287dd7cddfSDavid du Colombier 	ctlr->flag |= Fsnarf;
297dd7cddfSDavid du Colombier }
307dd7cddfSDavid du Colombier 
317dd7cddfSDavid du Colombier static void
options(Vga *,Ctlr * ctlr)327dd7cddfSDavid du Colombier options(Vga*, Ctlr* ctlr)
337dd7cddfSDavid du Colombier {
347dd7cddfSDavid du Colombier 	ctlr->flag |= Hlinear|Hpclk2x8|Henhanced|Foptions;
357dd7cddfSDavid du Colombier }
367dd7cddfSDavid du Colombier 
377dd7cddfSDavid du Colombier void
trio64clock(Vga * vga,Ctlr * ctlr)387dd7cddfSDavid du Colombier trio64clock(Vga* vga, Ctlr* ctlr)
397dd7cddfSDavid du Colombier {
407dd7cddfSDavid du Colombier 	int d;
417dd7cddfSDavid du Colombier 	ulong f, fmax, fmin, n, m, r;
427dd7cddfSDavid du Colombier 	double trouble;
437dd7cddfSDavid du Colombier 
447dd7cddfSDavid du Colombier 	/*
4514414594SDavid du Colombier 	 * The max value of R, M, N, and the speed rating of the part vary
467dd7cddfSDavid du Colombier 	 * between parts and are passed to this routine in r[1] and f[1].
477dd7cddfSDavid du Colombier 	 *			R	    F
487dd7cddfSDavid du Colombier 	 *	Trio64		3	135000000
497dd7cddfSDavid du Colombier 	 *	ViRGE		3	135000000
507dd7cddfSDavid du Colombier 	 *	ViRGE/[DG]X	4	170000000
517dd7cddfSDavid du Colombier 	 *	ViRGE/GX2	4	170000000
527dd7cddfSDavid du Colombier 	 *	ViRGE/VX	4	220000000
537dd7cddfSDavid du Colombier 	 */
547dd7cddfSDavid du Colombier 
557dd7cddfSDavid du Colombier 	/*
567dd7cddfSDavid du Colombier 	 * The PLL frequency is defined by the following equation:
577dd7cddfSDavid du Colombier 	 *		   (M+2)
587dd7cddfSDavid du Colombier 	 *	Fout = ------------- x Fref
597dd7cddfSDavid du Colombier 	 *		(N+2) x 2**R
607dd7cddfSDavid du Colombier 	 * where M, N and R have the following contraints:
617dd7cddfSDavid du Colombier 	 * 1)		   (M+2) x Fref
627dd7cddfSDavid du Colombier 	 *    vga->f[1] <= ------------ <= vga->f[1]*2
637dd7cddfSDavid du Colombier 	 *		       (N+2)
6414414594SDavid du Colombier 	 * 2) 1 <= M <= vga->m[1] (usually 127)
6514414594SDavid du Colombier 	 * 3) 1 <= N <= vga->n[1] (usually 31)
667dd7cddfSDavid du Colombier 	 * 4) 0 <= R <= vga->r[1]
677dd7cddfSDavid du Colombier 	 *
687dd7cddfSDavid du Colombier 	 * First determine R:
697dd7cddfSDavid du Colombier 	 *	vga->f[1] < 2**R x Fout <= vga->f[1]*2
707dd7cddfSDavid du Colombier 	 */
717dd7cddfSDavid du Colombier 	for(r = 0; r <= vga->r[1]; r++){
727dd7cddfSDavid du Colombier 		f = vga->f[0]*(1<<r);
737dd7cddfSDavid du Colombier 		if(vga->f[1] < f && f <= vga->f[1]*2)
747dd7cddfSDavid du Colombier 			vga->r[0] = r;
757dd7cddfSDavid du Colombier 	}
767dd7cddfSDavid du Colombier 	if(vga->r[0] > vga->r[1])
777dd7cddfSDavid du Colombier 		error("%s: pclk %lud out of range\n", ctlr->name, vga->f[0]);
787dd7cddfSDavid du Colombier 
797dd7cddfSDavid du Colombier 	/*
807dd7cddfSDavid du Colombier 	 * Now find the closest match for M and N.
817dd7cddfSDavid du Colombier 	 */
827dd7cddfSDavid du Colombier 	vga->d[0] = vga->f[0]+1;
8314414594SDavid du Colombier 	for(n = 1; n <= vga->n[1]; n++){
847dd7cddfSDavid du Colombier 		trouble = vga->f[0]*(n+2)*(1<<vga->r[0]);
857dd7cddfSDavid du Colombier 		trouble /= RefFreq;
867dd7cddfSDavid du Colombier 		m = (trouble+0.5) - 2;
8714414594SDavid du Colombier 		if(m > vga->m[1])
887dd7cddfSDavid du Colombier 			continue;
897dd7cddfSDavid du Colombier 
907dd7cddfSDavid du Colombier 		trouble = (m+2)*RefFreq;
917dd7cddfSDavid du Colombier 		trouble /= (n+2)*(1<<vga->r[0]);
927dd7cddfSDavid du Colombier 		f = trouble+0.5;
937dd7cddfSDavid du Colombier 
947dd7cddfSDavid du Colombier 		d = vga->f[0] - f;
957dd7cddfSDavid du Colombier 		if(d < 0)
967dd7cddfSDavid du Colombier 			d = -d;
977dd7cddfSDavid du Colombier 		if(d <= vga->d[0]){
987dd7cddfSDavid du Colombier 			vga->m[0] = m;
997dd7cddfSDavid du Colombier 			vga->n[0] = n;
1007dd7cddfSDavid du Colombier 			vga->d[0] = d;
1017dd7cddfSDavid du Colombier 		}
1027dd7cddfSDavid du Colombier 	}
1037dd7cddfSDavid du Colombier 
1047dd7cddfSDavid du Colombier 	trouble = vga->f[0]*1.005;
1057dd7cddfSDavid du Colombier 	fmax = trouble;
1067dd7cddfSDavid du Colombier 	trouble = vga->f[0]*0.995;
1077dd7cddfSDavid du Colombier 	fmin = trouble;
1087dd7cddfSDavid du Colombier 	trouble = (vga->m[0]+2)*RefFreq;
1097dd7cddfSDavid du Colombier 	trouble /= (vga->n[0]+2)*(1<<vga->r[0]);
1107dd7cddfSDavid du Colombier 	f = trouble+0.5;
1117dd7cddfSDavid du Colombier 	if(fmin >= f || f >= fmax)
1127dd7cddfSDavid du Colombier 		error("%s: pclk %lud out of range\n", ctlr->name, vga->f[0]);
1137dd7cddfSDavid du Colombier }
1147dd7cddfSDavid du Colombier 
1157dd7cddfSDavid du Colombier static void
init(Vga * vga,Ctlr * ctlr)1167dd7cddfSDavid du Colombier init(Vga* vga, Ctlr* ctlr)
1177dd7cddfSDavid du Colombier {
1187dd7cddfSDavid du Colombier 	ulong pclk, x;
1197dd7cddfSDavid du Colombier 
1207dd7cddfSDavid du Colombier 	s3generic.init(vga, ctlr);
1217dd7cddfSDavid du Colombier 
1227dd7cddfSDavid du Colombier 	/*
1237dd7cddfSDavid du Colombier 	 * Clock bits. If the desired video clock is
1247dd7cddfSDavid du Colombier 	 * one of the two standard VGA clocks it can just be
1257dd7cddfSDavid du Colombier 	 * set using bits <3:2> of vga->misc, otherwise we
1267dd7cddfSDavid du Colombier 	 * need to programme the DCLK PLL.
1277dd7cddfSDavid du Colombier 	 */
1287dd7cddfSDavid du Colombier 	if(vga->mode->z > 8)
1297dd7cddfSDavid du Colombier 		error("depth %d not supported\n", vga->mode->z);
1307dd7cddfSDavid du Colombier 
1317dd7cddfSDavid du Colombier 	if(vga->f[0] == 0)
1327dd7cddfSDavid du Colombier 		vga->f[0] = vga->mode->frequency;
1337dd7cddfSDavid du Colombier 	vga->misc &= ~0x0C;
134*9a747e4fSDavid du Colombier 	if(vga->f[0] == VgaFreq0){
135*9a747e4fSDavid du Colombier 		/* nothing to do */;
136*9a747e4fSDavid du Colombier 	}
1377dd7cddfSDavid du Colombier 	else if(vga->f[0] == VgaFreq1)
1387dd7cddfSDavid du Colombier 		vga->misc |= 0x04;
1397dd7cddfSDavid du Colombier 	else{
1407dd7cddfSDavid du Colombier 		/*
1417dd7cddfSDavid du Colombier 		 * Part comes in -135MHz speed grade. In 8-bit mode
1427dd7cddfSDavid du Colombier 		 * the maximum DCLK is 80MHz. In 2x8-bit mode the maximum
1437dd7cddfSDavid du Colombier 		 * DCLK is 135MHz using the internal clock doubler.
1447dd7cddfSDavid du Colombier 		 */
1457dd7cddfSDavid du Colombier 		if((ctlr->flag & Hpclk2x8) && vga->mode->z == 8){
1467dd7cddfSDavid du Colombier 			pclk = 135000000;
1477dd7cddfSDavid du Colombier 			if(vga->f[0] > 80000000)
1487dd7cddfSDavid du Colombier 				ctlr->flag |= Upclk2x8;
1497dd7cddfSDavid du Colombier 		}
1507dd7cddfSDavid du Colombier 		else
1517dd7cddfSDavid du Colombier 			pclk = 80000000;
1527dd7cddfSDavid du Colombier 		if(vga->f[0] > pclk)
1537dd7cddfSDavid du Colombier 			error("%s: invalid pclk - %lud\n",
1547dd7cddfSDavid du Colombier 				ctlr->name, vga->f[0]);
1557dd7cddfSDavid du Colombier 
1567dd7cddfSDavid du Colombier 		vga->f[1] = 135000000;
1577dd7cddfSDavid du Colombier 		vga->r[1] = 3;
15814414594SDavid du Colombier 		vga->n[1] = 31;
15914414594SDavid du Colombier 		vga->m[1] = 127;
1607dd7cddfSDavid du Colombier 		trio64clock(vga, ctlr);
1617dd7cddfSDavid du Colombier 		vga->sequencer[0x12] = (vga->r[0]<<5)|vga->n[0];
1627dd7cddfSDavid du Colombier 		vga->sequencer[0x13] = vga->m[0];
1637dd7cddfSDavid du Colombier 		vga->misc |= 0x0C;
1647dd7cddfSDavid du Colombier 	}
1657dd7cddfSDavid du Colombier 
1667dd7cddfSDavid du Colombier 	/*
1677dd7cddfSDavid du Colombier 	 * Internal clock generator.
1687dd7cddfSDavid du Colombier 	 */
1697dd7cddfSDavid du Colombier 	vga->sequencer[0x15] &= ~0x31;
1707dd7cddfSDavid du Colombier 	vga->sequencer[0x15] |= 0x02;
1717dd7cddfSDavid du Colombier 	vga->sequencer[0x18] &= ~0x80;
1727dd7cddfSDavid du Colombier 	vga->crt[0x67] &= ~0xF2;
1737dd7cddfSDavid du Colombier 	if(ctlr->flag & Upclk2x8){
1747dd7cddfSDavid du Colombier 		vga->sequencer[0x15] |= 0x10;
1757dd7cddfSDavid du Colombier 		vga->sequencer[0x18] |= 0x80;
1767dd7cddfSDavid du Colombier 		/*
1777dd7cddfSDavid du Colombier 		 * There's a little strip of the border
1787dd7cddfSDavid du Colombier 		 * appears on the left in resolutions
1797dd7cddfSDavid du Colombier 		 * 1280 and above if the 0x02 bit isn't
1807dd7cddfSDavid du Colombier 		 * set (when it appears on the right...).
1817dd7cddfSDavid du Colombier 		 */
1827dd7cddfSDavid du Colombier 		vga->crt[0x67] |= 0x10;
1837dd7cddfSDavid du Colombier 	}
1847dd7cddfSDavid du Colombier 
1857dd7cddfSDavid du Colombier 	/*
1867dd7cddfSDavid du Colombier 	 * VLB address latch delay.
1877dd7cddfSDavid du Colombier 	 */
1887dd7cddfSDavid du Colombier 	if((vga->crt[0x36] & 0x03) == 0x01)
1897dd7cddfSDavid du Colombier 		vga->crt[0x58] &= ~0x08;
1907dd7cddfSDavid du Colombier 
1917dd7cddfSDavid du Colombier 	/*
1927dd7cddfSDavid du Colombier 	 * Start display FIFO fetch.
1937dd7cddfSDavid du Colombier 	 */
1947dd7cddfSDavid du Colombier 	x = vga->crt[0]-5;
1957dd7cddfSDavid du Colombier 	vga->crt[0x3B] = x;
1967dd7cddfSDavid du Colombier 	if(x & 0x100)
1977dd7cddfSDavid du Colombier 		vga->crt[0x5D] |= 0x40;
1987dd7cddfSDavid du Colombier 
1997dd7cddfSDavid du Colombier 	/*
2007dd7cddfSDavid du Colombier 	 * Display memory access control.
2017dd7cddfSDavid du Colombier 	 * Calculation of the M-parameter (Crt54) is
2027dd7cddfSDavid du Colombier 	 * memory-system and dot-clock dependent, the
2037dd7cddfSDavid du Colombier 	 * values below are guesses from dumping
2047dd7cddfSDavid du Colombier 	 * registers.
2057dd7cddfSDavid du Colombier 	 */
2067dd7cddfSDavid du Colombier 	vga->crt[0x60] = 0xFF;
2077dd7cddfSDavid du Colombier 	if(vga->mode->x <= 800)
2087dd7cddfSDavid du Colombier 		vga->crt[0x54] = 0xE8;
2097dd7cddfSDavid du Colombier 	else if(vga->mode->x <= 1024)
2107dd7cddfSDavid du Colombier 		vga->crt[0x54] = 0xA8;
2117dd7cddfSDavid du Colombier 	else
2127dd7cddfSDavid du Colombier 		vga->crt[0x54] = 0x00/*0x48*/;
2137dd7cddfSDavid du Colombier 
2147dd7cddfSDavid du Colombier 	ctlr->flag |= Finit;
2157dd7cddfSDavid du Colombier }
2167dd7cddfSDavid du Colombier 
2177dd7cddfSDavid du Colombier static void
load(Vga * vga,Ctlr * ctlr)2187dd7cddfSDavid du Colombier load(Vga* vga, Ctlr* ctlr)
2197dd7cddfSDavid du Colombier {
2207dd7cddfSDavid du Colombier 	ushort advfunc;
2217dd7cddfSDavid du Colombier 
2227dd7cddfSDavid du Colombier 	s3generic.load(vga, ctlr);
2237dd7cddfSDavid du Colombier 	vgaxo(Crtx, 0x60, vga->crt[0x60]);
2247dd7cddfSDavid du Colombier 	vgaxo(Crtx, 0x67, vga->crt[0x67]);
2257dd7cddfSDavid du Colombier 
2267dd7cddfSDavid du Colombier 	/*
2277dd7cddfSDavid du Colombier 	 * Load the PLL registers if necessary.
2287dd7cddfSDavid du Colombier 	 * Not sure if the variable-delay method of setting the
2297dd7cddfSDavid du Colombier 	 * PLL will work without a write here to vga->misc,
2307dd7cddfSDavid du Colombier 	 * so use the immediate-load method by toggling bit 5
2317dd7cddfSDavid du Colombier 	 * of Seq15 if necessary.
2327dd7cddfSDavid du Colombier 	 */
2337dd7cddfSDavid du Colombier 	vgaxo(Seqx, 0x12, vga->sequencer[0x12]);
2347dd7cddfSDavid du Colombier 	vgaxo(Seqx, 0x13, vga->sequencer[0x13]);
2357dd7cddfSDavid du Colombier 	if((vga->misc & 0x0C) == 0x0C)
2367dd7cddfSDavid du Colombier 		vgaxo(Seqx, 0x15, vga->sequencer[0x15]|0x20);
2377dd7cddfSDavid du Colombier 	vgaxo(Seqx, 0x15, vga->sequencer[0x15]);
2387dd7cddfSDavid du Colombier 	vgaxo(Seqx, 0x18, vga->sequencer[0x18]);
2397dd7cddfSDavid du Colombier 
2407dd7cddfSDavid du Colombier 	advfunc = 0x0000;
2417dd7cddfSDavid du Colombier 	if(ctlr->flag & Uenhanced)
2427dd7cddfSDavid du Colombier 		advfunc = 0x0001;
2437dd7cddfSDavid du Colombier 	outportw(0x4AE8, advfunc);
2447dd7cddfSDavid du Colombier }
2457dd7cddfSDavid du Colombier 
2467dd7cddfSDavid du Colombier static void
dump(Vga * vga,Ctlr * ctlr)2477dd7cddfSDavid du Colombier dump(Vga* vga, Ctlr* ctlr)
2487dd7cddfSDavid du Colombier {
2497dd7cddfSDavid du Colombier 	int i;
2507dd7cddfSDavid du Colombier 	ulong dclk, m, n, r;
2517dd7cddfSDavid du Colombier 
2527dd7cddfSDavid du Colombier 	s3generic.dump(vga, ctlr);
2537dd7cddfSDavid du Colombier 
2547dd7cddfSDavid du Colombier 	printitem(ctlr->name, "Seq08");
2557dd7cddfSDavid du Colombier 	for(i = 0x08; i < 0x19; i++)
2567dd7cddfSDavid du Colombier 		printreg(vga->sequencer[i]);
2577dd7cddfSDavid du Colombier 
2587dd7cddfSDavid du Colombier 	printitem(ctlr->name, "Crt2D");
2597dd7cddfSDavid du Colombier 	printreg(vga->crt[0x2D]);
2607dd7cddfSDavid du Colombier 	printreg(vga->crt[0x2E]);
2617dd7cddfSDavid du Colombier 	printreg(vga->crt[0x2F]);
2627dd7cddfSDavid du Colombier 
2637dd7cddfSDavid du Colombier 	n = vga->sequencer[0x12] & 0x1F;
2647dd7cddfSDavid du Colombier 	r = (vga->sequencer[0x12]>>5) & 0x03;
2657dd7cddfSDavid du Colombier 	m = vga->sequencer[0x13] & 0x7F;
2667dd7cddfSDavid du Colombier 	dclk = (m+2)*RefFreq;
2677dd7cddfSDavid du Colombier 	dclk /= (n+2)*(1<<r);
2687dd7cddfSDavid du Colombier 	printitem(ctlr->name, "dclk m n r");
2697dd7cddfSDavid du Colombier 	Bprint(&stdout, "%9ld %8ld       - %8ld %8ld\n", dclk, m, n, r);
2707dd7cddfSDavid du Colombier }
2717dd7cddfSDavid du Colombier 
2727dd7cddfSDavid du Colombier Ctlr trio64 = {
2737dd7cddfSDavid du Colombier 	"trio64",			/* name */
2747dd7cddfSDavid du Colombier 	snarf,				/* snarf */
2757dd7cddfSDavid du Colombier 	options,			/* options */
2767dd7cddfSDavid du Colombier 	init,				/* init */
2777dd7cddfSDavid du Colombier 	load,				/* load */
2787dd7cddfSDavid du Colombier 	dump,				/* dump */
2797dd7cddfSDavid du Colombier };
280