Software APIs
dif_rv_timer.h
Go to the documentation of this file.
1 // Copyright lowRISC contributors.
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 
16 
17 #ifdef __cplusplus
18 extern "C" {
19 #endif // __cplusplus
20 
21 /**
22  * Represents an "enabled" state for a timer.
23  */
24 typedef enum dif_rv_timer_enabled {
25  kDifRvTimerDisabled = 0,
26  kDifRvTimerEnabled,
28 
29 /**
30  * Represents timekeeping parameters for a particular timer.
31  */
32 typedef struct dif_rv_timer_tick_params {
33  /**
34  * The prescaler value is the period of the timer tick in clock cycles,
35  * minus one. That is,
36  *
37  * prescale = clock_freq * tick_period - 1
38  *
39  * with |clock_freq| and |tick_period| given in units of hertz and seconds,
40  * respectively.
41  *
42  * For example, if the clock frequency is 50 MHz, and the desired tick
43  * period is is 1 microsecond, i.e, a tick frequency of 1 MHz, then the
44  * prescaler should be:
45  *
46  * (50 * 10^6) * (1 * 10^-6) - 1 = 49
47  *
48  * However, since |tick_period| is very small, it is much more convenient to
49  * work with |tick_freq|, its inverse, which will be an integer number of
50  * hertz. In particular,
51  *
52  * prescale = (clock_freq / tick_freq) - 1
53  *
54  * This value is declared as a uint16_t, but only the lowest 12 bits are
55  * actually used.
56  */
57  uint16_t prescale;
58 
59  /**
60  * The amount to increment the timer counter at each tick.
61  */
62  uint8_t tick_step;
64 
65 /**
66  * Represents the result of an RV timer operation..
67  */
68 typedef enum dif_rv_timer_result {
69  kDifRvTimerOk = 0,
70  kDifRvTimerBadArg = 1,
71  kDifRvTimerError = 2,
73 
74 /**
75  * Errors returned by `dif_rv_timer_approximate_tick_params()`.
76  */
78  kDifRvTimerApproximateTickParamsOk = kDifRvTimerOk,
79  kDifRvTimerApproximateTickParamsBadArg = kDifRvTimerBadArg,
80  kDifRvTimerApproximateTickParamsError = kDifRvTimerError,
81  /**
82  * Indicates that the requested counter frequency cannot be represented
83  * without loss in precission.
84  */
87 
88 /**
89  * Generates an aproximate `dif_rv_timer_tick_params_t` given the device
90  * clock frequency and desired counter frequency (both given in Hertz).
91  *
92  * For the purposes of this function, "counter frequency" is the frequency
93  * at which software would observe a timer counter to increase. If the
94  * clock has insufficient resolution, high counter frequencies may set a
95  * larger value for `tick_step`. For example, if the clock ticks at 50kHz,
96  * but we want a counter that seems to tick every microsecond (1MHz),
97  * we can achieve this with a prescale of 0 (so that there is a tick per
98  * clock cycle) and a tick step of 20 (since 20 * 50kHz = 1MHz).
99  *
100  * The return value of this function is only an approximation, and the
101  * actual counter frequency ultimately depends on the accuracy of the
102  * clock. The function will return an error if it cannot produce an acceptably
103  * accurate counter frequency using the given clock resolution.
104  *
105  * @param clock_freq The device clock frequency, in Hertz.
106  * @param counter_freq The desired counter frequency, in Hertz.
107  * @param[out] out Tick parameters that will approximately produce the desired
108  * counter frequency.
109  * @return The result of the operation.
110  */
111 dif_rv_timer_approximate_tick_params_result_t
112 dif_rv_timer_approximate_tick_params(uint64_t clock_freq, uint64_t counter_freq,
114 /**
115  * Configuration for initializing the RISC-V timer device.
116  */
117 typedef struct dif_rv_timer_config {
118  /**
119  * The number of harts that this device supports time counters for.
120  * Must be at least one.
121  *
122  * This value is determined entirely by the hardware configuration.
123  */
124  uint32_t hart_count;
125 
126  /**
127  * The number of comparators (i.e, timers that can be set) associated
128  * with each hart. Must be at least one.
129  *
130  * This value is determined entirely by the hardware configuration.
131  */
134 
135 /**
136  * State for a RISC-V timer, associated with a particular hardware thread.
137  *
138  * Its member variables should be considered private, and are only provided so
139  * that callers can allocate it.
140  */
141 typedef struct dif_rv_timer {
142  mmio_region_t base_addr;
143  dif_rv_timer_config_t config;
145 
146 /**
147  * Initialize a RISC-V timer device with the given configuration.
148  *
149  * This function will deactivate all counters and reset all timers, which should
150  * each be configured and turned on manually after this function returns.
151  *
152  * @param base_addr MMIO region for the device hardware registers.
153  * @param config Configuration for initializing a particular timer.
154  * @param[out] timer_out The timer device.
155  * @return The result of the operation.
156  */
158  dif_rv_timer_config_t config,
159  dif_rv_timer_t *timer_out);
160 
161 /**
162  * Completely resets a timer device, disabling all IRQs, counters, and
163  * comparators.
164  *
165  * @param timer A timer device.
166  * @return The result of the operation.
167  */
169 
170 /**
171  * Configures the tick params for a particular hart's counter.
172  *
173  * This function should not be called when `hart_id`'s counter is enabled; it is
174  * the caller's responsibility to assert this precondition.
175  * The function `dif_rv_timer_approximate_tick_params()` can be used to generate
176  * tick parameter values.
177  *
178  * @param timer A timer device.
179  * @param hart_id The hart to configure.
180  * @param params The timing parameters.
181  * @return The result of the operation.
182  */
184  const dif_rv_timer_t *timer, uint32_t hart_id,
186 
187 /**
188  * Starts or stops a particular hart's counter.
189  *
190  * While a counter is enabled, the counter value will increase each tick, but
191  * its timekeeping values cannot be reconfigured.
192  *
193  * @param timer A timer device.
194  * @param hart_id The hart counter to enable/disable.
195  * @param state The new enablement state.
196  * @return The result of the operation.
197  */
199  const dif_rv_timer_t *timer, uint32_t hart_id,
200  dif_rv_timer_enabled_t state);
201 
202 /**
203  * Reads the current value on a particlar hart's timer.
204  *
205  * @param timer A timer device.
206  * @param hart_id The hart counter to read.
207  * @param[out] out The counter value.
208  * @return The result of the operation.
209  */
211  uint32_t hart_id,
212  uint64_t *out);
213 
214 /**
215  * Arms the timer to go off once the counter value is greater than
216  * or equal to `threshold`, by setting up the given comparator.
217  *
218  * Beware that the following naive implementation of setting an alarm
219  * contains a bug:
220  * uint64_t time;
221  * dif_rv_timer_counter_read(my_timer, kMyHart, &time);
222  * time += kSomeDuration; // (*)
223  * dif_rv_timer_arm(my_timer, kMyHart, kMyComp, time);
224  *
225  * If `time` wraps around when performing the addition, an interrupt will be
226  * fired immediately upon calling `dif_rv_timer_arm`. Care should be taken to
227  * perform saturating addition at (*), so that the interrupt is fired when the
228  * timer value wraps around; this way, the interrupt handler can re-arm the
229  * timer for the rest of the duration.
230  *
231  * This function makes no effort to protect the caller from setting alarms in
232  * the past that would immediately fire an interrupt. It is the caller's
233  * responsibility to read the current counter value and pick a reasonable alarm
234  * threshold.
235  *
236  * @param timer A timer device.
237  * @param hart_id The hart counter to arm against.
238  * @param comp_id The comparator to set up.
239  * @param threshold The value to go off at.
240  * @return The result of the operation.
241  */
243  uint32_t hart_id, uint32_t comp_id,
244  uint64_t threshold);
245 
246 /**
247  * Enables or disables a particular timer's IRQ. That is, this function controls
248  * whether or not an IRQ is fired when the timer reaches its configured
249  * threshold.
250  *
251  * @param timer A timer device.
252  * @param hart_id The hart counter associated with the timer.
253  * @param comp_id The comparator associated with the timer.
254  * @param state The desired status.
255  * @return the result of the operation.
256  */
258  uint32_t hart_id,
259  uint32_t comp_id,
260  dif_rv_timer_enabled_t state);
261 
262 /**
263  * Returns whether the IRQ for a particular timer is currently being serviced.
264  *
265  * @param timer A timer device.
266  * @param hart_id The hart counter associated with the timer.
267  * @param comp_id The comparator associated with the timer.
268  * @param[out] flag_out The interrupt status.
269  * @return the result of the operation.
270  */
272  uint32_t hart_id, uint32_t comp_id,
273  bool *flag_out);
274 
275 /**
276  * Clears the IRQ for a particular timer.
277  *
278  * @param timer A timer device.
279  * @param hart_id The hart counter associated with the timer.
280  * @param comp_id The comparator associated with the timer.
281  * @return the result of the operation.
282  */
284  uint32_t hart_id,
285  uint32_t comp_id);
286 
287 /**
288  * Forces the IRQ for a particular timer to fire.
289  *
290  * @param timer A timer device.
291  * @param hart_id The hart counter associated with the timer.
292  * @param comp_id The comparator associated with the timer.
293  * @return the result of the operation.
294  */
296  uint32_t hart_id,
297  uint32_t comp_id);
298 
299 /**
300  * Disables all IRQs for a particular hart.
301  *
302  * Optionally returns a `state` value containing the previous itnerrupt state.
303  * `state` may be NULL. See `dif_rv_timer_irq_restore()`.
304  *
305  * @param timer a timer device.
306  * @param[out] state IRQ state information for use with
307  * `dif_rv_timer_irq_restore`.
308  * @return the result of the operation.
309  */
311  uint32_t hart_id,
312  uint32_t *state);
313 
314 /**
315  * Restores IRQ state for a particular hart.
316  *
317  * @param timer a timer device.
318  * @param state IRQ state information to restore.
319  * @return the result of the operation.
320  */
322  uint32_t hart_id,
323  uint32_t state);
324 
325 #ifdef __cplusplus
326 } // extern "C"
327 #endif // __cplusplus
328 
329 #endif // OPENTITAN_SW_DEVICE_LIB_DIF_DIF_RV_TIMER_H_