[U-Boot] [PATCH 1/6] armv8: Make COUNTER_FREQUENCY optional

From: Thierry Reding treding@nvidia.com
Some platforms have the means to determine the counter frequency at runtime, so give them an opportunity to do so.
Signed-off-by: Thierry Reding treding@nvidia.com --- arch/arm/cpu/armv8/start.S | 2 ++ 1 file changed, 2 insertions(+)
diff --git a/arch/arm/cpu/armv8/start.S b/arch/arm/cpu/armv8/start.S index e70bed462a59..da45d984d01a 100644 --- a/arch/arm/cpu/armv8/start.S +++ b/arch/arm/cpu/armv8/start.S @@ -54,8 +54,10 @@ reset: orr x0, x0, #0xf /* SCR_EL3.NS|IRQ|FIQ|EA */ msr scr_el3, x0 msr cptr_el3, xzr /* Enable FP/SIMD */ +#ifdef COUNTER_FREQUENCY ldr x0, =COUNTER_FREQUENCY msr cntfrq_el0, x0 /* Initialize CNTFRQ */ +#endif b 0f 2: msr vbar_el2, x0 mov x0, #0x33ff

From: Thierry Reding treding@nvidia.com
On currently supported SoCs, clk_m always runs at the same frequency as the oscillator input. However newer SoC generations such as Tegra210 no longer have that restriction. Prepare for that by separating clk_m from the oscillator clock and allow SoC code to override the clk_m rate.
Signed-off-by: Thierry Reding treding@nvidia.com --- arch/arm/include/asm/arch-tegra/clock.h | 3 +++ arch/arm/include/asm/arch-tegra114/clock-tables.h | 1 + arch/arm/include/asm/arch-tegra124/clock-tables.h | 1 + arch/arm/include/asm/arch-tegra20/clock-tables.h | 1 + arch/arm/include/asm/arch-tegra210/clock-tables.h | 1 + arch/arm/include/asm/arch-tegra30/clock-tables.h | 1 + arch/arm/mach-tegra/clock.c | 10 ++++++++++ arch/arm/mach-tegra/tegra210/clock.c | 11 +++++++++++ 8 files changed, 29 insertions(+)
diff --git a/arch/arm/include/asm/arch-tegra/clock.h b/arch/arm/include/asm/arch-tegra/clock.h index d570d7f134a8..eb07c4a07522 100644 --- a/arch/arm/include/asm/arch-tegra/clock.h +++ b/arch/arm/include/asm/arch-tegra/clock.h @@ -44,6 +44,9 @@ enum { /* return the current oscillator clock frequency */ enum clock_osc_freq clock_get_osc_freq(void);
+/* return the clk_m frequency */ +unsigned int clk_m_get_rate(unsigned int parent_rate); + /** * Start PLL using the provided configuration parameters. * diff --git a/arch/arm/include/asm/arch-tegra114/clock-tables.h b/arch/arm/include/asm/arch-tegra114/clock-tables.h index d8fa0e1d2cee..3f910f5ae8b9 100644 --- a/arch/arm/include/asm/arch-tegra114/clock-tables.h +++ b/arch/arm/include/asm/arch-tegra114/clock-tables.h @@ -38,6 +38,7 @@ enum clock_id { /* These are the base clocks (inputs to the Tegra SOC) */ CLOCK_ID_32KHZ, CLOCK_ID_OSC, + CLOCK_ID_CLK_M,
CLOCK_ID_COUNT, /* number of PLLs */ CLOCK_ID_DISPLAY2, /* placeholder */ diff --git a/arch/arm/include/asm/arch-tegra124/clock-tables.h b/arch/arm/include/asm/arch-tegra124/clock-tables.h index 3c67e72afe89..9466b4ffb33e 100644 --- a/arch/arm/include/asm/arch-tegra124/clock-tables.h +++ b/arch/arm/include/asm/arch-tegra124/clock-tables.h @@ -30,6 +30,7 @@ enum clock_id { /* These are the base clocks (inputs to the Tegra SoC) */ CLOCK_ID_32KHZ, CLOCK_ID_OSC, + CLOCK_ID_CLK_M,
CLOCK_ID_COUNT, /* number of PLLs */
diff --git a/arch/arm/include/asm/arch-tegra20/clock-tables.h b/arch/arm/include/asm/arch-tegra20/clock-tables.h index 894be088cde2..812e8760d0cd 100644 --- a/arch/arm/include/asm/arch-tegra20/clock-tables.h +++ b/arch/arm/include/asm/arch-tegra20/clock-tables.h @@ -29,6 +29,7 @@ enum clock_id { /* These are the base clocks (inputs to the Tegra SOC) */ CLOCK_ID_32KHZ, CLOCK_ID_OSC, + CLOCK_ID_CLK_M,
CLOCK_ID_COUNT, /* number of clocks */ CLOCK_ID_NONE = -1, diff --git a/arch/arm/include/asm/arch-tegra210/clock-tables.h b/arch/arm/include/asm/arch-tegra210/clock-tables.h index 175040dae618..a612485d8e23 100644 --- a/arch/arm/include/asm/arch-tegra210/clock-tables.h +++ b/arch/arm/include/asm/arch-tegra210/clock-tables.h @@ -30,6 +30,7 @@ enum clock_id { /* These are the base clocks (inputs to the Tegra SoC) */ CLOCK_ID_32KHZ, CLOCK_ID_OSC, + CLOCK_ID_CLK_M,
CLOCK_ID_COUNT, /* number of PLLs */
diff --git a/arch/arm/include/asm/arch-tegra30/clock-tables.h b/arch/arm/include/asm/arch-tegra30/clock-tables.h index cb619f1f2d61..f7c7af80faaf 100644 --- a/arch/arm/include/asm/arch-tegra30/clock-tables.h +++ b/arch/arm/include/asm/arch-tegra30/clock-tables.h @@ -38,6 +38,7 @@ enum clock_id { /* These are the base clocks (inputs to the Tegra SOC) */ CLOCK_ID_32KHZ, CLOCK_ID_OSC, + CLOCK_ID_CLK_M,
CLOCK_ID_COUNT, /* number of PLLs */ CLOCK_ID_DISPLAY2, /* Tegra3, placeholder */ diff --git a/arch/arm/mach-tegra/clock.c b/arch/arm/mach-tegra/clock.c index f9dfcd04115a..41e7de95a2e3 100644 --- a/arch/arm/mach-tegra/clock.c +++ b/arch/arm/mach-tegra/clock.c @@ -461,6 +461,11 @@ void reset_cmplx_set_enable(int cpu, int which, int reset) writel(mask, &clkrst->crc_cpu_cmplx_clr); }
+unsigned int __weak clk_m_get_rate(unsigned int parent_rate) +{ + return parent_rate; +} + unsigned clock_get_rate(enum clock_id clkid) { struct clk_pll *pll; @@ -472,6 +477,9 @@ unsigned clock_get_rate(enum clock_id clkid) if (clkid == CLOCK_ID_OSC) return parent_rate;
+ if (clkid == CLOCK_ID_CLK_M) + return clk_m_get_rate(parent_rate); + pll = get_pll(clkid); if (!pll) return 0; @@ -613,8 +621,10 @@ void clock_init(void) pll_rate[CLOCK_ID_XCPU] = clock_get_rate(CLOCK_ID_XCPU); pll_rate[CLOCK_ID_SFROM32KHZ] = 32768; pll_rate[CLOCK_ID_OSC] = clock_get_rate(CLOCK_ID_OSC); + pll_rate[CLOCK_ID_CLK_M] = clock_get_rate(CLOCK_ID_CLK_M);
debug("Osc = %d\n", pll_rate[CLOCK_ID_OSC]); + debug("CLKM = %d\n", pll_rate[CLOCK_ID_CLK_M]); debug("PLLC = %d\n", pll_rate[CLOCK_ID_CGENERAL]); debug("PLLM = %d\n", pll_rate[CLOCK_ID_MEMORY]); debug("PLLP = %d\n", pll_rate[CLOCK_ID_PERIPH]); diff --git a/arch/arm/mach-tegra/tegra210/clock.c b/arch/arm/mach-tegra/tegra210/clock.c index 830a33ffc938..146bb6453a19 100644 --- a/arch/arm/mach-tegra/tegra210/clock.c +++ b/arch/arm/mach-tegra/tegra210/clock.c @@ -998,6 +998,17 @@ void clock_early_init(void) udelay(2); }
+unsigned int clk_m_get_rate(unsigned parent_rate) +{ + struct clk_rst_ctlr *clkrst = (struct clk_rst_ctlr *)NV_PA_CLK_RST_BASE; + u32 value, div; + + value = readl(&clkrst->crc_spare_reg0); + div = ((value >> 2) & 0x3) + 1; + + return parent_rate / div; +} + void arch_timer_init(void) { struct sysctr_ctlr *sysctr = (struct sysctr_ctlr *)NV_PA_TSC_BASE;

On 08/20/2015 03:42 AM, Thierry Reding wrote:
From: Thierry Reding treding@nvidia.com
On currently supported SoCs, clk_m always runs at the same frequency as the oscillator input. However newer SoC generations such as Tegra210 no longer have that restriction. Prepare for that by separating clk_m from the oscillator clock and allow SoC code to override the clk_m rate.
diff --git a/arch/arm/include/asm/arch-tegra114/clock-tables.h b/arch/arm/include/asm/arch-tegra114/clock-tables.h index d8fa0e1d2cee..3f910f5ae8b9 100644 --- a/arch/arm/include/asm/arch-tegra114/clock-tables.h +++ b/arch/arm/include/asm/arch-tegra114/clock-tables.h @@ -38,6 +38,7 @@ enum clock_id { /* These are the base clocks (inputs to the Tegra SOC) */ CLOCK_ID_32KHZ, CLOCK_ID_OSC,
CLOCK_ID_CLK_M,
CLOCK_ID_COUNT, /* number of PLLs */ CLOCK_ID_DISPLAY2, /* placeholder */
clock.h contains the following:
/* Number of PLL-based clocks (i.e. not OSC or 32KHz) */ #define CLOCK_ID_PLL_COUNT (CLOCK_ID_COUNT - 2)
... which would need to be updated. Related, see internal bug number 1676978 to see if any of the other gotchas there affect this patch.

Stephen/Thierry,
-----Original Message----- From: Stephen Warren [mailto:swarren@wwwdotorg.org] Sent: Thursday, August 20, 2015 7:59 AM To: Thierry Reding Cc: Albert Aribaud; Tom Warren; u-boot@lists.denx.de; Stephen Warren Subject: Re: [U-Boot] [PATCH 2/6] ARM: tegra: Implement clk_m
On 08/20/2015 03:42 AM, Thierry Reding wrote:
From: Thierry Reding treding@nvidia.com
On currently supported SoCs, clk_m always runs at the same frequency as the oscillator input. However newer SoC generations such as Tegra210 no longer have that restriction. Prepare for that by separating clk_m from the oscillator clock and allow SoC code to override
the clk_m rate.
diff --git a/arch/arm/include/asm/arch-tegra114/clock-tables.h b/arch/arm/include/asm/arch-tegra114/clock-tables.h index d8fa0e1d2cee..3f910f5ae8b9 100644 --- a/arch/arm/include/asm/arch-tegra114/clock-tables.h +++ b/arch/arm/include/asm/arch-tegra114/clock-tables.h @@ -38,6 +38,7 @@ enum clock_id { /* These are the base clocks (inputs to the Tegra SOC) */ CLOCK_ID_32KHZ, CLOCK_ID_OSC,
CLOCK_ID_CLK_M,
CLOCK_ID_COUNT, /* number of PLLs */ CLOCK_ID_DISPLAY2, /* placeholder */
clock.h contains the following:
/* Number of PLL-based clocks (i.e. not OSC or 32KHz) */ #define CLOCK_ID_PLL_COUNT (CLOCK_ID_COUNT - 2)
I decremented the CLOCK_ID_COUNT for my pllinfo tables, since 32KHZ and OSC have no PLL params that can be configured, to remove the 2 extra, empty table entries. We can either remove it, and add 2 empty entries for OSC/32KHZ in all the pllinfo tables (per SoC), and then add new CLOCK_ID entries wherever, or have a rule that new entries here need to be above ID_32KHZ for any PLL needing dividers, etc., and below it for any static clock like OSC, 32KHz, etc. Of course, we'll need to keep track of the decrement depending on how many IDs are added and where. Might be easier to just have an entry for every CLOCK_ID, regardless.
Tom -- nvpublic
... which would need to be updated. Related, see internal bug number 1676978 to see if any of the other gotchas there affect this patch.

-----Original Message----- From: Tom Warren Sent: Thursday, August 20, 2015 9:20 AM To: 'Stephen Warren'; Thierry Reding Cc: Albert Aribaud; u-boot@lists.denx.de; Stephen Warren Subject: RE: [U-Boot] [PATCH 2/6] ARM: tegra: Implement clk_m
Stephen/Thierry,
-----Original Message----- From: Stephen Warren [mailto:swarren@wwwdotorg.org] Sent: Thursday, August 20, 2015 7:59 AM To: Thierry Reding Cc: Albert Aribaud; Tom Warren; u-boot@lists.denx.de; Stephen Warren Subject: Re: [U-Boot] [PATCH 2/6] ARM: tegra: Implement clk_m
On 08/20/2015 03:42 AM, Thierry Reding wrote:
From: Thierry Reding treding@nvidia.com
On currently supported SoCs, clk_m always runs at the same frequency as the oscillator input. However newer SoC generations such as Tegra210 no longer have that restriction. Prepare for that by separating clk_m from the oscillator clock and allow SoC code to override
the clk_m rate.
diff --git a/arch/arm/include/asm/arch-tegra114/clock-tables.h b/arch/arm/include/asm/arch-tegra114/clock-tables.h index d8fa0e1d2cee..3f910f5ae8b9 100644 --- a/arch/arm/include/asm/arch-tegra114/clock-tables.h +++ b/arch/arm/include/asm/arch-tegra114/clock-tables.h @@ -38,6 +38,7 @@ enum clock_id { /* These are the base clocks (inputs to the Tegra SOC) */ CLOCK_ID_32KHZ, CLOCK_ID_OSC,
CLOCK_ID_CLK_M,
CLOCK_ID_COUNT, /* number of PLLs */ CLOCK_ID_DISPLAY2, /* placeholder */
clock.h contains the following:
/* Number of PLL-based clocks (i.e. not OSC or 32KHz) */ #define CLOCK_ID_PLL_COUNT (CLOCK_ID_COUNT - 2)
I decremented the CLOCK_ID_COUNT for my pllinfo tables, since 32KHZ and OSC have no PLL params that can be configured, to remove the 2 extra, empty table entries. We can either remove it, and add 2 empty entries for OSC/32KHZ in all the pllinfo tables (per SoC), and then add new CLOCK_ID entries wherever, or have a rule that new entries here need to be above ID_32KHZ for any PLL needing dividers, etc., and below it for any static clock like OSC, 32KHz, etc. Of course, we'll need to keep track of the decrement depending on how many IDs are added and where. Might be easier to just have an entry for every CLOCK_ID, regardless.
I applied Thierry's patchset and found that adding CLK_M to the CLOCK_ID tables results in an extra empty pll_info_table entry (3 32-bit words) for each SoC.
So I can leave it as-is, or I can adjust CLOCK_ID_PLL_COUNT in clock.h to be CLOCK_ID_COUNT - 3 to account for the 3 non-configurable clocks (OSC, 32KHz and MCLK), and there'll be no extra empty data in the pll_info tables.
I'm going to go with the 2nd approach. I've applied these (plus some from Stephen and one from Axel Lin) to u-boot-tegra/next and after some testing today I'll be pushing this to Denx for everyone to play with it before I send a PR to TomR. So PTAL.
Thanks
Tom -- nvpublic
... which would need to be updated. Related, see internal bug number 1676978 to see if any of the other gotchas there affect this patch.

From: Thierry Reding treding@nvidia.com
While clk_m and the oscillator run at the same frequencies on Tegra114 and Tegra124, clk_m is the proper source for the architected timer. On more recent Tegra generations, Tegra210 and later, both the oscillator and clk_m can run at different frequencies. clk_m will be divided down from the oscillator.
Signed-off-by: Thierry Reding treding@nvidia.com --- arch/arm/mach-tegra/tegra114/clock.c | 4 ++-- arch/arm/mach-tegra/tegra124/clock.c | 4 ++-- arch/arm/mach-tegra/tegra210/clock.c | 10 ++++------ 3 files changed, 8 insertions(+), 10 deletions(-)
diff --git a/arch/arm/mach-tegra/tegra114/clock.c b/arch/arm/mach-tegra/tegra114/clock.c index 5e805a7baf03..cec843b27df7 100644 --- a/arch/arm/mach-tegra/tegra114/clock.c +++ b/arch/arm/mach-tegra/tegra114/clock.c @@ -679,8 +679,8 @@ void arch_timer_init(void) struct sysctr_ctlr *sysctr = (struct sysctr_ctlr *)NV_PA_TSC_BASE; u32 freq, val;
- freq = clock_get_rate(CLOCK_ID_OSC); - debug("%s: osc freq is %dHz [0x%08X]\n", __func__, freq, freq); + freq = clock_get_rate(CLOCK_ID_CLK_M); + debug("%s: clk_m freq is %dHz [0x%08X]\n", __func__, freq, freq);
/* ARM CNTFRQ */ asm("mcr p15, 0, %0, c14, c0, 0\n" : : "r" (freq)); diff --git a/arch/arm/mach-tegra/tegra124/clock.c b/arch/arm/mach-tegra/tegra124/clock.c index 61e8ab7053fd..aa046e8950f7 100644 --- a/arch/arm/mach-tegra/tegra124/clock.c +++ b/arch/arm/mach-tegra/tegra124/clock.c @@ -859,8 +859,8 @@ void arch_timer_init(void) struct sysctr_ctlr *sysctr = (struct sysctr_ctlr *)NV_PA_TSC_BASE; u32 freq, val;
- freq = clock_get_rate(CLOCK_ID_OSC); - debug("%s: osc freq is %dHz [0x%08X]\n", __func__, freq, freq); + freq = clock_get_rate(CLOCK_ID_CLK_M); + debug("%s: clk_m freq is %dHz [0x%08X]\n", __func__, freq, freq);
/* ARM CNTFRQ */ asm("mcr p15, 0, %0, c14, c0, 0\n" : : "r" (freq)); diff --git a/arch/arm/mach-tegra/tegra210/clock.c b/arch/arm/mach-tegra/tegra210/clock.c index 146bb6453a19..6d75d371cb03 100644 --- a/arch/arm/mach-tegra/tegra210/clock.c +++ b/arch/arm/mach-tegra/tegra210/clock.c @@ -1014,13 +1014,11 @@ void arch_timer_init(void) struct sysctr_ctlr *sysctr = (struct sysctr_ctlr *)NV_PA_TSC_BASE; u32 freq, val;
- freq = clock_get_rate(CLOCK_ID_OSC); - debug("%s: osc freq is %dHz [0x%08X]\n", __func__, freq, freq); + freq = clock_get_rate(CLOCK_ID_CLK_M); + debug("%s: clk_m freq is %dHz [0x%08X]\n", __func__, freq, freq);
- /* ARM CNTFRQ */ -#ifndef CONFIG_ARM64 - asm("mcr p15, 0, %0, c14, c0, 0\n" : : "r" (freq)); -#endif + if (current_el() == 3) + asm("msr cntfrq_el0, %0\n" : : "r" (freq));
/* Only Tegra114+ has the System Counter regs */ debug("%s: setting CNTFID0 to 0x%08X\n", __func__, freq);

From: Thierry Reding treding@nvidia.com
The counter frequency is derived from clk_m on Tegra, but that clock can be configured by the primary bootloader to run at the same frequency as the oscillator (38.4 MHz on Tegra210) or a divided down frequency (most typically 19.2 MHz). Remove the hard-coded frequency and allow the timer setup code to query the correct value at runtime.
Signed-off-by: Thierry Reding treding@nvidia.com --- include/configs/e2220-1170.h | 2 -- 1 file changed, 2 deletions(-)
diff --git a/include/configs/e2220-1170.h b/include/configs/e2220-1170.h index dff3f2a35733..47d491f05078 100644 --- a/include/configs/e2220-1170.h +++ b/include/configs/e2220-1170.h @@ -60,6 +60,4 @@ #include "tegra-common-usb-gadget.h" #include "tegra-common-post.h"
-#define COUNTER_FREQUENCY 38400000 - #endif /* _E2220_1170_H */

From: Thierry Reding treding@nvidia.com
The counter frequency is derived from clk_m on Tegra, but that clock can be configured by the primary bootloader to run at the same frequency as the oscillator (38.4 MHz on Tegra210) or a divided down frequency (most typically 19.2 MHz). Remove the hard-coded frequency and allow the timer setup code to query the correct value at runtime.
Signed-off-by: Thierry Reding treding@nvidia.com --- include/configs/p2371-0000.h | 2 -- 1 file changed, 2 deletions(-)
diff --git a/include/configs/p2371-0000.h b/include/configs/p2371-0000.h index 9d7b650d98ca..e190733357b5 100644 --- a/include/configs/p2371-0000.h +++ b/include/configs/p2371-0000.h @@ -60,6 +60,4 @@ #include "tegra-common-usb-gadget.h" #include "tegra-common-post.h"
-#define COUNTER_FREQUENCY 38400000 - #endif /* _P2371_0000_H */

On 08/20/2015 03:42 AM, Thierry Reding wrote:
From: Thierry Reding treding@nvidia.com
The counter frequency is derived from clk_m on Tegra, but that clock can be configured by the primary bootloader to run at the same frequency as the oscillator (38.4 MHz on Tegra210) or a divided down frequency (most typically 19.2 MHz). Remove the hard-coded frequency and allow the timer setup code to query the correct value at runtime.
include/configs/p2371-0000.h | 2 --
Oh, there needs to be a patch for p2371-2180.h too. Perhaps just patch all 4 boards in one go?

From: Thierry Reding treding@nvidia.com
The counter frequency is derived from clk_m on Tegra, but that clock can be configured by the primary bootloader to run at the same frequency as the oscillator (38.4 MHz on Tegra210) or a divided down frequency (most typically 19.2 MHz). Remove the hard-coded frequency and allow the timer setup code to query the correct value at runtime.
Signed-off-by: Thierry Reding treding@nvidia.com --- include/configs/p2571.h | 1 - 1 file changed, 1 deletion(-)
diff --git a/include/configs/p2571.h b/include/configs/p2571.h index 356c941a773f..87abee603dc1 100644 --- a/include/configs/p2571.h +++ b/include/configs/p2571.h @@ -61,7 +61,6 @@ #include "tegra-common-usb-gadget.h" #include "tegra-common-post.h"
-#define COUNTER_FREQUENCY 38400000 #define CONFIG_OF_BOARD_SETUP
#endif /* _P2571_H */

On 08/20/2015 03:42 AM, Thierry Reding wrote:
From: Thierry Reding treding@nvidia.com
Some platforms have the means to determine the counter frequency at runtime, so give them an opportunity to do so.
Aside from the one comment I already made, the series,
Acked-by: Stephen Warren swarren@nvidia.com Tested-by: Stephen Warren swarren@nvidia.com
I validated that the calculated clk_m rate is correct on p2371-2180 when booted under L4T's nvtboot. I didn't validate the programming of cntfrq_el0, since I'm booting at EL2 not EL3. Still, that part is trivial and the same code as in start.S.
Tom, this series would replace my patch "ARM: tegra: fix COUNTER_FREQUENCY for T210". Or perhaps apply my patch then fix up the minor conflicts when applying this series. That would at least document the fact that COUNTER_FREQUENCY was wrong in all the initial header files, in case someone looks back at old git versions.
participants (3)
-
Stephen Warren
-
Thierry Reding
-
Tom Warren