Arvind Ram Prakash | eaa9019 | 2023-12-21 00:25:52 -0600 | [diff] [blame] | 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 | |
| 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 | |
| 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 | *****************************************************************************/ |
| 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 | |
| 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 | |