xref: /rk3399_ARM-atf/plat/common/plat_gicv2.c (revision 53a98be35f614caa1d2c34076b43b08d0810b6fa)
1f14d1886SSoby Mathew /*
2eb68ea9bSJeenu Viswambharan  * Copyright (c) 2015-2017, 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>
11f14d1886SSoby Mathew 
12f14d1886SSoby Mathew /*
13f14d1886SSoby Mathew  * The following platform GIC functions are weakly defined. They
14f14d1886SSoby Mathew  * provide typical implementations that may be re-used by multiple
15f14d1886SSoby Mathew  * platforms but may also be overridden by a platform if required.
16f14d1886SSoby Mathew  */
17f14d1886SSoby Mathew #pragma weak plat_ic_get_pending_interrupt_id
18f14d1886SSoby Mathew #pragma weak plat_ic_get_pending_interrupt_type
19f14d1886SSoby Mathew #pragma weak plat_ic_acknowledge_interrupt
20f14d1886SSoby Mathew #pragma weak plat_ic_get_interrupt_type
21f14d1886SSoby Mathew #pragma weak plat_ic_end_of_interrupt
22f14d1886SSoby Mathew #pragma weak plat_interrupt_type_to_line
23f14d1886SSoby Mathew 
24eb68ea9bSJeenu Viswambharan #pragma weak plat_ic_get_running_priority
25ca43b55dSJeenu Viswambharan #pragma weak plat_ic_is_spi
26ca43b55dSJeenu Viswambharan #pragma weak plat_ic_is_ppi
27ca43b55dSJeenu Viswambharan #pragma weak plat_ic_is_sgi
28cbd3f370SJeenu Viswambharan #pragma weak plat_ic_get_interrupt_active
29979225f4SJeenu Viswambharan #pragma weak plat_ic_enable_interrupt
30979225f4SJeenu Viswambharan #pragma weak plat_ic_disable_interrupt
31f3a86600SJeenu Viswambharan #pragma weak plat_ic_set_interrupt_priority
3274dce7faSJeenu Viswambharan #pragma weak plat_ic_set_interrupt_type
338db978b5SJeenu Viswambharan #pragma weak plat_ic_raise_el3_sgi
34fc529feeSJeenu Viswambharan #pragma weak plat_ic_set_spi_routing
35eb68ea9bSJeenu Viswambharan 
36f14d1886SSoby Mathew /*
37f14d1886SSoby Mathew  * This function returns the highest priority pending interrupt at
38f14d1886SSoby Mathew  * the Interrupt controller
39f14d1886SSoby Mathew  */
40f14d1886SSoby Mathew uint32_t plat_ic_get_pending_interrupt_id(void)
41f14d1886SSoby Mathew {
42f14d1886SSoby Mathew 	unsigned int id;
43f14d1886SSoby Mathew 
44f14d1886SSoby Mathew 	id = gicv2_get_pending_interrupt_id();
45f14d1886SSoby Mathew 	if (id == GIC_SPURIOUS_INTERRUPT)
46f14d1886SSoby Mathew 		return INTR_ID_UNAVAILABLE;
47f14d1886SSoby Mathew 
48f14d1886SSoby Mathew 	return id;
49f14d1886SSoby Mathew }
50f14d1886SSoby Mathew 
51f14d1886SSoby Mathew /*
52f14d1886SSoby Mathew  * This function returns the type of the highest priority pending interrupt
53f14d1886SSoby Mathew  * at the Interrupt controller. In the case of GICv2, the Highest Priority
54f14d1886SSoby Mathew  * Pending interrupt register (`GICC_HPPIR`) is read to determine the id of
55f14d1886SSoby Mathew  * the pending interrupt. The type of interrupt depends upon the id value
56f14d1886SSoby Mathew  * as follows.
57f14d1886SSoby Mathew  *   1. id < PENDING_G1_INTID (1022) is reported as a S-EL1 interrupt
58f14d1886SSoby Mathew  *   2. id = PENDING_G1_INTID (1022) is reported as a Non-secure interrupt.
59f14d1886SSoby Mathew  *   3. id = GIC_SPURIOUS_INTERRUPT (1023) is reported as an invalid interrupt
60f14d1886SSoby Mathew  *           type.
61f14d1886SSoby Mathew  */
62f14d1886SSoby Mathew uint32_t plat_ic_get_pending_interrupt_type(void)
63f14d1886SSoby Mathew {
64f14d1886SSoby Mathew 	unsigned int id;
65f14d1886SSoby Mathew 
66f14d1886SSoby Mathew 	id = gicv2_get_pending_interrupt_type();
67f14d1886SSoby Mathew 
68f14d1886SSoby Mathew 	/* Assume that all secure interrupts are S-EL1 interrupts */
6974dce7faSJeenu Viswambharan 	if (id < PENDING_G1_INTID) {
7074dce7faSJeenu Viswambharan #if GICV2_G0_FOR_EL3
7174dce7faSJeenu Viswambharan 		return INTR_TYPE_EL3;
7274dce7faSJeenu Viswambharan #else
73f14d1886SSoby Mathew 		return INTR_TYPE_S_EL1;
7474dce7faSJeenu Viswambharan #endif
7574dce7faSJeenu Viswambharan 	}
76f14d1886SSoby Mathew 
77f14d1886SSoby Mathew 	if (id == GIC_SPURIOUS_INTERRUPT)
78f14d1886SSoby Mathew 		return INTR_TYPE_INVAL;
79f14d1886SSoby Mathew 
80f14d1886SSoby Mathew 	return INTR_TYPE_NS;
81f14d1886SSoby Mathew }
82f14d1886SSoby Mathew 
83f14d1886SSoby Mathew /*
84f14d1886SSoby Mathew  * This function returns the highest priority pending interrupt at
85f14d1886SSoby Mathew  * the Interrupt controller and indicates to the Interrupt controller
86f14d1886SSoby Mathew  * that the interrupt processing has started.
87f14d1886SSoby Mathew  */
88f14d1886SSoby Mathew uint32_t plat_ic_acknowledge_interrupt(void)
89f14d1886SSoby Mathew {
90f14d1886SSoby Mathew 	return gicv2_acknowledge_interrupt();
91f14d1886SSoby Mathew }
92f14d1886SSoby Mathew 
93f14d1886SSoby Mathew /*
94f14d1886SSoby Mathew  * This function returns the type of the interrupt `id`, depending on how
95f14d1886SSoby Mathew  * the interrupt has been configured in the interrupt controller
96f14d1886SSoby Mathew  */
97f14d1886SSoby Mathew uint32_t plat_ic_get_interrupt_type(uint32_t id)
98f14d1886SSoby Mathew {
99f14d1886SSoby Mathew 	unsigned int type;
100f14d1886SSoby Mathew 
101f14d1886SSoby Mathew 	type = gicv2_get_interrupt_group(id);
102f14d1886SSoby Mathew 
103f14d1886SSoby Mathew 	/* Assume that all secure interrupts are S-EL1 interrupts */
10474dce7faSJeenu Viswambharan 	return type == GICV2_INTR_GROUP1 ? INTR_TYPE_NS :
10574dce7faSJeenu Viswambharan #if GICV2_G0_FOR_EL3
10674dce7faSJeenu Viswambharan 		INTR_TYPE_EL3;
10774dce7faSJeenu Viswambharan #else
10874dce7faSJeenu Viswambharan 		INTR_TYPE_S_EL1;
10974dce7faSJeenu Viswambharan #endif
110f14d1886SSoby Mathew }
111f14d1886SSoby Mathew 
112f14d1886SSoby Mathew /*
113f14d1886SSoby Mathew  * This functions is used to indicate to the interrupt controller that
114f14d1886SSoby Mathew  * the processing of the interrupt corresponding to the `id` has
115f14d1886SSoby Mathew  * finished.
116f14d1886SSoby Mathew  */
117f14d1886SSoby Mathew void plat_ic_end_of_interrupt(uint32_t id)
118f14d1886SSoby Mathew {
119f14d1886SSoby Mathew 	gicv2_end_of_interrupt(id);
120f14d1886SSoby Mathew }
121f14d1886SSoby Mathew 
122f14d1886SSoby Mathew /*
123f14d1886SSoby Mathew  * An ARM processor signals interrupt exceptions through the IRQ and FIQ pins.
124f14d1886SSoby Mathew  * The interrupt controller knows which pin/line it uses to signal a type of
125f14d1886SSoby Mathew  * interrupt. It lets the interrupt management framework determine
126f14d1886SSoby Mathew  * for a type of interrupt and security state, which line should be used in the
127f14d1886SSoby Mathew  * SCR_EL3 to control its routing to EL3. The interrupt line is represented
128f14d1886SSoby Mathew  * as the bit position of the IRQ or FIQ bit in the SCR_EL3.
129f14d1886SSoby Mathew  */
130f14d1886SSoby Mathew uint32_t plat_interrupt_type_to_line(uint32_t type,
131f14d1886SSoby Mathew 				uint32_t security_state)
132f14d1886SSoby Mathew {
133f14d1886SSoby Mathew 	assert(type == INTR_TYPE_S_EL1 ||
134f14d1886SSoby Mathew 		       type == INTR_TYPE_EL3 ||
135f14d1886SSoby Mathew 		       type == INTR_TYPE_NS);
136f14d1886SSoby Mathew 
137*53a98be3SSanteri Salko 	assert(sec_state_is_valid(security_state));
138*53a98be3SSanteri 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 	 */
147f14d1886SSoby Mathew 	return ((gicv2_is_fiq_enabled()) ? __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 {
19374dce7faSJeenu Viswambharan 	switch (type) {
19474dce7faSJeenu Viswambharan #if GICV2_G0_FOR_EL3
19574dce7faSJeenu Viswambharan 	case INTR_TYPE_EL3:
19674dce7faSJeenu Viswambharan #else
19774dce7faSJeenu Viswambharan 	case INTR_TYPE_S_EL1:
19874dce7faSJeenu Viswambharan #endif
19974dce7faSJeenu Viswambharan 	case INTR_TYPE_NS:
20074dce7faSJeenu Viswambharan 		return 1;
20174dce7faSJeenu Viswambharan 	default:
20274dce7faSJeenu Viswambharan 		return 0;
20374dce7faSJeenu Viswambharan 	}
20474dce7faSJeenu Viswambharan }
20574dce7faSJeenu Viswambharan 
20674dce7faSJeenu Viswambharan void plat_ic_set_interrupt_type(unsigned int id, unsigned int type)
20774dce7faSJeenu Viswambharan {
20874dce7faSJeenu Viswambharan 	int gicv2_type = 0;
20974dce7faSJeenu Viswambharan 
21074dce7faSJeenu Viswambharan 	/* Map canonical interrupt type to GICv2 type */
21174dce7faSJeenu Viswambharan 	switch (type) {
21274dce7faSJeenu Viswambharan #if GICV2_G0_FOR_EL3
21374dce7faSJeenu Viswambharan 	case INTR_TYPE_EL3:
21474dce7faSJeenu Viswambharan #else
21574dce7faSJeenu Viswambharan 	case INTR_TYPE_S_EL1:
21674dce7faSJeenu Viswambharan #endif
21774dce7faSJeenu Viswambharan 		gicv2_type = GICV2_INTR_GROUP0;
21874dce7faSJeenu Viswambharan 		break;
21974dce7faSJeenu Viswambharan 	case INTR_TYPE_NS:
22074dce7faSJeenu Viswambharan 		gicv2_type = GICV2_INTR_GROUP1;
22174dce7faSJeenu Viswambharan 		break;
22274dce7faSJeenu Viswambharan 	default:
22374dce7faSJeenu Viswambharan 		assert(0);
22474dce7faSJeenu Viswambharan 	}
22574dce7faSJeenu Viswambharan 
22674dce7faSJeenu Viswambharan 	gicv2_set_interrupt_type(id, gicv2_type);
22774dce7faSJeenu Viswambharan }
2288db978b5SJeenu Viswambharan 
2298db978b5SJeenu Viswambharan void plat_ic_raise_el3_sgi(int sgi_num, u_register_t target)
2308db978b5SJeenu Viswambharan {
2318db978b5SJeenu Viswambharan #if GICV2_G0_FOR_EL3
2328db978b5SJeenu Viswambharan 	int id;
2338db978b5SJeenu Viswambharan 
2348db978b5SJeenu Viswambharan 	/* Target must be a valid MPIDR in the system */
2358db978b5SJeenu Viswambharan 	id = plat_core_pos_by_mpidr(target);
2368db978b5SJeenu Viswambharan 	assert(id >= 0);
2378db978b5SJeenu Viswambharan 
2388db978b5SJeenu Viswambharan 	/* Verify that this is a secure SGI */
2398db978b5SJeenu Viswambharan 	assert(plat_ic_get_interrupt_type(sgi_num) == INTR_TYPE_EL3);
2408db978b5SJeenu Viswambharan 
2418db978b5SJeenu Viswambharan 	gicv2_raise_sgi(sgi_num, id);
2428db978b5SJeenu Viswambharan #else
2438db978b5SJeenu Viswambharan 	assert(0);
2448db978b5SJeenu Viswambharan #endif
2458db978b5SJeenu Viswambharan }
246fc529feeSJeenu Viswambharan 
247fc529feeSJeenu Viswambharan void plat_ic_set_spi_routing(unsigned int id, unsigned int routing_mode,
248fc529feeSJeenu Viswambharan 		u_register_t mpidr)
249fc529feeSJeenu Viswambharan {
250fc529feeSJeenu Viswambharan 	int proc_num = 0;
251fc529feeSJeenu Viswambharan 
252fc529feeSJeenu Viswambharan 	switch (routing_mode) {
253fc529feeSJeenu Viswambharan 	case INTR_ROUTING_MODE_PE:
254fc529feeSJeenu Viswambharan 		proc_num = plat_core_pos_by_mpidr(mpidr);
255fc529feeSJeenu Viswambharan 		assert(proc_num >= 0);
256fc529feeSJeenu Viswambharan 		break;
257fc529feeSJeenu Viswambharan 	case INTR_ROUTING_MODE_ANY:
258fc529feeSJeenu Viswambharan 		/* Bit mask selecting all 8 CPUs as candidates */
259fc529feeSJeenu Viswambharan 		proc_num = -1;
260fc529feeSJeenu Viswambharan 		break;
261fc529feeSJeenu Viswambharan 	default:
262fc529feeSJeenu Viswambharan 		assert(0);
263fc529feeSJeenu Viswambharan 	}
264fc529feeSJeenu Viswambharan 
265fc529feeSJeenu Viswambharan 	gicv2_set_spi_routing(id, proc_num);
266fc529feeSJeenu Viswambharan }
267a2816a16SJeenu Viswambharan 
268a2816a16SJeenu Viswambharan void plat_ic_set_interrupt_pending(unsigned int id)
269a2816a16SJeenu Viswambharan {
270a2816a16SJeenu Viswambharan 	gicv2_set_interrupt_pending(id);
271a2816a16SJeenu Viswambharan }
272a2816a16SJeenu Viswambharan 
273a2816a16SJeenu Viswambharan void plat_ic_clear_interrupt_pending(unsigned int id)
274a2816a16SJeenu Viswambharan {
275a2816a16SJeenu Viswambharan 	gicv2_clear_interrupt_pending(id);
276a2816a16SJeenu Viswambharan }
277d55a4450SJeenu Viswambharan 
278d55a4450SJeenu Viswambharan unsigned int plat_ic_set_priority_mask(unsigned int mask)
279d55a4450SJeenu Viswambharan {
280d55a4450SJeenu Viswambharan 	return gicv2_set_pmr(mask);
281d55a4450SJeenu Viswambharan }
2824ee8d0beSJeenu Viswambharan 
2834ee8d0beSJeenu Viswambharan unsigned int plat_ic_get_interrupt_id(unsigned int raw)
2844ee8d0beSJeenu Viswambharan {
2854ee8d0beSJeenu Viswambharan 	unsigned int id = (raw & INT_ID_MASK);
2864ee8d0beSJeenu Viswambharan 
2874ee8d0beSJeenu Viswambharan 	if (id == GIC_SPURIOUS_INTERRUPT)
2884ee8d0beSJeenu Viswambharan 		id = INTR_ID_UNAVAILABLE;
2894ee8d0beSJeenu Viswambharan 
2904ee8d0beSJeenu Viswambharan 	return id;
2914ee8d0beSJeenu Viswambharan }
292