Merge branch 'opp/linux-next' of git://git.kernel.org/pub/scm/linux/kernel/git/vireshk/pm
Pull operating performance points (OPP) framework changes for 5.4 from Viresh Kumar: "This contains: - OPP core fixes to better support genpd devices (Viresh Kumar). - OPP core changes to support multiple suspend-opps in DT (Anson Huang). - New OPP API (dev_pm_opp_find_level_exact()) and Qcom OPP binding changes for CPR (Niklas Cassel). - Qcom minor update (Sricharan R). - OPP Documentation fix (Yue Hu). - OPP core support to enable/disable regulators (k.konieczny)." * 'opp/linux-next' of git://git.kernel.org/pub/scm/linux/kernel/git/vireshk/pm: dt-bindings: opp: Add qcom-opp bindings with properties needed for CPR dt-bindings: opp: qcom-nvmem: Support pstates provided by a power domain dt-bindings: opp: qcom-nvmem: Make speedbin related properties optional dt-bindings: opp: Re-organise kryo cpufreq to use it for other nvmem based qcom socs PM / OPP: Correct Documentation about library location opp: of: Support multiple suspend OPPs defined in DT dt-bindings: opp: Support multiple opp-suspend properties opp: core: add regulators enable and disable opp: Don't decrement uninitialized list_kref opp: Add dev_pm_opp_find_level_exact() opp: Return genpd virtual devices from dev_pm_opp_attach_genpd() opp: Not all power-domains are scalable
This commit is contained in:
commit
e47bc756ad
|
@ -140,8 +140,8 @@ Optional properties:
|
||||||
frequency for a short duration of time limited by the device's power, current
|
frequency for a short duration of time limited by the device's power, current
|
||||||
and thermal limits.
|
and thermal limits.
|
||||||
|
|
||||||
- opp-suspend: Marks the OPP to be used during device suspend. Only one OPP in
|
- opp-suspend: Marks the OPP to be used during device suspend. If multiple OPPs
|
||||||
the table should have this.
|
in the table have this, the OPP with highest opp-hz will be used.
|
||||||
|
|
||||||
- opp-supported-hw: This enables us to select only a subset of OPPs from the
|
- opp-supported-hw: This enables us to select only a subset of OPPs from the
|
||||||
larger OPP table, based on what version of the hardware we are running on. We
|
larger OPP table, based on what version of the hardware we are running on. We
|
||||||
|
|
|
@ -1,25 +1,38 @@
|
||||||
Qualcomm Technologies, Inc. KRYO CPUFreq and OPP bindings
|
Qualcomm Technologies, Inc. NVMEM CPUFreq and OPP bindings
|
||||||
===================================
|
===================================
|
||||||
|
|
||||||
In Certain Qualcomm Technologies, Inc. SoCs like apq8096 and msm8996
|
In Certain Qualcomm Technologies, Inc. SoCs like apq8096 and msm8996,
|
||||||
that have KRYO processors, the CPU ferequencies subset and voltage value
|
the CPU frequencies subset and voltage value of each OPP varies based on
|
||||||
of each OPP varies based on the silicon variant in use.
|
the silicon variant in use.
|
||||||
Qualcomm Technologies, Inc. Process Voltage Scaling Tables
|
Qualcomm Technologies, Inc. Process Voltage Scaling Tables
|
||||||
defines the voltage and frequency value based on the msm-id in SMEM
|
defines the voltage and frequency value based on the msm-id in SMEM
|
||||||
and speedbin blown in the efuse combination.
|
and speedbin blown in the efuse combination.
|
||||||
The qcom-cpufreq-kryo driver reads the msm-id and efuse value from the SoC
|
The qcom-cpufreq-nvmem driver reads the msm-id and efuse value from the SoC
|
||||||
to provide the OPP framework with required information (existing HW bitmap).
|
to provide the OPP framework with required information (existing HW bitmap).
|
||||||
This is used to determine the voltage and frequency value for each OPP of
|
This is used to determine the voltage and frequency value for each OPP of
|
||||||
operating-points-v2 table when it is parsed by the OPP framework.
|
operating-points-v2 table when it is parsed by the OPP framework.
|
||||||
|
|
||||||
Required properties:
|
Required properties:
|
||||||
--------------------
|
--------------------
|
||||||
In 'cpus' nodes:
|
In 'cpu' nodes:
|
||||||
- operating-points-v2: Phandle to the operating-points-v2 table to use.
|
- operating-points-v2: Phandle to the operating-points-v2 table to use.
|
||||||
|
|
||||||
In 'operating-points-v2' table:
|
In 'operating-points-v2' table:
|
||||||
- compatible: Should be
|
- compatible: Should be
|
||||||
- 'operating-points-v2-kryo-cpu' for apq8096 and msm8996.
|
- 'operating-points-v2-kryo-cpu' for apq8096 and msm8996.
|
||||||
|
|
||||||
|
Optional properties:
|
||||||
|
--------------------
|
||||||
|
In 'cpu' nodes:
|
||||||
|
- power-domains: A phandle pointing to the PM domain specifier which provides
|
||||||
|
the performance states available for active state management.
|
||||||
|
Please refer to the power-domains bindings
|
||||||
|
Documentation/devicetree/bindings/power/power_domain.txt
|
||||||
|
and also examples below.
|
||||||
|
- power-domain-names: Should be
|
||||||
|
- 'cpr' for qcs404.
|
||||||
|
|
||||||
|
In 'operating-points-v2' table:
|
||||||
- nvmem-cells: A phandle pointing to a nvmem-cells node representing the
|
- nvmem-cells: A phandle pointing to a nvmem-cells node representing the
|
||||||
efuse registers that has information about the
|
efuse registers that has information about the
|
||||||
speedbin that is used to select the right frequency/voltage
|
speedbin that is used to select the right frequency/voltage
|
||||||
|
@ -678,3 +691,105 @@ soc {
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
Example 2:
|
||||||
|
---------
|
||||||
|
|
||||||
|
cpus {
|
||||||
|
#address-cells = <1>;
|
||||||
|
#size-cells = <0>;
|
||||||
|
|
||||||
|
CPU0: cpu@100 {
|
||||||
|
device_type = "cpu";
|
||||||
|
compatible = "arm,cortex-a53";
|
||||||
|
reg = <0x100>;
|
||||||
|
....
|
||||||
|
clocks = <&apcs_glb>;
|
||||||
|
operating-points-v2 = <&cpu_opp_table>;
|
||||||
|
power-domains = <&cpr>;
|
||||||
|
power-domain-names = "cpr";
|
||||||
|
};
|
||||||
|
|
||||||
|
CPU1: cpu@101 {
|
||||||
|
device_type = "cpu";
|
||||||
|
compatible = "arm,cortex-a53";
|
||||||
|
reg = <0x101>;
|
||||||
|
....
|
||||||
|
clocks = <&apcs_glb>;
|
||||||
|
operating-points-v2 = <&cpu_opp_table>;
|
||||||
|
power-domains = <&cpr>;
|
||||||
|
power-domain-names = "cpr";
|
||||||
|
};
|
||||||
|
|
||||||
|
CPU2: cpu@102 {
|
||||||
|
device_type = "cpu";
|
||||||
|
compatible = "arm,cortex-a53";
|
||||||
|
reg = <0x102>;
|
||||||
|
....
|
||||||
|
clocks = <&apcs_glb>;
|
||||||
|
operating-points-v2 = <&cpu_opp_table>;
|
||||||
|
power-domains = <&cpr>;
|
||||||
|
power-domain-names = "cpr";
|
||||||
|
};
|
||||||
|
|
||||||
|
CPU3: cpu@103 {
|
||||||
|
device_type = "cpu";
|
||||||
|
compatible = "arm,cortex-a53";
|
||||||
|
reg = <0x103>;
|
||||||
|
....
|
||||||
|
clocks = <&apcs_glb>;
|
||||||
|
operating-points-v2 = <&cpu_opp_table>;
|
||||||
|
power-domains = <&cpr>;
|
||||||
|
power-domain-names = "cpr";
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
cpu_opp_table: cpu-opp-table {
|
||||||
|
compatible = "operating-points-v2-kryo-cpu";
|
||||||
|
opp-shared;
|
||||||
|
|
||||||
|
opp-1094400000 {
|
||||||
|
opp-hz = /bits/ 64 <1094400000>;
|
||||||
|
required-opps = <&cpr_opp1>;
|
||||||
|
};
|
||||||
|
opp-1248000000 {
|
||||||
|
opp-hz = /bits/ 64 <1248000000>;
|
||||||
|
required-opps = <&cpr_opp2>;
|
||||||
|
};
|
||||||
|
opp-1401600000 {
|
||||||
|
opp-hz = /bits/ 64 <1401600000>;
|
||||||
|
required-opps = <&cpr_opp3>;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
cpr_opp_table: cpr-opp-table {
|
||||||
|
compatible = "operating-points-v2-qcom-level";
|
||||||
|
|
||||||
|
cpr_opp1: opp1 {
|
||||||
|
opp-level = <1>;
|
||||||
|
qcom,opp-fuse-level = <1>;
|
||||||
|
};
|
||||||
|
cpr_opp2: opp2 {
|
||||||
|
opp-level = <2>;
|
||||||
|
qcom,opp-fuse-level = <2>;
|
||||||
|
};
|
||||||
|
cpr_opp3: opp3 {
|
||||||
|
opp-level = <3>;
|
||||||
|
qcom,opp-fuse-level = <3>;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
....
|
||||||
|
|
||||||
|
soc {
|
||||||
|
....
|
||||||
|
cpr: power-controller@b018000 {
|
||||||
|
compatible = "qcom,qcs404-cpr", "qcom,cpr";
|
||||||
|
reg = <0x0b018000 0x1000>;
|
||||||
|
....
|
||||||
|
vdd-apc-supply = <&pms405_s3>;
|
||||||
|
#power-domain-cells = <0>;
|
||||||
|
operating-points-v2 = <&cpr_opp_table>;
|
||||||
|
....
|
||||||
|
};
|
||||||
|
};
|
|
@ -0,0 +1,19 @@
|
||||||
|
Qualcomm OPP bindings to describe OPP nodes
|
||||||
|
|
||||||
|
The bindings are based on top of the operating-points-v2 bindings
|
||||||
|
described in Documentation/devicetree/bindings/opp/opp.txt
|
||||||
|
Additional properties are described below.
|
||||||
|
|
||||||
|
* OPP Table Node
|
||||||
|
|
||||||
|
Required properties:
|
||||||
|
- compatible: Allow OPPs to express their compatibility. It should be:
|
||||||
|
"operating-points-v2-qcom-level"
|
||||||
|
|
||||||
|
* OPP Node
|
||||||
|
|
||||||
|
Required properties:
|
||||||
|
- qcom,opp-fuse-level: A positive value representing the fuse corner/level
|
||||||
|
associated with this OPP node. Sometimes several corners/levels shares
|
||||||
|
a certain fuse corner/level. A fuse corner/level contains e.g. ref uV,
|
||||||
|
min uV, and max uV.
|
|
@ -46,7 +46,7 @@ We can represent these as three OPPs as the following {Hz, uV} tuples:
|
||||||
----------------------------------------
|
----------------------------------------
|
||||||
|
|
||||||
OPP library provides a set of helper functions to organize and query the OPP
|
OPP library provides a set of helper functions to organize and query the OPP
|
||||||
information. The library is located in drivers/base/power/opp.c and the header
|
information. The library is located in drivers/opp/ directory and the header
|
||||||
is located in include/linux/pm_opp.h. OPP library can be enabled by enabling
|
is located in include/linux/pm_opp.h. OPP library can be enabled by enabling
|
||||||
CONFIG_PM_OPP from power management menuconfig menu. OPP library depends on
|
CONFIG_PM_OPP from power management menuconfig menu. OPP library depends on
|
||||||
CONFIG_PM as certain SoCs such as Texas Instrument's OMAP framework allows to
|
CONFIG_PM as certain SoCs such as Texas Instrument's OMAP framework allows to
|
||||||
|
|
|
@ -401,6 +401,54 @@ struct dev_pm_opp *dev_pm_opp_find_freq_exact(struct device *dev,
|
||||||
}
|
}
|
||||||
EXPORT_SYMBOL_GPL(dev_pm_opp_find_freq_exact);
|
EXPORT_SYMBOL_GPL(dev_pm_opp_find_freq_exact);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* dev_pm_opp_find_level_exact() - search for an exact level
|
||||||
|
* @dev: device for which we do this operation
|
||||||
|
* @level: level to search for
|
||||||
|
*
|
||||||
|
* Return: Searches for exact match in the opp table and returns pointer to the
|
||||||
|
* matching opp if found, else returns ERR_PTR in case of error and should
|
||||||
|
* be handled using IS_ERR. Error return values can be:
|
||||||
|
* EINVAL: for bad pointer
|
||||||
|
* ERANGE: no match found for search
|
||||||
|
* ENODEV: if device not found in list of registered devices
|
||||||
|
*
|
||||||
|
* The callers are required to call dev_pm_opp_put() for the returned OPP after
|
||||||
|
* use.
|
||||||
|
*/
|
||||||
|
struct dev_pm_opp *dev_pm_opp_find_level_exact(struct device *dev,
|
||||||
|
unsigned int level)
|
||||||
|
{
|
||||||
|
struct opp_table *opp_table;
|
||||||
|
struct dev_pm_opp *temp_opp, *opp = ERR_PTR(-ERANGE);
|
||||||
|
|
||||||
|
opp_table = _find_opp_table(dev);
|
||||||
|
if (IS_ERR(opp_table)) {
|
||||||
|
int r = PTR_ERR(opp_table);
|
||||||
|
|
||||||
|
dev_err(dev, "%s: OPP table not found (%d)\n", __func__, r);
|
||||||
|
return ERR_PTR(r);
|
||||||
|
}
|
||||||
|
|
||||||
|
mutex_lock(&opp_table->lock);
|
||||||
|
|
||||||
|
list_for_each_entry(temp_opp, &opp_table->opp_list, node) {
|
||||||
|
if (temp_opp->level == level) {
|
||||||
|
opp = temp_opp;
|
||||||
|
|
||||||
|
/* Increment the reference count of OPP */
|
||||||
|
dev_pm_opp_get(opp);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
mutex_unlock(&opp_table->lock);
|
||||||
|
dev_pm_opp_put_opp_table(opp_table);
|
||||||
|
|
||||||
|
return opp;
|
||||||
|
}
|
||||||
|
EXPORT_SYMBOL_GPL(dev_pm_opp_find_level_exact);
|
||||||
|
|
||||||
static noinline struct dev_pm_opp *_find_freq_ceil(struct opp_table *opp_table,
|
static noinline struct dev_pm_opp *_find_freq_ceil(struct opp_table *opp_table,
|
||||||
unsigned long *freq)
|
unsigned long *freq)
|
||||||
{
|
{
|
||||||
|
@ -940,6 +988,7 @@ static struct opp_table *_allocate_opp_table(struct device *dev, int index)
|
||||||
BLOCKING_INIT_NOTIFIER_HEAD(&opp_table->head);
|
BLOCKING_INIT_NOTIFIER_HEAD(&opp_table->head);
|
||||||
INIT_LIST_HEAD(&opp_table->opp_list);
|
INIT_LIST_HEAD(&opp_table->opp_list);
|
||||||
kref_init(&opp_table->kref);
|
kref_init(&opp_table->kref);
|
||||||
|
kref_init(&opp_table->list_kref);
|
||||||
|
|
||||||
/* Secure the device table modification */
|
/* Secure the device table modification */
|
||||||
list_add(&opp_table->node, &opp_tables);
|
list_add(&opp_table->node, &opp_tables);
|
||||||
|
@ -1577,6 +1626,12 @@ struct opp_table *dev_pm_opp_set_regulators(struct device *dev,
|
||||||
goto free_regulators;
|
goto free_regulators;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ret = regulator_enable(reg);
|
||||||
|
if (ret < 0) {
|
||||||
|
regulator_put(reg);
|
||||||
|
goto free_regulators;
|
||||||
|
}
|
||||||
|
|
||||||
opp_table->regulators[i] = reg;
|
opp_table->regulators[i] = reg;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1590,8 +1645,10 @@ struct opp_table *dev_pm_opp_set_regulators(struct device *dev,
|
||||||
return opp_table;
|
return opp_table;
|
||||||
|
|
||||||
free_regulators:
|
free_regulators:
|
||||||
while (i != 0)
|
while (i--) {
|
||||||
regulator_put(opp_table->regulators[--i]);
|
regulator_disable(opp_table->regulators[i]);
|
||||||
|
regulator_put(opp_table->regulators[i]);
|
||||||
|
}
|
||||||
|
|
||||||
kfree(opp_table->regulators);
|
kfree(opp_table->regulators);
|
||||||
opp_table->regulators = NULL;
|
opp_table->regulators = NULL;
|
||||||
|
@ -1617,8 +1674,10 @@ void dev_pm_opp_put_regulators(struct opp_table *opp_table)
|
||||||
/* Make sure there are no concurrent readers while updating opp_table */
|
/* Make sure there are no concurrent readers while updating opp_table */
|
||||||
WARN_ON(!list_empty(&opp_table->opp_list));
|
WARN_ON(!list_empty(&opp_table->opp_list));
|
||||||
|
|
||||||
for (i = opp_table->regulator_count - 1; i >= 0; i--)
|
for (i = opp_table->regulator_count - 1; i >= 0; i--) {
|
||||||
|
regulator_disable(opp_table->regulators[i]);
|
||||||
regulator_put(opp_table->regulators[i]);
|
regulator_put(opp_table->regulators[i]);
|
||||||
|
}
|
||||||
|
|
||||||
_free_set_opp_data(opp_table);
|
_free_set_opp_data(opp_table);
|
||||||
|
|
||||||
|
@ -1771,6 +1830,7 @@ static void _opp_detach_genpd(struct opp_table *opp_table)
|
||||||
* dev_pm_opp_attach_genpd - Attach genpd(s) for the device and save virtual device pointer
|
* dev_pm_opp_attach_genpd - Attach genpd(s) for the device and save virtual device pointer
|
||||||
* @dev: Consumer device for which the genpd is getting attached.
|
* @dev: Consumer device for which the genpd is getting attached.
|
||||||
* @names: Null terminated array of pointers containing names of genpd to attach.
|
* @names: Null terminated array of pointers containing names of genpd to attach.
|
||||||
|
* @virt_devs: Pointer to return the array of virtual devices.
|
||||||
*
|
*
|
||||||
* Multiple generic power domains for a device are supported with the help of
|
* Multiple generic power domains for a device are supported with the help of
|
||||||
* virtual genpd devices, which are created for each consumer device - genpd
|
* virtual genpd devices, which are created for each consumer device - genpd
|
||||||
|
@ -1784,12 +1844,16 @@ static void _opp_detach_genpd(struct opp_table *opp_table)
|
||||||
*
|
*
|
||||||
* This helper needs to be called once with a list of all genpd to attach.
|
* This helper needs to be called once with a list of all genpd to attach.
|
||||||
* Otherwise the original device structure will be used instead by the OPP core.
|
* Otherwise the original device structure will be used instead by the OPP core.
|
||||||
|
*
|
||||||
|
* The order of entries in the names array must match the order in which
|
||||||
|
* "required-opps" are added in DT.
|
||||||
*/
|
*/
|
||||||
struct opp_table *dev_pm_opp_attach_genpd(struct device *dev, const char **names)
|
struct opp_table *dev_pm_opp_attach_genpd(struct device *dev,
|
||||||
|
const char **names, struct device ***virt_devs)
|
||||||
{
|
{
|
||||||
struct opp_table *opp_table;
|
struct opp_table *opp_table;
|
||||||
struct device *virt_dev;
|
struct device *virt_dev;
|
||||||
int index, ret = -EINVAL;
|
int index = 0, ret = -EINVAL;
|
||||||
const char **name = names;
|
const char **name = names;
|
||||||
|
|
||||||
opp_table = dev_pm_opp_get_opp_table(dev);
|
opp_table = dev_pm_opp_get_opp_table(dev);
|
||||||
|
@ -1815,14 +1879,6 @@ struct opp_table *dev_pm_opp_attach_genpd(struct device *dev, const char **names
|
||||||
goto unlock;
|
goto unlock;
|
||||||
|
|
||||||
while (*name) {
|
while (*name) {
|
||||||
index = of_property_match_string(dev->of_node,
|
|
||||||
"power-domain-names", *name);
|
|
||||||
if (index < 0) {
|
|
||||||
dev_err(dev, "Failed to find power domain: %s (%d)\n",
|
|
||||||
*name, index);
|
|
||||||
goto err;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (index >= opp_table->required_opp_count) {
|
if (index >= opp_table->required_opp_count) {
|
||||||
dev_err(dev, "Index can't be greater than required-opp-count - 1, %s (%d : %d)\n",
|
dev_err(dev, "Index can't be greater than required-opp-count - 1, %s (%d : %d)\n",
|
||||||
*name, opp_table->required_opp_count, index);
|
*name, opp_table->required_opp_count, index);
|
||||||
|
@ -1843,9 +1899,12 @@ struct opp_table *dev_pm_opp_attach_genpd(struct device *dev, const char **names
|
||||||
}
|
}
|
||||||
|
|
||||||
opp_table->genpd_virt_devs[index] = virt_dev;
|
opp_table->genpd_virt_devs[index] = virt_dev;
|
||||||
|
index++;
|
||||||
name++;
|
name++;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (virt_devs)
|
||||||
|
*virt_devs = opp_table->genpd_virt_devs;
|
||||||
mutex_unlock(&opp_table->genpd_virt_dev_lock);
|
mutex_unlock(&opp_table->genpd_virt_dev_lock);
|
||||||
|
|
||||||
return opp_table;
|
return opp_table;
|
||||||
|
|
|
@ -617,9 +617,12 @@ static struct dev_pm_opp *_opp_add_static_v2(struct opp_table *opp_table,
|
||||||
/* OPP to select on device suspend */
|
/* OPP to select on device suspend */
|
||||||
if (of_property_read_bool(np, "opp-suspend")) {
|
if (of_property_read_bool(np, "opp-suspend")) {
|
||||||
if (opp_table->suspend_opp) {
|
if (opp_table->suspend_opp) {
|
||||||
dev_warn(dev, "%s: Multiple suspend OPPs found (%lu %lu)\n",
|
/* Pick the OPP with higher rate as suspend OPP */
|
||||||
__func__, opp_table->suspend_opp->rate,
|
if (new_opp->rate > opp_table->suspend_opp->rate) {
|
||||||
new_opp->rate);
|
opp_table->suspend_opp->suspend = false;
|
||||||
|
new_opp->suspend = true;
|
||||||
|
opp_table->suspend_opp = new_opp;
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
new_opp->suspend = true;
|
new_opp->suspend = true;
|
||||||
opp_table->suspend_opp = new_opp;
|
opp_table->suspend_opp = new_opp;
|
||||||
|
@ -662,8 +665,6 @@ static int _of_add_opp_table_v2(struct device *dev, struct opp_table *opp_table)
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
kref_init(&opp_table->list_kref);
|
|
||||||
|
|
||||||
/* We have opp-table node now, iterate over it and add OPPs */
|
/* We have opp-table node now, iterate over it and add OPPs */
|
||||||
for_each_available_child_of_node(opp_table->np, np) {
|
for_each_available_child_of_node(opp_table->np, np) {
|
||||||
opp = _opp_add_static_v2(opp_table, dev, np);
|
opp = _opp_add_static_v2(opp_table, dev, np);
|
||||||
|
@ -672,17 +673,15 @@ static int _of_add_opp_table_v2(struct device *dev, struct opp_table *opp_table)
|
||||||
dev_err(dev, "%s: Failed to add OPP, %d\n", __func__,
|
dev_err(dev, "%s: Failed to add OPP, %d\n", __func__,
|
||||||
ret);
|
ret);
|
||||||
of_node_put(np);
|
of_node_put(np);
|
||||||
goto put_list_kref;
|
return ret;
|
||||||
} else if (opp) {
|
} else if (opp) {
|
||||||
count++;
|
count++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* There should be one of more OPP defined */
|
/* There should be one of more OPP defined */
|
||||||
if (WARN_ON(!count)) {
|
if (WARN_ON(!count))
|
||||||
ret = -ENOENT;
|
return -ENOENT;
|
||||||
goto put_list_kref;
|
|
||||||
}
|
|
||||||
|
|
||||||
list_for_each_entry(opp, &opp_table->opp_list, node)
|
list_for_each_entry(opp, &opp_table->opp_list, node)
|
||||||
pstate_count += !!opp->pstate;
|
pstate_count += !!opp->pstate;
|
||||||
|
@ -691,8 +690,7 @@ static int _of_add_opp_table_v2(struct device *dev, struct opp_table *opp_table)
|
||||||
if (pstate_count && pstate_count != count) {
|
if (pstate_count && pstate_count != count) {
|
||||||
dev_err(dev, "Not all nodes have performance state set (%d: %d)\n",
|
dev_err(dev, "Not all nodes have performance state set (%d: %d)\n",
|
||||||
count, pstate_count);
|
count, pstate_count);
|
||||||
ret = -ENOENT;
|
return -ENOENT;
|
||||||
goto put_list_kref;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (pstate_count)
|
if (pstate_count)
|
||||||
|
@ -701,11 +699,6 @@ static int _of_add_opp_table_v2(struct device *dev, struct opp_table *opp_table)
|
||||||
opp_table->parsed_static_opps = true;
|
opp_table->parsed_static_opps = true;
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
put_list_kref:
|
|
||||||
_put_opp_list_kref(opp_table);
|
|
||||||
|
|
||||||
return ret;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Initializes OPP tables based on old-deprecated bindings */
|
/* Initializes OPP tables based on old-deprecated bindings */
|
||||||
|
@ -731,8 +724,6 @@ static int _of_add_opp_table_v1(struct device *dev, struct opp_table *opp_table)
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
}
|
}
|
||||||
|
|
||||||
kref_init(&opp_table->list_kref);
|
|
||||||
|
|
||||||
val = prop->value;
|
val = prop->value;
|
||||||
while (nr) {
|
while (nr) {
|
||||||
unsigned long freq = be32_to_cpup(val++) * 1000;
|
unsigned long freq = be32_to_cpup(val++) * 1000;
|
||||||
|
@ -742,7 +733,6 @@ static int _of_add_opp_table_v1(struct device *dev, struct opp_table *opp_table)
|
||||||
if (ret) {
|
if (ret) {
|
||||||
dev_err(dev, "%s: Failed to add OPP %ld (%d)\n",
|
dev_err(dev, "%s: Failed to add OPP %ld (%d)\n",
|
||||||
__func__, freq, ret);
|
__func__, freq, ret);
|
||||||
_put_opp_list_kref(opp_table);
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
nr -= 2;
|
nr -= 2;
|
||||||
|
|
|
@ -96,6 +96,8 @@ unsigned long dev_pm_opp_get_suspend_opp_freq(struct device *dev);
|
||||||
struct dev_pm_opp *dev_pm_opp_find_freq_exact(struct device *dev,
|
struct dev_pm_opp *dev_pm_opp_find_freq_exact(struct device *dev,
|
||||||
unsigned long freq,
|
unsigned long freq,
|
||||||
bool available);
|
bool available);
|
||||||
|
struct dev_pm_opp *dev_pm_opp_find_level_exact(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);
|
||||||
|
@ -128,7 +130,7 @@ 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 *dev_pm_opp_attach_genpd(struct device *dev, const char **names);
|
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);
|
||||||
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);
|
||||||
|
@ -200,6 +202,12 @@ static inline struct dev_pm_opp *dev_pm_opp_find_freq_exact(struct device *dev,
|
||||||
return ERR_PTR(-ENOTSUPP);
|
return ERR_PTR(-ENOTSUPP);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static inline struct dev_pm_opp *dev_pm_opp_find_level_exact(struct device *dev,
|
||||||
|
unsigned int level)
|
||||||
|
{
|
||||||
|
return ERR_PTR(-ENOTSUPP);
|
||||||
|
}
|
||||||
|
|
||||||
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)
|
||||||
{
|
{
|
||||||
|
@ -292,7 +300,7 @@ static inline struct opp_table *dev_pm_opp_set_clkname(struct device *dev, const
|
||||||
|
|
||||||
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)
|
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(-ENOTSUPP);
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue