[PATCH 15/15] ddr: altera: n5x: Replay PIE handoff on DDR retention restore

Chen Huei Lok chen.huei.lok at altera.com
Wed Jul 8 03:12:28 CEST 2026


On the DDR retention restore path the trained PHY results are reloaded
from the calibration backup by cal_data_ocram() in init_phy(), which
leaves the PHY microcontroller stalled. Running update_training_result()
there reads back results from a PHY that was never freshly trained and
fails the DFI handshake, so DRAM init returns -ENODEV.

Instead, bring the PHY microcontroller out of reset/stall and replay the
PHY Init Engine handoff to return the PHY to normal operating mode.

The PIE handoff table shares memory with the memclk hash scratch area
(DDR_HANDOFF_IMG_ADDR + DDR_HANDOFF_IMG_LEN - SZ_512) used by
is_ddrconfig_hash_match(). Snapshot and restore those bytes around the
hash computation so the replayed PIE table is not corrupted.

Signed-off-by: Chen Huei Lok <chen.huei.lok at altera.com>
---
 drivers/ddr/altera/sdram_n5x.c | 48 +++++++++++++++++++++++++++++-----
 1 file changed, 42 insertions(+), 6 deletions(-)

diff --git a/drivers/ddr/altera/sdram_n5x.c b/drivers/ddr/altera/sdram_n5x.c
index bfa08f62ad6..d09cea5d2ac 100644
--- a/drivers/ddr/altera/sdram_n5x.c
+++ b/drivers/ddr/altera/sdram_n5x.c
@@ -1496,6 +1496,9 @@ static bool is_ddrconfig_hash_match(const void *buffer)
 	u8 hash[SHA384_SUM_LEN];
 	u32 memclk_table[4];
 	u32 size = ARRAY_SIZE(memclk_table);
+	u8 *memclk_hash_dst = (u8 *)(DDR_HANDOFF_IMG_ADDR +
+				     DDR_HANDOFF_IMG_LEN - SZ_512);
+	u8 saved_handoff[SHA384_SUM_LEN];
 
 	/* Magic symbol in first 4 bytes of header */
 	struct cal_header_t *header = (struct cal_header_t *)buffer;
@@ -1512,14 +1515,26 @@ static bool is_ddrconfig_hash_match(const void *buffer)
 		return -EFAULT;
 	}
 
+	/*
+	 * The memclk hash is written into the tail of the hashed handoff image
+	 * (DDR_HANDOFF_IMG_ADDR + DDR_HANDOFF_IMG_LEN - SZ_512) so that the
+	 * whole-image hash covers it. That location overlaps the PHY init
+	 * engine handoff table that phy_init_engine() replays on the retention
+	 * restore path, so snapshot the original handoff bytes and restore them
+	 * once the hash has been computed.
+	 */
+	memcpy(saved_handoff, memclk_hash_dst, SHA384_SUM_LEN);
+
 	sha384_csum_wd((u8 *)memclk_table, (4 * sizeof(u32)),
-		       (u8 *)DDR_HANDOFF_IMG_ADDR + DDR_HANDOFF_IMG_LEN - SZ_512,
-		       CHUNKSZ_PER_WD_RESET);
+		       memclk_hash_dst, CHUNKSZ_PER_WD_RESET);
 
 	/* Generate HASH384 from the image */
 	sha384_csum_wd((u8 *)DDR_HANDOFF_IMG_ADDR, DDR_HANDOFF_IMG_LEN,
 		       hash, CHUNKSZ_PER_WD_RESET);
 
+	/* Restore the handoff bytes clobbered by the memclk hash above */
+	memcpy(memclk_hash_dst, saved_handoff, SHA384_SUM_LEN);
+
 	ret = memcmp((void *)hash, (const void *)header->ddrconfig_hash,
 		     SHA384_SUM_LEN);
 	if (ret) {
@@ -2956,10 +2971,31 @@ int sdram_mmr_init_full(struct udevice *dev)
 			}
 
 		} else {
-			/* Updating training result to DDR controller */
-			ret = update_training_result(&ddr_handoff_info);
-			if (ret)
-				return ret;
+			/*
+			 * Retention restore path: the trained results were
+			 * already reloaded into the PHY by cal_data_ocram()
+			 * (LOADING) in init_phy(), so update_training_result()
+			 * must not run here (it would read back results from a
+			 * PHY that was never freshly trained and fail the DFI
+			 * handshake). Bring the PHY microcontroller out of
+			 * reset/stall, then replay the PIE handoff to return the
+			 * PHY to normal operating mode.
+			 */
+			clrbits_le16(ddr_handoff_info.phy_base +
+				     DDR_PHY_APBONLY0_OFFSET,
+				     DDR_PHY_MICROCONTMUXSEL);
+			setbits_le16(ddr_handoff_info.phy_base +
+				     DDR_PHY_MICRORESET_OFFSET,
+				     DDR_PHY_MICRORESET_RESET |
+				     DDR_PHY_MICRORESET_STALL);
+			clrbits_le16(ddr_handoff_info.phy_base +
+				     DDR_PHY_MICRORESET_OFFSET,
+				     DDR_PHY_MICRORESET_RESET);
+			setbits_le16(ddr_handoff_info.phy_base +
+				     DDR_PHY_APBONLY0_OFFSET,
+				     DDR_PHY_MICROCONTMUXSEL);
+
+			phy_init_engine(&ddr_handoff_info);
 		}
 
 		/*
-- 
2.43.7



More information about the U-Boot mailing list