1380559c1SDimitris Papastamos /* 2*83ec7e45SBoyan Karatotev * Copyright (c) 2017-2025, Arm Limited and Contributors. All rights reserved. 3380559c1SDimitris Papastamos * 4380559c1SDimitris Papastamos * SPDX-License-Identifier: BSD-3-Clause 5380559c1SDimitris Papastamos */ 6380559c1SDimitris Papastamos 709d40e0eSAntonio Nino Diaz #include <assert.h> 833b9be6dSChris Kay #include <cdefs.h> 94ce3e99aSScott Branden #include <inttypes.h> 1009d40e0eSAntonio Nino Diaz #include <stdbool.h> 114ce3e99aSScott Branden #include <stdint.h> 1209d40e0eSAntonio Nino Diaz 13380559c1SDimitris Papastamos #include <arch.h> 14873d4241Sjohpow01 #include <arch_features.h> 15380559c1SDimitris Papastamos #include <arch_helpers.h> 16742ca230SChris Kay #include <common/debug.h> 1709d40e0eSAntonio Nino Diaz #include <lib/el3_runtime/pubsub_events.h> 1809d40e0eSAntonio Nino Diaz #include <lib/extensions/amu.h> 19*83ec7e45SBoyan Karatotev #include <lib/utils_def.h> 20*83ec7e45SBoyan Karatotev #include <platform_def.h> 21f3ccf036SAlexei Fedorov 22*83ec7e45SBoyan Karatotev amu_regs_t amu_ctx[PLATFORM_CORE_COUNT]; 23380559c1SDimitris Papastamos 24*83ec7e45SBoyan Karatotev static inline uint8_t read_amcgcr_el0_cg1nc(void) 2533b9be6dSChris Kay { 2633b9be6dSChris Kay return (read_amcgcr_el0() >> AMCGCR_EL0_CG1NC_SHIFT) & 2733b9be6dSChris Kay AMCGCR_EL0_CG1NC_MASK; 2833b9be6dSChris Kay } 2933b9be6dSChris Kay 304085a02cSBoyan Karatotev void amu_enable(cpu_context_t *ctx) 310767d50eSDimitris Papastamos { 324085a02cSBoyan Karatotev /* Initialize FEAT_AMUv1p1 features if present. */ 334085a02cSBoyan Karatotev if (is_feat_amuv1p1_supported()) { 34*83ec7e45SBoyan Karatotev el3_state_t *state = get_el3state_ctx(ctx); 35*83ec7e45SBoyan Karatotev u_register_t reg; 36*83ec7e45SBoyan Karatotev 37e747a59bSChris Kay /* 384085a02cSBoyan Karatotev * Set SCR_EL3.AMVOFFEN to one so that accesses to virtual 394085a02cSBoyan Karatotev * offset registers at EL2 do not trap to EL3 40e747a59bSChris Kay */ 41*83ec7e45SBoyan Karatotev reg = read_ctx_reg(state, CTX_SCR_EL3); 42*83ec7e45SBoyan Karatotev reg |= SCR_AMVOFFEN_BIT; 43*83ec7e45SBoyan Karatotev write_ctx_reg(state, CTX_SCR_EL3, reg); 444085a02cSBoyan Karatotev } 454085a02cSBoyan Karatotev } 46f3ccf036SAlexei Fedorov 47461c0a5dSElizabeth Ho void amu_enable_per_world(per_world_context_t *per_world_ctx) 48461c0a5dSElizabeth Ho { 49461c0a5dSElizabeth Ho /* 50461c0a5dSElizabeth Ho * Set CPTR_EL3.TAM to zero so that any accesses to the Activity Monitor 51461c0a5dSElizabeth Ho * registers do not trap to EL3. 52461c0a5dSElizabeth Ho */ 53461c0a5dSElizabeth Ho uint64_t cptr_el3 = per_world_ctx->ctx_cptr_el3; 54461c0a5dSElizabeth Ho 55461c0a5dSElizabeth Ho cptr_el3 &= ~TAM_BIT; 56461c0a5dSElizabeth Ho per_world_ctx->ctx_cptr_el3 = cptr_el3; 57461c0a5dSElizabeth Ho } 58461c0a5dSElizabeth Ho 59*83ec7e45SBoyan Karatotev void amu_init_el3(unsigned int core_pos) 604085a02cSBoyan Karatotev { 61*83ec7e45SBoyan Karatotev /* architecture is currently pinned to 4 */ 62*83ec7e45SBoyan Karatotev assert((read_amcgcr_el0() & AMCGCR_EL0_CG0NC_MASK) == CTX_AMU_GRP0_ALL); 63e747a59bSChris Kay 644085a02cSBoyan Karatotev /* Enable all architected counters by default */ 65*83ec7e45SBoyan Karatotev write_amcntenset0_el0(AMCNTENSET0_EL0_Pn_MASK); 66*83ec7e45SBoyan Karatotev if (is_feat_amu_aux_supported()) { 67*83ec7e45SBoyan Karatotev /* something went wrong if we're trying to write higher bits */ 68*83ec7e45SBoyan Karatotev assert((get_amu_aux_enables(core_pos) & ~AMCNTENSET1_EL0_Pn_MASK) == 0); 69*83ec7e45SBoyan Karatotev write_amcntenset1_el0(get_amu_aux_enables(core_pos)); 70742ca230SChris Kay } 714085a02cSBoyan Karatotev 72b57e16a4SAndre Przywara if (is_feat_amuv1p1_supported()) { 73873d4241Sjohpow01 #if AMU_RESTRICT_COUNTERS 74873d4241Sjohpow01 /* 7568120783SChris Kay * FEAT_AMUv1p1 adds a register field to restrict access to 7668120783SChris Kay * group 1 counters at all but the highest implemented EL. This 7768120783SChris Kay * is controlled with the `AMU_RESTRICT_COUNTERS` compile time 7868120783SChris Kay * flag, when set, system register reads at lower ELs return 7968120783SChris Kay * zero. Reads from the memory mapped view are unaffected. 80873d4241Sjohpow01 */ 81873d4241Sjohpow01 VERBOSE("AMU group 1 counter access restricted.\n"); 82*83ec7e45SBoyan Karatotev write_amcr_el0(AMCR_CG1RZ_BIT); 83873d4241Sjohpow01 #else 84*83ec7e45SBoyan Karatotev /* HDBG = 0 in both cases */ 85*83ec7e45SBoyan Karatotev write_amcr_el0(0); 86873d4241Sjohpow01 #endif 87380559c1SDimitris Papastamos } 8868120783SChris Kay } 8968120783SChris Kay 904085a02cSBoyan Karatotev void amu_init_el2_unused(void) 914085a02cSBoyan Karatotev { 924085a02cSBoyan Karatotev /* 934085a02cSBoyan Karatotev * CPTR_EL2.TAM: Set to zero so any accesses to the Activity Monitor 944085a02cSBoyan Karatotev * registers do not trap to EL2. 954085a02cSBoyan Karatotev */ 96*83ec7e45SBoyan Karatotev write_cptr_el2(read_cptr_el2() & ~CPTR_EL2_TAM_BIT); 974085a02cSBoyan Karatotev 984085a02cSBoyan Karatotev if (is_feat_amuv1p1_supported()) { 99*83ec7e45SBoyan Karatotev /* Make sure virtual offsets are disabled */ 100*83ec7e45SBoyan Karatotev write_hcr_el2(read_hcr_el2() & ~HCR_AMVOFFEN_BIT); 1014085a02cSBoyan Karatotev } 1024085a02cSBoyan Karatotev } 1034085a02cSBoyan Karatotev 104b6eb3932SDimitris Papastamos static void *amu_context_save(const void *arg) 105b6eb3932SDimitris Papastamos { 106b57e16a4SAndre Przywara if (!is_feat_amu_supported()) { 107e747a59bSChris Kay return (void *)0; 108e747a59bSChris Kay } 109e747a59bSChris Kay 110*83ec7e45SBoyan Karatotev unsigned int core_pos = *(unsigned int *)arg; 111*83ec7e45SBoyan Karatotev amu_regs_t *ctx = &amu_ctx[core_pos]; 112e747a59bSChris Kay 113*83ec7e45SBoyan Karatotev /* disable all counters so we can write them safely later */ 114*83ec7e45SBoyan Karatotev write_amcntenclr0_el0(AMCNTENCLR0_EL0_Pn_MASK); 115*83ec7e45SBoyan Karatotev if (is_feat_amu_aux_supported()) { 116*83ec7e45SBoyan Karatotev write_amcntenclr1_el0(get_amu_aux_enables(core_pos)); 117b57e16a4SAndre Przywara } 118e747a59bSChris Kay 119*83ec7e45SBoyan Karatotev isb(); 120e747a59bSChris Kay 121*83ec7e45SBoyan Karatotev write_amu_grp0_ctx_reg(ctx, 0, read_amevcntr00_el0()); 122*83ec7e45SBoyan Karatotev write_amu_grp0_ctx_reg(ctx, 1, read_amevcntr01_el0()); 123*83ec7e45SBoyan Karatotev write_amu_grp0_ctx_reg(ctx, 2, read_amevcntr02_el0()); 124*83ec7e45SBoyan Karatotev write_amu_grp0_ctx_reg(ctx, 3, read_amevcntr03_el0()); 125e747a59bSChris Kay 126*83ec7e45SBoyan Karatotev if (is_feat_amu_aux_supported()) { 127*83ec7e45SBoyan Karatotev uint8_t num_counters = read_amcgcr_el0_cg1nc(); 128e747a59bSChris Kay 129*83ec7e45SBoyan Karatotev switch (num_counters) { 130*83ec7e45SBoyan Karatotev case 0x10: 131*83ec7e45SBoyan Karatotev write_amu_grp1_ctx_reg(ctx, 0xf, read_amevcntr1f_el0()); 132*83ec7e45SBoyan Karatotev __fallthrough; 133*83ec7e45SBoyan Karatotev case 0x0f: 134*83ec7e45SBoyan Karatotev write_amu_grp1_ctx_reg(ctx, 0xe, read_amevcntr1e_el0()); 135*83ec7e45SBoyan Karatotev __fallthrough; 136*83ec7e45SBoyan Karatotev case 0x0e: 137*83ec7e45SBoyan Karatotev write_amu_grp1_ctx_reg(ctx, 0xd, read_amevcntr1d_el0()); 138*83ec7e45SBoyan Karatotev __fallthrough; 139*83ec7e45SBoyan Karatotev case 0x0d: 140*83ec7e45SBoyan Karatotev write_amu_grp1_ctx_reg(ctx, 0xc, read_amevcntr1c_el0()); 141*83ec7e45SBoyan Karatotev __fallthrough; 142*83ec7e45SBoyan Karatotev case 0x0c: 143*83ec7e45SBoyan Karatotev write_amu_grp1_ctx_reg(ctx, 0xb, read_amevcntr1b_el0()); 144*83ec7e45SBoyan Karatotev __fallthrough; 145*83ec7e45SBoyan Karatotev case 0x0b: 146*83ec7e45SBoyan Karatotev write_amu_grp1_ctx_reg(ctx, 0xa, read_amevcntr1a_el0()); 147*83ec7e45SBoyan Karatotev __fallthrough; 148*83ec7e45SBoyan Karatotev case 0x0a: 149*83ec7e45SBoyan Karatotev write_amu_grp1_ctx_reg(ctx, 0x9, read_amevcntr19_el0()); 150*83ec7e45SBoyan Karatotev __fallthrough; 151*83ec7e45SBoyan Karatotev case 0x09: 152*83ec7e45SBoyan Karatotev write_amu_grp1_ctx_reg(ctx, 0x8, read_amevcntr18_el0()); 153*83ec7e45SBoyan Karatotev __fallthrough; 154*83ec7e45SBoyan Karatotev case 0x08: 155*83ec7e45SBoyan Karatotev write_amu_grp1_ctx_reg(ctx, 0x7, read_amevcntr17_el0()); 156*83ec7e45SBoyan Karatotev __fallthrough; 157*83ec7e45SBoyan Karatotev case 0x07: 158*83ec7e45SBoyan Karatotev write_amu_grp1_ctx_reg(ctx, 0x6, read_amevcntr16_el0()); 159*83ec7e45SBoyan Karatotev __fallthrough; 160*83ec7e45SBoyan Karatotev case 0x06: 161*83ec7e45SBoyan Karatotev write_amu_grp1_ctx_reg(ctx, 0x5, read_amevcntr15_el0()); 162*83ec7e45SBoyan Karatotev __fallthrough; 163*83ec7e45SBoyan Karatotev case 0x05: 164*83ec7e45SBoyan Karatotev write_amu_grp1_ctx_reg(ctx, 0x4, read_amevcntr14_el0()); 165*83ec7e45SBoyan Karatotev __fallthrough; 166*83ec7e45SBoyan Karatotev case 0x04: 167*83ec7e45SBoyan Karatotev write_amu_grp1_ctx_reg(ctx, 0x3, read_amevcntr13_el0()); 168*83ec7e45SBoyan Karatotev __fallthrough; 169*83ec7e45SBoyan Karatotev case 0x03: 170*83ec7e45SBoyan Karatotev write_amu_grp1_ctx_reg(ctx, 0x2, read_amevcntr12_el0()); 171*83ec7e45SBoyan Karatotev __fallthrough; 172*83ec7e45SBoyan Karatotev case 0x02: 173*83ec7e45SBoyan Karatotev write_amu_grp1_ctx_reg(ctx, 0x1, read_amevcntr11_el0()); 174*83ec7e45SBoyan Karatotev __fallthrough; 175*83ec7e45SBoyan Karatotev case 0x01: 176*83ec7e45SBoyan Karatotev write_amu_grp1_ctx_reg(ctx, 0x0, read_amevcntr10_el0()); 177*83ec7e45SBoyan Karatotev __fallthrough; 178*83ec7e45SBoyan Karatotev case 0x00: 179*83ec7e45SBoyan Karatotev break; 180*83ec7e45SBoyan Karatotev default: 181*83ec7e45SBoyan Karatotev assert(0); /* something is wrong */ 1821fd685a7SChris Kay } 183e747a59bSChris Kay } 1841fd685a7SChris Kay 18540daecc1SAntonio Nino Diaz return (void *)0; 186b6eb3932SDimitris Papastamos } 187b6eb3932SDimitris Papastamos 188b6eb3932SDimitris Papastamos static void *amu_context_restore(const void *arg) 189b6eb3932SDimitris Papastamos { 190b57e16a4SAndre Przywara if (!is_feat_amu_supported()) { 191e747a59bSChris Kay return (void *)0; 192e747a59bSChris Kay } 193e747a59bSChris Kay 194*83ec7e45SBoyan Karatotev unsigned int core_pos = *(unsigned int *)arg; 195*83ec7e45SBoyan Karatotev amu_regs_t *ctx = &amu_ctx[core_pos]; 196e747a59bSChris Kay 197*83ec7e45SBoyan Karatotev write_amevcntr00_el0(read_amu_grp0_ctx_reg(ctx, 0)); 198*83ec7e45SBoyan Karatotev write_amevcntr01_el0(read_amu_grp0_ctx_reg(ctx, 1)); 199*83ec7e45SBoyan Karatotev write_amevcntr02_el0(read_amu_grp0_ctx_reg(ctx, 2)); 200*83ec7e45SBoyan Karatotev write_amevcntr03_el0(read_amu_grp0_ctx_reg(ctx, 3)); 201e747a59bSChris Kay 202*83ec7e45SBoyan Karatotev if (is_feat_amu_aux_supported()) { 203*83ec7e45SBoyan Karatotev uint8_t num_counters = read_amcgcr_el0_cg1nc(); 204*83ec7e45SBoyan Karatotev 205*83ec7e45SBoyan Karatotev switch (num_counters) { 206*83ec7e45SBoyan Karatotev case 0x10: 207*83ec7e45SBoyan Karatotev write_amevcntr1f_el0(read_amu_grp1_ctx_reg(ctx, 0xf)); 208*83ec7e45SBoyan Karatotev __fallthrough; 209*83ec7e45SBoyan Karatotev case 0x0f: 210*83ec7e45SBoyan Karatotev write_amevcntr1e_el0(read_amu_grp1_ctx_reg(ctx, 0xe)); 211*83ec7e45SBoyan Karatotev __fallthrough; 212*83ec7e45SBoyan Karatotev case 0x0e: 213*83ec7e45SBoyan Karatotev write_amevcntr1d_el0(read_amu_grp1_ctx_reg(ctx, 0xd)); 214*83ec7e45SBoyan Karatotev __fallthrough; 215*83ec7e45SBoyan Karatotev case 0x0d: 216*83ec7e45SBoyan Karatotev write_amevcntr1c_el0(read_amu_grp1_ctx_reg(ctx, 0xc)); 217*83ec7e45SBoyan Karatotev __fallthrough; 218*83ec7e45SBoyan Karatotev case 0x0c: 219*83ec7e45SBoyan Karatotev write_amevcntr1b_el0(read_amu_grp1_ctx_reg(ctx, 0xb)); 220*83ec7e45SBoyan Karatotev __fallthrough; 221*83ec7e45SBoyan Karatotev case 0x0b: 222*83ec7e45SBoyan Karatotev write_amevcntr1a_el0(read_amu_grp1_ctx_reg(ctx, 0xa)); 223*83ec7e45SBoyan Karatotev __fallthrough; 224*83ec7e45SBoyan Karatotev case 0x0a: 225*83ec7e45SBoyan Karatotev write_amevcntr19_el0(read_amu_grp1_ctx_reg(ctx, 0x9)); 226*83ec7e45SBoyan Karatotev __fallthrough; 227*83ec7e45SBoyan Karatotev case 0x09: 228*83ec7e45SBoyan Karatotev write_amevcntr18_el0(read_amu_grp1_ctx_reg(ctx, 0x8)); 229*83ec7e45SBoyan Karatotev __fallthrough; 230*83ec7e45SBoyan Karatotev case 0x08: 231*83ec7e45SBoyan Karatotev write_amevcntr17_el0(read_amu_grp1_ctx_reg(ctx, 0x7)); 232*83ec7e45SBoyan Karatotev __fallthrough; 233*83ec7e45SBoyan Karatotev case 0x07: 234*83ec7e45SBoyan Karatotev write_amevcntr16_el0(read_amu_grp1_ctx_reg(ctx, 0x6)); 235*83ec7e45SBoyan Karatotev __fallthrough; 236*83ec7e45SBoyan Karatotev case 0x06: 237*83ec7e45SBoyan Karatotev write_amevcntr15_el0(read_amu_grp1_ctx_reg(ctx, 0x5)); 238*83ec7e45SBoyan Karatotev __fallthrough; 239*83ec7e45SBoyan Karatotev case 0x05: 240*83ec7e45SBoyan Karatotev write_amevcntr14_el0(read_amu_grp1_ctx_reg(ctx, 0x4)); 241*83ec7e45SBoyan Karatotev __fallthrough; 242*83ec7e45SBoyan Karatotev case 0x04: 243*83ec7e45SBoyan Karatotev write_amevcntr13_el0(read_amu_grp1_ctx_reg(ctx, 0x3)); 244*83ec7e45SBoyan Karatotev __fallthrough; 245*83ec7e45SBoyan Karatotev case 0x03: 246*83ec7e45SBoyan Karatotev write_amevcntr12_el0(read_amu_grp1_ctx_reg(ctx, 0x2)); 247*83ec7e45SBoyan Karatotev __fallthrough; 248*83ec7e45SBoyan Karatotev case 0x02: 249*83ec7e45SBoyan Karatotev write_amevcntr11_el0(read_amu_grp1_ctx_reg(ctx, 0x1)); 250*83ec7e45SBoyan Karatotev __fallthrough; 251*83ec7e45SBoyan Karatotev case 0x01: 252*83ec7e45SBoyan Karatotev write_amevcntr10_el0(read_amu_grp1_ctx_reg(ctx, 0x0)); 253*83ec7e45SBoyan Karatotev __fallthrough; 254*83ec7e45SBoyan Karatotev case 0x00: 255*83ec7e45SBoyan Karatotev break; 256*83ec7e45SBoyan Karatotev default: 257*83ec7e45SBoyan Karatotev assert(0); /* something is wrong */ 258*83ec7e45SBoyan Karatotev } 259b57e16a4SAndre Przywara } 260e747a59bSChris Kay 261e747a59bSChris Kay 262*83ec7e45SBoyan Karatotev /* now enable them again */ 263*83ec7e45SBoyan Karatotev write_amcntenset0_el0(AMCNTENSET0_EL0_Pn_MASK); 264*83ec7e45SBoyan Karatotev if (is_feat_amu_aux_supported()) { 265*83ec7e45SBoyan Karatotev write_amcntenset1_el0(get_amu_aux_enables(core_pos)); 266f3ccf036SAlexei Fedorov } 267b6eb3932SDimitris Papastamos 268*83ec7e45SBoyan Karatotev isb(); 26940daecc1SAntonio Nino Diaz return (void *)0; 270b6eb3932SDimitris Papastamos } 271b6eb3932SDimitris Papastamos 272b6eb3932SDimitris Papastamos SUBSCRIBE_TO_EVENT(psci_suspend_pwrdown_start, amu_context_save); 273b6eb3932SDimitris Papastamos SUBSCRIBE_TO_EVENT(psci_suspend_pwrdown_finish, amu_context_restore); 274