Branch data Line data Source code
1 : : // SPDX-License-Identifier: GPL-2.0-only 2 : : /* 3 : : * Delay loops based on the OpenRISC implementation. 4 : : * 5 : : * Copyright (C) 2012 ARM Limited 6 : : * 7 : : * Author: Will Deacon <will.deacon@arm.com> 8 : : */ 9 : : 10 : : #include <linux/clocksource.h> 11 : : #include <linux/delay.h> 12 : : #include <linux/init.h> 13 : : #include <linux/kernel.h> 14 : : #include <linux/module.h> 15 : : #include <linux/timex.h> 16 : : 17 : : /* 18 : : * Default to the loop-based delay implementation. 19 : : */ 20 : : struct arm_delay_ops arm_delay_ops __ro_after_init = { 21 : : .delay = __loop_delay, 22 : : .const_udelay = __loop_const_udelay, 23 : : .udelay = __loop_udelay, 24 : : }; 25 : : 26 : : static const struct delay_timer *delay_timer; 27 : : static bool delay_calibrated; 28 : : static u64 delay_res; 29 : : 30 : 173325030 : int read_current_timer(unsigned long *timer_val) 31 : : { 32 [ + - + + : 1453955108 : if (!delay_timer) + + ] 33 : : return -ENXIO; 34 : : 35 : 1453883872 : *timer_val = delay_timer->read_current_timer(); 36 : 173255070 : return 0; 37 : : } 38 : : EXPORT_SYMBOL_GPL(read_current_timer); 39 : : 40 : : static inline u64 cyc_to_ns(u64 cyc, u32 mult, u32 shift) 41 : : { 42 : 404 : return (cyc * mult) >> shift; 43 : : } 44 : : 45 : 233198 : static void __timer_delay(unsigned long cycles) 46 : : { 47 [ + - ]: 233198 : cycles_t start = get_cycles(); 48 : : 49 [ + + + + ]: 1280630282 : while ((get_cycles() - start) < cycles) 50 : 1280163886 : cpu_relax(); 51 : 233198 : } 52 : : 53 : 226724 : static void __timer_const_udelay(unsigned long xloops) 54 : : { 55 : 233198 : unsigned long long loops = xloops; 56 : 233198 : loops *= arm_delay_ops.ticks_per_jiffy; 57 : 233198 : __timer_delay(loops >> UDELAY_SHIFT); 58 : 226724 : } 59 : : 60 : 6474 : static void __timer_udelay(unsigned long usecs) 61 : : { 62 : 6474 : __timer_const_udelay(usecs * UDELAY_MULT); 63 : 6474 : } 64 : : 65 : 404 : void __init register_current_timer_delay(const struct delay_timer *timer) 66 : : { 67 : : u32 new_mult, new_shift; 68 : : u64 res; 69 : : 70 : 404 : clocks_calc_mult_shift(&new_mult, &new_shift, timer->freq, 71 : : NSEC_PER_SEC, 3600); 72 : 404 : res = cyc_to_ns(1ULL, new_mult, new_shift); 73 : : 74 [ - + ]: 404 : if (res > 1000) { 75 : 0 : pr_err("Ignoring delay timer %ps, which has insufficient resolution of %lluns\n", 76 : : timer, res); 77 : 404 : return; 78 : : } 79 : : 80 [ + - - + : 404 : if (!delay_calibrated && (!delay_res || (res < delay_res))) { # # ] 81 : 404 : pr_info("Switching to timer-based delay loop, resolution %lluns\n", res); 82 : 404 : delay_timer = timer; 83 : 404 : lpj_fine = timer->freq / HZ; 84 : 404 : delay_res = res; 85 : : 86 : : /* cpufreq may scale loops_per_jiffy, so keep a private copy */ 87 : 404 : arm_delay_ops.ticks_per_jiffy = lpj_fine; 88 : 404 : arm_delay_ops.delay = __timer_delay; 89 : 404 : arm_delay_ops.const_udelay = __timer_const_udelay; 90 : 404 : arm_delay_ops.udelay = __timer_udelay; 91 : : } else { 92 : 0 : pr_info("Ignoring duplicate/late registration of read_current_timer delay\n"); 93 : : } 94 : : } 95 : : 96 : 1212 : unsigned long calibrate_delay_is_known(void) 97 : : { 98 : 1212 : delay_calibrated = true; 99 : 1212 : return lpj_fine; 100 : : } 101 : : 102 : 0 : void calibration_delay_done(void) 103 : : { 104 : 0 : delay_calibrated = true; 105 : 0 : }