1 /*
2 * IC Designs ICD2061A Dual Programmable Graphics Clock Generator.
3 */
4 #include <u.h>
5 #include <libc.h>
6 #include <bio.h>
7
8 #include "pci.h"
9 #include "vga.h"
10
11 enum {
12 Prescale = 2, /* P counter prescale (default) */
13 NIndex = 14, /* number of index field values */
14 };
15
16 /*
17 * For an index value of x, the appropriate VCO range
18 * is >= index[x] && <= index[x+1]. The higher index is
19 * prefered if VCO is on a boundary.
20 */
21 static ulong index[NIndex] = {
22 50000000,
23 51000000,
24 53200000,
25 58500000,
26 60700000,
27 64400000,
28 66800000,
29 73500000,
30 75600000,
31 80900000,
32 83200000,
33 91500000,
34 100000000,
35 120000000,
36 };
37
38 static void
init(Vga * vga,Ctlr * ctlr)39 init(Vga* vga, Ctlr* ctlr)
40 {
41 int f;
42 ulong d, dmax, fmin, n;
43
44 if(ctlr->flag & Finit)
45 return;
46
47 if(vga->f[0] == 0)
48 vga->f[0] = vga->mode->frequency;
49
50 if(vga->mode->z > 8)
51 error("depth %d not supported\n", vga->mode->z);
52
53 /*
54 * Post-VCO divisor. Constraint:
55 * 50MHz <= vga->f <= 120MHz
56 */
57 for(vga->p[0] = 0; vga->f[0] <= 50000000; vga->p[0]++)
58 vga->f[0] <<= 1;
59
60 /*
61 * Determine index.
62 */
63 for(vga->i[0] = NIndex-1; vga->f[0] < index[vga->i[0]] && vga->i[0]; vga->i[0]--)
64 ;
65
66 /*
67 * Denominator. Constraints:
68 * 200KHz <= RefFreq/d <= 1MHz
69 * and
70 * 3 <= d <= 129
71 *
72 * Numerator. Constraint:
73 * 4 <= n <= 130
74 */
75 d = RefFreq/1000000 > 3 ? RefFreq/1000000: 3;
76 dmax = RefFreq/200000 < 129 ? RefFreq/200000: 129;
77
78 /*
79 * Now look for values of p and q that give
80 * the least error for
81 * vga->f = (Prescale*RefFreq*n/d);
82 */
83 vga->d[0] = d;
84 vga->n[0] = 4;
85 for(fmin = vga->f[0]; d <= dmax; d++){
86 for(n = 4; n <= 130; n++){
87 f = vga->f[0] - (Prescale*RefFreq*n/d);
88 if(f < 0)
89 f = -f;
90 if(f < fmin){
91 fmin = f;
92 vga->d[0] = d;
93 vga->n[0] = n;
94 }
95 }
96 }
97
98 /*
99 * The serial word to be loaded into the icd2061a is
100 * (2<<21)|(vga->i<<17)|((vga->n)<<10)|(vga->p<<7)|vga->d
101 * Always select ICD2061A REG2.
102 */
103 vga->f[0] = (Prescale*RefFreq*vga->n[0]/vga->d[0]);
104 vga->d[0] -= 2;
105 vga->n[0] -= 3;
106
107 ctlr->flag |= Finit;
108 }
109
110 Ctlr icd2061a = {
111 "icd2061a",
112 0, /* snarf */
113 0, /* options */
114 init, /* init */
115 0, /* load */
116 0, /* dump */
117 };
118