imx8m: configure arm clk sources from PLL
authorPeng Fan <peng.fan@nxp.com>
Thu, 9 Jul 2020 03:06:24 +0000 (11:06 +0800)
committerPeng Fan <peng.fan@nxp.com>
Tue, 14 Jul 2020 07:23:47 +0000 (15:23 +0800)
A53 CCM root max support 1GHz, to support high freq, we need
to switch ARM clk sources from ARM PLL directly.

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

index aafe2ed..6ab75f0 100644 (file)
@@ -19,6 +19,7 @@ DECLARE_GLOBAL_DATA_PTR;
 
 static struct anamix_pll *ana_pll = (struct anamix_pll *)ANATOP_BASE_ADDR;
 
+static u32 get_root_clk(enum clk_root_index clock_id);
 void enable_ocotp_clk(unsigned char enable)
 {
        clock_enable(CCGR_OCOTP, !!enable);
@@ -164,6 +165,109 @@ void dram_disable_bypass(void)
 }
 #endif
 
+int intpll_configure(enum pll_clocks pll, ulong freq)
+{
+       void __iomem *pll_gnrl_ctl, __iomem *pll_div_ctl;
+       u32 pll_div_ctl_val, pll_clke_masks;
+
+       switch (pll) {
+       case ANATOP_SYSTEM_PLL1:
+               pll_gnrl_ctl = &ana_pll->sys_pll1_gnrl_ctl;
+               pll_div_ctl = &ana_pll->sys_pll1_div_ctl;
+               pll_clke_masks = INTPLL_DIV20_CLKE_MASK |
+                       INTPLL_DIV10_CLKE_MASK | INTPLL_DIV8_CLKE_MASK |
+                       INTPLL_DIV6_CLKE_MASK | INTPLL_DIV5_CLKE_MASK |
+                       INTPLL_DIV4_CLKE_MASK | INTPLL_DIV3_CLKE_MASK |
+                       INTPLL_DIV2_CLKE_MASK | INTPLL_CLKE_MASK;
+               break;
+       case ANATOP_SYSTEM_PLL2:
+               pll_gnrl_ctl = &ana_pll->sys_pll2_gnrl_ctl;
+               pll_div_ctl = &ana_pll->sys_pll2_div_ctl;
+               pll_clke_masks = INTPLL_DIV20_CLKE_MASK |
+                       INTPLL_DIV10_CLKE_MASK | INTPLL_DIV8_CLKE_MASK |
+                       INTPLL_DIV6_CLKE_MASK | INTPLL_DIV5_CLKE_MASK |
+                       INTPLL_DIV4_CLKE_MASK | INTPLL_DIV3_CLKE_MASK |
+                       INTPLL_DIV2_CLKE_MASK | INTPLL_CLKE_MASK;
+               break;
+       case ANATOP_SYSTEM_PLL3:
+               pll_gnrl_ctl = &ana_pll->sys_pll3_gnrl_ctl;
+               pll_div_ctl = &ana_pll->sys_pll3_div_ctl;
+               pll_clke_masks = INTPLL_CLKE_MASK;
+               break;
+       case ANATOP_ARM_PLL:
+               pll_gnrl_ctl = &ana_pll->arm_pll_gnrl_ctl;
+               pll_div_ctl = &ana_pll->arm_pll_div_ctl;
+               pll_clke_masks = INTPLL_CLKE_MASK;
+               break;
+       case ANATOP_GPU_PLL:
+               pll_gnrl_ctl = &ana_pll->gpu_pll_gnrl_ctl;
+               pll_div_ctl = &ana_pll->gpu_pll_div_ctl;
+               pll_clke_masks = INTPLL_CLKE_MASK;
+               break;
+       case ANATOP_VPU_PLL:
+               pll_gnrl_ctl = &ana_pll->vpu_pll_gnrl_ctl;
+               pll_div_ctl = &ana_pll->vpu_pll_div_ctl;
+               pll_clke_masks = INTPLL_CLKE_MASK;
+               break;
+       default:
+               return -EINVAL;
+       };
+
+       switch (freq) {
+       case MHZ(600):
+               /* 24 * 0x12c / 3 / 2 ^ 2 */
+               pll_div_ctl_val = INTPLL_MAIN_DIV_VAL(0x12c) |
+                       INTPLL_PRE_DIV_VAL(3) | INTPLL_POST_DIV_VAL(2);
+               break;
+       case MHZ(750):
+               /* 24 * 0xfa / 2 / 2 ^ 2 */
+               pll_div_ctl_val = INTPLL_MAIN_DIV_VAL(0xfa) |
+                       INTPLL_PRE_DIV_VAL(2) | INTPLL_POST_DIV_VAL(2);
+               break;
+       case MHZ(800):
+               /* 24 * 0x190 / 3 / 2 ^ 2 */
+               pll_div_ctl_val = INTPLL_MAIN_DIV_VAL(0x190) |
+                       INTPLL_PRE_DIV_VAL(3) | INTPLL_POST_DIV_VAL(2);
+               break;
+       case MHZ(1000):
+               /* 24 * 0xfa / 3 / 2 ^ 1 */
+               pll_div_ctl_val = INTPLL_MAIN_DIV_VAL(0xfa) |
+                       INTPLL_PRE_DIV_VAL(3) | INTPLL_POST_DIV_VAL(1);
+               break;
+       case MHZ(1200):
+               /* 24 * 0xc8 / 2 / 2 ^ 1 */
+               pll_div_ctl_val = INTPLL_MAIN_DIV_VAL(0xc8) |
+                       INTPLL_PRE_DIV_VAL(2) | INTPLL_POST_DIV_VAL(1);
+               break;
+       case MHZ(2000):
+               /* 24 * 0xfa / 3 / 2 ^ 0 */
+               pll_div_ctl_val = INTPLL_MAIN_DIV_VAL(0xfa) |
+                       INTPLL_PRE_DIV_VAL(3) | INTPLL_POST_DIV_VAL(0);
+               break;
+       default:
+               return -EINVAL;
+       };
+       /* Bypass clock and set lock to pll output lock */
+       setbits_le32(pll_gnrl_ctl, INTPLL_BYPASS_MASK | INTPLL_LOCK_SEL_MASK);
+       /* Enable reset */
+       clrbits_le32(pll_gnrl_ctl, INTPLL_RST_MASK);
+       /* Configure */
+       writel(pll_div_ctl_val, pll_div_ctl);
+
+       __udelay(100);
+
+       /* Disable reset */
+       setbits_le32(pll_gnrl_ctl, INTPLL_RST_MASK);
+       /* Wait Lock */
+       while (!(readl(pll_gnrl_ctl) & INTPLL_LOCK_MASK))
+               ;
+       /* Clear bypass */
+       clrbits_le32(pll_gnrl_ctl, INTPLL_BYPASS_MASK);
+       setbits_le32(pll_gnrl_ctl, pll_clke_masks);
+
+       return 0;
+}
+
 void init_uart_clk(u32 index)
 {
        /*
@@ -240,6 +344,15 @@ int clock_init(void)
                INTPLL_DIV20_CLKE_MASK;
        writel(val_cfg0, &ana_pll->sys_pll2_gnrl_ctl);
 
+       /* Configure ARM at 1.2GHz */
+       clock_set_target_val(ARM_A53_CLK_ROOT, CLK_ROOT_ON |
+                            CLK_ROOT_SOURCE_SEL(2));
+
+       intpll_configure(ANATOP_ARM_PLL, MHZ(1200));
+
+       /* Bypass CCM A53 ROOT, Switch to ARM PLL -> MUX-> CPU */
+       clock_set_target_val(CORE_SEL_CFG, CLK_ROOT_SOURCE_SEL(1));
+
        /* config GIC to sys_pll2_100m */
        clock_enable(CCGR_GIC, 0);
        clock_set_target_val(GIC_CLK_ROOT, CLK_ROOT_ON |
@@ -519,6 +632,8 @@ static u32 get_root_src_clk(enum clk_root_src root_src)
        case AUDIO_PLL2_CLK:
        case VIDEO_PLL_CLK:
                return decode_fracpll(root_src);
+       case ARM_A53_ALT_CLK:
+               return get_root_clk(ARM_A53_CLK_ROOT);
        default:
                return 0;
        }
@@ -548,13 +663,26 @@ static u32 get_root_clk(enum clk_root_index clock_id)
        return root_src_clk / (post_podf + 1) / (pre_podf + 1);
 }
 
+u32 get_arm_core_clk(void)
+{
+       enum clk_root_src root_src;
+       u32 root_src_clk;
+
+       if (clock_get_src(CORE_SEL_CFG, &root_src) < 0)
+               return 0;
+
+       root_src_clk = get_root_src_clk(root_src);
+
+       return root_src_clk;
+}
+
 u32 mxc_get_clock(enum mxc_clock clk)
 {
        u32 val;
 
        switch (clk) {
        case MXC_ARM_CLK:
-               return get_root_clk(ARM_A53_CLK_ROOT);
+               return get_arm_core_clk();
        case MXC_IPG_CLK:
                clock_get_target_val(IPG_CLK_ROOT, &val);
                val = val & 0x3;