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 BUILD_ASSERT(sizeof(_z_irq_t) == sizeof(uint32_t), "Size of `_z_irq_t` must equal to `uint32_t`");
57 
_z_l1_irq(_z_irq_t irq)58 static inline uint32_t _z_l1_irq(_z_irq_t irq)
59 {
60 	return irq.bits.l1;
61 }
62 
_z_l2_irq(_z_irq_t irq)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
_z_l3_irq(_z_irq_t irq)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 
_z_irq_get_level(_z_irq_t z_irq)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  */
irq_get_level(unsigned int irq)98 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  */
irq_from_level_2(unsigned int irq)117 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 #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  */
irq_to_level_2(unsigned int irq)147 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  */
irq_parent_level_2(unsigned int irq)172 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  */
irq_from_level_3(unsigned int irq)193 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 #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  */
irq_to_level_3(unsigned int irq)224 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  */
irq_parent_level_3(unsigned int irq)247 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  */
irq_from_level(unsigned int irq,unsigned int level)265 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  */
irq_to_level(unsigned int irq,unsigned int level)291 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  */
irq_parent_level(unsigned int irq,unsigned int level)317 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  */
irq_get_intc_irq(unsigned int irq)343 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  */
irq_increment(unsigned int irq,unsigned int val)374 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_ */
402