blob: 05c98f1cdad0624cf2dd33f3eb3d090cfaa7d1ff [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>
Joel Hutton0dcdd8d2017-12-21 15:21:20 +00008#include <amu_private.h>
Dimitris Papastamosdda48b02017-10-17 14:03:14 +01009#include <arch.h>
10#include <arch_helpers.h>
Dimitris Papastamoseaf3e6d2017-11-28 13:47:06 +000011#include <platform.h>
12#include <pubsub_events.h>
13
14#define AMU_GROUP0_NR_COUNTERS 4
15
16struct amu_ctx {
17 uint64_t group0_cnts[AMU_GROUP0_NR_COUNTERS];
Joel Hutton0dcdd8d2017-12-21 15:21:20 +000018 uint64_t group1_cnts[AMU_GROUP1_NR_COUNTERS];
Dimitris Papastamoseaf3e6d2017-11-28 13:47:06 +000019};
20
21static struct amu_ctx amu_ctxs[PLATFORM_CORE_COUNT];
Dimitris Papastamosdda48b02017-10-17 14:03:14 +010022
Joel Hutton0dcdd8d2017-12-21 15:21:20 +000023int amu_supported(void)
Dimitris Papastamosdda48b02017-10-17 14:03:14 +010024{
25 uint64_t features;
26
27 features = read_id_pfr0() >> ID_PFR0_AMU_SHIFT;
Joel Hutton0dcdd8d2017-12-21 15:21:20 +000028 return (features & ID_PFR0_AMU_MASK) == 1;
29}
30
31void amu_enable(int el2_unused)
32{
Dimitris Papastamosaaa19852018-02-26 17:56:31 +000033 if (amu_supported() == 0)
Dimitris Papastamos525c37a2017-11-13 09:49:45 +000034 return;
Dimitris Papastamosdda48b02017-10-17 14:03:14 +010035
Dimitris Papastamos525c37a2017-11-13 09:49:45 +000036 if (el2_unused) {
37 uint64_t v;
Dimitris Papastamos525c37a2017-11-13 09:49:45 +000038 /*
39 * Non-secure access from EL0 or EL1 to the Activity Monitor
40 * registers do not trap to EL2.
41 */
42 v = read_hcptr();
43 v &= ~TAM_BIT;
44 write_hcptr(v);
Dimitris Papastamosdda48b02017-10-17 14:03:14 +010045 }
Dimitris Papastamos525c37a2017-11-13 09:49:45 +000046
47 /* Enable group 0 counters */
48 write_amcntenset0(AMU_GROUP0_COUNTERS_MASK);
Joel Hutton0dcdd8d2017-12-21 15:21:20 +000049
50 /* Enable group 1 counters */
51 write_amcntenset1(AMU_GROUP1_COUNTERS_MASK);
52}
53
54/* Read the group 0 counter identified by the given `idx`. */
55uint64_t amu_group0_cnt_read(int idx)
56{
Dimitris Papastamosaaa19852018-02-26 17:56:31 +000057 assert(amu_supported() != 0);
Joel Hutton0dcdd8d2017-12-21 15:21:20 +000058 assert(idx >= 0 && idx < AMU_GROUP0_NR_COUNTERS);
59
60 return amu_group0_cnt_read_internal(idx);
61}
62
63/* Write the group 0 counter identified by the given `idx` with `val`. */
64void amu_group0_cnt_write(int idx, uint64_t val)
65{
Dimitris Papastamosaaa19852018-02-26 17:56:31 +000066 assert(amu_supported() != 0);
Joel Hutton0dcdd8d2017-12-21 15:21:20 +000067 assert(idx >= 0 && idx < AMU_GROUP0_NR_COUNTERS);
68
69 amu_group0_cnt_write_internal(idx, val);
70 isb();
71}
72
73/* Read the group 1 counter identified by the given `idx`. */
74uint64_t amu_group1_cnt_read(int idx)
75{
Dimitris Papastamosaaa19852018-02-26 17:56:31 +000076 assert(amu_supported() != 0);
Joel Hutton0dcdd8d2017-12-21 15:21:20 +000077 assert(idx >= 0 && idx < AMU_GROUP1_NR_COUNTERS);
78
79 return amu_group1_cnt_read_internal(idx);
80}
81
82/* Write the group 1 counter identified by the given `idx` with `val`. */
83void amu_group1_cnt_write(int idx, uint64_t val)
84{
Dimitris Papastamosaaa19852018-02-26 17:56:31 +000085 assert(amu_supported() != 0);
Joel Hutton0dcdd8d2017-12-21 15:21:20 +000086 assert(idx >= 0 && idx < AMU_GROUP1_NR_COUNTERS);
87
88 amu_group1_cnt_write_internal(idx, val);
89 isb();
90}
91
92void amu_group1_set_evtype(int idx, unsigned int val)
93{
Dimitris Papastamosaaa19852018-02-26 17:56:31 +000094 assert(amu_supported() != 0);
Joel Hutton0dcdd8d2017-12-21 15:21:20 +000095 assert(idx >= 0 && idx < AMU_GROUP1_NR_COUNTERS);
96
97 amu_group1_set_evtype_internal(idx, val);
98 isb();
Dimitris Papastamoseaf3e6d2017-11-28 13:47:06 +000099}
100
101static void *amu_context_save(const void *arg)
102{
103 struct amu_ctx *ctx;
Joel Hutton0dcdd8d2017-12-21 15:21:20 +0000104 int i;
Dimitris Papastamoseaf3e6d2017-11-28 13:47:06 +0000105
Dimitris Papastamosaaa19852018-02-26 17:56:31 +0000106 if (amu_supported() == 0)
Dimitris Papastamoseaf3e6d2017-11-28 13:47:06 +0000107 return (void *)-1;
108
109 ctx = &amu_ctxs[plat_my_core_pos()];
110
111 /* Assert that group 0 counter configuration is what we expect */
Dimitris Papastamos430f1152018-02-20 11:16:44 +0000112 assert(read_amcntenset0() == AMU_GROUP0_COUNTERS_MASK &&
113 read_amcntenset1() == AMU_GROUP1_COUNTERS_MASK);
Dimitris Papastamoseaf3e6d2017-11-28 13:47:06 +0000114
115 /*
116 * Disable group 0 counters to avoid other observers like SCP sampling
117 * counter values from the future via the memory mapped view.
118 */
119 write_amcntenclr0(AMU_GROUP0_COUNTERS_MASK);
Joel Hutton0dcdd8d2017-12-21 15:21:20 +0000120 write_amcntenclr1(AMU_GROUP1_COUNTERS_MASK);
Dimitris Papastamoseaf3e6d2017-11-28 13:47:06 +0000121 isb();
122
Joel Hutton0dcdd8d2017-12-21 15:21:20 +0000123 for (i = 0; i < AMU_GROUP0_NR_COUNTERS; i++)
124 ctx->group0_cnts[i] = amu_group0_cnt_read(i);
125
126 for (i = 0; i < AMU_GROUP1_NR_COUNTERS; i++)
127 ctx->group1_cnts[i] = amu_group1_cnt_read(i);
Dimitris Papastamoseaf3e6d2017-11-28 13:47:06 +0000128
129 return 0;
130}
131
132static void *amu_context_restore(const void *arg)
133{
134 struct amu_ctx *ctx;
Joel Hutton0dcdd8d2017-12-21 15:21:20 +0000135 int i;
Dimitris Papastamoseaf3e6d2017-11-28 13:47:06 +0000136
Dimitris Papastamosaaa19852018-02-26 17:56:31 +0000137 if (amu_supported() == 0)
Dimitris Papastamoseaf3e6d2017-11-28 13:47:06 +0000138 return (void *)-1;
139
140 ctx = &amu_ctxs[plat_my_core_pos()];
141
142 /* Counters were disabled in `amu_context_save()` */
Dimitris Papastamos430f1152018-02-20 11:16:44 +0000143 assert(read_amcntenset0() == 0 && read_amcntenset1() == 0);
Dimitris Papastamoseaf3e6d2017-11-28 13:47:06 +0000144
145 /* Restore group 0 counters */
Joel Hutton0dcdd8d2017-12-21 15:21:20 +0000146 for (i = 0; i < AMU_GROUP0_NR_COUNTERS; i++)
147 amu_group0_cnt_write(i, ctx->group0_cnts[i]);
148 for (i = 0; i < AMU_GROUP1_NR_COUNTERS; i++)
149 amu_group1_cnt_write(i, ctx->group1_cnts[i]);
Dimitris Papastamoseaf3e6d2017-11-28 13:47:06 +0000150
151 /* Enable group 0 counters */
152 write_amcntenset0(AMU_GROUP0_COUNTERS_MASK);
153
Joel Hutton0dcdd8d2017-12-21 15:21:20 +0000154 /* Enable group 1 counters */
155 write_amcntenset1(AMU_GROUP1_COUNTERS_MASK);
Dimitris Papastamoseaf3e6d2017-11-28 13:47:06 +0000156 return 0;
Dimitris Papastamosdda48b02017-10-17 14:03:14 +0100157}
Dimitris Papastamoseaf3e6d2017-11-28 13:47:06 +0000158
159SUBSCRIBE_TO_EVENT(psci_suspend_pwrdown_start, amu_context_save);
160SUBSCRIBE_TO_EVENT(psci_suspend_pwrdown_finish, amu_context_restore);