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