From ed12b1f3d215953536d9079723751fe3cf340fb6 Mon Sep 17 00:00:00 2001 From: Carlo Caione Date: Sat, 19 Dec 2020 15:52:48 +0100 Subject: [PATCH 1/2] drivers: PSCI: Add driver and subsystem Firmware implementing the PSCI functions described in ARM document number ARM DEN 0022A ("Power State Coordination Interface System Software on ARM processors") can be used by Zephyr to initiate various CPU-centric power operations. It is needed for virtualization, it is used to coordinate OSes and hypervisors and it provides the functions used for SMP bring-up such as CPU_ON and CPU_OFF. A new PSCI driver is introduced to setup a proper subsystem used to communicate with the PSCI firmware, implementing the basic operations: get_version, cpu_on, cpu_off and affinity_info. The current implementation only supports PSCI 0.2 and PSCI 1.0 The PSCI conduit (SMC or HVC) is setup reading the corresponding property in the DTS node. Signed-off-by: Carlo Caione --- CODEOWNERS | 4 + MAINTAINERS.yml | 11 ++ arch/arm/core/aarch64/CMakeLists.txt | 1 + arch/arm/core/aarch64/smccc-call.S | 40 +++++ .../arm/qemu_cortex_a53/qemu_cortex_a53.dts | 6 + .../qemu_cortex_a53/qemu_cortex_a53_defconfig | 3 + drivers/CMakeLists.txt | 1 + drivers/Kconfig | 2 + drivers/psci/CMakeLists.txt | 6 + drivers/psci/Kconfig | 22 +++ drivers/psci/psci.c | 159 +++++++++++++++++ drivers/psci/psci.h | 63 +++++++ drivers/psci/psci_handlers.c | 45 +++++ dts/bindings/psci/arm,psci.yaml | 20 +++ include/arch/arm/arm-smccc.h | 53 ++++++ include/drivers/psci.h | 160 ++++++++++++++++++ 16 files changed, 596 insertions(+) create mode 100644 arch/arm/core/aarch64/smccc-call.S create mode 100644 drivers/psci/CMakeLists.txt create mode 100644 drivers/psci/Kconfig create mode 100644 drivers/psci/psci.c create mode 100644 drivers/psci/psci.h create mode 100644 drivers/psci/psci_handlers.c create mode 100644 dts/bindings/psci/arm,psci.yaml create mode 100644 include/arch/arm/arm-smccc.h create mode 100644 include/drivers/psci.h diff --git a/CODEOWNERS b/CODEOWNERS index 77a13b33c1a9b3..db2b2265730a5c 100644 --- a/CODEOWNERS +++ b/CODEOWNERS @@ -235,6 +235,7 @@ /drivers/peci/ @albertofloyd @franciscomunoz @scottwcpg /drivers/pinmux/*hsdk* @iriszzw /drivers/pinmux/*it8xxx2* @ite +/drivers/psci/ @carlocaione /drivers/ps2/ @albertofloyd @franciscomunoz @scottwcpg /drivers/pwm/*sam0* @nzmichaelh /drivers/pwm/*stm32* @gmarull @@ -350,6 +351,7 @@ /dts/bindings/*/sifive* @mateusz-holenko @kgugala @pgielda @nategraff-sifive /dts/bindings/*/litex* @mateusz-holenko @kgugala @pgielda /dts/bindings/*/vexriscv* @mateusz-holenko @kgugala @pgielda +/dts/bindings/psci/* @carlocaione /dts/posix/ @aescolar @vanwinkeljan @daor-oti /dts/bindings/sensor/*bme680* @BoschSensortec /dts/bindings/sensor/st* @avisconti @@ -376,6 +378,7 @@ /include/drivers/spi.h @tbursztyka /include/drivers/lora.h @Mani-Sadhasivam /include/drivers/peci.h @albertofloyd @franciscomunoz @scottwcpg +/include/drivers/psci.h @carlocaione /include/app_memory/ @andrewboie /include/arch/arc/ @abrodkin @ruuddw /include/arch/arc/arch.h @andrewboie @@ -383,6 +386,7 @@ /include/arch/arm/aarch32/ @MaureenHelm @galak @ioannisg /include/arch/arm/aarch32/cortex_a_r/ @stephanosio /include/arch/arm/aarch64/ @carlocaione +/include/arch/arm/arm-smccc.h @carlocaione /include/arch/arm/aarch32/irq.h @andrewboie /include/arch/nios2/ @andrewboie /include/arch/nios2/arch.h @andrewboie diff --git a/MAINTAINERS.yml b/MAINTAINERS.yml index c09132919f9609..7c7f9f01b1ab21 100644 --- a/MAINTAINERS.yml +++ b/MAINTAINERS.yml @@ -654,6 +654,17 @@ Documentation: labels: - "area: Clocks" +"Drivers: PSCI": + status: maintained + maintainers: + - carlocaione + files: + - drivers/psci/ + - include/drivers/psci.h + - include/arch/arm/arm-smccc.h + labels: + - "area: PSCI" + "Drivers: PWM": status: maintained maintainers: diff --git a/arch/arm/core/aarch64/CMakeLists.txt b/arch/arm/core/aarch64/CMakeLists.txt index 3ce4a174971eb7..7f4c8db955839e 100644 --- a/arch/arm/core/aarch64/CMakeLists.txt +++ b/arch/arm/core/aarch64/CMakeLists.txt @@ -30,5 +30,6 @@ endif () zephyr_library_sources_ifdef(CONFIG_GEN_SW_ISR_TABLE isr_wrapper.S) zephyr_library_sources_ifdef(CONFIG_IRQ_OFFLOAD irq_offload.c) zephyr_library_sources_ifdef(CONFIG_THREAD_LOCAL_STORAGE ../common/tls.c) +zephyr_library_sources_ifdef(CONFIG_ARM_PSCI smccc-call.S) add_subdirectory_ifdef(CONFIG_ARM_MMU mmu) diff --git a/arch/arm/core/aarch64/smccc-call.S b/arch/arm/core/aarch64/smccc-call.S new file mode 100644 index 00000000000000..10e32ccaafb1f2 --- /dev/null +++ b/arch/arm/core/aarch64/smccc-call.S @@ -0,0 +1,40 @@ +/* + * Copyright (c) 2019 Carlo Caione + * + * SPDX-License-Identifier: Apache-2.0 + */ + +/* + * This file implements the common calling mechanism to be used with the Secure + * Monitor Call (SMC) and Hypervisor Call (HVC). + * + * See http://infocenter.arm.com/help/topic/com.arm.doc.den0028a/index.html + */ + +#include +#include +#include + +.macro SMCCC instr + \instr #0 + ldr x4, [sp] + stp x0, x1, [x4] + stp x2, x3, [x4, #16] + ret +.endm + +/* + * The SMC instruction is used to generate a synchronous exception that is + * handled by Secure Monitor code running in EL3. + */ +GTEXT(arm_smccc_smc) +SECTION_FUNC(TEXT, arm_smccc_smc) + SMCCC smc + +/* + * The HVC instruction is used to generate a synchronous exception that is + * handled by a hypervisor running in EL2. + */ +GTEXT(arm_smccc_hvc) +SECTION_FUNC(TEXT, arm_smccc_hvc) + SMCCC hvc diff --git a/boards/arm/qemu_cortex_a53/qemu_cortex_a53.dts b/boards/arm/qemu_cortex_a53/qemu_cortex_a53.dts index ee7358df6a8225..d93f42735d2f4c 100644 --- a/boards/arm/qemu_cortex_a53/qemu_cortex_a53.dts +++ b/boards/arm/qemu_cortex_a53/qemu_cortex_a53.dts @@ -12,6 +12,12 @@ model = "QEMU Cortex-A53"; compatible = "qemu,arm-cortex-a53"; + psci { + compatible = "arm,psci-0.2"; + method = "hvc"; + label = "PSCI"; + }; + chosen { zephyr,sram = &sram0; zephyr,console = &uart0; diff --git a/boards/arm/qemu_cortex_a53/qemu_cortex_a53_defconfig b/boards/arm/qemu_cortex_a53/qemu_cortex_a53_defconfig index f37de02c00434b..e6ac5b542ecdaf 100644 --- a/boards/arm/qemu_cortex_a53/qemu_cortex_a53_defconfig +++ b/boards/arm/qemu_cortex_a53/qemu_cortex_a53_defconfig @@ -11,6 +11,9 @@ CONFIG_SERIAL=y CONFIG_CONSOLE=y CONFIG_UART_CONSOLE=y +# PSCI is supported +CONFIG_ARM_PSCI=y + # Enable serial port CONFIG_UART_PL011=y CONFIG_UART_PL011_PORT0=y diff --git a/drivers/CMakeLists.txt b/drivers/CMakeLists.txt index 1e09fe0f7496e9..03aed8fa953db1 100644 --- a/drivers/CMakeLists.txt +++ b/drivers/CMakeLists.txt @@ -42,6 +42,7 @@ add_subdirectory_ifdef(CONFIG_PECI peci) add_subdirectory_ifdef(CONFIG_REGULATOR regulator) add_subdirectory_ifdef(CONFIG_MEMC memc) add_subdirectory_ifdef(CONFIG_VIRTUALIZATION virtualization) +add_subdirectory_ifdef(CONFIG_ARM_PSCI psci) add_subdirectory_ifdef(CONFIG_FLASH_HAS_DRIVER_ENABLED flash) add_subdirectory_ifdef(CONFIG_SERIAL_HAS_DRIVER serial) diff --git a/drivers/Kconfig b/drivers/Kconfig index e49f06a92173ee..f544db0b6ee25d 100644 --- a/drivers/Kconfig +++ b/drivers/Kconfig @@ -105,4 +105,6 @@ source "drivers/memc/Kconfig" source "drivers/virtualization/Kconfig" +source "drivers/psci/Kconfig" + endmenu diff --git a/drivers/psci/CMakeLists.txt b/drivers/psci/CMakeLists.txt new file mode 100644 index 00000000000000..98afb5ce09b443 --- /dev/null +++ b/drivers/psci/CMakeLists.txt @@ -0,0 +1,6 @@ +# SPDX-License-Identifier: Apache-2.0 + +zephyr_library() + +zephyr_library_sources_ifdef(CONFIG_ARM_PSCI psci.c) +zephyr_library_sources_ifdef(CONFIG_USERSPACE psci_handlers.c) diff --git a/drivers/psci/Kconfig b/drivers/psci/Kconfig new file mode 100644 index 00000000000000..cc2e7167d9dfaa --- /dev/null +++ b/drivers/psci/Kconfig @@ -0,0 +1,22 @@ +# PSCI driver configuration options + +# Copyright (c) 2020 Carlo Caione +# SPDX-License-Identifier: Apache-2.0 + +config ARM_PSCI + bool "Support for the ARM Power State Coordination Interface (PSCI)" + depends on ARMV8_A + help + Say Y here if you want Zephyr to communicate with system firmware + implementing the PSCI specification for CPU-centric power + management operations described in ARM document number ARM DEN + 0022A ("Power State Coordination Interface System Software on + ARM processors"). + +if ARM_PSCI + +module = PSCI +module-str = psci +source "subsys/logging/Kconfig.template.log_config" + +endif diff --git a/drivers/psci/psci.c b/drivers/psci/psci.c new file mode 100644 index 00000000000000..91eb52f411d28b --- /dev/null +++ b/drivers/psci/psci.c @@ -0,0 +1,159 @@ +/* + * Copyright 2020 Carlo Caione + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#define DT_DRV_COMPAT arm_psci_0_2 + +#define LOG_LEVEL CONFIG_PSCI_LOG_LEVEL +#include +LOG_MODULE_REGISTER(psci); + +#include +#include + +#include +#include +#include + +#include +#include "psci.h" + +static int psci_to_dev_err(int ret) +{ + switch (ret) { + case PSCI_RET_SUCCESS: + return 0; + case PSCI_RET_NOT_SUPPORTED: + return -ENOTSUP; + case PSCI_RET_INVALID_PARAMS: + case PSCI_RET_INVALID_ADDRESS: + return -EINVAL; + case PSCI_RET_DENIED: + return -EPERM; + }; + + return -EINVAL; +} + +static uint32_t psci_api_get_version(const struct device *dev) +{ + struct psci *data = dev->data; + + return data->invoke_psci_fn(PSCI_0_2_FN_PSCI_VERSION, 0, 0, 0); +} + +static int psci_api_cpu_off(const struct device *dev, uint32_t state) +{ + struct psci *data = dev->data; + int ret; + + ret = data->invoke_psci_fn(PSCI_0_2_FN_CPU_OFF, state, 0, 0); + + return psci_to_dev_err(ret); +} + +static int psci_api_cpu_on(const struct device *dev, unsigned long cpuid, + unsigned long entry_point) +{ + struct psci *data = dev->data; + int ret; + + ret = data->invoke_psci_fn(PSCI_FN_NATIVE(0_2, CPU_ON), cpuid, + entry_point, 0); + + return psci_to_dev_err(ret); +} + +static int psci_api_affinity_info(const struct device *dev, + unsigned long target_affinity, + unsigned long lowest_affinity_level) +{ + struct psci *data = dev->data; + + return data->invoke_psci_fn(PSCI_FN_NATIVE(0_2, AFFINITY_INFO), + target_affinity, lowest_affinity_level, 0); +} + +static unsigned long __invoke_psci_fn_hvc(unsigned long function_id, + unsigned long arg0, + unsigned long arg1, + unsigned long arg2) +{ + struct arm_smccc_res res; + + arm_smccc_hvc(function_id, arg0, arg1, arg2, 0, 0, 0, 0, &res); + return res.a0; +} + +static unsigned long __invoke_psci_fn_smc(unsigned long function_id, + unsigned long arg0, + unsigned long arg1, + unsigned long arg2) +{ + struct arm_smccc_res res; + + arm_smccc_smc(function_id, arg0, arg1, arg2, 0, 0, 0, 0, &res); + return res.a0; +} + +static int set_conduit_method(struct psci *data) +{ + const char *method; + + method = DT_PROP(DT_INST(0, DT_DRV_COMPAT), method); + + if (!strcmp("hvc", method)) { + data->conduit = SMCCC_CONDUIT_HVC; + data->invoke_psci_fn = __invoke_psci_fn_hvc; + } else if (!strcmp("smc", method)) { + data->conduit = SMCCC_CONDUIT_SMC; + data->invoke_psci_fn = __invoke_psci_fn_smc; + } else { + LOG_ERR("Invalid conduit method"); + return -EINVAL; + } + + return 0; +} + +static int psci_detect(const struct device *dev) +{ + uint32_t ver = psci_api_get_version(dev); + + LOG_DBG("Detected PSCIv%d.%d", + PSCI_VERSION_MAJOR(ver), + PSCI_VERSION_MINOR(ver)); + + if (PSCI_VERSION_MAJOR(ver) == 0 && PSCI_VERSION_MINOR(ver) < 2) { + LOG_ERR("PSCI unsupported version"); + return -ENOTSUP; + } + + return 0; +} + +static int psci_init(const struct device *dev) +{ + struct psci *data = dev->data; + + if (set_conduit_method(data)) { + return -ENOTSUP; + } + + return psci_detect(dev); +} + +static const struct psci_driver_api psci_api = { + .get_version = psci_api_get_version, + .cpu_off = psci_api_cpu_off, + .cpu_on = psci_api_cpu_on, + .affinity_info = psci_api_affinity_info, +}; + +static struct psci psci_data; + +DEVICE_DT_INST_DEFINE(0, psci_init, device_pm_control_nop, + &psci_data, NULL, PRE_KERNEL_1, CONFIG_KERNEL_INIT_PRIORITY_DEVICE, + &psci_api); diff --git a/drivers/psci/psci.h b/drivers/psci/psci.h new file mode 100644 index 00000000000000..8271180e97cde8 --- /dev/null +++ b/drivers/psci/psci.h @@ -0,0 +1,63 @@ +/* + * Copyright 2020 Carlo Caione + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef ZEPHYR_DRIVERS_PSCI_PSCI_H_ +#define ZEPHYR_DRIVERS_PSCI_PSCI_H_ + +#include + +#ifdef CONFIG_64BIT +#define PSCI_FN_NATIVE(version, name) PSCI_##version##_FN64_##name +#else +#define PSCI_FN_NATIVE(version, name) PSCI_##version##_FN_##name +#endif + +/* PSCI v0.2 interface */ +#define PSCI_0_2_FN_BASE 0x84000000 +#define PSCI_0_2_FN(n) (PSCI_0_2_FN_BASE + (n)) +#define PSCI_0_2_64BIT 0x40000000 +#define PSCI_0_2_FN64_BASE \ + (PSCI_0_2_FN_BASE + PSCI_0_2_64BIT) +#define PSCI_0_2_FN64(n) (PSCI_0_2_FN64_BASE + (n)) + +#define PSCI_0_2_FN_PSCI_VERSION PSCI_0_2_FN(0) +#define PSCI_0_2_FN_CPU_SUSPEND PSCI_0_2_FN(1) +#define PSCI_0_2_FN_CPU_OFF PSCI_0_2_FN(2) +#define PSCI_0_2_FN_CPU_ON PSCI_0_2_FN(3) +#define PSCI_0_2_FN_AFFINITY_INFO PSCI_0_2_FN(4) +#define PSCI_0_2_FN_MIGRATE PSCI_0_2_FN(5) +#define PSCI_0_2_FN_MIGRATE_INFO_TYPE PSCI_0_2_FN(6) +#define PSCI_0_2_FN_MIGRATE_INFO_UP_CPU PSCI_0_2_FN(7) +#define PSCI_0_2_FN_SYSTEM_OFF PSCI_0_2_FN(8) +#define PSCI_0_2_FN_SYSTEM_RESET PSCI_0_2_FN(9) + +#define PSCI_0_2_FN64_CPU_SUSPEND PSCI_0_2_FN64(1) +#define PSCI_0_2_FN64_CPU_ON PSCI_0_2_FN64(3) +#define PSCI_0_2_FN64_AFFINITY_INFO PSCI_0_2_FN64(4) +#define PSCI_0_2_FN64_MIGRATE PSCI_0_2_FN64(5) +#define PSCI_0_2_FN64_MIGRATE_INFO_UP_CPU PSCI_0_2_FN64(7) + +/* PSCI return values (inclusive of all PSCI versions) */ +#define PSCI_RET_SUCCESS 0 +#define PSCI_RET_NOT_SUPPORTED -1 +#define PSCI_RET_INVALID_PARAMS -2 +#define PSCI_RET_DENIED -3 +#define PSCI_RET_ALREADY_ON -4 +#define PSCI_RET_ON_PENDING -5 +#define PSCI_RET_INTERNAL_FAILURE -6 +#define PSCI_RET_NOT_PRESENT -7 +#define PSCI_RET_DISABLED -8 +#define PSCI_RET_INVALID_ADDRESS -9 + +typedef unsigned long (psci_fn)(unsigned long, unsigned long, + unsigned long, unsigned long); + +struct psci { + psci_fn *invoke_psci_fn; + enum arm_smccc_conduit conduit; +}; + +#endif /* ZEPHYR_DRIVERS_PSCI_PSCI_H_ */ diff --git a/drivers/psci/psci_handlers.c b/drivers/psci/psci_handlers.c new file mode 100644 index 00000000000000..9149889049b210 --- /dev/null +++ b/drivers/psci/psci_handlers.c @@ -0,0 +1,45 @@ +/* + * Copyright 2020 Carlo Caione + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include +#include + +static inline uint32_t z_vrfy_psci_get_version(const struct device *dev) +{ + Z_OOPS(Z_SYSCALL_DRIVER_PSCI(dev, get_version)); + + return z_impl_psci_get_version(dev); +} +#include + +static inline int z_vrfy_psci_cpu_off(const struct device *dev, uint32_t state) +{ + Z_OOPS(Z_SYSCALL_DRIVER_PSCI(dev, cpu_off)); + + return z_impl_psci_cpu_off(dev, state); +} +#include + +static inline int z_vrfy_psci_cpu_on(const struct device *dev, + unsigned long cpuid, + unsigned long entry_point) { + Z_OOPS(Z_SYSCALL_DRIVER_PSCI(dev, cpu_on)); + + return z_impl_psci_cpu_on(dev, cpuid, entry_point); +} +#include + +static inline int z_vrfy_psci_affinity_info(const struct device *dev, + unsigned long target_affinity, + unsigned long lowest_affinity_level) +{ + Z_OOPS(Z_SYSCALL_DRIVER_PSCI(dev, affinity_info)); + + return z_impl_psci_affinity_info(dev, target_affinity, + lowest_affinity_level); +} +#include diff --git a/dts/bindings/psci/arm,psci.yaml b/dts/bindings/psci/arm,psci.yaml new file mode 100644 index 00000000000000..3f82067466a91c --- /dev/null +++ b/dts/bindings/psci/arm,psci.yaml @@ -0,0 +1,20 @@ +# Copyright (c) 2020 Carlo Caione +# SPDX-License-Identifier: Apache-2.0 + +description: PSCI + +compatible: "arm,psci-0.2" + +include: base.yaml + +properties: + label: + required: true + + method: + type: string + required: true + description: The method of calling the PSCI firmware. + enum: + - smc + - hvc diff --git a/include/arch/arm/arm-smccc.h b/include/arch/arm/arm-smccc.h new file mode 100644 index 00000000000000..90b5f42cf7fee2 --- /dev/null +++ b/include/arch/arm/arm-smccc.h @@ -0,0 +1,53 @@ +/* + * Copyright 2020 Carlo Caione + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef ZEPHYR_INCLUDE_ARCH_ARM_ARM_SMCCC_H_ +#define ZEPHYR_INCLUDE_ARCH_ARM_ARM_SMCCC_H_ + +/* + * Result from SMC/HVC call + * @a0-a3 result values from registers 0 to 3 + */ +struct arm_smccc_res { + unsigned long a0; + unsigned long a1; + unsigned long a2; + unsigned long a3; +}; + +enum arm_smccc_conduit { + SMCCC_CONDUIT_NONE, + SMCCC_CONDUIT_SMC, + SMCCC_CONDUIT_HVC, +}; + +/* + * @brief Make HVC calls + * + * @param a0 function identifier + * @param a1-a7 parameters registers + * @param res results + */ +void arm_smccc_hvc(unsigned long a0, unsigned long a1, + unsigned long a2, unsigned long a3, + unsigned long a4, unsigned long a5, + unsigned long a6, unsigned long a7, + struct arm_smccc_res *res); + +/* + * @brief Make SMC calls + * + * @param a0 function identifier + * @param a1-a7 parameters registers + * @param res results + */ +void arm_smccc_smc(unsigned long a0, unsigned long a1, + unsigned long a2, unsigned long a3, + unsigned long a4, unsigned long a5, + unsigned long a6, unsigned long a7, + struct arm_smccc_res *res); + +#endif /* ZEPHYR_INCLUDE_ARCH_ARM_ARM_SMCCC_H_ */ diff --git a/include/drivers/psci.h b/include/drivers/psci.h new file mode 100644 index 00000000000000..10dfc5c20cfa50 --- /dev/null +++ b/include/drivers/psci.h @@ -0,0 +1,160 @@ +/* + * Copyright 2020 Carlo Caione + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef ZEPHYR_INCLUDE_DRIVERS_PSCI_H_ +#define ZEPHYR_INCLUDE_DRIVERS_PSCI_H_ + +/** + * @file + * @brief Public API for ARM PSCI + */ + +#include +#include +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/* PSCI version decoding (independent of PSCI version) */ +#define PSCI_VERSION_MAJOR_SHIFT 16 +#define PSCI_VERSION_MINOR_MASK \ + ((1U << PSCI_VERSION_MAJOR_SHIFT) - 1) +#define PSCI_VERSION_MAJOR_MASK ~PSCI_VERSION_MINOR_MASK + +#define PSCI_VERSION_MAJOR(ver) \ + (((ver) & PSCI_VERSION_MAJOR_MASK) >> PSCI_VERSION_MAJOR_SHIFT) +#define PSCI_VERSION_MINOR(ver) \ + ((ver) & PSCI_VERSION_MINOR_MASK) + +/** + * @brief ARM PSCI Driver API + * @defgroup arm_psci ARM PSCI Driver API + * @{ + */ + +typedef uint32_t (*psci_get_version_f)(const struct device *dev); + +typedef int (*psci_cpu_off_f)(const struct device *dev, uint32_t state); + +typedef int (*psci_cpu_on_f)(const struct device *dev, unsigned long cpuid, + unsigned long entry_point); + +typedef int (*psci_affinity_info_f)(const struct device *dev, + unsigned long target_affinity, + unsigned long lowest_affinity_level); + +__subsystem struct psci_driver_api { + psci_get_version_f get_version; + psci_cpu_off_f cpu_off; + psci_cpu_on_f cpu_on; + psci_affinity_info_f affinity_info; +}; + +/** + * @brief Return the version of PSCI implemented + * + * @param dev Pointer to the device structure for the driver instance + * + * @return The PSCI version + */ +__syscall uint32_t psci_get_version(const struct device *dev); + +static inline uint32_t z_impl_psci_get_version(const struct device *dev) +{ + const struct psci_driver_api *api = + (const struct psci_driver_api *)dev->api; + + return api->get_version(dev); +} + +/** + * @brief Power down the calling core + * + * This call is intended foruse in hotplug. A core that is powered down by + * CPU_OFF can only be powered up again in response to a CPU_ON + * + * @param dev Pointer to the device structure for the driver instance + * @param state Not used + * + * @return The call does not return when successful + */ +__syscall int psci_cpu_off(const struct device *dev, uint32_t state); + +static inline int z_impl_psci_cpu_off(const struct device *dev, uint32_t state) +{ + const struct psci_driver_api *api = + (const struct psci_driver_api *)dev->api; + + return api->cpu_off(dev, state); +} + +/** + * @brief Power up a core + * + * This call is used to power up cores that either have not yet been booted + * into the calling supervisory software or have been previously powered down + * with a CPU_OFF call + * + * @param dev Pointer to the device structure for the driver instance + * @param cpuid This parameter contains a copy of the affinity fields of the + * MPIDR register + * @param entry_point Address at which the core must commence execution, when + * it enters the return Non-secure Exception level. + * + * @return 0 on success, a negative errno otherwise + */ +__syscall int psci_cpu_on(const struct device *dev, unsigned long cpuid, + unsigned long entry_point); + +static inline int z_impl_psci_cpu_on(const struct device *dev, + unsigned long cpuid, + unsigned long entry_point) { + const struct psci_driver_api *api = + (const struct psci_driver_api *)dev->api; + + return api->cpu_on(dev, cpuid, entry_point); +} + +/** + * @brief Enable the caller to request status of an affinity instance + * + * @param dev Pointer to the device structure for the driver instance + * @param target_affinity This parameter contains a copy of the affinity fields + * of the MPIDR register + * @param lowest_affinity_level Denotes the lowest affinity level field that is + * valid in the target_affinity parameter + * + * @return 2 if the affinity instance is transitioning to an ON sate, 1 off, 0 + * on, a negative errno otherwise + */ +__syscall int psci_affinity_info(const struct device *dev, + unsigned long target_affinity, + unsigned long lowest_affinity_level); + +static inline int z_impl_psci_affinity_info(const struct device *dev, + unsigned long target_affinity, + unsigned long lowest_affinity_level) +{ + const struct psci_driver_api *api = + (const struct psci_driver_api *)dev->api; + + return api->affinity_info(dev, target_affinity, lowest_affinity_level); +} + +#ifdef __cplusplus +} +#endif + +/** + * @} + */ + +#include + +#endif /* ZEPHYR_INCLUDE_DRIVERS_PSCI_H_ */ From 7b0835100609f9791decfc229ce9dd39e9aa0fc7 Mon Sep 17 00:00:00 2001 From: Carlo Caione Date: Sat, 19 Dec 2020 15:52:54 +0100 Subject: [PATCH 2/2] tests: psci: Introduce PSCI test Add a simple test to the the PSCI driver Signed-off-by: Carlo Caione --- tests/arch/arm/arm_psci/CMakeLists.txt | 12 +++++++ tests/arch/arm/arm_psci/prj.conf | 2 ++ tests/arch/arm/arm_psci/src/main.c | 46 ++++++++++++++++++++++++++ tests/arch/arm/arm_psci/testcase.yaml | 5 +++ 4 files changed, 65 insertions(+) create mode 100644 tests/arch/arm/arm_psci/CMakeLists.txt create mode 100644 tests/arch/arm/arm_psci/prj.conf create mode 100644 tests/arch/arm/arm_psci/src/main.c create mode 100644 tests/arch/arm/arm_psci/testcase.yaml diff --git a/tests/arch/arm/arm_psci/CMakeLists.txt b/tests/arch/arm/arm_psci/CMakeLists.txt new file mode 100644 index 00000000000000..ef6532fa189005 --- /dev/null +++ b/tests/arch/arm/arm_psci/CMakeLists.txt @@ -0,0 +1,12 @@ +# SPDX-License-Identifier: Apache-2.0 + +cmake_minimum_required(VERSION 3.13.1) + +find_package(Zephyr REQUIRED HINTS $ENV{ZEPHYR_BASE}) +project(arm_psci) + +FILE(GLOB app_sources src/*.c) +target_sources(app PRIVATE ${app_sources}) +target_include_directories(app PRIVATE + ${ARCH_DIR}/${ARCH}/include +) diff --git a/tests/arch/arm/arm_psci/prj.conf b/tests/arch/arm/arm_psci/prj.conf new file mode 100644 index 00000000000000..232de93ca9d5ee --- /dev/null +++ b/tests/arch/arm/arm_psci/prj.conf @@ -0,0 +1,2 @@ +CONFIG_TEST_USERSPACE=y +CONFIG_ZTEST=y diff --git a/tests/arch/arm/arm_psci/src/main.c b/tests/arch/arm/arm_psci/src/main.c new file mode 100644 index 00000000000000..932260772da4ba --- /dev/null +++ b/tests/arch/arm/arm_psci/src/main.c @@ -0,0 +1,46 @@ +/* + * Copyright (c) 2020 Carlo Caione + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include + +#define PSCI_DEV_NAME "PSCI" + +void test_psci_func(void) +{ + const struct device *psci; + uint32_t ver; + int ret; + + psci = device_get_binding(PSCI_DEV_NAME); + zassert_not_null(psci, "Could not get psci device"); + + /* This should return 2 for v0.2 */ + ver = psci_get_version(psci); + zassert_false((PSCI_VERSION_MAJOR(ver) == 0 && + PSCI_VERSION_MINOR(ver) < 2), + "Wrong PSCI firware version"); + + /* This should return 0: (one core in the affinity instance is ON) */ + ret = psci_affinity_info(psci, 0, 0); + zassert_true(ret == 0, "Wrong return code from psci_affinity_info"); + + /* This should return -PSCI_RET_ALREADY_ON that is mapped to -EINVAL */ + ret = psci_cpu_on(psci, 0, 0); + zassert_true(ret == -EINVAL, "Wrong return code from psci_cpu_on"); +} + +void test_main(void) +{ + const struct device *psci = device_get_binding(PSCI_DEV_NAME); + zassert_not_null(psci, "Could not get psci device"); + + k_object_access_grant(psci, k_current_get()); + + ztest_test_suite(psci_func, + ztest_user_unit_test(test_psci_func)); + ztest_run_test_suite(psci_func); +} diff --git a/tests/arch/arm/arm_psci/testcase.yaml b/tests/arch/arm/arm_psci/testcase.yaml new file mode 100644 index 00000000000000..8be71bd3a2d0a2 --- /dev/null +++ b/tests/arch/arm/arm_psci/testcase.yaml @@ -0,0 +1,5 @@ +tests: + arch.arm64.psci: + arch_allow: arm + tags: arm psci drivers userspace + filter: CONFIG_ARM_PSCI