123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424 |
- /*
- * 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){
- if(uart->console){
- if(uart->opens == 1)
- uart->putc = kbdcr2nl;
- else
- uart->putc = nil;
- }
- do{
- uartrecv(uart, ap[MuIo] & 0xFF);
- }while(ap[MuLsr] & RxRdy);
- }
- coherence();
- }
- static Uart*
- pnp(void)
- {
- Uart *uart;
- uart = &miniuart;
- if(uart->console == 0)
- kbdq = qopen(8*1024, 0, nil, nil);
- return uart;
- }
- 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);
- }
|