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