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