xref: /plan9/sys/src/9/bcm/vcore.c (revision b4d1cf41cd5301e4c76aef9c04ddee28ac168a8e)
15d9de2d3SDavid du Colombier #include "u.h"
25d9de2d3SDavid du Colombier #include "../port/lib.h"
35d9de2d3SDavid du Colombier #include "mem.h"
45d9de2d3SDavid du Colombier #include "dat.h"
55d9de2d3SDavid du Colombier #include "fns.h"
65d9de2d3SDavid du Colombier 
75d9de2d3SDavid du Colombier /*
85d9de2d3SDavid du Colombier  * Mailbox interface with videocore gpu
95d9de2d3SDavid du Colombier  */
105d9de2d3SDavid du Colombier 
115d9de2d3SDavid du Colombier #define	MAILBOX		(VIRTIO+0xB880)
125d9de2d3SDavid du Colombier 
135d9de2d3SDavid du Colombier typedef struct Prophdr Prophdr;
145d9de2d3SDavid du Colombier typedef struct Fbinfo Fbinfo;
155d9de2d3SDavid du Colombier 
165d9de2d3SDavid du Colombier enum {
175d9de2d3SDavid du Colombier 	Read		= 0x00>>2,
185d9de2d3SDavid du Colombier 	Write		= 0x00>>2,
195d9de2d3SDavid du Colombier 	Peek		= 0x10>>2,
205d9de2d3SDavid du Colombier 	Sender		= 0x14>>2,
215d9de2d3SDavid du Colombier 	Status		= 0x18>>2,
225d9de2d3SDavid du Colombier 		Full		= 1<<31,
235d9de2d3SDavid du Colombier 		Empty		= 1<<30,
245d9de2d3SDavid du Colombier 	Config		= 0x1C>>2,
255d9de2d3SDavid du Colombier 	NRegs		= 0x20>>2,
265d9de2d3SDavid du Colombier 
275d9de2d3SDavid du Colombier 	ChanMask	= 0xF,
285d9de2d3SDavid du Colombier 	ChanProps	= 8,
295d9de2d3SDavid du Colombier 	ChanFb		= 1,
305d9de2d3SDavid du Colombier 
315d9de2d3SDavid du Colombier 	Req			= 0x0,
325d9de2d3SDavid du Colombier 	RspOk		= 0x80000000,
335d9de2d3SDavid du Colombier 	TagResp		= 1<<31,
345d9de2d3SDavid du Colombier 
355d9de2d3SDavid du Colombier 	TagGetfwrev	= 0x00000001,
365d9de2d3SDavid du Colombier 	TagGetmac	= 0x00010003,
375d9de2d3SDavid du Colombier 	TagGetram	= 0x00010005,
385d9de2d3SDavid du Colombier 	TagGetpower	= 0x00020001,
395d9de2d3SDavid du Colombier 	TagSetpower	= 0x00028001,
405d9de2d3SDavid du Colombier 		Powerwait	= 1<<1,
415d9de2d3SDavid du Colombier 	TagGetclkspd= 0x00030002,
425d9de2d3SDavid du Colombier 	TagFballoc	= 0x00040001,
435d9de2d3SDavid du Colombier 	TagFbfree	= 0x00048001,
445d9de2d3SDavid du Colombier 	TagFbblank	= 0x00040002,
455d9de2d3SDavid du Colombier 	TagGetres	= 0x00040003,
465d9de2d3SDavid du Colombier 	TagSetres	= 0x00048003,
475d9de2d3SDavid du Colombier 	TagGetvres	= 0x00040004,
485d9de2d3SDavid du Colombier 	TagSetvres	= 0x00048004,
495d9de2d3SDavid du Colombier 	TagGetdepth	= 0x00040005,
505d9de2d3SDavid du Colombier 	TagSetdepth	= 0x00048005,
515d9de2d3SDavid du Colombier 	TagGetrgb	= 0x00044006,
525d9de2d3SDavid du Colombier 	TagSetrgb	= 0x00048006,
535d9de2d3SDavid du Colombier };
545d9de2d3SDavid du Colombier 
555d9de2d3SDavid du Colombier struct Fbinfo {
565d9de2d3SDavid du Colombier 	u32int	xres;
575d9de2d3SDavid du Colombier 	u32int	yres;
585d9de2d3SDavid du Colombier 	u32int	xresvirtual;
595d9de2d3SDavid du Colombier 	u32int	yresvirtual;
605d9de2d3SDavid du Colombier 	u32int	pitch;			/* returned by gpu */
615d9de2d3SDavid du Colombier 	u32int	bpp;
625d9de2d3SDavid du Colombier 	u32int	xoffset;
635d9de2d3SDavid du Colombier 	u32int	yoffset;
645d9de2d3SDavid du Colombier 	u32int	base;			/* returned by gpu */
655d9de2d3SDavid du Colombier 	u32int	screensize;		/* returned by gpu */
665d9de2d3SDavid du Colombier };
675d9de2d3SDavid du Colombier 
685d9de2d3SDavid du Colombier 
695d9de2d3SDavid du Colombier struct Prophdr {
705d9de2d3SDavid du Colombier 	u32int	len;
715d9de2d3SDavid du Colombier 	u32int	req;
725d9de2d3SDavid du Colombier 	u32int	tag;
735d9de2d3SDavid du Colombier 	u32int	tagbuflen;
745d9de2d3SDavid du Colombier 	u32int	taglen;
755d9de2d3SDavid du Colombier 	u32int	data[1];
765d9de2d3SDavid du Colombier };
775d9de2d3SDavid du Colombier 
785d9de2d3SDavid du Colombier static void
vcwrite(uint chan,int val)795d9de2d3SDavid du Colombier vcwrite(uint chan, int val)
805d9de2d3SDavid du Colombier {
815d9de2d3SDavid du Colombier 	u32int *r;
825d9de2d3SDavid du Colombier 
835d9de2d3SDavid du Colombier 	r = (u32int*)MAILBOX + NRegs;
845d9de2d3SDavid du Colombier 	val &= ~ChanMask;
855d9de2d3SDavid du Colombier 	while(r[Status]&Full)
865d9de2d3SDavid du Colombier 		;
875d9de2d3SDavid du Colombier 	coherence();
885d9de2d3SDavid du Colombier 	r[Write] = val | chan;
895d9de2d3SDavid du Colombier }
905d9de2d3SDavid du Colombier 
915d9de2d3SDavid du Colombier static int
vcread(uint chan)925d9de2d3SDavid du Colombier vcread(uint chan)
935d9de2d3SDavid du Colombier {
945d9de2d3SDavid du Colombier 	u32int *r;
955d9de2d3SDavid du Colombier 	int x;
965d9de2d3SDavid du Colombier 
975d9de2d3SDavid du Colombier 	r = (u32int*)MAILBOX;
985d9de2d3SDavid du Colombier 	do{
995d9de2d3SDavid du Colombier 		while(r[Status]&Empty)
1005d9de2d3SDavid du Colombier 			;
1015d9de2d3SDavid du Colombier 		coherence();
1025d9de2d3SDavid du Colombier 		x = r[Read];
1035d9de2d3SDavid du Colombier 	}while((x&ChanMask) != chan);
1045d9de2d3SDavid du Colombier 	return x & ~ChanMask;
1055d9de2d3SDavid du Colombier }
1065d9de2d3SDavid du Colombier 
1075d9de2d3SDavid du Colombier /*
1085d9de2d3SDavid du Colombier  * Property interface
1095d9de2d3SDavid du Colombier  */
1105d9de2d3SDavid du Colombier 
1115d9de2d3SDavid du Colombier static int
vcreq(int tag,void * buf,int vallen,int rsplen)1125d9de2d3SDavid du Colombier vcreq(int tag, void *buf, int vallen, int rsplen)
1135d9de2d3SDavid du Colombier {
1145d9de2d3SDavid du Colombier 	uintptr r;
1155d9de2d3SDavid du Colombier 	int n;
1165d9de2d3SDavid du Colombier 	Prophdr *prop;
1175d9de2d3SDavid du Colombier 	static uintptr base = BUSDRAM;
1185d9de2d3SDavid du Colombier 
1195d9de2d3SDavid du Colombier 	if(rsplen < vallen)
1205d9de2d3SDavid du Colombier 		rsplen = vallen;
1215d9de2d3SDavid du Colombier 	rsplen = (rsplen+3) & ~3;
1225d9de2d3SDavid du Colombier 	prop = (Prophdr*)(VCBUFFER);
1235d9de2d3SDavid du Colombier 	n = sizeof(Prophdr) + rsplen + 8;
1245d9de2d3SDavid du Colombier 	memset(prop, 0, n);
1255d9de2d3SDavid du Colombier 	prop->len = n;
1265d9de2d3SDavid du Colombier 	prop->req = Req;
1275d9de2d3SDavid du Colombier 	prop->tag = tag;
1285d9de2d3SDavid du Colombier 	prop->tagbuflen = rsplen;
1295d9de2d3SDavid du Colombier 	prop->taglen = vallen;
1305d9de2d3SDavid du Colombier 	if(vallen > 0)
1315d9de2d3SDavid du Colombier 		memmove(prop->data, buf, vallen);
1325d9de2d3SDavid du Colombier 	cachedwbinvse(prop, prop->len);
1335d9de2d3SDavid du Colombier 	for(;;){
1345d9de2d3SDavid du Colombier 		vcwrite(ChanProps, PADDR(prop) + base);
1355d9de2d3SDavid du Colombier 		r = vcread(ChanProps);
1365d9de2d3SDavid du Colombier 		if(r == PADDR(prop) + base)
1375d9de2d3SDavid du Colombier 			break;
1385d9de2d3SDavid du Colombier 		if(base == 0)
1395d9de2d3SDavid du Colombier 			return -1;
1405d9de2d3SDavid du Colombier 		base = 0;
1415d9de2d3SDavid du Colombier 	}
142*b4d1cf41SDavid du Colombier 	if(prop->req == RspOk &&
143*b4d1cf41SDavid du Colombier 	   prop->tag == tag &&
144*b4d1cf41SDavid du Colombier 	   (prop->taglen&TagResp)) {
1455d9de2d3SDavid du Colombier 		if((n = prop->taglen & ~TagResp) < rsplen)
1465d9de2d3SDavid du Colombier 			rsplen = n;
1475d9de2d3SDavid du Colombier 		memmove(buf, prop->data, rsplen);
1485d9de2d3SDavid du Colombier 	}else
1495d9de2d3SDavid du Colombier 		rsplen = -1;
1505d9de2d3SDavid du Colombier 
1515d9de2d3SDavid du Colombier 	return rsplen;
1525d9de2d3SDavid du Colombier }
1535d9de2d3SDavid du Colombier 
1545d9de2d3SDavid du Colombier /*
1555d9de2d3SDavid du Colombier  * Framebuffer
1565d9de2d3SDavid du Colombier  */
1575d9de2d3SDavid du Colombier 
1585d9de2d3SDavid du Colombier static int
fbdefault(int * width,int * height,int * depth)1595d9de2d3SDavid du Colombier fbdefault(int *width, int *height, int *depth)
1605d9de2d3SDavid du Colombier {
1615d9de2d3SDavid du Colombier 	u32int buf[3];
1625d9de2d3SDavid du Colombier 
1635d9de2d3SDavid du Colombier 	if(vcreq(TagGetres, &buf[0], 0, 2*4) != 2*4 ||
1645d9de2d3SDavid du Colombier 	   vcreq(TagGetdepth, &buf[2], 0, 4) != 4)
1655d9de2d3SDavid du Colombier 		return -1;
1665d9de2d3SDavid du Colombier 	*width = buf[0];
1675d9de2d3SDavid du Colombier 	*height = buf[1];
1685d9de2d3SDavid du Colombier 	*depth = buf[2];
1695d9de2d3SDavid du Colombier 	return 0;
1705d9de2d3SDavid du Colombier }
1715d9de2d3SDavid du Colombier 
1725d9de2d3SDavid du Colombier void*
fbinit(int set,int * width,int * height,int * depth)1735d9de2d3SDavid du Colombier fbinit(int set, int *width, int *height, int *depth)
1745d9de2d3SDavid du Colombier {
1755d9de2d3SDavid du Colombier 	Fbinfo *fi;
1765d9de2d3SDavid du Colombier 	uintptr va;
1775d9de2d3SDavid du Colombier 
1785d9de2d3SDavid du Colombier 	if(!set)
1795d9de2d3SDavid du Colombier 		fbdefault(width, height, depth);
1805d9de2d3SDavid du Colombier 	/* Screen width must be a multiple of 16 */
1815d9de2d3SDavid du Colombier 	*width &= ~0xF;
1825d9de2d3SDavid du Colombier 	fi = (Fbinfo*)(VCBUFFER);
1835d9de2d3SDavid du Colombier 	memset(fi, 0, sizeof(*fi));
1845d9de2d3SDavid du Colombier 	fi->xres = fi->xresvirtual = *width;
1855d9de2d3SDavid du Colombier 	fi->yres = fi->yresvirtual = *height;
1865d9de2d3SDavid du Colombier 	fi->bpp = *depth;
1875d9de2d3SDavid du Colombier 	cachedwbinvse(fi, sizeof(*fi));
1885d9de2d3SDavid du Colombier 	vcwrite(ChanFb, DMAADDR(fi));
1895d9de2d3SDavid du Colombier 	if(vcread(ChanFb) != 0)
1905d9de2d3SDavid du Colombier 		return 0;
1915d9de2d3SDavid du Colombier 	va = mmukmap(FRAMEBUFFER, PADDR(fi->base), fi->screensize);
1925d9de2d3SDavid du Colombier 	if(va)
1935d9de2d3SDavid du Colombier 		memset((char*)va, 0x7F, fi->screensize);
1945d9de2d3SDavid du Colombier 	return (void*)va;
1955d9de2d3SDavid du Colombier }
1965d9de2d3SDavid du Colombier 
1975d9de2d3SDavid du Colombier int
fbblank(int blank)1985d9de2d3SDavid du Colombier fbblank(int blank)
1995d9de2d3SDavid du Colombier {
2005d9de2d3SDavid du Colombier 	u32int buf[1];
2015d9de2d3SDavid du Colombier 
2025d9de2d3SDavid du Colombier 	buf[0] = blank;
2035d9de2d3SDavid du Colombier 	if(vcreq(TagFbblank, buf, sizeof buf, sizeof buf) != sizeof buf)
2045d9de2d3SDavid du Colombier 		return -1;
2055d9de2d3SDavid du Colombier 	return buf[0] & 1;
2065d9de2d3SDavid du Colombier }
2075d9de2d3SDavid du Colombier 
2085d9de2d3SDavid du Colombier /*
2095d9de2d3SDavid du Colombier  * Power management
2105d9de2d3SDavid du Colombier  */
2115d9de2d3SDavid du Colombier void
setpower(int dev,int on)2125d9de2d3SDavid du Colombier setpower(int dev, int on)
2135d9de2d3SDavid du Colombier {
2145d9de2d3SDavid du Colombier 	u32int buf[2];
2155d9de2d3SDavid du Colombier 
2165d9de2d3SDavid du Colombier 	buf[0] = dev;
2175d9de2d3SDavid du Colombier 	buf[1] = Powerwait | (on? 1 : 0);
2185d9de2d3SDavid du Colombier 	vcreq(TagSetpower, buf, sizeof buf, sizeof buf);
2195d9de2d3SDavid du Colombier }
2205d9de2d3SDavid du Colombier 
2215d9de2d3SDavid du Colombier int
getpower(int dev)2225d9de2d3SDavid du Colombier getpower(int dev)
2235d9de2d3SDavid du Colombier {
2245d9de2d3SDavid du Colombier 	u32int buf[2];
2255d9de2d3SDavid du Colombier 
2265d9de2d3SDavid du Colombier 	buf[0] = dev;
2275d9de2d3SDavid du Colombier 	buf[1] = 0;
2285d9de2d3SDavid du Colombier 	if(vcreq(TagGetpower, buf, sizeof buf[0], sizeof buf) != sizeof buf)
2295d9de2d3SDavid du Colombier 		return -1;
2305d9de2d3SDavid du Colombier 	return buf[0] & 1;
2315d9de2d3SDavid du Colombier }
2325d9de2d3SDavid du Colombier 
2335d9de2d3SDavid du Colombier /*
2345d9de2d3SDavid du Colombier  * Get ethernet address (as hex string)
2355d9de2d3SDavid du Colombier  *	 [not reentrant]
2365d9de2d3SDavid du Colombier  */
2375d9de2d3SDavid du Colombier char *
getethermac(void)2385d9de2d3SDavid du Colombier getethermac(void)
2395d9de2d3SDavid du Colombier {
2405d9de2d3SDavid du Colombier 	uchar ea[8];
2415d9de2d3SDavid du Colombier 	char *p;
2425d9de2d3SDavid du Colombier 	int i;
2435d9de2d3SDavid du Colombier 	static char buf[16];
2445d9de2d3SDavid du Colombier 
2455d9de2d3SDavid du Colombier 	memset(ea, 0, sizeof ea);
2465d9de2d3SDavid du Colombier 	vcreq(TagGetmac, ea, 0, sizeof ea);
2475d9de2d3SDavid du Colombier 	p = buf;
2485d9de2d3SDavid du Colombier 	for(i = 0; i < 6; i++)
2495d9de2d3SDavid du Colombier 		p += sprint(p, "%.2x", ea[i]);
2505d9de2d3SDavid du Colombier 	return buf;
2515d9de2d3SDavid du Colombier }
2525d9de2d3SDavid du Colombier 
2535d9de2d3SDavid du Colombier /*
2545d9de2d3SDavid du Colombier  * Get firmware revision
2555d9de2d3SDavid du Colombier  */
2565d9de2d3SDavid du Colombier uint
getfirmware(void)2575d9de2d3SDavid du Colombier getfirmware(void)
2585d9de2d3SDavid du Colombier {
2595d9de2d3SDavid du Colombier 	u32int buf[1];
2605d9de2d3SDavid du Colombier 
2615d9de2d3SDavid du Colombier 	if(vcreq(TagGetfwrev, buf, 0, sizeof buf) != sizeof buf)
2625d9de2d3SDavid du Colombier 		return 0;
2635d9de2d3SDavid du Colombier 	return buf[0];
2645d9de2d3SDavid du Colombier }
2655d9de2d3SDavid du Colombier 
2665d9de2d3SDavid du Colombier /*
2675d9de2d3SDavid du Colombier  * Get ARM ram
2685d9de2d3SDavid du Colombier  */
2695d9de2d3SDavid du Colombier void
getramsize(Confmem * mem)2705d9de2d3SDavid du Colombier getramsize(Confmem *mem)
2715d9de2d3SDavid du Colombier {
2725d9de2d3SDavid du Colombier 	u32int buf[2];
2735d9de2d3SDavid du Colombier 
2745d9de2d3SDavid du Colombier 	if(vcreq(TagGetram, buf, 0, sizeof buf) != sizeof buf)
2755d9de2d3SDavid du Colombier 		return;
2765d9de2d3SDavid du Colombier 	mem->base = buf[0];
2775d9de2d3SDavid du Colombier 	mem->limit = buf[1];
2785d9de2d3SDavid du Colombier }
2795d9de2d3SDavid du Colombier 
2805d9de2d3SDavid du Colombier /*
2815d9de2d3SDavid du Colombier  * Get clock rate
2825d9de2d3SDavid du Colombier  */
2835d9de2d3SDavid du Colombier ulong
getclkrate(int clkid)2845d9de2d3SDavid du Colombier getclkrate(int clkid)
2855d9de2d3SDavid du Colombier {
2865d9de2d3SDavid du Colombier 	u32int buf[2];
2875d9de2d3SDavid du Colombier 
2885d9de2d3SDavid du Colombier 	buf[0] = clkid;
2895d9de2d3SDavid du Colombier 	if(vcreq(TagGetclkspd, buf, sizeof(buf[0]), sizeof(buf)) != sizeof buf)
2905d9de2d3SDavid du Colombier 		return 0;
2915d9de2d3SDavid du Colombier 	return buf[1];
2925d9de2d3SDavid du Colombier }
293