xref: /rk3399_ARM-atf/lib/extensions/amu/aarch32/amu.c (revision 31d3cc2570dd61ac30efab030708ef32fcc987e5)
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 
4681e2ff1fSChris Kay static inline __unused uint32_t read_amcgcr_cg0nc(void)
4781e2ff1fSChris Kay {
4881e2ff1fSChris Kay 	return (read_amcgcr() >> AMCGCR_CG0NC_SHIFT) &
4981e2ff1fSChris Kay 		AMCGCR_CG0NC_MASK;
5081e2ff1fSChris Kay }
5181e2ff1fSChris Kay 
5233b9be6dSChris Kay static inline __unused uint32_t read_amcgcr_cg1nc(void)
5333b9be6dSChris Kay {
5433b9be6dSChris Kay 	return (read_amcgcr() >> AMCGCR_CG1NC_SHIFT) &
5533b9be6dSChris Kay 		AMCGCR_CG1NC_MASK;
5633b9be6dSChris Kay }
5733b9be6dSChris Kay 
5833b9be6dSChris Kay static inline __unused uint32_t read_amcntenset0_px(void)
5933b9be6dSChris Kay {
6033b9be6dSChris Kay 	return (read_amcntenset0() >> AMCNTENSET0_Pn_SHIFT) &
6133b9be6dSChris Kay 		AMCNTENSET0_Pn_MASK;
6233b9be6dSChris Kay }
6333b9be6dSChris Kay 
6433b9be6dSChris Kay static inline __unused uint32_t read_amcntenset1_px(void)
6533b9be6dSChris Kay {
6633b9be6dSChris Kay 	return (read_amcntenset1() >> AMCNTENSET1_Pn_SHIFT) &
6733b9be6dSChris Kay 		AMCNTENSET1_Pn_MASK;
6833b9be6dSChris Kay }
6933b9be6dSChris Kay 
7033b9be6dSChris Kay static inline __unused void write_amcntenset0_px(uint32_t px)
7133b9be6dSChris Kay {
7233b9be6dSChris Kay 	uint32_t value = read_amcntenset0();
7333b9be6dSChris Kay 
7433b9be6dSChris Kay 	value &= ~AMCNTENSET0_Pn_MASK;
7533b9be6dSChris Kay 	value |= (px << AMCNTENSET0_Pn_SHIFT) &
7633b9be6dSChris Kay 		AMCNTENSET0_Pn_MASK;
7733b9be6dSChris Kay 
7833b9be6dSChris Kay 	write_amcntenset0(value);
7933b9be6dSChris Kay }
8033b9be6dSChris Kay 
8133b9be6dSChris Kay static inline __unused void write_amcntenset1_px(uint32_t px)
8233b9be6dSChris Kay {
8333b9be6dSChris Kay 	uint32_t value = read_amcntenset1();
8433b9be6dSChris Kay 
8533b9be6dSChris Kay 	value &= ~AMCNTENSET1_Pn_MASK;
8633b9be6dSChris Kay 	value |= (px << AMCNTENSET1_Pn_SHIFT) &
8733b9be6dSChris Kay 		AMCNTENSET1_Pn_MASK;
8833b9be6dSChris Kay 
8933b9be6dSChris Kay 	write_amcntenset1(value);
9033b9be6dSChris Kay }
9133b9be6dSChris Kay 
9233b9be6dSChris Kay static inline __unused void write_amcntenclr0_px(uint32_t px)
9333b9be6dSChris Kay {
9433b9be6dSChris Kay 	uint32_t value = read_amcntenclr0();
9533b9be6dSChris Kay 
9633b9be6dSChris Kay 	value &= ~AMCNTENCLR0_Pn_MASK;
9733b9be6dSChris Kay 	value |= (px << AMCNTENCLR0_Pn_SHIFT) & AMCNTENCLR0_Pn_MASK;
9833b9be6dSChris Kay 
9933b9be6dSChris Kay 	write_amcntenclr0(value);
10033b9be6dSChris Kay }
10133b9be6dSChris Kay 
10233b9be6dSChris Kay static inline __unused void write_amcntenclr1_px(uint32_t px)
10333b9be6dSChris Kay {
10433b9be6dSChris Kay 	uint32_t value = read_amcntenclr1();
10533b9be6dSChris Kay 
10633b9be6dSChris Kay 	value &= ~AMCNTENCLR1_Pn_MASK;
10733b9be6dSChris Kay 	value |= (px << AMCNTENCLR1_Pn_SHIFT) & AMCNTENCLR1_Pn_MASK;
10833b9be6dSChris Kay 
10933b9be6dSChris Kay 	write_amcntenclr1(value);
11033b9be6dSChris Kay }
11133b9be6dSChris Kay 
11233b9be6dSChris Kay static bool amu_supported(void)
11333b9be6dSChris Kay {
11433b9be6dSChris Kay 	return read_id_pfr0_amu() >= ID_PFR0_AMU_V1;
11533b9be6dSChris Kay }
11633b9be6dSChris Kay 
11733b9be6dSChris Kay static bool amu_v1p1_supported(void)
11833b9be6dSChris Kay {
11933b9be6dSChris Kay 	return read_id_pfr0_amu() >= ID_PFR0_AMU_V1P1;
12033b9be6dSChris Kay }
12133b9be6dSChris Kay 
12233b9be6dSChris Kay #if ENABLE_AMU_AUXILIARY_COUNTERS
123b4b726eaSChris Kay static bool amu_group1_supported(void)
124f3ccf036SAlexei Fedorov {
12533b9be6dSChris Kay 	return read_amcfgr_ncg() > 0U;
126f3ccf036SAlexei Fedorov }
127f3ccf036SAlexei Fedorov #endif
128f3ccf036SAlexei Fedorov 
129f3ccf036SAlexei Fedorov /*
130f3ccf036SAlexei Fedorov  * Enable counters. This function is meant to be invoked
131f3ccf036SAlexei Fedorov  * by the context management library before exiting from EL3.
132f3ccf036SAlexei Fedorov  */
13340daecc1SAntonio Nino Diaz void amu_enable(bool el2_unused)
134c70da546SJoel Hutton {
13533b9be6dSChris Kay 	if (!amu_supported()) {
1360767d50eSDimitris Papastamos 		return;
137f3ccf036SAlexei Fedorov 	}
138f3ccf036SAlexei Fedorov 
139ef69e1eaSDimitris Papastamos 	if (el2_unused) {
140ef69e1eaSDimitris Papastamos 		/*
141ef69e1eaSDimitris Papastamos 		 * Non-secure access from EL0 or EL1 to the Activity Monitor
142ef69e1eaSDimitris Papastamos 		 * registers do not trap to EL2.
143ef69e1eaSDimitris Papastamos 		 */
14433b9be6dSChris Kay 		write_hcptr_tam(0U);
145ef69e1eaSDimitris Papastamos 	}
146ef69e1eaSDimitris Papastamos 
147ef69e1eaSDimitris Papastamos 	/* Enable group 0 counters */
14881e2ff1fSChris Kay 	write_amcntenset0_px((UINT32_C(1) << read_amcgcr_cg0nc()) - 1U);
149c70da546SJoel Hutton 
1501fd685a7SChris Kay #if ENABLE_AMU_AUXILIARY_COUNTERS
151*31d3cc25SChris Kay 	if (amu_group1_supported()) {
152c70da546SJoel Hutton 		/* Enable group 1 counters */
15333b9be6dSChris Kay 		write_amcntenset1_px(AMU_GROUP1_COUNTERS_MASK);
1541fd685a7SChris Kay 	}
155f3ccf036SAlexei Fedorov #endif
156873d4241Sjohpow01 
157873d4241Sjohpow01 	/* Initialize FEAT_AMUv1p1 features if present. */
15833b9be6dSChris Kay 	if (!amu_v1p1_supported()) {
159873d4241Sjohpow01 		return;
160873d4241Sjohpow01 	}
161873d4241Sjohpow01 
162873d4241Sjohpow01 #if AMU_RESTRICT_COUNTERS
163873d4241Sjohpow01 	/*
164873d4241Sjohpow01 	 * FEAT_AMUv1p1 adds a register field to restrict access to group 1
165873d4241Sjohpow01 	 * counters at all but the highest implemented EL.  This is controlled
166873d4241Sjohpow01 	 * with the AMU_RESTRICT_COUNTERS compile time flag, when set, system
167873d4241Sjohpow01 	 * register reads at lower ELs return zero.  Reads from the memory
168873d4241Sjohpow01 	 * mapped view are unaffected.
169873d4241Sjohpow01 	 */
170873d4241Sjohpow01 	VERBOSE("AMU group 1 counter access restricted.\n");
17133b9be6dSChris Kay 	write_amcr_cg1rz(1U);
172873d4241Sjohpow01 #else
17333b9be6dSChris Kay 	write_amcr_cg1rz(0U);
174873d4241Sjohpow01 #endif
175c70da546SJoel Hutton }
176c70da546SJoel Hutton 
177c70da546SJoel Hutton /* Read the group 0 counter identified by the given `idx`. */
178b4b726eaSChris Kay static uint64_t amu_group0_cnt_read(unsigned int idx)
179c70da546SJoel Hutton {
18033b9be6dSChris Kay 	assert(amu_supported());
18181e2ff1fSChris Kay 	assert(idx < read_amcgcr_cg0nc());
182c70da546SJoel Hutton 
183c70da546SJoel Hutton 	return amu_group0_cnt_read_internal(idx);
184c70da546SJoel Hutton }
185c70da546SJoel Hutton 
186f3ccf036SAlexei Fedorov /* Write the group 0 counter identified by the given `idx` with `val` */
187b4b726eaSChris Kay static void amu_group0_cnt_write(unsigned  int idx, uint64_t val)
188c70da546SJoel Hutton {
18933b9be6dSChris Kay 	assert(amu_supported());
19081e2ff1fSChris Kay 	assert(idx < read_amcgcr_cg0nc());
191c70da546SJoel Hutton 
192c70da546SJoel Hutton 	amu_group0_cnt_write_internal(idx, val);
193c70da546SJoel Hutton 	isb();
194c70da546SJoel Hutton }
195c70da546SJoel Hutton 
1961fd685a7SChris Kay #if ENABLE_AMU_AUXILIARY_COUNTERS
197f3ccf036SAlexei Fedorov /* Read the group 1 counter identified by the given `idx` */
198b4b726eaSChris Kay static uint64_t amu_group1_cnt_read(unsigned  int idx)
199c70da546SJoel Hutton {
20033b9be6dSChris Kay 	assert(amu_supported());
201f3ccf036SAlexei Fedorov 	assert(amu_group1_supported());
202*31d3cc25SChris Kay 	assert(idx < read_amcgcr_cg1nc());
203c70da546SJoel Hutton 
204c70da546SJoel Hutton 	return amu_group1_cnt_read_internal(idx);
205c70da546SJoel Hutton }
206c70da546SJoel Hutton 
207f3ccf036SAlexei Fedorov /* Write the group 1 counter identified by the given `idx` with `val` */
208b4b726eaSChris Kay static void amu_group1_cnt_write(unsigned  int idx, uint64_t val)
209c70da546SJoel Hutton {
21033b9be6dSChris Kay 	assert(amu_supported());
211f3ccf036SAlexei Fedorov 	assert(amu_group1_supported());
212*31d3cc25SChris Kay 	assert(idx < read_amcgcr_cg1nc());
213c70da546SJoel Hutton 
214c70da546SJoel Hutton 	amu_group1_cnt_write_internal(idx, val);
215c70da546SJoel Hutton 	isb();
216c70da546SJoel Hutton }
2171fd685a7SChris Kay #endif
218b6eb3932SDimitris Papastamos 
219b6eb3932SDimitris Papastamos static void *amu_context_save(const void *arg)
220b6eb3932SDimitris Papastamos {
221f3ccf036SAlexei Fedorov 	struct amu_ctx *ctx = &amu_ctxs[plat_my_core_pos()];
222f3ccf036SAlexei Fedorov 	unsigned int i;
223b6eb3932SDimitris Papastamos 
22433b9be6dSChris Kay 	if (!amu_supported()) {
225b6eb3932SDimitris Papastamos 		return (void *)-1;
226f3ccf036SAlexei Fedorov 	}
227b6eb3932SDimitris Papastamos 
228f3ccf036SAlexei Fedorov 	/* Assert that group 0/1 counter configuration is what we expect */
22981e2ff1fSChris Kay 	assert(read_amcntenset0_px() ==
23081e2ff1fSChris Kay 		((UINT32_C(1) << read_amcgcr_cg0nc()) - 1U));
231b6eb3932SDimitris Papastamos 
2321fd685a7SChris Kay #if ENABLE_AMU_AUXILIARY_COUNTERS
233*31d3cc25SChris Kay 	if (amu_group1_supported()) {
23433b9be6dSChris Kay 		assert(read_amcntenset1_px() == AMU_GROUP1_COUNTERS_MASK);
2351fd685a7SChris Kay 	}
236f3ccf036SAlexei Fedorov #endif
237b6eb3932SDimitris Papastamos 	/*
238f3ccf036SAlexei Fedorov 	 * Disable group 0/1 counters to avoid other observers like SCP sampling
239b6eb3932SDimitris Papastamos 	 * counter values from the future via the memory mapped view.
240b6eb3932SDimitris Papastamos 	 */
24181e2ff1fSChris Kay 	write_amcntenclr0_px((UINT32_C(1) << read_amcgcr_cg0nc()) - 1U);
242f3ccf036SAlexei Fedorov 
2431fd685a7SChris Kay #if ENABLE_AMU_AUXILIARY_COUNTERS
244*31d3cc25SChris Kay 	if (amu_group1_supported()) {
24533b9be6dSChris Kay 		write_amcntenclr1_px(AMU_GROUP1_COUNTERS_MASK);
2461fd685a7SChris Kay 	}
247f3ccf036SAlexei Fedorov #endif
2481fd685a7SChris Kay 
249b6eb3932SDimitris Papastamos 	isb();
250b6eb3932SDimitris Papastamos 
251f3ccf036SAlexei Fedorov 	/* Save all group 0 counters */
25281e2ff1fSChris Kay 	for (i = 0U; i < read_amcgcr_cg0nc(); i++) {
253c70da546SJoel Hutton 		ctx->group0_cnts[i] = amu_group0_cnt_read(i);
254f3ccf036SAlexei Fedorov 	}
255c70da546SJoel Hutton 
2561fd685a7SChris Kay #if ENABLE_AMU_AUXILIARY_COUNTERS
257*31d3cc25SChris Kay 	if (amu_group1_supported()) {
258f3ccf036SAlexei Fedorov 		/* Save group 1 counters */
259*31d3cc25SChris Kay 		for (i = 0U; i < read_amcgcr_cg1nc(); i++) {
260f3ccf036SAlexei Fedorov 			if ((AMU_GROUP1_COUNTERS_MASK & (1U << i)) != 0U) {
261c70da546SJoel Hutton 				ctx->group1_cnts[i] = amu_group1_cnt_read(i);
262f3ccf036SAlexei Fedorov 			}
263f3ccf036SAlexei Fedorov 		}
2641fd685a7SChris Kay 	}
265f3ccf036SAlexei Fedorov #endif
2661fd685a7SChris Kay 
26740daecc1SAntonio Nino Diaz 	return (void *)0;
268b6eb3932SDimitris Papastamos }
269b6eb3932SDimitris Papastamos 
270b6eb3932SDimitris Papastamos static void *amu_context_restore(const void *arg)
271b6eb3932SDimitris Papastamos {
272f3ccf036SAlexei Fedorov 	struct amu_ctx *ctx = &amu_ctxs[plat_my_core_pos()];
273f3ccf036SAlexei Fedorov 	unsigned int i;
274b6eb3932SDimitris Papastamos 
27533b9be6dSChris Kay 	if (!amu_supported()) {
276b6eb3932SDimitris Papastamos 		return (void *)-1;
277f3ccf036SAlexei Fedorov 	}
278b6eb3932SDimitris Papastamos 
279b6eb3932SDimitris Papastamos 	/* Counters were disabled in `amu_context_save()` */
28033b9be6dSChris Kay 	assert(read_amcntenset0_px() == 0U);
281b6eb3932SDimitris Papastamos 
2821fd685a7SChris Kay #if ENABLE_AMU_AUXILIARY_COUNTERS
283*31d3cc25SChris Kay 	if (amu_group1_supported()) {
28433b9be6dSChris Kay 		assert(read_amcntenset1_px() == 0U);
2851fd685a7SChris Kay 	}
286f3ccf036SAlexei Fedorov #endif
287f3ccf036SAlexei Fedorov 
288f3ccf036SAlexei Fedorov 	/* Restore all group 0 counters */
28981e2ff1fSChris Kay 	for (i = 0U; i < read_amcgcr_cg0nc(); i++) {
290c70da546SJoel Hutton 		amu_group0_cnt_write(i, ctx->group0_cnts[i]);
291f3ccf036SAlexei Fedorov 	}
292b6eb3932SDimitris Papastamos 
293f3ccf036SAlexei Fedorov 	/* Restore group 0 counter configuration */
29481e2ff1fSChris Kay 	write_amcntenset0_px((UINT32_C(1) << read_amcgcr_cg0nc()) - 1U);
295b6eb3932SDimitris Papastamos 
2961fd685a7SChris Kay #if ENABLE_AMU_AUXILIARY_COUNTERS
297*31d3cc25SChris Kay 	if (amu_group1_supported()) {
298f3ccf036SAlexei Fedorov 		/* Restore group 1 counters */
299*31d3cc25SChris Kay 		for (i = 0U; i < read_amcgcr_cg1nc(); i++) {
300f3ccf036SAlexei Fedorov 			if ((AMU_GROUP1_COUNTERS_MASK & (1U << i)) != 0U) {
301f3ccf036SAlexei Fedorov 				amu_group1_cnt_write(i, ctx->group1_cnts[i]);
302f3ccf036SAlexei Fedorov 			}
303f3ccf036SAlexei Fedorov 		}
304f3ccf036SAlexei Fedorov 
305f3ccf036SAlexei Fedorov 		/* Restore group 1 counter configuration */
30633b9be6dSChris Kay 		write_amcntenset1_px(AMU_GROUP1_COUNTERS_MASK);
3071fd685a7SChris Kay 	}
308f3ccf036SAlexei Fedorov #endif
309f3ccf036SAlexei Fedorov 
31040daecc1SAntonio Nino Diaz 	return (void *)0;
311b6eb3932SDimitris Papastamos }
312b6eb3932SDimitris Papastamos 
313b6eb3932SDimitris Papastamos SUBSCRIBE_TO_EVENT(psci_suspend_pwrdown_start, amu_context_save);
314b6eb3932SDimitris Papastamos SUBSCRIBE_TO_EVENT(psci_suspend_pwrdown_finish, amu_context_restore);
315