Skip to content

Commit 8e264f6

Browse files
committed
Fixes to get SDHCI stable (DISK_TEST=1) passing and image hash/verify passing. Only issue is test-app EL level. Peer review fixes.
1 parent b5c0185 commit 8e264f6

File tree

6 files changed

+179
-16
lines changed

6 files changed

+179
-16
lines changed

config/examples/zynqmp_sdcard.config

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
# Zynq UltraScale+ MPSoC ZU9EG - Quad-core ARM Cortex-A53
33
#
44
# This configuration enables SD card boot for the ZynqMP:
5-
# FSBL -> BL31 (EL3) -> wolfBoot (EL2) -> Linux (EL1)
5+
# FSBL -> PMUFW -> BL31 (EL3) -> wolfBoot (EL2) -> Linux (EL1)
66
#
77
# wolfBoot loads firmware images from MBR partitions on SD card.
88
# Uses the generic SDHCI driver with SD1 controller (external SD slot on ZCU102).
@@ -29,6 +29,8 @@ DISK_EMMC?=0
2929
# ZynqMP Arasan SDHCI does not support CDSS/CDTL card detect test level.
3030
# Since FSBL booted from the same SD card, we know it is present.
3131
CFLAGS_EXTRA+=-DSDHCI_FORCE_CARD_DETECT
32+
# Note: Arasan SDHCI v3.0 does not support HV4E mode. The platform layer
33+
# in hal/zynq.c transparently redirects SRS22/SRS23 to SRS00 for legacy SDMA.
3234

3335
# Disable QSPI flash when using SD card
3436
EXT_FLASH?=0
@@ -37,6 +39,9 @@ NO_XIP=1
3739
# ELF loading support
3840
ELF?=1
3941

42+
# Boot Exception Level: transition from EL2 -> EL1 before jumping to app
43+
BOOT_EL1?=1
44+
4045
# General options
4146
VTOR?=1
4247
CORTEX_M0?=0

docs/Targets.md

Lines changed: 14 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1991,7 +1991,7 @@ wolfBoot replaces U-Boot in the ZynqMP boot flow:
19911991
FSBL -> PMUFW -> BL31 (EL3) -> wolfBoot (EL2) -> Linux (EL1)
19921992
```
19931993

1994-
wolfBoot runs from DDR at `0x7FF00000` (EL2, non-secure). All clock, MIO, and DDR initialization is handled by the FSBL/PMUFW before wolfBoot starts.
1994+
For QSPI boot, wolfBoot runs from DDR at `0x7FF00000` (EL2, non-secure). For SD card boot, wolfBoot runs at `0x8000000`. All clock, MIO, and DDR initialization is handled by the FSBL/PMUFW before wolfBoot starts.
19951995

19961996
This target supports **two boot paths**:
19971997
- **QSPI boot** (primary, production-style): `config/examples/zynqmp.config`
@@ -2101,8 +2101,8 @@ make clean
21012101
make
21022102

21032103
make test-app/image.bin
2104-
./tools/keytools/sign --rsa4096 --sha3 test-app/image.bin wolfboot_signing_private_key.der 1
2105-
./tools/keytools/sign --rsa4096 --sha3 test-app/image.bin wolfboot_signing_private_key.der 2
2104+
IMAGE_HEADER_SIZE=1024 ./tools/keytools/sign --rsa4096 --sha3 test-app/image.elf wolfboot_signing_private_key.der 1
2105+
IMAGE_HEADER_SIZE=1024 ./tools/keytools/sign --rsa4096 --sha3 test-app/image.elf wolfboot_signing_private_key.der 2
21062106
```
21072107

21082108
**Build BOOT.BIN for SD card**
@@ -2154,6 +2154,17 @@ sudo umount /mnt
21542154
sudo fdisk -l /dev/sdX
21552155
```
21562156

2157+
Or just mount and copy the BOOT.BIN and "dd" the partitions
2158+
2159+
```sh
2160+
# Mount the FAT boot partition and copy just the updated BOOT.BIN
2161+
sudo mount /dev/sdc1 /mnt && sudo cp BOOT.BIN /mnt/ && sudo umount /mnt && sync
2162+
2163+
# Write the signed image to partition 2 (P:A) and partition 3 (P:B)
2164+
sudo dd if=test-app/image_v1_signed.bin of=/dev/sdc2 bs=4k
2165+
sudo dd if=test-app/image_v1_signed.bin of=/dev/sdc3 bs=4k
2166+
```
2167+
21572168
**Boot Mode**
21582169

21592170
Set the ZCU102 boot mode switches (SW6) for SD card boot:
@@ -2459,7 +2470,6 @@ make test-app/image.bin
24592470
dd if=/dev/zero of=sdcard.img bs=1M count=1024
24602471
sfdisk sdcard.img <<EOF
24612472
label: dos
2462-
unit: sectors
24632473
24642474
1 : start=2048, size=128M, type=c, bootable
24652475
2 : size=200M, type=83

hal/zynq.c

Lines changed: 126 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1596,6 +1596,24 @@ void hal_prepare_boot(void)
15961596
mDev.qnx = NULL;
15971597
}
15981598
#endif
1599+
1600+
/* Clean and invalidate caches for the loaded application.
1601+
* The application was written to RAM via D-cache, but the CPU will
1602+
* fetch instructions via I-cache from main memory. We must:
1603+
* 1. Clean D-cache (flush dirty data to memory)
1604+
* 2. Invalidate I-cache (ensure fresh instruction fetch) */
1605+
__asm__ volatile("dsb sy");
1606+
{
1607+
uintptr_t addr;
1608+
uintptr_t end = WOLFBOOT_LOAD_ADDRESS + APP_CACHE_FLUSH_SIZE;
1609+
for (addr = WOLFBOOT_LOAD_ADDRESS; addr < end; addr += CACHE_LINE_SIZE) {
1610+
__asm__ volatile("dc cvac, %0" : : "r"(addr));
1611+
}
1612+
}
1613+
__asm__ volatile("dsb sy");
1614+
__asm__ volatile("ic iallu");
1615+
__asm__ volatile("dsb sy");
1616+
__asm__ volatile("isb");
15991617
}
16001618

16011619
/* Flash functions must be relocated to RAM for execution */
@@ -1866,6 +1884,16 @@ static int test_ext_flash(QspiDev_t* dev)
18661884

18671885
#define CADENCE_SRS_OFFSET 0x200
18681886

1887+
/* Legacy SDMA system address register (standard SDHCI offset 0x00).
1888+
* The Arasan SDHCI v3.0 on ZynqMP does not support Host Version 4 Enable
1889+
* (HV4E) mode. The generic SDHCI driver uses HV4E-style 64-bit DMA
1890+
* addressing via SRS22/SRS23 (offsets 0x58/0x5C), but on this controller
1891+
* we must use the legacy SRS00 register (offset 0x00) for SDMA addresses.
1892+
* The platform reg_read/reg_write functions transparently redirect
1893+
* SRS22 <-> SRS00, making legacy SDMA work without changes to sdhci.c. */
1894+
#define STD_SDHCI_SDMA_ADDR 0x00 /* SDMA System Address (32-bit) */
1895+
#define STD_SDHCI_HOST_CTRL2 0x3C /* Auto CMD Err(16) + Host Ctrl 2(16) */
1896+
18691897
/* Standard SDHCI register offsets (byte addresses within the controller) */
18701898
#define STD_SDHCI_HOST_CTRL1 0x28 /* Host Control 1 (8-bit) */
18711899
#define STD_SDHCI_POWER_CTRL 0x29 /* Power Control (8-bit) */
@@ -1939,8 +1967,25 @@ uint32_t sdhci_reg_read(uint32_t offset)
19391967

19401968
/* Cadence SRS registers (0x200+) -> standard SDHCI (subtract 0x200) */
19411969
if (offset >= CADENCE_SRS_OFFSET) {
1942-
/* 32-bit reads work for all SDHCI registers */
1943-
return *((volatile uint32_t *)(base + offset - CADENCE_SRS_OFFSET));
1970+
uint32_t std_off = offset - CADENCE_SRS_OFFSET;
1971+
1972+
/* SRS22 (0x58) -> SRS00 (0x00): Legacy SDMA address register */
1973+
if (std_off == 0x58) {
1974+
return *((volatile uint32_t *)(base + STD_SDHCI_SDMA_ADDR));
1975+
}
1976+
/* SRS23 (0x5C) -> 0: No 64-bit addressing on SDHCI v3.0 */
1977+
if (std_off == 0x5C) {
1978+
return 0;
1979+
}
1980+
1981+
{
1982+
uint32_t val = *((volatile uint32_t *)(base + std_off));
1983+
/* Mask out A64S from Capabilities to prevent HV4E init */
1984+
if (std_off == 0x40) { /* SRS16 - Capabilities */
1985+
val &= ~SDHCI_SRS16_A64S;
1986+
}
1987+
return val;
1988+
}
19441989
}
19451990
/* Cadence HRS registers (0x000-0x1FF) -> translate to standard equivalents */
19461991
return zynqmp_sdhci_hrs_read(offset);
@@ -1984,6 +2029,27 @@ void sdhci_reg_write(uint32_t offset, uint32_t val)
19842029
return;
19852030
}
19862031

2032+
/* SRS22 (0x58) -> SRS00 (0x00): Legacy SDMA address register.
2033+
* The generic driver writes the DMA buffer address here for HV4E mode.
2034+
* Redirect to SRS00 which is the legacy SDMA system address register.
2035+
* Writing SRS00 also restarts DMA after a boundary interrupt. */
2036+
if (std_off == 0x58) {
2037+
*((volatile uint32_t *)(base + STD_SDHCI_SDMA_ADDR)) = val;
2038+
return;
2039+
}
2040+
/* SRS23 (0x5C) -> no-op: No 64-bit addressing on SDHCI v3.0 */
2041+
if (std_off == 0x5C) {
2042+
return;
2043+
}
2044+
2045+
/* SRS15 (0x3C) -> mask out HV4E and A64 bits.
2046+
* The generic driver enables HV4E for SDMA, but the Arasan SDHCI v3.0
2047+
* does not support it. These are reserved bits on v3.0 and must not
2048+
* be set. */
2049+
if (std_off == STD_SDHCI_HOST_CTRL2) {
2050+
val &= ~(SDHCI_SRS15_HV4E | SDHCI_SRS15_A64);
2051+
}
2052+
19872053
/* All other SRS registers: 32-bit write */
19882054
*((volatile uint32_t *)(base + std_off)) = val;
19892055
return;
@@ -2010,22 +2076,35 @@ void sdhci_platform_init(void)
20102076
{
20112077
uint32_t reg;
20122078
volatile int i;
2079+
uint32_t slot_mask;
2080+
uint32_t slot_shift;
2081+
uint32_t reset_bit;
20132082

2014-
/* Set SD1 slot type to "Embedded Slot for One Device" (01).
2083+
/* Set the selected SDx slot type to "Embedded Slot for One Device" (01).
20152084
* This feeds into the SDHCI Capabilities register bits 31:30 and makes
20162085
* the controller report card as always present, bypassing the physical
20172086
* CD pin that is not connected to the SDHCI controller on ZCU102. */
2087+
if (ZYNQMP_SDHCI_BASE == ZYNQMP_SD0_BASE) {
2088+
slot_mask = SD_CONFIG_REG2_SD0_SLOTTYPE_MASK;
2089+
slot_shift = SD_CONFIG_REG2_SD0_SLOTTYPE_SHIFT;
2090+
reset_bit = RST_LPD_IOU2_SDIO0;
2091+
} else {
2092+
slot_mask = SD_CONFIG_REG2_SD1_SLOTTYPE_MASK;
2093+
slot_shift = SD_CONFIG_REG2_SD1_SLOTTYPE_SHIFT;
2094+
reset_bit = RST_LPD_IOU2_SDIO1;
2095+
}
2096+
20182097
reg = IOU_SLCR_SD_CONFIG_REG2;
2019-
reg &= ~SD_CONFIG_REG2_SD1_SLOTTYPE_MASK;
2020-
reg |= (1UL << SD_CONFIG_REG2_SD1_SLOTTYPE_SHIFT); /* 01 = Embedded */
2098+
reg &= ~slot_mask;
2099+
reg |= (1UL << slot_shift); /* 01 = Embedded */
20212100
IOU_SLCR_SD_CONFIG_REG2 = reg;
20222101

20232102
/* The SDHCI Capabilities register latches IOU_SLCR values on controller
2024-
* reset. Issue SDIO1 reset via CRL_APB so the controller picks up the
2103+
* reset. Issue SDIOx reset via CRL_APB so the controller picks up the
20252104
* new slot type configuration. */
2026-
RST_LPD_IOU2 |= RST_LPD_IOU2_SDIO1; /* Assert SDIO1 reset */
2105+
RST_LPD_IOU2 |= reset_bit; /* Assert SDIOx reset */
20272106
for (i = 0; i < 100; i++) {} /* Brief delay */
2028-
RST_LPD_IOU2 &= ~RST_LPD_IOU2_SDIO1; /* De-assert SDIO1 reset */
2107+
RST_LPD_IOU2 &= ~reset_bit; /* De-assert SDIOx reset */
20292108
for (i = 0; i < 1000; i++) {} /* Wait for controller ready */
20302109

20312110
#ifdef DEBUG_SDHCI
@@ -2068,6 +2147,45 @@ void sdhci_platform_set_bus_mode(int is_emmc)
20682147
wolfBoot_printf("sdhci_platform_set_bus_mode: is_emmc=%d\n", is_emmc);
20692148
#endif
20702149
}
2150+
2151+
/* DMA cache maintenance - called from sdhci_transfer() around SDMA operations.
2152+
* The SDMA engine transfers data directly to/from physical memory, bypassing
2153+
* the CPU's L1/L2 caches. We must ensure cache coherency:
2154+
* - Before DMA write (card←memory): clean D-cache so DMA reads correct data
2155+
* - After DMA read (card→memory): invalidate D-cache so CPU sees new data */
2156+
void sdhci_platform_dma_prepare(void *buf, uint32_t sz, int is_write)
2157+
{
2158+
uintptr_t addr;
2159+
uintptr_t start = (uintptr_t)buf & ~(CACHE_LINE_SIZE - 1);
2160+
uintptr_t end = (uintptr_t)buf + sz;
2161+
2162+
if (is_write) {
2163+
/* Clean D-cache: flush dirty lines to memory for DMA to read */
2164+
for (addr = start; addr < end; addr += CACHE_LINE_SIZE) {
2165+
__asm__ volatile("dc cvac, %0" : : "r"(addr) : "memory");
2166+
}
2167+
} else {
2168+
/* Invalidate D-cache: discard stale lines before DMA writes to memory */
2169+
for (addr = start; addr < end; addr += CACHE_LINE_SIZE) {
2170+
__asm__ volatile("dc civac, %0" : : "r"(addr) : "memory");
2171+
}
2172+
}
2173+
__asm__ volatile("dsb sy" : : : "memory");
2174+
}
2175+
2176+
void sdhci_platform_dma_complete(void *buf, uint32_t sz, int is_write)
2177+
{
2178+
(void)is_write;
2179+
/* After DMA: clean and invalidate to ensure CPU sees DMA-written data */
2180+
uintptr_t addr;
2181+
uintptr_t start = (uintptr_t)buf & ~(CACHE_LINE_SIZE - 1);
2182+
uintptr_t end = (uintptr_t)buf + sz;
2183+
2184+
for (addr = start; addr < end; addr += CACHE_LINE_SIZE) {
2185+
__asm__ volatile("dc civac, %0" : : "r"(addr) : "memory");
2186+
}
2187+
__asm__ volatile("dsb sy" : : : "memory");
2188+
}
20712189
#endif /* DISK_SDCARD || DISK_EMMC */
20722190

20732191

hal/zynq.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,11 @@
3232
#ifndef EL2_HYPERVISOR
3333
#define EL2_HYPERVISOR 1
3434
#endif
35+
36+
/* Cache line size for Cortex-A53 (AArch64) */
37+
#define CACHE_LINE_SIZE 64
38+
/* Region size to flush before booting application */
39+
#define APP_CACHE_FLUSH_SIZE (1 * 1024 * 1024) /* 1MB */
3540
#ifndef EL1_NONSECURE
3641
#define EL1_NONSECURE 0
3742
#endif

hal/zynq.ld

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ MEMORY
1616
* Loaded by FSBL to end of DDR0
1717
* For SD card boot see zynq_sd.ld
1818
*/
19-
psu_ddr_0_MEM_0 : ORIGIN = 0x7FF00000, LENGTH = 0x200000
19+
psu_ddr_0_MEM_0 : ORIGIN = 0x7FE00000, LENGTH = 0x200000
2020
psu_ddr_1_MEM_0 : ORIGIN = 0x800000000, LENGTH = 0x80000000
2121
psu_ocm_ram_0_MEM_0 : ORIGIN = 0xFFFC0000, LENGTH = 0x40000
2222
psu_qspi_linear_0_MEM_0 : ORIGIN = 0xC0000000, LENGTH = 0x20000000

src/sdhci.c

Lines changed: 27 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,22 @@
3434
#include "hal.h"
3535
#include "disk.h"
3636

37+
/* ============================================================================
38+
* Platform DMA cache maintenance (weak defaults - override in HAL)
39+
* ============================================================================ */
40+
#ifndef SDHCI_SDMA_DISABLED
41+
void __attribute__((weak)) sdhci_platform_dma_prepare(
42+
void *buf, uint32_t sz, int is_write)
43+
{
44+
(void)buf; (void)sz; (void)is_write;
45+
}
46+
void __attribute__((weak)) sdhci_platform_dma_complete(
47+
void *buf, uint32_t sz, int is_write)
48+
{
49+
(void)buf; (void)sz; (void)is_write;
50+
}
51+
#endif
52+
3753
/* ============================================================================
3854
* Internal state
3955
* ============================================================================ */
@@ -368,7 +384,7 @@ static uint32_t sdhci_set_clock(uint32_t clock_khz)
368384
reg = SDHCI_REG(SDHCI_SRS11);
369385
reg &= ~(SDHCI_SRS11_SDCFSL_MASK | SDHCI_SRS11_SDCFSH_MASK);
370386
reg |= (((mclk & 0x0FF) << SDHCI_SRS11_SDCFSL_SHIFT) & SDHCI_SRS11_SDCFSL_MASK); /* lower 8 bits */
371-
reg |= (((mclk & 0x300) << SDHCI_SRS11_SDCFSH_SHIFT) & SDHCI_SRS11_SDCFSH_MASK); /* upper 2 bits */
387+
reg |= (((mclk & 0x300) >> 2) & SDHCI_SRS11_SDCFSH_MASK); /* upper 2 bits */
372388
reg |= SDHCI_SRS11_ICE; /* clock enable */
373389
reg &= ~SDHCI_SRS11_CGS; /* select clock */
374390
SDHCI_REG_SET(SDHCI_SRS11, reg);
@@ -1190,10 +1206,16 @@ static int sdhci_transfer(int dir, uint32_t cmd_index, uint32_t block_addr,
11901206
/* SDMA mode with Host Version 4 enable.
11911207
* HV4E is required for SDMA to use the 64-bit address registers
11921208
* (SRS22/SRS23) instead of the legacy 32-bit register (SRS00).
1193-
* A64 is cleared in SRS15 to use 32-bit DMA addressing. */
1209+
* A64 is cleared in SRS15 to use 32-bit DMA addressing.
1210+
* Note: Platform may redirect SRS22/SRS23 to SRS00 for legacy
1211+
* SDMA on controllers that don't support HV4E. */
11941212
sdhci_reg_or(SDHCI_SRS10, SDHCI_SRS10_DMA_SDMA);
11951213
sdhci_reg_or(SDHCI_SRS15, SDHCI_SRS15_HV4E);
11961214
sdhci_reg_and(SDHCI_SRS15, ~SDHCI_SRS15_A64);
1215+
1216+
/* Platform DMA cache maintenance before transfer */
1217+
sdhci_platform_dma_prepare(buf, sz, dir == SDHCI_DIR_WRITE);
1218+
11971219
/* Set SDMA address */
11981220
SDHCI_REG_SET(SDHCI_SRS22, (uint32_t)(uintptr_t)buf);
11991221
SDHCI_REG_SET(SDHCI_SRS23, (uint32_t)(((uint64_t)(uintptr_t)buf) >> 32));
@@ -1230,6 +1252,9 @@ static int sdhci_transfer(int dir, uint32_t cmd_index, uint32_t block_addr,
12301252
}
12311253
}
12321254
sdhci_disable_sdma_interrupts();
1255+
1256+
/* Platform DMA cache maintenance after transfer */
1257+
sdhci_platform_dma_complete(buf, sz, dir == SDHCI_DIR_WRITE);
12331258
}
12341259
else {
12351260
/* Blocking mode - buffer ready flag differs for read vs write */

0 commit comments

Comments
 (0)