obj-$(CONFIG_CPU_IDLE)                 += cpuidle.o
 obj-$(CONFIG_ARCH_TEGRA_2x_SOC)                += pm-tegra20.o
 obj-$(CONFIG_ARCH_TEGRA_3x_SOC)                += pm-tegra30.o
-ifeq ($(CONFIG_CPU_IDLE),y)
-obj-$(CONFIG_ARCH_TEGRA_3x_SOC)                += cpuidle-tegra30.o
-endif
 obj-$(CONFIG_SMP)                      += platsmp.o
 obj-$(CONFIG_HOTPLUG_CPU)               += hotplug.o
 
 
+++ /dev/null
-// SPDX-License-Identifier: GPL-2.0-or-later
-/*
- * CPU idle driver for Tegra CPUs
- *
- * Copyright (c) 2010-2012, NVIDIA Corporation.
- * Copyright (c) 2011 Google, Inc.
- * Author: Colin Cross <ccross@android.com>
- *         Gary King <gking@nvidia.com>
- *
- * Rework for 3.3 by Peter De Schrijver <pdeschrijver@nvidia.com>
- */
-
-#include <linux/clk/tegra.h>
-#include <linux/tick.h>
-#include <linux/cpuidle.h>
-#include <linux/cpu_pm.h>
-#include <linux/kernel.h>
-#include <linux/module.h>
-
-#include <soc/tegra/pm.h>
-
-#include <asm/cpuidle.h>
-#include <asm/smp_plat.h>
-#include <asm/suspend.h>
-
-#include "cpuidle.h"
-#include "sleep.h"
-
-#ifdef CONFIG_PM_SLEEP
-static int tegra30_idle_lp2(struct cpuidle_device *dev,
-                           struct cpuidle_driver *drv,
-                           int index);
-#endif
-
-static struct cpuidle_driver tegra_idle_driver = {
-       .name = "tegra_idle",
-       .owner = THIS_MODULE,
-#ifdef CONFIG_PM_SLEEP
-       .state_count = 2,
-#else
-       .state_count = 1,
-#endif
-       .states = {
-               [0] = ARM_CPUIDLE_WFI_STATE_PWR(600),
-#ifdef CONFIG_PM_SLEEP
-               [1] = {
-                       .enter                  = tegra30_idle_lp2,
-                       .exit_latency           = 2000,
-                       .target_residency       = 2200,
-                       .power_usage            = 0,
-                       .flags                  = CPUIDLE_FLAG_TIMER_STOP,
-                       .name                   = "powered-down",
-                       .desc                   = "CPU power gated",
-               },
-#endif
-       },
-};
-
-#ifdef CONFIG_PM_SLEEP
-static bool tegra30_cpu_cluster_power_down(struct cpuidle_device *dev,
-                                          struct cpuidle_driver *drv,
-                                          int index)
-{
-       /* All CPUs entering LP2 is not working.
-        * Don't let CPU0 enter LP2 when any secondary CPU is online.
-        */
-       if (num_online_cpus() > 1 || !tegra_cpu_rail_off_ready()) {
-               cpu_do_idle();
-               return false;
-       }
-
-       return !tegra_pm_enter_lp2();
-}
-
-#ifdef CONFIG_SMP
-static bool tegra30_cpu_core_power_down(struct cpuidle_device *dev,
-                                       struct cpuidle_driver *drv,
-                                       int index)
-{
-       smp_wmb();
-
-       cpu_suspend(0, tegra30_pm_secondary_cpu_suspend);
-
-       return true;
-}
-#else
-static inline bool tegra30_cpu_core_power_down(struct cpuidle_device *dev,
-                                              struct cpuidle_driver *drv,
-                                              int index)
-{
-       return true;
-}
-#endif
-
-static int tegra30_idle_lp2(struct cpuidle_device *dev,
-                           struct cpuidle_driver *drv,
-                           int index)
-{
-       bool entered_lp2 = false;
-
-       local_fiq_disable();
-
-       tegra_pm_set_cpu_in_lp2();
-       cpu_pm_enter();
-
-       if (dev->cpu == 0)
-               entered_lp2 = tegra30_cpu_cluster_power_down(dev, drv, index);
-       else
-               entered_lp2 = tegra30_cpu_core_power_down(dev, drv, index);
-
-       cpu_pm_exit();
-       tegra_pm_clear_cpu_in_lp2();
-
-       local_fiq_enable();
-
-       return (entered_lp2) ? index : 0;
-}
-#endif
-
-int __init tegra30_cpuidle_init(void)
-{
-       return cpuidle_register(&tegra_idle_driver, NULL);
-}
 
 {
        switch (tegra_get_chip_id()) {
        case TEGRA20:
-               platform_device_register_simple("tegra-cpuidle", -1, NULL, 0);
-               break;
        case TEGRA30:
-               if (IS_ENABLED(CONFIG_ARCH_TEGRA_3x_SOC))
-                       tegra30_cpuidle_init();
+               platform_device_register_simple("tegra-cpuidle", -1, NULL, 0);
                break;
        case TEGRA114:
        case TEGRA124:
 
 #define __MACH_TEGRA_CPUIDLE_H
 
 #ifdef CONFIG_CPU_IDLE
-int tegra30_cpuidle_init(void);
 int tegra114_cpuidle_init(void);
 void tegra_cpuidle_init(void);
 #else
 
 
 enum tegra_state {
        TEGRA_C1,
+       TEGRA_C7,
        TEGRA_CC6,
        TEGRA_STATE_COUNT,
 };
        return ret;
 }
 
+static int tegra_cpuidle_c7_enter(void)
+{
+       return cpu_suspend(0, tegra30_pm_secondary_cpu_suspend);
+}
+
 static int tegra_cpuidle_coupled_barrier(struct cpuidle_device *dev)
 {
        if (tegra_pending_sgi()) {
        cpu_pm_enter();
 
        switch (index) {
+       case TEGRA_C7:
+               ret = tegra_cpuidle_c7_enter();
+               break;
+
        case TEGRA_CC6:
                ret = tegra_cpuidle_cc6_enter(cpu);
                break;
        return ret;
 }
 
+static int tegra_cpuidle_adjust_state_index(int index, unsigned int cpu)
+{
+       /*
+        * On Tegra30 CPU0 can't be power-gated separately from secondary
+        * cores because it gates the whole CPU cluster.
+        */
+       if (cpu > 0 || index != TEGRA_C7 || tegra_get_chip_id() != TEGRA30)
+               return index;
+
+       /* put CPU0 into C1 if C7 is requested and secondaries are online */
+       if (!IS_ENABLED(CONFIG_PM_SLEEP) || num_online_cpus() > 1)
+               index = TEGRA_C1;
+       else
+               index = TEGRA_CC6;
+
+       return index;
+}
+
 static int tegra_cpuidle_enter(struct cpuidle_device *dev,
                               struct cpuidle_driver *drv,
                               int index)
        unsigned int cpu = cpu_logical_map(dev->cpu);
        int err;
 
-       err = tegra_cpuidle_state_enter(dev, index, cpu);
-       if (err && err != -EINTR)
-               pr_err_once("cpu%u failed to enter idle state %d err: %d\n",
-                           cpu, index, err);
+       index = tegra_cpuidle_adjust_state_index(index, cpu);
+       if (dev->states_usage[index].disable)
+               return -1;
+
+       if (index == TEGRA_C1)
+               err = arm_cpuidle_simple_enter(dev, drv, index);
+       else
+               err = tegra_cpuidle_state_enter(dev, index, cpu);
+
+       if (err && (err != -EINTR || index != TEGRA_CC6))
+               pr_err_once("failed to enter state %d err: %d\n", index, err);
 
        return err ? -1 : index;
 }
        .name = "tegra_idle",
        .states = {
                [TEGRA_C1] = ARM_CPUIDLE_WFI_STATE_PWR(600),
+               [TEGRA_C7] = {
+                       .enter                  = tegra_cpuidle_enter,
+                       .exit_latency           = 2000,
+                       .target_residency       = 2200,
+                       .power_usage            = 100,
+                       .flags                  = CPUIDLE_FLAG_TIMER_STOP,
+                       .name                   = "C7",
+                       .desc                   = "CPU core powered off",
+               },
                [TEGRA_CC6] = {
                        .enter                  = tegra_cpuidle_enter,
                        .exit_latency           = 5000,
         * Tegra-arch core and PMC driver, is unavailable if PM-sleep option
         * is disabled.
         */
-       if (!IS_ENABLED(CONFIG_PM_SLEEP))
+       if (!IS_ENABLED(CONFIG_PM_SLEEP)) {
+               tegra_cpuidle_disable_state(TEGRA_C7);
                tegra_cpuidle_disable_state(TEGRA_CC6);
+       }
+
+       /*
+        * Generic WFI state (also known as C1 or LP3) and the coupled CPU
+        * cluster power-off (CC6 or LP2) states are common for all Tegra SoCs.
+        */
+       switch (tegra_get_chip_id()) {
+       case TEGRA20:
+               /* Tegra20 isn't capable to power-off individual CPU cores */
+               tegra_cpuidle_disable_state(TEGRA_C7);
+               break;
+
+       case TEGRA30:
+               tegra_cpuidle_disable_state(TEGRA_CC6);
+               break;
+
+       default:
+               return -EINVAL;
+       }
 
        return cpuidle_register(&tegra_idle_driver, cpu_possible_mask);
 }