From mboxrd@z Thu Jan 1 00:00:00 1970 From: Shinya Kuribayashi Date: Sat, 24 May 2008 22:02:28 +0900 Subject: [U-Boot-Users] [PATCH 3/3][MIPS] lib_mips/time.c: Fix improper use of CFG_HZ and timer routines In-Reply-To: <48381147.5060803@ruby.dti.ne.jp> References: <20080520185822.8B9C86545F@mcmullan-linux.hq.netapp.com> <48339C9D.5040800@necel.com> <20080521153255.GD13959@ld0162-tx32.am.freescale.net> <483810E2.7020105@ruby.dti.ne.jp> <48381147.5060803@ruby.dti.ne.jp> Message-ID: <483811E4.3070209@ruby.dti.ne.jp> List-Id: MIME-Version: 1.0 Content-Type: text/plain; charset="us-ascii" Content-Transfer-Encoding: 7bit To: u-boot@lists.denx.de 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 --- 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 #include +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); } /*