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 static uint32_t esp_intr_enabled_mask[2] = {0, 0};
45 
esp_intr_find_irq_for_source(uint32_t source)46 static uint32_t esp_intr_find_irq_for_source(uint32_t source)
47 {
48 	/* in general case, each 2 sources goes routed to
49 	 * 1 IRQ line.
50 	 */
51 	uint32_t irq = (source / ESP32C3_INTC_SRCS_PER_IRQ);
52 
53 	if (irq > ESP32C3_INTC_AVAILABLE_IRQS) {
54 		INTC_LOG("Clamping the source: %d no more IRQs available", source);
55 		irq = ESP32C3_INTC_AVAILABLE_IRQS;
56 	} else if (irq == 0) {
57 		irq = 1;
58 	}
59 
60 	INTC_LOG("Found IRQ: %d for source: %d", irq, source);
61 
62 	return irq;
63 }
64 
esp_intr_initialize(void)65 void esp_intr_initialize(void)
66 {
67 	/* IRQ 31 is reserved for disabled interrupts,
68 	 * so route all sources to it
69 	 */
70 	for (int i = 0 ; i < ESP32C3_INTC_AVAILABLE_IRQS + 2; i++) {
71 		irq_disable(i);
72 	}
73 
74 	for (int i = 0; i < ETS_MAX_INTR_SOURCE; i++) {
75 		esp_rom_intr_matrix_set(0, i, ESP32C3_INTC_DISABLED_SLOT);
76 	}
77 
78 	/* set global esp32c3's INTC masking level */
79 	esprv_intc_int_set_threshold(ESP32C3_INTC_DEFAULT_THRESHOLD);
80 }
81 
esp_intr_alloc(int source,int flags,isr_handler_t handler,void * arg,void ** ret_handle)82 int esp_intr_alloc(int source,
83 		int flags,
84 		isr_handler_t handler,
85 		void *arg,
86 		void **ret_handle)
87 {
88 	ARG_UNUSED(flags);
89 	ARG_UNUSED(ret_handle);
90 
91 	if (handler == NULL) {
92 		return -EINVAL;
93 	}
94 
95 	if (source < 0 || source >= ETS_MAX_INTR_SOURCE) {
96 		return -EINVAL;
97 	}
98 
99 	uint32_t key = irq_lock();
100 
101 	irq_connect_dynamic(source,
102 		ESP32C3_INTC_DEFAULT_PRIORITY,
103 		handler,
104 		arg,
105 		0);
106 
107 	if (source < 32) {
108 		esp_intr_enabled_mask[0] |= (1 << source);
109 	} else {
110 		esp_intr_enabled_mask[1] |= (1 << (source - 32));
111 	}
112 
113 	INTC_LOG("Enabled ISRs -- 0: 0x%X -- 1: 0x%X",
114 		esp_intr_enabled_mask[0], esp_intr_enabled_mask[1]);
115 
116 	irq_unlock(key);
117 	irq_enable(source);
118 
119 	return 0;
120 }
121 
esp_intr_disable(int source)122 int esp_intr_disable(int source)
123 {
124 	if (source < 0 || source >= ETS_MAX_INTR_SOURCE) {
125 		return -EINVAL;
126 	}
127 
128 	uint32_t key = irq_lock();
129 
130 	esp_rom_intr_matrix_set(0,
131 		source,
132 		ESP32C3_INTC_DISABLED_SLOT);
133 
134 	if (source < 32) {
135 		esp_intr_enabled_mask[0] &= ~(1 << source);
136 	} else {
137 		esp_intr_enabled_mask[1] &= ~(1 << (source - 32));
138 	}
139 
140 	INTC_LOG("Enabled ISRs -- 0: 0x%X -- 1: 0x%X",
141 		esp_intr_enabled_mask[0], esp_intr_enabled_mask[1]);
142 
143 	irq_unlock(key);
144 
145 	return 0;
146 }
147 
esp_intr_enable(int source)148 int esp_intr_enable(int source)
149 {
150 	if (source < 0 || source >= ETS_MAX_INTR_SOURCE) {
151 		return -EINVAL;
152 	}
153 
154 	uint32_t key = irq_lock();
155 	uint32_t irq = esp_intr_find_irq_for_source(source);
156 
157 	esp_rom_intr_matrix_set(0, source, irq);
158 
159 	if (source < 32) {
160 		esp_intr_enabled_mask[0] |= (1 << source);
161 	} else {
162 		esp_intr_enabled_mask[1] |= (1 << (source - 32));
163 	}
164 
165 	INTC_LOG("Enabled ISRs -- 0: 0x%X -- 1: 0x%X",
166 		esp_intr_enabled_mask[0], esp_intr_enabled_mask[1]);
167 
168 	esprv_intc_int_set_priority(irq, ESP32C3_INTC_DEFAULT_PRIO);
169 	esprv_intc_int_set_type(irq, INTR_TYPE_LEVEL);
170 	esprv_intc_int_enable(1 << irq);
171 
172 	irq_unlock(key);
173 
174 	return 0;
175 }
176 
esp_intr_get_enabled_intmask(int status_mask_number)177 uint32_t esp_intr_get_enabled_intmask(int status_mask_number)
178 {
179 	INTC_LOG("Enabled ISRs -- 0: 0x%X -- 1: 0x%X",
180 		esp_intr_enabled_mask[0], esp_intr_enabled_mask[1]);
181 
182 	if (status_mask_number == 0) {
183 		return esp_intr_enabled_mask[0];
184 	} else {
185 		return esp_intr_enabled_mask[1];
186 	}
187 }
188