diff --git a/arch/arm/mach-at91/Kconfig b/arch/arm/mach-at91/Kconfig index 02f6b108fd5d0f..bb11a914ad3efa 100644 --- a/arch/arm/mach-at91/Kconfig +++ b/arch/arm/mach-at91/Kconfig @@ -201,14 +201,24 @@ config SOC_SAM_V7 config SOC_SAMA5 bool select ATMEL_AIC5_IRQ - select ATMEL_PM if PM select ATMEL_SDRAMC select MEMORY select SOC_SAM_V7 select SRAM if PM config ATMEL_PM - bool + bool "Atmel PM support" + default y if SOC_SAMA5 && PM + depends on !ATMEL_SECURE_PM + +config ATMEL_SECURE_PM + bool "Atmel Secure PM support" + depends on SOC_SAMA5D2 && PM + help + When running under a TEE, the suspend mode must be requested to be set + at TEE level. When enable, this option will use secure monitor calls + to set the suspend level. + NOTE: This support is mutually exclusive with CONFIG_ATMEL_PM config SOC_SAMA7 bool diff --git a/arch/arm/mach-at91/Makefile b/arch/arm/mach-at91/Makefile index 23620ccf7ab6c2..ebd88de8d0e780 100644 --- a/arch/arm/mach-at91/Makefile +++ b/arch/arm/mach-at91/Makefile @@ -13,6 +13,7 @@ obj-$(CONFIG_SOC_SAMV7) += samv7.o # Power Management obj-$(CONFIG_ATMEL_PM) += pm.o pm_suspend.o pm_common.o +obj-$(CONFIG_ATMEL_SECURE_PM) += pm_secure.o pm_common.o ifeq ($(CONFIG_CPU_V7),y) AFLAGS_pm_suspend.o := -march=armv7-a diff --git a/arch/arm/mach-at91/pm_secure.c b/arch/arm/mach-at91/pm_secure.c new file mode 100644 index 00000000000000..2f63ff8c6226fa --- /dev/null +++ b/arch/arm/mach-at91/pm_secure.c @@ -0,0 +1,64 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Copyright (C) 2012, Bootlin + */ + +#include +#include +#include +#include +#include "generic.h" +#include "sam_secure.h" +#include "pm.h" + +static int suspend_mode = AT91_PM_ULP0; + +static void at91_pm_secure_init(void) +{ + struct arm_smccc_res res; + + res = sam_smccc_call(SAMA5_SMC_SIP_SET_SUSPEND_MODE, suspend_mode, 0); + if (res.a0 == 0) { + pr_info("AT91: Secure PM: suspend mode set to %s\n", + pm_modes[suspend_mode].pattern); + return; + } + + pr_warn("AT91: Secure PM: %s mode not supported !\n", + pm_modes[suspend_mode].pattern); + + res = sam_smccc_call(SAMA5_SMC_SIP_GET_SUSPEND_MODE, 0, 0); + if (res.a0 == 0) { + pr_warn("AT91: Secure PM: failed to get default mode\n"); + return; + } + suspend_mode = res.a1; + + pr_info("AT91: Secure PM: using default suspend mode %s\n", + pm_modes[suspend_mode].pattern); +} + +void __init sama5_pm_init(void) +{ +} + +void __init sama5d2_pm_init(void) +{ + at91_pm_secure_init(); +} + +int at91_suspend_entering_slow_clock(void) +{ + return (suspend_mode >= AT91_PM_ULP0); +} +EXPORT_SYMBOL(at91_suspend_entering_slow_clock); + +static int __init at91_pm_modes_select(char *str) +{ + int dummy; + + pr_warn("AT91: Secure PM: ignoring standby mode\n"); + + return at91_pm_common_modes_select(str, &dummy, &suspend_mode); +} +early_param("atmel.pm_modes", at91_pm_modes_select); diff --git a/arch/arm/mach-at91/sam_secure.h b/arch/arm/mach-at91/sam_secure.h index af19e24ca59e2c..b169317f61f6c8 100644 --- a/arch/arm/mach-at91/sam_secure.h +++ b/arch/arm/mach-at91/sam_secure.h @@ -8,6 +8,10 @@ #include +/* Secure Monitor mode APIs */ +#define SAMA5_SMC_SIP_SET_SUSPEND_MODE 0x400 +#define SAMA5_SMC_SIP_GET_SUSPEND_MODE 0x401 + void __init sam_secure_init(void); struct arm_smccc_res sam_smccc_call(u32 fn, u32 arg0, u32 arg1); diff --git a/include/linux/platform_data/atmel.h b/include/linux/platform_data/atmel.h index 73f63be509c44c..cbb19712b4f0b2 100644 --- a/include/linux/platform_data/atmel.h +++ b/include/linux/platform_data/atmel.h @@ -7,7 +7,7 @@ #define __ATMEL_H__ /* FIXME: this needs a better location, but gets stuff building again */ -#ifdef CONFIG_ATMEL_PM +#if defined(CONFIG_ATMEL_PM) || defined(CONFIG_ATMEL_SECURE_PM) extern int at91_suspend_entering_slow_clock(void); #else static inline int at91_suspend_entering_slow_clock(void)