diff options
author | cinap_lenrek <cinap_lenrek@gmx.de> | 2013-01-26 17:33:56 +0100 |
---|---|---|
committer | cinap_lenrek <cinap_lenrek@gmx.de> | 2013-01-26 17:33:56 +0100 |
commit | bc610a1b1c32f6e2e9b034217bb3ce9a7defa739 (patch) | |
tree | 98fa1e680867eaf19c1be5e818a570713fa7a286 /sys/src/9/bcm/uartmini.c | |
parent | ea108c8ca6e726ac008f75775ab83775ec233171 (diff) |
add raspberry pi kernel (from sources)
Diffstat (limited to 'sys/src/9/bcm/uartmini.c')
-rw-r--r-- | sys/src/9/bcm/uartmini.c | 413 |
1 files changed, 413 insertions, 0 deletions
diff --git a/sys/src/9/bcm/uartmini.c b/sys/src/9/bcm/uartmini.c new file mode 100644 index 000000000..aa9b87f13 --- /dev/null +++ b/sys/src/9/bcm/uartmini.c @@ -0,0 +1,413 @@ +/* + * bcm2835 mini uart (UART1) + */ + +#include "u.h" +#include "../port/lib.h" +#include "../port/error.h" +#include "mem.h" +#include "dat.h" +#include "fns.h" +#include "io.h" + +#define GPIOREGS (VIRTIO+0x200000) +#define AUXREGS (VIRTIO+0x215000) +#define OkLed 16 +#define TxPin 14 +#define RxPin 15 + +/* GPIO regs */ +enum { + Fsel0 = 0x00>>2, + FuncMask= 0x7, + Input = 0x0, + Output = 0x1, + Alt0 = 0x4, + Alt1 = 0x5, + Alt2 = 0x6, + Alt3 = 0x7, + Alt4 = 0x3, + Alt5 = 0x2, + Set0 = 0x1c>>2, + Clr0 = 0x28>>2, + Lev0 = 0x34>>2, + PUD = 0x94>>2, + Off = 0x0, + Pulldown= 0x1, + Pullup = 0x2, + PUDclk0 = 0x98>>2, + PUDclk1 = 0x9c>>2, +}; + +/* AUX regs */ +enum { + Irq = 0x00>>2, + UartIrq = 1<<0, + Enables = 0x04>>2, + UartEn = 1<<0, + MuIo = 0x40>>2, + MuIer = 0x44>>2, + RxIen = 1<<0, + TxIen = 1<<1, + MuIir = 0x48>>2, + MuLcr = 0x4c>>2, + Bitsmask= 3<<0, + Bits7 = 2<<0, + Bits8 = 3<<0, + MuMcr = 0x50>>2, + RtsN = 1<<1, + MuLsr = 0x54>>2, + TxDone = 1<<6, + TxRdy = 1<<5, + RxRdy = 1<<0, + MuCntl = 0x60>>2, + CtsFlow = 1<<3, + TxEn = 1<<1, + RxEn = 1<<0, + MuBaud = 0x68>>2, +}; + +extern PhysUart miniphysuart; + +static Uart miniuart = { + .regs = (u32int*)AUXREGS, + .name = "uart0", + .freq = 250000000, + .phys = &miniphysuart, +}; + +void +gpiosel(uint pin, int func) +{ + u32int *gp, *fsel; + int off; + + gp = (u32int*)GPIOREGS; + fsel = &gp[Fsel0 + pin/10]; + off = (pin % 10) * 3; + *fsel = (*fsel & ~(FuncMask << off)) | func << off; +} + +void +gpiopulloff(uint pin) +{ + u32int *gp, *reg; + u32int mask; + + gp = (u32int*)GPIOREGS; + reg = &gp[PUDclk0 + pin/32]; + mask = 1 << (pin % 32); + gp[PUD] = Off; + microdelay(1); + *reg = mask; + microdelay(1); + *reg = 0; +} + +void +gpioout(uint pin, int set) +{ + u32int *gp; + int v; + + gp = (u32int*)GPIOREGS; + v = set? Set0: Clr0; + gp[v + pin/32] = 1 << (pin % 32); +} + +int +gpioin(uint pin) +{ + u32int *gp; + + gp = (u32int*)GPIOREGS; + return (gp[Lev0 + pin/32] & (1 << (pin % 32))) != 0; +} + +static void +interrupt(Ureg*, void *arg) +{ + Uart *uart; + u32int *ap; + + uart = arg; + ap = (u32int*)uart->regs; + + coherence(); + if(0 && (ap[Irq] & UartIrq) == 0) + return; + if(ap[MuLsr] & TxRdy) + uartkick(uart); + if(ap[MuLsr] & RxRdy){ + do{ + uartrecv(uart, ap[MuIo] & 0xFF); + }while(ap[MuLsr] & RxRdy); + } + coherence(); +} + +static Uart* +pnp(void) +{ + return &miniuart; +} + +static void +enable(Uart *uart, int ie) +{ + u32int *ap; + + ap = (u32int*)uart->regs; + delay(10); + gpiosel(TxPin, Alt5); + gpiosel(RxPin, Alt5); + gpiopulloff(TxPin); + gpiopulloff(RxPin); + ap[Enables] |= UartEn; + ap[MuIir] = 6; + ap[MuLcr] = Bits8; + ap[MuCntl] = TxEn|RxEn; + ap[MuBaud] = 250000000 / (115200 * 8) - 1; + if(ie){ + intrenable(IRQaux, interrupt, uart, 0, "uart"); + ap[MuIer] = RxIen|TxIen; + }else + ap[MuIer] = 0; +} + +static void +disable(Uart *uart) +{ + u32int *ap; + + ap = (u32int*)uart->regs; + ap[MuCntl] = 0; + ap[MuIer] = 0; +} + +static void +kick(Uart *uart) +{ + u32int *ap; + + ap = (u32int*)uart->regs; + if(uart->blocked) + return; + coherence(); + while(ap[MuLsr] & TxRdy){ + if(uart->op >= uart->oe && uartstageoutput(uart) == 0) + break; + ap[MuIo] = *(uart->op++); + } + if(ap[MuLsr] & TxDone) + ap[MuIer] &= ~TxIen; + else + ap[MuIer] |= TxIen; + coherence(); +} + +/* TODO */ +static void +dobreak(Uart *uart, int ms) +{ + USED(uart, ms); +} + +static int +baud(Uart *uart, int n) +{ + u32int *ap; + + ap = (u32int*)uart->regs; + if(uart->freq == 0 || n <= 0) + return -1; + ap[MuBaud] = (uart->freq + 4*n - 1) / (8 * n) - 1; + uart->baud = n; + return 0; +} + +static int +bits(Uart *uart, int n) +{ + u32int *ap; + int set; + + ap = (u32int*)uart->regs; + switch(n){ + case 7: + set = Bits7; + break; + case 8: + set = Bits8; + break; + default: + return -1; + } + ap[MuLcr] = (ap[MuLcr] & ~Bitsmask) | set; + uart->bits = n; + return 0; +} + +static int +stop(Uart *uart, int n) +{ + if(n != 1) + return -1; + uart->stop = n; + return 0; +} + +static int +parity(Uart *uart, int n) +{ + if(n != 'n') + return -1; + uart->parity = n; + return 0; +} + +/* + * cts/rts flow control + * need to bring signals to gpio pins before enabling this + */ + +static void +modemctl(Uart *uart, int on) +{ + u32int *ap; + + ap = (u32int*)uart->regs; + if(on) + ap[MuCntl] |= CtsFlow; + else + ap[MuCntl] &= ~CtsFlow; + uart->modem = on; +} + +static void +rts(Uart *uart, int on) +{ + u32int *ap; + + ap = (u32int*)uart->regs; + if(on) + ap[MuMcr] &= ~RtsN; + else + ap[MuMcr] |= RtsN; +} + +static long +status(Uart *uart, void *buf, long n, long offset) +{ + char *p; + + p = malloc(READSTR); + if(p == nil) + error(Enomem); + snprint(p, READSTR, + "b%d\n" + "dev(%d) type(%d) framing(%d) overruns(%d) " + "berr(%d) serr(%d)\n", + + uart->baud, + uart->dev, + uart->type, + uart->ferr, + uart->oerr, + uart->berr, + uart->serr + ); + n = readstr(offset, buf, n, p); + free(p); + + return n; +} + +static void +donothing(Uart*, int) +{ +} + +void +putc(Uart*, int c) +{ + u32int *ap; + + ap = (u32int*)AUXREGS; + while((ap[MuLsr] & TxRdy) == 0) + ; + ap[MuIo] = c; + while((ap[MuLsr] & TxRdy) == 0) + ; +} + +int +getc(Uart*) +{ + u32int *ap; + + ap = (u32int*)AUXREGS; + while((ap[MuLsr] & RxRdy) == 0) + ; + return ap[MuIo] & 0xFF; +} + +void +uartconsinit(void) +{ + Uart *uart; + int n; + char *p, *cmd; + + if((p = getconf("console")) == nil) + return; + n = strtoul(p, &cmd, 0); + if(p == cmd) + return; + switch(n){ + default: + return; + case 0: + uart = &miniuart; + break; + } + + if(!uart->enabled) + (*uart->phys->enable)(uart, 0); + uartctl(uart, "b9600 l8 pn s1"); + if(*cmd != '\0') + uartctl(uart, cmd); + + consuart = uart; + uart->console = 1; +} + +PhysUart miniphysuart = { + .name = "miniuart", + .pnp = pnp, + .enable = enable, + .disable = disable, + .kick = kick, + .dobreak = dobreak, + .baud = baud, + .bits = bits, + .stop = stop, + .parity = parity, + .modemctl = donothing, + .rts = rts, + .dtr = donothing, + .status = status, + .fifo = donothing, + .getc = getc, + .putc = putc, +}; + +void +okay(int on) +{ + static int first; + + if(!first++) + gpiosel(OkLed, Output); + gpioout(OkLed, !on); +} |