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> 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]; 18c70da546SJoel 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 23c70da546SJoel Hutton int amu_supported(void) 24ef69e1eaSDimitris Papastamos { 25ef69e1eaSDimitris Papastamos uint64_t features; 26ef69e1eaSDimitris Papastamos 27ef69e1eaSDimitris Papastamos features = read_id_pfr0() >> ID_PFR0_AMU_SHIFT; 28c70da546SJoel Hutton return (features & ID_PFR0_AMU_MASK) == 1; 29c70da546SJoel Hutton } 30c70da546SJoel Hutton 31c70da546SJoel Hutton void amu_enable(int el2_unused) 32c70da546SJoel Hutton { 33c70da546SJoel 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); 49c70da546SJoel Hutton 50c70da546SJoel Hutton /* Enable group 1 counters */ 51c70da546SJoel Hutton write_amcntenset1(AMU_GROUP1_COUNTERS_MASK); 52c70da546SJoel Hutton } 53c70da546SJoel Hutton 54c70da546SJoel Hutton /* Read the group 0 counter identified by the given `idx`. */ 55c70da546SJoel Hutton uint64_t amu_group0_cnt_read(int idx) 56c70da546SJoel Hutton { 57c70da546SJoel Hutton assert(amu_supported()); 58c70da546SJoel Hutton assert(idx >= 0 && idx < AMU_GROUP0_NR_COUNTERS); 59c70da546SJoel Hutton 60c70da546SJoel Hutton return amu_group0_cnt_read_internal(idx); 61c70da546SJoel Hutton } 62c70da546SJoel Hutton 63c70da546SJoel Hutton /* Write the group 0 counter identified by the given `idx` with `val`. */ 64c70da546SJoel Hutton void amu_group0_cnt_write(int idx, uint64_t val) 65c70da546SJoel Hutton { 66c70da546SJoel Hutton assert(amu_supported()); 67c70da546SJoel Hutton assert(idx >= 0 && idx < AMU_GROUP0_NR_COUNTERS); 68c70da546SJoel Hutton 69c70da546SJoel Hutton amu_group0_cnt_write_internal(idx, val); 70c70da546SJoel Hutton isb(); 71c70da546SJoel Hutton } 72c70da546SJoel Hutton 73c70da546SJoel Hutton /* Read the group 1 counter identified by the given `idx`. */ 74c70da546SJoel Hutton uint64_t amu_group1_cnt_read(int idx) 75c70da546SJoel Hutton { 76c70da546SJoel Hutton assert(amu_supported()); 77c70da546SJoel Hutton assert(idx >= 0 && idx < AMU_GROUP1_NR_COUNTERS); 78c70da546SJoel Hutton 79c70da546SJoel Hutton return amu_group1_cnt_read_internal(idx); 80c70da546SJoel Hutton } 81c70da546SJoel Hutton 82c70da546SJoel Hutton /* Write the group 1 counter identified by the given `idx` with `val`. */ 83c70da546SJoel Hutton void amu_group1_cnt_write(int idx, uint64_t val) 84c70da546SJoel Hutton { 85c70da546SJoel Hutton assert(amu_supported()); 86c70da546SJoel Hutton assert(idx >= 0 && idx < AMU_GROUP1_NR_COUNTERS); 87c70da546SJoel Hutton 88c70da546SJoel Hutton amu_group1_cnt_write_internal(idx, val); 89c70da546SJoel Hutton isb(); 90c70da546SJoel Hutton } 91c70da546SJoel Hutton 92c70da546SJoel Hutton void amu_group1_set_evtype(int idx, unsigned int val) 93c70da546SJoel Hutton { 94c70da546SJoel Hutton assert(amu_supported()); 95c70da546SJoel Hutton assert(idx >= 0 && idx < AMU_GROUP1_NR_COUNTERS); 96c70da546SJoel Hutton 97c70da546SJoel Hutton amu_group1_set_evtype_internal(idx, val); 98c70da546SJoel Hutton isb(); 99ef69e1eaSDimitris Papastamos } 100b6eb3932SDimitris Papastamos 101b6eb3932SDimitris Papastamos static void *amu_context_save(const void *arg) 102b6eb3932SDimitris Papastamos { 103b6eb3932SDimitris Papastamos struct amu_ctx *ctx; 104c70da546SJoel Hutton int i; 105b6eb3932SDimitris Papastamos 106c70da546SJoel 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 */ 112*e6e17ee8SDimitris Papastamos assert(read_amcntenset0() == AMU_GROUP0_COUNTERS_MASK && 113*e6e17ee8SDimitris Papastamos read_amcntenset1() == AMU_GROUP1_COUNTERS_MASK); 114b6eb3932SDimitris Papastamos 115b6eb3932SDimitris Papastamos /* 116b6eb3932SDimitris Papastamos * Disable group 0 counters to avoid other observers like SCP sampling 117b6eb3932SDimitris Papastamos * counter values from the future via the memory mapped view. 118b6eb3932SDimitris Papastamos */ 119b6eb3932SDimitris Papastamos write_amcntenclr0(AMU_GROUP0_COUNTERS_MASK); 120c70da546SJoel Hutton write_amcntenclr1(AMU_GROUP1_COUNTERS_MASK); 121b6eb3932SDimitris Papastamos isb(); 122b6eb3932SDimitris Papastamos 123c70da546SJoel Hutton for (i = 0; i < AMU_GROUP0_NR_COUNTERS; i++) 124c70da546SJoel Hutton ctx->group0_cnts[i] = amu_group0_cnt_read(i); 125c70da546SJoel Hutton 126c70da546SJoel Hutton for (i = 0; i < AMU_GROUP1_NR_COUNTERS; i++) 127c70da546SJoel Hutton ctx->group1_cnts[i] = amu_group1_cnt_read(i); 128b6eb3932SDimitris Papastamos 129b6eb3932SDimitris Papastamos return 0; 130b6eb3932SDimitris Papastamos } 131b6eb3932SDimitris Papastamos 132b6eb3932SDimitris Papastamos static void *amu_context_restore(const void *arg) 133b6eb3932SDimitris Papastamos { 134b6eb3932SDimitris Papastamos struct amu_ctx *ctx; 135b6eb3932SDimitris Papastamos uint64_t features; 136c70da546SJoel Hutton int i; 137b6eb3932SDimitris Papastamos 138b6eb3932SDimitris Papastamos features = read_id_pfr0() >> ID_PFR0_AMU_SHIFT; 139b6eb3932SDimitris Papastamos if ((features & ID_PFR0_AMU_MASK) != 1) 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()` */ 145*e6e17ee8SDimitris Papastamos assert(read_amcntenset0() == 0 && read_amcntenset1() == 0); 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); 158b6eb3932SDimitris Papastamos return 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