xref: /plan9/sys/src/9/pc/vgas3.c (revision 4de34a7edde43207e841ec91ecd12e6cf5f5ebe7)
1219b2ee8SDavid du Colombier #include "u.h"
2219b2ee8SDavid du Colombier #include "../port/lib.h"
3219b2ee8SDavid du Colombier #include "mem.h"
4219b2ee8SDavid du Colombier #include "dat.h"
5219b2ee8SDavid du Colombier #include "fns.h"
67dd7cddfSDavid du Colombier #include "io.h"
7219b2ee8SDavid du Colombier #include "../port/error.h"
8219b2ee8SDavid du Colombier 
97dd7cddfSDavid du Colombier #define	Image	IMAGE
107dd7cddfSDavid du Colombier #include <draw.h>
117dd7cddfSDavid du Colombier #include <memdraw.h>
127dd7cddfSDavid du Colombier #include <cursor.h>
13219b2ee8SDavid du Colombier #include "screen.h"
14219b2ee8SDavid du Colombier 
1559cc4ca5SDavid du Colombier enum {
1659cc4ca5SDavid du Colombier 	PCIS3		= 0x5333,		/* PCI VID */
1759cc4ca5SDavid du Colombier 
1859cc4ca5SDavid du Colombier 	SAVAGE3D	= 0x8A20,		/* PCI DID */
1959cc4ca5SDavid du Colombier 	SAVAGE3DMV	= 0x8A21,
2059cc4ca5SDavid du Colombier 	SAVAGE4		= 0x8A22,
210b459c2cSDavid du Colombier 	PROSAVAGEP	= 0x8A25,
220b459c2cSDavid du Colombier 	PROSAVAGEK	= 0x8A26,
2319dc9ffeSDavid du Colombier 	PROSAVAGE8	= 0x8D04,
2459cc4ca5SDavid du Colombier 	SAVAGEMXMV	= 0x8C10,
2559cc4ca5SDavid du Colombier 	SAVAGEMX	= 0x8C11,
2659cc4ca5SDavid du Colombier 	SAVAGEIXMV	= 0x8C12,
2759cc4ca5SDavid du Colombier 	SAVAGEIX	= 0x8C13,
289a747e4fSDavid du Colombier 	SUPERSAVAGEIXC16 = 0x8C2E,
2959cc4ca5SDavid du Colombier 	SAVAGE2000	= 0x9102,
3059cc4ca5SDavid du Colombier 
3159cc4ca5SDavid du Colombier 	VIRGE		= 0x5631,
3259cc4ca5SDavid du Colombier 	VIRGEGX2	= 0x8A10,
3359cc4ca5SDavid du Colombier 	VIRGEDXGX	= 0x8A01,
3459cc4ca5SDavid du Colombier 	VIRGEVX		= 0x883D,
3559cc4ca5SDavid du Colombier 	VIRGEMX		= 0x8C01,
3659cc4ca5SDavid du Colombier 	VIRGEMXP	= 0x8C03,
3759cc4ca5SDavid du Colombier 
38a4285193SDavid du Colombier 	VIRTUALPC2004	= 0x8810,
3959cc4ca5SDavid du Colombier 	AURORA64VPLUS	= 0x8812,
4059cc4ca5SDavid du Colombier };
4159cc4ca5SDavid du Colombier 
427dd7cddfSDavid du Colombier static int
s3pageset(VGAscr * scr,int page)437dd7cddfSDavid du Colombier s3pageset(VGAscr* scr, int page)
44219b2ee8SDavid du Colombier {
457dd7cddfSDavid du Colombier 	uchar crt35, crt51;
467dd7cddfSDavid du Colombier 	int opage;
47219b2ee8SDavid du Colombier 
487dd7cddfSDavid du Colombier 	crt35 = vgaxi(Crtx, 0x35);
497dd7cddfSDavid du Colombier 	if(scr->gscreen->depth >= 8){
50219b2ee8SDavid du Colombier 		/*
51219b2ee8SDavid du Colombier 		 * The S3 registers need to be unlocked for this.
52219b2ee8SDavid du Colombier 		 * Let's hope they are already:
53219b2ee8SDavid du Colombier 		 *	vgaxo(Crtx, 0x38, 0x48);
54219b2ee8SDavid du Colombier 		 *	vgaxo(Crtx, 0x39, 0xA0);
55219b2ee8SDavid du Colombier 		 *
56219b2ee8SDavid du Colombier 		 * The page is 6 bits, the lower 4 bits in Crt35<3:0>,
57219b2ee8SDavid du Colombier 		 * the upper 2 in Crt51<3:2>.
58219b2ee8SDavid du Colombier 		 */
59219b2ee8SDavid du Colombier 		vgaxo(Crtx, 0x35, page & 0x0F);
607dd7cddfSDavid du Colombier 		crt51 = vgaxi(Crtx, 0x51);
617dd7cddfSDavid du Colombier 		vgaxo(Crtx, 0x51, (crt51 & ~0x0C)|((page & 0x30)>>2));
627dd7cddfSDavid du Colombier 		opage = ((crt51 & 0x0C)<<2)|(crt35 & 0x0F);
63219b2ee8SDavid du Colombier 	}
647dd7cddfSDavid du Colombier 	else{
65219b2ee8SDavid du Colombier 		vgaxo(Crtx, 0x35, (page<<2) & 0x0C);
667dd7cddfSDavid du Colombier 		opage = (crt35>>2) & 0x03;
677dd7cddfSDavid du Colombier 	}
687dd7cddfSDavid du Colombier 
697dd7cddfSDavid du Colombier 	return opage;
70219b2ee8SDavid du Colombier }
71219b2ee8SDavid du Colombier 
72219b2ee8SDavid du Colombier static void
s3page(VGAscr * scr,int page)737dd7cddfSDavid du Colombier s3page(VGAscr* scr, int page)
747dd7cddfSDavid du Colombier {
757dd7cddfSDavid du Colombier 	int id;
767dd7cddfSDavid du Colombier 
7759cc4ca5SDavid du Colombier 	id = (vgaxi(Crtx, 0x2D)<<8)|vgaxi(Crtx, 0x2E);
787dd7cddfSDavid du Colombier 	switch(id){
797dd7cddfSDavid du Colombier 
8059cc4ca5SDavid du Colombier 	case VIRGEGX2:
817dd7cddfSDavid du Colombier 		break;
827dd7cddfSDavid du Colombier 
837dd7cddfSDavid du Colombier 	default:
847dd7cddfSDavid du Colombier 		lock(&scr->devlock);
857dd7cddfSDavid du Colombier 		s3pageset(scr, page);
867dd7cddfSDavid du Colombier 		unlock(&scr->devlock);
877dd7cddfSDavid du Colombier 		break;
887dd7cddfSDavid du Colombier 	}
897dd7cddfSDavid du Colombier }
907dd7cddfSDavid du Colombier 
91*4de34a7eSDavid du Colombier static void
s3linear(VGAscr * scr,int,int)92*4de34a7eSDavid du Colombier s3linear(VGAscr* scr, int, int)
937dd7cddfSDavid du Colombier {
94*4de34a7eSDavid du Colombier 	int id, j;
95*4de34a7eSDavid du Colombier 	ulong mmiobase, mmiosize;
967dd7cddfSDavid du Colombier 	Pcidev *p;
977dd7cddfSDavid du Colombier 
98*4de34a7eSDavid du Colombier 	vgalinearpciid(scr, PCIS3, 0);
99*4de34a7eSDavid du Colombier 	p = scr->pci;
100*4de34a7eSDavid du Colombier 	if(scr->paddr == 0 || p == nil)
101*4de34a7eSDavid du Colombier 		return;
10214414594SDavid du Colombier 
103*4de34a7eSDavid du Colombier 	addvgaseg("s3screen", scr->paddr, scr->apsize);
10414414594SDavid du Colombier 
10559cc4ca5SDavid du Colombier 	id = (vgaxi(Crtx, 0x2D)<<8)|vgaxi(Crtx, 0x2E);
1069a747e4fSDavid du Colombier 	switch(id){			/* find mmio */
1079a747e4fSDavid du Colombier 	case SAVAGE4:
1080b459c2cSDavid du Colombier 	case PROSAVAGEP:
1090b459c2cSDavid du Colombier 	case PROSAVAGEK:
11019dc9ffeSDavid du Colombier 	case PROSAVAGE8:
1119a747e4fSDavid du Colombier 	case SUPERSAVAGEIXC16:
11214414594SDavid du Colombier 		/*
11314414594SDavid du Colombier 		 * We could assume that the MMIO registers
11414414594SDavid du Colombier 		 * will be in the screen segment and just use
11514414594SDavid du Colombier 		 * that, but PCI software is allowed to move them
11614414594SDavid du Colombier 		 * if it feels like it, so we look for an aperture of
11714414594SDavid du Colombier 		 * the right size; only the first 512k actually means
11814414594SDavid du Colombier 		 * anything.  The S3 engineers overestimated how
11914414594SDavid du Colombier 		 * much space they would need in the first design.
12014414594SDavid du Colombier 		 */
12114414594SDavid du Colombier 		for(j=0; j<nelem(p->mem); j++){
122*4de34a7eSDavid du Colombier 			if((p->mem[j].bar&~0x0F) != scr->paddr)
12314414594SDavid du Colombier 			if(p->mem[j].size==512*1024 || p->mem[j].size==16*1024*1024){
12414414594SDavid du Colombier 				mmiobase = p->mem[j].bar & ~0x0F;
12514414594SDavid du Colombier 				mmiosize = 512*1024;
126*4de34a7eSDavid du Colombier 				scr->mmio = vmap(mmiobase, mmiosize);
127*4de34a7eSDavid du Colombier 				if(scr->mmio == nil)
128*4de34a7eSDavid du Colombier 					return;
129*4de34a7eSDavid du Colombier 				addvgaseg("savagemmio", mmiobase, mmiosize);
13014414594SDavid du Colombier 				break;
13114414594SDavid du Colombier 			}
13214414594SDavid du Colombier 		}
13314414594SDavid du Colombier 	}
13414414594SDavid du Colombier }
1357dd7cddfSDavid du Colombier 
1367dd7cddfSDavid du Colombier static void
s3vsyncactive(void)1377dd7cddfSDavid du Colombier s3vsyncactive(void)
138219b2ee8SDavid du Colombier {
139219b2ee8SDavid du Colombier 	/*
140219b2ee8SDavid du Colombier 	 * Hardware cursor information is fetched from display memory
141219b2ee8SDavid du Colombier 	 * during the horizontal blank active time. The 80x chips may hang
142219b2ee8SDavid du Colombier 	 * if the cursor is turned on or off during this period.
143219b2ee8SDavid du Colombier 	 */
144219b2ee8SDavid du Colombier 	while((vgai(Status1) & 0x08) == 0)
145219b2ee8SDavid du Colombier 		;
146219b2ee8SDavid du Colombier }
147219b2ee8SDavid du Colombier 
148219b2ee8SDavid du Colombier static void
s3disable(VGAscr *)1497dd7cddfSDavid du Colombier s3disable(VGAscr*)
150219b2ee8SDavid du Colombier {
151219b2ee8SDavid du Colombier 	uchar crt45;
152219b2ee8SDavid du Colombier 
153219b2ee8SDavid du Colombier 	/*
154219b2ee8SDavid du Colombier 	 * Turn cursor off.
155219b2ee8SDavid du Colombier 	 */
156219b2ee8SDavid du Colombier 	crt45 = vgaxi(Crtx, 0x45) & 0xFE;
1577dd7cddfSDavid du Colombier 	s3vsyncactive();
158219b2ee8SDavid du Colombier 	vgaxo(Crtx, 0x45, crt45);
159219b2ee8SDavid du Colombier }
160219b2ee8SDavid du Colombier 
161219b2ee8SDavid du Colombier static void
s3load(VGAscr * scr,Cursor * curs)1627dd7cddfSDavid du Colombier s3load(VGAscr* scr, Cursor* curs)
163219b2ee8SDavid du Colombier {
164219b2ee8SDavid du Colombier 	uchar *p;
1659a747e4fSDavid du Colombier 	int id, dolock, opage, x, y;
166219b2ee8SDavid du Colombier 
167219b2ee8SDavid du Colombier 	/*
1687dd7cddfSDavid du Colombier 	 * Disable the cursor and
1697dd7cddfSDavid du Colombier 	 * set the pointer to the two planes.
170219b2ee8SDavid du Colombier 	 */
1717dd7cddfSDavid du Colombier 	s3disable(scr);
1727dd7cddfSDavid du Colombier 
1737dd7cddfSDavid du Colombier 	opage = 0;
174*4de34a7eSDavid du Colombier 	p = scr->vaddr;
17559cc4ca5SDavid du Colombier 	id = (vgaxi(Crtx, 0x2D)<<8)|vgaxi(Crtx, 0x2E);
1767dd7cddfSDavid du Colombier 	switch(id){
1777dd7cddfSDavid du Colombier 
178a4285193SDavid du Colombier 	case VIRTUALPC2004:
17959cc4ca5SDavid du Colombier 	case VIRGE:
18059cc4ca5SDavid du Colombier 	case VIRGEDXGX:
18159cc4ca5SDavid du Colombier 	case VIRGEGX2:
18259cc4ca5SDavid du Colombier 	case VIRGEVX:
1839a747e4fSDavid du Colombier 	case SAVAGEMXMV:
18459cc4ca5SDavid du Colombier 	case SAVAGEIXMV:
18559cc4ca5SDavid du Colombier 	case SAVAGE4:
1860b459c2cSDavid du Colombier 	case PROSAVAGEP:
1870b459c2cSDavid du Colombier 	case PROSAVAGEK:
18819dc9ffeSDavid du Colombier 	case PROSAVAGE8:
1899a747e4fSDavid du Colombier 	case SUPERSAVAGEIXC16:
1909a747e4fSDavid du Colombier 		dolock = 0;
1917dd7cddfSDavid du Colombier 		p += scr->storage;
1927dd7cddfSDavid du Colombier 		break;
1937dd7cddfSDavid du Colombier 
1947dd7cddfSDavid du Colombier 	default:
1959a747e4fSDavid du Colombier 		dolock = 1;
1967dd7cddfSDavid du Colombier 		lock(&scr->devlock);
1977dd7cddfSDavid du Colombier 		opage = s3pageset(scr, scr->storage>>16);
1987dd7cddfSDavid du Colombier 		p += (scr->storage & 0xFFFF);
1997dd7cddfSDavid du Colombier 		break;
200219b2ee8SDavid du Colombier 	}
201219b2ee8SDavid du Colombier 
202219b2ee8SDavid du Colombier 	/*
20359cc4ca5SDavid du Colombier 	 * The cursor is set in Microsoft Windows format (the ViRGE/GX2 doesn't
20459cc4ca5SDavid du Colombier 	 * support the X11 format) which gives the following truth table:
205219b2ee8SDavid du Colombier 	 *	and xor	colour
2067dd7cddfSDavid du Colombier 	 *	 0   0	background colour
2077dd7cddfSDavid du Colombier 	 *	 0   1	foreground colour
2087dd7cddfSDavid du Colombier 	 *	 1   0	current screen pixel
2097dd7cddfSDavid du Colombier 	 *	 1   1	NOT current screen pixel
210219b2ee8SDavid du Colombier 	 * Put the cursor into the top-left of the 64x64 array.
211219b2ee8SDavid du Colombier 	 *
212219b2ee8SDavid du Colombier 	 * The cursor pattern in memory is interleaved words of
213219b2ee8SDavid du Colombier 	 * AND and XOR patterns.
214219b2ee8SDavid du Colombier 	 */
215219b2ee8SDavid du Colombier 	for(y = 0; y < 64; y++){
216219b2ee8SDavid du Colombier 		for(x = 0; x < 64/8; x += 2){
217219b2ee8SDavid du Colombier 			if(x < 16/8 && y < 16){
2187dd7cddfSDavid du Colombier 				*p++ = ~(curs->clr[2*y + x]|curs->set[2*y + x]);
2197dd7cddfSDavid du Colombier 				*p++ = ~(curs->clr[2*y + x+1]|curs->set[2*y + x+1]);
2207dd7cddfSDavid du Colombier 				*p++ = curs->set[2*y + x];
2217dd7cddfSDavid du Colombier 				*p++ = curs->set[2*y + x+1];
222219b2ee8SDavid du Colombier 			}
223219b2ee8SDavid du Colombier 			else {
2247dd7cddfSDavid du Colombier 				*p++ = 0xFF;
2257dd7cddfSDavid du Colombier 				*p++ = 0xFF;
226219b2ee8SDavid du Colombier 				*p++ = 0x00;
227219b2ee8SDavid du Colombier 				*p++ = 0x00;
228219b2ee8SDavid du Colombier 			}
229219b2ee8SDavid du Colombier 		}
230219b2ee8SDavid du Colombier 	}
231219b2ee8SDavid du Colombier 
2329a747e4fSDavid du Colombier 	if(dolock){
2337dd7cddfSDavid du Colombier 		s3pageset(scr, opage);
2347dd7cddfSDavid du Colombier 		unlock(&scr->devlock);
2357dd7cddfSDavid du Colombier 	}
2367dd7cddfSDavid du Colombier 
237219b2ee8SDavid du Colombier 	/*
2387dd7cddfSDavid du Colombier 	 * Save the cursor hotpoint and enable the cursor.
239219b2ee8SDavid du Colombier 	 */
2407dd7cddfSDavid du Colombier 	scr->offset = curs->offset;
2417dd7cddfSDavid du Colombier 	s3vsyncactive();
242219b2ee8SDavid du Colombier 	vgaxo(Crtx, 0x45, 0x01);
243219b2ee8SDavid du Colombier }
244219b2ee8SDavid du Colombier 
245219b2ee8SDavid du Colombier static int
s3move(VGAscr * scr,Point p)2467dd7cddfSDavid du Colombier s3move(VGAscr* scr, Point p)
247219b2ee8SDavid du Colombier {
248219b2ee8SDavid du Colombier 	int x, xo, y, yo;
249219b2ee8SDavid du Colombier 
250219b2ee8SDavid du Colombier 	/*
251219b2ee8SDavid du Colombier 	 * Mustn't position the cursor offscreen even partially,
252219b2ee8SDavid du Colombier 	 * or it disappears. Therefore, if x or y is -ve, adjust the
253219b2ee8SDavid du Colombier 	 * cursor offset instead.
254219b2ee8SDavid du Colombier 	 * There seems to be a bug in that if the offset is 1, the
255219b2ee8SDavid du Colombier 	 * cursor doesn't disappear off the left edge properly, so
256219b2ee8SDavid du Colombier 	 * round it up to be even.
257219b2ee8SDavid du Colombier 	 */
2587dd7cddfSDavid du Colombier 	if((x = p.x+scr->offset.x) < 0){
259219b2ee8SDavid du Colombier 		xo = -x;
260219b2ee8SDavid du Colombier 		xo = ((xo+1)/2)*2;
261219b2ee8SDavid du Colombier 		x = 0;
262219b2ee8SDavid du Colombier 	}
263219b2ee8SDavid du Colombier 	else
264219b2ee8SDavid du Colombier 		xo = 0;
2657dd7cddfSDavid du Colombier 	if((y = p.y+scr->offset.y) < 0){
266219b2ee8SDavid du Colombier 		yo = -y;
267219b2ee8SDavid du Colombier 		y = 0;
268219b2ee8SDavid du Colombier 	}
269219b2ee8SDavid du Colombier 	else
270219b2ee8SDavid du Colombier 		yo = 0;
271219b2ee8SDavid du Colombier 
272219b2ee8SDavid du Colombier 	vgaxo(Crtx, 0x46, (x>>8) & 0x07);
273219b2ee8SDavid du Colombier 	vgaxo(Crtx, 0x47, x & 0xFF);
274219b2ee8SDavid du Colombier 	vgaxo(Crtx, 0x49, y & 0xFF);
275219b2ee8SDavid du Colombier 	vgaxo(Crtx, 0x4E, xo);
276219b2ee8SDavid du Colombier 	vgaxo(Crtx, 0x4F, yo);
277219b2ee8SDavid du Colombier 	vgaxo(Crtx, 0x48, (y>>8) & 0x07);
278219b2ee8SDavid du Colombier 
279219b2ee8SDavid du Colombier 	return 0;
280219b2ee8SDavid du Colombier }
281219b2ee8SDavid du Colombier 
28259cc4ca5SDavid du Colombier static void
s3enable(VGAscr * scr)28359cc4ca5SDavid du Colombier s3enable(VGAscr* scr)
28459cc4ca5SDavid du Colombier {
28559cc4ca5SDavid du Colombier 	int i;
28659cc4ca5SDavid du Colombier 	ulong storage;
28759cc4ca5SDavid du Colombier 
28859cc4ca5SDavid du Colombier 	s3disable(scr);
28959cc4ca5SDavid du Colombier 
29059cc4ca5SDavid du Colombier 	/*
29159cc4ca5SDavid du Colombier 	 * Cursor colours. Set both the CR0[EF] and the colour
29259cc4ca5SDavid du Colombier 	 * stack in case we are using a 16-bit RAMDAC.
29359cc4ca5SDavid du Colombier 	 */
29459cc4ca5SDavid du Colombier 	vgaxo(Crtx, 0x0E, Pwhite);
29559cc4ca5SDavid du Colombier 	vgaxo(Crtx, 0x0F, Pblack);
29659cc4ca5SDavid du Colombier 	vgaxi(Crtx, 0x45);
29759cc4ca5SDavid du Colombier 
29859cc4ca5SDavid du Colombier 	for(i = 0; i < 3; i++)
29959cc4ca5SDavid du Colombier 		vgaxo(Crtx, 0x4A, Pblack);
30059cc4ca5SDavid du Colombier 	vgaxi(Crtx, 0x45);
30159cc4ca5SDavid du Colombier 	for(i = 0; i < 3; i++)
30259cc4ca5SDavid du Colombier 		vgaxo(Crtx, 0x4B, Pwhite);
30359cc4ca5SDavid du Colombier 
30459cc4ca5SDavid du Colombier 	/*
30559cc4ca5SDavid du Colombier 	 * Find a place for the cursor data in display memory.
30659cc4ca5SDavid du Colombier 	 * Must be on a 1024-byte boundary.
30759cc4ca5SDavid du Colombier 	 */
30859cc4ca5SDavid du Colombier 	storage = (scr->gscreen->width*BY2WD*scr->gscreen->r.max.y+1023)/1024;
30959cc4ca5SDavid du Colombier 	vgaxo(Crtx, 0x4C, storage>>8);
31059cc4ca5SDavid du Colombier 	vgaxo(Crtx, 0x4D, storage & 0xFF);
31159cc4ca5SDavid du Colombier 	storage *= 1024;
31259cc4ca5SDavid du Colombier 	scr->storage = storage;
31359cc4ca5SDavid du Colombier 
31459cc4ca5SDavid du Colombier 	/*
31559cc4ca5SDavid du Colombier 	 * Load, locate and enable the cursor
31659cc4ca5SDavid du Colombier 	 * in Microsoft Windows format.
31759cc4ca5SDavid du Colombier 	 */
31859cc4ca5SDavid du Colombier 	s3load(scr, &arrow);
31959cc4ca5SDavid du Colombier 	s3move(scr, ZP);
32059cc4ca5SDavid du Colombier 	vgaxo(Crtx, 0x55, vgaxi(Crtx, 0x55) & ~0x10);
32159cc4ca5SDavid du Colombier 	s3vsyncactive();
32259cc4ca5SDavid du Colombier 	vgaxo(Crtx, 0x45, 0x01);
32359cc4ca5SDavid du Colombier }
32459cc4ca5SDavid du Colombier 
3257dd7cddfSDavid du Colombier /*
3267dd7cddfSDavid du Colombier  * The manual gives byte offsets, but we want ulong offsets, hence /4.
3277dd7cddfSDavid du Colombier  */
3287dd7cddfSDavid du Colombier enum {
3297dd7cddfSDavid du Colombier 	SrcBase = 0xA4D4/4,
3307dd7cddfSDavid du Colombier 	DstBase = 0xA4D8/4,
3317dd7cddfSDavid du Colombier 	Stride = 0xA4E4/4,
3327dd7cddfSDavid du Colombier 	FgrdData = 0xA4F4/4,
3337dd7cddfSDavid du Colombier 	WidthHeight = 0xA504/4,
3347dd7cddfSDavid du Colombier 	SrcXY = 0xA508/4,
3357dd7cddfSDavid du Colombier 	DestXY = 0xA50C/4,
3367dd7cddfSDavid du Colombier 	Command = 0xA500/4,
3377dd7cddfSDavid du Colombier 	SubStat = 0x8504/4,
3387dd7cddfSDavid du Colombier 	FifoStat = 0x850C/4,
3397dd7cddfSDavid du Colombier };
340219b2ee8SDavid du Colombier 
3417dd7cddfSDavid du Colombier /*
3427dd7cddfSDavid du Colombier  * Wait for writes to VGA memory via linear aperture to flush.
3437dd7cddfSDavid du Colombier  */
3447dd7cddfSDavid du Colombier enum {Maxloop = 1<<24};
3457dd7cddfSDavid du Colombier struct {
3467dd7cddfSDavid du Colombier 	ulong linear;
3477dd7cddfSDavid du Colombier 	ulong fifo;
3487dd7cddfSDavid du Colombier 	ulong idle;
34914414594SDavid du Colombier 	ulong lineartimeout;
35014414594SDavid du Colombier 	ulong fifotimeout;
35114414594SDavid du Colombier 	ulong idletimeout;
3527dd7cddfSDavid du Colombier } waitcount;
3537dd7cddfSDavid du Colombier 
3547dd7cddfSDavid du Colombier static void
waitforlinearfifo(VGAscr * scr)3557dd7cddfSDavid du Colombier waitforlinearfifo(VGAscr *scr)
3567dd7cddfSDavid du Colombier {
3577dd7cddfSDavid du Colombier 	ulong *mmio;
3587dd7cddfSDavid du Colombier 	long x;
3597dd7cddfSDavid du Colombier 	static ulong nwaitforlinearfifo;
3607dd7cddfSDavid du Colombier 	ulong mask, val;
3617dd7cddfSDavid du Colombier 
3627dd7cddfSDavid du Colombier 	switch(scr->id){
3637dd7cddfSDavid du Colombier 	default:
3647dd7cddfSDavid du Colombier 		panic("unknown scr->id in s3 waitforlinearfifo");
365fb7f0c93SDavid du Colombier 	case 0x8A01:	/* ViRGE/[DG]X.  XFree86 says no waiting necessary */
366fb7f0c93SDavid du Colombier 		return;
36759cc4ca5SDavid du Colombier 	case 0x5631:	/* ViRGE */
36859cc4ca5SDavid du Colombier 	case 0x883D:	/* ViRGE/VX */
3697dd7cddfSDavid du Colombier 		mask = 0x0F<<6;
3707dd7cddfSDavid du Colombier 		val = 0x08<<6;
3717dd7cddfSDavid du Colombier 		break;
37259cc4ca5SDavid du Colombier 	case 0x8A10:	/* ViRGE/GX2 */
3737dd7cddfSDavid du Colombier 		mask = 0x1F<<6;
3747dd7cddfSDavid du Colombier 		val = 0x10<<6;
3757dd7cddfSDavid du Colombier 		break;
3767dd7cddfSDavid du Colombier 	}
3777dd7cddfSDavid du Colombier 	mmio = scr->mmio;
3787dd7cddfSDavid du Colombier 	x = 0;
3797dd7cddfSDavid du Colombier 	while((mmio[FifoStat]&mask) != val && x++ < Maxloop)
3807dd7cddfSDavid du Colombier 		waitcount.linear++;
38114414594SDavid du Colombier 	if(x >= Maxloop)
38214414594SDavid du Colombier 		waitcount.lineartimeout++;
3837dd7cddfSDavid du Colombier }
3847dd7cddfSDavid du Colombier 
3857dd7cddfSDavid du Colombier static void
waitforfifo(VGAscr * scr,int entries)3867dd7cddfSDavid du Colombier waitforfifo(VGAscr *scr, int entries)
3877dd7cddfSDavid du Colombier {
3887dd7cddfSDavid du Colombier 	ulong *mmio;
3897dd7cddfSDavid du Colombier 	long x;
3907dd7cddfSDavid du Colombier 	static ulong nwaitforfifo;
3917dd7cddfSDavid du Colombier 
3927dd7cddfSDavid du Colombier 	mmio = scr->mmio;
3937dd7cddfSDavid du Colombier 	x = 0;
3947dd7cddfSDavid du Colombier 	while((mmio[SubStat]&0x1F00) < ((entries+2)<<8) && x++ < Maxloop)
3957dd7cddfSDavid du Colombier 		waitcount.fifo++;
39614414594SDavid du Colombier 	if(x >= Maxloop)
39714414594SDavid du Colombier 		waitcount.fifotimeout++;
3987dd7cddfSDavid du Colombier }
3997dd7cddfSDavid du Colombier 
4007dd7cddfSDavid du Colombier static void
waitforidle(VGAscr * scr)4017dd7cddfSDavid du Colombier waitforidle(VGAscr *scr)
4027dd7cddfSDavid du Colombier {
4037dd7cddfSDavid du Colombier 	ulong *mmio;
4047dd7cddfSDavid du Colombier 	long x;
4057dd7cddfSDavid du Colombier 
4067dd7cddfSDavid du Colombier 	mmio = scr->mmio;
4077dd7cddfSDavid du Colombier 	x = 0;
4087dd7cddfSDavid du Colombier 	while((mmio[SubStat]&0x3F00) != 0x3000 && x++ < Maxloop)
4097dd7cddfSDavid du Colombier 		waitcount.idle++;
41014414594SDavid du Colombier 	if(x >= Maxloop)
41114414594SDavid du Colombier 		waitcount.idletimeout++;
4127dd7cddfSDavid du Colombier }
4137dd7cddfSDavid du Colombier 
4147dd7cddfSDavid du Colombier static int
hwscroll(VGAscr * scr,Rectangle r,Rectangle sr)4157dd7cddfSDavid du Colombier hwscroll(VGAscr *scr, Rectangle r, Rectangle sr)
4167dd7cddfSDavid du Colombier {
4177dd7cddfSDavid du Colombier 	enum { Bitbltop = 0xCC };	/* copy source */
4187dd7cddfSDavid du Colombier 	ulong *mmio;
4197dd7cddfSDavid du Colombier 	ulong cmd, stride;
4207dd7cddfSDavid du Colombier 	Point dp, sp;
4217dd7cddfSDavid du Colombier 	int did, d;
4227dd7cddfSDavid du Colombier 
4237dd7cddfSDavid du Colombier 	d = scr->gscreen->depth;
4247dd7cddfSDavid du Colombier 	did = (d-8)/8;
4257dd7cddfSDavid du Colombier 	cmd = 0x00000020|(Bitbltop<<17)|(did<<2);
4267dd7cddfSDavid du Colombier 	stride = Dx(scr->gscreen->r)*d/8;
4277dd7cddfSDavid du Colombier 
4287dd7cddfSDavid du Colombier 	if(r.min.x <= sr.min.x){
4297dd7cddfSDavid du Colombier 		cmd |= 1<<25;
4307dd7cddfSDavid du Colombier 		dp.x = r.min.x;
4317dd7cddfSDavid du Colombier 		sp.x = sr.min.x;
4327dd7cddfSDavid du Colombier 	}else{
4337dd7cddfSDavid du Colombier 		dp.x = r.max.x-1;
4347dd7cddfSDavid du Colombier 		sp.x = sr.max.x-1;
4357dd7cddfSDavid du Colombier 	}
4367dd7cddfSDavid du Colombier 
4377dd7cddfSDavid du Colombier 	if(r.min.y <= sr.min.y){
4387dd7cddfSDavid du Colombier 		cmd |= 1<<26;
4397dd7cddfSDavid du Colombier 		dp.y = r.min.y;
4407dd7cddfSDavid du Colombier 		sp.y = sr.min.y;
4417dd7cddfSDavid du Colombier 	}else{
4427dd7cddfSDavid du Colombier 		dp.y = r.max.y-1;
4437dd7cddfSDavid du Colombier 		sp.y = sr.max.y-1;
4447dd7cddfSDavid du Colombier 	}
4457dd7cddfSDavid du Colombier 
4467dd7cddfSDavid du Colombier 	mmio = scr->mmio;
4477dd7cddfSDavid du Colombier 	waitforlinearfifo(scr);
4487dd7cddfSDavid du Colombier 	waitforfifo(scr, 7);
449*4de34a7eSDavid du Colombier 	mmio[SrcBase] = scr->paddr;
450*4de34a7eSDavid du Colombier 	mmio[DstBase] = scr->paddr;
4517dd7cddfSDavid du Colombier 	mmio[Stride] = (stride<<16)|stride;
4527dd7cddfSDavid du Colombier 	mmio[WidthHeight] = ((Dx(r)-1)<<16)|Dy(r);
4537dd7cddfSDavid du Colombier 	mmio[SrcXY] = (sp.x<<16)|sp.y;
4547dd7cddfSDavid du Colombier 	mmio[DestXY] = (dp.x<<16)|dp.y;
4557dd7cddfSDavid du Colombier 	mmio[Command] = cmd;
4567dd7cddfSDavid du Colombier 	waitforidle(scr);
4577dd7cddfSDavid du Colombier 	return 1;
4587dd7cddfSDavid du Colombier }
4597dd7cddfSDavid du Colombier 
4607dd7cddfSDavid du Colombier static int
hwfill(VGAscr * scr,Rectangle r,ulong sval)4617dd7cddfSDavid du Colombier hwfill(VGAscr *scr, Rectangle r, ulong sval)
4627dd7cddfSDavid du Colombier {
4637dd7cddfSDavid du Colombier 	enum { Bitbltop = 0xCC };	/* copy source */
4647dd7cddfSDavid du Colombier 	ulong *mmio;
4657dd7cddfSDavid du Colombier 	ulong cmd, stride;
4667dd7cddfSDavid du Colombier 	int did, d;
4677dd7cddfSDavid du Colombier 
4687dd7cddfSDavid du Colombier 	d = scr->gscreen->depth;
4697dd7cddfSDavid du Colombier 	did = (d-8)/8;
4707dd7cddfSDavid du Colombier 	cmd = 0x16000120|(Bitbltop<<17)|(did<<2);
4717dd7cddfSDavid du Colombier 	stride = Dx(scr->gscreen->r)*d/8;
4727dd7cddfSDavid du Colombier 	mmio = scr->mmio;
4737dd7cddfSDavid du Colombier 	waitforlinearfifo(scr);
4747dd7cddfSDavid du Colombier 	waitforfifo(scr, 8);
475*4de34a7eSDavid du Colombier 	mmio[SrcBase] = scr->paddr;
476*4de34a7eSDavid du Colombier 	mmio[DstBase] = scr->paddr;
477*4de34a7eSDavid du Colombier 	mmio[DstBase] = scr->paddr;
4787dd7cddfSDavid du Colombier 	mmio[Stride] = (stride<<16)|stride;
4797dd7cddfSDavid du Colombier 	mmio[FgrdData] = sval;
4807dd7cddfSDavid du Colombier 	mmio[WidthHeight] = ((Dx(r)-1)<<16)|Dy(r);
4817dd7cddfSDavid du Colombier 	mmio[DestXY] = (r.min.x<<16)|r.min.y;
4827dd7cddfSDavid du Colombier 	mmio[Command] = cmd;
4837dd7cddfSDavid du Colombier 	waitforidle(scr);
4847dd7cddfSDavid du Colombier 	return 1;
4857dd7cddfSDavid du Colombier }
4867dd7cddfSDavid du Colombier 
4877dd7cddfSDavid du Colombier enum {
4887dd7cddfSDavid du Colombier 	CursorSyncCtl = 0x0D,	/* in Seqx */
4897dd7cddfSDavid du Colombier 	VsyncHi = 0x80,
4907dd7cddfSDavid du Colombier 	VsyncLo = 0x40,
4917dd7cddfSDavid du Colombier 	HsyncHi = 0x20,
4927dd7cddfSDavid du Colombier 	HsyncLo = 0x10,
493219b2ee8SDavid du Colombier };
494219b2ee8SDavid du Colombier 
495219b2ee8SDavid du Colombier static void
s3blank(VGAscr *,int blank)4969a747e4fSDavid du Colombier s3blank(VGAscr*, int blank)
497219b2ee8SDavid du Colombier {
4987dd7cddfSDavid du Colombier 	uchar x;
4997dd7cddfSDavid du Colombier 
5007dd7cddfSDavid du Colombier 	x = vgaxi(Seqx, CursorSyncCtl);
5017dd7cddfSDavid du Colombier 	x &= ~0xF0;
5027dd7cddfSDavid du Colombier 	if(blank)
5037dd7cddfSDavid du Colombier 		x |= VsyncLo | HsyncLo;
5047dd7cddfSDavid du Colombier 	vgaxo(Seqx, CursorSyncCtl, x);
505219b2ee8SDavid du Colombier }
506219b2ee8SDavid du Colombier 
5077dd7cddfSDavid du Colombier static void
s3drawinit(VGAscr * scr)5087dd7cddfSDavid du Colombier s3drawinit(VGAscr *scr)
5097dd7cddfSDavid du Colombier {
51059cc4ca5SDavid du Colombier 	extern void savageinit(VGAscr*);	/* vgasavage.c */
5117dd7cddfSDavid du Colombier 	ulong id;
5127dd7cddfSDavid du Colombier 
51359cc4ca5SDavid du Colombier 	id = (vgaxi(Crtx, 0x2D)<<8)|vgaxi(Crtx, 0x2E);
5147dd7cddfSDavid du Colombier 	scr->id = id;
5157dd7cddfSDavid du Colombier 
5167dd7cddfSDavid du Colombier 	/*
5177dd7cddfSDavid du Colombier 	 * It's highly likely that other ViRGEs will work without
5187dd7cddfSDavid du Colombier 	 * change to the driver, with the exception of the size of
5197dd7cddfSDavid du Colombier 	 * the linear aperture memory write FIFO.  Since we don't
5207dd7cddfSDavid du Colombier 	 * know that size, I'm not turning them on.  See waitforlinearfifo
5217dd7cddfSDavid du Colombier 	 * above.
5227dd7cddfSDavid du Colombier 	 */
5239a747e4fSDavid du Colombier 	scr->blank = s3blank;
5249a747e4fSDavid du Colombier 	/* hwblank = 1;		not known to work well */
5259a747e4fSDavid du Colombier 
5267dd7cddfSDavid du Colombier 	switch(id){
52759cc4ca5SDavid du Colombier 	case VIRGE:
52859cc4ca5SDavid du Colombier 	case VIRGEVX:
52959cc4ca5SDavid du Colombier 	case VIRGEGX2:
530*4de34a7eSDavid du Colombier 		scr->mmio = (ulong*)((char*)scr->vaddr+0x1000000);
5317dd7cddfSDavid du Colombier 		scr->fill = hwfill;
5327dd7cddfSDavid du Colombier 		scr->scroll = hwscroll;
53359cc4ca5SDavid du Colombier 		break;
5349a747e4fSDavid du Colombier 	case SAVAGEMXMV:
53559cc4ca5SDavid du Colombier 	case SAVAGEIXMV:
536*4de34a7eSDavid du Colombier 		scr->mmio = (ulong*)((char*)scr->vaddr+0x1000000);
53759cc4ca5SDavid du Colombier 		savageinit(scr);
53859cc4ca5SDavid du Colombier 		break;
5399a747e4fSDavid du Colombier 	case SUPERSAVAGEIXC16:
54059cc4ca5SDavid du Colombier 	case SAVAGE4:
5410b459c2cSDavid du Colombier 	case PROSAVAGEP:
54219dc9ffeSDavid du Colombier 	case PROSAVAGE8:
5430b459c2cSDavid du Colombier 	case PROSAVAGEK:
54459cc4ca5SDavid du Colombier 		/* scr->mmio is set by s3linear */
54559cc4ca5SDavid du Colombier 		savageinit(scr);
54659cc4ca5SDavid du Colombier 		break;
5477dd7cddfSDavid du Colombier 	}
5487dd7cddfSDavid du Colombier }
5497dd7cddfSDavid du Colombier 
5507dd7cddfSDavid du Colombier VGAdev vgas3dev = {
551219b2ee8SDavid du Colombier 	"s3",
552219b2ee8SDavid du Colombier 
553219b2ee8SDavid du Colombier 	0,
5547dd7cddfSDavid du Colombier 	0,
5557dd7cddfSDavid du Colombier 	s3page,
5567dd7cddfSDavid du Colombier 	s3linear,
5577dd7cddfSDavid du Colombier 	s3drawinit,
558219b2ee8SDavid du Colombier };
559219b2ee8SDavid du Colombier 
5607dd7cddfSDavid du Colombier VGAcur vgas3cur = {
5617dd7cddfSDavid du Colombier 	"s3hwgc",
5627dd7cddfSDavid du Colombier 
5637dd7cddfSDavid du Colombier 	s3enable,
5647dd7cddfSDavid du Colombier 	s3disable,
5657dd7cddfSDavid du Colombier 	s3load,
5667dd7cddfSDavid du Colombier 	s3move,
5677dd7cddfSDavid du Colombier };
56819dc9ffeSDavid du Colombier 
569