[U-Boot-Users] [PATCH v2] ARM: Davinci: Fix DM644x timer overflow handling and cleanup

dirk.behme at googlemail.com dirk.behme at googlemail.com
Wed Mar 26 09:53:29 CET 2008


Fix ARM based DaVinci DM644x timer overflow handling and cleanup timer code.

Changes:

- Remove *_masked() functions as noted by Wolfgang

- Adapt register naming to recent TI spec (sprue26, March 2007)

- Fix reset_timer() handling

- As reported by Pieter [1] the overflow fix introduced a delay of factor 16 (e.g 2 seconds became 32). While the overflow fix is basically okay, it missed to divide udelay by 16, too. Fix this.

[1] http://article.gmane.org/gmane.comp.boot-loaders.u-boot/38179

- Remove software division of timer count value (DIV(x) macro) and do it in hardware (TIM_CLK_DIV).

Many thanks to Troy Kisky <troy.kisky at boundarydevices.com> and Pieter Voorthuijsen <pieter.voorthuijsen at Prodrive.nl> for the hints & testing!

Patch is compile tested with davinci_dvevm & sonata & schmoogie configuration and tested by Pieter on DaVinci EVM hardware.

Signed-off-by: Dirk Behme <dirk.behme at gmail.com>

---

This patch completely replaces first version of this patch

http://article.gmane.org/gmane.comp.boot-loaders.u-boot/38312/

Changes:

- Incorporate findings from testing on real HW: Don't change CFG_HZ_CLOCK in config files, instead divide in udelay() and get_timer() correctly.

Thanks to Pieter!

Index: uboot_davinci/cpu/arm926ejs/davinci/timer.c
===================================================================
--- uboot_davinci.orig/cpu/arm926ejs/davinci/timer.c
+++ uboot_davinci/cpu/arm926ejs/davinci/timer.c
@@ -42,9 +42,9 @@
 
 typedef volatile struct {
 	u_int32_t	pid12;
-	u_int32_t	emumgt_clksped;
-	u_int32_t	gpint_en;
-	u_int32_t	gpdir_dat;
+	u_int32_t	emumgt;
+	u_int32_t	na1;
+	u_int32_t	na2;
 	u_int32_t	tim12;
 	u_int32_t	tim34;
 	u_int32_t	prd12;
@@ -52,21 +52,12 @@ typedef volatile struct {
 	u_int32_t	tcr;
 	u_int32_t	tgcr;
 	u_int32_t	wdtcr;
-	u_int32_t	tlgc;
-	u_int32_t	tlmr;
 } davinci_timer;
 
 davinci_timer		*timer = (davinci_timer *)CFG_TIMERBASE;
 
 #define TIMER_LOAD_VAL	(CFG_HZ_CLOCK / CFG_HZ)
-#define READ_TIMER	timer->tim34
-
-/*
- * Timer runs with CFG_HZ_CLOCK, currently 27MHz. To avoid wrap
- * around of timestamp already after min ~159s, divide it, e.g. by 16.
- * timestamp will then wrap around all min ~42min
- */
-#define DIV(x)		((x) >> 4)
+#define TIM_CLK_DIV	16
 
 static ulong timestamp;
 static ulong lastinc;
@@ -76,63 +67,51 @@ int timer_init(void)
 	/* We are using timer34 in unchained 32-bit mode, full speed */
 	timer->tcr = 0x0;
 	timer->tgcr = 0x0;
-	timer->tgcr = 0x06;
+	timer->tgcr = 0x06 | ((TIM_CLK_DIV - 1) << 8);
 	timer->tim34 = 0x0;
 	timer->prd34 = TIMER_LOAD_VAL;
 	lastinc = 0;
-	timer->tcr = 0x80 << 16;
 	timestamp = 0;
+	timer->tcr = 2 << 22;
 
 	return(0);
 }
 
 void reset_timer(void)
 {
-	reset_timer_masked();
-}
-
-ulong get_timer(ulong base)
-{
-	return(get_timer_masked() - base);
-}
-
-void set_timer(ulong t)
-{
-	timestamp = t;
-}
-
-void udelay(unsigned long usec)
-{
-	udelay_masked(usec);
-}
-
-void reset_timer_masked(void)
-{
-	lastinc = DIV(READ_TIMER);
+	timer->tcr = 0x0;
+	timer->tim34 = 0;
+	lastinc = 0;
 	timestamp = 0;
+	timer->tcr = 2 << 22;
 }
 
-ulong get_timer_raw(void)
+static ulong get_timer_raw(void)
 {
-	ulong now = DIV(READ_TIMER);
+	ulong now = timer->tim34;
 
 	if (now >= lastinc) {
 		/* normal mode */
 		timestamp += now - lastinc;
 	} else {
 		/* overflow ... */
-		timestamp += now + DIV(TIMER_LOAD_VAL) - lastinc;
+		timestamp += now + TIMER_LOAD_VAL - lastinc;
 	}
 	lastinc = now;
 	return timestamp;
 }
 
-ulong get_timer_masked(void)
+ulong get_timer(ulong base)
+{
+	return((get_timer_raw() / (TIMER_LOAD_VAL / TIM_CLK_DIV)) - base);
+}
+
+void set_timer(ulong t)
 {
-	return(get_timer_raw() / DIV(TIMER_LOAD_VAL));
+	timestamp = t;
 }
 
-void udelay_masked(unsigned long usec)
+void udelay(unsigned long usec)
 {
 	ulong tmo;
 	ulong endtime;
@@ -140,7 +119,7 @@ void udelay_masked(unsigned long usec)
 
 	tmo = CFG_HZ_CLOCK / 1000;
 	tmo *= usec;
-	tmo /= 1000;
+	tmo /= (1000 * TIM_CLK_DIV);
 
 	endtime = get_timer_raw() + tmo;
 
@@ -165,8 +144,5 @@ unsigned long long get_ticks(void)
  */
 ulong get_tbclk(void)
 {
-	ulong tbclk;
-
-	tbclk = CFG_HZ;
-	return(tbclk);
+	return CFG_HZ;
 }




More information about the U-Boot mailing list