uboot/arch/nds32/cpu/n1213/ag101/timer.c
<<
>>
Prefs
   1/*
   2 * (C) Copyright 2009 Faraday Technology
   3 * Po-Yu Chuang <ratbert@faraday-tech.com>
   4 *
   5 * Copyright (C) 2011 Andes Technology Corporation
   6 * Shawn Lin, Andes Technology Corporation <nobuhiro@andestech.com>
   7 * Macpaul Lin, Andes Technology Corporation <macpaul@andestech.com>
   8 *
   9 * See file CREDITS for list of people who contributed to this
  10 * project.
  11 *
  12 * This program is free software; you can redistribute it and/or modify
  13 * it under the terms of the GNU General Public License as published by
  14 * the Free Software Foundation; either version 2 of the License, or
  15 * (at your option) any later version.
  16 *
  17 * This program is distributed in the hope that it will be useful,
  18 * but WITHOUT ANY WARRANTY; without even the implied warranty of
  19 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  20 * GNU General Public License for more details.
  21 *
  22 * You should have received a copy of the GNU General Public License
  23 * along with this program; if not, write to the Free Software
  24 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  25 */
  26
  27#include <common.h>
  28#include <asm/io.h>
  29#include <faraday/fttmr010.h>
  30
  31static ulong timestamp;
  32static ulong lastdec;
  33
  34int timer_init(void)
  35{
  36        struct fttmr010 *tmr = (struct fttmr010 *)CONFIG_FTTMR010_BASE;
  37        unsigned int cr;
  38
  39        debug("%s()\n", __func__);
  40
  41        /* disable timers */
  42        writel(0, &tmr->cr);
  43
  44#ifdef CONFIG_FTTMR010_EXT_CLK
  45        /* use 32768Hz oscillator for RTC, WDT, TIMER */
  46        ftpmu010_32768osc_enable();
  47#endif
  48
  49        /* setup timer */
  50        writel(TIMER_LOAD_VAL, &tmr->timer3_load);
  51        writel(TIMER_LOAD_VAL, &tmr->timer3_counter);
  52        writel(0, &tmr->timer3_match1);
  53        writel(0, &tmr->timer3_match2);
  54
  55        /* we don't want timer to issue interrupts */
  56        writel(FTTMR010_TM3_MATCH1 |
  57               FTTMR010_TM3_MATCH2 |
  58               FTTMR010_TM3_OVERFLOW,
  59               &tmr->interrupt_mask);
  60
  61        cr = readl(&tmr->cr);
  62#ifdef CONFIG_FTTMR010_EXT_CLK
  63        cr |= FTTMR010_TM3_CLOCK;       /* use external clock */
  64#endif
  65        cr |= FTTMR010_TM3_ENABLE;
  66        writel(cr, &tmr->cr);
  67
  68        /* init the timestamp and lastdec value */
  69        reset_timer_masked();
  70
  71        return 0;
  72}
  73
  74/*
  75 * timer without interrupts
  76 */
  77
  78/*
  79 * reset time
  80 */
  81void reset_timer_masked(void)
  82{
  83        struct fttmr010 *tmr = (struct fttmr010 *)CONFIG_FTTMR010_BASE;
  84
  85        /* capure current decrementer value time */
  86#ifdef CONFIG_FTTMR010_EXT_CLK
  87        lastdec = readl(&tmr->timer3_counter) / (TIMER_CLOCK / CONFIG_SYS_HZ);
  88#else
  89        lastdec = readl(&tmr->timer3_counter) / (CONFIG_SYS_CLK_FREQ / 2);
  90#endif
  91        timestamp = 0;          /* start "advancing" time stamp from 0 */
  92
  93        debug("%s(): lastdec = %lx\n", __func__, lastdec);
  94}
  95
  96void reset_timer(void)
  97{
  98        debug("%s()\n", __func__);
  99        reset_timer_masked();
 100}
 101
 102/*
 103 * return timer ticks
 104 */
 105ulong get_timer_masked(void)
 106{
 107        struct fttmr010 *tmr = (struct fttmr010 *)CONFIG_FTTMR010_BASE;
 108
 109        /* current tick value */
 110#ifdef CONFIG_FTTMR010_EXT_CLK
 111        ulong now = readl(&tmr->timer3_counter) / (TIMER_CLOCK / CONFIG_SYS_HZ);
 112#else
 113        ulong now = readl(&tmr->timer3_counter) / \
 114                        (CONFIG_SYS_CLK_FREQ / 2 / 1024);
 115#endif
 116
 117        debug("%s(): now = %lx, lastdec = %lx\n", __func__, now, lastdec);
 118
 119        if (lastdec >= now) {
 120                /*
 121                 * normal mode (non roll)
 122                 * move stamp fordward with absoulte diff ticks
 123                 */
 124                timestamp += lastdec - now;
 125        } else {
 126                /*
 127                 * we have overflow of the count down timer
 128                 *
 129                 * nts = ts + ld + (TLV - now)
 130                 * ts=old stamp, ld=time that passed before passing through -1
 131                 * (TLV-now) amount of time after passing though -1
 132                 * nts = new "advancing time stamp"...it could also roll and
 133                 * cause problems.
 134                 */
 135                timestamp += lastdec + TIMER_LOAD_VAL - now;
 136        }
 137
 138        lastdec = now;
 139
 140        debug("%s() returns %lx\n", __func__, timestamp);
 141
 142        return timestamp;
 143}
 144
 145/*
 146 * return difference between timer ticks and base
 147 */
 148ulong get_timer(ulong base)
 149{
 150        debug("%s(%lx)\n", __func__, base);
 151        return get_timer_masked() - base;
 152}
 153
 154void set_timer(ulong t)
 155{
 156        debug("%s(%lx)\n", __func__, t);
 157        timestamp = t;
 158}
 159
 160/* delay x useconds AND preserve advance timestamp value */
 161void __udelay(unsigned long usec)
 162{
 163        struct fttmr010 *tmr = (struct fttmr010 *)CONFIG_FTTMR010_BASE;
 164
 165#ifdef CONFIG_FTTMR010_EXT_CLK
 166        long tmo = usec * (TIMER_CLOCK / 1000) / 1000;
 167#else
 168        long tmo = usec * ((CONFIG_SYS_CLK_FREQ / 2) / 1000) / 1000;
 169#endif
 170        unsigned long now, last = readl(&tmr->timer3_counter);
 171
 172        debug("%s(%lu)\n", __func__, usec);
 173        while (tmo > 0) {
 174                now = readl(&tmr->timer3_counter);
 175                if (now > last) /* count down timer overflow */
 176                        tmo -= TIMER_LOAD_VAL + last - now;
 177                else
 178                        tmo -= last - now;
 179                last = now;
 180        }
 181}
 182
 183/*
 184 * This function is derived from PowerPC code (read timebase as long long).
 185 * On ARM it just returns the timer value.
 186 */
 187unsigned long long get_ticks(void)
 188{
 189        debug("%s()\n", __func__);
 190        return get_timer(0);
 191}
 192
 193/*
 194 * This function is derived from PowerPC code (timebase clock frequency).
 195 * On ARM it returns the number of timer ticks per second.
 196 */
 197ulong get_tbclk(void)
 198{
 199        debug("%s()\n", __func__);
 200#ifdef CONFIG_FTTMR010_EXT_CLK
 201        return CONFIG_SYS_HZ;
 202#else
 203        return CONFIG_SYS_CLK_FREQ;
 204#endif
 205}
 206