[U-Boot] [PATCH] AT91 clock/timer: move static data to global_data struct

Reinhard Meyer u-boot at emk-elektronik.de
Tue Oct 5 16:54:35 CEST 2010


clock.c / timer.c used static data and are called before relocation.
Move all static variables into global_data structure. Also cleanup
timer.c from unused stubs and make it truly use 64 bit tick values.

Signed-off-by: Reinhard Meyer <u-boot at emk-elektronik.de>
---
 arch/arm/cpu/arm926ejs/at91/clock.c |   55 +++++++++++-----------
 arch/arm/cpu/arm926ejs/at91/timer.c |   85 +++++++++++++++++------------------
 arch/arm/include/asm/global_data.h  |   14 ++++++
 3 files changed, 83 insertions(+), 71 deletions(-)

diff --git a/arch/arm/cpu/arm926ejs/at91/clock.c b/arch/arm/cpu/arm926ejs/at91/clock.c
index ecf91f5..7a10a77 100644
--- a/arch/arm/cpu/arm926ejs/at91/clock.c
+++ b/arch/arm/cpu/arm926ejs/at91/clock.c
@@ -11,47 +11,46 @@
  * (at your option) any later version.
  */
 
-#include <config.h>
+#include <common.h>
 #include <asm/arch/hardware.h>
 #include <asm/arch/io.h>
 #include <asm/arch/at91_pmc.h>
 #include <asm/arch/clk.h>
 
-static unsigned long cpu_clk_rate_hz;
-static unsigned long main_clk_rate_hz;
-static unsigned long mck_rate_hz;
-static unsigned long plla_rate_hz;
-static unsigned long pllb_rate_hz;
-static u32 at91_pllb_usb_init;
+#if !defined(CONFIG_AT91FAMILY)
+# error You need to define CONFIG_AT91FAMILY in your board config!
+#endif
+
+DECLARE_GLOBAL_DATA_PTR;
 
 unsigned long get_cpu_clk_rate(void)
 {
-	return cpu_clk_rate_hz;
+	return gd->cpu_clk_rate_hz;
 }
 
 unsigned long get_main_clk_rate(void)
 {
-	return main_clk_rate_hz;
+	return gd->main_clk_rate_hz;
 }
 
 unsigned long get_mck_clk_rate(void)
 {
-	return mck_rate_hz;
+	return gd->mck_rate_hz;
 }
 
 unsigned long get_plla_clk_rate(void)
 {
-	return plla_rate_hz;
+	return gd->plla_rate_hz;
 }
 
 unsigned long get_pllb_clk_rate(void)
 {
-	return pllb_rate_hz;
+	return gd->pllb_rate_hz;
 }
 
 u32 get_pllb_init(void)
 {
-	return at91_pllb_usb_init;
+	return gd->at91_pllb_usb_init;
 }
 
 static unsigned long at91_css_to_rate(unsigned long css)
@@ -60,11 +59,11 @@ static unsigned long at91_css_to_rate(unsigned long css)
 	case AT91_PMC_MCKR_CSS_SLOW:
 		return AT91_SLOW_CLOCK;
 	case AT91_PMC_MCKR_CSS_MAIN:
-		return main_clk_rate_hz;
+		return gd->main_clk_rate_hz;
 	case AT91_PMC_MCKR_CSS_PLLA:
-		return plla_rate_hz;
+		return gd->plla_rate_hz;
 	case AT91_PMC_MCKR_CSS_PLLB:
-		return pllb_rate_hz;
+		return gd->pllb_rate_hz;
 	}
 
 	return 0;
@@ -163,10 +162,10 @@ int at91_clock_init(unsigned long main_clock)
 		main_clock = tmp * (AT91_SLOW_CLOCK / 16);
 	}
 #endif
-	main_clk_rate_hz = main_clock;
+	gd->main_clk_rate_hz = main_clock;
 
 	/* report if PLLA is more than mildly overclocked */
-	plla_rate_hz = at91_pll_rate(main_clock, readl(&pmc->pllar));
+	gd->plla_rate_hz = at91_pll_rate(main_clock, readl(&pmc->pllar));
 
 #ifdef CONFIG_USB_ATMEL
 	/*
@@ -175,9 +174,9 @@ int at91_clock_init(unsigned long main_clock)
 	 *
 	 * REVISIT:  assumes MCK doesn't derive from PLLB!
 	 */
-	at91_pllb_usb_init = at91_pll_calc(main_clock, 48000000 * 2) |
+	gd->at91_pllb_usb_init = at91_pll_calc(main_clock, 48000000 * 2) |
 			     AT91_PMC_PLLBR_USBDIV_2;
-	pllb_rate_hz = at91_pll_rate(main_clock, at91_pllb_usb_init);
+	gd->pllb_rate_hz = at91_pll_rate(main_clock, gd->at91_pllb_usb_init);
 #endif
 
 	/*
@@ -187,30 +186,30 @@ int at91_clock_init(unsigned long main_clock)
 	mckr = readl(&pmc->mckr);
 #if defined(CONFIG_AT91SAM9G45) || defined(CONFIG_AT91SAM9M10G45)
 	/* plla divisor by 2 */
-	plla_rate_hz /= (1 << ((mckr & 1 << 12) >> 12));
+	gd->plla_rate_hz /= (1 << ((mckr & 1 << 12) >> 12));
 #endif
-	mck_rate_hz = at91_css_to_rate(mckr & AT91_PMC_MCKR_CSS_MASK);
-	freq = mck_rate_hz;
+	gd->mck_rate_hz = at91_css_to_rate(mckr & AT91_PMC_MCKR_CSS_MASK);
+	freq = gd->mck_rate_hz;
 
 	freq /= (1 << ((mckr & AT91_PMC_MCKR_PRES_MASK) >> 2));	/* prescale */
 #if defined(CONFIG_AT91RM9200)
 	/* mdiv */
-	mck_rate_hz = freq / (1 + ((mckr & AT91_PMC_MCKR_MDIV_MASK) >> 8));
+	gd->mck_rate_hz = freq / (1 + ((mckr & AT91_PMC_MCKR_MDIV_MASK) >> 8));
 #elif defined(CONFIG_AT91SAM9G20)
 	/* mdiv ; (x >> 7) = ((x >> 8) * 2) */
-	mck_rate_hz = (mckr & AT91_PMC_MCKR_MDIV_MASK) ?
+	gd->mck_rate_hz = (mckr & AT91_PMC_MCKR_MDIV_MASK) ?
 		freq / ((mckr & AT91_PMC_MCKR_MDIV_MASK) >> 7) : freq;
 	if (mckr & AT91_PMC_MCKR_MDIV_MASK)
 		freq /= 2;			/* processor clock division */
 #elif defined(CONFIG_AT91SAM9G45) || defined(CONFIG_AT91SAM9M10G45)
-	mck_rate_hz = (mckr & AT91_PMC_MCKR_MDIV_MASK) ==
+	gd->mck_rate_hz = (mckr & AT91_PMC_MCKR_MDIV_MASK) ==
 		(AT91_PMC_MCKR_MDIV_2 | AT91_PMC_MCKR_MDIV_4)
 		? freq / 3
 		: freq / (1 << ((mckr & AT91_PMC_MCKR_MDIV_MASK) >> 8));
 #else
-	mck_rate_hz = freq / (1 << ((mckr & AT91_PMC_MCKR_MDIV_MASK) >> 8));
+	gd->mck_rate_hz = freq / (1 << ((mckr & AT91_PMC_MCKR_MDIV_MASK) >> 8));
 #endif
-	cpu_clk_rate_hz = freq;
+	gd->cpu_clk_rate_hz = freq;
 
 	return 0;
 }
diff --git a/arch/arm/cpu/arm926ejs/at91/timer.c b/arch/arm/cpu/arm926ejs/at91/timer.c
index 8efc34b..82b8d7e 100644
--- a/arch/arm/cpu/arm926ejs/at91/timer.c
+++ b/arch/arm/cpu/arm926ejs/at91/timer.c
@@ -30,55 +30,63 @@
 #include <asm/arch/io.h>
 #include <div64.h>
 
+#if !defined(CONFIG_AT91FAMILY)
+# error You need to define CONFIG_AT91FAMILY in your board config!
+#endif
+
+DECLARE_GLOBAL_DATA_PTR;
+
 /*
  * We're using the AT91CAP9/SAM9 PITC in 32 bit mode, by
  * setting the 20 bit counter period to its maximum (0xfffff).
+ * (See the relevant data sheets to understand that this really works)
+ *
+ * We do also mimic the typical powerpc way of incrementing
+ * two 32 bit registers called tbl and tbu.
+ *
+ * Those registers increment at 1/16 the main clock rate.
  */
-#define TIMER_LOAD_VAL	0xfffff
 
-static ulong timestamp;
-static ulong lastinc;
-static ulong timer_freq;
+#define TIMER_LOAD_VAL	0xfffff
 
 static inline unsigned long long tick_to_time(unsigned long long tick)
 {
 	tick *= CONFIG_SYS_HZ;
-	do_div(tick, timer_freq);
+	do_div(tick, gd->timer_rate_hz);
 
 	return tick;
 }
 
 static inline unsigned long long usec_to_tick(unsigned long long usec)
 {
-	usec *= timer_freq;
+	usec *= gd->timer_rate_hz;
 	do_div(usec, 1000000);
 
 	return usec;
 }
 
-/* nothing really to do with interrupts, just starts up a counter. */
+/*
+ * Use the PITC in full 32 bit incrementing mode
+ */
 int timer_init(void)
 {
 	at91_pmc_t *pmc = (at91_pmc_t *) AT91_PMC_BASE;
 	at91_pit_t *pit = (at91_pit_t *) AT91_PIT_BASE;
-	/*
-	 * Enable PITC Clock
-	 * The clock is already enabled for system controller in boot
-	 */
+
+	/* Enable PITC Clock */
 	writel(1 << AT91_ID_SYS, &pmc->pcer);
 
 	/* Enable PITC */
 	writel(TIMER_LOAD_VAL | AT91_PIT_MR_EN , &pit->mr);
 
-	reset_timer_masked();
-
-	timer_freq = get_mck_clk_rate() >> 4;
+	gd->timer_rate_hz = gd->mck_rate_hz / 16;
+	gd->tbu = gd->tbl = 0;
 
 	return 0;
 }
 
 /*
- * timer without interrupts
+ * Get the current 64 bit timer tick count
  */
 unsigned long long get_ticks(void)
 {
@@ -86,28 +94,11 @@ unsigned long long get_ticks(void)
 
 	ulong now = readl(&pit->piir);
 
-	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;
-}
-
-void reset_timer_masked(void)
-{
-	/* reset time */
-	at91_pit_t *pit = (at91_pit_t *) AT91_PIT_BASE;
-
-	/* capture current incrementer value time */
-	lastinc = readl(&pit->piir);
-	timestamp = 0; /* start "advancing" time stamp from 0 */
-}
-
-ulong get_timer_masked(void)
-{
-	return tick_to_time(get_ticks());
+	/* increment tbu if tbl has rolled over */
+	if (now < gd->tbl)
+		gd->tbu++;
+	gd->tbl = now;
+	return (((unsigned long long)gd->tbu) << 32) | gd->tbl;
 }
 
 void __udelay(unsigned long usec)
@@ -119,24 +110,32 @@ void __udelay(unsigned long usec)
 	tmp = get_ticks() + tmo;	/* get current timestamp */
 
 	while (get_ticks() < tmp)	/* loop till event */
-		 /*NOP*/;
+		;
 }
 
+/*
+ * reset_timer() and get_timer(base) are a pair of functions that are used by
+ * some timeout/sleep mechanisms in u-boot.
+ *
+ * reset_timer() marks the current time as epoch and
+ * get_timer(base) works relative to that epoch.
+ *
+ * The time is used in CONFIG_SYS_HZ units!
+ */
 void reset_timer(void)
 {
-	reset_timer_masked();
+	gd->timer_reset_value = get_ticks();
 }
 
 ulong get_timer(ulong base)
 {
-	return get_timer_masked () - base;
+	return tick_to_time(get_ticks() - gd->timer_reset_value) - base;
 }
 
 /*
- * This function is derived from PowerPC code (timebase clock frequency).
- * On ARM it returns the number of timer ticks per second.
+ * Return the number of timer ticks per second.
  */
 ulong get_tbclk(void)
 {
-	return timer_freq;
+	return gd->timer_rate_hz;
 }
diff --git a/arch/arm/include/asm/global_data.h b/arch/arm/include/asm/global_data.h
index 6152f34..b173ea5 100644
--- a/arch/arm/include/asm/global_data.h
+++ b/arch/arm/include/asm/global_data.h
@@ -47,6 +47,20 @@ typedef	struct	global_data {
 #ifdef CONFIG_FSL_ESDHC
 	unsigned long	sdhc_clk;
 #endif
+#ifdef CONFIG_AT91FAMILY
+	/* "static data" needed by at91's clock.c */
+ 	unsigned long	cpu_clk_rate_hz;
+	unsigned long	main_clk_rate_hz;
+	unsigned long	mck_rate_hz;
+	unsigned long	plla_rate_hz;
+	unsigned long	pllb_rate_hz;
+	unsigned long	at91_pllb_usb_init;
+	/* "static data" needed by at91's timer.c */
+	unsigned long	timer_rate_hz;
+	unsigned long	tbl;
+	unsigned long	tbu;
+	unsigned long long	timer_reset_value;
+#endif
 #if !defined(CONFIG_SYS_ARM_WITHOUT_RELOC)
 	unsigned long	relocaddr;	/* Start address of U-Boot in RAM */
 	phys_size_t	ram_size;	/* RAM size */
-- 
1.5.6.5



More information about the U-Boot mailing list