Merge tag 'cleanup-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/arm...
[firefly-linux-kernel-4.4.55.git] / arch / arm / mach-tegra / pm.c
1 /*
2  * CPU complex suspend & resume functions for Tegra SoCs
3  *
4  * Copyright (c) 2009-2012, NVIDIA Corporation. All rights reserved.
5  *
6  * This program is free software; you can redistribute it and/or modify it
7  * under the terms and conditions of the GNU General Public License,
8  * version 2, as published by the Free Software Foundation.
9  *
10  * This program is distributed in the hope it will be useful, but WITHOUT
11  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
12  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
13  * more details.
14  *
15  * You should have received a copy of the GNU General Public License
16  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
17  */
18
19 #include <linux/kernel.h>
20 #include <linux/spinlock.h>
21 #include <linux/io.h>
22 #include <linux/cpumask.h>
23 #include <linux/delay.h>
24 #include <linux/cpu_pm.h>
25 #include <linux/clk.h>
26 #include <linux/err.h>
27 #include <linux/clk/tegra.h>
28
29 #include <asm/smp_plat.h>
30 #include <asm/cacheflush.h>
31 #include <asm/suspend.h>
32 #include <asm/idmap.h>
33 #include <asm/proc-fns.h>
34 #include <asm/tlbflush.h>
35
36 #include "iomap.h"
37 #include "reset.h"
38 #include "flowctrl.h"
39 #include "fuse.h"
40 #include "sleep.h"
41
42 #define TEGRA_POWER_CPU_PWRREQ_OE       (1 << 16)  /* CPU pwr req enable */
43
44 #define PMC_CTRL                0x0
45 #define PMC_CPUPWRGOOD_TIMER    0xc8
46 #define PMC_CPUPWROFF_TIMER     0xcc
47
48 #ifdef CONFIG_PM_SLEEP
49 static DEFINE_SPINLOCK(tegra_lp2_lock);
50 static void __iomem *pmc = IO_ADDRESS(TEGRA_PMC_BASE);
51 static struct clk *tegra_pclk;
52 void (*tegra_tear_down_cpu)(void);
53
54 static void set_power_timers(unsigned long us_on, unsigned long us_off)
55 {
56         unsigned long long ticks;
57         unsigned long long pclk;
58         unsigned long rate;
59         static unsigned long tegra_last_pclk;
60
61         if (tegra_pclk == NULL) {
62                 tegra_pclk = clk_get_sys(NULL, "pclk");
63                 WARN_ON(IS_ERR(tegra_pclk));
64         }
65
66         rate = clk_get_rate(tegra_pclk);
67
68         if (WARN_ON_ONCE(rate <= 0))
69                 pclk = 100000000;
70         else
71                 pclk = rate;
72
73         if ((rate != tegra_last_pclk)) {
74                 ticks = (us_on * pclk) + 999999ull;
75                 do_div(ticks, 1000000);
76                 writel((unsigned long)ticks, pmc + PMC_CPUPWRGOOD_TIMER);
77
78                 ticks = (us_off * pclk) + 999999ull;
79                 do_div(ticks, 1000000);
80                 writel((unsigned long)ticks, pmc + PMC_CPUPWROFF_TIMER);
81                 wmb();
82         }
83         tegra_last_pclk = pclk;
84 }
85
86 /*
87  * restore_cpu_complex
88  *
89  * restores cpu clock setting, clears flow controller
90  *
91  * Always called on CPU 0.
92  */
93 static void restore_cpu_complex(void)
94 {
95         int cpu = smp_processor_id();
96
97         BUG_ON(cpu != 0);
98
99 #ifdef CONFIG_SMP
100         cpu = cpu_logical_map(cpu);
101 #endif
102
103         /* Restore the CPU clock settings */
104         tegra_cpu_clock_resume();
105
106         flowctrl_cpu_suspend_exit(cpu);
107 }
108
109 /*
110  * suspend_cpu_complex
111  *
112  * saves pll state for use by restart_plls, prepares flow controller for
113  * transition to suspend state
114  *
115  * Must always be called on cpu 0.
116  */
117 static void suspend_cpu_complex(void)
118 {
119         int cpu = smp_processor_id();
120
121         BUG_ON(cpu != 0);
122
123 #ifdef CONFIG_SMP
124         cpu = cpu_logical_map(cpu);
125 #endif
126
127         /* Save the CPU clock settings */
128         tegra_cpu_clock_suspend();
129
130         flowctrl_cpu_suspend_enter(cpu);
131 }
132
133 void tegra_clear_cpu_in_lp2(int phy_cpu_id)
134 {
135         u32 *cpu_in_lp2 = tegra_cpu_lp2_mask;
136
137         spin_lock(&tegra_lp2_lock);
138
139         BUG_ON(!(*cpu_in_lp2 & BIT(phy_cpu_id)));
140         *cpu_in_lp2 &= ~BIT(phy_cpu_id);
141
142         spin_unlock(&tegra_lp2_lock);
143 }
144
145 bool tegra_set_cpu_in_lp2(int phy_cpu_id)
146 {
147         bool last_cpu = false;
148         cpumask_t *cpu_lp2_mask = tegra_cpu_lp2_mask;
149         u32 *cpu_in_lp2 = tegra_cpu_lp2_mask;
150
151         spin_lock(&tegra_lp2_lock);
152
153         BUG_ON((*cpu_in_lp2 & BIT(phy_cpu_id)));
154         *cpu_in_lp2 |= BIT(phy_cpu_id);
155
156         if ((phy_cpu_id == 0) && cpumask_equal(cpu_lp2_mask, cpu_online_mask))
157                 last_cpu = true;
158         else if (tegra_chip_id == TEGRA20 && phy_cpu_id == 1)
159                 tegra20_cpu_set_resettable_soon();
160
161         spin_unlock(&tegra_lp2_lock);
162         return last_cpu;
163 }
164
165 int tegra_cpu_do_idle(void)
166 {
167         return cpu_do_idle();
168 }
169
170 static int tegra_sleep_cpu(unsigned long v2p)
171 {
172         setup_mm_for_reboot();
173         tegra_sleep_cpu_finish(v2p);
174
175         /* should never here */
176         BUG();
177
178         return 0;
179 }
180
181 void tegra_idle_lp2_last(u32 cpu_on_time, u32 cpu_off_time)
182 {
183         u32 mode;
184
185         /* Only the last cpu down does the final suspend steps */
186         mode = readl(pmc + PMC_CTRL);
187         mode |= TEGRA_POWER_CPU_PWRREQ_OE;
188         writel(mode, pmc + PMC_CTRL);
189
190         set_power_timers(cpu_on_time, cpu_off_time);
191
192         cpu_cluster_pm_enter();
193         suspend_cpu_complex();
194
195         cpu_suspend(PHYS_OFFSET - PAGE_OFFSET, &tegra_sleep_cpu);
196
197         restore_cpu_complex();
198         cpu_cluster_pm_exit();
199 }
200 #endif