xref: /plan9/sys/src/cmd/aux/vga/icd2061a.c (revision 9a747e4fd48b9f4522c70c07e8f882a15030f964)
1219b2ee8SDavid du Colombier /*
2219b2ee8SDavid du Colombier  * IC Designs ICD2061A Dual Programmable Graphics Clock Generator.
3219b2ee8SDavid du Colombier  */
4219b2ee8SDavid du Colombier #include <u.h>
5219b2ee8SDavid du Colombier #include <libc.h>
67dd7cddfSDavid du Colombier #include <bio.h>
7219b2ee8SDavid du Colombier 
8*9a747e4fSDavid du Colombier #include "pci.h"
9219b2ee8SDavid du Colombier #include "vga.h"
10219b2ee8SDavid du Colombier 
11219b2ee8SDavid du Colombier enum {
12219b2ee8SDavid du Colombier 	Prescale	= 2,			/* P counter prescale (default) */
13219b2ee8SDavid du Colombier 	NIndex		= 14,			/* number of index field values */
14219b2ee8SDavid du Colombier };
15219b2ee8SDavid du Colombier 
16219b2ee8SDavid du Colombier /*
17219b2ee8SDavid du Colombier  * For an index value of x, the appropriate VCO range
18219b2ee8SDavid du Colombier  * is >= index[x] && <= index[x+1]. The higher index is
19219b2ee8SDavid du Colombier  * prefered if VCO is on a boundary.
20219b2ee8SDavid du Colombier  */
21219b2ee8SDavid du Colombier static ulong index[NIndex] = {
22219b2ee8SDavid du Colombier 	 50000000,
23219b2ee8SDavid du Colombier 	 51000000,
24219b2ee8SDavid du Colombier 	 53200000,
25219b2ee8SDavid du Colombier 	 58500000,
26219b2ee8SDavid du Colombier 	 60700000,
27219b2ee8SDavid du Colombier 	 64400000,
28219b2ee8SDavid du Colombier 	 66800000,
29219b2ee8SDavid du Colombier 	 73500000,
30219b2ee8SDavid du Colombier 	 75600000,
31219b2ee8SDavid du Colombier 	 80900000,
32219b2ee8SDavid du Colombier 	 83200000,
33219b2ee8SDavid du Colombier 	 91500000,
34219b2ee8SDavid du Colombier 	100000000,
35219b2ee8SDavid du Colombier 	120000000,
36219b2ee8SDavid du Colombier };
37219b2ee8SDavid du Colombier 
38219b2ee8SDavid du Colombier static void
init(Vga * vga,Ctlr * ctlr)39219b2ee8SDavid du Colombier init(Vga* vga, Ctlr* ctlr)
40219b2ee8SDavid du Colombier {
41219b2ee8SDavid du Colombier 	int f;
42219b2ee8SDavid du Colombier 	ulong d, dmax, fmin, n;
43219b2ee8SDavid du Colombier 
44219b2ee8SDavid du Colombier 	if(ctlr->flag & Finit)
45219b2ee8SDavid du Colombier 		return;
46219b2ee8SDavid du Colombier 
477dd7cddfSDavid du Colombier 	if(vga->f[0] == 0)
487dd7cddfSDavid du Colombier 		vga->f[0] = vga->mode->frequency;
497dd7cddfSDavid du Colombier 
507dd7cddfSDavid du Colombier 	if(vga->mode->z > 8)
517dd7cddfSDavid du Colombier 		error("depth %d not supported\n", vga->mode->z);
52219b2ee8SDavid du Colombier 
53219b2ee8SDavid du Colombier 	/*
54219b2ee8SDavid du Colombier 	 * Post-VCO divisor. Constraint:
55219b2ee8SDavid du Colombier 	 * 	50MHz <= vga->f <= 120MHz
56219b2ee8SDavid du Colombier 	 */
577dd7cddfSDavid du Colombier 	for(vga->p[0] = 0; vga->f[0] <= 50000000; vga->p[0]++)
587dd7cddfSDavid du Colombier 		vga->f[0] <<= 1;
59219b2ee8SDavid du Colombier 
60219b2ee8SDavid du Colombier 	/*
61219b2ee8SDavid du Colombier 	 * Determine index.
62219b2ee8SDavid du Colombier 	 */
637dd7cddfSDavid du Colombier 	for(vga->i[0] = NIndex-1; vga->f[0] < index[vga->i[0]] && vga->i[0]; vga->i[0]--)
64219b2ee8SDavid du Colombier 		;
65219b2ee8SDavid du Colombier 
66219b2ee8SDavid du Colombier 	/*
67219b2ee8SDavid du Colombier 	 * Denominator. Constraints:
687dd7cddfSDavid du Colombier 	 *	200KHz <= RefFreq/d <= 1MHz
69219b2ee8SDavid du Colombier 	 * and
70219b2ee8SDavid du Colombier 	 *	3 <= d <= 129
71219b2ee8SDavid du Colombier 	 *
72219b2ee8SDavid du Colombier 	 * Numerator. Constraint:
73219b2ee8SDavid du Colombier 	 *	4 <= n <= 130
74219b2ee8SDavid du Colombier 	 */
757dd7cddfSDavid du Colombier 	d = RefFreq/1000000 > 3 ? RefFreq/1000000: 3;
767dd7cddfSDavid du Colombier 	dmax = RefFreq/200000 < 129 ? RefFreq/200000: 129;
77219b2ee8SDavid du Colombier 
78219b2ee8SDavid du Colombier 	/*
79219b2ee8SDavid du Colombier 	 * Now look for values of p and q that give
80219b2ee8SDavid du Colombier 	 * the least error for
817dd7cddfSDavid du Colombier 	 *	vga->f = (Prescale*RefFreq*n/d);
82219b2ee8SDavid du Colombier 	 */
837dd7cddfSDavid du Colombier 	vga->d[0] = d;
847dd7cddfSDavid du Colombier 	vga->n[0] = 4;
857dd7cddfSDavid du Colombier 	for(fmin = vga->f[0]; d <= dmax; d++){
86219b2ee8SDavid du Colombier 		for(n = 4; n <= 130; n++){
877dd7cddfSDavid du Colombier 			f = vga->f[0] - (Prescale*RefFreq*n/d);
88219b2ee8SDavid du Colombier 			if(f < 0)
89219b2ee8SDavid du Colombier 				f = -f;
90219b2ee8SDavid du Colombier 			if(f < fmin){
91219b2ee8SDavid du Colombier 				fmin = f;
927dd7cddfSDavid du Colombier 				vga->d[0] = d;
937dd7cddfSDavid du Colombier 				vga->n[0] = n;
94219b2ee8SDavid du Colombier 			}
95219b2ee8SDavid du Colombier 		}
96219b2ee8SDavid du Colombier 	}
97219b2ee8SDavid du Colombier 
98219b2ee8SDavid du Colombier 	/*
99219b2ee8SDavid du Colombier 	 * The serial word to be loaded into the icd2061a is
100219b2ee8SDavid du Colombier 	 *	(2<<21)|(vga->i<<17)|((vga->n)<<10)|(vga->p<<7)|vga->d
101219b2ee8SDavid du Colombier 	 * Always select ICD2061A REG2.
102219b2ee8SDavid du Colombier 	 */
1037dd7cddfSDavid du Colombier 	vga->f[0] = (Prescale*RefFreq*vga->n[0]/vga->d[0]);
1047dd7cddfSDavid du Colombier 	vga->d[0] -= 2;
1057dd7cddfSDavid du Colombier 	vga->n[0] -= 3;
106219b2ee8SDavid du Colombier 
107219b2ee8SDavid du Colombier 	ctlr->flag |= Finit;
108219b2ee8SDavid du Colombier }
109219b2ee8SDavid du Colombier 
110219b2ee8SDavid du Colombier Ctlr icd2061a = {
111219b2ee8SDavid du Colombier 	"icd2061a",
112219b2ee8SDavid du Colombier 	0,				/* snarf */
113219b2ee8SDavid du Colombier 	0,				/* options */
114219b2ee8SDavid du Colombier 	init,				/* init */
115219b2ee8SDavid du Colombier 	0,				/* load */
116219b2ee8SDavid du Colombier 	0,				/* dump */
117219b2ee8SDavid du Colombier };
118