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> 833b9be6dSChris Kay #include <cdefs.h> 909d40e0eSAntonio Nino Diaz #include <stdbool.h> 1009d40e0eSAntonio Nino Diaz 11380559c1SDimitris Papastamos #include <arch.h> 12873d4241Sjohpow01 #include <arch_features.h> 13380559c1SDimitris Papastamos #include <arch_helpers.h> 14f3ccf036SAlexei Fedorov 1509d40e0eSAntonio Nino Diaz #include <lib/el3_runtime/pubsub_events.h> 1609d40e0eSAntonio Nino Diaz #include <lib/extensions/amu.h> 1709d40e0eSAntonio Nino Diaz #include <lib/extensions/amu_private.h> 18f3ccf036SAlexei Fedorov 1909d40e0eSAntonio Nino Diaz #include <plat/common/platform.h> 20380559c1SDimitris Papastamos 21b6eb3932SDimitris Papastamos static struct amu_ctx amu_ctxs[PLATFORM_CORE_COUNT]; 22b6eb3932SDimitris Papastamos 2333b9be6dSChris Kay static inline __unused uint64_t read_id_aa64pfr0_el1_amu(void) 24380559c1SDimitris Papastamos { 2533b9be6dSChris Kay return (read_id_aa64pfr0_el1() >> ID_AA64PFR0_AMU_SHIFT) & 26873d4241Sjohpow01 ID_AA64PFR0_AMU_MASK; 270767d50eSDimitris Papastamos } 280767d50eSDimitris Papastamos 2933b9be6dSChris Kay static inline __unused uint64_t read_hcr_el2_amvoffen(void) 3033b9be6dSChris Kay { 3133b9be6dSChris Kay return (read_hcr_el2() & HCR_AMVOFFEN_BIT) >> 3233b9be6dSChris Kay HCR_AMVOFFEN_SHIFT; 3333b9be6dSChris Kay } 3433b9be6dSChris Kay 3533b9be6dSChris Kay static inline __unused void write_cptr_el2_tam(uint64_t value) 3633b9be6dSChris Kay { 3733b9be6dSChris Kay write_cptr_el2((read_cptr_el2() & ~CPTR_EL2_TAM_BIT) | 3833b9be6dSChris Kay ((value << CPTR_EL2_TAM_SHIFT) & CPTR_EL2_TAM_BIT)); 3933b9be6dSChris Kay } 4033b9be6dSChris Kay 4133b9be6dSChris Kay static inline __unused void write_cptr_el3_tam(cpu_context_t *ctx, uint64_t tam) 4233b9be6dSChris Kay { 4333b9be6dSChris Kay uint64_t value = read_ctx_reg(get_el3state_ctx(ctx), CTX_CPTR_EL3); 4433b9be6dSChris Kay 4533b9be6dSChris Kay value &= ~TAM_BIT; 4633b9be6dSChris Kay value |= (tam << TAM_SHIFT) & TAM_BIT; 4733b9be6dSChris Kay 4833b9be6dSChris Kay write_ctx_reg(get_el3state_ctx(ctx), CTX_CPTR_EL3, value); 4933b9be6dSChris Kay } 5033b9be6dSChris Kay 5133b9be6dSChris Kay static inline __unused void write_hcr_el2_amvoffen(uint64_t value) 5233b9be6dSChris Kay { 5333b9be6dSChris Kay write_hcr_el2((read_hcr_el2() & ~HCR_AMVOFFEN_BIT) | 5433b9be6dSChris Kay ((value << HCR_AMVOFFEN_SHIFT) & HCR_AMVOFFEN_BIT)); 5533b9be6dSChris Kay } 5633b9be6dSChris Kay 5733b9be6dSChris Kay static inline __unused void write_amcr_el0_cg1rz(uint64_t value) 5833b9be6dSChris Kay { 5933b9be6dSChris Kay write_amcr_el0((read_amcr_el0() & ~AMCR_CG1RZ_BIT) | 6033b9be6dSChris Kay ((value << AMCR_CG1RZ_SHIFT) & AMCR_CG1RZ_BIT)); 6133b9be6dSChris Kay } 6233b9be6dSChris Kay 6333b9be6dSChris Kay static inline __unused uint64_t read_amcfgr_el0_ncg(void) 6433b9be6dSChris Kay { 6533b9be6dSChris Kay return (read_amcfgr_el0() >> AMCFGR_EL0_NCG_SHIFT) & 6633b9be6dSChris Kay AMCFGR_EL0_NCG_MASK; 6733b9be6dSChris Kay } 6833b9be6dSChris Kay 6981e2ff1fSChris Kay static inline uint64_t read_amcgcr_el0_cg0nc(void) 7081e2ff1fSChris Kay { 7181e2ff1fSChris Kay return (read_amcgcr_el0() >> AMCGCR_EL0_CG0NC_SHIFT) & 7281e2ff1fSChris Kay AMCGCR_EL0_CG0NC_MASK; 7381e2ff1fSChris Kay } 7481e2ff1fSChris Kay 7533b9be6dSChris Kay static inline __unused uint64_t read_amcg1idr_el0_voff(void) 7633b9be6dSChris Kay { 7733b9be6dSChris Kay return (read_amcg1idr_el0() >> AMCG1IDR_VOFF_SHIFT) & 7833b9be6dSChris Kay AMCG1IDR_VOFF_MASK; 7933b9be6dSChris Kay } 8033b9be6dSChris Kay 8133b9be6dSChris Kay static inline __unused uint64_t read_amcgcr_el0_cg1nc(void) 8233b9be6dSChris Kay { 8333b9be6dSChris Kay return (read_amcgcr_el0() >> AMCGCR_EL0_CG1NC_SHIFT) & 8433b9be6dSChris Kay AMCGCR_EL0_CG1NC_MASK; 8533b9be6dSChris Kay } 8633b9be6dSChris Kay 8733b9be6dSChris Kay static inline __unused uint64_t read_amcntenset0_el0_px(void) 8833b9be6dSChris Kay { 8933b9be6dSChris Kay return (read_amcntenset0_el0() >> AMCNTENSET0_EL0_Pn_SHIFT) & 9033b9be6dSChris Kay AMCNTENSET0_EL0_Pn_MASK; 9133b9be6dSChris Kay } 9233b9be6dSChris Kay 9333b9be6dSChris Kay static inline __unused uint64_t read_amcntenset1_el0_px(void) 9433b9be6dSChris Kay { 9533b9be6dSChris Kay return (read_amcntenset1_el0() >> AMCNTENSET1_EL0_Pn_SHIFT) & 9633b9be6dSChris Kay AMCNTENSET1_EL0_Pn_MASK; 9733b9be6dSChris Kay } 9833b9be6dSChris Kay 9933b9be6dSChris Kay static inline __unused void write_amcntenset0_el0_px(uint64_t px) 10033b9be6dSChris Kay { 10133b9be6dSChris Kay uint64_t value = read_amcntenset0_el0(); 10233b9be6dSChris Kay 10333b9be6dSChris Kay value &= ~AMCNTENSET0_EL0_Pn_MASK; 10433b9be6dSChris Kay value |= (px << AMCNTENSET0_EL0_Pn_SHIFT) & AMCNTENSET0_EL0_Pn_MASK; 10533b9be6dSChris Kay 10633b9be6dSChris Kay write_amcntenset0_el0(value); 10733b9be6dSChris Kay } 10833b9be6dSChris Kay 10933b9be6dSChris Kay static inline __unused void write_amcntenset1_el0_px(uint64_t px) 11033b9be6dSChris Kay { 11133b9be6dSChris Kay uint64_t value = read_amcntenset1_el0(); 11233b9be6dSChris Kay 11333b9be6dSChris Kay value &= ~AMCNTENSET1_EL0_Pn_MASK; 11433b9be6dSChris Kay value |= (px << AMCNTENSET1_EL0_Pn_SHIFT) & AMCNTENSET1_EL0_Pn_MASK; 11533b9be6dSChris Kay 11633b9be6dSChris Kay write_amcntenset1_el0(value); 11733b9be6dSChris Kay } 11833b9be6dSChris Kay 11933b9be6dSChris Kay static inline __unused void write_amcntenclr0_el0_px(uint64_t px) 12033b9be6dSChris Kay { 12133b9be6dSChris Kay uint64_t value = read_amcntenclr0_el0(); 12233b9be6dSChris Kay 12333b9be6dSChris Kay value &= ~AMCNTENCLR0_EL0_Pn_MASK; 12433b9be6dSChris Kay value |= (px << AMCNTENCLR0_EL0_Pn_SHIFT) & AMCNTENCLR0_EL0_Pn_MASK; 12533b9be6dSChris Kay 12633b9be6dSChris Kay write_amcntenclr0_el0(value); 12733b9be6dSChris Kay } 12833b9be6dSChris Kay 12933b9be6dSChris Kay static inline __unused void write_amcntenclr1_el0_px(uint64_t px) 13033b9be6dSChris Kay { 13133b9be6dSChris Kay uint64_t value = read_amcntenclr1_el0(); 13233b9be6dSChris Kay 13333b9be6dSChris Kay value &= ~AMCNTENCLR1_EL0_Pn_MASK; 13433b9be6dSChris Kay value |= (px << AMCNTENCLR1_EL0_Pn_SHIFT) & AMCNTENCLR1_EL0_Pn_MASK; 13533b9be6dSChris Kay 13633b9be6dSChris Kay write_amcntenclr1_el0(value); 13733b9be6dSChris Kay } 13833b9be6dSChris Kay 13933b9be6dSChris Kay static bool amu_supported(void) 14033b9be6dSChris Kay { 14133b9be6dSChris Kay return read_id_aa64pfr0_el1_amu() >= ID_AA64PFR0_AMU_V1; 14233b9be6dSChris Kay } 14333b9be6dSChris Kay 14433b9be6dSChris Kay static bool amu_v1p1_supported(void) 14533b9be6dSChris Kay { 14633b9be6dSChris Kay return read_id_aa64pfr0_el1_amu() >= ID_AA64PFR0_AMU_V1P1; 14733b9be6dSChris Kay } 14833b9be6dSChris Kay 14933b9be6dSChris Kay #if ENABLE_AMU_AUXILIARY_COUNTERS 150b4b726eaSChris Kay static bool amu_group1_supported(void) 151f3ccf036SAlexei Fedorov { 15233b9be6dSChris Kay return read_amcfgr_el0_ncg() > 0U; 153f3ccf036SAlexei Fedorov } 154f3ccf036SAlexei Fedorov #endif 155f3ccf036SAlexei Fedorov 1560767d50eSDimitris Papastamos /* 1570767d50eSDimitris Papastamos * Enable counters. This function is meant to be invoked 1580767d50eSDimitris Papastamos * by the context management library before exiting from EL3. 1590767d50eSDimitris Papastamos */ 16068ac5ed0SArunachalam Ganapathy void amu_enable(bool el2_unused, cpu_context_t *ctx) 1610767d50eSDimitris Papastamos { 16233b9be6dSChris Kay if (!amu_supported()) { 1630767d50eSDimitris Papastamos return; 164f3ccf036SAlexei Fedorov } 165f3ccf036SAlexei Fedorov 166380559c1SDimitris Papastamos if (el2_unused) { 167380559c1SDimitris Papastamos /* 168380559c1SDimitris Papastamos * CPTR_EL2.TAM: Set to zero so any accesses to 169380559c1SDimitris Papastamos * the Activity Monitor registers do not trap to EL2. 170380559c1SDimitris Papastamos */ 17133b9be6dSChris Kay write_cptr_el2_tam(0U); 172380559c1SDimitris Papastamos } 173380559c1SDimitris Papastamos 174380559c1SDimitris Papastamos /* 17568ac5ed0SArunachalam Ganapathy * Retrieve and update the CPTR_EL3 value from the context mentioned 17668ac5ed0SArunachalam Ganapathy * in 'ctx'. Set CPTR_EL3.TAM to zero so that any accesses to 177380559c1SDimitris Papastamos * the Activity Monitor registers do not trap to EL3. 178380559c1SDimitris Papastamos */ 17933b9be6dSChris Kay write_cptr_el3_tam(ctx, 0U); 180380559c1SDimitris Papastamos 181380559c1SDimitris Papastamos /* Enable group 0 counters */ 18281e2ff1fSChris Kay write_amcntenset0_el0_px((UINT64_C(1) << read_amcgcr_el0_cg0nc()) - 1U); 183f3ccf036SAlexei Fedorov 1841fd685a7SChris Kay #if ENABLE_AMU_AUXILIARY_COUNTERS 185*31d3cc25SChris Kay if (amu_group1_supported()) { 18659902b7cSDimitris Papastamos /* Enable group 1 counters */ 18733b9be6dSChris Kay write_amcntenset1_el0_px(AMU_GROUP1_COUNTERS_MASK); 1881fd685a7SChris Kay } 189f3ccf036SAlexei Fedorov #endif 190873d4241Sjohpow01 191873d4241Sjohpow01 /* Initialize FEAT_AMUv1p1 features if present. */ 19233b9be6dSChris Kay if (!amu_v1p1_supported()) { 193873d4241Sjohpow01 return; 194873d4241Sjohpow01 } 195873d4241Sjohpow01 196873d4241Sjohpow01 if (el2_unused) { 197873d4241Sjohpow01 /* Make sure virtual offsets are disabled if EL2 not used. */ 19833b9be6dSChris Kay write_hcr_el2_amvoffen(0U); 199873d4241Sjohpow01 } 200873d4241Sjohpow01 201873d4241Sjohpow01 #if AMU_RESTRICT_COUNTERS 202873d4241Sjohpow01 /* 203873d4241Sjohpow01 * FEAT_AMUv1p1 adds a register field to restrict access to group 1 204873d4241Sjohpow01 * counters at all but the highest implemented EL. This is controlled 205873d4241Sjohpow01 * with the AMU_RESTRICT_COUNTERS compile time flag, when set, system 206873d4241Sjohpow01 * register reads at lower ELs return zero. Reads from the memory 207873d4241Sjohpow01 * mapped view are unaffected. 208873d4241Sjohpow01 */ 209873d4241Sjohpow01 VERBOSE("AMU group 1 counter access restricted.\n"); 21033b9be6dSChris Kay write_amcr_el0_cg1rz(1U); 211873d4241Sjohpow01 #else 21233b9be6dSChris Kay write_amcr_el0_cg1rz(0U); 213873d4241Sjohpow01 #endif 214380559c1SDimitris Papastamos } 2150767d50eSDimitris Papastamos 2160767d50eSDimitris Papastamos /* Read the group 0 counter identified by the given `idx`. */ 217b4b726eaSChris Kay static uint64_t amu_group0_cnt_read(unsigned int idx) 2180767d50eSDimitris Papastamos { 21933b9be6dSChris Kay assert(amu_supported()); 22081e2ff1fSChris Kay assert(idx < read_amcgcr_el0_cg0nc()); 2210767d50eSDimitris Papastamos 2220767d50eSDimitris Papastamos return amu_group0_cnt_read_internal(idx); 2230767d50eSDimitris Papastamos } 2240767d50eSDimitris Papastamos 225f3ccf036SAlexei Fedorov /* Write the group 0 counter identified by the given `idx` with `val` */ 226b4b726eaSChris Kay static void amu_group0_cnt_write(unsigned int idx, uint64_t val) 2270767d50eSDimitris Papastamos { 22833b9be6dSChris Kay assert(amu_supported()); 22981e2ff1fSChris Kay assert(idx < read_amcgcr_el0_cg0nc()); 2300767d50eSDimitris Papastamos 2310767d50eSDimitris Papastamos amu_group0_cnt_write_internal(idx, val); 2320767d50eSDimitris Papastamos isb(); 2330767d50eSDimitris Papastamos } 2340767d50eSDimitris Papastamos 235873d4241Sjohpow01 /* 236873d4241Sjohpow01 * Read the group 0 offset register for a given index. Index must be 0, 2, 237873d4241Sjohpow01 * or 3, the register for 1 does not exist. 238873d4241Sjohpow01 * 239873d4241Sjohpow01 * Using this function requires FEAT_AMUv1p1 support. 240873d4241Sjohpow01 */ 241b4b726eaSChris Kay static uint64_t amu_group0_voffset_read(unsigned int idx) 242873d4241Sjohpow01 { 24333b9be6dSChris Kay assert(amu_v1p1_supported()); 24481e2ff1fSChris Kay assert(idx < read_amcgcr_el0_cg0nc()); 245873d4241Sjohpow01 assert(idx != 1U); 246873d4241Sjohpow01 247873d4241Sjohpow01 return amu_group0_voffset_read_internal(idx); 248873d4241Sjohpow01 } 249873d4241Sjohpow01 250873d4241Sjohpow01 /* 251873d4241Sjohpow01 * Write the group 0 offset register for a given index. Index must be 0, 2, or 252873d4241Sjohpow01 * 3, the register for 1 does not exist. 253873d4241Sjohpow01 * 254873d4241Sjohpow01 * Using this function requires FEAT_AMUv1p1 support. 255873d4241Sjohpow01 */ 256b4b726eaSChris Kay static void amu_group0_voffset_write(unsigned int idx, uint64_t val) 257873d4241Sjohpow01 { 25833b9be6dSChris Kay assert(amu_v1p1_supported()); 25981e2ff1fSChris Kay assert(idx < read_amcgcr_el0_cg0nc()); 260873d4241Sjohpow01 assert(idx != 1U); 261873d4241Sjohpow01 262873d4241Sjohpow01 amu_group0_voffset_write_internal(idx, val); 263873d4241Sjohpow01 isb(); 264873d4241Sjohpow01 } 265873d4241Sjohpow01 2661fd685a7SChris Kay #if ENABLE_AMU_AUXILIARY_COUNTERS 267f3ccf036SAlexei Fedorov /* Read the group 1 counter identified by the given `idx` */ 268b4b726eaSChris Kay static uint64_t amu_group1_cnt_read(unsigned int idx) 2690767d50eSDimitris Papastamos { 27033b9be6dSChris Kay assert(amu_supported()); 271f3ccf036SAlexei Fedorov assert(amu_group1_supported()); 272*31d3cc25SChris Kay assert(idx < read_amcgcr_el0_cg1nc()); 2730767d50eSDimitris Papastamos 2740767d50eSDimitris Papastamos return amu_group1_cnt_read_internal(idx); 2750767d50eSDimitris Papastamos } 2760767d50eSDimitris Papastamos 277f3ccf036SAlexei Fedorov /* Write the group 1 counter identified by the given `idx` with `val` */ 278b4b726eaSChris Kay static void amu_group1_cnt_write(unsigned int idx, uint64_t val) 2790767d50eSDimitris Papastamos { 28033b9be6dSChris Kay assert(amu_supported()); 281f3ccf036SAlexei Fedorov assert(amu_group1_supported()); 282*31d3cc25SChris Kay assert(idx < read_amcgcr_el0_cg1nc()); 2830767d50eSDimitris Papastamos 2840767d50eSDimitris Papastamos amu_group1_cnt_write_internal(idx, val); 2850767d50eSDimitris Papastamos isb(); 2860767d50eSDimitris Papastamos } 2870767d50eSDimitris Papastamos 2880767d50eSDimitris Papastamos /* 289873d4241Sjohpow01 * Read the group 1 offset register for a given index. 290873d4241Sjohpow01 * 291873d4241Sjohpow01 * Using this function requires FEAT_AMUv1p1 support. 292873d4241Sjohpow01 */ 293b4b726eaSChris Kay static uint64_t amu_group1_voffset_read(unsigned int idx) 294873d4241Sjohpow01 { 29533b9be6dSChris Kay assert(amu_v1p1_supported()); 296873d4241Sjohpow01 assert(amu_group1_supported()); 297*31d3cc25SChris Kay assert(idx < read_amcgcr_el0_cg1nc()); 29833b9be6dSChris Kay assert((read_amcg1idr_el0_voff() & (UINT64_C(1) << idx)) != 0U); 299873d4241Sjohpow01 300873d4241Sjohpow01 return amu_group1_voffset_read_internal(idx); 301873d4241Sjohpow01 } 302873d4241Sjohpow01 303873d4241Sjohpow01 /* 304873d4241Sjohpow01 * Write the group 1 offset register for a given index. 305873d4241Sjohpow01 * 306873d4241Sjohpow01 * Using this function requires FEAT_AMUv1p1 support. 307873d4241Sjohpow01 */ 308b4b726eaSChris Kay static void amu_group1_voffset_write(unsigned int idx, uint64_t val) 309873d4241Sjohpow01 { 31033b9be6dSChris Kay assert(amu_v1p1_supported()); 311873d4241Sjohpow01 assert(amu_group1_supported()); 312*31d3cc25SChris Kay assert(idx < read_amcgcr_el0_cg1nc()); 31333b9be6dSChris Kay assert((read_amcg1idr_el0_voff() & (UINT64_C(1) << idx)) != 0U); 314873d4241Sjohpow01 315873d4241Sjohpow01 amu_group1_voffset_write_internal(idx, val); 316873d4241Sjohpow01 isb(); 317873d4241Sjohpow01 } 3181fd685a7SChris Kay #endif 319b6eb3932SDimitris Papastamos 320b6eb3932SDimitris Papastamos static void *amu_context_save(const void *arg) 321b6eb3932SDimitris Papastamos { 322b6eb3932SDimitris Papastamos struct amu_ctx *ctx = &amu_ctxs[plat_my_core_pos()]; 323f3ccf036SAlexei Fedorov unsigned int i; 324b6eb3932SDimitris Papastamos 32533b9be6dSChris Kay if (!amu_supported()) { 326b6eb3932SDimitris Papastamos return (void *)-1; 327f3ccf036SAlexei Fedorov } 328b6eb3932SDimitris Papastamos 329b6eb3932SDimitris Papastamos /* Assert that group 0/1 counter configuration is what we expect */ 33081e2ff1fSChris Kay assert(read_amcntenset0_el0_px() == 33181e2ff1fSChris Kay ((UINT64_C(1) << read_amcgcr_el0_cg0nc()) - 1U)); 332b6eb3932SDimitris Papastamos 3331fd685a7SChris Kay #if ENABLE_AMU_AUXILIARY_COUNTERS 334*31d3cc25SChris Kay if (amu_group1_supported()) { 33533b9be6dSChris Kay assert(read_amcntenset1_el0_px() == AMU_GROUP1_COUNTERS_MASK); 3361fd685a7SChris Kay } 337f3ccf036SAlexei Fedorov #endif 3381fd685a7SChris Kay 339b6eb3932SDimitris Papastamos /* 340b6eb3932SDimitris Papastamos * Disable group 0/1 counters to avoid other observers like SCP sampling 341b6eb3932SDimitris Papastamos * counter values from the future via the memory mapped view. 342b6eb3932SDimitris Papastamos */ 34381e2ff1fSChris Kay write_amcntenclr0_el0_px((UINT64_C(1) << read_amcgcr_el0_cg0nc()) - 1U); 344f3ccf036SAlexei Fedorov 3451fd685a7SChris Kay #if ENABLE_AMU_AUXILIARY_COUNTERS 346*31d3cc25SChris Kay if (amu_group1_supported()) { 34733b9be6dSChris Kay write_amcntenclr1_el0_px(AMU_GROUP1_COUNTERS_MASK); 3481fd685a7SChris Kay } 349f3ccf036SAlexei Fedorov #endif 3501fd685a7SChris Kay 351b6eb3932SDimitris Papastamos isb(); 352b6eb3932SDimitris Papastamos 353f3ccf036SAlexei Fedorov /* Save all group 0 counters */ 35481e2ff1fSChris Kay for (i = 0U; i < read_amcgcr_el0_cg0nc(); i++) { 355b6eb3932SDimitris Papastamos ctx->group0_cnts[i] = amu_group0_cnt_read(i); 356f3ccf036SAlexei Fedorov } 357b6eb3932SDimitris Papastamos 358873d4241Sjohpow01 /* Save group 0 virtual offsets if supported and enabled. */ 35933b9be6dSChris Kay if (amu_v1p1_supported() && (read_hcr_el2_amvoffen() != 0U)) { 360873d4241Sjohpow01 /* Not using a loop because count is fixed and index 1 DNE. */ 361873d4241Sjohpow01 ctx->group0_voffsets[0U] = amu_group0_voffset_read(0U); 362873d4241Sjohpow01 ctx->group0_voffsets[1U] = amu_group0_voffset_read(2U); 363873d4241Sjohpow01 ctx->group0_voffsets[2U] = amu_group0_voffset_read(3U); 364873d4241Sjohpow01 } 365873d4241Sjohpow01 3661fd685a7SChris Kay #if ENABLE_AMU_AUXILIARY_COUNTERS 367*31d3cc25SChris Kay if (amu_group1_supported()) { 368b6eb3932SDimitris Papastamos /* Save group 1 counters */ 369*31d3cc25SChris Kay for (i = 0U; i < read_amcgcr_el0_cg1nc(); i++) { 370873d4241Sjohpow01 if ((AMU_GROUP1_COUNTERS_MASK & (1UL << i)) != 0U) { 371b6eb3932SDimitris Papastamos ctx->group1_cnts[i] = amu_group1_cnt_read(i); 372f3ccf036SAlexei Fedorov } 373f3ccf036SAlexei Fedorov } 374873d4241Sjohpow01 375873d4241Sjohpow01 /* Save group 1 virtual offsets if supported and enabled. */ 37633b9be6dSChris Kay if (amu_v1p1_supported() && (read_hcr_el2_amvoffen() != 0U)) { 37733b9be6dSChris Kay uint64_t amcg1idr = read_amcg1idr_el0_voff() & 37833b9be6dSChris Kay AMU_GROUP1_COUNTERS_MASK; 379873d4241Sjohpow01 380*31d3cc25SChris Kay for (i = 0U; i < read_amcgcr_el0_cg1nc(); i++) { 381873d4241Sjohpow01 if (((amcg1idr >> i) & 1ULL) != 0ULL) { 382873d4241Sjohpow01 ctx->group1_voffsets[i] = 383873d4241Sjohpow01 amu_group1_voffset_read(i); 384873d4241Sjohpow01 } 385873d4241Sjohpow01 } 386873d4241Sjohpow01 } 3871fd685a7SChris Kay } 388f3ccf036SAlexei Fedorov #endif 3891fd685a7SChris Kay 39040daecc1SAntonio Nino Diaz return (void *)0; 391b6eb3932SDimitris Papastamos } 392b6eb3932SDimitris Papastamos 393b6eb3932SDimitris Papastamos static void *amu_context_restore(const void *arg) 394b6eb3932SDimitris Papastamos { 395b6eb3932SDimitris Papastamos struct amu_ctx *ctx = &amu_ctxs[plat_my_core_pos()]; 396f3ccf036SAlexei Fedorov unsigned int i; 397b6eb3932SDimitris Papastamos 39833b9be6dSChris Kay if (!amu_supported()) { 399b6eb3932SDimitris Papastamos return (void *)-1; 400f3ccf036SAlexei Fedorov } 401b6eb3932SDimitris Papastamos 402b6eb3932SDimitris Papastamos /* Counters were disabled in `amu_context_save()` */ 40333b9be6dSChris Kay assert(read_amcntenset0_el0_px() == 0U); 404b6eb3932SDimitris Papastamos 4051fd685a7SChris Kay #if ENABLE_AMU_AUXILIARY_COUNTERS 406*31d3cc25SChris Kay if (amu_group1_supported()) { 40733b9be6dSChris Kay assert(read_amcntenset1_el0_px() == 0U); 4081fd685a7SChris Kay } 409f3ccf036SAlexei Fedorov #endif 410b6eb3932SDimitris Papastamos 411f3ccf036SAlexei Fedorov /* Restore all group 0 counters */ 41281e2ff1fSChris Kay for (i = 0U; i < read_amcgcr_el0_cg0nc(); i++) { 413b6eb3932SDimitris Papastamos amu_group0_cnt_write(i, ctx->group0_cnts[i]); 414f3ccf036SAlexei Fedorov } 415b6eb3932SDimitris Papastamos 416873d4241Sjohpow01 /* Restore group 0 virtual offsets if supported and enabled. */ 41733b9be6dSChris Kay if (amu_v1p1_supported() && (read_hcr_el2_amvoffen() != 0U)) { 418873d4241Sjohpow01 /* Not using a loop because count is fixed and index 1 DNE. */ 419873d4241Sjohpow01 amu_group0_voffset_write(0U, ctx->group0_voffsets[0U]); 420873d4241Sjohpow01 amu_group0_voffset_write(2U, ctx->group0_voffsets[1U]); 421873d4241Sjohpow01 amu_group0_voffset_write(3U, ctx->group0_voffsets[2U]); 422873d4241Sjohpow01 } 423873d4241Sjohpow01 424f3ccf036SAlexei Fedorov /* Restore group 0 counter configuration */ 42581e2ff1fSChris Kay write_amcntenset0_el0_px((UINT64_C(1) << read_amcgcr_el0_cg0nc()) - 1U); 426f3ccf036SAlexei Fedorov 4271fd685a7SChris Kay #if ENABLE_AMU_AUXILIARY_COUNTERS 428*31d3cc25SChris Kay if (amu_group1_supported()) { 429f3ccf036SAlexei Fedorov /* Restore group 1 counters */ 430*31d3cc25SChris Kay for (i = 0U; i < read_amcgcr_el0_cg1nc(); i++) { 431873d4241Sjohpow01 if ((AMU_GROUP1_COUNTERS_MASK & (1UL << i)) != 0U) { 432f3ccf036SAlexei Fedorov amu_group1_cnt_write(i, ctx->group1_cnts[i]); 433f3ccf036SAlexei Fedorov } 434f3ccf036SAlexei Fedorov } 435f3ccf036SAlexei Fedorov 436873d4241Sjohpow01 /* Restore group 1 virtual offsets if supported and enabled. */ 43733b9be6dSChris Kay if (amu_v1p1_supported() && (read_hcr_el2_amvoffen() != 0U)) { 43833b9be6dSChris Kay uint64_t amcg1idr = read_amcg1idr_el0_voff() & 43933b9be6dSChris Kay AMU_GROUP1_COUNTERS_MASK; 440873d4241Sjohpow01 441*31d3cc25SChris Kay for (i = 0U; i < read_amcgcr_el0_cg1nc(); i++) { 442873d4241Sjohpow01 if (((amcg1idr >> i) & 1ULL) != 0ULL) { 443873d4241Sjohpow01 amu_group1_voffset_write(i, 444873d4241Sjohpow01 ctx->group1_voffsets[i]); 445873d4241Sjohpow01 } 446873d4241Sjohpow01 } 447873d4241Sjohpow01 } 448873d4241Sjohpow01 449f3ccf036SAlexei Fedorov /* Restore group 1 counter configuration */ 45033b9be6dSChris Kay write_amcntenset1_el0_px(AMU_GROUP1_COUNTERS_MASK); 4511fd685a7SChris Kay } 452f3ccf036SAlexei Fedorov #endif 453b6eb3932SDimitris Papastamos 45440daecc1SAntonio Nino Diaz return (void *)0; 455b6eb3932SDimitris Papastamos } 456b6eb3932SDimitris Papastamos 457b6eb3932SDimitris Papastamos SUBSCRIBE_TO_EVENT(psci_suspend_pwrdown_start, amu_context_save); 458b6eb3932SDimitris Papastamos SUBSCRIBE_TO_EVENT(psci_suspend_pwrdown_finish, amu_context_restore); 459