diff options
Diffstat (limited to 'arch/arm/cpu/arm926ejs/at91/timer.c')
| -rw-r--r-- | arch/arm/cpu/arm926ejs/at91/timer.c | 85 | 
1 files changed, 42 insertions, 43 deletions
| diff --git a/arch/arm/cpu/arm926ejs/at91/timer.c b/arch/arm/cpu/arm926ejs/at91/timer.c index 8efc34bcf..82b8d7e7d 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;  } |