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