xref: /rk3399_ARM-atf/lib/extensions/amu/aarch64/amu.c (revision 31d3cc2570dd61ac30efab030708ef32fcc987e5)
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 
6981e2ff1fSChris Kay static inline uint64_t read_amcgcr_el0_cg0nc(void)
7081e2ff1fSChris Kay {
7181e2ff1fSChris Kay 	return (read_amcgcr_el0() >> AMCGCR_EL0_CG0NC_SHIFT) &
7281e2ff1fSChris Kay 		AMCGCR_EL0_CG0NC_MASK;
7381e2ff1fSChris Kay }
7481e2ff1fSChris 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 
166380559c1SDimitris Papastamos 	if (el2_unused) {
167380559c1SDimitris Papastamos 		/*
168380559c1SDimitris Papastamos 		 * CPTR_EL2.TAM: Set to zero so any accesses to
169380559c1SDimitris Papastamos 		 * the Activity Monitor registers do not trap to EL2.
170380559c1SDimitris Papastamos 		 */
17133b9be6dSChris Kay 		write_cptr_el2_tam(0U);
172380559c1SDimitris Papastamos 	}
173380559c1SDimitris Papastamos 
174380559c1SDimitris Papastamos 	/*
17568ac5ed0SArunachalam Ganapathy 	 * Retrieve and update the CPTR_EL3 value from the context mentioned
17668ac5ed0SArunachalam Ganapathy 	 * in 'ctx'. Set CPTR_EL3.TAM to zero so that any accesses to
177380559c1SDimitris Papastamos 	 * the Activity Monitor registers do not trap to EL3.
178380559c1SDimitris Papastamos 	 */
17933b9be6dSChris Kay 	write_cptr_el3_tam(ctx, 0U);
180380559c1SDimitris Papastamos 
181380559c1SDimitris Papastamos 	/* Enable group 0 counters */
18281e2ff1fSChris Kay 	write_amcntenset0_el0_px((UINT64_C(1) << read_amcgcr_el0_cg0nc()) - 1U);
183f3ccf036SAlexei Fedorov 
1841fd685a7SChris Kay #if ENABLE_AMU_AUXILIARY_COUNTERS
185*31d3cc25SChris Kay 	if (amu_group1_supported()) {
18659902b7cSDimitris Papastamos 		/* Enable group 1 counters */
18733b9be6dSChris Kay 		write_amcntenset1_el0_px(AMU_GROUP1_COUNTERS_MASK);
1881fd685a7SChris Kay 	}
189f3ccf036SAlexei Fedorov #endif
190873d4241Sjohpow01 
191873d4241Sjohpow01 	/* Initialize FEAT_AMUv1p1 features if present. */
19233b9be6dSChris Kay 	if (!amu_v1p1_supported()) {
193873d4241Sjohpow01 		return;
194873d4241Sjohpow01 	}
195873d4241Sjohpow01 
196873d4241Sjohpow01 	if (el2_unused) {
197873d4241Sjohpow01 		/* Make sure virtual offsets are disabled if EL2 not used. */
19833b9be6dSChris Kay 		write_hcr_el2_amvoffen(0U);
199873d4241Sjohpow01 	}
200873d4241Sjohpow01 
201873d4241Sjohpow01 #if AMU_RESTRICT_COUNTERS
202873d4241Sjohpow01 	/*
203873d4241Sjohpow01 	 * FEAT_AMUv1p1 adds a register field to restrict access to group 1
204873d4241Sjohpow01 	 * counters at all but the highest implemented EL.  This is controlled
205873d4241Sjohpow01 	 * with the AMU_RESTRICT_COUNTERS compile time flag, when set, system
206873d4241Sjohpow01 	 * register reads at lower ELs return zero.  Reads from the memory
207873d4241Sjohpow01 	 * mapped view are unaffected.
208873d4241Sjohpow01 	 */
209873d4241Sjohpow01 	VERBOSE("AMU group 1 counter access restricted.\n");
21033b9be6dSChris Kay 	write_amcr_el0_cg1rz(1U);
211873d4241Sjohpow01 #else
21233b9be6dSChris Kay 	write_amcr_el0_cg1rz(0U);
213873d4241Sjohpow01 #endif
214380559c1SDimitris Papastamos }
2150767d50eSDimitris Papastamos 
2160767d50eSDimitris Papastamos /* Read the group 0 counter identified by the given `idx`. */
217b4b726eaSChris Kay static uint64_t amu_group0_cnt_read(unsigned int idx)
2180767d50eSDimitris Papastamos {
21933b9be6dSChris Kay 	assert(amu_supported());
22081e2ff1fSChris Kay 	assert(idx < read_amcgcr_el0_cg0nc());
2210767d50eSDimitris Papastamos 
2220767d50eSDimitris Papastamos 	return amu_group0_cnt_read_internal(idx);
2230767d50eSDimitris Papastamos }
2240767d50eSDimitris Papastamos 
225f3ccf036SAlexei Fedorov /* Write the group 0 counter identified by the given `idx` with `val` */
226b4b726eaSChris Kay static void amu_group0_cnt_write(unsigned  int idx, uint64_t val)
2270767d50eSDimitris Papastamos {
22833b9be6dSChris Kay 	assert(amu_supported());
22981e2ff1fSChris Kay 	assert(idx < read_amcgcr_el0_cg0nc());
2300767d50eSDimitris Papastamos 
2310767d50eSDimitris Papastamos 	amu_group0_cnt_write_internal(idx, val);
2320767d50eSDimitris Papastamos 	isb();
2330767d50eSDimitris Papastamos }
2340767d50eSDimitris Papastamos 
235873d4241Sjohpow01 /*
236873d4241Sjohpow01  * Read the group 0 offset register for a given index. Index must be 0, 2,
237873d4241Sjohpow01  * or 3, the register for 1 does not exist.
238873d4241Sjohpow01  *
239873d4241Sjohpow01  * Using this function requires FEAT_AMUv1p1 support.
240873d4241Sjohpow01  */
241b4b726eaSChris Kay static uint64_t amu_group0_voffset_read(unsigned int idx)
242873d4241Sjohpow01 {
24333b9be6dSChris Kay 	assert(amu_v1p1_supported());
24481e2ff1fSChris Kay 	assert(idx < read_amcgcr_el0_cg0nc());
245873d4241Sjohpow01 	assert(idx != 1U);
246873d4241Sjohpow01 
247873d4241Sjohpow01 	return amu_group0_voffset_read_internal(idx);
248873d4241Sjohpow01 }
249873d4241Sjohpow01 
250873d4241Sjohpow01 /*
251873d4241Sjohpow01  * Write the group 0 offset register for a given index. Index must be 0, 2, or
252873d4241Sjohpow01  * 3, the register for 1 does not exist.
253873d4241Sjohpow01  *
254873d4241Sjohpow01  * Using this function requires FEAT_AMUv1p1 support.
255873d4241Sjohpow01  */
256b4b726eaSChris Kay static void amu_group0_voffset_write(unsigned int idx, uint64_t val)
257873d4241Sjohpow01 {
25833b9be6dSChris Kay 	assert(amu_v1p1_supported());
25981e2ff1fSChris Kay 	assert(idx < read_amcgcr_el0_cg0nc());
260873d4241Sjohpow01 	assert(idx != 1U);
261873d4241Sjohpow01 
262873d4241Sjohpow01 	amu_group0_voffset_write_internal(idx, val);
263873d4241Sjohpow01 	isb();
264873d4241Sjohpow01 }
265873d4241Sjohpow01 
2661fd685a7SChris Kay #if ENABLE_AMU_AUXILIARY_COUNTERS
267f3ccf036SAlexei Fedorov /* Read the group 1 counter identified by the given `idx` */
268b4b726eaSChris Kay static uint64_t amu_group1_cnt_read(unsigned int idx)
2690767d50eSDimitris Papastamos {
27033b9be6dSChris Kay 	assert(amu_supported());
271f3ccf036SAlexei Fedorov 	assert(amu_group1_supported());
272*31d3cc25SChris Kay 	assert(idx < read_amcgcr_el0_cg1nc());
2730767d50eSDimitris Papastamos 
2740767d50eSDimitris Papastamos 	return amu_group1_cnt_read_internal(idx);
2750767d50eSDimitris Papastamos }
2760767d50eSDimitris Papastamos 
277f3ccf036SAlexei Fedorov /* Write the group 1 counter identified by the given `idx` with `val` */
278b4b726eaSChris Kay static void amu_group1_cnt_write(unsigned int idx, uint64_t val)
2790767d50eSDimitris Papastamos {
28033b9be6dSChris Kay 	assert(amu_supported());
281f3ccf036SAlexei Fedorov 	assert(amu_group1_supported());
282*31d3cc25SChris Kay 	assert(idx < read_amcgcr_el0_cg1nc());
2830767d50eSDimitris Papastamos 
2840767d50eSDimitris Papastamos 	amu_group1_cnt_write_internal(idx, val);
2850767d50eSDimitris Papastamos 	isb();
2860767d50eSDimitris Papastamos }
2870767d50eSDimitris Papastamos 
2880767d50eSDimitris Papastamos /*
289873d4241Sjohpow01  * Read the group 1 offset register for a given index.
290873d4241Sjohpow01  *
291873d4241Sjohpow01  * Using this function requires FEAT_AMUv1p1 support.
292873d4241Sjohpow01  */
293b4b726eaSChris Kay static uint64_t amu_group1_voffset_read(unsigned int idx)
294873d4241Sjohpow01 {
29533b9be6dSChris Kay 	assert(amu_v1p1_supported());
296873d4241Sjohpow01 	assert(amu_group1_supported());
297*31d3cc25SChris Kay 	assert(idx < read_amcgcr_el0_cg1nc());
29833b9be6dSChris Kay 	assert((read_amcg1idr_el0_voff() & (UINT64_C(1) << idx)) != 0U);
299873d4241Sjohpow01 
300873d4241Sjohpow01 	return amu_group1_voffset_read_internal(idx);
301873d4241Sjohpow01 }
302873d4241Sjohpow01 
303873d4241Sjohpow01 /*
304873d4241Sjohpow01  * Write the group 1 offset register for a given index.
305873d4241Sjohpow01  *
306873d4241Sjohpow01  * Using this function requires FEAT_AMUv1p1 support.
307873d4241Sjohpow01  */
308b4b726eaSChris Kay static void amu_group1_voffset_write(unsigned int idx, uint64_t val)
309873d4241Sjohpow01 {
31033b9be6dSChris Kay 	assert(amu_v1p1_supported());
311873d4241Sjohpow01 	assert(amu_group1_supported());
312*31d3cc25SChris Kay 	assert(idx < read_amcgcr_el0_cg1nc());
31333b9be6dSChris Kay 	assert((read_amcg1idr_el0_voff() & (UINT64_C(1) << idx)) != 0U);
314873d4241Sjohpow01 
315873d4241Sjohpow01 	amu_group1_voffset_write_internal(idx, val);
316873d4241Sjohpow01 	isb();
317873d4241Sjohpow01 }
3181fd685a7SChris Kay #endif
319b6eb3932SDimitris Papastamos 
320b6eb3932SDimitris Papastamos static void *amu_context_save(const void *arg)
321b6eb3932SDimitris Papastamos {
322b6eb3932SDimitris Papastamos 	struct amu_ctx *ctx = &amu_ctxs[plat_my_core_pos()];
323f3ccf036SAlexei Fedorov 	unsigned int i;
324b6eb3932SDimitris Papastamos 
32533b9be6dSChris Kay 	if (!amu_supported()) {
326b6eb3932SDimitris Papastamos 		return (void *)-1;
327f3ccf036SAlexei Fedorov 	}
328b6eb3932SDimitris Papastamos 
329b6eb3932SDimitris Papastamos 	/* Assert that group 0/1 counter configuration is what we expect */
33081e2ff1fSChris Kay 	assert(read_amcntenset0_el0_px() ==
33181e2ff1fSChris Kay 		((UINT64_C(1) << read_amcgcr_el0_cg0nc()) - 1U));
332b6eb3932SDimitris Papastamos 
3331fd685a7SChris Kay #if ENABLE_AMU_AUXILIARY_COUNTERS
334*31d3cc25SChris Kay 	if (amu_group1_supported()) {
33533b9be6dSChris Kay 		assert(read_amcntenset1_el0_px() == AMU_GROUP1_COUNTERS_MASK);
3361fd685a7SChris Kay 	}
337f3ccf036SAlexei Fedorov #endif
3381fd685a7SChris Kay 
339b6eb3932SDimitris Papastamos 	/*
340b6eb3932SDimitris Papastamos 	 * Disable group 0/1 counters to avoid other observers like SCP sampling
341b6eb3932SDimitris Papastamos 	 * counter values from the future via the memory mapped view.
342b6eb3932SDimitris Papastamos 	 */
34381e2ff1fSChris Kay 	write_amcntenclr0_el0_px((UINT64_C(1) << read_amcgcr_el0_cg0nc()) - 1U);
344f3ccf036SAlexei Fedorov 
3451fd685a7SChris Kay #if ENABLE_AMU_AUXILIARY_COUNTERS
346*31d3cc25SChris Kay 	if (amu_group1_supported()) {
34733b9be6dSChris Kay 		write_amcntenclr1_el0_px(AMU_GROUP1_COUNTERS_MASK);
3481fd685a7SChris Kay 	}
349f3ccf036SAlexei Fedorov #endif
3501fd685a7SChris Kay 
351b6eb3932SDimitris Papastamos 	isb();
352b6eb3932SDimitris Papastamos 
353f3ccf036SAlexei Fedorov 	/* Save all group 0 counters */
35481e2ff1fSChris Kay 	for (i = 0U; i < read_amcgcr_el0_cg0nc(); i++) {
355b6eb3932SDimitris Papastamos 		ctx->group0_cnts[i] = amu_group0_cnt_read(i);
356f3ccf036SAlexei Fedorov 	}
357b6eb3932SDimitris Papastamos 
358873d4241Sjohpow01 	/* Save group 0 virtual offsets if supported and enabled. */
35933b9be6dSChris Kay 	if (amu_v1p1_supported() && (read_hcr_el2_amvoffen() != 0U)) {
360873d4241Sjohpow01 		/* Not using a loop because count is fixed and index 1 DNE. */
361873d4241Sjohpow01 		ctx->group0_voffsets[0U] = amu_group0_voffset_read(0U);
362873d4241Sjohpow01 		ctx->group0_voffsets[1U] = amu_group0_voffset_read(2U);
363873d4241Sjohpow01 		ctx->group0_voffsets[2U] = amu_group0_voffset_read(3U);
364873d4241Sjohpow01 	}
365873d4241Sjohpow01 
3661fd685a7SChris Kay #if ENABLE_AMU_AUXILIARY_COUNTERS
367*31d3cc25SChris Kay 	if (amu_group1_supported()) {
368b6eb3932SDimitris Papastamos 		/* Save group 1 counters */
369*31d3cc25SChris Kay 		for (i = 0U; i < read_amcgcr_el0_cg1nc(); i++) {
370873d4241Sjohpow01 			if ((AMU_GROUP1_COUNTERS_MASK & (1UL << i)) != 0U) {
371b6eb3932SDimitris Papastamos 				ctx->group1_cnts[i] = amu_group1_cnt_read(i);
372f3ccf036SAlexei Fedorov 			}
373f3ccf036SAlexei Fedorov 		}
374873d4241Sjohpow01 
375873d4241Sjohpow01 		/* Save group 1 virtual offsets if supported and enabled. */
37633b9be6dSChris Kay 		if (amu_v1p1_supported() && (read_hcr_el2_amvoffen() != 0U)) {
37733b9be6dSChris Kay 			uint64_t amcg1idr = read_amcg1idr_el0_voff() &
37833b9be6dSChris Kay 				AMU_GROUP1_COUNTERS_MASK;
379873d4241Sjohpow01 
380*31d3cc25SChris Kay 			for (i = 0U; i < read_amcgcr_el0_cg1nc(); i++) {
381873d4241Sjohpow01 				if (((amcg1idr >> i) & 1ULL) != 0ULL) {
382873d4241Sjohpow01 					ctx->group1_voffsets[i] =
383873d4241Sjohpow01 						amu_group1_voffset_read(i);
384873d4241Sjohpow01 				}
385873d4241Sjohpow01 			}
386873d4241Sjohpow01 		}
3871fd685a7SChris Kay 	}
388f3ccf036SAlexei Fedorov #endif
3891fd685a7SChris Kay 
39040daecc1SAntonio Nino Diaz 	return (void *)0;
391b6eb3932SDimitris Papastamos }
392b6eb3932SDimitris Papastamos 
393b6eb3932SDimitris Papastamos static void *amu_context_restore(const void *arg)
394b6eb3932SDimitris Papastamos {
395b6eb3932SDimitris Papastamos 	struct amu_ctx *ctx = &amu_ctxs[plat_my_core_pos()];
396f3ccf036SAlexei Fedorov 	unsigned int i;
397b6eb3932SDimitris Papastamos 
39833b9be6dSChris Kay 	if (!amu_supported()) {
399b6eb3932SDimitris Papastamos 		return (void *)-1;
400f3ccf036SAlexei Fedorov 	}
401b6eb3932SDimitris Papastamos 
402b6eb3932SDimitris Papastamos 	/* Counters were disabled in `amu_context_save()` */
40333b9be6dSChris Kay 	assert(read_amcntenset0_el0_px() == 0U);
404b6eb3932SDimitris Papastamos 
4051fd685a7SChris Kay #if ENABLE_AMU_AUXILIARY_COUNTERS
406*31d3cc25SChris Kay 	if (amu_group1_supported()) {
40733b9be6dSChris Kay 		assert(read_amcntenset1_el0_px() == 0U);
4081fd685a7SChris Kay 	}
409f3ccf036SAlexei Fedorov #endif
410b6eb3932SDimitris Papastamos 
411f3ccf036SAlexei Fedorov 	/* Restore all group 0 counters */
41281e2ff1fSChris Kay 	for (i = 0U; i < read_amcgcr_el0_cg0nc(); i++) {
413b6eb3932SDimitris Papastamos 		amu_group0_cnt_write(i, ctx->group0_cnts[i]);
414f3ccf036SAlexei Fedorov 	}
415b6eb3932SDimitris Papastamos 
416873d4241Sjohpow01 	/* Restore group 0 virtual offsets if supported and enabled. */
41733b9be6dSChris Kay 	if (amu_v1p1_supported() && (read_hcr_el2_amvoffen() != 0U)) {
418873d4241Sjohpow01 		/* Not using a loop because count is fixed and index 1 DNE. */
419873d4241Sjohpow01 		amu_group0_voffset_write(0U, ctx->group0_voffsets[0U]);
420873d4241Sjohpow01 		amu_group0_voffset_write(2U, ctx->group0_voffsets[1U]);
421873d4241Sjohpow01 		amu_group0_voffset_write(3U, ctx->group0_voffsets[2U]);
422873d4241Sjohpow01 	}
423873d4241Sjohpow01 
424f3ccf036SAlexei Fedorov 	/* Restore group 0 counter configuration */
42581e2ff1fSChris Kay 	write_amcntenset0_el0_px((UINT64_C(1) << read_amcgcr_el0_cg0nc()) - 1U);
426f3ccf036SAlexei Fedorov 
4271fd685a7SChris Kay #if ENABLE_AMU_AUXILIARY_COUNTERS
428*31d3cc25SChris Kay 	if (amu_group1_supported()) {
429f3ccf036SAlexei Fedorov 		/* Restore group 1 counters */
430*31d3cc25SChris Kay 		for (i = 0U; i < read_amcgcr_el0_cg1nc(); i++) {
431873d4241Sjohpow01 			if ((AMU_GROUP1_COUNTERS_MASK & (1UL << i)) != 0U) {
432f3ccf036SAlexei Fedorov 				amu_group1_cnt_write(i, ctx->group1_cnts[i]);
433f3ccf036SAlexei Fedorov 			}
434f3ccf036SAlexei Fedorov 		}
435f3ccf036SAlexei Fedorov 
436873d4241Sjohpow01 		/* Restore group 1 virtual offsets if supported and enabled. */
43733b9be6dSChris Kay 		if (amu_v1p1_supported() && (read_hcr_el2_amvoffen() != 0U)) {
43833b9be6dSChris Kay 			uint64_t amcg1idr = read_amcg1idr_el0_voff() &
43933b9be6dSChris Kay 				AMU_GROUP1_COUNTERS_MASK;
440873d4241Sjohpow01 
441*31d3cc25SChris Kay 			for (i = 0U; i < read_amcgcr_el0_cg1nc(); i++) {
442873d4241Sjohpow01 				if (((amcg1idr >> i) & 1ULL) != 0ULL) {
443873d4241Sjohpow01 					amu_group1_voffset_write(i,
444873d4241Sjohpow01 						ctx->group1_voffsets[i]);
445873d4241Sjohpow01 				}
446873d4241Sjohpow01 			}
447873d4241Sjohpow01 		}
448873d4241Sjohpow01 
449f3ccf036SAlexei Fedorov 		/* Restore group 1 counter configuration */
45033b9be6dSChris Kay 		write_amcntenset1_el0_px(AMU_GROUP1_COUNTERS_MASK);
4511fd685a7SChris Kay 	}
452f3ccf036SAlexei Fedorov #endif
453b6eb3932SDimitris Papastamos 
45440daecc1SAntonio Nino Diaz 	return (void *)0;
455b6eb3932SDimitris Papastamos }
456b6eb3932SDimitris Papastamos 
457b6eb3932SDimitris Papastamos SUBSCRIBE_TO_EVENT(psci_suspend_pwrdown_start, amu_context_save);
458b6eb3932SDimitris Papastamos SUBSCRIBE_TO_EVENT(psci_suspend_pwrdown_finish, amu_context_restore);
459