1 /* 2 * Copyright (c) 2013-2017, ARM Limited and Contributors. All rights reserved. 3 * 4 * SPDX-License-Identifier: BSD-3-Clause 5 */ 6 7 #include <arch.h> 8 #include <asm_macros.S> 9 #include <gicv2.h> 10 #include <gicv3.h> 11 #include <platform_def.h> 12 #include <v2m_def.h> 13 #include "../drivers/pwrc/fvp_pwrc.h" 14 #include "../fvp_def.h" 15 16 .globl plat_secondary_cold_boot_setup 17 .globl plat_get_my_entrypoint 18 .globl plat_is_my_cpu_primary 19 .globl plat_arm_calc_core_pos 20 21 .macro fvp_choose_gicmmap param1, param2, x_tmp, w_tmp, res 22 ldr \x_tmp, =V2M_SYSREGS_BASE + V2M_SYS_ID 23 ldr \w_tmp, [\x_tmp] 24 ubfx \w_tmp, \w_tmp, #V2M_SYS_ID_BLD_SHIFT, #V2M_SYS_ID_BLD_LENGTH 25 cmp \w_tmp, #BLD_GIC_VE_MMAP 26 csel \res, \param1, \param2, eq 27 .endm 28 29 /* ----------------------------------------------------- 30 * void plat_secondary_cold_boot_setup (void); 31 * 32 * This function performs any platform specific actions 33 * needed for a secondary cpu after a cold reset e.g 34 * mark the cpu's presence, mechanism to place it in a 35 * holding pen etc. 36 * TODO: Should we read the PSYS register to make sure 37 * that the request has gone through. 38 * ----------------------------------------------------- 39 */ 40 func plat_secondary_cold_boot_setup 41 #ifndef EL3_PAYLOAD_BASE 42 /* --------------------------------------------- 43 * Power down this cpu. 44 * TODO: Do we need to worry about powering the 45 * cluster down as well here. That will need 46 * locks which we won't have unless an elf- 47 * loader zeroes out the zi section. 48 * --------------------------------------------- 49 */ 50 mrs x0, mpidr_el1 51 ldr x1, =PWRC_BASE 52 str w0, [x1, #PPOFFR_OFF] 53 54 /* --------------------------------------------- 55 * Disable GIC bypass as well 56 * --------------------------------------------- 57 */ 58 /* Check for GICv3 system register access */ 59 mrs x0, id_aa64pfr0_el1 60 ubfx x0, x0, #ID_AA64PFR0_GIC_SHIFT, #ID_AA64PFR0_GIC_WIDTH 61 cmp x0, #1 62 b.ne gicv2_bypass_disable 63 64 /* Check for SRE enable */ 65 mrs x1, ICC_SRE_EL3 66 tst x1, #ICC_SRE_SRE_BIT 67 b.eq gicv2_bypass_disable 68 69 mrs x2, ICC_SRE_EL3 70 orr x2, x2, #(ICC_SRE_DIB_BIT | ICC_SRE_DFB_BIT) 71 msr ICC_SRE_EL3, x2 72 b secondary_cold_boot_wait 73 74 gicv2_bypass_disable: 75 ldr x0, =VE_GICC_BASE 76 ldr x1, =BASE_GICC_BASE 77 fvp_choose_gicmmap x0, x1, x2, w2, x1 78 mov w0, #(IRQ_BYP_DIS_GRP1 | FIQ_BYP_DIS_GRP1) 79 orr w0, w0, #(IRQ_BYP_DIS_GRP0 | FIQ_BYP_DIS_GRP0) 80 str w0, [x1, #GICC_CTLR] 81 82 secondary_cold_boot_wait: 83 /* --------------------------------------------- 84 * There is no sane reason to come out of this 85 * wfi so panic if we do. This cpu will be pow- 86 * ered on and reset by the cpu_on pm api 87 * --------------------------------------------- 88 */ 89 dsb sy 90 wfi 91 no_ret plat_panic_handler 92 #else 93 mov_imm x0, PLAT_ARM_TRUSTED_MAILBOX_BASE 94 95 /* Wait until the entrypoint gets populated */ 96 poll_mailbox: 97 ldr x1, [x0] 98 cbz x1, 1f 99 br x1 100 1: 101 wfe 102 b poll_mailbox 103 #endif /* EL3_PAYLOAD_BASE */ 104 endfunc plat_secondary_cold_boot_setup 105 106 /* --------------------------------------------------------------------- 107 * uintptr_t plat_get_my_entrypoint (void); 108 * 109 * Main job of this routine is to distinguish between a cold and warm 110 * boot. On FVP, this information can be queried from the power 111 * controller. The Power Control SYS Status Register (PSYSR) indicates 112 * the wake-up reason for the CPU. 113 * 114 * For a cold boot, return 0. 115 * For a warm boot, read the mailbox and return the address it contains. 116 * 117 * TODO: PSYSR is a common register and should be 118 * accessed using locks. Since it is not possible 119 * to use locks immediately after a cold reset 120 * we are relying on the fact that after a cold 121 * reset all cpus will read the same WK field 122 * --------------------------------------------------------------------- 123 */ 124 func plat_get_my_entrypoint 125 /* --------------------------------------------------------------------- 126 * When bit PSYSR.WK indicates either "Wake by PPONR" or "Wake by GIC 127 * WakeRequest signal" then it is a warm boot. 128 * --------------------------------------------------------------------- 129 */ 130 mrs x2, mpidr_el1 131 ldr x1, =PWRC_BASE 132 str w2, [x1, #PSYSR_OFF] 133 ldr w2, [x1, #PSYSR_OFF] 134 ubfx w2, w2, #PSYSR_WK_SHIFT, #PSYSR_WK_WIDTH 135 cmp w2, #WKUP_PPONR 136 beq warm_reset 137 cmp w2, #WKUP_GICREQ 138 beq warm_reset 139 140 /* Cold reset */ 141 mov x0, #0 142 ret 143 144 warm_reset: 145 /* --------------------------------------------------------------------- 146 * A mailbox is maintained in the trusted SRAM. It is flushed out of the 147 * caches after every update using normal memory so it is safe to read 148 * it here with SO attributes. 149 * --------------------------------------------------------------------- 150 */ 151 mov_imm x0, PLAT_ARM_TRUSTED_MAILBOX_BASE 152 ldr x0, [x0] 153 cbz x0, _panic_handler 154 ret 155 156 /* --------------------------------------------------------------------- 157 * The power controller indicates this is a warm reset but the mailbox 158 * is empty. This should never happen! 159 * --------------------------------------------------------------------- 160 */ 161 _panic_handler: 162 no_ret plat_panic_handler 163 endfunc plat_get_my_entrypoint 164 165 /* ----------------------------------------------------- 166 * unsigned int plat_is_my_cpu_primary (void); 167 * 168 * Find out whether the current cpu is the primary 169 * cpu. 170 * ----------------------------------------------------- 171 */ 172 func plat_is_my_cpu_primary 173 mrs x0, mpidr_el1 174 ldr x1, =MPIDR_AFFINITY_MASK 175 and x0, x0, x1 176 cmp x0, #FVP_PRIMARY_CPU 177 cset w0, eq 178 ret 179 endfunc plat_is_my_cpu_primary 180 181 /* ----------------------------------------------------- 182 * unsigned int plat_arm_calc_core_pos(u_register_t mpidr) 183 * 184 * Function to calculate the core position on FVP. 185 * 186 * (ClusterId * FVP_MAX_CPUS_PER_CLUSTER) + 187 * (CPUId * FVP_MAX_PE_PER_CPU) + 188 * ThreadId 189 * ----------------------------------------------------- 190 */ 191 func plat_arm_calc_core_pos 192 mov x3, x0 193 194 /* 195 * Check for MT bit in MPIDR. If not set, shift MPIDR to left to make it 196 * look as if in a multi-threaded implementation. 197 */ 198 tst x0, #MPIDR_MT_MASK 199 lsl x3, x0, #MPIDR_AFFINITY_BITS 200 csel x3, x3, x0, eq 201 202 /* Extract individual affinity fields from MPIDR */ 203 ubfx x0, x3, #MPIDR_AFF0_SHIFT, #MPIDR_AFFINITY_BITS 204 ubfx x1, x3, #MPIDR_AFF1_SHIFT, #MPIDR_AFFINITY_BITS 205 ubfx x2, x3, #MPIDR_AFF2_SHIFT, #MPIDR_AFFINITY_BITS 206 207 /* Compute linear position */ 208 mov x4, #FVP_MAX_PE_PER_CPU 209 madd x0, x1, x4, x0 210 mov x5, #FVP_MAX_CPUS_PER_CLUSTER 211 madd x0, x2, x5, x0 212 ret 213 endfunc plat_arm_calc_core_pos 214