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