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 6933b9be6dSChris Kay static inline __unused uint64_t read_amcg1idr_el0_voff(void) 7033b9be6dSChris Kay { 7133b9be6dSChris Kay return (read_amcg1idr_el0() >> AMCG1IDR_VOFF_SHIFT) & 7233b9be6dSChris Kay AMCG1IDR_VOFF_MASK; 7333b9be6dSChris Kay } 7433b9be6dSChris Kay 7533b9be6dSChris Kay static inline __unused uint64_t read_amcgcr_el0_cg1nc(void) 7633b9be6dSChris Kay { 7733b9be6dSChris Kay return (read_amcgcr_el0() >> AMCGCR_EL0_CG1NC_SHIFT) & 7833b9be6dSChris Kay AMCGCR_EL0_CG1NC_MASK; 7933b9be6dSChris Kay } 8033b9be6dSChris Kay 8133b9be6dSChris Kay static inline __unused uint64_t read_amcntenset0_el0_px(void) 8233b9be6dSChris Kay { 8333b9be6dSChris Kay return (read_amcntenset0_el0() >> AMCNTENSET0_EL0_Pn_SHIFT) & 8433b9be6dSChris Kay AMCNTENSET0_EL0_Pn_MASK; 8533b9be6dSChris Kay } 8633b9be6dSChris Kay 8733b9be6dSChris Kay static inline __unused uint64_t read_amcntenset1_el0_px(void) 8833b9be6dSChris Kay { 8933b9be6dSChris Kay return (read_amcntenset1_el0() >> AMCNTENSET1_EL0_Pn_SHIFT) & 9033b9be6dSChris Kay AMCNTENSET1_EL0_Pn_MASK; 9133b9be6dSChris Kay } 9233b9be6dSChris Kay 9333b9be6dSChris Kay static inline __unused void write_amcntenset0_el0_px(uint64_t px) 9433b9be6dSChris Kay { 9533b9be6dSChris Kay uint64_t value = read_amcntenset0_el0(); 9633b9be6dSChris Kay 9733b9be6dSChris Kay value &= ~AMCNTENSET0_EL0_Pn_MASK; 9833b9be6dSChris Kay value |= (px << AMCNTENSET0_EL0_Pn_SHIFT) & AMCNTENSET0_EL0_Pn_MASK; 9933b9be6dSChris Kay 10033b9be6dSChris Kay write_amcntenset0_el0(value); 10133b9be6dSChris Kay } 10233b9be6dSChris Kay 10333b9be6dSChris Kay static inline __unused void write_amcntenset1_el0_px(uint64_t px) 10433b9be6dSChris Kay { 10533b9be6dSChris Kay uint64_t value = read_amcntenset1_el0(); 10633b9be6dSChris Kay 10733b9be6dSChris Kay value &= ~AMCNTENSET1_EL0_Pn_MASK; 10833b9be6dSChris Kay value |= (px << AMCNTENSET1_EL0_Pn_SHIFT) & AMCNTENSET1_EL0_Pn_MASK; 10933b9be6dSChris Kay 11033b9be6dSChris Kay write_amcntenset1_el0(value); 11133b9be6dSChris Kay } 11233b9be6dSChris Kay 11333b9be6dSChris Kay static inline __unused void write_amcntenclr0_el0_px(uint64_t px) 11433b9be6dSChris Kay { 11533b9be6dSChris Kay uint64_t value = read_amcntenclr0_el0(); 11633b9be6dSChris Kay 11733b9be6dSChris Kay value &= ~AMCNTENCLR0_EL0_Pn_MASK; 11833b9be6dSChris Kay value |= (px << AMCNTENCLR0_EL0_Pn_SHIFT) & AMCNTENCLR0_EL0_Pn_MASK; 11933b9be6dSChris Kay 12033b9be6dSChris Kay write_amcntenclr0_el0(value); 12133b9be6dSChris Kay } 12233b9be6dSChris Kay 12333b9be6dSChris Kay static inline __unused void write_amcntenclr1_el0_px(uint64_t px) 12433b9be6dSChris Kay { 12533b9be6dSChris Kay uint64_t value = read_amcntenclr1_el0(); 12633b9be6dSChris Kay 12733b9be6dSChris Kay value &= ~AMCNTENCLR1_EL0_Pn_MASK; 12833b9be6dSChris Kay value |= (px << AMCNTENCLR1_EL0_Pn_SHIFT) & AMCNTENCLR1_EL0_Pn_MASK; 12933b9be6dSChris Kay 13033b9be6dSChris Kay write_amcntenclr1_el0(value); 13133b9be6dSChris Kay } 13233b9be6dSChris Kay 13333b9be6dSChris Kay static bool amu_supported(void) 13433b9be6dSChris Kay { 13533b9be6dSChris Kay return read_id_aa64pfr0_el1_amu() >= ID_AA64PFR0_AMU_V1; 13633b9be6dSChris Kay } 13733b9be6dSChris Kay 13833b9be6dSChris Kay static bool amu_v1p1_supported(void) 13933b9be6dSChris Kay { 14033b9be6dSChris Kay return read_id_aa64pfr0_el1_amu() >= ID_AA64PFR0_AMU_V1P1; 14133b9be6dSChris Kay } 14233b9be6dSChris Kay 14333b9be6dSChris Kay #if ENABLE_AMU_AUXILIARY_COUNTERS 144b4b726eaSChris Kay static bool amu_group1_supported(void) 145f3ccf036SAlexei Fedorov { 14633b9be6dSChris Kay return read_amcfgr_el0_ncg() > 0U; 147f3ccf036SAlexei Fedorov } 148f3ccf036SAlexei Fedorov #endif 149f3ccf036SAlexei Fedorov 1500767d50eSDimitris Papastamos /* 1510767d50eSDimitris Papastamos * Enable counters. This function is meant to be invoked 1520767d50eSDimitris Papastamos * by the context management library before exiting from EL3. 1530767d50eSDimitris Papastamos */ 15468ac5ed0SArunachalam Ganapathy void amu_enable(bool el2_unused, cpu_context_t *ctx) 1550767d50eSDimitris Papastamos { 15633b9be6dSChris Kay if (!amu_supported()) { 1570767d50eSDimitris Papastamos return; 158f3ccf036SAlexei Fedorov } 159f3ccf036SAlexei Fedorov 160*1fd685a7SChris Kay #if ENABLE_AMU_AUXILIARY_COUNTERS 161*1fd685a7SChris Kay if (AMU_GROUP1_NR_COUNTERS > 0U) { 162f3ccf036SAlexei Fedorov /* Check and set presence of group 1 counters */ 163f3ccf036SAlexei Fedorov if (!amu_group1_supported()) { 164f3ccf036SAlexei Fedorov ERROR("AMU Counter Group 1 is not implemented\n"); 165f3ccf036SAlexei Fedorov panic(); 166f3ccf036SAlexei Fedorov } 167f3ccf036SAlexei Fedorov 168f3ccf036SAlexei Fedorov /* Check number of group 1 counters */ 16933b9be6dSChris Kay uint64_t cnt_num = read_amcgcr_el0_cg1nc(); 170*1fd685a7SChris Kay 171f3ccf036SAlexei Fedorov VERBOSE("%s%llu. %s%u\n", 172f3ccf036SAlexei Fedorov "Number of AMU Group 1 Counters ", cnt_num, 173f3ccf036SAlexei Fedorov "Requested number ", AMU_GROUP1_NR_COUNTERS); 174f3ccf036SAlexei Fedorov 175f3ccf036SAlexei Fedorov if (cnt_num < AMU_GROUP1_NR_COUNTERS) { 176f3ccf036SAlexei Fedorov ERROR("%s%llu is less than %s%u\n", 177f3ccf036SAlexei Fedorov "Number of AMU Group 1 Counters ", cnt_num, 178f3ccf036SAlexei Fedorov "Requested number ", AMU_GROUP1_NR_COUNTERS); 179f3ccf036SAlexei Fedorov panic(); 180f3ccf036SAlexei Fedorov } 181*1fd685a7SChris Kay } 182f3ccf036SAlexei Fedorov #endif 1830767d50eSDimitris Papastamos 184380559c1SDimitris Papastamos if (el2_unused) { 185380559c1SDimitris Papastamos /* 186380559c1SDimitris Papastamos * CPTR_EL2.TAM: Set to zero so any accesses to 187380559c1SDimitris Papastamos * the Activity Monitor registers do not trap to EL2. 188380559c1SDimitris Papastamos */ 18933b9be6dSChris Kay write_cptr_el2_tam(0U); 190380559c1SDimitris Papastamos } 191380559c1SDimitris Papastamos 192380559c1SDimitris Papastamos /* 19368ac5ed0SArunachalam Ganapathy * Retrieve and update the CPTR_EL3 value from the context mentioned 19468ac5ed0SArunachalam Ganapathy * in 'ctx'. Set CPTR_EL3.TAM to zero so that any accesses to 195380559c1SDimitris Papastamos * the Activity Monitor registers do not trap to EL3. 196380559c1SDimitris Papastamos */ 19733b9be6dSChris Kay write_cptr_el3_tam(ctx, 0U); 198380559c1SDimitris Papastamos 199380559c1SDimitris Papastamos /* Enable group 0 counters */ 20033b9be6dSChris Kay write_amcntenset0_el0_px(AMU_GROUP0_COUNTERS_MASK); 201f3ccf036SAlexei Fedorov 202*1fd685a7SChris Kay #if ENABLE_AMU_AUXILIARY_COUNTERS 203*1fd685a7SChris Kay if (AMU_GROUP1_NR_COUNTERS > 0U) { 20459902b7cSDimitris Papastamos /* Enable group 1 counters */ 20533b9be6dSChris Kay write_amcntenset1_el0_px(AMU_GROUP1_COUNTERS_MASK); 206*1fd685a7SChris Kay } 207f3ccf036SAlexei Fedorov #endif 208873d4241Sjohpow01 209873d4241Sjohpow01 /* Initialize FEAT_AMUv1p1 features if present. */ 21033b9be6dSChris Kay if (!amu_v1p1_supported()) { 211873d4241Sjohpow01 return; 212873d4241Sjohpow01 } 213873d4241Sjohpow01 214873d4241Sjohpow01 if (el2_unused) { 215873d4241Sjohpow01 /* Make sure virtual offsets are disabled if EL2 not used. */ 21633b9be6dSChris Kay write_hcr_el2_amvoffen(0U); 217873d4241Sjohpow01 } 218873d4241Sjohpow01 219873d4241Sjohpow01 #if AMU_RESTRICT_COUNTERS 220873d4241Sjohpow01 /* 221873d4241Sjohpow01 * FEAT_AMUv1p1 adds a register field to restrict access to group 1 222873d4241Sjohpow01 * counters at all but the highest implemented EL. This is controlled 223873d4241Sjohpow01 * with the AMU_RESTRICT_COUNTERS compile time flag, when set, system 224873d4241Sjohpow01 * register reads at lower ELs return zero. Reads from the memory 225873d4241Sjohpow01 * mapped view are unaffected. 226873d4241Sjohpow01 */ 227873d4241Sjohpow01 VERBOSE("AMU group 1 counter access restricted.\n"); 22833b9be6dSChris Kay write_amcr_el0_cg1rz(1U); 229873d4241Sjohpow01 #else 23033b9be6dSChris Kay write_amcr_el0_cg1rz(0U); 231873d4241Sjohpow01 #endif 232380559c1SDimitris Papastamos } 2330767d50eSDimitris Papastamos 2340767d50eSDimitris Papastamos /* Read the group 0 counter identified by the given `idx`. */ 235b4b726eaSChris Kay static uint64_t amu_group0_cnt_read(unsigned int idx) 2360767d50eSDimitris Papastamos { 23733b9be6dSChris Kay assert(amu_supported()); 238f3ccf036SAlexei Fedorov assert(idx < AMU_GROUP0_NR_COUNTERS); 2390767d50eSDimitris Papastamos 2400767d50eSDimitris Papastamos return amu_group0_cnt_read_internal(idx); 2410767d50eSDimitris Papastamos } 2420767d50eSDimitris Papastamos 243f3ccf036SAlexei Fedorov /* Write the group 0 counter identified by the given `idx` with `val` */ 244b4b726eaSChris Kay static void amu_group0_cnt_write(unsigned int idx, uint64_t val) 2450767d50eSDimitris Papastamos { 24633b9be6dSChris Kay assert(amu_supported()); 247f3ccf036SAlexei Fedorov assert(idx < AMU_GROUP0_NR_COUNTERS); 2480767d50eSDimitris Papastamos 2490767d50eSDimitris Papastamos amu_group0_cnt_write_internal(idx, val); 2500767d50eSDimitris Papastamos isb(); 2510767d50eSDimitris Papastamos } 2520767d50eSDimitris Papastamos 253873d4241Sjohpow01 /* 254873d4241Sjohpow01 * Read the group 0 offset register for a given index. Index must be 0, 2, 255873d4241Sjohpow01 * or 3, the register for 1 does not exist. 256873d4241Sjohpow01 * 257873d4241Sjohpow01 * Using this function requires FEAT_AMUv1p1 support. 258873d4241Sjohpow01 */ 259b4b726eaSChris Kay static uint64_t amu_group0_voffset_read(unsigned int idx) 260873d4241Sjohpow01 { 26133b9be6dSChris Kay assert(amu_v1p1_supported()); 262873d4241Sjohpow01 assert(idx < AMU_GROUP0_NR_COUNTERS); 263873d4241Sjohpow01 assert(idx != 1U); 264873d4241Sjohpow01 265873d4241Sjohpow01 return amu_group0_voffset_read_internal(idx); 266873d4241Sjohpow01 } 267873d4241Sjohpow01 268873d4241Sjohpow01 /* 269873d4241Sjohpow01 * Write the group 0 offset register for a given index. Index must be 0, 2, or 270873d4241Sjohpow01 * 3, the register for 1 does not exist. 271873d4241Sjohpow01 * 272873d4241Sjohpow01 * Using this function requires FEAT_AMUv1p1 support. 273873d4241Sjohpow01 */ 274b4b726eaSChris Kay static void amu_group0_voffset_write(unsigned int idx, uint64_t val) 275873d4241Sjohpow01 { 27633b9be6dSChris Kay assert(amu_v1p1_supported()); 277873d4241Sjohpow01 assert(idx < AMU_GROUP0_NR_COUNTERS); 278873d4241Sjohpow01 assert(idx != 1U); 279873d4241Sjohpow01 280873d4241Sjohpow01 amu_group0_voffset_write_internal(idx, val); 281873d4241Sjohpow01 isb(); 282873d4241Sjohpow01 } 283873d4241Sjohpow01 284*1fd685a7SChris Kay #if ENABLE_AMU_AUXILIARY_COUNTERS 285f3ccf036SAlexei Fedorov /* Read the group 1 counter identified by the given `idx` */ 286b4b726eaSChris Kay static uint64_t amu_group1_cnt_read(unsigned int idx) 2870767d50eSDimitris Papastamos { 28833b9be6dSChris Kay assert(amu_supported()); 289f3ccf036SAlexei Fedorov assert(amu_group1_supported()); 290f3ccf036SAlexei Fedorov assert(idx < AMU_GROUP1_NR_COUNTERS); 2910767d50eSDimitris Papastamos 2920767d50eSDimitris Papastamos return amu_group1_cnt_read_internal(idx); 2930767d50eSDimitris Papastamos } 2940767d50eSDimitris Papastamos 295f3ccf036SAlexei Fedorov /* Write the group 1 counter identified by the given `idx` with `val` */ 296b4b726eaSChris Kay static void amu_group1_cnt_write(unsigned int idx, uint64_t val) 2970767d50eSDimitris Papastamos { 29833b9be6dSChris Kay assert(amu_supported()); 299f3ccf036SAlexei Fedorov assert(amu_group1_supported()); 300f3ccf036SAlexei Fedorov assert(idx < AMU_GROUP1_NR_COUNTERS); 3010767d50eSDimitris Papastamos 3020767d50eSDimitris Papastamos amu_group1_cnt_write_internal(idx, val); 3030767d50eSDimitris Papastamos isb(); 3040767d50eSDimitris Papastamos } 3050767d50eSDimitris Papastamos 3060767d50eSDimitris Papastamos /* 307873d4241Sjohpow01 * Read the group 1 offset register for a given index. 308873d4241Sjohpow01 * 309873d4241Sjohpow01 * Using this function requires FEAT_AMUv1p1 support. 310873d4241Sjohpow01 */ 311b4b726eaSChris Kay static uint64_t amu_group1_voffset_read(unsigned int idx) 312873d4241Sjohpow01 { 31333b9be6dSChris Kay assert(amu_v1p1_supported()); 314873d4241Sjohpow01 assert(amu_group1_supported()); 315873d4241Sjohpow01 assert(idx < AMU_GROUP1_NR_COUNTERS); 31633b9be6dSChris Kay assert((read_amcg1idr_el0_voff() & (UINT64_C(1) << idx)) != 0U); 317873d4241Sjohpow01 318873d4241Sjohpow01 return amu_group1_voffset_read_internal(idx); 319873d4241Sjohpow01 } 320873d4241Sjohpow01 321873d4241Sjohpow01 /* 322873d4241Sjohpow01 * Write the group 1 offset register for a given index. 323873d4241Sjohpow01 * 324873d4241Sjohpow01 * Using this function requires FEAT_AMUv1p1 support. 325873d4241Sjohpow01 */ 326b4b726eaSChris Kay static void amu_group1_voffset_write(unsigned int idx, uint64_t val) 327873d4241Sjohpow01 { 32833b9be6dSChris Kay assert(amu_v1p1_supported()); 329873d4241Sjohpow01 assert(amu_group1_supported()); 330873d4241Sjohpow01 assert(idx < AMU_GROUP1_NR_COUNTERS); 33133b9be6dSChris Kay assert((read_amcg1idr_el0_voff() & (UINT64_C(1) << idx)) != 0U); 332873d4241Sjohpow01 333873d4241Sjohpow01 amu_group1_voffset_write_internal(idx, val); 334873d4241Sjohpow01 isb(); 335873d4241Sjohpow01 } 336*1fd685a7SChris Kay #endif 337b6eb3932SDimitris Papastamos 338b6eb3932SDimitris Papastamos static void *amu_context_save(const void *arg) 339b6eb3932SDimitris Papastamos { 340b6eb3932SDimitris Papastamos struct amu_ctx *ctx = &amu_ctxs[plat_my_core_pos()]; 341f3ccf036SAlexei Fedorov unsigned int i; 342b6eb3932SDimitris Papastamos 34333b9be6dSChris Kay if (!amu_supported()) { 344b6eb3932SDimitris Papastamos return (void *)-1; 345f3ccf036SAlexei Fedorov } 346b6eb3932SDimitris Papastamos 347*1fd685a7SChris Kay #if ENABLE_AMU_AUXILIARY_COUNTERS 348*1fd685a7SChris Kay if (AMU_GROUP1_NR_COUNTERS > 0U) { 349f3ccf036SAlexei Fedorov if (!amu_group1_supported()) { 350f3ccf036SAlexei Fedorov return (void *)-1; 351f3ccf036SAlexei Fedorov } 352*1fd685a7SChris Kay } 353f3ccf036SAlexei Fedorov #endif 354*1fd685a7SChris Kay 355b6eb3932SDimitris Papastamos /* Assert that group 0/1 counter configuration is what we expect */ 35633b9be6dSChris Kay assert(read_amcntenset0_el0_px() == AMU_GROUP0_COUNTERS_MASK); 357b6eb3932SDimitris Papastamos 358*1fd685a7SChris Kay #if ENABLE_AMU_AUXILIARY_COUNTERS 359*1fd685a7SChris Kay if (AMU_GROUP1_NR_COUNTERS > 0U) { 36033b9be6dSChris Kay assert(read_amcntenset1_el0_px() == AMU_GROUP1_COUNTERS_MASK); 361*1fd685a7SChris Kay } 362f3ccf036SAlexei Fedorov #endif 363*1fd685a7SChris Kay 364b6eb3932SDimitris Papastamos /* 365b6eb3932SDimitris Papastamos * Disable group 0/1 counters to avoid other observers like SCP sampling 366b6eb3932SDimitris Papastamos * counter values from the future via the memory mapped view. 367b6eb3932SDimitris Papastamos */ 36833b9be6dSChris Kay write_amcntenclr0_el0_px(AMU_GROUP0_COUNTERS_MASK); 369f3ccf036SAlexei Fedorov 370*1fd685a7SChris Kay #if ENABLE_AMU_AUXILIARY_COUNTERS 371*1fd685a7SChris Kay if (AMU_GROUP1_NR_COUNTERS > 0U) { 37233b9be6dSChris Kay write_amcntenclr1_el0_px(AMU_GROUP1_COUNTERS_MASK); 373*1fd685a7SChris Kay } 374f3ccf036SAlexei Fedorov #endif 375*1fd685a7SChris Kay 376b6eb3932SDimitris Papastamos isb(); 377b6eb3932SDimitris Papastamos 378f3ccf036SAlexei Fedorov /* Save all group 0 counters */ 379f3ccf036SAlexei Fedorov for (i = 0U; i < AMU_GROUP0_NR_COUNTERS; i++) { 380b6eb3932SDimitris Papastamos ctx->group0_cnts[i] = amu_group0_cnt_read(i); 381f3ccf036SAlexei Fedorov } 382b6eb3932SDimitris Papastamos 383873d4241Sjohpow01 /* Save group 0 virtual offsets if supported and enabled. */ 38433b9be6dSChris Kay if (amu_v1p1_supported() && (read_hcr_el2_amvoffen() != 0U)) { 385873d4241Sjohpow01 /* Not using a loop because count is fixed and index 1 DNE. */ 386873d4241Sjohpow01 ctx->group0_voffsets[0U] = amu_group0_voffset_read(0U); 387873d4241Sjohpow01 ctx->group0_voffsets[1U] = amu_group0_voffset_read(2U); 388873d4241Sjohpow01 ctx->group0_voffsets[2U] = amu_group0_voffset_read(3U); 389873d4241Sjohpow01 } 390873d4241Sjohpow01 391*1fd685a7SChris Kay #if ENABLE_AMU_AUXILIARY_COUNTERS 392*1fd685a7SChris Kay if (AMU_GROUP1_NR_COUNTERS > 0U) { 393b6eb3932SDimitris Papastamos /* Save group 1 counters */ 394f3ccf036SAlexei Fedorov for (i = 0U; i < AMU_GROUP1_NR_COUNTERS; i++) { 395873d4241Sjohpow01 if ((AMU_GROUP1_COUNTERS_MASK & (1UL << i)) != 0U) { 396b6eb3932SDimitris Papastamos ctx->group1_cnts[i] = amu_group1_cnt_read(i); 397f3ccf036SAlexei Fedorov } 398f3ccf036SAlexei Fedorov } 399873d4241Sjohpow01 400873d4241Sjohpow01 /* Save group 1 virtual offsets if supported and enabled. */ 40133b9be6dSChris Kay if (amu_v1p1_supported() && (read_hcr_el2_amvoffen() != 0U)) { 40233b9be6dSChris Kay uint64_t amcg1idr = read_amcg1idr_el0_voff() & 40333b9be6dSChris Kay AMU_GROUP1_COUNTERS_MASK; 404873d4241Sjohpow01 405873d4241Sjohpow01 for (i = 0U; i < AMU_GROUP1_NR_COUNTERS; i++) { 406873d4241Sjohpow01 if (((amcg1idr >> i) & 1ULL) != 0ULL) { 407873d4241Sjohpow01 ctx->group1_voffsets[i] = 408873d4241Sjohpow01 amu_group1_voffset_read(i); 409873d4241Sjohpow01 } 410873d4241Sjohpow01 } 411873d4241Sjohpow01 } 412*1fd685a7SChris Kay } 413f3ccf036SAlexei Fedorov #endif 414*1fd685a7SChris Kay 41540daecc1SAntonio Nino Diaz return (void *)0; 416b6eb3932SDimitris Papastamos } 417b6eb3932SDimitris Papastamos 418b6eb3932SDimitris Papastamos static void *amu_context_restore(const void *arg) 419b6eb3932SDimitris Papastamos { 420b6eb3932SDimitris Papastamos struct amu_ctx *ctx = &amu_ctxs[plat_my_core_pos()]; 421f3ccf036SAlexei Fedorov unsigned int i; 422b6eb3932SDimitris Papastamos 42333b9be6dSChris Kay if (!amu_supported()) { 424b6eb3932SDimitris Papastamos return (void *)-1; 425f3ccf036SAlexei Fedorov } 426b6eb3932SDimitris Papastamos 427*1fd685a7SChris Kay #if ENABLE_AMU_AUXILIARY_COUNTERS 428*1fd685a7SChris Kay if (AMU_GROUP1_NR_COUNTERS > 0U) { 429f3ccf036SAlexei Fedorov if (!amu_group1_supported()) { 430f3ccf036SAlexei Fedorov return (void *)-1; 431f3ccf036SAlexei Fedorov } 432*1fd685a7SChris Kay } 433f3ccf036SAlexei Fedorov #endif 434*1fd685a7SChris Kay 435b6eb3932SDimitris Papastamos /* Counters were disabled in `amu_context_save()` */ 43633b9be6dSChris Kay assert(read_amcntenset0_el0_px() == 0U); 437b6eb3932SDimitris Papastamos 438*1fd685a7SChris Kay #if ENABLE_AMU_AUXILIARY_COUNTERS 439*1fd685a7SChris Kay if (AMU_GROUP1_NR_COUNTERS > 0U) { 44033b9be6dSChris Kay assert(read_amcntenset1_el0_px() == 0U); 441*1fd685a7SChris Kay } 442f3ccf036SAlexei Fedorov #endif 443b6eb3932SDimitris Papastamos 444f3ccf036SAlexei Fedorov /* Restore all group 0 counters */ 445f3ccf036SAlexei Fedorov for (i = 0U; i < AMU_GROUP0_NR_COUNTERS; i++) { 446b6eb3932SDimitris Papastamos amu_group0_cnt_write(i, ctx->group0_cnts[i]); 447f3ccf036SAlexei Fedorov } 448b6eb3932SDimitris Papastamos 449873d4241Sjohpow01 /* Restore group 0 virtual offsets if supported and enabled. */ 45033b9be6dSChris Kay if (amu_v1p1_supported() && (read_hcr_el2_amvoffen() != 0U)) { 451873d4241Sjohpow01 /* Not using a loop because count is fixed and index 1 DNE. */ 452873d4241Sjohpow01 amu_group0_voffset_write(0U, ctx->group0_voffsets[0U]); 453873d4241Sjohpow01 amu_group0_voffset_write(2U, ctx->group0_voffsets[1U]); 454873d4241Sjohpow01 amu_group0_voffset_write(3U, ctx->group0_voffsets[2U]); 455873d4241Sjohpow01 } 456873d4241Sjohpow01 457f3ccf036SAlexei Fedorov /* Restore group 0 counter configuration */ 45833b9be6dSChris Kay write_amcntenset0_el0_px(AMU_GROUP0_COUNTERS_MASK); 459f3ccf036SAlexei Fedorov 460*1fd685a7SChris Kay #if ENABLE_AMU_AUXILIARY_COUNTERS 461*1fd685a7SChris Kay if (AMU_GROUP1_NR_COUNTERS > 0U) { 462f3ccf036SAlexei Fedorov /* Restore group 1 counters */ 463f3ccf036SAlexei Fedorov for (i = 0U; i < AMU_GROUP1_NR_COUNTERS; i++) { 464873d4241Sjohpow01 if ((AMU_GROUP1_COUNTERS_MASK & (1UL << i)) != 0U) { 465f3ccf036SAlexei Fedorov amu_group1_cnt_write(i, ctx->group1_cnts[i]); 466f3ccf036SAlexei Fedorov } 467f3ccf036SAlexei Fedorov } 468f3ccf036SAlexei Fedorov 469873d4241Sjohpow01 /* Restore group 1 virtual offsets if supported and enabled. */ 47033b9be6dSChris Kay if (amu_v1p1_supported() && (read_hcr_el2_amvoffen() != 0U)) { 47133b9be6dSChris Kay uint64_t amcg1idr = read_amcg1idr_el0_voff() & 47233b9be6dSChris Kay AMU_GROUP1_COUNTERS_MASK; 473873d4241Sjohpow01 474873d4241Sjohpow01 for (i = 0U; i < AMU_GROUP1_NR_COUNTERS; i++) { 475873d4241Sjohpow01 if (((amcg1idr >> i) & 1ULL) != 0ULL) { 476873d4241Sjohpow01 amu_group1_voffset_write(i, 477873d4241Sjohpow01 ctx->group1_voffsets[i]); 478873d4241Sjohpow01 } 479873d4241Sjohpow01 } 480873d4241Sjohpow01 } 481873d4241Sjohpow01 482f3ccf036SAlexei Fedorov /* Restore group 1 counter configuration */ 48333b9be6dSChris Kay write_amcntenset1_el0_px(AMU_GROUP1_COUNTERS_MASK); 484*1fd685a7SChris Kay } 485f3ccf036SAlexei Fedorov #endif 486b6eb3932SDimitris Papastamos 48740daecc1SAntonio Nino Diaz return (void *)0; 488b6eb3932SDimitris Papastamos } 489b6eb3932SDimitris Papastamos 490b6eb3932SDimitris Papastamos SUBSCRIBE_TO_EVENT(psci_suspend_pwrdown_start, amu_context_save); 491b6eb3932SDimitris Papastamos SUBSCRIBE_TO_EVENT(psci_suspend_pwrdown_finish, amu_context_restore); 492