uboot/arch/xtensa/lib/time.c
<<
>>
Prefs
   1/*
   2 * (C) Copyright 2008 - 2013 Tensilica Inc.
   3 *
   4 * SPDX-License-Identifier:     GPL-2.0+
   5 */
   6
   7#include <common.h>
   8#include <asm/global_data.h>
   9#include <linux/stringify.h>
  10
  11DECLARE_GLOBAL_DATA_PTR;
  12
  13#if XCHAL_HAVE_CCOUNT
  14static ulong get_ccount(void)
  15{
  16        ulong ccount;
  17        asm volatile ("rsr %0,"__stringify(CCOUNT) : "=a" (ccount));
  18        return ccount;
  19}
  20#else
  21static ulong fake_ccount;
  22#define get_ccount() fake_ccount
  23#endif
  24
  25static void delay_cycles(unsigned cycles)
  26{
  27#if XCHAL_HAVE_CCOUNT
  28        unsigned expiry = get_ccount() + cycles;
  29        while ((signed)(expiry - get_ccount()) > 0)
  30                ;
  31#else
  32#warning "Without Xtensa timer option, timing will not be accurate."
  33
  34        /*
  35         * Approximate the cycle count by a loop iteration count.
  36         * This is highly dependent on config and optimization.
  37         */
  38
  39        volatile unsigned i;
  40        for (i = cycles >> 4U; i > 0; --i)
  41                ;
  42        fake_ccount += cycles;
  43#endif
  44}
  45
  46/*
  47 * Delay (busy-wait) for a number of microseconds.
  48 */
  49
  50void __udelay(unsigned long usec)
  51{
  52        ulong lo, hi, i;
  53        ulong mhz = CONFIG_SYS_CLK_FREQ / 1000000;
  54
  55        /* Scale to support full 32-bit usec range */
  56
  57        lo = usec & ((1<<22)-1);
  58        hi = usec >> 22UL;
  59        for (i = 0; i < hi; ++i)
  60                delay_cycles(mhz << 22);
  61        delay_cycles(mhz * lo);
  62}
  63
  64
  65/*
  66 * Return the elapsed time (ticks) since 'base'.
  67 */
  68
  69ulong get_timer(ulong base)
  70{
  71        /* Don't tie up a timer; use cycle counter if available (or fake it) */
  72
  73#if XCHAL_HAVE_CCOUNT
  74        register ulong ccount;
  75        __asm__ volatile ("rsr %0, CCOUNT" : "=a"(ccount));
  76        return ccount / (CONFIG_SYS_CLK_FREQ / CONFIG_SYS_HZ) - base;
  77#else
  78        /*
  79         * Add at least the overhead of this call (in cycles).
  80         * Avoids hanging in case caller doesn't use udelay().
  81         * Note that functions that don't call udelay() (such as
  82         * the "sleep" command) will not get a significant delay
  83         * because there is no time reference.
  84         */
  85
  86        fake_ccount += 20;
  87        return fake_ccount / (CONFIG_SYS_CLK_FREQ / CONFIG_SYS_HZ) - base;
  88#endif
  89}
  90
  91
  92/*
  93 * This function is derived from ARM/PowerPC code (read timebase as long long).
  94 * On Xtensa it just returns the timer value.
  95 */
  96unsigned long long get_ticks(void)
  97{
  98        return get_timer(0);
  99}
 100
 101/*
 102 * This function is derived from ARM/PowerPC code (timebase clock frequency).
 103 * On Xtensa it returns the number of timer ticks per second.
 104 */
 105ulong get_tbclk(void)
 106{
 107        return CONFIG_SYS_HZ;
 108}
 109
 110#if XCHAL_HAVE_CCOUNT
 111unsigned long timer_get_us(void)
 112{
 113        unsigned long ccount;
 114
 115        __asm__ volatile ("rsr %0, CCOUNT" : "=a"(ccount));
 116        return ccount / (CONFIG_SYS_CLK_FREQ / 1000000);
 117}
 118#endif
 119