xref: /plan9/sys/src/9/bcm/uartmini.c (revision b4d1cf41cd5301e4c76aef9c04ddee28ac168a8e)
1 /*
2  * bcm2835 mini uart (UART1)
3  */
4 
5 #include "u.h"
6 #include "../port/lib.h"
7 #include "../port/error.h"
8 #include "mem.h"
9 #include "dat.h"
10 #include "fns.h"
11 #include "io.h"
12 
13 #define GPIOREGS	(VIRTIO+0x200000)
14 #define AUXREGS		(VIRTIO+0x215000)
15 #define	OkLed		16
16 #define	TxPin		14
17 #define	RxPin		15
18 
19 /* GPIO regs */
20 enum {
21 	Fsel0	= 0x00>>2,
22 		FuncMask= 0x7,
23 		Input	= 0x0,
24 		Output	= 0x1,
25 		Alt0	= 0x4,
26 		Alt1	= 0x5,
27 		Alt2	= 0x6,
28 		Alt3	= 0x7,
29 		Alt4	= 0x3,
30 		Alt5	= 0x2,
31 	Set0	= 0x1c>>2,
32 	Clr0	= 0x28>>2,
33 	Lev0	= 0x34>>2,
34 	PUD	= 0x94>>2,
35 		Off	= 0x0,
36 		Pulldown= 0x1,
37 		Pullup	= 0x2,
38 	PUDclk0	= 0x98>>2,
39 	PUDclk1	= 0x9c>>2,
40 };
41 
42 /* AUX regs */
43 enum {
44 	Irq	= 0x00>>2,
45 		UartIrq	= 1<<0,
46 	Enables	= 0x04>>2,
47 		UartEn	= 1<<0,
48 	MuIo	= 0x40>>2,
49 	MuIer	= 0x44>>2,
50 		RxIen	= 1<<0,
51 		TxIen	= 1<<1,
52 	MuIir	= 0x48>>2,
53 	MuLcr	= 0x4c>>2,
54 		Bitsmask= 3<<0,
55 		Bits7	= 2<<0,
56 		Bits8	= 3<<0,
57 	MuMcr	= 0x50>>2,
58 		RtsN	= 1<<1,
59 	MuLsr	= 0x54>>2,
60 		TxDone	= 1<<6,
61 		TxRdy	= 1<<5,
62 		RxRdy	= 1<<0,
63 	MuCntl	= 0x60>>2,
64 		CtsFlow	= 1<<3,
65 		TxEn	= 1<<1,
66 		RxEn	= 1<<0,
67 	MuBaud	= 0x68>>2,
68 };
69 
70 extern PhysUart miniphysuart;
71 
72 static Uart miniuart = {
73 	.regs	= (u32int*)AUXREGS,
74 	.name	= "uart0",
75 	.freq	= 250000000,
76 	.phys	= &miniphysuart,
77 };
78 
79 void
gpiosel(uint pin,int func)80 gpiosel(uint pin, int func)
81 {
82 	u32int *gp, *fsel;
83 	int off;
84 
85 	gp = (u32int*)GPIOREGS;
86 	fsel = &gp[Fsel0 + pin/10];
87 	off = (pin % 10) * 3;
88 	*fsel = (*fsel & ~(FuncMask<<off)) | func<<off;
89 }
90 
91 void
gpiopulloff(uint pin)92 gpiopulloff(uint pin)
93 {
94 	u32int *gp, *reg;
95 	u32int mask;
96 
97 	gp = (u32int*)GPIOREGS;
98 	reg = &gp[PUDclk0 + pin/32];
99 	mask = 1 << (pin % 32);
100 	gp[PUD] = Off;
101 	microdelay(1);
102 	*reg = mask;
103 	microdelay(1);
104 	*reg = 0;
105 }
106 
107 void
gpioout(uint pin,int set)108 gpioout(uint pin, int set)
109 {
110 	u32int *gp;
111 	int v;
112 
113 	gp = (u32int*)GPIOREGS;
114 	v = set? Set0 : Clr0;
115 	gp[v + pin/32] = 1 << (pin % 32);
116 }
117 
118 int
gpioin(uint pin)119 gpioin(uint pin)
120 {
121 	u32int *gp;
122 
123 	gp = (u32int*)GPIOREGS;
124 	return (gp[Lev0 + pin/32] & (1 << (pin % 32))) != 0;
125 }
126 
127 static void
interrupt(Ureg *,void * arg)128 interrupt(Ureg*, void *arg)
129 {
130 	Uart *uart;
131 	u32int *ap;
132 
133 	uart = arg;
134 	ap = (u32int*)uart->regs;
135 
136 	coherence();
137 	if(0 && (ap[Irq] & UartIrq) == 0)
138 		return;
139 	if(ap[MuLsr] & TxRdy)
140 		uartkick(uart);
141 	if(ap[MuLsr] & RxRdy){
142 		if(uart->console){
143 			if(uart->opens == 1)
144 				uart->putc = kbdcr2nl;
145 			else
146 				uart->putc = nil;
147 		}
148 		do{
149 			uartrecv(uart, ap[MuIo] & 0xFF);
150 		}while(ap[MuLsr] & RxRdy);
151 	}
152 	coherence();
153 }
154 
155 static Uart*
pnp(void)156 pnp(void)
157 {
158 	Uart *uart;
159 
160 	uart = &miniuart;
161 	if(uart->console == 0)
162 		kbdq = qopen(8*1024, 0, nil, nil);
163 	return uart;
164 }
165 
166 static void
enable(Uart * uart,int ie)167 enable(Uart *uart, int ie)
168 {
169 	u32int *ap;
170 
171 	ap = (u32int*)uart->regs;
172 	delay(10);
173 	gpiosel(TxPin, Alt5);
174 	gpiosel(RxPin, Alt5);
175 	gpiopulloff(TxPin);
176 	gpiopulloff(RxPin);
177 	ap[Enables] |= UartEn;
178 	ap[MuIir] = 6;
179 	ap[MuLcr] = Bits8;
180 	ap[MuCntl] = TxEn|RxEn;
181 	ap[MuBaud] = 250000000/(115200*8) - 1;
182 	if(ie){
183 		intrenable(IRQaux, interrupt, uart, 0, "uart");
184 		ap[MuIer] = RxIen|TxIen;
185 	}else
186 		ap[MuIer] = 0;
187 }
188 
189 static void
disable(Uart * uart)190 disable(Uart *uart)
191 {
192 	u32int *ap;
193 
194 	ap = (u32int*)uart->regs;
195 	ap[MuCntl] = 0;
196 	ap[MuIer] = 0;
197 }
198 
199 static void
kick(Uart * uart)200 kick(Uart *uart)
201 {
202 	u32int *ap;
203 
204 	ap = (u32int*)uart->regs;
205 	if(uart->blocked)
206 		return;
207 	coherence();
208 	while(ap[MuLsr] & TxRdy){
209 		if(uart->op >= uart->oe && uartstageoutput(uart) == 0)
210 			break;
211 		ap[MuIo] = *(uart->op++);
212 	}
213 	if(ap[MuLsr] & TxDone)
214 		ap[MuIer] &= ~TxIen;
215 	else
216 		ap[MuIer] |= TxIen;
217 	coherence();
218 }
219 
220 /* TODO */
221 static void
dobreak(Uart * uart,int ms)222 dobreak(Uart *uart, int ms)
223 {
224 	USED(uart, ms);
225 }
226 
227 static int
baud(Uart * uart,int n)228 baud(Uart *uart, int n)
229 {
230 	u32int *ap;
231 
232 	ap = (u32int*)uart->regs;
233 	if(uart->freq == 0 || n <= 0)
234 		return -1;
235 	ap[MuBaud] = (uart->freq + 4*n - 1) / (8 * n) - 1;
236 	uart->baud = n;
237 	return 0;
238 }
239 
240 static int
bits(Uart * uart,int n)241 bits(Uart *uart, int n)
242 {
243 	u32int *ap;
244 	int set;
245 
246 	ap = (u32int*)uart->regs;
247 	switch(n){
248 	case 7:
249 		set = Bits7;
250 		break;
251 	case 8:
252 		set = Bits8;
253 		break;
254 	default:
255 		return -1;
256 	}
257 	ap[MuLcr] = (ap[MuLcr] & ~Bitsmask) | set;
258 	uart->bits = n;
259 	return 0;
260 }
261 
262 static int
stop(Uart * uart,int n)263 stop(Uart *uart, int n)
264 {
265 	if(n != 1)
266 		return -1;
267 	uart->stop = n;
268 	return 0;
269 }
270 
271 static int
parity(Uart * uart,int n)272 parity(Uart *uart, int n)
273 {
274 	if(n != 'n')
275 		return -1;
276 	uart->parity = n;
277 	return 0;
278 }
279 
280 /*
281  * cts/rts flow control
282  *   need to bring signals to gpio pins before enabling this
283  */
284 
285 static void
modemctl(Uart * uart,int on)286 modemctl(Uart *uart, int on)
287 {
288 	u32int *ap;
289 
290 	ap = (u32int*)uart->regs;
291 	if(on)
292 		ap[MuCntl] |= CtsFlow;
293 	else
294 		ap[MuCntl] &= ~CtsFlow;
295 	uart->modem = on;
296 }
297 
298 static void
rts(Uart * uart,int on)299 rts(Uart *uart, int on)
300 {
301 	u32int *ap;
302 
303 	ap = (u32int*)uart->regs;
304 	if(on)
305 		ap[MuMcr] &= ~RtsN;
306 	else
307 		ap[MuMcr] |= RtsN;
308 }
309 
310 static long
status(Uart * uart,void * buf,long n,long offset)311 status(Uart *uart, void *buf, long n, long offset)
312 {
313 	char *p;
314 
315 	p = malloc(READSTR);
316 	if(p == nil)
317 		error(Enomem);
318 	snprint(p, READSTR,
319 		"b%d\n"
320 		"dev(%d) type(%d) framing(%d) overruns(%d) "
321 		"berr(%d) serr(%d)\n",
322 
323 		uart->baud,
324 		uart->dev,
325 		uart->type,
326 		uart->ferr,
327 		uart->oerr,
328 		uart->berr,
329 		uart->serr
330 	);
331 	n = readstr(offset, buf, n, p);
332 	free(p);
333 
334 	return n;
335 }
336 
337 static void
donothing(Uart *,int)338 donothing(Uart*, int)
339 {
340 }
341 
342 void
putc(Uart *,int c)343 putc(Uart*, int c)
344 {
345 	u32int *ap;
346 
347 	ap = (u32int*)AUXREGS;
348 	while((ap[MuLsr] & TxRdy) == 0)
349 		;
350 	ap[MuIo] = c;
351 	while((ap[MuLsr] & TxRdy) == 0)
352 		;
353 }
354 
355 int
getc(Uart *)356 getc(Uart*)
357 {
358 	u32int *ap;
359 
360 	ap = (u32int*)AUXREGS;
361 	while((ap[MuLsr] & RxRdy) == 0)
362 		;
363 	return ap[MuIo] & 0xFF;
364 }
365 
366 void
uartconsinit(void)367 uartconsinit(void)
368 {
369 	Uart *uart;
370 	int n;
371 	char *p, *cmd;
372 
373 	if((p = getconf("console")) == nil)
374 		return;
375 	n = strtoul(p, &cmd, 0);
376 	if(p == cmd)
377 		return;
378 	switch(n){
379 	default:
380 		return;
381 	case 0:
382 		uart = &miniuart;
383 		break;
384 	}
385 
386 	if(!uart->enabled)
387 		(*uart->phys->enable)(uart, 0);
388 	uartctl(uart, "b9600 l8 pn s1");
389 	if(*cmd != '\0')
390 		uartctl(uart, cmd);
391 
392 	consuart = uart;
393 	uart->console = 1;
394 }
395 
396 PhysUart miniphysuart = {
397 	.name		= "miniuart",
398 	.pnp		= pnp,
399 	.enable		= enable,
400 	.disable	= disable,
401 	.kick		= kick,
402 	.dobreak	= dobreak,
403 	.baud		= baud,
404 	.bits		= bits,
405 	.stop		= stop,
406 	.parity		= parity,
407 	.modemctl	= donothing,
408 	.rts		= rts,
409 	.dtr		= donothing,
410 	.status		= status,
411 	.fifo		= donothing,
412 	.getc		= getc,
413 	.putc		= putc,
414 };
415 
416 void
okay(int on)417 okay(int on)
418 {
419 	static int first;
420 
421 	if(!first++)
422 		gpiosel(OkLed, Output);
423 	gpioout(OkLed, !on);
424 }
425