BeRTOS
ser_lpc2.c
Go to the documentation of this file.
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 }