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 * SPDX-License-Identifier:     GPL-2.0+
  17 */
  18
  19#include <common.h>
  20#include <div64.h>
  21#include <asm/io.h>
  22#include <asm/arch/imx-regs.h>
  23
  24/* General purpose timers bitfields */
  25#define GPTCR_SWR               (1 << 15)       /* Software reset       */
  26#define GPTCR_FRR               (1 << 8)        /* Freerun / restart    */
  27#define GPTCR_CLKSOURCE_32      (4 << 1)        /* Clock source         */
  28#define GPTCR_TEN               1               /* Timer enable         */
  29
  30DECLARE_GLOBAL_DATA_PTR;
  31
  32#define timestamp       (gd->arch.tbl)
  33#define lastinc         (gd->arch.lastinc)
  34
  35/*
  36 * "time" is measured in 1 / CONFIG_SYS_HZ seconds,
  37 * "tick" is internal timer period
  38 */
  39#ifdef CONFIG_MX27_TIMER_HIGH_PRECISION
  40/* ~0.4% error - measured with stop-watch on 100s boot-delay */
  41static inline unsigned long long tick_to_time(unsigned long long tick)
  42{
  43        tick *= CONFIG_SYS_HZ;
  44        do_div(tick, CONFIG_MX27_CLK32);
  45        return tick;
  46}
  47
  48static inline unsigned long long time_to_tick(unsigned long long time)
  49{
  50        time *= CONFIG_MX27_CLK32;
  51        do_div(time, CONFIG_SYS_HZ);
  52        return time;
  53}
  54
  55static inline unsigned long long us_to_tick(unsigned long long us)
  56{
  57        us = us * CONFIG_MX27_CLK32 + 999999;
  58        do_div(us, 1000000);
  59        return us;
  60}
  61#else
  62/* ~2% error */
  63#define TICK_PER_TIME   ((CONFIG_MX27_CLK32 + CONFIG_SYS_HZ / 2) / \
  64                CONFIG_SYS_HZ)
  65#define US_PER_TICK     (1000000 / CONFIG_MX27_CLK32)
  66
  67static inline unsigned long long tick_to_time(unsigned long long tick)
  68{
  69        do_div(tick, TICK_PER_TIME);
  70        return tick;
  71}
  72
  73static inline unsigned long long time_to_tick(unsigned long long time)
  74{
  75        return time * TICK_PER_TIME;
  76}
  77
  78static inline unsigned long long us_to_tick(unsigned long long us)
  79{
  80        us += US_PER_TICK - 1;
  81        do_div(us, US_PER_TICK);
  82        return us;
  83}
  84#endif
  85
  86/* nothing really to do with interrupts, just starts up a counter. */
  87/* The 32768Hz 32-bit timer overruns in 131072 seconds */
  88int timer_init(void)
  89{
  90        int i;
  91        struct gpt_regs *regs = (struct gpt_regs *)IMX_TIM1_BASE;
  92        struct pll_regs *pll = (struct pll_regs *)IMX_PLL_BASE;
  93
  94        /* setup GP Timer 1 */
  95        writel(GPTCR_SWR, &regs->gpt_tctl);
  96
  97        writel(readl(&pll->pccr0) | PCCR0_GPT1_EN, &pll->pccr0);
  98        writel(readl(&pll->pccr1) | PCCR1_PERCLK1_EN, &pll->pccr1);
  99
 100        for (i = 0; i < 100; i++)
 101                writel(0, &regs->gpt_tctl); /* We have no udelay by now */
 102        writel(0, &regs->gpt_tprer); /* 32Khz */
 103        /* Freerun Mode, PERCLK1 input */
 104        writel(readl(&regs->gpt_tctl) | GPTCR_CLKSOURCE_32 | GPTCR_FRR,
 105                        &regs->gpt_tctl);
 106        writel(readl(&regs->gpt_tctl) | GPTCR_TEN, &regs->gpt_tctl);
 107
 108        return 0;
 109}
 110
 111unsigned long long get_ticks(void)
 112{
 113        struct gpt_regs *regs = (struct gpt_regs *)IMX_TIM1_BASE;
 114        ulong now = readl(&regs->gpt_tcn); /* current tick value */
 115
 116        if (now >= lastinc) {
 117                /*
 118                 * normal mode (non roll)
 119                 * move stamp forward with absolut diff ticks
 120                 */
 121                timestamp += (now - lastinc);
 122        } else {
 123                /* we have rollover of incrementer */
 124                timestamp += (0xFFFFFFFF - lastinc) + now;
 125        }
 126        lastinc = now;
 127        return timestamp;
 128}
 129
 130ulong get_timer_masked(void)
 131{
 132        /*
 133         * get_ticks() returns a long long (64 bit), it wraps in
 134         * 2^64 / CONFIG_MX27_CLK32 = 2^64 / 2^15 = 2^49 ~ 5 * 10^14 (s) ~
 135         * 5 * 10^9 days... and get_ticks() * CONFIG_SYS_HZ wraps in
 136         * 5 * 10^6 days - long enough.
 137         */
 138        return tick_to_time(get_ticks());
 139}
 140
 141ulong get_timer(ulong base)
 142{
 143        return get_timer_masked() - base;
 144}
 145
 146/* delay x useconds AND preserve advance timstamp value */
 147void __udelay(unsigned long usec)
 148{
 149        unsigned long long tmp;
 150        ulong tmo;
 151
 152        tmo = us_to_tick(usec);
 153        tmp = get_ticks() + tmo;        /* get current timestamp */
 154
 155        while (get_ticks() < tmp)       /* loop till event */
 156                 /*NOP*/;
 157}
 158
 159ulong get_tbclk(void)
 160{
 161        return CONFIG_MX27_CLK32;
 162}
 163