xref: /rk3399_ARM-atf/include/plat/common/plat_hold_pen.S (revision ecab5d9e3f81b7bf093002b8614359adfc8d880d)
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