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