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