1380559c1SDimitris Papastamos /* 283ec7e45SBoyan 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> 190f90f374SSammit Joshi #include <lib/per_cpu/per_cpu.h> 2083ec7e45SBoyan Karatotev #include <lib/utils_def.h> 2183ec7e45SBoyan Karatotev #include <platform_def.h> 22f3ccf036SAlexei Fedorov 230f90f374SSammit Joshi PER_CPU_DEFINE(amu_regs_t, amu_ctx); 24380559c1SDimitris Papastamos 2583ec7e45SBoyan Karatotev static inline uint8_t read_amcgcr_el0_cg1nc(void) 2633b9be6dSChris Kay { 2733b9be6dSChris Kay return (read_amcgcr_el0() >> AMCGCR_EL0_CG1NC_SHIFT) & 2833b9be6dSChris Kay AMCGCR_EL0_CG1NC_MASK; 2933b9be6dSChris Kay } 3033b9be6dSChris Kay 314085a02cSBoyan Karatotev void amu_enable(cpu_context_t *ctx) 320767d50eSDimitris Papastamos { 334085a02cSBoyan Karatotev /* Initialize FEAT_AMUv1p1 features if present. */ 344085a02cSBoyan Karatotev if (is_feat_amuv1p1_supported()) { 3583ec7e45SBoyan Karatotev el3_state_t *state = get_el3state_ctx(ctx); 3683ec7e45SBoyan Karatotev u_register_t reg; 3783ec7e45SBoyan Karatotev 38e747a59bSChris Kay /* 394085a02cSBoyan Karatotev * Set SCR_EL3.AMVOFFEN to one so that accesses to virtual 404085a02cSBoyan Karatotev * offset registers at EL2 do not trap to EL3 41e747a59bSChris Kay */ 4283ec7e45SBoyan Karatotev reg = read_ctx_reg(state, CTX_SCR_EL3); 4383ec7e45SBoyan Karatotev reg |= SCR_AMVOFFEN_BIT; 4483ec7e45SBoyan Karatotev write_ctx_reg(state, CTX_SCR_EL3, reg); 454085a02cSBoyan Karatotev } 464085a02cSBoyan Karatotev } 47f3ccf036SAlexei Fedorov 48461c0a5dSElizabeth Ho void amu_enable_per_world(per_world_context_t *per_world_ctx) 49461c0a5dSElizabeth Ho { 50461c0a5dSElizabeth Ho /* 51461c0a5dSElizabeth Ho * Set CPTR_EL3.TAM to zero so that any accesses to the Activity Monitor 52461c0a5dSElizabeth Ho * registers do not trap to EL3. 53461c0a5dSElizabeth Ho */ 54461c0a5dSElizabeth Ho uint64_t cptr_el3 = per_world_ctx->ctx_cptr_el3; 55461c0a5dSElizabeth Ho 56461c0a5dSElizabeth Ho cptr_el3 &= ~TAM_BIT; 57461c0a5dSElizabeth Ho per_world_ctx->ctx_cptr_el3 = cptr_el3; 58461c0a5dSElizabeth Ho } 59461c0a5dSElizabeth Ho 6083ec7e45SBoyan Karatotev void amu_init_el3(unsigned int core_pos) 614085a02cSBoyan Karatotev { 6283ec7e45SBoyan Karatotev /* architecture is currently pinned to 4 */ 6383ec7e45SBoyan Karatotev assert((read_amcgcr_el0() & AMCGCR_EL0_CG0NC_MASK) == CTX_AMU_GRP0_ALL); 64e747a59bSChris Kay 654085a02cSBoyan Karatotev /* Enable all architected counters by default */ 6683ec7e45SBoyan Karatotev write_amcntenset0_el0(AMCNTENSET0_EL0_Pn_MASK); 67*6edbd2d6SBoyan Karatotev 68*6edbd2d6SBoyan Karatotev if (!is_feat_amuv1p1_supported()) { 69*6edbd2d6SBoyan Karatotev return; 70*6edbd2d6SBoyan Karatotev } 71*6edbd2d6SBoyan Karatotev 7283ec7e45SBoyan Karatotev if (is_feat_amu_aux_supported()) { 7383ec7e45SBoyan Karatotev /* something went wrong if we're trying to write higher bits */ 7483ec7e45SBoyan Karatotev assert((get_amu_aux_enables(core_pos) & ~AMCNTENSET1_EL0_Pn_MASK) == 0); 7583ec7e45SBoyan Karatotev write_amcntenset1_el0(get_amu_aux_enables(core_pos)); 76742ca230SChris Kay } 774085a02cSBoyan Karatotev 78873d4241Sjohpow01 #if AMU_RESTRICT_COUNTERS 79873d4241Sjohpow01 /* 8068120783SChris Kay * FEAT_AMUv1p1 adds a register field to restrict access to 8168120783SChris Kay * group 1 counters at all but the highest implemented EL. This 8268120783SChris Kay * is controlled with the `AMU_RESTRICT_COUNTERS` compile time 8368120783SChris Kay * flag, when set, system register reads at lower ELs return 8468120783SChris Kay * zero. Reads from the memory mapped view are unaffected. 85873d4241Sjohpow01 */ 86873d4241Sjohpow01 VERBOSE("AMU group 1 counter access restricted.\n"); 8783ec7e45SBoyan Karatotev write_amcr_el0(AMCR_CG1RZ_BIT); 88873d4241Sjohpow01 #else 8983ec7e45SBoyan Karatotev /* HDBG = 0 in both cases */ 9083ec7e45SBoyan Karatotev write_amcr_el0(0); 91873d4241Sjohpow01 #endif 92380559c1SDimitris Papastamos } 9368120783SChris Kay 944085a02cSBoyan Karatotev void amu_init_el2_unused(void) 954085a02cSBoyan Karatotev { 964085a02cSBoyan Karatotev /* 974085a02cSBoyan Karatotev * CPTR_EL2.TAM: Set to zero so any accesses to the Activity Monitor 984085a02cSBoyan Karatotev * registers do not trap to EL2. 994085a02cSBoyan Karatotev */ 10083ec7e45SBoyan Karatotev write_cptr_el2(read_cptr_el2() & ~CPTR_EL2_TAM_BIT); 1014085a02cSBoyan Karatotev 1024085a02cSBoyan Karatotev if (is_feat_amuv1p1_supported()) { 10383ec7e45SBoyan Karatotev /* Make sure virtual offsets are disabled */ 10483ec7e45SBoyan Karatotev write_hcr_el2(read_hcr_el2() & ~HCR_AMVOFFEN_BIT); 1054085a02cSBoyan Karatotev } 1064085a02cSBoyan Karatotev } 1074085a02cSBoyan Karatotev 108b6eb3932SDimitris Papastamos static void *amu_context_save(const void *arg) 109b6eb3932SDimitris Papastamos { 110b57e16a4SAndre Przywara if (!is_feat_amu_supported()) { 111e747a59bSChris Kay return (void *)0; 112e747a59bSChris Kay } 113e747a59bSChris Kay 11483ec7e45SBoyan Karatotev unsigned int core_pos = *(unsigned int *)arg; 1150f90f374SSammit Joshi amu_regs_t *ctx = PER_CPU_CUR(amu_ctx); 116e747a59bSChris Kay 11783ec7e45SBoyan Karatotev /* disable all counters so we can write them safely later */ 11883ec7e45SBoyan Karatotev write_amcntenclr0_el0(AMCNTENCLR0_EL0_Pn_MASK); 11983ec7e45SBoyan Karatotev if (is_feat_amu_aux_supported()) { 12083ec7e45SBoyan Karatotev write_amcntenclr1_el0(get_amu_aux_enables(core_pos)); 121b57e16a4SAndre Przywara } 122e747a59bSChris Kay 12383ec7e45SBoyan Karatotev isb(); 124e747a59bSChris Kay 12583ec7e45SBoyan Karatotev write_amu_grp0_ctx_reg(ctx, 0, read_amevcntr00_el0()); 12683ec7e45SBoyan Karatotev write_amu_grp0_ctx_reg(ctx, 1, read_amevcntr01_el0()); 12783ec7e45SBoyan Karatotev write_amu_grp0_ctx_reg(ctx, 2, read_amevcntr02_el0()); 12883ec7e45SBoyan Karatotev write_amu_grp0_ctx_reg(ctx, 3, read_amevcntr03_el0()); 129e747a59bSChris Kay 13083ec7e45SBoyan Karatotev if (is_feat_amu_aux_supported()) { 13183ec7e45SBoyan Karatotev uint8_t num_counters = read_amcgcr_el0_cg1nc(); 132e747a59bSChris Kay 13383ec7e45SBoyan Karatotev switch (num_counters) { 13483ec7e45SBoyan Karatotev case 0x10: 13583ec7e45SBoyan Karatotev write_amu_grp1_ctx_reg(ctx, 0xf, read_amevcntr1f_el0()); 13683ec7e45SBoyan Karatotev __fallthrough; 13783ec7e45SBoyan Karatotev case 0x0f: 13883ec7e45SBoyan Karatotev write_amu_grp1_ctx_reg(ctx, 0xe, read_amevcntr1e_el0()); 13983ec7e45SBoyan Karatotev __fallthrough; 14083ec7e45SBoyan Karatotev case 0x0e: 14183ec7e45SBoyan Karatotev write_amu_grp1_ctx_reg(ctx, 0xd, read_amevcntr1d_el0()); 14283ec7e45SBoyan Karatotev __fallthrough; 14383ec7e45SBoyan Karatotev case 0x0d: 14483ec7e45SBoyan Karatotev write_amu_grp1_ctx_reg(ctx, 0xc, read_amevcntr1c_el0()); 14583ec7e45SBoyan Karatotev __fallthrough; 14683ec7e45SBoyan Karatotev case 0x0c: 14783ec7e45SBoyan Karatotev write_amu_grp1_ctx_reg(ctx, 0xb, read_amevcntr1b_el0()); 14883ec7e45SBoyan Karatotev __fallthrough; 14983ec7e45SBoyan Karatotev case 0x0b: 15083ec7e45SBoyan Karatotev write_amu_grp1_ctx_reg(ctx, 0xa, read_amevcntr1a_el0()); 15183ec7e45SBoyan Karatotev __fallthrough; 15283ec7e45SBoyan Karatotev case 0x0a: 15383ec7e45SBoyan Karatotev write_amu_grp1_ctx_reg(ctx, 0x9, read_amevcntr19_el0()); 15483ec7e45SBoyan Karatotev __fallthrough; 15583ec7e45SBoyan Karatotev case 0x09: 15683ec7e45SBoyan Karatotev write_amu_grp1_ctx_reg(ctx, 0x8, read_amevcntr18_el0()); 15783ec7e45SBoyan Karatotev __fallthrough; 15883ec7e45SBoyan Karatotev case 0x08: 15983ec7e45SBoyan Karatotev write_amu_grp1_ctx_reg(ctx, 0x7, read_amevcntr17_el0()); 16083ec7e45SBoyan Karatotev __fallthrough; 16183ec7e45SBoyan Karatotev case 0x07: 16283ec7e45SBoyan Karatotev write_amu_grp1_ctx_reg(ctx, 0x6, read_amevcntr16_el0()); 16383ec7e45SBoyan Karatotev __fallthrough; 16483ec7e45SBoyan Karatotev case 0x06: 16583ec7e45SBoyan Karatotev write_amu_grp1_ctx_reg(ctx, 0x5, read_amevcntr15_el0()); 16683ec7e45SBoyan Karatotev __fallthrough; 16783ec7e45SBoyan Karatotev case 0x05: 16883ec7e45SBoyan Karatotev write_amu_grp1_ctx_reg(ctx, 0x4, read_amevcntr14_el0()); 16983ec7e45SBoyan Karatotev __fallthrough; 17083ec7e45SBoyan Karatotev case 0x04: 17183ec7e45SBoyan Karatotev write_amu_grp1_ctx_reg(ctx, 0x3, read_amevcntr13_el0()); 17283ec7e45SBoyan Karatotev __fallthrough; 17383ec7e45SBoyan Karatotev case 0x03: 17483ec7e45SBoyan Karatotev write_amu_grp1_ctx_reg(ctx, 0x2, read_amevcntr12_el0()); 17583ec7e45SBoyan Karatotev __fallthrough; 17683ec7e45SBoyan Karatotev case 0x02: 17783ec7e45SBoyan Karatotev write_amu_grp1_ctx_reg(ctx, 0x1, read_amevcntr11_el0()); 17883ec7e45SBoyan Karatotev __fallthrough; 17983ec7e45SBoyan Karatotev case 0x01: 18083ec7e45SBoyan Karatotev write_amu_grp1_ctx_reg(ctx, 0x0, read_amevcntr10_el0()); 18183ec7e45SBoyan Karatotev __fallthrough; 18283ec7e45SBoyan Karatotev case 0x00: 18383ec7e45SBoyan Karatotev break; 18483ec7e45SBoyan Karatotev default: 18583ec7e45SBoyan Karatotev assert(0); /* something is wrong */ 1861fd685a7SChris Kay } 187e747a59bSChris Kay } 1881fd685a7SChris Kay 18940daecc1SAntonio Nino Diaz return (void *)0; 190b6eb3932SDimitris Papastamos } 191b6eb3932SDimitris Papastamos 192b6eb3932SDimitris Papastamos static void *amu_context_restore(const void *arg) 193b6eb3932SDimitris Papastamos { 194b57e16a4SAndre Przywara if (!is_feat_amu_supported()) { 195e747a59bSChris Kay return (void *)0; 196e747a59bSChris Kay } 197e747a59bSChris Kay 19883ec7e45SBoyan Karatotev unsigned int core_pos = *(unsigned int *)arg; 1990f90f374SSammit Joshi amu_regs_t *ctx = PER_CPU_CUR(amu_ctx); 200e747a59bSChris Kay 20183ec7e45SBoyan Karatotev write_amevcntr00_el0(read_amu_grp0_ctx_reg(ctx, 0)); 20283ec7e45SBoyan Karatotev write_amevcntr01_el0(read_amu_grp0_ctx_reg(ctx, 1)); 20383ec7e45SBoyan Karatotev write_amevcntr02_el0(read_amu_grp0_ctx_reg(ctx, 2)); 20483ec7e45SBoyan Karatotev write_amevcntr03_el0(read_amu_grp0_ctx_reg(ctx, 3)); 205e747a59bSChris Kay 20683ec7e45SBoyan Karatotev if (is_feat_amu_aux_supported()) { 20783ec7e45SBoyan Karatotev uint8_t num_counters = read_amcgcr_el0_cg1nc(); 20883ec7e45SBoyan Karatotev 20983ec7e45SBoyan Karatotev switch (num_counters) { 21083ec7e45SBoyan Karatotev case 0x10: 21183ec7e45SBoyan Karatotev write_amevcntr1f_el0(read_amu_grp1_ctx_reg(ctx, 0xf)); 21283ec7e45SBoyan Karatotev __fallthrough; 21383ec7e45SBoyan Karatotev case 0x0f: 21483ec7e45SBoyan Karatotev write_amevcntr1e_el0(read_amu_grp1_ctx_reg(ctx, 0xe)); 21583ec7e45SBoyan Karatotev __fallthrough; 21683ec7e45SBoyan Karatotev case 0x0e: 21783ec7e45SBoyan Karatotev write_amevcntr1d_el0(read_amu_grp1_ctx_reg(ctx, 0xd)); 21883ec7e45SBoyan Karatotev __fallthrough; 21983ec7e45SBoyan Karatotev case 0x0d: 22083ec7e45SBoyan Karatotev write_amevcntr1c_el0(read_amu_grp1_ctx_reg(ctx, 0xc)); 22183ec7e45SBoyan Karatotev __fallthrough; 22283ec7e45SBoyan Karatotev case 0x0c: 22383ec7e45SBoyan Karatotev write_amevcntr1b_el0(read_amu_grp1_ctx_reg(ctx, 0xb)); 22483ec7e45SBoyan Karatotev __fallthrough; 22583ec7e45SBoyan Karatotev case 0x0b: 22683ec7e45SBoyan Karatotev write_amevcntr1a_el0(read_amu_grp1_ctx_reg(ctx, 0xa)); 22783ec7e45SBoyan Karatotev __fallthrough; 22883ec7e45SBoyan Karatotev case 0x0a: 22983ec7e45SBoyan Karatotev write_amevcntr19_el0(read_amu_grp1_ctx_reg(ctx, 0x9)); 23083ec7e45SBoyan Karatotev __fallthrough; 23183ec7e45SBoyan Karatotev case 0x09: 23283ec7e45SBoyan Karatotev write_amevcntr18_el0(read_amu_grp1_ctx_reg(ctx, 0x8)); 23383ec7e45SBoyan Karatotev __fallthrough; 23483ec7e45SBoyan Karatotev case 0x08: 23583ec7e45SBoyan Karatotev write_amevcntr17_el0(read_amu_grp1_ctx_reg(ctx, 0x7)); 23683ec7e45SBoyan Karatotev __fallthrough; 23783ec7e45SBoyan Karatotev case 0x07: 23883ec7e45SBoyan Karatotev write_amevcntr16_el0(read_amu_grp1_ctx_reg(ctx, 0x6)); 23983ec7e45SBoyan Karatotev __fallthrough; 24083ec7e45SBoyan Karatotev case 0x06: 24183ec7e45SBoyan Karatotev write_amevcntr15_el0(read_amu_grp1_ctx_reg(ctx, 0x5)); 24283ec7e45SBoyan Karatotev __fallthrough; 24383ec7e45SBoyan Karatotev case 0x05: 24483ec7e45SBoyan Karatotev write_amevcntr14_el0(read_amu_grp1_ctx_reg(ctx, 0x4)); 24583ec7e45SBoyan Karatotev __fallthrough; 24683ec7e45SBoyan Karatotev case 0x04: 24783ec7e45SBoyan Karatotev write_amevcntr13_el0(read_amu_grp1_ctx_reg(ctx, 0x3)); 24883ec7e45SBoyan Karatotev __fallthrough; 24983ec7e45SBoyan Karatotev case 0x03: 25083ec7e45SBoyan Karatotev write_amevcntr12_el0(read_amu_grp1_ctx_reg(ctx, 0x2)); 25183ec7e45SBoyan Karatotev __fallthrough; 25283ec7e45SBoyan Karatotev case 0x02: 25383ec7e45SBoyan Karatotev write_amevcntr11_el0(read_amu_grp1_ctx_reg(ctx, 0x1)); 25483ec7e45SBoyan Karatotev __fallthrough; 25583ec7e45SBoyan Karatotev case 0x01: 25683ec7e45SBoyan Karatotev write_amevcntr10_el0(read_amu_grp1_ctx_reg(ctx, 0x0)); 25783ec7e45SBoyan Karatotev __fallthrough; 25883ec7e45SBoyan Karatotev case 0x00: 25983ec7e45SBoyan Karatotev break; 26083ec7e45SBoyan Karatotev default: 26183ec7e45SBoyan Karatotev assert(0); /* something is wrong */ 26283ec7e45SBoyan Karatotev } 263b57e16a4SAndre Przywara } 264e747a59bSChris Kay 265e747a59bSChris Kay 26683ec7e45SBoyan Karatotev /* now enable them again */ 26783ec7e45SBoyan Karatotev write_amcntenset0_el0(AMCNTENSET0_EL0_Pn_MASK); 26883ec7e45SBoyan Karatotev if (is_feat_amu_aux_supported()) { 26983ec7e45SBoyan Karatotev write_amcntenset1_el0(get_amu_aux_enables(core_pos)); 270f3ccf036SAlexei Fedorov } 271b6eb3932SDimitris Papastamos 27283ec7e45SBoyan Karatotev isb(); 27340daecc1SAntonio Nino Diaz return (void *)0; 274b6eb3932SDimitris Papastamos } 275b6eb3932SDimitris Papastamos 276b6eb3932SDimitris Papastamos SUBSCRIBE_TO_EVENT(psci_suspend_pwrdown_start, amu_context_save); 277b6eb3932SDimitris Papastamos SUBSCRIBE_TO_EVENT(psci_suspend_pwrdown_finish, amu_context_restore); 278