diff options
Diffstat (limited to '')
18 files changed, 1227 insertions, 87 deletions
diff --git a/bsps/microblaze/include/bsp/microblaze-fdt-support.h b/bsps/microblaze/include/bsp/microblaze-fdt-support.h new file mode 100644 index 0000000000..d4430c5a3a --- /dev/null +++ b/bsps/microblaze/include/bsp/microblaze-fdt-support.h @@ -0,0 +1,65 @@ +/* SPDX-License-Identifier: BSD-2-Clause */ + +/** + * @file + * + * @ingroup RTEMSBSPsMicroblaze + * + * @brief This header file provides support for the device tree. + */ + +/* + * Copyright (C) 2022 On-Line Applications Research Corporation (OAR) + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef LIBBSP_MICROBLAZE_MICROBLAZE_FDT_SUPPORT_H +#define LIBBSP_MICROBLAZE_MICROBLAZE_FDT_SUPPORT_H + +#ifdef __cplusplus +extern "C" { +#endif + +#include <stdint.h> + +/** + * @brief Get the value of a property from a compatible node in the device tree. + * + * @param[in] compatible The 'compatible' string to match against. + * @param[in] prop_name The property name. + * @param[in] default_value The default value to return if no compatible node + * was found or the property was not found. + * + * @return The value of the property or the default value. + */ +uint32_t try_get_prop_from_device_tree( + const char *compatible, + const char *prop_name, + uint32_t default_value +); + +#ifdef __cplusplus +} +#endif + +#endif /* LIBBSP_MICROBLAZE_MICROBLAZE_FDT_SUPPORT_H */ diff --git a/bsps/microblaze/include/dev/serial/uartlite.h b/bsps/microblaze/include/dev/serial/uartlite.h index 6e288d4dc7..f58ae92ef8 100644 --- a/bsps/microblaze/include/dev/serial/uartlite.h +++ b/bsps/microblaze/include/dev/serial/uartlite.h @@ -36,6 +36,7 @@ #ifndef LIBBSP_MICROBLAZE_SHARED_UARTLITE_H #define LIBBSP_MICROBLAZE_SHARED_UARTLITE_H +#include <bspopts.h> #include <rtems/termiostypes.h> #include <dev/serial/uartlite_l.h> @@ -48,8 +49,12 @@ typedef struct { rtems_termios_device_context base; uintptr_t address; uint32_t initial_baud; + uint32_t enabled; #ifdef BSP_MICROBLAZE_FPGA_CONSOLE_INTERRUPTS + struct rtems_termios_tty *tty; bool transmitting; + size_t tx_queued; + uint32_t irq; #endif } uart_lite_context; diff --git a/bsps/microblaze/include/dev/serial/uartlite_l.h b/bsps/microblaze/include/dev/serial/uartlite_l.h index 8c0598e191..834fbb5f75 100644 --- a/bsps/microblaze/include/dev/serial/uartlite_l.h +++ b/bsps/microblaze/include/dev/serial/uartlite_l.h @@ -234,6 +234,24 @@ static inline void Xil_Out32(UINTPTR Addr, u32 Value) ((XUartLite_GetStatusReg((BaseAddress)) & XUL_SR_RX_FIFO_VALID_DATA) != \ XUL_SR_RX_FIFO_VALID_DATA) +#ifdef __rtems__ +/****************************************************************************/ +/** +* +* Check to see if the transmitter is empty. +* +* @param BaseAddress is the base address of the device +* +* @return TRUE if the transmitter is empty, FALSE otherwise. +* +* @note C-style Signature: +* int XUartLite_IsTransmitEmpty(u32 BaseAddress); +* +*****************************************************************************/ +#define XUartLite_IsTransmitEmpty(BaseAddress) \ + ((XUartLite_GetStatusReg((BaseAddress)) & XUL_SR_TX_FIFO_EMPTY) == \ + XUL_SR_TX_FIFO_EMPTY) +#endif /* __rtems__ */ /****************************************************************************/ /** diff --git a/bsps/microblaze/microblaze_fpga/clock/clock.c b/bsps/microblaze/microblaze_fpga/clock/clock.c index 957d0fdadb..16acbaeebb 100644 --- a/bsps/microblaze/microblaze_fpga/clock/clock.c +++ b/bsps/microblaze/microblaze_fpga/clock/clock.c @@ -33,6 +33,7 @@ * POSSIBILITY OF SUCH DAMAGE. */ +#include <bsp.h> #include <bsp/fatal.h> #include <bsp/timer.h> @@ -41,17 +42,16 @@ #include <rtems/timecounter.h> static rtems_timecounter_simple mblaze_tc; +static volatile Microblaze_Timer *mblaze_timer; static uint32_t microblaze_tc_get( rtems_timecounter_simple *tc ) { - volatile Microblaze_Timer *timer = _Microblaze_Timer; - return timer->tcr0; + return mblaze_timer->tcr0; } static bool microblaze_tc_is_pending( rtems_timecounter_simple *tc ) { - volatile Microblaze_Timer *timer = _Microblaze_Timer; - return ( timer->tcsr0 & MICROBLAZE_TIMER_TCSR0_T0INT ) != 0; + return ( mblaze_timer->tcsr0 & MICROBLAZE_TIMER_TCSR0_T0INT ) != 0; } static uint32_t microblaze_tc_get_timecount( struct timecounter *tc ) @@ -65,32 +65,41 @@ static uint32_t microblaze_tc_get_timecount( struct timecounter *tc ) static void microblaze_clock_initialize( void ) { - volatile Microblaze_Timer *timer = _Microblaze_Timer; + mblaze_timer = (volatile Microblaze_Timer *) try_get_prop_from_device_tree( + "xlnx,xps-timer-1.00.a", + "reg", + BSP_MICROBLAZE_FPGA_TIMER_BASE + ); + /* Set load register to 0 */ - timer->tlr0 = 0; + mblaze_timer->tlr0 = 0; /* Reset the timer and interrupt */ - timer->tcsr0 = MICROBLAZE_TIMER_TCSR0_T0INT | MICROBLAZE_TIMER_TCSR0_LOAD0; + mblaze_timer->tcsr0 = MICROBLAZE_TIMER_TCSR0_T0INT | MICROBLAZE_TIMER_TCSR0_LOAD0; /* Release the reset */ - timer->tcsr0 = 0; + mblaze_timer->tcsr0 = 0; /* * Enable interrupt, auto reload mode, external interrupt signal, * and down counter */ - timer->tcsr0 = MICROBLAZE_TIMER_TCSR0_ARHT0 | MICROBLAZE_TIMER_TCSR0_ENIT0 | + mblaze_timer->tcsr0 = MICROBLAZE_TIMER_TCSR0_ARHT0 | MICROBLAZE_TIMER_TCSR0_ENIT0 | MICROBLAZE_TIMER_TCSR0_GENT0 | MICROBLAZE_TIMER_TCSR0_UDT0; uint64_t us_per_tick = rtems_configuration_get_microseconds_per_tick(); - uint32_t counter_frequency_in_hz = BSP_MICROBLAZE_FPGA_TIMER_FREQUENCY; + uint32_t counter_frequency_in_hz = try_get_prop_from_device_tree( + "xlnx,xps-timer-1.00.a", + "clock-frequency", + BSP_MICROBLAZE_FPGA_TIMER_FREQUENCY + ); uint32_t counter_ticks_per_clock_tick = ( counter_frequency_in_hz * us_per_tick ) / 1000000; /* Set a reset value for the timer counter */ - timer->tlr0 = counter_ticks_per_clock_tick; - uint32_t control_status_reg = timer->tcsr0; + mblaze_timer->tlr0 = counter_ticks_per_clock_tick; + uint32_t control_status_reg = mblaze_timer->tcsr0; /* Load the reset value into the counter register */ - timer->tcsr0 = MICROBLAZE_TIMER_TCSR0_LOAD0; + mblaze_timer->tcsr0 = MICROBLAZE_TIMER_TCSR0_LOAD0; /* Enable the timer */ - timer->tcsr0 = control_status_reg | MICROBLAZE_TIMER_TCSR0_ENT0; + mblaze_timer->tcsr0 = control_status_reg | MICROBLAZE_TIMER_TCSR0_ENT0; rtems_timecounter_simple_install( &mblaze_tc, @@ -102,18 +111,17 @@ static void microblaze_clock_initialize( void ) static void microblaze_clock_at_tick( rtems_timecounter_simple *tc ) { - volatile Microblaze_Timer *timer = _Microblaze_Timer; - if ( ( timer->tcsr0 & MICROBLAZE_TIMER_TCSR0_T0INT ) == 0 ) { + if ( ( mblaze_timer->tcsr0 & MICROBLAZE_TIMER_TCSR0_T0INT ) == 0 ) { return; } /* Clear the interrupt */ - timer->tcsr0 |= MICROBLAZE_TIMER_TCSR0_T0INT; + mblaze_timer->tcsr0 |= MICROBLAZE_TIMER_TCSR0_T0INT; } -static void microblaze_tc_tick( void ) +static void microblaze_tc_tick( rtems_timecounter_simple *tc ) { rtems_timecounter_simple_downcounter_tick( - &mblaze_tc, + tc, microblaze_tc_get, microblaze_clock_at_tick ); @@ -123,12 +131,18 @@ static void microblaze_clock_handler_install( rtems_interrupt_handler isr ) { rtems_status_code sc = RTEMS_SUCCESSFUL; + uint32_t clock_irq_num = try_get_prop_from_device_tree( + "xlnx,xps-timer-1.00.a", + "interrupts", + 0 + ); + sc = rtems_interrupt_handler_install( - 0, + clock_irq_num, "Clock", RTEMS_INTERRUPT_UNIQUE, isr, - NULL + &mblaze_tc ); if ( sc != RTEMS_SUCCESSFUL ) { @@ -139,7 +153,7 @@ static void microblaze_clock_handler_install( rtems_interrupt_handler isr ) #define Clock_driver_support_initialize_hardware() microblaze_clock_initialize() #define Clock_driver_support_install_isr( isr ) \ microblaze_clock_handler_install( isr ) -#define Clock_driver_timecounter_tick() microblaze_tc_tick() +#define Clock_driver_timecounter_tick(arg) microblaze_tc_tick(arg) /* Include shared source clock driver code */ #include "../../shared/dev/clock/clockimpl.h" diff --git a/bsps/microblaze/microblaze_fpga/console/console-io.c b/bsps/microblaze/microblaze_fpga/console/console-io.c index cb2e367035..a07c85642f 100644 --- a/bsps/microblaze/microblaze_fpga/console/console-io.c +++ b/bsps/microblaze/microblaze_fpga/console/console-io.c @@ -34,24 +34,200 @@ * POSSIBILITY OF SUCH DAMAGE. */ +#include <unistd.h> +#include <string.h> +#include <stdio.h> + +#include <sys/param.h> #include <bsp/console-termios.h> +#include <bsp/fatal.h> +#include <bspopts.h> #include <dev/serial/uartlite.h> -#include <bspopts.h> +#ifdef BSP_MICROBLAZE_FPGA_USE_FDT +#include <bsp/fdt.h> +#include <libfdt.h> +#endif -uart_lite_context microblaze_qemu_uart_context = { - .base = RTEMS_TERMIOS_DEVICE_CONTEXT_INITIALIZER( "UARTLITE" ), - .address = BSP_MICROBLAZE_FPGA_UART_BASE, - .initial_baud = 115200 +#include <rtems/console.h> + +#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 = console_device_probe_default, .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/microblaze_fpga/console/debug-io.c b/bsps/microblaze/microblaze_fpga/console/debug-io.c index e88f5468a7..d85229ae9e 100644 --- a/bsps/microblaze/microblaze_fpga/console/debug-io.c +++ b/bsps/microblaze/microblaze_fpga/console/debug-io.c @@ -37,23 +37,42 @@ #include <dev/serial/uartlite_l.h> #include <rtems/bspIo.h> +#include <bsp.h> #include <bspopts.h> +static uint32_t mblaze_uart_base = 0; + static void output_char( char c ) { - if ( c == '\n' ) { - XUartLite_SendByte( BSP_MICROBLAZE_FPGA_UART_BASE, '\r' ); + if (mblaze_uart_base == 0 ) { + mblaze_uart_base = try_get_prop_from_device_tree( + "xlnx,xps-uartlite-1.00.a", + "reg", + BSP_MICROBLAZE_FPGA_UART_BASE + ); + } + + if ( c == '\n' ) { + XUartLite_SendByte( mblaze_uart_base, '\r' ); } - XUartLite_SendByte( BSP_MICROBLAZE_FPGA_UART_BASE, c ); + XUartLite_SendByte( mblaze_uart_base, c ); } static int xUartLite_RecvByte( int minor ) { - if ( XUartLite_IsReceiveEmpty( BSP_MICROBLAZE_FPGA_UART_BASE ) ) { + if (mblaze_uart_base == 0 ) { + mblaze_uart_base = try_get_prop_from_device_tree( + "xlnx,xps-uartlite-1.00.a", + "reg", + BSP_MICROBLAZE_FPGA_UART_BASE + ); + } + + if ( XUartLite_IsReceiveEmpty( mblaze_uart_base ) ) { return -1; } - return XUartLite_ReadReg( BSP_MICROBLAZE_FPGA_UART_BASE, XUL_RX_FIFO_OFFSET ); + return XUartLite_ReadReg( mblaze_uart_base, XUL_RX_FIFO_OFFSET ); } static int get_char( void ) diff --git a/bsps/microblaze/microblaze_fpga/fdt/bsp_fdt.c b/bsps/microblaze/microblaze_fpga/fdt/bsp_fdt.c deleted file mode 100644 index 9eb92c5dc6..0000000000 --- a/bsps/microblaze/microblaze_fpga/fdt/bsp_fdt.c +++ /dev/null @@ -1,23 +0,0 @@ -/* - * COPYRIGHT (c) 2021. - * On-Line Applications Research Corporation (OAR). - * - * 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 <bsp.h> -#include <bsp/fdt.h> - -#include BSP_MICROBLAZE_FPGA_DTB_HEADER_PATH - -const void *bsp_fdt_get(void) -{ - return system_dtb; -} - -uint32_t bsp_fdt_map_intr(const uint32_t *intr, size_t icells) -{ - return intr[0]; -} diff --git a/bsps/microblaze/microblaze_fpga/fs/jffs2_qspi.c b/bsps/microblaze/microblaze_fpga/fs/jffs2_qspi.c index 39328b6b7c..49859a03f1 100644 --- a/bsps/microblaze/microblaze_fpga/fs/jffs2_qspi.c +++ b/bsps/microblaze/microblaze_fpga/fs/jffs2_qspi.c @@ -46,6 +46,7 @@ #include <rtems/jffs2.h> #include <rtems/libio.h> +#include <bsp.h> #include <bsp/jffs2_qspi.h> #define BLOCK_SIZE (64UL * 1024UL) @@ -286,12 +287,24 @@ int microblaze_jffs2_initialize( const char* mount_dir ) int rv = 0; int fd = -1; + uintptr_t mblaze_spi_base = try_get_prop_from_device_tree( + "xlnx,xps-spi-2.00.a", + "reg", + BSP_MICROBLAZE_FPGA_SPI_BASE + ); + + rtems_vector_number mblaze_spi_irq_num = try_get_prop_from_device_tree( + "xlnx,xps-spi-2.00.a", + "interrupts", + BSP_MICROBLAZE_FPGA_SPI_IRQ_NUM + ); + rv = spi_bus_register_xilinx_axi( BUS_PATH, - BSP_MICROBLAZE_FPGA_SPI_BASE, + mblaze_spi_base, FLASH_PAGE_SIZE, FLASH_NUM_CS, - BSP_MICROBLAZE_FPGA_SPI_IRQ_NUM + mblaze_spi_irq_num ); if ( rv != 0 ) { return rv; diff --git a/bsps/microblaze/microblaze_fpga/gpio/microblaze-gpio.c b/bsps/microblaze/microblaze_fpga/gpio/microblaze-gpio.c new file mode 100644 index 0000000000..5444052b9e --- /dev/null +++ b/bsps/microblaze/microblaze_fpga/gpio/microblaze-gpio.c @@ -0,0 +1,292 @@ +/* SPDX-License-Identifier: BSD-2-Clause */ + +/** + * @file + * + * @ingroup RTEMSBSPsMicroblaze + * + * @brief MicroBlaze AXI GPIO implementation + */ + +/* + * Copyright (C) 2022 On-Line Applications Research Corporation (OAR) + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#include <assert.h> + +#include <bsp/fatal.h> +#include <bsp/fdt.h> +#include <bsp/microblaze-gpio.h> + +#include <libfdt.h> + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + +#ifdef BSP_MICROBLAZE_FPGA_USE_FDT +rtems_status_code microblaze_gpio_init_context_from_fdt( + Microblaze_GPIO_context *context, + int index +) +{ + if ( context == NULL ) { + return RTEMS_INVALID_ADDRESS; + } + + const char* compatible = "xlnx,xps-gpio-1.00.a"; + const void *fdt = bsp_fdt_get(); + int node = fdt_node_offset_by_compatible( fdt, -1, compatible ); + if ( node < 0 ) { + return RTEMS_INVALID_NUMBER; + } + + /* Get the desired GPIO node if index is greater than zero. */ + for(int i = 0; i < index; i++) { + node = fdt_node_offset_by_compatible( fdt, node, compatible ); + if ( node < 0 ) { + return RTEMS_INVALID_NUMBER; + } + } + + const uint32_t *prop; + prop = fdt_getprop( fdt, node, "reg", NULL ); + if ( prop != NULL ) { + context->regs = (Microblaze_GPIO_registers *) fdt32_to_cpu( prop[0] ); + } else { + return RTEMS_INVALID_NUMBER; + } + + prop = fdt_getprop( fdt, node, "xlnx,is-dual", NULL ); + if ( prop != NULL ) { + context->is_dual = fdt32_to_cpu( prop[0] ) != 0 ? true : false; + } else { + return RTEMS_INVALID_NUMBER; + } + + prop = fdt_getprop( fdt, node, "xlnx,interrupt-present", NULL ); + if ( prop != NULL ) { + context->has_interrupts = fdt32_to_cpu( prop[0] ) != 0 ? true : false; + } else { + return RTEMS_INVALID_NUMBER; + } + + if ( context->has_interrupts ) { + prop = fdt_getprop( fdt, node, "interrupts", NULL ); + if ( prop != NULL ) { + context->irq = fdt32_to_cpu( prop[0] ); + } else { + return RTEMS_INVALID_NUMBER; + } + } + + return RTEMS_SUCCESSFUL; +} +#endif /* BSP_MICROBLAZE_FPGA_USE_FDT */ + +void microblaze_gpio_set_data_direction( + Microblaze_GPIO_context *ctx, + uint32_t channel, + uint32_t mask +) +{ + assert( channel == 1 || (ctx->is_dual && channel == 2) ); + + if ( channel == 1 ) { + ctx->regs->gpio_tri = mask; + } else if ( ctx->is_dual && channel == 2 ) { + ctx->regs->gpio2_tri = mask; + } +} + +uint32_t microblaze_gpio_get_data_direction( + Microblaze_GPIO_context *ctx, + uint32_t channel +) +{ + assert( channel == 1 || (ctx->is_dual && channel == 2) ); + + if ( channel == 1 ) { + return ctx->regs->gpio_tri; + } else if ( ctx->is_dual && channel == 2 ) { + return ctx->regs->gpio2_tri; + } + + return 0; +} + +uint32_t microblaze_gpio_discrete_read( + Microblaze_GPIO_context *ctx, + uint32_t channel +) +{ + assert( channel == 1 || (ctx->is_dual && channel == 2) ); + + if ( channel == 1 ) { + return ctx->regs->gpio_data; + } else if ( ctx->is_dual && channel == 2 ) { + return ctx->regs->gpio2_tri; + } + + return 0; +} + +void microblaze_gpio_discrete_write( + Microblaze_GPIO_context *ctx, + uint32_t channel, + uint32_t mask +) +{ + assert( channel == 1 || (ctx->is_dual && channel == 2) ); + + if ( channel == 1 ) { + ctx->regs->gpio_data = mask; + } else if ( ctx->is_dual && channel == 2 ) { + ctx->regs->gpio2_tri = mask; + } +} + +void microblaze_gpio_discrete_set( + Microblaze_GPIO_context *ctx, + uint32_t channel, + uint32_t mask +) +{ + assert( channel == 1 || (ctx->is_dual && channel == 2) ); + + if ( channel == 1 ) { + ctx->regs->gpio_data |= mask; + } else if ( ctx->is_dual && channel == 2 ) { + ctx->regs->gpio2_tri |= mask; + } +} + +void microblaze_gpio_discrete_clear( + Microblaze_GPIO_context *ctx, + uint32_t channel, + uint32_t mask +) +{ + assert( channel == 1 || (ctx->is_dual && channel == 2) ); + + if ( channel == 1 ) { + ctx->regs->gpio_data &= ~mask; + } else if ( ctx->is_dual && channel == 2 ) { + ctx->regs->gpio2_tri &= ~mask; + } +} + +rtems_vector_number microblaze_gpio_get_irq( Microblaze_GPIO_context *ctx ) +{ + return ctx->irq; +} + +void microblaze_gpio_interrupt_global_enable( Microblaze_GPIO_context *ctx ) +{ + assert( ctx->has_interrupts ); + + if ( ctx->has_interrupts ) { + ctx->regs->gier = GLOBAL_INTERRUPT_REGISTER_ENABLE; + } +} + +void microblaze_gpio_interrupt_global_disable( Microblaze_GPIO_context *ctx ) +{ + assert( ctx->has_interrupts ); + + if ( ctx->has_interrupts ) { + ctx->regs->gier = 0x0; + } +} + +void microblaze_gpio_interrupt_enable( + Microblaze_GPIO_context *ctx, + uint32_t channel +) +{ + assert( ctx->has_interrupts ); + assert( channel == 1 || (ctx->is_dual && channel == 2) ); + + if ( ctx->has_interrupts ) { + if ( channel == 1 ) { + ctx->regs->ip_ier |= CHANNEL_1_INTERRUPT_REGISTER; + } else if ( ctx->is_dual && channel == 2 ) { + ctx->regs->ip_ier |= CHANNEL_2_INTERRUPT_REGISTER; + } + } +} + +void microblaze_gpio_interrupt_disable( + Microblaze_GPIO_context *ctx, + uint32_t channel +) +{ + assert( channel == 1 || (ctx->is_dual && channel == 2) ); + + if ( channel == 1 ) { + ctx->regs->ip_ier &= ~CHANNEL_1_INTERRUPT_REGISTER; + } else if ( ctx->is_dual && channel == 2 ) { + ctx->regs->ip_ier &= ~CHANNEL_2_INTERRUPT_REGISTER; + } +} + +void microblaze_gpio_interrupt_clear( + Microblaze_GPIO_context *ctx, + uint32_t channel +) +{ + assert( channel == 1 || (ctx->is_dual && channel == 2) ); + + if ( channel == 1 ) { + ctx->regs->ip_isr &= CHANNEL_1_INTERRUPT_REGISTER; + } else if ( ctx->is_dual && channel == 2 ) { + ctx->regs->ip_isr &= CHANNEL_2_INTERRUPT_REGISTER; + } +} + +uint32_t microblaze_gpio_interrupt_get_enabled( Microblaze_GPIO_context *ctx ) +{ + assert( ctx->has_interrupts ); + + if ( ctx->has_interrupts ) { + return ctx->regs->ip_ier; + } + + return 0; +} + +uint32_t microblaze_gpio_interrupt_get_status( Microblaze_GPIO_context *ctx ) +{ + assert( ctx->has_interrupts ); + + if ( ctx->has_interrupts ) { + return ctx->regs->ip_isr; + } + + return 0; +} + +#ifdef __cplusplus +} +#endif /* __cplusplus */ diff --git a/bsps/microblaze/microblaze_fpga/include/bsp.h b/bsps/microblaze/microblaze_fpga/include/bsp.h index 93cf0e4b34..6890f33395 100644 --- a/bsps/microblaze/microblaze_fpga/include/bsp.h +++ b/bsps/microblaze/microblaze_fpga/include/bsp.h @@ -43,17 +43,23 @@ extern "C" { #include <bspopts.h> #include <bsp/default-initial-extension.h> +#include <bsp/microblaze-fdt-support.h> #include <rtems.h> +#ifdef BSP_MICROBLAZE_FPGA_USE_FDT #define BSP_FDT_IS_SUPPORTED +#ifndef BSP_START_COPY_FDT_FROM_U_BOOT extern const unsigned char system_dtb[]; extern const size_t system_dtb_size; +#endif /* BSP_START_COPY_FDT_FROM_U_BOOT */ +#endif /* BSP_MICROBLAZE_FPGA_USE_FDT */ void microblaze_enable_icache(void); void microblaze_enable_dcache(void); void microblaze_invalidate_icache(void); void microblaze_invalidate_dcache(void); +void microblaze_invalidate_dcache_range(unsigned int cacheaddr, unsigned int len); #ifdef __cplusplus } diff --git a/bsps/microblaze/microblaze_fpga/include/bsp/intc.h b/bsps/microblaze/microblaze_fpga/include/bsp/intc.h index df4554386d..c270c7464f 100644 --- a/bsps/microblaze/microblaze_fpga/include/bsp/intc.h +++ b/bsps/microblaze/microblaze_fpga/include/bsp/intc.h @@ -65,8 +65,6 @@ typedef struct { uint32_t ilr; } Microblaze_INTC; -#define _Microblaze_INTC ((volatile Microblaze_INTC *) BSP_MICROBLAZE_FPGA_INTC_BASE) - #ifdef __cplusplus } #endif /* __cplusplus */ diff --git a/bsps/microblaze/microblaze_fpga/include/bsp/microblaze-gpio.h b/bsps/microblaze/microblaze_fpga/include/bsp/microblaze-gpio.h new file mode 100644 index 0000000000..e8f569c8fd --- /dev/null +++ b/bsps/microblaze/microblaze_fpga/include/bsp/microblaze-gpio.h @@ -0,0 +1,329 @@ +/* SPDX-License-Identifier: BSD-2-Clause */ + +/** + * @file + * + * @ingroup RTEMSBSPsMicroblaze + * + * @brief MicroBlaze AXI GPIO definitions + */ + +/* + * Copyright (C) 2022 On-Line Applications Research Corporation (OAR) + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef LIBBSP_MICROBLAZE_FPGA_MICROBLAZE_GPIO_H +#define LIBBSP_MICROBLAZE_FPGA_MICROBLAZE_GPIO_H + +#include <bspopts.h> +#include <bsp/utility.h> +#include <rtems.h> + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + +typedef struct { + /* Channel 1 data values */ + + /* + * Used to read general purpose input ports and write to general purpose + * output ports from channel 1. + */ + volatile uint32_t gpio_data; + + /* + * The 3-state control register for channel 1 is used for the dynamic + * configuration of ports as input or output. When a bit is set to 1, the + * corresponding I/O port is an input port. When a bit is set to 0, it is an + * output port. + */ + volatile uint32_t gpio_tri; + + /* Channel 2 data values */ + + /* + * Used to read general purpose input ports and write to general purpose + * output ports from channel 2. + */ + volatile uint32_t gpio2_data; + + /* + * The 3-state control register for channel 2 is used for the dynamic + * configuration of ports as input or output. When a bit is set to 1, the + * corresponding I/O port is an input port. When a bit is set to 0, it is an + * output port. + */ + volatile uint32_t gpio2_tri; + + char _unused[272]; + + /* Only the 31st bit is used to enable interrupts globally */ +#define GLOBAL_INTERRUPT_REGISTER_ENABLE BSP_BIT32(31) + + /* + * Global Interrupt Enable Register + * + * Determines whether interrupts are enabled or disabled. + * + * 0 - Disabled + * 1 - Enabled + */ + volatile uint32_t gier; + + char _unused2[12]; + + /* Used with ip_isr and ip_ier member variables */ +#define CHANNEL_1_INTERRUPT_REGISTER BSP_BIT32(0) +#define CHANNEL_2_INTERRUPT_REGISTER BSP_BIT32(1) + + /* + * IP Status Registers + * + * Contains the status bit for each channel. + * + * 0 - Disabled + * 1 - Enabled + */ + volatile uint32_t ip_isr; + + char _unused3[4]; + + /* + * IP Interrupt Enable Register + * + * Provides the ability to independtly control whether interrupts for each + * channel are enabled or disabled. + * + * 0 - No Channel input interrupt + * 1 - Channel input interrupt + */ + volatile uint32_t ip_ier; +} Microblaze_GPIO_registers; + +typedef struct { + Microblaze_GPIO_registers *regs; + bool is_dual; + uint32_t irq; + bool has_interrupts; +} Microblaze_GPIO_context; + +#ifdef BSP_MICROBLAZE_FPGA_USE_FDT +/** + * @brief Initialize GPIO context from FDT. + * + * @param[in] context the GPIO context to initialize + * @param[in] index the zero-based GPIO index in the FDT + * + * @retval RTEMS_SUCCESSFUL on success + * @retval RTEMS_INVALID_NUMBER if the index is invalid or the node is missing a + * required property + * @retval RTEMS_INVALID_ADDRESS if the context is NULL + */ +rtems_status_code microblaze_gpio_init_context_from_fdt( + Microblaze_GPIO_context *context, + int index +); +#endif /* BSP_MICROBLAZE_FPGA_USE_FDT */ + +/** + * @brief Set pin configuration for the specified GPIO channel. + * + * Changes the pin configuration for a channel. Bits set to 0 are output, and + * bits set to 1 are input. + * + * @param[in] ctx the GPIO context + * @param[in] channel the GPIO channel + * @param[in] mask the mask to be applied to @ channel + * + * @retval None + */ +void microblaze_gpio_set_data_direction( + Microblaze_GPIO_context *ctx, + uint32_t channel, + uint32_t mask +); + +/** + * @brief Get pin configuration for specified GPIO channel. + * + * Gets the current pin configuration for a specified GPIO channel. Bits set to + * 0 are output, and bits set to 1 are input. + * + * @param[in] ctx the GPIO context + * @param[in] channel the GPIO channel + * + * @retval bitmask specifiying which pins on a channel are input or output + */ +uint32_t microblaze_gpio_get_data_direction( + Microblaze_GPIO_context *ctx, + uint32_t channel +); + +/** + * @brief Reads data for specified GPIO channel. + * + * @param[in] channel the GPIO channel + * + * @retval Current values in discretes register. + */ +uint32_t microblaze_gpio_discrete_read( + Microblaze_GPIO_context *ctx, + uint32_t channel +); + +/** + * @brief Writes to data register for specified GPIO channel. + * + * @param[in] ctx the GPIO context + * @param[in] channel the GPIO channel + * @param[in] mask the mask to be applied to @ channel + * + * @retval None + */ +void microblaze_gpio_discrete_write( + Microblaze_GPIO_context *ctx, + uint32_t channel, + uint32_t mask +); + +/** + * @brief Set bits to 1 on specified GPIO channel. + * + * @param[in] ctx the GPIO context + * @param[in] channel the GPIO channel + * @param[in] mask the mask to be applied to @ channel + * + * @retval None + */ +void microblaze_gpio_discrete_set( + Microblaze_GPIO_context *ctx, + uint32_t channel, + uint32_t mask +); + +/** + * @brief Set bits to 0 on specified GPIO channel. + * + * @param[in] ctx the GPIO context + * @param[in] channel the GPIO channel + * @param[in] mask the mask to be applied to @ channel + * + * @retval None + */ +void microblaze_gpio_discrete_clear( + Microblaze_GPIO_context *ctx, + uint32_t channel, + uint32_t mask +); + +/** + * @brief Returns the vector number of the interrupt handler. + * + * @param[in] ctx the GPIO context + * + * @retval the vector number + */ +rtems_vector_number microblaze_gpio_get_irq( Microblaze_GPIO_context *ctx ); + +/** + * @brief Turns on interrupts globally. + * + * @param[in] ctx the GPIO context + * + * @retval None + */ +void microblaze_gpio_interrupt_global_enable( Microblaze_GPIO_context *ctx ); + +/** + * @brief Turns off interrupts globally. + * + * @param[in] ctx the GPIO context + * + * @retval None + */ +void microblaze_gpio_interrupt_global_disable( Microblaze_GPIO_context *ctx ); + +/** + * @brief Enables interrupts on specified channel + * + * @param[in] ctx the GPIO context + * @param[in] channel the channel to enable interrupts on + * + * @retval None + */ +void microblaze_gpio_interrupt_enable( + Microblaze_GPIO_context *ctx, + uint32_t channel +); + +/** + * @brief Disables interrupts on specified channel + * + * @param[in] ctx the GPIO context + * @param[in] channel the channel to turn interrupts on for + * + * @retval None + */ +void microblaze_gpio_interrupt_disable( + Microblaze_GPIO_context *ctx, + uint32_t channel +); + +/** + * @brief Clear status of interrupt signals on a specific channel + * + * @param[in] ctx the GPIO context + * @param[in] channel the channel to clear the interrupt pending status from + * + * @retval None + */ +void microblaze_gpio_interrupt_clear( + Microblaze_GPIO_context *ctx, + uint32_t channel +); + +/** + * @brief Return a bitmask of the interrupts that are enabled + * + * @param[in] ctx the GPIO context + * + * @retval the bitmask of enabled interrupts + */ +uint32_t microblaze_gpio_interrupt_get_enabled( Microblaze_GPIO_context *ctx ); + +/** + * @brief Return a bitmask of the status of the interrupt signals + * + * @param[in] ctx the GPIO context + * + * @retval bitmask containing statuses of interrupt signals + */ +uint32_t microblaze_gpio_interrupt_get_status( Microblaze_GPIO_context *ctx ); + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + +#endif /* LIBBSP_MICROBLAZE_FPGA_MICROBLAZE_GPIO_H */ diff --git a/bsps/microblaze/microblaze_fpga/include/bsp/timer.h b/bsps/microblaze/microblaze_fpga/include/bsp/timer.h index 562fdd79b0..bd8661d47c 100644 --- a/bsps/microblaze/microblaze_fpga/include/bsp/timer.h +++ b/bsps/microblaze/microblaze_fpga/include/bsp/timer.h @@ -60,8 +60,6 @@ typedef struct { uint32_t tcr0; } Microblaze_Timer; -#define _Microblaze_Timer ((volatile Microblaze_Timer *) BSP_MICROBLAZE_FPGA_TIMER_BASE) - #ifdef __cplusplus } #endif /* __cplusplus */ diff --git a/bsps/microblaze/microblaze_fpga/irq/irq.c b/bsps/microblaze/microblaze_fpga/irq/irq.c index 7148aed8cd..f14eddc799 100644 --- a/bsps/microblaze/microblaze_fpga/irq/irq.c +++ b/bsps/microblaze/microblaze_fpga/irq/irq.c @@ -33,15 +33,17 @@ * POSSIBILITY OF SUCH DAMAGE. */ +#include <bsp.h> #include <bsp/intc.h> #include <bsp/irq-generic.h> #include <rtems/score/cpu.h> +static volatile Microblaze_INTC *mblaze_intc; + static void ack_interrupt( uint8_t source ) { - volatile Microblaze_INTC *intc = _Microblaze_INTC; - intc->iar = 0x1 << source; + mblaze_intc->iar = 0x1 << source; } rtems_status_code bsp_interrupt_get_attributes( @@ -79,8 +81,7 @@ rtems_status_code bsp_interrupt_clear( rtems_vector_number vector ) { bsp_interrupt_assert( bsp_interrupt_is_valid_vector( vector ) ); - volatile Microblaze_INTC *intc = _Microblaze_INTC; - intc->iar = 0x1 << vector; + mblaze_intc->iar = 0x1 << vector; return RTEMS_SUCCESSFUL; } @@ -93,10 +94,9 @@ rtems_status_code bsp_interrupt_vector_is_enabled( bsp_interrupt_assert( bsp_interrupt_is_valid_vector( vector ) ); bsp_interrupt_assert( enabled != NULL ); - volatile Microblaze_INTC *intc = _Microblaze_INTC; uint32_t mask = 1 << vector; - *enabled = (intc->ier & mask) != 0; + *enabled = (mblaze_intc->ier & mask) != 0; return RTEMS_SUCCESSFUL; } @@ -104,10 +104,9 @@ rtems_status_code bsp_interrupt_vector_enable( rtems_vector_number vector ) { bsp_interrupt_assert( bsp_interrupt_is_valid_vector( vector ) ); - volatile Microblaze_INTC *intc = _Microblaze_INTC; uint32_t mask = 1 << vector; - intc->ier |= mask; + mblaze_intc->ier |= mask; return RTEMS_SUCCESSFUL; } @@ -116,32 +115,35 @@ rtems_status_code bsp_interrupt_vector_disable( rtems_vector_number vector ) { bsp_interrupt_assert( bsp_interrupt_is_valid_vector( vector ) ); - volatile Microblaze_INTC *intc = _Microblaze_INTC; uint32_t mask = 1 << vector; - intc->ier &= ~mask; + mblaze_intc->ier &= ~mask; return RTEMS_SUCCESSFUL; } void bsp_interrupt_facility_initialize( void ) { - volatile Microblaze_INTC *intc = _Microblaze_INTC; /* * Enable HW interrupts on the interrupt controller. This happens before * interrupts are enabled on the processor. */ - intc->mer = MICROBLAZE_INTC_MER_ME | MICROBLAZE_INTC_MER_HIE; + mblaze_intc = (volatile Microblaze_INTC *) try_get_prop_from_device_tree( + "xlnx,xps-intc-1.00.a", + "reg", + BSP_MICROBLAZE_FPGA_INTC_BASE + ); + + mblaze_intc->mer = MICROBLAZE_INTC_MER_ME | MICROBLAZE_INTC_MER_HIE; } void bsp_interrupt_dispatch( uint32_t source ) { - volatile Microblaze_INTC *intc = _Microblaze_INTC; uint32_t vector_number = 0; if ( source == 0xFF ) { /* Read interrupt controller to get the source */ - vector_number = intc->isr & intc->ier; + vector_number = mblaze_intc->isr & mblaze_intc->ier; /* Handle and the first interrupt that is set */ uint8_t interrupt_status = 0; @@ -149,13 +151,13 @@ void bsp_interrupt_dispatch( uint32_t source ) interrupt_status = vector_number >> i & 0x1; if ( interrupt_status != 0 ) { /* save current ILR */ - uint32_t interrupt_levels = intc->ilr; + uint32_t interrupt_levels = mblaze_intc->ilr; /* set ILR to block out every interrupt less than or equal to priority of i */ - intc->ilr = 0xFFFFFFFF >> (32 - i); + mblaze_intc->ilr = 0xFFFFFFFF >> (32 - i); bsp_interrupt_handler_dispatch( i ); ack_interrupt( i ); /* restore ILR */ - intc->ilr = interrupt_levels; + mblaze_intc->ilr = interrupt_levels; break; } } diff --git a/bsps/microblaze/microblaze_fpga/start/crtinit.S b/bsps/microblaze/microblaze_fpga/start/crtinit.S index d56bee3b19..6c7fc3af23 100644 --- a/bsps/microblaze/microblaze_fpga/start/crtinit.S +++ b/bsps/microblaze/microblaze_fpga/start/crtinit.S @@ -30,6 +30,8 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ +#include <bspopts.h> + .globl _crtinit .align 2 .ent _crtinit @@ -75,7 +77,9 @@ _crtinit: brlid r15, __init /* Invoke language initialization functions */ nop #endif /* __rtems__ */ - +#ifdef BSP_START_COPY_FDT_FROM_U_BOOT /* Boot loaders may pass the device tree in r5 */ + brlid r15, bsp_fdt_copy /* Do not touch r5 until bsp_fdt_copy() is called */ +#endif /* BSP_START_COPY_FDT_FROM_U_BOOT */ addi r6, r0, 0 /* Initialize argc = 1 and argv = NULL and envp = NULL */ addi r7, r0, 0 #ifndef __rtems__ diff --git a/bsps/microblaze/microblaze_fpga/start/microblaze_invalidate_dcache_range.S b/bsps/microblaze/microblaze_fpga/start/microblaze_invalidate_dcache_range.S new file mode 100644 index 0000000000..89d5fff16b --- /dev/null +++ b/bsps/microblaze/microblaze_fpga/start/microblaze_invalidate_dcache_range.S @@ -0,0 +1,104 @@ +/****************************************************************************** +* Copyright (c) 2008 - 2020 Xilinx, Inc. All rights reserved. +* SPDX-License-Identifier: MIT +******************************************************************************/ +/****************************************************************************** +* +* +* microblaze_invalidate_dcache_range (unsigned int cacheaddr, unsigned int len) +* +* Invalidate a Dcache range +* +* Parameters: +* 'cacheaddr' - address in the Dcache where invalidation begins +* 'len ' - length (in bytes) worth of Dcache to be invalidated +* +* +*******************************************************************************/ + +#include <bspopts.h> + +#define MICROBLAZE_MSR_DCACHE_ENABLE 0x00000080 +#define MICROBLAZE_MSR_INTR_ENABLE 0x00000002 + +#ifndef XPAR_MICROBLAZE_USE_DCACHE +#define XPAR_MICROBLAZE_USE_DCACHE 1 +#endif + +#ifndef XPAR_MICROBLAZE_ALLOW_DCACHE_WR +#define XPAR_MICROBLAZE_ALLOW_DCACHE_WR 1 +#endif + +#ifndef XPAR_MICROBLAZE_DCACHE_USE_WRITEBACK +#define MB_VERSION_LT_v720 +#define MB_HAS_WRITEBACK_SET 0 +#else +#define MB_HAS_WRITEBACK_SET XPAR_MICROBLAZE_DCACHE_USE_WRITEBACK +#endif + + .text + .globl microblaze_invalidate_dcache_range + .ent microblaze_invalidate_dcache_range + .align 2 + +microblaze_invalidate_dcache_range: +#if (XPAR_MICROBLAZE_USE_DCACHE==1) && (XPAR_MICROBLAZE_ALLOW_DCACHE_WR==1) + +#ifdef MB_VERSION_LT_v720 /* Disable Dcache and interrupts before invalidating */ + mfs r9, rmsr + andi r10, r9, ~(MICROBLAZE_MSR_DCACHE_ENABLE | MICROBLAZE_MSR_INTR_ENABLE) + mts rmsr, r10 +#endif + + BEQI r6, L_done /* Skip loop if size is zero */ + + ADD r6, r5, r6 /* Compute end address */ + ADDIK r6, r6, -1 + + ANDI r6, r6, -(4 * BSP_MICROBLAZE_FPGA_DCACHE_LINE_LEN) /* Align end down to cache line */ + ANDI r5, r5, -(4 * BSP_MICROBLAZE_FPGA_DCACHE_LINE_LEN) /* Align start down to cache line */ + +#if MB_HAS_WRITEBACK_SET == 0 /* Use a different scheme for MB version < v7.20 or when caches are write-through */ + +L_start: + CMPU r18, r5, r6 /* Are we at the end? */ + BLTI r18, L_done + + wdc r5, r0 + +#if defined (__arch64__ ) + addlik r5, r5, (BSP_MICROBLAZE_FPGA_DCACHE_LINE_LEN * 4) /* Increment the address by 4 */ + breai L_start /* Branch to the beginning of the loop */ +#else + brid L_start /* Branch to the beginning of the loop */ + addik r5, r5, (BSP_MICROBLAZE_FPGA_DCACHE_LINE_LEN * 4) /* Increment the address by 4 (delay slot) */ +#endif +#else + + RSUBK r6, r5, r6 + /* r6 will now contain (count of bytes - (4 * BSP_MICROBLAZE_FPGA_DCACHE_LINE_LEN)) */ +L_start: + wdc.clear r5, r6 /* Invalidate the cache line only if the address matches */ +#if defined (__arch64__ ) + addlik r6, r6, -(BSP_MICROBLAZE_FPGA_DCACHE_LINE_LEN * 4) + beagei r6, L_start +#else + bneid r6, L_start + addik r6, r6, -(BSP_MICROBLAZE_FPGA_DCACHE_LINE_LEN * 4) +#endif + +#endif + +L_done: + rtsd r15, 8 +#ifdef MB_VERSION_LT_v720 /* restore MSR only for MB version < v7.20 */ + mts rmsr, r9 +#else + nop +#endif + +#else + rtsd r15, 8 + nop +#endif + .end microblaze_invalidate_dcache_range diff --git a/bsps/microblaze/shared/dev/serial/uartlite.c b/bsps/microblaze/shared/dev/serial/uartlite.c index 7387e22635..611c339371 100644 --- a/bsps/microblaze/shared/dev/serial/uartlite.c +++ b/bsps/microblaze/shared/dev/serial/uartlite.c @@ -35,6 +35,7 @@ #include <bsp/irq.h> #include <dev/serial/uartlite.h> +#include <bspopts.h> #ifdef BSP_MICROBLAZE_FPGA_CONSOLE_INTERRUPTS static void microblaze_uart_interrupt( void *arg ) @@ -47,8 +48,11 @@ static void microblaze_uart_interrupt( void *arg ) rtems_termios_enqueue_raw_characters( tty, &c, 1 ); } - while ( ctx->transmitting && !XUartLite_IsTransmitEmpty( ctx ) ) { - rtems_termios_dequeue_characters( tty, 1 ); + if ( ctx->transmitting && XUartLite_IsTransmitEmpty( ctx->address ) ) { + size_t sent = ctx->tx_queued; + ctx->transmitting = false; + ctx->tx_queued = 0; + rtems_termios_dequeue_characters( tty, sent ); } } #endif @@ -69,8 +73,9 @@ static bool uart_first_open( #ifdef BSP_MICROBLAZE_FPGA_CONSOLE_INTERRUPTS XUartLite_EnableIntr( ctx->address ); + sc = rtems_interrupt_handler_install( - 1, + ctx->irq, "UART", RTEMS_INTERRUPT_SHARED, microblaze_uart_interrupt, @@ -79,6 +84,8 @@ static bool uart_first_open( if ( sc != RTEMS_SUCCESSFUL ) { return false; } + + ctx->tty = tty; #endif return true; @@ -118,10 +125,17 @@ static void uart_write( #ifdef BSP_MICROBLAZE_FPGA_CONSOLE_INTERRUPTS if ( n > 0 ) { + size_t remaining = n; + const char *p = &s[0]; + + while (!XUartLite_IsTransmitFull( ctx->address ) && remaining > 0) { + XUartLite_SendByte( ctx->address, *p ); + p++; + remaining--; + } + ctx->transmitting = true; - XUartLite_SendByte( ctx->address, s[0] ); - } else { - ctx->transmitting = false; + ctx->tx_queued = n - remaining; } #else size_t i = 0; diff --git a/bsps/microblaze/shared/fdt/microblaze-fdt-support.c b/bsps/microblaze/shared/fdt/microblaze-fdt-support.c new file mode 100644 index 0000000000..b1d8d186c4 --- /dev/null +++ b/bsps/microblaze/shared/fdt/microblaze-fdt-support.c @@ -0,0 +1,106 @@ +/* SPDX-License-Identifier: BSD-2-Clause */ + +/* + * Copyright (C) 2022 On-Line Applications Research Corporation (OAR) + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#include <bspopts.h> +#include <bsp/microblaze-fdt-support.h> +#include <bsp/fdt.h> + +#include <libfdt.h> + +#ifdef BSP_START_COPY_FDT_FROM_U_BOOT +/* use external dtb provided by u-boot */ +#include <sys/param.h> + +#ifndef BSP_FDT_BLOB_SIZE_MAX +#define BSP_FDT_BLOB_SIZE_MAX 0 +#endif + +static RTEMS_ALIGNED(8) uint32_t +system_dtb[BSP_FDT_BLOB_SIZE_MAX / sizeof(uint32_t)]; + +void bsp_fdt_copy(const void *src) +{ + const volatile uint32_t *s = (const uint32_t *) src; + uint32_t *d = RTEMS_DECONST(uint32_t *, &system_dtb[0]); + + if (s != d) { + size_t m = MIN(sizeof(system_dtb), fdt_totalsize(src)); + size_t aligned_size = roundup2(m, CPU_CACHE_LINE_BYTES); + size_t n = (m + sizeof(*d) - 1) / sizeof(*d); + size_t i; + + for (i = 0; i < n; ++i) { + d[i] = s[i]; + } + + rtems_cache_flush_multiple_data_lines(d, aligned_size); + } +} +#endif /* BSP_START_COPY_FDT_FROM_U_BOOT */ + +#ifdef BSP_MICROBLAZE_FPGA_USE_FDT +#ifndef BSP_START_COPY_FDT_FROM_U_BOOT +/* use internal bsp dtb */ +#include BSP_MICROBLAZE_FPGA_DTB_HEADER_PATH +#endif /* BSP_START_COPY_FDT_FROM_U_BOOT */ + +const void *bsp_fdt_get(void) +{ + return system_dtb; +} + +uint32_t bsp_fdt_map_intr(const uint32_t *intr, size_t icells) +{ + return intr[0]; +} +#endif /* BSP_MICROBLAZE_FPGA_USE_FDT */ + +uint32_t try_get_prop_from_device_tree( + const char *compatible, + const char *prop_name, + uint32_t default_value +) +{ + uint32_t value = default_value; + +#ifdef BSP_MICROBLAZE_FPGA_USE_FDT + const void *fdt = bsp_fdt_get(); + int node = fdt_node_offset_by_compatible( fdt, -1, compatible ); + if ( node < 0 ) { + return default_value; + } + + const uint32_t *prop = fdt_getprop( fdt, node, prop_name, NULL ); + if ( prop == NULL ) { + return default_value; + } + + value = fdt32_to_cpu( prop[0] ); +#endif /* BSP_MICROBLAZE_FPGA_USE_FDT */ + + return value; +} |