xref: /plan9/sys/src/cmd/aux/vga/tvp3026clock.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)/10)		/* could be /10 */
9 
10 static void
init(Vga * vga,Ctlr * ctlr)11 init(Vga* vga, Ctlr* ctlr)
12 {
13 	int f, k;
14 	ulong fmin, fvco, m, n, p, q;
15 	double z;
16 
17 	if(ctlr->flag & Finit)
18 		return;
19 
20 	if(vga->f[0] == 0)
21 		vga->f[0] = vga->mode->frequency;
22 	vga->misc &= ~0x0C;
23 	if(vga->f[0] == VgaFreq0){
24 		/* nothing to do */;
25 	}
26 	else if(vga->f[0] == VgaFreq1)
27 		vga->misc |= 0x04;
28 	else
29 		vga->misc |= 0x0C;
30 
31 	/*
32 	 * Look for values of n, d and p that give
33 	 * the least error for
34 	 *	Fvco = 8*RefFreq*(65-m)/(65-n)
35 	 *	Fpll = Fvco/2**p
36 	 * N and m are 6 bits, p is 2 bits. Constraints:
37 	 *	110MHz <= Fvco <= 250MHz
38 	 *	40 <= n <= 62
39 	 *	 1 <= m <= 62
40 	 *	 0 <= p <=  3
41 	 * Should try to minimise n, m.
42 	 *
43 	 * There's nothing like brute force and ignorance.
44 	 */
45 	fmin = vga->f[0];
46 	vga->m[0] = 0x15;
47 	vga->n[0] = 0x18;
48 	vga->p[0] = 3;
49 	for(m = 62; m > 0; m--){
50 		for(n = 62; n >= 40; n--){
51 			fvco = 8*SCALE(RefFreq)*(65-m)/(65-n);
52 			if(fvco < SCALE(110000000) || fvco > SCALE(250000000))
53 				continue;
54 			for(p = 0; p < 4; p++){
55 				f = SCALE(vga->f[0]) - (fvco>>p);
56 				if(f < 0)
57 					f = -f;
58 				if(f < fmin){
59 					fmin = f;
60 					vga->m[0] = m;
61 					vga->n[0] = n;
62 					vga->p[0] = p;
63 				}
64 			}
65 		}
66 	}
67 
68 	/*
69 	 * Now the loop clock:
70 	 * 	m is fixed;
71 	 *	calculate n;
72 	 *	set z to the lower bound (110MHz) and calculate p and q.
73 	 */
74 	vga->m[1] = 61;
75 	if(ctlr->flag & Uenhanced)
76 		k = 64/8;
77 	else
78 		k = 8/8;
79 	n = 65 - 4*k;
80 	fvco = (8*RefFreq*(65-vga->m[0]))/(65-vga->n[0]);
81 	vga->f[1] = fvco;
82 	z = 110.0*(65-n)/(4*(fvco/1000000.0)*k);
83 	if(z <= 16){
84 		for(p = 0; p < 4; p++){
85 			if(1<<(p+1) > z)
86 				break;
87 		}
88 		q = 0;
89 	}
90 	else{
91 		p = 3;
92 		q = (z - 16)/16 + 1;
93 	}
94 	vga->n[1] = n;
95 	vga->p[1] = p;
96 	vga->q[1] = q;
97 
98 	ctlr->flag |= Finit;
99 }
100 
101 Ctlr tvp3026clock = {
102 	"tvp3026clock",			/* name */
103 	0,				/* snarf */
104 	0,				/* options */
105 	init,				/* init */
106 	0,				/* load */
107 	0,				/* dump */
108 };
109