1ef69e1eaSDimitris Papastamos /*
283ec7e45SBoyan 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
2083ec7e45SBoyan Karatotev amu_regs_t amu_ctx[PLATFORM_CORE_COUNT];
2181e2ff1fSChris Kay
read_amcgcr_cg1nc(void)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 */
amu_enable(bool el2_unused)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 */
3983ec7e45SBoyan Karatotev write_hcptr(read_hcptr() & ~TAM_BIT);
40ef69e1eaSDimitris Papastamos }
41ef69e1eaSDimitris Papastamos
4283ec7e45SBoyan Karatotev /* Architecture is currently pinned to 4 */
4383ec7e45SBoyan Karatotev assert((read_amcgcr() & AMCGCR_CG0NC_MASK) == CTX_AMU_GRP0_ALL);
44c70da546SJoel Hutton
4583ec7e45SBoyan Karatotev /* Enable all architected counters by default */
4683ec7e45SBoyan Karatotev write_amcntenset0(AMCNTENSET0_Pn_MASK);
47*6edbd2d6SBoyan Karatotev
48*6edbd2d6SBoyan Karatotev /* Bail out if FEAT_AMUv1p1 features are not present. */
49*6edbd2d6SBoyan Karatotev if (!is_feat_amuv1p1_supported()) {
50*6edbd2d6SBoyan Karatotev return;
51*6edbd2d6SBoyan Karatotev }
52*6edbd2d6SBoyan Karatotev
5383ec7e45SBoyan Karatotev if (is_feat_amu_aux_supported()) {
54742ca230SChris Kay unsigned int core_pos = plat_my_core_pos();
55742ca230SChris Kay
5683ec7e45SBoyan Karatotev /* Something went wrong if we're trying to write higher bits */
5783ec7e45SBoyan Karatotev assert((get_amu_aux_enables(core_pos) & ~AMCNTENSET1_Pn_MASK) == 0);
5883ec7e45SBoyan Karatotev write_amcntenset1(get_amu_aux_enables(core_pos));
591fd685a7SChris Kay }
60873d4241Sjohpow01
61873d4241Sjohpow01 #if AMU_RESTRICT_COUNTERS
62873d4241Sjohpow01 /*
63873d4241Sjohpow01 * FEAT_AMUv1p1 adds a register field to restrict access to group 1
64873d4241Sjohpow01 * counters at all but the highest implemented EL. This is controlled
65873d4241Sjohpow01 * with the AMU_RESTRICT_COUNTERS compile time flag, when set, system
66873d4241Sjohpow01 * register reads at lower ELs return zero. Reads from the memory
67873d4241Sjohpow01 * mapped view are unaffected.
68873d4241Sjohpow01 */
69873d4241Sjohpow01 VERBOSE("AMU group 1 counter access restricted.\n");
7083ec7e45SBoyan Karatotev write_amcr(read_amcr() | 1U);
71873d4241Sjohpow01 #else
7283ec7e45SBoyan Karatotev write_amcr(0);
73873d4241Sjohpow01 #endif
74c70da546SJoel Hutton }
amu_context_save(const void * arg)75c70da546SJoel Hutton
76b6eb3932SDimitris Papastamos static void *amu_context_save(const void *arg)
77b6eb3932SDimitris Papastamos {
78b57e16a4SAndre Przywara if (!is_feat_amu_supported()) {
79e747a59bSChris Kay return (void *)0;
80e747a59bSChris Kay }
81e747a59bSChris Kay
8283ec7e45SBoyan Karatotev unsigned int core_pos = *(unsigned int *)arg;
8383ec7e45SBoyan Karatotev amu_regs_t *ctx = &amu_ctx[core_pos];
84e747a59bSChris Kay
8583ec7e45SBoyan Karatotev /* Disable all counters so we can write to them safely later */
8683ec7e45SBoyan Karatotev write_amcntenclr0(AMCNTENCLR0_Pn_MASK);
8783ec7e45SBoyan Karatotev if (is_feat_amu_aux_supported()) {
8883ec7e45SBoyan Karatotev write_amcntenclr1(get_amu_aux_enables(core_pos));
891fd685a7SChris Kay }
90b6eb3932SDimitris Papastamos
91e747a59bSChris Kay isb(); /* Ensure counters have been stopped */
92e747a59bSChris Kay
9383ec7e45SBoyan Karatotev write_amu_grp0_ctx_reg(ctx, 0, read64_amevcntr00());
9483ec7e45SBoyan Karatotev write_amu_grp0_ctx_reg(ctx, 1, read64_amevcntr01());
9583ec7e45SBoyan Karatotev write_amu_grp0_ctx_reg(ctx, 2, read64_amevcntr02());
9683ec7e45SBoyan Karatotev write_amu_grp0_ctx_reg(ctx, 3, read64_amevcntr03());
97c70da546SJoel Hutton
9883ec7e45SBoyan Karatotev if (is_feat_amu_aux_supported()) {
9983ec7e45SBoyan Karatotev uint8_t num_counters = read_amcgcr_cg1nc();
10083ec7e45SBoyan Karatotev
10183ec7e45SBoyan Karatotev switch (num_counters) {
10283ec7e45SBoyan Karatotev case 0x10:
10383ec7e45SBoyan Karatotev write_amu_grp1_ctx_reg(ctx, 0xf, read64_amevcntr1f());
10483ec7e45SBoyan Karatotev __fallthrough;
10583ec7e45SBoyan Karatotev case 0x0f:
10683ec7e45SBoyan Karatotev write_amu_grp1_ctx_reg(ctx, 0xe, read64_amevcntr1e());
10783ec7e45SBoyan Karatotev __fallthrough;
10883ec7e45SBoyan Karatotev case 0x0e:
10983ec7e45SBoyan Karatotev write_amu_grp1_ctx_reg(ctx, 0xd, read64_amevcntr1d());
11083ec7e45SBoyan Karatotev __fallthrough;
11183ec7e45SBoyan Karatotev case 0x0d:
11283ec7e45SBoyan Karatotev write_amu_grp1_ctx_reg(ctx, 0xc, read64_amevcntr1c());
11383ec7e45SBoyan Karatotev __fallthrough;
11483ec7e45SBoyan Karatotev case 0x0c:
11583ec7e45SBoyan Karatotev write_amu_grp1_ctx_reg(ctx, 0xb, read64_amevcntr1b());
11683ec7e45SBoyan Karatotev __fallthrough;
11783ec7e45SBoyan Karatotev case 0x0b:
11883ec7e45SBoyan Karatotev write_amu_grp1_ctx_reg(ctx, 0xa, read64_amevcntr1a());
11983ec7e45SBoyan Karatotev __fallthrough;
12083ec7e45SBoyan Karatotev case 0x0a:
12183ec7e45SBoyan Karatotev write_amu_grp1_ctx_reg(ctx, 0x9, read64_amevcntr19());
12283ec7e45SBoyan Karatotev __fallthrough;
12383ec7e45SBoyan Karatotev case 0x09:
12483ec7e45SBoyan Karatotev write_amu_grp1_ctx_reg(ctx, 0x8, read64_amevcntr18());
12583ec7e45SBoyan Karatotev __fallthrough;
12683ec7e45SBoyan Karatotev case 0x08:
12783ec7e45SBoyan Karatotev write_amu_grp1_ctx_reg(ctx, 0x7, read64_amevcntr17());
12883ec7e45SBoyan Karatotev __fallthrough;
12983ec7e45SBoyan Karatotev case 0x07:
13083ec7e45SBoyan Karatotev write_amu_grp1_ctx_reg(ctx, 0x6, read64_amevcntr16());
13183ec7e45SBoyan Karatotev __fallthrough;
13283ec7e45SBoyan Karatotev case 0x06:
13383ec7e45SBoyan Karatotev write_amu_grp1_ctx_reg(ctx, 0x5, read64_amevcntr15());
13483ec7e45SBoyan Karatotev __fallthrough;
13583ec7e45SBoyan Karatotev case 0x05:
13683ec7e45SBoyan Karatotev write_amu_grp1_ctx_reg(ctx, 0x4, read64_amevcntr14());
13783ec7e45SBoyan Karatotev __fallthrough;
13883ec7e45SBoyan Karatotev case 0x04:
13983ec7e45SBoyan Karatotev write_amu_grp1_ctx_reg(ctx, 0x3, read64_amevcntr13());
14083ec7e45SBoyan Karatotev __fallthrough;
14183ec7e45SBoyan Karatotev case 0x03:
14283ec7e45SBoyan Karatotev write_amu_grp1_ctx_reg(ctx, 0x2, read64_amevcntr12());
14383ec7e45SBoyan Karatotev __fallthrough;
14483ec7e45SBoyan Karatotev case 0x02:
14583ec7e45SBoyan Karatotev write_amu_grp1_ctx_reg(ctx, 0x1, read64_amevcntr11());
14683ec7e45SBoyan Karatotev __fallthrough;
14783ec7e45SBoyan Karatotev case 0x01:
14883ec7e45SBoyan Karatotev write_amu_grp1_ctx_reg(ctx, 0x0, read64_amevcntr10());
14983ec7e45SBoyan Karatotev __fallthrough;
15083ec7e45SBoyan Karatotev case 0x00:
15183ec7e45SBoyan Karatotev break;
15283ec7e45SBoyan Karatotev default:
15383ec7e45SBoyan Karatotev assert(0); /* something is wrong */
154f3ccf036SAlexei Fedorov }
15583ec7e45SBoyan Karatotev }
1561fd685a7SChris Kay
15740daecc1SAntonio Nino Diaz return (void *)0;
158b6eb3932SDimitris Papastamos }
amu_context_restore(const void * arg)159b6eb3932SDimitris Papastamos
160b6eb3932SDimitris Papastamos static void *amu_context_restore(const void *arg)
161b6eb3932SDimitris Papastamos {
162b57e16a4SAndre Przywara if (!is_feat_amu_supported()) {
163e747a59bSChris Kay return (void *)0;
164e747a59bSChris Kay }
165e747a59bSChris Kay
16683ec7e45SBoyan Karatotev unsigned int core_pos = *(unsigned int *)arg;
16783ec7e45SBoyan Karatotev amu_regs_t *ctx = &amu_ctx[core_pos];
168e747a59bSChris Kay
16983ec7e45SBoyan Karatotev write64_amevcntr00(read_amu_grp0_ctx_reg(ctx, 0));
17083ec7e45SBoyan Karatotev write64_amevcntr01(read_amu_grp0_ctx_reg(ctx, 1));
17183ec7e45SBoyan Karatotev write64_amevcntr02(read_amu_grp0_ctx_reg(ctx, 2));
17283ec7e45SBoyan Karatotev write64_amevcntr03(read_amu_grp0_ctx_reg(ctx, 3));
173e747a59bSChris Kay
17483ec7e45SBoyan Karatotev if (is_feat_amu_aux_supported()) {
17583ec7e45SBoyan Karatotev uint8_t num_counters = read_amcgcr_cg1nc();
176e747a59bSChris Kay
17783ec7e45SBoyan Karatotev switch (num_counters) {
17883ec7e45SBoyan Karatotev case 0x10:
17983ec7e45SBoyan Karatotev write64_amevcntr1f(read_amu_grp1_ctx_reg(ctx, 0xf));
18083ec7e45SBoyan Karatotev __fallthrough;
18183ec7e45SBoyan Karatotev case 0x0f:
18283ec7e45SBoyan Karatotev write64_amevcntr1e(read_amu_grp1_ctx_reg(ctx, 0xe));
18383ec7e45SBoyan Karatotev __fallthrough;
18483ec7e45SBoyan Karatotev case 0x0e:
18583ec7e45SBoyan Karatotev write64_amevcntr1d(read_amu_grp1_ctx_reg(ctx, 0xd));
18683ec7e45SBoyan Karatotev __fallthrough;
18783ec7e45SBoyan Karatotev case 0x0d:
18883ec7e45SBoyan Karatotev write64_amevcntr1c(read_amu_grp1_ctx_reg(ctx, 0xc));
18983ec7e45SBoyan Karatotev __fallthrough;
19083ec7e45SBoyan Karatotev case 0x0c:
19183ec7e45SBoyan Karatotev write64_amevcntr1b(read_amu_grp1_ctx_reg(ctx, 0xb));
19283ec7e45SBoyan Karatotev __fallthrough;
19383ec7e45SBoyan Karatotev case 0x0b:
19483ec7e45SBoyan Karatotev write64_amevcntr1a(read_amu_grp1_ctx_reg(ctx, 0xa));
19583ec7e45SBoyan Karatotev __fallthrough;
19683ec7e45SBoyan Karatotev case 0x0a:
19783ec7e45SBoyan Karatotev write64_amevcntr19(read_amu_grp1_ctx_reg(ctx, 0x9));
19883ec7e45SBoyan Karatotev __fallthrough;
19983ec7e45SBoyan Karatotev case 0x09:
20083ec7e45SBoyan Karatotev write64_amevcntr18(read_amu_grp1_ctx_reg(ctx, 0x8));
20183ec7e45SBoyan Karatotev __fallthrough;
20283ec7e45SBoyan Karatotev case 0x08:
20383ec7e45SBoyan Karatotev write64_amevcntr17(read_amu_grp1_ctx_reg(ctx, 0x7));
20483ec7e45SBoyan Karatotev __fallthrough;
20583ec7e45SBoyan Karatotev case 0x07:
20683ec7e45SBoyan Karatotev write64_amevcntr16(read_amu_grp1_ctx_reg(ctx, 0x6));
20783ec7e45SBoyan Karatotev __fallthrough;
20883ec7e45SBoyan Karatotev case 0x06:
20983ec7e45SBoyan Karatotev write64_amevcntr15(read_amu_grp1_ctx_reg(ctx, 0x5));
21083ec7e45SBoyan Karatotev __fallthrough;
21183ec7e45SBoyan Karatotev case 0x05:
21283ec7e45SBoyan Karatotev write64_amevcntr14(read_amu_grp1_ctx_reg(ctx, 0x4));
21383ec7e45SBoyan Karatotev __fallthrough;
21483ec7e45SBoyan Karatotev case 0x04:
21583ec7e45SBoyan Karatotev write64_amevcntr13(read_amu_grp1_ctx_reg(ctx, 0x3));
21683ec7e45SBoyan Karatotev __fallthrough;
21783ec7e45SBoyan Karatotev case 0x03:
21883ec7e45SBoyan Karatotev write64_amevcntr12(read_amu_grp1_ctx_reg(ctx, 0x2));
21983ec7e45SBoyan Karatotev __fallthrough;
22083ec7e45SBoyan Karatotev case 0x02:
22183ec7e45SBoyan Karatotev write64_amevcntr11(read_amu_grp1_ctx_reg(ctx, 0x1));
22283ec7e45SBoyan Karatotev __fallthrough;
22383ec7e45SBoyan Karatotev case 0x01:
22483ec7e45SBoyan Karatotev write64_amevcntr10(read_amu_grp1_ctx_reg(ctx, 0x0));
22583ec7e45SBoyan Karatotev __fallthrough;
22683ec7e45SBoyan Karatotev case 0x00:
22783ec7e45SBoyan Karatotev break;
22883ec7e45SBoyan Karatotev default:
22983ec7e45SBoyan Karatotev assert(0); /* something is wrong */
23083ec7e45SBoyan Karatotev }
231e747a59bSChris Kay }
232e747a59bSChris Kay
233e747a59bSChris Kay
23483ec7e45SBoyan Karatotev /* now enable them again */
23583ec7e45SBoyan Karatotev write_amcntenset0(AMCNTENSET0_Pn_MASK);
23683ec7e45SBoyan Karatotev if (is_feat_amu_aux_supported()) {
23783ec7e45SBoyan Karatotev write_amcntenset1(get_amu_aux_enables(core_pos));
238f3ccf036SAlexei Fedorov }
239b6eb3932SDimitris Papastamos
24083ec7e45SBoyan Karatotev isb();
24140daecc1SAntonio Nino Diaz return (void *)0;
242b6eb3932SDimitris Papastamos }
243b6eb3932SDimitris Papastamos
244b6eb3932SDimitris Papastamos SUBSCRIBE_TO_EVENT(psci_suspend_pwrdown_start, amu_context_save);
245b6eb3932SDimitris Papastamos SUBSCRIBE_TO_EVENT(psci_suspend_pwrdown_finish, amu_context_restore);
246