memoryCall.c 6.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257
  1. /*
  2. * OMAP powerdomain control
  3. *
  4. * Copyright (C) 2007-2008, 2011 Texas Instruments, Inc.
  5. * Copyright (C) 2007-2011 Nokia Corporation
  6. *
  7. * Written by Paul Walmsley
  8. * Added OMAP4 specific support by Abhijit Pagare <abhijitpagare@ti.com>
  9. * State counting code by Tero Kristo <tero.kristo@nokia.com>
  10. *
  11. * This program is free software; you can redistribute it and/or modify
  12. * it under the terms of the GNU General Public License version 2 as
  13. * published by the Free Software Foundation.
  14. */
  15. #undef DEBUG
  16. #include <linux/kernel.h>
  17. #include <linux/types.h>
  18. #include <linux/list.h>
  19. #include <linux/errno.h>
  20. #include <linux/string.h>
  21. #include <trace/events/power.h>
  22. #include "cm2xxx_3xxx.h"
  23. #include "prcm44xx.h"
  24. #include "cm44xx.h"
  25. #include "prm2xxx_3xxx.h"
  26. #include "prm44xx.h"
  27. #include <asm/cpu.h>
  28. #include "powerdomain.h"
  29. #include "clockdomain.h"
  30. #include "soc.h"
  31. #include "pm.h"
  32. #define PWRDM_TRACE_STATES_FLAG (1<<31)
  33. enum {
  34. PWRDM_STATE_NOW = 0,
  35. PWRDM_STATE_PREV,
  36. };
  37. /* pwrdm_list contains all registered struct powerdomains */
  38. static LIST_HEAD(pwrdm_list);
  39. static struct pwrdm_ops *arch_pwrdm;
  40. /* Private functions */
  41. static struct powerdomain *_pwrdm_lookup(const char *name)
  42. {
  43. struct powerdomain *pwrdm, *temp_pwrdm;
  44. pwrdm = NULL;
  45. list_for_each_entry(temp_pwrdm, &pwrdm_list, node) {
  46. if (!strcmp(name, temp_pwrdm->name)) {
  47. pwrdm = temp_pwrdm;
  48. break;
  49. }
  50. }
  51. return pwrdm;
  52. }
  53. /**
  54. * _pwrdm_register - register a powerdomain
  55. * @pwrdm: struct powerdomain * to register
  56. *
  57. * Adds a powerdomain to the internal powerdomain list. Returns
  58. * -EINVAL if given a null pointer, -EEXIST if a powerdomain is
  59. * already registered by the provided name, or 0 upon success.
  60. */
  61. static int _pwrdm_register(struct powerdomain *pwrdm)
  62. {
  63. int i;
  64. struct voltagedomain *voltdm;
  65. if (!pwrdm || !pwrdm->name)
  66. return -EINVAL;
  67. if (cpu_is_omap44xx() &&
  68. pwrdm->prcm_partition == OMAP4430_INVALID_PRCM_PARTITION) {
  69. pr_err("powerdomain: %s: missing OMAP4 PRCM partition ID\n",
  70. pwrdm->name);
  71. return -EINVAL;
  72. }
  73. if (_pwrdm_lookup(pwrdm->name))
  74. return -EEXIST;
  75. voltdm = voltdm_lookup(pwrdm->voltdm.name);
  76. if (!voltdm) {
  77. pr_err("powerdomain: %s: voltagedomain %s does not exist\n",
  78. pwrdm->name, pwrdm->voltdm.name);
  79. return -EINVAL;
  80. }
  81. pwrdm->voltdm.ptr = voltdm;
  82. INIT_LIST_HEAD(&pwrdm->voltdm_node);
  83. voltdm_add_pwrdm(voltdm, pwrdm);
  84. list_add(&pwrdm->node, &pwrdm_list);
  85. /* Initialize the powerdomain's state counter */
  86. for (i = 0; i < PWRDM_MAX_PWRSTS; i++)
  87. pwrdm->state_counter[i] = 0;
  88. pwrdm->ret_logic_off_counter = 0;
  89. for (i = 0; i < pwrdm->banks; i++)
  90. pwrdm->ret_mem_off_counter[i] = 0;
  91. pwrdm_wait_transition(pwrdm);
  92. pwrdm->state = pwrdm_read_pwrst(pwrdm);
  93. pwrdm->state_counter[pwrdm->state] = 1;
  94. pr_debug("powerdomain: registered %s\n", pwrdm->name);
  95. return 0;
  96. }
  97. static void _update_logic_membank_counters(struct powerdomain *pwrdm)
  98. {
  99. int i;
  100. u8 prev_logic_pwrst, prev_mem_pwrst;
  101. prev_logic_pwrst = pwrdm_read_prev_logic_pwrst(pwrdm);
  102. if ((pwrdm->pwrsts_logic_ret == PWRSTS_OFF_RET) &&
  103. (prev_logic_pwrst == PWRDM_POWER_OFF))
  104. pwrdm->ret_logic_off_counter++;
  105. for (i = 0; i < pwrdm->banks; i++) {
  106. prev_mem_pwrst = pwrdm_read_prev_mem_pwrst(pwrdm, i);
  107. if ((pwrdm->pwrsts_mem_ret[i] == PWRSTS_OFF_RET) &&
  108. (prev_mem_pwrst == PWRDM_POWER_OFF))
  109. pwrdm->ret_mem_off_counter[i]++;
  110. }
  111. }
  112. static int _pwrdm_state_switch(struct powerdomain *pwrdm, int flag)
  113. {
  114. int prev, state, trace_state = 0;
  115. if (pwrdm == NULL)
  116. return -EINVAL;
  117. state = pwrdm_read_pwrst(pwrdm);
  118. switch (flag) {
  119. case PWRDM_STATE_NOW:
  120. prev = pwrdm->state;
  121. break;
  122. case PWRDM_STATE_PREV:
  123. prev = pwrdm_read_prev_pwrst(pwrdm);
  124. if (pwrdm->state != prev)
  125. pwrdm->state_counter[prev]++;
  126. if (prev == PWRDM_POWER_RET)
  127. _update_logic_membank_counters(pwrdm);
  128. /*
  129. * If the power domain did not hit the desired state,
  130. * generate a trace event with both the desired and hit states
  131. */
  132. if (state != prev) {
  133. trace_state = (PWRDM_TRACE_STATES_FLAG |
  134. ((state & OMAP_POWERSTATE_MASK) << 8) |
  135. ((prev & OMAP_POWERSTATE_MASK) << 0));
  136. trace_power_domain_target(pwrdm->name, trace_state,
  137. smp_processor_id());
  138. }
  139. break;
  140. default:
  141. return -EINVAL;
  142. }
  143. if (state != prev)
  144. pwrdm->state_counter[state]++;
  145. pm_dbg_update_time(pwrdm, prev);
  146. pwrdm->state = state;
  147. return 0;
  148. }
  149. static int _pwrdm_pre_transition_cb(struct powerdomain *pwrdm, void *unused)
  150. {
  151. pwrdm_clear_all_prev_pwrst(pwrdm);
  152. _pwrdm_state_switch(pwrdm, PWRDM_STATE_NOW);
  153. return 0;
  154. }
  155. static int _pwrdm_post_transition_cb(struct powerdomain *pwrdm, void *unused)
  156. {
  157. _pwrdm_state_switch(pwrdm, PWRDM_STATE_PREV);
  158. return 0;
  159. }
  160. /* Public functions */
  161. /**
  162. * pwrdm_register_platform_funcs - register powerdomain implementation fns
  163. * @po: func pointers for arch specific implementations
  164. *
  165. * Register the list of function pointers used to implement the
  166. * powerdomain functions on different OMAP SoCs. Should be called
  167. * before any other pwrdm_register*() function. Returns -EINVAL if
  168. * @po is null, -EEXIST if platform functions have already been
  169. * registered, or 0 upon success.
  170. */
  171. int pwrdm_register_platform_funcs(struct pwrdm_ops *po)
  172. {
  173. if (!po)
  174. return -EINVAL;
  175. if (arch_pwrdm)
  176. return -EEXIST;
  177. arch_pwrdm = po;
  178. return 0;
  179. }
  180. /**
  181. * pwrdm_register_pwrdms - register SoC powerdomains
  182. * @ps: pointer to an array of struct powerdomain to register
  183. *
  184. * Register the powerdomains available on a particular OMAP SoC. Must
  185. * be called after pwrdm_register_platform_funcs(). May be called
  186. * multiple times. Returns -EACCES if called before
  187. * pwrdm_register_platform_funcs(); -EINVAL if the argument @ps is
  188. * null; or 0 upon success.
  189. */
  190. int pwrdm_register_pwrdms(struct powerdomain **ps)
  191. {
  192. struct powerdomain **p = NULL;
  193. if (!arch_pwrdm)
  194. return -EEXIST;
  195. if (!ps)
  196. return -EINVAL;
  197. for (p = ps; *p; p++)
  198. _pwrdm_register(*p);
  199. return 0;
  200. }
  201. /**
  202. * pwrdm_complete_init - set up the powerdomain layer
  203. *
  204. * Do whatever is necessary to initialize registered powerdomains and
  205. * powerdomain code. Currently, this programs the next power state