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