[PATCH v3] ddr: imx: Reload the training firmware for every PHY configuration
Frieder Schrempf <[email protected]>
| Newsgroups | org.u-boot-project.lists.u-boot |
|---|---|
| Message-ID | <[email protected]> |
From: Frieder Schrempf <[email protected]> ddr_load_train_firmware() remembers the type of the last loaded firmware image in a static variable and returns early if the same type is requested again. That is valid within a single ddr_cfg_phy() call, where the 1D image is used for several frequency setpoints in a row, but the state also survives across calls. Boards that probe several DDR configurations call ddr_init() more than once. The power up procedure at the beginning of ddr_init() resets the DDR PHY, which leaves the image in the PHY memory in an undefined state. The second call then skips the loading, starts the PMU on whatever is left of it and the training firmware never reports a result. As the PHY also stops answering on its APB interface at that point, the boot hangs in a register read, which no software timeout can recover from. On some specific Kontron SL i.MX8MM with 1GB or 2GB DDR, where the first init is expected to fail and the second one uses an adjusted configuration, this made the boot hang every few cycles. Move the check into ddr_cfg_phy(), the only caller, so that the loading is still skipped for repeated setpoints of one run, but never across runs. Fixes: b614ddb5d335 ("ddr: imx: Save the FW loading if it hasn't changed") Assisted-by: Claude:claude-opus-5 Signed-off-by: Frieder Schrempf <[email protected]> --- Changes in v3: * Drop patch 2-4 as they need to be sent separately Changes in v2: * Add missing hunk due to rebase gone wrong --- drivers/ddr/imx/phy/ddrphy_train.c | 14 ++++++++++++-- drivers/ddr/imx/phy/helper.c | 7 ------- 2 files changed, 12 insertions(+), 9 deletions(-) diff --git a/drivers/ddr/imx/phy/ddrphy_train.c b/drivers/ddr/imx/phy/ddrphy_train.c index 1a2d071d6f1..63a6ca800a3 100644 --- a/drivers/ddr/imx/phy/ddrphy_train.c +++ b/drivers/ddr/imx/phy/ddrphy_train.c @@ -12,6 +12,7 @@ int ddr_cfg_phy(struct dram_timing_info *dram_timing) { struct dram_cfg_param *dram_cfg; struct dram_fsp_msg *fsp_msg; + int last_fw_type = -1; unsigned int num; int i = 0; int j = 0; @@ -33,9 +34,18 @@ int ddr_cfg_phy(struct dram_timing_info *dram_timing) /* set dram PHY input clocks to desired frequency */ ddrphy_init_set_dfi_clk(fsp_msg->drate); - /* load the dram training firmware image */ + /* + * Load the DRAM training firmware image, unless the same image has + * already been loaded for an earlier frequency setpoint of this run. + * It must be loaded again for every ddr_cfg_phy() call as the caller + * resets the PHY before this, which leaves the image in the PHY memory + * in an undefined state. + */ dwc_ddrphy_apb_wr(0xd0000, 0x0); - ddr_load_train_firmware(fsp_msg->fw_type); + if (fsp_msg->fw_type != last_fw_type) { + ddr_load_train_firmware(fsp_msg->fw_type); + last_fw_type = fsp_msg->fw_type; + } /* load the frequency set point message block parameter */ dram_cfg = fsp_msg->fsp_cfg; diff --git a/drivers/ddr/imx/phy/helper.c b/drivers/ddr/imx/phy/helper.c index 147ec9ab061..3c39c89de19 100644 --- a/drivers/ddr/imx/phy/helper.c +++ b/drivers/ddr/imx/phy/helper.c @@ -50,15 +50,8 @@ void ddr_load_train_firmware(enum fw_type type) unsigned long imem_start = (unsigned long)_end + fw_offset; unsigned long dmem_start; unsigned long imem_len = IMEM_LEN, dmem_len = DMEM_LEN; - static enum fw_type last_type = -1; unsigned long spl_start = 0; - /* If FW doesn't change, we can save the loading. */ - if (last_type == type) - return; - - last_type = type; - #ifdef CONFIG_SPL_OF_CONTROL if (gd->fdt_blob && !fdt_check_header(gd->fdt_blob)) { imem_start = roundup((unsigned long)_end + -- 2.55.0