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