diff --git a/.github/workflows/test-configs.yml b/.github/workflows/test-configs.yml index ad7244b7df..91fe5ccc80 100644 --- a/.github/workflows/test-configs.yml +++ b/.github/workflows/test-configs.yml @@ -624,6 +624,23 @@ jobs: config-file: ./config/examples/polarfire_mpfs250_m.config pre-build: sh tools/ci/gen_mpfs_libero_stub.sh tools/ci/mpfs_libero_stub make-args: LIBERO_FPGA_CONFIG_DIR=tools/ci/mpfs_libero_stub + # The HSS replacement booting from the other two stores: eMMC (same SDHCI + # driver as SD, different pads) and QSPI into DDR (src/update_ram.c rather + # than src/update_disk.c). + microchip_mpfs250_m_emmc_test: + uses: ./.github/workflows/test-build-riscv.yml + with: + arch: riscv64 + config-file: ./config/examples/polarfire_mpfs250_m_emmc.config + pre-build: sh tools/ci/gen_mpfs_libero_stub.sh tools/ci/mpfs_libero_stub + make-args: LIBERO_FPGA_CONFIG_DIR=tools/ci/mpfs_libero_stub + microchip_mpfs250_m_qspi_ddr_test: + uses: ./.github/workflows/test-build-riscv.yml + with: + arch: riscv64 + config-file: ./config/examples/polarfire_mpfs250_m_qspi_ddr.config + pre-build: sh tools/ci/gen_mpfs_libero_stub.sh tools/ci/mpfs_libero_stub + make-args: LIBERO_FPGA_CONFIG_DIR=tools/ci/mpfs_libero_stub microchip_mpfs250_m_mldsa_test: uses: ./.github/workflows/test-build-riscv.yml with: diff --git a/config/examples/polarfire_mpfs250_m_emmc.config b/config/examples/polarfire_mpfs250_m_emmc.config new file mode 100644 index 0000000000..a6a724a749 --- /dev/null +++ b/config/examples/polarfire_mpfs250_m_emmc.config @@ -0,0 +1,162 @@ +# PolarFire SoC MPFS250T M-Mode (Machine Mode) with LPDDR4 + eMMC +# +# Identical to polarfire_mpfs250_m.config except for the boot device. One +# SDHCI controller serves both the SD slot and the eMMC through an external +# demux, so the two are mutually exclusive: this build drives the eMMC pads +# and the SD slot is unreachable until a build with DISK_SDCARD=1 runs again. +# On the Video Kit, check the MMC bus voltage jumpers (J16/J35/J36) before +# programming an eMMC build. +# +# Standalone wolfBoot replacing HSS: +# 1. eNVM (0x20220100) -> L2_SCRATCH (0x0A000000) - wolfBoot starts +# 2. M-mode init: PLLs, DDR controller, LPDDR4 training (Video Kit) +# 3. Load signed FIT from eMMC to DDR staging (0x82000000); after verify, +# kernel -> 0x80200000 (FIT "load"), DTB -> 0x8A000000 +# 4. Verify ECC384/SHA384 signature +# 5. Drop to S-mode and jump to kernel +# +# Flash via mpfsBootmodeProgrammer (bootmode 1): +# java -jar mpfsBootmodeProgrammer.jar --bootmode 1 --die MPFS250T \ +# --package FCG1152 --workdir $PWD wolfboot.elf + +ARCH?=RISCV64 +TARGET?=mpfs250 +SIGN?=ECC384 +HASH?=SHA384 +IMAGE_HEADER_SIZE=512 +WOLFBOOT_VERSION?=1 +ARMORED?=0 +DEBUG?=0 +DEBUG_SYMBOLS?=1 +DEBUG_UART?=1 +VTOR?=1 +EXT_FLASH?=0 +SPI_FLASH?=0 +NO_XIP?=1 +NVM_FLASH_WRITEONCE?=0 +UART_FLASH?=0 +V?=0 +NO_MPU?=1 +RAM_CODE?=0 +SPMATH?=0 +SPMATHALL?=1 +DUALBANK_SWAP?=0 +PKA?=0 +ENCRYPT=0 +WOLFTPM?=0 +ELF?=1 +#DEBUG_ELF?=1 + +OPTIMIZATION_LEVEL=1 + +# M-Mode configuration: runs on E51 from L2 SRAM +RISCV_MMODE?=1 + +# Stack size per hart (L2 SRAM constraints). Single source of truth: this +# Makefile var feeds both the startup asm (-DSTACK_SIZE_PER_HART) and the +# linker script (@STACK_SIZE_PER_HART@ in mpfs250-m.ld). +STACK_SIZE_PER_HART=4096 + +# E51 core lacks RISC-V crypto extensions (Zknh), use portable C +# RISC-V SHA256/384/512 assembly (wolfcrypt port/riscv) enabled by default. +# Verified on the MPFS250 E51 (rv64imac); requires wolfSSL with the RISC-V +# unaligned-access fix (PR #10530, present in the lib/wolfssl submodule). +# The E51 handles unaligned access so the default (faster) asm path is used; +# add -DWOLFSSL_RISCV_ASM_NO_UNALIGNED for RISC-V cores that trap on it. +NO_ASM?=0 + +# Enable LPDDR4 init in hal_init() by pointing at the Libero/HSS-generated +# fpga_design_config directory for this board. The directory must contain +# fpga_design_config.h and its sub-headers (memory_map/, ddr/, clocks/, ...). +# Typical sources: +# - HSS Video Kit build: +# /build/boards/mpfs-video-kit/fpga_design_config +# - Libero MSS Configurator export for the design. +# The -I path is added and -DMPFS_DDR_INIT is set automatically when this is +# non-empty (see arch.mk). Override on the command line for one-off builds: +# make LIBERO_FPGA_CONFIG_DIR=/path/to/fpga_design_config +LIBERO_FPGA_CONFIG_DIR?= + +# Boot Linux: drop to S-mode after wolfBoot verifies kernel +CFLAGS_EXTRA+=-DWOLFBOOT_MMODE_SMODE_BOOT + +# SD card storage for kernel image (no QSPI flash) +DISK_SDCARD?=0 +DISK_EMMC?=1 + +# wolfBoot in L2 SRAM: all 4 scratchpad ways (0x0A000000 - 0x0A07FFFF) +WOLFBOOT_ORIGIN?=0x0A000000 +WOLFBOOT_L2SCRATCH_SIZE?=512k + +# Boot-hart stack, sized for ML-DSA-87 verify on top of the two +# IMAGE_HEADER_SIZE buffers update_disk.c puts on the stack. ECC384 needs less. +STACK_SIZE?=64k + +# 4KB sector size (SD card flow is partition-based, not flash-erase-based) +WOLFBOOT_SECTOR_SIZE?=0x1000 + +# Scratch address where the signed FIT image is staged before signature +# verification + FIT parse. 0x82000000 is 32 MB into the cached DDR window +# at 0x80000000, which is 1 GB wide - 0xC0000000 up is the non-cached alias +# onto the same DDR, so staging must stay below it. It is clear of the +# kernel destination below and 128 MB below the DTB region, which is the +# headroom the staged-image bound further down depends on. +# After the FIT is parsed: +# kernel is copied to 0x80200000 (FIT-internal "load") +# DTB is copied to WOLFBOOT_LOAD_DTS_ADDRESS (0x8A000000) +# Layout: +# 0x80200000 - 0x814FFFFF : kernel (~19 MB after parse) +# 0x82000000 - 0x832FFFFF : FIT scratch (~19 MB - overwritten on next boot) +# 0x8A000000 - 0x8A004FFF : DTB +WOLFBOOT_LOAD_ADDRESS?=0x82000000 + +# DTB load address in DDR +WOLFBOOT_LOAD_DTS_ADDRESS?=0x8A000000 + +# Bound the UNAUTHENTICATED FIT image length before it drives the disk read +# into the DDR staging region (required by src/update_disk.c). The FIT is +# staged at WOLFBOOT_LOAD_ADDRESS (0x82000000); the DTB load region begins +# 128 MB above at 0x8A000000, so cap the staged image at 128 MB so an +# attacker-declared fw_size cannot overrun the DTB region before the +# signature check runs. +WOLFBOOT_RAMBOOT_MAX_SIZE=0x08000000 + +# Use update_disk loader (partition A/B numbering instead of flash addresses). +# BOOT_PART_A / BOOT_PART_B are 0-indexed GPT entry numbers. GPT partitions +# in the SD card layout of docs/PolarFire.md: +# index 0 (parted "boot" 1 MiB - 33 MiB) -> active boot FIT +# index 1 (parted "update" 33 MiB - 65 MiB) -> inactive/update slot +# index 2 (parted "rootfs" 65 MiB - end) -> Linux rootfs +WOLFBOOT_NO_PARTITIONS=1 +CFLAGS_EXTRA+=-DBOOT_PART_A=0 +CFLAGS_EXTRA+=-DBOOT_PART_B=1 + +# Speed up disk partition read (512KB chunks - max DMA size) +CFLAGS_EXTRA+=-DDISK_BLOCK_SIZE=0x80000 + +# Video Kit routes the SD slot's Card Detect (CD#) signal through the FPGA +# fabric rather than MSSIO, so the SDHCI controller's hardware CI/CDPL +# detection always reads 'no card' in M-mode (no fabric configuration). +# Force the SD bring-up code to assume a card is present. +CFLAGS_EXTRA+=-DSDHCI_FORCE_CARD_DETECT + +# Optional encryption (kernel signed+encrypted with AES-256) +#CUSTOM_ENCRYPT_KEY=1 +#ENCRYPT=1 +#ENCRYPT_WITH_AES256=1 +#OBJS_EXTRA=src/my_custom_encrypt_key.o + +# Used by test-application/ELF wrapper +WOLFBOOT_PARTITION_BOOT_ADDRESS=0x80200000 +WOLFBOOT_PARTITION_SIZE=0x4000000 + +# Debug options (useful for initial M-mode + DDR bring-up) +CFLAGS_EXTRA+=-DDEBUG_BOOT +#CFLAGS_EXTRA+=-DDEBUG_SDHCI +#CFLAGS_EXTRA+=-DDEBUG_DISK +#CFLAGS_EXTRA+=-DDISK_TEST +# Verbose register-level DDR tracing (development aid). Historically the +# DBG_DDR printf delays appeared load-bearing for TIP training; that was +# resolved by the auto-init-disable training reorder and the WRCALIB +# all-4-lane accept gate with retry, so this is safe to leave disabled. +#CFLAGS_EXTRA+=-DDEBUG_DDR diff --git a/config/examples/polarfire_mpfs250_m_qspi_ddr.config b/config/examples/polarfire_mpfs250_m_qspi_ddr.config new file mode 100644 index 0000000000..06eefb558c --- /dev/null +++ b/config/examples/polarfire_mpfs250_m_qspi_ddr.config @@ -0,0 +1,80 @@ +# PolarFire SoC MPFS250T M-Mode (Machine Mode) with LPDDR4 + SC QSPI +# +# Standalone wolfBoot replacing HSS, booting Linux from QSPI instead of a +# disk. polarfire_mpfs250_m_qspi.config is the other QSPI M-mode build: it +# runs an application out of the L2 scratchpad and never brings up DDR. This +# one is the HSS-replacement configuration with QSPI as the image store, so it +# uses src/update_ram.c rather than src/update_disk.c and keeps the A/B update +# slots the disk configuration does not have. +# +# Standalone wolfBoot replacing HSS: +# 1. eNVM (0x20220100) -> L2_SCRATCH (0x0A000000) - wolfBoot starts +# 2. M-mode init: PLLs, DDR controller, LPDDR4 training (Video Kit) +# 3. Load signed FIT from QSPI to DDR staging (0x82000000); after verify, +# kernel -> 0x80200000 (FIT "load"), DTB -> 0x8A000000 +# 4. Verify ECC384/SHA384 signature +# 5. Drop to S-mode and jump to kernel +# +# The slots are sized for a Linux FIT: 48 MB each in the Video Kit's 128 MB +# MT25QL01G, which the 32 MB slots of the application configuration cannot +# hold. Writing a slot that size over the UART programmer is impractical, so +# UART_QSPI_PROGRAM is off here; write QSPI from a running Linux (the SBI +# vendor extension flash services, MPFS_SBI_VENDOR=1) or from a programmer. +# +# Flash via mpfsBootmodeProgrammer (bootmode 1): +# java -jar mpfsBootmodeProgrammer.jar --bootmode 1 --die MPFS250T \ +# --package FCG1152 --workdir $PWD wolfboot.elf + +ARCH?=RISCV64 +TARGET?=mpfs250 +SIGN?=ECC384 +HASH?=SHA384 +IMAGE_HEADER_SIZE=512 +WOLFBOOT_VERSION?=1 +ARMORED?=0 +DEBUG?=0 +DEBUG_SYMBOLS?=1 +DEBUG_UART?=1 +VTOR?=1 +EXT_FLASH?=1 +SPI_FLASH?=0 +NO_XIP?=1 +NVM_FLASH_WRITEONCE?=0 +UART_FLASH?=0 +UART_QSPI_PROGRAM?=0 +V?=0 +NO_MPU?=1 +RAM_CODE?=0 +SPMATH?=0 +SPMATHALL?=1 +DUALBANK_SWAP?=0 +PKA?=0 +ENCRYPT=0 +WOLFTPM?=0 +ELF?=1 +OPTIMIZATION_LEVEL=1 +RISCV_MMODE?=1 +STACK_SIZE_PER_HART=4096 +NO_ASM?=0 +LIBERO_FPGA_CONFIG_DIR?= +CFLAGS_EXTRA+=-DWOLFBOOT_MMODE_SMODE_BOOT +CFLAGS_EXTRA+=-DMPFS_SC_SPI +DISK_SDCARD?=0 +DISK_EMMC?=0 +WOLFBOOT_ORIGIN?=0x0A000000 +WOLFBOOT_L2SCRATCH_SIZE?=512k +STACK_SIZE?=64k +WOLFBOOT_SECTOR_SIZE?=0x10000 +WOLFBOOT_LOAD_ADDRESS?=0x82000000 +WOLFBOOT_LOAD_DTS_ADDRESS?=0x8A000000 +WOLFBOOT_RAMBOOT_MAX_SIZE=0x08000000 +WOLFBOOT_PARTITION_BOOT_ADDRESS=0x100000 +WOLFBOOT_PARTITION_SIZE=0x3000000 +WOLFBOOT_PARTITION_UPDATE_ADDRESS=0x3100000 +WOLFBOOT_PARTITION_SWAP_ADDRESS=0x6100000 +# Standalone DTB regions after the swap, as polarfire_mpfs250_qspi.config has +# them. A FIT carries its own fdt sub-image and never reaches these; they are +# the fallback for booting a plain kernel image out of QSPI. +WOLFBOOT_DTS_BOOT_ADDRESS=0x6110000 +WOLFBOOT_DTS_UPDATE_ADDRESS=0x6120000 +CFLAGS_EXTRA+=-DDEBUG_BOOT diff --git a/docs/PolarFire.md b/docs/PolarFire.md index e69e6a0f1d..a8ca7c3c6f 100644 --- a/docs/PolarFire.md +++ b/docs/PolarFire.md @@ -219,7 +219,7 @@ The programmer's `--die` list covers `MPFS025T` through `MPFS460T` and their `_E ## Boot configurations -Seven ready-to-use config templates cover all supported boot mode / storage / memory combinations: +Nine ready-to-use config templates cover all supported boot mode / storage / memory combinations: | Configuration | Config File | Boot Mode | Storage | Memory | HSS | |---------------|-------------|-----------|---------|--------|-----| @@ -229,6 +229,8 @@ Seven ready-to-use config templates cover all supported boot mode / storage / me | **QSPI + L2-LIM** | `polarfire_mpfs250_hss_l2lim.config` | S-mode (U54 via HSS) | SC QSPI | L2-LIM (no DDR) | Yes | | **M-Mode (no HSS)** | `polarfire_mpfs250_m_qspi.config` | M-mode (E51, no HSS) | SC QSPI | L2 Scratchpad | No | | **M-Mode + DDR** | `polarfire_mpfs250_m.config` | M-mode (E51, no HSS) | SD Card | LPDDR4 (DDR) | No | +| **M-Mode + DDR, eMMC** | `polarfire_mpfs250_m_emmc.config` | M-mode (E51, no HSS) | eMMC | LPDDR4 (DDR) | No | +| **M-Mode + DDR, QSPI** | `polarfire_mpfs250_m_qspi_ddr.config` | M-mode (E51, no HSS) | SC QSPI | LPDDR4 (DDR) | No | | **Boot mode 2 UBL** | `polarfire_mpfs250_ubl.config` | System Controller -> sNVM stub | eNVM (verifies it) | L2-LIM | No | The **M-Mode + DDR** configuration brings up the LPDDR4 controller from @@ -250,6 +252,16 @@ still produces a working M-mode wolfBoot without DDR. Add `-DDEBUG_DDR` to `CFLAGS_EXTRA` for verbose register-level traces during bring-up. +The eMMC and QSPI variants are the same configuration with a different +image store. One SDHCI controller reaches both the SD slot and the eMMC +through an external demux, so the SD and eMMC builds are mutually exclusive: +`DISK_EMMC=1` drives the eMMC pads (the Libero `ALT_` IOMUX set on a design +that configures both) and the SD slot is then unreachable until an SD build +runs again. The QSPI variant drops the disk driver entirely and loads the +signed FIT from flash with `src/update_ram.c`, which keeps the A/B update +slots the disk configuration does not have; its slots are 48 MB because a +Linux FIT does not fit the 32 MB slots of the application QSPI build. + For GitHub Actions, `tools/ci/gen_mpfs_libero_stub.sh` generates a compile-only stub (every `LIBERO_SETTING_*` symbol referenced by the HAL, defined to `0`; loop-bound settings to `1U`) so the M-Mode + DDR diff --git a/hal/hal.c b/hal/hal.c index dbd39264c1..8be30ef42c 100644 --- a/hal/hal.c +++ b/hal/hal.c @@ -284,14 +284,16 @@ int hal_flash_test_dualbank(void) #endif /* TEST_FLASH */ -#ifdef MMU +#if defined(MMU) || defined(WOLFBOOT_FDT) /* Weak default for targets with no configured device tree; some HALs also - * compile their own out under WOLFBOOT_NO_PARTITIONS. */ + * compile their own out under WOLFBOOT_NO_PARTITIONS. Guarded to match the + * callers in src/update_ram.c and the declaration in include/hal.h: a target + * that parses a device tree without a full MMU configuration needs it too. */ WEAKFUNCTION void* hal_get_dts_address(void) { return NULL; } -#endif /* MMU */ +#endif /* MMU || WOLFBOOT_FDT */ WEAKFUNCTION int RAMFUNCTION hal_flash_protect(haladdr_t address, int len) { diff --git a/hal/mpfs250.c b/hal/mpfs250.c index 4a26432e9b..545565f5c3 100644 --- a/hal/mpfs250.c +++ b/hal/mpfs250.c @@ -279,6 +279,10 @@ hal_smode_boot(unsigned long entry, unsigned long hartid, unsigned long dtb) (MSS_PERIPH_MMUART0 << 4)); __asm__ volatile("fence iorw, iorw" ::: "memory"); + /* Same for the MMC: a QSPI-boot build never touches it, and the kernel's + * clock driver ungates SUBBLK_CLOCK_CR but does not lift the soft reset. */ + mpfs_mmc_os_release(); + mpfs_kernel_handoff[MPFS_FIRST_U54_HART].entry = (uint64_t)entry; mpfs_kernel_handoff[MPFS_FIRST_U54_HART].opaque = (uint64_t)dtb; __asm__ volatile("fence iorw, iorw" ::: "memory"); @@ -1697,6 +1701,12 @@ static int qspi_flash_read(uint32_t address, uint8_t *data, uint32_t len) address += chunk_len; data += chunk_len; remaining -= chunk_len; + + /* A watchdog that cannot be disabled counts from its last refresh, and + * this loop is the only thing running for the whole of a multi-megabyte + * image load, so an unserviced load resets the chip mid-read. One + * refresh per 64 KB chunk costs nothing against the transfer. */ + mpfs_wdt_pet_all(); } return (int)len; @@ -2127,7 +2137,8 @@ int ext_flash_erase(uintptr_t address, int len) #endif /* EXT_FLASH */ -#if defined(MMU) && !defined(WOLFBOOT_NO_PARTITIONS) +#if (defined(MMU) || defined(WOLFBOOT_FDT)) && \ + !defined(WOLFBOOT_NO_PARTITIONS) void* hal_get_dts_address(void) { #if defined(EXT_FLASH) && defined(NO_XIP) @@ -2188,26 +2199,61 @@ void plic_dispatch_irq(uint32_t irq) /* Route the SDHCI pins to the slot pads, which HSS does in mssio_setup(): * without it the controller talks to floating pads. Values from Libero. */ #if defined(WOLFBOOT_RISCV_MMODE) && defined(MPFS_DDR_INIT) + +/* One SDHCI controller reaches either the SD slot or the eMMC through an + * external demux, so a build drives the pads for the one it boots from. A + * Libero design that configures both (MSSIO_CONFIGURATION_OPTIONS carrying + * EMMC_CONFIGURED | SD_CONFIGURED) names one of them in DEFAULT_ON_START and + * supplies the other as the ALT_ settings; the kits set SD as the default, so + * eMMC is the alternate set. HSS picks between them in switch_mssio_config(). + */ +#if defined(DISK_EMMC) +#if !defined(LIBERO_SETTING_ALT_IOMUX0_CR) +#error "an eMMC build needs a Libero design that configures SD and eMMC both" +#endif +/* Named one per register rather than pasted together: the CI Libero stub + * generator collects the LIBERO_SETTING_* names by grepping these sources, so + * a pasted name would not be declared in a stub build. */ +#define MPFS_IOMUX0_CR LIBERO_SETTING_ALT_IOMUX0_CR +#define MPFS_IOMUX1_CR LIBERO_SETTING_ALT_IOMUX1_CR +#define MPFS_IOMUX2_CR LIBERO_SETTING_ALT_IOMUX2_CR +#define MPFS_IOMUX3_CR LIBERO_SETTING_ALT_IOMUX3_CR +#define MPFS_IOMUX4_CR LIBERO_SETTING_ALT_IOMUX4_CR +#define MPFS_IOMUX5_CR LIBERO_SETTING_ALT_IOMUX5_CR +#define MPFS_IOMUX6_CR LIBERO_SETTING_ALT_IOMUX6_CR +/* Pads 30 and 34 pull down for eMMC where the SD side drives them high. */ +#define MPFS_DEMUX_SELECT ((0xDu << 0) | (0xDu << 16) | (0xDu << 28)) +#else +#define MPFS_IOMUX0_CR LIBERO_SETTING_IOMUX0_CR +#define MPFS_IOMUX1_CR LIBERO_SETTING_IOMUX1_CR +#define MPFS_IOMUX2_CR LIBERO_SETTING_IOMUX2_CR +#define MPFS_IOMUX3_CR LIBERO_SETTING_IOMUX3_CR +#define MPFS_IOMUX4_CR LIBERO_SETTING_IOMUX4_CR +#define MPFS_IOMUX5_CR LIBERO_SETTING_IOMUX5_CR +#define MPFS_IOMUX6_CR LIBERO_SETTING_IOMUX6_CR +#define MPFS_DEMUX_SELECT ((0xEu << 0) | (0xEu << 16) | (0xDu << 28)) +#endif + void mpfs_iomux_init(void) { uint32_t iomux4, iomux5; - SYSREG_REG(SYSREG_IOMUX0_CR_OFFSET) = LIBERO_SETTING_IOMUX0_CR; - SYSREG_REG(SYSREG_IOMUX1_CR_OFFSET) = LIBERO_SETTING_IOMUX1_CR; - SYSREG_REG(SYSREG_IOMUX2_CR_OFFSET) = LIBERO_SETTING_IOMUX2_CR; - SYSREG_REG(SYSREG_IOMUX3_CR_OFFSET) = LIBERO_SETTING_IOMUX3_CR; + SYSREG_REG(SYSREG_IOMUX0_CR_OFFSET) = MPFS_IOMUX0_CR; + SYSREG_REG(SYSREG_IOMUX1_CR_OFFSET) = MPFS_IOMUX1_CR; + SYSREG_REG(SYSREG_IOMUX2_CR_OFFSET) = MPFS_IOMUX2_CR; + SYSREG_REG(SYSREG_IOMUX3_CR_OFFSET) = MPFS_IOMUX3_CR; - /* Board GPIO drive overrides that steer the external SD/eMMC demux into - * SD-card mode; HSS does this in switch_demux_using_fabric_ip(). */ - iomux4 = LIBERO_SETTING_IOMUX4_CR; - iomux5 = LIBERO_SETTING_IOMUX5_CR; + /* Board GPIO drive overrides that steer the external SD/eMMC demux to the + * selected device; HSS does this in switch_demux_using_fabric_ip(). */ + iomux4 = MPFS_IOMUX4_CR; + iomux5 = MPFS_IOMUX5_CR; iomux4 &= ~(0xFu << 16); iomux4 |= (0xDu << 16); iomux5 &= ~((0xFu << 0) | (0xFu << 16) | (0xFu << 28)); - iomux5 |= ((0xEu << 0) | (0xEu << 16) | (0xDu << 28)); + iomux5 |= MPFS_DEMUX_SELECT; SYSREG_REG(SYSREG_IOMUX4_CR_OFFSET) = iomux4; SYSREG_REG(SYSREG_IOMUX5_CR_OFFSET) = iomux5; - SYSREG_REG(SYSREG_IOMUX6_CR_OFFSET) = LIBERO_SETTING_IOMUX6_CR; + SYSREG_REG(SYSREG_IOMUX6_CR_OFFSET) = MPFS_IOMUX6_CR; /* Bank-wide config goes via SCB; per-pad IO_CFG goes via SYSREG. */ SYSREGSCB_REG(SCB_MSSIO_BANK4_CFG_CR_OFFSET) = @@ -2246,30 +2292,36 @@ void mpfs_iomux_init(void) __asm__ volatile("fence iorw, iorw" ::: "memory"); } -#endif /* WOLFBOOT_RISCV_MMODE && MPFS_DDR_INIT */ - -#if defined(DISK_SDCARD) || defined(DISK_EMMC) -/* SDHCI Platform HAL */ - /* Each AXI master has 16 PMPCFG entries at 0x20005000 + (index << 8); MMC is * index 7. Without them a master stalls silently mid-transaction. */ #define MSS_MPU_BASE 0x20005000UL #define MSS_MPU_MMC_BASE (MSS_MPU_BASE + (7UL << 8)) -#ifdef MPFS_DDR_INIT -/* Needs LIBERO_FPGA_CONFIG_DIR. HSS configures these entries itself, so - * HSS-loaded builds do not need it. */ -static void mpfs_mpu_init_mmc(void) +/* Leave the MMC usable by whoever runs next, which a build that boots from + * QSPI would otherwise never do: the block stays clock-gated and in soft + * reset, and the OS driver's first register access hangs the bus rather than + * failing. HSS does this for its payload, so an HSS replacement owes the OS + * the same, exactly as it does for the MMUARTs at the hand-off. Needs + * LIBERO_FPGA_CONFIG_DIR for the MPU entries. */ +void mpfs_mmc_os_release(void) { volatile uint64_t *pmp = (volatile uint64_t *)MSS_MPU_MMC_BASE; + pmp[0] = LIBERO_SETTING_MMC_MPU_CFG_PMP0; pmp[1] = LIBERO_SETTING_MMC_MPU_CFG_PMP1; pmp[2] = LIBERO_SETTING_MMC_MPU_CFG_PMP2; pmp[3] = LIBERO_SETTING_MMC_MPU_CFG_PMP3; __asm__ volatile("fence iorw, iorw" ::: "memory"); + SYSREG_REG(SYSREG_SUBBLK_CLOCK_CR_OFF) |= MSS_PERIPH_MMC; + __asm__ volatile("fence iorw, iorw" ::: "memory"); + SYSREG_SOFT_RESET_CR &= ~MSS_PERIPH_MMC; + __asm__ volatile("fence iorw, iorw" ::: "memory"); } -#endif /* MPFS_DDR_INIT */ +#endif /* WOLFBOOT_RISCV_MMODE && MPFS_DDR_INIT */ + +#if defined(DISK_SDCARD) || defined(DISK_EMMC) +/* SDHCI Platform HAL */ /* Pet the watchdogs during the SDHCI read loops; overrides the weak no-op in * src/sdhci.c. A multi-second image load outlives the watchdog period. */ @@ -2283,15 +2335,18 @@ void sdhci_platform_init(void) /* Routing is already committed by nwc_init(); this is the MMC master MPU, * clock and soft reset, mirroring the DDRC sequence in mpfs_ddr_init(). */ wolfBoot_printf("SDHCI: platform init\n"); -#ifdef MPFS_DDR_INIT - /* LIBERO_SETTING_MMC_MPU_CFG_* needs LIBERO_FPGA_CONFIG_DIR; without it - * the build runs under HSS, which has configured the MPU already. */ - mpfs_mpu_init_mmc(); -#endif +/* Guarded to match the definition above rather than relying on MPFS_DDR_INIT + * implying an M-mode build. LIBERO_SETTING_MMC_MPU_CFG_* needs + * LIBERO_FPGA_CONFIG_DIR; without it the build runs under HSS, which has + * configured the MPU already. */ +#if defined(MPFS_DDR_INIT) && defined(WOLFBOOT_RISCV_MMODE) + mpfs_mmc_os_release(); +#else SYSREG_REG(SYSREG_SUBBLK_CLOCK_CR_OFF) |= MSS_PERIPH_MMC; __asm__ volatile("fence iorw, iorw" ::: "memory"); SYSREG_SOFT_RESET_CR &= ~MSS_PERIPH_MMC; __asm__ volatile("fence iorw, iorw" ::: "memory"); +#endif } void sdhci_platform_irq_init(void) diff --git a/hal/mpfs250.h b/hal/mpfs250.h index 0a87a8c0c9..01dcdd8fe7 100644 --- a/hal/mpfs250.h +++ b/hal/mpfs250.h @@ -762,6 +762,9 @@ extern uint32_t mpfs_apb_clk_hz; /* MSSIO IOMUX setup: defined in hal/mpfs250.c (alongside the SDHCI platform * helpers) but called from nwc_init() in hal/mpfs250_ddr.c. */ void mpfs_iomux_init(void); +/* MMC clock, soft reset and master MPU, left configured for the OS even when + * wolfBoot does not boot from the MMC itself. */ +void mpfs_mmc_os_release(void); #endif /* PDMA-based memcpy: src must be CPU-readable (L2 Scratch / LIM / DDR diff --git a/include/hal.h b/include/hal.h index e95fec218c..05b7f33338 100644 --- a/include/hal.h +++ b/include/hal.h @@ -155,7 +155,9 @@ int hal_dma_set_noncached(uintptr_t start, uintptr_t end); void* hal_get_update_address(void); #endif -#ifdef MMU +/* The FDT boot path needs these on a target that parses a device tree + * without a full MMU configuration (RISC-V M-mode). */ +#if defined(MMU) || defined(WOLFBOOT_FDT) void *hal_get_dts_address(void); void *hal_get_dts_update_address(void); /* Optional hook: supply a boot DTB when the loaded image carries none. @@ -169,7 +171,7 @@ int hal_dma_set_noncached(uintptr_t start, uintptr_t end); * boot disk is still open. Weak default is a no-op returning 0. */ int hal_boot_slot_select(void); -#endif +#endif /* MMU || WOLFBOOT_FDT */ #ifdef DISK_FAILOVER_ZEROIZE /* Disk boot: why the operational slots are being given up on, handed to diff --git a/src/sdhci.c b/src/sdhci.c index 55ecd0e1c1..fdf360763c 100644 --- a/src/sdhci.c +++ b/src/sdhci.c @@ -1329,10 +1329,21 @@ static int emmc_send_op_cond(uint32_t ocr_arg, uint32_t *ocr_reg) { int status; uint32_t timeout = 1000; /* retry count */ + uint32_t query = 1000; /* retry count for the first CMD1 */ uint32_t response; - /* First CMD1 to query supported voltages */ - status = sdhci_cmd(MMC_CMD1_SEND_OP_COND, 0, SDHCI_RESP_R3); + /* First CMD1 to query supported voltages. A device still powering up + * does not answer this, so it is retried like the ready poll below + * instead of failing the whole init on one timeout: on a cold boot the + * first attempt loses the race and a warm one does not, which shows up + * as an eMMC that only boots every second time. */ + do { + status = sdhci_cmd(MMC_CMD1_SEND_OP_COND, 0, SDHCI_RESP_R3); + if (status == 0) { + break; + } + udelay(1000); + } while (--query); if (status != 0) { wolfBoot_printf("eMMC: CMD1 query failed\n"); return status; diff --git a/src/update_ram.c b/src/update_ram.c index d92d2d46bc..81dad3fb20 100644 --- a/src/update_ram.c +++ b/src/update_ram.c @@ -298,7 +298,7 @@ void RAMFUNCTION wolfBoot_start(void) * WOLFBOOT_FDT without MMU, booting a non-FIT image -> no fixup). */ uint8_t *dts_addr = NULL; #endif -#ifdef MMU +#if defined(MMU) || defined(WOLFBOOT_FDT) uint32_t dts_size = 0; /* Validated view of the FIT staged at load_address. */ fdt_ctx fit_ctx; @@ -612,7 +612,7 @@ void RAMFUNCTION wolfBoot_start(void) #endif #endif -#ifdef MMU +#if defined(MMU) || defined(WOLFBOOT_FDT) /* Snapshot the digest from the verified header before os_image can be * reused for the DTS partition below. (FIT DTBs are covered by the FIT.) */ dts_tlv_len = wolfBoot_get_header(&os_image, HDR_DEVICE_TREE_DIGEST, @@ -832,7 +832,7 @@ void RAMFUNCTION wolfBoot_start(void) } } #endif -#endif /* MMU */ +#endif /* MMU || WOLFBOOT_FDT */ #ifdef WOLFBOOT_UBOOT_LEGACY /* Enter the uImage at ih_ep. Skipped if a later stage (ELF/FIT) succeeded