summaryrefslogtreecommitdiffstats
path: root/bsps/microblaze
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--bsps/microblaze/include/bsp/microblaze-fdt-support.h65
-rw-r--r--bsps/microblaze/include/dev/serial/uartlite.h5
-rw-r--r--bsps/microblaze/include/dev/serial/uartlite_l.h18
-rw-r--r--bsps/microblaze/microblaze_fpga/clock/clock.c58
-rw-r--r--bsps/microblaze/microblaze_fpga/console/console-io.c190
-rw-r--r--bsps/microblaze/microblaze_fpga/console/debug-io.c29
-rw-r--r--bsps/microblaze/microblaze_fpga/fdt/bsp_fdt.c23
-rw-r--r--bsps/microblaze/microblaze_fpga/fs/jffs2_qspi.c17
-rw-r--r--bsps/microblaze/microblaze_fpga/gpio/microblaze-gpio.c292
-rw-r--r--bsps/microblaze/microblaze_fpga/include/bsp.h6
-rw-r--r--bsps/microblaze/microblaze_fpga/include/bsp/intc.h2
-rw-r--r--bsps/microblaze/microblaze_fpga/include/bsp/microblaze-gpio.h329
-rw-r--r--bsps/microblaze/microblaze_fpga/include/bsp/timer.h2
-rw-r--r--bsps/microblaze/microblaze_fpga/irq/irq.c36
-rw-r--r--bsps/microblaze/microblaze_fpga/start/crtinit.S6
-rw-r--r--bsps/microblaze/microblaze_fpga/start/microblaze_invalidate_dcache_range.S104
-rw-r--r--bsps/microblaze/shared/dev/serial/uartlite.c26
-rw-r--r--bsps/microblaze/shared/fdt/microblaze-fdt-support.c106
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 = &microblaze_uart_fns,
- .context = &microblaze_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 = &microblaze_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;
+}