root/arch/arm/lib/delay.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. read_current_timer
  2. cyc_to_ns
  3. __timer_delay
  4. __timer_const_udelay
  5. __timer_udelay
  6. register_current_timer_delay
  7. calibrate_delay_is_known
  8. calibration_delay_done

   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 int read_current_timer(unsigned long *timer_val)
  31 {
  32         if (!delay_timer)
  33                 return -ENXIO;
  34 
  35         *timer_val = delay_timer->read_current_timer();
  36         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         return (cyc * mult) >> shift;
  43 }
  44 
  45 static void __timer_delay(unsigned long cycles)
  46 {
  47         cycles_t start = get_cycles();
  48 
  49         while ((get_cycles() - start) < cycles)
  50                 cpu_relax();
  51 }
  52 
  53 static void __timer_const_udelay(unsigned long xloops)
  54 {
  55         unsigned long long loops = xloops;
  56         loops *= arm_delay_ops.ticks_per_jiffy;
  57         __timer_delay(loops >> UDELAY_SHIFT);
  58 }
  59 
  60 static void __timer_udelay(unsigned long usecs)
  61 {
  62         __timer_const_udelay(usecs * UDELAY_MULT);
  63 }
  64 
  65 void __init register_current_timer_delay(const struct delay_timer *timer)
  66 {
  67         u32 new_mult, new_shift;
  68         u64 res;
  69 
  70         clocks_calc_mult_shift(&new_mult, &new_shift, timer->freq,
  71                                NSEC_PER_SEC, 3600);
  72         res = cyc_to_ns(1ULL, new_mult, new_shift);
  73 
  74         if (res > 1000) {
  75                 pr_err("Ignoring delay timer %ps, which has insufficient resolution of %lluns\n",
  76                         timer, res);
  77                 return;
  78         }
  79 
  80         if (!delay_calibrated && (!delay_res || (res < delay_res))) {
  81                 pr_info("Switching to timer-based delay loop, resolution %lluns\n", res);
  82                 delay_timer                     = timer;
  83                 lpj_fine                        = timer->freq / HZ;
  84                 delay_res                       = res;
  85 
  86                 /* cpufreq may scale loops_per_jiffy, so keep a private copy */
  87                 arm_delay_ops.ticks_per_jiffy   = lpj_fine;
  88                 arm_delay_ops.delay             = __timer_delay;
  89                 arm_delay_ops.const_udelay      = __timer_const_udelay;
  90                 arm_delay_ops.udelay            = __timer_udelay;
  91         } else {
  92                 pr_info("Ignoring duplicate/late registration of read_current_timer delay\n");
  93         }
  94 }
  95 
  96 unsigned long calibrate_delay_is_known(void)
  97 {
  98         delay_calibrated = true;
  99         return lpj_fine;
 100 }
 101 
 102 void calibration_delay_done(void)
 103 {
 104         delay_calibrated = true;
 105 }

/* [<][>][^][v][top][bottom][index][help] */