[U-Boot] [PATCH] ARM: tegra: don't exceed AVP limits when configuring PLLP

Stephen Warren swarren at wwwdotorg.org
Wed Jan 22 21:21:15 CET 2014


From: Jimmy Zhang <jimmzhang at nvidia.com>

Based on the Tegra114 TRM, the system clock (which is the AVP clock) can
run up to 275MHz. On power on, the default sytem clock source is set to
PLLP_OUT0. In function clock_early_init(), PLLP_OUT0 will be set to
408MHz which is beyond system clock's upper limit.

The fix is to set the system clock to CLK_M before initializing PLLP,
and then switch back to PLLP_OUT4, which has an appropriate divider
configured, after PLLP has been configured

Signed-off-by: Jimmy Zhang <jimmzhang at nvidia.com>
[swarren, significantly refactored the changes, so that AVP only runs on
clk_m for the short duration that PLLP is being reconfigured. Fixed
Tegra30 too]
Signed-off-by: Stephen Warren <swarren at nvidia.com>
---
 arch/arm/cpu/arm720t/tegra114/cpu.c       | 12 ------------
 arch/arm/cpu/arm720t/tegra30/cpu.c        | 12 ------------
 arch/arm/cpu/tegra-common/clock.c         | 15 +++++++++++++++
 arch/arm/cpu/tegra114-common/clock.c      | 27 +++++++++++++++++++++++++++
 arch/arm/cpu/tegra30-common/clock.c       | 30 ++++++++++++++++++++++++++++++
 arch/arm/include/asm/arch-tegra/clk_rst.h |  7 +++++++
 arch/arm/include/asm/arch-tegra/clock.h   |  2 ++
 7 files changed, 81 insertions(+), 24 deletions(-)

diff --git a/arch/arm/cpu/arm720t/tegra114/cpu.c b/arch/arm/cpu/arm720t/tegra114/cpu.c
index 7a1747a3beb8..042942f61dd4 100644
--- a/arch/arm/cpu/arm720t/tegra114/cpu.c
+++ b/arch/arm/cpu/arm720t/tegra114/cpu.c
@@ -126,18 +126,6 @@ void t114_init_clocks(void)
 	/* Set active CPU cluster to G */
 	clrbits_le32(&flow->cluster_control, 1);
 
-	/*
-	 * Switch system clock to PLLP_OUT4 (108 MHz), AVP will now run
-	 * at 108 MHz. This is glitch free as only the source is changed, no
-	 * special precaution needed.
-	 */
-	val = (SCLK_SOURCE_PLLP_OUT4 << SCLK_SWAKEUP_FIQ_SOURCE_SHIFT) |
-		(SCLK_SOURCE_PLLP_OUT4 << SCLK_SWAKEUP_IRQ_SOURCE_SHIFT) |
-		(SCLK_SOURCE_PLLP_OUT4 << SCLK_SWAKEUP_RUN_SOURCE_SHIFT) |
-		(SCLK_SOURCE_PLLP_OUT4 << SCLK_SWAKEUP_IDLE_SOURCE_SHIFT) |
-		(SCLK_SYS_STATE_RUN << SCLK_SYS_STATE_SHIFT);
-	writel(val, &clkrst->crc_sclk_brst_pol);
-
 	writel(SUPER_SCLK_ENB_MASK, &clkrst->crc_super_sclk_div);
 
 	debug("Setting up PLLX\n");
diff --git a/arch/arm/cpu/arm720t/tegra30/cpu.c b/arch/arm/cpu/arm720t/tegra30/cpu.c
index e16235748449..3c50844c12be 100644
--- a/arch/arm/cpu/arm720t/tegra30/cpu.c
+++ b/arch/arm/cpu/arm720t/tegra30/cpu.c
@@ -84,18 +84,6 @@ void t30_init_clocks(void)
 	/* Set active CPU cluster to G */
 	clrbits_le32(flow->cluster_control, 1 << 0);
 
-	/*
-	 * Switch system clock to PLLP_OUT4 (108 MHz), AVP will now run
-	 * at 108 MHz. This is glitch free as only the source is changed, no
-	 * special precaution needed.
-	 */
-	val = (SCLK_SOURCE_PLLP_OUT4 << SCLK_SWAKEUP_FIQ_SOURCE_SHIFT) |
-		(SCLK_SOURCE_PLLP_OUT4 << SCLK_SWAKEUP_IRQ_SOURCE_SHIFT) |
-		(SCLK_SOURCE_PLLP_OUT4 << SCLK_SWAKEUP_RUN_SOURCE_SHIFT) |
-		(SCLK_SOURCE_PLLP_OUT4 << SCLK_SWAKEUP_IDLE_SOURCE_SHIFT) |
-		(SCLK_SYS_STATE_RUN << SCLK_SYS_STATE_SHIFT);
-	writel(val, &clkrst->crc_sclk_brst_pol);
-
 	writel(SUPER_SCLK_ENB_MASK, &clkrst->crc_super_sclk_div);
 
 	val = (0 << CLK_SYS_RATE_HCLK_DISABLE_SHIFT) |
diff --git a/arch/arm/cpu/tegra-common/clock.c b/arch/arm/cpu/tegra-common/clock.c
index 33bb19084b8c..488721cf4de3 100644
--- a/arch/arm/cpu/tegra-common/clock.c
+++ b/arch/arm/cpu/tegra-common/clock.c
@@ -575,3 +575,18 @@ void clock_init(void)
 	/* Do any special system timer/TSC setup */
 	arch_timer_init();
 }
+
+void set_avp_clock_to(u32 src)
+{
+	struct clk_rst_ctlr *clkrst =
+			(struct clk_rst_ctlr *)NV_PA_CLK_RST_BASE;
+	u32 val;
+
+	val = (src << SCLK_SWAKEUP_FIQ_SOURCE_SHIFT) |
+		(src << SCLK_SWAKEUP_IRQ_SOURCE_SHIFT) |
+		(src << SCLK_SWAKEUP_RUN_SOURCE_SHIFT) |
+		(src << SCLK_SWAKEUP_IDLE_SOURCE_SHIFT) |
+		(SCLK_SYS_STATE_RUN << SCLK_SYS_STATE_SHIFT);
+	writel(val, &clkrst->crc_sclk_brst_pol);
+	udelay(3);
+}
diff --git a/arch/arm/cpu/tegra114-common/clock.c b/arch/arm/cpu/tegra114-common/clock.c
index 3bede71a7a1f..14d1d99cfe49 100644
--- a/arch/arm/cpu/tegra114-common/clock.c
+++ b/arch/arm/cpu/tegra114-common/clock.c
@@ -603,6 +603,19 @@ void clock_early_init(void)
 {
 	struct clk_rst_ctlr *clkrst =
 		(struct clk_rst_ctlr *)NV_PA_CLK_RST_BASE;
+	u32	reg;
+
+	/*
+	 * Based on the Tegra TRM, the system clock (which is the AVP clock) can
+	 * run up to 275MHz. On power on, the default sytem clock source is set
+	 * to PLLP_OUT0. This function sets PLLP's (hence PLLP_OUT0's) rate to
+	 * 408MHz which is beyond system clock's upper limit.
+	 *
+	 * The fix is to set the system clock to CLK_M before initializing PLLP,
+	 * and then switch back to PLLP_OUT4, which has an appropriate divider
+	 * configured, after PLLP has been configured
+	 */
+	set_avp_clock_to(SCLK_SOURCE_CLKM);
 
 	/*
 	 * PLLP output frequency set to 408Mhz
@@ -637,6 +650,20 @@ void clock_early_init(void)
 		break;
 	}
 
+	/* Set PLLP_OUT3 and 4 freqs to 102MHz and 204MHz */
+	/* Assert RSTN before enable */
+	reg = PLLP_OUT4_RSTN_EN | PLLP_OUT3_RSTN_EN;
+	writel(reg, &clkrst->crc_pll[CLOCK_ID_PERIPH].pll_out[1]);
+	/* Set divisor and reenable */
+	reg = (IN_408_OUT_204_DIVISOR << PLLP_OUT4_RATIO)
+		| PLLP_OUT4_OVR | PLLP_OUT4_CLKEN | PLLP_OUT4_RSTN_DIS
+		| (IN_408_OUT_102_DIVISOR << PLLP_OUT3_RATIO)
+		| PLLP_OUT3_OVR | PLLP_OUT3_CLKEN | PLLP_OUT3_RSTN_DIS;
+	writel(reg, &clkrst->crc_pll[CLOCK_ID_PERIPH].pll_out[1]);
+	udelay(3);
+
+	set_avp_clock_to(SCLK_SOURCE_PLLP_OUT4);
+
 	/* PLLC_MISC2: Set dynramp_stepA/B. MISC2 maps to pll_out[1] */
 	writel(0x00561600, &clkrst->crc_pll[CLOCK_ID_CGENERAL].pll_out[1]);
 
diff --git a/arch/arm/cpu/tegra30-common/clock.c b/arch/arm/cpu/tegra30-common/clock.c
index 33528702185e..c06c3c7a0acc 100644
--- a/arch/arm/cpu/tegra30-common/clock.c
+++ b/arch/arm/cpu/tegra30-common/clock.c
@@ -581,6 +581,22 @@ enum periph_id clk_id_to_periph_id(int clk_id)
 
 void clock_early_init(void)
 {
+	struct clk_rst_ctlr *clkrst =
+		(struct clk_rst_ctlr *)NV_PA_CLK_RST_BASE;
+	u32	reg;
+
+	/*
+	 * Based on the Tegra TRM, the system clock (which is the AVP clock) can
+	 * run up to 275MHz. On power on, the default sytem clock source is set
+	 * to PLLP_OUT0. This function sets PLLP's (hence PLLP_OUT0's) rate to
+	 * 408MHz which is beyond system clock's upper limit.
+	 *
+	 * The fix is to set the system clock to CLK_M before initializing PLLP,
+	 * and then switch back to PLLP_OUT4, which has an appropriate divider
+	 * configured, after PLLP has been configured
+	 */
+	set_avp_clock_to(SCLK_SOURCE_CLKM);
+
 	/*
 	 * PLLP output frequency set to 408Mhz
 	 * PLLC output frequency set to 228Mhz
@@ -609,6 +625,20 @@ void clock_early_init(void)
 		 */
 		break;
 	}
+
+	/* Set PLLP_OUT3 and 4 freqs to 102MHz and 204MHz */
+	/* Assert RSTN before enable */
+	reg = PLLP_OUT4_RSTN_EN | PLLP_OUT3_RSTN_EN;
+	writel(reg, &clkrst->crc_pll[CLOCK_ID_PERIPH].pll_out[1]);
+	/* Set divisor and reenable */
+	reg = (IN_408_OUT_204_DIVISOR << PLLP_OUT4_RATIO)
+		| PLLP_OUT4_OVR | PLLP_OUT4_CLKEN | PLLP_OUT4_RSTN_DIS
+		| (IN_408_OUT_102_DIVISOR << PLLP_OUT3_RATIO)
+		| PLLP_OUT3_OVR | PLLP_OUT3_CLKEN | PLLP_OUT3_RSTN_DIS;
+	writel(reg, &clkrst->crc_pll[CLOCK_ID_PERIPH].pll_out[1]);
+	udelay(3);
+
+	set_avp_clock_to(SCLK_SOURCE_PLLP_OUT4);
 }
 
 void arch_timer_init(void)
diff --git a/arch/arm/include/asm/arch-tegra/clk_rst.h b/arch/arm/include/asm/arch-tegra/clk_rst.h
index f07b83d26af4..21f353994870 100644
--- a/arch/arm/include/asm/arch-tegra/clk_rst.h
+++ b/arch/arm/include/asm/arch-tegra/clk_rst.h
@@ -209,6 +209,13 @@ enum {
 	IN_408_OUT_9_6_DIVISOR = 83,
 };
 
+#define PLLP_OUT3_RSTN_DIS	(1 << 0)
+#define PLLP_OUT3_RSTN_EN	(0 << 0)
+#define PLLP_OUT3_CLKEN		(1 << 1)
+#define PLLP_OUT4_RSTN_DIS	(1 << 16)
+#define PLLP_OUT4_RSTN_EN	(0 << 16)
+#define PLLP_OUT4_CLKEN		(1 << 17)
+
 /* CLK_RST_CONTROLLER_UTMIP_PLL_CFG1_0 */
 #define PLLU_POWERDOWN		(1 << 16)
 #define PLL_ENABLE_POWERDOWN	(1 << 14)
diff --git a/arch/arm/include/asm/arch-tegra/clock.h b/arch/arm/include/asm/arch-tegra/clock.h
index 357d9c592b55..c579e3099a08 100644
--- a/arch/arm/include/asm/arch-tegra/clock.h
+++ b/arch/arm/include/asm/arch-tegra/clock.h
@@ -320,4 +320,6 @@ int clock_set_rate(enum clock_id clkid, u32 n, u32 m, u32 p, u32 cpcon);
 /* SoC-specific TSC init */
 void arch_timer_init(void);
 
+void set_avp_clock_to(u32 src);
+
 #endif  /* _TEGRA_CLOCK_H_ */
-- 
1.8.1.5



More information about the U-Boot mailing list