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