blob: dea89c5efd1f686e6b8a6970ce6a85deeaf2a65a [file] [log] [blame]
Arvind Ram Prakashf99a69c2023-12-21 00:25:52 -06001/*
Arvind Ram Prakashd52ff2b2025-05-07 10:01:57 -05002 * Copyright (c) 2025, Arm Limited. All rights reserved.
Arvind Ram Prakashf99a69c2023-12-21 00:25:52 -06003 *
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>
Arvind Ram Prakashd52ff2b2025-05-07 10:01:57 -050013#include <drivers/arm/dsu.h>
14#include <dsu_def.h>
15#include <lib/utils_def.h>
Arvind Ram Prakashf99a69c2023-12-21 00:25:52 -060016
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 */
23cluster_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
50void 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
77void cluster_off_dsu_pmu_context_save(void)
78{
79 unsigned int cluster_pos;
80
81 cluster_pos = (unsigned int) plat_cluster_id_by_mpidr(read_mpidr_el1());
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 *****************************************************************************/
103void 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
129void cluster_on_dsu_pmu_context_restore(void)
130{
131 unsigned int cluster_pos;
132
133 cluster_pos = (unsigned int) plat_cluster_id_by_mpidr(read_mpidr_el1());
134
135 restore_dsu_pmu_state(&cluster_pmu_context[cluster_pos]);
136}
137
Arvind Ram Prakashd52ff2b2025-05-07 10:01:57 -0500138void dsu_driver_init(const dsu_driver_data_t *plat_driver_data)
139{
140 uint64_t actlr_el3 = read_actlr_el3();
141 uint64_t pwrctlr = read_clusterpwrctlr_el1();
142 uint64_t pwrdn = read_clusterpwrdn_el1();
143
144 /* enable access to power control registers. */
145 actlr_el3 |= ACTLR_EL3_PWREN_BIT;
146 write_actlr_el3(actlr_el3);
147
148 UPDATE_REG_FIELD(CLUSTERPWRCTLR_FUNCRET, pwrctlr,
149 plat_driver_data->clusterpwrctlr_funcret);
150
151 UPDATE_REG_FIELD(CLUSTERPWRCTLR_CACHEPWR, pwrctlr,
152 plat_driver_data->clusterpwrctlr_cachepwr);
153
154 write_clusterpwrctlr_el1(pwrctlr);
155
156 UPDATE_REG_FIELD(CLUSTERPWRDN_PWRDN, pwrdn,
157 plat_driver_data->clusterpwrdwn_pwrdn);
158
159 UPDATE_REG_FIELD(CLUSTERPWRDN_MEMRET, pwrdn,
160 plat_driver_data->clusterpwrdwn_memret);
161
162 write_clusterpwrdn_el1(pwrdn);
163}
164