From d70f5e541ab30bf5ff29b219e9d1980e082ba159 Mon Sep 17 00:00:00 2001 From: Thierry Reding Date: Wed, 22 Apr 2020 00:00:53 +0200 Subject: [PATCH 1/4] firmware: tegra: Make BPMP a regular driver The Tegra BPMP driver typically ends up deferring probe because it wants to attach to the SMMU, so there's little sense in registering it at the core init-level. One side-effect of this is that the driver will be probed later even if it doesn't want to attach to an SMMU, which means that consumers will end up deferring probe, which in turn takes care of ordering the suspend and resume queue in the correct way. Currently since suspend/resume order depends on instantiation order, and because BPMP is listed at the very end of the device tree (after most of its consumers), the suspend and resume queue is ordered wrongly, which can cause issues for drivers (like I2C) which suspend after and resume before BPMP. In the case of I2C this typically leads to the clock failing to enable. Besides fixing this suspend/resume ordering issue, this also has the added benefit of allowing the driver to be built as a loadable module, which can help decrease the size of multiplatform kernel. Signed-off-by: Thierry Reding --- drivers/firmware/tegra/bpmp.c | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/drivers/firmware/tegra/bpmp.c b/drivers/firmware/tegra/bpmp.c index 6741fcda0c37..fe6702df24bf 100644 --- a/drivers/firmware/tegra/bpmp.c +++ b/drivers/firmware/tegra/bpmp.c @@ -6,6 +6,7 @@ #include #include #include +#include #include #include #include @@ -869,12 +870,8 @@ static struct platform_driver tegra_bpmp_driver = { .name = "tegra-bpmp", .of_match_table = tegra_bpmp_match, .pm = &tegra_bpmp_pm_ops, + .suppress_bind_attrs = true, }, .probe = tegra_bpmp_probe, }; - -static int __init tegra_bpmp_init(void) -{ - return platform_driver_register(&tegra_bpmp_driver); -} -core_initcall(tegra_bpmp_init); +builtin_platform_driver(tegra_bpmp_driver); From b720aaa347f227c416e8aed2f12ca62ea4f1cd4e Mon Sep 17 00:00:00 2001 From: Dmitry Osipenko Date: Wed, 25 Mar 2020 01:43:34 +0300 Subject: [PATCH 2/4] firmware: tf: Different way of L2 cache enabling after LP2 suspend MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ASUS TF300T device may not work properly if firmware is asked to fully re-initialize L2 cache after resume from LP2 suspend. The downstream kernel of TF300T uses different opcode to enable cache after resuming from LP2, this opcode also works fine on Nexus 7 and Ouya devices. Supposedly, this may be needed by an older firmware versions. Reported-by: Michał Mirosław Tested-by: Michał Mirosław Tested-by: Jasper Korten Tested-by: David Heidelberg Tested-by: Peter Geis Signed-off-by: Dmitry Osipenko Signed-off-by: Thierry Reding --- drivers/firmware/trusted_foundations.c | 21 ++++++++++++++++++-- include/linux/firmware/trusted_foundations.h | 1 + 2 files changed, 20 insertions(+), 2 deletions(-) diff --git a/drivers/firmware/trusted_foundations.c b/drivers/firmware/trusted_foundations.c index fc544e19b0a1..1389fa9418a7 100644 --- a/drivers/firmware/trusted_foundations.c +++ b/drivers/firmware/trusted_foundations.c @@ -19,6 +19,7 @@ #define TF_CACHE_ENABLE 1 #define TF_CACHE_DISABLE 2 +#define TF_CACHE_REENABLE 4 #define TF_SET_CPU_BOOT_ADDR_SMC 0xfffff200 @@ -29,6 +30,7 @@ #define TF_CPU_PM_S1 0xffffffe4 #define TF_CPU_PM_S1_NOFLUSH_L2 0xffffffe7 +static unsigned long tf_idle_mode = TF_PM_MODE_NONE; static unsigned long cpu_boot_addr; static void tf_generic_smc(u32 type, u32 arg1, u32 arg2) @@ -85,25 +87,40 @@ static int tf_prepare_idle(unsigned long mode) cpu_boot_addr); break; + case TF_PM_MODE_NONE: + break; + default: return -EINVAL; } + tf_idle_mode = mode; + return 0; } #ifdef CONFIG_CACHE_L2X0 static void tf_cache_write_sec(unsigned long val, unsigned int reg) { - u32 l2x0_way_mask = 0xff; + u32 enable_op, l2x0_way_mask = 0xff; switch (reg) { case L2X0_CTRL: if (l2x0_saved_regs.aux_ctrl & L310_AUX_CTRL_ASSOCIATIVITY_16) l2x0_way_mask = 0xffff; + switch (tf_idle_mode) { + case TF_PM_MODE_LP2: + enable_op = TF_CACHE_REENABLE; + break; + + default: + enable_op = TF_CACHE_ENABLE; + break; + } + if (val == L2X0_CTRL_EN) - tf_generic_smc(TF_CACHE_MAINT, TF_CACHE_ENABLE, + tf_generic_smc(TF_CACHE_MAINT, enable_op, l2x0_saved_regs.aux_ctrl); else tf_generic_smc(TF_CACHE_MAINT, TF_CACHE_DISABLE, diff --git a/include/linux/firmware/trusted_foundations.h b/include/linux/firmware/trusted_foundations.h index 2549a2db56aa..be5984bda592 100644 --- a/include/linux/firmware/trusted_foundations.h +++ b/include/linux/firmware/trusted_foundations.h @@ -32,6 +32,7 @@ #define TF_PM_MODE_LP1_NO_MC_CLK 2 #define TF_PM_MODE_LP2 3 #define TF_PM_MODE_LP2_NOFLUSH_L2 4 +#define TF_PM_MODE_NONE 5 struct trusted_foundations_platform_data { unsigned int version_major; From 36dc3b1a7e9dd332d224cc187acdaa9f2023a1f1 Mon Sep 17 00:00:00 2001 From: Dmitry Osipenko Date: Wed, 25 Mar 2020 01:43:33 +0300 Subject: [PATCH 3/4] ARM: tegra: Initialize r0 register for firmware wake-up MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Downstream kernel of ASUS TF300T sets r0 to #3. There is no explanation in downstream code whether this is really needed and some of T30 downstream kernels have and explicit comment telling that all arguments are ignored by firmware. Let's take a safe side by replicating behavior of the TF300T downstream kernel. This change works fine on Ouya and Nexus 7 devices. Tested-by: Michał Mirosław Tested-by: Jasper Korten Tested-by: David Heidelberg Tested-by: Peter Geis Signed-off-by: Dmitry Osipenko Signed-off-by: Thierry Reding --- arch/arm/mach-tegra/reset-handler.S | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/arch/arm/mach-tegra/reset-handler.S b/arch/arm/mach-tegra/reset-handler.S index 53123ae4ac3b..06ca44b09381 100644 --- a/arch/arm/mach-tegra/reset-handler.S +++ b/arch/arm/mach-tegra/reset-handler.S @@ -98,7 +98,12 @@ ENTRY(tegra_resume_trusted_foundations) reteq lr .arch_extension sec - /* First call after suspend wakes firmware. No arguments required. */ + /* + * First call after suspend wakes firmware. No arguments required + * for some firmware versions. Downstream kernel of ASUS TF300T uses + * r0=3 for the wake-up notification. + */ + mov r0, #3 smc #0 b cpu_resume From 38743e414e7cc6d23f41276f298ad4781890a89f Mon Sep 17 00:00:00 2001 From: Dmitry Osipenko Date: Wed, 25 Mar 2020 01:43:34 +0300 Subject: [PATCH 4/4] ARM: tegra: Do not fully reinitialize L2 on resume MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ASUS TF300T device may not work properly if firmware is asked to fully re-initialize L2 cache after resume from LP2 suspend. The downstream kernel of TF300T uses different opcode to enable cache after resuming from LP2, this opcode also works fine on Nexus 7 and Ouya devices. Supposedly, this may be needed by an older firmware versions. Reported-by: Michał Mirosław Tested-by: Michał Mirosław Tested-by: Jasper Korten Tested-by: David Heidelberg Tested-by: Peter Geis Signed-off-by: Dmitry Osipenko Signed-off-by: Thierry Reding --- arch/arm/mach-tegra/pm.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/arch/arm/mach-tegra/pm.c b/arch/arm/mach-tegra/pm.c index d1e1a61b12cf..6452ebf68d40 100644 --- a/arch/arm/mach-tegra/pm.c +++ b/arch/arm/mach-tegra/pm.c @@ -216,6 +216,8 @@ int tegra_pm_enter_lp2(void) restore_cpu_complex(); cpu_cluster_pm_exit(); + call_firmware_op(prepare_idle, TF_PM_MODE_NONE); + return err; } @@ -391,6 +393,8 @@ static int tegra_suspend_enter(suspend_state_t state) local_fiq_enable(); + call_firmware_op(prepare_idle, TF_PM_MODE_NONE); + return 0; }