xref: /rk3399_ARM-atf/lib/extensions/amu/aarch64/amu.c (revision 81e2ff1f364fdf18e086f690eb3715bc89307592)
1380559c1SDimitris Papastamos /*
2873d4241Sjohpow01  * Copyright (c) 2017-2021, ARM Limited and Contributors. All rights reserved.
3380559c1SDimitris Papastamos  *
4380559c1SDimitris Papastamos  * SPDX-License-Identifier: BSD-3-Clause
5380559c1SDimitris Papastamos  */
6380559c1SDimitris Papastamos 
709d40e0eSAntonio Nino Diaz #include <assert.h>
833b9be6dSChris Kay #include <cdefs.h>
909d40e0eSAntonio Nino Diaz #include <stdbool.h>
1009d40e0eSAntonio Nino Diaz 
11380559c1SDimitris Papastamos #include <arch.h>
12873d4241Sjohpow01 #include <arch_features.h>
13380559c1SDimitris Papastamos #include <arch_helpers.h>
14f3ccf036SAlexei Fedorov 
1509d40e0eSAntonio Nino Diaz #include <lib/el3_runtime/pubsub_events.h>
1609d40e0eSAntonio Nino Diaz #include <lib/extensions/amu.h>
1709d40e0eSAntonio Nino Diaz #include <lib/extensions/amu_private.h>
18f3ccf036SAlexei Fedorov 
1909d40e0eSAntonio Nino Diaz #include <plat/common/platform.h>
20380559c1SDimitris Papastamos 
21b6eb3932SDimitris Papastamos static struct amu_ctx amu_ctxs[PLATFORM_CORE_COUNT];
22b6eb3932SDimitris Papastamos 
2333b9be6dSChris Kay static inline __unused uint64_t read_id_aa64pfr0_el1_amu(void)
24380559c1SDimitris Papastamos {
2533b9be6dSChris Kay 	return (read_id_aa64pfr0_el1() >> ID_AA64PFR0_AMU_SHIFT) &
26873d4241Sjohpow01 		ID_AA64PFR0_AMU_MASK;
270767d50eSDimitris Papastamos }
280767d50eSDimitris Papastamos 
2933b9be6dSChris Kay static inline __unused uint64_t read_hcr_el2_amvoffen(void)
3033b9be6dSChris Kay {
3133b9be6dSChris Kay 	return (read_hcr_el2() & HCR_AMVOFFEN_BIT) >>
3233b9be6dSChris Kay 		HCR_AMVOFFEN_SHIFT;
3333b9be6dSChris Kay }
3433b9be6dSChris Kay 
3533b9be6dSChris Kay static inline __unused void write_cptr_el2_tam(uint64_t value)
3633b9be6dSChris Kay {
3733b9be6dSChris Kay 	write_cptr_el2((read_cptr_el2() & ~CPTR_EL2_TAM_BIT) |
3833b9be6dSChris Kay 		((value << CPTR_EL2_TAM_SHIFT) & CPTR_EL2_TAM_BIT));
3933b9be6dSChris Kay }
4033b9be6dSChris Kay 
4133b9be6dSChris Kay static inline __unused void write_cptr_el3_tam(cpu_context_t *ctx, uint64_t tam)
4233b9be6dSChris Kay {
4333b9be6dSChris Kay 	uint64_t value = read_ctx_reg(get_el3state_ctx(ctx), CTX_CPTR_EL3);
4433b9be6dSChris Kay 
4533b9be6dSChris Kay 	value &= ~TAM_BIT;
4633b9be6dSChris Kay 	value |= (tam << TAM_SHIFT) & TAM_BIT;
4733b9be6dSChris Kay 
4833b9be6dSChris Kay 	write_ctx_reg(get_el3state_ctx(ctx), CTX_CPTR_EL3, value);
4933b9be6dSChris Kay }
5033b9be6dSChris Kay 
5133b9be6dSChris Kay static inline __unused void write_hcr_el2_amvoffen(uint64_t value)
5233b9be6dSChris Kay {
5333b9be6dSChris Kay 	write_hcr_el2((read_hcr_el2() & ~HCR_AMVOFFEN_BIT) |
5433b9be6dSChris Kay 		((value << HCR_AMVOFFEN_SHIFT) & HCR_AMVOFFEN_BIT));
5533b9be6dSChris Kay }
5633b9be6dSChris Kay 
5733b9be6dSChris Kay static inline __unused void write_amcr_el0_cg1rz(uint64_t value)
5833b9be6dSChris Kay {
5933b9be6dSChris Kay 	write_amcr_el0((read_amcr_el0() & ~AMCR_CG1RZ_BIT) |
6033b9be6dSChris Kay 		((value << AMCR_CG1RZ_SHIFT) & AMCR_CG1RZ_BIT));
6133b9be6dSChris Kay }
6233b9be6dSChris Kay 
6333b9be6dSChris Kay static inline __unused uint64_t read_amcfgr_el0_ncg(void)
6433b9be6dSChris Kay {
6533b9be6dSChris Kay 	return (read_amcfgr_el0() >> AMCFGR_EL0_NCG_SHIFT) &
6633b9be6dSChris Kay 		AMCFGR_EL0_NCG_MASK;
6733b9be6dSChris Kay }
6833b9be6dSChris Kay 
69*81e2ff1fSChris Kay static inline uint64_t read_amcgcr_el0_cg0nc(void)
70*81e2ff1fSChris Kay {
71*81e2ff1fSChris Kay 	return (read_amcgcr_el0() >> AMCGCR_EL0_CG0NC_SHIFT) &
72*81e2ff1fSChris Kay 		AMCGCR_EL0_CG0NC_MASK;
73*81e2ff1fSChris Kay }
74*81e2ff1fSChris Kay 
7533b9be6dSChris Kay static inline __unused uint64_t read_amcg1idr_el0_voff(void)
7633b9be6dSChris Kay {
7733b9be6dSChris Kay 	return (read_amcg1idr_el0() >> AMCG1IDR_VOFF_SHIFT) &
7833b9be6dSChris Kay 		AMCG1IDR_VOFF_MASK;
7933b9be6dSChris Kay }
8033b9be6dSChris Kay 
8133b9be6dSChris Kay static inline __unused uint64_t read_amcgcr_el0_cg1nc(void)
8233b9be6dSChris Kay {
8333b9be6dSChris Kay 	return (read_amcgcr_el0() >> AMCGCR_EL0_CG1NC_SHIFT) &
8433b9be6dSChris Kay 		AMCGCR_EL0_CG1NC_MASK;
8533b9be6dSChris Kay }
8633b9be6dSChris Kay 
8733b9be6dSChris Kay static inline __unused uint64_t read_amcntenset0_el0_px(void)
8833b9be6dSChris Kay {
8933b9be6dSChris Kay 	return (read_amcntenset0_el0() >> AMCNTENSET0_EL0_Pn_SHIFT) &
9033b9be6dSChris Kay 		AMCNTENSET0_EL0_Pn_MASK;
9133b9be6dSChris Kay }
9233b9be6dSChris Kay 
9333b9be6dSChris Kay static inline __unused uint64_t read_amcntenset1_el0_px(void)
9433b9be6dSChris Kay {
9533b9be6dSChris Kay 	return (read_amcntenset1_el0() >> AMCNTENSET1_EL0_Pn_SHIFT) &
9633b9be6dSChris Kay 		AMCNTENSET1_EL0_Pn_MASK;
9733b9be6dSChris Kay }
9833b9be6dSChris Kay 
9933b9be6dSChris Kay static inline __unused void write_amcntenset0_el0_px(uint64_t px)
10033b9be6dSChris Kay {
10133b9be6dSChris Kay 	uint64_t value = read_amcntenset0_el0();
10233b9be6dSChris Kay 
10333b9be6dSChris Kay 	value &= ~AMCNTENSET0_EL0_Pn_MASK;
10433b9be6dSChris Kay 	value |= (px << AMCNTENSET0_EL0_Pn_SHIFT) & AMCNTENSET0_EL0_Pn_MASK;
10533b9be6dSChris Kay 
10633b9be6dSChris Kay 	write_amcntenset0_el0(value);
10733b9be6dSChris Kay }
10833b9be6dSChris Kay 
10933b9be6dSChris Kay static inline __unused void write_amcntenset1_el0_px(uint64_t px)
11033b9be6dSChris Kay {
11133b9be6dSChris Kay 	uint64_t value = read_amcntenset1_el0();
11233b9be6dSChris Kay 
11333b9be6dSChris Kay 	value &= ~AMCNTENSET1_EL0_Pn_MASK;
11433b9be6dSChris Kay 	value |= (px << AMCNTENSET1_EL0_Pn_SHIFT) & AMCNTENSET1_EL0_Pn_MASK;
11533b9be6dSChris Kay 
11633b9be6dSChris Kay 	write_amcntenset1_el0(value);
11733b9be6dSChris Kay }
11833b9be6dSChris Kay 
11933b9be6dSChris Kay static inline __unused void write_amcntenclr0_el0_px(uint64_t px)
12033b9be6dSChris Kay {
12133b9be6dSChris Kay 	uint64_t value = read_amcntenclr0_el0();
12233b9be6dSChris Kay 
12333b9be6dSChris Kay 	value &= ~AMCNTENCLR0_EL0_Pn_MASK;
12433b9be6dSChris Kay 	value |= (px << AMCNTENCLR0_EL0_Pn_SHIFT) & AMCNTENCLR0_EL0_Pn_MASK;
12533b9be6dSChris Kay 
12633b9be6dSChris Kay 	write_amcntenclr0_el0(value);
12733b9be6dSChris Kay }
12833b9be6dSChris Kay 
12933b9be6dSChris Kay static inline __unused void write_amcntenclr1_el0_px(uint64_t px)
13033b9be6dSChris Kay {
13133b9be6dSChris Kay 	uint64_t value = read_amcntenclr1_el0();
13233b9be6dSChris Kay 
13333b9be6dSChris Kay 	value &= ~AMCNTENCLR1_EL0_Pn_MASK;
13433b9be6dSChris Kay 	value |= (px << AMCNTENCLR1_EL0_Pn_SHIFT) & AMCNTENCLR1_EL0_Pn_MASK;
13533b9be6dSChris Kay 
13633b9be6dSChris Kay 	write_amcntenclr1_el0(value);
13733b9be6dSChris Kay }
13833b9be6dSChris Kay 
13933b9be6dSChris Kay static bool amu_supported(void)
14033b9be6dSChris Kay {
14133b9be6dSChris Kay 	return read_id_aa64pfr0_el1_amu() >= ID_AA64PFR0_AMU_V1;
14233b9be6dSChris Kay }
14333b9be6dSChris Kay 
14433b9be6dSChris Kay static bool amu_v1p1_supported(void)
14533b9be6dSChris Kay {
14633b9be6dSChris Kay 	return read_id_aa64pfr0_el1_amu() >= ID_AA64PFR0_AMU_V1P1;
14733b9be6dSChris Kay }
14833b9be6dSChris Kay 
14933b9be6dSChris Kay #if ENABLE_AMU_AUXILIARY_COUNTERS
150b4b726eaSChris Kay static bool amu_group1_supported(void)
151f3ccf036SAlexei Fedorov {
15233b9be6dSChris Kay 	return read_amcfgr_el0_ncg() > 0U;
153f3ccf036SAlexei Fedorov }
154f3ccf036SAlexei Fedorov #endif
155f3ccf036SAlexei Fedorov 
1560767d50eSDimitris Papastamos /*
1570767d50eSDimitris Papastamos  * Enable counters. This function is meant to be invoked
1580767d50eSDimitris Papastamos  * by the context management library before exiting from EL3.
1590767d50eSDimitris Papastamos  */
16068ac5ed0SArunachalam Ganapathy void amu_enable(bool el2_unused, cpu_context_t *ctx)
1610767d50eSDimitris Papastamos {
16233b9be6dSChris Kay 	if (!amu_supported()) {
1630767d50eSDimitris Papastamos 		return;
164f3ccf036SAlexei Fedorov 	}
165f3ccf036SAlexei Fedorov 
1661fd685a7SChris Kay #if ENABLE_AMU_AUXILIARY_COUNTERS
1671fd685a7SChris Kay 	if (AMU_GROUP1_NR_COUNTERS > 0U) {
168f3ccf036SAlexei Fedorov 		/* Check and set presence of group 1 counters */
169f3ccf036SAlexei Fedorov 		if (!amu_group1_supported()) {
170f3ccf036SAlexei Fedorov 			ERROR("AMU Counter Group 1 is not implemented\n");
171f3ccf036SAlexei Fedorov 			panic();
172f3ccf036SAlexei Fedorov 		}
173f3ccf036SAlexei Fedorov 
174f3ccf036SAlexei Fedorov 		/* Check number of group 1 counters */
17533b9be6dSChris Kay 		uint64_t cnt_num = read_amcgcr_el0_cg1nc();
1761fd685a7SChris Kay 
177f3ccf036SAlexei Fedorov 		VERBOSE("%s%llu. %s%u\n",
178f3ccf036SAlexei Fedorov 			"Number of AMU Group 1 Counters ", cnt_num,
179f3ccf036SAlexei Fedorov 			"Requested number ", AMU_GROUP1_NR_COUNTERS);
180f3ccf036SAlexei Fedorov 
181f3ccf036SAlexei Fedorov 		if (cnt_num < AMU_GROUP1_NR_COUNTERS) {
182f3ccf036SAlexei Fedorov 			ERROR("%s%llu is less than %s%u\n",
183f3ccf036SAlexei Fedorov 			"Number of AMU Group 1 Counters ", cnt_num,
184f3ccf036SAlexei Fedorov 			"Requested number ", AMU_GROUP1_NR_COUNTERS);
185f3ccf036SAlexei Fedorov 			panic();
186f3ccf036SAlexei Fedorov 		}
1871fd685a7SChris Kay 	}
188f3ccf036SAlexei Fedorov #endif
1890767d50eSDimitris Papastamos 
190380559c1SDimitris Papastamos 	if (el2_unused) {
191380559c1SDimitris Papastamos 		/*
192380559c1SDimitris Papastamos 		 * CPTR_EL2.TAM: Set to zero so any accesses to
193380559c1SDimitris Papastamos 		 * the Activity Monitor registers do not trap to EL2.
194380559c1SDimitris Papastamos 		 */
19533b9be6dSChris Kay 		write_cptr_el2_tam(0U);
196380559c1SDimitris Papastamos 	}
197380559c1SDimitris Papastamos 
198380559c1SDimitris Papastamos 	/*
19968ac5ed0SArunachalam Ganapathy 	 * Retrieve and update the CPTR_EL3 value from the context mentioned
20068ac5ed0SArunachalam Ganapathy 	 * in 'ctx'. Set CPTR_EL3.TAM to zero so that any accesses to
201380559c1SDimitris Papastamos 	 * the Activity Monitor registers do not trap to EL3.
202380559c1SDimitris Papastamos 	 */
20333b9be6dSChris Kay 	write_cptr_el3_tam(ctx, 0U);
204380559c1SDimitris Papastamos 
205380559c1SDimitris Papastamos 	/* Enable group 0 counters */
206*81e2ff1fSChris Kay 	write_amcntenset0_el0_px((UINT64_C(1) << read_amcgcr_el0_cg0nc()) - 1U);
207f3ccf036SAlexei Fedorov 
2081fd685a7SChris Kay #if ENABLE_AMU_AUXILIARY_COUNTERS
2091fd685a7SChris Kay 	if (AMU_GROUP1_NR_COUNTERS > 0U) {
21059902b7cSDimitris Papastamos 		/* Enable group 1 counters */
21133b9be6dSChris Kay 		write_amcntenset1_el0_px(AMU_GROUP1_COUNTERS_MASK);
2121fd685a7SChris Kay 	}
213f3ccf036SAlexei Fedorov #endif
214873d4241Sjohpow01 
215873d4241Sjohpow01 	/* Initialize FEAT_AMUv1p1 features if present. */
21633b9be6dSChris Kay 	if (!amu_v1p1_supported()) {
217873d4241Sjohpow01 		return;
218873d4241Sjohpow01 	}
219873d4241Sjohpow01 
220873d4241Sjohpow01 	if (el2_unused) {
221873d4241Sjohpow01 		/* Make sure virtual offsets are disabled if EL2 not used. */
22233b9be6dSChris Kay 		write_hcr_el2_amvoffen(0U);
223873d4241Sjohpow01 	}
224873d4241Sjohpow01 
225873d4241Sjohpow01 #if AMU_RESTRICT_COUNTERS
226873d4241Sjohpow01 	/*
227873d4241Sjohpow01 	 * FEAT_AMUv1p1 adds a register field to restrict access to group 1
228873d4241Sjohpow01 	 * counters at all but the highest implemented EL.  This is controlled
229873d4241Sjohpow01 	 * with the AMU_RESTRICT_COUNTERS compile time flag, when set, system
230873d4241Sjohpow01 	 * register reads at lower ELs return zero.  Reads from the memory
231873d4241Sjohpow01 	 * mapped view are unaffected.
232873d4241Sjohpow01 	 */
233873d4241Sjohpow01 	VERBOSE("AMU group 1 counter access restricted.\n");
23433b9be6dSChris Kay 	write_amcr_el0_cg1rz(1U);
235873d4241Sjohpow01 #else
23633b9be6dSChris Kay 	write_amcr_el0_cg1rz(0U);
237873d4241Sjohpow01 #endif
238380559c1SDimitris Papastamos }
2390767d50eSDimitris Papastamos 
2400767d50eSDimitris Papastamos /* Read the group 0 counter identified by the given `idx`. */
241b4b726eaSChris Kay static uint64_t amu_group0_cnt_read(unsigned int idx)
2420767d50eSDimitris Papastamos {
24333b9be6dSChris Kay 	assert(amu_supported());
244*81e2ff1fSChris Kay 	assert(idx < read_amcgcr_el0_cg0nc());
2450767d50eSDimitris Papastamos 
2460767d50eSDimitris Papastamos 	return amu_group0_cnt_read_internal(idx);
2470767d50eSDimitris Papastamos }
2480767d50eSDimitris Papastamos 
249f3ccf036SAlexei Fedorov /* Write the group 0 counter identified by the given `idx` with `val` */
250b4b726eaSChris Kay static void amu_group0_cnt_write(unsigned  int idx, uint64_t val)
2510767d50eSDimitris Papastamos {
25233b9be6dSChris Kay 	assert(amu_supported());
253*81e2ff1fSChris Kay 	assert(idx < read_amcgcr_el0_cg0nc());
2540767d50eSDimitris Papastamos 
2550767d50eSDimitris Papastamos 	amu_group0_cnt_write_internal(idx, val);
2560767d50eSDimitris Papastamos 	isb();
2570767d50eSDimitris Papastamos }
2580767d50eSDimitris Papastamos 
259873d4241Sjohpow01 /*
260873d4241Sjohpow01  * Read the group 0 offset register for a given index. Index must be 0, 2,
261873d4241Sjohpow01  * or 3, the register for 1 does not exist.
262873d4241Sjohpow01  *
263873d4241Sjohpow01  * Using this function requires FEAT_AMUv1p1 support.
264873d4241Sjohpow01  */
265b4b726eaSChris Kay static uint64_t amu_group0_voffset_read(unsigned int idx)
266873d4241Sjohpow01 {
26733b9be6dSChris Kay 	assert(amu_v1p1_supported());
268*81e2ff1fSChris Kay 	assert(idx < read_amcgcr_el0_cg0nc());
269873d4241Sjohpow01 	assert(idx != 1U);
270873d4241Sjohpow01 
271873d4241Sjohpow01 	return amu_group0_voffset_read_internal(idx);
272873d4241Sjohpow01 }
273873d4241Sjohpow01 
274873d4241Sjohpow01 /*
275873d4241Sjohpow01  * Write the group 0 offset register for a given index. Index must be 0, 2, or
276873d4241Sjohpow01  * 3, the register for 1 does not exist.
277873d4241Sjohpow01  *
278873d4241Sjohpow01  * Using this function requires FEAT_AMUv1p1 support.
279873d4241Sjohpow01  */
280b4b726eaSChris Kay static void amu_group0_voffset_write(unsigned int idx, uint64_t val)
281873d4241Sjohpow01 {
28233b9be6dSChris Kay 	assert(amu_v1p1_supported());
283*81e2ff1fSChris Kay 	assert(idx < read_amcgcr_el0_cg0nc());
284873d4241Sjohpow01 	assert(idx != 1U);
285873d4241Sjohpow01 
286873d4241Sjohpow01 	amu_group0_voffset_write_internal(idx, val);
287873d4241Sjohpow01 	isb();
288873d4241Sjohpow01 }
289873d4241Sjohpow01 
2901fd685a7SChris Kay #if ENABLE_AMU_AUXILIARY_COUNTERS
291f3ccf036SAlexei Fedorov /* Read the group 1 counter identified by the given `idx` */
292b4b726eaSChris Kay static uint64_t amu_group1_cnt_read(unsigned int idx)
2930767d50eSDimitris Papastamos {
29433b9be6dSChris Kay 	assert(amu_supported());
295f3ccf036SAlexei Fedorov 	assert(amu_group1_supported());
296f3ccf036SAlexei Fedorov 	assert(idx < AMU_GROUP1_NR_COUNTERS);
2970767d50eSDimitris Papastamos 
2980767d50eSDimitris Papastamos 	return amu_group1_cnt_read_internal(idx);
2990767d50eSDimitris Papastamos }
3000767d50eSDimitris Papastamos 
301f3ccf036SAlexei Fedorov /* Write the group 1 counter identified by the given `idx` with `val` */
302b4b726eaSChris Kay static void amu_group1_cnt_write(unsigned int idx, uint64_t val)
3030767d50eSDimitris Papastamos {
30433b9be6dSChris Kay 	assert(amu_supported());
305f3ccf036SAlexei Fedorov 	assert(amu_group1_supported());
306f3ccf036SAlexei Fedorov 	assert(idx < AMU_GROUP1_NR_COUNTERS);
3070767d50eSDimitris Papastamos 
3080767d50eSDimitris Papastamos 	amu_group1_cnt_write_internal(idx, val);
3090767d50eSDimitris Papastamos 	isb();
3100767d50eSDimitris Papastamos }
3110767d50eSDimitris Papastamos 
3120767d50eSDimitris Papastamos /*
313873d4241Sjohpow01  * Read the group 1 offset register for a given index.
314873d4241Sjohpow01  *
315873d4241Sjohpow01  * Using this function requires FEAT_AMUv1p1 support.
316873d4241Sjohpow01  */
317b4b726eaSChris Kay static uint64_t amu_group1_voffset_read(unsigned int idx)
318873d4241Sjohpow01 {
31933b9be6dSChris Kay 	assert(amu_v1p1_supported());
320873d4241Sjohpow01 	assert(amu_group1_supported());
321873d4241Sjohpow01 	assert(idx < AMU_GROUP1_NR_COUNTERS);
32233b9be6dSChris Kay 	assert((read_amcg1idr_el0_voff() & (UINT64_C(1) << idx)) != 0U);
323873d4241Sjohpow01 
324873d4241Sjohpow01 	return amu_group1_voffset_read_internal(idx);
325873d4241Sjohpow01 }
326873d4241Sjohpow01 
327873d4241Sjohpow01 /*
328873d4241Sjohpow01  * Write the group 1 offset register for a given index.
329873d4241Sjohpow01  *
330873d4241Sjohpow01  * Using this function requires FEAT_AMUv1p1 support.
331873d4241Sjohpow01  */
332b4b726eaSChris Kay static void amu_group1_voffset_write(unsigned int idx, uint64_t val)
333873d4241Sjohpow01 {
33433b9be6dSChris Kay 	assert(amu_v1p1_supported());
335873d4241Sjohpow01 	assert(amu_group1_supported());
336873d4241Sjohpow01 	assert(idx < AMU_GROUP1_NR_COUNTERS);
33733b9be6dSChris Kay 	assert((read_amcg1idr_el0_voff() & (UINT64_C(1) << idx)) != 0U);
338873d4241Sjohpow01 
339873d4241Sjohpow01 	amu_group1_voffset_write_internal(idx, val);
340873d4241Sjohpow01 	isb();
341873d4241Sjohpow01 }
3421fd685a7SChris Kay #endif
343b6eb3932SDimitris Papastamos 
344b6eb3932SDimitris Papastamos static void *amu_context_save(const void *arg)
345b6eb3932SDimitris Papastamos {
346b6eb3932SDimitris Papastamos 	struct amu_ctx *ctx = &amu_ctxs[plat_my_core_pos()];
347f3ccf036SAlexei Fedorov 	unsigned int i;
348b6eb3932SDimitris Papastamos 
34933b9be6dSChris Kay 	if (!amu_supported()) {
350b6eb3932SDimitris Papastamos 		return (void *)-1;
351f3ccf036SAlexei Fedorov 	}
352b6eb3932SDimitris Papastamos 
3531fd685a7SChris Kay #if ENABLE_AMU_AUXILIARY_COUNTERS
3541fd685a7SChris Kay 	if (AMU_GROUP1_NR_COUNTERS > 0U) {
355f3ccf036SAlexei Fedorov 		if (!amu_group1_supported()) {
356f3ccf036SAlexei Fedorov 			return (void *)-1;
357f3ccf036SAlexei Fedorov 		}
3581fd685a7SChris Kay 	}
359f3ccf036SAlexei Fedorov #endif
3601fd685a7SChris Kay 
361b6eb3932SDimitris Papastamos 	/* Assert that group 0/1 counter configuration is what we expect */
362*81e2ff1fSChris Kay 	assert(read_amcntenset0_el0_px() ==
363*81e2ff1fSChris Kay 		((UINT64_C(1) << read_amcgcr_el0_cg0nc()) - 1U));
364b6eb3932SDimitris Papastamos 
3651fd685a7SChris Kay #if ENABLE_AMU_AUXILIARY_COUNTERS
3661fd685a7SChris Kay 	if (AMU_GROUP1_NR_COUNTERS > 0U) {
36733b9be6dSChris Kay 		assert(read_amcntenset1_el0_px() == AMU_GROUP1_COUNTERS_MASK);
3681fd685a7SChris Kay 	}
369f3ccf036SAlexei Fedorov #endif
3701fd685a7SChris Kay 
371b6eb3932SDimitris Papastamos 	/*
372b6eb3932SDimitris Papastamos 	 * Disable group 0/1 counters to avoid other observers like SCP sampling
373b6eb3932SDimitris Papastamos 	 * counter values from the future via the memory mapped view.
374b6eb3932SDimitris Papastamos 	 */
375*81e2ff1fSChris Kay 	write_amcntenclr0_el0_px((UINT64_C(1) << read_amcgcr_el0_cg0nc()) - 1U);
376f3ccf036SAlexei Fedorov 
3771fd685a7SChris Kay #if ENABLE_AMU_AUXILIARY_COUNTERS
3781fd685a7SChris Kay 	if (AMU_GROUP1_NR_COUNTERS > 0U) {
37933b9be6dSChris Kay 		write_amcntenclr1_el0_px(AMU_GROUP1_COUNTERS_MASK);
3801fd685a7SChris Kay 	}
381f3ccf036SAlexei Fedorov #endif
3821fd685a7SChris Kay 
383b6eb3932SDimitris Papastamos 	isb();
384b6eb3932SDimitris Papastamos 
385f3ccf036SAlexei Fedorov 	/* Save all group 0 counters */
386*81e2ff1fSChris Kay 	for (i = 0U; i < read_amcgcr_el0_cg0nc(); i++) {
387b6eb3932SDimitris Papastamos 		ctx->group0_cnts[i] = amu_group0_cnt_read(i);
388f3ccf036SAlexei Fedorov 	}
389b6eb3932SDimitris Papastamos 
390873d4241Sjohpow01 	/* Save group 0 virtual offsets if supported and enabled. */
39133b9be6dSChris Kay 	if (amu_v1p1_supported() && (read_hcr_el2_amvoffen() != 0U)) {
392873d4241Sjohpow01 		/* Not using a loop because count is fixed and index 1 DNE. */
393873d4241Sjohpow01 		ctx->group0_voffsets[0U] = amu_group0_voffset_read(0U);
394873d4241Sjohpow01 		ctx->group0_voffsets[1U] = amu_group0_voffset_read(2U);
395873d4241Sjohpow01 		ctx->group0_voffsets[2U] = amu_group0_voffset_read(3U);
396873d4241Sjohpow01 	}
397873d4241Sjohpow01 
3981fd685a7SChris Kay #if ENABLE_AMU_AUXILIARY_COUNTERS
3991fd685a7SChris Kay 	if (AMU_GROUP1_NR_COUNTERS > 0U) {
400b6eb3932SDimitris Papastamos 		/* Save group 1 counters */
401f3ccf036SAlexei Fedorov 		for (i = 0U; i < AMU_GROUP1_NR_COUNTERS; i++) {
402873d4241Sjohpow01 			if ((AMU_GROUP1_COUNTERS_MASK & (1UL << i)) != 0U) {
403b6eb3932SDimitris Papastamos 				ctx->group1_cnts[i] = amu_group1_cnt_read(i);
404f3ccf036SAlexei Fedorov 			}
405f3ccf036SAlexei Fedorov 		}
406873d4241Sjohpow01 
407873d4241Sjohpow01 		/* Save group 1 virtual offsets if supported and enabled. */
40833b9be6dSChris Kay 		if (amu_v1p1_supported() && (read_hcr_el2_amvoffen() != 0U)) {
40933b9be6dSChris Kay 			uint64_t amcg1idr = read_amcg1idr_el0_voff() &
41033b9be6dSChris Kay 				AMU_GROUP1_COUNTERS_MASK;
411873d4241Sjohpow01 
412873d4241Sjohpow01 			for (i = 0U; i < AMU_GROUP1_NR_COUNTERS; i++) {
413873d4241Sjohpow01 				if (((amcg1idr >> i) & 1ULL) != 0ULL) {
414873d4241Sjohpow01 					ctx->group1_voffsets[i] =
415873d4241Sjohpow01 						amu_group1_voffset_read(i);
416873d4241Sjohpow01 				}
417873d4241Sjohpow01 			}
418873d4241Sjohpow01 		}
4191fd685a7SChris Kay 	}
420f3ccf036SAlexei Fedorov #endif
4211fd685a7SChris Kay 
42240daecc1SAntonio Nino Diaz 	return (void *)0;
423b6eb3932SDimitris Papastamos }
424b6eb3932SDimitris Papastamos 
425b6eb3932SDimitris Papastamos static void *amu_context_restore(const void *arg)
426b6eb3932SDimitris Papastamos {
427b6eb3932SDimitris Papastamos 	struct amu_ctx *ctx = &amu_ctxs[plat_my_core_pos()];
428f3ccf036SAlexei Fedorov 	unsigned int i;
429b6eb3932SDimitris Papastamos 
43033b9be6dSChris Kay 	if (!amu_supported()) {
431b6eb3932SDimitris Papastamos 		return (void *)-1;
432f3ccf036SAlexei Fedorov 	}
433b6eb3932SDimitris Papastamos 
4341fd685a7SChris Kay #if ENABLE_AMU_AUXILIARY_COUNTERS
4351fd685a7SChris Kay 	if (AMU_GROUP1_NR_COUNTERS > 0U) {
436f3ccf036SAlexei Fedorov 		if (!amu_group1_supported()) {
437f3ccf036SAlexei Fedorov 			return (void *)-1;
438f3ccf036SAlexei Fedorov 		}
4391fd685a7SChris Kay 	}
440f3ccf036SAlexei Fedorov #endif
4411fd685a7SChris Kay 
442b6eb3932SDimitris Papastamos 	/* Counters were disabled in `amu_context_save()` */
44333b9be6dSChris Kay 	assert(read_amcntenset0_el0_px() == 0U);
444b6eb3932SDimitris Papastamos 
4451fd685a7SChris Kay #if ENABLE_AMU_AUXILIARY_COUNTERS
4461fd685a7SChris Kay 	if (AMU_GROUP1_NR_COUNTERS > 0U) {
44733b9be6dSChris Kay 		assert(read_amcntenset1_el0_px() == 0U);
4481fd685a7SChris Kay 	}
449f3ccf036SAlexei Fedorov #endif
450b6eb3932SDimitris Papastamos 
451f3ccf036SAlexei Fedorov 	/* Restore all group 0 counters */
452*81e2ff1fSChris Kay 	for (i = 0U; i < read_amcgcr_el0_cg0nc(); i++) {
453b6eb3932SDimitris Papastamos 		amu_group0_cnt_write(i, ctx->group0_cnts[i]);
454f3ccf036SAlexei Fedorov 	}
455b6eb3932SDimitris Papastamos 
456873d4241Sjohpow01 	/* Restore group 0 virtual offsets if supported and enabled. */
45733b9be6dSChris Kay 	if (amu_v1p1_supported() && (read_hcr_el2_amvoffen() != 0U)) {
458873d4241Sjohpow01 		/* Not using a loop because count is fixed and index 1 DNE. */
459873d4241Sjohpow01 		amu_group0_voffset_write(0U, ctx->group0_voffsets[0U]);
460873d4241Sjohpow01 		amu_group0_voffset_write(2U, ctx->group0_voffsets[1U]);
461873d4241Sjohpow01 		amu_group0_voffset_write(3U, ctx->group0_voffsets[2U]);
462873d4241Sjohpow01 	}
463873d4241Sjohpow01 
464f3ccf036SAlexei Fedorov 	/* Restore group 0 counter configuration */
465*81e2ff1fSChris Kay 	write_amcntenset0_el0_px((UINT64_C(1) << read_amcgcr_el0_cg0nc()) - 1U);
466f3ccf036SAlexei Fedorov 
4671fd685a7SChris Kay #if ENABLE_AMU_AUXILIARY_COUNTERS
4681fd685a7SChris Kay 	if (AMU_GROUP1_NR_COUNTERS > 0U) {
469f3ccf036SAlexei Fedorov 		/* Restore group 1 counters */
470f3ccf036SAlexei Fedorov 		for (i = 0U; i < AMU_GROUP1_NR_COUNTERS; i++) {
471873d4241Sjohpow01 			if ((AMU_GROUP1_COUNTERS_MASK & (1UL << i)) != 0U) {
472f3ccf036SAlexei Fedorov 				amu_group1_cnt_write(i, ctx->group1_cnts[i]);
473f3ccf036SAlexei Fedorov 			}
474f3ccf036SAlexei Fedorov 		}
475f3ccf036SAlexei Fedorov 
476873d4241Sjohpow01 		/* Restore group 1 virtual offsets if supported and enabled. */
47733b9be6dSChris Kay 		if (amu_v1p1_supported() && (read_hcr_el2_amvoffen() != 0U)) {
47833b9be6dSChris Kay 			uint64_t amcg1idr = read_amcg1idr_el0_voff() &
47933b9be6dSChris Kay 				AMU_GROUP1_COUNTERS_MASK;
480873d4241Sjohpow01 
481873d4241Sjohpow01 			for (i = 0U; i < AMU_GROUP1_NR_COUNTERS; i++) {
482873d4241Sjohpow01 				if (((amcg1idr >> i) & 1ULL) != 0ULL) {
483873d4241Sjohpow01 					amu_group1_voffset_write(i,
484873d4241Sjohpow01 						ctx->group1_voffsets[i]);
485873d4241Sjohpow01 				}
486873d4241Sjohpow01 			}
487873d4241Sjohpow01 		}
488873d4241Sjohpow01 
489f3ccf036SAlexei Fedorov 		/* Restore group 1 counter configuration */
49033b9be6dSChris Kay 		write_amcntenset1_el0_px(AMU_GROUP1_COUNTERS_MASK);
4911fd685a7SChris Kay 	}
492f3ccf036SAlexei Fedorov #endif
493b6eb3932SDimitris Papastamos 
49440daecc1SAntonio Nino Diaz 	return (void *)0;
495b6eb3932SDimitris Papastamos }
496b6eb3932SDimitris Papastamos 
497b6eb3932SDimitris Papastamos SUBSCRIBE_TO_EVENT(psci_suspend_pwrdown_start, amu_context_save);
498b6eb3932SDimitris Papastamos SUBSCRIBE_TO_EVENT(psci_suspend_pwrdown_finish, amu_context_restore);
499