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 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 */ 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 } 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 } 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