blob: 5f23c07df33948421eb933f1971e5d8c98fd03ae [file] [log] [blame]
Dimitris Papastamos380559c2017-10-12 13:02:29 +01001/*
Boyan Karatotev83ec7e42024-11-06 14:55:35 +00002 * Copyright (c) 2017-2025, Arm Limited and Contributors. All rights reserved.
Dimitris Papastamos380559c2017-10-12 13:02:29 +01003 *
4 * SPDX-License-Identifier: BSD-3-Clause
5 */
6
Antonio Nino Diaz09d40e02018-12-14 00:18:21 +00007#include <assert.h>
Chris Kay33b9be62021-05-26 11:58:23 +01008#include <cdefs.h>
Scott Branden4ce3e992020-08-25 13:49:32 -07009#include <inttypes.h>
Antonio Nino Diaz09d40e02018-12-14 00:18:21 +000010#include <stdbool.h>
Scott Branden4ce3e992020-08-25 13:49:32 -070011#include <stdint.h>
Antonio Nino Diaz09d40e02018-12-14 00:18:21 +000012
Dimitris Papastamos380559c2017-10-12 13:02:29 +010013#include <arch.h>
johpow01873d4242020-10-02 13:41:11 -050014#include <arch_features.h>
Dimitris Papastamos380559c2017-10-12 13:02:29 +010015#include <arch_helpers.h>
Chris Kay742ca232021-08-19 11:21:52 +010016#include <common/debug.h>
Antonio Nino Diaz09d40e02018-12-14 00:18:21 +000017#include <lib/el3_runtime/pubsub_events.h>
18#include <lib/extensions/amu.h>
Boyan Karatotev83ec7e42024-11-06 14:55:35 +000019#include <lib/utils_def.h>
20#include <platform_def.h>
Alexei Fedorovf3ccf032020-07-14 08:17:56 +010021
Boyan Karatotev83ec7e42024-11-06 14:55:35 +000022amu_regs_t amu_ctx[PLATFORM_CORE_COUNT];
Dimitris Papastamos380559c2017-10-12 13:02:29 +010023
Boyan Karatotev83ec7e42024-11-06 14:55:35 +000024static inline uint8_t read_amcgcr_el0_cg1nc(void)
Chris Kay33b9be62021-05-26 11:58:23 +010025{
26 return (read_amcgcr_el0() >> AMCGCR_EL0_CG1NC_SHIFT) &
27 AMCGCR_EL0_CG1NC_MASK;
28}
29
Boyan Karatotev4085a022023-03-27 17:02:43 +010030void amu_enable(cpu_context_t *ctx)
Dimitris Papastamos0767d502017-11-13 09:49:45 +000031{
Boyan Karatotev4085a022023-03-27 17:02:43 +010032 /* Initialize FEAT_AMUv1p1 features if present. */
33 if (is_feat_amuv1p1_supported()) {
Boyan Karatotev83ec7e42024-11-06 14:55:35 +000034 el3_state_t *state = get_el3state_ctx(ctx);
35 u_register_t reg;
36
Boyan Karatotev4085a022023-03-27 17:02:43 +010037 /*
38 * Set SCR_EL3.AMVOFFEN to one so that accesses to virtual
39 * offset registers at EL2 do not trap to EL3
40 */
Boyan Karatotev83ec7e42024-11-06 14:55:35 +000041 reg = read_ctx_reg(state, CTX_SCR_EL3);
42 reg |= SCR_AMVOFFEN_BIT;
43 write_ctx_reg(state, CTX_SCR_EL3, reg);
Boyan Karatotev4085a022023-03-27 17:02:43 +010044 }
45}
Alexei Fedorovf3ccf032020-07-14 08:17:56 +010046
Elizabeth Ho461c0a52023-07-18 14:10:25 +010047void amu_enable_per_world(per_world_context_t *per_world_ctx)
48{
49 /*
50 * Set CPTR_EL3.TAM to zero so that any accesses to the Activity Monitor
51 * registers do not trap to EL3.
52 */
53 uint64_t cptr_el3 = per_world_ctx->ctx_cptr_el3;
54
55 cptr_el3 &= ~TAM_BIT;
56 per_world_ctx->ctx_cptr_el3 = cptr_el3;
57}
58
Boyan Karatotev83ec7e42024-11-06 14:55:35 +000059void amu_init_el3(unsigned int core_pos)
Boyan Karatotev4085a022023-03-27 17:02:43 +010060{
Boyan Karatotev83ec7e42024-11-06 14:55:35 +000061 /* architecture is currently pinned to 4 */
62 assert((read_amcgcr_el0() & AMCGCR_EL0_CG0NC_MASK) == CTX_AMU_GRP0_ALL);
Chris Kaye747a592021-05-24 20:35:26 +010063
Boyan Karatotev4085a022023-03-27 17:02:43 +010064 /* Enable all architected counters by default */
Boyan Karatotev83ec7e42024-11-06 14:55:35 +000065 write_amcntenset0_el0(AMCNTENSET0_EL0_Pn_MASK);
66 if (is_feat_amu_aux_supported()) {
67 /* something went wrong if we're trying to write higher bits */
68 assert((get_amu_aux_enables(core_pos) & ~AMCNTENSET1_EL0_Pn_MASK) == 0);
69 write_amcntenset1_el0(get_amu_aux_enables(core_pos));
Boyan Karatotev4085a022023-03-27 17:02:43 +010070 }
Chris Kay742ca232021-08-19 11:21:52 +010071
Andre Przywarab57e16a2023-03-03 10:30:06 +000072 if (is_feat_amuv1p1_supported()) {
johpow01873d4242020-10-02 13:41:11 -050073#if AMU_RESTRICT_COUNTERS
Chris Kay68120782021-05-05 13:38:30 +010074 /*
75 * FEAT_AMUv1p1 adds a register field to restrict access to
76 * group 1 counters at all but the highest implemented EL. This
77 * is controlled with the `AMU_RESTRICT_COUNTERS` compile time
78 * flag, when set, system register reads at lower ELs return
79 * zero. Reads from the memory mapped view are unaffected.
80 */
81 VERBOSE("AMU group 1 counter access restricted.\n");
Boyan Karatotev83ec7e42024-11-06 14:55:35 +000082 write_amcr_el0(AMCR_CG1RZ_BIT);
johpow01873d4242020-10-02 13:41:11 -050083#else
Boyan Karatotev83ec7e42024-11-06 14:55:35 +000084 /* HDBG = 0 in both cases */
85 write_amcr_el0(0);
Chris Kay68120782021-05-05 13:38:30 +010086#endif
87 }
Dimitris Papastamos0767d502017-11-13 09:49:45 +000088}
89
Boyan Karatotev4085a022023-03-27 17:02:43 +010090void amu_init_el2_unused(void)
91{
92 /*
93 * CPTR_EL2.TAM: Set to zero so any accesses to the Activity Monitor
94 * registers do not trap to EL2.
95 */
Boyan Karatotev83ec7e42024-11-06 14:55:35 +000096 write_cptr_el2(read_cptr_el2() & ~CPTR_EL2_TAM_BIT);
Boyan Karatotev4085a022023-03-27 17:02:43 +010097
Boyan Karatotev4085a022023-03-27 17:02:43 +010098 if (is_feat_amuv1p1_supported()) {
Boyan Karatotev83ec7e42024-11-06 14:55:35 +000099 /* Make sure virtual offsets are disabled */
100 write_hcr_el2(read_hcr_el2() & ~HCR_AMVOFFEN_BIT);
Boyan Karatotev4085a022023-03-27 17:02:43 +0100101 }
102}
103
Dimitris Papastamosb6eb3932017-11-28 13:47:06 +0000104static void *amu_context_save(const void *arg)
105{
Andre Przywarab57e16a2023-03-03 10:30:06 +0000106 if (!is_feat_amu_supported()) {
Chris Kaye747a592021-05-24 20:35:26 +0100107 return (void *)0;
108 }
109
Boyan Karatotev83ec7e42024-11-06 14:55:35 +0000110 unsigned int core_pos = *(unsigned int *)arg;
111 amu_regs_t *ctx = &amu_ctx[core_pos];
Chris Kaye747a592021-05-24 20:35:26 +0100112
Boyan Karatotev83ec7e42024-11-06 14:55:35 +0000113 /* disable all counters so we can write them safely later */
114 write_amcntenclr0_el0(AMCNTENCLR0_EL0_Pn_MASK);
115 if (is_feat_amu_aux_supported()) {
116 write_amcntenclr1_el0(get_amu_aux_enables(core_pos));
Andre Przywarab57e16a2023-03-03 10:30:06 +0000117 }
Chris Kaye747a592021-05-24 20:35:26 +0100118
Boyan Karatotev83ec7e42024-11-06 14:55:35 +0000119 isb();
Chris Kaye747a592021-05-24 20:35:26 +0100120
Boyan Karatotev83ec7e42024-11-06 14:55:35 +0000121 write_amu_grp0_ctx_reg(ctx, 0, read_amevcntr00_el0());
122 write_amu_grp0_ctx_reg(ctx, 1, read_amevcntr01_el0());
123 write_amu_grp0_ctx_reg(ctx, 2, read_amevcntr02_el0());
124 write_amu_grp0_ctx_reg(ctx, 3, read_amevcntr03_el0());
Chris Kaye747a592021-05-24 20:35:26 +0100125
Boyan Karatotev83ec7e42024-11-06 14:55:35 +0000126 if (is_feat_amu_aux_supported()) {
127 uint8_t num_counters = read_amcgcr_el0_cg1nc();
Chris Kaye747a592021-05-24 20:35:26 +0100128
Boyan Karatotev83ec7e42024-11-06 14:55:35 +0000129 switch (num_counters) {
130 case 0x10:
131 write_amu_grp1_ctx_reg(ctx, 0xf, read_amevcntr1f_el0());
132 __fallthrough;
133 case 0x0f:
134 write_amu_grp1_ctx_reg(ctx, 0xe, read_amevcntr1e_el0());
135 __fallthrough;
136 case 0x0e:
137 write_amu_grp1_ctx_reg(ctx, 0xd, read_amevcntr1d_el0());
138 __fallthrough;
139 case 0x0d:
140 write_amu_grp1_ctx_reg(ctx, 0xc, read_amevcntr1c_el0());
141 __fallthrough;
142 case 0x0c:
143 write_amu_grp1_ctx_reg(ctx, 0xb, read_amevcntr1b_el0());
144 __fallthrough;
145 case 0x0b:
146 write_amu_grp1_ctx_reg(ctx, 0xa, read_amevcntr1a_el0());
147 __fallthrough;
148 case 0x0a:
149 write_amu_grp1_ctx_reg(ctx, 0x9, read_amevcntr19_el0());
150 __fallthrough;
151 case 0x09:
152 write_amu_grp1_ctx_reg(ctx, 0x8, read_amevcntr18_el0());
153 __fallthrough;
154 case 0x08:
155 write_amu_grp1_ctx_reg(ctx, 0x7, read_amevcntr17_el0());
156 __fallthrough;
157 case 0x07:
158 write_amu_grp1_ctx_reg(ctx, 0x6, read_amevcntr16_el0());
159 __fallthrough;
160 case 0x06:
161 write_amu_grp1_ctx_reg(ctx, 0x5, read_amevcntr15_el0());
162 __fallthrough;
163 case 0x05:
164 write_amu_grp1_ctx_reg(ctx, 0x4, read_amevcntr14_el0());
165 __fallthrough;
166 case 0x04:
167 write_amu_grp1_ctx_reg(ctx, 0x3, read_amevcntr13_el0());
168 __fallthrough;
169 case 0x03:
170 write_amu_grp1_ctx_reg(ctx, 0x2, read_amevcntr12_el0());
171 __fallthrough;
172 case 0x02:
173 write_amu_grp1_ctx_reg(ctx, 0x1, read_amevcntr11_el0());
174 __fallthrough;
175 case 0x01:
176 write_amu_grp1_ctx_reg(ctx, 0x0, read_amevcntr10_el0());
177 __fallthrough;
178 case 0x00:
179 break;
180 default:
181 assert(0); /* something is wrong */
Chris Kaye747a592021-05-24 20:35:26 +0100182 }
Chris Kaye747a592021-05-24 20:35:26 +0100183 }
184
Antonio Nino Diaz40daecc2018-10-25 16:52:26 +0100185 return (void *)0;
Dimitris Papastamosb6eb3932017-11-28 13:47:06 +0000186}
187
188static void *amu_context_restore(const void *arg)
189{
Andre Przywarab57e16a2023-03-03 10:30:06 +0000190 if (!is_feat_amu_supported()) {
Chris Kaye747a592021-05-24 20:35:26 +0100191 return (void *)0;
192 }
193
Boyan Karatotev83ec7e42024-11-06 14:55:35 +0000194 unsigned int core_pos = *(unsigned int *)arg;
195 amu_regs_t *ctx = &amu_ctx[core_pos];
Chris Kaye747a592021-05-24 20:35:26 +0100196
Boyan Karatotev83ec7e42024-11-06 14:55:35 +0000197 write_amevcntr00_el0(read_amu_grp0_ctx_reg(ctx, 0));
198 write_amevcntr01_el0(read_amu_grp0_ctx_reg(ctx, 1));
199 write_amevcntr02_el0(read_amu_grp0_ctx_reg(ctx, 2));
200 write_amevcntr03_el0(read_amu_grp0_ctx_reg(ctx, 3));
Chris Kaye747a592021-05-24 20:35:26 +0100201
Boyan Karatotev83ec7e42024-11-06 14:55:35 +0000202 if (is_feat_amu_aux_supported()) {
203 uint8_t num_counters = read_amcgcr_el0_cg1nc();
Chris Kaye747a592021-05-24 20:35:26 +0100204
Boyan Karatotev83ec7e42024-11-06 14:55:35 +0000205 switch (num_counters) {
206 case 0x10:
207 write_amevcntr1f_el0(read_amu_grp1_ctx_reg(ctx, 0xf));
208 __fallthrough;
209 case 0x0f:
210 write_amevcntr1e_el0(read_amu_grp1_ctx_reg(ctx, 0xe));
211 __fallthrough;
212 case 0x0e:
213 write_amevcntr1d_el0(read_amu_grp1_ctx_reg(ctx, 0xd));
214 __fallthrough;
215 case 0x0d:
216 write_amevcntr1c_el0(read_amu_grp1_ctx_reg(ctx, 0xc));
217 __fallthrough;
218 case 0x0c:
219 write_amevcntr1b_el0(read_amu_grp1_ctx_reg(ctx, 0xb));
220 __fallthrough;
221 case 0x0b:
222 write_amevcntr1a_el0(read_amu_grp1_ctx_reg(ctx, 0xa));
223 __fallthrough;
224 case 0x0a:
225 write_amevcntr19_el0(read_amu_grp1_ctx_reg(ctx, 0x9));
226 __fallthrough;
227 case 0x09:
228 write_amevcntr18_el0(read_amu_grp1_ctx_reg(ctx, 0x8));
229 __fallthrough;
230 case 0x08:
231 write_amevcntr17_el0(read_amu_grp1_ctx_reg(ctx, 0x7));
232 __fallthrough;
233 case 0x07:
234 write_amevcntr16_el0(read_amu_grp1_ctx_reg(ctx, 0x6));
235 __fallthrough;
236 case 0x06:
237 write_amevcntr15_el0(read_amu_grp1_ctx_reg(ctx, 0x5));
238 __fallthrough;
239 case 0x05:
240 write_amevcntr14_el0(read_amu_grp1_ctx_reg(ctx, 0x4));
241 __fallthrough;
242 case 0x04:
243 write_amevcntr13_el0(read_amu_grp1_ctx_reg(ctx, 0x3));
244 __fallthrough;
245 case 0x03:
246 write_amevcntr12_el0(read_amu_grp1_ctx_reg(ctx, 0x2));
247 __fallthrough;
248 case 0x02:
249 write_amevcntr11_el0(read_amu_grp1_ctx_reg(ctx, 0x1));
250 __fallthrough;
251 case 0x01:
252 write_amevcntr10_el0(read_amu_grp1_ctx_reg(ctx, 0x0));
253 __fallthrough;
254 case 0x00:
255 break;
256 default:
257 assert(0); /* something is wrong */
Chris Kaye747a592021-05-24 20:35:26 +0100258 }
Chris Kaye747a592021-05-24 20:35:26 +0100259 }
johpow01873d4242020-10-02 13:41:11 -0500260
Chris Kay1fd685a2021-05-25 10:42:56 +0100261
Boyan Karatotev83ec7e42024-11-06 14:55:35 +0000262 /* now enable them again */
263 write_amcntenset0_el0(AMCNTENSET0_EL0_Pn_MASK);
264 if (is_feat_amu_aux_supported()) {
265 write_amcntenset1_el0(get_amu_aux_enables(core_pos));
Chris Kay1fd685a2021-05-25 10:42:56 +0100266 }
Dimitris Papastamosb6eb3932017-11-28 13:47:06 +0000267
Boyan Karatotev83ec7e42024-11-06 14:55:35 +0000268 isb();
Antonio Nino Diaz40daecc2018-10-25 16:52:26 +0100269 return (void *)0;
Dimitris Papastamosb6eb3932017-11-28 13:47:06 +0000270}
271
272SUBSCRIBE_TO_EVENT(psci_suspend_pwrdown_start, amu_context_save);
273SUBSCRIBE_TO_EVENT(psci_suspend_pwrdown_finish, amu_context_restore);