1 /* 2 * Copyright (c) 2015-2021, ARM Limited and Contributors. All rights reserved. 3 * 4 * SPDX-License-Identifier: BSD-3-Clause 5 */ 6 7 #include <assert.h> 8 #include <platform_def.h> 9 10 #include <common/interrupt_props.h> 11 #include <drivers/arm/gicv3.h> 12 #include <fconf_hw_config_getter.h> 13 #include <lib/utils.h> 14 #include <plat/arm/common/plat_arm.h> 15 #include <plat/arm/common/fconf_sec_intr_config.h> 16 #include <plat/common/platform.h> 17 18 #if FVP_GICR_REGION_PROTECTION 19 /* To indicate GICR region of the core initialized as Read-Write */ 20 static bool fvp_gicr_rw_region_init[PLATFORM_CORE_COUNT] = {false}; 21 #endif /* FVP_GICR_REGION_PROTECTION */ 22 23 /* The GICv3 driver only needs to be initialized in EL3 */ 24 static uintptr_t fvp_rdistif_base_addrs[PLATFORM_CORE_COUNT]; 25 26 /* Default GICR base address to be used for GICR probe. */ 27 static uint64_t fvp_gicr_base_addrs[2] = { 0U }; 28 29 /* List of zero terminated GICR frame addresses which CPUs will probe */ 30 static uint64_t *fvp_gicr_frames = fvp_gicr_base_addrs; 31 32 #if !(SEC_INT_DESC_IN_FCONF && ((!defined(__aarch64__) && defined(IMAGE_BL32)) || \ 33 (defined(__aarch64__) && defined(IMAGE_BL31)))) 34 static const interrupt_prop_t fvp_interrupt_props[] = { 35 PLAT_ARM_G1S_IRQ_PROPS(INTR_GROUP1S), 36 PLAT_ARM_G0_IRQ_PROPS(INTR_GROUP0) 37 }; 38 #endif 39 40 /* 41 * MPIDR hashing function for translating MPIDRs read from GICR_TYPER register 42 * to core position. 43 * 44 * Calculating core position is dependent on MPIDR_EL1.MT bit. However, affinity 45 * values read from GICR_TYPER don't have an MT field. To reuse the same 46 * translation used for CPUs, we insert MT bit read from the PE's MPIDR into 47 * that read from GICR_TYPER. 48 * 49 * Assumptions: 50 * 51 * - All CPUs implemented in the system have MPIDR_EL1.MT bit set; 52 * - No CPUs implemented in the system use affinity level 3. 53 */ 54 static unsigned int fvp_gicv3_mpidr_hash(u_register_t mpidr) 55 { 56 u_register_t temp_mpidr = mpidr; 57 58 temp_mpidr |= (read_mpidr_el1() & MPIDR_MT_MASK); 59 return plat_arm_calc_core_pos(temp_mpidr); 60 } 61 62 63 static gicv3_driver_data_t fvp_gic_data = { 64 .rdistif_num = PLATFORM_CORE_COUNT, 65 .rdistif_base_addrs = fvp_rdistif_base_addrs, 66 .mpidr_to_core_pos = fvp_gicv3_mpidr_hash 67 }; 68 69 /****************************************************************************** 70 * This function gets called per core to make its redistributor frame rw 71 *****************************************************************************/ 72 static void fvp_gicv3_make_rdistrif_rw(void) 73 { 74 #if FVP_GICR_REGION_PROTECTION 75 unsigned int core_pos = plat_my_core_pos(); 76 77 /* Make the redistributor frame RW if it is not done previously */ 78 if (fvp_gicr_rw_region_init[core_pos] != true) { 79 int ret = xlat_change_mem_attributes(BASE_GICR_BASE + 80 (core_pos * BASE_GICR_SIZE), 81 BASE_GICR_SIZE, 82 MT_EXECUTE_NEVER | 83 MT_DEVICE | MT_RW | 84 MT_SECURE); 85 86 if (ret != 0) { 87 ERROR("Failed to make redistributor frame \ 88 read write = %d\n", ret); 89 panic(); 90 } else { 91 fvp_gicr_rw_region_init[core_pos] = true; 92 } 93 } 94 #else 95 return; 96 #endif /* FVP_GICR_REGION_PROTECTION */ 97 } 98 99 void plat_arm_gic_driver_init(void) 100 { 101 fvp_gicv3_make_rdistrif_rw(); 102 /* 103 * Get GICD and GICR base addressed through FCONF APIs. 104 * FCONF is not supported in BL32 for FVP. 105 */ 106 #if (!defined(__aarch64__) && defined(IMAGE_BL32)) || \ 107 (defined(__aarch64__) && defined(IMAGE_BL31)) 108 fvp_gic_data.gicd_base = (uintptr_t)FCONF_GET_PROPERTY(hw_config, 109 gicv3_config, 110 gicd_base); 111 fvp_gicr_base_addrs[0] = FCONF_GET_PROPERTY(hw_config, gicv3_config, 112 gicr_base); 113 #if SEC_INT_DESC_IN_FCONF 114 fvp_gic_data.interrupt_props = FCONF_GET_PROPERTY(hw_config, 115 sec_intr_prop, descriptor); 116 fvp_gic_data.interrupt_props_num = FCONF_GET_PROPERTY(hw_config, 117 sec_intr_prop, count); 118 #else 119 fvp_gic_data.interrupt_props = fvp_interrupt_props; 120 fvp_gic_data.interrupt_props_num = ARRAY_SIZE(fvp_interrupt_props); 121 #endif 122 #else 123 fvp_gic_data.gicd_base = PLAT_ARM_GICD_BASE; 124 fvp_gicr_base_addrs[0] = PLAT_ARM_GICR_BASE; 125 fvp_gic_data.interrupt_props = fvp_interrupt_props; 126 fvp_gic_data.interrupt_props_num = ARRAY_SIZE(fvp_interrupt_props); 127 #endif 128 129 /* 130 * The GICv3 driver is initialized in EL3 and does not need 131 * to be initialized again in SEL1. This is because the S-EL1 132 * can use GIC system registers to manage interrupts and does 133 * not need GIC interface base addresses to be configured. 134 */ 135 136 #if (!defined(__aarch64__) && defined(IMAGE_BL32)) || \ 137 (defined(__aarch64__) && defined(IMAGE_BL31)) 138 gicv3_driver_init(&fvp_gic_data); 139 if (gicv3_rdistif_probe((uintptr_t)fvp_gicr_base_addrs[0]) == -1) { 140 ERROR("No GICR base frame found for Primary CPU\n"); 141 panic(); 142 } 143 #endif 144 } 145 146 /****************************************************************************** 147 * Function to iterate over all GICR frames and discover the corresponding 148 * per-cpu redistributor frame as well as initialize the corresponding 149 * interface in GICv3. 150 *****************************************************************************/ 151 void plat_arm_gic_pcpu_init(void) 152 { 153 int result; 154 const uint64_t *plat_gicr_frames = fvp_gicr_frames; 155 156 fvp_gicv3_make_rdistrif_rw(); 157 158 do { 159 result = gicv3_rdistif_probe(*plat_gicr_frames); 160 161 /* If the probe is successful, no need to proceed further */ 162 if (result == 0) 163 break; 164 165 plat_gicr_frames++; 166 } while (*plat_gicr_frames != 0U); 167 168 if (result == -1) { 169 ERROR("No GICR base frame found for CPU 0x%lx\n", read_mpidr()); 170 panic(); 171 } 172 gicv3_rdistif_init(plat_my_core_pos()); 173 } 174