/************************************************************* * File: lib/p16550.c * Purpose: Driver for 16550D UART * Author: Phil Bunce (pjb@carmel.com) * Revision History: * 980615 Created * 980618 Added OP_BAUDRATES * 981106 Works with "-board bdmr4102" */ #include /* * Polled I/O routines for the National NS16550 UART * */ #include #include /* btab = sysclk/(baudrate*N) */ /* btab = 14.7456MHz/(baudrate*16) */ static long btab_14[] = { -1, /* B0 */ -1, /* B50 */ -1, /* B75 */ -1, /* B110 */ -1, /* B134 */ 6144, /* B150 */ 4608, /* B200 */ 3072, /* B300 */ 1536, /* B600 */ 768, /* B1200 */ 512, /* B1800 */ 384, /* B2400 */ 192, /* B4800 */ 96, /* B9600 */ 48, /* B19200 */ 24, /* B38400 */ 16, /* B57600 */ 12, /* B76800 */ 8, /* B115200 */ 6, /* B153600 */ 4, /* B230400 */ 3, /* B307200 */ 2, /* B460800 */ 1, /* B921600 */ 0 /* end */ }; /* assumes a 18.432 MHz crystal is in use */ static long btab_18[] = { -1, /* B0 */ 23040, /* B50 */ 15360, /* B75 */ 10473, /* B110 */ 8565, /* B134 */ 7680, /* B150 */ -1, /* B200 */ 3840, /* B300 */ 1920, /* B600 */ 960, /* B1200 */ 640, /* B1800 */ 480, /* B2400 */ 240, /* B4800 */ 120, /* B9600 */ 60, /* B19200 */ 30, /* B38400 */ 20, /* B57600 */ -1, /* B76800 */ 10, /* B115200 */ -1, /* B153600 */ 5, /* B230400 */ -1, /* B307200 */ 2, /* B460800 */ -1, /* B921600 */ 0 /* end */ }; #define DEFRATE 13 /* default baudrate (9600) */ #define inb(a) (*((volatile Uchar *)(a))) #define inh(a) (*((volatile Ushort *)(a))) #define outb(a,v) (*((volatile Uchar *)(a))=(v)) #define outh(a,v) (*((volatile Ushort *)(a))=(v)) #define outw(a,v) (*((volatile Ulong *)(a))=(v)) #define RXRDY 0x01 #define TXRDY 0x20 #define STATUS (gap*5) #define RXHR (gap*0) #define TXHR (gap*0) /* ------- Registers ------------ Read Write --------------------- 0 RHR THR 1 --- int_enable ----- 2 int_ident FIFO cntrl 3 ---- line cntrl ---- 4 ---- modem ctrl ---- 5 ---- line status --- 01=rxrdy 20=txrdy 6 --- modem status --- 7 ----- scratch ------ 0+dlab - ls divisor latch - 1+dlab - ms divisor latch - ---------------------------------- */ /************************************************************* * p16550(op,siodat,chan,ch) */ p16550(op,siodat,chan,ch) int op,chan,ch; void *siodat; { int i,brate; struct p16550Rec *info = siodat; Ulong base = info->base; int gap = info->gap; Ulong m,v; long *btab; #ifdef MIPSEB base += info->beoffs; #endif if (info->baudclk == 14) btab = btab_14; else btab = btab_18; switch (op) { case OP_RXRDY : if (inb(base+STATUS)&RXRDY) return(1); break; case OP_RX : return inb(base+RXHR); case OP_TXRDY : if (inb(base+STATUS)&TXRDY) return(1); break; case OP_TX : outb(base+TXHR,ch); break; case OP_INIT : /* set DLAB */ outb(base+(3*gap),0x80); /* ms baud */ outb(base+(1*gap),btab[DEFRATE]>>8); /* ls baud */ outb(base+(0*gap),btab[DEFRATE]&0xff); /* mode: 2 stopbits, no parity, 8 bitsdata */ outb(base+(3*gap),0x03); break; case OP_BAUD : brate = ch; /* check brate <= 23 */ if (brate > 23) return(1); /* baud rate too large */ /* return if unsupported baud rate */ if (btab[brate] == -1) return(1); outb(base+(3*gap),0x80); /* ms baud */ outb(base+(1*gap),btab[brate]>>8); /* ls baud */ outb(base+(0*gap),btab[brate]&0xff); /* mode: 2 stopbits, no parity, 8 bitsdata */ outb(base+(3*gap),0x03); break; case OP_CLKINIT : break; case OP_DELAY : return(0); break; case OP_BAUDRATES : m = 1; for (i=v=0;btab[i];i++) { if (btab[i] != -1) v |= m; m <<= 1; } return(v); break; } return(0); }