1ef69e1eaSDimitris Papastamos /* 2ef69e1eaSDimitris Papastamos * Copyright (c) 2017, 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> 8ef69e1eaSDimitris Papastamos #include <arch.h> 9ef69e1eaSDimitris Papastamos #include <arch_helpers.h> 100767d50eSDimitris Papastamos #include <debug.h> 11*b6eb3932SDimitris Papastamos #include <platform.h> 12*b6eb3932SDimitris Papastamos #include <pubsub_events.h> 13*b6eb3932SDimitris Papastamos 14*b6eb3932SDimitris Papastamos #define AMU_GROUP0_NR_COUNTERS 4 15*b6eb3932SDimitris Papastamos 16*b6eb3932SDimitris Papastamos struct amu_ctx { 17*b6eb3932SDimitris Papastamos uint64_t group0_cnts[AMU_GROUP0_NR_COUNTERS]; 18*b6eb3932SDimitris Papastamos }; 19*b6eb3932SDimitris Papastamos 20*b6eb3932SDimitris Papastamos static struct amu_ctx amu_ctxs[PLATFORM_CORE_COUNT]; 21ef69e1eaSDimitris Papastamos 22ef69e1eaSDimitris Papastamos void amu_enable(int el2_unused) 23ef69e1eaSDimitris Papastamos { 24ef69e1eaSDimitris Papastamos uint64_t features; 25ef69e1eaSDimitris Papastamos 26ef69e1eaSDimitris Papastamos features = read_id_pfr0() >> ID_PFR0_AMU_SHIFT; 270767d50eSDimitris Papastamos if ((features & ID_PFR0_AMU_MASK) != 1) { 280767d50eSDimitris Papastamos WARN("Cannot enable AMU - not supported\n"); 290767d50eSDimitris Papastamos return; 300767d50eSDimitris Papastamos } 310767d50eSDimitris Papastamos 32ef69e1eaSDimitris Papastamos if (el2_unused) { 33ef69e1eaSDimitris Papastamos uint64_t v; 34ef69e1eaSDimitris Papastamos 35ef69e1eaSDimitris Papastamos /* 36ef69e1eaSDimitris Papastamos * Non-secure access from EL0 or EL1 to the Activity Monitor 37ef69e1eaSDimitris Papastamos * registers do not trap to EL2. 38ef69e1eaSDimitris Papastamos */ 39ef69e1eaSDimitris Papastamos v = read_hcptr(); 40ef69e1eaSDimitris Papastamos v &= ~TAM_BIT; 41ef69e1eaSDimitris Papastamos write_hcptr(v); 42ef69e1eaSDimitris Papastamos } 43ef69e1eaSDimitris Papastamos 44ef69e1eaSDimitris Papastamos /* Enable group 0 counters */ 45ef69e1eaSDimitris Papastamos write_amcntenset0(AMU_GROUP0_COUNTERS_MASK); 46ef69e1eaSDimitris Papastamos } 47*b6eb3932SDimitris Papastamos 48*b6eb3932SDimitris Papastamos static void *amu_context_save(const void *arg) 49*b6eb3932SDimitris Papastamos { 50*b6eb3932SDimitris Papastamos struct amu_ctx *ctx; 51*b6eb3932SDimitris Papastamos uint64_t features; 52*b6eb3932SDimitris Papastamos 53*b6eb3932SDimitris Papastamos features = read_id_pfr0() >> ID_PFR0_AMU_SHIFT; 54*b6eb3932SDimitris Papastamos if ((features & ID_PFR0_AMU_MASK) != 1) 55*b6eb3932SDimitris Papastamos return (void *)-1; 56*b6eb3932SDimitris Papastamos 57*b6eb3932SDimitris Papastamos ctx = &amu_ctxs[plat_my_core_pos()]; 58*b6eb3932SDimitris Papastamos 59*b6eb3932SDimitris Papastamos /* Assert that group 0 counter configuration is what we expect */ 60*b6eb3932SDimitris Papastamos assert(read_amcntenset0() == AMU_GROUP0_COUNTERS_MASK); 61*b6eb3932SDimitris Papastamos 62*b6eb3932SDimitris Papastamos /* 63*b6eb3932SDimitris Papastamos * Disable group 0 counters to avoid other observers like SCP sampling 64*b6eb3932SDimitris Papastamos * counter values from the future via the memory mapped view. 65*b6eb3932SDimitris Papastamos */ 66*b6eb3932SDimitris Papastamos write_amcntenclr0(AMU_GROUP0_COUNTERS_MASK); 67*b6eb3932SDimitris Papastamos isb(); 68*b6eb3932SDimitris Papastamos 69*b6eb3932SDimitris Papastamos ctx->group0_cnts[0] = read64_amevcntr00(); 70*b6eb3932SDimitris Papastamos ctx->group0_cnts[1] = read64_amevcntr01(); 71*b6eb3932SDimitris Papastamos ctx->group0_cnts[2] = read64_amevcntr02(); 72*b6eb3932SDimitris Papastamos ctx->group0_cnts[3] = read64_amevcntr03(); 73*b6eb3932SDimitris Papastamos 74*b6eb3932SDimitris Papastamos return 0; 75*b6eb3932SDimitris Papastamos } 76*b6eb3932SDimitris Papastamos 77*b6eb3932SDimitris Papastamos static void *amu_context_restore(const void *arg) 78*b6eb3932SDimitris Papastamos { 79*b6eb3932SDimitris Papastamos struct amu_ctx *ctx; 80*b6eb3932SDimitris Papastamos uint64_t features; 81*b6eb3932SDimitris Papastamos 82*b6eb3932SDimitris Papastamos features = read_id_pfr0() >> ID_PFR0_AMU_SHIFT; 83*b6eb3932SDimitris Papastamos if ((features & ID_PFR0_AMU_MASK) != 1) 84*b6eb3932SDimitris Papastamos return (void *)-1; 85*b6eb3932SDimitris Papastamos 86*b6eb3932SDimitris Papastamos ctx = &amu_ctxs[plat_my_core_pos()]; 87*b6eb3932SDimitris Papastamos 88*b6eb3932SDimitris Papastamos /* Counters were disabled in `amu_context_save()` */ 89*b6eb3932SDimitris Papastamos assert(read_amcntenset0() == 0); 90*b6eb3932SDimitris Papastamos 91*b6eb3932SDimitris Papastamos /* Restore group 0 counters */ 92*b6eb3932SDimitris Papastamos if (AMU_GROUP0_COUNTERS_MASK & (1U << 0)) 93*b6eb3932SDimitris Papastamos write64_amevcntr00(ctx->group0_cnts[0]); 94*b6eb3932SDimitris Papastamos if (AMU_GROUP0_COUNTERS_MASK & (1U << 1)) 95*b6eb3932SDimitris Papastamos write64_amevcntr01(ctx->group0_cnts[1]); 96*b6eb3932SDimitris Papastamos if (AMU_GROUP0_COUNTERS_MASK & (1U << 2)) 97*b6eb3932SDimitris Papastamos write64_amevcntr02(ctx->group0_cnts[2]); 98*b6eb3932SDimitris Papastamos if (AMU_GROUP0_COUNTERS_MASK & (1U << 3)) 99*b6eb3932SDimitris Papastamos write64_amevcntr03(ctx->group0_cnts[3]); 100*b6eb3932SDimitris Papastamos isb(); 101*b6eb3932SDimitris Papastamos 102*b6eb3932SDimitris Papastamos /* Enable group 0 counters */ 103*b6eb3932SDimitris Papastamos write_amcntenset0(AMU_GROUP0_COUNTERS_MASK); 104*b6eb3932SDimitris Papastamos 105*b6eb3932SDimitris Papastamos return 0; 106*b6eb3932SDimitris Papastamos } 107*b6eb3932SDimitris Papastamos 108*b6eb3932SDimitris Papastamos SUBSCRIBE_TO_EVENT(psci_suspend_pwrdown_start, amu_context_save); 109*b6eb3932SDimitris Papastamos SUBSCRIBE_TO_EVENT(psci_suspend_pwrdown_finish, amu_context_restore); 110