1281a08ccSDimitris Papastamos /* 2777f1f68SJayanth Dodderi Chidanand * Copyright (c) 2017-2024, Arm Limited and Contributors. All rights reserved. 3281a08ccSDimitris Papastamos * 4281a08ccSDimitris Papastamos * SPDX-License-Identifier: BSD-3-Clause 5281a08ccSDimitris Papastamos */ 6281a08ccSDimitris Papastamos 709d40e0eSAntonio Nino Diaz #include <stdbool.h> 809d40e0eSAntonio Nino Diaz 9281a08ccSDimitris Papastamos #include <arch.h> 106437a09aSAndre Przywara #include <arch_features.h> 11281a08ccSDimitris Papastamos #include <arch_helpers.h> 1209d40e0eSAntonio Nino Diaz #include <lib/el3_runtime/pubsub.h> 1309d40e0eSAntonio Nino Diaz #include <lib/extensions/spe.h> 14281a08ccSDimitris Papastamos 15777f1f68SJayanth Dodderi Chidanand #include <plat/common/platform.h> 16777f1f68SJayanth Dodderi Chidanand 17777f1f68SJayanth Dodderi Chidanand typedef struct spe_ctx { 18777f1f68SJayanth Dodderi Chidanand u_register_t pmblimitr_el1; 19777f1f68SJayanth Dodderi Chidanand } spe_ctx_t; 20777f1f68SJayanth Dodderi Chidanand 21777f1f68SJayanth Dodderi Chidanand static struct spe_ctx spe_ctxs[PLATFORM_CORE_COUNT]; 22777f1f68SJayanth Dodderi Chidanand 2340daecc1SAntonio Nino Diaz static inline void psb_csync(void) 2440daecc1SAntonio Nino Diaz { 25281a08ccSDimitris Papastamos /* 26281a08ccSDimitris Papastamos * The assembler does not yet understand the psb csync mnemonic 27281a08ccSDimitris Papastamos * so use the equivalent hint instruction. 28281a08ccSDimitris Papastamos */ 2940daecc1SAntonio Nino Diaz __asm__ volatile("hint #17"); 3040daecc1SAntonio Nino Diaz } 31281a08ccSDimitris Papastamos 32123002f9SJayanth Dodderi Chidanand void spe_enable(cpu_context_t *ctx) 332ff8fbf3SDimitris Papastamos { 34123002f9SJayanth Dodderi Chidanand el3_state_t *state = get_el3state_ctx(ctx); 35123002f9SJayanth Dodderi Chidanand u_register_t mdcr_el3_val = read_ctx_reg(state, CTX_MDCR_EL3); 36281a08ccSDimitris Papastamos 37281a08ccSDimitris Papastamos /* 3899506facSBoyan Karatotev * MDCR_EL3.NSPB (ARM v8.2): SPE enabled in Non-secure state 39281a08ccSDimitris Papastamos * and disabled in secure state. Accesses to SPE registers at 40281a08ccSDimitris Papastamos * S-EL1 generate trap exceptions to EL3. 41f20eb893SManish V Badarkhe * 4299506facSBoyan Karatotev * MDCR_EL3.NSPBE: Profiling Buffer uses Non-secure Virtual Addresses. 4399506facSBoyan Karatotev * When FEAT_RME is not implemented, this field is RES0. 4499506facSBoyan Karatotev * 45f20eb893SManish V Badarkhe * MDCR_EL3.EnPMSN (ARM v8.7): Do not trap access to PMSNEVFR_EL1 46f20eb893SManish V Badarkhe * register at NS-EL1 or NS-EL2 to EL3 if FEAT_SPEv1p2 is implemented. 47f20eb893SManish V Badarkhe * Setting this bit to 1 doesn't have any effect on it when 48f20eb893SManish V Badarkhe * FEAT_SPEv1p2 not implemented. 49281a08ccSDimitris Papastamos */ 50123002f9SJayanth Dodderi Chidanand mdcr_el3_val |= MDCR_NSPB(MDCR_NSPB_EL1) | MDCR_EnPMSN_BIT; 51123002f9SJayanth Dodderi Chidanand mdcr_el3_val &= ~(MDCR_NSPBE_BIT); 52123002f9SJayanth Dodderi Chidanand write_ctx_reg(state, CTX_MDCR_EL3, mdcr_el3_val); 53281a08ccSDimitris Papastamos } 54281a08ccSDimitris Papastamos 55*651fe507SManish Pandey void spe_disable(cpu_context_t *ctx) 56*651fe507SManish Pandey { 57*651fe507SManish Pandey el3_state_t *state = get_el3state_ctx(ctx); 58*651fe507SManish Pandey u_register_t mdcr_el3_val = read_ctx_reg(state, CTX_MDCR_EL3); 59*651fe507SManish Pandey 60*651fe507SManish Pandey /* 61*651fe507SManish Pandey * MDCR_EL3.NSPB: Clear these bits to disable SPE feature, as it was enabled 62*651fe507SManish Pandey * for Non-secure state only. After clearing these bits Secure state owns 63*651fe507SManish Pandey * the Profiling Buffer and accesses to Statistical Profiling and Profiling 64*651fe507SManish Pandey * Buffer control registers at EL2 and EL1 generate Trap exceptions to EL3 65*651fe507SManish Pandey * 66*651fe507SManish Pandey * MDCR_EL3.NSPBE: Don't care as it was cleared during spe_enable and setting 67*651fe507SManish Pandey * this to 1 does not make sense as NSPBE{1} and NSPB{0b0x} is RESERVED. 68*651fe507SManish Pandey * 69*651fe507SManish Pandey * MDCR_EL3.EnPMSN (ARM v8.7): Clear the bit to trap access of PMSNEVFR_EL1 70*651fe507SManish Pandey * from EL2/EL1 to EL3. 71*651fe507SManish Pandey */ 72*651fe507SManish Pandey mdcr_el3_val &= ~(MDCR_NSPB(MDCR_NSPB_EL1) | MDCR_EnPMSN_BIT); 73*651fe507SManish Pandey write_ctx_reg(state, CTX_MDCR_EL3, mdcr_el3_val); 74*651fe507SManish Pandey } 75*651fe507SManish Pandey 7660d330dcSBoyan Karatotev void spe_init_el2_unused(void) 7760d330dcSBoyan Karatotev { 7860d330dcSBoyan Karatotev uint64_t v; 7960d330dcSBoyan Karatotev 8060d330dcSBoyan Karatotev /* 8160d330dcSBoyan Karatotev * MDCR_EL2.TPMS (ARM v8.2): Do not trap statistical 8260d330dcSBoyan Karatotev * profiling controls to EL2. 8360d330dcSBoyan Karatotev * 8460d330dcSBoyan Karatotev * MDCR_EL2.E2PB (ARM v8.2): SPE enabled in Non-secure 8560d330dcSBoyan Karatotev * state. Accesses to profiling buffer controls at 8660d330dcSBoyan Karatotev * Non-secure EL1 are not trapped to EL2. 8760d330dcSBoyan Karatotev */ 8860d330dcSBoyan Karatotev v = read_mdcr_el2(); 8960d330dcSBoyan Karatotev v &= ~MDCR_EL2_TPMS; 9060d330dcSBoyan Karatotev v |= MDCR_EL2_E2PB(MDCR_EL2_E2PB_EL1); 9160d330dcSBoyan Karatotev write_mdcr_el2(v); 9260d330dcSBoyan Karatotev } 9360d330dcSBoyan Karatotev 944de07b4bSManish Pandey void spe_stop(void) 95281a08ccSDimitris Papastamos { 96281a08ccSDimitris Papastamos uint64_t v; 97281a08ccSDimitris Papastamos 98281a08ccSDimitris Papastamos /* Drain buffered data */ 99281a08ccSDimitris Papastamos psb_csync(); 100281a08ccSDimitris Papastamos dsbnsh(); 101281a08ccSDimitris Papastamos 102281a08ccSDimitris Papastamos /* Disable profiling buffer */ 103281a08ccSDimitris Papastamos v = read_pmblimitr_el1(); 104281a08ccSDimitris Papastamos v &= ~(1ULL << 0); 105281a08ccSDimitris Papastamos write_pmblimitr_el1(v); 106281a08ccSDimitris Papastamos isb(); 107281a08ccSDimitris Papastamos } 108281a08ccSDimitris Papastamos 109281a08ccSDimitris Papastamos static void *spe_drain_buffers_hook(const void *arg) 110281a08ccSDimitris Papastamos { 1116437a09aSAndre Przywara if (!is_feat_spe_supported()) 1122ff8fbf3SDimitris Papastamos return (void *)-1; 113281a08ccSDimitris Papastamos 114281a08ccSDimitris Papastamos /* Drain buffered data */ 115281a08ccSDimitris Papastamos psb_csync(); 116281a08ccSDimitris Papastamos dsbnsh(); 11740daecc1SAntonio Nino Diaz 11840daecc1SAntonio Nino Diaz return (void *)0; 119281a08ccSDimitris Papastamos } 120281a08ccSDimitris Papastamos 121777f1f68SJayanth Dodderi Chidanand static void *spe_context_save(const void *arg) 122777f1f68SJayanth Dodderi Chidanand { 123777f1f68SJayanth Dodderi Chidanand unsigned int core_pos; 124777f1f68SJayanth Dodderi Chidanand struct spe_ctx *ctx; 125777f1f68SJayanth Dodderi Chidanand 126777f1f68SJayanth Dodderi Chidanand if (is_feat_spe_supported()) { 127777f1f68SJayanth Dodderi Chidanand core_pos = plat_my_core_pos(); 128777f1f68SJayanth Dodderi Chidanand ctx = &spe_ctxs[core_pos]; 129777f1f68SJayanth Dodderi Chidanand ctx->pmblimitr_el1 = read_pmblimitr_el1(); 130777f1f68SJayanth Dodderi Chidanand } 131777f1f68SJayanth Dodderi Chidanand 132777f1f68SJayanth Dodderi Chidanand return NULL; 133777f1f68SJayanth Dodderi Chidanand } 134777f1f68SJayanth Dodderi Chidanand 135777f1f68SJayanth Dodderi Chidanand static void *spe_context_restore(const void *arg) 136777f1f68SJayanth Dodderi Chidanand { 137777f1f68SJayanth Dodderi Chidanand unsigned int core_pos; 138777f1f68SJayanth Dodderi Chidanand struct spe_ctx *ctx; 139777f1f68SJayanth Dodderi Chidanand 140777f1f68SJayanth Dodderi Chidanand if (is_feat_spe_supported()) { 141777f1f68SJayanth Dodderi Chidanand core_pos = plat_my_core_pos(); 142777f1f68SJayanth Dodderi Chidanand ctx = &spe_ctxs[core_pos]; 143777f1f68SJayanth Dodderi Chidanand write_pmblimitr_el1(ctx->pmblimitr_el1); 144777f1f68SJayanth Dodderi Chidanand } 145777f1f68SJayanth Dodderi Chidanand 146777f1f68SJayanth Dodderi Chidanand return NULL; 147777f1f68SJayanth Dodderi Chidanand } 148777f1f68SJayanth Dodderi Chidanand 149281a08ccSDimitris Papastamos SUBSCRIBE_TO_EVENT(cm_entering_secure_world, spe_drain_buffers_hook); 150777f1f68SJayanth Dodderi Chidanand 151777f1f68SJayanth Dodderi Chidanand SUBSCRIBE_TO_EVENT(psci_suspend_pwrdown_start, spe_context_save); 152777f1f68SJayanth Dodderi Chidanand SUBSCRIBE_TO_EVENT(psci_suspend_pwrdown_finish, spe_context_restore); 153