xref: /plan9/sys/src/9/bcm/vcore.c (revision b4d1cf41cd5301e4c76aef9c04ddee28ac168a8e)
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