1  // SPDX-License-Identifier: GPL-2.0+
2  /*
3   * Based on clocksource code. See commit 74d23cc704d1
4   */
5  #include <linux/export.h>
6  #include <linux/timecounter.h>
7  
timecounter_init(struct timecounter * tc,const struct cyclecounter * cc,u64 start_tstamp)8  void timecounter_init(struct timecounter *tc,
9  		      const struct cyclecounter *cc,
10  		      u64 start_tstamp)
11  {
12  	tc->cc = cc;
13  	tc->cycle_last = cc->read(cc);
14  	tc->nsec = start_tstamp;
15  	tc->mask = (1ULL << cc->shift) - 1;
16  	tc->frac = 0;
17  }
18  EXPORT_SYMBOL_GPL(timecounter_init);
19  
20  /**
21   * timecounter_read_delta - get nanoseconds since last call of this function
22   * @tc:         Pointer to time counter
23   *
24   * When the underlying cycle counter runs over, this will be handled
25   * correctly as long as it does not run over more than once between
26   * calls.
27   *
28   * The first call to this function for a new time counter initializes
29   * the time tracking and returns an undefined result.
30   */
timecounter_read_delta(struct timecounter * tc)31  static u64 timecounter_read_delta(struct timecounter *tc)
32  {
33  	u64 cycle_now, cycle_delta;
34  	u64 ns_offset;
35  
36  	/* read cycle counter: */
37  	cycle_now = tc->cc->read(tc->cc);
38  
39  	/* calculate the delta since the last timecounter_read_delta(): */
40  	cycle_delta = (cycle_now - tc->cycle_last) & tc->cc->mask;
41  
42  	/* convert to nanoseconds: */
43  	ns_offset = cyclecounter_cyc2ns(tc->cc, cycle_delta,
44  					tc->mask, &tc->frac);
45  
46  	/* update time stamp of timecounter_read_delta() call: */
47  	tc->cycle_last = cycle_now;
48  
49  	return ns_offset;
50  }
51  
timecounter_read(struct timecounter * tc)52  u64 timecounter_read(struct timecounter *tc)
53  {
54  	u64 nsec;
55  
56  	/* increment time by nanoseconds since last call */
57  	nsec = timecounter_read_delta(tc);
58  	nsec += tc->nsec;
59  	tc->nsec = nsec;
60  
61  	return nsec;
62  }
63  EXPORT_SYMBOL_GPL(timecounter_read);
64  
65  /*
66   * This is like cyclecounter_cyc2ns(), but it is used for computing a
67   * time previous to the time stored in the cycle counter.
68   */
cc_cyc2ns_backwards(const struct cyclecounter * cc,u64 cycles,u64 mask,u64 frac)69  static u64 cc_cyc2ns_backwards(const struct cyclecounter *cc,
70  			       u64 cycles, u64 mask, u64 frac)
71  {
72  	u64 ns = (u64) cycles;
73  
74  	ns = ((ns * cc->mult) - frac) >> cc->shift;
75  
76  	return ns;
77  }
78  
timecounter_cyc2time(const struct timecounter * tc,u64 cycle_tstamp)79  u64 timecounter_cyc2time(const struct timecounter *tc,
80  			 u64 cycle_tstamp)
81  {
82  	u64 delta = (cycle_tstamp - tc->cycle_last) & tc->cc->mask;
83  	u64 nsec = tc->nsec, frac = tc->frac;
84  
85  	/*
86  	 * Instead of always treating cycle_tstamp as more recent
87  	 * than tc->cycle_last, detect when it is too far in the
88  	 * future and treat it as old time stamp instead.
89  	 */
90  	if (delta > tc->cc->mask / 2) {
91  		delta = (tc->cycle_last - cycle_tstamp) & tc->cc->mask;
92  		nsec -= cc_cyc2ns_backwards(tc->cc, delta, tc->mask, frac);
93  	} else {
94  		nsec += cyclecounter_cyc2ns(tc->cc, delta, tc->mask, &frac);
95  	}
96  
97  	return nsec;
98  }
99  EXPORT_SYMBOL_GPL(timecounter_cyc2time);
100