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