1 /* 2 * Copyright (c) 2021 Espressif Systems (Shanghai) Co., Ltd. 3 * 4 * SPDX-License-Identifier: Apache-2.0 5 */ 6 7 #ifndef ZEPHYR_INCLUDE_DRIVERS_INTERRUPT_CONTROLLER_INTC_ESP32_H_ 8 #define ZEPHYR_INCLUDE_DRIVERS_INTERRUPT_CONTROLLER_INTC_ESP32_H_ 9 10 #include <stdint.h> 11 #include <stdbool.h> 12 13 /* number of possible interrupts per core */ 14 #define ESP_INTC_INTS_NUM (32) 15 16 /* 17 * Interrupt allocation flags - These flags can be used to specify 18 * which interrupt qualities the code calling esp_intr_alloc* needs. 19 * 20 */ 21 22 /* Keep the LEVELx values as they are here; they match up with (1<<level) */ 23 #define ESP_INTR_FLAG_LEVEL1 (1<<1) /* Accept a Level 1 int vector, lowest priority */ 24 #define ESP_INTR_FLAG_LEVEL2 (1<<2) /* Accept a Level 2 int vector */ 25 #define ESP_INTR_FLAG_LEVEL3 (1<<3) /* Accept a Level 3 int vector */ 26 #define ESP_INTR_FLAG_LEVEL4 (1<<4) /* Accept a Level 4 int vector */ 27 #define ESP_INTR_FLAG_LEVEL5 (1<<5) /* Accept a Level 5 int vector */ 28 #define ESP_INTR_FLAG_LEVEL6 (1<<6) /* Accept a Level 6 int vector */ 29 #define ESP_INTR_FLAG_NMI (1<<7) /* Accept a Level 7 int vector, highest priority */ 30 #define ESP_INTR_FLAG_SHARED (1<<8) /* Interrupt can be shared between ISRs */ 31 #define ESP_INTR_FLAG_EDGE (1<<9) /* Edge-triggered interrupt */ 32 #define ESP_INTR_FLAG_IRAM (1<<10) /* ISR can be called if cache is disabled */ 33 #define ESP_INTR_FLAG_INTRDISABLED (1<<11) /* Return with this interrupt disabled */ 34 35 /* Low and medium prio interrupts. These can be handled in C. */ 36 #define ESP_INTR_FLAG_LOWMED (ESP_INTR_FLAG_LEVEL1|ESP_INTR_FLAG_LEVEL2|ESP_INTR_FLAG_LEVEL3) 37 38 /* High level interrupts. Need to be handled in assembly. */ 39 #define ESP_INTR_FLAG_HIGH (ESP_INTR_FLAG_LEVEL4|ESP_INTR_FLAG_LEVEL5|ESP_INTR_FLAG_LEVEL6| \ 40 ESP_INTR_FLAG_NMI) 41 42 /* Mask for all level flags */ 43 #define ESP_INTR_FLAG_LEVELMASK (ESP_INTR_FLAG_LEVEL1|ESP_INTR_FLAG_LEVEL2|ESP_INTR_FLAG_LEVEL3| \ 44 ESP_INTR_FLAG_LEVEL4|ESP_INTR_FLAG_LEVEL5|ESP_INTR_FLAG_LEVEL6| \ 45 ESP_INTR_FLAG_NMI) 46 47 /* 48 * Get the interrupt flags from the supplied priority. 49 */ 50 #define ESP_PRIO_TO_FLAGS(priority) \ 51 ((priority) > 0 ? ((1 << (priority)) & ESP_INTR_FLAG_LEVELMASK) : 0) 52 53 /* 54 * Check interrupt flags from input and filter unallowed values. 55 */ 56 #define ESP_INT_FLAGS_CHECK(int_flags) ((int_flags) & ESP_INTR_FLAG_SHARED) 57 58 /* 59 * The esp_intr_alloc* functions can allocate an int for all *_INTR_SOURCE int sources that 60 * are routed through the interrupt mux. Apart from these sources, each core also has some internal 61 * sources that do not pass through the interrupt mux. To allocate an interrupt for these sources, 62 * pass these pseudo-sources to the functions. 63 */ 64 #define ETS_INTERNAL_TIMER0_INTR_SOURCE -1 /* Xtensa timer 0 interrupt source */ 65 #define ETS_INTERNAL_TIMER1_INTR_SOURCE -2 /* Xtensa timer 1 interrupt source */ 66 #define ETS_INTERNAL_TIMER2_INTR_SOURCE -3 /* Xtensa timer 2 interrupt source */ 67 #define ETS_INTERNAL_SW0_INTR_SOURCE -4 /* Software int source 1 */ 68 #define ETS_INTERNAL_SW1_INTR_SOURCE -5 /* Software int source 2 */ 69 #define ETS_INTERNAL_PROFILING_INTR_SOURCE -6 /* Int source for profiling */ 70 71 /* Function prototype for interrupt handler function */ 72 typedef void (*intr_handler_t)(void *arg); 73 74 struct shared_vector_desc_t { 75 int disabled : 1; 76 int source : 8; 77 volatile uint32_t *statusreg; 78 uint32_t statusmask; 79 intr_handler_t isr; 80 void *arg; 81 struct shared_vector_desc_t *next; 82 }; 83 84 /* Pack using bitfields for better memory use */ 85 struct vector_desc_t { 86 int flags : 16; /* OR of VECDESC_FLAG_* defines */ 87 unsigned int cpu : 1; 88 unsigned int intno : 5; 89 int source : 8; /* Int mux flags, used when not shared */ 90 struct shared_vector_desc_t *shared_vec_info; /* used when VECDESC_FL_SHARED */ 91 struct vector_desc_t *next; 92 }; 93 94 /** Interrupt handler associated data structure */ 95 struct intr_handle_data_t { 96 struct vector_desc_t *vector_desc; 97 struct shared_vector_desc_t *shared_vector_desc; 98 }; 99 100 /** 101 * @brief Initializes interrupt table to its defaults 102 */ 103 void esp_intr_initialize(void); 104 105 /** 106 * @brief Mark an interrupt as a shared interrupt 107 * 108 * This will mark a certain interrupt on the specified CPU as 109 * an interrupt that can be used to hook shared interrupt handlers 110 * to. 111 * 112 * @param intno The number of the interrupt (0-31) 113 * @param cpu CPU on which the interrupt should be marked as shared (0 or 1) 114 * @param is_in_iram Shared interrupt is for handlers that reside in IRAM and 115 * the int can be left enabled while the flash cache is disabled. 116 * 117 * @return -EINVAL if cpu or intno is invalid 118 * 0 otherwise 119 */ 120 int esp_intr_mark_shared(int intno, int cpu, bool is_in_iram); 121 122 /** 123 * @brief Reserve an interrupt to be used outside of this framework 124 * 125 * This will mark a certain interrupt on the specified CPU as 126 * reserved, not to be allocated for any reason. 127 * 128 * @param intno The number of the interrupt (0-31) 129 * @param cpu CPU on which the interrupt should be marked as shared (0 or 1) 130 * 131 * @return -EINVAL if cpu or intno is invalid 132 * 0 otherwise 133 */ 134 int esp_intr_reserve(int intno, int cpu); 135 136 /** 137 * @brief Allocate an interrupt with the given parameters. 138 * 139 * This finds an interrupt that matches the restrictions as given in the flags 140 * parameter, maps the given interrupt source to it and hooks up the given 141 * interrupt handler (with optional argument) as well. If needed, it can return 142 * a handle for the interrupt as well. 143 * 144 * The interrupt will always be allocated on the core that runs this function. 145 * 146 * If ESP_INTR_FLAG_IRAM flag is used, and handler address is not in IRAM or 147 * RTC_FAST_MEM, then ESP_ERR_INVALID_ARG is returned. 148 * 149 * @param source The interrupt source. One of the *_INTR_SOURCE interrupt mux 150 * sources, as defined in esp-xtensa-intmux.h, or one of the internal 151 * ETS_INTERNAL_*_INTR_SOURCE sources as defined in this header. 152 * @param flags An ORred mask of the ESP_INTR_FLAG_* defines. These restrict the 153 * choice of interrupts that this routine can choose from. If this value 154 * is 0, it will default to allocating a non-shared interrupt of level 155 * 1, 2 or 3. If this is ESP_INTR_FLAG_SHARED, it will allocate a shared 156 * interrupt of level 1. Setting ESP_INTR_FLAG_INTRDISABLED will return 157 * from this function with the interrupt disabled. 158 * @param handler The interrupt handler. Must be NULL when an interrupt of level >3 159 * is requested, because these types of interrupts aren't C-callable. 160 * @param arg Optional argument for passed to the interrupt handler 161 * @param ret_handle Pointer to a struct intr_handle_data_t pointer to store a handle that can 162 * later be used to request details or free the interrupt. Can be NULL if no handle 163 * is required. 164 * 165 * @return -EINVAL if the combination of arguments is invalid. 166 * -ENODEV No free interrupt found with the specified flags 167 * 0 otherwise 168 */ 169 int esp_intr_alloc(int source, 170 int flags, 171 intr_handler_t handler, 172 void *arg, 173 struct intr_handle_data_t **ret_handle); 174 175 176 /** 177 * @brief Allocate an interrupt with the given parameters. 178 * 179 * 180 * This essentially does the same as esp_intr_alloc, but allows specifying a register and mask 181 * combo. For shared interrupts, the handler is only called if a read from the specified 182 * register, ANDed with the mask, returns non-zero. By passing an interrupt status register 183 * address and a fitting mask, this can be used to accelerate interrupt handling in the case 184 * a shared interrupt is triggered; by checking the interrupt statuses first, the code can 185 * decide which ISRs can be skipped 186 * 187 * @param source The interrupt source. One of the *_INTR_SOURCE interrupt mux 188 * sources, as defined in esp-xtensa-intmux.h, or one of the internal 189 * ETS_INTERNAL_*_INTR_SOURCE sources as defined in this header. 190 * @param flags An ORred mask of the ESP_INTR_FLAG_* defines. These restrict the 191 * choice of interrupts that this routine can choose from. If this value 192 * is 0, it will default to allocating a non-shared interrupt of level 193 * 1, 2 or 3. If this is ESP_INTR_FLAG_SHARED, it will allocate a shared 194 * interrupt of level 1. Setting ESP_INTR_FLAG_INTRDISABLED will return 195 * from this function with the interrupt disabled. 196 * @param intrstatusreg The address of an interrupt status register 197 * @param intrstatusmask A mask. If a read of address intrstatusreg has any of the bits 198 * that are 1 in the mask set, the ISR will be called. If not, it will be 199 * skipped. 200 * @param handler The interrupt handler. Must be NULL when an interrupt of level >3 201 * is requested, because these types of interrupts aren't C-callable. 202 * @param arg Optional argument for passed to the interrupt handler 203 * @param ret_handle Pointer to a struct intr_handle_data_t pointer to store a handle that can 204 * later be used to request details or free the interrupt. Can be NULL if no handle 205 * is required. 206 * 207 * @return -EINVAL if the combination of arguments is invalid. 208 * -ENODEV No free interrupt found with the specified flags 209 * 0 otherwise 210 */ 211 int esp_intr_alloc_intrstatus(int source, 212 int flags, 213 uint32_t intrstatusreg, 214 uint32_t intrstatusmask, 215 intr_handler_t handler, 216 void *arg, 217 struct intr_handle_data_t **ret_handle); 218 219 220 /** 221 * @brief Disable and free an interrupt. 222 * 223 * Use an interrupt handle to disable the interrupt and release the resources associated with it. 224 * If the current core is not the core that registered this interrupt, this routine will be 225 * assigned to the core that allocated this interrupt, blocking and waiting until the resource 226 * is successfully released. 227 * 228 * @note 229 * When the handler shares its source with other handlers, the interrupt status bits 230 * it's responsible for should be managed properly before freeing it. See ``esp_intr_disable`` 231 * for more details. Please do not call this function in ``esp_ipc_call_blocking``. 232 * 233 * @param handle The handle, as obtained by esp_intr_alloc or esp_intr_alloc_intrstatus 234 * 235 * @return -EINVAL the handle is NULL 236 * 0 otherwise 237 */ 238 int esp_intr_free(struct intr_handle_data_t *handle); 239 240 241 /** 242 * @brief Get CPU number an interrupt is tied to 243 * 244 * @param handle The handle, as obtained by esp_intr_alloc or esp_intr_alloc_intrstatus 245 * 246 * @return The core number where the interrupt is allocated 247 */ 248 int esp_intr_get_cpu(struct intr_handle_data_t *handle); 249 250 /** 251 * @brief Get the allocated interrupt for a certain handle 252 * 253 * @param handle The handle, as obtained by esp_intr_alloc or esp_intr_alloc_intrstatus 254 * 255 * @return The interrupt number 256 */ 257 int esp_intr_get_intno(struct intr_handle_data_t *handle); 258 259 /** 260 * @brief Disable the interrupt associated with the handle 261 * 262 * @note 263 * 1. For local interrupts (``ESP_INTERNAL_*`` sources), this function has to be called on the 264 * CPU the interrupt is allocated on. Other interrupts have no such restriction. 265 * 2. When several handlers sharing a same interrupt source, interrupt status bits, which are 266 * handled in the handler to be disabled, should be masked before the disabling, or handled 267 * in other enabled interrupts properly. Miss of interrupt status handling will cause infinite 268 * interrupt calls and finally system crash. 269 * 270 * @param handle The handle, as obtained by esp_intr_alloc or esp_intr_alloc_intrstatus 271 * 272 * @return -EINVAL if the combination of arguments is invalid. 273 * 0 otherwise 274 */ 275 int esp_intr_disable(struct intr_handle_data_t *handle); 276 277 /** 278 * @brief Enable the interrupt associated with the handle 279 * 280 * @note For local interrupts (``ESP_INTERNAL_*`` sources), this function has to be called on the 281 * CPU the interrupt is allocated on. Other interrupts have no such restriction. 282 * 283 * @param handle The handle, as obtained by esp_intr_alloc or esp_intr_alloc_intrstatus 284 * 285 * @return -EINVAL if the combination of arguments is invalid. 286 * 0 otherwise 287 */ 288 int esp_intr_enable(struct intr_handle_data_t *handle); 289 290 /** 291 * @brief Set the "in IRAM" status of the handler. 292 * 293 * @note Does not work on shared interrupts. 294 * 295 * @param handle The handle, as obtained by esp_intr_alloc or esp_intr_alloc_intrstatus 296 * @param is_in_iram Whether the handler associated with this handle resides in IRAM. 297 * Handlers residing in IRAM can be called when cache is disabled. 298 * 299 * @return -EINVAL if the combination of arguments is invalid. 300 * 0 otherwise 301 */ 302 int esp_intr_set_in_iram(struct intr_handle_data_t *handle, bool is_in_iram); 303 304 /** 305 * @brief Disable interrupts that aren't specifically marked as running from IRAM 306 */ 307 void esp_intr_noniram_disable(void); 308 309 /** 310 * @brief Re-enable interrupts disabled by esp_intr_noniram_disable 311 */ 312 void esp_intr_noniram_enable(void); 313 314 #endif /* ZEPHYR_INCLUDE_DRIVERS_INTERRUPT_CONTROLLER_INTC_ESP32_H_ */ 315