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 7ef69e1eaSDimitris Papastamos #include <amu.h> 8c70da546SJoel Hutton #include <amu_private.h> 9ef69e1eaSDimitris Papastamos #include <arch.h> 10ef69e1eaSDimitris Papastamos #include <arch_helpers.h> 11b6eb3932SDimitris Papastamos #include <platform.h> 12b6eb3932SDimitris Papastamos #include <pubsub_events.h> 13*40daecc1SAntonio Nino Diaz #include <stdbool.h> 14b6eb3932SDimitris Papastamos 15b6eb3932SDimitris Papastamos #define AMU_GROUP0_NR_COUNTERS 4 16b6eb3932SDimitris Papastamos 17b6eb3932SDimitris Papastamos struct amu_ctx { 18b6eb3932SDimitris Papastamos uint64_t group0_cnts[AMU_GROUP0_NR_COUNTERS]; 19c70da546SJoel Hutton uint64_t group1_cnts[AMU_GROUP1_NR_COUNTERS]; 20b6eb3932SDimitris Papastamos }; 21b6eb3932SDimitris Papastamos 22b6eb3932SDimitris Papastamos static struct amu_ctx amu_ctxs[PLATFORM_CORE_COUNT]; 23ef69e1eaSDimitris Papastamos 24*40daecc1SAntonio Nino Diaz bool amu_supported(void) 25ef69e1eaSDimitris Papastamos { 26ef69e1eaSDimitris Papastamos uint64_t features; 27ef69e1eaSDimitris Papastamos 28ef69e1eaSDimitris Papastamos features = read_id_pfr0() >> ID_PFR0_AMU_SHIFT; 29*40daecc1SAntonio Nino Diaz return (features & ID_PFR0_AMU_MASK) == 1U; 30c70da546SJoel Hutton } 31c70da546SJoel Hutton 32*40daecc1SAntonio Nino Diaz void amu_enable(bool el2_unused) 33c70da546SJoel Hutton { 34*40daecc1SAntonio Nino Diaz if (!amu_supported()) 350767d50eSDimitris Papastamos return; 360767d50eSDimitris Papastamos 37ef69e1eaSDimitris Papastamos if (el2_unused) { 38ef69e1eaSDimitris Papastamos uint64_t v; 39ef69e1eaSDimitris Papastamos /* 40ef69e1eaSDimitris Papastamos * Non-secure access from EL0 or EL1 to the Activity Monitor 41ef69e1eaSDimitris Papastamos * registers do not trap to EL2. 42ef69e1eaSDimitris Papastamos */ 43ef69e1eaSDimitris Papastamos v = read_hcptr(); 44ef69e1eaSDimitris Papastamos v &= ~TAM_BIT; 45ef69e1eaSDimitris Papastamos write_hcptr(v); 46ef69e1eaSDimitris Papastamos } 47ef69e1eaSDimitris Papastamos 48ef69e1eaSDimitris Papastamos /* Enable group 0 counters */ 49ef69e1eaSDimitris Papastamos write_amcntenset0(AMU_GROUP0_COUNTERS_MASK); 50c70da546SJoel Hutton 51c70da546SJoel Hutton /* Enable group 1 counters */ 52c70da546SJoel Hutton write_amcntenset1(AMU_GROUP1_COUNTERS_MASK); 53c70da546SJoel Hutton } 54c70da546SJoel Hutton 55c70da546SJoel Hutton /* Read the group 0 counter identified by the given `idx`. */ 56c70da546SJoel Hutton uint64_t amu_group0_cnt_read(int idx) 57c70da546SJoel Hutton { 58*40daecc1SAntonio Nino Diaz assert(amu_supported()); 59*40daecc1SAntonio Nino Diaz assert((idx >= 0) && (idx < AMU_GROUP0_NR_COUNTERS)); 60c70da546SJoel Hutton 61c70da546SJoel Hutton return amu_group0_cnt_read_internal(idx); 62c70da546SJoel Hutton } 63c70da546SJoel Hutton 64c70da546SJoel Hutton /* Write the group 0 counter identified by the given `idx` with `val`. */ 65c70da546SJoel Hutton void amu_group0_cnt_write(int idx, uint64_t val) 66c70da546SJoel Hutton { 67*40daecc1SAntonio Nino Diaz assert(amu_supported()); 68*40daecc1SAntonio Nino Diaz assert((idx >= 0) && (idx < AMU_GROUP0_NR_COUNTERS)); 69c70da546SJoel Hutton 70c70da546SJoel Hutton amu_group0_cnt_write_internal(idx, val); 71c70da546SJoel Hutton isb(); 72c70da546SJoel Hutton } 73c70da546SJoel Hutton 74c70da546SJoel Hutton /* Read the group 1 counter identified by the given `idx`. */ 75c70da546SJoel Hutton uint64_t amu_group1_cnt_read(int idx) 76c70da546SJoel Hutton { 77*40daecc1SAntonio Nino Diaz assert(amu_supported()); 78*40daecc1SAntonio Nino Diaz assert((idx >= 0) && (idx < AMU_GROUP1_NR_COUNTERS)); 79c70da546SJoel Hutton 80c70da546SJoel Hutton return amu_group1_cnt_read_internal(idx); 81c70da546SJoel Hutton } 82c70da546SJoel Hutton 83c70da546SJoel Hutton /* Write the group 1 counter identified by the given `idx` with `val`. */ 84c70da546SJoel Hutton void amu_group1_cnt_write(int idx, uint64_t val) 85c70da546SJoel Hutton { 86*40daecc1SAntonio Nino Diaz assert(amu_supported()); 87*40daecc1SAntonio Nino Diaz assert((idx >= 0) && (idx < AMU_GROUP1_NR_COUNTERS)); 88c70da546SJoel Hutton 89c70da546SJoel Hutton amu_group1_cnt_write_internal(idx, val); 90c70da546SJoel Hutton isb(); 91c70da546SJoel Hutton } 92c70da546SJoel Hutton 93c70da546SJoel Hutton void amu_group1_set_evtype(int idx, unsigned int val) 94c70da546SJoel Hutton { 95*40daecc1SAntonio Nino Diaz assert(amu_supported()); 96*40daecc1SAntonio Nino Diaz assert((idx >= 0) && (idx < AMU_GROUP1_NR_COUNTERS)); 97c70da546SJoel Hutton 98c70da546SJoel Hutton amu_group1_set_evtype_internal(idx, val); 99c70da546SJoel Hutton isb(); 100ef69e1eaSDimitris Papastamos } 101b6eb3932SDimitris Papastamos 102b6eb3932SDimitris Papastamos static void *amu_context_save(const void *arg) 103b6eb3932SDimitris Papastamos { 104b6eb3932SDimitris Papastamos struct amu_ctx *ctx; 105c70da546SJoel Hutton int i; 106b6eb3932SDimitris Papastamos 107*40daecc1SAntonio Nino Diaz if (!amu_supported()) 108b6eb3932SDimitris Papastamos return (void *)-1; 109b6eb3932SDimitris Papastamos 110b6eb3932SDimitris Papastamos ctx = &amu_ctxs[plat_my_core_pos()]; 111b6eb3932SDimitris Papastamos 112b6eb3932SDimitris Papastamos /* Assert that group 0 counter configuration is what we expect */ 113e6e17ee8SDimitris Papastamos assert(read_amcntenset0() == AMU_GROUP0_COUNTERS_MASK && 114e6e17ee8SDimitris Papastamos read_amcntenset1() == AMU_GROUP1_COUNTERS_MASK); 115b6eb3932SDimitris Papastamos 116b6eb3932SDimitris Papastamos /* 117b6eb3932SDimitris Papastamos * Disable group 0 counters to avoid other observers like SCP sampling 118b6eb3932SDimitris Papastamos * counter values from the future via the memory mapped view. 119b6eb3932SDimitris Papastamos */ 120b6eb3932SDimitris Papastamos write_amcntenclr0(AMU_GROUP0_COUNTERS_MASK); 121c70da546SJoel Hutton write_amcntenclr1(AMU_GROUP1_COUNTERS_MASK); 122b6eb3932SDimitris Papastamos isb(); 123b6eb3932SDimitris Papastamos 124c70da546SJoel Hutton for (i = 0; i < AMU_GROUP0_NR_COUNTERS; i++) 125c70da546SJoel Hutton ctx->group0_cnts[i] = amu_group0_cnt_read(i); 126c70da546SJoel Hutton 127c70da546SJoel Hutton for (i = 0; i < AMU_GROUP1_NR_COUNTERS; i++) 128c70da546SJoel Hutton ctx->group1_cnts[i] = amu_group1_cnt_read(i); 129b6eb3932SDimitris Papastamos 130*40daecc1SAntonio Nino Diaz return (void *)0; 131b6eb3932SDimitris Papastamos } 132b6eb3932SDimitris Papastamos 133b6eb3932SDimitris Papastamos static void *amu_context_restore(const void *arg) 134b6eb3932SDimitris Papastamos { 135b6eb3932SDimitris Papastamos struct amu_ctx *ctx; 136c70da546SJoel Hutton int i; 137b6eb3932SDimitris Papastamos 138*40daecc1SAntonio Nino Diaz if (!amu_supported()) 139b6eb3932SDimitris Papastamos return (void *)-1; 140b6eb3932SDimitris Papastamos 141b6eb3932SDimitris Papastamos ctx = &amu_ctxs[plat_my_core_pos()]; 142b6eb3932SDimitris Papastamos 143b6eb3932SDimitris Papastamos /* Counters were disabled in `amu_context_save()` */ 144*40daecc1SAntonio Nino Diaz assert((read_amcntenset0() == 0U) && (read_amcntenset1() == 0U)); 145b6eb3932SDimitris Papastamos 146b6eb3932SDimitris Papastamos /* Restore group 0 counters */ 147c70da546SJoel Hutton for (i = 0; i < AMU_GROUP0_NR_COUNTERS; i++) 148c70da546SJoel Hutton amu_group0_cnt_write(i, ctx->group0_cnts[i]); 149c70da546SJoel Hutton for (i = 0; i < AMU_GROUP1_NR_COUNTERS; i++) 150c70da546SJoel Hutton amu_group1_cnt_write(i, ctx->group1_cnts[i]); 151b6eb3932SDimitris Papastamos 152b6eb3932SDimitris Papastamos /* Enable group 0 counters */ 153b6eb3932SDimitris Papastamos write_amcntenset0(AMU_GROUP0_COUNTERS_MASK); 154b6eb3932SDimitris Papastamos 155c70da546SJoel Hutton /* Enable group 1 counters */ 156c70da546SJoel Hutton write_amcntenset1(AMU_GROUP1_COUNTERS_MASK); 157*40daecc1SAntonio Nino Diaz return (void *)0; 158b6eb3932SDimitris Papastamos } 159b6eb3932SDimitris Papastamos 160b6eb3932SDimitris Papastamos SUBSCRIBE_TO_EVENT(psci_suspend_pwrdown_start, amu_context_save); 161b6eb3932SDimitris Papastamos SUBSCRIBE_TO_EVENT(psci_suspend_pwrdown_finish, amu_context_restore); 162