|
@@ -22,6 +22,7 @@
|
|
|
#include <linux/cpumask.h>
|
|
|
#include <linux/delay.h>
|
|
|
#include <linux/cpu_pm.h>
|
|
|
+#include <linux/suspend.h>
|
|
|
#include <linux/err.h>
|
|
|
#include <linux/clk/tegra.h>
|
|
|
|
|
@@ -38,14 +39,10 @@
|
|
|
#include "fuse.h"
|
|
|
#include "pmc.h"
|
|
|
#include "sleep.h"
|
|
|
-
|
|
|
-#define TEGRA_POWER_CPU_PWRREQ_OE (1 << 16) /* CPU pwr req enable */
|
|
|
-
|
|
|
-#define PMC_CTRL 0x0
|
|
|
+#include "pmc.h"
|
|
|
|
|
|
#ifdef CONFIG_PM_SLEEP
|
|
|
static DEFINE_SPINLOCK(tegra_lp2_lock);
|
|
|
-static void __iomem *pmc = IO_ADDRESS(TEGRA_PMC_BASE);
|
|
|
void (*tegra_tear_down_cpu)(void);
|
|
|
|
|
|
/*
|
|
@@ -145,14 +142,7 @@ static int tegra_sleep_cpu(unsigned long v2p)
|
|
|
|
|
|
void tegra_idle_lp2_last(u32 cpu_on_time, u32 cpu_off_time)
|
|
|
{
|
|
|
- u32 mode;
|
|
|
-
|
|
|
- /* Only the last cpu down does the final suspend steps */
|
|
|
- mode = readl(pmc + PMC_CTRL);
|
|
|
- mode |= TEGRA_POWER_CPU_PWRREQ_OE;
|
|
|
- writel(mode, pmc + PMC_CTRL);
|
|
|
-
|
|
|
- set_power_timers(cpu_on_time, cpu_off_time);
|
|
|
+ tegra_pmc_pm_set(TEGRA_SUSPEND_LP2);
|
|
|
|
|
|
cpu_cluster_pm_enter();
|
|
|
suspend_cpu_complex();
|
|
@@ -162,4 +152,81 @@ void tegra_idle_lp2_last(u32 cpu_on_time, u32 cpu_off_time)
|
|
|
restore_cpu_complex();
|
|
|
cpu_cluster_pm_exit();
|
|
|
}
|
|
|
+
|
|
|
+enum tegra_suspend_mode tegra_pm_validate_suspend_mode(
|
|
|
+ enum tegra_suspend_mode mode)
|
|
|
+{
|
|
|
+ /* Tegra114 didn't support any suspending mode yet. */
|
|
|
+ if (tegra_chip_id == TEGRA114)
|
|
|
+ return TEGRA_SUSPEND_NONE;
|
|
|
+
|
|
|
+ /*
|
|
|
+ * The Tegra devices only support suspending to LP2 currently.
|
|
|
+ */
|
|
|
+ if (mode > TEGRA_SUSPEND_LP2)
|
|
|
+ return TEGRA_SUSPEND_LP2;
|
|
|
+
|
|
|
+ return mode;
|
|
|
+}
|
|
|
+
|
|
|
+static const char *lp_state[TEGRA_MAX_SUSPEND_MODE] = {
|
|
|
+ [TEGRA_SUSPEND_NONE] = "none",
|
|
|
+ [TEGRA_SUSPEND_LP2] = "LP2",
|
|
|
+ [TEGRA_SUSPEND_LP1] = "LP1",
|
|
|
+ [TEGRA_SUSPEND_LP0] = "LP0",
|
|
|
+};
|
|
|
+
|
|
|
+static int __cpuinit tegra_suspend_enter(suspend_state_t state)
|
|
|
+{
|
|
|
+ enum tegra_suspend_mode mode = tegra_pmc_get_suspend_mode();
|
|
|
+
|
|
|
+ if (WARN_ON(mode < TEGRA_SUSPEND_NONE ||
|
|
|
+ mode >= TEGRA_MAX_SUSPEND_MODE))
|
|
|
+ return -EINVAL;
|
|
|
+
|
|
|
+ pr_info("Entering suspend state %s\n", lp_state[mode]);
|
|
|
+
|
|
|
+ tegra_pmc_pm_set(mode);
|
|
|
+
|
|
|
+ local_fiq_disable();
|
|
|
+
|
|
|
+ suspend_cpu_complex();
|
|
|
+ switch (mode) {
|
|
|
+ case TEGRA_SUSPEND_LP2:
|
|
|
+ tegra_set_cpu_in_lp2(0);
|
|
|
+ break;
|
|
|
+ default:
|
|
|
+ break;
|
|
|
+ }
|
|
|
+
|
|
|
+ cpu_suspend(PHYS_OFFSET - PAGE_OFFSET, &tegra_sleep_cpu);
|
|
|
+
|
|
|
+ switch (mode) {
|
|
|
+ case TEGRA_SUSPEND_LP2:
|
|
|
+ tegra_clear_cpu_in_lp2(0);
|
|
|
+ break;
|
|
|
+ default:
|
|
|
+ break;
|
|
|
+ }
|
|
|
+ restore_cpu_complex();
|
|
|
+
|
|
|
+ local_fiq_enable();
|
|
|
+
|
|
|
+ return 0;
|
|
|
+}
|
|
|
+
|
|
|
+static const struct platform_suspend_ops tegra_suspend_ops = {
|
|
|
+ .valid = suspend_valid_only_mem,
|
|
|
+ .enter = tegra_suspend_enter,
|
|
|
+};
|
|
|
+
|
|
|
+void __init tegra_init_suspend(void)
|
|
|
+{
|
|
|
+ if (tegra_pmc_get_suspend_mode() == TEGRA_SUSPEND_NONE)
|
|
|
+ return;
|
|
|
+
|
|
|
+ tegra_pmc_suspend_init();
|
|
|
+
|
|
|
+ suspend_set_ops(&tegra_suspend_ops);
|
|
|
+}
|
|
|
#endif
|