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 int irq;
117
118 irq = sys_read32(GICC_IAR) & 0x3ff;
119 return irq;
120 }
121
arm_gic_eoi(unsigned int irq)122 void arm_gic_eoi(unsigned int irq)
123 {
124 /*
125 * Ensure the write to peripheral registers are *complete* before the write
126 * to GIC_EOIR.
127 *
128 * Note: The completion guarantee depends on various factors of system design
129 * and the barrier is the best core can do by which execution of further
130 * instructions waits till the barrier is alive.
131 */
132 barrier_dsync_fence_full();
133
134 /* set to inactive */
135 sys_write32(irq, GICC_EOIR);
136 }
137
gic_raise_sgi(unsigned int sgi_id,uint64_t target_aff,uint16_t target_list)138 void gic_raise_sgi(unsigned int sgi_id, uint64_t target_aff,
139 uint16_t target_list)
140 {
141 uint32_t sgi_val;
142
143 ARG_UNUSED(target_aff);
144
145 sgi_val = GICD_SGIR_TGTFILT_CPULIST |
146 GICD_SGIR_CPULIST(target_list & GICD_SGIR_CPULIST_MASK) |
147 sgi_id;
148
149 barrier_dsync_fence_full();
150 sys_write32(sgi_val, GICD_SGIR);
151 barrier_isync_fence_full();
152 }
153
gic_dist_init(void)154 static void gic_dist_init(void)
155 {
156 unsigned int gic_irqs, i;
157 uint8_t cpu_mask = 0;
158 uint32_t reg_val;
159
160 gic_irqs = sys_read32(GICD_TYPER) & 0x1f;
161 gic_irqs = (gic_irqs + 1) * 32;
162 if (gic_irqs > 1020) {
163 gic_irqs = 1020;
164 }
165
166 /*
167 * Disable the forwarding of pending interrupts
168 * from the Distributor to the CPU interfaces
169 */
170 sys_write32(0, GICD_CTLR);
171
172 /*
173 * Enable all global interrupts distributing to CPUs listed
174 * in dts with the count of arch_num_cpus().
175 */
176 unsigned int num_cpus = arch_num_cpus();
177
178 for (i = 0; i < num_cpus; i++) {
179 cpu_mask |= BIT(cpu_mpid_list[i]);
180 }
181 reg_val = cpu_mask | (cpu_mask << 8) | (cpu_mask << 16)
182 | (cpu_mask << 24);
183 for (i = GIC_SPI_INT_BASE; i < gic_irqs; i += 4) {
184 sys_write32(reg_val, GICD_ITARGETSRn + i);
185 }
186
187 /*
188 * Set all global interrupts to be level triggered, active low.
189 */
190 for (i = GIC_SPI_INT_BASE; i < gic_irqs; i += 16) {
191 sys_write32(0, GICD_ICFGRn + i / 4);
192 }
193
194 /* Set priority on all global interrupts. */
195 for (i = GIC_SPI_INT_BASE; i < gic_irqs; i += 4) {
196 sys_write32(0, GICD_IPRIORITYRn + i);
197 }
198
199 /* Set all interrupts to group 0 */
200 for (i = GIC_SPI_INT_BASE; i < gic_irqs; i += 32) {
201 sys_write32(0, GICD_IGROUPRn + i / 8);
202 }
203
204 /*
205 * Disable all interrupts. Leave the PPI and SGIs alone
206 * as these enables are banked registers.
207 */
208 for (i = GIC_SPI_INT_BASE; i < gic_irqs; i += 32) {
209 #ifndef CONFIG_GIC_V1
210 sys_write32(0xffffffff, GICD_ICACTIVERn + i / 8);
211 #endif
212 sys_write32(0xffffffff, GICD_ICENABLERn + i / 8);
213 }
214
215 /*
216 * Enable the forwarding of pending interrupts
217 * from the Distributor to the CPU interfaces
218 */
219 sys_write32(1, GICD_CTLR);
220 }
221
gic_cpu_init(void)222 static void gic_cpu_init(void)
223 {
224 int i;
225 uint32_t val;
226
227 /*
228 * Deal with the banked PPI and SGI interrupts - disable all
229 * PPI interrupts, ensure all SGI interrupts are enabled.
230 */
231 #ifndef CONFIG_GIC_V1
232 sys_write32(0xffffffff, GICD_ICACTIVERn);
233 #endif
234 sys_write32(0xffff0000, GICD_ICENABLERn);
235 sys_write32(0x0000ffff, GICD_ISENABLERn);
236
237 /*
238 * Set priority on PPI and SGI interrupts
239 */
240 for (i = 0; i < 32; i += 4) {
241 sys_write32(0xa0a0a0a0, GICD_IPRIORITYRn + i);
242 }
243
244 sys_write32(0xf0, GICC_PMR);
245
246 /*
247 * Enable interrupts and signal them using the IRQ signal.
248 */
249 val = sys_read32(GICC_CTLR);
250 #ifndef CONFIG_GIC_V1
251 val &= ~GICC_CTLR_BYPASS_MASK;
252 #endif
253 val |= GICC_CTLR_ENABLE_MASK;
254 sys_write32(val, GICC_CTLR);
255 }
256
257 #define GIC_PARENT_IRQ 0
258 #define GIC_PARENT_IRQ_PRI 0
259 #define GIC_PARENT_IRQ_FLAGS 0
260
261 /**
262 * @brief Initialize the GIC device driver
263 */
arm_gic_init(const struct device * dev)264 int arm_gic_init(const struct device *dev)
265 {
266 /* Init of Distributor interface registers */
267 gic_dist_init();
268
269 /* Init CPU interface registers */
270 gic_cpu_init();
271
272 return 0;
273 }
274
275 DEVICE_DT_INST_DEFINE(0, arm_gic_init, NULL, NULL, NULL,
276 PRE_KERNEL_1, CONFIG_INTC_INIT_PRIORITY, NULL);
277
278 #ifdef CONFIG_SMP
arm_gic_secondary_init(void)279 void arm_gic_secondary_init(void)
280 {
281 /* Init CPU interface registers for each secondary core */
282 gic_cpu_init();
283 }
284 #endif
285