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