Skip to content

Zynq UltraScale+ MPSoC PS-QSPI flashing support #654

Description

@xerpi

Zynq UltraScale+ MPSoC QSPI flash is PS-only, so the existing PL-based spiOverJtag approach does not seem applicable here.

I traced AMD Vitis 2025.2 program_flash and it appears to use this flow:

  1. program_flash starts rdi_zynq_flash.
  2. rdi_zynq_flash talks to hw_server.
  3. It runs the provided FSBL through the debug interface to initialize the PS/DDR/QSPI environment.
  4. It loads a Xilinx-provided AArch64 QSPI helper, selected by flash type/density, from:
    /opt/Xilinx/2025.2/data/xicom/cfgmem/uboot/
  5. It sends commands/data over XSDB/XMD/hw_server to that helper, which performs QSPI erase/write/read using the PS QSPI controller and MIO pins.

The helper selection appears to be by file name, for example:

  • zynqmp_qspi_x8_dual_parallel_1024.bin
  • zynqmp_qspi_x4_single.bin
  • zynqmp_qspi_x1_single.bin

Those files are not plain binaries. file reports:

ELF 64-bit LSB executable, ARM aarch64, statically linked

readelf shows:

Entry point address: 0xfffc0000
Section .data address: 0xfffc0000

So it is an AArch64 U-Boot image linked to run from ZynqMP OCM at 0xfffc0000.

The shipped images look like small boardless U-Boot builds, likely from AMD/Xilinx u-boot-xlnx. Strings in the helper identify it clearly:

U-Boot 2025.01
ZynqMP MINI QSPI PARALLEL
ZynqMP>
spi@ff0f0000
xlnx,zynqmp-qspi-1.0
jedec,spi-nor
parallel-memories
spi-rx-bus-width
SPI flash sub-system

Other variants show:

  • ZynqMP MINI QSPI SINGLE
  • ZynqMP MINI QSPI X1 SINGLE

The Vitis host library also builds normal U-Boot commands. I decoded these command templates from:

/opt/Xilinx/2025.2/Vitis/lib/lnx64.o/libxv_xicom_hw.so

sf erase %X %X
sf read %X %X %X
sf write %X %X %X
cp.b %X %X %X
nand erase %X %X
nand read %X %X %X
nand write %X %X %X

The helper itself contains the matching SPI flash strings, including probe, erase, write, and `No SPI flash selected. Please run \sf probe``.

The helper's embedded DTB sets:

aliases {
    serial0 = "/dcc";
};
chosen {
    stdout-path = "serial0:115200n8";
};
dcc {
    compatible = "arm,dcc";
    status = "okay";
};

So the mini U-Boot console is using the ARM Debug Communications Channel (arm_dcc), not a normal UART, as expected.

On the host side, hw_server / XSDB also appears to use debug streams. In /opt/Xilinx/2025.2/Vitis/lib/lnx64.o/libxv_xicom_hw.so, XicomHWXsdbInterfaceUtils::connectHWStreams() gets TX/RX stream IDs and connects them, and XicomHWDebugInterface::sendCommand() sends command strings through XicomHWStreamsWriteCmd to the helper's RX stream.

From: /opt/Xilinx/2025.2/data/xicom/cfgmem/uboot/zynqmp_qspi_x8_dual_parallel_1024.bin
llvm-objdump shows:

fffcb2e8: d5330100      mrs x0, MDCCSR_EL0
fffcb2ec: 36f7ffe0      tbz w0, #0x1e, 0xfffcb2e8
fffcb2f0: d5330500      mrs x0, DBGDTRRX_EL0
fffcb2f4: d65f03c0      ret

fffcb310: d5330102      mrs x2, MDCCSR_EL0
fffcb314: 37efff62      tbnz w2, #0x1d, 0xfffcb300
fffcb318: d5130501      msr DBGDTRTX_EL0, x1
fffcb31c: 52800000      mov w0, #0x0

fffcb32c: d5330100      mrs x0, MDCCSR_EL0
fffcb330: 12020000      and w0, w0, #0x40000000
fffcb338: d5330100      mrs x0, MDCCSR_EL0
fffcb33c: d2630000      eor x0, x0, #0x20000000
fffcb340: 531d7400      ubfx w0, w0, #29, #1

This is exactly the ARM DCC path:

  • MDCCSR_EL0 checks DCC status bits
  • DBGDTRRX_EL0 reads debugger -> CPU data
  • DBGDTRTX_EL0 writes CPU -> debugger data

So the command path seems to be:
program_flash -> hw_server -> XSDB run-control streams -> target DCC-backed console -> U-Boot command loop

Question:
Would it be acceptable to bundle a copy of the Vitis-provided U-Boot images used by program_flash, or would we need to build equivalent helpers from source instead?

If source is required, could we use upstream u-boot-xlnx and compile the different images when compiling openFPGALoader?

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions