blob: 9de41ad42037d0fb8d4c2c0b0561d85dddde92bd [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
Murali Nalajala41786ab2012-03-06 10:47:32 +053051#include <mach/socinfo.h>
Anji jonnala1f2377c2012-03-27 14:35:55 +053052#include <asm/smp_scu.h>
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070053
54#include "smd_private.h"
55#include "smd_rpcrouter.h"
56#include "acpuclock.h"
57#include "clock.h"
58#include "proc_comm.h"
59#include "idle.h"
60#include "irq.h"
61#include "gpio.h"
62#include "timer.h"
Matt Wagantall7cca4642012-02-01 16:43:24 -080063#include "pm.h"
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070064#include "spm.h"
65#include "sirc.h"
Maheshkumar Sivasubramanian8ccc16e2011-10-25 15:59:57 -060066#include "pm-boot.h"
Anji jonnala1f2377c2012-03-27 14:35:55 +053067#define MSM_CORE1_RESET 0xA8600590
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070068
69/******************************************************************************
70 * Debug Definitions
71 *****************************************************************************/
72
73enum {
Murali Nalajalaa7efba12012-02-23 18:13:52 +053074 MSM_PM_DEBUG_SUSPEND = BIT(0),
75 MSM_PM_DEBUG_POWER_COLLAPSE = BIT(1),
76 MSM_PM_DEBUG_STATE = BIT(2),
77 MSM_PM_DEBUG_CLOCK = BIT(3),
78 MSM_PM_DEBUG_RESET_VECTOR = BIT(4),
79 MSM_PM_DEBUG_SMSM_STATE = BIT(5),
80 MSM_PM_DEBUG_IDLE = BIT(6),
81 MSM_PM_DEBUG_HOTPLUG = BIT(7),
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070082};
83
84static int msm_pm_debug_mask;
Taniya Dase30a6b22012-03-20 11:37:45 +053085int power_collapsed;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070086module_param_named(
87 debug_mask, msm_pm_debug_mask, int, S_IRUGO | S_IWUSR | S_IWGRP
88);
89
90#define MSM_PM_DPRINTK(mask, level, message, ...) \
91 do { \
92 if ((mask) & msm_pm_debug_mask) \
93 printk(level message, ## __VA_ARGS__); \
94 } while (0)
95
96#define MSM_PM_DEBUG_PRINT_STATE(tag) \
97 do { \
98 MSM_PM_DPRINTK(MSM_PM_DEBUG_STATE, \
99 KERN_INFO, "%s: " \
100 "APPS_CLK_SLEEP_EN %x, APPS_PWRDOWN %x, " \
101 "SMSM_POWER_MASTER_DEM %x, SMSM_MODEM_STATE %x, " \
102 "SMSM_APPS_DEM %x\n", \
103 tag, \
104 __raw_readl(APPS_CLK_SLEEP_EN), \
105 __raw_readl(APPS_PWRDOWN), \
106 smsm_get_state(SMSM_POWER_MASTER_DEM), \
107 smsm_get_state(SMSM_MODEM_STATE), \
108 smsm_get_state(SMSM_APPS_DEM)); \
109 } while (0)
110
111#define MSM_PM_DEBUG_PRINT_SLEEP_INFO() \
112 do { \
113 if (msm_pm_debug_mask & MSM_PM_DEBUG_SMSM_STATE) \
114 smsm_print_sleep_info(msm_pm_smem_data->sleep_time, \
115 msm_pm_smem_data->resources_used, \
116 msm_pm_smem_data->irq_mask, \
117 msm_pm_smem_data->wakeup_reason, \
118 msm_pm_smem_data->pending_irqs); \
119 } while (0)
120
121
122/******************************************************************************
123 * Sleep Modes and Parameters
124 *****************************************************************************/
125
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700126static int msm_pm_idle_sleep_min_time = CONFIG_MSM7X00A_IDLE_SLEEP_MIN_TIME;
127module_param_named(
128 idle_sleep_min_time, msm_pm_idle_sleep_min_time,
129 int, S_IRUGO | S_IWUSR | S_IWGRP
130);
131
132enum {
133 MSM_PM_MODE_ATTR_SUSPEND,
134 MSM_PM_MODE_ATTR_IDLE,
135 MSM_PM_MODE_ATTR_LATENCY,
136 MSM_PM_MODE_ATTR_RESIDENCY,
137 MSM_PM_MODE_ATTR_NR,
138};
139
140static char *msm_pm_mode_attr_labels[MSM_PM_MODE_ATTR_NR] = {
141 [MSM_PM_MODE_ATTR_SUSPEND] = "suspend_enabled",
142 [MSM_PM_MODE_ATTR_IDLE] = "idle_enabled",
143 [MSM_PM_MODE_ATTR_LATENCY] = "latency",
144 [MSM_PM_MODE_ATTR_RESIDENCY] = "residency",
145};
146
147static char *msm_pm_sleep_mode_labels[MSM_PM_SLEEP_MODE_NR] = {
148 [MSM_PM_SLEEP_MODE_POWER_COLLAPSE_SUSPEND] = " ",
149 [MSM_PM_SLEEP_MODE_POWER_COLLAPSE] = "power_collapse",
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700150 [MSM_PM_SLEEP_MODE_RAMP_DOWN_AND_WAIT_FOR_INTERRUPT] =
151 "ramp_down_and_wfi",
152 [MSM_PM_SLEEP_MODE_WAIT_FOR_INTERRUPT] = "wfi",
153 [MSM_PM_SLEEP_MODE_POWER_COLLAPSE_NO_XO_SHUTDOWN] =
154 "power_collapse_no_xo_shutdown",
155 [MSM_PM_SLEEP_MODE_POWER_COLLAPSE_STANDALONE] =
156 "standalone_power_collapse",
157};
158
159static struct msm_pm_platform_data *msm_pm_modes;
Murali Nalajala2a0bbda2012-03-28 12:12:54 +0530160static struct msm_pm_irq_calls *msm_pm_irq_extns;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700161
Murali Nalajala0df9fee2012-01-12 15:26:09 +0530162struct msm_pm_kobj_attribute {
163 unsigned int cpu;
164 struct kobj_attribute ka;
165};
166
167#define GET_CPU_OF_ATTR(attr) \
168 (container_of(attr, struct msm_pm_kobj_attribute, ka)->cpu)
169
170struct msm_pm_sysfs_sleep_mode {
171 struct kobject *kobj;
172 struct attribute_group attr_group;
173 struct attribute *attrs[MSM_PM_MODE_ATTR_NR + 1];
174 struct msm_pm_kobj_attribute kas[MSM_PM_MODE_ATTR_NR];
175};
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700176
177/*
178 * Write out the attribute.
179 */
180static ssize_t msm_pm_mode_attr_show(
181 struct kobject *kobj, struct kobj_attribute *attr, char *buf)
182{
183 int ret = -EINVAL;
184 int i;
185
186 for (i = 0; i < MSM_PM_SLEEP_MODE_NR; i++) {
187 struct kernel_param kp;
Murali Nalajala0df9fee2012-01-12 15:26:09 +0530188 unsigned int cpu;
189 struct msm_pm_platform_data *mode;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700190
191 if (msm_pm_sleep_mode_labels[i] == NULL)
192 continue;
193
194 if (strcmp(kobj->name, msm_pm_sleep_mode_labels[i]))
195 continue;
196
Murali Nalajala0df9fee2012-01-12 15:26:09 +0530197 cpu = GET_CPU_OF_ATTR(attr);
198 mode = &msm_pm_modes[MSM_PM_MODE(cpu, i)];
199
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700200 if (!strcmp(attr->attr.name,
201 msm_pm_mode_attr_labels[MSM_PM_MODE_ATTR_SUSPEND])) {
Murali Nalajala0df9fee2012-01-12 15:26:09 +0530202 u32 arg = mode->suspend_enabled;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700203 kp.arg = &arg;
204 ret = param_get_ulong(buf, &kp);
205 } else if (!strcmp(attr->attr.name,
206 msm_pm_mode_attr_labels[MSM_PM_MODE_ATTR_IDLE])) {
Murali Nalajala0df9fee2012-01-12 15:26:09 +0530207 u32 arg = mode->idle_enabled;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700208 kp.arg = &arg;
209 ret = param_get_ulong(buf, &kp);
210 } else if (!strcmp(attr->attr.name,
211 msm_pm_mode_attr_labels[MSM_PM_MODE_ATTR_LATENCY])) {
Murali Nalajala0df9fee2012-01-12 15:26:09 +0530212 u32 arg = mode->latency;
213 kp.arg = &arg;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700214 ret = param_get_ulong(buf, &kp);
215 } else if (!strcmp(attr->attr.name,
216 msm_pm_mode_attr_labels[MSM_PM_MODE_ATTR_RESIDENCY])) {
Murali Nalajala0df9fee2012-01-12 15:26:09 +0530217 u32 arg = mode->residency;
218 kp.arg = &arg;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700219 ret = param_get_ulong(buf, &kp);
220 }
221
222 break;
223 }
224
225 if (ret > 0) {
Murali Nalajala0df9fee2012-01-12 15:26:09 +0530226 strlcat(buf, "\n", PAGE_SIZE);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700227 ret++;
228 }
229
230 return ret;
231}
232
233/*
234 * Read in the new attribute value.
235 */
236static ssize_t msm_pm_mode_attr_store(struct kobject *kobj,
237 struct kobj_attribute *attr, const char *buf, size_t count)
238{
239 int ret = -EINVAL;
240 int i;
241
242 for (i = 0; i < MSM_PM_SLEEP_MODE_NR; i++) {
243 struct kernel_param kp;
Murali Nalajala0df9fee2012-01-12 15:26:09 +0530244 unsigned int cpu;
245 struct msm_pm_platform_data *mode;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700246
247 if (msm_pm_sleep_mode_labels[i] == NULL)
248 continue;
249
250 if (strcmp(kobj->name, msm_pm_sleep_mode_labels[i]))
251 continue;
252
Murali Nalajala0df9fee2012-01-12 15:26:09 +0530253 cpu = GET_CPU_OF_ATTR(attr);
254 mode = &msm_pm_modes[MSM_PM_MODE(cpu, i)];
255
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700256 if (!strcmp(attr->attr.name,
257 msm_pm_mode_attr_labels[MSM_PM_MODE_ATTR_SUSPEND])) {
Murali Nalajala0df9fee2012-01-12 15:26:09 +0530258 kp.arg = &mode->suspend_enabled;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700259 ret = param_set_byte(buf, &kp);
260 } else if (!strcmp(attr->attr.name,
261 msm_pm_mode_attr_labels[MSM_PM_MODE_ATTR_IDLE])) {
Murali Nalajala0df9fee2012-01-12 15:26:09 +0530262 kp.arg = &mode->idle_enabled;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700263 ret = param_set_byte(buf, &kp);
264 } else if (!strcmp(attr->attr.name,
265 msm_pm_mode_attr_labels[MSM_PM_MODE_ATTR_LATENCY])) {
Murali Nalajala0df9fee2012-01-12 15:26:09 +0530266 kp.arg = &mode->latency;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700267 ret = param_set_ulong(buf, &kp);
268 } else if (!strcmp(attr->attr.name,
269 msm_pm_mode_attr_labels[MSM_PM_MODE_ATTR_RESIDENCY])) {
Murali Nalajala0df9fee2012-01-12 15:26:09 +0530270 kp.arg = &mode->residency;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700271 ret = param_set_ulong(buf, &kp);
272 }
273
274 break;
275 }
276
277 return ret ? ret : count;
278}
279
Murali Nalajala0df9fee2012-01-12 15:26:09 +0530280 /* Add sysfs entries for one cpu. */
281static int __init msm_pm_mode_sysfs_add_cpu(
282 unsigned int cpu, struct kobject *modes_kobj)
283{
284 char cpu_name[8];
285 struct kobject *cpu_kobj;
286 struct msm_pm_sysfs_sleep_mode *mode = NULL;
287 int i, j, k;
288 int ret;
289
290 snprintf(cpu_name, sizeof(cpu_name), "cpu%u", cpu);
291 cpu_kobj = kobject_create_and_add(cpu_name, modes_kobj);
292 if (!cpu_kobj) {
293 pr_err("%s: cannot create %s kobject\n", __func__, cpu_name);
294 ret = -ENOMEM;
295 goto mode_sysfs_add_cpu_exit;
296 }
297
298 for (i = 0; i < MSM_PM_SLEEP_MODE_NR; i++) {
299 int idx = MSM_PM_MODE(cpu, i);
300
301 if ((!msm_pm_modes[idx].suspend_supported) &&
302 (!msm_pm_modes[idx].idle_supported))
303 continue;
304
305 mode = kzalloc(sizeof(*mode), GFP_KERNEL);
306 if (!mode) {
307 pr_err("%s: cannot allocate memory for attributes\n",
308 __func__);
309 ret = -ENOMEM;
310 goto mode_sysfs_add_cpu_exit;
311 }
312
313 mode->kobj = kobject_create_and_add(
314 msm_pm_sleep_mode_labels[i], cpu_kobj);
315 if (!mode->kobj) {
316 pr_err("%s: cannot create kobject\n", __func__);
317 ret = -ENOMEM;
318 goto mode_sysfs_add_cpu_exit;
319 }
320
321 for (k = 0, j = 0; k < MSM_PM_MODE_ATTR_NR; k++) {
322 if ((k == MSM_PM_MODE_ATTR_IDLE) &&
323 !msm_pm_modes[idx].idle_supported)
324 continue;
325 if ((k == MSM_PM_MODE_ATTR_SUSPEND) &&
326 !msm_pm_modes[idx].suspend_supported)
327 continue;
328 mode->kas[j].cpu = cpu;
329 mode->kas[j].ka.attr.mode = 0644;
330 mode->kas[j].ka.show = msm_pm_mode_attr_show;
331 mode->kas[j].ka.store = msm_pm_mode_attr_store;
332 mode->kas[j].ka.attr.name = msm_pm_mode_attr_labels[k];
333 mode->attrs[j] = &mode->kas[j].ka.attr;
334 j++;
335 }
336 mode->attrs[j] = NULL;
337
338 mode->attr_group.attrs = mode->attrs;
339 ret = sysfs_create_group(mode->kobj, &mode->attr_group);
340 if (ret) {
341 printk(KERN_ERR
342 "%s: cannot create kobject attribute group\n",
343 __func__);
344 goto mode_sysfs_add_cpu_exit;
345 }
346 }
347
348 ret = 0;
349
350mode_sysfs_add_cpu_exit:
351 if (ret) {
352 if (mode && mode->kobj)
353 kobject_del(mode->kobj);
354 kfree(mode);
355 }
356
357 return ret;
358}
359
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700360/*
361 * Add sysfs entries for the sleep modes.
362 */
363static int __init msm_pm_mode_sysfs_add(void)
364{
365 struct kobject *module_kobj = NULL;
366 struct kobject *modes_kobj = NULL;
Murali Nalajala0df9fee2012-01-12 15:26:09 +0530367 unsigned int cpu;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700368 int ret;
369
370 module_kobj = kset_find_obj(module_kset, KBUILD_MODNAME);
371 if (!module_kobj) {
372 printk(KERN_ERR "%s: cannot find kobject for module %s\n",
373 __func__, KBUILD_MODNAME);
374 ret = -ENOENT;
Murali Nalajala0df9fee2012-01-12 15:26:09 +0530375 goto mode_sysfs_add_exit;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700376 }
377
378 modes_kobj = kobject_create_and_add("modes", module_kobj);
379 if (!modes_kobj) {
380 printk(KERN_ERR "%s: cannot create modes kobject\n", __func__);
381 ret = -ENOMEM;
Murali Nalajala0df9fee2012-01-12 15:26:09 +0530382 goto mode_sysfs_add_exit;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700383 }
384
Murali Nalajala0df9fee2012-01-12 15:26:09 +0530385 for_each_possible_cpu(cpu) {
386 ret = msm_pm_mode_sysfs_add_cpu(cpu, modes_kobj);
387 if (ret)
388 goto mode_sysfs_add_exit;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700389 }
390
Murali Nalajala0df9fee2012-01-12 15:26:09 +0530391 ret = 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700392
Murali Nalajala0df9fee2012-01-12 15:26:09 +0530393mode_sysfs_add_exit:
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700394 return ret;
395}
396
397void __init msm_pm_set_platform_data(
398 struct msm_pm_platform_data *data, int count)
399{
Murali Nalajala0df9fee2012-01-12 15:26:09 +0530400 BUG_ON(MSM_PM_SLEEP_MODE_NR * num_possible_cpus() > count);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700401 msm_pm_modes = data;
402}
403
Murali Nalajala2a0bbda2012-03-28 12:12:54 +0530404void __init msm_pm_set_irq_extns(struct msm_pm_irq_calls *irq_calls)
405{
406 /* sanity check */
407 BUG_ON(irq_calls == NULL || irq_calls->irq_pending == NULL ||
408 irq_calls->idle_sleep_allowed == NULL ||
409 irq_calls->enter_sleep1 == NULL ||
410 irq_calls->enter_sleep2 == NULL ||
411 irq_calls->exit_sleep1 == NULL ||
412 irq_calls->exit_sleep2 == NULL ||
413 irq_calls->exit_sleep3 == NULL);
414
415 msm_pm_irq_extns = irq_calls;
416}
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700417
418/******************************************************************************
419 * Sleep Limitations
420 *****************************************************************************/
421enum {
422 SLEEP_LIMIT_NONE = 0,
423 SLEEP_LIMIT_NO_TCXO_SHUTDOWN = 2,
424 SLEEP_LIMIT_MASK = 0x03,
425};
426
427#ifdef CONFIG_MSM_MEMORY_LOW_POWER_MODE
428enum {
429 SLEEP_RESOURCE_MEMORY_BIT0 = 0x0200,
430 SLEEP_RESOURCE_MEMORY_BIT1 = 0x0010,
431};
432#endif
433
434
435/******************************************************************************
436 * Configure Hardware for Power Down/Up
437 *****************************************************************************/
438
439#if defined(CONFIG_ARCH_MSM7X30)
Taniya Das298de8c2012-02-16 11:45:31 +0530440#define APPS_CLK_SLEEP_EN (MSM_APCS_GCC_BASE + 0x020)
441#define APPS_PWRDOWN (MSM_ACC0_BASE + 0x01c)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700442#define APPS_SECOP (MSM_TCSR_BASE + 0x038)
Murali Nalajala1bc1d7c2012-02-09 11:18:42 +0530443#define APPS_STANDBY_CTL NULL
444#else
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700445#define APPS_CLK_SLEEP_EN (MSM_CSR_BASE + 0x11c)
446#define APPS_PWRDOWN (MSM_CSR_BASE + 0x440)
447#define APPS_STANDBY_CTL (MSM_CSR_BASE + 0x108)
Murali Nalajala1bc1d7c2012-02-09 11:18:42 +0530448#define APPS_SECOP NULL
449#endif
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700450
451/*
452 * Configure hardware registers in preparation for Apps power down.
453 */
454static void msm_pm_config_hw_before_power_down(void)
455{
Murali Nalajala1bc1d7c2012-02-09 11:18:42 +0530456 if (cpu_is_msm7x30() || cpu_is_msm8x55()) {
457 __raw_writel(1, APPS_PWRDOWN);
458 mb();
459 __raw_writel(4, APPS_SECOP);
460 mb();
461 } else if (cpu_is_msm7x27()) {
462 __raw_writel(0x1f, APPS_CLK_SLEEP_EN);
463 mb();
464 __raw_writel(1, APPS_PWRDOWN);
465 mb();
466 } else if (cpu_is_msm7x27a() || cpu_is_msm7x27aa() ||
467 cpu_is_msm7x25a() || cpu_is_msm7x25aa()) {
468 __raw_writel(0x7, APPS_CLK_SLEEP_EN);
469 mb();
470 __raw_writel(1, APPS_PWRDOWN);
471 mb();
472 } else {
473 __raw_writel(0x1f, APPS_CLK_SLEEP_EN);
474 mb();
475 __raw_writel(1, APPS_PWRDOWN);
476 mb();
477 __raw_writel(0, APPS_STANDBY_CTL);
478 mb();
479 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700480}
481
482/*
Anji jonnala1f2377c2012-03-27 14:35:55 +0530483 * Program the top csr from core0 context to put the
484 * core1 into GDFS, as core1 is not running yet.
485 */
486static void configure_top_csr(void)
487{
488 void __iomem *base_ptr;
489 unsigned int value = 0;
490
491 base_ptr = ioremap_nocache(MSM_CORE1_RESET, SZ_4);
492 if (!base_ptr)
493 return;
494
495 /* bring the core1 out of reset */
496 __raw_writel(0x3, base_ptr);
497 mb();
498 /*
499 * override DBGNOPOWERDN and program the GDFS
500 * count val
501 */
502
503 __raw_writel(0x00030002, (MSM_CFG_CTL_BASE + 0x38));
504 mb();
505
506 /* Initialize the SPM0 and SPM1 registers */
507 msm_spm_reinit();
508
509 /* enable TCSR for core1 */
510 value = __raw_readl((MSM_CFG_CTL_BASE + MPA5_CFG_CTL_REG));
511 value |= BIT(22);
512 __raw_writel(value, MSM_CFG_CTL_BASE + MPA5_CFG_CTL_REG);
513 mb();
514
515 /* set reset bit for SPM1 */
516 value = __raw_readl((MSM_CFG_CTL_BASE + MPA5_CFG_CTL_REG));
517 value |= BIT(20);
518 __raw_writel(value, MSM_CFG_CTL_BASE + MPA5_CFG_CTL_REG);
519 mb();
520
521 /* set CLK_OFF bit */
522 value = __raw_readl((MSM_CFG_CTL_BASE + MPA5_CFG_CTL_REG));
523 value |= BIT(18);
524 __raw_writel(value, MSM_CFG_CTL_BASE + MPA5_CFG_CTL_REG);
525 mb();
526
527 /* set clamps bit */
528 value = __raw_readl((MSM_CFG_CTL_BASE + MPA5_CFG_CTL_REG));
529 value |= BIT(21);
530 __raw_writel(value, MSM_CFG_CTL_BASE + MPA5_CFG_CTL_REG);
531 mb();
532
533 /* set power_up bit */
534 value = __raw_readl((MSM_CFG_CTL_BASE + MPA5_CFG_CTL_REG));
535 value |= BIT(19);
536 __raw_writel(value, MSM_CFG_CTL_BASE + MPA5_CFG_CTL_REG);
537 mb();
538
539 /* Disable TSCR for core0 */
540 value = __raw_readl((MSM_CFG_CTL_BASE + MPA5_CFG_CTL_REG));
541 value &= ~BIT(22);
542 __raw_writel(value, MSM_CFG_CTL_BASE + MPA5_CFG_CTL_REG);
543 mb();
544 __raw_writel(0x0, base_ptr);
545 mb();
546 iounmap(base_ptr);
547}
548
549/*
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700550 * Clear hardware registers after Apps powers up.
551 */
552static void msm_pm_config_hw_after_power_up(void)
553{
Anji jonnala1f2377c2012-03-27 14:35:55 +0530554
Murali Nalajala1bc1d7c2012-02-09 11:18:42 +0530555 if (cpu_is_msm7x30() || cpu_is_msm8x55()) {
556 __raw_writel(0, APPS_SECOP);
557 mb();
558 __raw_writel(0, APPS_PWRDOWN);
559 mb();
560 msm_spm_reinit();
561 } else {
562 __raw_writel(0, APPS_PWRDOWN);
563 mb();
564 __raw_writel(0, APPS_CLK_SLEEP_EN);
565 mb();
Anji jonnala1f2377c2012-03-27 14:35:55 +0530566
567 if (cpu_is_msm8625()) {
568 /*
569 * enable the SCU while coming out of power
570 * collapse.
571 */
572 scu_enable(MSM_SCU_BASE);
573 /*
574 * Program the top csr to put the core1 into GDFS.
575 */
576 configure_top_csr();
577 }
Murali Nalajala1bc1d7c2012-02-09 11:18:42 +0530578 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700579}
580
581/*
582 * Configure hardware registers in preparation for SWFI.
583 */
584static void msm_pm_config_hw_before_swfi(void)
585{
Murali Nalajala1bc1d7c2012-02-09 11:18:42 +0530586 if (cpu_is_qsd8x50()) {
587 __raw_writel(0x1f, APPS_CLK_SLEEP_EN);
588 mb();
589 } else if (cpu_is_msm7x27()) {
590 __raw_writel(0x0f, APPS_CLK_SLEEP_EN);
591 mb();
592 } else if (cpu_is_msm7x27a() || cpu_is_msm7x27aa() ||
593 cpu_is_msm7x25a() || cpu_is_msm7x25aa()) {
594 __raw_writel(0x7, APPS_CLK_SLEEP_EN);
595 mb();
596 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700597}
598
599/*
600 * Respond to timing out waiting for Modem
601 *
602 * NOTE: The function never returns.
603 */
604static void msm_pm_timeout(void)
605{
606#if defined(CONFIG_MSM_PM_TIMEOUT_RESET_CHIP)
607 printk(KERN_EMERG "%s(): resetting chip\n", __func__);
608 msm_proc_comm(PCOM_RESET_CHIP_IMM, NULL, NULL);
609#elif defined(CONFIG_MSM_PM_TIMEOUT_RESET_MODEM)
610 printk(KERN_EMERG "%s(): resetting modem\n", __func__);
611 msm_proc_comm_reset_modem_now();
612#elif defined(CONFIG_MSM_PM_TIMEOUT_HALT)
613 printk(KERN_EMERG "%s(): halting\n", __func__);
614#endif
615 for (;;)
616 ;
617}
618
619
620/******************************************************************************
621 * State Polling Definitions
622 *****************************************************************************/
623
624struct msm_pm_polled_group {
625 uint32_t group_id;
626
627 uint32_t bits_all_set;
628 uint32_t bits_all_clear;
629 uint32_t bits_any_set;
630 uint32_t bits_any_clear;
631
632 uint32_t value_read;
633};
634
635/*
636 * Return true if all bits indicated by flag are set in source.
637 */
638static inline bool msm_pm_all_set(uint32_t source, uint32_t flag)
639{
640 return (source & flag) == flag;
641}
642
643/*
644 * Return true if any bit indicated by flag are set in source.
645 */
646static inline bool msm_pm_any_set(uint32_t source, uint32_t flag)
647{
648 return !flag || (source & flag);
649}
650
651/*
652 * Return true if all bits indicated by flag are cleared in source.
653 */
654static inline bool msm_pm_all_clear(uint32_t source, uint32_t flag)
655{
656 return (~source & flag) == flag;
657}
658
659/*
660 * Return true if any bit indicated by flag are cleared in source.
661 */
662static inline bool msm_pm_any_clear(uint32_t source, uint32_t flag)
663{
664 return !flag || (~source & flag);
665}
666
667/*
668 * Poll the shared memory states as indicated by the poll groups.
669 *
670 * nr_grps: number of groups in the array
671 * grps: array of groups
672 *
673 * The function returns when conditions specified by any of the poll
674 * groups become true. The conditions specified by a poll group are
675 * deemed true when 1) at least one bit from bits_any_set is set OR one
676 * bit from bits_any_clear is cleared; and 2) all bits in bits_all_set
677 * are set; and 3) all bits in bits_all_clear are cleared.
678 *
679 * Return value:
680 * >=0: index of the poll group whose conditions have become true
681 * -ETIMEDOUT: timed out
682 */
683static int msm_pm_poll_state(int nr_grps, struct msm_pm_polled_group *grps)
684{
685 int i, k;
686
687 for (i = 0; i < 50000; i++) {
688 for (k = 0; k < nr_grps; k++) {
689 bool all_set, all_clear;
690 bool any_set, any_clear;
691
692 grps[k].value_read = smsm_get_state(grps[k].group_id);
693
694 all_set = msm_pm_all_set(grps[k].value_read,
695 grps[k].bits_all_set);
696 all_clear = msm_pm_all_clear(grps[k].value_read,
697 grps[k].bits_all_clear);
698 any_set = msm_pm_any_set(grps[k].value_read,
699 grps[k].bits_any_set);
700 any_clear = msm_pm_any_clear(grps[k].value_read,
701 grps[k].bits_any_clear);
702
703 if (all_set && all_clear && (any_set || any_clear))
704 return k;
705 }
706 udelay(50);
707 }
708
709 printk(KERN_ERR "%s failed:\n", __func__);
710 for (k = 0; k < nr_grps; k++)
711 printk(KERN_ERR "(%x, %x, %x, %x) %x\n",
712 grps[k].bits_all_set, grps[k].bits_all_clear,
713 grps[k].bits_any_set, grps[k].bits_any_clear,
714 grps[k].value_read);
715
716 return -ETIMEDOUT;
717}
718
719
720/******************************************************************************
721 * Suspend Max Sleep Time
722 *****************************************************************************/
723
724#define SCLK_HZ (32768)
725#define MSM_PM_SLEEP_TICK_LIMIT (0x6DDD000)
726
727#ifdef CONFIG_MSM_SLEEP_TIME_OVERRIDE
728static int msm_pm_sleep_time_override;
729module_param_named(sleep_time_override,
730 msm_pm_sleep_time_override, int, S_IRUGO | S_IWUSR | S_IWGRP);
731#endif
732
733static uint32_t msm_pm_max_sleep_time;
734
735/*
736 * Convert time from nanoseconds to slow clock ticks, then cap it to the
737 * specified limit
738 */
739static int64_t msm_pm_convert_and_cap_time(int64_t time_ns, int64_t limit)
740{
741 do_div(time_ns, NSEC_PER_SEC / SCLK_HZ);
742 return (time_ns > limit) ? limit : time_ns;
743}
744
745/*
746 * Set the sleep time for suspend. 0 means infinite sleep time.
747 */
748void msm_pm_set_max_sleep_time(int64_t max_sleep_time_ns)
749{
750 unsigned long flags;
751
752 local_irq_save(flags);
753 if (max_sleep_time_ns == 0) {
754 msm_pm_max_sleep_time = 0;
755 } else {
756 msm_pm_max_sleep_time = (uint32_t)msm_pm_convert_and_cap_time(
757 max_sleep_time_ns, MSM_PM_SLEEP_TICK_LIMIT);
758
759 if (msm_pm_max_sleep_time == 0)
760 msm_pm_max_sleep_time = 1;
761 }
762
763 MSM_PM_DPRINTK(MSM_PM_DEBUG_SUSPEND, KERN_INFO,
764 "%s(): Requested %lld ns Giving %u sclk ticks\n", __func__,
765 max_sleep_time_ns, msm_pm_max_sleep_time);
766 local_irq_restore(flags);
767}
768EXPORT_SYMBOL(msm_pm_set_max_sleep_time);
769
770
771/******************************************************************************
772 * CONFIG_MSM_IDLE_STATS
773 *****************************************************************************/
774
775#ifdef CONFIG_MSM_IDLE_STATS
776enum msm_pm_time_stats_id {
777 MSM_PM_STAT_REQUESTED_IDLE,
778 MSM_PM_STAT_IDLE_SPIN,
779 MSM_PM_STAT_IDLE_WFI,
780 MSM_PM_STAT_IDLE_STANDALONE_POWER_COLLAPSE,
781 MSM_PM_STAT_IDLE_FAILED_STANDALONE_POWER_COLLAPSE,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700782 MSM_PM_STAT_IDLE_POWER_COLLAPSE,
783 MSM_PM_STAT_IDLE_FAILED_POWER_COLLAPSE,
784 MSM_PM_STAT_SUSPEND,
785 MSM_PM_STAT_FAILED_SUSPEND,
786 MSM_PM_STAT_NOT_IDLE,
787 MSM_PM_STAT_COUNT
788};
789
Murali Nalajala0df9fee2012-01-12 15:26:09 +0530790struct msm_pm_time_stats {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700791 const char *name;
792 int64_t first_bucket_time;
793 int bucket[CONFIG_MSM_IDLE_STATS_BUCKET_COUNT];
794 int64_t min_time[CONFIG_MSM_IDLE_STATS_BUCKET_COUNT];
795 int64_t max_time[CONFIG_MSM_IDLE_STATS_BUCKET_COUNT];
796 int count;
797 int64_t total_time;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700798};
799
Murali Nalajala0df9fee2012-01-12 15:26:09 +0530800struct msm_pm_cpu_time_stats {
801 struct msm_pm_time_stats stats[MSM_PM_STAT_COUNT];
802};
803
804static DEFINE_PER_CPU_SHARED_ALIGNED(
805 struct msm_pm_cpu_time_stats, msm_pm_stats);
806
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700807static uint32_t msm_pm_sleep_limit = SLEEP_LIMIT_NONE;
808
Murali Nalajala0df9fee2012-01-12 15:26:09 +0530809static DEFINE_SPINLOCK(msm_pm_stats_lock);
810
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700811/*
812 * Add the given time data to the statistics collection.
813 */
814static void msm_pm_add_stat(enum msm_pm_time_stats_id id, int64_t t)
815{
Murali Nalajala0df9fee2012-01-12 15:26:09 +0530816 unsigned long flags;
817 struct msm_pm_time_stats *stats;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700818 int i;
819 int64_t bt;
820
Murali Nalajala0df9fee2012-01-12 15:26:09 +0530821 spin_lock_irqsave(&msm_pm_stats_lock, flags);
822 stats = __get_cpu_var(msm_pm_stats).stats;
823
824 stats[id].total_time += t;
825 stats[id].count++;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700826
827 bt = t;
Murali Nalajala0df9fee2012-01-12 15:26:09 +0530828 do_div(bt, stats[id].first_bucket_time);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700829
830 if (bt < 1ULL << (CONFIG_MSM_IDLE_STATS_BUCKET_SHIFT *
831 (CONFIG_MSM_IDLE_STATS_BUCKET_COUNT - 1)))
832 i = DIV_ROUND_UP(fls((uint32_t)bt),
833 CONFIG_MSM_IDLE_STATS_BUCKET_SHIFT);
834 else
835 i = CONFIG_MSM_IDLE_STATS_BUCKET_COUNT - 1;
836
Murali Nalajala0df9fee2012-01-12 15:26:09 +0530837 if (i >= CONFIG_MSM_IDLE_STATS_BUCKET_COUNT)
838 i = CONFIG_MSM_IDLE_STATS_BUCKET_COUNT - 1;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700839
Murali Nalajala0df9fee2012-01-12 15:26:09 +0530840 stats[id].bucket[i]++;
841
842 if (t < stats[id].min_time[i] || !stats[id].max_time[i])
843 stats[id].min_time[i] = t;
844 if (t > stats[id].max_time[i])
845 stats[id].max_time[i] = t;
846
847 spin_unlock_irqrestore(&msm_pm_stats_lock, flags);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700848}
849
850/*
851 * Helper function of snprintf where buf is auto-incremented, size is auto-
852 * decremented, and there is no return value.
853 *
854 * NOTE: buf and size must be l-values (e.g. variables)
855 */
856#define SNPRINTF(buf, size, format, ...) \
857 do { \
858 if (size > 0) { \
859 int ret; \
860 ret = snprintf(buf, size, format, ## __VA_ARGS__); \
861 if (ret > size) { \
862 buf += size; \
863 size = 0; \
864 } else { \
865 buf += ret; \
866 size -= ret; \
867 } \
868 } \
869 } while (0)
870
871/*
872 * Write out the power management statistics.
873 */
874static int msm_pm_read_proc
875 (char *page, char **start, off_t off, int count, int *eof, void *data)
876{
Murali Nalajala0df9fee2012-01-12 15:26:09 +0530877 unsigned int cpu = off / MSM_PM_STAT_COUNT;
878 int id = off % MSM_PM_STAT_COUNT;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700879 char *p = page;
880
881 if (count < 1024) {
882 *start = (char *) 0;
883 *eof = 0;
884 return 0;
885 }
886
887 if (!off) {
888 SNPRINTF(p, count, "Last power collapse voted ");
889 if ((msm_pm_sleep_limit & SLEEP_LIMIT_MASK) ==
890 SLEEP_LIMIT_NONE)
891 SNPRINTF(p, count, "for TCXO shutdown\n\n");
892 else
893 SNPRINTF(p, count, "against TCXO shutdown\n\n");
Murali Nalajala0df9fee2012-01-12 15:26:09 +0530894 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700895
Murali Nalajala0df9fee2012-01-12 15:26:09 +0530896 if (cpu < num_possible_cpus()) {
897 unsigned long flags;
898 struct msm_pm_time_stats *stats;
899 int i;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700900 int64_t bucket_time;
901 int64_t s;
902 uint32_t ns;
903
Murali Nalajala0df9fee2012-01-12 15:26:09 +0530904 spin_lock_irqsave(&msm_pm_stats_lock, flags);
905 stats = per_cpu(msm_pm_stats, cpu).stats;
906
907 s = stats[id].total_time;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700908 ns = do_div(s, NSEC_PER_SEC);
909 SNPRINTF(p, count,
Murali Nalajala0df9fee2012-01-12 15:26:09 +0530910 "[cpu %u] %s:\n"
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700911 " count: %7d\n"
912 " total_time: %lld.%09u\n",
Murali Nalajala0df9fee2012-01-12 15:26:09 +0530913 cpu, stats[id].name,
914 stats[id].count,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700915 s, ns);
916
Murali Nalajala0df9fee2012-01-12 15:26:09 +0530917 bucket_time = stats[id].first_bucket_time;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700918 for (i = 0; i < CONFIG_MSM_IDLE_STATS_BUCKET_COUNT - 1; i++) {
919 s = bucket_time;
920 ns = do_div(s, NSEC_PER_SEC);
921 SNPRINTF(p, count,
922 " <%6lld.%09u: %7d (%lld-%lld)\n",
Murali Nalajala0df9fee2012-01-12 15:26:09 +0530923 s, ns, stats[id].bucket[i],
924 stats[id].min_time[i],
925 stats[id].max_time[i]);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700926
927 bucket_time <<= CONFIG_MSM_IDLE_STATS_BUCKET_SHIFT;
928 }
929
930 SNPRINTF(p, count, " >=%6lld.%09u: %7d (%lld-%lld)\n",
Murali Nalajala0df9fee2012-01-12 15:26:09 +0530931 s, ns, stats[id].bucket[i],
932 stats[id].min_time[i],
933 stats[id].max_time[i]);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700934
935 *start = (char *) 1;
Murali Nalajala0df9fee2012-01-12 15:26:09 +0530936 *eof = (off + 1 >= MSM_PM_STAT_COUNT * num_possible_cpus());
937
938 spin_unlock_irqrestore(&msm_pm_stats_lock, flags);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700939 }
940
941 return p - page;
942}
943#undef SNPRINTF
944
945#define MSM_PM_STATS_RESET "reset"
946
947/*
948 * Reset the power management statistics values.
949 */
950static int msm_pm_write_proc(struct file *file, const char __user *buffer,
951 unsigned long count, void *data)
952{
953 char buf[sizeof(MSM_PM_STATS_RESET)];
954 int ret;
955 unsigned long flags;
Murali Nalajala0df9fee2012-01-12 15:26:09 +0530956 unsigned int cpu;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700957
958 if (count < strlen(MSM_PM_STATS_RESET)) {
959 ret = -EINVAL;
960 goto write_proc_failed;
961 }
962
963 if (copy_from_user(buf, buffer, strlen(MSM_PM_STATS_RESET))) {
964 ret = -EFAULT;
965 goto write_proc_failed;
966 }
967
968 if (memcmp(buf, MSM_PM_STATS_RESET, strlen(MSM_PM_STATS_RESET))) {
969 ret = -EINVAL;
970 goto write_proc_failed;
971 }
972
Murali Nalajala0df9fee2012-01-12 15:26:09 +0530973 spin_lock_irqsave(&msm_pm_stats_lock, flags);
974 for_each_possible_cpu(cpu) {
975 struct msm_pm_time_stats *stats;
976 int i;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700977
Murali Nalajala0df9fee2012-01-12 15:26:09 +0530978 stats = per_cpu(msm_pm_stats, cpu).stats;
979 for (i = 0; i < MSM_PM_STAT_COUNT; i++) {
980 memset(stats[i].bucket,
981 0, sizeof(stats[i].bucket));
982 memset(stats[i].min_time,
983 0, sizeof(stats[i].min_time));
984 memset(stats[i].max_time,
985 0, sizeof(stats[i].max_time));
986 stats[i].count = 0;
987 stats[i].total_time = 0;
988 }
989 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700990 msm_pm_sleep_limit = SLEEP_LIMIT_NONE;
Murali Nalajala0df9fee2012-01-12 15:26:09 +0530991 spin_unlock_irqrestore(&msm_pm_stats_lock, flags);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700992
993 return count;
994
995write_proc_failed:
996 return ret;
997}
Murali Nalajala0df9fee2012-01-12 15:26:09 +0530998
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700999#undef MSM_PM_STATS_RESET
1000#endif /* CONFIG_MSM_IDLE_STATS */
1001
1002
1003/******************************************************************************
1004 * Shared Memory Bits
1005 *****************************************************************************/
1006
1007#define DEM_MASTER_BITS_PER_CPU 6
1008
1009/* Power Master State Bits - Per CPU */
1010#define DEM_MASTER_SMSM_RUN \
1011 (0x01UL << (DEM_MASTER_BITS_PER_CPU * SMSM_APPS_STATE))
1012#define DEM_MASTER_SMSM_RSA \
1013 (0x02UL << (DEM_MASTER_BITS_PER_CPU * SMSM_APPS_STATE))
1014#define DEM_MASTER_SMSM_PWRC_EARLY_EXIT \
1015 (0x04UL << (DEM_MASTER_BITS_PER_CPU * SMSM_APPS_STATE))
1016#define DEM_MASTER_SMSM_SLEEP_EXIT \
1017 (0x08UL << (DEM_MASTER_BITS_PER_CPU * SMSM_APPS_STATE))
1018#define DEM_MASTER_SMSM_READY \
1019 (0x10UL << (DEM_MASTER_BITS_PER_CPU * SMSM_APPS_STATE))
1020#define DEM_MASTER_SMSM_SLEEP \
1021 (0x20UL << (DEM_MASTER_BITS_PER_CPU * SMSM_APPS_STATE))
1022
1023/* Power Slave State Bits */
1024#define DEM_SLAVE_SMSM_RUN (0x0001)
1025#define DEM_SLAVE_SMSM_PWRC (0x0002)
1026#define DEM_SLAVE_SMSM_PWRC_DELAY (0x0004)
1027#define DEM_SLAVE_SMSM_PWRC_EARLY_EXIT (0x0008)
1028#define DEM_SLAVE_SMSM_WFPI (0x0010)
1029#define DEM_SLAVE_SMSM_SLEEP (0x0020)
1030#define DEM_SLAVE_SMSM_SLEEP_EXIT (0x0040)
1031#define DEM_SLAVE_SMSM_MSGS_REDUCED (0x0080)
1032#define DEM_SLAVE_SMSM_RESET (0x0100)
1033#define DEM_SLAVE_SMSM_PWRC_SUSPEND (0x0200)
1034
1035
1036/******************************************************************************
1037 * Shared Memory Data
1038 *****************************************************************************/
1039
1040#define DEM_MAX_PORT_NAME_LEN (20)
1041
1042struct msm_pm_smem_t {
1043 uint32_t sleep_time;
1044 uint32_t irq_mask;
1045 uint32_t resources_used;
1046 uint32_t reserved1;
1047
1048 uint32_t wakeup_reason;
1049 uint32_t pending_irqs;
1050 uint32_t rpc_prog;
1051 uint32_t rpc_proc;
1052 char smd_port_name[DEM_MAX_PORT_NAME_LEN];
1053 uint32_t reserved2;
1054};
1055
1056
1057/******************************************************************************
1058 *
1059 *****************************************************************************/
1060static struct msm_pm_smem_t *msm_pm_smem_data;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001061static atomic_t msm_pm_init_done = ATOMIC_INIT(0);
1062
1063static int msm_pm_modem_busy(void)
1064{
1065 if (!(smsm_get_state(SMSM_POWER_MASTER_DEM) & DEM_MASTER_SMSM_READY)) {
1066 MSM_PM_DPRINTK(MSM_PM_DEBUG_POWER_COLLAPSE,
1067 KERN_INFO, "%s(): master not ready\n", __func__);
1068 return -EBUSY;
1069 }
1070
1071 return 0;
1072}
1073
1074/*
1075 * Power collapse the Apps processor. This function executes the handshake
1076 * protocol with Modem.
1077 *
1078 * Return value:
1079 * -EAGAIN: modem reset occurred or early exit from power collapse
1080 * -EBUSY: modem not ready for our power collapse -- no power loss
1081 * -ETIMEDOUT: timed out waiting for modem's handshake -- no power loss
1082 * 0: success
1083 */
1084static int msm_pm_power_collapse
1085 (bool from_idle, uint32_t sleep_delay, uint32_t sleep_limit)
1086{
1087 struct msm_pm_polled_group state_grps[2];
1088 unsigned long saved_acpuclk_rate;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001089 int collapsed = 0;
1090 int ret;
1091
1092 MSM_PM_DPRINTK(MSM_PM_DEBUG_SUSPEND|MSM_PM_DEBUG_POWER_COLLAPSE,
1093 KERN_INFO, "%s(): idle %d, delay %u, limit %u\n", __func__,
1094 (int)from_idle, sleep_delay, sleep_limit);
1095
1096 if (!(smsm_get_state(SMSM_POWER_MASTER_DEM) & DEM_MASTER_SMSM_READY)) {
1097 MSM_PM_DPRINTK(
1098 MSM_PM_DEBUG_SUSPEND | MSM_PM_DEBUG_POWER_COLLAPSE,
1099 KERN_INFO, "%s(): master not ready\n", __func__);
1100 ret = -EBUSY;
1101 goto power_collapse_bail;
1102 }
1103
1104 memset(msm_pm_smem_data, 0, sizeof(*msm_pm_smem_data));
1105
Murali Nalajala41786ab2012-03-06 10:47:32 +05301106 if (cpu_is_msm8625()) {
1107 /* Program the SPM */
1108 ret = msm_spm_set_low_power_mode(MSM_SPM_MODE_POWER_COLLAPSE,
1109 false);
1110 WARN_ON(ret);
1111 }
1112
Murali Nalajala2a0bbda2012-03-28 12:12:54 +05301113 msm_pm_irq_extns->enter_sleep1(true, from_idle,
1114 &msm_pm_smem_data->irq_mask);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001115 msm_sirc_enter_sleep();
1116 msm_gpio_enter_sleep(from_idle);
1117
1118 msm_pm_smem_data->sleep_time = sleep_delay;
1119 msm_pm_smem_data->resources_used = sleep_limit;
1120
1121 /* Enter PWRC/PWRC_SUSPEND */
1122
1123 if (from_idle)
1124 smsm_change_state(SMSM_APPS_DEM, DEM_SLAVE_SMSM_RUN,
1125 DEM_SLAVE_SMSM_PWRC);
1126 else
1127 smsm_change_state(SMSM_APPS_DEM, DEM_SLAVE_SMSM_RUN,
1128 DEM_SLAVE_SMSM_PWRC | DEM_SLAVE_SMSM_PWRC_SUSPEND);
1129
1130 MSM_PM_DEBUG_PRINT_STATE("msm_pm_power_collapse(): PWRC");
1131 MSM_PM_DEBUG_PRINT_SLEEP_INFO();
1132
1133 memset(state_grps, 0, sizeof(state_grps));
1134 state_grps[0].group_id = SMSM_POWER_MASTER_DEM;
1135 state_grps[0].bits_all_set = DEM_MASTER_SMSM_RSA;
1136 state_grps[1].group_id = SMSM_MODEM_STATE;
1137 state_grps[1].bits_all_set = SMSM_RESET;
1138
1139 ret = msm_pm_poll_state(ARRAY_SIZE(state_grps), state_grps);
1140
1141 if (ret < 0) {
1142 printk(KERN_EMERG "%s(): power collapse entry "
1143 "timed out waiting for Modem's response\n", __func__);
1144 msm_pm_timeout();
1145 }
1146
1147 if (ret == 1) {
1148 MSM_PM_DPRINTK(
1149 MSM_PM_DEBUG_SUSPEND|MSM_PM_DEBUG_POWER_COLLAPSE,
1150 KERN_INFO,
1151 "%s(): msm_pm_poll_state detected Modem reset\n",
1152 __func__);
1153 goto power_collapse_early_exit;
1154 }
1155
1156 /* DEM Master in RSA */
1157
1158 MSM_PM_DEBUG_PRINT_STATE("msm_pm_power_collapse(): PWRC RSA");
1159
Murali Nalajala2a0bbda2012-03-28 12:12:54 +05301160 ret = msm_pm_irq_extns->enter_sleep2(true, from_idle);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001161 if (ret < 0) {
1162 MSM_PM_DPRINTK(
1163 MSM_PM_DEBUG_SUSPEND|MSM_PM_DEBUG_POWER_COLLAPSE,
1164 KERN_INFO,
1165 "%s(): msm_irq_enter_sleep2 aborted, %d\n", __func__,
1166 ret);
1167 goto power_collapse_early_exit;
1168 }
1169
1170 msm_pm_config_hw_before_power_down();
1171 MSM_PM_DEBUG_PRINT_STATE("msm_pm_power_collapse(): pre power down");
1172
1173 saved_acpuclk_rate = acpuclk_power_collapse();
1174 MSM_PM_DPRINTK(MSM_PM_DEBUG_CLOCK, KERN_INFO,
1175 "%s(): change clock rate (old rate = %lu)\n", __func__,
1176 saved_acpuclk_rate);
1177
1178 if (saved_acpuclk_rate == 0) {
1179 msm_pm_config_hw_after_power_up();
1180 goto power_collapse_early_exit;
1181 }
1182
Maheshkumar Sivasubramanian8ccc16e2011-10-25 15:59:57 -06001183 msm_pm_boot_config_before_pc(smp_processor_id(),
1184 virt_to_phys(msm_pm_collapse_exit));
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001185
1186#ifdef CONFIG_VFP
1187 if (from_idle)
1188 vfp_flush_context();
1189#endif
1190
1191#ifdef CONFIG_CACHE_L2X0
1192 l2x0_suspend();
1193#endif
1194
1195 collapsed = msm_pm_collapse();
Anji jonnala393ff612012-03-29 20:21:39 +05301196 if (collapsed)
1197 power_collapsed = 1;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001198
1199#ifdef CONFIG_CACHE_L2X0
1200 l2x0_resume(collapsed);
1201#endif
1202
Maheshkumar Sivasubramanian8ccc16e2011-10-25 15:59:57 -06001203 msm_pm_boot_config_after_pc(smp_processor_id());
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001204
1205 if (collapsed) {
1206#ifdef CONFIG_VFP
1207 if (from_idle)
1208 vfp_reinit();
1209#endif
1210 cpu_init();
1211 local_fiq_enable();
1212 }
1213
1214 MSM_PM_DPRINTK(MSM_PM_DEBUG_SUSPEND | MSM_PM_DEBUG_POWER_COLLAPSE,
1215 KERN_INFO,
1216 "%s(): msm_pm_collapse returned %d\n", __func__, collapsed);
1217
1218 MSM_PM_DPRINTK(MSM_PM_DEBUG_CLOCK, KERN_INFO,
1219 "%s(): restore clock rate to %lu\n", __func__,
1220 saved_acpuclk_rate);
1221 if (acpuclk_set_rate(smp_processor_id(), saved_acpuclk_rate,
1222 SETRATE_PC) < 0)
1223 printk(KERN_ERR "%s(): failed to restore clock rate(%lu)\n",
1224 __func__, saved_acpuclk_rate);
1225
Murali Nalajala2a0bbda2012-03-28 12:12:54 +05301226 msm_pm_irq_extns->exit_sleep1(msm_pm_smem_data->irq_mask,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001227 msm_pm_smem_data->wakeup_reason,
1228 msm_pm_smem_data->pending_irqs);
1229
1230 msm_pm_config_hw_after_power_up();
1231 MSM_PM_DEBUG_PRINT_STATE("msm_pm_power_collapse(): post power up");
1232
1233 memset(state_grps, 0, sizeof(state_grps));
1234 state_grps[0].group_id = SMSM_POWER_MASTER_DEM;
1235 state_grps[0].bits_any_set =
1236 DEM_MASTER_SMSM_RSA | DEM_MASTER_SMSM_PWRC_EARLY_EXIT;
1237 state_grps[1].group_id = SMSM_MODEM_STATE;
1238 state_grps[1].bits_all_set = SMSM_RESET;
1239
1240 ret = msm_pm_poll_state(ARRAY_SIZE(state_grps), state_grps);
1241
1242 if (ret < 0) {
1243 printk(KERN_EMERG "%s(): power collapse exit "
1244 "timed out waiting for Modem's response\n", __func__);
1245 msm_pm_timeout();
1246 }
1247
1248 if (ret == 1) {
1249 MSM_PM_DPRINTK(
1250 MSM_PM_DEBUG_SUSPEND|MSM_PM_DEBUG_POWER_COLLAPSE,
1251 KERN_INFO,
1252 "%s(): msm_pm_poll_state detected Modem reset\n",
1253 __func__);
1254 goto power_collapse_early_exit;
1255 }
1256
1257 /* Sanity check */
1258 if (collapsed) {
1259 BUG_ON(!(state_grps[0].value_read & DEM_MASTER_SMSM_RSA));
1260 } else {
1261 BUG_ON(!(state_grps[0].value_read &
1262 DEM_MASTER_SMSM_PWRC_EARLY_EXIT));
1263 goto power_collapse_early_exit;
1264 }
1265
1266 /* Enter WFPI */
1267
1268 smsm_change_state(SMSM_APPS_DEM,
1269 DEM_SLAVE_SMSM_PWRC | DEM_SLAVE_SMSM_PWRC_SUSPEND,
1270 DEM_SLAVE_SMSM_WFPI);
1271
1272 MSM_PM_DEBUG_PRINT_STATE("msm_pm_power_collapse(): WFPI");
1273
1274 memset(state_grps, 0, sizeof(state_grps));
1275 state_grps[0].group_id = SMSM_POWER_MASTER_DEM;
1276 state_grps[0].bits_all_set = DEM_MASTER_SMSM_RUN;
1277 state_grps[1].group_id = SMSM_MODEM_STATE;
1278 state_grps[1].bits_all_set = SMSM_RESET;
1279
1280 ret = msm_pm_poll_state(ARRAY_SIZE(state_grps), state_grps);
1281
1282 if (ret < 0) {
1283 printk(KERN_EMERG "%s(): power collapse WFPI "
1284 "timed out waiting for Modem's response\n", __func__);
1285 msm_pm_timeout();
1286 }
1287
1288 if (ret == 1) {
1289 MSM_PM_DPRINTK(
1290 MSM_PM_DEBUG_SUSPEND|MSM_PM_DEBUG_POWER_COLLAPSE,
1291 KERN_INFO,
1292 "%s(): msm_pm_poll_state detected Modem reset\n",
1293 __func__);
1294 ret = -EAGAIN;
1295 goto power_collapse_restore_gpio_bail;
1296 }
1297
1298 /* DEM Master == RUN */
1299
1300 MSM_PM_DEBUG_PRINT_STATE("msm_pm_power_collapse(): WFPI RUN");
1301 MSM_PM_DEBUG_PRINT_SLEEP_INFO();
1302
Murali Nalajala2a0bbda2012-03-28 12:12:54 +05301303 msm_pm_irq_extns->exit_sleep2(msm_pm_smem_data->irq_mask,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001304 msm_pm_smem_data->wakeup_reason,
1305 msm_pm_smem_data->pending_irqs);
Murali Nalajala2a0bbda2012-03-28 12:12:54 +05301306 msm_pm_irq_extns->exit_sleep3(msm_pm_smem_data->irq_mask,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001307 msm_pm_smem_data->wakeup_reason,
1308 msm_pm_smem_data->pending_irqs);
1309 msm_gpio_exit_sleep();
1310 msm_sirc_exit_sleep();
1311
1312 smsm_change_state(SMSM_APPS_DEM,
1313 DEM_SLAVE_SMSM_WFPI, DEM_SLAVE_SMSM_RUN);
1314
1315 MSM_PM_DEBUG_PRINT_STATE("msm_pm_power_collapse(): RUN");
1316
1317 smd_sleep_exit();
Murali Nalajala41786ab2012-03-06 10:47:32 +05301318
1319 if (cpu_is_msm8625()) {
1320 ret = msm_spm_set_low_power_mode(MSM_SPM_MODE_CLOCK_GATING,
1321 false);
1322 WARN_ON(ret);
1323 }
1324
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001325 return 0;
1326
1327power_collapse_early_exit:
1328 /* Enter PWRC_EARLY_EXIT */
1329
1330 smsm_change_state(SMSM_APPS_DEM,
1331 DEM_SLAVE_SMSM_PWRC | DEM_SLAVE_SMSM_PWRC_SUSPEND,
1332 DEM_SLAVE_SMSM_PWRC_EARLY_EXIT);
1333
1334 MSM_PM_DEBUG_PRINT_STATE("msm_pm_power_collapse(): EARLY_EXIT");
1335
1336 memset(state_grps, 0, sizeof(state_grps));
1337 state_grps[0].group_id = SMSM_POWER_MASTER_DEM;
1338 state_grps[0].bits_all_set = DEM_MASTER_SMSM_PWRC_EARLY_EXIT;
1339 state_grps[1].group_id = SMSM_MODEM_STATE;
1340 state_grps[1].bits_all_set = SMSM_RESET;
1341
1342 ret = msm_pm_poll_state(ARRAY_SIZE(state_grps), state_grps);
1343 MSM_PM_DEBUG_PRINT_STATE("msm_pm_power_collapse(): EARLY_EXIT EE");
1344
1345 if (ret < 0) {
1346 printk(KERN_EMERG "%s(): power collapse EARLY_EXIT "
1347 "timed out waiting for Modem's response\n", __func__);
1348 msm_pm_timeout();
1349 }
1350
1351 if (ret == 1) {
1352 MSM_PM_DPRINTK(
1353 MSM_PM_DEBUG_SUSPEND|MSM_PM_DEBUG_POWER_COLLAPSE,
1354 KERN_INFO,
1355 "%s(): msm_pm_poll_state detected Modem reset\n",
1356 __func__);
1357 }
1358
1359 /* DEM Master == RESET or PWRC_EARLY_EXIT */
1360
1361 ret = -EAGAIN;
1362
1363power_collapse_restore_gpio_bail:
1364 msm_gpio_exit_sleep();
1365 msm_sirc_exit_sleep();
1366
1367 /* Enter RUN */
1368 smsm_change_state(SMSM_APPS_DEM,
1369 DEM_SLAVE_SMSM_PWRC | DEM_SLAVE_SMSM_PWRC_SUSPEND |
1370 DEM_SLAVE_SMSM_PWRC_EARLY_EXIT, DEM_SLAVE_SMSM_RUN);
1371
1372 MSM_PM_DEBUG_PRINT_STATE("msm_pm_power_collapse(): RUN");
1373
1374 if (collapsed)
1375 smd_sleep_exit();
1376
1377power_collapse_bail:
Murali Nalajala41786ab2012-03-06 10:47:32 +05301378 if (cpu_is_msm8625()) {
1379 ret = msm_spm_set_low_power_mode(MSM_SPM_MODE_CLOCK_GATING,
1380 false);
1381 WARN_ON(ret);
1382 }
1383
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001384 return ret;
1385}
1386
1387/*
1388 * Power collapse the Apps processor without involving Modem.
1389 *
1390 * Return value:
1391 * 0: success
1392 */
Murali Nalajala41786ab2012-03-06 10:47:32 +05301393static int msm_pm_power_collapse_standalone(bool from_idle)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001394{
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001395 int collapsed = 0;
1396 int ret;
Murali Nalajala41786ab2012-03-06 10:47:32 +05301397 void *entry;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001398
1399 MSM_PM_DPRINTK(MSM_PM_DEBUG_SUSPEND|MSM_PM_DEBUG_POWER_COLLAPSE,
1400 KERN_INFO, "%s()\n", __func__);
1401
1402 ret = msm_spm_set_low_power_mode(MSM_SPM_MODE_POWER_COLLAPSE, false);
1403 WARN_ON(ret);
1404
Murali Nalajala41786ab2012-03-06 10:47:32 +05301405 entry = (!smp_processor_id() || from_idle) ?
1406 msm_pm_collapse_exit : msm_secondary_startup;
1407
Maheshkumar Sivasubramanian8ccc16e2011-10-25 15:59:57 -06001408 msm_pm_boot_config_before_pc(smp_processor_id(),
Murali Nalajala41786ab2012-03-06 10:47:32 +05301409 virt_to_phys(entry));
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001410
1411#ifdef CONFIG_VFP
1412 vfp_flush_context();
1413#endif
1414
1415#ifdef CONFIG_CACHE_L2X0
Murali Nalajala41786ab2012-03-06 10:47:32 +05301416 if (!cpu_is_msm8625())
1417 l2x0_suspend();
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001418#endif
1419
1420 collapsed = msm_pm_collapse();
1421
1422#ifdef CONFIG_CACHE_L2X0
Murali Nalajala41786ab2012-03-06 10:47:32 +05301423 if (!cpu_is_msm8625())
1424 l2x0_resume(collapsed);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001425#endif
1426
Maheshkumar Sivasubramanian8ccc16e2011-10-25 15:59:57 -06001427 msm_pm_boot_config_after_pc(smp_processor_id());
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001428
1429 if (collapsed) {
1430#ifdef CONFIG_VFP
1431 vfp_reinit();
1432#endif
1433 cpu_init();
1434 local_fiq_enable();
1435 }
1436
1437 MSM_PM_DPRINTK(MSM_PM_DEBUG_SUSPEND | MSM_PM_DEBUG_POWER_COLLAPSE,
1438 KERN_INFO,
1439 "%s(): msm_pm_collapse returned %d\n", __func__, collapsed);
1440
1441 ret = msm_spm_set_low_power_mode(MSM_SPM_MODE_CLOCK_GATING, false);
1442 WARN_ON(ret);
1443
1444 return 0;
1445}
1446
1447/*
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001448 * Bring the Apps processor to SWFI.
1449 *
1450 * Return value:
1451 * -EIO: could not ramp Apps processor clock
1452 * 0: success
1453 */
1454static int msm_pm_swfi(bool ramp_acpu)
1455{
1456 unsigned long saved_acpuclk_rate = 0;
1457
1458 if (ramp_acpu) {
1459 saved_acpuclk_rate = acpuclk_wait_for_irq();
1460 MSM_PM_DPRINTK(MSM_PM_DEBUG_CLOCK, KERN_INFO,
1461 "%s(): change clock rate (old rate = %lu)\n", __func__,
1462 saved_acpuclk_rate);
1463
1464 if (!saved_acpuclk_rate)
1465 return -EIO;
1466 }
1467
Murali Nalajala41786ab2012-03-06 10:47:32 +05301468 if (!cpu_is_msm8625())
1469 msm_pm_config_hw_before_swfi();
1470
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001471 msm_arch_idle();
1472
1473 if (ramp_acpu) {
1474 MSM_PM_DPRINTK(MSM_PM_DEBUG_CLOCK, KERN_INFO,
1475 "%s(): restore clock rate to %lu\n", __func__,
1476 saved_acpuclk_rate);
1477 if (acpuclk_set_rate(smp_processor_id(), saved_acpuclk_rate,
1478 SETRATE_SWFI) < 0)
1479 printk(KERN_ERR
1480 "%s(): failed to restore clock rate(%lu)\n",
1481 __func__, saved_acpuclk_rate);
1482 }
1483
1484 return 0;
1485}
1486
1487
1488/******************************************************************************
1489 * External Idle/Suspend Functions
1490 *****************************************************************************/
1491
1492/*
1493 * Put CPU in low power mode.
1494 */
1495void arch_idle(void)
1496{
1497 bool allow[MSM_PM_SLEEP_MODE_NR];
1498 uint32_t sleep_limit = SLEEP_LIMIT_NONE;
1499
1500 int latency_qos;
1501 int64_t timer_expiration;
1502
1503 int low_power;
1504 int ret;
1505 int i;
Murali Nalajala0df9fee2012-01-12 15:26:09 +05301506 unsigned int cpu;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001507
1508#ifdef CONFIG_MSM_IDLE_STATS
1509 int64_t t1;
1510 static int64_t t2;
1511 int exit_stat;
Murali Nalajala41786ab2012-03-06 10:47:32 +05301512 #endif
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001513
1514 if (!atomic_read(&msm_pm_init_done))
1515 return;
1516
Murali Nalajala0df9fee2012-01-12 15:26:09 +05301517 cpu = smp_processor_id();
1518
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001519 latency_qos = pm_qos_request(PM_QOS_CPU_DMA_LATENCY);
1520 timer_expiration = msm_timer_enter_idle();
1521
1522#ifdef CONFIG_MSM_IDLE_STATS
1523 t1 = ktime_to_ns(ktime_get());
1524 msm_pm_add_stat(MSM_PM_STAT_NOT_IDLE, t1 - t2);
1525 msm_pm_add_stat(MSM_PM_STAT_REQUESTED_IDLE, timer_expiration);
Murali Nalajala7744d162012-01-13 13:06:03 +05301526
1527 exit_stat = MSM_PM_STAT_IDLE_SPIN;
1528 low_power = 0;
Murali Nalajala41786ab2012-03-06 10:47:32 +05301529#endif
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001530
1531 for (i = 0; i < ARRAY_SIZE(allow); i++)
1532 allow[i] = true;
1533
Murali Nalajala41786ab2012-03-06 10:47:32 +05301534 if (num_online_cpus() > 1 ||
1535 (timer_expiration < msm_pm_idle_sleep_min_time) ||
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001536#ifdef CONFIG_HAS_WAKELOCK
1537 has_wake_lock(WAKE_LOCK_IDLE) ||
1538#endif
Murali Nalajala2a0bbda2012-03-28 12:12:54 +05301539 !msm_pm_irq_extns->idle_sleep_allowed()) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001540 allow[MSM_PM_SLEEP_MODE_POWER_COLLAPSE] = false;
1541 allow[MSM_PM_SLEEP_MODE_POWER_COLLAPSE_NO_XO_SHUTDOWN] = false;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001542 }
1543
1544 for (i = 0; i < ARRAY_SIZE(allow); i++) {
Murali Nalajala0df9fee2012-01-12 15:26:09 +05301545 struct msm_pm_platform_data *mode =
1546 &msm_pm_modes[MSM_PM_MODE(cpu, i)];
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001547 if (!mode->idle_supported || !mode->idle_enabled ||
1548 mode->latency >= latency_qos ||
1549 mode->residency * 1000ULL >= timer_expiration)
1550 allow[i] = false;
1551 }
1552
1553 if (allow[MSM_PM_SLEEP_MODE_POWER_COLLAPSE] ||
1554 allow[MSM_PM_SLEEP_MODE_POWER_COLLAPSE_NO_XO_SHUTDOWN]) {
1555 uint32_t wait_us = CONFIG_MSM_IDLE_WAIT_ON_MODEM;
1556 while (msm_pm_modem_busy() && wait_us) {
1557 if (wait_us > 100) {
1558 udelay(100);
1559 wait_us -= 100;
1560 } else {
1561 udelay(wait_us);
1562 wait_us = 0;
1563 }
1564 }
1565
1566 if (msm_pm_modem_busy()) {
1567 allow[MSM_PM_SLEEP_MODE_POWER_COLLAPSE] = false;
1568 allow[MSM_PM_SLEEP_MODE_POWER_COLLAPSE_NO_XO_SHUTDOWN]
1569 = false;
1570 }
1571 }
1572
1573 MSM_PM_DPRINTK(MSM_PM_DEBUG_IDLE, KERN_INFO,
1574 "%s(): latency qos %d, next timer %lld, sleep limit %u\n",
1575 __func__, latency_qos, timer_expiration, sleep_limit);
1576
1577 for (i = 0; i < ARRAY_SIZE(allow); i++)
1578 MSM_PM_DPRINTK(MSM_PM_DEBUG_IDLE, KERN_INFO,
1579 "%s(): allow %s: %d\n", __func__,
1580 msm_pm_sleep_mode_labels[i], (int)allow[i]);
1581
1582 if (allow[MSM_PM_SLEEP_MODE_POWER_COLLAPSE] ||
1583 allow[MSM_PM_SLEEP_MODE_POWER_COLLAPSE_NO_XO_SHUTDOWN]) {
1584 uint32_t sleep_delay;
1585
1586 sleep_delay = (uint32_t) msm_pm_convert_and_cap_time(
1587 timer_expiration, MSM_PM_SLEEP_TICK_LIMIT);
1588 if (sleep_delay == 0) /* 0 would mean infinite time */
1589 sleep_delay = 1;
1590
1591 if (!allow[MSM_PM_SLEEP_MODE_POWER_COLLAPSE])
1592 sleep_limit = SLEEP_LIMIT_NO_TCXO_SHUTDOWN;
1593
1594#if defined(CONFIG_MSM_MEMORY_LOW_POWER_MODE_IDLE_ACTIVE)
1595 sleep_limit |= SLEEP_RESOURCE_MEMORY_BIT1;
1596#elif defined(CONFIG_MSM_MEMORY_LOW_POWER_MODE_IDLE_RETENTION)
1597 sleep_limit |= SLEEP_RESOURCE_MEMORY_BIT0;
1598#endif
1599
1600 ret = msm_pm_power_collapse(true, sleep_delay, sleep_limit);
1601 low_power = (ret != -EBUSY && ret != -ETIMEDOUT);
1602
1603#ifdef CONFIG_MSM_IDLE_STATS
1604 if (ret)
1605 exit_stat = MSM_PM_STAT_IDLE_FAILED_POWER_COLLAPSE;
1606 else {
1607 exit_stat = MSM_PM_STAT_IDLE_POWER_COLLAPSE;
1608 msm_pm_sleep_limit = sleep_limit;
1609 }
Murali Nalajala41786ab2012-03-06 10:47:32 +05301610#endif
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001611 } else if (allow[MSM_PM_SLEEP_MODE_POWER_COLLAPSE_STANDALONE]) {
Murali Nalajala41786ab2012-03-06 10:47:32 +05301612 ret = msm_pm_power_collapse_standalone(true);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001613 low_power = 0;
1614#ifdef CONFIG_MSM_IDLE_STATS
1615 exit_stat = ret ?
1616 MSM_PM_STAT_IDLE_FAILED_STANDALONE_POWER_COLLAPSE :
1617 MSM_PM_STAT_IDLE_STANDALONE_POWER_COLLAPSE;
Murali Nalajala41786ab2012-03-06 10:47:32 +05301618#endif
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001619 } else if (allow[MSM_PM_SLEEP_MODE_RAMP_DOWN_AND_WAIT_FOR_INTERRUPT]) {
1620 ret = msm_pm_swfi(true);
1621 if (ret)
Murali Nalajala2a0bbda2012-03-28 12:12:54 +05301622 while (!msm_pm_irq_extns->irq_pending())
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001623 udelay(1);
1624 low_power = 0;
1625#ifdef CONFIG_MSM_IDLE_STATS
1626 exit_stat = ret ? MSM_PM_STAT_IDLE_SPIN : MSM_PM_STAT_IDLE_WFI;
Murali Nalajala41786ab2012-03-06 10:47:32 +05301627#endif
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001628 } else if (allow[MSM_PM_SLEEP_MODE_WAIT_FOR_INTERRUPT]) {
1629 msm_pm_swfi(false);
1630 low_power = 0;
1631#ifdef CONFIG_MSM_IDLE_STATS
1632 exit_stat = MSM_PM_STAT_IDLE_WFI;
Murali Nalajala41786ab2012-03-06 10:47:32 +05301633#endif
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001634 } else {
Murali Nalajala2a0bbda2012-03-28 12:12:54 +05301635 while (!msm_pm_irq_extns->irq_pending())
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001636 udelay(1);
1637 low_power = 0;
1638#ifdef CONFIG_MSM_IDLE_STATS
1639 exit_stat = MSM_PM_STAT_IDLE_SPIN;
Murali Nalajala41786ab2012-03-06 10:47:32 +05301640#endif
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001641 }
1642
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001643 msm_timer_exit_idle(low_power);
1644
1645#ifdef CONFIG_MSM_IDLE_STATS
1646 t2 = ktime_to_ns(ktime_get());
1647 msm_pm_add_stat(exit_stat, t2 - t1);
Murali Nalajala41786ab2012-03-06 10:47:32 +05301648#endif
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001649}
1650
1651/*
1652 * Suspend the Apps processor.
1653 *
1654 * Return value:
Murali Nalajala41786ab2012-03-06 10:47:32 +05301655 * -EPERM: Suspend happened by a not permitted core
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001656 * -EAGAIN: modem reset occurred or early exit from suspend
1657 * -EBUSY: modem not ready for our suspend
1658 * -EINVAL: invalid sleep mode
1659 * -EIO: could not ramp Apps processor clock
1660 * -ETIMEDOUT: timed out waiting for modem's handshake
1661 * 0: success
1662 */
1663static int msm_pm_enter(suspend_state_t state)
1664{
1665 bool allow[MSM_PM_SLEEP_MODE_NR];
1666 uint32_t sleep_limit = SLEEP_LIMIT_NONE;
Murali Nalajala41786ab2012-03-06 10:47:32 +05301667 int ret = -EPERM;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001668 int i;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001669#ifdef CONFIG_MSM_IDLE_STATS
1670 int64_t period = 0;
1671 int64_t time = 0;
Murali Nalajala41786ab2012-03-06 10:47:32 +05301672#endif
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001673
Murali Nalajala41786ab2012-03-06 10:47:32 +05301674 /* Must executed by CORE0 */
1675 if (smp_processor_id()) {
1676 __WARN();
1677 goto suspend_exit;
1678 }
1679
1680#ifdef CONFIG_MSM_IDLE_STATS
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001681 time = msm_timer_get_sclk_time(&period);
1682#endif
1683
1684 MSM_PM_DPRINTK(MSM_PM_DEBUG_SUSPEND, KERN_INFO,
1685 "%s(): sleep limit %u\n", __func__, sleep_limit);
1686
1687 for (i = 0; i < ARRAY_SIZE(allow); i++)
1688 allow[i] = true;
1689
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001690 for (i = 0; i < ARRAY_SIZE(allow); i++) {
Murali Nalajala0df9fee2012-01-12 15:26:09 +05301691 struct msm_pm_platform_data *mode;
1692 mode = &msm_pm_modes[MSM_PM_MODE(0, i)];
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001693 if (!mode->suspend_supported || !mode->suspend_enabled)
1694 allow[i] = false;
1695 }
1696
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001697 if (allow[MSM_PM_SLEEP_MODE_POWER_COLLAPSE] ||
1698 allow[MSM_PM_SLEEP_MODE_POWER_COLLAPSE_NO_XO_SHUTDOWN]) {
1699#ifdef CONFIG_MSM_IDLE_STATS
1700 enum msm_pm_time_stats_id id;
1701 int64_t end_time;
1702#endif
1703
1704 clock_debug_print_enabled();
1705
1706#ifdef CONFIG_MSM_SLEEP_TIME_OVERRIDE
1707 if (msm_pm_sleep_time_override > 0) {
1708 int64_t ns;
1709 ns = NSEC_PER_SEC * (int64_t)msm_pm_sleep_time_override;
1710 msm_pm_set_max_sleep_time(ns);
1711 msm_pm_sleep_time_override = 0;
1712 }
1713#endif
1714 if (!allow[MSM_PM_SLEEP_MODE_POWER_COLLAPSE])
1715 sleep_limit = SLEEP_LIMIT_NO_TCXO_SHUTDOWN;
1716
1717#if defined(CONFIG_MSM_MEMORY_LOW_POWER_MODE_SUSPEND_ACTIVE)
1718 sleep_limit |= SLEEP_RESOURCE_MEMORY_BIT1;
1719#elif defined(CONFIG_MSM_MEMORY_LOW_POWER_MODE_SUSPEND_RETENTION)
1720 sleep_limit |= SLEEP_RESOURCE_MEMORY_BIT0;
1721#elif defined(CONFIG_MSM_MEMORY_LOW_POWER_MODE_SUSPEND_DEEP_POWER_DOWN)
1722 if (get_msm_migrate_pages_status() != MEM_OFFLINE)
1723 sleep_limit |= SLEEP_RESOURCE_MEMORY_BIT0;
1724#endif
1725
1726 for (i = 0; i < 30 && msm_pm_modem_busy(); i++)
1727 udelay(500);
1728
1729 ret = msm_pm_power_collapse(
1730 false, msm_pm_max_sleep_time, sleep_limit);
1731
1732#ifdef CONFIG_MSM_IDLE_STATS
1733 if (ret)
1734 id = MSM_PM_STAT_FAILED_SUSPEND;
1735 else {
1736 id = MSM_PM_STAT_SUSPEND;
1737 msm_pm_sleep_limit = sleep_limit;
1738 }
1739
1740 if (time != 0) {
1741 end_time = msm_timer_get_sclk_time(NULL);
1742 if (end_time != 0) {
1743 time = end_time - time;
1744 if (time < 0)
1745 time += period;
1746 } else
1747 time = 0;
1748 }
1749
1750 msm_pm_add_stat(id, time);
1751#endif
1752 } else if (allow[MSM_PM_SLEEP_MODE_POWER_COLLAPSE_STANDALONE]) {
Murali Nalajala41786ab2012-03-06 10:47:32 +05301753 ret = msm_pm_power_collapse_standalone(false);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001754 } else if (allow[MSM_PM_SLEEP_MODE_RAMP_DOWN_AND_WAIT_FOR_INTERRUPT]) {
1755 ret = msm_pm_swfi(true);
1756 if (ret)
Murali Nalajala2a0bbda2012-03-28 12:12:54 +05301757 while (!msm_pm_irq_extns->irq_pending())
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001758 udelay(1);
1759 } else if (allow[MSM_PM_SLEEP_MODE_WAIT_FOR_INTERRUPT]) {
1760 msm_pm_swfi(false);
1761 }
1762
Murali Nalajala41786ab2012-03-06 10:47:32 +05301763suspend_exit:
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001764 MSM_PM_DPRINTK(MSM_PM_DEBUG_SUSPEND, KERN_INFO,
1765 "%s(): return %d\n", __func__, ret);
1766
1767 return ret;
1768}
1769
1770static struct platform_suspend_ops msm_pm_ops = {
1771 .enter = msm_pm_enter,
1772 .valid = suspend_valid_only_mem,
1773};
1774
Murali Nalajalac89f2f32012-02-07 19:23:52 +05301775/* Hotplug the "non boot" CPU's and put
1776 * the cores into low power mode
1777 */
1778void msm_pm_cpu_enter_lowpower(unsigned int cpu)
1779{
Murali Nalajalaa7efba12012-02-23 18:13:52 +05301780 bool allow[MSM_PM_SLEEP_MODE_NR];
1781 int i;
1782
1783 for (i = 0; i < MSM_PM_SLEEP_MODE_NR; i++) {
1784 struct msm_pm_platform_data *mode;
1785
1786 mode = &msm_pm_modes[MSM_PM_MODE(cpu, i)];
1787 allow[i] = mode->suspend_supported && mode->suspend_enabled;
1788 }
1789
1790 MSM_PM_DPRINTK(MSM_PM_DEBUG_HOTPLUG, KERN_INFO,
1791 "CPU%u: %s: shutting down cpu\n", cpu, __func__);
1792
1793 if (allow[MSM_PM_SLEEP_MODE_POWER_COLLAPSE_STANDALONE]) {
1794 msm_pm_power_collapse_standalone(false);
1795 } else if (allow[MSM_PM_SLEEP_MODE_WAIT_FOR_INTERRUPT]) {
1796 msm_pm_swfi(false);
1797 } else {
1798 MSM_PM_DPRINTK(MSM_PM_DEBUG_HOTPLUG, KERN_INFO,
1799 "CPU%u: %s: shutting down failed!!!\n", cpu, __func__);
1800 }
Murali Nalajalac89f2f32012-02-07 19:23:52 +05301801}
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001802
1803/******************************************************************************
1804 * Restart Definitions
1805 *****************************************************************************/
1806
1807static uint32_t restart_reason = 0x776655AA;
1808
1809static void msm_pm_power_off(void)
1810{
1811 msm_rpcrouter_close();
1812 msm_proc_comm(PCOM_POWER_DOWN, 0, 0);
1813 for (;;)
1814 ;
1815}
1816
1817static void msm_pm_restart(char str, const char *cmd)
1818{
1819 msm_rpcrouter_close();
1820 msm_proc_comm(PCOM_RESET_CHIP, &restart_reason, 0);
1821
1822 for (;;)
1823 ;
1824}
1825
1826static int msm_reboot_call
1827 (struct notifier_block *this, unsigned long code, void *_cmd)
1828{
1829 if ((code == SYS_RESTART) && _cmd) {
1830 char *cmd = _cmd;
1831 if (!strcmp(cmd, "bootloader")) {
1832 restart_reason = 0x77665500;
1833 } else if (!strcmp(cmd, "recovery")) {
1834 restart_reason = 0x77665502;
1835 } else if (!strcmp(cmd, "eraseflash")) {
1836 restart_reason = 0x776655EF;
1837 } else if (!strncmp(cmd, "oem-", 4)) {
1838 unsigned code = simple_strtoul(cmd + 4, 0, 16) & 0xff;
1839 restart_reason = 0x6f656d00 | code;
1840 } else {
1841 restart_reason = 0x77665501;
1842 }
1843 }
1844 return NOTIFY_DONE;
1845}
1846
1847static struct notifier_block msm_reboot_notifier = {
1848 .notifier_call = msm_reboot_call,
1849};
1850
1851
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001852/*
1853 * Initialize the power management subsystem.
1854 *
1855 * Return value:
1856 * -ENODEV: initialization failed
1857 * 0: success
1858 */
1859static int __init msm_pm_init(void)
1860{
1861#ifdef CONFIG_MSM_IDLE_STATS
1862 struct proc_dir_entry *d_entry;
Murali Nalajala0df9fee2012-01-12 15:26:09 +05301863 unsigned int cpu;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001864#endif
1865 int ret;
1866#ifdef CONFIG_CPU_V7
1867 pgd_t *pc_pgd;
1868 pmd_t *pmd;
1869 unsigned long pmdval;
1870
1871 /* Page table for cores to come back up safely. */
1872 pc_pgd = pgd_alloc(&init_mm);
1873 if (!pc_pgd)
1874 return -ENOMEM;
1875 pmd = pmd_offset(pc_pgd +
1876 pgd_index(virt_to_phys(msm_pm_collapse_exit)),
1877 virt_to_phys(msm_pm_collapse_exit));
1878 pmdval = (virt_to_phys(msm_pm_collapse_exit) & PGDIR_MASK) |
1879 PMD_TYPE_SECT | PMD_SECT_AP_WRITE;
1880 pmd[0] = __pmd(pmdval);
1881 pmd[1] = __pmd(pmdval + (1 << (PGDIR_SHIFT - 1)));
1882
1883 /* It is remotely possible that the code in msm_pm_collapse_exit()
1884 * which turns on the MMU with this mapping is in the
1885 * next even-numbered megabyte beyond the
1886 * start of msm_pm_collapse_exit().
1887 * Map this megabyte in as well.
1888 */
1889 pmd[2] = __pmd(pmdval + (2 << (PGDIR_SHIFT - 1)));
1890 flush_pmd_entry(pmd);
1891 msm_pm_pc_pgd = virt_to_phys(pc_pgd);
1892#endif
1893
1894 pm_power_off = msm_pm_power_off;
1895 arm_pm_restart = msm_pm_restart;
1896 register_reboot_notifier(&msm_reboot_notifier);
1897
1898 msm_pm_smem_data = smem_alloc(SMEM_APPS_DEM_SLAVE_DATA,
1899 sizeof(*msm_pm_smem_data));
1900 if (msm_pm_smem_data == NULL) {
1901 printk(KERN_ERR "%s: failed to get smsm_data\n", __func__);
1902 return -ENODEV;
1903 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001904
1905 ret = msm_timer_init_time_sync(msm_pm_timeout);
1906 if (ret)
1907 return ret;
1908
1909 ret = smsm_change_intr_mask(SMSM_POWER_MASTER_DEM, 0xFFFFFFFF, 0);
1910 if (ret) {
1911 printk(KERN_ERR "%s: failed to clear interrupt mask, %d\n",
1912 __func__, ret);
1913 return ret;
1914 }
1915
1916#ifdef CONFIG_MSM_MEMORY_LOW_POWER_MODE
1917 /* The wakeup_reason field is overloaded during initialization time
1918 to signal Modem that Apps will control the low power modes of
1919 the memory.
1920 */
1921 msm_pm_smem_data->wakeup_reason = 1;
1922 smsm_change_state(SMSM_APPS_DEM, 0, DEM_SLAVE_SMSM_RUN);
1923#endif
1924
1925 BUG_ON(msm_pm_modes == NULL);
1926
1927 atomic_set(&msm_pm_init_done, 1);
1928 suspend_set_ops(&msm_pm_ops);
1929
1930 msm_pm_mode_sysfs_add();
1931#ifdef CONFIG_MSM_IDLE_STATS
Murali Nalajala0df9fee2012-01-12 15:26:09 +05301932 for_each_possible_cpu(cpu) {
1933 struct msm_pm_time_stats *stats =
1934 per_cpu(msm_pm_stats, cpu).stats;
1935
1936 stats[MSM_PM_STAT_REQUESTED_IDLE].name = "idle-request";
1937 stats[MSM_PM_STAT_REQUESTED_IDLE].first_bucket_time =
1938 CONFIG_MSM_IDLE_STATS_FIRST_BUCKET;
1939
1940 stats[MSM_PM_STAT_IDLE_SPIN].name = "idle-spin";
1941 stats[MSM_PM_STAT_IDLE_SPIN].first_bucket_time =
1942 CONFIG_MSM_IDLE_STATS_FIRST_BUCKET;
1943
1944 stats[MSM_PM_STAT_IDLE_WFI].name = "idle-wfi";
1945 stats[MSM_PM_STAT_IDLE_WFI].first_bucket_time =
1946 CONFIG_MSM_IDLE_STATS_FIRST_BUCKET;
1947
1948 stats[MSM_PM_STAT_IDLE_STANDALONE_POWER_COLLAPSE].name =
1949 "idle-standalone-power-collapse";
1950 stats[MSM_PM_STAT_IDLE_STANDALONE_POWER_COLLAPSE].
1951 first_bucket_time =
1952 CONFIG_MSM_IDLE_STATS_FIRST_BUCKET;
1953
1954 stats[MSM_PM_STAT_IDLE_FAILED_STANDALONE_POWER_COLLAPSE].name =
1955 "idle-failed-standalone-power-collapse";
1956 stats[MSM_PM_STAT_IDLE_FAILED_STANDALONE_POWER_COLLAPSE].
1957 first_bucket_time =
1958 CONFIG_MSM_IDLE_STATS_FIRST_BUCKET;
1959
Murali Nalajala0df9fee2012-01-12 15:26:09 +05301960 stats[MSM_PM_STAT_IDLE_POWER_COLLAPSE].name =
1961 "idle-power-collapse";
1962 stats[MSM_PM_STAT_IDLE_POWER_COLLAPSE].first_bucket_time =
1963 CONFIG_MSM_IDLE_STATS_FIRST_BUCKET;
1964
1965 stats[MSM_PM_STAT_IDLE_FAILED_POWER_COLLAPSE].name =
1966 "idle-failed-power-collapse";
1967 stats[MSM_PM_STAT_IDLE_FAILED_POWER_COLLAPSE].
1968 first_bucket_time =
1969 CONFIG_MSM_IDLE_STATS_FIRST_BUCKET;
1970
1971 stats[MSM_PM_STAT_SUSPEND].name = "suspend";
1972 stats[MSM_PM_STAT_SUSPEND].first_bucket_time =
1973 CONFIG_MSM_SUSPEND_STATS_FIRST_BUCKET;
1974
1975 stats[MSM_PM_STAT_FAILED_SUSPEND].name = "failed-suspend";
1976 stats[MSM_PM_STAT_FAILED_SUSPEND].first_bucket_time =
1977 CONFIG_MSM_IDLE_STATS_FIRST_BUCKET;
1978
1979 stats[MSM_PM_STAT_NOT_IDLE].name = "not-idle";
1980 stats[MSM_PM_STAT_NOT_IDLE].first_bucket_time =
1981 CONFIG_MSM_IDLE_STATS_FIRST_BUCKET;
1982 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001983 d_entry = create_proc_entry("msm_pm_stats",
1984 S_IRUGO | S_IWUSR | S_IWGRP, NULL);
1985 if (d_entry) {
1986 d_entry->read_proc = msm_pm_read_proc;
1987 d_entry->write_proc = msm_pm_write_proc;
1988 d_entry->data = NULL;
1989 }
1990#endif
1991
1992 return 0;
1993}
1994
1995late_initcall_sync(msm_pm_init);