Hi Guys,
The aim of the series is to kill the users of cpufreq-dt's platform data, i.e. mvebu. And because that required a new API to the OPP core, this just became a mix of cpufreq and OPP patches.
V2: - New patch 2/7. - Use -ENOTSUPP instead of -ENOSYS or -EINVAL for unimplemented APIs. - Moved mvebu code to drivers/cpufreq and the same file creates the platform device now for maintaining ordering. - Not cast required to drop 'const' for cpumask *.
Viresh Kumar (7): PM / OPP: -ENOSYS is applicable only to syscalls PM / OPP: Mark cpumask as const in dev_pm_opp_set_sharing_cpus() PM / OPP: Add dev_pm_opp_get_sharing_cpus() cpufreq: dt: Identify cpu-sharing for platforms without operating-points-v2 mvebu: Use dev_pm_opp_set_sharing_cpus() to mark OPP tables as shared cpufreq: dt: Kill platform-data cpufreq: mvebu: Move cpufreq code into drivers/cpufreq/
MAINTAINERS | 1 + arch/arm/mach-mvebu/pmsu.c | 85 ------------------------------- drivers/base/power/opp/cpu.c | 48 +++++++++++++++++- drivers/cpufreq/Makefile | 1 + drivers/cpufreq/cpufreq-dt.c | 22 ++++----- drivers/cpufreq/mvebu-cpufreq.c | 107 ++++++++++++++++++++++++++++++++++++++++ include/linux/cpufreq-dt.h | 24 --------- include/linux/pm_opp.h | 36 ++++++++------ 8 files changed, 187 insertions(+), 137 deletions(-) create mode 100644 drivers/cpufreq/mvebu-cpufreq.c delete mode 100644 include/linux/cpufreq-dt.h
Some of the routines have used -ENOSYS for the cases where the functionality isn't implemented in the kernel. But ENOSYS is supposed to be used only for syscalls.
Replace that with -ENOTSUPP, which specifically means that the operation isn't supported.
While at it, replace exiting -EINVAL errors for similar cases to -ENOTSUPP.
Signed-off-by: Viresh Kumar viresh.kumar@linaro.org --- include/linux/pm_opp.h | 26 +++++++++++++------------- 1 file changed, 13 insertions(+), 13 deletions(-)
diff --git a/include/linux/pm_opp.h b/include/linux/pm_opp.h index 5b6ad31403a5..a2df8f6fcc25 100644 --- a/include/linux/pm_opp.h +++ b/include/linux/pm_opp.h @@ -110,25 +110,25 @@ static inline struct dev_pm_opp *dev_pm_opp_get_suspend_opp(struct device *dev) static inline struct dev_pm_opp *dev_pm_opp_find_freq_exact(struct device *dev, unsigned long freq, bool available) { - return ERR_PTR(-EINVAL); + return ERR_PTR(-ENOTSUPP); }
static inline struct dev_pm_opp *dev_pm_opp_find_freq_floor(struct device *dev, unsigned long *freq) { - return ERR_PTR(-EINVAL); + return ERR_PTR(-ENOTSUPP); }
static inline struct dev_pm_opp *dev_pm_opp_find_freq_ceil(struct device *dev, unsigned long *freq) { - return ERR_PTR(-EINVAL); + return ERR_PTR(-ENOTSUPP); }
static inline int dev_pm_opp_add(struct device *dev, unsigned long freq, unsigned long u_volt) { - return -EINVAL; + return -ENOTSUPP; }
static inline void dev_pm_opp_remove(struct device *dev, unsigned long freq) @@ -148,40 +148,40 @@ static inline int dev_pm_opp_disable(struct device *dev, unsigned long freq) static inline struct srcu_notifier_head *dev_pm_opp_get_notifier( struct device *dev) { - return ERR_PTR(-EINVAL); + return ERR_PTR(-ENOTSUPP); }
static inline int dev_pm_opp_set_supported_hw(struct device *dev, const u32 *versions, unsigned int count) { - return -EINVAL; + return -ENOTSUPP; }
static inline void dev_pm_opp_put_supported_hw(struct device *dev) {}
static inline int dev_pm_opp_set_prop_name(struct device *dev, const char *name) { - return -EINVAL; + return -ENOTSUPP; }
static inline void dev_pm_opp_put_prop_name(struct device *dev) {}
static inline int dev_pm_opp_set_regulator(struct device *dev, const char *name) { - return -EINVAL; + return -ENOTSUPP; }
static inline void dev_pm_opp_put_regulator(struct device *dev) {}
static inline int dev_pm_opp_set_rate(struct device *dev, unsigned long target_freq) { - return -EINVAL; + return -ENOTSUPP; }
static inline int dev_pm_opp_set_sharing_cpus(struct device *cpu_dev, cpumask_var_t cpumask) { - return -ENOSYS; + return -ENOTSUPP; }
#endif /* CONFIG_PM_OPP */ @@ -195,7 +195,7 @@ int dev_pm_opp_of_get_sharing_cpus(struct device *cpu_dev, cpumask_var_t cpumask #else static inline int dev_pm_opp_of_add_table(struct device *dev) { - return -EINVAL; + return -ENOTSUPP; }
static inline void dev_pm_opp_of_remove_table(struct device *dev) @@ -204,7 +204,7 @@ static inline void dev_pm_opp_of_remove_table(struct device *dev)
static inline int dev_pm_opp_of_cpumask_add_table(cpumask_var_t cpumask) { - return -ENOSYS; + return -ENOTSUPP; }
static inline void dev_pm_opp_of_cpumask_remove_table(cpumask_var_t cpumask) @@ -213,7 +213,7 @@ static inline void dev_pm_opp_of_cpumask_remove_table(cpumask_var_t cpumask)
static inline int dev_pm_opp_of_get_sharing_cpus(struct device *cpu_dev, cpumask_var_t cpumask) { - return -ENOSYS; + return -ENOTSUPP; } #endif
On 04/27, Viresh Kumar wrote:
Some of the routines have used -ENOSYS for the cases where the functionality isn't implemented in the kernel. But ENOSYS is supposed to be used only for syscalls.
Replace that with -ENOTSUPP, which specifically means that the operation isn't supported.
While at it, replace exiting -EINVAL errors for similar cases to -ENOTSUPP.
Signed-off-by: Viresh Kumar viresh.kumar@linaro.org
Reviewed-by: Stephen Boyd sboyd@codeaurora.org
dev_pm_opp_set_sharing_cpus() isn't supposed to update the cpumask passed as its parameter, and so it should always have been marked 'const'.
Do it now.
Signed-off-by: Viresh Kumar viresh.kumar@linaro.org --- drivers/base/power/opp/cpu.c | 3 ++- include/linux/pm_opp.h | 4 ++-- 2 files changed, 4 insertions(+), 3 deletions(-)
diff --git a/drivers/base/power/opp/cpu.c b/drivers/base/power/opp/cpu.c index 55cbf9bd8707..5469e7730ff2 100644 --- a/drivers/base/power/opp/cpu.c +++ b/drivers/base/power/opp/cpu.c @@ -287,7 +287,8 @@ EXPORT_SYMBOL_GPL(dev_pm_opp_of_get_sharing_cpus); * 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, cpumask_var_t cpumask) +int dev_pm_opp_set_sharing_cpus(struct device *cpu_dev, + const cpumask_var_t cpumask) { struct opp_device *opp_dev; struct opp_table *opp_table; diff --git a/include/linux/pm_opp.h b/include/linux/pm_opp.h index a2df8f6fcc25..0c08ed3836b1 100644 --- a/include/linux/pm_opp.h +++ b/include/linux/pm_opp.h @@ -65,7 +65,7 @@ void dev_pm_opp_put_prop_name(struct device *dev); int dev_pm_opp_set_regulator(struct device *dev, const char *name); void dev_pm_opp_put_regulator(struct device *dev); int dev_pm_opp_set_rate(struct device *dev, unsigned long target_freq); -int dev_pm_opp_set_sharing_cpus(struct device *cpu_dev, cpumask_var_t cpumask); +int dev_pm_opp_set_sharing_cpus(struct device *cpu_dev, const cpumask_var_t cpumask); #else static inline unsigned long dev_pm_opp_get_voltage(struct dev_pm_opp *opp) { @@ -179,7 +179,7 @@ static inline int dev_pm_opp_set_rate(struct device *dev, unsigned long target_f return -ENOTSUPP; }
-static inline int dev_pm_opp_set_sharing_cpus(struct device *cpu_dev, cpumask_var_t cpumask) +static inline int dev_pm_opp_set_sharing_cpus(struct device *cpu_dev, const cpumask_var_t cpumask) { return -ENOTSUPP; }
On 04/27, Viresh Kumar wrote:
dev_pm_opp_set_sharing_cpus() isn't supposed to update the cpumask passed as its parameter, and so it should always have been marked 'const'.
Do it now.
Signed-off-by: Viresh Kumar viresh.kumar@linaro.org
Reviewed-by: Stephen Boyd sboyd@codeaurora.org
I'm ignoring cpumask_var_t usage.
On 02-05-16, 17:43, Stephen Boyd wrote:
On 04/27, Viresh Kumar wrote:
dev_pm_opp_set_sharing_cpus() isn't supposed to update the cpumask passed as its parameter, and so it should always have been marked 'const'.
Do it now.
Signed-off-by: Viresh Kumar viresh.kumar@linaro.org
Reviewed-by: Stephen Boyd sboyd@codeaurora.org
I'm ignoring cpumask_var_t usage.
Yeah, this is already merged by Rafael and Arnd's patch applies over it.
OPP core allows a platform to mark OPP table as shared, when the platform isn't using operating-points-v2 bindings.
And, so there should be a non DT way of finding out if the OPP table is shared or not.
This patch adds dev_pm_opp_get_sharing_cpus(), which first tries to get OPP sharing information from the opp-table (in case it is already marked as shared), otherwise it uses the existing DT way of finding sharing information.
Signed-off-by: Viresh Kumar viresh.kumar@linaro.org --- drivers/base/power/opp/cpu.c | 45 ++++++++++++++++++++++++++++++++++++++++++++ include/linux/pm_opp.h | 6 ++++++ 2 files changed, 51 insertions(+)
diff --git a/drivers/base/power/opp/cpu.c b/drivers/base/power/opp/cpu.c index 5469e7730ff2..3428380dfca7 100644 --- a/drivers/base/power/opp/cpu.c +++ b/drivers/base/power/opp/cpu.c @@ -330,3 +330,48 @@ int dev_pm_opp_set_sharing_cpus(struct device *cpu_dev, return ret; } EXPORT_SYMBOL_GPL(dev_pm_opp_set_sharing_cpus); + +/** + * dev_pm_opp_get_sharing_cpus() - Get cpumask of CPUs sharing OPPs with @cpu_dev + * @cpu_dev: CPU device for which we do this operation + * @cpumask: cpumask to update with information of sharing CPUs + * + * This updates the @cpumask with CPUs that are sharing OPPs with @cpu_dev. + * + * 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_get_sharing_cpus(struct device *cpu_dev, cpumask_var_t cpumask) +{ + struct opp_device *opp_dev; + struct opp_table *opp_table; + int ret = 0; + + mutex_lock(&opp_table_lock); + + opp_table = _find_opp_table(cpu_dev); + if (IS_ERR(opp_table)) { + ret = PTR_ERR(opp_table); + goto unlock; + } + + cpumask_clear(cpumask); + + if (opp_table->shared_opp) { + list_for_each_entry(opp_dev, &opp_table->dev_list, node) + cpumask_set_cpu(opp_dev->dev->id, cpumask); + } else { + cpumask_set_cpu(cpu_dev->id, cpumask); + } + +unlock: + mutex_unlock(&opp_table_lock); + + return ret; +} +EXPORT_SYMBOL_GPL(dev_pm_opp_get_sharing_cpus); diff --git a/include/linux/pm_opp.h b/include/linux/pm_opp.h index 0c08ed3836b1..15f554443b59 100644 --- a/include/linux/pm_opp.h +++ b/include/linux/pm_opp.h @@ -66,6 +66,7 @@ int dev_pm_opp_set_regulator(struct device *dev, const char *name); void dev_pm_opp_put_regulator(struct device *dev); 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 cpumask_var_t cpumask); +int dev_pm_opp_get_sharing_cpus(struct device *cpu_dev, cpumask_var_t cpumask); #else static inline unsigned long dev_pm_opp_get_voltage(struct dev_pm_opp *opp) { @@ -184,6 +185,11 @@ static inline int dev_pm_opp_set_sharing_cpus(struct device *cpu_dev, const cpum return -ENOTSUPP; }
+static inline int dev_pm_opp_get_sharing_cpus(struct device *cpu_dev, cpumask_var_t cpumask) +{ + return -EINVAL; +} + #endif /* CONFIG_PM_OPP */
#if defined(CONFIG_PM_OPP) && defined(CONFIG_OF)
On 04/27, Viresh Kumar wrote:
OPP core allows a platform to mark OPP table as shared, when the platform isn't using operating-points-v2 bindings.
And, so there should be a non DT way of finding out if the OPP table is shared or not.
This patch adds dev_pm_opp_get_sharing_cpus(), which first tries to get OPP sharing information from the opp-table (in case it is already marked as shared), otherwise it uses the existing DT way of finding sharing information.
Signed-off-by: Viresh Kumar viresh.kumar@linaro.org
Reviewed-by: Stephen Boyd sboyd@codeaurora.org
Existing platforms, which do not support operating-points-v2, can explicitly tell the opp core that some of the CPUs share opp tables, with help of dev_pm_opp_set_sharing_cpus().
For such platforms, explicitly ask the opp core to provide list of CPUs sharing the opp table with current cpu device, before falling back to platform data.
Signed-off-by: Viresh Kumar viresh.kumar@linaro.org --- drivers/cpufreq/cpufreq-dt.c | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-)
diff --git a/drivers/cpufreq/cpufreq-dt.c b/drivers/cpufreq/cpufreq-dt.c index 5f8dbe640a20..aca9bec00f91 100644 --- a/drivers/cpufreq/cpufreq-dt.c +++ b/drivers/cpufreq/cpufreq-dt.c @@ -147,7 +147,7 @@ static int cpufreq_init(struct cpufreq_policy *policy) struct clk *cpu_clk; struct dev_pm_opp *suspend_opp; unsigned int transition_latency; - bool opp_v1 = false; + bool fallback = false; const char *name; int ret;
@@ -167,14 +167,16 @@ static int cpufreq_init(struct cpufreq_policy *policy) /* Get OPP-sharing information from "operating-points-v2" bindings */ ret = dev_pm_opp_of_get_sharing_cpus(cpu_dev, policy->cpus); if (ret) { + if (ret != -ENOENT) + goto out_put_clk; + /* * operating-points-v2 not supported, fallback to old method of - * finding shared-OPPs for backward compatibility. + * finding shared-OPPs for backward compatibility if the + * platform hasn't set sharing CPUs. */ - if (ret == -ENOENT) - opp_v1 = true; - else - goto out_put_clk; + if (dev_pm_opp_get_sharing_cpus(cpu_dev, policy->cpus)) + fallback = true; }
/* @@ -214,7 +216,7 @@ static int cpufreq_init(struct cpufreq_policy *policy) goto out_free_opp; }
- if (opp_v1) { + if (fallback) { struct cpufreq_dt_platform_data *pd = cpufreq_get_driver_data();
if (!pd || !pd->independent_clocks)
On 04/27, Viresh Kumar wrote:
Existing platforms, which do not support operating-points-v2, can explicitly tell the opp core that some of the CPUs share opp tables, with help of dev_pm_opp_set_sharing_cpus().
For such platforms, explicitly ask the opp core to provide list of CPUs sharing the opp table with current cpu device, before falling back to platform data.
Signed-off-by: Viresh Kumar viresh.kumar@linaro.org
Reviewed-by: Stephen Boyd sboyd@codeaurora.org
That will allow us to avoid using cpufreq-dt platform data.
Cc: Thomas Petazzoni thomas.petazzoni@free-electrons.com Cc: Jason Cooper jason@lakedaemon.net Cc: Andrew Lunn andrew@lunn.ch Cc: Gregory Clement gregory.clement@free-electrons.com Cc: Sebastian Hesselbarth sebastian.hesselbarth@gmail.com Signed-off-by: Viresh Kumar viresh.kumar@linaro.org --- arch/arm/mach-mvebu/pmsu.c | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-)
diff --git a/arch/arm/mach-mvebu/pmsu.c b/arch/arm/mach-mvebu/pmsu.c index ed8fda4cd055..8928f7caaf70 100644 --- a/arch/arm/mach-mvebu/pmsu.c +++ b/arch/arm/mach-mvebu/pmsu.c @@ -20,7 +20,6 @@
#include <linux/clk.h> #include <linux/cpu_pm.h> -#include <linux/cpufreq-dt.h> #include <linux/delay.h> #include <linux/init.h> #include <linux/io.h> @@ -609,10 +608,6 @@ int mvebu_pmsu_dfs_request(int cpu) return 0; }
-struct cpufreq_dt_platform_data cpufreq_dt_pd = { - .independent_clocks = true, -}; - static int __init armada_xp_pmsu_cpufreq_init(void) { struct device_node *np; @@ -683,10 +678,15 @@ static int __init armada_xp_pmsu_cpufreq_init(void) clk_put(clk); return ret; } + + ret = dev_pm_opp_set_sharing_cpus(cpu_dev, + cpumask_of(cpu_dev->id)); + if (ret) + dev_err(cpu_dev, "%s: failed to mark OPPs as shared: %d\n", + __func__, ret); }
- platform_device_register_data(NULL, "cpufreq-dt", -1, - &cpufreq_dt_pd, sizeof(cpufreq_dt_pd)); + platform_device_register_simple("cpufreq-dt", -1, NULL, 0); return 0; }
On 04/27, Viresh Kumar wrote:
That will allow us to avoid using cpufreq-dt platform data.
Cc: Thomas Petazzoni thomas.petazzoni@free-electrons.com Cc: Jason Cooper jason@lakedaemon.net Cc: Andrew Lunn andrew@lunn.ch Cc: Gregory Clement gregory.clement@free-electrons.com Cc: Sebastian Hesselbarth sebastian.hesselbarth@gmail.com Signed-off-by: Viresh Kumar viresh.kumar@linaro.org
Reviewed-by: Stephen Boyd sboyd@codeaurora.org
There are no more users of platform-data for cpufreq-dt driver, get rid of it.
Signed-off-by: Viresh Kumar viresh.kumar@linaro.org Reviewed-by: Stephen Boyd sboyd@codeaurora.org --- drivers/cpufreq/cpufreq-dt.c | 6 +----- include/linux/cpufreq-dt.h | 24 ------------------------ 2 files changed, 1 insertion(+), 29 deletions(-) delete mode 100644 include/linux/cpufreq-dt.h
diff --git a/drivers/cpufreq/cpufreq-dt.c b/drivers/cpufreq/cpufreq-dt.c index aca9bec00f91..3957de801ae8 100644 --- a/drivers/cpufreq/cpufreq-dt.c +++ b/drivers/cpufreq/cpufreq-dt.c @@ -15,7 +15,6 @@ #include <linux/cpu.h> #include <linux/cpu_cooling.h> #include <linux/cpufreq.h> -#include <linux/cpufreq-dt.h> #include <linux/cpumask.h> #include <linux/err.h> #include <linux/module.h> @@ -217,10 +216,7 @@ static int cpufreq_init(struct cpufreq_policy *policy) }
if (fallback) { - struct cpufreq_dt_platform_data *pd = cpufreq_get_driver_data(); - - if (!pd || !pd->independent_clocks) - cpumask_setall(policy->cpus); + cpumask_setall(policy->cpus);
/* * OPP tables are initialized only for policy->cpu, do it for diff --git a/include/linux/cpufreq-dt.h b/include/linux/cpufreq-dt.h deleted file mode 100644 index a87335a1660c..000000000000 --- a/include/linux/cpufreq-dt.h +++ /dev/null @@ -1,24 +0,0 @@ -/* - * Copyright (C) 2014 Marvell - * Thomas Petazzoni thomas.petazzoni@free-electrons.com - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - */ - -#ifndef __CPUFREQ_DT_H__ -#define __CPUFREQ_DT_H__ - -#include <linux/types.h> - -struct cpufreq_dt_platform_data { - /* - * True when each CPU has its own clock to control its - * frequency, false when all CPUs are controlled by a single - * clock. - */ - bool independent_clocks; -}; - -#endif /* __CPUFREQ_DT_H__ */
Move cpufreq bits for mvebu into drivers/cpufreq/ directory, that's where they really belong to.
Compiled tested only.
Cc: Thomas Petazzoni thomas.petazzoni@free-electrons.com Cc: Jason Cooper jason@lakedaemon.net Cc: Andrew Lunn andrew@lunn.ch Cc: Gregory Clement gregory.clement@free-electrons.com Cc: Sebastian Hesselbarth sebastian.hesselbarth@gmail.com Signed-off-by: Viresh Kumar viresh.kumar@linaro.org --- MAINTAINERS | 1 + arch/arm/mach-mvebu/pmsu.c | 85 ------------------------------- drivers/cpufreq/Makefile | 1 + drivers/cpufreq/mvebu-cpufreq.c | 107 ++++++++++++++++++++++++++++++++++++++++ 4 files changed, 109 insertions(+), 85 deletions(-) create mode 100644 drivers/cpufreq/mvebu-cpufreq.c
diff --git a/MAINTAINERS b/MAINTAINERS index 1d5b4becab6f..0bb566e7df9b 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -1322,6 +1322,7 @@ F: drivers/rtc/rtc-armada38x.c F: arch/arm/boot/dts/armada* F: arch/arm/boot/dts/kirkwood* F: arch/arm64/boot/dts/marvell/armada* +F: drivers/cpufreq/mvebu-cpufreq.c
ARM/Marvell Berlin SoC support diff --git a/arch/arm/mach-mvebu/pmsu.c b/arch/arm/mach-mvebu/pmsu.c index 8928f7caaf70..b44442338e4e 100644 --- a/arch/arm/mach-mvebu/pmsu.c +++ b/arch/arm/mach-mvebu/pmsu.c @@ -28,7 +28,6 @@ #include <linux/of_address.h> #include <linux/of_device.h> #include <linux/platform_device.h> -#include <linux/pm_opp.h> #include <linux/resource.h> #include <linux/slab.h> #include <linux/smp.h> @@ -607,87 +606,3 @@ int mvebu_pmsu_dfs_request(int cpu)
return 0; } - -static int __init armada_xp_pmsu_cpufreq_init(void) -{ - struct device_node *np; - struct resource res; - int ret, cpu; - - if (!of_machine_is_compatible("marvell,armadaxp")) - return 0; - - /* - * In order to have proper cpufreq handling, we need to ensure - * that the Device Tree description of the CPU clock includes - * the definition of the PMU DFS registers. If not, we do not - * register the clock notifier and the cpufreq driver. This - * piece of code is only for compatibility with old Device - * Trees. - */ - np = of_find_compatible_node(NULL, NULL, "marvell,armada-xp-cpu-clock"); - if (!np) - return 0; - - ret = of_address_to_resource(np, 1, &res); - if (ret) { - pr_warn(FW_WARN "not enabling cpufreq, deprecated armada-xp-cpu-clock binding\n"); - of_node_put(np); - return 0; - } - - of_node_put(np); - - /* - * For each CPU, this loop registers the operating points - * supported (which are the nominal CPU frequency and half of - * it), and registers the clock notifier that will take care - * of doing the PMSU part of a frequency transition. - */ - for_each_possible_cpu(cpu) { - struct device *cpu_dev; - struct clk *clk; - int ret; - - cpu_dev = get_cpu_device(cpu); - if (!cpu_dev) { - pr_err("Cannot get CPU %d\n", cpu); - continue; - } - - clk = clk_get(cpu_dev, 0); - if (IS_ERR(clk)) { - pr_err("Cannot get clock for CPU %d\n", cpu); - return PTR_ERR(clk); - } - - /* - * In case of a failure of dev_pm_opp_add(), we don't - * bother with cleaning up the registered OPP (there's - * no function to do so), and simply cancel the - * registration of the cpufreq device. - */ - ret = dev_pm_opp_add(cpu_dev, clk_get_rate(clk), 0); - if (ret) { - clk_put(clk); - return ret; - } - - ret = dev_pm_opp_add(cpu_dev, clk_get_rate(clk) / 2, 0); - if (ret) { - clk_put(clk); - return ret; - } - - ret = dev_pm_opp_set_sharing_cpus(cpu_dev, - cpumask_of(cpu_dev->id)); - if (ret) - dev_err(cpu_dev, "%s: failed to mark OPPs as shared: %d\n", - __func__, ret); - } - - platform_device_register_simple("cpufreq-dt", -1, NULL, 0); - return 0; -} - -device_initcall(armada_xp_pmsu_cpufreq_init); diff --git a/drivers/cpufreq/Makefile b/drivers/cpufreq/Makefile index 2cce2cd400f9..e1eb11ee3570 100644 --- a/drivers/cpufreq/Makefile +++ b/drivers/cpufreq/Makefile @@ -79,6 +79,7 @@ obj-$(CONFIG_ARM_TEGRA20_CPUFREQ) += tegra20-cpufreq.o obj-$(CONFIG_ARM_TEGRA124_CPUFREQ) += tegra124-cpufreq.o obj-$(CONFIG_ARM_VEXPRESS_SPC_CPUFREQ) += vexpress-spc-cpufreq.o obj-$(CONFIG_ACPI_CPPC_CPUFREQ) += cppc_cpufreq.o +obj-$(CONFIG_MACH_MVEBU_V7) += mvebu-cpufreq.o
################################################################################## diff --git a/drivers/cpufreq/mvebu-cpufreq.c b/drivers/cpufreq/mvebu-cpufreq.c new file mode 100644 index 000000000000..e920889b9ac2 --- /dev/null +++ b/drivers/cpufreq/mvebu-cpufreq.c @@ -0,0 +1,107 @@ +/* + * CPUFreq support for Armada 370/XP platforms. + * + * Copyright (C) 2012-2016 Marvell + * + * Yehuda Yitschak yehuday@marvell.com + * Gregory Clement gregory.clement@free-electrons.com + * Thomas Petazzoni thomas.petazzoni@free-electrons.com + * + * This file is licensed under the terms of the GNU General Public + * License version 2. This program is licensed "as is" without any + * warranty of any kind, whether express or implied. + */ + +#define pr_fmt(fmt) "mvebu-pmsu: " fmt + +#include <linux/clk.h> +#include <linux/cpu.h> +#include <linux/init.h> +#include <linux/kernel.h> +#include <linux/of_address.h> +#include <linux/platform_device.h> +#include <linux/pm_opp.h> +#include <linux/resource.h> + +static int __init armada_xp_pmsu_cpufreq_init(void) +{ + struct device_node *np; + struct resource res; + int ret, cpu; + + if (!of_machine_is_compatible("marvell,armadaxp")) + return 0; + + /* + * In order to have proper cpufreq handling, we need to ensure + * that the Device Tree description of the CPU clock includes + * the definition of the PMU DFS registers. If not, we do not + * register the clock notifier and the cpufreq driver. This + * piece of code is only for compatibility with old Device + * Trees. + */ + np = of_find_compatible_node(NULL, NULL, "marvell,armada-xp-cpu-clock"); + if (!np) + return 0; + + ret = of_address_to_resource(np, 1, &res); + if (ret) { + pr_warn(FW_WARN "not enabling cpufreq, deprecated armada-xp-cpu-clock binding\n"); + of_node_put(np); + return 0; + } + + of_node_put(np); + + /* + * For each CPU, this loop registers the operating points + * supported (which are the nominal CPU frequency and half of + * it), and registers the clock notifier that will take care + * of doing the PMSU part of a frequency transition. + */ + for_each_possible_cpu(cpu) { + struct device *cpu_dev; + struct clk *clk; + int ret; + + cpu_dev = get_cpu_device(cpu); + if (!cpu_dev) { + pr_err("Cannot get CPU %d\n", cpu); + continue; + } + + clk = clk_get(cpu_dev, 0); + if (IS_ERR(clk)) { + pr_err("Cannot get clock for CPU %d\n", cpu); + return PTR_ERR(clk); + } + + /* + * In case of a failure of dev_pm_opp_add(), we don't + * bother with cleaning up the registered OPP (there's + * no function to do so), and simply cancel the + * registration of the cpufreq device. + */ + ret = dev_pm_opp_add(cpu_dev, clk_get_rate(clk), 0); + if (ret) { + clk_put(clk); + return ret; + } + + ret = dev_pm_opp_add(cpu_dev, clk_get_rate(clk) / 2, 0); + if (ret) { + clk_put(clk); + return ret; + } + + ret = dev_pm_opp_set_sharing_cpus(cpu_dev, + cpumask_of(cpu_dev->id)); + if (ret) + dev_err(cpu_dev, "%s: failed to mark OPPs as shared: %d\n", + __func__, ret); + } + + platform_device_register_simple("cpufreq-dt", -1, NULL, 0); + return 0; +} +device_initcall(armada_xp_pmsu_cpufreq_init);
On Wednesday 27 April 2016 08:52:20 Viresh Kumar wrote:
Hi Guys,
The aim of the series is to kill the users of cpufreq-dt's platform data, i.e. mvebu. And because that required a new API to the OPP core, this just became a mix of cpufreq and OPP patches.
Acked-by: Arnd Bergmann arnd@arndb.de
linaro-kernel@lists.linaro.org