diff options
Diffstat (limited to 'cpu/arm926ejs/nomadik/timer.c')
-rw-r--r-- | cpu/arm926ejs/nomadik/timer.c | 166 |
1 files changed, 27 insertions, 139 deletions
diff --git a/cpu/arm926ejs/nomadik/timer.c b/cpu/arm926ejs/nomadik/timer.c index 2870d24..16067c9 100644 --- a/cpu/arm926ejs/nomadik/timer.c +++ b/cpu/arm926ejs/nomadik/timer.c @@ -1,20 +1,5 @@ /* - * (C) Copyright 2003 - * Texas Instruments <www.ti.com> - * - * (C) Copyright 2002 - * Sysgo Real-Time Solutions, GmbH <www.elinos.com> - * Marius Groeger <mgroeger@sysgo.de> - * - * (C) Copyright 2002 - * Sysgo Real-Time Solutions, GmbH <www.elinos.com> - * Alex Zuepke <azu@sysgo.de> - * - * (C) Copyright 2002-2004 - * Gary Jennejohn, DENX Software Engineering, <garyj@denx.de> - * - * (C) Copyright 2004 - * Philippe Robin, ARM Ltd. <philippe.robin@arm.com> + * (C) Copyright 2009 Alessandro Rubini * * See file CREDITS for list of people who contributed to this * project. @@ -37,146 +22,49 @@ #include <common.h> #include <asm/io.h> +#include <asm/arch/mtu.h> -#define TIMER_LOAD_VAL 0xffffffff - -/* macro to read the 32 bit timer */ -#define READ_TIMER readl(CONFIG_SYS_TIMERBASE + 20) +/* + * The timer is a decrementer, we'll left it free running at 2.4MHz. + * We have 2.4 ticks per microsecond and an overflow in almost 30min + */ +#define TIMER_CLOCK (24 * 100 * 1000) +#define COUNT_TO_USEC(x) ((x) * 5 / 12) /* overflows at 6min */ +#define USEC_TO_COUNT(x) ((x) * 12 / 5) /* overflows at 6min */ +#define TICKS_PER_HZ (TIMER_CLOCK / CONFIG_SYS_HZ) +#define TICKS_TO_HZ(x) ((x) / TICKS_PER_HZ) -static ulong timestamp; -static ulong lastdec; +/* macro to read the 32 bit timer: since it decrements, we invert read value */ +#define READ_TIMER() (~readl(CONFIG_SYS_TIMERBASE + MTU_VAL(0))) -/* nothing really to do with interrupts, just starts up a counter. */ +/* Configure a free-running, auto-wrap counter with no prescaler */ int timer_init(void) { - /* Load timer with initial value */ - writel(TIMER_LOAD_VAL, CONFIG_SYS_TIMERBASE + 16); - - /* - * Set timer to be enabled, free-running, no interrupts, 256 divider, - * 32-bit, wrap-mode - */ - writel(0x8a, CONFIG_SYS_TIMERBASE + 24); - - /* init the timestamp and lastdec value */ - reset_timer_masked(); - + writel(MTU_CRn_ENA | MTU_CRn_PRESCALE_1 | MTU_CRn_32BITS, + CONFIG_SYS_TIMERBASE + MTU_CR(0)); + reset_timer(); return 0; } -/* - * timer without interrupts - */ +/* Restart counting from 0 */ void reset_timer(void) { - reset_timer_masked(); + writel(0, CONFIG_SYS_TIMERBASE + MTU_LR(0)); /* Immediate effect */ } +/* Return how many HZ passed since "base" */ ulong get_timer(ulong base) { - return get_timer_masked() - base; + return TICKS_TO_HZ(READ_TIMER()) - base; } -void set_timer(ulong t) -{ - timestamp = t; -} - -/* delay x useconds AND perserve advance timstamp value */ +/* Delay x useconds */ void udelay(unsigned long usec) { - ulong tmo, tmp; - - if (usec >= 1000) { - /* if "big" number, spread normalization to seconds */ - tmo = usec / 1000; /* start to normalize */ - tmo *= CONFIG_SYS_HZ; /* find number of "ticks" */ - tmo /= 1000; /* finish normalize. */ - } 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) /* will roll time stamp? */ - reset_timer_masked(); /* reset to 0, set lastdec value */ - else - tmo += tmp; - - while (get_timer_masked() < tmo) - /* nothing */ ; -} - -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) */ - /* move stamp fordward */ - timestamp += lastdec - now; - } else { - /* - * An overflow is expected. - * 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 - */ - 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; - - if (usec >= 1000) { - /* if "big" number, spread normalization to seconds */ - tmo = usec / 1000; /* start to normalize */ - tmo *= CONFIG_SYS_HZ; /* find number of "ticks" */ - tmo /= 1000; /* finish normalize. */ - } else { - /* else small number, don't kill it prior to HZ multiply */ - tmo = usec * CONFIG_SYS_HZ; - tmo /= (1000*1000); - } - - reset_timer_masked(); - /* set "advancing" timestamp to 0, set lastdec vaule */ - - while (get_timer_masked() < tmo) - /* nothing */ ; -} - -/* - * 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; + ulong ini, end; - tbclk = CONFIG_SYS_HZ; - return tbclk; + ini = READ_TIMER(); + end = ini + USEC_TO_COUNT(usec); + while ((signed)(end - READ_TIMER()) > 0) + ; } |