]> git.lizzy.rs Git - plan9front.git/blob - sys/src/9/bcm/vcore.c
pc, pc64: make sure write combining is supported in MTRR's before setting it
[plan9front.git] / sys / src / 9 / bcm / vcore.c
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 typedef struct Vgpio Vgpio;
16
17 enum {
18         Read            = 0x00>>2,
19         Write           = 0x00>>2,
20         Peek            = 0x10>>2,
21         Sender          = 0x14>>2,
22         Status          = 0x18>>2,
23                 Full            = 1<<31,
24                 Empty           = 1<<30,
25         Config          = 0x1C>>2,
26         NRegs           = 0x20>>2,
27
28         ChanMask        = 0xF,
29         ChanProps       = 8,
30         ChanFb          = 1,
31
32         Req                     = 0x0,
33         RspOk           = 0x80000000,
34         TagResp         = 1<<31,
35
36         TagGetfwrev     = 0x00000001,
37         TagGetrev       = 0x00010002,
38         TagGetmac       = 0x00010003,
39         TagGetram       = 0x00010005,
40         TagGetpower     = 0x00020001,
41         TagSetpower     = 0x00028001,
42                 Powerwait       = 1<<1,
43         TagGetclkstate  = 0x00030001,
44         TagGetclkspd    = 0x00030002,
45         TagGetclkmax    = 0x00030004,
46         TagSetclkstate  = 0x00038001,
47         TagSetclkspd    = 0x00038002,
48
49         TagGetEgpioState= 0x00030041,
50         TagSetEgpioState= 0x00038041,
51         TagSetSdhostClk = 0x00038042,
52         TagGetEgpioConf = 0x00030043,
53         TagSetEgpioConf = 0x00038043,
54
55         TagGettemp      = 0x00030006,
56         TagXhciReset    = 0x00030058,
57         TagFballoc      = 0x00040001,
58         TagFbfree       = 0x00048001,
59         TagFbblank      = 0x00040002,
60         TagGetres       = 0x00040003,
61         TagSetres       = 0x00048003,
62         TagGetvres      = 0x00040004,
63         TagSetvres      = 0x00048004,
64         TagGetdepth     = 0x00040005,
65         TagSetdepth     = 0x00048005,
66         TagGetrgb       = 0x00040006,
67         TagSetrgb       = 0x00048006,
68         TagGetGpio      = 0x00040010,
69
70         Nvgpio          = 2,
71 };
72
73 struct Fbinfo {
74         u32int  xres;
75         u32int  yres;
76         u32int  xresvirtual;
77         u32int  yresvirtual;
78         u32int  pitch;                  /* returned by gpu */
79         u32int  bpp;
80         u32int  xoffset;
81         u32int  yoffset;
82         u32int  base;                   /* returned by gpu */
83         u32int  screensize;             /* returned by gpu */
84 };
85
86
87 struct Prophdr {
88         u32int  len;
89         u32int  req;
90         u32int  tag;
91         u32int  tagbuflen;
92         u32int  taglen;
93         u32int  data[1];
94 };
95
96 struct Vgpio {
97         u32int  *counts;
98         u16int  incs;
99         u16int  decs;
100         int     ison;
101 };
102
103 static Vgpio vgpio;
104
105 static void
106 vcwrite(uint chan, int val)
107 {
108         u32int *r;
109
110         r = (u32int*)MAILBOX + NRegs;
111         val &= ~ChanMask;
112         while(r[Status]&Full)
113                 ;
114         coherence();
115         r[Write] = val | chan;
116 }
117
118 static int
119 vcread(uint chan)
120 {
121         u32int *r;
122         int x;
123
124         r = (u32int*)MAILBOX;
125         do{
126                 while(r[Status]&Empty)
127                         ;
128                 coherence();
129                 x = r[Read];
130         }while((x&ChanMask) != chan);
131         return x & ~ChanMask;
132 }
133
134 /*
135  * Property interface
136  */
137
138 static int
139 vcreq(int tag, void *buf, int vallen, int rsplen)
140 {
141         uintptr r;
142         int n;
143         Prophdr *prop;
144         uintptr aprop;
145         static int busaddr = 1;
146
147         if(rsplen < vallen)
148                 rsplen = vallen;
149         rsplen = (rsplen+3) & ~3;
150         prop = (Prophdr*)(VCBUFFER);
151         n = sizeof(Prophdr) + rsplen + 8;
152         memset(prop, 0, n);
153         prop->len = n;
154         prop->req = Req;
155         prop->tag = tag;
156         prop->tagbuflen = rsplen;
157         prop->taglen = vallen;
158         if(vallen > 0)
159                 memmove(prop->data, buf, vallen);
160         cachedwbinvse(prop, n);
161         for(;;){
162                 aprop = busaddr? dmaaddr(prop) : (uintptr)prop;
163                 vcwrite(ChanProps, aprop);
164                 r = vcread(ChanProps);
165                 if(r == aprop)
166                         break;
167                 if(!busaddr)
168                         return -1;
169                 busaddr = 0;
170         }
171         cachedinvse(prop, n);
172         if(prop->req == RspOk &&
173            prop->tag == tag &&
174            (prop->taglen&TagResp)) {
175                 if((n = prop->taglen & ~TagResp) < rsplen)
176                         rsplen = n;
177                 memmove(buf, prop->data, rsplen);
178         }else
179                 rsplen = -1;
180
181         return rsplen;
182 }
183
184 /*
185  * Framebuffer
186  */
187
188 static int
189 fbdefault(int *width, int *height, int *depth)
190 {
191         u32int buf[3];
192         char *p;
193
194         if(vcreq(TagGetres, &buf[0], 0, 2*4) != 2*4 ||
195            vcreq(TagGetdepth, &buf[2], 0, 4) != 4)
196                 return -1;
197         *width = buf[0];
198         *height = buf[1];
199         if((p = getconf("bcm2708_fb.fbdepth")) != nil)
200                 *depth = atoi(p);
201         else
202                 *depth = buf[2];
203         return 0;
204 }
205
206 void*
207 fbinit(int set, int *width, int *height, int *depth)
208 {
209         Fbinfo *fi;
210         uintptr va;
211
212         if(!set)
213                 fbdefault(width, height, depth);
214         /* Screen width must be a multiple of 16 */
215         *width &= ~0xF;
216         fi = (Fbinfo*)(VCBUFFER);
217         memset(fi, 0, sizeof(*fi));
218         fi->xres = fi->xresvirtual = *width;
219         fi->yres = fi->yresvirtual = *height;
220         fi->bpp = *depth;
221         cachedwbinvse(fi, sizeof(*fi));
222         vcwrite(ChanFb, dmaaddr(fi));
223         if(vcread(ChanFb) != 0)
224                 return nil;
225         cachedinvse(fi, sizeof(*fi));
226         va = mmukmap(FRAMEBUFFER, (fi->base&~0xC0000000)|PHYSDRAM, fi->screensize);
227         if(va)
228                 memset((char*)va, 0x7F, fi->screensize);
229         return (void*)va;
230 }
231
232 int
233 fbblank(int blank)
234 {
235         u32int buf[1];
236
237         buf[0] = blank;
238         if(vcreq(TagFbblank, buf, sizeof buf, sizeof buf) != sizeof buf)
239                 return -1;
240         return buf[0] & 1;
241 }
242
243 /*
244  * Power management
245  */
246 void
247 setpower(int dev, int on)
248 {
249         u32int buf[2];
250
251         buf[0] = dev;
252         buf[1] = Powerwait | (on? 1 : 0);
253         vcreq(TagSetpower, buf, sizeof buf, sizeof buf);
254 }
255
256 int
257 getpower(int dev)
258 {
259         u32int buf[2];
260
261         buf[0] = dev;
262         buf[1] = 0;
263         if(vcreq(TagGetpower, buf, sizeof buf[0], sizeof buf) != sizeof buf)
264                 return -1;
265         return buf[0] & 1;
266 }
267
268 /*
269  * Get ethernet address (as hex string)
270  *       [not reentrant]
271  */
272 char *
273 getethermac(void)
274 {
275         uchar ea[8];
276         char *p;
277         int i;
278         static char buf[16];
279
280         memset(ea, 0, sizeof ea);
281         vcreq(TagGetmac, ea, 0, sizeof ea);
282         p = buf;
283         for(i = 0; i < 6; i++)
284                 p += sprint(p, "%.2x", ea[i]);
285         return buf;
286 }
287
288 /*
289  * Get board revision
290  */
291 uint
292 getboardrev(void)
293 {
294         u32int buf[1];
295
296         if(vcreq(TagGetrev, buf, 0, sizeof buf) != sizeof buf)
297                 return 0;
298         return buf[0];
299 }
300
301 /*
302  * Get firmware revision
303  */
304 uint
305 getfirmware(void)
306 {
307         u32int buf[1];
308
309         if(vcreq(TagGetfwrev, buf, 0, sizeof buf) != sizeof buf)
310                 return 0;
311         return buf[0];
312 }
313
314 /*
315  * Get ARM ram
316  */
317 void
318 getramsize(Confmem *mem)
319 {
320         u32int buf[2];
321
322         if(vcreq(TagGetram, buf, 0, sizeof buf) != sizeof buf)
323                 return;
324         mem->base = buf[0];
325         mem->limit = buf[1];
326 }
327
328 /*
329  * Get clock rate
330  */
331 ulong
332 getclkrate(int clkid)
333 {
334         u32int buf[2];
335
336         buf[0] = clkid;
337         if(vcreq(TagGetclkspd, buf, sizeof(buf[0]), sizeof(buf)) != sizeof buf)
338                 return 0;
339         return buf[1];
340 }
341
342 /*
343  * Set clock rate to hz (or max speed if hz == 0)
344  */
345 void
346 setclkrate(int clkid, ulong hz)
347 {
348         u32int buf[2];
349
350         buf[0] = clkid;
351         if(hz != 0)
352                 buf[1] = hz;
353         else if(vcreq(TagGetclkmax, buf, sizeof(buf[0]), sizeof(buf)) != sizeof buf)
354                 return;
355         vcreq(TagSetclkspd, buf, sizeof(buf), sizeof(buf));
356 }
357
358 /*
359  * Get cpu temperature
360  */
361 uint
362 getcputemp(void)
363 {
364         u32int buf[2];
365
366         buf[0] = 0;
367         if(vcreq(TagGettemp, buf, sizeof(buf[0]), sizeof buf) != sizeof buf)
368                 return 0;
369         return buf[1];
370 }
371
372 /*
373  * Virtual GPIO - used for ACT LED on pi3
374  */
375 void
376 vgpinit(void)
377 {
378         u32int buf[1];
379         uintptr va;
380
381         buf[0] = 0;
382         if(vcreq(TagGetGpio, buf, 0, sizeof(buf)) != sizeof buf || buf[0] == 0)
383                 return;
384         va = mmukmap(VGPIO, buf[0] & ~0xC0000000, BY2PG);
385         if(va == 0)
386                 return;
387         vgpio.counts = (u32int*)va;
388 }
389
390 void
391 vgpset(uint port, int on)
392 {
393         if(vgpio.counts == nil || port >= Nvgpio || on == vgpio.ison)
394                 return;
395         if(on)
396                 vgpio.incs++;
397         else
398                 vgpio.decs++;
399         vgpio.counts[port] = (vgpio.incs << 16) | vgpio.decs;
400         vgpio.ison = on;
401 }
402
403 /*
404  * Raspberry Pi GPIO expander (Pi 3 and 4)
405  */
406 void
407 egpset(uint port, int on)
408 {
409         u32int buf[2];
410
411         if(port >= 8)
412                 return;
413         buf[0] = 128 + port;
414         buf[1] = on;
415         vcreq(TagSetEgpioState, buf, sizeof(buf), sizeof(buf));
416 }
417
418 /*
419  * Notify gpu that xhci firmware might need loading. This is for some
420  * pi4 board versions which are missing the eeprom chip for the vl805,
421  * requiring its firmware to come from the boot eeprom instead.
422  */
423 int
424 xhcireset(int devaddr)
425 {
426         u32int buf[1];
427
428         buf[0] = devaddr;
429         if(vcreq(TagXhciReset, buf, sizeof(buf), sizeof(buf[0])) == sizeof(buf[0]))
430                 return buf[0];
431         return -1;
432 }