xref: /plan9/sys/src/cmd/aux/vga/tvp3025clock.c (revision 9a747e4fd48b9f4522c70c07e8f882a15030f964)
1219b2ee8SDavid du Colombier #include <u.h>
2219b2ee8SDavid du Colombier #include <libc.h>
37dd7cddfSDavid du Colombier #include <bio.h>
4219b2ee8SDavid du Colombier 
5*9a747e4fSDavid du Colombier #include "pci.h"
6219b2ee8SDavid du Colombier #include "vga.h"
7219b2ee8SDavid du Colombier 
8219b2ee8SDavid du Colombier #define SCALE(f)	((f)/1)		/* could be /10 */
9219b2ee8SDavid du Colombier 
10219b2ee8SDavid du Colombier static void
init(Vga * vga,Ctlr * ctlr)11219b2ee8SDavid du Colombier init(Vga* vga, Ctlr* ctlr)
12219b2ee8SDavid du Colombier {
13219b2ee8SDavid du Colombier 	int f;
14219b2ee8SDavid du Colombier 	ulong d, dmax, fmin, fvco, n, nmax, p;
15219b2ee8SDavid du Colombier 
16219b2ee8SDavid du Colombier 	if(ctlr->flag & Finit)
17219b2ee8SDavid du Colombier 		return;
18219b2ee8SDavid du Colombier 
197dd7cddfSDavid du Colombier 	if(vga->f[0] == 0)
207dd7cddfSDavid du Colombier 		vga->f[0] = vga->mode->frequency;
21219b2ee8SDavid du Colombier 
22219b2ee8SDavid du Colombier 	/*
23219b2ee8SDavid du Colombier 	 * Look for values of n, d and p that give
24219b2ee8SDavid du Colombier 	 * the least error for
257dd7cddfSDavid du Colombier 	 *	Fvco = RefFreq*((n+2)*8)/(d+2)
26219b2ee8SDavid du Colombier 	 *	Fpll = Fvco/2**p
27219b2ee8SDavid du Colombier 	 * N and d are 7-bits, p is 2-bits. Constraints:
287dd7cddfSDavid du Colombier 	 *	RefFreq/(n+2) > 1MHz
29219b2ee8SDavid du Colombier 	 *	110MHz <= Fvco <= 220MHz
30219b2ee8SDavid du Colombier 	 *	n, d >= 1
31219b2ee8SDavid du Colombier 	 * Should try to minimise n, d.
32219b2ee8SDavid du Colombier 	 *
33219b2ee8SDavid du Colombier 	 * There's nothing like brute force and ignorance.
34219b2ee8SDavid du Colombier 	 */
357dd7cddfSDavid du Colombier 	fmin = vga->f[0];
367dd7cddfSDavid du Colombier 	vga->d[0] = 6;
377dd7cddfSDavid du Colombier 	vga->n[0] = 5;
387dd7cddfSDavid du Colombier 	vga->p[0] = 2;
397dd7cddfSDavid du Colombier 	dmax = (RefFreq/1000000)-2;
40219b2ee8SDavid du Colombier 	for(d = 1; d < dmax; d++){
41219b2ee8SDavid du Colombier 		/*
42219b2ee8SDavid du Colombier 		 * Calculate an upper bound on n
43219b2ee8SDavid du Colombier 		 * to satisfy the condition
44219b2ee8SDavid du Colombier 		 *	Fvco <= 220MHz
45219b2ee8SDavid du Colombier 		 * This will hopefully prevent arithmetic
46219b2ee8SDavid du Colombier 		 * overflow.
47219b2ee8SDavid du Colombier 		 */
487dd7cddfSDavid du Colombier 		nmax = ((220000000+RefFreq)*(d+2))/(RefFreq*8) - 2;
49219b2ee8SDavid du Colombier 		for(n = 1; n < nmax; n++){
507dd7cddfSDavid du Colombier 			fvco = SCALE(RefFreq)*((n+2)*8)/(d+2);
51219b2ee8SDavid du Colombier 			if(fvco < SCALE(110000000) || fvco > SCALE(220000000))
52219b2ee8SDavid du Colombier 				continue;
53219b2ee8SDavid du Colombier 			for(p = 1; p < 4; p++){
547dd7cddfSDavid du Colombier 				f = SCALE(vga->f[0]) - (fvco>>p);
55219b2ee8SDavid du Colombier 				if(f < 0)
56219b2ee8SDavid du Colombier 					f = -f;
57219b2ee8SDavid du Colombier 				if(f < fmin){
58219b2ee8SDavid du Colombier 					fmin = f;
597dd7cddfSDavid du Colombier 					vga->d[0] = d;
607dd7cddfSDavid du Colombier 					vga->n[0] = n;
617dd7cddfSDavid du Colombier 					vga->p[0] = p;
62219b2ee8SDavid du Colombier 				}
63219b2ee8SDavid du Colombier 			}
64219b2ee8SDavid du Colombier 		}
65219b2ee8SDavid du Colombier 	}
66219b2ee8SDavid du Colombier 
67219b2ee8SDavid du Colombier 	ctlr->flag |= Finit;
68219b2ee8SDavid du Colombier }
69219b2ee8SDavid du Colombier 
70219b2ee8SDavid du Colombier Ctlr tvp3025clock = {
71219b2ee8SDavid du Colombier 	"tvp3025clock",			/* name */
72219b2ee8SDavid du Colombier 	0,				/* snarf */
73219b2ee8SDavid du Colombier 	0,				/* options */
74219b2ee8SDavid du Colombier 	init,				/* init */
757dd7cddfSDavid du Colombier 	0,				/* load */
76219b2ee8SDavid du Colombier 	0,				/* dump */
77219b2ee8SDavid du Colombier };
78