1*54fd6939SJiyong Park /*
2*54fd6939SJiyong Park * Copyright (c) 2015-2018, ARM Limited and Contributors. All rights reserved.
3*54fd6939SJiyong Park *
4*54fd6939SJiyong Park * SPDX-License-Identifier: BSD-3-Clause
5*54fd6939SJiyong Park */
6*54fd6939SJiyong Park
7*54fd6939SJiyong Park #include <assert.h>
8*54fd6939SJiyong Park #include <stdbool.h>
9*54fd6939SJiyong Park
10*54fd6939SJiyong Park #include <arch_helpers.h>
11*54fd6939SJiyong Park #include <common/bl_common.h>
12*54fd6939SJiyong Park #include <bl31/interrupt_mgmt.h>
13*54fd6939SJiyong Park #include <drivers/arm/gic_common.h>
14*54fd6939SJiyong Park #include <drivers/arm/gicv3.h>
15*54fd6939SJiyong Park #include <lib/cassert.h>
16*54fd6939SJiyong Park #include <plat/common/platform.h>
17*54fd6939SJiyong Park
18*54fd6939SJiyong Park #ifdef IMAGE_BL31
19*54fd6939SJiyong Park
20*54fd6939SJiyong Park /*
21*54fd6939SJiyong Park * The following platform GIC functions are weakly defined. They
22*54fd6939SJiyong Park * provide typical implementations that may be re-used by multiple
23*54fd6939SJiyong Park * platforms but may also be overridden by a platform if required.
24*54fd6939SJiyong Park */
25*54fd6939SJiyong Park #pragma weak plat_ic_get_pending_interrupt_id
26*54fd6939SJiyong Park #pragma weak plat_ic_get_pending_interrupt_type
27*54fd6939SJiyong Park #pragma weak plat_ic_acknowledge_interrupt
28*54fd6939SJiyong Park #pragma weak plat_ic_get_interrupt_type
29*54fd6939SJiyong Park #pragma weak plat_ic_end_of_interrupt
30*54fd6939SJiyong Park #pragma weak plat_interrupt_type_to_line
31*54fd6939SJiyong Park
32*54fd6939SJiyong Park #pragma weak plat_ic_get_running_priority
33*54fd6939SJiyong Park #pragma weak plat_ic_is_spi
34*54fd6939SJiyong Park #pragma weak plat_ic_is_ppi
35*54fd6939SJiyong Park #pragma weak plat_ic_is_sgi
36*54fd6939SJiyong Park #pragma weak plat_ic_get_interrupt_active
37*54fd6939SJiyong Park #pragma weak plat_ic_enable_interrupt
38*54fd6939SJiyong Park #pragma weak plat_ic_disable_interrupt
39*54fd6939SJiyong Park #pragma weak plat_ic_set_interrupt_priority
40*54fd6939SJiyong Park #pragma weak plat_ic_set_interrupt_type
41*54fd6939SJiyong Park #pragma weak plat_ic_raise_el3_sgi
42*54fd6939SJiyong Park #pragma weak plat_ic_set_spi_routing
43*54fd6939SJiyong Park #pragma weak plat_ic_set_interrupt_pending
44*54fd6939SJiyong Park #pragma weak plat_ic_clear_interrupt_pending
45*54fd6939SJiyong Park
46*54fd6939SJiyong Park CASSERT((INTR_TYPE_S_EL1 == INTR_GROUP1S) &&
47*54fd6939SJiyong Park (INTR_TYPE_NS == INTR_GROUP1NS) &&
48*54fd6939SJiyong Park (INTR_TYPE_EL3 == INTR_GROUP0), assert_interrupt_type_mismatch);
49*54fd6939SJiyong Park
50*54fd6939SJiyong Park /*
51*54fd6939SJiyong Park * This function returns the highest priority pending interrupt at
52*54fd6939SJiyong Park * the Interrupt controller
53*54fd6939SJiyong Park */
plat_ic_get_pending_interrupt_id(void)54*54fd6939SJiyong Park uint32_t plat_ic_get_pending_interrupt_id(void)
55*54fd6939SJiyong Park {
56*54fd6939SJiyong Park unsigned int irqnr;
57*54fd6939SJiyong Park
58*54fd6939SJiyong Park assert(IS_IN_EL3());
59*54fd6939SJiyong Park irqnr = gicv3_get_pending_interrupt_id();
60*54fd6939SJiyong Park return gicv3_is_intr_id_special_identifier(irqnr) ?
61*54fd6939SJiyong Park INTR_ID_UNAVAILABLE : irqnr;
62*54fd6939SJiyong Park }
63*54fd6939SJiyong Park
64*54fd6939SJiyong Park /*
65*54fd6939SJiyong Park * This function returns the type of the highest priority pending interrupt
66*54fd6939SJiyong Park * at the Interrupt controller. In the case of GICv3, the Highest Priority
67*54fd6939SJiyong Park * Pending interrupt system register (`ICC_HPPIR0_EL1`) is read to determine
68*54fd6939SJiyong Park * the id of the pending interrupt. The type of interrupt depends upon the
69*54fd6939SJiyong Park * id value as follows.
70*54fd6939SJiyong Park * 1. id = PENDING_G1S_INTID (1020) is reported as a S-EL1 interrupt
71*54fd6939SJiyong Park * 2. id = PENDING_G1NS_INTID (1021) is reported as a Non-secure interrupt.
72*54fd6939SJiyong Park * 3. id = GIC_SPURIOUS_INTERRUPT (1023) is reported as an invalid interrupt
73*54fd6939SJiyong Park * type.
74*54fd6939SJiyong Park * 4. All other interrupt id's are reported as EL3 interrupt.
75*54fd6939SJiyong Park */
plat_ic_get_pending_interrupt_type(void)76*54fd6939SJiyong Park uint32_t plat_ic_get_pending_interrupt_type(void)
77*54fd6939SJiyong Park {
78*54fd6939SJiyong Park unsigned int irqnr;
79*54fd6939SJiyong Park uint32_t type;
80*54fd6939SJiyong Park
81*54fd6939SJiyong Park assert(IS_IN_EL3());
82*54fd6939SJiyong Park irqnr = gicv3_get_pending_interrupt_type();
83*54fd6939SJiyong Park
84*54fd6939SJiyong Park switch (irqnr) {
85*54fd6939SJiyong Park case PENDING_G1S_INTID:
86*54fd6939SJiyong Park type = INTR_TYPE_S_EL1;
87*54fd6939SJiyong Park break;
88*54fd6939SJiyong Park case PENDING_G1NS_INTID:
89*54fd6939SJiyong Park type = INTR_TYPE_NS;
90*54fd6939SJiyong Park break;
91*54fd6939SJiyong Park case GIC_SPURIOUS_INTERRUPT:
92*54fd6939SJiyong Park type = INTR_TYPE_INVAL;
93*54fd6939SJiyong Park break;
94*54fd6939SJiyong Park default:
95*54fd6939SJiyong Park type = INTR_TYPE_EL3;
96*54fd6939SJiyong Park break;
97*54fd6939SJiyong Park }
98*54fd6939SJiyong Park
99*54fd6939SJiyong Park return type;
100*54fd6939SJiyong Park }
101*54fd6939SJiyong Park
102*54fd6939SJiyong Park /*
103*54fd6939SJiyong Park * This function returns the highest priority pending interrupt at
104*54fd6939SJiyong Park * the Interrupt controller and indicates to the Interrupt controller
105*54fd6939SJiyong Park * that the interrupt processing has started.
106*54fd6939SJiyong Park */
plat_ic_acknowledge_interrupt(void)107*54fd6939SJiyong Park uint32_t plat_ic_acknowledge_interrupt(void)
108*54fd6939SJiyong Park {
109*54fd6939SJiyong Park assert(IS_IN_EL3());
110*54fd6939SJiyong Park return gicv3_acknowledge_interrupt();
111*54fd6939SJiyong Park }
112*54fd6939SJiyong Park
113*54fd6939SJiyong Park /*
114*54fd6939SJiyong Park * This function returns the type of the interrupt `id`, depending on how
115*54fd6939SJiyong Park * the interrupt has been configured in the interrupt controller
116*54fd6939SJiyong Park */
plat_ic_get_interrupt_type(uint32_t id)117*54fd6939SJiyong Park uint32_t plat_ic_get_interrupt_type(uint32_t id)
118*54fd6939SJiyong Park {
119*54fd6939SJiyong Park assert(IS_IN_EL3());
120*54fd6939SJiyong Park return gicv3_get_interrupt_type(id, plat_my_core_pos());
121*54fd6939SJiyong Park }
122*54fd6939SJiyong Park
123*54fd6939SJiyong Park /*
124*54fd6939SJiyong Park * This functions is used to indicate to the interrupt controller that
125*54fd6939SJiyong Park * the processing of the interrupt corresponding to the `id` has
126*54fd6939SJiyong Park * finished.
127*54fd6939SJiyong Park */
plat_ic_end_of_interrupt(uint32_t id)128*54fd6939SJiyong Park void plat_ic_end_of_interrupt(uint32_t id)
129*54fd6939SJiyong Park {
130*54fd6939SJiyong Park assert(IS_IN_EL3());
131*54fd6939SJiyong Park gicv3_end_of_interrupt(id);
132*54fd6939SJiyong Park }
133*54fd6939SJiyong Park
134*54fd6939SJiyong Park /*
135*54fd6939SJiyong Park * An ARM processor signals interrupt exceptions through the IRQ and FIQ pins.
136*54fd6939SJiyong Park * The interrupt controller knows which pin/line it uses to signal a type of
137*54fd6939SJiyong Park * interrupt. It lets the interrupt management framework determine for a type of
138*54fd6939SJiyong Park * interrupt and security state, which line should be used in the SCR_EL3 to
139*54fd6939SJiyong Park * control its routing to EL3. The interrupt line is represented as the bit
140*54fd6939SJiyong Park * position of the IRQ or FIQ bit in the SCR_EL3.
141*54fd6939SJiyong Park */
plat_interrupt_type_to_line(uint32_t type,uint32_t security_state)142*54fd6939SJiyong Park uint32_t plat_interrupt_type_to_line(uint32_t type,
143*54fd6939SJiyong Park uint32_t security_state)
144*54fd6939SJiyong Park {
145*54fd6939SJiyong Park assert((type == INTR_TYPE_S_EL1) ||
146*54fd6939SJiyong Park (type == INTR_TYPE_EL3) ||
147*54fd6939SJiyong Park (type == INTR_TYPE_NS));
148*54fd6939SJiyong Park
149*54fd6939SJiyong Park assert(sec_state_is_valid(security_state));
150*54fd6939SJiyong Park assert(IS_IN_EL3());
151*54fd6939SJiyong Park
152*54fd6939SJiyong Park switch (type) {
153*54fd6939SJiyong Park case INTR_TYPE_S_EL1:
154*54fd6939SJiyong Park /*
155*54fd6939SJiyong Park * The S-EL1 interrupts are signaled as IRQ in S-EL0/1 contexts
156*54fd6939SJiyong Park * and as FIQ in the NS-EL0/1/2 contexts
157*54fd6939SJiyong Park */
158*54fd6939SJiyong Park if (security_state == SECURE)
159*54fd6939SJiyong Park return __builtin_ctz(SCR_IRQ_BIT);
160*54fd6939SJiyong Park else
161*54fd6939SJiyong Park return __builtin_ctz(SCR_FIQ_BIT);
162*54fd6939SJiyong Park assert(0); /* Unreachable */
163*54fd6939SJiyong Park case INTR_TYPE_NS:
164*54fd6939SJiyong Park /*
165*54fd6939SJiyong Park * The Non secure interrupts will be signaled as FIQ in S-EL0/1
166*54fd6939SJiyong Park * contexts and as IRQ in the NS-EL0/1/2 contexts.
167*54fd6939SJiyong Park */
168*54fd6939SJiyong Park if (security_state == SECURE)
169*54fd6939SJiyong Park return __builtin_ctz(SCR_FIQ_BIT);
170*54fd6939SJiyong Park else
171*54fd6939SJiyong Park return __builtin_ctz(SCR_IRQ_BIT);
172*54fd6939SJiyong Park assert(0); /* Unreachable */
173*54fd6939SJiyong Park case INTR_TYPE_EL3:
174*54fd6939SJiyong Park /*
175*54fd6939SJiyong Park * The EL3 interrupts are signaled as FIQ in both S-EL0/1 and
176*54fd6939SJiyong Park * NS-EL0/1/2 contexts
177*54fd6939SJiyong Park */
178*54fd6939SJiyong Park return __builtin_ctz(SCR_FIQ_BIT);
179*54fd6939SJiyong Park default:
180*54fd6939SJiyong Park panic();
181*54fd6939SJiyong Park }
182*54fd6939SJiyong Park }
183*54fd6939SJiyong Park
plat_ic_get_running_priority(void)184*54fd6939SJiyong Park unsigned int plat_ic_get_running_priority(void)
185*54fd6939SJiyong Park {
186*54fd6939SJiyong Park return gicv3_get_running_priority();
187*54fd6939SJiyong Park }
188*54fd6939SJiyong Park
plat_ic_is_spi(unsigned int id)189*54fd6939SJiyong Park int plat_ic_is_spi(unsigned int id)
190*54fd6939SJiyong Park {
191*54fd6939SJiyong Park return (id >= MIN_SPI_ID) && (id <= MAX_SPI_ID);
192*54fd6939SJiyong Park }
193*54fd6939SJiyong Park
plat_ic_is_ppi(unsigned int id)194*54fd6939SJiyong Park int plat_ic_is_ppi(unsigned int id)
195*54fd6939SJiyong Park {
196*54fd6939SJiyong Park return (id >= MIN_PPI_ID) && (id < MIN_SPI_ID);
197*54fd6939SJiyong Park }
198*54fd6939SJiyong Park
plat_ic_is_sgi(unsigned int id)199*54fd6939SJiyong Park int plat_ic_is_sgi(unsigned int id)
200*54fd6939SJiyong Park {
201*54fd6939SJiyong Park return (id >= MIN_SGI_ID) && (id < MIN_PPI_ID);
202*54fd6939SJiyong Park }
203*54fd6939SJiyong Park
plat_ic_get_interrupt_active(unsigned int id)204*54fd6939SJiyong Park unsigned int plat_ic_get_interrupt_active(unsigned int id)
205*54fd6939SJiyong Park {
206*54fd6939SJiyong Park return gicv3_get_interrupt_active(id, plat_my_core_pos());
207*54fd6939SJiyong Park }
208*54fd6939SJiyong Park
plat_ic_enable_interrupt(unsigned int id)209*54fd6939SJiyong Park void plat_ic_enable_interrupt(unsigned int id)
210*54fd6939SJiyong Park {
211*54fd6939SJiyong Park gicv3_enable_interrupt(id, plat_my_core_pos());
212*54fd6939SJiyong Park }
213*54fd6939SJiyong Park
plat_ic_disable_interrupt(unsigned int id)214*54fd6939SJiyong Park void plat_ic_disable_interrupt(unsigned int id)
215*54fd6939SJiyong Park {
216*54fd6939SJiyong Park gicv3_disable_interrupt(id, plat_my_core_pos());
217*54fd6939SJiyong Park }
218*54fd6939SJiyong Park
plat_ic_set_interrupt_priority(unsigned int id,unsigned int priority)219*54fd6939SJiyong Park void plat_ic_set_interrupt_priority(unsigned int id, unsigned int priority)
220*54fd6939SJiyong Park {
221*54fd6939SJiyong Park gicv3_set_interrupt_priority(id, plat_my_core_pos(), priority);
222*54fd6939SJiyong Park }
223*54fd6939SJiyong Park
plat_ic_has_interrupt_type(unsigned int type)224*54fd6939SJiyong Park int plat_ic_has_interrupt_type(unsigned int type)
225*54fd6939SJiyong Park {
226*54fd6939SJiyong Park assert((type == INTR_TYPE_EL3) || (type == INTR_TYPE_S_EL1) ||
227*54fd6939SJiyong Park (type == INTR_TYPE_NS));
228*54fd6939SJiyong Park return 1;
229*54fd6939SJiyong Park }
230*54fd6939SJiyong Park
plat_ic_set_interrupt_type(unsigned int id,unsigned int type)231*54fd6939SJiyong Park void plat_ic_set_interrupt_type(unsigned int id, unsigned int type)
232*54fd6939SJiyong Park {
233*54fd6939SJiyong Park gicv3_set_interrupt_type(id, plat_my_core_pos(), type);
234*54fd6939SJiyong Park }
235*54fd6939SJiyong Park
plat_ic_raise_el3_sgi(int sgi_num,u_register_t target)236*54fd6939SJiyong Park void plat_ic_raise_el3_sgi(int sgi_num, u_register_t target)
237*54fd6939SJiyong Park {
238*54fd6939SJiyong Park /* Target must be a valid MPIDR in the system */
239*54fd6939SJiyong Park assert(plat_core_pos_by_mpidr(target) >= 0);
240*54fd6939SJiyong Park
241*54fd6939SJiyong Park /* Verify that this is a secure EL3 SGI */
242*54fd6939SJiyong Park assert(plat_ic_get_interrupt_type((unsigned int)sgi_num) ==
243*54fd6939SJiyong Park INTR_TYPE_EL3);
244*54fd6939SJiyong Park
245*54fd6939SJiyong Park gicv3_raise_secure_g0_sgi((unsigned int)sgi_num, target);
246*54fd6939SJiyong Park }
247*54fd6939SJiyong Park
plat_ic_set_spi_routing(unsigned int id,unsigned int routing_mode,u_register_t mpidr)248*54fd6939SJiyong Park void plat_ic_set_spi_routing(unsigned int id, unsigned int routing_mode,
249*54fd6939SJiyong Park u_register_t mpidr)
250*54fd6939SJiyong Park {
251*54fd6939SJiyong Park unsigned int irm = 0;
252*54fd6939SJiyong Park
253*54fd6939SJiyong Park switch (routing_mode) {
254*54fd6939SJiyong Park case INTR_ROUTING_MODE_PE:
255*54fd6939SJiyong Park assert(plat_core_pos_by_mpidr(mpidr) >= 0);
256*54fd6939SJiyong Park irm = GICV3_IRM_PE;
257*54fd6939SJiyong Park break;
258*54fd6939SJiyong Park case INTR_ROUTING_MODE_ANY:
259*54fd6939SJiyong Park irm = GICV3_IRM_ANY;
260*54fd6939SJiyong Park break;
261*54fd6939SJiyong Park default:
262*54fd6939SJiyong Park assert(0); /* Unreachable */
263*54fd6939SJiyong Park break;
264*54fd6939SJiyong Park }
265*54fd6939SJiyong Park
266*54fd6939SJiyong Park gicv3_set_spi_routing(id, irm, mpidr);
267*54fd6939SJiyong Park }
268*54fd6939SJiyong Park
plat_ic_set_interrupt_pending(unsigned int id)269*54fd6939SJiyong Park void plat_ic_set_interrupt_pending(unsigned int id)
270*54fd6939SJiyong Park {
271*54fd6939SJiyong Park /* Disallow setting SGIs pending */
272*54fd6939SJiyong Park assert(id >= MIN_PPI_ID);
273*54fd6939SJiyong Park gicv3_set_interrupt_pending(id, plat_my_core_pos());
274*54fd6939SJiyong Park }
275*54fd6939SJiyong Park
plat_ic_clear_interrupt_pending(unsigned int id)276*54fd6939SJiyong Park void plat_ic_clear_interrupt_pending(unsigned int id)
277*54fd6939SJiyong Park {
278*54fd6939SJiyong Park /* Disallow setting SGIs pending */
279*54fd6939SJiyong Park assert(id >= MIN_PPI_ID);
280*54fd6939SJiyong Park gicv3_clear_interrupt_pending(id, plat_my_core_pos());
281*54fd6939SJiyong Park }
282*54fd6939SJiyong Park
plat_ic_set_priority_mask(unsigned int mask)283*54fd6939SJiyong Park unsigned int plat_ic_set_priority_mask(unsigned int mask)
284*54fd6939SJiyong Park {
285*54fd6939SJiyong Park return gicv3_set_pmr(mask);
286*54fd6939SJiyong Park }
287*54fd6939SJiyong Park
plat_ic_get_interrupt_id(unsigned int raw)288*54fd6939SJiyong Park unsigned int plat_ic_get_interrupt_id(unsigned int raw)
289*54fd6939SJiyong Park {
290*54fd6939SJiyong Park unsigned int id = raw & INT_ID_MASK;
291*54fd6939SJiyong Park
292*54fd6939SJiyong Park return gicv3_is_intr_id_special_identifier(id) ?
293*54fd6939SJiyong Park INTR_ID_UNAVAILABLE : id;
294*54fd6939SJiyong Park }
295*54fd6939SJiyong Park #endif
296*54fd6939SJiyong Park #ifdef IMAGE_BL32
297*54fd6939SJiyong Park
298*54fd6939SJiyong Park #pragma weak plat_ic_get_pending_interrupt_id
299*54fd6939SJiyong Park #pragma weak plat_ic_acknowledge_interrupt
300*54fd6939SJiyong Park #pragma weak plat_ic_end_of_interrupt
301*54fd6939SJiyong Park
302*54fd6939SJiyong Park /* In AArch32, the secure group1 interrupts are targeted to Secure PL1 */
303*54fd6939SJiyong Park #ifndef __aarch64__
304*54fd6939SJiyong Park #define IS_IN_EL1() IS_IN_SECURE()
305*54fd6939SJiyong Park #endif
306*54fd6939SJiyong Park
307*54fd6939SJiyong Park /*
308*54fd6939SJiyong Park * This function returns the highest priority pending interrupt at
309*54fd6939SJiyong Park * the Interrupt controller
310*54fd6939SJiyong Park */
plat_ic_get_pending_interrupt_id(void)311*54fd6939SJiyong Park uint32_t plat_ic_get_pending_interrupt_id(void)
312*54fd6939SJiyong Park {
313*54fd6939SJiyong Park unsigned int irqnr;
314*54fd6939SJiyong Park
315*54fd6939SJiyong Park assert(IS_IN_EL1());
316*54fd6939SJiyong Park irqnr = gicv3_get_pending_interrupt_id_sel1();
317*54fd6939SJiyong Park return (irqnr == GIC_SPURIOUS_INTERRUPT) ?
318*54fd6939SJiyong Park INTR_ID_UNAVAILABLE : irqnr;
319*54fd6939SJiyong Park }
320*54fd6939SJiyong Park
321*54fd6939SJiyong Park /*
322*54fd6939SJiyong Park * This function returns the highest priority pending interrupt at
323*54fd6939SJiyong Park * the Interrupt controller and indicates to the Interrupt controller
324*54fd6939SJiyong Park * that the interrupt processing has started.
325*54fd6939SJiyong Park */
plat_ic_acknowledge_interrupt(void)326*54fd6939SJiyong Park uint32_t plat_ic_acknowledge_interrupt(void)
327*54fd6939SJiyong Park {
328*54fd6939SJiyong Park assert(IS_IN_EL1());
329*54fd6939SJiyong Park return gicv3_acknowledge_interrupt_sel1();
330*54fd6939SJiyong Park }
331*54fd6939SJiyong Park
332*54fd6939SJiyong Park /*
333*54fd6939SJiyong Park * This functions is used to indicate to the interrupt controller that
334*54fd6939SJiyong Park * the processing of the interrupt corresponding to the `id` has
335*54fd6939SJiyong Park * finished.
336*54fd6939SJiyong Park */
plat_ic_end_of_interrupt(uint32_t id)337*54fd6939SJiyong Park void plat_ic_end_of_interrupt(uint32_t id)
338*54fd6939SJiyong Park {
339*54fd6939SJiyong Park assert(IS_IN_EL1());
340*54fd6939SJiyong Park gicv3_end_of_interrupt_sel1(id);
341*54fd6939SJiyong Park }
342*54fd6939SJiyong Park #endif
343