1380559c1SDimitris Papastamos /* 2*873d4241Sjohpow01 * Copyright (c) 2017-2021, 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> 809d40e0eSAntonio Nino Diaz #include <stdbool.h> 909d40e0eSAntonio Nino Diaz 10380559c1SDimitris Papastamos #include <arch.h> 11*873d4241Sjohpow01 #include <arch_features.h> 12380559c1SDimitris Papastamos #include <arch_helpers.h> 13f3ccf036SAlexei Fedorov 1409d40e0eSAntonio Nino Diaz #include <lib/el3_runtime/pubsub_events.h> 1509d40e0eSAntonio Nino Diaz #include <lib/extensions/amu.h> 1609d40e0eSAntonio Nino Diaz #include <lib/extensions/amu_private.h> 17f3ccf036SAlexei Fedorov 1809d40e0eSAntonio Nino Diaz #include <plat/common/platform.h> 19380559c1SDimitris Papastamos 20b6eb3932SDimitris Papastamos static struct amu_ctx amu_ctxs[PLATFORM_CORE_COUNT]; 21b6eb3932SDimitris Papastamos 22*873d4241Sjohpow01 /* 23*873d4241Sjohpow01 * Get AMU version value from aa64pfr0. 24*873d4241Sjohpow01 * Return values 25*873d4241Sjohpow01 * ID_AA64PFR0_AMU_V1: FEAT_AMUv1 supported (introduced in ARM v8.4) 26*873d4241Sjohpow01 * ID_AA64PFR0_AMU_V1P1: FEAT_AMUv1p1 supported (introduced in ARM v8.6) 27*873d4241Sjohpow01 * ID_AA64PFR0_AMU_NOT_SUPPORTED: not supported 28*873d4241Sjohpow01 */ 29*873d4241Sjohpow01 unsigned int amu_get_version(void) 30380559c1SDimitris Papastamos { 31*873d4241Sjohpow01 return (unsigned int)(read_id_aa64pfr0_el1() >> ID_AA64PFR0_AMU_SHIFT) & 32*873d4241Sjohpow01 ID_AA64PFR0_AMU_MASK; 330767d50eSDimitris Papastamos } 340767d50eSDimitris Papastamos 35f3ccf036SAlexei Fedorov #if AMU_GROUP1_NR_COUNTERS 36f3ccf036SAlexei Fedorov /* Check if group 1 counters is implemented */ 37f3ccf036SAlexei Fedorov bool amu_group1_supported(void) 38f3ccf036SAlexei Fedorov { 39f3ccf036SAlexei Fedorov uint64_t features = read_amcfgr_el0() >> AMCFGR_EL0_NCG_SHIFT; 40f3ccf036SAlexei Fedorov 41f3ccf036SAlexei Fedorov return (features & AMCFGR_EL0_NCG_MASK) == 1U; 42f3ccf036SAlexei Fedorov } 43f3ccf036SAlexei Fedorov #endif 44f3ccf036SAlexei Fedorov 450767d50eSDimitris Papastamos /* 460767d50eSDimitris Papastamos * Enable counters. This function is meant to be invoked 470767d50eSDimitris Papastamos * by the context management library before exiting from EL3. 480767d50eSDimitris Papastamos */ 4940daecc1SAntonio Nino Diaz void amu_enable(bool el2_unused) 500767d50eSDimitris Papastamos { 51380559c1SDimitris Papastamos uint64_t v; 52*873d4241Sjohpow01 unsigned int amu_version = amu_get_version(); 53380559c1SDimitris Papastamos 54*873d4241Sjohpow01 if (amu_version == ID_AA64PFR0_AMU_NOT_SUPPORTED) { 550767d50eSDimitris Papastamos return; 56f3ccf036SAlexei Fedorov } 57f3ccf036SAlexei Fedorov 58f3ccf036SAlexei Fedorov #if AMU_GROUP1_NR_COUNTERS 59f3ccf036SAlexei Fedorov /* Check and set presence of group 1 counters */ 60f3ccf036SAlexei Fedorov if (!amu_group1_supported()) { 61f3ccf036SAlexei Fedorov ERROR("AMU Counter Group 1 is not implemented\n"); 62f3ccf036SAlexei Fedorov panic(); 63f3ccf036SAlexei Fedorov } 64f3ccf036SAlexei Fedorov 65f3ccf036SAlexei Fedorov /* Check number of group 1 counters */ 66f3ccf036SAlexei Fedorov uint64_t cnt_num = (read_amcgcr_el0() >> AMCGCR_EL0_CG1NC_SHIFT) & 67f3ccf036SAlexei Fedorov AMCGCR_EL0_CG1NC_MASK; 68f3ccf036SAlexei Fedorov VERBOSE("%s%llu. %s%u\n", 69f3ccf036SAlexei Fedorov "Number of AMU Group 1 Counters ", cnt_num, 70f3ccf036SAlexei Fedorov "Requested number ", AMU_GROUP1_NR_COUNTERS); 71f3ccf036SAlexei Fedorov 72f3ccf036SAlexei Fedorov if (cnt_num < AMU_GROUP1_NR_COUNTERS) { 73f3ccf036SAlexei Fedorov ERROR("%s%llu is less than %s%u\n", 74f3ccf036SAlexei Fedorov "Number of AMU Group 1 Counters ", cnt_num, 75f3ccf036SAlexei Fedorov "Requested number ", AMU_GROUP1_NR_COUNTERS); 76f3ccf036SAlexei Fedorov panic(); 77f3ccf036SAlexei Fedorov } 78f3ccf036SAlexei Fedorov #endif 790767d50eSDimitris Papastamos 80380559c1SDimitris Papastamos if (el2_unused) { 81380559c1SDimitris Papastamos /* 82380559c1SDimitris Papastamos * CPTR_EL2.TAM: Set to zero so any accesses to 83380559c1SDimitris Papastamos * the Activity Monitor registers do not trap to EL2. 84380559c1SDimitris Papastamos */ 85380559c1SDimitris Papastamos v = read_cptr_el2(); 86380559c1SDimitris Papastamos v &= ~CPTR_EL2_TAM_BIT; 87380559c1SDimitris Papastamos write_cptr_el2(v); 88380559c1SDimitris Papastamos } 89380559c1SDimitris Papastamos 90380559c1SDimitris Papastamos /* 91380559c1SDimitris Papastamos * CPTR_EL3.TAM: Set to zero so that any accesses to 92380559c1SDimitris Papastamos * the Activity Monitor registers do not trap to EL3. 93380559c1SDimitris Papastamos */ 94380559c1SDimitris Papastamos v = read_cptr_el3(); 95380559c1SDimitris Papastamos v &= ~TAM_BIT; 96380559c1SDimitris Papastamos write_cptr_el3(v); 97380559c1SDimitris Papastamos 98380559c1SDimitris Papastamos /* Enable group 0 counters */ 99380559c1SDimitris Papastamos write_amcntenset0_el0(AMU_GROUP0_COUNTERS_MASK); 100f3ccf036SAlexei Fedorov 101f3ccf036SAlexei Fedorov #if AMU_GROUP1_NR_COUNTERS 10259902b7cSDimitris Papastamos /* Enable group 1 counters */ 10359902b7cSDimitris Papastamos write_amcntenset1_el0(AMU_GROUP1_COUNTERS_MASK); 104f3ccf036SAlexei Fedorov #endif 105*873d4241Sjohpow01 106*873d4241Sjohpow01 /* Initialize FEAT_AMUv1p1 features if present. */ 107*873d4241Sjohpow01 if (amu_version < ID_AA64PFR0_AMU_V1P1) { 108*873d4241Sjohpow01 return; 109*873d4241Sjohpow01 } 110*873d4241Sjohpow01 111*873d4241Sjohpow01 if (el2_unused) { 112*873d4241Sjohpow01 /* Make sure virtual offsets are disabled if EL2 not used. */ 113*873d4241Sjohpow01 write_hcr_el2(read_hcr_el2() & ~HCR_AMVOFFEN_BIT); 114*873d4241Sjohpow01 } 115*873d4241Sjohpow01 116*873d4241Sjohpow01 #if AMU_RESTRICT_COUNTERS 117*873d4241Sjohpow01 /* 118*873d4241Sjohpow01 * FEAT_AMUv1p1 adds a register field to restrict access to group 1 119*873d4241Sjohpow01 * counters at all but the highest implemented EL. This is controlled 120*873d4241Sjohpow01 * with the AMU_RESTRICT_COUNTERS compile time flag, when set, system 121*873d4241Sjohpow01 * register reads at lower ELs return zero. Reads from the memory 122*873d4241Sjohpow01 * mapped view are unaffected. 123*873d4241Sjohpow01 */ 124*873d4241Sjohpow01 VERBOSE("AMU group 1 counter access restricted.\n"); 125*873d4241Sjohpow01 write_amcr_el0(read_amcr_el0() | AMCR_CG1RZ_BIT); 126*873d4241Sjohpow01 #else 127*873d4241Sjohpow01 write_amcr_el0(read_amcr_el0() & ~AMCR_CG1RZ_BIT); 128*873d4241Sjohpow01 #endif 129380559c1SDimitris Papastamos } 1300767d50eSDimitris Papastamos 1310767d50eSDimitris Papastamos /* Read the group 0 counter identified by the given `idx`. */ 132f3ccf036SAlexei Fedorov uint64_t amu_group0_cnt_read(unsigned int idx) 1330767d50eSDimitris Papastamos { 134*873d4241Sjohpow01 assert(amu_get_version() != ID_AA64PFR0_AMU_NOT_SUPPORTED); 135f3ccf036SAlexei Fedorov assert(idx < AMU_GROUP0_NR_COUNTERS); 1360767d50eSDimitris Papastamos 1370767d50eSDimitris Papastamos return amu_group0_cnt_read_internal(idx); 1380767d50eSDimitris Papastamos } 1390767d50eSDimitris Papastamos 140f3ccf036SAlexei Fedorov /* Write the group 0 counter identified by the given `idx` with `val` */ 141f3ccf036SAlexei Fedorov void amu_group0_cnt_write(unsigned int idx, uint64_t val) 1420767d50eSDimitris Papastamos { 143*873d4241Sjohpow01 assert(amu_get_version() != ID_AA64PFR0_AMU_NOT_SUPPORTED); 144f3ccf036SAlexei Fedorov assert(idx < AMU_GROUP0_NR_COUNTERS); 1450767d50eSDimitris Papastamos 1460767d50eSDimitris Papastamos amu_group0_cnt_write_internal(idx, val); 1470767d50eSDimitris Papastamos isb(); 1480767d50eSDimitris Papastamos } 1490767d50eSDimitris Papastamos 150*873d4241Sjohpow01 /* 151*873d4241Sjohpow01 * Read the group 0 offset register for a given index. Index must be 0, 2, 152*873d4241Sjohpow01 * or 3, the register for 1 does not exist. 153*873d4241Sjohpow01 * 154*873d4241Sjohpow01 * Using this function requires FEAT_AMUv1p1 support. 155*873d4241Sjohpow01 */ 156*873d4241Sjohpow01 uint64_t amu_group0_voffset_read(unsigned int idx) 157*873d4241Sjohpow01 { 158*873d4241Sjohpow01 assert(amu_get_version() >= ID_AA64PFR0_AMU_V1P1); 159*873d4241Sjohpow01 assert(idx < AMU_GROUP0_NR_COUNTERS); 160*873d4241Sjohpow01 assert(idx != 1U); 161*873d4241Sjohpow01 162*873d4241Sjohpow01 return amu_group0_voffset_read_internal(idx); 163*873d4241Sjohpow01 } 164*873d4241Sjohpow01 165*873d4241Sjohpow01 /* 166*873d4241Sjohpow01 * Write the group 0 offset register for a given index. Index must be 0, 2, or 167*873d4241Sjohpow01 * 3, the register for 1 does not exist. 168*873d4241Sjohpow01 * 169*873d4241Sjohpow01 * Using this function requires FEAT_AMUv1p1 support. 170*873d4241Sjohpow01 */ 171*873d4241Sjohpow01 void amu_group0_voffset_write(unsigned int idx, uint64_t val) 172*873d4241Sjohpow01 { 173*873d4241Sjohpow01 assert(amu_get_version() >= ID_AA64PFR0_AMU_V1P1); 174*873d4241Sjohpow01 assert(idx < AMU_GROUP0_NR_COUNTERS); 175*873d4241Sjohpow01 assert(idx != 1U); 176*873d4241Sjohpow01 177*873d4241Sjohpow01 amu_group0_voffset_write_internal(idx, val); 178*873d4241Sjohpow01 isb(); 179*873d4241Sjohpow01 } 180*873d4241Sjohpow01 181f3ccf036SAlexei Fedorov #if AMU_GROUP1_NR_COUNTERS 182f3ccf036SAlexei Fedorov /* Read the group 1 counter identified by the given `idx` */ 183f3ccf036SAlexei Fedorov uint64_t amu_group1_cnt_read(unsigned int idx) 1840767d50eSDimitris Papastamos { 185*873d4241Sjohpow01 assert(amu_get_version() != ID_AA64PFR0_AMU_NOT_SUPPORTED); 186f3ccf036SAlexei Fedorov assert(amu_group1_supported()); 187f3ccf036SAlexei Fedorov assert(idx < AMU_GROUP1_NR_COUNTERS); 1880767d50eSDimitris Papastamos 1890767d50eSDimitris Papastamos return amu_group1_cnt_read_internal(idx); 1900767d50eSDimitris Papastamos } 1910767d50eSDimitris Papastamos 192f3ccf036SAlexei Fedorov /* Write the group 1 counter identified by the given `idx` with `val` */ 193f3ccf036SAlexei Fedorov void amu_group1_cnt_write(unsigned int idx, uint64_t val) 1940767d50eSDimitris Papastamos { 195*873d4241Sjohpow01 assert(amu_get_version() != ID_AA64PFR0_AMU_NOT_SUPPORTED); 196f3ccf036SAlexei Fedorov assert(amu_group1_supported()); 197f3ccf036SAlexei Fedorov assert(idx < AMU_GROUP1_NR_COUNTERS); 1980767d50eSDimitris Papastamos 1990767d50eSDimitris Papastamos amu_group1_cnt_write_internal(idx, val); 2000767d50eSDimitris Papastamos isb(); 2010767d50eSDimitris Papastamos } 2020767d50eSDimitris Papastamos 2030767d50eSDimitris Papastamos /* 204*873d4241Sjohpow01 * Read the group 1 offset register for a given index. 205*873d4241Sjohpow01 * 206*873d4241Sjohpow01 * Using this function requires FEAT_AMUv1p1 support. 207*873d4241Sjohpow01 */ 208*873d4241Sjohpow01 uint64_t amu_group1_voffset_read(unsigned int idx) 209*873d4241Sjohpow01 { 210*873d4241Sjohpow01 assert(amu_get_version() >= ID_AA64PFR0_AMU_V1P1); 211*873d4241Sjohpow01 assert(amu_group1_supported()); 212*873d4241Sjohpow01 assert(idx < AMU_GROUP1_NR_COUNTERS); 213*873d4241Sjohpow01 assert(((read_amcg1idr_el0() >> AMCG1IDR_VOFF_SHIFT) & 214*873d4241Sjohpow01 (1ULL << idx)) != 0ULL); 215*873d4241Sjohpow01 216*873d4241Sjohpow01 return amu_group1_voffset_read_internal(idx); 217*873d4241Sjohpow01 } 218*873d4241Sjohpow01 219*873d4241Sjohpow01 /* 220*873d4241Sjohpow01 * Write the group 1 offset register for a given index. 221*873d4241Sjohpow01 * 222*873d4241Sjohpow01 * Using this function requires FEAT_AMUv1p1 support. 223*873d4241Sjohpow01 */ 224*873d4241Sjohpow01 void amu_group1_voffset_write(unsigned int idx, uint64_t val) 225*873d4241Sjohpow01 { 226*873d4241Sjohpow01 assert(amu_get_version() >= ID_AA64PFR0_AMU_V1P1); 227*873d4241Sjohpow01 assert(amu_group1_supported()); 228*873d4241Sjohpow01 assert(idx < AMU_GROUP1_NR_COUNTERS); 229*873d4241Sjohpow01 assert(((read_amcg1idr_el0() >> AMCG1IDR_VOFF_SHIFT) & 230*873d4241Sjohpow01 (1ULL << idx)) != 0ULL); 231*873d4241Sjohpow01 232*873d4241Sjohpow01 amu_group1_voffset_write_internal(idx, val); 233*873d4241Sjohpow01 isb(); 234*873d4241Sjohpow01 } 235*873d4241Sjohpow01 236*873d4241Sjohpow01 /* 2370767d50eSDimitris Papastamos * Program the event type register for the given `idx` with 238f3ccf036SAlexei Fedorov * the event number `val` 2390767d50eSDimitris Papastamos */ 240f3ccf036SAlexei Fedorov void amu_group1_set_evtype(unsigned int idx, unsigned int val) 2410767d50eSDimitris Papastamos { 242*873d4241Sjohpow01 assert(amu_get_version() != ID_AA64PFR0_AMU_NOT_SUPPORTED); 243f3ccf036SAlexei Fedorov assert(amu_group1_supported()); 244f3ccf036SAlexei Fedorov assert(idx < AMU_GROUP1_NR_COUNTERS); 2450767d50eSDimitris Papastamos 2460767d50eSDimitris Papastamos amu_group1_set_evtype_internal(idx, val); 2470767d50eSDimitris Papastamos isb(); 248380559c1SDimitris Papastamos } 249f3ccf036SAlexei Fedorov #endif /* AMU_GROUP1_NR_COUNTERS */ 250b6eb3932SDimitris Papastamos 251b6eb3932SDimitris Papastamos static void *amu_context_save(const void *arg) 252b6eb3932SDimitris Papastamos { 253b6eb3932SDimitris Papastamos struct amu_ctx *ctx = &amu_ctxs[plat_my_core_pos()]; 254f3ccf036SAlexei Fedorov unsigned int i; 255b6eb3932SDimitris Papastamos 256*873d4241Sjohpow01 if (amu_get_version() == ID_AA64PFR0_AMU_NOT_SUPPORTED) { 257b6eb3932SDimitris Papastamos return (void *)-1; 258f3ccf036SAlexei Fedorov } 259b6eb3932SDimitris Papastamos 260f3ccf036SAlexei Fedorov #if AMU_GROUP1_NR_COUNTERS 261f3ccf036SAlexei Fedorov if (!amu_group1_supported()) { 262f3ccf036SAlexei Fedorov return (void *)-1; 263f3ccf036SAlexei Fedorov } 264f3ccf036SAlexei Fedorov #endif 265b6eb3932SDimitris Papastamos /* Assert that group 0/1 counter configuration is what we expect */ 266f3ccf036SAlexei Fedorov assert(read_amcntenset0_el0() == AMU_GROUP0_COUNTERS_MASK); 267b6eb3932SDimitris Papastamos 268f3ccf036SAlexei Fedorov #if AMU_GROUP1_NR_COUNTERS 269f3ccf036SAlexei Fedorov assert(read_amcntenset1_el0() == AMU_GROUP1_COUNTERS_MASK); 270f3ccf036SAlexei Fedorov #endif 271b6eb3932SDimitris Papastamos /* 272b6eb3932SDimitris Papastamos * Disable group 0/1 counters to avoid other observers like SCP sampling 273b6eb3932SDimitris Papastamos * counter values from the future via the memory mapped view. 274b6eb3932SDimitris Papastamos */ 275b6eb3932SDimitris Papastamos write_amcntenclr0_el0(AMU_GROUP0_COUNTERS_MASK); 276f3ccf036SAlexei Fedorov 277f3ccf036SAlexei Fedorov #if AMU_GROUP1_NR_COUNTERS 278b6eb3932SDimitris Papastamos write_amcntenclr1_el0(AMU_GROUP1_COUNTERS_MASK); 279f3ccf036SAlexei Fedorov #endif 280b6eb3932SDimitris Papastamos isb(); 281b6eb3932SDimitris Papastamos 282f3ccf036SAlexei Fedorov /* Save all group 0 counters */ 283f3ccf036SAlexei Fedorov for (i = 0U; i < AMU_GROUP0_NR_COUNTERS; i++) { 284b6eb3932SDimitris Papastamos ctx->group0_cnts[i] = amu_group0_cnt_read(i); 285f3ccf036SAlexei Fedorov } 286b6eb3932SDimitris Papastamos 287*873d4241Sjohpow01 /* Save group 0 virtual offsets if supported and enabled. */ 288*873d4241Sjohpow01 if ((amu_get_version() >= ID_AA64PFR0_AMU_V1P1) && 289*873d4241Sjohpow01 ((read_hcr_el2() & HCR_AMVOFFEN_BIT) != 0ULL)) { 290*873d4241Sjohpow01 /* Not using a loop because count is fixed and index 1 DNE. */ 291*873d4241Sjohpow01 ctx->group0_voffsets[0U] = amu_group0_voffset_read(0U); 292*873d4241Sjohpow01 ctx->group0_voffsets[1U] = amu_group0_voffset_read(2U); 293*873d4241Sjohpow01 ctx->group0_voffsets[2U] = amu_group0_voffset_read(3U); 294*873d4241Sjohpow01 } 295*873d4241Sjohpow01 296f3ccf036SAlexei Fedorov #if AMU_GROUP1_NR_COUNTERS 297b6eb3932SDimitris Papastamos /* Save group 1 counters */ 298f3ccf036SAlexei Fedorov for (i = 0U; i < AMU_GROUP1_NR_COUNTERS; i++) { 299*873d4241Sjohpow01 if ((AMU_GROUP1_COUNTERS_MASK & (1UL << i)) != 0U) { 300b6eb3932SDimitris Papastamos ctx->group1_cnts[i] = amu_group1_cnt_read(i); 301f3ccf036SAlexei Fedorov } 302f3ccf036SAlexei Fedorov } 303*873d4241Sjohpow01 304*873d4241Sjohpow01 /* Save group 1 virtual offsets if supported and enabled. */ 305*873d4241Sjohpow01 if ((amu_get_version() >= ID_AA64PFR0_AMU_V1P1) && 306*873d4241Sjohpow01 ((read_hcr_el2() & HCR_AMVOFFEN_BIT) != 0ULL)) { 307*873d4241Sjohpow01 u_register_t amcg1idr = read_amcg1idr_el0() >> 308*873d4241Sjohpow01 AMCG1IDR_VOFF_SHIFT; 309*873d4241Sjohpow01 amcg1idr = amcg1idr & AMU_GROUP1_COUNTERS_MASK; 310*873d4241Sjohpow01 311*873d4241Sjohpow01 for (i = 0U; i < AMU_GROUP1_NR_COUNTERS; i++) { 312*873d4241Sjohpow01 if (((amcg1idr >> i) & 1ULL) != 0ULL) { 313*873d4241Sjohpow01 ctx->group1_voffsets[i] = 314*873d4241Sjohpow01 amu_group1_voffset_read(i); 315*873d4241Sjohpow01 } 316*873d4241Sjohpow01 } 317*873d4241Sjohpow01 } 318f3ccf036SAlexei Fedorov #endif 31940daecc1SAntonio Nino Diaz return (void *)0; 320b6eb3932SDimitris Papastamos } 321b6eb3932SDimitris Papastamos 322b6eb3932SDimitris Papastamos static void *amu_context_restore(const void *arg) 323b6eb3932SDimitris Papastamos { 324b6eb3932SDimitris Papastamos struct amu_ctx *ctx = &amu_ctxs[plat_my_core_pos()]; 325f3ccf036SAlexei Fedorov unsigned int i; 326b6eb3932SDimitris Papastamos 327*873d4241Sjohpow01 if (amu_get_version() == ID_AA64PFR0_AMU_NOT_SUPPORTED) { 328b6eb3932SDimitris Papastamos return (void *)-1; 329f3ccf036SAlexei Fedorov } 330b6eb3932SDimitris Papastamos 331f3ccf036SAlexei Fedorov #if AMU_GROUP1_NR_COUNTERS 332f3ccf036SAlexei Fedorov if (!amu_group1_supported()) { 333f3ccf036SAlexei Fedorov return (void *)-1; 334f3ccf036SAlexei Fedorov } 335f3ccf036SAlexei Fedorov #endif 336b6eb3932SDimitris Papastamos /* Counters were disabled in `amu_context_save()` */ 337f3ccf036SAlexei Fedorov assert(read_amcntenset0_el0() == 0U); 338b6eb3932SDimitris Papastamos 339f3ccf036SAlexei Fedorov #if AMU_GROUP1_NR_COUNTERS 340f3ccf036SAlexei Fedorov assert(read_amcntenset1_el0() == 0U); 341f3ccf036SAlexei Fedorov #endif 342b6eb3932SDimitris Papastamos 343f3ccf036SAlexei Fedorov /* Restore all group 0 counters */ 344f3ccf036SAlexei Fedorov for (i = 0U; i < AMU_GROUP0_NR_COUNTERS; i++) { 345b6eb3932SDimitris Papastamos amu_group0_cnt_write(i, ctx->group0_cnts[i]); 346f3ccf036SAlexei Fedorov } 347b6eb3932SDimitris Papastamos 348*873d4241Sjohpow01 /* Restore group 0 virtual offsets if supported and enabled. */ 349*873d4241Sjohpow01 if ((amu_get_version() >= ID_AA64PFR0_AMU_V1P1) && 350*873d4241Sjohpow01 ((read_hcr_el2() & HCR_AMVOFFEN_BIT) != 0ULL)) { 351*873d4241Sjohpow01 /* Not using a loop because count is fixed and index 1 DNE. */ 352*873d4241Sjohpow01 amu_group0_voffset_write(0U, ctx->group0_voffsets[0U]); 353*873d4241Sjohpow01 amu_group0_voffset_write(2U, ctx->group0_voffsets[1U]); 354*873d4241Sjohpow01 amu_group0_voffset_write(3U, ctx->group0_voffsets[2U]); 355*873d4241Sjohpow01 } 356*873d4241Sjohpow01 357f3ccf036SAlexei Fedorov /* Restore group 0 counter configuration */ 358b6eb3932SDimitris Papastamos write_amcntenset0_el0(AMU_GROUP0_COUNTERS_MASK); 359f3ccf036SAlexei Fedorov 360f3ccf036SAlexei Fedorov #if AMU_GROUP1_NR_COUNTERS 361f3ccf036SAlexei Fedorov /* Restore group 1 counters */ 362f3ccf036SAlexei Fedorov for (i = 0U; i < AMU_GROUP1_NR_COUNTERS; i++) { 363*873d4241Sjohpow01 if ((AMU_GROUP1_COUNTERS_MASK & (1UL << i)) != 0U) { 364f3ccf036SAlexei Fedorov amu_group1_cnt_write(i, ctx->group1_cnts[i]); 365f3ccf036SAlexei Fedorov } 366f3ccf036SAlexei Fedorov } 367f3ccf036SAlexei Fedorov 368*873d4241Sjohpow01 /* Restore group 1 virtual offsets if supported and enabled. */ 369*873d4241Sjohpow01 if ((amu_get_version() >= ID_AA64PFR0_AMU_V1P1) && 370*873d4241Sjohpow01 ((read_hcr_el2() & HCR_AMVOFFEN_BIT) != 0ULL)) { 371*873d4241Sjohpow01 u_register_t amcg1idr = read_amcg1idr_el0() >> 372*873d4241Sjohpow01 AMCG1IDR_VOFF_SHIFT; 373*873d4241Sjohpow01 amcg1idr = amcg1idr & AMU_GROUP1_COUNTERS_MASK; 374*873d4241Sjohpow01 375*873d4241Sjohpow01 for (i = 0U; i < AMU_GROUP1_NR_COUNTERS; i++) { 376*873d4241Sjohpow01 if (((amcg1idr >> i) & 1ULL) != 0ULL) { 377*873d4241Sjohpow01 amu_group1_voffset_write(i, 378*873d4241Sjohpow01 ctx->group1_voffsets[i]); 379*873d4241Sjohpow01 } 380*873d4241Sjohpow01 } 381*873d4241Sjohpow01 } 382*873d4241Sjohpow01 383f3ccf036SAlexei Fedorov /* Restore group 1 counter configuration */ 384b6eb3932SDimitris Papastamos write_amcntenset1_el0(AMU_GROUP1_COUNTERS_MASK); 385f3ccf036SAlexei Fedorov #endif 386b6eb3932SDimitris Papastamos 38740daecc1SAntonio Nino Diaz return (void *)0; 388b6eb3932SDimitris Papastamos } 389b6eb3932SDimitris Papastamos 390b6eb3932SDimitris Papastamos SUBSCRIBE_TO_EVENT(psci_suspend_pwrdown_start, amu_context_save); 391b6eb3932SDimitris Papastamos SUBSCRIBE_TO_EVENT(psci_suspend_pwrdown_finish, amu_context_restore); 392