Skip to contentSkip to conversation

armv8/ls2085a: Fix generic timer clock source

PATCH Superseded York Sun 2 participants 4 messages Mar 19, 2015 – Mar 20, 2015

Subsystems (2)

v2 of 4 Superseded Latest is v4 →

lore
Share & tools
lore

York Sun

author
#0 lore raw

PATCH v2 4/28 armv8/ls2085a: Fix generic timer clock source

The timer clock is system clock divided by 4, not fixed 12MHz. This is common to the SoC, not board specific.

---

Changes in v2:
Fix CNTFRQ for secondary cores when COUNTER_FREQUENCY_REAL is defined.

 README                                  |    8 ++++++++
 arch/arm/cpu/armv8/fsl-lsch3/cpu.c      |   26 ++++++++++++++++++++++++++
 arch/arm/cpu/armv8/fsl-lsch3/lowlevel.S |    6 ++++++
 arch/arm/cpu/armv8/fsl-lsch3/mp.h       |    1 +
 board/freescale/ls2085a/ls2085a.c       |   18 ------------------
 include/configs/ls2085a_common.h        |    6 +++++-
 6 files changed, 46 insertions(+), 19 deletions(-)
README +8 -0
index f473515..776ebf4 100644
@@ -690,6 +690,14 @@ The following options need to be configured:
 		exists, unlike the similar options in the Linux kernel. Do not
 		set these options unless they apply!
 
+		COUNTER_FREQUENCY
+		Generic timer clock source frequency.
+
+		COUNTER_FREQUENCY_REAL
+		Generic timer clock source frequency if the real clock is
+		different from COUNTER_FREQUENCY, and can only be determined
+		at run time.
+
 		NOTE: The following can be machine specific errata. These
 		do have ability to provide rudimentary version and machine
 		specific checks, but expect no product checks.
arch/arm/cpu/armv8/fsl-lsch3/cpu.c +26 -0
index 94fd147..f75b21d 100644
@@ -395,3 +395,29 @@ int arch_early_init_r(void)
 
 	return 0;
 }
+
+int timer_init(void)
+{
+	u32 __iomem *cntcr = (u32 *)CONFIG_SYS_FSL_TIMER_ADDR;
+	u32 __iomem *cltbenr = (u32 *)CONFIG_SYS_FSL_PMU_CLTBENR;
+#ifdef COUNTER_FREQUENCY_REAL
+	unsigned long cntfrq = COUNTER_FREQUENCY_REAL;
+
+	/* Update with accurate clock frequency */
+	asm volatile("msr cntfrq_el0, %0" : : "r" (cntfrq) : "memory");
+
+	__real_cntfrq = cntfrq;	/* update for secondary cores */
+#endif
+
+	/* Enable timebase for all clusters.
+	 * It is safe to do so even some clusters are not enabled.
+	 */
+	out_le32(cltbenr, 0xf);
+
+	/* Enable clock for timer
+	 * This is a global setting.
+	 */
+	out_le32(cntcr, 0x1);
+
+	return 0;
+}
arch/arm/cpu/armv8/fsl-lsch3/lowlevel.S +6 -0
index 886576e..8d330ff 100644
@@ -224,6 +224,9 @@ ENTRY(secondary_boot_func)
 	/* physical address of this cpus spin table element */
 	add	x11, x1, x0
 
+	ldr	x0, =__real_cntfrq
+	ldr	x0, [x0]
+	msr	cntfrq_el0, x0	/* set with real frequency */
 	str	x9, [x11, #16]	/* LPID */
 	mov	x4, #1
 	str	x4, [x11, #8]	/* STATUS */
@@ -275,6 +278,9 @@ ENDPROC(secondary_switch_to_el1)
 
 	/* 64 bit alignment for elements accessed as data */
 	.align 4
+	.global __real_cntfrq
+__real_cntfrq:
+	.quad 0x17d7840		/* 25MHz */
 	.globl __secondary_boot_code_size
 	.type __secondary_boot_code_size, %object
 	/* Secondary Boot Code ends here */
arch/arm/cpu/armv8/fsl-lsch3/mp.h +1 -0
index 66144d6..c985d6a 100644
@@ -26,6 +26,7 @@
 #define id_to_core(x)	((x & 3) | (x >> 6))
 #ifndef __ASSEMBLY__
 extern u64 __spin_table[];
+extern u64 __real_cntfrq;
 extern u64 *secondary_boot_code;
 extern size_t __secondary_boot_code_size;
 int fsl_lsch3_wake_seconday_cores(void);
board/freescale/ls2085a/ls2085a.c +0 -18
index e78c63a..bd016e9 100644
@@ -55,24 +55,6 @@ int dram_init(void)
 	return 0;
 }
 
-int timer_init(void)
-{
-	u32 __iomem *cntcr = (u32 *)CONFIG_SYS_FSL_TIMER_ADDR;
-	u32 __iomem *cltbenr = (u32 *)CONFIG_SYS_FSL_PMU_CLTBENR;
-
-	/* Enable timebase for all clusters.
-	 * It is safe to do so even some clusters are not enabled.
-	 */
-	out_le32(cltbenr, 0xf);
-
-	/* Enable clock for timer
-	 * This is a global setting.
-	 */
-	out_le32(cntcr, 0x1);
-
-	return 0;
-}
-
 /*
  * Board specific reset that is system reset.
  */
include/configs/ls2085a_common.h +5 -1
index 339337d..b47cf68 100644
@@ -72,7 +72,11 @@
 #define CONFIG_DP_DDR_NUM_CTRLS		1
 
 /* Generic Timer Definitions */
-#define COUNTER_FREQUENCY		12000000	/* 12MHz */
+/*
+ * This is not an accurate number. It is used in start.S. The frequency
+ * will be udpated later when get_bus_freq(0) is available.
+ */
+#define COUNTER_FREQUENCY		25000000	/* 25MHz */
 
 /* Size of malloc() pool */
 #define CONFIG_SYS_MALLOC_LEN		(CONFIG_ENV_SIZE + 2048 * 1024)
Signature · 1 line
1.7.9.5
#1 lore raw

PATCH v2 4/28 armv8/ls2085a: Fix generic timer clock source

Hi,

Quoted 45 lines · York Sun

The timer clock is system clock divided by 4, not fixed 12MHz. This is common to the SoC, not board specific.

---

Changes in v2:
Fix CNTFRQ for secondary cores when COUNTER_FREQUENCY_REAL is defined.

 README                                  |    8 ++++++++
 arch/arm/cpu/armv8/fsl-lsch3/cpu.c      |   26 ++++++++++++++++++++++++++
 arch/arm/cpu/armv8/fsl-lsch3/lowlevel.S |    6 ++++++
 arch/arm/cpu/armv8/fsl-lsch3/mp.h       |    1 +
 board/freescale/ls2085a/ls2085a.c       |   18 ------------------
 include/configs/ls2085a_common.h        |    6 +++++-
 6 files changed, 46 insertions(+), 19 deletions(-)
README +8 -0
index f473515..776ebf4 100644
@@ -690,6 +690,14 @@ The following options need to be configured:
 		exists, unlike the similar options in the Linux kernel. Do not
 		set these options unless they apply!
 
+		COUNTER_FREQUENCY
+		Generic timer clock source frequency.
+
+		COUNTER_FREQUENCY_REAL
+		Generic timer clock source frequency if the real clock is
+		different from COUNTER_FREQUENCY, and can only be determined
+		at run time.
+
 		NOTE: The following can be machine specific errata. These
 		do have ability to provide rudimentary version and machine
 		specific checks, but expect no product checks.
arch/arm/cpu/armv8/fsl-lsch3/cpu.c +0 -0
index 94fd147..f75b21d 100644
@@ -395,3 +395,29 @@ int arch_early_init_r(void)
 
 	return 0;
 }

arch/arm/cpu/armv8/fsl-lsch3/cpu.c int arch_early_init_r(void) · line 407

Quoted 10 lines
arch/arm/cpu/armv8/fsl-lsch3/cpu.c +10 -0
+
+int timer_init(void)
+{
+	u32 __iomem *cntcr = (u32 *)CONFIG_SYS_FSL_TIMER_ADDR;
+	u32 __iomem *cltbenr = (u32 *)CONFIG_SYS_FSL_PMU_CLTBENR;
+#ifdef COUNTER_FREQUENCY_REAL
+	unsigned long cntfrq = COUNTER_FREQUENCY_REAL;
+
+	/* Update with accurate clock frequency */
+	asm volatile("msr cntfrq_el0, %0" : : "r" (cntfrq) : "memory");

The commit message says that this can only be determined at runtime, but this looks like we're writing a compile-time static value.

arch/arm/cpu/armv8/fsl-lsch3/cpu.c int arch_early_init_r(void) · line 409

Quoted 2 lines
arch/arm/cpu/armv8/fsl-lsch3/cpu.c +2 -0
+
+	__real_cntfrq = cntfrq;	/* update for secondary cores */

Do we need anything in the way or barriers and/or cache flushing to ensure that this is visible to the secondary CPUs? Or is the MMU off at this point?

Quoted 29 lines
arch/arm/cpu/armv8/fsl-lsch3/cpu.c +14 -0
+#endif
+
+	/* Enable timebase for all clusters.
+	 * It is safe to do so even some clusters are not enabled.
+	 */
+	out_le32(cltbenr, 0xf);
+
+	/* Enable clock for timer
+	 * This is a global setting.
+	 */
+	out_le32(cntcr, 0x1);
+
+	return 0;
+}
arch/arm/cpu/armv8/fsl-lsch3/lowlevel.S +3 -0
index 886576e..8d330ff 100644
@@ -224,6 +224,9 @@ ENTRY(secondary_boot_func)
 	/* physical address of this cpus spin table element */
 	add	x11, x1, x0
 
+	ldr	x0, =__real_cntfrq
+	ldr	x0, [x0]
+	msr	cntfrq_el0, x0	/* set with real frequency */
 	str	x9, [x11, #16]	/* LPID */
 	mov	x4, #1
 	str	x4, [x11, #8]	/* STATUS */

arch/arm/cpu/armv8/fsl-lsch3/lowlevel.S ENDPROC(secondary_switch_to_el1) · line 283

Quoted 6 lines
arch/arm/cpu/armv8/fsl-lsch3/lowlevel.S +3 -0
@@ -275,6 +278,9 @@ ENDPROC(secondary_switch_to_el1)
 
 	/* 64 bit alignment for elements accessed as data */
 	.align 4
+	.global __real_cntfrq
+__real_cntfrq:
+	.quad 0x17d7840		/* 25MHz */

I think this would be better as COUNTER_FREQUENCY, so as to avoid duplicating the value.

Thanks,
Mark.

author
#2 lore raw

PATCH v2 4/28 armv8/ls2085a: Fix generic timer clock source

Quoted 46 lines · Mark Rutland

Hi,

Quoted 43 lines · York Sun

The timer clock is system clock divided by 4, not fixed 12MHz. This is common to the SoC, not board specific.

---

Changes in v2:
Fix CNTFRQ for secondary cores when COUNTER_FREQUENCY_REAL is defined.

 README                                  |    8 ++++++++
 arch/arm/cpu/armv8/fsl-lsch3/cpu.c      |   26 ++++++++++++++++++++++++++
 arch/arm/cpu/armv8/fsl-lsch3/lowlevel.S |    6 ++++++
 arch/arm/cpu/armv8/fsl-lsch3/mp.h       |    1 +
 board/freescale/ls2085a/ls2085a.c       |   18 ------------------
 include/configs/ls2085a_common.h        |    6 +++++-
 6 files changed, 46 insertions(+), 19 deletions(-)
README +8 -0
index f473515..776ebf4 100644
@@ -690,6 +690,14 @@ The following options need to be configured:
 		exists, unlike the similar options in the Linux kernel. Do not
 		set these options unless they apply!
 
+		COUNTER_FREQUENCY
+		Generic timer clock source frequency.
+
+		COUNTER_FREQUENCY_REAL
+		Generic timer clock source frequency if the real clock is
+		different from COUNTER_FREQUENCY, and can only be determined
+		at run time.
+
 		NOTE: The following can be machine specific errata. These
 		do have ability to provide rudimentary version and machine
 		specific checks, but expect no product checks.
arch/arm/cpu/armv8/fsl-lsch3/cpu.c +0 -0
index 94fd147..f75b21d 100644
@@ -395,3 +395,29 @@ int arch_early_init_r(void)
 
Quoted 16 lines

arch/arm/cpu/armv8/fsl-lsch3/cpu.c int arch_early_init_r(void) · line 407

Quoted 12 lines
arch/arm/cpu/armv8/fsl-lsch3/cpu.c +10 -0
 	return 0;
 }
+
+int timer_init(void)
+{
+	u32 __iomem *cntcr = (u32 *)CONFIG_SYS_FSL_TIMER_ADDR;
+	u32 __iomem *cltbenr = (u32 *)CONFIG_SYS_FSL_PMU_CLTBENR;
+#ifdef COUNTER_FREQUENCY_REAL
+	unsigned long cntfrq = COUNTER_FREQUENCY_REAL;
+
+	/* Update with accurate clock frequency */
+	asm volatile("msr cntfrq_el0, %0" : : "r" (cntfrq) : "memory");

The commit message says that this can only be determined at runtime, but this looks like we're writing a compile-time static value.

The macro COUNTER_FREQUENCY_REA is (CONFIG_SYS_CLK_FREQ/4), where CONFIG_SYS_CLK_FREQ is a function call get_board_sys_clk().

Quoted 6 lines

arch/arm/cpu/armv8/fsl-lsch3/cpu.c int arch_early_init_r(void) · line 409

Quoted 2 lines
arch/arm/cpu/armv8/fsl-lsch3/cpu.c +2 -0
+
+	__real_cntfrq = cntfrq;	/* update for secondary cores */

Do we need anything in the way or barriers and/or cache flushing to ensure that this is visible to the secondary CPUs? Or is the MMU off at this point?

It is flushed before booting secondary cores. But I am relying on the trick of enabling cache on flash. It may not be as reliable if someone decide to disable the cache to begin with. I will move the code to somewhere safe in next version.

Quoted 31 lines
Quoted 31 lines
arch/arm/cpu/armv8/fsl-lsch3/cpu.c +14 -0
+#endif
+
+	/* Enable timebase for all clusters.
+	 * It is safe to do so even some clusters are not enabled.
+	 */
+	out_le32(cltbenr, 0xf);
+
+	/* Enable clock for timer
+	 * This is a global setting.
+	 */
+	out_le32(cntcr, 0x1);
+
+	return 0;
+}
arch/arm/cpu/armv8/fsl-lsch3/lowlevel.S +3 -0
index 886576e..8d330ff 100644
@@ -224,6 +224,9 @@ ENTRY(secondary_boot_func)
 	/* physical address of this cpus spin table element */
 	add	x11, x1, x0
 
+	ldr	x0, =__real_cntfrq
+	ldr	x0, [x0]
+	msr	cntfrq_el0, x0	/* set with real frequency */
 	str	x9, [x11, #16]	/* LPID */
 	mov	x4, #1
 	str	x4, [x11, #8]	/* STATUS */
@@ -275,6 +278,9 @@ ENDPROC(secondary_switch_to_el1)
 
Quoted 8 lines

arch/arm/cpu/armv8/fsl-lsch3/lowlevel.S ENDPROC(secondary_switch_to_el1) · line 283

Quoted 5 lines
arch/arm/cpu/armv8/fsl-lsch3/lowlevel.S +3 -0
 	/* 64 bit alignment for elements accessed as data */
 	.align 4
+	.global __real_cntfrq
+__real_cntfrq:
+	.quad 0x17d7840		/* 25MHz */

I think this would be better as COUNTER_FREQUENCY, so as to avoid duplicating the value.

Good idea. Will fix in next version.

York

#3 lore raw

PATCH v2 4/28 armv8/ls2085a: Fix generic timer clock source

Quoted 14 lines
Quoted 4 lines
Quoted 4 lines
arch/arm/cpu/armv8/fsl-lsch3/cpu.c +4 -0
+int timer_init(void)
+{
+	u32 __iomem *cntcr = (u32 *)CONFIG_SYS_FSL_TIMER_ADDR;
+	u32 __iomem *cltbenr = (u32 *)CONFIG_SYS_FSL_PMU_CLTBENR;
Quoted 9 lines

arch/arm/cpu/armv8/fsl-lsch3/cpu.c int arch_early_init_r(void) · line 407

Quoted 5 lines
arch/arm/cpu/armv8/fsl-lsch3/cpu.c +5 -0
+#ifdef COUNTER_FREQUENCY_REAL
+	unsigned long cntfrq = COUNTER_FREQUENCY_REAL;
+
+	/* Update with accurate clock frequency */
+	asm volatile("msr cntfrq_el0, %0" : : "r" (cntfrq) : "memory");

The commit message says that this can only be determined at runtime, but this looks like we're writing a compile-time static value.

Quoted 2 lines

The macro COUNTER_FREQUENCY_REA is (CONFIG_SYS_CLK_FREQ/4), where CONFIG_SYS_CLK_FREQ is a function call get_board_sys_clk().

Ah, that sounds fine to me then.

Quoted 9 lines
Quoted 5 lines

arch/arm/cpu/armv8/fsl-lsch3/cpu.c int arch_early_init_r(void) · line 409

Quoted 1 line
arch/arm/cpu/armv8/fsl-lsch3/cpu.c +1 -0
+	__real_cntfrq = cntfrq;	/* update for secondary cores */

Do we need anything in the way or barriers and/or cache flushing to ensure that this is visible to the secondary CPUs? Or is the MMU off at this point?

It is flushed before booting secondary cores. But I am relying on the trick of enabling cache on flash. It may not be as reliable if someone decide to disable the cache to begin with. I will move the code to somewhere safe in next version.

Ok.

Quoted 8 lines
Quoted 6 lines

arch/arm/cpu/armv8/fsl-lsch3/lowlevel.S ENDPROC(secondary_switch_to_el1) · line 283

Quoted 3 lines
arch/arm/cpu/armv8/fsl-lsch3/lowlevel.S +3 -0
+	.global __real_cntfrq
+__real_cntfrq:
+	.quad 0x17d7840		/* 25MHz */

I think this would be better as COUNTER_FREQUENCY, so as to avoid duplicating the value.

Good idea. Will fix in next version.

Great!

Mark.