Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0-only
0002 /*
0003  * Delay loops based on the OpenRISC implementation.
0004  *
0005  * Copyright (C) 2012 ARM Limited
0006  *
0007  * Author: Will Deacon <will.deacon@arm.com>
0008  */
0009 
0010 #include <linux/clocksource.h>
0011 #include <linux/delay.h>
0012 #include <linux/init.h>
0013 #include <linux/kernel.h>
0014 #include <linux/module.h>
0015 #include <linux/timex.h>
0016 
0017 /*
0018  * Default to the loop-based delay implementation.
0019  */
0020 struct arm_delay_ops arm_delay_ops __ro_after_init = {
0021     .delay      = __loop_delay,
0022     .const_udelay   = __loop_const_udelay,
0023     .udelay     = __loop_udelay,
0024 };
0025 
0026 static const struct delay_timer *delay_timer;
0027 static bool delay_calibrated;
0028 static u64 delay_res;
0029 
0030 int read_current_timer(unsigned long *timer_val)
0031 {
0032     if (!delay_timer)
0033         return -ENXIO;
0034 
0035     *timer_val = delay_timer->read_current_timer();
0036     return 0;
0037 }
0038 EXPORT_SYMBOL_GPL(read_current_timer);
0039 
0040 static inline u64 cyc_to_ns(u64 cyc, u32 mult, u32 shift)
0041 {
0042     return (cyc * mult) >> shift;
0043 }
0044 
0045 static void __timer_delay(unsigned long cycles)
0046 {
0047     cycles_t start = get_cycles();
0048 
0049     while ((get_cycles() - start) < cycles)
0050         cpu_relax();
0051 }
0052 
0053 static void __timer_const_udelay(unsigned long xloops)
0054 {
0055     unsigned long long loops = xloops;
0056     loops *= arm_delay_ops.ticks_per_jiffy;
0057     __timer_delay(loops >> UDELAY_SHIFT);
0058 }
0059 
0060 static void __timer_udelay(unsigned long usecs)
0061 {
0062     __timer_const_udelay(usecs * UDELAY_MULT);
0063 }
0064 
0065 void __init register_current_timer_delay(const struct delay_timer *timer)
0066 {
0067     u32 new_mult, new_shift;
0068     u64 res;
0069 
0070     clocks_calc_mult_shift(&new_mult, &new_shift, timer->freq,
0071                    NSEC_PER_SEC, 3600);
0072     res = cyc_to_ns(1ULL, new_mult, new_shift);
0073 
0074     if (res > 1000) {
0075         pr_err("Ignoring delay timer %ps, which has insufficient resolution of %lluns\n",
0076             timer, res);
0077         return;
0078     }
0079 
0080     if (!delay_calibrated && (!delay_res || (res < delay_res))) {
0081         pr_info("Switching to timer-based delay loop, resolution %lluns\n", res);
0082         delay_timer         = timer;
0083         lpj_fine            = timer->freq / HZ;
0084         delay_res           = res;
0085 
0086         /* cpufreq may scale loops_per_jiffy, so keep a private copy */
0087         arm_delay_ops.ticks_per_jiffy   = lpj_fine;
0088         arm_delay_ops.delay     = __timer_delay;
0089         arm_delay_ops.const_udelay  = __timer_const_udelay;
0090         arm_delay_ops.udelay        = __timer_udelay;
0091     } else {
0092         pr_info("Ignoring duplicate/late registration of read_current_timer delay\n");
0093     }
0094 }
0095 
0096 unsigned long calibrate_delay_is_known(void)
0097 {
0098     delay_calibrated = true;
0099     return lpj_fine;
0100 }
0101 
0102 void calibration_delay_done(void)
0103 {
0104     delay_calibrated = true;
0105 }