blob: d1cd0a95f0aac463fb1132717c7cf9b30c2f444a [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.
Murali Nalajala0df9fee2012-01-12 15:26:09 +05306 * Copyright (c) 2008-2012 Code Aurora Forum. All rights reserved.
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07007 *
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
Murali Nalajala0df9fee2012-01-12 15:26:09 +0530169struct msm_pm_kobj_attribute {
170 unsigned int cpu;
171 struct kobj_attribute ka;
172};
173
174#define GET_CPU_OF_ATTR(attr) \
175 (container_of(attr, struct msm_pm_kobj_attribute, ka)->cpu)
176
177struct msm_pm_sysfs_sleep_mode {
178 struct kobject *kobj;
179 struct attribute_group attr_group;
180 struct attribute *attrs[MSM_PM_MODE_ATTR_NR + 1];
181 struct msm_pm_kobj_attribute kas[MSM_PM_MODE_ATTR_NR];
182};
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700183
184/*
185 * Write out the attribute.
186 */
187static ssize_t msm_pm_mode_attr_show(
188 struct kobject *kobj, struct kobj_attribute *attr, char *buf)
189{
190 int ret = -EINVAL;
191 int i;
192
193 for (i = 0; i < MSM_PM_SLEEP_MODE_NR; i++) {
194 struct kernel_param kp;
Murali Nalajala0df9fee2012-01-12 15:26:09 +0530195 unsigned int cpu;
196 struct msm_pm_platform_data *mode;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700197
198 if (msm_pm_sleep_mode_labels[i] == NULL)
199 continue;
200
201 if (strcmp(kobj->name, msm_pm_sleep_mode_labels[i]))
202 continue;
203
Murali Nalajala0df9fee2012-01-12 15:26:09 +0530204 cpu = GET_CPU_OF_ATTR(attr);
205 mode = &msm_pm_modes[MSM_PM_MODE(cpu, i)];
206
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700207 if (!strcmp(attr->attr.name,
208 msm_pm_mode_attr_labels[MSM_PM_MODE_ATTR_SUSPEND])) {
Murali Nalajala0df9fee2012-01-12 15:26:09 +0530209 u32 arg = mode->suspend_enabled;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700210 kp.arg = &arg;
211 ret = param_get_ulong(buf, &kp);
212 } else if (!strcmp(attr->attr.name,
213 msm_pm_mode_attr_labels[MSM_PM_MODE_ATTR_IDLE])) {
Murali Nalajala0df9fee2012-01-12 15:26:09 +0530214 u32 arg = mode->idle_enabled;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700215 kp.arg = &arg;
216 ret = param_get_ulong(buf, &kp);
217 } else if (!strcmp(attr->attr.name,
218 msm_pm_mode_attr_labels[MSM_PM_MODE_ATTR_LATENCY])) {
Murali Nalajala0df9fee2012-01-12 15:26:09 +0530219 u32 arg = mode->latency;
220 kp.arg = &arg;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700221 ret = param_get_ulong(buf, &kp);
222 } else if (!strcmp(attr->attr.name,
223 msm_pm_mode_attr_labels[MSM_PM_MODE_ATTR_RESIDENCY])) {
Murali Nalajala0df9fee2012-01-12 15:26:09 +0530224 u32 arg = mode->residency;
225 kp.arg = &arg;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700226 ret = param_get_ulong(buf, &kp);
227 }
228
229 break;
230 }
231
232 if (ret > 0) {
Murali Nalajala0df9fee2012-01-12 15:26:09 +0530233 strlcat(buf, "\n", PAGE_SIZE);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700234 ret++;
235 }
236
237 return ret;
238}
239
240/*
241 * Read in the new attribute value.
242 */
243static ssize_t msm_pm_mode_attr_store(struct kobject *kobj,
244 struct kobj_attribute *attr, const char *buf, size_t count)
245{
246 int ret = -EINVAL;
247 int i;
248
249 for (i = 0; i < MSM_PM_SLEEP_MODE_NR; i++) {
250 struct kernel_param kp;
Murali Nalajala0df9fee2012-01-12 15:26:09 +0530251 unsigned int cpu;
252 struct msm_pm_platform_data *mode;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700253
254 if (msm_pm_sleep_mode_labels[i] == NULL)
255 continue;
256
257 if (strcmp(kobj->name, msm_pm_sleep_mode_labels[i]))
258 continue;
259
Murali Nalajala0df9fee2012-01-12 15:26:09 +0530260 cpu = GET_CPU_OF_ATTR(attr);
261 mode = &msm_pm_modes[MSM_PM_MODE(cpu, i)];
262
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700263 if (!strcmp(attr->attr.name,
264 msm_pm_mode_attr_labels[MSM_PM_MODE_ATTR_SUSPEND])) {
Murali Nalajala0df9fee2012-01-12 15:26:09 +0530265 kp.arg = &mode->suspend_enabled;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700266 ret = param_set_byte(buf, &kp);
267 } else if (!strcmp(attr->attr.name,
268 msm_pm_mode_attr_labels[MSM_PM_MODE_ATTR_IDLE])) {
Murali Nalajala0df9fee2012-01-12 15:26:09 +0530269 kp.arg = &mode->idle_enabled;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700270 ret = param_set_byte(buf, &kp);
271 } else if (!strcmp(attr->attr.name,
272 msm_pm_mode_attr_labels[MSM_PM_MODE_ATTR_LATENCY])) {
Murali Nalajala0df9fee2012-01-12 15:26:09 +0530273 kp.arg = &mode->latency;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700274 ret = param_set_ulong(buf, &kp);
275 } else if (!strcmp(attr->attr.name,
276 msm_pm_mode_attr_labels[MSM_PM_MODE_ATTR_RESIDENCY])) {
Murali Nalajala0df9fee2012-01-12 15:26:09 +0530277 kp.arg = &mode->residency;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700278 ret = param_set_ulong(buf, &kp);
279 }
280
281 break;
282 }
283
284 return ret ? ret : count;
285}
286
Murali Nalajala0df9fee2012-01-12 15:26:09 +0530287 /* Add sysfs entries for one cpu. */
288static int __init msm_pm_mode_sysfs_add_cpu(
289 unsigned int cpu, struct kobject *modes_kobj)
290{
291 char cpu_name[8];
292 struct kobject *cpu_kobj;
293 struct msm_pm_sysfs_sleep_mode *mode = NULL;
294 int i, j, k;
295 int ret;
296
297 snprintf(cpu_name, sizeof(cpu_name), "cpu%u", cpu);
298 cpu_kobj = kobject_create_and_add(cpu_name, modes_kobj);
299 if (!cpu_kobj) {
300 pr_err("%s: cannot create %s kobject\n", __func__, cpu_name);
301 ret = -ENOMEM;
302 goto mode_sysfs_add_cpu_exit;
303 }
304
305 for (i = 0; i < MSM_PM_SLEEP_MODE_NR; i++) {
306 int idx = MSM_PM_MODE(cpu, i);
307
308 if ((!msm_pm_modes[idx].suspend_supported) &&
309 (!msm_pm_modes[idx].idle_supported))
310 continue;
311
312 mode = kzalloc(sizeof(*mode), GFP_KERNEL);
313 if (!mode) {
314 pr_err("%s: cannot allocate memory for attributes\n",
315 __func__);
316 ret = -ENOMEM;
317 goto mode_sysfs_add_cpu_exit;
318 }
319
320 mode->kobj = kobject_create_and_add(
321 msm_pm_sleep_mode_labels[i], cpu_kobj);
322 if (!mode->kobj) {
323 pr_err("%s: cannot create kobject\n", __func__);
324 ret = -ENOMEM;
325 goto mode_sysfs_add_cpu_exit;
326 }
327
328 for (k = 0, j = 0; k < MSM_PM_MODE_ATTR_NR; k++) {
329 if ((k == MSM_PM_MODE_ATTR_IDLE) &&
330 !msm_pm_modes[idx].idle_supported)
331 continue;
332 if ((k == MSM_PM_MODE_ATTR_SUSPEND) &&
333 !msm_pm_modes[idx].suspend_supported)
334 continue;
335 mode->kas[j].cpu = cpu;
336 mode->kas[j].ka.attr.mode = 0644;
337 mode->kas[j].ka.show = msm_pm_mode_attr_show;
338 mode->kas[j].ka.store = msm_pm_mode_attr_store;
339 mode->kas[j].ka.attr.name = msm_pm_mode_attr_labels[k];
340 mode->attrs[j] = &mode->kas[j].ka.attr;
341 j++;
342 }
343 mode->attrs[j] = NULL;
344
345 mode->attr_group.attrs = mode->attrs;
346 ret = sysfs_create_group(mode->kobj, &mode->attr_group);
347 if (ret) {
348 printk(KERN_ERR
349 "%s: cannot create kobject attribute group\n",
350 __func__);
351 goto mode_sysfs_add_cpu_exit;
352 }
353 }
354
355 ret = 0;
356
357mode_sysfs_add_cpu_exit:
358 if (ret) {
359 if (mode && mode->kobj)
360 kobject_del(mode->kobj);
361 kfree(mode);
362 }
363
364 return ret;
365}
366
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700367/*
368 * Add sysfs entries for the sleep modes.
369 */
370static int __init msm_pm_mode_sysfs_add(void)
371{
372 struct kobject *module_kobj = NULL;
373 struct kobject *modes_kobj = NULL;
Murali Nalajala0df9fee2012-01-12 15:26:09 +0530374 unsigned int cpu;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700375 int ret;
376
377 module_kobj = kset_find_obj(module_kset, KBUILD_MODNAME);
378 if (!module_kobj) {
379 printk(KERN_ERR "%s: cannot find kobject for module %s\n",
380 __func__, KBUILD_MODNAME);
381 ret = -ENOENT;
Murali Nalajala0df9fee2012-01-12 15:26:09 +0530382 goto mode_sysfs_add_exit;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700383 }
384
385 modes_kobj = kobject_create_and_add("modes", module_kobj);
386 if (!modes_kobj) {
387 printk(KERN_ERR "%s: cannot create modes kobject\n", __func__);
388 ret = -ENOMEM;
Murali Nalajala0df9fee2012-01-12 15:26:09 +0530389 goto mode_sysfs_add_exit;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700390 }
391
Murali Nalajala0df9fee2012-01-12 15:26:09 +0530392 for_each_possible_cpu(cpu) {
393 ret = msm_pm_mode_sysfs_add_cpu(cpu, modes_kobj);
394 if (ret)
395 goto mode_sysfs_add_exit;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700396 }
397
Murali Nalajala0df9fee2012-01-12 15:26:09 +0530398 ret = 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700399
Murali Nalajala0df9fee2012-01-12 15:26:09 +0530400mode_sysfs_add_exit:
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700401 return ret;
402}
403
404void __init msm_pm_set_platform_data(
405 struct msm_pm_platform_data *data, int count)
406{
Murali Nalajala0df9fee2012-01-12 15:26:09 +0530407 BUG_ON(MSM_PM_SLEEP_MODE_NR * num_possible_cpus() > count);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700408 msm_pm_modes = data;
409}
410
411
412/******************************************************************************
413 * Sleep Limitations
414 *****************************************************************************/
415enum {
416 SLEEP_LIMIT_NONE = 0,
417 SLEEP_LIMIT_NO_TCXO_SHUTDOWN = 2,
418 SLEEP_LIMIT_MASK = 0x03,
419};
420
421#ifdef CONFIG_MSM_MEMORY_LOW_POWER_MODE
422enum {
423 SLEEP_RESOURCE_MEMORY_BIT0 = 0x0200,
424 SLEEP_RESOURCE_MEMORY_BIT1 = 0x0010,
425};
426#endif
427
428
429/******************************************************************************
430 * Configure Hardware for Power Down/Up
431 *****************************************************************************/
432
433#if defined(CONFIG_ARCH_MSM7X30)
434#define APPS_CLK_SLEEP_EN (MSM_GCC_BASE + 0x020)
435#define APPS_PWRDOWN (MSM_ACC_BASE + 0x01c)
436#define APPS_SECOP (MSM_TCSR_BASE + 0x038)
437#else /* defined(CONFIG_ARCH_MSM7X30) */
438#define APPS_CLK_SLEEP_EN (MSM_CSR_BASE + 0x11c)
439#define APPS_PWRDOWN (MSM_CSR_BASE + 0x440)
440#define APPS_STANDBY_CTL (MSM_CSR_BASE + 0x108)
441#endif /* defined(CONFIG_ARCH_MSM7X30) */
442
443/*
444 * Configure hardware registers in preparation for Apps power down.
445 */
446static void msm_pm_config_hw_before_power_down(void)
447{
448#if defined(CONFIG_ARCH_MSM7X30)
449 __raw_writel(1, APPS_PWRDOWN);
450 mb();
451 __raw_writel(4, APPS_SECOP);
452 mb();
453#elif defined(CONFIG_ARCH_MSM7X27)
454 __raw_writel(0x1f, APPS_CLK_SLEEP_EN);
455 mb();
456 __raw_writel(1, APPS_PWRDOWN);
457 mb();
458#elif defined(CONFIG_ARCH_MSM7x27A)
459 __raw_writel(0x7, APPS_CLK_SLEEP_EN);
460 mb();
461 __raw_writel(1, APPS_PWRDOWN);
462 mb();
463#else
464 __raw_writel(0x1f, APPS_CLK_SLEEP_EN);
465 mb();
466 __raw_writel(1, APPS_PWRDOWN);
467 mb();
468 __raw_writel(0, APPS_STANDBY_CTL);
469 mb();
470#endif
471}
472
473/*
474 * Clear hardware registers after Apps powers up.
475 */
476static void msm_pm_config_hw_after_power_up(void)
477{
478#if defined(CONFIG_ARCH_MSM7X30)
479 __raw_writel(0, APPS_SECOP);
480 mb();
481 __raw_writel(0, APPS_PWRDOWN);
482 mb();
483 msm_spm_reinit();
484#elif defined(CONFIG_ARCH_MSM7x27A)
485 __raw_writel(0, APPS_PWRDOWN);
486 mb();
487 __raw_writel(0, APPS_CLK_SLEEP_EN);
488 mb();
489#else
490 __raw_writel(0, APPS_PWRDOWN);
491 mb();
492 __raw_writel(0, APPS_CLK_SLEEP_EN);
493 mb();
494#endif
495}
496
497/*
498 * Configure hardware registers in preparation for SWFI.
499 */
500static void msm_pm_config_hw_before_swfi(void)
501{
502#if defined(CONFIG_ARCH_QSD8X50)
503 __raw_writel(0x1f, APPS_CLK_SLEEP_EN);
504 mb();
505#elif defined(CONFIG_ARCH_MSM7X27)
506 __raw_writel(0x0f, APPS_CLK_SLEEP_EN);
507 mb();
508#elif defined(CONFIG_ARCH_MSM7X27A)
509 __raw_writel(0x7, APPS_CLK_SLEEP_EN);
510 mb();
511#endif
512}
513
514/*
515 * Respond to timing out waiting for Modem
516 *
517 * NOTE: The function never returns.
518 */
519static void msm_pm_timeout(void)
520{
521#if defined(CONFIG_MSM_PM_TIMEOUT_RESET_CHIP)
522 printk(KERN_EMERG "%s(): resetting chip\n", __func__);
523 msm_proc_comm(PCOM_RESET_CHIP_IMM, NULL, NULL);
524#elif defined(CONFIG_MSM_PM_TIMEOUT_RESET_MODEM)
525 printk(KERN_EMERG "%s(): resetting modem\n", __func__);
526 msm_proc_comm_reset_modem_now();
527#elif defined(CONFIG_MSM_PM_TIMEOUT_HALT)
528 printk(KERN_EMERG "%s(): halting\n", __func__);
529#endif
530 for (;;)
531 ;
532}
533
534
535/******************************************************************************
536 * State Polling Definitions
537 *****************************************************************************/
538
539struct msm_pm_polled_group {
540 uint32_t group_id;
541
542 uint32_t bits_all_set;
543 uint32_t bits_all_clear;
544 uint32_t bits_any_set;
545 uint32_t bits_any_clear;
546
547 uint32_t value_read;
548};
549
550/*
551 * Return true if all bits indicated by flag are set in source.
552 */
553static inline bool msm_pm_all_set(uint32_t source, uint32_t flag)
554{
555 return (source & flag) == flag;
556}
557
558/*
559 * Return true if any bit indicated by flag are set in source.
560 */
561static inline bool msm_pm_any_set(uint32_t source, uint32_t flag)
562{
563 return !flag || (source & flag);
564}
565
566/*
567 * Return true if all bits indicated by flag are cleared in source.
568 */
569static inline bool msm_pm_all_clear(uint32_t source, uint32_t flag)
570{
571 return (~source & flag) == flag;
572}
573
574/*
575 * Return true if any bit indicated by flag are cleared in source.
576 */
577static inline bool msm_pm_any_clear(uint32_t source, uint32_t flag)
578{
579 return !flag || (~source & flag);
580}
581
582/*
583 * Poll the shared memory states as indicated by the poll groups.
584 *
585 * nr_grps: number of groups in the array
586 * grps: array of groups
587 *
588 * The function returns when conditions specified by any of the poll
589 * groups become true. The conditions specified by a poll group are
590 * deemed true when 1) at least one bit from bits_any_set is set OR one
591 * bit from bits_any_clear is cleared; and 2) all bits in bits_all_set
592 * are set; and 3) all bits in bits_all_clear are cleared.
593 *
594 * Return value:
595 * >=0: index of the poll group whose conditions have become true
596 * -ETIMEDOUT: timed out
597 */
598static int msm_pm_poll_state(int nr_grps, struct msm_pm_polled_group *grps)
599{
600 int i, k;
601
602 for (i = 0; i < 50000; i++) {
603 for (k = 0; k < nr_grps; k++) {
604 bool all_set, all_clear;
605 bool any_set, any_clear;
606
607 grps[k].value_read = smsm_get_state(grps[k].group_id);
608
609 all_set = msm_pm_all_set(grps[k].value_read,
610 grps[k].bits_all_set);
611 all_clear = msm_pm_all_clear(grps[k].value_read,
612 grps[k].bits_all_clear);
613 any_set = msm_pm_any_set(grps[k].value_read,
614 grps[k].bits_any_set);
615 any_clear = msm_pm_any_clear(grps[k].value_read,
616 grps[k].bits_any_clear);
617
618 if (all_set && all_clear && (any_set || any_clear))
619 return k;
620 }
621 udelay(50);
622 }
623
624 printk(KERN_ERR "%s failed:\n", __func__);
625 for (k = 0; k < nr_grps; k++)
626 printk(KERN_ERR "(%x, %x, %x, %x) %x\n",
627 grps[k].bits_all_set, grps[k].bits_all_clear,
628 grps[k].bits_any_set, grps[k].bits_any_clear,
629 grps[k].value_read);
630
631 return -ETIMEDOUT;
632}
633
634
635/******************************************************************************
636 * Suspend Max Sleep Time
637 *****************************************************************************/
638
639#define SCLK_HZ (32768)
640#define MSM_PM_SLEEP_TICK_LIMIT (0x6DDD000)
641
642#ifdef CONFIG_MSM_SLEEP_TIME_OVERRIDE
643static int msm_pm_sleep_time_override;
644module_param_named(sleep_time_override,
645 msm_pm_sleep_time_override, int, S_IRUGO | S_IWUSR | S_IWGRP);
646#endif
647
648static uint32_t msm_pm_max_sleep_time;
649
650/*
651 * Convert time from nanoseconds to slow clock ticks, then cap it to the
652 * specified limit
653 */
654static int64_t msm_pm_convert_and_cap_time(int64_t time_ns, int64_t limit)
655{
656 do_div(time_ns, NSEC_PER_SEC / SCLK_HZ);
657 return (time_ns > limit) ? limit : time_ns;
658}
659
660/*
661 * Set the sleep time for suspend. 0 means infinite sleep time.
662 */
663void msm_pm_set_max_sleep_time(int64_t max_sleep_time_ns)
664{
665 unsigned long flags;
666
667 local_irq_save(flags);
668 if (max_sleep_time_ns == 0) {
669 msm_pm_max_sleep_time = 0;
670 } else {
671 msm_pm_max_sleep_time = (uint32_t)msm_pm_convert_and_cap_time(
672 max_sleep_time_ns, MSM_PM_SLEEP_TICK_LIMIT);
673
674 if (msm_pm_max_sleep_time == 0)
675 msm_pm_max_sleep_time = 1;
676 }
677
678 MSM_PM_DPRINTK(MSM_PM_DEBUG_SUSPEND, KERN_INFO,
679 "%s(): Requested %lld ns Giving %u sclk ticks\n", __func__,
680 max_sleep_time_ns, msm_pm_max_sleep_time);
681 local_irq_restore(flags);
682}
683EXPORT_SYMBOL(msm_pm_set_max_sleep_time);
684
685
686/******************************************************************************
687 * CONFIG_MSM_IDLE_STATS
688 *****************************************************************************/
689
690#ifdef CONFIG_MSM_IDLE_STATS
691enum msm_pm_time_stats_id {
692 MSM_PM_STAT_REQUESTED_IDLE,
693 MSM_PM_STAT_IDLE_SPIN,
694 MSM_PM_STAT_IDLE_WFI,
695 MSM_PM_STAT_IDLE_STANDALONE_POWER_COLLAPSE,
696 MSM_PM_STAT_IDLE_FAILED_STANDALONE_POWER_COLLAPSE,
697 MSM_PM_STAT_IDLE_SLEEP,
698 MSM_PM_STAT_IDLE_FAILED_SLEEP,
699 MSM_PM_STAT_IDLE_POWER_COLLAPSE,
700 MSM_PM_STAT_IDLE_FAILED_POWER_COLLAPSE,
701 MSM_PM_STAT_SUSPEND,
702 MSM_PM_STAT_FAILED_SUSPEND,
703 MSM_PM_STAT_NOT_IDLE,
704 MSM_PM_STAT_COUNT
705};
706
Murali Nalajala0df9fee2012-01-12 15:26:09 +0530707struct msm_pm_time_stats {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700708 const char *name;
709 int64_t first_bucket_time;
710 int bucket[CONFIG_MSM_IDLE_STATS_BUCKET_COUNT];
711 int64_t min_time[CONFIG_MSM_IDLE_STATS_BUCKET_COUNT];
712 int64_t max_time[CONFIG_MSM_IDLE_STATS_BUCKET_COUNT];
713 int count;
714 int64_t total_time;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700715};
716
Murali Nalajala0df9fee2012-01-12 15:26:09 +0530717struct msm_pm_cpu_time_stats {
718 struct msm_pm_time_stats stats[MSM_PM_STAT_COUNT];
719};
720
721static DEFINE_PER_CPU_SHARED_ALIGNED(
722 struct msm_pm_cpu_time_stats, msm_pm_stats);
723
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700724static uint32_t msm_pm_sleep_limit = SLEEP_LIMIT_NONE;
725
Murali Nalajala0df9fee2012-01-12 15:26:09 +0530726static DEFINE_SPINLOCK(msm_pm_stats_lock);
727
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700728/*
729 * Add the given time data to the statistics collection.
730 */
731static void msm_pm_add_stat(enum msm_pm_time_stats_id id, int64_t t)
732{
Murali Nalajala0df9fee2012-01-12 15:26:09 +0530733 unsigned long flags;
734 struct msm_pm_time_stats *stats;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700735 int i;
736 int64_t bt;
737
Murali Nalajala0df9fee2012-01-12 15:26:09 +0530738 spin_lock_irqsave(&msm_pm_stats_lock, flags);
739 stats = __get_cpu_var(msm_pm_stats).stats;
740
741 stats[id].total_time += t;
742 stats[id].count++;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700743
744 bt = t;
Murali Nalajala0df9fee2012-01-12 15:26:09 +0530745 do_div(bt, stats[id].first_bucket_time);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700746
747 if (bt < 1ULL << (CONFIG_MSM_IDLE_STATS_BUCKET_SHIFT *
748 (CONFIG_MSM_IDLE_STATS_BUCKET_COUNT - 1)))
749 i = DIV_ROUND_UP(fls((uint32_t)bt),
750 CONFIG_MSM_IDLE_STATS_BUCKET_SHIFT);
751 else
752 i = CONFIG_MSM_IDLE_STATS_BUCKET_COUNT - 1;
753
Murali Nalajala0df9fee2012-01-12 15:26:09 +0530754 if (i >= CONFIG_MSM_IDLE_STATS_BUCKET_COUNT)
755 i = CONFIG_MSM_IDLE_STATS_BUCKET_COUNT - 1;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700756
Murali Nalajala0df9fee2012-01-12 15:26:09 +0530757 stats[id].bucket[i]++;
758
759 if (t < stats[id].min_time[i] || !stats[id].max_time[i])
760 stats[id].min_time[i] = t;
761 if (t > stats[id].max_time[i])
762 stats[id].max_time[i] = t;
763
764 spin_unlock_irqrestore(&msm_pm_stats_lock, flags);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700765}
766
767/*
768 * Helper function of snprintf where buf is auto-incremented, size is auto-
769 * decremented, and there is no return value.
770 *
771 * NOTE: buf and size must be l-values (e.g. variables)
772 */
773#define SNPRINTF(buf, size, format, ...) \
774 do { \
775 if (size > 0) { \
776 int ret; \
777 ret = snprintf(buf, size, format, ## __VA_ARGS__); \
778 if (ret > size) { \
779 buf += size; \
780 size = 0; \
781 } else { \
782 buf += ret; \
783 size -= ret; \
784 } \
785 } \
786 } while (0)
787
788/*
789 * Write out the power management statistics.
790 */
791static int msm_pm_read_proc
792 (char *page, char **start, off_t off, int count, int *eof, void *data)
793{
Murali Nalajala0df9fee2012-01-12 15:26:09 +0530794 unsigned int cpu = off / MSM_PM_STAT_COUNT;
795 int id = off % MSM_PM_STAT_COUNT;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700796 char *p = page;
797
798 if (count < 1024) {
799 *start = (char *) 0;
800 *eof = 0;
801 return 0;
802 }
803
804 if (!off) {
805 SNPRINTF(p, count, "Last power collapse voted ");
806 if ((msm_pm_sleep_limit & SLEEP_LIMIT_MASK) ==
807 SLEEP_LIMIT_NONE)
808 SNPRINTF(p, count, "for TCXO shutdown\n\n");
809 else
810 SNPRINTF(p, count, "against TCXO shutdown\n\n");
Murali Nalajala0df9fee2012-01-12 15:26:09 +0530811 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700812
Murali Nalajala0df9fee2012-01-12 15:26:09 +0530813 if (cpu < num_possible_cpus()) {
814 unsigned long flags;
815 struct msm_pm_time_stats *stats;
816 int i;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700817 int64_t bucket_time;
818 int64_t s;
819 uint32_t ns;
820
Murali Nalajala0df9fee2012-01-12 15:26:09 +0530821 spin_lock_irqsave(&msm_pm_stats_lock, flags);
822 stats = per_cpu(msm_pm_stats, cpu).stats;
823
824 s = stats[id].total_time;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700825 ns = do_div(s, NSEC_PER_SEC);
826 SNPRINTF(p, count,
Murali Nalajala0df9fee2012-01-12 15:26:09 +0530827 "[cpu %u] %s:\n"
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700828 " count: %7d\n"
829 " total_time: %lld.%09u\n",
Murali Nalajala0df9fee2012-01-12 15:26:09 +0530830 cpu, stats[id].name,
831 stats[id].count,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700832 s, ns);
833
Murali Nalajala0df9fee2012-01-12 15:26:09 +0530834 bucket_time = stats[id].first_bucket_time;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700835 for (i = 0; i < CONFIG_MSM_IDLE_STATS_BUCKET_COUNT - 1; i++) {
836 s = bucket_time;
837 ns = do_div(s, NSEC_PER_SEC);
838 SNPRINTF(p, count,
839 " <%6lld.%09u: %7d (%lld-%lld)\n",
Murali Nalajala0df9fee2012-01-12 15:26:09 +0530840 s, ns, stats[id].bucket[i],
841 stats[id].min_time[i],
842 stats[id].max_time[i]);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700843
844 bucket_time <<= CONFIG_MSM_IDLE_STATS_BUCKET_SHIFT;
845 }
846
847 SNPRINTF(p, count, " >=%6lld.%09u: %7d (%lld-%lld)\n",
Murali Nalajala0df9fee2012-01-12 15:26:09 +0530848 s, ns, stats[id].bucket[i],
849 stats[id].min_time[i],
850 stats[id].max_time[i]);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700851
852 *start = (char *) 1;
Murali Nalajala0df9fee2012-01-12 15:26:09 +0530853 *eof = (off + 1 >= MSM_PM_STAT_COUNT * num_possible_cpus());
854
855 spin_unlock_irqrestore(&msm_pm_stats_lock, flags);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700856 }
857
858 return p - page;
859}
860#undef SNPRINTF
861
862#define MSM_PM_STATS_RESET "reset"
863
864/*
865 * Reset the power management statistics values.
866 */
867static int msm_pm_write_proc(struct file *file, const char __user *buffer,
868 unsigned long count, void *data)
869{
870 char buf[sizeof(MSM_PM_STATS_RESET)];
871 int ret;
872 unsigned long flags;
Murali Nalajala0df9fee2012-01-12 15:26:09 +0530873 unsigned int cpu;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700874
875 if (count < strlen(MSM_PM_STATS_RESET)) {
876 ret = -EINVAL;
877 goto write_proc_failed;
878 }
879
880 if (copy_from_user(buf, buffer, strlen(MSM_PM_STATS_RESET))) {
881 ret = -EFAULT;
882 goto write_proc_failed;
883 }
884
885 if (memcmp(buf, MSM_PM_STATS_RESET, strlen(MSM_PM_STATS_RESET))) {
886 ret = -EINVAL;
887 goto write_proc_failed;
888 }
889
Murali Nalajala0df9fee2012-01-12 15:26:09 +0530890 spin_lock_irqsave(&msm_pm_stats_lock, flags);
891 for_each_possible_cpu(cpu) {
892 struct msm_pm_time_stats *stats;
893 int i;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700894
Murali Nalajala0df9fee2012-01-12 15:26:09 +0530895 stats = per_cpu(msm_pm_stats, cpu).stats;
896 for (i = 0; i < MSM_PM_STAT_COUNT; i++) {
897 memset(stats[i].bucket,
898 0, sizeof(stats[i].bucket));
899 memset(stats[i].min_time,
900 0, sizeof(stats[i].min_time));
901 memset(stats[i].max_time,
902 0, sizeof(stats[i].max_time));
903 stats[i].count = 0;
904 stats[i].total_time = 0;
905 }
906 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700907 msm_pm_sleep_limit = SLEEP_LIMIT_NONE;
Murali Nalajala0df9fee2012-01-12 15:26:09 +0530908 spin_unlock_irqrestore(&msm_pm_stats_lock, flags);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700909
910 return count;
911
912write_proc_failed:
913 return ret;
914}
Murali Nalajala0df9fee2012-01-12 15:26:09 +0530915
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700916#undef MSM_PM_STATS_RESET
917#endif /* CONFIG_MSM_IDLE_STATS */
918
919
920/******************************************************************************
921 * Shared Memory Bits
922 *****************************************************************************/
923
924#define DEM_MASTER_BITS_PER_CPU 6
925
926/* Power Master State Bits - Per CPU */
927#define DEM_MASTER_SMSM_RUN \
928 (0x01UL << (DEM_MASTER_BITS_PER_CPU * SMSM_APPS_STATE))
929#define DEM_MASTER_SMSM_RSA \
930 (0x02UL << (DEM_MASTER_BITS_PER_CPU * SMSM_APPS_STATE))
931#define DEM_MASTER_SMSM_PWRC_EARLY_EXIT \
932 (0x04UL << (DEM_MASTER_BITS_PER_CPU * SMSM_APPS_STATE))
933#define DEM_MASTER_SMSM_SLEEP_EXIT \
934 (0x08UL << (DEM_MASTER_BITS_PER_CPU * SMSM_APPS_STATE))
935#define DEM_MASTER_SMSM_READY \
936 (0x10UL << (DEM_MASTER_BITS_PER_CPU * SMSM_APPS_STATE))
937#define DEM_MASTER_SMSM_SLEEP \
938 (0x20UL << (DEM_MASTER_BITS_PER_CPU * SMSM_APPS_STATE))
939
940/* Power Slave State Bits */
941#define DEM_SLAVE_SMSM_RUN (0x0001)
942#define DEM_SLAVE_SMSM_PWRC (0x0002)
943#define DEM_SLAVE_SMSM_PWRC_DELAY (0x0004)
944#define DEM_SLAVE_SMSM_PWRC_EARLY_EXIT (0x0008)
945#define DEM_SLAVE_SMSM_WFPI (0x0010)
946#define DEM_SLAVE_SMSM_SLEEP (0x0020)
947#define DEM_SLAVE_SMSM_SLEEP_EXIT (0x0040)
948#define DEM_SLAVE_SMSM_MSGS_REDUCED (0x0080)
949#define DEM_SLAVE_SMSM_RESET (0x0100)
950#define DEM_SLAVE_SMSM_PWRC_SUSPEND (0x0200)
951
952
953/******************************************************************************
954 * Shared Memory Data
955 *****************************************************************************/
956
957#define DEM_MAX_PORT_NAME_LEN (20)
958
959struct msm_pm_smem_t {
960 uint32_t sleep_time;
961 uint32_t irq_mask;
962 uint32_t resources_used;
963 uint32_t reserved1;
964
965 uint32_t wakeup_reason;
966 uint32_t pending_irqs;
967 uint32_t rpc_prog;
968 uint32_t rpc_proc;
969 char smd_port_name[DEM_MAX_PORT_NAME_LEN];
970 uint32_t reserved2;
971};
972
973
974/******************************************************************************
975 *
976 *****************************************************************************/
977static struct msm_pm_smem_t *msm_pm_smem_data;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700978static atomic_t msm_pm_init_done = ATOMIC_INIT(0);
979
980static int msm_pm_modem_busy(void)
981{
982 if (!(smsm_get_state(SMSM_POWER_MASTER_DEM) & DEM_MASTER_SMSM_READY)) {
983 MSM_PM_DPRINTK(MSM_PM_DEBUG_POWER_COLLAPSE,
984 KERN_INFO, "%s(): master not ready\n", __func__);
985 return -EBUSY;
986 }
987
988 return 0;
989}
990
991/*
992 * Power collapse the Apps processor. This function executes the handshake
993 * protocol with Modem.
994 *
995 * Return value:
996 * -EAGAIN: modem reset occurred or early exit from power collapse
997 * -EBUSY: modem not ready for our power collapse -- no power loss
998 * -ETIMEDOUT: timed out waiting for modem's handshake -- no power loss
999 * 0: success
1000 */
1001static int msm_pm_power_collapse
1002 (bool from_idle, uint32_t sleep_delay, uint32_t sleep_limit)
1003{
1004 struct msm_pm_polled_group state_grps[2];
1005 unsigned long saved_acpuclk_rate;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001006 int collapsed = 0;
1007 int ret;
1008
1009 MSM_PM_DPRINTK(MSM_PM_DEBUG_SUSPEND|MSM_PM_DEBUG_POWER_COLLAPSE,
1010 KERN_INFO, "%s(): idle %d, delay %u, limit %u\n", __func__,
1011 (int)from_idle, sleep_delay, sleep_limit);
1012
1013 if (!(smsm_get_state(SMSM_POWER_MASTER_DEM) & DEM_MASTER_SMSM_READY)) {
1014 MSM_PM_DPRINTK(
1015 MSM_PM_DEBUG_SUSPEND | MSM_PM_DEBUG_POWER_COLLAPSE,
1016 KERN_INFO, "%s(): master not ready\n", __func__);
1017 ret = -EBUSY;
1018 goto power_collapse_bail;
1019 }
1020
1021 memset(msm_pm_smem_data, 0, sizeof(*msm_pm_smem_data));
1022
1023 msm_irq_enter_sleep1(true, from_idle, &msm_pm_smem_data->irq_mask);
1024 msm_sirc_enter_sleep();
1025 msm_gpio_enter_sleep(from_idle);
1026
1027 msm_pm_smem_data->sleep_time = sleep_delay;
1028 msm_pm_smem_data->resources_used = sleep_limit;
1029
1030 /* Enter PWRC/PWRC_SUSPEND */
1031
1032 if (from_idle)
1033 smsm_change_state(SMSM_APPS_DEM, DEM_SLAVE_SMSM_RUN,
1034 DEM_SLAVE_SMSM_PWRC);
1035 else
1036 smsm_change_state(SMSM_APPS_DEM, DEM_SLAVE_SMSM_RUN,
1037 DEM_SLAVE_SMSM_PWRC | DEM_SLAVE_SMSM_PWRC_SUSPEND);
1038
1039 MSM_PM_DEBUG_PRINT_STATE("msm_pm_power_collapse(): PWRC");
1040 MSM_PM_DEBUG_PRINT_SLEEP_INFO();
1041
1042 memset(state_grps, 0, sizeof(state_grps));
1043 state_grps[0].group_id = SMSM_POWER_MASTER_DEM;
1044 state_grps[0].bits_all_set = DEM_MASTER_SMSM_RSA;
1045 state_grps[1].group_id = SMSM_MODEM_STATE;
1046 state_grps[1].bits_all_set = SMSM_RESET;
1047
1048 ret = msm_pm_poll_state(ARRAY_SIZE(state_grps), state_grps);
1049
1050 if (ret < 0) {
1051 printk(KERN_EMERG "%s(): power collapse entry "
1052 "timed out waiting for Modem's response\n", __func__);
1053 msm_pm_timeout();
1054 }
1055
1056 if (ret == 1) {
1057 MSM_PM_DPRINTK(
1058 MSM_PM_DEBUG_SUSPEND|MSM_PM_DEBUG_POWER_COLLAPSE,
1059 KERN_INFO,
1060 "%s(): msm_pm_poll_state detected Modem reset\n",
1061 __func__);
1062 goto power_collapse_early_exit;
1063 }
1064
1065 /* DEM Master in RSA */
1066
1067 MSM_PM_DEBUG_PRINT_STATE("msm_pm_power_collapse(): PWRC RSA");
1068
1069 ret = msm_irq_enter_sleep2(true, from_idle);
1070 if (ret < 0) {
1071 MSM_PM_DPRINTK(
1072 MSM_PM_DEBUG_SUSPEND|MSM_PM_DEBUG_POWER_COLLAPSE,
1073 KERN_INFO,
1074 "%s(): msm_irq_enter_sleep2 aborted, %d\n", __func__,
1075 ret);
1076 goto power_collapse_early_exit;
1077 }
1078
1079 msm_pm_config_hw_before_power_down();
1080 MSM_PM_DEBUG_PRINT_STATE("msm_pm_power_collapse(): pre power down");
1081
1082 saved_acpuclk_rate = acpuclk_power_collapse();
1083 MSM_PM_DPRINTK(MSM_PM_DEBUG_CLOCK, KERN_INFO,
1084 "%s(): change clock rate (old rate = %lu)\n", __func__,
1085 saved_acpuclk_rate);
1086
1087 if (saved_acpuclk_rate == 0) {
1088 msm_pm_config_hw_after_power_up();
1089 goto power_collapse_early_exit;
1090 }
1091
Maheshkumar Sivasubramanian8ccc16e2011-10-25 15:59:57 -06001092 msm_pm_boot_config_before_pc(smp_processor_id(),
1093 virt_to_phys(msm_pm_collapse_exit));
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001094
1095#ifdef CONFIG_VFP
1096 if (from_idle)
1097 vfp_flush_context();
1098#endif
1099
1100#ifdef CONFIG_CACHE_L2X0
1101 l2x0_suspend();
1102#endif
1103
1104 collapsed = msm_pm_collapse();
1105
1106#ifdef CONFIG_CACHE_L2X0
1107 l2x0_resume(collapsed);
1108#endif
1109
Maheshkumar Sivasubramanian8ccc16e2011-10-25 15:59:57 -06001110 msm_pm_boot_config_after_pc(smp_processor_id());
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001111
1112 if (collapsed) {
1113#ifdef CONFIG_VFP
1114 if (from_idle)
1115 vfp_reinit();
1116#endif
1117 cpu_init();
1118 local_fiq_enable();
1119 }
1120
1121 MSM_PM_DPRINTK(MSM_PM_DEBUG_SUSPEND | MSM_PM_DEBUG_POWER_COLLAPSE,
1122 KERN_INFO,
1123 "%s(): msm_pm_collapse returned %d\n", __func__, collapsed);
1124
1125 MSM_PM_DPRINTK(MSM_PM_DEBUG_CLOCK, KERN_INFO,
1126 "%s(): restore clock rate to %lu\n", __func__,
1127 saved_acpuclk_rate);
1128 if (acpuclk_set_rate(smp_processor_id(), saved_acpuclk_rate,
1129 SETRATE_PC) < 0)
1130 printk(KERN_ERR "%s(): failed to restore clock rate(%lu)\n",
1131 __func__, saved_acpuclk_rate);
1132
1133 msm_irq_exit_sleep1(msm_pm_smem_data->irq_mask,
1134 msm_pm_smem_data->wakeup_reason,
1135 msm_pm_smem_data->pending_irqs);
1136
1137 msm_pm_config_hw_after_power_up();
1138 MSM_PM_DEBUG_PRINT_STATE("msm_pm_power_collapse(): post power up");
1139
1140 memset(state_grps, 0, sizeof(state_grps));
1141 state_grps[0].group_id = SMSM_POWER_MASTER_DEM;
1142 state_grps[0].bits_any_set =
1143 DEM_MASTER_SMSM_RSA | DEM_MASTER_SMSM_PWRC_EARLY_EXIT;
1144 state_grps[1].group_id = SMSM_MODEM_STATE;
1145 state_grps[1].bits_all_set = SMSM_RESET;
1146
1147 ret = msm_pm_poll_state(ARRAY_SIZE(state_grps), state_grps);
1148
1149 if (ret < 0) {
1150 printk(KERN_EMERG "%s(): power collapse exit "
1151 "timed out waiting for Modem's response\n", __func__);
1152 msm_pm_timeout();
1153 }
1154
1155 if (ret == 1) {
1156 MSM_PM_DPRINTK(
1157 MSM_PM_DEBUG_SUSPEND|MSM_PM_DEBUG_POWER_COLLAPSE,
1158 KERN_INFO,
1159 "%s(): msm_pm_poll_state detected Modem reset\n",
1160 __func__);
1161 goto power_collapse_early_exit;
1162 }
1163
1164 /* Sanity check */
1165 if (collapsed) {
1166 BUG_ON(!(state_grps[0].value_read & DEM_MASTER_SMSM_RSA));
1167 } else {
1168 BUG_ON(!(state_grps[0].value_read &
1169 DEM_MASTER_SMSM_PWRC_EARLY_EXIT));
1170 goto power_collapse_early_exit;
1171 }
1172
1173 /* Enter WFPI */
1174
1175 smsm_change_state(SMSM_APPS_DEM,
1176 DEM_SLAVE_SMSM_PWRC | DEM_SLAVE_SMSM_PWRC_SUSPEND,
1177 DEM_SLAVE_SMSM_WFPI);
1178
1179 MSM_PM_DEBUG_PRINT_STATE("msm_pm_power_collapse(): WFPI");
1180
1181 memset(state_grps, 0, sizeof(state_grps));
1182 state_grps[0].group_id = SMSM_POWER_MASTER_DEM;
1183 state_grps[0].bits_all_set = DEM_MASTER_SMSM_RUN;
1184 state_grps[1].group_id = SMSM_MODEM_STATE;
1185 state_grps[1].bits_all_set = SMSM_RESET;
1186
1187 ret = msm_pm_poll_state(ARRAY_SIZE(state_grps), state_grps);
1188
1189 if (ret < 0) {
1190 printk(KERN_EMERG "%s(): power collapse WFPI "
1191 "timed out waiting for Modem's response\n", __func__);
1192 msm_pm_timeout();
1193 }
1194
1195 if (ret == 1) {
1196 MSM_PM_DPRINTK(
1197 MSM_PM_DEBUG_SUSPEND|MSM_PM_DEBUG_POWER_COLLAPSE,
1198 KERN_INFO,
1199 "%s(): msm_pm_poll_state detected Modem reset\n",
1200 __func__);
1201 ret = -EAGAIN;
1202 goto power_collapse_restore_gpio_bail;
1203 }
1204
1205 /* DEM Master == RUN */
1206
1207 MSM_PM_DEBUG_PRINT_STATE("msm_pm_power_collapse(): WFPI RUN");
1208 MSM_PM_DEBUG_PRINT_SLEEP_INFO();
1209
1210 msm_irq_exit_sleep2(msm_pm_smem_data->irq_mask,
1211 msm_pm_smem_data->wakeup_reason,
1212 msm_pm_smem_data->pending_irqs);
1213 msm_irq_exit_sleep3(msm_pm_smem_data->irq_mask,
1214 msm_pm_smem_data->wakeup_reason,
1215 msm_pm_smem_data->pending_irqs);
1216 msm_gpio_exit_sleep();
1217 msm_sirc_exit_sleep();
1218
1219 smsm_change_state(SMSM_APPS_DEM,
1220 DEM_SLAVE_SMSM_WFPI, DEM_SLAVE_SMSM_RUN);
1221
1222 MSM_PM_DEBUG_PRINT_STATE("msm_pm_power_collapse(): RUN");
1223
1224 smd_sleep_exit();
1225 return 0;
1226
1227power_collapse_early_exit:
1228 /* Enter PWRC_EARLY_EXIT */
1229
1230 smsm_change_state(SMSM_APPS_DEM,
1231 DEM_SLAVE_SMSM_PWRC | DEM_SLAVE_SMSM_PWRC_SUSPEND,
1232 DEM_SLAVE_SMSM_PWRC_EARLY_EXIT);
1233
1234 MSM_PM_DEBUG_PRINT_STATE("msm_pm_power_collapse(): EARLY_EXIT");
1235
1236 memset(state_grps, 0, sizeof(state_grps));
1237 state_grps[0].group_id = SMSM_POWER_MASTER_DEM;
1238 state_grps[0].bits_all_set = DEM_MASTER_SMSM_PWRC_EARLY_EXIT;
1239 state_grps[1].group_id = SMSM_MODEM_STATE;
1240 state_grps[1].bits_all_set = SMSM_RESET;
1241
1242 ret = msm_pm_poll_state(ARRAY_SIZE(state_grps), state_grps);
1243 MSM_PM_DEBUG_PRINT_STATE("msm_pm_power_collapse(): EARLY_EXIT EE");
1244
1245 if (ret < 0) {
1246 printk(KERN_EMERG "%s(): power collapse EARLY_EXIT "
1247 "timed out waiting for Modem's response\n", __func__);
1248 msm_pm_timeout();
1249 }
1250
1251 if (ret == 1) {
1252 MSM_PM_DPRINTK(
1253 MSM_PM_DEBUG_SUSPEND|MSM_PM_DEBUG_POWER_COLLAPSE,
1254 KERN_INFO,
1255 "%s(): msm_pm_poll_state detected Modem reset\n",
1256 __func__);
1257 }
1258
1259 /* DEM Master == RESET or PWRC_EARLY_EXIT */
1260
1261 ret = -EAGAIN;
1262
1263power_collapse_restore_gpio_bail:
1264 msm_gpio_exit_sleep();
1265 msm_sirc_exit_sleep();
1266
1267 /* Enter RUN */
1268 smsm_change_state(SMSM_APPS_DEM,
1269 DEM_SLAVE_SMSM_PWRC | DEM_SLAVE_SMSM_PWRC_SUSPEND |
1270 DEM_SLAVE_SMSM_PWRC_EARLY_EXIT, DEM_SLAVE_SMSM_RUN);
1271
1272 MSM_PM_DEBUG_PRINT_STATE("msm_pm_power_collapse(): RUN");
1273
1274 if (collapsed)
1275 smd_sleep_exit();
1276
1277power_collapse_bail:
1278 return ret;
1279}
1280
1281/*
1282 * Power collapse the Apps processor without involving Modem.
1283 *
1284 * Return value:
1285 * 0: success
1286 */
1287static int msm_pm_power_collapse_standalone(void)
1288{
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001289 int collapsed = 0;
1290 int ret;
1291
1292 MSM_PM_DPRINTK(MSM_PM_DEBUG_SUSPEND|MSM_PM_DEBUG_POWER_COLLAPSE,
1293 KERN_INFO, "%s()\n", __func__);
1294
1295 ret = msm_spm_set_low_power_mode(MSM_SPM_MODE_POWER_COLLAPSE, false);
1296 WARN_ON(ret);
1297
Maheshkumar Sivasubramanian8ccc16e2011-10-25 15:59:57 -06001298 msm_pm_boot_config_before_pc(smp_processor_id(),
1299 virt_to_phys(msm_pm_collapse_exit));
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001300
1301#ifdef CONFIG_VFP
1302 vfp_flush_context();
1303#endif
1304
1305#ifdef CONFIG_CACHE_L2X0
1306 l2x0_suspend();
1307#endif
1308
1309 collapsed = msm_pm_collapse();
1310
1311#ifdef CONFIG_CACHE_L2X0
1312 l2x0_resume(collapsed);
1313#endif
1314
Maheshkumar Sivasubramanian8ccc16e2011-10-25 15:59:57 -06001315 msm_pm_boot_config_after_pc(smp_processor_id());
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001316
1317 if (collapsed) {
1318#ifdef CONFIG_VFP
1319 vfp_reinit();
1320#endif
1321 cpu_init();
1322 local_fiq_enable();
1323 }
1324
1325 MSM_PM_DPRINTK(MSM_PM_DEBUG_SUSPEND | MSM_PM_DEBUG_POWER_COLLAPSE,
1326 KERN_INFO,
1327 "%s(): msm_pm_collapse returned %d\n", __func__, collapsed);
1328
1329 ret = msm_spm_set_low_power_mode(MSM_SPM_MODE_CLOCK_GATING, false);
1330 WARN_ON(ret);
1331
1332 return 0;
1333}
1334
1335/*
1336 * Apps-sleep the Apps processor. This function execute the handshake
1337 * protocol with Modem.
1338 *
1339 * Return value:
1340 * -ENOSYS: function not implemented yet
1341 */
1342static int msm_pm_apps_sleep(uint32_t sleep_delay, uint32_t sleep_limit)
1343{
1344 return -ENOSYS;
1345}
1346
1347/*
1348 * Bring the Apps processor to SWFI.
1349 *
1350 * Return value:
1351 * -EIO: could not ramp Apps processor clock
1352 * 0: success
1353 */
1354static int msm_pm_swfi(bool ramp_acpu)
1355{
1356 unsigned long saved_acpuclk_rate = 0;
1357
1358 if (ramp_acpu) {
1359 saved_acpuclk_rate = acpuclk_wait_for_irq();
1360 MSM_PM_DPRINTK(MSM_PM_DEBUG_CLOCK, KERN_INFO,
1361 "%s(): change clock rate (old rate = %lu)\n", __func__,
1362 saved_acpuclk_rate);
1363
1364 if (!saved_acpuclk_rate)
1365 return -EIO;
1366 }
1367
1368 msm_pm_config_hw_before_swfi();
1369 msm_arch_idle();
1370
1371 if (ramp_acpu) {
1372 MSM_PM_DPRINTK(MSM_PM_DEBUG_CLOCK, KERN_INFO,
1373 "%s(): restore clock rate to %lu\n", __func__,
1374 saved_acpuclk_rate);
1375 if (acpuclk_set_rate(smp_processor_id(), saved_acpuclk_rate,
1376 SETRATE_SWFI) < 0)
1377 printk(KERN_ERR
1378 "%s(): failed to restore clock rate(%lu)\n",
1379 __func__, saved_acpuclk_rate);
1380 }
1381
1382 return 0;
1383}
1384
1385
1386/******************************************************************************
1387 * External Idle/Suspend Functions
1388 *****************************************************************************/
1389
1390/*
1391 * Put CPU in low power mode.
1392 */
1393void arch_idle(void)
1394{
1395 bool allow[MSM_PM_SLEEP_MODE_NR];
1396 uint32_t sleep_limit = SLEEP_LIMIT_NONE;
1397
1398 int latency_qos;
1399 int64_t timer_expiration;
1400
1401 int low_power;
1402 int ret;
1403 int i;
Murali Nalajala0df9fee2012-01-12 15:26:09 +05301404 unsigned int cpu;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001405
1406#ifdef CONFIG_MSM_IDLE_STATS
1407 int64_t t1;
1408 static int64_t t2;
1409 int exit_stat;
1410#endif /* CONFIG_MSM_IDLE_STATS */
1411
1412 if (!atomic_read(&msm_pm_init_done))
1413 return;
1414
Murali Nalajala0df9fee2012-01-12 15:26:09 +05301415 cpu = smp_processor_id();
1416
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001417 latency_qos = pm_qos_request(PM_QOS_CPU_DMA_LATENCY);
1418 timer_expiration = msm_timer_enter_idle();
1419
1420#ifdef CONFIG_MSM_IDLE_STATS
1421 t1 = ktime_to_ns(ktime_get());
1422 msm_pm_add_stat(MSM_PM_STAT_NOT_IDLE, t1 - t2);
1423 msm_pm_add_stat(MSM_PM_STAT_REQUESTED_IDLE, timer_expiration);
1424#endif /* CONFIG_MSM_IDLE_STATS */
1425
1426 for (i = 0; i < ARRAY_SIZE(allow); i++)
1427 allow[i] = true;
1428
1429 switch (msm_pm_idle_sleep_mode) {
1430 case MSM_PM_SLEEP_MODE_WAIT_FOR_INTERRUPT:
1431 allow[MSM_PM_SLEEP_MODE_RAMP_DOWN_AND_WAIT_FOR_INTERRUPT] =
1432 false;
1433 /* fall through */
1434 case MSM_PM_SLEEP_MODE_RAMP_DOWN_AND_WAIT_FOR_INTERRUPT:
1435 allow[MSM_PM_SLEEP_MODE_POWER_COLLAPSE_STANDALONE] = false;
1436 /* fall through */
1437 case MSM_PM_SLEEP_MODE_POWER_COLLAPSE_STANDALONE:
1438 allow[MSM_PM_SLEEP_MODE_APPS_SLEEP] = false;
1439 /* fall through */
1440 case MSM_PM_SLEEP_MODE_APPS_SLEEP:
1441 allow[MSM_PM_SLEEP_MODE_POWER_COLLAPSE_NO_XO_SHUTDOWN] = false;
1442 allow[MSM_PM_SLEEP_MODE_POWER_COLLAPSE] = false;
1443 /* fall through */
1444 case MSM_PM_SLEEP_MODE_POWER_COLLAPSE_SUSPEND:
1445 case MSM_PM_SLEEP_MODE_POWER_COLLAPSE:
1446 break;
1447 default:
1448 printk(KERN_ERR "idle sleep mode is invalid: %d\n",
1449 msm_pm_idle_sleep_mode);
1450#ifdef CONFIG_MSM_IDLE_STATS
1451 exit_stat = MSM_PM_STAT_IDLE_SPIN;
1452#endif /* CONFIG_MSM_IDLE_STATS */
1453 low_power = 0;
1454 goto arch_idle_exit;
1455 }
1456
1457 if ((timer_expiration < msm_pm_idle_sleep_min_time) ||
1458#ifdef CONFIG_HAS_WAKELOCK
1459 has_wake_lock(WAKE_LOCK_IDLE) ||
1460#endif
1461 !msm_irq_idle_sleep_allowed()) {
1462 allow[MSM_PM_SLEEP_MODE_POWER_COLLAPSE] = false;
1463 allow[MSM_PM_SLEEP_MODE_POWER_COLLAPSE_NO_XO_SHUTDOWN] = false;
1464 allow[MSM_PM_SLEEP_MODE_APPS_SLEEP] = false;
1465 }
1466
1467 for (i = 0; i < ARRAY_SIZE(allow); i++) {
Murali Nalajala0df9fee2012-01-12 15:26:09 +05301468 struct msm_pm_platform_data *mode =
1469 &msm_pm_modes[MSM_PM_MODE(cpu, i)];
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001470 if (!mode->idle_supported || !mode->idle_enabled ||
1471 mode->latency >= latency_qos ||
1472 mode->residency * 1000ULL >= timer_expiration)
1473 allow[i] = false;
1474 }
1475
1476 if (allow[MSM_PM_SLEEP_MODE_POWER_COLLAPSE] ||
1477 allow[MSM_PM_SLEEP_MODE_POWER_COLLAPSE_NO_XO_SHUTDOWN]) {
1478 uint32_t wait_us = CONFIG_MSM_IDLE_WAIT_ON_MODEM;
1479 while (msm_pm_modem_busy() && wait_us) {
1480 if (wait_us > 100) {
1481 udelay(100);
1482 wait_us -= 100;
1483 } else {
1484 udelay(wait_us);
1485 wait_us = 0;
1486 }
1487 }
1488
1489 if (msm_pm_modem_busy()) {
1490 allow[MSM_PM_SLEEP_MODE_POWER_COLLAPSE] = false;
1491 allow[MSM_PM_SLEEP_MODE_POWER_COLLAPSE_NO_XO_SHUTDOWN]
1492 = false;
1493 }
1494 }
1495
1496 MSM_PM_DPRINTK(MSM_PM_DEBUG_IDLE, KERN_INFO,
1497 "%s(): latency qos %d, next timer %lld, sleep limit %u\n",
1498 __func__, latency_qos, timer_expiration, sleep_limit);
1499
1500 for (i = 0; i < ARRAY_SIZE(allow); i++)
1501 MSM_PM_DPRINTK(MSM_PM_DEBUG_IDLE, KERN_INFO,
1502 "%s(): allow %s: %d\n", __func__,
1503 msm_pm_sleep_mode_labels[i], (int)allow[i]);
1504
1505 if (allow[MSM_PM_SLEEP_MODE_POWER_COLLAPSE] ||
1506 allow[MSM_PM_SLEEP_MODE_POWER_COLLAPSE_NO_XO_SHUTDOWN]) {
1507 uint32_t sleep_delay;
1508
1509 sleep_delay = (uint32_t) msm_pm_convert_and_cap_time(
1510 timer_expiration, MSM_PM_SLEEP_TICK_LIMIT);
1511 if (sleep_delay == 0) /* 0 would mean infinite time */
1512 sleep_delay = 1;
1513
1514 if (!allow[MSM_PM_SLEEP_MODE_POWER_COLLAPSE])
1515 sleep_limit = SLEEP_LIMIT_NO_TCXO_SHUTDOWN;
1516
1517#if defined(CONFIG_MSM_MEMORY_LOW_POWER_MODE_IDLE_ACTIVE)
1518 sleep_limit |= SLEEP_RESOURCE_MEMORY_BIT1;
1519#elif defined(CONFIG_MSM_MEMORY_LOW_POWER_MODE_IDLE_RETENTION)
1520 sleep_limit |= SLEEP_RESOURCE_MEMORY_BIT0;
1521#endif
1522
1523 ret = msm_pm_power_collapse(true, sleep_delay, sleep_limit);
1524 low_power = (ret != -EBUSY && ret != -ETIMEDOUT);
1525
1526#ifdef CONFIG_MSM_IDLE_STATS
1527 if (ret)
1528 exit_stat = MSM_PM_STAT_IDLE_FAILED_POWER_COLLAPSE;
1529 else {
1530 exit_stat = MSM_PM_STAT_IDLE_POWER_COLLAPSE;
1531 msm_pm_sleep_limit = sleep_limit;
1532 }
1533#endif /* CONFIG_MSM_IDLE_STATS */
1534 } else if (allow[MSM_PM_SLEEP_MODE_APPS_SLEEP]) {
1535 uint32_t sleep_delay;
1536
1537 sleep_delay = (uint32_t) msm_pm_convert_and_cap_time(
1538 timer_expiration, MSM_PM_SLEEP_TICK_LIMIT);
1539 if (sleep_delay == 0) /* 0 would mean infinite time */
1540 sleep_delay = 1;
1541
1542 ret = msm_pm_apps_sleep(sleep_delay, sleep_limit);
1543 low_power = 0;
1544
1545#ifdef CONFIG_MSM_IDLE_STATS
1546 if (ret)
1547 exit_stat = MSM_PM_STAT_IDLE_FAILED_SLEEP;
1548 else
1549 exit_stat = MSM_PM_STAT_IDLE_SLEEP;
1550#endif /* CONFIG_MSM_IDLE_STATS */
1551 } else if (allow[MSM_PM_SLEEP_MODE_POWER_COLLAPSE_STANDALONE]) {
1552 ret = msm_pm_power_collapse_standalone();
1553 low_power = 0;
1554#ifdef CONFIG_MSM_IDLE_STATS
1555 exit_stat = ret ?
1556 MSM_PM_STAT_IDLE_FAILED_STANDALONE_POWER_COLLAPSE :
1557 MSM_PM_STAT_IDLE_STANDALONE_POWER_COLLAPSE;
1558#endif /* CONFIG_MSM_IDLE_STATS */
1559 } else if (allow[MSM_PM_SLEEP_MODE_RAMP_DOWN_AND_WAIT_FOR_INTERRUPT]) {
1560 ret = msm_pm_swfi(true);
1561 if (ret)
1562 while (!msm_irq_pending())
1563 udelay(1);
1564 low_power = 0;
1565#ifdef CONFIG_MSM_IDLE_STATS
1566 exit_stat = ret ? MSM_PM_STAT_IDLE_SPIN : MSM_PM_STAT_IDLE_WFI;
1567#endif /* CONFIG_MSM_IDLE_STATS */
1568 } else if (allow[MSM_PM_SLEEP_MODE_WAIT_FOR_INTERRUPT]) {
1569 msm_pm_swfi(false);
1570 low_power = 0;
1571#ifdef CONFIG_MSM_IDLE_STATS
1572 exit_stat = MSM_PM_STAT_IDLE_WFI;
1573#endif /* CONFIG_MSM_IDLE_STATS */
1574 } else {
1575 while (!msm_irq_pending())
1576 udelay(1);
1577 low_power = 0;
1578#ifdef CONFIG_MSM_IDLE_STATS
1579 exit_stat = MSM_PM_STAT_IDLE_SPIN;
1580#endif /* CONFIG_MSM_IDLE_STATS */
1581 }
1582
1583arch_idle_exit:
1584 msm_timer_exit_idle(low_power);
1585
1586#ifdef CONFIG_MSM_IDLE_STATS
1587 t2 = ktime_to_ns(ktime_get());
1588 msm_pm_add_stat(exit_stat, t2 - t1);
1589#endif /* CONFIG_MSM_IDLE_STATS */
1590}
1591
1592/*
1593 * Suspend the Apps processor.
1594 *
1595 * Return value:
1596 * -EAGAIN: modem reset occurred or early exit from suspend
1597 * -EBUSY: modem not ready for our suspend
1598 * -EINVAL: invalid sleep mode
1599 * -EIO: could not ramp Apps processor clock
1600 * -ETIMEDOUT: timed out waiting for modem's handshake
1601 * 0: success
1602 */
1603static int msm_pm_enter(suspend_state_t state)
1604{
1605 bool allow[MSM_PM_SLEEP_MODE_NR];
1606 uint32_t sleep_limit = SLEEP_LIMIT_NONE;
1607 int ret;
1608 int i;
1609
1610#ifdef CONFIG_MSM_IDLE_STATS
1611 int64_t period = 0;
1612 int64_t time = 0;
1613
1614 time = msm_timer_get_sclk_time(&period);
1615#endif
1616
1617 MSM_PM_DPRINTK(MSM_PM_DEBUG_SUSPEND, KERN_INFO,
1618 "%s(): sleep limit %u\n", __func__, sleep_limit);
1619
1620 for (i = 0; i < ARRAY_SIZE(allow); i++)
1621 allow[i] = true;
1622
1623 switch (msm_pm_sleep_mode) {
1624 case MSM_PM_SLEEP_MODE_WAIT_FOR_INTERRUPT:
1625 allow[MSM_PM_SLEEP_MODE_RAMP_DOWN_AND_WAIT_FOR_INTERRUPT] =
1626 false;
1627 /* fall through */
1628 case MSM_PM_SLEEP_MODE_RAMP_DOWN_AND_WAIT_FOR_INTERRUPT:
1629 allow[MSM_PM_SLEEP_MODE_POWER_COLLAPSE_STANDALONE] = false;
1630 /* fall through */
1631 case MSM_PM_SLEEP_MODE_POWER_COLLAPSE_STANDALONE:
1632 allow[MSM_PM_SLEEP_MODE_APPS_SLEEP] = false;
1633 /* fall through */
1634 case MSM_PM_SLEEP_MODE_APPS_SLEEP:
1635 allow[MSM_PM_SLEEP_MODE_POWER_COLLAPSE_NO_XO_SHUTDOWN] = false;
1636 allow[MSM_PM_SLEEP_MODE_POWER_COLLAPSE] = false;
1637 /* fall through */
1638 case MSM_PM_SLEEP_MODE_POWER_COLLAPSE_SUSPEND:
1639 case MSM_PM_SLEEP_MODE_POWER_COLLAPSE:
1640 break;
1641 default:
1642 printk(KERN_ERR "suspend sleep mode is invalid: %d\n",
1643 msm_pm_sleep_mode);
1644 return -EINVAL;
1645 }
1646
1647 for (i = 0; i < ARRAY_SIZE(allow); i++) {
Murali Nalajala0df9fee2012-01-12 15:26:09 +05301648 struct msm_pm_platform_data *mode;
1649 mode = &msm_pm_modes[MSM_PM_MODE(0, i)];
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001650 if (!mode->suspend_supported || !mode->suspend_enabled)
1651 allow[i] = false;
1652 }
1653
1654 ret = 0;
1655
1656 if (allow[MSM_PM_SLEEP_MODE_POWER_COLLAPSE] ||
1657 allow[MSM_PM_SLEEP_MODE_POWER_COLLAPSE_NO_XO_SHUTDOWN]) {
1658#ifdef CONFIG_MSM_IDLE_STATS
1659 enum msm_pm_time_stats_id id;
1660 int64_t end_time;
1661#endif
1662
1663 clock_debug_print_enabled();
1664
1665#ifdef CONFIG_MSM_SLEEP_TIME_OVERRIDE
1666 if (msm_pm_sleep_time_override > 0) {
1667 int64_t ns;
1668 ns = NSEC_PER_SEC * (int64_t)msm_pm_sleep_time_override;
1669 msm_pm_set_max_sleep_time(ns);
1670 msm_pm_sleep_time_override = 0;
1671 }
1672#endif
1673 if (!allow[MSM_PM_SLEEP_MODE_POWER_COLLAPSE])
1674 sleep_limit = SLEEP_LIMIT_NO_TCXO_SHUTDOWN;
1675
1676#if defined(CONFIG_MSM_MEMORY_LOW_POWER_MODE_SUSPEND_ACTIVE)
1677 sleep_limit |= SLEEP_RESOURCE_MEMORY_BIT1;
1678#elif defined(CONFIG_MSM_MEMORY_LOW_POWER_MODE_SUSPEND_RETENTION)
1679 sleep_limit |= SLEEP_RESOURCE_MEMORY_BIT0;
1680#elif defined(CONFIG_MSM_MEMORY_LOW_POWER_MODE_SUSPEND_DEEP_POWER_DOWN)
1681 if (get_msm_migrate_pages_status() != MEM_OFFLINE)
1682 sleep_limit |= SLEEP_RESOURCE_MEMORY_BIT0;
1683#endif
1684
1685 for (i = 0; i < 30 && msm_pm_modem_busy(); i++)
1686 udelay(500);
1687
1688 ret = msm_pm_power_collapse(
1689 false, msm_pm_max_sleep_time, sleep_limit);
1690
1691#ifdef CONFIG_MSM_IDLE_STATS
1692 if (ret)
1693 id = MSM_PM_STAT_FAILED_SUSPEND;
1694 else {
1695 id = MSM_PM_STAT_SUSPEND;
1696 msm_pm_sleep_limit = sleep_limit;
1697 }
1698
1699 if (time != 0) {
1700 end_time = msm_timer_get_sclk_time(NULL);
1701 if (end_time != 0) {
1702 time = end_time - time;
1703 if (time < 0)
1704 time += period;
1705 } else
1706 time = 0;
1707 }
1708
1709 msm_pm_add_stat(id, time);
1710#endif
1711 } else if (allow[MSM_PM_SLEEP_MODE_POWER_COLLAPSE_STANDALONE]) {
1712 ret = msm_pm_power_collapse_standalone();
1713 } else if (allow[MSM_PM_SLEEP_MODE_RAMP_DOWN_AND_WAIT_FOR_INTERRUPT]) {
1714 ret = msm_pm_swfi(true);
1715 if (ret)
1716 while (!msm_irq_pending())
1717 udelay(1);
1718 } else if (allow[MSM_PM_SLEEP_MODE_WAIT_FOR_INTERRUPT]) {
1719 msm_pm_swfi(false);
1720 }
1721
1722 MSM_PM_DPRINTK(MSM_PM_DEBUG_SUSPEND, KERN_INFO,
1723 "%s(): return %d\n", __func__, ret);
1724
1725 return ret;
1726}
1727
1728static struct platform_suspend_ops msm_pm_ops = {
1729 .enter = msm_pm_enter,
1730 .valid = suspend_valid_only_mem,
1731};
1732
1733
1734/******************************************************************************
1735 * Restart Definitions
1736 *****************************************************************************/
1737
1738static uint32_t restart_reason = 0x776655AA;
1739
1740static void msm_pm_power_off(void)
1741{
1742 msm_rpcrouter_close();
1743 msm_proc_comm(PCOM_POWER_DOWN, 0, 0);
1744 for (;;)
1745 ;
1746}
1747
1748static void msm_pm_restart(char str, const char *cmd)
1749{
1750 msm_rpcrouter_close();
1751 msm_proc_comm(PCOM_RESET_CHIP, &restart_reason, 0);
1752
1753 for (;;)
1754 ;
1755}
1756
1757static int msm_reboot_call
1758 (struct notifier_block *this, unsigned long code, void *_cmd)
1759{
1760 if ((code == SYS_RESTART) && _cmd) {
1761 char *cmd = _cmd;
1762 if (!strcmp(cmd, "bootloader")) {
1763 restart_reason = 0x77665500;
1764 } else if (!strcmp(cmd, "recovery")) {
1765 restart_reason = 0x77665502;
1766 } else if (!strcmp(cmd, "eraseflash")) {
1767 restart_reason = 0x776655EF;
1768 } else if (!strncmp(cmd, "oem-", 4)) {
1769 unsigned code = simple_strtoul(cmd + 4, 0, 16) & 0xff;
1770 restart_reason = 0x6f656d00 | code;
1771 } else {
1772 restart_reason = 0x77665501;
1773 }
1774 }
1775 return NOTIFY_DONE;
1776}
1777
1778static struct notifier_block msm_reboot_notifier = {
1779 .notifier_call = msm_reboot_call,
1780};
1781
1782
1783/******************************************************************************
1784 *
1785 *****************************************************************************/
1786
1787/*
1788 * Initialize the power management subsystem.
1789 *
1790 * Return value:
1791 * -ENODEV: initialization failed
1792 * 0: success
1793 */
1794static int __init msm_pm_init(void)
1795{
1796#ifdef CONFIG_MSM_IDLE_STATS
1797 struct proc_dir_entry *d_entry;
Murali Nalajala0df9fee2012-01-12 15:26:09 +05301798 unsigned int cpu;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001799#endif
1800 int ret;
1801#ifdef CONFIG_CPU_V7
1802 pgd_t *pc_pgd;
1803 pmd_t *pmd;
1804 unsigned long pmdval;
1805
1806 /* Page table for cores to come back up safely. */
1807 pc_pgd = pgd_alloc(&init_mm);
1808 if (!pc_pgd)
1809 return -ENOMEM;
1810 pmd = pmd_offset(pc_pgd +
1811 pgd_index(virt_to_phys(msm_pm_collapse_exit)),
1812 virt_to_phys(msm_pm_collapse_exit));
1813 pmdval = (virt_to_phys(msm_pm_collapse_exit) & PGDIR_MASK) |
1814 PMD_TYPE_SECT | PMD_SECT_AP_WRITE;
1815 pmd[0] = __pmd(pmdval);
1816 pmd[1] = __pmd(pmdval + (1 << (PGDIR_SHIFT - 1)));
1817
1818 /* It is remotely possible that the code in msm_pm_collapse_exit()
1819 * which turns on the MMU with this mapping is in the
1820 * next even-numbered megabyte beyond the
1821 * start of msm_pm_collapse_exit().
1822 * Map this megabyte in as well.
1823 */
1824 pmd[2] = __pmd(pmdval + (2 << (PGDIR_SHIFT - 1)));
1825 flush_pmd_entry(pmd);
1826 msm_pm_pc_pgd = virt_to_phys(pc_pgd);
1827#endif
1828
1829 pm_power_off = msm_pm_power_off;
1830 arm_pm_restart = msm_pm_restart;
1831 register_reboot_notifier(&msm_reboot_notifier);
1832
1833 msm_pm_smem_data = smem_alloc(SMEM_APPS_DEM_SLAVE_DATA,
1834 sizeof(*msm_pm_smem_data));
1835 if (msm_pm_smem_data == NULL) {
1836 printk(KERN_ERR "%s: failed to get smsm_data\n", __func__);
1837 return -ENODEV;
1838 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001839
1840 ret = msm_timer_init_time_sync(msm_pm_timeout);
1841 if (ret)
1842 return ret;
1843
1844 ret = smsm_change_intr_mask(SMSM_POWER_MASTER_DEM, 0xFFFFFFFF, 0);
1845 if (ret) {
1846 printk(KERN_ERR "%s: failed to clear interrupt mask, %d\n",
1847 __func__, ret);
1848 return ret;
1849 }
1850
1851#ifdef CONFIG_MSM_MEMORY_LOW_POWER_MODE
1852 /* The wakeup_reason field is overloaded during initialization time
1853 to signal Modem that Apps will control the low power modes of
1854 the memory.
1855 */
1856 msm_pm_smem_data->wakeup_reason = 1;
1857 smsm_change_state(SMSM_APPS_DEM, 0, DEM_SLAVE_SMSM_RUN);
1858#endif
1859
1860 BUG_ON(msm_pm_modes == NULL);
1861
1862 atomic_set(&msm_pm_init_done, 1);
1863 suspend_set_ops(&msm_pm_ops);
1864
1865 msm_pm_mode_sysfs_add();
1866#ifdef CONFIG_MSM_IDLE_STATS
Murali Nalajala0df9fee2012-01-12 15:26:09 +05301867 for_each_possible_cpu(cpu) {
1868 struct msm_pm_time_stats *stats =
1869 per_cpu(msm_pm_stats, cpu).stats;
1870
1871 stats[MSM_PM_STAT_REQUESTED_IDLE].name = "idle-request";
1872 stats[MSM_PM_STAT_REQUESTED_IDLE].first_bucket_time =
1873 CONFIG_MSM_IDLE_STATS_FIRST_BUCKET;
1874
1875 stats[MSM_PM_STAT_IDLE_SPIN].name = "idle-spin";
1876 stats[MSM_PM_STAT_IDLE_SPIN].first_bucket_time =
1877 CONFIG_MSM_IDLE_STATS_FIRST_BUCKET;
1878
1879 stats[MSM_PM_STAT_IDLE_WFI].name = "idle-wfi";
1880 stats[MSM_PM_STAT_IDLE_WFI].first_bucket_time =
1881 CONFIG_MSM_IDLE_STATS_FIRST_BUCKET;
1882
1883 stats[MSM_PM_STAT_IDLE_STANDALONE_POWER_COLLAPSE].name =
1884 "idle-standalone-power-collapse";
1885 stats[MSM_PM_STAT_IDLE_STANDALONE_POWER_COLLAPSE].
1886 first_bucket_time =
1887 CONFIG_MSM_IDLE_STATS_FIRST_BUCKET;
1888
1889 stats[MSM_PM_STAT_IDLE_FAILED_STANDALONE_POWER_COLLAPSE].name =
1890 "idle-failed-standalone-power-collapse";
1891 stats[MSM_PM_STAT_IDLE_FAILED_STANDALONE_POWER_COLLAPSE].
1892 first_bucket_time =
1893 CONFIG_MSM_IDLE_STATS_FIRST_BUCKET;
1894
1895 stats[MSM_PM_STAT_IDLE_SLEEP].name = "idle-sleep";
1896 stats[MSM_PM_STAT_IDLE_SLEEP].first_bucket_time =
1897 CONFIG_MSM_IDLE_STATS_FIRST_BUCKET;
1898
1899 stats[MSM_PM_STAT_IDLE_FAILED_SLEEP].name =
1900 "idle-failed-sleep";
1901 stats[MSM_PM_STAT_IDLE_FAILED_SLEEP].first_bucket_time =
1902 CONFIG_MSM_IDLE_STATS_FIRST_BUCKET;
1903
1904 stats[MSM_PM_STAT_IDLE_POWER_COLLAPSE].name =
1905 "idle-power-collapse";
1906 stats[MSM_PM_STAT_IDLE_POWER_COLLAPSE].first_bucket_time =
1907 CONFIG_MSM_IDLE_STATS_FIRST_BUCKET;
1908
1909 stats[MSM_PM_STAT_IDLE_FAILED_POWER_COLLAPSE].name =
1910 "idle-failed-power-collapse";
1911 stats[MSM_PM_STAT_IDLE_FAILED_POWER_COLLAPSE].
1912 first_bucket_time =
1913 CONFIG_MSM_IDLE_STATS_FIRST_BUCKET;
1914
1915 stats[MSM_PM_STAT_SUSPEND].name = "suspend";
1916 stats[MSM_PM_STAT_SUSPEND].first_bucket_time =
1917 CONFIG_MSM_SUSPEND_STATS_FIRST_BUCKET;
1918
1919 stats[MSM_PM_STAT_FAILED_SUSPEND].name = "failed-suspend";
1920 stats[MSM_PM_STAT_FAILED_SUSPEND].first_bucket_time =
1921 CONFIG_MSM_IDLE_STATS_FIRST_BUCKET;
1922
1923 stats[MSM_PM_STAT_NOT_IDLE].name = "not-idle";
1924 stats[MSM_PM_STAT_NOT_IDLE].first_bucket_time =
1925 CONFIG_MSM_IDLE_STATS_FIRST_BUCKET;
1926 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001927 d_entry = create_proc_entry("msm_pm_stats",
1928 S_IRUGO | S_IWUSR | S_IWGRP, NULL);
1929 if (d_entry) {
1930 d_entry->read_proc = msm_pm_read_proc;
1931 d_entry->write_proc = msm_pm_write_proc;
1932 d_entry->data = NULL;
1933 }
1934#endif
1935
1936 return 0;
1937}
1938
1939late_initcall_sync(msm_pm_init);