diff options
Diffstat (limited to 'c/src/lib/libcpu/bfin/serial/uart.c')
-rw-r--r-- | c/src/lib/libcpu/bfin/serial/uart.c | 528 |
1 files changed, 0 insertions, 528 deletions
diff --git a/c/src/lib/libcpu/bfin/serial/uart.c b/c/src/lib/libcpu/bfin/serial/uart.c deleted file mode 100644 index 18a522e121..0000000000 --- a/c/src/lib/libcpu/bfin/serial/uart.c +++ /dev/null @@ -1,528 +0,0 @@ -/* UART driver for Blackfin - */ - -/* - * Copyright (c) 2008 Kallisti Labs, Los Gatos, CA, USA - * written by Allan Hessenflow <allanh@kallisti.com> - * - * The license and distribution terms for this file may be - * found in the file LICENSE in this distribution or at - * http://www.rtems.org/license/LICENSE. - */ - -#include <rtems.h> -#include <rtems/libio.h> -#include <rtems/termiostypes.h> -#include <termios.h> -#include <stdlib.h> - -#include <libcpu/uartRegs.h> -#include <libcpu/dmaRegs.h> -#include <libcpu/uart.h> - -/* flags */ -#define BFIN_UART_XMIT_BUSY 0x01 - -static bfin_uart_config_t *uartsConfig; - -static int pollRead(int minor) -{ - int c; - uint32_t base; - - base = uartsConfig->channels[minor].uart_baseAddress; - - /* check to see if driver is using interrupts so this call will be - harmless (though non-functional) in case some debug code tries to - use it */ - if (!uartsConfig->channels[minor].uart_useInterrupts && - *((uint16_t volatile *) (base + UART_LSR_OFFSET)) & UART_LSR_DR) - c = *((uint16_t volatile *) (base + UART_RBR_OFFSET)); - else - c = -1; - - return c; -} - -char bfin_uart_poll_read(rtems_device_minor_number minor) -{ - int c; - - do { - c = pollRead(minor); - } while (c == -1); - - return c; -} - -void bfin_uart_poll_write(int minor, char c) -{ - uint32_t base; - - base = uartsConfig->channels[minor].uart_baseAddress; - - while (!(*((uint16_t volatile *) (base + UART_LSR_OFFSET)) & UART_LSR_THRE)) - ; - *(uint16_t volatile *) (base + UART_THR_OFFSET) = c; -} - -/* - * Console Termios Support Entry Points - * - */ - -static ssize_t pollWrite(int minor, const char *buf, size_t len) -{ - size_t count; - for ( count = 0; count < len; count++ ) - bfin_uart_poll_write(minor, *buf++); - - return count; -} - -/** - * Routine to initialize the hardware. It initialize the DMA, - * interrupt if required. - * @param channel channel information - */ -static void initializeHardware(bfin_uart_channel_t *channel) -{ - uint16_t divisor = 0; - uint32_t base = 0; - uint32_t tx_dma_base = 0; - - if ( NULL == channel ) { - return; - } - - base = channel->uart_baseAddress; - tx_dma_base = channel->uart_txDmaBaseAddress; - /** - * RX based DMA and interrupt is not supported yet - * uint32_t tx_dma_base = 0; - * - * rx_dma_base = channel->uart_rxDmaBaseAddress; - */ - - - *(uint16_t volatile *) (base + UART_IER_OFFSET) = 0; - - if ( 0 != channel->uart_baud) { - divisor = (uint16_t) (uartsConfig->freq / - (channel->uart_baud * 16)); - } else { - divisor = (uint16_t) (uartsConfig->freq / (9600 * 16)); - } - - *(uint16_t volatile *) (base + UART_LCR_OFFSET) = UART_LCR_DLAB; - *(uint16_t volatile *) (base + UART_DLL_OFFSET) = (divisor & 0xff); - *(uint16_t volatile *) (base + UART_DLH_OFFSET) = ((divisor >> 8) & 0xff); - - *(uint16_t volatile *) (base + UART_LCR_OFFSET) = UART_LCR_WLS_8; - - *(uint16_t volatile *) (base + UART_GCTL_OFFSET) = UART_GCTL_UCEN; - - /** - * To clear previous status - * divisor is a temp variable here - */ - divisor = *(uint16_t volatile *) (base + UART_LSR_OFFSET); - divisor = *(uint16_t volatile *) (base + UART_RBR_OFFSET); - divisor = *(uint16_t volatile *) (base + UART_IIR_OFFSET); - - if ( channel->uart_useDma ) { - *(uint16_t volatile *)(tx_dma_base + DMA_CONFIG_OFFSET) = 0; - *(uint16_t volatile *)(tx_dma_base + DMA_CONFIG_OFFSET) = DMA_CONFIG_DI_EN - | DMA_CONFIG_SYNC ; - *(uint16_t volatile *)(tx_dma_base + DMA_IRQ_STATUS_OFFSET) |= - DMA_IRQ_STATUS_DMA_DONE | DMA_IRQ_STATUS_DMA_ERR; - - } else { - /** - * We use polling or interrupts only sending one char at a time :( - */ - } -} - - -/** - * Set the UART attributes. - * @param minor - * @param termios - * @return - */ -static int setAttributes(int minor, const struct termios *termios) -{ - uint32_t base; - int baud; - uint16_t divisor; - uint16_t lcr; - - base = uartsConfig->channels[minor].uart_baseAddress; - switch (termios->c_ospeed) { - case B0: baud = 0; break; - case B50: baud = 50; break; - case B75: baud = 75; break; - case B110: baud = 110; break; - case B134: baud = 134; break; - case B150: baud = 150; break; - case B200: baud = 200; break; - case B300: baud = 300; break; - case B600: baud = 600; break; - case B1200: baud = 1200; break; - case B1800: baud = 1800; break; - case B2400: baud = 2400; break; - case B4800: baud = 4800; break; - case B9600: baud = 9600; break; - case B19200: baud = 19200; break; - case B38400: baud = 38400; break; - case B57600: baud = 57600; break; - case B115200: baud = 115200; break; - case B230400: baud = 230400; break; - case B460800: baud = 460800; break; - default: baud = -1; break; - } - if (baud > 0 && uartsConfig->channels[minor].uart_baud) - baud = uartsConfig->channels[minor].uart_baud; - switch (termios->c_cflag & CSIZE) { - case CS5: lcr = UART_LCR_WLS_5; break; - case CS6: lcr = UART_LCR_WLS_6; break; - case CS7: lcr = UART_LCR_WLS_7; break; - default: - case CS8: lcr = UART_LCR_WLS_8; break; - } - switch (termios->c_cflag & (PARENB | PARODD)) { - case PARENB: - lcr |= UART_LCR_PEN | UART_LCR_EPS; - break; - case PARENB | PARODD: - lcr |= UART_LCR_PEN; - break; - default: - break; - } - if (termios->c_cflag & CSTOPB) - lcr |= UART_LCR_STB; - - if (baud > 0) { - divisor = (uint16_t) (uartsConfig->freq / (baud * 16)); - *(uint16_t volatile *) (base + UART_LCR_OFFSET) = lcr | UART_LCR_DLAB; - *(uint16_t volatile *) (base + UART_DLL_OFFSET) = (divisor & 0xff); - *(uint16_t volatile *) (base + UART_DLH_OFFSET) = ((divisor >> 8) & 0xff); - } - *(uint16_t volatile *) (base + UART_LCR_OFFSET) = lcr; - - return 0; -} - -/** - * Interrupt based uart tx routine. The routine writes one character at a time. - * - * @param minor Minor number to indicate uart number - * @param buf Character buffer which stores characters to be transmitted. - * @param len Length of buffer to be transmitted. - * @return - */ -static ssize_t uart_interruptWrite(int minor, const char *buf, size_t len) -{ - uint32_t base = 0; - bfin_uart_channel_t* channel = NULL; - - /** - * Sanity Check - */ - if ( - NULL == buf || NULL == channel || NULL == uartsConfig - || minor < 0 || 0 == len - ) { - return 0; - } - - channel = &(uartsConfig->channels[minor]); - - if ( NULL == channel || channel->flags & BFIN_UART_XMIT_BUSY ) { - return 0; - } - - base = channel->uart_baseAddress; - - channel->flags |= BFIN_UART_XMIT_BUSY; - channel->length = 1; - *(uint16_t volatile *) (base + UART_THR_OFFSET) = *buf; - *(uint16_t volatile *) (base + UART_IER_OFFSET) = UART_IER_ETBEI; - - return 0; -} - -/** - * This function implements RX ISR - */ -void bfinUart_rxIsr(void *_arg) -{ - /** - * TODO: UART RX ISR implementation. - */ -} - -/** - * This function implements TX ISR. The function gets called when the TX FIFO is - * empty. It clears the interrupt and dequeues the character. It only tx one - * character at a time. - * - * TODO: error handling. - * @param _arg gets the channel information. - */ -void bfinUart_txIsr(void *_arg) -{ - bfin_uart_channel_t* channel = NULL; - uint32_t base = 0; - - /** - * Sanity check - */ - if (NULL == _arg) { - /** It should never be NULL */ - return; - } - - channel = (bfin_uart_channel_t *) _arg; - - base = channel->uart_baseAddress; - - *(uint16_t volatile *) (base + UART_IER_OFFSET) &= ~UART_IER_ETBEI; - channel->flags &= ~BFIN_UART_XMIT_BUSY; - - rtems_termios_dequeue_characters(channel->termios, channel->length); -} - -/** - * interrupt based DMA write Routine. It configure the DMA to write len bytes. - * The DMA supports 64K data only. - * - * @param minor Identification number of the UART. - * @param buf Character buffer pointer - * @param len length of data items to be written - * @return data already written - */ -static ssize_t uart_DmaWrite(int minor, const char *buf, size_t len) -{ - uint32_t base = 0; - bfin_uart_channel_t* channel = NULL; - uint32_t tx_dma_base = 0; - - /** - * Sanity Check - */ - if ( NULL == buf || 0 > minor || NULL == uartsConfig || 0 == len ) { - return 0; - } - - channel = &(uartsConfig->channels[minor]); - - /** - * Sanity Check and check for transmit busy. - */ - if ( NULL == channel || BFIN_UART_XMIT_BUSY & channel->flags ) { - return 0; - } - - base = channel->uart_baseAddress; - tx_dma_base = channel->uart_txDmaBaseAddress; - - channel->flags |= BFIN_UART_XMIT_BUSY; - channel->length = len; - - *(uint16_t volatile *) (tx_dma_base + DMA_CONFIG_OFFSET) &= ~DMA_CONFIG_DMAEN; - *(uint32_t volatile *) (tx_dma_base + DMA_START_ADDR_OFFSET) = (uint32_t)buf; - *(uint16_t volatile *) (tx_dma_base + DMA_X_COUNT_OFFSET) = channel->length; - *(uint16_t volatile *) (tx_dma_base + DMA_X_MODIFY_OFFSET) = 1; - *(uint16_t volatile *) (tx_dma_base + DMA_CONFIG_OFFSET) |= DMA_CONFIG_DMAEN; - *(uint16_t volatile *) (base + UART_IER_OFFSET) = UART_IER_ETBEI; - - return 0; -} - -/** - * RX DMA ISR. - * The polling route is used for receiving the characters. This is a place - * holder for future implementation. - * @param _arg - */ -void bfinUart_rxDmaIsr(void *_arg) -{ -/** - * TODO: Implementation of RX DMA - */ -} - -/** - * This function implements TX dma ISR. It clears the IRQ and dequeues a char - * The channel argument will have the base address. Since there are two uart - * and both the uarts can use the same tx dma isr. - * - * TODO: 1. Error checking 2. sending correct length ie after looking at the - * number of elements the uart transmitted. - * - * @param _arg argument passed to the interrupt handler. It contains the - * channel argument. - */ -void bfinUart_txDmaIsr(void *_arg) -{ - bfin_uart_channel_t* channel = NULL; - uint32_t tx_dma_base = 0; - - /** - * Sanity check - */ - if (NULL == _arg) { - /** It should never be NULL */ - return; - } - - channel = (bfin_uart_channel_t *) _arg; - - tx_dma_base = channel->uart_txDmaBaseAddress; - - if ((*(uint16_t volatile *) (tx_dma_base + DMA_IRQ_STATUS_OFFSET) - & DMA_IRQ_STATUS_DMA_DONE)) { - - *(uint16_t volatile *) (tx_dma_base + DMA_IRQ_STATUS_OFFSET) - |= DMA_IRQ_STATUS_DMA_DONE | DMA_IRQ_STATUS_DMA_ERR; - channel->flags &= ~BFIN_UART_XMIT_BUSY; - rtems_termios_dequeue_characters(channel->termios, channel->length); - } else { - /* UART DMA did not generate interrupt. - * This routine must not be called. - */ - } -} - -/** - * Function called during exit - */ -static void uart_exit(void) -{ - /** - * TODO: Flushing of quques - */ -} - -/** - * Opens the device in different modes. The supported modes are - * 1. Polling - * 2. Interrupt - * 3. DMA - * At exit the uart_Exit function will be called to flush the device. - * - * @param major Major number of the device - * @param minor Minor number of the device - * @param arg - * @return - */ -rtems_device_driver bfin_uart_open(rtems_device_major_number major, - rtems_device_minor_number minor, void *arg) { - rtems_status_code sc = RTEMS_NOT_DEFINED; - rtems_libio_open_close_args_t *args = NULL; - - /** - * Callback function for polling - */ - static const rtems_termios_callbacks pollCallbacks = { - NULL, /* firstOpen */ - NULL, /* lastClose */ - pollRead, /* pollRead */ - pollWrite, /* write */ - setAttributes, /* setAttributes */ - NULL, /* stopRemoteTx */ - NULL, /* startRemoteTx */ - TERMIOS_POLLED /* outputUsesInterrupts */ - }; - - /** - * Callback function for interrupt based transfers without DMA. - * We use interrupts for writing only. For reading we use polling. - */ - static const rtems_termios_callbacks interruptCallbacks = { - NULL, /* firstOpen */ - NULL, /* lastClose */ - pollRead, /* pollRead */ - uart_interruptWrite, /* write */ - setAttributes, /* setAttributes */ - NULL, /* stopRemoteTx */ - NULL, /* startRemoteTx */ - TERMIOS_IRQ_DRIVEN /* outputUsesInterrupts */ - }; - - /** - * Callback function for interrupt based DMA transfers. - * We use interrupts for writing only. For reading we use polling. - */ - static const rtems_termios_callbacks interruptDmaCallbacks = { - NULL, /* firstOpen */ - NULL, /* lastClose */ - NULL, /* pollRead */ - uart_DmaWrite, /* write */ - setAttributes, /* setAttributes */ - NULL, /* stopRemoteTx */ - NULL, /* startRemoteTx */ - TERMIOS_IRQ_DRIVEN /* outputUsesInterrupts */ - }; - - if ( NULL == uartsConfig || 0 > minor || minor >= uartsConfig->num_channels) { - return RTEMS_INVALID_NUMBER; - } - - /** - * Opens device for handling uart send request either by - * 1. interrupt with DMA - * 2. interrupt based - * 3. Polling - */ - if ( uartsConfig->channels[minor].uart_useDma ) { - sc = rtems_termios_open(major, minor, arg, &interruptDmaCallbacks); - } else { - sc = rtems_termios_open(major, minor, arg, - uartsConfig->channels[minor].uart_useInterrupts ? - &interruptCallbacks : &pollCallbacks); - } - - args = arg; - uartsConfig->channels[minor].termios = args->iop->data1; - - atexit(uart_exit); - - return sc; -} - -/** -* Uart initialization function. -* @param major major number of the device -* @param config configuration parameters -* @return rtems status code -*/ -rtems_status_code bfin_uart_initialize( - rtems_device_major_number major, - bfin_uart_config_t *config -) -{ - rtems_status_code sc = RTEMS_NOT_DEFINED; - int i = 0; - - rtems_termios_initialize(); - - /* - * Register Device Names - */ - uartsConfig = config; - for (i = 0; i < config->num_channels; i++) { - config->channels[i].termios = NULL; - config->channels[i].flags = 0; - initializeHardware(&(config->channels[i])); - sc = rtems_io_register_name(config->channels[i].name, major, i); - if (RTEMS_SUCCESSFUL != sc) { - return sc; - } - } - - return sc; -} |