xref: /plan9-contrib/sys/src/9/pc/vganeomagic.c (revision 5b7f163ef926031138d13ab99fb6fc8ce599f427)
17dd7cddfSDavid du Colombier #include "u.h"
27dd7cddfSDavid du Colombier #include "../port/lib.h"
37dd7cddfSDavid du Colombier #include "mem.h"
47dd7cddfSDavid du Colombier #include "dat.h"
57dd7cddfSDavid du Colombier #include "fns.h"
67dd7cddfSDavid du Colombier #include "io.h"
77dd7cddfSDavid du Colombier #include "../port/error.h"
87dd7cddfSDavid 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>
137dd7cddfSDavid du Colombier #include "screen.h"
147dd7cddfSDavid du Colombier 
1559c21d95SDavid du Colombier typedef struct CursorNM CursorNM;
1659c21d95SDavid du Colombier struct CursorNM {
177dd7cddfSDavid du Colombier 	int	enable;
187dd7cddfSDavid du Colombier 	int	x;
197dd7cddfSDavid du Colombier 	int	y;
207dd7cddfSDavid du Colombier 	int	colour1;
217dd7cddfSDavid du Colombier 	int	colour2;
227dd7cddfSDavid du Colombier 	int	addr;
2359c21d95SDavid du Colombier };
247dd7cddfSDavid du Colombier 
257dd7cddfSDavid du Colombier static void
neomagicenable(VGAscr * scr)267dd7cddfSDavid du Colombier neomagicenable(VGAscr* scr)
277dd7cddfSDavid du Colombier {
287dd7cddfSDavid du Colombier 	Pcidev *p;
294de34a7eSDavid du Colombier 	int curoff, vmsize;
30375daca8SDavid du Colombier 	ulong ioaddr;
31375daca8SDavid du Colombier 	ulong iosize;
327dd7cddfSDavid du Colombier 
337dd7cddfSDavid du Colombier 	/*
344de34a7eSDavid du Colombier 	 * scr->mmio holds the virtual address of the cursor registers
357dd7cddfSDavid du Colombier 	 * in the MMIO space. This may need to change for older chips
367dd7cddfSDavid du Colombier 	 * which have the MMIO space offset in the framebuffer region.
37e862f8a5SDavid du Colombier 	 *
38e862f8a5SDavid du Colombier 	 * scr->io holds the offset into mmio of the CursorNM struct.
397dd7cddfSDavid du Colombier 	 */
404de34a7eSDavid du Colombier 	if(scr->mmio)
417dd7cddfSDavid du Colombier 		return;
427dd7cddfSDavid du Colombier 	if(p = pcimatch(nil, 0x10C8, 0)){
437dd7cddfSDavid du Colombier 		switch(p->did){
44afb30c3eSDavid du Colombier 		case 0x0003:		/* MagicGraph 128ZV */
45375daca8SDavid du Colombier 			curoff = 0x100;
46375daca8SDavid du Colombier 			vmsize = 1152*1024;
47375daca8SDavid du Colombier 			ioaddr = (p->mem[0].bar & ~0x0F) + 0x200000;
48375daca8SDavid du Colombier 			iosize = 0x200000;
49375daca8SDavid du Colombier 			break;
50afb30c3eSDavid du Colombier 		case 0x0083:		/* MagicGraph 128ZV+ */
51afb30c3eSDavid du Colombier 			curoff = 0x100;
52afb30c3eSDavid du Colombier 			vmsize = 1152*1024;
53afb30c3eSDavid du Colombier 			ioaddr = p->mem[1].bar & ~0x0F;
54afb30c3eSDavid du Colombier 			iosize = p->mem[1].size;
55afb30c3eSDavid du Colombier 			break;
567dd7cddfSDavid du Colombier 		case 0x0004:		/* MagicGraph 128XD */
577dd7cddfSDavid du Colombier 			curoff = 0x100;
587dd7cddfSDavid du Colombier 			vmsize = 2048*1024;
59375daca8SDavid du Colombier 			ioaddr = p->mem[1].bar & ~0x0F;
60375daca8SDavid du Colombier 			iosize = p->mem[1].size;
617dd7cddfSDavid du Colombier 			break;
627dd7cddfSDavid du Colombier 		case 0x0005:		/* MagicMedia 256AV */
637dd7cddfSDavid du Colombier 			curoff = 0x1000;
647dd7cddfSDavid du Colombier 			vmsize = 2560*1024;
65375daca8SDavid du Colombier 			ioaddr = p->mem[1].bar & ~0x0F;
66375daca8SDavid du Colombier 			iosize = p->mem[1].size;
677dd7cddfSDavid du Colombier 			break;
6814414594SDavid du Colombier 		case 0x0006:		/* MagicMedia 256ZX */
6914414594SDavid du Colombier 			curoff = 0x1000;
7014414594SDavid du Colombier 			vmsize = 4096*1024;
71375daca8SDavid du Colombier 			ioaddr = p->mem[1].bar & ~0x0F;
72375daca8SDavid du Colombier 			iosize = p->mem[1].size;
7314414594SDavid du Colombier 			break;
74*5b7f163eSDavid du Colombier 		case 0x0016:		/* MagicMedia 256XL+ */
75*5b7f163eSDavid du Colombier 			curoff = 0x1000;
76*5b7f163eSDavid du Colombier 			/* Vaio VESA BIOS says 6080, but then hwgc doesn't work */
77*5b7f163eSDavid du Colombier 			vmsize = 4096*1024;
78*5b7f163eSDavid du Colombier 			ioaddr = p->mem[1].bar & ~0x0F;
79*5b7f163eSDavid du Colombier 			iosize = p->mem[1].size;
80*5b7f163eSDavid du Colombier 			break;
817dd7cddfSDavid du Colombier 		default:
827dd7cddfSDavid du Colombier 			return;
837dd7cddfSDavid du Colombier 		}
847dd7cddfSDavid du Colombier 	}
857dd7cddfSDavid du Colombier 	else
867dd7cddfSDavid du Colombier 		return;
874de34a7eSDavid du Colombier 	scr->pci = p;
884de34a7eSDavid du Colombier 
894de34a7eSDavid du Colombier 	scr->mmio = vmap(ioaddr, iosize);
904de34a7eSDavid du Colombier 	if(scr->mmio == nil)
917dd7cddfSDavid du Colombier 		return;
924de34a7eSDavid du Colombier 	addvgaseg("neomagicmmio", ioaddr, iosize);
937dd7cddfSDavid du Colombier 
947dd7cddfSDavid du Colombier 	/*
957dd7cddfSDavid du Colombier 	 * Find a place for the cursor data in display memory.
967dd7cddfSDavid du Colombier 	 * 2 cursor images might be needed, 1KB each so use the
977dd7cddfSDavid du Colombier 	 * last 2KB of the framebuffer.
987dd7cddfSDavid du Colombier 	 */
997dd7cddfSDavid du Colombier 	scr->storage = vmsize-2*1024;
100e862f8a5SDavid du Colombier 	scr->io = curoff;
1014de34a7eSDavid du Colombier 	vgalinearpci(scr);
1024de34a7eSDavid du Colombier 	if(scr->paddr)
1034de34a7eSDavid du Colombier 		addvgaseg("neomagicscreen", scr->paddr, scr->apsize);
1047dd7cddfSDavid du Colombier }
1057dd7cddfSDavid du Colombier 
1067dd7cddfSDavid du Colombier static void
neomagiccurdisable(VGAscr * scr)1077dd7cddfSDavid du Colombier neomagiccurdisable(VGAscr* scr)
1087dd7cddfSDavid du Colombier {
1097dd7cddfSDavid du Colombier 	CursorNM *cursornm;
1107dd7cddfSDavid du Colombier 
1114de34a7eSDavid du Colombier 	if(scr->mmio == 0)
1127dd7cddfSDavid du Colombier 		return;
113e862f8a5SDavid du Colombier 	cursornm = (void*)((char*)scr->mmio + scr->io);
1147dd7cddfSDavid du Colombier 	cursornm->enable = 0;
1157dd7cddfSDavid du Colombier }
1167dd7cddfSDavid du Colombier 
1177dd7cddfSDavid du Colombier static void
neomagicinitcursor(VGAscr * scr,int xo,int yo,int index)1187dd7cddfSDavid du Colombier neomagicinitcursor(VGAscr* scr, int xo, int yo, int index)
1197dd7cddfSDavid du Colombier {
1207dd7cddfSDavid du Colombier 	uchar *p;
1217dd7cddfSDavid du Colombier 	uint p0, p1;
1227dd7cddfSDavid du Colombier 	int x, y;
1237dd7cddfSDavid du Colombier 
124e862f8a5SDavid du Colombier 	p = (uchar*)scr->vaddr;
1257dd7cddfSDavid du Colombier 	p += scr->storage + index*1024;
1267dd7cddfSDavid du Colombier 
1277dd7cddfSDavid du Colombier 	for(y = yo; y < 16; y++){
1287dd7cddfSDavid du Colombier 		p0 = scr->set[2*y];
1297dd7cddfSDavid du Colombier 		p1 = scr->set[2*y+1];
1307dd7cddfSDavid du Colombier 		if(xo){
1317dd7cddfSDavid du Colombier 			p0 = (p0<<xo)|(p1>>(8-xo));
1327dd7cddfSDavid du Colombier 			p1 <<= xo;
1337dd7cddfSDavid du Colombier 		}
1347dd7cddfSDavid du Colombier 		*p++ = p0;
1357dd7cddfSDavid du Colombier 		*p++ = p1;
1367dd7cddfSDavid du Colombier 
1377dd7cddfSDavid du Colombier 		for(x = 16; x < 64; x += 8)
1387dd7cddfSDavid du Colombier 			*p++ = 0x00;
1397dd7cddfSDavid du Colombier 
1407dd7cddfSDavid du Colombier 		p0 = scr->clr[2*y]|scr->set[2*y];
1417dd7cddfSDavid du Colombier 		p1 = scr->clr[2*y+1]|scr->set[2*y+1];
1427dd7cddfSDavid du Colombier 		if(xo){
1437dd7cddfSDavid du Colombier 			p0 = (p0<<xo)|(p1>>(8-xo));
1447dd7cddfSDavid du Colombier 			p1 <<= xo;
1457dd7cddfSDavid du Colombier 		}
1467dd7cddfSDavid du Colombier 		*p++ = p0;
1477dd7cddfSDavid du Colombier 		*p++ = p1;
1487dd7cddfSDavid du Colombier 
1497dd7cddfSDavid du Colombier 		for(x = 16; x < 64; x += 8)
1507dd7cddfSDavid du Colombier 			*p++ = 0x00;
1517dd7cddfSDavid du Colombier 	}
1527dd7cddfSDavid du Colombier 	while(y < 64+yo){
1537dd7cddfSDavid du Colombier 		for(x = 0; x < 64; x += 8){
1547dd7cddfSDavid du Colombier 			*p++ = 0x00;
1557dd7cddfSDavid du Colombier 			*p++ = 0x00;
1567dd7cddfSDavid du Colombier 		}
1577dd7cddfSDavid du Colombier 		y++;
1587dd7cddfSDavid du Colombier 	}
1597dd7cddfSDavid du Colombier }
1607dd7cddfSDavid du Colombier 
1617dd7cddfSDavid du Colombier static void
neomagiccurload(VGAscr * scr,Cursor * curs)1627dd7cddfSDavid du Colombier neomagiccurload(VGAscr* scr, Cursor* curs)
1637dd7cddfSDavid du Colombier {
1647dd7cddfSDavid du Colombier 	CursorNM *cursornm;
1657dd7cddfSDavid du Colombier 
1664de34a7eSDavid du Colombier 	if(scr->mmio == 0)
1677dd7cddfSDavid du Colombier 		return;
168e862f8a5SDavid du Colombier 	cursornm = (void*)((char*)scr->mmio + scr->io);
1697dd7cddfSDavid du Colombier 
1707dd7cddfSDavid du Colombier 	cursornm->enable = 0;
1717dd7cddfSDavid du Colombier 	memmove(&scr->Cursor, curs, sizeof(Cursor));
1727dd7cddfSDavid du Colombier 	neomagicinitcursor(scr, 0, 0, 0);
1737dd7cddfSDavid du Colombier 	cursornm->enable = 1;
1747dd7cddfSDavid du Colombier }
1757dd7cddfSDavid du Colombier 
1767dd7cddfSDavid du Colombier static int
neomagiccurmove(VGAscr * scr,Point p)1777dd7cddfSDavid du Colombier neomagiccurmove(VGAscr* scr, Point p)
1787dd7cddfSDavid du Colombier {
1797dd7cddfSDavid du Colombier 	CursorNM *cursornm;
1807dd7cddfSDavid du Colombier 	int addr, index, x, xo, y, yo;
1817dd7cddfSDavid du Colombier 
1824de34a7eSDavid du Colombier 	if(scr->mmio == 0)
1837dd7cddfSDavid du Colombier 		return 1;
184e862f8a5SDavid du Colombier 	cursornm = (void*)((char*)scr->mmio + scr->io);
1857dd7cddfSDavid du Colombier 
1867dd7cddfSDavid du Colombier 	index = 0;
1877dd7cddfSDavid du Colombier 	if((x = p.x+scr->offset.x) < 0){
1887dd7cddfSDavid du Colombier 		xo = -x;
1897dd7cddfSDavid du Colombier 		x = 0;
1907dd7cddfSDavid du Colombier 	}
1917dd7cddfSDavid du Colombier 	else
1927dd7cddfSDavid du Colombier 		xo = 0;
1937dd7cddfSDavid du Colombier 	if((y = p.y+scr->offset.y) < 0){
1947dd7cddfSDavid du Colombier 		yo = -y;
1957dd7cddfSDavid du Colombier 		y = 0;
1967dd7cddfSDavid du Colombier 	}
1977dd7cddfSDavid du Colombier 	else
1987dd7cddfSDavid du Colombier 		yo = 0;
1997dd7cddfSDavid du Colombier 
2007dd7cddfSDavid du Colombier 	if(xo || yo){
2017dd7cddfSDavid du Colombier 		index = 1;
2027dd7cddfSDavid du Colombier 		neomagicinitcursor(scr, xo, yo, index);
2037dd7cddfSDavid du Colombier 	}
2047dd7cddfSDavid du Colombier 	addr = ((scr->storage+(1024*index))>>10) & 0xFFF;
2057dd7cddfSDavid du Colombier 	addr = ((addr & 0x00F)<<8)|((addr>>4) & 0xFF);
2067dd7cddfSDavid du Colombier 	if(cursornm->addr != addr)
2077dd7cddfSDavid du Colombier 		cursornm->addr = addr;
2087dd7cddfSDavid du Colombier 
2097dd7cddfSDavid du Colombier 	cursornm->x = x;
2107dd7cddfSDavid du Colombier 	cursornm->y = y;
2117dd7cddfSDavid du Colombier 
2127dd7cddfSDavid du Colombier 	return 0;
2137dd7cddfSDavid du Colombier }
2147dd7cddfSDavid du Colombier 
2157dd7cddfSDavid du Colombier static void
neomagiccurenable(VGAscr * scr)2167dd7cddfSDavid du Colombier neomagiccurenable(VGAscr* scr)
2177dd7cddfSDavid du Colombier {
2187dd7cddfSDavid du Colombier 	CursorNM *cursornm;
2197dd7cddfSDavid du Colombier 
2207dd7cddfSDavid du Colombier 	neomagicenable(scr);
2214de34a7eSDavid du Colombier 	if(scr->mmio == 0)
2227dd7cddfSDavid du Colombier 		return;
223e862f8a5SDavid du Colombier 	cursornm = (void*)((char*)scr->mmio + scr->io);
2247dd7cddfSDavid du Colombier 	cursornm->enable = 0;
2257dd7cddfSDavid du Colombier 
2267dd7cddfSDavid du Colombier 	/*
2277dd7cddfSDavid du Colombier 	 * Cursor colours.
2287dd7cddfSDavid du Colombier 	 */
2297dd7cddfSDavid du Colombier 	cursornm->colour1 = (Pblack<<16)|(Pblack<<8)|Pblack;
2307dd7cddfSDavid du Colombier 	cursornm->colour2 = (Pwhite<<16)|(Pwhite<<8)|Pwhite;
2317dd7cddfSDavid du Colombier 
2327dd7cddfSDavid du Colombier 	/*
2337dd7cddfSDavid du Colombier 	 * Load, locate and enable the 64x64 cursor.
2347dd7cddfSDavid du Colombier 	 */
2357dd7cddfSDavid du Colombier 	neomagiccurload(scr, &arrow);
2367dd7cddfSDavid du Colombier 	neomagiccurmove(scr, ZP);
2377dd7cddfSDavid du Colombier 	cursornm->enable = 1;
2387dd7cddfSDavid du Colombier }
2397dd7cddfSDavid du Colombier 
2403ff48bf5SDavid du Colombier static int neomagicbltflags;
2413ff48bf5SDavid du Colombier 
2423ff48bf5SDavid du Colombier /* registers */
2433ff48bf5SDavid du Colombier enum {
2443ff48bf5SDavid du Colombier 	BltStat = 0,
2453ff48bf5SDavid du Colombier 	BltCntl = 1,
2463ff48bf5SDavid du Colombier 	XPColor = 2,
2473ff48bf5SDavid du Colombier 	FGColor = 3,
2483ff48bf5SDavid du Colombier 	BGColor = 4,
2493ff48bf5SDavid du Colombier 	Pitch = 5,
2503ff48bf5SDavid du Colombier 	ClipLT = 6,
2513ff48bf5SDavid du Colombier 	ClipRB = 7,
2523ff48bf5SDavid du Colombier 	SrcBitOff = 8,
2533ff48bf5SDavid du Colombier 	SrcStartOff = 9,
2543ff48bf5SDavid du Colombier 
2553ff48bf5SDavid du Colombier 	DstStartOff = 11,
2563ff48bf5SDavid du Colombier 	XYExt = 12,
2573ff48bf5SDavid du Colombier 
2583ff48bf5SDavid du Colombier 	PageCntl = 20,
2593ff48bf5SDavid du Colombier 	PageBase,
2603ff48bf5SDavid du Colombier 	PostBase,
2613ff48bf5SDavid du Colombier 	PostPtr,
2623ff48bf5SDavid du Colombier 	DataPtr,
2633ff48bf5SDavid du Colombier };
2643ff48bf5SDavid du Colombier 
2653ff48bf5SDavid du Colombier /* flags */
2663ff48bf5SDavid du Colombier enum {
2673ff48bf5SDavid du Colombier 	NEO_BS0_BLT_BUSY =	0x00000001,
2683ff48bf5SDavid du Colombier 	NEO_BS0_FIFO_AVAIL =	0x00000002,
2693ff48bf5SDavid du Colombier 	NEO_BS0_FIFO_PEND =	0x00000004,
2703ff48bf5SDavid du Colombier 
2713ff48bf5SDavid du Colombier 	NEO_BC0_DST_Y_DEC =	0x00000001,
2723ff48bf5SDavid du Colombier 	NEO_BC0_X_DEC =		0x00000002,
2733ff48bf5SDavid du Colombier 	NEO_BC0_SRC_TRANS =	0x00000004,
2743ff48bf5SDavid du Colombier 	NEO_BC0_SRC_IS_FG =	0x00000008,
2753ff48bf5SDavid du Colombier 	NEO_BC0_SRC_Y_DEC =	0x00000010,
2763ff48bf5SDavid du Colombier 	NEO_BC0_FILL_PAT =	0x00000020,
2773ff48bf5SDavid du Colombier 	NEO_BC0_SRC_MONO =	0x00000040,
2783ff48bf5SDavid du Colombier 	NEO_BC0_SYS_TO_VID =	0x00000080,
2793ff48bf5SDavid du Colombier 
2803ff48bf5SDavid du Colombier 	NEO_BC1_DEPTH8 =	0x00000100,
2813ff48bf5SDavid du Colombier 	NEO_BC1_DEPTH16 =	0x00000200,
2823ff48bf5SDavid du Colombier 	NEO_BC1_DEPTH24 =	0x00000300,
2833ff48bf5SDavid du Colombier 	NEO_BC1_X_320 =		0x00000400,
2843ff48bf5SDavid du Colombier 	NEO_BC1_X_640 =		0x00000800,
2853ff48bf5SDavid du Colombier 	NEO_BC1_X_800 =		0x00000c00,
2863ff48bf5SDavid du Colombier 	NEO_BC1_X_1024 =	0x00001000,
2873ff48bf5SDavid du Colombier 	NEO_BC1_X_1152 =	0x00001400,
2883ff48bf5SDavid du Colombier 	NEO_BC1_X_1280 =	0x00001800,
2893ff48bf5SDavid du Colombier 	NEO_BC1_X_1600 =	0x00001c00,
2903ff48bf5SDavid du Colombier 	NEO_BC1_DST_TRANS =	0x00002000,
2913ff48bf5SDavid du Colombier 	NEO_BC1_MSTR_BLT =	0x00004000,
2923ff48bf5SDavid du Colombier 	NEO_BC1_FILTER_Z =	0x00008000,
2933ff48bf5SDavid du Colombier 
2943ff48bf5SDavid du Colombier 	NEO_BC2_WR_TR_DST =	0x00800000,
2953ff48bf5SDavid du Colombier 
2963ff48bf5SDavid du Colombier 	NEO_BC3_SRC_XY_ADDR =	0x01000000,
2973ff48bf5SDavid du Colombier 	NEO_BC3_DST_XY_ADDR =	0x02000000,
2983ff48bf5SDavid du Colombier 	NEO_BC3_CLIP_ON =	0x04000000,
2993ff48bf5SDavid du Colombier 	NEO_BC3_FIFO_EN =	0x08000000,
3003ff48bf5SDavid du Colombier 	NEO_BC3_BLT_ON_ADDR =	0x10000000,
3013ff48bf5SDavid du Colombier 	NEO_BC3_SKIP_MAPPING =	0x80000000,
3023ff48bf5SDavid du Colombier 
3033ff48bf5SDavid du Colombier 	NEO_MODE1_DEPTH8 =	0x0100,
3043ff48bf5SDavid du Colombier 	NEO_MODE1_DEPTH16 =	0x0200,
3053ff48bf5SDavid du Colombier 	NEO_MODE1_DEPTH24 =	0x0300,
3063ff48bf5SDavid du Colombier 	NEO_MODE1_X_320 =	0x0400,
3073ff48bf5SDavid du Colombier 	NEO_MODE1_X_640 =	0x0800,
3083ff48bf5SDavid du Colombier 	NEO_MODE1_X_800 =	0x0c00,
3093ff48bf5SDavid du Colombier 	NEO_MODE1_X_1024 =	0x1000,
3103ff48bf5SDavid du Colombier 	NEO_MODE1_X_1152 =	0x1400,
3113ff48bf5SDavid du Colombier 	NEO_MODE1_X_1280 =	0x1800,
3123ff48bf5SDavid du Colombier 	NEO_MODE1_X_1600 =	0x1c00,
3133ff48bf5SDavid du Colombier 	NEO_MODE1_BLT_ON_ADDR =	0x2000,
3143ff48bf5SDavid du Colombier };
3153ff48bf5SDavid du Colombier 
3163ff48bf5SDavid du Colombier /* Raster Operations */
3173ff48bf5SDavid du Colombier enum {
3183ff48bf5SDavid du Colombier 	GXclear =		0x000000,	/* 0x0000 */
3193ff48bf5SDavid du Colombier 	GXand =			0x080000,	/* 0x1000 */
3203ff48bf5SDavid du Colombier 	GXandReverse =		0x040000,	/* 0x0100 */
3213ff48bf5SDavid du Colombier 	GXcopy =		0x0c0000,	/* 0x1100 */
3223ff48bf5SDavid du Colombier 	GXandInvert =		0x020000,	/* 0x0010 */
3233ff48bf5SDavid du Colombier 	GXnoop =		0x0a0000,	/* 0x1010 */
3243ff48bf5SDavid du Colombier 	GXxor =			0x060000,	/* 0x0110 */
3253ff48bf5SDavid du Colombier 	GXor =			0x0e0000,	/* 0x1110 */
3263ff48bf5SDavid du Colombier 	GXnor =			0x010000,	/* 0x0001 */
3273ff48bf5SDavid du Colombier 	GXequiv =		0x090000,	/* 0x1001 */
3283ff48bf5SDavid du Colombier 	GXinvert =		0x050000,	/* 0x0101 */
3293ff48bf5SDavid du Colombier 	GXorReverse =		0x0d0000,	/* 0x1101 */
3303ff48bf5SDavid du Colombier 	GXcopyInvert =		0x030000,	/* 0x0011 */
3313ff48bf5SDavid du Colombier 	GXorInverted =		0x0b0000,	/* 0x1011 */
3323ff48bf5SDavid du Colombier 	GXnand =		0x070000,	/* 0x0111 */
3333ff48bf5SDavid du Colombier 	GXset =			0x0f0000,	/* 0x1111 */
3343ff48bf5SDavid du Colombier };
3353ff48bf5SDavid du Colombier 
3363ff48bf5SDavid du Colombier static void
waitforidle(VGAscr * scr)3373ff48bf5SDavid du Colombier waitforidle(VGAscr *scr)
3383ff48bf5SDavid du Colombier {
3393ff48bf5SDavid du Colombier 	ulong *mmio;
3403ff48bf5SDavid du Colombier 	long x;
3413ff48bf5SDavid du Colombier 
3423ff48bf5SDavid du Colombier 	mmio = scr->mmio;
3433ff48bf5SDavid du Colombier 	x = 0;
3443ff48bf5SDavid du Colombier 	while((mmio[BltStat] & NEO_BS0_BLT_BUSY) && x++ < 1000000)
3453ff48bf5SDavid du Colombier 		;
3463ff48bf5SDavid du Colombier 	//if(x >= 1000000)
347567483c8SDavid du Colombier 	//	iprint("idle stat %lud scrmmio %#.8lux scr %#p pc %#p\n", mmio[BltStat], scr->mmio, scr, getcallerpc(&scr));
3483ff48bf5SDavid du Colombier }
3493ff48bf5SDavid du Colombier 
3503ff48bf5SDavid du Colombier static void
waitforfifo(VGAscr * scr,int entries)3513ff48bf5SDavid du Colombier waitforfifo(VGAscr *scr, int entries)
3523ff48bf5SDavid du Colombier {
3533ff48bf5SDavid du Colombier 	ulong *mmio;
3543ff48bf5SDavid du Colombier 	long x;
3553ff48bf5SDavid du Colombier 
3563ff48bf5SDavid du Colombier 	mmio = scr->mmio;
3573ff48bf5SDavid du Colombier 	x = 0;
3583ff48bf5SDavid du Colombier 	while(((mmio[BltStat]>>8) < entries) && x++ < 1000000)
3593ff48bf5SDavid du Colombier 		;
3603ff48bf5SDavid du Colombier 	//if(x >= 1000000)
361567483c8SDavid du Colombier 	//	iprint("fifo stat %d scrmmio %#.8lux scr %#p pc %#p\n", mmio[BltStat]>>8, scr->mmio, scr, getcallerpc(&scr));
3623ff48bf5SDavid du Colombier 	/* DirectFB says the above doesn't work.  if so... */
3633ff48bf5SDavid du Colombier 	/* waitforidle(scr); */
3643ff48bf5SDavid du Colombier }
3653ff48bf5SDavid du Colombier 
3663ff48bf5SDavid du Colombier static int
neomagichwfill(VGAscr * scr,Rectangle r,ulong sval)3673ff48bf5SDavid du Colombier neomagichwfill(VGAscr *scr, Rectangle r, ulong sval)
3683ff48bf5SDavid du Colombier {
3693ff48bf5SDavid du Colombier 	ulong *mmio;
3703ff48bf5SDavid du Colombier 
3713ff48bf5SDavid du Colombier 	mmio = scr->mmio;
3723ff48bf5SDavid du Colombier 
3733ff48bf5SDavid du Colombier 	waitforfifo(scr, 1);
3743ff48bf5SDavid du Colombier 	mmio[FGColor] = sval;
3753ff48bf5SDavid du Colombier 	waitforfifo(scr, 3);
3763ff48bf5SDavid du Colombier 	mmio[BltCntl] = neomagicbltflags
3773ff48bf5SDavid du Colombier 		| NEO_BC3_FIFO_EN
3783ff48bf5SDavid du Colombier 		| NEO_BC0_SRC_IS_FG
3793ff48bf5SDavid du Colombier 		| NEO_BC3_SKIP_MAPPING
3803ff48bf5SDavid du Colombier 		| GXcopy;
3814de34a7eSDavid du Colombier 	mmio[DstStartOff] = scr->paddr
3823ff48bf5SDavid du Colombier 		+ r.min.y*scr->gscreen->width*BY2WD
3833ff48bf5SDavid du Colombier 		+ r.min.x*scr->gscreen->depth/BI2BY;
3843ff48bf5SDavid du Colombier 	mmio[XYExt] = (Dy(r) << 16) | (Dx(r) & 0xffff);
3853ff48bf5SDavid du Colombier 	waitforidle(scr);
3863ff48bf5SDavid du Colombier 	return 1;
3873ff48bf5SDavid du Colombier }
3883ff48bf5SDavid du Colombier 
3893ff48bf5SDavid du Colombier static int
neomagichwscroll(VGAscr * scr,Rectangle r,Rectangle sr)3903ff48bf5SDavid du Colombier neomagichwscroll(VGAscr *scr, Rectangle r, Rectangle sr)
3913ff48bf5SDavid du Colombier {
3923ff48bf5SDavid du Colombier 	ulong *mmio;
3933ff48bf5SDavid du Colombier 	int pitch, pixel;
3943ff48bf5SDavid du Colombier 
3953ff48bf5SDavid du Colombier 	mmio = scr->mmio;
3963ff48bf5SDavid du Colombier 
3973ff48bf5SDavid du Colombier 	pitch = scr->gscreen->width*BY2WD;
3983ff48bf5SDavid du Colombier 	pixel = scr->gscreen->depth/BI2BY;
3993ff48bf5SDavid du Colombier 
4003ff48bf5SDavid du Colombier 	waitforfifo(scr, 4);
4013ff48bf5SDavid du Colombier 	if (r.min.y < sr.min.y || (r.min.y == sr.min.y && r.min.x < sr.min.x)) {
4023ff48bf5SDavid du Colombier 		/* start from upper-left */
4033ff48bf5SDavid du Colombier 		mmio[BltCntl] = neomagicbltflags
4043ff48bf5SDavid du Colombier 			| NEO_BC3_FIFO_EN
4053ff48bf5SDavid du Colombier 			| NEO_BC3_SKIP_MAPPING
4063ff48bf5SDavid du Colombier 			| GXcopy;
4074de34a7eSDavid du Colombier 		mmio[SrcStartOff] = scr->paddr
4083ff48bf5SDavid du Colombier 			+ sr.min.y*pitch + sr.min.x*pixel;
4094de34a7eSDavid du Colombier 		mmio[DstStartOff] = scr->paddr
4103ff48bf5SDavid du Colombier 			+ r.min.y*pitch + r.min.x*pixel;
4113ff48bf5SDavid du Colombier 	} else {
4123ff48bf5SDavid du Colombier 		/* start from lower-right */
4133ff48bf5SDavid du Colombier 		mmio[BltCntl] = neomagicbltflags
4143ff48bf5SDavid du Colombier 			| NEO_BC0_X_DEC
4153ff48bf5SDavid du Colombier 			| NEO_BC0_DST_Y_DEC
4163ff48bf5SDavid du Colombier 			| NEO_BC0_SRC_Y_DEC
4173ff48bf5SDavid du Colombier 			| NEO_BC3_FIFO_EN
4183ff48bf5SDavid du Colombier 			| NEO_BC3_SKIP_MAPPING
4193ff48bf5SDavid du Colombier 			| GXcopy;
4204de34a7eSDavid du Colombier 		mmio[SrcStartOff] = scr->paddr
4213ff48bf5SDavid du Colombier 			+ (sr.max.y-1)*pitch + (sr.max.x-1)*pixel;
4224de34a7eSDavid du Colombier 		mmio[DstStartOff] = scr->paddr
4233ff48bf5SDavid du Colombier 			+ (r.max.y-1)*pitch + (r.max.x-1)*pixel;
4243ff48bf5SDavid du Colombier 	}
4253ff48bf5SDavid du Colombier 	mmio[XYExt] = (Dy(r) << 16) | (Dx(r) & 0xffff);
4263ff48bf5SDavid du Colombier 	waitforidle(scr);
4273ff48bf5SDavid du Colombier 	return 1;
4283ff48bf5SDavid du Colombier }
4293ff48bf5SDavid du Colombier 
4303ff48bf5SDavid du Colombier static void
neomagicdrawinit(VGAscr * scr)4313ff48bf5SDavid du Colombier neomagicdrawinit(VGAscr *scr)
4323ff48bf5SDavid du Colombier {
4333ff48bf5SDavid du Colombier 	ulong *mmio;
4343ff48bf5SDavid du Colombier 	uint bltmode, pitch;
4353ff48bf5SDavid du Colombier 
4363ff48bf5SDavid du Colombier 	mmio = scr->mmio;
4373ff48bf5SDavid du Colombier 
4383ff48bf5SDavid du Colombier 	pitch = scr->gscreen->width*BY2WD;
4393ff48bf5SDavid du Colombier 
4403ff48bf5SDavid du Colombier 	neomagicbltflags = bltmode = 0;
4413ff48bf5SDavid du Colombier 
4423ff48bf5SDavid du Colombier 	switch(scr->gscreen->depth) {
4433ff48bf5SDavid du Colombier 	case 8:
4443ff48bf5SDavid du Colombier 		bltmode |= NEO_MODE1_DEPTH8;
4453ff48bf5SDavid du Colombier 		neomagicbltflags |= NEO_BC1_DEPTH8;
4463ff48bf5SDavid du Colombier 		break;
4473ff48bf5SDavid du Colombier 	case 16:
4483ff48bf5SDavid du Colombier 		bltmode |= NEO_MODE1_DEPTH16;
4493ff48bf5SDavid du Colombier 		neomagicbltflags |= NEO_BC1_DEPTH16;
4503ff48bf5SDavid du Colombier 		break;
4513ff48bf5SDavid du Colombier 	case 24:	/* I can't get it to work, and XFree86 doesn't either. */
4523ff48bf5SDavid du Colombier 	default:	/* give up */
4533ff48bf5SDavid du Colombier 		return;
4543ff48bf5SDavid du Colombier 	}
4553ff48bf5SDavid du Colombier 
4563ff48bf5SDavid du Colombier 	switch(Dx(scr->gscreen->r)) {
4573ff48bf5SDavid du Colombier 	case 320:
4583ff48bf5SDavid du Colombier 		bltmode |= NEO_MODE1_X_320;
4593ff48bf5SDavid du Colombier 		neomagicbltflags |= NEO_BC1_X_320;
4603ff48bf5SDavid du Colombier 		break;
4613ff48bf5SDavid du Colombier 	case 640:
4623ff48bf5SDavid du Colombier 		bltmode |= NEO_MODE1_X_640;
4633ff48bf5SDavid du Colombier 		neomagicbltflags |= NEO_BC1_X_640;
4643ff48bf5SDavid du Colombier 		break;
4653ff48bf5SDavid du Colombier 	case 800:
4663ff48bf5SDavid du Colombier 		bltmode |= NEO_MODE1_X_800;
4673ff48bf5SDavid du Colombier 		neomagicbltflags |= NEO_BC1_X_800;
4683ff48bf5SDavid du Colombier 		break;
4693ff48bf5SDavid du Colombier 	case 1024:
4703ff48bf5SDavid du Colombier 		bltmode |= NEO_MODE1_X_1024;
4713ff48bf5SDavid du Colombier 		neomagicbltflags |= NEO_BC1_X_1024;
4723ff48bf5SDavid du Colombier 		break;
4733ff48bf5SDavid du Colombier 	case 1152:
4743ff48bf5SDavid du Colombier 		bltmode |= NEO_MODE1_X_1152;
4753ff48bf5SDavid du Colombier 		neomagicbltflags |= NEO_BC1_X_1152;
4763ff48bf5SDavid du Colombier 		break;
4773ff48bf5SDavid du Colombier 	case 1280:
4783ff48bf5SDavid du Colombier 		bltmode |= NEO_MODE1_X_1280;
4793ff48bf5SDavid du Colombier 		neomagicbltflags |= NEO_BC1_X_1280;
4803ff48bf5SDavid du Colombier 		break;
4813ff48bf5SDavid du Colombier 	case 1600:
4823ff48bf5SDavid du Colombier 		bltmode |= NEO_MODE1_X_1600;
4833ff48bf5SDavid du Colombier 		neomagicbltflags |= NEO_BC1_X_1600;
4843ff48bf5SDavid du Colombier 		break;
4853ff48bf5SDavid du Colombier 	default:
4863ff48bf5SDavid du Colombier 		/* don't worry about it */
4873ff48bf5SDavid du Colombier 		break;
4883ff48bf5SDavid du Colombier 	}
4893ff48bf5SDavid du Colombier 
4903ff48bf5SDavid du Colombier 	waitforidle(scr);
4913ff48bf5SDavid du Colombier 	mmio[BltStat] = bltmode << 16;
4923ff48bf5SDavid du Colombier 	mmio[Pitch] = (pitch << 16) | (pitch & 0xffff);
4933ff48bf5SDavid du Colombier 
4943ff48bf5SDavid du Colombier 	scr->fill = neomagichwfill;
4953ff48bf5SDavid du Colombier 	scr->scroll = neomagichwscroll;
4963ff48bf5SDavid du Colombier }
4973ff48bf5SDavid du Colombier 
4987dd7cddfSDavid du Colombier VGAdev vganeomagicdev = {
4997dd7cddfSDavid du Colombier 	"neomagic",
5007dd7cddfSDavid du Colombier 
5017dd7cddfSDavid du Colombier 	neomagicenable,
5027dd7cddfSDavid du Colombier 	nil,
5037dd7cddfSDavid du Colombier 	nil,
5044de34a7eSDavid du Colombier 	nil,
5053ff48bf5SDavid du Colombier 	neomagicdrawinit,
5067dd7cddfSDavid du Colombier };
5077dd7cddfSDavid du Colombier 
5087dd7cddfSDavid du Colombier VGAcur vganeomagiccur = {
5097dd7cddfSDavid du Colombier 	"neomagichwgc",
5107dd7cddfSDavid du Colombier 
5117dd7cddfSDavid du Colombier 	neomagiccurenable,
5127dd7cddfSDavid du Colombier 	neomagiccurdisable,
5137dd7cddfSDavid du Colombier 	neomagiccurload,
5147dd7cddfSDavid du Colombier 	neomagiccurmove,
5157dd7cddfSDavid du Colombier };
5163ff48bf5SDavid du Colombier 
517