uboot/cpu/arm920t/ep93xx/timer.c
<<
>>
Prefs
   1/*
   2 * Cirrus Logic EP93xx timer support.
   3 *
   4 * Copyright (C) 2009, 2010
   5 * Matthias Kaehlcke <matthias@kaehlcke.net>
   6 *
   7 * Copyright (C) 2004, 2005
   8 * Cory T. Tusar, Videon Central, Inc., <ctusar@videon-central.com>
   9 *
  10 * Based on the original intr.c Cirrus Logic EP93xx Rev D. interrupt support,
  11 * author unknown.
  12 *
  13 * See file CREDITS for list of people who contributed to this project.
  14 *
  15 * This program is free software; you can redistribute it and/or modify
  16 * it under the terms of the GNU General Public License as published by
  17 * the Free Software Foundation; either version 2 of the License, or
  18 * (at your option) any later version.
  19 *
  20 * This program is distributed in the hope that it will be useful, but
  21 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
  22 * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
  23 * for more details.
  24 *
  25 * You should have received a copy of the GNU General Public License along
  26 * with this program; if not, write to the Free Software Foundation, Inc.,
  27 * 675 Mass Ave, Cambridge, MA 02139, USA.
  28 */
  29
  30#include <common.h>
  31#include <linux/types.h>
  32#include <asm/arch/ep93xx.h>
  33#include <asm/io.h>
  34#include <div64.h>
  35
  36#define TIMER_CLKSEL    (1 << 3)
  37#define TIMER_ENABLE    (1 << 7)
  38
  39#define TIMER_FREQ                      508469          /* ticks / second */
  40#define TIMER_MAX_VAL                   0xFFFFFFFF
  41
  42static struct ep93xx_timer
  43{
  44        unsigned long long ticks;
  45        unsigned long last_update;
  46} timer;
  47
  48static inline unsigned long clk_to_systicks(unsigned long long clk_ticks)
  49{
  50        unsigned long long sys_ticks = (clk_ticks * CONFIG_SYS_HZ);
  51        do_div(sys_ticks, TIMER_FREQ);
  52
  53        return (unsigned long)sys_ticks;
  54}
  55
  56static inline unsigned long long usecs_to_ticks(unsigned long usecs)
  57{
  58        unsigned long long ticks = (unsigned long long)usecs * TIMER_FREQ;
  59        do_div(ticks, 1000 * 1000);
  60
  61        return ticks;
  62}
  63
  64static inline unsigned long read_timer(void)
  65{
  66        struct timer_regs *timer = (struct timer_regs *)TIMER_BASE;
  67
  68        return TIMER_MAX_VAL - readl(&timer->timer3.value);
  69}
  70
  71/*
  72 * Get the number of ticks (in CONFIG_SYS_HZ resolution)
  73 */
  74unsigned long long get_ticks(void)
  75{
  76        const unsigned long now = read_timer();
  77
  78        if (now >= timer.last_update)
  79                timer.ticks += now - timer.last_update;
  80        else
  81                /* an overflow occurred */
  82                timer.ticks += TIMER_MAX_VAL - timer.last_update + now;
  83
  84        timer.last_update = now;
  85
  86        return clk_to_systicks(timer.ticks);
  87}
  88
  89unsigned long get_timer_masked(void)
  90{
  91        return get_ticks();
  92}
  93
  94unsigned long get_timer(unsigned long base)
  95{
  96        return get_timer_masked() - base;
  97}
  98
  99void reset_timer_masked(void)
 100{
 101        timer.last_update = read_timer();
 102        timer.ticks = 0;
 103}
 104
 105void reset_timer(void)
 106{
 107        reset_timer_masked();
 108}
 109
 110void __udelay(unsigned long usec)
 111{
 112        /* read the timer and update timer.ticks */
 113        get_ticks();
 114
 115        const unsigned long long target = timer.ticks + usecs_to_ticks(usec);
 116
 117        while (timer.ticks < target)
 118                get_ticks();
 119}
 120
 121int timer_init(void)
 122{
 123        struct timer_regs *timer = (struct timer_regs *)TIMER_BASE;
 124
 125        /* use timer 3 with 508KHz and free running */
 126        writel(TIMER_CLKSEL, &timer->timer3.control);
 127
 128        /* set initial timer value 3 */
 129        writel(TIMER_MAX_VAL, &timer->timer3.load);
 130
 131        /* Enable the timer */
 132        writel(TIMER_ENABLE | TIMER_CLKSEL,
 133                &timer->timer3.control);
 134
 135        reset_timer_masked();
 136
 137        return 0;
 138}
 139
 140/*
 141 * This function is derived from PowerPC code (timebase clock frequency).
 142 * On ARM it returns the number of timer ticks per second.
 143 */
 144unsigned long get_tbclk(void)
 145{
 146        return CONFIG_SYS_HZ;
 147}
 148