ARM: tegra: don't exceed AVP limits when configuring PLLP

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. 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

Implement this logic in new function tegra30_set_up_pllp(),
which sets up PLLP and all PLLP_OUT* dividers, and handles the AVP
clock switching. Remove the duplicate PLLP setup from pllx_set_rate()
and adjust_pllp_out_freqs().

Signed-off-by: Jimmy Zhang <jimmzhang@nvidia.com>
[swarren, significantly refactored the change]
Signed-off-by: Stephen Warren <swarren@nvidia.com>
Reviewed-by: Thierry Reding <treding@nvidia.com>
Tested-by: Thierry Reding <treding@nvidia.com>
Acked-by: Thierry Reding <treding@nvidia.com>
Signed-off-by: Tom Warren <twarren@nvidia.com>
master
Jimmy Zhang 11 years ago committed by Tom Warren
parent 9399e540ca
commit b9dd6215ce
  1. 26
      arch/arm/cpu/arm720t/tegra-common/cpu.c
  2. 14
      arch/arm/cpu/arm720t/tegra114/cpu.c
  3. 14
      arch/arm/cpu/arm720t/tegra30/cpu.c
  4. 94
      arch/arm/cpu/tegra-common/clock.c
  5. 8
      arch/arm/cpu/tegra114-common/clock.c
  6. 31
      arch/arm/cpu/tegra30-common/clock.c
  7. 16
      arch/arm/include/asm/arch-tegra/clk_rst.h
  8. 2
      arch/arm/include/asm/arch-tegra/clock.h

@ -1,5 +1,5 @@
/*
* Copyright (c) 2010-2012, NVIDIA CORPORATION. All rights reserved.
* Copyright (c) 2010-2014, NVIDIA CORPORATION. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License,
@ -114,24 +114,6 @@ struct clk_pll_table tegra_pll_x_table[TEGRA_SOC_CNT][CLOCK_OSC_FREQ_COUNT] = {
},
};
void adjust_pllp_out_freqs(void)
{
struct clk_rst_ctlr *clkrst = (struct clk_rst_ctlr *)NV_PA_CLK_RST_BASE;
struct clk_pll *pll = &clkrst->crc_pll[CLOCK_ID_PERIPH];
u32 reg;
/* Set T30 PLLP_OUT1, 2, 3 & 4 freqs to 9.6, 48, 102 & 204MHz */
reg = readl(&pll->pll_out[0]); /* OUTA, contains OUT2 / OUT1 */
reg |= (IN_408_OUT_48_DIVISOR << PLLP_OUT2_RATIO) | PLLP_OUT2_OVR
| (IN_408_OUT_9_6_DIVISOR << PLLP_OUT1_RATIO) | PLLP_OUT1_OVR;
writel(reg, &pll->pll_out[0]);
reg = readl(&pll->pll_out[1]); /* OUTB, contains OUT4 / OUT3 */
reg |= (IN_408_OUT_204_DIVISOR << PLLP_OUT4_RATIO) | PLLP_OUT4_OVR
| (IN_408_OUT_102_DIVISOR << PLLP_OUT3_RATIO) | PLLP_OUT3_OVR;
writel(reg, &pll->pll_out[1]);
}
int pllx_set_rate(struct clk_pll_simple *pll , u32 divn, u32 divm,
u32 divp, u32 cpcon)
{
@ -207,12 +189,6 @@ void init_pllx(void)
/* set pllx */
sel = &tegra_pll_x_table[chip_sku][osc];
pllx_set_rate(pll, sel->n, sel->m, sel->p, sel->cpcon);
/* adjust PLLP_out1-4 on T3x/T114 */
if (soc_type >= CHIPID_TEGRA30) {
debug(" init_pllx: adjusting PLLP out freqs\n");
adjust_pllp_out_freqs();
}
}
void enable_cpu_clock(int enable)

@ -1,5 +1,5 @@
/*
* Copyright (c) 2010-2013, NVIDIA CORPORATION. All rights reserved.
* Copyright (c) 2010-2014, NVIDIA CORPORATION. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License,
@ -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");

@ -1,5 +1,5 @@
/*
* Copyright (c) 2010-2012, NVIDIA CORPORATION. All rights reserved.
* Copyright (c) 2010-2014, NVIDIA CORPORATION. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License,
@ -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) |

@ -1,5 +1,5 @@
/*
* Copyright (c) 2010-2013, NVIDIA CORPORATION. All rights reserved.
* Copyright (c) 2010-2014, NVIDIA CORPORATION. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License,
@ -575,3 +575,95 @@ void clock_init(void)
/* Do any special system timer/TSC setup */
arch_timer_init();
}
static void set_avp_clock_source(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);
}
/*
* This function is useful on Tegra30, and any later SoCs that have compatible
* PLLP configuration registers.
*/
void tegra30_set_up_pllp(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_source(SCLK_SOURCE_CLKM);
/*
* PLLP output frequency set to 408Mhz
* PLLC output frequency set to 228Mhz
*/
switch (clock_get_osc_freq()) {
case CLOCK_OSC_FREQ_12_0: /* OSC is 12Mhz */
clock_set_rate(CLOCK_ID_PERIPH, 408, 12, 0, 8);
clock_set_rate(CLOCK_ID_CGENERAL, 456, 12, 1, 8);
break;
case CLOCK_OSC_FREQ_26_0: /* OSC is 26Mhz */
clock_set_rate(CLOCK_ID_PERIPH, 408, 26, 0, 8);
clock_set_rate(CLOCK_ID_CGENERAL, 600, 26, 0, 8);
break;
case CLOCK_OSC_FREQ_13_0: /* OSC is 13Mhz */
clock_set_rate(CLOCK_ID_PERIPH, 408, 13, 0, 8);
clock_set_rate(CLOCK_ID_CGENERAL, 600, 13, 0, 8);
break;
case CLOCK_OSC_FREQ_19_2:
default:
/*
* These are not supported. It is too early to print a
* message and the UART likely won't work anyway due to the
* oscillator being wrong.
*/
break;
}
/* Set PLLP_OUT1, 2, 3 & 4 freqs to 9.6, 48, 102 & 204MHz */
/* OUT1, 2 */
/* Assert RSTN before enable */
reg = PLLP_OUT2_RSTN_EN | PLLP_OUT1_RSTN_EN;
writel(reg, &clkrst->crc_pll[CLOCK_ID_PERIPH].pll_out[0]);
/* Set divisor and reenable */
reg = (IN_408_OUT_48_DIVISOR << PLLP_OUT2_RATIO)
| PLLP_OUT2_OVR | PLLP_OUT2_CLKEN | PLLP_OUT2_RSTN_DIS
| (IN_408_OUT_9_6_DIVISOR << PLLP_OUT1_RATIO)
| PLLP_OUT1_OVR | PLLP_OUT1_CLKEN | PLLP_OUT1_RSTN_DIS;
writel(reg, &clkrst->crc_pll[CLOCK_ID_PERIPH].pll_out[0]);
/* OUT3, 4 */
/* 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]);
set_avp_clock_source(SCLK_SOURCE_PLLP_OUT4);
}

@ -1,5 +1,5 @@
/*
* Copyright (c) 2010-2013, NVIDIA CORPORATION. All rights reserved.
* Copyright (c) 2010-2014, NVIDIA CORPORATION. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License,
@ -604,26 +604,24 @@ void clock_early_init(void)
struct clk_rst_ctlr *clkrst =
(struct clk_rst_ctlr *)NV_PA_CLK_RST_BASE;
tegra30_set_up_pllp();
/*
* PLLP output frequency set to 408Mhz
* PLLC output frequency set to 600Mhz
* PLLD output frequency set to 925Mhz
*/
switch (clock_get_osc_freq()) {
case CLOCK_OSC_FREQ_12_0: /* OSC is 12Mhz */
clock_set_rate(CLOCK_ID_PERIPH, 408, 12, 0, 8);
clock_set_rate(CLOCK_ID_CGENERAL, 600, 12, 0, 8);
clock_set_rate(CLOCK_ID_DISPLAY, 925, 12, 0, 12);
break;
case CLOCK_OSC_FREQ_26_0: /* OSC is 26Mhz */
clock_set_rate(CLOCK_ID_PERIPH, 408, 26, 0, 8);
clock_set_rate(CLOCK_ID_CGENERAL, 600, 26, 0, 8);
clock_set_rate(CLOCK_ID_DISPLAY, 925, 26, 0, 12);
break;
case CLOCK_OSC_FREQ_13_0: /* OSC is 13Mhz */
clock_set_rate(CLOCK_ID_PERIPH, 408, 13, 0, 8);
clock_set_rate(CLOCK_ID_CGENERAL, 600, 13, 0, 8);
clock_set_rate(CLOCK_ID_DISPLAY, 925, 13, 0, 12);
break;

@ -1,5 +1,5 @@
/*
* Copyright (c) 2010-2013, NVIDIA CORPORATION. All rights reserved.
* Copyright (c) 2010-2014, NVIDIA CORPORATION. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License,
@ -581,34 +581,7 @@ enum periph_id clk_id_to_periph_id(int clk_id)
void clock_early_init(void)
{
/*
* PLLP output frequency set to 408Mhz
* PLLC output frequency set to 228Mhz
*/
switch (clock_get_osc_freq()) {
case CLOCK_OSC_FREQ_12_0: /* OSC is 12Mhz */
clock_set_rate(CLOCK_ID_PERIPH, 408, 12, 0, 8);
clock_set_rate(CLOCK_ID_CGENERAL, 456, 12, 1, 8);
break;
case CLOCK_OSC_FREQ_26_0: /* OSC is 26Mhz */
clock_set_rate(CLOCK_ID_PERIPH, 408, 26, 0, 8);
clock_set_rate(CLOCK_ID_CGENERAL, 600, 26, 0, 8);
break;
case CLOCK_OSC_FREQ_13_0: /* OSC is 13Mhz */
clock_set_rate(CLOCK_ID_PERIPH, 408, 13, 0, 8);
clock_set_rate(CLOCK_ID_CGENERAL, 600, 13, 0, 8);
break;
case CLOCK_OSC_FREQ_19_2:
default:
/*
* These are not supported. It is too early to print a
* message and the UART likely won't work anyway due to the
* oscillator being wrong.
*/
break;
}
tegra30_set_up_pllp();
}
void arch_timer_init(void)

@ -1,5 +1,5 @@
/*
* (C) Copyright 2010,2011
* (C) Copyright 2010-2014
* NVIDIA Corporation <www.nvidia.com>
*
* SPDX-License-Identifier: GPL-2.0+
@ -209,6 +209,20 @@ enum {
IN_408_OUT_9_6_DIVISOR = 83,
};
#define PLLP_OUT1_RSTN_DIS (1 << 0)
#define PLLP_OUT1_RSTN_EN (0 << 0)
#define PLLP_OUT1_CLKEN (1 << 1)
#define PLLP_OUT2_RSTN_DIS (1 << 16)
#define PLLP_OUT2_RSTN_EN (0 << 16)
#define PLLP_OUT2_CLKEN (1 << 17)
#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)

@ -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 tegra30_set_up_pllp(void);
#endif /* _TEGRA_CLOCK_H_ */

Loading…
Cancel
Save