Hi Mike,

subject: please do

mach-zynq: Support SPL boot from QSPI in memory-mapped mode


On 9/11/26 15:18, Mike Looijmans wrote:
Ever since this commit:
   Commit 9bb02f7f4533 ("mtd: spi-nor: Fix the spi_nor_read() when config 
SPI_STACKED_PARALLEL is enabled")
booting a 7-series Zynq using the SPL flow is broken, the board is unable
to read u-boot.img from QSPI flash using the updated routines in SPL. In
U-Boot proper, reading QSPI flash works fine though.

I have tested SPL on zc702 and zc706 and I can't see any issue with it.

ff22b8227d25 (HEAD -> debian-sent3, wd/next) Merge patch series "fit: cipher: bounds checks on the ciphered image path"

That's why I don't agree with your description above. It can depend on different configuration but don't think it is valid in general.


U-Boot SPL 2026.10-rc4-00395-gff22b8227d25 (Sep 14 2026 - 13:03:51 +0200)
Silicon version:        1
Trying to boot from SPI

U-Boot 2026.10-rc4-00395-gff22b8227d25 (Sep 14 2026 - 13:03:51 +0200)

CPU:   Zynq 7z045
Silicon: v1.0
Model: Xilinx ZC706 board
DRAM:  ECC disabled 1 GiB
Xilinx I2C FRU format at nvmem0:
 Manufacturer Name: XILINX
 Product Name: ZC706
 Serial No: 123456
 Part Number: 123
 File ID: U-Boot generator
 Revision Number: A
Core:  32 devices, 20 uclasses, devicetree: board
Flash: 0 Bytes
NAND:  0 MiB
MMC:   mmc@e0100000: 0
SF: Detected s25fl128s with page size 512 Bytes, erase size 128 KiB, total 32 
MiB
*** Warning - bad CRC, using default environment

In:    serial@e0001000
Out:   serial@e0001000
Err:   serial@e0001000
Net:
ZYNQ GEM: e000b000, mdio bus e000b000, phyaddr 7, interface rgmii-id

Warning: ethernet@e000b000 (eth0) using random MAC address - be:e6:2e:6f:c0:62
eth0: ethernet@e000b000
Hit any key to stop autoboot: 0
Zynq>
Zynq>


U-Boot SPL 2026.10-rc4-00395-gff22b8227d25 (Sep 14 2026 - 13:12:16 +0200)
Silicon version:        0
Trying to boot from SPI


U-Boot 2026.10-rc4-00395-gff22b8227d25 (Sep 14 2026 - 13:12:16 +0200)

CPU:   Zynq 7z020
Silicon: v0.0
Model: Xilinx ZC702 board
DRAM:  ECC disabled 1 GiB
Core:  34 devices, 22 uclasses, devicetree: board
Flash: 0 Bytes
NAND:  0 MiB
MMC:   mmc@e0100000: 0
SF: Detected n25q128a11 with page size 256 Bytes, erase size 64 KiB, total 16 
MiB
*** Warning - bad CRC, using default environment

In:    serial@e0001000
Out:   serial@e0001000
Err:   serial@e0001000
Net:
ZYNQ GEM: e000b000, mdio bus e000b000, phyaddr 7, interface rgmii-id

Warning: ethernet@e000b000 (eth0) using random MAC address - e2:94:ff:eb:eb:af
eth0: ethernet@e000b000
Hit any key to stop autoboot: 0
Zynq>


When the Zynq boots from QSPI NOR flash, the ROM will have set up the
QSPI NOR in linear mode, and the contents are now memory mapped (the first
16MB/32MB at least). All that needs to be done at this stage is to memcpy
the u-boot code into DDR RAM. This is not only extremely simple, it's also
the fastest method to read QSPI flash on this platform.
This corresponds to a standard NOR boot, hence this mode is selected as
SPL_NOR_SUPPORT.

To accomplish this, first make the SPI support optional instead of
mandatory for the ZYNQ platform. In the bootmode detection, select the
NOR bootmode instead of SPI when SPL_NOR_SUPPORT has been enabled.

To boot from QSPI NOR, write "boot.bin" to offset 0 and write "u-boot.img"
to offset CONFIG_SPL_PAD_TO in the flash. Usually CONFIG_SPL_PAD_TO will
be 0x20000 as the SPL code easily fits in 128k. The offset must fit in the
accessible range for linear mode, which is 16MB for single and 32MB for
the dual chip modes.

Tested on topic_miami boards.


I have tested it on zc702 (silicon v1) and it is not working there.
But I have also tested it on zc706 with production silicon and it is working 
there.


Signed-off-by: Mike Looijmans <[email protected]>
---

Changes in v2:
Reworded and amended commit text
Add #define for magic QSPI linear mode address
Use old method by default, use SPL_NOR_SUPPORT to switch to mmap

  arch/arm/Kconfig              | 4 ++--
  arch/arm/mach-zynq/Kconfig    | 4 ++--
  arch/arm/mach-zynq/spl.c      | 8 +++++++-
  include/configs/zynq-common.h | 3 +++
  4 files changed, 14 insertions(+), 5 deletions(-)

diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig
index 514bf2000b4..f7eb9d94848 100644
--- a/arch/arm/Kconfig
+++ b/arch/arm/Kconfig
@@ -1346,8 +1346,8 @@ config ARCH_ZYNQ
        select SPL_SOC_INIT if SPL
        select SPL_CLK if SPL
        select SPL_DM if SPL
-       select SPL_DM_SPI if SPL
-       select SPL_DM_SPI_FLASH if SPL
+       select SPL_DM_SPI if SPL && !SPL_NOR_SUPPORT
+       select SPL_DM_SPI_FLASH if SPL && !SPL_NOR_SUPPORT
        select SPL_OF_CONTROL if SPL
        select SPL_SEPARATE_BSS if SPL
        select SPL_TIMER if SPL
diff --git a/arch/arm/mach-zynq/Kconfig b/arch/arm/mach-zynq/Kconfig
index c3f505fa15c..2e6aa09fb53 100644
--- a/arch/arm/mach-zynq/Kconfig
+++ b/arch/arm/mach-zynq/Kconfig
@@ -19,10 +19,10 @@ config SPL_SERIAL
        default y
config SPL_SPI_FLASH_SUPPORT
-       default y if ZYNQ_QSPI
+       default y if ZYNQ_QSPI && !SPL_NOR_SUPPORT
config SPL_SPI
-       default y if ZYNQ_QSPI
+       default y if ZYNQ_QSPI && !SPL_NOR_SUPPORT
config ZYNQ_DDRC_INIT
        bool "Zynq DDRC initialization"
diff --git a/arch/arm/mach-zynq/spl.c b/arch/arm/mach-zynq/spl.c
index dc964dc2f9f..0332dcee402 100644
--- a/arch/arm/mach-zynq/spl.c
+++ b/arch/arm/mach-zynq/spl.c
@@ -47,10 +47,16 @@ u32 spl_boot_device(void)
        u32 mode;
switch ((zynq_slcr_get_boot_mode()) & ZYNQ_BM_MASK) {
-#ifdef CONFIG_SPL_SPI
+#ifdef CONFIG_SPL_NOR_SUPPORT
+       case ZYNQ_BM_QSPI:
+               mode = BOOT_DEVICE_NOR;
+               break;
+#else
+# ifdef CONFIG_SPL_SPI

This is every likely elif



        case ZYNQ_BM_QSPI:
                mode = BOOT_DEVICE_SPI;
                break;
+# endif
  #endif
        case ZYNQ_BM_NAND:
                mode = BOOT_DEVICE_NAND;
diff --git a/include/configs/zynq-common.h b/include/configs/zynq-common.h
index 94273d0deb9..4e14c74e31f 100644
--- a/include/configs/zynq-common.h
+++ b/include/configs/zynq-common.h
@@ -35,6 +35,9 @@
  /* Ethernet driver */
/* NOR */
+/* Load address is mmap address of QSPI flash, plus the offset */
+#define ZYNQ_QSPI0_LINEAR_ADDR 0xfc000000
+#define CFG_SYS_UBOOT_BASE     (ZYNQ_QSPI0_LINEAR_ADDR + CONFIG_SPL_PAD_TO)
#ifdef CONFIG_USB_EHCI_ZYNQ
  # define DFU_DEFAULT_POLL_TIMEOUT     300
---
base-commit: fb2a4386029c5089c71d0d52caa3b09db9ee08ac
branch: upstream-topic-miami

I think that would be better to have choices which selects things which are necessary.

Something like this. Then every platform can decide if make sense to use it or 
not

choice
       prompt "SPL QSPI boot access method"
       depends on SPL && ZYNQ_QSPI
       default ZYNQ_SPL_QSPI_DM_SPI

config ZYNQ_SPL_QSPI_DM_SPI
       bool "DM SPI-NOR framework"
       select SPL_DM_SPI
       select SPL_DM_SPI_FLASH
       select SPL_SPI
       select SPL_SPI_FLASH_SUPPORT

config ZYNQ_SPL_QSPI_MMAP
       bool "Memory-mapped linear (NOR) mode"
       select SPL_NOR_SUPPORT

endchoice

Obviously I would like to see if there could be any check that U-Boot in spi is within that 16MB windows. I don't think that simple calculation will help here. Because SPL doesn't need to be at start. It means it is clear that it has to be till 16MB but start can vary. I would try to look at reading multiboot register.
Start is clear which is SPL_PAD_TO and size is something what SPL has to know.

Did you test what it will happen when SPL tries to read above 16MB offset?

Thanks,
Michal


--
Michal Simek, Ing. (M.Eng), OpenPGP -> KeyID: FE3D1F91
w: www.monstr.eu p: +42-0-721842854
Maintainer of Linux kernel - Xilinx Microblaze
Maintainer of Linux kernel - Xilinx Zynq ARM and ZynqMP/Versal ARM64 SoCs
U-Boot custodian - Xilinx Microblaze/Zynq/ZynqMP/Versal/Versal NET SoCs
TF-A maintainer - Xilinx ZynqMP/Versal/Versal NET SoCs

Reply via email to