Support for wolfBoot ZynqMP (UltraScale+ MPSoC) SD Card#699
Support for wolfBoot ZynqMP (UltraScale+ MPSoC) SD Card#699dgarske wants to merge 7 commits intowolfSSL:masterfrom
Conversation
There was a problem hiding this comment.
Pull request overview
This PR adds SD card boot support for the AMD Zynq UltraScale+ MPSoC (ZynqMP) platform, complementing the existing QSPI boot capability. wolfBoot can now load firmware images from MBR-partitioned SD cards using the Arasan SDHCI controller.
Changes:
- Implements SDHCI platform support for ZynqMP with register translation between Cadence SD4HC and Arasan layouts
- Adds conditional compilation for QSPI initialization to support SD-only boot configurations
- Documents SD card boot setup with MBR partitioning and dual A/B firmware images
Reviewed changes
Copilot reviewed 4 out of 4 changed files in this pull request and generated 3 comments.
| File | Description |
|---|---|
| hal/zynq.h | Adds SD/SDHCI controller base addresses and clock/reset control register definitions |
| hal/zynq.c | Implements SDHCI platform hooks with register translation and conditional QSPI initialization |
| docs/Targets.md | Documents SD card boot configuration, partition layout, and setup procedures |
| config/examples/zynqmp_sdcard.config | Provides complete SD card boot configuration with MBR partition support |
Comments suppressed due to low confidence (2)
config/examples/zynqmp_sdcard.config:1
- The size specification '128M' is ambiguous in sfdisk context. sfdisk expects sector counts or explicit +size notation. Use
size=+128Mor calculate the sector count (262144 sectors for 128MB with 512-byte sectors) to ensure consistent partition creation across different sfdisk versions.
# wolfBoot configuration for AMD ZynqMP ZCU102 - SD Card Boot
config/examples/zynqmp_sdcard.config:1
- The size specifications '200M' should use explicit +size notation for clarity. Use
size=+200Mto ensure sfdisk interprets these as size specifications rather than potential sector counts.
# wolfBoot configuration for AMD ZynqMP ZCU102 - SD Card Boot
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 6 out of 6 changed files in this pull request and generated 7 comments.
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
cde8a86 to
a13acfb
Compare
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 10 out of 11 changed files in this pull request and generated 6 comments.
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
… passing. Only issue is test-app EL level. Peer review fixes.
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 10 out of 11 changed files in this pull request and generated 6 comments.
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
You can also share your feedback on Copilot code review. Take the survey.
| #define RST_LPD_IOU2_SDIO1 (1UL << 6) | ||
|
|
||
| /* IOU_SLCR SD Configuration (feeds into SDHCI Capabilities register) */ | ||
| #define IOU_SLCR_SD_CONFIG_REG2 (*((volatile uint32_t*)(IOU_SLCR_BASSE + 0x320))) |
There was a problem hiding this comment.
Typo in macro: IOU_SLCR_BASSE should be IOU_SLCR_BASE. This will cause a compilation error if IOU_SLCR_BASSE is not defined elsewhere.
| *(.gnu.linkonce.t.*) | ||
| *(.plt) | ||
| *(.gnu_warning) | ||
| *(.gcc_execpt_table) |
There was a problem hiding this comment.
Typo in section name: .gcc_execpt_table should be .gcc_except_table. This misspelling means exception table entries in this section will not be collected, which could cause issues with C++ exception handling or unwinding.
| *(.gcc_execpt_table) | |
| *(.gcc_except_table) |
| .ARM.exidx : { | ||
| __exidx_start = .; | ||
| *(.ARM.exidx*) | ||
| *(.gnu.linkonce.armexidix.*.*) |
There was a problem hiding this comment.
Typo in section name: .gnu.linkonce.armexidix should be .gnu.linkonce.armexidx. The misspelling means ARM exception index entries will not be collected into the .ARM.exidx section.
| *(.gnu.linkonce.armexidix.*.*) | |
| *(.gnu.linkonce.armexidx.*.*) |
| (void)is_write; | ||
| /* After DMA: clean and invalidate to ensure CPU sees DMA-written data */ | ||
| uintptr_t addr; | ||
| uintptr_t start = (uintptr_t)buf & ~(CACHE_LINE_SIZE - 1); | ||
| uintptr_t end = (uintptr_t)buf + sz; | ||
|
|
||
| for (addr = start; addr < end; addr += CACHE_LINE_SIZE) { | ||
| __asm__ volatile("dc civac, %0" : : "r"(addr) : "memory"); |
There was a problem hiding this comment.
After a DMA write (card←memory), sdhci_platform_dma_complete unconditionally runs dc civac (clean-and-invalidate) on the output buffer. For a write transfer, there is no need to invalidate — the DMA has only read from memory, not written to it. Invalidating after a write could cause dirty cache lines written between the prepare and complete calls to be discarded, potentially corrupting data. The is_write flag should be used to skip invalidation for write transfers, matching the asymmetric prepare logic.
| (void)is_write; | |
| /* After DMA: clean and invalidate to ensure CPU sees DMA-written data */ | |
| uintptr_t addr; | |
| uintptr_t start = (uintptr_t)buf & ~(CACHE_LINE_SIZE - 1); | |
| uintptr_t end = (uintptr_t)buf + sz; | |
| for (addr = start; addr < end; addr += CACHE_LINE_SIZE) { | |
| __asm__ volatile("dc civac, %0" : : "r"(addr) : "memory"); | |
| /* After DMA read (card→memory): invalidate so CPU sees DMA-written data. | |
| * For DMA write (card←memory): DMA only read from memory, so there is no | |
| * new data for the CPU to see and invalidation could discard dirty lines. */ | |
| uintptr_t addr; | |
| uintptr_t start = (uintptr_t)buf & ~(CACHE_LINE_SIZE - 1); | |
| uintptr_t end = (uintptr_t)buf + sz; | |
| if (!is_write) { | |
| for (addr = start; addr < end; addr += CACHE_LINE_SIZE) { | |
| __asm__ volatile("dc civac, %0" : : "r"(addr) : "memory"); | |
| } |
| # DTS (Device Tree) load address | ||
| WOLFBOOT_LOAD_DTS_ADDRESS?=0x1000 |
There was a problem hiding this comment.
The DTS load address 0x1000 (4 KB) is unusually low and likely conflicts with the exception vector table or other low-memory structures on AArch64, where the reset vector starts at 0x0. On ZynqMP, low physical addresses (below a few MB) are typically used for interrupt vectors or OCM. A more typical device tree load address would be in DDR, e.g., 0x40000000 or similar. Please verify this is intentional.
| # DTS (Device Tree) load address | |
| WOLFBOOT_LOAD_DTS_ADDRESS?=0x1000 | |
| # DTS (Device Tree) load address (place in DDR to avoid low-memory conflicts) | |
| WOLFBOOT_LOAD_DTS_ADDRESS?=0x40000000 |
| **QSPI layout** | ||
| | Partition | Size | Address | Description | | ||
| |-------------|--------|-------------|--------------------------------| | ||
| | Bootloader | - | 0x7FF00000 | wolfBoot in DDR (loaded by FSBL) | |
There was a problem hiding this comment.
The QSPI layout table still lists the wolfBoot DDR address as 0x7FF00000, but hal/zynq.ld was updated to 0x7FE00000. This entry should be updated to 0x7FE00000 to match the linker script change.
| | Bootloader | - | 0x7FF00000 | wolfBoot in DDR (loaded by FSBL) | | |
| | Bootloader | - | 0x7FE00000 | wolfBoot in DDR (loaded by FSBL) | |
No description provided.