diff --git a/src/port/pic32mz/.gitignore b/src/port/pic32mz/.gitignore new file mode 100644 index 00000000..155f9d51 --- /dev/null +++ b/src/port/pic32mz/.gitignore @@ -0,0 +1,9 @@ +# Build artifacts +*.o +app.elf +app.hex +app.map +# MDB / IPE transient files +mdb_flash.cmd +MPLABXLog.* +log.* diff --git a/src/port/pic32mz/Makefile b/src/port/pic32mz/Makefile new file mode 100644 index 00000000..c3be1055 --- /dev/null +++ b/src/port/pic32mz/Makefile @@ -0,0 +1,102 @@ +# wolfIP PIC32MZ EF port - build with Microchip XC32 +# +# Copyright (C) 2026 wolfSSL Inc. Part of the wolfIP TCP/IP stack (GPLv3). +# +# Phase 0: clocks + UART2 console + heartbeat. +# Phase 1: wolfCrypt PIC32MZ hardware TRNG self-test. +# Phase 2: MDIO + LAN8740 PHY link bring-up. +# (Full Ethernet RX/TX driver + wolfIP core are added in later phases.) +# +# Usage: +# make # build app.hex +# make flash # program over the on-board debugger (v6.20 IPE) +# make clean +# Overridable: +# XC32_BIN= XC32 bin dir (default /opt/microchip/xc32/v5.10/bin) +# DFP= device family pack version dir +# DEVICE= 32MZ2048EFM144 +# WOLFSSL_ROOT= path to wolfssl checkout (used from Phase 1 on) +# MDB= MPLAB X MDB CLI (default v6.20; v6.30 dropped the EF SK debugger) + +XC32_BIN ?= /opt/microchip/xc32/v5.10/bin +DFP ?= /opt/microchip/mplabx/v6.30/packs/Microchip/PIC32MZ-EF_DFP/1.5.173 +DEVICE ?= 32MZ2048EFM144 + +CC := $(XC32_BIN)/xc32-gcc +BIN2HEX := $(XC32_BIN)/xc32-bin2hex +SIZE := $(XC32_BIN)/xc32-size + +# Flashing over the EF Starter Kit's on-board debugger. +# Use MPLAB X v6.20's MDB (Microchip DeBugger CLI): the stripped headless +# ipecmd cannot resolve the device pack ("Unable to locate DFP"), but MDB +# launches the full platform and resolves packs like the IDE/IPE GUI does. +# v6.30 dropped support for this on-board debugger, so v6.20 is required. +# MDB enumerates the on-board debugger as tool type "sk" (Starter Kit). +MDB ?= /opt/microchip/mplabx/v6.20/mplab_platform/bin/mdb.sh +MDB_DEVICE ?= PIC32MZ2048EFM144 +MDB_TOOL ?= sk + +ROOT := ../../.. +WOLFSSL_ROOT ?= /home/davidgarske/GitHub/wolfssl + +# -O1 is available in the free XC32 edition (-O2/-Os/-O3 need a PRO license). +CFLAGS := -mprocessor=$(DEVICE) -mdfp="$(DFP)" +CFLAGS += -O1 -g -Wall -Wextra -ffunction-sections -fdata-sections +CFLAGS += -I. -I$(ROOT) -I$(ROOT)/src +CFLAGS += -DWOLFSSL_USER_SETTINGS -I$(WOLFSSL_ROOT) +CFLAGS += $(EXTRA_CFLAGS) + +# Heap for the Hash-DRBG (wc_InitRng allocates the DRBG state). +LDFLAGS := -mprocessor=$(DEVICE) -mdfp="$(DFP)" +LDFLAGS += -Wl,--defsym,_min_heap_size=0x8000 +LDFLAGS += -Wl,--gc-sections -Wl,-Map=app.map,--cref + +# Port + application sources (strict warnings) +APP_SRCS := device_config.c clock_init.c uart_console.c timebase.c \ + wolf_compat.c rng_selftest.c pic32mz_eth.c phy_lan8740.c main.c +APP_OBJS := $(patsubst %.c,%.o,$(APP_SRCS)) + +# wolfcrypt sources for the RNG self-test (compiled with relaxed warnings). +# Pulled directly from the sibling wolfssl checkout, no copy. +WC_SRC := $(WOLFSSL_ROOT)/wolfcrypt/src +WC_NAMES := random sha256 hash wc_port logging memory error +WC_OBJS := $(addsuffix .o,$(addprefix wc_,$(WC_NAMES))) +CFLAGS_WC := -mprocessor=$(DEVICE) -mdfp="$(DFP)" -O1 -g \ + -ffunction-sections -fdata-sections \ + -DWOLFSSL_USER_SETTINGS -I. -I$(WOLFSSL_ROOT) -w + +ALL_OBJS := $(APP_OBJS) $(WC_OBJS) + +all: app.hex + @echo "Built PIC32MZ wolfIP port (Phase 0+1+2)" + @$(SIZE) app.elf + +app.elf: $(ALL_OBJS) + $(CC) $(CFLAGS) $(ALL_OBJS) $(LDFLAGS) -o $@ + +app.hex: app.elf + $(BIN2HEX) $< + +%.o: %.c + $(CC) $(CFLAGS) -c $< -o $@ + +wc_%.o: $(WC_SRC)/%.c + $(CC) $(CFLAGS_WC) -c $< -o $@ + +# Program the hex over the on-board debugger via MDB. Close/disconnect the +# MPLAB X IPE/IDE GUI first so it isn't holding the tool. The command script: +# set programoptions.eraseb4program true -> full chip erase before program +# hwtool sk -p -> connect Starter Kit for programming +# program -> erase + program, then release +# If there is more than one "sk" tool, append the index (e.g. "hwtool sk -p 0"). +# If "Failed to get Device ID" with the board visibly booting, the PKOB is +# losing MCLR (USB comms) -- move it to a direct/powered USB port and retry. +flash: app.hex + @printf 'device %s\nset programoptions.eraseb4program true\nhwtool %s -p\nprogram %s\nquit\n' \ + "$(MDB_DEVICE)" "$(MDB_TOOL)" "$(CURDIR)/app.hex" > mdb_flash.cmd + cd $(dir $(MDB)) && sh ./mdb.sh $(CURDIR)/mdb_flash.cmd + +clean: + rm -f *.o app.elf app.hex app.map mdb_flash.cmd MPLABXLog.* log.* + +.PHONY: all clean flash diff --git a/src/port/pic32mz/board.h b/src/port/pic32mz/board.h new file mode 100644 index 00000000..a0c56d49 --- /dev/null +++ b/src/port/pic32mz/board.h @@ -0,0 +1,38 @@ +/* board.h + * + * Board constants for the PIC32MZ EF Starter Kit (DM320007) + LAN8740 PHY DB. + * + * 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 PIC32MZ_BOARD_H +#define PIC32MZ_BOARD_H + +/* Clock tree (set by DEVCFG config words at reset; see device_config.c) */ +#define SYS_CLK_FREQ 200000000ul /* SYSCLK from SPLL */ +#define PBCLK2_FREQ 100000000ul /* peripheral bus 2 (UART) = SYSCLK/2 */ +#define PBCLK5_FREQ 100000000ul /* peripheral bus 5 (EMAC) = SYSCLK/2 */ + +/* Console UART: U2TX on RPB14, U2RX on RPG6 (external MCP2221 USB-UART) */ +#define CONSOLE_BAUD 115200u + +/* On-board LEDs LED1/LED2/LED3 on RH0/RH1/RH2 (active high) */ +#define LED_MASK 0x0007u +#define LED_HEARTBEAT 0x0001u /* LED1 = RH0 */ + +#endif /* PIC32MZ_BOARD_H */ diff --git a/src/port/pic32mz/cache.h b/src/port/pic32mz/cache.h new file mode 100644 index 00000000..586d19ab --- /dev/null +++ b/src/port/pic32mz/cache.h @@ -0,0 +1,51 @@ +/* cache.h + * + * MIPS KSEG segment helpers for DMA-coherent access on PIC32MZ. + * + * 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 PIC32MZ_CACHE_H +#define PIC32MZ_CACHE_H + +#include + +/* The PIC32MZ Ethernet controller (EMAC) is not cache-coherent and programs + * its descriptor base/buffer pointers with PHYSICAL addresses. The simplest + * coherent scheme on MIPS is to access all descriptor rings and DMA buffers + * through KSEG1 (uncached) virtual aliases and hand the EMAC the physical + * address. This avoids per-operation cache clean/invalidate entirely. + * + * Equivalent to XC32 KVA0_TO_KVA1 / KVA_TO_PA / PA_TO_KVA1, but + * kept self-contained so the early bare-metal layer can be lifted into + * wolfBoot without pulling in the XC32 system headers. + */ + +/* Cached KSEG0 virtual address -> uncached KSEG1 virtual address */ +#define PIC32_KVA0_TO_KVA1(v) (((uint32_t)(v)) | 0x20000000u) + +/* Any KSEG0/KSEG1 virtual address -> physical address (for the EMAC) */ +#define PIC32_KVA_TO_PA(v) (((uint32_t)(v)) & 0x1FFFFFFFu) + +/* Physical address -> uncached KSEG1 virtual address */ +#define PIC32_PA_TO_KVA1(pa) (((uint32_t)(pa)) | 0xA0000000u) + +/* Pointer helper: uncached view of a normally-allocated object */ +#define PIC32_UNCACHED(p) ((void *)PIC32_KVA0_TO_KVA1(p)) + +#endif /* PIC32MZ_CACHE_H */ diff --git a/src/port/pic32mz/clock_init.c b/src/port/pic32mz/clock_init.c new file mode 100644 index 00000000..4a5e32c8 --- /dev/null +++ b/src/port/pic32mz/clock_init.c @@ -0,0 +1,37 @@ +/* clock_init.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 "clock_init.h" + +void clock_init(void) +{ + /* Flash wait-states + prefetch for 200 MHz SYSCLK. + * PFMWS = 2 wait-states is required above ~134 MHz on PIC32MZ EF. + * PREFEN = 3 enables predictive prefetch for cacheable and + * non-cacheable regions. PRECON is not lock-protected. */ + PRECONbits.PFMWS = 2; + PRECONbits.PREFEN = 3; + + /* Peripheral buses PBCLK2 (UART) and PBCLK5 (EMAC) remain at their + * reset default of SYSCLK/2 = 100 MHz, which is what this port targets. + * The L1 cache and KSEG0 coherency are enabled by the XC32 reset + * startup code, so nothing is done here for v1. */ +} diff --git a/src/port/pic32mz/clock_init.h b/src/port/pic32mz/clock_init.h new file mode 100644 index 00000000..3e26aa61 --- /dev/null +++ b/src/port/pic32mz/clock_init.h @@ -0,0 +1,30 @@ +/* clock_init.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 PIC32MZ_CLOCK_INIT_H +#define PIC32MZ_CLOCK_INIT_H + +/* Configure flash wait-states / prefetch for 200 MHz operation. + * The PLL itself is brought up at reset from the DEVCFG config words + * (FNOSC=SPLL), so by the time main() runs SYSCLK is already 200 MHz. + * Bare-metal reusable (intended to be lifted into a future wolfBoot port). */ +void clock_init(void); + +#endif /* PIC32MZ_CLOCK_INIT_H */ diff --git a/src/port/pic32mz/device_config.c b/src/port/pic32mz/device_config.c new file mode 100644 index 00000000..b0c4a4d2 --- /dev/null +++ b/src/port/pic32mz/device_config.c @@ -0,0 +1,89 @@ +/* device_config.c + * + * PIC32MZ2048EFM144 device configuration words (DEVCFG0-3). + * + * 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 + */ + +/* Config-word settings for the PIC32MZ EF Starter Kit (DM320007). + * + * Clock: POSC = 24 MHz external clock (EC). SPLL multiplies to 200 MHz SYSCLK: + * 24 MHz / FPLLIDIV(3) = 8 MHz -> FPLLMULT(50) = 400 MHz -> FPLLODIV(2) = 200 MHz. + * Peripheral buses default to SYSCLK/2 = 100 MHz (PBCLK2 UART, PBCLK5 EMAC). + * + * Values mirror the known-good Harmony-derived settings in + * wolfssl/mplabx/PIC32MZ-serial.h, EXCEPT FMIIEN is OFF here: this port drives + * the LAN8740 PHY daughter board over RMII, not MII. + */ + +/*** DEVCFG0 ***/ +#pragma config DEBUG = OFF +#pragma config JTAGEN = OFF +#pragma config ICESEL = ICS_PGx2 +#pragma config TRCEN = OFF +#pragma config BOOTISA = MIPS32 +#pragma config FECCCON = OFF_UNLOCKED +#pragma config FSLEEP = OFF +#pragma config DBGPER = PG_ALL +#pragma config SMCLR = MCLR_NORM +#pragma config SOSCGAIN = GAIN_2X +#pragma config SOSCBOOST = ON +#pragma config POSCGAIN = GAIN_2X +#pragma config POSCBOOST = ON +#pragma config EJTAGBEN = NORMAL +#pragma config CP = OFF + +/*** DEVCFG1 ***/ +#pragma config FNOSC = SPLL +#pragma config DMTINTV = WIN_127_128 +#pragma config FSOSCEN = OFF +#pragma config IESO = OFF +#pragma config POSCMOD = EC +#pragma config OSCIOFNC = OFF +#pragma config FCKSM = CSECME +#pragma config WDTPS = PS1048576 +#pragma config WDTSPGM = STOP +#pragma config FWDTEN = OFF +#pragma config WINDIS = NORMAL +#pragma config FWDTWINSZ = WINSZ_25 +#pragma config DMTCNT = DMT31 +#pragma config FDMTEN = OFF + +/*** DEVCFG2 ***/ +#pragma config FPLLIDIV = DIV_3 +#pragma config FPLLRNG = RANGE_5_10_MHZ +#pragma config FPLLICLK = PLL_POSC +#pragma config FPLLMULT = MUL_50 +#pragma config FPLLODIV = DIV_2 +#pragma config UPLLFSEL = FREQ_24MHZ + +/*** DEVCFG3 ***/ +#pragma config USERID = 0xffff +#pragma config FMIIEN = OFF /* RMII (LAN8740 PHY daughter board) */ +#pragma config FETHIO = ON /* default Ethernet I/O pin set */ +#pragma config PGL1WAY = ON +#pragma config PMDL1WAY = ON +#pragma config IOL1WAY = ON +#pragma config FUSBIDIO = ON + +/*** BF1SEQ0 ***/ +#pragma config TSEQ = 0x0000 +#pragma config CSEQ = 0xffff + +#include diff --git a/src/port/pic32mz/main.c b/src/port/pic32mz/main.c new file mode 100644 index 00000000..e3cc3d9d --- /dev/null +++ b/src/port/pic32mz/main.c @@ -0,0 +1,126 @@ +/* main.c + * + * wolfIP PIC32MZ EF port bring-up. + * Phase 0: clocks + UART + heartbeat. + * Phase 1: wolfCrypt PIC32MZ hardware TRNG self-test. + * Phase 2: MDIO + LAN8740 PHY link bring-up. + * + * 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 "board.h" +#include "clock_init.h" +#include "uart_console.h" +#include "timebase.h" +#include "rng_selftest.h" +#include "pic32mz_eth.h" +#include "phy_lan8740.h" + +int main(void) +{ + uint64_t next; + uint64_t now; + uint32_t tick; + struct phy_link link; + int phy_ret; + int rng_ret; + + clock_init(); + uart_init(); + + /* LEDs on PORTH: digital outputs, start off. */ + ANSELHCLR = LED_MASK; + TRISHCLR = LED_MASK; + LATHCLR = LED_MASK; + + printf("\r\n=== wolfIP PIC32MZ EF port ===\r\n"); + printf("Device : PIC32MZ2048EFM144\r\n"); + printf("SYSCLK : %lu Hz, PBCLK2 : %lu Hz\r\n", + (unsigned long)SYS_CLK_FREQ, (unsigned long)PBCLK2_FREQ); + printf("Build : %s %s\r\n", __DATE__, __TIME__); + + /* Prove the timebase is live before anything that could block, so a TRNG + * hang (Phase 1) is still distinguishable from a clock/UART fault. */ + printf("Phase 0: clocks + UART OK, timebase ms=%lu\r\n", + (unsigned long)millis()); + + /* Phase 1: hardware TRNG self-test. */ + rng_ret = rng_selftest(); + + /* Phase 2: MDIO + LAN8740 PHY link bring-up. + * A EMAC-register bus stall here can wedge the ICSP debugger, so pause + * first in a benign spin: this guarantees a window each boot where the + * programmer can connect (device runs no risky peripheral code). */ + printf("\r\n[PHY] reflash window: pausing 3s before EMAC init...\r\n"); + delay_ms(3000); + + printf("[PHY] step1: emac_mii_init\r\n"); + pic32mz_emac_mii_init(); + printf("[PHY] step2: emac_mii_init returned; PHY bring-up\r\n"); + phy_ret = phy_lan8740_bringup(pic32mz_mdio_read, pic32mz_mdio_write, + 5000u, &link); + if (link.found) + printf("[PHY] found at addr %u, ID1=0x%04X ID2=0x%04X\r\n", + (unsigned)link.addr, (unsigned)link.id1, (unsigned)link.id2); + else + printf("[PHY] no PHY found on MDIO bus (ID=0xFFFF)\r\n"); + if (phy_ret == 0) + printf("[PHY] link UP: %s %s\r\n", + link.speed_100 ? "100M" : "10M", + link.full_duplex ? "Full" : "Half"); + else + printf("[PHY] link DOWN / autoneg timeout (check cable)\r\n"); + + printf("Phase done: entering heartbeat loop\r\n"); + + next = 0; + tick = 0; + for (;;) { + now = millis(); + if (now >= next) { + next = now + 1000; + tick++; + LATHINV = LED_HEARTBEAT; /* toggle LED1 */ + /* Re-print the phase results every 10 s. The console UART (an + * MCP2221 bridge) drops out intermittently and misses the one-shot + * boot banner, so this periodic summary makes the results + * observable whenever the log reconnects. */ + if ((tick % 10u) == 1u) { + printf("[STATUS] tick=%lu RNG=%s PHY=%s ID1=0x%04X link=%s", + (unsigned long)tick, + (rng_ret == 0) ? "PASS" : "FAIL", + link.found ? "found" : "none", + (unsigned)link.id1, + (phy_ret == 0) ? "UP" : "down"); + if (phy_ret == 0) + printf(" %s/%s", + link.speed_100 ? "100M" : "10M", + link.full_duplex ? "FD" : "HD"); + printf("\r\n"); + } + else { + printf("tick=%lu ms=%lu\r\n", + (unsigned long)tick, (unsigned long)now); + } + } + } + /* not reached */ +} diff --git a/src/port/pic32mz/phy_lan8740.c b/src/port/pic32mz/phy_lan8740.c new file mode 100644 index 00000000..4ab88e67 --- /dev/null +++ b/src/port/pic32mz/phy_lan8740.c @@ -0,0 +1,181 @@ +/* phy_lan8740.c + * + * Microchip LAN8740 (clause-22 MDIO) PHY driver for the PIC32MZ wolfIP port. + * + * 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 "phy_lan8740.h" +#include "timebase.h" + +#ifdef PIC32_ETH_TRACE +#include +#define PHY_TRACE(s) do { printf("[PHY] " s "\r\n"); } while (0) +#else +#define PHY_TRACE(s) do { } while (0) +#endif + +/* Standard clause-22 register addresses. */ +#define REG_BMCR 0x00 /* Basic control */ +#define REG_BMSR 0x01 /* Basic status */ +#define REG_PHYID1 0x02 +#define REG_PHYID2 0x03 +#define REG_ANAR 0x04 /* Auto-neg advertisement */ +#define REG_SCSR 0x1F /* LAN8740 Special Control/Status */ + +#define BMCR_RESET 0x8000 +#define BMCR_ANEN 0x1000 +#define BMCR_ANRESTART 0x0200 + +#define BMSR_ANCOMPLETE 0x0020 +#define BMSR_LINK 0x0004 + +/* Advertise 100/10 full and half duplex, IEEE 802.3 selector. */ +#define ANAR_DEFAULT 0x01E1 + +/* LAN8740 OUI high word. */ +#define LAN8740_ID1 0x0007 + +/* SCSR autonegotiation-done and resolved speed/duplex (HCDSPEED, bits [4:2]). */ +#define SCSR_AUTODONE 0x1000 +#define SCSR_SPD_MASK 0x001C +#define SCSR_SPD_10HD 0x0004 +#define SCSR_SPD_100HD 0x0008 +#define SCSR_SPD_10FD 0x0014 +#define SCSR_SPD_100FD 0x0018 + +static int phy_scan(mdio_read_fn rd, struct phy_link *out) +{ + uint16_t id1; + uint16_t id2; + int addr; + int candidate; + + candidate = -1; + for (addr = 0; addr < 32; addr++) { + if (rd((uint8_t)addr, REG_PHYID1, &id1) != 0) + continue; + if (id1 == 0xFFFF || id1 == 0x0000) + continue; + if (rd((uint8_t)addr, REG_PHYID2, &id2) != 0) + continue; + /* Prefer a LAN8740, but remember any responding PHY as a fallback. */ + if (id1 == LAN8740_ID1) { + out->found = 1; + out->addr = (uint8_t)addr; + out->id1 = id1; + out->id2 = id2; + return 0; + } + if (candidate < 0) { + candidate = addr; + out->id1 = id1; + out->id2 = id2; + } + } + + if (candidate >= 0) { + out->found = 1; + out->addr = (uint8_t)candidate; + return 0; + } + return -1; +} + +int phy_lan8740_bringup(mdio_read_fn rd, mdio_write_fn wr, + uint32_t link_up_timeout_ms, struct phy_link *out) +{ + uint16_t reg; + uint16_t spd; + uint32_t deadline; + + if (rd == NULL || wr == NULL || out == NULL) + return -1; + + out->found = 0; + out->addr = 0; + out->id1 = 0; + out->id2 = 0; + out->link_up = 0; + out->speed_100 = 0; + out->full_duplex = 0; + + PHY_TRACE("scan: reading PHY IDs over MDIO"); + if (phy_scan(rd, out) != 0) { + PHY_TRACE("scan: no PHY responded"); + return -1; + } + PHY_TRACE("scan: PHY found, resetting"); + + /* Software reset and wait for it to self-clear. */ + if (wr(out->addr, REG_BMCR, BMCR_RESET) != 0) + return -1; + deadline = (uint32_t)millis() + 1000u; + do { + if (rd(out->addr, REG_BMCR, ®) != 0) + return -1; + } while ((reg & BMCR_RESET) && ((uint32_t)millis() < deadline)); + if (reg & BMCR_RESET) + return -1; + + /* Advertise all speeds/duplex and restart auto-negotiation. */ + if (wr(out->addr, REG_ANAR, ANAR_DEFAULT) != 0) + return -1; + if (wr(out->addr, REG_BMCR, BMCR_ANEN | BMCR_ANRESTART) != 0) + return -1; + + /* Wait for link. BMSR latches link-low, so read it twice. */ + deadline = (uint32_t)millis() + link_up_timeout_ms; + for (;;) { + if (rd(out->addr, REG_BMSR, ®) != 0) + return -1; + if (rd(out->addr, REG_BMSR, ®) != 0) + return -1; + if (reg & BMSR_LINK) + break; + if ((uint32_t)millis() >= deadline) + return -1; + } + out->link_up = 1; + + /* Resolved speed/duplex from the LAN8740 Special Control/Status reg. */ + if (rd(out->addr, REG_SCSR, &spd) != 0) + return -1; + switch (spd & SCSR_SPD_MASK) { + case SCSR_SPD_100FD: + out->speed_100 = 1; + out->full_duplex = 1; + break; + case SCSR_SPD_100HD: + out->speed_100 = 1; + out->full_duplex = 0; + break; + case SCSR_SPD_10FD: + out->speed_100 = 0; + out->full_duplex = 1; + break; + case SCSR_SPD_10HD: + default: + out->speed_100 = 0; + out->full_duplex = 0; + break; + } + + return 0; +} diff --git a/src/port/pic32mz/phy_lan8740.h b/src/port/pic32mz/phy_lan8740.h new file mode 100644 index 00000000..83292bfe --- /dev/null +++ b/src/port/pic32mz/phy_lan8740.h @@ -0,0 +1,48 @@ +/* phy_lan8740.h + * + * Microchip LAN8740 (clause-22 MDIO) PHY driver for the PIC32MZ wolfIP port. + * + * 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 PHY_LAN8740_H +#define PHY_LAN8740_H + +#include + +/* MDIO accessors supplied by the MAC driver (see pic32mz_eth.h). */ +typedef int (*mdio_read_fn)(uint8_t phy_addr, uint8_t reg, uint16_t *val); +typedef int (*mdio_write_fn)(uint8_t phy_addr, uint8_t reg, uint16_t val); + +struct phy_link { + uint8_t found; /* 1 if a PHY responded on the bus */ + uint8_t addr; /* MDIO address of the PHY */ + uint16_t id1; /* PHYID1 (LAN8740 OUI high = 0x0007) */ + uint16_t id2; /* PHYID2 */ + uint8_t link_up; /* 1 if link is up */ + uint8_t speed_100; /* 1 = 100 Mbps, 0 = 10 Mbps */ + uint8_t full_duplex; /* 1 = full duplex, 0 = half */ +}; + +/* Scan for the PHY, reset it, advertise all modes, run auto-negotiation and + * wait for link. Fills *out. Returns 0 on link up, negative on error/timeout. + * link_up_timeout_ms bounds the link wait. */ +int phy_lan8740_bringup(mdio_read_fn rd, mdio_write_fn wr, + uint32_t link_up_timeout_ms, struct phy_link *out); + +#endif /* PHY_LAN8740_H */ diff --git a/src/port/pic32mz/pic32mz_eth.c b/src/port/pic32mz/pic32mz_eth.c new file mode 100644 index 00000000..19539c91 --- /dev/null +++ b/src/port/pic32mz/pic32mz_eth.c @@ -0,0 +1,170 @@ +/* pic32mz_eth.c + * + * PIC32MZ Ethernet controller (EMAC) driver for wolfIP. + * + * 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 "pic32mz_eth.h" + +/* Bring-up tracing: build with EXTRA_CFLAGS=-DPIC32_ETH_TRACE to emit a marker + * before each EMAC register-access group. If the console stops after a given + * marker, the following register access is stalling the CPU bus (typically a + * disabled/unclocked module). */ +#ifdef PIC32_ETH_TRACE +#include +#define ETH_TRACE(s) do { printf("[EMAC] " s "\r\n"); } while (0) +#else +#define ETH_TRACE(s) do { } while (0) +#endif + +/* MII management clock divisor (EMAC1MCFG.CLKSEL). + * 0b1010 = host clock / 50. At SYSCLK = 200 MHz this gives MDC ~= 4 MHz, the + * lowest the divider offers; LAN8740 tolerates it. */ +#define MII_CLKSEL_DIV50 0x0Au + +/* Bounded spin used to wait for MII management to finish a transfer. */ +#define MII_TIMEOUT 1000000u + +static void short_delay(void) +{ + volatile int i; + + /* The MIIMBUSY flag takes a few host-clock cycles to assert after a + * command is issued; give it time before polling. */ + for (i = 0; i < 64; i++) { + } +} + +void pic32mz_emac_mii_init(void) +{ + volatile int i; + uint32_t timeout; + + /* The Ethernet module is clocked by PBCLK5 and gated by PMD6.ETHMD. If + * PBCLK5 is off or the module is PMD-disabled, the first ETH/EMAC register + * access stalls the CPU bus forever (and wedges the ICSP debugger). Enable + * both before touching any EMAC register. These are behind the system + * unlock (SYSKEY); PMDLOCK is left unlocked afterwards to avoid the + * PMDL1WAY one-way trap. */ + ETH_TRACE("z0: enable PBCLK5"); + if (PB5DIVbits.ON == 0) { + SYSKEY = 0x00000000; + SYSKEY = 0xAA996655; + SYSKEY = 0x556699AA; + PB5DIVbits.ON = 1; + SYSKEY = 0x33333333; + } + ETH_TRACE("z1: enable ETH module (PMD6.ETHMD=0)"); + if (PMD6bits.ETHMD != 0) { + SYSKEY = 0x00000000; + SYSKEY = 0xAA996655; + SYSKEY = 0x556699AA; + CFGCONbits.PMDLOCK = 0; + PMD6bits.ETHMD = 0; + SYSKEY = 0x33333333; + } + + /* Disable the Ethernet controller and wait for it to go idle. + * If marker "a" prints but "b" never does, the ETHCON1 access below is + * still stalling (module clock/enable issue). */ + ETH_TRACE("a: ETHCON1 off"); + ETHCON1CLR = _ETHCON1_ON_MASK; + timeout = MII_TIMEOUT; + while ((ETHSTAT & _ETHSTAT_ETHBUSY_MASK) && (timeout != 0)) + timeout--; + + /* Enable the module (required to access the EMAC1 register block). */ + ETH_TRACE("b: ETHCON1 on"); + ETHCON1CLR = _ETHCON1_TXRTS_MASK | _ETHCON1_RXEN_MASK; + ETHCON1SET = _ETHCON1_ON_MASK; + + /* Reset the MAC: assert all soft resets, then release. */ + ETH_TRACE("c: EMAC1CFG1 reset"); + EMAC1CFG1 = _EMAC1CFG1_SOFTRESET_MASK | _EMAC1CFG1_SIMRESET_MASK | + _EMAC1CFG1_RESETRMCS_MASK | _EMAC1CFG1_RESETRFUN_MASK | + _EMAC1CFG1_RESETTMCS_MASK | _EMAC1CFG1_RESETTFUN_MASK; + for (i = 0; i < 1000; i++) { + } + EMAC1CFG1 = 0; + + /* Reset the RMII logic. */ + ETH_TRACE("d: EMAC1SUPP RMII reset"); + EMAC1SUPPSET = _EMAC1SUPP_RESETRMII_MASK; + for (i = 0; i < 1000; i++) { + } + EMAC1SUPPCLR = _EMAC1SUPP_RESETRMII_MASK; + + /* Reset MII management, then set the MDC clock divisor. */ + ETH_TRACE("e: EMAC1MCFG"); + EMAC1MCFGSET = _EMAC1MCFG_RESETMGMT_MASK; + for (i = 0; i < 100; i++) { + } + EMAC1MCFGCLR = _EMAC1MCFG_RESETMGMT_MASK; + EMAC1MCFGbits.CLKSEL = MII_CLKSEL_DIV50; + ETH_TRACE("f: mii init done"); +} + +int pic32mz_mdio_read(uint8_t phy_addr, uint8_t reg, uint16_t *val) +{ + uint32_t timeout; + + if (val == NULL) + return -1; + + EMAC1MADR = ((uint32_t)phy_addr << _EMAC1MADR_PHYADDR_POSITION) | + ((uint32_t)reg << _EMAC1MADR_REGADDR_POSITION); + + /* Issue a single read command. */ + EMAC1MCMDSET = _EMAC1MCMD_READ_MASK; + short_delay(); + + timeout = MII_TIMEOUT; + while ((EMAC1MIND & _EMAC1MIND_MIIMBUSY_MASK) && (timeout != 0)) + timeout--; + + EMAC1MCMDCLR = _EMAC1MCMD_READ_MASK; + + if (timeout == 0) + return -1; + + *val = (uint16_t)(EMAC1MRDD & _EMAC1MRDD_MRDD_MASK); + return 0; +} + +int pic32mz_mdio_write(uint8_t phy_addr, uint8_t reg, uint16_t val) +{ + uint32_t timeout; + + EMAC1MADR = ((uint32_t)phy_addr << _EMAC1MADR_PHYADDR_POSITION) | + ((uint32_t)reg << _EMAC1MADR_REGADDR_POSITION); + + /* Writing the data register initiates the management write. */ + EMAC1MWTD = (uint32_t)val; + short_delay(); + + timeout = MII_TIMEOUT; + while ((EMAC1MIND & _EMAC1MIND_MIIMBUSY_MASK) && (timeout != 0)) + timeout--; + + if (timeout == 0) + return -1; + return 0; +} diff --git a/src/port/pic32mz/pic32mz_eth.h b/src/port/pic32mz/pic32mz_eth.h new file mode 100644 index 00000000..88390bf5 --- /dev/null +++ b/src/port/pic32mz/pic32mz_eth.h @@ -0,0 +1,38 @@ +/* pic32mz_eth.h + * + * PIC32MZ Ethernet controller (EMAC) driver for wolfIP. + * + * 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 PIC32MZ_ETH_H +#define PIC32MZ_ETH_H + +#include + +/* Phase 2: bring the Ethernet module, RMII and MII-management block out of + * reset and program the MDC clock divisor. Must be called before any MDIO + * access. */ +void pic32mz_emac_mii_init(void); + +/* Clause-22 MDIO primitives. Return 0 on success, negative on timeout. + * Signatures match the mdio_read_fn / mdio_write_fn types in phy_lan8740.h. */ +int pic32mz_mdio_read(uint8_t phy_addr, uint8_t reg, uint16_t *val); +int pic32mz_mdio_write(uint8_t phy_addr, uint8_t reg, uint16_t val); + +#endif /* PIC32MZ_ETH_H */ diff --git a/src/port/pic32mz/rng_selftest.c b/src/port/pic32mz/rng_selftest.c new file mode 100644 index 00000000..2c365e1a --- /dev/null +++ b/src/port/pic32mz/rng_selftest.c @@ -0,0 +1,103 @@ +/* rng_selftest.c + * + * Standalone wolfCrypt RNG self-test for the PIC32MZ EF hardware TRNG. + * + * 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 "rng_selftest.h" + +#define RNG_BLOCK_LEN 32 + +static void print_hex(const char *label, const unsigned char *p, int n) +{ + int i; + + printf("%s", label); + for (i = 0; i < n; i++) + printf("%02X", p[i]); + printf("\r\n"); +} + +int rng_selftest(void) +{ + WC_RNG rng; + unsigned char a[RNG_BLOCK_LEN]; + unsigned char b[RNG_BLOCK_LEN]; + int ret; + int i; + int all_zero; + int all_ff; + int identical; + + printf("\r\n[RNG] WOLFSSL_PIC32MZ_RNG hardware TRNG self-test\r\n"); + + ret = wc_InitRng(&rng); + if (ret != 0) { + printf("[RNG] wc_InitRng failed: %d (%s)\r\n", + ret, wc_GetErrorString(ret)); + return -1; + } + + ret = wc_RNG_GenerateBlock(&rng, a, sizeof(a)); + if (ret != 0) { + printf("[RNG] GenerateBlock A failed: %d (%s)\r\n", + ret, wc_GetErrorString(ret)); + (void)wc_FreeRng(&rng); + return -1; + } + + ret = wc_RNG_GenerateBlock(&rng, b, sizeof(b)); + if (ret != 0) { + printf("[RNG] GenerateBlock B failed: %d (%s)\r\n", + ret, wc_GetErrorString(ret)); + (void)wc_FreeRng(&rng); + return -1; + } + + (void)wc_FreeRng(&rng); + + print_hex("[RNG] block A: ", a, RNG_BLOCK_LEN); + print_hex("[RNG] block B: ", b, RNG_BLOCK_LEN); + + /* Coarse sanity checks: blocks must not be trivial or identical. */ + all_zero = 1; + all_ff = 1; + identical = 1; + for (i = 0; i < RNG_BLOCK_LEN; i++) { + if (a[i] != 0x00) + all_zero = 0; + if (a[i] != 0xFF) + all_ff = 0; + if (a[i] != b[i]) + identical = 0; + } + + if (all_zero || all_ff || identical) { + printf("[RNG] self-test: FAIL (all_zero=%d all_ff=%d identical=%d)\r\n", + all_zero, all_ff, identical); + return -1; + } + + printf("[RNG] self-test: PASS\r\n"); + return 0; +} diff --git a/src/port/pic32mz/rng_selftest.h b/src/port/pic32mz/rng_selftest.h new file mode 100644 index 00000000..8ed3afb0 --- /dev/null +++ b/src/port/pic32mz/rng_selftest.h @@ -0,0 +1,29 @@ +/* rng_selftest.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 PIC32MZ_RNG_SELFTEST_H +#define PIC32MZ_RNG_SELFTEST_H + +/* Exercise wolfCrypt's WOLFSSL_PIC32MZ_RNG hardware TRNG path: seed a DRBG, + * generate two blocks, and sanity-check the output. Prints results over the + * console UART. Returns 0 on pass, negative on failure. */ +int rng_selftest(void); + +#endif /* PIC32MZ_RNG_SELFTEST_H */ diff --git a/src/port/pic32mz/timebase.c b/src/port/pic32mz/timebase.c new file mode 100644 index 00000000..07efab28 --- /dev/null +++ b/src/port/pic32mz/timebase.c @@ -0,0 +1,58 @@ +/* timebase.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 "timebase.h" +#include "board.h" + +/* The CP0 Count register increments at SYSCLK/2. It is 32-bit and wraps + * roughly every 42 s at 100 MHz, so it is extended to 64 bits by tracking + * wraps. millis() must be polled at least once per wrap period; the wolfIP + * main loop calls it continuously, so this is trivially satisfied. + * Single-threaded; not interrupt-safe. */ +#define COUNT_HZ (SYS_CLK_FREQ / 2u) +#define COUNT_PER_MS (COUNT_HZ / 1000u) + +static uint32_t s_last_count; +static uint64_t s_accum; + +static uint64_t cp0_count64(void) +{ + uint32_t c = _CP0_GET_COUNT(); + + if (c < s_last_count) + s_accum += 0x100000000ull; + s_last_count = c; + return s_accum + (uint64_t)c; +} + +uint64_t millis(void) +{ + return cp0_count64() / COUNT_PER_MS; +} + +void delay_ms(uint32_t ms) +{ + uint64_t target = millis() + (uint64_t)ms; + + while (millis() < target) { + /* busy wait */ + } +} diff --git a/src/port/pic32mz/timebase.h b/src/port/pic32mz/timebase.h new file mode 100644 index 00000000..e26a53f7 --- /dev/null +++ b/src/port/pic32mz/timebase.h @@ -0,0 +1,31 @@ +/* timebase.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 PIC32MZ_TIMEBASE_H +#define PIC32MZ_TIMEBASE_H + +#include + +/* Free-running millisecond counter derived from the CP0 Count register. + * This is the time source passed to wolfIP_poll(). */ +uint64_t millis(void); +void delay_ms(uint32_t ms); + +#endif /* PIC32MZ_TIMEBASE_H */ diff --git a/src/port/pic32mz/uart_console.c b/src/port/pic32mz/uart_console.c new file mode 100644 index 00000000..3dca0942 --- /dev/null +++ b/src/port/pic32mz/uart_console.c @@ -0,0 +1,84 @@ +/* uart_console.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 "uart_console.h" +#include "board.h" + +/* BRGH = 0 -> 16x oversampling. BRG = PBCLK2 / (16 * baud) - 1. */ +#define UART_BRG ((PBCLK2_FREQ / (16u * CONSOLE_BAUD)) - 1u) + +void uart_init(void) +{ + /* Make the two pins digital and set direction. */ + ANSELBCLR = (1u << 14); /* RB14 digital */ + ANSELGCLR = (1u << 6); /* RG6 digital */ + TRISBCLR = (1u << 14); /* RB14 output (U2TX) */ + TRISGSET = (1u << 6); /* RG6 input (U2RX) */ + + /* Peripheral Pin Select: RPB14 -> U2TX, U2RX <- RPG6. */ + RPB14R = 0x02; /* output function 2 = U2TX */ + U2RXR = 0x01; /* input selection 1 = RPG6 */ + + U2BRG = (uint32_t)UART_BRG; + U2STA = 0; + U2MODE = (1u << 15); /* ON, 8N1, BRGH=0, no flow control */ + U2STAbits.URXEN = 1; + U2STAbits.UTXEN = 1; +} + +void uart_putc(char c) +{ + while (U2STAbits.UTXBF) { + /* wait for room in the TX FIFO */ + } + U2TXREG = (uint8_t)c; +} + +void uart_write(const char *buf, unsigned int len) +{ + unsigned int i; + + if (buf == NULL) + return; + for (i = 0; i < len; i++) + uart_putc(buf[i]); +} + +int uart_rx_ready(void) +{ + return (int)U2STAbits.URXDA; +} + +int uart_getc(void) +{ + if (U2STAbits.URXDA == 0) + return -1; + return (int)(U2RXREG & 0xFF); +} + +/* XC32 retargets stdout (printf) through _mon_putc(). Map LF -> CRLF. */ +void _mon_putc(char c) +{ + if (c == '\n') + uart_putc('\r'); + uart_putc(c); +} diff --git a/src/port/pic32mz/uart_console.h b/src/port/pic32mz/uart_console.h new file mode 100644 index 00000000..1f668b1f --- /dev/null +++ b/src/port/pic32mz/uart_console.h @@ -0,0 +1,33 @@ +/* uart_console.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 PIC32MZ_UART_CONSOLE_H +#define PIC32MZ_UART_CONSOLE_H + +/* UART2 on RPB14 (U2TX) / RPG6 (U2RX) at 115200 8N1, via the external + * MCP2221 USB-UART bridge. Also retargets XC32 stdout (printf) to this UART + * through _mon_putc(). */ +void uart_init(void); +void uart_putc(char c); +void uart_write(const char *buf, unsigned int len); +int uart_rx_ready(void); +int uart_getc(void); /* returns byte, or -1 if none available */ + +#endif /* PIC32MZ_UART_CONSOLE_H */ diff --git a/src/port/pic32mz/user_settings.h b/src/port/pic32mz/user_settings.h new file mode 100644 index 00000000..154c0e5c --- /dev/null +++ b/src/port/pic32mz/user_settings.h @@ -0,0 +1,75 @@ +/* user_settings.h + * + * wolfCrypt configuration for the wolfIP PIC32MZ EF port. + * + * 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 WOLFSSL_USER_SETTINGS_H +#define WOLFSSL_USER_SETTINGS_H + +#ifdef __cplusplus +extern "C" { +#endif + +#include /* for size_t */ + +/* ---- Platform -------------------------------------------------------- */ +#define WOLFSSL_GENERAL_ALIGNMENT 4 +#define SINGLE_THREADED +#define WOLFSSL_SMALL_STACK + +#define MICROCHIP_PIC32 +#define WOLFSSL_MICROCHIP_PIC32MZ /* auto-enables WOLFSSL_PIC32MZ_RNG */ + +/* This milestone exercises ONLY the hardware TRNG. Keep the PIC32MZ crypto + * engine (AES/hash acceleration) disabled so SHA-256 (used by the Hash-DRBG) + * runs in software and we don't need the pic32mz-crypt.c engine driver yet. */ +#define NO_PIC32MZ_CRYPT +#define NO_PIC32MZ_HASH + +/* ---- RNG ------------------------------------------------------------- */ +#define HAVE_HASHDRBG /* SHA-256 based DRBG seeded by the TRNG */ + +/* ---- Trim algorithms not needed for the RNG self-test ---------------- */ +#define NO_RSA +#define NO_DH +#define NO_DSA +#define NO_AES +#define NO_DES3 +#define NO_RC4 +#define NO_MD4 +#define NO_MD5 +#define NO_SHA /* SHA-1 not needed; SHA-256 stays on */ +#define NO_PWDBASED +#define NO_PSK +#define NO_OLD_TLS + +/* ---- Environment ----------------------------------------------------- */ +#define NO_FILESYSTEM +#define NO_WRITEV +#define NO_MAIN_DRIVER +#define NO_DEV_RANDOM /* no /dev/random on bare metal */ +#define NO_ASN_TIME /* no RTC */ +#define WOLFSSL_NO_SOCK + +#ifdef __cplusplus +} +#endif + +#endif /* WOLFSSL_USER_SETTINGS_H */ diff --git a/src/port/pic32mz/wolf_compat.c b/src/port/pic32mz/wolf_compat.c new file mode 100644 index 00000000..727c481b --- /dev/null +++ b/src/port/pic32mz/wolf_compat.c @@ -0,0 +1,40 @@ +/* wolf_compat.c + * + * Small wolfCrypt compatibility shims for the bare-metal PIC32MZ port. + * + * 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 + */ + +/* The WOLFSSL_MICROCHIP_PIC32MZ settings block defines WOLFSSL_HAVE_MIN / + * WOLFSSL_HAVE_MAX, which tells wolfcrypt/src/misc.c NOT to define min()/max() + * because the Microchip Harmony / TCP-IP framework normally provides them. + * This bare-metal port does not use that framework, so provide them here. + * Signatures match the wolfcrypt/wolfcrypt/misc.h prototypes. */ +#include +#include + +word32 min(word32 a, word32 b) +{ + return (a < b) ? a : b; +} + +word32 max(word32 a, word32 b) +{ + return (a > b) ? a : b; +}