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