xref: /rk3399_ARM-atf/lib/extensions/amu/aarch32/amu.c (revision 9a207532f8216bf83fed0891fed9ed0bc72ca450)
1 /*
2  * Copyright (c) 2017-2018, ARM Limited and Contributors. All rights reserved.
3  *
4  * SPDX-License-Identifier: BSD-3-Clause
5  */
6 
7 #include <stdbool.h>
8 
9 #include <arch.h>
10 #include <arch_helpers.h>
11 #include <lib/el3_runtime/pubsub_events.h>
12 #include <lib/extensions/amu.h>
13 #include <lib/extensions/amu_private.h>
14 #include <plat/common/platform.h>
15 
16 #define AMU_GROUP0_NR_COUNTERS	4
17 
18 struct amu_ctx {
19 	uint64_t group0_cnts[AMU_GROUP0_NR_COUNTERS];
20 	uint64_t group1_cnts[AMU_GROUP1_NR_COUNTERS];
21 };
22 
23 static struct amu_ctx amu_ctxs[PLATFORM_CORE_COUNT];
24 
25 bool amu_supported(void)
26 {
27 	uint64_t features;
28 
29 	features = read_id_pfr0() >> ID_PFR0_AMU_SHIFT;
30 	return (features & ID_PFR0_AMU_MASK) == 1U;
31 }
32 
33 void amu_enable(bool el2_unused)
34 {
35 	if (!amu_supported())
36 		return;
37 
38 	if (el2_unused) {
39 		uint64_t v;
40 		/*
41 		 * Non-secure access from EL0 or EL1 to the Activity Monitor
42 		 * registers do not trap to EL2.
43 		 */
44 		v = read_hcptr();
45 		v &= ~TAM_BIT;
46 		write_hcptr(v);
47 	}
48 
49 	/* Enable group 0 counters */
50 	write_amcntenset0(AMU_GROUP0_COUNTERS_MASK);
51 
52 	/* Enable group 1 counters */
53 	write_amcntenset1(AMU_GROUP1_COUNTERS_MASK);
54 }
55 
56 /* Read the group 0 counter identified by the given `idx`. */
57 uint64_t amu_group0_cnt_read(int idx)
58 {
59 	assert(amu_supported());
60 	assert((idx >= 0) && (idx < AMU_GROUP0_NR_COUNTERS));
61 
62 	return amu_group0_cnt_read_internal(idx);
63 }
64 
65 /* Write the group 0 counter identified by the given `idx` with `val`. */
66 void amu_group0_cnt_write(int idx, uint64_t val)
67 {
68 	assert(amu_supported());
69 	assert((idx >= 0) && (idx < AMU_GROUP0_NR_COUNTERS));
70 
71 	amu_group0_cnt_write_internal(idx, val);
72 	isb();
73 }
74 
75 /* Read the group 1 counter identified by the given `idx`. */
76 uint64_t amu_group1_cnt_read(int idx)
77 {
78 	assert(amu_supported());
79 	assert((idx >= 0) && (idx < AMU_GROUP1_NR_COUNTERS));
80 
81 	return amu_group1_cnt_read_internal(idx);
82 }
83 
84 /* Write the group 1 counter identified by the given `idx` with `val`. */
85 void amu_group1_cnt_write(int idx, uint64_t val)
86 {
87 	assert(amu_supported());
88 	assert((idx >= 0) && (idx < AMU_GROUP1_NR_COUNTERS));
89 
90 	amu_group1_cnt_write_internal(idx, val);
91 	isb();
92 }
93 
94 void amu_group1_set_evtype(int idx, unsigned int val)
95 {
96 	assert(amu_supported());
97 	assert((idx >= 0) && (idx < AMU_GROUP1_NR_COUNTERS));
98 
99 	amu_group1_set_evtype_internal(idx, val);
100 	isb();
101 }
102 
103 static void *amu_context_save(const void *arg)
104 {
105 	struct amu_ctx *ctx;
106 	int i;
107 
108 	if (!amu_supported())
109 		return (void *)-1;
110 
111 	ctx = &amu_ctxs[plat_my_core_pos()];
112 
113 	/* Assert that group 0 counter configuration is what we expect */
114 	assert(read_amcntenset0() == AMU_GROUP0_COUNTERS_MASK &&
115 	       read_amcntenset1() == AMU_GROUP1_COUNTERS_MASK);
116 
117 	/*
118 	 * Disable group 0 counters to avoid other observers like SCP sampling
119 	 * counter values from the future via the memory mapped view.
120 	 */
121 	write_amcntenclr0(AMU_GROUP0_COUNTERS_MASK);
122 	write_amcntenclr1(AMU_GROUP1_COUNTERS_MASK);
123 	isb();
124 
125 	for (i = 0; i < AMU_GROUP0_NR_COUNTERS; i++)
126 		ctx->group0_cnts[i] = amu_group0_cnt_read(i);
127 
128 	for (i = 0; i < AMU_GROUP1_NR_COUNTERS; i++)
129 		ctx->group1_cnts[i] = amu_group1_cnt_read(i);
130 
131 	return (void *)0;
132 }
133 
134 static void *amu_context_restore(const void *arg)
135 {
136 	struct amu_ctx *ctx;
137 	int i;
138 
139 	if (!amu_supported())
140 		return (void *)-1;
141 
142 	ctx = &amu_ctxs[plat_my_core_pos()];
143 
144 	/* Counters were disabled in `amu_context_save()` */
145 	assert((read_amcntenset0() == 0U) && (read_amcntenset1() == 0U));
146 
147 	/* Restore group 0 counters */
148 	for (i = 0; i < AMU_GROUP0_NR_COUNTERS; i++)
149 		amu_group0_cnt_write(i, ctx->group0_cnts[i]);
150 	for (i = 0; i < AMU_GROUP1_NR_COUNTERS; i++)
151 		amu_group1_cnt_write(i, ctx->group1_cnts[i]);
152 
153 	/* Enable group 0 counters */
154 	write_amcntenset0(AMU_GROUP0_COUNTERS_MASK);
155 
156 	/* Enable group 1 counters */
157 	write_amcntenset1(AMU_GROUP1_COUNTERS_MASK);
158 	return (void *)0;
159 }
160 
161 SUBSCRIBE_TO_EVENT(psci_suspend_pwrdown_start, amu_context_save);
162 SUBSCRIBE_TO_EVENT(psci_suspend_pwrdown_finish, amu_context_restore);
163