uboot/arch/arm/cpu/arm926ejs/mx27/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 * See file CREDITS for list of people who contributed to this
  17 * project.
  18 *
  19 * This program is free software; you can redistribute it and/or
  20 * modify it under the terms of the GNU General Public License as
  21 * published by the Free Software Foundation; either version 2 of
  22 * the License, or (at your option) any later version.
  23 *
  24 * This program is distributed in the hope that it will be useful,
  25 * but WITHOUT ANY WARRANTY; without even the implied warranty of
  26 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  27 * GNU General Public License for more details.
  28 *
  29 * You should have received a copy of the GNU General Public License
  30 * along with this program; if not, write to the Free Software
  31 * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
  32 * MA 02111-1307 USA
  33 */
  34
  35#include <common.h>
  36#include <div64.h>
  37#include <asm/io.h>
  38#include <asm/arch/imx-regs.h>
  39
  40/* General purpose timers bitfields */
  41#define GPTCR_SWR               (1 << 15)       /* Software reset       */
  42#define GPTCR_FRR               (1 << 8)        /* Freerun / restart    */
  43#define GPTCR_CLKSOURCE_32      (4 << 1)        /* Clock source         */
  44#define GPTCR_TEN               1               /* Timer enable         */
  45
  46static ulong timestamp;
  47static ulong lastinc;
  48
  49/*
  50 * "time" is measured in 1 / CONFIG_SYS_HZ seconds,
  51 * "tick" is internal timer period
  52 */
  53#ifdef CONFIG_MX27_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_MX27_CLK32);
  59        return tick;
  60}
  61
  62static inline unsigned long long time_to_tick(unsigned long long time)
  63{
  64        time *= CONFIG_MX27_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_MX27_CLK32 + 999999;
  72        do_div(us, 1000000);
  73        return us;
  74}
  75#else
  76/* ~2% error */
  77#define TICK_PER_TIME   ((CONFIG_MX27_CLK32 + CONFIG_SYS_HZ / 2) / \
  78                CONFIG_SYS_HZ)
  79#define US_PER_TICK     (1000000 / CONFIG_MX27_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 32768Hz 32-bit timer overruns in 131072 seconds */
 102int timer_init(void)
 103{
 104        int i;
 105        struct gpt_regs *regs = (struct gpt_regs *)IMX_TIM1_BASE;
 106        struct pll_regs *pll = (struct pll_regs *)IMX_PLL_BASE;
 107
 108        /* setup GP Timer 1 */
 109        writel(GPTCR_SWR, &regs->gpt_tctl);
 110
 111        writel(readl(&pll->pccr0) | PCCR0_GPT1_EN, &pll->pccr0);
 112        writel(readl(&pll->pccr1) | PCCR1_PERCLK1_EN, &pll->pccr1);
 113
 114        for (i = 0; i < 100; i++)
 115                writel(0, &regs->gpt_tctl); /* We have no udelay by now */
 116        writel(0, &regs->gpt_tprer); /* 32Khz */
 117        /* Freerun Mode, PERCLK1 input */
 118        writel(readl(&regs->gpt_tctl) | GPTCR_CLKSOURCE_32 | GPTCR_FRR,
 119                        &regs->gpt_tctl);
 120        writel(readl(&regs->gpt_tctl) | GPTCR_TEN, &regs->gpt_tctl);
 121
 122        return 0;
 123}
 124
 125void reset_timer_masked(void)
 126{
 127        struct gpt_regs *regs = (struct gpt_regs *)IMX_TIM1_BASE;
 128        /* reset time */
 129        /* capture current incrementer value time */
 130        lastinc = readl(&regs->gpt_tcn);
 131        timestamp = 0; /* start "advancing" time stamp from 0 */
 132}
 133
 134void reset_timer(void)
 135{
 136        reset_timer_masked();
 137}
 138
 139unsigned long long get_ticks (void)
 140{
 141        struct gpt_regs *regs = (struct gpt_regs *)IMX_TIM1_BASE;
 142        ulong now = readl(&regs->gpt_tcn); /* current tick value */
 143
 144        if (now >= lastinc) {
 145                /*
 146                 * normal mode (non roll)
 147                 * move stamp forward with absolut diff ticks
 148                 */
 149                timestamp += (now - lastinc);
 150        } else {
 151                /* we have rollover of incrementer */
 152                timestamp += (0xFFFFFFFF - lastinc) + now;
 153        }
 154        lastinc = now;
 155        return timestamp;
 156}
 157
 158ulong get_timer_masked (void)
 159{
 160        /*
 161         * get_ticks() returns a long long (64 bit), it wraps in
 162         * 2^64 / CONFIG_MX27_CLK32 = 2^64 / 2^15 = 2^49 ~ 5 * 10^14 (s) ~
 163         * 5 * 10^9 days... and get_ticks() * CONFIG_SYS_HZ wraps in
 164         * 5 * 10^6 days - long enough.
 165         */
 166        return tick_to_time(get_ticks());
 167}
 168
 169ulong get_timer (ulong base)
 170{
 171        return get_timer_masked () - base;
 172}
 173
 174void set_timer (ulong t)
 175{
 176        timestamp = time_to_tick(t);
 177}
 178
 179/* delay x useconds AND preserve advance timstamp value */
 180void __udelay (unsigned long usec)
 181{
 182        unsigned long long tmp;
 183        ulong tmo;
 184
 185        tmo = us_to_tick(usec);
 186        tmp = get_ticks() + tmo;        /* get current timestamp */
 187
 188        while (get_ticks() < tmp)       /* loop till event */
 189                 /*NOP*/;
 190}
 191