Line data Source code
1 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/__assert.h>
16 : #include <zephyr/sys/util_macro.h>
17 : #include <zephyr/types.h>
18 :
19 : #ifdef __cplusplus
20 : extern "C" {
21 : #endif
22 :
23 : #if defined(CONFIG_MULTI_LEVEL_INTERRUPTS) || defined(__DOXYGEN__)
24 :
25 : typedef union _z_irq {
26 : /* Zephyr multilevel-encoded IRQ */
27 : uint32_t irq;
28 :
29 : /* Interrupt bits */
30 : struct {
31 : /* First level interrupt bits */
32 : uint32_t l1: CONFIG_1ST_LEVEL_INTERRUPT_BITS;
33 : /* Second level interrupt bits */
34 : uint32_t l2: CONFIG_2ND_LEVEL_INTERRUPT_BITS;
35 : #if defined(CONFIG_3RD_LEVEL_INTERRUPTS) || defined(__DOXYGEN__)
36 : /* Third level interrupt bits */
37 : uint32_t l3: CONFIG_3RD_LEVEL_INTERRUPT_BITS;
38 : #endif /* CONFIG_3RD_LEVEL_INTERRUPTS */
39 : } bits;
40 :
41 : #if defined(CONFIG_3RD_LEVEL_INTERRUPTS) || defined(__DOXYGEN__)
42 : /* Third level IRQ's interrupt controller */
43 : struct {
44 : /* IRQ of the third level interrupt aggregator */
45 : uint32_t irq: CONFIG_1ST_LEVEL_INTERRUPT_BITS + CONFIG_2ND_LEVEL_INTERRUPT_BITS;
46 : } l3_intc;
47 : #endif /* CONFIG_3RD_LEVEL_INTERRUPTS */
48 :
49 : /* Second level IRQ's interrupt controller */
50 : struct {
51 : /* IRQ of the second level interrupt aggregator */
52 : uint32_t irq: CONFIG_1ST_LEVEL_INTERRUPT_BITS;
53 : } l2_intc;
54 : } _z_irq_t;
55 :
56 0 : BUILD_ASSERT(sizeof(_z_irq_t) == sizeof(uint32_t), "Size of `_z_irq_t` must equal to `uint32_t`");
57 :
58 : static inline uint32_t _z_l1_irq(_z_irq_t irq)
59 : {
60 : return irq.bits.l1;
61 : }
62 :
63 : static inline uint32_t _z_l2_irq(_z_irq_t irq)
64 : {
65 : return irq.bits.l2 - 1;
66 : }
67 :
68 : #ifdef CONFIG_3RD_LEVEL_INTERRUPTS
69 : static inline uint32_t _z_l3_irq(_z_irq_t irq)
70 : {
71 : return irq.bits.l3 - 1;
72 : }
73 : #endif /* CONFIG_3RD_LEVEL_INTERRUPTS */
74 :
75 : static inline unsigned int _z_irq_get_level(_z_irq_t z_irq)
76 : {
77 : #ifdef CONFIG_3RD_LEVEL_INTERRUPTS
78 : if (z_irq.bits.l3 != 0) {
79 : return 3;
80 : }
81 : #endif /* CONFIG_3RD_LEVEL_INTERRUPTS */
82 :
83 : if (z_irq.bits.l2 != 0) {
84 : return 2;
85 : }
86 :
87 : return 1;
88 : }
89 :
90 : /**
91 : * @brief Return IRQ level
92 : * This routine returns the interrupt level number of the provided interrupt.
93 : *
94 : * @param irq IRQ number in its zephyr format
95 : *
96 : * @return 1 if IRQ level 1, 2 if IRQ level 2, 3 if IRQ level 3
97 : */
98 1 : static inline unsigned int irq_get_level(unsigned int irq)
99 : {
100 : _z_irq_t z_irq = {
101 : .irq = irq,
102 : };
103 :
104 : return _z_irq_get_level(z_irq);
105 : }
106 :
107 : /**
108 : * @brief Return the 2nd level interrupt number
109 : *
110 : * This routine returns the second level irq number of the zephyr irq
111 : * number passed in
112 : *
113 : * @param irq IRQ number in its zephyr format
114 : *
115 : * @return 2nd level IRQ number
116 : */
117 1 : static inline unsigned int irq_from_level_2(unsigned int irq)
118 : {
119 : _z_irq_t z_irq = {
120 : .irq = irq,
121 : };
122 :
123 : return _z_l2_irq(z_irq);
124 : }
125 :
126 : /**
127 : * @brief Preprocessor macro to convert `irq` from level 1 to level 2 format
128 : *
129 : * @param irq IRQ number in its zephyr format
130 : *
131 : * @return 2nd level IRQ number
132 : */
133 1 : #define IRQ_TO_L2(irq) ((irq + 1) << CONFIG_1ST_LEVEL_INTERRUPT_BITS)
134 :
135 : /**
136 : * @brief Converts irq from level 1 to level 2 format
137 : *
138 : *
139 : * This routine converts the input into the level 2 irq number format
140 : *
141 : * @note Values >= 0xFF are invalid
142 : *
143 : * @param irq IRQ number in its zephyr format
144 : *
145 : * @return 2nd level IRQ number
146 : */
147 1 : static inline unsigned int irq_to_level_2(unsigned int irq)
148 : {
149 : _z_irq_t z_irq = {
150 : .bits = {
151 : .l1 = 0,
152 : .l2 = irq + 1,
153 : #ifdef CONFIG_3RD_LEVEL_INTERRUPTS
154 : .l3 = 0,
155 : #endif /* CONFIG_3RD_LEVEL_INTERRUPTS */
156 : },
157 : };
158 :
159 : return z_irq.irq;
160 : }
161 :
162 : /**
163 : * @brief Returns the parent IRQ of the level 2 raw IRQ number
164 : *
165 : *
166 : * The parent of a 2nd level interrupt is in the 1st byte
167 : *
168 : * @param irq IRQ number in its zephyr format
169 : *
170 : * @return 2nd level IRQ parent
171 : */
172 1 : static inline unsigned int irq_parent_level_2(unsigned int irq)
173 : {
174 : _z_irq_t z_irq = {
175 : .irq = irq,
176 : };
177 :
178 : return _z_l1_irq(z_irq);
179 : }
180 :
181 : #if defined(CONFIG_3RD_LEVEL_INTERRUPTS) || defined(__DOXYGEN__)
182 : /**
183 : * @brief Return the 3rd level interrupt number
184 : *
185 : *
186 : * This routine returns the third level irq number of the zephyr irq
187 : * number passed in
188 : *
189 : * @param irq IRQ number in its zephyr format
190 : *
191 : * @return 3rd level IRQ number
192 : */
193 1 : static inline unsigned int irq_from_level_3(unsigned int irq)
194 : {
195 : _z_irq_t z_irq = {
196 : .irq = irq,
197 : };
198 :
199 : return _z_l3_irq(z_irq);
200 : }
201 :
202 : /**
203 : * @brief Preprocessor macro to convert `irq` from level 1 to level 3 format
204 : *
205 : * @param irq IRQ number in its zephyr format
206 : *
207 : * @return 3rd level IRQ number
208 : */
209 1 : #define IRQ_TO_L3(irq) \
210 : ((irq + 1) << (CONFIG_1ST_LEVEL_INTERRUPT_BITS + CONFIG_2ND_LEVEL_INTERRUPT_BITS))
211 :
212 : /**
213 : * @brief Converts irq from level 1 to level 3 format
214 : *
215 : *
216 : * This routine converts the input into the level 3 irq number format
217 : *
218 : * @note Values >= 0xFF are invalid
219 : *
220 : * @param irq IRQ number in its zephyr format
221 : *
222 : * @return 3rd level IRQ number
223 : */
224 1 : static inline unsigned int irq_to_level_3(unsigned int irq)
225 : {
226 : _z_irq_t z_irq = {
227 : .bits = {
228 : .l1 = 0,
229 : .l2 = 0,
230 : .l3 = irq + 1,
231 : },
232 : };
233 :
234 : return z_irq.irq;
235 : }
236 :
237 : /**
238 : * @brief Returns the parent IRQ of the level 3 raw IRQ number
239 : *
240 : *
241 : * The parent of a 3rd level interrupt is in the 2nd byte
242 : *
243 : * @param irq IRQ number in its zephyr format
244 : *
245 : * @return 3rd level IRQ parent
246 : */
247 1 : static inline unsigned int irq_parent_level_3(unsigned int irq)
248 : {
249 : _z_irq_t z_irq = {
250 : .irq = irq,
251 : };
252 :
253 : return _z_l2_irq(z_irq);
254 : }
255 : #endif /* CONFIG_3RD_LEVEL_INTERRUPTS */
256 :
257 : /**
258 : * @brief Return the interrupt number for a given level
259 : *
260 : * @param irq IRQ number in its zephyr format
261 : * @param level IRQ level
262 : *
263 : * @return IRQ number in the level
264 : */
265 1 : static inline unsigned int irq_from_level(unsigned int irq, unsigned int level)
266 : {
267 : if (level == 1) {
268 : return irq;
269 : } else if (level == 2) {
270 : return irq_from_level_2(irq);
271 : }
272 : #ifdef CONFIG_3RD_LEVEL_INTERRUPTS
273 : else if (level == 3) {
274 : return irq_from_level_3(irq);
275 : }
276 : #endif /* CONFIG_3RD_LEVEL_INTERRUPTS */
277 :
278 : /* level is higher than what's supported */
279 : __ASSERT_NO_MSG(false);
280 : return irq;
281 : }
282 :
283 : /**
284 : * @brief Converts irq from level 1 to a given level
285 : *
286 : * @param irq IRQ number in its zephyr format
287 : * @param level IRQ level
288 : *
289 : * @return Converted IRQ number in the level
290 : */
291 1 : static inline unsigned int irq_to_level(unsigned int irq, unsigned int level)
292 : {
293 : if (level == 1) {
294 : return irq;
295 : } else if (level == 2) {
296 : return irq_to_level_2(irq);
297 : }
298 : #ifdef CONFIG_3RD_LEVEL_INTERRUPTS
299 : else if (level == 3) {
300 : return irq_to_level_3(irq);
301 : }
302 : #endif /* CONFIG_3RD_LEVEL_INTERRUPTS */
303 :
304 : /* level is higher than what's supported */
305 : __ASSERT_NO_MSG(false);
306 : return irq;
307 : }
308 :
309 : /**
310 : * @brief Returns the parent IRQ of the given level raw IRQ number
311 : *
312 : * @param irq IRQ number in its zephyr format
313 : * @param level IRQ level
314 : *
315 : * @return IRQ parent of the given level
316 : */
317 1 : static inline unsigned int irq_parent_level(unsigned int irq, unsigned int level)
318 : {
319 : if (level == 1) {
320 : /* doesn't really make sense, but return anyway */
321 : return irq;
322 : } else if (level == 2) {
323 : return irq_parent_level_2(irq);
324 : }
325 : #ifdef CONFIG_3RD_LEVEL_INTERRUPTS
326 : else if (level == 3) {
327 : return irq_parent_level_3(irq);
328 : }
329 : #endif /* CONFIG_3RD_LEVEL_INTERRUPTS */
330 :
331 : /* level is higher than what's supported */
332 : __ASSERT_NO_MSG(false);
333 : return irq;
334 : }
335 :
336 : /**
337 : * @brief Returns the parent interrupt controller IRQ of the given IRQ number
338 : *
339 : * @param irq IRQ number in its zephyr format
340 : *
341 : * @return IRQ of the interrupt controller
342 : */
343 1 : static inline unsigned int irq_get_intc_irq(unsigned int irq)
344 : {
345 : const unsigned int level = irq_get_level(irq);
346 : _z_irq_t z_irq = {
347 : .irq = irq,
348 : };
349 :
350 : #ifdef CONFIG_3RD_LEVEL_INTERRUPTS
351 : __ASSERT_NO_MSG(level <= 3);
352 : if (level == 3) {
353 : return z_irq.l3_intc.irq;
354 : }
355 : #else
356 : __ASSERT_NO_MSG(level <= 2);
357 : #endif /* CONFIG_3RD_LEVEL_INTERRUPTS */
358 :
359 : if (level == 2) {
360 : return z_irq.l2_intc.irq;
361 : }
362 :
363 : return irq;
364 : }
365 :
366 : /**
367 : * @brief Increments the multilevel-encoded @a irq by @a val
368 : *
369 : * @param irq IRQ number in its zephyr format
370 : * @param val Amount to increment
371 : *
372 : * @return @a irq incremented by @a val
373 : */
374 1 : static inline unsigned int irq_increment(unsigned int irq, unsigned int val)
375 : {
376 : _z_irq_t z_irq = {
377 : .irq = irq,
378 : };
379 :
380 : if (false) {
381 : /* so that it evaluates the next condition */
382 : #ifdef CONFIG_3RD_LEVEL_INTERRUPTS
383 : } else if (z_irq.bits.l3 != 0) {
384 : z_irq.bits.l3 += val;
385 : #endif /* CONFIG_3RD_LEVEL_INTERRUPTS */
386 : } else if (z_irq.bits.l2 != 0) {
387 : z_irq.bits.l2 += val;
388 : } else {
389 : z_irq.bits.l1 += val;
390 : }
391 :
392 : return z_irq.irq;
393 : }
394 :
395 : #endif /* CONFIG_MULTI_LEVEL_INTERRUPTS */
396 : #ifdef __cplusplus
397 : }
398 : #endif
399 :
400 : #endif /* _ASMLANGUAGE */
401 : #endif /* ZEPHYR_INCLUDE_IRQ_MULTILEVEL_H_ */
|