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 JL |
28 | |
29 | #include "pm.h" | |
30 | #include "sleep.h" | |
31 | ||
32 | #ifdef CONFIG_PM_SLEEP | |
33 | #define TEGRA114_MAX_STATES 2 | |
34 | #else | |
35 | #define TEGRA114_MAX_STATES 1 | |
36 | #endif | |
37 | ||
38 | #ifdef CONFIG_PM_SLEEP | |
39 | static int tegra114_idle_power_down(struct cpuidle_device *dev, | |
40 | struct cpuidle_driver *drv, | |
41 | int index) | |
42 | { | |
43 | local_fiq_disable(); | |
44 | ||
45 | tegra_set_cpu_in_lp2(); | |
46 | cpu_pm_enter(); | |
47 | ||
338f2aad AC |
48 | call_firmware_op(prepare_idle); |
49 | ||
50 | /* Do suspend by ourselves if the firmware does not implement it */ | |
0b7778a8 | 51 | if (call_firmware_op(do_idle, 0) == -ENOSYS) |
338f2aad | 52 | cpu_suspend(0, tegra30_sleep_cpu_secondary_finish); |
3045cb33 | 53 | |
3045cb33 JL |
54 | cpu_pm_exit(); |
55 | tegra_clear_cpu_in_lp2(); | |
56 | ||
57 | local_fiq_enable(); | |
58 | ||
59 | return index; | |
60 | } | |
1ec0e115 TV |
61 | |
62 | static void tegra114_idle_enter_freeze(struct cpuidle_device *dev, | |
63 | struct cpuidle_driver *drv, | |
64 | int index) | |
65 | { | |
66 | tegra114_idle_power_down(dev, drv, index); | |
67 | } | |
3045cb33 | 68 | #endif |
51dc5259 JL |
69 | |
70 | static struct cpuidle_driver tegra_idle_driver = { | |
71 | .name = "tegra_idle", | |
72 | .owner = THIS_MODULE, | |
3045cb33 | 73 | .state_count = TEGRA114_MAX_STATES, |
51dc5259 JL |
74 | .states = { |
75 | [0] = ARM_CPUIDLE_WFI_STATE_PWR(600), | |
3045cb33 JL |
76 | #ifdef CONFIG_PM_SLEEP |
77 | [1] = { | |
78 | .enter = tegra114_idle_power_down, | |
1ec0e115 | 79 | .enter_freeze = tegra114_idle_enter_freeze, |
3045cb33 JL |
80 | .exit_latency = 500, |
81 | .target_residency = 1000, | |
1ec0e115 | 82 | .flags = CPUIDLE_FLAG_TIMER_STOP, |
3045cb33 | 83 | .power_usage = 0, |
3045cb33 JL |
84 | .name = "powered-down", |
85 | .desc = "CPU power gated", | |
86 | }, | |
87 | #endif | |
51dc5259 JL |
88 | }, |
89 | }; | |
90 | ||
51dc5259 JL |
91 | int __init tegra114_cpuidle_init(void) |
92 | { | |
fc0cf177 TR |
93 | if (!psci_smp_available()) |
94 | return cpuidle_register(&tegra_idle_driver, NULL); | |
95 | ||
96 | return 0; | |
51dc5259 | 97 | } |