xref: /rk3399_ARM-atf/plat/common/plat_gicv2.c (revision ab80cf35e7b7cc2730d1806348024416833e23f2)
1f14d1886SSoby Mathew /*
2*ab80cf35SMadhukar Pappireddy  * Copyright (c) 2015-2023, Arm Limited and Contributors. All rights reserved.
3dcb31ff7SFlorian Lugou  * Portions copyright (c) 2021-2022, ProvenRun S.A.S. All rights reserved.
4f14d1886SSoby Mathew  *
582cb2c1aSdp-arm  * SPDX-License-Identifier: BSD-3-Clause
6f14d1886SSoby Mathew  */
709d40e0eSAntonio Nino Diaz 
8f14d1886SSoby Mathew #include <assert.h>
9e0ced7a9SAntonio Nino Diaz #include <stdbool.h>
10f14d1886SSoby Mathew 
1109d40e0eSAntonio Nino Diaz #include <bl31/interrupt_mgmt.h>
1209d40e0eSAntonio Nino Diaz #include <drivers/arm/gic_common.h>
1309d40e0eSAntonio Nino Diaz #include <drivers/arm/gicv2.h>
1409d40e0eSAntonio Nino Diaz #include <plat/common/platform.h>
1509d40e0eSAntonio Nino Diaz 
16f14d1886SSoby Mathew /*
17f14d1886SSoby Mathew  * The following platform GIC functions are weakly defined. They
18f14d1886SSoby Mathew  * provide typical implementations that may be re-used by multiple
19f14d1886SSoby Mathew  * platforms but may also be overridden by a platform if required.
20f14d1886SSoby Mathew  */
21f14d1886SSoby Mathew #pragma weak plat_ic_get_pending_interrupt_id
22f14d1886SSoby Mathew #pragma weak plat_ic_get_pending_interrupt_type
23f14d1886SSoby Mathew #pragma weak plat_ic_acknowledge_interrupt
24f14d1886SSoby Mathew #pragma weak plat_ic_get_interrupt_type
25f14d1886SSoby Mathew #pragma weak plat_ic_end_of_interrupt
26f14d1886SSoby Mathew #pragma weak plat_interrupt_type_to_line
27f14d1886SSoby Mathew 
28eb68ea9bSJeenu Viswambharan #pragma weak plat_ic_get_running_priority
29ca43b55dSJeenu Viswambharan #pragma weak plat_ic_is_spi
30ca43b55dSJeenu Viswambharan #pragma weak plat_ic_is_ppi
31ca43b55dSJeenu Viswambharan #pragma weak plat_ic_is_sgi
32cbd3f370SJeenu Viswambharan #pragma weak plat_ic_get_interrupt_active
33979225f4SJeenu Viswambharan #pragma weak plat_ic_enable_interrupt
34979225f4SJeenu Viswambharan #pragma weak plat_ic_disable_interrupt
35f3a86600SJeenu Viswambharan #pragma weak plat_ic_set_interrupt_priority
3674dce7faSJeenu Viswambharan #pragma weak plat_ic_set_interrupt_type
378db978b5SJeenu Viswambharan #pragma weak plat_ic_raise_el3_sgi
38dcb31ff7SFlorian Lugou #pragma weak plat_ic_raise_ns_sgi
39dcb31ff7SFlorian Lugou #pragma weak plat_ic_raise_s_el1_sgi
40fc529feeSJeenu Viswambharan #pragma weak plat_ic_set_spi_routing
41eb68ea9bSJeenu Viswambharan 
42f14d1886SSoby Mathew /*
43f14d1886SSoby Mathew  * This function returns the highest priority pending interrupt at
44f14d1886SSoby Mathew  * the Interrupt controller
45f14d1886SSoby Mathew  */
46f14d1886SSoby Mathew uint32_t plat_ic_get_pending_interrupt_id(void)
47f14d1886SSoby Mathew {
48f14d1886SSoby Mathew 	unsigned int id;
49f14d1886SSoby Mathew 
50f14d1886SSoby Mathew 	id = gicv2_get_pending_interrupt_id();
51f14d1886SSoby Mathew 	if (id == GIC_SPURIOUS_INTERRUPT)
52f14d1886SSoby Mathew 		return INTR_ID_UNAVAILABLE;
53f14d1886SSoby Mathew 
54f14d1886SSoby Mathew 	return id;
55f14d1886SSoby Mathew }
56f14d1886SSoby Mathew 
57f14d1886SSoby Mathew /*
58f14d1886SSoby Mathew  * This function returns the type of the highest priority pending interrupt
59f14d1886SSoby Mathew  * at the Interrupt controller. In the case of GICv2, the Highest Priority
60f14d1886SSoby Mathew  * Pending interrupt register (`GICC_HPPIR`) is read to determine the id of
61f14d1886SSoby Mathew  * the pending interrupt. The type of interrupt depends upon the id value
62f14d1886SSoby Mathew  * as follows.
63f14d1886SSoby Mathew  *   1. id < PENDING_G1_INTID (1022) is reported as a S-EL1 interrupt
64f14d1886SSoby Mathew  *   2. id = PENDING_G1_INTID (1022) is reported as a Non-secure interrupt.
65f14d1886SSoby Mathew  *   3. id = GIC_SPURIOUS_INTERRUPT (1023) is reported as an invalid interrupt
66f14d1886SSoby Mathew  *           type.
67f14d1886SSoby Mathew  */
68f14d1886SSoby Mathew uint32_t plat_ic_get_pending_interrupt_type(void)
69f14d1886SSoby Mathew {
70f14d1886SSoby Mathew 	unsigned int id;
71f14d1886SSoby Mathew 
72f14d1886SSoby Mathew 	id = gicv2_get_pending_interrupt_type();
73f14d1886SSoby Mathew 
74f14d1886SSoby Mathew 	/* Assume that all secure interrupts are S-EL1 interrupts */
7574dce7faSJeenu Viswambharan 	if (id < PENDING_G1_INTID) {
7674dce7faSJeenu Viswambharan #if GICV2_G0_FOR_EL3
7774dce7faSJeenu Viswambharan 		return INTR_TYPE_EL3;
7874dce7faSJeenu Viswambharan #else
79f14d1886SSoby Mathew 		return INTR_TYPE_S_EL1;
8074dce7faSJeenu Viswambharan #endif
8174dce7faSJeenu Viswambharan 	}
82f14d1886SSoby Mathew 
83f14d1886SSoby Mathew 	if (id == GIC_SPURIOUS_INTERRUPT)
84f14d1886SSoby Mathew 		return INTR_TYPE_INVAL;
85f14d1886SSoby Mathew 
86f14d1886SSoby Mathew 	return INTR_TYPE_NS;
87f14d1886SSoby Mathew }
88f14d1886SSoby Mathew 
89f14d1886SSoby Mathew /*
90f14d1886SSoby Mathew  * This function returns the highest priority pending interrupt at
91f14d1886SSoby Mathew  * the Interrupt controller and indicates to the Interrupt controller
92f14d1886SSoby Mathew  * that the interrupt processing has started.
93f14d1886SSoby Mathew  */
94f14d1886SSoby Mathew uint32_t plat_ic_acknowledge_interrupt(void)
95f14d1886SSoby Mathew {
96f14d1886SSoby Mathew 	return gicv2_acknowledge_interrupt();
97f14d1886SSoby Mathew }
98f14d1886SSoby Mathew 
99f14d1886SSoby Mathew /*
100f14d1886SSoby Mathew  * This function returns the type of the interrupt `id`, depending on how
101f14d1886SSoby Mathew  * the interrupt has been configured in the interrupt controller
102f14d1886SSoby Mathew  */
103f14d1886SSoby Mathew uint32_t plat_ic_get_interrupt_type(uint32_t id)
104f14d1886SSoby Mathew {
105f14d1886SSoby Mathew 	unsigned int type;
106f14d1886SSoby Mathew 
107f14d1886SSoby Mathew 	type = gicv2_get_interrupt_group(id);
108f14d1886SSoby Mathew 
109f14d1886SSoby Mathew 	/* Assume that all secure interrupts are S-EL1 interrupts */
110e0ced7a9SAntonio Nino Diaz 	return (type == GICV2_INTR_GROUP1) ? INTR_TYPE_NS :
11174dce7faSJeenu Viswambharan #if GICV2_G0_FOR_EL3
11274dce7faSJeenu Viswambharan 		INTR_TYPE_EL3;
11374dce7faSJeenu Viswambharan #else
11474dce7faSJeenu Viswambharan 		INTR_TYPE_S_EL1;
11574dce7faSJeenu Viswambharan #endif
116f14d1886SSoby Mathew }
117f14d1886SSoby Mathew 
118f14d1886SSoby Mathew /*
119f14d1886SSoby Mathew  * This functions is used to indicate to the interrupt controller that
120f14d1886SSoby Mathew  * the processing of the interrupt corresponding to the `id` has
121f14d1886SSoby Mathew  * finished.
122f14d1886SSoby Mathew  */
123f14d1886SSoby Mathew void plat_ic_end_of_interrupt(uint32_t id)
124f14d1886SSoby Mathew {
125f14d1886SSoby Mathew 	gicv2_end_of_interrupt(id);
126f14d1886SSoby Mathew }
127f14d1886SSoby Mathew 
128f14d1886SSoby Mathew /*
129f14d1886SSoby Mathew  * An ARM processor signals interrupt exceptions through the IRQ and FIQ pins.
130f14d1886SSoby Mathew  * The interrupt controller knows which pin/line it uses to signal a type of
131f14d1886SSoby Mathew  * interrupt. It lets the interrupt management framework determine
132f14d1886SSoby Mathew  * for a type of interrupt and security state, which line should be used in the
133f14d1886SSoby Mathew  * SCR_EL3 to control its routing to EL3. The interrupt line is represented
134f14d1886SSoby Mathew  * as the bit position of the IRQ or FIQ bit in the SCR_EL3.
135f14d1886SSoby Mathew  */
136f14d1886SSoby Mathew uint32_t plat_interrupt_type_to_line(uint32_t type,
137f14d1886SSoby Mathew 				uint32_t security_state)
138f14d1886SSoby Mathew {
139e0ced7a9SAntonio Nino Diaz 	assert((type == INTR_TYPE_S_EL1) || (type == INTR_TYPE_EL3) ||
140e0ced7a9SAntonio Nino Diaz 	       (type == INTR_TYPE_NS));
141f14d1886SSoby Mathew 
14253a98be3SSanteri Salko 	assert(sec_state_is_valid(security_state));
14353a98be3SSanteri Salko 
144f14d1886SSoby Mathew 	/* Non-secure interrupts are signaled on the IRQ line always */
145f14d1886SSoby Mathew 	if (type == INTR_TYPE_NS)
146f14d1886SSoby Mathew 		return __builtin_ctz(SCR_IRQ_BIT);
147f14d1886SSoby Mathew 
148f14d1886SSoby Mathew 	/*
149f14d1886SSoby Mathew 	 * Secure interrupts are signaled using the IRQ line if the FIQ is
150f14d1886SSoby Mathew 	 * not enabled else they are signaled using the FIQ line.
151f14d1886SSoby Mathew 	 */
152e0ced7a9SAntonio Nino Diaz 	return ((gicv2_is_fiq_enabled() != 0U) ? __builtin_ctz(SCR_FIQ_BIT) :
153f14d1886SSoby Mathew 						 __builtin_ctz(SCR_IRQ_BIT));
154f14d1886SSoby Mathew }
155eb68ea9bSJeenu Viswambharan 
156eb68ea9bSJeenu Viswambharan unsigned int plat_ic_get_running_priority(void)
157eb68ea9bSJeenu Viswambharan {
158eb68ea9bSJeenu Viswambharan 	return gicv2_get_running_priority();
159eb68ea9bSJeenu Viswambharan }
160ca43b55dSJeenu Viswambharan 
161ca43b55dSJeenu Viswambharan int plat_ic_is_spi(unsigned int id)
162ca43b55dSJeenu Viswambharan {
163ca43b55dSJeenu Viswambharan 	return (id >= MIN_SPI_ID) && (id <= MAX_SPI_ID);
164ca43b55dSJeenu Viswambharan }
165ca43b55dSJeenu Viswambharan 
166ca43b55dSJeenu Viswambharan int plat_ic_is_ppi(unsigned int id)
167ca43b55dSJeenu Viswambharan {
168ca43b55dSJeenu Viswambharan 	return (id >= MIN_PPI_ID) && (id < MIN_SPI_ID);
169ca43b55dSJeenu Viswambharan }
170ca43b55dSJeenu Viswambharan 
171ca43b55dSJeenu Viswambharan int plat_ic_is_sgi(unsigned int id)
172ca43b55dSJeenu Viswambharan {
173ca43b55dSJeenu Viswambharan 	return (id >= MIN_SGI_ID) && (id < MIN_PPI_ID);
174ca43b55dSJeenu Viswambharan }
175cbd3f370SJeenu Viswambharan 
176cbd3f370SJeenu Viswambharan unsigned int plat_ic_get_interrupt_active(unsigned int id)
177cbd3f370SJeenu Viswambharan {
178cbd3f370SJeenu Viswambharan 	return gicv2_get_interrupt_active(id);
179cbd3f370SJeenu Viswambharan }
180979225f4SJeenu Viswambharan 
181979225f4SJeenu Viswambharan void plat_ic_enable_interrupt(unsigned int id)
182979225f4SJeenu Viswambharan {
183979225f4SJeenu Viswambharan 	gicv2_enable_interrupt(id);
184979225f4SJeenu Viswambharan }
185979225f4SJeenu Viswambharan 
186979225f4SJeenu Viswambharan void plat_ic_disable_interrupt(unsigned int id)
187979225f4SJeenu Viswambharan {
188979225f4SJeenu Viswambharan 	gicv2_disable_interrupt(id);
189979225f4SJeenu Viswambharan }
190f3a86600SJeenu Viswambharan 
191f3a86600SJeenu Viswambharan void plat_ic_set_interrupt_priority(unsigned int id, unsigned int priority)
192f3a86600SJeenu Viswambharan {
193f3a86600SJeenu Viswambharan 	gicv2_set_interrupt_priority(id, priority);
194f3a86600SJeenu Viswambharan }
19574dce7faSJeenu Viswambharan 
19674dce7faSJeenu Viswambharan int plat_ic_has_interrupt_type(unsigned int type)
19774dce7faSJeenu Viswambharan {
198649c48f5SJonathan Wright 	int has_interrupt_type = 0;
199649c48f5SJonathan Wright 
20074dce7faSJeenu Viswambharan 	switch (type) {
20174dce7faSJeenu Viswambharan #if GICV2_G0_FOR_EL3
20274dce7faSJeenu Viswambharan 	case INTR_TYPE_EL3:
20374dce7faSJeenu Viswambharan #else
20474dce7faSJeenu Viswambharan 	case INTR_TYPE_S_EL1:
20574dce7faSJeenu Viswambharan #endif
20674dce7faSJeenu Viswambharan 	case INTR_TYPE_NS:
207649c48f5SJonathan Wright 		has_interrupt_type = 1;
208649c48f5SJonathan Wright 		break;
20974dce7faSJeenu Viswambharan 	default:
210649c48f5SJonathan Wright 		/* Do nothing in default case */
211649c48f5SJonathan Wright 		break;
21274dce7faSJeenu Viswambharan 	}
213649c48f5SJonathan Wright 
214649c48f5SJonathan Wright 	return has_interrupt_type;
21574dce7faSJeenu Viswambharan }
21674dce7faSJeenu Viswambharan 
21774dce7faSJeenu Viswambharan void plat_ic_set_interrupt_type(unsigned int id, unsigned int type)
21874dce7faSJeenu Viswambharan {
219*ab80cf35SMadhukar Pappireddy 	unsigned int gicv2_group = 0U;
22074dce7faSJeenu Viswambharan 
22174dce7faSJeenu Viswambharan 	/* Map canonical interrupt type to GICv2 type */
22274dce7faSJeenu Viswambharan 	switch (type) {
22374dce7faSJeenu Viswambharan #if GICV2_G0_FOR_EL3
22474dce7faSJeenu Viswambharan 	case INTR_TYPE_EL3:
22574dce7faSJeenu Viswambharan #else
22674dce7faSJeenu Viswambharan 	case INTR_TYPE_S_EL1:
22774dce7faSJeenu Viswambharan #endif
228*ab80cf35SMadhukar Pappireddy 		gicv2_group = GICV2_INTR_GROUP0;
22974dce7faSJeenu Viswambharan 		break;
23074dce7faSJeenu Viswambharan 	case INTR_TYPE_NS:
231*ab80cf35SMadhukar Pappireddy 		gicv2_group = GICV2_INTR_GROUP1;
23274dce7faSJeenu Viswambharan 		break;
23374dce7faSJeenu Viswambharan 	default:
234*ab80cf35SMadhukar Pappireddy 		assert(false); /* Unreachable */
235649c48f5SJonathan Wright 		break;
23674dce7faSJeenu Viswambharan 	}
23774dce7faSJeenu Viswambharan 
238*ab80cf35SMadhukar Pappireddy 	gicv2_set_interrupt_group(id, gicv2_group);
23974dce7faSJeenu Viswambharan }
2408db978b5SJeenu Viswambharan 
2418db978b5SJeenu Viswambharan void plat_ic_raise_el3_sgi(int sgi_num, u_register_t target)
2428db978b5SJeenu Viswambharan {
2438db978b5SJeenu Viswambharan #if GICV2_G0_FOR_EL3
2448db978b5SJeenu Viswambharan 	int id;
2458db978b5SJeenu Viswambharan 
2468db978b5SJeenu Viswambharan 	/* Target must be a valid MPIDR in the system */
2478db978b5SJeenu Viswambharan 	id = plat_core_pos_by_mpidr(target);
2488db978b5SJeenu Viswambharan 	assert(id >= 0);
2498db978b5SJeenu Viswambharan 
2508db978b5SJeenu Viswambharan 	/* Verify that this is a secure SGI */
2518db978b5SJeenu Viswambharan 	assert(plat_ic_get_interrupt_type(sgi_num) == INTR_TYPE_EL3);
2528db978b5SJeenu Viswambharan 
253dcb31ff7SFlorian Lugou 	gicv2_raise_sgi(sgi_num, false, id);
2548db978b5SJeenu Viswambharan #else
255e0ced7a9SAntonio Nino Diaz 	assert(false);
2568db978b5SJeenu Viswambharan #endif
2578db978b5SJeenu Viswambharan }
258fc529feeSJeenu Viswambharan 
259dcb31ff7SFlorian Lugou void plat_ic_raise_ns_sgi(int sgi_num, u_register_t target)
260dcb31ff7SFlorian Lugou {
261dcb31ff7SFlorian Lugou 	int id;
262dcb31ff7SFlorian Lugou 
263dcb31ff7SFlorian Lugou 	/* Target must be a valid MPIDR in the system */
264dcb31ff7SFlorian Lugou 	id = plat_core_pos_by_mpidr(target);
265dcb31ff7SFlorian Lugou 	assert(id >= 0);
266dcb31ff7SFlorian Lugou 
267dcb31ff7SFlorian Lugou 	/* Verify that this is a non-secure SGI */
268dcb31ff7SFlorian Lugou 	assert(plat_ic_get_interrupt_type(sgi_num) == INTR_TYPE_NS);
269dcb31ff7SFlorian Lugou 
270dcb31ff7SFlorian Lugou 	gicv2_raise_sgi(sgi_num, true, id);
271dcb31ff7SFlorian Lugou }
272dcb31ff7SFlorian Lugou 
273dcb31ff7SFlorian Lugou void plat_ic_raise_s_el1_sgi(int sgi_num, u_register_t target)
274dcb31ff7SFlorian Lugou {
275dcb31ff7SFlorian Lugou #if GICV2_G0_FOR_EL3
276dcb31ff7SFlorian Lugou 	assert(false);
277dcb31ff7SFlorian Lugou #else
278dcb31ff7SFlorian Lugou 	int id;
279dcb31ff7SFlorian Lugou 
280dcb31ff7SFlorian Lugou 	/* Target must be a valid MPIDR in the system */
281dcb31ff7SFlorian Lugou 	id = plat_core_pos_by_mpidr(target);
282dcb31ff7SFlorian Lugou 	assert(id >= 0);
283dcb31ff7SFlorian Lugou 
284dcb31ff7SFlorian Lugou 	/* Verify that this is a secure EL1 SGI */
285dcb31ff7SFlorian Lugou 	assert(plat_ic_get_interrupt_type(sgi_num) == INTR_TYPE_S_EL1);
286dcb31ff7SFlorian Lugou 
287dcb31ff7SFlorian Lugou 	gicv2_raise_sgi(sgi_num, false, id);
288dcb31ff7SFlorian Lugou #endif
289dcb31ff7SFlorian Lugou }
290dcb31ff7SFlorian Lugou 
291fc529feeSJeenu Viswambharan void plat_ic_set_spi_routing(unsigned int id, unsigned int routing_mode,
292fc529feeSJeenu Viswambharan 		u_register_t mpidr)
293fc529feeSJeenu Viswambharan {
294fc529feeSJeenu Viswambharan 	int proc_num = 0;
295fc529feeSJeenu Viswambharan 
296fc529feeSJeenu Viswambharan 	switch (routing_mode) {
297fc529feeSJeenu Viswambharan 	case INTR_ROUTING_MODE_PE:
298fc529feeSJeenu Viswambharan 		proc_num = plat_core_pos_by_mpidr(mpidr);
299fc529feeSJeenu Viswambharan 		assert(proc_num >= 0);
300fc529feeSJeenu Viswambharan 		break;
301fc529feeSJeenu Viswambharan 	case INTR_ROUTING_MODE_ANY:
302fc529feeSJeenu Viswambharan 		/* Bit mask selecting all 8 CPUs as candidates */
303fc529feeSJeenu Viswambharan 		proc_num = -1;
304fc529feeSJeenu Viswambharan 		break;
305fc529feeSJeenu Viswambharan 	default:
306a08a2014SDaniel Boulby 		assert(0); /* Unreachable */
307649c48f5SJonathan Wright 		break;
308fc529feeSJeenu Viswambharan 	}
309fc529feeSJeenu Viswambharan 
310fc529feeSJeenu Viswambharan 	gicv2_set_spi_routing(id, proc_num);
311fc529feeSJeenu Viswambharan }
312a2816a16SJeenu Viswambharan 
313a2816a16SJeenu Viswambharan void plat_ic_set_interrupt_pending(unsigned int id)
314a2816a16SJeenu Viswambharan {
315a2816a16SJeenu Viswambharan 	gicv2_set_interrupt_pending(id);
316a2816a16SJeenu Viswambharan }
317a2816a16SJeenu Viswambharan 
318a2816a16SJeenu Viswambharan void plat_ic_clear_interrupt_pending(unsigned int id)
319a2816a16SJeenu Viswambharan {
320a2816a16SJeenu Viswambharan 	gicv2_clear_interrupt_pending(id);
321a2816a16SJeenu Viswambharan }
322d55a4450SJeenu Viswambharan 
323d55a4450SJeenu Viswambharan unsigned int plat_ic_set_priority_mask(unsigned int mask)
324d55a4450SJeenu Viswambharan {
325d55a4450SJeenu Viswambharan 	return gicv2_set_pmr(mask);
326d55a4450SJeenu Viswambharan }
3274ee8d0beSJeenu Viswambharan 
3284ee8d0beSJeenu Viswambharan unsigned int plat_ic_get_interrupt_id(unsigned int raw)
3294ee8d0beSJeenu Viswambharan {
3304ee8d0beSJeenu Viswambharan 	unsigned int id = (raw & INT_ID_MASK);
3314ee8d0beSJeenu Viswambharan 
3324ee8d0beSJeenu Viswambharan 	if (id == GIC_SPURIOUS_INTERRUPT)
3334ee8d0beSJeenu Viswambharan 		id = INTR_ID_UNAVAILABLE;
3344ee8d0beSJeenu Viswambharan 
3354ee8d0beSJeenu Viswambharan 	return id;
3364ee8d0beSJeenu Viswambharan }
337