xref: /arm-trusted-firmware/plat/common/plat_gicv2.c (revision 91f16700b400a8c0651d24a598fc48ee2997a0d7)
1*91f16700Schasinglulu /*
2*91f16700Schasinglulu  * Copyright (c) 2015-2023, Arm Limited and Contributors. All rights reserved.
3*91f16700Schasinglulu  * Portions copyright (c) 2021-2022, ProvenRun S.A.S. All rights reserved.
4*91f16700Schasinglulu  *
5*91f16700Schasinglulu  * SPDX-License-Identifier: BSD-3-Clause
6*91f16700Schasinglulu  */
7*91f16700Schasinglulu 
8*91f16700Schasinglulu #include <assert.h>
9*91f16700Schasinglulu #include <stdbool.h>
10*91f16700Schasinglulu 
11*91f16700Schasinglulu #include <bl31/interrupt_mgmt.h>
12*91f16700Schasinglulu #include <drivers/arm/gic_common.h>
13*91f16700Schasinglulu #include <drivers/arm/gicv2.h>
14*91f16700Schasinglulu #include <plat/common/platform.h>
15*91f16700Schasinglulu 
16*91f16700Schasinglulu /*
17*91f16700Schasinglulu  * The following platform GIC functions are weakly defined. They
18*91f16700Schasinglulu  * provide typical implementations that may be re-used by multiple
19*91f16700Schasinglulu  * platforms but may also be overridden by a platform if required.
20*91f16700Schasinglulu  */
21*91f16700Schasinglulu #pragma weak plat_ic_get_pending_interrupt_id
22*91f16700Schasinglulu #pragma weak plat_ic_get_pending_interrupt_type
23*91f16700Schasinglulu #pragma weak plat_ic_acknowledge_interrupt
24*91f16700Schasinglulu #pragma weak plat_ic_get_interrupt_type
25*91f16700Schasinglulu #pragma weak plat_ic_end_of_interrupt
26*91f16700Schasinglulu #pragma weak plat_interrupt_type_to_line
27*91f16700Schasinglulu 
28*91f16700Schasinglulu #pragma weak plat_ic_get_running_priority
29*91f16700Schasinglulu #pragma weak plat_ic_is_spi
30*91f16700Schasinglulu #pragma weak plat_ic_is_ppi
31*91f16700Schasinglulu #pragma weak plat_ic_is_sgi
32*91f16700Schasinglulu #pragma weak plat_ic_get_interrupt_active
33*91f16700Schasinglulu #pragma weak plat_ic_enable_interrupt
34*91f16700Schasinglulu #pragma weak plat_ic_disable_interrupt
35*91f16700Schasinglulu #pragma weak plat_ic_set_interrupt_priority
36*91f16700Schasinglulu #pragma weak plat_ic_set_interrupt_type
37*91f16700Schasinglulu #pragma weak plat_ic_raise_el3_sgi
38*91f16700Schasinglulu #pragma weak plat_ic_raise_ns_sgi
39*91f16700Schasinglulu #pragma weak plat_ic_raise_s_el1_sgi
40*91f16700Schasinglulu #pragma weak plat_ic_set_spi_routing
41*91f16700Schasinglulu 
42*91f16700Schasinglulu /*
43*91f16700Schasinglulu  * This function returns the highest priority pending interrupt at
44*91f16700Schasinglulu  * the Interrupt controller
45*91f16700Schasinglulu  */
46*91f16700Schasinglulu uint32_t plat_ic_get_pending_interrupt_id(void)
47*91f16700Schasinglulu {
48*91f16700Schasinglulu 	unsigned int id;
49*91f16700Schasinglulu 
50*91f16700Schasinglulu 	id = gicv2_get_pending_interrupt_id();
51*91f16700Schasinglulu 	if (id == GIC_SPURIOUS_INTERRUPT)
52*91f16700Schasinglulu 		return INTR_ID_UNAVAILABLE;
53*91f16700Schasinglulu 
54*91f16700Schasinglulu 	return id;
55*91f16700Schasinglulu }
56*91f16700Schasinglulu 
57*91f16700Schasinglulu /*
58*91f16700Schasinglulu  * This function returns the type of the highest priority pending interrupt
59*91f16700Schasinglulu  * at the Interrupt controller. In the case of GICv2, the Highest Priority
60*91f16700Schasinglulu  * Pending interrupt register (`GICC_HPPIR`) is read to determine the id of
61*91f16700Schasinglulu  * the pending interrupt. The type of interrupt depends upon the id value
62*91f16700Schasinglulu  * as follows.
63*91f16700Schasinglulu  *   1. id < PENDING_G1_INTID (1022) is reported as a S-EL1 interrupt
64*91f16700Schasinglulu  *   2. id = PENDING_G1_INTID (1022) is reported as a Non-secure interrupt.
65*91f16700Schasinglulu  *   3. id = GIC_SPURIOUS_INTERRUPT (1023) is reported as an invalid interrupt
66*91f16700Schasinglulu  *           type.
67*91f16700Schasinglulu  */
68*91f16700Schasinglulu uint32_t plat_ic_get_pending_interrupt_type(void)
69*91f16700Schasinglulu {
70*91f16700Schasinglulu 	unsigned int id;
71*91f16700Schasinglulu 
72*91f16700Schasinglulu 	id = gicv2_get_pending_interrupt_type();
73*91f16700Schasinglulu 
74*91f16700Schasinglulu 	/* Assume that all secure interrupts are S-EL1 interrupts */
75*91f16700Schasinglulu 	if (id < PENDING_G1_INTID) {
76*91f16700Schasinglulu #if GICV2_G0_FOR_EL3
77*91f16700Schasinglulu 		return INTR_TYPE_EL3;
78*91f16700Schasinglulu #else
79*91f16700Schasinglulu 		return INTR_TYPE_S_EL1;
80*91f16700Schasinglulu #endif
81*91f16700Schasinglulu 	}
82*91f16700Schasinglulu 
83*91f16700Schasinglulu 	if (id == GIC_SPURIOUS_INTERRUPT)
84*91f16700Schasinglulu 		return INTR_TYPE_INVAL;
85*91f16700Schasinglulu 
86*91f16700Schasinglulu 	return INTR_TYPE_NS;
87*91f16700Schasinglulu }
88*91f16700Schasinglulu 
89*91f16700Schasinglulu /*
90*91f16700Schasinglulu  * This function returns the highest priority pending interrupt at
91*91f16700Schasinglulu  * the Interrupt controller and indicates to the Interrupt controller
92*91f16700Schasinglulu  * that the interrupt processing has started.
93*91f16700Schasinglulu  */
94*91f16700Schasinglulu uint32_t plat_ic_acknowledge_interrupt(void)
95*91f16700Schasinglulu {
96*91f16700Schasinglulu 	return gicv2_acknowledge_interrupt();
97*91f16700Schasinglulu }
98*91f16700Schasinglulu 
99*91f16700Schasinglulu /*
100*91f16700Schasinglulu  * This function returns the type of the interrupt `id`, depending on how
101*91f16700Schasinglulu  * the interrupt has been configured in the interrupt controller
102*91f16700Schasinglulu  */
103*91f16700Schasinglulu uint32_t plat_ic_get_interrupt_type(uint32_t id)
104*91f16700Schasinglulu {
105*91f16700Schasinglulu 	unsigned int type;
106*91f16700Schasinglulu 
107*91f16700Schasinglulu 	type = gicv2_get_interrupt_group(id);
108*91f16700Schasinglulu 
109*91f16700Schasinglulu 	/* Assume that all secure interrupts are S-EL1 interrupts */
110*91f16700Schasinglulu 	return (type == GICV2_INTR_GROUP1) ? INTR_TYPE_NS :
111*91f16700Schasinglulu #if GICV2_G0_FOR_EL3
112*91f16700Schasinglulu 		INTR_TYPE_EL3;
113*91f16700Schasinglulu #else
114*91f16700Schasinglulu 		INTR_TYPE_S_EL1;
115*91f16700Schasinglulu #endif
116*91f16700Schasinglulu }
117*91f16700Schasinglulu 
118*91f16700Schasinglulu /*
119*91f16700Schasinglulu  * This functions is used to indicate to the interrupt controller that
120*91f16700Schasinglulu  * the processing of the interrupt corresponding to the `id` has
121*91f16700Schasinglulu  * finished.
122*91f16700Schasinglulu  */
123*91f16700Schasinglulu void plat_ic_end_of_interrupt(uint32_t id)
124*91f16700Schasinglulu {
125*91f16700Schasinglulu 	gicv2_end_of_interrupt(id);
126*91f16700Schasinglulu }
127*91f16700Schasinglulu 
128*91f16700Schasinglulu /*
129*91f16700Schasinglulu  * An ARM processor signals interrupt exceptions through the IRQ and FIQ pins.
130*91f16700Schasinglulu  * The interrupt controller knows which pin/line it uses to signal a type of
131*91f16700Schasinglulu  * interrupt. It lets the interrupt management framework determine
132*91f16700Schasinglulu  * for a type of interrupt and security state, which line should be used in the
133*91f16700Schasinglulu  * SCR_EL3 to control its routing to EL3. The interrupt line is represented
134*91f16700Schasinglulu  * as the bit position of the IRQ or FIQ bit in the SCR_EL3.
135*91f16700Schasinglulu  */
136*91f16700Schasinglulu uint32_t plat_interrupt_type_to_line(uint32_t type,
137*91f16700Schasinglulu 				uint32_t security_state)
138*91f16700Schasinglulu {
139*91f16700Schasinglulu 	assert((type == INTR_TYPE_S_EL1) || (type == INTR_TYPE_EL3) ||
140*91f16700Schasinglulu 	       (type == INTR_TYPE_NS));
141*91f16700Schasinglulu 
142*91f16700Schasinglulu 	assert(sec_state_is_valid(security_state));
143*91f16700Schasinglulu 
144*91f16700Schasinglulu 	/* Non-secure interrupts are signaled on the IRQ line always */
145*91f16700Schasinglulu 	if (type == INTR_TYPE_NS)
146*91f16700Schasinglulu 		return __builtin_ctz(SCR_IRQ_BIT);
147*91f16700Schasinglulu 
148*91f16700Schasinglulu 	/*
149*91f16700Schasinglulu 	 * Secure interrupts are signaled using the IRQ line if the FIQ is
150*91f16700Schasinglulu 	 * not enabled else they are signaled using the FIQ line.
151*91f16700Schasinglulu 	 */
152*91f16700Schasinglulu 	return ((gicv2_is_fiq_enabled() != 0U) ? __builtin_ctz(SCR_FIQ_BIT) :
153*91f16700Schasinglulu 						 __builtin_ctz(SCR_IRQ_BIT));
154*91f16700Schasinglulu }
155*91f16700Schasinglulu 
156*91f16700Schasinglulu unsigned int plat_ic_get_running_priority(void)
157*91f16700Schasinglulu {
158*91f16700Schasinglulu 	return gicv2_get_running_priority();
159*91f16700Schasinglulu }
160*91f16700Schasinglulu 
161*91f16700Schasinglulu int plat_ic_is_spi(unsigned int id)
162*91f16700Schasinglulu {
163*91f16700Schasinglulu 	return (id >= MIN_SPI_ID) && (id <= MAX_SPI_ID);
164*91f16700Schasinglulu }
165*91f16700Schasinglulu 
166*91f16700Schasinglulu int plat_ic_is_ppi(unsigned int id)
167*91f16700Schasinglulu {
168*91f16700Schasinglulu 	return (id >= MIN_PPI_ID) && (id < MIN_SPI_ID);
169*91f16700Schasinglulu }
170*91f16700Schasinglulu 
171*91f16700Schasinglulu int plat_ic_is_sgi(unsigned int id)
172*91f16700Schasinglulu {
173*91f16700Schasinglulu 	return (id >= MIN_SGI_ID) && (id < MIN_PPI_ID);
174*91f16700Schasinglulu }
175*91f16700Schasinglulu 
176*91f16700Schasinglulu unsigned int plat_ic_get_interrupt_active(unsigned int id)
177*91f16700Schasinglulu {
178*91f16700Schasinglulu 	return gicv2_get_interrupt_active(id);
179*91f16700Schasinglulu }
180*91f16700Schasinglulu 
181*91f16700Schasinglulu void plat_ic_enable_interrupt(unsigned int id)
182*91f16700Schasinglulu {
183*91f16700Schasinglulu 	gicv2_enable_interrupt(id);
184*91f16700Schasinglulu }
185*91f16700Schasinglulu 
186*91f16700Schasinglulu void plat_ic_disable_interrupt(unsigned int id)
187*91f16700Schasinglulu {
188*91f16700Schasinglulu 	gicv2_disable_interrupt(id);
189*91f16700Schasinglulu }
190*91f16700Schasinglulu 
191*91f16700Schasinglulu void plat_ic_set_interrupt_priority(unsigned int id, unsigned int priority)
192*91f16700Schasinglulu {
193*91f16700Schasinglulu 	gicv2_set_interrupt_priority(id, priority);
194*91f16700Schasinglulu }
195*91f16700Schasinglulu 
196*91f16700Schasinglulu bool plat_ic_has_interrupt_type(unsigned int type)
197*91f16700Schasinglulu {
198*91f16700Schasinglulu 	bool has_interrupt_type = false;
199*91f16700Schasinglulu 
200*91f16700Schasinglulu 	switch (type) {
201*91f16700Schasinglulu #if GICV2_G0_FOR_EL3
202*91f16700Schasinglulu 	case INTR_TYPE_EL3:
203*91f16700Schasinglulu #else
204*91f16700Schasinglulu 	case INTR_TYPE_S_EL1:
205*91f16700Schasinglulu #endif
206*91f16700Schasinglulu 	case INTR_TYPE_NS:
207*91f16700Schasinglulu 		has_interrupt_type = true;
208*91f16700Schasinglulu 		break;
209*91f16700Schasinglulu 	default:
210*91f16700Schasinglulu 		/* Do nothing in default case */
211*91f16700Schasinglulu 		break;
212*91f16700Schasinglulu 	}
213*91f16700Schasinglulu 
214*91f16700Schasinglulu 	return has_interrupt_type;
215*91f16700Schasinglulu }
216*91f16700Schasinglulu 
217*91f16700Schasinglulu void plat_ic_set_interrupt_type(unsigned int id, unsigned int type)
218*91f16700Schasinglulu {
219*91f16700Schasinglulu 	unsigned int gicv2_group = 0U;
220*91f16700Schasinglulu 
221*91f16700Schasinglulu 	/* Map canonical interrupt type to GICv2 type */
222*91f16700Schasinglulu 	switch (type) {
223*91f16700Schasinglulu #if GICV2_G0_FOR_EL3
224*91f16700Schasinglulu 	case INTR_TYPE_EL3:
225*91f16700Schasinglulu #else
226*91f16700Schasinglulu 	case INTR_TYPE_S_EL1:
227*91f16700Schasinglulu #endif
228*91f16700Schasinglulu 		gicv2_group = GICV2_INTR_GROUP0;
229*91f16700Schasinglulu 		break;
230*91f16700Schasinglulu 	case INTR_TYPE_NS:
231*91f16700Schasinglulu 		gicv2_group = GICV2_INTR_GROUP1;
232*91f16700Schasinglulu 		break;
233*91f16700Schasinglulu 	default:
234*91f16700Schasinglulu 		assert(false); /* Unreachable */
235*91f16700Schasinglulu 		break;
236*91f16700Schasinglulu 	}
237*91f16700Schasinglulu 
238*91f16700Schasinglulu 	gicv2_set_interrupt_group(id, gicv2_group);
239*91f16700Schasinglulu }
240*91f16700Schasinglulu 
241*91f16700Schasinglulu void plat_ic_raise_el3_sgi(int sgi_num, u_register_t target)
242*91f16700Schasinglulu {
243*91f16700Schasinglulu #if GICV2_G0_FOR_EL3
244*91f16700Schasinglulu 	int id;
245*91f16700Schasinglulu 
246*91f16700Schasinglulu 	/* Target must be a valid MPIDR in the system */
247*91f16700Schasinglulu 	id = plat_core_pos_by_mpidr(target);
248*91f16700Schasinglulu 	assert(id >= 0);
249*91f16700Schasinglulu 
250*91f16700Schasinglulu 	/* Verify that this is a secure SGI */
251*91f16700Schasinglulu 	assert(plat_ic_get_interrupt_type(sgi_num) == INTR_TYPE_EL3);
252*91f16700Schasinglulu 
253*91f16700Schasinglulu 	gicv2_raise_sgi(sgi_num, false, id);
254*91f16700Schasinglulu #else
255*91f16700Schasinglulu 	assert(false);
256*91f16700Schasinglulu #endif
257*91f16700Schasinglulu }
258*91f16700Schasinglulu 
259*91f16700Schasinglulu void plat_ic_raise_ns_sgi(int sgi_num, u_register_t target)
260*91f16700Schasinglulu {
261*91f16700Schasinglulu 	int id;
262*91f16700Schasinglulu 
263*91f16700Schasinglulu 	/* Target must be a valid MPIDR in the system */
264*91f16700Schasinglulu 	id = plat_core_pos_by_mpidr(target);
265*91f16700Schasinglulu 	assert(id >= 0);
266*91f16700Schasinglulu 
267*91f16700Schasinglulu 	/* Verify that this is a non-secure SGI */
268*91f16700Schasinglulu 	assert(plat_ic_get_interrupt_type(sgi_num) == INTR_TYPE_NS);
269*91f16700Schasinglulu 
270*91f16700Schasinglulu 	gicv2_raise_sgi(sgi_num, true, id);
271*91f16700Schasinglulu }
272*91f16700Schasinglulu 
273*91f16700Schasinglulu void plat_ic_raise_s_el1_sgi(int sgi_num, u_register_t target)
274*91f16700Schasinglulu {
275*91f16700Schasinglulu #if GICV2_G0_FOR_EL3
276*91f16700Schasinglulu 	assert(false);
277*91f16700Schasinglulu #else
278*91f16700Schasinglulu 	int id;
279*91f16700Schasinglulu 
280*91f16700Schasinglulu 	/* Target must be a valid MPIDR in the system */
281*91f16700Schasinglulu 	id = plat_core_pos_by_mpidr(target);
282*91f16700Schasinglulu 	assert(id >= 0);
283*91f16700Schasinglulu 
284*91f16700Schasinglulu 	/* Verify that this is a secure EL1 SGI */
285*91f16700Schasinglulu 	assert(plat_ic_get_interrupt_type(sgi_num) == INTR_TYPE_S_EL1);
286*91f16700Schasinglulu 
287*91f16700Schasinglulu 	gicv2_raise_sgi(sgi_num, false, id);
288*91f16700Schasinglulu #endif
289*91f16700Schasinglulu }
290*91f16700Schasinglulu 
291*91f16700Schasinglulu void plat_ic_set_spi_routing(unsigned int id, unsigned int routing_mode,
292*91f16700Schasinglulu 		u_register_t mpidr)
293*91f16700Schasinglulu {
294*91f16700Schasinglulu 	int proc_num = 0;
295*91f16700Schasinglulu 
296*91f16700Schasinglulu 	switch (routing_mode) {
297*91f16700Schasinglulu 	case INTR_ROUTING_MODE_PE:
298*91f16700Schasinglulu 		proc_num = plat_core_pos_by_mpidr(mpidr);
299*91f16700Schasinglulu 		assert(proc_num >= 0);
300*91f16700Schasinglulu 		break;
301*91f16700Schasinglulu 	case INTR_ROUTING_MODE_ANY:
302*91f16700Schasinglulu 		/* Bit mask selecting all 8 CPUs as candidates */
303*91f16700Schasinglulu 		proc_num = -1;
304*91f16700Schasinglulu 		break;
305*91f16700Schasinglulu 	default:
306*91f16700Schasinglulu 		assert(0); /* Unreachable */
307*91f16700Schasinglulu 		break;
308*91f16700Schasinglulu 	}
309*91f16700Schasinglulu 
310*91f16700Schasinglulu 	gicv2_set_spi_routing(id, proc_num);
311*91f16700Schasinglulu }
312*91f16700Schasinglulu 
313*91f16700Schasinglulu void plat_ic_set_interrupt_pending(unsigned int id)
314*91f16700Schasinglulu {
315*91f16700Schasinglulu 	gicv2_set_interrupt_pending(id);
316*91f16700Schasinglulu }
317*91f16700Schasinglulu 
318*91f16700Schasinglulu void plat_ic_clear_interrupt_pending(unsigned int id)
319*91f16700Schasinglulu {
320*91f16700Schasinglulu 	gicv2_clear_interrupt_pending(id);
321*91f16700Schasinglulu }
322*91f16700Schasinglulu 
323*91f16700Schasinglulu unsigned int plat_ic_set_priority_mask(unsigned int mask)
324*91f16700Schasinglulu {
325*91f16700Schasinglulu 	return gicv2_set_pmr(mask);
326*91f16700Schasinglulu }
327*91f16700Schasinglulu 
328*91f16700Schasinglulu unsigned int plat_ic_get_interrupt_id(unsigned int raw)
329*91f16700Schasinglulu {
330*91f16700Schasinglulu 	unsigned int id = (raw & INT_ID_MASK);
331*91f16700Schasinglulu 
332*91f16700Schasinglulu 	if (id == GIC_SPURIOUS_INTERRUPT)
333*91f16700Schasinglulu 		id = INTR_ID_UNAVAILABLE;
334*91f16700Schasinglulu 
335*91f16700Schasinglulu 	return id;
336*91f16700Schasinglulu }
337