1 /*
2 * Copyright (c) 2020 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 LOG_MODULE_REGISTER(intc_it8xxx2, LOG_LEVEL_DBG);
12 #include <zephyr/sys/printk.h>
13 #include <zephyr/sw_isr_table.h>
14 #include "intc_ite_it8xxx2.h"
15
16 #define MAX_REGISR_IRQ_NUM 8
17 #define IVECT_OFFSET_WITH_IRQ 0x10
18
19 /* Interrupt number of INTC module */
20 static uint8_t intc_irq;
21
22 static volatile uint8_t *const reg_status[] = {
23 &ISR0, &ISR1, &ISR2, &ISR3,
24 &ISR4, &ISR5, &ISR6, &ISR7,
25 &ISR8, &ISR9, &ISR10, &ISR11,
26 &ISR12, &ISR13, &ISR14, &ISR15,
27 &ISR16, &ISR17, &ISR18, &ISR19,
28 &ISR20, &ISR21, &ISR22, &ISR23
29 };
30
31 static volatile uint8_t *const reg_enable[] = {
32 &IER0, &IER1, &IER2, &IER3,
33 &IER4, &IER5, &IER6, &IER7,
34 &IER8, &IER9, &IER10, &IER11,
35 &IER12, &IER13, &IER14, &IER15,
36 &IER16, &IER17, &IER18, &IER19,
37 &IER20, &IER21, &IER22, &IER23
38 };
39
40 /* edge/level trigger register */
41 static volatile uint8_t *const reg_ielmr[] = {
42 &IELMR0, &IELMR1, &IELMR2, &IELMR3,
43 &IELMR4, &IELMR5, &IELMR6, &IELMR7,
44 &IELMR8, &IELMR9, &IELMR10, &IELMR11,
45 &IELMR12, &IELMR13, &IELMR14, &IELMR15,
46 &IELMR16, &IELMR17, &IELMR18, &IELMR19,
47 &IELMR20, &IELMR21, &IELMR22, &IELMR23,
48 };
49
50 /* high/low trigger register */
51 static volatile uint8_t *const reg_ipolr[] = {
52 &IPOLR0, &IPOLR1, &IPOLR2, &IPOLR3,
53 &IPOLR4, &IPOLR5, &IPOLR6, &IPOLR7,
54 &IPOLR8, &IPOLR9, &IPOLR10, &IPOLR11,
55 &IPOLR12, &IPOLR13, &IPOLR14, &IPOLR15,
56 &IPOLR16, &IPOLR17, &IPOLR18, &IPOLR19,
57 &IPOLR20, &IPOLR21, &IPOLR22, &IPOLR23
58 };
59
60 #define IT8XXX2_IER_COUNT ARRAY_SIZE(reg_enable)
61 static uint8_t ier_setting[IT8XXX2_IER_COUNT];
62
ite_intc_save_and_disable_interrupts(void)63 void ite_intc_save_and_disable_interrupts(void)
64 {
65 volatile uint8_t _ier __unused;
66 /* Disable global interrupt for critical section */
67 unsigned int key = irq_lock();
68
69 /* Save and disable interrupts */
70 for (int i = 0; i < IT8XXX2_IER_COUNT; i++) {
71 ier_setting[i] = *reg_enable[i];
72 *reg_enable[i] = 0;
73 }
74 /*
75 * This load operation will guarantee the above modification of
76 * SOC's register can be seen by any following instructions.
77 * Note: Barrier instruction can not synchronize chip register,
78 * so we introduce workaround here.
79 */
80 _ier = *reg_enable[IT8XXX2_IER_COUNT - 1];
81 irq_unlock(key);
82 }
83
ite_intc_restore_interrupts(void)84 void ite_intc_restore_interrupts(void)
85 {
86 /*
87 * Ensure the highest priority interrupt will be the first fired
88 * interrupt when soc is ready to go.
89 */
90 unsigned int key = irq_lock();
91
92 /* Restore interrupt state */
93 for (int i = 0; i < IT8XXX2_IER_COUNT; i++) {
94 *reg_enable[i] = ier_setting[i];
95 }
96 irq_unlock(key);
97 }
98
ite_intc_isr_clear(unsigned int irq)99 void ite_intc_isr_clear(unsigned int irq)
100 {
101 uint32_t g, i;
102 volatile uint8_t *isr;
103
104 if (irq > CONFIG_NUM_IRQS) {
105 return;
106 }
107 g = irq / MAX_REGISR_IRQ_NUM;
108 i = irq % MAX_REGISR_IRQ_NUM;
109 isr = reg_status[g];
110 *isr = BIT(i);
111 }
112
ite_intc_irq_enable(unsigned int irq)113 void __soc_ram_code ite_intc_irq_enable(unsigned int irq)
114 {
115 uint32_t g, i;
116 volatile uint8_t *en;
117
118 if (irq > CONFIG_NUM_IRQS) {
119 return;
120 }
121 g = irq / MAX_REGISR_IRQ_NUM;
122 i = irq % MAX_REGISR_IRQ_NUM;
123 en = reg_enable[g];
124
125 /* critical section due to run a bit-wise OR operation */
126 unsigned int key = irq_lock();
127 SET_MASK(*en, BIT(i));
128 irq_unlock(key);
129 }
130
ite_intc_irq_disable(unsigned int irq)131 void __soc_ram_code ite_intc_irq_disable(unsigned int irq)
132 {
133 uint32_t g, i;
134 volatile uint8_t *en;
135 volatile uint8_t _ier __unused;
136
137 if (irq > CONFIG_NUM_IRQS) {
138 return;
139 }
140 g = irq / MAX_REGISR_IRQ_NUM;
141 i = irq % MAX_REGISR_IRQ_NUM;
142 en = reg_enable[g];
143
144 /* critical section due to run a bit-wise OR operation */
145 unsigned int key = irq_lock();
146 CLEAR_MASK(*en, BIT(i));
147 /*
148 * This load operation will guarantee the above modification of
149 * SOC's register can be seen by any following instructions.
150 */
151 _ier = *en;
152 irq_unlock(key);
153 }
154
ite_intc_irq_polarity_set(unsigned int irq,unsigned int flags)155 void ite_intc_irq_polarity_set(unsigned int irq, unsigned int flags)
156 {
157 uint32_t g, i;
158 volatile uint8_t *tri;
159
160 if ((irq > CONFIG_NUM_IRQS) || ((flags&IRQ_TYPE_EDGE_BOTH) == IRQ_TYPE_EDGE_BOTH)) {
161 return;
162 }
163 g = irq / MAX_REGISR_IRQ_NUM;
164 i = irq % MAX_REGISR_IRQ_NUM;
165 tri = reg_ipolr[g];
166 if ((flags&IRQ_TYPE_LEVEL_HIGH) || (flags&IRQ_TYPE_EDGE_RISING)) {
167 CLEAR_MASK(*tri, BIT(i));
168 } else {
169 SET_MASK(*tri, BIT(i));
170 }
171 tri = reg_ielmr[g];
172 if ((flags&IRQ_TYPE_LEVEL_LOW) || (flags&IRQ_TYPE_LEVEL_HIGH)) {
173 CLEAR_MASK(*tri, BIT(i));
174 } else {
175 SET_MASK(*tri, BIT(i));
176 }
177 }
178
ite_intc_irq_is_enable(unsigned int irq)179 int __soc_ram_code ite_intc_irq_is_enable(unsigned int irq)
180 {
181 uint32_t g, i;
182 volatile uint8_t *en;
183
184 if (irq > CONFIG_NUM_IRQS) {
185 return 0;
186 }
187 g = irq / MAX_REGISR_IRQ_NUM;
188 i = irq % MAX_REGISR_IRQ_NUM;
189 en = reg_enable[g];
190 return IS_MASK_SET(*en, BIT(i));
191 }
192
ite_intc_get_irq_num(void)193 uint8_t __soc_ram_code ite_intc_get_irq_num(void)
194 {
195 return intc_irq;
196 }
197
ite_intc_no_irq(void)198 bool __soc_ram_code ite_intc_no_irq(void)
199 {
200 return (IVECT == IVECT_OFFSET_WITH_IRQ);
201 }
202
get_irq(void * arg)203 uint8_t __soc_ram_code get_irq(void *arg)
204 {
205 ARG_UNUSED(arg);
206
207 /* wait until two equal interrupt values are read */
208 do {
209 /* Read interrupt number from interrupt vector register */
210 intc_irq = IVECT;
211 /*
212 * WORKAROUND: when the interrupt vector register (IVECT)
213 * isn't latched in a load operation, we read it again to make
214 * sure the value we got is the correct value.
215 */
216 } while (intc_irq != IVECT);
217 /* determine interrupt number */
218 intc_irq -= IVECT_OFFSET_WITH_IRQ;
219 /*
220 * Look for pending interrupt if there's interrupt number 0 from
221 * the AIVECT register.
222 */
223 if (intc_irq == 0) {
224 uint8_t int_pending;
225
226 for (int i = (IT8XXX2_IER_COUNT - 1); i >= 0; i--) {
227 int_pending = (*reg_status[i] & *reg_enable[i]);
228 if (int_pending != 0) {
229 intc_irq = (MAX_REGISR_IRQ_NUM * i) +
230 find_msb_set(int_pending) - 1;
231 LOG_DBG("Pending interrupt found: %d",
232 intc_irq);
233 LOG_DBG("CPU mepc: 0x%lx", csr_read(mepc));
234 break;
235 }
236 }
237 }
238 /* clear interrupt status */
239 ite_intc_isr_clear(intc_irq);
240 /* return interrupt number */
241 return intc_irq;
242 }
243
soc_interrupt_init(void)244 void soc_interrupt_init(void)
245 {
246 #ifdef CONFIG_ZTEST
247 /*
248 * After flashed EC image, we needed to manually press the reset button
249 * on it8xxx2_evb, then run the test. Now, without pressing the button,
250 * we can disable debug mode and trigger a watchdog hard reset then
251 * run tests.
252 */
253 struct wdt_it8xxx2_regs *const wdt_regs = WDT_IT8XXX2_REGS_BASE;
254 struct gctrl_it8xxx2_regs *const gctrl_regs = GCTRL_IT8XXX2_REGS_BASE;
255
256 if (gctrl_regs->GCTRL_DBGROS & IT8XXX2_GCTRL_SMB_DBGR) {
257 /* Disable debug mode through i2c */
258 IT8XXX2_SMB_SLVISELR |= BIT(4);
259 /* Enable ETWD reset */
260 wdt_regs->ETWCFG = 0;
261 wdt_regs->ET1PSR = IT8XXX2_WDT_ETPS_1P024_KHZ;
262 wdt_regs->ETWCFG = (IT8XXX2_WDT_EWDKEYEN | IT8XXX2_WDT_EWDSRC);
263 /* Enable ETWD hardware reset */
264 gctrl_regs->GCTRL_ETWDUARTCR |= IT8XXX2_GCTRL_ETWD_HW_RST_EN;
265 /* Trigger ETWD reset */
266 wdt_regs->EWDKEYR = 0;
267
268 /* Spin and wait for reboot */
269 while (1)
270 ;
271 } else {
272 /* Disable ETWD hardware reset */
273 gctrl_regs->GCTRL_ETWDUARTCR &= ~IT8XXX2_GCTRL_ETWD_HW_RST_EN;
274 }
275 #endif
276
277 /* Ensure interrupts of soc are disabled at default */
278 for (int i = 0; i < ARRAY_SIZE(reg_enable); i++) {
279 *reg_enable[i] = 0;
280 }
281
282 /* Enable M-mode external interrupt */
283 csr_set(mie, MIP_MEIP);
284 }
285