1ef69e1eaSDimitris Papastamos /* 2c6cc9ac3SDimitris Papastamos * Copyright (c) 2017-2018, ARM Limited and Contributors. All rights reserved. 3ef69e1eaSDimitris Papastamos * 4ef69e1eaSDimitris Papastamos * SPDX-License-Identifier: BSD-3-Clause 5ef69e1eaSDimitris Papastamos */ 6ef69e1eaSDimitris Papastamos 7*09d40e0eSAntonio Nino Diaz #include <stdbool.h> 8*09d40e0eSAntonio Nino Diaz 9ef69e1eaSDimitris Papastamos #include <arch.h> 10ef69e1eaSDimitris Papastamos #include <arch_helpers.h> 11*09d40e0eSAntonio Nino Diaz #include <lib/el3_runtime/pubsub_events.h> 12*09d40e0eSAntonio Nino Diaz #include <lib/extensions/amu.h> 13*09d40e0eSAntonio Nino Diaz #include <lib/extensions/amu_private.h> 14*09d40e0eSAntonio Nino Diaz #include <plat/common/platform.h> 15b6eb3932SDimitris Papastamos 16b6eb3932SDimitris Papastamos #define AMU_GROUP0_NR_COUNTERS 4 17b6eb3932SDimitris Papastamos 18b6eb3932SDimitris Papastamos struct amu_ctx { 19b6eb3932SDimitris Papastamos uint64_t group0_cnts[AMU_GROUP0_NR_COUNTERS]; 20c70da546SJoel Hutton uint64_t group1_cnts[AMU_GROUP1_NR_COUNTERS]; 21b6eb3932SDimitris Papastamos }; 22b6eb3932SDimitris Papastamos 23b6eb3932SDimitris Papastamos static struct amu_ctx amu_ctxs[PLATFORM_CORE_COUNT]; 24ef69e1eaSDimitris Papastamos 2540daecc1SAntonio Nino Diaz bool amu_supported(void) 26ef69e1eaSDimitris Papastamos { 27ef69e1eaSDimitris Papastamos uint64_t features; 28ef69e1eaSDimitris Papastamos 29ef69e1eaSDimitris Papastamos features = read_id_pfr0() >> ID_PFR0_AMU_SHIFT; 3040daecc1SAntonio Nino Diaz return (features & ID_PFR0_AMU_MASK) == 1U; 31c70da546SJoel Hutton } 32c70da546SJoel Hutton 3340daecc1SAntonio Nino Diaz void amu_enable(bool el2_unused) 34c70da546SJoel Hutton { 3540daecc1SAntonio Nino Diaz if (!amu_supported()) 360767d50eSDimitris Papastamos return; 370767d50eSDimitris Papastamos 38ef69e1eaSDimitris Papastamos if (el2_unused) { 39ef69e1eaSDimitris Papastamos uint64_t v; 40ef69e1eaSDimitris Papastamos /* 41ef69e1eaSDimitris Papastamos * Non-secure access from EL0 or EL1 to the Activity Monitor 42ef69e1eaSDimitris Papastamos * registers do not trap to EL2. 43ef69e1eaSDimitris Papastamos */ 44ef69e1eaSDimitris Papastamos v = read_hcptr(); 45ef69e1eaSDimitris Papastamos v &= ~TAM_BIT; 46ef69e1eaSDimitris Papastamos write_hcptr(v); 47ef69e1eaSDimitris Papastamos } 48ef69e1eaSDimitris Papastamos 49ef69e1eaSDimitris Papastamos /* Enable group 0 counters */ 50ef69e1eaSDimitris Papastamos write_amcntenset0(AMU_GROUP0_COUNTERS_MASK); 51c70da546SJoel Hutton 52c70da546SJoel Hutton /* Enable group 1 counters */ 53c70da546SJoel Hutton write_amcntenset1(AMU_GROUP1_COUNTERS_MASK); 54c70da546SJoel Hutton } 55c70da546SJoel Hutton 56c70da546SJoel Hutton /* Read the group 0 counter identified by the given `idx`. */ 57c70da546SJoel Hutton uint64_t amu_group0_cnt_read(int idx) 58c70da546SJoel Hutton { 5940daecc1SAntonio Nino Diaz assert(amu_supported()); 6040daecc1SAntonio Nino Diaz assert((idx >= 0) && (idx < AMU_GROUP0_NR_COUNTERS)); 61c70da546SJoel Hutton 62c70da546SJoel Hutton return amu_group0_cnt_read_internal(idx); 63c70da546SJoel Hutton } 64c70da546SJoel Hutton 65c70da546SJoel Hutton /* Write the group 0 counter identified by the given `idx` with `val`. */ 66c70da546SJoel Hutton void amu_group0_cnt_write(int idx, uint64_t val) 67c70da546SJoel Hutton { 6840daecc1SAntonio Nino Diaz assert(amu_supported()); 6940daecc1SAntonio Nino Diaz assert((idx >= 0) && (idx < AMU_GROUP0_NR_COUNTERS)); 70c70da546SJoel Hutton 71c70da546SJoel Hutton amu_group0_cnt_write_internal(idx, val); 72c70da546SJoel Hutton isb(); 73c70da546SJoel Hutton } 74c70da546SJoel Hutton 75c70da546SJoel Hutton /* Read the group 1 counter identified by the given `idx`. */ 76c70da546SJoel Hutton uint64_t amu_group1_cnt_read(int idx) 77c70da546SJoel Hutton { 7840daecc1SAntonio Nino Diaz assert(amu_supported()); 7940daecc1SAntonio Nino Diaz assert((idx >= 0) && (idx < AMU_GROUP1_NR_COUNTERS)); 80c70da546SJoel Hutton 81c70da546SJoel Hutton return amu_group1_cnt_read_internal(idx); 82c70da546SJoel Hutton } 83c70da546SJoel Hutton 84c70da546SJoel Hutton /* Write the group 1 counter identified by the given `idx` with `val`. */ 85c70da546SJoel Hutton void amu_group1_cnt_write(int idx, uint64_t val) 86c70da546SJoel Hutton { 8740daecc1SAntonio Nino Diaz assert(amu_supported()); 8840daecc1SAntonio Nino Diaz assert((idx >= 0) && (idx < AMU_GROUP1_NR_COUNTERS)); 89c70da546SJoel Hutton 90c70da546SJoel Hutton amu_group1_cnt_write_internal(idx, val); 91c70da546SJoel Hutton isb(); 92c70da546SJoel Hutton } 93c70da546SJoel Hutton 94c70da546SJoel Hutton void amu_group1_set_evtype(int idx, unsigned int val) 95c70da546SJoel Hutton { 9640daecc1SAntonio Nino Diaz assert(amu_supported()); 9740daecc1SAntonio Nino Diaz assert((idx >= 0) && (idx < AMU_GROUP1_NR_COUNTERS)); 98c70da546SJoel Hutton 99c70da546SJoel Hutton amu_group1_set_evtype_internal(idx, val); 100c70da546SJoel Hutton isb(); 101ef69e1eaSDimitris Papastamos } 102b6eb3932SDimitris Papastamos 103b6eb3932SDimitris Papastamos static void *amu_context_save(const void *arg) 104b6eb3932SDimitris Papastamos { 105b6eb3932SDimitris Papastamos struct amu_ctx *ctx; 106c70da546SJoel Hutton int i; 107b6eb3932SDimitris Papastamos 10840daecc1SAntonio Nino Diaz if (!amu_supported()) 109b6eb3932SDimitris Papastamos return (void *)-1; 110b6eb3932SDimitris Papastamos 111b6eb3932SDimitris Papastamos ctx = &amu_ctxs[plat_my_core_pos()]; 112b6eb3932SDimitris Papastamos 113b6eb3932SDimitris Papastamos /* Assert that group 0 counter configuration is what we expect */ 114e6e17ee8SDimitris Papastamos assert(read_amcntenset0() == AMU_GROUP0_COUNTERS_MASK && 115e6e17ee8SDimitris Papastamos read_amcntenset1() == AMU_GROUP1_COUNTERS_MASK); 116b6eb3932SDimitris Papastamos 117b6eb3932SDimitris Papastamos /* 118b6eb3932SDimitris Papastamos * Disable group 0 counters to avoid other observers like SCP sampling 119b6eb3932SDimitris Papastamos * counter values from the future via the memory mapped view. 120b6eb3932SDimitris Papastamos */ 121b6eb3932SDimitris Papastamos write_amcntenclr0(AMU_GROUP0_COUNTERS_MASK); 122c70da546SJoel Hutton write_amcntenclr1(AMU_GROUP1_COUNTERS_MASK); 123b6eb3932SDimitris Papastamos isb(); 124b6eb3932SDimitris Papastamos 125c70da546SJoel Hutton for (i = 0; i < AMU_GROUP0_NR_COUNTERS; i++) 126c70da546SJoel Hutton ctx->group0_cnts[i] = amu_group0_cnt_read(i); 127c70da546SJoel Hutton 128c70da546SJoel Hutton for (i = 0; i < AMU_GROUP1_NR_COUNTERS; i++) 129c70da546SJoel Hutton ctx->group1_cnts[i] = amu_group1_cnt_read(i); 130b6eb3932SDimitris Papastamos 13140daecc1SAntonio Nino Diaz return (void *)0; 132b6eb3932SDimitris Papastamos } 133b6eb3932SDimitris Papastamos 134b6eb3932SDimitris Papastamos static void *amu_context_restore(const void *arg) 135b6eb3932SDimitris Papastamos { 136b6eb3932SDimitris Papastamos struct amu_ctx *ctx; 137c70da546SJoel Hutton int i; 138b6eb3932SDimitris Papastamos 13940daecc1SAntonio Nino Diaz if (!amu_supported()) 140b6eb3932SDimitris Papastamos return (void *)-1; 141b6eb3932SDimitris Papastamos 142b6eb3932SDimitris Papastamos ctx = &amu_ctxs[plat_my_core_pos()]; 143b6eb3932SDimitris Papastamos 144b6eb3932SDimitris Papastamos /* Counters were disabled in `amu_context_save()` */ 14540daecc1SAntonio Nino Diaz assert((read_amcntenset0() == 0U) && (read_amcntenset1() == 0U)); 146b6eb3932SDimitris Papastamos 147b6eb3932SDimitris Papastamos /* Restore group 0 counters */ 148c70da546SJoel Hutton for (i = 0; i < AMU_GROUP0_NR_COUNTERS; i++) 149c70da546SJoel Hutton amu_group0_cnt_write(i, ctx->group0_cnts[i]); 150c70da546SJoel Hutton for (i = 0; i < AMU_GROUP1_NR_COUNTERS; i++) 151c70da546SJoel Hutton amu_group1_cnt_write(i, ctx->group1_cnts[i]); 152b6eb3932SDimitris Papastamos 153b6eb3932SDimitris Papastamos /* Enable group 0 counters */ 154b6eb3932SDimitris Papastamos write_amcntenset0(AMU_GROUP0_COUNTERS_MASK); 155b6eb3932SDimitris Papastamos 156c70da546SJoel Hutton /* Enable group 1 counters */ 157c70da546SJoel Hutton write_amcntenset1(AMU_GROUP1_COUNTERS_MASK); 15840daecc1SAntonio Nino Diaz return (void *)0; 159b6eb3932SDimitris Papastamos } 160b6eb3932SDimitris Papastamos 161b6eb3932SDimitris Papastamos SUBSCRIBE_TO_EVENT(psci_suspend_pwrdown_start, amu_context_save); 162b6eb3932SDimitris Papastamos SUBSCRIBE_TO_EVENT(psci_suspend_pwrdown_finish, amu_context_restore); 163