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