1860fbde4SDmitry Osipenko // SPDX-License-Identifier: GPL-2.0-only 2860fbde4SDmitry Osipenko /* 3860fbde4SDmitry Osipenko * CPU idle driver for Tegra CPUs 4860fbde4SDmitry Osipenko * 5860fbde4SDmitry Osipenko * Copyright (c) 2010-2013, NVIDIA Corporation. 6860fbde4SDmitry Osipenko * Copyright (c) 2011 Google, Inc. 7860fbde4SDmitry Osipenko * Author: Colin Cross <ccross@android.com> 8860fbde4SDmitry Osipenko * Gary King <gking@nvidia.com> 9860fbde4SDmitry Osipenko * 10860fbde4SDmitry Osipenko * Rework for 3.3 by Peter De Schrijver <pdeschrijver@nvidia.com> 11860fbde4SDmitry Osipenko * 12860fbde4SDmitry Osipenko * Tegra20/124 driver unification by Dmitry Osipenko <digetx@gmail.com> 13860fbde4SDmitry Osipenko */ 14860fbde4SDmitry Osipenko 15860fbde4SDmitry Osipenko #define pr_fmt(fmt) "tegra-cpuidle: " fmt 16860fbde4SDmitry Osipenko 17860fbde4SDmitry Osipenko #include <linux/atomic.h> 18860fbde4SDmitry Osipenko #include <linux/cpuidle.h> 19860fbde4SDmitry Osipenko #include <linux/cpumask.h> 20860fbde4SDmitry Osipenko #include <linux/cpu_pm.h> 21860fbde4SDmitry Osipenko #include <linux/delay.h> 22860fbde4SDmitry Osipenko #include <linux/errno.h> 23860fbde4SDmitry Osipenko #include <linux/platform_device.h> 24860fbde4SDmitry Osipenko #include <linux/types.h> 25860fbde4SDmitry Osipenko 26860fbde4SDmitry Osipenko #include <linux/clk/tegra.h> 2714e086baSDmitry Osipenko #include <linux/firmware/trusted_foundations.h> 28860fbde4SDmitry Osipenko 29860fbde4SDmitry Osipenko #include <soc/tegra/cpuidle.h> 30860fbde4SDmitry Osipenko #include <soc/tegra/flowctrl.h> 31860fbde4SDmitry Osipenko #include <soc/tegra/fuse.h> 32860fbde4SDmitry Osipenko #include <soc/tegra/irq.h> 33860fbde4SDmitry Osipenko #include <soc/tegra/pm.h> 34382ac8e2SDmitry Osipenko #include <soc/tegra/pmc.h> 35860fbde4SDmitry Osipenko 36860fbde4SDmitry Osipenko #include <asm/cpuidle.h> 3714e086baSDmitry Osipenko #include <asm/firmware.h> 38860fbde4SDmitry Osipenko #include <asm/smp_plat.h> 39860fbde4SDmitry Osipenko #include <asm/suspend.h> 40860fbde4SDmitry Osipenko 41860fbde4SDmitry Osipenko enum tegra_state { 42860fbde4SDmitry Osipenko TEGRA_C1, 4319461a49SDmitry Osipenko TEGRA_C7, 44860fbde4SDmitry Osipenko TEGRA_CC6, 45860fbde4SDmitry Osipenko TEGRA_STATE_COUNT, 46860fbde4SDmitry Osipenko }; 47860fbde4SDmitry Osipenko 48860fbde4SDmitry Osipenko static atomic_t tegra_idle_barrier; 49860fbde4SDmitry Osipenko static atomic_t tegra_abort_flag; 50860fbde4SDmitry Osipenko 51860fbde4SDmitry Osipenko static void tegra_cpuidle_report_cpus_state(void) 52860fbde4SDmitry Osipenko { 53860fbde4SDmitry Osipenko unsigned long cpu, lcpu, csr; 54860fbde4SDmitry Osipenko 55860fbde4SDmitry Osipenko for_each_cpu(lcpu, cpu_possible_mask) { 56860fbde4SDmitry Osipenko cpu = cpu_logical_map(lcpu); 57860fbde4SDmitry Osipenko csr = flowctrl_read_cpu_csr(cpu); 58860fbde4SDmitry Osipenko 59860fbde4SDmitry Osipenko pr_err("cpu%lu: online=%d flowctrl_csr=0x%08lx\n", 60860fbde4SDmitry Osipenko cpu, cpu_online(lcpu), csr); 61860fbde4SDmitry Osipenko } 62860fbde4SDmitry Osipenko } 63860fbde4SDmitry Osipenko 64860fbde4SDmitry Osipenko static int tegra_cpuidle_wait_for_secondary_cpus_parking(void) 65860fbde4SDmitry Osipenko { 66860fbde4SDmitry Osipenko unsigned int retries = 3; 67860fbde4SDmitry Osipenko 68860fbde4SDmitry Osipenko while (retries--) { 69860fbde4SDmitry Osipenko unsigned int delay_us = 10; 70860fbde4SDmitry Osipenko unsigned int timeout_us = 500 * 1000 / delay_us; 71860fbde4SDmitry Osipenko 72860fbde4SDmitry Osipenko /* 73860fbde4SDmitry Osipenko * The primary CPU0 core shall wait for the secondaries 74860fbde4SDmitry Osipenko * shutdown in order to power-off CPU's cluster safely. 75860fbde4SDmitry Osipenko * The timeout value depends on the current CPU frequency, 76860fbde4SDmitry Osipenko * it takes about 40-150us in average and over 1000us in 77860fbde4SDmitry Osipenko * a worst case scenario. 78860fbde4SDmitry Osipenko */ 79860fbde4SDmitry Osipenko do { 80860fbde4SDmitry Osipenko if (tegra_cpu_rail_off_ready()) 81860fbde4SDmitry Osipenko return 0; 82860fbde4SDmitry Osipenko 83860fbde4SDmitry Osipenko udelay(delay_us); 84860fbde4SDmitry Osipenko 85860fbde4SDmitry Osipenko } while (timeout_us--); 86860fbde4SDmitry Osipenko 87860fbde4SDmitry Osipenko pr_err("secondary CPU taking too long to park\n"); 88860fbde4SDmitry Osipenko 89860fbde4SDmitry Osipenko tegra_cpuidle_report_cpus_state(); 90860fbde4SDmitry Osipenko } 91860fbde4SDmitry Osipenko 92860fbde4SDmitry Osipenko pr_err("timed out waiting secondaries to park\n"); 93860fbde4SDmitry Osipenko 94860fbde4SDmitry Osipenko return -ETIMEDOUT; 95860fbde4SDmitry Osipenko } 96860fbde4SDmitry Osipenko 97860fbde4SDmitry Osipenko static void tegra_cpuidle_unpark_secondary_cpus(void) 98860fbde4SDmitry Osipenko { 99860fbde4SDmitry Osipenko unsigned int cpu, lcpu; 100860fbde4SDmitry Osipenko 101860fbde4SDmitry Osipenko for_each_cpu(lcpu, cpu_online_mask) { 102860fbde4SDmitry Osipenko cpu = cpu_logical_map(lcpu); 103860fbde4SDmitry Osipenko 104860fbde4SDmitry Osipenko if (cpu > 0) { 105860fbde4SDmitry Osipenko tegra_enable_cpu_clock(cpu); 106860fbde4SDmitry Osipenko tegra_cpu_out_of_reset(cpu); 107860fbde4SDmitry Osipenko flowctrl_write_cpu_halt(cpu, 0); 108860fbde4SDmitry Osipenko } 109860fbde4SDmitry Osipenko } 110860fbde4SDmitry Osipenko } 111860fbde4SDmitry Osipenko 112860fbde4SDmitry Osipenko static int tegra_cpuidle_cc6_enter(unsigned int cpu) 113860fbde4SDmitry Osipenko { 114860fbde4SDmitry Osipenko int ret; 115860fbde4SDmitry Osipenko 116860fbde4SDmitry Osipenko if (cpu > 0) { 117860fbde4SDmitry Osipenko ret = cpu_suspend(cpu, tegra_pm_park_secondary_cpu); 118860fbde4SDmitry Osipenko } else { 119860fbde4SDmitry Osipenko ret = tegra_cpuidle_wait_for_secondary_cpus_parking(); 120860fbde4SDmitry Osipenko if (!ret) 121860fbde4SDmitry Osipenko ret = tegra_pm_enter_lp2(); 122860fbde4SDmitry Osipenko 123860fbde4SDmitry Osipenko tegra_cpuidle_unpark_secondary_cpus(); 124860fbde4SDmitry Osipenko } 125860fbde4SDmitry Osipenko 126860fbde4SDmitry Osipenko return ret; 127860fbde4SDmitry Osipenko } 128860fbde4SDmitry Osipenko 12919461a49SDmitry Osipenko static int tegra_cpuidle_c7_enter(void) 13019461a49SDmitry Osipenko { 13114e086baSDmitry Osipenko int err; 13214e086baSDmitry Osipenko 13314e086baSDmitry Osipenko err = call_firmware_op(prepare_idle, TF_PM_MODE_LP2_NOFLUSH_L2); 13432c8c34dSDmitry Osipenko if (err && err != -ENOSYS) 13514e086baSDmitry Osipenko return err; 13614e086baSDmitry Osipenko 13719461a49SDmitry Osipenko return cpu_suspend(0, tegra30_pm_secondary_cpu_suspend); 13819461a49SDmitry Osipenko } 13919461a49SDmitry Osipenko 140860fbde4SDmitry Osipenko static int tegra_cpuidle_coupled_barrier(struct cpuidle_device *dev) 141860fbde4SDmitry Osipenko { 142860fbde4SDmitry Osipenko if (tegra_pending_sgi()) { 143860fbde4SDmitry Osipenko /* 144860fbde4SDmitry Osipenko * CPU got local interrupt that will be lost after GIC's 145860fbde4SDmitry Osipenko * shutdown because GIC driver doesn't save/restore the 146860fbde4SDmitry Osipenko * pending SGI state across CPU cluster PM. Abort and retry 147860fbde4SDmitry Osipenko * next time. 148860fbde4SDmitry Osipenko */ 149860fbde4SDmitry Osipenko atomic_set(&tegra_abort_flag, 1); 150860fbde4SDmitry Osipenko } 151860fbde4SDmitry Osipenko 152860fbde4SDmitry Osipenko cpuidle_coupled_parallel_barrier(dev, &tegra_idle_barrier); 153860fbde4SDmitry Osipenko 154860fbde4SDmitry Osipenko if (atomic_read(&tegra_abort_flag)) { 155860fbde4SDmitry Osipenko cpuidle_coupled_parallel_barrier(dev, &tegra_idle_barrier); 156860fbde4SDmitry Osipenko atomic_set(&tegra_abort_flag, 0); 157860fbde4SDmitry Osipenko return -EINTR; 158860fbde4SDmitry Osipenko } 159860fbde4SDmitry Osipenko 160860fbde4SDmitry Osipenko return 0; 161860fbde4SDmitry Osipenko } 162860fbde4SDmitry Osipenko 163860fbde4SDmitry Osipenko static int tegra_cpuidle_state_enter(struct cpuidle_device *dev, 164860fbde4SDmitry Osipenko int index, unsigned int cpu) 165860fbde4SDmitry Osipenko { 1661170433eSDmitry Osipenko int err; 167860fbde4SDmitry Osipenko 168860fbde4SDmitry Osipenko /* 169860fbde4SDmitry Osipenko * CC6 state is the "CPU cluster power-off" state. In order to 170860fbde4SDmitry Osipenko * enter this state, at first the secondary CPU cores need to be 171860fbde4SDmitry Osipenko * parked into offline mode, then the last CPU should clean out 172860fbde4SDmitry Osipenko * remaining dirty cache lines into DRAM and trigger Flow Controller 173860fbde4SDmitry Osipenko * logic that turns off the cluster's power domain (which includes 174860fbde4SDmitry Osipenko * CPU cores, GIC and L2 cache). 175860fbde4SDmitry Osipenko */ 176860fbde4SDmitry Osipenko if (index == TEGRA_CC6) { 1771170433eSDmitry Osipenko err = tegra_cpuidle_coupled_barrier(dev); 1781170433eSDmitry Osipenko if (err) 1791170433eSDmitry Osipenko return err; 180860fbde4SDmitry Osipenko } 181860fbde4SDmitry Osipenko 182860fbde4SDmitry Osipenko local_fiq_disable(); 183c39de538SDmitry Osipenko RCU_NONIDLE(tegra_pm_set_cpu_in_lp2()); 184860fbde4SDmitry Osipenko cpu_pm_enter(); 185860fbde4SDmitry Osipenko 186860fbde4SDmitry Osipenko switch (index) { 18719461a49SDmitry Osipenko case TEGRA_C7: 1881170433eSDmitry Osipenko err = tegra_cpuidle_c7_enter(); 18919461a49SDmitry Osipenko break; 19019461a49SDmitry Osipenko 191860fbde4SDmitry Osipenko case TEGRA_CC6: 1921170433eSDmitry Osipenko err = tegra_cpuidle_cc6_enter(cpu); 193860fbde4SDmitry Osipenko break; 194860fbde4SDmitry Osipenko 195860fbde4SDmitry Osipenko default: 1961170433eSDmitry Osipenko err = -EINVAL; 197860fbde4SDmitry Osipenko break; 198860fbde4SDmitry Osipenko } 199860fbde4SDmitry Osipenko 200860fbde4SDmitry Osipenko cpu_pm_exit(); 201c39de538SDmitry Osipenko RCU_NONIDLE(tegra_pm_clear_cpu_in_lp2()); 202860fbde4SDmitry Osipenko local_fiq_enable(); 203860fbde4SDmitry Osipenko 2041170433eSDmitry Osipenko return err ?: index; 205860fbde4SDmitry Osipenko } 206860fbde4SDmitry Osipenko 20719461a49SDmitry Osipenko static int tegra_cpuidle_adjust_state_index(int index, unsigned int cpu) 20819461a49SDmitry Osipenko { 20919461a49SDmitry Osipenko /* 21019461a49SDmitry Osipenko * On Tegra30 CPU0 can't be power-gated separately from secondary 21119461a49SDmitry Osipenko * cores because it gates the whole CPU cluster. 21219461a49SDmitry Osipenko */ 21319461a49SDmitry Osipenko if (cpu > 0 || index != TEGRA_C7 || tegra_get_chip_id() != TEGRA30) 21419461a49SDmitry Osipenko return index; 21519461a49SDmitry Osipenko 21619461a49SDmitry Osipenko /* put CPU0 into C1 if C7 is requested and secondaries are online */ 21719461a49SDmitry Osipenko if (!IS_ENABLED(CONFIG_PM_SLEEP) || num_online_cpus() > 1) 21819461a49SDmitry Osipenko index = TEGRA_C1; 21919461a49SDmitry Osipenko else 22019461a49SDmitry Osipenko index = TEGRA_CC6; 22119461a49SDmitry Osipenko 22219461a49SDmitry Osipenko return index; 22319461a49SDmitry Osipenko } 22419461a49SDmitry Osipenko 225860fbde4SDmitry Osipenko static int tegra_cpuidle_enter(struct cpuidle_device *dev, 226860fbde4SDmitry Osipenko struct cpuidle_driver *drv, 227860fbde4SDmitry Osipenko int index) 228860fbde4SDmitry Osipenko { 229860fbde4SDmitry Osipenko unsigned int cpu = cpu_logical_map(dev->cpu); 2301170433eSDmitry Osipenko int ret; 231860fbde4SDmitry Osipenko 23219461a49SDmitry Osipenko index = tegra_cpuidle_adjust_state_index(index, cpu); 23319461a49SDmitry Osipenko if (dev->states_usage[index].disable) 23419461a49SDmitry Osipenko return -1; 23519461a49SDmitry Osipenko 23619461a49SDmitry Osipenko if (index == TEGRA_C1) 2371170433eSDmitry Osipenko ret = arm_cpuidle_simple_enter(dev, drv, index); 23819461a49SDmitry Osipenko else 2391170433eSDmitry Osipenko ret = tegra_cpuidle_state_enter(dev, index, cpu); 24019461a49SDmitry Osipenko 2411170433eSDmitry Osipenko if (ret < 0) { 2421170433eSDmitry Osipenko if (ret != -EINTR || index != TEGRA_CC6) 2431170433eSDmitry Osipenko pr_err_once("failed to enter state %d err: %d\n", 2441170433eSDmitry Osipenko index, ret); 2451170433eSDmitry Osipenko index = -1; 2461170433eSDmitry Osipenko } else { 2471170433eSDmitry Osipenko index = ret; 2481170433eSDmitry Osipenko } 249860fbde4SDmitry Osipenko 2501170433eSDmitry Osipenko return index; 251860fbde4SDmitry Osipenko } 252860fbde4SDmitry Osipenko 253efe97112SNeal Liu static int tegra114_enter_s2idle(struct cpuidle_device *dev, 25414e086baSDmitry Osipenko struct cpuidle_driver *drv, 25514e086baSDmitry Osipenko int index) 25614e086baSDmitry Osipenko { 25714e086baSDmitry Osipenko tegra_cpuidle_enter(dev, drv, index); 258efe97112SNeal Liu 259efe97112SNeal Liu return 0; 26014e086baSDmitry Osipenko } 26114e086baSDmitry Osipenko 262860fbde4SDmitry Osipenko /* 263860fbde4SDmitry Osipenko * The previous versions of Tegra CPUIDLE driver used a different "legacy" 264860fbde4SDmitry Osipenko * terminology for naming of the idling states, while this driver uses the 265860fbde4SDmitry Osipenko * new terminology. 266860fbde4SDmitry Osipenko * 267860fbde4SDmitry Osipenko * Mapping of the old terms into the new ones: 268860fbde4SDmitry Osipenko * 269860fbde4SDmitry Osipenko * Old | New 270860fbde4SDmitry Osipenko * --------- 271860fbde4SDmitry Osipenko * LP3 | C1 (CPU core clock gating) 272860fbde4SDmitry Osipenko * LP2 | C7 (CPU core power gating) 273860fbde4SDmitry Osipenko * LP2 | CC6 (CPU cluster power gating) 274860fbde4SDmitry Osipenko * 275860fbde4SDmitry Osipenko * Note that that the older CPUIDLE driver versions didn't explicitly 276860fbde4SDmitry Osipenko * differentiate the LP2 states because these states either used the same 277860fbde4SDmitry Osipenko * code path or because CC6 wasn't supported. 278860fbde4SDmitry Osipenko */ 279860fbde4SDmitry Osipenko static struct cpuidle_driver tegra_idle_driver = { 280860fbde4SDmitry Osipenko .name = "tegra_idle", 281860fbde4SDmitry Osipenko .states = { 282860fbde4SDmitry Osipenko [TEGRA_C1] = ARM_CPUIDLE_WFI_STATE_PWR(600), 28319461a49SDmitry Osipenko [TEGRA_C7] = { 28419461a49SDmitry Osipenko .enter = tegra_cpuidle_enter, 28519461a49SDmitry Osipenko .exit_latency = 2000, 28619461a49SDmitry Osipenko .target_residency = 2200, 28719461a49SDmitry Osipenko .power_usage = 100, 28819461a49SDmitry Osipenko .flags = CPUIDLE_FLAG_TIMER_STOP, 28919461a49SDmitry Osipenko .name = "C7", 29019461a49SDmitry Osipenko .desc = "CPU core powered off", 29119461a49SDmitry Osipenko }, 292860fbde4SDmitry Osipenko [TEGRA_CC6] = { 293860fbde4SDmitry Osipenko .enter = tegra_cpuidle_enter, 294860fbde4SDmitry Osipenko .exit_latency = 5000, 295860fbde4SDmitry Osipenko .target_residency = 10000, 296860fbde4SDmitry Osipenko .power_usage = 0, 297860fbde4SDmitry Osipenko .flags = CPUIDLE_FLAG_TIMER_STOP | 298860fbde4SDmitry Osipenko CPUIDLE_FLAG_COUPLED, 299860fbde4SDmitry Osipenko .name = "CC6", 300860fbde4SDmitry Osipenko .desc = "CPU cluster powered off", 301860fbde4SDmitry Osipenko }, 302860fbde4SDmitry Osipenko }, 303860fbde4SDmitry Osipenko .state_count = TEGRA_STATE_COUNT, 304860fbde4SDmitry Osipenko .safe_state_index = TEGRA_C1, 305860fbde4SDmitry Osipenko }; 306860fbde4SDmitry Osipenko 307860fbde4SDmitry Osipenko static inline void tegra_cpuidle_disable_state(enum tegra_state state) 308860fbde4SDmitry Osipenko { 309860fbde4SDmitry Osipenko cpuidle_driver_state_disabled(&tegra_idle_driver, state, true); 310860fbde4SDmitry Osipenko } 311860fbde4SDmitry Osipenko 312860fbde4SDmitry Osipenko /* 313860fbde4SDmitry Osipenko * Tegra20 HW appears to have a bug such that PCIe device interrupts, whether 314860fbde4SDmitry Osipenko * they are legacy IRQs or MSI, are lost when CC6 is enabled. To work around 315860fbde4SDmitry Osipenko * this, simply disable CC6 if the PCI driver and DT node are both enabled. 316860fbde4SDmitry Osipenko */ 317860fbde4SDmitry Osipenko void tegra_cpuidle_pcie_irqs_in_use(void) 318860fbde4SDmitry Osipenko { 319860fbde4SDmitry Osipenko struct cpuidle_state *state_cc6 = &tegra_idle_driver.states[TEGRA_CC6]; 320860fbde4SDmitry Osipenko 321860fbde4SDmitry Osipenko if ((state_cc6->flags & CPUIDLE_FLAG_UNUSABLE) || 322860fbde4SDmitry Osipenko tegra_get_chip_id() != TEGRA20) 323860fbde4SDmitry Osipenko return; 324860fbde4SDmitry Osipenko 325860fbde4SDmitry Osipenko pr_info("disabling CC6 state, since PCIe IRQs are in use\n"); 326860fbde4SDmitry Osipenko tegra_cpuidle_disable_state(TEGRA_CC6); 327860fbde4SDmitry Osipenko } 328860fbde4SDmitry Osipenko 32914e086baSDmitry Osipenko static void tegra_cpuidle_setup_tegra114_c7_state(void) 33014e086baSDmitry Osipenko { 33114e086baSDmitry Osipenko struct cpuidle_state *s = &tegra_idle_driver.states[TEGRA_C7]; 33214e086baSDmitry Osipenko 33314e086baSDmitry Osipenko s->enter_s2idle = tegra114_enter_s2idle; 33414e086baSDmitry Osipenko s->target_residency = 1000; 33514e086baSDmitry Osipenko s->exit_latency = 500; 33614e086baSDmitry Osipenko } 33714e086baSDmitry Osipenko 338860fbde4SDmitry Osipenko static int tegra_cpuidle_probe(struct platform_device *pdev) 339860fbde4SDmitry Osipenko { 340*bdb1ffdaSDmitry Osipenko if (tegra_pmc_get_suspend_mode() == TEGRA_SUSPEND_NOT_READY) 341*bdb1ffdaSDmitry Osipenko return -EPROBE_DEFER; 342*bdb1ffdaSDmitry Osipenko 343382ac8e2SDmitry Osipenko /* LP2 could be disabled in device-tree */ 344382ac8e2SDmitry Osipenko if (tegra_pmc_get_suspend_mode() < TEGRA_SUSPEND_LP2) 345382ac8e2SDmitry Osipenko tegra_cpuidle_disable_state(TEGRA_CC6); 346382ac8e2SDmitry Osipenko 347860fbde4SDmitry Osipenko /* 348860fbde4SDmitry Osipenko * Required suspend-resume functionality, which is provided by the 349860fbde4SDmitry Osipenko * Tegra-arch core and PMC driver, is unavailable if PM-sleep option 350860fbde4SDmitry Osipenko * is disabled. 351860fbde4SDmitry Osipenko */ 35219461a49SDmitry Osipenko if (!IS_ENABLED(CONFIG_PM_SLEEP)) { 35319461a49SDmitry Osipenko tegra_cpuidle_disable_state(TEGRA_C7); 354860fbde4SDmitry Osipenko tegra_cpuidle_disable_state(TEGRA_CC6); 35519461a49SDmitry Osipenko } 35619461a49SDmitry Osipenko 35719461a49SDmitry Osipenko /* 35819461a49SDmitry Osipenko * Generic WFI state (also known as C1 or LP3) and the coupled CPU 35919461a49SDmitry Osipenko * cluster power-off (CC6 or LP2) states are common for all Tegra SoCs. 36019461a49SDmitry Osipenko */ 36119461a49SDmitry Osipenko switch (tegra_get_chip_id()) { 36219461a49SDmitry Osipenko case TEGRA20: 36319461a49SDmitry Osipenko /* Tegra20 isn't capable to power-off individual CPU cores */ 36419461a49SDmitry Osipenko tegra_cpuidle_disable_state(TEGRA_C7); 36519461a49SDmitry Osipenko break; 36619461a49SDmitry Osipenko 36719461a49SDmitry Osipenko case TEGRA30: 36819461a49SDmitry Osipenko break; 36919461a49SDmitry Osipenko 37014e086baSDmitry Osipenko case TEGRA114: 37114e086baSDmitry Osipenko case TEGRA124: 37214e086baSDmitry Osipenko tegra_cpuidle_setup_tegra114_c7_state(); 37314e086baSDmitry Osipenko 37414e086baSDmitry Osipenko /* coupled CC6 (LP2) state isn't implemented yet */ 37514e086baSDmitry Osipenko tegra_cpuidle_disable_state(TEGRA_CC6); 37614e086baSDmitry Osipenko break; 37714e086baSDmitry Osipenko 37819461a49SDmitry Osipenko default: 37919461a49SDmitry Osipenko return -EINVAL; 38019461a49SDmitry Osipenko } 381860fbde4SDmitry Osipenko 382860fbde4SDmitry Osipenko return cpuidle_register(&tegra_idle_driver, cpu_possible_mask); 383860fbde4SDmitry Osipenko } 384860fbde4SDmitry Osipenko 385860fbde4SDmitry Osipenko static struct platform_driver tegra_cpuidle_driver = { 386860fbde4SDmitry Osipenko .probe = tegra_cpuidle_probe, 387860fbde4SDmitry Osipenko .driver = { 388860fbde4SDmitry Osipenko .name = "tegra-cpuidle", 389860fbde4SDmitry Osipenko }, 390860fbde4SDmitry Osipenko }; 391860fbde4SDmitry Osipenko builtin_platform_driver(tegra_cpuidle_driver); 392