xref: /plan9-contrib/sys/src/cmd/aux/vga/rgb524.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  * IBM RGB524.
107dd7cddfSDavid du Colombier  * 170/220MHz High Performance Palette DAC.
117dd7cddfSDavid du Colombier  *
127dd7cddfSDavid du Colombier  * Assumes hooked up to an S3 Vision96[48].
137dd7cddfSDavid du Colombier  */
147dd7cddfSDavid du Colombier enum {
157dd7cddfSDavid du Colombier 	IndexLo		= 0x00,
167dd7cddfSDavid du Colombier 	IndexHi		= 0x01,
177dd7cddfSDavid du Colombier 	Data		= 0x02,
187dd7cddfSDavid du Colombier 	IndexCtl	= 0x03,
197dd7cddfSDavid du Colombier };
207dd7cddfSDavid du Colombier 
217dd7cddfSDavid du Colombier enum {						/* index registers */
227dd7cddfSDavid du Colombier 	MiscClock	= 0x02,
237dd7cddfSDavid du Colombier 	PixelFormat	= 0x0A,
247dd7cddfSDavid du Colombier 	PLLControl1	= 0x10,
257dd7cddfSDavid du Colombier 	PLLControl2	= 0x11,
267dd7cddfSDavid du Colombier 	PLLReference	= 0x14,
277dd7cddfSDavid du Colombier 	Frequency0	= 0x20,
287dd7cddfSDavid du Colombier 	MiscControl1	= 0x70,
297dd7cddfSDavid du Colombier 	MiscControl2	= 0x71,
307dd7cddfSDavid du Colombier };
317dd7cddfSDavid du Colombier 
327dd7cddfSDavid du Colombier static uchar
setrs2(void)337dd7cddfSDavid du Colombier setrs2(void)
347dd7cddfSDavid du Colombier {
357dd7cddfSDavid du Colombier 	uchar rs2;
367dd7cddfSDavid du Colombier 
377dd7cddfSDavid du Colombier 	rs2 = vgaxi(Crtx, 0x55);
387dd7cddfSDavid du Colombier 	vgaxo(Crtx, 0x55, (rs2 & 0xFC)|0x01);
397dd7cddfSDavid du Colombier 
407dd7cddfSDavid du Colombier 	return rs2;
417dd7cddfSDavid du Colombier }
427dd7cddfSDavid du Colombier 
437dd7cddfSDavid du Colombier static uchar
rgb524xi(int index)447dd7cddfSDavid du Colombier rgb524xi(int index)
457dd7cddfSDavid du Colombier {
467dd7cddfSDavid du Colombier 	outportb(dacxreg[IndexLo], index & 0xFF);
477dd7cddfSDavid du Colombier 	outportb(dacxreg[IndexHi], (index>>8) & 0xFF);
487dd7cddfSDavid du Colombier 
497dd7cddfSDavid du Colombier 	return inportb(dacxreg[Data]);
507dd7cddfSDavid du Colombier }
517dd7cddfSDavid du Colombier 
527dd7cddfSDavid du Colombier static void
rgb524xo(int index,uchar data)537dd7cddfSDavid du Colombier rgb524xo(int index, uchar data)
547dd7cddfSDavid du Colombier {
557dd7cddfSDavid du Colombier 	outportb(dacxreg[IndexLo], index & 0xFF);
567dd7cddfSDavid du Colombier 	outportb(dacxreg[IndexHi], (index>>8) & 0xFF);
577dd7cddfSDavid du Colombier 
587dd7cddfSDavid du Colombier 	outportb(dacxreg[Data], data);
597dd7cddfSDavid du Colombier }
607dd7cddfSDavid du Colombier 
617dd7cddfSDavid du Colombier static void
restorers2(uchar rs2)627dd7cddfSDavid du Colombier restorers2(uchar rs2)
637dd7cddfSDavid du Colombier {
647dd7cddfSDavid du Colombier 	vgaxo(Crtx, 0x55, rs2);
657dd7cddfSDavid du Colombier }
667dd7cddfSDavid du Colombier 
677dd7cddfSDavid du Colombier static void
clock(Vga * vga,Ctlr * ctlr)687dd7cddfSDavid du Colombier clock(Vga* vga, Ctlr* ctlr)
697dd7cddfSDavid du Colombier {
707dd7cddfSDavid du Colombier 	if(vga->f[0] >= 16250000 && vga->f[0] <= 32000000){
717dd7cddfSDavid du Colombier 		vga->f[0] = (vga->f[0]/250000)*250000;
727dd7cddfSDavid du Colombier 		vga->d[0] = (4*vga->f[0])/1000000 - 65;
737dd7cddfSDavid du Colombier 	}
747dd7cddfSDavid du Colombier 	else if(vga->f[0] >= 32500000 && vga->f[0] <= 64000000){
757dd7cddfSDavid du Colombier 		vga->f[0] = (vga->f[0]/500000)*500000;
767dd7cddfSDavid du Colombier 		vga->d[0] = 0x40|((2*vga->f[0])/1000000 - 65);
777dd7cddfSDavid du Colombier 	}
787dd7cddfSDavid du Colombier 	else if(vga->f[0] >= 65000000 && vga->f[0] <= 128000000){
797dd7cddfSDavid du Colombier 		vga->f[0] = (vga->f[0]/1000000)*1000000;
807dd7cddfSDavid du Colombier 		vga->d[0] = 0x80|(vga->f[0]/1000000 - 65);
817dd7cddfSDavid du Colombier 	}
827dd7cddfSDavid du Colombier 	else if(vga->f[0] >= 130000000 && vga->f[0] <= 220000000){
837dd7cddfSDavid du Colombier 		vga->f[0] = (vga->f[0]/2000000)*2000000;
847dd7cddfSDavid du Colombier 		vga->d[0] = 0xC0|((vga->f[0]/2)/1000000 - 65);
857dd7cddfSDavid du Colombier 	}
867dd7cddfSDavid du Colombier 	else
877dd7cddfSDavid du Colombier 		error("%s: pclk %lud out of range\n",
887dd7cddfSDavid du Colombier 			ctlr->name, vga->f[0]);
897dd7cddfSDavid du Colombier }
907dd7cddfSDavid du Colombier 
917dd7cddfSDavid du Colombier static void
init(Vga * vga,Ctlr * ctlr)927dd7cddfSDavid du Colombier init(Vga* vga, Ctlr* ctlr)
937dd7cddfSDavid du Colombier {
947dd7cddfSDavid du Colombier 	ulong pclk;
957dd7cddfSDavid du Colombier 	char *p;
967dd7cddfSDavid du Colombier 
977dd7cddfSDavid du Colombier 	/*
987dd7cddfSDavid du Colombier 	 * Part comes in -170 and -220MHz speed-grades.
997dd7cddfSDavid du Colombier 	 */
1007dd7cddfSDavid du Colombier 	pclk = 170000000;
1017dd7cddfSDavid du Colombier 	if(p = strrchr(ctlr->name, '-'))
1027dd7cddfSDavid du Colombier 		pclk = strtoul(p+1, 0, 0) * 1000000;
1037dd7cddfSDavid du Colombier 
1047dd7cddfSDavid du Colombier 	/*
1057dd7cddfSDavid du Colombier 	 * If we don't already have a desired pclk,
1067dd7cddfSDavid du Colombier 	 * take it from the mode.
1077dd7cddfSDavid du Colombier 	 * Check it's within range.
1087dd7cddfSDavid du Colombier 	 */
1097dd7cddfSDavid du Colombier 	if(vga->f[0] == 0)
1107dd7cddfSDavid du Colombier 		vga->f[0] = vga->mode->frequency;
1117dd7cddfSDavid du Colombier 	if(vga->f[0] > pclk)
1127dd7cddfSDavid du Colombier 		error("%s: invalid pclk - %ld\n", ctlr->name, vga->f[0]);
1137dd7cddfSDavid du Colombier 
1147dd7cddfSDavid du Colombier 	/*
1157dd7cddfSDavid du Colombier 	 * Determine whether to use clock-doubler or not.
1167dd7cddfSDavid du Colombier 	 */
1177dd7cddfSDavid du Colombier 	if((ctlr->flag & Uclk2) == 0 && vga->mode->z == 8)
1187dd7cddfSDavid du Colombier 		resyncinit(vga, ctlr, Uclk2, 0);
1197dd7cddfSDavid du Colombier 
1207dd7cddfSDavid du Colombier 	/*
1217dd7cddfSDavid du Colombier 	 * Clock bits. If the desired video clock is
1227dd7cddfSDavid du Colombier 	 * one of the two standard VGA clocks it can just be
1237dd7cddfSDavid du Colombier 	 * set using bits <3:2> of vga->misc, otherwise we
1247dd7cddfSDavid du Colombier 	 * need to programme the PLL.
1257dd7cddfSDavid du Colombier 	 */
1267dd7cddfSDavid du Colombier 	vga->misc &= ~0x0C;
1277dd7cddfSDavid du Colombier 	if(vga->mode->z == 8 || (vga->f[0] != VgaFreq0 && vga->f[0] != VgaFreq1)){
1287dd7cddfSDavid du Colombier 		/*
1297dd7cddfSDavid du Colombier 		 * Initialise the PLL parameters.
1307dd7cddfSDavid du Colombier 		 * Use internal FS3 fixed-reference divider.
1317dd7cddfSDavid du Colombier 		 */
1327dd7cddfSDavid du Colombier 		clock(vga, ctlr);
1337dd7cddfSDavid du Colombier 		vga->i[0] = 0x03;
1347dd7cddfSDavid du Colombier 	}
1357dd7cddfSDavid du Colombier 	else if(vga->f[0] == VgaFreq0)
1367dd7cddfSDavid du Colombier 		vga->i[0] = 0;
1377dd7cddfSDavid du Colombier 	else if(vga->f[0] == VgaFreq1){
1387dd7cddfSDavid du Colombier 		vga->misc |= 0x04;
1397dd7cddfSDavid du Colombier 		vga->i[0] = 1;
1407dd7cddfSDavid du Colombier 	}
1417dd7cddfSDavid du Colombier 
1427dd7cddfSDavid du Colombier 	ctlr->flag |= Finit;
1437dd7cddfSDavid du Colombier }
1447dd7cddfSDavid du Colombier 
1457dd7cddfSDavid du Colombier static void
load(Vga * vga,Ctlr * ctlr)1467dd7cddfSDavid du Colombier load(Vga* vga, Ctlr* ctlr)
1477dd7cddfSDavid du Colombier {
1487dd7cddfSDavid du Colombier 	uchar mc2, rs2, x;
1497dd7cddfSDavid du Colombier 	char *val;
1507dd7cddfSDavid du Colombier 	int f;
1517dd7cddfSDavid du Colombier 
1527dd7cddfSDavid du Colombier 	rs2 = setrs2();
1537dd7cddfSDavid du Colombier 
1547dd7cddfSDavid du Colombier 	/*
1557dd7cddfSDavid du Colombier 	 * Set VgaFreq[01].
1567dd7cddfSDavid du Colombier 	 */
1577dd7cddfSDavid du Colombier 	rgb524xo(PLLControl1, 0x00);
1587dd7cddfSDavid du Colombier 	rgb524xo(Frequency0, 0x24);
1597dd7cddfSDavid du Colombier 	rgb524xo(Frequency0+1, 0x30);
1607dd7cddfSDavid du Colombier 
1617dd7cddfSDavid du Colombier 	if(val = dbattr(vga->attr, "rgb524refclk")){
1627dd7cddfSDavid du Colombier 		f = strtol(val, 0, 0);
1637dd7cddfSDavid du Colombier 		if(f > 1000000)
1647dd7cddfSDavid du Colombier 			f /= 1000000;
1657dd7cddfSDavid du Colombier 		rgb524xo(PLLReference, f/2);
1667dd7cddfSDavid du Colombier 	}
1677dd7cddfSDavid du Colombier 
1687dd7cddfSDavid du Colombier 	/*
1697dd7cddfSDavid du Colombier 	 * Enable pixel programming and clock divide
1707dd7cddfSDavid du Colombier 	 * factor.
1717dd7cddfSDavid du Colombier 	 */
1727dd7cddfSDavid du Colombier 	x = rgb524xi(MiscClock) & ~0x0E;
1737dd7cddfSDavid du Colombier 	x |= 0x01;
1747dd7cddfSDavid du Colombier 	if(ctlr->flag & Uclk2)
1757dd7cddfSDavid du Colombier 		x |= 0x02;
1767dd7cddfSDavid du Colombier 	rgb524xo(MiscClock, x);
1777dd7cddfSDavid du Colombier 
1787dd7cddfSDavid du Colombier 	if(vga->mode->z == 1)
1797dd7cddfSDavid du Colombier 		rgb524xo(PixelFormat, 0x02);
1807dd7cddfSDavid du Colombier 	else if(vga->mode->z == 8)
1817dd7cddfSDavid du Colombier 		rgb524xo(PixelFormat, 0x03);
1827dd7cddfSDavid du Colombier 
1837dd7cddfSDavid du Colombier 	x = rgb524xi(MiscControl1) & ~0x41;
1847dd7cddfSDavid du Colombier 	x |= 0x01;
1857dd7cddfSDavid du Colombier 	rgb524xo(MiscControl1, x);
1867dd7cddfSDavid du Colombier 
1877dd7cddfSDavid du Colombier 	mc2 = rgb524xi(MiscControl2) & ~0x41;
1887dd7cddfSDavid du Colombier 	vga->crt[0x22] &= ~0x08;
1897dd7cddfSDavid du Colombier 	if(vga->i[0] == 3){
1907dd7cddfSDavid du Colombier 		rgb524xo(Frequency0+3, vga->d[0]);
1917dd7cddfSDavid du Colombier 		rgb524xo(PLLControl1, 0x02);
1927dd7cddfSDavid du Colombier 		rgb524xo(PLLControl2, vga->i[0]);
1937dd7cddfSDavid du Colombier 		mc2 |= 0x41;
1947dd7cddfSDavid du Colombier 		vga->crt[0x22] |= 0x08;
1957dd7cddfSDavid du Colombier 	}
1967dd7cddfSDavid du Colombier 	rgb524xo(MiscControl2, mc2);
1977dd7cddfSDavid du Colombier 	vgaxo(Crtx, 0x22, vga->crt[0x22]);
1987dd7cddfSDavid du Colombier 
1997dd7cddfSDavid du Colombier 	restorers2(rs2);
2007dd7cddfSDavid du Colombier 	ctlr->flag |= Fload;
2017dd7cddfSDavid du Colombier }
2027dd7cddfSDavid du Colombier 
2037dd7cddfSDavid du Colombier static void
dump(Vga *,Ctlr * ctlr)2047dd7cddfSDavid du Colombier dump(Vga*, Ctlr* ctlr)
2057dd7cddfSDavid du Colombier {
2067dd7cddfSDavid du Colombier 	uchar rs2, r, x[256];
2077dd7cddfSDavid du Colombier 	char buf[32];
2087dd7cddfSDavid du Colombier 	int df, i, maxf, vcodc, vf;
2097dd7cddfSDavid du Colombier 
2107dd7cddfSDavid du Colombier 	rs2 = setrs2();
2117dd7cddfSDavid du Colombier 	printitem(ctlr->name, "index00");
2127dd7cddfSDavid du Colombier 	for(i = 0x00; i < 0x0F; i++){
2137dd7cddfSDavid du Colombier 		x[i] = rgb524xi(i);
2147dd7cddfSDavid du Colombier 		printreg(x[i]);
2157dd7cddfSDavid du Colombier 	}
2167dd7cddfSDavid du Colombier 	printitem(ctlr->name, "index10");
2177dd7cddfSDavid du Colombier 	for(i = 0x10; i < 0x17; i++){
2187dd7cddfSDavid du Colombier 		x[i] = rgb524xi(i);
2197dd7cddfSDavid du Colombier 		printreg(x[i]);
2207dd7cddfSDavid du Colombier 	}
2217dd7cddfSDavid du Colombier 	printitem(ctlr->name, "index20");
2227dd7cddfSDavid du Colombier 	for(i = 0x20; i < 0x30; i++){
2237dd7cddfSDavid du Colombier 		x[i] = rgb524xi(i);
2247dd7cddfSDavid du Colombier 		printreg(x[i]);
2257dd7cddfSDavid du Colombier 	}
2267dd7cddfSDavid du Colombier 	printitem(ctlr->name, "index30");
2277dd7cddfSDavid du Colombier 	for(i = 0x30; i < 0x37; i++){
2287dd7cddfSDavid du Colombier 		x[i] = rgb524xi(i);
2297dd7cddfSDavid du Colombier 		printreg(x[i]);
2307dd7cddfSDavid du Colombier 	}
2317dd7cddfSDavid du Colombier 	printitem(ctlr->name, "index40");
2327dd7cddfSDavid du Colombier 	for(i = 0x40; i < 0x49; i++){
2337dd7cddfSDavid du Colombier 		x[i] = rgb524xi(i);
2347dd7cddfSDavid du Colombier 		printreg(x[i]);
2357dd7cddfSDavid du Colombier 	}
2367dd7cddfSDavid du Colombier 	printitem(ctlr->name, "index60");
2377dd7cddfSDavid du Colombier 	for(i = 0x60; i < 0x63; i++){
2387dd7cddfSDavid du Colombier 		x[i] = rgb524xi(i);
2397dd7cddfSDavid du Colombier 		printreg(x[i]);
2407dd7cddfSDavid du Colombier 	}
2417dd7cddfSDavid du Colombier 	printitem(ctlr->name, "index70");
2427dd7cddfSDavid du Colombier 	for(i = 0x70; i < 0x73; i++){
2437dd7cddfSDavid du Colombier 		x[i] = rgb524xi(i);
2447dd7cddfSDavid du Colombier 		printreg(x[i]);
2457dd7cddfSDavid du Colombier 	}
2467dd7cddfSDavid du Colombier 	printitem(ctlr->name, "index8E");
2477dd7cddfSDavid du Colombier 	for(i = 0x8E; i < 0x92; i++){
2487dd7cddfSDavid du Colombier 		x[i] = rgb524xi(i);
2497dd7cddfSDavid du Colombier 		printreg(x[i]);
2507dd7cddfSDavid du Colombier 	}
2517dd7cddfSDavid du Colombier 	restorers2(rs2);
2527dd7cddfSDavid du Colombier 
2537dd7cddfSDavid du Colombier 	/*
2547dd7cddfSDavid du Colombier 	 * x[0x10]	pixel clock frequency selection
2557dd7cddfSDavid du Colombier 	 *		0, 2 for direct programming
2567dd7cddfSDavid du Colombier 	 * x[0x20-0x2F]	pixel frequency 0-15
2577dd7cddfSDavid du Colombier 	 */
2587dd7cddfSDavid du Colombier 	printitem(ctlr->name, "refclk");
2597dd7cddfSDavid du Colombier 	Bprint(&stdout, "%12ud\n", x[PLLReference]*2*1000000);
2607dd7cddfSDavid du Colombier 	if((i = (x[0x10] & 0x07)) == 0x00 || i == 0x02){
2617dd7cddfSDavid du Colombier 		/*
2627dd7cddfSDavid du Colombier 		 * Direct programming, external frequency select.
2637dd7cddfSDavid du Colombier 		 * F[0-4] are probably tied directly to the 2 clock-select
2647dd7cddfSDavid du Colombier 		 * bits in the VGA Misc register.
2657dd7cddfSDavid du Colombier 		 */
2667dd7cddfSDavid du Colombier 		if(i == 0)
2677dd7cddfSDavid du Colombier 			maxf = 4;
2687dd7cddfSDavid du Colombier 		else
2697dd7cddfSDavid du Colombier 			maxf = 16;
2707dd7cddfSDavid du Colombier 		for(i = 0; i < maxf; i++){
2717dd7cddfSDavid du Colombier 			if((r = x[0x20+i]) == 0)
2727dd7cddfSDavid du Colombier 				continue;
2737dd7cddfSDavid du Colombier 			sprint(buf, "direct F%X", i);
2747dd7cddfSDavid du Colombier 			printitem(ctlr->name, buf);
2757dd7cddfSDavid du Colombier 			df = (r>>6) & 0x03;
2767dd7cddfSDavid du Colombier 			vcodc = r & 0x3F;
2777dd7cddfSDavid du Colombier 
2787dd7cddfSDavid du Colombier 			vf = 0;
2797dd7cddfSDavid du Colombier 			switch(df){
2807dd7cddfSDavid du Colombier 			case 0:
2817dd7cddfSDavid du Colombier 				vf = (vcodc+65)/4;
2827dd7cddfSDavid du Colombier 				break;
2837dd7cddfSDavid du Colombier 
2847dd7cddfSDavid du Colombier 			case 1:
2857dd7cddfSDavid du Colombier 				vf = (vcodc+65)/2;
2867dd7cddfSDavid du Colombier 				break;
2877dd7cddfSDavid du Colombier 
2887dd7cddfSDavid du Colombier 			case 2:
2897dd7cddfSDavid du Colombier 				vf = (vcodc+65);
2907dd7cddfSDavid du Colombier 				break;
2917dd7cddfSDavid du Colombier 
2927dd7cddfSDavid du Colombier 			case 3:
2937dd7cddfSDavid du Colombier 				vf = (vcodc+65)*2;
2947dd7cddfSDavid du Colombier 				break;
2957dd7cddfSDavid du Colombier 			}
2967dd7cddfSDavid du Colombier 			Bprint(&stdout, "%12ud\n", vf);
2977dd7cddfSDavid du Colombier 		}
2987dd7cddfSDavid du Colombier 	}
2997dd7cddfSDavid du Colombier }
3007dd7cddfSDavid du Colombier 
3017dd7cddfSDavid du Colombier Ctlr rgb524 = {
3027dd7cddfSDavid du Colombier 	"rgb524",			/* name */
3037dd7cddfSDavid du Colombier 	0,				/* snarf */
3047dd7cddfSDavid du Colombier 	0,				/* options */
3057dd7cddfSDavid du Colombier 	init,				/* init */
3067dd7cddfSDavid du Colombier 	load,				/* load */
3077dd7cddfSDavid du Colombier 	dump,				/* dump */
3087dd7cddfSDavid du Colombier };
309