xref: /rk3399_ARM-atf/plat/common/plat_hold_pen.c (revision ecab5d9e3f81b7bf093002b8614359adfc8d880d)
1 /*
2  * Copyright (c) 2026, BayLibre SAS
3  *
4  * SPDX-License-Identifier: BSD-3-Clause
5  */
6 
7 #include <stdint.h>
8 
9 #include <arch_helpers.h>
10 #include <plat/common/plat_hold_pen.h>
11 
12 /*
13  * Initialise the hold pen by writing HOLD_STATE_WAIT and magic tags
14  * to every slot and flushing to main memory. The entry field is
15  * written first so it is safe before the magic tags make the slot
16  * visible to polling secondaries. This must be called once during
17  * boot (e.g. from plat_setup_psci_ops) before any secondary CPU
18  * is released.
19  */
plat_hold_pen_init(struct hold_slot * hold_pen,unsigned int core_count)20 void plat_hold_pen_init(struct hold_slot *hold_pen, unsigned int core_count)
21 {
22 	for (unsigned int i = 0U; i < core_count; i++) {
23 		hold_pen[i].entry  = HOLD_STATE_WAIT;
24 		/*
25 		 * Ensure the entry value is committed before the magic
26 		 * tags that make this slot visible to polling secondaries.
27 		 * Not strictly necessary since the subsequent flush
28 		 * pushes the whole cache line at once, but provides
29 		 * defence in depth against reordering.
30 		 */
31 		dmbish();
32 		hold_pen[i].magic1 = HOLD_MAGIC1;
33 		hold_pen[i].magic2 = HOLD_MAGIC2;
34 	}
35 
36 	flush_dcache_range((uintptr_t)hold_pen,
37 			   core_count * sizeof(struct hold_slot));
38 }
39 
40 /*
41  * Signal a secondary core to branch to the given entrypoint.
42  * Only the target slot is written and flushed.
43  */
plat_hold_pen_signal(struct hold_slot * hold_pen,unsigned int core_idx,uintptr_t entry_point)44 void plat_hold_pen_signal(struct hold_slot *hold_pen, unsigned int core_idx,
45 			  uintptr_t entry_point)
46 {
47 	hold_pen[core_idx].entry = entry_point;
48 
49 	flush_dcache_range((uintptr_t)&hold_pen[core_idx],
50 			   sizeof(struct hold_slot));
51 
52 	/* Wake secondaries out of their WFE polling loop. */
53 	sev();
54 }
55