]> git.lizzy.rs Git - plan9front.git/blob - sys/src/9/bcm/uartmini.c
pc kernel: fix wrong simd exception mask (fixes go bootstrap)
[plan9front.git] / sys / src / 9 / bcm / uartmini.c
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
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
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
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
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
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                 do{
143                         uartrecv(uart, ap[MuIo] & 0xFF);
144                 }while(ap[MuLsr] & RxRdy);
145         }
146         coherence();
147 }
148
149 static Uart*
150 pnp(void)
151 {
152         return &miniuart;
153 }
154
155 static void
156 enable(Uart *uart, int ie)
157 {
158         u32int *ap;
159
160         ap = (u32int*)uart->regs;
161         delay(10);
162         gpiosel(TxPin, Alt5);
163         gpiosel(RxPin, Alt5);
164         gpiopulloff(TxPin);
165         gpiopulloff(RxPin);
166         ap[Enables] |= UartEn;
167         ap[MuIir] = 6;
168         ap[MuCntl] = TxEn|RxEn;
169         if(ie){
170                 intrenable(IRQaux, interrupt, uart, 0, "uart");
171                 ap[MuIer] = RxIen|TxIen;
172         }else
173                 ap[MuIer] = 0;
174 }
175
176 static void
177 disable(Uart *uart)
178 {
179         u32int *ap;
180
181         ap = (u32int*)uart->regs;
182         ap[MuCntl] = 0;
183         ap[MuIer] = 0;
184 }
185
186 static void
187 kick(Uart *uart)
188 {
189         u32int *ap;
190
191         ap = (u32int*)uart->regs;
192         if(uart->blocked)
193                 return;
194         coherence();
195         while(ap[MuLsr] & TxRdy){
196                 if(uart->op >= uart->oe && uartstageoutput(uart) == 0)
197                         break;
198                 ap[MuIo] = *(uart->op++);
199         }
200         if(ap[MuLsr] & TxDone)
201                 ap[MuIer] &= ~TxIen;
202         else
203                 ap[MuIer] |= TxIen;
204         coherence();
205 }
206
207 /* TODO */
208 static void
209 dobreak(Uart *uart, int ms)
210 {
211         USED(uart, ms);
212 }
213
214 static int
215 baud(Uart *uart, int n)
216 {
217         u32int *ap;
218
219         ap = (u32int*)uart->regs;
220         if(uart->freq == 0 || n <= 0)
221                 return -1;
222         ap[MuBaud] = (uart->freq + 4*n - 1) / (8 * n) - 1;
223         uart->baud = n;
224         return 0;
225 }
226
227 static int
228 bits(Uart *uart, int n)
229 {
230         u32int *ap;
231         int set;
232
233         ap = (u32int*)uart->regs;
234         switch(n){
235         case 7:
236                 set = Bits7;
237                 break;
238         case 8:
239                 set = Bits8;
240                 break;
241         default:
242                 return -1;
243         }
244         ap[MuLcr] = (ap[MuLcr] & ~Bitsmask) | set;
245         uart->bits = n;
246         return 0;
247 }
248
249 static int
250 stop(Uart *uart, int n)
251 {
252         if(n != 1)
253                 return -1;
254         uart->stop = n;
255         return 0;
256 }
257
258 static int
259 parity(Uart *uart, int n)
260 {
261         if(n != 'n')
262                 return -1;
263         uart->parity = n;
264         return 0;
265 }
266
267 /*
268  * cts/rts flow control
269  *   need to bring signals to gpio pins before enabling this
270  */
271
272 static void
273 modemctl(Uart *uart, int on)
274 {
275         u32int *ap;
276
277         ap = (u32int*)uart->regs;
278         if(on)
279                 ap[MuCntl] |= CtsFlow;
280         else
281                 ap[MuCntl] &= ~CtsFlow;
282         uart->modem = on;
283 }
284
285 static void
286 rts(Uart *uart, int on)
287 {
288         u32int *ap;
289
290         ap = (u32int*)uart->regs;
291         if(on)
292                 ap[MuMcr] &= ~RtsN;
293         else
294                 ap[MuMcr] |= RtsN;
295 }
296
297 static long
298 status(Uart *uart, void *buf, long n, long offset)
299 {
300         char *p;
301
302         p = malloc(READSTR);
303         if(p == nil)
304                 error(Enomem);
305         snprint(p, READSTR,
306                 "b%d\n"
307                 "dev(%d) type(%d) framing(%d) overruns(%d) "
308                 "berr(%d) serr(%d)\n",
309
310                 uart->baud,
311                 uart->dev,
312                 uart->type,
313                 uart->ferr,
314                 uart->oerr,
315                 uart->berr,
316                 uart->serr
317         );
318         n = readstr(offset, buf, n, p);
319         free(p);
320
321         return n;
322 }
323
324 static void
325 donothing(Uart*, int)
326 {
327 }
328
329 void
330 putc(Uart*, int c)
331 {
332         u32int *ap;
333
334         ap = (u32int*)AUXREGS;
335         while((ap[MuLsr] & TxRdy) == 0)
336                 ;
337         ap[MuIo] = c;
338         while((ap[MuLsr] & TxRdy) == 0)
339                 ;
340 }
341
342 int
343 getc(Uart*)
344 {
345         u32int *ap;
346
347         ap = (u32int*)AUXREGS;
348         while((ap[MuLsr] & RxRdy) == 0)
349                 ;
350         return ap[MuIo] & 0xFF;
351 }
352
353 void
354 uartconsinit(void)
355 {
356         Uart *uart;
357         int n;
358         char *p, *cmd;
359
360         if((p = getconf("console")) == nil)
361                 return;
362         n = strtoul(p, &cmd, 0);
363         if(p == cmd)
364                 return;
365         switch(n){
366         default:
367                 return;
368         case 0:
369                 uart = &miniuart;
370                 break;
371         }
372
373         uartctl(uart, "b9600 l8 pn s1");
374         if(*cmd != '\0')
375                 uartctl(uart, cmd);
376
377         if(!uart->enabled)
378                 (*uart->phys->enable)(uart, 0);
379
380         consuart = uart;
381         uart->console = 1;
382 }
383
384 PhysUart miniphysuart = {
385         .name           = "miniuart",
386         .pnp            = pnp,
387         .enable         = enable,
388         .disable        = disable,
389         .kick           = kick,
390         .dobreak        = dobreak,
391         .baud           = baud,
392         .bits           = bits,
393         .stop           = stop,
394         .parity         = parity,
395         .modemctl       = donothing,
396         .rts            = rts,
397         .dtr            = donothing,
398         .status         = status,
399         .fifo           = donothing,
400         .getc           = getc,
401         .putc           = putc,
402 };
403
404 void
405 okay(int on)
406 {
407         static int first;
408
409         if(!first++)
410                 gpiosel(OkLed, Output);
411         gpioout(OkLed, !on);
412 }