public inbox for u-boot@lists.denx.de
 help / color / mirror / Atom feed
* [PATCH v3 0/6] imx9{4,5,52}: Add Quickboot support
@ 2026-04-02  9:40 Simona Toaca (OSS)
  2026-04-02  9:40 ` [PATCH v3 1/6] imx9: Add support for saving DDR training data to NVM Simona Toaca (OSS)
                   ` (5 more replies)
  0 siblings, 6 replies; 17+ messages in thread
From: Simona Toaca (OSS) @ 2026-04-02  9:40 UTC (permalink / raw)
  To: uboot-imx, u-boot
  Cc: Stefano Babic, festevam, peng.fan, alice.guo, viorel.suman,
	simona.toaca, ye.li, ping.bai, marex, sebastien.szymanski, ravi,
	joao.goncalves, ji.luo, semen.protsenko, tharvey, qijian.guo

From: Simona Toaca <simona.toaca@nxp.com>

This patch series adds support for saving DDR training
data to non-volatile memory on iMX94, iMX95 and iMX952 platforms.
The purpose is running DDR Quickboot flow on next reboot.

The process is as follows:
- OEI runs Training flow for the DDRPHY
- OEI saves the data from training to volatile memory
- U-Boot can then save it to non-volatile memory (e.g. SD)
- OEI loads the data from NVM at cold reboot and runs Quickboot flow

By skipping training, a much lower boot time is achieved.

Changes for v3:
- Rebased and added support for iMX952
- Removed IMX_SNPS_DDR_PHY_QB_GEN macro, as it was not useful ->
now CMD_QB is enabled by default on the supported boards
- Removed unnecessary #ifdefs -> replaced with if (CONFIG..)
- Replaced spi_flash_probe with udevice_first_device_err to
avoid using SPI macros that needed ifdefs, since there is only
one SPI flash device available.
- Adnotated qb methods with qb_ to be easier to see in asm dump
- Removed explicit pointer casts from (void *)
- Replaced custom qb_crc32 with the U-Boot one
- Made eveything snake_case
- Enabled SFDP support for iMX943/95, as it is necessary for
proper erase size parsing (and is already present in iMX952 config)
- Improved documentation - explanation about the space in bootloader
- Added commit fixing a style issue in Kconfig

Changes for v2:
- Improved documentation to clarify the questions asked
- Detailed log messages for all commits
- Detailed Kconfig options for SPL_IMX_QB and CMD_IMX_QB
- Fixed the mentioned coding style issues

Simona Toaca (6):
  imx9: Add support for saving DDR training data to NVM
  arm: mach-imx: Add command to expose QB functionality
  configs: imx9{43, 5}: Enable SPI SFDP support
  board: nxp: imx9{4,5,52}_evk: Add qb save option in SPL
  doc: board: nxp: Add Quickboot documentation
  drivers: ddr: imx: Fix Kconfig for SAVED_DRAM_TIMING_BASE

 arch/arm/include/asm/arch-imx9/ddr.h |  48 +++-
 arch/arm/include/asm/mach-imx/qb.h   |  15 ++
 arch/arm/mach-imx/Kconfig            |  19 ++
 arch/arm/mach-imx/Makefile           |   1 +
 arch/arm/mach-imx/cmd_qb.c           | 132 ++++++++++
 arch/arm/mach-imx/imx9/Makefile      |  10 +-
 arch/arm/mach-imx/imx9/qb.c          | 379 +++++++++++++++++++++++++++
 arch/arm/mach-imx/imx9/scmi/soc.c    |   7 +
 board/nxp/imx94_evk/spl.c            |   6 +-
 board/nxp/imx952_evk/spl.c           |   4 +
 board/nxp/imx95_evk/spl.c            |   6 +-
 configs/imx943_evk_defconfig         |   1 +
 configs/imx95_15x15_evk_defconfig    |   1 +
 configs/imx95_evk.config             |   1 +
 doc/board/nxp/index.rst              |   1 +
 doc/board/nxp/qb.rst                 |  54 ++++
 drivers/ddr/imx/imx9/Kconfig         |   9 +-
 17 files changed, 688 insertions(+), 6 deletions(-)
 create mode 100644 arch/arm/include/asm/mach-imx/qb.h
 create mode 100644 arch/arm/mach-imx/cmd_qb.c
 create mode 100644 arch/arm/mach-imx/imx9/qb.c
 create mode 100644 doc/board/nxp/qb.rst

-- 
2.43.0


^ permalink raw reply	[flat|nested] 17+ messages in thread

* [PATCH v3 1/6] imx9: Add support for saving DDR training data to NVM
  2026-04-02  9:40 [PATCH v3 0/6] imx9{4,5,52}: Add Quickboot support Simona Toaca (OSS)
@ 2026-04-02  9:40 ` Simona Toaca (OSS)
  2026-04-03 23:00   ` Marek Vasut
  2026-04-05 11:49   ` Simon Glass
  2026-04-02  9:40 ` [PATCH v3 2/6] arm: mach-imx: Add command to expose QB functionality Simona Toaca (OSS)
                   ` (4 subsequent siblings)
  5 siblings, 2 replies; 17+ messages in thread
From: Simona Toaca (OSS) @ 2026-04-02  9:40 UTC (permalink / raw)
  To: uboot-imx, u-boot
  Cc: Stefano Babic, festevam, peng.fan, alice.guo, viorel.suman,
	simona.toaca, ye.li, ping.bai, marex, sebastien.szymanski, ravi,
	joao.goncalves, ji.luo, semen.protsenko, tharvey, qijian.guo

From: Simona Toaca <simona.toaca@nxp.com>

DDR training data can be saved to NVM and be available
to OEI at boot time, which will trigger QuickBoot flow.

U-Boot only checks for data integrity (CRC32), while
OEI is in charge of authentication when it tries to
load the data from NVM.

On iMX95 A0/A1, 'authentication' is done via another
CRC32. On the other boards, authentication is done by
using ELE to check the MAC stored in the ddrphy_qb_state
structure.

Supported platforms: iMX94, iMX95, iMX952 (using OEI)
Supported storage types: eMMC, SD, SPI flash.

Signed-off-by: Viorel Suman <viorel.suman@nxp.com>
Signed-off-by: Ye Li <ye.li@nxp.com>
Signed-off-by: Simona Toaca <simona.toaca@nxp.com>
---
 arch/arm/include/asm/arch-imx9/ddr.h |  48 +++-
 arch/arm/include/asm/mach-imx/qb.h   |  15 ++
 arch/arm/mach-imx/imx9/Makefile      |   6 +-
 arch/arm/mach-imx/imx9/qb.c          | 379 +++++++++++++++++++++++++++
 arch/arm/mach-imx/imx9/scmi/soc.c    |   7 +
 drivers/ddr/imx/imx9/Kconfig         |   7 +
 6 files changed, 459 insertions(+), 3 deletions(-)
 create mode 100644 arch/arm/include/asm/mach-imx/qb.h
 create mode 100644 arch/arm/mach-imx/imx9/qb.c

diff --git a/arch/arm/include/asm/arch-imx9/ddr.h b/arch/arm/include/asm/arch-imx9/ddr.h
index a8e3f7354c7..290e3e4e06e 100644
--- a/arch/arm/include/asm/arch-imx9/ddr.h
+++ b/arch/arm/include/asm/arch-imx9/ddr.h
@@ -1,6 +1,6 @@
 /* SPDX-License-Identifier: GPL-2.0+ */
 /*
- * Copyright 2022 NXP
+ * Copyright 2022-2026 NXP
  */
 
 #ifndef __ASM_ARCH_IMX8M_DDR_H
@@ -100,6 +100,52 @@ struct dram_timing_info {
 
 extern struct dram_timing_info dram_timing;
 
+/* Quick Boot related */
+#define DDRPHY_QB_CSR_SIZE	5168
+#define DDRPHY_QB_ACSM_SIZE	(4 * 1024)
+#define DDRPHY_QB_MSB_SIZE	0x200
+#define DDRPHY_QB_PSTATES	0
+#define DDRPHY_QB_PST_SIZE	(DDRPHY_QB_PSTATES * 4 * 1024)
+
+/**
+ * This structure needs to be aligned with the one in OEI.
+ */
+struct ddrphy_qb_state {
+	u32 crc;		  /* Used for ensuring integrity in DRAM */
+#define MAC_LENGTH              8 /* 256 bits, 32-bit aligned */
+	u32 mac[MAC_LENGTH];	  /* For 95A0/1 use mac[0] to keep CRC32 value */
+	u8 trained_vrefca_a0;
+	u8 trained_vrefca_a1;
+	u8 trained_vrefca_b0;
+	u8 trained_vrefca_b1;
+	u8 trained_vrefdq_a0;
+	u8 trained_vrefdq_a1;
+	u8 trained_vrefdq_b0;
+	u8 trained_vrefdq_b1;
+	u8 trained_vrefdqu_a0;
+	u8 trained_vrefdqu_a1;
+	u8 trained_vrefdqu_b0;
+	u8 trained_vrefdqu_b1;
+	u8 trained_dramdfe_a0;
+	u8 trained_dramdfe_a1;
+	u8 trained_dramdfe_b0;
+	u8 trained_dramdfe_b1;
+	u8 trained_dramdca_a0;
+	u8 trained_dramdca_a1;
+	u8 trained_dramdca_b0;
+	u8 trained_dramdca_b1;
+	u16 qb_pll_upll_prog0;
+	u16 qb_pll_upll_prog1;
+	u16 qb_pll_upll_prog2;
+	u16 qb_pll_upll_prog3;
+	u16 qb_pll_ctrl1;
+	u16 qb_pll_ctrl4;
+	u16 qb_pll_ctrl5;
+	u16 csr[DDRPHY_QB_CSR_SIZE];
+	u16 acsm[DDRPHY_QB_ACSM_SIZE];
+	u16 pst[DDRPHY_QB_PST_SIZE];
+};
+
 void ddr_load_train_firmware(enum fw_type type);
 int ddr_init(struct dram_timing_info *timing_info);
 int ddr_cfg_phy(struct dram_timing_info *timing_info);
diff --git a/arch/arm/include/asm/mach-imx/qb.h b/arch/arm/include/asm/mach-imx/qb.h
new file mode 100644
index 00000000000..aeec26718cb
--- /dev/null
+++ b/arch/arm/include/asm/mach-imx/qb.h
@@ -0,0 +1,15 @@
+/* SPDX-License-Identifier: GPL-2.0+ */
+/*
+ * Copyright 2026 NXP
+ */
+
+#ifndef __IMX_QB_H__
+#define __IMX_QB_H__
+
+#include <stdbool.h>
+
+bool qb_check(void);
+int qb(int qb_dev, bool save);
+void spl_qb_save(void);
+
+#endif
diff --git a/arch/arm/mach-imx/imx9/Makefile b/arch/arm/mach-imx/imx9/Makefile
index 53cc97c6b47..d2e44f0d5f9 100644
--- a/arch/arm/mach-imx/imx9/Makefile
+++ b/arch/arm/mach-imx/imx9/Makefile
@@ -1,6 +1,6 @@
 # SPDX-License-Identifier: GPL-2.0+
 #
-# Copyright 2022 NXP
+# Copyright 2022,2026 NXP
 
 obj-y += lowlevel_init.o
 
@@ -12,4 +12,6 @@ endif
 
 ifneq ($(CONFIG_SPL_BUILD),y)
 obj-y += imx_bootaux.o
-endif
\ No newline at end of file
+endif
+
+obj-y += qb.o
diff --git a/arch/arm/mach-imx/imx9/qb.c b/arch/arm/mach-imx/imx9/qb.c
new file mode 100644
index 00000000000..220545192d4
--- /dev/null
+++ b/arch/arm/mach-imx/imx9/qb.c
@@ -0,0 +1,379 @@
+// SPDX-License-Identifier: GPL-2.0+
+/**
+ * Copyright 2024-2026 NXP
+ */
+#include <dm/device-internal.h>
+#include <dm/uclass.h>
+#include <errno.h>
+#include <imx_container.h>
+#include <linux/bitfield.h>
+#include <mmc.h>
+#include <spi_flash.h>
+#include <spl.h>
+#include <stdlib.h>
+#include <u-boot/crc.h>
+
+#include <asm/arch/ddr.h>
+#include <asm/mach-imx/boot_mode.h>
+#include <asm/mach-imx/sys_proto.h>
+
+#define QB_STATE_LOAD_SIZE    SZ_64K
+
+#define MMC_DEV		0
+#define QSPI_DEV	1
+
+#define IMG_FLAGS_IMG_TYPE_MASK   0xF
+#define IMG_FLAGS_IMG_TYPE(x)     FIELD_GET(IMG_FLAGS_IMG_TYPE_MASK, (x))
+
+#define IMG_TYPE_DDR_TDATA_DUMMY  0xD   /* dummy DDR training data image */
+
+bool qb_check(void)
+{
+	struct ddrphy_qb_state *qb_state;
+	u32 size, crc;
+
+	/**
+	 * Ensure CRC is not empty, the reason is that
+	 * the data is invalidated after first save run
+	 * or after it is overwritten.
+	 */
+	qb_state = (struct ddrphy_qb_state *)CONFIG_QB_SAVED_STATE_BASE;
+	size = sizeof(struct ddrphy_qb_state) - sizeof(qb_state->crc);
+	crc = crc32(0, (u8 *)qb_state->mac, size);
+
+	if (!qb_state->crc || crc != qb_state->crc)
+		return false;
+
+	return true;
+}
+
+static unsigned long qb_get_boot_device_offset(void *dev, int dev_type)
+{
+	unsigned long offset = 0;
+	struct mmc *mmc;
+
+	switch (dev_type) {
+	case MMC_DEV:
+		mmc = dev;
+
+		if (IS_SD(mmc) || mmc->part_config == MMCPART_NOAVAILABLE) {
+			offset = CONTAINER_HDR_MMCSD_OFFSET;
+		} else {
+			u8 part = EXT_CSD_EXTRACT_BOOT_PART(mmc->part_config);
+
+			if (part == EMMC_BOOT_PART_BOOT1 || part == EMMC_BOOT_PART_BOOT2)
+				offset = CONTAINER_HDR_EMMC_OFFSET;
+			else
+				offset = CONTAINER_HDR_MMCSD_OFFSET;
+		}
+		break;
+	case QSPI_DEV:
+		offset = CONTAINER_HDR_QSPI_OFFSET;
+		break;
+	default:
+		return -EOPNOTSUPP;
+	}
+
+	return offset;
+}
+
+static int qb_parse_container(void *addr, u32 *qb_data_off)
+{
+	struct container_hdr *phdr;
+	struct boot_img_t *img_entry;
+	int i = 0;
+	u32 img_type, img_end;
+
+	phdr = addr;
+	if (phdr->tag != 0x87 || (phdr->version != 0x0 && phdr->version != 0x2))
+		return -EINVAL;
+
+	img_entry = addr + sizeof(struct container_hdr);
+	for (i = 0; i < phdr->num_images; i++) {
+		img_type = IMG_FLAGS_IMG_TYPE(img_entry->hab_flags);
+		if (img_type == IMG_TYPE_DDR_TDATA_DUMMY && img_entry->size == 0) {
+			/* Image entry pointing to DDR Training Data */
+			*qb_data_off = img_entry->offset;
+			return 0;
+		}
+
+		img_end = img_entry->offset + img_entry->size;
+		if (i + 1 < phdr->num_images) {
+			img_entry++;
+			if (img_end + QB_STATE_LOAD_SIZE == img_entry->offset) {
+				/* hole detected */
+				*qb_data_off = img_end;
+				return 0;
+			}
+		}
+	}
+
+	return -EINVAL;
+}
+
+static int get_dev_qbdata_offset(void *dev, int dev_type, unsigned long offset,
+				 u32 *qbdata_offset)
+{
+	int ret = -EOPNOTSUPP;
+	u16 ctnr_hdr_align = CONTAINER_HDR_ALIGNMENT;
+	void *buf = kmalloc(ctnr_hdr_align, GFP_KERNEL);
+
+	if (!buf) {
+		printf("kmalloc buffer failed\n");
+		return -ENOMEM;
+	}
+
+	switch (dev_type) {
+	case MMC_DEV:
+		unsigned long count = 0;
+		struct mmc *mmc = dev;
+
+		if (!(CONFIG_IS_ENABLED(DM_MMC) && CONFIG_IS_ENABLED(MMC_WRITE)))
+			goto get_dev_qbdata_offset_exit;
+
+		count = blk_dread(mmc_get_blk_desc(mmc),
+				  offset / mmc->read_bl_len,
+				  ctnr_hdr_align / mmc->read_bl_len,
+				  buf);
+		if (count == 0) {
+			printf("Read container image from MMC/SD failed\n");
+			ret = -EIO;
+			goto get_dev_qbdata_offset_exit;
+		}
+		break;
+	case QSPI_DEV:
+		if (!CONFIG_IS_ENABLED(SPI))
+			goto get_dev_qbdata_offset_exit;
+
+		ret = spi_flash_read(dev, offset,
+				     ctnr_hdr_align, buf);
+		if (ret) {
+			printf("Read container header from QSPI failed\n");
+			ret = -EIO;
+			goto get_dev_qbdata_offset_exit;
+		}
+		break;
+	default:
+		printf("Support for device %d not enabled\n", dev_type);
+		goto get_dev_qbdata_offset_exit;
+	}
+
+	ret = qb_parse_container(buf, qbdata_offset);
+
+get_dev_qbdata_offset_exit:
+	free(buf);
+
+	return ret;
+}
+
+static int get_qbdata_offset(void *dev, int dev_type, u32 *qbdata_offset)
+{
+	u32 offset = qb_get_boot_device_offset(dev, dev_type);
+	u16 ctnr_hdr_align = CONTAINER_HDR_ALIGNMENT;
+	u32 cont_offset;
+	int ret, i;
+
+	for (i = 0; i < 3; i++) {
+		cont_offset = offset + i * ctnr_hdr_align;
+		ret = get_dev_qbdata_offset(dev, dev_type, cont_offset, qbdata_offset);
+		if (ret == 0) {
+			(*qbdata_offset) += cont_offset;
+			break;
+		}
+	}
+
+	return ret;
+}
+
+static int qb_mmc_get_device_index(u32 dev)
+{
+	switch (dev) {
+	case BOOT_DEVICE_MMC1:
+		return 0;
+	case BOOT_DEVICE_MMC2:
+	case BOOT_DEVICE_MMC2_2:
+		return 1;
+	}
+
+	return -ENODEV;
+}
+
+static int qb_mmc_find_device(struct mmc **mmcp, int mmc_dev)
+{
+	int ret;
+
+	ret = mmc_init_device(mmc_dev);
+	if (ret)
+		return ret;
+
+	*mmcp = find_mmc_device(mmc_dev);
+
+	return *mmcp ? 0 : -ENODEV;
+}
+
+static int qb_mmc(int dev, bool save)
+{
+	struct mmc *mmc;
+	int ret = 0, mmc_dev;
+	bool has_hw_part;
+	u8 orig_part, part;
+	u32 offset;
+	void *buf;
+
+	if (!(CONFIG_IS_ENABLED(DM_MMC) && CONFIG_IS_ENABLED(MMC_WRITE))) {
+		printf("Please enable MMC and MMC_WRITE.\n");
+		return -EOPNOTSUPP;
+	}
+
+	mmc_dev = qb_mmc_get_device_index(dev);
+	if (mmc_dev < 0)
+		return mmc_dev;
+
+	ret = qb_mmc_find_device(&mmc, mmc_dev);
+	if (ret) {
+		printf("MMC %d not found.\n", mmc_dev);
+		return ret;
+	}
+
+	ret = mmc_init(mmc);
+	if (ret)
+		return ret;
+
+	has_hw_part = !IS_SD(mmc) && mmc->part_config != MMCPART_NOAVAILABLE;
+
+	if (has_hw_part) {
+		orig_part = mmc_get_blk_desc(mmc)->hwpart;
+		part = EXT_CSD_EXTRACT_BOOT_PART(mmc->part_config);
+
+		/* Select the partition */
+		ret = mmc_switch_part(mmc, part);
+		if (ret)
+			return ret;
+	}
+
+	ret = get_qbdata_offset(mmc, MMC_DEV, &offset);
+	if (ret)
+		return ret;
+
+	if (save) {
+		/* QB data is stored in DDR -> can use it as buf */
+		buf = (void *)CONFIG_QB_SAVED_STATE_BASE;
+		ret = blk_dwrite(mmc_get_blk_desc(mmc),
+				 offset / mmc->write_bl_len,
+				 QB_STATE_LOAD_SIZE / mmc->write_bl_len,
+				 (const void *)buf);
+	} else {
+		/* erase */
+		ret = blk_derase(mmc_get_blk_desc(mmc),
+				 offset / mmc->write_bl_len,
+				 QB_STATE_LOAD_SIZE / mmc->write_bl_len);
+	}
+
+	if (!ret)
+		return -EIO;
+
+	if (!has_hw_part)
+		return 0;
+
+	/* Return to original partition */
+	return mmc_switch_part(mmc, orig_part);
+}
+
+static int qb_spi_find_device(struct spi_flash **dev)
+{
+	int ret;
+	struct udevice *udev;
+
+	ret = uclass_first_device_err(UCLASS_SPI_FLASH, &udev);
+
+	if (ret)
+		return ret;
+
+	*dev = dev_get_uclass_priv(udev);
+
+	return *dev ? 0 : -ENODEV;
+}
+
+static int qb_spi(int dev, bool save)
+{
+	int ret = 0;
+	u32 offset;
+	void *buf;
+	struct spi_flash *flash;
+
+	if (!CONFIG_IS_ENABLED(SPI)) {
+		printf("Please enable SPI.\n");
+		return -EOPNOTSUPP;
+	}
+
+	ret = qb_spi_find_device(&flash);
+	if (ret) {
+		printf("SPI flash not found.\n");
+		return -ENODEV;
+	}
+
+	ret = get_qbdata_offset(flash, QSPI_DEV, &offset);
+	if (ret)
+		return ret;
+
+	ret = spi_flash_erase(flash, offset,
+			      QB_STATE_LOAD_SIZE);
+
+	if (ret)
+		return ret;
+
+	if (!save)
+		return 0;
+
+	/* QB data is stored in DDR -> can use it as buf */
+	buf = (void *)CONFIG_QB_SAVED_STATE_BASE;
+	ret = spi_flash_write(flash, offset,
+			      QB_STATE_LOAD_SIZE, buf);
+
+	return ret;
+}
+
+int qb(int qb_dev, bool save)
+{
+	int ret = -EINVAL;
+
+	if (save && !qb_check())
+		return ret;
+
+	switch (qb_dev) {
+	case BOOT_DEVICE_MMC1:
+	case BOOT_DEVICE_MMC2:
+	case BOOT_DEVICE_MMC2_2:
+		ret = qb_mmc(qb_dev, save);
+		break;
+	case BOOT_DEVICE_SPI:
+		ret = qb_spi(qb_dev, save);
+		break;
+	default:
+		printf("Unsupported quickboot device\n");
+		break;
+	}
+
+	if (ret)
+		return ret;
+
+	if (!save)
+		return 0;
+
+	/**
+	 * invalidate qb_state mem so that at next boot
+	 * the check function will fail and save won't happen
+	 */
+	memset((void *)CONFIG_QB_SAVED_STATE_BASE, 0, sizeof(struct ddrphy_qb_state));
+
+	return 0;
+}
+
+void spl_qb_save(void)
+{
+	int dev = spl_boot_device();
+
+	/* Save QB data on current boot device */
+	if (qb(dev, true))
+		printf("QB save failed\n");
+}
diff --git a/arch/arm/mach-imx/imx9/scmi/soc.c b/arch/arm/mach-imx/imx9/scmi/soc.c
index fbee435786c..86570e763d7 100644
--- a/arch/arm/mach-imx/imx9/scmi/soc.c
+++ b/arch/arm/mach-imx/imx9/scmi/soc.c
@@ -310,6 +310,13 @@ static struct mm_region imx9_mem_map[] = {
 		.attrs = PTE_BLOCK_MEMTYPE(MT_DEVICE_NGNRNE) |
 			 PTE_BLOCK_NON_SHARE |
 			 PTE_BLOCK_PXN | PTE_BLOCK_UXN
+	}, {
+		/* QB data */
+		.virt = CONFIG_QB_SAVED_STATE_BASE,
+		.phys = CONFIG_QB_SAVED_STATE_BASE,
+		.size = 0x200000UL,	/* 2M */
+		.attrs = PTE_BLOCK_MEMTYPE(MT_NORMAL) |
+			 PTE_BLOCK_OUTER_SHARE
 	}, {
 		/* empty entry to split table entry 5 if needed when TEEs are used */
 		0,
diff --git a/drivers/ddr/imx/imx9/Kconfig b/drivers/ddr/imx/imx9/Kconfig
index 0a45340ffb6..de1f59bfaf5 100644
--- a/drivers/ddr/imx/imx9/Kconfig
+++ b/drivers/ddr/imx/imx9/Kconfig
@@ -29,4 +29,11 @@ config SAVED_DRAM_TIMING_BASE
 	  info into memory for low power use.
 	default 0x2051C000
 
+config QB_SAVED_STATE_BASE
+	hex "Define the base address for saved QuickBoot state"
+	default 0x8fe00000
+	help
+	  Once DRAM is trained, the resulted training info is
+	  saved into memory in order to be reachable from U-Boot.
+
 endmenu
-- 
2.43.0


^ permalink raw reply related	[flat|nested] 17+ messages in thread

* [PATCH v3 2/6] arm: mach-imx: Add command to expose QB functionality
  2026-04-02  9:40 [PATCH v3 0/6] imx9{4,5,52}: Add Quickboot support Simona Toaca (OSS)
  2026-04-02  9:40 ` [PATCH v3 1/6] imx9: Add support for saving DDR training data to NVM Simona Toaca (OSS)
@ 2026-04-02  9:40 ` Simona Toaca (OSS)
  2026-04-03 23:16   ` Marek Vasut
  2026-04-02  9:40 ` [PATCH v3 3/6] configs: imx9{43, 5}: Enable SPI SFDP support Simona Toaca (OSS)
                   ` (3 subsequent siblings)
  5 siblings, 1 reply; 17+ messages in thread
From: Simona Toaca (OSS) @ 2026-04-02  9:40 UTC (permalink / raw)
  To: uboot-imx, u-boot
  Cc: Stefano Babic, festevam, peng.fan, alice.guo, viorel.suman,
	simona.toaca, ye.li, ping.bai, marex, sebastien.szymanski, ravi,
	joao.goncalves, ji.luo, semen.protsenko, tharvey, qijian.guo

From: Simona Toaca <simona.toaca@nxp.com>

This command exposes 3 methods:
- check -> checks if the data in volatile memory is valid
	   (integrity check)
- save  -> saves the data to non-volatile memory and
	   erases the data in volatile memory
- erase	-> erases the data in non-volatile memory

cmd_qb can be used either directly in the U-Boot console
or in an uuu script to save the QB data during flashing.
It supports specifying a different boot medium than the
current boot device for saving the data.

Signed-off-by: Viorel Suman <viorel.suman@nxp.com>
Signed-off-by: Ye Li <ye.li@nxp.com>
Signed-off-by: Simona Toaca <simona.toaca@nxp.com>
---
 arch/arm/mach-imx/Kconfig       |  11 +++
 arch/arm/mach-imx/Makefile      |   1 +
 arch/arm/mach-imx/cmd_qb.c      | 132 ++++++++++++++++++++++++++++++++
 arch/arm/mach-imx/imx9/Makefile |   4 +-
 4 files changed, 147 insertions(+), 1 deletion(-)
 create mode 100644 arch/arm/mach-imx/cmd_qb.c

diff --git a/arch/arm/mach-imx/Kconfig b/arch/arm/mach-imx/Kconfig
index e4014226582..48266cfd6e2 100644
--- a/arch/arm/mach-imx/Kconfig
+++ b/arch/arm/mach-imx/Kconfig
@@ -71,6 +71,17 @@ config CSF_SIZE
 	  Define the maximum size for Command Sequence File (CSF) binary
 	  this information is used to define the image boot data.
 
+config CMD_IMX_QB
+	bool "Support the 'qb' command"
+	default y
+	depends on IMX94 || IMX95 || IMX952
+	help
+	  Enable qb command to write/erase DDR quick boot training
+	  data to/from a chosen boot device. Using 'qb save/erase'
+	  without arguments implies using the current boot device.
+	  For use in uuu scripts, the boot device must be specified
+	  explicitly.
+
 config CMD_BMODE
 	bool "Support the 'bmode' command"
 	default y
diff --git a/arch/arm/mach-imx/Makefile b/arch/arm/mach-imx/Makefile
index bf6820de655..43febc10460 100644
--- a/arch/arm/mach-imx/Makefile
+++ b/arch/arm/mach-imx/Makefile
@@ -80,6 +80,7 @@ endif
 ifneq ($(CONFIG_XPL_BUILD),y)
 obj-$(CONFIG_CMD_BMODE) += cmd_bmode.o
 obj-$(CONFIG_CMD_HDMIDETECT) += cmd_hdmidet.o
+obj-$(CONFIG_CMD_IMX_QB) += cmd_qb.o
 obj-$(CONFIG_CMD_DEKBLOB) += cmd_dek.o
 obj-$(CONFIG_CMD_NANDBCB) += cmd_nandbcb.o
 endif
diff --git a/arch/arm/mach-imx/cmd_qb.c b/arch/arm/mach-imx/cmd_qb.c
new file mode 100644
index 00000000000..33e987f18e0
--- /dev/null
+++ b/arch/arm/mach-imx/cmd_qb.c
@@ -0,0 +1,132 @@
+// SPDX-License-Identifier: GPL-2.0+
+/**
+ * Copyright 2024-2026 NXP
+ */
+#include <command.h>
+#include <spl.h>
+#include <stdlib.h>
+
+#include <asm/mach-imx/boot_mode.h>
+#include <asm/mach-imx/sys_proto.h>
+#include <asm/mach-imx/qb.h>
+
+static int get_board_boot_device(enum boot_device dev)
+{
+	switch (dev) {
+	case SD1_BOOT:
+	case MMC1_BOOT:
+		return BOOT_DEVICE_MMC1;
+	case SD2_BOOT:
+	case MMC2_BOOT:
+		return BOOT_DEVICE_MMC2;
+	case USB_BOOT:
+		return BOOT_DEVICE_BOARD;
+	case QSPI_BOOT:
+		return BOOT_DEVICE_SPI;
+	default:
+		return BOOT_DEVICE_NONE;
+	}
+}
+
+static void parse_qb_args(int argc, char * const argv[],
+			  int *qb_dev, int qb_bootdev)
+{
+	long dev = -1;
+	char *interface = "";
+
+	if (argc < 2) {
+		/* qb save -> use boot device */
+		*qb_dev = qb_bootdev;
+	} else {
+		interface = argv[1];
+	}
+
+	if (argc == 3)
+		dev = simple_strtol(argv[2], NULL, 10);
+
+	if (!strcmp(interface, "mmc") && dev >= 0 &&
+	    dev <= (BOOT_DEVICE_MMC2_2 - BOOT_DEVICE_MMC1))
+		*qb_dev = BOOT_DEVICE_MMC1 + dev;
+	else if (!strcmp(interface, "spi"))
+		*qb_dev = BOOT_DEVICE_SPI;
+}
+
+static int do_qb(struct cmd_tbl *cmdtp, int flag, int argc,
+		 char * const argv[], bool save)
+{
+	int ret = CMD_RET_FAILURE;
+	enum boot_device boot_dev = UNKNOWN_BOOT;
+	int qb_dev = BOOT_DEVICE_NONE, qb_bootdev;
+
+	boot_dev = get_boot_device();
+	qb_bootdev = get_board_boot_device(boot_dev);
+
+	parse_qb_args(argc, argv, &qb_dev, qb_bootdev);
+
+	ret = qb(qb_dev, save);
+
+	return ret ? CMD_RET_FAILURE : CMD_RET_SUCCESS;
+}
+
+static int do_qb_check(struct cmd_tbl *cmdtp, int flag,
+		       int argc, char * const argv[])
+{
+	return qb_check() ? CMD_RET_SUCCESS : CMD_RET_FAILURE;
+}
+
+static int do_qb_save(struct cmd_tbl *cmdtp, int flag,
+		      int argc, char * const argv[])
+{
+	return do_qb(cmdtp, flag, argc, argv, true);
+}
+
+static int do_qb_erase(struct cmd_tbl *cmdtp, int flag,
+		       int argc, char * const argv[])
+{
+	return do_qb(cmdtp, flag, argc, argv, false);
+}
+
+static struct cmd_tbl cmd_qb[] = {
+	U_BOOT_CMD_MKENT(check, 1, 1, do_qb_check, "", ""),
+	U_BOOT_CMD_MKENT(save,  3, 1, do_qb_save,  "", ""),
+	U_BOOT_CMD_MKENT(erase, 3, 1, do_qb_erase, "", ""),
+};
+
+static int do_qbops(struct cmd_tbl *cmdtp, int flag, int argc,
+		    char *const argv[])
+{
+	struct cmd_tbl *cp;
+
+	cp = find_cmd_tbl(argv[1], cmd_qb, ARRAY_SIZE(cmd_qb));
+
+	/* Drop the qb command */
+	argc--;
+	argv++;
+
+	if (!cp) {
+		printf("qb: %s: command not found\n", argv[0] ? argv[0] : " ");
+		return CMD_RET_USAGE;
+	}
+
+	if (argc > cp->maxargs) {
+		printf("qb %s: too many arguments: %d > %d\n", cp->name,
+		       argc - 1, cp->maxargs - 1);
+		return CMD_RET_USAGE;
+	}
+
+	if (flag == CMD_FLAG_REPEAT && !cmd_is_repeatable(cp)) {
+		printf("qb %s: repeat flag set but command is not repeatable\n",
+		       cp->name);
+		return CMD_RET_SUCCESS;
+	}
+
+	return cp->cmd(cmdtp, flag, argc, argv);
+}
+
+U_BOOT_CMD(
+	qb, 4, 1, do_qbops,
+	"DDR Quick Boot sub system",
+	"check - check if quick boot data is stored in mem by training flow\n"
+	"qb save [interface] [dev]  - save quick boot data in NVM => trigger quick boot flow\n"
+	"qb erase [interface] [dev] - erase quick boot data from NVM => trigger training flow\n"
+);
diff --git a/arch/arm/mach-imx/imx9/Makefile b/arch/arm/mach-imx/imx9/Makefile
index d2e44f0d5f9..3e323a714c1 100644
--- a/arch/arm/mach-imx/imx9/Makefile
+++ b/arch/arm/mach-imx/imx9/Makefile
@@ -14,4 +14,6 @@ ifneq ($(CONFIG_SPL_BUILD),y)
 obj-y += imx_bootaux.o
 endif
 
-obj-y += qb.o
+ifneq ($(CONFIG_XPL_BUILD),y)
+obj-$(CONFIG_CMD_IMX_QB) += qb.o
+endif
-- 
2.43.0


^ permalink raw reply related	[flat|nested] 17+ messages in thread

* [PATCH v3 3/6] configs: imx9{43, 5}: Enable SPI SFDP support
  2026-04-02  9:40 [PATCH v3 0/6] imx9{4,5,52}: Add Quickboot support Simona Toaca (OSS)
  2026-04-02  9:40 ` [PATCH v3 1/6] imx9: Add support for saving DDR training data to NVM Simona Toaca (OSS)
  2026-04-02  9:40 ` [PATCH v3 2/6] arm: mach-imx: Add command to expose QB functionality Simona Toaca (OSS)
@ 2026-04-02  9:40 ` Simona Toaca (OSS)
  2026-04-03 23:18   ` Marek Vasut
  2026-04-02  9:40 ` [PATCH v3 4/6] board: nxp: imx9{4, 5, 52}_evk: Add qb save option in SPL Simona Toaca (OSS)
                   ` (2 subsequent siblings)
  5 siblings, 1 reply; 17+ messages in thread
From: Simona Toaca (OSS) @ 2026-04-02  9:40 UTC (permalink / raw)
  To: uboot-imx, u-boot
  Cc: Stefano Babic, festevam, peng.fan, alice.guo, viorel.suman,
	simona.toaca, ye.li, ping.bai, marex, sebastien.szymanski, ravi,
	joao.goncalves, ji.luo, semen.protsenko, tharvey, qijian.guo

From: Simona Toaca <simona.toaca@nxp.com>

In the context of saving Quickboot data to SPI
NOR, this option needs to be enabled so that the
erase size is parsed correctly.

Signed-off-by: Simona Toaca <simona.toaca@nxp.com>
---
 configs/imx943_evk_defconfig      | 1 +
 configs/imx95_15x15_evk_defconfig | 1 +
 configs/imx95_evk.config          | 1 +
 3 files changed, 3 insertions(+)

diff --git a/configs/imx943_evk_defconfig b/configs/imx943_evk_defconfig
index 6acb49e47e2..624ee9b73d1 100644
--- a/configs/imx943_evk_defconfig
+++ b/configs/imx943_evk_defconfig
@@ -109,6 +109,7 @@ CONFIG_SUPPORT_EMMC_BOOT=y
 CONFIG_FSL_USDHC=y
 CONFIG_MTD=y
 CONFIG_DM_SPI_FLASH=y
+CONFIG_SPI_FLASH_SFDP_SUPPORT=y
 CONFIG_SPI_FLASH_SOFT_RESET=y
 CONFIG_SPI_FLASH_SOFT_RESET_ON_BOOT=y
 CONFIG_SPI_FLASH_STMICRO=y
diff --git a/configs/imx95_15x15_evk_defconfig b/configs/imx95_15x15_evk_defconfig
index 38a855417d0..97eebe83639 100644
--- a/configs/imx95_15x15_evk_defconfig
+++ b/configs/imx95_15x15_evk_defconfig
@@ -120,6 +120,7 @@ CONFIG_MMC_HS400_SUPPORT=y
 CONFIG_FSL_USDHC=y
 CONFIG_MTD=y
 CONFIG_DM_SPI_FLASH=y
+CONFIG_SPI_FLASH_SFDP_SUPPORT=y
 CONFIG_SPI_FLASH_STMICRO=y
 CONFIG_PHYLIB=y
 CONFIG_PHY_AQUANTIA=y
diff --git a/configs/imx95_evk.config b/configs/imx95_evk.config
index 3db583cce59..0388d999cfa 100644
--- a/configs/imx95_evk.config
+++ b/configs/imx95_evk.config
@@ -121,6 +121,7 @@ CONFIG_MMC_HS400_SUPPORT=y
 CONFIG_FSL_USDHC=y
 CONFIG_MTD=y
 CONFIG_DM_SPI_FLASH=y
+CONFIG_SPI_FLASH_SFDP_SUPPORT=y
 CONFIG_SPI_FLASH_STMICRO=y
 CONFIG_SPI_FLASH_MT35XU=y
 CONFIG_PHYLIB=y
-- 
2.43.0


^ permalink raw reply related	[flat|nested] 17+ messages in thread

* [PATCH v3 4/6] board: nxp: imx9{4, 5, 52}_evk: Add qb save option in SPL
  2026-04-02  9:40 [PATCH v3 0/6] imx9{4,5,52}: Add Quickboot support Simona Toaca (OSS)
                   ` (2 preceding siblings ...)
  2026-04-02  9:40 ` [PATCH v3 3/6] configs: imx9{43, 5}: Enable SPI SFDP support Simona Toaca (OSS)
@ 2026-04-02  9:40 ` Simona Toaca (OSS)
  2026-04-03 23:23   ` [PATCH v3 4/6] board: nxp: imx9{4,5,52}_evk: " Marek Vasut
  2026-04-02  9:40 ` [PATCH v3 5/6] doc: board: nxp: Add Quickboot documentation Simona Toaca (OSS)
  2026-04-02  9:40 ` [PATCH v3 6/6] drivers: ddr: imx: Fix Kconfig for SAVED_DRAM_TIMING_BASE Simona Toaca (OSS)
  5 siblings, 1 reply; 17+ messages in thread
From: Simona Toaca (OSS) @ 2026-04-02  9:40 UTC (permalink / raw)
  To: uboot-imx, u-boot
  Cc: Stefano Babic, festevam, peng.fan, alice.guo, viorel.suman,
	simona.toaca, ye.li, ping.bai, marex, sebastien.szymanski, ravi,
	joao.goncalves, ji.luo, semen.protsenko, tharvey, qijian.guo

From: Simona Toaca <simona.toaca@nxp.com>

Call qb save automatically in the board-specific
spl_board_init(), if SPL_IMX_QB option is enabled.
This makes sure qb_save is called before any image
loading is done by the SPL. This option is also
suitable for the case where U-Boot proper is
missing (Falcon mode).

qb save refers to saving DDR training data to NVM,
so that OEI runs Quickboot flow on next reboot,
skipping full training and achieveing a lower boot
time.

Signed-off-by: Simona Toaca <simona.toaca@nxp.com>
---
 arch/arm/mach-imx/Kconfig       | 8 ++++++++
 arch/arm/mach-imx/imx9/Makefile | 4 +++-
 board/nxp/imx94_evk/spl.c       | 6 +++++-
 board/nxp/imx952_evk/spl.c      | 4 ++++
 board/nxp/imx95_evk/spl.c       | 6 +++++-
 5 files changed, 25 insertions(+), 3 deletions(-)

diff --git a/arch/arm/mach-imx/Kconfig b/arch/arm/mach-imx/Kconfig
index 48266cfd6e2..3fb8ebb886c 100644
--- a/arch/arm/mach-imx/Kconfig
+++ b/arch/arm/mach-imx/Kconfig
@@ -71,6 +71,14 @@ config CSF_SIZE
 	  Define the maximum size for Command Sequence File (CSF) binary
 	  this information is used to define the image boot data.
 
+config SPL_IMX_QB
+	bool "Run qb save during SPL"
+	depends on SPL && (IMX94 || IMX95 || IMX952)
+	help
+	  Automatically save DDR training data (Quickboot data)
+	  to current boot device when needed (when OEI runs Training
+	  flow and saves qb data to volatile memory).
+
 config CMD_IMX_QB
 	bool "Support the 'qb' command"
 	default y
diff --git a/arch/arm/mach-imx/imx9/Makefile b/arch/arm/mach-imx/imx9/Makefile
index 3e323a714c1..8b01897b928 100644
--- a/arch/arm/mach-imx/imx9/Makefile
+++ b/arch/arm/mach-imx/imx9/Makefile
@@ -14,6 +14,8 @@ ifneq ($(CONFIG_SPL_BUILD),y)
 obj-y += imx_bootaux.o
 endif
 
-ifneq ($(CONFIG_XPL_BUILD),y)
+ifeq ($(CONFIG_XPL_BUILD),y)
+obj-$(CONFIG_SPL_IMX_QB) += qb.o
+else
 obj-$(CONFIG_CMD_IMX_QB) += qb.o
 endif
diff --git a/board/nxp/imx94_evk/spl.c b/board/nxp/imx94_evk/spl.c
index 6eb0fff99f4..df583c9adf0 100644
--- a/board/nxp/imx94_evk/spl.c
+++ b/board/nxp/imx94_evk/spl.c
@@ -1,6 +1,6 @@
 // SPDX-License-Identifier: GPL-2.0+
 /*
- * Copyright 2025 NXP
+ * Copyright 2025-2026 NXP
  */
 
 #include <hang.h>
@@ -14,6 +14,7 @@
 #include <asm/arch/sys_proto.h>
 #include <asm/mach-imx/boot_mode.h>
 #include <asm/mach-imx/ele_api.h>
+#include <asm/mach-imx/qb.h>
 
 DECLARE_GLOBAL_DATA_PTR;
 
@@ -44,6 +45,9 @@ void spl_board_init(void)
 	ret = ele_start_rng();
 	if (ret)
 		printf("Fail to start RNG: %d\n", ret);
+
+	if (IS_ENABLED(CONFIG_SPL_IMX_QB))
+		spl_qb_save();
 }
 
 static void xspi_nor_reset(void)
diff --git a/board/nxp/imx952_evk/spl.c b/board/nxp/imx952_evk/spl.c
index de9256dc267..d497597625f 100644
--- a/board/nxp/imx952_evk/spl.c
+++ b/board/nxp/imx952_evk/spl.c
@@ -8,6 +8,7 @@
 #include <asm/gpio.h>
 #include <asm/mach-imx/boot_mode.h>
 #include <asm/mach-imx/ele_api.h>
+#include <asm/mach-imx/qb.h>
 #include <asm/sections.h>
 #include <hang.h>
 #include <init.h>
@@ -44,6 +45,9 @@ void spl_board_init(void)
 	ret = ele_start_rng();
 	if (ret)
 		printf("Fail to start RNG: %d\n", ret);
+
+	if (IS_ENABLED(CONFIG_SPL_IMX_QB))
+		spl_qb_save();
 }
 
 static void xspi_nor_reset(void)
diff --git a/board/nxp/imx95_evk/spl.c b/board/nxp/imx95_evk/spl.c
index 761a1a4a0f6..35e4458f2b7 100644
--- a/board/nxp/imx95_evk/spl.c
+++ b/board/nxp/imx95_evk/spl.c
@@ -1,6 +1,6 @@
 // SPDX-License-Identifier: GPL-2.0+
 /*
- * Copyright 2025 NXP
+ * Copyright 2025-2026 NXP
  */
 
 #include <hang.h>
@@ -13,6 +13,7 @@
 #include <asm/arch/sys_proto.h>
 #include <asm/mach-imx/boot_mode.h>
 #include <asm/mach-imx/ele_api.h>
+#include <asm/mach-imx/qb.h>
 
 DECLARE_GLOBAL_DATA_PTR;
 
@@ -41,6 +42,9 @@ void spl_board_init(void)
 	ret = ele_start_rng();
 	if (ret)
 		printf("Fail to start RNG: %d\n", ret);
+
+	if (IS_ENABLED(CONFIG_SPL_IMX_QB))
+		spl_qb_save();
 }
 
 void board_init_f(ulong dummy)
-- 
2.43.0


^ permalink raw reply related	[flat|nested] 17+ messages in thread

* [PATCH v3 5/6] doc: board: nxp: Add Quickboot documentation
  2026-04-02  9:40 [PATCH v3 0/6] imx9{4,5,52}: Add Quickboot support Simona Toaca (OSS)
                   ` (3 preceding siblings ...)
  2026-04-02  9:40 ` [PATCH v3 4/6] board: nxp: imx9{4, 5, 52}_evk: Add qb save option in SPL Simona Toaca (OSS)
@ 2026-04-02  9:40 ` Simona Toaca (OSS)
  2026-04-03 23:27   ` Marek Vasut
  2026-04-04 11:46   ` Fabio Estevam
  2026-04-02  9:40 ` [PATCH v3 6/6] drivers: ddr: imx: Fix Kconfig for SAVED_DRAM_TIMING_BASE Simona Toaca (OSS)
  5 siblings, 2 replies; 17+ messages in thread
From: Simona Toaca (OSS) @ 2026-04-02  9:40 UTC (permalink / raw)
  To: uboot-imx, u-boot
  Cc: Stefano Babic, festevam, peng.fan, alice.guo, viorel.suman,
	simona.toaca, ye.li, ping.bai, marex, sebastien.szymanski, ravi,
	joao.goncalves, ji.luo, semen.protsenko, tharvey, qijian.guo

From: Simona Toaca <simona.toaca@nxp.com>

Add instructions on how to use U-Boot to save
DDR training data to NVM and explain the saving
process.

Signed-off-by: Simona Toaca <simona.toaca@nxp.com>
---
 doc/board/nxp/index.rst |  1 +
 doc/board/nxp/qb.rst    | 54 +++++++++++++++++++++++++++++++++++++++++
 2 files changed, 55 insertions(+)
 create mode 100644 doc/board/nxp/qb.rst

diff --git a/doc/board/nxp/index.rst b/doc/board/nxp/index.rst
index 8cd24aecf33..53ef220d989 100644
--- a/doc/board/nxp/index.rst
+++ b/doc/board/nxp/index.rst
@@ -30,3 +30,4 @@ NXP Semiconductors
    mx6ullevk
    rproc
    psb
+   qb
diff --git a/doc/board/nxp/qb.rst b/doc/board/nxp/qb.rst
new file mode 100644
index 00000000000..07953a1b7e9
--- /dev/null
+++ b/doc/board/nxp/qb.rst
@@ -0,0 +1,54 @@
+.. SPDX-License-Identifier: GPL-2.0+
+   Copyright 2026 NXP
+
+DDR QuickBoot flow
+------------------
+
+Some NXP boards (which use OEI - iMX943, iMX95, iMX952 etc.) support saving
+DDR training data (collected by OEI during Training flow) from volatile
+to non-volatile memory, which is then available to OEI at next cold reboot.
+OEI uses the saved data to run Quickboot flow and avoid training the DDR again.
+This significantly reduces the boot time.
+
+The location of the qb data in NVM is a space left in the bootloader by
+mkimage, with the size of 64K. The qb command searches for this space to
+save the data. Thus, the NVM should also be a boot device.
+
+U-Boot provides no authentication for qb data, only its integrity
+is verified via the CRC32. The authentication is done in OEI. With
+the exception of iMX95 A0/A1, which use CRC32 as well for verifying
+the data, the rest of the boards use ELE to verify the MAC stored
+in the ddrphy_qb_state structure.
+
+If the quickboot data in memory is not valid (CRC32 check fails),
+U-Boot does not save it to NVM. So, if OEI runs Quickboot flow -> no
+data is written to volatile memory -> invalid data -> no saving happens
+(qb save fails during qb check).
+
+After successful saving, U-Boot clears the data in volatile memory so
+that qb check fails at next reboot and the NVM isn't accessed again.
+
+There are 2 ways to save this data, both can be enabled:
+
+1. automatically, in SPL (by enabling CONFIG_SPL_IMX_QB)
+
+- this will save the data on the current boot device (e.g. SD)
+- other configs specific to the boot device need to be enabled (CONFIG_SPL_MMC_WRITE for saving to eMMC/SD)
+- use for: automating qb save / saving qb data if using Falcon mode (skipping U-Boot proper)
+
+2. using qb command in U-Boot console (by enabling CONFIG_CMD_IMX_QB)
+
+- supports saving on the current boot device, or on another, specified device.
+- if flashing via uuu, the command can be added in an uuu script (boot device needs to be specified)
+- use 'qb erase' to force DDR re-training
+- use for: saving qb data during flashing / controlling the NVM to save to / forcing re-training
+
+::
+
+        # To save/erase on current boot device
+        => qb save/erase
+
+        # To save/erase on other boot device
+        => qb save/erase mmc 0 # eMMC
+        => qb save/erase mmc 1 # SD
+        => qb save/erase spi   # NOR SPI
-- 
2.43.0


^ permalink raw reply related	[flat|nested] 17+ messages in thread

* [PATCH v3 6/6] drivers: ddr: imx: Fix Kconfig for SAVED_DRAM_TIMING_BASE
  2026-04-02  9:40 [PATCH v3 0/6] imx9{4,5,52}: Add Quickboot support Simona Toaca (OSS)
                   ` (4 preceding siblings ...)
  2026-04-02  9:40 ` [PATCH v3 5/6] doc: board: nxp: Add Quickboot documentation Simona Toaca (OSS)
@ 2026-04-02  9:40 ` Simona Toaca (OSS)
  2026-04-03 23:24   ` Marek Vasut
  5 siblings, 1 reply; 17+ messages in thread
From: Simona Toaca (OSS) @ 2026-04-02  9:40 UTC (permalink / raw)
  To: uboot-imx, u-boot
  Cc: Stefano Babic, festevam, peng.fan, alice.guo, viorel.suman,
	simona.toaca, ye.li, ping.bai, marex, sebastien.szymanski, ravi,
	joao.goncalves, ji.luo, semen.protsenko, tharvey, qijian.guo

From: Simona Toaca <simona.toaca@nxp.com>

The 'default' directive should be before 'help'.

Signed-off-by: Simona Toaca <simona.toaca@nxp.com>
---
 drivers/ddr/imx/imx9/Kconfig | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/drivers/ddr/imx/imx9/Kconfig b/drivers/ddr/imx/imx9/Kconfig
index de1f59bfaf5..7b3dbf53dff 100644
--- a/drivers/ddr/imx/imx9/Kconfig
+++ b/drivers/ddr/imx/imx9/Kconfig
@@ -24,10 +24,10 @@ config IMX9_DRAM_INLINE_ECC
 
 config SAVED_DRAM_TIMING_BASE
 	hex "Define the base address for saved dram timing"
+	default 0x2051C000
 	help
 	  after DRAM is trained, need to save the dram related timming
 	  info into memory for low power use.
-	default 0x2051C000
 
 config QB_SAVED_STATE_BASE
 	hex "Define the base address for saved QuickBoot state"
-- 
2.43.0


^ permalink raw reply related	[flat|nested] 17+ messages in thread

* Re: [PATCH v3 1/6] imx9: Add support for saving DDR training data to NVM
  2026-04-02  9:40 ` [PATCH v3 1/6] imx9: Add support for saving DDR training data to NVM Simona Toaca (OSS)
@ 2026-04-03 23:00   ` Marek Vasut
  2026-04-05 11:49   ` Simon Glass
  1 sibling, 0 replies; 17+ messages in thread
From: Marek Vasut @ 2026-04-03 23:00 UTC (permalink / raw)
  To: Simona Toaca (OSS), uboot-imx, u-boot
  Cc: Stefano Babic, festevam, peng.fan, alice.guo, viorel.suman,
	simona.toaca, ye.li, ping.bai, sebastien.szymanski, ravi,
	joao.goncalves, ji.luo, semen.protsenko, tharvey, qijian.guo

On 4/2/26 11:40 AM, Simona Toaca (OSS) wrote:
> From: Simona Toaca <simona.toaca@nxp.com>
> 
> DDR training data can be saved to NVM and be available
> to OEI at boot time, which will trigger QuickBoot flow.
> 
> U-Boot only checks for data integrity (CRC32), while
> OEI is in charge of authentication when it tries to
> load the data from NVM.
> 
> On iMX95 A0/A1, 'authentication' is done via another
> CRC32. On the other boards, authentication is done by

On the other ... SoC revisions (not boards) , ... ?

[...]

> +++ b/arch/arm/include/asm/arch-imx9/ddr.h
> @@ -1,6 +1,6 @@
>   /* SPDX-License-Identifier: GPL-2.0+ */
>   /*
> - * Copyright 2022 NXP
> + * Copyright 2022-2026 NXP
>    */
>   
>   #ifndef __ASM_ARCH_IMX8M_DDR_H
> @@ -100,6 +100,52 @@ struct dram_timing_info {
>   
>   extern struct dram_timing_info dram_timing;
>   
> +/* Quick Boot related */
> +#define DDRPHY_QB_CSR_SIZE	5168
> +#define DDRPHY_QB_ACSM_SIZE	(4 * 1024)
> +#define DDRPHY_QB_MSB_SIZE	0x200
> +#define DDRPHY_QB_PSTATES	0
> +#define DDRPHY_QB_PST_SIZE	(DDRPHY_QB_PSTATES * 4 * 1024)
> +
> +/**
> + * This structure needs to be aligned with the one in OEI.
> + */
> +struct ddrphy_qb_state {
> +	u32 crc;		  /* Used for ensuring integrity in DRAM */
> +#define MAC_LENGTH              8 /* 256 bits, 32-bit aligned */

Please indent with tabs.

> +	u32 mac[MAC_LENGTH];	  /* For 95A0/1 use mac[0] to keep CRC32 value */


[...]

> +++ b/arch/arm/include/asm/mach-imx/qb.h
> @@ -0,0 +1,15 @@
> +/* SPDX-License-Identifier: GPL-2.0+ */
> +/*
> + * Copyright 2026 NXP
> + */
> +
> +#ifndef __IMX_QB_H__
> +#define __IMX_QB_H__
> +
> +#include <stdbool.h>
> +
> +bool qb_check(void);
> +int qb(int qb_dev, bool save);
> +void spl_qb_save(void);

Please call the functions something less opaque than "qb()" , imx_qb_*() 
would alrady be so much better.

[...]

> diff --git a/arch/arm/mach-imx/imx9/qb.c b/arch/arm/mach-imx/imx9/qb.c
> new file mode 100644
> index 00000000000..220545192d4
> --- /dev/null
> +++ b/arch/arm/mach-imx/imx9/qb.c
> @@ -0,0 +1,379 @@
> +// SPDX-License-Identifier: GPL-2.0+
> +/**
> + * Copyright 2024-2026 NXP
> + */
> +#include <dm/device-internal.h>
> +#include <dm/uclass.h>
> +#include <errno.h>
> +#include <imx_container.h>
> +#include <linux/bitfield.h>
> +#include <mmc.h>
> +#include <spi_flash.h>
> +#include <spl.h>
> +#include <stdlib.h>
> +#include <u-boot/crc.h>
> +
> +#include <asm/arch/ddr.h>
> +#include <asm/mach-imx/boot_mode.h>
> +#include <asm/mach-imx/sys_proto.h>
> +
> +#define QB_STATE_LOAD_SIZE    SZ_64K
> +
> +#define MMC_DEV		0
> +#define QSPI_DEV	1
> +
> +#define IMG_FLAGS_IMG_TYPE_MASK   0xF
> +#define IMG_FLAGS_IMG_TYPE(x)     FIELD_GET(IMG_FLAGS_IMG_TYPE_MASK, (x))
> +
> +#define IMG_TYPE_DDR_TDATA_DUMMY  0xD   /* dummy DDR training data image */
> +
> +bool qb_check(void)
> +{
> +	struct ddrphy_qb_state *qb_state;
> +	u32 size, crc;
> +
> +	/**
> +	 * Ensure CRC is not empty, the reason is that
> +	 * the data is invalidated after first save run
> +	 * or after it is overwritten.
> +	 */
> +	qb_state = (struct ddrphy_qb_state *)CONFIG_QB_SAVED_STATE_BASE;
> +	size = sizeof(struct ddrphy_qb_state) - sizeof(qb_state->crc);
> +	crc = crc32(0, (u8 *)qb_state->mac, size);
> +
> +	if (!qb_state->crc || crc != qb_state->crc)
> +		return false;
> +
> +	return true;
> +}
> +
> +static unsigned long qb_get_boot_device_offset(void *dev, int dev_type)
> +{
> +	unsigned long offset = 0;
> +	struct mmc *mmc;
> +
> +	switch (dev_type) {
> +	case MMC_DEV:
> +		mmc = dev;
> +
> +		if (IS_SD(mmc) || mmc->part_config == MMCPART_NOAVAILABLE) {
> +			offset = CONTAINER_HDR_MMCSD_OFFSET;

Multiple return in this case will make the function simpler:

return CONTAINER_HDR_MMCSD_OFFSET;

> +		} else {

No need for } else { anymore.

> +			u8 part = EXT_CSD_EXTRACT_BOOT_PART(mmc->part_config);
> +
> +			if (part == EMMC_BOOT_PART_BOOT1 || part == EMMC_BOOT_PART_BOOT2)
> +				offset = CONTAINER_HDR_EMMC_OFFSET;

return CONTAINER_HDR_EMMC_OFFSET;

> +			else
> +				offset = CONTAINER_HDR_MMCSD_OFFSET;

return CONTAINER_HDR_MMCSD_OFFSET;

> +		}
> +		break;
> +	case QSPI_DEV:
> +		offset = CONTAINER_HDR_QSPI_OFFSET;
> +		break;
> +	default:
> +		return -EOPNOTSUPP;
> +	}
> +
> +	return offset;
> +}

[...]

> +static int get_dev_qbdata_offset(void *dev, int dev_type, unsigned long offset,
> +				 u32 *qbdata_offset)
> +{
> +	int ret = -EOPNOTSUPP;
> +	u16 ctnr_hdr_align = CONTAINER_HDR_ALIGNMENT;
> +	void *buf = kmalloc(ctnr_hdr_align, GFP_KERNEL);

Can you use buffer on stack ? u8 buf[CONTAINER_HDR_ALIGNMENT]; ? That 
would allow you to remove all the goto statements.

If not, use malloc() not kmalloc().

> +	if (!buf) {
> +		printf("kmalloc buffer failed\n");

if malloc fails, so will printing, so drop this print and return -ENOMEM 
only.

> +		return -ENOMEM;
> +	}
> +
> +	switch (dev_type) {
> +	case MMC_DEV:
> +		unsigned long count = 0;
> +		struct mmc *mmc = dev;
> +
> +		if (!(CONFIG_IS_ENABLED(DM_MMC) && CONFIG_IS_ENABLED(MMC_WRITE)))
> +			goto get_dev_qbdata_offset_exit;
> +
> +		count = blk_dread(mmc_get_blk_desc(mmc),
> +				  offset / mmc->read_bl_len,
> +				  ctnr_hdr_align / mmc->read_bl_len,
> +				  buf);
> +		if (count == 0) {
> +			printf("Read container image from MMC/SD failed\n");
> +			ret = -EIO;
> +			goto get_dev_qbdata_offset_exit;
> +		}
> +		break;
> +	case QSPI_DEV:
> +		if (!CONFIG_IS_ENABLED(SPI))
> +			goto get_dev_qbdata_offset_exit;
> +
> +		ret = spi_flash_read(dev, offset,
> +				     ctnr_hdr_align, buf);
> +		if (ret) {
> +			printf("Read container header from QSPI failed\n");
> +			ret = -EIO;
> +			goto get_dev_qbdata_offset_exit;
> +		}
> +		break;
> +	default:
> +		printf("Support for device %d not enabled\n", dev_type);
> +		goto get_dev_qbdata_offset_exit;
> +	}
> +
> +	ret = qb_parse_container(buf, qbdata_offset);
> +
> +get_dev_qbdata_offset_exit:
> +	free(buf);
> +
> +	return ret;
> +}

[...]

> +void spl_qb_save(void)
> +{
> +	int dev = spl_boot_device();
> +
> +	/* Save QB data on current boot device */
> +	if (qb(dev, true))

Please call this function something less opaque than "qb()" , pick 
something more descriptive.

> +		printf("QB save failed\n");
> +}
[...]

^ permalink raw reply	[flat|nested] 17+ messages in thread

* Re: [PATCH v3 2/6] arm: mach-imx: Add command to expose QB functionality
  2026-04-02  9:40 ` [PATCH v3 2/6] arm: mach-imx: Add command to expose QB functionality Simona Toaca (OSS)
@ 2026-04-03 23:16   ` Marek Vasut
  0 siblings, 0 replies; 17+ messages in thread
From: Marek Vasut @ 2026-04-03 23:16 UTC (permalink / raw)
  To: Simona Toaca (OSS), uboot-imx, u-boot
  Cc: Stefano Babic, festevam, peng.fan, alice.guo, viorel.suman,
	simona.toaca, ye.li, ping.bai, sebastien.szymanski, ravi,
	joao.goncalves, ji.luo, semen.protsenko, tharvey, qijian.guo

On 4/2/26 11:40 AM, Simona Toaca (OSS) wrote:

[...]

> +static void parse_qb_args(int argc, char * const argv[],
> +			  int *qb_dev, int qb_bootdev)
> +{
> +	long dev = -1;
> +	char *interface = "";
> +
> +	if (argc < 2) {
> +		/* qb save -> use boot device */
> +		*qb_dev = qb_bootdev;
> +	} else {
> +		interface = argv[1];
> +	}
> +
> +	if (argc == 3)
> +		dev = simple_strtol(argv[2], NULL, 10);
> +
> +	if (!strcmp(interface, "mmc") && dev >= 0 &&
> +	    dev <= (BOOT_DEVICE_MMC2_2 - BOOT_DEVICE_MMC1))
> +		*qb_dev = BOOT_DEVICE_MMC1 + dev;
> +	else if (!strcmp(interface, "spi"))
> +		*qb_dev = BOOT_DEVICE_SPI;

if (!strcmp(interface, "spi")) {
   *qb_dev = BOOT_DEVICE_SPI;
} else {
   blk_get_device_by_str(interface, argv[2], ...);
   -> This will handle all block devices and all block device
      names and format strings of those, no need to write yet
      another ad-hoc decoder for those by hand. Then use
      blk_dread()/blk_dwrite() to access block storage.
}

[...]

^ permalink raw reply	[flat|nested] 17+ messages in thread

* Re: [PATCH v3 3/6] configs: imx9{43, 5}: Enable SPI SFDP support
  2026-04-02  9:40 ` [PATCH v3 3/6] configs: imx9{43, 5}: Enable SPI SFDP support Simona Toaca (OSS)
@ 2026-04-03 23:18   ` Marek Vasut
  0 siblings, 0 replies; 17+ messages in thread
From: Marek Vasut @ 2026-04-03 23:18 UTC (permalink / raw)
  To: Simona Toaca (OSS), uboot-imx, u-boot
  Cc: Stefano Babic, festevam, peng.fan, alice.guo, viorel.suman,
	simona.toaca, ye.li, ping.bai, sebastien.szymanski, ravi,
	joao.goncalves, ji.luo, semen.protsenko, tharvey, qijian.guo

On 4/2/26 11:40 AM, Simona Toaca (OSS) wrote:
> From: Simona Toaca <simona.toaca@nxp.com>
> 
> In the context of saving Quickboot data to SPI
> NOR, this option needs to be enabled so that the
> erase size is parsed correctly.
> 
> Signed-off-by: Simona Toaca <simona.toaca@nxp.com>
This really has nothing to do with quickboot, this is a generic fix, so 
please send this separately with updated commit message, so it can go in 
quickly.

^ permalink raw reply	[flat|nested] 17+ messages in thread

* Re: [PATCH v3 4/6] board: nxp: imx9{4,5,52}_evk: Add qb save option in SPL
  2026-04-02  9:40 ` [PATCH v3 4/6] board: nxp: imx9{4, 5, 52}_evk: Add qb save option in SPL Simona Toaca (OSS)
@ 2026-04-03 23:23   ` Marek Vasut
  0 siblings, 0 replies; 17+ messages in thread
From: Marek Vasut @ 2026-04-03 23:23 UTC (permalink / raw)
  To: Simona Toaca (OSS), uboot-imx, u-boot
  Cc: Stefano Babic, festevam, peng.fan, alice.guo, viorel.suman,
	simona.toaca, ye.li, ping.bai, sebastien.szymanski, ravi,
	joao.goncalves, ji.luo, semen.protsenko, tharvey, qijian.guo

On 4/2/26 11:40 AM, Simona Toaca (OSS) wrote:

[...]

> +++ b/arch/arm/mach-imx/Kconfig
> @@ -71,6 +71,14 @@ config CSF_SIZE
>   	  Define the maximum size for Command Sequence File (CSF) binary
>   	  this information is used to define the image boot data.
>   
> +config SPL_IMX_QB
> +	bool "Run qb save during SPL"
> +	depends on SPL && (IMX94 || IMX95 || IMX952)
> +	help
> +	  Automatically save DDR training data (Quickboot data)
> +	  to current boot device when needed (when OEI runs Training
> +	  flow and saves qb data to volatile memory).
> +
>   config CMD_IMX_QB
>   	bool "Support the 'qb' command"
>   	default y
> diff --git a/arch/arm/mach-imx/imx9/Makefile b/arch/arm/mach-imx/imx9/Makefile
> index 3e323a714c1..8b01897b928 100644
> --- a/arch/arm/mach-imx/imx9/Makefile
> +++ b/arch/arm/mach-imx/imx9/Makefile
> @@ -14,6 +14,8 @@ ifneq ($(CONFIG_SPL_BUILD),y)
>   obj-y += imx_bootaux.o
>   endif
>   
> -ifneq ($(CONFIG_XPL_BUILD),y)
> +ifeq ($(CONFIG_XPL_BUILD),y)
> +obj-$(CONFIG_SPL_IMX_QB) += qb.o
> +else
>   obj-$(CONFIG_CMD_IMX_QB) += qb.o
>   endif

The qb.o should not be gated beyond CONFIG_CMD_IMX_QB , the 
CONFIG_CMD_IMX_QB is used to gate cmd_qb.o . Fix this and introduce 
CONFIG_IMX_QB to gate the core code, then do this to simplify the 
conditional:

obj-$(CONFIG_$(PHASE_)IMX_QB += qb.o

...

Also, changes to arch/ should be part of 1/6 .

^ permalink raw reply	[flat|nested] 17+ messages in thread

* Re: [PATCH v3 6/6] drivers: ddr: imx: Fix Kconfig for SAVED_DRAM_TIMING_BASE
  2026-04-02  9:40 ` [PATCH v3 6/6] drivers: ddr: imx: Fix Kconfig for SAVED_DRAM_TIMING_BASE Simona Toaca (OSS)
@ 2026-04-03 23:24   ` Marek Vasut
  0 siblings, 0 replies; 17+ messages in thread
From: Marek Vasut @ 2026-04-03 23:24 UTC (permalink / raw)
  To: Simona Toaca (OSS), uboot-imx, u-boot
  Cc: Stefano Babic, festevam, peng.fan, alice.guo, viorel.suman,
	simona.toaca, ye.li, ping.bai, sebastien.szymanski, ravi,
	joao.goncalves, ji.luo, semen.protsenko, tharvey, qijian.guo

On 4/2/26 11:40 AM, Simona Toaca (OSS) wrote:
> From: Simona Toaca <simona.toaca@nxp.com>
> 
> The 'default' directive should be before 'help'.
> 
> Signed-off-by: Simona Toaca <simona.toaca@nxp.com>
Please send this fix separately, so this can go in quickly. Thanks

^ permalink raw reply	[flat|nested] 17+ messages in thread

* Re: [PATCH v3 5/6] doc: board: nxp: Add Quickboot documentation
  2026-04-02  9:40 ` [PATCH v3 5/6] doc: board: nxp: Add Quickboot documentation Simona Toaca (OSS)
@ 2026-04-03 23:27   ` Marek Vasut
  2026-04-04 11:46   ` Fabio Estevam
  1 sibling, 0 replies; 17+ messages in thread
From: Marek Vasut @ 2026-04-03 23:27 UTC (permalink / raw)
  To: Simona Toaca (OSS), uboot-imx, u-boot
  Cc: Stefano Babic, festevam, peng.fan, alice.guo, viorel.suman,
	simona.toaca, ye.li, ping.bai, sebastien.szymanski, ravi,
	joao.goncalves, ji.luo, semen.protsenko, tharvey, qijian.guo

On 4/2/26 11:40 AM, Simona Toaca (OSS) wrote:

[...]

> +DDR QuickBoot flow
> +------------------
> +
> +Some NXP boards (which use OEI - iMX943, iMX95, iMX952 etc.) support saving

boards or SoCs ? I think SoCs ?

> +DDR training data (collected by OEI during Training flow) from volatile
> +to non-volatile memory, which is then available to OEI at next cold reboot.
> +OEI uses the saved data to run Quickboot flow and avoid training the DDR again.
> +This significantly reduces the boot time.
> +
> +The location of the qb data in NVM is a space left in the bootloader by
> +mkimage, with the size of 64K. The qb command searches for this space to
> +save the data. Thus, the NVM should also be a boot device.
> +
> +U-Boot provides no authentication for qb data, only its integrity
> +is verified via the CRC32. The authentication is done in OEI. With
> +the exception of iMX95 A0/A1, which use CRC32 as well for verifying
> +the data, the rest of the boards use ELE to verify the MAC stored

SoCs or SoC revisions ?

[...]

> +2. using qb command in U-Boot console (by enabling CONFIG_CMD_IMX_QB)
> +
> +- supports saving on the current boot device, or on another, specified device.
> +- if flashing via uuu, the command can be added in an uuu script (boot device needs to be specified)
> +- use 'qb erase' to force DDR re-training
> +- use for: saving qb data during flashing / controlling the NVM to save to / forcing re-training
> +
> +::
> +
> +        # To save/erase on current boot device
> +        => qb save/erase
> +
> +        # To save/erase on other boot device
> +        => qb save/erase mmc 0 # eMMC
> +        => qb save/erase mmc 1 # SD
> +        => qb save/erase spi   # NOR SPI

It would be good to have a way to instruct QB to save the data into 
backup location.

^ permalink raw reply	[flat|nested] 17+ messages in thread

* Re: [PATCH v3 5/6] doc: board: nxp: Add Quickboot documentation
  2026-04-02  9:40 ` [PATCH v3 5/6] doc: board: nxp: Add Quickboot documentation Simona Toaca (OSS)
  2026-04-03 23:27   ` Marek Vasut
@ 2026-04-04 11:46   ` Fabio Estevam
  1 sibling, 0 replies; 17+ messages in thread
From: Fabio Estevam @ 2026-04-04 11:46 UTC (permalink / raw)
  To: Simona Toaca (OSS)
  Cc: uboot-imx, u-boot, Stefano Babic, peng.fan, alice.guo,
	viorel.suman, simona.toaca, ye.li, ping.bai, marex,
	sebastien.szymanski, ravi, joao.goncalves, ji.luo,
	semen.protsenko, tharvey, qijian.guo

On Thu, Apr 2, 2026 at 6:29 AM Simona Toaca (OSS)
<simona.toaca@oss.nxp.com> wrote:

> diff --git a/doc/board/nxp/index.rst b/doc/board/nxp/index.rst
> index 8cd24aecf33..53ef220d989 100644
> --- a/doc/board/nxp/index.rst
> +++ b/doc/board/nxp/index.rst
> @@ -30,3 +30,4 @@ NXP Semiconductors
>     mx6ullevk
>     rproc
>     psb
> +   qb

'qb' is too cryptic. Please spell it as 'Quickboot'

> diff --git a/doc/board/nxp/qb.rst b/doc/board/nxp/qb.rst

Same here: quickboot.rst

> new file mode 100644
> index 00000000000..07953a1b7e9
> --- /dev/null
> +++ b/doc/board/nxp/qb.rst
> @@ -0,0 +1,54 @@
> +.. SPDX-License-Identifier: GPL-2.0+
> +   Copyright 2026 NXP
> +
> +DDR QuickBoot flow
> +------------------
> +
> +Some NXP boards (which use OEI - iMX943, iMX95, iMX952 etc.) support saving

s/boards/SoCs

> +DDR training data (collected by OEI during Training flow) from volatile
> +to non-volatile memory, which is then available to OEI at next cold reboot.
> +OEI uses the saved data to run Quickboot flow and avoid training the DDR again.
> +This significantly reduces the boot time.
> +
> +The location of the qb data in NVM is a space left in the bootloader by

Please use 'Quickboot' for consistency and clarity throughout this document.

^ permalink raw reply	[flat|nested] 17+ messages in thread

* Re: [PATCH v3 1/6] imx9: Add support for saving DDR training data to NVM
  2026-04-02  9:40 ` [PATCH v3 1/6] imx9: Add support for saving DDR training data to NVM Simona Toaca (OSS)
  2026-04-03 23:00   ` Marek Vasut
@ 2026-04-05 11:49   ` Simon Glass
  2026-04-06  8:39     ` Simona Toaca
  1 sibling, 1 reply; 17+ messages in thread
From: Simon Glass @ 2026-04-05 11:49 UTC (permalink / raw)
  To: Simona Toaca (OSS)
  Cc: uboot-imx, u-boot, Stefano Babic, festevam, peng.fan, alice.guo,
	viorel.suman, simona.toaca, ye.li, ping.bai, marex,
	sebastien.szymanski, ravi, joao.goncalves, ji.luo,
	semen.protsenko, tharvey, qijian.guo

Hi,

On Thu, 2 Apr 2026 at 03:29, Simona Toaca (OSS)
<simona.toaca@oss.nxp.com> wrote:
>
> From: Simona Toaca <simona.toaca@nxp.com>
>
> DDR training data can be saved to NVM and be available
> to OEI at boot time, which will trigger QuickBoot flow.
>
> U-Boot only checks for data integrity (CRC32), while
> OEI is in charge of authentication when it tries to
> load the data from NVM.
>
> On iMX95 A0/A1, 'authentication' is done via another
> CRC32. On the other boards, authentication is done by
> using ELE to check the MAC stored in the ddrphy_qb_state
> structure.
>
> Supported platforms: iMX94, iMX95, iMX952 (using OEI)
> Supported storage types: eMMC, SD, SPI flash.
>
> Signed-off-by: Viorel Suman <viorel.suman@nxp.com>
> Signed-off-by: Ye Li <ye.li@nxp.com>
> Signed-off-by: Simona Toaca <simona.toaca@nxp.com>
> ---
>  arch/arm/include/asm/arch-imx9/ddr.h |  48 +++-
>  arch/arm/include/asm/mach-imx/qb.h   |  15 ++
>  arch/arm/mach-imx/imx9/Makefile      |   6 +-
>  arch/arm/mach-imx/imx9/qb.c          | 379 +++++++++++++++++++++++++++
>  arch/arm/mach-imx/imx9/scmi/soc.c    |   7 +
>  drivers/ddr/imx/imx9/Kconfig         |   7 +
>  6 files changed, 459 insertions(+), 3 deletions(-)
>  create mode 100644 arch/arm/include/asm/mach-imx/qb.h
>  create mode 100644 arch/arm/mach-imx/imx9/qb.c

Note that this feature is present on x86 boards already.

I wonder if we could make this more generic? E.g. it could be a
function of UCLASS_RAM ? I could do the x86 part to try it out if you
like.

Regards,
Simon

^ permalink raw reply	[flat|nested] 17+ messages in thread

* Re: [PATCH v3 1/6] imx9: Add support for saving DDR training data to NVM
  2026-04-05 11:49   ` Simon Glass
@ 2026-04-06  8:39     ` Simona Toaca
  2026-04-07 18:13       ` Simon Glass
  0 siblings, 1 reply; 17+ messages in thread
From: Simona Toaca @ 2026-04-06  8:39 UTC (permalink / raw)
  To: Simon Glass
  Cc: uboot-imx, u-boot, Stefano Babic, festevam, peng.fan, alice.guo,
	viorel.suman, simona.toaca, ye.li, ping.bai, marex,
	sebastien.szymanski, ravi, joao.goncalves, ji.luo,
	semen.protsenko, tharvey, qijian.guo

Hi Simon,

On Sun, Apr 05, 2026 at 05:49:56AM -0600, Simon Glass wrote:
> Hi,
> 
> On Thu, 2 Apr 2026 at 03:29, Simona Toaca (OSS)
> <simona.toaca@oss.nxp.com> wrote:
> >
> > From: Simona Toaca <simona.toaca@nxp.com>
> >
> > DDR training data can be saved to NVM and be available
> > to OEI at boot time, which will trigger QuickBoot flow.
> >
> > U-Boot only checks for data integrity (CRC32), while
> > OEI is in charge of authentication when it tries to
> > load the data from NVM.
> >
> > On iMX95 A0/A1, 'authentication' is done via another
> > CRC32. On the other boards, authentication is done by
> > using ELE to check the MAC stored in the ddrphy_qb_state
> > structure.
> >
> > Supported platforms: iMX94, iMX95, iMX952 (using OEI)
> > Supported storage types: eMMC, SD, SPI flash.
> >
> > Signed-off-by: Viorel Suman <viorel.suman@nxp.com>
> > Signed-off-by: Ye Li <ye.li@nxp.com>
> > Signed-off-by: Simona Toaca <simona.toaca@nxp.com>
> > ---
> >  arch/arm/include/asm/arch-imx9/ddr.h |  48 +++-
> >  arch/arm/include/asm/mach-imx/qb.h   |  15 ++
> >  arch/arm/mach-imx/imx9/Makefile      |   6 +-
> >  arch/arm/mach-imx/imx9/qb.c          | 379 +++++++++++++++++++++++++++
> >  arch/arm/mach-imx/imx9/scmi/soc.c    |   7 +
> >  drivers/ddr/imx/imx9/Kconfig         |   7 +
> >  6 files changed, 459 insertions(+), 3 deletions(-)
> >  create mode 100644 arch/arm/include/asm/mach-imx/qb.h
> >  create mode 100644 arch/arm/mach-imx/imx9/qb.c
> 
> Note that this feature is present on x86 boards already.
> 
> I wonder if we could make this more generic? E.g. it could be a
> function of UCLASS_RAM ? I could do the x86 part to try it out if you
> like.
> 

Can you please point me to the implementation for x86? This Quickboot
feature is specific to Synopsis DDR PHYs, and the location where we
save this data is specific to iMX9 series (since it is needed by OEI).
I need a bit more details about what you mean.

Thank you,
Simona

^ permalink raw reply	[flat|nested] 17+ messages in thread

* Re: [PATCH v3 1/6] imx9: Add support for saving DDR training data to NVM
  2026-04-06  8:39     ` Simona Toaca
@ 2026-04-07 18:13       ` Simon Glass
  0 siblings, 0 replies; 17+ messages in thread
From: Simon Glass @ 2026-04-07 18:13 UTC (permalink / raw)
  To: Simona Toaca
  Cc: uboot-imx, u-boot, Stefano Babic, festevam, peng.fan, alice.guo,
	viorel.suman, simona.toaca, ye.li, ping.bai, marex,
	sebastien.szymanski, ravi, joao.goncalves, ji.luo,
	semen.protsenko, tharvey, qijian.guo

Hi Simona,

On Mon, 6 Apr 2026 at 02:28, Simona Toaca <simona.toaca@oss.nxp.com> wrote:
>
> Hi Simon,
>
> On Sun, Apr 05, 2026 at 05:49:56AM -0600, Simon Glass wrote:
> > Hi,
> >
> > On Thu, 2 Apr 2026 at 03:29, Simona Toaca (OSS)
> > <simona.toaca@oss.nxp.com> wrote:
> > >
> > > From: Simona Toaca <simona.toaca@nxp.com>
> > >
> > > DDR training data can be saved to NVM and be available
> > > to OEI at boot time, which will trigger QuickBoot flow.
> > >
> > > U-Boot only checks for data integrity (CRC32), while
> > > OEI is in charge of authentication when it tries to
> > > load the data from NVM.
> > >
> > > On iMX95 A0/A1, 'authentication' is done via another
> > > CRC32. On the other boards, authentication is done by
> > > using ELE to check the MAC stored in the ddrphy_qb_state
> > > structure.
> > >
> > > Supported platforms: iMX94, iMX95, iMX952 (using OEI)
> > > Supported storage types: eMMC, SD, SPI flash.
> > >
> > > Signed-off-by: Viorel Suman <viorel.suman@nxp.com>
> > > Signed-off-by: Ye Li <ye.li@nxp.com>
> > > Signed-off-by: Simona Toaca <simona.toaca@nxp.com>
> > > ---
> > >  arch/arm/include/asm/arch-imx9/ddr.h |  48 +++-
> > >  arch/arm/include/asm/mach-imx/qb.h   |  15 ++
> > >  arch/arm/mach-imx/imx9/Makefile      |   6 +-
> > >  arch/arm/mach-imx/imx9/qb.c          | 379 +++++++++++++++++++++++++++
> > >  arch/arm/mach-imx/imx9/scmi/soc.c    |   7 +
> > >  drivers/ddr/imx/imx9/Kconfig         |   7 +
> > >  6 files changed, 459 insertions(+), 3 deletions(-)
> > >  create mode 100644 arch/arm/include/asm/mach-imx/qb.h
> > >  create mode 100644 arch/arm/mach-imx/imx9/qb.c
> >
> > Note that this feature is present on x86 boards already.
> >
> > I wonder if we could make this more generic? E.g. it could be a
> > function of UCLASS_RAM ? I could do the x86 part to try it out if you
> > like.
> >
>
> Can you please point me to the implementation for x86? This Quickboot
> feature is specific to Synopsis DDR PHYs, and the location where we
> save this data is specific to iMX9 series (since it is needed by OEI).
> I need a bit more details about what you mean.

Yes, if you look at mrccache_save() you will see how this works. It is
controlled by a flash layout within the SPI-flash node:

 spi: spi {
    #address-cells = <1>;
    #size-cells = <0>;
    compatible = "intel,ich9-spi";
    spi-flash@0 {
       #address-cells = <1>;
       #size-cells = <1>;
       reg = <0>;
       m25p,fast-read;
       compatible = "winbond,w25q64dw",
          "jedec,spi-nor";
       memory-map = <0xff800000 0x00800000>;
       rw-mrc-cache {
          label = "rw-mrc-cache";
          reg = <0x005e0000 0x00010000>;
       };
    };
 };

Regards,
Simon

^ permalink raw reply	[flat|nested] 17+ messages in thread

end of thread, other threads:[~2026-04-07 18:14 UTC | newest]

Thread overview: 17+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-04-02  9:40 [PATCH v3 0/6] imx9{4,5,52}: Add Quickboot support Simona Toaca (OSS)
2026-04-02  9:40 ` [PATCH v3 1/6] imx9: Add support for saving DDR training data to NVM Simona Toaca (OSS)
2026-04-03 23:00   ` Marek Vasut
2026-04-05 11:49   ` Simon Glass
2026-04-06  8:39     ` Simona Toaca
2026-04-07 18:13       ` Simon Glass
2026-04-02  9:40 ` [PATCH v3 2/6] arm: mach-imx: Add command to expose QB functionality Simona Toaca (OSS)
2026-04-03 23:16   ` Marek Vasut
2026-04-02  9:40 ` [PATCH v3 3/6] configs: imx9{43, 5}: Enable SPI SFDP support Simona Toaca (OSS)
2026-04-03 23:18   ` Marek Vasut
2026-04-02  9:40 ` [PATCH v3 4/6] board: nxp: imx9{4, 5, 52}_evk: Add qb save option in SPL Simona Toaca (OSS)
2026-04-03 23:23   ` [PATCH v3 4/6] board: nxp: imx9{4,5,52}_evk: " Marek Vasut
2026-04-02  9:40 ` [PATCH v3 5/6] doc: board: nxp: Add Quickboot documentation Simona Toaca (OSS)
2026-04-03 23:27   ` Marek Vasut
2026-04-04 11:46   ` Fabio Estevam
2026-04-02  9:40 ` [PATCH v3 6/6] drivers: ddr: imx: Fix Kconfig for SAVED_DRAM_TIMING_BASE Simona Toaca (OSS)
2026-04-03 23:24   ` Marek Vasut

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox