The i.MX8MQ uses a different PLL type than the later i.MX8M family
members, so the PLL setup did not actually work on this SoC. In U-Boot
the used PLL setup routine is a compile time decision. As we want
our DRAM init code to work for multi-image builds, this passes the
SoC type through to the PLL init, so we can use the correct setup
routine depending on the SoC we are running on.

Signed-off-by: Lucas Stach <d...@lynxeye.de>
---
 drivers/ddr/imx8m/ddr_init.c     |   4 +-
 drivers/ddr/imx8m/ddrphy_train.c |   4 +-
 drivers/ddr/imx8m/ddrphy_utils.c | 107 ++++++++++++++++++++++++++++---
 include/soc/imx8m/ddr.h          |   4 +-
 4 files changed, 104 insertions(+), 15 deletions(-)

diff --git a/drivers/ddr/imx8m/ddr_init.c b/drivers/ddr/imx8m/ddr_init.c
index 1cd7b7406dc7..34da44af6446 100644
--- a/drivers/ddr/imx8m/ddr_init.c
+++ b/drivers/ddr/imx8m/ddr_init.c
@@ -62,7 +62,7 @@ static int imx8m_ddr_init(struct dram_timing_info 
*dram_timing,
 
        initial_drate = dram_timing->fsp_msg[0].drate;
        /* default to the frequency point 0 clock */
-       ddrphy_init_set_dfi_clk(initial_drate);
+       ddrphy_init_set_dfi_clk(initial_drate, type);
 
        /* D-aasert the presetn */
        reg32_write(src_ddrc_rcr, 0x8F000006);
@@ -115,7 +115,7 @@ static int imx8m_ddr_init(struct dram_timing_info 
*dram_timing,
         */
        pr_debug("ddrphy config start\n");
 
-       ret = ddr_cfg_phy(dram_timing);
+       ret = ddr_cfg_phy(dram_timing, type);
        if (ret)
                return ret;
 
diff --git a/drivers/ddr/imx8m/ddrphy_train.c b/drivers/ddr/imx8m/ddrphy_train.c
index 9280c853aa1c..a4677f903c6b 100644
--- a/drivers/ddr/imx8m/ddrphy_train.c
+++ b/drivers/ddr/imx8m/ddrphy_train.c
@@ -31,7 +31,7 @@ void ddr_load_train_code(enum fw_type type)
                               DDRC_PHY_DMEM, dmem, dsize);
 }
 
-int ddr_cfg_phy(struct dram_timing_info *dram_timing)
+int ddr_cfg_phy(struct dram_timing_info *dram_timing, enum ddrc_type type)
 {
        struct dram_cfg_param *dram_cfg;
        struct dram_fsp_msg *fsp_msg;
@@ -54,7 +54,7 @@ int ddr_cfg_phy(struct dram_timing_info *dram_timing)
        for (i = 0; i < dram_timing->fsp_msg_num; i++) {
                pr_debug("DRAM PHY training for %dMTS\n", fsp_msg->drate);
                /* set dram PHY input clocks to desired frequency */
-               ddrphy_init_set_dfi_clk(fsp_msg->drate);
+               ddrphy_init_set_dfi_clk(fsp_msg->drate, type);
 
                /* load the dram training firmware image */
                dwc_ddrphy_apb_wr(0xd0000, 0x0);
diff --git a/drivers/ddr/imx8m/ddrphy_utils.c b/drivers/ddr/imx8m/ddrphy_utils.c
index c48372491015..9a4e1a22ee5e 100644
--- a/drivers/ddr/imx8m/ddrphy_utils.c
+++ b/drivers/ddr/imx8m/ddrphy_utils.c
@@ -214,7 +214,7 @@ static struct imx_int_pll_rate_table *fracpll(u32 freq)
        return NULL;
 }
 
-static int dram_pll_init(u32 freq)
+static int dram_frac_pll_init(u32 freq)
 {
        volatile int i;
        u32 tmp;
@@ -261,35 +261,124 @@ static int dram_pll_init(u32 freq)
        return 0;
 }
 
-void ddrphy_init_set_dfi_clk(unsigned int drate)
+#define SSCG_PLL_LOCK                  BIT(31)
+#define SSCG_PLL_DRAM_PLL_CLKE         BIT(9)
+#define SSCG_PLL_PD                    BIT(7)
+#define SSCG_PLL_BYPASS1               BIT(5)
+#define SSCG_PLL_BYPASS2               BIT(4)
+
+#define SSCG_PLL_REF_DIVR2_MASK                (0x3f << 19)
+#define SSCG_PLL_REF_DIVR2_VAL(n)      (((n) << 19) & SSCG_PLL_REF_DIVR2_MASK)
+#define SSCG_PLL_FEEDBACK_DIV_F1_MASK  (0x3f << 13)
+#define SSCG_PLL_FEEDBACK_DIV_F1_VAL(n)        (((n) << 13) & 
SSCG_PLL_FEEDBACK_DIV_F1_MASK)
+#define SSCG_PLL_FEEDBACK_DIV_F2_MASK  (0x3f << 7)
+#define SSCG_PLL_FEEDBACK_DIV_F2_VAL(n)        (((n) << 7) & 
SSCG_PLL_FEEDBACK_DIV_F2_MASK)
+#define SSCG_PLL_OUTPUT_DIV_VAL_MASK   (0x3f << 1)
+#define SSCG_PLL_OUTPUT_DIV_VAL(n)     (((n) << 1) & 
SSCG_PLL_OUTPUT_DIV_VAL_MASK)
+
+static int dram_sscg_pll_init(u32 freq)
+{
+       u32 val;
+       void __iomem *pll_base = IOMEM(MX8M_ANATOP_BASE_ADDR) + 0x60;
+
+       /* Bypass */
+       setbits_le32(pll_base, SSCG_PLL_BYPASS1 | SSCG_PLL_BYPASS2);
+
+       val = readl(pll_base + 0x8);
+       val &= ~(SSCG_PLL_OUTPUT_DIV_VAL_MASK |
+                SSCG_PLL_FEEDBACK_DIV_F2_MASK |
+                SSCG_PLL_FEEDBACK_DIV_F1_MASK |
+                SSCG_PLL_REF_DIVR2_MASK);
+
+       switch (freq) {
+       case MHZ(800):
+               val |= SSCG_PLL_OUTPUT_DIV_VAL(0);
+               val |= SSCG_PLL_FEEDBACK_DIV_F2_VAL(11);
+               val |= SSCG_PLL_FEEDBACK_DIV_F1_VAL(39);
+               val |= SSCG_PLL_REF_DIVR2_VAL(29);
+               break;
+       case MHZ(600):
+               val |= SSCG_PLL_OUTPUT_DIV_VAL(1);
+               val |= SSCG_PLL_FEEDBACK_DIV_F2_VAL(17);
+               val |= SSCG_PLL_FEEDBACK_DIV_F1_VAL(39);
+               val |= SSCG_PLL_REF_DIVR2_VAL(29);
+               break;
+       case MHZ(400):
+               val |= SSCG_PLL_OUTPUT_DIV_VAL(1);
+               val |= SSCG_PLL_FEEDBACK_DIV_F2_VAL(11);
+               val |= SSCG_PLL_FEEDBACK_DIV_F1_VAL(39);
+               val |= SSCG_PLL_REF_DIVR2_VAL(29);
+               break;
+       case MHZ(167):
+               val |= SSCG_PLL_OUTPUT_DIV_VAL(3);
+               val |= SSCG_PLL_FEEDBACK_DIV_F2_VAL(8);
+               val |= SSCG_PLL_FEEDBACK_DIV_F1_VAL(45);
+               val |= SSCG_PLL_REF_DIVR2_VAL(30);
+               break;
+       default:
+               break;
+       }
+
+       writel(val, pll_base + 0x8);
+
+       /* Clear power down bit */
+       clrbits_le32(pll_base, SSCG_PLL_PD);
+       /* Enable PLL  */
+       setbits_le32(pll_base, SSCG_PLL_DRAM_PLL_CLKE);
+
+       /* Clear bypass */
+       clrbits_le32(pll_base, SSCG_PLL_BYPASS1);
+       udelay(100);
+       clrbits_le32(pll_base, SSCG_PLL_BYPASS2);
+       /* Wait lock */
+       while (!(readl(pll_base) & SSCG_PLL_LOCK))
+               ;
+
+       return 0;
+}
+
+static int dram_pll_init(u32 freq, enum ddrc_type type)
+{
+       switch (type) {
+       case DDRC_TYPE_MQ:
+               return dram_sscg_pll_init(freq);
+       case DDRC_TYPE_MM:
+       case DDRC_TYPE_MP:
+               return dram_frac_pll_init(freq);
+       default:
+               return -ENODEV;
+       }
+}
+
+void ddrphy_init_set_dfi_clk(unsigned int drate, enum ddrc_type type)
 {
        switch (drate) {
        case 4000:
-               dram_pll_init(MHZ(1000));
+               dram_pll_init(MHZ(1000), type);
                dram_disable_bypass();
                break;
        case 3200:
-               dram_pll_init(MHZ(800));
+               dram_pll_init(MHZ(800), type);
                dram_disable_bypass();
                break;
        case 3000:
-               dram_pll_init(MHZ(750));
+               dram_pll_init(MHZ(750), type);
                dram_disable_bypass();
                break;
        case 2400:
-               dram_pll_init(MHZ(600));
+               dram_pll_init(MHZ(600), type);
                dram_disable_bypass();
                break;
        case 1600:
-               dram_pll_init(MHZ(400));
+               dram_pll_init(MHZ(400), type);
                dram_disable_bypass();
                break;
        case 1066:
-               dram_pll_init(MHZ(266));
+               dram_pll_init(MHZ(266),type);
                dram_disable_bypass();
                break;
        case 667:
-               dram_pll_init(MHZ(167));
+               dram_pll_init(MHZ(167), type);
                dram_disable_bypass();
                break;
        case 400:
diff --git a/include/soc/imx8m/ddr.h b/include/soc/imx8m/ddr.h
index a5a610909212..78b15f1d461a 100644
--- a/include/soc/imx8m/ddr.h
+++ b/include/soc/imx8m/ddr.h
@@ -372,14 +372,14 @@ enum ddrc_type {
 int imx8mm_ddr_init(struct dram_timing_info *timing_info);
 int imx8mq_ddr_init(struct dram_timing_info *timing_info);
 int imx8mp_ddr_init(struct dram_timing_info *timing_info);
-int ddr_cfg_phy(struct dram_timing_info *timing_info);
+int ddr_cfg_phy(struct dram_timing_info *timing_info, enum ddrc_type type);
 void load_lpddr4_phy_pie(void);
 void ddrphy_trained_csr_save(struct dram_cfg_param *param, unsigned int num);
 void dram_config_save(struct dram_timing_info *info, unsigned long base);
 
 /* utils function for ddr phy training */
 int wait_ddrphy_training_complete(void);
-void ddrphy_init_set_dfi_clk(unsigned int drate);
+void ddrphy_init_set_dfi_clk(unsigned int drate, enum ddrc_type type);
 void ddrphy_init_read_msg_block(enum fw_type type);
 
 void update_umctl2_rank_space_setting(unsigned int pstat_num,
-- 
2.29.2


_______________________________________________
barebox mailing list
barebox@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/barebox

Reply via email to