Merge branch 'pm-domains'
* pm-domains: PM / Domains: Rename pm_genpd_sync_poweron|poweroff() PM / Domains: Don't measure latency of ->power_on|off() during system PM PM / Domains: Remove redundant system PM callbacks PM / Domains: Simplify detaching a device from its genpd PM / Domains: Allow holes in genpd_data.domains array PM / Domains: Add support for removing nested PM domains by provider PM / Domains: Add support for removing PM domains PM / Domains: Store the provider in the PM domain structure PM / Domains: Prepare for adding support to remove PM domains PM / Domains: Verify the PM domain is present when adding a provider PM / Domains: Don't expose xlate and provider helper functions PM / Domains: Don't expose generic_pm_domain structure to clients staging: board: Remove calls to of_genpd_get_from_provider() ARM: EXYNOS: Remove calls to of_genpd_get_from_provider() PM / Domains: Add new helper functions for device-tree PM / Domains: Always enable debugfs support if available
This commit is contained in:
commit
2dc3c72cd0
|
@ -45,7 +45,7 @@ static DEFINE_MUTEX(gpd_list_lock);
|
|||
* and checks that the PM domain pointer is a real generic PM domain.
|
||||
* Any failure results in NULL being returned.
|
||||
*/
|
||||
struct generic_pm_domain *pm_genpd_lookup_dev(struct device *dev)
|
||||
static struct generic_pm_domain *genpd_lookup_dev(struct device *dev)
|
||||
{
|
||||
struct generic_pm_domain *genpd = NULL, *gpd;
|
||||
|
||||
|
@ -586,7 +586,7 @@ static int __init genpd_poweroff_unused(void)
|
|||
}
|
||||
late_initcall(genpd_poweroff_unused);
|
||||
|
||||
#ifdef CONFIG_PM_SLEEP
|
||||
#if defined(CONFIG_PM_SLEEP) || defined(CONFIG_PM_GENERIC_DOMAINS_OF)
|
||||
|
||||
/**
|
||||
* pm_genpd_present - Check if the given PM domain has been initialized.
|
||||
|
@ -606,6 +606,10 @@ static bool pm_genpd_present(const struct generic_pm_domain *genpd)
|
|||
return false;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_PM_SLEEP
|
||||
|
||||
static bool genpd_dev_active_wakeup(struct generic_pm_domain *genpd,
|
||||
struct device *dev)
|
||||
{
|
||||
|
@ -613,9 +617,8 @@ static bool genpd_dev_active_wakeup(struct generic_pm_domain *genpd,
|
|||
}
|
||||
|
||||
/**
|
||||
* pm_genpd_sync_poweroff - Synchronously power off a PM domain and its masters.
|
||||
* genpd_sync_poweroff - Synchronously power off a PM domain and its masters.
|
||||
* @genpd: PM domain to power off, if possible.
|
||||
* @timed: True if latency measurements are allowed.
|
||||
*
|
||||
* Check if the given PM domain can be powered off (during system suspend or
|
||||
* hibernation) and do that if so. Also, in that case propagate to its masters.
|
||||
|
@ -625,8 +628,7 @@ static bool genpd_dev_active_wakeup(struct generic_pm_domain *genpd,
|
|||
* executed sequentially, so it is guaranteed that it will never run twice in
|
||||
* parallel).
|
||||
*/
|
||||
static void pm_genpd_sync_poweroff(struct generic_pm_domain *genpd,
|
||||
bool timed)
|
||||
static void genpd_sync_poweroff(struct generic_pm_domain *genpd)
|
||||
{
|
||||
struct gpd_link *link;
|
||||
|
||||
|
@ -639,28 +641,26 @@ static void pm_genpd_sync_poweroff(struct generic_pm_domain *genpd,
|
|||
|
||||
/* Choose the deepest state when suspending */
|
||||
genpd->state_idx = genpd->state_count - 1;
|
||||
genpd_power_off(genpd, timed);
|
||||
genpd_power_off(genpd, false);
|
||||
|
||||
genpd->status = GPD_STATE_POWER_OFF;
|
||||
|
||||
list_for_each_entry(link, &genpd->slave_links, slave_node) {
|
||||
genpd_sd_counter_dec(link->master);
|
||||
pm_genpd_sync_poweroff(link->master, timed);
|
||||
genpd_sync_poweroff(link->master);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* pm_genpd_sync_poweron - Synchronously power on a PM domain and its masters.
|
||||
* genpd_sync_poweron - Synchronously power on a PM domain and its masters.
|
||||
* @genpd: PM domain to power on.
|
||||
* @timed: True if latency measurements are allowed.
|
||||
*
|
||||
* This function is only called in "noirq" and "syscore" stages of system power
|
||||
* transitions, so it need not acquire locks (all of the "noirq" callbacks are
|
||||
* executed sequentially, so it is guaranteed that it will never run twice in
|
||||
* parallel).
|
||||
*/
|
||||
static void pm_genpd_sync_poweron(struct generic_pm_domain *genpd,
|
||||
bool timed)
|
||||
static void genpd_sync_poweron(struct generic_pm_domain *genpd)
|
||||
{
|
||||
struct gpd_link *link;
|
||||
|
||||
|
@ -668,11 +668,11 @@ static void pm_genpd_sync_poweron(struct generic_pm_domain *genpd,
|
|||
return;
|
||||
|
||||
list_for_each_entry(link, &genpd->slave_links, slave_node) {
|
||||
pm_genpd_sync_poweron(link->master, timed);
|
||||
genpd_sync_poweron(link->master);
|
||||
genpd_sd_counter_inc(link->master);
|
||||
}
|
||||
|
||||
genpd_power_on(genpd, timed);
|
||||
genpd_power_on(genpd, false);
|
||||
|
||||
genpd->status = GPD_STATE_ACTIVE;
|
||||
}
|
||||
|
@ -784,7 +784,7 @@ static int pm_genpd_suspend_noirq(struct device *dev)
|
|||
* the same PM domain, so it is not necessary to use locking here.
|
||||
*/
|
||||
genpd->suspended_count++;
|
||||
pm_genpd_sync_poweroff(genpd, true);
|
||||
genpd_sync_poweroff(genpd);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -814,7 +814,7 @@ static int pm_genpd_resume_noirq(struct device *dev)
|
|||
* guaranteed that this function will never run twice in parallel for
|
||||
* the same PM domain, so it is not necessary to use locking here.
|
||||
*/
|
||||
pm_genpd_sync_poweron(genpd, true);
|
||||
genpd_sync_poweron(genpd);
|
||||
genpd->suspended_count--;
|
||||
|
||||
if (genpd->dev_ops.stop && genpd->dev_ops.start)
|
||||
|
@ -902,12 +902,12 @@ static int pm_genpd_restore_noirq(struct device *dev)
|
|||
if (genpd->suspended_count++ == 0)
|
||||
/*
|
||||
* The boot kernel might put the domain into arbitrary state,
|
||||
* so make it appear as powered off to pm_genpd_sync_poweron(),
|
||||
* so make it appear as powered off to genpd_sync_poweron(),
|
||||
* so that it tries to power it on in case it was really off.
|
||||
*/
|
||||
genpd->status = GPD_STATE_POWER_OFF;
|
||||
|
||||
pm_genpd_sync_poweron(genpd, true);
|
||||
genpd_sync_poweron(genpd);
|
||||
|
||||
if (genpd->dev_ops.stop && genpd->dev_ops.start)
|
||||
ret = pm_runtime_force_resume(dev);
|
||||
|
@ -962,9 +962,9 @@ static void genpd_syscore_switch(struct device *dev, bool suspend)
|
|||
|
||||
if (suspend) {
|
||||
genpd->suspended_count++;
|
||||
pm_genpd_sync_poweroff(genpd, false);
|
||||
genpd_sync_poweroff(genpd);
|
||||
} else {
|
||||
pm_genpd_sync_poweron(genpd, false);
|
||||
genpd_sync_poweron(genpd);
|
||||
genpd->suspended_count--;
|
||||
}
|
||||
}
|
||||
|
@ -1056,14 +1056,8 @@ static void genpd_free_dev_data(struct device *dev,
|
|||
dev_pm_put_subsys_data(dev);
|
||||
}
|
||||
|
||||
/**
|
||||
* __pm_genpd_add_device - Add a device to an I/O PM domain.
|
||||
* @genpd: PM domain to add the device to.
|
||||
* @dev: Device to be added.
|
||||
* @td: Set of PM QoS timing parameters to attach to the device.
|
||||
*/
|
||||
int __pm_genpd_add_device(struct generic_pm_domain *genpd, struct device *dev,
|
||||
struct gpd_timing_data *td)
|
||||
static int genpd_add_device(struct generic_pm_domain *genpd, struct device *dev,
|
||||
struct gpd_timing_data *td)
|
||||
{
|
||||
struct generic_pm_domain_data *gpd_data;
|
||||
int ret = 0;
|
||||
|
@ -1103,15 +1097,28 @@ int __pm_genpd_add_device(struct generic_pm_domain *genpd, struct device *dev,
|
|||
|
||||
return ret;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(__pm_genpd_add_device);
|
||||
|
||||
/**
|
||||
* pm_genpd_remove_device - Remove a device from an I/O PM domain.
|
||||
* @genpd: PM domain to remove the device from.
|
||||
* @dev: Device to be removed.
|
||||
* __pm_genpd_add_device - Add a device to an I/O PM domain.
|
||||
* @genpd: PM domain to add the device to.
|
||||
* @dev: Device to be added.
|
||||
* @td: Set of PM QoS timing parameters to attach to the device.
|
||||
*/
|
||||
int pm_genpd_remove_device(struct generic_pm_domain *genpd,
|
||||
struct device *dev)
|
||||
int __pm_genpd_add_device(struct generic_pm_domain *genpd, struct device *dev,
|
||||
struct gpd_timing_data *td)
|
||||
{
|
||||
int ret;
|
||||
|
||||
mutex_lock(&gpd_list_lock);
|
||||
ret = genpd_add_device(genpd, dev, td);
|
||||
mutex_unlock(&gpd_list_lock);
|
||||
|
||||
return ret;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(__pm_genpd_add_device);
|
||||
|
||||
static int genpd_remove_device(struct generic_pm_domain *genpd,
|
||||
struct device *dev)
|
||||
{
|
||||
struct generic_pm_domain_data *gpd_data;
|
||||
struct pm_domain_data *pdd;
|
||||
|
@ -1119,10 +1126,6 @@ int pm_genpd_remove_device(struct generic_pm_domain *genpd,
|
|||
|
||||
dev_dbg(dev, "%s()\n", __func__);
|
||||
|
||||
if (!genpd || genpd != pm_genpd_lookup_dev(dev))
|
||||
return -EINVAL;
|
||||
|
||||
/* The above validation also means we have existing domain_data. */
|
||||
pdd = dev->power.subsys_data->domain_data;
|
||||
gpd_data = to_gpd_data(pdd);
|
||||
dev_pm_qos_remove_notifier(dev, &gpd_data->nb);
|
||||
|
@ -1154,15 +1157,24 @@ int pm_genpd_remove_device(struct generic_pm_domain *genpd,
|
|||
|
||||
return ret;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(pm_genpd_remove_device);
|
||||
|
||||
/**
|
||||
* pm_genpd_add_subdomain - Add a subdomain to an I/O PM domain.
|
||||
* @genpd: Master PM domain to add the subdomain to.
|
||||
* @subdomain: Subdomain to be added.
|
||||
* pm_genpd_remove_device - Remove a device from an I/O PM domain.
|
||||
* @genpd: PM domain to remove the device from.
|
||||
* @dev: Device to be removed.
|
||||
*/
|
||||
int pm_genpd_add_subdomain(struct generic_pm_domain *genpd,
|
||||
struct generic_pm_domain *subdomain)
|
||||
int pm_genpd_remove_device(struct generic_pm_domain *genpd,
|
||||
struct device *dev)
|
||||
{
|
||||
if (!genpd || genpd != genpd_lookup_dev(dev))
|
||||
return -EINVAL;
|
||||
|
||||
return genpd_remove_device(genpd, dev);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(pm_genpd_remove_device);
|
||||
|
||||
static int genpd_add_subdomain(struct generic_pm_domain *genpd,
|
||||
struct generic_pm_domain *subdomain)
|
||||
{
|
||||
struct gpd_link *link, *itr;
|
||||
int ret = 0;
|
||||
|
@ -1205,6 +1217,23 @@ int pm_genpd_add_subdomain(struct generic_pm_domain *genpd,
|
|||
kfree(link);
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* pm_genpd_add_subdomain - Add a subdomain to an I/O PM domain.
|
||||
* @genpd: Master PM domain to add the subdomain to.
|
||||
* @subdomain: Subdomain to be added.
|
||||
*/
|
||||
int pm_genpd_add_subdomain(struct generic_pm_domain *genpd,
|
||||
struct generic_pm_domain *subdomain)
|
||||
{
|
||||
int ret;
|
||||
|
||||
mutex_lock(&gpd_list_lock);
|
||||
ret = genpd_add_subdomain(genpd, subdomain);
|
||||
mutex_unlock(&gpd_list_lock);
|
||||
|
||||
return ret;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(pm_genpd_add_subdomain);
|
||||
|
||||
/**
|
||||
|
@ -1278,27 +1307,17 @@ int pm_genpd_init(struct generic_pm_domain *genpd,
|
|||
genpd->device_count = 0;
|
||||
genpd->max_off_time_ns = -1;
|
||||
genpd->max_off_time_changed = true;
|
||||
genpd->provider = NULL;
|
||||
genpd->has_provider = false;
|
||||
genpd->domain.ops.runtime_suspend = genpd_runtime_suspend;
|
||||
genpd->domain.ops.runtime_resume = genpd_runtime_resume;
|
||||
genpd->domain.ops.prepare = pm_genpd_prepare;
|
||||
genpd->domain.ops.suspend = pm_generic_suspend;
|
||||
genpd->domain.ops.suspend_late = pm_generic_suspend_late;
|
||||
genpd->domain.ops.suspend_noirq = pm_genpd_suspend_noirq;
|
||||
genpd->domain.ops.resume_noirq = pm_genpd_resume_noirq;
|
||||
genpd->domain.ops.resume_early = pm_generic_resume_early;
|
||||
genpd->domain.ops.resume = pm_generic_resume;
|
||||
genpd->domain.ops.freeze = pm_generic_freeze;
|
||||
genpd->domain.ops.freeze_late = pm_generic_freeze_late;
|
||||
genpd->domain.ops.freeze_noirq = pm_genpd_freeze_noirq;
|
||||
genpd->domain.ops.thaw_noirq = pm_genpd_thaw_noirq;
|
||||
genpd->domain.ops.thaw_early = pm_generic_thaw_early;
|
||||
genpd->domain.ops.thaw = pm_generic_thaw;
|
||||
genpd->domain.ops.poweroff = pm_generic_poweroff;
|
||||
genpd->domain.ops.poweroff_late = pm_generic_poweroff_late;
|
||||
genpd->domain.ops.poweroff_noirq = pm_genpd_suspend_noirq;
|
||||
genpd->domain.ops.restore_noirq = pm_genpd_restore_noirq;
|
||||
genpd->domain.ops.restore_early = pm_generic_restore_early;
|
||||
genpd->domain.ops.restore = pm_generic_restore;
|
||||
genpd->domain.ops.complete = pm_genpd_complete;
|
||||
|
||||
if (genpd->flags & GENPD_FLAG_PM_CLK) {
|
||||
|
@ -1328,7 +1347,71 @@ int pm_genpd_init(struct generic_pm_domain *genpd,
|
|||
}
|
||||
EXPORT_SYMBOL_GPL(pm_genpd_init);
|
||||
|
||||
static int genpd_remove(struct generic_pm_domain *genpd)
|
||||
{
|
||||
struct gpd_link *l, *link;
|
||||
|
||||
if (IS_ERR_OR_NULL(genpd))
|
||||
return -EINVAL;
|
||||
|
||||
mutex_lock(&genpd->lock);
|
||||
|
||||
if (genpd->has_provider) {
|
||||
mutex_unlock(&genpd->lock);
|
||||
pr_err("Provider present, unable to remove %s\n", genpd->name);
|
||||
return -EBUSY;
|
||||
}
|
||||
|
||||
if (!list_empty(&genpd->master_links) || genpd->device_count) {
|
||||
mutex_unlock(&genpd->lock);
|
||||
pr_err("%s: unable to remove %s\n", __func__, genpd->name);
|
||||
return -EBUSY;
|
||||
}
|
||||
|
||||
list_for_each_entry_safe(link, l, &genpd->slave_links, slave_node) {
|
||||
list_del(&link->master_node);
|
||||
list_del(&link->slave_node);
|
||||
kfree(link);
|
||||
}
|
||||
|
||||
list_del(&genpd->gpd_list_node);
|
||||
mutex_unlock(&genpd->lock);
|
||||
cancel_work_sync(&genpd->power_off_work);
|
||||
pr_debug("%s: removed %s\n", __func__, genpd->name);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* pm_genpd_remove - Remove a generic I/O PM domain
|
||||
* @genpd: Pointer to PM domain that is to be removed.
|
||||
*
|
||||
* To remove the PM domain, this function:
|
||||
* - Removes the PM domain as a subdomain to any parent domains,
|
||||
* if it was added.
|
||||
* - Removes the PM domain from the list of registered PM domains.
|
||||
*
|
||||
* The PM domain will only be removed, if the associated provider has
|
||||
* been removed, it is not a parent to any other PM domain and has no
|
||||
* devices associated with it.
|
||||
*/
|
||||
int pm_genpd_remove(struct generic_pm_domain *genpd)
|
||||
{
|
||||
int ret;
|
||||
|
||||
mutex_lock(&gpd_list_lock);
|
||||
ret = genpd_remove(genpd);
|
||||
mutex_unlock(&gpd_list_lock);
|
||||
|
||||
return ret;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(pm_genpd_remove);
|
||||
|
||||
#ifdef CONFIG_PM_GENERIC_DOMAINS_OF
|
||||
|
||||
typedef struct generic_pm_domain *(*genpd_xlate_t)(struct of_phandle_args *args,
|
||||
void *data);
|
||||
|
||||
/*
|
||||
* Device Tree based PM domain providers.
|
||||
*
|
||||
|
@ -1340,8 +1423,8 @@ EXPORT_SYMBOL_GPL(pm_genpd_init);
|
|||
* maps a PM domain specifier retrieved from the device tree to a PM domain.
|
||||
*
|
||||
* Two simple mapping functions have been provided for convenience:
|
||||
* - __of_genpd_xlate_simple() for 1:1 device tree node to PM domain mapping.
|
||||
* - __of_genpd_xlate_onecell() for mapping of multiple PM domains per node by
|
||||
* - genpd_xlate_simple() for 1:1 device tree node to PM domain mapping.
|
||||
* - genpd_xlate_onecell() for mapping of multiple PM domains per node by
|
||||
* index.
|
||||
*/
|
||||
|
||||
|
@ -1366,7 +1449,7 @@ static LIST_HEAD(of_genpd_providers);
|
|||
static DEFINE_MUTEX(of_genpd_mutex);
|
||||
|
||||
/**
|
||||
* __of_genpd_xlate_simple() - Xlate function for direct node-domain mapping
|
||||
* genpd_xlate_simple() - Xlate function for direct node-domain mapping
|
||||
* @genpdspec: OF phandle args to map into a PM domain
|
||||
* @data: xlate function private data - pointer to struct generic_pm_domain
|
||||
*
|
||||
|
@ -1374,7 +1457,7 @@ static DEFINE_MUTEX(of_genpd_mutex);
|
|||
* have their own device tree nodes. The private data of xlate function needs
|
||||
* to be a valid pointer to struct generic_pm_domain.
|
||||
*/
|
||||
struct generic_pm_domain *__of_genpd_xlate_simple(
|
||||
static struct generic_pm_domain *genpd_xlate_simple(
|
||||
struct of_phandle_args *genpdspec,
|
||||
void *data)
|
||||
{
|
||||
|
@ -1382,10 +1465,9 @@ struct generic_pm_domain *__of_genpd_xlate_simple(
|
|||
return ERR_PTR(-EINVAL);
|
||||
return data;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(__of_genpd_xlate_simple);
|
||||
|
||||
/**
|
||||
* __of_genpd_xlate_onecell() - Xlate function using a single index.
|
||||
* genpd_xlate_onecell() - Xlate function using a single index.
|
||||
* @genpdspec: OF phandle args to map into a PM domain
|
||||
* @data: xlate function private data - pointer to struct genpd_onecell_data
|
||||
*
|
||||
|
@ -1394,7 +1476,7 @@ EXPORT_SYMBOL_GPL(__of_genpd_xlate_simple);
|
|||
* A single cell is used as an index into an array of PM domains specified in
|
||||
* the genpd_onecell_data struct when registering the provider.
|
||||
*/
|
||||
struct generic_pm_domain *__of_genpd_xlate_onecell(
|
||||
static struct generic_pm_domain *genpd_xlate_onecell(
|
||||
struct of_phandle_args *genpdspec,
|
||||
void *data)
|
||||
{
|
||||
|
@ -1414,16 +1496,15 @@ struct generic_pm_domain *__of_genpd_xlate_onecell(
|
|||
|
||||
return genpd_data->domains[idx];
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(__of_genpd_xlate_onecell);
|
||||
|
||||
/**
|
||||
* __of_genpd_add_provider() - Register a PM domain provider for a node
|
||||
* genpd_add_provider() - Register a PM domain provider for a node
|
||||
* @np: Device node pointer associated with the PM domain provider.
|
||||
* @xlate: Callback for decoding PM domain from phandle arguments.
|
||||
* @data: Context pointer for @xlate callback.
|
||||
*/
|
||||
int __of_genpd_add_provider(struct device_node *np, genpd_xlate_t xlate,
|
||||
void *data)
|
||||
static int genpd_add_provider(struct device_node *np, genpd_xlate_t xlate,
|
||||
void *data)
|
||||
{
|
||||
struct of_genpd_provider *cp;
|
||||
|
||||
|
@ -1442,7 +1523,83 @@ int __of_genpd_add_provider(struct device_node *np, genpd_xlate_t xlate,
|
|||
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(__of_genpd_add_provider);
|
||||
|
||||
/**
|
||||
* of_genpd_add_provider_simple() - Register a simple PM domain provider
|
||||
* @np: Device node pointer associated with the PM domain provider.
|
||||
* @genpd: Pointer to PM domain associated with the PM domain provider.
|
||||
*/
|
||||
int of_genpd_add_provider_simple(struct device_node *np,
|
||||
struct generic_pm_domain *genpd)
|
||||
{
|
||||
int ret = -EINVAL;
|
||||
|
||||
if (!np || !genpd)
|
||||
return -EINVAL;
|
||||
|
||||
mutex_lock(&gpd_list_lock);
|
||||
|
||||
if (pm_genpd_present(genpd))
|
||||
ret = genpd_add_provider(np, genpd_xlate_simple, genpd);
|
||||
|
||||
if (!ret) {
|
||||
genpd->provider = &np->fwnode;
|
||||
genpd->has_provider = true;
|
||||
}
|
||||
|
||||
mutex_unlock(&gpd_list_lock);
|
||||
|
||||
return ret;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(of_genpd_add_provider_simple);
|
||||
|
||||
/**
|
||||
* of_genpd_add_provider_onecell() - Register a onecell PM domain provider
|
||||
* @np: Device node pointer associated with the PM domain provider.
|
||||
* @data: Pointer to the data associated with the PM domain provider.
|
||||
*/
|
||||
int of_genpd_add_provider_onecell(struct device_node *np,
|
||||
struct genpd_onecell_data *data)
|
||||
{
|
||||
unsigned int i;
|
||||
int ret = -EINVAL;
|
||||
|
||||
if (!np || !data)
|
||||
return -EINVAL;
|
||||
|
||||
mutex_lock(&gpd_list_lock);
|
||||
|
||||
for (i = 0; i < data->num_domains; i++) {
|
||||
if (!data->domains[i])
|
||||
continue;
|
||||
if (!pm_genpd_present(data->domains[i]))
|
||||
goto error;
|
||||
|
||||
data->domains[i]->provider = &np->fwnode;
|
||||
data->domains[i]->has_provider = true;
|
||||
}
|
||||
|
||||
ret = genpd_add_provider(np, genpd_xlate_onecell, data);
|
||||
if (ret < 0)
|
||||
goto error;
|
||||
|
||||
mutex_unlock(&gpd_list_lock);
|
||||
|
||||
return 0;
|
||||
|
||||
error:
|
||||
while (i--) {
|
||||
if (!data->domains[i])
|
||||
continue;
|
||||
data->domains[i]->provider = NULL;
|
||||
data->domains[i]->has_provider = false;
|
||||
}
|
||||
|
||||
mutex_unlock(&gpd_list_lock);
|
||||
|
||||
return ret;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(of_genpd_add_provider_onecell);
|
||||
|
||||
/**
|
||||
* of_genpd_del_provider() - Remove a previously registered PM domain provider
|
||||
|
@ -1451,10 +1608,21 @@ EXPORT_SYMBOL_GPL(__of_genpd_add_provider);
|
|||
void of_genpd_del_provider(struct device_node *np)
|
||||
{
|
||||
struct of_genpd_provider *cp;
|
||||
struct generic_pm_domain *gpd;
|
||||
|
||||
mutex_lock(&gpd_list_lock);
|
||||
mutex_lock(&of_genpd_mutex);
|
||||
list_for_each_entry(cp, &of_genpd_providers, link) {
|
||||
if (cp->node == np) {
|
||||
/*
|
||||
* For each PM domain associated with the
|
||||
* provider, set the 'has_provider' to false
|
||||
* so that the PM domain can be safely removed.
|
||||
*/
|
||||
list_for_each_entry(gpd, &gpd_list, gpd_list_node)
|
||||
if (gpd->provider == &np->fwnode)
|
||||
gpd->has_provider = false;
|
||||
|
||||
list_del(&cp->link);
|
||||
of_node_put(cp->node);
|
||||
kfree(cp);
|
||||
|
@ -1462,11 +1630,12 @@ void of_genpd_del_provider(struct device_node *np)
|
|||
}
|
||||
}
|
||||
mutex_unlock(&of_genpd_mutex);
|
||||
mutex_unlock(&gpd_list_lock);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(of_genpd_del_provider);
|
||||
|
||||
/**
|
||||
* of_genpd_get_from_provider() - Look-up PM domain
|
||||
* genpd_get_from_provider() - Look-up PM domain
|
||||
* @genpdspec: OF phandle args to use for look-up
|
||||
*
|
||||
* Looks for a PM domain provider under the node specified by @genpdspec and if
|
||||
|
@ -1476,7 +1645,7 @@ EXPORT_SYMBOL_GPL(of_genpd_del_provider);
|
|||
* Returns a valid pointer to struct generic_pm_domain on success or ERR_PTR()
|
||||
* on failure.
|
||||
*/
|
||||
struct generic_pm_domain *of_genpd_get_from_provider(
|
||||
static struct generic_pm_domain *genpd_get_from_provider(
|
||||
struct of_phandle_args *genpdspec)
|
||||
{
|
||||
struct generic_pm_domain *genpd = ERR_PTR(-ENOENT);
|
||||
|
@ -1499,7 +1668,109 @@ struct generic_pm_domain *of_genpd_get_from_provider(
|
|||
|
||||
return genpd;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(of_genpd_get_from_provider);
|
||||
|
||||
/**
|
||||
* of_genpd_add_device() - Add a device to an I/O PM domain
|
||||
* @genpdspec: OF phandle args to use for look-up PM domain
|
||||
* @dev: Device to be added.
|
||||
*
|
||||
* Looks-up an I/O PM domain based upon phandle args provided and adds
|
||||
* the device to the PM domain. Returns a negative error code on failure.
|
||||
*/
|
||||
int of_genpd_add_device(struct of_phandle_args *genpdspec, struct device *dev)
|
||||
{
|
||||
struct generic_pm_domain *genpd;
|
||||
int ret;
|
||||
|
||||
mutex_lock(&gpd_list_lock);
|
||||
|
||||
genpd = genpd_get_from_provider(genpdspec);
|
||||
if (IS_ERR(genpd)) {
|
||||
ret = PTR_ERR(genpd);
|
||||
goto out;
|
||||
}
|
||||
|
||||
ret = genpd_add_device(genpd, dev, NULL);
|
||||
|
||||
out:
|
||||
mutex_unlock(&gpd_list_lock);
|
||||
|
||||
return ret;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(of_genpd_add_device);
|
||||
|
||||
/**
|
||||
* of_genpd_add_subdomain - Add a subdomain to an I/O PM domain.
|
||||
* @parent_spec: OF phandle args to use for parent PM domain look-up
|
||||
* @subdomain_spec: OF phandle args to use for subdomain look-up
|
||||
*
|
||||
* Looks-up a parent PM domain and subdomain based upon phandle args
|
||||
* provided and adds the subdomain to the parent PM domain. Returns a
|
||||
* negative error code on failure.
|
||||
*/
|
||||
int of_genpd_add_subdomain(struct of_phandle_args *parent_spec,
|
||||
struct of_phandle_args *subdomain_spec)
|
||||
{
|
||||
struct generic_pm_domain *parent, *subdomain;
|
||||
int ret;
|
||||
|
||||
mutex_lock(&gpd_list_lock);
|
||||
|
||||
parent = genpd_get_from_provider(parent_spec);
|
||||
if (IS_ERR(parent)) {
|
||||
ret = PTR_ERR(parent);
|
||||
goto out;
|
||||
}
|
||||
|
||||
subdomain = genpd_get_from_provider(subdomain_spec);
|
||||
if (IS_ERR(subdomain)) {
|
||||
ret = PTR_ERR(subdomain);
|
||||
goto out;
|
||||
}
|
||||
|
||||
ret = genpd_add_subdomain(parent, subdomain);
|
||||
|
||||
out:
|
||||
mutex_unlock(&gpd_list_lock);
|
||||
|
||||
return ret;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(of_genpd_add_subdomain);
|
||||
|
||||
/**
|
||||
* of_genpd_remove_last - Remove the last PM domain registered for a provider
|
||||
* @provider: Pointer to device structure associated with provider
|
||||
*
|
||||
* Find the last PM domain that was added by a particular provider and
|
||||
* remove this PM domain from the list of PM domains. The provider is
|
||||
* identified by the 'provider' device structure that is passed. The PM
|
||||
* domain will only be removed, if the provider associated with domain
|
||||
* has been removed.
|
||||
*
|
||||
* Returns a valid pointer to struct generic_pm_domain on success or
|
||||
* ERR_PTR() on failure.
|
||||
*/
|
||||
struct generic_pm_domain *of_genpd_remove_last(struct device_node *np)
|
||||
{
|
||||
struct generic_pm_domain *gpd, *genpd = ERR_PTR(-ENOENT);
|
||||
int ret;
|
||||
|
||||
if (IS_ERR_OR_NULL(np))
|
||||
return ERR_PTR(-EINVAL);
|
||||
|
||||
mutex_lock(&gpd_list_lock);
|
||||
list_for_each_entry(gpd, &gpd_list, gpd_list_node) {
|
||||
if (gpd->provider == &np->fwnode) {
|
||||
ret = genpd_remove(gpd);
|
||||
genpd = ret ? ERR_PTR(ret) : gpd;
|
||||
break;
|
||||
}
|
||||
}
|
||||
mutex_unlock(&gpd_list_lock);
|
||||
|
||||
return genpd;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(of_genpd_remove_last);
|
||||
|
||||
/**
|
||||
* genpd_dev_pm_detach - Detach a device from its PM domain.
|
||||
|
@ -1515,14 +1786,14 @@ static void genpd_dev_pm_detach(struct device *dev, bool power_off)
|
|||
unsigned int i;
|
||||
int ret = 0;
|
||||
|
||||
pd = pm_genpd_lookup_dev(dev);
|
||||
if (!pd)
|
||||
pd = dev_to_genpd(dev);
|
||||
if (IS_ERR(pd))
|
||||
return;
|
||||
|
||||
dev_dbg(dev, "removing from PM domain %s\n", pd->name);
|
||||
|
||||
for (i = 1; i < GENPD_RETRY_MAX_MS; i <<= 1) {
|
||||
ret = pm_genpd_remove_device(pd, dev);
|
||||
ret = genpd_remove_device(pd, dev);
|
||||
if (ret != -EAGAIN)
|
||||
break;
|
||||
|
||||
|
@ -1596,9 +1867,11 @@ int genpd_dev_pm_attach(struct device *dev)
|
|||
return -ENOENT;
|
||||
}
|
||||
|
||||
pd = of_genpd_get_from_provider(&pd_args);
|
||||
mutex_lock(&gpd_list_lock);
|
||||
pd = genpd_get_from_provider(&pd_args);
|
||||
of_node_put(pd_args.np);
|
||||
if (IS_ERR(pd)) {
|
||||
mutex_unlock(&gpd_list_lock);
|
||||
dev_dbg(dev, "%s() failed to find PM domain: %ld\n",
|
||||
__func__, PTR_ERR(pd));
|
||||
return -EPROBE_DEFER;
|
||||
|
@ -1607,13 +1880,14 @@ int genpd_dev_pm_attach(struct device *dev)
|
|||
dev_dbg(dev, "adding to PM domain %s\n", pd->name);
|
||||
|
||||
for (i = 1; i < GENPD_RETRY_MAX_MS; i <<= 1) {
|
||||
ret = pm_genpd_add_device(pd, dev);
|
||||
ret = genpd_add_device(pd, dev, NULL);
|
||||
if (ret != -EAGAIN)
|
||||
break;
|
||||
|
||||
mdelay(i);
|
||||
cond_resched();
|
||||
}
|
||||
mutex_unlock(&gpd_list_lock);
|
||||
|
||||
if (ret < 0) {
|
||||
dev_err(dev, "failed to add to PM domain %s: %d",
|
||||
|
@ -1636,7 +1910,7 @@ EXPORT_SYMBOL_GPL(genpd_dev_pm_attach);
|
|||
|
||||
/*** debugfs support ***/
|
||||
|
||||
#ifdef CONFIG_PM_ADVANCED_DEBUG
|
||||
#ifdef CONFIG_DEBUG_FS
|
||||
#include <linux/pm.h>
|
||||
#include <linux/device.h>
|
||||
#include <linux/debugfs.h>
|
||||
|
@ -1784,4 +2058,4 @@ static void __exit pm_genpd_debug_exit(void)
|
|||
debugfs_remove_recursive(pm_genpd_debugfs_dir);
|
||||
}
|
||||
__exitcall(pm_genpd_debug_exit);
|
||||
#endif /* CONFIG_PM_ADVANCED_DEBUG */
|
||||
#endif /* CONFIG_DEBUG_FS */
|
||||
|
|
|
@ -215,29 +215,22 @@ no_clk:
|
|||
|
||||
/* Assign the child power domains to their parents */
|
||||
for_each_matching_node(np, exynos_pm_domain_of_match) {
|
||||
struct generic_pm_domain *child_domain, *parent_domain;
|
||||
struct of_phandle_args args;
|
||||
struct of_phandle_args child, parent;
|
||||
|
||||
args.np = np;
|
||||
args.args_count = 0;
|
||||
child_domain = of_genpd_get_from_provider(&args);
|
||||
if (IS_ERR(child_domain))
|
||||
continue;
|
||||
child.np = np;
|
||||
child.args_count = 0;
|
||||
|
||||
if (of_parse_phandle_with_args(np, "power-domains",
|
||||
"#power-domain-cells", 0, &args) != 0)
|
||||
"#power-domain-cells", 0,
|
||||
&parent) != 0)
|
||||
continue;
|
||||
|
||||
parent_domain = of_genpd_get_from_provider(&args);
|
||||
if (IS_ERR(parent_domain))
|
||||
continue;
|
||||
|
||||
if (pm_genpd_add_subdomain(parent_domain, child_domain))
|
||||
if (of_genpd_add_subdomain(&parent, &child))
|
||||
pr_warn("%s failed to add subdomain: %s\n",
|
||||
parent_domain->name, child_domain->name);
|
||||
parent.np->name, child.np->name);
|
||||
else
|
||||
pr_info("%s has as child subdomain: %s.\n",
|
||||
parent_domain->name, child_domain->name);
|
||||
parent.np->name, child.np->name);
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
|
|
@ -140,7 +140,6 @@ static int board_staging_add_dev_domain(struct platform_device *pdev,
|
|||
const char *domain)
|
||||
{
|
||||
struct of_phandle_args pd_args;
|
||||
struct generic_pm_domain *pd;
|
||||
struct device_node *np;
|
||||
|
||||
np = of_find_node_by_path(domain);
|
||||
|
@ -151,14 +150,8 @@ static int board_staging_add_dev_domain(struct platform_device *pdev,
|
|||
|
||||
pd_args.np = np;
|
||||
pd_args.args_count = 0;
|
||||
pd = of_genpd_get_from_provider(&pd_args);
|
||||
if (IS_ERR(pd)) {
|
||||
pr_err("Cannot find genpd %s (%ld)\n", domain, PTR_ERR(pd));
|
||||
return PTR_ERR(pd);
|
||||
}
|
||||
pr_debug("Found genpd %s for device %s\n", pd->name, pdev->name);
|
||||
|
||||
return pm_genpd_add_device(pd, &pdev->dev);
|
||||
return of_genpd_add_device(&pd_args, &pdev->dev);
|
||||
}
|
||||
#else
|
||||
static inline int board_staging_add_dev_domain(struct platform_device *pdev,
|
||||
|
|
|
@ -51,6 +51,8 @@ struct generic_pm_domain {
|
|||
struct mutex lock;
|
||||
struct dev_power_governor *gov;
|
||||
struct work_struct power_off_work;
|
||||
struct fwnode_handle *provider; /* Identity of the domain provider */
|
||||
bool has_provider;
|
||||
const char *name;
|
||||
atomic_t sd_count; /* Number of subdomains with power "on" */
|
||||
enum gpd_status status; /* Current state of the domain */
|
||||
|
@ -116,7 +118,6 @@ static inline struct generic_pm_domain_data *dev_gpd_data(struct device *dev)
|
|||
return to_gpd_data(dev->power.subsys_data->domain_data);
|
||||
}
|
||||
|
||||
extern struct generic_pm_domain *pm_genpd_lookup_dev(struct device *dev);
|
||||
extern int __pm_genpd_add_device(struct generic_pm_domain *genpd,
|
||||
struct device *dev,
|
||||
struct gpd_timing_data *td);
|
||||
|
@ -129,6 +130,7 @@ extern int pm_genpd_remove_subdomain(struct generic_pm_domain *genpd,
|
|||
struct generic_pm_domain *target);
|
||||
extern int pm_genpd_init(struct generic_pm_domain *genpd,
|
||||
struct dev_power_governor *gov, bool is_off);
|
||||
extern int pm_genpd_remove(struct generic_pm_domain *genpd);
|
||||
|
||||
extern struct dev_power_governor simple_qos_governor;
|
||||
extern struct dev_power_governor pm_domain_always_on_gov;
|
||||
|
@ -138,10 +140,6 @@ static inline struct generic_pm_domain_data *dev_gpd_data(struct device *dev)
|
|||
{
|
||||
return ERR_PTR(-ENOSYS);
|
||||
}
|
||||
static inline struct generic_pm_domain *pm_genpd_lookup_dev(struct device *dev)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
static inline int __pm_genpd_add_device(struct generic_pm_domain *genpd,
|
||||
struct device *dev,
|
||||
struct gpd_timing_data *td)
|
||||
|
@ -168,6 +166,10 @@ static inline int pm_genpd_init(struct generic_pm_domain *genpd,
|
|||
{
|
||||
return -ENOSYS;
|
||||
}
|
||||
static inline int pm_genpd_remove(struct generic_pm_domain *genpd)
|
||||
{
|
||||
return -ENOTSUPP;
|
||||
}
|
||||
#endif
|
||||
|
||||
static inline int pm_genpd_add_device(struct generic_pm_domain *genpd,
|
||||
|
@ -192,57 +194,57 @@ struct genpd_onecell_data {
|
|||
unsigned int num_domains;
|
||||
};
|
||||
|
||||
typedef struct generic_pm_domain *(*genpd_xlate_t)(struct of_phandle_args *args,
|
||||
void *data);
|
||||
|
||||
#ifdef CONFIG_PM_GENERIC_DOMAINS_OF
|
||||
int __of_genpd_add_provider(struct device_node *np, genpd_xlate_t xlate,
|
||||
void *data);
|
||||
int of_genpd_add_provider_simple(struct device_node *np,
|
||||
struct generic_pm_domain *genpd);
|
||||
int of_genpd_add_provider_onecell(struct device_node *np,
|
||||
struct genpd_onecell_data *data);
|
||||
void of_genpd_del_provider(struct device_node *np);
|
||||
struct generic_pm_domain *of_genpd_get_from_provider(
|
||||
struct of_phandle_args *genpdspec);
|
||||
|
||||
struct generic_pm_domain *__of_genpd_xlate_simple(
|
||||
struct of_phandle_args *genpdspec,
|
||||
void *data);
|
||||
struct generic_pm_domain *__of_genpd_xlate_onecell(
|
||||
struct of_phandle_args *genpdspec,
|
||||
void *data);
|
||||
extern int of_genpd_add_device(struct of_phandle_args *args,
|
||||
struct device *dev);
|
||||
extern int of_genpd_add_subdomain(struct of_phandle_args *parent,
|
||||
struct of_phandle_args *new_subdomain);
|
||||
extern struct generic_pm_domain *of_genpd_remove_last(struct device_node *np);
|
||||
|
||||
int genpd_dev_pm_attach(struct device *dev);
|
||||
#else /* !CONFIG_PM_GENERIC_DOMAINS_OF */
|
||||
static inline int __of_genpd_add_provider(struct device_node *np,
|
||||
genpd_xlate_t xlate, void *data)
|
||||
static inline int of_genpd_add_provider_simple(struct device_node *np,
|
||||
struct generic_pm_domain *genpd)
|
||||
{
|
||||
return 0;
|
||||
return -ENOTSUPP;
|
||||
}
|
||||
|
||||
static inline int of_genpd_add_provider_onecell(struct device_node *np,
|
||||
struct genpd_onecell_data *data)
|
||||
{
|
||||
return -ENOTSUPP;
|
||||
}
|
||||
|
||||
static inline void of_genpd_del_provider(struct device_node *np) {}
|
||||
|
||||
static inline struct generic_pm_domain *of_genpd_get_from_provider(
|
||||
struct of_phandle_args *genpdspec)
|
||||
static inline int of_genpd_add_device(struct of_phandle_args *args,
|
||||
struct device *dev)
|
||||
{
|
||||
return NULL;
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
#define __of_genpd_xlate_simple NULL
|
||||
#define __of_genpd_xlate_onecell NULL
|
||||
static inline int of_genpd_add_subdomain(struct of_phandle_args *parent,
|
||||
struct of_phandle_args *new_subdomain)
|
||||
{
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
static inline int genpd_dev_pm_attach(struct device *dev)
|
||||
{
|
||||
return -ENODEV;
|
||||
}
|
||||
#endif /* CONFIG_PM_GENERIC_DOMAINS_OF */
|
||||
|
||||
static inline int of_genpd_add_provider_simple(struct device_node *np,
|
||||
struct generic_pm_domain *genpd)
|
||||
static inline
|
||||
struct generic_pm_domain *of_genpd_remove_last(struct device_node *np)
|
||||
{
|
||||
return __of_genpd_add_provider(np, __of_genpd_xlate_simple, genpd);
|
||||
}
|
||||
static inline int of_genpd_add_provider_onecell(struct device_node *np,
|
||||
struct genpd_onecell_data *data)
|
||||
{
|
||||
return __of_genpd_add_provider(np, __of_genpd_xlate_onecell, data);
|
||||
return ERR_PTR(-ENOTSUPP);
|
||||
}
|
||||
#endif /* CONFIG_PM_GENERIC_DOMAINS_OF */
|
||||
|
||||
#ifdef CONFIG_PM
|
||||
extern int dev_pm_domain_attach(struct device *dev, bool power_on);
|
||||
|
|
Loading…
Reference in New Issue