1d0a533b18235d36206b9b422efadb7cee444dfdbWill Deacon/*
2d0a533b18235d36206b9b422efadb7cee444dfdbWill Deacon * Delay loops based on the OpenRISC implementation.
3d0a533b18235d36206b9b422efadb7cee444dfdbWill Deacon *
4d0a533b18235d36206b9b422efadb7cee444dfdbWill Deacon * Copyright (C) 2012 ARM Limited
5d0a533b18235d36206b9b422efadb7cee444dfdbWill Deacon *
6d0a533b18235d36206b9b422efadb7cee444dfdbWill Deacon * This program is free software; you can redistribute it and/or modify
7d0a533b18235d36206b9b422efadb7cee444dfdbWill Deacon * it under the terms of the GNU General Public License version 2 as
8d0a533b18235d36206b9b422efadb7cee444dfdbWill Deacon * published by the Free Software Foundation.
9d0a533b18235d36206b9b422efadb7cee444dfdbWill Deacon *
10d0a533b18235d36206b9b422efadb7cee444dfdbWill Deacon * This program is distributed in the hope that it will be useful,
11d0a533b18235d36206b9b422efadb7cee444dfdbWill Deacon * but WITHOUT ANY WARRANTY; without even the implied warranty of
12d0a533b18235d36206b9b422efadb7cee444dfdbWill Deacon * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13d0a533b18235d36206b9b422efadb7cee444dfdbWill Deacon * GNU General Public License for more details.
14d0a533b18235d36206b9b422efadb7cee444dfdbWill Deacon *
15d0a533b18235d36206b9b422efadb7cee444dfdbWill Deacon * You should have received a copy of the GNU General Public License
16d0a533b18235d36206b9b422efadb7cee444dfdbWill Deacon * along with this program; if not, write to the Free Software
17d0a533b18235d36206b9b422efadb7cee444dfdbWill Deacon * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
18d0a533b18235d36206b9b422efadb7cee444dfdbWill Deacon *
19d0a533b18235d36206b9b422efadb7cee444dfdbWill Deacon * Author: Will Deacon <will.deacon@arm.com>
20d0a533b18235d36206b9b422efadb7cee444dfdbWill Deacon */
21d0a533b18235d36206b9b422efadb7cee444dfdbWill Deacon
225930c1a1f7f8439883d0a2173c6ce51d577e36ecPeter De Schrijver#include <linux/clocksource.h>
23d0a533b18235d36206b9b422efadb7cee444dfdbWill Deacon#include <linux/delay.h>
24d0a533b18235d36206b9b422efadb7cee444dfdbWill Deacon#include <linux/init.h>
25d0a533b18235d36206b9b422efadb7cee444dfdbWill Deacon#include <linux/kernel.h>
26d0a533b18235d36206b9b422efadb7cee444dfdbWill Deacon#include <linux/module.h>
27d0a533b18235d36206b9b422efadb7cee444dfdbWill Deacon#include <linux/timex.h>
28d0a533b18235d36206b9b422efadb7cee444dfdbWill Deacon
29d0a533b18235d36206b9b422efadb7cee444dfdbWill Deacon/*
30d0a533b18235d36206b9b422efadb7cee444dfdbWill Deacon * Default to the loop-based delay implementation.
31d0a533b18235d36206b9b422efadb7cee444dfdbWill Deacon */
32d0a533b18235d36206b9b422efadb7cee444dfdbWill Deaconstruct arm_delay_ops arm_delay_ops = {
33d0a533b18235d36206b9b422efadb7cee444dfdbWill Deacon	.delay		= __loop_delay,
34d0a533b18235d36206b9b422efadb7cee444dfdbWill Deacon	.const_udelay	= __loop_const_udelay,
35d0a533b18235d36206b9b422efadb7cee444dfdbWill Deacon	.udelay		= __loop_udelay,
36d0a533b18235d36206b9b422efadb7cee444dfdbWill Deacon};
37d0a533b18235d36206b9b422efadb7cee444dfdbWill Deacon
3856942fec06efa0e17df0f4c3b438332c923b9014Jonathan Austinstatic const struct delay_timer *delay_timer;
3956942fec06efa0e17df0f4c3b438332c923b9014Jonathan Austinstatic bool delay_calibrated;
405930c1a1f7f8439883d0a2173c6ce51d577e36ecPeter De Schrijverstatic u64 delay_res;
4156942fec06efa0e17df0f4c3b438332c923b9014Jonathan Austin
4256942fec06efa0e17df0f4c3b438332c923b9014Jonathan Austinint read_current_timer(unsigned long *timer_val)
4356942fec06efa0e17df0f4c3b438332c923b9014Jonathan Austin{
4456942fec06efa0e17df0f4c3b438332c923b9014Jonathan Austin	if (!delay_timer)
4556942fec06efa0e17df0f4c3b438332c923b9014Jonathan Austin		return -ENXIO;
4656942fec06efa0e17df0f4c3b438332c923b9014Jonathan Austin
4756942fec06efa0e17df0f4c3b438332c923b9014Jonathan Austin	*timer_val = delay_timer->read_current_timer();
4856942fec06efa0e17df0f4c3b438332c923b9014Jonathan Austin	return 0;
4956942fec06efa0e17df0f4c3b438332c923b9014Jonathan Austin}
50f3accb122f2c758494a6db3b9e9a8cd62aafcf83Arnd BergmannEXPORT_SYMBOL_GPL(read_current_timer);
5156942fec06efa0e17df0f4c3b438332c923b9014Jonathan Austin
525930c1a1f7f8439883d0a2173c6ce51d577e36ecPeter De Schrijverstatic inline u64 cyc_to_ns(u64 cyc, u32 mult, u32 shift)
535930c1a1f7f8439883d0a2173c6ce51d577e36ecPeter De Schrijver{
545930c1a1f7f8439883d0a2173c6ce51d577e36ecPeter De Schrijver	return (cyc * mult) >> shift;
555930c1a1f7f8439883d0a2173c6ce51d577e36ecPeter De Schrijver}
565930c1a1f7f8439883d0a2173c6ce51d577e36ecPeter De Schrijver
57d0a533b18235d36206b9b422efadb7cee444dfdbWill Deaconstatic void __timer_delay(unsigned long cycles)
58d0a533b18235d36206b9b422efadb7cee444dfdbWill Deacon{
59d0a533b18235d36206b9b422efadb7cee444dfdbWill Deacon	cycles_t start = get_cycles();
60d0a533b18235d36206b9b422efadb7cee444dfdbWill Deacon
61d0a533b18235d36206b9b422efadb7cee444dfdbWill Deacon	while ((get_cycles() - start) < cycles)
62d0a533b18235d36206b9b422efadb7cee444dfdbWill Deacon		cpu_relax();
63d0a533b18235d36206b9b422efadb7cee444dfdbWill Deacon}
64d0a533b18235d36206b9b422efadb7cee444dfdbWill Deacon
65d0a533b18235d36206b9b422efadb7cee444dfdbWill Deaconstatic void __timer_const_udelay(unsigned long xloops)
66d0a533b18235d36206b9b422efadb7cee444dfdbWill Deacon{
67d0a533b18235d36206b9b422efadb7cee444dfdbWill Deacon	unsigned long long loops = xloops;
686f3d90e55660ba42301b5e9c7eed332cc9f70fd7Will Deacon	loops *= arm_delay_ops.ticks_per_jiffy;
69d0a533b18235d36206b9b422efadb7cee444dfdbWill Deacon	__timer_delay(loops >> UDELAY_SHIFT);
70d0a533b18235d36206b9b422efadb7cee444dfdbWill Deacon}
71d0a533b18235d36206b9b422efadb7cee444dfdbWill Deacon
72d0a533b18235d36206b9b422efadb7cee444dfdbWill Deaconstatic void __timer_udelay(unsigned long usecs)
73d0a533b18235d36206b9b422efadb7cee444dfdbWill Deacon{
74d0a533b18235d36206b9b422efadb7cee444dfdbWill Deacon	__timer_const_udelay(usecs * UDELAY_MULT);
75d0a533b18235d36206b9b422efadb7cee444dfdbWill Deacon}
76d0a533b18235d36206b9b422efadb7cee444dfdbWill Deacon
7756942fec06efa0e17df0f4c3b438332c923b9014Jonathan Austinvoid __init register_current_timer_delay(const struct delay_timer *timer)
78d0a533b18235d36206b9b422efadb7cee444dfdbWill Deacon{
795930c1a1f7f8439883d0a2173c6ce51d577e36ecPeter De Schrijver	u32 new_mult, new_shift;
805930c1a1f7f8439883d0a2173c6ce51d577e36ecPeter De Schrijver	u64 res;
815930c1a1f7f8439883d0a2173c6ce51d577e36ecPeter De Schrijver
825930c1a1f7f8439883d0a2173c6ce51d577e36ecPeter De Schrijver	clocks_calc_mult_shift(&new_mult, &new_shift, timer->freq,
835930c1a1f7f8439883d0a2173c6ce51d577e36ecPeter De Schrijver			       NSEC_PER_SEC, 3600);
845930c1a1f7f8439883d0a2173c6ce51d577e36ecPeter De Schrijver	res = cyc_to_ns(1ULL, new_mult, new_shift);
855930c1a1f7f8439883d0a2173c6ce51d577e36ecPeter De Schrijver
865930c1a1f7f8439883d0a2173c6ce51d577e36ecPeter De Schrijver	if (!delay_calibrated && (!delay_res || (res < delay_res))) {
875930c1a1f7f8439883d0a2173c6ce51d577e36ecPeter De Schrijver		pr_info("Switching to timer-based delay loop, resolution %lluns\n", res);
8856942fec06efa0e17df0f4c3b438332c923b9014Jonathan Austin		delay_timer			= timer;
8956942fec06efa0e17df0f4c3b438332c923b9014Jonathan Austin		lpj_fine			= timer->freq / HZ;
905930c1a1f7f8439883d0a2173c6ce51d577e36ecPeter De Schrijver		delay_res			= res;
916f3d90e55660ba42301b5e9c7eed332cc9f70fd7Will Deacon
926f3d90e55660ba42301b5e9c7eed332cc9f70fd7Will Deacon		/* cpufreq may scale loops_per_jiffy, so keep a private copy */
936f3d90e55660ba42301b5e9c7eed332cc9f70fd7Will Deacon		arm_delay_ops.ticks_per_jiffy	= lpj_fine;
9456942fec06efa0e17df0f4c3b438332c923b9014Jonathan Austin		arm_delay_ops.delay		= __timer_delay;
9556942fec06efa0e17df0f4c3b438332c923b9014Jonathan Austin		arm_delay_ops.const_udelay	= __timer_const_udelay;
9656942fec06efa0e17df0f4c3b438332c923b9014Jonathan Austin		arm_delay_ops.udelay		= __timer_udelay;
9756942fec06efa0e17df0f4c3b438332c923b9014Jonathan Austin	} else {
9856942fec06efa0e17df0f4c3b438332c923b9014Jonathan Austin		pr_info("Ignoring duplicate/late registration of read_current_timer delay\n");
9956942fec06efa0e17df0f4c3b438332c923b9014Jonathan Austin	}
100d0a533b18235d36206b9b422efadb7cee444dfdbWill Deacon}
101d0a533b18235d36206b9b422efadb7cee444dfdbWill Deacon
1028bd26e3a7e49af2697449bbcb7187a39dc85d672Paul Gortmakerunsigned long calibrate_delay_is_known(void)
103d0a533b18235d36206b9b422efadb7cee444dfdbWill Deacon{
10456942fec06efa0e17df0f4c3b438332c923b9014Jonathan Austin	delay_calibrated = true;
105d0a533b18235d36206b9b422efadb7cee444dfdbWill Deacon	return lpj_fine;
106d0a533b18235d36206b9b422efadb7cee444dfdbWill Deacon}
1075930c1a1f7f8439883d0a2173c6ce51d577e36ecPeter De Schrijver
1085930c1a1f7f8439883d0a2173c6ce51d577e36ecPeter De Schrijvervoid calibration_delay_done(void)
1095930c1a1f7f8439883d0a2173c6ce51d577e36ecPeter De Schrijver{
1105930c1a1f7f8439883d0a2173c6ce51d577e36ecPeter De Schrijver	delay_calibrated = true;
1115930c1a1f7f8439883d0a2173c6ce51d577e36ecPeter De Schrijver}
112