diff --git a/.github/workflows/test-configs.yml b/.github/workflows/test-configs.yml index a84cde0ccc..e65a797a8c 100644 --- a/.github/workflows/test-configs.yml +++ b/.github/workflows/test-configs.yml @@ -599,6 +599,12 @@ jobs: arch: aarch64 config-file: ./config/examples/zynqmp.config + zynqmp_sdcard_test: + uses: ./.github/workflows/test-build-aarch64.yml + with: + arch: aarch64 + config-file: ./config/examples/zynqmp_sdcard.config + versal_vmk180_test: uses: ./.github/workflows/test-build-aarch64.yml with: diff --git a/.gitignore b/.gitignore index ecdf1caff5..2bb7f203b1 100644 --- a/.gitignore +++ b/.gitignore @@ -343,3 +343,4 @@ image.ub *.pdi system-default.dtb test_output/ +sdcard.img diff --git a/arch.mk b/arch.mk index 10f4c6a0a1..9df13f8ffe 100644 --- a/arch.mk +++ b/arch.mk @@ -78,6 +78,7 @@ ifeq ($(ARCH),AARCH64) HASH_HAL=1 CFLAGS+=-DWOLFBOOT_ZYNQMP_CSU endif + endif ifeq ($(TARGET),versal) diff --git a/config/examples/zynqmp_sdcard.config b/config/examples/zynqmp_sdcard.config new file mode 100644 index 0000000000..00f62c4013 --- /dev/null +++ b/config/examples/zynqmp_sdcard.config @@ -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 diff --git a/docs/Targets.md b/docs/Targets.md index 3217652c0d..87429ed236 100644 --- a/docs/Targets.md +++ b/docs/Targets.md @@ -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 +``` + +### SD Card Boot (MBR + A/B) + +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/zcu102/zynqmp_sd_boot.bif -w -o BOOT.BIN ``` -#### Signing Zynq +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 -`tools/keytools/sign --rsa4096 --sha3 /srv/linux-rpi4/vmlinux.bin wolfboot_signing_private_key.der 1` +**Create SD image** +```sh +dd if=/dev/zero of=sdcard.img bs=1M count=1024 +sfdisk sdcard.img < 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; +#endif + + 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", +#if ZYNQMP_SDHCI_BASE == ZYNQMP_SD0_BASE + 0, +#else + 1, +#endif + (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 (card←memory): clean D-cache so DMA reads correct data + * - After DMA read (card→memory): 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 + CACHE_LINE_SIZE - 1) & + ~(CACHE_LINE_SIZE - 1); + + 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 + CACHE_LINE_SIZE - 1) & + ~(CACHE_LINE_SIZE - 1); + + 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 */ diff --git a/hal/zynq.h b/hal/zynq.h index 9282de33d3..ff1d2697a9 100644 --- a/hal/zynq.h +++ b/hal/zynq.h @@ -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) */ diff --git a/hal/zynq.ld b/hal/zynq.ld index 9aeeaaadff..230b76455c 100644 --- a/hal/zynq.ld +++ b/hal/zynq.ld @@ -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 diff --git a/include/sdhci.h b/include/sdhci.h index b88169100a..b7eb6d3095 100644 --- a/include/sdhci.h +++ b/include/sdhci.h @@ -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) diff --git a/src/boot_aarch64.c b/src/boot_aarch64.c index e7224827dc..892e42ea5c 100644 --- a/src/boot_aarch64.c +++ b/src/boot_aarch64.c @@ -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 diff --git a/src/sdhci.c b/src/sdhci.c index 907687be53..58d47527c2 100644 --- a/src/sdhci.c +++ b/src/sdhci.c @@ -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,11 @@ static int sdhci_transfer(int dir, uint32_t cmd_index, uint32_t block_addr, } } sdhci_disable_sdma_interrupts(); + + #ifndef SDHCI_SDMA_DISABLED + /* Platform DMA cache maintenance after transfer */ + sdhci_platform_dma_complete(buf, sz, dir == SDHCI_DIR_WRITE); + #endif /* !SDHCI_SDMA_DISABLED */ } else { /* Blocking mode - buffer ready flag differs for read vs write */ @@ -1407,6 +1441,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 +1454,7 @@ int sdhci_init(void) return -1; } #endif +#endif /* !SDHCI_FORCE_CARD_DETECT */ /* Start in 1-bit bus mode */ reg = SDHCI_REG(SDHCI_SRS10); diff --git a/test-app/app_zynq.c b/test-app/app_zynq.c index 89c9c13b6b..6e1976b523 100644 --- a/test-app/app_zynq.c +++ b/test-app/app_zynq.c @@ -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 #include -#include #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) */ +__attribute__((weak)) unsigned int current_el(void) +{ + unsigned long el; + __asm__ volatile("mrs %0, CurrentEL" : "=r" (el) : : "cc"); + return (unsigned int)((el >> 2) & 0x3U); +} + +/* 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"); - /* Wait for reboot */ - while(1) - ; + /* Idle loop */ + while (1) { + __asm__ volatile("wfi"); + } } #endif /** TARGET_zynq **/ diff --git a/tools/scripts/zcu102/zcu102-ca53-qspi.cmm b/tools/scripts/zcu102/zcu102-ca53-qspi.cmm new file mode 100755 index 0000000000..cb19d2fc5c --- /dev/null +++ b/tools/scripts/zcu102/zcu102-ca53-qspi.cmm @@ -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 + +; +; 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 +; + +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 +) diff --git a/tools/scripts/zcu102/zcu102-debug-wolfboot.cmm b/tools/scripts/zcu102/zcu102-debug-wolfboot.cmm new file mode 100644 index 0000000000..c0bc0cbabc --- /dev/null +++ b/tools/scripts/zcu102/zcu102-debug-wolfboot.cmm @@ -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 \ No newline at end of file diff --git a/tools/scripts/zcu102/zynqmp_sd_boot.bif b/tools/scripts/zcu102/zynqmp_sd_boot.bif new file mode 100644 index 0000000000..0040529ecf --- /dev/null +++ b/tools/scripts/zcu102/zynqmp_sd_boot.bif @@ -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 tools/scripts/zcu102/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 +}