Merge OPP material for v4.11 to satisfy dependencies.
This commit is contained in:
commit
40e993aa04
|
@ -79,22 +79,6 @@ dependent subsystems such as cpufreq are left to the discretion of the SoC
|
||||||
specific framework which uses the OPP library. Similar care needs to be taken
|
specific framework which uses the OPP library. Similar care needs to be taken
|
||||||
care to refresh the cpufreq table in cases of these operations.
|
care to refresh the cpufreq table in cases of these operations.
|
||||||
|
|
||||||
WARNING on OPP List locking mechanism:
|
|
||||||
-------------------------------------------------
|
|
||||||
OPP library uses RCU for exclusivity. RCU allows the query functions to operate
|
|
||||||
in multiple contexts and this synchronization mechanism is optimal for a read
|
|
||||||
intensive operations on data structure as the OPP library caters to.
|
|
||||||
|
|
||||||
To ensure that the data retrieved are sane, the users such as SoC framework
|
|
||||||
should ensure that the section of code operating on OPP queries are locked
|
|
||||||
using RCU read locks. The opp_find_freq_{exact,ceil,floor},
|
|
||||||
opp_get_{voltage, freq, opp_count} fall into this category.
|
|
||||||
|
|
||||||
opp_{add,enable,disable} are updaters which use mutex and implement it's own
|
|
||||||
RCU locking mechanisms. These functions should *NOT* be called under RCU locks
|
|
||||||
and other contexts that prevent blocking functions in RCU or mutex operations
|
|
||||||
from working.
|
|
||||||
|
|
||||||
2. Initial OPP List Registration
|
2. Initial OPP List Registration
|
||||||
================================
|
================================
|
||||||
The SoC implementation calls dev_pm_opp_add function iteratively to add OPPs per
|
The SoC implementation calls dev_pm_opp_add function iteratively to add OPPs per
|
||||||
|
@ -137,15 +121,18 @@ functions return the matching pointer representing the opp if a match is
|
||||||
found, else returns error. These errors are expected to be handled by standard
|
found, else returns error. These errors are expected to be handled by standard
|
||||||
error checks such as IS_ERR() and appropriate actions taken by the caller.
|
error checks such as IS_ERR() and appropriate actions taken by the caller.
|
||||||
|
|
||||||
|
Callers of these functions shall call dev_pm_opp_put() after they have used the
|
||||||
|
OPP. Otherwise the memory for the OPP will never get freed and result in
|
||||||
|
memleak.
|
||||||
|
|
||||||
dev_pm_opp_find_freq_exact - Search for an OPP based on an *exact* frequency and
|
dev_pm_opp_find_freq_exact - Search for an OPP based on an *exact* frequency and
|
||||||
availability. This function is especially useful to enable an OPP which
|
availability. This function is especially useful to enable an OPP which
|
||||||
is not available by default.
|
is not available by default.
|
||||||
Example: In a case when SoC framework detects a situation where a
|
Example: In a case when SoC framework detects a situation where a
|
||||||
higher frequency could be made available, it can use this function to
|
higher frequency could be made available, it can use this function to
|
||||||
find the OPP prior to call the dev_pm_opp_enable to actually make it available.
|
find the OPP prior to call the dev_pm_opp_enable to actually make it available.
|
||||||
rcu_read_lock();
|
|
||||||
opp = dev_pm_opp_find_freq_exact(dev, 1000000000, false);
|
opp = dev_pm_opp_find_freq_exact(dev, 1000000000, false);
|
||||||
rcu_read_unlock();
|
dev_pm_opp_put(opp);
|
||||||
/* dont operate on the pointer.. just do a sanity check.. */
|
/* dont operate on the pointer.. just do a sanity check.. */
|
||||||
if (IS_ERR(opp)) {
|
if (IS_ERR(opp)) {
|
||||||
pr_err("frequency not disabled!\n");
|
pr_err("frequency not disabled!\n");
|
||||||
|
@ -163,9 +150,8 @@ dev_pm_opp_find_freq_floor - Search for an available OPP which is *at most* the
|
||||||
frequency.
|
frequency.
|
||||||
Example: To find the highest opp for a device:
|
Example: To find the highest opp for a device:
|
||||||
freq = ULONG_MAX;
|
freq = ULONG_MAX;
|
||||||
rcu_read_lock();
|
opp = dev_pm_opp_find_freq_floor(dev, &freq);
|
||||||
dev_pm_opp_find_freq_floor(dev, &freq);
|
dev_pm_opp_put(opp);
|
||||||
rcu_read_unlock();
|
|
||||||
|
|
||||||
dev_pm_opp_find_freq_ceil - Search for an available OPP which is *at least* the
|
dev_pm_opp_find_freq_ceil - Search for an available OPP which is *at least* the
|
||||||
provided frequency. This function is useful while searching for a
|
provided frequency. This function is useful while searching for a
|
||||||
|
@ -173,17 +159,15 @@ dev_pm_opp_find_freq_ceil - Search for an available OPP which is *at least* the
|
||||||
frequency.
|
frequency.
|
||||||
Example 1: To find the lowest opp for a device:
|
Example 1: To find the lowest opp for a device:
|
||||||
freq = 0;
|
freq = 0;
|
||||||
rcu_read_lock();
|
opp = dev_pm_opp_find_freq_ceil(dev, &freq);
|
||||||
dev_pm_opp_find_freq_ceil(dev, &freq);
|
dev_pm_opp_put(opp);
|
||||||
rcu_read_unlock();
|
|
||||||
Example 2: A simplified implementation of a SoC cpufreq_driver->target:
|
Example 2: A simplified implementation of a SoC cpufreq_driver->target:
|
||||||
soc_cpufreq_target(..)
|
soc_cpufreq_target(..)
|
||||||
{
|
{
|
||||||
/* Do stuff like policy checks etc. */
|
/* Do stuff like policy checks etc. */
|
||||||
/* Find the best frequency match for the req */
|
/* Find the best frequency match for the req */
|
||||||
rcu_read_lock();
|
|
||||||
opp = dev_pm_opp_find_freq_ceil(dev, &freq);
|
opp = dev_pm_opp_find_freq_ceil(dev, &freq);
|
||||||
rcu_read_unlock();
|
dev_pm_opp_put(opp);
|
||||||
if (!IS_ERR(opp))
|
if (!IS_ERR(opp))
|
||||||
soc_switch_to_freq_voltage(freq);
|
soc_switch_to_freq_voltage(freq);
|
||||||
else
|
else
|
||||||
|
@ -208,9 +192,8 @@ dev_pm_opp_enable - Make a OPP available for operation.
|
||||||
implementation might choose to do something as follows:
|
implementation might choose to do something as follows:
|
||||||
if (cur_temp < temp_low_thresh) {
|
if (cur_temp < temp_low_thresh) {
|
||||||
/* Enable 1GHz if it was disabled */
|
/* Enable 1GHz if it was disabled */
|
||||||
rcu_read_lock();
|
|
||||||
opp = dev_pm_opp_find_freq_exact(dev, 1000000000, false);
|
opp = dev_pm_opp_find_freq_exact(dev, 1000000000, false);
|
||||||
rcu_read_unlock();
|
dev_pm_opp_put(opp);
|
||||||
/* just error check */
|
/* just error check */
|
||||||
if (!IS_ERR(opp))
|
if (!IS_ERR(opp))
|
||||||
ret = dev_pm_opp_enable(dev, 1000000000);
|
ret = dev_pm_opp_enable(dev, 1000000000);
|
||||||
|
@ -224,9 +207,8 @@ dev_pm_opp_disable - Make an OPP to be not available for operation
|
||||||
choose to do something as follows:
|
choose to do something as follows:
|
||||||
if (cur_temp > temp_high_thresh) {
|
if (cur_temp > temp_high_thresh) {
|
||||||
/* Disable 1GHz if it was enabled */
|
/* Disable 1GHz if it was enabled */
|
||||||
rcu_read_lock();
|
|
||||||
opp = dev_pm_opp_find_freq_exact(dev, 1000000000, true);
|
opp = dev_pm_opp_find_freq_exact(dev, 1000000000, true);
|
||||||
rcu_read_unlock();
|
dev_pm_opp_put(opp);
|
||||||
/* just error check */
|
/* just error check */
|
||||||
if (!IS_ERR(opp))
|
if (!IS_ERR(opp))
|
||||||
ret = dev_pm_opp_disable(dev, 1000000000);
|
ret = dev_pm_opp_disable(dev, 1000000000);
|
||||||
|
@ -249,10 +231,9 @@ dev_pm_opp_get_voltage - Retrieve the voltage represented by the opp pointer.
|
||||||
soc_switch_to_freq_voltage(freq)
|
soc_switch_to_freq_voltage(freq)
|
||||||
{
|
{
|
||||||
/* do things */
|
/* do things */
|
||||||
rcu_read_lock();
|
|
||||||
opp = dev_pm_opp_find_freq_ceil(dev, &freq);
|
opp = dev_pm_opp_find_freq_ceil(dev, &freq);
|
||||||
v = dev_pm_opp_get_voltage(opp);
|
v = dev_pm_opp_get_voltage(opp);
|
||||||
rcu_read_unlock();
|
dev_pm_opp_put(opp);
|
||||||
if (v)
|
if (v)
|
||||||
regulator_set_voltage(.., v);
|
regulator_set_voltage(.., v);
|
||||||
/* do other things */
|
/* do other things */
|
||||||
|
@ -266,12 +247,12 @@ dev_pm_opp_get_freq - Retrieve the freq represented by the opp pointer.
|
||||||
{
|
{
|
||||||
/* do things.. */
|
/* do things.. */
|
||||||
max_freq = ULONG_MAX;
|
max_freq = ULONG_MAX;
|
||||||
rcu_read_lock();
|
|
||||||
max_opp = dev_pm_opp_find_freq_floor(dev,&max_freq);
|
max_opp = dev_pm_opp_find_freq_floor(dev,&max_freq);
|
||||||
requested_opp = dev_pm_opp_find_freq_ceil(dev,&freq);
|
requested_opp = dev_pm_opp_find_freq_ceil(dev,&freq);
|
||||||
if (!IS_ERR(max_opp) && !IS_ERR(requested_opp))
|
if (!IS_ERR(max_opp) && !IS_ERR(requested_opp))
|
||||||
r = soc_test_validity(max_opp, requested_opp);
|
r = soc_test_validity(max_opp, requested_opp);
|
||||||
rcu_read_unlock();
|
dev_pm_opp_put(max_opp);
|
||||||
|
dev_pm_opp_put(requested_opp);
|
||||||
/* do other things */
|
/* do other things */
|
||||||
}
|
}
|
||||||
soc_test_validity(..)
|
soc_test_validity(..)
|
||||||
|
@ -289,7 +270,6 @@ dev_pm_opp_get_opp_count - Retrieve the number of available opps for a device
|
||||||
soc_notify_coproc_available_frequencies()
|
soc_notify_coproc_available_frequencies()
|
||||||
{
|
{
|
||||||
/* Do things */
|
/* Do things */
|
||||||
rcu_read_lock();
|
|
||||||
num_available = dev_pm_opp_get_opp_count(dev);
|
num_available = dev_pm_opp_get_opp_count(dev);
|
||||||
speeds = kzalloc(sizeof(u32) * num_available, GFP_KERNEL);
|
speeds = kzalloc(sizeof(u32) * num_available, GFP_KERNEL);
|
||||||
/* populate the table in increasing order */
|
/* populate the table in increasing order */
|
||||||
|
@ -298,8 +278,8 @@ dev_pm_opp_get_opp_count - Retrieve the number of available opps for a device
|
||||||
speeds[i] = freq;
|
speeds[i] = freq;
|
||||||
freq++;
|
freq++;
|
||||||
i++;
|
i++;
|
||||||
|
dev_pm_opp_put(opp);
|
||||||
}
|
}
|
||||||
rcu_read_unlock();
|
|
||||||
|
|
||||||
soc_notify_coproc(AVAILABLE_FREQs, speeds, num_available);
|
soc_notify_coproc(AVAILABLE_FREQs, speeds, num_available);
|
||||||
/* Do other things */
|
/* Do other things */
|
||||||
|
|
|
@ -130,17 +130,16 @@ static int __init omap2_set_init_voltage(char *vdd_name, char *clk_name,
|
||||||
freq = clk_get_rate(clk);
|
freq = clk_get_rate(clk);
|
||||||
clk_put(clk);
|
clk_put(clk);
|
||||||
|
|
||||||
rcu_read_lock();
|
|
||||||
opp = dev_pm_opp_find_freq_ceil(dev, &freq);
|
opp = dev_pm_opp_find_freq_ceil(dev, &freq);
|
||||||
if (IS_ERR(opp)) {
|
if (IS_ERR(opp)) {
|
||||||
rcu_read_unlock();
|
|
||||||
pr_err("%s: unable to find boot up OPP for vdd_%s\n",
|
pr_err("%s: unable to find boot up OPP for vdd_%s\n",
|
||||||
__func__, vdd_name);
|
__func__, vdd_name);
|
||||||
goto exit;
|
goto exit;
|
||||||
}
|
}
|
||||||
|
|
||||||
bootup_volt = dev_pm_opp_get_voltage(opp);
|
bootup_volt = dev_pm_opp_get_voltage(opp);
|
||||||
rcu_read_unlock();
|
dev_pm_opp_put(opp);
|
||||||
|
|
||||||
if (!bootup_volt) {
|
if (!bootup_volt) {
|
||||||
pr_err("%s: unable to find voltage corresponding to the bootup OPP for vdd_%s\n",
|
pr_err("%s: unable to find voltage corresponding to the bootup OPP for vdd_%s\n",
|
||||||
__func__, vdd_name);
|
__func__, vdd_name);
|
||||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -42,11 +42,6 @@
|
||||||
*
|
*
|
||||||
* WARNING: It is important for the callers to ensure refreshing their copy of
|
* WARNING: It is important for the callers to ensure refreshing their copy of
|
||||||
* the table if any of the mentioned functions have been invoked in the interim.
|
* the table if any of the mentioned functions have been invoked in the interim.
|
||||||
*
|
|
||||||
* Locking: The internal opp_table and opp structures are RCU protected.
|
|
||||||
* Since we just use the regular accessor functions to access the internal data
|
|
||||||
* structures, we use RCU read lock inside this function. As a result, users of
|
|
||||||
* this function DONOT need to use explicit locks for invoking.
|
|
||||||
*/
|
*/
|
||||||
int dev_pm_opp_init_cpufreq_table(struct device *dev,
|
int dev_pm_opp_init_cpufreq_table(struct device *dev,
|
||||||
struct cpufreq_frequency_table **table)
|
struct cpufreq_frequency_table **table)
|
||||||
|
@ -56,19 +51,13 @@ int dev_pm_opp_init_cpufreq_table(struct device *dev,
|
||||||
int i, max_opps, ret = 0;
|
int i, max_opps, ret = 0;
|
||||||
unsigned long rate;
|
unsigned long rate;
|
||||||
|
|
||||||
rcu_read_lock();
|
|
||||||
|
|
||||||
max_opps = dev_pm_opp_get_opp_count(dev);
|
max_opps = dev_pm_opp_get_opp_count(dev);
|
||||||
if (max_opps <= 0) {
|
if (max_opps <= 0)
|
||||||
ret = max_opps ? max_opps : -ENODATA;
|
return max_opps ? max_opps : -ENODATA;
|
||||||
goto out;
|
|
||||||
}
|
|
||||||
|
|
||||||
freq_table = kcalloc((max_opps + 1), sizeof(*freq_table), GFP_ATOMIC);
|
freq_table = kcalloc((max_opps + 1), sizeof(*freq_table), GFP_ATOMIC);
|
||||||
if (!freq_table) {
|
if (!freq_table)
|
||||||
ret = -ENOMEM;
|
return -ENOMEM;
|
||||||
goto out;
|
|
||||||
}
|
|
||||||
|
|
||||||
for (i = 0, rate = 0; i < max_opps; i++, rate++) {
|
for (i = 0, rate = 0; i < max_opps; i++, rate++) {
|
||||||
/* find next rate */
|
/* find next rate */
|
||||||
|
@ -83,6 +72,8 @@ int dev_pm_opp_init_cpufreq_table(struct device *dev,
|
||||||
/* Is Boost/turbo opp ? */
|
/* Is Boost/turbo opp ? */
|
||||||
if (dev_pm_opp_is_turbo(opp))
|
if (dev_pm_opp_is_turbo(opp))
|
||||||
freq_table[i].flags = CPUFREQ_BOOST_FREQ;
|
freq_table[i].flags = CPUFREQ_BOOST_FREQ;
|
||||||
|
|
||||||
|
dev_pm_opp_put(opp);
|
||||||
}
|
}
|
||||||
|
|
||||||
freq_table[i].driver_data = i;
|
freq_table[i].driver_data = i;
|
||||||
|
@ -91,7 +82,6 @@ int dev_pm_opp_init_cpufreq_table(struct device *dev,
|
||||||
*table = &freq_table[0];
|
*table = &freq_table[0];
|
||||||
|
|
||||||
out:
|
out:
|
||||||
rcu_read_unlock();
|
|
||||||
if (ret)
|
if (ret)
|
||||||
kfree(freq_table);
|
kfree(freq_table);
|
||||||
|
|
||||||
|
@ -147,12 +137,6 @@ void _dev_pm_opp_cpumask_remove_table(const struct cpumask *cpumask, bool of)
|
||||||
* This removes the OPP tables for CPUs present in the @cpumask.
|
* This removes the OPP tables for CPUs present in the @cpumask.
|
||||||
* This should be used to remove all the OPPs entries associated with
|
* This should be used to remove all the OPPs entries associated with
|
||||||
* the cpus in @cpumask.
|
* the cpus in @cpumask.
|
||||||
*
|
|
||||||
* Locking: The internal opp_table and opp structures are RCU protected.
|
|
||||||
* Hence this function internally uses RCU updater strategy with mutex locks
|
|
||||||
* to keep the integrity of the internal data structures. Callers should ensure
|
|
||||||
* that this function is *NOT* called under RCU protection or in contexts where
|
|
||||||
* mutex cannot be locked.
|
|
||||||
*/
|
*/
|
||||||
void dev_pm_opp_cpumask_remove_table(const struct cpumask *cpumask)
|
void dev_pm_opp_cpumask_remove_table(const struct cpumask *cpumask)
|
||||||
{
|
{
|
||||||
|
@ -169,12 +153,6 @@ EXPORT_SYMBOL_GPL(dev_pm_opp_cpumask_remove_table);
|
||||||
* @cpumask.
|
* @cpumask.
|
||||||
*
|
*
|
||||||
* Returns -ENODEV if OPP table isn't already present.
|
* Returns -ENODEV if OPP table isn't already present.
|
||||||
*
|
|
||||||
* Locking: The internal opp_table and opp structures are RCU protected.
|
|
||||||
* Hence this function internally uses RCU updater strategy with mutex locks
|
|
||||||
* to keep the integrity of the internal data structures. Callers should ensure
|
|
||||||
* that this function is *NOT* called under RCU protection or in contexts where
|
|
||||||
* mutex cannot be locked.
|
|
||||||
*/
|
*/
|
||||||
int dev_pm_opp_set_sharing_cpus(struct device *cpu_dev,
|
int dev_pm_opp_set_sharing_cpus(struct device *cpu_dev,
|
||||||
const struct cpumask *cpumask)
|
const struct cpumask *cpumask)
|
||||||
|
@ -184,13 +162,9 @@ int dev_pm_opp_set_sharing_cpus(struct device *cpu_dev,
|
||||||
struct device *dev;
|
struct device *dev;
|
||||||
int cpu, ret = 0;
|
int cpu, ret = 0;
|
||||||
|
|
||||||
mutex_lock(&opp_table_lock);
|
|
||||||
|
|
||||||
opp_table = _find_opp_table(cpu_dev);
|
opp_table = _find_opp_table(cpu_dev);
|
||||||
if (IS_ERR(opp_table)) {
|
if (IS_ERR(opp_table))
|
||||||
ret = PTR_ERR(opp_table);
|
return PTR_ERR(opp_table);
|
||||||
goto unlock;
|
|
||||||
}
|
|
||||||
|
|
||||||
for_each_cpu(cpu, cpumask) {
|
for_each_cpu(cpu, cpumask) {
|
||||||
if (cpu == cpu_dev->id)
|
if (cpu == cpu_dev->id)
|
||||||
|
@ -213,8 +187,8 @@ int dev_pm_opp_set_sharing_cpus(struct device *cpu_dev,
|
||||||
/* Mark opp-table as multiple CPUs are sharing it now */
|
/* Mark opp-table as multiple CPUs are sharing it now */
|
||||||
opp_table->shared_opp = OPP_TABLE_ACCESS_SHARED;
|
opp_table->shared_opp = OPP_TABLE_ACCESS_SHARED;
|
||||||
}
|
}
|
||||||
unlock:
|
|
||||||
mutex_unlock(&opp_table_lock);
|
dev_pm_opp_put_opp_table(opp_table);
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
@ -229,12 +203,6 @@ EXPORT_SYMBOL_GPL(dev_pm_opp_set_sharing_cpus);
|
||||||
*
|
*
|
||||||
* Returns -ENODEV if OPP table isn't already present and -EINVAL if the OPP
|
* Returns -ENODEV if OPP table isn't already present and -EINVAL if the OPP
|
||||||
* table's status is access-unknown.
|
* table's status is access-unknown.
|
||||||
*
|
|
||||||
* Locking: The internal opp_table and opp structures are RCU protected.
|
|
||||||
* Hence this function internally uses RCU updater strategy with mutex locks
|
|
||||||
* to keep the integrity of the internal data structures. Callers should ensure
|
|
||||||
* that this function is *NOT* called under RCU protection or in contexts where
|
|
||||||
* mutex cannot be locked.
|
|
||||||
*/
|
*/
|
||||||
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)
|
||||||
{
|
{
|
||||||
|
@ -242,17 +210,13 @@ int dev_pm_opp_get_sharing_cpus(struct device *cpu_dev, struct cpumask *cpumask)
|
||||||
struct opp_table *opp_table;
|
struct opp_table *opp_table;
|
||||||
int ret = 0;
|
int ret = 0;
|
||||||
|
|
||||||
mutex_lock(&opp_table_lock);
|
|
||||||
|
|
||||||
opp_table = _find_opp_table(cpu_dev);
|
opp_table = _find_opp_table(cpu_dev);
|
||||||
if (IS_ERR(opp_table)) {
|
if (IS_ERR(opp_table))
|
||||||
ret = PTR_ERR(opp_table);
|
return PTR_ERR(opp_table);
|
||||||
goto unlock;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (opp_table->shared_opp == OPP_TABLE_ACCESS_UNKNOWN) {
|
if (opp_table->shared_opp == OPP_TABLE_ACCESS_UNKNOWN) {
|
||||||
ret = -EINVAL;
|
ret = -EINVAL;
|
||||||
goto unlock;
|
goto put_opp_table;
|
||||||
}
|
}
|
||||||
|
|
||||||
cpumask_clear(cpumask);
|
cpumask_clear(cpumask);
|
||||||
|
@ -264,8 +228,8 @@ int dev_pm_opp_get_sharing_cpus(struct device *cpu_dev, struct cpumask *cpumask)
|
||||||
cpumask_set_cpu(cpu_dev->id, cpumask);
|
cpumask_set_cpu(cpu_dev->id, cpumask);
|
||||||
}
|
}
|
||||||
|
|
||||||
unlock:
|
put_opp_table:
|
||||||
mutex_unlock(&opp_table_lock);
|
dev_pm_opp_put_opp_table(opp_table);
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
|
@ -24,9 +24,11 @@
|
||||||
|
|
||||||
static struct opp_table *_managed_opp(const struct device_node *np)
|
static struct opp_table *_managed_opp(const struct device_node *np)
|
||||||
{
|
{
|
||||||
struct opp_table *opp_table;
|
struct opp_table *opp_table, *managed_table = NULL;
|
||||||
|
|
||||||
list_for_each_entry_rcu(opp_table, &opp_tables, node) {
|
mutex_lock(&opp_table_lock);
|
||||||
|
|
||||||
|
list_for_each_entry(opp_table, &opp_tables, node) {
|
||||||
if (opp_table->np == np) {
|
if (opp_table->np == np) {
|
||||||
/*
|
/*
|
||||||
* Multiple devices can point to the same OPP table and
|
* Multiple devices can point to the same OPP table and
|
||||||
|
@ -35,14 +37,18 @@ static struct opp_table *_managed_opp(const struct device_node *np)
|
||||||
* But the OPPs will be considered as shared only if the
|
* But the OPPs will be considered as shared only if the
|
||||||
* OPP table contains a "opp-shared" property.
|
* OPP table contains a "opp-shared" property.
|
||||||
*/
|
*/
|
||||||
if (opp_table->shared_opp == OPP_TABLE_ACCESS_SHARED)
|
if (opp_table->shared_opp == OPP_TABLE_ACCESS_SHARED) {
|
||||||
return opp_table;
|
_get_opp_table_kref(opp_table);
|
||||||
|
managed_table = opp_table;
|
||||||
|
}
|
||||||
|
|
||||||
return NULL;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return NULL;
|
mutex_unlock(&opp_table_lock);
|
||||||
|
|
||||||
|
return managed_table;
|
||||||
}
|
}
|
||||||
|
|
||||||
void _of_init_opp_table(struct opp_table *opp_table, struct device *dev)
|
void _of_init_opp_table(struct opp_table *opp_table, struct device *dev)
|
||||||
|
@ -229,34 +235,28 @@ static int opp_parse_supplies(struct dev_pm_opp *opp, struct device *dev,
|
||||||
* @dev: device pointer used to lookup OPP table.
|
* @dev: device pointer used to lookup OPP table.
|
||||||
*
|
*
|
||||||
* Free OPPs created using static entries present in DT.
|
* Free OPPs created using static entries present in DT.
|
||||||
*
|
|
||||||
* Locking: The internal opp_table and opp structures are RCU protected.
|
|
||||||
* Hence this function indirectly uses RCU updater strategy with mutex locks
|
|
||||||
* to keep the integrity of the internal data structures. Callers should ensure
|
|
||||||
* that this function is *NOT* called under RCU protection or in contexts where
|
|
||||||
* mutex cannot be locked.
|
|
||||||
*/
|
*/
|
||||||
void dev_pm_opp_of_remove_table(struct device *dev)
|
void dev_pm_opp_of_remove_table(struct device *dev)
|
||||||
{
|
{
|
||||||
_dev_pm_opp_remove_table(dev, false);
|
_dev_pm_opp_find_and_remove_table(dev, false);
|
||||||
}
|
}
|
||||||
EXPORT_SYMBOL_GPL(dev_pm_opp_of_remove_table);
|
EXPORT_SYMBOL_GPL(dev_pm_opp_of_remove_table);
|
||||||
|
|
||||||
/* Returns opp descriptor node for a device, caller must do of_node_put() */
|
/* Returns opp descriptor node for a device, caller must do of_node_put() */
|
||||||
static struct device_node *_of_get_opp_desc_node(struct device *dev)
|
struct device_node *dev_pm_opp_of_get_opp_desc_node(struct device *dev)
|
||||||
{
|
{
|
||||||
/*
|
/*
|
||||||
* TODO: Support for multiple OPP tables.
|
|
||||||
*
|
|
||||||
* There should be only ONE phandle present in "operating-points-v2"
|
* There should be only ONE phandle present in "operating-points-v2"
|
||||||
* property.
|
* property.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
return of_parse_phandle(dev->of_node, "operating-points-v2", 0);
|
return of_parse_phandle(dev->of_node, "operating-points-v2", 0);
|
||||||
}
|
}
|
||||||
|
EXPORT_SYMBOL_GPL(dev_pm_opp_of_get_opp_desc_node);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* _opp_add_static_v2() - Allocate static OPPs (As per 'v2' DT bindings)
|
* _opp_add_static_v2() - Allocate static OPPs (As per 'v2' DT bindings)
|
||||||
|
* @opp_table: OPP table
|
||||||
* @dev: device for which we do this operation
|
* @dev: device for which we do this operation
|
||||||
* @np: device node
|
* @np: device node
|
||||||
*
|
*
|
||||||
|
@ -264,12 +264,6 @@ static struct device_node *_of_get_opp_desc_node(struct device *dev)
|
||||||
* opp can be controlled using dev_pm_opp_enable/disable functions and may be
|
* opp can be controlled using dev_pm_opp_enable/disable functions and may be
|
||||||
* removed by dev_pm_opp_remove.
|
* removed by dev_pm_opp_remove.
|
||||||
*
|
*
|
||||||
* Locking: The internal opp_table and opp structures are RCU protected.
|
|
||||||
* Hence this function internally uses RCU updater strategy with mutex locks
|
|
||||||
* to keep the integrity of the internal data structures. Callers should ensure
|
|
||||||
* that this function is *NOT* called under RCU protection or in contexts where
|
|
||||||
* mutex cannot be locked.
|
|
||||||
*
|
|
||||||
* Return:
|
* Return:
|
||||||
* 0 On success OR
|
* 0 On success OR
|
||||||
* Duplicate OPPs (both freq and volt are same) and opp->available
|
* Duplicate OPPs (both freq and volt are same) and opp->available
|
||||||
|
@ -278,22 +272,17 @@ static struct device_node *_of_get_opp_desc_node(struct device *dev)
|
||||||
* -ENOMEM Memory allocation failure
|
* -ENOMEM Memory allocation failure
|
||||||
* -EINVAL Failed parsing the OPP node
|
* -EINVAL Failed parsing the OPP node
|
||||||
*/
|
*/
|
||||||
static int _opp_add_static_v2(struct device *dev, struct device_node *np)
|
static int _opp_add_static_v2(struct opp_table *opp_table, struct device *dev,
|
||||||
|
struct device_node *np)
|
||||||
{
|
{
|
||||||
struct opp_table *opp_table;
|
|
||||||
struct dev_pm_opp *new_opp;
|
struct dev_pm_opp *new_opp;
|
||||||
u64 rate;
|
u64 rate;
|
||||||
u32 val;
|
u32 val;
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
/* Hold our table modification lock here */
|
new_opp = _opp_allocate(opp_table);
|
||||||
mutex_lock(&opp_table_lock);
|
if (!new_opp)
|
||||||
|
return -ENOMEM;
|
||||||
new_opp = _allocate_opp(dev, &opp_table);
|
|
||||||
if (!new_opp) {
|
|
||||||
ret = -ENOMEM;
|
|
||||||
goto unlock;
|
|
||||||
}
|
|
||||||
|
|
||||||
ret = of_property_read_u64(np, "opp-hz", &rate);
|
ret = of_property_read_u64(np, "opp-hz", &rate);
|
||||||
if (ret < 0) {
|
if (ret < 0) {
|
||||||
|
@ -327,8 +316,12 @@ static int _opp_add_static_v2(struct device *dev, struct device_node *np)
|
||||||
goto free_opp;
|
goto free_opp;
|
||||||
|
|
||||||
ret = _opp_add(dev, new_opp, opp_table);
|
ret = _opp_add(dev, new_opp, opp_table);
|
||||||
if (ret)
|
if (ret) {
|
||||||
|
/* Don't return error for duplicate OPPs */
|
||||||
|
if (ret == -EBUSY)
|
||||||
|
ret = 0;
|
||||||
goto free_opp;
|
goto free_opp;
|
||||||
|
}
|
||||||
|
|
||||||
/* 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")) {
|
||||||
|
@ -345,8 +338,6 @@ static int _opp_add_static_v2(struct device *dev, struct device_node *np)
|
||||||
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;
|
||||||
|
|
||||||
mutex_unlock(&opp_table_lock);
|
|
||||||
|
|
||||||
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\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,
|
||||||
|
@ -356,13 +347,12 @@ static int _opp_add_static_v2(struct device *dev, struct device_node *np)
|
||||||
* Notify the changes in the availability of the operable
|
* Notify the changes in the availability of the operable
|
||||||
* frequency/voltage list.
|
* frequency/voltage list.
|
||||||
*/
|
*/
|
||||||
srcu_notifier_call_chain(&opp_table->srcu_head, OPP_EVENT_ADD, new_opp);
|
blocking_notifier_call_chain(&opp_table->head, OPP_EVENT_ADD, new_opp);
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
free_opp:
|
free_opp:
|
||||||
_opp_remove(opp_table, new_opp, false);
|
_opp_free(new_opp);
|
||||||
unlock:
|
|
||||||
mutex_unlock(&opp_table_lock);
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -373,41 +363,35 @@ static int _of_add_opp_table_v2(struct device *dev, struct device_node *opp_np)
|
||||||
struct opp_table *opp_table;
|
struct opp_table *opp_table;
|
||||||
int ret = 0, count = 0;
|
int ret = 0, count = 0;
|
||||||
|
|
||||||
mutex_lock(&opp_table_lock);
|
|
||||||
|
|
||||||
opp_table = _managed_opp(opp_np);
|
opp_table = _managed_opp(opp_np);
|
||||||
if (opp_table) {
|
if (opp_table) {
|
||||||
/* OPPs are already managed */
|
/* OPPs are already managed */
|
||||||
if (!_add_opp_dev(dev, opp_table))
|
if (!_add_opp_dev(dev, opp_table))
|
||||||
ret = -ENOMEM;
|
ret = -ENOMEM;
|
||||||
mutex_unlock(&opp_table_lock);
|
goto put_opp_table;
|
||||||
return ret;
|
|
||||||
}
|
}
|
||||||
mutex_unlock(&opp_table_lock);
|
|
||||||
|
opp_table = dev_pm_opp_get_opp_table(dev);
|
||||||
|
if (!opp_table)
|
||||||
|
return -ENOMEM;
|
||||||
|
|
||||||
/* 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_np, np) {
|
for_each_available_child_of_node(opp_np, np) {
|
||||||
count++;
|
count++;
|
||||||
|
|
||||||
ret = _opp_add_static_v2(dev, np);
|
ret = _opp_add_static_v2(opp_table, dev, np);
|
||||||
if (ret) {
|
if (ret) {
|
||||||
dev_err(dev, "%s: Failed to add OPP, %d\n", __func__,
|
dev_err(dev, "%s: Failed to add OPP, %d\n", __func__,
|
||||||
ret);
|
ret);
|
||||||
goto free_table;
|
_dev_pm_opp_remove_table(opp_table, dev, false);
|
||||||
|
goto put_opp_table;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* There should be one of more OPP defined */
|
/* There should be one of more OPP defined */
|
||||||
if (WARN_ON(!count))
|
if (WARN_ON(!count)) {
|
||||||
return -ENOENT;
|
ret = -ENOENT;
|
||||||
|
goto put_opp_table;
|
||||||
mutex_lock(&opp_table_lock);
|
|
||||||
|
|
||||||
opp_table = _find_opp_table(dev);
|
|
||||||
if (WARN_ON(IS_ERR(opp_table))) {
|
|
||||||
ret = PTR_ERR(opp_table);
|
|
||||||
mutex_unlock(&opp_table_lock);
|
|
||||||
goto free_table;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
opp_table->np = opp_np;
|
opp_table->np = opp_np;
|
||||||
|
@ -416,12 +400,8 @@ static int _of_add_opp_table_v2(struct device *dev, struct device_node *opp_np)
|
||||||
else
|
else
|
||||||
opp_table->shared_opp = OPP_TABLE_ACCESS_EXCLUSIVE;
|
opp_table->shared_opp = OPP_TABLE_ACCESS_EXCLUSIVE;
|
||||||
|
|
||||||
mutex_unlock(&opp_table_lock);
|
put_opp_table:
|
||||||
|
dev_pm_opp_put_opp_table(opp_table);
|
||||||
return 0;
|
|
||||||
|
|
||||||
free_table:
|
|
||||||
dev_pm_opp_of_remove_table(dev);
|
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
@ -429,9 +409,10 @@ static int _of_add_opp_table_v2(struct device *dev, struct device_node *opp_np)
|
||||||
/* Initializes OPP tables based on old-deprecated bindings */
|
/* Initializes OPP tables based on old-deprecated bindings */
|
||||||
static int _of_add_opp_table_v1(struct device *dev)
|
static int _of_add_opp_table_v1(struct device *dev)
|
||||||
{
|
{
|
||||||
|
struct opp_table *opp_table;
|
||||||
const struct property *prop;
|
const struct property *prop;
|
||||||
const __be32 *val;
|
const __be32 *val;
|
||||||
int nr;
|
int nr, ret = 0;
|
||||||
|
|
||||||
prop = of_find_property(dev->of_node, "operating-points", NULL);
|
prop = of_find_property(dev->of_node, "operating-points", NULL);
|
||||||
if (!prop)
|
if (!prop)
|
||||||
|
@ -449,18 +430,27 @@ static int _of_add_opp_table_v1(struct device *dev)
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
opp_table = dev_pm_opp_get_opp_table(dev);
|
||||||
|
if (!opp_table)
|
||||||
|
return -ENOMEM;
|
||||||
|
|
||||||
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;
|
||||||
unsigned long volt = be32_to_cpup(val++);
|
unsigned long volt = be32_to_cpup(val++);
|
||||||
|
|
||||||
if (_opp_add_v1(dev, freq, volt, false))
|
ret = _opp_add_v1(opp_table, dev, freq, volt, false);
|
||||||
dev_warn(dev, "%s: Failed to add OPP %ld\n",
|
if (ret) {
|
||||||
__func__, freq);
|
dev_err(dev, "%s: Failed to add OPP %ld (%d)\n",
|
||||||
|
__func__, freq, ret);
|
||||||
|
_dev_pm_opp_remove_table(opp_table, dev, false);
|
||||||
|
break;
|
||||||
|
}
|
||||||
nr -= 2;
|
nr -= 2;
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0;
|
dev_pm_opp_put_opp_table(opp_table);
|
||||||
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -469,12 +459,6 @@ static int _of_add_opp_table_v1(struct device *dev)
|
||||||
*
|
*
|
||||||
* Register the initial OPP table with the OPP library for given device.
|
* Register the initial OPP table with the OPP library for given device.
|
||||||
*
|
*
|
||||||
* Locking: The internal opp_table and opp structures are RCU protected.
|
|
||||||
* Hence this function indirectly uses RCU updater strategy with mutex locks
|
|
||||||
* to keep the integrity of the internal data structures. Callers should ensure
|
|
||||||
* that this function is *NOT* called under RCU protection or in contexts where
|
|
||||||
* mutex cannot be locked.
|
|
||||||
*
|
|
||||||
* Return:
|
* Return:
|
||||||
* 0 On success OR
|
* 0 On success OR
|
||||||
* Duplicate OPPs (both freq and volt are same) and opp->available
|
* Duplicate OPPs (both freq and volt are same) and opp->available
|
||||||
|
@ -495,7 +479,7 @@ int dev_pm_opp_of_add_table(struct device *dev)
|
||||||
* OPPs have two version of bindings now. The older one is deprecated,
|
* OPPs have two version of bindings now. The older one is deprecated,
|
||||||
* try for the new binding first.
|
* try for the new binding first.
|
||||||
*/
|
*/
|
||||||
opp_np = _of_get_opp_desc_node(dev);
|
opp_np = dev_pm_opp_of_get_opp_desc_node(dev);
|
||||||
if (!opp_np) {
|
if (!opp_np) {
|
||||||
/*
|
/*
|
||||||
* Try old-deprecated bindings for backward compatibility with
|
* Try old-deprecated bindings for backward compatibility with
|
||||||
|
@ -519,12 +503,6 @@ EXPORT_SYMBOL_GPL(dev_pm_opp_of_add_table);
|
||||||
*
|
*
|
||||||
* This removes the OPP tables for CPUs present in the @cpumask.
|
* This removes the OPP tables for CPUs present in the @cpumask.
|
||||||
* This should be used only to remove static entries created from DT.
|
* This should be used only to remove static entries created from DT.
|
||||||
*
|
|
||||||
* Locking: The internal opp_table and opp structures are RCU protected.
|
|
||||||
* Hence this function internally uses RCU updater strategy with mutex locks
|
|
||||||
* to keep the integrity of the internal data structures. Callers should ensure
|
|
||||||
* that this function is *NOT* called under RCU protection or in contexts where
|
|
||||||
* mutex cannot be locked.
|
|
||||||
*/
|
*/
|
||||||
void dev_pm_opp_of_cpumask_remove_table(const struct cpumask *cpumask)
|
void dev_pm_opp_of_cpumask_remove_table(const struct cpumask *cpumask)
|
||||||
{
|
{
|
||||||
|
@ -537,12 +515,6 @@ EXPORT_SYMBOL_GPL(dev_pm_opp_of_cpumask_remove_table);
|
||||||
* @cpumask: cpumask for which OPP table needs to be added.
|
* @cpumask: cpumask for which OPP table needs to be added.
|
||||||
*
|
*
|
||||||
* This adds the OPP tables for CPUs present in the @cpumask.
|
* This adds the OPP tables for CPUs present in the @cpumask.
|
||||||
*
|
|
||||||
* Locking: The internal opp_table and opp structures are RCU protected.
|
|
||||||
* Hence this function internally uses RCU updater strategy with mutex locks
|
|
||||||
* to keep the integrity of the internal data structures. Callers should ensure
|
|
||||||
* that this function is *NOT* called under RCU protection or in contexts where
|
|
||||||
* mutex cannot be locked.
|
|
||||||
*/
|
*/
|
||||||
int dev_pm_opp_of_cpumask_add_table(const struct cpumask *cpumask)
|
int dev_pm_opp_of_cpumask_add_table(const struct cpumask *cpumask)
|
||||||
{
|
{
|
||||||
|
@ -590,12 +562,6 @@ EXPORT_SYMBOL_GPL(dev_pm_opp_of_cpumask_add_table);
|
||||||
* This updates the @cpumask with CPUs that are sharing OPPs with @cpu_dev.
|
* This updates the @cpumask with CPUs that are sharing OPPs with @cpu_dev.
|
||||||
*
|
*
|
||||||
* Returns -ENOENT if operating-points-v2 isn't present for @cpu_dev.
|
* Returns -ENOENT if operating-points-v2 isn't present for @cpu_dev.
|
||||||
*
|
|
||||||
* Locking: The internal opp_table and opp structures are RCU protected.
|
|
||||||
* Hence this function internally uses RCU updater strategy with mutex locks
|
|
||||||
* to keep the integrity of the internal data structures. Callers should ensure
|
|
||||||
* that this function is *NOT* called under RCU protection or in contexts where
|
|
||||||
* mutex cannot be locked.
|
|
||||||
*/
|
*/
|
||||||
int dev_pm_opp_of_get_sharing_cpus(struct device *cpu_dev,
|
int dev_pm_opp_of_get_sharing_cpus(struct device *cpu_dev,
|
||||||
struct cpumask *cpumask)
|
struct cpumask *cpumask)
|
||||||
|
@ -605,7 +571,7 @@ int dev_pm_opp_of_get_sharing_cpus(struct device *cpu_dev,
|
||||||
int cpu, ret = 0;
|
int cpu, ret = 0;
|
||||||
|
|
||||||
/* Get OPP descriptor node */
|
/* Get OPP descriptor node */
|
||||||
np = _of_get_opp_desc_node(cpu_dev);
|
np = dev_pm_opp_of_get_opp_desc_node(cpu_dev);
|
||||||
if (!np) {
|
if (!np) {
|
||||||
dev_dbg(cpu_dev, "%s: Couldn't find opp node.\n", __func__);
|
dev_dbg(cpu_dev, "%s: Couldn't find opp node.\n", __func__);
|
||||||
return -ENOENT;
|
return -ENOENT;
|
||||||
|
@ -630,7 +596,7 @@ int dev_pm_opp_of_get_sharing_cpus(struct device *cpu_dev,
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Get OPP descriptor node */
|
/* Get OPP descriptor node */
|
||||||
tmp_np = _of_get_opp_desc_node(tcpu_dev);
|
tmp_np = dev_pm_opp_of_get_opp_desc_node(tcpu_dev);
|
||||||
if (!tmp_np) {
|
if (!tmp_np) {
|
||||||
dev_err(tcpu_dev, "%s: Couldn't find opp node.\n",
|
dev_err(tcpu_dev, "%s: Couldn't find opp node.\n",
|
||||||
__func__);
|
__func__);
|
||||||
|
|
|
@ -16,11 +16,11 @@
|
||||||
|
|
||||||
#include <linux/device.h>
|
#include <linux/device.h>
|
||||||
#include <linux/kernel.h>
|
#include <linux/kernel.h>
|
||||||
|
#include <linux/kref.h>
|
||||||
#include <linux/list.h>
|
#include <linux/list.h>
|
||||||
#include <linux/limits.h>
|
#include <linux/limits.h>
|
||||||
#include <linux/pm_opp.h>
|
#include <linux/pm_opp.h>
|
||||||
#include <linux/rculist.h>
|
#include <linux/notifier.h>
|
||||||
#include <linux/rcupdate.h>
|
|
||||||
|
|
||||||
struct clk;
|
struct clk;
|
||||||
struct regulator;
|
struct regulator;
|
||||||
|
@ -51,11 +51,9 @@ extern struct list_head opp_tables;
|
||||||
* @node: opp table node. The nodes are maintained throughout the lifetime
|
* @node: opp table node. The nodes are maintained throughout the lifetime
|
||||||
* of boot. It is expected only an optimal set of OPPs are
|
* of boot. It is expected only an optimal set of OPPs are
|
||||||
* added to the library by the SoC framework.
|
* added to the library by the SoC framework.
|
||||||
* RCU usage: opp table is traversed with RCU locks. node
|
|
||||||
* modification is possible realtime, hence the modifications
|
|
||||||
* are protected by the opp_table_lock for integrity.
|
|
||||||
* IMPORTANT: the opp nodes should be maintained in increasing
|
* IMPORTANT: the opp nodes should be maintained in increasing
|
||||||
* order.
|
* order.
|
||||||
|
* @kref: for reference count of the OPP.
|
||||||
* @available: true/false - marks if this OPP as available or not
|
* @available: true/false - marks if this OPP as available or not
|
||||||
* @dynamic: not-created from static DT entries.
|
* @dynamic: not-created from static DT entries.
|
||||||
* @turbo: true if turbo (boost) OPP
|
* @turbo: true if turbo (boost) OPP
|
||||||
|
@ -65,7 +63,6 @@ extern struct list_head opp_tables;
|
||||||
* @clock_latency_ns: Latency (in nanoseconds) of switching to this OPP's
|
* @clock_latency_ns: Latency (in nanoseconds) of switching to this OPP's
|
||||||
* frequency from any other OPP's frequency.
|
* frequency from any other OPP's frequency.
|
||||||
* @opp_table: points back to the opp_table struct this opp belongs to
|
* @opp_table: points back to the opp_table struct this opp belongs to
|
||||||
* @rcu_head: RCU callback head used for deferred freeing
|
|
||||||
* @np: OPP's device node.
|
* @np: OPP's device node.
|
||||||
* @dentry: debugfs dentry pointer (per opp)
|
* @dentry: debugfs dentry pointer (per opp)
|
||||||
*
|
*
|
||||||
|
@ -73,6 +70,7 @@ extern struct list_head opp_tables;
|
||||||
*/
|
*/
|
||||||
struct dev_pm_opp {
|
struct dev_pm_opp {
|
||||||
struct list_head node;
|
struct list_head node;
|
||||||
|
struct kref kref;
|
||||||
|
|
||||||
bool available;
|
bool available;
|
||||||
bool dynamic;
|
bool dynamic;
|
||||||
|
@ -85,7 +83,6 @@ struct dev_pm_opp {
|
||||||
unsigned long clock_latency_ns;
|
unsigned long clock_latency_ns;
|
||||||
|
|
||||||
struct opp_table *opp_table;
|
struct opp_table *opp_table;
|
||||||
struct rcu_head rcu_head;
|
|
||||||
|
|
||||||
struct device_node *np;
|
struct device_node *np;
|
||||||
|
|
||||||
|
@ -98,7 +95,6 @@ struct dev_pm_opp {
|
||||||
* struct opp_device - devices managed by 'struct opp_table'
|
* struct opp_device - devices managed by 'struct opp_table'
|
||||||
* @node: list node
|
* @node: list node
|
||||||
* @dev: device to which the struct object belongs
|
* @dev: device to which the struct object belongs
|
||||||
* @rcu_head: RCU callback head used for deferred freeing
|
|
||||||
* @dentry: debugfs dentry pointer (per device)
|
* @dentry: debugfs dentry pointer (per device)
|
||||||
*
|
*
|
||||||
* This is an internal data structure maintaining the devices that are managed
|
* This is an internal data structure maintaining the devices that are managed
|
||||||
|
@ -107,7 +103,6 @@ struct dev_pm_opp {
|
||||||
struct opp_device {
|
struct opp_device {
|
||||||
struct list_head node;
|
struct list_head node;
|
||||||
const struct device *dev;
|
const struct device *dev;
|
||||||
struct rcu_head rcu_head;
|
|
||||||
|
|
||||||
#ifdef CONFIG_DEBUG_FS
|
#ifdef CONFIG_DEBUG_FS
|
||||||
struct dentry *dentry;
|
struct dentry *dentry;
|
||||||
|
@ -125,12 +120,11 @@ enum opp_table_access {
|
||||||
* @node: table node - contains the devices with OPPs that
|
* @node: table node - contains the devices with OPPs that
|
||||||
* have been registered. Nodes once added are not modified in this
|
* have been registered. Nodes once added are not modified in this
|
||||||
* table.
|
* table.
|
||||||
* RCU usage: nodes are not modified in the table of opp_table,
|
* @head: notifier head to notify the OPP availability changes.
|
||||||
* however addition is possible and is secured by opp_table_lock
|
|
||||||
* @srcu_head: notifier head to notify the OPP availability changes.
|
|
||||||
* @rcu_head: RCU callback head used for deferred freeing
|
|
||||||
* @dev_list: list of devices that share these OPPs
|
* @dev_list: list of devices that share these OPPs
|
||||||
* @opp_list: table of opps
|
* @opp_list: table of opps
|
||||||
|
* @kref: for reference count of the table.
|
||||||
|
* @lock: mutex protecting the opp_list.
|
||||||
* @np: struct device_node pointer for opp's DT node.
|
* @np: struct device_node pointer for opp's DT node.
|
||||||
* @clock_latency_ns_max: Max clock latency in nanoseconds.
|
* @clock_latency_ns_max: Max clock latency in nanoseconds.
|
||||||
* @shared_opp: OPP is shared between multiple devices.
|
* @shared_opp: OPP is shared between multiple devices.
|
||||||
|
@ -151,18 +145,15 @@ enum opp_table_access {
|
||||||
* This is an internal data structure maintaining the link to opps attached to
|
* This is an internal data structure maintaining the link to opps attached to
|
||||||
* a device. This structure is not meant to be shared to users as it is
|
* a device. This structure is not meant to be shared to users as it is
|
||||||
* meant for book keeping and private to OPP library.
|
* meant for book keeping and private to OPP library.
|
||||||
*
|
|
||||||
* Because the opp structures can be used from both rcu and srcu readers, we
|
|
||||||
* need to wait for the grace period of both of them before freeing any
|
|
||||||
* resources. And so we have used kfree_rcu() from within call_srcu() handlers.
|
|
||||||
*/
|
*/
|
||||||
struct opp_table {
|
struct opp_table {
|
||||||
struct list_head node;
|
struct list_head node;
|
||||||
|
|
||||||
struct srcu_notifier_head srcu_head;
|
struct blocking_notifier_head head;
|
||||||
struct rcu_head rcu_head;
|
|
||||||
struct list_head dev_list;
|
struct list_head dev_list;
|
||||||
struct list_head opp_list;
|
struct list_head opp_list;
|
||||||
|
struct kref kref;
|
||||||
|
struct mutex lock;
|
||||||
|
|
||||||
struct device_node *np;
|
struct device_node *np;
|
||||||
unsigned long clock_latency_ns_max;
|
unsigned long clock_latency_ns_max;
|
||||||
|
@ -190,14 +181,17 @@ struct opp_table {
|
||||||
};
|
};
|
||||||
|
|
||||||
/* Routines internal to opp core */
|
/* Routines internal to opp core */
|
||||||
|
void _get_opp_table_kref(struct opp_table *opp_table);
|
||||||
struct opp_table *_find_opp_table(struct device *dev);
|
struct opp_table *_find_opp_table(struct device *dev);
|
||||||
struct opp_device *_add_opp_dev(const struct device *dev, struct opp_table *opp_table);
|
struct opp_device *_add_opp_dev(const struct device *dev, struct opp_table *opp_table);
|
||||||
void _dev_pm_opp_remove_table(struct device *dev, bool remove_all);
|
void _dev_pm_opp_remove_table(struct opp_table *opp_table, struct device *dev, bool remove_all);
|
||||||
struct dev_pm_opp *_allocate_opp(struct device *dev, struct opp_table **opp_table);
|
void _dev_pm_opp_find_and_remove_table(struct device *dev, bool remove_all);
|
||||||
|
struct dev_pm_opp *_opp_allocate(struct opp_table *opp_table);
|
||||||
|
void _opp_free(struct dev_pm_opp *opp);
|
||||||
int _opp_add(struct device *dev, struct dev_pm_opp *new_opp, struct opp_table *opp_table);
|
int _opp_add(struct device *dev, struct dev_pm_opp *new_opp, struct opp_table *opp_table);
|
||||||
void _opp_remove(struct opp_table *opp_table, struct dev_pm_opp *opp, bool notify);
|
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 device *dev, unsigned long freq, long u_volt, bool dynamic);
|
|
||||||
void _dev_pm_opp_cpumask_remove_table(const struct cpumask *cpumask, bool of);
|
void _dev_pm_opp_cpumask_remove_table(const struct cpumask *cpumask, bool of);
|
||||||
|
struct opp_table *_add_opp_table(struct device *dev);
|
||||||
|
|
||||||
#ifdef CONFIG_OF
|
#ifdef CONFIG_OF
|
||||||
void _of_init_opp_table(struct opp_table *opp_table, struct device *dev);
|
void _of_init_opp_table(struct opp_table *opp_table, struct device *dev);
|
||||||
|
|
|
@ -633,16 +633,12 @@ static int find_lut_index_for_rate(struct tegra_dfll *td, unsigned long rate)
|
||||||
struct dev_pm_opp *opp;
|
struct dev_pm_opp *opp;
|
||||||
int i, uv;
|
int i, uv;
|
||||||
|
|
||||||
rcu_read_lock();
|
|
||||||
|
|
||||||
opp = dev_pm_opp_find_freq_ceil(td->soc->dev, &rate);
|
opp = dev_pm_opp_find_freq_ceil(td->soc->dev, &rate);
|
||||||
if (IS_ERR(opp)) {
|
if (IS_ERR(opp))
|
||||||
rcu_read_unlock();
|
|
||||||
return PTR_ERR(opp);
|
return PTR_ERR(opp);
|
||||||
}
|
|
||||||
uv = dev_pm_opp_get_voltage(opp);
|
|
||||||
|
|
||||||
rcu_read_unlock();
|
uv = dev_pm_opp_get_voltage(opp);
|
||||||
|
dev_pm_opp_put(opp);
|
||||||
|
|
||||||
for (i = 0; i < td->i2c_lut_size; i++) {
|
for (i = 0; i < td->i2c_lut_size; i++) {
|
||||||
if (regulator_list_voltage(td->vdd_reg, td->i2c_lut[i]) == uv)
|
if (regulator_list_voltage(td->vdd_reg, td->i2c_lut[i]) == uv)
|
||||||
|
@ -1440,8 +1436,6 @@ static int dfll_build_i2c_lut(struct tegra_dfll *td)
|
||||||
struct dev_pm_opp *opp;
|
struct dev_pm_opp *opp;
|
||||||
int lut;
|
int lut;
|
||||||
|
|
||||||
rcu_read_lock();
|
|
||||||
|
|
||||||
rate = ULONG_MAX;
|
rate = ULONG_MAX;
|
||||||
opp = dev_pm_opp_find_freq_floor(td->soc->dev, &rate);
|
opp = dev_pm_opp_find_freq_floor(td->soc->dev, &rate);
|
||||||
if (IS_ERR(opp)) {
|
if (IS_ERR(opp)) {
|
||||||
|
@ -1449,6 +1443,7 @@ static int dfll_build_i2c_lut(struct tegra_dfll *td)
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
v_max = dev_pm_opp_get_voltage(opp);
|
v_max = dev_pm_opp_get_voltage(opp);
|
||||||
|
dev_pm_opp_put(opp);
|
||||||
|
|
||||||
v = td->soc->cvb->min_millivolts * 1000;
|
v = td->soc->cvb->min_millivolts * 1000;
|
||||||
lut = find_vdd_map_entry_exact(td, v);
|
lut = find_vdd_map_entry_exact(td, v);
|
||||||
|
@ -1465,6 +1460,8 @@ static int dfll_build_i2c_lut(struct tegra_dfll *td)
|
||||||
if (v_opp <= td->soc->cvb->min_millivolts * 1000)
|
if (v_opp <= td->soc->cvb->min_millivolts * 1000)
|
||||||
td->dvco_rate_min = dev_pm_opp_get_freq(opp);
|
td->dvco_rate_min = dev_pm_opp_get_freq(opp);
|
||||||
|
|
||||||
|
dev_pm_opp_put(opp);
|
||||||
|
|
||||||
for (;;) {
|
for (;;) {
|
||||||
v += max(1, (v_max - v) / (MAX_DFLL_VOLTAGES - j));
|
v += max(1, (v_max - v) / (MAX_DFLL_VOLTAGES - j));
|
||||||
if (v >= v_opp)
|
if (v >= v_opp)
|
||||||
|
@ -1496,8 +1493,6 @@ static int dfll_build_i2c_lut(struct tegra_dfll *td)
|
||||||
ret = 0;
|
ret = 0;
|
||||||
|
|
||||||
out:
|
out:
|
||||||
rcu_read_unlock();
|
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -148,7 +148,6 @@ static int cpufreq_init(struct cpufreq_policy *policy)
|
||||||
struct private_data *priv;
|
struct private_data *priv;
|
||||||
struct device *cpu_dev;
|
struct device *cpu_dev;
|
||||||
struct clk *cpu_clk;
|
struct clk *cpu_clk;
|
||||||
struct dev_pm_opp *suspend_opp;
|
|
||||||
unsigned int transition_latency;
|
unsigned int transition_latency;
|
||||||
bool fallback = false;
|
bool fallback = false;
|
||||||
const char *name;
|
const char *name;
|
||||||
|
@ -252,11 +251,7 @@ static int cpufreq_init(struct cpufreq_policy *policy)
|
||||||
policy->driver_data = priv;
|
policy->driver_data = priv;
|
||||||
policy->clk = cpu_clk;
|
policy->clk = cpu_clk;
|
||||||
|
|
||||||
rcu_read_lock();
|
policy->suspend_freq = dev_pm_opp_get_suspend_opp_freq(cpu_dev) / 1000;
|
||||||
suspend_opp = dev_pm_opp_get_suspend_opp(cpu_dev);
|
|
||||||
if (suspend_opp)
|
|
||||||
policy->suspend_freq = dev_pm_opp_get_freq(suspend_opp) / 1000;
|
|
||||||
rcu_read_unlock();
|
|
||||||
|
|
||||||
ret = cpufreq_table_validate_and_show(policy, freq_table);
|
ret = cpufreq_table_validate_and_show(policy, freq_table);
|
||||||
if (ret) {
|
if (ret) {
|
||||||
|
|
|
@ -118,12 +118,10 @@ static int init_div_table(void)
|
||||||
unsigned int tmp, clk_div, ema_div, freq, volt_id;
|
unsigned int tmp, clk_div, ema_div, freq, volt_id;
|
||||||
struct dev_pm_opp *opp;
|
struct dev_pm_opp *opp;
|
||||||
|
|
||||||
rcu_read_lock();
|
|
||||||
cpufreq_for_each_entry(pos, freq_tbl) {
|
cpufreq_for_each_entry(pos, freq_tbl) {
|
||||||
opp = dev_pm_opp_find_freq_exact(dvfs_info->dev,
|
opp = dev_pm_opp_find_freq_exact(dvfs_info->dev,
|
||||||
pos->frequency * 1000, true);
|
pos->frequency * 1000, true);
|
||||||
if (IS_ERR(opp)) {
|
if (IS_ERR(opp)) {
|
||||||
rcu_read_unlock();
|
|
||||||
dev_err(dvfs_info->dev,
|
dev_err(dvfs_info->dev,
|
||||||
"failed to find valid OPP for %u KHZ\n",
|
"failed to find valid OPP for %u KHZ\n",
|
||||||
pos->frequency);
|
pos->frequency);
|
||||||
|
@ -140,6 +138,7 @@ static int init_div_table(void)
|
||||||
|
|
||||||
/* Calculate EMA */
|
/* Calculate EMA */
|
||||||
volt_id = dev_pm_opp_get_voltage(opp);
|
volt_id = dev_pm_opp_get_voltage(opp);
|
||||||
|
|
||||||
volt_id = (MAX_VOLTAGE - volt_id) / VOLTAGE_STEP;
|
volt_id = (MAX_VOLTAGE - volt_id) / VOLTAGE_STEP;
|
||||||
if (volt_id < PMIC_HIGH_VOLT) {
|
if (volt_id < PMIC_HIGH_VOLT) {
|
||||||
ema_div = (CPUEMA_HIGH << P0_7_CPUEMA_SHIFT) |
|
ema_div = (CPUEMA_HIGH << P0_7_CPUEMA_SHIFT) |
|
||||||
|
@ -157,9 +156,9 @@ static int init_div_table(void)
|
||||||
|
|
||||||
__raw_writel(tmp, dvfs_info->base + XMU_PMU_P0_7 + 4 *
|
__raw_writel(tmp, dvfs_info->base + XMU_PMU_P0_7 + 4 *
|
||||||
(pos - freq_tbl));
|
(pos - freq_tbl));
|
||||||
|
dev_pm_opp_put(opp);
|
||||||
}
|
}
|
||||||
|
|
||||||
rcu_read_unlock();
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -53,16 +53,15 @@ static int imx6q_set_target(struct cpufreq_policy *policy, unsigned int index)
|
||||||
freq_hz = new_freq * 1000;
|
freq_hz = new_freq * 1000;
|
||||||
old_freq = clk_get_rate(arm_clk) / 1000;
|
old_freq = clk_get_rate(arm_clk) / 1000;
|
||||||
|
|
||||||
rcu_read_lock();
|
|
||||||
opp = dev_pm_opp_find_freq_ceil(cpu_dev, &freq_hz);
|
opp = dev_pm_opp_find_freq_ceil(cpu_dev, &freq_hz);
|
||||||
if (IS_ERR(opp)) {
|
if (IS_ERR(opp)) {
|
||||||
rcu_read_unlock();
|
|
||||||
dev_err(cpu_dev, "failed to find OPP for %ld\n", freq_hz);
|
dev_err(cpu_dev, "failed to find OPP for %ld\n", freq_hz);
|
||||||
return PTR_ERR(opp);
|
return PTR_ERR(opp);
|
||||||
}
|
}
|
||||||
|
|
||||||
volt = dev_pm_opp_get_voltage(opp);
|
volt = dev_pm_opp_get_voltage(opp);
|
||||||
rcu_read_unlock();
|
dev_pm_opp_put(opp);
|
||||||
|
|
||||||
volt_old = regulator_get_voltage(arm_reg);
|
volt_old = regulator_get_voltage(arm_reg);
|
||||||
|
|
||||||
dev_dbg(cpu_dev, "%u MHz, %ld mV --> %u MHz, %ld mV\n",
|
dev_dbg(cpu_dev, "%u MHz, %ld mV --> %u MHz, %ld mV\n",
|
||||||
|
@ -321,14 +320,15 @@ static int imx6q_cpufreq_probe(struct platform_device *pdev)
|
||||||
* freq_table initialised from OPP is therefore sorted in the
|
* freq_table initialised from OPP is therefore sorted in the
|
||||||
* same order.
|
* same order.
|
||||||
*/
|
*/
|
||||||
rcu_read_lock();
|
|
||||||
opp = dev_pm_opp_find_freq_exact(cpu_dev,
|
opp = dev_pm_opp_find_freq_exact(cpu_dev,
|
||||||
freq_table[0].frequency * 1000, true);
|
freq_table[0].frequency * 1000, true);
|
||||||
min_volt = dev_pm_opp_get_voltage(opp);
|
min_volt = dev_pm_opp_get_voltage(opp);
|
||||||
|
dev_pm_opp_put(opp);
|
||||||
opp = dev_pm_opp_find_freq_exact(cpu_dev,
|
opp = dev_pm_opp_find_freq_exact(cpu_dev,
|
||||||
freq_table[--num].frequency * 1000, true);
|
freq_table[--num].frequency * 1000, true);
|
||||||
max_volt = dev_pm_opp_get_voltage(opp);
|
max_volt = dev_pm_opp_get_voltage(opp);
|
||||||
rcu_read_unlock();
|
dev_pm_opp_put(opp);
|
||||||
|
|
||||||
ret = regulator_set_voltage_time(arm_reg, min_volt, max_volt);
|
ret = regulator_set_voltage_time(arm_reg, min_volt, max_volt);
|
||||||
if (ret > 0)
|
if (ret > 0)
|
||||||
transition_latency += ret * 1000;
|
transition_latency += ret * 1000;
|
||||||
|
|
|
@ -232,16 +232,14 @@ static int mtk_cpufreq_set_target(struct cpufreq_policy *policy,
|
||||||
|
|
||||||
freq_hz = freq_table[index].frequency * 1000;
|
freq_hz = freq_table[index].frequency * 1000;
|
||||||
|
|
||||||
rcu_read_lock();
|
|
||||||
opp = dev_pm_opp_find_freq_ceil(cpu_dev, &freq_hz);
|
opp = dev_pm_opp_find_freq_ceil(cpu_dev, &freq_hz);
|
||||||
if (IS_ERR(opp)) {
|
if (IS_ERR(opp)) {
|
||||||
rcu_read_unlock();
|
|
||||||
pr_err("cpu%d: failed to find OPP for %ld\n",
|
pr_err("cpu%d: failed to find OPP for %ld\n",
|
||||||
policy->cpu, freq_hz);
|
policy->cpu, freq_hz);
|
||||||
return PTR_ERR(opp);
|
return PTR_ERR(opp);
|
||||||
}
|
}
|
||||||
vproc = dev_pm_opp_get_voltage(opp);
|
vproc = dev_pm_opp_get_voltage(opp);
|
||||||
rcu_read_unlock();
|
dev_pm_opp_put(opp);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* If the new voltage or the intermediate voltage is higher than the
|
* If the new voltage or the intermediate voltage is higher than the
|
||||||
|
@ -411,16 +409,14 @@ static int mtk_cpu_dvfs_info_init(struct mtk_cpu_dvfs_info *info, int cpu)
|
||||||
|
|
||||||
/* Search a safe voltage for intermediate frequency. */
|
/* Search a safe voltage for intermediate frequency. */
|
||||||
rate = clk_get_rate(inter_clk);
|
rate = clk_get_rate(inter_clk);
|
||||||
rcu_read_lock();
|
|
||||||
opp = dev_pm_opp_find_freq_ceil(cpu_dev, &rate);
|
opp = dev_pm_opp_find_freq_ceil(cpu_dev, &rate);
|
||||||
if (IS_ERR(opp)) {
|
if (IS_ERR(opp)) {
|
||||||
rcu_read_unlock();
|
|
||||||
pr_err("failed to get intermediate opp for cpu%d\n", cpu);
|
pr_err("failed to get intermediate opp for cpu%d\n", cpu);
|
||||||
ret = PTR_ERR(opp);
|
ret = PTR_ERR(opp);
|
||||||
goto out_free_opp_table;
|
goto out_free_opp_table;
|
||||||
}
|
}
|
||||||
info->intermediate_voltage = dev_pm_opp_get_voltage(opp);
|
info->intermediate_voltage = dev_pm_opp_get_voltage(opp);
|
||||||
rcu_read_unlock();
|
dev_pm_opp_put(opp);
|
||||||
|
|
||||||
info->cpu_dev = cpu_dev;
|
info->cpu_dev = cpu_dev;
|
||||||
info->proc_reg = proc_reg;
|
info->proc_reg = proc_reg;
|
||||||
|
|
|
@ -63,16 +63,14 @@ static int omap_target(struct cpufreq_policy *policy, unsigned int index)
|
||||||
freq = ret;
|
freq = ret;
|
||||||
|
|
||||||
if (mpu_reg) {
|
if (mpu_reg) {
|
||||||
rcu_read_lock();
|
|
||||||
opp = dev_pm_opp_find_freq_ceil(mpu_dev, &freq);
|
opp = dev_pm_opp_find_freq_ceil(mpu_dev, &freq);
|
||||||
if (IS_ERR(opp)) {
|
if (IS_ERR(opp)) {
|
||||||
rcu_read_unlock();
|
|
||||||
dev_err(mpu_dev, "%s: unable to find MPU OPP for %d\n",
|
dev_err(mpu_dev, "%s: unable to find MPU OPP for %d\n",
|
||||||
__func__, new_freq);
|
__func__, new_freq);
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
}
|
}
|
||||||
volt = dev_pm_opp_get_voltage(opp);
|
volt = dev_pm_opp_get_voltage(opp);
|
||||||
rcu_read_unlock();
|
dev_pm_opp_put(opp);
|
||||||
tol = volt * OPP_TOLERANCE / 100;
|
tol = volt * OPP_TOLERANCE / 100;
|
||||||
volt_old = regulator_get_voltage(mpu_reg);
|
volt_old = regulator_get_voltage(mpu_reg);
|
||||||
}
|
}
|
||||||
|
|
|
@ -160,6 +160,7 @@ static int sti_cpufreq_set_opp_info(void)
|
||||||
int pcode, substrate, major, minor;
|
int pcode, substrate, major, minor;
|
||||||
int ret;
|
int ret;
|
||||||
char name[MAX_PCODE_NAME_LEN];
|
char name[MAX_PCODE_NAME_LEN];
|
||||||
|
struct opp_table *opp_table;
|
||||||
|
|
||||||
reg_fields = sti_cpufreq_match();
|
reg_fields = sti_cpufreq_match();
|
||||||
if (!reg_fields) {
|
if (!reg_fields) {
|
||||||
|
@ -211,20 +212,20 @@ static int sti_cpufreq_set_opp_info(void)
|
||||||
|
|
||||||
snprintf(name, MAX_PCODE_NAME_LEN, "pcode%d", pcode);
|
snprintf(name, MAX_PCODE_NAME_LEN, "pcode%d", pcode);
|
||||||
|
|
||||||
ret = dev_pm_opp_set_prop_name(dev, name);
|
opp_table = dev_pm_opp_set_prop_name(dev, name);
|
||||||
if (ret) {
|
if (IS_ERR(opp_table)) {
|
||||||
dev_err(dev, "Failed to set prop name\n");
|
dev_err(dev, "Failed to set prop name\n");
|
||||||
return ret;
|
return PTR_ERR(opp_table);
|
||||||
}
|
}
|
||||||
|
|
||||||
version[0] = BIT(major);
|
version[0] = BIT(major);
|
||||||
version[1] = BIT(minor);
|
version[1] = BIT(minor);
|
||||||
version[2] = BIT(substrate);
|
version[2] = BIT(substrate);
|
||||||
|
|
||||||
ret = dev_pm_opp_set_supported_hw(dev, version, VERSION_ELEMENTS);
|
opp_table = dev_pm_opp_set_supported_hw(dev, version, VERSION_ELEMENTS);
|
||||||
if (ret) {
|
if (IS_ERR(opp_table)) {
|
||||||
dev_err(dev, "Failed to set supported hardware\n");
|
dev_err(dev, "Failed to set supported hardware\n");
|
||||||
return ret;
|
return PTR_ERR(opp_table);
|
||||||
}
|
}
|
||||||
|
|
||||||
dev_dbg(dev, "pcode: %d major: %d minor: %d substrate: %d\n",
|
dev_dbg(dev, "pcode: %d major: %d minor: %d substrate: %d\n",
|
||||||
|
|
|
@ -111,18 +111,16 @@ static void devfreq_set_freq_table(struct devfreq *devfreq)
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
rcu_read_lock();
|
|
||||||
for (i = 0, freq = 0; i < profile->max_state; i++, freq++) {
|
for (i = 0, freq = 0; i < profile->max_state; i++, freq++) {
|
||||||
opp = dev_pm_opp_find_freq_ceil(devfreq->dev.parent, &freq);
|
opp = dev_pm_opp_find_freq_ceil(devfreq->dev.parent, &freq);
|
||||||
if (IS_ERR(opp)) {
|
if (IS_ERR(opp)) {
|
||||||
devm_kfree(devfreq->dev.parent, profile->freq_table);
|
devm_kfree(devfreq->dev.parent, profile->freq_table);
|
||||||
profile->max_state = 0;
|
profile->max_state = 0;
|
||||||
rcu_read_unlock();
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
dev_pm_opp_put(opp);
|
||||||
profile->freq_table[i] = freq;
|
profile->freq_table[i] = freq;
|
||||||
}
|
}
|
||||||
rcu_read_unlock();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -1112,17 +1110,16 @@ static ssize_t available_frequencies_show(struct device *d,
|
||||||
ssize_t count = 0;
|
ssize_t count = 0;
|
||||||
unsigned long freq = 0;
|
unsigned long freq = 0;
|
||||||
|
|
||||||
rcu_read_lock();
|
|
||||||
do {
|
do {
|
||||||
opp = dev_pm_opp_find_freq_ceil(dev, &freq);
|
opp = dev_pm_opp_find_freq_ceil(dev, &freq);
|
||||||
if (IS_ERR(opp))
|
if (IS_ERR(opp))
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
dev_pm_opp_put(opp);
|
||||||
count += scnprintf(&buf[count], (PAGE_SIZE - count - 2),
|
count += scnprintf(&buf[count], (PAGE_SIZE - count - 2),
|
||||||
"%lu ", freq);
|
"%lu ", freq);
|
||||||
freq++;
|
freq++;
|
||||||
} while (1);
|
} while (1);
|
||||||
rcu_read_unlock();
|
|
||||||
|
|
||||||
/* Truncate the trailing space */
|
/* Truncate the trailing space */
|
||||||
if (count)
|
if (count)
|
||||||
|
@ -1224,11 +1221,8 @@ subsys_initcall(devfreq_init);
|
||||||
* @freq: The frequency given to target function
|
* @freq: The frequency given to target function
|
||||||
* @flags: Flags handed from devfreq framework.
|
* @flags: Flags handed from devfreq framework.
|
||||||
*
|
*
|
||||||
* Locking: This function must be called under rcu_read_lock(). opp is a rcu
|
* The callers are required to call dev_pm_opp_put() for the returned OPP after
|
||||||
* protected pointer. The reason for the same is that the opp pointer which is
|
* use.
|
||||||
* returned will remain valid for use with opp_get_{voltage, freq} only while
|
|
||||||
* under the locked area. The pointer returned must be used prior to unlocking
|
|
||||||
* with rcu_read_unlock() to maintain the integrity of the pointer.
|
|
||||||
*/
|
*/
|
||||||
struct dev_pm_opp *devfreq_recommended_opp(struct device *dev,
|
struct dev_pm_opp *devfreq_recommended_opp(struct device *dev,
|
||||||
unsigned long *freq,
|
unsigned long *freq,
|
||||||
|
@ -1265,18 +1259,7 @@ EXPORT_SYMBOL(devfreq_recommended_opp);
|
||||||
*/
|
*/
|
||||||
int devfreq_register_opp_notifier(struct device *dev, struct devfreq *devfreq)
|
int devfreq_register_opp_notifier(struct device *dev, struct devfreq *devfreq)
|
||||||
{
|
{
|
||||||
struct srcu_notifier_head *nh;
|
return dev_pm_opp_register_notifier(dev, &devfreq->nb);
|
||||||
int ret = 0;
|
|
||||||
|
|
||||||
rcu_read_lock();
|
|
||||||
nh = dev_pm_opp_get_notifier(dev);
|
|
||||||
if (IS_ERR(nh))
|
|
||||||
ret = PTR_ERR(nh);
|
|
||||||
rcu_read_unlock();
|
|
||||||
if (!ret)
|
|
||||||
ret = srcu_notifier_chain_register(nh, &devfreq->nb);
|
|
||||||
|
|
||||||
return ret;
|
|
||||||
}
|
}
|
||||||
EXPORT_SYMBOL(devfreq_register_opp_notifier);
|
EXPORT_SYMBOL(devfreq_register_opp_notifier);
|
||||||
|
|
||||||
|
@ -1292,18 +1275,7 @@ EXPORT_SYMBOL(devfreq_register_opp_notifier);
|
||||||
*/
|
*/
|
||||||
int devfreq_unregister_opp_notifier(struct device *dev, struct devfreq *devfreq)
|
int devfreq_unregister_opp_notifier(struct device *dev, struct devfreq *devfreq)
|
||||||
{
|
{
|
||||||
struct srcu_notifier_head *nh;
|
return dev_pm_opp_unregister_notifier(dev, &devfreq->nb);
|
||||||
int ret = 0;
|
|
||||||
|
|
||||||
rcu_read_lock();
|
|
||||||
nh = dev_pm_opp_get_notifier(dev);
|
|
||||||
if (IS_ERR(nh))
|
|
||||||
ret = PTR_ERR(nh);
|
|
||||||
rcu_read_unlock();
|
|
||||||
if (!ret)
|
|
||||||
ret = srcu_notifier_chain_unregister(nh, &devfreq->nb);
|
|
||||||
|
|
||||||
return ret;
|
|
||||||
}
|
}
|
||||||
EXPORT_SYMBOL(devfreq_unregister_opp_notifier);
|
EXPORT_SYMBOL(devfreq_unregister_opp_notifier);
|
||||||
|
|
||||||
|
|
|
@ -103,18 +103,17 @@ static int exynos_bus_target(struct device *dev, unsigned long *freq, u32 flags)
|
||||||
int ret = 0;
|
int ret = 0;
|
||||||
|
|
||||||
/* Get new opp-bus instance according to new bus clock */
|
/* Get new opp-bus instance according to new bus clock */
|
||||||
rcu_read_lock();
|
|
||||||
new_opp = devfreq_recommended_opp(dev, freq, flags);
|
new_opp = devfreq_recommended_opp(dev, freq, flags);
|
||||||
if (IS_ERR(new_opp)) {
|
if (IS_ERR(new_opp)) {
|
||||||
dev_err(dev, "failed to get recommended opp instance\n");
|
dev_err(dev, "failed to get recommended opp instance\n");
|
||||||
rcu_read_unlock();
|
|
||||||
return PTR_ERR(new_opp);
|
return PTR_ERR(new_opp);
|
||||||
}
|
}
|
||||||
|
|
||||||
new_freq = dev_pm_opp_get_freq(new_opp);
|
new_freq = dev_pm_opp_get_freq(new_opp);
|
||||||
new_volt = dev_pm_opp_get_voltage(new_opp);
|
new_volt = dev_pm_opp_get_voltage(new_opp);
|
||||||
|
dev_pm_opp_put(new_opp);
|
||||||
|
|
||||||
old_freq = bus->curr_freq;
|
old_freq = bus->curr_freq;
|
||||||
rcu_read_unlock();
|
|
||||||
|
|
||||||
if (old_freq == new_freq)
|
if (old_freq == new_freq)
|
||||||
return 0;
|
return 0;
|
||||||
|
@ -214,17 +213,16 @@ static int exynos_bus_passive_target(struct device *dev, unsigned long *freq,
|
||||||
int ret = 0;
|
int ret = 0;
|
||||||
|
|
||||||
/* Get new opp-bus instance according to new bus clock */
|
/* Get new opp-bus instance according to new bus clock */
|
||||||
rcu_read_lock();
|
|
||||||
new_opp = devfreq_recommended_opp(dev, freq, flags);
|
new_opp = devfreq_recommended_opp(dev, freq, flags);
|
||||||
if (IS_ERR(new_opp)) {
|
if (IS_ERR(new_opp)) {
|
||||||
dev_err(dev, "failed to get recommended opp instance\n");
|
dev_err(dev, "failed to get recommended opp instance\n");
|
||||||
rcu_read_unlock();
|
|
||||||
return PTR_ERR(new_opp);
|
return PTR_ERR(new_opp);
|
||||||
}
|
}
|
||||||
|
|
||||||
new_freq = dev_pm_opp_get_freq(new_opp);
|
new_freq = dev_pm_opp_get_freq(new_opp);
|
||||||
|
dev_pm_opp_put(new_opp);
|
||||||
|
|
||||||
old_freq = bus->curr_freq;
|
old_freq = bus->curr_freq;
|
||||||
rcu_read_unlock();
|
|
||||||
|
|
||||||
if (old_freq == new_freq)
|
if (old_freq == new_freq)
|
||||||
return 0;
|
return 0;
|
||||||
|
@ -358,16 +356,14 @@ static int exynos_bus_parse_of(struct device_node *np,
|
||||||
|
|
||||||
rate = clk_get_rate(bus->clk);
|
rate = clk_get_rate(bus->clk);
|
||||||
|
|
||||||
rcu_read_lock();
|
|
||||||
opp = devfreq_recommended_opp(dev, &rate, 0);
|
opp = devfreq_recommended_opp(dev, &rate, 0);
|
||||||
if (IS_ERR(opp)) {
|
if (IS_ERR(opp)) {
|
||||||
dev_err(dev, "failed to find dev_pm_opp\n");
|
dev_err(dev, "failed to find dev_pm_opp\n");
|
||||||
rcu_read_unlock();
|
|
||||||
ret = PTR_ERR(opp);
|
ret = PTR_ERR(opp);
|
||||||
goto err_opp;
|
goto err_opp;
|
||||||
}
|
}
|
||||||
bus->curr_freq = dev_pm_opp_get_freq(opp);
|
bus->curr_freq = dev_pm_opp_get_freq(opp);
|
||||||
rcu_read_unlock();
|
dev_pm_opp_put(opp);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
|
|
|
@ -59,14 +59,14 @@ 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.
|
||||||
*/
|
*/
|
||||||
rcu_read_lock();
|
|
||||||
opp = devfreq_recommended_opp(parent_devfreq->dev.parent, freq, 0);
|
opp = devfreq_recommended_opp(parent_devfreq->dev.parent, freq, 0);
|
||||||
rcu_read_unlock();
|
|
||||||
if (IS_ERR(opp)) {
|
if (IS_ERR(opp)) {
|
||||||
ret = PTR_ERR(opp);
|
ret = PTR_ERR(opp);
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
dev_pm_opp_put(opp);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Get the OPP table's index of decided freqeuncy by governor
|
* Get the OPP table's index of decided freqeuncy by governor
|
||||||
* of parent device.
|
* of parent device.
|
||||||
|
|
|
@ -91,17 +91,13 @@ static int rk3399_dmcfreq_target(struct device *dev, unsigned long *freq,
|
||||||
unsigned long target_volt, target_rate;
|
unsigned long target_volt, target_rate;
|
||||||
int err;
|
int err;
|
||||||
|
|
||||||
rcu_read_lock();
|
|
||||||
opp = devfreq_recommended_opp(dev, freq, flags);
|
opp = devfreq_recommended_opp(dev, freq, flags);
|
||||||
if (IS_ERR(opp)) {
|
if (IS_ERR(opp))
|
||||||
rcu_read_unlock();
|
|
||||||
return PTR_ERR(opp);
|
return PTR_ERR(opp);
|
||||||
}
|
|
||||||
|
|
||||||
target_rate = dev_pm_opp_get_freq(opp);
|
target_rate = dev_pm_opp_get_freq(opp);
|
||||||
target_volt = dev_pm_opp_get_voltage(opp);
|
target_volt = dev_pm_opp_get_voltage(opp);
|
||||||
|
dev_pm_opp_put(opp);
|
||||||
rcu_read_unlock();
|
|
||||||
|
|
||||||
if (dmcfreq->rate == target_rate)
|
if (dmcfreq->rate == target_rate)
|
||||||
return 0;
|
return 0;
|
||||||
|
@ -422,15 +418,13 @@ static int rk3399_dmcfreq_probe(struct platform_device *pdev)
|
||||||
|
|
||||||
data->rate = clk_get_rate(data->dmc_clk);
|
data->rate = clk_get_rate(data->dmc_clk);
|
||||||
|
|
||||||
rcu_read_lock();
|
|
||||||
opp = devfreq_recommended_opp(dev, &data->rate, 0);
|
opp = devfreq_recommended_opp(dev, &data->rate, 0);
|
||||||
if (IS_ERR(opp)) {
|
if (IS_ERR(opp))
|
||||||
rcu_read_unlock();
|
|
||||||
return PTR_ERR(opp);
|
return PTR_ERR(opp);
|
||||||
}
|
|
||||||
data->rate = dev_pm_opp_get_freq(opp);
|
data->rate = dev_pm_opp_get_freq(opp);
|
||||||
data->volt = dev_pm_opp_get_voltage(opp);
|
data->volt = dev_pm_opp_get_voltage(opp);
|
||||||
rcu_read_unlock();
|
dev_pm_opp_put(opp);
|
||||||
|
|
||||||
rk3399_devfreq_dmc_profile.initial_freq = data->rate;
|
rk3399_devfreq_dmc_profile.initial_freq = data->rate;
|
||||||
|
|
||||||
|
|
|
@ -487,15 +487,13 @@ static int tegra_devfreq_target(struct device *dev, unsigned long *freq,
|
||||||
struct dev_pm_opp *opp;
|
struct dev_pm_opp *opp;
|
||||||
unsigned long rate = *freq * KHZ;
|
unsigned long rate = *freq * KHZ;
|
||||||
|
|
||||||
rcu_read_lock();
|
|
||||||
opp = devfreq_recommended_opp(dev, &rate, flags);
|
opp = devfreq_recommended_opp(dev, &rate, flags);
|
||||||
if (IS_ERR(opp)) {
|
if (IS_ERR(opp)) {
|
||||||
rcu_read_unlock();
|
|
||||||
dev_err(dev, "Failed to find opp for %lu KHz\n", *freq);
|
dev_err(dev, "Failed to find opp for %lu KHz\n", *freq);
|
||||||
return PTR_ERR(opp);
|
return PTR_ERR(opp);
|
||||||
}
|
}
|
||||||
rate = dev_pm_opp_get_freq(opp);
|
rate = dev_pm_opp_get_freq(opp);
|
||||||
rcu_read_unlock();
|
dev_pm_opp_put(opp);
|
||||||
|
|
||||||
clk_set_min_rate(tegra->emc_clock, rate);
|
clk_set_min_rate(tegra->emc_clock, rate);
|
||||||
clk_set_rate(tegra->emc_clock, 0);
|
clk_set_rate(tegra->emc_clock, 0);
|
||||||
|
|
|
@ -297,8 +297,6 @@ static int build_dyn_power_table(struct cpufreq_cooling_device *cpufreq_device,
|
||||||
if (!power_table)
|
if (!power_table)
|
||||||
return -ENOMEM;
|
return -ENOMEM;
|
||||||
|
|
||||||
rcu_read_lock();
|
|
||||||
|
|
||||||
for (freq = 0, i = 0;
|
for (freq = 0, i = 0;
|
||||||
opp = dev_pm_opp_find_freq_ceil(dev, &freq), !IS_ERR(opp);
|
opp = dev_pm_opp_find_freq_ceil(dev, &freq), !IS_ERR(opp);
|
||||||
freq++, i++) {
|
freq++, i++) {
|
||||||
|
@ -306,13 +304,13 @@ static int build_dyn_power_table(struct cpufreq_cooling_device *cpufreq_device,
|
||||||
u64 power;
|
u64 power;
|
||||||
|
|
||||||
if (i >= num_opps) {
|
if (i >= num_opps) {
|
||||||
rcu_read_unlock();
|
|
||||||
ret = -EAGAIN;
|
ret = -EAGAIN;
|
||||||
goto free_power_table;
|
goto free_power_table;
|
||||||
}
|
}
|
||||||
|
|
||||||
freq_mhz = freq / 1000000;
|
freq_mhz = freq / 1000000;
|
||||||
voltage_mv = dev_pm_opp_get_voltage(opp) / 1000;
|
voltage_mv = dev_pm_opp_get_voltage(opp) / 1000;
|
||||||
|
dev_pm_opp_put(opp);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Do the multiplication with MHz and millivolt so as
|
* Do the multiplication with MHz and millivolt so as
|
||||||
|
@ -328,8 +326,6 @@ static int build_dyn_power_table(struct cpufreq_cooling_device *cpufreq_device,
|
||||||
power_table[i].power = power;
|
power_table[i].power = power;
|
||||||
}
|
}
|
||||||
|
|
||||||
rcu_read_unlock();
|
|
||||||
|
|
||||||
if (i != num_opps) {
|
if (i != num_opps) {
|
||||||
ret = PTR_ERR(opp);
|
ret = PTR_ERR(opp);
|
||||||
goto free_power_table;
|
goto free_power_table;
|
||||||
|
@ -433,13 +429,10 @@ static int get_static_power(struct cpufreq_cooling_device *cpufreq_device,
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
rcu_read_lock();
|
|
||||||
|
|
||||||
opp = dev_pm_opp_find_freq_exact(cpufreq_device->cpu_dev, freq_hz,
|
opp = dev_pm_opp_find_freq_exact(cpufreq_device->cpu_dev, freq_hz,
|
||||||
true);
|
true);
|
||||||
voltage = dev_pm_opp_get_voltage(opp);
|
voltage = dev_pm_opp_get_voltage(opp);
|
||||||
|
dev_pm_opp_put(opp);
|
||||||
rcu_read_unlock();
|
|
||||||
|
|
||||||
if (voltage == 0) {
|
if (voltage == 0) {
|
||||||
dev_warn_ratelimited(cpufreq_device->cpu_dev,
|
dev_warn_ratelimited(cpufreq_device->cpu_dev,
|
||||||
|
|
|
@ -113,15 +113,15 @@ static int partition_enable_opps(struct devfreq_cooling_device *dfc,
|
||||||
unsigned int freq = dfc->freq_table[i];
|
unsigned int freq = dfc->freq_table[i];
|
||||||
bool want_enable = i >= cdev_state ? true : false;
|
bool want_enable = i >= cdev_state ? true : false;
|
||||||
|
|
||||||
rcu_read_lock();
|
|
||||||
opp = dev_pm_opp_find_freq_exact(dev, freq, !want_enable);
|
opp = dev_pm_opp_find_freq_exact(dev, freq, !want_enable);
|
||||||
rcu_read_unlock();
|
|
||||||
|
|
||||||
if (PTR_ERR(opp) == -ERANGE)
|
if (PTR_ERR(opp) == -ERANGE)
|
||||||
continue;
|
continue;
|
||||||
else if (IS_ERR(opp))
|
else if (IS_ERR(opp))
|
||||||
return PTR_ERR(opp);
|
return PTR_ERR(opp);
|
||||||
|
|
||||||
|
dev_pm_opp_put(opp);
|
||||||
|
|
||||||
if (want_enable)
|
if (want_enable)
|
||||||
ret = dev_pm_opp_enable(dev, freq);
|
ret = dev_pm_opp_enable(dev, freq);
|
||||||
else
|
else
|
||||||
|
@ -221,15 +221,12 @@ get_static_power(struct devfreq_cooling_device *dfc, unsigned long freq)
|
||||||
if (!dfc->power_ops->get_static_power)
|
if (!dfc->power_ops->get_static_power)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
rcu_read_lock();
|
|
||||||
|
|
||||||
opp = dev_pm_opp_find_freq_exact(dev, freq, true);
|
opp = dev_pm_opp_find_freq_exact(dev, freq, true);
|
||||||
if (IS_ERR(opp) && (PTR_ERR(opp) == -ERANGE))
|
if (IS_ERR(opp) && (PTR_ERR(opp) == -ERANGE))
|
||||||
opp = dev_pm_opp_find_freq_exact(dev, freq, false);
|
opp = dev_pm_opp_find_freq_exact(dev, freq, false);
|
||||||
|
|
||||||
voltage = dev_pm_opp_get_voltage(opp) / 1000; /* mV */
|
voltage = dev_pm_opp_get_voltage(opp) / 1000; /* mV */
|
||||||
|
dev_pm_opp_put(opp);
|
||||||
rcu_read_unlock();
|
|
||||||
|
|
||||||
if (voltage == 0) {
|
if (voltage == 0) {
|
||||||
dev_warn_ratelimited(dev,
|
dev_warn_ratelimited(dev,
|
||||||
|
@ -412,18 +409,14 @@ static int devfreq_cooling_gen_tables(struct devfreq_cooling_device *dfc)
|
||||||
unsigned long power_dyn, voltage;
|
unsigned long power_dyn, voltage;
|
||||||
struct dev_pm_opp *opp;
|
struct dev_pm_opp *opp;
|
||||||
|
|
||||||
rcu_read_lock();
|
|
||||||
|
|
||||||
opp = dev_pm_opp_find_freq_floor(dev, &freq);
|
opp = dev_pm_opp_find_freq_floor(dev, &freq);
|
||||||
if (IS_ERR(opp)) {
|
if (IS_ERR(opp)) {
|
||||||
rcu_read_unlock();
|
|
||||||
ret = PTR_ERR(opp);
|
ret = PTR_ERR(opp);
|
||||||
goto free_tables;
|
goto free_tables;
|
||||||
}
|
}
|
||||||
|
|
||||||
voltage = dev_pm_opp_get_voltage(opp) / 1000; /* mV */
|
voltage = dev_pm_opp_get_voltage(opp) / 1000; /* mV */
|
||||||
|
dev_pm_opp_put(opp);
|
||||||
rcu_read_unlock();
|
|
||||||
|
|
||||||
if (dfc->power_ops) {
|
if (dfc->power_ops) {
|
||||||
power_dyn = get_dynamic_power(dfc, freq, voltage);
|
power_dyn = get_dynamic_power(dfc, freq, voltage);
|
||||||
|
|
|
@ -78,6 +78,9 @@ struct dev_pm_set_opp_data {
|
||||||
|
|
||||||
#if defined(CONFIG_PM_OPP)
|
#if defined(CONFIG_PM_OPP)
|
||||||
|
|
||||||
|
struct opp_table *dev_pm_opp_get_opp_table(struct device *dev);
|
||||||
|
void dev_pm_opp_put_opp_table(struct opp_table *opp_table);
|
||||||
|
|
||||||
unsigned long dev_pm_opp_get_voltage(struct dev_pm_opp *opp);
|
unsigned long dev_pm_opp_get_voltage(struct dev_pm_opp *opp);
|
||||||
|
|
||||||
unsigned long dev_pm_opp_get_freq(struct dev_pm_opp *opp);
|
unsigned long dev_pm_opp_get_freq(struct dev_pm_opp *opp);
|
||||||
|
@ -88,7 +91,7 @@ int dev_pm_opp_get_opp_count(struct device *dev);
|
||||||
unsigned long dev_pm_opp_get_max_clock_latency(struct device *dev);
|
unsigned long dev_pm_opp_get_max_clock_latency(struct device *dev);
|
||||||
unsigned long dev_pm_opp_get_max_volt_latency(struct device *dev);
|
unsigned long dev_pm_opp_get_max_volt_latency(struct device *dev);
|
||||||
unsigned long dev_pm_opp_get_max_transition_latency(struct device *dev);
|
unsigned long dev_pm_opp_get_max_transition_latency(struct device *dev);
|
||||||
struct dev_pm_opp *dev_pm_opp_get_suspend_opp(struct device *dev);
|
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,
|
||||||
|
@ -99,6 +102,7 @@ struct dev_pm_opp *dev_pm_opp_find_freq_floor(struct device *dev,
|
||||||
|
|
||||||
struct dev_pm_opp *dev_pm_opp_find_freq_ceil(struct device *dev,
|
struct dev_pm_opp *dev_pm_opp_find_freq_ceil(struct device *dev,
|
||||||
unsigned long *freq);
|
unsigned long *freq);
|
||||||
|
void dev_pm_opp_put(struct dev_pm_opp *opp);
|
||||||
|
|
||||||
int dev_pm_opp_add(struct device *dev, unsigned long freq,
|
int dev_pm_opp_add(struct device *dev, unsigned long freq,
|
||||||
unsigned long u_volt);
|
unsigned long u_volt);
|
||||||
|
@ -108,22 +112,30 @@ int dev_pm_opp_enable(struct device *dev, unsigned long freq);
|
||||||
|
|
||||||
int dev_pm_opp_disable(struct device *dev, unsigned long freq);
|
int dev_pm_opp_disable(struct device *dev, unsigned long freq);
|
||||||
|
|
||||||
struct srcu_notifier_head *dev_pm_opp_get_notifier(struct device *dev);
|
int dev_pm_opp_register_notifier(struct device *dev, struct notifier_block *nb);
|
||||||
int dev_pm_opp_set_supported_hw(struct device *dev, const u32 *versions,
|
int dev_pm_opp_unregister_notifier(struct device *dev, struct notifier_block *nb);
|
||||||
unsigned int count);
|
|
||||||
void dev_pm_opp_put_supported_hw(struct device *dev);
|
struct opp_table *dev_pm_opp_set_supported_hw(struct device *dev, const u32 *versions, unsigned int count);
|
||||||
int dev_pm_opp_set_prop_name(struct device *dev, const char *name);
|
void dev_pm_opp_put_supported_hw(struct opp_table *opp_table);
|
||||||
void dev_pm_opp_put_prop_name(struct device *dev);
|
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);
|
||||||
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);
|
||||||
int 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_register_put_opp_helper(struct device *dev);
|
void dev_pm_opp_register_put_opp_helper(struct opp_table *opp_table);
|
||||||
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_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);
|
||||||
#else
|
#else
|
||||||
|
static inline struct opp_table *dev_pm_opp_get_opp_table(struct device *dev)
|
||||||
|
{
|
||||||
|
return ERR_PTR(-ENOTSUPP);
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline void dev_pm_opp_put_opp_table(struct opp_table *opp_table) {}
|
||||||
|
|
||||||
static inline unsigned long dev_pm_opp_get_voltage(struct dev_pm_opp *opp)
|
static inline unsigned long dev_pm_opp_get_voltage(struct dev_pm_opp *opp)
|
||||||
{
|
{
|
||||||
return 0;
|
return 0;
|
||||||
|
@ -159,9 +171,9 @@ static inline unsigned long dev_pm_opp_get_max_transition_latency(struct device
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline struct dev_pm_opp *dev_pm_opp_get_suspend_opp(struct device *dev)
|
static inline unsigned long dev_pm_opp_get_suspend_opp_freq(struct device *dev)
|
||||||
{
|
{
|
||||||
return NULL;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
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,
|
||||||
|
@ -182,6 +194,8 @@ static inline struct dev_pm_opp *dev_pm_opp_find_freq_ceil(struct device *dev,
|
||||||
return ERR_PTR(-ENOTSUPP);
|
return ERR_PTR(-ENOTSUPP);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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)
|
||||||
{
|
{
|
||||||
|
@ -202,35 +216,39 @@ static inline int dev_pm_opp_disable(struct device *dev, unsigned long freq)
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline struct srcu_notifier_head *dev_pm_opp_get_notifier(
|
static inline int dev_pm_opp_register_notifier(struct device *dev, struct notifier_block *nb)
|
||||||
struct device *dev)
|
{
|
||||||
|
return -ENOTSUPP;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline int dev_pm_opp_unregister_notifier(struct device *dev, struct notifier_block *nb)
|
||||||
|
{
|
||||||
|
return -ENOTSUPP;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline struct opp_table *dev_pm_opp_set_supported_hw(struct device *dev,
|
||||||
|
const u32 *versions,
|
||||||
|
unsigned int count)
|
||||||
{
|
{
|
||||||
return ERR_PTR(-ENOTSUPP);
|
return ERR_PTR(-ENOTSUPP);
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline int dev_pm_opp_set_supported_hw(struct device *dev,
|
static inline void dev_pm_opp_put_supported_hw(struct opp_table *opp_table) {}
|
||||||
const u32 *versions,
|
|
||||||
unsigned int count)
|
|
||||||
{
|
|
||||||
return -ENOTSUPP;
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline void dev_pm_opp_put_supported_hw(struct device *dev) {}
|
static inline struct opp_table *dev_pm_opp_register_set_opp_helper(struct device *dev,
|
||||||
|
|
||||||
static inline int 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 -ENOTSUPP;
|
return ERR_PTR(-ENOTSUPP);
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline void dev_pm_opp_register_put_opp_helper(struct device *dev) {}
|
static inline void dev_pm_opp_register_put_opp_helper(struct opp_table *opp_table) {}
|
||||||
|
|
||||||
static inline int 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 -ENOTSUPP;
|
return ERR_PTR(-ENOTSUPP);
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline void dev_pm_opp_put_prop_name(struct device *dev) {}
|
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)
|
||||||
{
|
{
|
||||||
|
@ -270,6 +288,7 @@ 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);
|
||||||
int dev_pm_opp_of_get_sharing_cpus(struct device *cpu_dev, struct cpumask *cpumask);
|
int dev_pm_opp_of_get_sharing_cpus(struct device *cpu_dev, struct cpumask *cpumask);
|
||||||
|
struct device_node *dev_pm_opp_of_get_opp_desc_node(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)
|
||||||
{
|
{
|
||||||
|
@ -293,6 +312,11 @@ static inline int dev_pm_opp_of_get_sharing_cpus(struct device *cpu_dev, struct
|
||||||
{
|
{
|
||||||
return -ENOTSUPP;
|
return -ENOTSUPP;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static inline struct device_node *dev_pm_opp_of_get_opp_desc_node(struct device *dev)
|
||||||
|
{
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#endif /* __LINUX_OPP_H__ */
|
#endif /* __LINUX_OPP_H__ */
|
||||||
|
|
Loading…
Reference in New Issue