MLK-17074-1 PM / Domains: support enter deepest state for multiple states domains
Currently the generic power domain suspend code pm_genpd_suspend_noirq will try to power off a domain used by devices in genpd_sync_poweroff if its status is not GPD_STATE_ACTIVE. However, for power domains supporting multiple low power states, it may already enter an intermediate low power state by runtime PM before system suspend and the status is already GPD_STATE_POWER_OFF which results in then the power domain stay at an intermediate low power state during system suspend. Let's give the power domain a chance to switch to the deepest state in case it's already off but in an intermediate low power state. Due to power domain is alway off, so no need to check device wakeup case anymore. Reviewed-by: Frank Li <frank.li@nxp.com> Reviewed-by: Ranjani Vaidyanathan <Ranjani.Vaidyanathan@nxp.com> Signed-off-by: Dong Aisheng <aisheng.dong@nxp.com>
This commit is contained in:
@ -247,6 +247,9 @@ static int _genpd_power_on(struct generic_pm_domain *genpd, bool timed)
|
||||
if (!genpd->power_on)
|
||||
return 0;
|
||||
|
||||
pr_debug("%s: Power-%s (idle state %d timed %s)\n", genpd->name, "on",
|
||||
state_idx, timed ? "true" : "false");
|
||||
|
||||
if (!timed)
|
||||
return genpd->power_on(genpd);
|
||||
|
||||
@ -277,6 +280,9 @@ static int _genpd_power_off(struct generic_pm_domain *genpd, bool timed)
|
||||
if (!genpd->power_off)
|
||||
return 0;
|
||||
|
||||
pr_debug("%s: Power-%s (idle state %d timed %s)\n", genpd->name, "off",
|
||||
state_idx, timed ? "true" : "false");
|
||||
|
||||
if (!timed)
|
||||
return genpd->power_off(genpd);
|
||||
|
||||
@ -795,7 +801,20 @@ static void genpd_sync_power_off(struct generic_pm_domain *genpd, bool use_lock,
|
||||
{
|
||||
struct gpd_link *link;
|
||||
|
||||
if (!genpd_status_on(genpd) || genpd_is_always_on(genpd))
|
||||
/*
|
||||
* Give the power domain a chance to switch to the deepest state in
|
||||
* case it's already off but in an intermediate low power state.
|
||||
* Due to power domain is alway off, so no need to check device wakeup
|
||||
* here anymore
|
||||
*/
|
||||
|
||||
genpd->state_idx_saved = genpd->state_idx;
|
||||
|
||||
if (genpd_is_always_on(genpd))
|
||||
return;
|
||||
|
||||
if (!genpd_status_on(genpd) &&
|
||||
genpd->state_idx == (genpd->state_count - 1))
|
||||
return;
|
||||
|
||||
if (genpd->suspended_count != genpd->device_count
|
||||
@ -807,6 +826,9 @@ static void genpd_sync_power_off(struct generic_pm_domain *genpd, bool use_lock,
|
||||
if (_genpd_power_off(genpd, false))
|
||||
return;
|
||||
|
||||
if (genpd->status == GPD_STATE_POWER_OFF)
|
||||
return;
|
||||
|
||||
genpd->status = GPD_STATE_POWER_OFF;
|
||||
|
||||
list_for_each_entry(link, &genpd->slave_links, slave_node) {
|
||||
@ -854,6 +876,8 @@ static void genpd_sync_power_on(struct generic_pm_domain *genpd, bool use_lock,
|
||||
|
||||
_genpd_power_on(genpd, false);
|
||||
|
||||
/* restore save power domain state after resume */
|
||||
genpd->state_idx = genpd->state_idx_saved;
|
||||
genpd->status = GPD_STATE_ACTIVE;
|
||||
}
|
||||
|
||||
|
||||
@ -90,6 +90,7 @@ struct generic_pm_domain {
|
||||
};
|
||||
};
|
||||
|
||||
unsigned int state_idx_saved; /* saved power state for recovery after system suspend/resume */
|
||||
};
|
||||
|
||||
static inline struct generic_pm_domain *pd_to_genpd(struct dev_pm_domain *pd)
|
||||
|
||||
Reference in New Issue
Block a user