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.
This commit is contained in:
parent
b8f273c9b6
commit
d75c373da7
9
zephyr/west.yml
Normal file
9
zephyr/west.yml
Normal file
@ -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
|
4
zephyr/zephyr/CMakeLists.txt
Normal file
4
zephyr/zephyr/CMakeLists.txt
Normal file
@ -0,0 +1,4 @@
|
||||
# Copyright (c) 2020 Olof Kindgren <olof.kindgren@gmail.com>
|
||||
# SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
add_subdirectory(drivers)
|
8
zephyr/zephyr/Kconfig
Normal file
8
zephyr/zephyr/Kconfig
Normal file
@ -0,0 +1,8 @@
|
||||
# Copyright (c) 2020 Olof Kindgren <olof.kindgren@gmail.com>
|
||||
# SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
menu "SweRVolf"
|
||||
|
||||
rsource "drivers/Kconfig"
|
||||
|
||||
endmenu
|
8
zephyr/zephyr/boards/riscv/trashernet_soc/Kconfig.board
Normal file
8
zephyr/zephyr/boards/riscv/trashernet_soc/Kconfig.board
Normal file
@ -0,0 +1,8 @@
|
||||
# Copyright (c) 2020 Olof Kindgren <olof.kindgren@gmail.com>
|
||||
# Copyright (c) 2024 Markus Koch <markus@notsyncing.net>
|
||||
#
|
||||
# SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
config BOARD_TRASHERNET_SOC
|
||||
bool "Trashernet SoC"
|
||||
depends on SOC_RISCV32_SERVANT
|
13
zephyr/zephyr/boards/riscv/trashernet_soc/Kconfig.defconfig
Normal file
13
zephyr/zephyr/boards/riscv/trashernet_soc/Kconfig.defconfig
Normal file
@ -0,0 +1,13 @@
|
||||
# Copyright (c) 2020 Olof Kindgren <olof.kindgren@gmail.com>
|
||||
# Copyright (c) 2024 Markus Koch <markus@notsyncing.net>
|
||||
#
|
||||
# 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
|
17
zephyr/zephyr/boards/riscv/trashernet_soc/trashernet.yaml
Normal file
17
zephyr/zephyr/boards/riscv/trashernet_soc/trashernet.yaml
Normal file
@ -0,0 +1,17 @@
|
||||
# Copyright (c) 2020 Olof Kindgren <olof.kindgren@gmail.com>
|
||||
# Copyright (c) 2024 Markus Koch <markus@notsyncing.net>
|
||||
#
|
||||
# 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
|
40
zephyr/zephyr/boards/riscv/trashernet_soc/trashernet_soc.dts
Normal file
40
zephyr/zephyr/boards/riscv/trashernet_soc/trashernet_soc.dts
Normal file
@ -0,0 +1,40 @@
|
||||
/*
|
||||
* Copyright (c) 2020 Olof Kindgren <olof.kindgren@gmail.com>
|
||||
* Copyright (c) 2024 Markus Koch <markus@notsyncing.net>
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
/dts-v1/;
|
||||
|
||||
#include <serv.dtsi>
|
||||
|
||||
/ {
|
||||
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];
|
||||
};
|
||||
};
|
||||
};
|
||||
|
@ -0,0 +1,13 @@
|
||||
# Copyright (c) 2020 Olof Kindgren <olof.kindgren@gmail.com>
|
||||
# Copyright (c) 2024 Markus Koch <markus@notsyncing.net>
|
||||
#
|
||||
# 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
|
7
zephyr/zephyr/drivers/CMakeLists.txt
Normal file
7
zephyr/zephyr/drivers/CMakeLists.txt
Normal file
@ -0,0 +1,7 @@
|
||||
# Copyright (c) 2020 Olof Kindgren <olof.kindgren@gmail.com>
|
||||
# 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)
|
||||
|
12
zephyr/zephyr/drivers/Kconfig
Normal file
12
zephyr/zephyr/drivers/Kconfig
Normal file
@ -0,0 +1,12 @@
|
||||
# Copyright (c) 2020 Olof Kindgren <olof.kindgren@gmail.com>
|
||||
# SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
menu "Device Drivers"
|
||||
|
||||
rsource "serial/Kconfig"
|
||||
|
||||
rsource "timer/Kconfig"
|
||||
|
||||
rsource "trashernet/Kconfig"
|
||||
|
||||
endmenu
|
7
zephyr/zephyr/drivers/serial/CMakeLists.txt
Normal file
7
zephyr/zephyr/drivers/serial/CMakeLists.txt
Normal file
@ -0,0 +1,7 @@
|
||||
# Copyright (c) 2020 Olof Kindgren <olof.kindgren@gmail.com>
|
||||
# Copyright (c) 2024 Markus Koch <markus@notsyncing.net>
|
||||
# SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
set(ZEPHYR_CURRENT_LIBRARY drivers__serial)
|
||||
|
||||
zephyr_library_sources_ifdef(CONFIG_UART_TRASHERNET uart_trashernet.c)
|
13
zephyr/zephyr/drivers/serial/Kconfig
Normal file
13
zephyr/zephyr/drivers/serial/Kconfig
Normal file
@ -0,0 +1,13 @@
|
||||
# Copyright (c) 2020 Olof Kindgren <olof.kindgren@gmail.com>
|
||||
# Copyright (c) 2024 Markus Koch <markus@notsyncing.net>
|
||||
# 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
|
79
zephyr/zephyr/drivers/serial/uart_trashernet.c
Normal file
79
zephyr/zephyr/drivers/serial/uart_trashernet.c
Normal file
@ -0,0 +1,79 @@
|
||||
/*
|
||||
* Copyright (c) 2020 Olof Kindgren <olof.kindgren@gmail.com>
|
||||
* Copyright (c) 2024 Markus Koch <markus@notsyncing.net>
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#include <zephyr/kernel.h>
|
||||
#include <zephyr/arch/cpu.h>
|
||||
#include <zephyr/device.h>
|
||||
#include <zephyr/drivers/uart.h>
|
||||
#include <inttypes.h>
|
||||
|
||||
#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)
|
5
zephyr/zephyr/drivers/timer/CMakeLists.txt
Normal file
5
zephyr/zephyr/drivers/timer/CMakeLists.txt
Normal file
@ -0,0 +1,5 @@
|
||||
# Copyright (c) 2020 Olof Kindgren <olof.kindgren@gmail.com>
|
||||
# SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
zephyr_library_sources_ifdef(CONFIG_SERV_TIMER serv_timer.c)
|
||||
|
9
zephyr/zephyr/drivers/timer/Kconfig
Normal file
9
zephyr/zephyr/drivers/timer/Kconfig
Normal file
@ -0,0 +1,9 @@
|
||||
# Copyright (c) 2020 Olof Kindgren <olof.kindgren@gmail.com>
|
||||
# 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.
|
142
zephyr/zephyr/drivers/timer/serv_timer.c
Normal file
142
zephyr/zephyr/drivers/timer/serv_timer.c
Normal file
@ -0,0 +1,142 @@
|
||||
/*
|
||||
* Copyright (c) 2020 Olof Kindgren <olof.kindgren@gmail.com>
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
/*
|
||||
This is basically a 32-bit version of riscv_machine_timer.c for Zephyr
|
||||
*/
|
||||
#include <zephyr/drivers/timer/system_timer.h>
|
||||
#include <zephyr/sys_clock.h>
|
||||
#include <zephyr/spinlock.h>
|
||||
#include <zephyr/device.h>
|
||||
#include <soc.h>
|
||||
|
||||
#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);
|
5
zephyr/zephyr/drivers/trashernet/CMakeLists.txt
Normal file
5
zephyr/zephyr/drivers/trashernet/CMakeLists.txt
Normal file
@ -0,0 +1,5 @@
|
||||
# Copyright (c) 2024 Markus Koch <markus@notsyncing.net>
|
||||
# SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
zephyr_library_sources_ifdef(CONFIG_ETH_TRASHERNET trashernet.c)
|
||||
|
10
zephyr/zephyr/drivers/trashernet/Kconfig
Normal file
10
zephyr/zephyr/drivers/trashernet/Kconfig
Normal file
@ -0,0 +1,10 @@
|
||||
# Copyright (c) 2024 Markus Koch <markus@notsyncing.net>
|
||||
# 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.
|
253
zephyr/zephyr/drivers/trashernet/trashernet.c
Normal file
253
zephyr/zephyr/drivers/trashernet/trashernet.c
Normal file
@ -0,0 +1,253 @@
|
||||
/* TRASHERNET Stand-alone Ethernet Controller with SPI
|
||||
*
|
||||
* Copyright (c) 2016 Markus Koch <markus@notsyncing.net>
|
||||
*
|
||||
* 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 <zephyr/logging/log.h>
|
||||
LOG_MODULE_REGISTER(LOG_MODULE_NAME);
|
||||
|
||||
#include <zephyr/kernel.h>
|
||||
#include <zephyr/device.h>
|
||||
#include <string.h>
|
||||
#include <errno.h>
|
||||
#include <zephyr/drivers/gpio.h>
|
||||
#include <zephyr/drivers/spi.h>
|
||||
#include <zephyr/net/net_pkt.h>
|
||||
#include <zephyr/net/net_if.h>
|
||||
#include <zephyr/net/ethernet.h>
|
||||
|
||||
#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);
|
@ -0,0 +1,14 @@
|
||||
# Copyright (c) 2024 Markus Koch <markus@notsyncing.net>
|
||||
# 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.
|
24
zephyr/zephyr/dts/riscv/serv.dtsi
Normal file
24
zephyr/zephyr/dts/riscv/serv.dtsi
Normal file
@ -0,0 +1,24 @@
|
||||
/*
|
||||
* Copyright (c) 2020 Olof Kindgren <olof.kindgren@gmail.com>
|
||||
* Copyright (c) 2024 Markus Koch <markus@notsyncing.net>
|
||||
*
|
||||
* 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";
|
||||
};
|
||||
};
|
||||
};
|
5
zephyr/zephyr/module.yml
Normal file
5
zephyr/zephyr/module.yml
Normal file
@ -0,0 +1,5 @@
|
||||
build:
|
||||
settings:
|
||||
board_root: zephyr
|
||||
dts_root: zephyr
|
||||
soc_root: zephyr
|
8
zephyr/zephyr/soc/riscv/servant/CMakeLists.txt
Normal file
8
zephyr/zephyr/soc/riscv/servant/CMakeLists.txt
Normal file
@ -0,0 +1,8 @@
|
||||
# Copyright (c) 2020 Olof Kindgren <olof.kindgren@gmail.com>
|
||||
# SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
zephyr_sources(
|
||||
soc_irq.S
|
||||
vector.S
|
||||
irq.c
|
||||
cpu_idle.c)
|
26
zephyr/zephyr/soc/riscv/servant/Kconfig.defconfig
Normal file
26
zephyr/zephyr/soc/riscv/servant/Kconfig.defconfig
Normal file
@ -0,0 +1,26 @@
|
||||
# Copyright (c) 2020 Olof Kindgren <olof.kindgren@gmail.com>
|
||||
# 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
|
8
zephyr/zephyr/soc/riscv/servant/Kconfig.soc
Normal file
8
zephyr/zephyr/soc/riscv/servant/Kconfig.soc
Normal file
@ -0,0 +1,8 @@
|
||||
# Copyright (c) 2020 Olof Kindgren <olof.kindgren@gmail.com>
|
||||
# SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
config SOC_RISCV32_SERVANT
|
||||
bool "servant SoC"
|
||||
select RISCV
|
||||
select ATOMIC_OPERATIONS_C
|
||||
select RISCV_ISA_EXT_ZICSR
|
22
zephyr/zephyr/soc/riscv/servant/cpu_idle.c
Normal file
22
zephyr/zephyr/soc/riscv/servant/cpu_idle.c
Normal file
@ -0,0 +1,22 @@
|
||||
#include <zephyr/irq.h>
|
||||
#include <zephyr/tracing/tracing.h>
|
||||
|
||||
// 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);
|
||||
}
|
||||
|
58
zephyr/zephyr/soc/riscv/servant/irq.c
Normal file
58
zephyr/zephyr/soc/riscv/servant/irq.c
Normal file
@ -0,0 +1,58 @@
|
||||
/*
|
||||
* Copyright (c) 2017 Jean-Paul Etienne <fractalclone@gmail.com>
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
/**
|
||||
* @file
|
||||
* @brief interrupt management code for riscv SOCs supporting the riscv
|
||||
privileged architecture specification
|
||||
*/
|
||||
#include <zephyr/irq.h>
|
||||
|
||||
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
|
7
zephyr/zephyr/soc/riscv/servant/linker.ld
Normal file
7
zephyr/zephyr/soc/riscv/servant/linker.ld
Normal file
@ -0,0 +1,7 @@
|
||||
/*
|
||||
* Copyright (c) 2018 Antmicro <www.antmicro.com>
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#include <zephyr/arch/riscv/common/linker.ld>
|
16
zephyr/zephyr/soc/riscv/servant/soc.h
Normal file
16
zephyr/zephyr/soc/riscv/servant/soc.h
Normal file
@ -0,0 +1,16 @@
|
||||
/*
|
||||
* Copyright (c) 2020 Olof Kindgren <olof.kindgren@gmail.com>
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#ifndef __RISCV32_SERVANT_SOC_H_
|
||||
#define __RISCV32_SERVANT_SOC_H_
|
||||
|
||||
#include <soc_common.h>
|
||||
|
||||
/* Timer configuration */
|
||||
#define SERV_TIMER_BASE 0x80000000
|
||||
#define SERV_TIMER_IRQ 7
|
||||
|
||||
#endif /* __RISCV32_SERVANT_SOC_H_ */
|
56
zephyr/zephyr/soc/riscv/servant/soc_common.h
Normal file
56
zephyr/zephyr/soc/riscv/servant/soc_common.h
Normal file
@ -0,0 +1,56 @@
|
||||
/*
|
||||
* Copyright (c) 2017 Jean-Paul Etienne <fractalclone@gmail.com>
|
||||
*
|
||||
* 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_ */
|
56
zephyr/zephyr/soc/riscv/servant/soc_irq.S
Normal file
56
zephyr/zephyr/soc/riscv/servant/soc_irq.S
Normal file
@ -0,0 +1,56 @@
|
||||
/*
|
||||
* Copyright (c) 2017 Jean-Paul Etienne <fractalclone@gmail.com>
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
/*
|
||||
* common interrupt management code for riscv SOCs supporting the riscv
|
||||
* privileged architecture specification
|
||||
*/
|
||||
#include <offsets.h>
|
||||
#include <zephyr/linker/sections.h>
|
||||
#include <soc.h>
|
||||
|
||||
/* 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
|
28
zephyr/zephyr/soc/riscv/servant/vector.S
Normal file
28
zephyr/zephyr/soc/riscv/servant/vector.S
Normal file
@ -0,0 +1,28 @@
|
||||
/*
|
||||
* Copyright (c) 2017 Jean-Paul Etienne <fractalclone@gmail.com>
|
||||
* Contributors: 2018 Antmicro <www.antmicro.com>
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#include <zephyr/toolchain.h>
|
||||
|
||||
/* 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
|
Loading…
Reference in New Issue
Block a user