127 lines
2.5 KiB
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 */
|
|
};
|