xref: /rk3399_ARM-atf/plat/common/plat_gicv2.c (revision 74dce7fa6e42cab3aa54a9543e4a546c1450b2ae)
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>
10f14d1886SSoby Mathew 
11f14d1886SSoby Mathew /*
12f14d1886SSoby Mathew  * The following platform GIC functions are weakly defined. They
13f14d1886SSoby Mathew  * provide typical implementations that may be re-used by multiple
14f14d1886SSoby Mathew  * platforms but may also be overridden by a platform if required.
15f14d1886SSoby Mathew  */
16f14d1886SSoby Mathew #pragma weak plat_ic_get_pending_interrupt_id
17f14d1886SSoby Mathew #pragma weak plat_ic_get_pending_interrupt_type
18f14d1886SSoby Mathew #pragma weak plat_ic_acknowledge_interrupt
19f14d1886SSoby Mathew #pragma weak plat_ic_get_interrupt_type
20f14d1886SSoby Mathew #pragma weak plat_ic_end_of_interrupt
21f14d1886SSoby Mathew #pragma weak plat_interrupt_type_to_line
22f14d1886SSoby Mathew 
23eb68ea9bSJeenu Viswambharan #pragma weak plat_ic_get_running_priority
24ca43b55dSJeenu Viswambharan #pragma weak plat_ic_is_spi
25ca43b55dSJeenu Viswambharan #pragma weak plat_ic_is_ppi
26ca43b55dSJeenu Viswambharan #pragma weak plat_ic_is_sgi
27cbd3f370SJeenu Viswambharan #pragma weak plat_ic_get_interrupt_active
28979225f4SJeenu Viswambharan #pragma weak plat_ic_enable_interrupt
29979225f4SJeenu Viswambharan #pragma weak plat_ic_disable_interrupt
30f3a86600SJeenu Viswambharan #pragma weak plat_ic_set_interrupt_priority
31*74dce7faSJeenu Viswambharan #pragma weak plat_ic_set_interrupt_type
32eb68ea9bSJeenu Viswambharan 
33f14d1886SSoby Mathew /*
34f14d1886SSoby Mathew  * This function returns the highest priority pending interrupt at
35f14d1886SSoby Mathew  * the Interrupt controller
36f14d1886SSoby Mathew  */
37f14d1886SSoby Mathew uint32_t plat_ic_get_pending_interrupt_id(void)
38f14d1886SSoby Mathew {
39f14d1886SSoby Mathew 	unsigned int id;
40f14d1886SSoby Mathew 
41f14d1886SSoby Mathew 	id = gicv2_get_pending_interrupt_id();
42f14d1886SSoby Mathew 	if (id == GIC_SPURIOUS_INTERRUPT)
43f14d1886SSoby Mathew 		return INTR_ID_UNAVAILABLE;
44f14d1886SSoby Mathew 
45f14d1886SSoby Mathew 	return id;
46f14d1886SSoby Mathew }
47f14d1886SSoby Mathew 
48f14d1886SSoby Mathew /*
49f14d1886SSoby Mathew  * This function returns the type of the highest priority pending interrupt
50f14d1886SSoby Mathew  * at the Interrupt controller. In the case of GICv2, the Highest Priority
51f14d1886SSoby Mathew  * Pending interrupt register (`GICC_HPPIR`) is read to determine the id of
52f14d1886SSoby Mathew  * the pending interrupt. The type of interrupt depends upon the id value
53f14d1886SSoby Mathew  * as follows.
54f14d1886SSoby Mathew  *   1. id < PENDING_G1_INTID (1022) is reported as a S-EL1 interrupt
55f14d1886SSoby Mathew  *   2. id = PENDING_G1_INTID (1022) is reported as a Non-secure interrupt.
56f14d1886SSoby Mathew  *   3. id = GIC_SPURIOUS_INTERRUPT (1023) is reported as an invalid interrupt
57f14d1886SSoby Mathew  *           type.
58f14d1886SSoby Mathew  */
59f14d1886SSoby Mathew uint32_t plat_ic_get_pending_interrupt_type(void)
60f14d1886SSoby Mathew {
61f14d1886SSoby Mathew 	unsigned int id;
62f14d1886SSoby Mathew 
63f14d1886SSoby Mathew 	id = gicv2_get_pending_interrupt_type();
64f14d1886SSoby Mathew 
65f14d1886SSoby Mathew 	/* Assume that all secure interrupts are S-EL1 interrupts */
66*74dce7faSJeenu Viswambharan 	if (id < PENDING_G1_INTID) {
67*74dce7faSJeenu Viswambharan #if GICV2_G0_FOR_EL3
68*74dce7faSJeenu Viswambharan 		return INTR_TYPE_EL3;
69*74dce7faSJeenu Viswambharan #else
70f14d1886SSoby Mathew 		return INTR_TYPE_S_EL1;
71*74dce7faSJeenu Viswambharan #endif
72*74dce7faSJeenu Viswambharan 	}
73f14d1886SSoby Mathew 
74f14d1886SSoby Mathew 	if (id == GIC_SPURIOUS_INTERRUPT)
75f14d1886SSoby Mathew 		return INTR_TYPE_INVAL;
76f14d1886SSoby Mathew 
77f14d1886SSoby Mathew 	return INTR_TYPE_NS;
78f14d1886SSoby Mathew }
79f14d1886SSoby Mathew 
80f14d1886SSoby Mathew /*
81f14d1886SSoby Mathew  * This function returns the highest priority pending interrupt at
82f14d1886SSoby Mathew  * the Interrupt controller and indicates to the Interrupt controller
83f14d1886SSoby Mathew  * that the interrupt processing has started.
84f14d1886SSoby Mathew  */
85f14d1886SSoby Mathew uint32_t plat_ic_acknowledge_interrupt(void)
86f14d1886SSoby Mathew {
87f14d1886SSoby Mathew 	return gicv2_acknowledge_interrupt();
88f14d1886SSoby Mathew }
89f14d1886SSoby Mathew 
90f14d1886SSoby Mathew /*
91f14d1886SSoby Mathew  * This function returns the type of the interrupt `id`, depending on how
92f14d1886SSoby Mathew  * the interrupt has been configured in the interrupt controller
93f14d1886SSoby Mathew  */
94f14d1886SSoby Mathew uint32_t plat_ic_get_interrupt_type(uint32_t id)
95f14d1886SSoby Mathew {
96f14d1886SSoby Mathew 	unsigned int type;
97f14d1886SSoby Mathew 
98f14d1886SSoby Mathew 	type = gicv2_get_interrupt_group(id);
99f14d1886SSoby Mathew 
100f14d1886SSoby Mathew 	/* Assume that all secure interrupts are S-EL1 interrupts */
101*74dce7faSJeenu Viswambharan 	return type == GICV2_INTR_GROUP1 ? INTR_TYPE_NS :
102*74dce7faSJeenu Viswambharan #if GICV2_G0_FOR_EL3
103*74dce7faSJeenu Viswambharan 		INTR_TYPE_EL3;
104*74dce7faSJeenu Viswambharan #else
105*74dce7faSJeenu Viswambharan 		INTR_TYPE_S_EL1;
106*74dce7faSJeenu Viswambharan #endif
107f14d1886SSoby Mathew }
108f14d1886SSoby Mathew 
109f14d1886SSoby Mathew /*
110f14d1886SSoby Mathew  * This functions is used to indicate to the interrupt controller that
111f14d1886SSoby Mathew  * the processing of the interrupt corresponding to the `id` has
112f14d1886SSoby Mathew  * finished.
113f14d1886SSoby Mathew  */
114f14d1886SSoby Mathew void plat_ic_end_of_interrupt(uint32_t id)
115f14d1886SSoby Mathew {
116f14d1886SSoby Mathew 	gicv2_end_of_interrupt(id);
117f14d1886SSoby Mathew }
118f14d1886SSoby Mathew 
119f14d1886SSoby Mathew /*
120f14d1886SSoby Mathew  * An ARM processor signals interrupt exceptions through the IRQ and FIQ pins.
121f14d1886SSoby Mathew  * The interrupt controller knows which pin/line it uses to signal a type of
122f14d1886SSoby Mathew  * interrupt. It lets the interrupt management framework determine
123f14d1886SSoby Mathew  * for a type of interrupt and security state, which line should be used in the
124f14d1886SSoby Mathew  * SCR_EL3 to control its routing to EL3. The interrupt line is represented
125f14d1886SSoby Mathew  * as the bit position of the IRQ or FIQ bit in the SCR_EL3.
126f14d1886SSoby Mathew  */
127f14d1886SSoby Mathew uint32_t plat_interrupt_type_to_line(uint32_t type,
128f14d1886SSoby Mathew 				uint32_t security_state)
129f14d1886SSoby Mathew {
130f14d1886SSoby Mathew 	assert(type == INTR_TYPE_S_EL1 ||
131f14d1886SSoby Mathew 		       type == INTR_TYPE_EL3 ||
132f14d1886SSoby Mathew 		       type == INTR_TYPE_NS);
133f14d1886SSoby Mathew 
134f14d1886SSoby Mathew 	/* Non-secure interrupts are signaled on the IRQ line always */
135f14d1886SSoby Mathew 	if (type == INTR_TYPE_NS)
136f14d1886SSoby Mathew 		return __builtin_ctz(SCR_IRQ_BIT);
137f14d1886SSoby Mathew 
138f14d1886SSoby Mathew 	/*
139f14d1886SSoby Mathew 	 * Secure interrupts are signaled using the IRQ line if the FIQ is
140f14d1886SSoby Mathew 	 * not enabled else they are signaled using the FIQ line.
141f14d1886SSoby Mathew 	 */
142f14d1886SSoby Mathew 	return ((gicv2_is_fiq_enabled()) ? __builtin_ctz(SCR_FIQ_BIT) :
143f14d1886SSoby Mathew 						__builtin_ctz(SCR_IRQ_BIT));
144f14d1886SSoby Mathew }
145eb68ea9bSJeenu Viswambharan 
146eb68ea9bSJeenu Viswambharan unsigned int plat_ic_get_running_priority(void)
147eb68ea9bSJeenu Viswambharan {
148eb68ea9bSJeenu Viswambharan 	return gicv2_get_running_priority();
149eb68ea9bSJeenu Viswambharan }
150ca43b55dSJeenu Viswambharan 
151ca43b55dSJeenu Viswambharan int plat_ic_is_spi(unsigned int id)
152ca43b55dSJeenu Viswambharan {
153ca43b55dSJeenu Viswambharan 	return (id >= MIN_SPI_ID) && (id <= MAX_SPI_ID);
154ca43b55dSJeenu Viswambharan }
155ca43b55dSJeenu Viswambharan 
156ca43b55dSJeenu Viswambharan int plat_ic_is_ppi(unsigned int id)
157ca43b55dSJeenu Viswambharan {
158ca43b55dSJeenu Viswambharan 	return (id >= MIN_PPI_ID) && (id < MIN_SPI_ID);
159ca43b55dSJeenu Viswambharan }
160ca43b55dSJeenu Viswambharan 
161ca43b55dSJeenu Viswambharan int plat_ic_is_sgi(unsigned int id)
162ca43b55dSJeenu Viswambharan {
163ca43b55dSJeenu Viswambharan 	return (id >= MIN_SGI_ID) && (id < MIN_PPI_ID);
164ca43b55dSJeenu Viswambharan }
165cbd3f370SJeenu Viswambharan 
166cbd3f370SJeenu Viswambharan unsigned int plat_ic_get_interrupt_active(unsigned int id)
167cbd3f370SJeenu Viswambharan {
168cbd3f370SJeenu Viswambharan 	return gicv2_get_interrupt_active(id);
169cbd3f370SJeenu Viswambharan }
170979225f4SJeenu Viswambharan 
171979225f4SJeenu Viswambharan void plat_ic_enable_interrupt(unsigned int id)
172979225f4SJeenu Viswambharan {
173979225f4SJeenu Viswambharan 	gicv2_enable_interrupt(id);
174979225f4SJeenu Viswambharan }
175979225f4SJeenu Viswambharan 
176979225f4SJeenu Viswambharan void plat_ic_disable_interrupt(unsigned int id)
177979225f4SJeenu Viswambharan {
178979225f4SJeenu Viswambharan 	gicv2_disable_interrupt(id);
179979225f4SJeenu Viswambharan }
180f3a86600SJeenu Viswambharan 
181f3a86600SJeenu Viswambharan void plat_ic_set_interrupt_priority(unsigned int id, unsigned int priority)
182f3a86600SJeenu Viswambharan {
183f3a86600SJeenu Viswambharan 	gicv2_set_interrupt_priority(id, priority);
184f3a86600SJeenu Viswambharan }
185*74dce7faSJeenu Viswambharan 
186*74dce7faSJeenu Viswambharan int plat_ic_has_interrupt_type(unsigned int type)
187*74dce7faSJeenu Viswambharan {
188*74dce7faSJeenu Viswambharan 	switch (type) {
189*74dce7faSJeenu Viswambharan #if GICV2_G0_FOR_EL3
190*74dce7faSJeenu Viswambharan 	case INTR_TYPE_EL3:
191*74dce7faSJeenu Viswambharan #else
192*74dce7faSJeenu Viswambharan 	case INTR_TYPE_S_EL1:
193*74dce7faSJeenu Viswambharan #endif
194*74dce7faSJeenu Viswambharan 	case INTR_TYPE_NS:
195*74dce7faSJeenu Viswambharan 		return 1;
196*74dce7faSJeenu Viswambharan 	default:
197*74dce7faSJeenu Viswambharan 		return 0;
198*74dce7faSJeenu Viswambharan 	}
199*74dce7faSJeenu Viswambharan }
200*74dce7faSJeenu Viswambharan 
201*74dce7faSJeenu Viswambharan void plat_ic_set_interrupt_type(unsigned int id, unsigned int type)
202*74dce7faSJeenu Viswambharan {
203*74dce7faSJeenu Viswambharan 	int gicv2_type = 0;
204*74dce7faSJeenu Viswambharan 
205*74dce7faSJeenu Viswambharan 	/* Map canonical interrupt type to GICv2 type */
206*74dce7faSJeenu Viswambharan 	switch (type) {
207*74dce7faSJeenu Viswambharan #if GICV2_G0_FOR_EL3
208*74dce7faSJeenu Viswambharan 	case INTR_TYPE_EL3:
209*74dce7faSJeenu Viswambharan #else
210*74dce7faSJeenu Viswambharan 	case INTR_TYPE_S_EL1:
211*74dce7faSJeenu Viswambharan #endif
212*74dce7faSJeenu Viswambharan 		gicv2_type = GICV2_INTR_GROUP0;
213*74dce7faSJeenu Viswambharan 		break;
214*74dce7faSJeenu Viswambharan 	case INTR_TYPE_NS:
215*74dce7faSJeenu Viswambharan 		gicv2_type = GICV2_INTR_GROUP1;
216*74dce7faSJeenu Viswambharan 		break;
217*74dce7faSJeenu Viswambharan 	default:
218*74dce7faSJeenu Viswambharan 		assert(0);
219*74dce7faSJeenu Viswambharan 	}
220*74dce7faSJeenu Viswambharan 
221*74dce7faSJeenu Viswambharan 	gicv2_set_interrupt_type(id, gicv2_type);
222*74dce7faSJeenu Viswambharan }
223