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