1ef69e1eaSDimitris Papastamos /* 2873d4241Sjohpow01 * Copyright (c) 2017-2021, ARM Limited and Contributors. All rights reserved. 3ef69e1eaSDimitris Papastamos * 4ef69e1eaSDimitris Papastamos * SPDX-License-Identifier: BSD-3-Clause 5ef69e1eaSDimitris Papastamos */ 6ef69e1eaSDimitris Papastamos 7f3ccf036SAlexei Fedorov #include <assert.h> 833b9be6dSChris Kay #include <cdefs.h> 909d40e0eSAntonio Nino Diaz #include <stdbool.h> 1009d40e0eSAntonio Nino Diaz 11ef69e1eaSDimitris Papastamos #include <arch.h> 12ef69e1eaSDimitris 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> 19b6eb3932SDimitris Papastamos 20b6eb3932SDimitris Papastamos static struct amu_ctx amu_ctxs[PLATFORM_CORE_COUNT]; 21ef69e1eaSDimitris Papastamos 2233b9be6dSChris Kay static inline __unused uint32_t read_id_pfr0_amu(void) 23ef69e1eaSDimitris Papastamos { 2433b9be6dSChris Kay return (read_id_pfr0() >> ID_PFR0_AMU_SHIFT) & 25873d4241Sjohpow01 ID_PFR0_AMU_MASK; 26c70da546SJoel Hutton } 27c70da546SJoel Hutton 2833b9be6dSChris Kay static inline __unused void write_hcptr_tam(uint32_t value) 2933b9be6dSChris Kay { 3033b9be6dSChris Kay write_hcptr((read_hcptr() & ~TAM_BIT) | 3133b9be6dSChris Kay ((value << TAM_SHIFT) & TAM_BIT)); 3233b9be6dSChris Kay } 3333b9be6dSChris Kay 3433b9be6dSChris Kay static inline __unused void write_amcr_cg1rz(uint32_t value) 3533b9be6dSChris Kay { 3633b9be6dSChris Kay write_amcr((read_amcr() & ~AMCR_CG1RZ_BIT) | 3733b9be6dSChris Kay ((value << AMCR_CG1RZ_SHIFT) & AMCR_CG1RZ_BIT)); 3833b9be6dSChris Kay } 3933b9be6dSChris Kay 4033b9be6dSChris Kay static inline __unused uint32_t read_amcfgr_ncg(void) 4133b9be6dSChris Kay { 4233b9be6dSChris Kay return (read_amcfgr() >> AMCFGR_NCG_SHIFT) & 4333b9be6dSChris Kay AMCFGR_NCG_MASK; 4433b9be6dSChris Kay } 4533b9be6dSChris Kay 4681e2ff1fSChris Kay static inline __unused uint32_t read_amcgcr_cg0nc(void) 4781e2ff1fSChris Kay { 4881e2ff1fSChris Kay return (read_amcgcr() >> AMCGCR_CG0NC_SHIFT) & 4981e2ff1fSChris Kay AMCGCR_CG0NC_MASK; 5081e2ff1fSChris Kay } 5181e2ff1fSChris Kay 5233b9be6dSChris Kay static inline __unused uint32_t read_amcgcr_cg1nc(void) 5333b9be6dSChris Kay { 5433b9be6dSChris Kay return (read_amcgcr() >> AMCGCR_CG1NC_SHIFT) & 5533b9be6dSChris Kay AMCGCR_CG1NC_MASK; 5633b9be6dSChris Kay } 5733b9be6dSChris Kay 5833b9be6dSChris Kay static inline __unused uint32_t read_amcntenset0_px(void) 5933b9be6dSChris Kay { 6033b9be6dSChris Kay return (read_amcntenset0() >> AMCNTENSET0_Pn_SHIFT) & 6133b9be6dSChris Kay AMCNTENSET0_Pn_MASK; 6233b9be6dSChris Kay } 6333b9be6dSChris Kay 6433b9be6dSChris Kay static inline __unused uint32_t read_amcntenset1_px(void) 6533b9be6dSChris Kay { 6633b9be6dSChris Kay return (read_amcntenset1() >> AMCNTENSET1_Pn_SHIFT) & 6733b9be6dSChris Kay AMCNTENSET1_Pn_MASK; 6833b9be6dSChris Kay } 6933b9be6dSChris Kay 7033b9be6dSChris Kay static inline __unused void write_amcntenset0_px(uint32_t px) 7133b9be6dSChris Kay { 7233b9be6dSChris Kay uint32_t value = read_amcntenset0(); 7333b9be6dSChris Kay 7433b9be6dSChris Kay value &= ~AMCNTENSET0_Pn_MASK; 7533b9be6dSChris Kay value |= (px << AMCNTENSET0_Pn_SHIFT) & 7633b9be6dSChris Kay AMCNTENSET0_Pn_MASK; 7733b9be6dSChris Kay 7833b9be6dSChris Kay write_amcntenset0(value); 7933b9be6dSChris Kay } 8033b9be6dSChris Kay 8133b9be6dSChris Kay static inline __unused void write_amcntenset1_px(uint32_t px) 8233b9be6dSChris Kay { 8333b9be6dSChris Kay uint32_t value = read_amcntenset1(); 8433b9be6dSChris Kay 8533b9be6dSChris Kay value &= ~AMCNTENSET1_Pn_MASK; 8633b9be6dSChris Kay value |= (px << AMCNTENSET1_Pn_SHIFT) & 8733b9be6dSChris Kay AMCNTENSET1_Pn_MASK; 8833b9be6dSChris Kay 8933b9be6dSChris Kay write_amcntenset1(value); 9033b9be6dSChris Kay } 9133b9be6dSChris Kay 9233b9be6dSChris Kay static inline __unused void write_amcntenclr0_px(uint32_t px) 9333b9be6dSChris Kay { 9433b9be6dSChris Kay uint32_t value = read_amcntenclr0(); 9533b9be6dSChris Kay 9633b9be6dSChris Kay value &= ~AMCNTENCLR0_Pn_MASK; 9733b9be6dSChris Kay value |= (px << AMCNTENCLR0_Pn_SHIFT) & AMCNTENCLR0_Pn_MASK; 9833b9be6dSChris Kay 9933b9be6dSChris Kay write_amcntenclr0(value); 10033b9be6dSChris Kay } 10133b9be6dSChris Kay 10233b9be6dSChris Kay static inline __unused void write_amcntenclr1_px(uint32_t px) 10333b9be6dSChris Kay { 10433b9be6dSChris Kay uint32_t value = read_amcntenclr1(); 10533b9be6dSChris Kay 10633b9be6dSChris Kay value &= ~AMCNTENCLR1_Pn_MASK; 10733b9be6dSChris Kay value |= (px << AMCNTENCLR1_Pn_SHIFT) & AMCNTENCLR1_Pn_MASK; 10833b9be6dSChris Kay 10933b9be6dSChris Kay write_amcntenclr1(value); 11033b9be6dSChris Kay } 11133b9be6dSChris Kay 11233b9be6dSChris Kay static bool amu_supported(void) 11333b9be6dSChris Kay { 11433b9be6dSChris Kay return read_id_pfr0_amu() >= ID_PFR0_AMU_V1; 11533b9be6dSChris Kay } 11633b9be6dSChris Kay 11733b9be6dSChris Kay static bool amu_v1p1_supported(void) 11833b9be6dSChris Kay { 11933b9be6dSChris Kay return read_id_pfr0_amu() >= ID_PFR0_AMU_V1P1; 12033b9be6dSChris Kay } 12133b9be6dSChris Kay 12233b9be6dSChris Kay #if ENABLE_AMU_AUXILIARY_COUNTERS 123b4b726eaSChris Kay static bool amu_group1_supported(void) 124f3ccf036SAlexei Fedorov { 12533b9be6dSChris Kay return read_amcfgr_ncg() > 0U; 126f3ccf036SAlexei Fedorov } 127f3ccf036SAlexei Fedorov #endif 128f3ccf036SAlexei Fedorov 129f3ccf036SAlexei Fedorov /* 130f3ccf036SAlexei Fedorov * Enable counters. This function is meant to be invoked 131f3ccf036SAlexei Fedorov * by the context management library before exiting from EL3. 132f3ccf036SAlexei Fedorov */ 13340daecc1SAntonio Nino Diaz void amu_enable(bool el2_unused) 134c70da546SJoel Hutton { 13533b9be6dSChris Kay if (!amu_supported()) { 1360767d50eSDimitris Papastamos return; 137f3ccf036SAlexei Fedorov } 138f3ccf036SAlexei Fedorov 139ef69e1eaSDimitris Papastamos if (el2_unused) { 140ef69e1eaSDimitris Papastamos /* 141ef69e1eaSDimitris Papastamos * Non-secure access from EL0 or EL1 to the Activity Monitor 142ef69e1eaSDimitris Papastamos * registers do not trap to EL2. 143ef69e1eaSDimitris Papastamos */ 14433b9be6dSChris Kay write_hcptr_tam(0U); 145ef69e1eaSDimitris Papastamos } 146ef69e1eaSDimitris Papastamos 147ef69e1eaSDimitris Papastamos /* Enable group 0 counters */ 14881e2ff1fSChris Kay write_amcntenset0_px((UINT32_C(1) << read_amcgcr_cg0nc()) - 1U); 149c70da546SJoel Hutton 1501fd685a7SChris Kay #if ENABLE_AMU_AUXILIARY_COUNTERS 151*31d3cc25SChris Kay if (amu_group1_supported()) { 152c70da546SJoel Hutton /* Enable group 1 counters */ 15333b9be6dSChris Kay write_amcntenset1_px(AMU_GROUP1_COUNTERS_MASK); 1541fd685a7SChris Kay } 155f3ccf036SAlexei Fedorov #endif 156873d4241Sjohpow01 157873d4241Sjohpow01 /* Initialize FEAT_AMUv1p1 features if present. */ 15833b9be6dSChris Kay if (!amu_v1p1_supported()) { 159873d4241Sjohpow01 return; 160873d4241Sjohpow01 } 161873d4241Sjohpow01 162873d4241Sjohpow01 #if AMU_RESTRICT_COUNTERS 163873d4241Sjohpow01 /* 164873d4241Sjohpow01 * FEAT_AMUv1p1 adds a register field to restrict access to group 1 165873d4241Sjohpow01 * counters at all but the highest implemented EL. This is controlled 166873d4241Sjohpow01 * with the AMU_RESTRICT_COUNTERS compile time flag, when set, system 167873d4241Sjohpow01 * register reads at lower ELs return zero. Reads from the memory 168873d4241Sjohpow01 * mapped view are unaffected. 169873d4241Sjohpow01 */ 170873d4241Sjohpow01 VERBOSE("AMU group 1 counter access restricted.\n"); 17133b9be6dSChris Kay write_amcr_cg1rz(1U); 172873d4241Sjohpow01 #else 17333b9be6dSChris Kay write_amcr_cg1rz(0U); 174873d4241Sjohpow01 #endif 175c70da546SJoel Hutton } 176c70da546SJoel Hutton 177c70da546SJoel Hutton /* Read the group 0 counter identified by the given `idx`. */ 178b4b726eaSChris Kay static uint64_t amu_group0_cnt_read(unsigned int idx) 179c70da546SJoel Hutton { 18033b9be6dSChris Kay assert(amu_supported()); 18181e2ff1fSChris Kay assert(idx < read_amcgcr_cg0nc()); 182c70da546SJoel Hutton 183c70da546SJoel Hutton return amu_group0_cnt_read_internal(idx); 184c70da546SJoel Hutton } 185c70da546SJoel Hutton 186f3ccf036SAlexei Fedorov /* Write the group 0 counter identified by the given `idx` with `val` */ 187b4b726eaSChris Kay static void amu_group0_cnt_write(unsigned int idx, uint64_t val) 188c70da546SJoel Hutton { 18933b9be6dSChris Kay assert(amu_supported()); 19081e2ff1fSChris Kay assert(idx < read_amcgcr_cg0nc()); 191c70da546SJoel Hutton 192c70da546SJoel Hutton amu_group0_cnt_write_internal(idx, val); 193c70da546SJoel Hutton isb(); 194c70da546SJoel Hutton } 195c70da546SJoel Hutton 1961fd685a7SChris Kay #if ENABLE_AMU_AUXILIARY_COUNTERS 197f3ccf036SAlexei Fedorov /* Read the group 1 counter identified by the given `idx` */ 198b4b726eaSChris Kay static uint64_t amu_group1_cnt_read(unsigned int idx) 199c70da546SJoel Hutton { 20033b9be6dSChris Kay assert(amu_supported()); 201f3ccf036SAlexei Fedorov assert(amu_group1_supported()); 202*31d3cc25SChris Kay assert(idx < read_amcgcr_cg1nc()); 203c70da546SJoel Hutton 204c70da546SJoel Hutton return amu_group1_cnt_read_internal(idx); 205c70da546SJoel Hutton } 206c70da546SJoel Hutton 207f3ccf036SAlexei Fedorov /* Write the group 1 counter identified by the given `idx` with `val` */ 208b4b726eaSChris Kay static void amu_group1_cnt_write(unsigned int idx, uint64_t val) 209c70da546SJoel Hutton { 21033b9be6dSChris Kay assert(amu_supported()); 211f3ccf036SAlexei Fedorov assert(amu_group1_supported()); 212*31d3cc25SChris Kay assert(idx < read_amcgcr_cg1nc()); 213c70da546SJoel Hutton 214c70da546SJoel Hutton amu_group1_cnt_write_internal(idx, val); 215c70da546SJoel Hutton isb(); 216c70da546SJoel Hutton } 2171fd685a7SChris Kay #endif 218b6eb3932SDimitris Papastamos 219b6eb3932SDimitris Papastamos static void *amu_context_save(const void *arg) 220b6eb3932SDimitris Papastamos { 221f3ccf036SAlexei Fedorov struct amu_ctx *ctx = &amu_ctxs[plat_my_core_pos()]; 222f3ccf036SAlexei Fedorov unsigned int i; 223b6eb3932SDimitris Papastamos 22433b9be6dSChris Kay if (!amu_supported()) { 225b6eb3932SDimitris Papastamos return (void *)-1; 226f3ccf036SAlexei Fedorov } 227b6eb3932SDimitris Papastamos 228f3ccf036SAlexei Fedorov /* Assert that group 0/1 counter configuration is what we expect */ 22981e2ff1fSChris Kay assert(read_amcntenset0_px() == 23081e2ff1fSChris Kay ((UINT32_C(1) << read_amcgcr_cg0nc()) - 1U)); 231b6eb3932SDimitris Papastamos 2321fd685a7SChris Kay #if ENABLE_AMU_AUXILIARY_COUNTERS 233*31d3cc25SChris Kay if (amu_group1_supported()) { 23433b9be6dSChris Kay assert(read_amcntenset1_px() == AMU_GROUP1_COUNTERS_MASK); 2351fd685a7SChris Kay } 236f3ccf036SAlexei Fedorov #endif 237b6eb3932SDimitris Papastamos /* 238f3ccf036SAlexei Fedorov * Disable group 0/1 counters to avoid other observers like SCP sampling 239b6eb3932SDimitris Papastamos * counter values from the future via the memory mapped view. 240b6eb3932SDimitris Papastamos */ 24181e2ff1fSChris Kay write_amcntenclr0_px((UINT32_C(1) << read_amcgcr_cg0nc()) - 1U); 242f3ccf036SAlexei Fedorov 2431fd685a7SChris Kay #if ENABLE_AMU_AUXILIARY_COUNTERS 244*31d3cc25SChris Kay if (amu_group1_supported()) { 24533b9be6dSChris Kay write_amcntenclr1_px(AMU_GROUP1_COUNTERS_MASK); 2461fd685a7SChris Kay } 247f3ccf036SAlexei Fedorov #endif 2481fd685a7SChris Kay 249b6eb3932SDimitris Papastamos isb(); 250b6eb3932SDimitris Papastamos 251f3ccf036SAlexei Fedorov /* Save all group 0 counters */ 25281e2ff1fSChris Kay for (i = 0U; i < read_amcgcr_cg0nc(); i++) { 253c70da546SJoel Hutton ctx->group0_cnts[i] = amu_group0_cnt_read(i); 254f3ccf036SAlexei Fedorov } 255c70da546SJoel Hutton 2561fd685a7SChris Kay #if ENABLE_AMU_AUXILIARY_COUNTERS 257*31d3cc25SChris Kay if (amu_group1_supported()) { 258f3ccf036SAlexei Fedorov /* Save group 1 counters */ 259*31d3cc25SChris Kay for (i = 0U; i < read_amcgcr_cg1nc(); i++) { 260f3ccf036SAlexei Fedorov if ((AMU_GROUP1_COUNTERS_MASK & (1U << i)) != 0U) { 261c70da546SJoel Hutton ctx->group1_cnts[i] = amu_group1_cnt_read(i); 262f3ccf036SAlexei Fedorov } 263f3ccf036SAlexei Fedorov } 2641fd685a7SChris Kay } 265f3ccf036SAlexei Fedorov #endif 2661fd685a7SChris Kay 26740daecc1SAntonio Nino Diaz return (void *)0; 268b6eb3932SDimitris Papastamos } 269b6eb3932SDimitris Papastamos 270b6eb3932SDimitris Papastamos static void *amu_context_restore(const void *arg) 271b6eb3932SDimitris Papastamos { 272f3ccf036SAlexei Fedorov struct amu_ctx *ctx = &amu_ctxs[plat_my_core_pos()]; 273f3ccf036SAlexei Fedorov unsigned int i; 274b6eb3932SDimitris Papastamos 27533b9be6dSChris Kay if (!amu_supported()) { 276b6eb3932SDimitris Papastamos return (void *)-1; 277f3ccf036SAlexei Fedorov } 278b6eb3932SDimitris Papastamos 279b6eb3932SDimitris Papastamos /* Counters were disabled in `amu_context_save()` */ 28033b9be6dSChris Kay assert(read_amcntenset0_px() == 0U); 281b6eb3932SDimitris Papastamos 2821fd685a7SChris Kay #if ENABLE_AMU_AUXILIARY_COUNTERS 283*31d3cc25SChris Kay if (amu_group1_supported()) { 28433b9be6dSChris Kay assert(read_amcntenset1_px() == 0U); 2851fd685a7SChris Kay } 286f3ccf036SAlexei Fedorov #endif 287f3ccf036SAlexei Fedorov 288f3ccf036SAlexei Fedorov /* Restore all group 0 counters */ 28981e2ff1fSChris Kay for (i = 0U; i < read_amcgcr_cg0nc(); i++) { 290c70da546SJoel Hutton amu_group0_cnt_write(i, ctx->group0_cnts[i]); 291f3ccf036SAlexei Fedorov } 292b6eb3932SDimitris Papastamos 293f3ccf036SAlexei Fedorov /* Restore group 0 counter configuration */ 29481e2ff1fSChris Kay write_amcntenset0_px((UINT32_C(1) << read_amcgcr_cg0nc()) - 1U); 295b6eb3932SDimitris Papastamos 2961fd685a7SChris Kay #if ENABLE_AMU_AUXILIARY_COUNTERS 297*31d3cc25SChris Kay if (amu_group1_supported()) { 298f3ccf036SAlexei Fedorov /* Restore group 1 counters */ 299*31d3cc25SChris Kay for (i = 0U; i < read_amcgcr_cg1nc(); i++) { 300f3ccf036SAlexei Fedorov if ((AMU_GROUP1_COUNTERS_MASK & (1U << i)) != 0U) { 301f3ccf036SAlexei Fedorov amu_group1_cnt_write(i, ctx->group1_cnts[i]); 302f3ccf036SAlexei Fedorov } 303f3ccf036SAlexei Fedorov } 304f3ccf036SAlexei Fedorov 305f3ccf036SAlexei Fedorov /* Restore group 1 counter configuration */ 30633b9be6dSChris Kay write_amcntenset1_px(AMU_GROUP1_COUNTERS_MASK); 3071fd685a7SChris Kay } 308f3ccf036SAlexei Fedorov #endif 309f3ccf036SAlexei Fedorov 31040daecc1SAntonio Nino Diaz return (void *)0; 311b6eb3932SDimitris Papastamos } 312b6eb3932SDimitris Papastamos 313b6eb3932SDimitris Papastamos SUBSCRIBE_TO_EVENT(psci_suspend_pwrdown_start, amu_context_save); 314b6eb3932SDimitris Papastamos SUBSCRIBE_TO_EVENT(psci_suspend_pwrdown_finish, amu_context_restore); 315