uboot/arch/arm/cpu/arm1136/mx31/timer.c
<<
>>
Prefs
   1/*
   2 * (C) Copyright 2007
   3 * Sascha Hauer, Pengutronix
   4 *
   5 * See file CREDITS for list of people who contributed to this
   6 * project.
   7 *
   8 * This program is free software; you can redistribute it and/or
   9 * modify it under the terms of the GNU General Public License as
  10 * published by the Free Software Foundation; either version 2 of
  11 * the License, or (at your option) any later version.
  12 *
  13 * This program is distributed in the hope that it will be useful,
  14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
  15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  16 * GNU General Public License for more details.
  17 *
  18 * You should have received a copy of the GNU General Public License
  19 * along with this program; if not, write to the Free Software
  20 * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
  21 * MA 02111-1307 USA
  22 */
  23
  24#include <common.h>
  25#include <asm/arch/imx-regs.h>
  26#include <div64.h>
  27#include <watchdog.h>
  28#include <asm/io.h>
  29
  30#define TIMER_BASE 0x53f90000 /* General purpose timer 1 */
  31
  32/* General purpose timers registers */
  33#define GPTCR   __REG(TIMER_BASE)               /* Control register     */
  34#define GPTPR   __REG(TIMER_BASE + 0x4)         /* Prescaler register   */
  35#define GPTSR   __REG(TIMER_BASE + 0x8)         /* Status register      */
  36#define GPTCNT  __REG(TIMER_BASE + 0x24)        /* Counter register     */
  37
  38/* General purpose timers bitfields */
  39#define GPTCR_SWR               (1 << 15)       /* Software reset       */
  40#define GPTCR_FRR               (1 << 9)        /* Freerun / restart    */
  41#define GPTCR_CLKSOURCE_32      (4 << 6)        /* Clock source         */
  42#define GPTCR_TEN               1               /* Timer enable         */
  43
  44DECLARE_GLOBAL_DATA_PTR;
  45
  46/*
  47 * "time" is measured in 1 / CONFIG_SYS_HZ seconds,
  48 * "tick" is internal timer period
  49 */
  50
  51#ifdef CONFIG_MX31_TIMER_HIGH_PRECISION
  52/* ~0.4% error - measured with stop-watch on 100s boot-delay */
  53static inline unsigned long long tick_to_time(unsigned long long tick)
  54{
  55        tick *= CONFIG_SYS_HZ;
  56        do_div(tick, CONFIG_MX31_CLK32);
  57        return tick;
  58}
  59
  60static inline unsigned long long time_to_tick(unsigned long long time)
  61{
  62        time *= CONFIG_MX31_CLK32;
  63        do_div(time, CONFIG_SYS_HZ);
  64        return time;
  65}
  66
  67static inline unsigned long long us_to_tick(unsigned long long us)
  68{
  69        us = us * CONFIG_MX31_CLK32 + 999999;
  70        do_div(us, 1000000);
  71        return us;
  72}
  73#else
  74/* ~2% error */
  75#define TICK_PER_TIME   ((CONFIG_MX31_CLK32 + CONFIG_SYS_HZ / 2) \
  76                                                        / CONFIG_SYS_HZ)
  77#define US_PER_TICK     (1000000 / CONFIG_MX31_CLK32)
  78
  79static inline unsigned long long tick_to_time(unsigned long long tick)
  80{
  81        do_div(tick, TICK_PER_TIME);
  82        return tick;
  83}
  84
  85static inline unsigned long long time_to_tick(unsigned long long time)
  86{
  87        return time * TICK_PER_TIME;
  88}
  89
  90static inline unsigned long long us_to_tick(unsigned long long us)
  91{
  92        us += US_PER_TICK - 1;
  93        do_div(us, US_PER_TICK);
  94        return us;
  95}
  96#endif
  97
  98/* The 32768Hz 32-bit timer overruns in 131072 seconds */
  99int timer_init(void)
 100{
 101        int i;
 102
 103        /* setup GP Timer 1 */
 104        GPTCR = GPTCR_SWR;
 105        for (i = 0; i < 100; i++)
 106                GPTCR = 0; /* We have no udelay by now */
 107        GPTPR = 0; /* 32Khz */
 108        /* Freerun Mode, PERCLK1 input */
 109        GPTCR |= GPTCR_CLKSOURCE_32 | GPTCR_TEN;
 110
 111        return 0;
 112}
 113
 114unsigned long long get_ticks(void)
 115{
 116        ulong now = GPTCNT; /* current tick value */
 117
 118        if (now >= gd->lastinc) /* normal mode (non roll) */
 119                /* move stamp forward with absolut diff ticks */
 120                gd->tbl += (now - gd->lastinc);
 121        else                    /* we have rollover of incrementer */
 122                gd->tbl += (0xFFFFFFFF - gd->lastinc) + now;
 123        gd->lastinc = now;
 124        return gd->tbl;
 125}
 126
 127ulong get_timer_masked(void)
 128{
 129        /*
 130         * get_ticks() returns a long long (64 bit), it wraps in
 131         * 2^64 / CONFIG_MX31_CLK32 = 2^64 / 2^15 = 2^49 ~ 5 * 10^14 (s) ~
 132         * 5 * 10^9 days... and get_ticks() * CONFIG_SYS_HZ wraps in
 133         * 5 * 10^6 days - long enough.
 134         */
 135        return tick_to_time(get_ticks());
 136}
 137
 138ulong get_timer(ulong base)
 139{
 140        return get_timer_masked() - base;
 141}
 142
 143/* delay x useconds AND preserve advance timestamp value */
 144void __udelay(unsigned long usec)
 145{
 146        unsigned long long tmp;
 147        ulong tmo;
 148
 149        tmo = us_to_tick(usec);
 150        tmp = get_ticks() + tmo;        /* get current timestamp */
 151
 152        while (get_ticks() < tmp)       /* loop till event */
 153                 /*NOP*/;
 154}
 155
 156/*
 157 * This function is derived from PowerPC code (timebase clock frequency).
 158 * On ARM it returns the number of timer ticks per second.
 159 */
 160ulong get_tbclk(void)
 161{
 162        return CONFIG_MX31_CLK32;
 163}
 164
 165void reset_cpu(ulong addr)
 166{
 167        struct wdog_regs *wdog = (struct wdog_regs *)WDOG_BASE;
 168        wdog->wcr = WDOG_ENABLE;
 169        while (1)
 170                ;
 171}
 172
 173#ifdef CONFIG_HW_WATCHDOG
 174void mxc_hw_watchdog_enable(void)
 175{
 176        struct wdog_regs *wdog = (struct wdog_regs *)WDOG_BASE;
 177        u16 secs;
 178
 179        /*
 180         * The timer watchdog can be set between
 181         * 0.5 and 128 Seconds. If not defined
 182         * in configuration file, sets 64 Seconds
 183         */
 184#ifdef CONFIG_SYS_WD_TIMER_SECS
 185        secs = (CONFIG_SYS_WD_TIMER_SECS << 1) & 0xFF;
 186        if (!secs) secs = 1;
 187#else
 188        secs = 64;
 189#endif
 190        setbits_le16(&wdog->wcr, (secs << WDOG_WT_SHIFT) | WDOG_ENABLE
 191                                                         | WDOG_WDZST);
 192}
 193
 194
 195void mxc_hw_watchdog_reset(void)
 196{
 197        struct wdog_regs *wdog = (struct wdog_regs *)WDOG_BASE;
 198
 199        writew(0x5555, &wdog->wsr);
 200        writew(0xAAAA, &wdog->wsr);
 201}
 202#endif
 203