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