#include "u.h" #include "../port/lib.h" #include "../port/error.h" #include "mem.h" #include "dat.h" #include "fns.h" #include "io.h" enum { URXD = 0x00/4, /* UART Receiver Register */ RX_CHARRDY = 1<<15, RX_ERR = 1<<14, RX_OVRRUN = 1<<13, RX_FRMERR = 1<<12, RX_BRK = 1<<11, RX_PRERR = 1<<10, RX_DATA = 0xFF, UTXD = 0x40/4, /* UART Transmitter Register */ TX_DATA = 0xFF, UCR1 = 0x80/4, /* UART Control Register 1 */ CR1_ADEN = 1<<15, /* Automatic Baud Rate Detection Interrupt Enable */ CR1_ADNR = 1<<14, /* Automatic Detection of Baud Rate */ CR1_TRDYEN = 1<<13, /* Transmitter Ready Interrupt Enable */ CR1_IDEN = 1<<12, /* Idle Condition Detected Interrupt Enable */ CR1_ICD_SHIFT = 10, /* Idle Condition Detect Mask */ CR1_ICD_MASK = 3<regs; while(u->op < u->oe || uartstageoutput(u)){ if(u->blocked) break; if((regs[USR1] & SR1_TRDY) == 0){ regs[UCR1] |= CR1_TRDYEN; return; } regs[UTXD] = *(u->op++) & TX_DATA; } regs[UCR1] &= ~CR1_TRDYEN; } static void config(Uart *u) { u32int cr2, *regs = u->regs; /* enable uart */ regs[UCR1] = CR1_UARTEN; cr2 = CR2_SRST | CR2_IRTS | CR2_RXEN | CR2_TXEN; switch(u->parity){ case 'e': cr2 |= CR2_PREN | CR2_PREVEN; break; case 'o': cr2 |= CR2_PREN | CR2_PRODD; break; } cr2 |= u->bits == 7 ? CR2_WS7 : CR2_WS8; if(u->stop == 2) cr2 |= CR2_STPB; regs[UCR2] = cr2; regs[UCR3] = 0x7<<8 | CR3_RXDMUXSEL; regs[UCR4] = 31<baud) / 1600)-1; regs[UBMR] = (u->freq / 1600)-1; regs[UCR1] = CR1_UARTEN | CR1_RRDYEN; } static int bits(Uart *u, int n) { switch(n){ case 8: break; case 7: break; default: return -1; } u->bits = n; config(u); return 0; } static int stop(Uart *u, int n) { switch(n){ case 1: break; case 2: break; default: return -1; } u->stop = n; config(u); return 0; } static int parity(Uart *u, int n) { switch(n){ case 'n': break; case 'e': break; case 'o': break; default: return -1; } u->parity = n; config(u); return 0; } static int baud(Uart *u, int n) { if(u->freq == 0 || n <= 0) return -1; u->baud = n; config(u); return 0; } static void rts(Uart*, int) { } static void dobreak(Uart*, int) { } static long status(Uart *uart, void *buf, long n, long offset) { char *p; p = malloc(READSTR); if(p == nil) error(Enomem); snprint(p, READSTR, "b%d\n" "dev(%d) type(%d) framing(%d) overruns(%d) " "berr(%d) serr(%d)\n", uart->baud, uart->dev, uart->type, uart->ferr, uart->oerr, uart->berr, uart->serr ); n = readstr(offset, buf, n, p); free(p); return n; } static void interrupt(Ureg*, void *arg) { Uart *uart = arg; u32int v, *regs = (u32int*)uart->regs; while((v = regs[URXD]) & RX_CHARRDY) uartrecv(uart, v & RX_DATA); uartkick(uart); } static void clkenable(Uart *u, int on) { char clk[32]; snprint(clk, sizeof(clk), "%s.ipg_perclk", u->name); if(on) setclkrate(clk, "osc_25m_ref_clk", u->freq); setclkgate(clk, on); } static void disable(Uart *u) { u32int *regs = u->regs; if(u->console) return; /* avoid glitch */ regs[UCR1] = 0; clkenable(u, 0); } static void enable(Uart *u, int ie) { disable(u); clkenable(u, 1); if(ie) intrenable(IRQuart1, interrupt, u, BUSUNKNOWN, u->name); config(u); } static void donothing(Uart*, int) { } static void putc(Uart *u, int c) { u32int *regs = u->regs; while((regs[USR1] & SR1_TRDY) == 0) ; regs[UTXD] = c & TX_DATA; } static int getc(Uart *u) { u32int c, *regs = (u32int*)u->regs; do c = regs[URXD]; while((c & RX_CHARRDY) == 0); return c & RX_DATA; } void uartconsinit(void) { consuart = &uart1; consuart->console = 1; uartctl(consuart, "l8 pn s1"); uartputs(kmesg.buf, kmesg.n); } PhysUart imxphysuart = { .name = "imx", .pnp = pnp, .enable = enable, .disable = disable, .kick = kick, .dobreak = dobreak, .baud = baud, .bits = bits, .stop = stop, .parity = parity, .modemctl = donothing, .rts = rts, .dtr = donothing, .status = status, .fifo = donothing, .getc = getc, .putc = putc, };