xref: /rk3399_ARM-atf/plat/common/plat_gicv3.c (revision ca43b55d22f3a48f408d16d4bedbf677cbdf8f48)
1 /*
2  * Copyright (c) 2015-2017, ARM Limited and Contributors. All rights reserved.
3  *
4  * SPDX-License-Identifier: BSD-3-Clause
5  */
6 #include <arch_helpers.h>
7 #include <assert.h>
8 #include <bl_common.h>
9 #include <cassert.h>
10 #include <gic_common.h>
11 #include <gicv3.h>
12 #include <interrupt_mgmt.h>
13 #include <platform.h>
14 
15 #ifdef IMAGE_BL31
16 
17 /*
18  * The following platform GIC functions are weakly defined. They
19  * provide typical implementations that may be re-used by multiple
20  * platforms but may also be overridden by a platform if required.
21  */
22 #pragma weak plat_ic_get_pending_interrupt_id
23 #pragma weak plat_ic_get_pending_interrupt_type
24 #pragma weak plat_ic_acknowledge_interrupt
25 #pragma weak plat_ic_get_interrupt_type
26 #pragma weak plat_ic_end_of_interrupt
27 #pragma weak plat_interrupt_type_to_line
28 
29 #pragma weak plat_ic_get_running_priority
30 #pragma weak plat_ic_is_spi
31 #pragma weak plat_ic_is_ppi
32 #pragma weak plat_ic_is_sgi
33 
34 CASSERT((INTR_TYPE_S_EL1 == INTR_GROUP1S) &&
35 	(INTR_TYPE_NS == INTR_GROUP1NS) &&
36 	(INTR_TYPE_EL3 == INTR_GROUP0), assert_interrupt_type_mismatch);
37 
38 /*
39  * This function returns the highest priority pending interrupt at
40  * the Interrupt controller
41  */
42 uint32_t plat_ic_get_pending_interrupt_id(void)
43 {
44 	unsigned int irqnr;
45 
46 	assert(IS_IN_EL3());
47 	irqnr = gicv3_get_pending_interrupt_id();
48 	return (gicv3_is_intr_id_special_identifier(irqnr)) ?
49 				INTR_ID_UNAVAILABLE : irqnr;
50 }
51 
52 /*
53  * This function returns the type of the highest priority pending interrupt
54  * at the Interrupt controller. In the case of GICv3, the Highest Priority
55  * Pending interrupt system register (`ICC_HPPIR0_EL1`) is read to determine
56  * the id of the pending interrupt. The type of interrupt depends upon the
57  * id value as follows.
58  *   1. id = PENDING_G1S_INTID (1020) is reported as a S-EL1 interrupt
59  *   2. id = PENDING_G1NS_INTID (1021) is reported as a Non-secure interrupt.
60  *   3. id = GIC_SPURIOUS_INTERRUPT (1023) is reported as an invalid interrupt
61  *           type.
62  *   4. All other interrupt id's are reported as EL3 interrupt.
63  */
64 uint32_t plat_ic_get_pending_interrupt_type(void)
65 {
66 	unsigned int irqnr;
67 
68 	assert(IS_IN_EL3());
69 	irqnr = gicv3_get_pending_interrupt_type();
70 
71 	switch (irqnr) {
72 	case PENDING_G1S_INTID:
73 		return INTR_TYPE_S_EL1;
74 	case PENDING_G1NS_INTID:
75 		return INTR_TYPE_NS;
76 	case GIC_SPURIOUS_INTERRUPT:
77 		return INTR_TYPE_INVAL;
78 	default:
79 		return INTR_TYPE_EL3;
80 	}
81 }
82 
83 /*
84  * This function returns the highest priority pending interrupt at
85  * the Interrupt controller and indicates to the Interrupt controller
86  * that the interrupt processing has started.
87  */
88 uint32_t plat_ic_acknowledge_interrupt(void)
89 {
90 	assert(IS_IN_EL3());
91 	return gicv3_acknowledge_interrupt();
92 }
93 
94 /*
95  * This function returns the type of the interrupt `id`, depending on how
96  * the interrupt has been configured in the interrupt controller
97  */
98 uint32_t plat_ic_get_interrupt_type(uint32_t id)
99 {
100 	assert(IS_IN_EL3());
101 	return gicv3_get_interrupt_type(id, plat_my_core_pos());
102 }
103 
104 /*
105  * This functions is used to indicate to the interrupt controller that
106  * the processing of the interrupt corresponding to the `id` has
107  * finished.
108  */
109 void plat_ic_end_of_interrupt(uint32_t id)
110 {
111 	assert(IS_IN_EL3());
112 	gicv3_end_of_interrupt(id);
113 }
114 
115 /*
116  * An ARM processor signals interrupt exceptions through the IRQ and FIQ pins.
117  * The interrupt controller knows which pin/line it uses to signal a type of
118  * interrupt. It lets the interrupt management framework determine for a type of
119  * interrupt and security state, which line should be used in the SCR_EL3 to
120  * control its routing to EL3. The interrupt line is represented as the bit
121  * position of the IRQ or FIQ bit in the SCR_EL3.
122  */
123 uint32_t plat_interrupt_type_to_line(uint32_t type,
124 				uint32_t security_state)
125 {
126 	assert(type == INTR_TYPE_S_EL1 ||
127 	       type == INTR_TYPE_EL3 ||
128 	       type == INTR_TYPE_NS);
129 
130 	assert(sec_state_is_valid(security_state));
131 	assert(IS_IN_EL3());
132 
133 	switch (type) {
134 	case INTR_TYPE_S_EL1:
135 		/*
136 		 * The S-EL1 interrupts are signaled as IRQ in S-EL0/1 contexts
137 		 * and as FIQ in the NS-EL0/1/2 contexts
138 		 */
139 		if (security_state == SECURE)
140 			return __builtin_ctz(SCR_IRQ_BIT);
141 		else
142 			return __builtin_ctz(SCR_FIQ_BIT);
143 	case INTR_TYPE_NS:
144 		/*
145 		 * The Non secure interrupts will be signaled as FIQ in S-EL0/1
146 		 * contexts and as IRQ in the NS-EL0/1/2 contexts.
147 		 */
148 		if (security_state == SECURE)
149 			return __builtin_ctz(SCR_FIQ_BIT);
150 		else
151 			return __builtin_ctz(SCR_IRQ_BIT);
152 	default:
153 		assert(0);
154 		/* Fall through in the release build */
155 	case INTR_TYPE_EL3:
156 		/*
157 		 * The EL3 interrupts are signaled as FIQ in both S-EL0/1 and
158 		 * NS-EL0/1/2 contexts
159 		 */
160 		return __builtin_ctz(SCR_FIQ_BIT);
161 	}
162 }
163 
164 unsigned int plat_ic_get_running_priority(void)
165 {
166 	return gicv3_get_running_priority();
167 }
168 
169 int plat_ic_is_spi(unsigned int id)
170 {
171 	return (id >= MIN_SPI_ID) && (id <= MAX_SPI_ID);
172 }
173 
174 int plat_ic_is_ppi(unsigned int id)
175 {
176 	return (id >= MIN_PPI_ID) && (id < MIN_SPI_ID);
177 }
178 
179 int plat_ic_is_sgi(unsigned int id)
180 {
181 	return (id >= MIN_SGI_ID) && (id < MIN_PPI_ID);
182 }
183 #endif
184 #ifdef IMAGE_BL32
185 
186 #pragma weak plat_ic_get_pending_interrupt_id
187 #pragma weak plat_ic_acknowledge_interrupt
188 #pragma weak plat_ic_end_of_interrupt
189 
190 /* In AArch32, the secure group1 interrupts are targeted to Secure PL1 */
191 #ifdef AARCH32
192 #define IS_IN_EL1()	IS_IN_SECURE()
193 #endif
194 
195 /*
196  * This function returns the highest priority pending interrupt at
197  * the Interrupt controller
198  */
199 uint32_t plat_ic_get_pending_interrupt_id(void)
200 {
201 	unsigned int irqnr;
202 
203 	assert(IS_IN_EL1());
204 	irqnr = gicv3_get_pending_interrupt_id_sel1();
205 	return (irqnr == GIC_SPURIOUS_INTERRUPT) ?
206 				INTR_ID_UNAVAILABLE : irqnr;
207 }
208 
209 /*
210  * This function returns the highest priority pending interrupt at
211  * the Interrupt controller and indicates to the Interrupt controller
212  * that the interrupt processing has started.
213  */
214 uint32_t plat_ic_acknowledge_interrupt(void)
215 {
216 	assert(IS_IN_EL1());
217 	return gicv3_acknowledge_interrupt_sel1();
218 }
219 
220 /*
221  * This functions is used to indicate to the interrupt controller that
222  * the processing of the interrupt corresponding to the `id` has
223  * finished.
224  */
225 void plat_ic_end_of_interrupt(uint32_t id)
226 {
227 	assert(IS_IN_EL1());
228 	gicv3_end_of_interrupt_sel1(id);
229 }
230 #endif
231