aboutsummaryrefslogtreecommitdiffstats
path: root/arch/arm/mach-omap2/powerdomain.c
diff options
context:
space:
mode:
authorPaul Walmsley <paul@pwsan.com>2013-01-29 15:45:09 -0500
committerPaul Walmsley <paul@pwsan.com>2013-01-29 16:59:57 -0500
commitc4978fba6b2d4e3a584d72c067a371871fecbedc (patch)
tree75add16022eb4e71ae50e1aecb42d1d5a9f420ab /arch/arm/mach-omap2/powerdomain.c
parentf8457c2d8be94779c8c460060e536d3a2a02c8d8 (diff)
ARM: OMAP2+: PM/powerdomain: move omap_set_pwrdm_state() to powerdomain code
Move omap_set_pwrdm_state() from the PM code to the powerdomain code, and refactor it to split it up into several functions. A subsequent patch will rename it to conform with the existing powerdomain function names. This version includes some additional documentation, based on a suggestion from Jean Pihet. It also modifies omap_set_pwrdm_state() to not bail out early unless both the powerdomain current power state and the next power state are equal. (Previously it would terminate early if the next power state was equal to the target power state, which was insufficiently rigorous.) Signed-off-by: Paul Walmsley <paul@pwsan.com> Cc: Jean Pihet <jean.pihet@newoldbits.com> Cc: Kevin Hilman <khilman@deeprootsystems.com> Cc: Tero Kristo <t-kristo@ti.com>
Diffstat (limited to 'arch/arm/mach-omap2/powerdomain.c')
-rw-r--r--arch/arm/mach-omap2/powerdomain.c161
1 files changed, 132 insertions, 29 deletions
diff --git a/arch/arm/mach-omap2/powerdomain.c b/arch/arm/mach-omap2/powerdomain.c
index 97b3881dd60d..65c34645c8ed 100644
--- a/arch/arm/mach-omap2/powerdomain.c
+++ b/arch/arm/mach-omap2/powerdomain.c
@@ -42,6 +42,16 @@ enum {
42 PWRDM_STATE_PREV, 42 PWRDM_STATE_PREV,
43}; 43};
44 44
45/*
46 * Types of sleep_switch used internally in omap_set_pwrdm_state()
47 * and its associated static functions
48 *
49 * XXX Better documentation is needed here
50 */
51#define ALREADYACTIVE_SWITCH 0
52#define FORCEWAKEUP_SWITCH 1
53#define LOWPOWERSTATE_SWITCH 2
54#define ERROR_SWITCH 3
45 55
46/* pwrdm_list contains all registered struct powerdomains */ 56/* pwrdm_list contains all registered struct powerdomains */
47static LIST_HEAD(pwrdm_list); 57static LIST_HEAD(pwrdm_list);
@@ -200,6 +210,80 @@ static int _pwrdm_post_transition_cb(struct powerdomain *pwrdm, void *unused)
200 return 0; 210 return 0;
201} 211}
202 212
213/**
214 * _pwrdm_save_clkdm_state_and_activate - prepare for power state change
215 * @pwrdm: struct powerdomain * to operate on
216 * @curr_pwrst: current power state of @pwrdm
217 * @pwrst: power state to switch to
218 * @hwsup: ptr to a bool to return whether the clkdm is hardware-supervised
219 *
220 * Determine whether the powerdomain needs to be turned on before
221 * attempting to switch power states. Called by
222 * omap_set_pwrdm_state(). NOTE that if the powerdomain contains
223 * multiple clockdomains, this code assumes that the first clockdomain
224 * supports software-supervised wakeup mode - potentially a problem.
225 * Returns the power state switch mode currently in use (see the
226 * "Types of sleep_switch" comment above).
227 */
228static u8 _pwrdm_save_clkdm_state_and_activate(struct powerdomain *pwrdm,
229 u8 curr_pwrst, u8 pwrst,
230 bool *hwsup)
231{
232 u8 sleep_switch;
233
234 if (curr_pwrst < 0) {
235 WARN_ON(1);
236 sleep_switch = ERROR_SWITCH;
237 } else if (curr_pwrst < PWRDM_POWER_ON) {
238 if (curr_pwrst > pwrst &&
239 pwrdm->flags & PWRDM_HAS_LOWPOWERSTATECHANGE &&
240 arch_pwrdm->pwrdm_set_lowpwrstchange) {
241 sleep_switch = LOWPOWERSTATE_SWITCH;
242 } else {
243 *hwsup = clkdm_in_hwsup(pwrdm->pwrdm_clkdms[0]);
244 clkdm_wakeup(pwrdm->pwrdm_clkdms[0]);
245 sleep_switch = FORCEWAKEUP_SWITCH;
246 }
247 } else {
248 sleep_switch = ALREADYACTIVE_SWITCH;
249 }
250
251 return sleep_switch;
252}
253
254/**
255 * _pwrdm_restore_clkdm_state - restore the clkdm hwsup state after pwrst change
256 * @pwrdm: struct powerdomain * to operate on
257 * @sleep_switch: return value from _pwrdm_save_clkdm_state_and_activate()
258 * @hwsup: should @pwrdm's first clockdomain be set to hardware-supervised mode?
259 *
260 * Restore the clockdomain state perturbed by
261 * _pwrdm_save_clkdm_state_and_activate(), and call the power state
262 * bookkeeping code. Called by omap_set_pwrdm_state(). NOTE that if
263 * the powerdomain contains multiple clockdomains, this assumes that
264 * the first associated clockdomain supports either
265 * hardware-supervised idle control in the register, or
266 * software-supervised sleep. No return value.
267 */
268static void _pwrdm_restore_clkdm_state(struct powerdomain *pwrdm,
269 u8 sleep_switch, bool hwsup)
270{
271 switch (sleep_switch) {
272 case FORCEWAKEUP_SWITCH:
273 if (hwsup)
274 clkdm_allow_idle(pwrdm->pwrdm_clkdms[0]);
275 else
276 clkdm_sleep(pwrdm->pwrdm_clkdms[0]);
277 break;
278 case LOWPOWERSTATE_SWITCH:
279 if (pwrdm->flags & PWRDM_HAS_LOWPOWERSTATECHANGE &&
280 arch_pwrdm->pwrdm_set_lowpwrstchange)
281 arch_pwrdm->pwrdm_set_lowpwrstchange(pwrdm);
282 pwrdm_state_switch(pwrdm);
283 break;
284 }
285}
286
203/* Public functions */ 287/* Public functions */
204 288
205/** 289/**
@@ -921,35 +1005,6 @@ bool pwrdm_has_hdwr_sar(struct powerdomain *pwrdm)
921 return (pwrdm && pwrdm->flags & PWRDM_HAS_HDWR_SAR) ? 1 : 0; 1005 return (pwrdm && pwrdm->flags & PWRDM_HAS_HDWR_SAR) ? 1 : 0;
922} 1006}
923 1007
924/**
925 * pwrdm_set_lowpwrstchange - Request a low power state change
926 * @pwrdm: struct powerdomain *
927 *
928 * Allows a powerdomain to transtion to a lower power sleep state
929 * from an existing sleep state without waking up the powerdomain.
930 * Returns -EINVAL if the powerdomain pointer is null or if the
931 * powerdomain does not support LOWPOWERSTATECHANGE, or returns 0
932 * upon success.
933 */
934int pwrdm_set_lowpwrstchange(struct powerdomain *pwrdm)
935{
936 int ret = -EINVAL;
937
938 if (!pwrdm)
939 return -EINVAL;
940
941 if (!(pwrdm->flags & PWRDM_HAS_LOWPOWERSTATECHANGE))
942 return -EINVAL;
943
944 pr_debug("powerdomain: %s: setting LOWPOWERSTATECHANGE bit\n",
945 pwrdm->name);
946
947 if (arch_pwrdm && arch_pwrdm->pwrdm_set_lowpwrstchange)
948 ret = arch_pwrdm->pwrdm_set_lowpwrstchange(pwrdm);
949
950 return ret;
951}
952
953int pwrdm_state_switch(struct powerdomain *pwrdm) 1008int pwrdm_state_switch(struct powerdomain *pwrdm)
954{ 1009{
955 int ret; 1010 int ret;
@@ -985,6 +1040,54 @@ int pwrdm_post_transition(struct powerdomain *pwrdm)
985} 1040}
986 1041
987/** 1042/**
1043 * omap_set_pwrdm_state - change a powerdomain's current power state
1044 * @pwrdm: struct powerdomain * to change the power state of
1045 * @pwrst: power state to change to
1046 *
1047 * Change the current hardware power state of the powerdomain
1048 * represented by @pwrdm to the power state represented by @pwrst.
1049 * Returns -EINVAL if @pwrdm is null or invalid or if the
1050 * powerdomain's current power state could not be read, or returns 0
1051 * upon success or if @pwrdm does not support @pwrst or any
1052 * lower-power state. XXX Should not return 0 if the @pwrdm does not
1053 * support @pwrst or any lower-power state: this should be an error.
1054 */
1055int omap_set_pwrdm_state(struct powerdomain *pwrdm, u8 pwrst)
1056{
1057 u8 curr_pwrst, next_pwrst, sleep_switch;
1058 int ret = 0;
1059 bool hwsup = false;
1060
1061 if (!pwrdm || IS_ERR(pwrdm))
1062 return -EINVAL;
1063
1064 while (!(pwrdm->pwrsts & (1 << pwrst))) {
1065 if (pwrst == PWRDM_POWER_OFF)
1066 return ret;
1067 pwrst--;
1068 }
1069
1070 curr_pwrst = pwrdm_read_pwrst(pwrdm);
1071 next_pwrst = pwrdm_read_next_pwrst(pwrdm);
1072 if (curr_pwrst == pwrst && next_pwrst == pwrst)
1073 return ret;
1074
1075 sleep_switch = _pwrdm_save_clkdm_state_and_activate(pwrdm, curr_pwrst,
1076 pwrst, &hwsup);
1077 if (sleep_switch == ERROR_SWITCH)
1078 return -EINVAL;
1079
1080 ret = pwrdm_set_next_pwrst(pwrdm, pwrst);
1081 if (ret)
1082 pr_err("%s: unable to set power state of powerdomain: %s\n",
1083 __func__, pwrdm->name);
1084
1085 _pwrdm_restore_clkdm_state(pwrdm, sleep_switch, hwsup);
1086
1087 return ret;
1088}
1089
1090/**
988 * pwrdm_get_context_loss_count - get powerdomain's context loss count 1091 * pwrdm_get_context_loss_count - get powerdomain's context loss count
989 * @pwrdm: struct powerdomain * to wait for 1092 * @pwrdm: struct powerdomain * to wait for
990 * 1093 *