xref: /rk3399_ARM-atf/plat/common/plat_gicv2.c (revision 09d40e0e08283a249e7dce0e106c07c5141f9b7e)
1f14d1886SSoby Mathew /*
2e0ced7a9SAntonio Nino Diaz  * Copyright (c) 2015-2018, ARM Limited and Contributors. All rights reserved.
3f14d1886SSoby Mathew  *
482cb2c1aSdp-arm  * SPDX-License-Identifier: BSD-3-Clause
5f14d1886SSoby Mathew  */
6*09d40e0eSAntonio Nino Diaz 
7f14d1886SSoby Mathew #include <assert.h>
8e0ced7a9SAntonio Nino Diaz #include <stdbool.h>
9f14d1886SSoby Mathew 
10*09d40e0eSAntonio Nino Diaz #include <bl31/interrupt_mgmt.h>
11*09d40e0eSAntonio Nino Diaz #include <drivers/arm/gic_common.h>
12*09d40e0eSAntonio Nino Diaz #include <drivers/arm/gicv2.h>
13*09d40e0eSAntonio Nino Diaz #include <plat/common/platform.h>
14*09d40e0eSAntonio Nino Diaz 
15f14d1886SSoby Mathew /*
16f14d1886SSoby Mathew  * The following platform GIC functions are weakly defined. They
17f14d1886SSoby Mathew  * provide typical implementations that may be re-used by multiple
18f14d1886SSoby Mathew  * platforms but may also be overridden by a platform if required.
19f14d1886SSoby Mathew  */
20f14d1886SSoby Mathew #pragma weak plat_ic_get_pending_interrupt_id
21f14d1886SSoby Mathew #pragma weak plat_ic_get_pending_interrupt_type
22f14d1886SSoby Mathew #pragma weak plat_ic_acknowledge_interrupt
23f14d1886SSoby Mathew #pragma weak plat_ic_get_interrupt_type
24f14d1886SSoby Mathew #pragma weak plat_ic_end_of_interrupt
25f14d1886SSoby Mathew #pragma weak plat_interrupt_type_to_line
26f14d1886SSoby Mathew 
27eb68ea9bSJeenu Viswambharan #pragma weak plat_ic_get_running_priority
28ca43b55dSJeenu Viswambharan #pragma weak plat_ic_is_spi
29ca43b55dSJeenu Viswambharan #pragma weak plat_ic_is_ppi
30ca43b55dSJeenu Viswambharan #pragma weak plat_ic_is_sgi
31cbd3f370SJeenu Viswambharan #pragma weak plat_ic_get_interrupt_active
32979225f4SJeenu Viswambharan #pragma weak plat_ic_enable_interrupt
33979225f4SJeenu Viswambharan #pragma weak plat_ic_disable_interrupt
34f3a86600SJeenu Viswambharan #pragma weak plat_ic_set_interrupt_priority
3574dce7faSJeenu Viswambharan #pragma weak plat_ic_set_interrupt_type
368db978b5SJeenu Viswambharan #pragma weak plat_ic_raise_el3_sgi
37fc529feeSJeenu Viswambharan #pragma weak plat_ic_set_spi_routing
38eb68ea9bSJeenu Viswambharan 
39f14d1886SSoby Mathew /*
40f14d1886SSoby Mathew  * This function returns the highest priority pending interrupt at
41f14d1886SSoby Mathew  * the Interrupt controller
42f14d1886SSoby Mathew  */
43f14d1886SSoby Mathew uint32_t plat_ic_get_pending_interrupt_id(void)
44f14d1886SSoby Mathew {
45f14d1886SSoby Mathew 	unsigned int id;
46f14d1886SSoby Mathew 
47f14d1886SSoby Mathew 	id = gicv2_get_pending_interrupt_id();
48f14d1886SSoby Mathew 	if (id == GIC_SPURIOUS_INTERRUPT)
49f14d1886SSoby Mathew 		return INTR_ID_UNAVAILABLE;
50f14d1886SSoby Mathew 
51f14d1886SSoby Mathew 	return id;
52f14d1886SSoby Mathew }
53f14d1886SSoby Mathew 
54f14d1886SSoby Mathew /*
55f14d1886SSoby Mathew  * This function returns the type of the highest priority pending interrupt
56f14d1886SSoby Mathew  * at the Interrupt controller. In the case of GICv2, the Highest Priority
57f14d1886SSoby Mathew  * Pending interrupt register (`GICC_HPPIR`) is read to determine the id of
58f14d1886SSoby Mathew  * the pending interrupt. The type of interrupt depends upon the id value
59f14d1886SSoby Mathew  * as follows.
60f14d1886SSoby Mathew  *   1. id < PENDING_G1_INTID (1022) is reported as a S-EL1 interrupt
61f14d1886SSoby Mathew  *   2. id = PENDING_G1_INTID (1022) is reported as a Non-secure interrupt.
62f14d1886SSoby Mathew  *   3. id = GIC_SPURIOUS_INTERRUPT (1023) is reported as an invalid interrupt
63f14d1886SSoby Mathew  *           type.
64f14d1886SSoby Mathew  */
65f14d1886SSoby Mathew uint32_t plat_ic_get_pending_interrupt_type(void)
66f14d1886SSoby Mathew {
67f14d1886SSoby Mathew 	unsigned int id;
68f14d1886SSoby Mathew 
69f14d1886SSoby Mathew 	id = gicv2_get_pending_interrupt_type();
70f14d1886SSoby Mathew 
71f14d1886SSoby Mathew 	/* Assume that all secure interrupts are S-EL1 interrupts */
7274dce7faSJeenu Viswambharan 	if (id < PENDING_G1_INTID) {
7374dce7faSJeenu Viswambharan #if GICV2_G0_FOR_EL3
7474dce7faSJeenu Viswambharan 		return INTR_TYPE_EL3;
7574dce7faSJeenu Viswambharan #else
76f14d1886SSoby Mathew 		return INTR_TYPE_S_EL1;
7774dce7faSJeenu Viswambharan #endif
7874dce7faSJeenu Viswambharan 	}
79f14d1886SSoby Mathew 
80f14d1886SSoby Mathew 	if (id == GIC_SPURIOUS_INTERRUPT)
81f14d1886SSoby Mathew 		return INTR_TYPE_INVAL;
82f14d1886SSoby Mathew 
83f14d1886SSoby Mathew 	return INTR_TYPE_NS;
84f14d1886SSoby Mathew }
85f14d1886SSoby Mathew 
86f14d1886SSoby Mathew /*
87f14d1886SSoby Mathew  * This function returns the highest priority pending interrupt at
88f14d1886SSoby Mathew  * the Interrupt controller and indicates to the Interrupt controller
89f14d1886SSoby Mathew  * that the interrupt processing has started.
90f14d1886SSoby Mathew  */
91f14d1886SSoby Mathew uint32_t plat_ic_acknowledge_interrupt(void)
92f14d1886SSoby Mathew {
93f14d1886SSoby Mathew 	return gicv2_acknowledge_interrupt();
94f14d1886SSoby Mathew }
95f14d1886SSoby Mathew 
96f14d1886SSoby Mathew /*
97f14d1886SSoby Mathew  * This function returns the type of the interrupt `id`, depending on how
98f14d1886SSoby Mathew  * the interrupt has been configured in the interrupt controller
99f14d1886SSoby Mathew  */
100f14d1886SSoby Mathew uint32_t plat_ic_get_interrupt_type(uint32_t id)
101f14d1886SSoby Mathew {
102f14d1886SSoby Mathew 	unsigned int type;
103f14d1886SSoby Mathew 
104f14d1886SSoby Mathew 	type = gicv2_get_interrupt_group(id);
105f14d1886SSoby Mathew 
106f14d1886SSoby Mathew 	/* Assume that all secure interrupts are S-EL1 interrupts */
107e0ced7a9SAntonio Nino Diaz 	return (type == GICV2_INTR_GROUP1) ? INTR_TYPE_NS :
10874dce7faSJeenu Viswambharan #if GICV2_G0_FOR_EL3
10974dce7faSJeenu Viswambharan 		INTR_TYPE_EL3;
11074dce7faSJeenu Viswambharan #else
11174dce7faSJeenu Viswambharan 		INTR_TYPE_S_EL1;
11274dce7faSJeenu Viswambharan #endif
113f14d1886SSoby Mathew }
114f14d1886SSoby Mathew 
115f14d1886SSoby Mathew /*
116f14d1886SSoby Mathew  * This functions is used to indicate to the interrupt controller that
117f14d1886SSoby Mathew  * the processing of the interrupt corresponding to the `id` has
118f14d1886SSoby Mathew  * finished.
119f14d1886SSoby Mathew  */
120f14d1886SSoby Mathew void plat_ic_end_of_interrupt(uint32_t id)
121f14d1886SSoby Mathew {
122f14d1886SSoby Mathew 	gicv2_end_of_interrupt(id);
123f14d1886SSoby Mathew }
124f14d1886SSoby Mathew 
125f14d1886SSoby Mathew /*
126f14d1886SSoby Mathew  * An ARM processor signals interrupt exceptions through the IRQ and FIQ pins.
127f14d1886SSoby Mathew  * The interrupt controller knows which pin/line it uses to signal a type of
128f14d1886SSoby Mathew  * interrupt. It lets the interrupt management framework determine
129f14d1886SSoby Mathew  * for a type of interrupt and security state, which line should be used in the
130f14d1886SSoby Mathew  * SCR_EL3 to control its routing to EL3. The interrupt line is represented
131f14d1886SSoby Mathew  * as the bit position of the IRQ or FIQ bit in the SCR_EL3.
132f14d1886SSoby Mathew  */
133f14d1886SSoby Mathew uint32_t plat_interrupt_type_to_line(uint32_t type,
134f14d1886SSoby Mathew 				uint32_t security_state)
135f14d1886SSoby Mathew {
136e0ced7a9SAntonio Nino Diaz 	assert((type == INTR_TYPE_S_EL1) || (type == INTR_TYPE_EL3) ||
137e0ced7a9SAntonio Nino Diaz 	       (type == INTR_TYPE_NS));
138f14d1886SSoby Mathew 
13953a98be3SSanteri Salko 	assert(sec_state_is_valid(security_state));
14053a98be3SSanteri Salko 
141f14d1886SSoby Mathew 	/* Non-secure interrupts are signaled on the IRQ line always */
142f14d1886SSoby Mathew 	if (type == INTR_TYPE_NS)
143f14d1886SSoby Mathew 		return __builtin_ctz(SCR_IRQ_BIT);
144f14d1886SSoby Mathew 
145f14d1886SSoby Mathew 	/*
146f14d1886SSoby Mathew 	 * Secure interrupts are signaled using the IRQ line if the FIQ is
147f14d1886SSoby Mathew 	 * not enabled else they are signaled using the FIQ line.
148f14d1886SSoby Mathew 	 */
149e0ced7a9SAntonio Nino Diaz 	return ((gicv2_is_fiq_enabled() != 0U) ? __builtin_ctz(SCR_FIQ_BIT) :
150f14d1886SSoby Mathew 						 __builtin_ctz(SCR_IRQ_BIT));
151f14d1886SSoby Mathew }
152eb68ea9bSJeenu Viswambharan 
153eb68ea9bSJeenu Viswambharan unsigned int plat_ic_get_running_priority(void)
154eb68ea9bSJeenu Viswambharan {
155eb68ea9bSJeenu Viswambharan 	return gicv2_get_running_priority();
156eb68ea9bSJeenu Viswambharan }
157ca43b55dSJeenu Viswambharan 
158ca43b55dSJeenu Viswambharan int plat_ic_is_spi(unsigned int id)
159ca43b55dSJeenu Viswambharan {
160ca43b55dSJeenu Viswambharan 	return (id >= MIN_SPI_ID) && (id <= MAX_SPI_ID);
161ca43b55dSJeenu Viswambharan }
162ca43b55dSJeenu Viswambharan 
163ca43b55dSJeenu Viswambharan int plat_ic_is_ppi(unsigned int id)
164ca43b55dSJeenu Viswambharan {
165ca43b55dSJeenu Viswambharan 	return (id >= MIN_PPI_ID) && (id < MIN_SPI_ID);
166ca43b55dSJeenu Viswambharan }
167ca43b55dSJeenu Viswambharan 
168ca43b55dSJeenu Viswambharan int plat_ic_is_sgi(unsigned int id)
169ca43b55dSJeenu Viswambharan {
170ca43b55dSJeenu Viswambharan 	return (id >= MIN_SGI_ID) && (id < MIN_PPI_ID);
171ca43b55dSJeenu Viswambharan }
172cbd3f370SJeenu Viswambharan 
173cbd3f370SJeenu Viswambharan unsigned int plat_ic_get_interrupt_active(unsigned int id)
174cbd3f370SJeenu Viswambharan {
175cbd3f370SJeenu Viswambharan 	return gicv2_get_interrupt_active(id);
176cbd3f370SJeenu Viswambharan }
177979225f4SJeenu Viswambharan 
178979225f4SJeenu Viswambharan void plat_ic_enable_interrupt(unsigned int id)
179979225f4SJeenu Viswambharan {
180979225f4SJeenu Viswambharan 	gicv2_enable_interrupt(id);
181979225f4SJeenu Viswambharan }
182979225f4SJeenu Viswambharan 
183979225f4SJeenu Viswambharan void plat_ic_disable_interrupt(unsigned int id)
184979225f4SJeenu Viswambharan {
185979225f4SJeenu Viswambharan 	gicv2_disable_interrupt(id);
186979225f4SJeenu Viswambharan }
187f3a86600SJeenu Viswambharan 
188f3a86600SJeenu Viswambharan void plat_ic_set_interrupt_priority(unsigned int id, unsigned int priority)
189f3a86600SJeenu Viswambharan {
190f3a86600SJeenu Viswambharan 	gicv2_set_interrupt_priority(id, priority);
191f3a86600SJeenu Viswambharan }
19274dce7faSJeenu Viswambharan 
19374dce7faSJeenu Viswambharan int plat_ic_has_interrupt_type(unsigned int type)
19474dce7faSJeenu Viswambharan {
195649c48f5SJonathan Wright 	int has_interrupt_type = 0;
196649c48f5SJonathan Wright 
19774dce7faSJeenu Viswambharan 	switch (type) {
19874dce7faSJeenu Viswambharan #if GICV2_G0_FOR_EL3
19974dce7faSJeenu Viswambharan 	case INTR_TYPE_EL3:
20074dce7faSJeenu Viswambharan #else
20174dce7faSJeenu Viswambharan 	case INTR_TYPE_S_EL1:
20274dce7faSJeenu Viswambharan #endif
20374dce7faSJeenu Viswambharan 	case INTR_TYPE_NS:
204649c48f5SJonathan Wright 		has_interrupt_type = 1;
205649c48f5SJonathan Wright 		break;
20674dce7faSJeenu Viswambharan 	default:
207649c48f5SJonathan Wright 		/* Do nothing in default case */
208649c48f5SJonathan Wright 		break;
20974dce7faSJeenu Viswambharan 	}
210649c48f5SJonathan Wright 
211649c48f5SJonathan Wright 	return has_interrupt_type;
21274dce7faSJeenu Viswambharan }
21374dce7faSJeenu Viswambharan 
21474dce7faSJeenu Viswambharan void plat_ic_set_interrupt_type(unsigned int id, unsigned int type)
21574dce7faSJeenu Viswambharan {
216e0ced7a9SAntonio Nino Diaz 	unsigned int gicv2_type = 0U;
21774dce7faSJeenu Viswambharan 
21874dce7faSJeenu Viswambharan 	/* Map canonical interrupt type to GICv2 type */
21974dce7faSJeenu Viswambharan 	switch (type) {
22074dce7faSJeenu Viswambharan #if GICV2_G0_FOR_EL3
22174dce7faSJeenu Viswambharan 	case INTR_TYPE_EL3:
22274dce7faSJeenu Viswambharan #else
22374dce7faSJeenu Viswambharan 	case INTR_TYPE_S_EL1:
22474dce7faSJeenu Viswambharan #endif
22574dce7faSJeenu Viswambharan 		gicv2_type = GICV2_INTR_GROUP0;
22674dce7faSJeenu Viswambharan 		break;
22774dce7faSJeenu Viswambharan 	case INTR_TYPE_NS:
22874dce7faSJeenu Viswambharan 		gicv2_type = GICV2_INTR_GROUP1;
22974dce7faSJeenu Viswambharan 		break;
23074dce7faSJeenu Viswambharan 	default:
231a08a2014SDaniel Boulby 		assert(0); /* Unreachable */
232649c48f5SJonathan Wright 		break;
23374dce7faSJeenu Viswambharan 	}
23474dce7faSJeenu Viswambharan 
23574dce7faSJeenu Viswambharan 	gicv2_set_interrupt_type(id, gicv2_type);
23674dce7faSJeenu Viswambharan }
2378db978b5SJeenu Viswambharan 
2388db978b5SJeenu Viswambharan void plat_ic_raise_el3_sgi(int sgi_num, u_register_t target)
2398db978b5SJeenu Viswambharan {
2408db978b5SJeenu Viswambharan #if GICV2_G0_FOR_EL3
2418db978b5SJeenu Viswambharan 	int id;
2428db978b5SJeenu Viswambharan 
2438db978b5SJeenu Viswambharan 	/* Target must be a valid MPIDR in the system */
2448db978b5SJeenu Viswambharan 	id = plat_core_pos_by_mpidr(target);
2458db978b5SJeenu Viswambharan 	assert(id >= 0);
2468db978b5SJeenu Viswambharan 
2478db978b5SJeenu Viswambharan 	/* Verify that this is a secure SGI */
2488db978b5SJeenu Viswambharan 	assert(plat_ic_get_interrupt_type(sgi_num) == INTR_TYPE_EL3);
2498db978b5SJeenu Viswambharan 
2508db978b5SJeenu Viswambharan 	gicv2_raise_sgi(sgi_num, id);
2518db978b5SJeenu Viswambharan #else
252e0ced7a9SAntonio Nino Diaz 	assert(false);
2538db978b5SJeenu Viswambharan #endif
2548db978b5SJeenu Viswambharan }
255fc529feeSJeenu Viswambharan 
256fc529feeSJeenu Viswambharan void plat_ic_set_spi_routing(unsigned int id, unsigned int routing_mode,
257fc529feeSJeenu Viswambharan 		u_register_t mpidr)
258fc529feeSJeenu Viswambharan {
259fc529feeSJeenu Viswambharan 	int proc_num = 0;
260fc529feeSJeenu Viswambharan 
261fc529feeSJeenu Viswambharan 	switch (routing_mode) {
262fc529feeSJeenu Viswambharan 	case INTR_ROUTING_MODE_PE:
263fc529feeSJeenu Viswambharan 		proc_num = plat_core_pos_by_mpidr(mpidr);
264fc529feeSJeenu Viswambharan 		assert(proc_num >= 0);
265fc529feeSJeenu Viswambharan 		break;
266fc529feeSJeenu Viswambharan 	case INTR_ROUTING_MODE_ANY:
267fc529feeSJeenu Viswambharan 		/* Bit mask selecting all 8 CPUs as candidates */
268fc529feeSJeenu Viswambharan 		proc_num = -1;
269fc529feeSJeenu Viswambharan 		break;
270fc529feeSJeenu Viswambharan 	default:
271a08a2014SDaniel Boulby 		assert(0); /* Unreachable */
272649c48f5SJonathan Wright 		break;
273fc529feeSJeenu Viswambharan 	}
274fc529feeSJeenu Viswambharan 
275fc529feeSJeenu Viswambharan 	gicv2_set_spi_routing(id, proc_num);
276fc529feeSJeenu Viswambharan }
277a2816a16SJeenu Viswambharan 
278a2816a16SJeenu Viswambharan void plat_ic_set_interrupt_pending(unsigned int id)
279a2816a16SJeenu Viswambharan {
280a2816a16SJeenu Viswambharan 	gicv2_set_interrupt_pending(id);
281a2816a16SJeenu Viswambharan }
282a2816a16SJeenu Viswambharan 
283a2816a16SJeenu Viswambharan void plat_ic_clear_interrupt_pending(unsigned int id)
284a2816a16SJeenu Viswambharan {
285a2816a16SJeenu Viswambharan 	gicv2_clear_interrupt_pending(id);
286a2816a16SJeenu Viswambharan }
287d55a4450SJeenu Viswambharan 
288d55a4450SJeenu Viswambharan unsigned int plat_ic_set_priority_mask(unsigned int mask)
289d55a4450SJeenu Viswambharan {
290d55a4450SJeenu Viswambharan 	return gicv2_set_pmr(mask);
291d55a4450SJeenu Viswambharan }
2924ee8d0beSJeenu Viswambharan 
2934ee8d0beSJeenu Viswambharan unsigned int plat_ic_get_interrupt_id(unsigned int raw)
2944ee8d0beSJeenu Viswambharan {
2954ee8d0beSJeenu Viswambharan 	unsigned int id = (raw & INT_ID_MASK);
2964ee8d0beSJeenu Viswambharan 
2974ee8d0beSJeenu Viswambharan 	if (id == GIC_SPURIOUS_INTERRUPT)
2984ee8d0beSJeenu Viswambharan 		id = INTR_ID_UNAVAILABLE;
2994ee8d0beSJeenu Viswambharan 
3004ee8d0beSJeenu Viswambharan 	return id;
3014ee8d0beSJeenu Viswambharan }
302