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