|
| 1 | +# wolfIP port: Xilinx Zynq-7000 (Cortex-A9, ARMv7-A 32-bit) |
| 2 | + |
| 3 | +**STATUS: brought up on a ZC702.** DHCP, ICMP ping and the UDP echo demo all work on real hardware (Cortex-A9, Marvell 88E1518 PHY). See "Hardware bring-up notes" below for the Zynq-7000-specific differences that mattered. |
| 4 | + |
| 5 | +## What this port is |
| 6 | + |
| 7 | +Bare-metal wolfIP port for the Xilinx Zynq-7000 family (Z-7020 etc., e.g. ZC702 / ZedBoard / MicroZed dev boards). Cortex-A9 in SVC mode, GCC bare-metal, no Xilinx Standalone BSP, no FreeRTOS. Targets the same deterministic UDP/IPv4 profile as the ZCU102 port. |
| 8 | + |
| 9 | +## What differs from ZCU102 |
| 10 | + |
| 11 | +| Subsystem | ZCU102 (ZynqMP) | Zynq-7000 | Where it lives | |
| 12 | +|-----------|-----------------|-----------|----------------| |
| 13 | +| Architecture | ARMv8-A AArch64 | ARMv7-A 32-bit | toolchain prefix | |
| 14 | +| CPU core | Cortex-A53 | Cortex-A9 | `Makefile` (-mcpu) | |
| 15 | +| Bootloader handoff | FSBL -> EL3 | FSBL -> SVC | `startup.S` | |
| 16 | +| Toolchain | `aarch64-none-elf-gcc` | `arm-none-eabi-gcc` | `Makefile` | |
| 17 | +| Exception model | EL3 vectors | ARMv7 exception modes | `startup.S` rewritten | |
| 18 | +| MMU | 4-level long descriptor | 1-level short descriptor | `mmu.c` rewritten | |
| 19 | +| Cache ops | DC CVAC / DC IVAC | MCR p15 c7 (DCCMVAC/DCIMVAC) | `gem.c` | |
| 20 | +| Generic timer | `mrs cntpct_el0` | `mrrc p15, 0, ..., c14` | `timer.h`, `entropy.c` | |
| 21 | +| GIC | GIC-400 (GICv2) | GIC-390 (GICv2) | `gic.c` (same driver, different base) | |
| 22 | +| GIC base addrs | `0xF901xxxx` | `0xF8F0xxxx` | `board.h` | |
| 23 | +| UART | Cadence at 0xFF000000 | Cadence at 0xE0000000 | `board.h` (same driver) | |
| 24 | +| Clock + reset | CRL_APB at 0xFF5E0000 | SLCR at 0xF8000000 | `board.h` (gem.c clock helper needs rewrite) | |
| 25 | +| GEM count | 4 (GEM0-3) | 2 (GEM0-1) | `board.h` | |
| 26 | +| On-board RJ45 | GEM3 (INTID 95) | GEM0 (INTID 54) | `board.h` | |
| 27 | +| BD format | 8-byte (DMACR[30]=0) | 8-byte (no 64-bit option) | `gem.c` (unchanged) | |
| 28 | + |
| 29 | +## Build |
| 30 | + |
| 31 | +``` |
| 32 | +cd src/port/zynq7000 |
| 33 | +make CROSS_COMPILE=arm-none-eabi- |
| 34 | +``` |
| 35 | + |
| 36 | +Output: `app.elf`. |
| 37 | + |
| 38 | +## JTAG boot (ZC702) |
| 39 | + |
| 40 | +The ZC702 boots its onboard JTAG over the Digilent USB module; set SW10 |
| 41 | +to the on-board (USB) JTAG position and SW16 to JTAG boot mode, then: |
| 42 | + |
| 43 | +``` |
| 44 | +XSDB=/opt/Xilinx/<ver>/Vitis/bin/xsdb \ |
| 45 | +FSBL_ELF=/path/to/zynq_fsbl.elf \ |
| 46 | +./jtag/boot.sh |
| 47 | +``` |
| 48 | + |
| 49 | +`jtag/boot.tcl` runs the prebuilt FSBL (ps7_init brings up DDR/MIO/clocks/ |
| 50 | +UART), remaps all four OCM banks high (`SLCR.OCM_CFG`) so the app can load |
| 51 | +at `0xFFFC0000`, then loads `app.elf` and starts it in SVC mode. The |
| 52 | +console is on **UART1** (the ZC702 USB-UART), not UART0. After a run the |
| 53 | +A9 must be power-cycled to be JTAG-loadable again. |
| 54 | + |
| 55 | +## Hardware bring-up notes (what was Zynq-7000-specific) |
| 56 | + |
| 57 | +These are the things that differed from the AArch64 ports and had to be |
| 58 | +fixed for the ZC702 to reach DHCP/ping/echo: |
| 59 | + |
| 60 | +- **No ARM generic timer.** The Cortex-A9 does not implement CNTPCT/CNTFRQ |
| 61 | + (CP15 c14); those encodings are UNDEFINED and trap. `timer.h` and |
| 62 | + `entropy.c` use the MPCore **Global Timer** at `0xF8F00200` (333 MHz) |
| 63 | + instead. |
| 64 | +- **Console is UART1.** The ZC702 routes the USB console to Cadence UART1 |
| 65 | + (`0xE0001000`); `uart.c` trusts the FSBL's baud config rather than |
| 66 | + reprogramming the divisor (the UART_REF_CLK is not the ZynqMP value). |
| 67 | +- **Marvell 88E1518 PHY, not DP83867.** The ZC702 fits a Marvell PHY |
| 68 | + (OUI `0x0141`) at MDIO addr 7. `phy_marvell.c` handles its paged RGMII |
| 69 | + delay registers + autoneg; `gem.c` dispatches on the PHY ID. |
| 70 | +- **GEM clock via SLCR, write-protected.** `SLCR.GEM0_CLK_CTRL` |
| 71 | + (`0xF8000140`) has a different layout than ZynqMP's CRL_APB and is |
| 72 | + write-locked. `gem3_set_ref_clk` unlocks the SLCR (`0xDF0D`) and writes |
| 73 | + `0x00100801` for 125 MHz (1 Gbps). `SLCR.GEM0_RCLK_CTRL` (`0xF8000138`) |
| 74 | + must also be set to source the RGMII RX clock from the PHY, or the MAC |
| 75 | + receives nothing (matches Xilinx ps7_init). |
| 76 | +- **Poll-driven RX, GEM IRQ masked.** Unlike the Versal GICv3, the A9 GIC |
| 77 | + delivers the GEM SPI, and an enabled RX-complete interrupt storms the |
| 78 | + CPU. RX is polled from `eth_poll` and the GEM interrupt is left masked. |
| 79 | +- **Non-cacheable OCM for DMA.** The 8-byte GEM descriptors share 32-byte |
| 80 | + cache lines, so per-descriptor cache maintenance corrupts neighbours' |
| 81 | + OWN bits and stalls RX. The OCM section is mapped Normal non-cacheable |
| 82 | + (`mmu.c`) so the descriptor rings and buffers are DMA-coherent. (The |
| 83 | + PL310 L2 is also disabled as a belt-and-braces measure.) Note the A9 |
| 84 | + L1 cache line is 32 bytes, not the 64 of the AArch64 cores. |
| 85 | +- `NWCFG_DWIDTH_64` (NWCFG bit 21) is never set: the A9 GEM AXI master |
| 86 | + path is 32-bit and the BDs stay 8 bytes. |
| 87 | + |
| 88 | +## Files |
| 89 | + |
| 90 | +Same layout as `src/port/zcu102/`, plus `phy_marvell.c` / `phy_marvell.h` |
| 91 | +(the ZC702 PHY) and `jtag/` (FSBL-based JTAG loader). See the ZCU102 |
| 92 | +README for the shared per-file responsibilities. |
0 commit comments