Commit 38fc7839 authored by Rafael J. Wysocki's avatar Rafael J. Wysocki

Merge back earlier cpufreq material for v4.1.

parents e5e02de0 5acb972f
...@@ -293,5 +293,13 @@ config SH_CPU_FREQ ...@@ -293,5 +293,13 @@ config SH_CPU_FREQ
If unsure, say N. If unsure, say N.
endif endif
config QORIQ_CPUFREQ
tristate "CPU frequency scaling driver for Freescale QorIQ SoCs"
depends on OF && COMMON_CLK && (PPC_E500MC || ARM)
select CLK_QORIQ
help
This adds the CPUFreq driver support for Freescale QorIQ SoCs
which are capable of changing the CPU's frequency dynamically.
endif endif
endmenu endmenu
...@@ -108,6 +108,15 @@ config ARM_HIGHBANK_CPUFREQ ...@@ -108,6 +108,15 @@ config ARM_HIGHBANK_CPUFREQ
If in doubt, say N. If in doubt, say N.
config ARM_HISI_ACPU_CPUFREQ
tristate "Hisilicon ACPU CPUfreq driver"
depends on ARCH_HISI && CPUFREQ_DT
select PM_OPP
help
This enables the hisilicon ACPU CPUfreq driver.
If in doubt, say N.
config ARM_IMX6Q_CPUFREQ config ARM_IMX6Q_CPUFREQ
tristate "Freescale i.MX6 cpufreq support" tristate "Freescale i.MX6 cpufreq support"
depends on ARCH_MXC depends on ARCH_MXC
......
...@@ -23,15 +23,6 @@ config CPU_FREQ_MAPLE ...@@ -23,15 +23,6 @@ config CPU_FREQ_MAPLE
This adds support for frequency switching on Maple 970FX This adds support for frequency switching on Maple 970FX
Evaluation Board and compatible boards (IBM JS2x blades). Evaluation Board and compatible boards (IBM JS2x blades).
config PPC_CORENET_CPUFREQ
tristate "CPU frequency scaling driver for Freescale E500MC SoCs"
depends on PPC_E500MC && 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.
config CPU_FREQ_PMAC config CPU_FREQ_PMAC
bool "Support for Apple PowerBooks" bool "Support for Apple PowerBooks"
depends on ADB_PMU && PPC32 depends on ADB_PMU && PPC32
......
...@@ -59,6 +59,7 @@ arm-exynos-cpufreq-$(CONFIG_ARM_EXYNOS4X12_CPUFREQ) += exynos4x12-cpufreq.o ...@@ -59,6 +59,7 @@ arm-exynos-cpufreq-$(CONFIG_ARM_EXYNOS4X12_CPUFREQ) += exynos4x12-cpufreq.o
arm-exynos-cpufreq-$(CONFIG_ARM_EXYNOS5250_CPUFREQ) += exynos5250-cpufreq.o arm-exynos-cpufreq-$(CONFIG_ARM_EXYNOS5250_CPUFREQ) += exynos5250-cpufreq.o
obj-$(CONFIG_ARM_EXYNOS5440_CPUFREQ) += exynos5440-cpufreq.o obj-$(CONFIG_ARM_EXYNOS5440_CPUFREQ) += exynos5440-cpufreq.o
obj-$(CONFIG_ARM_HIGHBANK_CPUFREQ) += highbank-cpufreq.o obj-$(CONFIG_ARM_HIGHBANK_CPUFREQ) += highbank-cpufreq.o
obj-$(CONFIG_ARM_HISI_ACPU_CPUFREQ) += hisi-acpu-cpufreq.o
obj-$(CONFIG_ARM_IMX6Q_CPUFREQ) += imx6q-cpufreq.o obj-$(CONFIG_ARM_IMX6Q_CPUFREQ) += imx6q-cpufreq.o
obj-$(CONFIG_ARM_INTEGRATOR) += integrator-cpufreq.o obj-$(CONFIG_ARM_INTEGRATOR) += integrator-cpufreq.o
obj-$(CONFIG_ARM_KIRKWOOD_CPUFREQ) += kirkwood-cpufreq.o obj-$(CONFIG_ARM_KIRKWOOD_CPUFREQ) += kirkwood-cpufreq.o
...@@ -85,7 +86,7 @@ obj-$(CONFIG_CPU_FREQ_CBE) += ppc-cbe-cpufreq.o ...@@ -85,7 +86,7 @@ obj-$(CONFIG_CPU_FREQ_CBE) += ppc-cbe-cpufreq.o
ppc-cbe-cpufreq-y += ppc_cbe_cpufreq_pervasive.o 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_CBE_PMI) += ppc_cbe_cpufreq_pmi.o
obj-$(CONFIG_CPU_FREQ_MAPLE) += maple-cpufreq.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_CPU_FREQ_PMAC) += pmac32-cpufreq.o obj-$(CONFIG_CPU_FREQ_PMAC) += pmac32-cpufreq.o
obj-$(CONFIG_CPU_FREQ_PMAC64) += pmac64-cpufreq.o obj-$(CONFIG_CPU_FREQ_PMAC64) += pmac64-cpufreq.o
obj-$(CONFIG_PPC_PASEMI_CPUFREQ) += pasemi-cpufreq.o obj-$(CONFIG_PPC_PASEMI_CPUFREQ) += pasemi-cpufreq.o
......
/*
* Hisilicon Platforms Using ACPU CPUFreq Support
*
* Copyright (c) 2015 Hisilicon Limited.
* Copyright (c) 2015 Linaro Limited.
*
* Leo Yan <leo.yan@linaro.org>
*
* 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.
*
* This program is distributed "as is" WITHOUT ANY WARRANTY of any
* kind, whether express or implied; without even the implied warranty
* of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*/
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
#include <linux/err.h>
#include <linux/init.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/of.h>
#include <linux/platform_device.h>
static int __init hisi_acpu_cpufreq_driver_init(void)
{
struct platform_device *pdev;
if (!of_machine_is_compatible("hisilicon,hi6220"))
return -ENODEV;
pdev = platform_device_register_simple("cpufreq-dt", -1, NULL, 0);
return PTR_ERR_OR_ZERO(pdev);
}
module_init(hisi_acpu_cpufreq_driver_init);
MODULE_AUTHOR("Leo Yan <leo.yan@linaro.org>");
MODULE_DESCRIPTION("Hisilicon acpu cpufreq driver");
MODULE_LICENSE("GPL v2");
...@@ -34,9 +34,13 @@ ...@@ -34,9 +34,13 @@
#include <asm/smp.h> /* Required for cpu_sibling_mask() in UP configs */ #include <asm/smp.h> /* Required for cpu_sibling_mask() in UP configs */
#define POWERNV_MAX_PSTATES 256 #define POWERNV_MAX_PSTATES 256
#define PMSR_PSAFE_ENABLE (1UL << 30)
#define PMSR_SPR_EM_DISABLE (1UL << 31)
#define PMSR_MAX(x) ((x >> 32) & 0xFF)
#define PMSR_LP(x) ((x >> 48) & 0xFF)
static struct cpufreq_frequency_table powernv_freqs[POWERNV_MAX_PSTATES+1]; static struct cpufreq_frequency_table powernv_freqs[POWERNV_MAX_PSTATES+1];
static bool rebooting; static bool rebooting, throttled;
/* /*
* Note: The set of pstates consists of contiguous integers, the * Note: The set of pstates consists of contiguous integers, the
...@@ -294,6 +298,44 @@ static inline unsigned int get_nominal_index(void) ...@@ -294,6 +298,44 @@ static inline unsigned int get_nominal_index(void)
return powernv_pstate_info.max - powernv_pstate_info.nominal; return powernv_pstate_info.max - powernv_pstate_info.nominal;
} }
static void powernv_cpufreq_throttle_check(unsigned int cpu)
{
unsigned long pmsr;
int pmsr_pmax, pmsr_lp;
pmsr = get_pmspr(SPRN_PMSR);
/* Check for Pmax Capping */
pmsr_pmax = (s8)PMSR_MAX(pmsr);
if (pmsr_pmax != powernv_pstate_info.max) {
throttled = true;
pr_info("CPU %d Pmax is reduced to %d\n", cpu, pmsr_pmax);
pr_info("Max allowed Pstate is capped\n");
}
/*
* Check for Psafe by reading LocalPstate
* or check if Psafe_mode_active is set in PMSR.
*/
pmsr_lp = (s8)PMSR_LP(pmsr);
if ((pmsr_lp < powernv_pstate_info.min) ||
(pmsr & PMSR_PSAFE_ENABLE)) {
throttled = true;
pr_info("Pstate set to safe frequency\n");
}
/* Check if SPR_EM_DISABLE is set in PMSR */
if (pmsr & PMSR_SPR_EM_DISABLE) {
throttled = true;
pr_info("Frequency Control disabled from OS\n");
}
if (throttled) {
pr_info("PMSR = %16lx\n", pmsr);
pr_crit("CPU Frequency could be throttled\n");
}
}
/* /*
* powernv_cpufreq_target_index: Sets the frequency corresponding to * powernv_cpufreq_target_index: Sets the frequency corresponding to
* the cpufreq table entry indexed by new_index on the cpus in the * the cpufreq table entry indexed by new_index on the cpus in the
...@@ -307,6 +349,9 @@ static int powernv_cpufreq_target_index(struct cpufreq_policy *policy, ...@@ -307,6 +349,9 @@ static int powernv_cpufreq_target_index(struct cpufreq_policy *policy,
if (unlikely(rebooting) && new_index != get_nominal_index()) if (unlikely(rebooting) && new_index != get_nominal_index())
return 0; return 0;
if (!throttled)
powernv_cpufreq_throttle_check(smp_processor_id());
freq_data.pstate_id = powernv_freqs[new_index].driver_data; freq_data.pstate_id = powernv_freqs[new_index].driver_data;
/* /*
......
/* /*
* Copyright 2013 Freescale Semiconductor, Inc. * 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 * 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 * it under the terms of the GNU General Public License version 2 as
...@@ -20,12 +20,11 @@ ...@@ -20,12 +20,11 @@
#include <linux/of.h> #include <linux/of.h>
#include <linux/slab.h> #include <linux/slab.h>
#include <linux/smp.h> #include <linux/smp.h>
#include <sysdev/fsl_soc.h>
#include <asm/smp.h> /* for get_hard_smp_processor_id() in UP configs */ #include <asm/smp.h> /* for get_hard_smp_processor_id() in UP configs */
/** /**
* struct cpu_data - per CPU data struct * struct cpu_data
* @parent: the parent node of cpu clock * @parent: the parent node of cpu clock
* @table: frequency table * @table: frequency table
*/ */
...@@ -69,17 +68,78 @@ static const struct soc_data sdata[] = { ...@@ -69,17 +68,78 @@ static const struct soc_data sdata[] = {
static u32 min_cpufreq; static u32 min_cpufreq;
static const u32 *fmask; static const u32 *fmask;
static DEFINE_PER_CPU(struct cpu_data *, cpu_data); #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);
/* cpumask in a cluster */ return sysfreq;
static DEFINE_PER_CPU(cpumask_var_t, cpu_mask); }
#ifndef CONFIG_SMP static struct device_node *cpu_to_clk_node(int cpu)
static inline const struct cpumask *cpu_core_mask(int cpu)
{ {
return cpumask_of(0); 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);
} }
#endif
/* reduce the duplicated frequencies in frequency table */ /* reduce the duplicated frequencies in frequency table */
static void freq_table_redup(struct cpufreq_frequency_table *freq_table, static void freq_table_redup(struct cpufreq_frequency_table *freq_table,
...@@ -107,6 +167,7 @@ static void freq_table_sort(struct cpufreq_frequency_table *freq_table, ...@@ -107,6 +167,7 @@ static void freq_table_sort(struct cpufreq_frequency_table *freq_table,
int i, j, ind; int i, j, ind;
unsigned int freq, max_freq; unsigned int freq, max_freq;
struct cpufreq_frequency_table table; struct cpufreq_frequency_table table;
for (i = 0; i < count - 1; i++) { for (i = 0; i < count - 1; i++) {
max_freq = freq_table[i].frequency; max_freq = freq_table[i].frequency;
ind = i; ind = i;
...@@ -131,7 +192,7 @@ static void freq_table_sort(struct cpufreq_frequency_table *freq_table, ...@@ -131,7 +192,7 @@ static void freq_table_sort(struct cpufreq_frequency_table *freq_table,
} }
} }
static int corenet_cpufreq_cpu_init(struct cpufreq_policy *policy) static int qoriq_cpufreq_cpu_init(struct cpufreq_policy *policy)
{ {
struct device_node *np; struct device_node *np;
int i, count, ret; int i, count, ret;
...@@ -147,10 +208,8 @@ static int corenet_cpufreq_cpu_init(struct cpufreq_policy *policy) ...@@ -147,10 +208,8 @@ static int corenet_cpufreq_cpu_init(struct cpufreq_policy *policy)
return -ENODEV; return -ENODEV;
data = kzalloc(sizeof(*data), GFP_KERNEL); data = kzalloc(sizeof(*data), GFP_KERNEL);
if (!data) { if (!data)
pr_err("%s: no memory\n", __func__);
goto err_np; goto err_np;
}
policy->clk = of_clk_get(np, 0); policy->clk = of_clk_get(np, 0);
if (IS_ERR(policy->clk)) { if (IS_ERR(policy->clk)) {
...@@ -172,7 +231,7 @@ static int corenet_cpufreq_cpu_init(struct cpufreq_policy *policy) ...@@ -172,7 +231,7 @@ static int corenet_cpufreq_cpu_init(struct cpufreq_policy *policy)
} }
if (fmask) if (fmask)
mask = fmask[get_hard_smp_processor_id(cpu)]; mask = fmask[get_cpu_physical_id(cpu)];
else else
mask = 0x0; mask = 0x0;
...@@ -203,13 +262,12 @@ static int corenet_cpufreq_cpu_init(struct cpufreq_policy *policy) ...@@ -203,13 +262,12 @@ static int corenet_cpufreq_cpu_init(struct cpufreq_policy *policy)
data->table = table; data->table = table;
/* update ->cpus if we have cluster, no harm if not */ /* update ->cpus if we have cluster, no harm if not */
cpumask_copy(policy->cpus, per_cpu(cpu_mask, cpu)); set_affected_cpus(policy);
for_each_cpu(i, per_cpu(cpu_mask, cpu)) policy->driver_data = data;
per_cpu(cpu_data, i) = data;
/* Minimum transition latency is 12 platform clocks */ /* Minimum transition latency is 12 platform clocks */
u64temp = 12ULL * NSEC_PER_SEC; 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->cpuinfo.transition_latency = u64temp + 1;
of_node_put(np); of_node_put(np);
...@@ -221,7 +279,7 @@ static int corenet_cpufreq_cpu_init(struct cpufreq_policy *policy) ...@@ -221,7 +279,7 @@ static int corenet_cpufreq_cpu_init(struct cpufreq_policy *policy)
err_node: err_node:
of_node_put(data->parent); of_node_put(data->parent);
err_nomem2: err_nomem2:
per_cpu(cpu_data, cpu) = NULL; policy->driver_data = NULL;
kfree(data); kfree(data);
err_np: err_np:
of_node_put(np); of_node_put(np);
...@@ -229,43 +287,40 @@ static int corenet_cpufreq_cpu_init(struct cpufreq_policy *policy) ...@@ -229,43 +287,40 @@ static int corenet_cpufreq_cpu_init(struct cpufreq_policy *policy)
return -ENODEV; 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); struct cpu_data *data = policy->driver_data;
unsigned int cpu;
of_node_put(data->parent); of_node_put(data->parent);
kfree(data->table); kfree(data->table);
kfree(data); kfree(data);
policy->driver_data = NULL;
for_each_cpu(cpu, per_cpu(cpu_mask, policy->cpu))
per_cpu(cpu_data, cpu) = NULL;
return 0; return 0;
} }
static int corenet_cpufreq_target(struct cpufreq_policy *policy, static int qoriq_cpufreq_target(struct cpufreq_policy *policy,
unsigned int index) unsigned int index)
{ {
struct clk *parent; struct clk *parent;
struct cpu_data *data = per_cpu(cpu_data, policy->cpu); struct cpu_data *data = policy->driver_data;
parent = of_clk_get(data->parent, data->table[index].driver_data); parent = of_clk_get(data->parent, data->table[index].driver_data);
return clk_set_parent(policy->clk, parent); return clk_set_parent(policy->clk, parent);
} }
static struct cpufreq_driver ppc_corenet_cpufreq_driver = { static struct cpufreq_driver qoriq_cpufreq_driver = {
.name = "ppc_cpufreq", .name = "qoriq_cpufreq",
.flags = CPUFREQ_CONST_LOOPS, .flags = CPUFREQ_CONST_LOOPS,
.init = corenet_cpufreq_cpu_init, .init = qoriq_cpufreq_cpu_init,
.exit = __exit_p(corenet_cpufreq_cpu_exit), .exit = __exit_p(qoriq_cpufreq_cpu_exit),
.verify = cpufreq_generic_frequency_table_verify, .verify = cpufreq_generic_frequency_table_verify,
.target_index = corenet_cpufreq_target, .target_index = qoriq_cpufreq_target,
.get = cpufreq_generic_get, .get = cpufreq_generic_get,
.attr = cpufreq_generic_attr, .attr = cpufreq_generic_attr,
}; };
static const struct of_device_id node_matches[] __initdata = { static const struct of_device_id node_matches[] __initconst = {
{ .compatible = "fsl,p2041-clockgen", .data = &sdata[0], }, { .compatible = "fsl,p2041-clockgen", .data = &sdata[0], },
{ .compatible = "fsl,p3041-clockgen", .data = &sdata[0], }, { .compatible = "fsl,p3041-clockgen", .data = &sdata[0], },
{ .compatible = "fsl,p5020-clockgen", .data = &sdata[1], }, { .compatible = "fsl,p5020-clockgen", .data = &sdata[1], },
...@@ -275,61 +330,43 @@ static const struct of_device_id node_matches[] __initdata = { ...@@ -275,61 +330,43 @@ static const struct of_device_id node_matches[] __initdata = {
{} {}
}; };
static int __init ppc_corenet_cpufreq_init(void) static int __init qoriq_cpufreq_init(void)
{ {
int ret; int ret;
struct device_node *np; struct device_node *np;
const struct of_device_id *match; const struct of_device_id *match;
const struct soc_data *data; const struct soc_data *data;
unsigned int cpu;
np = of_find_matching_node(NULL, node_matches); np = of_find_matching_node(NULL, node_matches);
if (!np) if (!np)
return -ENODEV; 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); match = of_match_node(node_matches, np);
data = match->data; data = match->data;
if (data) { if (data) {
if (data->flag) if (data->flag)
fmask = data->freq_mask; fmask = data->freq_mask;
min_cpufreq = fsl_get_sys_freq(); min_cpufreq = get_bus_freq();
} else { } else {
min_cpufreq = fsl_get_sys_freq() / 2; min_cpufreq = get_bus_freq() / 2;
} }
of_node_put(np); of_node_put(np);
ret = cpufreq_register_driver(&ppc_corenet_cpufreq_driver); ret = cpufreq_register_driver(&qoriq_cpufreq_driver);
if (!ret) if (!ret)
pr_info("Freescale PowerPC corenet CPU frequency scaling driver\n"); pr_info("Freescale QorIQ CPU frequency scaling driver\n");
return ret; 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; cpufreq_unregister_driver(&qoriq_cpufreq_driver);
for_each_possible_cpu(cpu)
free_cpumask_var(per_cpu(cpu_mask, cpu));
cpufreq_unregister_driver(&ppc_corenet_cpufreq_driver);
} }
module_exit(ppc_corenet_cpufreq_exit); module_exit(qoriq_cpufreq_exit);
MODULE_LICENSE("GPL"); MODULE_LICENSE("GPL");
MODULE_AUTHOR("Tang Yuantian <Yuantian.Tang@freescale.com>"); MODULE_AUTHOR("Tang Yuantian <Yuantian.Tang@freescale.com>");
MODULE_DESCRIPTION("cpufreq driver for Freescale e500mc series SoCs"); MODULE_DESCRIPTION("cpufreq driver for Freescale QorIQ series SoCs");
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment