imx: imx8ulp: add ND/LD clock

Add a new ddr script, defconfig for ND
Configure the clock for ND mode
changing A35 to 960MHz for OD mode
Update NIC CLK for the various modes
Introduce clock_init_early/late, late is used after pmic voltage
setting, early is used in the very early stage for upower mu, lpuart and
etc.

Note: NIC runs at 324MHz, 442MHz has some random kernel hang issue with
cpuidle enabled now.

Reviewed-by: Ye Li <ye.li@nxp.com>
Signed-off-by: Peng Fan <peng.fan@nxp.com>
diff --git a/arch/arm/mach-imx/imx8ulp/Kconfig b/arch/arm/mach-imx/imx8ulp/Kconfig
index d8b5ef7..bbdeaac 100644
--- a/arch/arm/mach-imx/imx8ulp/Kconfig
+++ b/arch/arm/mach-imx/imx8ulp/Kconfig
@@ -6,6 +6,12 @@
 config SYS_SOC
 	default "imx8ulp"
 
+config IMX8ULP_LD_MODE
+	bool
+
+config IMX8ULP_ND_MODE
+	bool "i.MX8ULP Low Driver Mode"
+
 choice
 	prompt "i.MX8ULP board select"
 	optional
diff --git a/arch/arm/mach-imx/imx8ulp/cgc.c b/arch/arm/mach-imx/imx8ulp/cgc.c
index 38bcbb9..494ddb0 100644
--- a/arch/arm/mach-imx/imx8ulp/cgc.c
+++ b/arch/arm/mach-imx/imx8ulp/cgc.c
@@ -9,9 +9,11 @@
 #include <errno.h>
 #include <asm/arch/imx-regs.h>
 #include <asm/arch/cgc.h>
+#include <asm/arch/clock.h>
 #include <asm/arch/sys_proto.h>
 #include <asm/global_data.h>
 #include <linux/delay.h>
+#include <hang.h>
 
 DECLARE_GLOBAL_DATA_PTR;
 
@@ -29,7 +31,7 @@
 	clrbits_le32(&cgc1_regs->frodiv, BIT(7));
 }
 
-void cgc1_pll2_init(void)
+void cgc1_pll2_init(ulong freq)
 {
 	u32 reg;
 
@@ -44,8 +46,8 @@
 	while ((readl(&cgc1_regs->pll2csr) & BIT(24)))
 		;
 
-	/* Select SOSC as source, freq = 31 * 24 =744mhz */
-	reg = 31 << 16;
+	/* Select SOSC as source */
+	reg = (freq / MHZ(24)) << 16;
 	writel(reg, &cgc1_regs->pll2cfg);
 
 	/* Enable PLL2 */
@@ -74,7 +76,7 @@
 		;
 }
 
-void cgc1_init_core_clk(void)
+void cgc1_init_core_clk(ulong freq)
 {
 	u32 reg = readl(&cgc1_regs->ca35clk);
 
@@ -82,8 +84,7 @@
 	if (((reg >> 28) & 0x3) == 0x1)
 		cgc1_set_a35_clk(0, 1);
 
-	/* Set pll2 to 750Mhz for 1V  */
-	cgc1_pll2_init();
+	cgc1_pll2_init(freq);
 
 	/* Set A35 clock to pll2 */
 	cgc1_set_a35_clk(1, 1);
@@ -94,7 +95,7 @@
 	writel((clk_src & 0x7) << 24, &cgc1_regs->enetstamp);
 }
 
-void cgc1_pll3_init(void)
+void cgc1_pll3_init(ulong freq)
 {
 	/* Gate off VCO */
 	setbits_le32(&cgc1_regs->pll3div_vco, BIT(7));
@@ -115,11 +116,15 @@
 	/* Select SOSC as source */
 	clrbits_le32(&cgc1_regs->pll3cfg, BIT(0));
 
-	//setbits_le32(&cgc1_regs->pll3cfg, 22 << 16);
-	writel(22 << 16, &cgc1_regs->pll3cfg);
-
-	writel(578, &cgc1_regs->pll3num);
-	writel(1000, &cgc1_regs->pll3denom);
+	switch (freq) {
+	case 540672000:
+		writel(0x16 << 16, &cgc1_regs->pll3cfg);
+		writel(0x16e3600, &cgc1_regs->pll3denom);
+		writel(0xc15c00, &cgc1_regs->pll3num);
+		break;
+	default:
+		hang();
+	}
 
 	/* Enable PLL3 */
 	setbits_le32(&cgc1_regs->pll3csr, BIT(0));
@@ -130,23 +135,30 @@
 	/* Gate on VCO */
 	clrbits_le32(&cgc1_regs->pll3div_vco, BIT(7));
 
-	/*
-	 * PFD0: 380MHz/396/396/328
-	 */
 	clrbits_le32(&cgc1_regs->pll3pfdcfg, 0x3F);
-	setbits_le32(&cgc1_regs->pll3pfdcfg, 25 << 0);
+
+	if (IS_ENABLED(CONFIG_IMX8ULP_LD_MODE)) {
+		setbits_le32(&cgc1_regs->pll3pfdcfg, 25 << 0);
+		clrsetbits_le32(&cgc1_regs->nicclk, GENMASK(26, 21), 3 << 21); /* 195M */
+	} else if (IS_ENABLED(CONFIG_IMX8ULP_ND_MODE)) {
+		setbits_le32(&cgc1_regs->pll3pfdcfg, 21 << 0);
+		clrsetbits_le32(&cgc1_regs->nicclk, GENMASK(26, 21), 1 << 21); /* 231M */
+	} else {
+		setbits_le32(&cgc1_regs->pll3pfdcfg, 30 << 0); /* 324M */
+	}
+
 	clrbits_le32(&cgc1_regs->pll3pfdcfg, BIT(7));
 	while (!(readl(&cgc1_regs->pll3pfdcfg) & BIT(6)))
 		;
 
 	clrbits_le32(&cgc1_regs->pll3pfdcfg, 0x3F << 8);
-	setbits_le32(&cgc1_regs->pll3pfdcfg, 24 << 8);
+	setbits_le32(&cgc1_regs->pll3pfdcfg, 25 << 8);
 	clrbits_le32(&cgc1_regs->pll3pfdcfg, BIT(15));
 	while (!(readl(&cgc1_regs->pll3pfdcfg) & BIT(14)))
 		;
 
 	clrbits_le32(&cgc1_regs->pll3pfdcfg, 0x3F << 16);
-	setbits_le32(&cgc1_regs->pll3pfdcfg, 24 << 16);
+	setbits_le32(&cgc1_regs->pll3pfdcfg, 25 << 16);
 	clrbits_le32(&cgc1_regs->pll3pfdcfg, BIT(23));
 	while (!(readl(&cgc1_regs->pll3pfdcfg) & BIT(22)))
 		;
@@ -166,6 +178,13 @@
 	clrbits_le32(&cgc1_regs->pll3div_pfd1, BIT(15));
 	clrbits_le32(&cgc1_regs->pll3div_pfd1, BIT(23));
 	clrbits_le32(&cgc1_regs->pll3div_pfd1, BIT(31));
+
+	if (!IS_ENABLED(CONFIG_IMX8ULP_LD_MODE) && !IS_ENABLED(CONFIG_IMX8ULP_ND_MODE)) {
+		/* nicclk select pll3 pfd0 */
+		clrsetbits_le32(&cgc1_regs->nicclk, GENMASK(29, 28), BIT(28));
+		while (!(readl(&cgc1_regs->nicclk) & BIT(27)))
+			;
+	}
 }
 
 void cgc2_pll4_init(void)
@@ -189,10 +208,21 @@
 		;
 
 	/* Enable all 4 PFDs */
-	setbits_le32(&cgc2_regs->pll4pfdcfg, 18 << 0);
-	setbits_le32(&cgc2_regs->pll4pfdcfg, 30 << 8); /* 316.8Mhz for NIC_LPAV */
-	setbits_le32(&cgc2_regs->pll4pfdcfg, 12 << 16);
-	setbits_le32(&cgc2_regs->pll4pfdcfg, 24 << 24);
+	setbits_le32(&cgc2_regs->pll4pfdcfg, 18 << 0); /* 528 */
+	if (IS_ENABLED(CONFIG_IMX8ULP_LD_MODE)) {
+		setbits_le32(&cgc2_regs->pll4pfdcfg, 24 << 8);
+		/* 99Mhz for NIC_LPAV */
+		clrsetbits_le32(&cgc2_regs->niclpavclk, GENMASK(26, 21), 3 << 21);
+	} else if (IS_ENABLED(CONFIG_IMX8ULP_ND_MODE)) {
+		setbits_le32(&cgc2_regs->pll4pfdcfg, 24 << 8);
+		/* 198Mhz for NIC_LPAV */
+		clrsetbits_le32(&cgc2_regs->niclpavclk, GENMASK(26, 21), 1 << 21);
+	} else {
+		setbits_le32(&cgc2_regs->pll4pfdcfg, 30 << 8); /* 316.8Mhz for NIC_LPAV */
+		clrbits_le32(&cgc2_regs->niclpavclk, GENMASK(26, 21));
+	}
+	setbits_le32(&cgc2_regs->pll4pfdcfg, 12 << 16); /* 792 */
+	setbits_le32(&cgc2_regs->pll4pfdcfg, 24 << 24); /* 396 */
 
 	clrbits_le32(&cgc2_regs->pll4pfdcfg, BIT(7) | BIT(15) | BIT(23) | BIT(31));
 
@@ -203,6 +233,10 @@
 	/* Enable PFD DIV */
 	clrbits_le32(&cgc2_regs->pll4div_pfd0, BIT(7) | BIT(15) | BIT(23) | BIT(31));
 	clrbits_le32(&cgc2_regs->pll4div_pfd1, BIT(7) | BIT(15) | BIT(23) | BIT(31));
+
+	clrsetbits_le32(&cgc2_regs->niclpavclk, GENMASK(29, 28), BIT(28));
+	while (!(readl(&cgc2_regs->niclpavclk) & BIT(27)))
+		;
 }
 
 void cgc2_pll4_pfd_config(enum cgc_clk pllpfd, u32 pfd)
diff --git a/arch/arm/mach-imx/imx8ulp/clock.c b/arch/arm/mach-imx/imx8ulp/clock.c
index a2b3ce7..4697157 100644
--- a/arch/arm/mach-imx/imx8ulp/clock.c
+++ b/arch/arm/mach-imx/imx8ulp/clock.c
@@ -102,7 +102,7 @@
 
 	/* enable pll4 and ddrclk*/
 	cgc2_pll4_init();
-	cgc2_ddrclk_config(1, 1);
+	cgc2_ddrclk_config(4, 1);
 
 	/* enable ddr pcc */
 	writel(0xd0000000, PCC5_LPDDR4_ADDR);
@@ -153,30 +153,66 @@
 	return 0;
 }
 
-void clock_init(void)
+void clock_init_early(void)
 {
 	cgc1_soscdiv_init();
-	cgc1_init_core_clk();
 
 	init_clk_lpuart();
 
-	pcc_clock_enable(4, SDHC0_PCC4_SLOT, false);
-	pcc_clock_sel(4, SDHC0_PCC4_SLOT, PLL3_PFD1_DIV2);
-	pcc_clock_enable(4, SDHC0_PCC4_SLOT, true);
-	pcc_reset_peripheral(4, SDHC0_PCC4_SLOT, false);
-
-	pcc_clock_enable(4, SDHC1_PCC4_SLOT, false);
-	pcc_clock_sel(4, SDHC1_PCC4_SLOT, PLL3_PFD2_DIV1);
-	pcc_clock_enable(4, SDHC1_PCC4_SLOT, true);
-	pcc_reset_peripheral(4, SDHC1_PCC4_SLOT, false);
-
-	pcc_clock_enable(4, SDHC2_PCC4_SLOT, false);
-	pcc_clock_sel(4, SDHC2_PCC4_SLOT, PLL3_PFD2_DIV1);
-	pcc_clock_enable(4, SDHC2_PCC4_SLOT, true);
-	pcc_reset_peripheral(4, SDHC2_PCC4_SLOT, false);
-
 	/* Enable upower mu1 clk */
 	pcc_clock_enable(3, UPOWER_PCC3_SLOT, true);
+}
+
+/* This will be invoked after pmic voltage setting */
+void clock_init_late(void)
+{
+
+	if (IS_ENABLED(CONFIG_IMX8ULP_LD_MODE))
+		cgc1_init_core_clk(MHZ(500));
+	else if (IS_ENABLED(CONFIG_IMX8ULP_ND_MODE))
+		cgc1_init_core_clk(MHZ(750));
+	else
+		cgc1_init_core_clk(MHZ(960));
+
+	/*
+	 * Audio use this frequency in kernel dts,
+	 * however nic use pll3 pfd0, we have to
+	 * make the freqency same as kernel to make nic
+	 * not being disabled
+	 */
+	cgc1_pll3_init(540672000);
+
+	if (IS_ENABLED(CONFIG_IMX8ULP_LD_MODE) || IS_ENABLED(CONFIG_IMX8ULP_ND_MODE)) {
+		pcc_clock_enable(4, SDHC0_PCC4_SLOT, false);
+		pcc_clock_sel(4, SDHC0_PCC4_SLOT, PLL3_PFD2_DIV2);
+		pcc_clock_enable(4, SDHC0_PCC4_SLOT, true);
+		pcc_reset_peripheral(4, SDHC0_PCC4_SLOT, false);
+
+		pcc_clock_enable(4, SDHC1_PCC4_SLOT, false);
+		pcc_clock_sel(4, SDHC1_PCC4_SLOT, PLL3_PFD2_DIV2);
+		pcc_clock_enable(4, SDHC1_PCC4_SLOT, true);
+		pcc_reset_peripheral(4, SDHC1_PCC4_SLOT, false);
+
+		pcc_clock_enable(4, SDHC2_PCC4_SLOT, false);
+		pcc_clock_sel(4, SDHC2_PCC4_SLOT, PLL3_PFD2_DIV2);
+		pcc_clock_enable(4, SDHC2_PCC4_SLOT, true);
+		pcc_reset_peripheral(4, SDHC2_PCC4_SLOT, false);
+	} else {
+		pcc_clock_enable(4, SDHC0_PCC4_SLOT, false);
+		pcc_clock_sel(4, SDHC0_PCC4_SLOT, PLL3_PFD1_DIV2);
+		pcc_clock_enable(4, SDHC0_PCC4_SLOT, true);
+		pcc_reset_peripheral(4, SDHC0_PCC4_SLOT, false);
+
+		pcc_clock_enable(4, SDHC1_PCC4_SLOT, false);
+		pcc_clock_sel(4, SDHC1_PCC4_SLOT, PLL3_PFD2_DIV1);
+		pcc_clock_enable(4, SDHC1_PCC4_SLOT, true);
+		pcc_reset_peripheral(4, SDHC1_PCC4_SLOT, false);
+
+		pcc_clock_enable(4, SDHC2_PCC4_SLOT, false);
+		pcc_clock_sel(4, SDHC2_PCC4_SLOT, PLL3_PFD2_DIV1);
+		pcc_clock_enable(4, SDHC2_PCC4_SLOT, true);
+		pcc_reset_peripheral(4, SDHC2_PCC4_SLOT, false);
+	}
 
 	/*
 	 * Enable clock division
diff --git a/arch/arm/mach-imx/imx8ulp/soc.c b/arch/arm/mach-imx/imx8ulp/soc.c
index 9a632b9..85bf57b 100644
--- a/arch/arm/mach-imx/imx8ulp/soc.c
+++ b/arch/arm/mach-imx/imx8ulp/soc.c
@@ -597,7 +597,7 @@
 
 		xrdc_mrc_region_set_access(2, CONFIG_SPL_TEXT_BASE, 0xE00);
 
-		clock_init();
+		clock_init_early();
 	} else {
 		/* reconfigure core0 reset vector to ROM */
 		set_core0_reset_vector(0x1000);