delay.c revision 56942fec06efa0e17df0f4c3b438332c923b9014
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
22d0a533b18235d36206b9b422efadb7cee444dfdbWill Deacon#include <linux/delay.h>
23d0a533b18235d36206b9b422efadb7cee444dfdbWill Deacon#include <linux/init.h>
24d0a533b18235d36206b9b422efadb7cee444dfdbWill Deacon#include <linux/kernel.h>
25d0a533b18235d36206b9b422efadb7cee444dfdbWill Deacon#include <linux/module.h>
26d0a533b18235d36206b9b422efadb7cee444dfdbWill Deacon#include <linux/timex.h>
27d0a533b18235d36206b9b422efadb7cee444dfdbWill Deacon
28d0a533b18235d36206b9b422efadb7cee444dfdbWill Deacon/*
29d0a533b18235d36206b9b422efadb7cee444dfdbWill Deacon * Default to the loop-based delay implementation.
30d0a533b18235d36206b9b422efadb7cee444dfdbWill Deacon */
31d0a533b18235d36206b9b422efadb7cee444dfdbWill Deaconstruct arm_delay_ops arm_delay_ops = {
32d0a533b18235d36206b9b422efadb7cee444dfdbWill Deacon	.delay		= __loop_delay,
33d0a533b18235d36206b9b422efadb7cee444dfdbWill Deacon	.const_udelay	= __loop_const_udelay,
34d0a533b18235d36206b9b422efadb7cee444dfdbWill Deacon	.udelay		= __loop_udelay,
35d0a533b18235d36206b9b422efadb7cee444dfdbWill Deacon};
36d0a533b18235d36206b9b422efadb7cee444dfdbWill Deacon
3756942fec06efa0e17df0f4c3b438332c923b9014Jonathan Austinstatic const struct delay_timer *delay_timer;
3856942fec06efa0e17df0f4c3b438332c923b9014Jonathan Austinstatic bool delay_calibrated;
3956942fec06efa0e17df0f4c3b438332c923b9014Jonathan Austin
4056942fec06efa0e17df0f4c3b438332c923b9014Jonathan Austinint read_current_timer(unsigned long *timer_val)
4156942fec06efa0e17df0f4c3b438332c923b9014Jonathan Austin{
4256942fec06efa0e17df0f4c3b438332c923b9014Jonathan Austin	if (!delay_timer)
4356942fec06efa0e17df0f4c3b438332c923b9014Jonathan Austin		return -ENXIO;
4456942fec06efa0e17df0f4c3b438332c923b9014Jonathan Austin
4556942fec06efa0e17df0f4c3b438332c923b9014Jonathan Austin	*timer_val = delay_timer->read_current_timer();
4656942fec06efa0e17df0f4c3b438332c923b9014Jonathan Austin	return 0;
4756942fec06efa0e17df0f4c3b438332c923b9014Jonathan Austin}
4856942fec06efa0e17df0f4c3b438332c923b9014Jonathan Austin
49d0a533b18235d36206b9b422efadb7cee444dfdbWill Deaconstatic void __timer_delay(unsigned long cycles)
50d0a533b18235d36206b9b422efadb7cee444dfdbWill Deacon{
51d0a533b18235d36206b9b422efadb7cee444dfdbWill Deacon	cycles_t start = get_cycles();
52d0a533b18235d36206b9b422efadb7cee444dfdbWill Deacon
53d0a533b18235d36206b9b422efadb7cee444dfdbWill Deacon	while ((get_cycles() - start) < cycles)
54d0a533b18235d36206b9b422efadb7cee444dfdbWill Deacon		cpu_relax();
55d0a533b18235d36206b9b422efadb7cee444dfdbWill Deacon}
56d0a533b18235d36206b9b422efadb7cee444dfdbWill Deacon
57d0a533b18235d36206b9b422efadb7cee444dfdbWill Deaconstatic void __timer_const_udelay(unsigned long xloops)
58d0a533b18235d36206b9b422efadb7cee444dfdbWill Deacon{
59d0a533b18235d36206b9b422efadb7cee444dfdbWill Deacon	unsigned long long loops = xloops;
60d0a533b18235d36206b9b422efadb7cee444dfdbWill Deacon	loops *= loops_per_jiffy;
61d0a533b18235d36206b9b422efadb7cee444dfdbWill Deacon	__timer_delay(loops >> UDELAY_SHIFT);
62d0a533b18235d36206b9b422efadb7cee444dfdbWill Deacon}
63d0a533b18235d36206b9b422efadb7cee444dfdbWill Deacon
64d0a533b18235d36206b9b422efadb7cee444dfdbWill Deaconstatic void __timer_udelay(unsigned long usecs)
65d0a533b18235d36206b9b422efadb7cee444dfdbWill Deacon{
66d0a533b18235d36206b9b422efadb7cee444dfdbWill Deacon	__timer_const_udelay(usecs * UDELAY_MULT);
67d0a533b18235d36206b9b422efadb7cee444dfdbWill Deacon}
68d0a533b18235d36206b9b422efadb7cee444dfdbWill Deacon
6956942fec06efa0e17df0f4c3b438332c923b9014Jonathan Austinvoid __init register_current_timer_delay(const struct delay_timer *timer)
70d0a533b18235d36206b9b422efadb7cee444dfdbWill Deacon{
7156942fec06efa0e17df0f4c3b438332c923b9014Jonathan Austin	if (!delay_calibrated) {
7256942fec06efa0e17df0f4c3b438332c923b9014Jonathan Austin		pr_info("Switching to timer-based delay loop\n");
7356942fec06efa0e17df0f4c3b438332c923b9014Jonathan Austin		delay_timer			= timer;
7456942fec06efa0e17df0f4c3b438332c923b9014Jonathan Austin		lpj_fine			= timer->freq / HZ;
7556942fec06efa0e17df0f4c3b438332c923b9014Jonathan Austin		loops_per_jiffy			= lpj_fine;
7656942fec06efa0e17df0f4c3b438332c923b9014Jonathan Austin		arm_delay_ops.delay		= __timer_delay;
7756942fec06efa0e17df0f4c3b438332c923b9014Jonathan Austin		arm_delay_ops.const_udelay	= __timer_const_udelay;
7856942fec06efa0e17df0f4c3b438332c923b9014Jonathan Austin		arm_delay_ops.udelay		= __timer_udelay;
7956942fec06efa0e17df0f4c3b438332c923b9014Jonathan Austin		delay_calibrated		= true;
8056942fec06efa0e17df0f4c3b438332c923b9014Jonathan Austin	} else {
8156942fec06efa0e17df0f4c3b438332c923b9014Jonathan Austin		pr_info("Ignoring duplicate/late registration of read_current_timer delay\n");
8256942fec06efa0e17df0f4c3b438332c923b9014Jonathan Austin	}
83d0a533b18235d36206b9b422efadb7cee444dfdbWill Deacon}
84d0a533b18235d36206b9b422efadb7cee444dfdbWill Deacon
85d0a533b18235d36206b9b422efadb7cee444dfdbWill Deaconunsigned long __cpuinit calibrate_delay_is_known(void)
86d0a533b18235d36206b9b422efadb7cee444dfdbWill Deacon{
8756942fec06efa0e17df0f4c3b438332c923b9014Jonathan Austin	delay_calibrated = true;
88d0a533b18235d36206b9b422efadb7cee444dfdbWill Deacon	return lpj_fine;
89d0a533b18235d36206b9b422efadb7cee444dfdbWill Deacon}
90