ref: a7b1ab8236b7ccd41e96e9e4008cbc3213294724
dir: /uartbbb.c/
#include "u.h"
#include "../port/lib.h"
#include "mem.h"
#include "dat.h"
#include "fns.h"
#include "io.h"
typedef struct Ctlr Ctlr;
struct Ctlr
{
Lock;
volatile ulong *r;
int irq, iena;
};
static Ctlr bbbctlr[1] = {
{
.r = (void*)VMAP,
.irq = UART0IRQ,
}
};
#define IT_TYPE(x) (((x)&0x3e)>>1)
enum
{
RHR = 0x00/4,
THR = 0x00/4,
IER = 0x04/4,
RHRIT = 1<<0,
THRIT = 1<<1,
SLEEPMODE = 1<<4,
RTSIT = 1<<6,
IIR = 0x08/4,
IT_PENDING = 1<<0,
IT_TYPE_MODEM = 0,
IT_TYPE_THR = 1,
IT_TYPE_RHR = 2,
IT_TYPE_RXTIMEOUT = 6,
EFR = 0x08/4,
ENHANCEDEN = 1<<4,
FCR = 0x08/4,
FIFO_EN = 1<<0,
RX_FIFO_CLEAR = 1<<1,
TX_FIFO_CLEAR = 1<<2,
LCR = 0x0c/4,
ConfigModeA = 0x80,
ConfigModeB = 0xbf,
OperMode = 0x00,
DIV_EN = 1<<7,
MCR = 0x10/4,
DTR = 1<<0,
RTS = 1<<1,
TCRTLR = 1<<6,
LSR = 0x14/4,
RXFIFOE = 1<<0,
TXFIFOE = 1<<5,
TXSRE = 1<<6,
MSR = 0x18/4,
MDR1 = 0x20/4,
MODESELECT = 0x3,
SCR = 0x40/4,
TXEMPTYCTLIT = 1<<3,
TXTRIGGRANU1 = 1<<6,
RXTRIGGRANU1 = 1<<7,
SSR = 0x44/4,
TXFIFOFULL = 1<<0,
SYSC = 0x54/4,
SOFTRESET = 1<<1,
SYSS = 0x58/4,
RESETDONE = 1<<0,
DLL = 0x00/4,
DLH = 0x04/4,
};
Uart* uartenable(Uart*);
static Uart *bbbuartpnp(void);
static void bbbuartkick(Uart*);
static void bbbuartintr(Ureg*, void*);
static void bbbuartenable(Uart*, int);
static int bbbuartgetc(Uart*);
static void bbbuartputc(Uart*, int);
static int bbbuartbits(Uart*, int);
static int bbbuartbaud(Uart*, int);
static int bbbuartparity(Uart*, int);
static void bbbuartnop(Uart*, int);
static int bbbuartnope(Uart*, int);
PhysUart bbbphysuart = {
.baud = bbbuartbaud,
.bits = bbbuartbits,
.dobreak = bbbuartnop,
.dtr = bbbuartnop,
.enable = bbbuartenable,
.fifo = bbbuartnop,
.getc = bbbuartgetc,
.kick = bbbuartkick,
.modemctl = bbbuartnop,
.parity = bbbuartparity,
.pnp = bbbuartpnp,
.power = bbbuartnop,
.putc = bbbuartputc,
.rts = bbbuartnop,
.stop = bbbuartnope,
};
static Uart bbbuart[1] = {
{
.regs = &bbbctlr[0],
.name = "UART0",
.freq = 25000000,
.phys = &bbbphysuart,
.console = 1,
.baud = 115200,
}
};
static Uart*
bbbuartpnp(void)
{
return bbbuart;
}
static void
bbbuartkick(Uart *uart)
{
Ctlr *ct;
int i;
if(uart->blocked)
return;
ct = uart->regs;
for(i = 0; i < 128; i++){
if((ct->r[SSR] & TXFIFOFULL) != 0)
break;
if(uart->op >= uart->oe)
if(uartstageoutput(uart) == 0)
break;
ct->r[THR] = *uart->op++;
ct->r[IER] |= THRIT;
//coherence();
}
}
static int
bbbuartbits(Uart*, int)
{
return -1;
}
static int
bbbuartbaud(Uart*, int)
{
return 0;
}
static void
bbbuartintr(Ureg *, void *arg)
{
Uart *uart;
Ctlr *ct;
ulong iir, c;
uart = arg;
ct = uart->regs;
for(iir = ct->r[IIR]; (iir & IT_PENDING) == 0; iir = ct->r[IIR]){
switch(IT_TYPE(iir)){
case IT_TYPE_RHR:
case IT_TYPE_RXTIMEOUT:
while((ct->r[LSR] & RXFIFOE) != 0){
c = ct->r[RHR];
uartrecv(uart, c);
}
break;
case IT_TYPE_THR:
bbbuartkick(uart);
if(uart->op >= uart->oe)
if(qlen(uart->oq) == 0)
if((ct->r[LSR] & TXSRE) != 0){
ct->r[IER] &= ~THRIT;
//coherence();
}
break;
}
}
}
static void
bbbuartenable(Uart *uart, int ie)
{
Ctlr *ctlr;
ctlr = uart->regs;
ilock(ctlr);
while((ctlr->r[LSR] & TXSRE) == 0);
ctlr->r[SYSC] |= SOFTRESET;
while((ctlr->r[SYSS] & RESETDONE) == 0);
ctlr->r[LCR] = ConfigModeB;
ctlr->r[EFR] |= ENHANCEDEN;
ctlr->r[LCR] = ConfigModeA;
ctlr->r[MCR] |= TCRTLR;
ctlr->r[FCR] = FIFO_EN;
ctlr->r[LCR] = ConfigModeB;
ctlr->r[EFR] &= ~ENHANCEDEN;
ctlr->r[LCR] = ConfigModeA;
ctlr->r[MCR] &= ~TCRTLR;
ctlr->r[MDR1] = 0x7;
ctlr->r[LCR] = ConfigModeB;
ctlr->r[EFR] |= ENHANCEDEN;
ctlr->r[LCR] = OperMode;
ctlr->r[IER] = 0;
ctlr->r[LCR] = ConfigModeB;
ctlr->r[DLL] = 0x1a;
ctlr->r[DLH] = 0x00; // 115200 baud
ctlr->r[LCR] = OperMode;
ctlr->r[SCR] |= TXEMPTYCTLIT;
ctlr->r[IER] = RHRIT | THRIT; // enable interrupts
ctlr->r[LCR] = ConfigModeB;
ctlr->r[EFR] &= ~ENHANCEDEN;
ctlr->r[LCR] = 0x03; // 8-it, 1 stop, no parity
ctlr->r[MDR1] = 0;
delay(25);
if(ie){
if(!ctlr->iena){
intrenable(ctlr->irq, bbbuartintr, uart, uart->name);
ctlr->iena = 1;
}
}
iunlock(ctlr);
}
static int
bbbuartgetc(Uart *u)
{
Ctlr *ct;
ct = u->regs;
while((ct->r[LSR] & RXFIFOE) == 0)
;
return ct->r[RHR];
}
static void
bbbuartputc(Uart *u, int c)
{
Ctlr *ct;
ct = u->regs;
while((ct->r[SSR] & TXFIFOFULL) != 0)
;
ct->r[THR] = c;
}
static int
bbbuartparity(Uart*, int)
{
return -1;
}
static void
bbbuartnop(Uart*, int)
{
}
static int
bbbuartnope(Uart*, int)
{
return -1;
}
void
uartinit(void)
{
consuart = bbbuart;
}
int
uartconsole(void)
{
Uart *uart = bbbuart;
if(up == nil)
return -1;
if(uartenable(uart) != nil){
serialoq = uart->oq;
uart->opens++;
consuart = uart;
}
return 0;
}