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