Support for wolfBoot ZynqMP (UltraScale+ MPSoC) SD Card

pull/700/head
David Garske 2026-03-04 09:19:22 -08:00 committed by Daniele Lacamera
parent 3ef250cb33
commit ff8bb8336c
15 changed files with 1169 additions and 36 deletions

1
.gitignore vendored
View File

@ -343,3 +343,4 @@ image.ub
*.pdi
system-default.dtb
test_output/
sdcard.img

View File

@ -78,6 +78,7 @@ ifeq ($(ARCH),AARCH64)
HASH_HAL=1
CFLAGS+=-DWOLFBOOT_ZYNQMP_CSU
endif
endif
ifeq ($(TARGET),versal)

View File

@ -0,0 +1,113 @@
# wolfBoot configuration for AMD ZynqMP ZCU102 - SD Card Boot
# Zynq UltraScale+ MPSoC ZU9EG - Quad-core ARM Cortex-A53
#
# This configuration enables SD card boot for the ZynqMP:
# FSBL -> PMUFW -> BL31 (EL3) -> wolfBoot (EL2) -> Linux (EL1)
#
# wolfBoot loads firmware images from MBR partitions on SD card.
# Uses the generic SDHCI driver with SD1 controller (external SD slot on ZCU102).
ARCH?=AARCH64
TARGET?=zynq
WOLFBOOT_VERSION?=0
# RSA 4096-bit with SHA3-384 (matching existing zynqmp.config)
SIGN?=RSA4096
HASH?=SHA3
IMAGE_HEADER_SIZE?=1024
# Debug options
DEBUG?=1
DEBUG_SYMBOLS=1
DEBUG_UART=1
CFLAGS_EXTRA+=-DDEBUG_ZYNQ=1
# SD card support - use SDHCI driver
DISK_SDCARD?=1
DISK_EMMC?=0
# ZynqMP Arasan SDHCI does not support CDSS/CDTL card detect test level.
# Since FSBL booted from the same SD card, we know it is present.
CFLAGS_EXTRA+=-DSDHCI_FORCE_CARD_DETECT
# Note: Arasan SDHCI v3.0 does not support HV4E mode. The platform layer
# in hal/zynq.c transparently redirects SRS22/SRS23 to SRS00 for legacy SDMA.
# Disable QSPI flash when using SD card
EXT_FLASH?=0
NO_XIP=1
# ELF loading support
ELF?=1
# Boot Exception Level: transition from EL2 -> EL1 before jumping to app
BOOT_EL1?=1
# General options
VTOR?=1
CORTEX_M0?=0
NO_ASM?=0
ALLOW_DOWNGRADE?=0
NVM_FLASH_WRITEONCE?=0
V?=0
SPMATH?=1
RAM_CODE?=0
DUALBANK_SWAP?=0
PKA?=0
WOLFTPM?=0
# Toolchain
USE_GCC=1
CROSS_COMPILE=aarch64-none-elf-
# ============================================================================
# Partition Layout - MBR
# ============================================================================
# SD Card partition layout (MBR):
# Partition 1: boot (128MB, FAT32 LBA, bootable) - BOOT.BIN
# Partition 2: OFP_A (200MB, Linux) - Primary signed image
# Partition 3: OFP_B (200MB, Linux) - Update signed image
# Partition 4: rootfs (remainder) - Linux root filesystem
#
# Use partition numbers instead of flash addresses
# These are 0-based indices into the parsed partition array:
# part[0]=boot, part[1]=OFP_A, part[2]=OFP_B, part[3]=rootfs
WOLFBOOT_NO_PARTITIONS=1
CFLAGS_EXTRA+=-DBOOT_PART_A=1
CFLAGS_EXTRA+=-DBOOT_PART_B=2
# Disk read chunk size (512KB)
CFLAGS_EXTRA+=-DDISK_BLOCK_SIZE=0x80000
# Linux rootfs is on partition 4 (SD1 = mmcblk1)
CFLAGS_EXTRA+=-DLINUX_BOOTARGS_ROOT=\"/dev/mmcblk1p4\"
# ============================================================================
# Boot Memory Layout
# ============================================================================
# wolfBoot runs from DDR at 0x8000000 (same as U-Boot, loaded via BL31)
WOLFBOOT_ORIGIN=0x8000000
# Load Partition to RAM Address (Linux kernel loads here)
WOLFBOOT_LOAD_ADDRESS?=0x10000000
# DTS (Device Tree) load address
WOLFBOOT_LOAD_DTS_ADDRESS?=0x1000
# ============================================================================
# Required for test-app (even with WOLFBOOT_NO_PARTITIONS=1)
# ============================================================================
WOLFBOOT_PARTITION_BOOT_ADDRESS=0x80200000
WOLFBOOT_PARTITION_SIZE=0x4000000
WOLFBOOT_SECTOR_SIZE=0x1000
# ============================================================================
# Optional Debug Options (uncomment to enable)
# ============================================================================
# SDHCI driver debug logs
#CFLAGS_EXTRA+=-DDEBUG_SDHCI
# Disk layer debug logs
#CFLAGS_EXTRA+=-DDEBUG_DISK
# GPT partition debug logs
#CFLAGS_EXTRA+=-DDEBUG_GPT
# Disk read/write test at boot
#CFLAGS_EXTRA+=-DDISK_TEST

View File

@ -1984,28 +1984,50 @@ qemu-system-aarch64 -M raspi3b -m 1024 -serial stdio -kernel wolfboot_linux_rasp
## Xilinx Zynq UltraScale
Xilinx UltraScale+ ZCU102 (Aarch64)
AMD Zynq UltraScale+ MPSoC ZCU102 Evaluation Kit - Quad-core ARM Cortex-A53 (plus dual Cortex-R5).
See example .config file at `config/examples/zynqmp.config`.
Example build options (.config):
wolfBoot replaces U-Boot in the ZynqMP boot flow:
```
TARGET=zynq
ARCH=AARCH64
SIGN=RSA4096
HASH=SHA3
FSBL -> PMUFW -> BL31 (EL3) -> wolfBoot (EL2) -> Linux (EL1)
```
### Building Zynq with Xilinx tools (Vitis IDE)
wolfBoot runs from DDR at `0x8000000` (128MB, EL2, non-secure) for both QSPI and SD card boot. All clock, MIO, and DDR initialization is handled by the FSBL/PMUFW before wolfBoot starts.
This target supports **two boot paths**:
- **QSPI boot** (primary, production-style): `config/examples/zynqmp.config`
- **SD card boot** (MBR, A/B images): `config/examples/zynqmp_sdcard.config`
### Prerequisites
1. **Xilinx Vitis 2024.1 or newer**
- Set `VITIS_PATH` environment variable: `export VITIS_PATH=/opt/Xilinx/Vitis/2024.1`
2. **Toolchain**: `aarch64-none-elf-gcc`
3. **Pre-built firmware** (FSBL, PMUFW, BL31):
```sh
git clone --branch xlnx_rel_v2024.2 https://github.com/Xilinx/soc-prebuilt-firmware.git
export PREBUILT_DIR=$(pwd)/../soc-prebuilt-firmware/zcu102-zynqmp
```
### Configuration Options
Key configuration options:
- `ARCH=AARCH64` - ARM 64-bit architecture
- `TARGET=zynq` - ZynqMP platform target
- `SIGN=RSA4096` - RSA 4096-bit signatures
- `HASH=SHA3` - SHA3-384 hashing
- `ELF=1` - ELF loading support
### Building with Xilinx tools (Vitis IDE)
See [IDE/XilinxSDK/README.md](/IDE/XilinxSDK/README.md) for using Xilinx IDE
### Building Zynq with gcc-aarch64-linux-gnu
### Building with gcc-aarch64-linux-gnu
Requires `gcc-aarch64-linux-gnu` package.
Use `make CROSS_COMPILE=aarch64-linux-gnu-`
### Building Zynq with QNX
### Building with QNX
```sh
source ~/qnx700/qnxsdp-env.sh
@ -2014,17 +2036,196 @@ make clean
make CROSS_COMPILE=aarch64-unknown-nto-qnx7.0.0-
```
#### Testing Zynq with QEMU
### QSPI Boot (default)
Use `config/examples/zynqmp.config`.
```sh
cp config/examples/zynqmp.config .config
make clean
make
```
**QSPI layout**
| Partition | Size | Address | Description |
|-------------|--------|-------------|--------------------------------|
| Bootloader | - | 0x8000000 | wolfBoot in DDR (loaded by FSBL) |
| Primary | 42MB | 0x800000 | Boot partition in QSPI |
| Update | 42MB | 0x3A00000 | Update partition in QSPI |
| Swap | - | 0x63E0000 | Swap area in QSPI |
**Build BOOT.BIN for QSPI**
See [IDE/XilinxSDK/README.md](/IDE/XilinxSDK/README.md) for creating BOOT.BIN with the Xilinx IDE, or use the existing BIF file:
```sh
cp ${PREBUILT_DIR}/zynqmp_fsbl.elf .
cp ${PREBUILT_DIR}/pmufw.elf .
cp ${PREBUILT_DIR}/bl31.elf .
source ${VITIS_PATH}/settings64.sh
bootgen -arch zynqmp -image ./IDE/XilinxSDK/boot.bif -w -o BOOT.BIN
```
**Signing**
```sh
tools/keytools/sign --rsa4096 --sha3 /path/to/vmlinux.bin wolfboot_signing_private_key.der 1
```
**Testing with QEMU**
```sh
qemu-system-aarch64 -machine xlnx-zcu102 -cpu cortex-a53 -serial stdio -display none \
-device loader,file=wolfboot.bin,cpu-num=0
```
#### Signing Zynq
### SD Card Boot (MBR + A/B)
`tools/keytools/sign --rsa4096 --sha3 /srv/linux-rpi4/vmlinux.bin wolfboot_signing_private_key.der 1`
Use `config/examples/zynqmp_sdcard.config`. This uses the Arasan SDHCI controller (SD1 - external SD card slot on ZCU102) and an **MBR** partitioned SD card.
**Partition layout**
| Partition | Name | Size | Type | Contents |
|-----------|--------|-----------|-------------------------------|-------------------------------------------|
| 1 | boot | 128MB | FAT32 LBA (0x0c), bootable | BOOT.BIN (FSBL + PMUFW + BL31 + wolfBoot) |
| 2 | OFP_A | 200MB | Linux (0x83) | Primary signed firmware image |
| 3 | OFP_B | 200MB | Linux (0x83) | Update signed firmware image |
| 4 | rootfs | remainder | Linux (0x83) | Linux root filesystem |
**Build wolfBoot + sign test images**
```sh
cp config/examples/zynqmp_sdcard.config .config
make clean
make
make test-app/image.bin
IMAGE_HEADER_SIZE=1024 ./tools/keytools/sign --rsa4096 --sha3 test-app/image.elf wolfboot_signing_private_key.der 1
IMAGE_HEADER_SIZE=1024 ./tools/keytools/sign --rsa4096 --sha3 test-app/image.elf wolfboot_signing_private_key.der 2
```
**Build BOOT.BIN for SD card**
Copy the pre-built firmware and generate BOOT.BIN:
```sh
cp ${PREBUILT_DIR}/zynqmp_fsbl.elf .
cp ${PREBUILT_DIR}/pmufw.elf .
cp ${PREBUILT_DIR}/bl31.elf .
source ${VITIS_PATH}/settings64.sh
bootgen -arch zynqmp -image ./tools/scripts/zynqmp_sd_boot.bif -w -o BOOT.BIN
```
The BIF file (`zynqmp_sd_boot.bif`) configures the boot chain:
- FSBL at A53-0 (bootloader)
- PMUFW at PMU
- BL31 at EL3 with TrustZone
- wolfBoot at EL2
**Create SD image**
```sh
dd if=/dev/zero of=sdcard.img bs=1M count=1024
sfdisk sdcard.img <<EOF
label: dos
1 : start=2048, size=128M, type=c, bootable
2 : size=200M, type=83
3 : size=200M, type=83
4 : type=83
EOF
SECTOR2=$(sfdisk -d sdcard.img | awk '/sdcard.img2/ {for (i=1;i<=NF;i++) if ($i ~ /start=/) {gsub(/start=|,/, "", $i); print $i}}')
SECTOR3=$(sfdisk -d sdcard.img | awk '/sdcard.img3/ {for (i=1;i<=NF;i++) if ($i ~ /start=/) {gsub(/start=|,/, "", $i); print $i}}')
dd if=test-app/image_v1_signed.bin of=sdcard.img bs=512 seek=$SECTOR2 conv=notrunc
dd if=test-app/image_v2_signed.bin of=sdcard.img bs=512 seek=$SECTOR3 conv=notrunc
```
**Provision SD card**
```sh
sudo dd if=sdcard.img of=/dev/sdX bs=4M status=progress conv=fsync
sync
sudo mkfs.vfat -F 32 -n BOOT /dev/sdX1
sudo mount /dev/sdX1 /mnt
sudo cp BOOT.BIN /mnt/
sudo umount /mnt
sudo fdisk -l /dev/sdX
```
Or just mount and copy the BOOT.BIN and "dd" the partitions
```sh
# Mount the FAT boot partition and copy just the updated BOOT.BIN
sudo mount /dev/sdX1 /mnt && sudo cp BOOT.BIN /mnt/ && sudo umount /mnt && sync
# Write the signed image to partition 2 (P:A) and partition 3 (P:B)
sudo dd if=test-app/image_v1_signed.bin of=/dev/sdX2 bs=4k
sudo dd if=test-app/image_v1_signed.bin of=/dev/sdX3 bs=4k
```
**Boot Mode**
Set the ZCU102 boot mode switches (SW6) for SD card boot:
| Boot Mode | MODE Pins 3:0 | SW6[4:1] |
| --------- | ------------- | -------------- |
| JTAG | 0 0 0 0 | on, on, on, on |
| QSPI32 | 0 0 1 0 | on, on, off, on |
| SD1 | 1 1 1 0 | off, off, off, on |
**Debug**
Enable SDHCI debug output by uncommenting in the config:
```
CFLAGS_EXTRA+=-DDEBUG_SDHCI
CFLAGS_EXTRA+=-DDEBUG_DISK
```
**Example Boot Output**
```
wolfBoot Secure Boot
Current EL: 2
PMUFW Ver: 1.1
SDHCI: SDCard mode
Reading MBR...
Found MBR partition table
MBR part 1: type=0x0C, start=0x100000, size=128MB
MBR part 2: type=0x83, start=0x8100000, size=200MB
MBR part 3: type=0x83, start=0x14900000, size=200MB
MBR part 4: type=0x83, start=0x21100000, size=71MB
Total partitions on disk0: 4
Checking primary OS image in 0,1...
Checking secondary OS image in 0,2...
Versions, A:1 B:1
Load address 0x10000000
Attempting boot from P:A
Boot partition: 0x8038AA0 (sz 211096, ver 0x1, type 0x401)
Loading image from disk...done
Boot partition: 0x8038AA0 (sz 211096, ver 0x1, type 0x401)
Checking image integrity...done
Verifying image signature...done
Firmware Valid.
Loading elf at 0x10000000
Found valid elf64 (little endian)
Program Headers 1 (size 56)
Load 29888 bytes (offset 0x10000) to 0x10000000 (p 0x10000000)
Clear 17540 bytes at 0x10000000 (p 0x10000000)
Entry point 0x10000000
Booting at 10000000
do_boot: entry=0x10000000, EL=2
do_boot: dts=0x00000000
===========================================
wolfBoot Test Application - AMD ZynqMP
===========================================
Current EL: 2
Boot mode: Disk-based (MBR partitions)
Application running successfully!
Entering idle loop...
```
## Versal Gen 1 VMK180
@ -2313,7 +2514,6 @@ make test-app/image.bin
dd if=/dev/zero of=sdcard.img bs=1M count=1024
sfdisk sdcard.img <<EOF
label: dos
unit: sectors
1 : start=2048, size=128M, type=c, bootable
2 : size=200M, type=83
@ -2343,8 +2543,8 @@ sudo fdisk -l /dev/sdX
| Boot Mode | MODE Pins 3:0 | Mode SW1[4:1] |
| --------- | ------------- | -------------- |
| JTAG | 0 0 0 0 | on, on, on, on |
| QSPI32 | 0 0 1 0 | on, on, off,on |
| SD1 | 1 1 1 0 | off,off,off,on |
| QSPI32 | 0 0 1 0 | on, on, off, on |
| SD1 | 1 1 1 0 | off, off, off, on |
## Cypress PSoC-6

View File

@ -1563,7 +1563,9 @@ void hal_init(void)
wolfBoot_printf(bootMsg);
wolfBoot_printf("Current EL: %d\n", current_el());
#if defined(EXT_FLASH) && (EXT_FLASH == 1)
qspi_init();
#endif
pmuVer = pmu_get_version();
wolfBoot_printf("PMUFW Ver: %d.%d\n",
@ -1581,7 +1583,7 @@ void hal_init(void)
void hal_prepare_boot(void)
{
#if GQPI_USE_4BYTE_ADDR == 1
#if defined(EXT_FLASH) && (EXT_FLASH == 1) && GQPI_USE_4BYTE_ADDR == 1
/* Exit 4-byte address mode */
int ret = qspi_exit_4byte_addr(&mDev);
if (ret != GQSPI_CODE_SUCCESS)
@ -1594,6 +1596,24 @@ void hal_prepare_boot(void)
mDev.qnx = NULL;
}
#endif
/* Clean and invalidate caches for the loaded application.
* The application was written to RAM via D-cache, but the CPU will
* fetch instructions via I-cache from main memory. We must:
* 1. Clean D-cache (flush dirty data to memory)
* 2. Invalidate I-cache (ensure fresh instruction fetch) */
__asm__ volatile("dsb sy");
{
uintptr_t addr;
uintptr_t end = WOLFBOOT_LOAD_ADDRESS + APP_CACHE_FLUSH_SIZE;
for (addr = WOLFBOOT_LOAD_ADDRESS; addr < end; addr += CACHE_LINE_SIZE) {
__asm__ volatile("dc civac, %0" : : "r"(addr));
}
}
__asm__ volatile("dsb sy");
__asm__ volatile("ic iallu");
__asm__ volatile("dsb sy");
__asm__ volatile("isb");
}
/* Flash functions must be relocated to RAM for execution */
@ -1779,7 +1799,13 @@ void RAMFUNCTION ext_flash_unlock(void)
#ifdef MMU
void* hal_get_dts_address(void)
{
#ifdef WOLFBOOT_DTS_BOOT_ADDRESS
return (void*)WOLFBOOT_DTS_BOOT_ADDRESS;
#elif defined(WOLFBOOT_LOAD_DTS_ADDRESS)
return (void*)WOLFBOOT_LOAD_DTS_ADDRESS;
#else
return NULL;
#endif
}
int hal_dts_fixup(void* dts_addr)
@ -1834,4 +1860,336 @@ static int test_ext_flash(QspiDev_t* dev)
}
#endif /* TEST_EXT_FLASH */
/* ============================================================================
* SDHCI (SD Card / eMMC) Platform Support
* ============================================================================
* Platform-specific hooks for the generic SDHCI driver (src/sdhci.c).
* ZynqMP uses the Arasan SDHCI controller with standard register layout.
* The generic driver uses Cadence SD4HC register offsets, so we translate:
* - HRS registers at 0x000-0x01F (Cadence-specific: reset, PHY, eMMC mode)
* - SRS registers at 0x200-0x2FF (standard SDHCI mapped at offset +0x200)
* Arasan uses standard SDHCI registers at 0x000-0x0FF (no 0x200 offset).
*/
#if defined(DISK_SDCARD) || defined(DISK_EMMC)
#include "sdhci.h"
/* SD controller base address selection:
* SD0 (ZYNQMP_SD0_BASE = 0xFF160000) - internal, typically eMMC
* SD1 (ZYNQMP_SD1_BASE = 0xFF170000) - external SD card slot on ZCU102
*/
#ifndef ZYNQMP_SDHCI_BASE
#define ZYNQMP_SDHCI_BASE ZYNQMP_SD1_BASE
#endif
#define CADENCE_SRS_OFFSET 0x200
/* Legacy SDMA system address register (standard SDHCI offset 0x00).
* The Arasan SDHCI v3.0 on ZynqMP does not support Host Version 4 Enable
* (HV4E) mode. The generic SDHCI driver uses HV4E-style 64-bit DMA
* addressing via SRS22/SRS23 (offsets 0x58/0x5C), but on this controller
* we must use the legacy SRS00 register (offset 0x00) for SDMA addresses.
* The platform reg_read/reg_write functions transparently redirect
* SRS22 <-> SRS00, making legacy SDMA work without changes to sdhci.c. */
#define STD_SDHCI_SDMA_ADDR 0x00 /* SDMA System Address (32-bit) */
#define STD_SDHCI_HOST_CTRL2 0x3C /* Auto CMD Err(16) + Host Ctrl 2(16) */
/* Standard SDHCI register offsets (byte addresses within the controller) */
#define STD_SDHCI_HOST_CTRL1 0x28 /* Host Control 1 (8-bit) */
#define STD_SDHCI_POWER_CTRL 0x29 /* Power Control (8-bit) */
#define STD_SDHCI_BLKGAP_CTRL 0x2A /* Block Gap Control (8-bit) */
#define STD_SDHCI_WAKEUP_CTRL 0x2B /* Wakeup Control (8-bit) */
#define STD_SDHCI_CLK_CTRL 0x2C /* Clock Control (16-bit) */
#define STD_SDHCI_TIMEOUT_CTRL 0x2E /* Timeout Control (8-bit) */
#define STD_SDHCI_SW_RESET 0x2F /* Software Reset (8-bit) */
/* Software Reset register bits (at offset 0x2F, 8-bit register) */
#define STD_SDHCI_SRA 0x01 /* Software Reset for All */
#define STD_SDHCI_SRCMD 0x02 /* Software Reset for CMD Line */
#define STD_SDHCI_SRDAT 0x04 /* Software Reset for DAT Line */
/* Handle reads from Cadence HRS registers (0x000-0x1FF) */
static uint32_t zynqmp_sdhci_hrs_read(uint32_t hrs_offset)
{
volatile uint8_t *base = (volatile uint8_t *)ZYNQMP_SDHCI_BASE;
switch (hrs_offset) {
case 0x000: /* HRS00 - Software Reset */
{
/* Map standard SRA (byte at 0x2F) to Cadence SWR (bit 0) */
uint8_t val = *((volatile uint8_t *)(base + STD_SDHCI_SW_RESET));
return (val & STD_SDHCI_SRA) ? 1U : 0U;
}
case 0x010: /* HRS04 - PHY access (Cadence-specific) */
/* Return ACK set to prevent wait loops from hanging */
return (1U << 26); /* SDHCI_HRS04_UIS_ACK */
default:
/* HRS01 (debounce), HRS02, HRS06 (eMMC mode) - not applicable */
return 0;
}
}
/* Handle writes to Cadence HRS registers (0x000-0x1FF) */
static void zynqmp_sdhci_hrs_write(uint32_t hrs_offset, uint32_t val)
{
volatile uint8_t *base = (volatile uint8_t *)ZYNQMP_SDHCI_BASE;
switch (hrs_offset) {
case 0x000: /* HRS00 - Software Reset */
if (val & 1U) {
/* Issue SRA via 8-bit write to offset 0x2F (per SDHCI spec).
* The Arasan controller requires byte-level access for the
* Software Reset register. */
*((volatile uint8_t *)(base + STD_SDHCI_SW_RESET)) = STD_SDHCI_SRA;
}
break;
default:
/* HRS01, HRS04, HRS06 - not applicable on ZynqMP, ignore */
break;
}
}
/* Register access functions for generic SDHCI driver.
* Translates Cadence SD4HC register offsets to standard Arasan SDHCI layout.
*
* IMPORTANT: The Arasan SDHCI on ZynqMP requires specific register access
* widths matching the SDHCI specification (see Xilinx SDPS driver reference):
* - Host Control 1 (0x28): 8-bit
* - Power Control (0x29): 8-bit
* - Clock Control (0x2C): 16-bit
* - Timeout Control (0x2E): 8-bit
* - Software Reset (0x2F): 8-bit
* The Cadence driver uses 32-bit SRS10/SRS11 registers that span these byte
* offsets. We decompose 32-bit writes into the correct access widths. */
uint32_t sdhci_reg_read(uint32_t offset)
{
volatile uint8_t *base = (volatile uint8_t *)ZYNQMP_SDHCI_BASE;
/* Cadence SRS registers (0x200+) -> standard SDHCI (subtract 0x200) */
if (offset >= CADENCE_SRS_OFFSET) {
uint32_t std_off = offset - CADENCE_SRS_OFFSET;
/* SRS22 (0x58) -> SRS00 (0x00): Legacy SDMA address register */
if (std_off == 0x58) {
return *((volatile uint32_t *)(base + STD_SDHCI_SDMA_ADDR));
}
/* SRS23 (0x5C) -> 0: No 64-bit addressing on SDHCI v3.0 */
if (std_off == 0x5C) {
return 0;
}
{
uint32_t val = *((volatile uint32_t *)(base + std_off));
/* Mask out A64S from Capabilities to prevent HV4E init */
if (std_off == 0x40) { /* SRS16 - Capabilities */
val &= ~SDHCI_SRS16_A64S;
}
return val;
}
}
/* Cadence HRS registers (0x000-0x1FF) -> translate to standard equivalents */
return zynqmp_sdhci_hrs_read(offset);
}
void sdhci_reg_write(uint32_t offset, uint32_t val)
{
volatile uint8_t *base = (volatile uint8_t *)ZYNQMP_SDHCI_BASE;
if (offset >= CADENCE_SRS_OFFSET) {
uint32_t std_off = offset - CADENCE_SRS_OFFSET;
/* SRS10 (Cadence 0x228) = standard 0x28-0x2B:
* 0x28: Host Control 1 (8-bit)
* 0x29: Power Control (8-bit)
* 0x2A: Block Gap Control (8-bit)
* 0x2B: Wakeup Control (8-bit) */
if (std_off == 0x28) {
*((volatile uint8_t *)(base + STD_SDHCI_HOST_CTRL1)) =
(uint8_t)(val & 0xFF);
*((volatile uint8_t *)(base + STD_SDHCI_POWER_CTRL)) =
(uint8_t)((val >> 8) & 0xFF);
*((volatile uint8_t *)(base + STD_SDHCI_BLKGAP_CTRL)) =
(uint8_t)((val >> 16) & 0xFF);
*((volatile uint8_t *)(base + STD_SDHCI_WAKEUP_CTRL)) =
(uint8_t)((val >> 24) & 0xFF);
return;
}
/* SRS11 (Cadence 0x22C) = standard 0x2C-0x2F:
* 0x2C: Clock Control (16-bit)
* 0x2E: Timeout Control (8-bit)
* 0x2F: Software Reset (8-bit) */
if (std_off == 0x2C) {
*((volatile uint16_t *)(base + STD_SDHCI_CLK_CTRL)) =
(uint16_t)(val & 0xFFFF);
*((volatile uint8_t *)(base + STD_SDHCI_TIMEOUT_CTRL)) =
(uint8_t)((val >> 16) & 0xFF);
*((volatile uint8_t *)(base + STD_SDHCI_SW_RESET)) =
(uint8_t)((val >> 24) & 0xFF);
return;
}
/* SRS22 (0x58) -> SRS00 (0x00): Legacy SDMA address register.
* The generic driver writes the DMA buffer address here for HV4E mode.
* Redirect to SRS00 which is the legacy SDMA system address register.
* Writing SRS00 also restarts DMA after a boundary interrupt. */
if (std_off == 0x58) {
*((volatile uint32_t *)(base + STD_SDHCI_SDMA_ADDR)) = val;
return;
}
/* SRS23 (0x5C) -> no-op: No 64-bit addressing on SDHCI v3.0 */
if (std_off == 0x5C) {
return;
}
/* SRS15 (0x3C) -> mask out HV4E and A64 bits.
* The generic driver enables HV4E for SDMA, but the Arasan SDHCI v3.0
* does not support it. These are reserved bits on v3.0 and must not
* be set. */
if (std_off == STD_SDHCI_HOST_CTRL2) {
val &= ~(SDHCI_SRS15_HV4E | SDHCI_SRS15_A64);
}
/* All other SRS registers: 32-bit write */
*((volatile uint32_t *)(base + std_off)) = val;
return;
}
/* Cadence HRS registers (0x000-0x1FF) -> translate to standard equivalents */
zynqmp_sdhci_hrs_write(offset, val);
}
/* Platform initialization - called from sdhci_init()
* FSBL already initializes the SD controller on ZynqMP when booting from SD,
* so we don't need to configure clocks/reset (CRL_APB registers).
*
* However, the FSBL uses GPIO-based card detect (polling MIO45 as GPIO)
* rather than the SDHCI controller's built-in CD mechanism. The default
* IOU_SLCR SD_CONFIG_REG2 slot type is "Removable" (00), but MIO45 is not
* routed to the SDHCI controller as a CD function. This causes the Arasan
* SDHCI to report Card Inserted=0 and gate writes to Bus Power and SD Clock
* Enable registers.
*
* Fix: Set SD1 slot type to "Embedded" (01) in IOU_SLCR SD_CONFIG_REG2.
* This makes the controller always assert Card Inserted and Card State
* Stable, allowing normal SDHCI register access. */
void sdhci_platform_init(void)
{
uint32_t reg;
volatile int i;
uint32_t slot_mask;
uint32_t slot_shift;
uint32_t reset_bit;
/* Set the selected SDx slot type to "Embedded Slot for One Device" (01).
* This feeds into the SDHCI Capabilities register bits 31:30 and makes
* the controller report card as always present, bypassing the physical
* CD pin that is not connected to the SDHCI controller on ZCU102. */
if (ZYNQMP_SDHCI_BASE == ZYNQMP_SD0_BASE) {
slot_mask = SD_CONFIG_REG2_SD0_SLOTTYPE_MASK;
slot_shift = SD_CONFIG_REG2_SD0_SLOTTYPE_SHIFT;
reset_bit = RST_LPD_IOU2_SDIO0;
} else {
slot_mask = SD_CONFIG_REG2_SD1_SLOTTYPE_MASK;
slot_shift = SD_CONFIG_REG2_SD1_SLOTTYPE_SHIFT;
reset_bit = RST_LPD_IOU2_SDIO1;
}
reg = IOU_SLCR_SD_CONFIG_REG2;
reg &= ~slot_mask;
reg |= (1UL << slot_shift); /* 01 = Embedded */
IOU_SLCR_SD_CONFIG_REG2 = reg;
/* The SDHCI Capabilities register latches IOU_SLCR values on controller
* reset. Issue SDIOx reset via CRL_APB so the controller picks up the
* new slot type configuration. */
RST_LPD_IOU2 |= reset_bit; /* Assert SDIOx reset */
for (i = 0; i < 100; i++) {} /* Brief delay */
RST_LPD_IOU2 &= ~reset_bit; /* De-assert SDIOx reset */
for (i = 0; i < 1000; i++) {} /* Wait for controller ready */
#ifdef DEBUG_SDHCI
{
volatile uint8_t *base = (volatile uint8_t *)ZYNQMP_SDHCI_BASE;
uint32_t val;
wolfBoot_printf("sdhci_platform_init: SD%d at 0x%x\n",
(ZYNQMP_SDHCI_BASE == ZYNQMP_SD0_BASE) ? 0 : 1,
(unsigned int)ZYNQMP_SDHCI_BASE);
wolfBoot_printf(" SD_CONFIG_REG2: 0x%x\n",
(unsigned int)IOU_SLCR_SD_CONFIG_REG2);
/* Read standard SDHCI registers to verify controller access */
val = *((volatile uint32_t *)(base + 0x24)); /* Present State */
wolfBoot_printf(" Present State: 0x%x\n", (unsigned int)val);
val = *((volatile uint32_t *)(base + 0x40)); /* Capabilities */
wolfBoot_printf(" Capabilities: 0x%x\n", (unsigned int)val);
(void)val;
}
#endif
}
/* Platform interrupt setup - called from sdhci_init()
* Using polling mode for simplicity - no GIC setup needed */
void sdhci_platform_irq_init(void)
{
#ifdef DEBUG_SDHCI
wolfBoot_printf("sdhci_platform_irq_init: Using polling mode\n");
#endif
}
/* Platform bus mode selection - called from sdhci_init() after software reset */
void sdhci_platform_set_bus_mode(int is_emmc)
{
(void)is_emmc;
#ifdef DEBUG_SDHCI
wolfBoot_printf("sdhci_platform_set_bus_mode: is_emmc=%d\n", is_emmc);
#endif
}
/* DMA cache maintenance - called from sdhci_transfer() around SDMA operations.
* The SDMA engine transfers data directly to/from physical memory, bypassing
* the CPU's L1/L2 caches. We must ensure cache coherency:
* - Before DMA write (cardmemory): clean D-cache so DMA reads correct data
* - After DMA read (cardmemory): invalidate D-cache so CPU sees new data */
void sdhci_platform_dma_prepare(void *buf, uint32_t sz, int is_write)
{
uintptr_t addr;
uintptr_t start = (uintptr_t)buf & ~(CACHE_LINE_SIZE - 1);
uintptr_t end = (uintptr_t)buf + sz;
if (is_write) {
/* Clean D-cache: flush dirty lines to memory for DMA to read */
for (addr = start; addr < end; addr += CACHE_LINE_SIZE) {
__asm__ volatile("dc cvac, %0" : : "r"(addr) : "memory");
}
} else {
/* Invalidate D-cache: discard stale lines before DMA writes to memory */
for (addr = start; addr < end; addr += CACHE_LINE_SIZE) {
__asm__ volatile("dc civac, %0" : : "r"(addr) : "memory");
}
}
__asm__ volatile("dsb sy" : : : "memory");
}
void sdhci_platform_dma_complete(void *buf, uint32_t sz, int is_write)
{
/* 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");
}
__asm__ volatile("dsb sy" : : : "memory");
}
}
#endif /* DISK_SDCARD || DISK_EMMC */
#endif /* TARGET_zynq */

View File

@ -32,6 +32,11 @@
#ifndef EL2_HYPERVISOR
#define EL2_HYPERVISOR 1
#endif
/* Cache line size for Cortex-A53 (AArch64) */
#define CACHE_LINE_SIZE 64
/* Region size to flush before booting application */
#define APP_CACHE_FLUSH_SIZE (1 * 1024 * 1024) /* 1MB */
#ifndef EL1_NONSECURE
#define EL1_NONSECURE 0
#endif
@ -58,8 +63,8 @@
/* IOP System-level Control */
#define IOU_SLCR_BASSE 0xFF180000
#define IOU_TAPDLY_BYPASS_ADDR (IOU_SLCR_BASSE + 0x390)
#define IOU_SLCR_BASE 0xFF180000
#define IOU_TAPDLY_BYPASS_ADDR (IOU_SLCR_BASE + 0x390)
#define IOU_TAPDLY_BYPASS (*((volatile uint32_t*)IOU_TAPDLY_BYPASS_ADDR))
#define IOU_TAPDLY_BYPASS_LQSPI_RX (1UL << 2) /* LQSPI Tap Delay Enable on Rx Clock signal. 0: enable. 1: disable (bypass tap delay). */
@ -398,7 +403,29 @@
#define QSPI_REF_CTRL_DIVISOR0(n) (((n) << 8) & QSPI_REF_CTRL_DIVISOR0_MASK)
#define QSPI_REF_CTRL_DIVISOR1_MASK (0x3F << 16)
#define QSPI_REF_CTRL_DIVISOR1(n) (((n) << 16) & QSPI_REF_CTRL_DIVISOR0_MASK)
#define QSPI_REF_CTRL_DIVISOR1(n) (((n) << 16) & QSPI_REF_CTRL_DIVISOR1_MASK)
/* SD/SDHCI Controller Base Addresses */
#define ZYNQMP_SD0_BASE 0xFF160000UL
#define ZYNQMP_SD1_BASE 0xFF170000UL
/* SD/SDIO Reference Clock Control (CRL_APB) */
#define SDIO0_REF_CTRL (*((volatile uint32_t*)(CRL_APB_BASE + 0x6C)))
#define SDIO1_REF_CTRL (*((volatile uint32_t*)(CRL_APB_BASE + 0x70)))
/* SD/SDIO Reset Control (CRL_APB RST_LPD_IOU2) */
#define RST_LPD_IOU2 (*((volatile uint32_t*)(CRL_APB_BASE + 0x0238)))
#define RST_LPD_IOU2_SDIO0 (1UL << 5)
#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_BASE + 0x320)))
/* SD1 Slot Type: 00=Removable, 01=Embedded, 10=Shared Bus */
#define SD_CONFIG_REG2_SD1_SLOTTYPE_SHIFT 28
#define SD_CONFIG_REG2_SD1_SLOTTYPE_MASK 0x30000000UL
/* SD0 Slot Type */
#define SD_CONFIG_REG2_SD0_SLOTTYPE_SHIFT 12
#define SD_CONFIG_REG2_SD0_SLOTTYPE_MASK 0x00003000UL
/* Configuration Security Unit (CSU) */

View File

@ -12,8 +12,11 @@ _EL2_STACK_SIZE = DEFINED(_EL2_STACK_SIZE) ? _EL2_STACK_SIZE : 1024;
MEMORY
{
/* psu_ddr_0_MEM_0 : ORIGIN = 0x0, LENGTH = 0x80000000 */
/* Use the end of DDR0 for wolfBoot (reserve 1MB) */
psu_ddr_0_MEM_0 : ORIGIN = 0x7FF00000, LENGTH = 0x100000
/* wolfBoot DDR location (2MB reserved):
* Loaded by FSBL/BL31 to DDR at 0x8000000 (128MB)
* Same address used for both QSPI and SD card boot
*/
psu_ddr_0_MEM_0 : ORIGIN = 0x8000000, LENGTH = 0x200000
psu_ddr_1_MEM_0 : ORIGIN = 0x800000000, LENGTH = 0x80000000
psu_ocm_ram_0_MEM_0 : ORIGIN = 0xFFFC0000, LENGTH = 0x40000
psu_qspi_linear_0_MEM_0 : ORIGIN = 0xC0000000, LENGTH = 0x20000000
@ -38,7 +41,7 @@ SECTIONS
*(.gnu.linkonce.t.*)
*(.plt)
*(.gnu_warning)
*(.gcc_execpt_table)
*(.gcc_except_table)
*(.glue_7)
*(.glue_7t)
*(.ARM.extab)
@ -197,7 +200,7 @@ SECTIONS
.ARM.exidx : {
__exidx_start = .;
*(.ARM.exidx*)
*(.gnu.linkonce.armexidix.*.*)
*(.gnu.linkonce.armexidx.*.*)
__exidx_end = .;
} > psu_ddr_0_MEM_0

View File

@ -212,6 +212,8 @@
/* SRS10 - Host Control 1 / Power / Block Gap / Wakeup */
#define SDHCI_SRS10_DTW (1U << 1) /* Data transfer width (4-bit) */
#define SDHCI_SRS10_EDTW (1U << 5) /* Extended data transfer width (8-bit) */
#define SDHCI_SRS10_CDTL (1U << 6) /* Card Detect Test Level */
#define SDHCI_SRS10_CDSS (1U << 7) /* Card Detect Signal Selection */
#define SDHCI_SRS10_HSE (1U << 2) /* High speed enable */
#define SDHCI_SRS10_BP (1U << 8) /* Bus power */
#define SDHCI_SRS10_BVS_MASK (0x7U << 9)

View File

@ -23,6 +23,7 @@
#include "image.h"
#include "loader.h"
#include "printf.h"
#include "wolfboot/wolfboot.h"
/* Include platform-specific header for EL configuration defines */
@ -130,7 +131,10 @@ void RAMFUNCTION do_boot(const uint32_t *app_offset, const uint32_t* dts_offset)
void RAMFUNCTION do_boot(const uint32_t *app_offset)
#endif
{
wolfBoot_printf("do_boot: entry=0x%08x, EL=%d\n",
(uint32_t)(uintptr_t)app_offset, current_el());
#ifdef MMU
wolfBoot_printf("do_boot: dts=0x%08x\n", (uint32_t)(uintptr_t)dts_offset);
hal_dts_fixup((uint32_t*)dts_offset);
#endif
@ -155,6 +159,7 @@ void RAMFUNCTION do_boot(const uint32_t *app_offset)
#else
uintptr_t dts = 0;
#endif
wolfBoot_printf("do_boot: EL2->EL1 via ERET\n");
el2_to_el1_boot((uintptr_t)app_offset, dts);
}
#else

View File

@ -34,6 +34,22 @@
#include "hal.h"
#include "disk.h"
/* ============================================================================
* Platform DMA cache maintenance (weak defaults - override in HAL)
* ============================================================================ */
#ifndef SDHCI_SDMA_DISABLED
void __attribute__((weak)) sdhci_platform_dma_prepare(
void *buf, uint32_t sz, int is_write)
{
(void)buf; (void)sz; (void)is_write;
}
void __attribute__((weak)) sdhci_platform_dma_complete(
void *buf, uint32_t sz, int is_write)
{
(void)buf; (void)sz; (void)is_write;
}
#endif
/* ============================================================================
* Internal state
* ============================================================================ */
@ -368,7 +384,7 @@ static uint32_t sdhci_set_clock(uint32_t clock_khz)
reg = SDHCI_REG(SDHCI_SRS11);
reg &= ~(SDHCI_SRS11_SDCFSL_MASK | SDHCI_SRS11_SDCFSH_MASK);
reg |= (((mclk & 0x0FF) << SDHCI_SRS11_SDCFSL_SHIFT) & SDHCI_SRS11_SDCFSL_MASK); /* lower 8 bits */
reg |= (((mclk & 0x300) << SDHCI_SRS11_SDCFSH_SHIFT) & SDHCI_SRS11_SDCFSH_SHIFT); /* upper 2 bits */
reg |= (((mclk & 0x300) >> 2) & SDHCI_SRS11_SDCFSH_MASK); /* upper 2 bits */
reg |= SDHCI_SRS11_ICE; /* clock enable */
reg &= ~SDHCI_SRS11_CGS; /* select clock */
SDHCI_REG_SET(SDHCI_SRS11, reg);
@ -560,6 +576,13 @@ static int sdcard_power_init_seq(uint32_t voltage)
{
/* Set power to specified voltage */
int status = sdhci_set_power(voltage);
#ifdef DEBUG_SDHCI
wolfBoot_printf("sdcard_power_init: power status=%d, SRS09=0x%x, "
"SRS10=0x%x, SRS11=0x%x, SRS12=0x%x\n",
status,
SDHCI_REG(SDHCI_SRS09), SDHCI_REG(SDHCI_SRS10),
SDHCI_REG(SDHCI_SRS11), SDHCI_REG(SDHCI_SRS12));
#endif
if (status == 0) {
/* send CMD0 (go idle) to reset card */
status = sdhci_cmd(MMC_CMD0_GO_IDLE, 0, SDHCI_RESP_NONE);
@ -1183,10 +1206,16 @@ static int sdhci_transfer(int dir, uint32_t cmd_index, uint32_t block_addr,
/* SDMA mode with Host Version 4 enable.
* HV4E is required for SDMA to use the 64-bit address registers
* (SRS22/SRS23) instead of the legacy 32-bit register (SRS00).
* A64 is cleared in SRS15 to use 32-bit DMA addressing. */
* A64 is cleared in SRS15 to use 32-bit DMA addressing.
* Note: Platform may redirect SRS22/SRS23 to SRS00 for legacy
* SDMA on controllers that don't support HV4E. */
sdhci_reg_or(SDHCI_SRS10, SDHCI_SRS10_DMA_SDMA);
sdhci_reg_or(SDHCI_SRS15, SDHCI_SRS15_HV4E);
sdhci_reg_and(SDHCI_SRS15, ~SDHCI_SRS15_A64);
/* Platform DMA cache maintenance before transfer */
sdhci_platform_dma_prepare(buf, sz, dir == SDHCI_DIR_WRITE);
/* Set SDMA address */
SDHCI_REG_SET(SDHCI_SRS22, (uint32_t)(uintptr_t)buf);
SDHCI_REG_SET(SDHCI_SRS23, (uint32_t)(((uint64_t)(uintptr_t)buf) >> 32));
@ -1223,6 +1252,9 @@ static int sdhci_transfer(int dir, uint32_t cmd_index, uint32_t block_addr,
}
}
sdhci_disable_sdma_interrupts();
/* Platform DMA cache maintenance after transfer */
sdhci_platform_dma_complete(buf, sz, dir == SDHCI_DIR_WRITE);
}
else {
/* Blocking mode - buffer ready flag differs for read vs write */
@ -1407,6 +1439,7 @@ int sdhci_init(void)
/* check if card inserted and stable */
reg = SDHCI_REG(SDHCI_SRS09);
#ifndef SDHCI_FORCE_CARD_DETECT
if ((reg & SDHCI_SRS09_CSS) == 0) {
/* card not inserted or not stable */
return -1;
@ -1419,6 +1452,7 @@ int sdhci_init(void)
return -1;
}
#endif
#endif /* !SDHCI_FORCE_CARD_DETECT */
/* Start in 1-bit bus mode */
reg = SDHCI_REG(SDHCI_SRS10);

View File

@ -1,6 +1,6 @@
/* app_zynq.c
*
* Test bare-metal boot application
* Test bare-metal boot application for AMD ZynqMP ZCU102
*
* Copyright (C) 2025 wolfSSL Inc.
*
@ -21,19 +21,56 @@
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335, USA
*/
#include <stdlib.h>
#include <stdint.h>
#include <string.h>
#include "wolfboot/wolfboot.h"
#include "printf.h"
#ifdef TARGET_zynq
volatile uint32_t time_elapsed = 0;
void main(void) {
/* Provide current_el() for hal/zynq.o (normally in boot_aarch64.c) */
unsigned int current_el(void)
{
unsigned long el;
__asm__ volatile("mrs %0, CurrentEL" : "=r" (el) : : "cc");
return (unsigned int)((el >> 2) & 0x3U);
}
/* Wait for reboot */
while(1)
;
/* Stub for QSPI DMA code in hal/zynq.o (not used with SD card boot) */
void flush_dcache_range(unsigned long start, unsigned long end)
{
(void)start;
(void)end;
}
void main(void)
{
#ifdef WOLFBOOT_FIXED_PARTITIONS
uint32_t boot_version, update_version;
#endif
wolfBoot_printf("\n\n");
wolfBoot_printf("===========================================\n");
wolfBoot_printf(" wolfBoot Test Application - AMD ZynqMP\n");
wolfBoot_printf("===========================================\n\n");
wolfBoot_printf("Current EL: %d\n", current_el());
#ifdef WOLFBOOT_FIXED_PARTITIONS
boot_version = wolfBoot_get_image_version(PART_BOOT);
update_version = wolfBoot_get_image_version(PART_UPDATE);
wolfBoot_printf("BOOT: Version: %d (0x%08x)\n", boot_version, boot_version);
wolfBoot_printf("UPDATE: Version: %d (0x%08x)\n", update_version, update_version);
#else
wolfBoot_printf("Boot mode: Disk-based (MBR partitions)\n");
#endif
wolfBoot_printf("Application running successfully!\n");
wolfBoot_printf("\nEntering idle loop...\n");
/* Idle loop */
while (1) {
__asm__ volatile("wfi");
}
}
#endif /** TARGET_zynq **/

View File

@ -0,0 +1,225 @@
; Zynq UltraScale+ ZCU102 Quad SPI FLASH Programming Script
;
; S(D)RAM : 0xFFFC1000
; Generic Quad-SPI Controller base: 0xFF0F0000
; FLASH: MT25QU512 (Micron)
;
; Based on Lauterbach TRACE32 ZCU102 QSPI demo scripts.
LOCAL &arg1
ENTRY &arg1
&arg1=STRing.UPpeR("&arg1") // for example "PREPAREONLY"
&dualqspi=1 ; dual(1) or single(0)
; Adjust to your TRACE32 installation path
LOCAL &pdd
&pdd="C:/T32/demo/arm"
SYStem.RESet
SYStem.CPU ZYNQ-ULTRASCALE+-APU
SYStem.MemAccess DAP
CORE.ASSIGN 1.
ETM.OFF
Trace.DISable
; <temporarily switch to BOOTMODE=JTAG>
; this sequence forces the SoC to use BOOTMODE=JTAG
; a SRST is issued using the debug logic
; we use the first A53 for flash programming
SYStem.Option ResBreak OFF
SYStem.Option EnReset OFF
SYStem.Option TRST OFF
DO &pdd/hardware/zynq_ultrascale/scripts/zynq-ultrascale_reset.cmm OVERRIDE_BOOTMODE=0x0
SYStem.Mode Prepare
DO &pdd/hardware/zynq_ultrascale/scripts/zynq-ultrascale_kick_bootcore.cmm "A53_X64"
SYStem.Mode.Attach
Break.direct
; </temporarily switch to BOOTMODE=JTAG>
SYStem.JtagClock CTCK 24MHz
; --------------------------------------------------------------------------------
; peripheral initializations
//Pin muxing MIO configuration MIO[0:12]
Data.Set A:0xFF5E0068 %LE %Long 0x01010c00 ;QSPI_REF_CTRL
&addr=0xFF180000
RePeaT 13.
(
Data.Set A:&addr %LE %Long 0x2
&addr=&addr+0x4
)
Data.Set A:0xFF180204 %LE %Long 0x2240000
Data.Set A:0xFF5E0238 %Long 0x17FFFE
IF &dualqspi==1
GOSUB READ_ID_TEST_DUAL
ELSE
GOSUB READ_ID_TEST
Data.Set A:0xFF0F0144 %LE %Long 1 ;enable GQSPI_SEL
Data.Set A:0xFF0F010C %Long 0x0FBE ; Interrupt disable register
Data.Set A:0xFF0F0128 %Long 0x01 ; thres hold
Data.Set A:0xFF0F012C %Long 0x01 ; thres hold
Data.Set A:0xFF0F0104 %Long 0x0FBE ; Interrupt status register
Data.Set A:0xFF0F014C %Long 0x7 ; reset tx fifo and gen_fifo..
WAIT 100.ms
Data.Set A:0xFF0F0100 %Long 0x00080010 ;Config register, clk speed control[5:3] , mode==00 [31:30] I/O mode
;The flash dualport works only under the non-secure mode for the ZYNQ-ULTRASCALE+
SYStem.MemAccess DAP
Register.Set NS 1.
Register.Set M 0x5 ;EL1h
; --------------------------------------------------------------------------------
; Flash Declaration
Break.RESet
FLASHFILE.RESet
FLASHFILE.CONFIG 0xFF0F0000
IF &dualqspi==1
FLASHFILE.TARGET 0xFFFC1000++0x2FFF E:0xFFFC4000++0x27FF &pdd/flash/word/spiw4b64_zynqultra.bin /KEEP /STACKSIZE 0x400 /DUALPORT
ELSE
FLASHFILE.TARGET 0xFFFC1000++0x2FFF E:0xFFFC4000++0x27FF &pdd/flash/byte/spi4b64fs_zynqultra.bin /KEEP /STACKSIZE 0x400 /DUALPORT
FLASHFILE.GETID
//End of the test prepareonly
IF "&arg1"=="PREPAREONLY"
ENDDO
; Save Whole Flash
;FLASHFILE.SAVE "flash_dump.bin" 0x0++0x1FFFFFFF
FLASHFILE.Create 0x0--0x1FFFFFFF 0x20000 Byte
; Flash BOOT.BIN (wolfBoot) at offset 0x0
DIALOG.YESNO "Flash wolfBoot BOOT.BIN now?"
ENTRY &programnow
if &programnow
(
FLASHFILE.ReProgram ALL
FLASHFILE.Load "BOOT.BIN" 0x0
FLASHFILE.ReProgram off
)
; Flash signed application image at partition offset
DIALOG.YESNO "Flash signed application image now?"
ENTRY &programnow
if &programnow
(
FLASHFILE.ReProgram ALL
FLASHFILE.Load "test-app/image_v1_signed.bin" 0x7000000
FLASHFILE.ReProgram off
)
ENDDO
; --------------------------------------------------------------------------------
; Subroutines
READ_ID_TEST:
(
Data.Set A:0xFF0F0144 %LE %Long 1 ;enable GQSPI_SEL
Data.Set A:0xFF0F010C %Long 0x0FBE ;Interrupt disable register
Data.Set A:0xFF0F0128 %Long 0x01 ;thres hold
Data.Set A:0xFF0F012C %Long 0x01 ;thres hold
Data.Set A:0xFF0F0104 %Long 0x0FBE ;Interrupt status register
;read A:0xFF0F0100 -> 0x0
Data.Set A:0xFF0f014c %Long 0x7 ; reset tx fifo and gen_fifo..
WAIT 100.ms
Data.Set A:0xFF0F0100 %Long 0x00080010 ;Config register, clk speed control[5:3] , mode==00 [31:30] I/O mode
&dat_xfer=0x1<<8.
&spimode=0x1<<10.
&cs_lower=0x1<<12.
&cs_upper=0x1<<13.
&bus_lower=0x1<<14.
&bus_upper=0x2<<14.
&bus_both=0x3<<14.
&transmit=0x1<<16.
&receive=0x1<<17.
&stripe=0x1<<18.
Data.Set A:0xFF0F0114 %Long 0x1 ;spi enable register , cs low
Data.Set A:0xFF0F011C %Long 0x9f ; tx, data transfer
Data.Set A:0xFF0F0140 %Long &transmit|&receive|&bus_lower|&cs_lower|&spimode|&dat_xfer|0x1
PRINT "read 0x" Data.Long(A:0xff0f0120) " (dummy)"
Data.Set A:0xFF0F011C %Long 0x00 ; tx, data transfer
Data.Set A:0xFF0F0140 %Long &transmit|&receive|&bus_lower|&cs_lower|&spimode|&dat_xfer|0x1
PRINT "read 0x" Data.Long(A:0xff0f0120) " (manufacture id)"
Data.Set A:0xFF0F011C %Long 0x00 ; tx, data transfer
Data.Set A:0xFF0F0140 %Long &transmit|&receive|&bus_lower|&cs_lower|&spimode|&dat_xfer|0x1
PRINT "read 0x" Data.Long(A:0xff0f0120) " (device id)"
Data.Set A:0xFF0F011C %Long 0x00 ; tx, data transfer
Data.Set A:0xFF0F0140 %Long &transmit|&receive|&bus_lower|&cs_lower|&spimode|&dat_xfer|0x1
PRINT "read 0x" Data.Long(A:0xff0f0120)
Data.Set A:0xFF0F0114 %Long 0x0 ;spi disable, cs high
RETURN
)
READ_ID_TEST_DUAL:
(
Data.Set A:0xFF0F0144 %LE %Long 1 ;enable GQSPI_SEL
Data.Set A:0xFF0F010C %Long 0x0FBE ;Interrupt disable register
Data.Set A:0xFF0F0128 %Long 0x01 ;thres hold
Data.Set A:0xFF0F012C %Long 0x01 ;thres hold
Data.Set A:0xFF0F0104 %Long 0x0FBE ;Interrupt status register
;read A:0xFF0F0100 -> 0x0
Data.Set A:0xFF0f014c %Long 0x7 ; reset tx fifo and gen_fifo..
WAIT 100.ms
Data.Set A:0xFF0F0100 %Long 0x00080010 ;Config register, clk speed control[5:3] , mode==00 [31:30] I/O mode
&dat_xfer=0x1<<8.
&spimode=0x1<<10.
&cs_lower=0x1<<12.
&cs_upper=0x1<<13.
&bus_lower=0x1<<14.
&bus_upper=0x2<<14.
&bus_both=0x3<<14.
&transmit=0x1<<16.
&receive=0x1<<17.
&stripe=0x1<<18.
Data.Set A:0xFF0F0114 %Long 0x1 ;spi enable register , cs low
Data.Set A:0xFF0F011C %Long 0x00009f9f ; tx, data transfer
Data.Set A:0xFF0F0140 %Long &stripe|&transmit|&receive|&bus_both|&cs_lower|&cs_upper|&spimode|&dat_xfer|0x4 ; tx,4 byte data transfer
PRINT "read 0x" Data.Long(A:0xff0f0120)
Data.Set A:0xFF0F011C %Long 0x00000000 ; tx, data transfer
Data.Set A:0xFF0F0140 %Long &stripe|&transmit|&receive|&bus_both|&cs_lower|&cs_upper|&spimode|&dat_xfer|0x4 ; tx,4 byte data transfer
PRINT "read 0x" Data.Long(A:0xff0f0120)
Data.Set A:0xFF0F011C %Long 0x00000000 ; tx, data transfer
Data.Set A:0xFF0F0140 %Long &stripe|&transmit|&receive|&bus_both|&cs_lower|&cs_upper|&spimode|&dat_xfer|0x4 ; tx,4 byte data transfer
PRINT "read 0x" Data.Long(A:0xff0f0120)
Data.Set A:0xFF0F011C %Long 0x00000000 ; tx, data transfer
Data.Set A:0xFF0F0140 %Long &stripe|&transmit|&receive|&bus_both|&cs_lower|&cs_upper|&spimode|&dat_xfer|0x4 ; tx,4 byte data transfer
PRINT "read 0x" Data.Long(A:0xff0f0120)
Data.Set A:0xFF0F0114 %Long 0x0 ;spi disable, cs high
RETURN
)

View File

@ -0,0 +1,56 @@
; ZCU102 wolfBoot Debug Script
;
; Debug wolfBoot on Zynq UltraScale+ ZCU102.
; Based on Lauterbach TRACE32 ZCU102 demo scripts.
;
; Prerequisites:
; * Connect Debug Cable to J6
; * set SW6 = 0y1111 (JTAG Bootmode)
; --------------------------------------------------------------------------------
; initialize and start the debugger
SYStem.RESet
SYStem.CPU ZYNQ-ULTRASCALE+-APU
SYStem.Option TRST OFF
SYStem.Option ResBreak OFF
SYStem.Option WaitDAPPWR ON
SYStem.JtagClock CTCK 20MHz
CORE.ASSIGN 1.
; disable Trace infrastructure for the moment - TPIU may be unclocked!
ETM.OFF
Trace.DISable
SYStem.Mode Prepare
;GOSUB DisableWatchdog
;DO "C:/T32/demo/arm/hardware/zynq_ultrascale/scripts/zynq-ultrascale_kick_bootcore.cmm" A53_X64
SYStem.Mode.Attach
; --------------------------------------------------------------------------------
; Load symbols for wolfBoot
sYmbol.SourcePATH.SetBaseDir "."
Data.LOAD.Elf "wolfboot.elf" /NoCode
;Data.LOAD.Elf "test-app/image.elf" /NoClear /NoCode
IF STATE.RUN()
Break.direct
B.Delete
B.Set wolfBoot_start
ENDDO
; ================================================================================
DisableWatchdog:
(
PRIVATE &swdtMode
&swdtMode=Data.Long(ENAXI:0xFF150000)
&swdtMode=&swdtMode&0xFFE ; Mode.WDEN = 0
&swdtMode=&swdtMode+0xABC000 ; zKEY
Data.Set ENAXI:0xFF150000 %LE %Long &swdtMode
)
RETURN

View File

@ -0,0 +1,48 @@
; ZCU102 TRACE32 Window Layout Script
B::
; Set working directory to wolfboot root
;ChDir "~/wolfboot"
TOOLBAR ON
STATUSBAR ON
FramePOS 313.29 58.733 363. 116.
WinPAGE.RESet
WinPAGE.Create P000
WinCLEAR
WinPOS 214.0 1.8 142. 5. 27. 1. W003
WinTABS 13. 16. 0. 0. 0. 0. 0. 0. 0. 71.
B.List
WinPOS 0.0 0.0 151. 58. 14. 0. W008
PEDIT "tools/scripts/zcu102/zcu102-ca53-qspi.cmm"
WinPOS 2.1429 1.2667 154. 59. 14. 0. W000
PEDIT "tools/scripts/zcu102/zcu102-debug-uboot.cmm"
WinPOS 4.2857 2.5333 156. 59. 14. 0. W004
PEDIT "tools/scripts/zcu102/zcu102-debug-wolfboot.cmm"
WinPOS 53.571 11.333 164. 76. 24. 1. W001
WinTABS 13. 18. 25.
List.auto
WinPOS 228.0 12.933 128. 25. 5. 0. W005
Frame
WinPOS 255.43 43.067 100. 25. 0. 0. W009
Var.Local
WinPAN 0. 6.
WinPOS 264.14 71.333 92. 29. 0. 0. W007
Register
WinPOS 1.4286 78.467 154. 23. 0. 0. W002
AREA
WinPAGE.select P000
ENDDO

View File

@ -0,0 +1,23 @@
// Boot BIF for wolfBoot ZynqMP SD Card Boot
// FSBL -> PMUFW -> BL31 (EL3) -> wolfBoot (EL2)
// wolfBoot loads firmware from MBR partitions on SD card
//
// Usage:
// bootgen -arch zynqmp -image zynqmp_sd_boot.bif -w -o BOOT.BIN
//
// Required files (copy to same directory):
// zynqmp_fsbl.elf - First Stage Boot Loader
// pmufw.elf - Platform Management Unit firmware
// bl31.elf - ARM Trusted Firmware (EL3)
// wolfboot.elf - wolfBoot bootloader
//
// Optional:
// system.bit - PL bitstream (uncomment line below)
the_ROM_image:
{
[bootloader, destination_cpu=a53-0] zynqmp_fsbl.elf
[pmufw_image] pmufw.elf
// [destination_device=pl] system.bit
[destination_cpu=a53-0, exception_level=el-3, trustzone] bl31.elf
[destination_cpu=a53-0, exception_level=el-2] wolfboot.elf
}