soc: neorv32: update to support NEORV32 v1.11.1

Update the NEORV32 SoC, peripheral drivers, and board to support NEORV32
v1.11.1. Notable changes include:

- Optional RISC-V ISA Kconfigs are now selected on the board level.
- Peripheral registers are now automatically reset in hardware, no need for
  software initialization code.
- The NEORV32 GPIO controller now supports 32 pins, not 64. Interrupt
  support will be submitted in a separate PR.
- Default board configuration has 64k RAM and is clocked at 18 MHz.

Signed-off-by: Henrik Brix Andersen <henrik@brixandersen.dk>
This commit is contained in:
Henrik Brix Andersen 2025-02-26 16:11:03 +00:00 committed by Benjamin Cabé
commit 63c24d9d34
20 changed files with 340 additions and 409 deletions

View file

@ -1,4 +1,4 @@
# Copyright (c) 2021 Henrik Brix Andersen <henrik@brixandersen.dk> # Copyright (c) 2021,2025 Henrik Brix Andersen <henrik@brixandersen.dk>
# SPDX-License-Identifier: Apache-2.0 # SPDX-License-Identifier: Apache-2.0
if((CONFIG_BOARD_NEORV32) AND (CONFIG_BUILD_OUTPUT_BIN)) if((CONFIG_BOARD_NEORV32) AND (CONFIG_BUILD_OUTPUT_BIN))
@ -18,7 +18,7 @@ if((CONFIG_BOARD_NEORV32) AND (CONFIG_BUILD_OUTPUT_BIN))
set_property(GLOBAL APPEND PROPERTY extra_post_build_commands set_property(GLOBAL APPEND PROPERTY extra_post_build_commands
COMMAND ${IMAGE_GEN} COMMAND ${IMAGE_GEN}
ARGS -app_img ARGS -app_vhd
${CONFIG_KERNEL_BIN_NAME}.bin ${CONFIG_KERNEL_BIN_NAME}.bin
${CONFIG_KERNEL_BIN_NAME}.vhd ${CONFIG_KERNEL_BIN_NAME}.vhd
${PROJECT_BINARY_DIR} ${PROJECT_BINARY_DIR}

View file

@ -0,0 +1,7 @@
# Copyright (c) 2021,2025 Henrik Brix Andersen <henrik@brixandersen.dk>
# SPDX-License-Identifier: Apache-2.0
config BOARD_NEORV32
select RISCV_ISA_RV32I
select RISCV_ISA_EXT_M
select ATOMIC_OPERATIONS_C

View file

@ -13,7 +13,7 @@ For more information about the NEORV32, see the following websites:
- `The NEORV32 RISC-V Processor Datasheet`_ - `The NEORV32 RISC-V Processor Datasheet`_
- `The NEORV32 RISC-V Processor User Guide`_ - `The NEORV32 RISC-V Processor User Guide`_
The currently supported version is 1.8.6. The currently supported version is NEORV32 v1.11.1.
Supported Features Supported Features
================== ==================
@ -27,7 +27,7 @@ using :ref:`devicetree overlays <use-dt-overlays>`.
System Clock System Clock
============ ============
The default board configuration assumes a system clock of 100 MHz. The clock The default board configuration assumes a system clock of 18 MHz. The clock
frequency can be overridden by changing the ``clock-frequency`` property of the frequency can be overridden by changing the ``clock-frequency`` property of the
``cpu0`` devicetree node. ``cpu0`` devicetree node.
@ -37,9 +37,10 @@ CPU
The default board configuration assumes the NEORV32 CPU implementation has the The default board configuration assumes the NEORV32 CPU implementation has the
following RISC-V ISA extensions enabled: following RISC-V ISA extensions enabled:
- C (Compresses Instructions) - I (Base Integer Instruction Set, 32-bit)
- M (Integer Multiplication and Division) - M (Integer Multiplication and Division)
- Zicsr (Control and Status Register (CSR) Instructions) - Zicsr (Control and Status Register (CSR) Instructions, always enabled)
- Zifencei (Instruction-fetch fence, always enabled)
Internal Instruction Memory Internal Instruction Memory
=========================== ===========================
@ -52,7 +53,7 @@ instruction memory can be overridden by changing the ``reg`` property of the
Internal Data Memory Internal Data Memory
==================== ====================
The default board configuration assumes the NEORV32 SoC implementation has a 32k The default board configuration assumes the NEORV32 SoC implementation has a 64k
byte internal data memory (DMEM). The size of the data memory can be overridden byte internal data memory (DMEM). The size of the data memory can be overridden
by changing the ``reg`` property of the ``dmem`` devicetree node. by changing the ``reg`` property of the ``dmem`` devicetree node.
@ -115,21 +116,21 @@ implementation with the On-Chip Debugger (OCD) and bootloader enabled.
The default board configuration uses an :ref:`openocd-debug-host-tools` The default board configuration uses an :ref:`openocd-debug-host-tools`
configuration similar to the example provided by the NEORV32 project. Other configuration similar to the example provided by the NEORV32 project. Other
JTAGs can be used by providing further arguments when building. Here is an JTAGs can be used by providing further arguments when flashing. Here is an
example for using the Flyswatter JTAG: example for using the Flyswatter JTAG @ 2 kHz:
.. zephyr-app-commands:: .. zephyr-app-commands::
:zephyr-app: samples/hello_world :zephyr-app: samples/hello_world
:board: neorv32 :board: neorv32
:goals: flash :goals: flash
:gen-args: -DBOARD_RUNNER_ARGS_openocd="--config;interface/ftdi/flyswatter.cfg;--config;neorv32.cfg;--cmd-pre-init;'adapter speed 2000'" :flash-args: --config interface/ftdi/flyswatter.cfg --config neorv32.cfg --cmd-pre-init 'adapter speed 2000'
After flashing, you should see message similar to the following in the terminal: After flashing, you should see message similar to the following in the terminal:
.. code-block:: console .. code-block:: console
*** Booting Zephyr OS build zephyr-vn.n.nn *** *** Booting Zephyr OS build zephyr-vn.n.nn ***
Hello World! neorv32 Hello World! neorv32/neorv32
Note, however, that the application was not persisted in flash memory by the Note, however, that the application was not persisted in flash memory by the
above steps. It was merely written to internal block RAM in the FPGA. It will above steps. It was merely written to internal block RAM in the FPGA. It will
@ -176,7 +177,7 @@ similar to the following in the terminal:
.. code-block:: console .. code-block:: console
*** Booting Zephyr OS build zephyr-vn.n.nn *** *** Booting Zephyr OS build zephyr-vn.n.nn ***
Hello World! neorv32 Hello World! neorv32/neorv32
.. _The NEORV32 RISC-V Processor GitHub: .. _The NEORV32 RISC-V Processor GitHub:
https://github.com/stnolting/neorv32 https://github.com/stnolting/neorv32

View file

@ -1,5 +1,5 @@
/* /*
* Copyright (c) 2021 Henrik Brix Andersen <henrik@brixandersen.dk> * Copyright (c) 2021,2025 Henrik Brix Andersen <henrik@brixandersen.dk>
* *
* SPDX-License-Identifier: Apache-2.0 * SPDX-License-Identifier: Apache-2.0
*/ */
@ -29,25 +29,9 @@
zephyr,uart-pipe = &uart0; zephyr,uart-pipe = &uart0;
}; };
soc {
imem: memory@0 {
compatible = "soc-nv-flash", "mmio-sram";
reg = <0x0 DT_SIZE_K(64)>;
};
bootrom: memory@ffff0000 {
compatible = "soc-nv-flash", "mmio-sram";
reg = <0xffff0000 DT_SIZE_K(4)>;
};
dmem: memory@80000000 {
compatible = "mmio-sram";
reg = <0x80000000 DT_SIZE_K(32)>;
};
};
leds { leds {
compatible = "gpio-leds"; compatible = "gpio-leds";
led0: led0 { led0: led0 {
gpios = <&gpio 0 GPIO_ACTIVE_HIGH>; gpios = <&gpio 0 GPIO_ACTIVE_HIGH>;
label = "LED_0"; label = "LED_0";
@ -71,7 +55,30 @@
}; };
&cpu0 { &cpu0 {
clock-frequency = <DT_FREQ_M(100)>; riscv,isa = "rv32im_zicsr_zifencei";
clock-frequency = <DT_FREQ_M(18)>;
};
&bootrom {
status = "okay";
};
&imem {
status = "okay";
reg = <0x0 DT_SIZE_K(64)>;
};
&dmem {
status = "okay";
reg = <0x80000000 DT_SIZE_K(64)>;
};
&clint {
status = "okay";
};
&mtimer {
status = "okay";
}; };
&uart0 { &uart0 {
@ -79,10 +86,6 @@
current-speed = <19200>; current-speed = <19200>;
}; };
&gpio_lo { &gpio {
status = "okay";
};
&gpio_hi {
status = "okay"; status = "okay";
}; };

View file

@ -5,7 +5,7 @@ arch: riscv
toolchain: toolchain:
- cross-compile - cross-compile
- zephyr - zephyr
ram: 32 ram: 64
flash: 64 flash: 64
supported: supported:
- gpio - gpio

View file

@ -1,7 +1,6 @@
# Copyright (c) 2021 Henrik Brix Andersen <henrik@brixandersen.dk> # Copyright (c) 2021,2025 Henrik Brix Andersen <henrik@brixandersen.dk>
# SPDX-License-Identifier: Apache-2.0 # SPDX-License-Identifier: Apache-2.0
CONFIG_SOC_NEORV32_ISA_C=y
CONFIG_SERIAL=y CONFIG_SERIAL=y
CONFIG_CONSOLE=y CONFIG_CONSOLE=y
CONFIG_UART_CONSOLE=y CONFIG_UART_CONSOLE=y

View file

@ -1,5 +1,5 @@
/* /*
* Copyright (c) 2021 Henrik Brix Andersen <henrik@brixandersen.dk> * Copyright (c) 2021,2025 Henrik Brix Andersen <henrik@brixandersen.dk>
* *
* SPDX-License-Identifier: Apache-2.0 * SPDX-License-Identifier: Apache-2.0
*/ */
@ -17,10 +17,19 @@
LOG_MODULE_REGISTER(neorv32_trng, CONFIG_ENTROPY_LOG_LEVEL); LOG_MODULE_REGISTER(neorv32_trng, CONFIG_ENTROPY_LOG_LEVEL);
/* TRNG CTRL register bits */ /* Register offsets */
#define NEORV32_TRNG_CTRL_DATA_MASK BIT_MASK(8) #define NEORV32_TRNG_CTRL 0x00
#define NEORV32_TRNG_CTRL_EN BIT(30) #define NEORV32_TRNG_DATA 0x04
#define NEORV32_TRNG_CTRL_VALID BIT(31)
/* CTRL register bits */
#define NEORV32_TRNG_CTRL_EN BIT(0)
#define NEORV32_TRNG_CTRL_FIFO_CLR BIT(1)
#define NEORV32_TRNG_CTRL_FIFO_DEPTH GENMASK(5, 2)
#define NEORV32_TRNG_CTRL_SIM_MODE BIT(6)
#define NEORV32_TRNG_CTRL_AVAIL BIT(7)
/* DATA register bits */
#define NEORV32_TRNG_DATA_MASK GENMASK(7, 0)
struct neorv32_trng_config { struct neorv32_trng_config {
const struct device *syscon; const struct device *syscon;
@ -31,14 +40,21 @@ static inline uint32_t neorv32_trng_read_ctrl(const struct device *dev)
{ {
const struct neorv32_trng_config *config = dev->config; const struct neorv32_trng_config *config = dev->config;
return sys_read32(config->base); return sys_read32(config->base + NEORV32_TRNG_CTRL);
} }
static inline void neorv32_trng_write_ctrl(const struct device *dev, uint32_t ctrl) static inline void neorv32_trng_write_ctrl(const struct device *dev, uint32_t ctrl)
{ {
const struct neorv32_trng_config *config = dev->config; const struct neorv32_trng_config *config = dev->config;
sys_write32(ctrl, config->base); sys_write32(ctrl, config->base + NEORV32_TRNG_CTRL);
}
static inline uint8_t neorv32_trng_read_data(const struct device *dev)
{
const struct neorv32_trng_config *config = dev->config;
return sys_read32(config->base + NEORV32_TRNG_DATA) & NEORV32_TRNG_DATA_MASK;
} }
static int neorv32_trng_get_entropy(const struct device *dev, uint8_t *buffer, uint16_t len) static int neorv32_trng_get_entropy(const struct device *dev, uint8_t *buffer, uint16_t len)
@ -48,8 +64,8 @@ static int neorv32_trng_get_entropy(const struct device *dev, uint8_t *buffer, u
while (len > 0) { while (len > 0) {
ctrl = neorv32_trng_read_ctrl(dev); ctrl = neorv32_trng_read_ctrl(dev);
if ((ctrl & NEORV32_TRNG_CTRL_VALID) != 0) { if ((ctrl & NEORV32_TRNG_CTRL_AVAIL) != 0) {
*buffer++ = ctrl & NEORV32_TRNG_CTRL_DATA_MASK; *buffer++ = neorv32_trng_read_data(dev);
len--; len--;
} }
} }
@ -65,8 +81,8 @@ static int neorv32_trng_get_entropy_isr(const struct device *dev, uint8_t *buffe
if ((flags & ENTROPY_BUSYWAIT) == 0) { if ((flags & ENTROPY_BUSYWAIT) == 0) {
ctrl = neorv32_trng_read_ctrl(dev); ctrl = neorv32_trng_read_ctrl(dev);
if ((ctrl & NEORV32_TRNG_CTRL_VALID) != 0) { if ((ctrl & NEORV32_TRNG_CTRL_AVAIL) != 0) {
*buffer = ctrl & NEORV32_TRNG_CTRL_DATA_MASK; *buffer = neorv32_trng_read_data(dev);
return 1; return 1;
} }
@ -93,13 +109,13 @@ static int neorv32_trng_init(const struct device *dev)
return -EINVAL; return -EINVAL;
} }
err = syscon_read_reg(config->syscon, NEORV32_SYSINFO_FEATURES, &features); err = syscon_read_reg(config->syscon, NEORV32_SYSINFO_SOC, &features);
if (err < 0) { if (err < 0) {
LOG_ERR("failed to determine implemented features (err %d)", err); LOG_ERR("failed to determine implemented features (err %d)", err);
return err; return err;
} }
if ((features & NEORV32_SYSINFO_FEATURES_IO_TRNG) == 0) { if ((features & NEORV32_SYSINFO_SOC_IO_TRNG) == 0) {
LOG_ERR("neorv32 trng not supported"); LOG_ERR("neorv32 trng not supported");
return -ENODEV; return -ENODEV;
} }

View file

@ -1,5 +1,5 @@
/* /*
* Copyright (c) 2021 Henrik Brix Andersen <henrik@brixandersen.dk> * Copyright (c) 2021,2025 Henrik Brix Andersen <henrik@brixandersen.dk>
* *
* SPDX-License-Identifier: Apache-2.0 * SPDX-License-Identifier: Apache-2.0
*/ */
@ -20,6 +20,10 @@ LOG_MODULE_REGISTER(gpio_neorv32, CONFIG_GPIO_LOG_LEVEL);
#include <zephyr/drivers/gpio/gpio_utils.h> #include <zephyr/drivers/gpio/gpio_utils.h>
/* Register offsets */
#define NEORV32_GPIO_PORT_IN 0x00
#define NEORV32_GPIO_PORT_OUT 0x04
/* Maximum number of GPIOs supported */ /* Maximum number of GPIOs supported */
#define MAX_GPIOS 32 #define MAX_GPIOS 32
@ -27,8 +31,7 @@ struct neorv32_gpio_config {
/* gpio_driver_config needs to be first */ /* gpio_driver_config needs to be first */
struct gpio_driver_config common; struct gpio_driver_config common;
const struct device *syscon; const struct device *syscon;
mm_reg_t input; mm_reg_t base;
mm_reg_t output;
}; };
struct neorv32_gpio_data { struct neorv32_gpio_data {
@ -42,14 +45,14 @@ static inline uint32_t neorv32_gpio_read(const struct device *dev)
{ {
const struct neorv32_gpio_config *config = dev->config; const struct neorv32_gpio_config *config = dev->config;
return sys_read32(config->input); return sys_read32(config->base + NEORV32_GPIO_PORT_IN);
} }
static inline void neorv32_gpio_write(const struct device *dev, uint32_t val) static inline void neorv32_gpio_write(const struct device *dev, uint32_t val)
{ {
const struct neorv32_gpio_config *config = dev->config; const struct neorv32_gpio_config *config = dev->config;
sys_write32(val, config->output); sys_write32(val, config->base + NEORV32_GPIO_PORT_OUT);
} }
static int neorv32_gpio_pin_configure(const struct device *dev, gpio_pin_t pin, static int neorv32_gpio_pin_configure(const struct device *dev, gpio_pin_t pin,
@ -179,13 +182,13 @@ static int neorv32_gpio_init(const struct device *dev)
return -EINVAL; return -EINVAL;
} }
err = syscon_read_reg(config->syscon, NEORV32_SYSINFO_FEATURES, &features); err = syscon_read_reg(config->syscon, NEORV32_SYSINFO_SOC, &features);
if (err < 0) { if (err < 0) {
LOG_ERR("failed to determine implemented features (err %d)", err); LOG_ERR("failed to determine implemented features (err %d)", err);
return -EIO; return -EIO;
} }
if ((features & NEORV32_SYSINFO_FEATURES_IO_GPIO) == 0) { if ((features & NEORV32_SYSINFO_SOC_IO_GPIO) == 0) {
LOG_ERR("neorv32 gpio not supported"); LOG_ERR("neorv32 gpio not supported");
return -ENODEV; return -ENODEV;
} }
@ -216,8 +219,7 @@ static DEVICE_API(gpio, neorv32_gpio_driver_api) = {
.port_pin_mask = GPIO_PORT_PIN_MASK_FROM_DT_INST(n) \ .port_pin_mask = GPIO_PORT_PIN_MASK_FROM_DT_INST(n) \
}, \ }, \
.syscon = DEVICE_DT_GET(DT_INST_PHANDLE(n, syscon)), \ .syscon = DEVICE_DT_GET(DT_INST_PHANDLE(n, syscon)), \
.input = DT_INST_REG_ADDR_BY_NAME(n, input), \ .base = DT_INST_REG_ADDR(n), \
.output = DT_INST_REG_ADDR_BY_NAME(n, output), \
}; \ }; \
\ \
DEVICE_DT_INST_DEFINE(n, \ DEVICE_DT_INST_DEFINE(n, \

View file

@ -1,5 +1,5 @@
/* /*
* Copyright (c) 2021 Henrik Brix Andersen <henrik@brixandersen.dk> * Copyright (c) 2021,2025 Henrik Brix Andersen <henrik@brixandersen.dk>
* *
* SPDX-License-Identifier: Apache-2.0 * SPDX-License-Identifier: Apache-2.0
*/ */
@ -9,40 +9,46 @@
#include <zephyr/device.h> #include <zephyr/device.h>
#include <zephyr/drivers/syscon.h> #include <zephyr/drivers/syscon.h>
#include <zephyr/drivers/uart.h> #include <zephyr/drivers/uart.h>
#include <zephyr/pm/device.h>
#include <zephyr/sys/sys_io.h>
#include <zephyr/logging/log.h>
#include <zephyr/irq.h> #include <zephyr/irq.h>
#include <zephyr/logging/log.h>
#include <zephyr/pm/device.h>
#include <zephyr/spinlock.h>
#include <zephyr/sys/sys_io.h>
#include <soc.h> #include <soc.h>
LOG_MODULE_REGISTER(uart_neorv32, CONFIG_UART_LOG_LEVEL); LOG_MODULE_REGISTER(uart_neorv32, CONFIG_UART_LOG_LEVEL);
/* NEORV32 UART registers offsets */ /* NEORV32 UART registers offsets */
#define NEORV32_UART_CTRL_OFFSET 0x00 #define NEORV32_UART_CTRL 0x00
#define NEORV32_UART_DATA_OFFSET 0x04 #define NEORV32_UART_DATA 0x04
/* UART_CTRL register bits */ /* NEORV32 UART CTRL register bits */
#define NEORV32_UART_CTRL_EN BIT(0) #define NEORV32_UART_CTRL_EN BIT(0)
#define NEORV32_UART_CTRL_SIM_MODE BIT(1) #define NEORV32_UART_CTRL_SIM_MODE BIT(1)
#define NEORV32_UART_CTRL_HWFC_EN BIT(2) #define NEORV32_UART_CTRL_HWFC_EN BIT(2)
#define NEORV32_UART_CTRL_PRSC_POS 3U #define NEORV32_UART_CTRL_PRSC GENMASK(5, 3)
#define NEORV32_UART_CTRL_PRSC_MASK BIT_MASK(3) #define NEORV32_UART_CTRL_BAUD GENMASK(15, 6)
#define NEORV32_UART_CTRL_BAUD_POS 6U #define NEORV32_UART_CTRL_RX_NEMPTY BIT(16)
#define NEORV32_UART_CTRL_BAUD_MASK BIT_MASK(10) #define NEORV32_UART_CTRL_RX_HALF BIT(17)
#define NEORV32_UART_CTRL_RX_NEMPTY BIT(16) #define NEORV32_UART_CTRL_RX_FULL BIT(18)
#define NEORV32_UART_CTRL_RX_HALF BIT(17) #define NEORV32_UART_CTRL_TX_EMPTY BIT(19)
#define NEORV32_UART_CTRL_RX_FULL BIT(18) #define NEORV32_UART_CTRL_TX_NHALF BIT(20)
#define NEORV32_UART_CTRL_TX_NEMPTY BIT(19) #define NEORV32_UART_CTRL_TX_FULL BIT(21)
#define NEORV32_UART_CTRL_TX_HALF BIT(20) #define NEORV32_UART_CTRL_IRQ_RX_NEMPTY BIT(22)
#define NEORV32_UART_CTRL_TX_FULL BIT(21) #define NEORV32_UART_CTRL_IRQ_RX_HALF BIT(23)
#define NEORV32_UART_CTRL_IRQ_RX_NEMPTY BIT(22) #define NEORV32_UART_CTRL_IRQ_RX_FULL BIT(24)
#define NEORV32_UART_CTRL_IRQ_RX_HALF BIT(23) #define NEORV32_UART_CTRL_IRQ_TX_EMPTY BIT(25)
#define NEORV32_UART_CTRL_IRQ_RX_FULL BIT(24) #define NEORV32_UART_CTRL_IRQ_TX_NHALF BIT(26)
#define NEORV32_UART_CTRL_IRQ_TX_EMPTY BIT(25) #define NEORV32_UART_CTRL_UART_CTRL_RX_CLR BIT(28)
#define NEORV32_UART_CTRL_IRQ_TX_NHALF BIT(26) #define NEORV32_UART_CTRL_UART_CTRL_TX_CLR BIT(29)
#define NEORV32_UART_CTRL_RX_OVER BIT(30) #define NEORV32_UART_CTRL_RX_OVER BIT(30)
#define NEORV32_UART_CTRL_TX_BUSY BIT(31) #define NEORV32_UART_CTRL_TX_BUSY BIT(31)
/* NEORV32 UART DATA register bits */
#define NEORV32_UART_DATA_RTX GENMASK(7, 0)
#define NEORV32_UART_DATA_RX_FIFO_SIZE GENMASK(11, 8)
#define NEORV32_UART_DATA_TX_FIFO_SIZE GENMASK(15, 12)
struct neorv32_uart_config { struct neorv32_uart_config {
const struct device *syscon; const struct device *syscon;
@ -50,18 +56,16 @@ struct neorv32_uart_config {
mm_reg_t base; mm_reg_t base;
#ifdef CONFIG_UART_INTERRUPT_DRIVEN #ifdef CONFIG_UART_INTERRUPT_DRIVEN
void (*irq_config_func)(const struct device *dev); void (*irq_config_func)(const struct device *dev);
unsigned int tx_irq;
unsigned int rx_irq;
#endif /* CONFIG_UART_INTERRUPT_DRIVEN */ #endif /* CONFIG_UART_INTERRUPT_DRIVEN */
}; };
struct neorv32_uart_data { struct neorv32_uart_data {
struct uart_config uart_cfg; struct uart_config uart_cfg;
uint32_t last_data; struct k_spinlock lock;
#ifdef CONFIG_UART_INTERRUPT_DRIVEN #ifdef CONFIG_UART_INTERRUPT_DRIVEN
struct k_timer timer;
uart_irq_callback_user_data_t callback; uart_irq_callback_user_data_t callback;
void *callback_data; void *callback_data;
uint32_t last_ctrl;
#endif /* CONFIG_UART_INTERRUPT_DRIVEN */ #endif /* CONFIG_UART_INTERRUPT_DRIVEN */
}; };
@ -69,44 +73,37 @@ static inline uint32_t neorv32_uart_read_ctrl(const struct device *dev)
{ {
const struct neorv32_uart_config *config = dev->config; const struct neorv32_uart_config *config = dev->config;
return sys_read32(config->base + NEORV32_UART_CTRL_OFFSET); return sys_read32(config->base + NEORV32_UART_CTRL);
} }
static inline void neorv32_uart_write_ctrl(const struct device *dev, uint32_t ctrl) static inline void neorv32_uart_write_ctrl(const struct device *dev, uint32_t ctrl)
{ {
const struct neorv32_uart_config *config = dev->config; const struct neorv32_uart_config *config = dev->config;
sys_write32(ctrl, config->base + NEORV32_UART_CTRL_OFFSET); sys_write32(ctrl, config->base + NEORV32_UART_CTRL);
} }
static inline uint32_t neorv32_uart_read_data(const struct device *dev) static inline uint32_t neorv32_uart_read_data(const struct device *dev)
{ {
const struct neorv32_uart_config *config = dev->config; const struct neorv32_uart_config *config = dev->config;
struct neorv32_uart_data *data = dev->data;
uint32_t reg;
/* Cache status bits as they are cleared upon read */ return sys_read32(config->base + NEORV32_UART_DATA);
reg = sys_read32(config->base + NEORV32_UART_DATA_OFFSET);
data->last_data = reg;
return reg;
} }
static inline void neorv32_uart_write_data(const struct device *dev, uint32_t data) static inline void neorv32_uart_write_data(const struct device *dev, uint32_t data)
{ {
const struct neorv32_uart_config *config = dev->config; const struct neorv32_uart_config *config = dev->config;
sys_write32(data, config->base + NEORV32_UART_DATA_OFFSET); sys_write32(data, config->base + NEORV32_UART_DATA);
} }
static int neorv32_uart_poll_in(const struct device *dev, unsigned char *c) static int neorv32_uart_poll_in(const struct device *dev, unsigned char *c)
{ {
uint32_t data; uint32_t ctrl;
data = neorv32_uart_read_data(dev); ctrl = neorv32_uart_read_ctrl(dev);
if ((ctrl & NEORV32_UART_CTRL_RX_NEMPTY) != 0U) {
if ((data & NEORV32_UART_CTRL_RX_NEMPTY) != 0) { *c = neorv32_uart_read_data(dev) & NEORV32_UART_DATA_RTX;
*c = data & BIT_MASK(8);
return 0; return 0;
} }
@ -115,7 +112,7 @@ static int neorv32_uart_poll_in(const struct device *dev, unsigned char *c)
static void neorv32_uart_poll_out(const struct device *dev, unsigned char c) static void neorv32_uart_poll_out(const struct device *dev, unsigned char c)
{ {
while ((neorv32_uart_read_ctrl(dev) & NEORV32_UART_CTRL_TX_BUSY) != 0) { while ((neorv32_uart_read_ctrl(dev) & NEORV32_UART_CTRL_TX_FULL) != 0U) {
} }
neorv32_uart_write_data(dev, c); neorv32_uart_write_data(dev, c);
@ -123,11 +120,15 @@ static void neorv32_uart_poll_out(const struct device *dev, unsigned char c)
static int neorv32_uart_configure(const struct device *dev, const struct uart_config *cfg) static int neorv32_uart_configure(const struct device *dev, const struct uart_config *cfg)
{ {
const uint16_t baudxx_max = FIELD_GET(NEORV32_UART_CTRL_BAUD, NEORV32_UART_CTRL_BAUD);
const uint8_t prscx_max = FIELD_GET(NEORV32_UART_CTRL_PRSC, NEORV32_UART_CTRL_PRSC);
const struct neorv32_uart_config *config = dev->config; const struct neorv32_uart_config *config = dev->config;
struct neorv32_uart_data *data = dev->data; struct neorv32_uart_data *data = dev->data;
uint32_t ctrl = NEORV32_UART_CTRL_EN; k_spinlock_key_t key;
uint16_t baudxx = 0; uint16_t baudxx = 0;
uint8_t prscx = 0; uint8_t prscx = 0;
uint32_t ctrl;
bool hwfc_en;
uint32_t clk; uint32_t clk;
int err; int err;
@ -143,20 +144,17 @@ static int neorv32_uart_configure(const struct device *dev, const struct uart_co
return -ENOTSUP; return -ENOTSUP;
} }
switch (cfg->parity) { if (cfg->parity != UART_CFG_PARITY_NONE) {
case UART_CFG_PARITY_NONE: LOG_ERR("hardware only supports parity mode none");
break;
default:
LOG_ERR("unsupported parity mode %d", cfg->parity);
return -ENOTSUP; return -ENOTSUP;
} }
switch (cfg->flow_ctrl) { switch (cfg->flow_ctrl) {
case UART_CFG_FLOW_CTRL_NONE: case UART_CFG_FLOW_CTRL_NONE:
ctrl |= 0; hwfc_en = false;
break; break;
case UART_CFG_FLOW_CTRL_RTS_CTS: case UART_CFG_FLOW_CTRL_RTS_CTS:
ctrl |= NEORV32_UART_CTRL_HWFC_EN; hwfc_en = true;
break; break;
default: default:
LOG_ERR("unsupported flow control mode %d", cfg->flow_ctrl); LOG_ERR("unsupported flow control mode %d", cfg->flow_ctrl);
@ -179,7 +177,7 @@ static int neorv32_uart_configure(const struct device *dev, const struct uart_co
* clock / 2. * clock / 2.
*/ */
baudxx = clk / (2 * cfg->baudrate); baudxx = clk / (2 * cfg->baudrate);
while (baudxx >= NEORV32_UART_CTRL_BAUD_MASK) { while (baudxx >= baudxx_max) {
if ((prscx == 2) || (prscx == 4)) { if ((prscx == 2) || (prscx == 4)) {
baudxx >>= 3; baudxx >>= 3;
} else { } else {
@ -189,16 +187,30 @@ static int neorv32_uart_configure(const struct device *dev, const struct uart_co
prscx++; prscx++;
} }
if (prscx > NEORV32_UART_CTRL_PRSC_MASK) { if (prscx > prscx_max) {
LOG_ERR("unsupported baud rate %d", cfg->baudrate); LOG_ERR("unsupported baud rate %d", cfg->baudrate);
return -ENOTSUP; return -ENOTSUP;
} }
ctrl |= (baudxx - 1) << NEORV32_UART_CTRL_BAUD_POS; key = k_spin_lock(&data->lock);
ctrl |= prscx << NEORV32_UART_CTRL_PRSC_POS;
ctrl = neorv32_uart_read_ctrl(dev);
ctrl |= NEORV32_UART_CTRL_EN;
if (hwfc_en) {
ctrl |= NEORV32_UART_CTRL_HWFC_EN;
} else {
ctrl &= ~NEORV32_UART_CTRL_HWFC_EN;
}
ctrl &= ~(NEORV32_UART_CTRL_BAUD | NEORV32_UART_CTRL_PRSC);
ctrl |= FIELD_PREP(NEORV32_UART_CTRL_BAUD, baudxx - 1U) |
FIELD_PREP(NEORV32_UART_CTRL_PRSC, prscx);
data->uart_cfg = *cfg;
neorv32_uart_write_ctrl(dev, ctrl); neorv32_uart_write_ctrl(dev, ctrl);
data->uart_cfg = *cfg;
k_spin_unlock(&data->lock, key);
return 0; return 0;
} }
@ -215,28 +227,25 @@ static int neorv32_uart_config_get(const struct device *dev, struct uart_config
} }
#ifdef CONFIG_UART_INTERRUPT_DRIVEN #ifdef CONFIG_UART_INTERRUPT_DRIVEN
static int neorv32_uart_fifo_fill(const struct device *dev, const uint8_t *tx_data, int len) static int neorv32_uart_fifo_fill(const struct device *dev, const uint8_t *tx_data, int size)
{ {
uint32_t ctrl; int count = 0;
if (len <= 0) { if (size <= 0) {
return 0; return 0;
} }
__ASSERT_NO_MSG(tx_data != NULL); __ASSERT_NO_MSG(tx_data != NULL);
ctrl = neorv32_uart_read_ctrl(dev); while (count < size && (neorv32_uart_read_ctrl(dev) & NEORV32_UART_CTRL_TX_FULL) == 0U) {
if ((ctrl & NEORV32_UART_CTRL_TX_BUSY) == 0) { neorv32_uart_write_data(dev, tx_data[count++]);
neorv32_uart_write_data(dev, *tx_data);
return 1;
} }
return 0; return count;
} }
static int neorv32_uart_fifo_read(const struct device *dev, uint8_t *rx_data, const int size) static int neorv32_uart_fifo_read(const struct device *dev, uint8_t *rx_data, const int size)
{ {
struct neorv32_uart_data *data = dev->data;
int count = 0; int count = 0;
if (size <= 0) { if (size <= 0) {
@ -245,104 +254,100 @@ static int neorv32_uart_fifo_read(const struct device *dev, uint8_t *rx_data, co
__ASSERT_NO_MSG(rx_data != NULL); __ASSERT_NO_MSG(rx_data != NULL);
while ((data->last_data & NEORV32_UART_CTRL_RX_NEMPTY) != 0) { while (count < size && (neorv32_uart_read_ctrl(dev) & NEORV32_UART_CTRL_RX_NEMPTY) != 0U) {
rx_data[count++] = data->last_data & BIT_MASK(8); rx_data[count++] = neorv32_uart_read_data(dev) & NEORV32_UART_DATA_RTX;
data->last_data &= ~(NEORV32_UART_CTRL_RX_NEMPTY);
if (count >= size) {
break;
}
(void)neorv32_uart_read_data(dev);
} }
return count; return count;
} }
static void neorv32_uart_tx_soft_isr(struct k_timer *timer)
{
const struct device *dev = k_timer_user_data_get(timer);
struct neorv32_uart_data *data = dev->data;
uart_irq_callback_user_data_t callback = data->callback;
if (callback) {
callback(dev, data->callback_data);
}
}
static void neorv32_uart_irq_tx_enable(const struct device *dev) static void neorv32_uart_irq_tx_enable(const struct device *dev)
{ {
const struct neorv32_uart_config *config = dev->config;
struct neorv32_uart_data *data = dev->data; struct neorv32_uart_data *data = dev->data;
k_spinlock_key_t key;
uint32_t ctrl; uint32_t ctrl;
irq_enable(config->tx_irq); key = k_spin_lock(&data->lock);
ctrl = neorv32_uart_read_ctrl(dev); ctrl = neorv32_uart_read_ctrl(dev);
if ((ctrl & NEORV32_UART_CTRL_TX_BUSY) == 0) { ctrl |= NEORV32_UART_CTRL_IRQ_TX_EMPTY;
/* neorv32_uart_write_ctrl(dev, ctrl);
* TX done event already generated an edge interrupt. Generate a
* soft interrupt and have it call the callback function in k_spin_unlock(&data->lock, key);
* timer isr context.
*/
k_timer_start(&data->timer, K_NO_WAIT, K_NO_WAIT);
}
} }
static void neorv32_uart_irq_tx_disable(const struct device *dev) static void neorv32_uart_irq_tx_disable(const struct device *dev)
{ {
const struct neorv32_uart_config *config = dev->config; struct neorv32_uart_data *data = dev->data;
k_spinlock_key_t key;
uint32_t ctrl;
irq_disable(config->tx_irq); key = k_spin_lock(&data->lock);
ctrl = neorv32_uart_read_ctrl(dev);
ctrl &= ~NEORV32_UART_CTRL_IRQ_TX_EMPTY;
neorv32_uart_write_ctrl(dev, ctrl);
k_spin_unlock(&data->lock, key);
} }
static int neorv32_uart_irq_tx_ready(const struct device *dev) static int neorv32_uart_irq_tx_ready(const struct device *dev)
{ {
const struct neorv32_uart_config *config = dev->config; struct neorv32_uart_data *data = dev->data;
uint32_t ctrl;
if (!irq_is_enabled(config->tx_irq)) { if ((data->last_ctrl & NEORV32_UART_CTRL_IRQ_TX_EMPTY) == 0U) {
return 0; return 0;
} }
ctrl = neorv32_uart_read_ctrl(dev); return (data->last_ctrl & NEORV32_UART_CTRL_TX_FULL) == 0U;
return (ctrl & NEORV32_UART_CTRL_TX_BUSY) == 0;
} }
static void neorv32_uart_irq_rx_enable(const struct device *dev) static void neorv32_uart_irq_rx_enable(const struct device *dev)
{ {
const struct neorv32_uart_config *config = dev->config; struct neorv32_uart_data *data = dev->data;
k_spinlock_key_t key;
uint32_t ctrl;
irq_enable(config->rx_irq); key = k_spin_lock(&data->lock);
ctrl = neorv32_uart_read_ctrl(dev);
ctrl |= NEORV32_UART_CTRL_IRQ_RX_NEMPTY;
neorv32_uart_write_ctrl(dev, ctrl);
k_spin_unlock(&data->lock, key);
} }
static void neorv32_uart_irq_rx_disable(const struct device *dev) static void neorv32_uart_irq_rx_disable(const struct device *dev)
{ {
const struct neorv32_uart_config *config = dev->config; struct neorv32_uart_data *data = dev->data;
k_spinlock_key_t key;
uint32_t ctrl;
irq_disable(config->rx_irq); key = k_spin_lock(&data->lock);
ctrl = neorv32_uart_read_ctrl(dev);
ctrl &= ~NEORV32_UART_CTRL_IRQ_RX_NEMPTY;
neorv32_uart_write_ctrl(dev, ctrl);
k_spin_unlock(&data->lock, key);
} }
static int neorv32_uart_irq_tx_complete(const struct device *dev) static int neorv32_uart_irq_tx_complete(const struct device *dev)
{ {
uint32_t ctrl; struct neorv32_uart_data *data = dev->data;
ctrl = neorv32_uart_read_ctrl(dev); return (data->last_ctrl & NEORV32_UART_CTRL_TX_BUSY) == 0U;
return (ctrl & NEORV32_UART_CTRL_TX_BUSY) == 0;
} }
static int neorv32_uart_irq_rx_ready(const struct device *dev) static int neorv32_uart_irq_rx_ready(const struct device *dev)
{ {
const struct neorv32_uart_config *config = dev->config;
struct neorv32_uart_data *data = dev->data; struct neorv32_uart_data *data = dev->data;
if (!irq_is_enabled(config->rx_irq)) { if ((data->last_ctrl & NEORV32_UART_CTRL_IRQ_RX_NEMPTY) == 0U) {
return 0; return 0;
} }
return (data->last_data & NEORV32_UART_CTRL_RX_NEMPTY) != 0; return (data->last_ctrl & NEORV32_UART_CTRL_RX_NEMPTY) != 0U;
} }
static int neorv32_uart_irq_is_pending(const struct device *dev) static int neorv32_uart_irq_is_pending(const struct device *dev)
@ -353,12 +358,14 @@ static int neorv32_uart_irq_is_pending(const struct device *dev)
static int neorv32_uart_irq_update(const struct device *dev) static int neorv32_uart_irq_update(const struct device *dev)
{ {
const struct neorv32_uart_config *config = dev->config; struct neorv32_uart_data *data = dev->data;
if (irq_is_enabled(config->rx_irq)) { /* Cache the CTRL register for use in the following functions:
/* Cache data for use by rx_ready() and fifo_read() */ * - neorv32_uart_irq_tx_complete()
(void)neorv32_uart_read_data(dev); * - neorv32_uart_irq_tx_ready()
} * - neorv32_uart_irq_rx_ready()
*/
data->last_ctrl = neorv32_uart_read_ctrl(dev);
return 1; return 1;
} }
@ -395,7 +402,7 @@ static int neorv32_uart_init(const struct device *dev)
return -EINVAL; return -EINVAL;
} }
err = syscon_read_reg(config->syscon, NEORV32_SYSINFO_FEATURES, &features); err = syscon_read_reg(config->syscon, NEORV32_SYSINFO_SOC, &features);
if (err < 0) { if (err < 0) {
LOG_ERR("failed to determine implemented features (err %d)", err); LOG_ERR("failed to determine implemented features (err %d)", err);
return -EIO; return -EIO;
@ -407,9 +414,6 @@ static int neorv32_uart_init(const struct device *dev)
} }
#ifdef CONFIG_UART_INTERRUPT_DRIVEN #ifdef CONFIG_UART_INTERRUPT_DRIVEN
k_timer_init(&data->timer, &neorv32_uart_tx_soft_isr, NULL);
k_timer_user_data_set(&data->timer, (void *)dev);
config->irq_config_func(dev); config->irq_config_func(dev);
#endif /* CONFIG_UART_INTERRUPT_DRIVEN */ #endif /* CONFIG_UART_INTERRUPT_DRIVEN */
@ -420,7 +424,12 @@ static int neorv32_uart_init(const struct device *dev)
static int neorv32_uart_pm_action(const struct device *dev, static int neorv32_uart_pm_action(const struct device *dev,
enum pm_device_action action) enum pm_device_action action)
{ {
uint32_t ctrl = neorv32_uart_read_ctrl(dev); struct neorv32_uart_data *data = dev->data;
k_spinlock_key_t key;
uint32_t ctrl;
key = k_spin_lock(&data->lock);
ctrl = neorv32_uart_read_ctrl(dev);
switch (action) { switch (action) {
case PM_DEVICE_ACTION_SUSPEND: case PM_DEVICE_ACTION_SUSPEND:
@ -434,6 +443,7 @@ static int neorv32_uart_pm_action(const struct device *dev,
} }
neorv32_uart_write_ctrl(dev, ctrl); neorv32_uart_write_ctrl(dev, ctrl);
k_spin_unlock(&data->lock, key);
return 0; return 0;
} }
@ -470,16 +480,16 @@ static DEVICE_API(uart, neorv32_uart_driver_api) = {
DT_IRQ_BY_NAME(node_id, tx, priority), \ DT_IRQ_BY_NAME(node_id, tx, priority), \
neorv32_uart_isr, \ neorv32_uart_isr, \
DEVICE_DT_GET(node_id), 0); \ DEVICE_DT_GET(node_id), 0); \
irq_enable(DT_IRQ_BY_NAME(node_id, tx, irq)); \
\ \
IRQ_CONNECT(DT_IRQ_BY_NAME(node_id, rx, irq), \ IRQ_CONNECT(DT_IRQ_BY_NAME(node_id, rx, irq), \
DT_IRQ_BY_NAME(node_id, rx, priority), \ DT_IRQ_BY_NAME(node_id, rx, priority), \
neorv32_uart_isr, \ neorv32_uart_isr, \
DEVICE_DT_GET(node_id), 0); \ DEVICE_DT_GET(node_id), 0); \
irq_enable(DT_IRQ_BY_NAME(node_id, rx, irq)); \
} }
#define NEORV32_UART_CONFIG_INIT(node_id, n) \ #define NEORV32_UART_CONFIG_INIT(node_id, n) \
.irq_config_func = neorv32_uart_config_func_##n, \ .irq_config_func = neorv32_uart_config_func_##n,
.tx_irq = DT_IRQ_BY_NAME(node_id, tx, irq), \
.rx_irq = DT_IRQ_BY_NAME(node_id, rx, irq),
#else #else
#define NEORV32_UART_CONFIG_FUNC(node_id, n) #define NEORV32_UART_CONFIG_FUNC(node_id, n)
#define NEORV32_UART_CONFIG_INIT(node_id, n) #define NEORV32_UART_CONFIG_INIT(node_id, n)
@ -502,7 +512,7 @@ static DEVICE_API(uart, neorv32_uart_driver_api) = {
\ \
static const struct neorv32_uart_config neorv32_uart_##n##_config = { \ static const struct neorv32_uart_config neorv32_uart_##n##_config = { \
.syscon = DEVICE_DT_GET(DT_PHANDLE(node_id, syscon)), \ .syscon = DEVICE_DT_GET(DT_PHANDLE(node_id, syscon)), \
.feature_mask = NEORV32_SYSINFO_FEATURES_IO_UART##n, \ .feature_mask = NEORV32_SYSINFO_SOC_IO_UART##n, \
.base = DT_REG_ADDR(node_id), \ .base = DT_REG_ADDR(node_id), \
NEORV32_UART_CONFIG_INIT(node_id, n) \ NEORV32_UART_CONFIG_INIT(node_id, n) \
}; \ }; \

View file

@ -8,9 +8,6 @@ properties:
reg: reg:
required: true required: true
reg-names:
required: true
syscon: syscon:
type: phandle type: phandle
required: true required: true

View file

@ -1,5 +1,5 @@
/* /*
* Copyright (c) 2021 Henrik Brix Andersen <henrik@brixandersen.dk> * Copyright (c) 2021,2025 Henrik Brix Andersen <henrik@brixandersen.dk>
* *
* SPDX-License-Identifier: Apache-2.0 * SPDX-License-Identifier: Apache-2.0
*/ */
@ -20,7 +20,6 @@
cpu0: cpu@0 { cpu0: cpu@0 {
compatible = "neorv32-cpu", "riscv"; compatible = "neorv32-cpu", "riscv";
riscv,isa = "rv32imc_zicsr";
reg = <0>; reg = <0>;
device_type = "cpu"; device_type = "cpu";
@ -64,77 +63,76 @@
#size-cells = <1>; #size-cells = <1>;
ranges; ranges;
mtimer: timer@ffffff90 { imem: memory@0 {
compatible = "soc-nv-flash", "mmio-sram";
status = "disabled";
};
dmem: memory@80000000 {
compatible = "mmio-sram";
status = "disabled";
};
bootrom: rom@ffe00000 {
compatible = "neorv32-bootrom", "mmio-sram";
status = "disabled";
reg = <0xffe00000 0x10000>;
};
clint: clint@fff40000 {
compatible = "neorv32-clint", "sifive,clint0";
status = "disabled";
reg = <0xfff40000 0x10000>;
interrupts-extended = <&intc 3>;
};
mtimer: timer@fff4bff8 {
compatible = "riscv,machine-timer"; compatible = "riscv,machine-timer";
reg = <0xffffff90 0x8 0xffffff98 0x8>; status = "disabled";
reg = <0xfff4bff8 0x8 0xfff44000 0x8>;
reg-names = "mtime", "mtimecmp";
interrupts-extended = <&intc 7>; interrupts-extended = <&intc 7>;
}; };
uart0: serial@ffffffa0 { uart0: serial@fff50000 {
compatible = "neorv32-uart"; compatible = "neorv32-uart";
status = "disabled"; status = "disabled";
reg = <0xffffffa0 8>; reg = <0xfff50000 0x10000>;
interrupts = <2>, <3>; interrupts = <2>, <3>;
interrupt-names = "RX", "TX"; interrupt-names = "RX", "TX";
syscon = <&sysinfo>; syscon = <&sysinfo>;
}; };
trng: rng@ffffffb8 { uart1: serial@fff60000 {
compatible = "neorv32-trng";
status = "disabled";
reg = <0xffffffb8 4>;
syscon = <&sysinfo>;
};
gpio: gpio {
compatible = "simple-bus";
gpio-map-mask = <0xffffffe0 0xffffffc0>;
gpio-map-pass-thru = <0x1f 0x3f>;
gpio-map = <
0x00 0x0 &gpio_lo 0x0 0x0
0x20 0x0 &gpio_hi 0x0 0x0
>;
#gpio-cells = <2>;
#address-cells = <1>;
#size-cells = <1>;
ranges;
gpio_lo: gpio@ffffffc0 {
compatible = "neorv32-gpio";
status = "disabled";
reg = <0xffffffc0 4 0xffffffc8 4>;
reg-names = "input", "output";
gpio-controller;
ngpios = <32>;
syscon = <&sysinfo>;
#gpio-cells = <2>;
};
gpio_hi: gpio@ffffffc4 {
compatible = "neorv32-gpio";
status = "disabled";
reg = <0xffffffc4 4 0xffffffcc 4>;
reg-names = "input", "output";
gpio-controller;
ngpios = <32>;
syscon = <&sysinfo>;
#gpio-cells = <2>;
};
};
uart1: serial@ffffffd0 {
compatible = "neorv32-uart"; compatible = "neorv32-uart";
status = "disabled"; status = "disabled";
reg = <0xffffffd0 8>; reg = <0xfff60000 0x10000>;
interrupts = <4>, <5>; interrupts = <4>, <5>;
interrupt-names = "RX", "TX"; interrupt-names = "RX", "TX";
syscon = <&sysinfo>; syscon = <&sysinfo>;
}; };
sysinfo: syscon@ffffffe0 { trng: rng@fffa0000 {
compatible = "neorv32-trng";
status = "disabled";
reg = <0xfffa0000 0x10000>;
syscon = <&sysinfo>;
};
gpio: gpio@fffc0000 {
compatible = "neorv32-gpio";
status = "disabled";
reg = <0xfffc0000 0x10000>;
syscon = <&sysinfo>;
gpio-controller;
ngpios = <32>;
#gpio-cells = <2>;
};
sysinfo: syscon@fffe0000 {
compatible = "neorv-sysinfo", "syscon"; compatible = "neorv-sysinfo", "syscon";
status = "okay"; status = "okay";
reg = <0xffffffe0 32>; reg = <0xfffe0000 0x10000>;
}; };
}; };
}; };

View file

@ -7,4 +7,4 @@ zephyr_sources(
soc.c soc.c
) )
set(SOC_LINKER_SCRIPT ${CMAKE_CURRENT_SOURCE_DIR}/linker.ld CACHE INTERNAL "") set(SOC_LINKER_SCRIPT ${ZEPHYR_BASE}/include/zephyr/arch/riscv/common/linker.ld CACHE INTERNAL "")

View file

@ -3,31 +3,20 @@
config SOC_NEORV32 config SOC_NEORV32
select RISCV select RISCV
select RISCV_ISA_RV32I
select RISCV_ISA_EXT_M
select RISCV_ISA_EXT_ZICSR
select RISCV_ISA_EXT_ZIFENCEI
select RISCV_PRIVILEGED select RISCV_PRIVILEGED
select RISCV_SOC_HAS_GP_RELATIVE_ADDRESSING select RISCV_SOC_HAS_GP_RELATIVE_ADDRESSING
# NEORV32 RISC-V ISA A extension implements only LR/SC, not AMO select RISCV_ISA_EXT_ZICSR
select ATOMIC_OPERATIONS_C select RISCV_ISA_EXT_ZIFENCEI
imply XIP imply XIP
if SOC_NEORV32 if SOC_NEORV32
config SOC_NEORV32_VERSION config SOC_NEORV32_VERSION
hex hex
default 0x01080600 default 0x01110100
help help
The targeted NEORV32 version as BCD-coded number. The format is The targeted NEORV32 version as BCD-coded number. The format is
identical to that of the NEORV32 Machine implementation ID (mimpid) identical to that of the NEORV32 Machine implementation ID (mimpid)
register. register.
config SOC_NEORV32_ISA_C
bool "RISC-V ISA Extension \"C\""
select RISCV_ISA_EXT_C
help
Enable this if the NEORV32 CPU implementation supports the RISC-V ISA
"C" extension (Compressed Instructions).
endif # SOC_NEORV32 endif # SOC_NEORV32

View file

@ -1,4 +1,4 @@
# Copyright (c) 2021 Henrik Brix Andersen <henrik@brixandersen.dk> # Copyright (c) 2021,2025 Henrik Brix Andersen <henrik@brixandersen.dk>
# SPDX-License-Identifier: Apache-2.0 # SPDX-License-Identifier: Apache-2.0
if SOC_NEORV32 if SOC_NEORV32
@ -12,12 +12,4 @@ config NUM_IRQS
config SYSCON config SYSCON
default y default y
config SERIAL_INIT_PRIORITY
default 55
depends on SERIAL
config ENTROPY_INIT_PRIORITY
default 55
depends on ENTROPY_GENERATOR
endif # SOC_NEORV32 endif # SOC_NEORV32

View file

@ -8,15 +8,9 @@ config SOC_NEORV32
The NEORV32 CPU implementation must have the following RISC-V ISA The NEORV32 CPU implementation must have the following RISC-V ISA
extensions enabled in order to support Zephyr: extensions enabled in order to support Zephyr:
- M (Integer Multiplication and Division) - Zicsr (always enabled)
- Zicsr (Control and Status Register (CSR) Instructions) - Zifencei (always enabled)
- Zicntr
The following NEORV32 CPU ISA extensions are not currently supported
by Zephyr and can safely be disabled:
- A (Atomic Instructions)
- E (Embedded, only 16 integer registers)
- Zbb (Basic Bit Manipulation)
- Zfinx (Floating Point in Integer Registers)
config SOC config SOC
default "neorv32" if SOC_NEORV32 default "neorv32" if SOC_NEORV32

View file

@ -1,23 +0,0 @@
/*
* Copyright (c) 2021 Henrik Brix Andersen <henrik@brixandersen.dk>
*
* SPDX-License-Identifier: Apache-2.0
*/
#include <zephyr/linker/linker-tool.h>
MEMORY
{
IO (rw) : ORIGIN = 0xFFFFFE00, LENGTH = 512
}
SECTIONS
{
SECTION_PROLOGUE(io, (NOLOAD),)
{
PROVIDE(__io_start = ORIGIN(IO));
PROVIDE(__io_end = ORIGIN(IO) + LENGTH(IO));
} GROUP_LINK_IN(IO)
}
#include <zephyr/arch/riscv/common/linker.ld>

View file

@ -1,5 +1,5 @@
/* /*
* Copyright (c) 2021 Henrik Brix Andersen <henrik@brixandersen.dk> * Copyright (c) 2021,2025 Henrik Brix Andersen <henrik@brixandersen.dk>
* *
* SPDX-License-Identifier: Apache-2.0 * SPDX-License-Identifier: Apache-2.0
*/ */
@ -13,9 +13,6 @@ GTEXT(__reset)
GTEXT(__initialize) GTEXT(__initialize)
SECTION_FUNC(reset, __reset) SECTION_FUNC(reset, __reset)
/* Zerorize zero register */
lui x0, 0
/* Disable interrupts */ /* Disable interrupts */
csrw mstatus, x0 csrw mstatus, x0
csrw mie, x0 csrw mie, x0
@ -26,7 +23,7 @@ SECTION_FUNC(reset, __reset)
#endif /* CONFIG_USERSPACE */ #endif /* CONFIG_USERSPACE */
/* Allow mcycle and minstret counters to increment */ /* Allow mcycle and minstret counters to increment */
li x11, ~2 li x11, ~5
csrw mcountinhibit, x11 csrw mcountinhibit, x11
/* Zerorize counters */ /* Zerorize counters */
@ -35,39 +32,5 @@ SECTION_FUNC(reset, __reset)
csrw minstret, x0 csrw minstret, x0
csrw minstreth, x0 csrw minstreth, x0
/*
* Simplify dummy machine trap code by not having to decode
* instruction width.
*/
.option push
.option norvc
/*
* Temporarily setup a dummy machine trap vector to catch (and ignore)
* Store Access faults due to unimplemented peripherals.
*/
csrr x6, mtvec
la x7, __dummy_trap_handler
csrw mtvec, x7
/* Attempt to zerorize all IO peripheral registers */
la x8, __io_start
la x9, __io_end
1: sw x0, 0(x8)
addi x8, x8, 4
bne x8, x9, 1b
/* Restore previous machine trap vector */
csrw mtvec, x6
.option pop
/* Jump to __initialize */ /* Jump to __initialize */
call __initialize call __initialize
.balign 4
SECTION_FUNC(reset, __dummy_trap_handler)
csrr x5, mepc
addi x5, x5, 4
csrw mepc, x5
mret

View file

@ -1,56 +1,60 @@
/* /*
* Copyright (c) 2021 Henrik Brix Andersen <henrik@brixandersen.dk> * Copyright (c) 2021,2025 Henrik Brix Andersen <henrik@brixandersen.dk>
* *
* SPDX-License-Identifier: Apache-2.0 * SPDX-License-Identifier: Apache-2.0
*/ */
#ifndef RISCV_NEORV32_SOC_H #ifndef _NEORV32_SOC_H
#define RISCV_NEORV32_SOC_H #define _NEORV32_SOC_H
/* System information (SYSINFO) register offsets */ /* System information (SYSINFO) register offsets */
#define NEORV32_SYSINFO_CLK 0x00U #define NEORV32_SYSINFO_CLK 0x00U
#define NEORV32_SYSINFO_CPU 0x04U #define NEORV32_SYSINFO_MISC 0x04U
#define NEORV32_SYSINFO_FEATURES 0x08U #define NEORV32_SYSINFO_SOC 0x08U
#define NEORV32_SYSINFO_CACHE 0x0cU #define NEORV32_SYSINFO_CACHE 0x0cU
#define NEORV32_SYSINFO_ISPACE_BASE 0xf0U
#define NEORV32_SYSINFO_IMEM_SIZE 0xf4U
#define NEORV32_SYSINFO_DSPACE_BASE 0xf8U
#define NEORV32_SYSINFO_DMEM_SIZE 0xfcU
/* System information (SYSINFO) CPU register bits */ /* System information (SYSINFO) MISC register bits */
#define NEORV32_SYSINFO_CPU_ZICSR BIT(0) #define NEORV32_SYSINFO_MISC_IMEM GENMASK(7, 0)
#define NEORV32_SYSINFO_CPU_ZIFENCEI BIT(1) #define NEORV32_SYSINFO_MISC_DMEM GENMASK(15, 8)
#define NEORV32_SYSINFO_CPU_ZMMUL BIT(2) #define NEORV32_SYSINFO_MISC_HART GENMASK(23, 16)
#define NEORV32_SYSINFO_CPU_ZBB BIT(3) #define NEORV32_SYSINFO_MISC_BOOT GENMASK(31, 24)
#define NEORV32_SYSINFO_CPU_ZFINX BIT(5)
#define NEORV32_SYSINFO_CPU_ZXSCNT BIT(6)
#define NEORV32_SYSINFO_CPU_ZXNOCNT BIT(7)
#define NEORV32_SYSINFO_CPU_PMP BIT(8)
#define NEORV32_SYSINFO_CPU_HPM BIT(9)
#define NEORV32_SYSINFO_CPU_DEBUGMODE BIT(10)
#define NEORV32_SYSINFO_CPU_FASTMUL BIT(30)
#define NEORV32_SYSINFO_CPU_FASTSHIFT BIT(31)
/* System information (SYSINFO) FEATURES register bits */ /* System information (SYSINFO) SOC register bits */
#define NEORV32_SYSINFO_FEATURES_BOOTLOADER BIT(0) #define NEORV32_SYSINFO_SOC_BOOTLOADER BIT(0)
#define NEORV32_SYSINFO_FEATURES_MEM_EXT BIT(1) #define NEORV32_SYSINFO_SOC_XBUS BIT(1)
#define NEORV32_SYSINFO_FEATURES_MEM_INT_IMEM BIT(2) #define NEORV32_SYSINFO_SOC_MEM_INT_IMEM BIT(2)
#define NEORV32_SYSINFO_FEATURES_MEM_INT_DMEM BIT(3) #define NEORV32_SYSINFO_SOC_MEM_INT_DMEM BIT(3)
#define NEORV32_SYSINFO_FEATURES_MEM_EXT_ENDIAN BIT(4) #define NEORV32_SYSINFO_SOC_OCD BIT(4)
#define NEORV32_SYSINFO_FEATURES_ICACHE BIT(5) #define NEORV32_SYSINFO_SOC_ICACHE BIT(5)
#define NEORV32_SYSINFO_FEATURES_OCD BIT(14) #define NEORV32_SYSINFO_SOC_DCACHE BIT(6)
#define NEORV32_SYSINFO_FEATURES_HW_RESET BIT(15) #define NEORV32_SYSINFO_SOC_XBUS_CACHE BIT(8)
#define NEORV32_SYSINFO_FEATURES_IO_GPIO BIT(16) #define NEORV32_SYSINFO_SOC_OCD_AUTH BIT(11)
#define NEORV32_SYSINFO_FEATURES_IO_MTIME BIT(17) #define NEORV32_SYSINFO_SOC_IMEM_ROM BIT(12)
#define NEORV32_SYSINFO_FEATURES_IO_UART0 BIT(18) #define NEORV32_SYSINFO_SOC_IO_TWD BIT(13)
#define NEORV32_SYSINFO_FEATURES_IO_SPI BIT(19) #define NEORV32_SYSINFO_SOC_IO_DMA BIT(14)
#define NEORV32_SYSINFO_FEATURES_IO_TWI BIT(20) #define NEORV32_SYSINFO_SOC_IO_GPIO BIT(15)
#define NEORV32_SYSINFO_FEATURES_IO_PWM BIT(21) #define NEORV32_SYSINFO_SOC_IO_CLINT BIT(16)
#define NEORV32_SYSINFO_FEATURES_IO_WDT BIT(22) #define NEORV32_SYSINFO_SOC_IO_UART0 BIT(17)
#define NEORV32_SYSINFO_FEATURES_IO_CFS BIT(23) #define NEORV32_SYSINFO_SOC_IO_SPI BIT(18)
#define NEORV32_SYSINFO_FEATURES_IO_TRNG BIT(24) #define NEORV32_SYSINFO_SOC_IO_TWI BIT(19)
#define NEORV32_SYSINFO_FEATURES_IO_SLINK BIT(25) #define NEORV32_SYSINFO_SOC_IO_PWM BIT(20)
#define NEORV32_SYSINFO_FEATURES_IO_UART1 BIT(26) #define NEORV32_SYSINFO_SOC_IO_WDT BIT(21)
#define NEORV32_SYSINFO_FEATURES_IO_NEOLED BIT(27) #define NEORV32_SYSINFO_SOC_IO_CFS BIT(22)
#define NEORV32_SYSINFO_SOC_IO_TRNG BIT(23)
#define NEORV32_SYSINFO_SOC_IO_SDI BIT(24)
#define NEORV32_SYSINFO_SOC_IO_UART1 BIT(25)
#define NEORV32_SYSINFO_SOC_IO_NEOLED BIT(26)
#define NEORV32_SYSINFO_SOC_IO_GPTMR BIT(28)
#define NEORV32_SYSINFO_SOC_IO_SLINK BIT(29)
#define NEORV32_SYSINFO_SOC_IO_ONEWIRE BIT(30)
#define NEORV32_SYSINFO_SOC_IO_CRC BIT(31)
#endif /* RISCV_NEORV32_SOC_H */ /* System information (SYSINFO) CACHE register bits */
#define NEORV32_SYSINFO_CACHE_INST_BLOCK_SIZE GENMASK(3, 0)
#define NEORV32_SYSINFO_CACHE_INST_NUM_BLOCKS GENMASK(7, 4)
#define NEORV32_SYSINFO_CACHE_DATA_BLOCK_SIZE GENMASK(11, 8)
#define NEORV32_SYSINFO_CACHE_DATA_NUM_BLOCKS GENMASK(15, 12)
#define NEORV32_SYSINFO_CACHE_XBUS_BLOCK_SIZE GENMASK(27, 24)
#define NEORV32_SYSINFO_CACHE_XBUS_NUM_BLOCKS GENMASK(31, 28)
#endif /* _NEORV32_SOC_H */

View file

@ -13,16 +13,4 @@ GTEXT(__soc_handle_irq)
* Exception number is given as parameter via register a0. * Exception number is given as parameter via register a0.
*/ */
SECTION_FUNC(exception.other, __soc_handle_irq) SECTION_FUNC(exception.other, __soc_handle_irq)
/*
* The MIP CSR on the NEORV32 is read-only and can thus not be used for
* clearing a pending IRQ. Instead we disable the IRQ in the MIE CSR and
* re-enable it (if it was enabled when clearing).
*/
li t1, 1
sll t0, t1, a0
csrrc t2, mie, t0
and t1, t2, t0
csrrs t2, mie, t1
/* Return */
ret ret

View file

@ -1,9 +0,0 @@
/*
* Copyright (c) 2021 Henrik Brix Andersen <henrik@brixandersen.dk>
*
* SPDX-License-Identifier: Apache-2.0
*/
&trng {
status = "okay";
};