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 * @brief Return IRQ level 26 * This routine returns the interrupt level number of the provided interrupt. 27 * 28 * @param irq IRQ number in its zephyr format 29 * 30 * @return 1 if IRQ level 1, 2 if IRQ level 2, 3 if IRQ level 3 31 */ irq_get_level(unsigned int irq)32static inline unsigned int irq_get_level(unsigned int irq) 33 { 34 const uint32_t mask2 = BIT_MASK(CONFIG_2ND_LEVEL_INTERRUPT_BITS) << 35 CONFIG_1ST_LEVEL_INTERRUPT_BITS; 36 const uint32_t mask3 = BIT_MASK(CONFIG_3RD_LEVEL_INTERRUPT_BITS) << 37 (CONFIG_1ST_LEVEL_INTERRUPT_BITS + CONFIG_2ND_LEVEL_INTERRUPT_BITS); 38 39 if (IS_ENABLED(CONFIG_3RD_LEVEL_INTERRUPTS) && (irq & mask3) != 0) { 40 return 3; 41 } 42 43 if (IS_ENABLED(CONFIG_2ND_LEVEL_INTERRUPTS) && (irq & mask2) != 0) { 44 return 2; 45 } 46 47 return 1; 48 } 49 50 /** 51 * @brief Return the 2nd level interrupt number 52 * 53 * This routine returns the second level irq number of the zephyr irq 54 * number passed in 55 * 56 * @param irq IRQ number in its zephyr format 57 * 58 * @return 2nd level IRQ number 59 */ irq_from_level_2(unsigned int irq)60static inline unsigned int irq_from_level_2(unsigned int irq) 61 { 62 if (IS_ENABLED(CONFIG_3RD_LEVEL_INTERRUPTS)) { 63 return ((irq >> CONFIG_1ST_LEVEL_INTERRUPT_BITS) & 64 BIT_MASK(CONFIG_2ND_LEVEL_INTERRUPT_BITS)) - 1; 65 } else { 66 return (irq >> CONFIG_1ST_LEVEL_INTERRUPT_BITS) - 1; 67 } 68 } 69 70 /** 71 * @brief Preprocessor macro to convert `irq` from level 1 to level 2 format 72 * 73 * @param irq IRQ number in its zephyr format 74 * 75 * @return 2nd level IRQ number 76 */ 77 #define IRQ_TO_L2(irq) ((irq + 1) << CONFIG_1ST_LEVEL_INTERRUPT_BITS) 78 79 /** 80 * @brief Converts irq from level 1 to level 2 format 81 * 82 * 83 * This routine converts the input into the level 2 irq number format 84 * 85 * @note Values >= 0xFF are invalid 86 * 87 * @param irq IRQ number in its zephyr format 88 * 89 * @return 2nd level IRQ number 90 */ irq_to_level_2(unsigned int irq)91static inline unsigned int irq_to_level_2(unsigned int irq) 92 { 93 return IRQ_TO_L2(irq); 94 } 95 96 /** 97 * @brief Returns the parent IRQ of the level 2 raw IRQ number 98 * 99 * 100 * The parent of a 2nd level interrupt is in the 1st byte 101 * 102 * @param irq IRQ number in its zephyr format 103 * 104 * @return 2nd level IRQ parent 105 */ irq_parent_level_2(unsigned int irq)106static inline unsigned int irq_parent_level_2(unsigned int irq) 107 { 108 return irq & BIT_MASK(CONFIG_1ST_LEVEL_INTERRUPT_BITS); 109 } 110 111 /** 112 * @brief Return the 3rd level interrupt number 113 * 114 * 115 * This routine returns the third level irq number of the zephyr irq 116 * number passed in 117 * 118 * @param irq IRQ number in its zephyr format 119 * 120 * @return 3rd level IRQ number 121 */ irq_from_level_3(unsigned int irq)122static inline unsigned int irq_from_level_3(unsigned int irq) 123 { 124 return (irq >> (CONFIG_1ST_LEVEL_INTERRUPT_BITS + CONFIG_2ND_LEVEL_INTERRUPT_BITS)) - 1; 125 } 126 127 /** 128 * @brief Preprocessor macro to convert `irq` from level 1 to level 3 format 129 * 130 * @param irq IRQ number in its zephyr format 131 * 132 * @return 3rd level IRQ number 133 */ 134 #define IRQ_TO_L3(irq) \ 135 ((irq + 1) << (CONFIG_1ST_LEVEL_INTERRUPT_BITS + CONFIG_2ND_LEVEL_INTERRUPT_BITS)) 136 137 /** 138 * @brief Converts irq from level 1 to level 3 format 139 * 140 * 141 * This routine converts the input into the level 3 irq number format 142 * 143 * @note Values >= 0xFF are invalid 144 * 145 * @param irq IRQ number in its zephyr format 146 * 147 * @return 3rd level IRQ number 148 */ irq_to_level_3(unsigned int irq)149static inline unsigned int irq_to_level_3(unsigned int irq) 150 { 151 return IRQ_TO_L3(irq); 152 } 153 154 /** 155 * @brief Returns the parent IRQ of the level 3 raw IRQ number 156 * 157 * 158 * The parent of a 3rd level interrupt is in the 2nd byte 159 * 160 * @param irq IRQ number in its zephyr format 161 * 162 * @return 3rd level IRQ parent 163 */ irq_parent_level_3(unsigned int irq)164static inline unsigned int irq_parent_level_3(unsigned int irq) 165 { 166 return (irq >> CONFIG_1ST_LEVEL_INTERRUPT_BITS) & 167 BIT_MASK(CONFIG_2ND_LEVEL_INTERRUPT_BITS); 168 } 169 170 /** 171 * @brief Return the interrupt number for a given level 172 * 173 * @param irq IRQ number in its zephyr format 174 * @param level IRQ level 175 * 176 * @return IRQ number in the level 177 */ irq_from_level(unsigned int irq,unsigned int level)178static inline unsigned int irq_from_level(unsigned int irq, unsigned int level) 179 { 180 if (level == 1) { 181 return irq; 182 } else if (level == 2) { 183 return irq_from_level_2(irq); 184 } else if (level == 3) { 185 return irq_from_level_3(irq); 186 } 187 188 /* level is higher than 3 */ 189 __ASSERT_NO_MSG(false); 190 return irq; 191 } 192 193 /** 194 * @brief Converts irq from level 1 to a given level 195 * 196 * @param irq IRQ number in its zephyr format 197 * @param level IRQ level 198 * 199 * @return Converted IRQ number in the level 200 */ irq_to_level(unsigned int irq,unsigned int level)201static inline unsigned int irq_to_level(unsigned int irq, unsigned int level) 202 { 203 if (level == 1) { 204 return irq; 205 } else if (level == 2) { 206 return irq_to_level_2(irq); 207 } else if (level == 3) { 208 return irq_to_level_3(irq); 209 } 210 211 /* level is higher than 3 */ 212 __ASSERT_NO_MSG(false); 213 return irq; 214 } 215 216 /** 217 * @brief Returns the parent IRQ of the given level raw IRQ number 218 * 219 * @param irq IRQ number in its zephyr format 220 * @param level IRQ level 221 * 222 * @return IRQ parent of the given level 223 */ irq_parent_level(unsigned int irq,unsigned int level)224static inline unsigned int irq_parent_level(unsigned int irq, unsigned int level) 225 { 226 if (level == 1) { 227 /* doesn't really make sense, but return anyway */ 228 return irq; 229 } else if (level == 2) { 230 return irq_parent_level_2(irq); 231 } else if (level == 3) { 232 return irq_parent_level_3(irq); 233 } 234 235 /* level is higher than 3 */ 236 __ASSERT_NO_MSG(false); 237 return irq; 238 } 239 240 /** 241 * @brief Returns the parent interrupt controller IRQ of the given IRQ number 242 * 243 * @param irq IRQ number in its zephyr format 244 * 245 * @return IRQ of the interrupt controller 246 */ irq_get_intc_irq(unsigned int irq)247static inline unsigned int irq_get_intc_irq(unsigned int irq) 248 { 249 const unsigned int level = irq_get_level(irq); 250 251 __ASSERT_NO_MSG(level > 1 && level <= 3); 252 253 return irq & BIT_MASK(CONFIG_1ST_LEVEL_INTERRUPT_BITS + 254 (level == 3 ? CONFIG_2ND_LEVEL_INTERRUPT_BITS : 0)); 255 } 256 257 #endif /* CONFIG_MULTI_LEVEL_INTERRUPTS */ 258 #ifdef __cplusplus 259 } 260 #endif 261 262 #endif /* _ASMLANGUAGE */ 263 #endif /* ZEPHYR_INCLUDE_IRQ_MULTILEVEL_H_ */ 264