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