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