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