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