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
 * 3Dfx.
10
 */
11
enum {
12
	dramInit0		= 0x018/4,
13
	dramInit1		= 0x01C/4,
14
	vgaInit0		= 0x028/4,
15
	pllCtrl0		= 0x040/4,
16
	pllCtrl1		= 0x044/4,
17
	pllCtrl2		= 0x048/4,
18
	dacMode			= 0x04C/4,
19
	vidProcCfg		= 0x05C/4,
20
	vidScreenSize		= 0x098/4,
21
	vidDesktopOverlayStride	= 0x0E8/4,
22
 
23
	Nior			= 0x100/4,
24
};
25
 
26
typedef struct Tdfx {
27
	ulong	io;
28
	Pcidev*	pci;
29
 
30
	ulong	r[Nior];
31
} Tdfx;
32
 
33
static ulong
34
io32r(Tdfx* tdfx, int r)
35
{
36
	return inportl(tdfx->io+(r*4));
37
}
38
 
39
static void
40
io32w(Tdfx* tdfx, int r, ulong l)
41
{
42
	outportl(tdfx->io+(r*4), l);
43
}
44
 
45
static void
46
snarf(Vga* vga, Ctlr* ctlr)
47
{
48
	int i;
49
	ulong v;
50
	Tdfx *tdfx;
51
 
52
	if(vga->private == nil){
53
		tdfx = alloc(sizeof(Tdfx));
54
		tdfx->pci = pcimatch(0, 0x121A, 0);
55
		if(tdfx->pci == nil)
56
			error("%s: not found\n", ctlr->name);
57
		switch(tdfx->pci->did){
58
		default:
59
			error("%s: unknown chip - DID %4.4uX\n",
60
				ctlr->name, tdfx->pci->did);
61
			break;
62
		case 0x0003:		/* Banshee */
63
			vga->f[1] = 270000000;
64
			break;
65
		case 0x0005:		/* Avenger (a.k.a. Voodoo3) */
66
			vga->f[1] = 300000000;
67
			break;
68
		case 0x0009:		/* Voodoo5 */
69
			vga->f[1] = 350000000;
70
			break;
71
		}
72
		/*
73
		 * Frequency output of PLL's is given by
74
		 *	fout = RefFreq*(n+2)/((m+2)*2^p)
75
		 * where there are 6 bits for m, 8 bits for n
76
		 * and 2 bits for p (k).
77
		 */
78
		vga->m[1] = 64;
79
		vga->n[1] = 256;
80
		vga->p[1] = 4;
81
 
82
		if((v = (tdfx->pci->mem[2].bar & ~0x3)) == 0)
83
			error("%s: I/O not mapped\n", ctlr->name);
84
		tdfx->io = v;
85
 
86
		vga->private = tdfx;
87
	}
88
	tdfx = vga->private;
89
 
90
	vga->crt[0x1A] = vgaxi(Crtx, 0x1A);
91
	vga->crt[0x1B] = vgaxi(Crtx, 0x1B);
92
	for(i = 0; i < Nior; i++)
93
		tdfx->r[i] = io32r(tdfx, i);
94
 
95
	/*
96
	 * If SDRAM then there's 16MB memory else it's SGRAM
97
	 * and can count it based on the power-on straps -
98
	 * chip size can be 8Mb or 16Mb, and there can be 4 or
99
	 * 8 of them.
100
	 */
101
	vga->vma = tdfx->pci->mem[1].size;
102
	if(tdfx->r[dramInit1] & 0x40000000)
103
		vga->vmz = 16*1024*1024;
104
	else{
105
		if(tdfx->r[dramInit0] & 0x08000000)
106
			i = 16*1024*1024/8;
107
		else
108
			i = 8*1024*1024/8;
109
		if(tdfx->r[dramInit0] & 0x04000000)
110
			i *= 8;
111
		else
112
			i *= 4;
113
		vga->vmz = i;
114
	}
115
 
116
	ctlr->flag |= Fsnarf;
117
}
118
 
119
static void
120
options(Vga*, Ctlr* ctlr)
121
{
122
	ctlr->flag |= Hlinear|Hclk2|Foptions;
123
}
124
 
125
static void
126
tdfxclock(Vga* vga, Ctlr*)
127
{
128
	int d, dmin;
129
	uint f, m, n, p;
130
 
131
	dmin = vga->f[0];
132
	for(m = 1; m < vga->m[1]; m++){
133
		for(n = 1; n < vga->n[1]; n++){
134
			f = (RefFreq*(n+2))/(m+2);
135
			for(p = 0; p < vga->p[1]; p++){
136
				d = vga->f[0] - (f/(1<<p));
137
				if(d < 0)
138
					d = -d;
139
				if(d >= dmin)
140
					continue;
141
				dmin = d;
142
				vga->m[0] = m;
143
				vga->n[0] = n;
144
				vga->p[0] = p;
145
			}
146
		}
147
	}
148
}
149
 
150
static void
151
init(Vga* vga, Ctlr* ctlr)
152
{
153
	int x;
154
	Mode *mode;
155
	Tdfx *tdfx;
156
 
157
	mode = vga->mode;
158
	tdfx = vga->private;
159
 
160
	if(vga->linear && (ctlr->flag & Hlinear))
161
		ctlr->flag |= Ulinear;
162
 
163
	/*
164
	 * Clock bits. If the desired video clock is
165
	 * one of the two standard VGA clocks or 50MHz it can just be
166
	 * set using bits <3:2> of vga->misc, otherwise we
167
	 * need to programme the PLL.
168
	 */
169
	if(vga->f[0] == 0)
170
		vga->f[0] = mode->frequency;
171
	vga->misc &= ~0x0C;
172
	if(vga->f[0] == VgaFreq0){
173
		/* nothing to do */;
174
	}
175
	else if(vga->f[0] == VgaFreq1)
176
		vga->misc |= 0x04;
177
	else if(vga->f[0] == 50000000)
178
		vga->misc |= 0x08;
179
	else{
180
		if(vga->f[0] > vga->f[1])
181
			error("%s: invalid pclk - %lud\n",
182
				ctlr->name, vga->f[0]);
183
		if(vga->f[0] > 135000000 && (ctlr->flag & Hclk2)){
184
			if(mode->x%16)
185
				error("%s: f > 135MHz requires (x%%16) == 0\n",
186
					ctlr->name);
187
			ctlr->flag |= Uclk2;
188
		}
189
		tdfxclock(vga, ctlr);
190
 
191
		tdfx->r[pllCtrl0] = (vga->n[0]<<8)|(vga->m[0]<<2)|vga->p[0];
192
		vga->misc |= 0x0C;
193
	}
194
 
195
	/*
196
	 * Pixel format and memory stride.
197
	 */
198
	tdfx->r[vidScreenSize] = (mode->y<<12)|mode->x;
199
	tdfx->r[vidProcCfg] = 0x00000081;
200
	switch(mode->z){
201
	default:
202
		error("%s: %d-bit mode not supported\n", ctlr->name, mode->z);
203
		break;
204
	case 8:
205
		tdfx->r[vidDesktopOverlayStride] = mode->x;
206
		break;
207
	case 16:
208
		tdfx->r[vidDesktopOverlayStride] = mode->x*2;
209
		tdfx->r[vidProcCfg] |= 0x00040400;
210
		break;
211
	case 32:
212
		tdfx->r[vidDesktopOverlayStride] = mode->x*4;
213
		tdfx->r[vidProcCfg] |= 0x000C0400;
214
		break;
215
	}
216
	tdfx->r[vgaInit0] = 0x140;
217
 
218
	/*
219
	 * Adjust horizontal timing if doing two screen pixels per clock.
220
	 */
221
	tdfx->r[dacMode] = 0;
222
	if(ctlr->flag & Uclk2){
223
		vga->crt[0x00] = ((mode->ht/2)>>3)-5;
224
		vga->crt[0x01] = ((mode->x/2)>>3)-1;
225
		vga->crt[0x02] = ((mode->shb/2)>>3)-1;
226
 
227
		x = (mode->ehb/2)>>3;
228
		vga->crt[0x03] = 0x80|(x & 0x1F);
229
		vga->crt[0x04] = (mode->shs/2)>>3;
230
		vga->crt[0x05] = ((mode->ehs/2)>>3) & 0x1F;
231
		if(x & 0x20)
232
			vga->crt[0x05] |= 0x80;
233
 
234
		tdfx->r[dacMode] |= 0x01;
235
		tdfx->r[vidProcCfg] |= 0x04000000;
236
	}
237
 
238
	/*
239
	 * Overflow.
240
	 */
241
	vga->crt[0x1A] = 0x00;
242
	if(vga->crt[0x00] & 0x100)
243
		vga->crt[0x1A] |= 0x01;
244
	if(vga->crt[0x01] & 0x100)
245
		vga->crt[0x1A] |= 0x04;
246
	if(vga->crt[0x03] & 0x100)
247
		vga->crt[0x1A] |= 0x10;
248
	x = mode->ehb;
249
	if(ctlr->flag & Uclk2)
250
		x /= 2;
251
	if((x>>3) & 0x40)
252
		vga->crt[0x1A] |= 0x20;
253
	if(vga->crt[0x04] & 0x100)
254
		vga->crt[0x1A] |= 0x40;
255
	x = mode->ehs;
256
	if(ctlr->flag & Uclk2)
257
		x /= 2;
258
	if((x>>3) & 0x20)
259
		vga->crt[0x1A] |= 0x80;
260
 
261
	vga->crt[0x1B] = 0x00;
262
	if(vga->crt[0x06] & 0x400)
263
		vga->crt[0x1B] |= 0x01;
264
	if(vga->crt[0x12] & 0x400)
265
		vga->crt[0x1B] |= 0x04;
266
	if(vga->crt[0x15] & 0x400)
267
		vga->crt[0x1B] |= 0x10;
268
	if(vga->crt[0x10] & 0x400)
269
		vga->crt[0x1B] |= 0x40;
270
 
271
	vga->attribute[0x11] = Pblack;
272
 
273
	ctlr->flag |= Finit;
274
}
275
 
276
static void
277
load(Vga* vga, Ctlr* ctlr)
278
{
279
	Tdfx *tdfx;
280
 
281
	vgaxo(Crtx, 0x1A, vga->crt[0x1A]);
282
	vgaxo(Crtx, 0x1B, vga->crt[0x1B]);
283
 
284
	tdfx = vga->private;
285
	io32w(tdfx, dacMode, tdfx->r[dacMode]);
286
	io32w(tdfx, vidScreenSize, tdfx->r[vidScreenSize]);
287
	io32w(tdfx, vidDesktopOverlayStride, tdfx->r[vidDesktopOverlayStride]);
288
	io32w(tdfx, vidProcCfg, tdfx->r[vidProcCfg]);
289
	io32w(tdfx, vgaInit0, tdfx->r[vgaInit0]);
290
 
291
	if((vga->misc & 0x0C) == 0x0C)
292
		io32w(tdfx, pllCtrl0, tdfx->r[pllCtrl0]);
293
 
294
	ctlr->flag |= Fload;
295
}
296
 
297
static uint
298
pllctrl(Tdfx* tdfx, int pll)
299
{
300
	uint k, m, n, r;
301
 
302
	r = tdfx->r[pllCtrl0+pll];
303
	k = r & 0x03;
304
	m = (r>>2) & 0x3F;
305
	n = (r>>8) & 0xFF;
306
 
307
	return (RefFreq*(n+2))/((m+2)*(1<<k));
308
}
309
 
310
static void
311
dump(Vga* vga, Ctlr* ctlr)
312
{
313
	int i;
314
	Tdfx *tdfx;
315
 
316
	if((tdfx = vga->private) == nil)
317
		return;
318
 
319
	printitem(ctlr->name, "Crt1A");
320
	printreg(vga->crt[0x1A]);
321
	printreg(vga->crt[0x1B]);
322
 
323
	Bprint(&stdout, "\n");
324
	for(i = 0; i < Nior; i++)
325
		Bprint(&stdout, "%s %2.2uX\t%.8luX\n",
326
			ctlr->name, i*4, tdfx->r[i]);
327
 
328
	printitem(ctlr->name, "pllCtrl");
329
	Bprint(&stdout, "%9ud %8ud\n", pllctrl(tdfx, 0), pllctrl(tdfx, 1));
330
}
331
 
332
Ctlr tdfx = {
333
	"3dfx",				/* name */
334
	snarf,				/* snarf */
335
	options,			/* options */
336
	init,				/* init */
337
	load,				/* load */
338
	dump,				/* dump */
339
};
340
 
341
Ctlr tdfxhwgc = {
342
	"3dfxhwgc",			/* name */
343
	0,				/* snarf */
344
	0,				/* options */
345
	0,				/* init */
346
	0,				/* load */
347
	0,				/* dump */
348
};