1177633Sdfr// SPDX-License-Identifier: GPL-2.0+ 2177633Sdfr/* 3177633Sdfr * (C) Copyright 2008 - 2013 Tensilica Inc. 4177633Sdfr */ 5177633Sdfr 6177633Sdfr#include <common.h> 7177633Sdfr#include <clock_legacy.h> 8177633Sdfr#include <time.h> 9177633Sdfr#include <asm/global_data.h> 10177633Sdfr#include <linux/delay.h> 11177633Sdfr#include <linux/stringify.h> 12177633Sdfr 13177633SdfrDECLARE_GLOBAL_DATA_PTR; 14177633Sdfr 15177633Sdfr#if XCHAL_HAVE_CCOUNT 16177633Sdfrstatic ulong get_ccount(void) 17177633Sdfr{ 18177633Sdfr ulong ccount; 19177633Sdfr asm volatile ("rsr %0,"__stringify(CCOUNT) : "=a" (ccount)); 20177633Sdfr return ccount; 21177633Sdfr} 22177633Sdfr#else 23177633Sdfrstatic ulong fake_ccount; 24177633Sdfr#define get_ccount() fake_ccount 25177633Sdfr#endif 26177633Sdfr 27177633Sdfrstatic void delay_cycles(unsigned cycles) 28213103Sattilio{ 29177633Sdfr#if XCHAL_HAVE_CCOUNT 30177685Sdfr unsigned expiry = get_ccount() + cycles; 31177685Sdfr while ((signed)(expiry - get_ccount()) > 0) 32177685Sdfr ; 33177685Sdfr#else 34177633Sdfr#warning "Without Xtensa timer option, timing will not be accurate." 35177633Sdfr 36177633Sdfr /* 37177633Sdfr * Approximate the cycle count by a loop iteration count. 38177633Sdfr * This is highly dependent on config and optimization. 39177633Sdfr */ 40177633Sdfr 41177633Sdfr volatile unsigned i; 42177633Sdfr for (i = cycles >> 4U; i > 0; --i) 43177633Sdfr ; 44177633Sdfr fake_ccount += cycles; 45177633Sdfr#endif 46177633Sdfr} 47177633Sdfr 48177633Sdfr/* 49177633Sdfr * Delay (busy-wait) for a number of microseconds. 50177633Sdfr */ 51177633Sdfr 52177633Sdfrvoid __udelay(unsigned long usec) 53177633Sdfr{ 54213103Sattilio ulong lo, hi, i; 55177633Sdfr ulong mhz = get_board_sys_clk() / 1000000; 56177633Sdfr 57177633Sdfr /* Scale to support full 32-bit usec range */ 58177633Sdfr 59177633Sdfr lo = usec & ((1<<22)-1); 60177633Sdfr hi = usec >> 22UL; 61177633Sdfr for (i = 0; i < hi; ++i) 62177633Sdfr delay_cycles(mhz << 22); 63177633Sdfr delay_cycles(mhz * lo); 64177633Sdfr} 65177633Sdfr 66177633Sdfr 67177633Sdfr/* 68177633Sdfr * Return the elapsed time (ticks) since 'base'. 69177633Sdfr */ 70177633Sdfr 71177633Sdfrulong get_timer(ulong base) 72177633Sdfr{ 73177633Sdfr /* Don't tie up a timer; use cycle counter if available (or fake it) */ 74177633Sdfr 75177633Sdfr#if XCHAL_HAVE_CCOUNT 76177633Sdfr register ulong ccount; 77177633Sdfr __asm__ volatile ("rsr %0, CCOUNT" : "=a"(ccount)); 78177633Sdfr return ccount / (get_board_sys_clk() / CONFIG_SYS_HZ) - base; 79177633Sdfr#else 80177633Sdfr /* 81177633Sdfr * Add at least the overhead of this call (in cycles). 82177633Sdfr * Avoids hanging in case caller doesn't use udelay(). 83177633Sdfr * Note that functions that don't call udelay() (such as 84177633Sdfr * the "sleep" command) will not get a significant delay 85177633Sdfr * because there is no time reference. 86177633Sdfr */ 87177633Sdfr 88177633Sdfr fake_ccount += 20; 89177633Sdfr return fake_ccount / (get_board_sys_clk() / CONFIG_SYS_HZ) - base; 90177633Sdfr#endif 91177633Sdfr} 92177633Sdfr 93177633Sdfr 94177633Sdfr/* 95177633Sdfr * This function is derived from ARM/PowerPC code (read timebase as long long). 96177633Sdfr * On Xtensa it just returns the timer value. 97177633Sdfr */ 98177633Sdfrunsigned long long get_ticks(void) 99177633Sdfr{ 100177633Sdfr return get_timer(0); 101177633Sdfr} 102177633Sdfr 103177633Sdfr/* 104177633Sdfr * This function is derived from ARM/PowerPC code (timebase clock frequency). 105177633Sdfr * On Xtensa it returns the number of timer ticks per second. 106177633Sdfr */ 107177633Sdfrulong get_tbclk(void) 108177633Sdfr{ 109177633Sdfr return CONFIG_SYS_HZ; 110177633Sdfr} 111177633Sdfr 112177633Sdfr#if XCHAL_HAVE_CCOUNT 113177633Sdfrunsigned long timer_get_us(void) 114177633Sdfr{ 115177633Sdfr unsigned long ccount; 116177633Sdfr 117177633Sdfr __asm__ volatile ("rsr %0, CCOUNT" : "=a"(ccount)); 118177633Sdfr return ccount / (get_board_sys_clk() / 1000000); 119177633Sdfr} 120177633Sdfr#endif 121177633Sdfr