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