summaryrefslogtreecommitdiff
path: root/drivers/cpufreq
diff options
context:
space:
mode:
authorTang Yuantian <Yuantian.Tang@freescale.com>2014-10-22 07:30:16 (GMT)
committerMatthew Weigel <Matthew.Weigel@freescale.com>2014-12-11 18:38:43 (GMT)
commit7249d334b969ab26fb33c03964fb04793809eb23 (patch)
tree5ad61a815c58593c0bed37b3e90a481f30911d5d /drivers/cpufreq
parentd1562a24d43a095746da240ead98faf1d0ece899 (diff)
downloadlinux-fsl-qoriq-7249d334b969ab26fb33c03964fb04793809eb23.tar.xz
cpufreq: qoriq: Make the driver usable on all QorIQ platforms
Freescale introduced new ARM core-based SoCs which support dynamic frequency switch feature. DFS on new SoCs are compatible with current PowerPC CoreNet platforms. In order to support those new platforms, this driver needs to be slightly adjusted. The main changes include: 1. Changed the names of driver and functions in driver. 2. Added two new functions get_cpu_physical_id() and get_bus_freq(). 3. Used a new way to get all the CPUs which sharing clock wire. Signed-off-by: Tang Yuantian <Yuantian.Tang@freescale.com> --- http://patchwork.ozlabs.org/patch/400406/ Change-Id: I29fc5fefd0860db5ee531844d1218a6b70098dfe Reviewed-on: http://git.am.freescale.net:8181/21874 Tested-by: Review Code-CDREVIEW <CDREVIEW@freescale.com> Reviewed-by: Zhengxiong Jin <Jason.Jin@freescale.com>
Diffstat (limited to 'drivers/cpufreq')
-rw-r--r--drivers/cpufreq/Kconfig.arm8
-rw-r--r--drivers/cpufreq/Kconfig.powerpc14
-rw-r--r--drivers/cpufreq/Makefile2
-rw-r--r--drivers/cpufreq/qoriq-cpufreq.c (renamed from drivers/cpufreq/ppc-corenet-cpufreq.c)165
4 files changed, 118 insertions, 71 deletions
diff --git a/drivers/cpufreq/Kconfig.arm b/drivers/cpufreq/Kconfig.arm
index 0fa204b..553a50c 100644
--- a/drivers/cpufreq/Kconfig.arm
+++ b/drivers/cpufreq/Kconfig.arm
@@ -235,3 +235,11 @@ config ARM_TEGRA_CPUFREQ
default y
help
This adds the CPUFreq driver support for TEGRA SOCs.
+
+config QORIQ_CPUFREQ
+ tristate "CPU frequency scaling driver for Freescale QorIQ SoCs"
+ depends on OF && COMMON_CLK
+ select CLK_QORIQ
+ help
+ This adds the CPUFreq driver support for Freescale QorIQ SoCs
+ which are capable of changing the CPU's frequency dynamically.
diff --git a/drivers/cpufreq/Kconfig.powerpc b/drivers/cpufreq/Kconfig.powerpc
index e859a1d..1527a79 100644
--- a/drivers/cpufreq/Kconfig.powerpc
+++ b/drivers/cpufreq/Kconfig.powerpc
@@ -35,15 +35,13 @@ config MPC85xx_CPUFREQ
have a JOG feature, which provides a dynamic mechanism
to lower or raise the CPU core clock at runtime.
-config PPC_CORENET_CPUFREQ
- tristate "CPU frequency scaling driver for Freescale E500MC SoCs"
- depends on PPC_E500MC && OF && COMMON_CLK
- select CPU_FREQ_TABLE
- select CLK_PPC_CORENET
+config QORIQ_CPUFREQ
+ tristate "CPU frequency scaling driver for Freescale QorIQ SoCs"
+ depends on OF && COMMON_CLK
+ select CLK_QORIQ
help
- This adds the CPUFreq driver support for Freescale e500mc,
- e5500 and e6500 series SoCs which are capable of changing
- the CPU's frequency dynamically.
+ This adds the CPUFreq driver support for Freescale QorIQ SoCs
+ which are capable of changing the CPU's frequency dynamically.
config CPU_FREQ_PMAC
bool "Support for Apple PowerBooks"
diff --git a/drivers/cpufreq/Makefile b/drivers/cpufreq/Makefile
index cc1b57d..708f794 100644
--- a/drivers/cpufreq/Makefile
+++ b/drivers/cpufreq/Makefile
@@ -84,7 +84,7 @@ obj-$(CONFIG_CPU_FREQ_CBE) += ppc-cbe-cpufreq.o
ppc-cbe-cpufreq-y += ppc_cbe_cpufreq_pervasive.o ppc_cbe_cpufreq.o
obj-$(CONFIG_CPU_FREQ_CBE_PMI) += ppc_cbe_cpufreq_pmi.o
obj-$(CONFIG_CPU_FREQ_MAPLE) += maple-cpufreq.o
-obj-$(CONFIG_PPC_CORENET_CPUFREQ) += ppc-corenet-cpufreq.o
+obj-$(CONFIG_QORIQ_CPUFREQ) += qoriq-cpufreq.o
obj-$(CONFIG_MPC85xx_CPUFREQ) += mpc85xx-cpufreq.o
obj-$(CONFIG_CPU_FREQ_PMAC) += pmac32-cpufreq.o
obj-$(CONFIG_CPU_FREQ_PMAC64) += pmac64-cpufreq.o
diff --git a/drivers/cpufreq/ppc-corenet-cpufreq.c b/drivers/cpufreq/qoriq-cpufreq.c
index 8500627..9d0aa19 100644
--- a/drivers/cpufreq/ppc-corenet-cpufreq.c
+++ b/drivers/cpufreq/qoriq-cpufreq.c
@@ -1,7 +1,7 @@
/*
* Copyright 2013 Freescale Semiconductor, Inc.
*
- * CPU Frequency Scaling driver for Freescale PowerPC corenet SoCs.
+ * CPU Frequency Scaling driver for Freescale QorIQ SoCs.
*
* 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
@@ -13,7 +13,6 @@
#include <linux/clk.h>
#include <linux/cpufreq.h>
#include <linux/errno.h>
-#include <sysdev/fsl_soc.h>
#include <linux/init.h>
#include <linux/kernel.h>
#include <linux/module.h>
@@ -73,17 +72,7 @@ static const u32 *fmask;
static DEFINE_MUTEX(cpufreq_lock);
static DEFINE_PER_CPU(struct cpu_data *, cpu_data);
-/* cpumask in a cluster */
-static DEFINE_PER_CPU(cpumask_var_t, cpu_mask);
-
-#ifndef CONFIG_SMP
-static inline const struct cpumask *cpu_core_mask(int cpu)
-{
- return cpumask_of(0);
-}
-#endif
-
-static unsigned int corenet_cpufreq_get_speed(unsigned int cpu)
+static unsigned int qoriq_cpufreq_get_speed(unsigned int cpu)
{
struct cpu_data *data = per_cpu(cpu_data, cpu);
@@ -140,7 +129,80 @@ static void freq_table_sort(struct cpufreq_frequency_table *freq_table,
}
}
-static int corenet_cpufreq_cpu_init(struct cpufreq_policy *policy)
+#if defined(CONFIG_ARM)
+static int get_cpu_physical_id(int cpu)
+{
+ return topology_core_id(cpu);
+}
+#else
+static int get_cpu_physical_id(int cpu)
+{
+ return get_hard_smp_processor_id(cpu);
+}
+#endif
+
+static u32 get_bus_freq(void)
+{
+ struct device_node *soc;
+ u32 sysfreq;
+
+ soc = of_find_node_by_type(NULL, "soc");
+ if (!soc)
+ return 0;
+
+ if (of_property_read_u32(soc, "bus-frequency", &sysfreq))
+ sysfreq = 0;
+
+ of_node_put(soc);
+
+ return sysfreq;
+}
+
+static struct device_node *cpu_to_clk_node(int cpu)
+{
+ struct device_node *np, *clk_np;
+
+ if (!cpu_present(cpu))
+ return NULL;
+
+ np = of_get_cpu_node(cpu, NULL);
+ if (!np)
+ return NULL;
+
+ clk_np = of_parse_phandle(np, "clocks", 0);
+ if (!clk_np)
+ return NULL;
+
+ of_node_put(np);
+
+ return clk_np;
+}
+
+/* traverse cpu nodes to get cpu mask of sharing clock wire */
+static void set_affected_cpus(struct cpufreq_policy *policy)
+{
+ struct device_node *np, *clk_np;
+ struct cpumask *dstp = policy->cpus;
+ int i;
+
+ np = cpu_to_clk_node(policy->cpu);
+ if (!np)
+ return;
+
+ for_each_present_cpu(i) {
+ clk_np = cpu_to_clk_node(i);
+ if (!clk_np)
+ continue;
+
+ if (clk_np == np)
+ cpumask_set_cpu(i, dstp);
+
+ of_node_put(clk_np);
+ }
+ of_node_put(np);
+}
+
+static int qoriq_cpufreq_cpu_init(struct cpufreq_policy *policy)
{
struct device_node *np;
int i, count, ret;
@@ -181,7 +243,7 @@ static int corenet_cpufreq_cpu_init(struct cpufreq_policy *policy)
}
if (fmask)
- mask = fmask[get_hard_smp_processor_id(cpu)];
+ mask = fmask[get_cpu_physical_id(cpu)];
else
mask = 0x0;
@@ -213,15 +275,15 @@ static int corenet_cpufreq_cpu_init(struct cpufreq_policy *policy)
per_cpu(cpu_data, cpu) = data;
/* update ->cpus if we have cluster, no harm if not */
- cpumask_copy(policy->cpus, per_cpu(cpu_mask, cpu));
- for_each_cpu(i, per_cpu(cpu_mask, cpu))
+ set_affected_cpus(policy);
+ for_each_cpu(i, policy->cpus)
per_cpu(cpu_data, i) = data;
/* Minimum transition latency is 12 platform clocks */
u64temp = 12ULL * NSEC_PER_SEC;
- do_div(u64temp, fsl_get_sys_freq());
+ do_div(u64temp, get_bus_freq());
policy->cpuinfo.transition_latency = u64temp + 1;
- policy->cur = corenet_cpufreq_get_speed(policy->cpu);
+ policy->cur = qoriq_cpufreq_get_speed(policy->cpu);
cpufreq_frequency_table_get_attr(table, cpu);
of_node_put(np);
@@ -241,23 +303,19 @@ err_np:
return -ENODEV;
}
-static int __exit corenet_cpufreq_cpu_exit(struct cpufreq_policy *policy)
+static int __exit qoriq_cpufreq_cpu_exit(struct cpufreq_policy *policy)
{
struct cpu_data *data = per_cpu(cpu_data, policy->cpu);
- unsigned int cpu;
cpufreq_frequency_table_put_attr(policy->cpu);
of_node_put(data->parent);
kfree(data->table);
kfree(data);
- for_each_cpu(cpu, per_cpu(cpu_mask, policy->cpu))
- per_cpu(cpu_data, cpu) = NULL;
-
return 0;
}
-static int corenet_cpufreq_verify(struct cpufreq_policy *policy)
+static int qoriq_cpufreq_verify(struct cpufreq_policy *policy)
{
struct cpufreq_frequency_table *table =
per_cpu(cpu_data, policy->cpu)->table;
@@ -265,7 +323,7 @@ static int corenet_cpufreq_verify(struct cpufreq_policy *policy)
return cpufreq_frequency_table_verify(policy, table);
}
-static int corenet_cpufreq_target(struct cpufreq_policy *policy,
+static int qoriq_cpufreq_target(struct cpufreq_policy *policy,
unsigned int target_freq, unsigned int relation)
{
struct cpufreq_freqs freqs;
@@ -297,20 +355,20 @@ static int corenet_cpufreq_target(struct cpufreq_policy *policy,
return ret;
}
-static struct freq_attr *corenet_cpufreq_attr[] = {
+static struct freq_attr *qoriq_cpufreq_attr[] = {
&cpufreq_freq_attr_scaling_available_freqs,
NULL,
};
-static struct cpufreq_driver ppc_corenet_cpufreq_driver = {
- .name = "ppc_cpufreq",
+static struct cpufreq_driver qoriq_cpufreq_driver = {
+ .name = "qoriq_cpufreq",
.flags = CPUFREQ_CONST_LOOPS,
- .init = corenet_cpufreq_cpu_init,
- .exit = __exit_p(corenet_cpufreq_cpu_exit),
- .verify = corenet_cpufreq_verify,
- .target = corenet_cpufreq_target,
- .get = corenet_cpufreq_get_speed,
- .attr = corenet_cpufreq_attr,
+ .init = qoriq_cpufreq_cpu_init,
+ .exit = __exit_p(qoriq_cpufreq_cpu_exit),
+ .verify = qoriq_cpufreq_verify,
+ .target = qoriq_cpufreq_target,
+ .get = qoriq_cpufreq_get_speed,
+ .attr = qoriq_cpufreq_attr,
};
static const struct of_device_id node_matches[] __initdata = {
@@ -320,63 +378,46 @@ static const struct of_device_id node_matches[] __initdata = {
{ .compatible = "fsl,p4080-clockgen", .data = &sdata[2], },
{ .compatible = "fsl,p5040-clockgen", .data = &sdata[2], },
{ .compatible = "fsl,qoriq-clockgen-2.0", },
+ { .compatible = "fsl,ls1021a-clockgen", },
{}
};
-static int __init ppc_corenet_cpufreq_init(void)
+static int __init qoriq_cpufreq_init(void)
{
int ret;
struct device_node *np;
const struct of_device_id *match;
const struct soc_data *data;
- unsigned int cpu;
np = of_find_matching_node(NULL, node_matches);
if (!np)
return -ENODEV;
- for_each_possible_cpu(cpu) {
- if (!alloc_cpumask_var(&per_cpu(cpu_mask, cpu), GFP_KERNEL))
- goto err_mask;
- cpumask_copy(per_cpu(cpu_mask, cpu), cpu_core_mask(cpu));
- }
-
match = of_match_node(node_matches, np);
data = match->data;
if (data) {
if (data->flag)
fmask = data->freq_mask;
- min_cpufreq = fsl_get_sys_freq();
+ min_cpufreq = get_bus_freq();
} else {
- min_cpufreq = fsl_get_sys_freq() / 2;
+ min_cpufreq = get_bus_freq() / 2;
}
of_node_put(np);
- ret = cpufreq_register_driver(&ppc_corenet_cpufreq_driver);
+ ret = cpufreq_register_driver(&qoriq_cpufreq_driver);
if (!ret)
- pr_info("Freescale PowerPC corenet CPU frequency scaling driver\n");
+ pr_info("Freescale PowerPC qoriq CPU frequency scaling driver\n");
return ret;
-
-err_mask:
- for_each_possible_cpu(cpu)
- free_cpumask_var(per_cpu(cpu_mask, cpu));
-
- return -ENOMEM;
}
-module_init(ppc_corenet_cpufreq_init);
+module_init(qoriq_cpufreq_init);
-static void __exit ppc_corenet_cpufreq_exit(void)
+static void __exit qoriq_cpufreq_exit(void)
{
- unsigned int cpu;
-
- for_each_possible_cpu(cpu)
- free_cpumask_var(per_cpu(cpu_mask, cpu));
-
- cpufreq_unregister_driver(&ppc_corenet_cpufreq_driver);
+ cpufreq_unregister_driver(&qoriq_cpufreq_driver);
}
-module_exit(ppc_corenet_cpufreq_exit);
+module_exit(qoriq_cpufreq_exit);
MODULE_LICENSE("GPL");
MODULE_AUTHOR("Tang Yuantian <Yuantian.Tang@freescale.com>");