xref: /rk3399_ARM-atf/lib/extensions/amu/aarch64/amu.c (revision bc3dac6c24f1941d21bbc6169fdf2dac6ad72f30)
1380559c1SDimitris Papastamos /*
283ec7e45SBoyan Karatotev  * Copyright (c) 2017-2025, 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>
94ce3e99aSScott Branden #include <inttypes.h>
1009d40e0eSAntonio Nino Diaz #include <stdbool.h>
114ce3e99aSScott Branden #include <stdint.h>
1209d40e0eSAntonio Nino Diaz 
13380559c1SDimitris Papastamos #include <arch.h>
14873d4241Sjohpow01 #include <arch_features.h>
15380559c1SDimitris Papastamos #include <arch_helpers.h>
16742ca230SChris Kay #include <common/debug.h>
1709d40e0eSAntonio Nino Diaz #include <lib/el3_runtime/pubsub_events.h>
1809d40e0eSAntonio Nino Diaz #include <lib/extensions/amu.h>
190f90f374SSammit Joshi #include <lib/per_cpu/per_cpu.h>
2083ec7e45SBoyan Karatotev #include <lib/utils_def.h>
2183ec7e45SBoyan Karatotev #include <platform_def.h>
22f3ccf036SAlexei Fedorov 
230f90f374SSammit Joshi PER_CPU_DEFINE(amu_regs_t, amu_ctx);
24380559c1SDimitris Papastamos 
read_amcgcr_el0_cg1nc(void)2583ec7e45SBoyan Karatotev static inline uint8_t read_amcgcr_el0_cg1nc(void)
2633b9be6dSChris Kay {
2733b9be6dSChris Kay 	return (read_amcgcr_el0() >> AMCGCR_EL0_CG1NC_SHIFT) &
2833b9be6dSChris Kay 		AMCGCR_EL0_CG1NC_MASK;
2933b9be6dSChris Kay }
3033b9be6dSChris Kay 
amu_enable(cpu_context_t * ctx)314085a02cSBoyan Karatotev void amu_enable(cpu_context_t *ctx)
320767d50eSDimitris Papastamos {
334085a02cSBoyan Karatotev 	/* Initialize FEAT_AMUv1p1 features if present. */
344085a02cSBoyan Karatotev 	if (is_feat_amuv1p1_supported()) {
3583ec7e45SBoyan Karatotev 		el3_state_t *state = get_el3state_ctx(ctx);
3683ec7e45SBoyan Karatotev 		u_register_t reg;
3783ec7e45SBoyan Karatotev 
38e747a59bSChris Kay 		/*
394085a02cSBoyan Karatotev 		 * Set SCR_EL3.AMVOFFEN to one so that accesses to virtual
404085a02cSBoyan Karatotev 		 * offset registers at EL2 do not trap to EL3
41e747a59bSChris Kay 		 */
4283ec7e45SBoyan Karatotev 		reg = read_ctx_reg(state, CTX_SCR_EL3);
4383ec7e45SBoyan Karatotev 		reg |= SCR_AMVOFFEN_BIT;
4483ec7e45SBoyan Karatotev 		write_ctx_reg(state, CTX_SCR_EL3, reg);
454085a02cSBoyan Karatotev 	}
464085a02cSBoyan Karatotev }
47f3ccf036SAlexei Fedorov 
amu_enable_per_world(per_world_context_t * per_world_ctx)48461c0a5dSElizabeth Ho void amu_enable_per_world(per_world_context_t *per_world_ctx)
49461c0a5dSElizabeth Ho {
50461c0a5dSElizabeth Ho 	/*
51461c0a5dSElizabeth Ho 	 * Set CPTR_EL3.TAM to zero so that any accesses to the Activity Monitor
52461c0a5dSElizabeth Ho 	 * registers do not trap to EL3.
53461c0a5dSElizabeth Ho 	 */
54461c0a5dSElizabeth Ho 	uint64_t cptr_el3 = per_world_ctx->ctx_cptr_el3;
55461c0a5dSElizabeth Ho 
56461c0a5dSElizabeth Ho 	cptr_el3 &= ~TAM_BIT;
57461c0a5dSElizabeth Ho 	per_world_ctx->ctx_cptr_el3 = cptr_el3;
58461c0a5dSElizabeth Ho }
59461c0a5dSElizabeth Ho 
amu_init_el3(unsigned int core_pos)6083ec7e45SBoyan Karatotev void amu_init_el3(unsigned int core_pos)
614085a02cSBoyan Karatotev {
6283ec7e45SBoyan Karatotev 	/* architecture is currently pinned to 4 */
6383ec7e45SBoyan Karatotev 	assert((read_amcgcr_el0() & AMCGCR_EL0_CG0NC_MASK) == CTX_AMU_GRP0_ALL);
64e747a59bSChris Kay 
654085a02cSBoyan Karatotev 	/* Enable all architected counters by default */
6683ec7e45SBoyan Karatotev 	write_amcntenset0_el0(AMCNTENSET0_EL0_Pn_MASK);
67*6edbd2d6SBoyan Karatotev 
68*6edbd2d6SBoyan Karatotev 	if (!is_feat_amuv1p1_supported()) {
69*6edbd2d6SBoyan Karatotev 		return;
70*6edbd2d6SBoyan Karatotev 	}
71*6edbd2d6SBoyan Karatotev 
7283ec7e45SBoyan Karatotev 	if (is_feat_amu_aux_supported()) {
7383ec7e45SBoyan Karatotev 		/* something went wrong if we're trying to write higher bits */
7483ec7e45SBoyan Karatotev 		assert((get_amu_aux_enables(core_pos) & ~AMCNTENSET1_EL0_Pn_MASK) == 0);
7583ec7e45SBoyan Karatotev 		write_amcntenset1_el0(get_amu_aux_enables(core_pos));
76742ca230SChris Kay 	}
774085a02cSBoyan Karatotev 
78873d4241Sjohpow01 #if AMU_RESTRICT_COUNTERS
79873d4241Sjohpow01 	/*
8068120783SChris Kay 	 * FEAT_AMUv1p1 adds a register field to restrict access to
8168120783SChris Kay 	 * group 1 counters at all but the highest implemented EL. This
8268120783SChris Kay 	 * is controlled with the `AMU_RESTRICT_COUNTERS` compile time
8368120783SChris Kay 	 * flag, when set, system register reads at lower ELs return
8468120783SChris Kay 	 * zero. Reads from the memory mapped view are unaffected.
85873d4241Sjohpow01 	 */
86873d4241Sjohpow01 	VERBOSE("AMU group 1 counter access restricted.\n");
8783ec7e45SBoyan Karatotev 	write_amcr_el0(AMCR_CG1RZ_BIT);
88873d4241Sjohpow01 #else
8983ec7e45SBoyan Karatotev 	/* HDBG = 0 in both cases */
9083ec7e45SBoyan Karatotev 	write_amcr_el0(0);
91873d4241Sjohpow01 #endif
92380559c1SDimitris Papastamos }
9368120783SChris Kay 
944085a02cSBoyan Karatotev void amu_init_el2_unused(void)
954085a02cSBoyan Karatotev {
964085a02cSBoyan Karatotev 	/*
974085a02cSBoyan Karatotev 	 * CPTR_EL2.TAM: Set to zero so any accesses to the Activity Monitor
984085a02cSBoyan Karatotev 	 *  registers do not trap to EL2.
994085a02cSBoyan Karatotev 	 */
10083ec7e45SBoyan Karatotev 	write_cptr_el2(read_cptr_el2() & ~CPTR_EL2_TAM_BIT);
1014085a02cSBoyan Karatotev 
1024085a02cSBoyan Karatotev 	if (is_feat_amuv1p1_supported()) {
10383ec7e45SBoyan Karatotev 		/* Make sure virtual offsets are disabled */
10483ec7e45SBoyan Karatotev 		write_hcr_el2(read_hcr_el2() & ~HCR_AMVOFFEN_BIT);
amu_context_save(const void * arg)1054085a02cSBoyan Karatotev 	}
1064085a02cSBoyan Karatotev }
1074085a02cSBoyan Karatotev 
108b6eb3932SDimitris Papastamos static void *amu_context_save(const void *arg)
109b6eb3932SDimitris Papastamos {
110b57e16a4SAndre Przywara 	if (!is_feat_amu_supported()) {
111e747a59bSChris Kay 		return (void *)0;
112e747a59bSChris Kay 	}
113e747a59bSChris Kay 
11483ec7e45SBoyan Karatotev 	unsigned int core_pos = *(unsigned int *)arg;
1150f90f374SSammit Joshi 	amu_regs_t *ctx = PER_CPU_CUR(amu_ctx);
116e747a59bSChris Kay 
11783ec7e45SBoyan Karatotev 	/* disable all counters so we can write them safely later */
11883ec7e45SBoyan Karatotev 	write_amcntenclr0_el0(AMCNTENCLR0_EL0_Pn_MASK);
11983ec7e45SBoyan Karatotev 	if (is_feat_amu_aux_supported()) {
12083ec7e45SBoyan Karatotev 		write_amcntenclr1_el0(get_amu_aux_enables(core_pos));
121b57e16a4SAndre Przywara 	}
122e747a59bSChris Kay 
12383ec7e45SBoyan Karatotev 	isb();
124e747a59bSChris Kay 
12583ec7e45SBoyan Karatotev 	write_amu_grp0_ctx_reg(ctx, 0, read_amevcntr00_el0());
12683ec7e45SBoyan Karatotev 	write_amu_grp0_ctx_reg(ctx, 1, read_amevcntr01_el0());
12783ec7e45SBoyan Karatotev 	write_amu_grp0_ctx_reg(ctx, 2, read_amevcntr02_el0());
12883ec7e45SBoyan Karatotev 	write_amu_grp0_ctx_reg(ctx, 3, read_amevcntr03_el0());
129e747a59bSChris Kay 
13083ec7e45SBoyan Karatotev 	if (is_feat_amu_aux_supported()) {
13183ec7e45SBoyan Karatotev 		uint8_t num_counters = read_amcgcr_el0_cg1nc();
132e747a59bSChris Kay 
13383ec7e45SBoyan Karatotev 		switch (num_counters) {
13483ec7e45SBoyan Karatotev 		case 0x10:
13583ec7e45SBoyan Karatotev 			write_amu_grp1_ctx_reg(ctx, 0xf, read_amevcntr1f_el0());
13683ec7e45SBoyan Karatotev 			__fallthrough;
13783ec7e45SBoyan Karatotev 		case 0x0f:
13883ec7e45SBoyan Karatotev 			write_amu_grp1_ctx_reg(ctx, 0xe, read_amevcntr1e_el0());
13983ec7e45SBoyan Karatotev 			__fallthrough;
14083ec7e45SBoyan Karatotev 		case 0x0e:
14183ec7e45SBoyan Karatotev 			write_amu_grp1_ctx_reg(ctx, 0xd, read_amevcntr1d_el0());
14283ec7e45SBoyan Karatotev 			__fallthrough;
14383ec7e45SBoyan Karatotev 		case 0x0d:
14483ec7e45SBoyan Karatotev 			write_amu_grp1_ctx_reg(ctx, 0xc, read_amevcntr1c_el0());
14583ec7e45SBoyan Karatotev 			__fallthrough;
14683ec7e45SBoyan Karatotev 		case 0x0c:
14783ec7e45SBoyan Karatotev 			write_amu_grp1_ctx_reg(ctx, 0xb, read_amevcntr1b_el0());
14883ec7e45SBoyan Karatotev 			__fallthrough;
14983ec7e45SBoyan Karatotev 		case 0x0b:
15083ec7e45SBoyan Karatotev 			write_amu_grp1_ctx_reg(ctx, 0xa, read_amevcntr1a_el0());
15183ec7e45SBoyan Karatotev 			__fallthrough;
15283ec7e45SBoyan Karatotev 		case 0x0a:
15383ec7e45SBoyan Karatotev 			write_amu_grp1_ctx_reg(ctx, 0x9, read_amevcntr19_el0());
15483ec7e45SBoyan Karatotev 			__fallthrough;
15583ec7e45SBoyan Karatotev 		case 0x09:
15683ec7e45SBoyan Karatotev 			write_amu_grp1_ctx_reg(ctx, 0x8, read_amevcntr18_el0());
15783ec7e45SBoyan Karatotev 			__fallthrough;
15883ec7e45SBoyan Karatotev 		case 0x08:
15983ec7e45SBoyan Karatotev 			write_amu_grp1_ctx_reg(ctx, 0x7, read_amevcntr17_el0());
16083ec7e45SBoyan Karatotev 			__fallthrough;
16183ec7e45SBoyan Karatotev 		case 0x07:
16283ec7e45SBoyan Karatotev 			write_amu_grp1_ctx_reg(ctx, 0x6, read_amevcntr16_el0());
16383ec7e45SBoyan Karatotev 			__fallthrough;
16483ec7e45SBoyan Karatotev 		case 0x06:
16583ec7e45SBoyan Karatotev 			write_amu_grp1_ctx_reg(ctx, 0x5, read_amevcntr15_el0());
16683ec7e45SBoyan Karatotev 			__fallthrough;
16783ec7e45SBoyan Karatotev 		case 0x05:
16883ec7e45SBoyan Karatotev 			write_amu_grp1_ctx_reg(ctx, 0x4, read_amevcntr14_el0());
16983ec7e45SBoyan Karatotev 			__fallthrough;
17083ec7e45SBoyan Karatotev 		case 0x04:
17183ec7e45SBoyan Karatotev 			write_amu_grp1_ctx_reg(ctx, 0x3, read_amevcntr13_el0());
17283ec7e45SBoyan Karatotev 			__fallthrough;
17383ec7e45SBoyan Karatotev 		case 0x03:
17483ec7e45SBoyan Karatotev 			write_amu_grp1_ctx_reg(ctx, 0x2, read_amevcntr12_el0());
17583ec7e45SBoyan Karatotev 			__fallthrough;
17683ec7e45SBoyan Karatotev 		case 0x02:
17783ec7e45SBoyan Karatotev 			write_amu_grp1_ctx_reg(ctx, 0x1, read_amevcntr11_el0());
17883ec7e45SBoyan Karatotev 			__fallthrough;
17983ec7e45SBoyan Karatotev 		case 0x01:
18083ec7e45SBoyan Karatotev 			write_amu_grp1_ctx_reg(ctx, 0x0, read_amevcntr10_el0());
18183ec7e45SBoyan Karatotev 			__fallthrough;
18283ec7e45SBoyan Karatotev 		case 0x00:
18383ec7e45SBoyan Karatotev 			break;
18483ec7e45SBoyan Karatotev 		default:
18583ec7e45SBoyan Karatotev 			assert(0); /* something is wrong */
1861fd685a7SChris Kay 		}
187e747a59bSChris Kay 	}
1881fd685a7SChris Kay 
18940daecc1SAntonio Nino Diaz 	return (void *)0;
190b6eb3932SDimitris Papastamos }
191b6eb3932SDimitris Papastamos 
192b6eb3932SDimitris Papastamos static void *amu_context_restore(const void *arg)
193b6eb3932SDimitris Papastamos {
194b57e16a4SAndre Przywara 	if (!is_feat_amu_supported()) {
195e747a59bSChris Kay 		return (void *)0;
196e747a59bSChris Kay 	}
197e747a59bSChris Kay 
19883ec7e45SBoyan Karatotev 	unsigned int core_pos = *(unsigned int *)arg;
1990f90f374SSammit Joshi 	amu_regs_t *ctx = PER_CPU_CUR(amu_ctx);
200e747a59bSChris Kay 
20183ec7e45SBoyan Karatotev 	write_amevcntr00_el0(read_amu_grp0_ctx_reg(ctx, 0));
20283ec7e45SBoyan Karatotev 	write_amevcntr01_el0(read_amu_grp0_ctx_reg(ctx, 1));
20383ec7e45SBoyan Karatotev 	write_amevcntr02_el0(read_amu_grp0_ctx_reg(ctx, 2));
20483ec7e45SBoyan Karatotev 	write_amevcntr03_el0(read_amu_grp0_ctx_reg(ctx, 3));
205e747a59bSChris Kay 
20683ec7e45SBoyan Karatotev 	if (is_feat_amu_aux_supported()) {
20783ec7e45SBoyan Karatotev 		uint8_t num_counters = read_amcgcr_el0_cg1nc();
20883ec7e45SBoyan Karatotev 
20983ec7e45SBoyan Karatotev 		switch (num_counters) {
21083ec7e45SBoyan Karatotev 		case 0x10:
21183ec7e45SBoyan Karatotev 			write_amevcntr1f_el0(read_amu_grp1_ctx_reg(ctx, 0xf));
21283ec7e45SBoyan Karatotev 			__fallthrough;
21383ec7e45SBoyan Karatotev 		case 0x0f:
21483ec7e45SBoyan Karatotev 			write_amevcntr1e_el0(read_amu_grp1_ctx_reg(ctx, 0xe));
21583ec7e45SBoyan Karatotev 			__fallthrough;
21683ec7e45SBoyan Karatotev 		case 0x0e:
21783ec7e45SBoyan Karatotev 			write_amevcntr1d_el0(read_amu_grp1_ctx_reg(ctx, 0xd));
21883ec7e45SBoyan Karatotev 			__fallthrough;
21983ec7e45SBoyan Karatotev 		case 0x0d:
22083ec7e45SBoyan Karatotev 			write_amevcntr1c_el0(read_amu_grp1_ctx_reg(ctx, 0xc));
22183ec7e45SBoyan Karatotev 			__fallthrough;
22283ec7e45SBoyan Karatotev 		case 0x0c:
22383ec7e45SBoyan Karatotev 			write_amevcntr1b_el0(read_amu_grp1_ctx_reg(ctx, 0xb));
22483ec7e45SBoyan Karatotev 			__fallthrough;
22583ec7e45SBoyan Karatotev 		case 0x0b:
22683ec7e45SBoyan Karatotev 			write_amevcntr1a_el0(read_amu_grp1_ctx_reg(ctx, 0xa));
22783ec7e45SBoyan Karatotev 			__fallthrough;
22883ec7e45SBoyan Karatotev 		case 0x0a:
22983ec7e45SBoyan Karatotev 			write_amevcntr19_el0(read_amu_grp1_ctx_reg(ctx, 0x9));
23083ec7e45SBoyan Karatotev 			__fallthrough;
23183ec7e45SBoyan Karatotev 		case 0x09:
23283ec7e45SBoyan Karatotev 			write_amevcntr18_el0(read_amu_grp1_ctx_reg(ctx, 0x8));
23383ec7e45SBoyan Karatotev 			__fallthrough;
23483ec7e45SBoyan Karatotev 		case 0x08:
23583ec7e45SBoyan Karatotev 			write_amevcntr17_el0(read_amu_grp1_ctx_reg(ctx, 0x7));
23683ec7e45SBoyan Karatotev 			__fallthrough;
23783ec7e45SBoyan Karatotev 		case 0x07:
23883ec7e45SBoyan Karatotev 			write_amevcntr16_el0(read_amu_grp1_ctx_reg(ctx, 0x6));
23983ec7e45SBoyan Karatotev 			__fallthrough;
24083ec7e45SBoyan Karatotev 		case 0x06:
24183ec7e45SBoyan Karatotev 			write_amevcntr15_el0(read_amu_grp1_ctx_reg(ctx, 0x5));
24283ec7e45SBoyan Karatotev 			__fallthrough;
24383ec7e45SBoyan Karatotev 		case 0x05:
24483ec7e45SBoyan Karatotev 			write_amevcntr14_el0(read_amu_grp1_ctx_reg(ctx, 0x4));
24583ec7e45SBoyan Karatotev 			__fallthrough;
24683ec7e45SBoyan Karatotev 		case 0x04:
24783ec7e45SBoyan Karatotev 			write_amevcntr13_el0(read_amu_grp1_ctx_reg(ctx, 0x3));
24883ec7e45SBoyan Karatotev 			__fallthrough;
24983ec7e45SBoyan Karatotev 		case 0x03:
25083ec7e45SBoyan Karatotev 			write_amevcntr12_el0(read_amu_grp1_ctx_reg(ctx, 0x2));
25183ec7e45SBoyan Karatotev 			__fallthrough;
25283ec7e45SBoyan Karatotev 		case 0x02:
25383ec7e45SBoyan Karatotev 			write_amevcntr11_el0(read_amu_grp1_ctx_reg(ctx, 0x1));
25483ec7e45SBoyan Karatotev 			__fallthrough;
25583ec7e45SBoyan Karatotev 		case 0x01:
25683ec7e45SBoyan Karatotev 			write_amevcntr10_el0(read_amu_grp1_ctx_reg(ctx, 0x0));
25783ec7e45SBoyan Karatotev 			__fallthrough;
25883ec7e45SBoyan Karatotev 		case 0x00:
25983ec7e45SBoyan Karatotev 			break;
26083ec7e45SBoyan Karatotev 		default:
26183ec7e45SBoyan Karatotev 			assert(0); /* something is wrong */
26283ec7e45SBoyan Karatotev 		}
263b57e16a4SAndre Przywara 	}
264e747a59bSChris Kay 
265e747a59bSChris Kay 
26683ec7e45SBoyan Karatotev 	/* now enable them again */
26783ec7e45SBoyan Karatotev 	write_amcntenset0_el0(AMCNTENSET0_EL0_Pn_MASK);
26883ec7e45SBoyan Karatotev 	if (is_feat_amu_aux_supported()) {
26983ec7e45SBoyan Karatotev 		write_amcntenset1_el0(get_amu_aux_enables(core_pos));
270f3ccf036SAlexei Fedorov 	}
271b6eb3932SDimitris Papastamos 
27283ec7e45SBoyan Karatotev 	isb();
27340daecc1SAntonio Nino Diaz 	return (void *)0;
274b6eb3932SDimitris Papastamos }
275b6eb3932SDimitris Papastamos 
276b6eb3932SDimitris Papastamos SUBSCRIBE_TO_EVENT(psci_suspend_pwrdown_start, amu_context_save);
277b6eb3932SDimitris Papastamos SUBSCRIBE_TO_EVENT(psci_suspend_pwrdown_finish, amu_context_restore);
278