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