📄 p16550u.c
字号:
/************************************************************** File: lib/p16550u.c* Purpose: PMON driver for 16550-like UART in RAP chip.* Author: Phil Bunce (pjb@carmel.com)* Revision History:* 970827 Start of revision history* 980701 Merged into PMON5* 980817 Switched over to Russell's version.* 980817 Added divisors for 200B*//** Desc: Driver for the 16550U UART to be used with PMON. This UART is* a modified version of the SWAN which is used in the RAP.* Assumes FIFO Polled Mode of operation.** The functions which are handled are:* 1) OP_RXRDY Reciver FIFO ready?* 2) OP_TXRDY Transmitter FIFO ready?* 3) OP_TX Send data in the Transmitter FIFO* 4) OP_RX Receive data in the Receiver FIFO* 5) OP_INIT Initialize the 16550U UART* 6) OP_BAUD Change the baud rate to specified value*** Polled I/O routines for LSI LOGIC UART implementation*** Each 16550U has the following registers:** Register Description Offset* -------- ------------------------------------ --------------------* Config Configuration Register OFFSET_config* Divisor Baud Rate Generator Count Register OFFSET_divisor* Reset Reset / Halt Register OFFSET_reset* Status Status Register OFFSET_status* RxBuff Receive Buffer OFFSET_rxbuff* TxBuff Transmit Buffer OFFSET_txbuff* Interval Interval Timer Register OFFSET_interval* Abrd ABRD Minimum Sample Register OFFSET_abrd* Channel Channel Configuration Register OFFSET_channel*** Information regarding the registers can be found in LSI Logic's* L64388A2 RAP Technical Manual.****************************************************************/#include <terms.h>#include <defines.h>typedef unsigned long ulong;typedef unsigned short ushort;#define OFFSET_config 0x00 #define OFFSET_divisor 0x08 #define OFFSET_reset 0x10 #define OFFSET_status 0x18 #define OFFSET_rxbuff 0x20 #define OFFSET_txbuff 0x28 #define OFFSET_interval 0x30 #define OFFSET_abrd 0x38 #define OFFSET_channel 0x40 #define STATUS_RDY 0x00008000#define STATUS_TXEMPTY 0x00000002#define STATUS_TXALMOSTFULL 0x01000000#define BRG_PS 0x00100000/* Driver for p16550U UART */int p16550U(int, unsigned long, int, int);/**************************************************************** Baud rate divisor tables. ***************************************************************//* assumes a 18.432 MHz crystal is in use *//* btab = 18432000/(baudrate*16) */static long btab_18[] = { -1, /* B0 */ 23040, /* B50 */ 15360, /* B75 */ 10473, /* B110 */ 8597, /* B134 */ 7680, /* B150 */ 5760, /* 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 */ };/* assumes a 40 MHz crystal is in use *//* btab = 40000000/(baudrate*16) */static long btab_40[] = { -1, /* B0 */ 50000, /* B50 */ 33333, /* B75 */ 22727, /* B110 */ 18657, /* B134 */ 16667, /* B150 */ 12500, /* B200 */ 8333, /* B300 */ 4167, /* B600 */ 2083, /* B1200 */ 1389, /* B1800 */ 1042, /* B2400 */ 521, /* B4800 */ 260, /* B9600 */ 130, /* B19200 */ 65, /* B38400 */ 43, /* B57600 */ -1, /* B76800 */ 22, /* B115200 */ -1, /* B153600 */ 11, /* B230400 */ -1, /* B307200 */ 5, /* B460800 */ -1, /* B921600 */ 0 /* end */ };/* assumes a 80 MHZ crystal is in use *//* btab = 80000000/(baudrate*16) */static long btab_80[] = { -1, /* B0 */ 100000, /* B50 */ 66667, /* B75 */ 45455, /* B110 */ 37313, /* B134 */ 33333, /* B150 */ 25000, /* B200 */ 16667, /* B300 */ 8333, /* B600 */ 4167, /* B1200 */ 2778, /* B1800 */ 2083, /* B2400 */ 1042, /* B4800 */ 521, /* B9600 */ 260, /* B19200 */ 130, /* B38400 */ 87, /* B57600 */ -1, /* B76800 */ 43, /* B115200 */ -1, /* B153600 */ 22, /* B230400 */ -1, /* B307200 */ 11, /* B460800 */ -1, /* B921600 */ 0 /* end */ };#define DEFRATE 13 /* default baud rate is 9600 baud */ /* inw is used to read a word sized value from a register */#define inw(a) (*((volatile unsigned long *)(a)))/* outw is used to place a word sized value into a register */#define outw(a,v) (*((volatile unsigned long *)(a))=(v))/******************************************************************* Func: p16550u* Desc: Provide capabilities to send, recieve, initialize,* and monitor the 16550U UART.** Params: int op, int chan, int ch, struct p16550Uinfo* Output: int*******************************************************************/int p16550u(int op, unsigned long base_addr, int chan, int ch) {unsigned long m,v;long *btab;int i,brate;/* determine what clock frequency we're running at */#ifdef CLKFREQif (CLKFREQ == 40) { btab = btab_40;} else if(CLKFREQ == 80) { btab = btab_80;} else { btab = btab_18;};#elsebtab = btab_18;#endif switch (op) { case OP_RXRDY : /* Is there one byte in the RCVR FIFO? */ if(inw(base_addr + OFFSET_status) & STATUS_RDY) return(1); break; case OP_RX : return inw(base_addr + OFFSET_rxbuff); case OP_TXRDY : /* Check to see if XMIT FIFO is empty */ if((inw(base_addr + OFFSET_status) & STATUS_TXALMOSTFULL) == 0) return(1); break; case OP_TX : return outw(base_addr + OFFSET_txbuff, ch); case OP_INIT : /* make sure UART is taken out of reset */ outw(base_addr + OFFSET_reset, 0xfffffffe); /* determine what clock frequency we're running at */#ifdef CLKFREQ if((CLKFREQ == 40) || (CLKFREQ == 80)) { /* turn loopback off, select system clock */ outw(base_addr + OFFSET_config, 0x00000008); } else { /* turn loopback off, select brg clock */ outw(base_addr + OFFSET_config, 0x00000000); }#else /* turn loopback off, select brg clock */ outw(base_addr + OFFSET_config, 0x00000000);#endif /* reset these bits to zero - optional */ outw(base_addr + OFFSET_status, 0x00000000); /* channel: 1 stopbit, no parity, 8 bits data, ignore cts, */ /* ignore dsr, ignore dcd */ outw(base_addr + OFFSET_channel, 0x000000e3); /* set baud rate to default */ outw(base_addr + OFFSET_divisor, btab[DEFRATE]); /* take out of tx and rx halt */ outw(base_addr + OFFSET_reset, 0x00000000); break; case OP_BAUD : brate = ch; /* check if given value is in table */ if (brate > 24) return(1); /* baud rate too large */ /* return if unsupported baud rate */ if (btab[brate] == -1) return(1); /* set baud rate to given value */ outw(base_addr + OFFSET_divisor, btab[brate]); break; case OP_CLKINIT : break; case OP_DELAY : 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);}#if 0#if 0 li t1,0xb0008600 li t0,0xfffe sw t0,16(t1) sw zero,0(t1) sw zero,24(t1) li t0,0xe3 sw t0,64(t1) li t0,120 # 9600 sw t0,8(t1) sw zero,16(t1)#endif#if 0 li t1,0xb0008600 1: lw t0,24(t1) and t0,0x01000000 bne t0,zero,1b li t0,0x41 sw t0,40(t1)#endifdiagc(int c){while (inw(0xb0008600+24)&0x01000000);outw(0xb0008600+40,c);}diagh(Ulong v,int n){int d,shmt;diagc('[');for (shmt=28;n>0;n--,shmt-=4) { d = (v>>shmt)&0xf; if (d >= 10) diagc('a'+d-10); else diagc('0'+d); }diagc(']');}#endif
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -