[PATCH 9/9] ddr: imx9: Add errata registers support

Peng Fan (OSS) peng.fan at oss.nxp.com
Mon Jul 28 05:24:55 CEST 2025


From: Viorel Suman <viorel.suman at nxp.com>

Collect errata registers values after the training and restore errata
registers values before starting quick boot firmware.

Signed-off-by: Viorel Suman <viorel.suman at nxp.com>
Reviewed-by: Tom Zheng <haidong.zheng at nxp.com>
Reviewed-by: Ye Li <ye.li at nxp.com>
Tested-by: Florin Pavelescu <florin.pavelescu at nxp.com>
Signed-off-by: Peng Fan <peng.fan at nxp.com>
---
 arch/arm/include/asm/arch-imx9/ddr.h   |  5 ++++-
 drivers/ddr/imx/phy/Makefile           |  4 ++--
 drivers/ddr/imx/phy/ddrphy_qb.c        |  4 ++++
 drivers/ddr/imx/phy/ddrphy_qb_errata.c | 39 ++++++++++++++++++++++++++++++++++
 drivers/ddr/imx/phy/ddrphy_qb_gen.c    |  3 +++
 5 files changed, 52 insertions(+), 3 deletions(-)

diff --git a/arch/arm/include/asm/arch-imx9/ddr.h b/arch/arm/include/asm/arch-imx9/ddr.h
index 6e5a3e3b6793d0171c2fbe6415821968ac1d3ba4..e30274035ca620fbcee46932b33374055aba3378 100644
--- a/arch/arm/include/asm/arch-imx9/ddr.h
+++ b/arch/arm/include/asm/arch-imx9/ddr.h
@@ -103,6 +103,7 @@ extern struct dram_timing_info dram_timing;
 
 #if (defined(CONFIG_IMX_SNPS_DDR_PHY_QB_GEN) || defined(CONFIG_IMX_SNPS_DDR_PHY_QB))
 #define DDRPHY_QB_FSP_SIZE	3
+#define DDRPHY_QB_ERR_SIZE	6
 #define DDRPHY_QB_CSR_SIZE	1792
 #define DDRPHY_QB_FLAG_2D	BIT(0)	/* =1 if First boot used 2D training, =0 otherwise */
 
@@ -110,13 +111,15 @@ struct ddrphy_qb_state {
 	u32 crc;
 	u32 flags;
 	u32 fsp[DDRPHY_QB_FSP_SIZE];
+	u32 err[DDRPHY_QB_ERR_SIZE];
 	u32 csr[DDRPHY_QB_CSR_SIZE];
 };
 
 #define DDRPHY_QB_STATE_SIZE \
-	(sizeof(u32) * (1 + DDRPHY_QB_FSP_SIZE + DDRPHY_QB_CSR_SIZE))
+	(sizeof(u32) * (1 + DDRPHY_QB_FSP_SIZE + DDRPHY_QB_ERR_SIZE + DDRPHY_QB_CSR_SIZE))
 
 extern struct ddrphy_qb_state qb_state;
+extern const u32 ddrphy_err_cfg[DDRPHY_QB_ERR_SIZE];
 
 #if defined(CONFIG_IMX_SNPS_DDR_PHY_QB_GEN)
 int ddrphy_qb_save(void);
diff --git a/drivers/ddr/imx/phy/Makefile b/drivers/ddr/imx/phy/Makefile
index 2310e69ab5c3036a2903465f4c4e95a79bf0b2c5..75c11625e8a23152e81700b747b216338af1406b 100644
--- a/drivers/ddr/imx/phy/Makefile
+++ b/drivers/ddr/imx/phy/Makefile
@@ -6,6 +6,6 @@
 
 ifdef CONFIG_XPL_BUILD
 obj-$(CONFIG_IMX_SNPS_DDR_PHY) += helper.o ddrphy_utils.o ddrphy_train.o
-obj-$(CONFIG_IMX_SNPS_DDR_PHY_QB_GEN) += ddrphy_qb_gen.o
-obj-$(CONFIG_IMX_SNPS_DDR_PHY_QB) += ddrphy_qb.o
+obj-$(CONFIG_IMX_SNPS_DDR_PHY_QB_GEN) += ddrphy_qb_gen.o ddrphy_qb_errata.o
+obj-$(CONFIG_IMX_SNPS_DDR_PHY_QB) += ddrphy_qb.o ddrphy_qb_errata.o
 endif
diff --git a/drivers/ddr/imx/phy/ddrphy_qb.c b/drivers/ddr/imx/phy/ddrphy_qb.c
index 04a6520be5464ac26e30a516265b1b6993eec38c..2bd34bf91fad46e41b3581d79db3523b5442654e 100644
--- a/drivers/ddr/imx/phy/ddrphy_qb.c
+++ b/drivers/ddr/imx/phy/ddrphy_qb.c
@@ -47,6 +47,10 @@ static int ddrphy_qb_restore(struct dram_timing_info *info, int fsp_id)
 		ddrphy_w(0x5403c, 0x78, qb_state.fsp[2] >> 8);   /* TrainedVREFDQ_B1 -> MR14_B1 */
 	}
 
+	/* restore errata registers */
+	for (i = 0; i < DDRPHY_QB_ERR_SIZE; i++)
+		dwc_ddrphy_apb_wr(ddrphy_err_cfg[i], qb_state.err[i]);
+
 	/* save CSRs to address starting with 0x54800 */
 	for (i = 0, to_addr = 0x54800; i < DDRPHY_QB_CSR_SIZE; i++, to_addr++)
 		dwc_ddrphy_apb_wr(to_addr, qb_state.csr[i]);
diff --git a/drivers/ddr/imx/phy/ddrphy_qb_errata.c b/drivers/ddr/imx/phy/ddrphy_qb_errata.c
new file mode 100644
index 0000000000000000000000000000000000000000..91843ab2d939fc973af35ce07a63b1b375463b92
--- /dev/null
+++ b/drivers/ddr/imx/phy/ddrphy_qb_errata.c
@@ -0,0 +1,39 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright 2025 NXP
+ */
+
+#include <asm/arch/ddr.h>
+#include <linux/types.h>
+
+/** Errata CSRs
+ * STAR_3141216	0x020021 -> in ddrphy_csr_cfg
+ * STAR_3256585	0x02000b -> in ddrphy_csr_cfg
+ *		0x12000b -> in ddrphy_csr_cfg
+ *		0x22000b -> in ddrphy_csr_cfg
+ * STAR_3975199	0x0200c7
+ *		0x0200ca
+ *		0x1200c7
+ *		0x1200ca
+ *		0x2200c7
+ *		0x2200ca
+ * STAR_4101789	0x0200c7 -> covered by STAR_3975199
+ *		0x0200c5 -> in ddrphy_csr_cfg
+ *		0x1200c7 -> covered by STAR_3975199
+ *		0x1200c5 -> in ddrphy_csr_cfg
+ *		0x2200c7 -> covered by STAR_3975199
+ *		0x2200c5 -> in ddrphy_csr_cfg
+ */
+
+/**
+ * All from STAR_3975199, the remaining errata registers
+ * are covered by either ddrphy_csr_cfg or STAR_3975199
+ */
+const u32 ddrphy_err_cfg[DDRPHY_QB_ERR_SIZE] = {
+	0x000200c7,
+	0x000200ca,
+	0x001200c7,
+	0x001200ca,
+	0x002200c7,
+	0x002200ca,
+};
diff --git a/drivers/ddr/imx/phy/ddrphy_qb_gen.c b/drivers/ddr/imx/phy/ddrphy_qb_gen.c
index d77bb8480d85770d29e4408c2a723b20377833f0..981bfa88dc59c69905d14ffc6cfad4a92da35843 100644
--- a/drivers/ddr/imx/phy/ddrphy_qb_gen.c
+++ b/drivers/ddr/imx/phy/ddrphy_qb_gen.c
@@ -1819,6 +1819,9 @@ int ddrphy_qb_save(void)
 	/* enable the ddrphy apb */
 	dwc_ddrphy_apb_wr(0xd0000, 0x0);
 
+	for (i = 0; i < DDRPHY_QB_ERR_SIZE; i++)
+		qb_state.err[i] = dwc_ddrphy_apb_rd(ddrphy_err_cfg[i]);
+
 	for (i = 0; i < DDRPHY_QB_CSR_SIZE; i++)
 		qb_state.csr[i] = dwc_ddrphy_apb_rd(ddrphy_csr_cfg[i]);
 

-- 
2.35.3



More information about the U-Boot mailing list