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 #pragma weak plat_ic_get_interrupt_active 34 #pragma weak plat_ic_enable_interrupt 35 #pragma weak plat_ic_disable_interrupt 36 #pragma weak plat_ic_set_interrupt_priority 37 #pragma weak plat_ic_set_interrupt_type 38 39 CASSERT((INTR_TYPE_S_EL1 == INTR_GROUP1S) && 40 (INTR_TYPE_NS == INTR_GROUP1NS) && 41 (INTR_TYPE_EL3 == INTR_GROUP0), assert_interrupt_type_mismatch); 42 43 /* 44 * This function returns the highest priority pending interrupt at 45 * the Interrupt controller 46 */ 47 uint32_t plat_ic_get_pending_interrupt_id(void) 48 { 49 unsigned int irqnr; 50 51 assert(IS_IN_EL3()); 52 irqnr = gicv3_get_pending_interrupt_id(); 53 return (gicv3_is_intr_id_special_identifier(irqnr)) ? 54 INTR_ID_UNAVAILABLE : irqnr; 55 } 56 57 /* 58 * This function returns the type of the highest priority pending interrupt 59 * at the Interrupt controller. In the case of GICv3, the Highest Priority 60 * Pending interrupt system register (`ICC_HPPIR0_EL1`) is read to determine 61 * the id of the pending interrupt. The type of interrupt depends upon the 62 * id value as follows. 63 * 1. id = PENDING_G1S_INTID (1020) is reported as a S-EL1 interrupt 64 * 2. id = PENDING_G1NS_INTID (1021) is reported as a Non-secure interrupt. 65 * 3. id = GIC_SPURIOUS_INTERRUPT (1023) is reported as an invalid interrupt 66 * type. 67 * 4. All other interrupt id's are reported as EL3 interrupt. 68 */ 69 uint32_t plat_ic_get_pending_interrupt_type(void) 70 { 71 unsigned int irqnr; 72 73 assert(IS_IN_EL3()); 74 irqnr = gicv3_get_pending_interrupt_type(); 75 76 switch (irqnr) { 77 case PENDING_G1S_INTID: 78 return INTR_TYPE_S_EL1; 79 case PENDING_G1NS_INTID: 80 return INTR_TYPE_NS; 81 case GIC_SPURIOUS_INTERRUPT: 82 return INTR_TYPE_INVAL; 83 default: 84 return INTR_TYPE_EL3; 85 } 86 } 87 88 /* 89 * This function returns the highest priority pending interrupt at 90 * the Interrupt controller and indicates to the Interrupt controller 91 * that the interrupt processing has started. 92 */ 93 uint32_t plat_ic_acknowledge_interrupt(void) 94 { 95 assert(IS_IN_EL3()); 96 return gicv3_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 assert(IS_IN_EL3()); 106 return gicv3_get_interrupt_type(id, plat_my_core_pos()); 107 } 108 109 /* 110 * This functions is used to indicate to the interrupt controller that 111 * the processing of the interrupt corresponding to the `id` has 112 * finished. 113 */ 114 void plat_ic_end_of_interrupt(uint32_t id) 115 { 116 assert(IS_IN_EL3()); 117 gicv3_end_of_interrupt(id); 118 } 119 120 /* 121 * An ARM processor signals interrupt exceptions through the IRQ and FIQ pins. 122 * The interrupt controller knows which pin/line it uses to signal a type of 123 * interrupt. It lets the interrupt management framework determine for a type of 124 * interrupt and security state, which line should be used in the SCR_EL3 to 125 * control its routing to EL3. The interrupt line is represented as the bit 126 * position of the IRQ or FIQ bit in the SCR_EL3. 127 */ 128 uint32_t plat_interrupt_type_to_line(uint32_t type, 129 uint32_t security_state) 130 { 131 assert(type == INTR_TYPE_S_EL1 || 132 type == INTR_TYPE_EL3 || 133 type == INTR_TYPE_NS); 134 135 assert(sec_state_is_valid(security_state)); 136 assert(IS_IN_EL3()); 137 138 switch (type) { 139 case INTR_TYPE_S_EL1: 140 /* 141 * The S-EL1 interrupts are signaled as IRQ in S-EL0/1 contexts 142 * and as FIQ in the NS-EL0/1/2 contexts 143 */ 144 if (security_state == SECURE) 145 return __builtin_ctz(SCR_IRQ_BIT); 146 else 147 return __builtin_ctz(SCR_FIQ_BIT); 148 case INTR_TYPE_NS: 149 /* 150 * The Non secure interrupts will be signaled as FIQ in S-EL0/1 151 * contexts and as IRQ in the NS-EL0/1/2 contexts. 152 */ 153 if (security_state == SECURE) 154 return __builtin_ctz(SCR_FIQ_BIT); 155 else 156 return __builtin_ctz(SCR_IRQ_BIT); 157 default: 158 assert(0); 159 /* Fall through in the release build */ 160 case INTR_TYPE_EL3: 161 /* 162 * The EL3 interrupts are signaled as FIQ in both S-EL0/1 and 163 * NS-EL0/1/2 contexts 164 */ 165 return __builtin_ctz(SCR_FIQ_BIT); 166 } 167 } 168 169 unsigned int plat_ic_get_running_priority(void) 170 { 171 return gicv3_get_running_priority(); 172 } 173 174 int plat_ic_is_spi(unsigned int id) 175 { 176 return (id >= MIN_SPI_ID) && (id <= MAX_SPI_ID); 177 } 178 179 int plat_ic_is_ppi(unsigned int id) 180 { 181 return (id >= MIN_PPI_ID) && (id < MIN_SPI_ID); 182 } 183 184 int plat_ic_is_sgi(unsigned int id) 185 { 186 return (id >= MIN_SGI_ID) && (id < MIN_PPI_ID); 187 } 188 189 unsigned int plat_ic_get_interrupt_active(unsigned int id) 190 { 191 return gicv3_get_interrupt_active(id, plat_my_core_pos()); 192 } 193 194 void plat_ic_enable_interrupt(unsigned int id) 195 { 196 gicv3_enable_interrupt(id, plat_my_core_pos()); 197 } 198 199 void plat_ic_disable_interrupt(unsigned int id) 200 { 201 gicv3_disable_interrupt(id, plat_my_core_pos()); 202 } 203 204 void plat_ic_set_interrupt_priority(unsigned int id, unsigned int priority) 205 { 206 gicv3_set_interrupt_priority(id, plat_my_core_pos(), priority); 207 } 208 209 int plat_ic_has_interrupt_type(unsigned int type) 210 { 211 assert((type == INTR_TYPE_EL3) || (type == INTR_TYPE_S_EL1) || 212 (type == INTR_TYPE_NS)); 213 return 1; 214 } 215 216 void plat_ic_set_interrupt_type(unsigned int id, unsigned int type) 217 { 218 gicv3_set_interrupt_type(id, plat_my_core_pos(), type); 219 } 220 #endif 221 #ifdef IMAGE_BL32 222 223 #pragma weak plat_ic_get_pending_interrupt_id 224 #pragma weak plat_ic_acknowledge_interrupt 225 #pragma weak plat_ic_end_of_interrupt 226 227 /* In AArch32, the secure group1 interrupts are targeted to Secure PL1 */ 228 #ifdef AARCH32 229 #define IS_IN_EL1() IS_IN_SECURE() 230 #endif 231 232 /* 233 * This function returns the highest priority pending interrupt at 234 * the Interrupt controller 235 */ 236 uint32_t plat_ic_get_pending_interrupt_id(void) 237 { 238 unsigned int irqnr; 239 240 assert(IS_IN_EL1()); 241 irqnr = gicv3_get_pending_interrupt_id_sel1(); 242 return (irqnr == GIC_SPURIOUS_INTERRUPT) ? 243 INTR_ID_UNAVAILABLE : irqnr; 244 } 245 246 /* 247 * This function returns the highest priority pending interrupt at 248 * the Interrupt controller and indicates to the Interrupt controller 249 * that the interrupt processing has started. 250 */ 251 uint32_t plat_ic_acknowledge_interrupt(void) 252 { 253 assert(IS_IN_EL1()); 254 return gicv3_acknowledge_interrupt_sel1(); 255 } 256 257 /* 258 * This functions is used to indicate to the interrupt controller that 259 * the processing of the interrupt corresponding to the `id` has 260 * finished. 261 */ 262 void plat_ic_end_of_interrupt(uint32_t id) 263 { 264 assert(IS_IN_EL1()); 265 gicv3_end_of_interrupt_sel1(id); 266 } 267 #endif 268