johpow01 | 9baade3 | 2021-07-08 14:14:00 -0500 | [diff] [blame] | 1 | /* |
Mark Brown | beaf5e8 | 2022-05-09 13:26:36 +0100 | [diff] [blame] | 2 | * Copyright (c) 2021-2022, Arm Limited and Contributors. All rights reserved. |
johpow01 | 9baade3 | 2021-07-08 14:14:00 -0500 | [diff] [blame] | 3 | * |
| 4 | * SPDX-License-Identifier: BSD-3-Clause |
| 5 | */ |
| 6 | |
| 7 | #include <stdbool.h> |
| 8 | |
| 9 | #include <arch.h> |
| 10 | #include <arch_helpers.h> |
| 11 | #include <common/debug.h> |
| 12 | #include <lib/el3_runtime/context_mgmt.h> |
| 13 | #include <lib/extensions/sme.h> |
| 14 | #include <lib/extensions/sve.h> |
| 15 | |
| 16 | static bool feat_sme_supported(void) |
| 17 | { |
| 18 | uint64_t features; |
| 19 | |
| 20 | features = read_id_aa64pfr1_el1() >> ID_AA64PFR1_EL1_SME_SHIFT; |
| 21 | return (features & ID_AA64PFR1_EL1_SME_MASK) != 0U; |
| 22 | } |
| 23 | |
| 24 | static bool feat_sme_fa64_supported(void) |
| 25 | { |
| 26 | uint64_t features; |
| 27 | |
| 28 | features = read_id_aa64smfr0_el1(); |
| 29 | return (features & ID_AA64SMFR0_EL1_FA64_BIT) != 0U; |
| 30 | } |
| 31 | |
| 32 | void sme_enable(cpu_context_t *context) |
| 33 | { |
| 34 | u_register_t reg; |
| 35 | u_register_t cptr_el3; |
| 36 | el3_state_t *state; |
| 37 | |
| 38 | /* Make sure SME is implemented in hardware before continuing. */ |
| 39 | if (!feat_sme_supported()) { |
Mark Brown | beaf5e8 | 2022-05-09 13:26:36 +0100 | [diff] [blame] | 40 | /* Perhaps the hardware supports SVE only */ |
| 41 | sve_enable(context); |
johpow01 | 9baade3 | 2021-07-08 14:14:00 -0500 | [diff] [blame] | 42 | return; |
| 43 | } |
| 44 | |
| 45 | /* Get the context state. */ |
| 46 | state = get_el3state_ctx(context); |
| 47 | |
| 48 | /* Enable SME in CPTR_EL3. */ |
| 49 | reg = read_ctx_reg(state, CTX_CPTR_EL3); |
| 50 | reg |= ESM_BIT; |
| 51 | write_ctx_reg(state, CTX_CPTR_EL3, reg); |
| 52 | |
| 53 | /* Set the ENTP2 bit in SCR_EL3 to enable access to TPIDR2_EL0. */ |
| 54 | reg = read_ctx_reg(state, CTX_SCR_EL3); |
| 55 | reg |= SCR_ENTP2_BIT; |
| 56 | write_ctx_reg(state, CTX_SCR_EL3, reg); |
| 57 | |
| 58 | /* Set CPTR_EL3.ESM bit so we can write SMCR_EL3 without trapping. */ |
| 59 | cptr_el3 = read_cptr_el3(); |
| 60 | write_cptr_el3(cptr_el3 | ESM_BIT); |
Boyan Karatotev | be028b4 | 2022-10-13 13:51:05 +0100 | [diff] [blame] | 61 | isb(); |
johpow01 | 9baade3 | 2021-07-08 14:14:00 -0500 | [diff] [blame] | 62 | |
| 63 | /* |
| 64 | * Set the max LEN value and FA64 bit. This register is set up globally |
| 65 | * to be the least restrictive, then lower ELs can restrict as needed |
| 66 | * using SMCR_EL2 and SMCR_EL1. |
| 67 | */ |
| 68 | reg = SMCR_ELX_LEN_MASK; |
| 69 | if (feat_sme_fa64_supported()) { |
| 70 | VERBOSE("[SME] FA64 enabled\n"); |
| 71 | reg |= SMCR_ELX_FA64_BIT; |
| 72 | } |
| 73 | write_smcr_el3(reg); |
| 74 | |
| 75 | /* Reset CPTR_EL3 value. */ |
| 76 | write_cptr_el3(cptr_el3); |
Boyan Karatotev | be028b4 | 2022-10-13 13:51:05 +0100 | [diff] [blame] | 77 | isb(); |
johpow01 | 9baade3 | 2021-07-08 14:14:00 -0500 | [diff] [blame] | 78 | |
| 79 | /* Enable SVE/FPU in addition to SME. */ |
| 80 | sve_enable(context); |
| 81 | } |
| 82 | |
| 83 | void sme_disable(cpu_context_t *context) |
| 84 | { |
| 85 | u_register_t reg; |
| 86 | el3_state_t *state; |
| 87 | |
| 88 | /* Make sure SME is implemented in hardware before continuing. */ |
| 89 | if (!feat_sme_supported()) { |
Mark Brown | beaf5e8 | 2022-05-09 13:26:36 +0100 | [diff] [blame] | 90 | /* Perhaps the hardware supports SVE only */ |
| 91 | sve_disable(context); |
johpow01 | 9baade3 | 2021-07-08 14:14:00 -0500 | [diff] [blame] | 92 | return; |
| 93 | } |
| 94 | |
| 95 | /* Get the context state. */ |
| 96 | state = get_el3state_ctx(context); |
| 97 | |
| 98 | /* Disable SME, SVE, and FPU since they all share registers. */ |
| 99 | reg = read_ctx_reg(state, CTX_CPTR_EL3); |
| 100 | reg &= ~ESM_BIT; /* Trap SME */ |
| 101 | reg &= ~CPTR_EZ_BIT; /* Trap SVE */ |
| 102 | reg |= TFP_BIT; /* Trap FPU/SIMD */ |
| 103 | write_ctx_reg(state, CTX_CPTR_EL3, reg); |
| 104 | |
| 105 | /* Disable access to TPIDR2_EL0. */ |
| 106 | reg = read_ctx_reg(state, CTX_SCR_EL3); |
| 107 | reg &= ~SCR_ENTP2_BIT; |
| 108 | write_ctx_reg(state, CTX_SCR_EL3, reg); |
| 109 | } |