imx: imx8m: clock refactor dram pll part
authorPeng Fan <peng.fan@nxp.com>
Tue, 20 Nov 2018 10:19:32 +0000 (10:19 +0000)
committerStefano Babic <sbabic@denx.de>
Tue, 1 Jan 2019 13:12:18 +0000 (14:12 +0100)
Refactor dram_pll_init to accept args to configure different pll freq.
Introduce dram_enable_bypass and dram_disable_bypass

Signed-off-by: Peng Fan <peng.fan@nxp.com>
arch/arm/include/asm/arch-imx8m/clock.h
arch/arm/mach-imx/imx8m/clock.c

index 45cfea301851f41fee00b454f2774c1dc629ff56..e7c1670f6b9da281d19e94fe6d1e831a4c50900e 100644 (file)
@@ -10,6 +10,8 @@
 
 #include <linux/bitops.h>
 
+#define MHZ(X) ((X) * 1000000UL)
+
 enum pll_clocks {
        ANATOP_ARM_PLL,
        ANATOP_GPU_PLL,
@@ -631,6 +633,26 @@ enum frac_pll_out_val {
        FRAC_PLL_OUT_1600M,
 };
 
+#define DRAM_BYPASS_ROOT_CONFIG(_rate, _m, _p, _s, _k)                 \
+       {                                                               \
+               .clk            =       (_rate),                        \
+               .alt_root_sel   =       (_m),                           \
+               .alt_pre_div    =       (_p),                           \
+               .apb_root_sel   =       (_s),                           \
+               .apb_pre_div    =       (_k),                           \
+       }
+
+struct dram_bypass_clk_setting {
+       ulong clk;
+       int alt_root_sel;
+       enum root_pre_div alt_pre_div;
+       int apb_root_sel;
+       enum root_pre_div apb_pre_div;
+};
+
+void dram_pll_init(ulong pll_val);
+void dram_enable_bypass(ulong clk_val);
+void dram_disable_bypass(void);
 u32 imx_get_fecclk(void);
 u32 imx_get_uartclk(void);
 int clock_init(void);
index f2cb4e1030531fa6677381660f1c7d223df75ce3..3766d988ba8d7af6506906647ec5034f12fc918a 100644 (file)
@@ -525,41 +525,127 @@ u32 imx_get_fecclk(void)
        return get_root_clk(ENET_AXI_CLK_ROOT);
 }
 
-#ifdef CONFIG_SPL_BUILD
-void dram_pll_init(void)
+static struct dram_bypass_clk_setting imx8mq_dram_bypass_tbl[] = {
+       DRAM_BYPASS_ROOT_CONFIG(MHZ(100), 2, CLK_ROOT_PRE_DIV1, 2,
+                               CLK_ROOT_PRE_DIV2),
+       DRAM_BYPASS_ROOT_CONFIG(MHZ(250), 3, CLK_ROOT_PRE_DIV2, 2,
+                               CLK_ROOT_PRE_DIV2),
+       DRAM_BYPASS_ROOT_CONFIG(MHZ(400), 1, CLK_ROOT_PRE_DIV2, 3,
+                               CLK_ROOT_PRE_DIV2),
+};
+
+void dram_enable_bypass(ulong clk_val)
 {
-       struct src *src = (struct src *)SRC_BASE_ADDR;
-       void __iomem *pll_control_reg = &ana_pll->dram_pll_cfg0;
-       u32 pwdn_mask = 0, pll_clke = 0, bypass1 = 0, bypass2 = 0;
-       u32 val;
-       int ret;
+       int i;
+       struct dram_bypass_clk_setting *config;
 
-       setbits_le32(GPC_BASE_ADDR + 0xEC, BIT(7));
-       setbits_le32(GPC_BASE_ADDR + 0xF8, BIT(5));
+       for (i = 0; i < ARRAY_SIZE(imx8mq_dram_bypass_tbl); i++) {
+               if (clk_val == imx8mq_dram_bypass_tbl[i].clk)
+                       break;
+       }
+
+       if (i == ARRAY_SIZE(imx8mq_dram_bypass_tbl)) {
+               printf("No matched freq table %lu\n", clk_val);
+               return;
+       }
 
-       pwdn_mask = SSCG_PLL_PD_MASK;
-       pll_clke = SSCG_PLL_DRAM_PLL_CLKE_MASK;
-       bypass1 = SSCG_PLL_BYPASS1_MASK;
-       bypass2 = SSCG_PLL_BYPASS2_MASK;
+       config = &imx8mq_dram_bypass_tbl[i];
 
-       /* Enable DDR1 and DDR2 domain */
-       writel(SRC_DDR1_ENABLE_MASK, &src->ddr1_rcr);
-       writel(SRC_DDR1_ENABLE_MASK, &src->ddr2_rcr);
+       clock_set_target_val(DRAM_ALT_CLK_ROOT, CLK_ROOT_ON |
+                            CLK_ROOT_SOURCE_SEL(config->alt_root_sel) |
+                            CLK_ROOT_PRE_DIV(config->alt_pre_div));
+       clock_set_target_val(DRAM_APB_CLK_ROOT, CLK_ROOT_ON |
+                            CLK_ROOT_SOURCE_SEL(config->apb_root_sel) |
+                            CLK_ROOT_PRE_DIV(config->apb_pre_div));
+       clock_set_target_val(DRAM_SEL_CFG, CLK_ROOT_ON |
+                            CLK_ROOT_SOURCE_SEL(1));
+}
+
+void dram_disable_bypass(void)
+{
+       clock_set_target_val(DRAM_SEL_CFG, CLK_ROOT_ON |
+                            CLK_ROOT_SOURCE_SEL(0));
+       clock_set_target_val(DRAM_APB_CLK_ROOT, CLK_ROOT_ON |
+                            CLK_ROOT_SOURCE_SEL(4) |
+                            CLK_ROOT_PRE_DIV(CLK_ROOT_PRE_DIV5));
+}
+
+#ifdef CONFIG_SPL_BUILD
+void dram_pll_init(ulong pll_val)
+{
+       u32 val;
+       void __iomem *pll_control_reg = &ana_pll->dram_pll_cfg0;
+       void __iomem *pll_cfg_reg2 = &ana_pll->dram_pll_cfg2;
+
+       /* Bypass */
+       setbits_le32(pll_control_reg, SSCG_PLL_BYPASS1_MASK);
+       setbits_le32(pll_control_reg, SSCG_PLL_BYPASS2_MASK);
+
+       switch (pll_val) {
+       case MHZ(800):
+               val = readl(pll_cfg_reg2);
+               val &= ~(SSCG_PLL_OUTPUT_DIV_VAL_MASK |
+                        SSCG_PLL_FEEDBACK_DIV_F2_MASK |
+                        SSCG_PLL_FEEDBACK_DIV_F1_MASK |
+                        SSCG_PLL_REF_DIVR2_MASK);
+               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);
+               writel(val, pll_cfg_reg2);
+               break;
+       case MHZ(600):
+               val = readl(pll_cfg_reg2);
+               val &= ~(SSCG_PLL_OUTPUT_DIV_VAL_MASK |
+                        SSCG_PLL_FEEDBACK_DIV_F2_MASK |
+                        SSCG_PLL_FEEDBACK_DIV_F1_MASK |
+                        SSCG_PLL_REF_DIVR2_MASK);
+               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);
+               writel(val, pll_cfg_reg2);
+               break;
+       case MHZ(400):
+               val = readl(pll_cfg_reg2);
+               val &= ~(SSCG_PLL_OUTPUT_DIV_VAL_MASK |
+                        SSCG_PLL_FEEDBACK_DIV_F2_MASK |
+                        SSCG_PLL_FEEDBACK_DIV_F1_MASK |
+                        SSCG_PLL_REF_DIVR2_MASK);
+               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);
+               writel(val, pll_cfg_reg2);
+               break;
+       case MHZ(167):
+               val = readl(pll_cfg_reg2);
+               val &= ~(SSCG_PLL_OUTPUT_DIV_VAL_MASK |
+                        SSCG_PLL_FEEDBACK_DIV_F2_MASK |
+                        SSCG_PLL_FEEDBACK_DIV_F1_MASK |
+                        SSCG_PLL_REF_DIVR2_MASK);
+               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);
+               writel(val, pll_cfg_reg2);
+               break;
+       default:
+               break;
+       }
 
        /* Clear power down bit */
-       clrbits_le32(pll_control_reg, pwdn_mask);
+       clrbits_le32(pll_control_reg, SSCG_PLL_PD_MASK);
        /* Eanble ARM_PLL/SYS_PLL  */
-       setbits_le32(pll_control_reg, pll_clke);
+       setbits_le32(pll_control_reg, SSCG_PLL_DRAM_PLL_CLKE_MASK);
 
        /* Clear bypass */
-       clrbits_le32(pll_control_reg, bypass1);
+       clrbits_le32(pll_control_reg, SSCG_PLL_BYPASS1_MASK);
        __udelay(100);
-       clrbits_le32(pll_control_reg, bypass2);
+       clrbits_le32(pll_control_reg, SSCG_PLL_BYPASS2_MASK);
        /* Wait lock */
-       ret = readl_poll_timeout(pll_control_reg, val,
-                                val & SSCG_PLL_LOCK_MASK, 1);
-       if (ret)
-               printf("%s timeout\n", __func__);
+       while (!(readl(pll_control_reg) & SSCG_PLL_LOCK_MASK))
+               ;
 }
 
 int frac_pll_init(u32 pll, enum frac_pll_out_val val)