Commit | Line | Data |
---|---|---|
51dc5259 JL |
1 | /* |
2 | * Copyright (c) 2013, NVIDIA Corporation. All rights reserved. | |
3 | * | |
4 | * This program is free software; you can redistribute it and/or modify it | |
5 | * under the terms and conditions of the GNU General Public License, | |
6 | * version 2, as published by the Free Software Foundation. | |
7 | * | |
8 | * This program is distributed in the hope it will be useful, but WITHOUT | |
9 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | |
10 | * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for | |
11 | * more details. | |
12 | * | |
13 | * You should have received a copy of the GNU General Public License | |
14 | * along with this program. If not, see <http://www.gnu.org/licenses/>. | |
15 | */ | |
16 | ||
a0524acc | 17 | #include <asm/firmware.h> |
a0b41224 | 18 | #include <linux/tick.h> |
51dc5259 | 19 | #include <linux/cpuidle.h> |
3045cb33 | 20 | #include <linux/cpu_pm.h> |
a0524acc TR |
21 | #include <linux/kernel.h> |
22 | #include <linux/module.h> | |
51dc5259 JL |
23 | |
24 | #include <asm/cpuidle.h> | |
3045cb33 | 25 | #include <asm/smp_plat.h> |
a0524acc | 26 | #include <asm/suspend.h> |
fc0cf177 | 27 | #include <asm/psci.h> |
3045cb33 | 28 | |
755c47ed | 29 | #include "cpuidle.h" |
3045cb33 JL |
30 | #include "pm.h" |
31 | #include "sleep.h" | |
32 | ||
33 | #ifdef CONFIG_PM_SLEEP | |
34 | #define TEGRA114_MAX_STATES 2 | |
35 | #else | |
36 | #define TEGRA114_MAX_STATES 1 | |
37 | #endif | |
38 | ||
39 | #ifdef CONFIG_PM_SLEEP | |
40 | static int tegra114_idle_power_down(struct cpuidle_device *dev, | |
41 | struct cpuidle_driver *drv, | |
42 | int index) | |
43 | { | |
44 | local_fiq_disable(); | |
45 | ||
46 | tegra_set_cpu_in_lp2(); | |
47 | cpu_pm_enter(); | |
48 | ||
338f2aad AC |
49 | call_firmware_op(prepare_idle); |
50 | ||
51 | /* Do suspend by ourselves if the firmware does not implement it */ | |
0b7778a8 | 52 | if (call_firmware_op(do_idle, 0) == -ENOSYS) |
338f2aad | 53 | cpu_suspend(0, tegra30_sleep_cpu_secondary_finish); |
3045cb33 | 54 | |
3045cb33 JL |
55 | cpu_pm_exit(); |
56 | tegra_clear_cpu_in_lp2(); | |
57 | ||
58 | local_fiq_enable(); | |
59 | ||
60 | return index; | |
61 | } | |
1ec0e115 | 62 | |
28ba086e | 63 | static void tegra114_idle_enter_s2idle(struct cpuidle_device *dev, |
1ec0e115 TV |
64 | struct cpuidle_driver *drv, |
65 | int index) | |
66 | { | |
67 | tegra114_idle_power_down(dev, drv, index); | |
68 | } | |
3045cb33 | 69 | #endif |
51dc5259 JL |
70 | |
71 | static struct cpuidle_driver tegra_idle_driver = { | |
72 | .name = "tegra_idle", | |
73 | .owner = THIS_MODULE, | |
3045cb33 | 74 | .state_count = TEGRA114_MAX_STATES, |
51dc5259 JL |
75 | .states = { |
76 | [0] = ARM_CPUIDLE_WFI_STATE_PWR(600), | |
3045cb33 JL |
77 | #ifdef CONFIG_PM_SLEEP |
78 | [1] = { | |
79 | .enter = tegra114_idle_power_down, | |
28ba086e | 80 | .enter_s2idle = tegra114_idle_enter_s2idle, |
3045cb33 JL |
81 | .exit_latency = 500, |
82 | .target_residency = 1000, | |
1ec0e115 | 83 | .flags = CPUIDLE_FLAG_TIMER_STOP, |
3045cb33 | 84 | .power_usage = 0, |
3045cb33 JL |
85 | .name = "powered-down", |
86 | .desc = "CPU power gated", | |
87 | }, | |
88 | #endif | |
51dc5259 JL |
89 | }, |
90 | }; | |
91 | ||
51dc5259 JL |
92 | int __init tegra114_cpuidle_init(void) |
93 | { | |
fc0cf177 TR |
94 | if (!psci_smp_available()) |
95 | return cpuidle_register(&tegra_idle_driver, NULL); | |
96 | ||
97 | return 0; | |
51dc5259 | 98 | } |