1*91f16700Schasinglulu/* 2*91f16700Schasinglulu * Copyright (c) 2016-2017, 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/fvp/fvp_pwrc.h> 10*91f16700Schasinglulu#include <platform_def.h> 11*91f16700Schasinglulu 12*91f16700Schasinglulu .globl plat_secondary_cold_boot_setup 13*91f16700Schasinglulu .globl plat_get_my_entrypoint 14*91f16700Schasinglulu .globl plat_is_my_cpu_primary 15*91f16700Schasinglulu .globl plat_arm_calc_core_pos 16*91f16700Schasinglulu 17*91f16700Schasinglulu /* -------------------------------------------------------------------- 18*91f16700Schasinglulu * void plat_secondary_cold_boot_setup (void); 19*91f16700Schasinglulu * 20*91f16700Schasinglulu * For AArch32, cold-booting secondary CPUs is not yet 21*91f16700Schasinglulu * implemented and they panic. 22*91f16700Schasinglulu * -------------------------------------------------------------------- 23*91f16700Schasinglulu */ 24*91f16700Schasinglulufunc plat_secondary_cold_boot_setup 25*91f16700Schasinglulucb_panic: 26*91f16700Schasinglulu b cb_panic 27*91f16700Schasingluluendfunc plat_secondary_cold_boot_setup 28*91f16700Schasinglulu 29*91f16700Schasinglulu /* --------------------------------------------------------------------- 30*91f16700Schasinglulu * unsigned long plat_get_my_entrypoint (void); 31*91f16700Schasinglulu * 32*91f16700Schasinglulu * Main job of this routine is to distinguish between a cold and warm 33*91f16700Schasinglulu * boot. On FVP, this information can be queried from the power 34*91f16700Schasinglulu * controller. The Power Control SYS Status Register (PSYSR) indicates 35*91f16700Schasinglulu * the wake-up reason for the CPU. 36*91f16700Schasinglulu * 37*91f16700Schasinglulu * For a cold boot, return 0. 38*91f16700Schasinglulu * For a warm boot, read the mailbox and return the address it contains. 39*91f16700Schasinglulu * 40*91f16700Schasinglulu * TODO: PSYSR is a common register and should be 41*91f16700Schasinglulu * accessed using locks. Since it is not possible 42*91f16700Schasinglulu * to use locks immediately after a cold reset 43*91f16700Schasinglulu * we are relying on the fact that after a cold 44*91f16700Schasinglulu * reset all cpus will read the same WK field 45*91f16700Schasinglulu * --------------------------------------------------------------------- 46*91f16700Schasinglulu */ 47*91f16700Schasinglulufunc plat_get_my_entrypoint 48*91f16700Schasinglulu /* --------------------------------------------------------------------- 49*91f16700Schasinglulu * When bit PSYSR.WK indicates either "Wake by PPONR" or "Wake by GIC 50*91f16700Schasinglulu * WakeRequest signal" then it is a warm boot. 51*91f16700Schasinglulu * --------------------------------------------------------------------- 52*91f16700Schasinglulu */ 53*91f16700Schasinglulu ldcopr r2, MPIDR 54*91f16700Schasinglulu ldr r1, =PWRC_BASE 55*91f16700Schasinglulu str r2, [r1, #PSYSR_OFF] 56*91f16700Schasinglulu ldr r2, [r1, #PSYSR_OFF] 57*91f16700Schasinglulu ubfx r2, r2, #PSYSR_WK_SHIFT, #PSYSR_WK_WIDTH 58*91f16700Schasinglulu cmp r2, #WKUP_PPONR 59*91f16700Schasinglulu beq warm_reset 60*91f16700Schasinglulu cmp r2, #WKUP_GICREQ 61*91f16700Schasinglulu beq warm_reset 62*91f16700Schasinglulu 63*91f16700Schasinglulu /* Cold reset */ 64*91f16700Schasinglulu mov r0, #0 65*91f16700Schasinglulu bx lr 66*91f16700Schasinglulu 67*91f16700Schasingluluwarm_reset: 68*91f16700Schasinglulu /* --------------------------------------------------------------------- 69*91f16700Schasinglulu * A mailbox is maintained in the trusted SRAM. It is flushed out of the 70*91f16700Schasinglulu * caches after every update using normal memory so it is safe to read 71*91f16700Schasinglulu * it here with SO attributes. 72*91f16700Schasinglulu * --------------------------------------------------------------------- 73*91f16700Schasinglulu */ 74*91f16700Schasinglulu ldr r0, =PLAT_ARM_TRUSTED_MAILBOX_BASE 75*91f16700Schasinglulu ldr r0, [r0] 76*91f16700Schasinglulu cmp r0, #0 77*91f16700Schasinglulu beq _panic 78*91f16700Schasinglulu bx lr 79*91f16700Schasinglulu 80*91f16700Schasinglulu /* --------------------------------------------------------------------- 81*91f16700Schasinglulu * The power controller indicates this is a warm reset but the mailbox 82*91f16700Schasinglulu * is empty. This should never happen! 83*91f16700Schasinglulu * --------------------------------------------------------------------- 84*91f16700Schasinglulu */ 85*91f16700Schasinglulu_panic: 86*91f16700Schasinglulu b _panic 87*91f16700Schasingluluendfunc plat_get_my_entrypoint 88*91f16700Schasinglulu 89*91f16700Schasinglulu /* ----------------------------------------------------- 90*91f16700Schasinglulu * unsigned int plat_is_my_cpu_primary (void); 91*91f16700Schasinglulu * 92*91f16700Schasinglulu * Find out whether the current cpu is the primary 93*91f16700Schasinglulu * cpu. 94*91f16700Schasinglulu * ----------------------------------------------------- 95*91f16700Schasinglulu */ 96*91f16700Schasinglulufunc plat_is_my_cpu_primary 97*91f16700Schasinglulu ldcopr r0, MPIDR 98*91f16700Schasinglulu ldr r1, =MPIDR_AFFINITY_MASK 99*91f16700Schasinglulu and r0, r1 100*91f16700Schasinglulu cmp r0, #FVP_PRIMARY_CPU 101*91f16700Schasinglulu moveq r0, #1 102*91f16700Schasinglulu movne r0, #0 103*91f16700Schasinglulu bx lr 104*91f16700Schasingluluendfunc plat_is_my_cpu_primary 105*91f16700Schasinglulu 106*91f16700Schasinglulu /* --------------------------------------------------------------------- 107*91f16700Schasinglulu * unsigned int plat_arm_calc_core_pos(u_register_t mpidr) 108*91f16700Schasinglulu * 109*91f16700Schasinglulu * Function to calculate the core position on FVP. 110*91f16700Schasinglulu * 111*91f16700Schasinglulu * (ClusterId * FVP_MAX_CPUS_PER_CLUSTER * FVP_MAX_PE_PER_CPU) + 112*91f16700Schasinglulu * (CPUId * FVP_MAX_PE_PER_CPU) + 113*91f16700Schasinglulu * ThreadId 114*91f16700Schasinglulu * 115*91f16700Schasinglulu * which can be simplified as: 116*91f16700Schasinglulu * 117*91f16700Schasinglulu * ((ClusterId * FVP_MAX_CPUS_PER_CLUSTER + CPUId) * FVP_MAX_PE_PER_CPU) 118*91f16700Schasinglulu * + ThreadId 119*91f16700Schasinglulu * --------------------------------------------------------------------- 120*91f16700Schasinglulu */ 121*91f16700Schasinglulufunc plat_arm_calc_core_pos 122*91f16700Schasinglulu mov r3, r0 123*91f16700Schasinglulu 124*91f16700Schasinglulu /* 125*91f16700Schasinglulu * Check for MT bit in MPIDR. If not set, shift MPIDR to left to make it 126*91f16700Schasinglulu * look as if in a multi-threaded implementation 127*91f16700Schasinglulu */ 128*91f16700Schasinglulu tst r0, #MPIDR_MT_MASK 129*91f16700Schasinglulu lsleq r3, r0, #MPIDR_AFFINITY_BITS 130*91f16700Schasinglulu 131*91f16700Schasinglulu /* Extract individual affinity fields from MPIDR */ 132*91f16700Schasinglulu ubfx r0, r3, #MPIDR_AFF0_SHIFT, #MPIDR_AFFINITY_BITS 133*91f16700Schasinglulu ubfx r1, r3, #MPIDR_AFF1_SHIFT, #MPIDR_AFFINITY_BITS 134*91f16700Schasinglulu ubfx r2, r3, #MPIDR_AFF2_SHIFT, #MPIDR_AFFINITY_BITS 135*91f16700Schasinglulu 136*91f16700Schasinglulu /* Compute linear position */ 137*91f16700Schasinglulu mov r3, #FVP_MAX_CPUS_PER_CLUSTER 138*91f16700Schasinglulu mla r1, r2, r3, r1 139*91f16700Schasinglulu mov r3, #FVP_MAX_PE_PER_CPU 140*91f16700Schasinglulu mla r0, r1, r3, r0 141*91f16700Schasinglulu 142*91f16700Schasinglulu bx lr 143*91f16700Schasingluluendfunc plat_arm_calc_core_pos 144