summaryrefslogtreecommitdiff
path: root/sys/src/9/kw/uartkw.c
diff options
context:
space:
mode:
authorTaru Karttunen <taruti@taruti.net>2011-03-30 15:46:40 +0300
committerTaru Karttunen <taruti@taruti.net>2011-03-30 15:46:40 +0300
commite5888a1ffdae813d7575f5fb02275c6bb07e5199 (patch)
treed8d51eac403f07814b9e936eed0c9a79195e2450 /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-xsys/src/9/kw/uartkw.c362
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++);
+ }
+}