362 lines
5.5 KiB
C
362 lines
5.5 KiB
C
/*
|
|
* 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++);
|
|
}
|
|
}
|