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