summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/arch/arm64/Makefile.mk13
-rw-r--r--src/arch/arm64/include/armv8/arch/smc.h52
-rw-r--r--src/arch/arm64/smc.c66
-rw-r--r--src/arch/arm64/smc_asm.S9
4 files changed, 140 insertions, 0 deletions
diff --git a/src/arch/arm64/Makefile.mk b/src/arch/arm64/Makefile.mk
index 897dae525f..6499283c08 100644
--- a/src/arch/arm64/Makefile.mk
+++ b/src/arch/arm64/Makefile.mk
@@ -30,6 +30,9 @@ bootblock-y += eabi_compat.c
decompressor-$(CONFIG_ARM64_USE_ARCH_TIMER) += arch_timer.c
bootblock-$(CONFIG_ARM64_USE_ARCH_TIMER) += arch_timer.c
bootblock-y += transition.c transition_asm.S
+ifneq ($(CONFIG_ARM64_CURRENT_EL),3)
+bootblock-y += smc.c smc_asm.S
+endif
decompressor-y += memset.S
bootblock-y += memset.S
@@ -69,6 +72,9 @@ verstage-y += memcpy.S
verstage-y += memmove.S
verstage-y += transition.c transition_asm.S
+ifneq ($(CONFIG_ARM64_CURRENT_EL),3)
+verstage-y += smc.c smc_asm.S
+endif
endif # CONFIG_ARCH_VERSTAGE_ARM64
@@ -88,6 +94,9 @@ romstage-y += memmove.S
romstage-y += ramdetect.c
romstage-y += romstage.c
romstage-y += transition.c transition_asm.S
+ifneq ($(CONFIG_ARM64_CURRENT_EL),3)
+romstage-y += smc.c smc_asm.S
+endif
rmodules_arm64-y += memset.S
rmodules_arm64-y += memcpy.S
@@ -109,6 +118,7 @@ ifeq ($(CONFIG_ARCH_RAMSTAGE_ARM64),y)
ramstage-y += div0.c
ramstage-y += eabi_compat.c
ramstage-y += boot.c
+ramstage-$(CONFIG_GENERATE_SMBIOS_TABLES) += smbios.c
ramstage-y += tables.c
ramstage-y += ramdetect.c
ramstage-$(CONFIG_ARM64_USE_ARCH_TIMER) += arch_timer.c
@@ -117,6 +127,9 @@ ramstage-y += memcpy.S
ramstage-y += memmove.S
ramstage-$(CONFIG_ARM64_USE_ARM_TRUSTED_FIRMWARE) += bl31.c
ramstage-y += transition.c transition_asm.S
+ifneq ($(CONFIG_ARM64_CURRENT_EL),3)
+ramstage-y += smc.c smc_asm.S
+endif
ramstage-$(CONFIG_PAYLOAD_FIT_SUPPORT) += fit_payload.c
ramstage-$(CONFIG_HAVE_ACPI_TABLES) += acpi.c
ramstage-y += dma.c
diff --git a/src/arch/arm64/include/armv8/arch/smc.h b/src/arch/arm64/include/armv8/arch/smc.h
new file mode 100644
index 0000000000..2e7cc8a3c2
--- /dev/null
+++ b/src/arch/arm64/include/armv8/arch/smc.h
@@ -0,0 +1,52 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+
+#ifndef ARM_ARM64_SMC_H
+#define ARM_ARM64_SMC_H
+
+#include <types.h>
+
+uint64_t smc(uint32_t function_id, uint64_t arg1, uint64_t arg2, uint64_t arg3,
+ uint64_t arg4, uint64_t arg5, uint64_t arg6, uint64_t arg7);
+
+#define smc_call0(function_id) smc(function_id, 0, 0, 0, 0, 0, 0, 0)
+#define smc_call1(function_id, a1) smc(function_id, a1, 0, 0, 0, 0, 0, 0)
+#define smc_call2(function_id, a1, a2) smc(function_id, a1, a2, 0, 0, 0, 0, 0)
+#define smc_call3(function_id, a1, a2, a3) smc(function_id, a1, a2, a3, 0, 0, 0, 0)
+
+/* Documented in https://developer.arm.com/documentation/den0022/ */
+enum psci_return_values {
+ PSCI_SUCCESS = 0,
+ PSCI_NOT_SUPPORTED = -1,
+ PSCI_INVALID_PARAMETERS = -2,
+ PSCI_DENIED = -3,
+ PSCI_ALREADY_ON = -4,
+ PSCI_ON_PENDING = -5,
+ PSCI_INTERNAL_FAILURE = -6,
+ PSCI_NOT_PRESENT = -7,
+ PSCI_DISABLED = -8,
+ PSCI_INVALID_ADDRESS = -9,
+};
+
+/* PSCI functions */
+#define PSCI_VERSION 0x84000000
+#define PSCI_FEATURES 0x8400000a
+
+/* Documented in https://developer.arm.com/documentation/den0028/ */
+enum smccc_return_values {
+ SMC_SUCCESS = 0,
+ SMC_NOT_SUPPORTED = -1,
+ SMC_NOT_REQUIRED = -2,
+ SMC_INVALID_PARAMETER = -3,
+};
+
+/* SMCCC functions */
+#define SMCCC_VERSION 0x80000000
+#define SMCCC_ARCH_FEATURES 0x80000001
+#define SMCCC_ARCH_SOC_ID 0x80000002
+#define SMCCC_GET_SOC_VERSION 0
+#define SMCCC_GET_SOC_REVISION 1
+
+uint8_t smccc_supports_arch_soc_id(void);
+enum cb_err smccc_arch_soc_id(uint32_t *jep106code, uint32_t *soc_revision);
+
+#endif /* ARM_ARM64_SMC_H */
diff --git a/src/arch/arm64/smc.c b/src/arch/arm64/smc.c
new file mode 100644
index 0000000000..9a8883fcff
--- /dev/null
+++ b/src/arch/arm64/smc.c
@@ -0,0 +1,66 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+
+#include <arch/smc.h>
+#include <console/console.h>
+#include <types.h>
+
+/* Assumes at least a PSCI implementation is present */
+uint8_t smccc_supports_arch_soc_id(void)
+{
+ static uint8_t supported = 0xff;
+ uint64_t smc_ret;
+
+ if (supported != 0xff)
+ return supported;
+
+ // PSCI_FEATURES mandatory from PSCI 1.0
+ smc_ret = smc_call0(PSCI_VERSION);
+ if (smc_ret < 0x10000)
+ goto fail;
+
+ smc_ret = smc_call1(PSCI_FEATURES, SMCCC_VERSION);
+ if (smc_ret == PSCI_NOT_SUPPORTED)
+ goto fail;
+
+ // SMCCC_ARCH_FEATURES supported from SMCCC 1.1
+ smc_ret = smc_call0(SMCCC_VERSION);
+ if (smc_ret < 0x10001)
+ goto fail;
+
+ smc_ret = smc_call1(SMCCC_ARCH_FEATURES, SMCCC_ARCH_SOC_ID);
+ if (smc_ret != SMC_SUCCESS)
+ goto fail;
+
+ supported = 1;
+ return supported;
+
+fail:
+ supported = 0;
+ return supported;
+}
+
+enum cb_err smccc_arch_soc_id(uint32_t *jep106code, uint32_t *soc_revision)
+{
+ uint64_t smc_ret;
+
+ if (jep106code == NULL || soc_revision == NULL)
+ return CB_ERR_ARG;
+
+ smc_ret = smc_call1(SMCCC_ARCH_SOC_ID, SMCCC_GET_SOC_VERSION);
+ if (smc_ret != SMC_INVALID_PARAMETER)
+ *jep106code = smc_ret;
+ else
+ *jep106code = -1;
+
+ smc_ret = smc_call1(SMCCC_ARCH_SOC_ID, SMCCC_GET_SOC_REVISION);
+ if (smc_ret != SMC_INVALID_PARAMETER)
+ *soc_revision = smc_ret;
+ else
+ *soc_revision = -1;
+
+ if (*jep106code == -1 || *soc_revision == -1) {
+ printk(BIOS_ERR, "SMCCC_ARCH_SOC_ID failed!\n");
+ return CB_ERR;
+ } else
+ return CB_SUCCESS;
+}
diff --git a/src/arch/arm64/smc_asm.S b/src/arch/arm64/smc_asm.S
new file mode 100644
index 0000000000..74b62c1ffa
--- /dev/null
+++ b/src/arch/arm64/smc_asm.S
@@ -0,0 +1,9 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+
+#include <arch/asm.h>
+
+ENTRY(smc)
+ /* W0, X1-X7 passed as arguments. Function ID is always W0. */
+ smc #0
+ ret /* X0 passed back as return value */
+ENDPROC(smc)