feat(imx8m): add the ddr frequency change support for imx8m family

Add the DDR frequency change support.

Signed-off-by: Jacky Bai <ping.bai@nxp.com>
Change-Id: If1167785796b8678c351569b83d2922c66f6e530
diff --git a/plat/imx/imx8m/ddr/clock.c b/plat/imx/imx8m/ddr/clock.c
new file mode 100644
index 0000000..7fb5730
--- /dev/null
+++ b/plat/imx/imx8m/ddr/clock.c
@@ -0,0 +1,136 @@
+/*
+ * Copyright 2018-2022 NXP
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <stdbool.h>
+
+#include <lib/mmio.h>
+#include <platform_def.h>
+
+#define IMX_CCM_IP_BASE				(IMX_CCM_BASE + 0xa000)
+#define DRAM_SEL_CFG				(IMX_CCM_BASE + 0x9800)
+#define CCM_IP_CLK_ROOT_GEN_TAGET(i)		(IMX_CCM_IP_BASE + 0x80 * (i) + 0x00)
+#define CCM_IP_CLK_ROOT_GEN_TAGET_SET(i)	(IMX_CCM_IP_BASE + 0x80 * (i) + 0x04)
+#define CCM_IP_CLK_ROOT_GEN_TAGET_CLR(i)	(IMX_CCM_IP_BASE + 0x80 * (i) + 0x08)
+#define PLL_FREQ_800M	U(0x00ece580)
+#define PLL_FREQ_400M	U(0x00ec6984)
+#define PLL_FREQ_167M	U(0x00f5a406)
+
+void ddr_pll_bypass_100mts(void)
+{
+	/* change the clock source of dram_alt_clk_root to source 2 --100MHz */
+	mmio_write_32(CCM_IP_CLK_ROOT_GEN_TAGET_CLR(0), (0x7 << 24) | (0x7 << 16));
+	mmio_write_32(CCM_IP_CLK_ROOT_GEN_TAGET_SET(0), (0x2 << 24));
+
+	/* change the clock source of dram_apb_clk_root to source 2 --40MHz/2 */
+	mmio_write_32(CCM_IP_CLK_ROOT_GEN_TAGET_CLR(1), (0x7 << 24) | (0x7 << 16));
+	mmio_write_32(CCM_IP_CLK_ROOT_GEN_TAGET_SET(1), (0x2 << 24) | (0x1 << 16));
+
+	/* configure pll bypass mode */
+	mmio_write_32(DRAM_SEL_CFG + 0x4, BIT(24));
+}
+
+void ddr_pll_bypass_400mts(void)
+{
+	/* change the clock source of dram_alt_clk_root to source 1 --400MHz */
+	mmio_write_32(CCM_IP_CLK_ROOT_GEN_TAGET_CLR(0), (0x7 << 24) | (0x7 << 16));
+	mmio_write_32(CCM_IP_CLK_ROOT_GEN_TAGET_SET(0), (0x1 << 24) | (0x1 << 16));
+
+	/* change the clock source of dram_apb_clk_root to source 3 --160MHz/2 */
+	mmio_write_32(CCM_IP_CLK_ROOT_GEN_TAGET_CLR(1), (0x7 << 24) | (0x7 << 16));
+	mmio_write_32(CCM_IP_CLK_ROOT_GEN_TAGET_SET(1), (0x3 << 24) | (0x1 << 16));
+
+	/* configure pll bypass mode */
+	mmio_write_32(DRAM_SEL_CFG + 0x4, BIT(24));
+}
+
+void ddr_pll_unbypass(void)
+{
+	mmio_write_32(DRAM_SEL_CFG + 0x8, BIT(24));
+	mmio_write_32(CCM_IP_CLK_ROOT_GEN_TAGET_CLR(1), (0x7 << 24) | (0x7 << 16));
+	/* to source 4 --800MHz/5 */
+	mmio_write_32(CCM_IP_CLK_ROOT_GEN_TAGET_SET(1), (0x4 << 24) | (0x4 << 16));
+}
+
+#if defined(PLAT_imx8mq)
+void dram_pll_init(unsigned int drate)
+{
+	/* bypass the PLL */
+	mmio_setbits_32(HW_DRAM_PLL_CFG0, 0x30);
+
+	switch (drate) {
+	case 3200:
+		mmio_write_32(HW_DRAM_PLL_CFG2, PLL_FREQ_800M);
+		break;
+	case 1600:
+		mmio_write_32(HW_DRAM_PLL_CFG2, PLL_FREQ_400M);
+		break;
+	case 667:
+		mmio_write_32(HW_DRAM_PLL_CFG2, PLL_FREQ_167M);
+		break;
+	default:
+		break;
+	}
+
+	/* unbypass the PLL */
+	mmio_clrbits_32(HW_DRAM_PLL_CFG0, 0x30);
+	while (!(mmio_read_32(HW_DRAM_PLL_CFG0) & (1 << 31))) {
+		;
+	}
+}
+#else
+void dram_pll_init(unsigned int drate)
+{
+	/* bypass the PLL */
+	mmio_setbits_32(DRAM_PLL_CTRL, (1 << 16));
+	mmio_clrbits_32(DRAM_PLL_CTRL, (1 << 9));
+
+	switch (drate) {
+	case 2400:
+		mmio_write_32(DRAM_PLL_CTRL + 0x4, (300 << 12) | (3 << 4) | 2);
+		break;
+	case 1600:
+		mmio_write_32(DRAM_PLL_CTRL + 0x4, (400 << 12) | (3 << 4) | 3);
+		break;
+	case 1066:
+		mmio_write_32(DRAM_PLL_CTRL + 0x4, (266 << 12) | (3 << 4) | 3);
+		break;
+	case 667:
+		mmio_write_32(DRAM_PLL_CTRL + 0x4, (334 << 12) | (3 << 4) | 4);
+		break;
+	default:
+		break;
+	}
+
+	mmio_setbits_32(DRAM_PLL_CTRL, BIT(9));
+	/* wait for PLL locked */
+	while (!(mmio_read_32(DRAM_PLL_CTRL) & BIT(31))) {
+		;
+	}
+
+	/* unbypass the PLL */
+	mmio_clrbits_32(DRAM_PLL_CTRL, BIT(16));
+}
+#endif
+
+/* change the dram clock frequency */
+void dram_clock_switch(unsigned int target_drate, bool bypass_mode)
+{
+	if (bypass_mode) {
+		switch (target_drate) {
+		case 400:
+			ddr_pll_bypass_400mts();
+			break;
+		case 100:
+			ddr_pll_bypass_100mts();
+			break;
+		default:
+			ddr_pll_unbypass();
+			break;
+		}
+	} else {
+		dram_pll_init(target_drate);
+	}
+}