aboutsummaryrefslogtreecommitdiffstats
path: root/arch/arm/mach-tegra/cpuidle-t3.c
diff options
context:
space:
mode:
Diffstat (limited to 'arch/arm/mach-tegra/cpuidle-t3.c')
-rw-r--r--arch/arm/mach-tegra/cpuidle-t3.c532
1 files changed, 532 insertions, 0 deletions
diff --git a/arch/arm/mach-tegra/cpuidle-t3.c b/arch/arm/mach-tegra/cpuidle-t3.c
new file mode 100644
index 00000000000..c6a50a542d8
--- /dev/null
+++ b/arch/arm/mach-tegra/cpuidle-t3.c
@@ -0,0 +1,532 @@
1/*
2 * arch/arm/mach-tegra/cpuidle-t3.c
3 *
4 * CPU idle driver for Tegra3 CPUs
5 *
6 * Copyright (c) 2010-2011, NVIDIA Corporation.
7 *
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation; either version 2 of the License, or
11 * (at your option) any later version.
12 *
13 * This program is distributed in the hope that it will be useful, but WITHOUT
14 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
15 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
16 * more details.
17 *
18 * You should have received a copy of the GNU General Public License along
19 * with this program; if not, write to the Free Software Foundation, Inc.,
20 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
21 */
22
23#include <linux/kernel.h>
24#include <linux/cpu.h>
25#include <linux/cpuidle.h>
26#include <linux/debugfs.h>
27#include <linux/delay.h>
28#include <linux/hrtimer.h>
29#include <linux/init.h>
30#include <linux/interrupt.h>
31#include <linux/irq.h>
32#include <linux/io.h>
33#include <linux/ratelimit.h>
34#include <linux/sched.h>
35#include <linux/seq_file.h>
36#include <linux/slab.h>
37#include <linux/smp.h>
38#include <linux/suspend.h>
39#include <linux/tick.h>
40#include <linux/clk.h>
41
42#include <asm/cacheflush.h>
43#include <asm/cpu_pm.h>
44#include <asm/hardware/gic.h>
45#include <asm/localtimer.h>
46
47#include <mach/iomap.h>
48#include <mach/irqs.h>
49
50#include <trace/events/power.h>
51
52#include "clock.h"
53#include "cpuidle.h"
54#include "dvfs.h"
55#include "fuse.h"
56#include "gic.h"
57#include "pm.h"
58#include "reset.h"
59#include "sleep.h"
60#include "timer.h"
61
62#define CLK_RST_CONTROLLER_CPU_CMPLX_STATUS \
63 (IO_ADDRESS(TEGRA_CLK_RESET_BASE) + 0x470)
64#define PMC_POWERGATE_STATUS \
65 (IO_ADDRESS(TEGRA_PMC_BASE) + 0x038)
66
67#ifdef CONFIG_SMP
68static s64 tegra_cpu_wake_by_time[4] = {
69 LLONG_MAX, LLONG_MAX, LLONG_MAX, LLONG_MAX };
70#endif
71
72static bool lp2_0_in_idle = true;
73module_param(lp2_0_in_idle, bool, 0644);
74
75static bool lp2_n_in_idle = true;
76module_param(lp2_n_in_idle, bool, 0644);
77
78static struct clk *cpu_clk_for_dvfs;
79static struct clk *twd_clk;
80
81static int lp2_exit_latencies[5];
82
83static struct {
84 unsigned int cpu_ready_count[5];
85 unsigned int tear_down_count[5];
86 unsigned long long cpu_wants_lp2_time[5];
87 unsigned long long in_lp2_time[5];
88 unsigned int lp2_count;
89 unsigned int lp2_completed_count;
90 unsigned int lp2_count_bin[32];
91 unsigned int lp2_completed_count_bin[32];
92 unsigned int lp2_int_count[NR_IRQS];
93 unsigned int last_lp2_int_count[NR_IRQS];
94} idle_stats;
95
96static inline unsigned int time_to_bin(unsigned int time)
97{
98 return fls(time);
99}
100
101static inline void tegra_irq_unmask(int irq)
102{
103 struct irq_data *data = irq_get_irq_data(irq);
104 data->chip->irq_unmask(data);
105}
106
107static inline unsigned int cpu_number(unsigned int n)
108{
109 return is_lp_cluster() ? 4 : n;
110}
111
112void tegra3_cpu_idle_stats_lp2_ready(unsigned int cpu)
113{
114 idle_stats.cpu_ready_count[cpu_number(cpu)]++;
115}
116
117void tegra3_cpu_idle_stats_lp2_time(unsigned int cpu, s64 us)
118{
119 idle_stats.cpu_wants_lp2_time[cpu_number(cpu)] += us;
120}
121
122/* Allow rail off only if all secondary CPUs are power gated, and no
123 rail update is in progress */
124static bool tegra3_rail_off_is_allowed(void)
125{
126 u32 rst = readl(CLK_RST_CONTROLLER_CPU_CMPLX_STATUS);
127 u32 pg = readl(PMC_POWERGATE_STATUS) >> 8;
128
129 if (((rst & 0xE) != 0xE) || ((pg & 0xE) != 0))
130 return false;
131
132 if (tegra_dvfs_rail_updating(cpu_clk_for_dvfs))
133 return false;
134
135 return true;
136}
137
138bool tegra3_lp2_is_allowed(struct cpuidle_device *dev,
139 struct cpuidle_state *state)
140{
141 s64 request;
142
143 if (!tegra_all_cpus_booted)
144 return false;
145
146 if ((!lp2_0_in_idle && !dev->cpu) || (!lp2_n_in_idle && dev->cpu))
147 return false;
148
149 /* On A01, LP2 on slave CPU's cause ranhdom CPU hangs.
150 * Refer to Bug 804085.
151 */
152 if ((tegra_get_revision() == TEGRA_REVISION_A01) &&
153 num_online_cpus() > 1)
154 return false;
155
156#ifndef CONFIG_TEGRA_RAIL_OFF_MULTIPLE_CPUS
157 /* FIXME: All CPU's entering LP2 is not working.
158 * Don't let CPU0 enter LP2 when any secondary CPU is online.
159 */
160 if ((dev->cpu == 0) && (num_online_cpus() > 1))
161 return false;
162#endif
163 if ((dev->cpu == 0) && (!tegra3_rail_off_is_allowed()))
164 return false;
165
166 request = ktime_to_us(tick_nohz_get_sleep_length());
167 if (state->exit_latency != lp2_exit_latencies[cpu_number(dev->cpu)]) {
168 /* possible on the 1st entry after cluster switch*/
169 state->exit_latency = lp2_exit_latencies[cpu_number(dev->cpu)];
170 tegra_lp2_update_target_residency(state);
171 }
172 if (request < state->target_residency) {
173 /* Not enough time left to enter LP2 */
174 return false;
175 }
176
177 return true;
178}
179
180static inline void tegra3_lp3_fall_back(struct cpuidle_device *dev)
181{
182 tegra_cpu_wfi();
183 /* fall back here from LP2 path - tell cpuidle governor */
184 dev->last_state = &dev->states[0];
185}
186
187static inline void tegra3_lp2_restore_affinity(void)
188{
189#ifdef CONFIG_SMP
190 /* Disable the distributor. */
191 tegra_gic_dist_disable();
192
193 /* Restore the other CPU's interrupt affinity. */
194 tegra_gic_restore_affinity();
195
196 /* Re-enable the distributor. */
197 tegra_gic_dist_enable();
198#endif
199}
200
201static void tegra3_idle_enter_lp2_cpu_0(struct cpuidle_device *dev,
202 struct cpuidle_state *state, s64 request)
203{
204 ktime_t entry_time;
205 ktime_t exit_time;
206 bool sleep_completed = false;
207 bool multi_cpu_entry = false;
208 int bin;
209 s64 sleep_time;
210
211 /* LP2 entry time */
212 entry_time = ktime_get();
213
214 if (request < state->target_residency) {
215 /* Not enough time left to enter LP2 */
216 tegra3_lp3_fall_back(dev);
217 return;
218 }
219
220#ifdef CONFIG_SMP
221 multi_cpu_entry = !is_lp_cluster() && (num_online_cpus() > 1);
222 if (multi_cpu_entry) {
223 s64 wake_time;
224 unsigned int i;
225
226 /* Disable the distributor -- this is the only way to
227 prevent the other CPUs from responding to interrupts
228 and potentially fiddling with the distributor
229 registers while we're fiddling with them. */
230 tegra_gic_dist_disable();
231
232 /* Did an interrupt come in for another CPU before we
233 could disable the distributor? */
234 if (!tegra3_rail_off_is_allowed()) {
235 /* Yes, re-enable the distributor and LP3. */
236 tegra_gic_dist_enable();
237 tegra3_lp3_fall_back(dev);
238 return;
239 }
240
241 /* LP2 initial targeted wake time */
242 wake_time = ktime_to_us(entry_time) + request;
243
244 /* CPU0 must wake up before any of the other CPUs. */
245 smp_rmb();
246 for (i = 1; i < CONFIG_NR_CPUS; i++)
247 wake_time = min_t(s64, wake_time,
248 tegra_cpu_wake_by_time[i]);
249
250 /* LP2 actual targeted wake time */
251 request = wake_time - ktime_to_us(entry_time);
252 BUG_ON(wake_time < 0LL);
253
254 if (request < state->target_residency) {
255 /* Not enough time left to enter LP2 */
256 tegra_gic_dist_enable();
257 tegra3_lp3_fall_back(dev);
258 return;
259 }
260
261 /* Cancel LP2 wake timers for all secondary CPUs */
262 tegra_lp2_timer_cancel_secondary();
263
264 /* Save and disable the affinity setting for the other
265 CPUs and route all interrupts to CPU0. */
266 tegra_gic_disable_affinity();
267
268 /* Re-enable the distributor. */
269 tegra_gic_dist_enable();
270 }
271#endif
272
273 sleep_time = request -
274 lp2_exit_latencies[cpu_number(dev->cpu)];
275
276 bin = time_to_bin((u32)request / 1000);
277 idle_stats.tear_down_count[cpu_number(dev->cpu)]++;
278 idle_stats.lp2_count++;
279 idle_stats.lp2_count_bin[bin]++;
280
281 trace_power_start(POWER_CSTATE, 2, dev->cpu);
282 clockevents_notify(CLOCK_EVT_NOTIFY_BROADCAST_ENTER, &dev->cpu);
283 if (!is_lp_cluster())
284 tegra_dvfs_rail_off(tegra_cpu_rail, entry_time);
285
286 if (tegra_idle_lp2_last(sleep_time, 0) == 0)
287 sleep_completed = true;
288 else {
289 int irq = tegra_gic_pending_interrupt();
290 idle_stats.lp2_int_count[irq]++;
291 }
292
293 clockevents_notify(CLOCK_EVT_NOTIFY_BROADCAST_EXIT, &dev->cpu);
294 exit_time = ktime_get();
295 if (!is_lp_cluster())
296 tegra_dvfs_rail_on(tegra_cpu_rail, exit_time);
297 idle_stats.in_lp2_time[cpu_number(dev->cpu)] +=
298 ktime_to_us(ktime_sub(exit_time, entry_time));
299
300 if (multi_cpu_entry)
301 tegra3_lp2_restore_affinity();
302
303 if (sleep_completed) {
304 /*
305 * Stayed in LP2 for the full time until the next tick,
306 * adjust the exit latency based on measurement
307 */
308 int offset = ktime_to_us(ktime_sub(exit_time, entry_time))
309 - request;
310 int latency = lp2_exit_latencies[cpu_number(dev->cpu)] +
311 offset / 16;
312 latency = clamp(latency, 0, 10000);
313 lp2_exit_latencies[cpu_number(dev->cpu)] = latency;
314 state->exit_latency = latency; /* for idle governor */
315 smp_wmb();
316
317 idle_stats.lp2_completed_count++;
318 idle_stats.lp2_completed_count_bin[bin]++;
319
320 pr_debug("%lld %lld %d %d\n", request,
321 ktime_to_us(ktime_sub(exit_time, entry_time)),
322 offset, bin);
323 }
324}
325
326static void tegra3_idle_enter_lp2_cpu_n(struct cpuidle_device *dev,
327 struct cpuidle_state *state, s64 request)
328{
329#ifdef CONFIG_SMP
330 s64 sleep_time;
331 ktime_t entry_time;
332 struct tegra_twd_context twd_context;
333 bool sleep_completed = false;
334 struct tick_sched *ts = tick_get_tick_sched(dev->cpu);
335
336 if (!tegra_twd_get_state(&twd_context)) {
337 unsigned long twd_rate = clk_get_rate(twd_clk);
338
339 if ((twd_context.twd_ctrl & TWD_TIMER_CONTROL_ENABLE) &&
340 (twd_context.twd_ctrl & TWD_TIMER_CONTROL_IT_ENABLE)) {
341 request = div_u64((u64)twd_context.twd_cnt * 1000000,
342 twd_rate);
343#ifdef CONFIG_TEGRA_LP2_ARM_TWD
344 if (request >= state->target_residency) {
345 twd_context.twd_cnt -= state->exit_latency *
346 (twd_rate / 1000000);
347 writel(twd_context.twd_cnt,
348 twd_base + TWD_TIMER_COUNTER);
349 }
350#endif
351 }
352 }
353
354 if (!tegra_is_lp2_timer_ready(dev->cpu) ||
355 (request < state->target_residency) ||
356 (!ts) || (ts->nohz_mode == NOHZ_MODE_INACTIVE)) {
357 /*
358 * Not enough time left to enter LP2, or wake timer not ready
359 */
360 tegra3_lp3_fall_back(dev);
361 return;
362 }
363
364#ifndef CONFIG_TEGRA_LP2_ARM_TWD
365 sleep_time = request - state->exit_latency;
366 clockevents_notify(CLOCK_EVT_NOTIFY_BROADCAST_ENTER, &dev->cpu);
367 tegra_twd_suspend(&twd_context);
368 tegra_lp2_set_trigger(sleep_time);
369#endif
370 idle_stats.tear_down_count[cpu_number(dev->cpu)]++;
371
372 trace_power_start(POWER_CSTATE, 2, dev->cpu);
373
374 entry_time = ktime_get();
375
376 /* Save time this CPU must be awakened by. */
377 tegra_cpu_wake_by_time[dev->cpu] = ktime_to_us(entry_time) + request;
378 smp_wmb();
379
380 tegra3_sleep_cpu_secondary(PLAT_PHYS_OFFSET - PAGE_OFFSET);
381
382 tegra_cpu_wake_by_time[dev->cpu] = LLONG_MAX;
383
384#ifdef CONFIG_TEGRA_LP2_ARM_TWD
385 if (!tegra_twd_get_state(&twd_context))
386 sleep_completed = (twd_context.twd_cnt == 0);
387#else
388 sleep_completed = !tegra_lp2_timer_remain();
389 tegra_lp2_set_trigger(0);
390 tegra_twd_resume(&twd_context);
391 clockevents_notify(CLOCK_EVT_NOTIFY_BROADCAST_EXIT, &dev->cpu);
392#endif
393 sleep_time = ktime_to_us(ktime_sub(ktime_get(), entry_time));
394 idle_stats.in_lp2_time[cpu_number(dev->cpu)] += sleep_time;
395 if (sleep_completed) {
396 /*
397 * Stayed in LP2 for the full time until timer expires,
398 * adjust the exit latency based on measurement
399 */
400 int offset = sleep_time - request;
401 int latency = lp2_exit_latencies[cpu_number(dev->cpu)] +
402 offset / 16;
403 latency = clamp(latency, 0, 10000);
404 lp2_exit_latencies[cpu_number(dev->cpu)] = latency;
405 state->exit_latency = latency; /* for idle governor */
406 smp_wmb();
407 }
408#endif
409}
410
411void tegra3_idle_lp2(struct cpuidle_device *dev,
412 struct cpuidle_state *state)
413{
414 s64 request = ktime_to_us(tick_nohz_get_sleep_length());
415 bool last_cpu = tegra_set_cpu_in_lp2(dev->cpu);
416
417 cpu_pm_enter();
418
419 if (dev->cpu == 0) {
420 if (last_cpu)
421 tegra3_idle_enter_lp2_cpu_0(dev, state, request);
422 else
423 tegra3_lp3_fall_back(dev);
424 } else
425 tegra3_idle_enter_lp2_cpu_n(dev, state, request);
426
427 cpu_pm_exit();
428 tegra_clear_cpu_in_lp2(dev->cpu);
429}
430
431int tegra3_cpudile_init_soc(void)
432{
433 int i;
434
435 cpu_clk_for_dvfs = tegra_get_clock_by_name("cpu_g");
436 twd_clk = tegra_get_clock_by_name("twd");
437
438 for (i = 0; i < ARRAY_SIZE(lp2_exit_latencies); i++)
439 lp2_exit_latencies[i] = tegra_lp2_exit_latency;
440
441 return 0;
442}
443
444#ifdef CONFIG_DEBUG_FS
445int tegra3_lp2_debug_show(struct seq_file *s, void *data)
446{
447 int bin;
448 int i;
449 seq_printf(s, " cpu0 cpu1 cpu2 cpu3 cpulp\n");
450 seq_printf(s, "-----------------------------------------------------------------------------\n");
451 seq_printf(s, "cpu ready: %8u %8u %8u %8u %8u\n",
452 idle_stats.cpu_ready_count[0],
453 idle_stats.cpu_ready_count[1],
454 idle_stats.cpu_ready_count[2],
455 idle_stats.cpu_ready_count[3],
456 idle_stats.cpu_ready_count[4]);
457 seq_printf(s, "tear down: %8u %8u %8u %8u %8u\n",
458 idle_stats.tear_down_count[0],
459 idle_stats.tear_down_count[1],
460 idle_stats.tear_down_count[2],
461 idle_stats.tear_down_count[3],
462 idle_stats.tear_down_count[4]);
463 seq_printf(s, "lp2: %8u\n", idle_stats.lp2_count);
464 seq_printf(s, "lp2 completed: %8u %7u%%\n",
465 idle_stats.lp2_completed_count,
466 idle_stats.lp2_completed_count * 100 /
467 (idle_stats.lp2_count ?: 1));
468
469 seq_printf(s, "\n");
470 seq_printf(s, "cpu ready time: %8llu %8llu %8llu %8llu %8llu ms\n",
471 div64_u64(idle_stats.cpu_wants_lp2_time[0], 1000),
472 div64_u64(idle_stats.cpu_wants_lp2_time[1], 1000),
473 div64_u64(idle_stats.cpu_wants_lp2_time[2], 1000),
474 div64_u64(idle_stats.cpu_wants_lp2_time[3], 1000),
475 div64_u64(idle_stats.cpu_wants_lp2_time[4], 1000));
476
477 seq_printf(s, "lp2 time: %8llu %8llu %8llu %8llu %8llu ms\n",
478 div64_u64(idle_stats.in_lp2_time[0], 1000),
479 div64_u64(idle_stats.in_lp2_time[1], 1000),
480 div64_u64(idle_stats.in_lp2_time[2], 1000),
481 div64_u64(idle_stats.in_lp2_time[3], 1000),
482 div64_u64(idle_stats.in_lp2_time[4], 1000));
483
484 seq_printf(s, "lp2 %%: %7d%% %7d%% %7d%% %7d%% %7d%%\n",
485 (int)(idle_stats.cpu_wants_lp2_time[0] ?
486 div64_u64(idle_stats.in_lp2_time[0] * 100,
487 idle_stats.cpu_wants_lp2_time[0]) : 0),
488 (int)(idle_stats.cpu_wants_lp2_time[1] ?
489 div64_u64(idle_stats.in_lp2_time[1] * 100,
490 idle_stats.cpu_wants_lp2_time[1]) : 0),
491 (int)(idle_stats.cpu_wants_lp2_time[2] ?
492 div64_u64(idle_stats.in_lp2_time[2] * 100,
493 idle_stats.cpu_wants_lp2_time[2]) : 0),
494 (int)(idle_stats.cpu_wants_lp2_time[3] ?
495 div64_u64(idle_stats.in_lp2_time[3] * 100,
496 idle_stats.cpu_wants_lp2_time[3]) : 0),
497 (int)(idle_stats.cpu_wants_lp2_time[4] ?
498 div64_u64(idle_stats.in_lp2_time[4] * 100,
499 idle_stats.cpu_wants_lp2_time[4]) : 0));
500 seq_printf(s, "\n");
501
502 seq_printf(s, "%19s %8s %8s %8s\n", "", "lp2", "comp", "%");
503 seq_printf(s, "-------------------------------------------------\n");
504 for (bin = 0; bin < 32; bin++) {
505 if (idle_stats.lp2_count_bin[bin] == 0)
506 continue;
507 seq_printf(s, "%6u - %6u ms: %8u %8u %7u%%\n",
508 1 << (bin - 1), 1 << bin,
509 idle_stats.lp2_count_bin[bin],
510 idle_stats.lp2_completed_count_bin[bin],
511 idle_stats.lp2_completed_count_bin[bin] * 100 /
512 idle_stats.lp2_count_bin[bin]);
513 }
514
515 seq_printf(s, "\n");
516 seq_printf(s, "%3s %20s %6s %10s\n",
517 "int", "name", "count", "last count");
518 seq_printf(s, "--------------------------------------------\n");
519 for (i = 0; i < NR_IRQS; i++) {
520 if (idle_stats.lp2_int_count[i] == 0)
521 continue;
522 seq_printf(s, "%3d %20s %6d %10d\n",
523 i, irq_to_desc(i)->action ?
524 irq_to_desc(i)->action->name ?: "???" : "???",
525 idle_stats.lp2_int_count[i],
526 idle_stats.lp2_int_count[i] -
527 idle_stats.last_lp2_int_count[i]);
528 idle_stats.last_lp2_int_count[i] = idle_stats.lp2_int_count[i];
529 };
530 return 0;
531}
532#endif