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