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 : /* 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 0 : BUILD_ASSERT(sizeof(_z_irq_t) == sizeof(uint32_t), "Size of `_z_irq_t` must equal to `uint32_t`"); 53 : 54 : static inline uint32_t _z_l1_irq(_z_irq_t irq) 55 : { 56 : return irq.bits.l1; 57 : } 58 : 59 : static inline uint32_t _z_l2_irq(_z_irq_t irq) 60 : { 61 : return irq.bits.l2 - 1; 62 : } 63 : 64 : static inline uint32_t _z_l3_irq(_z_irq_t irq) 65 : { 66 : return irq.bits.l3 - 1; 67 : } 68 : 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 : */ 90 1 : 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 : */ 109 1 : 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 1 : #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 : */ 139 1 : 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 : */ 162 1 : 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 : */ 182 1 : 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 1 : #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 : */ 213 1 : 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 : */ 236 1 : 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 : */ 253 1 : 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 : */ 276 1 : 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 : */ 299 1 : 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 : */ 322 1 : 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 : */ 348 1 : 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_ */