1 /*
2 * Copyright (c) 2025, Arm Limited. All rights reserved.
3 *
4 * SPDX-License-Identifier: BSD-3-Clause
5 */
6
7 #include <assert.h>
8
9 #include <arch.h>
10 #include <arch_helpers.h>
11 #include <common/bl_common.h>
12 #include <common/debug.h>
13 #include <drivers/arm/dsu.h>
14 #include <dsu_def.h>
15 #include <lib/utils_def.h>
16
17 #include <plat/arm/common/plat_arm.h>
18 #include <plat/common/platform.h>
19
20 /*
21 * Context structure that saves the state of DSU PMU registers
22 */
23 cluster_pmu_state_t cluster_pmu_context[PLAT_ARM_CLUSTER_COUNT];
24
25 /****************************************************************************
26 * This function, save_dsu_pmu_state, is designed to save the
27 * current state of the Performance Monitoring Unit (PMU) for a cluster.
28 *
29 * The function performs the following operations:
30 * 1. Saves the current values of several PMU registers
31 * (CLUSTERPMCR_EL1, CLUSTERPMCNTENSET_EL1, CLUSTERPMCCNTR_EL1,
32 * CLUSTERPMOVSSET_EL1, and CLUSTERPMSELR_EL1) into the cluster_pmu_state
33 * structure.
34 *
35 * 2. Disables the PMU event counting by
36 * clearing the E bit in the clusterpmcr_el1 register.
37 *
38 * 3. Iterates over the available PMU counters as
39 * determined by the read_cluster_eventctr_num() function.
40 * For each counter, it:
41 * a. Selects the counter by writing its index to CLUSTERPMSELR_EL1.
42 * b. Reads the current counter value (event count) and
43 * the event type being counted from CLUSTERPMXEVCNTR_EL1 and
44 * CLUSTERPMXEVTYPER_EL1 registers, respectively.
45 *
46 * This function is useful for preserving the DynamIQ Shared Unit's (DSU)
47 * PMU registers over a power cycle.
48 ***************************************************************************/
49
save_dsu_pmu_state(cluster_pmu_state_t * cluster_pmu_state)50 void save_dsu_pmu_state(cluster_pmu_state_t *cluster_pmu_state)
51 {
52 unsigned int idx = 0U;
53 unsigned int cluster_eventctr_num = read_cluster_eventctr_num();
54
55 assert(cluster_pmu_state != 0);
56
57 save_pmu_reg(cluster_pmu_state, clusterpmcr);
58
59 write_clusterpmcr(cluster_pmu_state->clusterpmcr &
60 ~(CLUSTERPMCR_E_BIT));
61
62 save_pmu_reg(cluster_pmu_state, clusterpmcntenset);
63
64 save_pmu_reg(cluster_pmu_state, clusterpmccntr);
65
66 save_pmu_reg(cluster_pmu_state, clusterpmovsset);
67
68 save_pmu_reg(cluster_pmu_state, clusterpmselr);
69
70 for (idx = 0U ; idx < cluster_eventctr_num ; idx++) {
71 write_clusterpmselr(idx);
72 cluster_pmu_state->counter_val[idx] = read_clusterpmxevcntr();
73 cluster_pmu_state->counter_type[idx] = read_clusterpmxevtyper();
74 }
75 }
76
cluster_off_dsu_pmu_context_save(void)77 void cluster_off_dsu_pmu_context_save(void)
78 {
79 unsigned int cluster_pos = plat_cluster_id_by_mpidr(read_mpidr_el1());
80
81 assert(cluster_pos < ARRAY_SIZE(cluster_pmu_context));
82
83 save_dsu_pmu_state(&cluster_pmu_context[cluster_pos]);
84 }
85
86 /*****************************************************************************
87 * This function, restore_dsu_pmu_state, restores the state of the
88 * Performance Monitoring Unit (PMU) from a previously saved state.
89 *
90 * The function performs the following operations:
91 * 1. Restores the CLUSTERPMCR_EL1 register with the
92 * saved value from the cluster_pmu_state structure.
93 * 2. Iterates over the available PMU counters as determined
94 * by the read_cluster_eventctr_num() function. For each counter, it:
95 * a. Selects the counter by writing its index to CLUSTERPMSELR_EL1.
96 * b. Restores the counter value (event count) and the event type to
97 * CLUSTERPMXEVCNTR_EL1 and CLUSTERPMXEVTYPER_EL1 registers, respectively
98 * 3. Restores several other PMU registers (CLUSTERPMSELR_EL1,
99 * CLUSTERPMOVSCLR_EL1, CLUSTERPMOVSSET_EL1, CLUSTERPMCCNTR_EL1,
100 * and CLUSTERPMCNTENSET_EL1) with their saved values.
101 *
102 *****************************************************************************/
restore_dsu_pmu_state(cluster_pmu_state_t * cluster_pmu_state)103 void restore_dsu_pmu_state(cluster_pmu_state_t *cluster_pmu_state)
104 {
105 unsigned int idx = 0U;
106 unsigned int cluster_eventctr_num = read_cluster_eventctr_num();
107
108 assert(cluster_pmu_state != 0);
109
110 for (idx = 0U ; idx < cluster_eventctr_num ; idx++) {
111 write_clusterpmselr(idx);
112 write_clusterpmxevcntr(cluster_pmu_state->counter_val[idx]);
113 write_clusterpmxevtyper(cluster_pmu_state->counter_type[idx]);
114 }
115
116 restore_pmu_reg(cluster_pmu_state, clusterpmselr);
117
118 write_clusterpmovsclr(~(uint32_t)cluster_pmu_state->clusterpmovsset);
119
120 restore_pmu_reg(cluster_pmu_state, clusterpmovsset);
121
122 restore_pmu_reg(cluster_pmu_state, clusterpmccntr);
123
124 restore_pmu_reg(cluster_pmu_state, clusterpmcntenset);
125
126 write_clusterpmcr(cluster_pmu_state->clusterpmcr);
127 }
128
cluster_on_dsu_pmu_context_restore(void)129 void cluster_on_dsu_pmu_context_restore(void)
130 {
131 unsigned int cluster_pos = plat_cluster_id_by_mpidr(read_mpidr_el1());
132
133 assert(cluster_pos < ARRAY_SIZE(cluster_pmu_context));
134
135 restore_dsu_pmu_state(&cluster_pmu_context[cluster_pos]);
136 }
137
dsu_driver_init(const dsu_driver_data_t * plat_driver_data)138 void dsu_driver_init(const dsu_driver_data_t *plat_driver_data)
139 {
140 uint64_t actlr_el3 = read_actlr_el3();
141 uint64_t actlr_el2 = read_actlr_el2();
142 uint64_t pwrctlr = read_clusterpwrctlr_el1();
143 uint64_t pwrdn = read_clusterpwrdn_el1();
144 unsigned int pmmdcr_el3 = read_clusterpmmdcr_el3();
145
146 /* Prohibit PMU event counting in secure state */
147 pmmdcr_el3 &= ~CLUSTERPMMDCR_SPME;
148 write_clusterpmmdcr_el3(pmmdcr_el3);
149
150 /* enable access to power control and PMU registers. */
151 actlr_el3 |= ACTLR_EL3_PWREN_BIT | ACTLR_CLUSTERPMUEN;
152 write_actlr_el3(actlr_el3);
153 actlr_el2 |= ACTLR_CLUSTERPMUEN;
154 write_actlr_el2(actlr_el2);
155
156 UPDATE_REG_FIELD(CLUSTERPWRCTLR_FUNCRET, pwrctlr,
157 plat_driver_data->clusterpwrctlr_funcret);
158
159 UPDATE_REG_FIELD(CLUSTERPWRCTLR_CACHEPWR, pwrctlr,
160 plat_driver_data->clusterpwrctlr_cachepwr);
161
162 write_clusterpwrctlr_el1(pwrctlr);
163
164 UPDATE_REG_FIELD(CLUSTERPWRDN_PWRDN, pwrdn,
165 plat_driver_data->clusterpwrdwn_pwrdn);
166
167 UPDATE_REG_FIELD(CLUSTERPWRDN_MEMRET, pwrdn,
168 plat_driver_data->clusterpwrdwn_memret);
169
170 write_clusterpwrdn_el1(pwrdn);
171 }
172
173