xref: /rk3399_ARM-atf/plat/common/plat_gicv2.c (revision a08a2014300a495381cdb8f6d59523bcd5d3b883)
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  */
6f14d1886SSoby Mathew #include <assert.h>
7f14d1886SSoby Mathew #include <gic_common.h>
8f14d1886SSoby Mathew #include <gicv2.h>
9f14d1886SSoby Mathew #include <interrupt_mgmt.h>
108db978b5SJeenu Viswambharan #include <platform.h>
11e0ced7a9SAntonio Nino Diaz #include <stdbool.h>
12f14d1886SSoby Mathew 
13f14d1886SSoby Mathew /*
14f14d1886SSoby Mathew  * The following platform GIC functions are weakly defined. They
15f14d1886SSoby Mathew  * provide typical implementations that may be re-used by multiple
16f14d1886SSoby Mathew  * platforms but may also be overridden by a platform if required.
17f14d1886SSoby Mathew  */
18f14d1886SSoby Mathew #pragma weak plat_ic_get_pending_interrupt_id
19f14d1886SSoby Mathew #pragma weak plat_ic_get_pending_interrupt_type
20f14d1886SSoby Mathew #pragma weak plat_ic_acknowledge_interrupt
21f14d1886SSoby Mathew #pragma weak plat_ic_get_interrupt_type
22f14d1886SSoby Mathew #pragma weak plat_ic_end_of_interrupt
23f14d1886SSoby Mathew #pragma weak plat_interrupt_type_to_line
24f14d1886SSoby Mathew 
25eb68ea9bSJeenu Viswambharan #pragma weak plat_ic_get_running_priority
26ca43b55dSJeenu Viswambharan #pragma weak plat_ic_is_spi
27ca43b55dSJeenu Viswambharan #pragma weak plat_ic_is_ppi
28ca43b55dSJeenu Viswambharan #pragma weak plat_ic_is_sgi
29cbd3f370SJeenu Viswambharan #pragma weak plat_ic_get_interrupt_active
30979225f4SJeenu Viswambharan #pragma weak plat_ic_enable_interrupt
31979225f4SJeenu Viswambharan #pragma weak plat_ic_disable_interrupt
32f3a86600SJeenu Viswambharan #pragma weak plat_ic_set_interrupt_priority
3374dce7faSJeenu Viswambharan #pragma weak plat_ic_set_interrupt_type
348db978b5SJeenu Viswambharan #pragma weak plat_ic_raise_el3_sgi
35fc529feeSJeenu Viswambharan #pragma weak plat_ic_set_spi_routing
36eb68ea9bSJeenu Viswambharan 
37f14d1886SSoby Mathew /*
38f14d1886SSoby Mathew  * This function returns the highest priority pending interrupt at
39f14d1886SSoby Mathew  * the Interrupt controller
40f14d1886SSoby Mathew  */
41f14d1886SSoby Mathew uint32_t plat_ic_get_pending_interrupt_id(void)
42f14d1886SSoby Mathew {
43f14d1886SSoby Mathew 	unsigned int id;
44f14d1886SSoby Mathew 
45f14d1886SSoby Mathew 	id = gicv2_get_pending_interrupt_id();
46f14d1886SSoby Mathew 	if (id == GIC_SPURIOUS_INTERRUPT)
47f14d1886SSoby Mathew 		return INTR_ID_UNAVAILABLE;
48f14d1886SSoby Mathew 
49f14d1886SSoby Mathew 	return id;
50f14d1886SSoby Mathew }
51f14d1886SSoby Mathew 
52f14d1886SSoby Mathew /*
53f14d1886SSoby Mathew  * This function returns the type of the highest priority pending interrupt
54f14d1886SSoby Mathew  * at the Interrupt controller. In the case of GICv2, the Highest Priority
55f14d1886SSoby Mathew  * Pending interrupt register (`GICC_HPPIR`) is read to determine the id of
56f14d1886SSoby Mathew  * the pending interrupt. The type of interrupt depends upon the id value
57f14d1886SSoby Mathew  * as follows.
58f14d1886SSoby Mathew  *   1. id < PENDING_G1_INTID (1022) is reported as a S-EL1 interrupt
59f14d1886SSoby Mathew  *   2. id = PENDING_G1_INTID (1022) is reported as a Non-secure interrupt.
60f14d1886SSoby Mathew  *   3. id = GIC_SPURIOUS_INTERRUPT (1023) is reported as an invalid interrupt
61f14d1886SSoby Mathew  *           type.
62f14d1886SSoby Mathew  */
63f14d1886SSoby Mathew uint32_t plat_ic_get_pending_interrupt_type(void)
64f14d1886SSoby Mathew {
65f14d1886SSoby Mathew 	unsigned int id;
66f14d1886SSoby Mathew 
67f14d1886SSoby Mathew 	id = gicv2_get_pending_interrupt_type();
68f14d1886SSoby Mathew 
69f14d1886SSoby Mathew 	/* Assume that all secure interrupts are S-EL1 interrupts */
7074dce7faSJeenu Viswambharan 	if (id < PENDING_G1_INTID) {
7174dce7faSJeenu Viswambharan #if GICV2_G0_FOR_EL3
7274dce7faSJeenu Viswambharan 		return INTR_TYPE_EL3;
7374dce7faSJeenu Viswambharan #else
74f14d1886SSoby Mathew 		return INTR_TYPE_S_EL1;
7574dce7faSJeenu Viswambharan #endif
7674dce7faSJeenu Viswambharan 	}
77f14d1886SSoby Mathew 
78f14d1886SSoby Mathew 	if (id == GIC_SPURIOUS_INTERRUPT)
79f14d1886SSoby Mathew 		return INTR_TYPE_INVAL;
80f14d1886SSoby Mathew 
81f14d1886SSoby Mathew 	return INTR_TYPE_NS;
82f14d1886SSoby Mathew }
83f14d1886SSoby Mathew 
84f14d1886SSoby Mathew /*
85f14d1886SSoby Mathew  * This function returns the highest priority pending interrupt at
86f14d1886SSoby Mathew  * the Interrupt controller and indicates to the Interrupt controller
87f14d1886SSoby Mathew  * that the interrupt processing has started.
88f14d1886SSoby Mathew  */
89f14d1886SSoby Mathew uint32_t plat_ic_acknowledge_interrupt(void)
90f14d1886SSoby Mathew {
91f14d1886SSoby Mathew 	return gicv2_acknowledge_interrupt();
92f14d1886SSoby Mathew }
93f14d1886SSoby Mathew 
94f14d1886SSoby Mathew /*
95f14d1886SSoby Mathew  * This function returns the type of the interrupt `id`, depending on how
96f14d1886SSoby Mathew  * the interrupt has been configured in the interrupt controller
97f14d1886SSoby Mathew  */
98f14d1886SSoby Mathew uint32_t plat_ic_get_interrupt_type(uint32_t id)
99f14d1886SSoby Mathew {
100f14d1886SSoby Mathew 	unsigned int type;
101f14d1886SSoby Mathew 
102f14d1886SSoby Mathew 	type = gicv2_get_interrupt_group(id);
103f14d1886SSoby Mathew 
104f14d1886SSoby Mathew 	/* Assume that all secure interrupts are S-EL1 interrupts */
105e0ced7a9SAntonio Nino Diaz 	return (type == GICV2_INTR_GROUP1) ? INTR_TYPE_NS :
10674dce7faSJeenu Viswambharan #if GICV2_G0_FOR_EL3
10774dce7faSJeenu Viswambharan 		INTR_TYPE_EL3;
10874dce7faSJeenu Viswambharan #else
10974dce7faSJeenu Viswambharan 		INTR_TYPE_S_EL1;
11074dce7faSJeenu Viswambharan #endif
111f14d1886SSoby Mathew }
112f14d1886SSoby Mathew 
113f14d1886SSoby Mathew /*
114f14d1886SSoby Mathew  * This functions is used to indicate to the interrupt controller that
115f14d1886SSoby Mathew  * the processing of the interrupt corresponding to the `id` has
116f14d1886SSoby Mathew  * finished.
117f14d1886SSoby Mathew  */
118f14d1886SSoby Mathew void plat_ic_end_of_interrupt(uint32_t id)
119f14d1886SSoby Mathew {
120f14d1886SSoby Mathew 	gicv2_end_of_interrupt(id);
121f14d1886SSoby Mathew }
122f14d1886SSoby Mathew 
123f14d1886SSoby Mathew /*
124f14d1886SSoby Mathew  * An ARM processor signals interrupt exceptions through the IRQ and FIQ pins.
125f14d1886SSoby Mathew  * The interrupt controller knows which pin/line it uses to signal a type of
126f14d1886SSoby Mathew  * interrupt. It lets the interrupt management framework determine
127f14d1886SSoby Mathew  * for a type of interrupt and security state, which line should be used in the
128f14d1886SSoby Mathew  * SCR_EL3 to control its routing to EL3. The interrupt line is represented
129f14d1886SSoby Mathew  * as the bit position of the IRQ or FIQ bit in the SCR_EL3.
130f14d1886SSoby Mathew  */
131f14d1886SSoby Mathew uint32_t plat_interrupt_type_to_line(uint32_t type,
132f14d1886SSoby Mathew 				uint32_t security_state)
133f14d1886SSoby Mathew {
134e0ced7a9SAntonio Nino Diaz 	assert((type == INTR_TYPE_S_EL1) || (type == INTR_TYPE_EL3) ||
135e0ced7a9SAntonio Nino Diaz 	       (type == INTR_TYPE_NS));
136f14d1886SSoby Mathew 
13753a98be3SSanteri Salko 	assert(sec_state_is_valid(security_state));
13853a98be3SSanteri Salko 
139f14d1886SSoby Mathew 	/* Non-secure interrupts are signaled on the IRQ line always */
140f14d1886SSoby Mathew 	if (type == INTR_TYPE_NS)
141f14d1886SSoby Mathew 		return __builtin_ctz(SCR_IRQ_BIT);
142f14d1886SSoby Mathew 
143f14d1886SSoby Mathew 	/*
144f14d1886SSoby Mathew 	 * Secure interrupts are signaled using the IRQ line if the FIQ is
145f14d1886SSoby Mathew 	 * not enabled else they are signaled using the FIQ line.
146f14d1886SSoby Mathew 	 */
147e0ced7a9SAntonio Nino Diaz 	return ((gicv2_is_fiq_enabled() != 0U) ? __builtin_ctz(SCR_FIQ_BIT) :
148f14d1886SSoby Mathew 						 __builtin_ctz(SCR_IRQ_BIT));
149f14d1886SSoby Mathew }
150eb68ea9bSJeenu Viswambharan 
151eb68ea9bSJeenu Viswambharan unsigned int plat_ic_get_running_priority(void)
152eb68ea9bSJeenu Viswambharan {
153eb68ea9bSJeenu Viswambharan 	return gicv2_get_running_priority();
154eb68ea9bSJeenu Viswambharan }
155ca43b55dSJeenu Viswambharan 
156ca43b55dSJeenu Viswambharan int plat_ic_is_spi(unsigned int id)
157ca43b55dSJeenu Viswambharan {
158ca43b55dSJeenu Viswambharan 	return (id >= MIN_SPI_ID) && (id <= MAX_SPI_ID);
159ca43b55dSJeenu Viswambharan }
160ca43b55dSJeenu Viswambharan 
161ca43b55dSJeenu Viswambharan int plat_ic_is_ppi(unsigned int id)
162ca43b55dSJeenu Viswambharan {
163ca43b55dSJeenu Viswambharan 	return (id >= MIN_PPI_ID) && (id < MIN_SPI_ID);
164ca43b55dSJeenu Viswambharan }
165ca43b55dSJeenu Viswambharan 
166ca43b55dSJeenu Viswambharan int plat_ic_is_sgi(unsigned int id)
167ca43b55dSJeenu Viswambharan {
168ca43b55dSJeenu Viswambharan 	return (id >= MIN_SGI_ID) && (id < MIN_PPI_ID);
169ca43b55dSJeenu Viswambharan }
170cbd3f370SJeenu Viswambharan 
171cbd3f370SJeenu Viswambharan unsigned int plat_ic_get_interrupt_active(unsigned int id)
172cbd3f370SJeenu Viswambharan {
173cbd3f370SJeenu Viswambharan 	return gicv2_get_interrupt_active(id);
174cbd3f370SJeenu Viswambharan }
175979225f4SJeenu Viswambharan 
176979225f4SJeenu Viswambharan void plat_ic_enable_interrupt(unsigned int id)
177979225f4SJeenu Viswambharan {
178979225f4SJeenu Viswambharan 	gicv2_enable_interrupt(id);
179979225f4SJeenu Viswambharan }
180979225f4SJeenu Viswambharan 
181979225f4SJeenu Viswambharan void plat_ic_disable_interrupt(unsigned int id)
182979225f4SJeenu Viswambharan {
183979225f4SJeenu Viswambharan 	gicv2_disable_interrupt(id);
184979225f4SJeenu Viswambharan }
185f3a86600SJeenu Viswambharan 
186f3a86600SJeenu Viswambharan void plat_ic_set_interrupt_priority(unsigned int id, unsigned int priority)
187f3a86600SJeenu Viswambharan {
188f3a86600SJeenu Viswambharan 	gicv2_set_interrupt_priority(id, priority);
189f3a86600SJeenu Viswambharan }
19074dce7faSJeenu Viswambharan 
19174dce7faSJeenu Viswambharan int plat_ic_has_interrupt_type(unsigned int type)
19274dce7faSJeenu Viswambharan {
193649c48f5SJonathan Wright 	int has_interrupt_type = 0;
194649c48f5SJonathan Wright 
19574dce7faSJeenu Viswambharan 	switch (type) {
19674dce7faSJeenu Viswambharan #if GICV2_G0_FOR_EL3
19774dce7faSJeenu Viswambharan 	case INTR_TYPE_EL3:
19874dce7faSJeenu Viswambharan #else
19974dce7faSJeenu Viswambharan 	case INTR_TYPE_S_EL1:
20074dce7faSJeenu Viswambharan #endif
20174dce7faSJeenu Viswambharan 	case INTR_TYPE_NS:
202649c48f5SJonathan Wright 		has_interrupt_type = 1;
203649c48f5SJonathan Wright 		break;
20474dce7faSJeenu Viswambharan 	default:
205649c48f5SJonathan Wright 		/* Do nothing in default case */
206649c48f5SJonathan Wright 		break;
20774dce7faSJeenu Viswambharan 	}
208649c48f5SJonathan Wright 
209649c48f5SJonathan Wright 	return has_interrupt_type;
21074dce7faSJeenu Viswambharan }
21174dce7faSJeenu Viswambharan 
21274dce7faSJeenu Viswambharan void plat_ic_set_interrupt_type(unsigned int id, unsigned int type)
21374dce7faSJeenu Viswambharan {
214e0ced7a9SAntonio Nino Diaz 	unsigned int gicv2_type = 0U;
21574dce7faSJeenu Viswambharan 
21674dce7faSJeenu Viswambharan 	/* Map canonical interrupt type to GICv2 type */
21774dce7faSJeenu Viswambharan 	switch (type) {
21874dce7faSJeenu Viswambharan #if GICV2_G0_FOR_EL3
21974dce7faSJeenu Viswambharan 	case INTR_TYPE_EL3:
22074dce7faSJeenu Viswambharan #else
22174dce7faSJeenu Viswambharan 	case INTR_TYPE_S_EL1:
22274dce7faSJeenu Viswambharan #endif
22374dce7faSJeenu Viswambharan 		gicv2_type = GICV2_INTR_GROUP0;
22474dce7faSJeenu Viswambharan 		break;
22574dce7faSJeenu Viswambharan 	case INTR_TYPE_NS:
22674dce7faSJeenu Viswambharan 		gicv2_type = GICV2_INTR_GROUP1;
22774dce7faSJeenu Viswambharan 		break;
22874dce7faSJeenu Viswambharan 	default:
229*a08a2014SDaniel Boulby 		assert(0); /* Unreachable */
230649c48f5SJonathan Wright 		break;
23174dce7faSJeenu Viswambharan 	}
23274dce7faSJeenu Viswambharan 
23374dce7faSJeenu Viswambharan 	gicv2_set_interrupt_type(id, gicv2_type);
23474dce7faSJeenu Viswambharan }
2358db978b5SJeenu Viswambharan 
2368db978b5SJeenu Viswambharan void plat_ic_raise_el3_sgi(int sgi_num, u_register_t target)
2378db978b5SJeenu Viswambharan {
2388db978b5SJeenu Viswambharan #if GICV2_G0_FOR_EL3
2398db978b5SJeenu Viswambharan 	int id;
2408db978b5SJeenu Viswambharan 
2418db978b5SJeenu Viswambharan 	/* Target must be a valid MPIDR in the system */
2428db978b5SJeenu Viswambharan 	id = plat_core_pos_by_mpidr(target);
2438db978b5SJeenu Viswambharan 	assert(id >= 0);
2448db978b5SJeenu Viswambharan 
2458db978b5SJeenu Viswambharan 	/* Verify that this is a secure SGI */
2468db978b5SJeenu Viswambharan 	assert(plat_ic_get_interrupt_type(sgi_num) == INTR_TYPE_EL3);
2478db978b5SJeenu Viswambharan 
2488db978b5SJeenu Viswambharan 	gicv2_raise_sgi(sgi_num, id);
2498db978b5SJeenu Viswambharan #else
250e0ced7a9SAntonio Nino Diaz 	assert(false);
2518db978b5SJeenu Viswambharan #endif
2528db978b5SJeenu Viswambharan }
253fc529feeSJeenu Viswambharan 
254fc529feeSJeenu Viswambharan void plat_ic_set_spi_routing(unsigned int id, unsigned int routing_mode,
255fc529feeSJeenu Viswambharan 		u_register_t mpidr)
256fc529feeSJeenu Viswambharan {
257fc529feeSJeenu Viswambharan 	int proc_num = 0;
258fc529feeSJeenu Viswambharan 
259fc529feeSJeenu Viswambharan 	switch (routing_mode) {
260fc529feeSJeenu Viswambharan 	case INTR_ROUTING_MODE_PE:
261fc529feeSJeenu Viswambharan 		proc_num = plat_core_pos_by_mpidr(mpidr);
262fc529feeSJeenu Viswambharan 		assert(proc_num >= 0);
263fc529feeSJeenu Viswambharan 		break;
264fc529feeSJeenu Viswambharan 	case INTR_ROUTING_MODE_ANY:
265fc529feeSJeenu Viswambharan 		/* Bit mask selecting all 8 CPUs as candidates */
266fc529feeSJeenu Viswambharan 		proc_num = -1;
267fc529feeSJeenu Viswambharan 		break;
268fc529feeSJeenu Viswambharan 	default:
269*a08a2014SDaniel Boulby 		assert(0); /* Unreachable */
270649c48f5SJonathan Wright 		break;
271fc529feeSJeenu Viswambharan 	}
272fc529feeSJeenu Viswambharan 
273fc529feeSJeenu Viswambharan 	gicv2_set_spi_routing(id, proc_num);
274fc529feeSJeenu Viswambharan }
275a2816a16SJeenu Viswambharan 
276a2816a16SJeenu Viswambharan void plat_ic_set_interrupt_pending(unsigned int id)
277a2816a16SJeenu Viswambharan {
278a2816a16SJeenu Viswambharan 	gicv2_set_interrupt_pending(id);
279a2816a16SJeenu Viswambharan }
280a2816a16SJeenu Viswambharan 
281a2816a16SJeenu Viswambharan void plat_ic_clear_interrupt_pending(unsigned int id)
282a2816a16SJeenu Viswambharan {
283a2816a16SJeenu Viswambharan 	gicv2_clear_interrupt_pending(id);
284a2816a16SJeenu Viswambharan }
285d55a4450SJeenu Viswambharan 
286d55a4450SJeenu Viswambharan unsigned int plat_ic_set_priority_mask(unsigned int mask)
287d55a4450SJeenu Viswambharan {
288d55a4450SJeenu Viswambharan 	return gicv2_set_pmr(mask);
289d55a4450SJeenu Viswambharan }
2904ee8d0beSJeenu Viswambharan 
2914ee8d0beSJeenu Viswambharan unsigned int plat_ic_get_interrupt_id(unsigned int raw)
2924ee8d0beSJeenu Viswambharan {
2934ee8d0beSJeenu Viswambharan 	unsigned int id = (raw & INT_ID_MASK);
2944ee8d0beSJeenu Viswambharan 
2954ee8d0beSJeenu Viswambharan 	if (id == GIC_SPURIOUS_INTERRUPT)
2964ee8d0beSJeenu Viswambharan 		id = INTR_ID_UNAVAILABLE;
2974ee8d0beSJeenu Viswambharan 
2984ee8d0beSJeenu Viswambharan 	return id;
2994ee8d0beSJeenu Viswambharan }
300