plan 9 kernel history: overview | file list | diff list

1999/1005/pc/vgamach64xx.c (diff list | history)

pc/vgamach64xx.c on 1998/0507
1998/0507    
#include "u.h" 
#include "../port/lib.h" 
#include "mem.h" 
#include "dat.h" 
#include "fns.h" 
#include "io.h" 
#include "../port/error.h" 
 
#define	Image	IMAGE 
#include <draw.h> 
#include <memdraw.h> 
1999/0119    
#include <cursor.h> 
1998/0507    
#include "screen.h" 
 
/* 
1999/1005    
 * ATI Mach64(CT|ET|G*|VT|VU|LP). 
1998/0507    
 */ 
static ushort mach64xxdid[] = { 
	('C'<<8)|'T', 
	('E'<<8)|'T', 
1998/0803    
	('G'<<8)|'B', 
	('G'<<8)|'D', 
	('G'<<8)|'I', 
1998/0507    
	('G'<<8)|'P', 
1998/0803    
	('G'<<8)|'Q', 
1998/0507    
	('G'<<8)|'T', 
	('G'<<8)|'U', 
	('V'<<8)|'T', 
	('V'<<8)|'U', 
1999/1005    
	('L'<<8)|'P', 
1998/0507    
	0, 
}; 
 
1999/1005    
static int hwfill(VGAscr*, Rectangle, ulong); 
static int hwscroll(VGAscr*, Rectangle, Rectangle); 
static void initengine(VGAscr*); 
 
1998/0507    
static Pcidev* 
mach64xxpci(void) 
{ 
	Pcidev *p; 
	ushort *did; 
 
	if((p = pcimatch(nil, 0x1002, 0)) == nil) 
		return nil; 
	for(did = mach64xxdid; *did; did++){ 
		if(*did == p->did) 
1998/0508    
			return p; 
1998/0507    
	} 
 
1998/0508    
	return nil; 
1998/0507    
} 
 
static void 
mach64xxenable(VGAscr* scr) 
{ 
	Pcidev *p; 
 
	/* 
	 * Only once, can't be disabled for now. 
	 */ 
	if(scr->io) 
		return; 
1998/0508    
	if(p = mach64xxpci()){ 
		/* 
		 * The CT doesn't always have the I/O base address 
		 * in the PCI base registers. There is a way to find 
		 * it via the vendor-specific PCI config space but 
		 * this will do for now. 
		 */ 
		scr->io = p->mem[1].bar & ~0x03; 
1999/1005    
 
1998/0508    
		if(scr->io == 0 && p->did == ('C'<<8)|'T') 
			scr->io = 0x2EC; 
	} 
1998/0507    
} 
 
static ulong 
mach64xxlinear(VGAscr* scr, int* size, int* align) 
{ 
1999/1005    
	ulong aperture, osize, oaperture; 
1998/0507    
	int oapsize, wasupamem; 
	Pcidev *p; 
1999/1005    
	Physseg seg; 
1998/0507    
 
1999/1005    
	osize = *size; 
1998/0507    
	oaperture = scr->aperture; 
	oapsize = scr->apsize; 
	wasupamem = scr->isupamem; 
	if(wasupamem) 
		upafree(oaperture, oapsize); 
	scr->isupamem = 0; 
 
	if(p = mach64xxpci()){ 
		aperture = p->mem[0].bar & ~0x0F; 
		*size = p->mem[0].size; 
	} 
	else 
		aperture = 0; 
 
	aperture = upamalloc(aperture, *size, *align); 
	if(aperture == 0){ 
		if(wasupamem && upamalloc(oaperture, oapsize, 0)) 
			scr->isupamem = 1; 
	} 
	else 
		scr->isupamem = 1; 
 
1999/1005    
	scr->mmio = (ulong*)(aperture+osize-0x400); 
	if(oaperture) 
		print("warning (BUG): redefinition of aperture does not change mach64mmio segment\n"); 
	memset(&seg, 0, sizeof(seg)); 
	seg.attr = SG_PHYSICAL; 
	seg.name = smalloc(NAMELEN); 
	snprint(seg.name, NAMELEN, "mach64mmio"); 
	seg.pa = aperture+osize - BY2PG; 
	seg.size = BY2PG; 
	addphysseg(&seg); 
 
	seg.name = smalloc(NAMELEN); 
	snprint(seg.name, NAMELEN, "mach64screen"); 
	seg.pa = aperture; 
	seg.size = osize; 
	addphysseg(&seg); 
 
1998/0507    
	return aperture; 
} 
 
1998/0511    
enum { 
1999/1005    
	CrtcOffPitch	= 0x05, 
	CrtcGenCtl	= 0x07, 
1998/0508    
	CurClr0		= 0x0B,		/* I/O Select */ 
	CurClr1		= 0x0C, 
	CurOffset	= 0x0D, 
	CurHVposn	= 0x0E, 
	CurHVoff	= 0x0F, 
1999/1005    
	BusCntl	= 0x13, 
1998/0508    
	GenTestCntl	= 0x19, 
1999/1005    
 
	ContextMask	= 0x100,	/* not accessible via I/O */ 
	FifoStat, 
	GuiStat, 
	DpFrgdClr, 
	DpBkgdClr, 
	DpWriteMask, 
	DpMix, 
	DpPixWidth, 
	DpSrc, 
	ClrCmpCntl, 
	GuiTrajCntl, 
	ScLeftRight, 
	ScTopBottom, 
	DstOffPitch, 
	DstYX, 
	DstHeightWidth, 
	DstCntl, 
	DstHeight, 
	DstBresErr, 
	DstBresInc, 
	DstBresDec, 
	SrcCntl, 
	SrcHeight1Width1, 
	SrcHeight2Width2, 
	SrcYX, 
	SrcWidth1, 
	SrcYXstart, 
	HostCntl, 
	PatReg0, 
	PatReg1, 
	PatCntl, 
	ScBottom, 
	ScLeft, 
	ScRight, 
	ScTop, 
	ClrCmpClr, 
	ClrCmpMask, 
	DpChainMask, 
	SrcOffPitch,	 
1998/0507    
}; 
 
1998/0508    
static uchar mmoffset[] = { 
1999/1005    
	[CrtcOffPitch]	0x05, 
1998/0508    
	[CurClr0]	0x18, 
	[CurClr1]	0x19, 
1998/0511    
	[CurOffset]	0x1A, 
	[CurHVposn]	0x1B, 
	[CurHVoff]	0x1C, 
1999/1005    
	[BusCntl]		0x28, 
1998/0508    
	[GenTestCntl]	0x34, 
1999/1005    
	[DstOffPitch]	0x40, 
	[DstYX]		0x43, 
	[DstHeight]	0x45, 
	[DstHeightWidth]	0x46, 
	[DstBresErr]	0x49, 
	[DstBresInc]	0x4A, 
	[DstBresDec]	0x4B, 
	[DstCntl]		0x4C, 
	[SrcOffPitch]	0x60, 
	[SrcYX]	0x63, 
	[SrcWidth1]	0x64, 
	[SrcYXstart]	0x69, 
	[SrcHeight1Width1]	0x66, 
	[SrcHeight2Width2]	0x6C, 
	[SrcCntl]		0x6D, 
	[HostCntl]	0x90, 
	[PatReg0]	0xA0, 
	[PatReg1]	0xA1, 
	[PatCntl]	0xA2, 
	[ScLeft]	0xA8, 
	[ScRight]	0xA9, 
	[ScLeftRight]	0xAA, 
	[ScTop]	0xAB, 
	[ScBottom] 0xAC, 
	[ScTopBottom]	0xAD, 
	[DpBkgdClr]	0xB0, 
	[DpFrgdClr]	0xB1, 
	[DpWriteMask]	0xB2, 
	[DpChainMask]	0xB3, 
	[DpPixWidth]	0xB4, 
	[DpMix]		0xB5, 
	[DpSrc]		0xB6, 
	[ClrCmpClr]	0xC0, 
	[ClrCmpMask]	0xC1, 
	[ClrCmpCntl]	0xC2, 
	[FifoStat]		0xC4, 
	[ContextMask]	0xC8, 
	[GuiTrajCntl]	0xCC, 
	[GuiStat]		0xCE, 
1998/0508    
}; 
 
1998/0507    
static ulong 
ior32(VGAscr* scr, int r) 
{ 
1998/0508    
	if(scr->io == 0x2EC || scr->io == 0x1C8) 
		return inl((r<<10)+scr->io); 
1999/1005    
	if(r >= 0x100 && scr->mmio != nil) 
		return scr->mmio[mmoffset[r]]; 
1998/0508    
	return inl((mmoffset[r]<<2)+scr->io); 
1998/0507    
} 
 
static void 
iow32(VGAscr* scr, int r, ulong l) 
{ 
1998/0508    
	if(scr->io == 0x2EC || scr->io == 0x1C8) 
		outl(((r)<<10)+scr->io, l); 
1999/1005    
	else if(r >= 0x100 && scr->mmio != nil) 
		scr->mmio[mmoffset[r]] = l; 
1998/0508    
	else 
		outl((mmoffset[r]<<2)+scr->io, l); 
1998/0507    
} 
 
static void 
mach64xxcurdisable(VGAscr* scr) 
{ 
	ulong r; 
 
	r = ior32(scr, GenTestCntl); 
	iow32(scr, GenTestCntl, r & ~0x80); 
} 
 
static void 
mach64xxcurload(VGAscr* scr, Cursor* curs) 
{ 
	uchar *p; 
	int i, y; 
	ulong c, s, m, r; 
 
	/* 
	 * Disable the cursor. 
	 */ 
	r = ior32(scr, GenTestCntl); 
	iow32(scr, GenTestCntl, r & ~0x80); 
 
	p = KADDR(scr->aperture); 
	p += scr->storage; 
 
1998/0511    
	/* 
	 * Initialise the 64x64 cursor RAM array. 
	 * The cursor mode gives the following truth table: 
	 *	p1 p0	colour 
	 *	 0  0	Cursor Colour 0 
	 *	 0  1	Cursor Colour 1 
	 *	 1  0	Transparent 
	 *	 1  1	Complement 
	 * Put the cursor into the top-right of the 64x64 array. 
	 */ 
1998/0507    
	for(y = 0; y < 16; y++){ 
		for(i = 0; i < (64-16)/8; i++){ 
			*p++ = 0xAA; 
			*p++ = 0xAA; 
		} 
 
		c = (curs->clr[2*y]<<8)|curs->clr[y*2 + 1]; 
		s = (curs->set[2*y]<<8)|curs->set[y*2 + 1]; 
 
		m = 0x00000000; 
		for(i = 0; i < 16; i++){ 
			if(s & (1<<(15-i))) 
				m |= 0x01<<(2*i); 
			else if(c & (1<<(15-i))) 
				; 
			else 
				m |= 0x02<<(2*i); 
		} 
		*p++ = m; 
		*p++ = m>>8; 
		*p++ = m>>16; 
		*p++ = m>>24; 
	} 
	memset(p, 0xAA, (64-16)*16); 
 
	/* 
	 * Set the cursor hotpoint and enable the cursor. 
	 */ 
	scr->offset = curs->offset; 
	iow32(scr, GenTestCntl, 0x80|r); 
} 
 
static int 
1999/1005    
ptalmostinrect(Point p, Rectangle r) 
{ 
	return p.x>=r.min.x && p.x<=r.max.x && 
	       p.y>=r.min.y && p.y<=r.max.y; 
} 
 
/* 
 * If necessary, translate the rectangle physr 
 * some multiple of [dx dy] so that it includes p. 
 * Return 1 if the rectangle changed. 
 */ 
static int 
screenpan(Point p, Rectangle *physr, int dx, int dy) 
{ 
	int d; 
 
	if(ptalmostinrect(p, *physr)) 
		return 0; 
 
	if(p.y < physr->min.y){ 
		d = physr->min.y - (p.y&~(dy-1)); 
		physr->min.y -= d; 
		physr->max.y -= d; 
	} 
	if(p.y > physr->max.y){ 
		d = ((p.y+dy-1)&~(dy-1)) - physr->max.y; 
		physr->min.y += d; 
		physr->max.y += d; 
	} 
 
	if(p.x < physr->min.x){ 
		d = physr->min.x - (p.x&~(dx-1)); 
		physr->min.x -= d; 
		physr->max.x -= d; 
	} 
	if(p.x > physr->max.x){ 
		d = ((p.x+dx-1)&~(dx-1)) - physr->max.x; 
		physr->min.x += d; 
		physr->max.x += d; 
	} 
	return 1; 
} 
 
static int 
1998/0507    
mach64xxcurmove(VGAscr* scr, Point p) 
{ 
	int x, xo, y, yo; 
1999/1005    
	int dx; 
	ulong off, pitch; 
1998/0507    
 
	/* 
1999/1005    
	 * If the point we want to display is outside the current 
	 * screen rectangle, pan the screen to display it. 
	 * 
	 * We have to move in 64-bit chunks. 
	 */ 
	if(scr->gscreen->depth == 24) 
		dx = (64*3)/24; 
	else 
		dx = 64 / scr->gscreen->depth; 
 
	if(screenpan(p, &physgscreenr, dx, 1)){ 
		off = (physgscreenr.min.y*Dx(scr->gscreen->r)+physgscreenr.min.x)/dx; 
		pitch = Dx(scr->gscreen->r)/8; 
		iow32(scr, CrtcOffPitch, (pitch<<22)|off); 
	} 
 
	p.x -= physgscreenr.min.x; 
	p.y -= physgscreenr.min.y; 
 
	/* 
1998/0507    
	 * Mustn't position the cursor offscreen even partially, 
	 * or it disappears. Therefore, if x or y is -ve, adjust the 
	 * cursor presets instead. If y is negative also have to 
	 * adjust the starting offset. 
	 */ 
	if((x = p.x+scr->offset.x) < 0){ 
		xo = x; 
		x = 0; 
	} 
	else 
		xo = 0; 
	if((y = p.y+scr->offset.y) < 0){ 
		yo = y; 
		y = 0; 
	} 
	else 
		yo = 0; 
 
	iow32(scr, CurHVoff, ((64-16-yo)<<16)|(64-16-xo)); 
	iow32(scr, CurOffset, scr->storage/8 + (-yo*2)); 
	iow32(scr, CurHVposn, (y<<16)|x); 
 
	return 0; 
} 
 
static void 
mach64xxcurenable(VGAscr* scr) 
{ 
	ulong r, storage; 
 
	mach64xxenable(scr); 
	if(scr->io == 0) 
		return; 
 
	r = ior32(scr, GenTestCntl); 
	iow32(scr, GenTestCntl, r & ~0x80); 
 
	iow32(scr, CurClr0, (Pwhite<<24)|(Pwhite<<16)|(Pwhite<<8)|Pwhite); 
	iow32(scr, CurClr1, (Pblack<<24)|(Pblack<<16)|(Pblack<<8)|Pblack); 
 
	/* 
	 * Find a place for the cursor data in display memory. 
	 * Must be 64-bit aligned. 
	 */ 
	storage = (scr->gscreen->width*BY2WD*scr->gscreen->r.max.y+7)/8; 
	iow32(scr, CurOffset, storage); 
	scr->storage = storage*8; 
 
	/* 
	 * Cursor goes in the top right corner of the 64x64 array 
	 * so the horizontal and vertical presets are 64-16. 
	 */ 
	iow32(scr, CurHVposn, (0<<16)|0); 
	iow32(scr, CurHVoff, ((64-16)<<16)|(64-16)); 
 
	/* 
	 * Load, locate and enable the 64x64 cursor. 
	 */ 
	mach64xxcurload(scr, &arrow); 
	mach64xxcurmove(scr, ZP); 
	iow32(scr, GenTestCntl, 0x80|r); 
} 
 
1999/1005    
static void 
waitforfifo(VGAscr *scr, int entries) 
{ 
	int x; 
	x = 0; 
	while((ior32(scr, FifoStat)&0xFF) > (0x8000>>entries) && x++ < 1000000) 
		; 
	if(x >= 1000000) 
		iprint("fifo %d stat %.8lux %.8lux scrio %.8lux mmio %p scr %p pc %luX\n", entries, ior32(scr, FifoStat), scr->mmio[mmoffset[FifoStat]], scr->io, scr->mmio, scr, getcallerpc(&scr)); 
} 
 
static void 
waitforidle(VGAscr *scr) 
{ 
	int x; 
	waitforfifo(scr, 16); 
	x = 0; 
	while((ior32(scr, GuiStat)&1) && x++ < 1000000) 
		; 
	if(x >= 1000000) 
		iprint("idle stat %.8lux %.8lux scrio %.8lux mmio %p scr %p pc %luX\n", ior32(scr, GuiStat), scr->mmio[mmoffset[GuiStat]], scr->io, scr->mmio, scr, getcallerpc(&scr)); 
} 
 
static void 
resetengine(VGAscr *scr) 
{ 
	ulong x; 
	x = ior32(scr, GenTestCntl); 
	iow32(scr, GenTestCntl, x&~0x100); 
	iow32(scr, GenTestCntl, x|0x100); 
	iow32(scr, BusCntl, ior32(scr, BusCntl)|0x00A00000); 
} 
 
static void 
initengine(VGAscr *scr) 
{ 
	ulong pitch; 
 
	pitch = Dx(scr->gscreen->r)/8; 
	if(scr->gscreen->depth == 24) 
		pitch *= 3; 
 
	resetengine(scr); 
	waitforfifo(scr, 14); 
	iow32(scr, ContextMask, ~0); 
	iow32(scr, DstOffPitch, pitch<<22); 
	iow32(scr, DstYX, 0); 
	iow32(scr, DstHeight, 0); 
	iow32(scr, DstBresErr, 0); 
	iow32(scr, DstBresInc, 0); 
	iow32(scr, DstBresDec, 0); 
	iow32(scr, DstCntl, 0x23); 
	iow32(scr, SrcOffPitch, pitch<<22); 
	iow32(scr, SrcYX, 0); 
	iow32(scr, SrcHeight1Width1, 1); 
	iow32(scr, SrcYXstart, 0); 
	iow32(scr, SrcHeight2Width2, 1); 
	iow32(scr, SrcCntl, 0x01); 
 
	waitforfifo(scr, 13); 
	iow32(scr, HostCntl, 0); 
	iow32(scr, PatReg0, 0); 
	iow32(scr, PatReg1, 0); 
	iow32(scr, PatCntl, 0); 
	iow32(scr, ScLeft, 0); 
	iow32(scr, ScTop, 0); 
	iow32(scr, ScBottom, 0xFFFF); 
	iow32(scr, ScRight, 0xFFFF); 
	iow32(scr, DpBkgdClr, 0); 
	iow32(scr, DpFrgdClr, ~0); 
	iow32(scr, DpWriteMask, ~0); 
	iow32(scr, DpMix, 0x70003); 
	iow32(scr, DpSrc, 0x00010100); 
 
	waitforfifo(scr, 3); 
	iow32(scr, ClrCmpClr, 0); 
	iow32(scr, ClrCmpMask, ~0); 
	iow32(scr, ClrCmpCntl, 0); 
 
	waitforfifo(scr, 2); 
	switch(scr->gscreen->depth){ 
	case 8: 
	case 24:	/* [sic] */ 
		iow32(scr, DpPixWidth, 0x00020202); 
		iow32(scr, DpChainMask, 0x8080); 
		break; 
	case 16: 
		iow32(scr, DpPixWidth, 0x00040404); 
		iow32(scr, DpChainMask, 0x8410); 
		break; 
	case 32: 
		iow32(scr, DpPixWidth, 0x00060606); 
		iow32(scr, DpChainMask, 0x8080); 
		break; 
	} 
 
	waitforidle(scr); 
} 
 
static int 
mach64hwfill(VGAscr *scr, Rectangle r, ulong sval) 
{ 
	ulong pitch; 
	ulong ctl; 
 
if(drawdebug) 
	iprint("hwfill %R val %lux...\n", r, sval); 
 
	/* shouldn't happen */ 
	if(scr->io == 0x2EC || scr->io == 0x1C8 || scr->io == 0) 
		return 0; 
 
	pitch = Dx(scr->gscreen->r)/8; 
	ctl = 1|2;	/* left-to-right, top-to-bottom */ 
	if(scr->gscreen->depth == 24){ 
		r.min.x *= 3; 
		r.max.x *= 3; 
		pitch *= 3; 
		ctl |= (1<<7)|(((r.min.x/4)%6)<<8); 
	} 
 
	waitforfifo(scr, 11); 
	iow32(scr, DpFrgdClr, sval); 
	iow32(scr, DpWriteMask, 0xFFFFFFFF); 
	iow32(scr, DpMix, 0x00070003); 
	iow32(scr, DpSrc, 0x00000111); 
	iow32(scr, ClrCmpCntl, 0x00000000); 
	iow32(scr, ScLeftRight, 0x1FFF0000); 
	iow32(scr, ScTopBottom, 0x1FFF0000); 
	iow32(scr, DstOffPitch, pitch<<22); 
	iow32(scr, DstCntl, ctl); 
	iow32(scr, DstYX, (r.min.x<<16)|r.min.y); 
	iow32(scr, DstHeightWidth, (Dx(r)<<16)|Dy(r)); 
 
	waitforidle(scr); 
	return 1; 
} 
 
static int 
mach64hwscroll(VGAscr *scr, Rectangle r, Rectangle sr) 
{ 
	ulong pitch; 
	Point dp, sp; 
	ulong ctl; 
	int dx, dy; 
 
	dx = Dx(r); 
	dy = Dy(r); 
	pitch = Dx(scr->gscreen->r)/8; 
	if(scr->gscreen->depth == 24){ 
		dx *= 3; 
		pitch *= 3; 
		r.min.x *= 3; 
		sr.min.x *= 3; 
	} 
 
	ctl = 0; 
	if(r.min.x <= sr.min.x){ 
		ctl |= 1; 
		dp.x = r.min.x; 
		sp.x = sr.min.x; 
	}else{ 
		dp.x = r.min.x+dx-1; 
		sp.x = sr.min.x+dx-1; 
	} 
 
	if(r.min.y <= sr.min.y){ 
		ctl |= 2; 
		dp.y = r.min.y; 
		sp.y = sr.min.y; 
	}else{ 
		dp.y = r.min.y+dy-1; 
		sp.y = sr.min.y+dy-1; 
	} 
 
	if(scr->gscreen->depth == 24) 
		ctl |= (1<<7)|(((dp.x/4)%6)<<8); 
 
	waitforfifo(scr, 6); 
	iow32(scr, ScLeftRight, 0x1FFF0000); 
	iow32(scr, ScTopBottom, 0x1FFF0000); 
	iow32(scr, DpWriteMask, 0xFFFFFFFF); 
	iow32(scr, DpMix, 0x00070003); 
	iow32(scr, DpSrc, 0x00000300); 
	iow32(scr, ClrCmpCntl, 0x00000000); 
 
	waitforfifo(scr, 8); 
	iow32(scr, SrcOffPitch, pitch<<22); 
	iow32(scr, SrcCntl, 0x00000000); 
	iow32(scr, SrcYX, (sp.x<<16)|sp.y); 
	iow32(scr, SrcWidth1, dx); 
	iow32(scr, DstOffPitch, pitch<<22); 
	iow32(scr, DstCntl, ctl); 
 
	iow32(scr, DstYX, (dp.x<<16)|dp.y); 
	iow32(scr, DstHeightWidth, (dx<<16)|dy); 
 
	waitforidle(scr); 
 
	return 1; 
} 
 
static void 
mach64xxdrawinit(VGAscr *scr) 
{ 
	if(scr->io > 0x2FF){ 
		initengine(scr); 
		scr->fill = mach64hwfill; 
		scr->scroll = mach64hwscroll; 
	} 
} 
 
 
1998/0507    
VGAdev vgamach64xxdev = { 
	"mach64xx", 
 
	mach64xxenable,			/* enable */ 
	0,				/* disable */ 
	0,				/* page */ 
	mach64xxlinear,			/* linear */ 
1999/1005    
	mach64xxdrawinit,	/* drawinit */ 
1998/0507    
}; 
 
VGAcur vgamach64xxcur = { 
	"mach64xxhwgc", 
 
	mach64xxcurenable,		/* enable */ 
	mach64xxcurdisable,		/* disable */ 
	mach64xxcurload,		/* load */ 
	mach64xxcurmove,		/* move */ 
1999/1005    
 
	1					/* doespanning */ 
1998/0507    
}; 


source code copyright © 1990-2005 Lucent Technologies; see license
Plan 9 distribution
comments to russ cox (rsc@swtch.com)