From fc3675e33844ac0ddaf73cd57150bbbf8cd38b48 Mon Sep 17 00:00:00 2001 From: Alex Lanzano Date: Tue, 7 Apr 2026 10:55:31 -0400 Subject: [PATCH] Add generic wolfHAL Ethernet port with STM32H563ZI Nucleo board support --- .../workflows/wolfhal-stm32h563zi-nucleo.yml | 37 ++ Makefile | 2 + src/port/wolfHAL/.gitignore | 1 + src/port/wolfHAL/Makefile | 49 +++ src/port/wolfHAL/README.md | 169 +++++++++ .../wolfHAL/boards/stm32h563zi_nucleo/board.c | 349 ++++++++++++++++++ .../wolfHAL/boards/stm32h563zi_nucleo/board.h | 60 +++ .../boards/stm32h563zi_nucleo/board.mk | 40 ++ .../wolfHAL/boards/stm32h563zi_nucleo/ivt.c | 59 +++ .../boards/stm32h563zi_nucleo/linker.ld | 92 +++++ .../boards/stm32h563zi_nucleo/startup.c | 47 +++ .../boards/stm32h563zi_nucleo/syscalls.c | 121 ++++++ src/port/wolfHAL/main.c | 148 ++++++++ src/port/wolfHAL/wolfhal_eth.c | 96 +++++ src/port/wolfHAL/wolfhal_eth.h | 107 ++++++ 15 files changed, 1377 insertions(+) create mode 100644 .github/workflows/wolfhal-stm32h563zi-nucleo.yml create mode 100644 src/port/wolfHAL/.gitignore create mode 100644 src/port/wolfHAL/Makefile create mode 100644 src/port/wolfHAL/README.md create mode 100644 src/port/wolfHAL/boards/stm32h563zi_nucleo/board.c create mode 100644 src/port/wolfHAL/boards/stm32h563zi_nucleo/board.h create mode 100644 src/port/wolfHAL/boards/stm32h563zi_nucleo/board.mk create mode 100644 src/port/wolfHAL/boards/stm32h563zi_nucleo/ivt.c create mode 100644 src/port/wolfHAL/boards/stm32h563zi_nucleo/linker.ld create mode 100644 src/port/wolfHAL/boards/stm32h563zi_nucleo/startup.c create mode 100644 src/port/wolfHAL/boards/stm32h563zi_nucleo/syscalls.c create mode 100644 src/port/wolfHAL/main.c create mode 100644 src/port/wolfHAL/wolfhal_eth.c create mode 100644 src/port/wolfHAL/wolfhal_eth.h diff --git a/.github/workflows/wolfhal-stm32h563zi-nucleo.yml b/.github/workflows/wolfhal-stm32h563zi-nucleo.yml new file mode 100644 index 00000000..bef4af18 --- /dev/null +++ b/.github/workflows/wolfhal-stm32h563zi-nucleo.yml @@ -0,0 +1,37 @@ +name: wolfHAL STM32H563ZI Nucleo Build + +on: + push: + branches: [ 'master', 'main', 'release/**' ] + pull_request: + branches: [ '*' ] + +jobs: + wolfhal_stm32h563zi_nucleo_build: + runs-on: ubuntu-latest + timeout-minutes: 10 + + steps: + - uses: actions/checkout@v4 + + - name: Install ARM toolchain + run: | + set -euo pipefail + sudo apt-get update + sudo apt-get install -y gcc-arm-none-eabi + + - name: Clone wolfHAL + run: | + set -euo pipefail + git clone --depth 1 https://github.com/wolfSSL/wolfHAL.git ../wolfHAL + + - name: Build wolfHAL port + run: | + set -euo pipefail + make -C src/port/wolfHAL BOARD=stm32h563zi_nucleo + + - name: Verify binary + run: | + set -euo pipefail + test -f src/port/wolfHAL/build/stm32h563zi_nucleo/app.bin + arm-none-eabi-size src/port/wolfHAL/build/stm32h563zi_nucleo/app.elf diff --git a/Makefile b/Makefile index 31ed261b..8d80b9d1 100644 --- a/Makefile +++ b/Makefile @@ -123,6 +123,8 @@ CPPCHECK_FLAGS=--enable=warning,performance,portability,missingInclude \ --suppress=comparePointers:src/port/stm32n6/syscalls.c \ --suppress=comparePointers:src/port/va416xx/startup.c \ --suppress=comparePointers:src/port/va416xx/syscalls.c \ + --suppress=comparePointers:src/port/wolfHAL/boards/stm32h563zi_nucleo/startup.c \ + --suppress=comparePointers:src/port/wolfHAL/boards/stm32h563zi_nucleo/syscalls.c \ --disable=style \ --std=c99 --language=c \ --platform=unix64 \ diff --git a/src/port/wolfHAL/.gitignore b/src/port/wolfHAL/.gitignore new file mode 100644 index 00000000..567609b1 --- /dev/null +++ b/src/port/wolfHAL/.gitignore @@ -0,0 +1 @@ +build/ diff --git a/src/port/wolfHAL/Makefile b/src/port/wolfHAL/Makefile new file mode 100644 index 00000000..977f6a6c --- /dev/null +++ b/src/port/wolfHAL/Makefile @@ -0,0 +1,49 @@ +ROOT = $(CURDIR)/../../.. +PORT_DIR = $(ROOT)/src/port/wolfHAL + +BOARD_DIR = $(PORT_DIR)/boards/$(BOARD) + +ifeq ($(BOARD),) + ifeq ($(MAKECMDGOALS),clean) + clean: + rm -rf build + .PHONY: clean + else + $(error BOARD is required. Usage: make BOARD=stm32h563zi_nucleo) + endif +else +include $(BOARD_DIR)/board.mk + +SOURCE = $(PORT_DIR)/main.c +SOURCE += $(PORT_DIR)/wolfhal_eth.c +SOURCE += $(ROOT)/src/wolfip.c +SOURCE += $(BOARD_SOURCE) + +BUILD_DIR = build/$(BOARD) +OBJECTS = $(patsubst %.c,$(BUILD_DIR)/%.o,$(SOURCE)) +DEPENDS = $(OBJECTS:.o=.d) + +all: $(BUILD_DIR)/app.bin + +$(BUILD_DIR)/%.o: %.c Makefile + @mkdir -p $(dir $@) + $(GCC) $(CFLAGS) -c -o $@ $< + +.SECONDARY: +$(BUILD_DIR)/%.elf: $(OBJECTS) $(LINKER_SCRIPT) + @mkdir -p $(dir $@) + $(GCC) $(CFLAGS) $(LDFLAGS) -T $(LINKER_SCRIPT) -o $@ $(OBJECTS) $(LDLIBS) + +$(BUILD_DIR)/%.bin: $(BUILD_DIR)/%.elf + $(OBJCOPY) $^ -O binary $@ + +.PHONY: clean size +clean: + rm -rf build + +size: $(BUILD_DIR)/app.elf + $(GCC_PATH)arm-none-eabi-size $< + +-include $(DEPENDS) + +endif diff --git a/src/port/wolfHAL/README.md b/src/port/wolfHAL/README.md new file mode 100644 index 00000000..f063b6a7 --- /dev/null +++ b/src/port/wolfHAL/README.md @@ -0,0 +1,169 @@ +# wolfHAL Port for wolfIP + +Generic wolfIP port that uses the wolfHAL Ethernet API (`whal_Eth` / +`whal_EthPhy`). Users create a wolfHAL board and the port handles the +rest — bridging wolfHAL's Ethernet MAC/PHY drivers to wolfIP's +link-layer device interface. + +## Supported Boards + +| Board | MCU | PHY | Directory | +|-------|-----|-----|-----------| +| NUCLEO-H563ZI | STM32H563ZI | LAN8742A | `boards/stm32h563zi_nucleo` | + +## Directory Structure + +``` +src/port/wolfHAL/ +├── Makefile # Top-level build: make BOARD= +├── main.c # Generic main: board_init -> wolfhal_eth_init -> wolfIP_poll loop +├── wolfhal_eth.h # Port API and wolfhal_eth_ctx struct +├── wolfhal_eth.c # Bridges wolfIP_ll_dev poll/send to whal_Eth_Recv/whal_Eth_Send +└── boards/ + └── / + ├── board.mk # Toolchain, CFLAGS, wolfHAL driver sources + ├── board.h # Board API declarations and device externs + ├── board.c # Clock, GPIO, Ethernet, PHY, UART, timer setup + ├── startup.c # Reset_Handler: copies .data, zeros .bss, calls main() + ├── ivt.c # Interrupt vector table + ├── syscalls.c # libc stubs (_write, _sbrk, etc.) + └── linker.ld # Memory layout (FLASH/RAM regions) +``` + +## Building + +``` +cd src/port/wolfHAL +make BOARD=stm32h563zi_nucleo +``` + +Override the wolfHAL location (defaults to `../../../wolfHAL` relative to +the wolfip root, i.e. a sibling directory): + +``` +make BOARD=stm32h563zi_nucleo WOLFHAL_ROOT=/path/to/wolfHAL +``` + +Override IP configuration or MAC address at build time: + +``` +make BOARD=stm32h563zi_nucleo \ + CFLAGS+='-DWOLFIP_IP=\"10.0.0.2\" -DWOLFIP_NETMASK=\"255.255.255.0\" -DWOLFIP_GW=\"10.0.0.1\"' +``` + +``` +make BOARD=stm32h563zi_nucleo \ + CFLAGS+='-DBOARD_MAC_ADDR={0x02,0xAA,0xBB,0xCC,0xDD,0xEE}' +``` + +## Adding a New Board + +Create a new directory under `boards/` with the following files: + +### board.h + +Must declare the following: + +#### Required Device Externs + +| Variable | Type | Description | +|----------|------|-------------| +| `g_whalEth` | `whal_Eth` | Initialized Ethernet MAC device | +| `g_whalEthPhy` | `whal_EthPhy` | Initialized Ethernet PHY device | +| `g_whalUart` | `whal_Uart` | Initialized UART device (used by `_write` syscall for printf) | +| `g_whalRng` | `whal_Rng` | Initialized RNG device (used by `wolfIP_getrandom`) | + +These names are required — `main.c`, `wolfhal_eth.c`, and `syscalls.c` +reference them directly. + +#### Required Functions + +| Function | Signature | Description | +|----------|-----------|-------------| +| `board_init` | `whal_Error board_init(void)` | Initialize all board hardware. Must call `whal_Eth_Init`, `whal_EthPhy_Init`, `whal_Uart_Init`, and start the system timer before returning. Returns `WHAL_SUCCESS` on success. | +| `board_deinit` | `whal_Error board_deinit(void)` | Tear down board hardware in reverse order. | +| `board_get_tick` | `uint32_t board_get_tick(void)` | Return a millisecond tick counter. Used by `wolfhal_eth_init` for link timeout and by `wolfIP_poll` for stack timing. | + +### board.c + +Implements the functions above. Typical `board_init` sequence: + +1. Initialize clocks (PLL, peripheral clocks) +2. Initialize GPIO (UART pins, Ethernet pins) +3. Initialize UART (`whal_Uart_Init`) +4. Initialize Ethernet MAC (`whal_Eth_Init`) +5. Initialize Ethernet PHY (`whal_EthPhy_Init`) +6. Initialize and start system timer + +The `whal_Eth` device must have its `macAddr` field set — this is +where wolfIP reads the interface MAC address from. + +### board.mk + +Provides build configuration. Must set: + +| Variable | Description | +|----------|-------------| +| `WOLFHAL_ROOT` | Path to wolfHAL (use `?=` so it's overridable) | +| `GCC` | Cross-compiler path (e.g. `arm-none-eabi-gcc`) | +| `OBJCOPY` | Objcopy tool | +| `CFLAGS` | Compiler flags (architecture, warnings, includes) | +| `LDFLAGS` | Linker flags | +| `LDLIBS` | Libraries to link (libc, libgcc, etc.) | +| `LINKER_SCRIPT` | Path to the board's linker script | +| `BOARD_SOURCE` | List of board + wolfHAL driver source files | + +`BOARD_SOURCE` must include at minimum: +- `startup.c`, `ivt.c`, `board.c`, `syscalls.c` from the board directory +- wolfHAL drivers: `eth/eth.c`, `eth/_eth.c`, + `eth_phy/eth_phy.c`, `eth_phy/.c`, `clock/clock.c`, + `clock/_rcc.c`, `gpio/gpio.c`, `gpio/_gpio.c`, + `timer/timer.c`, `timer/systick.c`, `uart/uart.c`, + `uart/_uart.c`, `rng/rng.c`, + `rng/_rng.c` + +### syscalls.c + +Must provide: +- Standard libc stubs: `_write`, `_read`, `_sbrk`, `_close`, `_fstat`, + `_isatty`, `_lseek`, `_exit`, `_kill`, `_getpid` +- `_write` should route to `whal_Uart_Send(&g_whalUart, ...)` so that + `printf` outputs to UART +- `uint32_t wolfIP_getrandom(void)` is provided by `main.c` using + `whal_Rng_Generate(&g_whalRng, ...)` + +### startup.c, ivt.c, linker.ld + +Standard bare-metal files for your target architecture. See the +`stm32h563zi_nucleo` board for a reference implementation. + +## Port API + +The port exposes a single function: + +```c +#include "wolfhal_eth.h" + +struct wolfhal_eth_ctx ctx = { + .eth = &g_whalEth, + .phy = &g_whalEthPhy, +}; + +int ret = wolfhal_eth_init(wolfIP_getdev(ipstack), &ctx); +``` + +`wolfhal_eth_init` will: +1. Poll `whal_EthPhy_GetLinkState` until link comes up (5s timeout, + configurable via `WOLFHAL_ETH_LINK_TIMEOUT_MS`) +2. Start the MAC with negotiated speed/duplex +3. Copy `eth->macAddr` to the wolfIP device +4. Register poll/send callbacks that bridge to `whal_Eth_Recv`/`whal_Eth_Send` + +## Naming Conventions + +- All port functions and variables use `snake_case` +- Board functions use `board_` prefix: `board_init`, `board_get_tick` +- Port functions use `wolfhal_` prefix: `wolfhal_eth_init` +- wolfHAL API calls retain their own naming (`whal_Eth_Init`, etc.) +- Global device instances use `g_whal` prefix: `g_whalEth`, `g_whalEthPhy`, `g_whalUart`, `g_whalRng` +- Macros use `UPPER_SNAKE_CASE` diff --git a/src/port/wolfHAL/boards/stm32h563zi_nucleo/board.c b/src/port/wolfHAL/boards/stm32h563zi_nucleo/board.c new file mode 100644 index 00000000..fe4d3cc6 --- /dev/null +++ b/src/port/wolfHAL/boards/stm32h563zi_nucleo/board.c @@ -0,0 +1,349 @@ +/* board.c + * + * Copyright (C) 2024-2026 wolfSSL Inc. + * + * Minimal board configuration for STM32H563ZI Nucleo-144 + * Only sets up what's needed for wolfIP: clocks, GPIO, Ethernet, PHY. + * + * 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 "board.h" +#include +#include + +/* SysTick timing */ +volatile uint32_t g_tick = 0; + +void SysTick_Handler(void) +{ + g_tick++; +} + +uint32_t board_get_tick(void) +{ + return g_tick; +} + +whal_Timeout g_whalTimeout = { + .timeoutTicks = 1000, + .GetTick = board_get_tick, +}; + +/* Clock: PLL1 from HSI to 168 MHz */ +static whal_Clock clock = { + WHAL_STM32H563_RCC_PLL_DEVICE, + + .cfg = &(whal_Stm32h5Rcc_Cfg) { + .sysClkSrc = WHAL_STM32H5_RCC_SYSCLK_SRC_PLL1, + .sysClkCfg = &(whal_Stm32h5Rcc_PllClkCfg) { + .clkSrc = WHAL_STM32H5_RCC_PLLCLK_SRC_HSI, + .m = 8, + .n = 62, + .p = 2, + .q = 2, + .r = 2, + }, + }, +}; + +static const whal_Stm32h5Rcc_Clk clocks[] = { + {WHAL_STM32H563_GPIOA_CLOCK}, + {WHAL_STM32H563_GPIOB_CLOCK}, + {WHAL_STM32H563_GPIOC_CLOCK}, + {WHAL_STM32H563_GPIOD_CLOCK}, + {WHAL_STM32H563_GPIOG_CLOCK}, + {WHAL_STM32H563_USART2_CLOCK}, + {WHAL_STM32H563_RNG_CLOCK}, + {WHAL_STM32H563_SBS_CLOCK}, +}; +#define CLOCK_COUNT (sizeof(clocks) / sizeof(clocks[0])) + +static const whal_Stm32h5Rcc_Clk eth_clocks[] = { + {WHAL_STM32H563_ETH_CLOCK}, + {WHAL_STM32H563_ETHTX_CLOCK}, + {WHAL_STM32H563_ETHRX_CLOCK}, +}; +#define ETH_CLOCK_COUNT (sizeof(eth_clocks) / sizeof(eth_clocks[0])) + +/* GPIO: only RMII pins */ +static whal_Gpio gpio = { + WHAL_STM32H563_GPIO_DEVICE, + + .cfg = &(whal_Stm32h5Gpio_Cfg) { + .pinCfg = (whal_Stm32h5Gpio_PinCfg[PIN_COUNT]) { + [UART_TX_PIN] = WHAL_STM32H5_GPIO_PIN( + WHAL_STM32H5_GPIO_PORT_D, 5, WHAL_STM32H5_GPIO_MODE_ALTFN, + WHAL_STM32H5_GPIO_OUTTYPE_PUSHPULL, WHAL_STM32H5_GPIO_SPEED_FAST, + WHAL_STM32H5_GPIO_PULL_UP, 7), + [UART_RX_PIN] = WHAL_STM32H5_GPIO_PIN( + WHAL_STM32H5_GPIO_PORT_D, 6, WHAL_STM32H5_GPIO_MODE_ALTFN, + WHAL_STM32H5_GPIO_OUTTYPE_PUSHPULL, WHAL_STM32H5_GPIO_SPEED_FAST, + WHAL_STM32H5_GPIO_PULL_UP, 7), + [ETH_RMII_REF_CLK_PIN] = WHAL_STM32H5_GPIO_PIN( + WHAL_STM32H5_GPIO_PORT_A, 1, WHAL_STM32H5_GPIO_MODE_ALTFN, + 0, WHAL_STM32H5_GPIO_SPEED_HIGH, + WHAL_STM32H5_GPIO_PULL_NONE, 11), + [ETH_RMII_MDIO_PIN] = WHAL_STM32H5_GPIO_PIN( + WHAL_STM32H5_GPIO_PORT_A, 2, WHAL_STM32H5_GPIO_MODE_ALTFN, + 0, WHAL_STM32H5_GPIO_SPEED_HIGH, + WHAL_STM32H5_GPIO_PULL_NONE, 11), + [ETH_RMII_MDC_PIN] = WHAL_STM32H5_GPIO_PIN( + WHAL_STM32H5_GPIO_PORT_C, 1, WHAL_STM32H5_GPIO_MODE_ALTFN, + 0, WHAL_STM32H5_GPIO_SPEED_HIGH, + WHAL_STM32H5_GPIO_PULL_NONE, 11), + [ETH_RMII_CRS_DV_PIN] = WHAL_STM32H5_GPIO_PIN( + WHAL_STM32H5_GPIO_PORT_A, 7, WHAL_STM32H5_GPIO_MODE_ALTFN, + 0, WHAL_STM32H5_GPIO_SPEED_HIGH, + WHAL_STM32H5_GPIO_PULL_NONE, 11), + [ETH_RMII_RXD0_PIN] = WHAL_STM32H5_GPIO_PIN( + WHAL_STM32H5_GPIO_PORT_C, 4, WHAL_STM32H5_GPIO_MODE_ALTFN, + 0, WHAL_STM32H5_GPIO_SPEED_HIGH, + WHAL_STM32H5_GPIO_PULL_NONE, 11), + [ETH_RMII_RXD1_PIN] = WHAL_STM32H5_GPIO_PIN( + WHAL_STM32H5_GPIO_PORT_C, 5, WHAL_STM32H5_GPIO_MODE_ALTFN, + 0, WHAL_STM32H5_GPIO_SPEED_HIGH, + WHAL_STM32H5_GPIO_PULL_NONE, 11), + [ETH_RMII_TX_EN_PIN] = WHAL_STM32H5_GPIO_PIN( + WHAL_STM32H5_GPIO_PORT_G, 11, WHAL_STM32H5_GPIO_MODE_ALTFN, + 0, WHAL_STM32H5_GPIO_SPEED_HIGH, + WHAL_STM32H5_GPIO_PULL_NONE, 11), + [ETH_RMII_TXD0_PIN] = WHAL_STM32H5_GPIO_PIN( + WHAL_STM32H5_GPIO_PORT_G, 13, WHAL_STM32H5_GPIO_MODE_ALTFN, + 0, WHAL_STM32H5_GPIO_SPEED_HIGH, + WHAL_STM32H5_GPIO_PULL_NONE, 11), + [ETH_RMII_TXD1_PIN] = WHAL_STM32H5_GPIO_PIN( + WHAL_STM32H5_GPIO_PORT_B, 15, WHAL_STM32H5_GPIO_MODE_ALTFN, + 0, WHAL_STM32H5_GPIO_SPEED_HIGH, + WHAL_STM32H5_GPIO_PULL_NONE, 11), + }, + .pinCount = PIN_COUNT, + }, +}; + +/* Timer: SysTick at 1 ms */ +static whal_Timer timer = { + WHAL_CORTEX_M33_SYSTICK_DEVICE, + + .cfg = &(whal_SysTick_Cfg) { + .cyclesPerTick = 168000000 / 1000, + .clkSrc = WHAL_SYSTICK_CLKSRC_SYSCLK, + .tickInt = WHAL_SYSTICK_TICKINT_ENABLED, + }, +}; + +/* Ethernet MAC */ +#define ETH_TX_DESC_COUNT 4 +#define ETH_RX_DESC_COUNT 4 +#define ETH_TX_BUF_SIZE 1536 +#define ETH_RX_BUF_SIZE 1536 + +static whal_Stm32h5Eth_TxDesc eth_tx_descs[ETH_TX_DESC_COUNT] + __attribute__((aligned(16))); +static whal_Stm32h5Eth_RxDesc eth_rx_descs[ETH_RX_DESC_COUNT] + __attribute__((aligned(16))); +static uint8_t eth_tx_bufs[ETH_TX_DESC_COUNT * ETH_TX_BUF_SIZE] + __attribute__((aligned(4))); +static uint8_t eth_rx_bufs[ETH_RX_DESC_COUNT * ETH_RX_BUF_SIZE] + __attribute__((aligned(4))); + +#ifndef BOARD_MAC_ADDR +#define BOARD_MAC_ADDR {0x00, 0x80, 0xE1, 0x00, 0x00, 0x01} +#endif + +whal_Eth g_whalEth = { + WHAL_STM32H563_ETH_DEVICE, + + .macAddr = BOARD_MAC_ADDR, + .cfg = &(whal_Stm32h5Eth_Cfg) { + .txDescs = eth_tx_descs, + .txBufs = eth_tx_bufs, + .txDescCount = ETH_TX_DESC_COUNT, + .txBufSize = ETH_TX_BUF_SIZE, + .rxDescs = eth_rx_descs, + .rxBufs = eth_rx_bufs, + .rxDescCount = ETH_RX_DESC_COUNT, + .rxBufSize = ETH_RX_BUF_SIZE, + .timeout = &g_whalTimeout, + }, +}; + +/* Ethernet PHY (LAN8742A) */ +whal_EthPhy g_whalEthPhy = { + .eth = &g_whalEth, + .addr = BOARD_ETH_PHY_ADDR, + .driver = &whal_Lan8742a_Driver, + + .cfg = &(whal_Lan8742a_Cfg) { + .timeout = &g_whalTimeout, + }, +}; + +/* UART: USART2 on ST-Link VCP */ +whal_Uart g_whalUart = { + WHAL_STM32H563_USART2_DEVICE, + + .cfg = &(whal_Stm32h5Uart_Cfg) { + .brr = WHAL_STM32H5_UART_BRR(168000000, 115200), + .timeout = &g_whalTimeout, + }, +}; + +/* RNG */ +whal_Rng g_whalRng = { + WHAL_STM32H563_RNG_DEVICE, + + .cfg = &(whal_Stm32h5Rng_Cfg) { + .timeout = &g_whalTimeout, + }, +}; + +/* Flash: needed for latency configuration before clock increase */ +static whal_Flash flash = { + WHAL_STM32H563_FLASH_DEVICE, + + .cfg = &(whal_Stm32h5Flash_Cfg) { + .startAddr = 0x08000000, + .size = 0x200000, + .timeout = &g_whalTimeout, + }, +}; + +/* 5 wait states + WRHIGHFREQ=2 for 168 MHz */ +#define FLASH_LATENCY_168MHZ ((2 << 4) | 5) + +whal_Error board_init(void) +{ + whal_Error err; + size_t i; + + /* Set flash latency before increasing clock speed */ + err = whal_Stm32h5Flash_Ext_SetLatency(&flash, FLASH_LATENCY_168MHZ); + if (err) + return err; + + err = whal_Clock_Init(&clock); + if (err) + return err; + + for (i = 0; i < CLOCK_COUNT; i++) { + err = whal_Clock_Enable(&clock, &clocks[i]); + if (err) + return err; + } + + /* Select RMII mode in SBS_PMCR before enabling ETH clocks */ + #define SBS_PMCR (*(volatile uint32_t *)0x44000500) + #define SBS_PMCR_ETH_SEL_Msk (7UL << 21) + #define SBS_PMCR_ETH_SEL_RMII (4UL << 21) + SBS_PMCR = (SBS_PMCR & ~SBS_PMCR_ETH_SEL_Msk) | SBS_PMCR_ETH_SEL_RMII; + + for (i = 0; i < ETH_CLOCK_COUNT; i++) { + err = whal_Clock_Enable(&clock, ð_clocks[i]); + if (err) + return err; + } + + err = whal_Gpio_Init(&gpio); + if (err) + return err; + + err = whal_Uart_Init(&g_whalUart); + if (err) + return err; + + /* Enable HSI48 for RNG kernel clock */ + err = whal_Stm32h5Rcc_Ext_EnableHsi48(&clock, 1); + if (err) + return err; + + err = whal_Rng_Init(&g_whalRng); + if (err) + return err; + + err = whal_Eth_Init(&g_whalEth); + if (err) + return err; + + err = whal_EthPhy_Init(&g_whalEthPhy); + if (err) + return err; + + err = whal_Timer_Init(&timer); + if (err) + return err; + + err = whal_Timer_Start(&timer); + if (err) + return err; + + return WHAL_SUCCESS; +} + +whal_Error board_deinit(void) +{ + whal_Error err; + size_t i; + + err = whal_Timer_Stop(&timer); + if (err) + return err; + + err = whal_Timer_Deinit(&timer); + if (err) + return err; + + err = whal_EthPhy_Deinit(&g_whalEthPhy); + if (err) + return err; + + err = whal_Eth_Deinit(&g_whalEth); + if (err) + return err; + + err = whal_Rng_Deinit(&g_whalRng); + if (err) + return err; + + err = whal_Uart_Deinit(&g_whalUart); + if (err) + return err; + + err = whal_Gpio_Deinit(&gpio); + if (err) + return err; + + for (i = 0; i < ETH_CLOCK_COUNT; i++) { + err = whal_Clock_Disable(&clock, ð_clocks[i]); + if (err) + return err; + } + + for (i = 0; i < CLOCK_COUNT; i++) { + err = whal_Clock_Disable(&clock, &clocks[i]); + if (err) + return err; + } + + err = whal_Clock_Deinit(&clock); + if (err) + return err; + + return WHAL_SUCCESS; +} diff --git a/src/port/wolfHAL/boards/stm32h563zi_nucleo/board.h b/src/port/wolfHAL/boards/stm32h563zi_nucleo/board.h new file mode 100644 index 00000000..dfe9c244 --- /dev/null +++ b/src/port/wolfHAL/boards/stm32h563zi_nucleo/board.h @@ -0,0 +1,60 @@ +/* board.h + * + * Copyright (C) 2024-2026 wolfSSL Inc. + * + * Minimal board configuration for STM32H563ZI Nucleo-144 + * + * 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 BOARD_H +#define BOARD_H + +#include +#include +#include + +extern whal_Eth g_whalEth; +extern whal_EthPhy g_whalEthPhy; +extern whal_Uart g_whalUart; +extern whal_Rng g_whalRng; + +extern whal_Timeout g_whalTimeout; +extern volatile uint32_t g_tick; + +/* Ethernet PHY: LAN8742A on MDIO address 0 */ +#define BOARD_ETH_PHY_ADDR 0 + +enum { + UART_TX_PIN, + UART_RX_PIN, + ETH_RMII_REF_CLK_PIN, + ETH_RMII_MDIO_PIN, + ETH_RMII_MDC_PIN, + ETH_RMII_CRS_DV_PIN, + ETH_RMII_RXD0_PIN, + ETH_RMII_RXD1_PIN, + ETH_RMII_TX_EN_PIN, + ETH_RMII_TXD0_PIN, + ETH_RMII_TXD1_PIN, + PIN_COUNT, +}; + +whal_Error board_init(void); +whal_Error board_deinit(void); +uint32_t board_get_tick(void); +#endif /* BOARD_H */ diff --git a/src/port/wolfHAL/boards/stm32h563zi_nucleo/board.mk b/src/port/wolfHAL/boards/stm32h563zi_nucleo/board.mk new file mode 100644 index 00000000..9c03eba4 --- /dev/null +++ b/src/port/wolfHAL/boards/stm32h563zi_nucleo/board.mk @@ -0,0 +1,40 @@ +_WOLFIP_BOARD_DIR := $(patsubst %/,%,$(dir $(lastword $(MAKEFILE_LIST)))) + +WOLFHAL_ROOT ?= $(ROOT)/../wolfHAL + +GCC = $(GCC_PATH)arm-none-eabi-gcc +LD = $(GCC_PATH)arm-none-eabi-ld +OBJCOPY = $(GCC_PATH)arm-none-eabi-objcopy + +CFLAGS += -Wall -Werror -g3 -ffreestanding -nostdlib -mcpu=cortex-m33 +CFLAGS += -DPLATFORM_STM32H5 -MMD -MP +CFLAGS += -I$(WOLFHAL_ROOT) -I$(_WOLFIP_BOARD_DIR) +CFLAGS += -I$(ROOT) -I$(ROOT)/src -I$(PORT_DIR) + +CFLAGS += -fdata-sections -ffunction-sections + +LDFLAGS = -nostdlib -Wl,-gc-sections +LDLIBS = -Wl,--start-group -lc -lm -lgcc -lnosys -Wl,--end-group +LINKER_SCRIPT ?= $(_WOLFIP_BOARD_DIR)/linker.ld + +BOARD_SOURCE = $(_WOLFIP_BOARD_DIR)/startup.c +BOARD_SOURCE += $(_WOLFIP_BOARD_DIR)/ivt.c +BOARD_SOURCE += $(_WOLFIP_BOARD_DIR)/board.c +BOARD_SOURCE += $(_WOLFIP_BOARD_DIR)/syscalls.c + +# wolfHAL drivers +BOARD_SOURCE += $(WOLFHAL_ROOT)/src/eth/eth.c +BOARD_SOURCE += $(WOLFHAL_ROOT)/src/eth/stm32h5_eth.c +BOARD_SOURCE += $(WOLFHAL_ROOT)/src/eth_phy/eth_phy.c +BOARD_SOURCE += $(WOLFHAL_ROOT)/src/eth_phy/lan8742a.c +BOARD_SOURCE += $(WOLFHAL_ROOT)/src/clock/clock.c +BOARD_SOURCE += $(WOLFHAL_ROOT)/src/clock/stm32h5_rcc.c +BOARD_SOURCE += $(WOLFHAL_ROOT)/src/gpio/gpio.c +BOARD_SOURCE += $(WOLFHAL_ROOT)/src/gpio/stm32h5_gpio.c +BOARD_SOURCE += $(WOLFHAL_ROOT)/src/timer/timer.c +BOARD_SOURCE += $(WOLFHAL_ROOT)/src/timer/systick.c +BOARD_SOURCE += $(WOLFHAL_ROOT)/src/uart/uart.c +BOARD_SOURCE += $(WOLFHAL_ROOT)/src/uart/stm32h5_uart.c +BOARD_SOURCE += $(WOLFHAL_ROOT)/src/flash/stm32h5_flash.c +BOARD_SOURCE += $(WOLFHAL_ROOT)/src/rng/rng.c +BOARD_SOURCE += $(WOLFHAL_ROOT)/src/rng/stm32h5_rng.c diff --git a/src/port/wolfHAL/boards/stm32h563zi_nucleo/ivt.c b/src/port/wolfHAL/boards/stm32h563zi_nucleo/ivt.c new file mode 100644 index 00000000..050ee86d --- /dev/null +++ b/src/port/wolfHAL/boards/stm32h563zi_nucleo/ivt.c @@ -0,0 +1,59 @@ +/* ivt.c + * + * Copyright (C) 2024-2026 wolfSSL Inc. + * + * Interrupt vector table for Cortex-M33 (STM32H563) + * + * 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/wolfHAL/boards/stm32h563zi_nucleo/linker.ld b/src/port/wolfHAL/boards/stm32h563zi_nucleo/linker.ld new file mode 100644 index 00000000..e7115549 --- /dev/null +++ b/src/port/wolfHAL/boards/stm32h563zi_nucleo/linker.ld @@ -0,0 +1,92 @@ +/* STM32H563ZI Linker Script + * + * Memory Map: + * FLASH: 2MB @ 0x08000000 + * SRAM: 640KB @ 0x20000000 (contiguous SRAM1+SRAM2+SRAM3) + */ + +MEMORY +{ + FLASH (rx) : ORIGIN = 0x08000000, LENGTH = 2048K + RAM (rwx) : ORIGIN = 0x20000000, LENGTH = 640K +} + +_estack = ORIGIN(RAM) + LENGTH(RAM); +_sidata = LOADADDR(.data); + +_Min_Heap_Size = 0x10000; /* 64KB heap */ +_Min_Stack_Size = 0x8000; /* 32KB stack */ +_heap_limit = _estack - _Min_Stack_Size; + +SECTIONS +{ + .isr_vector : + { + . = ALIGN(4); + KEEP(*(.isr_vector)) + . = ALIGN(4); + } > FLASH + + .text : + { + . = ALIGN(4); + *(.text*) + *(.rodata*) + *(.ARM.extab* .gnu.linkonce.armextab.*) + *(.ARM.exidx* .gnu.linkonce.armexidx.*) + *(.glue_7) + *(.glue_7t) + *(.eh_frame) + . = ALIGN(4); + } > 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 : + { + . = ALIGN(4); + _sdata = .; + *(.data*) + . = ALIGN(4); + _edata = .; + } > RAM AT > FLASH + + .bss (NOLOAD) : + { + . = ALIGN(4); + _sbss = .; + *(.bss*) + *(COMMON) + . = ALIGN(4); + _ebss = .; + } > RAM + + ._user_heap_stack (NOLOAD) : + { + . = ALIGN(8); + PROVIDE ( end = . ); + PROVIDE ( _end = . ); + . = . + _Min_Heap_Size; + . = . + _Min_Stack_Size; + . = ALIGN(8); + } > RAM +} diff --git a/src/port/wolfHAL/boards/stm32h563zi_nucleo/startup.c b/src/port/wolfHAL/boards/stm32h563zi_nucleo/startup.c new file mode 100644 index 00000000..45c4f0f3 --- /dev/null +++ b/src/port/wolfHAL/boards/stm32h563zi_nucleo/startup.c @@ -0,0 +1,47 @@ +/* startup.c + * + * Copyright (C) 2024-2026 wolfSSL Inc. + * + * Cortex-M startup: copies .data, zeros .bss, calls main(). + * + * 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/wolfHAL/boards/stm32h563zi_nucleo/syscalls.c b/src/port/wolfHAL/boards/stm32h563zi_nucleo/syscalls.c new file mode 100644 index 00000000..6fd78f7c --- /dev/null +++ b/src/port/wolfHAL/boards/stm32h563zi_nucleo/syscalls.c @@ -0,0 +1,121 @@ +/* syscalls.c + * + * Copyright (C) 2024-2026 wolfSSL Inc. + * + * Minimal libc stubs and wolfIP platform hooks for bare-metal. + * + * 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 +extern uint32_t _ebss; +extern uint32_t _heap_limit; +extern whal_Uart g_whalUart; + +static char *heap_end; + +int _write(int file, const char *ptr, int len) +{ + (void)file; + if (len > 0) + whal_Uart_Send(&g_whalUart, ptr, (size_t)len); + return len; +} + +int _close(int file) +{ + (void)file; + return -1; +} + +int _fstat(int file, struct stat *st) +{ + (void)file; + if (st == NULL) { + 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 *)&_heap_limit) { + errno = ENOMEM; + return (void *)-1; + } + heap_end += incr; + return prev; +} + +void _exit(int status) +{ + (void)status; + while (1) { } +} + +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/wolfHAL/main.c b/src/port/wolfHAL/main.c new file mode 100644 index 00000000..a046b059 --- /dev/null +++ b/src/port/wolfHAL/main.c @@ -0,0 +1,148 @@ +/* main.c + * + * Copyright (C) 2024-2026 wolfSSL Inc. + * + * Generic wolfHAL main for wolfIP — works with any wolfHAL board that + * provides whal_Eth and whal_EthPhy. + * + * 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 "wolfip.h" +#include "wolfhal_eth.h" +#include "board.h" + +#ifndef WOLFIP_IP +#define WOLFIP_IP "192.168.1.100" +#endif +#ifndef WOLFIP_NETMASK +#define WOLFIP_NETMASK "255.255.255.0" +#endif +#ifndef WOLFIP_GW +#define WOLFIP_GW "192.168.1.1" +#endif + +#define ECHO_PORT 7 + +static int listen_fd = -1; + +static void echo_cb(int sockfd, uint16_t events, void *arg) +{ + struct wolfIP *s = (struct wolfIP *)arg; + uint8_t buf[512]; + int ret; + + if ((events & CB_EVENT_CLOSED) && sockfd != listen_fd) { + wolfIP_sock_close(s, sockfd); + return; + } + + if (events & CB_EVENT_READABLE) { + if (sockfd == listen_fd) { + wolfIP_sock_accept(s, listen_fd, NULL, NULL); + } else { + ret = wolfIP_sock_read(s, sockfd, buf, sizeof(buf)); + if (ret > 0) + wolfIP_sock_write(s, sockfd, buf, ret); + else if (ret == 0) + wolfIP_sock_close(s, sockfd); + } + } +} + +uint32_t wolfIP_getrandom(void) +{ + uint32_t val = 0; + whal_Rng_Generate(&g_whalRng, &val, sizeof(val)); + return val; +} + +uint64_t wolfip_get_time_ms(void) +{ + return (uint64_t)board_get_tick(); +} + +int main(void) +{ + struct wolfIP_ll_dev *ll; + struct wolfIP_sockaddr_in addr; + struct wolfIP *ipstack; + struct wolfhal_eth_ctx eth_ctx; + uint8_t up, speed, duplex; + int ret; + + ret = board_init(); + if (ret != WHAL_SUCCESS) { + printf("board_init failed\r\n"); + return 1; + } + + eth_ctx.eth = &g_whalEth; + eth_ctx.phy = &g_whalEthPhy; + + printf("\r\n=== wolfIP + wolfHAL ===\r\n"); + + printf("Initializing wolfIP stack...\r\n"); + wolfIP_init_static(&ipstack); + + printf("Initializing Ethernet (waiting for link)...\r\n"); + ll = wolfIP_getdev(ipstack); + ret = wolfhal_eth_init(ll, ð_ctx); + if (ret == -4) { + printf("PHY link timeout\r\n"); + return 1; + } else if (ret < 0) { + printf("wolfhal_eth_init failed (%d)\r\n", ret); + return 1; + } + + ret = whal_EthPhy_GetLinkState(eth_ctx.phy, &up, &speed, &duplex); + if (ret == WHAL_SUCCESS) + printf("Link up: %d Mbps %s duplex\r\n", speed, + duplex ? "full" : "half"); + else + printf("Link up (could not read speed/duplex)\r\n"); + + printf("Setting IP: %s\r\n", WOLFIP_IP); + wolfIP_ipconfig_set(ipstack, + atoip4(WOLFIP_IP), + atoip4(WOLFIP_NETMASK), + atoip4(WOLFIP_GW)); + + printf("Starting TCP echo server on port %d...\r\n", ECHO_PORT); + 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; + wolfIP_sock_bind(ipstack, listen_fd, + (struct wolfIP_sockaddr *)&addr, sizeof(addr)); + wolfIP_sock_listen(ipstack, listen_fd, 1); + + printf("Ready.\r\n"); + + for (;;) { + wolfIP_poll(ipstack, board_get_tick()); + } + + return 0; +} diff --git a/src/port/wolfHAL/wolfhal_eth.c b/src/port/wolfHAL/wolfhal_eth.c new file mode 100644 index 00000000..463b8522 --- /dev/null +++ b/src/port/wolfHAL/wolfhal_eth.c @@ -0,0 +1,96 @@ +/* wolfhal_eth.c + * + * Copyright (C) 2024-2026 wolfSSL Inc. + * + * Generic wolfHAL Ethernet port for wolfIP + * + * 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 "wolfhal_eth.h" +#include "board.h" +#include + +#ifndef WOLFHAL_ETH_LINK_TIMEOUT_MS +#define WOLFHAL_ETH_LINK_TIMEOUT_MS 5000 +#endif + +static int wolfhal_eth_poll(struct wolfIP_ll_dev *dev, void *buf, uint32_t len) +{ + struct wolfhal_eth_ctx *ctx = (struct wolfhal_eth_ctx *)dev->priv; + size_t recv_len = (size_t)len; + whal_Error err; + + err = whal_Eth_Recv(ctx->eth, buf, &recv_len); + if (err == WHAL_ENOTREADY) + return 0; + if (err != WHAL_SUCCESS) + return -1; + + return (int)recv_len; +} + +static int wolfhal_eth_send(struct wolfIP_ll_dev *dev, void *buf, uint32_t len) +{ + struct wolfhal_eth_ctx *ctx = (struct wolfhal_eth_ctx *)dev->priv; + whal_Error err; + + err = whal_Eth_Send(ctx->eth, buf, (size_t)len); + if (err != WHAL_SUCCESS) + return -1; + + return (int)len; +} + +int wolfhal_eth_init(struct wolfIP_ll_dev *ll, struct wolfhal_eth_ctx *ctx) +{ + uint8_t link_up, speed, duplex; + whal_Error err; + uint32_t start; + + if (ll == NULL || ctx == NULL || ctx->eth == NULL || ctx->phy == NULL) + return -1; + + /* Wait for PHY link to come up */ + link_up = 0; + start = board_get_tick(); + do { + err = whal_EthPhy_GetLinkState(ctx->phy, &link_up, &speed, &duplex); + if (err != WHAL_SUCCESS) + return -2; + if (link_up) + break; + } while ((board_get_tick() - start) < WOLFHAL_ETH_LINK_TIMEOUT_MS); + + if (!link_up) + return -4; + + /* Start the MAC with negotiated link parameters */ + err = whal_Eth_Start(ctx->eth, speed, duplex); + if (err != WHAL_SUCCESS) + return -3; + + /* Configure wolfIP device */ + memcpy(ll->mac, ctx->eth->macAddr, 6); + strncpy(ll->ifname, "eth0", sizeof(ll->ifname) - 1); + ll->ifname[sizeof(ll->ifname) - 1] = '\0'; + ll->poll = wolfhal_eth_poll; + ll->send = wolfhal_eth_send; + ll->priv = ctx; + + return 0; +} diff --git a/src/port/wolfHAL/wolfhal_eth.h b/src/port/wolfHAL/wolfhal_eth.h new file mode 100644 index 00000000..9c9be923 --- /dev/null +++ b/src/port/wolfHAL/wolfhal_eth.h @@ -0,0 +1,107 @@ +/* wolfhal_eth.h + * + * Copyright (C) 2024-2026 wolfSSL Inc. + * + * Generic wolfHAL Ethernet port for wolfIP + * + * 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 + */ + +/** + * @file wolfhal_eth.h + * @brief Generic wolfHAL Ethernet port for wolfIP + * + * This port bridges wolfIP's link-layer device interface to wolfHAL's + * Ethernet MAC and PHY APIs. It works with any board that provides a + * configured whal_Eth and whal_EthPhy — no platform-specific code needed. + * + * ## Quick Start + * + * @code + * #include "wolfip.h" + * #include "wolfhal_eth.h" + * #include "board.h" + * + * int main(void) + * { + * struct wolfIP *ipstack; + * + * board_init(); + * + * struct wolfhal_eth_ctx eth_ctx = { + * .eth = &g_whalEth, + * .phy = &g_whalEthPhy, + * }; + * + * wolfIP_init_static(&ipstack); + * wolfhal_eth_init(wolfIP_getdev(ipstack), ð_ctx); + * wolfIP_ipconfig_set(ipstack, + * atoip4("192.168.1.100"), + * atoip4("255.255.255.0"), + * atoip4("192.168.1.1")); + * + * while (1) { + * wolfIP_poll(ipstack, board_get_tick()); + * } + * } + * @endcode + */ + +#ifndef WOLFIP_WOLFHAL_ETH_H +#define WOLFIP_WOLFHAL_ETH_H + +#include +#include "wolfip.h" +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +struct wolfhal_eth_ctx { + whal_Eth *eth; + whal_EthPhy *phy; +}; + +/** + * @brief Initialize the wolfHAL Ethernet port for wolfIP + * + * Queries the PHY for link state, starts the MAC with the negotiated + * speed and duplex, and registers poll/send callbacks on the wolfIP + * device. + * + * Prerequisites: + * - board_init() (or equivalent) has already called whal_Eth_Init() + * and whal_EthPhy_Init() to set up the hardware. + * + * @param ll Pointer to wolfIP low-level device (from wolfIP_getdev()) + * @param ctx Caller-owned context with eth and phy already set + * + * @return 0 on success + * @return -1 if any argument is NULL + * @return -2 if PHY link state query fails + * @return -3 if MAC start fails + * @return -4 if PHY link did not come up within timeout + */ +int wolfhal_eth_init(struct wolfIP_ll_dev *ll, struct wolfhal_eth_ctx *ctx); + +#ifdef __cplusplus +} +#endif + +#endif /* WOLFIP_WOLFHAL_ETH_H */