summaryrefslogtreecommitdiffstats
path: root/arch/arm/mach-imx/imx8m.c
diff options
context:
space:
mode:
Diffstat (limited to 'arch/arm/mach-imx/imx8m.c')
-rw-r--r--arch/arm/mach-imx/imx8m.c206
1 files changed, 206 insertions, 0 deletions
diff --git a/arch/arm/mach-imx/imx8m.c b/arch/arm/mach-imx/imx8m.c
new file mode 100644
index 0000000000..52e42ee9ef
--- /dev/null
+++ b/arch/arm/mach-imx/imx8m.c
@@ -0,0 +1,206 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+
+#include <init.h>
+#include <common.h>
+#include <linux/sizes.h>
+#include <io.h>
+#include <asm/syscounter.h>
+#include <asm/system.h>
+#include <mach/imx/generic.h>
+#include <mach/imx/imx8m-ccm-regs.h>
+#include <soc/imx8m/clk-early.h>
+
+#include <linux/bitfield.h>
+#include <linux/iopoll.h>
+
+#define IMX_SIP_BUILDINFO 0xC2000003
+#define IMX_SIP_BUILDINFO_GET_COMMITHASH 0x00
+
+void imx8m_clock_set_target_val(int clock_id, u32 val)
+{
+ void __iomem *ccm = IOMEM(MX8M_CCM_BASE_ADDR);
+
+ writel(val, ccm + IMX8M_CCM_TARGET_ROOTn(clock_id));
+}
+
+void imx8m_ccgr_clock_enable(int index)
+{
+ void __iomem *ccm = IOMEM(MX8M_CCM_BASE_ADDR);
+
+ writel(IMX8M_CCM_CCGR_SETTINGn_NEEDED(0),
+ ccm + IMX8M_CCM_CCGRn_SET(index));
+}
+
+void imx8m_ccgr_clock_disable(int index)
+{
+ void __iomem *ccm = IOMEM(MX8M_CCM_BASE_ADDR);
+
+ writel(IMX8M_CCM_CCGR_SETTINGn_NEEDED(0),
+ ccm + IMX8M_CCM_CCGRn_CLR(index));
+}
+
+#define INTPLL_DIV20_CLKE_MASK BIT(27)
+#define INTPLL_DIV10_CLKE_MASK BIT(25)
+#define INTPLL_DIV8_CLKE_MASK BIT(23)
+#define INTPLL_DIV6_CLKE_MASK BIT(21)
+#define INTPLL_DIV5_CLKE_MASK BIT(19)
+#define INTPLL_DIV4_CLKE_MASK BIT(17)
+#define INTPLL_DIV3_CLKE_MASK BIT(15)
+#define INTPLL_DIV2_CLKE_MASK BIT(13)
+#define INTPLL_CLKE_MASK BIT(11)
+
+#define CCM_TARGET_ROOT0_DIV GENMASK(1, 0)
+
+#define IMX8MM_CCM_ANALOG_ARM_PLL_GEN_CTRL 0x84
+#define IMX8MM_CCM_ANALOG_SYS_PLL1_GEN_CTRL 0x94
+#define IMX8MM_CCM_ANALOG_SYS_PLL2_GEN_CTRL 0x104
+#define IMX8MM_CCM_ANALOG_SYS_PLL3_GEN_CTRL 0x114
+
+static void __imx8m_early_clock_init(unsigned long pll3_freq) /* and later */
+{
+ void __iomem *ana = IOMEM(MX8M_ANATOP_BASE_ADDR);
+ void __iomem *ccm = IOMEM(MX8M_CCM_BASE_ADDR);
+ u32 val;
+
+ imx8m_ccgr_clock_disable(IMX8M_CCM_CCGR_DDR1);
+
+ imx8m_clock_set_target_val(IMX8M_DRAM_ALT_CLK_ROOT,
+ IMX8M_CCM_TARGET_ROOTn_ENABLE |
+ IMX8M_CCM_TARGET_ROOTn_MUX(1));
+
+ /* change the clock source of dram_apb_clk_root: source 4 800MHz /4 = 200MHz */
+ imx8m_clock_set_target_val(IMX8M_DRAM_APB_CLK_ROOT,
+ IMX8M_CCM_TARGET_ROOTn_ENABLE |
+ IMX8M_CCM_TARGET_ROOTn_MUX(4) |
+ IMX8M_CCM_TARGET_ROOTn_POST_DIV(4 - 1));
+
+ imx8m_ccgr_clock_enable(IMX8M_CCM_CCGR_DDR1);
+
+ val = readl(ana + IMX8MM_CCM_ANALOG_SYS_PLL1_GEN_CTRL);
+ val |= INTPLL_CLKE_MASK | INTPLL_DIV2_CLKE_MASK |
+ INTPLL_DIV3_CLKE_MASK | INTPLL_DIV4_CLKE_MASK |
+ INTPLL_DIV5_CLKE_MASK | INTPLL_DIV6_CLKE_MASK |
+ INTPLL_DIV8_CLKE_MASK | INTPLL_DIV10_CLKE_MASK |
+ INTPLL_DIV20_CLKE_MASK;
+ writel(val, ana + IMX8MM_CCM_ANALOG_SYS_PLL1_GEN_CTRL);
+
+ val = readl(ana + IMX8MM_CCM_ANALOG_SYS_PLL2_GEN_CTRL);
+ val |= INTPLL_CLKE_MASK | INTPLL_DIV2_CLKE_MASK |
+ INTPLL_DIV3_CLKE_MASK | INTPLL_DIV4_CLKE_MASK |
+ INTPLL_DIV5_CLKE_MASK | INTPLL_DIV6_CLKE_MASK |
+ INTPLL_DIV8_CLKE_MASK | INTPLL_DIV10_CLKE_MASK |
+ INTPLL_DIV20_CLKE_MASK;
+ writel(val, ana + IMX8MM_CCM_ANALOG_SYS_PLL2_GEN_CTRL);
+
+ /* config GIC to sys_pll2_100m */
+ imx8m_ccgr_clock_disable(IMX8M_CCM_CCGR_GIC);
+ imx8m_clock_set_target_val(IMX8M_GIC_CLK_ROOT,
+ IMX8M_CCM_TARGET_ROOTn_ENABLE |
+ IMX8M_CCM_TARGET_ROOTn_MUX(3));
+ imx8m_ccgr_clock_enable(IMX8M_CCM_CCGR_GIC);
+
+ /* Configure SYS_PLL3 */
+ clk_pll1416x_early_set_rate(ana + IMX8MM_CCM_ANALOG_SYS_PLL3_GEN_CTRL,
+ pll3_freq, 25000000UL);
+
+ clrsetbits_le32(ccm + IMX8M_CCM_TARGET_ROOTn(IMX8M_ARM_A53_CLK_ROOT),
+ IMX8M_CCM_TARGET_ROOTn_MUX(7),
+ IMX8M_CCM_TARGET_ROOTn_MUX(2));
+
+ /* Configure ARM PLL to 1.2GHz */
+ clk_pll1416x_early_set_rate(ana + IMX8MM_CCM_ANALOG_ARM_PLL_GEN_CTRL,
+ 1200000000UL, 25000000UL);
+
+ clrsetbits_le32(ana + IMX8MM_CCM_ANALOG_ARM_PLL_GEN_CTRL, 0,
+ INTPLL_CLKE_MASK);
+
+ clrsetbits_le32(ccm + IMX8M_CCM_TARGET_ROOTn(IMX8M_ARM_A53_CLK_ROOT),
+ IMX8M_CCM_TARGET_ROOTn_MUX(7),
+ IMX8M_CCM_TARGET_ROOTn_MUX(1));
+
+ /* Configure DIV to 1.2GHz */
+ clrsetbits_le32(ccm + IMX8M_CCM_TARGET_ROOTn(IMX8M_ARM_A53_CLK_ROOT),
+ CCM_TARGET_ROOT0_DIV,
+ FIELD_PREP(CCM_TARGET_ROOT0_DIV, 0));
+}
+
+void imx8mm_early_clock_init(void)
+{
+ __imx8m_early_clock_init(750000000UL);
+}
+
+void imx8mn_early_clock_init(void)
+{
+ __imx8m_early_clock_init(600000000UL);
+}
+
+void imx8mp_early_clock_init(void)
+{
+ __imx8m_early_clock_init(750000000UL);
+}
+
+
+#define KEEP_ALIVE 0x18
+#define VER_L 0x1c
+#define VER_H 0x20
+#define VER_LIB_L_ADDR 0x24
+#define VER_LIB_H_ADDR 0x28
+#define FW_ALIVE_TIMEOUT_US 100000
+
+static int imx8mq_report_hdmi_firmware(void)
+{
+ void __iomem *hdmi = IOMEM(MX8MQ_HDMI_CTRL_BASE_ADDR);
+ u16 ver_lib, ver;
+ u32 reg;
+ int ret;
+
+ if (!cpu_is_mx8mq())
+ return 0;
+
+ /* check the keep alive register to make sure fw working */
+ ret = readl_poll_timeout(hdmi + KEEP_ALIVE,
+ reg, reg, FW_ALIVE_TIMEOUT_US);
+ if (ret < 0) {
+ pr_info("HDP firmware is not running\n");
+ return 0;
+ }
+
+ ver = readl(hdmi + VER_H) & 0xff;
+ ver <<= 8;
+ ver |= readl(hdmi + VER_L) & 0xff;
+
+ ver_lib = readl(hdmi + VER_LIB_H_ADDR) & 0xff;
+ ver_lib <<= 8;
+ ver_lib |= readl(hdmi + VER_LIB_L_ADDR) & 0xff;
+
+ pr_info("HDP firmware ver: %d ver_lib: %d\n", ver, ver_lib);
+
+ return 0;
+}
+console_initcall(imx8mq_report_hdmi_firmware);
+
+void imx8m_early_setup_uart_clock(void)
+{
+ imx8m_ccgr_clock_disable(IMX8M_CCM_CCGR_UART1);
+ imx8m_ccgr_clock_disable(IMX8M_CCM_CCGR_UART2);
+ imx8m_ccgr_clock_disable(IMX8M_CCM_CCGR_UART3);
+ imx8m_ccgr_clock_disable(IMX8M_CCM_CCGR_UART4);
+
+ imx8m_clock_set_target_val(IMX8M_UART1_CLK_ROOT,
+ IMX8M_CCM_TARGET_ROOTn_ENABLE |
+ IMX8M_UART1_CLK_ROOT__25M_REF_CLK);
+ imx8m_clock_set_target_val(IMX8M_UART2_CLK_ROOT,
+ IMX8M_CCM_TARGET_ROOTn_ENABLE |
+ IMX8M_UART1_CLK_ROOT__25M_REF_CLK);
+ imx8m_clock_set_target_val(IMX8M_UART3_CLK_ROOT,
+ IMX8M_CCM_TARGET_ROOTn_ENABLE |
+ IMX8M_UART1_CLK_ROOT__25M_REF_CLK);
+ imx8m_clock_set_target_val(IMX8M_UART4_CLK_ROOT,
+ IMX8M_CCM_TARGET_ROOTn_ENABLE |
+ IMX8M_UART1_CLK_ROOT__25M_REF_CLK);
+
+ imx8m_ccgr_clock_enable(IMX8M_CCM_CCGR_UART1);
+ imx8m_ccgr_clock_enable(IMX8M_CCM_CCGR_UART2);
+ imx8m_ccgr_clock_enable(IMX8M_CCM_CCGR_UART3);
+ imx8m_ccgr_clock_enable(IMX8M_CCM_CCGR_UART4);
+}