AT91 clock/timer: move static data to global_data struct
[oweals/u-boot.git] / arch / arm / cpu / arm926ejs / at91 / timer.c
index 8efc34bcf12061d81244e6736c45b38b54e32b17..82b8d7e7d7f65bc39023444270feff720f20b13d 100644 (file)
 #include <asm/arch/io.h>
 #include <div64.h>
 
+#if !defined(CONFIG_AT91FAMILY)
+# error You need to define CONFIG_AT91FAMILY in your board config!
+#endif
+
+DECLARE_GLOBAL_DATA_PTR;
+
 /*
  * We're using the AT91CAP9/SAM9 PITC in 32 bit mode, by
  * setting the 20 bit counter period to its maximum (0xfffff).
+ * (See the relevant data sheets to understand that this really works)
+ *
+ * We do also mimic the typical powerpc way of incrementing
+ * two 32 bit registers called tbl and tbu.
+ *
+ * Those registers increment at 1/16 the main clock rate.
  */
-#define TIMER_LOAD_VAL 0xfffff
 
-static ulong timestamp;
-static ulong lastinc;
-static ulong timer_freq;
+#define TIMER_LOAD_VAL 0xfffff
 
 static inline unsigned long long tick_to_time(unsigned long long tick)
 {
        tick *= CONFIG_SYS_HZ;
-       do_div(tick, timer_freq);
+       do_div(tick, gd->timer_rate_hz);
 
        return tick;
 }
 
 static inline unsigned long long usec_to_tick(unsigned long long usec)
 {
-       usec *= timer_freq;
+       usec *= gd->timer_rate_hz;
        do_div(usec, 1000000);
 
        return usec;
 }
 
-/* nothing really to do with interrupts, just starts up a counter. */
+/*
+ * Use the PITC in full 32 bit incrementing mode
+ */
 int timer_init(void)
 {
        at91_pmc_t *pmc = (at91_pmc_t *) AT91_PMC_BASE;
        at91_pit_t *pit = (at91_pit_t *) AT91_PIT_BASE;
-       /*
-        * Enable PITC Clock
-        * The clock is already enabled for system controller in boot
-        */
+
+       /* Enable PITC Clock */
        writel(1 << AT91_ID_SYS, &pmc->pcer);
 
        /* Enable PITC */
        writel(TIMER_LOAD_VAL | AT91_PIT_MR_EN , &pit->mr);
 
-       reset_timer_masked();
-
-       timer_freq = get_mck_clk_rate() >> 4;
+       gd->timer_rate_hz = gd->mck_rate_hz / 16;
+       gd->tbu = gd->tbl = 0;
 
        return 0;
 }
 
 /*
- * timer without interrupts
+ * Get the current 64 bit timer tick count
  */
 unsigned long long get_ticks(void)
 {
@@ -86,28 +94,11 @@ unsigned long long get_ticks(void)
 
        ulong now = readl(&pit->piir);
 
-       if (now >= lastinc)     /* normal mode (non roll) */
-               /* move stamp forward with absolut diff ticks */
-               timestamp += (now - lastinc);
-       else                    /* we have rollover of incrementer */
-               timestamp += (0xFFFFFFFF - lastinc) + now;
-       lastinc = now;
-       return timestamp;
-}
-
-void reset_timer_masked(void)
-{
-       /* reset time */
-       at91_pit_t *pit = (at91_pit_t *) AT91_PIT_BASE;
-
-       /* capture current incrementer value time */
-       lastinc = readl(&pit->piir);
-       timestamp = 0; /* start "advancing" time stamp from 0 */
-}
-
-ulong get_timer_masked(void)
-{
-       return tick_to_time(get_ticks());
+       /* 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;
 }
 
 void __udelay(unsigned long usec)
@@ -119,24 +110,32 @@ void __udelay(unsigned long usec)
        tmp = get_ticks() + tmo;        /* get current timestamp */
 
        while (get_ticks() < tmp)       /* loop till event */
-                /*NOP*/;
+               ;
 }
 
+/*
+ * reset_timer() and get_timer(base) are a pair of functions that are used by
+ * some timeout/sleep mechanisms in u-boot.
+ *
+ * reset_timer() marks the current time as epoch and
+ * get_timer(base) works relative to that epoch.
+ *
+ * The time is used in CONFIG_SYS_HZ units!
+ */
 void reset_timer(void)
 {
-       reset_timer_masked();
+       gd->timer_reset_value = get_ticks();
 }
 
 ulong get_timer(ulong base)
 {
-       return get_timer_masked () - base;
+       return tick_to_time(get_ticks() - gd->timer_reset_value) - 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)
 {
-       return timer_freq;
+       return gd->timer_rate_hz;
 }