plan9fox/sys/src/9/cycv/uartcycv.c
2020-01-08 02:35:01 +00:00

244 lines
3.2 KiB
C

#include "u.h"
#include "../port/lib.h"
#include "mem.h"
#include "dat.h"
#include "fns.h"
#include "io.h"
enum {
RBR = 0,
IER,
FCR,
LCR,
MCR,
LSR,
MSR,
SCR,
IIR = FCR,
};
enum {
LSR_THRE = 1<<5,
LSR_DR = 1<<0,
ENTXIRQ = 1<<1,
ENRXIRQ = 1<<0
};
typedef struct Ctlr {
Lock;
ulong *r;
int irq, iena;
} Ctlr;
Uart* uartenable(Uart *);
extern PhysUart cycvphysuart;
static Ctlr vctlr[1] = {
{
.r = (void *) UART_BASE,
.irq = UART0IRQ,
}
};
static Uart vuart[1] = {
{
.regs = &vctlr[0],
.name = "UART1",
.freq = 25000000,
.phys = &cycvphysuart,
.console = 1,
.baud = 115200,
}
};
void
uartinit(void)
{
consuart = vuart;
}
static Uart *
vuartpnp(void)
{
return vuart;
}
static void
vuartkick(Uart *uart)
{
Ctlr *ct;
int i;
if(uart->blocked)
return;
ct = uart->regs;
if((ct->r[LSR] & LSR_THRE) == 0)
return;
for(i = 0; i < 128; i++){
if(uart->op >= uart->oe && uartstageoutput(uart) == 0)
break;
ct->r[RBR] = *uart->op++;
}
}
static void
vuartintr(Ureg *, void *arg)
{
Uart *uart;
Ctlr *c;
int ch, f;
uart = arg;
c = uart->regs;
for(;;){
f = c->r[IIR] & 15;
switch(f){
case 6: USED(c->r[LSR]); break;
case 4: case 8:
while((c->r[LSR] & LSR_DR) != 0){
ch = c->r[RBR];
uartrecv(uart, ch);
}
break;
case 2:
vuartkick(uart);
break;
default:
return;
}
}
}
static void
vuartenable(Uart *uart, int ie)
{
Ctlr *c;
c = uart->regs;
ilock(c);
while((c->r[LSR] & LSR_THRE) == 0)
;
c->r[LCR] = 0x03;
c->r[FCR] = 0x1;
c->r[IER] = 0x0;
if(ie){
if(!c->iena){
intrenable(c->irq, vuartintr, uart, LEVEL, uart->name);
c->iena = 1;
}
c->r[IER] = ENTXIRQ | ENRXIRQ;
}
iunlock(c);
}
static int
vuartgetc(Uart *uart)
{
Ctlr *c;
c = uart->regs;
while((c->r[LSR] & LSR_DR) == 0)
;
return c->r[RBR];
}
static void
vuartputc(Uart *uart, int c)
{
Ctlr *ct;
ct = uart->regs;
while((ct->r[LSR] & LSR_THRE) == 0)
;
ct->r[RBR] = c;
return;
}
int
uartconsole(void)
{
Uart *uart = vuart;
if(up == nil)
return -1;
if(uartenable(uart) != nil){
serialoq = uart->oq;
uart->opens++;
consuart = uart;
}
return 0;
}
int
vuartbits(Uart *uart, int n)
{
Ctlr *c;
c = uart->regs;
switch(n){
case 5: c->r[LCR] = c->r[LCR] & ~3 | 0; return 0;
case 6: c->r[LCR] = c->r[LCR] & ~3 | 1; return 0;
case 7: c->r[LCR] = c->r[LCR] & ~3 | 2; return 0;
case 8: c->r[LCR] = c->r[LCR] & ~3 | 3; return 0;
default:
return -1;
}
}
int
vuartbaud(Uart *, int n)
{
print("uart baud %d\n", n);
return 0;
}
int
vuartparity(Uart *uart, int p)
{
Ctlr *c;
c = uart->regs;
switch(p){
case 'n': c->r[LCR] = c->r[LCR] & ~0x38; return 0;
case 'o': c->r[LCR] = c->r[LCR] & ~0x38 | 0x08; return 0;
case 'e': c->r[LCR] = c->r[LCR] & ~0x38 | 0x18; return 0;
default:
return -1;
}
}
void
vuartnop(Uart *, int)
{
}
int
vuartnope(Uart *, int)
{
return -1;
}
PhysUart cycvphysuart = {
.pnp = vuartpnp,
.enable = vuartenable,
.kick = vuartkick,
.getc = vuartgetc,
.putc = vuartputc,
.bits = vuartbits,
.baud = vuartbaud,
.parity = vuartparity,
.stop = vuartnope,
.rts = vuartnop,
.dtr = vuartnop,
.dobreak = vuartnop,
.fifo = vuartnop,
.power = vuartnop,
.modemctl = vuartnop,
};