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