#include <common.h>
 #include <asm/io.h>
 
+DECLARE_GLOBAL_DATA_PTR;
+
 struct davinci_timer {
        u_int32_t       pid12;
        u_int32_t       emumgt;
 static struct davinci_timer * const timer =
        (struct davinci_timer *)CONFIG_SYS_TIMERBASE;
 
-#define TIMER_LOAD_VAL (CONFIG_SYS_HZ_CLOCK / CONFIG_SYS_HZ)
-#define TIM_CLK_DIV    16
+#define TIMER_LOAD_VAL 0xffffffff
 
-static ulong timestamp;
-static ulong lastinc;
+#define TIM_CLK_DIV    16
 
 int timer_init(void)
 {
        writel(0x06 | ((TIM_CLK_DIV - 1) << 8), &timer->tgcr);
        writel(0x0, &timer->tim34);
        writel(TIMER_LOAD_VAL, &timer->prd34);
-       lastinc = 0;
-       timestamp = 0;
        writel(2 << 22, &timer->tcr);
+       gd->timer_rate_hz = CONFIG_SYS_HZ_CLOCK / TIM_CLK_DIV;
+       gd->timer_reset_value = 0;
 
        return(0);
 }
 
 void reset_timer(void)
 {
-       writel(0x0, &timer->tcr);
-       writel(0x0, &timer->tim34);
-       lastinc = 0;
-       timestamp = 0;
-       writel(2 << 22, &timer->tcr);
+       gd->timer_reset_value = get_ticks();
 }
 
-static ulong get_timer_raw(void)
+/*
+ * Get the current 64 bit timer tick count
+ */
+unsigned long long get_ticks(void)
 {
-       ulong now = readl(&timer->tim34);
-
-       if (now >= lastinc) {
-               /* normal mode */
-               timestamp += now - lastinc;
-       } else {
-               /* overflow ... */
-               timestamp += now + TIMER_LOAD_VAL - lastinc;
-       }
-       lastinc = now;
-       return timestamp;
+       unsigned long now = readl(&timer->tim34);
+
+       /* 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;
 }
 
 ulong get_timer(ulong base)
 {
-       return((get_timer_raw() / (TIMER_LOAD_VAL / TIM_CLK_DIV)) - base);
-}
+       unsigned long long timer_diff;
 
-void set_timer(ulong t)
-{
-       timestamp = t;
+       timer_diff = get_ticks() - gd->timer_reset_value;
+
+       return (timer_diff / (gd->timer_rate_hz / CONFIG_SYS_HZ)) - base;
 }
 
 void __udelay(unsigned long usec)
 {
-       ulong tmo;
-       ulong endtime;
-       signed long diff;
-
-       tmo = CONFIG_SYS_HZ_CLOCK / 1000;
-       tmo *= usec;
-       tmo /= (1000 * TIM_CLK_DIV);
-
-       endtime = get_timer_raw() + tmo;
+       unsigned long long endtime;
 
-       do {
-               ulong now = get_timer_raw();
-               diff = endtime - now;
-       } while (diff >= 0);
-}
+       endtime = ((unsigned long long)usec * gd->timer_rate_hz) / 1000000UL;
+       endtime += get_ticks();
 
-/*
- * This function is derived from PowerPC code (read timebase as long long).
- * On ARM it just returns the timer value.
- */
-unsigned long long get_ticks(void)
-{
-       return(get_timer(0));
+       while (get_ticks() < endtime)
+               ;
 }
 
 /*