]> git.kernelconcepts.de Git - karo-tx-uboot.git/blobdiff - arch/arm/cpu/armv7/omap-common/timer.c
TX6 Release 2013-04-22
[karo-tx-uboot.git] / arch / arm / cpu / armv7 / omap-common / timer.c
index 36bea5f94c118c8adeb69e83eb99800107c41921..2292ea0eafe4882adb8f2969cc7f6db60cfad4bd 100644 (file)
@@ -33,7 +33,9 @@
  */
 
 #include <common.h>
+#include <div64.h>
 #include <asm/io.h>
+#include <asm/arch/cpu.h>
 
 DECLARE_GLOBAL_DATA_PTR;
 
@@ -43,23 +45,66 @@ static struct gptimer *timer_base = (struct gptimer *)CONFIG_SYS_TIMERBASE;
  * Nothing really to do with interrupts, just starts up a counter.
  */
 
+#if CONFIG_SYS_PTV > 7
+#error Invalid CONFIG_SYS_PTV value
+#elif CONFIG_SYS_PTV >= 0
 #define TIMER_CLOCK            (V_SCLK / (2 << CONFIG_SYS_PTV))
-#define TIMER_OVERFLOW_VAL     0xffffffff
+#define TCLR_VAL               ((CONFIG_SYS_PTV << 2) | TCLR_PRE | TCLR_AR | TCLR_ST)
+#else
+#define TIMER_CLOCK            V_SCLK
+#define TCLR_VAL               (TCLR_AR | TCLR_ST)
+#endif
 #define TIMER_LOAD_VAL         0
 
+#if TIMER_CLOCK < CONFIG_SYS_HZ
+#error TIMER_CLOCK must be > CONFIG_SYS_HZ
+#endif
+
+/*
+ * Start timer so that it will overflow 15 sec after boot,
+ * to catch misbehaving timer code early on!
+*/
+#define TIMER_START            (-time_to_tick(15 * CONFIG_SYS_HZ))
+
+static inline unsigned long tick_to_time(unsigned long tick)
+{
+       return tick / (TIMER_CLOCK / CONFIG_SYS_HZ);
+}
+
+static inline unsigned long time_to_tick(unsigned long time)
+{
+       return time * (TIMER_CLOCK / CONFIG_SYS_HZ);
+}
+
+static inline unsigned long us_to_ticks(unsigned long usec)
+{
+       return usec * (TIMER_CLOCK / CONFIG_SYS_HZ / 1000);
+}
+
 int timer_init(void)
 {
+#if !defined(CONFIG_SPL) || defined(CONFIG_SPL_BUILD)
+       /* Reset the Timer */
+       writel(0x2, &timer_base->tscir);
+
+       /* Wait until the reset is done */
+       while (readl(&timer_base->tiocp_cfg) & 1)
+               ;
+
+       /* preload the counter to make overflow occur early */
+       writel(TIMER_START, &timer_base->tldr);
+       writel(~0, &timer_base->ttgr);
+
        /* start the counter ticking up, reload value on overflow */
        writel(TIMER_LOAD_VAL, &timer_base->tldr);
        /* enable timer */
-       writel((CONFIG_SYS_PTV << 2) | TCLR_PRE | TCLR_AR | TCLR_ST,
-               &timer_base->tclr);
-
-       /* reset time, capture current incrementer value time */
-       gd->arch.lastinc = readl(&timer_base->tcrr) /
-                                       (TIMER_CLOCK / CONFIG_SYS_HZ);
-       gd->arch.tbl = 0;       /* start "advancing" time stamp from 0 */
-
+       writel(TCLR_VAL, &timer_base->tclr);
+#endif
+#ifndef CONFIG_SPL_BUILD
+       gd->arch.lastinc = -30 * TIMER_CLOCK;
+       gd->arch.tbl = TIMER_START;
+       gd->arch.timer_rate_hz = TIMER_CLOCK;
+#endif
        return 0;
 }
 
@@ -68,39 +113,29 @@ int timer_init(void)
  */
 ulong get_timer(ulong base)
 {
-       return get_timer_masked() - base;
+       return tick_to_time(get_ticks() - time_to_tick(base));
 }
 
 /* delay x useconds */
 void __udelay(unsigned long usec)
 {
-       long tmo = usec * (TIMER_CLOCK / 1000) / 1000;
-       unsigned long now, last = readl(&timer_base->tcrr);
-
-       while (tmo > 0) {
-               now = readl(&timer_base->tcrr);
-               if (last > now) /* count up timer overflow */
-                       tmo -= TIMER_OVERFLOW_VAL - last + now + 1;
-               else
-                       tmo -= now - last;
-               last = now;
-       }
+       unsigned long start = readl(&timer_base->tcrr);
+       unsigned long ticks = us_to_ticks(usec);
+
+       if (usec == 0)
+               return;
+
+       if (ticks == 0)
+               ticks++;
+
+       while (readl(&timer_base->tcrr) - start < ticks)
+               /* NOP */ ;
 }
 
 ulong get_timer_masked(void)
 {
        /* current tick value */
-       ulong now = readl(&timer_base->tcrr) / (TIMER_CLOCK / CONFIG_SYS_HZ);
-
-       if (now >= gd->arch.lastinc) {  /* normal mode (non roll) */
-               /* move stamp fordward with absoulte diff ticks */
-               gd->arch.tbl += (now - gd->arch.lastinc);
-       } else {        /* we have rollover of incrementer */
-               gd->arch.tbl += ((TIMER_LOAD_VAL / (TIMER_CLOCK /
-                               CONFIG_SYS_HZ)) - gd->arch.lastinc) + now;
-       }
-       gd->arch.lastinc = now;
-       return gd->arch.tbl;
+       return tick_to_time(get_ticks());
 }
 
 /*
@@ -109,7 +144,12 @@ ulong get_timer_masked(void)
  */
 unsigned long long get_ticks(void)
 {
-       return get_timer(0);
+       ulong now = readl(&timer_base->tcrr);
+       ulong inc = now - gd->arch.lastinc;
+
+       gd->arch.tbl += inc;
+       gd->arch.lastinc = now;
+       return gd->arch.tbl;
 }
 
 /*
@@ -118,5 +158,5 @@ unsigned long long get_ticks(void)
  */
 ulong get_tbclk(void)
 {
-       return CONFIG_SYS_HZ;
+       return gd->arch.timer_rate_hz;
 }