Subversion Repositories planix.SVN

Rev

Rev 2 | Details | Compare with Previous | Last modification | View Log | RSS feed

Rev Author Line No. Line
2 - 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
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
};