Subversion Repositories planix.SVN

Rev

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

Rev Author Line No. Line
2 - 1
#include <u.h>
2
#include <libc.h>
3
#include <bio.h>
4
 
5
#include "pci.h"
6
#include "vga.h"
7
 
8
/*
9
 * S3 Trio64.
10
 */
11
static void
12
snarf(Vga* vga, Ctlr* ctlr)
13
{
14
	int i;
15
 
16
	/*
17
	 * The Trio has some extra sequencer registers which
18
	 * need to be unlocked for access.
19
	 */
20
	vgaxo(Seqx, 0x08, 0x06);
21
	for(i = 0x08; i < 0x19; i++)
22
		vga->sequencer[i] = vgaxi(Seqx, i);
23
	vga->crt[0x2D] = vgaxi(Crtx, 0x2D);
24
	vga->crt[0x2E] = vgaxi(Crtx, 0x2E);
25
	vga->crt[0x2F] = vgaxi(Crtx, 0x2F);
26
 
27
	s3generic.snarf(vga, ctlr);
28
	ctlr->flag |= Fsnarf;
29
}
30
 
31
static void
32
options(Vga*, Ctlr* ctlr)
33
{
34
	ctlr->flag |= Hlinear|Hpclk2x8|Henhanced|Foptions;
35
}
36
 
37
void
38
trio64clock(Vga* vga, Ctlr* ctlr)
39
{
40
	int d;
41
	ulong f, fmax, fmin, n, m, r;
42
	double trouble;
43
 
44
	/*
45
	 * The max value of R, M, N, and the speed rating of the part vary
46
	 * between parts and are passed to this routine in r[1] and f[1].
47
	 *			R	    F
48
	 *	Trio64		3	135000000
49
	 *	ViRGE		3	135000000
50
	 *	ViRGE/[DG]X	4	170000000
51
	 *	ViRGE/GX2	4	170000000
52
	 *	ViRGE/VX	4	220000000
53
	 */
54
 
55
	/*
56
	 * The PLL frequency is defined by the following equation:
57
	 *		   (M+2)
58
	 *	Fout = ------------- x Fref
59
	 *		(N+2) x 2**R
60
	 * where M, N and R have the following contraints:
61
	 * 1)		   (M+2) x Fref
62
	 *    vga->f[1] <= ------------ <= vga->f[1]*2
63
	 *		       (N+2)
64
	 * 2) 1 <= M <= vga->m[1] (usually 127)
65
	 * 3) 1 <= N <= vga->n[1] (usually 31)
66
	 * 4) 0 <= R <= vga->r[1]
67
	 *
68
	 * First determine R:
69
	 *	vga->f[1] < 2**R x Fout <= vga->f[1]*2
70
	 */
71
	for(r = 0; r <= vga->r[1]; r++){
72
		f = vga->f[0]*(1<<r);
73
		if(vga->f[1] < f && f <= vga->f[1]*2)
74
			vga->r[0] = r;
75
	}
76
	if(vga->r[0] > vga->r[1])
77
		error("%s: pclk %lud out of range\n", ctlr->name, vga->f[0]);
78
 
79
	/*
80
	 * Now find the closest match for M and N.
81
	 */
82
	vga->d[0] = vga->f[0]+1;
83
	for(n = 1; n <= vga->n[1]; n++){
84
		trouble = vga->f[0]*(n+2)*(1<<vga->r[0]);
85
		trouble /= RefFreq;
86
		m = (trouble+0.5) - 2;
87
		if(m > vga->m[1])
88
			continue;
89
 
90
		trouble = (m+2)*RefFreq;
91
		trouble /= (n+2)*(1<<vga->r[0]);
92
		f = trouble+0.5;
93
 
94
		d = vga->f[0] - f;
95
		if(d < 0)
96
			d = -d;
97
		if(d <= vga->d[0]){
98
			vga->m[0] = m;
99
			vga->n[0] = n;
100
			vga->d[0] = d;
101
		}
102
	}
103
 
104
	trouble = vga->f[0]*1.005;
105
	fmax = trouble;
106
	trouble = vga->f[0]*0.995;
107
	fmin = trouble;
108
	trouble = (vga->m[0]+2)*RefFreq;
109
	trouble /= (vga->n[0]+2)*(1<<vga->r[0]);
110
	f = trouble+0.5;
111
	if(fmin >= f || f >= fmax)
112
		error("%s: pclk %lud out of range\n", ctlr->name, vga->f[0]);
113
}
114
 
115
static void
116
init(Vga* vga, Ctlr* ctlr)
117
{
118
	ulong pclk, x;
119
 
120
	s3generic.init(vga, ctlr);
121
 
122
	/*
123
	 * Clock bits. If the desired video clock is
124
	 * one of the two standard VGA clocks it can just be
125
	 * set using bits <3:2> of vga->misc, otherwise we
126
	 * need to programme the DCLK PLL.
127
	 */
128
	if(vga->mode->z > 8)
129
		error("depth %d not supported\n", vga->mode->z);
130
 
131
	if(vga->f[0] == 0)
132
		vga->f[0] = vga->mode->frequency;
133
	vga->misc &= ~0x0C;
134
	if(vga->f[0] == VgaFreq0){
135
		/* nothing to do */;
136
	}
137
	else if(vga->f[0] == VgaFreq1)
138
		vga->misc |= 0x04;
139
	else{
140
		/*
141
		 * Part comes in -135MHz speed grade. In 8-bit mode
142
		 * the maximum DCLK is 80MHz. In 2x8-bit mode the maximum
143
		 * DCLK is 135MHz using the internal clock doubler.
144
		 */
145
		if((ctlr->flag & Hpclk2x8) && vga->mode->z == 8){
146
			pclk = 135000000;
147
			if(vga->f[0] > 80000000)
148
				ctlr->flag |= Upclk2x8;
149
		}
150
		else
151
			pclk = 80000000;
152
		if(vga->f[0] > pclk)
153
			error("%s: invalid pclk - %lud\n",
154
				ctlr->name, vga->f[0]);
155
 
156
		vga->f[1] = 135000000;
157
		vga->r[1] = 3;
158
		vga->n[1] = 31;
159
		vga->m[1] = 127;
160
		trio64clock(vga, ctlr);
161
		vga->sequencer[0x12] = (vga->r[0]<<5)|vga->n[0];
162
		vga->sequencer[0x13] = vga->m[0];
163
		vga->misc |= 0x0C;
164
	}
165
 
166
	/*
167
	 * Internal clock generator.
168
	 */
169
	vga->sequencer[0x15] &= ~0x31;
170
	vga->sequencer[0x15] |= 0x02;
171
	vga->sequencer[0x18] &= ~0x80;
172
	vga->crt[0x67] &= ~0xF2;
173
	if(ctlr->flag & Upclk2x8){
174
		vga->sequencer[0x15] |= 0x10;
175
		vga->sequencer[0x18] |= 0x80;
176
		/*
177
		 * There's a little strip of the border
178
		 * appears on the left in resolutions
179
		 * 1280 and above if the 0x02 bit isn't
180
		 * set (when it appears on the right...).
181
		 */
182
		vga->crt[0x67] |= 0x10;
183
	}
184
 
185
	/*
186
	 * VLB address latch delay.
187
	 */
188
	if((vga->crt[0x36] & 0x03) == 0x01)
189
		vga->crt[0x58] &= ~0x08;
190
 
191
	/*
192
	 * Start display FIFO fetch.
193
	 */
194
	x = vga->crt[0]-5;
195
	vga->crt[0x3B] = x;
196
	if(x & 0x100)
197
		vga->crt[0x5D] |= 0x40;
198
 
199
	/*
200
	 * Display memory access control.
201
	 * Calculation of the M-parameter (Crt54) is
202
	 * memory-system and dot-clock dependent, the
203
	 * values below are guesses from dumping
204
	 * registers.
205
	 */
206
	vga->crt[0x60] = 0xFF;
207
	if(vga->mode->x <= 800)
208
		vga->crt[0x54] = 0xE8;
209
	else if(vga->mode->x <= 1024)
210
		vga->crt[0x54] = 0xA8;
211
	else
212
		vga->crt[0x54] = 0x00/*0x48*/;
213
 
214
	ctlr->flag |= Finit;
215
}
216
 
217
static void
218
load(Vga* vga, Ctlr* ctlr)
219
{
220
	ushort advfunc;
221
 
222
	s3generic.load(vga, ctlr);
223
	vgaxo(Crtx, 0x60, vga->crt[0x60]);
224
	vgaxo(Crtx, 0x67, vga->crt[0x67]);
225
 
226
	/*
227
	 * Load the PLL registers if necessary.
228
	 * Not sure if the variable-delay method of setting the
229
	 * PLL will work without a write here to vga->misc,
230
	 * so use the immediate-load method by toggling bit 5
231
	 * of Seq15 if necessary.
232
	 */
233
	vgaxo(Seqx, 0x12, vga->sequencer[0x12]);
234
	vgaxo(Seqx, 0x13, vga->sequencer[0x13]);
235
	if((vga->misc & 0x0C) == 0x0C)
236
		vgaxo(Seqx, 0x15, vga->sequencer[0x15]|0x20);
237
	vgaxo(Seqx, 0x15, vga->sequencer[0x15]);
238
	vgaxo(Seqx, 0x18, vga->sequencer[0x18]);
239
 
240
	advfunc = 0x0000;
241
	if(ctlr->flag & Uenhanced)
242
		advfunc = 0x0001;
243
	outportw(0x4AE8, advfunc);
244
}
245
 
246
static void
247
dump(Vga* vga, Ctlr* ctlr)
248
{
249
	int i;
250
	ulong dclk, m, n, r;
251
 
252
	s3generic.dump(vga, ctlr);
253
 
254
	printitem(ctlr->name, "Seq08");
255
	for(i = 0x08; i < 0x19; i++)
256
		printreg(vga->sequencer[i]);
257
 
258
	printitem(ctlr->name, "Crt2D");
259
	printreg(vga->crt[0x2D]);
260
	printreg(vga->crt[0x2E]);
261
	printreg(vga->crt[0x2F]);
262
 
263
	n = vga->sequencer[0x12] & 0x1F;
264
	r = (vga->sequencer[0x12]>>5) & 0x03;
265
	m = vga->sequencer[0x13] & 0x7F;
266
	dclk = (m+2)*RefFreq;
267
	dclk /= (n+2)*(1<<r);
268
	printitem(ctlr->name, "dclk m n r");
269
	Bprint(&stdout, "%9ld %8ld       - %8ld %8ld\n", dclk, m, n, r);
270
}
271
 
272
Ctlr trio64 = {
273
	"trio64",			/* name */
274
	snarf,				/* snarf */
275
	options,			/* options */
276
	init,				/* init */
277
	load,				/* load */
278
	dump,				/* dump */
279
};