xref: /plan9/sys/src/cmd/aux/vga/tvp3025clock.c (revision 9a747e4fd48b9f4522c70c07e8f882a15030f964)
1 #include <u.h>
2 #include <libc.h>
3 #include <bio.h>
4 
5 #include "pci.h"
6 #include "vga.h"
7 
8 #define SCALE(f)	((f)/1)		/* could be /10 */
9 
10 static void
init(Vga * vga,Ctlr * ctlr)11 init(Vga* vga, Ctlr* ctlr)
12 {
13 	int f;
14 	ulong d, dmax, fmin, fvco, n, nmax, p;
15 
16 	if(ctlr->flag & Finit)
17 		return;
18 
19 	if(vga->f[0] == 0)
20 		vga->f[0] = vga->mode->frequency;
21 
22 	/*
23 	 * Look for values of n, d and p that give
24 	 * the least error for
25 	 *	Fvco = RefFreq*((n+2)*8)/(d+2)
26 	 *	Fpll = Fvco/2**p
27 	 * N and d are 7-bits, p is 2-bits. Constraints:
28 	 *	RefFreq/(n+2) > 1MHz
29 	 *	110MHz <= Fvco <= 220MHz
30 	 *	n, d >= 1
31 	 * Should try to minimise n, d.
32 	 *
33 	 * There's nothing like brute force and ignorance.
34 	 */
35 	fmin = vga->f[0];
36 	vga->d[0] = 6;
37 	vga->n[0] = 5;
38 	vga->p[0] = 2;
39 	dmax = (RefFreq/1000000)-2;
40 	for(d = 1; d < dmax; d++){
41 		/*
42 		 * Calculate an upper bound on n
43 		 * to satisfy the condition
44 		 *	Fvco <= 220MHz
45 		 * This will hopefully prevent arithmetic
46 		 * overflow.
47 		 */
48 		nmax = ((220000000+RefFreq)*(d+2))/(RefFreq*8) - 2;
49 		for(n = 1; n < nmax; n++){
50 			fvco = SCALE(RefFreq)*((n+2)*8)/(d+2);
51 			if(fvco < SCALE(110000000) || fvco > SCALE(220000000))
52 				continue;
53 			for(p = 1; p < 4; p++){
54 				f = SCALE(vga->f[0]) - (fvco>>p);
55 				if(f < 0)
56 					f = -f;
57 				if(f < fmin){
58 					fmin = f;
59 					vga->d[0] = d;
60 					vga->n[0] = n;
61 					vga->p[0] = p;
62 				}
63 			}
64 		}
65 	}
66 
67 	ctlr->flag |= Finit;
68 }
69 
70 Ctlr tvp3025clock = {
71 	"tvp3025clock",			/* name */
72 	0,				/* snarf */
73 	0,				/* options */
74 	init,				/* init */
75 	0,				/* load */
76 	0,				/* dump */
77 };
78