xref: /plan9/sys/src/cmd/aux/vga/ics534x.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  * ICS534x GENDAC.
107dd7cddfSDavid du Colombier  * For now assumed to be hooked to either a Tseng Labs ET4000-W32p
117dd7cddfSDavid du Colombier  * (Hercules Dynamite Power, the Hercules generates RS2 using CLK3)
127dd7cddfSDavid du Colombier  * or an ARK2000pv (Diamond Stealth64 Graphics 2001).
137dd7cddfSDavid du Colombier  */
147dd7cddfSDavid du Colombier static uchar
setrs2(Vga * vga,Ctlr * ctlr)157dd7cddfSDavid du Colombier setrs2(Vga* vga, Ctlr* ctlr)
167dd7cddfSDavid du Colombier {
177dd7cddfSDavid du Colombier 	uchar rs2;
187dd7cddfSDavid du Colombier 
197dd7cddfSDavid du Colombier 	rs2 = 0;
207dd7cddfSDavid du Colombier 	if(strncmp(vga->ctlr->name, "et4000-w32", 10) == 0){
217dd7cddfSDavid du Colombier 		rs2 = vgaxi(Crtx, 0x31);
227dd7cddfSDavid du Colombier 		vgaxo(Crtx, 0x31, 0x40|rs2);
237dd7cddfSDavid du Colombier 	}
247dd7cddfSDavid du Colombier 	else if(strncmp(vga->ctlr->name, "ark2000pv", 9) == 0){
257dd7cddfSDavid du Colombier 		rs2 = vgaxi(Seqx, 0x1C);
267dd7cddfSDavid du Colombier 		vgaxo(Seqx, 0x1C, 0x80|rs2);
277dd7cddfSDavid du Colombier 	}
287dd7cddfSDavid du Colombier 	else
297dd7cddfSDavid du Colombier 		error("%s: not configured for %s\n", vga->ctlr->name, ctlr->name);
307dd7cddfSDavid du Colombier 
317dd7cddfSDavid du Colombier 	return rs2;
327dd7cddfSDavid du Colombier }
337dd7cddfSDavid du Colombier 
347dd7cddfSDavid du Colombier static void
restorers2(Vga * vga,uchar rs2)357dd7cddfSDavid du Colombier restorers2(Vga* vga, uchar rs2)
367dd7cddfSDavid du Colombier {
377dd7cddfSDavid du Colombier 	if(strncmp(vga->ctlr->name, "et4000-w32", 10) == 0)
387dd7cddfSDavid du Colombier 		vgaxo(Crtx, 0x31, rs2);
397dd7cddfSDavid du Colombier 	else if(strncmp(vga->ctlr->name, "ark2000pv", 9) == 0)
407dd7cddfSDavid du Colombier 		vgaxo(Seqx, 0x1C, rs2);
417dd7cddfSDavid du Colombier }
427dd7cddfSDavid du Colombier 
437dd7cddfSDavid du Colombier static void
options(Vga *,Ctlr * ctlr)447dd7cddfSDavid du Colombier options(Vga*, Ctlr* ctlr)
457dd7cddfSDavid du Colombier {
467dd7cddfSDavid du Colombier 	ctlr->flag |= Hpclk2x8|Foptions;
477dd7cddfSDavid du Colombier }
487dd7cddfSDavid du Colombier 
497dd7cddfSDavid du Colombier static void
clock(Vga * vga,Ctlr * ctlr)507dd7cddfSDavid du Colombier clock(Vga* vga, Ctlr* ctlr)
517dd7cddfSDavid du Colombier {
527dd7cddfSDavid du Colombier 	ulong f, m, n, r;
537dd7cddfSDavid du Colombier 	double fmin, fmax, t, tok;
547dd7cddfSDavid du Colombier 
557dd7cddfSDavid du Colombier 	/*
567dd7cddfSDavid du Colombier 	 * The PLL frequency is defined by:
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)	     2MHz < Fref < 32MHz
627dd7cddfSDavid du Colombier 	 * 2)		    Fref
637dd7cddfSDavid du Colombier 	 *         600KHz < ----- <= 8Mhz
647dd7cddfSDavid du Colombier 	 *	            (N+2)
657dd7cddfSDavid du Colombier 	 * 3)		(M+2) x Fref
667dd7cddfSDavid du Colombier 	 *     60MHz <= ------------ <= 270MHz
677dd7cddfSDavid du Colombier 	 *		    (N+2)
687dd7cddfSDavid du Colombier 	 * 4) Fout < 135MHz
697dd7cddfSDavid du Colombier 	 * 5) 1 <= M <= 127, 1 <= N <= 31, 0 <= R <= 3
707dd7cddfSDavid du Colombier 	 *
717dd7cddfSDavid du Colombier 	 * First determine R by finding the highest value
727dd7cddfSDavid du Colombier 	 * for which
737dd7cddfSDavid du Colombier 	 *	      2**R x Fout <= 270Mhz
747dd7cddfSDavid du Colombier 	 * The datasheet says that if the multiplexed 16-bit
757dd7cddfSDavid du Colombier 	 * pseudo-colour mode is used then N2 (vga->r) must
767dd7cddfSDavid du Colombier 	 * be 2.
777dd7cddfSDavid du Colombier 	 */
787dd7cddfSDavid du Colombier 	if(ctlr->flag & Upclk2x8)
797dd7cddfSDavid du Colombier 		vga->r[0] = 2;
807dd7cddfSDavid du Colombier 	else{
817dd7cddfSDavid du Colombier 		vga->r[0] = 4;
827dd7cddfSDavid du Colombier 		for(r = 0; r <= 3; r++){
837dd7cddfSDavid du Colombier 			f = vga->f[0]*(1<<r);
847dd7cddfSDavid du Colombier 			if(60000000 < f && f <= 270000000)
857dd7cddfSDavid du Colombier 				vga->r[0] = r;
867dd7cddfSDavid du Colombier 		}
877dd7cddfSDavid du Colombier 		if(vga->r[0] > 3)
887dd7cddfSDavid du Colombier 			error("%s: pclk %lud out of range\n",
897dd7cddfSDavid du Colombier 				ctlr->name, vga->f[0]);
907dd7cddfSDavid du Colombier 	}
917dd7cddfSDavid du Colombier 
927dd7cddfSDavid du Colombier 	/*
937dd7cddfSDavid du Colombier 	 * Now find the closest match for M and N.
947dd7cddfSDavid du Colombier 	 * Lower values of M and N give better noise rejection.
957dd7cddfSDavid du Colombier 	 */
967dd7cddfSDavid du Colombier 	fmin = vga->f[0]*0.995;
977dd7cddfSDavid du Colombier 	fmax = vga->f[0]*1.005;
987dd7cddfSDavid du Colombier 	tok = 0.0;
997dd7cddfSDavid du Colombier 	for(n = 31; n >= 1; n--){
1007dd7cddfSDavid du Colombier 		t = RefFreq/(n+2);
1017dd7cddfSDavid du Colombier 		if(600000 >= t || t > 8000000)
1027dd7cddfSDavid du Colombier 			continue;
1037dd7cddfSDavid du Colombier 
1047dd7cddfSDavid du Colombier 		t = vga->f[0]*(n+2)*(1<<vga->r[0]);
1057dd7cddfSDavid du Colombier 		t /= RefFreq;
1067dd7cddfSDavid du Colombier 		m = (t+0.5) - 2;
1077dd7cddfSDavid du Colombier 		if(m > 127)
1087dd7cddfSDavid du Colombier 			continue;
1097dd7cddfSDavid du Colombier 
1107dd7cddfSDavid du Colombier 		t = (m+2)*RefFreq;
1117dd7cddfSDavid du Colombier 		t /= (n+2)*(1<<vga->r[0]);
1127dd7cddfSDavid du Colombier 
1137dd7cddfSDavid du Colombier 		if(fmin <= t && t < fmax){
1147dd7cddfSDavid du Colombier 			vga->m[0] = m;
1157dd7cddfSDavid du Colombier 			vga->n[0] = n;
1167dd7cddfSDavid du Colombier 			tok = t;
1177dd7cddfSDavid du Colombier 		}
1187dd7cddfSDavid du Colombier 	}
1197dd7cddfSDavid du Colombier 
1207dd7cddfSDavid du Colombier 	if(tok == 0.0)
1217dd7cddfSDavid du Colombier 		error("%s: pclk %lud out of range\n", ctlr->name, vga->f[0]);
1227dd7cddfSDavid du Colombier }
1237dd7cddfSDavid du Colombier 
1247dd7cddfSDavid du Colombier static void
init(Vga * vga,Ctlr * ctlr)1257dd7cddfSDavid du Colombier init(Vga* vga, Ctlr* ctlr)
1267dd7cddfSDavid du Colombier {
1277dd7cddfSDavid du Colombier 	ulong pclk;
1287dd7cddfSDavid du Colombier 	char *p;
1297dd7cddfSDavid du Colombier 
1307dd7cddfSDavid du Colombier 	/*
1317dd7cddfSDavid du Colombier 	 * Part comes in -135, -110 and -80MHz speed-grades.
1327dd7cddfSDavid du Colombier 	 */
1337dd7cddfSDavid du Colombier 	pclk = 80000000;
1347dd7cddfSDavid du Colombier 	if(p = strrchr(ctlr->name, '-'))
1357dd7cddfSDavid du Colombier 		pclk = strtoul(p+1, 0, 0) * 1000000;
1367dd7cddfSDavid du Colombier 
1377dd7cddfSDavid du Colombier 	/*
1387dd7cddfSDavid du Colombier 	 * If we don't already have a desired pclk,
1397dd7cddfSDavid du Colombier 	 * take it from the mode.
1407dd7cddfSDavid du Colombier 	 * Check it's within range.
1417dd7cddfSDavid du Colombier 	 */
1427dd7cddfSDavid du Colombier 	if(vga->f[0] == 0)
1437dd7cddfSDavid du Colombier 		vga->f[0] = vga->mode->frequency;
1447dd7cddfSDavid du Colombier 	if(vga->f[0] > pclk)
1457dd7cddfSDavid du Colombier 		error("%s: invalid pclk - %ld\n", ctlr->name, vga->f[0]);
1467dd7cddfSDavid du Colombier 
1477dd7cddfSDavid du Colombier 	/*
1487dd7cddfSDavid du Colombier 	 * Determine whether to use 2x8-bit mode or not.
1497dd7cddfSDavid du Colombier 	 * If yes and the clock has already been initialised,
1507dd7cddfSDavid du Colombier 	 * initialise it again.
1517dd7cddfSDavid du Colombier 	 */
1527dd7cddfSDavid du Colombier 	if(vga->ctlr && (vga->ctlr->flag & Hpclk2x8) && vga->mode->z == 8 && vga->f[0] >= pclk/2){
1537dd7cddfSDavid du Colombier 		vga->f[0] /= 2;
1547dd7cddfSDavid du Colombier 		resyncinit(vga, ctlr, Upclk2x8, 0);
1557dd7cddfSDavid du Colombier 	}
1567dd7cddfSDavid du Colombier 
1577dd7cddfSDavid du Colombier 	/*
1587dd7cddfSDavid du Colombier 	 * Clock bits. If the desired video clock is
1597dd7cddfSDavid du Colombier 	 * one of the two standard VGA clocks it can just be
1607dd7cddfSDavid du Colombier 	 * set using bits <3:2> of vga->misc, otherwise we
1617dd7cddfSDavid du Colombier 	 * need to programme the DCLK PLL.
1627dd7cddfSDavid du Colombier 	 */
1637dd7cddfSDavid du Colombier 	vga->misc &= ~0x0C;
1647dd7cddfSDavid du Colombier 	if(vga->f[0] == VgaFreq0)
1657dd7cddfSDavid du Colombier 		vga->i[0] = 0;
1667dd7cddfSDavid du Colombier 	else if(vga->f[0] == VgaFreq1){
1677dd7cddfSDavid du Colombier 		vga->misc |= 0x04;
1687dd7cddfSDavid du Colombier 		vga->i[0] = 1;
1697dd7cddfSDavid du Colombier 	}
1707dd7cddfSDavid du Colombier 	else{
1717dd7cddfSDavid du Colombier 		/*
1727dd7cddfSDavid du Colombier 		 * Initialise the PLL parameters.
1737dd7cddfSDavid du Colombier 		 * Use CLK0 f7 internal clock (there are only 3
1747dd7cddfSDavid du Colombier 		 * clock-select bits).
1757dd7cddfSDavid du Colombier 		 */
1767dd7cddfSDavid du Colombier 		clock(vga, ctlr);
1777dd7cddfSDavid du Colombier 		vga->i[0] = 0x07;
1787dd7cddfSDavid du Colombier 	}
1797dd7cddfSDavid du Colombier 
1807dd7cddfSDavid du Colombier 	ctlr->flag |= Finit;
1817dd7cddfSDavid du Colombier }
1827dd7cddfSDavid du Colombier 
1837dd7cddfSDavid du Colombier static void
load(Vga * vga,Ctlr * ctlr)1847dd7cddfSDavid du Colombier load(Vga* vga, Ctlr* ctlr)
1857dd7cddfSDavid du Colombier {
1867dd7cddfSDavid du Colombier 	uchar rs2, mode, pll;
1877dd7cddfSDavid du Colombier 
1887dd7cddfSDavid du Colombier 	rs2 = setrs2(vga, ctlr);
1897dd7cddfSDavid du Colombier 
1907dd7cddfSDavid du Colombier 	/*
1917dd7cddfSDavid du Colombier 	 * Put the chip into snooze mode,
1927dd7cddfSDavid du Colombier 	 * colour mode 0.
1937dd7cddfSDavid du Colombier 	 */
1947dd7cddfSDavid du Colombier 	mode = 0x00;
1957dd7cddfSDavid du Colombier 	outportb(Pixmask, 0x01);
1967dd7cddfSDavid du Colombier 
1977dd7cddfSDavid du Colombier 	if(ctlr->flag & Upclk2x8)
1987dd7cddfSDavid du Colombier 		mode = 0x10;
1997dd7cddfSDavid du Colombier 
2007dd7cddfSDavid du Colombier 	/*
2017dd7cddfSDavid du Colombier 	 * If necessary, set the PLL parameters for CLK0 f7
2027dd7cddfSDavid du Colombier 	 * and make sure the PLL control register selects the
2037dd7cddfSDavid du Colombier 	 * correct clock. Preserve the memory clock setting.
2047dd7cddfSDavid du Colombier 	 */
2057dd7cddfSDavid du Colombier 	outportb(PaddrR, 0x0E);
2067dd7cddfSDavid du Colombier 	pll = inportb(Pdata) & 0x10;
2077dd7cddfSDavid du Colombier 	if(vga->i[0] == 0x07){
2087dd7cddfSDavid du Colombier 		outportb(PaddrW, vga->i[0]);
2097dd7cddfSDavid du Colombier 		outportb(Pdata, vga->m[0]);
2107dd7cddfSDavid du Colombier 		outportb(Pdata, (vga->r[0]<<5)|vga->n[0]);
2117dd7cddfSDavid du Colombier 		pll |= 0x27;
2127dd7cddfSDavid du Colombier 	}
2137dd7cddfSDavid du Colombier 	outportb(PaddrW, 0x0E);
2147dd7cddfSDavid du Colombier 	outportb(Pdata, pll);
2157dd7cddfSDavid du Colombier 	outportb(Pixmask, mode);
2167dd7cddfSDavid du Colombier 
2177dd7cddfSDavid du Colombier 	restorers2(vga, rs2);
2187dd7cddfSDavid du Colombier 	ctlr->flag |= Fload;
2197dd7cddfSDavid du Colombier }
2207dd7cddfSDavid du Colombier 
2217dd7cddfSDavid du Colombier static void
dump(Vga * vga,Ctlr * ctlr)2227dd7cddfSDavid du Colombier dump(Vga* vga, Ctlr* ctlr)
2237dd7cddfSDavid du Colombier {
2247dd7cddfSDavid du Colombier 	int i;
2257dd7cddfSDavid du Colombier 	uchar rs2, m, n;
2267dd7cddfSDavid du Colombier 	char buf[32];
2277dd7cddfSDavid du Colombier 	ulong f;
2287dd7cddfSDavid du Colombier 
2297dd7cddfSDavid du Colombier 	rs2 = setrs2(vga, ctlr);
2307dd7cddfSDavid du Colombier 
2317dd7cddfSDavid du Colombier 	printitem(ctlr->name, "command");
2327dd7cddfSDavid du Colombier 	printreg(inportb(Pixmask));
2337dd7cddfSDavid du Colombier 
2347dd7cddfSDavid du Colombier 	outportb(PaddrR, 0x00);
2357dd7cddfSDavid du Colombier 	for(i = 0; i < 0x0E; i++){
2367dd7cddfSDavid du Colombier 		sprint(buf, "f%X m n", i);
2377dd7cddfSDavid du Colombier 		printitem(ctlr->name, buf);
2387dd7cddfSDavid du Colombier 		m = inportb(Pdata);
2397dd7cddfSDavid du Colombier 		printreg(m);
2407dd7cddfSDavid du Colombier 		n = inportb(Pdata);
2417dd7cddfSDavid du Colombier 		printreg(n);
2427dd7cddfSDavid du Colombier 
2437dd7cddfSDavid du Colombier 		f = 14318180*(m+2);
2447dd7cddfSDavid du Colombier 		f /= (n & 0x1F)+2;
2457dd7cddfSDavid du Colombier 		f /= 1<<((n>>5) & 0x03);
2467dd7cddfSDavid du Colombier 		Bprint(&stdout, "%12lud", f);
2477dd7cddfSDavid du Colombier 	}
2487dd7cddfSDavid du Colombier 	printitem(ctlr->name, "control");
2497dd7cddfSDavid du Colombier 	printreg(inportb(Pdata));
2507dd7cddfSDavid du Colombier 
2517dd7cddfSDavid du Colombier 	restorers2(vga, rs2);
2527dd7cddfSDavid du Colombier }
2537dd7cddfSDavid du Colombier 
2547dd7cddfSDavid du Colombier Ctlr ics534x = {
2557dd7cddfSDavid du Colombier 	"ics534x",			/* name */
2567dd7cddfSDavid du Colombier 	0,				/* snarf */
2577dd7cddfSDavid du Colombier 	options,			/* options */
2587dd7cddfSDavid du Colombier 	init,				/* init */
2597dd7cddfSDavid du Colombier 	load,				/* load */
2607dd7cddfSDavid du Colombier 	dump,				/* dump */
2617dd7cddfSDavid du Colombier };
262