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