You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
AMD/Xilinx Zynq-7000 (XC7Z020) on the ZC702 Evaluation Kit - dual ARM Cortex-A9 (ARMv7-A 32-bit), 1 GB DDR3, 16 MB QSPI NOR (N25Q128A), SDIO, dual UART. Older sibling of the ZynqMP family - distinct silicon, different controllers (`XQspiPs` not `XQspiPsu`, Arasan SDHCI v2.0 not v3.0, no CSU/PMU/PUF, PL310 L2).
3398
+
3399
+
wolfBoot is loaded by the Xilinx Zynq-7000 FSBL into DDR:
3400
+
```
3401
+
BootROM -> FSBL -> wolfBoot -> signed app (or U-Boot/Linux)
3402
+
```
3403
+
3404
+
The FSBL handles all PS init (DDR, MIO, clocks, QSPI ref clock); wolfBoot only initializes UART, the QSPI controller, runs the verify/swap logic, and chain-loads the next stage.
5.**Hardware**: ZC702 with Platform Cable II (USB JTAG) connected to J22 and powered.
3433
+
3434
+
### Configuration Options
3435
+
3436
+
Key options in `config/examples/zynq7000.config`:
3437
+
3438
+
-`ARCH=ARM` - 32-bit ARM
3439
+
-`TARGET=zynq7000` - selects `hal/zynq7000.{c,h,ld}` and the `CORTEX_A9` arch.mk block
3440
+
-`SIGN=ECC256` / `HASH=SHA256` - smaller and faster than RSA on Cortex-A9
3441
+
-`EXT_FLASH=1` - QSPI as external flash via `XQspiPs`
3442
+
-`WOLFBOOT_LOAD_ADDRESS=0x10000000` - DDR offset 256 MB, where the verified app is staged before `do_boot`. Must be **above** wolfBoot's own region (`0x04000000`-`0x040FFFFF`) because `src/update_ram.c` enforces `dst > _end`.
`bootgen` ships with Vitis. The `.bif` template at `tools/scripts/zc702/zc702_qspi.bif` is the minimum bootable image; add `download.bit` and a DTB if you also need to load the PL bitstream and a Linux device tree (see Milestone 5).
3483
+
3484
+
### Programming QSPI
3485
+
3486
+
Set ZC702 boot mode straps to **JTAG** for programming, then either:
- Vivado Hardware Manager: Tools -> Add Configuration Memory Device -> select N25Q128 -> program with BOOT.BIN at offset 0.
3489
+
3490
+
After programming, set boot mode to **QSPI** (SW16 - see UG850 ch.1.2.4) and power-cycle. Console comes up on UART1 (J17 USB-UART), 115200 8N1.
3491
+
3492
+
### JTAG-loaded development (no flash)
3493
+
3494
+
For driver bring-up or quick iteration, skip bootgen and load directly via Platform Cable II:
3495
+
3496
+
```sh
3497
+
source /opt/Xilinx/2025.2/Vitis/settings64.sh # once per shell
3498
+
xsdb tools/scripts/zc702/jtag_load.tcl
3499
+
```
3500
+
3501
+
The script runs the prebuilt FSBL (PS init: DDR/MIO/clocks/UART), then loads `wolfboot.elf` over the top, sets PC to `0x04000000` and CPSR to SVC with IRQ/FIQ masked, and resumes. Override paths via `FSBL_ELF=...` or `WOLFBOOT_ELF=...` env vars.
3502
+
3503
+
With a signed image programmed at QSPI offset `0x100000` (see "Building and flashing the signed test app" below), expected UART output is:
3504
+
3505
+
```
3506
+
wolfBoot Zynq-7000 (ZC702) hal_init
3507
+
Versions: Boot 1, Update 0
3508
+
Trying Boot partition at 0x100000
3509
+
Loading header 1024 bytes from 0x100000 to 0xFFFFC00
3510
+
Loading image 396 bytes from 0x100400 to 0x10000000...done
3511
+
Boot partition: 0xFFFFC00 (sz 396, ver 0x1, type 0x201)
3512
+
Checking integrity...done
3513
+
Verifying signature...done
3514
+
Successfully selected image in part: 0
3515
+
Firmware Valid
3516
+
Booting at 0x10000000
3517
+
3518
+
=== ZC702 test-app: BOOT OK ===
3519
+
wolfBoot verified + chain-loaded this image
3520
+
.....
3521
+
```
3522
+
3523
+
On a **blank** QSPI (no signed image yet), wolfBoot prints `Versions: Boot 0, Update 0 / No valid image found! / wolfBoot: PANIC!` instead - that is correct behavior, not a bug.
3524
+
3525
+
If `xsdb` reports `no targets found` or empty `jtag servers`, either:
3526
+
- Cable USB drivers not installed - see step 3 of Prerequisites, OR
3527
+
- A previous run left the CPU in a stuck JTAG state - power-cycle the ZC702 (SW10, the Pi4 GPIO 20 power relay, or your PSU control) and retry.
3528
+
3529
+
A separate JTAG-only dev build (no QSPI driver) can be produced with `make EXT_FLASH=0`.
3530
+
3531
+
### Building and flashing the signed test app
3532
+
3533
+
A minimal Cortex-A9 test app lives at `test-app/app_zynq7000.c` (UART banner + heartbeat dots). The top-level `make` target produces both `wolfboot.elf` and `test-app/image_v1_signed.bin` with the keys generated under `wolfboot_signing_private_key.der`:
3534
+
3535
+
```sh
3536
+
cp config/examples/zynq7000.config .config
3537
+
make keysclean && make # builds wolfboot.elf + test-app/image_v1_signed.bin
3538
+
```
3539
+
3540
+
Program the signed image to QSPI offset `0x100000` (the BOOT_A partition):
3541
+
3542
+
```sh
3543
+
program_flash -f test-app/image_v1_signed.bin \
3544
+
-fsbl ${PREBUILT_DIR}/zynq_fsbl.elf \
3545
+
-flash_type qspi_single -offset 0x100000
3546
+
```
3547
+
3548
+
`program_flash` ships with Vitis. Then run wolfBoot via `xsdb tools/scripts/zc702/jtag_load.tcl` - it should verify and chain-load the test app, producing the heartbeat output above.
3549
+
3550
+
### QSPI driver self-test (`TEST_EXT_FLASH`)
3551
+
3552
+
To exercise the `XQspiPs` driver in isolation - read JEDEC ID, sector erase + page program + linear-mode read-back of a 256-byte pattern at `0x200000`:
3553
+
3554
+
```sh
3555
+
make CFLAGS_EXTRA=-DTEST_EXT_FLASH wolfboot.elf
3556
+
xsdb tools/scripts/zc702/jtag_load.tcl
3557
+
```
3558
+
3559
+
Expected output:
3560
+
3561
+
```
3562
+
qspi: --- TEST_EXT_FLASH start ---
3563
+
qspi: JEDEC ID = 0x20bb18 rc=00 <- Micron N25Q128
3564
+
qspi: read @0x100000 = 574f4c468c010000 <- "WOLF" magic from a programmed signed image
3565
+
qspi: erase sector @ 0x00200000 ...
3566
+
qspi: page program ...
3567
+
qspi: post-program JEDEC = 0x20bb18
3568
+
qspi: rdback[0..7] = 0001020304050607
3569
+
qspi: --- TEST_EXT_FLASH PASS ---
3570
+
```
3571
+
3572
+
### QSPI driver design
3573
+
3574
+
The driver in `hal/zynq7000.c` splits read vs cmd-only paths similarly to how the ZynqMP HAL splits SDHCI CMD17 (single-block PIO) vs CMD18 (multi-block SDMA):
| Bulk reads (signed image, partition headers) | Linear/XIP mode (`memcpy` from `0xFC000000+offset`) | Hardware-accelerated; controller drives cmd+addr+dummy and presents data through the AXI window |
3580
+
3581
+
`qspi_linear_mode_setup()` configures `LQSPI_CR=0x8000010B` (single-bit `FAST_READ` 0x0B + 1 dummy byte) which avoids needing the flash QE bit set. A sacrificial first-byte read primes the linear-mode pipeline before the actual `memcpy`.
3582
+
3583
+
For TX-only commands sent without RX capture, `qspi_xfer4` picks `TXD1`/`TXD2`/`TXD3` so the controller clocks exactly *N* bytes on the wire (no 4-byte padding that some flash interprets as additional commands - this caused our WREN to fail in an early iteration).
3584
+
3585
+
### Boot flow notes
3586
+
3587
+
-**Cortex-A9 startup**: `src/boot_zynq7000_start.S` (Z7-specific) plus shared `src/boot_arm32.c` for `do_boot()`. Sets VBAR to wolfBoot's vector table at `0x04000000`, clears `SCTLR.{A,C,I,V}`, invalidates I-cache + branch predictor + TLB, sets stack pointers for IRQ/FIQ/ABT/UND/SVC modes, then unmasks async aborts and calls `main`.
3588
+
-**MMU stays ON**, inheriting FSBL's flat 1:1 DDR mapping. Disabling the MMU on Cortex-A9 makes all memory Strongly-Ordered, which traps unaligned LDR/STR and breaks any ARMv7-A unrolled `memcpy`.
3589
+
-**memcpy/memset**: do **not** define `WOLFBOOT_USE_STDLIBC` for this target. newlib's ARMv7-A `memcpy` uses unaligned word LDRs from arbitrary alignments and faults under any code path that runs without the MMU configured for Normal memory. wolfBoot's own byte-wise / aligned-word `memcpy` in `src/string.c` is used instead.
3590
+
-**`ext_flash_read` returns bytes-read** (not 0 on success): `src/update_ram.c` checks `ret != IMAGE_HEADER_SIZE` for the header read and `ret < 0` for the body read.
3591
+
-**Cache teardown** in `hal_prepare_boot()`: cleans+invalidates L1 D-cache by set/way, invalidates L1 I-cache and branch predictor, then disables MMU+caches via SCTLR before `do_boot()` performs `bx r4`.
3592
+
-**Register handoff**: per ARM Linux boot ABI - `r0 = 0`, `r1 = 0`, `r2 = DTB ptr` (Linux/U-Boot, Milestone 5), entry in `r4`.
3593
+
-**L2 (PL310)**: not touched by wolfBoot. Stock ZC702 FSBLs do not enable PL310; if your customised FSBL does, extend `hal_prepare_boot()` with an L2x0 clean-invalidate + disable.
0 commit comments