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
18#include "sw/device/lib/dif/autogen/dif_rv_timer_autogen.h"
19
20#ifdef __cplusplus
21extern "C" {
22#endif // __cplusplus
23
24/**
25 * Represents timekeeping parameters for a particular timer.
26 */
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 */
185dif_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_