1 /*
2  * Copyright (c) 2024, 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/css/dsu.h>
14 
15 #include <plat/arm/common/plat_arm.h>
16 #include <plat/common/platform.h>
17 
18 /*
19  * Context structure that saves the state of DSU PMU registers
20  */
21 cluster_pmu_state_t cluster_pmu_context[PLAT_ARM_CLUSTER_COUNT];
22 
23 /****************************************************************************
24  * This function, save_dsu_pmu_state, is designed to save the
25  * current state of the Performance Monitoring Unit (PMU) for a cluster.
26  *
27  * The function performs the following operations:
28  * 1. Saves the current values of several PMU registers
29  *    (CLUSTERPMCR_EL1, CLUSTERPMCNTENSET_EL1, CLUSTERPMCCNTR_EL1,
30  *    CLUSTERPMOVSSET_EL1, and CLUSTERPMSELR_EL1) into the cluster_pmu_state
31  *    structure.
32  *
33  * 2. Disables the PMU event counting by
34  *    clearing the E bit in the clusterpmcr_el1 register.
35  *
36  * 3. Iterates over the available PMU counters as
37  *    determined by the read_cluster_eventctr_num() function.
38  *    For each counter, it:
39  *    a. Selects the counter by writing its index to CLUSTERPMSELR_EL1.
40  *    b. Reads the current counter value (event count) and
41  *       the event type being counted from CLUSTERPMXEVCNTR_EL1 and
42  *       CLUSTERPMXEVTYPER_EL1 registers, respectively.
43  *
44  * This function is useful for preserving the DynamIQ Shared Unit's (DSU)
45  * PMU registers over a power cycle.
46  ***************************************************************************/
47 
save_dsu_pmu_state(cluster_pmu_state_t * cluster_pmu_state)48 void save_dsu_pmu_state(cluster_pmu_state_t *cluster_pmu_state)
49 {
50 	unsigned int idx = 0U;
51 	unsigned int cluster_eventctr_num = read_cluster_eventctr_num();
52 
53 	assert(cluster_pmu_state != 0);
54 
55 	save_pmu_reg(cluster_pmu_state, clusterpmcr);
56 
57 	write_clusterpmcr(cluster_pmu_state->clusterpmcr &
58 			~(CLUSTERPMCR_E_BIT));
59 
60 	save_pmu_reg(cluster_pmu_state, clusterpmcntenset);
61 
62 	save_pmu_reg(cluster_pmu_state, clusterpmccntr);
63 
64 	save_pmu_reg(cluster_pmu_state, clusterpmovsset);
65 
66 	save_pmu_reg(cluster_pmu_state, clusterpmselr);
67 
68 	for (idx = 0U ; idx < cluster_eventctr_num ; idx++) {
69 		write_clusterpmselr(idx);
70 		cluster_pmu_state->counter_val[idx] = read_clusterpmxevcntr();
71 		cluster_pmu_state->counter_type[idx] = read_clusterpmxevtyper();
72 	}
73 }
74 
cluster_off_dsu_pmu_context_save(void)75 void cluster_off_dsu_pmu_context_save(void)
76 {
77 	unsigned int cluster_pos;
78 
79 	cluster_pos = (unsigned int) plat_cluster_id_by_mpidr(read_mpidr_el1());
80 
81 	save_dsu_pmu_state(&cluster_pmu_context[cluster_pos]);
82 }
83 
84 /*****************************************************************************
85  * This function, restore_dsu_pmu_state, restores the state of the
86  * Performance Monitoring Unit (PMU) from a previously saved state.
87  *
88  * The function performs the following operations:
89  * 1. Restores the CLUSTERPMCR_EL1 register with the
90  *    saved value from the cluster_pmu_state structure.
91  * 2. Iterates over the available PMU counters as determined
92  *    by the read_cluster_eventctr_num() function. For each counter, it:
93  *    a. Selects the counter by writing its index to CLUSTERPMSELR_EL1.
94  *    b. Restores the counter value (event count) and the event type to
95  *       CLUSTERPMXEVCNTR_EL1 and CLUSTERPMXEVTYPER_EL1 registers, respectively
96  * 3. Restores several other PMU registers (CLUSTERPMSELR_EL1,
97  *    CLUSTERPMOVSCLR_EL1, CLUSTERPMOVSSET_EL1, CLUSTERPMCCNTR_EL1,
98  *    and CLUSTERPMCNTENSET_EL1) with their saved values.
99  *
100  *****************************************************************************/
restore_dsu_pmu_state(cluster_pmu_state_t * cluster_pmu_state)101 void restore_dsu_pmu_state(cluster_pmu_state_t *cluster_pmu_state)
102 {
103 	unsigned int idx = 0U;
104 	unsigned int cluster_eventctr_num = read_cluster_eventctr_num();
105 
106 	assert(cluster_pmu_state != 0);
107 
108 	for (idx = 0U ; idx < cluster_eventctr_num ; idx++) {
109 		write_clusterpmselr(idx);
110 		write_clusterpmxevcntr(cluster_pmu_state->counter_val[idx]);
111 		write_clusterpmxevtyper(cluster_pmu_state->counter_type[idx]);
112 	}
113 
114 	restore_pmu_reg(cluster_pmu_state, clusterpmselr);
115 
116 	write_clusterpmovsclr(~(uint32_t)cluster_pmu_state->clusterpmovsset);
117 
118 	restore_pmu_reg(cluster_pmu_state, clusterpmovsset);
119 
120 	restore_pmu_reg(cluster_pmu_state, clusterpmccntr);
121 
122 	restore_pmu_reg(cluster_pmu_state, clusterpmcntenset);
123 
124 	write_clusterpmcr(cluster_pmu_state->clusterpmcr);
125 }
126 
cluster_on_dsu_pmu_context_restore(void)127 void cluster_on_dsu_pmu_context_restore(void)
128 {
129 	unsigned int cluster_pos;
130 
131 	cluster_pos = (unsigned int) plat_cluster_id_by_mpidr(read_mpidr_el1());
132 
133 	restore_dsu_pmu_state(&cluster_pmu_context[cluster_pos]);
134 }
135 
136