1*e45ca16eSNicolas Pitre/* 2*e45ca16eSNicolas Pitre * Copyright (c) 2026, BayLibre SAS 3*e45ca16eSNicolas Pitre * 4*e45ca16eSNicolas Pitre * SPDX-License-Identifier: BSD-3-Clause 5*e45ca16eSNicolas Pitre */ 6*e45ca16eSNicolas Pitre 7*e45ca16eSNicolas Pitre#ifndef PLAT_HOLD_PEN_S 8*e45ca16eSNicolas Pitre#define PLAT_HOLD_PEN_S 9*e45ca16eSNicolas Pitre 10*e45ca16eSNicolas Pitre#include <plat/common/plat_hold_pen.h> 11*e45ca16eSNicolas Pitre 12*e45ca16eSNicolas Pitre/* 13*e45ca16eSNicolas Pitre * plat_hold_pen_wait_and_jump base, idx, tmp 14*e45ca16eSNicolas Pitre * 15*e45ca16eSNicolas Pitre * Compute the hold pen slot address from a base address and core 16*e45ca16eSNicolas Pitre * index, then poll until both magic tags are valid and the entry 17*e45ca16eSNicolas Pitre * field contains a real entrypoint (not HOLD_STATE_WAIT), then 18*e45ca16eSNicolas Pitre * branch to it. This macro does not return. 19*e45ca16eSNicolas Pitre * 20*e45ca16eSNicolas Pitre * Before branching, writes HOLD_STATE_WAIT back to prevent stale 21*e45ca16eSNicolas Pitre * reuse on warm boot. The dcache is not enabled when this macro is 22*e45ca16eSNicolas Pitre * used so no flush is needed. 23*e45ca16eSNicolas Pitre * 24*e45ca16eSNicolas Pitre * base: register holding the hold pen base address (clobbered) 25*e45ca16eSNicolas Pitre * idx: register holding the core index (clobbered) 26*e45ca16eSNicolas Pitre * tmp: scratch register 27*e45ca16eSNicolas Pitre */ 28*e45ca16eSNicolas Pitre 29*e45ca16eSNicolas Pitre#ifdef __aarch64__ 30*e45ca16eSNicolas Pitre .macro plat_hold_pen_wait_and_jump base, idx, tmp 31*e45ca16eSNicolas Pitre mov \tmp, #HOLD_SLOT_SIZE 32*e45ca16eSNicolas Pitre madd \base, \idx, \tmp, \base 33*e45ca16eSNicolas Pitrepoll_\@: 34*e45ca16eSNicolas Pitre ldr \idx, [\base, #HOLD_SLOT_MAGIC1] 35*e45ca16eSNicolas Pitre mov_imm \tmp, HOLD_MAGIC1 36*e45ca16eSNicolas Pitre cmp \idx, \tmp 37*e45ca16eSNicolas Pitre b.ne wait_\@ 38*e45ca16eSNicolas Pitre ldr \idx, [\base, #HOLD_SLOT_MAGIC2] 39*e45ca16eSNicolas Pitre mov_imm \tmp, HOLD_MAGIC2 40*e45ca16eSNicolas Pitre cmp \idx, \tmp 41*e45ca16eSNicolas Pitre b.ne wait_\@ 42*e45ca16eSNicolas Pitre ldr \idx, [\base, #HOLD_SLOT_ENTRY] 43*e45ca16eSNicolas Pitre cmp \idx, #HOLD_STATE_WAIT 44*e45ca16eSNicolas Pitre b.eq wait_\@ 45*e45ca16eSNicolas Pitre /* Prevent reuse of stale entry on warm boot */ 46*e45ca16eSNicolas Pitre mov \tmp, #HOLD_STATE_WAIT 47*e45ca16eSNicolas Pitre str \tmp, [\base, #HOLD_SLOT_ENTRY] 48*e45ca16eSNicolas Pitre br \idx 49*e45ca16eSNicolas Pitrewait_\@: 50*e45ca16eSNicolas Pitre wfe 51*e45ca16eSNicolas Pitre b poll_\@ 52*e45ca16eSNicolas Pitre .endm 53*e45ca16eSNicolas Pitre#else /* __aarch64__ */ 54*e45ca16eSNicolas Pitre .macro plat_hold_pen_wait_and_jump base, idx, tmp 55*e45ca16eSNicolas Pitre mov \tmp, #HOLD_SLOT_SIZE 56*e45ca16eSNicolas Pitre mla \base, \idx, \tmp, \base 57*e45ca16eSNicolas Pitrepoll_\@: 58*e45ca16eSNicolas Pitre ldr \idx, [\base, #HOLD_SLOT_MAGIC1] 59*e45ca16eSNicolas Pitre mov_imm \tmp, HOLD_MAGIC1 60*e45ca16eSNicolas Pitre cmp \idx, \tmp 61*e45ca16eSNicolas Pitre bne wait_\@ 62*e45ca16eSNicolas Pitre ldr \idx, [\base, #HOLD_SLOT_MAGIC2] 63*e45ca16eSNicolas Pitre mov_imm \tmp, HOLD_MAGIC2 64*e45ca16eSNicolas Pitre cmp \idx, \tmp 65*e45ca16eSNicolas Pitre bne wait_\@ 66*e45ca16eSNicolas Pitre ldr \idx, [\base, #HOLD_SLOT_ENTRY] 67*e45ca16eSNicolas Pitre cmp \idx, #HOLD_STATE_WAIT 68*e45ca16eSNicolas Pitre beq wait_\@ 69*e45ca16eSNicolas Pitre /* Prevent reuse of stale entry on warm boot */ 70*e45ca16eSNicolas Pitre mov \tmp, #HOLD_STATE_WAIT 71*e45ca16eSNicolas Pitre str \tmp, [\base, #HOLD_SLOT_ENTRY] 72*e45ca16eSNicolas Pitre bx \idx 73*e45ca16eSNicolas Pitrewait_\@: 74*e45ca16eSNicolas Pitre wfe 75*e45ca16eSNicolas Pitre b poll_\@ 76*e45ca16eSNicolas Pitre .endm 77*e45ca16eSNicolas Pitre#endif /* __aarch64__ */ 78*e45ca16eSNicolas Pitre 79*e45ca16eSNicolas Pitre#endif /* PLAT_HOLD_PEN_S */ 80