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