xref: /rk3399_ARM-atf/lib/extensions/amu/aarch32/amu.c (revision 83ec7e452c182af1148af0abaf8f24da2585102a)
1ef69e1eaSDimitris Papastamos /*
2*83ec7e45SBoyan Karatotev  * Copyright (c) 2017-2025, Arm Limited and Contributors. All rights reserved.
3ef69e1eaSDimitris Papastamos  *
4ef69e1eaSDimitris Papastamos  * SPDX-License-Identifier: BSD-3-Clause
5ef69e1eaSDimitris Papastamos  */
6ef69e1eaSDimitris Papastamos 
7f3ccf036SAlexei Fedorov #include <assert.h>
833b9be6dSChris Kay #include <cdefs.h>
909d40e0eSAntonio Nino Diaz #include <stdbool.h>
1009d40e0eSAntonio Nino Diaz 
11ef69e1eaSDimitris Papastamos #include <arch.h>
12b57e16a4SAndre Przywara #include <arch_features.h>
13ef69e1eaSDimitris Papastamos #include <arch_helpers.h>
14742ca230SChris Kay #include <common/debug.h>
1509d40e0eSAntonio Nino Diaz #include <lib/el3_runtime/pubsub_events.h>
1609d40e0eSAntonio Nino Diaz #include <lib/extensions/amu.h>
17f3ccf036SAlexei Fedorov 
1809d40e0eSAntonio Nino Diaz #include <plat/common/platform.h>
19b6eb3932SDimitris Papastamos 
20*83ec7e45SBoyan Karatotev amu_regs_t amu_ctx[PLATFORM_CORE_COUNT];
2181e2ff1fSChris Kay 
2233b9be6dSChris Kay static inline __unused uint32_t read_amcgcr_cg1nc(void)
2333b9be6dSChris Kay {
2433b9be6dSChris Kay 	return (read_amcgcr() >> AMCGCR_CG1NC_SHIFT) &
2533b9be6dSChris Kay 		AMCGCR_CG1NC_MASK;
2633b9be6dSChris Kay }
2733b9be6dSChris Kay 
28f3ccf036SAlexei Fedorov /*
29e747a59bSChris Kay  * Enable counters. This function is meant to be invoked by the context
30e747a59bSChris Kay  * management library before exiting from EL3.
31f3ccf036SAlexei Fedorov  */
3240daecc1SAntonio Nino Diaz void amu_enable(bool el2_unused)
33c70da546SJoel Hutton {
34ef69e1eaSDimitris Papastamos 	if (el2_unused) {
35ef69e1eaSDimitris Papastamos 		/*
36e747a59bSChris Kay 		 * HCPTR.TAM: Set to zero so any accesses to the Activity
37e747a59bSChris Kay 		 * Monitor registers do not trap to EL2.
38ef69e1eaSDimitris Papastamos 		 */
39*83ec7e45SBoyan Karatotev 		write_hcptr(read_hcptr() & ~TAM_BIT);
40ef69e1eaSDimitris Papastamos 	}
41ef69e1eaSDimitris Papastamos 
42*83ec7e45SBoyan Karatotev 	/* Architecture is currently pinned to 4 */
43*83ec7e45SBoyan Karatotev 	assert((read_amcgcr() & AMCGCR_CG0NC_MASK) == CTX_AMU_GRP0_ALL);
44c70da546SJoel Hutton 
45*83ec7e45SBoyan Karatotev 	/* Enable all architected counters by default */
46*83ec7e45SBoyan Karatotev 	write_amcntenset0(AMCNTENSET0_Pn_MASK);
47*83ec7e45SBoyan Karatotev 	if (is_feat_amu_aux_supported()) {
48742ca230SChris Kay 		unsigned int core_pos = plat_my_core_pos();
49742ca230SChris Kay 
50*83ec7e45SBoyan Karatotev 		/* Something went wrong if we're trying to write higher bits */
51*83ec7e45SBoyan Karatotev 		assert((get_amu_aux_enables(core_pos) & ~AMCNTENSET1_Pn_MASK) == 0);
52*83ec7e45SBoyan Karatotev 		write_amcntenset1(get_amu_aux_enables(core_pos));
531fd685a7SChris Kay 	}
54873d4241Sjohpow01 
55b57e16a4SAndre Przywara 	/* Bail out if FEAT_AMUv1p1 features are not present. */
56b57e16a4SAndre Przywara 	if (!is_feat_amuv1p1_supported()) {
57873d4241Sjohpow01 		return;
58873d4241Sjohpow01 	}
59873d4241Sjohpow01 
60873d4241Sjohpow01 #if AMU_RESTRICT_COUNTERS
61873d4241Sjohpow01 	/*
62873d4241Sjohpow01 	 * FEAT_AMUv1p1 adds a register field to restrict access to group 1
63873d4241Sjohpow01 	 * counters at all but the highest implemented EL.  This is controlled
64873d4241Sjohpow01 	 * with the AMU_RESTRICT_COUNTERS compile time flag, when set, system
65873d4241Sjohpow01 	 * register reads at lower ELs return zero.  Reads from the memory
66873d4241Sjohpow01 	 * mapped view are unaffected.
67873d4241Sjohpow01 	 */
68873d4241Sjohpow01 	VERBOSE("AMU group 1 counter access restricted.\n");
69*83ec7e45SBoyan Karatotev 	write_amcr(read_amcr() | 1U);
70873d4241Sjohpow01 #else
71*83ec7e45SBoyan Karatotev 	write_amcr(0);
72873d4241Sjohpow01 #endif
73c70da546SJoel Hutton }
74c70da546SJoel Hutton 
75b6eb3932SDimitris Papastamos static void *amu_context_save(const void *arg)
76b6eb3932SDimitris Papastamos {
77b57e16a4SAndre Przywara 	if (!is_feat_amu_supported()) {
78e747a59bSChris Kay 		return (void *)0;
79e747a59bSChris Kay 	}
80e747a59bSChris Kay 
81*83ec7e45SBoyan Karatotev 	unsigned int core_pos = *(unsigned int *)arg;
82*83ec7e45SBoyan Karatotev 	amu_regs_t *ctx = &amu_ctx[core_pos];
83e747a59bSChris Kay 
84*83ec7e45SBoyan Karatotev 	/* Disable all counters so we can write to them safely later */
85*83ec7e45SBoyan Karatotev 	write_amcntenclr0(AMCNTENCLR0_Pn_MASK);
86*83ec7e45SBoyan Karatotev 	if (is_feat_amu_aux_supported()) {
87*83ec7e45SBoyan Karatotev 		write_amcntenclr1(get_amu_aux_enables(core_pos));
881fd685a7SChris Kay 	}
89b6eb3932SDimitris Papastamos 
90e747a59bSChris Kay 	isb(); /* Ensure counters have been stopped */
91e747a59bSChris Kay 
92*83ec7e45SBoyan Karatotev 	write_amu_grp0_ctx_reg(ctx, 0, read64_amevcntr00());
93*83ec7e45SBoyan Karatotev 	write_amu_grp0_ctx_reg(ctx, 1, read64_amevcntr01());
94*83ec7e45SBoyan Karatotev 	write_amu_grp0_ctx_reg(ctx, 2, read64_amevcntr02());
95*83ec7e45SBoyan Karatotev 	write_amu_grp0_ctx_reg(ctx, 3, read64_amevcntr03());
96c70da546SJoel Hutton 
97*83ec7e45SBoyan Karatotev 	if (is_feat_amu_aux_supported()) {
98*83ec7e45SBoyan Karatotev 		uint8_t num_counters = read_amcgcr_cg1nc();
99*83ec7e45SBoyan Karatotev 
100*83ec7e45SBoyan Karatotev 		switch (num_counters) {
101*83ec7e45SBoyan Karatotev 		case 0x10:
102*83ec7e45SBoyan Karatotev 			write_amu_grp1_ctx_reg(ctx, 0xf, read64_amevcntr1f());
103*83ec7e45SBoyan Karatotev 			__fallthrough;
104*83ec7e45SBoyan Karatotev 		case 0x0f:
105*83ec7e45SBoyan Karatotev 			write_amu_grp1_ctx_reg(ctx, 0xe, read64_amevcntr1e());
106*83ec7e45SBoyan Karatotev 			__fallthrough;
107*83ec7e45SBoyan Karatotev 		case 0x0e:
108*83ec7e45SBoyan Karatotev 			write_amu_grp1_ctx_reg(ctx, 0xd, read64_amevcntr1d());
109*83ec7e45SBoyan Karatotev 			__fallthrough;
110*83ec7e45SBoyan Karatotev 		case 0x0d:
111*83ec7e45SBoyan Karatotev 			write_amu_grp1_ctx_reg(ctx, 0xc, read64_amevcntr1c());
112*83ec7e45SBoyan Karatotev 			__fallthrough;
113*83ec7e45SBoyan Karatotev 		case 0x0c:
114*83ec7e45SBoyan Karatotev 			write_amu_grp1_ctx_reg(ctx, 0xb, read64_amevcntr1b());
115*83ec7e45SBoyan Karatotev 			__fallthrough;
116*83ec7e45SBoyan Karatotev 		case 0x0b:
117*83ec7e45SBoyan Karatotev 			write_amu_grp1_ctx_reg(ctx, 0xa, read64_amevcntr1a());
118*83ec7e45SBoyan Karatotev 			__fallthrough;
119*83ec7e45SBoyan Karatotev 		case 0x0a:
120*83ec7e45SBoyan Karatotev 			write_amu_grp1_ctx_reg(ctx, 0x9, read64_amevcntr19());
121*83ec7e45SBoyan Karatotev 			__fallthrough;
122*83ec7e45SBoyan Karatotev 		case 0x09:
123*83ec7e45SBoyan Karatotev 			write_amu_grp1_ctx_reg(ctx, 0x8, read64_amevcntr18());
124*83ec7e45SBoyan Karatotev 			__fallthrough;
125*83ec7e45SBoyan Karatotev 		case 0x08:
126*83ec7e45SBoyan Karatotev 			write_amu_grp1_ctx_reg(ctx, 0x7, read64_amevcntr17());
127*83ec7e45SBoyan Karatotev 			__fallthrough;
128*83ec7e45SBoyan Karatotev 		case 0x07:
129*83ec7e45SBoyan Karatotev 			write_amu_grp1_ctx_reg(ctx, 0x6, read64_amevcntr16());
130*83ec7e45SBoyan Karatotev 			__fallthrough;
131*83ec7e45SBoyan Karatotev 		case 0x06:
132*83ec7e45SBoyan Karatotev 			write_amu_grp1_ctx_reg(ctx, 0x5, read64_amevcntr15());
133*83ec7e45SBoyan Karatotev 			__fallthrough;
134*83ec7e45SBoyan Karatotev 		case 0x05:
135*83ec7e45SBoyan Karatotev 			write_amu_grp1_ctx_reg(ctx, 0x4, read64_amevcntr14());
136*83ec7e45SBoyan Karatotev 			__fallthrough;
137*83ec7e45SBoyan Karatotev 		case 0x04:
138*83ec7e45SBoyan Karatotev 			write_amu_grp1_ctx_reg(ctx, 0x3, read64_amevcntr13());
139*83ec7e45SBoyan Karatotev 			__fallthrough;
140*83ec7e45SBoyan Karatotev 		case 0x03:
141*83ec7e45SBoyan Karatotev 			write_amu_grp1_ctx_reg(ctx, 0x2, read64_amevcntr12());
142*83ec7e45SBoyan Karatotev 			__fallthrough;
143*83ec7e45SBoyan Karatotev 		case 0x02:
144*83ec7e45SBoyan Karatotev 			write_amu_grp1_ctx_reg(ctx, 0x1, read64_amevcntr11());
145*83ec7e45SBoyan Karatotev 			__fallthrough;
146*83ec7e45SBoyan Karatotev 		case 0x01:
147*83ec7e45SBoyan Karatotev 			write_amu_grp1_ctx_reg(ctx, 0x0, read64_amevcntr10());
148*83ec7e45SBoyan Karatotev 			__fallthrough;
149*83ec7e45SBoyan Karatotev 		case 0x00:
150*83ec7e45SBoyan Karatotev 			break;
151*83ec7e45SBoyan Karatotev 		default:
152*83ec7e45SBoyan Karatotev 			assert(0); /* something is wrong */
153f3ccf036SAlexei Fedorov 		}
154*83ec7e45SBoyan Karatotev 	}
1551fd685a7SChris Kay 
15640daecc1SAntonio Nino Diaz 	return (void *)0;
157b6eb3932SDimitris Papastamos }
158b6eb3932SDimitris Papastamos 
159b6eb3932SDimitris Papastamos static void *amu_context_restore(const void *arg)
160b6eb3932SDimitris Papastamos {
161b57e16a4SAndre Przywara 	if (!is_feat_amu_supported()) {
162e747a59bSChris Kay 		return (void *)0;
163e747a59bSChris Kay 	}
164e747a59bSChris Kay 
165*83ec7e45SBoyan Karatotev 	unsigned int core_pos = *(unsigned int *)arg;
166*83ec7e45SBoyan Karatotev 	amu_regs_t *ctx = &amu_ctx[core_pos];
167e747a59bSChris Kay 
168*83ec7e45SBoyan Karatotev 	write64_amevcntr00(read_amu_grp0_ctx_reg(ctx, 0));
169*83ec7e45SBoyan Karatotev 	write64_amevcntr01(read_amu_grp0_ctx_reg(ctx, 1));
170*83ec7e45SBoyan Karatotev 	write64_amevcntr02(read_amu_grp0_ctx_reg(ctx, 2));
171*83ec7e45SBoyan Karatotev 	write64_amevcntr03(read_amu_grp0_ctx_reg(ctx, 3));
172e747a59bSChris Kay 
173*83ec7e45SBoyan Karatotev 	if (is_feat_amu_aux_supported()) {
174*83ec7e45SBoyan Karatotev 		uint8_t num_counters = read_amcgcr_cg1nc();
175e747a59bSChris Kay 
176*83ec7e45SBoyan Karatotev 		switch (num_counters) {
177*83ec7e45SBoyan Karatotev 		case 0x10:
178*83ec7e45SBoyan Karatotev 			write64_amevcntr1f(read_amu_grp1_ctx_reg(ctx, 0xf));
179*83ec7e45SBoyan Karatotev 			__fallthrough;
180*83ec7e45SBoyan Karatotev 		case 0x0f:
181*83ec7e45SBoyan Karatotev 			write64_amevcntr1e(read_amu_grp1_ctx_reg(ctx, 0xe));
182*83ec7e45SBoyan Karatotev 			__fallthrough;
183*83ec7e45SBoyan Karatotev 		case 0x0e:
184*83ec7e45SBoyan Karatotev 			write64_amevcntr1d(read_amu_grp1_ctx_reg(ctx, 0xd));
185*83ec7e45SBoyan Karatotev 			__fallthrough;
186*83ec7e45SBoyan Karatotev 		case 0x0d:
187*83ec7e45SBoyan Karatotev 			write64_amevcntr1c(read_amu_grp1_ctx_reg(ctx, 0xc));
188*83ec7e45SBoyan Karatotev 			__fallthrough;
189*83ec7e45SBoyan Karatotev 		case 0x0c:
190*83ec7e45SBoyan Karatotev 			write64_amevcntr1b(read_amu_grp1_ctx_reg(ctx, 0xb));
191*83ec7e45SBoyan Karatotev 			__fallthrough;
192*83ec7e45SBoyan Karatotev 		case 0x0b:
193*83ec7e45SBoyan Karatotev 			write64_amevcntr1a(read_amu_grp1_ctx_reg(ctx, 0xa));
194*83ec7e45SBoyan Karatotev 			__fallthrough;
195*83ec7e45SBoyan Karatotev 		case 0x0a:
196*83ec7e45SBoyan Karatotev 			write64_amevcntr19(read_amu_grp1_ctx_reg(ctx, 0x9));
197*83ec7e45SBoyan Karatotev 			__fallthrough;
198*83ec7e45SBoyan Karatotev 		case 0x09:
199*83ec7e45SBoyan Karatotev 			write64_amevcntr18(read_amu_grp1_ctx_reg(ctx, 0x8));
200*83ec7e45SBoyan Karatotev 			__fallthrough;
201*83ec7e45SBoyan Karatotev 		case 0x08:
202*83ec7e45SBoyan Karatotev 			write64_amevcntr17(read_amu_grp1_ctx_reg(ctx, 0x7));
203*83ec7e45SBoyan Karatotev 			__fallthrough;
204*83ec7e45SBoyan Karatotev 		case 0x07:
205*83ec7e45SBoyan Karatotev 			write64_amevcntr16(read_amu_grp1_ctx_reg(ctx, 0x6));
206*83ec7e45SBoyan Karatotev 			__fallthrough;
207*83ec7e45SBoyan Karatotev 		case 0x06:
208*83ec7e45SBoyan Karatotev 			write64_amevcntr15(read_amu_grp1_ctx_reg(ctx, 0x5));
209*83ec7e45SBoyan Karatotev 			__fallthrough;
210*83ec7e45SBoyan Karatotev 		case 0x05:
211*83ec7e45SBoyan Karatotev 			write64_amevcntr14(read_amu_grp1_ctx_reg(ctx, 0x4));
212*83ec7e45SBoyan Karatotev 			__fallthrough;
213*83ec7e45SBoyan Karatotev 		case 0x04:
214*83ec7e45SBoyan Karatotev 			write64_amevcntr13(read_amu_grp1_ctx_reg(ctx, 0x3));
215*83ec7e45SBoyan Karatotev 			__fallthrough;
216*83ec7e45SBoyan Karatotev 		case 0x03:
217*83ec7e45SBoyan Karatotev 			write64_amevcntr12(read_amu_grp1_ctx_reg(ctx, 0x2));
218*83ec7e45SBoyan Karatotev 			__fallthrough;
219*83ec7e45SBoyan Karatotev 		case 0x02:
220*83ec7e45SBoyan Karatotev 			write64_amevcntr11(read_amu_grp1_ctx_reg(ctx, 0x1));
221*83ec7e45SBoyan Karatotev 			__fallthrough;
222*83ec7e45SBoyan Karatotev 		case 0x01:
223*83ec7e45SBoyan Karatotev 			write64_amevcntr10(read_amu_grp1_ctx_reg(ctx, 0x0));
224*83ec7e45SBoyan Karatotev 			__fallthrough;
225*83ec7e45SBoyan Karatotev 		case 0x00:
226*83ec7e45SBoyan Karatotev 			break;
227*83ec7e45SBoyan Karatotev 		default:
228*83ec7e45SBoyan Karatotev 			assert(0); /* something is wrong */
229*83ec7e45SBoyan Karatotev 		}
230e747a59bSChris Kay 	}
231e747a59bSChris Kay 
232e747a59bSChris Kay 
233*83ec7e45SBoyan Karatotev 	/* now enable them again */
234*83ec7e45SBoyan Karatotev 	write_amcntenset0(AMCNTENSET0_Pn_MASK);
235*83ec7e45SBoyan Karatotev 	if (is_feat_amu_aux_supported()) {
236*83ec7e45SBoyan Karatotev 		write_amcntenset1(get_amu_aux_enables(core_pos));
237f3ccf036SAlexei Fedorov 	}
238b6eb3932SDimitris Papastamos 
239*83ec7e45SBoyan Karatotev 	isb();
24040daecc1SAntonio Nino Diaz 	return (void *)0;
241b6eb3932SDimitris Papastamos }
242b6eb3932SDimitris Papastamos 
243b6eb3932SDimitris Papastamos SUBSCRIBE_TO_EVENT(psci_suspend_pwrdown_start, amu_context_save);
244b6eb3932SDimitris Papastamos SUBSCRIBE_TO_EVENT(psci_suspend_pwrdown_finish, amu_context_restore);
245