diff --git a/core/arch/arm/plat-stm32mp2/stm32mp_pm.c b/core/arch/arm/plat-stm32mp2/stm32mp_pm.c new file mode 100644 index 00000000000..e93ca15de72 --- /dev/null +++ b/core/arch/arm/plat-stm32mp2/stm32mp_pm.c @@ -0,0 +1,98 @@ +// SPDX-License-Identifier: BSD-2-Clause +/* + * Copyright (c) 2023, STMicroelectronics + */ + +#include +#include +#include +#include +#include + +/** + * @brief Handler for system off + * + * @param[in] a0 Unused + * @param[in] a1 Unused + * + * @retval 0 if OK, other value else and TF-A will panic + */ +unsigned long thread_system_off_handler(unsigned long a0 __unused, + unsigned long a1 __unused) +{ + /* + * configure targeted mode in PMIC for system OFF, + * no need to save context + */ + uint32_t pm_hint = PM_HINT_CLOCK_STATE | + ((PM_MAX_LEVEL << PM_HINT_PLATFORM_STATE_SHIFT) & + PM_HINT_PLATFORM_STATE_MASK); + + return pm_change_state(PM_OP_SUSPEND, pm_hint); +} + +static uint32_t get_pm_hint(unsigned long a0) +{ + uint32_t pm_hint = 0U; + + /* a0 is the highest power level which was powered down. */ + if (a0 < PM_D2_LPLV_LEVEL) + pm_hint = PM_HINT_CLOCK_STATE; + else + pm_hint = PM_HINT_CONTEXT_STATE; + + pm_hint |= ((a0 << PM_HINT_PLATFORM_STATE_SHIFT) & + PM_HINT_PLATFORM_STATE_MASK); + + return pm_hint; +} + +/** + * @brief Handler for cpu resume + * + * @param[in] a0 Max power level powered down + * @param[in] a1 Unused + * + * @retval 0 if OK, other value else and TF-A will panic + */ +unsigned long thread_cpu_resume_handler(unsigned long a0, + unsigned long a1 __unused) +{ + TEE_Result retstatus = TEE_SUCCESS; + + retstatus = pm_change_state(PM_OP_RESUME, get_pm_hint(a0)); + + /* + * Returned value to the TF-A. + * If it is not 0, the system will panic + */ + if (retstatus == TEE_SUCCESS) + return 0; + else + return 1; +} + +/** + * @brief Handler for cpu suspend + * + * @param[in] a0 Max power level to power down + * @param[in] a1 Unused + * + * @retval 0 if OK, other value else and TF-A will panic + */ +unsigned long thread_cpu_suspend_handler(unsigned long a0, + unsigned long a1 __unused) +{ + TEE_Result retstatus = TEE_SUCCESS; + + retstatus = pm_change_state(PM_OP_SUSPEND, get_pm_hint(a0)); + + /* + * Returned value to the TF-A. + * If it is not 0, the system will panic + */ + if (retstatus == TEE_SUCCESS) + return 0; + else + return 1; +} diff --git a/core/arch/arm/plat-stm32mp2/stm32mp_pm.h b/core/arch/arm/plat-stm32mp2/stm32mp_pm.h new file mode 100644 index 00000000000..45fec094005 --- /dev/null +++ b/core/arch/arm/plat-stm32mp2/stm32mp_pm.h @@ -0,0 +1,35 @@ +/* SPDX-License-Identifier: BSD-2-Clause */ +/* + * Copyright (c) 2023, STMicroelectronics + */ + +#ifndef __STM32MP_PM_H__ +#define __STM32MP_PM_H__ + +/* + * The PSCI topology is defined in TF-A, with 5 power levels supported in + * the first parameter a0="Max power level powered down" of TF-A SPD hooks + * + * power level (associated low power mode for a0) + * 0: CPU1 core#0 or core#1 (Stop1 or LP-Stop1) + * 1: D1 domain (LPLV-Stop1) + * 2: LPLV D1 (Stop2 or LP-Stop2) + * 3: D2 (LPLV-Stop1) + * 4: LPLV D2 (Standby) + * 5: MAX (PowerOff) + * + * these power level are only managed in power driver (PMIC), for pm function + * use the 2 associated parameters: + * - PM_HINT_CONTEXT_STATE : advertise driver to save all their context in DDR + * (self refresh) for standby mode + * - PM_HINT_CLOCK_STATE : advertise driver to interrupt operation when clock + * are stalled for the other low power modes + */ +#define PM_CORE_LEVEL 0 +#define PM_D1_LEVEL 1 +#define PM_D1_LPLV_LEVEL 2 +#define PM_D2_LEVEL 3 +#define PM_D2_LPLV_LEVEL 4 +#define PM_MAX_LEVEL 5 + +#endif /*__STM32MP_PM_H__*/ diff --git a/core/arch/arm/plat-stm32mp2/sub.mk b/core/arch/arm/plat-stm32mp2/sub.mk index b5d5551e7f4..9d15798f890 100644 --- a/core/arch/arm/plat-stm32mp2/sub.mk +++ b/core/arch/arm/plat-stm32mp2/sub.mk @@ -1,3 +1,4 @@ global-incdirs-y += . srcs-y += main.c +srcs-y += stm32mp_pm.c