xref: /plan9/sys/src/cmd/aux/vga/tvp3026clock.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 #define SCALE(f)	((f)/10)		/* could be /10 */
97dd7cddfSDavid du Colombier 
107dd7cddfSDavid du Colombier static void
init(Vga * vga,Ctlr * ctlr)117dd7cddfSDavid du Colombier init(Vga* vga, Ctlr* ctlr)
127dd7cddfSDavid du Colombier {
137dd7cddfSDavid du Colombier 	int f, k;
147dd7cddfSDavid du Colombier 	ulong fmin, fvco, m, n, p, q;
157dd7cddfSDavid du Colombier 	double z;
167dd7cddfSDavid du Colombier 
177dd7cddfSDavid du Colombier 	if(ctlr->flag & Finit)
187dd7cddfSDavid du Colombier 		return;
197dd7cddfSDavid du Colombier 
207dd7cddfSDavid du Colombier 	if(vga->f[0] == 0)
217dd7cddfSDavid du Colombier 		vga->f[0] = vga->mode->frequency;
227dd7cddfSDavid du Colombier 	vga->misc &= ~0x0C;
23*9a747e4fSDavid du Colombier 	if(vga->f[0] == VgaFreq0){
24*9a747e4fSDavid du Colombier 		/* nothing to do */;
25*9a747e4fSDavid du Colombier 	}
267dd7cddfSDavid du Colombier 	else if(vga->f[0] == VgaFreq1)
277dd7cddfSDavid du Colombier 		vga->misc |= 0x04;
287dd7cddfSDavid du Colombier 	else
297dd7cddfSDavid du Colombier 		vga->misc |= 0x0C;
307dd7cddfSDavid du Colombier 
317dd7cddfSDavid du Colombier 	/*
327dd7cddfSDavid du Colombier 	 * Look for values of n, d and p that give
337dd7cddfSDavid du Colombier 	 * the least error for
347dd7cddfSDavid du Colombier 	 *	Fvco = 8*RefFreq*(65-m)/(65-n)
357dd7cddfSDavid du Colombier 	 *	Fpll = Fvco/2**p
367dd7cddfSDavid du Colombier 	 * N and m are 6 bits, p is 2 bits. Constraints:
377dd7cddfSDavid du Colombier 	 *	110MHz <= Fvco <= 250MHz
387dd7cddfSDavid du Colombier 	 *	40 <= n <= 62
397dd7cddfSDavid du Colombier 	 *	 1 <= m <= 62
407dd7cddfSDavid du Colombier 	 *	 0 <= p <=  3
417dd7cddfSDavid du Colombier 	 * Should try to minimise n, m.
427dd7cddfSDavid du Colombier 	 *
437dd7cddfSDavid du Colombier 	 * There's nothing like brute force and ignorance.
447dd7cddfSDavid du Colombier 	 */
457dd7cddfSDavid du Colombier 	fmin = vga->f[0];
467dd7cddfSDavid du Colombier 	vga->m[0] = 0x15;
477dd7cddfSDavid du Colombier 	vga->n[0] = 0x18;
487dd7cddfSDavid du Colombier 	vga->p[0] = 3;
497dd7cddfSDavid du Colombier 	for(m = 62; m > 0; m--){
507dd7cddfSDavid du Colombier 		for(n = 62; n >= 40; n--){
517dd7cddfSDavid du Colombier 			fvco = 8*SCALE(RefFreq)*(65-m)/(65-n);
527dd7cddfSDavid du Colombier 			if(fvco < SCALE(110000000) || fvco > SCALE(250000000))
537dd7cddfSDavid du Colombier 				continue;
547dd7cddfSDavid du Colombier 			for(p = 0; p < 4; p++){
557dd7cddfSDavid du Colombier 				f = SCALE(vga->f[0]) - (fvco>>p);
567dd7cddfSDavid du Colombier 				if(f < 0)
577dd7cddfSDavid du Colombier 					f = -f;
587dd7cddfSDavid du Colombier 				if(f < fmin){
597dd7cddfSDavid du Colombier 					fmin = f;
607dd7cddfSDavid du Colombier 					vga->m[0] = m;
617dd7cddfSDavid du Colombier 					vga->n[0] = n;
627dd7cddfSDavid du Colombier 					vga->p[0] = p;
637dd7cddfSDavid du Colombier 				}
647dd7cddfSDavid du Colombier 			}
657dd7cddfSDavid du Colombier 		}
667dd7cddfSDavid du Colombier 	}
677dd7cddfSDavid du Colombier 
687dd7cddfSDavid du Colombier 	/*
697dd7cddfSDavid du Colombier 	 * Now the loop clock:
707dd7cddfSDavid du Colombier 	 * 	m is fixed;
717dd7cddfSDavid du Colombier 	 *	calculate n;
727dd7cddfSDavid du Colombier 	 *	set z to the lower bound (110MHz) and calculate p and q.
737dd7cddfSDavid du Colombier 	 */
747dd7cddfSDavid du Colombier 	vga->m[1] = 61;
757dd7cddfSDavid du Colombier 	if(ctlr->flag & Uenhanced)
767dd7cddfSDavid du Colombier 		k = 64/8;
777dd7cddfSDavid du Colombier 	else
787dd7cddfSDavid du Colombier 		k = 8/8;
797dd7cddfSDavid du Colombier 	n = 65 - 4*k;
807dd7cddfSDavid du Colombier 	fvco = (8*RefFreq*(65-vga->m[0]))/(65-vga->n[0]);
817dd7cddfSDavid du Colombier 	vga->f[1] = fvco;
827dd7cddfSDavid du Colombier 	z = 110.0*(65-n)/(4*(fvco/1000000.0)*k);
837dd7cddfSDavid du Colombier 	if(z <= 16){
847dd7cddfSDavid du Colombier 		for(p = 0; p < 4; p++){
857dd7cddfSDavid du Colombier 			if(1<<(p+1) > z)
867dd7cddfSDavid du Colombier 				break;
877dd7cddfSDavid du Colombier 		}
887dd7cddfSDavid du Colombier 		q = 0;
897dd7cddfSDavid du Colombier 	}
907dd7cddfSDavid du Colombier 	else{
917dd7cddfSDavid du Colombier 		p = 3;
927dd7cddfSDavid du Colombier 		q = (z - 16)/16 + 1;
937dd7cddfSDavid du Colombier 	}
947dd7cddfSDavid du Colombier 	vga->n[1] = n;
957dd7cddfSDavid du Colombier 	vga->p[1] = p;
967dd7cddfSDavid du Colombier 	vga->q[1] = q;
977dd7cddfSDavid du Colombier 
987dd7cddfSDavid du Colombier 	ctlr->flag |= Finit;
997dd7cddfSDavid du Colombier }
1007dd7cddfSDavid du Colombier 
1017dd7cddfSDavid du Colombier Ctlr tvp3026clock = {
1027dd7cddfSDavid du Colombier 	"tvp3026clock",			/* name */
1037dd7cddfSDavid du Colombier 	0,				/* snarf */
1047dd7cddfSDavid du Colombier 	0,				/* options */
1057dd7cddfSDavid du Colombier 	init,				/* init */
1067dd7cddfSDavid du Colombier 	0,				/* load */
1077dd7cddfSDavid du Colombier 	0,				/* dump */
1087dd7cddfSDavid du Colombier };
109