summaryrefslogtreecommitdiffstats
path: root/c/src/lib/libbsp/arm/tms570/console/tms570-sci.c
diff options
context:
space:
mode:
authorPremysl Houdek <kom541000@gmail.com>2014-08-20 17:24:23 +0200
committerGedare Bloom <gedare@rtems.org>2014-08-20 13:44:23 -0400
commit4407ee675cb22e8bb870a76eafc590eb6e754315 (patch)
treeaf8b73c912e1011cd99d5c8966756c06a08bacfd /c/src/lib/libbsp/arm/tms570/console/tms570-sci.c
parentlpc24xx/lpc17xx: lpc24xx_pin_set_function() keep LPC4088 W type pin in digita... (diff)
downloadrtems-4407ee675cb22e8bb870a76eafc590eb6e754315.tar.bz2
BSP for TMS570LS31x Hercules Development Kit from TI (TMS570LS3137)
Included variants: tms570ls3137_hdk_intram - place code and data into internal SRAM tms570ls3137_hdk_sdram - place code into external SDRAM and data to SRAM tms570ls3137_hdk - variant prepared for stand-alone RTEMS aplication stored and running directly from flash. Not working yet. Chip initialization code not included in BSP. External startup generated by TI's HalCoGen was used for testing and debugging. More information about TMS570 BSP can be found at http://www.rtems.org/wiki/index.php/Tms570 Patch version 2 - most of the formatting suggestion applied. - BSP converted to use clock shell - console driver "set attributes" tested. Baudrate change working Patch version 3 - more formatting changes. - removed leftover defines and test functions Todo: refactor header files (name register fields)
Diffstat (limited to 'c/src/lib/libbsp/arm/tms570/console/tms570-sci.c')
-rw-r--r--c/src/lib/libbsp/arm/tms570/console/tms570-sci.c559
1 files changed, 559 insertions, 0 deletions
diff --git a/c/src/lib/libbsp/arm/tms570/console/tms570-sci.c b/c/src/lib/libbsp/arm/tms570/console/tms570-sci.c
new file mode 100644
index 0000000000..8aa3cafcb3
--- /dev/null
+++ b/c/src/lib/libbsp/arm/tms570/console/tms570-sci.c
@@ -0,0 +1,559 @@
+/**
+ * @file tms570-sci.c
+ *
+ * @ingroup tms570
+ *
+ * @brief Serial communication interface (SCI) functions definitions.
+ */
+
+/*
+ * Copyright (c) 2014 Premysl Houdek <kom541000@gmail.com>
+ *
+ * Google Summer of Code 2014 at
+ * Czech Technical University in Prague
+ * Zikova 1903/4
+ * 166 36 Praha 6
+ * Czech Republic
+ *
+ * Based on LPC24xx and LPC1768 BSP
+ * by embedded brains GmbH and others
+ *
+ * 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 <bspopts.h>
+#include <termios.h>
+#include <rtems/termiostypes.h>
+#include <libchip/sersupp.h>
+#include <bsp/tms570-sci.h>
+#include <bsp/tms570-sci-driver.h>
+#include <rtems/console.h>
+#include <bsp.h>
+#include <bsp/fatal.h>
+#include <bsp/irq.h>
+
+#define TMS570_SCI_BUFFER_SIZE 1
+
+/**
+ * @brief Table including all serial drivers
+ *
+ * Definitions of all serial drivers
+ */
+const tms570_sci_context driver_context_table[] = {
+ {
+ .device_name = "/dev/console",
+ .regs = &TMS570_SCI,
+ .irq = TMS570_IRQ_SCI_LEVEL_0,
+ },
+ {
+ .device_name = "/dev/ttyS1",
+ .regs = &TMS570_SCI2,
+ .irq = TMS570_IRQ_SCI2_LEVEL_0,
+ }
+};
+
+/**
+ * @brief Serial drivers init function
+ *
+ * Initialize all serial drivers specified in driver_context_table
+ *
+ * @param[in] major
+ * @param[in] minor
+ * @param[in] arg
+ * @retval RTEMS_SUCCESSFUL Initialization completed
+ */
+rtems_device_driver console_initialize(
+ rtems_device_major_number major,
+ rtems_device_minor_number minor,
+ void *arg
+)
+{
+ rtems_status_code sc;
+#if CONSOLE_USE_INTERRUPTS
+ const rtems_termios_device_handler *handler = &tms570_sci_handler_interrupt;
+#else
+ const rtems_termios_device_handler *handler = &tms570_sci_handler_polled;
+#endif
+
+ /*
+ * Initialize the Termios infrastructure. If Termios has already
+ * been initialized by another device driver, then this call will
+ * have no effect.
+ */
+ rtems_termios_initialize();
+
+ /* Initialize each device */
+ for (
+ minor = 0;
+ minor < RTEMS_ARRAY_SIZE(driver_context_table);
+ ++minor
+ ) {
+ const tms570_sci_context *ctx = &driver_context_table[minor];
+
+ /*
+ * Install this device in the file system and Termios. In order
+ * to use the console (i.e. being able to do printf, scanf etc.
+ * on stdin, stdout and stderr), one device must be registered as
+ * "/dev/console" (CONSOLE_DEVICE_NAME).
+ */
+ sc = rtems_termios_device_install(
+ ctx->device_name,
+ major,
+ minor,
+ handler,
+ (void *) ctx
+ );
+ if ( sc != RTEMS_SUCCESSFUL ) {
+ bsp_fatal(BSP_FATAL_CONSOLE_NO_DEV);
+ }
+ }
+ return RTEMS_SUCCESSFUL;
+}
+
+/**
+ * @brief Reads chars from HW
+ *
+ * Reads chars from HW peripheral specified in driver context.
+ * TMS570 does not have HW buffer for serial line so this function can
+ * return only 0 or 1 char
+ *
+ * @param[in] ctx context of the driver
+ * @param[out] buf read data buffer
+ * @param[in] N size of buffer
+ * @retval x Number of read chars from peripherals
+ */
+static int tms570_sci_read_received_chars(
+ tms570_sci_context * ctx,
+ char * buf,
+ int N)
+{
+ if ( N < 1 ) {
+ return 0;
+ }
+ if ( ctx->regs->SCIRD != 0 ) {
+ buf[0] = ctx->regs->SCIRD;
+ return 1;
+ }
+ return 0;
+}
+
+/**
+ * @brief Enables RX interrupt
+ *
+ * Enables RX interrupt source of SCI peripheral
+ * specified in the driver context.
+ *
+ * @param[in] ctx context of the driver
+ * @retval Void
+ */
+static void tms570_sci_enable_interrupts(tms570_sci_context * ctx)
+{
+ ctx->regs->SCISETINT = (1<<9);
+}
+
+/**
+ * @brief Disables RX interrupt
+ *
+ * Disables RX interrupt source of SCI peripheral specified in the driver
+ * context.
+ *
+ * @param[in] ctx context of the driver
+ * @retval Void
+ */
+static void tms570_sci_disable_interrupts(tms570_sci_context * ctx)
+{
+ ctx->regs->SCICLEARINT = (1<<9);
+}
+
+/**
+ * @brief Check whether driver has put char in HW
+ *
+ * Check whether driver has put char in HW.
+ * This information is read from the driver context not from a peripheral.
+ * TMS570 does not have write data buffer asociated with SCI
+ * so the return can be only 0 or 1.
+ *
+ * @param[in] ctx context of the driver
+ * @retval x
+ */
+static int tms570_sci_transmitted_chars(tms570_sci_context * ctx)
+{
+ int ret;
+
+ ret = ctx->tx_chars_in_hw;
+ if ( ret == 1 ) {
+ ctx->tx_chars_in_hw = 0;
+ return 1;
+ }
+ return ret;
+}
+
+/**
+ * @brief Set attributes of the HW peripheral
+ *
+ * Sets attributes of the HW peripheral (parity, baud rate, etc.)
+ *
+ * @param[in] tty rtems_termios_tty
+ * @param[in] t termios driver
+ * @retval true peripheral setting is changed
+ */
+static bool tms570_sci_set_attributes(
+ rtems_termios_tty *tty,
+ const struct termios *t
+)
+{
+ tms570_sci_context *ctx = rtems_termios_get_device_context(tty);
+ rtems_interrupt_lock_context lock_context;
+ int32_t bauddiv;
+ int32_t baudrate;
+
+ rtems_termios_interrupt_lock_acquire(tty, &lock_context);
+
+ ctx->regs->SCIGCR1 &= ~( (1<<7) | (1<<25) | (1<<24) );
+
+ ctx->regs->SCIGCR1 &= ~(1<<4); /*one stop bit*/
+ ctx->regs->SCIFORMAT = 0x7;
+
+ switch ( t->c_cflag & ( PARENB|PARODD ) ) {
+ case ( PARENB|PARODD ):
+ /* Odd parity */
+ ctx->regs->SCIGCR1 &= ~(1<<3);
+ ctx->regs->SCIGCR1 |= (1<<2);
+ break;
+
+ case PARENB:
+ /* Even parity */
+ ctx->regs->SCIGCR1 |= (1<<3);
+ ctx->regs->SCIGCR1 |= (1<<2);
+ break;
+
+ default:
+ case 0:
+ case PARODD:
+ /* No Parity */
+ ctx->regs->SCIGCR1 &= ~(1<<2);
+ }
+
+ /* Baud rate */
+ baudrate = rtems_termios_baud_to_number(cfgetospeed(t));
+ baudrate *= 2 * 16;
+ bauddiv = (BSP_PLL_OUT_CLOCK + baudrate / 2) / baudrate;
+ ctx->regs->BRS = bauddiv;
+
+ ctx->regs->SCIGCR1 |= (1<<7) | (1<<25) | (1<<24);
+
+ rtems_termios_interrupt_lock_release(tty, &lock_context);
+
+ return true;
+}
+
+/**
+ * @brief sci interrupt handler
+ *
+ * Handler checks which interrupt occured and provides nessesary maintenance
+ * dequeue characters in termios driver whether character is send succesfully
+ * enqueue characters in termios driver whether character is recieved
+ *
+ * @param[in] arg rtems_termios_tty
+ * @retval Void
+ */
+static void tms570_sci_interrupt_handler(void * arg)
+{
+ rtems_termios_tty *tty = arg;
+ tms570_sci_context *ctx = rtems_termios_get_device_context(tty);
+ char buf[TMS570_SCI_BUFFER_SIZE];
+ size_t n;
+
+ /*
+ * Check if we have received something.
+ */
+ if ( (ctx->regs->SCIFLR & (1<<9) ) == (1<<9) ) {
+ n = tms570_sci_read_received_chars(ctx, buf, TMS570_SCI_BUFFER_SIZE);
+ if ( n > 0 ) {
+ /* Hand the data over to the Termios infrastructure */
+ rtems_termios_enqueue_raw_characters(tty, buf, n);
+ }
+ }
+ /*
+ * Check if we have something transmitted.
+ */
+ if ( (ctx->regs->SCIFLR & (1<<8) ) == (1<<8) ) {
+ n = tms570_sci_transmitted_chars(ctx);
+ if ( n > 0 ) {
+ /*
+ * Notify Termios that we have transmitted some characters. It
+ * will call now the interrupt write function if more characters
+ * are ready for transmission.
+ */
+ rtems_termios_dequeue_characters(tty, n);
+ }
+ }
+}
+
+/**
+ * @brief sci write function called from interrupt
+ *
+ * Nonblocking write function. Writes characters to HW peripheral
+ * TMS570 does not have write data buffer asociated with SCI
+ * so only one character can be written.
+ *
+ * @param[in] tty rtems_termios_tty
+ * @param[in] buf buffer of characters pending to send
+ * @param[in] len size of the buffer
+ * @retval Void
+ */
+static void tms570_sci_interrupt_write(
+ rtems_termios_tty *tty,
+ const char *buf,
+ size_t len
+)
+{
+ tms570_sci_context *ctx = rtems_termios_get_device_context(tty);
+
+ if ( len > 0 ) {
+ /* start UART TX, this will result in an interrupt when done */
+ ctx->regs->SCITD = *buf;
+ /* character written - raise count*/
+ ctx->tx_chars_in_hw = 1;
+ /* Enable TX interrupt (interrupt is edge-triggered) */
+ ctx->regs->SCISETINT = (1<<8);
+
+ } else {
+ /* No more to send, disable TX interrupts */
+ ctx->regs->SCICLEARINT = (1<<8);
+ /* Tell close that we sent everything */
+ }
+}
+
+/**
+ * @brief sci write function
+ *
+ * Blocking write function. Waits until HW peripheral is ready and then writes
+ * character to HW peripheral. Writes all characters in the buffer.
+ *
+ * @param[in] tty rtems_termios_tty
+ * @param[in] buf buffer of characters pending to send
+ * @param[in] len size of the buffer
+ * @retval Void
+ */
+static void tms570_sci_poll_write(
+ rtems_termios_tty *tty,
+ const char *buf,
+ size_t n
+)
+{
+ tms570_sci_context *ctx = rtems_termios_get_device_context(tty);
+ size_t i;
+
+ /* Write */
+
+ for ( i = 0; i < n; ++i ) {
+ while ( (ctx->regs->SCIFLR & (1<<11) ) == 0) {
+ ;
+ }
+ ctx->regs->SCITD = buf[i];
+ }
+}
+
+/**
+ * @brief See if there is recieved charakter to read
+ *
+ * read the RX flag from peripheral specified in context
+ *
+ * @param[in] ctx context of the driver
+ * @retval 0 No character to read
+ * @retval x Character ready to read
+ */
+static int TMS570_sci_can_read_char(
+ tms570_sci_context * ctx
+)
+{
+ return ctx->regs->SCIFLR & (1<<9);
+}
+
+/**
+ * @brief reads character from peripheral
+ *
+ * reads the recieved character from peripheral specified in context
+ *
+ * @param[in] ctx context of the driver
+ * @retval x Character
+ */
+static char TMS570_sci_read_char(
+ tms570_sci_context * ctx
+)
+{
+ return ctx->regs->SCIRD;
+}
+
+/**
+ * @brief sci read function
+ *
+ * check if there is recieved character to be read and reads it.
+ *
+ * @param[in] tty rtems_termios_tty (context of the driver)
+ * @retval -1 No character to be read
+ * @retval x Read character
+ */
+static int tms570_sci_poll_read(rtems_termios_tty *tty)
+{
+ tms570_sci_context *ctx = rtems_termios_get_device_context(tty);
+
+ /* Check if a character is available */
+ if ( TMS570_sci_can_read_char(ctx) ) {
+ return TMS570_sci_read_char(ctx);
+ } else {
+ return -1;
+ }
+}
+
+/**
+ * @brief initialization of the driver
+ *
+ * initialization of the HW peripheral specified in contex of the driver.
+ * This function is called only once when opening the driver.
+ *
+ * @param[in] tty context of the driver
+ * @param[in] args
+ * @retval false Error occured during initialization
+ * @retval true Driver is open and ready
+ */
+static bool tms570_sci_poll_first_open(
+ rtems_termios_tty *tty,
+ rtems_libio_open_close_args_t *args
+)
+{
+ bool ok;
+
+ rtems_termios_set_best_baud(tty, TMS570_SCI_BAUD_RATE);
+ ok = tms570_sci_set_attributes(tty, rtems_termios_get_termios(tty));
+ if ( !ok ) {
+ return false;
+ }
+ return true;
+}
+
+/**
+ * @brief initialization of the interrupt driven driver
+ *
+ * calls tms570_sci_poll_first_open function.
+ * install and enables interrupts.
+ *
+ * @param[in] tty context of the driver
+ * @param[in] args
+ * @retval false Error occured during initialization
+ * @retval true Driver is open and ready
+ */
+static bool tms570_sci_interrupt_first_open(
+ rtems_termios_tty *tty,
+ rtems_libio_open_close_args_t *args
+)
+{
+ tms570_sci_context *ctx = rtems_termios_get_device_context(tty);
+ rtems_status_code sc;
+ bool ret;
+
+ ret = tms570_sci_poll_first_open(tty,args);
+ if ( ret == false ) {
+ return false;
+ }
+ ctx->regs->SCISETINTLVL = 0;
+ /* Register Interrupt handler */
+ sc = rtems_interrupt_handler_install(ctx->irq,
+ ctx->device_name,
+ RTEMS_INTERRUPT_SHARED,
+ tms570_sci_interrupt_handler,
+ tty
+ );
+ if ( sc != RTEMS_SUCCESSFUL ) {
+ return false;
+ }
+ tms570_sci_enable_interrupts(rtems_termios_get_device_context(tty));
+ return true;
+}
+
+/**
+ * @brief closes sci peripheral
+ *
+ * @param[in] tty context of the driver
+ * @param[in] args
+ * @retval false Error occured during initialization
+ * @retval true Driver is open and ready
+ */
+static void tms570_sci_poll_last_close(
+ rtems_termios_tty *tty,
+ rtems_libio_open_close_args_t *args
+)
+{
+ ;
+}
+
+/**
+ * @brief closes sci peripheral of interrupt driven driver
+ *
+ * calls tms570_sci_poll_last_close and disables interrupts
+ *
+ * @param[in] tty context of the driver
+ * @param[in] args
+ * @retval false Error occured during initialization
+ * @retval true Driver is open and ready
+ */
+static void tms570_sci_interrupt_last_close(
+ rtems_termios_tty *tty,
+ rtems_libio_open_close_args_t *args
+)
+{
+ tms570_sci_context *ctx = rtems_termios_get_device_context(tty);
+ rtems_interrupt_lock_context lock_context;
+
+ /* Turn off RX interrupts */
+ rtems_termios_interrupt_lock_acquire(tty, &lock_context);
+ tms570_sci_disable_interrupts(ctx);
+ rtems_termios_interrupt_lock_release(tty, &lock_context);
+
+ /* Flush device */
+ while ( ( ctx->regs->SCIFLR & (1<<11) ) > 0 ) {
+ ;/* Wait until all data has been sent */
+ }
+
+ /* uninstall ISR */
+ rtems_interrupt_handler_remove(ctx->irq, tms570_sci_interrupt_handler, tty);
+
+ tms570_sci_poll_last_close(tty,args);
+}
+
+/**
+ * @brief Struct containing definitions of polled driver functions.
+ *
+ * Encapsulates polled driver functions.
+ * Use of this table is determited by not defining TMS570_USE_INTERRUPTS
+ */
+const rtems_termios_device_handler tms570_sci_handler_polled = {
+ .first_open = tms570_sci_poll_first_open,
+ .last_close = tms570_sci_poll_last_close,
+ .poll_read = tms570_sci_poll_read,
+ .write = tms570_sci_poll_write,
+ .set_attributes = tms570_sci_set_attributes,
+ .stop_remote_tx = NULL,
+ .start_remote_tx = NULL,
+ .mode = TERMIOS_POLLED
+};
+
+/**
+ * @brief Struct containing definitions of interrupt driven driver functions.
+ *
+ * Encapsulates interrupt driven driver functions.
+ * Use of this table is determited by defining TMS570_USE_INTERRUPTS
+ */
+const rtems_termios_device_handler tms570_sci_handler_interrupt = {
+ .first_open = tms570_sci_interrupt_first_open,
+ .last_close = tms570_sci_interrupt_last_close,
+ .poll_read = NULL,
+ .write = tms570_sci_interrupt_write,
+ .set_attributes = tms570_sci_set_attributes,
+ .stop_remote_tx = NULL,
+ .start_remote_tx = NULL,
+ .mode = TERMIOS_IRQ_DRIVEN
+};