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 * SPDX-License-Identifier:     GPL-2.0+
  10 */
  11
  12#include <common.h>
  13#include <asm/io.h>
  14#include <faraday/fttmr010.h>
  15
  16static ulong timestamp;
  17static ulong lastdec;
  18
  19int timer_init(void)
  20{
  21        struct fttmr010 *tmr = (struct fttmr010 *)CONFIG_FTTMR010_BASE;
  22        unsigned int cr;
  23
  24        debug("%s()\n", __func__);
  25
  26        /* disable timers */
  27        writel(0, &tmr->cr);
  28
  29#ifdef CONFIG_FTTMR010_EXT_CLK
  30        /* use 32768Hz oscillator for RTC, WDT, TIMER */
  31        ftpmu010_32768osc_enable();
  32#endif
  33
  34        /* setup timer */
  35        writel(TIMER_LOAD_VAL, &tmr->timer3_load);
  36        writel(TIMER_LOAD_VAL, &tmr->timer3_counter);
  37        writel(0, &tmr->timer3_match1);
  38        writel(0, &tmr->timer3_match2);
  39
  40        /* we don't want timer to issue interrupts */
  41        writel(FTTMR010_TM3_MATCH1 |
  42               FTTMR010_TM3_MATCH2 |
  43               FTTMR010_TM3_OVERFLOW,
  44               &tmr->interrupt_mask);
  45
  46        cr = readl(&tmr->cr);
  47#ifdef CONFIG_FTTMR010_EXT_CLK
  48        cr |= FTTMR010_TM3_CLOCK;       /* use external clock */
  49#endif
  50        cr |= FTTMR010_TM3_ENABLE;
  51        writel(cr, &tmr->cr);
  52
  53        /* init the timestamp and lastdec value */
  54        reset_timer_masked();
  55
  56        return 0;
  57}
  58
  59/*
  60 * timer without interrupts
  61 */
  62
  63/*
  64 * reset time
  65 */
  66void reset_timer_masked(void)
  67{
  68        struct fttmr010 *tmr = (struct fttmr010 *)CONFIG_FTTMR010_BASE;
  69
  70        /* capure current decrementer value time */
  71#ifdef CONFIG_FTTMR010_EXT_CLK
  72        lastdec = readl(&tmr->timer3_counter) / (TIMER_CLOCK / CONFIG_SYS_HZ);
  73#else
  74        lastdec = readl(&tmr->timer3_counter) /
  75                        (CONFIG_SYS_CLK_FREQ / 2 / CONFIG_SYS_HZ);
  76#endif
  77        timestamp = 0;          /* start "advancing" time stamp from 0 */
  78
  79        debug("%s(): lastdec = %lx\n", __func__, lastdec);
  80}
  81
  82void reset_timer(void)
  83{
  84        debug("%s()\n", __func__);
  85        reset_timer_masked();
  86}
  87
  88/*
  89 * return timer ticks
  90 */
  91ulong get_timer_masked(void)
  92{
  93        struct fttmr010 *tmr = (struct fttmr010 *)CONFIG_FTTMR010_BASE;
  94
  95        /* current tick value */
  96#ifdef CONFIG_FTTMR010_EXT_CLK
  97        ulong now = readl(&tmr->timer3_counter) / (TIMER_CLOCK / CONFIG_SYS_HZ);
  98#else
  99        ulong now = readl(&tmr->timer3_counter) /
 100                        (CONFIG_SYS_CLK_FREQ / 2 / CONFIG_SYS_HZ);
 101#endif
 102
 103        debug("%s(): now = %lx, lastdec = %lx\n", __func__, now, lastdec);
 104
 105        if (lastdec >= now) {
 106                /*
 107                 * normal mode (non roll)
 108                 * move stamp fordward with absoulte diff ticks
 109                 */
 110                timestamp += lastdec - now;
 111        } else {
 112                /*
 113                 * we have overflow of the count down timer
 114                 *
 115                 * nts = ts + ld + (TLV - now)
 116                 * ts=old stamp, ld=time that passed before passing through -1
 117                 * (TLV-now) amount of time after passing though -1
 118                 * nts = new "advancing time stamp"...it could also roll and
 119                 * cause problems.
 120                 */
 121                timestamp += lastdec + TIMER_LOAD_VAL - now;
 122        }
 123
 124        lastdec = now;
 125
 126        debug("%s() returns %lx\n", __func__, timestamp);
 127
 128        return timestamp;
 129}
 130
 131/*
 132 * return difference between timer ticks and base
 133 */
 134ulong get_timer(ulong base)
 135{
 136        debug("%s(%lx)\n", __func__, base);
 137        return get_timer_masked() - base;
 138}
 139
 140void set_timer(ulong t)
 141{
 142        debug("%s(%lx)\n", __func__, t);
 143        timestamp = t;
 144}
 145
 146/* delay x useconds AND preserve advance timestamp value */
 147void __udelay(unsigned long usec)
 148{
 149        struct fttmr010 *tmr = (struct fttmr010 *)CONFIG_FTTMR010_BASE;
 150
 151#ifdef CONFIG_FTTMR010_EXT_CLK
 152        long tmo = usec * (TIMER_CLOCK / 1000) / 1000;
 153#else
 154        long tmo = usec * ((CONFIG_SYS_CLK_FREQ / 2) / 1000) / 1000;
 155#endif
 156        unsigned long now, last = readl(&tmr->timer3_counter);
 157
 158        debug("%s(%lu)\n", __func__, usec);
 159        while (tmo > 0) {
 160                now = readl(&tmr->timer3_counter);
 161                if (now > last) /* count down timer overflow */
 162                        tmo -= TIMER_LOAD_VAL + last - now;
 163                else
 164                        tmo -= last - now;
 165                last = now;
 166        }
 167}
 168
 169/*
 170 * This function is derived from PowerPC code (read timebase as long long).
 171 * On ARM it just returns the timer value.
 172 */
 173unsigned long long get_ticks(void)
 174{
 175        debug("%s()\n", __func__);
 176        return get_timer(0);
 177}
 178
 179/*
 180 * This function is derived from PowerPC code (timebase clock frequency).
 181 * On ARM it returns the number of timer ticks per second.
 182 */
 183ulong get_tbclk(void)
 184{
 185        debug("%s()\n", __func__);
 186#ifdef CONFIG_FTTMR010_EXT_CLK
 187        return CONFIG_SYS_HZ;
 188#else
 189        return CONFIG_SYS_CLK_FREQ;
 190#endif
 191}
 192