--- zzzz-none-000/linux-3.10.107/arch/arm/lib/delay.c 2017-06-27 09:49:32.000000000 +0000 +++ scorpion-7490-727/linux-3.10.107/arch/arm/lib/delay.c 2021-02-04 17:41:59.000000000 +0000 @@ -19,6 +19,7 @@ * Author: Will Deacon */ +#include #include #include #include @@ -36,6 +37,7 @@ static const struct delay_timer *delay_timer; static bool delay_calibrated; +static u64 delay_res; int read_current_timer(unsigned long *timer_val) { @@ -47,6 +49,11 @@ } EXPORT_SYMBOL_GPL(read_current_timer); +static inline u64 cyc_to_ns(u64 cyc, u32 mult, u32 shift) +{ + return (cyc * mult) >> shift; +} + static void __timer_delay(unsigned long cycles) { cycles_t start = get_cycles(); @@ -69,25 +76,42 @@ void __init register_current_timer_delay(const struct delay_timer *timer) { - if (!delay_calibrated) { - pr_info("Switching to timer-based delay loop\n"); + 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); + + if (res > 1000) { + pr_err("Ignoring delay timer %ps, which has insufficient resolution of %lluns\n", + timer, res); + return; + } + + if (!delay_calibrated && (!delay_res || (res < delay_res))) { + pr_info("Switching to timer-based delay loop, resolution %lluns\n", res); delay_timer = timer; lpj_fine = timer->freq / HZ; + delay_res = res; /* cpufreq may scale loops_per_jiffy, so keep a private copy */ arm_delay_ops.ticks_per_jiffy = lpj_fine; arm_delay_ops.delay = __timer_delay; arm_delay_ops.const_udelay = __timer_const_udelay; arm_delay_ops.udelay = __timer_udelay; - - delay_calibrated = true; } else { pr_info("Ignoring duplicate/late registration of read_current_timer delay\n"); } } -unsigned long __cpuinit calibrate_delay_is_known(void) +unsigned long calibrate_delay_is_known(void) { delay_calibrated = true; return lpj_fine; } + +void calibration_delay_done(void) +{ + delay_calibrated = true; +}