Skip to content

PolarFire SoC: LPDDR4 init for MPFS250T Video Kit (M-Mode)#774

Draft
dgarske wants to merge 1 commit intowolfSSL:masterfrom
dgarske:polarfire_ddr_2
Draft

PolarFire SoC: LPDDR4 init for MPFS250T Video Kit (M-Mode)#774
dgarske wants to merge 1 commit intowolfSSL:masterfrom
dgarske:polarfire_ddr_2

Conversation

@dgarske
Copy link
Copy Markdown
Member

@dgarske dgarske commented May 7, 2026

Summary

This PR adds standalone wolfBoot M-mode support for the Microchip PolarFire SoC MPFS250T Video Kit, including full LPDDR4 initialization that replaces the Hart Software Services (HSS) bootloader for the early boot path. wolfBoot now runs on the E51 monitor hart from L2 Scratch, brings up the LPDDR4 controller and PHY, runs Microchip's TIP autonomous training to completion, and exposes the trained DDR for Linux S-mode handoff.

What this enables

  • Single-bootloader flow: wolfBoot in eNVM is the only bootloader; HSS is no longer required for DDR bring-up on this board.
  • 2 GB LPDDR4 (Micron MT53D512M32D2DS-053, 1600 Mbps) usable from M-mode wolfBoot.
  • Foundation for booting Yocto Linux from SD card by staging a signed FIT image into DDR and entering S-mode on a U54 (the M->S handoff plumbing is in place; the disk-load reliability work is still in progress -- see "Known limitations" below).

Boot flow

  1. Boot ROM loads wolfBoot from eNVM (0x20220100) into L2 Scratch (0x0A000000).
  2. wolfBoot starts on E51 (hart 0) in M-mode.
  3. mpfs_ddr_init() runs:
    • NWC + MSS PLL + DDR PLL bring-up.
    • PHY setup including the 24 per-lane WPU/WPD overrides
      (config_ddr_io_pull_up_downs_rpc_bits equivalent).
    • DDR controller setup -- 183 of HSS's 199 init_ddrc register
      writes (the csr_custom block @ 0x3C000 is included with the
      critical PHY_RESET_CONTROL twin-write handshake).
    • LPDDR4 manual training body: device reset, PLL freq doubling,
      MR writes via AUTOINIT, CA-VREF, ADDCMD.
    • Hand-off to TIP for autonomous WRLVL + RDGATE + DQ_DQS.
    • Wait until train_stat = 0x1D (all four phases done).
    • Post-training sequence: DDRPHY_MODE rewrite to LIBERO value,
      rpc220 = 0xC, per-lane load_dq, MTC sanity test (256 B
      counting pattern), L2 cache flush via FLUSH64.
    • 4-pattern memory test at 0x80000000.
  4. do_boot() for WOLFBOOT_RISCV_MMODE direct M-mode jump to test app, or M->S handoff to Linux on U54 hart 1 (Phase 4A.6 disk-load is still under investigation, see "Known limitations").

Build / flash

# Toolchain: SoftConsole RISC-V GCC.
# Libero/HSS-generated fpga_design_config directory must be available
# (e.g. from the HSS Video Kit build):
HSS_FPGA=$HOME/workspace_riscv/hart-software-services/build/boards/mpfs-video-kit/fpga_design_config

# Build wolfBoot
cp config/examples/polarfire_mpfs250_m.config .config
make clean
make wolfboot.elf LIBERO_FPGA_CONFIG_DIR=$HSS_FPGA

# Flash to eNVM via mpfsBootmodeProgrammer (resets the target):
java -jar $SC_INSTALL_DIR/extras/mpfs/mpfsBootmodeProgrammer.jar \
    --bootmode 1 --die MPFS250T --package FCG1152 \
    --workdir $PWD wolfboot.elf

# UART0 at 115200 8N1 shows the DDR-init log + a 256 KB pattern
# self-test (which currently halts the boot to make it easy to
# verify reliability before disk-load runs).

The LIBERO_FPGA_CONFIG_DIR Makefile variable (added in arch.mk) is the only project-specific path; the HAL pulls every LIBERO_SETTING_* value from the standard Libero/HSS-generated fpga_design_config tree, which means a different MPFS board can re-use the HAL just by pointing this variable at its own fpga_design_config and adjusting wolfBoot's load addresses.

Verification on hardware

5-cold-boot reliability with this PR (Video Kit, eNVM bootmode 1):

Check Result
TIP train_stat = 0x1D (BCLK_SCLK + WRLVL + RDGATE + DQ_DQS) 5/5 PASS
4-pattern memory_test at 0x80000000 5/5 PASS
256 KB cached DDR-TEST at 0x82000000 (triple-write) 5/5 PASS

All four data lanes reach wl_dly = 0x31 and the controller reports INIT_DONE = 0x1. The pattern-test halts the boot on completion; disabling it (and disk-loading 19 MB) is currently the open work item described below.

@dgarske dgarske self-assigned this May 7, 2026
Copilot AI review requested due to automatic review settings May 7, 2026 22:48
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Note

Copilot was unable to run its full agentic suite in this review.

Adds standalone wolfBoot M-mode support for the PolarFire SoC MPFS250T Video Kit, including LPDDR4 bring-up (replacing HSS in the early boot path) and Linux S-mode handoff plumbing.

Changes:

  • Enhance SDHCI diagnostics and reliability workarounds (CMD0→CMD8 delay, single-block read option, capability logging).
  • Extend RISC-V M-mode boot flow with a reusable M→S handoff API and MPFS-specific “release U54 hart” implementation.
  • Introduce MPFS250 DDR/PHY init infrastructure, build-time enablement via LIBERO_FPGA_CONFIG_DIR, new config template, and CI build job.

Reviewed changes

Copilot reviewed 7 out of 8 changed files in this pull request and generated 7 comments.

Show a summary per file
File Description
src/sdhci.c Adds richer error logging, controller register dump, and reliability workarounds for Cadence SD4HC.
src/boot_riscv.c Adds trap register dump support (regs frame) and factors M→S handoff into overridable helpers.
hal/mpfs250.h Adds MPFS250 peripheral bits and extensive DDRC/PHY register definitions + DDR init declarations.
hal/mpfs250.c Implements MPFS250 DDR/PLL/PHY init, M→S boot on a U54 via IPI handoff, and UART reinit after PLL.
docs/Targets.md Documents new “M-Mode + DDR” configuration and build-time Libero config integration.
config/examples/polarfire_mpfs250_m.config Adds new example config for M-mode + LPDDR4 + SD + S-mode Linux boot.
arch.mk Enables MPFS DDR init when LIBERO_FPGA_CONFIG_DIR is provided (adds -DMPFS_DDR_INIT and include path).
.github/workflows/test-configs.yml Adds CI build job for the new MPFS250 M-mode + DDR config template.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread hal/mpfs250.c
Comment on lines +561 to +563

/* Reinitialize UART for new clock frequency */
hal_uart_reinit();
Comment thread hal/mpfs250.c
Comment on lines +1953 to +1965
uint32_t div0_1_orig = DDR_PLL_REG(PLL_DIV_0_1);
uint32_t div2_3_orig = DDR_PLL_REG(PLL_DIV_2_3);
{
uint32_t div0 = div0_1_orig & 0x3F00UL;
uint32_t div1 = div0_1_orig & 0x3F000000UL;
uint32_t div2 = div2_3_orig & 0x3F00UL;
uint32_t div3 = div2_3_orig & 0x3F000000UL;
uint32_t mult = 2;

/* Double the dividers for MR writes */
DDR_PLL_REG(PLL_DIV_0_1) = (div0 | div1) * mult;
DDR_PLL_REG(PLL_DIV_2_3) = (div2 | div3) * mult;

Comment thread hal/mpfs250.c
Comment on lines +282 to +291
/* Simple busy-loop delay
* Approximately us microseconds at ~40MHz (early boot clock)
* This is used before the timer is fully reliable */
static void ddr_delay(uint32_t us)
{
volatile uint32_t i;
/* At ~40MHz, ~10 loop iterations per microsecond */
for (i = 0; i < us * 10; i++) {
__asm__ volatile("nop");
}
Comment thread hal/mpfs250.c
Comment on lines +1966 to +1968
/* Wait for PHY PLL to lock */
while ((DDRPHY_REG(PHY_PLL_CTRL_MAIN) & 0x2000000UL) == 0) {}
ddr_delay(5000);
Comment thread src/boot_riscv.c

unsigned long WEAKFUNCTION handle_trap(unsigned long cause, unsigned long epc,
unsigned long tval)
unsigned long tval, unsigned long *regs)
Comment thread src/sdhci.c
Comment on lines 1430 to +1435

/* Dump capability + presence registers so the bring-up log shows the
* controller's reported base clock and whether a card was detected. */
wolfBoot_printf("SDHCI: SRS09=0x%08X SRS16=0x%08X SRS17=0x%08X\n",
SDHCI_REG(SDHCI_SRS09), SDHCI_REG(SDHCI_SRS16),
SDHCI_REG(SDHCI_SRS17));
uses: ./.github/workflows/test-build-riscv.yml
with:
arch: riscv64
config-file: ./config/examples/polarfire_mpfs250_m.config
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants