1/* 2 * Copyright (c) 2021, 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 <drivers/arm/gicv2.h> 11#include <drivers/arm/gicv3.h> 12 13#include <platform_def.h> 14 15 16 .globl plat_secondary_cold_boot_setup 17 .globl plat_get_my_entrypoint 18 .globl plat_is_my_cpu_primary 19 20 /* ----------------------------------------------------- 21 * void plat_secondary_cold_boot_setup (void); 22 * 23 * This function performs any platform specific actions 24 * needed for a secondary cpu after a cold reset e.g 25 * mark the cpu's presence, mechanism to place it in a 26 * holding pen etc. 27 * TODO: Should we read the PSYS register to make sure 28 * that the request has gone through. 29 * ----------------------------------------------------- 30 */ 31func plat_secondary_cold_boot_setup 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 53endfunc plat_secondary_cold_boot_setup 54 55 /* --------------------------------------------------------------------- 56 * uintptr_t plat_get_my_entrypoint (void); 57 * 58 * Main job of this routine is to distinguish between a cold and warm 59 * boot. On FVP_R, this information can be queried from the power 60 * controller. The Power Control SYS Status Register (PSYSR) indicates 61 * the wake-up reason for the CPU. 62 * 63 * For a cold boot, return 0. 64 * For a warm boot, read the mailbox and return the address it contains. 65 * 66 * TODO: PSYSR is a common register and should be 67 * accessed using locks. Since it is not possible 68 * to use locks immediately after a cold reset 69 * we are relying on the fact that after a cold 70 * reset all cpus will read the same WK field 71 * --------------------------------------------------------------------- 72 */ 73func plat_get_my_entrypoint 74 /* --------------------------------------------------------------------- 75 * When bit PSYSR.WK indicates either "Wake by PPONR" or "Wake by GIC 76 * WakeRequest signal" then it is a warm boot. 77 * --------------------------------------------------------------------- 78 */ 79 mrs x2, mpidr_el1 80 mov_imm x1, PWRC_BASE 81 str w2, [x1, #PSYSR_OFF] 82 ldr w2, [x1, #PSYSR_OFF] 83 ubfx w2, w2, #PSYSR_WK_SHIFT, #PSYSR_WK_WIDTH 84 cmp w2, #WKUP_PPONR 85 beq warm_reset 86 cmp w2, #WKUP_GICREQ 87 beq warm_reset 88 89 /* Cold reset */ 90 mov x0, #0 91 ret 92 93warm_reset: 94 /* --------------------------------------------------------------------- 95 * A mailbox is maintained in the trusted SRAM. It is flushed out of the 96 * caches after every update using normal memory so it is safe to read 97 * it here with SO attributes. 98 * --------------------------------------------------------------------- 99 */ 100 mov_imm x0, PLAT_ARM_TRUSTED_MAILBOX_BASE 101 ldr x0, [x0] 102 cbz x0, _panic_handler 103 ret 104 105 /* --------------------------------------------------------------------- 106 * The power controller indicates this is a warm reset but the mailbox 107 * is empty. This should never happen! 108 * --------------------------------------------------------------------- 109 */ 110_panic_handler: 111 no_ret plat_panic_handler 112endfunc plat_get_my_entrypoint 113 114 /* ----------------------------------------------------- 115 * unsigned int plat_is_my_cpu_primary (void); 116 * 117 * Find out whether the current cpu is the primary 118 * cpu. 119 * ----------------------------------------------------- 120 */ 121func plat_is_my_cpu_primary 122 mrs x0, mpidr_el1 123 mov_imm x1, MPIDR_AFFINITY_MASK 124 and x0, x0, x1 125 cmp x0, #FVP_R_PRIMARY_CPU 126 cset w0, eq 127 ret 128endfunc plat_is_my_cpu_primary 129