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 
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 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  */
84  uint64_t clock_freq, uint64_t counter_freq,
86 
87 /**
88  * Completely resets a timer device, disabling all IRQs, counters, and
89  * comparators.
90  *
91  * @param timer A timer device.
92  * @return The result of the operation.
93  */
95 
96 /**
97  * Configures the tick params for a particular hart's counter.
98  *
99  * This function should not be called when `hart_id`'s counter is enabled; it is
100  * the caller's responsibility to assert this precondition.
101  * The function `dif_rv_timer_approximate_tick_params()` can be used to generate
102  * tick parameter values.
103  *
104  * @param timer A timer device.
105  * @param hart_id The hart to configure.
106  * @param params The timing parameters.
107  * @return The result of the operation.
108  */
110  uint32_t hart_id,
112 
113 /**
114  * Starts or stops a particular hart's counter.
115  *
116  * While a counter is enabled, the counter value will increase each tick, but
117  * its timekeeping values cannot be reconfigured.
118  *
119  * @param timer A timer device.
120  * @param hart_id The hart counter to enable/disable.
121  * @param state The new enablement state.
122  * @return The result of the operation.
123  */
125  uint32_t hart_id,
126  dif_toggle_t state);
127 
128 /**
129  * Reads the current value on a particular hart's timer.
130  *
131  * @param timer A timer device.
132  * @param hart_id The hart counter to read.
133  * @param[out] out The counter value.
134  * @return The result of the operation.
135  */
137  uint32_t hart_id, uint64_t *out);
138 
139 /**
140  * Writes the given value to a particular hart's timer.
141  *
142  * @param timer A timer device.
143  * @param hart_id The hart counter to write.
144  * @param count The counter value to write.
145  * @return The result of the operation.
146  */
148  uint32_t hart_id, uint64_t count);
149 
150 /**
151  * Arms the timer to go off once the counter value is greater than
152  * or equal to `threshold`, by setting up the given comparator.
153  *
154  * Beware that the following naive implementation of setting an alarm
155  * contains a bug:
156  * uint64_t time;
157  * dif_rv_timer_counter_read(my_timer, kMyHart, &time);
158  * time += kSomeDuration; // (*)
159  * dif_rv_timer_arm(my_timer, kMyHart, kMyComp, time);
160  *
161  * If `time` wraps around when performing the addition, an interrupt will be
162  * fired immediately upon calling `dif_rv_timer_arm`. Care should be taken to
163  * perform saturating addition at (*), so that the interrupt is fired when the
164  * timer value wraps around; this way, the interrupt handler can re-arm the
165  * timer for the rest of the duration.
166  *
167  * This function makes no effort to protect the caller from setting alarms in
168  * the past that would immediately fire an interrupt. It is the caller's
169  * responsibility to read the current counter value and pick a reasonable alarm
170  * threshold.
171  *
172  * @param timer A timer device.
173  * @param hart_id The hart counter to arm against.
174  * @param comp_id The comparator to set up.
175  * @param threshold The value to go off at.
176  * @return The result of the operation.
177  */
178 dif_result_t dif_rv_timer_arm(const dif_rv_timer_t *timer, uint32_t hart_id,
179  uint32_t comp_id, uint64_t threshold);
180 
181 #ifdef __cplusplus
182 } // extern "C"
183 #endif // __cplusplus
184 
185 #endif // OPENTITAN_SW_DEVICE_LIB_DIF_DIF_RV_TIMER_H_