uboot/arch/arm/cpu/arm920t/ep93xx/timer.c
<<
>>
Prefs
   1/*
   2 * Cirrus Logic EP93xx timer support.
   3 *
   4 * Copyright (C) 2009, 2010 Matthias Kaehlcke <matthias@kaehlcke.net>
   5 *
   6 * Copyright (C) 2004, 2005
   7 * Cory T. Tusar, Videon Central, Inc., <ctusar@videon-central.com>
   8 *
   9 * Based on the original intr.c Cirrus Logic EP93xx Rev D. interrupt support,
  10 * author unknown.
  11 *
  12 * SPDX-License-Identifier:     GPL-2.0+
  13 */
  14
  15#include <common.h>
  16#include <linux/types.h>
  17#include <asm/arch/ep93xx.h>
  18#include <asm/io.h>
  19#include <div64.h>
  20
  21#define TIMER_CLKSEL    (1 << 3)
  22#define TIMER_ENABLE    (1 << 7)
  23
  24#define TIMER_FREQ                      508469          /* ticks / second */
  25#define TIMER_MAX_VAL                   0xFFFFFFFF
  26
  27static struct ep93xx_timer
  28{
  29        unsigned long long ticks;
  30        unsigned long last_read;
  31} timer;
  32
  33static inline unsigned long long usecs_to_ticks(unsigned long usecs)
  34{
  35        unsigned long long ticks = (unsigned long long)usecs * TIMER_FREQ;
  36        do_div(ticks, 1000 * 1000);
  37
  38        return ticks;
  39}
  40
  41static inline void read_timer(void)
  42{
  43        struct timer_regs *timer_regs = (struct timer_regs *)TIMER_BASE;
  44        const unsigned long now = TIMER_MAX_VAL - readl(&timer_regs->timer3.value);
  45
  46        if (now >= timer.last_read)
  47                timer.ticks += now - timer.last_read;
  48        else
  49                /* an overflow occurred */
  50                timer.ticks += TIMER_MAX_VAL - timer.last_read + now;
  51
  52        timer.last_read = now;
  53}
  54
  55/*
  56 * Get the number of ticks (in CONFIG_SYS_HZ resolution)
  57 */
  58unsigned long long get_ticks(void)
  59{
  60        unsigned long long sys_ticks;
  61
  62        read_timer();
  63
  64        sys_ticks = timer.ticks * CONFIG_SYS_HZ;
  65        do_div(sys_ticks, TIMER_FREQ);
  66
  67        return sys_ticks;
  68}
  69
  70unsigned long get_timer_masked(void)
  71{
  72        return get_ticks();
  73}
  74
  75unsigned long get_timer(unsigned long base)
  76{
  77        return get_timer_masked() - base;
  78}
  79
  80void __udelay(unsigned long usec)
  81{
  82        unsigned long long target;
  83
  84        read_timer();
  85
  86        target = timer.ticks + usecs_to_ticks(usec);
  87
  88        while (timer.ticks < target)
  89                read_timer();
  90}
  91
  92int timer_init(void)
  93{
  94        struct timer_regs *timer_regs = (struct timer_regs *)TIMER_BASE;
  95
  96        /* use timer 3 with 508KHz and free running, not enabled now */
  97        writel(TIMER_CLKSEL, &timer_regs->timer3.control);
  98
  99        /* set initial timer value */
 100        writel(TIMER_MAX_VAL, &timer_regs->timer3.load);
 101
 102        /* Enable the timer */
 103        writel(TIMER_ENABLE | TIMER_CLKSEL,
 104                &timer_regs->timer3.control);
 105
 106        /* Reset the timer */
 107        read_timer();
 108        timer.ticks = 0;
 109
 110        return 0;
 111}
 112
 113/*
 114 * This function is derived from PowerPC code (timebase clock frequency).
 115 * On ARM it returns the number of timer ticks per second.
 116 */
 117unsigned long get_tbclk(void)
 118{
 119        return CONFIG_SYS_HZ;
 120}
 121