Merge branch 'pm-opp' into pm

* pm-opp: (37 commits)
  PM / devfreq: Add required OPPs support to passive governor
  PM / devfreq: Cache OPP table reference in devfreq
  OPP: Add function to look up required OPP's for a given OPP
  opp: Replace ENOTSUPP with EOPNOTSUPP
  opp: Fix "foo * bar" should be "foo *bar"
  opp: Don't ignore clk_get() errors other than -ENOENT
  opp: Update bandwidth requirements based on scaling up/down
  opp: Allow lazy-linking of required-opps
  opp: Remove dev_pm_opp_set_bw()
  devfreq: tegra30: Migrate to dev_pm_opp_set_opp()
  drm: msm: Migrate to dev_pm_opp_set_opp()
  cpufreq: qcom: Migrate to dev_pm_opp_set_opp()
  opp: Implement dev_pm_opp_set_opp()
  opp: Update parameters of  _set_opp_custom()
  opp: Allow _generic_set_opp_clk_only() to work for non-freq devices
  opp: Allow _generic_set_opp_regulator() to work for non-freq devices
  opp: Allow _set_opp() to work for non-freq devices
  opp: Split _set_opp() out of dev_pm_opp_set_rate()
  opp: Keep track of currently programmed OPP
  opp: No need to check clk for errors
  ...
This commit is contained in:
Rafael J. Wysocki
2021-02-15 17:01:46 +01:00
10 changed files with 898 additions and 352 deletions

View File

@@ -54,7 +54,7 @@ static int qcom_cpufreq_set_bw(struct cpufreq_policy *policy,
if (IS_ERR(opp)) if (IS_ERR(opp))
return PTR_ERR(opp); return PTR_ERR(opp);
ret = dev_pm_opp_set_bw(dev, opp); ret = dev_pm_opp_set_opp(dev, opp);
dev_pm_opp_put(opp); dev_pm_opp_put(opp);
return ret; return ret;
} }

View File

@@ -757,6 +757,9 @@ static void devfreq_dev_release(struct device *dev)
if (devfreq->profile->exit) if (devfreq->profile->exit)
devfreq->profile->exit(devfreq->dev.parent); devfreq->profile->exit(devfreq->dev.parent);
if (devfreq->opp_table)
dev_pm_opp_put_opp_table(devfreq->opp_table);
mutex_destroy(&devfreq->lock); mutex_destroy(&devfreq->lock);
kfree(devfreq); kfree(devfreq);
} }
@@ -844,6 +847,10 @@ struct devfreq *devfreq_add_device(struct device *dev,
} }
devfreq->suspend_freq = dev_pm_opp_get_suspend_opp_freq(dev); devfreq->suspend_freq = dev_pm_opp_get_suspend_opp_freq(dev);
devfreq->opp_table = dev_pm_opp_get_opp_table(dev);
if (IS_ERR(devfreq->opp_table))
devfreq->opp_table = NULL;
atomic_set(&devfreq->suspend_count, 0); atomic_set(&devfreq->suspend_count, 0);
dev_set_name(&devfreq->dev, "%s", dev_name(dev)); dev_set_name(&devfreq->dev, "%s", dev_name(dev));

View File

@@ -19,18 +19,16 @@ static int devfreq_passive_get_target_freq(struct devfreq *devfreq,
= (struct devfreq_passive_data *)devfreq->data; = (struct devfreq_passive_data *)devfreq->data;
struct devfreq *parent_devfreq = (struct devfreq *)p_data->parent; struct devfreq *parent_devfreq = (struct devfreq *)p_data->parent;
unsigned long child_freq = ULONG_MAX; unsigned long child_freq = ULONG_MAX;
struct dev_pm_opp *opp; struct dev_pm_opp *opp, *p_opp;
int i, count, ret = 0; int i, count;
/* /*
* If the devfreq device with passive governor has the specific method * If the devfreq device with passive governor has the specific method
* to determine the next frequency, should use the get_target_freq() * to determine the next frequency, should use the get_target_freq()
* of struct devfreq_passive_data. * of struct devfreq_passive_data.
*/ */
if (p_data->get_target_freq) { if (p_data->get_target_freq)
ret = p_data->get_target_freq(devfreq, freq); return p_data->get_target_freq(devfreq, freq);
goto out;
}
/* /*
* If the parent and passive devfreq device uses the OPP table, * If the parent and passive devfreq device uses the OPP table,
@@ -56,26 +54,35 @@ static int devfreq_passive_get_target_freq(struct devfreq *devfreq,
* list of parent device. Because in this case, *freq is temporary * list of parent device. Because in this case, *freq is temporary
* value which is decided by ondemand governor. * value which is decided by ondemand governor.
*/ */
opp = devfreq_recommended_opp(parent_devfreq->dev.parent, freq, 0); if (devfreq->opp_table && parent_devfreq->opp_table) {
if (IS_ERR(opp)) { p_opp = devfreq_recommended_opp(parent_devfreq->dev.parent,
ret = PTR_ERR(opp); freq, 0);
goto out; if (IS_ERR(p_opp))
return PTR_ERR(p_opp);
opp = dev_pm_opp_xlate_required_opp(parent_devfreq->opp_table,
devfreq->opp_table, p_opp);
dev_pm_opp_put(p_opp);
if (IS_ERR(opp))
return PTR_ERR(opp);
*freq = dev_pm_opp_get_freq(opp);
dev_pm_opp_put(opp);
return 0;
} }
dev_pm_opp_put(opp);
/* /*
* Get the OPP table's index of decided freqeuncy by governor * Get the OPP table's index of decided frequency by governor
* of parent device. * of parent device.
*/ */
for (i = 0; i < parent_devfreq->profile->max_state; i++) for (i = 0; i < parent_devfreq->profile->max_state; i++)
if (parent_devfreq->profile->freq_table[i] == *freq) if (parent_devfreq->profile->freq_table[i] == *freq)
break; break;
if (i == parent_devfreq->profile->max_state) { if (i == parent_devfreq->profile->max_state)
ret = -EINVAL; return -EINVAL;
goto out;
}
/* Get the suitable frequency by using index of parent device. */ /* Get the suitable frequency by using index of parent device. */
if (i < devfreq->profile->max_state) { if (i < devfreq->profile->max_state) {
@@ -88,8 +95,7 @@ static int devfreq_passive_get_target_freq(struct devfreq *devfreq,
/* Return the suitable frequency for passive device. */ /* Return the suitable frequency for passive device. */
*freq = child_freq; *freq = child_freq;
out: return 0;
return ret;
} }
static int devfreq_passive_notifier_call(struct notifier_block *nb, static int devfreq_passive_notifier_call(struct notifier_block *nb,

View File

@@ -647,7 +647,7 @@ static int tegra_devfreq_target(struct device *dev, unsigned long *freq,
return PTR_ERR(opp); return PTR_ERR(opp);
} }
ret = dev_pm_opp_set_bw(dev, opp); ret = dev_pm_opp_set_opp(dev, opp);
dev_pm_opp_put(opp); dev_pm_opp_put(opp);
return ret; return ret;
@@ -849,7 +849,7 @@ static int tegra_devfreq_probe(struct platform_device *pdev)
return err; return err;
} }
err = dev_pm_opp_of_add_table(&pdev->dev); err = dev_pm_opp_of_add_table_noclk(&pdev->dev, 0);
if (err) { if (err) {
dev_err(&pdev->dev, "Failed to add OPP table: %d\n", err); dev_err(&pdev->dev, "Failed to add OPP table: %d\n", err);
goto put_hw; goto put_hw;

View File

@@ -134,7 +134,7 @@ void a6xx_gmu_set_freq(struct msm_gpu *gpu, struct dev_pm_opp *opp)
if (!gmu->legacy) { if (!gmu->legacy) {
a6xx_hfi_set_freq(gmu, perf_index); a6xx_hfi_set_freq(gmu, perf_index);
dev_pm_opp_set_bw(&gpu->pdev->dev, opp); dev_pm_opp_set_opp(&gpu->pdev->dev, opp);
pm_runtime_put(gmu->dev); pm_runtime_put(gmu->dev);
return; return;
} }
@@ -158,7 +158,7 @@ void a6xx_gmu_set_freq(struct msm_gpu *gpu, struct dev_pm_opp *opp)
if (ret) if (ret)
dev_err(gmu->dev, "GMU set GPU frequency error: %d\n", ret); dev_err(gmu->dev, "GMU set GPU frequency error: %d\n", ret);
dev_pm_opp_set_bw(&gpu->pdev->dev, opp); dev_pm_opp_set_opp(&gpu->pdev->dev, opp);
pm_runtime_put(gmu->dev); pm_runtime_put(gmu->dev);
} }
@@ -866,7 +866,7 @@ static void a6xx_gmu_set_initial_bw(struct msm_gpu *gpu, struct a6xx_gmu *gmu)
if (IS_ERR_OR_NULL(gpu_opp)) if (IS_ERR_OR_NULL(gpu_opp))
return; return;
dev_pm_opp_set_bw(&gpu->pdev->dev, gpu_opp); dev_pm_opp_set_opp(&gpu->pdev->dev, gpu_opp);
dev_pm_opp_put(gpu_opp); dev_pm_opp_put(gpu_opp);
} }
@@ -1072,7 +1072,7 @@ int a6xx_gmu_stop(struct a6xx_gpu *a6xx_gpu)
a6xx_gmu_shutdown(gmu); a6xx_gmu_shutdown(gmu);
/* Remove the bus vote */ /* Remove the bus vote */
dev_pm_opp_set_bw(&gpu->pdev->dev, NULL); dev_pm_opp_set_opp(&gpu->pdev->dev, NULL);
/* /*
* Make sure the GX domain is off before turning off the GMU (CX) * Make sure the GX domain is off before turning off the GMU (CX)

File diff suppressed because it is too large Load Diff

View File

@@ -144,7 +144,7 @@ static void _opp_table_free_required_tables(struct opp_table *opp_table)
for (i = 0; i < opp_table->required_opp_count; i++) { for (i = 0; i < opp_table->required_opp_count; i++) {
if (IS_ERR_OR_NULL(required_opp_tables[i])) if (IS_ERR_OR_NULL(required_opp_tables[i]))
break; continue;
dev_pm_opp_put_opp_table(required_opp_tables[i]); dev_pm_opp_put_opp_table(required_opp_tables[i]);
} }
@@ -153,6 +153,7 @@ static void _opp_table_free_required_tables(struct opp_table *opp_table)
opp_table->required_opp_count = 0; opp_table->required_opp_count = 0;
opp_table->required_opp_tables = NULL; opp_table->required_opp_tables = NULL;
list_del(&opp_table->lazy);
} }
/* /*
@@ -165,6 +166,7 @@ static void _opp_table_alloc_required_tables(struct opp_table *opp_table,
{ {
struct opp_table **required_opp_tables; struct opp_table **required_opp_tables;
struct device_node *required_np, *np; struct device_node *required_np, *np;
bool lazy = false;
int count, i; int count, i;
/* Traversing the first OPP node is all we need */ /* Traversing the first OPP node is all we need */
@@ -195,8 +197,10 @@ static void _opp_table_alloc_required_tables(struct opp_table *opp_table,
required_opp_tables[i] = _find_table_of_opp_np(required_np); required_opp_tables[i] = _find_table_of_opp_np(required_np);
of_node_put(required_np); of_node_put(required_np);
if (IS_ERR(required_opp_tables[i])) if (IS_ERR(required_opp_tables[i])) {
goto free_required_tables; lazy = true;
continue;
}
/* /*
* We only support genpd's OPPs in the "required-opps" for now, * We only support genpd's OPPs in the "required-opps" for now,
@@ -210,6 +214,10 @@ static void _opp_table_alloc_required_tables(struct opp_table *opp_table,
} }
} }
/* Let's do the linking later on */
if (lazy)
list_add(&opp_table->lazy, &lazy_opp_tables);
goto put_np; goto put_np;
free_required_tables: free_required_tables:
@@ -278,14 +286,14 @@ void _of_opp_free_required_opps(struct opp_table *opp_table,
for (i = 0; i < opp_table->required_opp_count; i++) { for (i = 0; i < opp_table->required_opp_count; i++) {
if (!required_opps[i]) if (!required_opps[i])
break; continue;
/* Put the reference back */ /* Put the reference back */
dev_pm_opp_put(required_opps[i]); dev_pm_opp_put(required_opps[i]);
} }
kfree(required_opps);
opp->required_opps = NULL; opp->required_opps = NULL;
kfree(required_opps);
} }
/* Populate all required OPPs which are part of "required-opps" list */ /* Populate all required OPPs which are part of "required-opps" list */
@@ -309,6 +317,10 @@ static int _of_opp_alloc_required_opps(struct opp_table *opp_table,
for (i = 0; i < count; i++) { for (i = 0; i < count; i++) {
required_table = opp_table->required_opp_tables[i]; required_table = opp_table->required_opp_tables[i];
/* Required table not added yet, we will link later */
if (IS_ERR_OR_NULL(required_table))
continue;
np = of_parse_required_opp(opp->np, i); np = of_parse_required_opp(opp->np, i);
if (unlikely(!np)) { if (unlikely(!np)) {
ret = -ENODEV; ret = -ENODEV;
@@ -334,6 +346,104 @@ free_required_opps:
return ret; return ret;
} }
/* Link required OPPs for an individual OPP */
static int lazy_link_required_opps(struct opp_table *opp_table,
struct opp_table *new_table, int index)
{
struct device_node *required_np;
struct dev_pm_opp *opp;
list_for_each_entry(opp, &opp_table->opp_list, node) {
required_np = of_parse_required_opp(opp->np, index);
if (unlikely(!required_np))
return -ENODEV;
opp->required_opps[index] = _find_opp_of_np(new_table, required_np);
of_node_put(required_np);
if (!opp->required_opps[index]) {
pr_err("%s: Unable to find required OPP node: %pOF (%d)\n",
__func__, opp->np, index);
return -ENODEV;
}
}
return 0;
}
/* Link required OPPs for all OPPs of the newly added OPP table */
static void lazy_link_required_opp_table(struct opp_table *new_table)
{
struct opp_table *opp_table, *temp, **required_opp_tables;
struct device_node *required_np, *opp_np, *required_table_np;
struct dev_pm_opp *opp;
int i, ret;
/*
* We only support genpd's OPPs in the "required-opps" for now,
* as we don't know much about other cases.
*/
if (!new_table->is_genpd)
return;
mutex_lock(&opp_table_lock);
list_for_each_entry_safe(opp_table, temp, &lazy_opp_tables, lazy) {
bool lazy = false;
/* opp_np can't be invalid here */
opp_np = of_get_next_available_child(opp_table->np, NULL);
for (i = 0; i < opp_table->required_opp_count; i++) {
required_opp_tables = opp_table->required_opp_tables;
/* Required opp-table is already parsed */
if (!IS_ERR(required_opp_tables[i]))
continue;
/* required_np can't be invalid here */
required_np = of_parse_required_opp(opp_np, i);
required_table_np = of_get_parent(required_np);
of_node_put(required_table_np);
of_node_put(required_np);
/*
* Newly added table isn't the required opp-table for
* opp_table.
*/
if (required_table_np != new_table->np) {
lazy = true;
continue;
}
required_opp_tables[i] = new_table;
_get_opp_table_kref(new_table);
/* Link OPPs now */
ret = lazy_link_required_opps(opp_table, new_table, i);
if (ret) {
/* The OPPs will be marked unusable */
lazy = false;
break;
}
}
of_node_put(opp_np);
/* All required opp-tables found, remove from lazy list */
if (!lazy) {
list_del(&opp_table->lazy);
INIT_LIST_HEAD(&opp_table->lazy);
list_for_each_entry(opp, &opp_table->opp_list, node)
_required_opps_available(opp, opp_table->required_opp_count);
}
}
mutex_unlock(&opp_table_lock);
}
static int _bandwidth_supported(struct device *dev, struct opp_table *opp_table) static int _bandwidth_supported(struct device *dev, struct opp_table *opp_table)
{ {
struct device_node *np, *opp_np; struct device_node *np, *opp_np;
@@ -755,7 +865,6 @@ static struct dev_pm_opp *_opp_add_static_v2(struct opp_table *opp_table,
struct device *dev, struct device_node *np) struct device *dev, struct device_node *np)
{ {
struct dev_pm_opp *new_opp; struct dev_pm_opp *new_opp;
u64 rate = 0;
u32 val; u32 val;
int ret; int ret;
bool rate_not_available = false; bool rate_not_available = false;
@@ -772,7 +881,8 @@ static struct dev_pm_opp *_opp_add_static_v2(struct opp_table *opp_table,
/* Check if the OPP supports hardware's hierarchy of versions or not */ /* Check if the OPP supports hardware's hierarchy of versions or not */
if (!_opp_is_supported(dev, opp_table, np)) { if (!_opp_is_supported(dev, opp_table, np)) {
dev_dbg(dev, "OPP not supported by hardware: %llu\n", rate); dev_dbg(dev, "OPP not supported by hardware: %lu\n",
new_opp->rate);
goto free_opp; goto free_opp;
} }
@@ -822,10 +932,11 @@ static struct dev_pm_opp *_opp_add_static_v2(struct opp_table *opp_table,
if (new_opp->clock_latency_ns > opp_table->clock_latency_ns_max) if (new_opp->clock_latency_ns > opp_table->clock_latency_ns_max)
opp_table->clock_latency_ns_max = new_opp->clock_latency_ns; opp_table->clock_latency_ns_max = new_opp->clock_latency_ns;
pr_debug("%s: turbo:%d rate:%lu uv:%lu uvmin:%lu uvmax:%lu latency:%lu\n", pr_debug("%s: turbo:%d rate:%lu uv:%lu uvmin:%lu uvmax:%lu latency:%lu level:%u\n",
__func__, new_opp->turbo, new_opp->rate, __func__, new_opp->turbo, new_opp->rate,
new_opp->supplies[0].u_volt, new_opp->supplies[0].u_volt_min, new_opp->supplies[0].u_volt, new_opp->supplies[0].u_volt_min,
new_opp->supplies[0].u_volt_max, new_opp->clock_latency_ns); new_opp->supplies[0].u_volt_max, new_opp->clock_latency_ns,
new_opp->level);
/* /*
* Notify the changes in the availability of the operable * Notify the changes in the availability of the operable
@@ -888,6 +999,8 @@ static int _of_add_opp_table_v2(struct device *dev, struct opp_table *opp_table)
} }
} }
lazy_link_required_opp_table(opp_table);
return 0; return 0;
remove_static_opp: remove_static_opp:
@@ -956,6 +1069,41 @@ remove_static_opp:
return ret; return ret;
} }
static int _of_add_table_indexed(struct device *dev, int index, bool getclk)
{
struct opp_table *opp_table;
int ret, count;
if (index) {
/*
* If only one phandle is present, then the same OPP table
* applies for all index requests.
*/
count = of_count_phandle_with_args(dev->of_node,
"operating-points-v2", NULL);
if (count == 1)
index = 0;
}
opp_table = _add_opp_table_indexed(dev, index, getclk);
if (IS_ERR(opp_table))
return PTR_ERR(opp_table);
/*
* OPPs have two version of bindings now. Also try the old (v1)
* bindings for backward compatibility with older dtbs.
*/
if (opp_table->np)
ret = _of_add_opp_table_v2(dev, opp_table);
else
ret = _of_add_opp_table_v1(dev, opp_table);
if (ret)
dev_pm_opp_put_opp_table(opp_table);
return ret;
}
/** /**
* dev_pm_opp_of_add_table() - Initialize opp table from device tree * dev_pm_opp_of_add_table() - Initialize opp table from device tree
* @dev: device pointer used to lookup OPP table. * @dev: device pointer used to lookup OPP table.
@@ -975,26 +1123,7 @@ remove_static_opp:
*/ */
int dev_pm_opp_of_add_table(struct device *dev) int dev_pm_opp_of_add_table(struct device *dev)
{ {
struct opp_table *opp_table; return _of_add_table_indexed(dev, 0, true);
int ret;
opp_table = _add_opp_table_indexed(dev, 0);
if (IS_ERR(opp_table))
return PTR_ERR(opp_table);
/*
* OPPs have two version of bindings now. Also try the old (v1)
* bindings for backward compatibility with older dtbs.
*/
if (opp_table->np)
ret = _of_add_opp_table_v2(dev, opp_table);
else
ret = _of_add_opp_table_v1(dev, opp_table);
if (ret)
dev_pm_opp_put_opp_table(opp_table);
return ret;
} }
EXPORT_SYMBOL_GPL(dev_pm_opp_of_add_table); EXPORT_SYMBOL_GPL(dev_pm_opp_of_add_table);
@@ -1006,45 +1135,32 @@ EXPORT_SYMBOL_GPL(dev_pm_opp_of_add_table);
* Register the initial OPP table with the OPP library for given device only * Register the initial OPP table with the OPP library for given device only
* using the "operating-points-v2" property. * using the "operating-points-v2" property.
* *
* Return: * Return: Refer to dev_pm_opp_of_add_table() for return values.
* 0 On success OR
* Duplicate OPPs (both freq and volt are same) and opp->available
* -EEXIST Freq are same and volt are different OR
* Duplicate OPPs (both freq and volt are same) and !opp->available
* -ENOMEM Memory allocation failure
* -ENODEV when 'operating-points' property is not found or is invalid data
* in device node.
* -ENODATA when empty 'operating-points' property is found
* -EINVAL when invalid entries are found in opp-v2 table
*/ */
int dev_pm_opp_of_add_table_indexed(struct device *dev, int index) int dev_pm_opp_of_add_table_indexed(struct device *dev, int index)
{ {
struct opp_table *opp_table; return _of_add_table_indexed(dev, index, true);
int ret, count;
if (index) {
/*
* If only one phandle is present, then the same OPP table
* applies for all index requests.
*/
count = of_count_phandle_with_args(dev->of_node,
"operating-points-v2", NULL);
if (count == 1)
index = 0;
}
opp_table = _add_opp_table_indexed(dev, index);
if (IS_ERR(opp_table))
return PTR_ERR(opp_table);
ret = _of_add_opp_table_v2(dev, opp_table);
if (ret)
dev_pm_opp_put_opp_table(opp_table);
return ret;
} }
EXPORT_SYMBOL_GPL(dev_pm_opp_of_add_table_indexed); EXPORT_SYMBOL_GPL(dev_pm_opp_of_add_table_indexed);
/**
* dev_pm_opp_of_add_table_noclk() - Initialize indexed opp table from device
* tree without getting clk for device.
* @dev: device pointer used to lookup OPP table.
* @index: Index number.
*
* Register the initial OPP table with the OPP library for given device only
* using the "operating-points-v2" property. Do not try to get the clk for the
* device.
*
* Return: Refer to dev_pm_opp_of_add_table() for return values.
*/
int dev_pm_opp_of_add_table_noclk(struct device *dev, int index)
{
return _of_add_table_indexed(dev, index, false);
}
EXPORT_SYMBOL_GPL(dev_pm_opp_of_add_table_noclk);
/* CPU device specific helpers */ /* CPU device specific helpers */
/** /**

View File

@@ -26,7 +26,7 @@ struct regulator;
/* Lock to allow exclusive modification to the device and opp lists */ /* Lock to allow exclusive modification to the device and opp lists */
extern struct mutex opp_table_lock; extern struct mutex opp_table_lock;
extern struct list_head opp_tables; extern struct list_head opp_tables, lazy_opp_tables;
/* /*
* Internal data structure organization with the OPP layer library is as * Internal data structure organization with the OPP layer library is as
@@ -135,6 +135,7 @@ enum opp_table_access {
* @clock_latency_ns_max: Max clock latency in nanoseconds. * @clock_latency_ns_max: Max clock latency in nanoseconds.
* @parsed_static_opps: Count of devices for which OPPs are initialized from DT. * @parsed_static_opps: Count of devices for which OPPs are initialized from DT.
* @shared_opp: OPP is shared between multiple devices. * @shared_opp: OPP is shared between multiple devices.
* @current_opp: Currently configured OPP for the table.
* @suspend_opp: Pointer to OPP to be used during device suspend. * @suspend_opp: Pointer to OPP to be used during device suspend.
* @genpd_virt_dev_lock: Mutex protecting the genpd virtual device pointers. * @genpd_virt_dev_lock: Mutex protecting the genpd virtual device pointers.
* @genpd_virt_devs: List of virtual devices for multiple genpd support. * @genpd_virt_devs: List of virtual devices for multiple genpd support.
@@ -155,6 +156,7 @@ enum opp_table_access {
* @genpd_performance_state: Device's power domain support performance state. * @genpd_performance_state: Device's power domain support performance state.
* @is_genpd: Marks if the OPP table belongs to a genpd. * @is_genpd: Marks if the OPP table belongs to a genpd.
* @set_opp: Platform specific set_opp callback * @set_opp: Platform specific set_opp callback
* @sod_supplies: Set opp data supplies
* @set_opp_data: Data to be passed to set_opp callback * @set_opp_data: Data to be passed to set_opp callback
* @dentry: debugfs dentry pointer of the real device directory (not links). * @dentry: debugfs dentry pointer of the real device directory (not links).
* @dentry_name: Name of the real dentry. * @dentry_name: Name of the real dentry.
@@ -166,7 +168,7 @@ enum opp_table_access {
* meant for book keeping and private to OPP library. * meant for book keeping and private to OPP library.
*/ */
struct opp_table { struct opp_table {
struct list_head node; struct list_head node, lazy;
struct blocking_notifier_head head; struct blocking_notifier_head head;
struct list_head dev_list; struct list_head dev_list;
@@ -182,6 +184,7 @@ struct opp_table {
unsigned int parsed_static_opps; unsigned int parsed_static_opps;
enum opp_table_access shared_opp; enum opp_table_access shared_opp;
struct dev_pm_opp *current_opp;
struct dev_pm_opp *suspend_opp; struct dev_pm_opp *suspend_opp;
struct mutex genpd_virt_dev_lock; struct mutex genpd_virt_dev_lock;
@@ -202,6 +205,7 @@ struct opp_table {
bool is_genpd; bool is_genpd;
int (*set_opp)(struct dev_pm_set_opp_data *data); int (*set_opp)(struct dev_pm_set_opp_data *data);
struct dev_pm_opp_supply *sod_supplies;
struct dev_pm_set_opp_data *set_opp_data; struct dev_pm_set_opp_data *set_opp_data;
#ifdef CONFIG_DEBUG_FS #ifdef CONFIG_DEBUG_FS
@@ -223,9 +227,14 @@ int _opp_compare_key(struct dev_pm_opp *opp1, struct dev_pm_opp *opp2);
int _opp_add(struct device *dev, struct dev_pm_opp *new_opp, struct opp_table *opp_table, bool rate_not_available); int _opp_add(struct device *dev, struct dev_pm_opp *new_opp, struct opp_table *opp_table, bool rate_not_available);
int _opp_add_v1(struct opp_table *opp_table, struct device *dev, unsigned long freq, long u_volt, bool dynamic); int _opp_add_v1(struct opp_table *opp_table, struct device *dev, unsigned long freq, long u_volt, bool dynamic);
void _dev_pm_opp_cpumask_remove_table(const struct cpumask *cpumask, int last_cpu); void _dev_pm_opp_cpumask_remove_table(const struct cpumask *cpumask, int last_cpu);
struct opp_table *_add_opp_table(struct device *dev); struct opp_table *_add_opp_table_indexed(struct device *dev, int index, bool getclk);
struct opp_table *_add_opp_table_indexed(struct device *dev, int index);
void _put_opp_list_kref(struct opp_table *opp_table); void _put_opp_list_kref(struct opp_table *opp_table);
void _required_opps_available(struct dev_pm_opp *opp, int count);
static inline bool lazy_linking_pending(struct opp_table *opp_table)
{
return unlikely(!list_empty(&opp_table->lazy));
}
#ifdef CONFIG_OF #ifdef CONFIG_OF
void _of_init_opp_table(struct opp_table *opp_table, struct device *dev, int index); void _of_init_opp_table(struct opp_table *opp_table, struct device *dev, int index);

View File

@@ -137,6 +137,7 @@ struct devfreq_stats {
* using devfreq. * using devfreq.
* @profile: device-specific devfreq profile * @profile: device-specific devfreq profile
* @governor: method how to choose frequency based on the usage. * @governor: method how to choose frequency based on the usage.
* @opp_table: Reference to OPP table of dev.parent, if one exists.
* @nb: notifier block used to notify devfreq object that it should * @nb: notifier block used to notify devfreq object that it should
* reevaluate operable frequencies. Devfreq users may use * reevaluate operable frequencies. Devfreq users may use
* devfreq.nb to the corresponding register notifier call chain. * devfreq.nb to the corresponding register notifier call chain.
@@ -173,6 +174,7 @@ struct devfreq {
struct device dev; struct device dev;
struct devfreq_dev_profile *profile; struct devfreq_dev_profile *profile;
const struct devfreq_governor *governor; const struct devfreq_governor *governor;
struct opp_table *opp_table;
struct notifier_block nb; struct notifier_block nb;
struct delayed_work work; struct delayed_work work;

View File

@@ -98,6 +98,9 @@ unsigned long dev_pm_opp_get_freq(struct dev_pm_opp *opp);
unsigned int dev_pm_opp_get_level(struct dev_pm_opp *opp); unsigned int dev_pm_opp_get_level(struct dev_pm_opp *opp);
unsigned int dev_pm_opp_get_required_pstate(struct dev_pm_opp *opp,
unsigned int index);
bool dev_pm_opp_is_turbo(struct dev_pm_opp *opp); bool dev_pm_opp_is_turbo(struct dev_pm_opp *opp);
int dev_pm_opp_get_opp_count(struct device *dev); int dev_pm_opp_get_opp_count(struct device *dev);
@@ -111,6 +114,8 @@ struct dev_pm_opp *dev_pm_opp_find_freq_exact(struct device *dev,
bool available); bool available);
struct dev_pm_opp *dev_pm_opp_find_level_exact(struct device *dev, struct dev_pm_opp *dev_pm_opp_find_level_exact(struct device *dev,
unsigned int level); unsigned int level);
struct dev_pm_opp *dev_pm_opp_find_level_ceil(struct device *dev,
unsigned int *level);
struct dev_pm_opp *dev_pm_opp_find_freq_floor(struct device *dev, struct dev_pm_opp *dev_pm_opp_find_freq_floor(struct device *dev,
unsigned long *freq); unsigned long *freq);
@@ -143,28 +148,32 @@ struct opp_table *dev_pm_opp_set_prop_name(struct device *dev, const char *name)
void dev_pm_opp_put_prop_name(struct opp_table *opp_table); void dev_pm_opp_put_prop_name(struct opp_table *opp_table);
struct opp_table *dev_pm_opp_set_regulators(struct device *dev, const char * const names[], unsigned int count); struct opp_table *dev_pm_opp_set_regulators(struct device *dev, const char * const names[], unsigned int count);
void dev_pm_opp_put_regulators(struct opp_table *opp_table); void dev_pm_opp_put_regulators(struct opp_table *opp_table);
struct opp_table *dev_pm_opp_set_clkname(struct device *dev, const char * name); struct opp_table *dev_pm_opp_set_clkname(struct device *dev, const char *name);
void dev_pm_opp_put_clkname(struct opp_table *opp_table); void dev_pm_opp_put_clkname(struct opp_table *opp_table);
struct opp_table *dev_pm_opp_register_set_opp_helper(struct device *dev, int (*set_opp)(struct dev_pm_set_opp_data *data)); struct opp_table *dev_pm_opp_register_set_opp_helper(struct device *dev, int (*set_opp)(struct dev_pm_set_opp_data *data));
void dev_pm_opp_unregister_set_opp_helper(struct opp_table *opp_table); void dev_pm_opp_unregister_set_opp_helper(struct opp_table *opp_table);
struct opp_table *devm_pm_opp_register_set_opp_helper(struct device *dev, int (*set_opp)(struct dev_pm_set_opp_data *data));
struct opp_table *dev_pm_opp_attach_genpd(struct device *dev, const char **names, struct device ***virt_devs); struct opp_table *dev_pm_opp_attach_genpd(struct device *dev, const char **names, struct device ***virt_devs);
void dev_pm_opp_detach_genpd(struct opp_table *opp_table); void dev_pm_opp_detach_genpd(struct opp_table *opp_table);
struct opp_table *devm_pm_opp_attach_genpd(struct device *dev, const char **names, struct device ***virt_devs);
struct dev_pm_opp *dev_pm_opp_xlate_required_opp(struct opp_table *src_table, struct opp_table *dst_table, struct dev_pm_opp *src_opp);
int dev_pm_opp_xlate_performance_state(struct opp_table *src_table, struct opp_table *dst_table, unsigned int pstate); int dev_pm_opp_xlate_performance_state(struct opp_table *src_table, struct opp_table *dst_table, unsigned int pstate);
int dev_pm_opp_set_rate(struct device *dev, unsigned long target_freq); int dev_pm_opp_set_rate(struct device *dev, unsigned long target_freq);
int dev_pm_opp_set_bw(struct device *dev, struct dev_pm_opp *opp); int dev_pm_opp_set_opp(struct device *dev, struct dev_pm_opp *opp);
int dev_pm_opp_set_sharing_cpus(struct device *cpu_dev, const struct cpumask *cpumask); int dev_pm_opp_set_sharing_cpus(struct device *cpu_dev, const struct cpumask *cpumask);
int dev_pm_opp_get_sharing_cpus(struct device *cpu_dev, struct cpumask *cpumask); int dev_pm_opp_get_sharing_cpus(struct device *cpu_dev, struct cpumask *cpumask);
void dev_pm_opp_remove_table(struct device *dev); void dev_pm_opp_remove_table(struct device *dev);
void dev_pm_opp_cpumask_remove_table(const struct cpumask *cpumask); void dev_pm_opp_cpumask_remove_table(const struct cpumask *cpumask);
int dev_pm_opp_sync_regulators(struct device *dev);
#else #else
static inline struct opp_table *dev_pm_opp_get_opp_table(struct device *dev) static inline struct opp_table *dev_pm_opp_get_opp_table(struct device *dev)
{ {
return ERR_PTR(-ENOTSUPP); return ERR_PTR(-EOPNOTSUPP);
} }
static inline struct opp_table *dev_pm_opp_get_opp_table_indexed(struct device *dev, int index) static inline struct opp_table *dev_pm_opp_get_opp_table_indexed(struct device *dev, int index)
{ {
return ERR_PTR(-ENOTSUPP); return ERR_PTR(-EOPNOTSUPP);
} }
static inline void dev_pm_opp_put_opp_table(struct opp_table *opp_table) {} static inline void dev_pm_opp_put_opp_table(struct opp_table *opp_table) {}
@@ -184,6 +193,13 @@ static inline unsigned int dev_pm_opp_get_level(struct dev_pm_opp *opp)
return 0; return 0;
} }
static inline
unsigned int dev_pm_opp_get_required_pstate(struct dev_pm_opp *opp,
unsigned int index)
{
return 0;
}
static inline bool dev_pm_opp_is_turbo(struct dev_pm_opp *opp) static inline bool dev_pm_opp_is_turbo(struct dev_pm_opp *opp)
{ {
return false; return false;
@@ -217,31 +233,37 @@ static inline unsigned long dev_pm_opp_get_suspend_opp_freq(struct device *dev)
static inline struct dev_pm_opp *dev_pm_opp_find_freq_exact(struct device *dev, static inline struct dev_pm_opp *dev_pm_opp_find_freq_exact(struct device *dev,
unsigned long freq, bool available) unsigned long freq, bool available)
{ {
return ERR_PTR(-ENOTSUPP); return ERR_PTR(-EOPNOTSUPP);
} }
static inline struct dev_pm_opp *dev_pm_opp_find_level_exact(struct device *dev, static inline struct dev_pm_opp *dev_pm_opp_find_level_exact(struct device *dev,
unsigned int level) unsigned int level)
{ {
return ERR_PTR(-ENOTSUPP); return ERR_PTR(-EOPNOTSUPP);
}
static inline struct dev_pm_opp *dev_pm_opp_find_level_ceil(struct device *dev,
unsigned int *level)
{
return ERR_PTR(-EOPNOTSUPP);
} }
static inline struct dev_pm_opp *dev_pm_opp_find_freq_floor(struct device *dev, static inline struct dev_pm_opp *dev_pm_opp_find_freq_floor(struct device *dev,
unsigned long *freq) unsigned long *freq)
{ {
return ERR_PTR(-ENOTSUPP); return ERR_PTR(-EOPNOTSUPP);
} }
static inline struct dev_pm_opp *dev_pm_opp_find_freq_ceil_by_volt(struct device *dev, static inline struct dev_pm_opp *dev_pm_opp_find_freq_ceil_by_volt(struct device *dev,
unsigned long u_volt) unsigned long u_volt)
{ {
return ERR_PTR(-ENOTSUPP); return ERR_PTR(-EOPNOTSUPP);
} }
static inline struct dev_pm_opp *dev_pm_opp_find_freq_ceil(struct device *dev, static inline struct dev_pm_opp *dev_pm_opp_find_freq_ceil(struct device *dev,
unsigned long *freq) unsigned long *freq)
{ {
return ERR_PTR(-ENOTSUPP); return ERR_PTR(-EOPNOTSUPP);
} }
static inline void dev_pm_opp_put(struct dev_pm_opp *opp) {} static inline void dev_pm_opp_put(struct dev_pm_opp *opp) {}
@@ -249,7 +271,7 @@ static inline void dev_pm_opp_put(struct dev_pm_opp *opp) {}
static inline int dev_pm_opp_add(struct device *dev, unsigned long freq, static inline int dev_pm_opp_add(struct device *dev, unsigned long freq,
unsigned long u_volt) unsigned long u_volt)
{ {
return -ENOTSUPP; return -EOPNOTSUPP;
} }
static inline void dev_pm_opp_remove(struct device *dev, unsigned long freq) static inline void dev_pm_opp_remove(struct device *dev, unsigned long freq)
@@ -280,19 +302,19 @@ static inline int dev_pm_opp_disable(struct device *dev, unsigned long freq)
static inline int dev_pm_opp_register_notifier(struct device *dev, struct notifier_block *nb) static inline int dev_pm_opp_register_notifier(struct device *dev, struct notifier_block *nb)
{ {
return -ENOTSUPP; return -EOPNOTSUPP;
} }
static inline int dev_pm_opp_unregister_notifier(struct device *dev, struct notifier_block *nb) static inline int dev_pm_opp_unregister_notifier(struct device *dev, struct notifier_block *nb)
{ {
return -ENOTSUPP; return -EOPNOTSUPP;
} }
static inline struct opp_table *dev_pm_opp_set_supported_hw(struct device *dev, static inline struct opp_table *dev_pm_opp_set_supported_hw(struct device *dev,
const u32 *versions, const u32 *versions,
unsigned int count) unsigned int count)
{ {
return ERR_PTR(-ENOTSUPP); return ERR_PTR(-EOPNOTSUPP);
} }
static inline void dev_pm_opp_put_supported_hw(struct opp_table *opp_table) {} static inline void dev_pm_opp_put_supported_hw(struct opp_table *opp_table) {}
@@ -300,57 +322,76 @@ static inline void dev_pm_opp_put_supported_hw(struct opp_table *opp_table) {}
static inline struct opp_table *dev_pm_opp_register_set_opp_helper(struct device *dev, static inline struct opp_table *dev_pm_opp_register_set_opp_helper(struct device *dev,
int (*set_opp)(struct dev_pm_set_opp_data *data)) int (*set_opp)(struct dev_pm_set_opp_data *data))
{ {
return ERR_PTR(-ENOTSUPP); return ERR_PTR(-EOPNOTSUPP);
} }
static inline void dev_pm_opp_unregister_set_opp_helper(struct opp_table *opp_table) {} static inline void dev_pm_opp_unregister_set_opp_helper(struct opp_table *opp_table) {}
static inline struct opp_table *
devm_pm_opp_register_set_opp_helper(struct device *dev,
int (*set_opp)(struct dev_pm_set_opp_data *data))
{
return ERR_PTR(-EOPNOTSUPP);
}
static inline struct opp_table *dev_pm_opp_set_prop_name(struct device *dev, const char *name) static inline struct opp_table *dev_pm_opp_set_prop_name(struct device *dev, const char *name)
{ {
return ERR_PTR(-ENOTSUPP); return ERR_PTR(-EOPNOTSUPP);
} }
static inline void dev_pm_opp_put_prop_name(struct opp_table *opp_table) {} static inline void dev_pm_opp_put_prop_name(struct opp_table *opp_table) {}
static inline struct opp_table *dev_pm_opp_set_regulators(struct device *dev, const char * const names[], unsigned int count) static inline struct opp_table *dev_pm_opp_set_regulators(struct device *dev, const char * const names[], unsigned int count)
{ {
return ERR_PTR(-ENOTSUPP); return ERR_PTR(-EOPNOTSUPP);
} }
static inline void dev_pm_opp_put_regulators(struct opp_table *opp_table) {} static inline void dev_pm_opp_put_regulators(struct opp_table *opp_table) {}
static inline struct opp_table *dev_pm_opp_set_clkname(struct device *dev, const char * name) static inline struct opp_table *dev_pm_opp_set_clkname(struct device *dev, const char *name)
{ {
return ERR_PTR(-ENOTSUPP); return ERR_PTR(-EOPNOTSUPP);
} }
static inline void dev_pm_opp_put_clkname(struct opp_table *opp_table) {} static inline void dev_pm_opp_put_clkname(struct opp_table *opp_table) {}
static inline struct opp_table *dev_pm_opp_attach_genpd(struct device *dev, const char **names, struct device ***virt_devs) static inline struct opp_table *dev_pm_opp_attach_genpd(struct device *dev, const char **names, struct device ***virt_devs)
{ {
return ERR_PTR(-ENOTSUPP); return ERR_PTR(-EOPNOTSUPP);
} }
static inline void dev_pm_opp_detach_genpd(struct opp_table *opp_table) {} static inline void dev_pm_opp_detach_genpd(struct opp_table *opp_table) {}
static inline struct opp_table *devm_pm_opp_attach_genpd(struct device *dev,
const char **names, struct device ***virt_devs)
{
return ERR_PTR(-EOPNOTSUPP);
}
static inline struct dev_pm_opp *dev_pm_opp_xlate_required_opp(struct opp_table *src_table,
struct opp_table *dst_table, struct dev_pm_opp *src_opp)
{
return ERR_PTR(-EOPNOTSUPP);
}
static inline int dev_pm_opp_xlate_performance_state(struct opp_table *src_table, struct opp_table *dst_table, unsigned int pstate) static inline int dev_pm_opp_xlate_performance_state(struct opp_table *src_table, struct opp_table *dst_table, unsigned int pstate)
{ {
return -ENOTSUPP; return -EOPNOTSUPP;
} }
static inline int dev_pm_opp_set_rate(struct device *dev, unsigned long target_freq) static inline int dev_pm_opp_set_rate(struct device *dev, unsigned long target_freq)
{ {
return -ENOTSUPP; return -EOPNOTSUPP;
} }
static inline int dev_pm_opp_set_bw(struct device *dev, struct dev_pm_opp *opp) static inline int dev_pm_opp_set_opp(struct device *dev, struct dev_pm_opp *opp)
{ {
return -EOPNOTSUPP; return -EOPNOTSUPP;
} }
static inline int dev_pm_opp_set_sharing_cpus(struct device *cpu_dev, const struct cpumask *cpumask) static inline int dev_pm_opp_set_sharing_cpus(struct device *cpu_dev, const struct cpumask *cpumask)
{ {
return -ENOTSUPP; return -EOPNOTSUPP;
} }
static inline int dev_pm_opp_get_sharing_cpus(struct device *cpu_dev, struct cpumask *cpumask) static inline int dev_pm_opp_get_sharing_cpus(struct device *cpu_dev, struct cpumask *cpumask)
@@ -366,11 +407,17 @@ static inline void dev_pm_opp_cpumask_remove_table(const struct cpumask *cpumask
{ {
} }
static inline int dev_pm_opp_sync_regulators(struct device *dev)
{
return -EOPNOTSUPP;
}
#endif /* CONFIG_PM_OPP */ #endif /* CONFIG_PM_OPP */
#if defined(CONFIG_PM_OPP) && defined(CONFIG_OF) #if defined(CONFIG_PM_OPP) && defined(CONFIG_OF)
int dev_pm_opp_of_add_table(struct device *dev); int dev_pm_opp_of_add_table(struct device *dev);
int dev_pm_opp_of_add_table_indexed(struct device *dev, int index); int dev_pm_opp_of_add_table_indexed(struct device *dev, int index);
int dev_pm_opp_of_add_table_noclk(struct device *dev, int index);
void dev_pm_opp_of_remove_table(struct device *dev); void dev_pm_opp_of_remove_table(struct device *dev);
int dev_pm_opp_of_cpumask_add_table(const struct cpumask *cpumask); int dev_pm_opp_of_cpumask_add_table(const struct cpumask *cpumask);
void dev_pm_opp_of_cpumask_remove_table(const struct cpumask *cpumask); void dev_pm_opp_of_cpumask_remove_table(const struct cpumask *cpumask);
@@ -387,12 +434,17 @@ static inline void dev_pm_opp_of_unregister_em(struct device *dev)
#else #else
static inline int dev_pm_opp_of_add_table(struct device *dev) static inline int dev_pm_opp_of_add_table(struct device *dev)
{ {
return -ENOTSUPP; return -EOPNOTSUPP;
} }
static inline int dev_pm_opp_of_add_table_indexed(struct device *dev, int index) static inline int dev_pm_opp_of_add_table_indexed(struct device *dev, int index)
{ {
return -ENOTSUPP; return -EOPNOTSUPP;
}
static inline int dev_pm_opp_of_add_table_noclk(struct device *dev, int index)
{
return -EOPNOTSUPP;
} }
static inline void dev_pm_opp_of_remove_table(struct device *dev) static inline void dev_pm_opp_of_remove_table(struct device *dev)
@@ -401,7 +453,7 @@ static inline void dev_pm_opp_of_remove_table(struct device *dev)
static inline int dev_pm_opp_of_cpumask_add_table(const struct cpumask *cpumask) static inline int dev_pm_opp_of_cpumask_add_table(const struct cpumask *cpumask)
{ {
return -ENOTSUPP; return -EOPNOTSUPP;
} }
static inline void dev_pm_opp_of_cpumask_remove_table(const struct cpumask *cpumask) static inline void dev_pm_opp_of_cpumask_remove_table(const struct cpumask *cpumask)
@@ -410,7 +462,7 @@ static inline void dev_pm_opp_of_cpumask_remove_table(const struct cpumask *cpum
static inline int dev_pm_opp_of_get_sharing_cpus(struct device *cpu_dev, struct cpumask *cpumask) static inline int dev_pm_opp_of_get_sharing_cpus(struct device *cpu_dev, struct cpumask *cpumask)
{ {
return -ENOTSUPP; return -EOPNOTSUPP;
} }
static inline struct device_node *dev_pm_opp_of_get_opp_desc_node(struct device *dev) static inline struct device_node *dev_pm_opp_of_get_opp_desc_node(struct device *dev)
@@ -426,7 +478,7 @@ static inline struct device_node *dev_pm_opp_get_of_node(struct dev_pm_opp *opp)
static inline int dev_pm_opp_of_register_em(struct device *dev, static inline int dev_pm_opp_of_register_em(struct device *dev,
struct cpumask *cpus) struct cpumask *cpus)
{ {
return -ENOTSUPP; return -EOPNOTSUPP;
} }
static inline void dev_pm_opp_of_unregister_em(struct device *dev) static inline void dev_pm_opp_of_unregister_em(struct device *dev)
@@ -435,12 +487,12 @@ static inline void dev_pm_opp_of_unregister_em(struct device *dev)
static inline int of_get_required_opp_performance_state(struct device_node *np, int index) static inline int of_get_required_opp_performance_state(struct device_node *np, int index)
{ {
return -ENOTSUPP; return -EOPNOTSUPP;
} }
static inline int dev_pm_opp_of_find_icc_paths(struct device *dev, struct opp_table *opp_table) static inline int dev_pm_opp_of_find_icc_paths(struct device *dev, struct opp_table *opp_table)
{ {
return -ENOTSUPP; return -EOPNOTSUPP;
} }
#endif #endif