Skip to contentSkip to conversation

armv8: Make COUNTER_FREQUENCY optional

PATCH New Thierry Reding 3 participants 11 messages Aug 20, 2015 – Aug 27, 2015

Subsystems (3)
lore
Share & tools
lore
#0 lore raw

PATCH 1/6 armv8: Make COUNTER_FREQUENCY optional

From: Thierry Reding <[email protected]>

Some platforms have the means to determine the counter frequency at runtime, so give them an opportunity to do so.

---
 arch/arm/cpu/armv8/start.S | 2 ++
 1 file changed, 2 insertions(+)
arch/arm/cpu/armv8/start.S +2 -0
index e70bed462a59..da45d984d01a 100644
@@ -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
Signature · 1 line
2.4.5
#1 lore raw

PATCH 2/6 ARM: tegra: Implement clk_m

From: Thierry Reding <[email protected]>

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.

---
 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(+)
arch/arm/include/asm/arch-tegra/clock.h +3 -0
index d570d7f134a8..eb07c4a07522 100644
@@ -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.
  *
arch/arm/include/asm/arch-tegra114/clock-tables.h +1 -0
index d8fa0e1d2cee..3f910f5ae8b9 100644
@@ -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 */
arch/arm/include/asm/arch-tegra124/clock-tables.h +1 -0
index 3c67e72afe89..9466b4ffb33e 100644
@@ -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 */
 
arch/arm/include/asm/arch-tegra20/clock-tables.h +1 -0
index 894be088cde2..812e8760d0cd 100644
@@ -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,
arch/arm/include/asm/arch-tegra210/clock-tables.h +1 -0
index 175040dae618..a612485d8e23 100644
@@ -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 */
 
arch/arm/include/asm/arch-tegra30/clock-tables.h +1 -0
index cb619f1f2d61..f7c7af80faaf 100644
@@ -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 */
arch/arm/mach-tegra/clock.c +10 -0
index f9dfcd04115a..41e7de95a2e3 100644
@@ -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]);
arch/arm/mach-tegra/tegra210/clock.c +11 -0
index 830a33ffc938..146bb6453a19 100644
@@ -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;
Signature · 1 line
2.4.5
#2 lore raw

PATCH 2/6 ARM: tegra: Implement clk_m

Quoted 12 lines · Thierry Reding

From: Thierry Reding <[email protected]>

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.

arch/arm/include/asm/arch-tegra114/clock-tables.h +0 -0
index d8fa0e1d2cee..3f910f5ae8b9 100644

arch/arm/include/asm/arch-tegra114/clock-tables.h enum clock_id { · line 44

Quoted 7 lines
arch/arm/include/asm/arch-tegra114/clock-tables.h +1 -0
@@ -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.

#3 lore raw

PATCH 2/6 ARM: tegra: Implement clk_m

Stephen/Thierry,

Quoted 27 lines

-----Original Message-----
From: Stephen Warren [mailto:swarren at wwwdotorg.org]
Sent: Thursday, August 20, 2015 7:59 AM
To: Thierry Reding
Cc: Albert Aribaud; Tom Warren; u-boot at lists.denx.de; Stephen Warren
Subject: Re: [U-Boot] [PATCH 2/6] ARM: tegra: Implement clk_m

Quoted 6 lines · Thierry Reding

From: Thierry Reding <[email protected]>

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.

Quoted 11 lines
arch/arm/include/asm/arch-tegra114/clock-tables.h +1 -0
index d8fa0e1d2cee..3f910f5ae8b9 100644
@@ -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,
 
Quoted 7 lines

arch/arm/include/asm/arch-tegra114/clock-tables.h enum clock_id { · line 44

Quoted 2 lines
arch/arm/include/asm/arch-tegra114/clock-tables.h +0 -0
  	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

Quoted 3 lines

... which would need to be updated. Related, see internal bug number 1676978 to see if any of the other gotchas there affect this patch.

#4 lore raw

PATCH 2/6 ARM: tegra: Implement clk_m

In reply to Stephen Warren
Quoted 45 lines

-----Original Message-----
From: Tom Warren
Sent: Thursday, August 20, 2015 9:20 AM
To: 'Stephen Warren'; Thierry Reding
Cc: Albert Aribaud; u-boot at lists.denx.de; Stephen Warren
Subject: RE: [U-Boot] [PATCH 2/6] ARM: tegra: Implement clk_m

Stephen/Thierry,

Quoted 28 lines

-----Original Message-----
From: Stephen Warren [mailto:swarren at wwwdotorg.org]
Sent: Thursday, August 20, 2015 7:59 AM
To: Thierry Reding
Cc: Albert Aribaud; Tom Warren; u-boot at lists.denx.de; Stephen Warren
Subject: Re: [U-Boot] [PATCH 2/6] ARM: tegra: Implement clk_m

Quoted 7 lines · Thierry Reding

From: Thierry Reding <[email protected]>

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.

Quoted 11 lines
arch/arm/include/asm/arch-tegra114/clock-tables.h +1 -0
index d8fa0e1d2cee..3f910f5ae8b9 100644
@@ -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,
 
Quoted 7 lines

arch/arm/include/asm/arch-tegra114/clock-tables.h enum clock_id { · line 44

Quoted 2 lines
arch/arm/include/asm/arch-tegra114/clock-tables.h +0 -0
  	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)

Quoted 10 lines

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

Quoted 4 lines
Quoted 4 lines

... which would need to be updated. Related, see internal bug number 1676978 to see if any of the other gotchas there affect this patch.

#5 lore raw

PATCH 3/6 ARM: tegra: clk_m is the architected timer source clock

In reply to Thierry Reding

From: Thierry Reding <[email protected]>

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.

---
 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(-)
arch/arm/mach-tegra/tegra114/clock.c +2 -2
index 5e805a7baf03..cec843b27df7 100644
@@ -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));
arch/arm/mach-tegra/tegra124/clock.c +2 -2
index 61e8ab7053fd..aa046e8950f7 100644
@@ -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));
arch/arm/mach-tegra/tegra210/clock.c +4 -6
index 146bb6453a19..6d75d371cb03 100644
@@ -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);
Signature · 1 line
2.4.5
#6 lore raw

PATCH 4/6 e2220-1170: Remove hard-coded counter frequency

In reply to Thierry Reding

From: Thierry Reding <[email protected]>

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/e2220-1170.h | 2 --
 1 file changed, 2 deletions(-)
include/configs/e2220-1170.h +0 -2
index dff3f2a35733..47d491f05078 100644
@@ -60,6 +60,4 @@
 #include "tegra-common-usb-gadget.h"
 #include "tegra-common-post.h"
 
-#define COUNTER_FREQUENCY	38400000
-
 #endif /* _E2220_1170_H */
Signature · 1 line
2.4.5
#7 lore raw

PATCH 5/6 p2371: Remove hard-coded counter frequency

In reply to Thierry Reding

From: Thierry Reding <[email protected]>

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 --
 1 file changed, 2 deletions(-)
include/configs/p2371-0000.h +0 -2
index 9d7b650d98ca..e190733357b5 100644
@@ -60,6 +60,4 @@
 #include "tegra-common-usb-gadget.h"
 #include "tegra-common-post.h"
 
-#define COUNTER_FREQUENCY	38400000
-
 #endif /* _P2371_0000_H */
Signature · 1 line
2.4.5
#8 lore raw

PATCH 5/6 p2371: Remove hard-coded counter frequency

Quoted 9 lines · Thierry Reding

From: Thierry Reding <[email protected]>

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?

#9 lore raw

PATCH 6/6 p2571: Remove hard-coded counter frequency

In reply to Thierry Reding

From: Thierry Reding <[email protected]>

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/p2571.h | 1 -
 1 file changed, 1 deletion(-)
include/configs/p2571.h +0 -1
index 356c941a773f..87abee603dc1 100644
@@ -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 */
Signature · 1 line
2.4.5
#10 lore raw

PATCH 1/6 armv8: Make COUNTER_FREQUENCY optional

In reply to Thierry Reding
Quoted 4 lines · Thierry Reding

From: Thierry Reding <[email protected]>

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,

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.