1 /***************************************************************************//**
2  * @file
3  * @brief Interrupt Management API to enable and configure interrupts.
4  *******************************************************************************
5  * # License
6  * <b>Copyright 2023 Silicon Laboratories Inc. www.silabs.com</b>
7  *******************************************************************************
8  *
9  * SPDX-License-Identifier: Zlib
10  *
11  * The licensor of this software is Silicon Laboratories Inc.
12  *
13  * This software is provided 'as-is', without any express or implied
14  * warranty. In no event will the authors be held liable for any damages
15  * arising from the use of this software.
16  *
17  * Permission is granted to anyone to use this software for any purpose,
18  * including commercial applications, and to alter it and redistribute it
19  * freely, subject to the following restrictions:
20  *
21  * 1. The origin of this software must not be misrepresented; you must not
22  *    claim that you wrote the original software. If you use this software
23  *    in a product, an acknowledgment in the product documentation would be
24  *    appreciated but is not required.
25  * 2. Altered source versions must be plainly marked as such, and must not be
26  *    misrepresented as being the original software.
27  * 3. This notice may not be removed or altered from any source distribution.
28  *
29  ******************************************************************************/
30 
31 #ifndef SL_INTERRUPT_MANAGER_H
32 #define SL_INTERRUPT_MANAGER_H
33 
34 #include <stdint.h>
35 #include <stdbool.h>
36 #include "sl_core.h"
37 #include "sl_status.h"
38 
39 #ifdef __cplusplus
40 extern "C" {
41 #endif
42 
43 /***************************************************************************//**
44  * @addtogroup interrupt_manager Interrupt Manager
45  * @brief Interrupt management service can be used for general interrupt management.
46  * The source files for Interrupt Manager platform software module are present under
47  * platform/services/interrupt_manager.
48  * @details
49  * ## Overview
50  * The Interrupt Manager is a service that offers interupt management functions and configurations
51  * for setting the interrupt vector in RAM, managing the core reset initiation function and
52  * doing general interrupt management operations.
53  *
54  * ## Configuration Options
55  *
56  * Some properties of the Interrupt Manager are compile-time configurable. These
57  * properties are set in the sl_interrupt_manager_s2_config.h file.
58  * These are the available configuration parameters with default values defined.
59  * @code
60  *
61  * // <q SL_INTERRUPT_MANAGER_S2_INTERRUPTS_IN_RAM> Put the interrupt vector table in RAM.
62  * // <i> Set to 1 to put the vector table in RAM.
63  * // <i> Default: 0
64  * #define SL_INTERRUPT_MANAGER_S2_INTERRUPTS_IN_RAM  0
65  * @endcode
66  *
67  * @note The SL_INTERRUPT_MANAGER_S2_INTERRUPTS_IN_RAM configuration is only available
68  * on series 2. Enabling the S2_INTERRUPTS_IN_RAM configuration will tell the Interrupt Manager
69  * to copy the interrupt vector table from ROM to RAM and select it as the interrupt table.
70  * On newer series this feature is always enabled.
71  *
72  * ## The API
73  *
74  * This section contains brief descriptions of the functions in the API. For more
75  * information on input and output parameters and return values,
76  * click on the hyperlinked function names.
77  *
78  * @ref sl_interrupt_manager_disable_interrupts and @ref sl_interrupt_manager_enable_interrupts()
79  * are used to prevent interrupts from executing during a certain timelapse.
80  *
81  * @ref sl_interrupt_manager_is_irq_disabled, @ref sl_interrupt_manager_is_irq_blocked
82  * are used to know the status of an interrupt, either if it's disabled or blocked by one of the
83  * following reasons: priority masking, disabling or an active interrupt of higher priority
84  * is executing.
85  *
86  * @ref sl_interrupt_manager_is_irq_pending, @ref sl_interrupt_manager_set_irq_pending and
87  * @ref sl_interrupt_manager_clear_irq_pending
88  * are used for control and query of external interrupt source pending status.
89  *
90  * @ref sl_interrupt_manager_get_irq_priority and @ref sl_interrupt_manager_set_irq_priority
91  * are used to get or set the priority for a specific interrupt.
92  *
93  * ## Priority Stratification
94  * With the Interrupt Manager service and more generally in the Simplicity SDK, there are multiple distinct
95  * levels of priority stratification.
96  *
97  * Each of these has their own characteristics and purposes.
98  * For example, the higher priority group is considered to not be able to call kernel, power manager
99  * or protocol stacks functions. They will only be impacted by critical sections (general interrupt
100  * disable) but will be above atomic base interrupt priority level for execution. The higher level
101  * is considered to be between 0 and 2 and the base interrupt priority level is 3.
102  *
103  * In the normal priority group you will find most application interrupts and such interrupts will be
104  * the ones that will make calls to more features such as kernel, power manager and protocol stacks API.
105  * It is this way because they are less deterministic than the "higher priority interrupts".
106  *
107  * <table>
108  * <caption id="interrupt_priority_strat">Priority stratification inside SDK</caption>
109  * <tr><th>Priority<th>Purpose
110  * <tr><td>0 - 2 (Highest)<td>
111  * <ul>
112  *     <li>No Kernel calls
113  *     <li>No Power Manager calls
114  *      <li>Not maskable by atomic sections
115  * </ul>
116  * <tr><td>3 - 7 (Normal)<td>
117  * <ul>
118  *     <li>kernel calls
119  *     <li>power manager
120  *      <li>protocol stacks API
121  * </ul>
122  * <tr><td>7 (Lowest)<td>
123  * <ul>
124  *     <li>PendSV level of priority
125  * </ul>
126  * </table>
127  * @{
128  ******************************************************************************/
129 
130 /// @brief sl_interrupt_manager interrupt handler function.
131 typedef void(*sl_interrupt_manager_irq_handler_t)(void);
132 
133 /***************************************************************************//**
134  * @brief
135  *   Initialize interrupt controller hardware and initialise vector table
136  *   in RAM.
137  *
138  * @note
139  *   The interrupt manager init function will perform the initialization only
140  *   once even if it's called multiple times.
141  ******************************************************************************/
142 void sl_interrupt_manager_init(void);
143 
144 /***************************************************************************//**
145  * @brief
146  *   Reset the cpu core.
147  ******************************************************************************/
148 void sl_interrupt_manager_reset_system(void);
149 
150 /***************************************************************************//**
151  * @brief
152  *   Disable interrupts.
153  ******************************************************************************/
154 void sl_interrupt_manager_disable_interrupts(void);
155 
156 /***************************************************************************//**
157  * @brief
158  *   Enable interrupts.
159  ******************************************************************************/
160 void sl_interrupt_manager_enable_interrupts(void);
161 
162 /***************************************************************************//**
163  * @brief
164  *   Disable interrupt for an interrupt source.
165  *
166  * @param[in] irqn
167  *   The interrupt number of the interrupt source.
168  ******************************************************************************/
169 void sl_interrupt_manager_disable_irq(int32_t irqn);
170 
171 /***************************************************************************//**
172  * @brief
173  *   Enable interrupt for an interrupt source.
174  *
175  * @param[in] irqn
176  *   The interrupt number of the interrupt source.
177  ******************************************************************************/
178 void sl_interrupt_manager_enable_irq(int32_t irqn);
179 
180 /***************************************************************************//**
181  * @brief
182  *   Check if an interrupt is disabled.
183  *
184  * @param[in] irqn
185  *   The interrupt number of the interrupt source.
186  *
187  * @return
188  *   True if the interrupt is disabled.
189  ******************************************************************************/
190 bool sl_interrupt_manager_is_irq_disabled(int32_t irqn);
191 
192 /***************************************************************************//**
193  * @brief
194  *   Check if a specific interrupt is blocked.
195  *
196  * @note
197  *   The function return true if the IRQ is disabled.
198  *
199  * @param[in] irqn
200  *   The interrupt number of the interrupt source.
201  *
202  * @return
203  *   True if the interrupt is disabled or blocked.
204  ******************************************************************************/
205 bool sl_interrupt_manager_is_irq_blocked(int32_t irqn);
206 
207 /***************************************************************************//**
208  * @brief
209  *   Get Pending Interrupt
210  *
211  * @note
212  *   Read the pending status of a specified interrupt and returns it status.
213  *
214  * @param[in] irqn
215  *   The interrupt number of the interrupt source.
216  *
217  * @return
218  *   false  Interrupt status is not pending.
219  *   true   Interrupt status is pending.
220  ******************************************************************************/
221 bool sl_interrupt_manager_is_irq_pending(int32_t irqn);
222 
223 /***************************************************************************//**
224  * @brief
225  *   Set interrupt status to pending.
226  *
227  * @note
228  *   Sets an interrupt pending status to true.
229  *
230  * @param[in] irqn
231  *   The interrupt number of the interrupt source.
232  ******************************************************************************/
233 void sl_interrupt_manager_set_irq_pending(int32_t irqn);
234 
235 /***************************************************************************//**
236 *  @brief
237 *    Clear Pending Interrupt
238 *
239 *  @details
240 *   Clear an interrupt pending status
241 *
242 * @param[in] irqn
243 *   The interrupt number of the interrupt source.
244 *
245 *  @note
246 *   irqn must not be negative.
247 *******************************************************************************/
248 void sl_interrupt_manager_clear_irq_pending(int32_t irqn);
249 
250 /***************************************************************************//**
251  * @brief
252  *   Set the interrupt handler of an interrupt source.
253  *
254  * @note
255  *   This function depends on a RAM based interrupt vector table, i.e.
256  *   SL_INTERRUPT_MANAGER_S2_INTERRUPTS_IN_RAM must be true. Or the device
257  *   must be Series 3.
258  *
259  * @param[in] irqn
260  *   The interrupt number of the interrupt source.
261  *
262  * @param[in] handler
263  *   The new interrupt handler for the interrupt source.
264  *
265  * @return
266  *   The prior interrupt handler for the interrupt source.
267  ******************************************************************************/
268 sl_status_t sl_interrupt_manager_set_irq_handler(int32_t irqn,
269                                                  sl_interrupt_manager_irq_handler_t handler);
270 
271 /***************************************************************************//**
272  * @brief
273  *   Get the interrupt preemption priority of an interrupt source.
274  *
275  * @note
276  *   The number of priority levels is platform dependent.
277  *
278  * @param[in] irqn
279  *   The interrupt number of the interrupt source.
280  *
281  * @return
282  *   The interrupt priority for the interrupt source.
283  *   Value 0 denotes the highest priority.
284  ******************************************************************************/
285 uint32_t sl_interrupt_manager_get_irq_priority(int32_t irqn);
286 
287 /***************************************************************************//**
288  * @brief
289  *   Set the interrupt preemption priority of an interrupt source.
290  *
291  * @note
292  *   The number of priority levels is platform dependent.
293  *
294  * @param[in] irqn
295  *   The interrupt number of the interrupt source.
296  *
297  * @param[in] priority
298  *   The new interrupt priority for the interrupt source.
299  *   Value 0 denotes the highest priority.
300  ******************************************************************************/
301 void sl_interrupt_manager_set_irq_priority(int32_t irqn, uint32_t priority);
302 
303 /***************************************************************************//**
304  * @brief
305  *   Increase the interrupt preemption priority of an interrupt source.
306  *   relative to the default priority.
307  *
308  * @details
309  *   This function is useful to be architecture agnostic with priority values.
310  *
311  *   Usage:
312  *   new_prio = sl_interrupt_manager_increase_irq_priority_from_default(IRQn, 1);
313  *
314  *   This will increase the priority of IRQn by 1.
315  *
316  * @param[in] irqn
317  *   The irq to change the priority.
318  *
319  * @param[in] diff
320  *   The relative difference.
321  ******************************************************************************/
322 void sl_interrupt_manager_increase_irq_priority_from_default(int32_t irqn, uint32_t diff);
323 
324 /***************************************************************************//**
325  * @brief
326  *   Decrease the interrupt preemption priority of an interrupt source
327  *   relative to the default priority.
328  *
329  * @details
330  *   This function is useful to be architecture agnostic with priority values.
331  *
332  *   Usage:
333  *   new_prio = sl_interrupt_manager_decrease_irq_priority_from_default(IRQn, 1);
334  *
335  *   This will decrease the priority of IRQn by 1.
336  *
337  * @param[in] irqn
338  *   The irq to change the priority.
339  *
340  * @param[in] diff
341  *   The relative difference.
342  ******************************************************************************/
343 void sl_interrupt_manager_decrease_irq_priority_from_default(int32_t irqn, uint32_t diff);
344 
345 /***************************************************************************//**
346  * @brief
347  *   Get the default interrupt preemption priority value.
348  *
349  * @return
350  *   The default priority.
351  ******************************************************************************/
352 uint32_t sl_interrupt_manager_get_default_priority(void);
353 
354 /***************************************************************************//**
355  * @brief
356  *   Get the highest interrupt preemption priority value.
357  *
358  * @return
359  *   The highest priority value.
360  ******************************************************************************/
361 uint32_t sl_interrupt_manager_get_highest_priority(void);
362 
363 /***************************************************************************//**
364  * @brief
365  *   Get the lowest interrupt preemption priority value.
366  *
367  * @return
368  *   The lowest priority value.
369  ******************************************************************************/
370 uint32_t sl_interrupt_manager_get_lowest_priority(void);
371 
372 /***************************************************************************//**
373  * @brief
374  *   Get the interrupt active status.
375  *
376  * @param[in] irqn
377  *   The interrupt number of the interrupt source.
378  *
379  * @return
380  *   The interrupt active status.
381  ******************************************************************************/
382 uint32_t sl_interrupt_manager_get_active_irq(int32_t irqn);
383 
384 /***************************************************************************//**
385  * @brief
386  *   Get the current ISR table.
387  *
388  * @details
389  *   Depending on the configuration of the Interrupt Manager, this table of
390  *   ISRs may be in RAM or in FLASH, and each ISR may or may not be wrapped by
391  *   enter/exit hooks.
392  *
393  * @return
394  *   The current ISR table.
395  ******************************************************************************/
396 sl_interrupt_manager_irq_handler_t* sl_interrupt_manager_get_isr_table(void);
397 
398 /** @} (end addtogroup interrupt_manager) */
399 
400 #ifdef __cplusplus
401 }
402 #endif
403 
404 #endif /* SL_INTERRUPT_MANAGER_H */
405