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