1 /*
2  * Copyright (c) 2023 Meta
3  *
4  * SPDX-License-Identifier: Apache-2.0
5  */
6 
7 /**
8  * @file
9  * @brief Public interface for multi-level interrupts
10  */
11 #ifndef ZEPHYR_INCLUDE_IRQ_MULTILEVEL_H_
12 #define ZEPHYR_INCLUDE_IRQ_MULTILEVEL_H_
13 
14 #ifndef _ASMLANGUAGE
15 #include <zephyr/sys/util_macro.h>
16 #include <zephyr/types.h>
17 
18 #ifdef __cplusplus
19 extern "C" {
20 #endif
21 
22 #if defined(CONFIG_MULTI_LEVEL_INTERRUPTS) || defined(__DOXYGEN__)
23 /**
24  * @brief Return IRQ level
25  * This routine returns the interrupt level number of the provided interrupt.
26  *
27  * @param irq IRQ number in its zephyr format
28  *
29  * @return 1 if IRQ level 1, 2 if IRQ level 2, 3 if IRQ level 3
30  */
irq_get_level(unsigned int irq)31 static inline unsigned int irq_get_level(unsigned int irq)
32 {
33 	const uint32_t mask2 = BIT_MASK(CONFIG_2ND_LEVEL_INTERRUPT_BITS) <<
34 		CONFIG_1ST_LEVEL_INTERRUPT_BITS;
35 	const uint32_t mask3 = BIT_MASK(CONFIG_3RD_LEVEL_INTERRUPT_BITS) <<
36 		(CONFIG_1ST_LEVEL_INTERRUPT_BITS + CONFIG_2ND_LEVEL_INTERRUPT_BITS);
37 
38 	if (IS_ENABLED(CONFIG_3RD_LEVEL_INTERRUPTS) && (irq & mask3) != 0) {
39 		return 3;
40 	}
41 
42 	if (IS_ENABLED(CONFIG_2ND_LEVEL_INTERRUPTS) && (irq & mask2) != 0) {
43 		return 2;
44 	}
45 
46 	return 1;
47 }
48 
49 /**
50  * @brief Return the 2nd level interrupt number
51  *
52  * This routine returns the second level irq number of the zephyr irq
53  * number passed in
54  *
55  * @param irq IRQ number in its zephyr format
56  *
57  * @return 2nd level IRQ number
58  */
irq_from_level_2(unsigned int irq)59 static inline unsigned int irq_from_level_2(unsigned int irq)
60 {
61 	if (IS_ENABLED(CONFIG_3RD_LEVEL_INTERRUPTS)) {
62 		return ((irq >> CONFIG_1ST_LEVEL_INTERRUPT_BITS) &
63 			BIT_MASK(CONFIG_2ND_LEVEL_INTERRUPT_BITS)) - 1;
64 	} else {
65 		return (irq >> CONFIG_1ST_LEVEL_INTERRUPT_BITS) - 1;
66 	}
67 }
68 
69 /**
70  * @brief Preprocessor macro to convert `irq` from level 1 to level 2 format
71  *
72  * @param irq IRQ number in its zephyr format
73  *
74  * @return 2nd level IRQ number
75  */
76 #define IRQ_TO_L2(irq) ((irq + 1) << CONFIG_1ST_LEVEL_INTERRUPT_BITS)
77 
78 /**
79  * @brief Converts irq from level 1 to level 2 format
80  *
81  *
82  * This routine converts the input into the level 2 irq number format
83  *
84  * @note Values >= 0xFF are invalid
85  *
86  * @param irq IRQ number in its zephyr format
87  *
88  * @return 2nd level IRQ number
89  */
irq_to_level_2(unsigned int irq)90 static inline unsigned int irq_to_level_2(unsigned int irq)
91 {
92 	return IRQ_TO_L2(irq);
93 }
94 
95 /**
96  * @brief Returns the parent IRQ of the level 2 raw IRQ number
97  *
98  *
99  * The parent of a 2nd level interrupt is in the 1st byte
100  *
101  * @param irq IRQ number in its zephyr format
102  *
103  * @return 2nd level IRQ parent
104  */
irq_parent_level_2(unsigned int irq)105 static inline unsigned int irq_parent_level_2(unsigned int irq)
106 {
107 	return irq & BIT_MASK(CONFIG_1ST_LEVEL_INTERRUPT_BITS);
108 }
109 
110 /**
111  * @brief Return the 3rd level interrupt number
112  *
113  *
114  * This routine returns the third level irq number of the zephyr irq
115  * number passed in
116  *
117  * @param irq IRQ number in its zephyr format
118  *
119  * @return 3rd level IRQ number
120  */
irq_from_level_3(unsigned int irq)121 static inline unsigned int irq_from_level_3(unsigned int irq)
122 {
123 	return (irq >> (CONFIG_1ST_LEVEL_INTERRUPT_BITS + CONFIG_2ND_LEVEL_INTERRUPT_BITS)) - 1;
124 }
125 
126 /**
127  * @brief Preprocessor macro to convert `irq` from level 1 to level 3 format
128  *
129  * @param irq IRQ number in its zephyr format
130  *
131  * @return 3rd level IRQ number
132  */
133 #define IRQ_TO_L3(irq)                                                                             \
134 	((irq + 1) << (CONFIG_1ST_LEVEL_INTERRUPT_BITS + CONFIG_2ND_LEVEL_INTERRUPT_BITS))
135 
136 /**
137  * @brief Converts irq from level 1 to level 3 format
138  *
139  *
140  * This routine converts the input into the level 3 irq number format
141  *
142  * @note Values >= 0xFF are invalid
143  *
144  * @param irq IRQ number in its zephyr format
145  *
146  * @return 3rd level IRQ number
147  */
irq_to_level_3(unsigned int irq)148 static inline unsigned int irq_to_level_3(unsigned int irq)
149 {
150 	return IRQ_TO_L3(irq);
151 }
152 
153 /**
154  * @brief Returns the parent IRQ of the level 3 raw IRQ number
155  *
156  *
157  * The parent of a 3rd level interrupt is in the 2nd byte
158  *
159  * @param irq IRQ number in its zephyr format
160  *
161  * @return 3rd level IRQ parent
162  */
irq_parent_level_3(unsigned int irq)163 static inline unsigned int irq_parent_level_3(unsigned int irq)
164 {
165 	return (irq >> CONFIG_1ST_LEVEL_INTERRUPT_BITS) &
166 		BIT_MASK(CONFIG_2ND_LEVEL_INTERRUPT_BITS);
167 }
168 
169 #endif /* CONFIG_MULTI_LEVEL_INTERRUPTS */
170 #ifdef __cplusplus
171 }
172 #endif
173 
174 #endif /* _ASMLANGUAGE */
175 #endif /* ZEPHYR_INCLUDE_IRQ_MULTILEVEL_H_ */
176