Skip to content

Add Xilinx Zynq-7000 (ZC702) wolfBoot port#770

Open
dgarske wants to merge 1 commit intowolfSSL:masterfrom
dgarske:zynq7000
Open

Add Xilinx Zynq-7000 (ZC702) wolfBoot port#770
dgarske wants to merge 1 commit intowolfSSL:masterfrom
dgarske:zynq7000

Conversation

@dgarske
Copy link
Copy Markdown
Member

@dgarske dgarske commented May 2, 2026

Summary

Adds a wolfBoot port for the Xilinx Zynq-7000 SoC (Cortex-A9 dual-core, ARMv7-A 32-bit), verified end-to-end on the ZC702 Evaluation Kit (XC7Z020). This is a distinct port from the existing ZynqMP/zynq target -- different CPU architecture (A9 vs A53), different QSPI controller (XQspiPs vs XQspiPsu GQSPI), different SDHCI revision (Arasan v2.0 vs v3.0), and a simpler boot model (FSBL -> wolfBoot, no PMUFW/BL31).

Three boot configurations, all verified on real ZC702 hardware:

Config Storage Payload Verified
config/examples/zynq7000.config QSPI NOR (16 MB) bare-metal signed app cold-boot pass
config/examples/zynq7000_linux.config QSPI NOR Linux 6.1.70 (zImage + appended DTB) kernel boots through full SMP init
config/examples/zc702_sdcard.config SD card (MBR) bare-metal signed app cold-boot pass

What's included

HAL (hal/zynq7000.{c,h,ld})

  • UART driver (XUartPs UART1, 115200 8N1, MIO48/49 on the ZC702 J17 console).
  • QSPI driver (XQspiPs -- the older Linear/Static QSPI on Z7, not the GQSPI on ZynqMP):
    • I/O mode for short command ops (RDID/RDSR/WREN/SE/PP) using the TXD1/TXD2/TXD3 auto-start FIFOs.
    • Linear/XIP mode for bulk reads via the memory-mapped 0xFC000000 window (32-bit AXI reads with byte unpack -- single-byte loads to the linear window are unreliable).
    • Wired to ext_flash_read/write/erase; hal_flash_* are no-ops (Z7 has no internal flash).
  • SDHCI driver hooks (Arasan v2.0): translates the generic Cadence SD4HC layout used by src/sdhci.c to the Arasan standard SDHCI layout, plus SLCR clock + reset for the SDIO0 controller, plus ARMv7 D-cache maintenance via CP15 for SDMA.
  • hal_get_timer_us via Cortex-A9 Global Timer at PERIPHCLK = CPU_3x2x = 333.33 MHz on the default ZC702 FSBL clock plan; feeds udelay() in the SDHCI driver.
  • hal_prepare_boot: cleans+invalidates L1 D-cache by set/way, invalidates I-cache + branch predictor, disables MMU+caches via SCTLR before chain-load.

Cortex-A9 startup (M8 -- generic ARMv7-A)

  • src/boot_arm32_start.S rewritten as a generic ARMv7-A startup file (was SAMA5D3-specific). Now handles per-mode stacks (IRQ/FIQ/ABT/UND/SVC), VBAR setup, SCTLR.{A,V,C,I} clearing, TLB/I-cache/branch-predictor invalidate, async-abort enable, and .data/.bss setup. Used by both SAMA5D3 (Cortex-A5) and Zynq-7000 (Cortex-A9).
  • src/boot_arm32.c do_boot gets a WOLFBOOT_LINUX_PAYLOAD branch that follows the ARM Linux boot ABI (r0=0, r1=~0, r2=DTB_phys, r3=0) for kernel/U-Boot handoff. Default behavior (legacy DTS-in-r0) preserved when the flag is unset. Also fixes a stray mov r5, 0 -> mov r5, #0 so GAS accepts it in ARM mode.

Build system

  • arch.mk Cortex-A9 block: -mcpu=cortex-a9 -marm -mfpu=neon-vfpv3 -mfloat-abi=softfp, pulls in the ARMv7-A SHA256 + SP-math objects, and gates MMU=1 -> -DMMU -DWOLFBOOT_FDT + src/fdt.o for the Linux config. DISK_SDCARD=1 pulls in src/sdhci.o, src/gpt.o, src/disk.o, src/update_disk.o.
  • Makefile + test-app/Makefile: TARGET=zynq7000 plumbing.

Tools

  • tools/scripts/zc702/zc702_qspi.bif -- bootgen template for BOOT.BIN (FSBL + wolfboot.elf), shared by all three configs.
  • tools/scripts/zc702/jtag_load.tcl -- xsdb script for JTAG-loaded development via Platform Cable II (runs the prebuilt FSBL, stops at handoff, loads wolfboot.elf at 0x04000000, sets PC + SVC CPSR, resumes).
  • tools/scripts/zc702/prepare_linux.sh -- signs zImage for the QSPI Linux config. Defaults to APPENDED=1 (concatenates DTB onto zImage and signs the pair as one wolfBoot image -- works around an ARMv7 zImage decompressor that loses r2 between entry and __atags_pointer on this kernel/load combo). APPENDED=0 for the raw-DTB-via-PART_DTS_BOOT path.
  • tools/scripts/zc702/prepare_sdcard.sh -- lays out a pure-MBR SD card (parted msdos + manual MBR type/active patch), formats p1 as FAT32, copies BOOT.BIN, dd's the signed image into raw partitions p2 and p3.

Test app

  • test-app/app_zynq7000.c + test-app/ARM-zynq7000.ld -- minimal banner + heartbeat dot loop over UART1 to validate the chain-load handoff.

Docs

  • docs/Targets.md gets a complete "Xilinx Zynq-7000 (ZC702)" section: prerequisites (Vitis 2025.2 settings64.sh, Platform Cable II driver install, prebuilt FSBL clone), JTAG bring-up flow, partition layout, DDR map, sample cold-boot UART output, TEST_EXT_FLASH selftest expected output, SD-card boot table + Arasan v2.0 quirks, and a comparison table vs the ZynqMP port.

@dgarske dgarske self-assigned this May 2, 2026
Copilot AI review requested due to automatic review settings May 2, 2026 01:53
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR adds an initial wolfBoot port for Xilinx Zynq-7000 on the ZC702 board, extending the codebase with a new ARMv7-A / Cortex-A9 target that boots via the Xilinx FSBL, verifies images from QSPI, and chain-loads a staged payload from DDR.

Changes:

  • Adds a new zynq7000 target across the HAL, startup code, linker scripts, and build system for FSBL-loaded Cortex-A9 boot.
  • Introduces a Zynq-7000 QSPI/UART HAL, RAM-boot configuration, and a minimal test application for bring-up validation.
  • Documents the target, JTAG workflow, QSPI layout, and adds helper scripts for XSDB/bootgen usage.

Reviewed changes

Copilot reviewed 14 out of 14 changed files in this pull request and generated 1 comment.

Show a summary per file
File Description
tools/scripts/zc702/zc702_qspi.bif Adds a bootgen BIF template for packaging FSBL + wolfBoot into BOOT.BIN.
tools/scripts/zc702/jtag_load.tcl Adds an XSDB script for JTAG bring-up by running FSBL and loading wolfboot.elf into DDR.
test-app/app_zynq7000.c Adds a minimal bare-metal ZC702 test app that prints a boot banner and heartbeat on UART1.
test-app/Makefile Wires the new target into test-app builds with the ARM32 startup object and target linker script.
test-app/ARM-zynq7000.ld Adds the linker script for the staged Zynq-7000 test application in DDR.
src/boot_zynq7000_start.S Adds Zynq-7000-specific ARMv7-A startup, vector setup, stack initialization, and early CPU state handling.
src/boot_arm32.c Adjusts ARM32 inline assembly immediate syntax used during chain-load handoff.
hal/zynq7000.ld Adds the wolfBoot linker script for execution from DDR at the FSBL handoff address.
hal/zynq7000.h Defines Zynq-7000 register maps and bitfields for UART, QSPI, and related peripherals.
hal/zynq7000.c Implements the new Zynq-7000 HAL, including UART, QSPI external flash access, and boot-preparation logic.
docs/Targets.md Documents the new ZC702 target, configuration, memory map, JTAG flow, and expected output.
config/examples/zynq7000.config Adds an example configuration for ECC256/SHA256 RAM-boot from external QSPI flash.
arch.mk Adds target selection and Cortex-A9-specific compiler/object settings for zynq7000.
Makefile Includes the new target in the default main build outputs.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread hal/zynq7000.c Outdated
@dgarske dgarske marked this pull request as ready for review May 6, 2026 22:08
@dgarske dgarske requested a review from Copilot May 6, 2026 22:08
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 19 out of 19 changed files in this pull request and generated 9 comments.

Comment thread hal/zynq7000.c
Comment on lines +254 to +261
* MANSTRTEN=0 (auto-start), CPHA/CPOL=0, PCS bit 10 cleared (CS0
* asserted - in linear mode the controller still wants this). */
Z7_QSPI_CR = Z7_QSPI_CR_IFMODE
| Z7_QSPI_CR_HOLD_B
| Z7_QSPI_CR_SSFORCE
| Z7_QSPI_CR_FIFO_WIDTH
| Z7_QSPI_CR_BAUD_DIV_4
| Z7_QSPI_CR_MSTREN;
Comment thread hal/zynq7000.c
Comment on lines +817 to +820
* 64-bit free-running counter, increments at PERIPHCLK (~166.67 MHz on
* ZC702 with the default FSBL clock plan: CPU_6x4x = 666.67 MHz). The
* Global Timer is started by the FSBL; if it isn't running yet we kick
* it here. */
Comment thread arch.mk
Comment on lines +312 to +314
# Do NOT define WOLFBOOT_USE_STDLIBC: newlib's memcpy uses unaligned
# LDRs which fault on Cortex-A9 when MMU is off (FSBL leaves MMU off
# on Zynq-7000). Use wolfBoot's own aligned-safe memcpy from src/string.c.
Comment thread arch.mk
Comment on lines +367 to +369
FPU=-mfpu=vfp3-d16
CFLAGS+=-mcpu=cortex-a9 -mtune=cortex-a9 -marm -static -z noexecstack \
-mno-unaligned-access
Comment thread docs/Targets.md
Comment on lines +3406 to +3409
This target supports:
- **QSPI boot** (primary): `config/examples/zynq7000.config`
- **SD card boot** (Milestone 6, planned): `config/examples/zc702_sdcard.config`
- **JTAG-loaded dev** via Platform Cable II + xsdb (no flash required)
Comment on lines +23 to +29
# GPT/MBR partition layout on the SD card.
# GPT partition 0 (idx 0): FAT32 - holds BOOT.BIN for the BootROM.
# GPT partition 1 (idx 1): raw - signed boot image (BOOT_PART_A).
# GPT partition 2 (idx 2): raw - signed update image (BOOT_PART_B).
# tools/scripts/zc702/prepare_sdcard.sh lays this out; BOOT_PART_A/B tell
# update_disk.c which GPT entries to use for boot/update.
CFLAGS_EXTRA+=-DBOOT_PART_A=1 -DBOOT_PART_B=2
Comment on lines +35 to +40
/dev/sda|/dev/nvme*) echo -e "${RED}refusing $DEV${NC}" >&2; exit 1 ;;
/dev/sd[b-z]|/dev/mmcblk[0-9]) ;;
*) echo -e "${RED}unsupported device: $DEV${NC}" >&2; exit 1 ;;
esac

[ -b "$DEV" ] || { echo -e "${RED}$DEV not a block device${NC}" >&2; exit 1; }
Comment on lines +32 to +34
# Source .config (Makefile syntax: NAME ?= value).
eval "$(sed -e 's/?=/=/' -e 's/^\([A-Z_][A-Z_0-9]*\)=\(.*\)$/\1="\2"/' .config 2>/dev/null | grep -E '^[A-Z]')"

Comment thread test-app/app_zynq7000.c
Comment on lines +57 to +65
void main(void)
{
uart_puts("\n=== ZC702 test-app: BOOT OK ===\n");
uart_puts("wolfBoot verified + chain-loaded this image\n");
while (1) {
uart_putc('.');
delay(2000000);
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants