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 Thierrystatic 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 Zyngiervoid __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 Zyngierinline 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 Zyngiervoid __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 Zyngiervoid __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