uboot/arch/arm/cpu/arm926ejs/mx25/timer.c
<<
>>
Prefs
   1/*
   2 * (C) Copyright 2002
   3 * Sysgo Real-Time Solutions, GmbH <www.elinos.com>
   4 * Marius Groeger <mgroeger@sysgo.de>
   5 *
   6 * (C) Copyright 2002
   7 * Sysgo Real-Time Solutions, GmbH <www.elinos.com>
   8 * Alex Zuepke <azu@sysgo.de>
   9 *
  10 * (C) Copyright 2002
  11 * Gary Jennejohn, DENX Software Engineering, <gj@denx.de>
  12 *
  13 * (C) Copyright 2009
  14 * Ilya Yanok, Emcraft Systems Ltd, <yanok@emcraft.com>
  15 *
  16 * (C) Copyright 2009 DENX Software Engineering
  17 * Author: John Rigby <jrigby@gmail.com>
  18 *      Add support for MX25
  19 *
  20 * See file CREDITS for list of people who contributed to this
  21 * project.
  22 *
  23 * This program is free software; you can redistribute it and/or
  24 * modify it under the terms of the GNU General Public License as
  25 * published by the Free Software Foundation; either version 2 of
  26 * the License, or (at your option) any later version.
  27 *
  28 * This program is distributed in the hope that it will be useful,
  29 * but WITHOUT ANY WARRANTY; without even the implied warranty of
  30 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  31 * GNU General Public License for more details.
  32 *
  33 * You should have received a copy of the GNU General Public License
  34 * along with this program; if not, write to the Free Software
  35 * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
  36 * MA 02111-1307 USA
  37 */
  38
  39#include <common.h>
  40#include <div64.h>
  41#include <asm/io.h>
  42#include <asm/arch/imx-regs.h>
  43
  44DECLARE_GLOBAL_DATA_PTR;
  45
  46#define timestamp       (gd->tbl)
  47#define lastinc         (gd->lastinc)
  48
  49/*
  50 * "time" is measured in 1 / CONFIG_SYS_HZ seconds,
  51 * "tick" is internal timer period
  52 */
  53#ifdef CONFIG_MX25_TIMER_HIGH_PRECISION
  54/* ~0.4% error - measured with stop-watch on 100s boot-delay */
  55static inline unsigned long long tick_to_time(unsigned long long tick)
  56{
  57        tick *= CONFIG_SYS_HZ;
  58        do_div(tick, CONFIG_MX25_CLK32);
  59        return tick;
  60}
  61
  62static inline unsigned long long time_to_tick(unsigned long long time)
  63{
  64        time *= CONFIG_MX25_CLK32;
  65        do_div(time, CONFIG_SYS_HZ);
  66        return time;
  67}
  68
  69static inline unsigned long long us_to_tick(unsigned long long us)
  70{
  71        us = us * CONFIG_MX25_CLK32 + 999999;
  72        do_div(us, 1000000);
  73        return us;
  74}
  75#else
  76/* ~2% error */
  77#define TICK_PER_TIME   ((CONFIG_MX25_CLK32 + CONFIG_SYS_HZ / 2) / \
  78                CONFIG_SYS_HZ)
  79#define US_PER_TICK     (1000000 / CONFIG_MX25_CLK32)
  80
  81static inline unsigned long long tick_to_time(unsigned long long tick)
  82{
  83        do_div(tick, TICK_PER_TIME);
  84        return tick;
  85}
  86
  87static inline unsigned long long time_to_tick(unsigned long long time)
  88{
  89        return time * TICK_PER_TIME;
  90}
  91
  92static inline unsigned long long us_to_tick(unsigned long long us)
  93{
  94        us += US_PER_TICK - 1;
  95        do_div(us, US_PER_TICK);
  96        return us;
  97}
  98#endif
  99
 100/* nothing really to do with interrupts, just starts up a counter. */
 101/* The 32KHz 32-bit timer overruns in 134217 seconds */
 102int timer_init(void)
 103{
 104        int i;
 105        struct gpt_regs *gpt = (struct gpt_regs *)IMX_GPT1_BASE;
 106        struct ccm_regs *ccm = (struct ccm_regs *)IMX_CCM_BASE;
 107
 108        /* setup GP Timer 1 */
 109        writel(GPT_CTRL_SWR, &gpt->ctrl);
 110
 111        writel(readl(&ccm->cgr1) | CCM_CGR1_GPT1, &ccm->cgr1);
 112
 113        for (i = 0; i < 100; i++)
 114                writel(0, &gpt->ctrl); /* We have no udelay by now */
 115        writel(0, &gpt->pre); /* prescaler = 1 */
 116        /* Freerun Mode, 32KHz input */
 117        writel(readl(&gpt->ctrl) | GPT_CTRL_CLKSOURCE_32 | GPT_CTRL_FRR,
 118                        &gpt->ctrl);
 119        writel(readl(&gpt->ctrl) | GPT_CTRL_TEN, &gpt->ctrl);
 120
 121        return 0;
 122}
 123
 124unsigned long long get_ticks(void)
 125{
 126        struct gpt_regs *gpt = (struct gpt_regs *)IMX_GPT1_BASE;
 127        ulong now = readl(&gpt->counter); /* current tick value */
 128
 129        if (now >= lastinc) {
 130                /*
 131                 * normal mode (non roll)
 132                 * move stamp forward with absolut diff ticks
 133                 */
 134                timestamp += (now - lastinc);
 135        } else {
 136                /* we have rollover of incrementer */
 137                timestamp += (0xFFFFFFFF - lastinc) + now;
 138        }
 139        lastinc = now;
 140        return timestamp;
 141}
 142
 143ulong get_timer_masked(void)
 144{
 145        /*
 146         * get_ticks() returns a long long (64 bit), it wraps in
 147         * 2^64 / CONFIG_MX25_CLK32 = 2^64 / 2^15 = 2^49 ~ 5 * 10^14 (s) ~
 148         * 5 * 10^9 days... and get_ticks() * CONFIG_SYS_HZ wraps in
 149         * 5 * 10^6 days - long enough.
 150         */
 151        return tick_to_time(get_ticks());
 152}
 153
 154ulong get_timer(ulong base)
 155{
 156        return get_timer_masked() - base;
 157}
 158
 159/* delay x useconds AND preserve advance timstamp value */
 160void __udelay(unsigned long usec)
 161{
 162        unsigned long long tmp;
 163        ulong tmo;
 164
 165        tmo = us_to_tick(usec);
 166        tmp = get_ticks() + tmo;        /* get current timestamp */
 167
 168        while (get_ticks() < tmp)       /* loop till event */
 169                 /*NOP*/;
 170}
 171
 172/*
 173 * This function is derived from PowerPC code (timebase clock frequency).
 174 * On ARM it returns the number of timer ticks per second.
 175 */
 176ulong get_tbclk(void)
 177{
 178        ulong tbclk;
 179
 180        tbclk = CONFIG_MX25_CLK32;
 181        return tbclk;
 182}
 183