From c627a13239d8568a63cb192ed4bc8bb75a746399 Mon Sep 17 00:00:00 2001 From: "Maldonado, Sergio E. (GSFC-580.0)" Date: Mon, 27 Feb 2023 22:44:51 -0600 Subject: bsps/microblaze: Add support for multiple UARTs --- bsps/microblaze/include/dev/serial/uartlite.h | 2 + .../microblaze_fpga/console/console-io.c | 205 ++++++++++++++++++--- bsps/microblaze/shared/dev/serial/uartlite.c | 8 +- 3 files changed, 186 insertions(+), 29 deletions(-) (limited to 'bsps') diff --git a/bsps/microblaze/include/dev/serial/uartlite.h b/bsps/microblaze/include/dev/serial/uartlite.h index 2fda3796b3..009f416508 100644 --- a/bsps/microblaze/include/dev/serial/uartlite.h +++ b/bsps/microblaze/include/dev/serial/uartlite.h @@ -49,8 +49,10 @@ typedef struct { rtems_termios_device_context base; uintptr_t address; uint32_t initial_baud; + uint32_t enabled; #ifdef BSP_MICROBLAZE_FPGA_CONSOLE_INTERRUPTS bool transmitting; + uint32_t irq; #endif } uart_lite_context; diff --git a/bsps/microblaze/microblaze_fpga/console/console-io.c b/bsps/microblaze/microblaze_fpga/console/console-io.c index 81c4e73690..a07c85642f 100644 --- a/bsps/microblaze/microblaze_fpga/console/console-io.c +++ b/bsps/microblaze/microblaze_fpga/console/console-io.c @@ -34,39 +34,200 @@ * POSSIBILITY OF SUCH DAMAGE. */ -#include -#include -#include +#include +#include +#include +#include +#include +#include #include +#include -uart_lite_context microblaze_qemu_uart_context = { - .base = RTEMS_TERMIOS_DEVICE_CONTEXT_INITIALIZER( "UARTLITE" ), - .initial_baud = 115200 -}; - -static bool fill_uart_base(rtems_termios_device_context *context) -{ - uint32_t mblaze_uart_base; - - mblaze_uart_base = try_get_prop_from_device_tree( - "xlnx,xps-uartlite-1.00.a", - "reg", - BSP_MICROBLAZE_FPGA_UART_BASE - ); +#ifdef BSP_MICROBLAZE_FPGA_USE_FDT +#include +#include +#endif - microblaze_qemu_uart_context.address = mblaze_uart_base; +#include - return true; -} +#ifndef BSP_MICROBLAZE_FPGA_USE_FDT +static uart_lite_context uart_lite_instances[] = { + { + .base = RTEMS_TERMIOS_DEVICE_CONTEXT_INITIALIZER( "UARTLITE" ), + .initial_baud = 115200, + .address = BSP_MICROBLAZE_FPGA_UART_BASE, +#if BSP_MICROBLAZE_FPGA_USE_UART + .enabled = 1, +#endif +#ifdef BSP_MICROBLAZE_FPGA_CONSOLE_INTERRUPTS + .irq = BSP_MICROBLAZE_FPGA_UART_IRQ +#endif + } +}; const console_device console_device_table[] = { { .device_file = "/dev/ttyS0", - .probe = fill_uart_base, .handler = µblaze_uart_fns, - .context = µblaze_qemu_uart_context.base + .context = &uart_lite_instances[0].base } }; const size_t console_device_count = RTEMS_ARRAY_SIZE( console_device_table ); +#else +static uart_lite_context uart_lite_instances[BSP_MICROBLAZE_FPGA_MAX_UARTS]; +console_device *dynamic_console_device_table; +size_t dynamic_console_device_count; + +/* Override the console_device_table and console_device_count */ +#define console_device_table dynamic_console_device_table +#define console_device_count dynamic_console_device_count +#endif /* BSP_MICROBLAZE_FPGA_USE_FDT */ + +#ifdef BSP_MICROBLAZE_FPGA_USE_FDT +static int microblaze_fpga_get_stdout_node(const void *fdt) +{ + int node; + int len; + int offset; + const char *console; + const char *q; + + node = fdt_path_offset( fdt, "/chosen" ); + if ( node < 0 ) { + return 0; + } + + console = fdt_getprop( fdt, node, "stdout-path", NULL ); + if ( console == NULL ) { + return 0; + } + + q = strchr(console, ':'); + if ( !q ) { + return 0; + } + + len = q - console; + + /* Get the node specified by stdout-path */ + offset = fdt_path_offset_namelen( fdt, console, len ); + if (offset < 0) { + return 0; + } + + return offset; +} + +static void initialize_uart_arrays(uint32_t max_uarts) { + dynamic_console_device_table = calloc(max_uarts, sizeof(console_device)); + dynamic_console_device_count = max_uarts; + + for (uint32_t i = 0; i < max_uarts; i++) { + rtems_termios_device_context_initialize(&uart_lite_instances[i].base, "UARTLITE"); + uart_lite_instances[i].initial_baud = 115200; + + dynamic_console_device_table[i].device_file = malloc(11); + snprintf((char *)console_device_table[i].device_file, 11, "/dev/ttyS%u", i); + dynamic_console_device_table[i].handler = µblaze_uart_fns; + dynamic_console_device_table[i].context = &uart_lite_instances[i].base; + } +} +#endif + +rtems_device_driver console_initialize( + rtems_device_major_number major, + rtems_device_minor_number minor, + void *arg +) +{ + uint32_t port; + uint32_t stdout_port = BSP_MICROBLAZE_FPGA_CONSOLE_UART; + +#ifdef BSP_MICROBLAZE_FPGA_USE_FDT + initialize_uart_arrays(BSP_MICROBLAZE_FPGA_MAX_UARTS); + + const char compatible[] = "xlnx,xps-uartlite-1.00.a"; + const void *fdt = bsp_fdt_get(); + int len; + int stdout_node = microblaze_fpga_get_stdout_node(fdt); + int node = fdt_node_offset_by_compatible( fdt, -1, compatible); + + while ( node != -FDT_ERR_NOTFOUND ) { + const uint32_t *prop; + const void *status; + uint32_t disabled = 0; + port = console_device_count; + + /* check if node device status has been set to disabled */ + status = fdt_getprop( fdt, node, "status", &len ); + if ( status != NULL ) { + if ( strncmp( status, "disabled", MIN( 9, len) ) == 0 ) { + disabled = 1; + } + } + + if ( !disabled ) { + /* use port number property as the device table index */ + prop = fdt_getprop( fdt, node, "port-number", NULL ); + if ( prop != NULL ) { + port = fdt32_to_cpu( prop[0] ); + } + + if ( port < console_device_count ) { + prop = fdt_getprop( fdt, node, "reg", NULL ); + if ( prop != NULL ) { + uint32_t address = fdt32_to_cpu( prop[0] ); + uart_lite_instances[ port ].address = address; + uart_lite_instances[ port ].enabled = 1; + if ( node == stdout_node ) { + stdout_port = port; + } + } + +#ifdef BSP_MICROBLAZE_FPGA_CONSOLE_INTERRUPTS + prop = fdt_getprop( fdt, node, "interrupts", NULL ); + if ( prop != NULL ) { + uint32_t irq = fdt32_to_cpu( prop[0] ); + uart_lite_instances[ port ].irq = irq; + } +#endif + } + } + + node = fdt_node_offset_by_compatible( fdt, node, compatible ); + + if ( disabled || ( port >= console_device_count ) ) + continue; + } +#endif /* BSP_MICROBLAZE_FPGA_USE_FDT */ + + rtems_termios_initialize(); + + for ( port = 0; port < console_device_count; port++ ) { + const console_device *ctx = &console_device_table[ port ]; + rtems_status_code sc; + + if ( !uart_lite_instances[ port ].enabled ) + continue; + + sc = rtems_termios_device_install( + ctx->device_file, + ctx->handler, + ctx->flow, + ctx->context + ); + if ( sc != RTEMS_SUCCESSFUL ) { + bsp_fatal( BSP_FATAL_CONSOLE_INSTALL_0 ); + } + + if ( port == stdout_port ) { + if ( link( ctx->device_file, CONSOLE_DEVICE_NAME ) != 0 ) { + bsp_fatal( BSP_FATAL_CONSOLE_INSTALL_1 ); + } + } + } + + return RTEMS_SUCCESSFUL; +} diff --git a/bsps/microblaze/shared/dev/serial/uartlite.c b/bsps/microblaze/shared/dev/serial/uartlite.c index 953c630759..e2007ee24a 100644 --- a/bsps/microblaze/shared/dev/serial/uartlite.c +++ b/bsps/microblaze/shared/dev/serial/uartlite.c @@ -71,14 +71,8 @@ static bool uart_first_open( #ifdef BSP_MICROBLAZE_FPGA_CONSOLE_INTERRUPTS XUartLite_EnableIntr( ctx->address ); - uint32_t uart_irq_num = try_get_prop_from_device_tree( - "xlnx,xps-uartlite-1.00.a", - "interrupts", - 1 - ); - sc = rtems_interrupt_handler_install( - uart_irq_num, + ctx->irq, "UART", RTEMS_INTERRUPT_SHARED, microblaze_uart_interrupt, -- cgit v1.2.3