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 "../port/lib.h"
3
#include "mem.h"
4
#include "dat.h"
5
#include "fns.h"
6
#include "io.h"
7
#include "../port/error.h"
8
 
9
#define	Image	IMAGE
10
#include <draw.h>
11
#include <memdraw.h>
12
#include <cursor.h>
13
#include "screen.h"
14
 
15
enum {
16
	PCIS3		= 0x5333,		/* PCI VID */
17
 
18
	SAVAGE3D	= 0x8A20,		/* PCI DID */
19
	SAVAGE3DMV	= 0x8A21,
20
	SAVAGE4		= 0x8A22,
21
	PROSAVAGEP	= 0x8A25,
22
	PROSAVAGEK	= 0x8A26,
23
	PROSAVAGE8	= 0x8D04,
24
	SAVAGEMXMV	= 0x8C10,
25
	SAVAGEMX	= 0x8C11,
26
	SAVAGEIXMV	= 0x8C12,
27
	SAVAGEIX	= 0x8C13,
28
	SUPERSAVAGEIXC16 = 0x8C2E,
29
	SAVAGE2000	= 0x9102,
30
 
31
	VIRGE		= 0x5631,
32
	VIRGEGX2	= 0x8A10,
33
	VIRGEDXGX	= 0x8A01,
34
	VIRGEVX		= 0x883D,
35
	VIRGEMX		= 0x8C01,
36
	VIRGEMXP	= 0x8C03,
37
 
38
	VIRTUALPC2004	= 0x8810,
39
	AURORA64VPLUS	= 0x8812,
40
};
41
 
42
static int
43
s3pageset(VGAscr* scr, int page)
44
{
45
	uchar crt35, crt51;
46
	int opage;
47
 
48
	crt35 = vgaxi(Crtx, 0x35);
49
	if(scr->gscreen->depth >= 8){
50
		/*
51
		 * The S3 registers need to be unlocked for this.
52
		 * Let's hope they are already:
53
		 *	vgaxo(Crtx, 0x38, 0x48);
54
		 *	vgaxo(Crtx, 0x39, 0xA0);
55
		 *
56
		 * The page is 6 bits, the lower 4 bits in Crt35<3:0>,
57
		 * the upper 2 in Crt51<3:2>.
58
		 */
59
		vgaxo(Crtx, 0x35, page & 0x0F);
60
		crt51 = vgaxi(Crtx, 0x51);
61
		vgaxo(Crtx, 0x51, (crt51 & ~0x0C)|((page & 0x30)>>2));
62
		opage = ((crt51 & 0x0C)<<2)|(crt35 & 0x0F);
63
	}
64
	else{
65
		vgaxo(Crtx, 0x35, (page<<2) & 0x0C);
66
		opage = (crt35>>2) & 0x03;
67
	}
68
 
69
	return opage;
70
}
71
 
72
static void
73
s3page(VGAscr* scr, int page)
74
{
75
	int id;
76
 
77
	id = (vgaxi(Crtx, 0x2D)<<8)|vgaxi(Crtx, 0x2E);
78
	switch(id){
79
 
80
	case VIRGEGX2:
81
		break;
82
 
83
	default:
84
		lock(&scr->devlock);
85
		s3pageset(scr, page);
86
		unlock(&scr->devlock);
87
		break;
88
	}
89
}
90
 
91
static void
92
s3linear(VGAscr* scr, int, int)
93
{
94
	int id, j;
95
	ulong mmiobase, mmiosize;
96
	Pcidev *p;
97
 
98
	vgalinearpciid(scr, PCIS3, 0);
99
	p = scr->pci;
100
	if(scr->paddr == 0 || p == nil)
101
		return;
102
 
103
	addvgaseg("s3screen", scr->paddr, scr->apsize);
104
 
105
	id = (vgaxi(Crtx, 0x2D)<<8)|vgaxi(Crtx, 0x2E);
106
	switch(id){			/* find mmio */
107
	case SAVAGE4:
108
	case PROSAVAGEP:
109
	case PROSAVAGEK:
110
	case PROSAVAGE8:
111
	case SUPERSAVAGEIXC16:
112
		/*
113
		 * We could assume that the MMIO registers
114
		 * will be in the screen segment and just use
115
		 * that, but PCI software is allowed to move them
116
		 * if it feels like it, so we look for an aperture of
117
		 * the right size; only the first 512k actually means
118
		 * anything.  The S3 engineers overestimated how
119
		 * much space they would need in the first design.
120
		 */
121
		for(j=0; j<nelem(p->mem); j++){
122
			if((p->mem[j].bar&~0x0F) != scr->paddr)
123
			if(p->mem[j].size==512*1024 || p->mem[j].size==16*1024*1024){
124
				mmiobase = p->mem[j].bar & ~0x0F;
125
				mmiosize = 512*1024;
126
				scr->mmio = vmap(mmiobase, mmiosize);
127
				if(scr->mmio == nil)
128
					return;
129
				addvgaseg("savagemmio", mmiobase, mmiosize);
130
				break;
131
			}
132
		}
133
	}
134
}
135
 
136
static void
137
s3vsyncactive(void)
138
{
139
	/*
140
	 * Hardware cursor information is fetched from display memory
141
	 * during the horizontal blank active time. The 80x chips may hang
142
	 * if the cursor is turned on or off during this period.
143
	 */
144
	while((vgai(Status1) & 0x08) == 0)
145
		;
146
}
147
 
148
static void
149
s3disable(VGAscr*)
150
{
151
	uchar crt45;
152
 
153
	/*
154
	 * Turn cursor off.
155
	 */
156
	crt45 = vgaxi(Crtx, 0x45) & 0xFE;
157
	s3vsyncactive();
158
	vgaxo(Crtx, 0x45, crt45);
159
}
160
 
161
static void
162
s3load(VGAscr* scr, Cursor* curs)
163
{
164
	uchar *p;
165
	int id, dolock, opage, x, y;
166
 
167
	/*
168
	 * Disable the cursor and
169
	 * set the pointer to the two planes.
170
	 */
171
	s3disable(scr);
172
 
173
	opage = 0;
174
	p = scr->vaddr;
175
	id = (vgaxi(Crtx, 0x2D)<<8)|vgaxi(Crtx, 0x2E);
176
	switch(id){
177
 
178
	case VIRTUALPC2004:
179
	case VIRGE:
180
	case VIRGEDXGX:
181
	case VIRGEGX2:
182
	case VIRGEVX:	
183
	case SAVAGEMXMV:
184
	case SAVAGEIXMV:
185
	case SAVAGE4:
186
	case PROSAVAGEP:
187
	case PROSAVAGEK:
188
	case PROSAVAGE8:
189
	case SUPERSAVAGEIXC16:
190
		dolock = 0;
191
		p += scr->storage;
192
		break;
193
 
194
	default:
195
		dolock = 1;
196
		lock(&scr->devlock);
197
		opage = s3pageset(scr, scr->storage>>16);
198
		p += (scr->storage & 0xFFFF);
199
		break;
200
	}
201
 
202
	/*
203
	 * The cursor is set in Microsoft Windows format (the ViRGE/GX2 doesn't
204
	 * support the X11 format) which gives the following truth table:
205
	 *	and xor	colour
206
	 *	 0   0	background colour
207
	 *	 0   1	foreground colour
208
	 *	 1   0	current screen pixel
209
	 *	 1   1	NOT current screen pixel
210
	 * Put the cursor into the top-left of the 64x64 array.
211
	 *
212
	 * The cursor pattern in memory is interleaved words of
213
	 * AND and XOR patterns.
214
	 */
215
	for(y = 0; y < 64; y++){
216
		for(x = 0; x < 64/8; x += 2){
217
			if(x < 16/8 && y < 16){
218
				*p++ = ~(curs->clr[2*y + x]|curs->set[2*y + x]);
219
				*p++ = ~(curs->clr[2*y + x+1]|curs->set[2*y + x+1]);
220
				*p++ = curs->set[2*y + x];
221
				*p++ = curs->set[2*y + x+1];
222
			}
223
			else {
224
				*p++ = 0xFF;
225
				*p++ = 0xFF;
226
				*p++ = 0x00;
227
				*p++ = 0x00;
228
			}
229
		}
230
	}
231
 
232
	if(dolock){
233
		s3pageset(scr, opage);
234
		unlock(&scr->devlock);
235
	}
236
 
237
	/*
238
	 * Save the cursor hotpoint and enable the cursor.
239
	 */
240
	scr->offset = curs->offset;
241
	s3vsyncactive();
242
	vgaxo(Crtx, 0x45, 0x01);
243
}
244
 
245
static int
246
s3move(VGAscr* scr, Point p)
247
{
248
	int x, xo, y, yo;
249
 
250
	/*
251
	 * Mustn't position the cursor offscreen even partially,
252
	 * or it disappears. Therefore, if x or y is -ve, adjust the
253
	 * cursor offset instead.
254
	 * There seems to be a bug in that if the offset is 1, the
255
	 * cursor doesn't disappear off the left edge properly, so
256
	 * round it up to be even.
257
	 */
258
	if((x = p.x+scr->offset.x) < 0){
259
		xo = -x;
260
		xo = ((xo+1)/2)*2;
261
		x = 0;
262
	}
263
	else
264
		xo = 0;
265
	if((y = p.y+scr->offset.y) < 0){
266
		yo = -y;
267
		y = 0;
268
	}
269
	else
270
		yo = 0;
271
 
272
	vgaxo(Crtx, 0x46, (x>>8) & 0x07);
273
	vgaxo(Crtx, 0x47, x & 0xFF);
274
	vgaxo(Crtx, 0x49, y & 0xFF);
275
	vgaxo(Crtx, 0x4E, xo);
276
	vgaxo(Crtx, 0x4F, yo);
277
	vgaxo(Crtx, 0x48, (y>>8) & 0x07);
278
 
279
	return 0;
280
}
281
 
282
static void
283
s3enable(VGAscr* scr)
284
{
285
	int i;
286
	ulong storage;
287
 
288
	s3disable(scr);
289
 
290
	/*
291
	 * Cursor colours. Set both the CR0[EF] and the colour
292
	 * stack in case we are using a 16-bit RAMDAC.
293
	 */
294
	vgaxo(Crtx, 0x0E, Pwhite);
295
	vgaxo(Crtx, 0x0F, Pblack);
296
	vgaxi(Crtx, 0x45);
297
 
298
	for(i = 0; i < 3; i++)
299
		vgaxo(Crtx, 0x4A, Pblack);
300
	vgaxi(Crtx, 0x45);
301
	for(i = 0; i < 3; i++)
302
		vgaxo(Crtx, 0x4B, Pwhite);
303
 
304
	/*
305
	 * Find a place for the cursor data in display memory.
306
	 * Must be on a 1024-byte boundary.
307
	 */
308
	storage = (scr->gscreen->width*BY2WD*scr->gscreen->r.max.y+1023)/1024;
309
	vgaxo(Crtx, 0x4C, storage>>8);
310
	vgaxo(Crtx, 0x4D, storage & 0xFF);
311
	storage *= 1024;
312
	scr->storage = storage;
313
 
314
	/*
315
	 * Load, locate and enable the cursor
316
	 * in Microsoft Windows format.
317
	 */
318
	s3load(scr, &arrow);
319
	s3move(scr, ZP);
320
	vgaxo(Crtx, 0x55, vgaxi(Crtx, 0x55) & ~0x10);
321
	s3vsyncactive();
322
	vgaxo(Crtx, 0x45, 0x01);
323
}
324
 
325
/*
326
 * The manual gives byte offsets, but we want ulong offsets, hence /4.
327
 */
328
enum {
329
	SrcBase = 0xA4D4/4,
330
	DstBase = 0xA4D8/4,
331
	Stride = 0xA4E4/4,
332
	FgrdData = 0xA4F4/4,
333
	WidthHeight = 0xA504/4,
334
	SrcXY = 0xA508/4,
335
	DestXY = 0xA50C/4,
336
	Command = 0xA500/4,
337
	SubStat = 0x8504/4,
338
	FifoStat = 0x850C/4,
339
};
340
 
341
/*
342
 * Wait for writes to VGA memory via linear aperture to flush.
343
 */
344
enum {Maxloop = 1<<24};
345
struct {
346
	ulong linear;
347
	ulong fifo;
348
	ulong idle;
349
	ulong lineartimeout;
350
	ulong fifotimeout;
351
	ulong idletimeout;
352
} waitcount;
353
 
354
static void
355
waitforlinearfifo(VGAscr *scr)
356
{
357
	ulong *mmio;
358
	long x;
359
	static ulong nwaitforlinearfifo;
360
	ulong mask, val;
361
 
362
	switch(scr->id){
363
	default:
364
		panic("unknown scr->id in s3 waitforlinearfifo");
365
	case 0x8A01:	/* ViRGE/[DG]X.  XFree86 says no waiting necessary */
366
		return;
367
	case 0x5631:	/* ViRGE */
368
	case 0x883D:	/* ViRGE/VX */
369
		mask = 0x0F<<6;
370
		val = 0x08<<6;
371
		break;
372
	case 0x8A10:	/* ViRGE/GX2 */
373
		mask = 0x1F<<6;
374
		val = 0x10<<6;
375
		break;
376
	}
377
	mmio = scr->mmio;
378
	x = 0;
379
	while((mmio[FifoStat]&mask) != val && x++ < Maxloop)
380
		waitcount.linear++;
381
	if(x >= Maxloop)
382
		waitcount.lineartimeout++;
383
}
384
 
385
static void
386
waitforfifo(VGAscr *scr, int entries)
387
{
388
	ulong *mmio;
389
	long x;
390
	static ulong nwaitforfifo;
391
 
392
	mmio = scr->mmio;
393
	x = 0;
394
	while((mmio[SubStat]&0x1F00) < ((entries+2)<<8) && x++ < Maxloop)
395
		waitcount.fifo++;
396
	if(x >= Maxloop)
397
		waitcount.fifotimeout++;
398
}
399
 
400
static void
401
waitforidle(VGAscr *scr)
402
{
403
	ulong *mmio;
404
	long x;
405
 
406
	mmio = scr->mmio;
407
	x = 0;
408
	while((mmio[SubStat]&0x3F00) != 0x3000 && x++ < Maxloop)
409
		waitcount.idle++;
410
	if(x >= Maxloop)
411
		waitcount.idletimeout++;
412
}
413
 
414
static int
415
hwscroll(VGAscr *scr, Rectangle r, Rectangle sr)
416
{
417
	enum { Bitbltop = 0xCC };	/* copy source */
418
	ulong *mmio;
419
	ulong cmd, stride;
420
	Point dp, sp;
421
	int did, d;
422
 
423
	d = scr->gscreen->depth;
424
	did = (d-8)/8;
425
	cmd = 0x00000020|(Bitbltop<<17)|(did<<2);
426
	stride = Dx(scr->gscreen->r)*d/8;
427
 
428
	if(r.min.x <= sr.min.x){
429
		cmd |= 1<<25;
430
		dp.x = r.min.x;
431
		sp.x = sr.min.x;
432
	}else{
433
		dp.x = r.max.x-1;
434
		sp.x = sr.max.x-1;
435
	}
436
 
437
	if(r.min.y <= sr.min.y){
438
		cmd |= 1<<26;
439
		dp.y = r.min.y;
440
		sp.y = sr.min.y;
441
	}else{
442
		dp.y = r.max.y-1;
443
		sp.y = sr.max.y-1;
444
	}
445
 
446
	mmio = scr->mmio;
447
	waitforlinearfifo(scr);
448
	waitforfifo(scr, 7);
449
	mmio[SrcBase] = scr->paddr;
450
	mmio[DstBase] = scr->paddr;
451
	mmio[Stride] = (stride<<16)|stride;
452
	mmio[WidthHeight] = ((Dx(r)-1)<<16)|Dy(r);
453
	mmio[SrcXY] = (sp.x<<16)|sp.y;
454
	mmio[DestXY] = (dp.x<<16)|dp.y;
455
	mmio[Command] = cmd;
456
	waitforidle(scr);
457
	return 1;
458
}
459
 
460
static int
461
hwfill(VGAscr *scr, Rectangle r, ulong sval)
462
{
463
	enum { Bitbltop = 0xCC };	/* copy source */
464
	ulong *mmio;
465
	ulong cmd, stride;
466
	int did, d;
467
 
468
	d = scr->gscreen->depth;
469
	did = (d-8)/8;
470
	cmd = 0x16000120|(Bitbltop<<17)|(did<<2);
471
	stride = Dx(scr->gscreen->r)*d/8;
472
	mmio = scr->mmio;
473
	waitforlinearfifo(scr);
474
	waitforfifo(scr, 8);
475
	mmio[SrcBase] = scr->paddr;
476
	mmio[DstBase] = scr->paddr;
477
	mmio[DstBase] = scr->paddr;
478
	mmio[Stride] = (stride<<16)|stride;
479
	mmio[FgrdData] = sval;
480
	mmio[WidthHeight] = ((Dx(r)-1)<<16)|Dy(r);
481
	mmio[DestXY] = (r.min.x<<16)|r.min.y;
482
	mmio[Command] = cmd;
483
	waitforidle(scr);
484
	return 1;
485
}
486
 
487
enum {
488
	CursorSyncCtl = 0x0D,	/* in Seqx */
489
	VsyncHi = 0x80,
490
	VsyncLo = 0x40,
491
	HsyncHi = 0x20,
492
	HsyncLo = 0x10,
493
};
494
 
495
static void
496
s3blank(VGAscr*, int blank)
497
{
498
	uchar x;
499
 
500
	x = vgaxi(Seqx, CursorSyncCtl);
501
	x &= ~0xF0;
502
	if(blank)
503
		x |= VsyncLo | HsyncLo;
504
	vgaxo(Seqx, CursorSyncCtl, x);
505
}
506
 
507
static void
508
s3drawinit(VGAscr *scr)
509
{
510
	extern void savageinit(VGAscr*);	/* vgasavage.c */
511
	ulong id;
512
 
513
	id = (vgaxi(Crtx, 0x2D)<<8)|vgaxi(Crtx, 0x2E);
514
	scr->id = id;
515
 
516
	/*
517
	 * It's highly likely that other ViRGEs will work without
518
	 * change to the driver, with the exception of the size of
519
	 * the linear aperture memory write FIFO.  Since we don't
520
	 * know that size, I'm not turning them on.  See waitforlinearfifo
521
	 * above.
522
	 */
523
	scr->blank = s3blank;
524
	/* hwblank = 1;		not known to work well */
525
 
526
	switch(id){
527
	case VIRGE:
528
	case VIRGEVX:
529
	case VIRGEGX2:
530
		scr->mmio = (ulong*)((char*)scr->vaddr+0x1000000);
531
		scr->fill = hwfill;
532
		scr->scroll = hwscroll;
533
		break;
534
	case SAVAGEMXMV:
535
	case SAVAGEIXMV:
536
		scr->mmio = (ulong*)((char*)scr->vaddr+0x1000000);
537
		savageinit(scr);	
538
		break;
539
	case SUPERSAVAGEIXC16:
540
	case SAVAGE4:
541
	case PROSAVAGEP:
542
	case PROSAVAGE8:
543
	case PROSAVAGEK:
544
		/* scr->mmio is set by s3linear */
545
		savageinit(scr);
546
		break;
547
	}
548
}
549
 
550
VGAdev vgas3dev = {
551
	"s3",
552
 
553
	0,
554
	0,
555
	s3page,
556
	s3linear,
557
	s3drawinit,
558
};
559
 
560
VGAcur vgas3cur = {
561
	"s3hwgc",
562
 
563
	s3enable,
564
	s3disable,
565
	s3load,
566
	s3move,
567
};
568