Warning: Attempt to read property "date" on null in /usr/local/www/websvn.planix.org/blame.php on line 247

Warning: Attempt to read property "msg" on null in /usr/local/www/websvn.planix.org/blame.php on line 247
WebSVN – planix.SVN – Blame – /os/branches/feature-vt/sys/src/cmd/aux/vga/mga2164w.c – Rev 2

Subversion Repositories planix.SVN

Rev

Go to most recent revision | Details | 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
 * Matrox Millenium and Matrox Millenium II.
10
 * Matrox MGA-2064W, MGA-2164W 3D graphics accelerators
11
 * Texas Instruments Tvp3026 RAMDAC.
12
 */
13
enum {
14
	Meg		= 1024*1024,
15
	/* pci chip manufacturer */
16
	MATROX		= 0x102B,
17
 
18
	/* pci chip device ids */
19
	MGA2064		= 0x0519,
20
	MGA2164		= 0x051B,
21
	MGA2164AGP	= 0x051F,
22
 
23
	/* i/o ports */
24
	Crtcext		= 0x03DE,	/* CRTC Extensions */
25
 
26
	/* config space offsets */
27
	Devctrl		= 0x04,		/* Device Control */
28
	Option		= 0x40,		/* Option */
29
 
30
	/* control aperture offsets */
31
	RAMDAC		= 0x3C00,	/* RAMDAC registers */
32
	CACHEFLUSH	= 0x1FFF,
33
};
34
 
35
typedef struct {
36
	Pcidev*	pci;
37
	int	devid;
38
	uchar*	membase1;
39
	uchar*	membase2;
40
	ulong	devctrl;
41
	ulong	option;
42
	uchar	crtcext[6];
43
	uchar	tvp[64];
44
	uchar	pclk[3];
45
	uchar	mclk[3];
46
	uchar	lclk[3];
47
} Mga;
48
 
49
static uchar
50
_tvp3026i(Vga* vga, Ctlr* ctlr, uchar reg)
51
{
52
	Mga *mga;
53
 
54
	if(reg >= 0x10)
55
		error("%s: tvp3026io: direct reg 0x%uX out of range\n", ctlr->name, reg);
56
 
57
	if(vga->private == nil)
58
		error("%s: tvp3026io: no *mga\n", ctlr->name);
59
	mga = vga->private;
60
 
61
	return *(mga->membase1+RAMDAC+reg);
62
}
63
 
64
static void
65
_tvp3026o(Vga* vga, Ctlr* ctlr, uchar reg, uchar data)
66
{
67
	Mga *mga;
68
 
69
	if(reg >= 0x10)
70
		error("%s: tvp3026io: direct reg 0x%uX out of range\n", ctlr->name, reg);
71
 
72
	if(vga->private == nil)
73
		error("%s: tvp3026io: no *mga\n", ctlr->name);
74
	mga = vga->private;
75
 
76
	*(mga->membase1+RAMDAC+reg) = data;
77
}
78
 
79
static uchar
80
_tvp3026xi(Vga* vga, Ctlr* ctlr, uchar index)
81
{
82
	if(index >= 0x40)
83
		error("%s: tvp3026xi: reg 0x%uX out of range\n", ctlr->name, index);
84
 
85
	_tvp3026o(vga, ctlr, 0x00, index);
86
 
87
	return _tvp3026i(vga, ctlr, 0x0A);
88
}
89
 
90
void
91
_tvp3026xo(Vga* vga, Ctlr* ctlr, uchar index, uchar data)
92
{
93
	if(index >= 0x40)
94
		error("%s: tvp3026xo: reg 0x%uX out of range\n", ctlr->name, index);
95
 
96
	_tvp3026o(vga, ctlr, 0x00, index);
97
	_tvp3026o(vga, ctlr, 0x0A, data);
98
}
99
 
100
static uchar
101
crtcexti(uchar index)
102
{
103
	uchar data;
104
 
105
	outportb(Crtcext, index);
106
	data = inportb(Crtcext+1);
107
 
108
	return data;
109
}
110
 
111
static void
112
crtcexto(uchar index, uchar data)
113
{
114
	outportb(Crtcext, index);
115
	outportb(Crtcext+1, data);
116
}
117
 
118
static void
119
mapmga(Vga* vga, Ctlr* ctlr)
120
{
121
	int f;
122
	uchar *m;
123
	Mga *mga;
124
 
125
	if(vga->private == nil)
126
		error("%s: tvp3026io: no *mga\n", ctlr->name);
127
	mga = vga->private;
128
 
129
	f = open("#v/vgactl", OWRITE);
130
	if(f < 0)
131
		error("%s: can't open vgactl\n", ctlr->name);
132
	if(write(f, "type mga2164w", 13) != 13)
133
		error("%s: can't set mga type\n", ctlr->name);
134
 
135
	m = segattach(0, "mga2164wmmio", 0, 16*1024);
136
	if(m == (void*)-1)
137
		error("%s: can't attach mga2164wmmio segment\n", ctlr->name);
138
	mga->membase1 = m;
139
 
140
	m = segattach(0, "mga2164wscreen", 0, (mga->devid==MGA2064? 8 : 16)*Meg);
141
	if(m ==(void*)-1)
142
		error("%s: can't attach mga2164wscreen segment\n", ctlr->name);
143
 
144
	mga->membase2 = m;
145
}
146
 
147
static void
148
clockcalc(Vga* vga, Ctlr* ctlr, int bpp)
149
{
150
	ulong m, n, p, q;
151
	double z, fdiff, fmindiff, fvco, fgoal;
152
	Mga *mga;
153
 
154
	USED(ctlr);
155
 
156
	mga = vga->private;
157
 
158
	/*
159
	 * Look for values of n, d and p that give
160
	 * the least error for
161
	 *	Fvco = 8*RefFreq*(65-m)/(65-n)
162
	 *	Fpll = Fvco/2**p
163
	 * N and m are 6 bits, p is 2 bits. Constraints:
164
	 *	110MHz <= Fvco <= 250MHz
165
	 *	40 <= n <= 62
166
	 *	 1 <= m <= 62
167
	 *	 0 <= p <=  3
168
	 */
169
	fgoal = (double)vga->f[0];
170
	fmindiff = fgoal;
171
	vga->m[0] = 0x15;
172
	vga->n[0] = 0x18;
173
	vga->p[0] = 3;
174
	for(m = 62; m > 0; m--){
175
		for(n = 62; n >= 40; n--){
176
			fvco = 8.*((double)RefFreq)*(65.-m)/(65.-n);
177
			if(fvco < 110e6 || fvco > 250e6)
178
				continue;
179
			for(p = 0; p < 4; p++){
180
				fdiff = fgoal - fvco/(1<<p);
181
				if(fdiff < 0)
182
					fdiff = -fdiff;
183
				if(fdiff < fmindiff){
184
					fmindiff = fdiff;
185
					vga->m[0] = m;
186
					vga->n[0] = n;
187
					vga->p[0] = p;
188
				}
189
			}
190
		}
191
	}
192
	mga->pclk[0] = 0xC0 | (vga->n[0] & 0x3f);
193
	mga->pclk[1] = (vga->m[0] & 0x3f);
194
	mga->pclk[2] = 0xB0 | (vga->p[0] & 0x03);
195
 
196
	/*
197
	 * Now the loop clock:
198
	 * 	m is fixed;
199
	 *	calculate n;
200
	 *	set z to the lower bound (110MHz) and calculate p and q.
201
	 */
202
	vga->m[1] = 61;
203
	n = 65 - 4*(64/(vga->vmz==2*Meg? bpp*2 : bpp));
204
	fvco = (8*RefFreq*(65-vga->m[0]))/(65-vga->n[0]);
205
	vga->f[1] = fvco/(1<<vga->p[0]);
206
	z = 110e6*(65.-n)/(4.*vga->f[1]);
207
	if(z <= 16){
208
		for(p = 0; p < 4; p++){
209
			if(1<<(p+1) > z)
210
				break;
211
		}
212
		q = 0;
213
	}
214
	else{
215
		p = 3;
216
		q = (z - 16)/16 + 1;
217
	}
218
	vga->n[1] = n;
219
	vga->p[1] = p;
220
	vga->q[1] = q;
221
	mga->lclk[0] = 0xC0 | (vga->n[1] & 0x3f);
222
	mga->lclk[1] = (vga->m[1] & 0x3f);
223
	mga->lclk[2] = 0xF0 | (vga->p[1] & 0x03);
224
	mga->tvp[0x39] = 0x38 | q;
225
}
226
 
227
static void
228
snarf(Vga* vga, Ctlr* ctlr)
229
{
230
	int i, k, n;
231
	uchar *p, x[8];
232
	Pcidev *pci;
233
	Mga *mga;
234
 
235
	if(vga->private == nil) {
236
		pci = pcimatch(nil, MATROX, MGA2164AGP);
237
		if(pci == nil)
238
			pci = pcimatch(nil, MATROX, MGA2164);
239
		if(pci == nil)
240
			pci = pcimatch(nil, MATROX, MGA2064);
241
		if(pci == nil)
242
			error("%s: no Pcidev with Vid=0x102B, Did=0x051[9BF] or 0x521\n", ctlr->name);
243
 
244
		vga->private = alloc(sizeof(Mga));
245
		mga = (Mga*)vga->private;
246
		mga->devid = pci->did;
247
		mga->pci = pci;
248
		mapmga(vga, ctlr);
249
	}
250
	else {
251
		mga = (Mga*)vga->private;
252
		pci = mga->pci;
253
	}
254
 
255
	for(i = 0; i < 0x06; i++)
256
		mga->crtcext[i] = crtcexti(i);
257
 
258
	mga->devctrl = pcicfgr32(pci, Devctrl);
259
	mga->option = pcicfgr32(pci, Option);
260
 
261
	for(i = 0; i < 64; i++)
262
		mga->tvp[i] = _tvp3026xi(vga, ctlr, i);
263
 
264
	for(i = 0; i < 3; i++){
265
		_tvp3026xo(vga, ctlr, 0x2C, (i<<4)|(i<<2)|i);
266
		mga->pclk[i] = _tvp3026xi(vga, ctlr, 0x2D);
267
	}
268
 
269
	for(i = 0; i < 3; i++){
270
		_tvp3026xo(vga, ctlr, 0x2C, (i<<4)|(i<<2)|i);
271
		mga->mclk[i] = _tvp3026xi(vga, ctlr, 0x2E);
272
	}
273
 
274
	for(i = 0; i < 3; i++){
275
		_tvp3026xo(vga, ctlr, 0x2C, (i<<4)|(i<<2)|i);
276
		mga->lclk[i] = _tvp3026xi(vga, ctlr, 0x2F);
277
	}
278
 
279
	/* find out how much memory is here, some multiple of 2Meg */
280
	crtcexto(3, mga->crtcext[3] | 0x80);	/* mga mode */
281
	p = mga->membase2;
282
	n = (mga->devid==MGA2064? 4 : 8);
283
	for(i = 0; i < n; i++) {
284
		k = (2*i+1)*Meg;
285
		p[k] = 0;
286
		p[k] = i+1;
287
		*(mga->membase1+CACHEFLUSH) = 0;
288
		x[i] = p[k];
289
		trace("x[%d]=%d\n", i, x[i]);
290
	}
291
	for(i = 1; i < n; i++)
292
		if(x[i] != i+1)
293
			break;
294
	vga->vmz = 2*i*Meg;
295
	trace("probe found %d megabytes\n", 2*i);
296
	crtcexto(3, mga->crtcext[3]);	/* restore mga mode */
297
 
298
 
299
	ctlr->flag |= Fsnarf;
300
}
301
 
302
static void
303
options(Vga* vga, Ctlr* ctlr)
304
{
305
	if(vga->virtx & 127)
306
		vga->virtx = (vga->virtx+127)&~127;
307
	ctlr->flag |= Foptions;
308
}
309
 
310
static void
311
init(Vga* vga, Ctlr* ctlr)
312
{
313
	Mode *mode;
314
	Ctlr *c;
315
	Mga *mga;
316
	int scale, offset, pixbuswidth;
317
 
318
	mga = vga->private;
319
	mode = vga->mode;
320
 
321
	ctlr->flag |= Ulinear;
322
 
323
	pixbuswidth = (vga->vmz == 2*Meg) ? 32 : 64;
324
	trace("pixbuswidth=%d\n", pixbuswidth);
325
 
326
	if(vga->mode->z > 8)
327
		error("depth %d not supported\n", vga->mode->z);
328
 
329
	if(vga->f[0] == 0)
330
		vga->f[0] = vga->mode->frequency;
331
 
332
	/* supposed to let tvp reg 1D control sync polarity */
333
	vga->misc |= 0xC8;
334
 
335
	/*
336
	 * In power graphics mode, supposed to use
337
	 *	hblkend = htotal+4
338
	 *	hblkstr = hdispend
339
	 */
340
	if((vga->crt[0x00] & 0x0F) == 0x0F) {
341
		vga->crt[0x00]++;
342
		mode->ht += 8;
343
	}
344
	vga->crt[0x02] = vga->crt[0x01];
345
	vga->crt[0x03] = (((mode->ht>>3)-1) & 0x1F) | 0x80;
346
	vga->crt[0x05] = ((((mode->ht>>3)-1) & 0x20) << 2)
347
		| ((mode->ehs>>3) & 0x1F);
348
 
349
	offset = (vga->virtx*mode->z) >> ((pixbuswidth==32)? 6 : 7);
350
	vga->crt[0x13] = offset;
351
	vga->crt[0x14] = 0;
352
	vga->crt[0x17] = 0xE3;
353
 
354
	mga->crtcext[0] = (offset & 0x300) >> 4;
355
	mga->crtcext[1] = ((((mode->ht>>3)-5) & 0x100) >> 8)
356
		| ((((mode->x>>3)-1) & 0x100) >> 7)
357
		| (((mode->shs>>3) & 0x100) >> 6)  /* why not (shs>>3)-1 ? */
358
		| (((mode->ht>>3)-1) & 0x40);
359
	mga->crtcext[2] = (((mode->vt-2) & 0xC00) >> 10)
360
		| (((mode->y-1) & 0x400) >> 8)
361
		| ((mode->vrs & 0xC00) >> 7)
362
		| ((mode->vrs & 0xC00) >> 5);
363
	scale = mode->z == 8 ? 1 : (mode->z == 16? 2 : 4);
364
	if(pixbuswidth == 32)
365
		scale *= 2;
366
	scale--;
367
	mga->crtcext[3] = scale | 0x80;
368
	if(vga->vmz >= 8*Meg)
369
		mga->crtcext[3] |= 0x10;
370
	else if(vga->vmz == 2*Meg)
371
		mga->crtcext[3] |= 0x08;
372
	mga->crtcext[4] = 0;
373
	mga->crtcext[5] = 0;
374
 
375
	mga->tvp[0x0F] = (mode->z == 8) ? 0x06 : 0x07;
376
	mga->tvp[0x18] = (mode->z == 8) ? 0x80 :
377
		(mode->z == 16) ? 0x05 : 0x06;
378
	mga->tvp[0x19] = (mode->z == 8) ? 0x4C :
379
		(mode->z == 16) ? 0x54 : 0x5C;
380
	if(pixbuswidth == 32)
381
		mga->tvp[0x19]--;
382
	mga->tvp[0x1A] = (mode->z == 8) ? 0x25 :
383
		(mode->z == 16) ? 0x15 : 0x05;
384
	mga->tvp[0x1C] = 0;
385
	mga->tvp[0x1D] = (mode->y < 768) ? 0x00 : 0x03;
386
	mga->tvp[0x1E] = (mode->z == 8) ? 0x04 : 0x24; /* six bit mode */
387
	mga->tvp[0x2A] = 0;
388
	mga->tvp[0x2B] = 0x1E;
389
	mga->tvp[0x30] = 0xFF;
390
	mga->tvp[0x31] = 0xFF;
391
	mga->tvp[0x32] = 0xFF;
392
	mga->tvp[0x33] = 0xFF;
393
	mga->tvp[0x34] = 0xFF;
394
	mga->tvp[0x35] = 0xFF;
395
	mga->tvp[0x36] = 0xFF;
396
	mga->tvp[0x37] = 0xFF;
397
	mga->tvp[0x38] = 0;
398
	mga->tvp[0x39] = 0;
399
	mga->tvp[0x3A] = 0;
400
	mga->tvp[0x06] = 0;
401
 
402
	// From: "Bruce G. Stewart" <bruce.g.stewart@worldnet.att.net>
403
	// 05-Jul-00 - Fix vertical blanking setup
404
	// This should probably be corrected in vga.c too.
405
	{
406
		// Start vertical blanking after the last displayed line
407
		// End vertical blanking after the total line count
408
		int svb = mode->y;
409
		int evb = mode->vt;
410
 
411
		// A field is 1/2 of the lines in interlaced mode
412
		if(mode->interlace == 'v'){
413
			svb /= 2;
414
			evb /= 2;
415
		}
416
		--svb;
417
		--evb;			// line counter counts from 0
418
 
419
		vga->crt[0x15] = svb;
420
		vga->crt[0x07] = (vga->crt[0x07] & ~0x08) | ((svb & 0x100)>>5);
421
		vga->crt[0x09] = (vga->crt[0x09] & ~0x20) | ((svb & 0x200)>>4);
422
		// MGA specific: bits 10 and 11
423
		mga->crtcext[0x02] &=  ~0x18;
424
		mga->crtcext[0x02] |= ((svb & 0xC00)>>7);
425
 
426
		vga->crt[0x16]     = evb;
427
	}
428
 
429
	clockcalc(vga, ctlr, mode->z);
430
 
431
 
432
	mga->option = mga->option & ~0x3000;
433
	if(vga->vmz > 2*Meg)
434
		mga->option |= 0x1000;
435
 
436
	/* disable vga load (want to do fields in different order) */
437
	for(c = vga->link; c; c = c->link)
438
		if(c->name == "vga")
439
			c->load = nil;
440
 
441
	ctlr->flag |= Finit;
442
}
443
 
444
static void
445
load(Vga* vga, Ctlr* ctlr)
446
{
447
	int i;
448
	Mga *mga;
449
	Pcidev* pci;
450
 
451
	mga = vga->private;
452
	pci = mga->pci;
453
 
454
	trace("loading crtcext0-5\n");
455
	/* turn on mga mode, set other crt high bits */
456
	for(i = 0; i < 6; i++)
457
		crtcexto(i, mga->crtcext[i]);
458
 
459
	trace("setting memory mode\n");
460
	/* set memory mode */
461
	pcicfgw32(pci, Option, mga->option);
462
 
463
	/* clocksource: pixel clock PLL */
464
	_tvp3026xo(vga, ctlr, 0x1A, mga->tvp[0x1A]);
465
 
466
	/* disable pclk and lclk */
467
	_tvp3026xo(vga, ctlr, 0x2C, 0x2A);
468
	_tvp3026xo(vga, ctlr, 0x2F, 0);
469
	_tvp3026xo(vga, ctlr, 0x2D, 0);
470
 
471
	trace("loading vga registers\n");
472
	/* vga misc, seq, and registers */
473
	vgao(MiscW, vga->misc);
474
 
475
	for(i = 2; i < 0x05; i++)
476
		vgaxo(Seqx, i, vga->sequencer[i]);
477
 
478
	vgaxo(Crtx, 0x11, vga->crt[0x11] & ~0x80);
479
	for(i = 0; i < 0x19; i++)
480
		vgaxo(Crtx, i, vga->crt[i]);
481
 
482
	/* apparently AGP needs this to restore start address */
483
	crtcexto(0, mga->crtcext[0]);
484
 
485
	trace("programming pclk\n");
486
	/* set up pclk */
487
	_tvp3026xo(vga, ctlr, 0x2C, 0);
488
	for(i = 0; i < 3; i++)
489
		_tvp3026xo(vga, ctlr, 0x2D, mga->pclk[i]);
490
	while(!(_tvp3026xi(vga, ctlr, 0x2D) & 0x40))
491
		;
492
 
493
	trace("programming lclk\n");
494
	/* set up lclk */
495
	_tvp3026xo(vga, ctlr, 0x39, mga->tvp[0x39]);
496
	_tvp3026xo(vga, ctlr, 0x2C, 0);
497
	for(i = 0; i < 3; i++)
498
		_tvp3026xo(vga, ctlr, 0x2F, mga->lclk[i]);
499
	while(!(_tvp3026xi(vga, ctlr, 0x2F) & 0x40))
500
		;
501
 
502
	trace("loading tvp registers\n");
503
	/* tvp registers, order matters */
504
	_tvp3026xo(vga, ctlr, 0x0F, mga->tvp[0x0F]);
505
	_tvp3026xo(vga, ctlr, 0x18, mga->tvp[0x18]);
506
	_tvp3026xo(vga, ctlr, 0x19, mga->tvp[0x19]);
507
	_tvp3026xo(vga, ctlr, 0x1A, mga->tvp[0x1A]);
508
	_tvp3026xo(vga, ctlr, 0x1C, mga->tvp[0x1C]);
509
	_tvp3026xo(vga, ctlr, 0x1D, mga->tvp[0x1D]);
510
	_tvp3026xo(vga, ctlr, 0x1E, mga->tvp[0x1E]);
511
	_tvp3026xo(vga, ctlr, 0x2A, mga->tvp[0x2A]);
512
	_tvp3026xo(vga, ctlr, 0x2B, mga->tvp[0x2B]);
513
	_tvp3026xo(vga, ctlr, 0x30, mga->tvp[0x30]);
514
	_tvp3026xo(vga, ctlr, 0x31, mga->tvp[0x31]);
515
	_tvp3026xo(vga, ctlr, 0x32, mga->tvp[0x32]);
516
	_tvp3026xo(vga, ctlr, 0x33, mga->tvp[0x33]);
517
	_tvp3026xo(vga, ctlr, 0x34, mga->tvp[0x34]);
518
	_tvp3026xo(vga, ctlr, 0x35, mga->tvp[0x35]);
519
	_tvp3026xo(vga, ctlr, 0x36, mga->tvp[0x36]);
520
	_tvp3026xo(vga, ctlr, 0x37, mga->tvp[0x37]);
521
	_tvp3026xo(vga, ctlr, 0x38, mga->tvp[0x38]);
522
	_tvp3026xo(vga, ctlr, 0x39, mga->tvp[0x39]);
523
	_tvp3026xo(vga, ctlr, 0x3A, mga->tvp[0x3A]);
524
	_tvp3026xo(vga, ctlr, 0x06, mga->tvp[0x06]);
525
 
526
	trace("done mga load\n");
527
	ctlr->flag |= Fload;
528
}
529
 
530
static void
531
dump(Vga* vga, Ctlr* ctlr)
532
{
533
	int i;
534
	char *name;
535
	Mga *mga;
536
 
537
	name = ctlr->name;
538
	mga = vga->private;
539
 
540
	printitem(name, "Devctrl");
541
	printreg(mga->devctrl);
542
 
543
	printitem(name, "Option");
544
	printreg(mga->option);
545
 
546
	printitem(name, "Crtcext");
547
	for(i = 0; i < 0x06; i++)
548
		printreg(mga->crtcext[i]);
549
 
550
	printitem(name, "TVP");
551
	for(i = 0; i < 64; i++)
552
		printreg(mga->tvp[i]);
553
 
554
	printitem(name, "PCLK");
555
	for(i = 0; i < 3; i++)
556
		printreg(mga->pclk[i]);
557
 
558
	printitem(name, "MCLK");
559
	for(i = 0; i < 3; i++)
560
		printreg(mga->mclk[i]);
561
 
562
	printitem(name, "LCLK");
563
	for(i = 0; i < 3; i++)
564
		printreg(mga->lclk[i]);
565
}
566
 
567
Ctlr mga2164w = {
568
	"mga2164w",			/* name */
569
	snarf,				/* snarf */
570
	options,			/* options */
571
	init,				/* init */
572
	load,				/* load */
573
	dump,				/* dump */
574
};
575
 
576
Ctlr mga2164whwgc = {
577
	"mga2164whwgc",			/* name */
578
	0,				/* snarf */
579
	0,				/* options */
580
	0,				/* init */
581
	0,				/* load */
582
	dump,				/* dump */
583
};