summaryrefslogtreecommitdiff
path: root/drivers/cpuidle
diff options
context:
space:
mode:
authorDmitry Osipenko <digetx@gmail.com>2020-02-25 01:40:54 +0300
committerThierry Reding <treding@nvidia.com>2020-03-13 11:32:01 +0100
commit14e086baca509ef244715ad8b6c3f7bf80621e0b (patch)
tree7b927be7a0aaa2dd176c0f2696fdb36f4ee1277f /drivers/cpuidle
parent19461a499c9e47d38f29e1ec4f0f614197cd67f2 (diff)
cpuidle: tegra: Squash Tegra114 driver into the common driver
Tegra20/30/114/124 SoCs have common idling states, thus there is no much point in having separate drivers for a similar hardware. This patch moves Tegra114/124 arch/ drivers into the common driver without any functional changes. The CC6 state is kept disabled on Tegra114/124 because the core Tegra PM code needs some more work in order to support that state. Acked-by: Peter De Schrijver <pdeschrijver@nvidia.com> Signed-off-by: Dmitry Osipenko <digetx@gmail.com> Acked-by: Daniel Lezcano <daniel.lezcano@linaro.org> Signed-off-by: Thierry Reding <treding@nvidia.com>
Diffstat (limited to 'drivers/cpuidle')
-rw-r--r--drivers/cpuidle/cpuidle-tegra.c45
1 files changed, 44 insertions, 1 deletions
diff --git a/drivers/cpuidle/cpuidle-tegra.c b/drivers/cpuidle/cpuidle-tegra.c
index cd969ec18651..2ddbd289e17d 100644
--- a/drivers/cpuidle/cpuidle-tegra.c
+++ b/drivers/cpuidle/cpuidle-tegra.c
@@ -24,6 +24,7 @@
#include <linux/types.h>
#include <linux/clk/tegra.h>
+#include <linux/firmware/trusted_foundations.h>
#include <soc/tegra/cpuidle.h>
#include <soc/tegra/flowctrl.h>
@@ -32,6 +33,7 @@
#include <soc/tegra/pm.h>
#include <asm/cpuidle.h>
+#include <asm/firmware.h>
#include <asm/smp_plat.h>
#include <asm/suspend.h>
@@ -45,6 +47,11 @@ enum tegra_state {
static atomic_t tegra_idle_barrier;
static atomic_t tegra_abort_flag;
+static inline bool tegra_cpuidle_using_firmware(void)
+{
+ return firmware_ops->prepare_idle && firmware_ops->do_idle;
+}
+
static void tegra_cpuidle_report_cpus_state(void)
{
unsigned long cpu, lcpu, csr;
@@ -125,6 +132,16 @@ static int tegra_cpuidle_cc6_enter(unsigned int cpu)
static int tegra_cpuidle_c7_enter(void)
{
+ int err;
+
+ if (tegra_cpuidle_using_firmware()) {
+ err = call_firmware_op(prepare_idle, TF_PM_MODE_LP2_NOFLUSH_L2);
+ if (err)
+ return err;
+
+ return call_firmware_op(do_idle, 0);
+ }
+
return cpu_suspend(0, tegra30_pm_secondary_cpu_suspend);
}
@@ -235,6 +252,13 @@ static int tegra_cpuidle_enter(struct cpuidle_device *dev,
return err ? -1 : index;
}
+static void tegra114_enter_s2idle(struct cpuidle_device *dev,
+ struct cpuidle_driver *drv,
+ int index)
+{
+ tegra_cpuidle_enter(dev, drv, index);
+}
+
/*
* The previous versions of Tegra CPUIDLE driver used a different "legacy"
* terminology for naming of the idling states, while this driver uses the
@@ -302,6 +326,15 @@ void tegra_cpuidle_pcie_irqs_in_use(void)
tegra_cpuidle_disable_state(TEGRA_CC6);
}
+static void tegra_cpuidle_setup_tegra114_c7_state(void)
+{
+ struct cpuidle_state *s = &tegra_idle_driver.states[TEGRA_C7];
+
+ s->enter_s2idle = tegra114_enter_s2idle;
+ s->target_residency = 1000;
+ s->exit_latency = 500;
+}
+
static int tegra_cpuidle_probe(struct platform_device *pdev)
{
/*
@@ -310,7 +343,9 @@ static int tegra_cpuidle_probe(struct platform_device *pdev)
* is disabled.
*/
if (!IS_ENABLED(CONFIG_PM_SLEEP)) {
- tegra_cpuidle_disable_state(TEGRA_C7);
+ if (!tegra_cpuidle_using_firmware())
+ tegra_cpuidle_disable_state(TEGRA_C7);
+
tegra_cpuidle_disable_state(TEGRA_CC6);
}
@@ -328,6 +363,14 @@ static int tegra_cpuidle_probe(struct platform_device *pdev)
tegra_cpuidle_disable_state(TEGRA_CC6);
break;
+ case TEGRA114:
+ case TEGRA124:
+ tegra_cpuidle_setup_tegra114_c7_state();
+
+ /* coupled CC6 (LP2) state isn't implemented yet */
+ tegra_cpuidle_disable_state(TEGRA_CC6);
+ break;
+
default:
return -EINVAL;
}