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