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:
parent
4899cc10ac
commit
63c24d9d34
20 changed files with 340 additions and 409 deletions
|
@ -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}
|
||||||
|
|
7
boards/others/neorv32/Kconfig
Normal file
7
boards/others/neorv32/Kconfig
Normal 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
|
|
@ -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
|
||||||
|
|
|
@ -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";
|
||||||
};
|
};
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
|
@ -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, \
|
||||||
|
|
|
@ -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) \
|
||||||
}; \
|
}; \
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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>;
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
|
@ -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 "")
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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>
|
|
|
@ -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
|
|
||||||
|
|
|
@ -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 */
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -1,9 +0,0 @@
|
||||||
/*
|
|
||||||
* Copyright (c) 2021 Henrik Brix Andersen <henrik@brixandersen.dk>
|
|
||||||
*
|
|
||||||
* SPDX-License-Identifier: Apache-2.0
|
|
||||||
*/
|
|
||||||
|
|
||||||
&trng {
|
|
||||||
status = "okay";
|
|
||||||
};
|
|
Loading…
Add table
Add a link
Reference in a new issue