1 #include "u.h"
2 #include "../port/lib.h"
3 #include "mem.h"
4 #include "dat.h"
5 #include "fns.h"
6
7 /*
8 * Mailbox interface with videocore gpu
9 */
10
11 #define MAILBOX (VIRTIO+0xB880)
12
13 typedef struct Prophdr Prophdr;
14 typedef struct Fbinfo Fbinfo;
15
16 enum {
17 Read = 0x00>>2,
18 Write = 0x00>>2,
19 Peek = 0x10>>2,
20 Sender = 0x14>>2,
21 Status = 0x18>>2,
22 Full = 1<<31,
23 Empty = 1<<30,
24 Config = 0x1C>>2,
25 NRegs = 0x20>>2,
26
27 ChanMask = 0xF,
28 ChanProps = 8,
29 ChanFb = 1,
30
31 Req = 0x0,
32 RspOk = 0x80000000,
33 TagResp = 1<<31,
34
35 TagGetfwrev = 0x00000001,
36 TagGetmac = 0x00010003,
37 TagGetram = 0x00010005,
38 TagGetpower = 0x00020001,
39 TagSetpower = 0x00028001,
40 Powerwait = 1<<1,
41 TagGetclkspd= 0x00030002,
42 TagFballoc = 0x00040001,
43 TagFbfree = 0x00048001,
44 TagFbblank = 0x00040002,
45 TagGetres = 0x00040003,
46 TagSetres = 0x00048003,
47 TagGetvres = 0x00040004,
48 TagSetvres = 0x00048004,
49 TagGetdepth = 0x00040005,
50 TagSetdepth = 0x00048005,
51 TagGetrgb = 0x00044006,
52 TagSetrgb = 0x00048006,
53 };
54
55 struct Fbinfo {
56 u32int xres;
57 u32int yres;
58 u32int xresvirtual;
59 u32int yresvirtual;
60 u32int pitch; /* returned by gpu */
61 u32int bpp;
62 u32int xoffset;
63 u32int yoffset;
64 u32int base; /* returned by gpu */
65 u32int screensize; /* returned by gpu */
66 };
67
68
69 struct Prophdr {
70 u32int len;
71 u32int req;
72 u32int tag;
73 u32int tagbuflen;
74 u32int taglen;
75 u32int data[1];
76 };
77
78 static void
vcwrite(uint chan,int val)79 vcwrite(uint chan, int val)
80 {
81 u32int *r;
82
83 r = (u32int*)MAILBOX + NRegs;
84 val &= ~ChanMask;
85 while(r[Status]&Full)
86 ;
87 coherence();
88 r[Write] = val | chan;
89 }
90
91 static int
vcread(uint chan)92 vcread(uint chan)
93 {
94 u32int *r;
95 int x;
96
97 r = (u32int*)MAILBOX;
98 do{
99 while(r[Status]&Empty)
100 ;
101 coherence();
102 x = r[Read];
103 }while((x&ChanMask) != chan);
104 return x & ~ChanMask;
105 }
106
107 /*
108 * Property interface
109 */
110
111 static int
vcreq(int tag,void * buf,int vallen,int rsplen)112 vcreq(int tag, void *buf, int vallen, int rsplen)
113 {
114 uintptr r;
115 int n;
116 Prophdr *prop;
117 static uintptr base = BUSDRAM;
118
119 if(rsplen < vallen)
120 rsplen = vallen;
121 rsplen = (rsplen+3) & ~3;
122 prop = (Prophdr*)(VCBUFFER);
123 n = sizeof(Prophdr) + rsplen + 8;
124 memset(prop, 0, n);
125 prop->len = n;
126 prop->req = Req;
127 prop->tag = tag;
128 prop->tagbuflen = rsplen;
129 prop->taglen = vallen;
130 if(vallen > 0)
131 memmove(prop->data, buf, vallen);
132 cachedwbinvse(prop, prop->len);
133 for(;;){
134 vcwrite(ChanProps, PADDR(prop) + base);
135 r = vcread(ChanProps);
136 if(r == PADDR(prop) + base)
137 break;
138 if(base == 0)
139 return -1;
140 base = 0;
141 }
142 if(prop->req == RspOk &&
143 prop->tag == tag &&
144 (prop->taglen&TagResp)) {
145 if((n = prop->taglen & ~TagResp) < rsplen)
146 rsplen = n;
147 memmove(buf, prop->data, rsplen);
148 }else
149 rsplen = -1;
150
151 return rsplen;
152 }
153
154 /*
155 * Framebuffer
156 */
157
158 static int
fbdefault(int * width,int * height,int * depth)159 fbdefault(int *width, int *height, int *depth)
160 {
161 u32int buf[3];
162
163 if(vcreq(TagGetres, &buf[0], 0, 2*4) != 2*4 ||
164 vcreq(TagGetdepth, &buf[2], 0, 4) != 4)
165 return -1;
166 *width = buf[0];
167 *height = buf[1];
168 *depth = buf[2];
169 return 0;
170 }
171
172 void*
fbinit(int set,int * width,int * height,int * depth)173 fbinit(int set, int *width, int *height, int *depth)
174 {
175 Fbinfo *fi;
176 uintptr va;
177
178 if(!set)
179 fbdefault(width, height, depth);
180 /* Screen width must be a multiple of 16 */
181 *width &= ~0xF;
182 fi = (Fbinfo*)(VCBUFFER);
183 memset(fi, 0, sizeof(*fi));
184 fi->xres = fi->xresvirtual = *width;
185 fi->yres = fi->yresvirtual = *height;
186 fi->bpp = *depth;
187 cachedwbinvse(fi, sizeof(*fi));
188 vcwrite(ChanFb, DMAADDR(fi));
189 if(vcread(ChanFb) != 0)
190 return 0;
191 va = mmukmap(FRAMEBUFFER, PADDR(fi->base), fi->screensize);
192 if(va)
193 memset((char*)va, 0x7F, fi->screensize);
194 return (void*)va;
195 }
196
197 int
fbblank(int blank)198 fbblank(int blank)
199 {
200 u32int buf[1];
201
202 buf[0] = blank;
203 if(vcreq(TagFbblank, buf, sizeof buf, sizeof buf) != sizeof buf)
204 return -1;
205 return buf[0] & 1;
206 }
207
208 /*
209 * Power management
210 */
211 void
setpower(int dev,int on)212 setpower(int dev, int on)
213 {
214 u32int buf[2];
215
216 buf[0] = dev;
217 buf[1] = Powerwait | (on? 1 : 0);
218 vcreq(TagSetpower, buf, sizeof buf, sizeof buf);
219 }
220
221 int
getpower(int dev)222 getpower(int dev)
223 {
224 u32int buf[2];
225
226 buf[0] = dev;
227 buf[1] = 0;
228 if(vcreq(TagGetpower, buf, sizeof buf[0], sizeof buf) != sizeof buf)
229 return -1;
230 return buf[0] & 1;
231 }
232
233 /*
234 * Get ethernet address (as hex string)
235 * [not reentrant]
236 */
237 char *
getethermac(void)238 getethermac(void)
239 {
240 uchar ea[8];
241 char *p;
242 int i;
243 static char buf[16];
244
245 memset(ea, 0, sizeof ea);
246 vcreq(TagGetmac, ea, 0, sizeof ea);
247 p = buf;
248 for(i = 0; i < 6; i++)
249 p += sprint(p, "%.2x", ea[i]);
250 return buf;
251 }
252
253 /*
254 * Get firmware revision
255 */
256 uint
getfirmware(void)257 getfirmware(void)
258 {
259 u32int buf[1];
260
261 if(vcreq(TagGetfwrev, buf, 0, sizeof buf) != sizeof buf)
262 return 0;
263 return buf[0];
264 }
265
266 /*
267 * Get ARM ram
268 */
269 void
getramsize(Confmem * mem)270 getramsize(Confmem *mem)
271 {
272 u32int buf[2];
273
274 if(vcreq(TagGetram, buf, 0, sizeof buf) != sizeof buf)
275 return;
276 mem->base = buf[0];
277 mem->limit = buf[1];
278 }
279
280 /*
281 * Get clock rate
282 */
283 ulong
getclkrate(int clkid)284 getclkrate(int clkid)
285 {
286 u32int buf[2];
287
288 buf[0] = clkid;
289 if(vcreq(TagGetclkspd, buf, sizeof(buf[0]), sizeof(buf)) != sizeof buf)
290 return 0;
291 return buf[1];
292 }
293