
MIPS port has two problems in timer routines. One is now we assume CFG_HZ == CP0 counter frequency, but this is wrong. CFG_HZ has to be 1000 in the U-Boot system.
The other is we don't have a proper time management counter like timestamp other ARCHs have. We need the 32-bit millisecond clock that U-Boot wants.
This patch adds 3 global variables; timestamp, cycles_per_jiffy, expirelo. timestamp is a 32-bit non-overflowing CFG_HZ counter. cycles_per_jiffy is calculated counter cycles in a CFG_HZ. And expirelo holds the count value for next CPU timer expiration.
With these variables, fix each functions. Notably,
* timer_init: Initialize cycles_per_jiffy, timestamp, and expirelo. Note that we don't have to initialize CP0 count/compare registers here. They have been already cleared on the system reset. Leave them as they are.
* get_timer: Calculate how many timestamps have been passed, then return (relative) timestamp. I'm afraid we might suffer from a big catch up loop if this function is called after a long delay.
* get_ticks: Return the current timestamp, that is get_timer(0).
Most parts are from good old Linux v2.6.16 kernel.
Signed-off-by: Shinya Kuribayashi skuribay@ruby.dti.ne.jp ---
lib_mips/time.c | 44 ++++++++++++++++++++++++++++++++++++++------ 1 files changed, 38 insertions(+), 6 deletions(-)
diff --git a/lib_mips/time.c b/lib_mips/time.c index 154d792..4b47e41 100644 --- a/lib_mips/time.c +++ b/lib_mips/time.c @@ -24,31 +24,63 @@ #include <common.h> #include <asm/mipsregs.h>
+static unsigned long timestamp; + +/* how many counter cycles in a jiffy */ +static unsigned long cycles_per_jiffy; + +/* expirelo is the count value for next CPU timer interrupt */ +static unsigned int expirelo; + /* * timer without interrupts */
int timer_init(void) { - write_32bit_cp0_register(CP0_COMPARE, 0); - write_32bit_cp0_register(CP0_COUNT, 0); + /* Calculate cache parameters. */ + cycles_per_jiffy = (CONFIG_MIPS_TIMER_FREQ + CFG_HZ / 2) / CFG_HZ; + + /* Report the high precision timer rate for a reference. */ + printf("Using %u.%03u MHz high precision timer.\n", + ((CONFIG_MIPS_TIMER_FREQ + 500) / 1000) / 1000, + ((CONFIG_MIPS_TIMER_FREQ + 500) / 1000) % 1000); + + /* Set up the timer for the first expiration. */ + timestamp = 0; + expirelo = read_32bit_cp0_register(CP0_COUNT) + cycles_per_jiffy;
return 0; }
void reset_timer(void) { - write_32bit_cp0_register(CP0_COUNT, 0); + timestamp = 0; + expirelo = read_32bit_cp0_register(CP0_COUNT) + cycles_per_jiffy; }
ulong get_timer(ulong base) { - return read_32bit_cp0_register(CP0_COUNT) - base; + unsigned int count; + + /* Check to see if we have missed any timestamps. */ + count = read_32bit_cp0_register(CP0_COUNT); + while ((count - expirelo) < 0x7fffffff) { + /* + * FIXME: We might suffer from a big catch up loop + * if called after a long delay. + */ + expirelo += cycles_per_jiffy; + timestamp++; + } + + return (timestamp - base); }
void set_timer(ulong t) { - write_32bit_cp0_register(CP0_COUNT, t); + timestamp = t; + expirelo = read_32bit_cp0_register(CP0_COUNT) + cycles_per_jiffy; }
void udelay(unsigned long usec) @@ -67,7 +99,7 @@ void udelay(unsigned long usec) */ unsigned long long get_ticks(void) { - return read_32bit_cp0_register(CP0_COUNT); + return get_timer(0); }
/*