diff mbox series

[01/11] imx8m: configure arm clk sources from PLL

Message ID 20200709084042.8234-2-peng.fan@nxp.com
State Accepted
Commit 46a8a28bf60bde07e6c3b5c44a77af2544d8aee9
Headers show
Series imx8m: soc/clk update | expand

Commit Message

Peng Fan July 9, 2020, 8:40 a.m. UTC
From: Peng Fan <peng.fan@nxp.com>

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 | 130 ++++++++++++++++++++++++++++++++-
 1 file changed, 129 insertions(+), 1 deletion(-)
diff mbox series

Patch

diff --git a/arch/arm/mach-imx/imx8m/clock_imx8mm.c b/arch/arm/mach-imx/imx8m/clock_imx8mm.c
index aafe2ed084..6ab75f0e2c 100644
--- a/arch/arm/mach-imx/imx8m/clock_imx8mm.c
+++ b/arch/arm/mach-imx/imx8m/clock_imx8mm.c
@@ -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;