xref: /rk3399_ARM-atf/lib/extensions/amu/aarch32/amu.c (revision 1fd685a74dd33c9c26a0ec0e82e7a5a378461362)
1ef69e1eaSDimitris Papastamos /*
2873d4241Sjohpow01  * Copyright (c) 2017-2021, 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>
12ef69e1eaSDimitris Papastamos #include <arch_helpers.h>
13f3ccf036SAlexei Fedorov 
1409d40e0eSAntonio Nino Diaz #include <lib/el3_runtime/pubsub_events.h>
1509d40e0eSAntonio Nino Diaz #include <lib/extensions/amu.h>
1609d40e0eSAntonio Nino Diaz #include <lib/extensions/amu_private.h>
17f3ccf036SAlexei Fedorov 
1809d40e0eSAntonio Nino Diaz #include <plat/common/platform.h>
19b6eb3932SDimitris Papastamos 
20b6eb3932SDimitris Papastamos static struct amu_ctx amu_ctxs[PLATFORM_CORE_COUNT];
21ef69e1eaSDimitris Papastamos 
2233b9be6dSChris Kay static inline __unused uint32_t read_id_pfr0_amu(void)
23ef69e1eaSDimitris Papastamos {
2433b9be6dSChris Kay 	return (read_id_pfr0() >> ID_PFR0_AMU_SHIFT) &
25873d4241Sjohpow01 		ID_PFR0_AMU_MASK;
26c70da546SJoel Hutton }
27c70da546SJoel Hutton 
2833b9be6dSChris Kay static inline __unused void write_hcptr_tam(uint32_t value)
2933b9be6dSChris Kay {
3033b9be6dSChris Kay 	write_hcptr((read_hcptr() & ~TAM_BIT) |
3133b9be6dSChris Kay 		((value << TAM_SHIFT) & TAM_BIT));
3233b9be6dSChris Kay }
3333b9be6dSChris Kay 
3433b9be6dSChris Kay static inline __unused void write_amcr_cg1rz(uint32_t value)
3533b9be6dSChris Kay {
3633b9be6dSChris Kay 	write_amcr((read_amcr() & ~AMCR_CG1RZ_BIT) |
3733b9be6dSChris Kay 		((value << AMCR_CG1RZ_SHIFT) & AMCR_CG1RZ_BIT));
3833b9be6dSChris Kay }
3933b9be6dSChris Kay 
4033b9be6dSChris Kay static inline __unused uint32_t read_amcfgr_ncg(void)
4133b9be6dSChris Kay {
4233b9be6dSChris Kay 	return (read_amcfgr() >> AMCFGR_NCG_SHIFT) &
4333b9be6dSChris Kay 		AMCFGR_NCG_MASK;
4433b9be6dSChris Kay }
4533b9be6dSChris Kay 
4633b9be6dSChris Kay static inline __unused uint32_t read_amcgcr_cg1nc(void)
4733b9be6dSChris Kay {
4833b9be6dSChris Kay 	return (read_amcgcr() >> AMCGCR_CG1NC_SHIFT) &
4933b9be6dSChris Kay 		AMCGCR_CG1NC_MASK;
5033b9be6dSChris Kay }
5133b9be6dSChris Kay 
5233b9be6dSChris Kay static inline __unused uint32_t read_amcntenset0_px(void)
5333b9be6dSChris Kay {
5433b9be6dSChris Kay 	return (read_amcntenset0() >> AMCNTENSET0_Pn_SHIFT) &
5533b9be6dSChris Kay 		AMCNTENSET0_Pn_MASK;
5633b9be6dSChris Kay }
5733b9be6dSChris Kay 
5833b9be6dSChris Kay static inline __unused uint32_t read_amcntenset1_px(void)
5933b9be6dSChris Kay {
6033b9be6dSChris Kay 	return (read_amcntenset1() >> AMCNTENSET1_Pn_SHIFT) &
6133b9be6dSChris Kay 		AMCNTENSET1_Pn_MASK;
6233b9be6dSChris Kay }
6333b9be6dSChris Kay 
6433b9be6dSChris Kay static inline __unused void write_amcntenset0_px(uint32_t px)
6533b9be6dSChris Kay {
6633b9be6dSChris Kay 	uint32_t value = read_amcntenset0();
6733b9be6dSChris Kay 
6833b9be6dSChris Kay 	value &= ~AMCNTENSET0_Pn_MASK;
6933b9be6dSChris Kay 	value |= (px << AMCNTENSET0_Pn_SHIFT) &
7033b9be6dSChris Kay 		AMCNTENSET0_Pn_MASK;
7133b9be6dSChris Kay 
7233b9be6dSChris Kay 	write_amcntenset0(value);
7333b9be6dSChris Kay }
7433b9be6dSChris Kay 
7533b9be6dSChris Kay static inline __unused void write_amcntenset1_px(uint32_t px)
7633b9be6dSChris Kay {
7733b9be6dSChris Kay 	uint32_t value = read_amcntenset1();
7833b9be6dSChris Kay 
7933b9be6dSChris Kay 	value &= ~AMCNTENSET1_Pn_MASK;
8033b9be6dSChris Kay 	value |= (px << AMCNTENSET1_Pn_SHIFT) &
8133b9be6dSChris Kay 		AMCNTENSET1_Pn_MASK;
8233b9be6dSChris Kay 
8333b9be6dSChris Kay 	write_amcntenset1(value);
8433b9be6dSChris Kay }
8533b9be6dSChris Kay 
8633b9be6dSChris Kay static inline __unused void write_amcntenclr0_px(uint32_t px)
8733b9be6dSChris Kay {
8833b9be6dSChris Kay 	uint32_t value = read_amcntenclr0();
8933b9be6dSChris Kay 
9033b9be6dSChris Kay 	value &= ~AMCNTENCLR0_Pn_MASK;
9133b9be6dSChris Kay 	value |= (px << AMCNTENCLR0_Pn_SHIFT) & AMCNTENCLR0_Pn_MASK;
9233b9be6dSChris Kay 
9333b9be6dSChris Kay 	write_amcntenclr0(value);
9433b9be6dSChris Kay }
9533b9be6dSChris Kay 
9633b9be6dSChris Kay static inline __unused void write_amcntenclr1_px(uint32_t px)
9733b9be6dSChris Kay {
9833b9be6dSChris Kay 	uint32_t value = read_amcntenclr1();
9933b9be6dSChris Kay 
10033b9be6dSChris Kay 	value &= ~AMCNTENCLR1_Pn_MASK;
10133b9be6dSChris Kay 	value |= (px << AMCNTENCLR1_Pn_SHIFT) & AMCNTENCLR1_Pn_MASK;
10233b9be6dSChris Kay 
10333b9be6dSChris Kay 	write_amcntenclr1(value);
10433b9be6dSChris Kay }
10533b9be6dSChris Kay 
10633b9be6dSChris Kay static bool amu_supported(void)
10733b9be6dSChris Kay {
10833b9be6dSChris Kay 	return read_id_pfr0_amu() >= ID_PFR0_AMU_V1;
10933b9be6dSChris Kay }
11033b9be6dSChris Kay 
11133b9be6dSChris Kay static bool amu_v1p1_supported(void)
11233b9be6dSChris Kay {
11333b9be6dSChris Kay 	return read_id_pfr0_amu() >= ID_PFR0_AMU_V1P1;
11433b9be6dSChris Kay }
11533b9be6dSChris Kay 
11633b9be6dSChris Kay #if ENABLE_AMU_AUXILIARY_COUNTERS
117b4b726eaSChris Kay static bool amu_group1_supported(void)
118f3ccf036SAlexei Fedorov {
11933b9be6dSChris Kay 	return read_amcfgr_ncg() > 0U;
120f3ccf036SAlexei Fedorov }
121f3ccf036SAlexei Fedorov #endif
122f3ccf036SAlexei Fedorov 
123f3ccf036SAlexei Fedorov /*
124f3ccf036SAlexei Fedorov  * Enable counters. This function is meant to be invoked
125f3ccf036SAlexei Fedorov  * by the context management library before exiting from EL3.
126f3ccf036SAlexei Fedorov  */
12740daecc1SAntonio Nino Diaz void amu_enable(bool el2_unused)
128c70da546SJoel Hutton {
12933b9be6dSChris Kay 	if (!amu_supported()) {
1300767d50eSDimitris Papastamos 		return;
131f3ccf036SAlexei Fedorov 	}
132f3ccf036SAlexei Fedorov 
133*1fd685a7SChris Kay #if ENABLE_AMU_AUXILIARY_COUNTERS
134*1fd685a7SChris Kay 	if (AMU_GROUP1_NR_COUNTERS > 0U) {
135f3ccf036SAlexei Fedorov 		/* Check and set presence of group 1 counters */
136f3ccf036SAlexei Fedorov 		if (!amu_group1_supported()) {
137f3ccf036SAlexei Fedorov 			ERROR("AMU Counter Group 1 is not implemented\n");
138f3ccf036SAlexei Fedorov 			panic();
139f3ccf036SAlexei Fedorov 		}
140f3ccf036SAlexei Fedorov 
141f3ccf036SAlexei Fedorov 		/* Check number of group 1 counters */
14233b9be6dSChris Kay 		uint32_t cnt_num = read_amcgcr_cg1nc();
143*1fd685a7SChris Kay 
144f3ccf036SAlexei Fedorov 		VERBOSE("%s%u. %s%u\n",
145f3ccf036SAlexei Fedorov 			"Number of AMU Group 1 Counters ", cnt_num,
146f3ccf036SAlexei Fedorov 			"Requested number ", AMU_GROUP1_NR_COUNTERS);
147f3ccf036SAlexei Fedorov 
148f3ccf036SAlexei Fedorov 		if (cnt_num < AMU_GROUP1_NR_COUNTERS) {
149f3ccf036SAlexei Fedorov 			ERROR("%s%u is less than %s%u\n",
150f3ccf036SAlexei Fedorov 			"Number of AMU Group 1 Counters ", cnt_num,
151f3ccf036SAlexei Fedorov 			"Requested number ", AMU_GROUP1_NR_COUNTERS);
152f3ccf036SAlexei Fedorov 			panic();
153f3ccf036SAlexei Fedorov 		}
154*1fd685a7SChris Kay 	}
155f3ccf036SAlexei Fedorov #endif
1560767d50eSDimitris Papastamos 
157ef69e1eaSDimitris Papastamos 	if (el2_unused) {
158ef69e1eaSDimitris Papastamos 		/*
159ef69e1eaSDimitris Papastamos 		 * Non-secure access from EL0 or EL1 to the Activity Monitor
160ef69e1eaSDimitris Papastamos 		 * registers do not trap to EL2.
161ef69e1eaSDimitris Papastamos 		 */
16233b9be6dSChris Kay 		write_hcptr_tam(0U);
163ef69e1eaSDimitris Papastamos 	}
164ef69e1eaSDimitris Papastamos 
165ef69e1eaSDimitris Papastamos 	/* Enable group 0 counters */
16633b9be6dSChris Kay 	write_amcntenset0_px(AMU_GROUP0_COUNTERS_MASK);
167c70da546SJoel Hutton 
168*1fd685a7SChris Kay #if ENABLE_AMU_AUXILIARY_COUNTERS
169*1fd685a7SChris Kay 	if (AMU_GROUP1_NR_COUNTERS > 0U) {
170c70da546SJoel Hutton 		/* Enable group 1 counters */
17133b9be6dSChris Kay 		write_amcntenset1_px(AMU_GROUP1_COUNTERS_MASK);
172*1fd685a7SChris Kay 	}
173f3ccf036SAlexei Fedorov #endif
174873d4241Sjohpow01 
175873d4241Sjohpow01 	/* Initialize FEAT_AMUv1p1 features if present. */
17633b9be6dSChris Kay 	if (!amu_v1p1_supported()) {
177873d4241Sjohpow01 		return;
178873d4241Sjohpow01 	}
179873d4241Sjohpow01 
180873d4241Sjohpow01 #if AMU_RESTRICT_COUNTERS
181873d4241Sjohpow01 	/*
182873d4241Sjohpow01 	 * FEAT_AMUv1p1 adds a register field to restrict access to group 1
183873d4241Sjohpow01 	 * counters at all but the highest implemented EL.  This is controlled
184873d4241Sjohpow01 	 * with the AMU_RESTRICT_COUNTERS compile time flag, when set, system
185873d4241Sjohpow01 	 * register reads at lower ELs return zero.  Reads from the memory
186873d4241Sjohpow01 	 * mapped view are unaffected.
187873d4241Sjohpow01 	 */
188873d4241Sjohpow01 	VERBOSE("AMU group 1 counter access restricted.\n");
18933b9be6dSChris Kay 	write_amcr_cg1rz(1U);
190873d4241Sjohpow01 #else
19133b9be6dSChris Kay 	write_amcr_cg1rz(0U);
192873d4241Sjohpow01 #endif
193c70da546SJoel Hutton }
194c70da546SJoel Hutton 
195c70da546SJoel Hutton /* Read the group 0 counter identified by the given `idx`. */
196b4b726eaSChris Kay static uint64_t amu_group0_cnt_read(unsigned int idx)
197c70da546SJoel Hutton {
19833b9be6dSChris Kay 	assert(amu_supported());
199f3ccf036SAlexei Fedorov 	assert(idx < AMU_GROUP0_NR_COUNTERS);
200c70da546SJoel Hutton 
201c70da546SJoel Hutton 	return amu_group0_cnt_read_internal(idx);
202c70da546SJoel Hutton }
203c70da546SJoel Hutton 
204f3ccf036SAlexei Fedorov /* Write the group 0 counter identified by the given `idx` with `val` */
205b4b726eaSChris Kay static void amu_group0_cnt_write(unsigned  int idx, uint64_t val)
206c70da546SJoel Hutton {
20733b9be6dSChris Kay 	assert(amu_supported());
208f3ccf036SAlexei Fedorov 	assert(idx < AMU_GROUP0_NR_COUNTERS);
209c70da546SJoel Hutton 
210c70da546SJoel Hutton 	amu_group0_cnt_write_internal(idx, val);
211c70da546SJoel Hutton 	isb();
212c70da546SJoel Hutton }
213c70da546SJoel Hutton 
214*1fd685a7SChris Kay #if ENABLE_AMU_AUXILIARY_COUNTERS
215f3ccf036SAlexei Fedorov /* Read the group 1 counter identified by the given `idx` */
216b4b726eaSChris Kay static uint64_t amu_group1_cnt_read(unsigned  int idx)
217c70da546SJoel Hutton {
21833b9be6dSChris Kay 	assert(amu_supported());
219f3ccf036SAlexei Fedorov 	assert(amu_group1_supported());
220f3ccf036SAlexei Fedorov 	assert(idx < AMU_GROUP1_NR_COUNTERS);
221c70da546SJoel Hutton 
222c70da546SJoel Hutton 	return amu_group1_cnt_read_internal(idx);
223c70da546SJoel Hutton }
224c70da546SJoel Hutton 
225f3ccf036SAlexei Fedorov /* Write the group 1 counter identified by the given `idx` with `val` */
226b4b726eaSChris Kay static void amu_group1_cnt_write(unsigned  int idx, uint64_t val)
227c70da546SJoel Hutton {
22833b9be6dSChris Kay 	assert(amu_supported());
229f3ccf036SAlexei Fedorov 	assert(amu_group1_supported());
230f3ccf036SAlexei Fedorov 	assert(idx < AMU_GROUP1_NR_COUNTERS);
231c70da546SJoel Hutton 
232c70da546SJoel Hutton 	amu_group1_cnt_write_internal(idx, val);
233c70da546SJoel Hutton 	isb();
234c70da546SJoel Hutton }
235*1fd685a7SChris Kay #endif
236b6eb3932SDimitris Papastamos 
237b6eb3932SDimitris Papastamos static void *amu_context_save(const void *arg)
238b6eb3932SDimitris Papastamos {
239f3ccf036SAlexei Fedorov 	struct amu_ctx *ctx = &amu_ctxs[plat_my_core_pos()];
240f3ccf036SAlexei Fedorov 	unsigned int i;
241b6eb3932SDimitris Papastamos 
24233b9be6dSChris Kay 	if (!amu_supported()) {
243b6eb3932SDimitris Papastamos 		return (void *)-1;
244f3ccf036SAlexei Fedorov 	}
245b6eb3932SDimitris Papastamos 
246*1fd685a7SChris Kay #if ENABLE_AMU_AUXILIARY_COUNTERS
247*1fd685a7SChris Kay 	if (AMU_GROUP1_NR_COUNTERS > 0U) {
248f3ccf036SAlexei Fedorov 		if (!amu_group1_supported()) {
249f3ccf036SAlexei Fedorov 			return (void *)-1;
250f3ccf036SAlexei Fedorov 		}
251*1fd685a7SChris Kay 	}
252f3ccf036SAlexei Fedorov #endif
253*1fd685a7SChris Kay 
254f3ccf036SAlexei Fedorov 	/* Assert that group 0/1 counter configuration is what we expect */
25533b9be6dSChris Kay 	assert(read_amcntenset0_px() == AMU_GROUP0_COUNTERS_MASK);
256b6eb3932SDimitris Papastamos 
257*1fd685a7SChris Kay #if ENABLE_AMU_AUXILIARY_COUNTERS
258*1fd685a7SChris Kay 	if (AMU_GROUP1_NR_COUNTERS > 0U) {
25933b9be6dSChris Kay 		assert(read_amcntenset1_px() == AMU_GROUP1_COUNTERS_MASK);
260*1fd685a7SChris Kay 	}
261f3ccf036SAlexei Fedorov #endif
262b6eb3932SDimitris Papastamos 	/*
263f3ccf036SAlexei Fedorov 	 * Disable group 0/1 counters to avoid other observers like SCP sampling
264b6eb3932SDimitris Papastamos 	 * counter values from the future via the memory mapped view.
265b6eb3932SDimitris Papastamos 	 */
26633b9be6dSChris Kay 	write_amcntenclr0_px(AMU_GROUP0_COUNTERS_MASK);
267f3ccf036SAlexei Fedorov 
268*1fd685a7SChris Kay #if ENABLE_AMU_AUXILIARY_COUNTERS
269*1fd685a7SChris Kay 	if (AMU_GROUP1_NR_COUNTERS > 0U) {
27033b9be6dSChris Kay 		write_amcntenclr1_px(AMU_GROUP1_COUNTERS_MASK);
271*1fd685a7SChris Kay 	}
272f3ccf036SAlexei Fedorov #endif
273*1fd685a7SChris Kay 
274b6eb3932SDimitris Papastamos 	isb();
275b6eb3932SDimitris Papastamos 
276f3ccf036SAlexei Fedorov 	/* Save all group 0 counters */
277f3ccf036SAlexei Fedorov 	for (i = 0U; i < AMU_GROUP0_NR_COUNTERS; i++) {
278c70da546SJoel Hutton 		ctx->group0_cnts[i] = amu_group0_cnt_read(i);
279f3ccf036SAlexei Fedorov 	}
280c70da546SJoel Hutton 
281*1fd685a7SChris Kay #if ENABLE_AMU_AUXILIARY_COUNTERS
282*1fd685a7SChris Kay 	if (AMU_GROUP1_NR_COUNTERS > 0U) {
283f3ccf036SAlexei Fedorov 		/* Save group 1 counters */
284f3ccf036SAlexei Fedorov 		for (i = 0U; i < AMU_GROUP1_NR_COUNTERS; i++) {
285f3ccf036SAlexei Fedorov 			if ((AMU_GROUP1_COUNTERS_MASK & (1U << i)) != 0U) {
286c70da546SJoel Hutton 				ctx->group1_cnts[i] = amu_group1_cnt_read(i);
287f3ccf036SAlexei Fedorov 			}
288f3ccf036SAlexei Fedorov 		}
289*1fd685a7SChris Kay 	}
290f3ccf036SAlexei Fedorov #endif
291*1fd685a7SChris Kay 
29240daecc1SAntonio Nino Diaz 	return (void *)0;
293b6eb3932SDimitris Papastamos }
294b6eb3932SDimitris Papastamos 
295b6eb3932SDimitris Papastamos static void *amu_context_restore(const void *arg)
296b6eb3932SDimitris Papastamos {
297f3ccf036SAlexei Fedorov 	struct amu_ctx *ctx = &amu_ctxs[plat_my_core_pos()];
298f3ccf036SAlexei Fedorov 	unsigned int i;
299b6eb3932SDimitris Papastamos 
30033b9be6dSChris Kay 	if (!amu_supported()) {
301b6eb3932SDimitris Papastamos 		return (void *)-1;
302f3ccf036SAlexei Fedorov 	}
303b6eb3932SDimitris Papastamos 
304*1fd685a7SChris Kay #if ENABLE_AMU_AUXILIARY_COUNTERS
305*1fd685a7SChris Kay 	if (AMU_GROUP1_NR_COUNTERS > 0U) {
306*1fd685a7SChris Kay 		if (!amu_group1_supported()) {
307f3ccf036SAlexei Fedorov 			return (void *)-1;
308f3ccf036SAlexei Fedorov 		}
309*1fd685a7SChris Kay 	}
310f3ccf036SAlexei Fedorov #endif
311*1fd685a7SChris Kay 
312b6eb3932SDimitris Papastamos 	/* Counters were disabled in `amu_context_save()` */
31333b9be6dSChris Kay 	assert(read_amcntenset0_px() == 0U);
314b6eb3932SDimitris Papastamos 
315*1fd685a7SChris Kay #if ENABLE_AMU_AUXILIARY_COUNTERS
316*1fd685a7SChris Kay 	if (AMU_GROUP1_NR_COUNTERS > 0U) {
31733b9be6dSChris Kay 		assert(read_amcntenset1_px() == 0U);
318*1fd685a7SChris Kay 	}
319f3ccf036SAlexei Fedorov #endif
320f3ccf036SAlexei Fedorov 
321f3ccf036SAlexei Fedorov 	/* Restore all group 0 counters */
322f3ccf036SAlexei Fedorov 	for (i = 0U; i < AMU_GROUP0_NR_COUNTERS; i++) {
323c70da546SJoel Hutton 		amu_group0_cnt_write(i, ctx->group0_cnts[i]);
324f3ccf036SAlexei Fedorov 	}
325b6eb3932SDimitris Papastamos 
326f3ccf036SAlexei Fedorov 	/* Restore group 0 counter configuration */
32733b9be6dSChris Kay 	write_amcntenset0_px(AMU_GROUP0_COUNTERS_MASK);
328b6eb3932SDimitris Papastamos 
329*1fd685a7SChris Kay #if ENABLE_AMU_AUXILIARY_COUNTERS
330*1fd685a7SChris Kay 	if (AMU_GROUP1_NR_COUNTERS > 0U) {
331f3ccf036SAlexei Fedorov 		/* Restore group 1 counters */
332f3ccf036SAlexei Fedorov 		for (i = 0U; i < AMU_GROUP1_NR_COUNTERS; i++) {
333f3ccf036SAlexei Fedorov 			if ((AMU_GROUP1_COUNTERS_MASK & (1U << i)) != 0U) {
334f3ccf036SAlexei Fedorov 				amu_group1_cnt_write(i, ctx->group1_cnts[i]);
335f3ccf036SAlexei Fedorov 			}
336f3ccf036SAlexei Fedorov 		}
337f3ccf036SAlexei Fedorov 
338f3ccf036SAlexei Fedorov 		/* Restore group 1 counter configuration */
33933b9be6dSChris Kay 		write_amcntenset1_px(AMU_GROUP1_COUNTERS_MASK);
340*1fd685a7SChris Kay 	}
341f3ccf036SAlexei Fedorov #endif
342f3ccf036SAlexei Fedorov 
34340daecc1SAntonio Nino Diaz 	return (void *)0;
344b6eb3932SDimitris Papastamos }
345b6eb3932SDimitris Papastamos 
346b6eb3932SDimitris Papastamos SUBSCRIBE_TO_EVENT(psci_suspend_pwrdown_start, amu_context_save);
347b6eb3932SDimitris Papastamos SUBSCRIBE_TO_EVENT(psci_suspend_pwrdown_finish, amu_context_restore);
348