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