diff options
author | Taru Karttunen <taruti@taruti.net> | 2011-03-30 15:46:40 +0300 |
---|---|---|
committer | Taru Karttunen <taruti@taruti.net> | 2011-03-30 15:46:40 +0300 |
commit | e5888a1ffdae813d7575f5fb02275c6bb07e5199 (patch) | |
tree | d8d51eac403f07814b9e936eed0c9a79195e2450 /sys/src/cmd/aux/vga/icd2061a.c |
Import sources from 2011-03-30 iso image
Diffstat (limited to 'sys/src/cmd/aux/vga/icd2061a.c')
-rwxr-xr-x | sys/src/cmd/aux/vga/icd2061a.c | 117 |
1 files changed, 117 insertions, 0 deletions
diff --git a/sys/src/cmd/aux/vga/icd2061a.c b/sys/src/cmd/aux/vga/icd2061a.c new file mode 100755 index 000000000..24eae0dfa --- /dev/null +++ b/sys/src/cmd/aux/vga/icd2061a.c @@ -0,0 +1,117 @@ +/* + * IC Designs ICD2061A Dual Programmable Graphics Clock Generator. + */ +#include <u.h> +#include <libc.h> +#include <bio.h> + +#include "pci.h" +#include "vga.h" + +enum { + Prescale = 2, /* P counter prescale (default) */ + NIndex = 14, /* number of index field values */ +}; + +/* + * For an index value of x, the appropriate VCO range + * is >= index[x] && <= index[x+1]. The higher index is + * prefered if VCO is on a boundary. + */ +static ulong index[NIndex] = { + 50000000, + 51000000, + 53200000, + 58500000, + 60700000, + 64400000, + 66800000, + 73500000, + 75600000, + 80900000, + 83200000, + 91500000, + 100000000, + 120000000, +}; + +static void +init(Vga* vga, Ctlr* ctlr) +{ + int f; + ulong d, dmax, fmin, n; + + if(ctlr->flag & Finit) + return; + + if(vga->f[0] == 0) + vga->f[0] = vga->mode->frequency; + + if(vga->mode->z > 8) + error("depth %d not supported\n", vga->mode->z); + + /* + * Post-VCO divisor. Constraint: + * 50MHz <= vga->f <= 120MHz + */ + for(vga->p[0] = 0; vga->f[0] <= 50000000; vga->p[0]++) + vga->f[0] <<= 1; + + /* + * Determine index. + */ + for(vga->i[0] = NIndex-1; vga->f[0] < index[vga->i[0]] && vga->i[0]; vga->i[0]--) + ; + + /* + * Denominator. Constraints: + * 200KHz <= RefFreq/d <= 1MHz + * and + * 3 <= d <= 129 + * + * Numerator. Constraint: + * 4 <= n <= 130 + */ + d = RefFreq/1000000 > 3 ? RefFreq/1000000: 3; + dmax = RefFreq/200000 < 129 ? RefFreq/200000: 129; + + /* + * Now look for values of p and q that give + * the least error for + * vga->f = (Prescale*RefFreq*n/d); + */ + vga->d[0] = d; + vga->n[0] = 4; + for(fmin = vga->f[0]; d <= dmax; d++){ + for(n = 4; n <= 130; n++){ + f = vga->f[0] - (Prescale*RefFreq*n/d); + if(f < 0) + f = -f; + if(f < fmin){ + fmin = f; + vga->d[0] = d; + vga->n[0] = n; + } + } + } + + /* + * The serial word to be loaded into the icd2061a is + * (2<<21)|(vga->i<<17)|((vga->n)<<10)|(vga->p<<7)|vga->d + * Always select ICD2061A REG2. + */ + vga->f[0] = (Prescale*RefFreq*vga->n[0]/vga->d[0]); + vga->d[0] -= 2; + vga->n[0] -= 3; + + ctlr->flag |= Finit; +} + +Ctlr icd2061a = { + "icd2061a", + 0, /* snarf */ + 0, /* options */ + init, /* init */ + 0, /* load */ + 0, /* dump */ +}; |