Software APIs
dif_rv_plic.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_PLIC_H_
6 #define OPENTITAN_SW_DEVICE_LIB_DIF_DIF_RV_PLIC_H_
7 
8 /**
9  * @file
10  * @brief <a href="/hw/ip/rv_plic/doc/">PLIC</a> Device Interface Functions
11  *
12  * The PLIC should be largely compatible with the (currently draft) [RISC-V PLIC
13  * specification][plic], but tailored for the OpenTitan rv_plic register
14  * addresses. We intend to make the addresses compatible with the PLIC
15  * specification in the near future.
16  *
17  * [plic]: https://github.com/riscv/riscv-plic-spec/blob/master/riscv-plic.adoc
18  */
19 
20 #include <stdbool.h>
21 #include <stdint.h>
22 
23 #include "dt/dt_api.h" // Generated
27 
28 #include "sw/device/lib/dif/autogen/dif_rv_plic_autogen.h"
29 
30 #ifdef __cplusplus
31 extern "C" {
32 #endif // __cplusplus
33 
34 /**
35  * The lowest interrupt priority.
36  */
37 extern const uint32_t kDifRvPlicMinPriority;
38 
39 /**
40  * The highest interrupt priority.
41  */
42 extern const uint32_t kDifRvPlicMaxPriority;
43 
44 /**
45  * A PLIC interrupt source identifier.
46  *
47  * This corresponds to a specific interrupt, and not the device it originates
48  * from.
49  *
50  * This is an unsigned 32-bit value that is at least zero and is less than the
51  * `NumSrc` instantiation parameter of the `rv_plic` device.
52  *
53  * The value 0 corresponds to "No Interrupt".
54  */
55 typedef dt_plic_irq_id_t dif_rv_plic_irq_id_t;
56 
57 /**
58  * A PLIC interrupt target.
59  *
60  * This corresponds to a specific system that can service an interrupt. In
61  * OpenTitan's case, that is the Ibex core. If there were multiple cores in the
62  * system, each core would have its own specific interrupt target ID.
63  *
64  * This is an unsigned 32-bit value that is at least 0 and is less than the
65  * `NumTarget` instantiation parameter of the `rv_plic` device.
66  */
67 typedef uint32_t dif_rv_plic_target_t;
68 
69 /**
70  * Resets the PLIC to a clean state.
71  *
72  *
73  * This function resets all the relevant PLIC registers, apart from the CC
74  * register. There is no reliable way of knowing the ID of an IRQ that has
75  * claimed the CC register, so we assume that the previous "owner" of the
76  * resource has cleared/completed the CC access.
77  *
78  * @param plic A PLIC handle.
79  * @return The result of the operation.
80  */
82 dif_result_t dif_rv_plic_reset(const dif_rv_plic_t *plic);
83 
84 /**
85  * Returns whether a particular interrupt is currently pending.
86  *
87  * @param plic A PLIC handle.
88  * @param irq An interrupt type.
89  * @param[out] is_pending Out-param for whether the interrupt is pending.
90  * @return The result of the operation.
91  */
93 dif_result_t dif_rv_plic_irq_is_pending(const dif_rv_plic_t *plic,
95  bool *is_pending);
96 
97 /**
98  * Checks whether a particular interrupt is currently enabled or disabled.
99  *
100  * @param plic A PLIC handle.
101  * @param irq An interrupt type.
102  * @param target An interrupt target.
103  * @param[out] state Out-param toggle state of the interrupt.
104  * @return The result of the operation.
105  */
107 dif_result_t dif_rv_plic_irq_get_enabled(const dif_rv_plic_t *plic,
109  dif_rv_plic_target_t target,
110  dif_toggle_t *state);
111 
112 /**
113  * Sets whether a particular interrupt is currently enabled or disabled.
114  *
115  * This operation does not affect IRQ generation in `target`, which
116  * must be configured in the corresponding peripheral itself.
117  *
118  * @param plic A PLIC handle.
119  * @param irq An interrupt type.
120  * @param target An interrupt target.
121  * @param state The new toggle state for the interrupt.
122  * @return The result of the operation.
123  */
125 dif_result_t dif_rv_plic_irq_set_enabled(const dif_rv_plic_t *plic,
127  dif_rv_plic_target_t target,
128  dif_toggle_t state);
129 
130 /**
131  * Sets IRQ source priority (0-3).
132  *
133  * In order for the PLIC to set a Claim/Complete register and assert the
134  * external interrupt line to the target (Ibex, ...), the priority of the IRQ
135  * source must be higher than the threshold for this source.
136  *
137  * @param plic A PLIC handle.
138  * @param irq An interrupt type.
139  * @param priority Priority to set.
140  * @return The result of the operation.
141  */
143 dif_result_t dif_rv_plic_irq_set_priority(const dif_rv_plic_t *plic,
145  uint32_t priority);
146 
147 /**
148  * Sets the target priority threshold.
149  *
150  * Sets the target priority threshold. PLIC will only interrupt a target when
151  * IRQ source priority is set higher than the priority threshold for the
152  * corresponding target.
153  *
154  * @param plic A PLIC handle.
155  * @param target Target to set the IRQ priority threshold for.
156  * @param threshold IRQ priority threshold to be set.
157  * @return The result of the operation.
158  */
160 dif_result_t dif_rv_plic_target_set_threshold(const dif_rv_plic_t *plic,
161  dif_rv_plic_target_t target,
162  uint32_t threshold);
163 
164 /**
165  * Claims an IRQ and gets the information about the source.
166  *
167  * Claims an IRQ and returns the IRQ related data to the caller. This function
168  * reads a target specific Claim/Complete register. #dif_rv_plic_irq_complete
169  * must be called in order to allow another interrupt with the same source id to
170  * be delivered. This usually would be done once the interrupt has been
171  * serviced.
172  *
173  * Another IRQ can be claimed before a prior IRQ is completed. In this way, this
174  * functionality is compatible with nested interrupt handling. The restriction
175  * is that you must Complete a Claimed IRQ before you will be able to claim an
176  * IRQ with the same ID. This allows a pair of Claim/Complete calls to be
177  * overlapped with another pair -- and there is no requirement that the
178  * interrupts should be Completed in the reverse order of when they were
179  * Claimed.
180  *
181  * @see #dif_rv_plic_irq_complete
182  *
183  * @param plic A PLIC handle.
184  * @param target Target that claimed the IRQ.
185  * @param[out] claim_data Data that describes the origin of the IRQ.
186  * @return The result of the operation.
187  */
189 dif_result_t dif_rv_plic_irq_claim(const dif_rv_plic_t *plic,
190  dif_rv_plic_target_t target,
191  dif_rv_plic_irq_id_t *claim_data);
192 
193 /**
194  * Completes the claimed IRQ.
195  *
196  * Finishes servicing of the claimed IRQ by writing the IRQ source ID back to a
197  * target specific Claim/Complete register. This function must be called after
198  * #dif_rv_plic_irq_claim, when the caller is prepared to service another IRQ
199  * with the same source ID. If a source ID is never Completed, then when future
200  * interrupts are Claimed, they will never have the source ID of the uncompleted
201  * IRQ.
202  *
203  * @see #dif_rv_plic_irq_claim
204  *
205  * @param plic A PLIC handle.
206  * @param target Target that claimed the IRQ.
207  * @param complete_data Previously claimed IRQ data that is used to signal
208  * PLIC of the IRQ servicing completion.
209  * @return The result of the operation.
210  */
212 dif_result_t dif_rv_plic_irq_complete(const dif_rv_plic_t *plic,
213  dif_rv_plic_target_t target,
214  dif_rv_plic_irq_id_t complete_data);
215 
216 /**
217  * Forces the software interrupt for a particular target.
218  *
219  * This function causes an interrupt to the `target` HART to be serviced as if
220  * hardware had asserted it.
221  *
222  * This function allows to synchronise between the HARTs, which otherwise
223  * would not be possible due to HART being only able to access own CSRs.
224  * NOTE: this is not an issue on Ibex, as it has only one HART.
225  *
226  * An interrupt handler is expected to call
227  * `dif_rv_plic_software_irq_acknowledge` when the interrupt has been handled.
228  *
229  * @param plic PLIC state data.
230  * @param target Target HART.
231  * @return `dif_result_t`.
232  */
234 dif_result_t dif_rv_plic_software_irq_force(const dif_rv_plic_t *plic,
235  dif_rv_plic_target_t target);
236 
237 /**
238  * Acknowledges the software interrupt for a particular target.
239  *
240  * This function indicates to the hardware that the software interrupt has been
241  * successfully serviced. It is expected to be called from a software interrupt
242  * handler.
243  *
244  * @param plic PLIC state data.
245  * @param target Target HART.
246  * @return `dif_result_t`.
247  */
249 dif_result_t dif_rv_plic_software_irq_acknowledge(const dif_rv_plic_t *plic,
250  dif_rv_plic_target_t target);
251 
252 /**
253  * Returns software interrupt pending state for a particular target.
254  *
255  * @param plic PLIC state data.
256  * @param target Target HART.
257  * @param[out] is_pending Flag indicating whether the interrupt is pending.
258  * @return `dif_result_t`.
259  */
261 dif_result_t dif_rv_plic_software_irq_is_pending(const dif_rv_plic_t *plic,
262  dif_rv_plic_target_t target,
263  bool *is_pending);
264 
265 #ifdef __cplusplus
266 } // extern "C"
267 #endif // __cplusplus
268 
269 #endif // OPENTITAN_SW_DEVICE_LIB_DIF_DIF_RV_PLIC_H_