xref: /rk3399_ARM-atf/lib/extensions/amu/aarch64/amu.c (revision 83ec7e452c182af1148af0abaf8f24da2585102a)
1380559c1SDimitris Papastamos /*
2*83ec7e45SBoyan 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>
19*83ec7e45SBoyan Karatotev #include <lib/utils_def.h>
20*83ec7e45SBoyan Karatotev #include <platform_def.h>
21f3ccf036SAlexei Fedorov 
22*83ec7e45SBoyan Karatotev amu_regs_t amu_ctx[PLATFORM_CORE_COUNT];
23380559c1SDimitris Papastamos 
24*83ec7e45SBoyan Karatotev static inline uint8_t read_amcgcr_el0_cg1nc(void)
2533b9be6dSChris Kay {
2633b9be6dSChris Kay 	return (read_amcgcr_el0() >> AMCGCR_EL0_CG1NC_SHIFT) &
2733b9be6dSChris Kay 		AMCGCR_EL0_CG1NC_MASK;
2833b9be6dSChris Kay }
2933b9be6dSChris Kay 
304085a02cSBoyan Karatotev void amu_enable(cpu_context_t *ctx)
310767d50eSDimitris Papastamos {
324085a02cSBoyan Karatotev 	/* Initialize FEAT_AMUv1p1 features if present. */
334085a02cSBoyan Karatotev 	if (is_feat_amuv1p1_supported()) {
34*83ec7e45SBoyan Karatotev 		el3_state_t *state = get_el3state_ctx(ctx);
35*83ec7e45SBoyan Karatotev 		u_register_t reg;
36*83ec7e45SBoyan Karatotev 
37e747a59bSChris Kay 		/*
384085a02cSBoyan Karatotev 		 * Set SCR_EL3.AMVOFFEN to one so that accesses to virtual
394085a02cSBoyan Karatotev 		 * offset registers at EL2 do not trap to EL3
40e747a59bSChris Kay 		 */
41*83ec7e45SBoyan Karatotev 		reg = read_ctx_reg(state, CTX_SCR_EL3);
42*83ec7e45SBoyan Karatotev 		reg |= SCR_AMVOFFEN_BIT;
43*83ec7e45SBoyan Karatotev 		write_ctx_reg(state, CTX_SCR_EL3, reg);
444085a02cSBoyan Karatotev 	}
454085a02cSBoyan Karatotev }
46f3ccf036SAlexei Fedorov 
47461c0a5dSElizabeth Ho void amu_enable_per_world(per_world_context_t *per_world_ctx)
48461c0a5dSElizabeth Ho {
49461c0a5dSElizabeth Ho 	/*
50461c0a5dSElizabeth Ho 	 * Set CPTR_EL3.TAM to zero so that any accesses to the Activity Monitor
51461c0a5dSElizabeth Ho 	 * registers do not trap to EL3.
52461c0a5dSElizabeth Ho 	 */
53461c0a5dSElizabeth Ho 	uint64_t cptr_el3 = per_world_ctx->ctx_cptr_el3;
54461c0a5dSElizabeth Ho 
55461c0a5dSElizabeth Ho 	cptr_el3 &= ~TAM_BIT;
56461c0a5dSElizabeth Ho 	per_world_ctx->ctx_cptr_el3 = cptr_el3;
57461c0a5dSElizabeth Ho }
58461c0a5dSElizabeth Ho 
59*83ec7e45SBoyan Karatotev void amu_init_el3(unsigned int core_pos)
604085a02cSBoyan Karatotev {
61*83ec7e45SBoyan Karatotev 	/* architecture is currently pinned to 4 */
62*83ec7e45SBoyan Karatotev 	assert((read_amcgcr_el0() & AMCGCR_EL0_CG0NC_MASK) == CTX_AMU_GRP0_ALL);
63e747a59bSChris Kay 
644085a02cSBoyan Karatotev 	/* Enable all architected counters by default */
65*83ec7e45SBoyan Karatotev 	write_amcntenset0_el0(AMCNTENSET0_EL0_Pn_MASK);
66*83ec7e45SBoyan Karatotev 	if (is_feat_amu_aux_supported()) {
67*83ec7e45SBoyan Karatotev 		/* something went wrong if we're trying to write higher bits */
68*83ec7e45SBoyan Karatotev 		assert((get_amu_aux_enables(core_pos) & ~AMCNTENSET1_EL0_Pn_MASK) == 0);
69*83ec7e45SBoyan Karatotev 		write_amcntenset1_el0(get_amu_aux_enables(core_pos));
70742ca230SChris Kay 	}
714085a02cSBoyan Karatotev 
72b57e16a4SAndre Przywara 	if (is_feat_amuv1p1_supported()) {
73873d4241Sjohpow01 #if AMU_RESTRICT_COUNTERS
74873d4241Sjohpow01 		/*
7568120783SChris Kay 		 * FEAT_AMUv1p1 adds a register field to restrict access to
7668120783SChris Kay 		 * group 1 counters at all but the highest implemented EL. This
7768120783SChris Kay 		 * is controlled with the `AMU_RESTRICT_COUNTERS` compile time
7868120783SChris Kay 		 * flag, when set, system register reads at lower ELs return
7968120783SChris Kay 		 * zero. Reads from the memory mapped view are unaffected.
80873d4241Sjohpow01 		 */
81873d4241Sjohpow01 		VERBOSE("AMU group 1 counter access restricted.\n");
82*83ec7e45SBoyan Karatotev 		write_amcr_el0(AMCR_CG1RZ_BIT);
83873d4241Sjohpow01 #else
84*83ec7e45SBoyan Karatotev 		/* HDBG = 0 in both cases */
85*83ec7e45SBoyan Karatotev 		write_amcr_el0(0);
86873d4241Sjohpow01 #endif
87380559c1SDimitris Papastamos 	}
8868120783SChris Kay }
8968120783SChris Kay 
904085a02cSBoyan Karatotev void amu_init_el2_unused(void)
914085a02cSBoyan Karatotev {
924085a02cSBoyan Karatotev 	/*
934085a02cSBoyan Karatotev 	 * CPTR_EL2.TAM: Set to zero so any accesses to the Activity Monitor
944085a02cSBoyan Karatotev 	 *  registers do not trap to EL2.
954085a02cSBoyan Karatotev 	 */
96*83ec7e45SBoyan Karatotev 	write_cptr_el2(read_cptr_el2() & ~CPTR_EL2_TAM_BIT);
974085a02cSBoyan Karatotev 
984085a02cSBoyan Karatotev 	if (is_feat_amuv1p1_supported()) {
99*83ec7e45SBoyan Karatotev 		/* Make sure virtual offsets are disabled */
100*83ec7e45SBoyan Karatotev 		write_hcr_el2(read_hcr_el2() & ~HCR_AMVOFFEN_BIT);
1014085a02cSBoyan Karatotev 	}
1024085a02cSBoyan Karatotev }
1034085a02cSBoyan Karatotev 
104b6eb3932SDimitris Papastamos static void *amu_context_save(const void *arg)
105b6eb3932SDimitris Papastamos {
106b57e16a4SAndre Przywara 	if (!is_feat_amu_supported()) {
107e747a59bSChris Kay 		return (void *)0;
108e747a59bSChris Kay 	}
109e747a59bSChris Kay 
110*83ec7e45SBoyan Karatotev 	unsigned int core_pos = *(unsigned int *)arg;
111*83ec7e45SBoyan Karatotev 	amu_regs_t *ctx = &amu_ctx[core_pos];
112e747a59bSChris Kay 
113*83ec7e45SBoyan Karatotev 	/* disable all counters so we can write them safely later */
114*83ec7e45SBoyan Karatotev 	write_amcntenclr0_el0(AMCNTENCLR0_EL0_Pn_MASK);
115*83ec7e45SBoyan Karatotev 	if (is_feat_amu_aux_supported()) {
116*83ec7e45SBoyan Karatotev 		write_amcntenclr1_el0(get_amu_aux_enables(core_pos));
117b57e16a4SAndre Przywara 	}
118e747a59bSChris Kay 
119*83ec7e45SBoyan Karatotev 	isb();
120e747a59bSChris Kay 
121*83ec7e45SBoyan Karatotev 	write_amu_grp0_ctx_reg(ctx, 0, read_amevcntr00_el0());
122*83ec7e45SBoyan Karatotev 	write_amu_grp0_ctx_reg(ctx, 1, read_amevcntr01_el0());
123*83ec7e45SBoyan Karatotev 	write_amu_grp0_ctx_reg(ctx, 2, read_amevcntr02_el0());
124*83ec7e45SBoyan Karatotev 	write_amu_grp0_ctx_reg(ctx, 3, read_amevcntr03_el0());
125e747a59bSChris Kay 
126*83ec7e45SBoyan Karatotev 	if (is_feat_amu_aux_supported()) {
127*83ec7e45SBoyan Karatotev 		uint8_t num_counters = read_amcgcr_el0_cg1nc();
128e747a59bSChris Kay 
129*83ec7e45SBoyan Karatotev 		switch (num_counters) {
130*83ec7e45SBoyan Karatotev 		case 0x10:
131*83ec7e45SBoyan Karatotev 			write_amu_grp1_ctx_reg(ctx, 0xf, read_amevcntr1f_el0());
132*83ec7e45SBoyan Karatotev 			__fallthrough;
133*83ec7e45SBoyan Karatotev 		case 0x0f:
134*83ec7e45SBoyan Karatotev 			write_amu_grp1_ctx_reg(ctx, 0xe, read_amevcntr1e_el0());
135*83ec7e45SBoyan Karatotev 			__fallthrough;
136*83ec7e45SBoyan Karatotev 		case 0x0e:
137*83ec7e45SBoyan Karatotev 			write_amu_grp1_ctx_reg(ctx, 0xd, read_amevcntr1d_el0());
138*83ec7e45SBoyan Karatotev 			__fallthrough;
139*83ec7e45SBoyan Karatotev 		case 0x0d:
140*83ec7e45SBoyan Karatotev 			write_amu_grp1_ctx_reg(ctx, 0xc, read_amevcntr1c_el0());
141*83ec7e45SBoyan Karatotev 			__fallthrough;
142*83ec7e45SBoyan Karatotev 		case 0x0c:
143*83ec7e45SBoyan Karatotev 			write_amu_grp1_ctx_reg(ctx, 0xb, read_amevcntr1b_el0());
144*83ec7e45SBoyan Karatotev 			__fallthrough;
145*83ec7e45SBoyan Karatotev 		case 0x0b:
146*83ec7e45SBoyan Karatotev 			write_amu_grp1_ctx_reg(ctx, 0xa, read_amevcntr1a_el0());
147*83ec7e45SBoyan Karatotev 			__fallthrough;
148*83ec7e45SBoyan Karatotev 		case 0x0a:
149*83ec7e45SBoyan Karatotev 			write_amu_grp1_ctx_reg(ctx, 0x9, read_amevcntr19_el0());
150*83ec7e45SBoyan Karatotev 			__fallthrough;
151*83ec7e45SBoyan Karatotev 		case 0x09:
152*83ec7e45SBoyan Karatotev 			write_amu_grp1_ctx_reg(ctx, 0x8, read_amevcntr18_el0());
153*83ec7e45SBoyan Karatotev 			__fallthrough;
154*83ec7e45SBoyan Karatotev 		case 0x08:
155*83ec7e45SBoyan Karatotev 			write_amu_grp1_ctx_reg(ctx, 0x7, read_amevcntr17_el0());
156*83ec7e45SBoyan Karatotev 			__fallthrough;
157*83ec7e45SBoyan Karatotev 		case 0x07:
158*83ec7e45SBoyan Karatotev 			write_amu_grp1_ctx_reg(ctx, 0x6, read_amevcntr16_el0());
159*83ec7e45SBoyan Karatotev 			__fallthrough;
160*83ec7e45SBoyan Karatotev 		case 0x06:
161*83ec7e45SBoyan Karatotev 			write_amu_grp1_ctx_reg(ctx, 0x5, read_amevcntr15_el0());
162*83ec7e45SBoyan Karatotev 			__fallthrough;
163*83ec7e45SBoyan Karatotev 		case 0x05:
164*83ec7e45SBoyan Karatotev 			write_amu_grp1_ctx_reg(ctx, 0x4, read_amevcntr14_el0());
165*83ec7e45SBoyan Karatotev 			__fallthrough;
166*83ec7e45SBoyan Karatotev 		case 0x04:
167*83ec7e45SBoyan Karatotev 			write_amu_grp1_ctx_reg(ctx, 0x3, read_amevcntr13_el0());
168*83ec7e45SBoyan Karatotev 			__fallthrough;
169*83ec7e45SBoyan Karatotev 		case 0x03:
170*83ec7e45SBoyan Karatotev 			write_amu_grp1_ctx_reg(ctx, 0x2, read_amevcntr12_el0());
171*83ec7e45SBoyan Karatotev 			__fallthrough;
172*83ec7e45SBoyan Karatotev 		case 0x02:
173*83ec7e45SBoyan Karatotev 			write_amu_grp1_ctx_reg(ctx, 0x1, read_amevcntr11_el0());
174*83ec7e45SBoyan Karatotev 			__fallthrough;
175*83ec7e45SBoyan Karatotev 		case 0x01:
176*83ec7e45SBoyan Karatotev 			write_amu_grp1_ctx_reg(ctx, 0x0, read_amevcntr10_el0());
177*83ec7e45SBoyan Karatotev 			__fallthrough;
178*83ec7e45SBoyan Karatotev 		case 0x00:
179*83ec7e45SBoyan Karatotev 			break;
180*83ec7e45SBoyan Karatotev 		default:
181*83ec7e45SBoyan Karatotev 			assert(0); /* something is wrong */
1821fd685a7SChris Kay 		}
183e747a59bSChris Kay 	}
1841fd685a7SChris Kay 
18540daecc1SAntonio Nino Diaz 	return (void *)0;
186b6eb3932SDimitris Papastamos }
187b6eb3932SDimitris Papastamos 
188b6eb3932SDimitris Papastamos static void *amu_context_restore(const void *arg)
189b6eb3932SDimitris Papastamos {
190b57e16a4SAndre Przywara 	if (!is_feat_amu_supported()) {
191e747a59bSChris Kay 		return (void *)0;
192e747a59bSChris Kay 	}
193e747a59bSChris Kay 
194*83ec7e45SBoyan Karatotev 	unsigned int core_pos = *(unsigned int *)arg;
195*83ec7e45SBoyan Karatotev 	amu_regs_t *ctx = &amu_ctx[core_pos];
196e747a59bSChris Kay 
197*83ec7e45SBoyan Karatotev 	write_amevcntr00_el0(read_amu_grp0_ctx_reg(ctx, 0));
198*83ec7e45SBoyan Karatotev 	write_amevcntr01_el0(read_amu_grp0_ctx_reg(ctx, 1));
199*83ec7e45SBoyan Karatotev 	write_amevcntr02_el0(read_amu_grp0_ctx_reg(ctx, 2));
200*83ec7e45SBoyan Karatotev 	write_amevcntr03_el0(read_amu_grp0_ctx_reg(ctx, 3));
201e747a59bSChris Kay 
202*83ec7e45SBoyan Karatotev 	if (is_feat_amu_aux_supported()) {
203*83ec7e45SBoyan Karatotev 		uint8_t num_counters = read_amcgcr_el0_cg1nc();
204*83ec7e45SBoyan Karatotev 
205*83ec7e45SBoyan Karatotev 		switch (num_counters) {
206*83ec7e45SBoyan Karatotev 		case 0x10:
207*83ec7e45SBoyan Karatotev 			write_amevcntr1f_el0(read_amu_grp1_ctx_reg(ctx, 0xf));
208*83ec7e45SBoyan Karatotev 			__fallthrough;
209*83ec7e45SBoyan Karatotev 		case 0x0f:
210*83ec7e45SBoyan Karatotev 			write_amevcntr1e_el0(read_amu_grp1_ctx_reg(ctx, 0xe));
211*83ec7e45SBoyan Karatotev 			__fallthrough;
212*83ec7e45SBoyan Karatotev 		case 0x0e:
213*83ec7e45SBoyan Karatotev 			write_amevcntr1d_el0(read_amu_grp1_ctx_reg(ctx, 0xd));
214*83ec7e45SBoyan Karatotev 			__fallthrough;
215*83ec7e45SBoyan Karatotev 		case 0x0d:
216*83ec7e45SBoyan Karatotev 			write_amevcntr1c_el0(read_amu_grp1_ctx_reg(ctx, 0xc));
217*83ec7e45SBoyan Karatotev 			__fallthrough;
218*83ec7e45SBoyan Karatotev 		case 0x0c:
219*83ec7e45SBoyan Karatotev 			write_amevcntr1b_el0(read_amu_grp1_ctx_reg(ctx, 0xb));
220*83ec7e45SBoyan Karatotev 			__fallthrough;
221*83ec7e45SBoyan Karatotev 		case 0x0b:
222*83ec7e45SBoyan Karatotev 			write_amevcntr1a_el0(read_amu_grp1_ctx_reg(ctx, 0xa));
223*83ec7e45SBoyan Karatotev 			__fallthrough;
224*83ec7e45SBoyan Karatotev 		case 0x0a:
225*83ec7e45SBoyan Karatotev 			write_amevcntr19_el0(read_amu_grp1_ctx_reg(ctx, 0x9));
226*83ec7e45SBoyan Karatotev 			__fallthrough;
227*83ec7e45SBoyan Karatotev 		case 0x09:
228*83ec7e45SBoyan Karatotev 			write_amevcntr18_el0(read_amu_grp1_ctx_reg(ctx, 0x8));
229*83ec7e45SBoyan Karatotev 			__fallthrough;
230*83ec7e45SBoyan Karatotev 		case 0x08:
231*83ec7e45SBoyan Karatotev 			write_amevcntr17_el0(read_amu_grp1_ctx_reg(ctx, 0x7));
232*83ec7e45SBoyan Karatotev 			__fallthrough;
233*83ec7e45SBoyan Karatotev 		case 0x07:
234*83ec7e45SBoyan Karatotev 			write_amevcntr16_el0(read_amu_grp1_ctx_reg(ctx, 0x6));
235*83ec7e45SBoyan Karatotev 			__fallthrough;
236*83ec7e45SBoyan Karatotev 		case 0x06:
237*83ec7e45SBoyan Karatotev 			write_amevcntr15_el0(read_amu_grp1_ctx_reg(ctx, 0x5));
238*83ec7e45SBoyan Karatotev 			__fallthrough;
239*83ec7e45SBoyan Karatotev 		case 0x05:
240*83ec7e45SBoyan Karatotev 			write_amevcntr14_el0(read_amu_grp1_ctx_reg(ctx, 0x4));
241*83ec7e45SBoyan Karatotev 			__fallthrough;
242*83ec7e45SBoyan Karatotev 		case 0x04:
243*83ec7e45SBoyan Karatotev 			write_amevcntr13_el0(read_amu_grp1_ctx_reg(ctx, 0x3));
244*83ec7e45SBoyan Karatotev 			__fallthrough;
245*83ec7e45SBoyan Karatotev 		case 0x03:
246*83ec7e45SBoyan Karatotev 			write_amevcntr12_el0(read_amu_grp1_ctx_reg(ctx, 0x2));
247*83ec7e45SBoyan Karatotev 			__fallthrough;
248*83ec7e45SBoyan Karatotev 		case 0x02:
249*83ec7e45SBoyan Karatotev 			write_amevcntr11_el0(read_amu_grp1_ctx_reg(ctx, 0x1));
250*83ec7e45SBoyan Karatotev 			__fallthrough;
251*83ec7e45SBoyan Karatotev 		case 0x01:
252*83ec7e45SBoyan Karatotev 			write_amevcntr10_el0(read_amu_grp1_ctx_reg(ctx, 0x0));
253*83ec7e45SBoyan Karatotev 			__fallthrough;
254*83ec7e45SBoyan Karatotev 		case 0x00:
255*83ec7e45SBoyan Karatotev 			break;
256*83ec7e45SBoyan Karatotev 		default:
257*83ec7e45SBoyan Karatotev 			assert(0); /* something is wrong */
258*83ec7e45SBoyan Karatotev 		}
259b57e16a4SAndre Przywara 	}
260e747a59bSChris Kay 
261e747a59bSChris Kay 
262*83ec7e45SBoyan Karatotev 	/* now enable them again */
263*83ec7e45SBoyan Karatotev 	write_amcntenset0_el0(AMCNTENSET0_EL0_Pn_MASK);
264*83ec7e45SBoyan Karatotev 	if (is_feat_amu_aux_supported()) {
265*83ec7e45SBoyan Karatotev 		write_amcntenset1_el0(get_amu_aux_enables(core_pos));
266f3ccf036SAlexei Fedorov 	}
267b6eb3932SDimitris Papastamos 
268*83ec7e45SBoyan Karatotev 	isb();
26940daecc1SAntonio Nino Diaz 	return (void *)0;
270b6eb3932SDimitris Papastamos }
271b6eb3932SDimitris Papastamos 
272b6eb3932SDimitris Papastamos SUBSCRIBE_TO_EVENT(psci_suspend_pwrdown_start, amu_context_save);
273b6eb3932SDimitris Papastamos SUBSCRIBE_TO_EVENT(psci_suspend_pwrdown_finish, amu_context_restore);
274