diff options
author | Daniel Hellstrom <daniel@gaisler.com> | 2012-04-19 15:46:10 +0200 |
---|---|---|
committer | Gedare Bloom <gedare@rtems.org> | 2012-04-19 12:34:21 -0400 |
commit | 62694fd68fd8b3cd71cea9d3a2541edb7b9b91bb (patch) | |
tree | be0be07b4b65d3b9faf9fbe95d98e4bb417c7ee2 /c | |
parent | LEON3: add console attributes such as parity and baudrate (diff) | |
download | rtems-62694fd68fd8b3cd71cea9d3a2541edb7b9b91bb.tar.bz2 |
LEON3: add console interrupt mode support
The comment in configure.ac is probably inherited from the LEON2
BSP. The LEON3 console driver implements a "flush" mechanism on
console_close() in order to solve the problem described with
sis/LEON2.
Signed-off-by: Daniel Hellstrom <daniel@gaisler.com>
Diffstat (limited to 'c')
-rw-r--r-- | c/src/lib/libbsp/sparc/leon3/configure.ac | 5 | ||||
-rw-r--r-- | c/src/lib/libbsp/sparc/leon3/console/console.c | 171 |
2 files changed, 153 insertions, 23 deletions
diff --git a/c/src/lib/libbsp/sparc/leon3/configure.ac b/c/src/lib/libbsp/sparc/leon3/configure.ac index 6d86386101..3f2d445e92 100644 --- a/c/src/lib/libbsp/sparc/leon3/configure.ac +++ b/c/src/lib/libbsp/sparc/leon3/configure.ac @@ -26,10 +26,7 @@ RTEMS_BSPOPTS_SET([CONSOLE_USE_INTERRUPTS],[*],[0]) RTEMS_BSPOPTS_HELP([CONSOLE_USE_INTERRUPTS], [The leon3 console driver can operate in either polled or interrupt mode. Under the simulator (especially when FAST_UART is defined), polled seems to operate -better. It is common for a task to print a line (like the end of test message) and -then exit. In this case, the program returns control to the simulator command line -before the program has even queued the output to the uart. Thus sis has no chance -of getting the data out.]) +better.]) RTEMS_BSPOPTS_SET([SIMSPARC_FAST_IDLE],[*],[]) RTEMS_BSPOPTS_HELP([SIMSPARC_FAST_IDLE], diff --git a/c/src/lib/libbsp/sparc/leon3/console/console.c b/c/src/lib/libbsp/sparc/leon3/console/console.c index 45ec82eff5..f286a6867c 100644 --- a/c/src/lib/libbsp/sparc/leon3/console/console.c +++ b/c/src/lib/libbsp/sparc/leon3/console/console.c @@ -15,6 +15,17 @@ * http://www.rtems.com/license/LICENSE. */ +/* Define CONSOLE_USE_INTERRUPTS to enable APBUART interrupt handling instead + * of polling mode. + * + * Note that it is not possible to use the interrupt mode of the driver + * together with the "old" APBUART and -u to GRMON. However the new + * APBUART core (from GRLIB 1.0.17-b2710) has the GRMON debug bit and can + * handle interrupts. + * + * NOTE: This can be defined in the make/custom/leon3.cfg file. + */ + #include <bsp.h> #include <rtems/libio.h> #include <stdlib.h> @@ -32,12 +43,6 @@ int syscon_uart_index __attribute__((weak)) = 0; /* - * Should we use a polled or interrupt drived console? - * - * NOTE: This is defined in the custom/leon.cfg file. - */ - -/* * apbuart_outbyte_polled * * This routine transmits a character using polling. @@ -63,16 +68,85 @@ extern int apbuart_inbyte_nonblocking(ambapp_apb_uart *regs); struct apbuart_priv { ambapp_apb_uart *regs; unsigned int freq_hz; +#if CONSOLE_USE_INTERRUPTS + int irq; + void *cookie; + volatile int sending; + char *buf; +#endif }; static struct apbuart_priv apbuarts[BSP_NUMBER_OF_TERMIOS_PORTS]; static int uarts = 0; +#if CONSOLE_USE_INTERRUPTS + +/* Handle UART interrupts */ +void console_isr(void *arg) +{ + struct apbuart_priv *uart = arg; + unsigned int status; + char data; + + /* Get all received characters */ + while ((status=uart->regs->status) & LEON_REG_UART_STATUS_DR) { + /* Data has arrived, get new data */ + data = uart->regs->data; + + /* Tell termios layer about new character */ + rtems_termios_enqueue_raw_characters(uart->cookie, &data, 1); + } + + if (status & LEON_REG_UART_STATUS_THE) { + /* Sent the one char, we disable TX interrupts */ + uart->regs->ctrl &= ~LEON_REG_UART_CTRL_TI; + + /* Tell close that we sent everything */ + uart->sending = 0; + + /* write_interrupt will get called from this function */ + rtems_termios_dequeue_characters(uart->cookie, 1); + } +} + +/* + * Console Termios Write-Buffer Support Entry Point + * + */ +int console_write_interrupt(int minor, const char *buf, int len) +{ + struct apbuart_priv *uart; + unsigned int oldLevel; + + if (minor == 0) + uart = &apbuarts[syscon_uart_index]; + else + uart = &apbuarts[minor - 1]; + + /* Remember what position in buffer */ + + rtems_interrupt_disable(oldLevel); + + /* Enable TX interrupt */ + uart->regs->ctrl |= LEON_REG_UART_CTRL_TI; + + /* start UART TX, this will result in an interrupt when done */ + uart->regs->data = *buf; + + uart->sending = 1; + + rtems_interrupt_enable(oldLevel); + + return 0; +} + +#else + /* * Console Termios Support Entry Points * */ -ssize_t console_write_support (int minor, const char *buf, size_t len) +ssize_t console_write_polled(int minor, const char *buf, size_t len) { int nwrite = 0, port; @@ -100,6 +174,8 @@ int console_pollRead(int minor) return apbuart_inbyte_nonblocking(apbuarts[port].regs); } +#endif + int console_set_attributes(int minor, const struct termios *t) { unsigned int scaler; @@ -174,6 +250,9 @@ int find_matching_apbuart(struct ambapp_dev *dev, int index, void *arg) /* Extract needed information of one APBUART */ apbuarts[uarts].regs = (ambapp_apb_uart *)apb->start; +#if CONSOLE_USE_INTERRUPTS + apbuarts[uarts].irq = apb->irq; +#endif /* Get APBUART core frequency, it is assumed that it is the same * as Bus frequency where the UART is situated */ @@ -266,35 +345,70 @@ rtems_device_driver console_open( ) { rtems_status_code sc; - int port; + struct apbuart_priv *uart; +#if CONSOLE_USE_INTERRUPTS + rtems_libio_open_close_args_t *priv = arg; - static const rtems_termios_callbacks pollCallbacks = { + /* Interrupt mode routines */ + static const rtems_termios_callbacks Callbacks = { + NULL, /* firstOpen */ + NULL, /* lastClose */ + NULL, /* pollRead */ + console_write_interrupt, /* write */ + console_set_attributes, /* setAttributes */ + NULL, /* stopRemoteTx */ + NULL, /* startRemoteTx */ + 1 /* outputUsesInterrupts */ + }; +#else + /* Polling mode routines */ + static const rtems_termios_callbacks Callbacks = { NULL, /* firstOpen */ NULL, /* lastClose */ console_pollRead, /* pollRead */ - console_write_support, /* write */ + console_write_polled, /* write */ console_set_attributes, /* setAttributes */ NULL, /* stopRemoteTx */ NULL, /* startRemoteTx */ 0 /* outputUsesInterrupts */ }; +#endif assert(minor <= uarts); if (minor > uarts || minor == (syscon_uart_index + 1)) return RTEMS_INVALID_NUMBER; - sc = rtems_termios_open (major, minor, arg, &pollCallbacks); + sc = rtems_termios_open(major, minor, arg, &Callbacks); if (sc != RTEMS_SUCCESSFUL) return sc; if (minor == 0) - port = syscon_uart_index; + uart = &apbuarts[syscon_uart_index]; else - port = minor - 1; + uart = &apbuarts[minor - 1]; + +#if CONSOLE_USE_INTERRUPTS + if (priv && priv->iop) + uart->cookie = priv->iop->data1; + else + uart->cookie = NULL; + + /* Register Interrupt handler */ + sc = rtems_interrupt_handler_install(uart->irq, "console", + RTEMS_INTERRUPT_SHARED, console_isr, + uart); + if (sc != RTEMS_SUCCESSFUL) + return sc; + uart->sending = 0; + /* Enable Receiver and transmitter and Turn on RX interrupts */ + uart->regs->ctrl |= LEON_REG_UART_CTRL_RE | LEON_REG_UART_CTRL_TE | + LEON_REG_UART_CTRL_RI; +#else /* Initialize UART on opening */ - apbuarts[port]->regs->ctrl |= LEON_REG_UART_CTRL_RE | LEON_REG_UART_CTRL_TE; - apbuarts[port]->regs->status = 0; + uart->regs->ctrl |= LEON_REG_UART_CTRL_RE | LEON_REG_UART_CTRL_TE; +#endif + uart->regs->status = 0; return RTEMS_SUCCESSFUL; } @@ -305,7 +419,26 @@ rtems_device_driver console_close( void * arg ) { - return rtems_termios_close (arg); +#if CONSOLE_USE_INTERRUPTS + struct apbuart_priv *uart; + + if (minor == 0) + uart = &apbuarts[syscon_uart_index]; + else + uart = &apbuarts[minor - 1]; + + /* Turn off RX interrupts */ + uart->regs->ctrl &= ~(LEON_REG_UART_CTRL_RI); + + /**** Flush device ****/ + while (uart->sending) { + /* Wait until all data has been sent */ + } + + /* uninstall ISR */ + rtems_interrupt_handler_remove(uart->irq, console_isr, uart); +#endif + return rtems_termios_close(arg); } rtems_device_driver console_read( @@ -314,7 +447,7 @@ rtems_device_driver console_read( void * arg ) { - return rtems_termios_read (arg); + return rtems_termios_read(arg); } rtems_device_driver console_write( @@ -323,7 +456,7 @@ rtems_device_driver console_write( void * arg ) { - return rtems_termios_write (arg); + return rtems_termios_write(arg); } rtems_device_driver console_control( @@ -332,6 +465,6 @@ rtems_device_driver console_control( void * arg ) { - return rtems_termios_ioctl (arg); + return rtems_termios_ioctl(arg); } |