-
Notifications
You must be signed in to change notification settings - Fork 777
/
dif_rv_plic.h
268 lines (245 loc) · 9.43 KB
/
dif_rv_plic.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
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
// 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_PLIC_H_
#define OPENTITAN_SW_DEVICE_LIB_DIF_DIF_RV_PLIC_H_
/**
* @file
* @brief <a href="/hw/ip/rv_plic/doc/">PLIC</a> Device Interface Functions
*
* The PLIC should be largely compatible with the (currently draft) [RISC-V PLIC
* specification][plic], but tailored for the OpenTitan rv_plic register
* addresses. We intend to make the addresses compatible with the PLIC
* specification in the near future.
*
* [plic]: https://github.com/riscv/riscv-plic-spec/blob/master/riscv-plic.adoc
*/
#include <stdbool.h>
#include <stdint.h>
#include "sw/device/lib/base/macros.h"
#include "sw/device/lib/base/mmio.h"
#include "sw/device/lib/dif/dif_base.h"
#include "sw/device/lib/dif/autogen/dif_rv_plic_autogen.h"
#ifdef __cplusplus
extern "C" {
#endif // __cplusplus
/**
* The lowest interrupt priority.
*/
extern const uint32_t kDifRvPlicMinPriority;
/**
* The highest interrupt priority.
*/
extern const uint32_t kDifRvPlicMaxPriority;
/**
* A PLIC interrupt source identifier.
*
* This corresponds to a specific interrupt, and not the device it originates
* from.
*
* This is an unsigned 32-bit value that is at least zero and is less than the
* `NumSrc` instantiation parameter of the `rv_plic` device.
*
* The value 0 corresponds to "No Interrupt".
*/
typedef uint32_t dif_rv_plic_irq_id_t;
/**
* A PLIC interrupt target.
*
* This corresponds to a specific system that can service an interrupt. In
* OpenTitan's case, that is the Ibex core. If there were multiple cores in the
* system, each core would have its own specific interrupt target ID.
*
* This is an unsigned 32-bit value that is at least 0 and is less than the
* `NumTarget` instantiation parameter of the `rv_plic` device.
*/
typedef uint32_t dif_rv_plic_target_t;
/**
* Resets the PLIC to a clean state.
*
*
* This function resets all the relevant PLIC registers, apart from the CC
* register. There is no reliable way of knowing the ID of an IRQ that has
* claimed the CC register, so we assume that the previous "owner" of the
* resource has cleared/completed the CC access.
*
* @param plic A PLIC handle.
* @return The result of the operation.
*/
OT_WARN_UNUSED_RESULT
dif_result_t dif_rv_plic_reset(const dif_rv_plic_t *plic);
/**
* Returns whether a particular interrupt is currently pending.
*
* @param plic A PLIC handle.
* @param irq An interrupt type.
* @param[out] is_pending Out-param for whether the interrupt is pending.
* @return The result of the operation.
*/
OT_WARN_UNUSED_RESULT
dif_result_t dif_rv_plic_irq_is_pending(const dif_rv_plic_t *plic,
dif_rv_plic_irq_id_t irq,
bool *is_pending);
/**
* Checks whether a particular interrupt is currently enabled or disabled.
*
* @param plic A PLIC handle.
* @param irq An interrupt type.
* @param target An interrupt target.
* @param[out] state Out-param toggle state of the interrupt.
* @return The result of the operation.
*/
OT_WARN_UNUSED_RESULT
dif_result_t dif_rv_plic_irq_get_enabled(const dif_rv_plic_t *plic,
dif_rv_plic_irq_id_t irq,
dif_rv_plic_target_t target,
dif_toggle_t *state);
/**
* Sets whether a particular interrupt is currently enabled or disabled.
*
* This operation does not affect IRQ generation in `target`, which
* must be configured in the corresponding peripheral itself.
*
* @param plic A PLIC handle.
* @param irq An interrupt type.
* @param target An interrupt target.
* @param state The new toggle state for the interrupt.
* @return The result of the operation.
*/
OT_WARN_UNUSED_RESULT
dif_result_t dif_rv_plic_irq_set_enabled(const dif_rv_plic_t *plic,
dif_rv_plic_irq_id_t irq,
dif_rv_plic_target_t target,
dif_toggle_t state);
/**
* Sets IRQ source priority (0-3).
*
* In order for the PLIC to set a Claim/Complete register and assert the
* external interrupt line to the target (Ibex, ...), the priority of the IRQ
* source must be higher than the threshold for this source.
*
* @param plic A PLIC handle.
* @param irq An interrupt type.
* @param priority Priority to set.
* @return The result of the operation.
*/
OT_WARN_UNUSED_RESULT
dif_result_t dif_rv_plic_irq_set_priority(const dif_rv_plic_t *plic,
dif_rv_plic_irq_id_t irq,
uint32_t priority);
/**
* Sets the target priority threshold.
*
* Sets the target priority threshold. PLIC will only interrupt a target when
* IRQ source priority is set higher than the priority threshold for the
* corresponding target.
*
* @param plic A PLIC handle.
* @param target Target to set the IRQ priority threshold for.
* @param threshold IRQ priority threshold to be set.
* @return The result of the operation.
*/
OT_WARN_UNUSED_RESULT
dif_result_t dif_rv_plic_target_set_threshold(const dif_rv_plic_t *plic,
dif_rv_plic_target_t target,
uint32_t threshold);
/**
* Claims an IRQ and gets the information about the source.
*
* Claims an IRQ and returns the IRQ related data to the caller. This function
* reads a target specific Claim/Complete register. #dif_rv_plic_irq_complete
* must be called in order to allow another interrupt with the same source id to
* be delivered. This usually would be done once the interrupt has been
* serviced.
*
* Another IRQ can be claimed before a prior IRQ is completed. In this way, this
* functionality is compatible with nested interrupt handling. The restriction
* is that you must Complete a Claimed IRQ before you will be able to claim an
* IRQ with the same ID. This allows a pair of Claim/Complete calls to be
* overlapped with another pair -- and there is no requirement that the
* interrupts should be Completed in the reverse order of when they were
* Claimed.
*
* @see #dif_rv_plic_irq_complete
*
* @param plic A PLIC handle.
* @param target Target that claimed the IRQ.
* @param[out] claim_data Data that describes the origin of the IRQ.
* @return The result of the operation.
*/
OT_WARN_UNUSED_RESULT
dif_result_t dif_rv_plic_irq_claim(const dif_rv_plic_t *plic,
dif_rv_plic_target_t target,
dif_rv_plic_irq_id_t *claim_data);
/**
* Completes the claimed IRQ.
*
* Finishes servicing of the claimed IRQ by writing the IRQ source ID back to a
* target specific Claim/Complete register. This function must be called after
* #dif_rv_plic_irq_claim, when the caller is prepared to service another IRQ
* with the same source ID. If a source ID is never Completed, then when future
* interrupts are Claimed, they will never have the source ID of the uncompleted
* IRQ.
*
* @see #dif_rv_plic_irq_claim
*
* @param plic A PLIC handle.
* @param target Target that claimed the IRQ.
* @param complete_data Previously claimed IRQ data that is used to signal
* PLIC of the IRQ servicing completion.
* @return The result of the operation.
*/
OT_WARN_UNUSED_RESULT
dif_result_t dif_rv_plic_irq_complete(const dif_rv_plic_t *plic,
dif_rv_plic_target_t target,
dif_rv_plic_irq_id_t complete_data);
/**
* Forces the software interrupt for a particular target.
*
* This function causes an interrupt to the `target` HART to be serviced as if
* hardware had asserted it.
*
* This function allows to synchronise between the HARTs, which otherwise
* would not be possible due to HART being only able to access own CSRs.
* NOTE: this is not an issue on Ibex, as it has only one HART.
*
* An interrupt handler is expected to call
* `dif_rv_plic_software_irq_acknowledge` when the interrupt has been handled.
*
* @param plic PLIC state data.
* @param target Target HART.
* @return `dif_result_t`.
*/
OT_WARN_UNUSED_RESULT
dif_result_t dif_rv_plic_software_irq_force(const dif_rv_plic_t *plic,
dif_rv_plic_target_t target);
/**
* Acknowledges the software interrupt for a particular target.
*
* This function indicates to the hardware that the software interrupt has been
* successfully serviced. It is expected to be called from a software interrupt
* handler.
*
* @param plic PLIC state data.
* @param target Target HART.
* @return `dif_result_t`.
*/
OT_WARN_UNUSED_RESULT
dif_result_t dif_rv_plic_software_irq_acknowledge(const dif_rv_plic_t *plic,
dif_rv_plic_target_t target);
/**
* Returns software interrupt pending state for a particular target.
*
* @param plic PLIC state data.
* @param target Target HART.
* @param[out] is_pending Flag indicating whether the interrupt is pending.
* @return `dif_result_t`.
*/
OT_WARN_UNUSED_RESULT
dif_result_t dif_rv_plic_software_irq_is_pending(const dif_rv_plic_t *plic,
dif_rv_plic_target_t target,
bool *is_pending);
#ifdef __cplusplus
} // extern "C"
#endif // __cplusplus
#endif // OPENTITAN_SW_DEVICE_LIB_DIF_DIF_RV_PLIC_H_