|
| 1 | +# wolfIP port: Pi Pico 2 W (RP2350 + CYW43439) |
| 2 | + |
| 3 | +Bare-metal wolfIP port for the [Raspberry Pi Pico 2 W](https://www.raspberrypi.com/products/raspberry-pi-pico-2/) board (RP2350 dual-arch SoC + Infineon CYW43439 Wi-Fi radio). |
| 4 | + |
| 5 | +## Highlights |
| 6 | + |
| 7 | +- **Dual-arch build**. `make CORE=m33` for Cortex-M33, `make CORE=hazard3` for Hazard3 RISC-V. Same wolfIP + supplicant source, different toolchain and entry stub. |
| 8 | +- **Firmware-loader-only CYW43439 driver**. Clean-room gSPI transport + SDPCM/CDC/BDC ioctl shim. No `cyw43-driver`, no WHD source reuse. The Infineon firmware blob is loaded into the radio's RAM at boot and is the only binary artifact carried over. |
| 9 | +- **wolfIP supplicant runs in host RAM**. All of WPA2-PSK 4-way, EAP-TLS (optional), WPA3-SAE (optional, software) is the in-tree `src/supplicant/`. The CYW43439 firmware does 802.11 mgmt (scan, auth-open, assoc) and never sees the PSK. |
| 10 | + |
| 11 | +## Status |
| 12 | + |
| 13 | +| Milestone | State | |
| 14 | +|-----------------------------------|-------| |
| 15 | +| Scaffolding (linker, startup) | done | |
| 16 | +| Boot + clocks + UART console | done, hardware-proven | |
| 17 | +| gSPI/PIO transport + 32-bit mode | done, hardware-proven | |
| 18 | +| Backplane + ALP + firmware load | done, hardware-proven (firmware RUNNING) | |
| 19 | +| SDPCM/CDC ioctl control plane | done, hardware-proven (WLC_UP + STA MAC read) | |
| 20 | +| Join + event-driven assoc state | done, hardware-proven (`cyw43_connect` associates to a real AP; `cyw43_poll` decodes `WLC_E_LINK` up/down) | |
| 21 | +| BDC EAPOL/802.3 TX-RX + `set_key` | **written, not yet validated on silicon** (needs the 4-way to drive them) | |
| 22 | +| `wolfIP_wifi_ops` impl | done (scan still a stub) | |
| 23 | +| Host supplicant 4-way integration | written behind `WOLFIP_WITH_SUPPLICANT` (needs cross-built wolfSSL) | |
| 24 | +| WPA2-PSK 4-way + UDP echo on real AP | pending wolfSSL-linked build | |
| 25 | + |
| 26 | +The control plane (boot -> firmware -> ioctl) and the **join + event path** are proven on a real Pico 2 W: the radio associates to a WPA2 AP and `cyw43_poll` reports `assoc: UP`/`down` from the decoded events. Still unexercised: the BDC EAPOL data path and `cyw43_set_key`, which only run once the 4-way handshake drives them - that needs the wolfIP supplicant linked in (`WOLFIP_WITH_SUPPLICANT`). See "Open items" below. |
| 27 | + |
| 28 | +Hardware validation runs against a real AP on the desk - hwsim does not validate this port (see `tools/hostapd/README.md` for the FullMAC limitation). |
| 29 | + |
| 30 | +## Build |
| 31 | + |
| 32 | +Requires: |
| 33 | + |
| 34 | +- `arm-none-eabi-gcc` (M33 path) and/or `riscv32-unknown-elf-gcc` (Hazard3 path) |
| 35 | +- `picotool` on PATH (for UF2 conversion + flash) |
| 36 | +- A wolfSSL install with `WOLFSSL_PUBLIC_MP` if you enable SAE |
| 37 | + |
| 38 | +```sh |
| 39 | +# Cortex-M33 build (default) |
| 40 | +make |
| 41 | + |
| 42 | +# Hazard3 RISC-V build |
| 43 | +make CORE=hazard3 |
| 44 | + |
| 45 | +# Override the SSID / PSK baked into the binary |
| 46 | +make WIFI_SSID="my-ap" WIFI_PSK="my-passphrase" |
| 47 | +``` |
| 48 | + |
| 49 | +## Flash and run |
| 50 | + |
| 51 | +```sh |
| 52 | +# Hold BOOTSEL on the Pico 2 W, plug USB, then: |
| 53 | +make flash |
| 54 | +# or copy app.uf2 to the RPI-RP2 mass-storage drive. |
| 55 | + |
| 56 | +# Watch the UART console (GP0/GP1, 115200 8N1): |
| 57 | +stty -F /dev/ttyACM0 115200 raw -echo |
| 58 | +cat /dev/ttyACM0 |
| 59 | +``` |
| 60 | + |
| 61 | +A Picoprobe (CMSIS-DAP) attached over SWD gives you live GDB: |
| 62 | + |
| 63 | +```sh |
| 64 | +openocd -f interface/cmsis-dap.cfg -c "transport select swd" \ |
| 65 | + -f target/rp2350.cfg -c "init" |
| 66 | +gdb-multiarch app.elf -ex 'target remote localhost:3333' |
| 67 | +``` |
| 68 | + |
| 69 | +## Pin map |
| 70 | + |
| 71 | +| Function | RP2350 GPIO | Notes | |
| 72 | +|-------------------|------------:|------------------------------------------------| |
| 73 | +| UART0 TX | GP0 | console out | |
| 74 | +| UART0 RX | GP1 | console in | |
| 75 | +| CYW43 WL_REG_ON | GP23 | active high; pulses radio power | |
| 76 | +| CYW43 SPI DATA | GP24 | shared MOSI/MISO via 470 ohm series resistor; PIO-driven; also the chip's host-IRQ line when idle | |
| 77 | +| CYW43 SPI CS | GP25 | active low; CPU-driven | |
| 78 | +| CYW43 SPI CLK | GP29 | PIO side-set clock | |
| 79 | + |
| 80 | +## Memory budget |
| 81 | + |
| 82 | +| Region | Size | Notes | |
| 83 | +|----------|------|---------------------------------------------------------| |
| 84 | +| Flash | 4 MB | XIP from QSPI. ~225 KB consumed by CYW43439 blob. | |
| 85 | +| SRAM | 520 KB | Generous; wolfIP + supplicant + 8 TCP + driver < 200 KB| |
| 86 | +| Stack | 16 KB | Reserved at top of SRAM by `target_*.ld`. | |
| 87 | + |
| 88 | +## Known constraints |
| 89 | + |
| 90 | +- The CYW43439 gSPI bus is single-data-line and shares MOSI/MISO via a 470 ohm series resistor on the Pico 2 W carrier. The clean-room driver in `cyw43439_driver.c` accounts for this (PIO transport in `rp2350_pio.c`). |
| 91 | +- The DATA line (GP24) is owned by the PIO state machine, so the chip's host-IRQ-when-idle signal cannot be read via SIO. `cyw43_poll()` therefore polls `SPI_STATUS` (F2-packet-available) rather than a GPIO; IRQ-driven RX is deferred (RP2350 erratum E9 also makes edge-IRQ GPIO modes risky). |
| 92 | +- Bring-up logging is gated by `DEBUG_BRINGUP` (default 1 in `cyw43439_driver.h`). Build with `EXTRA_CFLAGS=-DDEBUG_BRINGUP=0` to compile out the gSPI/firmware/ioctl progress prints for a production image. |
| 93 | +- The supplicant defaults to WPA2-PSK with `mfp_capable=1`. For WPA3-SAE targets, build with `WOLFIP_ENABLE_SAE=1 WOLFSSL_PUBLIC_MP` and set `cfg.auth_mode=WOLFIP_AUTH_SAE`. |
| 94 | + |
| 95 | +## Open items / not yet validated |
| 96 | + |
| 97 | +Validated on real silicon (a WPA2 AP on the desk): the **join** (`cyw43_connect` -> rc=0, radio associates) and the **event path** (`cyw43_poll` -> `cyw43_handle_event` decodes `WLC_E_LINK` and reports `assoc: UP`/`down`). With no host 4-way linked the link flaps UP/down as the AP times out the missing EAPOL - which also exercises the link-down decode. Note: `cyw43_rsn_ie_wpa2_psk[]` MUST match the supplicant's `own_rsn_ie` (WPA2-PSK/CCMP, MFP off); if MFP is enabled the IE has to be plumbed from the supplicant instead of hard-coded. |
| 98 | + |
| 99 | +Still to validate, in order: |
| 100 | + |
| 101 | +1. **BDC TX/RX**: EAPOL (`cyw43_tx_eapol`) and 802.3 (`cyw43_tx_eth`) framing, and the inbound `data_offset` handling in `cyw43_poll` (only exercised once EAPOL flows). |
| 102 | +2. **Key install** (`cyw43_set_key`): the 160-byte `wl_wsec_key` layout (CCMP algo, primary-key flag, pairwise vs group MAC). |
| 103 | +3. **End-to-end**: link the host supplicant (`WOLFIP_WITH_SUPPLICANT` + cross-built wolfSSL), reach `AUTHENTICATED` (stops the flap), then DHCP + UDP echo on port 7. |
| 104 | + |
| 105 | +Other gaps: `op_scan` is a stub (join-by-known-SSID only); the `supp_now_ms()` time source in `main.c` is a placeholder counter and needs a real RP2350 timer; the PMKSA-cache reuse path (PSK re-init) is exercised only by construction, not by a dedicated unit test; SAE-on-hardware stays software-validated this pass. |
0 commit comments