xref: /plan9-contrib/sys/src/cmd/aux/vga/rgb524mn.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 RGB52x and compatibles.
107dd7cddfSDavid du Colombier  * High Performance Palette DAC.
117dd7cddfSDavid du Colombier  */
127dd7cddfSDavid du Colombier uchar (*rgb524mnxi)(Vga*, int);
137dd7cddfSDavid du Colombier void (*rgb524mnxo)(Vga*, int, uchar);
147dd7cddfSDavid du Colombier 
157dd7cddfSDavid du Colombier enum {						/* index registers */
167dd7cddfSDavid du Colombier 	MiscClock	= 0x02,
177dd7cddfSDavid du Colombier 	SyncControl	= 0x03,
187dd7cddfSDavid du Colombier 	HSyncControl	= 0x04,
197dd7cddfSDavid du Colombier 	PowerMgmnt	= 0x05,
207dd7cddfSDavid du Colombier 	PaletteControl	= 0x07,
217dd7cddfSDavid du Colombier 	SYSCLKControl	= 0x08,
227dd7cddfSDavid du Colombier 	PixelFormat	= 0x0A,
237dd7cddfSDavid du Colombier 	Pixel8Control	= 0x0B,
247dd7cddfSDavid du Colombier 	Pixel16Control	= 0x0C,
257dd7cddfSDavid du Colombier 	Pixel32Control	= 0x0E,
267dd7cddfSDavid du Colombier 	PLLControl1	= 0x10,
277dd7cddfSDavid du Colombier 	PLLControl2	= 0x11,
287dd7cddfSDavid du Colombier 	SYSCLKN		= 0x15,
297dd7cddfSDavid du Colombier 	SYSCLKM		= 0x16,
307dd7cddfSDavid du Colombier 	M0		= 0x20,
317dd7cddfSDavid du Colombier 	N0		= 0x21,
327dd7cddfSDavid du Colombier 	MiscControl1	= 0x70,
337dd7cddfSDavid du Colombier 	MiscControl2	= 0x71,
347dd7cddfSDavid du Colombier };
357dd7cddfSDavid du Colombier 
367dd7cddfSDavid du Colombier static void
clock(Vga * vga,Ctlr *,ulong fref,ulong maxpclk)377dd7cddfSDavid du Colombier clock(Vga* vga, Ctlr*, ulong fref, ulong maxpclk)
387dd7cddfSDavid du Colombier {
397dd7cddfSDavid du Colombier 	int d, mind;
407dd7cddfSDavid du Colombier 	ulong df, f, m, n, vrf;
417dd7cddfSDavid du Colombier 
427dd7cddfSDavid du Colombier 	mind = vga->f[0]+1;
437dd7cddfSDavid du Colombier 	for(df = 0; df < 4; df++){
447dd7cddfSDavid du Colombier 		for(m = 2; m < 64; m++){
457dd7cddfSDavid du Colombier 			for(n = 2; n < 32; n++){
467dd7cddfSDavid du Colombier 				f = (fref*(m+65))/n;
477dd7cddfSDavid du Colombier 				switch(df){
487dd7cddfSDavid du Colombier 				case 0:
497dd7cddfSDavid du Colombier 					vrf = fref/(n*2);
507dd7cddfSDavid du Colombier 					if(vrf > maxpclk/4 || vrf < 1000000)
517dd7cddfSDavid du Colombier 						continue;
527dd7cddfSDavid du Colombier 					f /= 8;
537dd7cddfSDavid du Colombier 					break;
547dd7cddfSDavid du Colombier 				case 1:
557dd7cddfSDavid du Colombier 					vrf = fref/(n*2);
567dd7cddfSDavid du Colombier 					if(vrf > maxpclk/2 || vrf < 1000000)
577dd7cddfSDavid du Colombier 						continue;
587dd7cddfSDavid du Colombier 					f /= 4;
597dd7cddfSDavid du Colombier 					break;
607dd7cddfSDavid du Colombier 				case 2:
617dd7cddfSDavid du Colombier 					vrf = fref/(n*2);
627dd7cddfSDavid du Colombier 					if(vrf > maxpclk || vrf < 1000000)
637dd7cddfSDavid du Colombier 						continue;
647dd7cddfSDavid du Colombier 					f /= 2;
657dd7cddfSDavid du Colombier 					break;
667dd7cddfSDavid du Colombier 				case 3:
677dd7cddfSDavid du Colombier 					vrf = fref/n;
687dd7cddfSDavid du Colombier 					if(vrf > maxpclk || vrf < 1000000)
697dd7cddfSDavid du Colombier 						continue;
707dd7cddfSDavid du Colombier 					break;
717dd7cddfSDavid du Colombier 				}
727dd7cddfSDavid du Colombier 				if(f > maxpclk)
737dd7cddfSDavid du Colombier 					continue;
747dd7cddfSDavid du Colombier 
757dd7cddfSDavid du Colombier 				d = vga->f[0] - f;
767dd7cddfSDavid du Colombier 				if(d < 0)
777dd7cddfSDavid du Colombier 					d = -d;
787dd7cddfSDavid du Colombier 				if(d <= mind){
797dd7cddfSDavid du Colombier 					vga->m[0] = m;
807dd7cddfSDavid du Colombier 					vga->n[0] = n;
817dd7cddfSDavid du Colombier 					vga->d[0] = df;
827dd7cddfSDavid du Colombier 					mind = d;
837dd7cddfSDavid du Colombier 				}
847dd7cddfSDavid du Colombier 			}
857dd7cddfSDavid du Colombier 		}
867dd7cddfSDavid du Colombier 	}
877dd7cddfSDavid du Colombier }
887dd7cddfSDavid du Colombier 
897dd7cddfSDavid du Colombier static void
init(Vga * vga,Ctlr * ctlr)907dd7cddfSDavid du Colombier init(Vga* vga, Ctlr* ctlr)
917dd7cddfSDavid du Colombier {
927dd7cddfSDavid du Colombier 	ulong fref, maxpclk;
937dd7cddfSDavid du Colombier 	char *p, *val;
947dd7cddfSDavid du Colombier 
957dd7cddfSDavid du Colombier 	/*
967dd7cddfSDavid du Colombier 	 * Part comes in at least a -170MHz speed-grade.
977dd7cddfSDavid du Colombier 	 */
987dd7cddfSDavid du Colombier 	maxpclk = 170000000;
997dd7cddfSDavid du Colombier 	if(p = strrchr(ctlr->name, '-'))
1007dd7cddfSDavid du Colombier 		maxpclk = strtoul(p+1, 0, 0) * 1000000;
1017dd7cddfSDavid du Colombier 
1027dd7cddfSDavid du Colombier 	/*
1037dd7cddfSDavid du Colombier 	 * If we don't already have a desired pclk,
1047dd7cddfSDavid du Colombier 	 * take it from the mode.
1057dd7cddfSDavid du Colombier 	 * Check it's within range.
1067dd7cddfSDavid du Colombier 	 */
1077dd7cddfSDavid du Colombier 	if(vga->f[0] == 0)
1087dd7cddfSDavid du Colombier 		vga->f[0] = vga->mode->frequency;
1097dd7cddfSDavid du Colombier 	if(vga->f[0] > maxpclk)
1107dd7cddfSDavid du Colombier 		error("%s: invalid pclk - %ld\n", ctlr->name, vga->f[0]);
1117dd7cddfSDavid du Colombier 	if(val = dbattr(vga->attr, "rgb524mnrefclk"))
1127dd7cddfSDavid du Colombier 		fref = strtol(val, 0, 0);
1137dd7cddfSDavid du Colombier 	else
1147dd7cddfSDavid du Colombier 		fref = RefFreq;
1157dd7cddfSDavid du Colombier 
1167dd7cddfSDavid du Colombier 	/*
1177dd7cddfSDavid du Colombier 	 * Initialise the PLL parameters.
1187dd7cddfSDavid du Colombier 	 * Use m/n pair 2.
1197dd7cddfSDavid du Colombier 	 */
1207dd7cddfSDavid du Colombier 	clock(vga, ctlr, fref, maxpclk);
1217dd7cddfSDavid du Colombier 	vga->i[0] = 2;
1227dd7cddfSDavid du Colombier 
1237dd7cddfSDavid du Colombier 	ctlr->flag |= Finit;
1247dd7cddfSDavid du Colombier }
1257dd7cddfSDavid du Colombier 
1267dd7cddfSDavid du Colombier static void
load(Vga * vga,Ctlr * ctlr)1277dd7cddfSDavid du Colombier load(Vga* vga, Ctlr* ctlr)
1287dd7cddfSDavid du Colombier {
1297dd7cddfSDavid du Colombier 	char *val;
1307dd7cddfSDavid du Colombier 	int hsyncdelay, x;
1317dd7cddfSDavid du Colombier 
1327dd7cddfSDavid du Colombier 	if(rgb524mnxi == nil && rgb524mnxo == nil)
1337dd7cddfSDavid du Colombier 		error("%s->load: no access routines\n", ctlr->name);
1347dd7cddfSDavid du Colombier 
1357dd7cddfSDavid du Colombier 	/*
1367dd7cddfSDavid du Colombier 	 * Set the m/n values for the desired frequency and
1377dd7cddfSDavid du Colombier 	 * set pixel control to use compatibility mode with
1387dd7cddfSDavid du Colombier 	 * internal frequency select using the specified set
1397dd7cddfSDavid du Colombier 	 * of m/n registers.
1407dd7cddfSDavid du Colombier 	 */
1417dd7cddfSDavid du Colombier 	rgb524mnxo(vga, M0+vga->i[0]*2, vga->d[0]<<6|vga->m[0]);
1427dd7cddfSDavid du Colombier 	rgb524mnxo(vga, N0+vga->i[0]*2, vga->n[0]);
1437dd7cddfSDavid du Colombier 	rgb524mnxo(vga, PLLControl2, vga->i[0]);
1447dd7cddfSDavid du Colombier 	rgb524mnxo(vga, PLLControl1, 0x03);
1457dd7cddfSDavid du Colombier 
1467dd7cddfSDavid du Colombier 	/*
1477dd7cddfSDavid du Colombier 	 * Enable pixel programming in MiscClock;
1487dd7cddfSDavid du Colombier 	 * nothing to do in MiscControl1;
1497dd7cddfSDavid du Colombier 	 * set internal PLL clock and !vga in MiscControl2;
1507dd7cddfSDavid du Colombier 	 */
1517dd7cddfSDavid du Colombier 	x = rgb524mnxi(vga, MiscClock) & ~0x01;
1527dd7cddfSDavid du Colombier 	x |= 0x01;
1537dd7cddfSDavid du Colombier 	rgb524mnxo(vga, MiscClock, x);
1547dd7cddfSDavid du Colombier 
1557dd7cddfSDavid du Colombier 	x = rgb524mnxi(vga, MiscControl2) & ~0x41;
1567dd7cddfSDavid du Colombier 	x |= 0x41;
1577dd7cddfSDavid du Colombier 	rgb524mnxo(vga, MiscControl2, x);
1587dd7cddfSDavid du Colombier 
1597dd7cddfSDavid du Colombier 	/*
1607dd7cddfSDavid du Colombier 	 * Syncs.
1617dd7cddfSDavid du Colombier 	 */
1627dd7cddfSDavid du Colombier 	x = 0;
1637dd7cddfSDavid du Colombier 	if(vga->mode->hsync == '+')
1647dd7cddfSDavid du Colombier 		x |= 0x10;
1657dd7cddfSDavid du Colombier 	if(vga->mode->vsync == '+')
1667dd7cddfSDavid du Colombier 		x |= 0x20;
1677dd7cddfSDavid du Colombier 	rgb524mnxo(vga, SyncControl, x);
1687dd7cddfSDavid du Colombier 	if(val = dbattr(vga->mode->attr, "hsyncdelay"))
1697dd7cddfSDavid du Colombier 		hsyncdelay = strtol(val, 0, 0);
1707dd7cddfSDavid du Colombier 	else switch(vga->mode->z){
1717dd7cddfSDavid du Colombier 	default:
1727dd7cddfSDavid du Colombier 	case 8:
1737dd7cddfSDavid du Colombier 		hsyncdelay = 1;
1747dd7cddfSDavid du Colombier 		break;
1757dd7cddfSDavid du Colombier 	case 15:
1767dd7cddfSDavid du Colombier 	case 16:
1777dd7cddfSDavid du Colombier 		hsyncdelay = 5;
1787dd7cddfSDavid du Colombier 		break;
1797dd7cddfSDavid du Colombier 	case 32:
1807dd7cddfSDavid du Colombier 		hsyncdelay = 7;
1817dd7cddfSDavid du Colombier 		break;
1827dd7cddfSDavid du Colombier 	}
1837dd7cddfSDavid du Colombier 	rgb524mnxo(vga, HSyncControl, hsyncdelay);
1847dd7cddfSDavid du Colombier 
1857dd7cddfSDavid du Colombier rgb524mnxo(vga, SYSCLKM, 0x50);
1867dd7cddfSDavid du Colombier rgb524mnxo(vga, SYSCLKN, 0x08);
1877dd7cddfSDavid du Colombier sleep(50);
1887dd7cddfSDavid du Colombier //rgb524mnxo(vga, SYSCLKM, 0x6F);
1897dd7cddfSDavid du Colombier //rgb524mnxo(vga, SYSCLKN, 0x0F);
1907dd7cddfSDavid du Colombier //sleep(500);
1917dd7cddfSDavid du Colombier 
1927dd7cddfSDavid du Colombier 	/*
1937dd7cddfSDavid du Colombier 	 * Set the palette for the desired format.
1947dd7cddfSDavid du Colombier 	 * ****NEEDS WORK FOR OTHER THAN 8-BITS****
1957dd7cddfSDavid du Colombier 	 */
1967dd7cddfSDavid du Colombier 	rgb524mnxo(vga, PaletteControl, 0x00);
1977dd7cddfSDavid du Colombier 	switch(vga->mode->z){
1987dd7cddfSDavid du Colombier 	case 8:
1997dd7cddfSDavid du Colombier 		rgb524mnxo(vga, PixelFormat, 0x03);
2007dd7cddfSDavid du Colombier 		rgb524mnxo(vga, Pixel8Control, 0x00);
2017dd7cddfSDavid du Colombier 		break;
2027dd7cddfSDavid du Colombier 	case 15:
2037dd7cddfSDavid du Colombier 		rgb524mnxo(vga, PixelFormat, 0x04);
2047dd7cddfSDavid du Colombier 		rgb524mnxo(vga, Pixel16Control, 0xC4);
2057dd7cddfSDavid du Colombier 	case 16:
2067dd7cddfSDavid du Colombier 		rgb524mnxo(vga, PixelFormat, 0x04);
2077dd7cddfSDavid du Colombier 		rgb524mnxo(vga, Pixel16Control, 0xC6);
2087dd7cddfSDavid du Colombier 		break;
2097dd7cddfSDavid du Colombier 	case 32:
2107dd7cddfSDavid du Colombier 		rgb524mnxo(vga, PixelFormat, 0x06);
2117dd7cddfSDavid du Colombier 		rgb524mnxo(vga, Pixel32Control, 0x03);
2127dd7cddfSDavid du Colombier 		break;
2137dd7cddfSDavid du Colombier 	}
2147dd7cddfSDavid du Colombier }
2157dd7cddfSDavid du Colombier 
2167dd7cddfSDavid du Colombier static void
dumpclock(Vga *,Ctlr * ctlr,ulong fref,ulong m,ulong n,char * name)2177dd7cddfSDavid du Colombier dumpclock(Vga*, Ctlr* ctlr, ulong fref, ulong m, ulong n, char* name)
2187dd7cddfSDavid du Colombier {
2197dd7cddfSDavid du Colombier 	ulong df, f;
2207dd7cddfSDavid du Colombier 
2217dd7cddfSDavid du Colombier 	df = (m>>6) & 0x03;
2227dd7cddfSDavid du Colombier 	m &= 0x3F;
2237dd7cddfSDavid du Colombier 	n &= 0x1F;
2247dd7cddfSDavid du Colombier 	if(m == 0 || n == 0)
2257dd7cddfSDavid du Colombier 		return;
2267dd7cddfSDavid du Colombier 	f = (fref*(m+65))/n;
2277dd7cddfSDavid du Colombier 	switch(df){
2287dd7cddfSDavid du Colombier 	case 0:
2297dd7cddfSDavid du Colombier 		f /= 8;
2307dd7cddfSDavid du Colombier 		break;
2317dd7cddfSDavid du Colombier 	case 1:
2327dd7cddfSDavid du Colombier 		f /= 4;
2337dd7cddfSDavid du Colombier 		break;
2347dd7cddfSDavid du Colombier 	case 2:
2357dd7cddfSDavid du Colombier 		f /= 2;
2367dd7cddfSDavid du Colombier 		break;
2377dd7cddfSDavid du Colombier 	case 3:
2387dd7cddfSDavid du Colombier 		break;
2397dd7cddfSDavid du Colombier 	}
2407dd7cddfSDavid du Colombier 	printitem(ctlr->name, name);
2417dd7cddfSDavid du Colombier 	Bprint(&stdout, "%12lud\n", f);
2427dd7cddfSDavid du Colombier }
2437dd7cddfSDavid du Colombier 
2447dd7cddfSDavid du Colombier static void
dump(Vga * vga,Ctlr * ctlr)2457dd7cddfSDavid du Colombier dump(Vga* vga, Ctlr* ctlr)
2467dd7cddfSDavid du Colombier {
2477dd7cddfSDavid du Colombier 	int i;
2487dd7cddfSDavid du Colombier 	char *val;
2497dd7cddfSDavid du Colombier 	uchar x[256];
2507dd7cddfSDavid du Colombier 	ulong fref, fs;
2517dd7cddfSDavid du Colombier 
2527dd7cddfSDavid du Colombier 	if(rgb524mnxi == nil && rgb524mnxo == nil)
2537dd7cddfSDavid du Colombier 		error("%s->dump: no access routines\n", ctlr->name);
2547dd7cddfSDavid du Colombier 
2557dd7cddfSDavid du Colombier 	printitem(ctlr->name, "index00");
2567dd7cddfSDavid du Colombier 	for(i = 0x00; i < 0x0F; i++){
2577dd7cddfSDavid du Colombier 		x[i] = rgb524mnxi(vga, i);
2587dd7cddfSDavid du Colombier 		printreg(x[i]);
2597dd7cddfSDavid du Colombier 	}
2607dd7cddfSDavid du Colombier 	printitem(ctlr->name, "index10");
2617dd7cddfSDavid du Colombier 	for(i = 0x10; i < 0x18; i++){
2627dd7cddfSDavid du Colombier 		x[i] = rgb524mnxi(vga, i);
2637dd7cddfSDavid du Colombier 		printreg(x[i]);
2647dd7cddfSDavid du Colombier 	}
2657dd7cddfSDavid du Colombier 	printitem(ctlr->name, "index20");
2667dd7cddfSDavid du Colombier 	for(i = 0x20; i < 0x30; i++){
2677dd7cddfSDavid du Colombier 		x[i] = rgb524mnxi(vga, i);
2687dd7cddfSDavid du Colombier 		printreg(x[i]);
2697dd7cddfSDavid du Colombier 	}
2707dd7cddfSDavid du Colombier 	printitem(ctlr->name, "index30");
2717dd7cddfSDavid du Colombier 	for(i = 0x30; i < 0x39; i++){
2727dd7cddfSDavid du Colombier 		x[i] = rgb524mnxi(vga, i);
2737dd7cddfSDavid du Colombier 		printreg(x[i]);
2747dd7cddfSDavid du Colombier 	}
2757dd7cddfSDavid du Colombier 	printitem(ctlr->name, "index40");
2767dd7cddfSDavid du Colombier 	for(i = 0x40; i < 0x49; i++){
2777dd7cddfSDavid du Colombier 		x[i] = rgb524mnxi(vga, i);
2787dd7cddfSDavid du Colombier 		printreg(x[i]);
2797dd7cddfSDavid du Colombier 	}
2807dd7cddfSDavid du Colombier 	printitem(ctlr->name, "index60");
2817dd7cddfSDavid du Colombier 	for(i = 0x60; i < 0x63; i++){
2827dd7cddfSDavid du Colombier 		x[i] = rgb524mnxi(vga, i);
2837dd7cddfSDavid du Colombier 		printreg(x[i]);
2847dd7cddfSDavid du Colombier 	}
2857dd7cddfSDavid du Colombier 	printitem(ctlr->name, "index70");
2867dd7cddfSDavid du Colombier 	for(i = 0x70; i < 0x73; i++){
2877dd7cddfSDavid du Colombier 		x[i] = rgb524mnxi(vga, i);
2887dd7cddfSDavid du Colombier 		printreg(x[i]);
2897dd7cddfSDavid du Colombier 	}
2907dd7cddfSDavid du Colombier 	printitem(ctlr->name, "index8E");
2917dd7cddfSDavid du Colombier 	for(i = 0x8E; i < 0x92; i++){
2927dd7cddfSDavid du Colombier 		x[i] = rgb524mnxi(vga, i);
2937dd7cddfSDavid du Colombier 		printreg(x[i]);
2947dd7cddfSDavid du Colombier 	}
2957dd7cddfSDavid du Colombier 
2967dd7cddfSDavid du Colombier 	if(val = dbattr(vga->attr, "rgb524mnrefclk"))
2977dd7cddfSDavid du Colombier 		fref = strtol(val, 0, 0);
2987dd7cddfSDavid du Colombier 	else
2997dd7cddfSDavid du Colombier 		fref = RefFreq;
3007dd7cddfSDavid du Colombier 	if(!(x[SYSCLKControl] & 0x04))
3017dd7cddfSDavid du Colombier 		dumpclock(vga, ctlr, fref, x[0x16], x[0x15], "sysclk");
3027dd7cddfSDavid du Colombier 	fs = x[PLLControl1] & 0x07;
3037dd7cddfSDavid du Colombier 	if(fs == 0x01 || fs == 0x03){
3047dd7cddfSDavid du Colombier 		if(fs == 0x01)
3057dd7cddfSDavid du Colombier 			i = ((vga->misc>>2) & 0x03)*2;
3067dd7cddfSDavid du Colombier 		else
3077dd7cddfSDavid du Colombier 			i = x[PLLControl2] & 0x07;
3087dd7cddfSDavid du Colombier 		dumpclock(vga, ctlr, fref, x[M0+i*2], x[N0+i*2], "pllclk");
3097dd7cddfSDavid du Colombier 	}
3107dd7cddfSDavid du Colombier }
3117dd7cddfSDavid du Colombier 
3127dd7cddfSDavid du Colombier Ctlr rgb524mn = {
3137dd7cddfSDavid du Colombier 	"rgb524mn",			/* name */
3147dd7cddfSDavid du Colombier 	0,				/* snarf */
3157dd7cddfSDavid du Colombier 	0,				/* options */
3167dd7cddfSDavid du Colombier 	init,				/* init */
3177dd7cddfSDavid du Colombier 	load,				/* load */
3187dd7cddfSDavid du Colombier 	dump,				/* dump */
3197dd7cddfSDavid du Colombier };
320