]> nv-tegra.nvidia Code Review - linux-2.6.git/blobdiff - arch/arm/mach-tegra/pm.c
Ventana: KBC: Removing the KBC usage on ventana
[linux-2.6.git] / arch / arm / mach-tegra / pm.c
index 8fb1d865760bf6b8a49b4d0bd18eb60508317ba9..587b5d6097f261d37f0cc8040664619321338e4d 100644 (file)
@@ -1,9 +1,9 @@
 /*
- * arch/arm/mach-tegra/suspend.c
+ * arch/arm/mach-tegra/pm.c
  *
  * CPU complex suspend & resume functions for Tegra SoCs
  *
- * Copyright (c) 2009-2010, NVIDIA Corporation.
+ * Copyright (c) 2009-2011, 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
@@ -21,6 +21,7 @@
  */
 
 #include <linux/kernel.h>
+#include <linux/ctype.h>
 #include <linux/init.h>
 #include <linux/io.h>
 #include <linux/sched.h>
@@ -37,6 +38,9 @@
 #include <linux/seq_file.h>
 #include <linux/uaccess.h>
 #include <linux/syscore_ops.h>
+#include <linux/vmalloc.h>
+#include <linux/memblock.h>
+#include <linux/console.h>
 
 #include <asm/cacheflush.h>
 #include <asm/cpu_pm.h>
 #include <asm/hardware/gic.h>
 #include <asm/localtimer.h>
 #include <asm/pgalloc.h>
+#include <asm/pgtable.h>
 #include <asm/tlbflush.h>
 
 #include <mach/clk.h>
 #include <mach/iomap.h>
 #include <mach/irqs.h>
+#include <mach/powergate.h>
 
 #include "board.h"
 #include "clock.h"
+#include "cpuidle.h"
+#include "fuse.h"
+#include "gic.h"
 #include "pm.h"
 #include "pm-irq.h"
+#include "reset.h"
 #include "sleep.h"
+#include "timer.h"
+#include "reset.h"
 
 struct suspend_context {
        /*
@@ -75,21 +87,30 @@ struct suspend_context {
 
        u32 mc[3];
        u8 uart[5];
+
+       struct tegra_twd_context twd;
 };
 
+#ifdef CONFIG_PM_SLEEP
+#if USE_TEGRA_CPU_SUSPEND
+void *tegra_cpu_context;       /* non-cacheable page for CPU context */
+#endif
+phys_addr_t tegra_pgd_phys;    /* pgd used by hotplug & LP2 bootup */
+static pgd_t *tegra_pgd;
+static DEFINE_SPINLOCK(tegra_lp2_lock);
+static cpumask_t tegra_in_lp2;
+static cpumask_t *iram_cpu_lp2_mask;
+static unsigned long *iram_cpu_lp1_mask;
 static u8 *iram_save;
 static unsigned long iram_save_size;
-
-struct suspend_context tegra_sctx;
-
 static void __iomem *iram_code = IO_ADDRESS(TEGRA_IRAM_CODE_AREA);
-static void __iomem *pmc = IO_ADDRESS(TEGRA_PMC_BASE);
-#ifdef CONFIG_PM
 static void __iomem *clk_rst = IO_ADDRESS(TEGRA_CLK_RESET_BASE);
-static void __iomem *evp_reset =
-       IO_ADDRESS(TEGRA_EXCEPTION_VECTORS_BASE) + 0x100;
+static void __iomem *pmc = IO_ADDRESS(TEGRA_PMC_BASE);
+static int tegra_last_pclk;
 #endif
 
+struct suspend_context tegra_sctx;
+
 #define TEGRA_POWER_PWRREQ_POLARITY    (1 << 8)   /* core power request polarity */
 #define TEGRA_POWER_PWRREQ_OE          (1 << 9)   /* core power request enable */
 #define TEGRA_POWER_SYSCLK_POLARITY    (1 << 10)  /* sys clk polarity */
@@ -112,10 +133,15 @@ static void __iomem *evp_reset =
 #define PMC_COREPWRGOOD_TIMER  0x3c
 #define PMC_SCRATCH0           0x50
 #define PMC_SCRATCH1           0x54
+#define PMC_SCRATCH4           0x60
 #define PMC_CPUPWRGOOD_TIMER   0xc8
 #define PMC_CPUPWROFF_TIMER    0xcc
 #define PMC_COREPWROFF_TIMER   PMC_WAKE_DELAY
 
+#ifdef CONFIG_TEGRA_CLUSTER_CONTROL
+#define PMC_SCRATCH4_WAKE_CLUSTER_MASK (1<<31)
+#endif
+
 #define CLK_RESET_CCLK_BURST   0x20
 #define CLK_RESET_CCLK_DIVIDER  0x24
 #define CLK_RESET_PLLC_BASE    0x80
@@ -133,20 +159,6 @@ static void __iomem *evp_reset =
 #define CLK_RESET_CCLK_BURST_POLICY_PLLM   3
 #define CLK_RESET_CCLK_BURST_POLICY_PLLX   8
 
-#ifdef CONFIG_ARCH_TEGRA_2x_SOC
-#define FLOW_CTRL_CSR_WFE_CPU0         (1 << 4)
-#define FLOW_CTRL_CSR_WFE_BITMAP       (3 << 4)
-#define FLOW_CTRL_CSR_WFI_BITMAP       0
-#else
-#define FLOW_CTRL_CSR_WFE_BITMAP       (0xF << 4)
-#define FLOW_CTRL_CSR_WFI_CPU0         (1 << 8)
-#define FLOW_CTRL_CSR_WFI_BITMAP       (0xF << 8)
-#endif
-
-#define FLOW_CTRL_CSR_CLEAR_INTR       (1 << 15)
-#define FLOW_CTRL_CSR_CLEAR_EVENT      (1 << 14)
-#define FLOW_CTRL_CSR_ENABLE           (1 << 0)
-
 #define EMC_MRW_0              0x0e8
 #define EMC_MRW_DEV_SELECTN     30
 #define EMC_MRW_DEV_NONE       (3 << EMC_MRW_DEV_SELECTN)
@@ -155,20 +167,19 @@ static void __iomem *evp_reset =
 #define MC_SECURITY_SIZE       0x70
 #define MC_SECURITY_CFG2       0x7c
 
-unsigned long tegra_pgd_phys;  /* pgd used by hotplug & LP2 bootup */
-static pgd_t *tegra_pgd;
-
-static int tegra_last_pclk;
 static struct clk *tegra_pclk;
 static const struct tegra_suspend_platform_data *pdata;
 static enum tegra_suspend_mode current_suspend_mode = TEGRA_SUSPEND_NONE;
 
-static DEFINE_SPINLOCK(tegra_lp2_lock);
-static cpumask_t tegra_in_lp2;
+static const char *tegra_suspend_name[TEGRA_MAX_SUSPEND_MODE] = {
+       [TEGRA_SUSPEND_NONE]    = "none",
+       [TEGRA_SUSPEND_LP2]     = "lp2",
+       [TEGRA_SUSPEND_LP1]     = "lp1",
+       [TEGRA_SUSPEND_LP0]     = "lp0",
+};
 
-#if INSTRUMENT_CLUSTER_SWITCH
-enum tegra_cluster_switch_time_id
-{
+#if defined(CONFIG_TEGRA_CLUSTER_CONTROL) && INSTRUMENT_CLUSTER_SWITCH
+enum tegra_cluster_switch_time_id {
        tegra_cluster_switch_time_id_start = 0,
        tegra_cluster_switch_time_id_prolog,
        tegra_cluster_switch_time_id_switch,
@@ -176,14 +187,17 @@ enum tegra_cluster_switch_time_id
        tegra_cluster_switch_time_id_max
 };
 
-static unsigned long tegra_cluster_switch_times[tegra_cluster_switch_time_id_max];
+static unsigned long
+               tegra_cluster_switch_times[tegra_cluster_switch_time_id_max];
 #define tegra_cluster_switch_time(flags, id) \
        do { \
                barrier(); \
                if (flags & TEGRA_POWER_CLUSTER_MASK) { \
-                       void __iomem *timer_us = IO_ADDRESS(TEGRA_TMRUS_BASE); \
+                       void __iomem *timer_us = \
+                                               IO_ADDRESS(TEGRA_TMRUS_BASE); \
                        if (id < tegra_cluster_switch_time_id_max) \
-                               tegra_cluster_switch_times[id] = readl(timer_us); \
+                               tegra_cluster_switch_times[id] = \
+                                                       readl(timer_us); \
                                wmb(); \
                } \
                barrier(); \
@@ -192,6 +206,7 @@ static unsigned long tegra_cluster_switch_times[tegra_cluster_switch_time_id_max
 #define tegra_cluster_switch_time(flags, id) do {} while(0)
 #endif
 
+#ifdef CONFIG_PM_SLEEP
 unsigned long tegra_cpu_power_good_time(void)
 {
        if (WARN_ON_ONCE(!pdata))
@@ -208,36 +223,12 @@ unsigned long tegra_cpu_power_off_time(void)
        return pdata->cpu_off_timer;
 }
 
-/* ensures that sufficient time is passed for a register write to
- * serialize into the 32KHz domain */
-static void pmc_32kwritel(u32 val, unsigned long offs)
-{
-       writel(val, pmc + offs);
-       udelay(130);
-}
-
-static void set_power_timers(unsigned long us_on, unsigned long us_off,
-                            long rate)
+unsigned long tegra_cpu_lp2_min_residency(void)
 {
-       unsigned long long ticks;
-       unsigned long long pclk;
-
-       if (WARN_ON_ONCE(rate <= 0))
-               pclk = 100000000;
-       else
-               pclk = rate;
-
-       if (rate != tegra_last_pclk) {
-               ticks = (us_on * pclk) + 999999ull;
-               do_div(ticks, 1000000);
-               writel((unsigned long)ticks, pmc + PMC_CPUPWRGOOD_TIMER);
+       if (WARN_ON_ONCE(!pdata))
+               return 2000;
 
-               ticks = (us_off * pclk) + 999999ull;
-               do_div(ticks, 1000000);
-               writel((unsigned long)ticks, pmc + PMC_CPUPWROFF_TIMER);
-               wmb();
-       }
-       tegra_last_pclk = pclk;
+       return pdata->cpu_lp2_min_residency;
 }
 
 /*
@@ -246,71 +237,129 @@ static void set_power_timers(unsigned long us_on, unsigned long us_off,
  * Creates a page table with identity mappings of physical memory and IRAM
  * for use when the MMU is off, in addition to all the regular kernel mappings.
  */
-static int create_suspend_pgtable(void)
+static __init int create_suspend_pgtable(void)
 {
        tegra_pgd = pgd_alloc(&init_mm);
        if (!tegra_pgd)
                return -ENOMEM;
 
-       identity_mapping_add(tegra_pgd, PLAT_PHYS_OFFSET, IO_IRAM_PHYS);
+       identity_mapping_add(tegra_pgd, PLAT_PHYS_OFFSET,
+                            PLAT_PHYS_OFFSET + memblock_phys_mem_size());
        identity_mapping_add(tegra_pgd, IO_IRAM_PHYS,
                IO_IRAM_PHYS + SECTION_SIZE);
 
-       tegra_pgd_phys = virt_to_phys(tegra_pgd);
+       /* inner/outer write-back/write-allocate, sharable */
+       tegra_pgd_phys = (virt_to_phys(tegra_pgd) & PAGE_MASK) | 0x4A;
 
        return 0;
 }
 
-static int tegra_reset_sleeping_cpu(int cpu)
+/*
+ * alloc_suspend_context
+ *
+ * Allocate a non-cacheable page to hold the CPU contexts.
+ * The standard ARM CPU context save functions don't work if there's
+ * an external L2 cache controller (like a PL310) in system.
+ */
+static __init int alloc_suspend_context(void)
 {
-       int ret = 0;
-
-       BUG_ON(cpu == smp_processor_id());
-       tegra_pen_lock();
+#if USE_TEGRA_CPU_SUSPEND
+       pgprot_t prot = __pgprot_modify(pgprot_kernel, L_PTE_MT_MASK,
+                                       L_PTE_MT_BUFFERABLE | L_PTE_XN);
+       struct page *ctx_page;
+       unsigned long ctx_virt = 0;
+       pgd_t *pgd;
+       pmd_t *pmd;
+       pte_t *pte;
+
+       ctx_page = alloc_pages(GFP_KERNEL, 0);
+       if (IS_ERR_OR_NULL(ctx_page))
+               goto fail;
+
+       tegra_cpu_context = vm_map_ram(&ctx_page, 1, -1, prot);
+       if (IS_ERR_OR_NULL(tegra_cpu_context))
+               goto fail;
+
+       /* Add the context page to our private pgd. */
+       ctx_virt = (unsigned long)tegra_cpu_context;
+
+       pgd = tegra_pgd + pgd_index(ctx_virt);
+       if (!pgd_present(*pgd))
+               goto fail;
+       pmd = pmd_offset(pgd, ctx_virt);
+       if (!pmd_none(*pmd))
+               goto fail;
+       pte = pte_alloc_kernel(pmd, ctx_virt);
+       if (!pte)
+               goto fail;
+
+       set_pte_ext(pte, mk_pte(ctx_page, prot), 0);
+
+       outer_clean_range(__pa(pmd), __pa(pmd + 1));
 
-       if (readl(pmc + PMC_SCRATCH41) == CPU_RESETTABLE)
-               tegra_cpu_reset(cpu);
-       else
-               ret = -EINVAL;
-
-       tegra_pen_unlock();
+       return 0;
 
-       return ret;
+fail:
+       if (ctx_page)
+               __free_page(ctx_page);
+       if (ctx_virt)
+               vm_unmap_ram((void*)ctx_virt, 1);
+       tegra_cpu_context = NULL;
+       return -ENOMEM;
+#else
+       return 0;
+#endif
 }
 
-static void tegra_wake_reset_cpu(int cpu)
+/* ensures that sufficient time is passed for a register write to
+ * serialize into the 32KHz domain */
+static void pmc_32kwritel(u32 val, unsigned long offs)
 {
-       u32 reg;
+       writel(val, pmc + offs);
+       udelay(130);
+}
 
-       writel(virt_to_phys(tegra_secondary_resume), evp_reset);
+static void set_power_timers(unsigned long us_on, unsigned long us_off,
+                            long rate)
+{
+       static unsigned long last_us_off = 0;
+       unsigned long long ticks;
+       unsigned long long pclk;
 
-       /* enable cpu clock on cpu */
-       reg = readl(clk_rst + 0x4c);
-       writel(reg & ~(1 << (8 + cpu)), clk_rst + 0x4c);
+       if (WARN_ON_ONCE(rate <= 0))
+               pclk = 100000000;
+       else
+               pclk = rate;
 
-       reg = 0x1111 << cpu;
-       writel(reg, clk_rst + 0x344);
+       if ((rate != tegra_last_pclk) || (us_off != last_us_off)) {
+               ticks = (us_on * pclk) + 999999ull;
+               do_div(ticks, 1000000);
+               writel((unsigned long)ticks, pmc + PMC_CPUPWRGOOD_TIMER);
 
-       /* unhalt the cpu */
-       flowctrl_writel(0, FLOW_CTRL_HALT_CPU(1));
+               ticks = (us_off * pclk) + 999999ull;
+               do_div(ticks, 1000000);
+               writel((unsigned long)ticks, pmc + PMC_CPUPWROFF_TIMER);
+               wmb();
+       }
+       tegra_last_pclk = pclk;
+       last_us_off = us_off;
 }
 
-#ifdef CONFIG_PM
 /*
  * restore_cpu_complex
  *
  * restores cpu clock setting, clears flow controller
  *
- * always called on cpu 0, even when suspend_cpu_complex was called on cpu 1
- * in idle
+ * Always called on CPU 0.
  */
-static void restore_cpu_complex(void)
+static void restore_cpu_complex(u32 mode)
 {
+       int cpu = smp_processor_id();
        unsigned int reg;
-       int i;
 
-       /* restore original burst policy setting */
+       BUG_ON(cpu != 0);
 
+       /* restore original PLL settings */
        writel(tegra_sctx.pllx_misc, clk_rst + CLK_RESET_PLLX_MISC);
        writel(tegra_sctx.pllx_base, clk_rst + CLK_RESET_PLLX_BASE);
        writel(tegra_sctx.pllp_misc, clk_rst + CLK_RESET_PLLP_MISC);
@@ -326,8 +375,10 @@ static void restore_cpu_complex(void)
                 * by CPU boot-up code - wait for PLL stabilization if PLLX
                 * was enabled */
 
-               BUG_ON(readl(clk_rst + CLK_RESET_PLLX_BASE) !=
-                      tegra_sctx.pllx_base);
+               reg = readl(clk_rst + CLK_RESET_PLLX_BASE);
+               /* mask out bit 27 - not to check PLL lock bit */
+               BUG_ON((reg & (~(1 << 27))) !=
+                               (tegra_sctx.pllx_base & (~(1 << 27))));
 
                if (tegra_sctx.pllx_base & (1<<30)) {
 #if USE_PLL_LOCK_BITS
@@ -350,16 +401,19 @@ static void restore_cpu_complex(void)
 
        writel(tegra_sctx.clk_csite_src, clk_rst + CLK_RESET_SOURCE_CSITE);
 
-       /* do not power-gate the CPU when flow controlled */
-       for (i = 0; i < num_possible_cpus(); i++) {
-               reg = readl(FLOW_CTRL_CPU_CSR(i));
-               reg &= ~FLOW_CTRL_CSR_WFE_BITMAP;       /* clear wfe bitmap */
-               reg &= ~FLOW_CTRL_CSR_WFI_BITMAP;       /* clear wfi bitmap */
-               reg &= ~FLOW_CTRL_CSR_ENABLE;           /* clear enable */
-               reg |= FLOW_CTRL_CSR_CLEAR_INTR;        /* clear intr */
-               reg |= FLOW_CTRL_CSR_CLEAR_EVENT;       /* clear event */
-               flowctrl_writel(reg, FLOW_CTRL_CPU_CSR(i));
-       }
+       /* Do not power-gate CPU 0 when flow controlled */
+       reg = readl(FLOW_CTRL_CPU_CSR(cpu));
+       reg &= ~FLOW_CTRL_CSR_WFE_BITMAP;       /* clear wfe bitmap */
+       reg &= ~FLOW_CTRL_CSR_WFI_BITMAP;       /* clear wfi bitmap */
+       reg &= ~FLOW_CTRL_CSR_ENABLE;           /* clear enable */
+       reg |= FLOW_CTRL_CSR_INTR_FLAG;         /* clear intr */
+       reg |= FLOW_CTRL_CSR_EVENT_FLAG;        /* clear event */
+       flowctrl_writel(reg, FLOW_CTRL_CPU_CSR(cpu));
+
+       /* If an immedidate cluster switch is being perfomed, restore the
+          local timer registers. See save_cpu_complex() for the details. */
+       if (mode & (TEGRA_POWER_CLUSTER_MASK | TEGRA_POWER_CLUSTER_IMMEDIATE))
+               tegra_twd_resume(&tegra_sctx.twd);
 }
 
 /*
@@ -368,14 +422,15 @@ static void restore_cpu_complex(void)
  * saves pll state for use by restart_plls, prepares flow controller for
  * transition to suspend state
  *
- * in suspend, always called on cpu 0
- * in idle, called on the last cpu to request lp2
+ * Must always be called on cpu 0.
  */
-static void suspend_cpu_complex(void)
+static void suspend_cpu_complex(u32 mode)
 {
+       int cpu = smp_processor_id();
        unsigned int reg;
        int i;
-       int cpu = smp_processor_id();
+
+       BUG_ON(cpu != 0);
 
        /* switch coresite to clk_m, save off original source */
        tegra_sctx.clk_csite_src = readl(clk_rst + CLK_RESET_SOURCE_CSITE);
@@ -390,10 +445,18 @@ static void suspend_cpu_complex(void)
        tegra_sctx.pllp_misc = readl(clk_rst + CLK_RESET_PLLP_MISC);
        tegra_sctx.cclk_divider = readl(clk_rst + CLK_RESET_CCLK_DIVIDER);
 
+       /* If an immedidate cluster switch is being perfomed, save the
+          local timer registers. For calls resulting from CPU LP2 in
+          idle or system suspend, the local timer is shut down and
+          timekeeping switches over to the global system timer. */
+       if (mode & (TEGRA_POWER_CLUSTER_MASK | TEGRA_POWER_CLUSTER_IMMEDIATE))
+               tegra_twd_suspend(&tegra_sctx.twd);
+
        reg = readl(FLOW_CTRL_CPU_CSR(cpu));
        reg &= ~FLOW_CTRL_CSR_WFE_BITMAP;       /* clear wfe bitmap */
        reg &= ~FLOW_CTRL_CSR_WFI_BITMAP;       /* clear wfi bitmap */
-       reg |= FLOW_CTRL_CSR_CLEAR_EVENT;       /* clear event flag */
+       reg |= FLOW_CTRL_CSR_INTR_FLAG;         /* clear intr flag */
+       reg |= FLOW_CTRL_CSR_EVENT_FLAG;        /* clear event flag */
 #ifdef CONFIG_ARCH_TEGRA_2x_SOC
        reg |= FLOW_CTRL_CSR_WFE_CPU0 << cpu;   /* enable power gating on wfe */
 #else
@@ -406,75 +469,95 @@ static void suspend_cpu_complex(void)
                if (i == cpu)
                        continue;
                reg = readl(FLOW_CTRL_CPU_CSR(i));
-               reg |= FLOW_CTRL_CSR_CLEAR_EVENT;
-               reg |= FLOW_CTRL_CSR_CLEAR_INTR;
+               reg |= FLOW_CTRL_CSR_EVENT_FLAG;
+               reg |= FLOW_CTRL_CSR_INTR_FLAG;
                flowctrl_writel(reg, FLOW_CTRL_CPU_CSR(i));
-               flowctrl_writel(0, FLOW_CTRL_HALT_CPU(i));
        }
+
+       tegra_gic_cpu_disable();
+#ifndef CONFIG_ARCH_TEGRA_2x_SOC
+       /* Tegra3 enters LPx states via WFI - do not propagate legacy IRQs
+          to CPU core to avoid fall through WFI (IRQ-to-flow controller wake
+          path is not affected). */
+       tegra_gic_pass_through_disable();
+#endif
 }
 
-int tegra_reset_other_cpus(int cpu)
+void tegra_clear_cpu_in_lp2(int cpu)
 {
-       int i;
-       int abort = -1;
-
-       for_each_online_cpu(i) {
-               if (i != cpu) {
-                       if (tegra_reset_sleeping_cpu(i)) {
-                               abort = i;
-                               break;
-                       }
-               }
-       }
+       spin_lock(&tegra_lp2_lock);
+       BUG_ON(!cpumask_test_cpu(cpu, &tegra_in_lp2));
+       cpumask_clear_cpu(cpu, &tegra_in_lp2);
 
-       if (abort >= 0) {
-               for_each_online_cpu(i) {
-                       if (i != cpu && i < abort)
-                               tegra_wake_reset_cpu(i);
-               }
-               return -EINVAL;
-       }
+       /* Update the IRAM copy used by the reset handler. The IRAM copy
+          can't use used directly by cpumask_clear_cpu() because it uses
+          LDREX/STREX which requires the addressed location to be inner
+          cacheable and sharable which IRAM isn't. */
+       writel(tegra_in_lp2.bits[0], iram_cpu_lp2_mask);
+       dsb();
 
-       return 0;
+       spin_unlock(&tegra_lp2_lock);
 }
 
-void tegra_idle_lp2_last(unsigned int flags)
+bool tegra_set_cpu_in_lp2(int cpu)
 {
-       u32 reg;
-       int i;
-       int cpu = smp_processor_id();
+       bool last_cpu = false;
 
-       while (tegra_cpu_is_resettable_soon())
-               cpu_relax();
+       spin_lock(&tegra_lp2_lock);
+       BUG_ON(cpumask_test_cpu(cpu, &tegra_in_lp2));
+       cpumask_set_cpu(cpu, &tegra_in_lp2);
 
-       if (tegra_reset_other_cpus(cpu))
-               return;
+       /* Update the IRAM copy used by the reset handler. The IRAM copy
+          can't use used directly by cpumask_set_cpu() because it uses
+          LDREX/STREX which requires the addressed location to be inner
+          cacheable and sharable which IRAM isn't. */
+       writel(tegra_in_lp2.bits[0], iram_cpu_lp2_mask);
+       dsb();
+
+       if ((cpu == 0) && cpumask_equal(&tegra_in_lp2, cpu_online_mask))
+               last_cpu = true;
+#ifdef CONFIG_ARCH_TEGRA_2x_SOC
+       else
+               tegra2_cpu_set_resettable_soon();
+#endif
+
+       spin_unlock(&tegra_lp2_lock);
+       return last_cpu;
+}
+
+unsigned int tegra_idle_lp2_last(unsigned int sleep_time, unsigned int flags)
+{
+       u32 mode;       /* hardware + software power mode flags */
+       unsigned int remain;
 
        /* Only the last cpu down does the final suspend steps */
-       reg = readl(pmc + PMC_CTRL);
-       reg |= TEGRA_POWER_CPU_PWRREQ_OE;
-       reg |= TEGRA_POWER_PWRREQ_OE;
-       reg |= flags;
-       reg &= ~TEGRA_POWER_EFFECT_LP0;
-       pmc_32kwritel(reg, PMC_CTRL);
+       mode = readl(pmc + PMC_CTRL);
+       mode |= TEGRA_POWER_CPU_PWRREQ_OE;
+       mode |= TEGRA_POWER_PWRREQ_OE;
+       mode &= ~TEGRA_POWER_EFFECT_LP0;
+       pmc_32kwritel(mode, PMC_CTRL);
+       mode |= flags;
 
        tegra_cluster_switch_time(flags, tegra_cluster_switch_time_id_start);
 
-       writel(virt_to_phys(tegra_resume), evp_reset);
-
        /*
-        * we can use the locked call here, because all other cpus are in reset
-        * and irqs are disabled
+        * We can use clk_get_rate_all_locked() here, because all other cpus
+        * are in LP2 state and irqs are disabled
         */
-       set_power_timers(pdata->cpu_timer, pdata->cpu_off_timer,
-               clk_get_rate_all_locked(tegra_pclk));
-
-       if (flags & TEGRA_POWER_CLUSTER_MASK)
+       if (flags & TEGRA_POWER_CLUSTER_MASK) {
+               set_power_timers(pdata->cpu_timer, 0,
+                       clk_get_rate_all_locked(tegra_pclk));
                tegra_cluster_switch_prolog(mode);
+       } else {
+               set_power_timers(pdata->cpu_timer, pdata->cpu_off_timer,
+                       clk_get_rate_all_locked(tegra_pclk));
+       }
 
-       cpu_complex_pm_enter();
+       if (sleep_time)
+               tegra_lp2_set_trigger(sleep_time);
 
-       suspend_cpu_complex();
+       cpu_complex_pm_enter();
+       suspend_cpu_complex(mode);
        tegra_cluster_switch_time(flags, tegra_cluster_switch_time_id_prolog);
        flush_cache_all();
        outer_flush_all();
@@ -482,23 +565,25 @@ void tegra_idle_lp2_last(unsigned int flags)
 
        tegra_sleep_cpu(PLAT_PHYS_OFFSET - PAGE_OFFSET);
 
+#ifdef CONFIG_CACHE_L2X0
        l2x0_enable();
+#endif
        tegra_cluster_switch_time(flags, tegra_cluster_switch_time_id_switch);
-       restore_cpu_complex();
+       restore_cpu_complex(mode);
        cpu_complex_pm_exit();
 
+       remain = tegra_lp2_timer_remain();
+       if (sleep_time)
+               tegra_lp2_set_trigger(0);
+
        if (flags & TEGRA_POWER_CLUSTER_MASK)
                tegra_cluster_switch_epilog(mode);
 
-       for_each_online_cpu(i)
-               if (i != cpu)
-                       tegra_wake_reset_cpu(i);
-
        tegra_cluster_switch_time(flags, tegra_cluster_switch_time_id_epilog);
 
 #if INSTRUMENT_CLUSTER_SWITCH
        if (flags & TEGRA_POWER_CLUSTER_MASK) {
-               printk("%s: prolog %lu us, switch %lu us, epilog %lu us, total %lu us\n",
+               pr_err("%s: prolog %lu us, switch %lu us, epilog %lu us, total %lu us\n",
                        is_lp_cluster() ? "G=>LP" : "LP=>G",
                        tegra_cluster_switch_times[tegra_cluster_switch_time_id_prolog] -
                        tegra_cluster_switch_times[tegra_cluster_switch_time_id_start],
@@ -510,48 +595,7 @@ void tegra_idle_lp2_last(unsigned int flags)
                        tegra_cluster_switch_times[tegra_cluster_switch_time_id_start]);
        }
 #endif
-}
-
-void tegra_idle_lp2(void)
-{
-       bool last_cpu = false;
-       int cpu = smp_processor_id();
-
-       spin_lock(&tegra_lp2_lock);
-
-       cpumask_set_cpu(cpu, &tegra_in_lp2);
-       if (cpumask_equal(&tegra_in_lp2, cpu_online_mask))
-               last_cpu = true;
-       else
-               tegra_cpu_set_resettable_soon();
-
-       spin_unlock(&tegra_lp2_lock);
-
-       cpu_pm_enter();
-
-       if (last_cpu)
-               tegra_idle_lp2_last(0);
-       else
-               tegra_sleep_wfi(PLAT_PHYS_OFFSET - PAGE_OFFSET);
-
-       cpu_pm_exit();
-
-       spin_lock(&tegra_lp2_lock);
-       cpumask_clear_cpu(cpu, &tegra_in_lp2);
-
-       /*
-        * cpus coming out of idle muck with page tables that belong to the
-        * last process executed before idle.  Don't release any cpus back to
-        * the scheduler until all cpus have booted to avoid modifying the
-        * page table of a running process on another cpu.
-        */
-       while (!cpumask_empty(&tegra_in_lp2)) {
-               spin_unlock(&tegra_lp2_lock);
-               cpu_relax();
-               spin_lock(&tegra_lp2_lock);
-       }
-
-       spin_unlock(&tegra_lp2_lock);
+       return remain;
 }
 
 static int tegra_common_suspend(void)
@@ -564,7 +608,7 @@ static int tegra_common_suspend(void)
 
        /* copy the reset vector and SDRAM shutdown code into IRAM */
        memcpy(iram_save, iram_code, iram_save_size);
-       memcpy(iram_code, &tegra_iram_start, iram_save_size);
+       memcpy(iram_code, tegra_iram_start(), iram_save_size);
 
        return 0;
 }
@@ -572,7 +616,9 @@ static int tegra_common_suspend(void)
 static void tegra_common_resume(void)
 {
        void __iomem *mc = IO_ADDRESS(TEGRA_MC_BASE);
+#ifdef CONFIG_ARCH_TEGRA_2x_SOC
        void __iomem *emc = IO_ADDRESS(TEGRA_EMC_BASE);
+#endif
 
        /* Clear DPD sample */
        writel(0x0, pmc + PMC_DPD_SAMPLE);
@@ -580,10 +626,10 @@ static void tegra_common_resume(void)
        writel(tegra_sctx.mc[0], mc + MC_SECURITY_START);
        writel(tegra_sctx.mc[1], mc + MC_SECURITY_SIZE);
        writel(tegra_sctx.mc[2], mc + MC_SECURITY_CFG2);
-
+#ifdef CONFIG_ARCH_TEGRA_2x_SOC
        /* trigger emc mode write */
        writel(EMC_MRW_DEV_NONE, emc + EMC_MRW_0);
-
+#endif
        /* clear scratch registers shared by suspend and the reset pen */
        writel(0x0, pmc + PMC_SCRATCH39);
        writel(0x0, pmc + PMC_SCRATCH41);
@@ -609,7 +655,7 @@ static void tegra_suspend_wake(void)
 
 static void tegra_pm_set(enum tegra_suspend_mode mode)
 {
-       u32 reg;
+       u32 reg, boot_flag;
        unsigned long rate = 32768;
 
        reg = readl(pmc + PMC_CTRL);
@@ -620,36 +666,33 @@ static void tegra_pm_set(enum tegra_suspend_mode mode)
        switch (mode) {
        case TEGRA_SUSPEND_LP0:
                /*
-                * lp0 boots through the AVP, which then resumes the AVP to
+                * LP0 boots through the AVP, which then resumes the AVP to
                 * the address in scratch 39, and the cpu to the address in
                 * scratch 41 to tegra_resume
                 */
                writel(0x0, pmc + PMC_SCRATCH39);
-               __raw_writel(virt_to_phys(tegra_resume), pmc + PMC_SCRATCH41);
-               reg |= TEGRA_POWER_EFFECT_LP0;
 
                /* Enable DPD sample to trigger sampling pads data and direction
                 * in which pad will be driven during lp0 mode*/
                writel(0x1, pmc + PMC_DPD_SAMPLE);
-               break;
+
+               /* Set warmboot flag */
+               boot_flag = readl(pmc + PMC_SCRATCH0);
+               pmc_32kwritel(boot_flag | 1, PMC_SCRATCH0);
+
+               pmc_32kwritel(tegra_lp0_vec_start, PMC_SCRATCH1);
+
+               reg |= TEGRA_POWER_EFFECT_LP0;
+               /* No break here. LP0 code falls through to write SCRATCH41 */
        case TEGRA_SUSPEND_LP1:
-               /*
-                * lp1 boots through the normal cpu reset vector pointing to
-                * tegra_lp1_reset in IRAM, which resumes the CPU to
-                * the address in scratch 41 to tegra_resume
-                */
-               writel(&tegra_lp1_reset - &tegra_iram_start +
-                       TEGRA_IRAM_CODE_AREA, evp_reset);
                __raw_writel(virt_to_phys(tegra_resume), pmc + PMC_SCRATCH41);
+               wmb();
                break;
        case TEGRA_SUSPEND_LP2:
-               /*
-                * lp2 boots through the normal cpu reset vector directly to
-                * tegra_resume
-                */
-               writel(virt_to_phys(tegra_resume), evp_reset);
                rate = clk_get_rate(tegra_pclk);
                break;
+       case TEGRA_SUSPEND_NONE:
+               return;
        default:
                BUG();
        }
@@ -657,12 +700,6 @@ static void tegra_pm_set(enum tegra_suspend_mode mode)
        set_power_timers(pdata->cpu_timer, pdata->cpu_off_timer, rate);
 
        pmc_32kwritel(reg, PMC_CTRL);
-
-       /* Set warmboot flag */
-       reg = readl(pmc + PMC_SCRATCH0);
-       pmc_32kwritel(reg | 1, PMC_SCRATCH0);
-
-       pmc_32kwritel(tegra_lp0_vec_start, PMC_SCRATCH1);
 }
 
 static const char *lp_state[TEGRA_MAX_SUSPEND_MODE] = {
@@ -674,8 +711,47 @@ static const char *lp_state[TEGRA_MAX_SUSPEND_MODE] = {
 
 static int tegra_suspend_enter(suspend_state_t state)
 {
-       enum tegra_suspend_mode mode = current_suspend_mode;
+       int ret;
+
+       if (pdata && pdata->board_suspend)
+               pdata->board_suspend(current_suspend_mode, TEGRA_SUSPEND_BEFORE_PERIPHERAL);
+
+       ret = tegra_suspend_dram(current_suspend_mode, 0);
+
+       if (pdata && pdata->board_resume)
+               pdata->board_resume(current_suspend_mode, TEGRA_RESUME_AFTER_PERIPHERAL);
+
+       return ret;
+}
+
+static void tegra_suspend_check_pwr_stats(void)
+{
+       /* cpus and l2 are powered off later */
+       unsigned long pwrgate_partid_mask =
+#if !defined(CONFIG_ARCH_TEGRA_2x_SOC)
+               (1 << TEGRA_POWERGATE_HEG)      |
+               (1 << TEGRA_POWERGATE_SATA)     |
+               (1 << TEGRA_POWERGATE_3D1)      |
+#endif
+               (1 << TEGRA_POWERGATE_3D)       |
+               (1 << TEGRA_POWERGATE_VENC)     |
+               (1 << TEGRA_POWERGATE_PCIE)     |
+               (1 << TEGRA_POWERGATE_VDEC)     |
+               (1 << TEGRA_POWERGATE_MPE);
 
+       int partid;
+
+       for (partid = 0; partid < TEGRA_NUM_POWERGATE; partid++)
+               if ((1 << partid) & pwrgate_partid_mask)
+                       if (tegra_powergate_is_powered(partid))
+                               pr_warning("partition %s is left on before suspend\n",
+                                       tegra_powergate_get_name(partid));
+
+       return;
+}
+
+int tegra_suspend_dram(enum tegra_suspend_mode mode, unsigned int flags)
+{
        BUG_ON(mode < 0 || mode >= TEGRA_MAX_SUSPEND_MODE);
 
        if ((mode == TEGRA_SUSPEND_LP0) && !tegra_pm_irq_lp0_allowed()) {
@@ -683,21 +759,39 @@ static int tegra_suspend_enter(suspend_state_t state)
                mode = TEGRA_SUSPEND_LP1;
        }
 
-       tegra_common_suspend();
+       if ((mode == TEGRA_SUSPEND_LP0) || (mode == TEGRA_SUSPEND_LP1))
+               tegra_suspend_check_pwr_stats();
 
-       pr_info("Entering suspend state %s\n", lp_state[mode]);
+       tegra_common_suspend();
 
        tegra_pm_set(mode);
 
+       if (pdata && pdata->board_suspend)
+               pdata->board_suspend(mode, TEGRA_SUSPEND_BEFORE_CPU);
+
        local_fiq_disable();
 
        cpu_pm_enter();
        cpu_complex_pm_enter();
 
-       if (mode == TEGRA_SUSPEND_LP0)
+       if (mode == TEGRA_SUSPEND_LP0) {
+#ifdef CONFIG_TEGRA_CLUSTER_CONTROL
+               u32 reg = readl(pmc + PMC_SCRATCH4);
+               if (is_lp_cluster())
+                       reg |= PMC_SCRATCH4_WAKE_CLUSTER_MASK;
+               else
+                       reg &= (~PMC_SCRATCH4_WAKE_CLUSTER_MASK);
+               pmc_32kwritel(reg, PMC_SCRATCH4);
+#endif
                tegra_lp0_suspend_mc();
+               tegra_cpu_reset_handler_save();
+
+       }
+       else if (mode == TEGRA_SUSPEND_LP1)
+               *iram_cpu_lp1_mask = 1;
+
+       suspend_cpu_complex(flags);
 
-       suspend_cpu_complex();
        flush_cache_all();
        outer_flush_all();
        outer_disable();
@@ -709,14 +803,20 @@ static int tegra_suspend_enter(suspend_state_t state)
 
        tegra_init_cache();
 
-       if (mode == TEGRA_SUSPEND_LP0)
+       if (mode == TEGRA_SUSPEND_LP0) {
+               tegra_cpu_reset_handler_restore();
                tegra_lp0_resume_mc();
+       } else if (mode == TEGRA_SUSPEND_LP1)
+               *iram_cpu_lp1_mask = 0;
 
-       restore_cpu_complex();
+       restore_cpu_complex(flags);
 
        cpu_complex_pm_exit();
        cpu_pm_exit();
 
+       if (pdata && pdata->board_resume)
+               pdata->board_resume(mode, TEGRA_RESUME_AFTER_CPU);
+
        local_fiq_enable();
 
        tegra_common_resume();
@@ -751,6 +851,80 @@ static const struct platform_suspend_ops tegra_suspend_ops = {
        .wake           = tegra_suspend_wake,
        .enter          = tegra_suspend_enter,
 };
+
+static ssize_t suspend_mode_show(struct kobject *kobj,
+                                       struct kobj_attribute *attr, char *buf)
+{
+       char *start = buf;
+       char *end = buf + PAGE_SIZE;
+
+       start += scnprintf(start, end - start, "%s ", \
+                               tegra_suspend_name[current_suspend_mode]);
+       start += scnprintf(start, end - start, "\n");
+
+       return start - buf;
+}
+
+static ssize_t suspend_mode_store(struct kobject *kobj,
+                                       struct kobj_attribute *attr,
+                                       const char *buf, size_t n)
+{
+       int len;
+       const char *name_ptr;
+       enum tegra_suspend_mode new_mode;
+
+       name_ptr = buf;
+       while (*name_ptr && !isspace(*name_ptr))
+               name_ptr++;
+       len = name_ptr - buf;
+       if (!len)
+               goto bad_name;
+
+       for (new_mode = TEGRA_SUSPEND_NONE; \
+                       new_mode < TEGRA_MAX_SUSPEND_MODE; ++new_mode) {
+               if (!strncmp(buf, tegra_suspend_name[new_mode], len)) {
+                       current_suspend_mode = new_mode;
+                       break;
+               }
+       }
+
+bad_name:
+       return n;
+}
+
+static struct kobj_attribute suspend_mode_attribute =
+       __ATTR(mode, 0644, suspend_mode_show, suspend_mode_store);
+
+static struct kobject *suspend_kobj;
+#endif
+
+#ifdef CONFIG_PM_SLEEP
+static int tegra_pm_enter_suspend(void)
+{
+       pr_info("Entering suspend state %s\n", lp_state[current_suspend_mode]);
+       if (current_suspend_mode == TEGRA_SUSPEND_LP0)
+               tegra_lp0_cpu_mode(true);
+       return 0;
+}
+
+static void tegra_pm_enter_resume(void)
+{
+       if (current_suspend_mode == TEGRA_SUSPEND_LP0)
+               tegra_lp0_cpu_mode(false);
+       pr_info("Exited suspend state %s\n", lp_state[current_suspend_mode]);
+}
+
+static struct syscore_ops tegra_pm_enter_syscore_ops = {
+       .suspend = tegra_pm_enter_suspend,
+       .resume = tegra_pm_enter_resume,
+};
+
+static __init int tegra_pm_enter_syscore_init(void)
+{
+       register_syscore_ops(&tegra_pm_enter_syscore_ops);
+       return 0;
+}
+subsys_initcall(tegra_pm_enter_syscore_init);
 #endif
 
 void __init tegra_init_suspend(struct tegra_suspend_platform_data *plat)
@@ -764,24 +938,84 @@ void __init tegra_init_suspend(struct tegra_suspend_platform_data *plat)
        (void)reg;
        (void)mode;
 
-       create_suspend_pgtable();
+#ifndef CONFIG_PM_SLEEP
+       if (plat->suspend_mode != TEGRA_SUSPEND_NONE) {
+               pr_warning("%s: Suspend requires CONFIG_PM_SLEEP -- "
+                          "disabling suspend\n", __func__);
+               plat->suspend_mode = TEGRA_SUSPEND_NONE;
+       }
+#else
+       if (create_suspend_pgtable() < 0) {
+               pr_err("%s: PGD memory alloc failed -- LP0/LP1/LP2 unavailable\n",
+                               __func__);
+               plat->suspend_mode = TEGRA_SUSPEND_NONE;
+               goto fail;
+       }
+
+       if (alloc_suspend_context() < 0) {
+               pr_err("%s: CPU context alloc failed -- LP0/LP1/LP2 unavailable\n",
+                               __func__);
+               plat->suspend_mode = TEGRA_SUSPEND_NONE;
+               goto fail;
+       }
+
+       if ((tegra_get_chipid() == TEGRA_CHIPID_TEGRA3) &&
+           (tegra_get_revision() == TEGRA_REVISION_A01) &&
+           (plat->suspend_mode == TEGRA_SUSPEND_LP0)) {
+               /* Tegra 3 A01 supports only LP1 */
+               pr_warning("%s: Suspend mode LP0 is not supported on A01 "
+                          "-- disabling LP0\n", __func__);
+               plat->suspend_mode = TEGRA_SUSPEND_LP1;
+       }
+       if (plat->suspend_mode == TEGRA_SUSPEND_LP0 && tegra_lp0_vec_size &&
+               tegra_lp0_vec_relocate) {
+               unsigned char *reloc_lp0;
+               unsigned long tmp;
+               void __iomem *orig;
+               reloc_lp0 = kmalloc(tegra_lp0_vec_size + L1_CACHE_BYTES - 1,
+                                       GFP_KERNEL);
+               WARN_ON(!reloc_lp0);
+               if (!reloc_lp0) {
+                       pr_err("%s: Failed to allocate reloc_lp0\n",
+                               __func__);
+                       goto out;
+               }
 
-#ifdef CONFIG_PM
+               orig = ioremap(tegra_lp0_vec_start, tegra_lp0_vec_size);
+               WARN_ON(!orig);
+               if (!orig) {
+                       pr_err("%s: Failed to map tegra_lp0_vec_start %08lx\n",
+                               __func__, tegra_lp0_vec_start);
+                       kfree(reloc_lp0);
+                       goto out;
+               }
+
+               tmp = (unsigned long) reloc_lp0;
+               tmp = (tmp + L1_CACHE_BYTES - 1) & ~(L1_CACHE_BYTES - 1);
+               reloc_lp0 = (unsigned char *)tmp;
+               memcpy(reloc_lp0, orig, tegra_lp0_vec_size);
+               iounmap(orig);
+               tegra_lp0_vec_start = virt_to_phys(reloc_lp0);
+       }
+
+out:
        if (plat->suspend_mode == TEGRA_SUSPEND_LP0 && !tegra_lp0_vec_size) {
-               pr_warning("Suspend mode LP0 requested, no lp0_vec\n");
-               pr_warning("Disabling LP0\n");
+               pr_warning("%s: Suspend mode LP0 requested, no lp0_vec "
+                          "provided by bootlader -- disabling LP0\n",
+                          __func__);
                plat->suspend_mode = TEGRA_SUSPEND_LP1;
        }
 
-       iram_save_size = &tegra_iram_end - &tegra_iram_start;
+       iram_save_size = tegra_iram_end() - tegra_iram_start();
 
        iram_save = kmalloc(iram_save_size, GFP_KERNEL);
-       if (!iram_save) {
+       if (!iram_save && (plat->suspend_mode >= TEGRA_SUSPEND_LP1)) {
                pr_err("%s: unable to allocate memory for SDRAM self-refresh "
-                      "LP0/LP1 unavailable\n", __func__);
+                      "-- LP0/LP1 unavailable\n", __func__);
                plat->suspend_mode = TEGRA_SUSPEND_LP2;
        }
 
+       /* !!!FIXME!!! THIS IS TEGRA2 ONLY */
        /* Initialize scratch registers used for CPU LP2 synchronization */
        writel(0, pmc + PMC_SCRATCH37);
        writel(0, pmc + PMC_SCRATCH38);
@@ -820,23 +1054,41 @@ void __init tegra_init_suspend(struct tegra_suspend_platform_data *plat)
        pmc_32kwritel(reg, PMC_CTRL);
 
        if (pdata->suspend_mode == TEGRA_SUSPEND_LP0)
-               tegra2_lp0_suspend_init();
+               tegra_lp0_suspend_init();
 
        suspend_set_ops(&tegra_suspend_ops);
+
+       /* Create /sys/power/suspend/type */
+       suspend_kobj = kobject_create_and_add("suspend", power_kobj);
+       if (suspend_kobj) {
+               if (sysfs_create_file(suspend_kobj, \
+                                               &suspend_mode_attribute.attr))
+                       pr_err("%s: sysfs_create_file suspend type failed!\n",
+                                                               __func__);
+       }
+
+       iram_cpu_lp2_mask = tegra_cpu_lp2_mask;
+       iram_cpu_lp1_mask = tegra_cpu_lp1_mask;
+fail:
 #endif
+       if (plat->suspend_mode == TEGRA_SUSPEND_NONE)
+               tegra_lp2_in_idle(false);
 
        current_suspend_mode = plat->suspend_mode;
 }
 
+unsigned long debug_uart_port_base = 0;
+EXPORT_SYMBOL(debug_uart_port_base);
+
 static int tegra_debug_uart_suspend(void)
 {
        void __iomem *uart;
        u32 lcr;
 
-       if (TEGRA_DEBUG_UART_BASE == 0)
+       if (!debug_uart_port_base)
                return 0;
 
-       uart = IO_ADDRESS(TEGRA_DEBUG_UART_BASE);
+       uart = IO_ADDRESS(debug_uart_port_base);
 
        lcr = readb(uart + UART_LCR * 4);
 
@@ -864,10 +1116,10 @@ static void tegra_debug_uart_resume(void)
        void __iomem *uart;
        u32 lcr;
 
-       if (TEGRA_DEBUG_UART_BASE == 0)
+       if (!debug_uart_port_base)
                return;
 
-       uart = IO_ADDRESS(TEGRA_DEBUG_UART_BASE);
+       uart = IO_ADDRESS(debug_uart_port_base);
 
        lcr = tegra_sctx.uart[0];
 
@@ -892,6 +1144,21 @@ static struct syscore_ops tegra_debug_uart_syscore_ops = {
        .resume = tegra_debug_uart_resume,
 };
 
+struct clk *debug_uart_clk = NULL;
+EXPORT_SYMBOL(debug_uart_clk);
+
+void tegra_console_uart_suspend(void)
+{
+       if (console_suspend_enabled && debug_uart_clk)
+               clk_disable(debug_uart_clk);
+}
+
+void tegra_console_uart_resume(void)
+{
+       if (console_suspend_enabled && debug_uart_clk)
+               clk_enable(debug_uart_clk);
+}
+
 static int tegra_debug_uart_syscore_init(void)
 {
        register_syscore_ops(&tegra_debug_uart_syscore_ops);
@@ -900,13 +1167,6 @@ static int tegra_debug_uart_syscore_init(void)
 arch_initcall(tegra_debug_uart_syscore_init);
 
 #ifdef CONFIG_DEBUG_FS
-static const char *tegra_suspend_name[TEGRA_MAX_SUSPEND_MODE] = {
-       [TEGRA_SUSPEND_NONE]    = "none",
-       [TEGRA_SUSPEND_LP2]     = "lp2",
-       [TEGRA_SUSPEND_LP1]     = "lp1",
-       [TEGRA_SUSPEND_LP0]     = "lp0",
-};
-
 static int tegra_suspend_debug_show(struct seq_file *s, void *data)
 {
        seq_printf(s, "%s\n", tegra_suspend_name[*(int *)s->private]);