Skip to content

ZynqMP ZCU102 SD-card Linux boot: EL2 handoff, SDHCI init, QSPI hardening#750

Open
dgarske wants to merge 5 commits intowolfSSL:masterfrom
dgarske:zynqmp_bb
Open

ZynqMP ZCU102 SD-card Linux boot: EL2 handoff, SDHCI init, QSPI hardening#750
dgarske wants to merge 5 commits intowolfSSL:masterfrom
dgarske:zynqmp_bb

Conversation

@dgarske
Copy link
Copy Markdown
Member

@dgarske dgarske commented Apr 14, 2026

End-to-end fixes for booting Linux from an SD card on the ZynqMP ZCU102
with wolfBoot at EL2, plus QSPI-boot and large-FIT hardening uncovered
during bring-up.

EL2 handoff

  • Cache/MMU teardown (src/boot_aarch64_start.S): new
    el2_flush_and_disable_mmu cleans D-cache to PoC, invalidates I-cache
    to PoU, clears SCTLR_EL2.{M,C,I}. Required by the ARM64 Linux boot
    protocol. Called from do_boot() on the EL2 direct-jump path.
  • Config (config/examples/zynqmp_sdcard.config): default to EL2
    (comment out BOOT_EL1) to match the PetaLinux U-Boot flow and
    preserve KVM/hypervisor use of EL2.

Device-tree fixups

  • hal_dts_fixup() (hal/zynq.c): inject /chosen/bootargs from
    LINUX_BOOTARGS; grow DTB totalsize by 512 bytes for
    fdt_setprop() headroom. Only defined when MMU && __WOLFBOOT.
  • hal_get_timer_us(): ARMv8 generic-timer read via CNTPCT_EL0
    with a 100 MHz fallback when CNTFRQ_EL0 is not programmed.

SDHCI reliability

  • Settling delay after platform init + CMD0 retry loop (up to 10×10 ms)
    so the Arasan controller consistently detects the card after the
    slot-type change / soft reset.
  • SDHCI_DMA_THRESHOLD lowered to 4 KB so multi-block reads use SDMA
    instead of PIO, sidestepping the Arasan BRR re-poll race under
    -Os/-O2.
  • SDHCI_DMA_BUFF_BOUNDARY auto-derived from the threshold; documented
    override uses the raw register value (0x7000) so it is safe inside
    #if expressions.

QSPI hardening (hal/zynq.c)

  • New qspi_flash_reset() (0x66 RESET_ENABLE + 0x99 RESET_MEMORY)
    per chip in qspi_init, so the flash starts from a known state
    regardless of what FSBL/BootROM left behind (XIP, 4-byte addressing,
    auto-boot probing).
  • IOU_TAPDLY_BYPASS writes now route through pmu_request at EL≤2 in
    the ≤40 MHz and ≤100 MHz branches (previously only the ≤150 MHz
    branch handled this); the register is equally unwritable from EL2/EL1
    at lower clocks.

Linker layout (hal/zynq.ld)

  • ORIGIN moved from 0x080000000x10000000 with a 2 MB
    reservation. Kernels loaded at 0x00200000 with payloads >~126 MB
    would otherwise memcpy across 0x08000000 and clobber wolfBoot's own
    .text during handoff.
  • WOLFBOOT_ORIGIN in config/examples/zynqmp_sdcard.config aligned to
    0x10000000 to match the linker (so factory.bin/factory.srec
    encode the correct load address).

TRACE32 tooling (tools/scripts/zcu102/zcu102-ca53-qspi.cmm)

  • Rewritten against the Lauterbach ZCU102 QSPI demo: PREPAREONLY
    entry, single/dual toggle, READ_ID_TEST for single-flash variants,
    separate dialogs for BOOT.BIN at offset 0 and
    test-app/image_v1_signed.bin at the partition boot address.
  • Documented the ~128 MB TRACE32 temp-memory ceiling on
    FLASHFILE.Create: larger files must be split externally (e.g. via
    dd) and loaded in chunks.

Versal alignment

  • hal/versal.c default LINUX_BOOTARGS_ROOT restored to
    /dev/mmcblk0p2 (matching the prior Versal layout); a comment points
    to /dev/mmcblk0p4 for configs using the 4-partition OFP_A/OFP_B
    layout.
  • hal_dts_fixup() no longer masks fdt_find_node_offset errors —
    only -FDT_ERR_NOTFOUND falls through to fdt_add_subnode()
    (applied to both hal/zynq.c and hal/versal.c).

Docs (docs/Targets.md)

  • SDHCI notes (SDMA vs PIO, HV4E redirect, card-detect, block size),
    EL2 cleanup behavior for ZynqMP and Versal SD-card sections.

Behavior changes

  • EL2 payloads now enter with MMU off and caches clean instead of
    inheriting wolfBoot's translation tables. No in-tree payload relies
    on the old state leakage.
  • SDHCI_DMA_THRESHOLD lowered to 4 KB (was 512 KB): virtually all
    multi-block reads go through SDMA.
  • ZynqMP config defaults to EL2 (was EL1).
  • wolfBoot linker ORIGIN is 0x10000000 (was 0x08000000) on
    hal/zynq.ld; WOLFBOOT_ORIGIN in zynqmp_sdcard.config follows.

Verification

  • Boots Linux end-to-end on ZCU102 SD-card; UART shows
    Load address 0x10000000, kernel brings up rootfs on
    /dev/mmcblk0p4.
  • CI builds: zynqmp.config, zynqmp_sdcard.config,
    versal_vmk180.config, versal_vmk180_sdcard.config all build clean
    (via .github/workflows/test-configs.yml).

@dgarske dgarske self-assigned this Apr 14, 2026
@dgarske dgarske requested review from Copilot and danielinux April 14, 2026 19:09
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

Note

Copilot was unable to run its full agentic suite in this review.

Targets reliable SD-card Linux boot on Xilinx ZynqMP (ZCU102) by improving SDHCI init timing, adding timer support, patching DT bootargs at runtime, and ensuring ARM64 Linux entry requirements are met when booting from EL2.

Changes:

  • Add SDHCI delays/retries to avoid CMD0 cold-boot timeout on Arasan SDHCI.
  • Add ZynqMP timer + DTB /chosen/bootargs runtime fixup to match wolfBoot partitioning.
  • Add EL2 cache clean + MMU/I/D-cache disable path before jumping to Linux.

Reviewed changes

Copilot reviewed 4 out of 4 changed files in this pull request and generated 11 comments.

File Description
src/sdhci.c Adds settle delays and CMD0 retry loop to stabilize SD card initialization timing.
src/boot_aarch64_start.S Introduces an EL2 cleanup/jump helper to satisfy Linux boot protocol cache/MMU requirements.
src/boot_aarch64.c Calls the EL2 cleanup/jump helper when booting from EL2.
hal/zynq.c Implements DTB bootargs fixup and adds a microsecond timer using the ARMv8 generic timer.

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

Comment thread src/sdhci.c
Comment thread src/sdhci.c
Comment thread src/sdhci.c
Comment thread src/sdhci.c Outdated
Comment thread src/boot_aarch64_start.S Outdated
Comment thread src/boot_aarch64.c
Comment thread src/boot_aarch64.c Outdated
Comment thread hal/zynq.c Outdated
Comment thread hal/zynq.c Outdated
Comment thread hal/zynq.c Outdated
Copy link
Copy Markdown

@wolfSSL-Fenrir-bot wolfSSL-Fenrir-bot left a comment

Choose a reason for hiding this comment

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

Fenrir Automated Review — PR #750

Scan targets checked: wolfboot-bugs, wolfboot-consttime, wolfboot-defaults, wolfboot-mutation, wolfboot-proptest, wolfboot-src, wolfboot-zeroize

Findings: 1
1 finding(s) posted as inline comments (see file-level comments below)

This review was generated automatically by Fenrir. Findings are non-blocking.

Copilot AI review requested due to automatic review settings April 15, 2026 18:38
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 6 out of 6 changed files in this pull request and generated 5 comments.


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

Comment thread src/boot_aarch64.c Outdated
Comment thread src/boot_aarch64_start.S
Comment thread hal/zynq.c Outdated
Comment thread hal/zynq.c
Comment thread hal/zynq.c
Copilot AI review requested due to automatic review settings April 15, 2026 18:58
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 6 out of 6 changed files in this pull request and generated 2 comments.


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

Comment thread src/boot_aarch64.c Outdated
Comment thread hal/zynq.c
@dgarske dgarske changed the title Fixes for Xilinx ZynqMP ZCU102 SD card boot with Linux ZynqMP ZCU102 SD-card Linux boot: EL2 cleanup, DTS bootargs, SDHCI init Apr 15, 2026
@dgarske dgarske added the Later It won't be fixed in the upcoming release label Apr 15, 2026
@dgarske dgarske force-pushed the zynqmp_bb branch 3 times, most recently from 04f54a3 to f4f631f Compare April 20, 2026 18:13
Add the pieces needed to boot Linux end-to-end from the ZCU102 SD card
with wolfBoot at EL2:

* src/boot_aarch64_start.S: new el2_flush_and_disable_mmu helper that
  cleans D-cache to PoC, invalidates I-cache to PoU, and clears
  SCTLR_EL2.{M,C,I}, then returns. Satisfies the ARM64 Linux boot
  protocol and is also correct for any other payload that sets up its
  own translation (hypervisor, RTOS, later bootloader stage).
* src/boot_aarch64.c: call el2_flush_and_disable_mmu from do_boot() on
  the EL2 direct-jump path before falling through to the br x4 block.
  Also pull in hal/zynq.h and hal/nxp_ls1028a.h so the EL_HYPERVISOR /
  BOOT_EL1 guards compile for those targets.
* hal/zynq.c: implement hal_dts_fixup() — set /chosen/bootargs from
  LINUX_BOOTARGS (with a LINUX_BOOTARGS_ROOT default of /dev/mmcblk0p4)
  and grow DTB totalsize by 512 bytes to give fdt_setprop() headroom
  (matches hal/versal.c). Add hal_get_timer_us() via CNTPCT_EL0.
* src/sdhci.c: add a 1 ms settling delay after sdhci_platform_init()
  and a CMD0 retry loop (up to 10 x 10 ms) so the ZCU102 Arasan
  controller reliably detects the card after the slot-type change +
  soft reset.
* config/examples/zynqmp_sdcard.config: stay at EL2 by default (comment
  out BOOT_EL1), default rootfs to /dev/mmcblk0p4, turn DEBUG off.
* hal/versal.c: correct the default LINUX_BOOTARGS_ROOT to
  /dev/mmcblk0p4 to match the shipped MBR layout.
* docs/Targets.md: note the unconditional EL2 cleanup in the ZynqMP
  and Versal SD-card sections.

Behavior change: non-Linux AArch64 EL2 payloads now enter with MMU
off and caches clean instead of inheriting wolfBoot's tables. No
in-tree payload relies on the old state leakage.
@dgarske dgarske changed the title ZynqMP ZCU102 SD-card Linux boot: EL2 cleanup, DTS bootargs, SDHCI init ZynqMP ZCU102 SD-card Linux boot: EL2 cleanup, DTS bootargs, SDHCI reliability Apr 23, 2026
dgarske added a commit to dgarske/meta-wolfssl that referenced this pull request Apr 23, 2026
Copy link
Copy Markdown

@wolfSSL-Fenrir-bot wolfSSL-Fenrir-bot left a comment

Choose a reason for hiding this comment

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

Fenrir Automated Review — PR #750

Scan targets checked: wolfboot-bugs, wolfboot-src

No new issues found in the changed files. ✅

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 9 out of 9 changed files in this pull request and generated 7 comments.


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

Comment thread hal/zynq.c
Comment thread src/sdhci.c
Comment thread src/boot_aarch64.c Outdated
Comment thread include/sdhci.h
Comment thread docs/Targets.md Outdated
Comment thread docs/Targets.md Outdated
Comment thread config/examples/zynqmp_sdcard.config Outdated
dgarske added a commit to dgarske/meta-wolfssl that referenced this pull request Apr 23, 2026
@dgarske dgarske assigned danielinux and wolfSSL-Bot and unassigned dgarske Apr 24, 2026
hal/zynq.c:
  - Route IOU_TAPDLY_BYPASS writes through pmu_request at EL<=2 in the
    <=40 MHz and <=100 MHz branches (previously only done at <=150 MHz);
    the register is equally unwritable from EL2/EL1 at lower clocks.
  - Add qspi_flash_reset() (RESET_ENABLE 0x66 + RESET_MEMORY 0x99),
    called per chip in qspi_init so the flash starts from a known state
    regardless of what FSBL/BootROM left behind (XIP, 4-byte addr,
    auto-boot).
  - Drop unused 'reg' in csu_aes and 'ms' in csu_init so
    -Werror=unused-variable builds (OPTIMIZATION_LEVEL=0 / DEBUG=1) pass.

hal/zynq.ld:
  - Move wolfBoot ORIGIN from 0x08000000 to 0x10000000. Large FIT images
    (kernel load=0x00200000, payload >~126 MB) would sweep across
    0x08000000 at handoff and overwrite wolfBoot's own code.

tools/scripts/zcu102/zcu102-ca53-qspi.cmm:
  - Rewrite against the Lauterbach TRACE32 ZCU102 QSPI demo: PREPAREONLY
    entry mode, single/dual toggle, READ_ID_TEST, separate flash dialogs
    for BOOT.BIN (offset 0) and test-app/image_v1_signed.bin.
  - Document the ~128 MB TRACE32 temp-memory ceiling on FLASHFILE.Create:
    larger files must be split externally and loaded in chunks.
@dgarske dgarske changed the title ZynqMP ZCU102 SD-card Linux boot: EL2 cleanup, DTS bootargs, SDHCI reliability ZynqMP ZCU102 SD-card Linux boot: EL2 handoff, SDHCI init, QSPI hardening Apr 24, 2026
The previous commit moved WOLFBOOT_ORIGIN from 0x8000000 to 0x10000000
to match the linker script, but WOLFBOOT_LOAD_ADDRESS is also 0x10000000.
This causes wolfBoot to overwrite itself when loading the firmware image
(32MB FIT written to 0x10000000 overwrites wolfBoot's .text at the same
address mid-read, hanging the boot).

Revert to 0x8000000 (128MB, same as U-Boot) and update linker script to
match. WOLFBOOT_LOAD_ADDRESS at 0x10000000 is safely above wolfBoot's
2MB footprint at 0x8000000-0x8200000.
dgarske added a commit to dgarske/meta-wolfssl that referenced this pull request Apr 24, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Later It won't be fixed in the upcoming release

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants