[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