From: Viorel Suman <viorel.su...@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.su...@nxp.com>
Reviewed-by: Tom Zheng <haidong.zh...@nxp.com>
Reviewed-by: Ye Li <ye...@nxp.com>
Tested-by: Florin Pavelescu <florin.pavele...@nxp.com>
Signed-off-by: Peng Fan <peng....@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

Reply via email to