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;
15*5c47fe09SDavid du Colombier typedef struct Vgpio Vgpio;
165d9de2d3SDavid du Colombier
175d9de2d3SDavid du Colombier enum {
185d9de2d3SDavid du Colombier Read = 0x00>>2,
195d9de2d3SDavid du Colombier Write = 0x00>>2,
205d9de2d3SDavid du Colombier Peek = 0x10>>2,
215d9de2d3SDavid du Colombier Sender = 0x14>>2,
225d9de2d3SDavid du Colombier Status = 0x18>>2,
235d9de2d3SDavid du Colombier Full = 1<<31,
245d9de2d3SDavid du Colombier Empty = 1<<30,
255d9de2d3SDavid du Colombier Config = 0x1C>>2,
265d9de2d3SDavid du Colombier NRegs = 0x20>>2,
275d9de2d3SDavid du Colombier
285d9de2d3SDavid du Colombier ChanMask = 0xF,
295d9de2d3SDavid du Colombier ChanProps = 8,
305d9de2d3SDavid du Colombier ChanFb = 1,
315d9de2d3SDavid du Colombier
325d9de2d3SDavid du Colombier Req = 0x0,
335d9de2d3SDavid du Colombier RspOk = 0x80000000,
345d9de2d3SDavid du Colombier TagResp = 1<<31,
355d9de2d3SDavid du Colombier
365d9de2d3SDavid du Colombier TagGetfwrev = 0x00000001,
37*5c47fe09SDavid du Colombier TagGetrev = 0x00010002,
385d9de2d3SDavid du Colombier TagGetmac = 0x00010003,
39*5c47fe09SDavid du Colombier TagGetser = 0x00010004,
405d9de2d3SDavid du Colombier TagGetram = 0x00010005,
415d9de2d3SDavid du Colombier TagGetpower = 0x00020001,
425d9de2d3SDavid du Colombier TagSetpower = 0x00028001,
435d9de2d3SDavid du Colombier Powerwait = 1<<1,
445d9de2d3SDavid du Colombier TagGetclkspd= 0x00030002,
45*5c47fe09SDavid du Colombier TagGetclkmax= 0x00030004,
46*5c47fe09SDavid du Colombier TagSetclkspd= 0x00038002,
47*5c47fe09SDavid du Colombier TagGettemp = 0x00030006,
48*5c47fe09SDavid du Colombier TagXhciReset= 0x00030058,
495d9de2d3SDavid du Colombier TagFballoc = 0x00040001,
505d9de2d3SDavid du Colombier TagFbfree = 0x00048001,
515d9de2d3SDavid du Colombier TagFbblank = 0x00040002,
525d9de2d3SDavid du Colombier TagGetres = 0x00040003,
535d9de2d3SDavid du Colombier TagSetres = 0x00048003,
545d9de2d3SDavid du Colombier TagGetvres = 0x00040004,
555d9de2d3SDavid du Colombier TagSetvres = 0x00048004,
565d9de2d3SDavid du Colombier TagGetdepth = 0x00040005,
575d9de2d3SDavid du Colombier TagSetdepth = 0x00048005,
58*5c47fe09SDavid du Colombier TagGetrgb = 0x00040006,
595d9de2d3SDavid du Colombier TagSetrgb = 0x00048006,
60*5c47fe09SDavid du Colombier TagGetGpio = 0x00040010,
61*5c47fe09SDavid du Colombier
62*5c47fe09SDavid du Colombier Nvgpio = 2,
635d9de2d3SDavid du Colombier };
645d9de2d3SDavid du Colombier
655d9de2d3SDavid du Colombier struct Fbinfo {
665d9de2d3SDavid du Colombier u32int xres;
675d9de2d3SDavid du Colombier u32int yres;
685d9de2d3SDavid du Colombier u32int xresvirtual;
695d9de2d3SDavid du Colombier u32int yresvirtual;
705d9de2d3SDavid du Colombier u32int pitch; /* returned by gpu */
715d9de2d3SDavid du Colombier u32int bpp;
725d9de2d3SDavid du Colombier u32int xoffset;
735d9de2d3SDavid du Colombier u32int yoffset;
745d9de2d3SDavid du Colombier u32int base; /* returned by gpu */
755d9de2d3SDavid du Colombier u32int screensize; /* returned by gpu */
765d9de2d3SDavid du Colombier };
775d9de2d3SDavid du Colombier
785d9de2d3SDavid du Colombier
795d9de2d3SDavid du Colombier struct Prophdr {
805d9de2d3SDavid du Colombier u32int len;
815d9de2d3SDavid du Colombier u32int req;
825d9de2d3SDavid du Colombier u32int tag;
835d9de2d3SDavid du Colombier u32int tagbuflen;
845d9de2d3SDavid du Colombier u32int taglen;
855d9de2d3SDavid du Colombier u32int data[1];
865d9de2d3SDavid du Colombier };
875d9de2d3SDavid du Colombier
88*5c47fe09SDavid du Colombier struct Vgpio {
89*5c47fe09SDavid du Colombier u32int *counts;
90*5c47fe09SDavid du Colombier u16int incs;
91*5c47fe09SDavid du Colombier u16int decs;
92*5c47fe09SDavid du Colombier int ison;
93*5c47fe09SDavid du Colombier };
94*5c47fe09SDavid du Colombier
95*5c47fe09SDavid du Colombier static Vgpio vgpio;
96*5c47fe09SDavid du Colombier
975d9de2d3SDavid du Colombier static void
vcwrite(uint chan,int val)985d9de2d3SDavid du Colombier vcwrite(uint chan, int val)
995d9de2d3SDavid du Colombier {
1005d9de2d3SDavid du Colombier u32int *r;
1015d9de2d3SDavid du Colombier
1025d9de2d3SDavid du Colombier r = (u32int*)MAILBOX + NRegs;
1035d9de2d3SDavid du Colombier val &= ~ChanMask;
1045d9de2d3SDavid du Colombier while(r[Status]&Full)
1055d9de2d3SDavid du Colombier ;
1065d9de2d3SDavid du Colombier coherence();
1075d9de2d3SDavid du Colombier r[Write] = val | chan;
1085d9de2d3SDavid du Colombier }
1095d9de2d3SDavid du Colombier
1105d9de2d3SDavid du Colombier static int
vcread(uint chan)1115d9de2d3SDavid du Colombier vcread(uint chan)
1125d9de2d3SDavid du Colombier {
1135d9de2d3SDavid du Colombier u32int *r;
1145d9de2d3SDavid du Colombier int x;
1155d9de2d3SDavid du Colombier
1165d9de2d3SDavid du Colombier r = (u32int*)MAILBOX;
1175d9de2d3SDavid du Colombier do{
1185d9de2d3SDavid du Colombier while(r[Status]&Empty)
1195d9de2d3SDavid du Colombier ;
1205d9de2d3SDavid du Colombier coherence();
1215d9de2d3SDavid du Colombier x = r[Read];
1225d9de2d3SDavid du Colombier }while((x&ChanMask) != chan);
1235d9de2d3SDavid du Colombier return x & ~ChanMask;
1245d9de2d3SDavid du Colombier }
1255d9de2d3SDavid du Colombier
1265d9de2d3SDavid du Colombier /*
1275d9de2d3SDavid du Colombier * Property interface
1285d9de2d3SDavid du Colombier */
1295d9de2d3SDavid du Colombier
1305d9de2d3SDavid du Colombier static int
vcreq(int tag,void * buf,int vallen,int rsplen)1315d9de2d3SDavid du Colombier vcreq(int tag, void *buf, int vallen, int rsplen)
1325d9de2d3SDavid du Colombier {
1335d9de2d3SDavid du Colombier uintptr r;
1345d9de2d3SDavid du Colombier int n;
1355d9de2d3SDavid du Colombier Prophdr *prop;
136*5c47fe09SDavid du Colombier uintptr aprop;
137*5c47fe09SDavid du Colombier static int busaddr = 1;
1385d9de2d3SDavid du Colombier
1395d9de2d3SDavid du Colombier if(rsplen < vallen)
1405d9de2d3SDavid du Colombier rsplen = vallen;
1415d9de2d3SDavid du Colombier rsplen = (rsplen+3) & ~3;
1425d9de2d3SDavid du Colombier prop = (Prophdr*)(VCBUFFER);
1435d9de2d3SDavid du Colombier n = sizeof(Prophdr) + rsplen + 8;
1445d9de2d3SDavid du Colombier memset(prop, 0, n);
1455d9de2d3SDavid du Colombier prop->len = n;
1465d9de2d3SDavid du Colombier prop->req = Req;
1475d9de2d3SDavid du Colombier prop->tag = tag;
1485d9de2d3SDavid du Colombier prop->tagbuflen = rsplen;
1495d9de2d3SDavid du Colombier prop->taglen = vallen;
1505d9de2d3SDavid du Colombier if(vallen > 0)
1515d9de2d3SDavid du Colombier memmove(prop->data, buf, vallen);
1525d9de2d3SDavid du Colombier cachedwbinvse(prop, prop->len);
1535d9de2d3SDavid du Colombier for(;;){
154*5c47fe09SDavid du Colombier aprop = busaddr? dmaaddr(prop) : PTR2UINT(prop);
155*5c47fe09SDavid du Colombier vcwrite(ChanProps, aprop);
1565d9de2d3SDavid du Colombier r = vcread(ChanProps);
157*5c47fe09SDavid du Colombier if(r == aprop)
1585d9de2d3SDavid du Colombier break;
159*5c47fe09SDavid du Colombier if(!busaddr)
1605d9de2d3SDavid du Colombier return -1;
161*5c47fe09SDavid du Colombier busaddr = 0;
1625d9de2d3SDavid du Colombier }
163b4d1cf41SDavid du Colombier if(prop->req == RspOk &&
164b4d1cf41SDavid du Colombier prop->tag == tag &&
165b4d1cf41SDavid du Colombier (prop->taglen&TagResp)) {
1665d9de2d3SDavid du Colombier if((n = prop->taglen & ~TagResp) < rsplen)
1675d9de2d3SDavid du Colombier rsplen = n;
1685d9de2d3SDavid du Colombier memmove(buf, prop->data, rsplen);
1695d9de2d3SDavid du Colombier }else
1705d9de2d3SDavid du Colombier rsplen = -1;
1715d9de2d3SDavid du Colombier
1725d9de2d3SDavid du Colombier return rsplen;
1735d9de2d3SDavid du Colombier }
1745d9de2d3SDavid du Colombier
1755d9de2d3SDavid du Colombier /*
1765d9de2d3SDavid du Colombier * Framebuffer
1775d9de2d3SDavid du Colombier */
1785d9de2d3SDavid du Colombier
1795d9de2d3SDavid du Colombier static int
fbdefault(int * width,int * height,int * depth)1805d9de2d3SDavid du Colombier fbdefault(int *width, int *height, int *depth)
1815d9de2d3SDavid du Colombier {
1825d9de2d3SDavid du Colombier u32int buf[3];
183*5c47fe09SDavid du Colombier char *p;
1845d9de2d3SDavid du Colombier
1855d9de2d3SDavid du Colombier if(vcreq(TagGetres, &buf[0], 0, 2*4) != 2*4 ||
1865d9de2d3SDavid du Colombier vcreq(TagGetdepth, &buf[2], 0, 4) != 4)
1875d9de2d3SDavid du Colombier return -1;
1885d9de2d3SDavid du Colombier *width = buf[0];
1895d9de2d3SDavid du Colombier *height = buf[1];
190*5c47fe09SDavid du Colombier if((p = getconf("bcm2708_fb.fbdepth")) != nil)
191*5c47fe09SDavid du Colombier *depth = atoi(p);
192*5c47fe09SDavid du Colombier else
1935d9de2d3SDavid du Colombier *depth = buf[2];
1945d9de2d3SDavid du Colombier return 0;
1955d9de2d3SDavid du Colombier }
1965d9de2d3SDavid du Colombier
1975d9de2d3SDavid du Colombier void*
fbinit(int set,int * width,int * height,int * depth)1985d9de2d3SDavid du Colombier fbinit(int set, int *width, int *height, int *depth)
1995d9de2d3SDavid du Colombier {
2005d9de2d3SDavid du Colombier Fbinfo *fi;
2015d9de2d3SDavid du Colombier uintptr va;
2025d9de2d3SDavid du Colombier
2035d9de2d3SDavid du Colombier if(!set)
2045d9de2d3SDavid du Colombier fbdefault(width, height, depth);
2055d9de2d3SDavid du Colombier /* Screen width must be a multiple of 16 */
2065d9de2d3SDavid du Colombier *width &= ~0xF;
2075d9de2d3SDavid du Colombier fi = (Fbinfo*)(VCBUFFER);
2085d9de2d3SDavid du Colombier memset(fi, 0, sizeof(*fi));
2095d9de2d3SDavid du Colombier fi->xres = fi->xresvirtual = *width;
2105d9de2d3SDavid du Colombier fi->yres = fi->yresvirtual = *height;
2115d9de2d3SDavid du Colombier fi->bpp = *depth;
2125d9de2d3SDavid du Colombier cachedwbinvse(fi, sizeof(*fi));
213*5c47fe09SDavid du Colombier vcwrite(ChanFb, dmaaddr(fi));
2145d9de2d3SDavid du Colombier if(vcread(ChanFb) != 0)
2155d9de2d3SDavid du Colombier return 0;
216*5c47fe09SDavid du Colombier va = mmukmap(FRAMEBUFFER, fi->base & ~0xC0000000, fi->screensize);
2175d9de2d3SDavid du Colombier if(va)
2185d9de2d3SDavid du Colombier memset((char*)va, 0x7F, fi->screensize);
2195d9de2d3SDavid du Colombier return (void*)va;
2205d9de2d3SDavid du Colombier }
2215d9de2d3SDavid du Colombier
2225d9de2d3SDavid du Colombier int
fbblank(int blank)2235d9de2d3SDavid du Colombier fbblank(int blank)
2245d9de2d3SDavid du Colombier {
2255d9de2d3SDavid du Colombier u32int buf[1];
2265d9de2d3SDavid du Colombier
2275d9de2d3SDavid du Colombier buf[0] = blank;
2285d9de2d3SDavid du Colombier if(vcreq(TagFbblank, buf, sizeof buf, 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 * Power management
2355d9de2d3SDavid du Colombier */
2365d9de2d3SDavid du Colombier void
setpower(int dev,int on)2375d9de2d3SDavid du Colombier setpower(int dev, int on)
2385d9de2d3SDavid du Colombier {
2395d9de2d3SDavid du Colombier u32int buf[2];
2405d9de2d3SDavid du Colombier
2415d9de2d3SDavid du Colombier buf[0] = dev;
2425d9de2d3SDavid du Colombier buf[1] = Powerwait | (on? 1 : 0);
2435d9de2d3SDavid du Colombier vcreq(TagSetpower, buf, sizeof buf, sizeof buf);
2445d9de2d3SDavid du Colombier }
2455d9de2d3SDavid du Colombier
2465d9de2d3SDavid du Colombier int
getpower(int dev)2475d9de2d3SDavid du Colombier getpower(int dev)
2485d9de2d3SDavid du Colombier {
2495d9de2d3SDavid du Colombier u32int buf[2];
2505d9de2d3SDavid du Colombier
2515d9de2d3SDavid du Colombier buf[0] = dev;
2525d9de2d3SDavid du Colombier buf[1] = 0;
2535d9de2d3SDavid du Colombier if(vcreq(TagGetpower, buf, sizeof buf[0], sizeof buf) != sizeof buf)
2545d9de2d3SDavid du Colombier return -1;
2555d9de2d3SDavid du Colombier return buf[0] & 1;
2565d9de2d3SDavid du Colombier }
2575d9de2d3SDavid du Colombier
2585d9de2d3SDavid du Colombier /*
2595d9de2d3SDavid du Colombier * Get ethernet address (as hex string)
2605d9de2d3SDavid du Colombier * [not reentrant]
2615d9de2d3SDavid du Colombier */
2625d9de2d3SDavid du Colombier char *
getethermac(void)2635d9de2d3SDavid du Colombier getethermac(void)
2645d9de2d3SDavid du Colombier {
2655d9de2d3SDavid du Colombier uchar ea[8];
2665d9de2d3SDavid du Colombier char *p;
2675d9de2d3SDavid du Colombier int i;
2685d9de2d3SDavid du Colombier static char buf[16];
2695d9de2d3SDavid du Colombier
2705d9de2d3SDavid du Colombier memset(ea, 0, sizeof ea);
2715d9de2d3SDavid du Colombier vcreq(TagGetmac, ea, 0, sizeof ea);
2725d9de2d3SDavid du Colombier p = buf;
2735d9de2d3SDavid du Colombier for(i = 0; i < 6; i++)
2745d9de2d3SDavid du Colombier p += sprint(p, "%.2x", ea[i]);
2755d9de2d3SDavid du Colombier return buf;
2765d9de2d3SDavid du Colombier }
2775d9de2d3SDavid du Colombier
2785d9de2d3SDavid du Colombier /*
279*5c47fe09SDavid du Colombier * Get board revision
280*5c47fe09SDavid du Colombier */
281*5c47fe09SDavid du Colombier uint
getboardrev(void)282*5c47fe09SDavid du Colombier getboardrev(void)
283*5c47fe09SDavid du Colombier {
284*5c47fe09SDavid du Colombier u32int buf[1];
285*5c47fe09SDavid du Colombier
286*5c47fe09SDavid du Colombier if(vcreq(TagGetrev, buf, 0, sizeof buf) != sizeof buf)
287*5c47fe09SDavid du Colombier return 0;
288*5c47fe09SDavid du Colombier return buf[0];
289*5c47fe09SDavid du Colombier }
290*5c47fe09SDavid du Colombier
291*5c47fe09SDavid du Colombier /*
2925d9de2d3SDavid du Colombier * Get firmware revision
2935d9de2d3SDavid du Colombier */
2945d9de2d3SDavid du Colombier uint
getfirmware(void)2955d9de2d3SDavid du Colombier getfirmware(void)
2965d9de2d3SDavid du Colombier {
2975d9de2d3SDavid du Colombier u32int buf[1];
2985d9de2d3SDavid du Colombier
2995d9de2d3SDavid du Colombier if(vcreq(TagGetfwrev, buf, 0, sizeof buf) != sizeof buf)
3005d9de2d3SDavid du Colombier return 0;
3015d9de2d3SDavid du Colombier return buf[0];
3025d9de2d3SDavid du Colombier }
3035d9de2d3SDavid du Colombier
3045d9de2d3SDavid du Colombier /*
305*5c47fe09SDavid du Colombier * Get serial number
306*5c47fe09SDavid du Colombier */
307*5c47fe09SDavid du Colombier uvlong
getserial(void)308*5c47fe09SDavid du Colombier getserial(void)
309*5c47fe09SDavid du Colombier {
310*5c47fe09SDavid du Colombier uvlong buf;
311*5c47fe09SDavid du Colombier
312*5c47fe09SDavid du Colombier if(vcreq(TagGetser, &buf, 0, sizeof buf) != sizeof buf)
313*5c47fe09SDavid du Colombier return 0;
314*5c47fe09SDavid du Colombier return buf;
315*5c47fe09SDavid du Colombier }
316*5c47fe09SDavid du Colombier
317*5c47fe09SDavid du Colombier /*
3185d9de2d3SDavid du Colombier * Get ARM ram
3195d9de2d3SDavid du Colombier */
3205d9de2d3SDavid du Colombier void
getramsize(Confmem * mem)3215d9de2d3SDavid du Colombier getramsize(Confmem *mem)
3225d9de2d3SDavid du Colombier {
3235d9de2d3SDavid du Colombier u32int buf[2];
3245d9de2d3SDavid du Colombier
3255d9de2d3SDavid du Colombier if(vcreq(TagGetram, buf, 0, sizeof buf) != sizeof buf)
3265d9de2d3SDavid du Colombier return;
3275d9de2d3SDavid du Colombier mem->base = buf[0];
3285d9de2d3SDavid du Colombier mem->limit = buf[1];
3295d9de2d3SDavid du Colombier }
3305d9de2d3SDavid du Colombier
3315d9de2d3SDavid du Colombier /*
3325d9de2d3SDavid du Colombier * Get clock rate
3335d9de2d3SDavid du Colombier */
3345d9de2d3SDavid du Colombier ulong
getclkrate(int clkid)3355d9de2d3SDavid du Colombier getclkrate(int clkid)
3365d9de2d3SDavid du Colombier {
3375d9de2d3SDavid du Colombier u32int buf[2];
3385d9de2d3SDavid du Colombier
3395d9de2d3SDavid du Colombier buf[0] = clkid;
3405d9de2d3SDavid du Colombier if(vcreq(TagGetclkspd, buf, sizeof(buf[0]), sizeof(buf)) != sizeof buf)
3415d9de2d3SDavid du Colombier return 0;
3425d9de2d3SDavid du Colombier return buf[1];
3435d9de2d3SDavid du Colombier }
344*5c47fe09SDavid du Colombier
345*5c47fe09SDavid du Colombier /*
346*5c47fe09SDavid du Colombier * Set clock rate to hz (or max speed if hz == 0)
347*5c47fe09SDavid du Colombier */
348*5c47fe09SDavid du Colombier void
setclkrate(int clkid,ulong hz)349*5c47fe09SDavid du Colombier setclkrate(int clkid, ulong hz)
350*5c47fe09SDavid du Colombier {
351*5c47fe09SDavid du Colombier u32int buf[2];
352*5c47fe09SDavid du Colombier
353*5c47fe09SDavid du Colombier buf[0] = clkid;
354*5c47fe09SDavid du Colombier if(hz != 0)
355*5c47fe09SDavid du Colombier buf[1] = hz;
356*5c47fe09SDavid du Colombier else if(vcreq(TagGetclkmax, buf, sizeof(buf[0]), sizeof(buf)) != sizeof buf)
357*5c47fe09SDavid du Colombier return;
358*5c47fe09SDavid du Colombier vcreq(TagSetclkspd, buf, sizeof(buf), sizeof(buf));
359*5c47fe09SDavid du Colombier }
360*5c47fe09SDavid du Colombier
361*5c47fe09SDavid du Colombier /*
362*5c47fe09SDavid du Colombier * Get cpu temperature
363*5c47fe09SDavid du Colombier */
364*5c47fe09SDavid du Colombier uint
getcputemp(void)365*5c47fe09SDavid du Colombier getcputemp(void)
366*5c47fe09SDavid du Colombier {
367*5c47fe09SDavid du Colombier u32int buf[2];
368*5c47fe09SDavid du Colombier
369*5c47fe09SDavid du Colombier buf[0] = 0;
370*5c47fe09SDavid du Colombier if(vcreq(TagGettemp, buf, sizeof(buf[0]), sizeof buf) != sizeof buf)
371*5c47fe09SDavid du Colombier return 0;
372*5c47fe09SDavid du Colombier return buf[1];
373*5c47fe09SDavid du Colombier }
374*5c47fe09SDavid du Colombier
375*5c47fe09SDavid du Colombier /*
376*5c47fe09SDavid du Colombier * Notify gpu that xhci firmware might need loading. This is for some
377*5c47fe09SDavid du Colombier * pi4 board versions which are missing the eeprom chip for the vl805,
378*5c47fe09SDavid du Colombier * requiring its firmware to come from the boot eeprom instead.
379*5c47fe09SDavid du Colombier */
380*5c47fe09SDavid du Colombier int
xhcireset(int devaddr)381*5c47fe09SDavid du Colombier xhcireset(int devaddr)
382*5c47fe09SDavid du Colombier {
383*5c47fe09SDavid du Colombier u32int buf[1];
384*5c47fe09SDavid du Colombier
385*5c47fe09SDavid du Colombier buf[0] = devaddr;
386*5c47fe09SDavid du Colombier if(vcreq(TagXhciReset, buf, sizeof(buf), sizeof(buf[0])) == sizeof(buf[0]))
387*5c47fe09SDavid du Colombier return buf[0];
388*5c47fe09SDavid du Colombier return -1;
389*5c47fe09SDavid du Colombier }
390*5c47fe09SDavid du Colombier
391*5c47fe09SDavid du Colombier /*
392*5c47fe09SDavid du Colombier * Virtual GPIO - used for ACT LED on pi3
393*5c47fe09SDavid du Colombier */
394*5c47fe09SDavid du Colombier void
vgpinit(void)395*5c47fe09SDavid du Colombier vgpinit(void)
396*5c47fe09SDavid du Colombier {
397*5c47fe09SDavid du Colombier u32int buf[1];
398*5c47fe09SDavid du Colombier uintptr va;
399*5c47fe09SDavid du Colombier
400*5c47fe09SDavid du Colombier buf[0] = 0;
401*5c47fe09SDavid du Colombier if(vcreq(TagGetGpio, buf, 0, sizeof(buf)) != sizeof buf || buf[0] == 0)
402*5c47fe09SDavid du Colombier return;
403*5c47fe09SDavid du Colombier va = mmukmap(VGPIO, buf[0] & ~0xC0000000, BY2PG);
404*5c47fe09SDavid du Colombier if(va == 0)
405*5c47fe09SDavid du Colombier return;
406*5c47fe09SDavid du Colombier vgpio.counts = (u32int*)va;
407*5c47fe09SDavid du Colombier }
408*5c47fe09SDavid du Colombier
409*5c47fe09SDavid du Colombier void
vgpset(uint port,int on)410*5c47fe09SDavid du Colombier vgpset(uint port, int on)
411*5c47fe09SDavid du Colombier {
412*5c47fe09SDavid du Colombier if(vgpio.counts == nil || port >= Nvgpio || on == vgpio.ison)
413*5c47fe09SDavid du Colombier return;
414*5c47fe09SDavid du Colombier if(on)
415*5c47fe09SDavid du Colombier vgpio.incs++;
416*5c47fe09SDavid du Colombier else
417*5c47fe09SDavid du Colombier vgpio.decs++;
418*5c47fe09SDavid du Colombier vgpio.counts[port] = (vgpio.incs << 16) | vgpio.decs;
419*5c47fe09SDavid du Colombier vgpio.ison = on;
420*5c47fe09SDavid du Colombier }
421