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