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

From: Jimmy Zhang jimmzhang@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@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@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_ */

On 01/22/2014 01:21 PM, Stephen Warren wrote:
From: Jimmy Zhang jimmzhang@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@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]
I think I need to revise this one patch; while going through the Tegra124 patches, I found function adjust_pllp_out_freqs(), which really should be used by this patch.
participants (1)
-
Stephen Warren