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