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 4633b9be6dSChris Kay static inline __unused uint32_t read_amcgcr_cg1nc(void) 4733b9be6dSChris Kay { 4833b9be6dSChris Kay return (read_amcgcr() >> AMCGCR_CG1NC_SHIFT) & 4933b9be6dSChris Kay AMCGCR_CG1NC_MASK; 5033b9be6dSChris Kay } 5133b9be6dSChris Kay 5233b9be6dSChris Kay static inline __unused uint32_t read_amcntenset0_px(void) 5333b9be6dSChris Kay { 5433b9be6dSChris Kay return (read_amcntenset0() >> AMCNTENSET0_Pn_SHIFT) & 5533b9be6dSChris Kay AMCNTENSET0_Pn_MASK; 5633b9be6dSChris Kay } 5733b9be6dSChris Kay 5833b9be6dSChris Kay static inline __unused uint32_t read_amcntenset1_px(void) 5933b9be6dSChris Kay { 6033b9be6dSChris Kay return (read_amcntenset1() >> AMCNTENSET1_Pn_SHIFT) & 6133b9be6dSChris Kay AMCNTENSET1_Pn_MASK; 6233b9be6dSChris Kay } 6333b9be6dSChris Kay 6433b9be6dSChris Kay static inline __unused void write_amcntenset0_px(uint32_t px) 6533b9be6dSChris Kay { 6633b9be6dSChris Kay uint32_t value = read_amcntenset0(); 6733b9be6dSChris Kay 6833b9be6dSChris Kay value &= ~AMCNTENSET0_Pn_MASK; 6933b9be6dSChris Kay value |= (px << AMCNTENSET0_Pn_SHIFT) & 7033b9be6dSChris Kay AMCNTENSET0_Pn_MASK; 7133b9be6dSChris Kay 7233b9be6dSChris Kay write_amcntenset0(value); 7333b9be6dSChris Kay } 7433b9be6dSChris Kay 7533b9be6dSChris Kay static inline __unused void write_amcntenset1_px(uint32_t px) 7633b9be6dSChris Kay { 7733b9be6dSChris Kay uint32_t value = read_amcntenset1(); 7833b9be6dSChris Kay 7933b9be6dSChris Kay value &= ~AMCNTENSET1_Pn_MASK; 8033b9be6dSChris Kay value |= (px << AMCNTENSET1_Pn_SHIFT) & 8133b9be6dSChris Kay AMCNTENSET1_Pn_MASK; 8233b9be6dSChris Kay 8333b9be6dSChris Kay write_amcntenset1(value); 8433b9be6dSChris Kay } 8533b9be6dSChris Kay 8633b9be6dSChris Kay static inline __unused void write_amcntenclr0_px(uint32_t px) 8733b9be6dSChris Kay { 8833b9be6dSChris Kay uint32_t value = read_amcntenclr0(); 8933b9be6dSChris Kay 9033b9be6dSChris Kay value &= ~AMCNTENCLR0_Pn_MASK; 9133b9be6dSChris Kay value |= (px << AMCNTENCLR0_Pn_SHIFT) & AMCNTENCLR0_Pn_MASK; 9233b9be6dSChris Kay 9333b9be6dSChris Kay write_amcntenclr0(value); 9433b9be6dSChris Kay } 9533b9be6dSChris Kay 9633b9be6dSChris Kay static inline __unused void write_amcntenclr1_px(uint32_t px) 9733b9be6dSChris Kay { 9833b9be6dSChris Kay uint32_t value = read_amcntenclr1(); 9933b9be6dSChris Kay 10033b9be6dSChris Kay value &= ~AMCNTENCLR1_Pn_MASK; 10133b9be6dSChris Kay value |= (px << AMCNTENCLR1_Pn_SHIFT) & AMCNTENCLR1_Pn_MASK; 10233b9be6dSChris Kay 10333b9be6dSChris Kay write_amcntenclr1(value); 10433b9be6dSChris Kay } 10533b9be6dSChris Kay 10633b9be6dSChris Kay static bool amu_supported(void) 10733b9be6dSChris Kay { 10833b9be6dSChris Kay return read_id_pfr0_amu() >= ID_PFR0_AMU_V1; 10933b9be6dSChris Kay } 11033b9be6dSChris Kay 11133b9be6dSChris Kay static bool amu_v1p1_supported(void) 11233b9be6dSChris Kay { 11333b9be6dSChris Kay return read_id_pfr0_amu() >= ID_PFR0_AMU_V1P1; 11433b9be6dSChris Kay } 11533b9be6dSChris Kay 11633b9be6dSChris Kay #if ENABLE_AMU_AUXILIARY_COUNTERS 117b4b726eaSChris Kay static bool amu_group1_supported(void) 118f3ccf036SAlexei Fedorov { 11933b9be6dSChris Kay return read_amcfgr_ncg() > 0U; 120f3ccf036SAlexei Fedorov } 121f3ccf036SAlexei Fedorov #endif 122f3ccf036SAlexei Fedorov 123f3ccf036SAlexei Fedorov /* 124f3ccf036SAlexei Fedorov * Enable counters. This function is meant to be invoked 125f3ccf036SAlexei Fedorov * by the context management library before exiting from EL3. 126f3ccf036SAlexei Fedorov */ 12740daecc1SAntonio Nino Diaz void amu_enable(bool el2_unused) 128c70da546SJoel Hutton { 12933b9be6dSChris Kay if (!amu_supported()) { 1300767d50eSDimitris Papastamos return; 131f3ccf036SAlexei Fedorov } 132f3ccf036SAlexei Fedorov 133*1fd685a7SChris Kay #if ENABLE_AMU_AUXILIARY_COUNTERS 134*1fd685a7SChris Kay if (AMU_GROUP1_NR_COUNTERS > 0U) { 135f3ccf036SAlexei Fedorov /* Check and set presence of group 1 counters */ 136f3ccf036SAlexei Fedorov if (!amu_group1_supported()) { 137f3ccf036SAlexei Fedorov ERROR("AMU Counter Group 1 is not implemented\n"); 138f3ccf036SAlexei Fedorov panic(); 139f3ccf036SAlexei Fedorov } 140f3ccf036SAlexei Fedorov 141f3ccf036SAlexei Fedorov /* Check number of group 1 counters */ 14233b9be6dSChris Kay uint32_t cnt_num = read_amcgcr_cg1nc(); 143*1fd685a7SChris Kay 144f3ccf036SAlexei Fedorov VERBOSE("%s%u. %s%u\n", 145f3ccf036SAlexei Fedorov "Number of AMU Group 1 Counters ", cnt_num, 146f3ccf036SAlexei Fedorov "Requested number ", AMU_GROUP1_NR_COUNTERS); 147f3ccf036SAlexei Fedorov 148f3ccf036SAlexei Fedorov if (cnt_num < AMU_GROUP1_NR_COUNTERS) { 149f3ccf036SAlexei Fedorov ERROR("%s%u is less than %s%u\n", 150f3ccf036SAlexei Fedorov "Number of AMU Group 1 Counters ", cnt_num, 151f3ccf036SAlexei Fedorov "Requested number ", AMU_GROUP1_NR_COUNTERS); 152f3ccf036SAlexei Fedorov panic(); 153f3ccf036SAlexei Fedorov } 154*1fd685a7SChris Kay } 155f3ccf036SAlexei Fedorov #endif 1560767d50eSDimitris Papastamos 157ef69e1eaSDimitris Papastamos if (el2_unused) { 158ef69e1eaSDimitris Papastamos /* 159ef69e1eaSDimitris Papastamos * Non-secure access from EL0 or EL1 to the Activity Monitor 160ef69e1eaSDimitris Papastamos * registers do not trap to EL2. 161ef69e1eaSDimitris Papastamos */ 16233b9be6dSChris Kay write_hcptr_tam(0U); 163ef69e1eaSDimitris Papastamos } 164ef69e1eaSDimitris Papastamos 165ef69e1eaSDimitris Papastamos /* Enable group 0 counters */ 16633b9be6dSChris Kay write_amcntenset0_px(AMU_GROUP0_COUNTERS_MASK); 167c70da546SJoel Hutton 168*1fd685a7SChris Kay #if ENABLE_AMU_AUXILIARY_COUNTERS 169*1fd685a7SChris Kay if (AMU_GROUP1_NR_COUNTERS > 0U) { 170c70da546SJoel Hutton /* Enable group 1 counters */ 17133b9be6dSChris Kay write_amcntenset1_px(AMU_GROUP1_COUNTERS_MASK); 172*1fd685a7SChris Kay } 173f3ccf036SAlexei Fedorov #endif 174873d4241Sjohpow01 175873d4241Sjohpow01 /* Initialize FEAT_AMUv1p1 features if present. */ 17633b9be6dSChris Kay if (!amu_v1p1_supported()) { 177873d4241Sjohpow01 return; 178873d4241Sjohpow01 } 179873d4241Sjohpow01 180873d4241Sjohpow01 #if AMU_RESTRICT_COUNTERS 181873d4241Sjohpow01 /* 182873d4241Sjohpow01 * FEAT_AMUv1p1 adds a register field to restrict access to group 1 183873d4241Sjohpow01 * counters at all but the highest implemented EL. This is controlled 184873d4241Sjohpow01 * with the AMU_RESTRICT_COUNTERS compile time flag, when set, system 185873d4241Sjohpow01 * register reads at lower ELs return zero. Reads from the memory 186873d4241Sjohpow01 * mapped view are unaffected. 187873d4241Sjohpow01 */ 188873d4241Sjohpow01 VERBOSE("AMU group 1 counter access restricted.\n"); 18933b9be6dSChris Kay write_amcr_cg1rz(1U); 190873d4241Sjohpow01 #else 19133b9be6dSChris Kay write_amcr_cg1rz(0U); 192873d4241Sjohpow01 #endif 193c70da546SJoel Hutton } 194c70da546SJoel Hutton 195c70da546SJoel Hutton /* Read the group 0 counter identified by the given `idx`. */ 196b4b726eaSChris Kay static uint64_t amu_group0_cnt_read(unsigned int idx) 197c70da546SJoel Hutton { 19833b9be6dSChris Kay assert(amu_supported()); 199f3ccf036SAlexei Fedorov assert(idx < AMU_GROUP0_NR_COUNTERS); 200c70da546SJoel Hutton 201c70da546SJoel Hutton return amu_group0_cnt_read_internal(idx); 202c70da546SJoel Hutton } 203c70da546SJoel Hutton 204f3ccf036SAlexei Fedorov /* Write the group 0 counter identified by the given `idx` with `val` */ 205b4b726eaSChris Kay static void amu_group0_cnt_write(unsigned int idx, uint64_t val) 206c70da546SJoel Hutton { 20733b9be6dSChris Kay assert(amu_supported()); 208f3ccf036SAlexei Fedorov assert(idx < AMU_GROUP0_NR_COUNTERS); 209c70da546SJoel Hutton 210c70da546SJoel Hutton amu_group0_cnt_write_internal(idx, val); 211c70da546SJoel Hutton isb(); 212c70da546SJoel Hutton } 213c70da546SJoel Hutton 214*1fd685a7SChris Kay #if ENABLE_AMU_AUXILIARY_COUNTERS 215f3ccf036SAlexei Fedorov /* Read the group 1 counter identified by the given `idx` */ 216b4b726eaSChris Kay static uint64_t amu_group1_cnt_read(unsigned int idx) 217c70da546SJoel Hutton { 21833b9be6dSChris Kay assert(amu_supported()); 219f3ccf036SAlexei Fedorov assert(amu_group1_supported()); 220f3ccf036SAlexei Fedorov assert(idx < AMU_GROUP1_NR_COUNTERS); 221c70da546SJoel Hutton 222c70da546SJoel Hutton return amu_group1_cnt_read_internal(idx); 223c70da546SJoel Hutton } 224c70da546SJoel Hutton 225f3ccf036SAlexei Fedorov /* Write the group 1 counter identified by the given `idx` with `val` */ 226b4b726eaSChris Kay static void amu_group1_cnt_write(unsigned int idx, uint64_t val) 227c70da546SJoel Hutton { 22833b9be6dSChris Kay assert(amu_supported()); 229f3ccf036SAlexei Fedorov assert(amu_group1_supported()); 230f3ccf036SAlexei Fedorov assert(idx < AMU_GROUP1_NR_COUNTERS); 231c70da546SJoel Hutton 232c70da546SJoel Hutton amu_group1_cnt_write_internal(idx, val); 233c70da546SJoel Hutton isb(); 234c70da546SJoel Hutton } 235*1fd685a7SChris Kay #endif 236b6eb3932SDimitris Papastamos 237b6eb3932SDimitris Papastamos static void *amu_context_save(const void *arg) 238b6eb3932SDimitris Papastamos { 239f3ccf036SAlexei Fedorov struct amu_ctx *ctx = &amu_ctxs[plat_my_core_pos()]; 240f3ccf036SAlexei Fedorov unsigned int i; 241b6eb3932SDimitris Papastamos 24233b9be6dSChris Kay if (!amu_supported()) { 243b6eb3932SDimitris Papastamos return (void *)-1; 244f3ccf036SAlexei Fedorov } 245b6eb3932SDimitris Papastamos 246*1fd685a7SChris Kay #if ENABLE_AMU_AUXILIARY_COUNTERS 247*1fd685a7SChris Kay if (AMU_GROUP1_NR_COUNTERS > 0U) { 248f3ccf036SAlexei Fedorov if (!amu_group1_supported()) { 249f3ccf036SAlexei Fedorov return (void *)-1; 250f3ccf036SAlexei Fedorov } 251*1fd685a7SChris Kay } 252f3ccf036SAlexei Fedorov #endif 253*1fd685a7SChris Kay 254f3ccf036SAlexei Fedorov /* Assert that group 0/1 counter configuration is what we expect */ 25533b9be6dSChris Kay assert(read_amcntenset0_px() == AMU_GROUP0_COUNTERS_MASK); 256b6eb3932SDimitris Papastamos 257*1fd685a7SChris Kay #if ENABLE_AMU_AUXILIARY_COUNTERS 258*1fd685a7SChris Kay if (AMU_GROUP1_NR_COUNTERS > 0U) { 25933b9be6dSChris Kay assert(read_amcntenset1_px() == AMU_GROUP1_COUNTERS_MASK); 260*1fd685a7SChris Kay } 261f3ccf036SAlexei Fedorov #endif 262b6eb3932SDimitris Papastamos /* 263f3ccf036SAlexei Fedorov * Disable group 0/1 counters to avoid other observers like SCP sampling 264b6eb3932SDimitris Papastamos * counter values from the future via the memory mapped view. 265b6eb3932SDimitris Papastamos */ 26633b9be6dSChris Kay write_amcntenclr0_px(AMU_GROUP0_COUNTERS_MASK); 267f3ccf036SAlexei Fedorov 268*1fd685a7SChris Kay #if ENABLE_AMU_AUXILIARY_COUNTERS 269*1fd685a7SChris Kay if (AMU_GROUP1_NR_COUNTERS > 0U) { 27033b9be6dSChris Kay write_amcntenclr1_px(AMU_GROUP1_COUNTERS_MASK); 271*1fd685a7SChris Kay } 272f3ccf036SAlexei Fedorov #endif 273*1fd685a7SChris Kay 274b6eb3932SDimitris Papastamos isb(); 275b6eb3932SDimitris Papastamos 276f3ccf036SAlexei Fedorov /* Save all group 0 counters */ 277f3ccf036SAlexei Fedorov for (i = 0U; i < AMU_GROUP0_NR_COUNTERS; i++) { 278c70da546SJoel Hutton ctx->group0_cnts[i] = amu_group0_cnt_read(i); 279f3ccf036SAlexei Fedorov } 280c70da546SJoel Hutton 281*1fd685a7SChris Kay #if ENABLE_AMU_AUXILIARY_COUNTERS 282*1fd685a7SChris Kay if (AMU_GROUP1_NR_COUNTERS > 0U) { 283f3ccf036SAlexei Fedorov /* Save group 1 counters */ 284f3ccf036SAlexei Fedorov for (i = 0U; i < AMU_GROUP1_NR_COUNTERS; i++) { 285f3ccf036SAlexei Fedorov if ((AMU_GROUP1_COUNTERS_MASK & (1U << i)) != 0U) { 286c70da546SJoel Hutton ctx->group1_cnts[i] = amu_group1_cnt_read(i); 287f3ccf036SAlexei Fedorov } 288f3ccf036SAlexei Fedorov } 289*1fd685a7SChris Kay } 290f3ccf036SAlexei Fedorov #endif 291*1fd685a7SChris Kay 29240daecc1SAntonio Nino Diaz return (void *)0; 293b6eb3932SDimitris Papastamos } 294b6eb3932SDimitris Papastamos 295b6eb3932SDimitris Papastamos static void *amu_context_restore(const void *arg) 296b6eb3932SDimitris Papastamos { 297f3ccf036SAlexei Fedorov struct amu_ctx *ctx = &amu_ctxs[plat_my_core_pos()]; 298f3ccf036SAlexei Fedorov unsigned int i; 299b6eb3932SDimitris Papastamos 30033b9be6dSChris Kay if (!amu_supported()) { 301b6eb3932SDimitris Papastamos return (void *)-1; 302f3ccf036SAlexei Fedorov } 303b6eb3932SDimitris Papastamos 304*1fd685a7SChris Kay #if ENABLE_AMU_AUXILIARY_COUNTERS 305*1fd685a7SChris Kay if (AMU_GROUP1_NR_COUNTERS > 0U) { 306*1fd685a7SChris Kay if (!amu_group1_supported()) { 307f3ccf036SAlexei Fedorov return (void *)-1; 308f3ccf036SAlexei Fedorov } 309*1fd685a7SChris Kay } 310f3ccf036SAlexei Fedorov #endif 311*1fd685a7SChris Kay 312b6eb3932SDimitris Papastamos /* Counters were disabled in `amu_context_save()` */ 31333b9be6dSChris Kay assert(read_amcntenset0_px() == 0U); 314b6eb3932SDimitris Papastamos 315*1fd685a7SChris Kay #if ENABLE_AMU_AUXILIARY_COUNTERS 316*1fd685a7SChris Kay if (AMU_GROUP1_NR_COUNTERS > 0U) { 31733b9be6dSChris Kay assert(read_amcntenset1_px() == 0U); 318*1fd685a7SChris Kay } 319f3ccf036SAlexei Fedorov #endif 320f3ccf036SAlexei Fedorov 321f3ccf036SAlexei Fedorov /* Restore all group 0 counters */ 322f3ccf036SAlexei Fedorov for (i = 0U; i < AMU_GROUP0_NR_COUNTERS; i++) { 323c70da546SJoel Hutton amu_group0_cnt_write(i, ctx->group0_cnts[i]); 324f3ccf036SAlexei Fedorov } 325b6eb3932SDimitris Papastamos 326f3ccf036SAlexei Fedorov /* Restore group 0 counter configuration */ 32733b9be6dSChris Kay write_amcntenset0_px(AMU_GROUP0_COUNTERS_MASK); 328b6eb3932SDimitris Papastamos 329*1fd685a7SChris Kay #if ENABLE_AMU_AUXILIARY_COUNTERS 330*1fd685a7SChris Kay if (AMU_GROUP1_NR_COUNTERS > 0U) { 331f3ccf036SAlexei Fedorov /* Restore group 1 counters */ 332f3ccf036SAlexei Fedorov for (i = 0U; i < AMU_GROUP1_NR_COUNTERS; i++) { 333f3ccf036SAlexei Fedorov if ((AMU_GROUP1_COUNTERS_MASK & (1U << i)) != 0U) { 334f3ccf036SAlexei Fedorov amu_group1_cnt_write(i, ctx->group1_cnts[i]); 335f3ccf036SAlexei Fedorov } 336f3ccf036SAlexei Fedorov } 337f3ccf036SAlexei Fedorov 338f3ccf036SAlexei Fedorov /* Restore group 1 counter configuration */ 33933b9be6dSChris Kay write_amcntenset1_px(AMU_GROUP1_COUNTERS_MASK); 340*1fd685a7SChris Kay } 341f3ccf036SAlexei Fedorov #endif 342f3ccf036SAlexei Fedorov 34340daecc1SAntonio Nino Diaz return (void *)0; 344b6eb3932SDimitris Papastamos } 345b6eb3932SDimitris Papastamos 346b6eb3932SDimitris Papastamos SUBSCRIBE_TO_EVENT(psci_suspend_pwrdown_start, amu_context_save); 347b6eb3932SDimitris Papastamos SUBSCRIBE_TO_EVENT(psci_suspend_pwrdown_finish, amu_context_restore); 348