1380559c1SDimitris Papastamos /* 2873d4241Sjohpow01 * 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> 11873d4241Sjohpow01 #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 22873d4241Sjohpow01 /* 23873d4241Sjohpow01 * Get AMU version value from aa64pfr0. 24873d4241Sjohpow01 * Return values 25873d4241Sjohpow01 * ID_AA64PFR0_AMU_V1: FEAT_AMUv1 supported (introduced in ARM v8.4) 26873d4241Sjohpow01 * ID_AA64PFR0_AMU_V1P1: FEAT_AMUv1p1 supported (introduced in ARM v8.6) 27873d4241Sjohpow01 * ID_AA64PFR0_AMU_NOT_SUPPORTED: not supported 28873d4241Sjohpow01 */ 29*b4b726eaSChris Kay static unsigned int amu_get_version(void) 30380559c1SDimitris Papastamos { 31873d4241Sjohpow01 return (unsigned int)(read_id_aa64pfr0_el1() >> ID_AA64PFR0_AMU_SHIFT) & 32873d4241Sjohpow01 ID_AA64PFR0_AMU_MASK; 330767d50eSDimitris Papastamos } 340767d50eSDimitris Papastamos 35f3ccf036SAlexei Fedorov #if AMU_GROUP1_NR_COUNTERS 36f3ccf036SAlexei Fedorov /* Check if group 1 counters is implemented */ 37*b4b726eaSChris Kay static 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 */ 4968ac5ed0SArunachalam Ganapathy void amu_enable(bool el2_unused, cpu_context_t *ctx) 500767d50eSDimitris Papastamos { 51380559c1SDimitris Papastamos uint64_t v; 52873d4241Sjohpow01 unsigned int amu_version = amu_get_version(); 53380559c1SDimitris Papastamos 54873d4241Sjohpow01 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 /* 9168ac5ed0SArunachalam Ganapathy * Retrieve and update the CPTR_EL3 value from the context mentioned 9268ac5ed0SArunachalam Ganapathy * in 'ctx'. Set CPTR_EL3.TAM to zero so that any accesses to 93380559c1SDimitris Papastamos * the Activity Monitor registers do not trap to EL3. 94380559c1SDimitris Papastamos */ 9568ac5ed0SArunachalam Ganapathy v = read_ctx_reg(get_el3state_ctx(ctx), CTX_CPTR_EL3); 96380559c1SDimitris Papastamos v &= ~TAM_BIT; 9768ac5ed0SArunachalam Ganapathy write_ctx_reg(get_el3state_ctx(ctx), CTX_CPTR_EL3, v); 98380559c1SDimitris Papastamos 99380559c1SDimitris Papastamos /* Enable group 0 counters */ 100380559c1SDimitris Papastamos write_amcntenset0_el0(AMU_GROUP0_COUNTERS_MASK); 101f3ccf036SAlexei Fedorov 102f3ccf036SAlexei Fedorov #if AMU_GROUP1_NR_COUNTERS 10359902b7cSDimitris Papastamos /* Enable group 1 counters */ 10459902b7cSDimitris Papastamos write_amcntenset1_el0(AMU_GROUP1_COUNTERS_MASK); 105f3ccf036SAlexei Fedorov #endif 106873d4241Sjohpow01 107873d4241Sjohpow01 /* Initialize FEAT_AMUv1p1 features if present. */ 108873d4241Sjohpow01 if (amu_version < ID_AA64PFR0_AMU_V1P1) { 109873d4241Sjohpow01 return; 110873d4241Sjohpow01 } 111873d4241Sjohpow01 112873d4241Sjohpow01 if (el2_unused) { 113873d4241Sjohpow01 /* Make sure virtual offsets are disabled if EL2 not used. */ 114873d4241Sjohpow01 write_hcr_el2(read_hcr_el2() & ~HCR_AMVOFFEN_BIT); 115873d4241Sjohpow01 } 116873d4241Sjohpow01 117873d4241Sjohpow01 #if AMU_RESTRICT_COUNTERS 118873d4241Sjohpow01 /* 119873d4241Sjohpow01 * FEAT_AMUv1p1 adds a register field to restrict access to group 1 120873d4241Sjohpow01 * counters at all but the highest implemented EL. This is controlled 121873d4241Sjohpow01 * with the AMU_RESTRICT_COUNTERS compile time flag, when set, system 122873d4241Sjohpow01 * register reads at lower ELs return zero. Reads from the memory 123873d4241Sjohpow01 * mapped view are unaffected. 124873d4241Sjohpow01 */ 125873d4241Sjohpow01 VERBOSE("AMU group 1 counter access restricted.\n"); 126873d4241Sjohpow01 write_amcr_el0(read_amcr_el0() | AMCR_CG1RZ_BIT); 127873d4241Sjohpow01 #else 128873d4241Sjohpow01 write_amcr_el0(read_amcr_el0() & ~AMCR_CG1RZ_BIT); 129873d4241Sjohpow01 #endif 130380559c1SDimitris Papastamos } 1310767d50eSDimitris Papastamos 1320767d50eSDimitris Papastamos /* Read the group 0 counter identified by the given `idx`. */ 133*b4b726eaSChris Kay static uint64_t amu_group0_cnt_read(unsigned int idx) 1340767d50eSDimitris Papastamos { 135873d4241Sjohpow01 assert(amu_get_version() != ID_AA64PFR0_AMU_NOT_SUPPORTED); 136f3ccf036SAlexei Fedorov assert(idx < AMU_GROUP0_NR_COUNTERS); 1370767d50eSDimitris Papastamos 1380767d50eSDimitris Papastamos return amu_group0_cnt_read_internal(idx); 1390767d50eSDimitris Papastamos } 1400767d50eSDimitris Papastamos 141f3ccf036SAlexei Fedorov /* Write the group 0 counter identified by the given `idx` with `val` */ 142*b4b726eaSChris Kay static void amu_group0_cnt_write(unsigned int idx, uint64_t val) 1430767d50eSDimitris Papastamos { 144873d4241Sjohpow01 assert(amu_get_version() != ID_AA64PFR0_AMU_NOT_SUPPORTED); 145f3ccf036SAlexei Fedorov assert(idx < AMU_GROUP0_NR_COUNTERS); 1460767d50eSDimitris Papastamos 1470767d50eSDimitris Papastamos amu_group0_cnt_write_internal(idx, val); 1480767d50eSDimitris Papastamos isb(); 1490767d50eSDimitris Papastamos } 1500767d50eSDimitris Papastamos 151873d4241Sjohpow01 /* 152873d4241Sjohpow01 * Read the group 0 offset register for a given index. Index must be 0, 2, 153873d4241Sjohpow01 * or 3, the register for 1 does not exist. 154873d4241Sjohpow01 * 155873d4241Sjohpow01 * Using this function requires FEAT_AMUv1p1 support. 156873d4241Sjohpow01 */ 157*b4b726eaSChris Kay static uint64_t amu_group0_voffset_read(unsigned int idx) 158873d4241Sjohpow01 { 159873d4241Sjohpow01 assert(amu_get_version() >= ID_AA64PFR0_AMU_V1P1); 160873d4241Sjohpow01 assert(idx < AMU_GROUP0_NR_COUNTERS); 161873d4241Sjohpow01 assert(idx != 1U); 162873d4241Sjohpow01 163873d4241Sjohpow01 return amu_group0_voffset_read_internal(idx); 164873d4241Sjohpow01 } 165873d4241Sjohpow01 166873d4241Sjohpow01 /* 167873d4241Sjohpow01 * Write the group 0 offset register for a given index. Index must be 0, 2, or 168873d4241Sjohpow01 * 3, the register for 1 does not exist. 169873d4241Sjohpow01 * 170873d4241Sjohpow01 * Using this function requires FEAT_AMUv1p1 support. 171873d4241Sjohpow01 */ 172*b4b726eaSChris Kay static void amu_group0_voffset_write(unsigned int idx, uint64_t val) 173873d4241Sjohpow01 { 174873d4241Sjohpow01 assert(amu_get_version() >= ID_AA64PFR0_AMU_V1P1); 175873d4241Sjohpow01 assert(idx < AMU_GROUP0_NR_COUNTERS); 176873d4241Sjohpow01 assert(idx != 1U); 177873d4241Sjohpow01 178873d4241Sjohpow01 amu_group0_voffset_write_internal(idx, val); 179873d4241Sjohpow01 isb(); 180873d4241Sjohpow01 } 181873d4241Sjohpow01 182f3ccf036SAlexei Fedorov #if AMU_GROUP1_NR_COUNTERS 183f3ccf036SAlexei Fedorov /* Read the group 1 counter identified by the given `idx` */ 184*b4b726eaSChris Kay static uint64_t amu_group1_cnt_read(unsigned int idx) 1850767d50eSDimitris Papastamos { 186873d4241Sjohpow01 assert(amu_get_version() != ID_AA64PFR0_AMU_NOT_SUPPORTED); 187f3ccf036SAlexei Fedorov assert(amu_group1_supported()); 188f3ccf036SAlexei Fedorov assert(idx < AMU_GROUP1_NR_COUNTERS); 1890767d50eSDimitris Papastamos 1900767d50eSDimitris Papastamos return amu_group1_cnt_read_internal(idx); 1910767d50eSDimitris Papastamos } 1920767d50eSDimitris Papastamos 193f3ccf036SAlexei Fedorov /* Write the group 1 counter identified by the given `idx` with `val` */ 194*b4b726eaSChris Kay static void amu_group1_cnt_write(unsigned int idx, uint64_t val) 1950767d50eSDimitris Papastamos { 196873d4241Sjohpow01 assert(amu_get_version() != ID_AA64PFR0_AMU_NOT_SUPPORTED); 197f3ccf036SAlexei Fedorov assert(amu_group1_supported()); 198f3ccf036SAlexei Fedorov assert(idx < AMU_GROUP1_NR_COUNTERS); 1990767d50eSDimitris Papastamos 2000767d50eSDimitris Papastamos amu_group1_cnt_write_internal(idx, val); 2010767d50eSDimitris Papastamos isb(); 2020767d50eSDimitris Papastamos } 2030767d50eSDimitris Papastamos 2040767d50eSDimitris Papastamos /* 205873d4241Sjohpow01 * Read the group 1 offset register for a given index. 206873d4241Sjohpow01 * 207873d4241Sjohpow01 * Using this function requires FEAT_AMUv1p1 support. 208873d4241Sjohpow01 */ 209*b4b726eaSChris Kay static uint64_t amu_group1_voffset_read(unsigned int idx) 210873d4241Sjohpow01 { 211873d4241Sjohpow01 assert(amu_get_version() >= ID_AA64PFR0_AMU_V1P1); 212873d4241Sjohpow01 assert(amu_group1_supported()); 213873d4241Sjohpow01 assert(idx < AMU_GROUP1_NR_COUNTERS); 214873d4241Sjohpow01 assert(((read_amcg1idr_el0() >> AMCG1IDR_VOFF_SHIFT) & 215873d4241Sjohpow01 (1ULL << idx)) != 0ULL); 216873d4241Sjohpow01 217873d4241Sjohpow01 return amu_group1_voffset_read_internal(idx); 218873d4241Sjohpow01 } 219873d4241Sjohpow01 220873d4241Sjohpow01 /* 221873d4241Sjohpow01 * Write the group 1 offset register for a given index. 222873d4241Sjohpow01 * 223873d4241Sjohpow01 * Using this function requires FEAT_AMUv1p1 support. 224873d4241Sjohpow01 */ 225*b4b726eaSChris Kay static void amu_group1_voffset_write(unsigned int idx, uint64_t val) 226873d4241Sjohpow01 { 227873d4241Sjohpow01 assert(amu_get_version() >= ID_AA64PFR0_AMU_V1P1); 228873d4241Sjohpow01 assert(amu_group1_supported()); 229873d4241Sjohpow01 assert(idx < AMU_GROUP1_NR_COUNTERS); 230873d4241Sjohpow01 assert(((read_amcg1idr_el0() >> AMCG1IDR_VOFF_SHIFT) & 231873d4241Sjohpow01 (1ULL << idx)) != 0ULL); 232873d4241Sjohpow01 233873d4241Sjohpow01 amu_group1_voffset_write_internal(idx, val); 234873d4241Sjohpow01 isb(); 235873d4241Sjohpow01 } 236f3ccf036SAlexei Fedorov #endif /* AMU_GROUP1_NR_COUNTERS */ 237b6eb3932SDimitris Papastamos 238b6eb3932SDimitris Papastamos static void *amu_context_save(const void *arg) 239b6eb3932SDimitris Papastamos { 240b6eb3932SDimitris Papastamos struct amu_ctx *ctx = &amu_ctxs[plat_my_core_pos()]; 241f3ccf036SAlexei Fedorov unsigned int i; 242b6eb3932SDimitris Papastamos 243873d4241Sjohpow01 if (amu_get_version() == ID_AA64PFR0_AMU_NOT_SUPPORTED) { 244b6eb3932SDimitris Papastamos return (void *)-1; 245f3ccf036SAlexei Fedorov } 246b6eb3932SDimitris Papastamos 247f3ccf036SAlexei Fedorov #if AMU_GROUP1_NR_COUNTERS 248f3ccf036SAlexei Fedorov if (!amu_group1_supported()) { 249f3ccf036SAlexei Fedorov return (void *)-1; 250f3ccf036SAlexei Fedorov } 251f3ccf036SAlexei Fedorov #endif 252b6eb3932SDimitris Papastamos /* Assert that group 0/1 counter configuration is what we expect */ 253f3ccf036SAlexei Fedorov assert(read_amcntenset0_el0() == AMU_GROUP0_COUNTERS_MASK); 254b6eb3932SDimitris Papastamos 255f3ccf036SAlexei Fedorov #if AMU_GROUP1_NR_COUNTERS 256f3ccf036SAlexei Fedorov assert(read_amcntenset1_el0() == AMU_GROUP1_COUNTERS_MASK); 257f3ccf036SAlexei Fedorov #endif 258b6eb3932SDimitris Papastamos /* 259b6eb3932SDimitris Papastamos * Disable group 0/1 counters to avoid other observers like SCP sampling 260b6eb3932SDimitris Papastamos * counter values from the future via the memory mapped view. 261b6eb3932SDimitris Papastamos */ 262b6eb3932SDimitris Papastamos write_amcntenclr0_el0(AMU_GROUP0_COUNTERS_MASK); 263f3ccf036SAlexei Fedorov 264f3ccf036SAlexei Fedorov #if AMU_GROUP1_NR_COUNTERS 265b6eb3932SDimitris Papastamos write_amcntenclr1_el0(AMU_GROUP1_COUNTERS_MASK); 266f3ccf036SAlexei Fedorov #endif 267b6eb3932SDimitris Papastamos isb(); 268b6eb3932SDimitris Papastamos 269f3ccf036SAlexei Fedorov /* Save all group 0 counters */ 270f3ccf036SAlexei Fedorov for (i = 0U; i < AMU_GROUP0_NR_COUNTERS; i++) { 271b6eb3932SDimitris Papastamos ctx->group0_cnts[i] = amu_group0_cnt_read(i); 272f3ccf036SAlexei Fedorov } 273b6eb3932SDimitris Papastamos 274873d4241Sjohpow01 /* Save group 0 virtual offsets if supported and enabled. */ 275873d4241Sjohpow01 if ((amu_get_version() >= ID_AA64PFR0_AMU_V1P1) && 276873d4241Sjohpow01 ((read_hcr_el2() & HCR_AMVOFFEN_BIT) != 0ULL)) { 277873d4241Sjohpow01 /* Not using a loop because count is fixed and index 1 DNE. */ 278873d4241Sjohpow01 ctx->group0_voffsets[0U] = amu_group0_voffset_read(0U); 279873d4241Sjohpow01 ctx->group0_voffsets[1U] = amu_group0_voffset_read(2U); 280873d4241Sjohpow01 ctx->group0_voffsets[2U] = amu_group0_voffset_read(3U); 281873d4241Sjohpow01 } 282873d4241Sjohpow01 283f3ccf036SAlexei Fedorov #if AMU_GROUP1_NR_COUNTERS 284b6eb3932SDimitris Papastamos /* Save group 1 counters */ 285f3ccf036SAlexei Fedorov for (i = 0U; i < AMU_GROUP1_NR_COUNTERS; i++) { 286873d4241Sjohpow01 if ((AMU_GROUP1_COUNTERS_MASK & (1UL << i)) != 0U) { 287b6eb3932SDimitris Papastamos ctx->group1_cnts[i] = amu_group1_cnt_read(i); 288f3ccf036SAlexei Fedorov } 289f3ccf036SAlexei Fedorov } 290873d4241Sjohpow01 291873d4241Sjohpow01 /* Save group 1 virtual offsets if supported and enabled. */ 292873d4241Sjohpow01 if ((amu_get_version() >= ID_AA64PFR0_AMU_V1P1) && 293873d4241Sjohpow01 ((read_hcr_el2() & HCR_AMVOFFEN_BIT) != 0ULL)) { 294873d4241Sjohpow01 u_register_t amcg1idr = read_amcg1idr_el0() >> 295873d4241Sjohpow01 AMCG1IDR_VOFF_SHIFT; 296873d4241Sjohpow01 amcg1idr = amcg1idr & AMU_GROUP1_COUNTERS_MASK; 297873d4241Sjohpow01 298873d4241Sjohpow01 for (i = 0U; i < AMU_GROUP1_NR_COUNTERS; i++) { 299873d4241Sjohpow01 if (((amcg1idr >> i) & 1ULL) != 0ULL) { 300873d4241Sjohpow01 ctx->group1_voffsets[i] = 301873d4241Sjohpow01 amu_group1_voffset_read(i); 302873d4241Sjohpow01 } 303873d4241Sjohpow01 } 304873d4241Sjohpow01 } 305f3ccf036SAlexei Fedorov #endif 30640daecc1SAntonio Nino Diaz return (void *)0; 307b6eb3932SDimitris Papastamos } 308b6eb3932SDimitris Papastamos 309b6eb3932SDimitris Papastamos static void *amu_context_restore(const void *arg) 310b6eb3932SDimitris Papastamos { 311b6eb3932SDimitris Papastamos struct amu_ctx *ctx = &amu_ctxs[plat_my_core_pos()]; 312f3ccf036SAlexei Fedorov unsigned int i; 313b6eb3932SDimitris Papastamos 314873d4241Sjohpow01 if (amu_get_version() == ID_AA64PFR0_AMU_NOT_SUPPORTED) { 315b6eb3932SDimitris Papastamos return (void *)-1; 316f3ccf036SAlexei Fedorov } 317b6eb3932SDimitris Papastamos 318f3ccf036SAlexei Fedorov #if AMU_GROUP1_NR_COUNTERS 319f3ccf036SAlexei Fedorov if (!amu_group1_supported()) { 320f3ccf036SAlexei Fedorov return (void *)-1; 321f3ccf036SAlexei Fedorov } 322f3ccf036SAlexei Fedorov #endif 323b6eb3932SDimitris Papastamos /* Counters were disabled in `amu_context_save()` */ 324f3ccf036SAlexei Fedorov assert(read_amcntenset0_el0() == 0U); 325b6eb3932SDimitris Papastamos 326f3ccf036SAlexei Fedorov #if AMU_GROUP1_NR_COUNTERS 327f3ccf036SAlexei Fedorov assert(read_amcntenset1_el0() == 0U); 328f3ccf036SAlexei Fedorov #endif 329b6eb3932SDimitris Papastamos 330f3ccf036SAlexei Fedorov /* Restore all group 0 counters */ 331f3ccf036SAlexei Fedorov for (i = 0U; i < AMU_GROUP0_NR_COUNTERS; i++) { 332b6eb3932SDimitris Papastamos amu_group0_cnt_write(i, ctx->group0_cnts[i]); 333f3ccf036SAlexei Fedorov } 334b6eb3932SDimitris Papastamos 335873d4241Sjohpow01 /* Restore group 0 virtual offsets if supported and enabled. */ 336873d4241Sjohpow01 if ((amu_get_version() >= ID_AA64PFR0_AMU_V1P1) && 337873d4241Sjohpow01 ((read_hcr_el2() & HCR_AMVOFFEN_BIT) != 0ULL)) { 338873d4241Sjohpow01 /* Not using a loop because count is fixed and index 1 DNE. */ 339873d4241Sjohpow01 amu_group0_voffset_write(0U, ctx->group0_voffsets[0U]); 340873d4241Sjohpow01 amu_group0_voffset_write(2U, ctx->group0_voffsets[1U]); 341873d4241Sjohpow01 amu_group0_voffset_write(3U, ctx->group0_voffsets[2U]); 342873d4241Sjohpow01 } 343873d4241Sjohpow01 344f3ccf036SAlexei Fedorov /* Restore group 0 counter configuration */ 345b6eb3932SDimitris Papastamos write_amcntenset0_el0(AMU_GROUP0_COUNTERS_MASK); 346f3ccf036SAlexei Fedorov 347f3ccf036SAlexei Fedorov #if AMU_GROUP1_NR_COUNTERS 348f3ccf036SAlexei Fedorov /* Restore group 1 counters */ 349f3ccf036SAlexei Fedorov for (i = 0U; i < AMU_GROUP1_NR_COUNTERS; i++) { 350873d4241Sjohpow01 if ((AMU_GROUP1_COUNTERS_MASK & (1UL << i)) != 0U) { 351f3ccf036SAlexei Fedorov amu_group1_cnt_write(i, ctx->group1_cnts[i]); 352f3ccf036SAlexei Fedorov } 353f3ccf036SAlexei Fedorov } 354f3ccf036SAlexei Fedorov 355873d4241Sjohpow01 /* Restore group 1 virtual offsets if supported and enabled. */ 356873d4241Sjohpow01 if ((amu_get_version() >= ID_AA64PFR0_AMU_V1P1) && 357873d4241Sjohpow01 ((read_hcr_el2() & HCR_AMVOFFEN_BIT) != 0ULL)) { 358873d4241Sjohpow01 u_register_t amcg1idr = read_amcg1idr_el0() >> 359873d4241Sjohpow01 AMCG1IDR_VOFF_SHIFT; 360873d4241Sjohpow01 amcg1idr = amcg1idr & AMU_GROUP1_COUNTERS_MASK; 361873d4241Sjohpow01 362873d4241Sjohpow01 for (i = 0U; i < AMU_GROUP1_NR_COUNTERS; i++) { 363873d4241Sjohpow01 if (((amcg1idr >> i) & 1ULL) != 0ULL) { 364873d4241Sjohpow01 amu_group1_voffset_write(i, 365873d4241Sjohpow01 ctx->group1_voffsets[i]); 366873d4241Sjohpow01 } 367873d4241Sjohpow01 } 368873d4241Sjohpow01 } 369873d4241Sjohpow01 370f3ccf036SAlexei Fedorov /* Restore group 1 counter configuration */ 371b6eb3932SDimitris Papastamos write_amcntenset1_el0(AMU_GROUP1_COUNTERS_MASK); 372f3ccf036SAlexei Fedorov #endif 373b6eb3932SDimitris Papastamos 37440daecc1SAntonio Nino Diaz return (void *)0; 375b6eb3932SDimitris Papastamos } 376b6eb3932SDimitris Papastamos 377b6eb3932SDimitris Papastamos SUBSCRIBE_TO_EVENT(psci_suspend_pwrdown_start, amu_context_save); 378b6eb3932SDimitris Papastamos SUBSCRIBE_TO_EVENT(psci_suspend_pwrdown_finish, amu_context_restore); 379