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