cpuidle.c 4.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177
  1. /* Copyright (c) 2010-2013, The Linux Foundation. All rights reserved.
  2. *
  3. * This program is free software; you can redistribute it and/or modify
  4. * it under the terms of the GNU General Public License version 2 and
  5. * only version 2 as published by the Free Software Foundation.
  6. *
  7. * This program is distributed in the hope that it will be useful,
  8. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  9. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  10. * GNU General Public License for more details.
  11. */
  12. #include <linux/module.h>
  13. #include <linux/kernel.h>
  14. #include <linux/init.h>
  15. #include <linux/cpuidle.h>
  16. #include <mach/cpuidle.h>
  17. #include "pm.h"
  18. static DEFINE_PER_CPU_SHARED_ALIGNED(struct cpuidle_device, msm_cpuidle_devs);
  19. static struct cpuidle_driver msm_cpuidle_driver = {
  20. .name = "msm_idle",
  21. .owner = THIS_MODULE,
  22. };
  23. static struct msm_cpuidle_state msm_cstates[] = {
  24. {0, 0, "C0", "WFI",
  25. MSM_PM_SLEEP_MODE_WAIT_FOR_INTERRUPT},
  26. {0, 1, "C1", "RETENTION",
  27. MSM_PM_SLEEP_MODE_RETENTION},
  28. {0, 2, "C2", "STANDALONE_POWER_COLLAPSE",
  29. MSM_PM_SLEEP_MODE_POWER_COLLAPSE_STANDALONE},
  30. {0, 3, "C3", "POWER_COLLAPSE",
  31. MSM_PM_SLEEP_MODE_POWER_COLLAPSE},
  32. {1, 0, "C0", "WFI",
  33. MSM_PM_SLEEP_MODE_WAIT_FOR_INTERRUPT},
  34. {1, 1, "C1", "RETENTION",
  35. MSM_PM_SLEEP_MODE_RETENTION},
  36. {1, 2, "C2", "STANDALONE_POWER_COLLAPSE",
  37. MSM_PM_SLEEP_MODE_POWER_COLLAPSE_STANDALONE},
  38. {2, 0, "C0", "WFI",
  39. MSM_PM_SLEEP_MODE_WAIT_FOR_INTERRUPT},
  40. {2, 1, "C1", "RETENTION",
  41. MSM_PM_SLEEP_MODE_RETENTION},
  42. {2, 2, "C2", "STANDALONE_POWER_COLLAPSE",
  43. MSM_PM_SLEEP_MODE_POWER_COLLAPSE_STANDALONE},
  44. {3, 0, "C0", "WFI",
  45. MSM_PM_SLEEP_MODE_WAIT_FOR_INTERRUPT},
  46. {3, 1, "C1", "RETENTION",
  47. MSM_PM_SLEEP_MODE_RETENTION},
  48. {3, 2, "C2", "STANDALONE_POWER_COLLAPSE",
  49. MSM_PM_SLEEP_MODE_POWER_COLLAPSE_STANDALONE},
  50. };
  51. static int msm_cpuidle_enter(
  52. struct cpuidle_device *dev, struct cpuidle_driver *drv, int index)
  53. {
  54. int ret = 0;
  55. int i;
  56. enum msm_pm_sleep_mode pm_mode;
  57. pm_mode = msm_pm_idle_enter(dev, drv, index);
  58. for (i = 0; i < dev->state_count; i++) {
  59. struct cpuidle_state_usage *st_usage = &dev->states_usage[i];
  60. enum msm_pm_sleep_mode last_mode =
  61. (enum msm_pm_sleep_mode)cpuidle_get_statedata(st_usage);
  62. if (last_mode == pm_mode) {
  63. ret = i;
  64. break;
  65. }
  66. }
  67. local_irq_enable();
  68. return ret;
  69. }
  70. static void __devinit msm_cpuidle_set_states(void)
  71. {
  72. int i = 0;
  73. int state_count = 0;
  74. struct msm_cpuidle_state *cstate = NULL;
  75. struct cpuidle_state *state = NULL;
  76. for (i = 0; i < ARRAY_SIZE(msm_cstates); i++) {
  77. cstate = &msm_cstates[i];
  78. /* We have an asymmetric CPU C-State in MSMs.
  79. * The primary CPU can do PC while all secondary cpus
  80. * can only do standalone PC as part of their idle LPM.
  81. * However, the secondary cpus can do PC when hotplugged
  82. * We do not care about the hotplug here.
  83. * Register the C-States available for Core0.
  84. */
  85. if (cstate->cpu)
  86. continue;
  87. state = &msm_cpuidle_driver.states[state_count];
  88. snprintf(state->name, CPUIDLE_NAME_LEN, "%s", cstate->name);
  89. snprintf(state->desc, CPUIDLE_DESC_LEN, "%s", cstate->desc);
  90. state->flags = 0;
  91. state->exit_latency = 0;
  92. state->power_usage = 0;
  93. state->target_residency = 0;
  94. state->enter = msm_cpuidle_enter;
  95. state_count++;
  96. BUG_ON(state_count >= CPUIDLE_STATE_MAX);
  97. }
  98. msm_cpuidle_driver.state_count = state_count;
  99. msm_cpuidle_driver.safe_state_index = 0;
  100. }
  101. static void __init msm_cpuidle_set_cpu_statedata(struct cpuidle_device *dev)
  102. {
  103. int i = 0;
  104. int state_count = 0;
  105. struct cpuidle_state_usage *st_usage = NULL;
  106. struct msm_cpuidle_state *cstate = NULL;
  107. for (i = 0; i < ARRAY_SIZE(msm_cstates); i++) {
  108. cstate = &msm_cstates[i];
  109. if (cstate->cpu != dev->cpu)
  110. continue;
  111. st_usage = &dev->states_usage[state_count];
  112. cpuidle_set_statedata(st_usage, (void *)cstate->mode_nr);
  113. state_count++;
  114. BUG_ON(state_count > msm_cpuidle_driver.state_count);
  115. }
  116. dev->state_count = state_count; /* Per cpu state count */
  117. }
  118. int __devinit msm_cpuidle_init(void)
  119. {
  120. unsigned int cpu = 0;
  121. int ret = 0;
  122. msm_cpuidle_set_states();
  123. ret = cpuidle_register_driver(&msm_cpuidle_driver);
  124. if (ret)
  125. pr_err("%s: failed to register cpuidle driver: %d\n",
  126. __func__, ret);
  127. for_each_possible_cpu(cpu) {
  128. struct cpuidle_device *dev = &per_cpu(msm_cpuidle_devs, cpu);
  129. dev->cpu = cpu;
  130. msm_cpuidle_set_cpu_statedata(dev);
  131. ret = cpuidle_register_device(dev);
  132. if (ret) {
  133. pr_err("%s: failed to register cpuidle device for "
  134. "cpu %u: %d\n", __func__, cpu, ret);
  135. return ret;
  136. }
  137. }
  138. return 0;
  139. }