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