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