2019-05-29 16:57:47 -07:00
// SPDX-License-Identifier: GPL-2.0-only
2012-07-06 15:47:17 +01:00
/*
* Delay loops based on the OpenRISC implementation .
*
* Copyright ( C ) 2012 ARM Limited
*
* Author : Will Deacon < will . deacon @ arm . com >
*/
2014-06-12 18:58:28 +03:00
# include <linux/clocksource.h>
2012-07-06 15:47:17 +01:00
# include <linux/delay.h>
# include <linux/init.h>
# include <linux/kernel.h>
# include <linux/module.h>
# include <linux/timex.h>
/*
* Default to the loop - based delay implementation .
*/
2016-08-10 22:46:49 +01:00
struct arm_delay_ops arm_delay_ops __ro_after_init = {
2012-07-06 15:47:17 +01:00
. delay = __loop_delay ,
. const_udelay = __loop_const_udelay ,
. udelay = __loop_udelay ,
} ;
2012-09-21 18:51:44 +01:00
static const struct delay_timer * delay_timer ;
static bool delay_calibrated ;
2014-06-12 18:58:28 +03:00
static u64 delay_res ;
2012-09-21 18:51:44 +01:00
int read_current_timer ( unsigned long * timer_val )
{
if ( ! delay_timer )
return - ENXIO ;
* timer_val = delay_timer - > read_current_timer ( ) ;
return 0 ;
}
2012-10-01 14:47:31 +00:00
EXPORT_SYMBOL_GPL ( read_current_timer ) ;
2012-09-21 18:51:44 +01:00
2014-06-12 18:58:28 +03:00
static inline u64 cyc_to_ns ( u64 cyc , u32 mult , u32 shift )
{
return ( cyc * mult ) > > shift ;
}
2012-07-06 15:47:17 +01:00
static void __timer_delay ( unsigned long cycles )
{
cycles_t start = get_cycles ( ) ;
while ( ( get_cycles ( ) - start ) < cycles )
cpu_relax ( ) ;
}
static void __timer_const_udelay ( unsigned long xloops )
{
unsigned long long loops = xloops ;
2013-03-28 11:17:55 +01:00
loops * = arm_delay_ops . ticks_per_jiffy ;
2012-07-06 15:47:17 +01:00
__timer_delay ( loops > > UDELAY_SHIFT ) ;
}
static void __timer_udelay ( unsigned long usecs )
{
__timer_const_udelay ( usecs * UDELAY_MULT ) ;
}
2012-09-21 18:51:44 +01:00
void __init register_current_timer_delay ( const struct delay_timer * timer )
2012-07-06 15:47:17 +01:00
{
2014-06-12 18:58:28 +03:00
u32 new_mult , new_shift ;
u64 res ;
clocks_calc_mult_shift ( & new_mult , & new_shift , timer - > freq ,
NSEC_PER_SEC , 3600 ) ;
res = cyc_to_ns ( 1ULL , new_mult , new_shift ) ;
2015-04-13 10:36:04 +01:00
if ( res > 1000 ) {
pr_err ( " Ignoring delay timer %ps, which has insufficient resolution of %lluns \n " ,
timer , res ) ;
return ;
}
2014-06-12 18:58:28 +03:00
if ( ! delay_calibrated & & ( ! delay_res | | ( res < delay_res ) ) ) {
pr_info ( " Switching to timer-based delay loop, resolution %lluns \n " , res ) ;
2012-09-21 18:51:44 +01:00
delay_timer = timer ;
lpj_fine = timer - > freq / HZ ;
2014-06-12 18:58:28 +03:00
delay_res = res ;
2013-03-28 11:17:55 +01:00
/* cpufreq may scale loops_per_jiffy, so keep a private copy */
arm_delay_ops . ticks_per_jiffy = lpj_fine ;
2012-09-21 18:51:44 +01:00
arm_delay_ops . delay = __timer_delay ;
arm_delay_ops . const_udelay = __timer_const_udelay ;
arm_delay_ops . udelay = __timer_udelay ;
} else {
pr_info ( " Ignoring duplicate/late registration of read_current_timer delay \n " ) ;
}
2012-07-06 15:47:17 +01:00
}
2013-06-17 15:43:14 -04:00
unsigned long calibrate_delay_is_known ( void )
2012-07-06 15:47:17 +01:00
{
2012-09-21 18:51:44 +01:00
delay_calibrated = true ;
2012-07-06 15:47:17 +01:00
return lpj_fine ;
}
2014-06-12 18:58:28 +03:00
void calibration_delay_done ( void )
{
delay_calibrated = true ;
}