1 /*
2 * Copyright (c) 2021 Espressif Systems (Shanghai) Co., Ltd.
3 *
4 * SPDX-License-Identifier: Apache-2.0
5 */
6
7 #include <stdint.h>
8 #include <stdio.h>
9 #include <stdlib.h>
10 #include <stdbool.h>
11 #include <string.h>
12 #include <soc/periph_defs.h>
13 #include <limits.h>
14 #include <assert.h>
15 #include "soc/soc.h"
16 #include <soc.h>
17 #include <zephyr/kernel.h>
18 #include <zephyr/drivers/interrupt_controller/intc_esp32c3.h>
19 #include <zephyr/sw_isr_table.h>
20 #include <riscv/interrupt.h>
21
22 #define ESP32C3_INTC_DEFAULT_PRIO 15
23
24 #include <zephyr/logging/log.h>
25 LOG_MODULE_REGISTER(intc_esp32c3, CONFIG_LOG_DEFAULT_LEVEL);
26
27 /*
28 * Define this to debug the choices made when allocating the interrupt. This leads to much debugging
29 * output within a critical region, which can lead to weird effects like e.g. the interrupt watchdog
30 * being triggered, that is why it is separate from the normal LOG* scheme.
31 */
32 #ifdef CONFIG_INTC_ESP32C3_DECISIONS_LOG
33 # define INTC_LOG(...) LOG_INF(__VA_ARGS__)
34 #else
35 # define INTC_LOG(...) do {} while (0)
36 #endif
37
38 #define ESP32C3_INTC_DEFAULT_PRIORITY 15
39 #define ESP32C3_INTC_DEFAULT_THRESHOLD 1
40 #define ESP32C3_INTC_DISABLED_SLOT 31
41 #define ESP32C3_INTC_SRCS_PER_IRQ 2
42 #define ESP32C3_INTC_AVAILABLE_IRQS 30
43
44 #if defined(CONFIG_SOC_SERIES_ESP32C6)
45
46 #define IRQ_NA 0xFF /* IRQ not available */
47 #define IRQ_FREE 0xFE
48
49 #define ESP32C6_INTC_SRCS_PER_IRQ 2
50 #define ESP32C6_INTC_AVAILABLE_IRQS 31
51
52 /* Interrupt overview for ESP32C6:
53 * - 0, 3, 4, and 7 are used by the CPU for core-local interrupts (CLINT)
54 * - 1 is used for Wi-Fi in Espressif HAL
55 * - 2, 5, 6, 8 .. 31 are available for Zephyr
56 * - 31 is reserved for disabled interrupts
57 */
58 static uint8_t esp_intr_irq_alloc[ESP32C6_INTC_AVAILABLE_IRQS][ESP32C6_INTC_SRCS_PER_IRQ] = {
59 [0] = {IRQ_NA, IRQ_NA},
60 [1] = {IRQ_NA, IRQ_NA},
61 [2] = {IRQ_FREE, IRQ_FREE},
62 [3] = {IRQ_NA, IRQ_NA},
63 [4] = {IRQ_NA, IRQ_NA},
64 [5 ... 6] = {IRQ_FREE, IRQ_FREE},
65 [7] = {IRQ_NA, IRQ_NA},
66 [8 ... 30] = {IRQ_FREE, IRQ_FREE}
67 };
68 #endif
69
70 #define STATUS_MASK_NUM 3
71
72 static uint32_t esp_intr_enabled_mask[STATUS_MASK_NUM] = {0, 0, 0};
73
74 #if defined(CONFIG_SOC_SERIES_ESP32C2) || defined(CONFIG_SOC_SERIES_ESP32C3)
75
esp_intr_find_irq_for_source(uint32_t source)76 static uint32_t esp_intr_find_irq_for_source(uint32_t source)
77 {
78 /* in general case, each 2 sources goes routed to
79 * 1 IRQ line.
80 */
81 uint32_t irq = (source / ESP32C3_INTC_SRCS_PER_IRQ);
82
83 if (irq > ESP32C3_INTC_AVAILABLE_IRQS) {
84 INTC_LOG("Clamping the source: %d no more IRQs available", source);
85 irq = ESP32C3_INTC_AVAILABLE_IRQS;
86 } else if (irq == 0) {
87 irq = 1;
88 }
89
90 INTC_LOG("Found IRQ: %d for source: %d", irq, source);
91
92 return irq;
93 }
94
95 #elif defined(CONFIG_SOC_SERIES_ESP32C6)
96
esp_intr_find_irq_for_source(uint32_t source)97 static uint32_t esp_intr_find_irq_for_source(uint32_t source)
98 {
99 uint32_t irq = IRQ_NA;
100 uint32_t irq_free = IRQ_NA;
101 uint8_t *irq_ptr = NULL;
102
103 /* First allocate one source per IRQ, then two
104 * if there are more sources than free IRQs
105 */
106 for (int j = 0; j < ESP32C6_INTC_SRCS_PER_IRQ; j++) {
107 for (int i = 0; i < ESP32C6_INTC_AVAILABLE_IRQS; i++) {
108 /* Find first free slot but keep searching to see
109 * if source is already associated to an IRQ
110 */
111 if (esp_intr_irq_alloc[i][j] == source) {
112 /* Source is already associated to an IRQ */
113 irq = i;
114 goto found;
115 } else if ((irq_free == IRQ_NA) && (esp_intr_irq_alloc[i][j] == IRQ_FREE)) {
116 irq_free = i;
117 irq_ptr = &esp_intr_irq_alloc[i][j];
118 }
119 }
120 }
121
122 if (irq_ptr != NULL) {
123 *irq_ptr = (uint8_t)source;
124 irq = irq_free;
125 } else {
126 return IRQ_NA;
127 }
128
129 found:
130 INTC_LOG("Found IRQ: %d for source: %d", irq, source);
131
132 return irq;
133 }
134
135 #endif
136
esp_intr_initialize(void)137 void esp_intr_initialize(void)
138 {
139 /* IRQ 31 is reserved for disabled interrupts,
140 * so route all sources to it
141 */
142 for (int i = 0 ; i < ESP32C3_INTC_AVAILABLE_IRQS + 2; i++) {
143 irq_disable(i);
144 }
145
146 for (int i = 0; i < ETS_MAX_INTR_SOURCE; i++) {
147 esp_rom_intr_matrix_set(0, i, ESP32C3_INTC_DISABLED_SLOT);
148 }
149
150 #if defined(CONFIG_SOC_SERIES_ESP32C6)
151 /* Clear up IRQ allocation */
152 for (int j = 0; j < ESP32C6_INTC_SRCS_PER_IRQ; j++) {
153 for (int i = 0; i < ESP32C6_INTC_AVAILABLE_IRQS; i++) {
154 /* screen out reserved IRQs */
155 if (esp_intr_irq_alloc[i][j] != IRQ_NA) {
156 esp_intr_irq_alloc[i][j] = IRQ_FREE;
157 }
158 }
159 }
160 #endif
161
162 /* set global esp32c3's INTC masking level */
163 esprv_intc_int_set_threshold(ESP32C3_INTC_DEFAULT_THRESHOLD);
164 }
165
esp_intr_alloc(int source,int flags,isr_handler_t handler,void * arg,void ** ret_handle)166 int esp_intr_alloc(int source,
167 int flags,
168 isr_handler_t handler,
169 void *arg,
170 void **ret_handle)
171 {
172 ARG_UNUSED(flags);
173 ARG_UNUSED(ret_handle);
174
175 if (handler == NULL) {
176 return -EINVAL;
177 }
178
179 if (source < 0 || source >= ETS_MAX_INTR_SOURCE) {
180 return -EINVAL;
181 }
182
183 uint32_t key = irq_lock();
184
185 irq_connect_dynamic(source,
186 ESP32C3_INTC_DEFAULT_PRIORITY,
187 handler,
188 arg,
189 0);
190
191 if (source < 32) {
192 esp_intr_enabled_mask[0] |= (1 << source);
193 } else if (source < 64) {
194 esp_intr_enabled_mask[1] |= (1 << (source - 32));
195 } else if (source < 96) {
196 esp_intr_enabled_mask[2] |= (1 << (source - 64));
197 }
198
199 INTC_LOG("Enabled ISRs -- 0: 0x%X -- 1: 0x%X -- 2: 0x%X",
200 esp_intr_enabled_mask[0], esp_intr_enabled_mask[1], esp_intr_enabled_mask[2]);
201
202 irq_unlock(key);
203 int ret = esp_intr_enable(source);
204
205 return ret;
206 }
207
esp_intr_disable(int source)208 int esp_intr_disable(int source)
209 {
210 if (source < 0 || source >= ETS_MAX_INTR_SOURCE) {
211 return -EINVAL;
212 }
213
214 uint32_t key = irq_lock();
215
216 esp_rom_intr_matrix_set(0,
217 source,
218 ESP32C3_INTC_DISABLED_SLOT);
219
220 #if defined(CONFIG_SOC_SERIES_ESP32C6)
221 for (int j = 0; j < ESP32C6_INTC_SRCS_PER_IRQ; j++) {
222 for (int i = 0; i < ESP32C6_INTC_AVAILABLE_IRQS; i++) {
223 if (esp_intr_irq_alloc[i][j] == source) {
224 esp_intr_irq_alloc[i][j] = IRQ_FREE;
225 goto freed;
226 }
227 }
228 }
229 freed:
230 #endif
231
232 if (source < 32) {
233 esp_intr_enabled_mask[0] &= ~(1 << source);
234 } else if (source < 64) {
235 esp_intr_enabled_mask[1] &= ~(1 << (source - 32));
236 } else if (source < 96) {
237 esp_intr_enabled_mask[2] &= ~(1 << (source - 64));
238 }
239
240 INTC_LOG("Enabled ISRs -- 0: 0x%X -- 1: 0x%X -- 2: 0x%X",
241 esp_intr_enabled_mask[0], esp_intr_enabled_mask[1], esp_intr_enabled_mask[2]);
242
243 irq_unlock(key);
244
245 return 0;
246 }
247
esp_intr_enable(int source)248 int esp_intr_enable(int source)
249 {
250 if (source < 0 || source >= ETS_MAX_INTR_SOURCE) {
251 return -EINVAL;
252 }
253
254 uint32_t key = irq_lock();
255 uint32_t irq = esp_intr_find_irq_for_source(source);
256
257 #if defined(CONFIG_SOC_SERIES_ESP32C6)
258 if (irq == IRQ_NA) {
259 irq_unlock(key);
260 return -ENOMEM;
261 }
262 #endif
263
264 esp_rom_intr_matrix_set(0, source, irq);
265
266 if (source < 32) {
267 esp_intr_enabled_mask[0] |= (1 << source);
268 } else if (source < 64) {
269 esp_intr_enabled_mask[1] |= (1 << (source - 32));
270 } else if (source < 96) {
271 esp_intr_enabled_mask[2] |= (1 << (source - 64));
272 }
273
274 INTC_LOG("Enabled ISRs -- 0: 0x%X -- 1: 0x%X -- 2: 0x%X",
275 esp_intr_enabled_mask[0], esp_intr_enabled_mask[1], esp_intr_enabled_mask[2]);
276
277 esprv_intc_int_set_priority(irq, ESP32C3_INTC_DEFAULT_PRIO);
278 esprv_intc_int_set_type(irq, INTR_TYPE_LEVEL);
279 esprv_intc_int_enable(1 << irq);
280
281 irq_unlock(key);
282
283 return 0;
284 }
285
esp_intr_get_enabled_intmask(int status_mask_number)286 uint32_t esp_intr_get_enabled_intmask(int status_mask_number)
287 {
288 INTC_LOG("Enabled ISRs -- 0: 0x%X -- 1: 0x%X -- 2: 0x%X",
289 esp_intr_enabled_mask[0], esp_intr_enabled_mask[1], esp_intr_enabled_mask[2]);
290
291 if (status_mask_number < STATUS_MASK_NUM) {
292 return esp_intr_enabled_mask[status_mask_number];
293 } else {
294 return 0; /* error */
295 }
296 }
297