Skip to content

Commit

Permalink
---
Browse files Browse the repository at this point in the history
yaml
---
r: 355615
b: refs/heads/master
c: c4978fb
h: refs/heads/master
i:
  355613: fc6b0c7
  355611: d0dfb30
  355607: 7d96653
  355599: 37d77a5
  355583: dfbc085
v: v3
  • Loading branch information
Paul Walmsley committed Jan 29, 2013
1 parent 71444c5 commit 1030354
Show file tree
Hide file tree
Showing 5 changed files with 145 additions and 93 deletions.
2 changes: 1 addition & 1 deletion [refs]
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
---
refs/heads/master: f8457c2d8be94779c8c460060e536d3a2a02c8d8
refs/heads/master: c4978fba6b2d4e3a584d72c067a371871fecbedc
61 changes: 0 additions & 61 deletions trunk/arch/arm/mach-omap2/pm.c
Original file line number Diff line number Diff line change
Expand Up @@ -108,10 +108,6 @@ static void __init omap2_init_processor_devices(void)
}
}

/* Types of sleep_switch used in omap_set_pwrdm_state */
#define FORCEWAKEUP_SWITCH 0
#define LOWPOWERSTATE_SWITCH 1

int __init omap_pm_clkdms_setup(struct clockdomain *clkdm, void *unused)
{
if ((clkdm->flags & CLKDM_CAN_ENABLE_AUTO) &&
Expand All @@ -123,63 +119,6 @@ int __init omap_pm_clkdms_setup(struct clockdomain *clkdm, void *unused)
return 0;
}

/*
* This sets pwrdm state (other than mpu & core. Currently only ON &
* RET are supported.
*/
int omap_set_pwrdm_state(struct powerdomain *pwrdm, u32 pwrst)
{
u8 curr_pwrst, next_pwrst;
int sleep_switch = -1, ret = 0, hwsup = 0;

if (!pwrdm || IS_ERR(pwrdm))
return -EINVAL;

while (!(pwrdm->pwrsts & (1 << pwrst))) {
if (pwrst == PWRDM_POWER_OFF)
return ret;
pwrst--;
}

next_pwrst = pwrdm_read_next_pwrst(pwrdm);
if (next_pwrst == pwrst)
return ret;

curr_pwrst = pwrdm_read_pwrst(pwrdm);
if (curr_pwrst < PWRDM_POWER_ON) {
if ((curr_pwrst > pwrst) &&
(pwrdm->flags & PWRDM_HAS_LOWPOWERSTATECHANGE)) {
sleep_switch = LOWPOWERSTATE_SWITCH;
} else {
hwsup = clkdm_in_hwsup(pwrdm->pwrdm_clkdms[0]);
clkdm_wakeup(pwrdm->pwrdm_clkdms[0]);
sleep_switch = FORCEWAKEUP_SWITCH;
}
}

ret = pwrdm_set_next_pwrst(pwrdm, pwrst);
if (ret)
pr_err("%s: unable to set power state of powerdomain: %s\n",
__func__, pwrdm->name);

switch (sleep_switch) {
case FORCEWAKEUP_SWITCH:
if (hwsup)
clkdm_allow_idle(pwrdm->pwrdm_clkdms[0]);
else
clkdm_sleep(pwrdm->pwrdm_clkdms[0]);
break;
case LOWPOWERSTATE_SWITCH:
pwrdm_set_lowpwrstchange(pwrdm);
pwrdm_state_switch(pwrdm);
break;
}

return ret;
}



/*
* This API is to be called during init to set the various voltage
* domains to the voltage as per the opp table. Typically we boot up
Expand Down
1 change: 0 additions & 1 deletion trunk/arch/arm/mach-omap2/pm.h
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,6 @@ static inline int omap4_idle_init(void)
extern void *omap3_secure_ram_storage;
extern void omap3_pm_off_mode_enable(int);
extern void omap_sram_idle(void);
extern int omap_set_pwrdm_state(struct powerdomain *pwrdm, u32 state);
extern int omap_pm_clkdms_setup(struct clockdomain *clkdm, void *unused);
extern int (*omap_pm_suspend)(void);

Expand Down
161 changes: 132 additions & 29 deletions trunk/arch/arm/mach-omap2/powerdomain.c
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,16 @@ enum {
PWRDM_STATE_PREV,
};

/*
* Types of sleep_switch used internally in omap_set_pwrdm_state()
* and its associated static functions
*
* XXX Better documentation is needed here
*/
#define ALREADYACTIVE_SWITCH 0
#define FORCEWAKEUP_SWITCH 1
#define LOWPOWERSTATE_SWITCH 2
#define ERROR_SWITCH 3

/* pwrdm_list contains all registered struct powerdomains */
static LIST_HEAD(pwrdm_list);
Expand Down Expand Up @@ -200,6 +210,80 @@ static int _pwrdm_post_transition_cb(struct powerdomain *pwrdm, void *unused)
return 0;
}

/**
* _pwrdm_save_clkdm_state_and_activate - prepare for power state change
* @pwrdm: struct powerdomain * to operate on
* @curr_pwrst: current power state of @pwrdm
* @pwrst: power state to switch to
* @hwsup: ptr to a bool to return whether the clkdm is hardware-supervised
*
* Determine whether the powerdomain needs to be turned on before
* attempting to switch power states. Called by
* omap_set_pwrdm_state(). NOTE that if the powerdomain contains
* multiple clockdomains, this code assumes that the first clockdomain
* supports software-supervised wakeup mode - potentially a problem.
* Returns the power state switch mode currently in use (see the
* "Types of sleep_switch" comment above).
*/
static u8 _pwrdm_save_clkdm_state_and_activate(struct powerdomain *pwrdm,
u8 curr_pwrst, u8 pwrst,
bool *hwsup)
{
u8 sleep_switch;

if (curr_pwrst < 0) {
WARN_ON(1);
sleep_switch = ERROR_SWITCH;
} else if (curr_pwrst < PWRDM_POWER_ON) {
if (curr_pwrst > pwrst &&
pwrdm->flags & PWRDM_HAS_LOWPOWERSTATECHANGE &&
arch_pwrdm->pwrdm_set_lowpwrstchange) {
sleep_switch = LOWPOWERSTATE_SWITCH;
} else {
*hwsup = clkdm_in_hwsup(pwrdm->pwrdm_clkdms[0]);
clkdm_wakeup(pwrdm->pwrdm_clkdms[0]);
sleep_switch = FORCEWAKEUP_SWITCH;
}
} else {
sleep_switch = ALREADYACTIVE_SWITCH;
}

return sleep_switch;
}

/**
* _pwrdm_restore_clkdm_state - restore the clkdm hwsup state after pwrst change
* @pwrdm: struct powerdomain * to operate on
* @sleep_switch: return value from _pwrdm_save_clkdm_state_and_activate()
* @hwsup: should @pwrdm's first clockdomain be set to hardware-supervised mode?
*
* Restore the clockdomain state perturbed by
* _pwrdm_save_clkdm_state_and_activate(), and call the power state
* bookkeeping code. Called by omap_set_pwrdm_state(). NOTE that if
* the powerdomain contains multiple clockdomains, this assumes that
* the first associated clockdomain supports either
* hardware-supervised idle control in the register, or
* software-supervised sleep. No return value.
*/
static void _pwrdm_restore_clkdm_state(struct powerdomain *pwrdm,
u8 sleep_switch, bool hwsup)
{
switch (sleep_switch) {
case FORCEWAKEUP_SWITCH:
if (hwsup)
clkdm_allow_idle(pwrdm->pwrdm_clkdms[0]);
else
clkdm_sleep(pwrdm->pwrdm_clkdms[0]);
break;
case LOWPOWERSTATE_SWITCH:
if (pwrdm->flags & PWRDM_HAS_LOWPOWERSTATECHANGE &&
arch_pwrdm->pwrdm_set_lowpwrstchange)
arch_pwrdm->pwrdm_set_lowpwrstchange(pwrdm);
pwrdm_state_switch(pwrdm);
break;
}
}

/* Public functions */

/**
Expand Down Expand Up @@ -921,35 +1005,6 @@ bool pwrdm_has_hdwr_sar(struct powerdomain *pwrdm)
return (pwrdm && pwrdm->flags & PWRDM_HAS_HDWR_SAR) ? 1 : 0;
}

/**
* pwrdm_set_lowpwrstchange - Request a low power state change
* @pwrdm: struct powerdomain *
*
* Allows a powerdomain to transtion to a lower power sleep state
* from an existing sleep state without waking up the powerdomain.
* Returns -EINVAL if the powerdomain pointer is null or if the
* powerdomain does not support LOWPOWERSTATECHANGE, or returns 0
* upon success.
*/
int pwrdm_set_lowpwrstchange(struct powerdomain *pwrdm)
{
int ret = -EINVAL;

if (!pwrdm)
return -EINVAL;

if (!(pwrdm->flags & PWRDM_HAS_LOWPOWERSTATECHANGE))
return -EINVAL;

pr_debug("powerdomain: %s: setting LOWPOWERSTATECHANGE bit\n",
pwrdm->name);

if (arch_pwrdm && arch_pwrdm->pwrdm_set_lowpwrstchange)
ret = arch_pwrdm->pwrdm_set_lowpwrstchange(pwrdm);

return ret;
}

int pwrdm_state_switch(struct powerdomain *pwrdm)
{
int ret;
Expand Down Expand Up @@ -984,6 +1039,54 @@ int pwrdm_post_transition(struct powerdomain *pwrdm)
return 0;
}

/**
* omap_set_pwrdm_state - change a powerdomain's current power state
* @pwrdm: struct powerdomain * to change the power state of
* @pwrst: power state to change to
*
* Change the current hardware power state of the powerdomain
* represented by @pwrdm to the power state represented by @pwrst.
* Returns -EINVAL if @pwrdm is null or invalid or if the
* powerdomain's current power state could not be read, or returns 0
* upon success or if @pwrdm does not support @pwrst or any
* lower-power state. XXX Should not return 0 if the @pwrdm does not
* support @pwrst or any lower-power state: this should be an error.
*/
int omap_set_pwrdm_state(struct powerdomain *pwrdm, u8 pwrst)
{
u8 curr_pwrst, next_pwrst, sleep_switch;
int ret = 0;
bool hwsup = false;

if (!pwrdm || IS_ERR(pwrdm))
return -EINVAL;

while (!(pwrdm->pwrsts & (1 << pwrst))) {
if (pwrst == PWRDM_POWER_OFF)
return ret;
pwrst--;
}

curr_pwrst = pwrdm_read_pwrst(pwrdm);
next_pwrst = pwrdm_read_next_pwrst(pwrdm);
if (curr_pwrst == pwrst && next_pwrst == pwrst)
return ret;

sleep_switch = _pwrdm_save_clkdm_state_and_activate(pwrdm, curr_pwrst,
pwrst, &hwsup);
if (sleep_switch == ERROR_SWITCH)
return -EINVAL;

ret = pwrdm_set_next_pwrst(pwrdm, pwrst);
if (ret)
pr_err("%s: unable to set power state of powerdomain: %s\n",
__func__, pwrdm->name);

_pwrdm_restore_clkdm_state(pwrdm, sleep_switch, hwsup);

return ret;
}

/**
* pwrdm_get_context_loss_count - get powerdomain's context loss count
* @pwrdm: struct powerdomain * to wait for
Expand Down
13 changes: 12 additions & 1 deletion trunk/arch/arm/mach-omap2/powerdomain.h
Original file line number Diff line number Diff line change
Expand Up @@ -162,6 +162,16 @@ struct powerdomain {
* @pwrdm_disable_hdwr_sar: Disable Hardware Save-Restore feature for a pd
* @pwrdm_set_lowpwrstchange: Enable pd transitions from a shallow to deep sleep
* @pwrdm_wait_transition: Wait for a pd state transition to complete
*
* Regarding @pwrdm_set_lowpwrstchange: On the OMAP2 and 3-family
* chips, a powerdomain's power state is not allowed to directly
* transition from one low-power state (e.g., CSWR) to another
* low-power state (e.g., OFF) without first waking up the
* powerdomain. This wastes energy. So OMAP4 chips support the
* ability to transition a powerdomain power state directly from one
* low-power state to another. The function pointed to by
* @pwrdm_set_lowpwrstchange is intended to configure the OMAP4
* hardware powerdomain state machine to enable this feature.
*/
struct pwrdm_ops {
int (*pwrdm_set_next_pwrst)(struct powerdomain *pwrdm, u8 pwrst);
Expand Down Expand Up @@ -228,10 +238,11 @@ bool pwrdm_has_hdwr_sar(struct powerdomain *pwrdm);
int pwrdm_state_switch(struct powerdomain *pwrdm);
int pwrdm_pre_transition(struct powerdomain *pwrdm);
int pwrdm_post_transition(struct powerdomain *pwrdm);
int pwrdm_set_lowpwrstchange(struct powerdomain *pwrdm);
int pwrdm_get_context_loss_count(struct powerdomain *pwrdm);
bool pwrdm_can_ever_lose_context(struct powerdomain *pwrdm);

extern int omap_set_pwrdm_state(struct powerdomain *pwrdm, u8 state);

extern void omap242x_powerdomains_init(void);
extern void omap243x_powerdomains_init(void);
extern void omap3xxx_powerdomains_init(void);
Expand Down

0 comments on commit 1030354

Please sign in to comment.