diff --git a/src/port/stm32h563/Makefile b/src/port/stm32h563/Makefile new file mode 100644 index 0000000..026557d --- /dev/null +++ b/src/port/stm32h563/Makefile @@ -0,0 +1,28 @@ +CC=arm-none-eabi-gcc +OBJCOPY ?= arm-none-eabi-objcopy + +ROOT := ../../.. + +CFLAGS := -mcpu=cortex-m33 -mthumb -mcmse -Os -ffreestanding -fdata-sections -ffunction-sections +CFLAGS += -g -ggdb -Wall -Wextra -Werror -Wdeclaration-after-statement +CFLAGS += -I. -I$(ROOT) -I$(ROOT)/src +LDFLAGS := -nostdlib -T target.ld -Wl,-gc-sections + +SRCS := startup.c ivt.c syscalls.c main.c stm32h5_eth.c $(ROOT)/src/wolfip.c +OBJS := $(patsubst %.c,%.o,$(SRCS)) + +all: app.bin + +app.elf: $(OBJS) target.ld + $(CC) $(CFLAGS) $(OBJS) $(LDFLAGS) -Wl,--start-group -lc -lm -lgcc -lnosys -Wl,--end-group -o $@ + +app.bin: app.elf + $(OBJCOPY) -O binary $< $@ + +%.o: %.c + $(CC) $(CFLAGS) -c $< -o $@ + +clean: + rm -f $(OBJS) app.elf app.bin + +.PHONY: all clean diff --git a/src/port/stm32h563/config.h b/src/port/stm32h563/config.h new file mode 100644 index 0000000..eebf072 --- /dev/null +++ b/src/port/stm32h563/config.h @@ -0,0 +1,56 @@ +/* config.h + * + * Copyright (C) 2026 wolfSSL Inc. + * + * This file is part of wolfIP TCP/IP stack. + * + * wolfIP is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * wolfIP is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335, USA + */ +#ifndef WOLF_CONFIG_H +#define WOLF_CONFIG_H + +#ifndef CONFIG_IPFILTER +#define CONFIG_IPFILTER 0 +#endif + +#define ETHERNET +#define LINK_MTU 1536 + +#define MAX_TCPSOCKETS 4 +#define MAX_UDPSOCKETS 2 +#define MAX_ICMPSOCKETS 2 +#define RXBUF_SIZE (LINK_MTU * 16) +#define TXBUF_SIZE (LINK_MTU * 16) + +#define MAX_NEIGHBORS 16 + +#ifndef WOLFIP_MAX_INTERFACES +#define WOLFIP_MAX_INTERFACES 1 +#endif + +#ifndef WOLFIP_ENABLE_FORWARDING +#define WOLFIP_ENABLE_FORWARDING 0 +#endif + +#ifndef WOLFIP_ENABLE_LOOPBACK +#define WOLFIP_ENABLE_LOOPBACK 0 +#endif + +#define WOLFIP_IP "192.168.12.11" +#define WOLFIP_NETMASK "255.255.255.0" +#define WOLFIP_GW "192.168.12.1" +#define WOLFIP_STATIC_DNS_IP "9.9.9.9" + +#endif diff --git a/src/port/stm32h563/ivt.c b/src/port/stm32h563/ivt.c new file mode 100644 index 0000000..2ae1689 --- /dev/null +++ b/src/port/stm32h563/ivt.c @@ -0,0 +1,57 @@ +/* ivt.c + * + * Copyright (C) 2026 wolfSSL Inc. + * + * This file is part of wolfIP TCP/IP stack. + * + * wolfIP is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * wolfIP is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335, USA + */ +#include + +extern void Reset_Handler(void); +extern unsigned long _estack; + +static void default_handler(void) +{ + while (1) { } +} + +void NMI_Handler(void) __attribute__((weak, alias("default_handler"))); +void HardFault_Handler(void) __attribute__((weak, alias("default_handler"))); +void MemManage_Handler(void) __attribute__((weak, alias("default_handler"))); +void BusFault_Handler(void) __attribute__((weak, alias("default_handler"))); +void UsageFault_Handler(void)__attribute__((weak, alias("default_handler"))); +void SVC_Handler(void) __attribute__((weak, alias("default_handler"))); +void DebugMon_Handler(void) __attribute__((weak, alias("default_handler"))); +void PendSV_Handler(void) __attribute__((weak, alias("default_handler"))); +void SysTick_Handler(void) __attribute__((weak, alias("default_handler"))); + +__attribute__((section(".isr_vector"))) +const uint32_t vector_table[16 + 96] = { + [0] = (uint32_t)&_estack, + [1] = (uint32_t)&Reset_Handler, + [2] = (uint32_t)&NMI_Handler, + [3] = (uint32_t)&HardFault_Handler, + [4] = (uint32_t)&MemManage_Handler, + [5] = (uint32_t)&BusFault_Handler, + [6] = (uint32_t)&UsageFault_Handler, + [7] = 0, [8] = 0, [9] = 0, [10] = 0, + [11] = (uint32_t)&SVC_Handler, + [12] = (uint32_t)&DebugMon_Handler, + [13] = 0, + [14] = (uint32_t)&PendSV_Handler, + [15] = (uint32_t)&SysTick_Handler, + [16 ... 111] = (uint32_t)&default_handler +}; diff --git a/src/port/stm32h563/main.c b/src/port/stm32h563/main.c new file mode 100644 index 0000000..f121dd0 --- /dev/null +++ b/src/port/stm32h563/main.c @@ -0,0 +1,106 @@ +/* main.c + * + * Copyright (C) 2026 wolfSSL Inc. + * + * This file is part of wolfIP TCP/IP stack. + * + * wolfIP is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * wolfIP is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335, USA + */ +#include +#include +#include "config.h" +#include "wolfip.h" +#include "stm32h5_eth.h" + +#define ECHO_PORT 7 +#define RX_BUF_SIZE 1024 + +#define RCC_BASE 0x44020C00u +#define RCC_AHB1ENR (*(volatile uint32_t *)(RCC_BASE + 0x88u)) + +static struct wolfIP *IPStack; +static int listen_fd = -1; +static int client_fd = -1; +static uint8_t rx_buf[RX_BUF_SIZE]; + +uint32_t wolfIP_getrandom(void) +{ + static uint32_t lfsr = 0x1A2B3C4DU; + lfsr ^= lfsr << 13; + lfsr ^= lfsr >> 17; + lfsr ^= lfsr << 5; + return lfsr; +} + +static void echo_cb(int fd, uint16_t event, void *arg) +{ + struct wolfIP *s = (struct wolfIP *)arg; + int ret; + + if ((fd == listen_fd) && (event & CB_EVENT_READABLE) && (client_fd == -1)) { + client_fd = wolfIP_sock_accept(s, listen_fd, NULL, NULL); + if (client_fd > 0) { + wolfIP_register_callback(s, client_fd, echo_cb, s); + } + return; + } + + if ((fd == client_fd) && (event & CB_EVENT_READABLE)) { + ret = wolfIP_sock_recvfrom(s, client_fd, rx_buf, sizeof(rx_buf), 0, NULL, NULL); + if (ret > 0) { + (void)wolfIP_sock_sendto(s, client_fd, rx_buf, (uint32_t)ret, 0, NULL, 0); + } else if (ret == 0) { + wolfIP_sock_close(s, client_fd); + client_fd = -1; + } + } + + if ((fd == client_fd) && (event & CB_EVENT_CLOSED)) { + wolfIP_sock_close(s, client_fd); + client_fd = -1; + } +} + +int main(void) +{ + struct wolfIP_ll_dev *ll; + struct wolfIP_sockaddr_in addr; + uint64_t tick = 0; + + wolfIP_init_static(&IPStack); + RCC_AHB1ENR |= (1u << 19) | (1u << 20) | (1u << 21); + ll = wolfIP_getdev(IPStack); + (void)stm32h5_eth_init(ll, NULL); + + wolfIP_ipconfig_set(IPStack, + atoip4(WOLFIP_IP), + atoip4(WOLFIP_NETMASK), + atoip4(WOLFIP_GW)); + + listen_fd = wolfIP_sock_socket(IPStack, AF_INET, IPSTACK_SOCK_STREAM, 0); + wolfIP_register_callback(IPStack, listen_fd, echo_cb, IPStack); + + memset(&addr, 0, sizeof(addr)); + addr.sin_family = AF_INET; + addr.sin_port = ee16(ECHO_PORT); + addr.sin_addr.s_addr = 0; + (void)wolfIP_sock_bind(IPStack, listen_fd, (struct wolfIP_sockaddr *)&addr, sizeof(addr)); + (void)wolfIP_sock_listen(IPStack, listen_fd, 1); + + for (;;) { + (void)wolfIP_poll(IPStack, tick++); + } + return 0; +} diff --git a/src/port/stm32h563/startup.c b/src/port/stm32h563/startup.c new file mode 100644 index 0000000..53cecea --- /dev/null +++ b/src/port/stm32h563/startup.c @@ -0,0 +1,47 @@ +/* startup.c + * + * Copyright (C) 2026 wolfSSL Inc. + * + * This file is part of wolfIP TCP/IP stack. + * + * wolfIP is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * wolfIP is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335, USA + */ +#include + +extern uint32_t _sidata; +extern uint32_t _sdata; +extern uint32_t _edata; +extern uint32_t _sbss; +extern uint32_t _ebss; +extern void __libc_init_array(void); + +int main(void); + +void Reset_Handler(void) +{ + uint32_t *src; + uint32_t *dst; + + src = &_sidata; + for (dst = &_sdata; dst < &_edata; ) { + *dst++ = *src++; + } + for (dst = &_sbss; dst < &_ebss; ) { + *dst++ = 0u; + } + __libc_init_array(); + (void)main(); + while (1) { } +} diff --git a/src/port/stm32h563/stm32h5_eth.c b/src/port/stm32h563/stm32h5_eth.c new file mode 100644 index 0000000..4530338 --- /dev/null +++ b/src/port/stm32h563/stm32h5_eth.c @@ -0,0 +1,443 @@ +/* stm32h5_eth.c + * + * Copyright (C) 2026 wolfSSL Inc. + * + * This file is part of wolfIP TCP/IP stack. + * + * wolfIP is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * wolfIP is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335, USA + */ +#include +#include +#include "config.h" +#include "stm32h5_eth.h" + +#define ETH_BASE 0x40028000UL +#define ETH_REG(offset) (*(volatile uint32_t *)(ETH_BASE + (offset))) +#define ETH_TPDR ETH_REG(0x1180U) + +/* MAC registers */ +#define ETH_MACCR ETH_REG(0x0000U) +#define ETH_MACPFR ETH_REG(0x0004U) +#define ETH_MACA0HR ETH_REG(0x0300U) +#define ETH_MACA0LR ETH_REG(0x0304U) + +/* MTL registers */ +#define ETH_MTLTXQOMR ETH_REG(0x0D00U) +#define ETH_MTLRXQOMR ETH_REG(0x0D30U) + +/* DMA registers */ +#define ETH_DMAMR ETH_REG(0x1000U) +#define ETH_DMASBMR ETH_REG(0x1004U) +#define ETH_DMACTXCR ETH_REG(0x1104U) +#define ETH_DMACRXCR ETH_REG(0x1108U) +#define ETH_DMACTXDLAR ETH_REG(0x1114U) +#define ETH_DMACRXDLAR ETH_REG(0x111CU) +#define ETH_DMACTXDTPR ETH_REG(0x1120U) +#define ETH_DMACRXDTPR ETH_REG(0x1128U) +#define ETH_DMACTXRLR ETH_REG(0x112CU) +#define ETH_DMACRXRLR ETH_REG(0x1130U) +#define ETH_DMACSR ETH_REG(0x1160U) +#define ETH_MACMDIOAR ETH_REG(0x0200U) +#define ETH_MACMDIODR ETH_REG(0x0204U) + +/* MAC control bits */ +#define ETH_MACCR_RE (1U << 0) +#define ETH_MACCR_TE (1U << 1) +#define ETH_MACCR_DM (1U << 13) +#define ETH_MACCR_FES (1U << 14) + +/* DMA bits */ +#define ETH_DMAMR_SWR (1U << 0) +#define ETH_DMASBMR_FB (1U << 0) +#define ETH_DMASBMR_AAL (1U << 12) + +#define ETH_DMACTXCR_ST (1U << 0) +#define ETH_DMACTXCR_OSF (1U << 4) +#define ETH_DMACRXCR_SR (1U << 0) +#define ETH_DMACRXCR_RBSZ_SHIFT 1 +#define ETH_DMACSR_TBU (1U << 2) +#define ETH_DMACTXCR_TPBL_SHIFT 16 +#define ETH_DMACTXCR_TPBL(val) (((uint32_t)(val) & 0x3FU) << ETH_DMACTXCR_TPBL_SHIFT) +#define ETH_DMACRXCR_RPBL_SHIFT 16 +#define ETH_DMACRXCR_RPBL(val) (((uint32_t)(val) & 0x3FU) << ETH_DMACRXCR_RPBL_SHIFT) + +/* MTL bits */ +#define ETH_MTLTXQOMR_FTQ (1U << 0) +#define ETH_MTLTXQOMR_TSF (1U << 1) +#define ETH_MTLTXQOMR_TXQEN_SHIFT 2 +#define ETH_MTLTXQOMR_TXQEN_ENABLE (2U << ETH_MTLTXQOMR_TXQEN_SHIFT) +#define ETH_MTLTXQOMR_MASK 0x00000072U +#define ETH_MTLRXQOMR_RSF (1U << 5) +#define ETH_MTLRXQOMR_MASK 0x0000007BU + +#define ETH_MACMDIOAR_MB (1U << 0) +#define ETH_MACMDIOAR_GOC_SHIFT 2 +#define ETH_MACMDIOAR_GOC_WRITE 0x1U +#define ETH_MACMDIOAR_GOC_READ 0x3U +#define ETH_MACMDIOAR_CR_SHIFT 8 +#define ETH_MACMDIOAR_RDA_SHIFT 16 +#define ETH_MACMDIOAR_PA_SHIFT 21 + +#define PHY_REG_BCR 0x00U +#define PHY_REG_BSR 0x01U +#define PHY_REG_ID1 0x02U +#define PHY_REG_ANAR 0x04U +#define PHY_REG_SCSR 0x1FU + +#define PHY_BCR_RESET (1U << 15) +#define PHY_BCR_SPEED_100 (1U << 13) +#define PHY_BCR_AUTONEG_ENABLE (1U << 12) +#define PHY_BCR_POWER_DOWN (1U << 11) +#define PHY_BCR_ISOLATE (1U << 10) +#define PHY_BCR_RESTART_AUTONEG (1U << 9) +#define PHY_BCR_FULL_DUPLEX (1U << 8) + +#define PHY_BSR_LINK_STATUS (1U << 2) +#define PHY_BSR_AUTONEG_COMPLETE (1U << 5) +#define PHY_BSR_10_HALF (1U << 11) +#define PHY_BSR_10_FULL (1U << 12) +#define PHY_BSR_100_HALF (1U << 13) +#define PHY_BSR_100_FULL (1U << 14) + +#define PHY_ANAR_DEFAULT 0x01E1U + +struct eth_desc { + volatile uint32_t des0; + volatile uint32_t des1; + volatile uint32_t des2; + volatile uint32_t des3; +}; + +#define ETH_TDES3_OWN (1U << 31) +#define ETH_TDES3_FD (1U << 29) +#define ETH_TDES3_LD (1U << 28) +#define ETH_TDES2_B1L_MASK (0x3FFFU) +#define ETH_TDES3_FL_MASK (0x7FFFU) + +#define ETH_RDES3_OWN (1U << 31) +#define ETH_RDES3_BUF1V (1U << 24) +#define ETH_RDES3_FS (1U << 29) +#define ETH_RDES3_LS (1U << 28) +#define ETH_RDES3_PL_MASK (0x3FFFU) + +#define RX_DESC_COUNT 4U +#define TX_DESC_COUNT 3U +#define RX_BUF_SIZE LINK_MTU +#define TX_BUF_SIZE LINK_MTU +#define FRAME_MIN_LEN 60U +#define DMA_TPBL 32U +#define DMA_RPBL 32U + +static struct eth_desc rx_ring[RX_DESC_COUNT] __attribute__((aligned(32))); +static struct eth_desc tx_ring[TX_DESC_COUNT] __attribute__((aligned(32))); +static uint8_t rx_buffers[RX_DESC_COUNT][RX_BUF_SIZE] __attribute__((aligned(32))); +static uint8_t tx_buffers[TX_DESC_COUNT][TX_BUF_SIZE] __attribute__((aligned(32))); +static uint8_t rx_staging_buffer[RX_BUF_SIZE] __attribute__((aligned(32))); + +static uint32_t rx_idx; +static uint32_t tx_idx; +static int32_t phy_addr = -1; + +static void eth_hw_reset(void) +{ + ETH_DMAMR |= ETH_DMAMR_SWR; + while (ETH_DMAMR & ETH_DMAMR_SWR) { + } +} + +static void eth_trigger_tx(void) +{ + ETH_TPDR = 0U; + __asm volatile ("dsb sy" ::: "memory"); +} + +static uint16_t eth_mdio_read(uint32_t phy, uint32_t reg); +static void eth_mdio_write(uint32_t phy, uint32_t reg, uint16_t value); + +static void eth_config_mac(const uint8_t mac[6]) +{ + uint32_t maccr = ETH_MACCR; + maccr &= ~(ETH_MACCR_DM | ETH_MACCR_FES); + maccr |= ETH_MACCR_DM | ETH_MACCR_FES; + ETH_MACCR = maccr; + ETH_MACPFR = 0U; + ETH_MACA0HR = ((uint32_t)mac[5] << 8) | (uint32_t)mac[4]; + ETH_MACA0LR = ((uint32_t)mac[3] << 24) | + ((uint32_t)mac[2] << 16) | + ((uint32_t)mac[1] << 8) | + (uint32_t)mac[0]; +} + +static void eth_config_speed_duplex(void) +{ + uint32_t maccr; + uint16_t bsr; + + if (phy_addr < 0) return; + + maccr = ETH_MACCR; + maccr &= ~(ETH_MACCR_FES | ETH_MACCR_DM); + bsr = eth_mdio_read((uint32_t)phy_addr, PHY_REG_BSR); + bsr |= eth_mdio_read((uint32_t)phy_addr, PHY_REG_BSR); + + if ((bsr & PHY_BSR_100_FULL) != 0U) { + maccr |= ETH_MACCR_FES | ETH_MACCR_DM; + } else if ((bsr & PHY_BSR_100_HALF) != 0U) { + maccr |= ETH_MACCR_FES; + } else if ((bsr & PHY_BSR_10_FULL) != 0U) { + maccr |= ETH_MACCR_DM; + } + ETH_MACCR = maccr; +} + +static void eth_config_mtl(void) +{ + uint32_t txqomr = ETH_MTLTXQOMR; + uint32_t rxqomr = ETH_MTLRXQOMR; + + txqomr &= ~ETH_MTLTXQOMR_MASK; + txqomr |= (ETH_MTLTXQOMR_TSF | ETH_MTLTXQOMR_TXQEN_ENABLE); + ETH_MTLTXQOMR = txqomr; + + rxqomr &= ~ETH_MTLRXQOMR_MASK; + rxqomr |= ETH_MTLRXQOMR_RSF; + ETH_MTLRXQOMR = rxqomr; +} + +static void eth_init_desc(void) +{ + uint32_t i; + for (i = 0; i < TX_DESC_COUNT; i++) { + tx_ring[i].des0 = (uint32_t)tx_buffers[i]; + tx_ring[i].des1 = 0; + tx_ring[i].des2 = 0; + tx_ring[i].des3 = 0; + } + for (i = 0; i < RX_DESC_COUNT; i++) { + rx_ring[i].des0 = (uint32_t)rx_buffers[i]; + rx_ring[i].des1 = 0; + rx_ring[i].des2 = 0; + rx_ring[i].des3 = (RX_BUF_SIZE & ETH_RDES3_PL_MASK) | + ETH_RDES3_OWN | + ETH_RDES3_BUF1V; + } + rx_idx = 0; + tx_idx = 0; + ETH_DMACTXDLAR = (uint32_t)&tx_ring[0]; + ETH_DMACRXDLAR = (uint32_t)&rx_ring[0]; + ETH_DMACTXRLR = TX_DESC_COUNT - 1U; + ETH_DMACRXRLR = RX_DESC_COUNT - 1U; + ETH_DMACTXDTPR = (uint32_t)&tx_ring[0]; + ETH_DMACRXDTPR = (uint32_t)&rx_ring[RX_DESC_COUNT - 1U]; +} + +static void eth_config_dma(void) +{ + ETH_DMASBMR = ETH_DMASBMR_FB | ETH_DMASBMR_AAL; + ETH_DMACRXCR = ((RX_BUF_SIZE & ETH_RDES3_PL_MASK) << ETH_DMACRXCR_RBSZ_SHIFT) | + ETH_DMACRXCR_RPBL(DMA_RPBL); + ETH_DMACTXCR = ETH_DMACTXCR_OSF | ETH_DMACTXCR_TPBL(DMA_TPBL); +} + +static void eth_start(void) +{ + ETH_MACCR |= ETH_MACCR_TE | ETH_MACCR_RE; + ETH_MTLTXQOMR |= ETH_MTLTXQOMR_FTQ; + ETH_DMACTXCR |= ETH_DMACTXCR_ST; + ETH_DMACRXCR |= ETH_DMACRXCR_SR; +} + +static void eth_stop(void) +{ + ETH_DMACTXCR &= ~ETH_DMACTXCR_ST; + ETH_DMACRXCR &= ~ETH_DMACRXCR_SR; + ETH_MACCR &= ~ETH_MACCR_RE; + ETH_MTLTXQOMR |= ETH_MTLTXQOMR_FTQ; + ETH_MACCR &= ~ETH_MACCR_TE; +} + +static void eth_mdio_wait_ready(void) +{ + uint32_t timeout = 100000U; + while ((ETH_MACMDIOAR & ETH_MACMDIOAR_MB) != 0U && timeout != 0U) { + timeout--; + } +} + +static uint16_t eth_mdio_read(uint32_t phy, uint32_t reg) +{ + uint32_t cfg; + eth_mdio_wait_ready(); + cfg = (4U << ETH_MACMDIOAR_CR_SHIFT) | + (reg << ETH_MACMDIOAR_RDA_SHIFT) | + (phy << ETH_MACMDIOAR_PA_SHIFT) | + (ETH_MACMDIOAR_GOC_READ << ETH_MACMDIOAR_GOC_SHIFT); + ETH_MACMDIOAR = cfg | ETH_MACMDIOAR_MB; + eth_mdio_wait_ready(); + return (uint16_t)(ETH_MACMDIODR & 0xFFFFU); +} + +static void eth_mdio_write(uint32_t phy, uint32_t reg, uint16_t value) +{ + uint32_t cfg; + eth_mdio_wait_ready(); + ETH_MACMDIODR = (uint32_t)value; + cfg = (4U << ETH_MACMDIOAR_CR_SHIFT) | + (reg << ETH_MACMDIOAR_RDA_SHIFT) | + (phy << ETH_MACMDIOAR_PA_SHIFT) | + (ETH_MACMDIOAR_GOC_WRITE << ETH_MACMDIOAR_GOC_SHIFT); + ETH_MACMDIOAR = cfg | ETH_MACMDIOAR_MB; + eth_mdio_wait_ready(); +} + +static int32_t eth_detect_phy(void) +{ + uint32_t addr; + for (addr = 0U; addr < 32U; addr++) { + uint16_t id1 = eth_mdio_read(addr, PHY_REG_ID1); + if (id1 != 0xFFFFU && id1 != 0x0000U) { + return (int32_t)addr; + } + } + return -1; +} + +static void eth_phy_init(void) +{ + uint32_t timeout; + uint16_t ctrl; + uint16_t bsr; + + if (phy_addr < 0) { + phy_addr = eth_detect_phy(); + if (phy_addr < 0) phy_addr = 0; + } + + eth_mdio_write((uint32_t)phy_addr, PHY_REG_BCR, PHY_BCR_RESET); + timeout = 100000U; + do { + ctrl = eth_mdio_read((uint32_t)phy_addr, PHY_REG_BCR); + } while ((ctrl & PHY_BCR_RESET) != 0U && --timeout != 0U); + + ctrl &= ~(PHY_BCR_POWER_DOWN | PHY_BCR_ISOLATE | PHY_BCR_SPEED_100 | PHY_BCR_FULL_DUPLEX); + eth_mdio_write((uint32_t)phy_addr, PHY_REG_ANAR, PHY_ANAR_DEFAULT); + ctrl |= PHY_BCR_AUTONEG_ENABLE | PHY_BCR_RESTART_AUTONEG; + eth_mdio_write((uint32_t)phy_addr, PHY_REG_BCR, ctrl); + + timeout = 100000U; + do { + bsr = eth_mdio_read((uint32_t)phy_addr, PHY_REG_BSR); + bsr |= eth_mdio_read((uint32_t)phy_addr, PHY_REG_BSR); + } while ((bsr & PHY_BSR_AUTONEG_COMPLETE) == 0U && --timeout != 0U); + + timeout = 100000U; + do { + bsr = eth_mdio_read((uint32_t)phy_addr, PHY_REG_BSR); + bsr |= eth_mdio_read((uint32_t)phy_addr, PHY_REG_BSR); + } while ((bsr & PHY_BSR_LINK_STATUS) == 0U && --timeout != 0U); +} + +static int eth_poll(struct wolfIP_ll_dev *dev, void *frame, uint32_t len) +{ + struct eth_desc *desc; + uint32_t status; + uint32_t frame_len = 0; + + (void)dev; + desc = &rx_ring[rx_idx]; + if (desc->des3 & ETH_RDES3_OWN) return 0; + status = desc->des3; + if ((status & (ETH_RDES3_FS | ETH_RDES3_LS)) == + (ETH_RDES3_FS | ETH_RDES3_LS)) { + frame_len = status & ETH_RDES3_PL_MASK; + if (frame_len > len) frame_len = len; + memcpy(rx_staging_buffer, rx_buffers[rx_idx], frame_len); + memcpy(frame, rx_staging_buffer, frame_len); + } + desc->des1 = 0; + desc->des3 = (RX_BUF_SIZE & ETH_RDES3_PL_MASK) | + ETH_RDES3_OWN | + ETH_RDES3_BUF1V; + __asm volatile ("dsb sy" ::: "memory"); + ETH_DMACRXDTPR = (uint32_t)desc; + rx_idx = (rx_idx + 1U) % RX_DESC_COUNT; + return (int)frame_len; +} + +static int eth_send(struct wolfIP_ll_dev *dev, void *frame, uint32_t len) +{ + struct eth_desc *desc; + uint32_t dma_len; + uint32_t next_idx; + + (void)dev; + if (len == 0 || len > TX_BUF_SIZE) return -1; + desc = &tx_ring[tx_idx]; + if (desc->des3 & ETH_TDES3_OWN) return -2; + memcpy(tx_buffers[tx_idx], frame, len); + dma_len = (len < FRAME_MIN_LEN) ? FRAME_MIN_LEN : len; + if (dma_len > len) memset(tx_buffers[tx_idx] + len, 0, dma_len - len); + desc->des0 = (uint32_t)tx_buffers[tx_idx]; + desc->des1 = 0; + desc->des2 = (dma_len & ETH_TDES2_B1L_MASK); + __asm volatile ("dsb sy" ::: "memory"); + desc->des3 = (dma_len & ETH_TDES3_FL_MASK) | + ETH_TDES3_FD | + ETH_TDES3_LD | + ETH_TDES3_OWN; + __asm volatile ("dsb sy" ::: "memory"); + ETH_DMACSR = ETH_DMACSR_TBU; + if (tx_idx == 0U) eth_trigger_tx(); + next_idx = (tx_idx + 1U) % TX_DESC_COUNT; + ETH_DMACTXDTPR = (uint32_t)&tx_ring[next_idx]; + tx_idx = next_idx; + return (int)len; +} + +static void stm32h5_eth_generate_mac(uint8_t mac[6]) +{ + mac[0] = 0x02; + mac[1] = 0x11; + mac[2] = 0xAA; + mac[3] = 0xBB; + mac[4] = 0x22; + mac[5] = 0x33; +} + +int stm32h5_eth_init(struct wolfIP_ll_dev *ll, const uint8_t *mac) +{ + uint8_t local_mac[6]; + if (ll == NULL) return -1; + if (mac == NULL) { + stm32h5_eth_generate_mac(local_mac); + mac = local_mac; + } + memcpy(ll->mac, mac, 6); + strncpy(ll->ifname, "eth0", sizeof(ll->ifname) - 1); + ll->ifname[sizeof(ll->ifname) - 1] = '\0'; + ll->poll = eth_poll; + ll->send = eth_send; + + eth_stop(); + eth_hw_reset(); + eth_config_mac(mac); + eth_config_mtl(); + eth_init_desc(); + eth_config_dma(); + eth_phy_init(); + eth_config_speed_duplex(); + eth_start(); + return 0; +} diff --git a/src/port/stm32h563/stm32h5_eth.h b/src/port/stm32h563/stm32h5_eth.h new file mode 100644 index 0000000..0b31e11 --- /dev/null +++ b/src/port/stm32h563/stm32h5_eth.h @@ -0,0 +1,29 @@ +/* stm32h5_eth.h + * + * Copyright (C) 2026 wolfSSL Inc. + * + * This file is part of wolfIP TCP/IP stack. + * + * wolfIP is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * wolfIP is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335, USA + */ +#ifndef WOLFIP_STM32H5_ETH_H +#define WOLFIP_STM32H5_ETH_H + +#include +#include "wolfip.h" + +int stm32h5_eth_init(struct wolfIP_ll_dev *ll, const uint8_t *mac); + +#endif diff --git a/src/port/stm32h563/syscalls.c b/src/port/stm32h563/syscalls.c new file mode 100644 index 0000000..034d707 --- /dev/null +++ b/src/port/stm32h563/syscalls.c @@ -0,0 +1,141 @@ +/* syscalls.c + * + * Copyright (C) 2026 wolfSSL Inc. + * + * This file is part of wolfIP TCP/IP stack. + * + * wolfIP is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * wolfIP is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335, USA + */ +#include +#include +#include +#include +#include +#include + +extern uint32_t _ebss; +extern uint32_t _estack; + +static char *heap_end; + +int _write(int file, const char *ptr, int len) +{ + (void)file; + (void)ptr; + return len; +} + +int _close(int file) +{ + (void)file; + return -1; +} + +int _fstat(int file, struct stat *st) +{ + (void)file; + if (st == 0) { + errno = EINVAL; + return -1; + } + st->st_mode = S_IFCHR; + return 0; +} + +int _isatty(int file) +{ + (void)file; + return 1; +} + +int _lseek(int file, int ptr, int dir) +{ + (void)file; + (void)ptr; + (void)dir; + return 0; +} + +int _read(int file, char *ptr, int len) +{ + (void)file; + (void)ptr; + (void)len; + return 0; +} + +void *_sbrk(ptrdiff_t incr) +{ + char *prev; + if (heap_end == 0) { + heap_end = (char *)&_ebss; + } + prev = heap_end; + if ((heap_end + incr) >= (char *)&_estack) { + errno = ENOMEM; + return (void *)-1; + } + heap_end += incr; + return prev; +} + +int _gettimeofday(struct timeval *tv, void *tzvp) +{ + (void)tzvp; + if (tv == 0) { + errno = EINVAL; + return -1; + } + tv->tv_sec = 0; + tv->tv_usec = 0; + return 0; +} + +time_t time(time_t *t) +{ + if (t != 0) { + *t = 0; + } + return 0; +} + +void _exit(int status) +{ + (void)status; + while (1) { + __asm volatile("wfi"); + } +} + +int _kill(int pid, int sig) +{ + (void)pid; + (void)sig; + errno = EINVAL; + return -1; +} + +int _getpid(void) +{ + return 1; +} + +void _init(void) +{ +} + +void _fini(void) +{ +} diff --git a/src/port/stm32h563/target.ld b/src/port/stm32h563/target.ld new file mode 100644 index 0000000..32a273c --- /dev/null +++ b/src/port/stm32h563/target.ld @@ -0,0 +1,63 @@ +MEMORY +{ + FLASH (rx) : ORIGIN = 0x0C000000, LENGTH = 0x00200000 + RAM (rwx) : ORIGIN = 0x30000000, LENGTH = 0x000A0000 +} + +_estack = ORIGIN(RAM) + LENGTH(RAM); +_sidata = LOADADDR(.data); + +SECTIONS +{ + .isr_vector : + { + KEEP(*(.isr_vector)) + } > FLASH + + .text : + { + *(.text*) + *(.rodata*) + *(.ARM.extab* .gnu.linkonce.armextab.*) + *(.ARM.exidx* .gnu.linkonce.armexidx.*) + *(.glue_7) + *(.glue_7t) + *(.eh_frame) + } > FLASH + + .preinit_array : + { + __preinit_array_start = .; + KEEP(*(.preinit_array*)) + __preinit_array_end = .; + } > FLASH + + .init_array : + { + __init_array_start = .; + KEEP(*(.init_array*)) + __init_array_end = .; + } > FLASH + + .fini_array : + { + __fini_array_start = .; + KEEP(*(.fini_array*)) + __fini_array_end = .; + } > FLASH + + .data : + { + _sdata = .; + *(.data*) + _edata = .; + } > RAM AT > FLASH + + .bss (NOLOAD) : + { + _sbss = .; + *(.bss*) + *(COMMON) + _ebss = .; + } > RAM +}