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 <[email protected]>
---
 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


Reply via email to