xref: /openbmc/linux/arch/arm64/lib/delay.c (revision 7d26b051)
1caab277bSThomas Gleixner // SPDX-License-Identifier: GPL-2.0-only
2f27bb139SMarc Zyngier /*
3f27bb139SMarc Zyngier  * Delay loops based on the OpenRISC implementation.
4f27bb139SMarc Zyngier  *
5f27bb139SMarc Zyngier  * Copyright (C) 2012 ARM Limited
6f27bb139SMarc Zyngier  *
7f27bb139SMarc Zyngier  * Author: Will Deacon <will.deacon@arm.com>
8f27bb139SMarc Zyngier  */
9f27bb139SMarc Zyngier 
10f27bb139SMarc Zyngier #include <linux/delay.h>
11f27bb139SMarc Zyngier #include <linux/init.h>
12f27bb139SMarc Zyngier #include <linux/kernel.h>
13f27bb139SMarc Zyngier #include <linux/module.h>
14f27bb139SMarc Zyngier #include <linux/timex.h>
15f27bb139SMarc Zyngier 
167b77452eSJulien Thierry #include <clocksource/arm_arch_timer.h>
177b77452eSJulien Thierry 
187b77452eSJulien Thierry #define USECS_TO_CYCLES(time_usecs)			\
197b77452eSJulien Thierry 	xloops_to_cycles((time_usecs) * 0x10C7UL)
207b77452eSJulien Thierry 
xloops_to_cycles(unsigned long xloops)217b77452eSJulien Thierry static inline unsigned long xloops_to_cycles(unsigned long xloops)
227b77452eSJulien Thierry {
237b77452eSJulien Thierry 	return (xloops * loops_per_jiffy * HZ) >> 32;
247b77452eSJulien Thierry }
257b77452eSJulien Thierry 
__delay(unsigned long cycles)26f27bb139SMarc Zyngier void __delay(unsigned long cycles)
27f27bb139SMarc Zyngier {
28f27bb139SMarc Zyngier 	cycles_t start = get_cycles();
29f27bb139SMarc Zyngier 
30*7d26b051SMarc Zyngier 	if (cpus_have_const_cap(ARM64_HAS_WFXT)) {
31*7d26b051SMarc Zyngier 		u64 end = start + cycles;
32*7d26b051SMarc Zyngier 
33*7d26b051SMarc Zyngier 		/*
34*7d26b051SMarc Zyngier 		 * Start with WFIT. If an interrupt makes us resume
35*7d26b051SMarc Zyngier 		 * early, use a WFET loop to complete the delay.
36*7d26b051SMarc Zyngier 		 */
37*7d26b051SMarc Zyngier 		wfit(end);
38*7d26b051SMarc Zyngier 		while ((get_cycles() - start) < cycles)
39*7d26b051SMarc Zyngier 			wfet(end);
40*7d26b051SMarc Zyngier 	} else 	if (arch_timer_evtstrm_available()) {
417b77452eSJulien Thierry 		const cycles_t timer_evt_period =
427b77452eSJulien Thierry 			USECS_TO_CYCLES(ARCH_TIMER_EVT_STREAM_PERIOD_US);
437b77452eSJulien Thierry 
447b77452eSJulien Thierry 		while ((get_cycles() - start + timer_evt_period) < cycles)
457b77452eSJulien Thierry 			wfe();
467b77452eSJulien Thierry 	}
477b77452eSJulien Thierry 
48f27bb139SMarc Zyngier 	while ((get_cycles() - start) < cycles)
49f27bb139SMarc Zyngier 		cpu_relax();
50f27bb139SMarc Zyngier }
51f27bb139SMarc Zyngier EXPORT_SYMBOL(__delay);
52f27bb139SMarc Zyngier 
__const_udelay(unsigned long xloops)53f27bb139SMarc Zyngier inline void __const_udelay(unsigned long xloops)
54f27bb139SMarc Zyngier {
557b77452eSJulien Thierry 	__delay(xloops_to_cycles(xloops));
56f27bb139SMarc Zyngier }
57f27bb139SMarc Zyngier EXPORT_SYMBOL(__const_udelay);
58f27bb139SMarc Zyngier 
__udelay(unsigned long usecs)59f27bb139SMarc Zyngier void __udelay(unsigned long usecs)
60f27bb139SMarc Zyngier {
61f27bb139SMarc Zyngier 	__const_udelay(usecs * 0x10C7UL); /* 2**32 / 1000000 (rounded up) */
62f27bb139SMarc Zyngier }
63f27bb139SMarc Zyngier EXPORT_SYMBOL(__udelay);
64f27bb139SMarc Zyngier 
__ndelay(unsigned long nsecs)65f27bb139SMarc Zyngier void __ndelay(unsigned long nsecs)
66f27bb139SMarc Zyngier {
67f27bb139SMarc Zyngier 	__const_udelay(nsecs * 0x5UL); /* 2**32 / 1000000000 (rounded up) */
68f27bb139SMarc Zyngier }
69f27bb139SMarc Zyngier EXPORT_SYMBOL(__ndelay);
70