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> 34860fbde4SDmitry Osipenko 35860fbde4SDmitry Osipenko #include <asm/cpuidle.h> 3614e086baSDmitry Osipenko #include <asm/firmware.h> 37860fbde4SDmitry Osipenko #include <asm/smp_plat.h> 38860fbde4SDmitry Osipenko #include <asm/suspend.h> 39860fbde4SDmitry Osipenko 40860fbde4SDmitry Osipenko enum tegra_state { 41860fbde4SDmitry Osipenko TEGRA_C1, 4219461a49SDmitry Osipenko TEGRA_C7, 43860fbde4SDmitry Osipenko TEGRA_CC6, 44860fbde4SDmitry Osipenko TEGRA_STATE_COUNT, 45860fbde4SDmitry Osipenko }; 46860fbde4SDmitry Osipenko 47860fbde4SDmitry Osipenko static atomic_t tegra_idle_barrier; 48860fbde4SDmitry Osipenko static atomic_t tegra_abort_flag; 49860fbde4SDmitry Osipenko 5014e086baSDmitry Osipenko static inline bool tegra_cpuidle_using_firmware(void) 5114e086baSDmitry Osipenko { 5214e086baSDmitry Osipenko return firmware_ops->prepare_idle && firmware_ops->do_idle; 5314e086baSDmitry Osipenko } 5414e086baSDmitry Osipenko 55860fbde4SDmitry Osipenko static void tegra_cpuidle_report_cpus_state(void) 56860fbde4SDmitry Osipenko { 57860fbde4SDmitry Osipenko unsigned long cpu, lcpu, csr; 58860fbde4SDmitry Osipenko 59860fbde4SDmitry Osipenko for_each_cpu(lcpu, cpu_possible_mask) { 60860fbde4SDmitry Osipenko cpu = cpu_logical_map(lcpu); 61860fbde4SDmitry Osipenko csr = flowctrl_read_cpu_csr(cpu); 62860fbde4SDmitry Osipenko 63860fbde4SDmitry Osipenko pr_err("cpu%lu: online=%d flowctrl_csr=0x%08lx\n", 64860fbde4SDmitry Osipenko cpu, cpu_online(lcpu), csr); 65860fbde4SDmitry Osipenko } 66860fbde4SDmitry Osipenko } 67860fbde4SDmitry Osipenko 68860fbde4SDmitry Osipenko static int tegra_cpuidle_wait_for_secondary_cpus_parking(void) 69860fbde4SDmitry Osipenko { 70860fbde4SDmitry Osipenko unsigned int retries = 3; 71860fbde4SDmitry Osipenko 72860fbde4SDmitry Osipenko while (retries--) { 73860fbde4SDmitry Osipenko unsigned int delay_us = 10; 74860fbde4SDmitry Osipenko unsigned int timeout_us = 500 * 1000 / delay_us; 75860fbde4SDmitry Osipenko 76860fbde4SDmitry Osipenko /* 77860fbde4SDmitry Osipenko * The primary CPU0 core shall wait for the secondaries 78860fbde4SDmitry Osipenko * shutdown in order to power-off CPU's cluster safely. 79860fbde4SDmitry Osipenko * The timeout value depends on the current CPU frequency, 80860fbde4SDmitry Osipenko * it takes about 40-150us in average and over 1000us in 81860fbde4SDmitry Osipenko * a worst case scenario. 82860fbde4SDmitry Osipenko */ 83860fbde4SDmitry Osipenko do { 84860fbde4SDmitry Osipenko if (tegra_cpu_rail_off_ready()) 85860fbde4SDmitry Osipenko return 0; 86860fbde4SDmitry Osipenko 87860fbde4SDmitry Osipenko udelay(delay_us); 88860fbde4SDmitry Osipenko 89860fbde4SDmitry Osipenko } while (timeout_us--); 90860fbde4SDmitry Osipenko 91860fbde4SDmitry Osipenko pr_err("secondary CPU taking too long to park\n"); 92860fbde4SDmitry Osipenko 93860fbde4SDmitry Osipenko tegra_cpuidle_report_cpus_state(); 94860fbde4SDmitry Osipenko } 95860fbde4SDmitry Osipenko 96860fbde4SDmitry Osipenko pr_err("timed out waiting secondaries to park\n"); 97860fbde4SDmitry Osipenko 98860fbde4SDmitry Osipenko return -ETIMEDOUT; 99860fbde4SDmitry Osipenko } 100860fbde4SDmitry Osipenko 101860fbde4SDmitry Osipenko static void tegra_cpuidle_unpark_secondary_cpus(void) 102860fbde4SDmitry Osipenko { 103860fbde4SDmitry Osipenko unsigned int cpu, lcpu; 104860fbde4SDmitry Osipenko 105860fbde4SDmitry Osipenko for_each_cpu(lcpu, cpu_online_mask) { 106860fbde4SDmitry Osipenko cpu = cpu_logical_map(lcpu); 107860fbde4SDmitry Osipenko 108860fbde4SDmitry Osipenko if (cpu > 0) { 109860fbde4SDmitry Osipenko tegra_enable_cpu_clock(cpu); 110860fbde4SDmitry Osipenko tegra_cpu_out_of_reset(cpu); 111860fbde4SDmitry Osipenko flowctrl_write_cpu_halt(cpu, 0); 112860fbde4SDmitry Osipenko } 113860fbde4SDmitry Osipenko } 114860fbde4SDmitry Osipenko } 115860fbde4SDmitry Osipenko 116860fbde4SDmitry Osipenko static int tegra_cpuidle_cc6_enter(unsigned int cpu) 117860fbde4SDmitry Osipenko { 118860fbde4SDmitry Osipenko int ret; 119860fbde4SDmitry Osipenko 120860fbde4SDmitry Osipenko if (cpu > 0) { 121860fbde4SDmitry Osipenko ret = cpu_suspend(cpu, tegra_pm_park_secondary_cpu); 122860fbde4SDmitry Osipenko } else { 123860fbde4SDmitry Osipenko ret = tegra_cpuidle_wait_for_secondary_cpus_parking(); 124860fbde4SDmitry Osipenko if (!ret) 125860fbde4SDmitry Osipenko ret = tegra_pm_enter_lp2(); 126860fbde4SDmitry Osipenko 127860fbde4SDmitry Osipenko tegra_cpuidle_unpark_secondary_cpus(); 128860fbde4SDmitry Osipenko } 129860fbde4SDmitry Osipenko 130860fbde4SDmitry Osipenko return ret; 131860fbde4SDmitry Osipenko } 132860fbde4SDmitry Osipenko 13319461a49SDmitry Osipenko static int tegra_cpuidle_c7_enter(void) 13419461a49SDmitry Osipenko { 13514e086baSDmitry Osipenko int err; 13614e086baSDmitry Osipenko 13714e086baSDmitry Osipenko if (tegra_cpuidle_using_firmware()) { 13814e086baSDmitry Osipenko err = call_firmware_op(prepare_idle, TF_PM_MODE_LP2_NOFLUSH_L2); 13914e086baSDmitry Osipenko if (err) 14014e086baSDmitry Osipenko return err; 14114e086baSDmitry Osipenko 14214e086baSDmitry Osipenko return call_firmware_op(do_idle, 0); 14314e086baSDmitry Osipenko } 14414e086baSDmitry Osipenko 14519461a49SDmitry Osipenko return cpu_suspend(0, tegra30_pm_secondary_cpu_suspend); 14619461a49SDmitry Osipenko } 14719461a49SDmitry Osipenko 148860fbde4SDmitry Osipenko static int tegra_cpuidle_coupled_barrier(struct cpuidle_device *dev) 149860fbde4SDmitry Osipenko { 150860fbde4SDmitry Osipenko if (tegra_pending_sgi()) { 151860fbde4SDmitry Osipenko /* 152860fbde4SDmitry Osipenko * CPU got local interrupt that will be lost after GIC's 153860fbde4SDmitry Osipenko * shutdown because GIC driver doesn't save/restore the 154860fbde4SDmitry Osipenko * pending SGI state across CPU cluster PM. Abort and retry 155860fbde4SDmitry Osipenko * next time. 156860fbde4SDmitry Osipenko */ 157860fbde4SDmitry Osipenko atomic_set(&tegra_abort_flag, 1); 158860fbde4SDmitry Osipenko } 159860fbde4SDmitry Osipenko 160860fbde4SDmitry Osipenko cpuidle_coupled_parallel_barrier(dev, &tegra_idle_barrier); 161860fbde4SDmitry Osipenko 162860fbde4SDmitry Osipenko if (atomic_read(&tegra_abort_flag)) { 163860fbde4SDmitry Osipenko cpuidle_coupled_parallel_barrier(dev, &tegra_idle_barrier); 164860fbde4SDmitry Osipenko atomic_set(&tegra_abort_flag, 0); 165860fbde4SDmitry Osipenko return -EINTR; 166860fbde4SDmitry Osipenko } 167860fbde4SDmitry Osipenko 168860fbde4SDmitry Osipenko return 0; 169860fbde4SDmitry Osipenko } 170860fbde4SDmitry Osipenko 171860fbde4SDmitry Osipenko static int tegra_cpuidle_state_enter(struct cpuidle_device *dev, 172860fbde4SDmitry Osipenko int index, unsigned int cpu) 173860fbde4SDmitry Osipenko { 174860fbde4SDmitry Osipenko int ret; 175860fbde4SDmitry Osipenko 176860fbde4SDmitry Osipenko /* 177860fbde4SDmitry Osipenko * CC6 state is the "CPU cluster power-off" state. In order to 178860fbde4SDmitry Osipenko * enter this state, at first the secondary CPU cores need to be 179860fbde4SDmitry Osipenko * parked into offline mode, then the last CPU should clean out 180860fbde4SDmitry Osipenko * remaining dirty cache lines into DRAM and trigger Flow Controller 181860fbde4SDmitry Osipenko * logic that turns off the cluster's power domain (which includes 182860fbde4SDmitry Osipenko * CPU cores, GIC and L2 cache). 183860fbde4SDmitry Osipenko */ 184860fbde4SDmitry Osipenko if (index == TEGRA_CC6) { 185860fbde4SDmitry Osipenko ret = tegra_cpuidle_coupled_barrier(dev); 186860fbde4SDmitry Osipenko if (ret) 187860fbde4SDmitry Osipenko return ret; 188860fbde4SDmitry Osipenko } 189860fbde4SDmitry Osipenko 190860fbde4SDmitry Osipenko local_fiq_disable(); 191860fbde4SDmitry Osipenko tegra_pm_set_cpu_in_lp2(); 192860fbde4SDmitry Osipenko cpu_pm_enter(); 193860fbde4SDmitry Osipenko 194860fbde4SDmitry Osipenko switch (index) { 19519461a49SDmitry Osipenko case TEGRA_C7: 19619461a49SDmitry Osipenko ret = tegra_cpuidle_c7_enter(); 19719461a49SDmitry Osipenko break; 19819461a49SDmitry Osipenko 199860fbde4SDmitry Osipenko case TEGRA_CC6: 200860fbde4SDmitry Osipenko ret = tegra_cpuidle_cc6_enter(cpu); 201860fbde4SDmitry Osipenko break; 202860fbde4SDmitry Osipenko 203860fbde4SDmitry Osipenko default: 204860fbde4SDmitry Osipenko ret = -EINVAL; 205860fbde4SDmitry Osipenko break; 206860fbde4SDmitry Osipenko } 207860fbde4SDmitry Osipenko 208860fbde4SDmitry Osipenko cpu_pm_exit(); 209860fbde4SDmitry Osipenko tegra_pm_clear_cpu_in_lp2(); 210860fbde4SDmitry Osipenko local_fiq_enable(); 211860fbde4SDmitry Osipenko 212860fbde4SDmitry Osipenko return ret; 213860fbde4SDmitry Osipenko } 214860fbde4SDmitry Osipenko 21519461a49SDmitry Osipenko static int tegra_cpuidle_adjust_state_index(int index, unsigned int cpu) 21619461a49SDmitry Osipenko { 21719461a49SDmitry Osipenko /* 21819461a49SDmitry Osipenko * On Tegra30 CPU0 can't be power-gated separately from secondary 21919461a49SDmitry Osipenko * cores because it gates the whole CPU cluster. 22019461a49SDmitry Osipenko */ 22119461a49SDmitry Osipenko if (cpu > 0 || index != TEGRA_C7 || tegra_get_chip_id() != TEGRA30) 22219461a49SDmitry Osipenko return index; 22319461a49SDmitry Osipenko 22419461a49SDmitry Osipenko /* put CPU0 into C1 if C7 is requested and secondaries are online */ 22519461a49SDmitry Osipenko if (!IS_ENABLED(CONFIG_PM_SLEEP) || num_online_cpus() > 1) 22619461a49SDmitry Osipenko index = TEGRA_C1; 22719461a49SDmitry Osipenko else 22819461a49SDmitry Osipenko index = TEGRA_CC6; 22919461a49SDmitry Osipenko 23019461a49SDmitry Osipenko return index; 23119461a49SDmitry Osipenko } 23219461a49SDmitry Osipenko 233860fbde4SDmitry Osipenko static int tegra_cpuidle_enter(struct cpuidle_device *dev, 234860fbde4SDmitry Osipenko struct cpuidle_driver *drv, 235860fbde4SDmitry Osipenko int index) 236860fbde4SDmitry Osipenko { 237860fbde4SDmitry Osipenko unsigned int cpu = cpu_logical_map(dev->cpu); 238860fbde4SDmitry Osipenko int err; 239860fbde4SDmitry Osipenko 24019461a49SDmitry Osipenko index = tegra_cpuidle_adjust_state_index(index, cpu); 24119461a49SDmitry Osipenko if (dev->states_usage[index].disable) 24219461a49SDmitry Osipenko return -1; 24319461a49SDmitry Osipenko 24419461a49SDmitry Osipenko if (index == TEGRA_C1) 24519461a49SDmitry Osipenko err = arm_cpuidle_simple_enter(dev, drv, index); 24619461a49SDmitry Osipenko else 247860fbde4SDmitry Osipenko err = tegra_cpuidle_state_enter(dev, index, cpu); 24819461a49SDmitry Osipenko 24919461a49SDmitry Osipenko if (err && (err != -EINTR || index != TEGRA_CC6)) 25019461a49SDmitry Osipenko pr_err_once("failed to enter state %d err: %d\n", index, err); 251860fbde4SDmitry Osipenko 252860fbde4SDmitry Osipenko return err ? -1 : index; 253860fbde4SDmitry Osipenko } 254860fbde4SDmitry Osipenko 25514e086baSDmitry Osipenko static void tegra114_enter_s2idle(struct cpuidle_device *dev, 25614e086baSDmitry Osipenko struct cpuidle_driver *drv, 25714e086baSDmitry Osipenko int index) 25814e086baSDmitry Osipenko { 25914e086baSDmitry Osipenko tegra_cpuidle_enter(dev, drv, index); 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 { 340860fbde4SDmitry Osipenko /* 341860fbde4SDmitry Osipenko * Required suspend-resume functionality, which is provided by the 342860fbde4SDmitry Osipenko * Tegra-arch core and PMC driver, is unavailable if PM-sleep option 343860fbde4SDmitry Osipenko * is disabled. 344860fbde4SDmitry Osipenko */ 34519461a49SDmitry Osipenko if (!IS_ENABLED(CONFIG_PM_SLEEP)) { 34614e086baSDmitry Osipenko if (!tegra_cpuidle_using_firmware()) 34719461a49SDmitry Osipenko tegra_cpuidle_disable_state(TEGRA_C7); 34814e086baSDmitry Osipenko 349860fbde4SDmitry Osipenko tegra_cpuidle_disable_state(TEGRA_CC6); 35019461a49SDmitry Osipenko } 35119461a49SDmitry Osipenko 35219461a49SDmitry Osipenko /* 35319461a49SDmitry Osipenko * Generic WFI state (also known as C1 or LP3) and the coupled CPU 35419461a49SDmitry Osipenko * cluster power-off (CC6 or LP2) states are common for all Tegra SoCs. 35519461a49SDmitry Osipenko */ 35619461a49SDmitry Osipenko switch (tegra_get_chip_id()) { 35719461a49SDmitry Osipenko case TEGRA20: 35819461a49SDmitry Osipenko /* Tegra20 isn't capable to power-off individual CPU cores */ 35919461a49SDmitry Osipenko tegra_cpuidle_disable_state(TEGRA_C7); 36019461a49SDmitry Osipenko break; 36119461a49SDmitry Osipenko 36219461a49SDmitry Osipenko case TEGRA30: 36319461a49SDmitry Osipenko tegra_cpuidle_disable_state(TEGRA_CC6); 36419461a49SDmitry Osipenko break; 36519461a49SDmitry Osipenko 36614e086baSDmitry Osipenko case TEGRA114: 36714e086baSDmitry Osipenko case TEGRA124: 36814e086baSDmitry Osipenko tegra_cpuidle_setup_tegra114_c7_state(); 36914e086baSDmitry Osipenko 37014e086baSDmitry Osipenko /* coupled CC6 (LP2) state isn't implemented yet */ 37114e086baSDmitry Osipenko tegra_cpuidle_disable_state(TEGRA_CC6); 37214e086baSDmitry Osipenko break; 37314e086baSDmitry Osipenko 37419461a49SDmitry Osipenko default: 37519461a49SDmitry Osipenko return -EINVAL; 37619461a49SDmitry Osipenko } 377860fbde4SDmitry Osipenko 378860fbde4SDmitry Osipenko return cpuidle_register(&tegra_idle_driver, cpu_possible_mask); 379860fbde4SDmitry Osipenko } 380860fbde4SDmitry Osipenko 381860fbde4SDmitry Osipenko static struct platform_driver tegra_cpuidle_driver = { 382860fbde4SDmitry Osipenko .probe = tegra_cpuidle_probe, 383860fbde4SDmitry Osipenko .driver = { 384860fbde4SDmitry Osipenko .name = "tegra-cpuidle", 385860fbde4SDmitry Osipenko }, 386860fbde4SDmitry Osipenko }; 387860fbde4SDmitry Osipenko builtin_platform_driver(tegra_cpuidle_driver); 388