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