Software APIs
dif_rv_timer.h
Go to the documentation of this file.
1 // Copyright lowRISC contributors (OpenTitan project).
2 // Licensed under the Apache License, Version 2.0, see LICENSE for details.
3 // SPDX-License-Identifier: Apache-2.0
4 
5 #ifndef OPENTITAN_SW_DEVICE_LIB_DIF_DIF_RV_TIMER_H_
6 #define OPENTITAN_SW_DEVICE_LIB_DIF_DIF_RV_TIMER_H_
7 
8 /**
9  * @file
10  * @brief <a href="/hw/ip/rv_timer/doc/">RV Timer</a> Device Interface Functions
11  */
12 
13 #include <stdint.h>
14 
17 
19 
20 #ifdef __cplusplus
21 extern "C" {
22 #endif // __cplusplus
23 
24 /**
25  * Represents timekeeping parameters for a particular timer.
26  */
27 typedef struct dif_rv_timer_tick_params {
28  /**
29  * The prescaler value is the period of the timer tick in clock cycles,
30  * minus one. That is,
31  *
32  * prescale = clock_freq * tick_period - 1
33  *
34  * with |clock_freq| and |tick_period| given in units of hertz and seconds,
35  * respectively.
36  *
37  * For example, if the clock frequency is 50 MHz, and the desired tick
38  * period is 1 microsecond, i.e, a tick frequency of 1 MHz, then the
39  * prescaler should be:
40  *
41  * (50 * 10^6) * (1 * 10^-6) - 1 = 49
42  *
43  * However, since |tick_period| is very small, it is much more convenient to
44  * work with |tick_freq|, its inverse, which will be an integer number of
45  * hertz. In particular,
46  *
47  * prescale = (clock_freq / tick_freq) - 1
48  *
49  * This value is declared as a uint16_t, but only the lowest 12 bits are
50  * actually used.
51  */
52  uint16_t prescale;
53 
54  /**
55  * The amount to increment the timer counter at each tick.
56  */
57  uint8_t tick_step;
59 
60 /**
61  * Generates an aproximate `dif_rv_timer_tick_params_t` given the device
62  * clock frequency and desired counter frequency (both given in Hertz).
63  *
64  * For the purposes of this function, "counter frequency" is the frequency
65  * at which software would observe a timer counter to increase. If the
66  * clock has insufficient resolution, high counter frequencies may set a
67  * larger value for `tick_step`. For example, if the clock ticks at 50kHz,
68  * but we want a counter that seems to tick every microsecond (1MHz),
69  * we can achieve this with a prescale of 0 (so that there is a tick per
70  * clock cycle) and a tick step of 20 (since 20 * 50kHz = 1MHz).
71  *
72  * The return value of this function is only an approximation, and the
73  * actual counter frequency ultimately depends on the accuracy of the
74  * clock. The function will return an error if it cannot produce an acceptably
75  * accurate counter frequency using the given clock resolution.
76  *
77  * @param clock_freq The device clock frequency, in Hertz.
78  * @param counter_freq The desired counter frequency, in Hertz.
79  * @param[out] out Tick parameters that will approximately produce the desired
80  * counter frequency.
81  * @return The result of the operation.
82  */
85  uint64_t clock_freq, uint64_t counter_freq,
87 
88 /**
89  * Completely resets a timer device, disabling all IRQs, counters, and
90  * comparators.
91  *
92  * @param timer A timer device.
93  * @return The result of the operation.
94  */
97 
98 /**
99  * Configures the tick params for a particular hart's counter.
100  *
101  * This function should not be called when `hart_id`'s counter is enabled; it is
102  * the caller's responsibility to assert this precondition.
103  * The function `dif_rv_timer_approximate_tick_params()` can be used to generate
104  * tick parameter values.
105  *
106  * @param timer A timer device.
107  * @param hart_id The hart to configure.
108  * @param params The timing parameters.
109  * @return The result of the operation.
110  */
113  uint32_t hart_id,
115 
116 /**
117  * Starts or stops a particular hart's counter.
118  *
119  * While a counter is enabled, the counter value will increase each tick, but
120  * its timekeeping values cannot be reconfigured.
121  *
122  * @param timer A timer device.
123  * @param hart_id The hart counter to enable/disable.
124  * @param state The new enablement state.
125  * @return The result of the operation.
126  */
129  uint32_t hart_id,
130  dif_toggle_t state);
131 
132 /**
133  * Reads the current value on a particular hart's timer.
134  *
135  * @param timer A timer device.
136  * @param hart_id The hart counter to read.
137  * @param[out] out The counter value.
138  * @return The result of the operation.
139  */
142  uint32_t hart_id, uint64_t *out);
143 
144 /**
145  * Writes the given value to a particular hart's timer.
146  *
147  * @param timer A timer device.
148  * @param hart_id The hart counter to write.
149  * @param count The counter value to write.
150  * @return The result of the operation.
151  */
154  uint32_t hart_id, uint64_t count);
155 
156 /**
157  * Arms the timer to go off once the counter value is greater than
158  * or equal to `threshold`, by setting up the given comparator.
159  *
160  * Beware that the following naive implementation of setting an alarm
161  * contains a bug:
162  * uint64_t time;
163  * dif_rv_timer_counter_read(my_timer, kMyHart, &time);
164  * time += kSomeDuration; // (*)
165  * dif_rv_timer_arm(my_timer, kMyHart, kMyComp, time);
166  *
167  * If `time` wraps around when performing the addition, an interrupt will be
168  * fired immediately upon calling `dif_rv_timer_arm`. Care should be taken to
169  * perform saturating addition at (*), so that the interrupt is fired when the
170  * timer value wraps around; this way, the interrupt handler can re-arm the
171  * timer for the rest of the duration.
172  *
173  * This function makes no effort to protect the caller from setting alarms in
174  * the past that would immediately fire an interrupt. It is the caller's
175  * responsibility to read the current counter value and pick a reasonable alarm
176  * threshold.
177  *
178  * @param timer A timer device.
179  * @param hart_id The hart counter to arm against.
180  * @param comp_id The comparator to set up.
181  * @param threshold The value to go off at.
182  * @return The result of the operation.
183  */
185 dif_result_t dif_rv_timer_arm(const dif_rv_timer_t *timer, uint32_t hart_id,
186  uint32_t comp_id, uint64_t threshold);
187 
188 #ifdef __cplusplus
189 } // extern "C"
190 #endif // __cplusplus
191 
192 #endif // OPENTITAN_SW_DEVICE_LIB_DIF_DIF_RV_TIMER_H_