From ebca2a6ee161502828de017b28a8f1d7422073f0 Mon Sep 17 00:00:00 2001 From: Dmitry Osipenko Date: Mon, 18 Mar 2019 01:52:04 +0300 Subject: ARM: trusted_foundations: Support L2 cache maintenance Implement L2 cache initialization firmware callback that should be invoked early during boot in order to set up the required outer cache driver's callbacks and add the callback required for L2X0 maintenance. Partially based on work done by Michał Mirosław [1]. [1] https://www.spinics.net/lists/arm-kernel/msg594765.html Tested-by: Robert Yang Tested-by: Michał Mirosław Signed-off-by: Michał Mirosław Signed-off-by: Dmitry Osipenko Signed-off-by: Thierry Reding --- arch/arm/include/asm/trusted_foundations.h | 10 ++++++++++ 1 file changed, 10 insertions(+) (limited to 'arch/arm/include') diff --git a/arch/arm/include/asm/trusted_foundations.h b/arch/arm/include/asm/trusted_foundations.h index 00748350cf72..9e6a41e9215e 100644 --- a/arch/arm/include/asm/trusted_foundations.h +++ b/arch/arm/include/asm/trusted_foundations.h @@ -32,6 +32,9 @@ #include #include +#include +#include + struct trusted_foundations_platform_data { unsigned int version_major; unsigned int version_minor; @@ -43,6 +46,9 @@ void register_trusted_foundations(struct trusted_foundations_platform_data *pd); void of_register_trusted_foundations(void); #else /* CONFIG_TRUSTED_FOUNDATIONS */ +static inline void tf_dummy_write_sec(unsigned long val, unsigned int reg) +{ +} static inline void register_trusted_foundations( struct trusted_foundations_platform_data *pd) @@ -53,6 +59,10 @@ static inline void register_trusted_foundations( */ pr_err("No support for Trusted Foundations, continuing in degraded mode.\n"); pr_err("Secondary processors as well as CPU PM will be disabled.\n"); +#if IS_ENABLED(CONFIG_CACHE_L2X0) + pr_err("L2X0 cache will be kept disabled.\n"); + outer_cache.write_sec = tf_dummy_write_sec; +#endif #if IS_ENABLED(CONFIG_SMP) setup_max_cpus = 0; #endif -- cgit v1.2.3 From 96446e21d6e9303cce0374af3f4012556dc501ce Mon Sep 17 00:00:00 2001 From: Dmitry Osipenko Date: Mon, 18 Mar 2019 01:52:05 +0300 Subject: ARM: trusted_foundations: Make prepare_idle call to take mode argument The Trusted Foundations firmware call varies depending on the required suspend-mode. Make the firmware API to take the mode argument in order to expose all of the modes to firmware user. Tested-by: Robert Yang Tested-by: Michał Mirosław Signed-off-by: Dmitry Osipenko Signed-off-by: Thierry Reding --- arch/arm/firmware/trusted_foundations.c | 29 +++++++++++++++++++++++++++-- arch/arm/include/asm/firmware.h | 2 +- arch/arm/include/asm/trusted_foundations.h | 6 ++++++ arch/arm/mach-tegra/cpuidle-tegra114.c | 3 ++- 4 files changed, 36 insertions(+), 4 deletions(-) (limited to 'arch/arm/include') diff --git a/arch/arm/firmware/trusted_foundations.c b/arch/arm/firmware/trusted_foundations.c index d7ac05103a52..720904a43c00 100644 --- a/arch/arm/firmware/trusted_foundations.c +++ b/arch/arm/firmware/trusted_foundations.c @@ -67,9 +67,34 @@ static int tf_set_cpu_boot_addr(int cpu, unsigned long boot_addr) return 0; } -static int tf_prepare_idle(void) +static int tf_prepare_idle(unsigned long mode) { - tf_generic_smc(TF_CPU_PM, TF_CPU_PM_S1_NOFLUSH_L2, cpu_boot_addr); + switch (mode) { + case TF_PM_MODE_LP0: + tf_generic_smc(TF_CPU_PM, TF_CPU_PM_S3, cpu_boot_addr); + break; + + case TF_PM_MODE_LP1: + tf_generic_smc(TF_CPU_PM, TF_CPU_PM_S2, cpu_boot_addr); + break; + + case TF_PM_MODE_LP1_NO_MC_CLK: + tf_generic_smc(TF_CPU_PM, TF_CPU_PM_S2_NO_MC_CLK, + cpu_boot_addr); + break; + + case TF_PM_MODE_LP2: + tf_generic_smc(TF_CPU_PM, TF_CPU_PM_S1, cpu_boot_addr); + break; + + case TF_PM_MODE_LP2_NOFLUSH_L2: + tf_generic_smc(TF_CPU_PM, TF_CPU_PM_S1_NOFLUSH_L2, + cpu_boot_addr); + break; + + default: + return -EINVAL; + } return 0; } diff --git a/arch/arm/include/asm/firmware.h b/arch/arm/include/asm/firmware.h index 34c1d96ef46d..6698272bbcbf 100644 --- a/arch/arm/include/asm/firmware.h +++ b/arch/arm/include/asm/firmware.h @@ -24,7 +24,7 @@ struct firmware_ops { /* * Inform the firmware we intend to enter CPU idle mode */ - int (*prepare_idle)(void); + int (*prepare_idle)(unsigned long mode); /* * Enters CPU idle mode */ diff --git a/arch/arm/include/asm/trusted_foundations.h b/arch/arm/include/asm/trusted_foundations.h index 9e6a41e9215e..201ceb259e71 100644 --- a/arch/arm/include/asm/trusted_foundations.h +++ b/arch/arm/include/asm/trusted_foundations.h @@ -35,6 +35,12 @@ #include #include +#define TF_PM_MODE_LP0 0 +#define TF_PM_MODE_LP1 1 +#define TF_PM_MODE_LP1_NO_MC_CLK 2 +#define TF_PM_MODE_LP2 3 +#define TF_PM_MODE_LP2_NOFLUSH_L2 4 + struct trusted_foundations_platform_data { unsigned int version_major; unsigned int version_minor; diff --git a/arch/arm/mach-tegra/cpuidle-tegra114.c b/arch/arm/mach-tegra/cpuidle-tegra114.c index e3fbcfedf845..3b9af4766cdf 100644 --- a/arch/arm/mach-tegra/cpuidle-tegra114.c +++ b/arch/arm/mach-tegra/cpuidle-tegra114.c @@ -24,6 +24,7 @@ #include #include #include +#include #include #include "cpuidle.h" @@ -46,7 +47,7 @@ static int tegra114_idle_power_down(struct cpuidle_device *dev, tegra_set_cpu_in_lp2(); cpu_pm_enter(); - call_firmware_op(prepare_idle); + call_firmware_op(prepare_idle, TF_PM_MODE_LP2_NOFLUSH_L2); /* Do suspend by ourselves if the firmware does not implement it */ if (call_firmware_op(do_idle, 0) == -ENOSYS) -- cgit v1.2.3 From ebc7c1a26578683a4d12ab3434a92c225a97e240 Mon Sep 17 00:00:00 2001 From: Dmitry Osipenko Date: Mon, 18 Mar 2019 01:52:06 +0300 Subject: ARM: trusted_foundations: Provide information about whether firmware is registered Add a helper that provides information about whether Trusted Foundations firmware operations have been registered. Tested-by: Robert Yang Tested-by: Michał Mirosław Signed-off-by: Dmitry Osipenko Signed-off-by: Thierry Reding --- arch/arm/firmware/trusted_foundations.c | 5 +++++ arch/arm/include/asm/trusted_foundations.h | 7 +++++++ 2 files changed, 12 insertions(+) (limited to 'arch/arm/include') diff --git a/arch/arm/firmware/trusted_foundations.c b/arch/arm/firmware/trusted_foundations.c index 720904a43c00..bb2ee73d9e02 100644 --- a/arch/arm/firmware/trusted_foundations.c +++ b/arch/arm/firmware/trusted_foundations.c @@ -167,3 +167,8 @@ void of_register_trusted_foundations(void) panic("Trusted Foundation: missing version-minor property\n"); register_trusted_foundations(&pdata); } + +bool trusted_foundations_registered(void) +{ + return firmware_ops == &trusted_foundations_ops; +} diff --git a/arch/arm/include/asm/trusted_foundations.h b/arch/arm/include/asm/trusted_foundations.h index 201ceb259e71..54513c533811 100644 --- a/arch/arm/include/asm/trusted_foundations.h +++ b/arch/arm/include/asm/trusted_foundations.h @@ -31,6 +31,7 @@ #include #include #include +#include #include #include @@ -50,6 +51,7 @@ struct trusted_foundations_platform_data { void register_trusted_foundations(struct trusted_foundations_platform_data *pd); void of_register_trusted_foundations(void); +bool trusted_foundations_registered(void); #else /* CONFIG_TRUSTED_FOUNDATIONS */ static inline void tf_dummy_write_sec(unsigned long val, unsigned int reg) @@ -84,6 +86,11 @@ static inline void of_register_trusted_foundations(void) if (of_find_compatible_node(NULL, NULL, "tlm,trusted-foundations")) register_trusted_foundations(NULL); } + +static inline bool trusted_foundations_registered(void) +{ + return false; +} #endif /* CONFIG_TRUSTED_FOUNDATIONS */ #endif -- cgit v1.2.3 From 4cb5d9eca143f7fbf8cc457be19a91914f978a00 Mon Sep 17 00:00:00 2001 From: Thierry Reding Date: Wed, 10 Apr 2019 10:47:28 +0200 Subject: firmware: Move Trusted Foundations support Move the Trusted Foundations support out of arch/arm/firmware and into drivers/firmware where most other firmware support implementations are located. Signed-off-by: Thierry Reding --- arch/arm/Kconfig | 2 - arch/arm/Makefile | 1 - arch/arm/firmware/Kconfig | 29 ----- arch/arm/firmware/Makefile | 4 - arch/arm/firmware/trusted_foundations.c | 174 -------------------------- arch/arm/include/asm/trusted_foundations.h | 96 --------------- arch/arm/mach-tegra/Kconfig | 1 - arch/arm/mach-tegra/cpuidle-tegra114.c | 3 +- arch/arm/mach-tegra/pm.c | 3 +- arch/arm/mach-tegra/reset.c | 3 +- arch/arm/mach-tegra/tegra.c | 3 +- drivers/firmware/Kconfig | 16 +++ drivers/firmware/Makefile | 1 + drivers/firmware/trusted_foundations.c | 176 +++++++++++++++++++++++++++ include/linux/firmware/trusted_foundations.h | 96 +++++++++++++++ 15 files changed, 297 insertions(+), 311 deletions(-) delete mode 100644 arch/arm/firmware/Kconfig delete mode 100644 arch/arm/firmware/Makefile delete mode 100644 arch/arm/firmware/trusted_foundations.c delete mode 100644 arch/arm/include/asm/trusted_foundations.h create mode 100644 drivers/firmware/trusted_foundations.c create mode 100644 include/linux/firmware/trusted_foundations.h (limited to 'arch/arm/include') diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig index 054ead960f98..f006b3c69247 100644 --- a/arch/arm/Kconfig +++ b/arch/arm/Kconfig @@ -899,8 +899,6 @@ config PLAT_PXA config PLAT_VERSATILE bool -source "arch/arm/firmware/Kconfig" - source "arch/arm/mm/Kconfig" config IWMMXT diff --git a/arch/arm/Makefile b/arch/arm/Makefile index 807a7d06c2a0..05ecc004de86 100644 --- a/arch/arm/Makefile +++ b/arch/arm/Makefile @@ -290,7 +290,6 @@ core-y += arch/arm/kernel/ arch/arm/mm/ arch/arm/common/ core-y += arch/arm/probes/ core-y += arch/arm/net/ core-y += arch/arm/crypto/ -core-y += arch/arm/firmware/ core-y += $(machdirs) $(platdirs) drivers-$(CONFIG_OPROFILE) += arch/arm/oprofile/ diff --git a/arch/arm/firmware/Kconfig b/arch/arm/firmware/Kconfig deleted file mode 100644 index ad396af68e47..000000000000 --- a/arch/arm/firmware/Kconfig +++ /dev/null @@ -1,29 +0,0 @@ -config ARCH_SUPPORTS_FIRMWARE - bool - -config ARCH_SUPPORTS_TRUSTED_FOUNDATIONS - bool - select ARCH_SUPPORTS_FIRMWARE - -menu "Firmware options" - depends on ARCH_SUPPORTS_FIRMWARE - -config TRUSTED_FOUNDATIONS - bool "Trusted Foundations secure monitor support" - depends on ARCH_SUPPORTS_TRUSTED_FOUNDATIONS - default y - help - Some devices (including most Tegra-based consumer devices on the - market) are booted with the Trusted Foundations secure monitor - active, requiring some core operations to be performed by the secure - monitor instead of the kernel. - - This option allows the kernel to invoke the secure monitor whenever - required on devices using Trusted Foundations. See - arch/arm/include/asm/trusted_foundations.h or the - tlm,trusted-foundations device tree binding documentation for details - on how to use it. - - Say n if you don't know what this is about. - -endmenu diff --git a/arch/arm/firmware/Makefile b/arch/arm/firmware/Makefile deleted file mode 100644 index 6e41336b0bc4..000000000000 --- a/arch/arm/firmware/Makefile +++ /dev/null @@ -1,4 +0,0 @@ -obj-$(CONFIG_TRUSTED_FOUNDATIONS) += trusted_foundations.o - -# tf_generic_smc() fails to build with -fsanitize-coverage=trace-pc -KCOV_INSTRUMENT := n diff --git a/arch/arm/firmware/trusted_foundations.c b/arch/arm/firmware/trusted_foundations.c deleted file mode 100644 index bb2ee73d9e02..000000000000 --- a/arch/arm/firmware/trusted_foundations.c +++ /dev/null @@ -1,174 +0,0 @@ -/* - * Trusted Foundations support for ARM CPUs - * - * Copyright (c) 2013, NVIDIA Corporation. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - */ - -#include -#include -#include -#include -#include -#include -#include - -#define TF_CACHE_MAINT 0xfffff100 - -#define TF_CACHE_ENABLE 1 -#define TF_CACHE_DISABLE 2 - -#define TF_SET_CPU_BOOT_ADDR_SMC 0xfffff200 - -#define TF_CPU_PM 0xfffffffc -#define TF_CPU_PM_S3 0xffffffe3 -#define TF_CPU_PM_S2 0xffffffe6 -#define TF_CPU_PM_S2_NO_MC_CLK 0xffffffe5 -#define TF_CPU_PM_S1 0xffffffe4 -#define TF_CPU_PM_S1_NOFLUSH_L2 0xffffffe7 - -static unsigned long cpu_boot_addr; - -static void tf_generic_smc(u32 type, u32 arg1, u32 arg2) -{ - register u32 r0 asm("r0") = type; - register u32 r1 asm("r1") = arg1; - register u32 r2 asm("r2") = arg2; - - asm volatile( - ".arch_extension sec\n\t" - "stmfd sp!, {r4 - r11}\n\t" - __asmeq("%0", "r0") - __asmeq("%1", "r1") - __asmeq("%2", "r2") - "mov r3, #0\n\t" - "mov r4, #0\n\t" - "smc #0\n\t" - "ldmfd sp!, {r4 - r11}\n\t" - : - : "r" (r0), "r" (r1), "r" (r2) - : "memory", "r3", "r12", "lr"); -} - -static int tf_set_cpu_boot_addr(int cpu, unsigned long boot_addr) -{ - cpu_boot_addr = boot_addr; - tf_generic_smc(TF_SET_CPU_BOOT_ADDR_SMC, cpu_boot_addr, 0); - - return 0; -} - -static int tf_prepare_idle(unsigned long mode) -{ - switch (mode) { - case TF_PM_MODE_LP0: - tf_generic_smc(TF_CPU_PM, TF_CPU_PM_S3, cpu_boot_addr); - break; - - case TF_PM_MODE_LP1: - tf_generic_smc(TF_CPU_PM, TF_CPU_PM_S2, cpu_boot_addr); - break; - - case TF_PM_MODE_LP1_NO_MC_CLK: - tf_generic_smc(TF_CPU_PM, TF_CPU_PM_S2_NO_MC_CLK, - cpu_boot_addr); - break; - - case TF_PM_MODE_LP2: - tf_generic_smc(TF_CPU_PM, TF_CPU_PM_S1, cpu_boot_addr); - break; - - case TF_PM_MODE_LP2_NOFLUSH_L2: - tf_generic_smc(TF_CPU_PM, TF_CPU_PM_S1_NOFLUSH_L2, - cpu_boot_addr); - break; - - default: - return -EINVAL; - } - - return 0; -} - -#ifdef CONFIG_CACHE_L2X0 -static void tf_cache_write_sec(unsigned long val, unsigned int reg) -{ - u32 l2x0_way_mask = 0xff; - - switch (reg) { - case L2X0_CTRL: - if (l2x0_saved_regs.aux_ctrl & L310_AUX_CTRL_ASSOCIATIVITY_16) - l2x0_way_mask = 0xffff; - - if (val == L2X0_CTRL_EN) - tf_generic_smc(TF_CACHE_MAINT, TF_CACHE_ENABLE, - l2x0_saved_regs.aux_ctrl); - else - tf_generic_smc(TF_CACHE_MAINT, TF_CACHE_DISABLE, - l2x0_way_mask); - break; - - default: - break; - } -} - -static int tf_init_cache(void) -{ - outer_cache.write_sec = tf_cache_write_sec; - - return 0; -} -#endif /* CONFIG_CACHE_L2X0 */ - -static const struct firmware_ops trusted_foundations_ops = { - .set_cpu_boot_addr = tf_set_cpu_boot_addr, - .prepare_idle = tf_prepare_idle, -#ifdef CONFIG_CACHE_L2X0 - .l2x0_init = tf_init_cache, -#endif -}; - -void register_trusted_foundations(struct trusted_foundations_platform_data *pd) -{ - /* - * we are not using version information for now since currently - * supported SMCs are compatible with all TF releases - */ - register_firmware_ops(&trusted_foundations_ops); -} - -void of_register_trusted_foundations(void) -{ - struct device_node *node; - struct trusted_foundations_platform_data pdata; - int err; - - node = of_find_compatible_node(NULL, NULL, "tlm,trusted-foundations"); - if (!node) - return; - - err = of_property_read_u32(node, "tlm,version-major", - &pdata.version_major); - if (err != 0) - panic("Trusted Foundation: missing version-major property\n"); - err = of_property_read_u32(node, "tlm,version-minor", - &pdata.version_minor); - if (err != 0) - panic("Trusted Foundation: missing version-minor property\n"); - register_trusted_foundations(&pdata); -} - -bool trusted_foundations_registered(void) -{ - return firmware_ops == &trusted_foundations_ops; -} diff --git a/arch/arm/include/asm/trusted_foundations.h b/arch/arm/include/asm/trusted_foundations.h deleted file mode 100644 index 54513c533811..000000000000 --- a/arch/arm/include/asm/trusted_foundations.h +++ /dev/null @@ -1,96 +0,0 @@ -/* - * Copyright (c) 2013, NVIDIA Corporation. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - */ - -/* - * Support for the Trusted Foundations secure monitor. - * - * Trusted Foundation comes active on some ARM consumer devices (most - * Tegra-based devices sold on the market are concerned). Such devices can only - * perform some basic operations, like setting the CPU reset vector, through - * SMC calls to the secure monitor. The calls are completely specific to - * Trusted Foundations, and do *not* follow the SMC calling convention or the - * PSCI standard. - */ - -#ifndef __ASM_ARM_TRUSTED_FOUNDATIONS_H -#define __ASM_ARM_TRUSTED_FOUNDATIONS_H - -#include -#include -#include -#include -#include -#include - -#include -#include - -#define TF_PM_MODE_LP0 0 -#define TF_PM_MODE_LP1 1 -#define TF_PM_MODE_LP1_NO_MC_CLK 2 -#define TF_PM_MODE_LP2 3 -#define TF_PM_MODE_LP2_NOFLUSH_L2 4 - -struct trusted_foundations_platform_data { - unsigned int version_major; - unsigned int version_minor; -}; - -#if IS_ENABLED(CONFIG_TRUSTED_FOUNDATIONS) - -void register_trusted_foundations(struct trusted_foundations_platform_data *pd); -void of_register_trusted_foundations(void); -bool trusted_foundations_registered(void); - -#else /* CONFIG_TRUSTED_FOUNDATIONS */ -static inline void tf_dummy_write_sec(unsigned long val, unsigned int reg) -{ -} - -static inline void register_trusted_foundations( - struct trusted_foundations_platform_data *pd) -{ - /* - * If the system requires TF and we cannot provide it, continue booting - * but disable features that cannot be provided. - */ - pr_err("No support for Trusted Foundations, continuing in degraded mode.\n"); - pr_err("Secondary processors as well as CPU PM will be disabled.\n"); -#if IS_ENABLED(CONFIG_CACHE_L2X0) - pr_err("L2X0 cache will be kept disabled.\n"); - outer_cache.write_sec = tf_dummy_write_sec; -#endif -#if IS_ENABLED(CONFIG_SMP) - setup_max_cpus = 0; -#endif - cpu_idle_poll_ctrl(true); -} - -static inline void of_register_trusted_foundations(void) -{ - /* - * If we find the target should enable TF but does not support it, - * fail as the system won't be able to do much anyway - */ - if (of_find_compatible_node(NULL, NULL, "tlm,trusted-foundations")) - register_trusted_foundations(NULL); -} - -static inline bool trusted_foundations_registered(void) -{ - return false; -} -#endif /* CONFIG_TRUSTED_FOUNDATIONS */ - -#endif diff --git a/arch/arm/mach-tegra/Kconfig b/arch/arm/mach-tegra/Kconfig index 7b3fd0995a16..63e89e75639b 100644 --- a/arch/arm/mach-tegra/Kconfig +++ b/arch/arm/mach-tegra/Kconfig @@ -3,7 +3,6 @@ menuconfig ARCH_TEGRA bool "NVIDIA Tegra" depends on ARCH_MULTI_V7 select ARCH_HAS_RESET_CONTROLLER - select ARCH_SUPPORTS_TRUSTED_FOUNDATIONS select ARM_AMBA select ARM_GIC select CLKSRC_MMIO diff --git a/arch/arm/mach-tegra/cpuidle-tegra114.c b/arch/arm/mach-tegra/cpuidle-tegra114.c index 3b9af4766cdf..43c695d83f03 100644 --- a/arch/arm/mach-tegra/cpuidle-tegra114.c +++ b/arch/arm/mach-tegra/cpuidle-tegra114.c @@ -21,10 +21,11 @@ #include #include +#include + #include #include #include -#include #include #include "cpuidle.h" diff --git a/arch/arm/mach-tegra/pm.c b/arch/arm/mach-tegra/pm.c index abf5f88778f4..1b0ade06f204 100644 --- a/arch/arm/mach-tegra/pm.c +++ b/arch/arm/mach-tegra/pm.c @@ -27,6 +27,8 @@ #include #include +#include + #include #include #include @@ -39,7 +41,6 @@ #include #include #include -#include #include "iomap.h" #include "pm.h" diff --git a/arch/arm/mach-tegra/reset.c b/arch/arm/mach-tegra/reset.c index b02ae7699842..35dc5d419b6f 100644 --- a/arch/arm/mach-tegra/reset.c +++ b/arch/arm/mach-tegra/reset.c @@ -19,12 +19,13 @@ #include #include +#include + #include #include #include #include -#include #include "iomap.h" #include "irammap.h" diff --git a/arch/arm/mach-tegra/tegra.c b/arch/arm/mach-tegra/tegra.c index 1e89cfefbf68..3e88f67dd521 100644 --- a/arch/arm/mach-tegra/tegra.c +++ b/arch/arm/mach-tegra/tegra.c @@ -35,6 +35,8 @@ #include #include +#include + #include #include @@ -44,7 +46,6 @@ #include #include #include -#include #include "board.h" #include "common.h" diff --git a/drivers/firmware/Kconfig b/drivers/firmware/Kconfig index cac16c4b0df3..f0646ac75868 100644 --- a/drivers/firmware/Kconfig +++ b/drivers/firmware/Kconfig @@ -267,6 +267,22 @@ config TI_SCI_PROTOCOL This protocol library is used by client drivers to use the features provided by the system controller. +config TRUSTED_FOUNDATIONS + bool "Trusted Foundations secure monitor support" + depends on ARM + help + Some devices (including most early Tegra-based consumer devices on + the market) are booted with the Trusted Foundations secure monitor + active, requiring some core operations to be performed by the secure + monitor instead of the kernel. + + This option allows the kernel to invoke the secure monitor whenever + required on devices using Trusted Foundations. See the functions and + comments in linux/firmware/trusted_foundations.h or the device tree + bindings for "tlm,trusted-foundations" for details on how to use it. + + Choose N if you don't know what this is about. + config HAVE_ARM_SMCCC bool diff --git a/drivers/firmware/Makefile b/drivers/firmware/Makefile index 80feb635120f..745f4907e69b 100644 --- a/drivers/firmware/Makefile +++ b/drivers/firmware/Makefile @@ -23,6 +23,7 @@ obj-$(CONFIG_QCOM_SCM_64) += qcom_scm-64.o obj-$(CONFIG_QCOM_SCM_32) += qcom_scm-32.o CFLAGS_qcom_scm-32.o :=$(call as-instr,.arch armv7-a\n.arch_extension sec,-DREQUIRES_SEC=1) -march=armv7-a obj-$(CONFIG_TI_SCI_PROTOCOL) += ti_sci.o +obj-$(CONFIG_TRUSTED_FOUNDATIONS) += trusted_foundations.o obj-$(CONFIG_ARM_SCMI_PROTOCOL) += arm_scmi/ obj-y += broadcom/ diff --git a/drivers/firmware/trusted_foundations.c b/drivers/firmware/trusted_foundations.c new file mode 100644 index 000000000000..fd4999388ff1 --- /dev/null +++ b/drivers/firmware/trusted_foundations.c @@ -0,0 +1,176 @@ +/* + * Trusted Foundations support for ARM CPUs + * + * Copyright (c) 2013, NVIDIA Corporation. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + */ + +#include +#include +#include + +#include + +#include +#include +#include + +#define TF_CACHE_MAINT 0xfffff100 + +#define TF_CACHE_ENABLE 1 +#define TF_CACHE_DISABLE 2 + +#define TF_SET_CPU_BOOT_ADDR_SMC 0xfffff200 + +#define TF_CPU_PM 0xfffffffc +#define TF_CPU_PM_S3 0xffffffe3 +#define TF_CPU_PM_S2 0xffffffe6 +#define TF_CPU_PM_S2_NO_MC_CLK 0xffffffe5 +#define TF_CPU_PM_S1 0xffffffe4 +#define TF_CPU_PM_S1_NOFLUSH_L2 0xffffffe7 + +static unsigned long cpu_boot_addr; + +static void tf_generic_smc(u32 type, u32 arg1, u32 arg2) +{ + register u32 r0 asm("r0") = type; + register u32 r1 asm("r1") = arg1; + register u32 r2 asm("r2") = arg2; + + asm volatile( + ".arch_extension sec\n\t" + "stmfd sp!, {r4 - r11}\n\t" + __asmeq("%0", "r0") + __asmeq("%1", "r1") + __asmeq("%2", "r2") + "mov r3, #0\n\t" + "mov r4, #0\n\t" + "smc #0\n\t" + "ldmfd sp!, {r4 - r11}\n\t" + : + : "r" (r0), "r" (r1), "r" (r2) + : "memory", "r3", "r12", "lr"); +} + +static int tf_set_cpu_boot_addr(int cpu, unsigned long boot_addr) +{ + cpu_boot_addr = boot_addr; + tf_generic_smc(TF_SET_CPU_BOOT_ADDR_SMC, cpu_boot_addr, 0); + + return 0; +} + +static int tf_prepare_idle(unsigned long mode) +{ + switch (mode) { + case TF_PM_MODE_LP0: + tf_generic_smc(TF_CPU_PM, TF_CPU_PM_S3, cpu_boot_addr); + break; + + case TF_PM_MODE_LP1: + tf_generic_smc(TF_CPU_PM, TF_CPU_PM_S2, cpu_boot_addr); + break; + + case TF_PM_MODE_LP1_NO_MC_CLK: + tf_generic_smc(TF_CPU_PM, TF_CPU_PM_S2_NO_MC_CLK, + cpu_boot_addr); + break; + + case TF_PM_MODE_LP2: + tf_generic_smc(TF_CPU_PM, TF_CPU_PM_S1, cpu_boot_addr); + break; + + case TF_PM_MODE_LP2_NOFLUSH_L2: + tf_generic_smc(TF_CPU_PM, TF_CPU_PM_S1_NOFLUSH_L2, + cpu_boot_addr); + break; + + default: + return -EINVAL; + } + + return 0; +} + +#ifdef CONFIG_CACHE_L2X0 +static void tf_cache_write_sec(unsigned long val, unsigned int reg) +{ + u32 l2x0_way_mask = 0xff; + + switch (reg) { + case L2X0_CTRL: + if (l2x0_saved_regs.aux_ctrl & L310_AUX_CTRL_ASSOCIATIVITY_16) + l2x0_way_mask = 0xffff; + + if (val == L2X0_CTRL_EN) + tf_generic_smc(TF_CACHE_MAINT, TF_CACHE_ENABLE, + l2x0_saved_regs.aux_ctrl); + else + tf_generic_smc(TF_CACHE_MAINT, TF_CACHE_DISABLE, + l2x0_way_mask); + break; + + default: + break; + } +} + +static int tf_init_cache(void) +{ + outer_cache.write_sec = tf_cache_write_sec; + + return 0; +} +#endif /* CONFIG_CACHE_L2X0 */ + +static const struct firmware_ops trusted_foundations_ops = { + .set_cpu_boot_addr = tf_set_cpu_boot_addr, + .prepare_idle = tf_prepare_idle, +#ifdef CONFIG_CACHE_L2X0 + .l2x0_init = tf_init_cache, +#endif +}; + +void register_trusted_foundations(struct trusted_foundations_platform_data *pd) +{ + /* + * we are not using version information for now since currently + * supported SMCs are compatible with all TF releases + */ + register_firmware_ops(&trusted_foundations_ops); +} + +void of_register_trusted_foundations(void) +{ + struct device_node *node; + struct trusted_foundations_platform_data pdata; + int err; + + node = of_find_compatible_node(NULL, NULL, "tlm,trusted-foundations"); + if (!node) + return; + + err = of_property_read_u32(node, "tlm,version-major", + &pdata.version_major); + if (err != 0) + panic("Trusted Foundation: missing version-major property\n"); + err = of_property_read_u32(node, "tlm,version-minor", + &pdata.version_minor); + if (err != 0) + panic("Trusted Foundation: missing version-minor property\n"); + register_trusted_foundations(&pdata); +} + +bool trusted_foundations_registered(void) +{ + return firmware_ops == &trusted_foundations_ops; +} diff --git a/include/linux/firmware/trusted_foundations.h b/include/linux/firmware/trusted_foundations.h new file mode 100644 index 000000000000..4064e7c74715 --- /dev/null +++ b/include/linux/firmware/trusted_foundations.h @@ -0,0 +1,96 @@ +/* + * Copyright (c) 2013, NVIDIA Corporation. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + */ + +/* + * Support for the Trusted Foundations secure monitor. + * + * Trusted Foundation comes active on some ARM consumer devices (most + * Tegra-based devices sold on the market are concerned). Such devices can only + * perform some basic operations, like setting the CPU reset vector, through + * SMC calls to the secure monitor. The calls are completely specific to + * Trusted Foundations, and do *not* follow the SMC calling convention or the + * PSCI standard. + */ + +#ifndef __FIRMWARE_TRUSTED_FOUNDATIONS_H +#define __FIRMWARE_TRUSTED_FOUNDATIONS_H + +#include +#include +#include +#include +#include +#include + +#include +#include + +#define TF_PM_MODE_LP0 0 +#define TF_PM_MODE_LP1 1 +#define TF_PM_MODE_LP1_NO_MC_CLK 2 +#define TF_PM_MODE_LP2 3 +#define TF_PM_MODE_LP2_NOFLUSH_L2 4 + +struct trusted_foundations_platform_data { + unsigned int version_major; + unsigned int version_minor; +}; + +#if IS_ENABLED(CONFIG_TRUSTED_FOUNDATIONS) + +void register_trusted_foundations(struct trusted_foundations_platform_data *pd); +void of_register_trusted_foundations(void); +bool trusted_foundations_registered(void); + +#else /* CONFIG_TRUSTED_FOUNDATIONS */ +static inline void tf_dummy_write_sec(unsigned long val, unsigned int reg) +{ +} + +static inline void register_trusted_foundations( + struct trusted_foundations_platform_data *pd) +{ + /* + * If the system requires TF and we cannot provide it, continue booting + * but disable features that cannot be provided. + */ + pr_err("No support for Trusted Foundations, continuing in degraded mode.\n"); + pr_err("Secondary processors as well as CPU PM will be disabled.\n"); +#if IS_ENABLED(CONFIG_CACHE_L2X0) + pr_err("L2X0 cache will be kept disabled.\n"); + outer_cache.write_sec = tf_dummy_write_sec; +#endif +#if IS_ENABLED(CONFIG_SMP) + setup_max_cpus = 0; +#endif + cpu_idle_poll_ctrl(true); +} + +static inline void of_register_trusted_foundations(void) +{ + /* + * If we find the target should enable TF but does not support it, + * fail as the system won't be able to do much anyway + */ + if (of_find_compatible_node(NULL, NULL, "tlm,trusted-foundations")) + register_trusted_foundations(NULL); +} + +static inline bool trusted_foundations_registered(void) +{ + return false; +} +#endif /* CONFIG_TRUSTED_FOUNDATIONS */ + +#endif -- cgit v1.2.3