Re: [PATCH 01/12] cpufreq: arm_big_little: add cluster regulator support
Hi Ben Gamari, On 3 December 2015 at 02:49, Ben Gamari wrote: > From: Bartlomiej Zolnierkiewicz > > Add cluster regulator support as a preparation to adding > generic arm_big_little_dt cpufreq_dt driver support for > ODROID-XU3 board. This allows arm_big_little[_dt] driver > to set not only the frequency but also the voltage (which > is obtained from operating point's voltage value) for CPU > clusters. > > Cc: Kukjin Kim > Cc: Doug Anderson > Cc: Javier Martinez Canillas > Cc: Andreas Faerber > Cc: Sachin Kamat > Cc: Thomas Abraham > Signed-off-by: Bartlomiej Zolnierkiewicz > Signed-off-by: Ben Gamari > --- > .../bindings/cpufreq/arm_big_little_dt.txt | 4 + > drivers/cpufreq/arm_big_little.c | 155 > ++--- > 2 files changed, 142 insertions(+), 17 deletions(-) > > diff --git a/Documentation/devicetree/bindings/cpufreq/arm_big_little_dt.txt > b/Documentation/devicetree/bindings/cpufreq/arm_big_little_dt.txt > index 0715695..8ca4a12 100644 > --- a/Documentation/devicetree/bindings/cpufreq/arm_big_little_dt.txt > +++ b/Documentation/devicetree/bindings/cpufreq/arm_big_little_dt.txt > @@ -18,6 +18,10 @@ Required properties: > Optional properties: > - clock-latency: Specify the possible maximum transition latency for clock, >in unit of nanoseconds. > +- cpu-cluster.0-supply: Provides the regulator node supplying voltage to CPU > + cluster 0. > +- cpu-cluster.1-supply: Provides the regulator node supplying voltage to CPU > + cluster 1. > > Examples: > > diff --git a/drivers/cpufreq/arm_big_little.c > b/drivers/cpufreq/arm_big_little.c > index c5d256c..855599b 100644 > --- a/drivers/cpufreq/arm_big_little.c > +++ b/drivers/cpufreq/arm_big_little.c > @@ -31,6 +31,7 @@ > #include > #include > #include > +#include > > #include "arm_big_little.h" > > @@ -57,6 +58,9 @@ static bool bL_switching_enabled; > > static struct cpufreq_arm_bL_ops *arm_bL_ops; > static struct clk *clk[MAX_CLUSTERS]; > +static struct regulator *reg[MAX_CLUSTERS]; > +static struct device *cpu_devs[MAX_CLUSTERS]; > +static int transition_latencies[MAX_CLUSTERS]; > static struct cpufreq_frequency_table *freq_table[MAX_CLUSTERS + 1]; > static atomic_t cluster_usage[MAX_CLUSTERS + 1]; > > @@ -125,6 +129,75 @@ static unsigned int bL_cpufreq_get_rate(unsigned int cpu) > } > } > > +static int > +bL_cpufreq_set_rate_cluster(u32 cpu, u32 cluster, u32 new_rate) > +{ > + unsigned long volt = 0, volt_old = 0; > + long freq_Hz; > + u32 old_rate; > + int ret; > + > + freq_Hz = new_rate * 1000; > + old_rate = clk_get_rate(clk[cluster]) / 1000; > + > + if (!IS_ERR(reg[cluster])) { > + struct dev_pm_opp *opp; > + unsigned long opp_freq; > + > + rcu_read_lock(); > + opp = dev_pm_opp_find_freq_ceil(cpu_devs[cluster], _Hz); > + if (IS_ERR(opp)) { > + rcu_read_unlock(); > + pr_err("%s: cpu %d, cluster: %d, failed to find OPP > for %ld\n", > + __func__, cpu, cluster, freq_Hz); > + return PTR_ERR(opp); > + } > + volt = dev_pm_opp_get_voltage(opp); > + opp_freq = dev_pm_opp_get_freq(opp); > + rcu_read_unlock(); > + volt_old = regulator_get_voltage(reg[cluster]); > + pr_debug("%s: cpu %d, cluster: %d, Found OPP: %ld kHz, %ld > uV\n", > + __func__, cpu, cluster, opp_freq / 1000, volt); > + } > + > + pr_debug("%s: cpu %d, cluster: %d, %u MHz, %ld mV --> %u MHz, %ld > mV\n", > + __func__, cpu, cluster, > + old_rate / 1000, (volt_old > 0) ? volt_old / 1000 : -1, > + new_rate / 1000, volt ? volt / 1000 : -1); > + > + /* scaling up? scale voltage before frequency */ > + if (!IS_ERR(reg[cluster]) && new_rate > old_rate) { > + ret = regulator_set_voltage_tol(reg[cluster], volt, 0); > + if (ret) { > + pr_err("%s: cpu: %d, cluster: %d, failed to scale > voltage up: %d\n", > + __func__, cpu, cluster, ret); > + return ret; > + } > + } > + > + ret = clk_set_rate(clk[cluster], new_rate * 1000); > + if (WARN_ON(ret)) { > + pr_err("%s: clk_set_rate failed: %d, cluster: %d\n", > + __func__, cluster, ret); > + if (!IS_ERR(reg[cluster]) && volt_old > 0) > + regulator_set_voltage_tol(reg[cluster], volt_old, 0); > + return ret; > + } > + > + /* scaling down? scale voltage after frequency */ > + if (!IS_ERR(reg[cluster]) && new_rate < old_rate) { > + ret = regulator_set_voltage_tol(reg[cluster], volt, 0); > + if (ret) { > + pr_err("%s: cpu:
[PATCH 01/12] cpufreq: arm_big_little: add cluster regulator support
From: Bartlomiej Zolnierkiewicz Add cluster regulator support as a preparation to adding generic arm_big_little_dt cpufreq_dt driver support for ODROID-XU3 board. This allows arm_big_little[_dt] driver to set not only the frequency but also the voltage (which is obtained from operating point's voltage value) for CPU clusters. Cc: Kukjin Kim Cc: Doug Anderson Cc: Javier Martinez Canillas Cc: Andreas Faerber Cc: Sachin Kamat Cc: Thomas Abraham Signed-off-by: Bartlomiej Zolnierkiewicz Signed-off-by: Ben Gamari --- .../bindings/cpufreq/arm_big_little_dt.txt | 4 + drivers/cpufreq/arm_big_little.c | 155 ++--- 2 files changed, 142 insertions(+), 17 deletions(-) diff --git a/Documentation/devicetree/bindings/cpufreq/arm_big_little_dt.txt b/Documentation/devicetree/bindings/cpufreq/arm_big_little_dt.txt index 0715695..8ca4a12 100644 --- a/Documentation/devicetree/bindings/cpufreq/arm_big_little_dt.txt +++ b/Documentation/devicetree/bindings/cpufreq/arm_big_little_dt.txt @@ -18,6 +18,10 @@ Required properties: Optional properties: - clock-latency: Specify the possible maximum transition latency for clock, in unit of nanoseconds. +- cpu-cluster.0-supply: Provides the regulator node supplying voltage to CPU + cluster 0. +- cpu-cluster.1-supply: Provides the regulator node supplying voltage to CPU + cluster 1. Examples: diff --git a/drivers/cpufreq/arm_big_little.c b/drivers/cpufreq/arm_big_little.c index c5d256c..855599b 100644 --- a/drivers/cpufreq/arm_big_little.c +++ b/drivers/cpufreq/arm_big_little.c @@ -31,6 +31,7 @@ #include #include #include +#include #include "arm_big_little.h" @@ -57,6 +58,9 @@ static bool bL_switching_enabled; static struct cpufreq_arm_bL_ops *arm_bL_ops; static struct clk *clk[MAX_CLUSTERS]; +static struct regulator *reg[MAX_CLUSTERS]; +static struct device *cpu_devs[MAX_CLUSTERS]; +static int transition_latencies[MAX_CLUSTERS]; static struct cpufreq_frequency_table *freq_table[MAX_CLUSTERS + 1]; static atomic_t cluster_usage[MAX_CLUSTERS + 1]; @@ -125,6 +129,75 @@ static unsigned int bL_cpufreq_get_rate(unsigned int cpu) } } +static int +bL_cpufreq_set_rate_cluster(u32 cpu, u32 cluster, u32 new_rate) +{ + unsigned long volt = 0, volt_old = 0; + long freq_Hz; + u32 old_rate; + int ret; + + freq_Hz = new_rate * 1000; + old_rate = clk_get_rate(clk[cluster]) / 1000; + + if (!IS_ERR(reg[cluster])) { + struct dev_pm_opp *opp; + unsigned long opp_freq; + + rcu_read_lock(); + opp = dev_pm_opp_find_freq_ceil(cpu_devs[cluster], _Hz); + if (IS_ERR(opp)) { + rcu_read_unlock(); + pr_err("%s: cpu %d, cluster: %d, failed to find OPP for %ld\n", + __func__, cpu, cluster, freq_Hz); + return PTR_ERR(opp); + } + volt = dev_pm_opp_get_voltage(opp); + opp_freq = dev_pm_opp_get_freq(opp); + rcu_read_unlock(); + volt_old = regulator_get_voltage(reg[cluster]); + pr_debug("%s: cpu %d, cluster: %d, Found OPP: %ld kHz, %ld uV\n", + __func__, cpu, cluster, opp_freq / 1000, volt); + } + + pr_debug("%s: cpu %d, cluster: %d, %u MHz, %ld mV --> %u MHz, %ld mV\n", + __func__, cpu, cluster, + old_rate / 1000, (volt_old > 0) ? volt_old / 1000 : -1, + new_rate / 1000, volt ? volt / 1000 : -1); + + /* scaling up? scale voltage before frequency */ + if (!IS_ERR(reg[cluster]) && new_rate > old_rate) { + ret = regulator_set_voltage_tol(reg[cluster], volt, 0); + if (ret) { + pr_err("%s: cpu: %d, cluster: %d, failed to scale voltage up: %d\n", + __func__, cpu, cluster, ret); + return ret; + } + } + + ret = clk_set_rate(clk[cluster], new_rate * 1000); + if (WARN_ON(ret)) { + pr_err("%s: clk_set_rate failed: %d, cluster: %d\n", + __func__, cluster, ret); + if (!IS_ERR(reg[cluster]) && volt_old > 0) + regulator_set_voltage_tol(reg[cluster], volt_old, 0); + return ret; + } + + /* scaling down? scale voltage after frequency */ + if (!IS_ERR(reg[cluster]) && new_rate < old_rate) { + ret = regulator_set_voltage_tol(reg[cluster], volt, 0); + if (ret) { + pr_err("%s: cpu: %d, cluster: %d, failed to scale voltage down: %d\n", + __func__, cpu, cluster, ret); + clk_set_rate(clk[cluster], old_rate * 1000); + return ret; + } + } + + return 0; +} + static unsigned int
[PATCH 01/12] cpufreq: arm_big_little: add cluster regulator support
From: Bartlomiej ZolnierkiewiczAdd cluster regulator support as a preparation to adding generic arm_big_little_dt cpufreq_dt driver support for ODROID-XU3 board. This allows arm_big_little[_dt] driver to set not only the frequency but also the voltage (which is obtained from operating point's voltage value) for CPU clusters. Cc: Kukjin Kim Cc: Doug Anderson Cc: Javier Martinez Canillas Cc: Andreas Faerber Cc: Sachin Kamat Cc: Thomas Abraham Signed-off-by: Bartlomiej Zolnierkiewicz Signed-off-by: Ben Gamari --- .../bindings/cpufreq/arm_big_little_dt.txt | 4 + drivers/cpufreq/arm_big_little.c | 155 ++--- 2 files changed, 142 insertions(+), 17 deletions(-) diff --git a/Documentation/devicetree/bindings/cpufreq/arm_big_little_dt.txt b/Documentation/devicetree/bindings/cpufreq/arm_big_little_dt.txt index 0715695..8ca4a12 100644 --- a/Documentation/devicetree/bindings/cpufreq/arm_big_little_dt.txt +++ b/Documentation/devicetree/bindings/cpufreq/arm_big_little_dt.txt @@ -18,6 +18,10 @@ Required properties: Optional properties: - clock-latency: Specify the possible maximum transition latency for clock, in unit of nanoseconds. +- cpu-cluster.0-supply: Provides the regulator node supplying voltage to CPU + cluster 0. +- cpu-cluster.1-supply: Provides the regulator node supplying voltage to CPU + cluster 1. Examples: diff --git a/drivers/cpufreq/arm_big_little.c b/drivers/cpufreq/arm_big_little.c index c5d256c..855599b 100644 --- a/drivers/cpufreq/arm_big_little.c +++ b/drivers/cpufreq/arm_big_little.c @@ -31,6 +31,7 @@ #include #include #include +#include #include "arm_big_little.h" @@ -57,6 +58,9 @@ static bool bL_switching_enabled; static struct cpufreq_arm_bL_ops *arm_bL_ops; static struct clk *clk[MAX_CLUSTERS]; +static struct regulator *reg[MAX_CLUSTERS]; +static struct device *cpu_devs[MAX_CLUSTERS]; +static int transition_latencies[MAX_CLUSTERS]; static struct cpufreq_frequency_table *freq_table[MAX_CLUSTERS + 1]; static atomic_t cluster_usage[MAX_CLUSTERS + 1]; @@ -125,6 +129,75 @@ static unsigned int bL_cpufreq_get_rate(unsigned int cpu) } } +static int +bL_cpufreq_set_rate_cluster(u32 cpu, u32 cluster, u32 new_rate) +{ + unsigned long volt = 0, volt_old = 0; + long freq_Hz; + u32 old_rate; + int ret; + + freq_Hz = new_rate * 1000; + old_rate = clk_get_rate(clk[cluster]) / 1000; + + if (!IS_ERR(reg[cluster])) { + struct dev_pm_opp *opp; + unsigned long opp_freq; + + rcu_read_lock(); + opp = dev_pm_opp_find_freq_ceil(cpu_devs[cluster], _Hz); + if (IS_ERR(opp)) { + rcu_read_unlock(); + pr_err("%s: cpu %d, cluster: %d, failed to find OPP for %ld\n", + __func__, cpu, cluster, freq_Hz); + return PTR_ERR(opp); + } + volt = dev_pm_opp_get_voltage(opp); + opp_freq = dev_pm_opp_get_freq(opp); + rcu_read_unlock(); + volt_old = regulator_get_voltage(reg[cluster]); + pr_debug("%s: cpu %d, cluster: %d, Found OPP: %ld kHz, %ld uV\n", + __func__, cpu, cluster, opp_freq / 1000, volt); + } + + pr_debug("%s: cpu %d, cluster: %d, %u MHz, %ld mV --> %u MHz, %ld mV\n", + __func__, cpu, cluster, + old_rate / 1000, (volt_old > 0) ? volt_old / 1000 : -1, + new_rate / 1000, volt ? volt / 1000 : -1); + + /* scaling up? scale voltage before frequency */ + if (!IS_ERR(reg[cluster]) && new_rate > old_rate) { + ret = regulator_set_voltage_tol(reg[cluster], volt, 0); + if (ret) { + pr_err("%s: cpu: %d, cluster: %d, failed to scale voltage up: %d\n", + __func__, cpu, cluster, ret); + return ret; + } + } + + ret = clk_set_rate(clk[cluster], new_rate * 1000); + if (WARN_ON(ret)) { + pr_err("%s: clk_set_rate failed: %d, cluster: %d\n", + __func__, cluster, ret); + if (!IS_ERR(reg[cluster]) && volt_old > 0) + regulator_set_voltage_tol(reg[cluster], volt_old, 0); + return ret; + } + + /* scaling down? scale voltage after frequency */ + if (!IS_ERR(reg[cluster]) && new_rate < old_rate) { + ret = regulator_set_voltage_tol(reg[cluster], volt, 0); + if (ret) { + pr_err("%s: cpu: %d, cluster: %d, failed to scale voltage down: %d\n", + __func__, cpu,
Re: [PATCH 01/12] cpufreq: arm_big_little: add cluster regulator support
Hi Ben Gamari, On 3 December 2015 at 02:49, Ben Gamariwrote: > From: Bartlomiej Zolnierkiewicz > > Add cluster regulator support as a preparation to adding > generic arm_big_little_dt cpufreq_dt driver support for > ODROID-XU3 board. This allows arm_big_little[_dt] driver > to set not only the frequency but also the voltage (which > is obtained from operating point's voltage value) for CPU > clusters. > > Cc: Kukjin Kim > Cc: Doug Anderson > Cc: Javier Martinez Canillas > Cc: Andreas Faerber > Cc: Sachin Kamat > Cc: Thomas Abraham > Signed-off-by: Bartlomiej Zolnierkiewicz > Signed-off-by: Ben Gamari > --- > .../bindings/cpufreq/arm_big_little_dt.txt | 4 + > drivers/cpufreq/arm_big_little.c | 155 > ++--- > 2 files changed, 142 insertions(+), 17 deletions(-) > > diff --git a/Documentation/devicetree/bindings/cpufreq/arm_big_little_dt.txt > b/Documentation/devicetree/bindings/cpufreq/arm_big_little_dt.txt > index 0715695..8ca4a12 100644 > --- a/Documentation/devicetree/bindings/cpufreq/arm_big_little_dt.txt > +++ b/Documentation/devicetree/bindings/cpufreq/arm_big_little_dt.txt > @@ -18,6 +18,10 @@ Required properties: > Optional properties: > - clock-latency: Specify the possible maximum transition latency for clock, >in unit of nanoseconds. > +- cpu-cluster.0-supply: Provides the regulator node supplying voltage to CPU > + cluster 0. > +- cpu-cluster.1-supply: Provides the regulator node supplying voltage to CPU > + cluster 1. > > Examples: > > diff --git a/drivers/cpufreq/arm_big_little.c > b/drivers/cpufreq/arm_big_little.c > index c5d256c..855599b 100644 > --- a/drivers/cpufreq/arm_big_little.c > +++ b/drivers/cpufreq/arm_big_little.c > @@ -31,6 +31,7 @@ > #include > #include > #include > +#include > > #include "arm_big_little.h" > > @@ -57,6 +58,9 @@ static bool bL_switching_enabled; > > static struct cpufreq_arm_bL_ops *arm_bL_ops; > static struct clk *clk[MAX_CLUSTERS]; > +static struct regulator *reg[MAX_CLUSTERS]; > +static struct device *cpu_devs[MAX_CLUSTERS]; > +static int transition_latencies[MAX_CLUSTERS]; > static struct cpufreq_frequency_table *freq_table[MAX_CLUSTERS + 1]; > static atomic_t cluster_usage[MAX_CLUSTERS + 1]; > > @@ -125,6 +129,75 @@ static unsigned int bL_cpufreq_get_rate(unsigned int cpu) > } > } > > +static int > +bL_cpufreq_set_rate_cluster(u32 cpu, u32 cluster, u32 new_rate) > +{ > + unsigned long volt = 0, volt_old = 0; > + long freq_Hz; > + u32 old_rate; > + int ret; > + > + freq_Hz = new_rate * 1000; > + old_rate = clk_get_rate(clk[cluster]) / 1000; > + > + if (!IS_ERR(reg[cluster])) { > + struct dev_pm_opp *opp; > + unsigned long opp_freq; > + > + rcu_read_lock(); > + opp = dev_pm_opp_find_freq_ceil(cpu_devs[cluster], _Hz); > + if (IS_ERR(opp)) { > + rcu_read_unlock(); > + pr_err("%s: cpu %d, cluster: %d, failed to find OPP > for %ld\n", > + __func__, cpu, cluster, freq_Hz); > + return PTR_ERR(opp); > + } > + volt = dev_pm_opp_get_voltage(opp); > + opp_freq = dev_pm_opp_get_freq(opp); > + rcu_read_unlock(); > + volt_old = regulator_get_voltage(reg[cluster]); > + pr_debug("%s: cpu %d, cluster: %d, Found OPP: %ld kHz, %ld > uV\n", > + __func__, cpu, cluster, opp_freq / 1000, volt); > + } > + > + pr_debug("%s: cpu %d, cluster: %d, %u MHz, %ld mV --> %u MHz, %ld > mV\n", > + __func__, cpu, cluster, > + old_rate / 1000, (volt_old > 0) ? volt_old / 1000 : -1, > + new_rate / 1000, volt ? volt / 1000 : -1); > + > + /* scaling up? scale voltage before frequency */ > + if (!IS_ERR(reg[cluster]) && new_rate > old_rate) { > + ret = regulator_set_voltage_tol(reg[cluster], volt, 0); > + if (ret) { > + pr_err("%s: cpu: %d, cluster: %d, failed to scale > voltage up: %d\n", > + __func__, cpu, cluster, ret); > + return ret; > + } > + } > + > + ret = clk_set_rate(clk[cluster], new_rate * 1000); > + if (WARN_ON(ret)) { > + pr_err("%s: clk_set_rate failed: %d, cluster: %d\n", > + __func__, cluster, ret); > + if (!IS_ERR(reg[cluster]) && volt_old > 0) > + regulator_set_voltage_tol(reg[cluster], volt_old, 0); > + return ret; > + } > + > + /* scaling down? scale