1 /*
2  * Copyright (c) 2021-2025 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 #include <zephyr/logging/log.h>
23 LOG_MODULE_REGISTER(intc_esp32, CONFIG_LOG_DEFAULT_LEVEL);
24 
25 /*
26  * Define this to debug the choices made when allocating the interrupt. This leads to much debugging
27  * output within a critical region, which can lead to weird effects like e.g. the interrupt watchdog
28  * being triggered, that is why it is separate from the normal LOG* scheme.
29  */
30 #ifdef CONFIG_INTC_ESP32C3_DECISIONS_LOG
31 # define INTC_LOG(...) LOG_INF(__VA_ARGS__)
32 #else
33 # define INTC_LOG(...) do {} while (0)
34 #endif
35 
36 #define ESP32_INTC_DEFAULT_PRIORITY  15
37 #define ESP32_INTC_DEFAULT_THRESHOLD 1
38 #define ESP32_INTC_DISABLED_SLOT     31
39 #define ESP32_INTC_SRCS_PER_IRQ      2
40 
41 /* Define maximum interrupt sources per SoC */
42 #if defined(CONFIG_SOC_SERIES_ESP32C6)
43 /*
44  * Interrupt reserved mask
45  * 0 is reserved
46  * 1 is for Wi-Fi
47  * 3, 4 and 7 are unavailable for PULP CPU as they are bound to Core-Local Interrupts (CLINT)
48  */
49 #define RSVD_MASK (BIT(0) | BIT(1) | BIT(3) | BIT(4) | BIT(7))
50 #define ESP_INTC_AVAILABLE_IRQS 31
51 #else
52 /*
53  * Interrupt reserved mask
54  * 1 is for Wi-Fi
55  */
56 #define RSVD_MASK (BIT(0) | BIT(1))
57 #define ESP_INTC_AVAILABLE_IRQS 30
58 #endif
59 
60 /* Single array for IRQ allocation */
61 static uint8_t esp_intr_irq_alloc[ESP_INTC_AVAILABLE_IRQS * ESP32_INTC_SRCS_PER_IRQ];
62 
63 #define ESP_INTR_IDX(irq, slot) ((irq % ESP_INTC_AVAILABLE_IRQS) * ESP32_INTC_SRCS_PER_IRQ + slot)
64 
65 #define STATUS_MASK_NUM 3
66 
67 static uint32_t esp_intr_enabled_mask[STATUS_MASK_NUM] = {0, 0, 0};
68 
esp_intr_find_irq_for_source(uint32_t source)69 static uint32_t esp_intr_find_irq_for_source(uint32_t source)
70 {
71 	if (source >= ETS_MAX_INTR_SOURCE) {
72 		return IRQ_NA;
73 	}
74 
75 	uint32_t irq = source / ESP32_INTC_SRCS_PER_IRQ;
76 
77 	/* Check if the derived IRQ is usable first */
78 	for (int j = 0; j < ESP32_INTC_SRCS_PER_IRQ; j++) {
79 		int idx = ESP_INTR_IDX(irq, j);
80 
81 		/* Ensure idx is within a valid range */
82 		if (idx >= ARRAY_SIZE(esp_intr_irq_alloc)) {
83 			continue;
84 		}
85 
86 		/* If source is already assigned, return the IRQ */
87 		if (esp_intr_irq_alloc[idx] == source) {
88 			return irq;
89 		}
90 
91 		/* If slot is free, allocate it */
92 		if (esp_intr_irq_alloc[idx] == IRQ_FREE) {
93 			esp_intr_irq_alloc[idx] = source;
94 			return irq;
95 		}
96 	}
97 
98 	/* If derived IRQ is full, search for another available IRQ */
99 	for (irq = 0; irq < ESP_INTC_AVAILABLE_IRQS; irq++) {
100 		if (RSVD_MASK & (1U << irq)) {
101 			continue;
102 		}
103 		for (int j = 0; j < ESP32_INTC_SRCS_PER_IRQ; j++) {
104 			int idx = ESP_INTR_IDX(irq, j);
105 
106 			/* Ensure idx is within a valid range */
107 			if (idx >= ARRAY_SIZE(esp_intr_irq_alloc)) {
108 				continue;
109 			}
110 
111 			/* If source is already assigned, return this IRQ */
112 			if (esp_intr_irq_alloc[idx] == source) {
113 				return irq;
114 			}
115 
116 			/* If slot is free, allocate it */
117 			if (esp_intr_irq_alloc[idx] == IRQ_FREE) {
118 				esp_intr_irq_alloc[idx] = source;
119 				return irq;
120 			}
121 		}
122 	}
123 
124 	/* No available slot found */
125 	return IRQ_NA;
126 }
127 
esp_intr_initialize(void)128 void esp_intr_initialize(void)
129 {
130 	for (int i = 0; i < ETS_MAX_INTR_SOURCE; i++) {
131 		esp_rom_intr_matrix_set(0, i, ESP32_INTC_DISABLED_SLOT);
132 	}
133 
134 	for (int irq = 0; irq < ESP_INTC_AVAILABLE_IRQS; irq++) {
135 		for (int j = 0; j < ESP32_INTC_SRCS_PER_IRQ; j++) {
136 			int idx = ESP_INTR_IDX(irq, j);
137 
138 			if (RSVD_MASK & (1U << irq)) {
139 				esp_intr_irq_alloc[idx] = IRQ_NA;
140 			} else {
141 				esp_intr_irq_alloc[idx] = IRQ_FREE;
142 			}
143 		}
144 	}
145 
146 	/* set global INTC masking level */
147 	esprv_intc_int_set_threshold(ESP32_INTC_DEFAULT_THRESHOLD);
148 }
149 
esp_intr_alloc(int source,int flags,isr_handler_t handler,void * arg,void ** ret_handle)150 int esp_intr_alloc(int source,
151 		int flags,
152 		isr_handler_t handler,
153 		void *arg,
154 		void **ret_handle)
155 {
156 	ARG_UNUSED(flags);
157 	ARG_UNUSED(ret_handle);
158 
159 	if (handler == NULL) {
160 		return -EINVAL;
161 	}
162 
163 	if (source < 0 || source >= ETS_MAX_INTR_SOURCE) {
164 		return -EINVAL;
165 	}
166 
167 	uint32_t key = irq_lock();
168 	uint32_t irq = esp_intr_find_irq_for_source(source);
169 
170 	if (irq == IRQ_NA) {
171 		irq_unlock(key);
172 		return -ENOMEM;
173 	}
174 
175 	irq_connect_dynamic(source,
176 		ESP32_INTC_DEFAULT_PRIORITY,
177 		handler,
178 		arg,
179 		0);
180 
181 	INTC_LOG("Enabled ISRs -- 0: 0x%X -- 1: 0x%X -- 2: 0x%X",
182 		esp_intr_enabled_mask[0], esp_intr_enabled_mask[1], esp_intr_enabled_mask[2]);
183 
184 	irq_unlock(key);
185 	int ret = esp_intr_enable(source);
186 
187 	return ret;
188 }
189 
esp_intr_disable(int source)190 int esp_intr_disable(int source)
191 {
192 	if (source < 0 || source >= ETS_MAX_INTR_SOURCE) {
193 		return -EINVAL;
194 	}
195 
196 	uint32_t key = irq_lock();
197 
198 	esp_rom_intr_matrix_set(0,
199 		source,
200 		ESP32_INTC_DISABLED_SLOT);
201 
202 	for (int i = 0; i < ESP_INTC_AVAILABLE_IRQS; i++) {
203 		if (RSVD_MASK & (1U << i)) {
204 			continue;
205 		}
206 		for (int j = 0; j < ESP32_INTC_SRCS_PER_IRQ; j++) {
207 			int idx = ESP_INTR_IDX(i, j);
208 
209 			if (esp_intr_irq_alloc[idx] == source) {
210 				esp_intr_irq_alloc[idx] = IRQ_FREE;
211 			}
212 		}
213 	}
214 
215 	if (source < 32) {
216 		esp_intr_enabled_mask[0] &= ~(1 << source);
217 	} else if (source < 64) {
218 		esp_intr_enabled_mask[1] &= ~(1 << (source - 32));
219 	} else if (source < 96) {
220 		esp_intr_enabled_mask[2] &= ~(1 << (source - 64));
221 	}
222 
223 	INTC_LOG("Enabled ISRs -- 0: 0x%X -- 1: 0x%X -- 2: 0x%X",
224 		esp_intr_enabled_mask[0], esp_intr_enabled_mask[1], esp_intr_enabled_mask[2]);
225 
226 	irq_unlock(key);
227 
228 	return 0;
229 }
230 
esp_intr_enable(int source)231 int esp_intr_enable(int source)
232 {
233 	if (source < 0 || source >= ETS_MAX_INTR_SOURCE) {
234 		return -EINVAL;
235 	}
236 
237 	uint32_t key = irq_lock();
238 	uint32_t irq = esp_intr_find_irq_for_source(source);
239 
240 	if (irq == IRQ_NA) {
241 		irq_unlock(key);
242 		return -ENOMEM;
243 	}
244 
245 	esp_rom_intr_matrix_set(0, source, irq);
246 
247 	if (source < 32) {
248 		esp_intr_enabled_mask[0] |= (1 << source);
249 	} else if (source < 64) {
250 		esp_intr_enabled_mask[1] |= (1 << (source - 32));
251 	} else if (source < 96) {
252 		esp_intr_enabled_mask[2] |= (1 << (source - 64));
253 	}
254 
255 	INTC_LOG("Enabled ISRs -- 0: 0x%X -- 1: 0x%X -- 2: 0x%X",
256 		esp_intr_enabled_mask[0], esp_intr_enabled_mask[1], esp_intr_enabled_mask[2]);
257 
258 	esprv_intc_int_set_priority(irq, ESP32_INTC_DEFAULT_PRIORITY);
259 	esprv_intc_int_set_type(irq, INTR_TYPE_LEVEL);
260 	esprv_intc_int_enable(1 << irq);
261 
262 	irq_unlock(key);
263 
264 	return 0;
265 }
266 
esp_intr_get_enabled_intmask(int status_mask_number)267 uint32_t esp_intr_get_enabled_intmask(int status_mask_number)
268 {
269 	INTC_LOG("Enabled ISRs -- 0: 0x%X -- 1: 0x%X -- 2: 0x%X",
270 		esp_intr_enabled_mask[0], esp_intr_enabled_mask[1], esp_intr_enabled_mask[2]);
271 
272 	if (status_mask_number < STATUS_MASK_NUM) {
273 		return esp_intr_enabled_mask[status_mask_number];
274 	}
275 
276 	return 0;
277 }
278