BeRTOS
|
00001 00040 #include "ser_lpc2.h" 00041 00042 #include "cfg/cfg_ser.h" 00043 00044 #include <cfg/macros.h> /* for BV() */ 00045 00046 #include <cpu/power.h> /* cpu_relax() */ 00047 00048 #include <drv/ser_p.h> 00049 #include <drv/ser.h> 00050 #include <drv/vic_lpc2.h> /* vic_handler_t */ 00051 00052 #include <io/lpc23xx.h> 00053 00054 00055 /* Register offsets */ 00056 #define RBR 0x00 00057 #define THR 0x00 00058 #define DLL 0x00 00059 #define DLM 0x04 00060 #define IER 0x04 00061 #define IIR 0x08 00062 #define FCR 0x08 00063 #define LCR 0x0c 00064 #define LSR 0x14 00065 #define SCR 0x1c 00066 #define ACR 0x20 00067 #define ICR 0x24 00068 #define FDR 0x28 00069 #define TER 0x30 00070 00071 /* From the high-level serial driver */ 00072 extern struct Serial *ser_handles[SER_CNT]; 00073 00074 struct LPC2Serial 00075 { 00076 struct SerialHardware hw; 00077 bool sending; 00078 int irq; 00079 }; 00080 00081 /* Forward declaration */ 00082 static struct LPC2Serial UARTDesc[SER_CNT]; 00083 00084 struct uart_config 00085 { 00086 uint32_t base; 00087 uint32_t pconp; 00088 uint32_t pclksel0; 00089 uint32_t pclksel0_mask; 00090 uint32_t pclksel1; 00091 uint32_t pclksel1_mask; 00092 uint32_t pinsel0; 00093 uint32_t pinsel0_mask; 00094 uint32_t pinsel4; 00095 uint32_t pinsel4_mask; 00096 }; 00097 00098 /* UART registers configuration */ 00099 static const struct uart_config uart_param[] = 00100 { 00101 /* UART0 */ 00102 { 00103 .base = UART0_BASE_ADDR, 00104 .pconp = BV(3), 00105 00106 .pclksel0 = BV(6), 00107 .pclksel0_mask = BV(7) | BV(6), 00108 00109 .pclksel1 = 0, 00110 .pclksel1_mask = 0, 00111 00112 .pinsel0 = BV(6) | BV(4), 00113 .pinsel0_mask = BV(7) | BV(6) | BV(5) | BV(4), 00114 00115 .pinsel4 = 0, 00116 .pinsel4_mask = 0, 00117 }, 00118 /* UART1 */ 00119 { 00120 .base = UART1_BASE_ADDR, 00121 .pconp = BV(4), 00122 00123 .pclksel0 = BV(8), 00124 .pclksel0_mask = BV(9) | BV(8), 00125 00126 .pclksel1 = 0, 00127 .pclksel1_mask = 0, 00128 00129 .pinsel0 = 0, 00130 .pinsel0_mask = 0, 00131 00132 .pinsel4 = BV(3) | BV(1), 00133 .pinsel4_mask = BV(3) | BV(2) | BV(1) | BV(0), 00134 }, 00135 /* UART2 */ 00136 { 00137 .base = UART2_BASE_ADDR, 00138 .pconp = BV(24), 00139 00140 .pclksel0 = 0, 00141 .pclksel0_mask = 0, 00142 00143 .pclksel1 = BV(16), 00144 .pclksel1_mask = BV(17) | BV(16), 00145 00146 .pinsel0 = 0, 00147 .pinsel0_mask = 0, 00148 00149 .pinsel4 = BV(19) | BV(17), 00150 .pinsel4_mask = BV(19) | BV(18) | BV(17) | BV(16), 00151 }, 00152 /* UART3 */ 00153 { 00154 .base = UART3_BASE_ADDR, 00155 .pconp = BV(25), 00156 00157 .pclksel0 = 0, 00158 .pclksel0_mask = 0, 00159 00160 .pclksel1 = BV(18), 00161 .pclksel1_mask = BV(19) | BV(18), 00162 00163 .pinsel0 = BV(3) | BV(1), 00164 .pinsel0_mask = BV(3) | BV(2) | BV(1) | BV(0), 00165 00166 .pinsel4 = 0, 00167 .pinsel4_mask = 0, 00168 }, 00169 }; 00170 00171 static void lpc2_uartSetBaudRate(int port, unsigned long baud) 00172 { 00173 cpu_flags_t flags; 00174 00175 IRQ_SAVE_DISABLE(flags); 00176 00177 /* LCR: DLAB = 1 (enable divisor modify) */ 00178 *(reg8_t *)(uart_param[port].base + LCR) |= 0x80; 00179 /* DLL */ 00180 *(reg8_t *)(uart_param[port].base + DLL) = 00181 DIV_ROUND(CPU_FREQ, 16 * baud) & 0xFF; 00182 /* DLM */ 00183 *(reg8_t *)(uart_param[port].base + DLM) = 00184 (DIV_ROUND(CPU_FREQ, 16 * baud) >> 8) & 0xFF; 00185 *(reg32_t *)(uart_param[port].base + LCR) &= ~0x80; 00186 /* LCR: DLAB = 0 (disable divisor modify) */ 00187 *(reg8_t *)(uart_param[port].base + LCR) &= ~0x80; 00188 00189 IRQ_RESTORE(flags); 00190 } 00191 00192 static void lpc2_uartSetParity(int port, int parity) 00193 { 00194 /* Set 8-bit word, one stop bit by default */ 00195 uint32_t config = BV(1) | BV(0); 00196 00197 cpu_flags_t flags; 00198 00199 IRQ_SAVE_DISABLE(flags); 00200 00201 switch(parity) 00202 { 00203 case SER_PARITY_NONE: 00204 break; 00205 case SER_PARITY_ODD: 00206 config |= BV(3); 00207 break; 00208 case SER_PARITY_EVEN: 00209 config |= BV(4) | BV(3); 00210 break; 00211 default: 00212 ASSERT(0); 00213 IRQ_RESTORE(flags); 00214 return; 00215 } 00216 /* LCR */ 00217 *(reg8_t *)(uart_param[port].base + LCR) = config; 00218 00219 IRQ_RESTORE(flags); 00220 } 00221 00222 static void lpc2_uartPutChar(uint32_t base, uint8_t c) 00223 { 00224 reg8_t *lsr = (reg8_t *)base + LSR; 00225 reg8_t *thr = (reg8_t *)base + THR; 00226 00227 while (!(*lsr & BV(6))) 00228 cpu_relax(); 00229 *thr = c; 00230 } 00231 00232 void lpc2_uartInit(int port) 00233 { 00234 cpu_flags_t flags; 00235 00236 IRQ_SAVE_DISABLE(flags); 00237 00238 /* Power-on the device */ 00239 PCONP |= uart_param[port].pconp; 00240 /* Set UART clk to CPU_FREQ */ 00241 PCLKSEL0 &= ~uart_param[port].pclksel0_mask; 00242 PCLKSEL0 |= uart_param[port].pclksel0; 00243 PCLKSEL1 &= ~uart_param[port].pclksel1_mask; 00244 PCLKSEL1 |= uart_param[port].pclksel1; 00245 00246 /* LCR: 8bit, 1 stop bit, no parity, DLAB = 1 (enable divisor modify) */ 00247 *(reg8_t *)(uart_param[port].base + LCR) = 0x83; 00248 /* DLL */ 00249 *(reg8_t *)(uart_param[port].base + DLL) = 00250 DIV_ROUND(CPU_FREQ, 16 * CONFIG_KDEBUG_BAUDRATE) & 0xFF; 00251 /* DLM */ 00252 *(reg8_t *)(uart_param[port].base + DLM) = 00253 (DIV_ROUND(CPU_FREQ, 16 * CONFIG_KDEBUG_BAUDRATE) >> 8) & 0xFF; 00254 /* FDR */ 00255 *(reg32_t *)(uart_param[port].base + FDR) = 0x10; 00256 00257 /* Assign TX pin to UART0*/ 00258 PINSEL0 &= ~uart_param[port].pinsel0_mask; 00259 PINSEL0 |= uart_param[port].pinsel0; 00260 PINSEL4 &= ~uart_param[port].pinsel4_mask; 00261 PINSEL4 |= uart_param[port].pinsel4; 00262 /* LCR: set 8bit, 1 stop bit, no parity, DLAB = 0 (disable divisor modify) */ 00263 *(reg8_t *)(uart_param[port].base + LCR) = 0x03; 00264 00265 /* TER: Enable transmitter */ 00266 *(reg8_t *)(uart_param[port].base + TER) = BV(7); 00267 /* IER: Enable RBR interrupt */ 00268 *(reg8_t *)(uart_param[port].base + IER) = BV(0); 00269 00270 IRQ_RESTORE(flags); 00271 } 00272 00273 static bool tx_sending(struct SerialHardware *_hw) 00274 { 00275 struct LPC2Serial *hw = (struct LPC2Serial *)_hw; 00276 return hw->sending; 00277 } 00278 00279 INLINE bool lpc2_uartRxReady(int port) 00280 { 00281 /* LSR: check Receiver Data Ready (RDR) bit */ 00282 return *(reg8_t *)(uart_param[port].base + LSR) & BV(0) ? true : false; 00283 } 00284 00285 static void uart_irq_rx(int port) 00286 { 00287 struct FIFOBuffer *rxfifo = &ser_handles[port]->rxfifo; 00288 char c; 00289 00290 while (lpc2_uartRxReady(port)) 00291 { 00292 /* RBR: read a character from the Receiver Buffer Register */ 00293 c = *(reg8_t *)(uart_param[port].base + RBR); 00294 if (fifo_isfull(rxfifo)) 00295 ser_handles[port]->status |= SERRF_RXFIFOOVERRUN; 00296 else 00297 fifo_push(rxfifo, c); 00298 } 00299 } 00300 00301 INLINE bool lpc2_uartTxReady(int port) 00302 { 00303 /* LSR: check Transmitter Holding Register Empty (THRE) bit */ 00304 return *(reg8_t *)(uart_param[port].base + LSR) & BV(5) ? true : false; 00305 } 00306 00307 static void uart_irq_tx(int port) 00308 { 00309 struct FIFOBuffer *txfifo = &ser_handles[port]->txfifo; 00310 00311 while (lpc2_uartTxReady(port)) 00312 { 00313 /* 00314 * Disable TX empty interrupts if there're no more 00315 * characters to transmit. 00316 */ 00317 if (fifo_isempty(txfifo)) 00318 { 00319 /* IER: Disable THRE interrupt */ 00320 *(reg8_t *)(uart_param[port].base + IER) &= ~BV(1); 00321 UARTDesc[port].sending = false; 00322 break; 00323 } 00324 /* THR: put a character to the Transmit Holding Register */ 00325 *(reg8_t *)(uart_param[port].base + THR) = fifo_pop(txfifo); 00326 } 00327 } 00328 00329 static void uart_common_irq_handler(int port) 00330 { 00331 /* IIR: identify the interrupt source */ 00332 uint32_t status = *(reg32_t *)(uart_param[port].base + IIR) >> 1 & 0x7; 00333 00334 /* Receiver Data Ready (RDR) */ 00335 if (status == 0x02) 00336 uart_irq_rx(port); 00337 /* Transmit Holding Register Empty (THRE) */ 00338 else if (status == 0x01) 00339 uart_irq_tx(port); 00340 /* Signal the VIC we have completed the ISR */ 00341 VICVectAddr = 0; 00342 } 00343 00344 static void lpc2_uartIRQEnable(int port, vic_handler_t handler) 00345 { 00346 vic_setVector(UARTDesc[port].irq, handler); 00347 vic_enable(UARTDesc[port].irq); 00348 } 00349 00350 static void lpc2_uartIRQDisable(int port) 00351 { 00352 vic_disable(UARTDesc[port].irq); 00353 } 00354 00355 /* UART class definition */ 00356 #define UART_PORT(port) \ 00357 /* UART TX and RX buffers */ \ 00358 static unsigned char \ 00359 uart ## port ## _txbuffer[CONFIG_UART ## port ## _TXBUFSIZE]; \ 00360 static unsigned char \ 00361 uart ## port ## _rxbuffer[CONFIG_UART ## port ## _RXBUFSIZE]; \ 00362 \ 00363 /* UART interrupt handler */ \ 00364 static DECLARE_ISR(uart ## port ## _irq_handler) \ 00365 { \ 00366 uart_common_irq_handler(port); \ 00367 } \ 00368 \ 00369 /* UART public methods */ \ 00370 static void \ 00371 uart ## port ## _txStart(struct SerialHardware *_hw) \ 00372 { \ 00373 struct FIFOBuffer *txfifo = &ser_handles[port]->txfifo; \ 00374 struct LPC2Serial *hw = (struct LPC2Serial *)_hw; \ 00375 \ 00376 if (hw->sending) \ 00377 return; \ 00378 lpc2_uartPutChar(UART ## port ## _BASE_ADDR, fifo_pop(txfifo)); \ 00379 if (!fifo_isempty(txfifo)) \ 00380 { \ 00381 hw->sending = true; \ 00382 /* IER: Enable THRE interrupt */ \ 00383 *(reg8_t *)(uart_param[port].base + IER) |= BV(1); \ 00384 } \ 00385 } \ 00386 \ 00387 static void \ 00388 uart ## port ## _setbaudrate(UNUSED_ARG(struct SerialHardware *, hw), \ 00389 unsigned long baud) \ 00390 { \ 00391 lpc2_uartSetBaudRate(port, baud); \ 00392 } \ 00393 \ 00394 static void \ 00395 uart ## port ## _setparity(UNUSED_ARG(struct SerialHardware *, hw), \ 00396 int parity) \ 00397 { \ 00398 lpc2_uartSetParity(port, parity); \ 00399 } \ 00400 \ 00401 static void \ 00402 uart ## port ## _cleanup(struct SerialHardware *_hw) \ 00403 { \ 00404 struct LPC2Serial *hw = (struct LPC2Serial *)_hw; \ 00405 \ 00406 hw->sending = false; \ 00407 lpc2_uartIRQDisable(port); \ 00408 } \ 00409 \ 00410 static void \ 00411 uart ## port ## _init(UNUSED_ARG(struct SerialHardware *, hw), \ 00412 UNUSED_ARG(struct Serial *, ser)) \ 00413 { \ 00414 lpc2_uartInit(port); \ 00415 lpc2_uartIRQEnable(port, uart ## port ## _irq_handler); \ 00416 } \ 00417 \ 00418 /* UART operations */ \ 00419 static const struct SerialHardwareVT UART ## port ## _VT = \ 00420 { \ 00421 .init = uart ## port ## _init, \ 00422 .cleanup = uart ## port ## _cleanup, \ 00423 .setBaudrate = uart ## port ## _setbaudrate, \ 00424 .setParity = uart ## port ## _setparity, \ 00425 .txStart = uart ## port ## _txStart, \ 00426 .txSending = tx_sending, \ 00427 }; 00428 00429 /* UART port instances */ 00430 UART_PORT(0) 00431 UART_PORT(1) 00432 UART_PORT(2) 00433 UART_PORT(3) 00434 00435 static struct LPC2Serial UARTDesc[SER_CNT] = 00436 { 00437 { 00438 .hw = { 00439 .table = &UART0_VT, 00440 .txbuffer = uart0_txbuffer, 00441 .rxbuffer = uart0_rxbuffer, 00442 .txbuffer_size = sizeof(uart0_txbuffer), 00443 .rxbuffer_size = sizeof(uart0_rxbuffer), 00444 }, 00445 .sending = false, 00446 .irq = INT_UART0, 00447 }, 00448 { 00449 .hw = { 00450 .table = &UART1_VT, 00451 .txbuffer = uart1_txbuffer, 00452 .rxbuffer = uart1_rxbuffer, 00453 .txbuffer_size = sizeof(uart1_txbuffer), 00454 .rxbuffer_size = sizeof(uart1_rxbuffer), 00455 }, 00456 .sending = false, 00457 .irq = INT_UART1, 00458 }, 00459 { 00460 .hw = { 00461 .table = &UART2_VT, 00462 .txbuffer = uart2_txbuffer, 00463 .rxbuffer = uart2_rxbuffer, 00464 .txbuffer_size = sizeof(uart2_txbuffer), 00465 .rxbuffer_size = sizeof(uart2_rxbuffer), 00466 }, 00467 .sending = false, 00468 .irq = INT_UART2, 00469 }, 00470 { 00471 .hw = { 00472 .table = &UART3_VT, 00473 .txbuffer = uart3_txbuffer, 00474 .rxbuffer = uart3_rxbuffer, 00475 .txbuffer_size = sizeof(uart3_txbuffer), 00476 .rxbuffer_size = sizeof(uart3_rxbuffer), 00477 }, 00478 .sending = false, 00479 .irq = INT_UART3, 00480 }, 00481 }; 00482 00483 struct SerialHardware *ser_hw_getdesc(int port) 00484 { 00485 ASSERT(port >= 0 && port < SER_CNT); 00486 return &UARTDesc[port].hw; 00487 }