[U-Boot] [PATCH 0/9] Consolidate ARM timer code

From: Rob Herring rob.herring@calxeda.com
Much of the ARM timer code is re-implemented for each platform yet it is all pretty much the same code.
This series introduces a common implementation of timer functions and simplifies the platform code down to 2 or 3 config defines. It is intended for platforms with 32-bit freerunning timers. I've converted a couple of platforms as an example, but there are many more still that can be converted. This probably could be extended to work with 16-bit timers as well.
I've compiled all ARM boards, but only tested on highbank.
Rob
Rob Herring (9): ARM: add common timer functions examples: enable gc-sections option time: create default __udelay ARM: highbank: convert to common timer code ARM: mx25: convert to common timer code ARM: mx27: convert to common timer code ARM: vexpress: convert to common timer code ARM: socfpga: convert to common timer code ARM: tegra: convert to common timer code
arch/arm/cpu/arm926ejs/mx25/timer.c | 117 -------------------------------- arch/arm/cpu/arm926ejs/mx27/timer.c | 110 ------------------------------ arch/arm/cpu/armv7/highbank/timer.c | 83 ---------------------- arch/arm/cpu/armv7/socfpga/timer.c | 72 -------------------- arch/arm/cpu/tegra-common/Makefile | 2 +- arch/arm/cpu/tegra-common/timer.c | 95 -------------------------- arch/arm/lib/Makefile | 2 +- arch/arm/lib/time.c | 59 ++++++++++++++++ board/armltd/vexpress/vexpress_common.c | 71 ------------------- examples/api/Makefile | 2 +- include/configs/highbank.h | 4 ++ include/configs/imx27lite-common.h | 3 + include/configs/mx25pdk.h | 3 + include/configs/socfpga_cyclone5.h | 3 +- include/configs/tegra-common.h | 3 + include/configs/tx25.h | 2 + include/configs/vexpress_common.h | 4 ++ include/configs/zmx25.h | 3 + lib/time.c | 21 ++++++ 19 files changed, 107 insertions(+), 552 deletions(-) delete mode 100644 arch/arm/cpu/tegra-common/timer.c create mode 100644 arch/arm/lib/time.c

From: Rob Herring rob.herring@calxeda.com
Many ARM platforms duplicate pretty much the same timer code yet they all have a 32-bit freerunning counter register. Create a common implementation that simply requires 3 defines to add timer support:
CONFIG_SYS_TIMER_RATE - Clock rate of the timer counter CONFIG_SYS_TIMER_COUNTER - Address of 32-bit counter CONFIG_SYS_TIMER_COUNTS_DOWN - Define if counter counts down
Signed-off-by: Rob Herring rob.herring@calxeda.com --- arch/arm/lib/Makefile | 2 +- arch/arm/lib/time.c | 59 +++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 60 insertions(+), 1 deletion(-) create mode 100644 arch/arm/lib/time.c
diff --git a/arch/arm/lib/Makefile b/arch/arm/lib/Makefile index 4e78723..0bf5877 100644 --- a/arch/arm/lib/Makefile +++ b/arch/arm/lib/Makefile @@ -38,7 +38,7 @@ else COBJS-$(CONFIG_SPL_FRAMEWORK) += spl.o endif
-COBJS-y += interrupts.o +COBJS-y += interrupts.o time.o COBJS-y += reset.o
COBJS-y += cache.o diff --git a/arch/arm/lib/time.c b/arch/arm/lib/time.c new file mode 100644 index 0000000..0ec8ded --- /dev/null +++ b/arch/arm/lib/time.c @@ -0,0 +1,59 @@ +/* + * Copyright 2013 Calxeda, Inc. + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#include <common.h> +#include <div64.h> +#include <asm/io.h> + +DECLARE_GLOBAL_DATA_PTR; + +#ifdef CONFIG_SYS_TIMER_RATE +ulong notrace get_tbclk(void) +{ + return CONFIG_SYS_TIMER_RATE; +} +#endif + +#ifdef CONFIG_SYS_TIMER_COUNTER +unsigned long notrace timer_read_counter(void) +{ +#ifdef CONFIG_SYS_TIMER_COUNTS_DOWN + return ~readl(CONFIG_SYS_TIMER_COUNTER); +#else + return readl(CONFIG_SYS_TIMER_COUNTER); +#endif +} +#endif + +unsigned long long __weak notrace get_ticks(void) +{ + unsigned long now = timer_read_counter(); + + /* increment tbu if tbl has rolled over */ + if (now < gd->arch.tbl) + gd->arch.tbu++; + gd->arch.tbl = now; + return (((unsigned long long)gd->arch.tbu) << 32) | gd->arch.tbl; +} + +static unsigned long long notrace tick_to_time(unsigned long long tick) +{ + unsigned int div = get_tbclk(); + + tick *= CONFIG_SYS_HZ; + do_div(tick, div); + return tick; +} + +ulong __weak get_timer(ulong base) +{ + return tick_to_time(get_ticks()) - base; +} + +unsigned long __weak notrace timer_get_us(void) +{ + return tick_to_time(get_ticks() * 1000); +}

From: Rob Herring rob.herring@calxeda.com
This fixes building time.c when unreferenced functions are added.
Signed-off-by: Rob Herring rob.herring@calxeda.com --- examples/api/Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/examples/api/Makefile b/examples/api/Makefile index 4d68340..33cc91b 100644 --- a/examples/api/Makefile +++ b/examples/api/Makefile @@ -53,7 +53,7 @@ all: $(obj).depend $(OUTPUT) #########################################################################
$(OUTPUT): $(OBJS) - $(LD) -Ttext $(LOAD_ADDR) -o $@ $^ $(PLATFORM_LIBS) + $(LD) --gc-sections -Ttext $(LOAD_ADDR) -o $@ $^ $(PLATFORM_LIBS) $(OBJCOPY) -O binary $@ $(OUTPUT).bin 2>/dev/null
# Rule to build generic library C files

From: Rob Herring rob.herring@calxeda.com
Implement a default __udelay using get_tbclk and get_ticks.
Signed-off-by: Rob Herring rob.herring@calxeda.com --- lib/time.c | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+)
diff --git a/lib/time.c b/lib/time.c index 68b8ff4..55f05bb 100644 --- a/lib/time.c +++ b/lib/time.c @@ -7,11 +7,32 @@
#include <common.h> #include <watchdog.h> +#include <div64.h>
#ifndef CONFIG_WD_PERIOD # define CONFIG_WD_PERIOD (10 * 1000 * 1000) /* 10 seconds default*/ #endif
+static unsigned long long usec_to_tick(unsigned long usec) +{ + unsigned long long tick = usec * get_tbclk(); + usec *= get_tbclk(); + do_div(tick, 1000000); + return tick; +} + +void __weak __udelay(unsigned long usec) +{ + unsigned long long tmp; + ulong tmo; + + tmo = usec_to_tick(usec); + tmp = get_ticks() + tmo; /* get current timestamp */ + + while (get_ticks() < tmp) /* loop till event */ + /*NOP*/; +} + /* ------------------------------------------------------------------------- */
void udelay(unsigned long usec)

From: Rob Herring rob.herring@calxeda.com
Convert highbank to use the commmon timer code.
Signed-off-by: Rob Herring rob.herring@calxeda.com --- arch/arm/cpu/armv7/highbank/timer.c | 83 ------------------------------------- include/configs/highbank.h | 4 ++ 2 files changed, 4 insertions(+), 83 deletions(-)
diff --git a/arch/arm/cpu/armv7/highbank/timer.c b/arch/arm/cpu/armv7/highbank/timer.c index b61cd69..d56bf21 100644 --- a/arch/arm/cpu/armv7/highbank/timer.c +++ b/arch/arm/cpu/armv7/highbank/timer.c @@ -7,18 +7,12 @@ */
#include <common.h> -#include <div64.h> -#include <linux/types.h> /* for size_t */ -#include <linux/stddef.h> /* for NULL */ #include <asm/io.h> #include <asm/arch-armv7/systimer.h>
#undef SYSTIMER_BASE #define SYSTIMER_BASE 0xFFF34000 /* Timer 0 and 1 base */ -#define SYSTIMER_RATE (150000000 / 256)
-static ulong timestamp; -static ulong lastinc; static struct systimer *systimer_base = (struct systimer *)SYSTIMER_BASE;
/* @@ -38,80 +32,3 @@ int timer_init(void) return 0;
} - -#define TICK_PER_TIME ((SYSTIMER_RATE + CONFIG_SYS_HZ / 2) / CONFIG_SYS_HZ) -#define NS_PER_TICK (1000000000 / SYSTIMER_RATE) - -static inline unsigned long long tick_to_time(unsigned long long tick) -{ - do_div(tick, TICK_PER_TIME); - return tick; -} - -static inline unsigned long long time_to_tick(unsigned long long time) -{ - return time * TICK_PER_TIME; -} - -static inline unsigned long long us_to_tick(unsigned long long us) -{ - unsigned long long tick = us * 1000; - tick += NS_PER_TICK - 1; - do_div(tick, NS_PER_TICK); - return tick; -} - -unsigned long long get_ticks(void) -{ - ulong now = ~readl(&systimer_base->timer0value); - - if (now >= lastinc) /* normal mode (non roll) */ - /* move stamp forward with absolut diff ticks */ - timestamp += (now - lastinc); - else /* we have rollover of incrementer */ - timestamp += (0xFFFFFFFF - lastinc) + now; - lastinc = now; - return timestamp; -} - -/* - * Delay x useconds AND preserve advance timstamp value - * assumes timer is ticking at 1 msec - */ -void __udelay(ulong usec) -{ - unsigned long long tmp; - ulong tmo; - - tmo = us_to_tick(usec); - tmp = get_ticks() + tmo; /* get current timestamp */ - - while (get_ticks() < tmp) /* loop till event */ - /*NOP*/; -} - -ulong get_timer(ulong base) -{ - return get_timer_masked() - base; -} - -void reset_timer_masked(void) -{ - lastinc = ~readl(&systimer_base->timer0value); - timestamp = 0; -} - -void reset_timer(void) -{ - reset_timer_masked(); -} - -ulong get_timer_masked(void) -{ - return tick_to_time(get_ticks()); -} - -ulong get_tbclk(void) -{ - return SYSTIMER_RATE; -} diff --git a/include/configs/highbank.h b/include/configs/highbank.h index 24f9350..dc027a7 100644 --- a/include/configs/highbank.h +++ b/include/configs/highbank.h @@ -19,6 +19,10 @@ #define CONFIG_SUPPORT_RAW_INITRD #define CONFIG_SYS_BOOTMAPSZ (16 << 20)
+#define CONFIG_SYS_TIMER_RATE (150000000/256) +#define CONFIG_SYS_TIMER_COUNTER (0xFFF34000 + 0x4) +#define CONFIG_SYS_TIMER_COUNTS_DOWN + /* * Size of malloc() pool */

From: Rob Herring rob.herring@calxeda.com
Convert mx25 to use the commmon timer code.
Signed-off-by: Rob Herring rob.herring@calxeda.com --- arch/arm/cpu/arm926ejs/mx25/timer.c | 117 ------------------------------------ include/configs/mx25pdk.h | 3 + include/configs/tx25.h | 2 + include/configs/zmx25.h | 3 + 4 files changed, 8 insertions(+), 117 deletions(-)
diff --git a/arch/arm/cpu/arm926ejs/mx25/timer.c b/arch/arm/cpu/arm926ejs/mx25/timer.c index 42b6076..7f19791 100644 --- a/arch/arm/cpu/arm926ejs/mx25/timer.c +++ b/arch/arm/cpu/arm926ejs/mx25/timer.c @@ -21,65 +21,8 @@ */
#include <common.h> -#include <div64.h> #include <asm/io.h> #include <asm/arch/imx-regs.h> -#include <asm/arch/clock.h> - -DECLARE_GLOBAL_DATA_PTR; - -#define timestamp (gd->arch.tbl) -#define lastinc (gd->arch.lastinc) - -/* - * "time" is measured in 1 / CONFIG_SYS_HZ seconds, - * "tick" is internal timer period - */ -#ifdef CONFIG_MX25_TIMER_HIGH_PRECISION -/* ~0.4% error - measured with stop-watch on 100s boot-delay */ -static inline unsigned long long tick_to_time(unsigned long long tick) -{ - tick *= CONFIG_SYS_HZ; - do_div(tick, MXC_CLK32); - return tick; -} - -static inline unsigned long long time_to_tick(unsigned long long time) -{ - time *= MXC_CLK32; - do_div(time, CONFIG_SYS_HZ); - return time; -} - -static inline unsigned long long us_to_tick(unsigned long long us) -{ - us = us * MXC_CLK32 + 999999; - do_div(us, 1000000); - return us; -} -#else -/* ~2% error */ -#define TICK_PER_TIME ((MXC_CLK32 + CONFIG_SYS_HZ / 2) / CONFIG_SYS_HZ) -#define US_PER_TICK (1000000 / MXC_CLK32) - -static inline unsigned long long tick_to_time(unsigned long long tick) -{ - do_div(tick, TICK_PER_TIME); - return tick; -} - -static inline unsigned long long time_to_tick(unsigned long long time) -{ - return time * TICK_PER_TIME; -} - -static inline unsigned long long us_to_tick(unsigned long long us) -{ - us += US_PER_TICK - 1; - do_div(us, US_PER_TICK); - return us; -} -#endif
/* nothing really to do with interrupts, just starts up a counter. */ /* The 32KHz 32-bit timer overruns in 134217 seconds */ @@ -104,63 +47,3 @@ int timer_init(void)
return 0; } - -unsigned long long get_ticks(void) -{ - struct gpt_regs *gpt = (struct gpt_regs *)IMX_GPT1_BASE; - ulong now = readl(&gpt->counter); /* current tick value */ - - if (now >= lastinc) { - /* - * normal mode (non roll) - * move stamp forward with absolut diff ticks - */ - timestamp += (now - lastinc); - } else { - /* we have rollover of incrementer */ - timestamp += (0xFFFFFFFF - lastinc) + now; - } - lastinc = now; - return timestamp; -} - -ulong get_timer_masked(void) -{ - /* - * get_ticks() returns a long long (64 bit), it wraps in - * 2^64 / MXC_CLK32 = 2^64 / 2^15 = 2^49 ~ 5 * 10^14 (s) ~ - * 5 * 10^9 days... and get_ticks() * CONFIG_SYS_HZ wraps in - * 5 * 10^6 days - long enough. - */ - return tick_to_time(get_ticks()); -} - -ulong get_timer(ulong base) -{ - return get_timer_masked() - base; -} - -/* delay x useconds AND preserve advance timstamp value */ -void __udelay(unsigned long usec) -{ - unsigned long long tmp; - ulong tmo; - - tmo = us_to_tick(usec); - tmp = get_ticks() + tmo; /* get current timestamp */ - - while (get_ticks() < tmp) /* loop till event */ - /*NOP*/; -} - -/* - * This function is derived from PowerPC code (timebase clock frequency). - * On ARM it returns the number of timer ticks per second. - */ -ulong get_tbclk(void) -{ - ulong tbclk; - - tbclk = MXC_CLK32; - return tbclk; -} diff --git a/include/configs/mx25pdk.h b/include/configs/mx25pdk.h index ccd3b6c..568ed6c 100644 --- a/include/configs/mx25pdk.h +++ b/include/configs/mx25pdk.h @@ -15,6 +15,9 @@ #define CONFIG_SYS_TEXT_BASE 0x81200000 #define CONFIG_MXC_GPIO
+#define CONFIG_SYS_TIMER_RATE 32768 +#define CONFIG_SYS_TIMER_COUNTER (IMX_GPT1_BASE + 0x24) + #define CONFIG_DISPLAY_CPUINFO #define CONFIG_DISPLAY_BOARDINFO
diff --git a/include/configs/tx25.h b/include/configs/tx25.h index 2d7479b..f879441 100644 --- a/include/configs/tx25.h +++ b/include/configs/tx25.h @@ -15,6 +15,8 @@ */ #define CONFIG_MX25 #define CONFIG_MX25_CLK32 32000 /* OSC32K frequency */ +#define CONFIG_SYS_TIMER_RATE CONFIG_MX25_CLK32 +#define CONFIG_SYS_TIMER_COUNTER (IMX_GPT1_BASE + 0x24)
#define CONFIG_SYS_MONITOR_LEN (256 << 10) /* 256 kB for U-Boot */
diff --git a/include/configs/zmx25.h b/include/configs/zmx25.h index 2e7f145..deaadfa 100644 --- a/include/configs/zmx25.h +++ b/include/configs/zmx25.h @@ -14,6 +14,9 @@ #define CONFIG_MX25 #define CONFIG_SYS_TEXT_BASE 0xA0000000
+#define CONFIG_SYS_TIMER_RATE 32768 +#define CONFIG_SYS_TIMER_COUNTER (IMX_GPT1_BASE + 0x24) + #define CONFIG_MACH_TYPE MACH_TYPE_ZMX25 /* * Environment settings

Dear Rob Herring,
On Sunday, September 8, 2013 10:12:50 PM, Rob Herring wrote:
From: Rob Herring rob.herring@calxeda.com
Convert mx25 to use the commmon timer code.
Signed-off-by: Rob Herring rob.herring@calxeda.com
[...]
diff --git a/include/configs/mx25pdk.h b/include/configs/mx25pdk.h index ccd3b6c..568ed6c 100644 --- a/include/configs/mx25pdk.h +++ b/include/configs/mx25pdk.h @@ -15,6 +15,9 @@ #define CONFIG_SYS_TEXT_BASE 0x81200000 #define CONFIG_MXC_GPIO
+#define CONFIG_SYS_TIMER_RATE 32768
^ MXC_CLK32 could be used here.
+#define CONFIG_SYS_TIMER_COUNTER (IMX_GPT1_BASE + 0x24)
This Linux-style (base + offset) register access is against U-Boot rules. You could write: (&((struct gpt_regs *)IMX_GPT1_BASE)->counter)
#define CONFIG_DISPLAY_CPUINFO #define CONFIG_DISPLAY_BOARDINFO
diff --git a/include/configs/tx25.h b/include/configs/tx25.h index 2d7479b..f879441 100644 --- a/include/configs/tx25.h +++ b/include/configs/tx25.h @@ -15,6 +15,8 @@ */ #define CONFIG_MX25 #define CONFIG_MX25_CLK32 32000 /* OSC32K frequency */ +#define CONFIG_SYS_TIMER_RATE CONFIG_MX25_CLK32
Ditto 1.
+#define CONFIG_SYS_TIMER_COUNTER (IMX_GPT1_BASE + 0x24)
Ditto 2.
#define CONFIG_SYS_MONITOR_LEN (256 << 10) /* 256 kB for U-Boot */
diff --git a/include/configs/zmx25.h b/include/configs/zmx25.h index 2e7f145..deaadfa 100644 --- a/include/configs/zmx25.h +++ b/include/configs/zmx25.h @@ -14,6 +14,9 @@ #define CONFIG_MX25 #define CONFIG_SYS_TEXT_BASE 0xA0000000
+#define CONFIG_SYS_TIMER_RATE 32768
Ditto 1.
+#define CONFIG_SYS_TIMER_COUNTER (IMX_GPT1_BASE + 0x24)
Ditto 2.
#define CONFIG_MACH_TYPE MACH_TYPE_ZMX25 /*
- Environment settings
Best regards, Benoît

On Sun, Sep 8, 2013 at 6:56 PM, Benoît Thébaudeau benoit.thebaudeau@advansee.com wrote:
Dear Rob Herring,
On Sunday, September 8, 2013 10:12:50 PM, Rob Herring wrote:
From: Rob Herring rob.herring@calxeda.com
Convert mx25 to use the commmon timer code.
Signed-off-by: Rob Herring rob.herring@calxeda.com
[...]
diff --git a/include/configs/mx25pdk.h b/include/configs/mx25pdk.h index ccd3b6c..568ed6c 100644 --- a/include/configs/mx25pdk.h +++ b/include/configs/mx25pdk.h @@ -15,6 +15,9 @@ #define CONFIG_SYS_TEXT_BASE 0x81200000 #define CONFIG_MXC_GPIO
+#define CONFIG_SYS_TIMER_RATE 32768
^
MXC_CLK32 could be used here.
The problem the circular dependency that creates. MXC_CLK32 depends on CONFIG_MX25_CLK32. Ordering could fix this, but
+#define CONFIG_SYS_TIMER_COUNTER (IMX_GPT1_BASE + 0x24)
This Linux-style (base + offset) register access is against U-Boot rules. You could write: (&((struct gpt_regs *)IMX_GPT1_BASE)->counter)
This may also have ordering issues. Including imx-regs.h just for the base address doesn't work on mx27 for example.
Also, it seems like if u-boot is moving towards using kconfig, then creating more include dependencies in the config headers is the wrong direction.
Rob

On Monday, September 9, 2013 11:00:51 PM, Rob Herring wrote:
On Sun, Sep 8, 2013 at 6:56 PM, Benoît Thébaudeau benoit.thebaudeau@advansee.com wrote:
Dear Rob Herring,
On Sunday, September 8, 2013 10:12:50 PM, Rob Herring wrote:
From: Rob Herring rob.herring@calxeda.com
Convert mx25 to use the commmon timer code.
Signed-off-by: Rob Herring rob.herring@calxeda.com
[...]
diff --git a/include/configs/mx25pdk.h b/include/configs/mx25pdk.h index ccd3b6c..568ed6c 100644 --- a/include/configs/mx25pdk.h +++ b/include/configs/mx25pdk.h @@ -15,6 +15,9 @@ #define CONFIG_SYS_TEXT_BASE 0x81200000 #define CONFIG_MXC_GPIO
+#define CONFIG_SYS_TIMER_RATE 32768
^
MXC_CLK32 could be used here.
The problem the circular dependency that creates. MXC_CLK32 depends on CONFIG_MX25_CLK32. Ordering could fix this, but
"but" what?
Yes: #define CONFIG_MX25_CLK32 32000 /* OSC32K frequency */ #include <asm/arch/clock.h> #define CONFIG_SYS_TIMER_RATE MXC_CLK32
+#define CONFIG_SYS_TIMER_COUNTER (IMX_GPT1_BASE + 0x24)
This Linux-style (base + offset) register access is against U-Boot rules. You could write: (&((struct gpt_regs *)IMX_GPT1_BASE)->counter)
This may also have ordering issues. Including imx-regs.h just for the base address doesn't work on mx27 for example.
There has to be a way to make the inclusion of imx-regs.h work on mx27 like on mx25. Also, imx27lite-common.h uses UART1_BASE from imx-regs.h, and it is very dirty to use literal constants for CONFIG_SYS_TIMER_COUNTER instead of definitions from imx-regs.h. The fix here should really be to make the inclusion of imx-regs.h work on mx27.
Also, it seems like if u-boot is moving towards using kconfig, then creating more include dependencies in the config headers is the wrong direction.
Right. However, the only thing that asm/arch/clock.h does here is to define a SoC-specific value with a default value. Converted to kconfig, that would just give:
Kconfig file for i.MX25 SoC: --- config MXC_CLK32 int "32-kHz oscillator frequency" default 32768 help Exact frequency of the 32-kHz oscillator, expressed in Hz ---
Kconfig file for your generic timer base driver: --- config SYS_TIMER_RATE int "System timer rate (Hz)" default MXC_CLK32 if MXC ---
Best regards, Benoît

On Tue, Sep 10, 2013 at 5:25 AM, Benoît Thébaudeau benoit.thebaudeau@advansee.com wrote:
On Monday, September 9, 2013 11:00:51 PM, Rob Herring wrote:
On Sun, Sep 8, 2013 at 6:56 PM, Benoît Thébaudeau benoit.thebaudeau@advansee.com wrote:
Dear Rob Herring,
On Sunday, September 8, 2013 10:12:50 PM, Rob Herring wrote:
From: Rob Herring rob.herring@calxeda.com
Convert mx25 to use the commmon timer code.
Signed-off-by: Rob Herring rob.herring@calxeda.com
[...]
diff --git a/include/configs/mx25pdk.h b/include/configs/mx25pdk.h index ccd3b6c..568ed6c 100644 --- a/include/configs/mx25pdk.h +++ b/include/configs/mx25pdk.h @@ -15,6 +15,9 @@ #define CONFIG_SYS_TEXT_BASE 0x81200000 #define CONFIG_MXC_GPIO
+#define CONFIG_SYS_TIMER_RATE 32768
^
MXC_CLK32 could be used here.
The problem the circular dependency that creates. MXC_CLK32 depends on CONFIG_MX25_CLK32. Ordering could fix this, but
"but" what?
Oops. But it is fragile is what I meant to say.
Yes: #define CONFIG_MX25_CLK32 32000 /* OSC32K frequency */ #include <asm/arch/clock.h> #define CONFIG_SYS_TIMER_RATE MXC_CLK32
This example highlights the fragility as you have to know all the CONFIG_* defines clock.h and anything clock.h includes.
+#define CONFIG_SYS_TIMER_COUNTER (IMX_GPT1_BASE + 0x24)
This Linux-style (base + offset) register access is against U-Boot rules. You could write: (&((struct gpt_regs *)IMX_GPT1_BASE)->counter)
This may also have ordering issues. Including imx-regs.h just for the base address doesn't work on mx27 for example.
There has to be a way to make the inclusion of imx-regs.h work on mx27 like on mx25. Also, imx27lite-common.h uses UART1_BASE from imx-regs.h, and it is very dirty to use literal constants for CONFIG_SYS_TIMER_COUNTER instead of definitions from imx-regs.h. The fix here should really be to make the inclusion of imx-regs.h work on mx27.
Well, to start with mx27 imx-regs.h has this:
#ifdef CONFIG_MXC_UART extern void mx27_uart1_init_pins(void); #endif /* CONFIG_MXC_UART */
#ifdef CONFIG_FEC_MXC extern void mx27_fec_init_pins(void); #endif /* CONFIG_FEC_MXC */
#ifdef CONFIG_MXC_MMC extern void mx27_sd1_init_pins(void); extern void mx27_sd2_init_pins(void); #endif /* CONFIG_MXC_MMC */
I will drop mx27 from the series and leave this to someone else to fix.
Also, it seems like if u-boot is moving towards using kconfig, then creating more include dependencies in the config headers is the wrong direction.
Right. However, the only thing that asm/arch/clock.h does here is to define a SoC-specific value with a default value. Converted to kconfig, that would just give:
Kconfig file for i.MX25 SoC:
config MXC_CLK32 int "32-kHz oscillator frequency" default 32768 help Exact frequency of the 32-kHz oscillator, expressed in Hz
Kconfig file for your generic timer base driver:
config SYS_TIMER_RATE int "System timer rate (Hz)" default MXC_CLK32 if MXC
This would not scale well to hundreds of platforms, so it probably needs to be in the platform kconfig. But this is another discussion...
Rob

From: Rob Herring rob.herring@calxeda.com
Convert mx27 to use the commmon timer code.
Signed-off-by: Rob Herring rob.herring@calxeda.com --- arch/arm/cpu/arm926ejs/mx27/timer.c | 110 ------------------------------------ include/configs/imx27lite-common.h | 3 + 2 files changed, 3 insertions(+), 110 deletions(-)
diff --git a/arch/arm/cpu/arm926ejs/mx27/timer.c b/arch/arm/cpu/arm926ejs/mx27/timer.c index 40fe2aa..b64875a 100644 --- a/arch/arm/cpu/arm926ejs/mx27/timer.c +++ b/arch/arm/cpu/arm926ejs/mx27/timer.c @@ -17,7 +17,6 @@ */
#include <common.h> -#include <div64.h> #include <asm/io.h> #include <asm/arch/imx-regs.h>
@@ -27,62 +26,6 @@ #define GPTCR_CLKSOURCE_32 (4 << 1) /* Clock source */ #define GPTCR_TEN 1 /* Timer enable */
-DECLARE_GLOBAL_DATA_PTR; - -#define timestamp (gd->arch.tbl) -#define lastinc (gd->arch.lastinc) - -/* - * "time" is measured in 1 / CONFIG_SYS_HZ seconds, - * "tick" is internal timer period - */ -#ifdef CONFIG_MX27_TIMER_HIGH_PRECISION -/* ~0.4% error - measured with stop-watch on 100s boot-delay */ -static inline unsigned long long tick_to_time(unsigned long long tick) -{ - tick *= CONFIG_SYS_HZ; - do_div(tick, CONFIG_MX27_CLK32); - return tick; -} - -static inline unsigned long long time_to_tick(unsigned long long time) -{ - time *= CONFIG_MX27_CLK32; - do_div(time, CONFIG_SYS_HZ); - return time; -} - -static inline unsigned long long us_to_tick(unsigned long long us) -{ - us = us * CONFIG_MX27_CLK32 + 999999; - do_div(us, 1000000); - return us; -} -#else -/* ~2% error */ -#define TICK_PER_TIME ((CONFIG_MX27_CLK32 + CONFIG_SYS_HZ / 2) / \ - CONFIG_SYS_HZ) -#define US_PER_TICK (1000000 / CONFIG_MX27_CLK32) - -static inline unsigned long long tick_to_time(unsigned long long tick) -{ - do_div(tick, TICK_PER_TIME); - return tick; -} - -static inline unsigned long long time_to_tick(unsigned long long time) -{ - return time * TICK_PER_TIME; -} - -static inline unsigned long long us_to_tick(unsigned long long us) -{ - us += US_PER_TICK - 1; - do_div(us, US_PER_TICK); - return us; -} -#endif - /* nothing really to do with interrupts, just starts up a counter. */ /* The 32768Hz 32-bit timer overruns in 131072 seconds */ int timer_init(void) @@ -107,56 +50,3 @@ int timer_init(void)
return 0; } - -unsigned long long get_ticks(void) -{ - struct gpt_regs *regs = (struct gpt_regs *)IMX_TIM1_BASE; - ulong now = readl(®s->gpt_tcn); /* current tick value */ - - if (now >= lastinc) { - /* - * normal mode (non roll) - * move stamp forward with absolut diff ticks - */ - timestamp += (now - lastinc); - } else { - /* we have rollover of incrementer */ - timestamp += (0xFFFFFFFF - lastinc) + now; - } - lastinc = now; - return timestamp; -} - -ulong get_timer_masked(void) -{ - /* - * get_ticks() returns a long long (64 bit), it wraps in - * 2^64 / CONFIG_MX27_CLK32 = 2^64 / 2^15 = 2^49 ~ 5 * 10^14 (s) ~ - * 5 * 10^9 days... and get_ticks() * CONFIG_SYS_HZ wraps in - * 5 * 10^6 days - long enough. - */ - return tick_to_time(get_ticks()); -} - -ulong get_timer(ulong base) -{ - return get_timer_masked() - base; -} - -/* delay x useconds AND preserve advance timstamp value */ -void __udelay(unsigned long usec) -{ - unsigned long long tmp; - ulong tmo; - - tmo = us_to_tick(usec); - tmp = get_ticks() + tmo; /* get current timestamp */ - - while (get_ticks() < tmp) /* loop till event */ - /*NOP*/; -} - -ulong get_tbclk(void) -{ - return CONFIG_MX27_CLK32; -} diff --git a/include/configs/imx27lite-common.h b/include/configs/imx27lite-common.h index 8236133..3c825df 100644 --- a/include/configs/imx27lite-common.h +++ b/include/configs/imx27lite-common.h @@ -17,6 +17,9 @@ #define CONFIG_MX27 #define CONFIG_MX27_CLK32 32768 /* OSC32K frequency */
+#define CONFIG_SYS_TIMER_RATE CONFIG_MX27_CLK32 +#define CONFIG_SYS_TIMER_COUNTER (0x10003000 + 0x10) + #define CONFIG_DISPLAY_BOARDINFO #define CONFIG_DISPLAY_CPUINFO

From: Rob Herring rob.herring@calxeda.com
Convert vexpress to use the commmon timer code.
Signed-off-by: Rob Herring rob.herring@calxeda.com --- board/armltd/vexpress/vexpress_common.c | 71 --------------------------------- include/configs/vexpress_common.h | 4 ++ 2 files changed, 4 insertions(+), 71 deletions(-)
diff --git a/board/armltd/vexpress/vexpress_common.c b/board/armltd/vexpress/vexpress_common.c index 4c7a7f4..25438fb 100644 --- a/board/armltd/vexpress/vexpress_common.c +++ b/board/armltd/vexpress/vexpress_common.c @@ -26,9 +26,6 @@ #include <asm/arch/wdt.h> #include "../drivers/mmc/arm_pl180_mmci.h"
-static ulong timestamp; -static ulong lastdec; - static struct systimer *systimer_base = (struct systimer *)V2M_TIMER01; static struct sysctrl *sysctrl_base = (struct sysctrl *)SCTL_BASE;
@@ -152,8 +149,6 @@ static void vexpress_timer_init(void) writel(SYSTIMER_EN | SYSTIMER_32BIT | readl(&systimer_base->timer0control), &systimer_base->timer0control); - - reset_timer_masked(); }
int v2m_cfg_write(u32 devfn, u32 data) @@ -183,62 +178,6 @@ void reset_cpu(ulong addr) printf("Unable to reboot\n"); }
-/* - * Delay x useconds AND perserve advance timstamp value - * assumes timer is ticking at 1 msec - */ -void __udelay(ulong usec) -{ - ulong tmo, tmp; - - tmo = usec / 1000; - tmp = get_timer(0); /* get current timestamp */ - - /* - * If setting this forward will roll time stamp then - * reset "advancing" timestamp to 0 and set lastdec value - * otherwise set the advancing stamp to the wake up time - */ - if ((tmo + tmp + 1) < tmp) - reset_timer_masked(); - else - tmo += tmp; - - while (get_timer_masked() < tmo) - ; /* loop till wakeup event */ -} - -ulong get_timer(ulong base) -{ - return get_timer_masked() - base; -} - -void reset_timer_masked(void) -{ - lastdec = readl(&systimer_base->timer0value) / 1000; - timestamp = 0; -} - -ulong get_timer_masked(void) -{ - ulong now = readl(&systimer_base->timer0value) / 1000; - - if (lastdec >= now) { /* normal mode (non roll) */ - timestamp += lastdec - now; - } else { /* count down timer overflowed */ - /* - * nts = ts + ld - now - * ts = old stamp, ld = time before passing through - 1 - * now = amount of time after passing though - 1 - * nts = new "advancing time stamp" - */ - timestamp += lastdec + SYSTIMER_RELOAD - now; - } - lastdec = now; - - return timestamp; -} - void lowlevel_init(void) { } @@ -246,13 +185,3 @@ void lowlevel_init(void) ulong get_board_rev(void){ return readl((u32 *)SYS_ID); } - -unsigned long long get_ticks(void) -{ - return get_timer(0); -} - -ulong get_tbclk(void) -{ - return (ulong)CONFIG_SYS_HZ; -} diff --git a/include/configs/vexpress_common.h b/include/configs/vexpress_common.h index 5b0721c..f204551 100644 --- a/include/configs/vexpress_common.h +++ b/include/configs/vexpress_common.h @@ -131,6 +131,10 @@ #define SCTL_BASE V2M_SYSCTL #define VEXPRESS_FLASHPROG_FLVPPEN (1 << 0)
+#define CONFIG_SYS_TIMER_RATE 1000000 +#define CONFIG_SYS_TIMER_COUNTER (0x10011000 + 0x4) +#define CONFIG_SYS_TIMER_COUNTS_DOWN + /* SMSC9115 Ethernet from SMSC9118 family */ #define CONFIG_SMC911X 1 #define CONFIG_SMC911X_32_BIT 1

From: Rob Herring rob.herring@calxeda.com
Convert socfpga to use the commmon timer code.
Signed-off-by: Rob Herring rob.herring@calxeda.com --- arch/arm/cpu/armv7/socfpga/timer.c | 72 -------------------------------------- include/configs/socfpga_cyclone5.h | 3 +- 2 files changed, 2 insertions(+), 73 deletions(-)
diff --git a/arch/arm/cpu/armv7/socfpga/timer.c b/arch/arm/cpu/armv7/socfpga/timer.c index 09f6f14..58fc789 100644 --- a/arch/arm/cpu/armv7/socfpga/timer.c +++ b/arch/arm/cpu/armv7/socfpga/timer.c @@ -8,8 +8,6 @@ #include <asm/io.h> #include <asm/arch/timer.h>
-DECLARE_GLOBAL_DATA_PTR; - static const struct socfpga_timer *timer_base = (void *)CONFIG_SYS_TIMERBASE;
/* @@ -22,73 +20,3 @@ int timer_init(void) writel(readl(&timer_base->ctrl) | 0x3, &timer_base->ctrl); return 0; } - -static u32 read_timer(void) -{ - return readl(&timer_base->curr_val); -} - -/* - * Delay x useconds - */ -void __udelay(unsigned long usec) -{ - unsigned long now, last; - /* - * get the tmo value based on timer clock speed - * tmo = delay required / period of timer clock - */ - long tmo = usec * CONFIG_TIMER_CLOCK_KHZ / 1000; - - last = read_timer(); - while (tmo > 0) { - now = read_timer(); - if (last >= now) - /* normal mode (non roll) */ - tmo -= last - now; - else - /* we have overflow of the count down timer */ - tmo -= TIMER_LOAD_VAL - last + now; - last = now; - } -} - -/* - * Get the timer value - */ -ulong get_timer(ulong base) -{ - return get_timer_masked() - base; -} - -/* - * Timer : get the time difference - * Unit of tick is based on the CONFIG_SYS_HZ - */ -ulong get_timer_masked(void) -{ - /* current tick value */ - ulong now = read_timer() / (CONFIG_TIMER_CLOCK_KHZ/CONFIG_SYS_HZ); - if (gd->arch.lastinc >= now) { - /* normal mode (non roll) */ - /* move stamp forward with absolute diff ticks */ - gd->arch.tbl += gd->arch.lastinc - now; - } else { - /* we have overflow of the count down timer */ - gd->arch.tbl += TIMER_LOAD_VAL - gd->arch.lastinc + now; - } - gd->arch.lastinc = now; - return gd->arch.tbl; -} - -/* - * Reset the timer - */ -void reset_timer(void) -{ - /* capture current decrementer value time */ - gd->arch.lastinc = read_timer() / - (CONFIG_TIMER_CLOCK_KHZ / CONFIG_SYS_HZ); - /* start "advancing" time stamp from 0 */ - gd->arch.tbl = 0; -} diff --git a/include/configs/socfpga_cyclone5.h b/include/configs/socfpga_cyclone5.h index 450b5e6..aecb217 100644 --- a/include/configs/socfpga_cyclone5.h +++ b/include/configs/socfpga_cyclone5.h @@ -24,7 +24,8 @@ #define CONFIG_SYS_TEXT_BASE 0x08000040 #define V_NS16550_CLK 1000000 #define CONFIG_BAUDRATE 57600 -#define CONFIG_TIMER_CLOCK_KHZ 2400 +#define CONFIG_SYS_TIMER_RATE 2400000 +#define CONFIG_SYS_TIMER_COUNTER (CONFIG_SYS_TIMERBASE + 0x4) #define CONFIG_SYS_LOAD_ADDR 0x7fc0
/* Console I/O Buffer Size */

From: Rob Herring rob.herring@calxeda.com
Convert tegra to use the commmon timer code.
Signed-off-by: Rob Herring rob.herring@calxeda.com --- arch/arm/cpu/tegra-common/Makefile | 2 +- arch/arm/cpu/tegra-common/timer.c | 95 -------------------------------------- include/configs/tegra-common.h | 3 ++ 3 files changed, 4 insertions(+), 96 deletions(-) delete mode 100644 arch/arm/cpu/tegra-common/timer.c
diff --git a/arch/arm/cpu/tegra-common/Makefile b/arch/arm/cpu/tegra-common/Makefile index 1b6cdf7..89b2210 100644 --- a/arch/arm/cpu/tegra-common/Makefile +++ b/arch/arm/cpu/tegra-common/Makefile @@ -12,7 +12,7 @@ include $(TOPDIR)/config.mk LIB = $(obj)libcputegra-common.o
SOBJS += lowlevel_init.o -COBJS-y += ap.o board.o sys_info.o timer.o clock.o cache.o +COBJS-y += ap.o board.o sys_info.o clock.o cache.o
SRCS := $(SOBJS:.o=.S) $(COBJS-y:.o=.c) OBJS := $(addprefix $(obj),$(SOBJS) $(COBJS-y)) diff --git a/arch/arm/cpu/tegra-common/timer.c b/arch/arm/cpu/tegra-common/timer.c deleted file mode 100644 index d0f783e..0000000 --- a/arch/arm/cpu/tegra-common/timer.c +++ /dev/null @@ -1,95 +0,0 @@ -/* - * (C) Copyright 2010,2011 - * NVIDIA Corporation <www.nvidia.com> - * - * (C) Copyright 2008 - * Texas Instruments - * - * Richard Woodruff r-woodruff2@ti.com - * Syed Moahmmed Khasim khasim@ti.com - * - * (C) Copyright 2002 - * Sysgo Real-Time Solutions, GmbH <www.elinos.com> - * Marius Groeger mgroeger@sysgo.de - * Alex Zuepke azu@sysgo.de - * - * (C) Copyright 2002 - * Gary Jennejohn, DENX Software Engineering, garyj@denx.de - * - * SPDX-License-Identifier: GPL-2.0+ - */ - -#include <common.h> -#include <asm/io.h> -#include <asm/arch/tegra.h> -#include <asm/arch-tegra/timer.h> - -DECLARE_GLOBAL_DATA_PTR; - -/* counter runs at 1MHz */ -#define TIMER_CLK 1000000 -#define TIMER_LOAD_VAL 0xffffffff - -/* timer without interrupts */ -ulong get_timer(ulong base) -{ - return get_timer_masked() - base; -} - -/* delay x useconds */ -void __udelay(unsigned long usec) -{ - long tmo = usec * (TIMER_CLK / 1000) / 1000; - unsigned long now, last = timer_get_us(); - - while (tmo > 0) { - now = timer_get_us(); - if (last > now) /* count up timer overflow */ - tmo -= TIMER_LOAD_VAL - last + now; - else - tmo -= now - last; - last = now; - } -} - -ulong get_timer_masked(void) -{ - ulong now; - - /* current tick value */ - now = timer_get_us() / (TIMER_CLK / CONFIG_SYS_HZ); - - if (now >= gd->arch.lastinc) /* normal mode (non roll) */ - /* move stamp forward with absolute diff ticks */ - gd->arch.tbl += (now - gd->arch.lastinc); - else /* we have rollover of incrementer */ - gd->arch.tbl += ((TIMER_LOAD_VAL / (TIMER_CLK / CONFIG_SYS_HZ)) - - gd->arch.lastinc) + now; - gd->arch.lastinc = now; - return gd->arch.tbl; -} - -/* - * This function is derived from PowerPC code (read timebase as long long). - * On ARM it just returns the timer value. - */ -unsigned long long get_ticks(void) -{ - return get_timer(0); -} - -/* - * This function is derived from PowerPC code (timebase clock frequency). - * On ARM it returns the number of timer ticks per second. - */ -ulong get_tbclk(void) -{ - return CONFIG_SYS_HZ; -} - -unsigned long timer_get_us(void) -{ - struct timerus *timer_base = (struct timerus *)NV_PA_TMRUS_BASE; - - return readl(&timer_base->cntr_1us); -} diff --git a/include/configs/tegra-common.h b/include/configs/tegra-common.h index e75e8cc..c605dd0 100644 --- a/include/configs/tegra-common.h +++ b/include/configs/tegra-common.h @@ -21,6 +21,9 @@
#include <asm/arch/tegra.h> /* get chip and board defs */
+#define CONFIG_SYS_TIMER_RATE 1000000 +#define CONFIG_SYS_TIMER_COUNTER NV_PA_TMRUS_BASE + /* * Display CPU and Board information */

Dear Rob Herring,
In message 1378671174-18535-1-git-send-email-robherring2@gmail.com you wrote:
From: Rob Herring rob.herring@calxeda.com
Much of the ARM timer code is re-implemented for each platform yet it is all pretty much the same code.
This series introduces a common implementation of timer functions and simplifies the platform code down to 2 or 3 config defines. It is intended for platforms with 32-bit freerunning timers. I've converted a couple of platforms as an example, but there are many more still that can be converted. This probably could be extended to work with 16-bit timers as well.
I've compiled all ARM boards, but only tested on highbank.
Why do we need any ARM specific code at all? What's the difference between an ARM and - say - a PowerPC system in this respect, and why do we need different code for both?
If we consolidate code, it should always be done in a cross-platform way, unless platform specifc code really cannot be avoided (which I fail to see yet here).
Best regards,
Wolfgang Denk

On 09/09/2013 12:53 AM, Wolfgang Denk wrote:
Dear Rob Herring,
In message 1378671174-18535-1-git-send-email-robherring2@gmail.com you wrote:
From: Rob Herring rob.herring@calxeda.com
Much of the ARM timer code is re-implemented for each platform yet it is all pretty much the same code.
This series introduces a common implementation of timer functions and simplifies the platform code down to 2 or 3 config defines. It is intended for platforms with 32-bit freerunning timers. I've converted a couple of platforms as an example, but there are many more still that can be converted. This probably could be extended to work with 16-bit timers as well.
I've compiled all ARM boards, but only tested on highbank.
Why do we need any ARM specific code at all? What's the difference between an ARM and - say - a PowerPC system in this respect, and why do we need different code for both?
If we consolidate code, it should always be done in a cross-platform way, unless platform specifc code really cannot be avoided (which I fail to see yet here).
I agree, but it appeared that at least some PPC platforms implement timers differently using a timer interrupt. I haven't really looked at other architectures. At least moving the code to a common spot is trivial. Aside from the location, do you have any comments on the implementation?
Rob

Dear Rob Herring,
In message 522DE0B3.20201@gmail.com you wrote:
If we consolidate code, it should always be done in a cross-platform way, unless platform specifc code really cannot be avoided (which I fail to see yet here).
I agree, but it appeared that at least some PPC platforms implement timers differently using a timer interrupt. I haven't really looked at
Correct, PPC uses the decrementer with interrupts.
other architectures. At least moving the code to a common spot is trivial. Aside from the location, do you have any comments on the implementation?
Only very cursory.
Best regards,
Wolfgang Denk

Hi Rob,
From: Rob Herring rob.herring@calxeda.com
Much of the ARM timer code is re-implemented for each platform yet it is all pretty much the same code.
This series introduces a common implementation of timer functions and simplifies the platform code down to 2 or 3 config defines. It is intended for platforms with 32-bit freerunning timers. I've converted a couple of platforms as an example, but there are many more still that can be converted. This probably could be extended to work with 16-bit timers as well.
I'm wondering if we could also move the Exynos related timer code to ./arch/arm/lib/time.c?
Anyway, Rob very good idea!
I've compiled all ARM boards, but only tested on highbank.
Rob
Rob Herring (9): ARM: add common timer functions examples: enable gc-sections option time: create default __udelay ARM: highbank: convert to common timer code ARM: mx25: convert to common timer code ARM: mx27: convert to common timer code ARM: vexpress: convert to common timer code ARM: socfpga: convert to common timer code ARM: tegra: convert to common timer code
arch/arm/cpu/arm926ejs/mx25/timer.c | 117
arch/arm/cpu/arm926ejs/mx27/timer.c | 110
arch/arm/cpu/armv7/highbank/timer.c | 83 ---------------------- arch/arm/cpu/armv7/socfpga/timer.c | 72 -------------------- arch/arm/cpu/tegra-common/Makefile | 2 +- arch/arm/cpu/tegra-common/timer.c | 95 -------------------------- arch/arm/lib/Makefile | 2 +- arch/arm/lib/time.c | 59 ++++++++++++++++ board/armltd/vexpress/vexpress_common.c | 71 ------------------- examples/api/Makefile | 2 +- include/configs/highbank.h | 4 ++ include/configs/imx27lite-common.h | 3 + include/configs/mx25pdk.h | 3 + include/configs/socfpga_cyclone5.h | 3 +- include/configs/tegra-common.h | 3 + include/configs/tx25.h | 2 + include/configs/vexpress_common.h | 4 ++ include/configs/zmx25.h | 3 + lib/time.c | 21 ++++++ 19 files changed, 107 insertions(+), 552 deletions(-) delete mode 100644 arch/arm/cpu/tegra-common/timer.c create mode 100644 arch/arm/lib/time.c

On Mon, Sep 9, 2013 at 2:13 AM, Lukasz Majewski l.majewski@samsung.com wrote:
Hi Rob,
From: Rob Herring rob.herring@calxeda.com
Much of the ARM timer code is re-implemented for each platform yet it is all pretty much the same code.
This series introduces a common implementation of timer functions and simplifies the platform code down to 2 or 3 config defines. It is intended for platforms with 32-bit freerunning timers. I've converted a couple of platforms as an example, but there are many more still that can be converted. This probably could be extended to work with 16-bit timers as well.
I'm wondering if we could also move the Exynos related timer code to ./arch/arm/lib/time.c?
Most likely yes. I don't intend to sloth thru all the implementations, so patches welcome. :)
Rob

From: Rob Herring rob.herring@calxeda.com
Much of the timer code is re-implemented for each platform/arch yet it is all pretty much the same code.
This series introduces a common implementation of timer functions and simplifies the platform code down to 2 or 3 config defines or 2 simple functions. It is intended for platforms with 32-bit freerunning timers. I've converted SH and a couple of ARM platforms as an example, but there are many more still that can be converted. This probably could be extended to work with 16-bit timers as well.
I've compiled on ARM, SH4, and PPC.
v2: - Make timer code common for all architectures - Convert SH timer to common code - Drop mx27 due to include mess. - Add converting versatile to common code
Rob
Rob Herring (9): examples: enable gc-sections option Introduce common timer functions sh: convert to common timer code ARM: highbank: convert to common timer code ARM: mx25: convert to common timer code ARM: vexpress: convert to common timer code ARM: socfpga: convert to common timer code ARM: tegra: convert to common timer code ARM: versatile: convert to common timer code
arch/arm/cpu/arm926ejs/mx25/timer.c | 117 ------------------------------- arch/arm/cpu/arm926ejs/versatile/timer.c | 116 ------------------------------ arch/arm/cpu/armv7/highbank/timer.c | 83 ---------------------- arch/arm/cpu/armv7/socfpga/timer.c | 72 ------------------- arch/arm/cpu/tegra-common/Makefile | 2 +- arch/arm/cpu/tegra-common/timer.c | 95 ------------------------- arch/sh/lib/time.c | 61 +--------------- board/armltd/vexpress/vexpress_common.c | 71 ------------------- examples/api/Makefile | 2 +- include/asm-generic/global_data.h | 2 + include/configs/highbank.h | 4 ++ include/configs/mx25pdk.h | 4 ++ include/configs/socfpga_cyclone5.h | 5 +- include/configs/tegra-common.h | 3 + include/configs/tx25.h | 5 +- include/configs/versatile.h | 9 ++- include/configs/vexpress_common.h | 4 ++ include/configs/zmx25.h | 6 ++ lib/time.c | 73 +++++++++++++++++++ 19 files changed, 111 insertions(+), 623 deletions(-) delete mode 100644 arch/arm/cpu/tegra-common/timer.c

From: Rob Herring rob.herring@calxeda.com
This fixes building time.c when unreferenced functions are added.
Signed-off-by: Rob Herring rob.herring@calxeda.com --- examples/api/Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/examples/api/Makefile b/examples/api/Makefile index 4d68340..33cc91b 100644 --- a/examples/api/Makefile +++ b/examples/api/Makefile @@ -53,7 +53,7 @@ all: $(obj).depend $(OUTPUT) #########################################################################
$(OUTPUT): $(OBJS) - $(LD) -Ttext $(LOAD_ADDR) -o $@ $^ $(PLATFORM_LIBS) + $(LD) --gc-sections -Ttext $(LOAD_ADDR) -o $@ $^ $(PLATFORM_LIBS) $(OBJCOPY) -O binary $@ $(OUTPUT).bin 2>/dev/null
# Rule to build generic library C files

From: Rob Herring rob.herring@calxeda.com
Many platforms duplicate pretty much the same timer code yet they all have a 32-bit freerunning counter register. Create a common implementation that minimally requires 2 or 3 defines to add timer support:
CONFIG_SYS_TIMER_RATE - Clock rate of the timer counter CONFIG_SYS_TIMER_COUNTER - Address of 32-bit counter CONFIG_SYS_TIMER_COUNTS_DOWN - Define if counter counts down
All functions are weak or ifdef'ed so they can still be overriden by any platform.
Signed-off-by: Rob Herring rob.herring@calxeda.com --- v2: - Move to common location for all arches - Add extern timer_read_counter declaration - Add new global data timebase_h and timebase_l
include/asm-generic/global_data.h | 2 ++ lib/time.c | 73 +++++++++++++++++++++++++++++++++++++++ 2 files changed, 75 insertions(+)
diff --git a/include/asm-generic/global_data.h b/include/asm-generic/global_data.h index 77e06fb..0de0bea 100644 --- a/include/asm-generic/global_data.h +++ b/include/asm-generic/global_data.h @@ -72,6 +72,8 @@ typedef struct global_data { #if defined(CONFIG_SYS_I2C) int cur_i2c_bus; /* current used i2c bus */ #endif + unsigned long timebase_h; + unsigned long timebase_l; struct arch_global_data arch; /* architecture-specific data */ } gd_t; #endif diff --git a/lib/time.c b/lib/time.c index 68b8ff4..761272a 100644 --- a/lib/time.c +++ b/lib/time.c @@ -7,11 +7,84 @@
#include <common.h> #include <watchdog.h> +#include <div64.h> +#include <asm/io.h>
#ifndef CONFIG_WD_PERIOD # define CONFIG_WD_PERIOD (10 * 1000 * 1000) /* 10 seconds default*/ #endif
+DECLARE_GLOBAL_DATA_PTR; + +#ifdef CONFIG_SYS_TIMER_RATE +ulong notrace get_tbclk(void) +{ + return CONFIG_SYS_TIMER_RATE; +} +#endif + +#ifdef CONFIG_SYS_TIMER_COUNTER +unsigned long notrace timer_read_counter(void) +{ +#ifdef CONFIG_SYS_TIMER_COUNTS_DOWN + return ~readl(CONFIG_SYS_TIMER_COUNTER); +#else + return readl(CONFIG_SYS_TIMER_COUNTER); +#endif +} +#else +extern unsigned long timer_read_counter(void); +#endif + +unsigned long long __weak notrace get_ticks(void) +{ + unsigned long now = timer_read_counter(); + + /* increment tbu if tbl has rolled over */ + if (now < gd->timebase_l) + gd->timebase_h++; + gd->timebase_l = now; + return ((unsigned long long)gd->timebase_h << 32) | gd->timebase_l; +} + +static unsigned long long notrace tick_to_time(unsigned long long tick) +{ + unsigned int div = get_tbclk(); + + tick *= CONFIG_SYS_HZ; + do_div(tick, div); + return tick; +} + +ulong __weak get_timer(ulong base) +{ + return tick_to_time(get_ticks()) - base; +} + +unsigned long __weak notrace timer_get_us(void) +{ + return tick_to_time(get_ticks() * 1000); +} +static unsigned long long usec_to_tick(unsigned long usec) +{ + unsigned long long tick = usec * get_tbclk(); + usec *= get_tbclk(); + do_div(tick, 1000000); + return tick; +} + +void __weak __udelay(unsigned long usec) +{ + unsigned long long tmp; + ulong tmo; + + tmo = usec_to_tick(usec); + tmp = get_ticks() + tmo; /* get current timestamp */ + + while (get_ticks() < tmp) /* loop till event */ + /*NOP*/; +} + /* ------------------------------------------------------------------------- */
void udelay(unsigned long usec)

From: Rob Herring rob.herring@calxeda.com
Convert sh to use the commmon timer code. Remove reset_timer and set_timer as they are unused on sh.
Signed-off-by: Rob Herring rob.herring@calxeda.com --- arch/sh/lib/time.c | 61 ++---------------------------------------------------- 1 file changed, 2 insertions(+), 59 deletions(-)
diff --git a/arch/sh/lib/time.c b/arch/sh/lib/time.c index 1fe537e..b182dd2 100644 --- a/arch/sh/lib/time.c +++ b/arch/sh/lib/time.c @@ -12,7 +12,6 @@ */
#include <common.h> -#include <div64.h> #include <asm/processor.h> #include <asm/io.h> #include <sh_tmu.h> @@ -20,28 +19,15 @@ static struct tmu_regs *tmu = (struct tmu_regs *)TMU_BASE;
static u16 bit; -static unsigned long last_tcnt; -static unsigned long long overflow_ticks;
unsigned long get_tbclk(void) { return get_tmu0_clk_rate() >> ((bit + 1) * 2); }
-static inline unsigned long long tick_to_time(unsigned long long tick) +unsigned long timer_read_counter(void) { - tick *= CONFIG_SYS_HZ; - do_div(tick, get_tbclk()); - - return tick; -} - -static inline unsigned long long usec_to_tick(unsigned long long usec) -{ - usec *= get_tbclk(); - do_div(usec, 1000000); - - return usec; + return ~readl(&tmu->tcnt0); }
static void tmu_timer_start(unsigned int timer) @@ -66,49 +52,6 @@ int timer_init(void) tmu_timer_stop(0); tmu_timer_start(0);
- last_tcnt = 0; - overflow_ticks = 0; - return 0; }
-unsigned long long get_ticks(void) -{ - unsigned long tcnt = 0 - readl(&tmu->tcnt0); - - if (last_tcnt > tcnt) /* overflow */ - overflow_ticks++; - last_tcnt = tcnt; - - return (overflow_ticks << 32) | tcnt; -} - -void __udelay(unsigned long usec) -{ - unsigned long long tmp; - ulong tmo; - - tmo = usec_to_tick(usec); - tmp = get_ticks() + tmo; /* get current timestamp */ - - while (get_ticks() < tmp) /* loop till event */ - /*NOP*/; -} - -unsigned long get_timer(unsigned long base) -{ - /* return msec */ - return tick_to_time(get_ticks()) - base; -} - -void set_timer(unsigned long t) -{ - writel((0 - t), &tmu->tcnt0); -} - -void reset_timer(void) -{ - tmu_timer_stop(0); - set_timer(0); - tmu_timer_start(0); -}

From: Rob Herring rob.herring@calxeda.com
Convert highbank to use the commmon timer code.
Signed-off-by: Rob Herring rob.herring@calxeda.com --- arch/arm/cpu/armv7/highbank/timer.c | 83 ------------------------------------- include/configs/highbank.h | 4 ++ 2 files changed, 4 insertions(+), 83 deletions(-)
diff --git a/arch/arm/cpu/armv7/highbank/timer.c b/arch/arm/cpu/armv7/highbank/timer.c index b61cd69..d56bf21 100644 --- a/arch/arm/cpu/armv7/highbank/timer.c +++ b/arch/arm/cpu/armv7/highbank/timer.c @@ -7,18 +7,12 @@ */
#include <common.h> -#include <div64.h> -#include <linux/types.h> /* for size_t */ -#include <linux/stddef.h> /* for NULL */ #include <asm/io.h> #include <asm/arch-armv7/systimer.h>
#undef SYSTIMER_BASE #define SYSTIMER_BASE 0xFFF34000 /* Timer 0 and 1 base */ -#define SYSTIMER_RATE (150000000 / 256)
-static ulong timestamp; -static ulong lastinc; static struct systimer *systimer_base = (struct systimer *)SYSTIMER_BASE;
/* @@ -38,80 +32,3 @@ int timer_init(void) return 0;
} - -#define TICK_PER_TIME ((SYSTIMER_RATE + CONFIG_SYS_HZ / 2) / CONFIG_SYS_HZ) -#define NS_PER_TICK (1000000000 / SYSTIMER_RATE) - -static inline unsigned long long tick_to_time(unsigned long long tick) -{ - do_div(tick, TICK_PER_TIME); - return tick; -} - -static inline unsigned long long time_to_tick(unsigned long long time) -{ - return time * TICK_PER_TIME; -} - -static inline unsigned long long us_to_tick(unsigned long long us) -{ - unsigned long long tick = us * 1000; - tick += NS_PER_TICK - 1; - do_div(tick, NS_PER_TICK); - return tick; -} - -unsigned long long get_ticks(void) -{ - ulong now = ~readl(&systimer_base->timer0value); - - if (now >= lastinc) /* normal mode (non roll) */ - /* move stamp forward with absolut diff ticks */ - timestamp += (now - lastinc); - else /* we have rollover of incrementer */ - timestamp += (0xFFFFFFFF - lastinc) + now; - lastinc = now; - return timestamp; -} - -/* - * Delay x useconds AND preserve advance timstamp value - * assumes timer is ticking at 1 msec - */ -void __udelay(ulong usec) -{ - unsigned long long tmp; - ulong tmo; - - tmo = us_to_tick(usec); - tmp = get_ticks() + tmo; /* get current timestamp */ - - while (get_ticks() < tmp) /* loop till event */ - /*NOP*/; -} - -ulong get_timer(ulong base) -{ - return get_timer_masked() - base; -} - -void reset_timer_masked(void) -{ - lastinc = ~readl(&systimer_base->timer0value); - timestamp = 0; -} - -void reset_timer(void) -{ - reset_timer_masked(); -} - -ulong get_timer_masked(void) -{ - return tick_to_time(get_ticks()); -} - -ulong get_tbclk(void) -{ - return SYSTIMER_RATE; -} diff --git a/include/configs/highbank.h b/include/configs/highbank.h index afb6e64..2504c42 100644 --- a/include/configs/highbank.h +++ b/include/configs/highbank.h @@ -21,6 +21,10 @@ #define CONFIG_SUPPORT_RAW_INITRD #define CONFIG_SYS_BOOTMAPSZ (16 << 20)
+#define CONFIG_SYS_TIMER_RATE (150000000/256) +#define CONFIG_SYS_TIMER_COUNTER (0xFFF34000 + 0x4) +#define CONFIG_SYS_TIMER_COUNTS_DOWN + /* * Size of malloc() pool */

From: Rob Herring rob.herring@calxeda.com
Convert mx25 to use the commmon timer code.
Signed-off-by: Rob Herring rob.herring@calxeda.com ---
v2: - Use GPT struct for register offset
arch/arm/cpu/arm926ejs/mx25/timer.c | 117 ------------------------------------ include/configs/mx25pdk.h | 4 ++ include/configs/tx25.h | 5 +- include/configs/zmx25.h | 6 ++ 4 files changed, 14 insertions(+), 118 deletions(-)
diff --git a/arch/arm/cpu/arm926ejs/mx25/timer.c b/arch/arm/cpu/arm926ejs/mx25/timer.c index 42b6076..7f19791 100644 --- a/arch/arm/cpu/arm926ejs/mx25/timer.c +++ b/arch/arm/cpu/arm926ejs/mx25/timer.c @@ -21,65 +21,8 @@ */
#include <common.h> -#include <div64.h> #include <asm/io.h> #include <asm/arch/imx-regs.h> -#include <asm/arch/clock.h> - -DECLARE_GLOBAL_DATA_PTR; - -#define timestamp (gd->arch.tbl) -#define lastinc (gd->arch.lastinc) - -/* - * "time" is measured in 1 / CONFIG_SYS_HZ seconds, - * "tick" is internal timer period - */ -#ifdef CONFIG_MX25_TIMER_HIGH_PRECISION -/* ~0.4% error - measured with stop-watch on 100s boot-delay */ -static inline unsigned long long tick_to_time(unsigned long long tick) -{ - tick *= CONFIG_SYS_HZ; - do_div(tick, MXC_CLK32); - return tick; -} - -static inline unsigned long long time_to_tick(unsigned long long time) -{ - time *= MXC_CLK32; - do_div(time, CONFIG_SYS_HZ); - return time; -} - -static inline unsigned long long us_to_tick(unsigned long long us) -{ - us = us * MXC_CLK32 + 999999; - do_div(us, 1000000); - return us; -} -#else -/* ~2% error */ -#define TICK_PER_TIME ((MXC_CLK32 + CONFIG_SYS_HZ / 2) / CONFIG_SYS_HZ) -#define US_PER_TICK (1000000 / MXC_CLK32) - -static inline unsigned long long tick_to_time(unsigned long long tick) -{ - do_div(tick, TICK_PER_TIME); - return tick; -} - -static inline unsigned long long time_to_tick(unsigned long long time) -{ - return time * TICK_PER_TIME; -} - -static inline unsigned long long us_to_tick(unsigned long long us) -{ - us += US_PER_TICK - 1; - do_div(us, US_PER_TICK); - return us; -} -#endif
/* nothing really to do with interrupts, just starts up a counter. */ /* The 32KHz 32-bit timer overruns in 134217 seconds */ @@ -104,63 +47,3 @@ int timer_init(void)
return 0; } - -unsigned long long get_ticks(void) -{ - struct gpt_regs *gpt = (struct gpt_regs *)IMX_GPT1_BASE; - ulong now = readl(&gpt->counter); /* current tick value */ - - if (now >= lastinc) { - /* - * normal mode (non roll) - * move stamp forward with absolut diff ticks - */ - timestamp += (now - lastinc); - } else { - /* we have rollover of incrementer */ - timestamp += (0xFFFFFFFF - lastinc) + now; - } - lastinc = now; - return timestamp; -} - -ulong get_timer_masked(void) -{ - /* - * get_ticks() returns a long long (64 bit), it wraps in - * 2^64 / MXC_CLK32 = 2^64 / 2^15 = 2^49 ~ 5 * 10^14 (s) ~ - * 5 * 10^9 days... and get_ticks() * CONFIG_SYS_HZ wraps in - * 5 * 10^6 days - long enough. - */ - return tick_to_time(get_ticks()); -} - -ulong get_timer(ulong base) -{ - return get_timer_masked() - base; -} - -/* delay x useconds AND preserve advance timstamp value */ -void __udelay(unsigned long usec) -{ - unsigned long long tmp; - ulong tmo; - - tmo = us_to_tick(usec); - tmp = get_ticks() + tmo; /* get current timestamp */ - - while (get_ticks() < tmp) /* loop till event */ - /*NOP*/; -} - -/* - * This function is derived from PowerPC code (timebase clock frequency). - * On ARM it returns the number of timer ticks per second. - */ -ulong get_tbclk(void) -{ - ulong tbclk; - - tbclk = MXC_CLK32; - return tbclk; -} diff --git a/include/configs/mx25pdk.h b/include/configs/mx25pdk.h index 543c415..0a9f442 100644 --- a/include/configs/mx25pdk.h +++ b/include/configs/mx25pdk.h @@ -16,6 +16,10 @@ #define CONFIG_SYS_TEXT_BASE 0x81200000 #define CONFIG_MXC_GPIO
+#define CONFIG_SYS_TIMER_RATE 32768 +#define CONFIG_SYS_TIMER_COUNTER \ + (&((struct gpt_regs *)IMX_GPT1_BASE)->counter) + #define CONFIG_DISPLAY_CPUINFO #define CONFIG_DISPLAY_BOARDINFO
diff --git a/include/configs/tx25.h b/include/configs/tx25.h index 93dd3c5..beea612 100644 --- a/include/configs/tx25.h +++ b/include/configs/tx25.h @@ -16,6 +16,9 @@ #define CONFIG_MX25 #define CONFIG_MX25_CLK32 32000 /* OSC32K frequency */ #define CONFIG_SYS_HZ 1000 +#define CONFIG_SYS_TIMER_RATE CONFIG_MX25_CLK32 +#define CONFIG_SYS_TIMER_COUNTER \ + (&((struct gpt_regs *)IMX_GPT1_BASE)->counter)
#define CONFIG_SYS_MONITOR_LEN (256 << 10) /* 256 kB for U-Boot */
diff --git a/include/configs/zmx25.h b/include/configs/zmx25.h index 765b849..ee48429 100644 --- a/include/configs/zmx25.h +++ b/include/configs/zmx25.h @@ -10,11 +10,17 @@ #ifndef __CONFIG_H #define __CONFIG_H
+#include <asm/arch/imx-regs.h> + #define CONFIG_ARM926EJS /* arm926ejs CPU core */ #define CONFIG_MX25 #define CONFIG_SYS_HZ 1000 #define CONFIG_SYS_TEXT_BASE 0xA0000000
+#define CONFIG_SYS_TIMER_RATE 32768 +#define CONFIG_SYS_TIMER_COUNTER \ + (&((struct gpt_regs *)IMX_GPT1_BASE)->counter) + #define CONFIG_MACH_TYPE MACH_TYPE_ZMX25 /* * Environment settings

From: Rob Herring rob.herring@calxeda.com
Convert vexpress to use the commmon timer code.
Signed-off-by: Rob Herring rob.herring@calxeda.com --- board/armltd/vexpress/vexpress_common.c | 71 --------------------------------- include/configs/vexpress_common.h | 4 ++ 2 files changed, 4 insertions(+), 71 deletions(-)
diff --git a/board/armltd/vexpress/vexpress_common.c b/board/armltd/vexpress/vexpress_common.c index 4c7a7f4..25438fb 100644 --- a/board/armltd/vexpress/vexpress_common.c +++ b/board/armltd/vexpress/vexpress_common.c @@ -26,9 +26,6 @@ #include <asm/arch/wdt.h> #include "../drivers/mmc/arm_pl180_mmci.h"
-static ulong timestamp; -static ulong lastdec; - static struct systimer *systimer_base = (struct systimer *)V2M_TIMER01; static struct sysctrl *sysctrl_base = (struct sysctrl *)SCTL_BASE;
@@ -152,8 +149,6 @@ static void vexpress_timer_init(void) writel(SYSTIMER_EN | SYSTIMER_32BIT | readl(&systimer_base->timer0control), &systimer_base->timer0control); - - reset_timer_masked(); }
int v2m_cfg_write(u32 devfn, u32 data) @@ -183,62 +178,6 @@ void reset_cpu(ulong addr) printf("Unable to reboot\n"); }
-/* - * Delay x useconds AND perserve advance timstamp value - * assumes timer is ticking at 1 msec - */ -void __udelay(ulong usec) -{ - ulong tmo, tmp; - - tmo = usec / 1000; - tmp = get_timer(0); /* get current timestamp */ - - /* - * If setting this forward will roll time stamp then - * reset "advancing" timestamp to 0 and set lastdec value - * otherwise set the advancing stamp to the wake up time - */ - if ((tmo + tmp + 1) < tmp) - reset_timer_masked(); - else - tmo += tmp; - - while (get_timer_masked() < tmo) - ; /* loop till wakeup event */ -} - -ulong get_timer(ulong base) -{ - return get_timer_masked() - base; -} - -void reset_timer_masked(void) -{ - lastdec = readl(&systimer_base->timer0value) / 1000; - timestamp = 0; -} - -ulong get_timer_masked(void) -{ - ulong now = readl(&systimer_base->timer0value) / 1000; - - if (lastdec >= now) { /* normal mode (non roll) */ - timestamp += lastdec - now; - } else { /* count down timer overflowed */ - /* - * nts = ts + ld - now - * ts = old stamp, ld = time before passing through - 1 - * now = amount of time after passing though - 1 - * nts = new "advancing time stamp" - */ - timestamp += lastdec + SYSTIMER_RELOAD - now; - } - lastdec = now; - - return timestamp; -} - void lowlevel_init(void) { } @@ -246,13 +185,3 @@ void lowlevel_init(void) ulong get_board_rev(void){ return readl((u32 *)SYS_ID); } - -unsigned long long get_ticks(void) -{ - return get_timer(0); -} - -ulong get_tbclk(void) -{ - return (ulong)CONFIG_SYS_HZ; -} diff --git a/include/configs/vexpress_common.h b/include/configs/vexpress_common.h index 75a4500..46bab0b 100644 --- a/include/configs/vexpress_common.h +++ b/include/configs/vexpress_common.h @@ -132,6 +132,10 @@ #define SCTL_BASE V2M_SYSCTL #define VEXPRESS_FLASHPROG_FLVPPEN (1 << 0)
+#define CONFIG_SYS_TIMER_RATE 1000000 +#define CONFIG_SYS_TIMER_COUNTER (0x10011000 + 0x4) +#define CONFIG_SYS_TIMER_COUNTS_DOWN + /* SMSC9115 Ethernet from SMSC9118 family */ #define CONFIG_SMC911X 1 #define CONFIG_SMC911X_32_BIT 1

From: Rob Herring rob.herring@calxeda.com
Convert socfpga to use the commmon timer code.
Signed-off-by: Rob Herring rob.herring@calxeda.com --- arch/arm/cpu/armv7/socfpga/timer.c | 72 -------------------------------------- include/configs/socfpga_cyclone5.h | 5 +-- 2 files changed, 3 insertions(+), 74 deletions(-)
diff --git a/arch/arm/cpu/armv7/socfpga/timer.c b/arch/arm/cpu/armv7/socfpga/timer.c index 09f6f14..58fc789 100644 --- a/arch/arm/cpu/armv7/socfpga/timer.c +++ b/arch/arm/cpu/armv7/socfpga/timer.c @@ -8,8 +8,6 @@ #include <asm/io.h> #include <asm/arch/timer.h>
-DECLARE_GLOBAL_DATA_PTR; - static const struct socfpga_timer *timer_base = (void *)CONFIG_SYS_TIMERBASE;
/* @@ -22,73 +20,3 @@ int timer_init(void) writel(readl(&timer_base->ctrl) | 0x3, &timer_base->ctrl); return 0; } - -static u32 read_timer(void) -{ - return readl(&timer_base->curr_val); -} - -/* - * Delay x useconds - */ -void __udelay(unsigned long usec) -{ - unsigned long now, last; - /* - * get the tmo value based on timer clock speed - * tmo = delay required / period of timer clock - */ - long tmo = usec * CONFIG_TIMER_CLOCK_KHZ / 1000; - - last = read_timer(); - while (tmo > 0) { - now = read_timer(); - if (last >= now) - /* normal mode (non roll) */ - tmo -= last - now; - else - /* we have overflow of the count down timer */ - tmo -= TIMER_LOAD_VAL - last + now; - last = now; - } -} - -/* - * Get the timer value - */ -ulong get_timer(ulong base) -{ - return get_timer_masked() - base; -} - -/* - * Timer : get the time difference - * Unit of tick is based on the CONFIG_SYS_HZ - */ -ulong get_timer_masked(void) -{ - /* current tick value */ - ulong now = read_timer() / (CONFIG_TIMER_CLOCK_KHZ/CONFIG_SYS_HZ); - if (gd->arch.lastinc >= now) { - /* normal mode (non roll) */ - /* move stamp forward with absolute diff ticks */ - gd->arch.tbl += gd->arch.lastinc - now; - } else { - /* we have overflow of the count down timer */ - gd->arch.tbl += TIMER_LOAD_VAL - gd->arch.lastinc + now; - } - gd->arch.lastinc = now; - return gd->arch.tbl; -} - -/* - * Reset the timer - */ -void reset_timer(void) -{ - /* capture current decrementer value time */ - gd->arch.lastinc = read_timer() / - (CONFIG_TIMER_CLOCK_KHZ / CONFIG_SYS_HZ); - /* start "advancing" time stamp from 0 */ - gd->arch.tbl = 0; -} diff --git a/include/configs/socfpga_cyclone5.h b/include/configs/socfpga_cyclone5.h index 06aeba6..fa49f85 100644 --- a/include/configs/socfpga_cyclone5.h +++ b/include/configs/socfpga_cyclone5.h @@ -197,10 +197,11 @@ /* Timer info */ #define CONFIG_SYS_HZ 1000 #ifdef CONFIG_SOCFPGA_VIRTUAL_TARGET -#define CONFIG_TIMER_CLOCK_KHZ 2400 +#define CONFIG_SYS_TIMER_RATE 2400000 #else -#define CONFIG_TIMER_CLOCK_KHZ 25000 +#define CONFIG_SYS_TIMER_RATE 25000000 #endif +#define CONFIG_SYS_TIMER_COUNTER (CONFIG_SYS_TIMERBASE + 0x4)
#define CONFIG_ENV_IS_NOWHERE

From: Rob Herring rob.herring@calxeda.com
Convert tegra to use the commmon timer code.
Signed-off-by: Rob Herring rob.herring@calxeda.com --- arch/arm/cpu/tegra-common/Makefile | 2 +- arch/arm/cpu/tegra-common/timer.c | 95 -------------------------------------- include/configs/tegra-common.h | 3 ++ 3 files changed, 4 insertions(+), 96 deletions(-) delete mode 100644 arch/arm/cpu/tegra-common/timer.c
diff --git a/arch/arm/cpu/tegra-common/Makefile b/arch/arm/cpu/tegra-common/Makefile index 1b6cdf7..89b2210 100644 --- a/arch/arm/cpu/tegra-common/Makefile +++ b/arch/arm/cpu/tegra-common/Makefile @@ -12,7 +12,7 @@ include $(TOPDIR)/config.mk LIB = $(obj)libcputegra-common.o
SOBJS += lowlevel_init.o -COBJS-y += ap.o board.o sys_info.o timer.o clock.o cache.o +COBJS-y += ap.o board.o sys_info.o clock.o cache.o
SRCS := $(SOBJS:.o=.S) $(COBJS-y:.o=.c) OBJS := $(addprefix $(obj),$(SOBJS) $(COBJS-y)) diff --git a/arch/arm/cpu/tegra-common/timer.c b/arch/arm/cpu/tegra-common/timer.c deleted file mode 100644 index d0f783e..0000000 --- a/arch/arm/cpu/tegra-common/timer.c +++ /dev/null @@ -1,95 +0,0 @@ -/* - * (C) Copyright 2010,2011 - * NVIDIA Corporation <www.nvidia.com> - * - * (C) Copyright 2008 - * Texas Instruments - * - * Richard Woodruff r-woodruff2@ti.com - * Syed Moahmmed Khasim khasim@ti.com - * - * (C) Copyright 2002 - * Sysgo Real-Time Solutions, GmbH <www.elinos.com> - * Marius Groeger mgroeger@sysgo.de - * Alex Zuepke azu@sysgo.de - * - * (C) Copyright 2002 - * Gary Jennejohn, DENX Software Engineering, garyj@denx.de - * - * SPDX-License-Identifier: GPL-2.0+ - */ - -#include <common.h> -#include <asm/io.h> -#include <asm/arch/tegra.h> -#include <asm/arch-tegra/timer.h> - -DECLARE_GLOBAL_DATA_PTR; - -/* counter runs at 1MHz */ -#define TIMER_CLK 1000000 -#define TIMER_LOAD_VAL 0xffffffff - -/* timer without interrupts */ -ulong get_timer(ulong base) -{ - return get_timer_masked() - base; -} - -/* delay x useconds */ -void __udelay(unsigned long usec) -{ - long tmo = usec * (TIMER_CLK / 1000) / 1000; - unsigned long now, last = timer_get_us(); - - while (tmo > 0) { - now = timer_get_us(); - if (last > now) /* count up timer overflow */ - tmo -= TIMER_LOAD_VAL - last + now; - else - tmo -= now - last; - last = now; - } -} - -ulong get_timer_masked(void) -{ - ulong now; - - /* current tick value */ - now = timer_get_us() / (TIMER_CLK / CONFIG_SYS_HZ); - - if (now >= gd->arch.lastinc) /* normal mode (non roll) */ - /* move stamp forward with absolute diff ticks */ - gd->arch.tbl += (now - gd->arch.lastinc); - else /* we have rollover of incrementer */ - gd->arch.tbl += ((TIMER_LOAD_VAL / (TIMER_CLK / CONFIG_SYS_HZ)) - - gd->arch.lastinc) + now; - gd->arch.lastinc = now; - return gd->arch.tbl; -} - -/* - * This function is derived from PowerPC code (read timebase as long long). - * On ARM it just returns the timer value. - */ -unsigned long long get_ticks(void) -{ - return get_timer(0); -} - -/* - * This function is derived from PowerPC code (timebase clock frequency). - * On ARM it returns the number of timer ticks per second. - */ -ulong get_tbclk(void) -{ - return CONFIG_SYS_HZ; -} - -unsigned long timer_get_us(void) -{ - struct timerus *timer_base = (struct timerus *)NV_PA_TMRUS_BASE; - - return readl(&timer_base->cntr_1us); -} diff --git a/include/configs/tegra-common.h b/include/configs/tegra-common.h index ba6c6bb..d4361a5 100644 --- a/include/configs/tegra-common.h +++ b/include/configs/tegra-common.h @@ -19,6 +19,9 @@
#include <asm/arch/tegra.h> /* get chip and board defs */
+#define CONFIG_SYS_TIMER_RATE 1000000 +#define CONFIG_SYS_TIMER_COUNTER NV_PA_TMRUS_BASE + /* * Display CPU and Board information */

From: Rob Herring rob.herring@calxeda.com
Convert versatile to use the commmon timer code.
Signed-off-by: Rob Herring rob.herring@calxeda.com --- arch/arm/cpu/arm926ejs/versatile/timer.c | 116 ------------------------------- include/configs/versatile.h | 9 ++- 2 files changed, 4 insertions(+), 121 deletions(-)
diff --git a/arch/arm/cpu/arm926ejs/versatile/timer.c b/arch/arm/cpu/arm926ejs/versatile/timer.c index 5436162..f31d9bd 100644 --- a/arch/arm/cpu/arm926ejs/versatile/timer.c +++ b/arch/arm/cpu/arm926ejs/versatile/timer.c @@ -21,16 +21,6 @@
#include <common.h>
-#define TIMER_LOAD_VAL 0xffffffff - -/* macro to read the 32 bit timer */ -#define READ_TIMER (*(volatile ulong *)(CONFIG_SYS_TIMERBASE+4)) - -DECLARE_GLOBAL_DATA_PTR; - -#define timestamp gd->arch.tbl -#define lastdec gd->arch.lastinc - #define TIMER_ENABLE (1 << 7) #define TIMER_MODE_MSK (1 << 6) #define TIMER_MODE_FR (0 << 6) @@ -69,112 +59,6 @@ int timer_init (void)
*(volatile ulong *)(CONFIG_SYS_TIMERBASE + 8) = tmr_ctrl_val;
- /* init the timestamp and lastdec value */ - reset_timer_masked(); - return 0; }
-/* - * timer without interrupts - */ -ulong get_timer (ulong base) -{ - return get_timer_masked () - base; -} - -/* delay x useconds AND preserve advance timestamp value */ -void __udelay (unsigned long usec) -{ - ulong tmo, tmp; - - if(usec >= 1000){ /* if "big" number, spread normalization to seconds */ - tmo = usec / 1000; /* start to normalize for usec to ticks per sec */ - tmo *= CONFIG_SYS_HZ; /* find number of "ticks" to wait to achieve target */ - tmo /= 1000; /* finish normalize. */ - }else{ /* else small number, don't kill it prior to HZ multiply */ - tmo = usec * CONFIG_SYS_HZ; - tmo /= (1000*1000); - } - - tmp = get_timer (0); /* get current timestamp */ - if( (tmo + tmp + 1) < tmp ) /* if setting this fordward will roll time stamp */ - reset_timer_masked (); /* reset "advancing" timestamp to 0, set lastdec value */ - else - tmo += tmp; /* else, set advancing stamp wake up time */ - - while (get_timer_masked () < tmo)/* loop till event */ - /*NOP*/; -} - -void reset_timer_masked (void) -{ - /* reset time */ - lastdec = READ_TIMER; /* capure current decrementer value time */ - timestamp = 0; /* start "advancing" time stamp from 0 */ -} - -ulong get_timer_masked (void) -{ - ulong now = READ_TIMER; /* current tick value */ - - if (lastdec >= now) { /* normal mode (non roll) */ - /* normal mode */ - timestamp += lastdec - now; /* move stamp fordward with absoulte diff ticks */ - } else { /* we have overflow of the count down timer */ - /* nts = ts + ld + (TLV - now) - * ts=old stamp, ld=time that passed before passing through -1 - * (TLV-now) amount of time after passing though -1 - * nts = new "advancing time stamp"...it could also roll and cause problems. - */ - timestamp += lastdec + TIMER_LOAD_VAL - now; - } - lastdec = now; - - return timestamp; -} - -/* waits specified delay value and resets timestamp */ -void udelay_masked (unsigned long usec) -{ - ulong tmo; - ulong endtime; - signed long diff; - - if (usec >= 1000) { /* if "big" number, spread normalization to seconds */ - tmo = usec / 1000; /* start to normalize for usec to ticks per sec */ - tmo *= CONFIG_SYS_HZ; /* find number of "ticks" to wait to achieve target */ - tmo /= 1000; /* finish normalize. */ - } else { /* else small number, don't kill it prior to HZ multiply */ - tmo = usec * CONFIG_SYS_HZ; - tmo /= (1000*1000); - } - - endtime = get_timer_masked () + tmo; - - do { - ulong now = get_timer_masked (); - diff = endtime - now; - } while (diff >= 0); -} - -/* - * This function is derived from PowerPC code (read timebase as long long). - * On ARM it just returns the timer value. - */ -unsigned long long get_ticks(void) -{ - return get_timer(0); -} - -/* - * This function is derived from PowerPC code (timebase clock frequency). - * On ARM it returns the number of timer ticks per second. - */ -ulong get_tbclk (void) -{ - ulong tbclk; - - tbclk = CONFIG_SYS_HZ; - return tbclk; -} diff --git a/include/configs/versatile.h b/include/configs/versatile.h index 8d3ff6a..0d23262 100644 --- a/include/configs/versatile.h +++ b/include/configs/versatile.h @@ -25,12 +25,11 @@
#define CONFIG_SYS_MEMTEST_START 0x100000 #define CONFIG_SYS_MEMTEST_END 0x10000000 -#define CONFIG_SYS_HZ (1000000 / 256) -#define CONFIG_SYS_TIMERBASE 0x101E2000 /* Timer 0 and 1 base */
-#define CONFIG_SYS_TIMER_INTERVAL 10000 -#define CONFIG_SYS_TIMER_RELOAD (CONFIG_SYS_TIMER_INTERVAL >> 4) -#define CONFIG_SYS_TIMER_CTRL 0x84 /* Enable, Clock / 16 */ +#define CONFIG_SYS_TIMERBASE 0x101E2000 /* Timer 0 and 1 base */ +#define CONFIG_SYS_TIMER_RATE (1000000 / 256) +#define CONFIG_SYS_TIMER_COUNTER (CONFIG_SYS_TIMERBASE + 0x4) +#define CONFIG_SYS_TIMER_COUNTS_DOWN
/* * control registers

On Fri, Oct 04, 2013 at 10:22:39AM -0500, Rob Herring wrote:
From: Rob Herring rob.herring@calxeda.com
Much of the timer code is re-implemented for each platform/arch yet it is all pretty much the same code.
This series introduces a common implementation of timer functions and simplifies the platform code down to 2 or 3 config defines or 2 simple functions. It is intended for platforms with 32-bit freerunning timers. I've converted SH and a couple of ARM platforms as an example, but there are many more still that can be converted. This probably could be extended to work with 16-bit timers as well.
I've compiled on ARM, SH4, and PPC.
For the series, applied to u-boot/master, thanks!
participants (5)
-
Benoît Thébaudeau
-
Lukasz Majewski
-
Rob Herring
-
Tom Rini
-
Wolfgang Denk