Commit 8dfafdde88eb3e71d5569846396ae67a91017232

Authored by Rob Herring
Committed by Tom Rini
1 parent e32a268b6f

Introduce common timer functions

Many platforms duplicate pretty much the same timer code yet they all have
a 32-bit freerunning counter register. Create a common implementation that
minimally requires 2 or 3 defines to add timer support:

CONFIG_SYS_TIMER_RATE - Clock rate of the timer counter
CONFIG_SYS_TIMER_COUNTER - Address of 32-bit counter
CONFIG_SYS_TIMER_COUNTS_DOWN - Define if counter counts down

All functions are weak or ifdef'ed so they can still be overriden by any
platform.

Signed-off-by: Rob Herring <rob.herring@calxeda.com>

Showing 2 changed files with 75 additions and 0 deletions Side-by-side Diff

include/asm-generic/global_data.h
... ... @@ -72,6 +72,8 @@
72 72 #if defined(CONFIG_SYS_I2C)
73 73 int cur_i2c_bus; /* current used i2c bus */
74 74 #endif
  75 + unsigned long timebase_h;
  76 + unsigned long timebase_l;
75 77 struct arch_global_data arch; /* architecture-specific data */
76 78 } gd_t;
77 79 #endif
... ... @@ -7,6 +7,8 @@
7 7  
8 8 #include <common.h>
9 9 #include <watchdog.h>
  10 +#include <div64.h>
  11 +#include <asm/io.h>
10 12  
11 13 #if CONFIG_SYS_HZ != 1000
12 14 #warning "CONFIG_SYS_HZ must be 1000 and should not be defined by platforms"
... ... @@ -15,6 +17,77 @@
15 17 #ifndef CONFIG_WD_PERIOD
16 18 # define CONFIG_WD_PERIOD (10 * 1000 * 1000) /* 10 seconds default*/
17 19 #endif
  20 +
  21 +DECLARE_GLOBAL_DATA_PTR;
  22 +
  23 +#ifdef CONFIG_SYS_TIMER_RATE
  24 +ulong notrace get_tbclk(void)
  25 +{
  26 + return CONFIG_SYS_TIMER_RATE;
  27 +}
  28 +#endif
  29 +
  30 +#ifdef CONFIG_SYS_TIMER_COUNTER
  31 +unsigned long notrace timer_read_counter(void)
  32 +{
  33 +#ifdef CONFIG_SYS_TIMER_COUNTS_DOWN
  34 + return ~readl(CONFIG_SYS_TIMER_COUNTER);
  35 +#else
  36 + return readl(CONFIG_SYS_TIMER_COUNTER);
  37 +#endif
  38 +}
  39 +#else
  40 +extern unsigned long timer_read_counter(void);
  41 +#endif
  42 +
  43 +unsigned long long __weak notrace get_ticks(void)
  44 +{
  45 + unsigned long now = timer_read_counter();
  46 +
  47 + /* increment tbu if tbl has rolled over */
  48 + if (now < gd->timebase_l)
  49 + gd->timebase_h++;
  50 + gd->timebase_l = now;
  51 + return ((unsigned long long)gd->timebase_h << 32) | gd->timebase_l;
  52 +}
  53 +
  54 +static unsigned long long notrace tick_to_time(unsigned long long tick)
  55 +{
  56 + unsigned int div = get_tbclk();
  57 +
  58 + tick *= CONFIG_SYS_HZ;
  59 + do_div(tick, div);
  60 + return tick;
  61 +}
  62 +
  63 +ulong __weak get_timer(ulong base)
  64 +{
  65 + return tick_to_time(get_ticks()) - base;
  66 +}
  67 +
  68 +unsigned long __weak notrace timer_get_us(void)
  69 +{
  70 + return tick_to_time(get_ticks() * 1000);
  71 +}
  72 +static unsigned long long usec_to_tick(unsigned long usec)
  73 +{
  74 + unsigned long long tick = usec * get_tbclk();
  75 + usec *= get_tbclk();
  76 + do_div(tick, 1000000);
  77 + return tick;
  78 +}
  79 +
  80 +void __weak __udelay(unsigned long usec)
  81 +{
  82 + unsigned long long tmp;
  83 + ulong tmo;
  84 +
  85 + tmo = usec_to_tick(usec);
  86 + tmp = get_ticks() + tmo; /* get current timestamp */
  87 +
  88 + while (get_ticks() < tmp) /* loop till event */
  89 + /*NOP*/;
  90 +}
18 91  
19 92 /* ------------------------------------------------------------------------- */
20 93