blob: a7337ee6544c5ace6624278daaee8fc219ca1d92 [file] [log] [blame]
/*
* Copyright (c) 2021-2024, ARM Limited and Contributors. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#include <stdbool.h>
#include <stdio.h>
#include <arch.h>
#include <arch_features.h>
#include <arch_helpers.h>
#include <assert.h>
#include <debug.h>
#include <lib/extensions/sme.h>
/*
* Function: sme_smstart
* This function enables streaming mode and ZA array storage access
* independently or together based on the type of instruction variant.
*
* Parameters
* smstart_type: If SMSTART, streaming mode and ZA access is enabled.
* If SMSTART_SM, streaming mode enabled.
* If SMSTART_ZA enables SME ZA storage and, ZT0 storage access.
*/
void sme_smstart(smestart_instruction_type_t smstart_type)
{
u_register_t svcr = 0ULL;
switch (smstart_type) {
case SMSTART:
svcr = (SVCR_SM_BIT | SVCR_ZA_BIT);
break;
case SMSTART_SM:
svcr = SVCR_SM_BIT;
break;
case SMSTART_ZA:
svcr = SVCR_ZA_BIT;
break;
default:
ERROR("Illegal SMSTART Instruction Variant\n");
break;
}
write_svcr(read_svcr() | svcr);
isb();
}
/*
* sme_smstop
* This function exits streaming mode and disables ZA array storage access
* independently or together based on the type of instruction variant.
*
* Parameters
* smstop_type: If SMSTOP, exits streaming mode and ZA access is disabled
* If SMSTOP_SM, exits streaming mode.
* If SMSTOP_ZA disables SME ZA storage and, ZT0 storage access.
*/
void sme_smstop(smestop_instruction_type_t smstop_type)
{
u_register_t svcr = 0ULL;
switch (smstop_type) {
case SMSTOP:
svcr = (~SVCR_SM_BIT) & (~SVCR_ZA_BIT);
break;
case SMSTOP_SM:
svcr = ~SVCR_SM_BIT;
break;
case SMSTOP_ZA:
svcr = ~SVCR_ZA_BIT;
break;
default:
ERROR("Illegal SMSTOP Instruction Variant\n");
break;
}
write_svcr(read_svcr() & svcr);
isb();
}
/* Set the Streaming SVE vector length (SVL) in the SMCR_EL2 register */
void sme_config_svq(uint32_t svq)
{
u_register_t smcr_el2_val;
/* Cap svq to arch supported max value. */
if (svq > SME_SVQ_ARCH_MAX) {
svq = SME_SVQ_ARCH_MAX;
}
smcr_el2_val = read_smcr_el2();
smcr_el2_val &= ~(MASK(SMCR_ELX_LEN));
smcr_el2_val |= INPLACE(SMCR_ELX_LEN, svq);
write_smcr_el2(smcr_el2_val);
isb();
}
static void set_smcr_fa64(bool enable)
{
if (enable) {
write_smcr_el2(read_smcr_el2() | SMCR_ELX_FA64_BIT);
} else {
write_smcr_el2(read_smcr_el2() & ~SMCR_ELX_FA64_BIT);
}
isb();
}
/*
* Enable FEAT_SME_FA64, This control causes all implemented A64 instructions
* to be treated as legal in Streaming SVE mode at EL2, if they are treated as
* legal at EL3.
*/
void sme_enable_fa64(void)
{
return set_smcr_fa64(true);
}
/*
* Disable FEAT_SME_FA64, This control does not cause any instruction to be
* treated as legal in Streaming SVE mode.
*/
void sme_disable_fa64(void)
{
return set_smcr_fa64(false);
}
/* Returns 'true' if the CPU is in Streaming SVE mode */
bool sme_smstat_sm(void)
{
return ((read_svcr() & SVCR_SM_BIT) != 0U);
}
bool sme_feat_fa64_enabled(void)
{
return ((read_smcr_el2() & SMCR_ELX_FA64_BIT) != 0U);
}
uint32_t sme_probe_svl(uint8_t sme_max_svq)
{
uint32_t svl_bitmap = 0;
uint8_t svq, rdsvl_vq;
/* Cap svq to arch supported max value. */
if (sme_max_svq > SME_SVQ_ARCH_MAX) {
sme_max_svq = SME_SVQ_ARCH_MAX;
}
for (svq = 0; svq <= sme_max_svq; svq++) {
sme_config_svq(svq);
rdsvl_vq = SME_SVL_TO_SVQ(sme_rdsvl_1());
if (svl_bitmap & BIT_32(rdsvl_vq)) {
continue;
}
svl_bitmap |= BIT_32(rdsvl_vq);
}
return svl_bitmap;
}