Software APIs
sw
device
lib
dif
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
15
#include "
sw/device/lib/base/mmio.h
"
16
#include "
sw/device/lib/dif/dif_base.h
"
17
18
#include "
sw/device/lib/dif/autogen/dif_rv_timer_autogen.h
"
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
;
58
}
dif_rv_timer_tick_params_t
;
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
*/
83
OT_WARN_UNUSED_RESULT
84
dif_result_t
dif_rv_timer_approximate_tick_params
(
85
uint64_t clock_freq, uint64_t counter_freq,
86
dif_rv_timer_tick_params_t
*out);
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
*/
95
OT_WARN_UNUSED_RESULT
96
dif_result_t
dif_rv_timer_reset
(
const
dif_rv_timer_t
*timer);
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
*/
111
OT_WARN_UNUSED_RESULT
112
dif_result_t
dif_rv_timer_set_tick_params
(
const
dif_rv_timer_t
*timer,
113
uint32_t hart_id,
114
dif_rv_timer_tick_params_t
params);
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
*/
127
OT_WARN_UNUSED_RESULT
128
dif_result_t
dif_rv_timer_counter_set_enabled
(
const
dif_rv_timer_t
*timer,
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
*/
140
OT_WARN_UNUSED_RESULT
141
dif_result_t
dif_rv_timer_counter_read
(
const
dif_rv_timer_t
*timer,
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
*/
152
OT_WARN_UNUSED_RESULT
153
dif_result_t
dif_rv_timer_counter_write
(
const
dif_rv_timer_t
*timer,
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
*/
184
OT_WARN_UNUSED_RESULT
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_
Return to
OpenTitan Documentation