1 /*
2 * Copyright (c) 2023 ITE Corporation. All Rights Reserved
3 *
4 * SPDX-License-Identifier: Apache-2.0
5 */
6
7 #include <zephyr/kernel.h>
8 #include <zephyr/arch/cpu.h>
9 #include <zephyr/init.h>
10 #include <zephyr/logging/log.h>
11 #include <zephyr/sys/printk.h>
12 #include <zephyr/sw_isr_table.h>
13 #include "intc_ite_it8xxx2.h"
14 LOG_MODULE_REGISTER(intc_it8xxx2_v2, LOG_LEVEL_DBG);
15
16 #define IT8XXX2_INTC_BASE DT_REG_ADDR(DT_NODELABEL(intc))
17 #define IT8XXX2_INTC_BASE_SHIFT(g) (IT8XXX2_INTC_BASE + ((g) << 2))
18
19 /* Interrupt status register */
20 #define IT8XXX2_INTC_ISR(g) ECREG(IT8XXX2_INTC_BASE_SHIFT(g) + \
21 ((g) < 4 ? 0x0 : 0x4))
22 /* Interrupt enable register */
23 #define IT8XXX2_INTC_IER(g) ECREG(IT8XXX2_INTC_BASE_SHIFT(g) + \
24 ((g) < 4 ? 0x1 : 0x5))
25 /* Interrupt edge/level triggered mode register */
26 #define IT8XXX2_INTC_IELMR(g) ECREG(IT8XXX2_INTC_BASE_SHIFT(g) + \
27 ((g) < 4 ? 0x2 : 0x6))
28 /* Interrupt polarity register */
29 #define IT8XXX2_INTC_IPOLR(g) ECREG(IT8XXX2_INTC_BASE_SHIFT(g) + \
30 ((g) < 4 ? 0x3 : 0x7))
31
32 #define IT8XXX2_INTC_GROUP_CNT 24
33 #define MAX_REGISR_IRQ_NUM 8
34 #define IVECT_OFFSET_WITH_IRQ 0x10
35
36 /* Interrupt number of INTC module */
37 static uint8_t intc_irq;
38 static uint8_t ier_setting[IT8XXX2_INTC_GROUP_CNT];
39
ite_intc_save_and_disable_interrupts(void)40 void ite_intc_save_and_disable_interrupts(void)
41 {
42 /* Disable global interrupt for critical section */
43 unsigned int key = irq_lock();
44
45 /* Save and disable interrupts */
46 for (int i = 0; i < IT8XXX2_INTC_GROUP_CNT; i++) {
47 ier_setting[i] = IT8XXX2_INTC_IER(i);
48 IT8XXX2_INTC_IER(i) = 0;
49 }
50
51 /*
52 * This load operation will guarantee the above modification of
53 * SOC's register can be seen by any following instructions.
54 * Note: Barrier instruction can not synchronize chip register,
55 * so we introduce workaround here.
56 */
57 IT8XXX2_INTC_IER(IT8XXX2_INTC_GROUP_CNT - 1);
58
59 irq_unlock(key);
60 }
61
ite_intc_restore_interrupts(void)62 void ite_intc_restore_interrupts(void)
63 {
64 /*
65 * Ensure the highest priority interrupt will be the first fired
66 * interrupt when soc is ready to go.
67 */
68 unsigned int key = irq_lock();
69
70 /* Restore interrupt state */
71 for (int i = 0; i < IT8XXX2_INTC_GROUP_CNT; i++) {
72 IT8XXX2_INTC_IER(i) = ier_setting[i];
73 }
74
75 irq_unlock(key);
76 }
77
ite_intc_isr_clear(unsigned int irq)78 void ite_intc_isr_clear(unsigned int irq)
79 {
80 uint32_t group, index;
81
82 if (irq > CONFIG_NUM_IRQS) {
83 return;
84 }
85
86 group = irq / MAX_REGISR_IRQ_NUM;
87 index = irq % MAX_REGISR_IRQ_NUM;
88
89 IT8XXX2_INTC_ISR(group) = BIT(index);
90 }
91
ite_intc_irq_enable(unsigned int irq)92 void __soc_ram_code ite_intc_irq_enable(unsigned int irq)
93 {
94 uint32_t group, index;
95
96 if (irq > CONFIG_NUM_IRQS) {
97 return;
98 }
99
100 group = irq / MAX_REGISR_IRQ_NUM;
101 index = irq % MAX_REGISR_IRQ_NUM;
102
103 /* Critical section due to run a bit-wise OR operation */
104 unsigned int key = irq_lock();
105
106 IT8XXX2_INTC_IER(group) |= BIT(index);
107
108 irq_unlock(key);
109 }
110
ite_intc_irq_disable(unsigned int irq)111 void __soc_ram_code ite_intc_irq_disable(unsigned int irq)
112 {
113 uint32_t group, index;
114
115 if (irq > CONFIG_NUM_IRQS) {
116 return;
117 }
118
119 group = irq / MAX_REGISR_IRQ_NUM;
120 index = irq % MAX_REGISR_IRQ_NUM;
121
122 /* Critical section due to run a bit-wise NAND operation */
123 unsigned int key = irq_lock();
124
125 IT8XXX2_INTC_IER(group) &= ~BIT(index);
126 /*
127 * This load operation will guarantee the above modification of
128 * SOC's register can be seen by any following instructions.
129 */
130 IT8XXX2_INTC_IER(group);
131
132 irq_unlock(key);
133 }
134
ite_intc_irq_polarity_set(unsigned int irq,unsigned int flags)135 void ite_intc_irq_polarity_set(unsigned int irq, unsigned int flags)
136 {
137 uint32_t group, index;
138
139 if (irq > CONFIG_NUM_IRQS) {
140 return;
141 }
142
143 if ((flags & IRQ_TYPE_EDGE_BOTH) == IRQ_TYPE_EDGE_BOTH) {
144 return;
145 }
146
147 group = irq / MAX_REGISR_IRQ_NUM;
148 index = irq % MAX_REGISR_IRQ_NUM;
149
150 if ((flags & IRQ_TYPE_LEVEL_HIGH) || (flags & IRQ_TYPE_EDGE_RISING)) {
151 IT8XXX2_INTC_IPOLR(group) &= ~BIT(index);
152 } else {
153 IT8XXX2_INTC_IPOLR(group) |= BIT(index);
154 }
155
156 if ((flags & IRQ_TYPE_LEVEL_LOW) || (flags & IRQ_TYPE_LEVEL_HIGH)) {
157 IT8XXX2_INTC_IELMR(group) &= ~BIT(index);
158 } else {
159 IT8XXX2_INTC_IELMR(group) |= BIT(index);
160 }
161 }
162
ite_intc_irq_is_enable(unsigned int irq)163 int __soc_ram_code ite_intc_irq_is_enable(unsigned int irq)
164 {
165 uint32_t group, index;
166
167 if (irq > CONFIG_NUM_IRQS) {
168 return 0;
169 }
170
171 group = irq / MAX_REGISR_IRQ_NUM;
172 index = irq % MAX_REGISR_IRQ_NUM;
173
174 return IS_MASK_SET(IT8XXX2_INTC_IER(group), BIT(index));
175 }
176
ite_intc_get_irq_num(void)177 uint8_t __soc_ram_code ite_intc_get_irq_num(void)
178 {
179 return intc_irq;
180 }
181
ite_intc_no_irq(void)182 bool __soc_ram_code ite_intc_no_irq(void)
183 {
184 return (IVECT == IVECT_OFFSET_WITH_IRQ);
185 }
186
get_irq(void * arg)187 uint8_t __soc_ram_code get_irq(void *arg)
188 {
189 ARG_UNUSED(arg);
190
191 /* Wait until two equal interrupt values are read */
192 do {
193 /* Read interrupt number from interrupt vector register */
194 intc_irq = IVECT;
195 /*
196 * WORKAROUND: when the interrupt vector register (IVECT)
197 * isn't latched in a load operation, we read it again to make
198 * sure the value we got is the correct value.
199 */
200 } while (intc_irq != IVECT);
201
202 /* Determine interrupt number */
203 intc_irq -= IVECT_OFFSET_WITH_IRQ;
204
205 /*
206 * Look for pending interrupt if there's interrupt number 0 from
207 * the AIVECT register.
208 */
209 if (intc_irq == 0) {
210 uint8_t int_pending;
211
212 for (int i = (IT8XXX2_INTC_GROUP_CNT - 1); i >= 0; i--) {
213 int_pending =
214 (IT8XXX2_INTC_ISR(i) & IT8XXX2_INTC_IER(i));
215 if (int_pending != 0) {
216 intc_irq = (MAX_REGISR_IRQ_NUM * i) +
217 find_msb_set(int_pending) - 1;
218 LOG_DBG("Pending interrupt found: %d",
219 intc_irq);
220 LOG_DBG("CPU mepc: 0x%lx", csr_read(mepc));
221 break;
222 }
223 }
224 }
225
226 /* Clear interrupt status */
227 ite_intc_isr_clear(intc_irq);
228
229 /* Return interrupt number */
230 return intc_irq;
231 }
232
soc_interrupt_init(void)233 void soc_interrupt_init(void)
234 {
235 /* Ensure interrupts of soc are disabled at default */
236 for (int i = 0; i < IT8XXX2_INTC_GROUP_CNT; i++) {
237 IT8XXX2_INTC_IER(i) = 0;
238 }
239
240 /* Enable M-mode external interrupt */
241 csr_set(mie, MIP_MEIP);
242 }
243