jehanne/sys/src/cmd/hmi/vga/icd2061a.c

127 lines
2.5 KiB
C

/*
* This file is part of the UCB release of Plan 9. It is subject to the license
* terms in the LICENSE file found in the top-level directory of this
* distribution and at http://akaros.cs.berkeley.edu/files/Plan9License. No
* part of the UCB release of Plan 9, including this file, may be copied,
* modified, propagated, or distributed except according to the terms contained
* in the LICENSE file.
*/
/*
* IC Designs ICD2061A Dual Programmable Graphics Clock Generator.
*/
#include <u.h>
#include <lib9.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 uint32_t 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;
uint32_t 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 */
};