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