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