From d75c373da786598a50dc1a43c3fa452e980f707a Mon Sep 17 00:00:00 2001 From: Markus Koch Date: Mon, 2 Dec 2024 13:28:44 +0100 Subject: [PATCH] Add support for Zephyr Most of the basic SoC drivers are copied from the official SERV source code and have only been adapted. This commit also adds device tree files and other definitions to support the Trashernet hardware. A preliminary driver (polling-based) for the Trashernet Ethernet module is also included. --- zephyr/west.yml | 9 + zephyr/zephyr/CMakeLists.txt | 4 + zephyr/zephyr/Kconfig | 8 + .../boards/riscv/trashernet_soc/Kconfig.board | 8 + .../riscv/trashernet_soc/Kconfig.defconfig | 13 + .../riscv/trashernet_soc/trashernet.yaml | 17 ++ .../riscv/trashernet_soc/trashernet_soc.dts | 40 +++ .../trashernet_soc/trashernet_soc_defconfig | 13 + zephyr/zephyr/drivers/CMakeLists.txt | 7 + zephyr/zephyr/drivers/Kconfig | 12 + zephyr/zephyr/drivers/serial/CMakeLists.txt | 7 + zephyr/zephyr/drivers/serial/Kconfig | 13 + .../zephyr/drivers/serial/uart_trashernet.c | 79 ++++++ zephyr/zephyr/drivers/timer/CMakeLists.txt | 5 + zephyr/zephyr/drivers/timer/Kconfig | 9 + zephyr/zephyr/drivers/timer/serv_timer.c | 142 ++++++++++ .../zephyr/drivers/trashernet/CMakeLists.txt | 5 + zephyr/zephyr/drivers/trashernet/Kconfig | 10 + zephyr/zephyr/drivers/trashernet/trashernet.c | 253 ++++++++++++++++++ .../ethernet/notsyncing,trashernet.yaml | 14 + zephyr/zephyr/dts/riscv/serv.dtsi | 24 ++ zephyr/zephyr/module.yml | 5 + .../zephyr/soc/riscv/servant/CMakeLists.txt | 8 + .../soc/riscv/servant/Kconfig.defconfig | 26 ++ zephyr/zephyr/soc/riscv/servant/Kconfig.soc | 8 + zephyr/zephyr/soc/riscv/servant/cpu_idle.c | 22 ++ zephyr/zephyr/soc/riscv/servant/irq.c | 58 ++++ zephyr/zephyr/soc/riscv/servant/linker.ld | 7 + zephyr/zephyr/soc/riscv/servant/soc.h | 16 ++ zephyr/zephyr/soc/riscv/servant/soc_common.h | 56 ++++ zephyr/zephyr/soc/riscv/servant/soc_irq.S | 56 ++++ zephyr/zephyr/soc/riscv/servant/vector.S | 28 ++ 32 files changed, 982 insertions(+) create mode 100644 zephyr/west.yml create mode 100644 zephyr/zephyr/CMakeLists.txt create mode 100644 zephyr/zephyr/Kconfig create mode 100644 zephyr/zephyr/boards/riscv/trashernet_soc/Kconfig.board create mode 100644 zephyr/zephyr/boards/riscv/trashernet_soc/Kconfig.defconfig create mode 100644 zephyr/zephyr/boards/riscv/trashernet_soc/trashernet.yaml create mode 100644 zephyr/zephyr/boards/riscv/trashernet_soc/trashernet_soc.dts create mode 100644 zephyr/zephyr/boards/riscv/trashernet_soc/trashernet_soc_defconfig create mode 100644 zephyr/zephyr/drivers/CMakeLists.txt create mode 100644 zephyr/zephyr/drivers/Kconfig create mode 100644 zephyr/zephyr/drivers/serial/CMakeLists.txt create mode 100644 zephyr/zephyr/drivers/serial/Kconfig create mode 100644 zephyr/zephyr/drivers/serial/uart_trashernet.c create mode 100644 zephyr/zephyr/drivers/timer/CMakeLists.txt create mode 100644 zephyr/zephyr/drivers/timer/Kconfig create mode 100644 zephyr/zephyr/drivers/timer/serv_timer.c create mode 100644 zephyr/zephyr/drivers/trashernet/CMakeLists.txt create mode 100644 zephyr/zephyr/drivers/trashernet/Kconfig create mode 100644 zephyr/zephyr/drivers/trashernet/trashernet.c create mode 100644 zephyr/zephyr/dts/bindings/ethernet/notsyncing,trashernet.yaml create mode 100644 zephyr/zephyr/dts/riscv/serv.dtsi create mode 100644 zephyr/zephyr/module.yml create mode 100644 zephyr/zephyr/soc/riscv/servant/CMakeLists.txt create mode 100644 zephyr/zephyr/soc/riscv/servant/Kconfig.defconfig create mode 100644 zephyr/zephyr/soc/riscv/servant/Kconfig.soc create mode 100644 zephyr/zephyr/soc/riscv/servant/cpu_idle.c create mode 100644 zephyr/zephyr/soc/riscv/servant/irq.c create mode 100644 zephyr/zephyr/soc/riscv/servant/linker.ld create mode 100644 zephyr/zephyr/soc/riscv/servant/soc.h create mode 100644 zephyr/zephyr/soc/riscv/servant/soc_common.h create mode 100644 zephyr/zephyr/soc/riscv/servant/soc_irq.S create mode 100644 zephyr/zephyr/soc/riscv/servant/vector.S diff --git a/zephyr/west.yml b/zephyr/west.yml new file mode 100644 index 0000000..cc4c437 --- /dev/null +++ b/zephyr/west.yml @@ -0,0 +1,9 @@ +manifest: + remotes: + - name: zephyrproject-rtos + url-base: https://github.com/zephyrproject-rtos + projects: + - name: zephyr + remote: zephyrproject-rtos + revision: v3.7.0 + import: true diff --git a/zephyr/zephyr/CMakeLists.txt b/zephyr/zephyr/CMakeLists.txt new file mode 100644 index 0000000..359918e --- /dev/null +++ b/zephyr/zephyr/CMakeLists.txt @@ -0,0 +1,4 @@ +# Copyright (c) 2020 Olof Kindgren +# SPDX-License-Identifier: Apache-2.0 + +add_subdirectory(drivers) diff --git a/zephyr/zephyr/Kconfig b/zephyr/zephyr/Kconfig new file mode 100644 index 0000000..b4e2f3b --- /dev/null +++ b/zephyr/zephyr/Kconfig @@ -0,0 +1,8 @@ +# Copyright (c) 2020 Olof Kindgren +# SPDX-License-Identifier: Apache-2.0 + +menu "SweRVolf" + +rsource "drivers/Kconfig" + +endmenu diff --git a/zephyr/zephyr/boards/riscv/trashernet_soc/Kconfig.board b/zephyr/zephyr/boards/riscv/trashernet_soc/Kconfig.board new file mode 100644 index 0000000..0953158 --- /dev/null +++ b/zephyr/zephyr/boards/riscv/trashernet_soc/Kconfig.board @@ -0,0 +1,8 @@ +# Copyright (c) 2020 Olof Kindgren +# Copyright (c) 2024 Markus Koch +# +# SPDX-License-Identifier: Apache-2.0 + +config BOARD_TRASHERNET_SOC + bool "Trashernet SoC" + depends on SOC_RISCV32_SERVANT diff --git a/zephyr/zephyr/boards/riscv/trashernet_soc/Kconfig.defconfig b/zephyr/zephyr/boards/riscv/trashernet_soc/Kconfig.defconfig new file mode 100644 index 0000000..4467d88 --- /dev/null +++ b/zephyr/zephyr/boards/riscv/trashernet_soc/Kconfig.defconfig @@ -0,0 +1,13 @@ +# Copyright (c) 2020 Olof Kindgren +# Copyright (c) 2024 Markus Koch +# +# SPDX-License-Identifier: Apache-2.0 + +config BOARD + default "trashernet_soc" + depends on BOARD_TRASHERNET_SOC + +config ETH_TRASHERNET + bool + default y + depends on NET_L2_ETHERNET diff --git a/zephyr/zephyr/boards/riscv/trashernet_soc/trashernet.yaml b/zephyr/zephyr/boards/riscv/trashernet_soc/trashernet.yaml new file mode 100644 index 0000000..3b91a50 --- /dev/null +++ b/zephyr/zephyr/boards/riscv/trashernet_soc/trashernet.yaml @@ -0,0 +1,17 @@ +# Copyright (c) 2020 Olof Kindgren +# Copyright (c) 2024 Markus Koch +# +# SPDX-License-Identifier: Apache-2.0 + +identifier: trashernet_soc +name: Trashernet SoC +type: mcu +arch: riscv32 +toolchain: + - zephyr +ram: 32 +vendor: notsyncing.net +testing: + ignore_tags: + - net + - bluetooth diff --git a/zephyr/zephyr/boards/riscv/trashernet_soc/trashernet_soc.dts b/zephyr/zephyr/boards/riscv/trashernet_soc/trashernet_soc.dts new file mode 100644 index 0000000..ae70730 --- /dev/null +++ b/zephyr/zephyr/boards/riscv/trashernet_soc/trashernet_soc.dts @@ -0,0 +1,40 @@ +/* + * Copyright (c) 2020 Olof Kindgren + * Copyright (c) 2024 Markus Koch + * + * SPDX-License-Identifier: Apache-2.0 + */ + +/dts-v1/; + +#include + +/ { + chosen { + zephyr,sram = &ram; + zephyr,console = &uart0; + }; + + ram: memory@0 { + compatible = "mmio-sram"; + reg = <0x40000000 0x800000>; + }; + + soc { + compatible = "olofk,serv"; + #address-cells = <1>; + #size-cells = <1>; + + uart0: serial@0 { + reg = <0x0 0x1>; + compatible = "trashernet,serial"; + }; + + eth0: ethernet@0 { + reg = <0x0 0x1>; + compatible = "notsyncing,trashernet"; + local-mac-address = [10 b1 7d df 6f db]; + }; + }; +}; + diff --git a/zephyr/zephyr/boards/riscv/trashernet_soc/trashernet_soc_defconfig b/zephyr/zephyr/boards/riscv/trashernet_soc/trashernet_soc_defconfig new file mode 100644 index 0000000..160cc20 --- /dev/null +++ b/zephyr/zephyr/boards/riscv/trashernet_soc/trashernet_soc_defconfig @@ -0,0 +1,13 @@ +# Copyright (c) 2020 Olof Kindgren +# Copyright (c) 2024 Markus Koch +# +# SPDX-License-Identifier: Apache-2.0 + +CONFIG_BOARD_TRASHERNET_SOC=y +CONFIG_CONSOLE=y +CONFIG_SERIAL=y +CONFIG_UART_TRASHERNET=y +CONFIG_NET_L2_ETHERNET=y +CONFIG_UART_CONSOLE=y + +CONFIG_XIP=n diff --git a/zephyr/zephyr/drivers/CMakeLists.txt b/zephyr/zephyr/drivers/CMakeLists.txt new file mode 100644 index 0000000..5a27ff7 --- /dev/null +++ b/zephyr/zephyr/drivers/CMakeLists.txt @@ -0,0 +1,7 @@ +# Copyright (c) 2020 Olof Kindgren +# SPDX-License-Identifier: Apache-2.0 + +add_subdirectory_ifdef(CONFIG_SERIAL_HAS_DRIVER serial) +add_subdirectory_ifdef(CONFIG_SYS_CLOCK_EXISTS timer) +add_subdirectory_ifdef(CONFIG_ETH_TRASHERNET trashernet) + diff --git a/zephyr/zephyr/drivers/Kconfig b/zephyr/zephyr/drivers/Kconfig new file mode 100644 index 0000000..055ae63 --- /dev/null +++ b/zephyr/zephyr/drivers/Kconfig @@ -0,0 +1,12 @@ +# Copyright (c) 2020 Olof Kindgren +# SPDX-License-Identifier: Apache-2.0 + +menu "Device Drivers" + +rsource "serial/Kconfig" + +rsource "timer/Kconfig" + +rsource "trashernet/Kconfig" + +endmenu diff --git a/zephyr/zephyr/drivers/serial/CMakeLists.txt b/zephyr/zephyr/drivers/serial/CMakeLists.txt new file mode 100644 index 0000000..8a91125 --- /dev/null +++ b/zephyr/zephyr/drivers/serial/CMakeLists.txt @@ -0,0 +1,7 @@ +# Copyright (c) 2020 Olof Kindgren +# Copyright (c) 2024 Markus Koch +# SPDX-License-Identifier: Apache-2.0 + +set(ZEPHYR_CURRENT_LIBRARY drivers__serial) + +zephyr_library_sources_ifdef(CONFIG_UART_TRASHERNET uart_trashernet.c) diff --git a/zephyr/zephyr/drivers/serial/Kconfig b/zephyr/zephyr/drivers/serial/Kconfig new file mode 100644 index 0000000..f4e6fce --- /dev/null +++ b/zephyr/zephyr/drivers/serial/Kconfig @@ -0,0 +1,13 @@ +# Copyright (c) 2020 Olof Kindgren +# Copyright (c) 2024 Markus Koch +# SPDX-License-Identifier: Apache-2.0 + +if SERIAL + +menuconfig UART_TRASHERNET + bool "Trashernet serial driver" + select SERIAL_HAS_DRIVER + help + Enables the Trashernet serial driver + +endif diff --git a/zephyr/zephyr/drivers/serial/uart_trashernet.c b/zephyr/zephyr/drivers/serial/uart_trashernet.c new file mode 100644 index 0000000..1aa674e --- /dev/null +++ b/zephyr/zephyr/drivers/serial/uart_trashernet.c @@ -0,0 +1,79 @@ +/* + * Copyright (c) 2020 Olof Kindgren + * Copyright (c) 2024 Markus Koch + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include +#include +#include +#include + +#define UART0_BASE 0x81000000 +#define UART0_SR (*((volatile uint32_t *) (UART0_BASE + 0x00))) +#define UART0_DR (*((volatile uint32_t *) (UART0_BASE + 0x04))) + +#define UART0_SR_RX_DATA_EMPTY (1 << 0) +#define UART0_SR_TX_FULL (1 << 1) + +#define DT_DRV_COMPAT trashernet_serial + +static struct k_spinlock lock; + +static void uart_trashernet_poll_out(const struct device *dev, unsigned char c) +{ + ARG_UNUSED(dev); + + k_spinlock_key_t key = k_spin_lock(&lock); + + while (UART0_SR & UART0_SR_TX_FULL); + UART0_DR = c; + + k_spin_unlock(&lock, key); +} + +static int uart_trashernet_poll_in(const struct device *dev, unsigned char *c) +{ + ARG_UNUSED(dev); + + *c = UART0_DR; + + return (UART0_SR & UART0_SR_RX_DATA_EMPTY) ? -1 : 0; +} + +static int uart_trashernet_init(const struct device *dev) +{ + ARG_UNUSED(dev); + return 0; +} + +static const struct uart_driver_api uart_trashernet_driver_api = { + .poll_in = uart_trashernet_poll_in, + .poll_out = uart_trashernet_poll_out, + .err_check = NULL, +}; + +struct my_dev_data { + +}; + +struct my_dev_cfg { + +}; + +#define CREATE_MY_DEVICE(inst) \ + static struct my_dev_data my_data_##inst = { \ + }; \ + static const struct my_dev_cfg my_cfg_##inst = { \ + }; \ + DEVICE_DT_INST_DEFINE(inst, \ + uart_trashernet_init, \ + NULL, \ + &my_data_##inst, \ + &my_cfg_##inst, \ + PRE_KERNEL_1, CONFIG_SERIAL_INIT_PRIORITY, \ + &uart_trashernet_driver_api); + +DT_INST_FOREACH_STATUS_OKAY(CREATE_MY_DEVICE) diff --git a/zephyr/zephyr/drivers/timer/CMakeLists.txt b/zephyr/zephyr/drivers/timer/CMakeLists.txt new file mode 100644 index 0000000..0a14e26 --- /dev/null +++ b/zephyr/zephyr/drivers/timer/CMakeLists.txt @@ -0,0 +1,5 @@ +# Copyright (c) 2020 Olof Kindgren +# SPDX-License-Identifier: Apache-2.0 + +zephyr_library_sources_ifdef(CONFIG_SERV_TIMER serv_timer.c) + diff --git a/zephyr/zephyr/drivers/timer/Kconfig b/zephyr/zephyr/drivers/timer/Kconfig new file mode 100644 index 0000000..24b9356 --- /dev/null +++ b/zephyr/zephyr/drivers/timer/Kconfig @@ -0,0 +1,9 @@ +# Copyright (c) 2020 Olof Kindgren +# SPDX-License-Identifier: Apache-2.0 + +config SERV_TIMER + bool "SERV Timer" + select TICKLESS_CAPABLE + help + This module implements a kernel device driver for the SERV + timer driver. It provides the standard "system clock driver" interfaces. diff --git a/zephyr/zephyr/drivers/timer/serv_timer.c b/zephyr/zephyr/drivers/timer/serv_timer.c new file mode 100644 index 0000000..a31e555 --- /dev/null +++ b/zephyr/zephyr/drivers/timer/serv_timer.c @@ -0,0 +1,142 @@ +/* + * Copyright (c) 2020 Olof Kindgren + * + * SPDX-License-Identifier: Apache-2.0 + */ + +/* + This is basically a 32-bit version of riscv_machine_timer.c for Zephyr +*/ +#include +#include +#include +#include +#include + +#define CYC_PER_TICK ((uint32_t)((uint32_t)sys_clock_hw_cycles_per_sec() \ + / (uint32_t)CONFIG_SYS_CLOCK_TICKS_PER_SEC)) +#define MAX_CYC 0xffffffffu +#define MAX_TICKS ((MAX_CYC - CYC_PER_TICK) / CYC_PER_TICK) +#define MIN_DELAY 1000 + +#define TICKLESS IS_ENABLED(CONFIG_TICKLESS_KERNEL) + +static struct k_spinlock lock; +static uint32_t last_count; + +static ALWAYS_INLINE void set_mtimecmp(uint32_t time) +{ + //printk("set_mtimecmp to %d @ %d\n", time, sys_read32(SERV_TIMER_BASE)); + sys_write32(time, SERV_TIMER_BASE); +} + +static ALWAYS_INLINE uint32_t mtime(void) +{ + return sys_read32(SERV_TIMER_BASE); +} + +static void timer_isr(void *arg) +{ + //printk("timer isr\n"); + ARG_UNUSED(arg); + + k_spinlock_key_t key = k_spin_lock(&lock); + uint32_t now = mtime(); + uint32_t dticks = ((now - last_count) / CYC_PER_TICK); + + last_count += dticks * CYC_PER_TICK; + + if (!TICKLESS) { + uint32_t next = last_count + CYC_PER_TICK; + + if ((int32_t)(next - now) < MIN_DELAY) { + next += CYC_PER_TICK; + } + set_mtimecmp(next); + } + + k_spin_unlock(&lock, key); + sys_clock_announce(IS_ENABLED(CONFIG_TICKLESS_KERNEL) ? dticks : 1); +} + +int irq_testy() +{ + printk("test isr\n"); + return 0; +} + +int sys_clock_driver_init() +{ + IRQ_CONNECT(RISCV_MACHINE_TIMER_IRQ, 0, timer_isr, NULL, 0); + //IRQ_CONNECT(5, 0, irq_testy, NULL, 0); + last_count = mtime(); + set_mtimecmp(last_count + (uint32_t)CYC_PER_TICK); + //irq_enable(5); + irq_enable(RISCV_MACHINE_TIMER_IRQ); + return 0; +} + +void sys_clock_set_timeout(int32_t ticks, bool idle) +{ + ARG_UNUSED(idle); + +#if defined(CONFIG_TICKLESS_KERNEL) + /* RISCV has no idle handler yet, so if we try to spin on the + * logic below to reset the comparator, we'll always bump it + * forward to the "next tick" due to MIN_DELAY handling and + * the interrupt will never fire! Just rely on the fact that + * the OS gave us the proper timeout already. + */ + if (idle) { + return; + } + + ticks = ticks == K_TICKS_FOREVER ? MAX_TICKS : ticks; + ticks = MAX(MIN(ticks - 1, (int32_t)MAX_TICKS), 0); + + k_spinlock_key_t key = k_spin_lock(&lock); + uint32_t now = mtime(); + uint32_t adj, cyc = ticks * CYC_PER_TICK; + + /* Round up to next tick boundary. */ + adj = (now - last_count) + (CYC_PER_TICK - 1); + if (cyc <= MAX_CYC - adj) { + cyc += adj; + } else { + cyc = MAX_CYC; + } + cyc = (cyc / CYC_PER_TICK) * CYC_PER_TICK; + + if ((int32_t)(cyc + last_count - now) < MIN_DELAY) { + cyc += CYC_PER_TICK; + } + + set_mtimecmp(cyc + last_count); + k_spin_unlock(&lock, key); +#endif +} + +uint32_t sys_clock_elapsed(void) +{ + if (!IS_ENABLED(CONFIG_TICKLESS_KERNEL)) { + return 0; + } + + k_spinlock_key_t key = k_spin_lock(&lock); + uint32_t ret = (mtime() - last_count) / CYC_PER_TICK; + + k_spin_unlock(&lock, key); + return ret; +} + +uint32_t sys_timer_cycle_get_32(void) +{ + return mtime(); +} + +uint32_t sys_clock_cycle_get_32(void) +{ + return mtime(); +} +SYS_INIT(sys_clock_driver_init, PRE_KERNEL_2, + CONFIG_SYSTEM_CLOCK_INIT_PRIORITY); diff --git a/zephyr/zephyr/drivers/trashernet/CMakeLists.txt b/zephyr/zephyr/drivers/trashernet/CMakeLists.txt new file mode 100644 index 0000000..b9e732d --- /dev/null +++ b/zephyr/zephyr/drivers/trashernet/CMakeLists.txt @@ -0,0 +1,5 @@ +# Copyright (c) 2024 Markus Koch +# SPDX-License-Identifier: Apache-2.0 + +zephyr_library_sources_ifdef(CONFIG_ETH_TRASHERNET trashernet.c) + diff --git a/zephyr/zephyr/drivers/trashernet/Kconfig b/zephyr/zephyr/drivers/trashernet/Kconfig new file mode 100644 index 0000000..4fd2cb8 --- /dev/null +++ b/zephyr/zephyr/drivers/trashernet/Kconfig @@ -0,0 +1,10 @@ +# Copyright (c) 2024 Markus Koch +# SPDX-License-Identifier: Apache-2.0 + +config ETH_TRASHERNET + bool "Trashernet 10MBit/s PHY driver" + depends on NETWORKING + depends on !TEST_NET + depends on NET_L2_ETHERNET + help + This module implements a kernel device driver for the Trashernet 10 MBit/s PHY. diff --git a/zephyr/zephyr/drivers/trashernet/trashernet.c b/zephyr/zephyr/drivers/trashernet/trashernet.c new file mode 100644 index 0000000..e2e5d1d --- /dev/null +++ b/zephyr/zephyr/drivers/trashernet/trashernet.c @@ -0,0 +1,253 @@ +/* TRASHERNET Stand-alone Ethernet Controller with SPI + * + * Copyright (c) 2016 Markus Koch + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#define DT_DRV_COMPAT notsyncing_trashernet + +#define LOG_MODULE_NAME eth_trashernet +#define LOG_LEVEL CONFIG_ETHERNET_LOG_LEVEL + +// TODO: Load this stuff from DT +#define TRASHERNET_BASE 0x82000000 +#define TRASHERNET_SR (*((volatile uint32_t *) (TRASHERNET_BASE + 0x00))) +#define TRASHERNET_DR (*((volatile uint8_t *) (TRASHERNET_BASE + 0x04))) + +#define TRASHERNET_SR_LINK_UP (1 << 0) +#define TRASHERNET_SR_RX_AVAILABLE (1 << 1) +#define TRASHERNET_SR_TX_NOTEMPTY (1 << 2) + +#include +LOG_MODULE_REGISTER(LOG_MODULE_NAME); + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define ETH_TRASHERNET_RX_THREAD_STACK_SIZE 800 +#define ETH_TRASHERNET_RX_THREAD_PRIO 2 + +struct eth_trashernet_config { + int32_t timeout; +}; + +struct eth_trashernet_runtime { + struct net_if *iface; + K_KERNEL_STACK_MEMBER(thread_stack, ETH_TRASHERNET_RX_THREAD_STACK_SIZE); + struct k_thread thread; + struct k_sem int_sem; + bool iface_initialized : 1; + uint8_t mac_address[6]; +}; + +static void eth_trashernet_set_data(const struct device *dev, uint8_t *buffer, uint16_t length) +{ + uint16_t i; + for (i=0; i < length; ++i) { + TRASHERNET_DR = buffer[i]; + } +} + +static int eth_trashernet_tx(const struct device *dev, struct net_pkt *pkt) +{ + struct eth_trashernet_runtime *context = dev->data; + uint16_t len = net_pkt_get_len(pkt); + struct net_buf *frag; + + LOG_DBG("TX %s: pkt %p (len %u)", dev->name, pkt, len); + + while (TRASHERNET_SR & TRASHERNET_SR_TX_NOTEMPTY); // FIXME: To be fixed in HDL: We currently do not support TX packet separation, so we have to wait for the TX buffer to be completely empty before adding the next packet. + + for (frag = pkt->frags; frag; frag = frag->frags) { + eth_trashernet_set_data(dev, frag->data, frag->len); + } + TRASHERNET_SR = TRASHERNET_SR_TX_NOTEMPTY; // Frame complete, TX now + + //LOG_DBG("%s: Tx successful", dev->name); + + return 0; +} + +static void eth_trashernet_get_data(const struct device *dev, uint8_t *buffer, uint16_t length) +{ + for (int x = 0; x < length; ++x) { + buffer[x] = TRASHERNET_DR; + } +} + +static int eth_trashernet_rx(const struct device *dev) +{ + struct eth_trashernet_runtime *context = dev->data; + const struct eth_trashernet_config *config = dev->config; + uint16_t frm_len; + uint16_t lengthfr; + + struct net_buf *pkt_buf; + struct net_pkt *pkt; + + frm_len = TRASHERNET_SR >> 16; + TRASHERNET_SR = (1 << 1); // Confirm that we've read the length + if (!frm_len) { + LOG_ERR("%s: Receive called without data available!", dev->name); + return 0; + } + //LOG_DBG("RX Data %d", frm_len); + + pkt = net_pkt_rx_alloc_with_buffer(context->iface, frm_len, + AF_UNSPEC, 0, K_MSEC(config->timeout)); + if (!pkt) { + LOG_ERR("%s: Could not allocate rx buffer", dev->name); + return 0; + } + + pkt_buf = pkt->buffer; + lengthfr = frm_len; + + do { + size_t frag_len; + uint8_t *data_ptr; + size_t spi_frame_len; + + data_ptr = pkt_buf->data; + + /* Review the space available for the new frag */ + frag_len = net_buf_tailroom(pkt_buf); + + if (frm_len > frag_len) { + spi_frame_len = frag_len; + } else { + spi_frame_len = frm_len; + } + + eth_trashernet_get_data(dev, data_ptr, spi_frame_len); + + net_buf_add(pkt_buf, spi_frame_len); + + /* One fragment has been written via SPI */ + frm_len -= spi_frame_len; + pkt_buf = pkt_buf->frags; + } while (frm_len > 0); + + net_pkt_set_iface(pkt, context->iface); + + LOG_DBG("%s: Received packet of length %u", dev->name, lengthfr); + if (net_recv_data(net_pkt_iface(pkt), pkt) < 0) { + net_pkt_unref(pkt); + } + + return 0; +} + +static void eth_trashernet_rx_thread(void *p1, void *p2, void *p3) +{ + int status_last = 0; + int status = 0; + ARG_UNUSED(p2); + ARG_UNUSED(p3); + + const struct device *dev = p1; + struct eth_trashernet_runtime *context = dev->data; + + while (true) { + //k_sem_take(&context->int_sem, K_FOREVER); // Set to wait for IRQ + //k_sem_give(&context->int_sem); // Set in IRQ + + status = TRASHERNET_SR; + if ((status ^ status_last) & TRASHERNET_SR_LINK_UP) { // Link change + if (status & TRASHERNET_SR_LINK_UP) { + LOG_INF("%s: Link up", dev->name); + net_eth_carrier_on(context->iface); + } else { + LOG_INF("%s: Link down", dev->name); + + if (context->iface_initialized) { + net_eth_carrier_off(context->iface); + } + } + } + if (status & TRASHERNET_SR_RX_AVAILABLE) { // New RX data + eth_trashernet_rx(dev); + } else { + k_msleep(10); // We poll + } + status_last = status; + } +} + +static enum ethernet_hw_caps eth_trashernet_get_capabilities(const struct device *dev) +{ + ARG_UNUSED(dev); + + return ETHERNET_LINK_10BASE_T +#if defined(CONFIG_NET_VLAN) + | ETHERNET_HW_VLAN +#endif + ; +} + +static void eth_trashernet_iface_init(struct net_if *iface) +{ + const struct device *dev = net_if_get_device(iface); + struct eth_trashernet_runtime *context = dev->data; + + net_if_set_link_addr(iface, context->mac_address, + sizeof(context->mac_address), + NET_LINK_ETHERNET); + + if (context->iface == NULL) { + context->iface = iface; + } + + ethernet_init(iface); + + net_if_carrier_off(iface); + context->iface_initialized = true; +} + +static const struct ethernet_api api_funcs = { + .iface_api.init = eth_trashernet_iface_init, + + .get_capabilities = eth_trashernet_get_capabilities, + .send = eth_trashernet_tx, +}; + +static int eth_trashernet_init(const struct device *dev) +{ + const struct eth_trashernet_config *config = dev->config; + struct eth_trashernet_runtime *context = dev->data; + + /* Start interruption-poll thread */ + k_thread_create(&context->thread, context->thread_stack, + ETH_TRASHERNET_RX_THREAD_STACK_SIZE, + eth_trashernet_rx_thread, + (void *)dev, NULL, NULL, + K_PRIO_COOP(ETH_TRASHERNET_RX_THREAD_PRIO), + 0, K_NO_WAIT); + + LOG_INF("%s: Initialized", dev->name); + return 0; +} + +#define TRASHERNET_DEFINE(inst) \ + static struct eth_trashernet_runtime eth_trashernet_runtime_##inst = { \ + .mac_address = DT_INST_PROP(inst, local_mac_address), \ + .int_sem = Z_SEM_INITIALIZER((eth_trashernet_runtime_##inst).int_sem, 0, UINT_MAX), \ + }; \ + \ + static const struct eth_trashernet_config eth_trashernet_config_##inst = { \ + .timeout = 500, \ + }; \ + \ + ETH_NET_DEVICE_DT_INST_DEFINE(inst, eth_trashernet_init, NULL, ð_trashernet_runtime_##inst, \ + ð_trashernet_config_##inst, CONFIG_ETH_INIT_PRIORITY, \ + &api_funcs, NET_ETH_MTU); + +DT_INST_FOREACH_STATUS_OKAY(TRASHERNET_DEFINE); diff --git a/zephyr/zephyr/dts/bindings/ethernet/notsyncing,trashernet.yaml b/zephyr/zephyr/dts/bindings/ethernet/notsyncing,trashernet.yaml new file mode 100644 index 0000000..43bf263 --- /dev/null +++ b/zephyr/zephyr/dts/bindings/ethernet/notsyncing,trashernet.yaml @@ -0,0 +1,14 @@ +# Copyright (c) 2024 Markus Koch +# SPDX-License-Identifier: Apache-2.0 + +description: Trashernet PHY + +compatible: "notsyncing,trashernet" + +include: [ethernet-controller.yaml] + +properties: + full-duplex: + type: boolean + description: | + Optional feature flag - Enables full duplex reception and transmission. diff --git a/zephyr/zephyr/dts/riscv/serv.dtsi b/zephyr/zephyr/dts/riscv/serv.dtsi new file mode 100644 index 0000000..139b86a --- /dev/null +++ b/zephyr/zephyr/dts/riscv/serv.dtsi @@ -0,0 +1,24 @@ +/* + * Copyright (c) 2020 Olof Kindgren + * Copyright (c) 2024 Markus Koch + * + * SPDX-License-Identifier: Apache-2.0 + */ + +/ { + #address-cells = <1>; + #size-cells = <1>; + compatible = "olofk,servant"; + + cpus { + #address-cells = <1>; + #size-cells = <0>; + + cpu0: cpu@0 { + compatible = "olofk,serv"; + riscv,isa = "rv32i_zicsr"; + reg = <0>; + device_type = "cpu"; + }; + }; +}; diff --git a/zephyr/zephyr/module.yml b/zephyr/zephyr/module.yml new file mode 100644 index 0000000..07da43f --- /dev/null +++ b/zephyr/zephyr/module.yml @@ -0,0 +1,5 @@ +build: + settings: + board_root: zephyr + dts_root: zephyr + soc_root: zephyr diff --git a/zephyr/zephyr/soc/riscv/servant/CMakeLists.txt b/zephyr/zephyr/soc/riscv/servant/CMakeLists.txt new file mode 100644 index 0000000..d49f442 --- /dev/null +++ b/zephyr/zephyr/soc/riscv/servant/CMakeLists.txt @@ -0,0 +1,8 @@ +# Copyright (c) 2020 Olof Kindgren +# SPDX-License-Identifier: Apache-2.0 + +zephyr_sources( + soc_irq.S + vector.S + irq.c + cpu_idle.c) diff --git a/zephyr/zephyr/soc/riscv/servant/Kconfig.defconfig b/zephyr/zephyr/soc/riscv/servant/Kconfig.defconfig new file mode 100644 index 0000000..c1ed843 --- /dev/null +++ b/zephyr/zephyr/soc/riscv/servant/Kconfig.defconfig @@ -0,0 +1,26 @@ +# Copyright (c) 2020 Olof Kindgren +# SPDX-License-Identifier: Apache-2.0 + +if SOC_RISCV32_SERVANT + +config SOC + string + default "servant" + +config SYS_CLOCK_HW_CYCLES_PER_SEC + int + default 25000000 + +config RISCV_SOC_INTERRUPT_INIT + bool + default y + +config NUM_IRQS + int + default 8 + +config SERV_TIMER + bool + default y + +endif # SOC_RISCV32_SERVANT diff --git a/zephyr/zephyr/soc/riscv/servant/Kconfig.soc b/zephyr/zephyr/soc/riscv/servant/Kconfig.soc new file mode 100644 index 0000000..932055c --- /dev/null +++ b/zephyr/zephyr/soc/riscv/servant/Kconfig.soc @@ -0,0 +1,8 @@ +# Copyright (c) 2020 Olof Kindgren +# SPDX-License-Identifier: Apache-2.0 + +config SOC_RISCV32_SERVANT + bool "servant SoC" + select RISCV + select ATOMIC_OPERATIONS_C + select RISCV_ISA_EXT_ZICSR diff --git a/zephyr/zephyr/soc/riscv/servant/cpu_idle.c b/zephyr/zephyr/soc/riscv/servant/cpu_idle.c new file mode 100644 index 0000000..e51fd9a --- /dev/null +++ b/zephyr/zephyr/soc/riscv/servant/cpu_idle.c @@ -0,0 +1,22 @@ +#include +#include + +// Override arch_cpu_idle() and arch_cpu_atomic_idle() to prevent insertion +// of `wfi` instructions which lock up our system. This was introduced in +// Zephyr 3.6.0 with commit 5fb6e267f629dedb8382da6bcad8018b1bb8930a. +// +// This is probably a hardware bug in SERV. This issue is tracked as #131. +// https://github.com/olofk/serv/issues/131 + +void arch_cpu_idle(void) +{ + sys_trace_idle(); + irq_unlock(MSTATUS_IEN); +} + +void arch_cpu_atomic_idle(unsigned int key) +{ + sys_trace_idle(); + irq_unlock(key); +} + diff --git a/zephyr/zephyr/soc/riscv/servant/irq.c b/zephyr/zephyr/soc/riscv/servant/irq.c new file mode 100644 index 0000000..61a343f --- /dev/null +++ b/zephyr/zephyr/soc/riscv/servant/irq.c @@ -0,0 +1,58 @@ +/* + * Copyright (c) 2017 Jean-Paul Etienne + * + * SPDX-License-Identifier: Apache-2.0 + */ + +/** + * @file + * @brief interrupt management code for riscv SOCs supporting the riscv + privileged architecture specification + */ +#include + +void arch_irq_enable(unsigned int irq) +{ + uint32_t mie; + + /* + * CSR mie register is updated using atomic instruction csrrs + * (atomic read and set bits in CSR register) + */ + __asm__ volatile ("csrrs %0, mie, %1\n" + : "=r" (mie) + : "r" (1 << irq)); +} + +void arch_irq_disable(unsigned int irq) +{ + uint32_t mie; + + /* + * Use atomic instruction csrrc to disable device interrupt in mie CSR. + * (atomic read and clear bits in CSR register) + */ + __asm__ volatile ("csrrc %0, mie, %1\n" + : "=r" (mie) + : "r" (1 << irq)); +}; + +int arch_irq_is_enabled(unsigned int irq) +{ + uint32_t mie; + + __asm__ volatile ("csrr %0, mie" : "=r" (mie)); + + return !!(mie & (1 << irq)); +} + +#if defined(CONFIG_RISCV_SOC_INTERRUPT_INIT) +void soc_interrupt_init(void) +{ + /* ensure that all interrupts are disabled */ + (void)irq_lock(); + + __asm__ volatile ("csrwi mie, 0\n" + "csrwi mip, 0\n"); +} +#endif diff --git a/zephyr/zephyr/soc/riscv/servant/linker.ld b/zephyr/zephyr/soc/riscv/servant/linker.ld new file mode 100644 index 0000000..0d220a2 --- /dev/null +++ b/zephyr/zephyr/soc/riscv/servant/linker.ld @@ -0,0 +1,7 @@ +/* + * Copyright (c) 2018 Antmicro + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include diff --git a/zephyr/zephyr/soc/riscv/servant/soc.h b/zephyr/zephyr/soc/riscv/servant/soc.h new file mode 100644 index 0000000..7af08cb --- /dev/null +++ b/zephyr/zephyr/soc/riscv/servant/soc.h @@ -0,0 +1,16 @@ +/* + * Copyright (c) 2020 Olof Kindgren + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef __RISCV32_SERVANT_SOC_H_ +#define __RISCV32_SERVANT_SOC_H_ + +#include + +/* Timer configuration */ +#define SERV_TIMER_BASE 0x80000000 +#define SERV_TIMER_IRQ 7 + +#endif /* __RISCV32_SERVANT_SOC_H_ */ diff --git a/zephyr/zephyr/soc/riscv/servant/soc_common.h b/zephyr/zephyr/soc/riscv/servant/soc_common.h new file mode 100644 index 0000000..37c8d6d --- /dev/null +++ b/zephyr/zephyr/soc/riscv/servant/soc_common.h @@ -0,0 +1,56 @@ +/* + * Copyright (c) 2017 Jean-Paul Etienne + * + * SPDX-License-Identifier: Apache-2.0 + */ + +/** + * @file configuration macros for riscv SOCs supporting the riscv + * privileged architecture specification + */ + +#ifndef __SOC_COMMON_H_ +#define __SOC_COMMON_H_ + +/* IRQ numbers */ +#define RISCV_MACHINE_SOFT_IRQ 3 /* Machine Software Interrupt */ +#define RISCV_MACHINE_TIMER_IRQ 7 /* Machine Timer Interrupt */ +#define RISCV_MACHINE_EXT_IRQ 11 /* Machine External Interrupt */ + +/* ECALL Exception numbers */ +#define SOC_MCAUSE_ECALL_EXP 11 /* Machine ECALL instruction */ +#define SOC_MCAUSE_USER_ECALL_EXP 8 /* User ECALL instruction */ + +/* SOC-specific MCAUSE bitfields */ +#ifdef CONFIG_64BIT +/* Interrupt Mask */ +#define SOC_MCAUSE_IRQ_MASK (1 << 63) +/* Exception code Mask */ +#define SOC_MCAUSE_EXP_MASK 0x7FFFFFFFFFFFFFFF +#else +/* Interrupt Mask */ +#define SOC_MCAUSE_IRQ_MASK (1 << 31) +/* Exception code Mask */ +#define SOC_MCAUSE_EXP_MASK 0x7FFFFFFF +#endif + +/* SOC-Specific EXIT ISR command */ +#define SOC_ERET mret + +#ifndef _ASMLANGUAGE + +#if defined(CONFIG_RISCV_SOC_INTERRUPT_INIT) +void soc_interrupt_init(void); +#endif + +#if defined(CONFIG_RISCV_HAS_PLIC) +void riscv_plic_irq_enable(uint32_t irq); +void riscv_plic_irq_disable(uint32_t irq); +int riscv_plic_irq_is_enabled(uint32_t irq); +void riscv_plic_set_priority(uint32_t irq, uint32_t priority); +int riscv_plic_get_irq(void); +#endif + +#endif /* !_ASMLANGUAGE */ + +#endif /* __SOC_COMMON_H_ */ diff --git a/zephyr/zephyr/soc/riscv/servant/soc_irq.S b/zephyr/zephyr/soc/riscv/servant/soc_irq.S new file mode 100644 index 0000000..bbaef8c --- /dev/null +++ b/zephyr/zephyr/soc/riscv/servant/soc_irq.S @@ -0,0 +1,56 @@ +/* + * Copyright (c) 2017 Jean-Paul Etienne + * + * SPDX-License-Identifier: Apache-2.0 + */ + +/* + * common interrupt management code for riscv SOCs supporting the riscv + * privileged architecture specification + */ +#include +#include +#include + +/* exports */ +GTEXT(__soc_handle_irq) + +/* + * SOC-specific function to handle pending IRQ number generating the interrupt. + * Exception number is given as parameter via register a0. + */ +SECTION_FUNC(exception.other, __soc_handle_irq) + /* Clear exception number from CSR mip register */ + li t1, 1 + sll t0, t1, a0 + csrrc t1, mip, t0 + + /* Return */ + jalr x0, ra + +/* + * __soc_is_irq is defined as .weak to allow re-implementation by + * SOCs that does not truly follow the riscv privilege specification. + */ +WTEXT(__soc_is_irq) + +/* + * SOC-specific function to determine if the exception is the result of a + * an interrupt or an exception + * return 1 (interrupt) or 0 (exception) + * + */ +SECTION_FUNC(exception.other, __soc_is_irq) + /* Read mcause and check if interrupt bit is set */ + csrr t0, mcause + li t1, SOC_MCAUSE_IRQ_MASK + and t0, t0, t1 + + /* If interrupt bit is not set, return with 0 */ + addi a0, x0, 0 + beqz t0, not_interrupt + addi a0, a0, 1 + +not_interrupt: + /* return */ + jalr x0, ra diff --git a/zephyr/zephyr/soc/riscv/servant/vector.S b/zephyr/zephyr/soc/riscv/servant/vector.S new file mode 100644 index 0000000..3fa9897 --- /dev/null +++ b/zephyr/zephyr/soc/riscv/servant/vector.S @@ -0,0 +1,28 @@ +/* + * Copyright (c) 2017 Jean-Paul Etienne + * Contributors: 2018 Antmicro + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include + +/* exports */ +GTEXT(__start) + +/* imports */ +GTEXT(__initialize) +GTEXT(_isr_wrapper) + +SECTION_FUNC(vectors, __start) + .option norvc; + + /* + * Set mtvec (Machine Trap-Vector Base-Address Register) + * to __isr_wrapper. + */ + la t0, _isr_wrapper + csrw mtvec, t0 + + /* Jump to __initialize */ + tail __initialize