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