tkernel_2/monitor/driver/sio/src/ns16550.c | bare source | permlink (0.02 seconds) |
1: /* 2: *---------------------------------------------------------------------- 3: * T-Kernel 2.0 Software Package 4: * 5: * Copyright 2011 by Ken Sakamura. 6: * This software is distributed under the latest version of T-License 2.x. 7: *---------------------------------------------------------------------- 8: * 9: * Released by T-Engine Forum(http://www.t-engine.org/) at 2011/05/17. 10: * Modified by T-Engine Forum at 2013/02/28. 11: * Modified by TRON Forum(http://www.tron.org/) at 2015/06/01. 12: * 13: *---------------------------------------------------------------------- 14: */ 15: 16: /* 17: * ns16550.c 18: * 19: * serial port I/O 20: */ 21: 22: #include <tmonitor.h> 23: 24: /* 25: * serial port hardware configuration definition 26: */ 27: typedef struct { 28: UW iob; /* I/O base address */ 29: } DEFSIO; 30: 31: #if 0 32: # define IOSTEP /* I/O address separation */ 33: # define CLOCK /* input clock (Hz) */ 34: 35: /* ----------------------------------------------------------------------- */ 36: #elif _TEF_EM1D_ 37: # include <arm/em1d512.h> 38: LOCAL const DEFSIO DefSIO[3] = { 39: { UARTnBase(UART0) }, 40: { UARTnBase(UART1) }, 41: { UARTnBase(UART2) }, 42: }; 43: # define IOSTEP 4 44: # define CLOCK 229376000 45: 46: // Unlike ordinary 16550, all registers exist and are independently accessed. 47: // (No overlaid meaning/behavior per read or write, or switching of register sets is necessary. 48: // also, 16-bits read/write to data register while FIFO is enabled causes two character input/output.) 49: // 50: #define UART(n) ( IOB + (n) * IOSTEP ) 51: #define regDATA UART(0) /* data register (RW) */ 52: #define regINTE UART(1) /* interrupt enable register (RW) */ 53: #define regINTS UART(2) /* interrupt selection register(R ) */ 54: #define regFCTL UART(3) /* FIFO control register (RW) */ 55: #define regLCTL UART(4) /* line control register (RW) */ 56: #define regMCTL UART(5) /* model control register (RW) */ 57: #define regLSTS UART(6) /* line status register (R ) */ 58: #define regMSTS UART(7) /* modem status register (R ) */ 59: #define regSCRA UART(8) /* scratch data register (RW) */ 60: #define regDIVL UART(9) /* divisor lower bits (RW) */ 61: #define regDIVH UART(10) /* divisor upper bits (RW) */ 62: /* ----------------------------------------------------------------------- */ 63: #endif 64: 65: #define N_DEFSIO ( sizeof(DefSIO) / sizeof(DEFSIO) ) 66: 67: /* ------------------------------------------------------------------------ */ 68: 69: #define IOB ( scb->info ) /* I/O base address */ 70: 71: #if !defined(IN) 72: #define IN(x) in_b(x) 73: #define OUT(x, y) out_b((x), (y)) 74: #endif 75: 76: /* 77: * definition of 16550 78: * Every access is byte access. 79: */ 80: #if !defined(UART) 81: #define UART(n) ( IOB + (n) * IOSTEP ) 82: #define regDATA UART(0) /* data register (RW) */ 83: #define regINTE UART(1) /* interrupt enable register (RW) */ 84: #define regINTS UART(2) /* interrupt selection register(R ) */ 85: #define regFCTL UART(2) /* FIFO control register ( W) */ 86: #define regLCTL UART(3) /* line control register (RW) */ 87: #define regMCTL UART(4) /* modem control register (RW) */ 88: #define regLSTS UART(5) /* line status register (R ) */ 89: #define regMSTS UART(6) /* modem status register (R ) */ 90: #define regSCRA UART(7) /* scratch data register (RW) */ 91: #define regDIVL UART(0) /* divisor lower bits (RW) */ 92: #define regDIVH UART(1) /* divisor upper bits (RW) */ 93: #endif 94: 95: /* transmission speed -> divided counter value. */ 96: #define LC_LINE_SPEED(bps) (CLOCK / 16 / (bps)) 97: 98: /* line control register */ 99: #define LC_DLAB 0x80 /* (divided) counter access */ 100: #define LC_SBRK 0x40 /* send BREAK */ 101: #define LC_SNDP 0x20 /* with parity */ 102: #define LC_EVNP 0x10 /* even parity */ 103: #define LC_ENAP 0x08 /* enable parity */ 104: #define LC_STOP 0x04 /* stop bit */ 105: #define LC_BLEN 0x03 /* number of bits in data */ 106: 107: /* default : 8 bits data, one bit stop, and no parity. */ 108: #define dtLC (0x03) 109: 110: /* line status register */ 111: #define LS_TSRE 0x40 /* transmission shift register empty */ 112: #define LS_THRE 0x20 /* transmission hold register empty */ 113: #define LS_BINT 0x10 /* BREAK received */ 114: #define LS_FERR 0x08 /* framing error */ 115: #define LS_PERR 0x04 /* parity error */ 116: #define LS_OERR 0x02 /* overrun error */ 117: #define LS_DRDY 0x01 /* received data ready */ 118: 119: #define LS_RxERR (LS_BINT|LS_FERR|LS_PERR|LS_OERR) 120: 121: /* modem control register */ 122: #define MC_OUT2 0x08 /* auxiliary output #2 (enable interrupt) */ 123: #define MC_OUT1 0x04 /* auxiliary output #1 */ 124: #define MC_RTS 0x02 /* Request To Send */ 125: #define MC_DTR 0x01 /* Data Terminal Ready */ 126: 127: /* default : disable interrupt */ 128: #define dtMC (MC_RTS | MC_DTR) 129: 130: /* modem status register */ 131: #define MS_CD 0x80 /* Data Carrier Detect */ 132: #define MS_RI 0x40 /* Ring Indicate */ 133: #define MS_DR 0x20 /* Data Set Ready */ 134: #define MS_CS 0x10 /* Clear To Send */ 135: #define MS_D_CD 0x08 /* change of CD detected */ 136: #define MS_D_RI 0x04 /* change of RI detected */ 137: #define MS_D_DR 0x02 /* change of DR detected */ 138: #define MS_D_CS 0x01 /* change of CS detected */ 139: 140: /* interrupt enable register */ 141: #define IM_MSTS 0x08 /* modem state interrupt */ 142: #define IM_LSTS 0x04 /* receive line state interrupt */ 143: #define IM_SND 0x02 /* send ready interrupt */ 144: #define IM_RCV 0x01 /* input data ready interrupt */ 145: 146: /* default : all interrupts are disabled */ 147: #define dtIM (0x00) 148: 149: /* interrupt selection register */ 150: #define IS_PEND 0x01 /* interrupt is pending */ 151: #define IS_ID 0x0e /* interrupt ID */ 152: #define IS_CTMO 0x0c /* ID=6 timeout interrupt */ 153: #define IS_LSTS 0x06 /* ID=3 receive line state interrupt. */ 154: #define IS_RCV 0x04 /* ID=2 input data ready interupt */ 155: #define IS_SND 0x02 /* ID=1 send ready interrupt */ 156: #define IS_MSTS 0x00 /* ID=0 modem state interrupt */ 157: #define IS_FIFO 0xc0 /* FIFO is in use */ 158: 159: /* FIFO control register */ 160: #define FC_TL01 0x00 /* receive interrupt threshold ( 1 byte ) */ 161: #define FC_TL04 0x40 /* receive threshold 4 byte */ 162: #define FC_TL08 0x80 /* receive interrupt thereshold 8 byte */ 163: #define FC_TL14 0xc0 /* receive interrupt threshold 14 byte */ 164: #define FC_TXCLR 0x04 /* clear trasnmission FIFO */ 165: #define FC_RXCLR 0x02 /* receive FIFO clear. */ 166: #if _TEF_EM1D_ 167: #define FC_FIFO 0x21 /* enable 64 bytes FIFO */ 168: #define FIFO_SIZE 64 /* FIFO size */ 169: #define dtFC (FC_FIFO | FC_TL14) /* default */ 170: #else 171: #define FC_FIFO 0x01 /* enable FIFO */ 172: #define FIFO_SIZE 16 /* FIFO size */ 173: #define dtFC (FC_FIFO | FC_TL08) /* default */ 174: #endif 175: 176: /* default : enable FIFO, 8 byte threshold */ 177: #define dtFC_CLR (FC_FIFO | FC_TXCLR | FC_RXCLR) /* clear */ 178: 179: /* ------------------------------------------------------------------------ */ 180: 181: /* 182: * Power on RS-232C driver IC 183: */ 184: #define RSDRV_PWON(siocb) /* no operation */ 185: 186: /* 187: * serial port I/O 188: */ 189: LOCAL void putSIO_16550( SIOCB *scb, UB c ) 190: { 191: RSDRV_PWON(scb); 192: 193: /* wait until transmission is ready. */ 194: while ((IN(regLSTS) & LS_THRE) == 0); 195: 196: /* write transmission data */ 197: OUT(regDATA, c); 198: 199: /* wait until the completion of transmission */ 200: while ((IN(regLSTS) & LS_THRE) == 0); 201: } 202: 203: /* 204: * serial port input 205: * tmo timeout (milliseconds) 206: * You can not wait forever. 207: * return value >= 0 : character code 208: * -1 : timeout 209: * input data using buffer. 210: * receive error is ignored. 211: */ 212: LOCAL W getSIO_16550(SIOCB *scb, W tmo ) 213: { 214: W sts, c = 0; 215: 216: RSDRV_PWON(); 217: 218: tmo *= 1000/20; /* convert tmo to 20 usec units */ 219: 220: /* receive as much data as possible in the receive buffer */ 221: while (scb->iptr - scb->optr < SIO_RCVBUFSZ) { 222: 223: /* is there data in FIFO? */ 224: if ( !((sts = IN(regLSTS)) & (LS_DRDY | LS_RxERR))) { 225: if (scb->iptr != scb->optr) break; /* already received */ 226: if (tmo-- <= 0) break; /* timeout */ 227: waitUsec(20); 228: continue; 229: } 230: 231: /* receive data input */ 232: if (sts & LS_DRDY) c = IN(regDATA); 233: 234: /* error check */ 235: if (sts & LS_RxERR) continue; 236: 237: /* set data to rcvbuf */ 238: scb->rcvbuf[scb->iptr++ & SIO_PTRMSK] = c; 239: } 240: 241: /* return the data in rcvbuf */ 242: return (scb->iptr == scb->optr)? 243: -1 : scb->rcvbuf[scb->optr++ & SIO_PTRMSK]; 244: } 245: 246: /* ------------------------------------------------------------------------ */ 247: 248: /* 249: * initialize serial port 250: * serial port that is supported by the initialization of CFGSIO 251: * speed communication speed (bps) 252: * initialize the serial port according to the specified parameters and set SIOCB 253: * SIOCB is given in 0-cleared state initially. 254: * Subsequent I/O operations uses the SIOCB. 255: * 256: * Only for PC/AT version 257: * if speed = 0, we use the value in biosp->siomode. 258: * But we use only the transmission speed and other settings are ignored. 259: * Efforts were made to be compatible B-right/V, but because of the ignorance of no-speed settings such as data length and stop bit length, 260: * we have reduced functionality. 261: */ 262: EXPORT ER initSIO_ns16550(SIOCB *scb, const CFGSIO *csio, W speed) 263: { 264: UH div; 265: 266: if ( (UW)csio->info >= N_DEFSIO ) return E_PAR; 267: 268: /* select the target port */ 269: scb->info = DefSIO[csio->info].iob; 270: 271: /* communicatin speed default value */ 272: div = LC_LINE_SPEED(speed); 273: 274: /* initialize serial controller */ 275: IN(regLSTS); /* clear IS_LSTS */ 276: IN(regINTS); /* clear IS_SND */ 277: IN(regMSTS); /* clear IS_MSTS */ 278: 279: OUT(regLCTL, LC_DLAB); 280: OUT(regDIVL, 0xff); /* to keep the following from happening, Div = 0 */ 281: OUT(regDIVH, div >> 8); /* communication speed */ 282: OUT(regDIVL, div & 0xff); 283: OUT(regLCTL, dtLC); /* line mode */ 284: OUT(regFCTL, dtFC_CLR); /* clear FIFO */ 285: OUT(regFCTL, dtFC); /* FIFO mode */ 286: OUT(regMCTL, dtMC); /* modem mode */ 287: OUT(regINTE, dtIM); /* interrupt mask */ 288: 289: /* I/O function default */ 290: scb->put = putSIO_16550; 291: scb->get = getSIO_16550; 292: 293: return E_OK; 294: }