Commit 60af981c authored by Rafael J. Wysocki's avatar Rafael J. Wysocki

Merge branch 'pm-cpufreq'

* pm-cpufreq: (22 commits)
  cpufreq: stats: Handle the case when trans_table goes beyond PAGE_SIZE
  cpufreq: arm_big_little: make cpufreq_arm_bL_ops structures const
  cpufreq: arm_big_little: make function arguments and structure pointer const
  cpufreq: pxa: convert to clock API
  cpufreq: speedstep-lib: mark expected switch fall-through
  cpufreq: ti-cpufreq: add missing of_node_put()
  cpufreq: dt: Remove support for Exynos4212 SoCs
  cpufreq: imx6q: Move speed grading check to cpufreq driver
  cpufreq: ti-cpufreq: kfree opp_data when failure
  cpufreq: SPEAr: pr_err() strings should end with newlines
  cpufreq: powernow-k8: pr_err() strings should end with newlines
  cpufreq: dt-platdev: drop socionext,uniphier-ld6b from whitelist
  arm64: wire cpu-invariant accounting support up to the task scheduler
  arm64: wire frequency-invariant accounting support up to the task scheduler
  arm: wire cpu-invariant accounting support up to the task scheduler
  arm: wire frequency-invariant accounting support up to the task scheduler
  drivers base/arch_topology: allow inlining cpu-invariant accounting support
  drivers base/arch_topology: provide frequency-invariant accounting support
  cpufreq: dt: invoke frequency-invariance setter function
  cpufreq: arm_big_little: invoke frequency-invariance setter function
  ...
parents 622ade3a f7bc9b20
...@@ -90,6 +90,9 @@ Freq_i to Freq_j. Freq_i is in descending order with increasing rows and ...@@ -90,6 +90,9 @@ Freq_i to Freq_j. Freq_i is in descending order with increasing rows and
Freq_j is in descending order with increasing columns. The output here also Freq_j is in descending order with increasing columns. The output here also
contains the actual freq values for each row and column for better readability. contains the actual freq values for each row and column for better readability.
If the transition table is bigger than PAGE_SIZE, reading this will
return an -EFBIG error.
-------------------------------------------------------------------------------- --------------------------------------------------------------------------------
<mysystem>:/sys/devices/system/cpu/cpu0/cpufreq/stats # cat trans_table <mysystem>:/sys/devices/system/cpu/cpu0/cpufreq/stats # cat trans_table
From : To From : To
......
...@@ -25,6 +25,14 @@ void init_cpu_topology(void); ...@@ -25,6 +25,14 @@ void init_cpu_topology(void);
void store_cpu_topology(unsigned int cpuid); void store_cpu_topology(unsigned int cpuid);
const struct cpumask *cpu_coregroup_mask(int cpu); const struct cpumask *cpu_coregroup_mask(int cpu);
#include <linux/arch_topology.h>
/* Replace task scheduler's default frequency-invariant accounting */
#define arch_scale_freq_capacity topology_get_freq_scale
/* Replace task scheduler's default cpu-invariant accounting */
#define arch_scale_cpu_capacity topology_get_cpu_scale
#else #else
static inline void init_cpu_topology(void) { } static inline void init_cpu_topology(void) { }
......
...@@ -286,88 +286,6 @@ static void __init imx6q_init_machine(void) ...@@ -286,88 +286,6 @@ static void __init imx6q_init_machine(void)
imx6q_axi_init(); imx6q_axi_init();
} }
#define OCOTP_CFG3 0x440
#define OCOTP_CFG3_SPEED_SHIFT 16
#define OCOTP_CFG3_SPEED_1P2GHZ 0x3
#define OCOTP_CFG3_SPEED_996MHZ 0x2
#define OCOTP_CFG3_SPEED_852MHZ 0x1
static void __init imx6q_opp_check_speed_grading(struct device *cpu_dev)
{
struct device_node *np;
void __iomem *base;
u32 val;
np = of_find_compatible_node(NULL, NULL, "fsl,imx6q-ocotp");
if (!np) {
pr_warn("failed to find ocotp node\n");
return;
}
base = of_iomap(np, 0);
if (!base) {
pr_warn("failed to map ocotp\n");
goto put_node;
}
/*
* SPEED_GRADING[1:0] defines the max speed of ARM:
* 2b'11: 1200000000Hz;
* 2b'10: 996000000Hz;
* 2b'01: 852000000Hz; -- i.MX6Q Only, exclusive with 996MHz.
* 2b'00: 792000000Hz;
* We need to set the max speed of ARM according to fuse map.
*/
val = readl_relaxed(base + OCOTP_CFG3);
val >>= OCOTP_CFG3_SPEED_SHIFT;
val &= 0x3;
if ((val != OCOTP_CFG3_SPEED_1P2GHZ) && cpu_is_imx6q())
if (dev_pm_opp_disable(cpu_dev, 1200000000))
pr_warn("failed to disable 1.2 GHz OPP\n");
if (val < OCOTP_CFG3_SPEED_996MHZ)
if (dev_pm_opp_disable(cpu_dev, 996000000))
pr_warn("failed to disable 996 MHz OPP\n");
if (cpu_is_imx6q()) {
if (val != OCOTP_CFG3_SPEED_852MHZ)
if (dev_pm_opp_disable(cpu_dev, 852000000))
pr_warn("failed to disable 852 MHz OPP\n");
}
iounmap(base);
put_node:
of_node_put(np);
}
static void __init imx6q_opp_init(void)
{
struct device_node *np;
struct device *cpu_dev = get_cpu_device(0);
if (!cpu_dev) {
pr_warn("failed to get cpu0 device\n");
return;
}
np = of_node_get(cpu_dev->of_node);
if (!np) {
pr_warn("failed to find cpu0 node\n");
return;
}
if (dev_pm_opp_of_add_table(cpu_dev)) {
pr_warn("failed to init OPP table\n");
goto put_node;
}
imx6q_opp_check_speed_grading(cpu_dev);
put_node:
of_node_put(np);
}
static struct platform_device imx6q_cpufreq_pdev = {
.name = "imx6q-cpufreq",
};
static void __init imx6q_init_late(void) static void __init imx6q_init_late(void)
{ {
/* /*
...@@ -377,10 +295,8 @@ static void __init imx6q_init_late(void) ...@@ -377,10 +295,8 @@ static void __init imx6q_init_late(void)
if (imx_get_soc_revision() > IMX_CHIP_REVISION_1_1) if (imx_get_soc_revision() > IMX_CHIP_REVISION_1_1)
imx6q_cpuidle_init(); imx6q_cpuidle_init();
if (IS_ENABLED(CONFIG_ARM_IMX6Q_CPUFREQ)) { if (IS_ENABLED(CONFIG_ARM_IMX6Q_CPUFREQ))
imx6q_opp_init(); platform_device_register_simple("imx6q-cpufreq", -1, NULL, 0);
platform_device_register(&imx6q_cpufreq_pdev);
}
} }
static void __init imx6q_map_io(void) static void __init imx6q_map_io(void)
......
...@@ -33,6 +33,14 @@ int pcibus_to_node(struct pci_bus *bus); ...@@ -33,6 +33,14 @@ int pcibus_to_node(struct pci_bus *bus);
#endif /* CONFIG_NUMA */ #endif /* CONFIG_NUMA */
#include <linux/arch_topology.h>
/* Replace task scheduler's default frequency-invariant accounting */
#define arch_scale_freq_capacity topology_get_freq_scale
/* Replace task scheduler's default cpu-invariant accounting */
#define arch_scale_cpu_capacity topology_get_cpu_scale
#include <asm-generic/topology.h> #include <asm-generic/topology.h>
#endif /* _ASM_ARM_TOPOLOGY_H */ #endif /* _ASM_ARM_TOPOLOGY_H */
...@@ -22,14 +22,23 @@ ...@@ -22,14 +22,23 @@
#include <linux/string.h> #include <linux/string.h>
#include <linux/sched/topology.h> #include <linux/sched/topology.h>
static DEFINE_MUTEX(cpu_scale_mutex); DEFINE_PER_CPU(unsigned long, freq_scale) = SCHED_CAPACITY_SCALE;
static DEFINE_PER_CPU(unsigned long, cpu_scale) = SCHED_CAPACITY_SCALE;
unsigned long topology_get_cpu_scale(struct sched_domain *sd, int cpu) void arch_set_freq_scale(struct cpumask *cpus, unsigned long cur_freq,
unsigned long max_freq)
{ {
return per_cpu(cpu_scale, cpu); unsigned long scale;
int i;
scale = (cur_freq << SCHED_CAPACITY_SHIFT) / max_freq;
for_each_cpu(i, cpus)
per_cpu(freq_scale, i) = scale;
} }
static DEFINE_MUTEX(cpu_scale_mutex);
DEFINE_PER_CPU(unsigned long, cpu_scale) = SCHED_CAPACITY_SCALE;
void topology_set_cpu_scale(unsigned int cpu, unsigned long capacity) void topology_set_cpu_scale(unsigned int cpu, unsigned long capacity)
{ {
per_cpu(cpu_scale, cpu) = capacity; per_cpu(cpu_scale, cpu) = capacity;
...@@ -212,6 +221,8 @@ static struct notifier_block init_cpu_capacity_notifier __initdata = { ...@@ -212,6 +221,8 @@ static struct notifier_block init_cpu_capacity_notifier __initdata = {
static int __init register_cpufreq_notifier(void) static int __init register_cpufreq_notifier(void)
{ {
int ret;
/* /*
* on ACPI-based systems we need to use the default cpu capacity * on ACPI-based systems we need to use the default cpu capacity
* until we have the necessary code to parse the cpu capacity, so * until we have the necessary code to parse the cpu capacity, so
...@@ -227,8 +238,13 @@ static int __init register_cpufreq_notifier(void) ...@@ -227,8 +238,13 @@ static int __init register_cpufreq_notifier(void)
cpumask_copy(cpus_to_visit, cpu_possible_mask); cpumask_copy(cpus_to_visit, cpu_possible_mask);
return cpufreq_register_notifier(&init_cpu_capacity_notifier, ret = cpufreq_register_notifier(&init_cpu_capacity_notifier,
CPUFREQ_POLICY_NOTIFIER); CPUFREQ_POLICY_NOTIFIER);
if (ret)
free_cpumask_var(cpus_to_visit);
return ret;
} }
core_initcall(register_cpufreq_notifier); core_initcall(register_cpufreq_notifier);
...@@ -236,6 +252,7 @@ static void __init parsing_done_workfn(struct work_struct *work) ...@@ -236,6 +252,7 @@ static void __init parsing_done_workfn(struct work_struct *work)
{ {
cpufreq_unregister_notifier(&init_cpu_capacity_notifier, cpufreq_unregister_notifier(&init_cpu_capacity_notifier,
CPUFREQ_POLICY_NOTIFIER); CPUFREQ_POLICY_NOTIFIER);
free_cpumask_var(cpus_to_visit);
} }
#else #else
......
...@@ -57,7 +57,7 @@ static bool bL_switching_enabled; ...@@ -57,7 +57,7 @@ static bool bL_switching_enabled;
#define VIRT_FREQ(cluster, freq) ((cluster == A7_CLUSTER) ? freq >> 1 : freq) #define VIRT_FREQ(cluster, freq) ((cluster == A7_CLUSTER) ? freq >> 1 : freq)
static struct thermal_cooling_device *cdev[MAX_CLUSTERS]; static struct thermal_cooling_device *cdev[MAX_CLUSTERS];
static struct cpufreq_arm_bL_ops *arm_bL_ops; static const struct cpufreq_arm_bL_ops *arm_bL_ops;
static struct clk *clk[MAX_CLUSTERS]; static struct clk *clk[MAX_CLUSTERS];
static struct cpufreq_frequency_table *freq_table[MAX_CLUSTERS + 1]; static struct cpufreq_frequency_table *freq_table[MAX_CLUSTERS + 1];
static atomic_t cluster_usage[MAX_CLUSTERS + 1]; static atomic_t cluster_usage[MAX_CLUSTERS + 1];
...@@ -213,6 +213,7 @@ static int bL_cpufreq_set_target(struct cpufreq_policy *policy, ...@@ -213,6 +213,7 @@ static int bL_cpufreq_set_target(struct cpufreq_policy *policy,
{ {
u32 cpu = policy->cpu, cur_cluster, new_cluster, actual_cluster; u32 cpu = policy->cpu, cur_cluster, new_cluster, actual_cluster;
unsigned int freqs_new; unsigned int freqs_new;
int ret;
cur_cluster = cpu_to_cluster(cpu); cur_cluster = cpu_to_cluster(cpu);
new_cluster = actual_cluster = per_cpu(physical_cluster, cpu); new_cluster = actual_cluster = per_cpu(physical_cluster, cpu);
...@@ -229,7 +230,14 @@ static int bL_cpufreq_set_target(struct cpufreq_policy *policy, ...@@ -229,7 +230,14 @@ static int bL_cpufreq_set_target(struct cpufreq_policy *policy,
} }
} }
return bL_cpufreq_set_rate(cpu, actual_cluster, new_cluster, freqs_new); ret = bL_cpufreq_set_rate(cpu, actual_cluster, new_cluster, freqs_new);
if (!ret) {
arch_set_freq_scale(policy->related_cpus, freqs_new,
policy->cpuinfo.max_freq);
}
return ret;
} }
static inline u32 get_table_count(struct cpufreq_frequency_table *table) static inline u32 get_table_count(struct cpufreq_frequency_table *table)
...@@ -609,7 +617,7 @@ static int __bLs_register_notifier(void) { return 0; } ...@@ -609,7 +617,7 @@ static int __bLs_register_notifier(void) { return 0; }
static int __bLs_unregister_notifier(void) { return 0; } static int __bLs_unregister_notifier(void) { return 0; }
#endif #endif
int bL_cpufreq_register(struct cpufreq_arm_bL_ops *ops) int bL_cpufreq_register(const struct cpufreq_arm_bL_ops *ops)
{ {
int ret, i; int ret, i;
...@@ -653,7 +661,7 @@ int bL_cpufreq_register(struct cpufreq_arm_bL_ops *ops) ...@@ -653,7 +661,7 @@ int bL_cpufreq_register(struct cpufreq_arm_bL_ops *ops)
} }
EXPORT_SYMBOL_GPL(bL_cpufreq_register); EXPORT_SYMBOL_GPL(bL_cpufreq_register);
void bL_cpufreq_unregister(struct cpufreq_arm_bL_ops *ops) void bL_cpufreq_unregister(const struct cpufreq_arm_bL_ops *ops)
{ {
if (arm_bL_ops != ops) { if (arm_bL_ops != ops) {
pr_err("%s: Registered with: %s, can't unregister, exiting\n", pr_err("%s: Registered with: %s, can't unregister, exiting\n",
......
...@@ -37,7 +37,7 @@ struct cpufreq_arm_bL_ops { ...@@ -37,7 +37,7 @@ struct cpufreq_arm_bL_ops {
void (*free_opp_table)(const struct cpumask *cpumask); void (*free_opp_table)(const struct cpumask *cpumask);
}; };
int bL_cpufreq_register(struct cpufreq_arm_bL_ops *ops); int bL_cpufreq_register(const struct cpufreq_arm_bL_ops *ops);
void bL_cpufreq_unregister(struct cpufreq_arm_bL_ops *ops); void bL_cpufreq_unregister(const struct cpufreq_arm_bL_ops *ops);
#endif /* CPUFREQ_ARM_BIG_LITTLE_H */ #endif /* CPUFREQ_ARM_BIG_LITTLE_H */
...@@ -61,7 +61,7 @@ static int dt_get_transition_latency(struct device *cpu_dev) ...@@ -61,7 +61,7 @@ static int dt_get_transition_latency(struct device *cpu_dev)
return transition_latency; return transition_latency;
} }
static struct cpufreq_arm_bL_ops dt_bL_ops = { static const struct cpufreq_arm_bL_ops dt_bL_ops = {
.name = "dt-bl", .name = "dt-bl",
.get_transition_latency = dt_get_transition_latency, .get_transition_latency = dt_get_transition_latency,
.init_opp_table = dev_pm_opp_of_cpumask_add_table, .init_opp_table = dev_pm_opp_of_cpumask_add_table,
......
...@@ -48,7 +48,6 @@ static const struct of_device_id whitelist[] __initconst = { ...@@ -48,7 +48,6 @@ static const struct of_device_id whitelist[] __initconst = {
{ .compatible = "samsung,exynos3250", }, { .compatible = "samsung,exynos3250", },
{ .compatible = "samsung,exynos4210", }, { .compatible = "samsung,exynos4210", },
{ .compatible = "samsung,exynos4212", },
{ .compatible = "samsung,exynos5250", }, { .compatible = "samsung,exynos5250", },
#ifndef CONFIG_BL_SWITCHER #ifndef CONFIG_BL_SWITCHER
{ .compatible = "samsung,exynos5800", }, { .compatible = "samsung,exynos5800", },
...@@ -83,8 +82,6 @@ static const struct of_device_id whitelist[] __initconst = { ...@@ -83,8 +82,6 @@ static const struct of_device_id whitelist[] __initconst = {
{ .compatible = "rockchip,rk3368", }, { .compatible = "rockchip,rk3368", },
{ .compatible = "rockchip,rk3399", }, { .compatible = "rockchip,rk3399", },
{ .compatible = "socionext,uniphier-ld6b", },
{ .compatible = "st-ericsson,u8500", }, { .compatible = "st-ericsson,u8500", },
{ .compatible = "st-ericsson,u8540", }, { .compatible = "st-ericsson,u8540", },
{ .compatible = "st-ericsson,u9500", }, { .compatible = "st-ericsson,u9500", },
......
...@@ -43,9 +43,17 @@ static struct freq_attr *cpufreq_dt_attr[] = { ...@@ -43,9 +43,17 @@ static struct freq_attr *cpufreq_dt_attr[] = {
static int set_target(struct cpufreq_policy *policy, unsigned int index) static int set_target(struct cpufreq_policy *policy, unsigned int index)
{ {
struct private_data *priv = policy->driver_data; struct private_data *priv = policy->driver_data;
unsigned long freq = policy->freq_table[index].frequency;
int ret;
ret = dev_pm_opp_set_rate(priv->cpu_dev, freq * 1000);
return dev_pm_opp_set_rate(priv->cpu_dev, if (!ret) {
policy->freq_table[index].frequency * 1000); arch_set_freq_scale(policy->related_cpus, freq,
policy->cpuinfo.max_freq);
}
return ret;
} }
/* /*
......
...@@ -161,6 +161,12 @@ u64 get_cpu_idle_time(unsigned int cpu, u64 *wall, int io_busy) ...@@ -161,6 +161,12 @@ u64 get_cpu_idle_time(unsigned int cpu, u64 *wall, int io_busy)
} }
EXPORT_SYMBOL_GPL(get_cpu_idle_time); EXPORT_SYMBOL_GPL(get_cpu_idle_time);
__weak void arch_set_freq_scale(struct cpumask *cpus, unsigned long cur_freq,
unsigned long max_freq)
{
}
EXPORT_SYMBOL_GPL(arch_set_freq_scale);
/* /*
* This is a generic cpufreq init() routine which can be used by cpufreq * This is a generic cpufreq init() routine which can be used by cpufreq
* drivers of SMP systems. It will do following: * drivers of SMP systems. It will do following:
......
...@@ -118,8 +118,11 @@ static ssize_t show_trans_table(struct cpufreq_policy *policy, char *buf) ...@@ -118,8 +118,11 @@ static ssize_t show_trans_table(struct cpufreq_policy *policy, char *buf)
break; break;
len += snprintf(buf + len, PAGE_SIZE - len, "\n"); len += snprintf(buf + len, PAGE_SIZE - len, "\n");
} }
if (len >= PAGE_SIZE)
return PAGE_SIZE; if (len >= PAGE_SIZE) {
pr_warn_once("cpufreq transition table exceeds PAGE_SIZE. Disabling\n");
return -EFBIG;
}
return len; return len;
} }
cpufreq_freq_attr_ro(trans_table); cpufreq_freq_attr_ro(trans_table);
......
...@@ -12,6 +12,7 @@ ...@@ -12,6 +12,7 @@
#include <linux/err.h> #include <linux/err.h>
#include <linux/module.h> #include <linux/module.h>
#include <linux/of.h> #include <linux/of.h>
#include <linux/of_address.h>
#include <linux/pm_opp.h> #include <linux/pm_opp.h>
#include <linux/platform_device.h> #include <linux/platform_device.h>
#include <linux/regulator/consumer.h> #include <linux/regulator/consumer.h>
...@@ -191,6 +192,57 @@ static struct cpufreq_driver imx6q_cpufreq_driver = { ...@@ -191,6 +192,57 @@ static struct cpufreq_driver imx6q_cpufreq_driver = {
.suspend = cpufreq_generic_suspend, .suspend = cpufreq_generic_suspend,
}; };
#define OCOTP_CFG3 0x440
#define OCOTP_CFG3_SPEED_SHIFT 16
#define OCOTP_CFG3_SPEED_1P2GHZ 0x3
#define OCOTP_CFG3_SPEED_996MHZ 0x2
#define OCOTP_CFG3_SPEED_852MHZ 0x1
static void imx6q_opp_check_speed_grading(struct device *dev)
{
struct device_node *np;
void __iomem *base;
u32 val;
np = of_find_compatible_node(NULL, NULL, "fsl,imx6q-ocotp");
if (!np)
return;
base = of_iomap(np, 0);
if (!base) {
dev_err(dev, "failed to map ocotp\n");
goto put_node;
}
/*
* SPEED_GRADING[1:0] defines the max speed of ARM:
* 2b'11: 1200000000Hz;
* 2b'10: 996000000Hz;
* 2b'01: 852000000Hz; -- i.MX6Q Only, exclusive with 996MHz.
* 2b'00: 792000000Hz;
* We need to set the max speed of ARM according to fuse map.
*/
val = readl_relaxed(base + OCOTP_CFG3);
val >>= OCOTP_CFG3_SPEED_SHIFT;
val &= 0x3;
if ((val != OCOTP_CFG3_SPEED_1P2GHZ) &&
of_machine_is_compatible("fsl,imx6q"))
if (dev_pm_opp_disable(dev, 1200000000))
dev_warn(dev, "failed to disable 1.2GHz OPP\n");
if (val < OCOTP_CFG3_SPEED_996MHZ)
if (dev_pm_opp_disable(dev, 996000000))
dev_warn(dev, "failed to disable 996MHz OPP\n");
if (of_machine_is_compatible("fsl,imx6q")) {
if (val != OCOTP_CFG3_SPEED_852MHZ)
if (dev_pm_opp_disable(dev, 852000000))
dev_warn(dev, "failed to disable 852MHz OPP\n");
}
iounmap(base);
put_node:
of_node_put(np);
}
static int imx6q_cpufreq_probe(struct platform_device *pdev) static int imx6q_cpufreq_probe(struct platform_device *pdev)
{ {
struct device_node *np; struct device_node *np;
...@@ -252,28 +304,21 @@ static int imx6q_cpufreq_probe(struct platform_device *pdev) ...@@ -252,28 +304,21 @@ static int imx6q_cpufreq_probe(struct platform_device *pdev)
goto put_reg; goto put_reg;
} }
/* ret = dev_pm_opp_of_add_table(cpu_dev);
* We expect an OPP table supplied by platform. if (ret < 0) {
* Just, incase the platform did not supply the OPP dev_err(cpu_dev, "failed to init OPP table: %d\n", ret);
* table, it will try to get it. goto put_reg;
*/ }
num = dev_pm_opp_get_opp_count(cpu_dev);
if (num < 0) {
ret = dev_pm_opp_of_add_table(cpu_dev);
if (ret < 0) {
dev_err(cpu_dev, "failed to init OPP table: %d\n", ret);
goto put_reg;
}
/* Because we have added the OPPs here, we must free them */ imx6q_opp_check_speed_grading(cpu_dev);
free_opp = true;
num = dev_pm_opp_get_opp_count(cpu_dev); /* Because we have added the OPPs here, we must free them */
if (num < 0) { free_opp = true;
ret = num; num = dev_pm_opp_get_opp_count(cpu_dev);
dev_err(cpu_dev, "no OPP table is found: %d\n", ret); if (num < 0) {
goto out_free_opp; ret = num;
} dev_err(cpu_dev, "no OPP table is found: %d\n", ret);
goto out_free_opp;
} }
ret = dev_pm_opp_init_cpufreq_table(cpu_dev, &freq_table); ret = dev_pm_opp_init_cpufreq_table(cpu_dev, &freq_table);
......
...@@ -1043,7 +1043,7 @@ static int powernowk8_cpu_init(struct cpufreq_policy *pol) ...@@ -1043,7 +1043,7 @@ static int powernowk8_cpu_init(struct cpufreq_policy *pol)
data = kzalloc(sizeof(*data), GFP_KERNEL); data = kzalloc(sizeof(*data), GFP_KERNEL);
if (!data) { if (!data) {
pr_err("unable to alloc powernow_k8_data"); pr_err("unable to alloc powernow_k8_data\n");
return -ENOMEM; return -ENOMEM;
} }
......
...@@ -58,56 +58,40 @@ module_param(pxa27x_maxfreq, uint, 0); ...@@ -58,56 +58,40 @@ module_param(pxa27x_maxfreq, uint, 0);
MODULE_PARM_DESC(pxa27x_maxfreq, "Set the pxa27x maxfreq in MHz" MODULE_PARM_DESC(pxa27x_maxfreq, "Set the pxa27x maxfreq in MHz"
"(typically 624=>pxa270, 416=>pxa271, 520=>pxa272)"); "(typically 624=>pxa270, 416=>pxa271, 520=>pxa272)");
struct pxa_cpufreq_data {
struct clk *clk_core;
};
static struct pxa_cpufreq_data pxa_cpufreq_data;
struct pxa_freqs { struct pxa_freqs {
unsigned int khz; unsigned int khz;
unsigned int membus;
unsigned int cccr;
unsigned int div2;
unsigned int cclkcfg;
int vmin; int vmin;
int vmax; int vmax;
}; };
/* Define the refresh period in mSec for the SDRAM and the number of rows */
#define SDRAM_TREF 64 /* standard 64ms SDRAM */
static unsigned int sdram_rows;
#define CCLKCFG_TURBO 0x1
#define CCLKCFG_FCS 0x2
#define CCLKCFG_HALFTURBO 0x4
#define CCLKCFG_FASTBUS 0x8
#define MDREFR_DB2_MASK (MDREFR_K2DB2 | MDREFR_K1DB2)
#define MDREFR_DRI_MASK 0xFFF
#define MDCNFG_DRAC2(mdcnfg) (((mdcnfg) >> 21) & 0x3)
#define MDCNFG_DRAC0(mdcnfg) (((mdcnfg) >> 5) & 0x3)
/* /*
* PXA255 definitions * PXA255 definitions
*/ */
/* Use the run mode frequencies for the CPUFREQ_POLICY_PERFORMANCE policy */
#define CCLKCFG CCLKCFG_TURBO | CCLKCFG_FCS
static const struct pxa_freqs pxa255_run_freqs[] = static const struct pxa_freqs pxa255_run_freqs[] =
{ {
/* CPU MEMBUS CCCR DIV2 CCLKCFG run turbo PXbus SDRAM */ /* CPU MEMBUS run turbo PXbus SDRAM */
{ 99500, 99500, 0x121, 1, CCLKCFG, -1, -1}, /* 99, 99, 50, 50 */ { 99500, -1, -1}, /* 99, 99, 50, 50 */
{132700, 132700, 0x123, 1, CCLKCFG, -1, -1}, /* 133, 133, 66, 66 */ {132700, -1, -1}, /* 133, 133, 66, 66 */
{199100, 99500, 0x141, 0, CCLKCFG, -1, -1}, /* 199, 199, 99, 99 */ {199100, -1, -1}, /* 199, 199, 99, 99 */
{265400, 132700, 0x143, 1, CCLKCFG, -1, -1}, /* 265, 265, 133, 66 */ {265400, -1, -1}, /* 265, 265, 133, 66 */
{331800, 165900, 0x145, 1, CCLKCFG, -1, -1}, /* 331, 331, 166, 83 */ {331800, -1, -1}, /* 331, 331, 166, 83 */
{398100, 99500, 0x161, 0, CCLKCFG, -1, -1}, /* 398, 398, 196, 99 */ {398100, -1, -1}, /* 398, 398, 196, 99 */
}; };
/* Use the turbo mode frequencies for the CPUFREQ_POLICY_POWERSAVE policy */ /* Use the turbo mode frequencies for the CPUFREQ_POLICY_POWERSAVE policy */
static const struct pxa_freqs pxa255_turbo_freqs[] = static const struct pxa_freqs pxa255_turbo_freqs[] =
{ {
/* CPU MEMBUS CCCR DIV2 CCLKCFG run turbo PXbus SDRAM */ /* CPU run turbo PXbus SDRAM */
{ 99500, 99500, 0x121, 1, CCLKCFG, -1, -1}, /* 99, 99, 50, 50 */ { 99500, -1, -1}, /* 99, 99, 50, 50 */
{199100, 99500, 0x221, 0, CCLKCFG, -1, -1}, /* 99, 199, 50, 99 */ {199100, -1, -1}, /* 99, 199, 50, 99 */
{298500, 99500, 0x321, 0, CCLKCFG, -1, -1}, /* 99, 287, 50, 99 */ {298500, -1, -1}, /* 99, 287, 50, 99 */
{298600, 99500, 0x1c1, 0, CCLKCFG, -1, -1}, /* 199, 287, 99, 99 */ {298600, -1, -1}, /* 199, 287, 99, 99 */
{398100, 99500, 0x241, 0, CCLKCFG, -1, -1}, /* 199, 398, 99, 99 */ {398100, -1, -1}, /* 199, 398, 99, 99 */
}; };
#define NUM_PXA25x_RUN_FREQS ARRAY_SIZE(pxa255_run_freqs) #define NUM_PXA25x_RUN_FREQS ARRAY_SIZE(pxa255_run_freqs)
...@@ -122,47 +106,14 @@ static unsigned int pxa255_turbo_table; ...@@ -122,47 +106,14 @@ static unsigned int pxa255_turbo_table;
module_param(pxa255_turbo_table, uint, 0); module_param(pxa255_turbo_table, uint, 0);
MODULE_PARM_DESC(pxa255_turbo_table, "Selects the frequency table (0 = run table, !0 = turbo table)"); MODULE_PARM_DESC(pxa255_turbo_table, "Selects the frequency table (0 = run table, !0 = turbo table)");
/*
* PXA270 definitions
*
* For the PXA27x:
* Control variables are A, L, 2N for CCCR; B, HT, T for CLKCFG.
*
* A = 0 => memory controller clock from table 3-7,
* A = 1 => memory controller clock = system bus clock
* Run mode frequency = 13 MHz * L
* Turbo mode frequency = 13 MHz * L * N
* System bus frequency = 13 MHz * L / (B + 1)
*
* In CCCR:
* A = 1
* L = 16 oscillator to run mode ratio
* 2N = 6 2 * (turbo mode to run mode ratio)
*
* In CCLKCFG:
* B = 1 Fast bus mode
* HT = 0 Half-Turbo mode
* T = 1 Turbo mode
*
* For now, just support some of the combinations in table 3-7 of
* PXA27x Processor Family Developer's Manual to simplify frequency
* change sequences.
*/
#define PXA27x_CCCR(A, L, N2) (A << 25 | N2 << 7 | L)
#define CCLKCFG2(B, HT, T) \
(CCLKCFG_FCS | \
((B) ? CCLKCFG_FASTBUS : 0) | \
((HT) ? CCLKCFG_HALFTURBO : 0) | \
((T) ? CCLKCFG_TURBO : 0))
static struct pxa_freqs pxa27x_freqs[] = { static struct pxa_freqs pxa27x_freqs[] = {
{104000, 104000, PXA27x_CCCR(1, 8, 2), 0, CCLKCFG2(1, 0, 1), 900000, 1705000 }, {104000, 900000, 1705000 },
{156000, 104000, PXA27x_CCCR(1, 8, 3), 0, CCLKCFG2(1, 0, 1), 1000000, 1705000 }, {156000, 1000000, 1705000 },
{208000, 208000, PXA27x_CCCR(0, 16, 2), 1, CCLKCFG2(0, 0, 1), 1180000, 1705000 }, {208000, 1180000, 1705000 },
{312000, 208000, PXA27x_CCCR(1, 16, 3), 1, CCLKCFG2(1, 0, 1), 1250000, 1705000 }, {312000, 1250000, 1705000 },
{416000, 208000, PXA27x_CCCR(1, 16, 4), 1, CCLKCFG2(1, 0, 1), 1350000, 1705000 }, {416000, 1350000, 1705000 },
{520000, 208000, PXA27x_CCCR(1, 16, 5), 1, CCLKCFG2(1, 0, 1), 1450000, 1705000 }, {520000, 1450000, 1705000 },
{624000, 208000, PXA27x_CCCR(1, 16, 6), 1, CCLKCFG2(1, 0, 1), 1550000, 1705000 } {624000, 1550000, 1705000 }
}; };
#define NUM_PXA27x_FREQS ARRAY_SIZE(pxa27x_freqs) #define NUM_PXA27x_FREQS ARRAY_SIZE(pxa27x_freqs)
...@@ -241,51 +192,29 @@ static void pxa27x_guess_max_freq(void) ...@@ -241,51 +192,29 @@ static void pxa27x_guess_max_freq(void)
} }
} }
static void init_sdram_rows(void)
{
uint32_t mdcnfg = __raw_readl(MDCNFG);
unsigned int drac2 = 0, drac0 = 0;
if (mdcnfg & (MDCNFG_DE2 | MDCNFG_DE3))
drac2 = MDCNFG_DRAC2(mdcnfg);
if (mdcnfg & (MDCNFG_DE0 | MDCNFG_DE1))
drac0 = MDCNFG_DRAC0(mdcnfg);
sdram_rows = 1 << (11 + max(drac0, drac2));
}
static u32 mdrefr_dri(unsigned int freq)
{
u32 interval = freq * SDRAM_TREF / sdram_rows;
return (interval - (cpu_is_pxa27x() ? 31 : 0)) / 32;
}
static unsigned int pxa_cpufreq_get(unsigned int cpu) static unsigned int pxa_cpufreq_get(unsigned int cpu)
{ {
return get_clk_frequency_khz(0); struct pxa_cpufreq_data *data = cpufreq_get_driver_data();
return (unsigned int) clk_get_rate(data->clk_core) / 1000;
} }
static int pxa_set_target(struct cpufreq_policy *policy, unsigned int idx) static int pxa_set_target(struct cpufreq_policy *policy, unsigned int idx)
{ {
struct cpufreq_frequency_table *pxa_freqs_table; struct cpufreq_frequency_table *pxa_freqs_table;
const struct pxa_freqs *pxa_freq_settings; const struct pxa_freqs *pxa_freq_settings;
unsigned long flags; struct pxa_cpufreq_data *data = cpufreq_get_driver_data();
unsigned int new_freq_cpu, new_freq_mem; unsigned int new_freq_cpu;
unsigned int unused, preset_mdrefr, postset_mdrefr, cclkcfg;
int ret = 0; int ret = 0;
/* Get the current policy */ /* Get the current policy */
find_freq_tables(&pxa_freqs_table, &pxa_freq_settings); find_freq_tables(&pxa_freqs_table, &pxa_freq_settings);
new_freq_cpu = pxa_freq_settings[idx].khz; new_freq_cpu = pxa_freq_settings[idx].khz;
new_freq_mem = pxa_freq_settings[idx].membus;
if (freq_debug) if (freq_debug)
pr_debug("Changing CPU frequency to %d Mhz, (SDRAM %d Mhz)\n", pr_debug("Changing CPU frequency from %d Mhz to %d Mhz\n",
new_freq_cpu / 1000, (pxa_freq_settings[idx].div2) ? policy->cur / 1000, new_freq_cpu / 1000);
(new_freq_mem / 2000) : (new_freq_mem / 1000));
if (vcc_core && new_freq_cpu > policy->cur) { if (vcc_core && new_freq_cpu > policy->cur) {
ret = pxa_cpufreq_change_voltage(&pxa_freq_settings[idx]); ret = pxa_cpufreq_change_voltage(&pxa_freq_settings[idx]);
...@@ -293,53 +222,7 @@ static int pxa_set_target(struct cpufreq_policy *policy, unsigned int idx) ...@@ -293,53 +222,7 @@ static int pxa_set_target(struct cpufreq_policy *policy, unsigned int idx)
return ret; return ret;
} }
/* Calculate the next MDREFR. If we're slowing down the SDRAM clock clk_set_rate(data->clk_core, new_freq_cpu * 1000);
* we need to preset the smaller DRI before the change. If we're
* speeding up we need to set the larger DRI value after the change.
*/
preset_mdrefr = postset_mdrefr = __raw_readl(MDREFR);
if ((preset_mdrefr & MDREFR_DRI_MASK) > mdrefr_dri(new_freq_mem)) {
preset_mdrefr = (preset_mdrefr & ~MDREFR_DRI_MASK);
preset_mdrefr |= mdrefr_dri(new_freq_mem);
}
postset_mdrefr =
(postset_mdrefr & ~MDREFR_DRI_MASK) | mdrefr_dri(new_freq_mem);
/* If we're dividing the memory clock by two for the SDRAM clock, this
* must be set prior to the change. Clearing the divide must be done
* after the change.
*/
if (pxa_freq_settings[idx].div2) {
preset_mdrefr |= MDREFR_DB2_MASK;
postset_mdrefr |= MDREFR_DB2_MASK;
} else {
postset_mdrefr &= ~MDREFR_DB2_MASK;
}
local_irq_save(flags);
/* Set new the CCCR and prepare CCLKCFG */
writel(pxa_freq_settings[idx].cccr, CCCR);
cclkcfg = pxa_freq_settings[idx].cclkcfg;
asm volatile(" \n\
ldr r4, [%1] /* load MDREFR */ \n\
b 2f \n\
.align 5 \n\
1: \n\
str %3, [%1] /* preset the MDREFR */ \n\
mcr p14, 0, %2, c6, c0, 0 /* set CCLKCFG[FCS] */ \n\
str %4, [%1] /* postset the MDREFR */ \n\
\n\
b 3f \n\
2: b 1b \n\
3: nop \n\
"
: "=&r" (unused)
: "r" (MDREFR), "r" (cclkcfg),
"r" (preset_mdrefr), "r" (postset_mdrefr)
: "r4", "r5");
local_irq_restore(flags);
/* /*
* Even if voltage setting fails, we don't report it, as the frequency * Even if voltage setting fails, we don't report it, as the frequency
...@@ -369,8 +252,6 @@ static int pxa_cpufreq_init(struct cpufreq_policy *policy) ...@@ -369,8 +252,6 @@ static int pxa_cpufreq_init(struct cpufreq_policy *policy)
pxa_cpufreq_init_voltages(); pxa_cpufreq_init_voltages();
init_sdram_rows();
/* set default policy and cpuinfo */ /* set default policy and cpuinfo */
policy->cpuinfo.transition_latency = 1000; /* FIXME: 1 ms, assumed */ policy->cpuinfo.transition_latency = 1000; /* FIXME: 1 ms, assumed */
...@@ -429,11 +310,17 @@ static struct cpufreq_driver pxa_cpufreq_driver = { ...@@ -429,11 +310,17 @@ static struct cpufreq_driver pxa_cpufreq_driver = {
.init = pxa_cpufreq_init, .init = pxa_cpufreq_init,
.get = pxa_cpufreq_get, .get = pxa_cpufreq_get,
.name = "PXA2xx", .name = "PXA2xx",
.driver_data = &pxa_cpufreq_data,
}; };
static int __init pxa_cpu_init(void) static int __init pxa_cpu_init(void)
{ {
int ret = -ENODEV; int ret = -ENODEV;
pxa_cpufreq_data.clk_core = clk_get_sys(NULL, "core");
if (IS_ERR(pxa_cpufreq_data.clk_core))
return PTR_ERR(pxa_cpufreq_data.clk_core);
if (cpu_is_pxa25x() || cpu_is_pxa27x()) if (cpu_is_pxa25x() || cpu_is_pxa27x())
ret = cpufreq_register_driver(&pxa_cpufreq_driver); ret = cpufreq_register_driver(&pxa_cpufreq_driver);
return ret; return ret;
......
...@@ -53,7 +53,7 @@ static int scpi_init_opp_table(const struct cpumask *cpumask) ...@@ -53,7 +53,7 @@ static int scpi_init_opp_table(const struct cpumask *cpumask)
return ret; return ret;
} }
static struct cpufreq_arm_bL_ops scpi_cpufreq_ops = { static const struct cpufreq_arm_bL_ops scpi_cpufreq_ops = {
.name = "scpi", .name = "scpi",
.get_transition_latency = scpi_get_transition_latency, .get_transition_latency = scpi_get_transition_latency,
.init_opp_table = scpi_init_opp_table, .init_opp_table = scpi_init_opp_table,
......
...@@ -177,7 +177,7 @@ static int spear_cpufreq_probe(struct platform_device *pdev) ...@@ -177,7 +177,7 @@ static int spear_cpufreq_probe(struct platform_device *pdev)
np = of_cpu_device_node_get(0); np = of_cpu_device_node_get(0);
if (!np) { if (!np) {
pr_err("No cpu node found"); pr_err("No cpu node found\n");
return -ENODEV; return -ENODEV;
} }
...@@ -187,7 +187,7 @@ static int spear_cpufreq_probe(struct platform_device *pdev) ...@@ -187,7 +187,7 @@ static int spear_cpufreq_probe(struct platform_device *pdev)
prop = of_find_property(np, "cpufreq_tbl", NULL); prop = of_find_property(np, "cpufreq_tbl", NULL);
if (!prop || !prop->value) { if (!prop || !prop->value) {
pr_err("Invalid cpufreq_tbl"); pr_err("Invalid cpufreq_tbl\n");
ret = -ENODEV; ret = -ENODEV;
goto out_put_node; goto out_put_node;
} }
......
...@@ -367,7 +367,7 @@ unsigned int speedstep_detect_processor(void) ...@@ -367,7 +367,7 @@ unsigned int speedstep_detect_processor(void)
} else } else
return SPEEDSTEP_CPU_PIII_C; return SPEEDSTEP_CPU_PIII_C;
} }
/* fall through */
default: default:
return 0; return 0;
} }
......
...@@ -205,6 +205,7 @@ static int ti_cpufreq_init(void) ...@@ -205,6 +205,7 @@ static int ti_cpufreq_init(void)
np = of_find_node_by_path("/"); np = of_find_node_by_path("/");
match = of_match_node(ti_cpufreq_of_match, np); match = of_match_node(ti_cpufreq_of_match, np);
of_node_put(np);
if (!match) if (!match)
return -ENODEV; return -ENODEV;
...@@ -217,7 +218,8 @@ static int ti_cpufreq_init(void) ...@@ -217,7 +218,8 @@ static int ti_cpufreq_init(void)
opp_data->cpu_dev = get_cpu_device(0); opp_data->cpu_dev = get_cpu_device(0);
if (!opp_data->cpu_dev) { if (!opp_data->cpu_dev) {
pr_err("%s: Failed to get device for CPU0\n", __func__); pr_err("%s: Failed to get device for CPU0\n", __func__);
return -ENODEV; ret = ENODEV;
goto free_opp_data;
} }
opp_data->opp_node = dev_pm_opp_of_get_opp_desc_node(opp_data->cpu_dev); opp_data->opp_node = dev_pm_opp_of_get_opp_desc_node(opp_data->cpu_dev);
...@@ -262,6 +264,8 @@ static int ti_cpufreq_init(void) ...@@ -262,6 +264,8 @@ static int ti_cpufreq_init(void)
fail_put_node: fail_put_node:
of_node_put(opp_data->opp_node); of_node_put(opp_data->opp_node);
free_opp_data:
kfree(opp_data);
return ret; return ret;
} }
......
...@@ -42,7 +42,7 @@ static int ve_spc_get_transition_latency(struct device *cpu_dev) ...@@ -42,7 +42,7 @@ static int ve_spc_get_transition_latency(struct device *cpu_dev)
return 1000000; /* 1 ms */ return 1000000; /* 1 ms */
} }
static struct cpufreq_arm_bL_ops ve_spc_cpufreq_ops = { static const struct cpufreq_arm_bL_ops ve_spc_cpufreq_ops = {
.name = "vexpress-spc", .name = "vexpress-spc",
.get_transition_latency = ve_spc_get_transition_latency, .get_transition_latency = ve_spc_get_transition_latency,
.init_opp_table = ve_spc_init_opp_table, .init_opp_table = ve_spc_init_opp_table,
......
...@@ -6,15 +6,30 @@ ...@@ -6,15 +6,30 @@
#define _LINUX_ARCH_TOPOLOGY_H_ #define _LINUX_ARCH_TOPOLOGY_H_
#include <linux/types.h> #include <linux/types.h>
#include <linux/percpu.h>
void topology_normalize_cpu_scale(void); void topology_normalize_cpu_scale(void);
struct device_node; struct device_node;
bool topology_parse_cpu_capacity(struct device_node *cpu_node, int cpu); bool topology_parse_cpu_capacity(struct device_node *cpu_node, int cpu);
DECLARE_PER_CPU(unsigned long, cpu_scale);
struct sched_domain; struct sched_domain;
unsigned long topology_get_cpu_scale(struct sched_domain *sd, int cpu); static inline
unsigned long topology_get_cpu_scale(struct sched_domain *sd, int cpu)
{
return per_cpu(cpu_scale, cpu);
}
void topology_set_cpu_scale(unsigned int cpu, unsigned long capacity); void topology_set_cpu_scale(unsigned int cpu, unsigned long capacity);
DECLARE_PER_CPU(unsigned long, freq_scale);
static inline
unsigned long topology_get_freq_scale(struct sched_domain *sd, int cpu)
{
return per_cpu(freq_scale, cpu);
}
#endif /* _LINUX_ARCH_TOPOLOGY_H_ */ #endif /* _LINUX_ARCH_TOPOLOGY_H_ */
...@@ -919,6 +919,9 @@ static inline bool policy_has_boost_freq(struct cpufreq_policy *policy) ...@@ -919,6 +919,9 @@ static inline bool policy_has_boost_freq(struct cpufreq_policy *policy)
extern unsigned int arch_freq_get_on_cpu(int cpu); extern unsigned int arch_freq_get_on_cpu(int cpu);
extern void arch_set_freq_scale(struct cpumask *cpus, unsigned long cur_freq,
unsigned long max_freq);
/* the following are really really optional */ /* the following are really really optional */
extern struct freq_attr cpufreq_freq_attr_scaling_available_freqs; extern struct freq_attr cpufreq_freq_attr_scaling_available_freqs;
extern struct freq_attr cpufreq_freq_attr_scaling_boost_freqs; extern struct freq_attr cpufreq_freq_attr_scaling_boost_freqs;
......
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