blob: 4cdd7ae09628a1633236a136e5067ca0ddfeab68 [file] [log] [blame]
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001/* arch/arm/mach-msm/pm2.c
2 *
3 * MSM Power Management Routines
4 *
5 * Copyright (C) 2007 Google, Inc.
6 * Copyright (c) 2008-2011 Code Aurora Forum. All rights reserved.
7 *
8 * This software is licensed under the terms of the GNU General Public
9 * License version 2, as published by the Free Software Foundation, and
10 * may be copied, distributed, and modified under those terms.
11 *
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
16 *
17 */
18
19#include <linux/module.h>
20#include <linux/kernel.h>
21#include <linux/clk.h>
22#include <linux/delay.h>
23#include <linux/init.h>
24#include <linux/pm.h>
25#include <linux/pm_qos_params.h>
26#include <linux/proc_fs.h>
27#include <linux/suspend.h>
28#include <linux/reboot.h>
29#include <linux/uaccess.h>
30#include <linux/io.h>
31#include <linux/memory.h>
32#ifdef CONFIG_HAS_WAKELOCK
33#include <linux/wakelock.h>
34#endif
35#include <mach/msm_iomap.h>
36#include <mach/system.h>
37#ifdef CONFIG_CPU_V7
38#include <asm/pgtable.h>
39#include <asm/pgalloc.h>
40#endif
41#ifdef CONFIG_CACHE_L2X0
42#include <asm/hardware/cache-l2x0.h>
43#endif
44#ifdef CONFIG_VFP
45#include <asm/vfp.h>
46#endif
47
48#ifdef CONFIG_MSM_MEMORY_LOW_POWER_MODE_SUSPEND_DEEP_POWER_DOWN
49#include <mach/msm_migrate_pages.h>
50#endif
51
52#include "smd_private.h"
53#include "smd_rpcrouter.h"
54#include "acpuclock.h"
55#include "clock.h"
56#include "proc_comm.h"
57#include "idle.h"
58#include "irq.h"
59#include "gpio.h"
60#include "timer.h"
Matt Wagantall7cca4642012-02-01 16:43:24 -080061#include "pm.h"
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070062#include "spm.h"
63#include "sirc.h"
Maheshkumar Sivasubramanian8ccc16e2011-10-25 15:59:57 -060064#include "pm-boot.h"
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070065
66/******************************************************************************
67 * Debug Definitions
68 *****************************************************************************/
69
70enum {
71 MSM_PM_DEBUG_SUSPEND = 1U << 0,
72 MSM_PM_DEBUG_POWER_COLLAPSE = 1U << 1,
73 MSM_PM_DEBUG_STATE = 1U << 2,
74 MSM_PM_DEBUG_CLOCK = 1U << 3,
75 MSM_PM_DEBUG_RESET_VECTOR = 1U << 4,
76 MSM_PM_DEBUG_SMSM_STATE = 1U << 5,
77 MSM_PM_DEBUG_IDLE = 1U << 6,
78};
79
80static int msm_pm_debug_mask;
81module_param_named(
82 debug_mask, msm_pm_debug_mask, int, S_IRUGO | S_IWUSR | S_IWGRP
83);
84
85#define MSM_PM_DPRINTK(mask, level, message, ...) \
86 do { \
87 if ((mask) & msm_pm_debug_mask) \
88 printk(level message, ## __VA_ARGS__); \
89 } while (0)
90
91#define MSM_PM_DEBUG_PRINT_STATE(tag) \
92 do { \
93 MSM_PM_DPRINTK(MSM_PM_DEBUG_STATE, \
94 KERN_INFO, "%s: " \
95 "APPS_CLK_SLEEP_EN %x, APPS_PWRDOWN %x, " \
96 "SMSM_POWER_MASTER_DEM %x, SMSM_MODEM_STATE %x, " \
97 "SMSM_APPS_DEM %x\n", \
98 tag, \
99 __raw_readl(APPS_CLK_SLEEP_EN), \
100 __raw_readl(APPS_PWRDOWN), \
101 smsm_get_state(SMSM_POWER_MASTER_DEM), \
102 smsm_get_state(SMSM_MODEM_STATE), \
103 smsm_get_state(SMSM_APPS_DEM)); \
104 } while (0)
105
106#define MSM_PM_DEBUG_PRINT_SLEEP_INFO() \
107 do { \
108 if (msm_pm_debug_mask & MSM_PM_DEBUG_SMSM_STATE) \
109 smsm_print_sleep_info(msm_pm_smem_data->sleep_time, \
110 msm_pm_smem_data->resources_used, \
111 msm_pm_smem_data->irq_mask, \
112 msm_pm_smem_data->wakeup_reason, \
113 msm_pm_smem_data->pending_irqs); \
114 } while (0)
115
116
117/******************************************************************************
118 * Sleep Modes and Parameters
119 *****************************************************************************/
120
121static int msm_pm_sleep_mode = CONFIG_MSM7X00A_SLEEP_MODE;
122module_param_named(
123 sleep_mode, msm_pm_sleep_mode,
124 int, S_IRUGO | S_IWUSR | S_IWGRP
125);
126
127static int msm_pm_idle_sleep_mode = CONFIG_MSM7X00A_IDLE_SLEEP_MODE;
128module_param_named(
129 idle_sleep_mode, msm_pm_idle_sleep_mode,
130 int, S_IRUGO | S_IWUSR | S_IWGRP
131);
132
133static int msm_pm_idle_sleep_min_time = CONFIG_MSM7X00A_IDLE_SLEEP_MIN_TIME;
134module_param_named(
135 idle_sleep_min_time, msm_pm_idle_sleep_min_time,
136 int, S_IRUGO | S_IWUSR | S_IWGRP
137);
138
139enum {
140 MSM_PM_MODE_ATTR_SUSPEND,
141 MSM_PM_MODE_ATTR_IDLE,
142 MSM_PM_MODE_ATTR_LATENCY,
143 MSM_PM_MODE_ATTR_RESIDENCY,
144 MSM_PM_MODE_ATTR_NR,
145};
146
147static char *msm_pm_mode_attr_labels[MSM_PM_MODE_ATTR_NR] = {
148 [MSM_PM_MODE_ATTR_SUSPEND] = "suspend_enabled",
149 [MSM_PM_MODE_ATTR_IDLE] = "idle_enabled",
150 [MSM_PM_MODE_ATTR_LATENCY] = "latency",
151 [MSM_PM_MODE_ATTR_RESIDENCY] = "residency",
152};
153
154static char *msm_pm_sleep_mode_labels[MSM_PM_SLEEP_MODE_NR] = {
155 [MSM_PM_SLEEP_MODE_POWER_COLLAPSE_SUSPEND] = " ",
156 [MSM_PM_SLEEP_MODE_POWER_COLLAPSE] = "power_collapse",
157 [MSM_PM_SLEEP_MODE_APPS_SLEEP] = "apps_sleep",
158 [MSM_PM_SLEEP_MODE_RAMP_DOWN_AND_WAIT_FOR_INTERRUPT] =
159 "ramp_down_and_wfi",
160 [MSM_PM_SLEEP_MODE_WAIT_FOR_INTERRUPT] = "wfi",
161 [MSM_PM_SLEEP_MODE_POWER_COLLAPSE_NO_XO_SHUTDOWN] =
162 "power_collapse_no_xo_shutdown",
163 [MSM_PM_SLEEP_MODE_POWER_COLLAPSE_STANDALONE] =
164 "standalone_power_collapse",
165};
166
167static struct msm_pm_platform_data *msm_pm_modes;
168
169static struct kobject *msm_pm_mode_kobjs[MSM_PM_SLEEP_MODE_NR];
170static struct attribute_group *msm_pm_mode_attr_group[MSM_PM_SLEEP_MODE_NR];
171static struct attribute **msm_pm_mode_attrs[MSM_PM_SLEEP_MODE_NR];
172static struct kobj_attribute *msm_pm_mode_kobj_attrs[MSM_PM_SLEEP_MODE_NR];
173
174/*
175 * Write out the attribute.
176 */
177static ssize_t msm_pm_mode_attr_show(
178 struct kobject *kobj, struct kobj_attribute *attr, char *buf)
179{
180 int ret = -EINVAL;
181 int i;
182
183 for (i = 0; i < MSM_PM_SLEEP_MODE_NR; i++) {
184 struct kernel_param kp;
185
186 if (msm_pm_sleep_mode_labels[i] == NULL)
187 continue;
188
189 if (strcmp(kobj->name, msm_pm_sleep_mode_labels[i]))
190 continue;
191
192 if (!strcmp(attr->attr.name,
193 msm_pm_mode_attr_labels[MSM_PM_MODE_ATTR_SUSPEND])) {
194 u32 arg = msm_pm_modes[i].suspend_enabled;
195 kp.arg = &arg;
196 ret = param_get_ulong(buf, &kp);
197 } else if (!strcmp(attr->attr.name,
198 msm_pm_mode_attr_labels[MSM_PM_MODE_ATTR_IDLE])) {
199 u32 arg = msm_pm_modes[i].idle_enabled;
200 kp.arg = &arg;
201 ret = param_get_ulong(buf, &kp);
202 } else if (!strcmp(attr->attr.name,
203 msm_pm_mode_attr_labels[MSM_PM_MODE_ATTR_LATENCY])) {
204 kp.arg = &msm_pm_modes[i].latency;
205 ret = param_get_ulong(buf, &kp);
206 } else if (!strcmp(attr->attr.name,
207 msm_pm_mode_attr_labels[MSM_PM_MODE_ATTR_RESIDENCY])) {
208 kp.arg = &msm_pm_modes[i].residency;
209 ret = param_get_ulong(buf, &kp);
210 }
211
212 break;
213 }
214
215 if (ret > 0) {
216 strcat(buf, "\n");
217 ret++;
218 }
219
220 return ret;
221}
222
223/*
224 * Read in the new attribute value.
225 */
226static ssize_t msm_pm_mode_attr_store(struct kobject *kobj,
227 struct kobj_attribute *attr, const char *buf, size_t count)
228{
229 int ret = -EINVAL;
230 int i;
231
232 for (i = 0; i < MSM_PM_SLEEP_MODE_NR; i++) {
233 struct kernel_param kp;
234
235 if (msm_pm_sleep_mode_labels[i] == NULL)
236 continue;
237
238 if (strcmp(kobj->name, msm_pm_sleep_mode_labels[i]))
239 continue;
240
241 if (!strcmp(attr->attr.name,
242 msm_pm_mode_attr_labels[MSM_PM_MODE_ATTR_SUSPEND])) {
243 kp.arg = &msm_pm_modes[i].suspend_enabled;
244 ret = param_set_byte(buf, &kp);
245 } else if (!strcmp(attr->attr.name,
246 msm_pm_mode_attr_labels[MSM_PM_MODE_ATTR_IDLE])) {
247 kp.arg = &msm_pm_modes[i].idle_enabled;
248 ret = param_set_byte(buf, &kp);
249 } else if (!strcmp(attr->attr.name,
250 msm_pm_mode_attr_labels[MSM_PM_MODE_ATTR_LATENCY])) {
251 kp.arg = &msm_pm_modes[i].latency;
252 ret = param_set_ulong(buf, &kp);
253 } else if (!strcmp(attr->attr.name,
254 msm_pm_mode_attr_labels[MSM_PM_MODE_ATTR_RESIDENCY])) {
255 kp.arg = &msm_pm_modes[i].residency;
256 ret = param_set_ulong(buf, &kp);
257 }
258
259 break;
260 }
261
262 return ret ? ret : count;
263}
264
265/*
266 * Add sysfs entries for the sleep modes.
267 */
268static int __init msm_pm_mode_sysfs_add(void)
269{
270 struct kobject *module_kobj = NULL;
271 struct kobject *modes_kobj = NULL;
272
273 struct kobject *kobj;
274 struct attribute_group *attr_group;
275 struct attribute **attrs;
276 struct kobj_attribute *kobj_attrs;
277
278 int i, j, k;
279 int ret;
280
281 module_kobj = kset_find_obj(module_kset, KBUILD_MODNAME);
282 if (!module_kobj) {
283 printk(KERN_ERR "%s: cannot find kobject for module %s\n",
284 __func__, KBUILD_MODNAME);
285 ret = -ENOENT;
286 goto mode_sysfs_add_cleanup;
287 }
288
289 modes_kobj = kobject_create_and_add("modes", module_kobj);
290 if (!modes_kobj) {
291 printk(KERN_ERR "%s: cannot create modes kobject\n", __func__);
292 ret = -ENOMEM;
293 goto mode_sysfs_add_cleanup;
294 }
295
296 for (i = 0; i < ARRAY_SIZE(msm_pm_mode_kobjs); i++) {
297 if (!msm_pm_modes[i].suspend_supported &&
298 !msm_pm_modes[i].idle_supported)
299 continue;
300
301 kobj = kobject_create_and_add(
302 msm_pm_sleep_mode_labels[i], modes_kobj);
303 attr_group = kzalloc(sizeof(*attr_group), GFP_KERNEL);
304 attrs = kzalloc(sizeof(*attrs) * (MSM_PM_MODE_ATTR_NR + 1),
305 GFP_KERNEL);
306 kobj_attrs = kzalloc(sizeof(*kobj_attrs) * MSM_PM_MODE_ATTR_NR,
307 GFP_KERNEL);
308
309 if (!kobj || !attr_group || !attrs || !kobj_attrs) {
310 printk(KERN_ERR
311 "%s: cannot create kobject or attributes\n",
312 __func__);
313 ret = -ENOMEM;
314 goto mode_sysfs_add_abort;
315 }
316
317 for (k = 0, j = 0; k < MSM_PM_MODE_ATTR_NR; k++) {
318 if ((k == MSM_PM_MODE_ATTR_SUSPEND) &&
319 (!msm_pm_modes[i].suspend_supported))
320 continue;
321 if ((k == MSM_PM_MODE_ATTR_IDLE) &&
322 (!msm_pm_modes[i].idle_supported))
323 continue;
324
325 kobj_attrs[j].attr.mode = 0644;
326 kobj_attrs[j].show = msm_pm_mode_attr_show;
327 kobj_attrs[j].store = msm_pm_mode_attr_store;
328 kobj_attrs[j].attr.name = msm_pm_mode_attr_labels[k];
329 attrs[j] = &kobj_attrs[j].attr;
330 j++;
331 }
332 attrs[j] = NULL;
333
334 attr_group->attrs = attrs;
335 ret = sysfs_create_group(kobj, attr_group);
336 if (ret) {
337 printk(KERN_ERR
338 "%s: cannot create kobject attribute group\n",
339 __func__);
340 goto mode_sysfs_add_abort;
341 }
342
343 msm_pm_mode_kobjs[i] = kobj;
344 msm_pm_mode_attr_group[i] = attr_group;
345 msm_pm_mode_attrs[i] = attrs;
346 msm_pm_mode_kobj_attrs[i] = kobj_attrs;
347 }
348
349 return 0;
350
351mode_sysfs_add_abort:
352 kfree(kobj_attrs);
353 kfree(attrs);
354 kfree(attr_group);
355 kobject_put(kobj);
356
357mode_sysfs_add_cleanup:
358 for (i = ARRAY_SIZE(msm_pm_mode_kobjs) - 1; i >= 0; i--) {
359 if (!msm_pm_mode_kobjs[i])
360 continue;
361
362 sysfs_remove_group(
363 msm_pm_mode_kobjs[i], msm_pm_mode_attr_group[i]);
364
365 kfree(msm_pm_mode_kobj_attrs[i]);
366 kfree(msm_pm_mode_attrs[i]);
367 kfree(msm_pm_mode_attr_group[i]);
368 kobject_put(msm_pm_mode_kobjs[i]);
369 }
370
371 return ret;
372}
373
374void __init msm_pm_set_platform_data(
375 struct msm_pm_platform_data *data, int count)
376{
377 BUG_ON(MSM_PM_SLEEP_MODE_NR != count);
378 msm_pm_modes = data;
379}
380
381
382/******************************************************************************
383 * Sleep Limitations
384 *****************************************************************************/
385enum {
386 SLEEP_LIMIT_NONE = 0,
387 SLEEP_LIMIT_NO_TCXO_SHUTDOWN = 2,
388 SLEEP_LIMIT_MASK = 0x03,
389};
390
391#ifdef CONFIG_MSM_MEMORY_LOW_POWER_MODE
392enum {
393 SLEEP_RESOURCE_MEMORY_BIT0 = 0x0200,
394 SLEEP_RESOURCE_MEMORY_BIT1 = 0x0010,
395};
396#endif
397
398
399/******************************************************************************
400 * Configure Hardware for Power Down/Up
401 *****************************************************************************/
402
403#if defined(CONFIG_ARCH_MSM7X30)
404#define APPS_CLK_SLEEP_EN (MSM_GCC_BASE + 0x020)
405#define APPS_PWRDOWN (MSM_ACC_BASE + 0x01c)
406#define APPS_SECOP (MSM_TCSR_BASE + 0x038)
407#else /* defined(CONFIG_ARCH_MSM7X30) */
408#define APPS_CLK_SLEEP_EN (MSM_CSR_BASE + 0x11c)
409#define APPS_PWRDOWN (MSM_CSR_BASE + 0x440)
410#define APPS_STANDBY_CTL (MSM_CSR_BASE + 0x108)
411#endif /* defined(CONFIG_ARCH_MSM7X30) */
412
413/*
414 * Configure hardware registers in preparation for Apps power down.
415 */
416static void msm_pm_config_hw_before_power_down(void)
417{
418#if defined(CONFIG_ARCH_MSM7X30)
419 __raw_writel(1, APPS_PWRDOWN);
420 mb();
421 __raw_writel(4, APPS_SECOP);
422 mb();
423#elif defined(CONFIG_ARCH_MSM7X27)
424 __raw_writel(0x1f, APPS_CLK_SLEEP_EN);
425 mb();
426 __raw_writel(1, APPS_PWRDOWN);
427 mb();
428#elif defined(CONFIG_ARCH_MSM7x27A)
429 __raw_writel(0x7, APPS_CLK_SLEEP_EN);
430 mb();
431 __raw_writel(1, APPS_PWRDOWN);
432 mb();
433#else
434 __raw_writel(0x1f, APPS_CLK_SLEEP_EN);
435 mb();
436 __raw_writel(1, APPS_PWRDOWN);
437 mb();
438 __raw_writel(0, APPS_STANDBY_CTL);
439 mb();
440#endif
441}
442
443/*
444 * Clear hardware registers after Apps powers up.
445 */
446static void msm_pm_config_hw_after_power_up(void)
447{
448#if defined(CONFIG_ARCH_MSM7X30)
449 __raw_writel(0, APPS_SECOP);
450 mb();
451 __raw_writel(0, APPS_PWRDOWN);
452 mb();
453 msm_spm_reinit();
454#elif defined(CONFIG_ARCH_MSM7x27A)
455 __raw_writel(0, APPS_PWRDOWN);
456 mb();
457 __raw_writel(0, APPS_CLK_SLEEP_EN);
458 mb();
459#else
460 __raw_writel(0, APPS_PWRDOWN);
461 mb();
462 __raw_writel(0, APPS_CLK_SLEEP_EN);
463 mb();
464#endif
465}
466
467/*
468 * Configure hardware registers in preparation for SWFI.
469 */
470static void msm_pm_config_hw_before_swfi(void)
471{
472#if defined(CONFIG_ARCH_QSD8X50)
473 __raw_writel(0x1f, APPS_CLK_SLEEP_EN);
474 mb();
475#elif defined(CONFIG_ARCH_MSM7X27)
476 __raw_writel(0x0f, APPS_CLK_SLEEP_EN);
477 mb();
478#elif defined(CONFIG_ARCH_MSM7X27A)
479 __raw_writel(0x7, APPS_CLK_SLEEP_EN);
480 mb();
481#endif
482}
483
484/*
485 * Respond to timing out waiting for Modem
486 *
487 * NOTE: The function never returns.
488 */
489static void msm_pm_timeout(void)
490{
491#if defined(CONFIG_MSM_PM_TIMEOUT_RESET_CHIP)
492 printk(KERN_EMERG "%s(): resetting chip\n", __func__);
493 msm_proc_comm(PCOM_RESET_CHIP_IMM, NULL, NULL);
494#elif defined(CONFIG_MSM_PM_TIMEOUT_RESET_MODEM)
495 printk(KERN_EMERG "%s(): resetting modem\n", __func__);
496 msm_proc_comm_reset_modem_now();
497#elif defined(CONFIG_MSM_PM_TIMEOUT_HALT)
498 printk(KERN_EMERG "%s(): halting\n", __func__);
499#endif
500 for (;;)
501 ;
502}
503
504
505/******************************************************************************
506 * State Polling Definitions
507 *****************************************************************************/
508
509struct msm_pm_polled_group {
510 uint32_t group_id;
511
512 uint32_t bits_all_set;
513 uint32_t bits_all_clear;
514 uint32_t bits_any_set;
515 uint32_t bits_any_clear;
516
517 uint32_t value_read;
518};
519
520/*
521 * Return true if all bits indicated by flag are set in source.
522 */
523static inline bool msm_pm_all_set(uint32_t source, uint32_t flag)
524{
525 return (source & flag) == flag;
526}
527
528/*
529 * Return true if any bit indicated by flag are set in source.
530 */
531static inline bool msm_pm_any_set(uint32_t source, uint32_t flag)
532{
533 return !flag || (source & flag);
534}
535
536/*
537 * Return true if all bits indicated by flag are cleared in source.
538 */
539static inline bool msm_pm_all_clear(uint32_t source, uint32_t flag)
540{
541 return (~source & flag) == flag;
542}
543
544/*
545 * Return true if any bit indicated by flag are cleared in source.
546 */
547static inline bool msm_pm_any_clear(uint32_t source, uint32_t flag)
548{
549 return !flag || (~source & flag);
550}
551
552/*
553 * Poll the shared memory states as indicated by the poll groups.
554 *
555 * nr_grps: number of groups in the array
556 * grps: array of groups
557 *
558 * The function returns when conditions specified by any of the poll
559 * groups become true. The conditions specified by a poll group are
560 * deemed true when 1) at least one bit from bits_any_set is set OR one
561 * bit from bits_any_clear is cleared; and 2) all bits in bits_all_set
562 * are set; and 3) all bits in bits_all_clear are cleared.
563 *
564 * Return value:
565 * >=0: index of the poll group whose conditions have become true
566 * -ETIMEDOUT: timed out
567 */
568static int msm_pm_poll_state(int nr_grps, struct msm_pm_polled_group *grps)
569{
570 int i, k;
571
572 for (i = 0; i < 50000; i++) {
573 for (k = 0; k < nr_grps; k++) {
574 bool all_set, all_clear;
575 bool any_set, any_clear;
576
577 grps[k].value_read = smsm_get_state(grps[k].group_id);
578
579 all_set = msm_pm_all_set(grps[k].value_read,
580 grps[k].bits_all_set);
581 all_clear = msm_pm_all_clear(grps[k].value_read,
582 grps[k].bits_all_clear);
583 any_set = msm_pm_any_set(grps[k].value_read,
584 grps[k].bits_any_set);
585 any_clear = msm_pm_any_clear(grps[k].value_read,
586 grps[k].bits_any_clear);
587
588 if (all_set && all_clear && (any_set || any_clear))
589 return k;
590 }
591 udelay(50);
592 }
593
594 printk(KERN_ERR "%s failed:\n", __func__);
595 for (k = 0; k < nr_grps; k++)
596 printk(KERN_ERR "(%x, %x, %x, %x) %x\n",
597 grps[k].bits_all_set, grps[k].bits_all_clear,
598 grps[k].bits_any_set, grps[k].bits_any_clear,
599 grps[k].value_read);
600
601 return -ETIMEDOUT;
602}
603
604
605/******************************************************************************
606 * Suspend Max Sleep Time
607 *****************************************************************************/
608
609#define SCLK_HZ (32768)
610#define MSM_PM_SLEEP_TICK_LIMIT (0x6DDD000)
611
612#ifdef CONFIG_MSM_SLEEP_TIME_OVERRIDE
613static int msm_pm_sleep_time_override;
614module_param_named(sleep_time_override,
615 msm_pm_sleep_time_override, int, S_IRUGO | S_IWUSR | S_IWGRP);
616#endif
617
618static uint32_t msm_pm_max_sleep_time;
619
620/*
621 * Convert time from nanoseconds to slow clock ticks, then cap it to the
622 * specified limit
623 */
624static int64_t msm_pm_convert_and_cap_time(int64_t time_ns, int64_t limit)
625{
626 do_div(time_ns, NSEC_PER_SEC / SCLK_HZ);
627 return (time_ns > limit) ? limit : time_ns;
628}
629
630/*
631 * Set the sleep time for suspend. 0 means infinite sleep time.
632 */
633void msm_pm_set_max_sleep_time(int64_t max_sleep_time_ns)
634{
635 unsigned long flags;
636
637 local_irq_save(flags);
638 if (max_sleep_time_ns == 0) {
639 msm_pm_max_sleep_time = 0;
640 } else {
641 msm_pm_max_sleep_time = (uint32_t)msm_pm_convert_and_cap_time(
642 max_sleep_time_ns, MSM_PM_SLEEP_TICK_LIMIT);
643
644 if (msm_pm_max_sleep_time == 0)
645 msm_pm_max_sleep_time = 1;
646 }
647
648 MSM_PM_DPRINTK(MSM_PM_DEBUG_SUSPEND, KERN_INFO,
649 "%s(): Requested %lld ns Giving %u sclk ticks\n", __func__,
650 max_sleep_time_ns, msm_pm_max_sleep_time);
651 local_irq_restore(flags);
652}
653EXPORT_SYMBOL(msm_pm_set_max_sleep_time);
654
655
656/******************************************************************************
657 * CONFIG_MSM_IDLE_STATS
658 *****************************************************************************/
659
660#ifdef CONFIG_MSM_IDLE_STATS
661enum msm_pm_time_stats_id {
662 MSM_PM_STAT_REQUESTED_IDLE,
663 MSM_PM_STAT_IDLE_SPIN,
664 MSM_PM_STAT_IDLE_WFI,
665 MSM_PM_STAT_IDLE_STANDALONE_POWER_COLLAPSE,
666 MSM_PM_STAT_IDLE_FAILED_STANDALONE_POWER_COLLAPSE,
667 MSM_PM_STAT_IDLE_SLEEP,
668 MSM_PM_STAT_IDLE_FAILED_SLEEP,
669 MSM_PM_STAT_IDLE_POWER_COLLAPSE,
670 MSM_PM_STAT_IDLE_FAILED_POWER_COLLAPSE,
671 MSM_PM_STAT_SUSPEND,
672 MSM_PM_STAT_FAILED_SUSPEND,
673 MSM_PM_STAT_NOT_IDLE,
674 MSM_PM_STAT_COUNT
675};
676
677static struct msm_pm_time_stats {
678 const char *name;
679 int64_t first_bucket_time;
680 int bucket[CONFIG_MSM_IDLE_STATS_BUCKET_COUNT];
681 int64_t min_time[CONFIG_MSM_IDLE_STATS_BUCKET_COUNT];
682 int64_t max_time[CONFIG_MSM_IDLE_STATS_BUCKET_COUNT];
683 int count;
684 int64_t total_time;
685} msm_pm_stats[MSM_PM_STAT_COUNT] = {
686 [MSM_PM_STAT_REQUESTED_IDLE].name = "idle-request",
687 [MSM_PM_STAT_REQUESTED_IDLE].first_bucket_time =
688 CONFIG_MSM_IDLE_STATS_FIRST_BUCKET,
689
690 [MSM_PM_STAT_IDLE_SPIN].name = "idle-spin",
691 [MSM_PM_STAT_IDLE_SPIN].first_bucket_time =
692 CONFIG_MSM_IDLE_STATS_FIRST_BUCKET,
693
694 [MSM_PM_STAT_IDLE_WFI].name = "idle-wfi",
695 [MSM_PM_STAT_IDLE_WFI].first_bucket_time =
696 CONFIG_MSM_IDLE_STATS_FIRST_BUCKET,
697
698 [MSM_PM_STAT_IDLE_STANDALONE_POWER_COLLAPSE].name =
699 "idle-standalone-power-collapse",
700 [MSM_PM_STAT_IDLE_STANDALONE_POWER_COLLAPSE].first_bucket_time =
701 CONFIG_MSM_IDLE_STATS_FIRST_BUCKET,
702
703 [MSM_PM_STAT_IDLE_FAILED_STANDALONE_POWER_COLLAPSE].name =
704 "idle-failed-standalone-power-collapse",
705 [MSM_PM_STAT_IDLE_FAILED_STANDALONE_POWER_COLLAPSE].first_bucket_time =
706 CONFIG_MSM_IDLE_STATS_FIRST_BUCKET,
707
708 [MSM_PM_STAT_IDLE_SLEEP].name = "idle-sleep",
709 [MSM_PM_STAT_IDLE_SLEEP].first_bucket_time =
710 CONFIG_MSM_IDLE_STATS_FIRST_BUCKET,
711
712 [MSM_PM_STAT_IDLE_FAILED_SLEEP].name = "idle-failed-sleep",
713 [MSM_PM_STAT_IDLE_FAILED_SLEEP].first_bucket_time =
714 CONFIG_MSM_IDLE_STATS_FIRST_BUCKET,
715
716 [MSM_PM_STAT_IDLE_POWER_COLLAPSE].name = "idle-power-collapse",
717 [MSM_PM_STAT_IDLE_POWER_COLLAPSE].first_bucket_time =
718 CONFIG_MSM_IDLE_STATS_FIRST_BUCKET,
719
720 [MSM_PM_STAT_IDLE_FAILED_POWER_COLLAPSE].name =
721 "idle-failed-power-collapse",
722 [MSM_PM_STAT_IDLE_FAILED_POWER_COLLAPSE].first_bucket_time =
723 CONFIG_MSM_IDLE_STATS_FIRST_BUCKET,
724
725 [MSM_PM_STAT_SUSPEND].name = "suspend",
726 [MSM_PM_STAT_SUSPEND].first_bucket_time =
727 CONFIG_MSM_SUSPEND_STATS_FIRST_BUCKET,
728
729 [MSM_PM_STAT_FAILED_SUSPEND].name = "failed-suspend",
730 [MSM_PM_STAT_FAILED_SUSPEND].first_bucket_time =
731 CONFIG_MSM_IDLE_STATS_FIRST_BUCKET,
732
733 [MSM_PM_STAT_NOT_IDLE].name = "not-idle",
734 [MSM_PM_STAT_NOT_IDLE].first_bucket_time =
735 CONFIG_MSM_IDLE_STATS_FIRST_BUCKET,
736};
737
738static uint32_t msm_pm_sleep_limit = SLEEP_LIMIT_NONE;
739
740/*
741 * Add the given time data to the statistics collection.
742 */
743static void msm_pm_add_stat(enum msm_pm_time_stats_id id, int64_t t)
744{
745 int i;
746 int64_t bt;
747
748 msm_pm_stats[id].total_time += t;
749 msm_pm_stats[id].count++;
750
751 bt = t;
752 do_div(bt, msm_pm_stats[id].first_bucket_time);
753
754 if (bt < 1ULL << (CONFIG_MSM_IDLE_STATS_BUCKET_SHIFT *
755 (CONFIG_MSM_IDLE_STATS_BUCKET_COUNT - 1)))
756 i = DIV_ROUND_UP(fls((uint32_t)bt),
757 CONFIG_MSM_IDLE_STATS_BUCKET_SHIFT);
758 else
759 i = CONFIG_MSM_IDLE_STATS_BUCKET_COUNT - 1;
760
761 msm_pm_stats[id].bucket[i]++;
762
763 if (t < msm_pm_stats[id].min_time[i] || !msm_pm_stats[id].max_time[i])
764 msm_pm_stats[id].min_time[i] = t;
765 if (t > msm_pm_stats[id].max_time[i])
766 msm_pm_stats[id].max_time[i] = t;
767}
768
769/*
770 * Helper function of snprintf where buf is auto-incremented, size is auto-
771 * decremented, and there is no return value.
772 *
773 * NOTE: buf and size must be l-values (e.g. variables)
774 */
775#define SNPRINTF(buf, size, format, ...) \
776 do { \
777 if (size > 0) { \
778 int ret; \
779 ret = snprintf(buf, size, format, ## __VA_ARGS__); \
780 if (ret > size) { \
781 buf += size; \
782 size = 0; \
783 } else { \
784 buf += ret; \
785 size -= ret; \
786 } \
787 } \
788 } while (0)
789
790/*
791 * Write out the power management statistics.
792 */
793static int msm_pm_read_proc
794 (char *page, char **start, off_t off, int count, int *eof, void *data)
795{
796 int i;
797 char *p = page;
798
799 if (count < 1024) {
800 *start = (char *) 0;
801 *eof = 0;
802 return 0;
803 }
804
805 if (!off) {
806 SNPRINTF(p, count, "Last power collapse voted ");
807 if ((msm_pm_sleep_limit & SLEEP_LIMIT_MASK) ==
808 SLEEP_LIMIT_NONE)
809 SNPRINTF(p, count, "for TCXO shutdown\n\n");
810 else
811 SNPRINTF(p, count, "against TCXO shutdown\n\n");
812
813 *start = (char *) 1;
814 *eof = 0;
815 } else if (--off < ARRAY_SIZE(msm_pm_stats)) {
816 int64_t bucket_time;
817 int64_t s;
818 uint32_t ns;
819
820 s = msm_pm_stats[off].total_time;
821 ns = do_div(s, NSEC_PER_SEC);
822 SNPRINTF(p, count,
823 "%s:\n"
824 " count: %7d\n"
825 " total_time: %lld.%09u\n",
826 msm_pm_stats[off].name,
827 msm_pm_stats[off].count,
828 s, ns);
829
830 bucket_time = msm_pm_stats[off].first_bucket_time;
831 for (i = 0; i < CONFIG_MSM_IDLE_STATS_BUCKET_COUNT - 1; i++) {
832 s = bucket_time;
833 ns = do_div(s, NSEC_PER_SEC);
834 SNPRINTF(p, count,
835 " <%6lld.%09u: %7d (%lld-%lld)\n",
836 s, ns, msm_pm_stats[off].bucket[i],
837 msm_pm_stats[off].min_time[i],
838 msm_pm_stats[off].max_time[i]);
839
840 bucket_time <<= CONFIG_MSM_IDLE_STATS_BUCKET_SHIFT;
841 }
842
843 SNPRINTF(p, count, " >=%6lld.%09u: %7d (%lld-%lld)\n",
844 s, ns, msm_pm_stats[off].bucket[i],
845 msm_pm_stats[off].min_time[i],
846 msm_pm_stats[off].max_time[i]);
847
848 *start = (char *) 1;
849 *eof = (off + 1 >= ARRAY_SIZE(msm_pm_stats));
850 }
851
852 return p - page;
853}
854#undef SNPRINTF
855
856#define MSM_PM_STATS_RESET "reset"
857
858/*
859 * Reset the power management statistics values.
860 */
861static int msm_pm_write_proc(struct file *file, const char __user *buffer,
862 unsigned long count, void *data)
863{
864 char buf[sizeof(MSM_PM_STATS_RESET)];
865 int ret;
866 unsigned long flags;
867 int i;
868
869 if (count < strlen(MSM_PM_STATS_RESET)) {
870 ret = -EINVAL;
871 goto write_proc_failed;
872 }
873
874 if (copy_from_user(buf, buffer, strlen(MSM_PM_STATS_RESET))) {
875 ret = -EFAULT;
876 goto write_proc_failed;
877 }
878
879 if (memcmp(buf, MSM_PM_STATS_RESET, strlen(MSM_PM_STATS_RESET))) {
880 ret = -EINVAL;
881 goto write_proc_failed;
882 }
883
884 local_irq_save(flags);
885 for (i = 0; i < ARRAY_SIZE(msm_pm_stats); i++) {
886 memset(msm_pm_stats[i].bucket,
887 0, sizeof(msm_pm_stats[i].bucket));
888 memset(msm_pm_stats[i].min_time,
889 0, sizeof(msm_pm_stats[i].min_time));
890 memset(msm_pm_stats[i].max_time,
891 0, sizeof(msm_pm_stats[i].max_time));
892 msm_pm_stats[i].count = 0;
893 msm_pm_stats[i].total_time = 0;
894 }
895
896 msm_pm_sleep_limit = SLEEP_LIMIT_NONE;
897 local_irq_restore(flags);
898
899 return count;
900
901write_proc_failed:
902 return ret;
903}
904#undef MSM_PM_STATS_RESET
905#endif /* CONFIG_MSM_IDLE_STATS */
906
907
908/******************************************************************************
909 * Shared Memory Bits
910 *****************************************************************************/
911
912#define DEM_MASTER_BITS_PER_CPU 6
913
914/* Power Master State Bits - Per CPU */
915#define DEM_MASTER_SMSM_RUN \
916 (0x01UL << (DEM_MASTER_BITS_PER_CPU * SMSM_APPS_STATE))
917#define DEM_MASTER_SMSM_RSA \
918 (0x02UL << (DEM_MASTER_BITS_PER_CPU * SMSM_APPS_STATE))
919#define DEM_MASTER_SMSM_PWRC_EARLY_EXIT \
920 (0x04UL << (DEM_MASTER_BITS_PER_CPU * SMSM_APPS_STATE))
921#define DEM_MASTER_SMSM_SLEEP_EXIT \
922 (0x08UL << (DEM_MASTER_BITS_PER_CPU * SMSM_APPS_STATE))
923#define DEM_MASTER_SMSM_READY \
924 (0x10UL << (DEM_MASTER_BITS_PER_CPU * SMSM_APPS_STATE))
925#define DEM_MASTER_SMSM_SLEEP \
926 (0x20UL << (DEM_MASTER_BITS_PER_CPU * SMSM_APPS_STATE))
927
928/* Power Slave State Bits */
929#define DEM_SLAVE_SMSM_RUN (0x0001)
930#define DEM_SLAVE_SMSM_PWRC (0x0002)
931#define DEM_SLAVE_SMSM_PWRC_DELAY (0x0004)
932#define DEM_SLAVE_SMSM_PWRC_EARLY_EXIT (0x0008)
933#define DEM_SLAVE_SMSM_WFPI (0x0010)
934#define DEM_SLAVE_SMSM_SLEEP (0x0020)
935#define DEM_SLAVE_SMSM_SLEEP_EXIT (0x0040)
936#define DEM_SLAVE_SMSM_MSGS_REDUCED (0x0080)
937#define DEM_SLAVE_SMSM_RESET (0x0100)
938#define DEM_SLAVE_SMSM_PWRC_SUSPEND (0x0200)
939
940
941/******************************************************************************
942 * Shared Memory Data
943 *****************************************************************************/
944
945#define DEM_MAX_PORT_NAME_LEN (20)
946
947struct msm_pm_smem_t {
948 uint32_t sleep_time;
949 uint32_t irq_mask;
950 uint32_t resources_used;
951 uint32_t reserved1;
952
953 uint32_t wakeup_reason;
954 uint32_t pending_irqs;
955 uint32_t rpc_prog;
956 uint32_t rpc_proc;
957 char smd_port_name[DEM_MAX_PORT_NAME_LEN];
958 uint32_t reserved2;
959};
960
961
962/******************************************************************************
963 *
964 *****************************************************************************/
965static struct msm_pm_smem_t *msm_pm_smem_data;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700966static atomic_t msm_pm_init_done = ATOMIC_INIT(0);
967
968static int msm_pm_modem_busy(void)
969{
970 if (!(smsm_get_state(SMSM_POWER_MASTER_DEM) & DEM_MASTER_SMSM_READY)) {
971 MSM_PM_DPRINTK(MSM_PM_DEBUG_POWER_COLLAPSE,
972 KERN_INFO, "%s(): master not ready\n", __func__);
973 return -EBUSY;
974 }
975
976 return 0;
977}
978
979/*
980 * Power collapse the Apps processor. This function executes the handshake
981 * protocol with Modem.
982 *
983 * Return value:
984 * -EAGAIN: modem reset occurred or early exit from power collapse
985 * -EBUSY: modem not ready for our power collapse -- no power loss
986 * -ETIMEDOUT: timed out waiting for modem's handshake -- no power loss
987 * 0: success
988 */
989static int msm_pm_power_collapse
990 (bool from_idle, uint32_t sleep_delay, uint32_t sleep_limit)
991{
992 struct msm_pm_polled_group state_grps[2];
993 unsigned long saved_acpuclk_rate;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700994 int collapsed = 0;
995 int ret;
996
997 MSM_PM_DPRINTK(MSM_PM_DEBUG_SUSPEND|MSM_PM_DEBUG_POWER_COLLAPSE,
998 KERN_INFO, "%s(): idle %d, delay %u, limit %u\n", __func__,
999 (int)from_idle, sleep_delay, sleep_limit);
1000
1001 if (!(smsm_get_state(SMSM_POWER_MASTER_DEM) & DEM_MASTER_SMSM_READY)) {
1002 MSM_PM_DPRINTK(
1003 MSM_PM_DEBUG_SUSPEND | MSM_PM_DEBUG_POWER_COLLAPSE,
1004 KERN_INFO, "%s(): master not ready\n", __func__);
1005 ret = -EBUSY;
1006 goto power_collapse_bail;
1007 }
1008
1009 memset(msm_pm_smem_data, 0, sizeof(*msm_pm_smem_data));
1010
1011 msm_irq_enter_sleep1(true, from_idle, &msm_pm_smem_data->irq_mask);
1012 msm_sirc_enter_sleep();
1013 msm_gpio_enter_sleep(from_idle);
1014
1015 msm_pm_smem_data->sleep_time = sleep_delay;
1016 msm_pm_smem_data->resources_used = sleep_limit;
1017
1018 /* Enter PWRC/PWRC_SUSPEND */
1019
1020 if (from_idle)
1021 smsm_change_state(SMSM_APPS_DEM, DEM_SLAVE_SMSM_RUN,
1022 DEM_SLAVE_SMSM_PWRC);
1023 else
1024 smsm_change_state(SMSM_APPS_DEM, DEM_SLAVE_SMSM_RUN,
1025 DEM_SLAVE_SMSM_PWRC | DEM_SLAVE_SMSM_PWRC_SUSPEND);
1026
1027 MSM_PM_DEBUG_PRINT_STATE("msm_pm_power_collapse(): PWRC");
1028 MSM_PM_DEBUG_PRINT_SLEEP_INFO();
1029
1030 memset(state_grps, 0, sizeof(state_grps));
1031 state_grps[0].group_id = SMSM_POWER_MASTER_DEM;
1032 state_grps[0].bits_all_set = DEM_MASTER_SMSM_RSA;
1033 state_grps[1].group_id = SMSM_MODEM_STATE;
1034 state_grps[1].bits_all_set = SMSM_RESET;
1035
1036 ret = msm_pm_poll_state(ARRAY_SIZE(state_grps), state_grps);
1037
1038 if (ret < 0) {
1039 printk(KERN_EMERG "%s(): power collapse entry "
1040 "timed out waiting for Modem's response\n", __func__);
1041 msm_pm_timeout();
1042 }
1043
1044 if (ret == 1) {
1045 MSM_PM_DPRINTK(
1046 MSM_PM_DEBUG_SUSPEND|MSM_PM_DEBUG_POWER_COLLAPSE,
1047 KERN_INFO,
1048 "%s(): msm_pm_poll_state detected Modem reset\n",
1049 __func__);
1050 goto power_collapse_early_exit;
1051 }
1052
1053 /* DEM Master in RSA */
1054
1055 MSM_PM_DEBUG_PRINT_STATE("msm_pm_power_collapse(): PWRC RSA");
1056
1057 ret = msm_irq_enter_sleep2(true, from_idle);
1058 if (ret < 0) {
1059 MSM_PM_DPRINTK(
1060 MSM_PM_DEBUG_SUSPEND|MSM_PM_DEBUG_POWER_COLLAPSE,
1061 KERN_INFO,
1062 "%s(): msm_irq_enter_sleep2 aborted, %d\n", __func__,
1063 ret);
1064 goto power_collapse_early_exit;
1065 }
1066
1067 msm_pm_config_hw_before_power_down();
1068 MSM_PM_DEBUG_PRINT_STATE("msm_pm_power_collapse(): pre power down");
1069
1070 saved_acpuclk_rate = acpuclk_power_collapse();
1071 MSM_PM_DPRINTK(MSM_PM_DEBUG_CLOCK, KERN_INFO,
1072 "%s(): change clock rate (old rate = %lu)\n", __func__,
1073 saved_acpuclk_rate);
1074
1075 if (saved_acpuclk_rate == 0) {
1076 msm_pm_config_hw_after_power_up();
1077 goto power_collapse_early_exit;
1078 }
1079
Maheshkumar Sivasubramanian8ccc16e2011-10-25 15:59:57 -06001080 msm_pm_boot_config_before_pc(smp_processor_id(),
1081 virt_to_phys(msm_pm_collapse_exit));
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001082
1083#ifdef CONFIG_VFP
1084 if (from_idle)
1085 vfp_flush_context();
1086#endif
1087
1088#ifdef CONFIG_CACHE_L2X0
1089 l2x0_suspend();
1090#endif
1091
1092 collapsed = msm_pm_collapse();
1093
1094#ifdef CONFIG_CACHE_L2X0
1095 l2x0_resume(collapsed);
1096#endif
1097
Maheshkumar Sivasubramanian8ccc16e2011-10-25 15:59:57 -06001098 msm_pm_boot_config_after_pc(smp_processor_id());
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001099
1100 if (collapsed) {
1101#ifdef CONFIG_VFP
1102 if (from_idle)
1103 vfp_reinit();
1104#endif
1105 cpu_init();
1106 local_fiq_enable();
1107 }
1108
1109 MSM_PM_DPRINTK(MSM_PM_DEBUG_SUSPEND | MSM_PM_DEBUG_POWER_COLLAPSE,
1110 KERN_INFO,
1111 "%s(): msm_pm_collapse returned %d\n", __func__, collapsed);
1112
1113 MSM_PM_DPRINTK(MSM_PM_DEBUG_CLOCK, KERN_INFO,
1114 "%s(): restore clock rate to %lu\n", __func__,
1115 saved_acpuclk_rate);
1116 if (acpuclk_set_rate(smp_processor_id(), saved_acpuclk_rate,
1117 SETRATE_PC) < 0)
1118 printk(KERN_ERR "%s(): failed to restore clock rate(%lu)\n",
1119 __func__, saved_acpuclk_rate);
1120
1121 msm_irq_exit_sleep1(msm_pm_smem_data->irq_mask,
1122 msm_pm_smem_data->wakeup_reason,
1123 msm_pm_smem_data->pending_irqs);
1124
1125 msm_pm_config_hw_after_power_up();
1126 MSM_PM_DEBUG_PRINT_STATE("msm_pm_power_collapse(): post power up");
1127
1128 memset(state_grps, 0, sizeof(state_grps));
1129 state_grps[0].group_id = SMSM_POWER_MASTER_DEM;
1130 state_grps[0].bits_any_set =
1131 DEM_MASTER_SMSM_RSA | DEM_MASTER_SMSM_PWRC_EARLY_EXIT;
1132 state_grps[1].group_id = SMSM_MODEM_STATE;
1133 state_grps[1].bits_all_set = SMSM_RESET;
1134
1135 ret = msm_pm_poll_state(ARRAY_SIZE(state_grps), state_grps);
1136
1137 if (ret < 0) {
1138 printk(KERN_EMERG "%s(): power collapse exit "
1139 "timed out waiting for Modem's response\n", __func__);
1140 msm_pm_timeout();
1141 }
1142
1143 if (ret == 1) {
1144 MSM_PM_DPRINTK(
1145 MSM_PM_DEBUG_SUSPEND|MSM_PM_DEBUG_POWER_COLLAPSE,
1146 KERN_INFO,
1147 "%s(): msm_pm_poll_state detected Modem reset\n",
1148 __func__);
1149 goto power_collapse_early_exit;
1150 }
1151
1152 /* Sanity check */
1153 if (collapsed) {
1154 BUG_ON(!(state_grps[0].value_read & DEM_MASTER_SMSM_RSA));
1155 } else {
1156 BUG_ON(!(state_grps[0].value_read &
1157 DEM_MASTER_SMSM_PWRC_EARLY_EXIT));
1158 goto power_collapse_early_exit;
1159 }
1160
1161 /* Enter WFPI */
1162
1163 smsm_change_state(SMSM_APPS_DEM,
1164 DEM_SLAVE_SMSM_PWRC | DEM_SLAVE_SMSM_PWRC_SUSPEND,
1165 DEM_SLAVE_SMSM_WFPI);
1166
1167 MSM_PM_DEBUG_PRINT_STATE("msm_pm_power_collapse(): WFPI");
1168
1169 memset(state_grps, 0, sizeof(state_grps));
1170 state_grps[0].group_id = SMSM_POWER_MASTER_DEM;
1171 state_grps[0].bits_all_set = DEM_MASTER_SMSM_RUN;
1172 state_grps[1].group_id = SMSM_MODEM_STATE;
1173 state_grps[1].bits_all_set = SMSM_RESET;
1174
1175 ret = msm_pm_poll_state(ARRAY_SIZE(state_grps), state_grps);
1176
1177 if (ret < 0) {
1178 printk(KERN_EMERG "%s(): power collapse WFPI "
1179 "timed out waiting for Modem's response\n", __func__);
1180 msm_pm_timeout();
1181 }
1182
1183 if (ret == 1) {
1184 MSM_PM_DPRINTK(
1185 MSM_PM_DEBUG_SUSPEND|MSM_PM_DEBUG_POWER_COLLAPSE,
1186 KERN_INFO,
1187 "%s(): msm_pm_poll_state detected Modem reset\n",
1188 __func__);
1189 ret = -EAGAIN;
1190 goto power_collapse_restore_gpio_bail;
1191 }
1192
1193 /* DEM Master == RUN */
1194
1195 MSM_PM_DEBUG_PRINT_STATE("msm_pm_power_collapse(): WFPI RUN");
1196 MSM_PM_DEBUG_PRINT_SLEEP_INFO();
1197
1198 msm_irq_exit_sleep2(msm_pm_smem_data->irq_mask,
1199 msm_pm_smem_data->wakeup_reason,
1200 msm_pm_smem_data->pending_irqs);
1201 msm_irq_exit_sleep3(msm_pm_smem_data->irq_mask,
1202 msm_pm_smem_data->wakeup_reason,
1203 msm_pm_smem_data->pending_irqs);
1204 msm_gpio_exit_sleep();
1205 msm_sirc_exit_sleep();
1206
1207 smsm_change_state(SMSM_APPS_DEM,
1208 DEM_SLAVE_SMSM_WFPI, DEM_SLAVE_SMSM_RUN);
1209
1210 MSM_PM_DEBUG_PRINT_STATE("msm_pm_power_collapse(): RUN");
1211
1212 smd_sleep_exit();
1213 return 0;
1214
1215power_collapse_early_exit:
1216 /* Enter PWRC_EARLY_EXIT */
1217
1218 smsm_change_state(SMSM_APPS_DEM,
1219 DEM_SLAVE_SMSM_PWRC | DEM_SLAVE_SMSM_PWRC_SUSPEND,
1220 DEM_SLAVE_SMSM_PWRC_EARLY_EXIT);
1221
1222 MSM_PM_DEBUG_PRINT_STATE("msm_pm_power_collapse(): EARLY_EXIT");
1223
1224 memset(state_grps, 0, sizeof(state_grps));
1225 state_grps[0].group_id = SMSM_POWER_MASTER_DEM;
1226 state_grps[0].bits_all_set = DEM_MASTER_SMSM_PWRC_EARLY_EXIT;
1227 state_grps[1].group_id = SMSM_MODEM_STATE;
1228 state_grps[1].bits_all_set = SMSM_RESET;
1229
1230 ret = msm_pm_poll_state(ARRAY_SIZE(state_grps), state_grps);
1231 MSM_PM_DEBUG_PRINT_STATE("msm_pm_power_collapse(): EARLY_EXIT EE");
1232
1233 if (ret < 0) {
1234 printk(KERN_EMERG "%s(): power collapse EARLY_EXIT "
1235 "timed out waiting for Modem's response\n", __func__);
1236 msm_pm_timeout();
1237 }
1238
1239 if (ret == 1) {
1240 MSM_PM_DPRINTK(
1241 MSM_PM_DEBUG_SUSPEND|MSM_PM_DEBUG_POWER_COLLAPSE,
1242 KERN_INFO,
1243 "%s(): msm_pm_poll_state detected Modem reset\n",
1244 __func__);
1245 }
1246
1247 /* DEM Master == RESET or PWRC_EARLY_EXIT */
1248
1249 ret = -EAGAIN;
1250
1251power_collapse_restore_gpio_bail:
1252 msm_gpio_exit_sleep();
1253 msm_sirc_exit_sleep();
1254
1255 /* Enter RUN */
1256 smsm_change_state(SMSM_APPS_DEM,
1257 DEM_SLAVE_SMSM_PWRC | DEM_SLAVE_SMSM_PWRC_SUSPEND |
1258 DEM_SLAVE_SMSM_PWRC_EARLY_EXIT, DEM_SLAVE_SMSM_RUN);
1259
1260 MSM_PM_DEBUG_PRINT_STATE("msm_pm_power_collapse(): RUN");
1261
1262 if (collapsed)
1263 smd_sleep_exit();
1264
1265power_collapse_bail:
1266 return ret;
1267}
1268
1269/*
1270 * Power collapse the Apps processor without involving Modem.
1271 *
1272 * Return value:
1273 * 0: success
1274 */
1275static int msm_pm_power_collapse_standalone(void)
1276{
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001277 int collapsed = 0;
1278 int ret;
1279
1280 MSM_PM_DPRINTK(MSM_PM_DEBUG_SUSPEND|MSM_PM_DEBUG_POWER_COLLAPSE,
1281 KERN_INFO, "%s()\n", __func__);
1282
1283 ret = msm_spm_set_low_power_mode(MSM_SPM_MODE_POWER_COLLAPSE, false);
1284 WARN_ON(ret);
1285
Maheshkumar Sivasubramanian8ccc16e2011-10-25 15:59:57 -06001286 msm_pm_boot_config_before_pc(smp_processor_id(),
1287 virt_to_phys(msm_pm_collapse_exit));
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001288
1289#ifdef CONFIG_VFP
1290 vfp_flush_context();
1291#endif
1292
1293#ifdef CONFIG_CACHE_L2X0
1294 l2x0_suspend();
1295#endif
1296
1297 collapsed = msm_pm_collapse();
1298
1299#ifdef CONFIG_CACHE_L2X0
1300 l2x0_resume(collapsed);
1301#endif
1302
Maheshkumar Sivasubramanian8ccc16e2011-10-25 15:59:57 -06001303 msm_pm_boot_config_after_pc(smp_processor_id());
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001304
1305 if (collapsed) {
1306#ifdef CONFIG_VFP
1307 vfp_reinit();
1308#endif
1309 cpu_init();
1310 local_fiq_enable();
1311 }
1312
1313 MSM_PM_DPRINTK(MSM_PM_DEBUG_SUSPEND | MSM_PM_DEBUG_POWER_COLLAPSE,
1314 KERN_INFO,
1315 "%s(): msm_pm_collapse returned %d\n", __func__, collapsed);
1316
1317 ret = msm_spm_set_low_power_mode(MSM_SPM_MODE_CLOCK_GATING, false);
1318 WARN_ON(ret);
1319
1320 return 0;
1321}
1322
1323/*
1324 * Apps-sleep the Apps processor. This function execute the handshake
1325 * protocol with Modem.
1326 *
1327 * Return value:
1328 * -ENOSYS: function not implemented yet
1329 */
1330static int msm_pm_apps_sleep(uint32_t sleep_delay, uint32_t sleep_limit)
1331{
1332 return -ENOSYS;
1333}
1334
1335/*
1336 * Bring the Apps processor to SWFI.
1337 *
1338 * Return value:
1339 * -EIO: could not ramp Apps processor clock
1340 * 0: success
1341 */
1342static int msm_pm_swfi(bool ramp_acpu)
1343{
1344 unsigned long saved_acpuclk_rate = 0;
1345
1346 if (ramp_acpu) {
1347 saved_acpuclk_rate = acpuclk_wait_for_irq();
1348 MSM_PM_DPRINTK(MSM_PM_DEBUG_CLOCK, KERN_INFO,
1349 "%s(): change clock rate (old rate = %lu)\n", __func__,
1350 saved_acpuclk_rate);
1351
1352 if (!saved_acpuclk_rate)
1353 return -EIO;
1354 }
1355
1356 msm_pm_config_hw_before_swfi();
1357 msm_arch_idle();
1358
1359 if (ramp_acpu) {
1360 MSM_PM_DPRINTK(MSM_PM_DEBUG_CLOCK, KERN_INFO,
1361 "%s(): restore clock rate to %lu\n", __func__,
1362 saved_acpuclk_rate);
1363 if (acpuclk_set_rate(smp_processor_id(), saved_acpuclk_rate,
1364 SETRATE_SWFI) < 0)
1365 printk(KERN_ERR
1366 "%s(): failed to restore clock rate(%lu)\n",
1367 __func__, saved_acpuclk_rate);
1368 }
1369
1370 return 0;
1371}
1372
1373
1374/******************************************************************************
1375 * External Idle/Suspend Functions
1376 *****************************************************************************/
1377
1378/*
1379 * Put CPU in low power mode.
1380 */
1381void arch_idle(void)
1382{
1383 bool allow[MSM_PM_SLEEP_MODE_NR];
1384 uint32_t sleep_limit = SLEEP_LIMIT_NONE;
1385
1386 int latency_qos;
1387 int64_t timer_expiration;
1388
1389 int low_power;
1390 int ret;
1391 int i;
1392
1393#ifdef CONFIG_MSM_IDLE_STATS
1394 int64_t t1;
1395 static int64_t t2;
1396 int exit_stat;
1397#endif /* CONFIG_MSM_IDLE_STATS */
1398
1399 if (!atomic_read(&msm_pm_init_done))
1400 return;
1401
1402 latency_qos = pm_qos_request(PM_QOS_CPU_DMA_LATENCY);
1403 timer_expiration = msm_timer_enter_idle();
1404
1405#ifdef CONFIG_MSM_IDLE_STATS
1406 t1 = ktime_to_ns(ktime_get());
1407 msm_pm_add_stat(MSM_PM_STAT_NOT_IDLE, t1 - t2);
1408 msm_pm_add_stat(MSM_PM_STAT_REQUESTED_IDLE, timer_expiration);
1409#endif /* CONFIG_MSM_IDLE_STATS */
1410
1411 for (i = 0; i < ARRAY_SIZE(allow); i++)
1412 allow[i] = true;
1413
1414 switch (msm_pm_idle_sleep_mode) {
1415 case MSM_PM_SLEEP_MODE_WAIT_FOR_INTERRUPT:
1416 allow[MSM_PM_SLEEP_MODE_RAMP_DOWN_AND_WAIT_FOR_INTERRUPT] =
1417 false;
1418 /* fall through */
1419 case MSM_PM_SLEEP_MODE_RAMP_DOWN_AND_WAIT_FOR_INTERRUPT:
1420 allow[MSM_PM_SLEEP_MODE_POWER_COLLAPSE_STANDALONE] = false;
1421 /* fall through */
1422 case MSM_PM_SLEEP_MODE_POWER_COLLAPSE_STANDALONE:
1423 allow[MSM_PM_SLEEP_MODE_APPS_SLEEP] = false;
1424 /* fall through */
1425 case MSM_PM_SLEEP_MODE_APPS_SLEEP:
1426 allow[MSM_PM_SLEEP_MODE_POWER_COLLAPSE_NO_XO_SHUTDOWN] = false;
1427 allow[MSM_PM_SLEEP_MODE_POWER_COLLAPSE] = false;
1428 /* fall through */
1429 case MSM_PM_SLEEP_MODE_POWER_COLLAPSE_SUSPEND:
1430 case MSM_PM_SLEEP_MODE_POWER_COLLAPSE:
1431 break;
1432 default:
1433 printk(KERN_ERR "idle sleep mode is invalid: %d\n",
1434 msm_pm_idle_sleep_mode);
1435#ifdef CONFIG_MSM_IDLE_STATS
1436 exit_stat = MSM_PM_STAT_IDLE_SPIN;
1437#endif /* CONFIG_MSM_IDLE_STATS */
1438 low_power = 0;
1439 goto arch_idle_exit;
1440 }
1441
1442 if ((timer_expiration < msm_pm_idle_sleep_min_time) ||
1443#ifdef CONFIG_HAS_WAKELOCK
1444 has_wake_lock(WAKE_LOCK_IDLE) ||
1445#endif
1446 !msm_irq_idle_sleep_allowed()) {
1447 allow[MSM_PM_SLEEP_MODE_POWER_COLLAPSE] = false;
1448 allow[MSM_PM_SLEEP_MODE_POWER_COLLAPSE_NO_XO_SHUTDOWN] = false;
1449 allow[MSM_PM_SLEEP_MODE_APPS_SLEEP] = false;
1450 }
1451
1452 for (i = 0; i < ARRAY_SIZE(allow); i++) {
1453 struct msm_pm_platform_data *mode = &msm_pm_modes[i];
1454 if (!mode->idle_supported || !mode->idle_enabled ||
1455 mode->latency >= latency_qos ||
1456 mode->residency * 1000ULL >= timer_expiration)
1457 allow[i] = false;
1458 }
1459
1460 if (allow[MSM_PM_SLEEP_MODE_POWER_COLLAPSE] ||
1461 allow[MSM_PM_SLEEP_MODE_POWER_COLLAPSE_NO_XO_SHUTDOWN]) {
1462 uint32_t wait_us = CONFIG_MSM_IDLE_WAIT_ON_MODEM;
1463 while (msm_pm_modem_busy() && wait_us) {
1464 if (wait_us > 100) {
1465 udelay(100);
1466 wait_us -= 100;
1467 } else {
1468 udelay(wait_us);
1469 wait_us = 0;
1470 }
1471 }
1472
1473 if (msm_pm_modem_busy()) {
1474 allow[MSM_PM_SLEEP_MODE_POWER_COLLAPSE] = false;
1475 allow[MSM_PM_SLEEP_MODE_POWER_COLLAPSE_NO_XO_SHUTDOWN]
1476 = false;
1477 }
1478 }
1479
1480 MSM_PM_DPRINTK(MSM_PM_DEBUG_IDLE, KERN_INFO,
1481 "%s(): latency qos %d, next timer %lld, sleep limit %u\n",
1482 __func__, latency_qos, timer_expiration, sleep_limit);
1483
1484 for (i = 0; i < ARRAY_SIZE(allow); i++)
1485 MSM_PM_DPRINTK(MSM_PM_DEBUG_IDLE, KERN_INFO,
1486 "%s(): allow %s: %d\n", __func__,
1487 msm_pm_sleep_mode_labels[i], (int)allow[i]);
1488
1489 if (allow[MSM_PM_SLEEP_MODE_POWER_COLLAPSE] ||
1490 allow[MSM_PM_SLEEP_MODE_POWER_COLLAPSE_NO_XO_SHUTDOWN]) {
1491 uint32_t sleep_delay;
1492
1493 sleep_delay = (uint32_t) msm_pm_convert_and_cap_time(
1494 timer_expiration, MSM_PM_SLEEP_TICK_LIMIT);
1495 if (sleep_delay == 0) /* 0 would mean infinite time */
1496 sleep_delay = 1;
1497
1498 if (!allow[MSM_PM_SLEEP_MODE_POWER_COLLAPSE])
1499 sleep_limit = SLEEP_LIMIT_NO_TCXO_SHUTDOWN;
1500
1501#if defined(CONFIG_MSM_MEMORY_LOW_POWER_MODE_IDLE_ACTIVE)
1502 sleep_limit |= SLEEP_RESOURCE_MEMORY_BIT1;
1503#elif defined(CONFIG_MSM_MEMORY_LOW_POWER_MODE_IDLE_RETENTION)
1504 sleep_limit |= SLEEP_RESOURCE_MEMORY_BIT0;
1505#endif
1506
1507 ret = msm_pm_power_collapse(true, sleep_delay, sleep_limit);
1508 low_power = (ret != -EBUSY && ret != -ETIMEDOUT);
1509
1510#ifdef CONFIG_MSM_IDLE_STATS
1511 if (ret)
1512 exit_stat = MSM_PM_STAT_IDLE_FAILED_POWER_COLLAPSE;
1513 else {
1514 exit_stat = MSM_PM_STAT_IDLE_POWER_COLLAPSE;
1515 msm_pm_sleep_limit = sleep_limit;
1516 }
1517#endif /* CONFIG_MSM_IDLE_STATS */
1518 } else if (allow[MSM_PM_SLEEP_MODE_APPS_SLEEP]) {
1519 uint32_t sleep_delay;
1520
1521 sleep_delay = (uint32_t) msm_pm_convert_and_cap_time(
1522 timer_expiration, MSM_PM_SLEEP_TICK_LIMIT);
1523 if (sleep_delay == 0) /* 0 would mean infinite time */
1524 sleep_delay = 1;
1525
1526 ret = msm_pm_apps_sleep(sleep_delay, sleep_limit);
1527 low_power = 0;
1528
1529#ifdef CONFIG_MSM_IDLE_STATS
1530 if (ret)
1531 exit_stat = MSM_PM_STAT_IDLE_FAILED_SLEEP;
1532 else
1533 exit_stat = MSM_PM_STAT_IDLE_SLEEP;
1534#endif /* CONFIG_MSM_IDLE_STATS */
1535 } else if (allow[MSM_PM_SLEEP_MODE_POWER_COLLAPSE_STANDALONE]) {
1536 ret = msm_pm_power_collapse_standalone();
1537 low_power = 0;
1538#ifdef CONFIG_MSM_IDLE_STATS
1539 exit_stat = ret ?
1540 MSM_PM_STAT_IDLE_FAILED_STANDALONE_POWER_COLLAPSE :
1541 MSM_PM_STAT_IDLE_STANDALONE_POWER_COLLAPSE;
1542#endif /* CONFIG_MSM_IDLE_STATS */
1543 } else if (allow[MSM_PM_SLEEP_MODE_RAMP_DOWN_AND_WAIT_FOR_INTERRUPT]) {
1544 ret = msm_pm_swfi(true);
1545 if (ret)
1546 while (!msm_irq_pending())
1547 udelay(1);
1548 low_power = 0;
1549#ifdef CONFIG_MSM_IDLE_STATS
1550 exit_stat = ret ? MSM_PM_STAT_IDLE_SPIN : MSM_PM_STAT_IDLE_WFI;
1551#endif /* CONFIG_MSM_IDLE_STATS */
1552 } else if (allow[MSM_PM_SLEEP_MODE_WAIT_FOR_INTERRUPT]) {
1553 msm_pm_swfi(false);
1554 low_power = 0;
1555#ifdef CONFIG_MSM_IDLE_STATS
1556 exit_stat = MSM_PM_STAT_IDLE_WFI;
1557#endif /* CONFIG_MSM_IDLE_STATS */
1558 } else {
1559 while (!msm_irq_pending())
1560 udelay(1);
1561 low_power = 0;
1562#ifdef CONFIG_MSM_IDLE_STATS
1563 exit_stat = MSM_PM_STAT_IDLE_SPIN;
1564#endif /* CONFIG_MSM_IDLE_STATS */
1565 }
1566
1567arch_idle_exit:
1568 msm_timer_exit_idle(low_power);
1569
1570#ifdef CONFIG_MSM_IDLE_STATS
1571 t2 = ktime_to_ns(ktime_get());
1572 msm_pm_add_stat(exit_stat, t2 - t1);
1573#endif /* CONFIG_MSM_IDLE_STATS */
1574}
1575
1576/*
1577 * Suspend the Apps processor.
1578 *
1579 * Return value:
1580 * -EAGAIN: modem reset occurred or early exit from suspend
1581 * -EBUSY: modem not ready for our suspend
1582 * -EINVAL: invalid sleep mode
1583 * -EIO: could not ramp Apps processor clock
1584 * -ETIMEDOUT: timed out waiting for modem's handshake
1585 * 0: success
1586 */
1587static int msm_pm_enter(suspend_state_t state)
1588{
1589 bool allow[MSM_PM_SLEEP_MODE_NR];
1590 uint32_t sleep_limit = SLEEP_LIMIT_NONE;
1591 int ret;
1592 int i;
1593
1594#ifdef CONFIG_MSM_IDLE_STATS
1595 int64_t period = 0;
1596 int64_t time = 0;
1597
1598 time = msm_timer_get_sclk_time(&period);
1599#endif
1600
1601 MSM_PM_DPRINTK(MSM_PM_DEBUG_SUSPEND, KERN_INFO,
1602 "%s(): sleep limit %u\n", __func__, sleep_limit);
1603
1604 for (i = 0; i < ARRAY_SIZE(allow); i++)
1605 allow[i] = true;
1606
1607 switch (msm_pm_sleep_mode) {
1608 case MSM_PM_SLEEP_MODE_WAIT_FOR_INTERRUPT:
1609 allow[MSM_PM_SLEEP_MODE_RAMP_DOWN_AND_WAIT_FOR_INTERRUPT] =
1610 false;
1611 /* fall through */
1612 case MSM_PM_SLEEP_MODE_RAMP_DOWN_AND_WAIT_FOR_INTERRUPT:
1613 allow[MSM_PM_SLEEP_MODE_POWER_COLLAPSE_STANDALONE] = false;
1614 /* fall through */
1615 case MSM_PM_SLEEP_MODE_POWER_COLLAPSE_STANDALONE:
1616 allow[MSM_PM_SLEEP_MODE_APPS_SLEEP] = false;
1617 /* fall through */
1618 case MSM_PM_SLEEP_MODE_APPS_SLEEP:
1619 allow[MSM_PM_SLEEP_MODE_POWER_COLLAPSE_NO_XO_SHUTDOWN] = false;
1620 allow[MSM_PM_SLEEP_MODE_POWER_COLLAPSE] = false;
1621 /* fall through */
1622 case MSM_PM_SLEEP_MODE_POWER_COLLAPSE_SUSPEND:
1623 case MSM_PM_SLEEP_MODE_POWER_COLLAPSE:
1624 break;
1625 default:
1626 printk(KERN_ERR "suspend sleep mode is invalid: %d\n",
1627 msm_pm_sleep_mode);
1628 return -EINVAL;
1629 }
1630
1631 for (i = 0; i < ARRAY_SIZE(allow); i++) {
1632 struct msm_pm_platform_data *mode = &msm_pm_modes[i];
1633 if (!mode->suspend_supported || !mode->suspend_enabled)
1634 allow[i] = false;
1635 }
1636
1637 ret = 0;
1638
1639 if (allow[MSM_PM_SLEEP_MODE_POWER_COLLAPSE] ||
1640 allow[MSM_PM_SLEEP_MODE_POWER_COLLAPSE_NO_XO_SHUTDOWN]) {
1641#ifdef CONFIG_MSM_IDLE_STATS
1642 enum msm_pm_time_stats_id id;
1643 int64_t end_time;
1644#endif
1645
1646 clock_debug_print_enabled();
1647
1648#ifdef CONFIG_MSM_SLEEP_TIME_OVERRIDE
1649 if (msm_pm_sleep_time_override > 0) {
1650 int64_t ns;
1651 ns = NSEC_PER_SEC * (int64_t)msm_pm_sleep_time_override;
1652 msm_pm_set_max_sleep_time(ns);
1653 msm_pm_sleep_time_override = 0;
1654 }
1655#endif
1656 if (!allow[MSM_PM_SLEEP_MODE_POWER_COLLAPSE])
1657 sleep_limit = SLEEP_LIMIT_NO_TCXO_SHUTDOWN;
1658
1659#if defined(CONFIG_MSM_MEMORY_LOW_POWER_MODE_SUSPEND_ACTIVE)
1660 sleep_limit |= SLEEP_RESOURCE_MEMORY_BIT1;
1661#elif defined(CONFIG_MSM_MEMORY_LOW_POWER_MODE_SUSPEND_RETENTION)
1662 sleep_limit |= SLEEP_RESOURCE_MEMORY_BIT0;
1663#elif defined(CONFIG_MSM_MEMORY_LOW_POWER_MODE_SUSPEND_DEEP_POWER_DOWN)
1664 if (get_msm_migrate_pages_status() != MEM_OFFLINE)
1665 sleep_limit |= SLEEP_RESOURCE_MEMORY_BIT0;
1666#endif
1667
1668 for (i = 0; i < 30 && msm_pm_modem_busy(); i++)
1669 udelay(500);
1670
1671 ret = msm_pm_power_collapse(
1672 false, msm_pm_max_sleep_time, sleep_limit);
1673
1674#ifdef CONFIG_MSM_IDLE_STATS
1675 if (ret)
1676 id = MSM_PM_STAT_FAILED_SUSPEND;
1677 else {
1678 id = MSM_PM_STAT_SUSPEND;
1679 msm_pm_sleep_limit = sleep_limit;
1680 }
1681
1682 if (time != 0) {
1683 end_time = msm_timer_get_sclk_time(NULL);
1684 if (end_time != 0) {
1685 time = end_time - time;
1686 if (time < 0)
1687 time += period;
1688 } else
1689 time = 0;
1690 }
1691
1692 msm_pm_add_stat(id, time);
1693#endif
1694 } else if (allow[MSM_PM_SLEEP_MODE_POWER_COLLAPSE_STANDALONE]) {
1695 ret = msm_pm_power_collapse_standalone();
1696 } else if (allow[MSM_PM_SLEEP_MODE_RAMP_DOWN_AND_WAIT_FOR_INTERRUPT]) {
1697 ret = msm_pm_swfi(true);
1698 if (ret)
1699 while (!msm_irq_pending())
1700 udelay(1);
1701 } else if (allow[MSM_PM_SLEEP_MODE_WAIT_FOR_INTERRUPT]) {
1702 msm_pm_swfi(false);
1703 }
1704
1705 MSM_PM_DPRINTK(MSM_PM_DEBUG_SUSPEND, KERN_INFO,
1706 "%s(): return %d\n", __func__, ret);
1707
1708 return ret;
1709}
1710
1711static struct platform_suspend_ops msm_pm_ops = {
1712 .enter = msm_pm_enter,
1713 .valid = suspend_valid_only_mem,
1714};
1715
1716
1717/******************************************************************************
1718 * Restart Definitions
1719 *****************************************************************************/
1720
1721static uint32_t restart_reason = 0x776655AA;
1722
1723static void msm_pm_power_off(void)
1724{
1725 msm_rpcrouter_close();
1726 msm_proc_comm(PCOM_POWER_DOWN, 0, 0);
1727 for (;;)
1728 ;
1729}
1730
1731static void msm_pm_restart(char str, const char *cmd)
1732{
1733 msm_rpcrouter_close();
1734 msm_proc_comm(PCOM_RESET_CHIP, &restart_reason, 0);
1735
1736 for (;;)
1737 ;
1738}
1739
1740static int msm_reboot_call
1741 (struct notifier_block *this, unsigned long code, void *_cmd)
1742{
1743 if ((code == SYS_RESTART) && _cmd) {
1744 char *cmd = _cmd;
1745 if (!strcmp(cmd, "bootloader")) {
1746 restart_reason = 0x77665500;
1747 } else if (!strcmp(cmd, "recovery")) {
1748 restart_reason = 0x77665502;
1749 } else if (!strcmp(cmd, "eraseflash")) {
1750 restart_reason = 0x776655EF;
1751 } else if (!strncmp(cmd, "oem-", 4)) {
1752 unsigned code = simple_strtoul(cmd + 4, 0, 16) & 0xff;
1753 restart_reason = 0x6f656d00 | code;
1754 } else {
1755 restart_reason = 0x77665501;
1756 }
1757 }
1758 return NOTIFY_DONE;
1759}
1760
1761static struct notifier_block msm_reboot_notifier = {
1762 .notifier_call = msm_reboot_call,
1763};
1764
1765
1766/******************************************************************************
1767 *
1768 *****************************************************************************/
1769
1770/*
1771 * Initialize the power management subsystem.
1772 *
1773 * Return value:
1774 * -ENODEV: initialization failed
1775 * 0: success
1776 */
1777static int __init msm_pm_init(void)
1778{
1779#ifdef CONFIG_MSM_IDLE_STATS
1780 struct proc_dir_entry *d_entry;
1781#endif
1782 int ret;
1783#ifdef CONFIG_CPU_V7
1784 pgd_t *pc_pgd;
1785 pmd_t *pmd;
1786 unsigned long pmdval;
1787
1788 /* Page table for cores to come back up safely. */
1789 pc_pgd = pgd_alloc(&init_mm);
1790 if (!pc_pgd)
1791 return -ENOMEM;
1792 pmd = pmd_offset(pc_pgd +
1793 pgd_index(virt_to_phys(msm_pm_collapse_exit)),
1794 virt_to_phys(msm_pm_collapse_exit));
1795 pmdval = (virt_to_phys(msm_pm_collapse_exit) & PGDIR_MASK) |
1796 PMD_TYPE_SECT | PMD_SECT_AP_WRITE;
1797 pmd[0] = __pmd(pmdval);
1798 pmd[1] = __pmd(pmdval + (1 << (PGDIR_SHIFT - 1)));
1799
1800 /* It is remotely possible that the code in msm_pm_collapse_exit()
1801 * which turns on the MMU with this mapping is in the
1802 * next even-numbered megabyte beyond the
1803 * start of msm_pm_collapse_exit().
1804 * Map this megabyte in as well.
1805 */
1806 pmd[2] = __pmd(pmdval + (2 << (PGDIR_SHIFT - 1)));
1807 flush_pmd_entry(pmd);
1808 msm_pm_pc_pgd = virt_to_phys(pc_pgd);
1809#endif
1810
1811 pm_power_off = msm_pm_power_off;
1812 arm_pm_restart = msm_pm_restart;
1813 register_reboot_notifier(&msm_reboot_notifier);
1814
1815 msm_pm_smem_data = smem_alloc(SMEM_APPS_DEM_SLAVE_DATA,
1816 sizeof(*msm_pm_smem_data));
1817 if (msm_pm_smem_data == NULL) {
1818 printk(KERN_ERR "%s: failed to get smsm_data\n", __func__);
1819 return -ENODEV;
1820 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001821
1822 ret = msm_timer_init_time_sync(msm_pm_timeout);
1823 if (ret)
1824 return ret;
1825
1826 ret = smsm_change_intr_mask(SMSM_POWER_MASTER_DEM, 0xFFFFFFFF, 0);
1827 if (ret) {
1828 printk(KERN_ERR "%s: failed to clear interrupt mask, %d\n",
1829 __func__, ret);
1830 return ret;
1831 }
1832
1833#ifdef CONFIG_MSM_MEMORY_LOW_POWER_MODE
1834 /* The wakeup_reason field is overloaded during initialization time
1835 to signal Modem that Apps will control the low power modes of
1836 the memory.
1837 */
1838 msm_pm_smem_data->wakeup_reason = 1;
1839 smsm_change_state(SMSM_APPS_DEM, 0, DEM_SLAVE_SMSM_RUN);
1840#endif
1841
1842 BUG_ON(msm_pm_modes == NULL);
1843
1844 atomic_set(&msm_pm_init_done, 1);
1845 suspend_set_ops(&msm_pm_ops);
1846
1847 msm_pm_mode_sysfs_add();
1848#ifdef CONFIG_MSM_IDLE_STATS
1849 d_entry = create_proc_entry("msm_pm_stats",
1850 S_IRUGO | S_IWUSR | S_IWGRP, NULL);
1851 if (d_entry) {
1852 d_entry->read_proc = msm_pm_read_proc;
1853 d_entry->write_proc = msm_pm_write_proc;
1854 d_entry->data = NULL;
1855 }
1856#endif
1857
1858 return 0;
1859}
1860
1861late_initcall_sync(msm_pm_init);