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