diff options
author | Taru Karttunen <taruti@taruti.net> | 2011-03-30 15:46:40 +0300 |
---|---|---|
committer | Taru Karttunen <taruti@taruti.net> | 2011-03-30 15:46:40 +0300 |
commit | e5888a1ffdae813d7575f5fb02275c6bb07e5199 (patch) | |
tree | d8d51eac403f07814b9e936eed0c9a79195e2450 /sys/src/9/kw/uartkw.c |
Import sources from 2011-03-30 iso image
Diffstat (limited to 'sys/src/9/kw/uartkw.c')
-rwxr-xr-x | sys/src/9/kw/uartkw.c | 362 |
1 files changed, 362 insertions, 0 deletions
diff --git a/sys/src/9/kw/uartkw.c b/sys/src/9/kw/uartkw.c new file mode 100755 index 000000000..0b7e048d0 --- /dev/null +++ b/sys/src/9/kw/uartkw.c @@ -0,0 +1,362 @@ +/* + * marvell kirkwood uart (supposed to be a 16550) + */ +#include "u.h" +#include "../port/lib.h" +#include "mem.h" +#include "dat.h" +#include "fns.h" +#include "io.h" +#include "../port/error.h" +// #include "../port/uart.h" + +enum { + UartFREQ = 0, // xxx + + IERrx = 1<<0, + IERtx = 1<<1, + + IRRintrmask = (1<<4)-1, + IRRnointr = 1, + IRRthrempty = 2, + IRRrxdata = 4, + IRRrxstatus = 6, + IRRtimeout = 12, + + IRRfifomask = 3<<6, + IRRfifoenable = 3<<6, + + FCRenable = 1<<0, + FCRrxreset = 1<<1, + FCRtxreset = 1<<2, + /* reserved */ + FCRrxtriggermask = 3<<6, + FCRrxtrigger1 = 0<<6, + FCRrxtrigger4 = 1<<6, + FCRrxtrigger8 = 2<<6, + FCRrxtrigger14 = 3<<6, + + LCRbpcmask = 3<<0, + LCRbpc5 = 0<<0, + LCRbpc6 = 1<<0, + LCRbpc7 = 2<<0, + LCRbpc8 = 3<<0, + LCRstop2b = 1<<2, + LCRparity = 1<<3, + LCRparityeven = 1<<4, + LCRbreak = 1<<6, + LCRdivlatch = 1<<7, + + LSRrx = 1<<0, + LSRrunerr = 1<<1, + LSRparerr = 1<<2, + LSRframeerr = 1<<3, + LSRbi = 1<<4, + LSRthre = 1<<5, + LSRtxempty = 1<<6, + LSRfifoerr = 1<<7, +}; + +extern PhysUart kwphysuart; + +typedef struct UartReg UartReg; +struct UartReg +{ + union { + ulong thr; + ulong dll; + ulong rbr; + }; + union { + ulong ier; + ulong dlh; + }; + union { + ulong iir; + ulong fcr; + }; + ulong lcr; + ulong mcr; + ulong lsr; + ulong scr; +}; + +typedef struct Ctlr Ctlr; +struct Ctlr { + UartReg*regs; + int irq; + Lock; +}; + +static Ctlr kirkwoodctlr[] = { +{ + .regs = nil, /* filled in below */ + .irq = IRQ1uart0, }, +}; + +static Uart kirkwooduart[] = { +{ + .regs = &kirkwoodctlr[0], + .name = "eia0", + .freq = UartFREQ, + .phys = &kwphysuart, + .special= 0, + .console= 1, + .next = nil, }, +}; + +static void +kw_read(Uart *uart) +{ + Ctlr *ctlr = uart->regs; + UartReg *regs = ctlr->regs; + ulong lsr; + char c; + + while ((lsr = regs->lsr) & LSRrx) { + if(lsr&LSRrunerr) + uart->oerr++; + if(lsr&LSRparerr) + uart->perr++; + if(lsr&LSRframeerr) + uart->ferr++; + c = regs->rbr; + if((lsr & (LSRbi|LSRframeerr|LSRparerr)) == 0) + uartrecv(uart, c); + } +} + +static void +kw_intr(Ureg*, void *arg) +{ + Uart *uart = arg; + Ctlr *ctlr = uart->regs; + UartReg *regs = ctlr->regs; + ulong v; + + if(regs == 0) { + kirkwoodctlr[0].regs = (UartReg *)soc.uart[0]; + regs = (UartReg *)soc.uart[0]; /* caution */ + coherence(); + } + v = regs->iir; + if(v & IRRthrempty) + uartkick(uart); + if(v & IRRrxdata) + kw_read(uart); + + intrclear(Irqhi, ctlr->irq); +} + +static Uart* +kw_pnp(void) +{ + kirkwoodctlr[0].regs = (UartReg *)soc.uart[0]; + coherence(); + return kirkwooduart; +} + +static void +kw_enable(Uart* uart, int ie) +{ + Ctlr *ctlr = uart->regs; + UartReg *regs = ctlr->regs; + + if(regs == 0) { + kirkwoodctlr[0].regs = (UartReg *)soc.uart[0]; + regs = (UartReg *)soc.uart[0]; /* caution */ + coherence(); + } + USED(ie); + regs->fcr = FCRenable|FCRrxtrigger4; + regs->ier = IERrx|IERtx; + intrenable(Irqhi, ctlr->irq, kw_intr, uart, uart->name); + + (*uart->phys->dtr)(uart, 1); + (*uart->phys->rts)(uart, 1); +} + +static void +kw_disable(Uart* uart) +{ + Ctlr *ctlr = uart->regs; + + (*uart->phys->dtr)(uart, 0); + (*uart->phys->rts)(uart, 0); + (*uart->phys->fifo)(uart, 0); + + intrdisable(Irqhi, ctlr->irq, kw_intr, uart, uart->name); +} + +static void +kw_kick(Uart* uart) +{ + Ctlr *ctlr = uart->regs; + UartReg *regs = ctlr->regs; + int i; + + if(uart->cts == 0 || uart->blocked) + return; + + for(i = 0; i < 16; i++) { + if((regs->lsr & LSRthre) == 0 || + uart->op >= uart->oe && uartstageoutput(uart) == 0) + break; + regs->thr = *uart->op++; + } +} + +static void +kw_break(Uart* uart, int ms) +{ + USED(uart, ms); +} + +static int +kw_baud(Uart* uart, int baud) +{ + USED(uart, baud); + return 0; +} + +static int +kw_bits(Uart* uart, int bits) +{ + USED(uart, bits); + return 0; +} + +static int +kw_stop(Uart* uart, int stop) +{ + USED(uart, stop); + return 0; +} + +static int +kw_parity(Uart* uart, int parity) +{ + USED(uart, parity); + return 0; +} + +static void +kw_modemctl(Uart* uart, int on) +{ + USED(uart, on); +} + +static void +kw_rts(Uart* uart, int on) +{ + USED(uart, on); +} + +static void +kw_dtr(Uart* uart, int on) +{ + USED(uart, on); +} + +static long +kw_status(Uart* uart, void* buf, long n, long offset) +{ + USED(uart, buf, n, offset); + return 0; +} + +static void +kw_fifo(Uart* uart, int level) +{ + USED(uart, level); +} + +static int +kw_getc(Uart *uart) +{ + Ctlr *ctlr = uart->regs; + UartReg *regs = ctlr->regs; + + while((regs->lsr&LSRrx) == 0) + ; + return regs->rbr; +} + +static void +kw_putc(Uart *uart, int c) +{ + Ctlr *ctlr = uart->regs; + UartReg *regs = ctlr->regs; + + /* can be called from iprint, among many other places */ + if(regs == 0) { + kirkwoodctlr[0].regs = (UartReg *)soc.uart[0]; + regs = (UartReg *)soc.uart[0]; /* caution */ + coherence(); + } + while((regs->lsr&LSRthre) == 0) + ; + regs->thr = c; + coherence(); +} + +PhysUart kwphysuart = { + .name = "kirkwood", + .pnp = kw_pnp, + .enable = kw_enable, + .disable = kw_disable, + .kick = kw_kick, + .dobreak = kw_break, + .baud = kw_baud, + .bits = kw_bits, + .stop = kw_stop, + .parity = kw_parity, + .modemctl = kw_modemctl, + .rts = kw_rts, + .dtr = kw_dtr, + .status = kw_status, + .fifo = kw_fifo, + .getc = kw_getc, + .putc = kw_putc, +}; + +void +uartkirkwoodconsole(void) +{ + Uart *uart; + + uart = &kirkwooduart[0]; + (*uart->phys->enable)(uart, 0); + uartctl(uart, "b115200 l8 pn s1 i1"); + uart->console = 1; + consuart = uart; +//serialputs("uart0 kirkwood\n", strlen("uart0 kirkwood\n")); +} + +void +serialputc(int c) +{ + int cnt, s; + UartReg *regs = (UartReg *)soc.uart[0]; + + s = splhi(); + cnt = m->cpuhz; + if (cnt <= 0) /* cpuhz not set yet? */ + cnt = 1000000; + while((regs->lsr & LSRthre) == 0 && --cnt > 0) + ; + regs->thr = c; + coherence(); + delay(1); + splx(s); +} + +void +serialputs(char *p, int len) +{ + while(--len >= 0) { + if(*p == '\n') + serialputc('\r'); + serialputc(*p++); + } +} |