Patchwork [U-Boot] arm: a320: fix broken timer

login
register
mail settings
Submitter Po-Yu Chuang
Date Aug. 11, 2011, 3:44 a.m.
Message ID <1313034261-1701-1-git-send-email-ratbert.chuang@gmail.com>
Download mbox | patch
Permalink /patch/109515/
State Accepted
Commit 60d1ea94ead7327d46f0a38cf8d20663a508fe34
Headers show

Comments

Po-Yu Chuang - Aug. 11, 2011, 3:44 a.m.
From: Po-Yu Chuang <ratbert@faraday-tech.com>

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.

Remove reset_timer_masked() get_timer_masked()

reference: arch/arm/cpu/arm926ejs/at91/timer.c

Based on Reinhard Meyer <u-boot@emk-elektronik.de>'s patches
5dca710a3d7703e41da0e9894f2d71f9e25bea6b
cfff263f41e32c7ba2ee9162a8cc6423eb5a8390

Signed-off-by: Po-Yu Chuang <ratbert@faraday-tech.com>
---
 arch/arm/cpu/arm920t/a320/timer.c |  134 ++++++++++++++-----------------------
 1 files changed, 50 insertions(+), 84 deletions(-)
Macpaul Lin - Aug. 30, 2011, 6:01 a.m.
Hi Albert and Po-Yu,

2011/8/11 Po-Yu Chuang <ratbert.chuang@gmail.com>
>
> From: Po-Yu Chuang <ratbert@faraday-tech.com>
>
> 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.

This patch has been tested by Macpaul on AG101 and AG101P boards.

Tested-by: Macpaul Lin <macpaul@gmail.com>

--
Best regards,
Macpaul Lin
Po-Yu Chuang - Oct. 18, 2011, 2:34 a.m.
Dear Albert

On Tue, Aug 30, 2011 at 2:01 PM, 馬克泡 <macpaul@gmail.com> wrote:
> Hi Albert and Po-Yu,
>
> 2011/8/11 Po-Yu Chuang <ratbert.chuang@gmail.com>
>>
>> From: Po-Yu Chuang <ratbert@faraday-tech.com>
>>
>> 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.
>
> This patch has been tested by Macpaul on AG101 and AG101P boards.
>
> Tested-by: Macpaul Lin <macpaul@gmail.com>

This patch was posted 2 months ago and is still not in mainline.
Is there any problem?

Best regards,
Po-Yu Chuang
Albert ARIBAUD - Nov. 8, 2011, 7:53 p.m.
Hi Po-Yu,

Le 18/10/2011 04:34, Po-Yu Chuang a écrit :
> Dear Albert
>
> On Tue, Aug 30, 2011 at 2:01 PM, 馬克泡<macpaul@gmail.com>  wrote:
>> Hi Albert and Po-Yu,
>>
>> 2011/8/11 Po-Yu Chuang<ratbert.chuang@gmail.com>
>>>
>>> From: Po-Yu Chuang<ratbert@faraday-tech.com>
>>>
>>> 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.
>>
>> This patch has been tested by Macpaul on AG101 and AG101P boards.
>>
>> Tested-by: Macpaul Lin<macpaul@gmail.com>
>
> This patch was posted 2 months ago and is still not in mainline.
> Is there any problem?

None, except my own slowness.

Applied to u-boot-arm/master, and apologies.

> Best regards,
> Po-Yu Chuang

Amicalement,

Patch

diff --git a/arch/arm/cpu/arm920t/a320/timer.c b/arch/arm/cpu/arm920t/a320/timer.c
index 443d31d..4bfcef2 100644
--- a/arch/arm/cpu/arm920t/a320/timer.c
+++ b/arch/arm/cpu/arm920t/a320/timer.c
@@ -18,20 +18,35 @@ 
  */
 
 #include <common.h>
+#include <div64.h>
 #include <asm/io.h>
 #include <faraday/ftpmu010.h>
 #include <faraday/fttmr010.h>
 
-static ulong timestamp;
-static ulong lastdec;
-
-static struct fttmr010 *tmr = (struct fttmr010 *)CONFIG_FTTMR010_BASE;
+DECLARE_GLOBAL_DATA_PTR;
 
 #define TIMER_CLOCK	32768
 #define TIMER_LOAD_VAL	0xffffffff
 
+static inline unsigned long long tick_to_time(unsigned long long tick)
+{
+	tick *= CONFIG_SYS_HZ;
+	do_div(tick, gd->timer_rate_hz);
+
+	return tick;
+}
+
+static inline unsigned long long usec_to_tick(unsigned long long usec)
+{
+	usec *= gd->timer_rate_hz;
+	do_div(usec, 1000000);
+
+	return usec;
+}
+
 int timer_init(void)
 {
+	struct fttmr010 *tmr = (struct fttmr010 *)CONFIG_FTTMR010_BASE;
 	unsigned int cr;
 
 	debug("%s()\n", __func__);
@@ -59,106 +74,57 @@  int timer_init(void)
 	cr |= FTTMR010_TM3_ENABLE;
 	writel(cr, &tmr->cr);
 
-	/* init the timestamp and lastdec value */
-	reset_timer_masked();
+	gd->timer_rate_hz = TIMER_CLOCK;
+	gd->tbu = gd->tbl = 0;
 
 	return 0;
 }
 
 /*
- * timer without interrupts
- */
-
-/*
- * reset time
- */
-void reset_timer_masked(void)
-{
-	/* capure current decrementer value time */
-	lastdec = readl(&tmr->timer3_counter) / (TIMER_CLOCK / CONFIG_SYS_HZ);
-	timestamp = 0;		/* start "advancing" time stamp from 0 */
-
-	debug("%s(): lastdec = %lx\n", __func__, lastdec);
-}
-
-/*
- * return timer ticks
- */
-ulong get_timer_masked(void)
-{
-	/* current tick value */
-	ulong now = readl(&tmr->timer3_counter) / (TIMER_CLOCK / CONFIG_SYS_HZ);
-
-	debug("%s(): now = %lx, lastdec = %lx\n", __func__, now, lastdec);
-
-	if (lastdec >= now) {
-		/*
-		 * normal mode (non roll)
-		 * move stamp fordward with absoulte diff ticks
-		 */
-		timestamp += lastdec - now;
-	} else {
-		/*
-		 * we have overflow of the count down timer
-		 *
-		 * 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 and
-		 * cause problems.
-		 */
-		timestamp += lastdec + TIMER_LOAD_VAL - now;
-	}
-
-	lastdec = now;
-
-	debug("%s() returns %lx\n", __func__, timestamp);
-
-	return timestamp;
-}
-
-/*
- * return difference between timer ticks and base
+ * Get the current 64 bit timer tick count
  */
-ulong get_timer(ulong base)
+unsigned long long get_ticks(void)
 {
-	debug("%s(%lx)\n", __func__, base);
-	return get_timer_masked() - base;
+	struct fttmr010 *tmr = (struct fttmr010 *)CONFIG_FTTMR010_BASE;
+	ulong now = TIMER_LOAD_VAL - readl(&tmr->timer3_counter);
+
+	/* 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;
 }
 
-/* delay x useconds AND preserve advance timestamp value */
 void __udelay(unsigned long usec)
 {
-	long tmo = usec * (TIMER_CLOCK / 1000) / 1000;
-	unsigned long now, last = readl(&tmr->timer3_counter);
-
-	debug("%s(%lu)\n", __func__, usec);
-	while (tmo > 0) {
-		now = readl(&tmr->timer3_counter);
-		if (now > last) /* count down timer overflow */
-			tmo -= TIMER_LOAD_VAL + last - now;
-		else
-			tmo -= last - now;
-		last = now;
-	}
+	unsigned long long start;
+	ulong tmo;
+
+	start = get_ticks();		/* get current timestamp */
+	tmo = usec_to_tick(usec);	/* convert usecs to ticks */
+	while ((get_ticks() - start) < tmo)
+		;			/* loop till time has passed */
 }
 
 /*
- * This function is derived from PowerPC code (read timebase as long long).
- * On ARM it just returns the timer value.
+ * get_timer(base) can be used to check for timeouts or
+ * to measure elasped time relative to an event:
+ *
+ * ulong start_time = get_timer(0) sets start_time to the current
+ * time value.
+ * get_timer(start_time) returns the time elapsed since then.
+ *
+ * The time is used in CONFIG_SYS_HZ units!
  */
-unsigned long long get_ticks(void)
+ulong get_timer(ulong base)
 {
-	debug("%s()\n", __func__);
-	return get_timer(0);
+	return tick_to_time(get_ticks()) - 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)
 {
-	debug("%s()\n", __func__);
-	return CONFIG_SYS_HZ;
+	return gd->timer_rate_hz;
 }