1 /*
2  * Copyright (c) 2018 Marvell
3  * Copyright (c) 2018 Lexmark International, Inc.
4  * Copyright (c) 2019 Stephanos Ioannidis <root@stephanos.io>
5  *
6  * SPDX-License-Identifier: Apache-2.0
7  */
8 
9 /*
10  * NOTE: This driver implements the GICv1 and GICv2 interfaces.
11  */
12 
13 #include <zephyr/device.h>
14 #include <zephyr/arch/cpu.h>
15 #include <zephyr/devicetree.h>
16 #include <zephyr/sw_isr_table.h>
17 #include <zephyr/dt-bindings/interrupt-controller/arm-gic.h>
18 #include <zephyr/drivers/interrupt_controller/gic.h>
19 #include <zephyr/sys/barrier.h>
20 
21 #if defined(CONFIG_GIC_V1)
22 #define DT_DRV_COMPAT arm_gic_v1
23 #elif defined(CONFIG_GIC_V2)
24 #define DT_DRV_COMPAT arm_gic_v2
25 #else
26 #error "Unknown GIC controller compatible for this configuration"
27 #endif
28 
29 static const uint64_t cpu_mpid_list[] = {
30 	DT_FOREACH_CHILD_STATUS_OKAY_SEP(DT_PATH(cpus), DT_REG_ADDR, (,))
31 };
32 
33 BUILD_ASSERT(ARRAY_SIZE(cpu_mpid_list) >= CONFIG_MP_MAX_NUM_CPUS,
34 		"The count of CPU Cores nodes in dts is less than CONFIG_MP_MAX_NUM_CPUS\n");
35 
arm_gic_irq_enable(unsigned int irq)36 void arm_gic_irq_enable(unsigned int irq)
37 {
38 	int int_grp, int_off;
39 
40 	int_grp = irq / 32;
41 	int_off = irq % 32;
42 
43 	sys_write32((1 << int_off), (GICD_ISENABLERn + int_grp * 4));
44 }
45 
arm_gic_irq_disable(unsigned int irq)46 void arm_gic_irq_disable(unsigned int irq)
47 {
48 	int int_grp, int_off;
49 
50 	int_grp = irq / 32;
51 	int_off = irq % 32;
52 
53 	sys_write32((1 << int_off), (GICD_ICENABLERn + int_grp * 4));
54 }
55 
arm_gic_irq_is_enabled(unsigned int irq)56 bool arm_gic_irq_is_enabled(unsigned int irq)
57 {
58 	int int_grp, int_off;
59 	unsigned int enabler;
60 
61 	int_grp = irq / 32;
62 	int_off = irq % 32;
63 
64 	enabler = sys_read32(GICD_ISENABLERn + int_grp * 4);
65 
66 	return (enabler & (1 << int_off)) != 0;
67 }
68 
arm_gic_irq_is_pending(unsigned int irq)69 bool arm_gic_irq_is_pending(unsigned int irq)
70 {
71 	int int_grp, int_off;
72 	unsigned int enabler;
73 
74 	int_grp = irq / 32;
75 	int_off = irq % 32;
76 
77 	enabler = sys_read32(GICD_ISPENDRn + int_grp * 4);
78 
79 	return (enabler & (1 << int_off)) != 0;
80 }
81 
arm_gic_irq_clear_pending(unsigned int irq)82 void arm_gic_irq_clear_pending(unsigned int irq)
83 {
84 	int int_grp, int_off;
85 
86 	int_grp = irq / 32;
87 	int_off = irq % 32;
88 
89 	sys_write32((1 << int_off), (GICD_ICPENDRn + int_grp * 4));
90 }
91 
arm_gic_irq_set_priority(unsigned int irq,unsigned int prio,uint32_t flags)92 void arm_gic_irq_set_priority(
93 	unsigned int irq, unsigned int prio, uint32_t flags)
94 {
95 	int int_grp, int_off;
96 	uint32_t val;
97 
98 	/* Set priority */
99 	sys_write8(prio & 0xff, GICD_IPRIORITYRn + irq);
100 
101 	/* Set interrupt type */
102 	int_grp = (irq / 16) * 4;
103 	int_off = (irq % 16) * 2;
104 
105 	val = sys_read32(GICD_ICFGRn + int_grp);
106 	val &= ~(GICD_ICFGR_MASK << int_off);
107 	if (flags & IRQ_TYPE_EDGE) {
108 		val |= (GICD_ICFGR_TYPE << int_off);
109 	}
110 
111 	sys_write32(val, GICD_ICFGRn + int_grp);
112 }
113 
arm_gic_get_active(void)114 unsigned int arm_gic_get_active(void)
115 {
116 	unsigned int irq;
117 
118 	/*
119 	 * "ARM Generic Interrupt Controller Architecture version 2.0" states that
120 	 * [4.4.5 End of Interrupt Register, GICC_EOIR)]:
121 	 * """
122 	 * For compatibility with possible extensions to the GIC architecture
123 	 * specification, ARM recommends that software preserves the entire register
124 	 * value read from the GICC_IAR when it acknowledges the interrupt, and uses
125 	 * that entire value for its corresponding write to the GICC_EOIR.
126 	 * """
127 	 * Because of that, we read the entire value here, to be later written back to GICC_EOIR
128 	 */
129 	irq = sys_read32(GICC_IAR);
130 	return irq;
131 }
132 
arm_gic_eoi(unsigned int irq)133 void arm_gic_eoi(unsigned int irq)
134 {
135 	/*
136 	 * Ensure the write to peripheral registers are *complete* before the write
137 	 * to GIC_EOIR.
138 	 *
139 	 * Note: The completion guarantee depends on various factors of system design
140 	 * and the barrier is the best core can do by which execution of further
141 	 * instructions waits till the barrier is alive.
142 	 */
143 	barrier_dsync_fence_full();
144 
145 	/* set to inactive */
146 	sys_write32(irq, GICC_EOIR);
147 }
148 
gic_raise_sgi(unsigned int sgi_id,uint64_t target_aff,uint16_t target_list)149 void gic_raise_sgi(unsigned int sgi_id, uint64_t target_aff,
150 		uint16_t target_list)
151 {
152 	uint32_t sgi_val;
153 
154 	ARG_UNUSED(target_aff);
155 
156 	sgi_val = GICD_SGIR_TGTFILT_CPULIST |
157 		GICD_SGIR_CPULIST(target_list & GICD_SGIR_CPULIST_MASK) |
158 		sgi_id;
159 
160 	barrier_dsync_fence_full();
161 	sys_write32(sgi_val, GICD_SGIR);
162 	barrier_isync_fence_full();
163 }
164 
gic_dist_init(void)165 static void gic_dist_init(void)
166 {
167 	unsigned int gic_irqs, i;
168 	uint8_t cpu_mask = 0;
169 	uint32_t reg_val;
170 
171 	gic_irqs = sys_read32(GICD_TYPER) & 0x1f;
172 	gic_irqs = (gic_irqs + 1) * 32;
173 	if (gic_irqs > 1020) {
174 		gic_irqs = 1020;
175 	}
176 
177 	/*
178 	 * Disable the forwarding of pending interrupts
179 	 * from the Distributor to the CPU interfaces
180 	 */
181 	sys_write32(0, GICD_CTLR);
182 
183 	/*
184 	 * Enable all global interrupts distributing to CPUs listed
185 	 * in dts with the count of arch_num_cpus().
186 	 */
187 	unsigned int num_cpus = arch_num_cpus();
188 
189 	for (i = 0; i < num_cpus; i++) {
190 		cpu_mask |= BIT(cpu_mpid_list[i]);
191 	}
192 	reg_val = cpu_mask | (cpu_mask << 8) | (cpu_mask << 16)
193 		| (cpu_mask << 24);
194 	for (i = GIC_SPI_INT_BASE; i < gic_irqs; i += 4) {
195 		sys_write32(reg_val, GICD_ITARGETSRn + i);
196 	}
197 
198 	/*
199 	 * Set all global interrupts to be level triggered, active low.
200 	 */
201 	for (i = GIC_SPI_INT_BASE; i < gic_irqs; i += 16) {
202 		sys_write32(0, GICD_ICFGRn + i / 4);
203 	}
204 
205 	/*  Set priority on all global interrupts.   */
206 	for (i = GIC_SPI_INT_BASE; i < gic_irqs; i += 4) {
207 		sys_write32(0, GICD_IPRIORITYRn + i);
208 	}
209 
210 	/* Set all interrupts to group 0 */
211 	for (i = GIC_SPI_INT_BASE; i < gic_irqs; i += 32) {
212 		sys_write32(0, GICD_IGROUPRn + i / 8);
213 	}
214 
215 	/*
216 	 * Disable all interrupts.  Leave the PPI and SGIs alone
217 	 * as these enables are banked registers.
218 	 */
219 	for (i = GIC_SPI_INT_BASE; i < gic_irqs; i += 32) {
220 #ifndef CONFIG_GIC_V1
221 		sys_write32(0xffffffff, GICD_ICACTIVERn + i / 8);
222 #endif
223 		sys_write32(0xffffffff, GICD_ICENABLERn + i / 8);
224 	}
225 
226 	/*
227 	 * Enable the forwarding of pending interrupts
228 	 * from the Distributor to the CPU interfaces
229 	 */
230 	sys_write32(1, GICD_CTLR);
231 }
232 
gic_cpu_init(void)233 static void gic_cpu_init(void)
234 {
235 	int i;
236 	uint32_t val;
237 
238 	/*
239 	 * Deal with the banked PPI and SGI interrupts - disable all
240 	 * PPI interrupts, ensure all SGI interrupts are enabled.
241 	 */
242 #ifndef CONFIG_GIC_V1
243 	sys_write32(0xffffffff, GICD_ICACTIVERn);
244 #endif
245 	sys_write32(0xffff0000, GICD_ICENABLERn);
246 	sys_write32(0x0000ffff, GICD_ISENABLERn);
247 
248 	/*
249 	 * Set priority on PPI and SGI interrupts
250 	 */
251 	for (i = 0; i < 32; i += 4) {
252 		sys_write32(0xa0a0a0a0, GICD_IPRIORITYRn + i);
253 	}
254 
255 	sys_write32(0xf0, GICC_PMR);
256 
257 	/*
258 	 * Enable interrupts and signal them using the IRQ signal.
259 	 */
260 	val = sys_read32(GICC_CTLR);
261 #ifndef CONFIG_GIC_V1
262 	val &= ~GICC_CTLR_BYPASS_MASK;
263 #endif
264 	val |= GICC_CTLR_ENABLE_MASK;
265 	sys_write32(val, GICC_CTLR);
266 }
267 
268 #define GIC_PARENT_IRQ 0
269 #define GIC_PARENT_IRQ_PRI 0
270 #define GIC_PARENT_IRQ_FLAGS 0
271 
272 /**
273  * @brief Initialize the GIC device driver
274  */
arm_gic_init(const struct device * dev)275 int arm_gic_init(const struct device *dev)
276 {
277 	/* Init of Distributor interface registers */
278 	gic_dist_init();
279 
280 	/* Init CPU interface registers */
281 	gic_cpu_init();
282 
283 	return 0;
284 }
285 
286 DEVICE_DT_INST_DEFINE(0, arm_gic_init, NULL, NULL, NULL,
287 		      PRE_KERNEL_1, CONFIG_INTC_INIT_PRIORITY, NULL);
288 
289 #ifdef CONFIG_SMP
arm_gic_secondary_init(void)290 void arm_gic_secondary_init(void)
291 {
292 	/* Init CPU interface registers for each secondary core */
293 	gic_cpu_init();
294 }
295 #endif
296