diff options
author | Daniel Hellstrom <daniel@gaisler.com> | 2011-12-09 14:17:51 +0100 |
---|---|---|
committer | Daniel Hellstrom <daniel@gaisler.com> | 2012-03-27 15:20:13 +0200 |
commit | bafd5983ad99ef5b7eae8d6dd3f297867b342fac (patch) | |
tree | 47feab1f23e1e0826c6a12662ae0db8c086882dd | |
parent | 3dab4d6846ae639e1f870a74a9fbc98bb1a8feec (diff) |
LEON3: console: updated UART index handling, various cleanups
-rw-r--r-- | c/src/lib/libbsp/sparc/leon3/console/console.c | 234 |
1 files changed, 140 insertions, 94 deletions
diff --git a/c/src/lib/libbsp/sparc/leon3/console/console.c b/c/src/lib/libbsp/sparc/leon3/console/console.c index a39fe93e3a..58545ff80a 100644 --- a/c/src/lib/libbsp/sparc/leon3/console/console.c +++ b/c/src/lib/libbsp/sparc/leon3/console/console.c @@ -17,6 +17,17 @@ * $Id$ */ +/* 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> @@ -26,29 +37,46 @@ #ifndef RTEMS_DRVMGR_STARTUP -#if CONSOLE_USE_INTERRUPTS && defined(RTEMS_MULTIPROCESSING) -#error LEON3 console driver does not support interrupt mode in multi processor systems -#endif +/* Let user override which on-chip APBUART will be debug UART + * 0 = Default APBUART. On MP system CPU0=APBUART0, CPU1=APBUART1... + * 1 = APBUART[0] + * 2 = APBUART[1] + * 3 = APBUART[2] + * ... + */ +int syscon_uart_index __attribute__((weak)) = 0; + +/* + * apbuart_outbyte_polled + * + * This routine transmits a character using polling. + */ extern void apbuart_outbyte_polled( ambapp_apb_uart *regs, unsigned char ch, int do_cr_on_newline, int wait_sent); -extern int apbuart_inbyte_nonblocking(ambapp_apb_uart *regs); -/* 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 1.0.17-b2710) has the GRMON debug bit and can - * handle interrupts. + +/* body is in debugputs.c */ + +/* + * apbuart_inbyte_nonblocking + * + * This routine polls for a character. */ +extern int apbuart_inbyte_nonblocking(ambapp_apb_uart *regs); + +/* body is in debugputs.c */ + struct apbuart_priv { ambapp_apb_uart *regs; - int irq; - void *cookie; unsigned int freq_hz; #if CONSOLE_USE_INTERRUPTS + int irq; + void *cookie; volatile int sending; char *buf; #endif @@ -56,17 +84,6 @@ struct apbuart_priv { static struct apbuart_priv apbuarts[CONFIGURE_NUMBER_OF_TERMIOS_PORTS]; static int uarts = 0; -/* - * Should we use a polled or interrupt drived console? - * - * NOTE: This is defined in the custom/leon.cfg file. - */ - -int console_pollRead( int minor ) -{ - return apbuart_inbyte_nonblocking(apbuarts[minor+LEON3_Cpu_Index].regs); -} - #if CONSOLE_USE_INTERRUPTS /* Handle UART interrupts */ @@ -76,19 +93,16 @@ void console_isr(void *arg) unsigned int status; char data; - /* Clear interrupt */ - LEON_Clear_interrupt(uart->irq); - /* Get all received characters */ - while ( (status=uart->regs->status) & LEON_REG_UART_STATUS_DR ){ + 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); + rtems_termios_enqueue_raw_characters(uart->cookie, &data, 1); } - if ( status & LEON_REG_UART_STATUS_THE ){ + if (status & LEON_REG_UART_STATUS_THE) { /* Sent the one char, we disable TX interrupts */ uart->regs->ctrl &= ~LEON_REG_UART_CTRL_TI; @@ -96,19 +110,24 @@ void console_isr(void *arg) uart->sending = 0; /* write_interrupt will get called from this function */ - rtems_termios_dequeue_characters(uart->cookie,1); + 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 ) - minor = LEON3_Cpu_Index; - - uart = &apbuarts[minor]; + if (minor == 0) + uart = &apbuarts[syscon_uart_index]; + else + uart = &apbuarts[minor - 1]; /* Remember what position in buffer */ @@ -126,7 +145,9 @@ int console_write_interrupt (int minor, const char *buf, int len) return 0; } -#endif + +#else + /* * Console Termios Support Entry Points * @@ -134,24 +155,34 @@ int console_write_interrupt (int minor, const char *buf, int len) ssize_t console_write_polled (int minor, const char *buf, size_t len) { - int nwrite = 0; - struct apbuart_priv *uart; - - if ( minor == 0 ) - minor = LEON3_Cpu_Index; + int nwrite = 0, port; - if ( minor >= uarts ) - return -1; - - uart = &apbuarts[minor]; + if (minor == 0) + port = syscon_uart_index; + else + port = minor - 1; while (nwrite < len) { - apbuart_outbyte_polled( uart->regs, *buf++, 1, 0 ); + apbuart_outbyte_polled(apbuarts[port]->regs, *buf++, 1, 0 ); nwrite++; } return nwrite; } +int console_pollRead(int minor) +{ + int port; + + if (minor == 0) + port = syscon_uart_index; + else + port = minor - 1; + + return apbuart_inbyte_nonblocking(apbuarts[port]->regs); +} + +#endif + int console_set_attributes(int minor, const struct termios *t) { unsigned int scaler; @@ -170,13 +201,10 @@ int console_set_attributes(int minor, const struct termios *t) break; } - if ( minor == 0 ) - minor = LEON3_Cpu_Index; - - if ( minor >= uarts ) - return -1; - - uart = &apbuarts[minor]; + if (minor == 0) + uart = &apbuarts[syscon_uart_index]; + else + uart = &apbuarts[minor - 1]; /* Read out current value */ ctrl = uart->regs->ctrl; @@ -251,7 +279,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 */ @@ -264,24 +294,23 @@ int find_matching_apbuart(struct ambapp_dev *dev, int index, void *arg) return 0; /* Continue searching for more UARTs */ } -/* - * Console Device Driver Entry Points - * - */ - -int scan_uarts(void) +/* Find all UARTs */ +int console_scan_uarts(void) { - if (uarts == 0) { - memset(apbuarts, 0, sizeof(apbuarts)); + memset(apbuarts, 0, sizeof(apbuarts)); - /* Find APBUART cores */ - ambapp_for_each(&ambapp_plb, (OPTIONS_ALL|OPTIONS_APB_SLVS), VENDOR_GAISLER, - GAISLER_APBUART, find_matching_apbuart, NULL); - } + /* Find APBUART cores */ + ambapp_for_each(&ambapp_plb, (OPTIONS_ALL|OPTIONS_APB_SLVS), VENDOR_GAISLER, + GAISLER_APBUART, find_matching_apbuart, NULL); return uarts; } +/* + * Console Device Driver Entry Points + * + */ + rtems_device_driver console_initialize( rtems_device_major_number major, rtems_device_minor_number minor, @@ -289,34 +318,50 @@ rtems_device_driver console_initialize( ) { rtems_status_code status; - int i, uart0; + int i; char console_name[16]; rtems_termios_initialize(); /* Find UARTs */ - scan_uarts(); + console_scan_uarts(); - /* Let LEON3 CPU index select UART, this is useful in AMP - * systems. LEON3_Cpu_Index is zero for CPU0, one for CPU1... - * Note that looking at the RTEMS_MULTIPROCESSING macro - * does not work when different operating systems are used - * and RTEMS is configured non-MP. + /* Update syscon_uart_index to index used as /dev/console + * Let user select System console by setting syscon_uart_index. If the + * BSP is to provide the default UART (syscon_uart_index==0): + * non-MP: APBUART[0] is system console + * MP: LEON CPU index select UART */ - uart0 = LEON3_Cpu_Index; + if (syscon_uart_index == 0) { +#if defined(RTEMS_MULTIPROCESSING) + syscon_uart_index = LEON3_Cpu_Index; +#else + syscon_uart_index = 0; +#endif + } else { + syscon_uart_index = syscon_uart_index - 1; /* User selected sys-console */ + } - /* Register Device Names */ - if (uarts && (uart0 < uarts)) - { + /* Register Device Names + * + * 0 /dev/console - APBUART[USER-SELECTED, DEFAULT=APBUART[0]] + * 1 /dev/console_a - APBUART[0] (by default not present because is console) + * 2 /dev/console_b - APBUART[1] + * ... + * + * On a MP system one should not open UARTs that other OS instances use. + */ + if (syscon_uart_index < uarts) { status = rtems_io_register_name( "/dev/console", major, 0 ); if (status != RTEMS_SUCCESSFUL) rtems_fatal_error_occurred(status); - - strcpy(console_name,"/dev/console_a"); - for (i = uart0+1; i < uarts; i++) { - console_name[13]++; - status = rtems_io_register_name( console_name, major, i); - } + } + strcpy(console_name,"/dev/console_a"); + for (i = 0; i < uarts; i++) { + if (i == syscon_uart_index) + continue; /* skip UART that is registered as /dev/console */ + console_name[13] = 'a' + i; + status = rtems_io_register_name( console_name, major, i+1); } return RTEMS_SUCCESSFUL; @@ -330,9 +375,9 @@ rtems_device_driver console_open( { rtems_status_code sc; struct apbuart_priv *uart; +#if CONSOLE_USE_INTERRUPTS rtems_libio_open_close_args_t *priv = arg; -#if CONSOLE_USE_INTERRUPTS /* Interrupt mode routines */ static const rtems_termios_callbacks Callbacks = { NULL, /* firstOpen */ @@ -358,28 +403,29 @@ rtems_device_driver console_open( }; #endif - assert( minor < uarts ); - if ( minor >= uarts ) + assert(minor <= uarts); + if (minor > uarts || minor == (syscon_uart_index + 1)) return RTEMS_INVALID_NUMBER; sc = rtems_termios_open (major, minor, arg, &Callbacks); if (sc != RTEMS_SUCCESSFUL) return sc; - if ( minor == 0 ) - minor = LEON3_Cpu_Index; - uart = &apbuarts[minor]; + if (minor == 0) + uart = &apbuarts[syscon_uart_index]; + else + uart = &apbuarts[minor - 1]; - if ( priv && priv->iop ) +#if CONSOLE_USE_INTERRUPTS + if (priv && priv->iop) uart->cookie = priv->iop->data1; else uart->cookie = NULL; -#if CONSOLE_USE_INTERRUPTS /* Register Interrupt handler */ sc = rtems_interrupt_handler_install(uart->irq, "console", RTEMS_INTERRUPT_SHARED, console_isr, - uart); + uart); if (sc != RTEMS_SUCCESSFUL) return sc; @@ -388,7 +434,7 @@ rtems_device_driver console_open( uart->regs->ctrl |= LEON_REG_UART_CTRL_RE | LEON_REG_UART_CTRL_TE | LEON_REG_UART_CTRL_RI; #else - /* Enable Receiver and transmitter */ + /* Initialize UART on opening */ uart->regs->ctrl |= LEON_REG_UART_CTRL_RE | LEON_REG_UART_CTRL_TE; #endif uart->regs->status = 0; @@ -405,21 +451,21 @@ rtems_device_driver console_close( #if CONSOLE_USE_INTERRUPTS struct apbuart_priv *uart; - if ( minor == 0) - minor = LEON3_Cpu_Index; + if (minor == 0) + uart = &apbuarts[syscon_uart_index]; + else + uart = &apbuarts[minor - 1]; /* Turn off RX interrupts */ - uart = &apbuarts[minor]; uart->regs->ctrl &= ~(LEON_REG_UART_CTRL_RI); /**** Flush device ****/ - while ( uart->sending ) { + 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); } |