[PATCH 4/4] arm: socfpga: iossm: wait for PLL lock from handoff table
Michael Tretter
m.tretter at pengutronix.de
Thu Sep 3 09:12:45 PDT 2026
The PLL setting in the handoff table tells barebox, for which PLL it
needs to wait to be locked before configuring the IOSSM.
While at it, fix the typo in the ECC_INTSTATUS_DERR register.
Signed-off-by: Michael Tretter <m.tretter at pengutronix.de>
---
arch/arm/mach-socfpga/agilex5-sdram.c | 6 ++++
arch/arm/mach-socfpga/iossm_mailbox.c | 58 +++++++++++++++++++++++++----------
arch/arm/mach-socfpga/iossm_mailbox.h | 2 ++
3 files changed, 50 insertions(+), 16 deletions(-)
diff --git a/arch/arm/mach-socfpga/agilex5-sdram.c b/arch/arm/mach-socfpga/agilex5-sdram.c
index 4a28713a3588..e3c6c414b261 100644
--- a/arch/arm/mach-socfpga/agilex5-sdram.c
+++ b/arch/arm/mach-socfpga/agilex5-sdram.c
@@ -107,6 +107,12 @@ static int populate_ddr_handoff(struct altera_sdram_plat *plat, struct io96b_inf
else
io96b_ctrl->num_instance = 1;
+ /* Read PLL from handoff */
+ io96b_ctrl->selected_plls = FIELD_GET(GENMASK(19, 16),
+ handoff_table[PORT_EMIF_CONFIG_OFFSET]);
+ pr_debug("%s: selected PLLs from handoff: 0x%x\n",
+ __func__, io96b_ctrl->selected_plls);
+
/* Assign IO96B CSR base address if it is valid */
for (i = 0; i < io96b_ctrl->num_instance; i++) {
io96b_ctrl->io96b[i].io96b_csr_addr = IOMEM(io96b_csr_reg_addr[i]);
diff --git a/arch/arm/mach-socfpga/iossm_mailbox.c b/arch/arm/mach-socfpga/iossm_mailbox.c
index 28070121ee6b..2822920ebdf0 100644
--- a/arch/arm/mach-socfpga/iossm_mailbox.c
+++ b/arch/arm/mach-socfpga/iossm_mailbox.c
@@ -17,7 +17,7 @@
#include <mach/socfpga/soc64-system-manager.h>
#define ECC_INTSTATUS_SERR 0x9C
-#define ECC_INISTATUS_DERR 0xA0
+#define ECC_INTSTATUS_DERR 0xA0
#define DDR_CSR_CLKGEN_LOCKED_IO96B0_MASK BIT(16)
#define DDR_CSR_CLKGEN_LOCKED_IO96B1_MASK BIT(17)
@@ -47,21 +47,49 @@
#define IOSSM_MEM_INIT_STATUS_INTF0_OFFSET 0x260
#define IOSSM_MEM_INIT_STATUS_INTF1_OFFSET 0x2E0
+#define IO96B0_PLL_A BIT(0)
+#define IO96B0_PLL_B BIT(1)
+#define IO96B1_PLL_A BIT(2)
+#define IO96B1_PLL_B BIT(3)
+
+static const unsigned int plls[] = {
+ IO96B0_PLL_A, IO96B0_PLL_B, IO96B1_PLL_A, IO96B1_PLL_B
+};
+
+#define IO96B_PLL_REG(pll) \
+ (pll & (IO96B0_PLL_A | IO96B1_PLL_A) ? ECC_INTSTATUS_SERR : ECC_INTSTATUS_DERR)
+#define IO96B_PLL_INSTANCE(pll) \
+ (pll & (IO96B0_PLL_A | IO96B0_PLL_B) ? 0 : 1)
+#define IO96B_PLL_LOCATION(pll) \
+ (pll & (IO96B0_PLL_A | IO96B1_PLL_A) ? "A" : "B")
+
/* supported DDR type list */
static const char *ddr_type_list[7] = {
"DDR4", "DDR5", "DDR5_RDIMM", "LPDDR4", "LPDDR5", "QDRIV", "UNKNOWN"
};
-static int is_ddr_csr_clkgen_locked(u32 clkgen_mask)
+static int io96b_pll_locked_poll_timeout(unsigned int pll)
{
- int ret;
+ u32 mask = DDR_CSR_CLKGEN_LOCKED_IO96B_MASK(IO96B_PLL_INSTANCE(pll));
+ void __iomem *reg = IOMEM(SOCFPGA_SYSMGR_ADDRESS) + IO96B_PLL_REG(pll);
u32 tmp;
- ret = readl_poll_timeout(IOMEM(SOCFPGA_SYSMGR_ADDRESS) + ECC_INTSTATUS_SERR,
- tmp, tmp & clkgen_mask, 10 * USEC_PER_SEC);
- if (ret) {
- pr_debug("%s: ddr csr clkgena locked is timeout\n", __func__);
- return ret;
+ pr_debug("poll for locked PLL: instance %d, location %s\n",
+ IO96B_PLL_INSTANCE(pll), IO96B_PLL_LOCATION(pll));
+ return readl_poll_timeout(reg, tmp, tmp & mask, 10 * USEC_PER_SEC);
+}
+
+static int is_ddr_csr_clkgen_locked(unsigned int selected_plls)
+{
+ int ret;
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(plls); i++) {
+ if (!(selected_plls & plls[i]))
+ continue;
+ ret = io96b_pll_locked_poll_timeout(plls[i]);
+ if (ret)
+ return ret;
}
return 0;
@@ -288,17 +316,15 @@ void io96b_init_mem_cal(struct io96b_info *io96b_ctrl)
/* Initialize overall calibration status */
io96b_ctrl->overall_cal_status = false;
+ if (io96b_ctrl->ckgen_lock) {
+ ret = is_ddr_csr_clkgen_locked(io96b_ctrl->selected_plls);
+ if (ret)
+ hang();
+ }
+
/* Check initial calibration status for the assigned IO96B*/
count = 0;
for (i = 0; i < io96b_ctrl->num_instance; i++) {
- if (io96b_ctrl->ckgen_lock) {
- ret = is_ddr_csr_clkgen_locked(DDR_CSR_CLKGEN_LOCKED_IO96B_MASK(i));
- if (ret) {
- pr_err("%s: ckgena_lock iossm IO96B_%d is not locked\n",
- __func__, i);
- hang();
- }
- }
ret = io96b_cal_status(io96b_ctrl->io96b[i].io96b_csr_addr);
if (ret) {
io96b_ctrl->io96b[i].cal_status = false;
diff --git a/arch/arm/mach-socfpga/iossm_mailbox.h b/arch/arm/mach-socfpga/iossm_mailbox.h
index 954bfcdf382e..55c51c2c091c 100644
--- a/arch/arm/mach-socfpga/iossm_mailbox.h
+++ b/arch/arm/mach-socfpga/iossm_mailbox.h
@@ -119,6 +119,7 @@ struct io96b_instance {
* @overall_size: Total DDR memory size
* @io96b[]: IO96B instance specific information
* @ckgen_lock: IO96B GEN PLL lock (false = not locked, true = locked)
+ * @selected_plls: Selected IO96B PLLs
*/
struct io96b_info {
int version;
@@ -130,6 +131,7 @@ struct io96b_info {
phys_size_t overall_size;
struct io96b_instance io96b[MAX_IO96B_SUPPORTED];
bool ckgen_lock;
+ unsigned int selected_plls;
};
int io96b_mb_req(void __iomem *io96b_csr_addr, u32 ip_type, u32 instance_id,
--
2.47.3
More information about the barebox
mailing list