提交 15d4cb90 编写于 作者: R Rafael J. Wysocki

Merge branch 'pm-cpufreq'

* pm-cpufreq:
  intel_pstate: skip the driver if ACPI has power mgmt option
  cpufreq: ondemand: Remove redundant return statement
  cpufreq: move freq change notifications to cpufreq core
  cpufreq: distinguish drivers that do asynchronous notifications
  cpufreq/intel_pstate: Add static declarations to internal functions
  cpufreq: arm_big_little: reconfigure switcher behavior at run time
  cpufreq: arm_big_little: add in-kernel switching (IKS) support
  ARM: vexpress/TC2: register vexpress-spc cpufreq device
  cpufreq: arm_big_little: add vexpress SPC interface driver
  ARM: vexpress/TC2: add cpu clock support
  ARM: vexpress/TC2: add support for CPU DVFS
...@@ -66,10 +66,22 @@ config ARCH_VEXPRESS_DCSCB ...@@ -66,10 +66,22 @@ config ARCH_VEXPRESS_DCSCB
This is needed to provide CPU and cluster power management This is needed to provide CPU and cluster power management
on RTSM implementing big.LITTLE. on RTSM implementing big.LITTLE.
config ARCH_VEXPRESS_SPC
bool "Versatile Express Serial Power Controller (SPC)"
select ARCH_HAS_CPUFREQ
select ARCH_HAS_OPP
select PM_OPP
help
The TC2 (A15x2 A7x3) versatile express core tile integrates a logic
block called Serial Power Controller (SPC) that provides the interface
between the dual cluster test-chip and the M3 microcontroller that
carries out power management.
config ARCH_VEXPRESS_TC2_PM config ARCH_VEXPRESS_TC2_PM
bool "Versatile Express TC2 power management" bool "Versatile Express TC2 power management"
depends on MCPM depends on MCPM
select ARM_CCI select ARM_CCI
select ARCH_VEXPRESS_SPC
help help
Support for CPU and cluster power management on Versatile Express Support for CPU and cluster power management on Versatile Express
with a TC2 (A15x2 A7x3) big.LITTLE core tile. with a TC2 (A15x2 A7x3) big.LITTLE core tile.
......
...@@ -8,7 +8,8 @@ obj-y := v2m.o ...@@ -8,7 +8,8 @@ obj-y := v2m.o
obj-$(CONFIG_ARCH_VEXPRESS_CA9X4) += ct-ca9x4.o obj-$(CONFIG_ARCH_VEXPRESS_CA9X4) += ct-ca9x4.o
obj-$(CONFIG_ARCH_VEXPRESS_DCSCB) += dcscb.o dcscb_setup.o obj-$(CONFIG_ARCH_VEXPRESS_DCSCB) += dcscb.o dcscb_setup.o
CFLAGS_dcscb.o += -march=armv7-a CFLAGS_dcscb.o += -march=armv7-a
obj-$(CONFIG_ARCH_VEXPRESS_TC2_PM) += tc2_pm.o spc.o obj-$(CONFIG_ARCH_VEXPRESS_SPC) += spc.o
obj-$(CONFIG_ARCH_VEXPRESS_TC2_PM) += tc2_pm.o
CFLAGS_tc2_pm.o += -march=armv7-a CFLAGS_tc2_pm.o += -march=armv7-a
obj-$(CONFIG_SMP) += platsmp.o obj-$(CONFIG_SMP) += platsmp.o
obj-$(CONFIG_HOTPLUG_CPU) += hotplug.o obj-$(CONFIG_HOTPLUG_CPU) += hotplug.o
...@@ -17,14 +17,31 @@ ...@@ -17,14 +17,31 @@
* GNU General Public License for more details. * GNU General Public License for more details.
*/ */
#include <linux/clk-provider.h>
#include <linux/clkdev.h>
#include <linux/cpu.h>
#include <linux/delay.h>
#include <linux/err.h> #include <linux/err.h>
#include <linux/interrupt.h>
#include <linux/io.h> #include <linux/io.h>
#include <linux/platform_device.h>
#include <linux/pm_opp.h>
#include <linux/slab.h> #include <linux/slab.h>
#include <linux/semaphore.h>
#include <asm/cacheflush.h> #include <asm/cacheflush.h>
#define SPCLOG "vexpress-spc: " #define SPCLOG "vexpress-spc: "
#define PERF_LVL_A15 0x00
#define PERF_REQ_A15 0x04
#define PERF_LVL_A7 0x08
#define PERF_REQ_A7 0x0c
#define COMMS 0x10
#define COMMS_REQ 0x14
#define PWC_STATUS 0x18
#define PWC_FLAG 0x1c
/* SPC wake-up IRQs status and mask */ /* SPC wake-up IRQs status and mask */
#define WAKE_INT_MASK 0x24 #define WAKE_INT_MASK 0x24
#define WAKE_INT_RAW 0x28 #define WAKE_INT_RAW 0x28
...@@ -36,12 +53,45 @@ ...@@ -36,12 +53,45 @@
#define A15_BX_ADDR0 0x68 #define A15_BX_ADDR0 0x68
#define A7_BX_ADDR0 0x78 #define A7_BX_ADDR0 0x78
/* SPC system config interface registers */
#define SYSCFG_WDATA 0x70
#define SYSCFG_RDATA 0x74
/* A15/A7 OPP virtual register base */
#define A15_PERFVAL_BASE 0xC10
#define A7_PERFVAL_BASE 0xC30
/* Config interface control bits */
#define SYSCFG_START (1 << 31)
#define SYSCFG_SCC (6 << 20)
#define SYSCFG_STAT (14 << 20)
/* wake-up interrupt masks */ /* wake-up interrupt masks */
#define GBL_WAKEUP_INT_MSK (0x3 << 10) #define GBL_WAKEUP_INT_MSK (0x3 << 10)
/* TC2 static dual-cluster configuration */ /* TC2 static dual-cluster configuration */
#define MAX_CLUSTERS 2 #define MAX_CLUSTERS 2
/*
* Even though the SPC takes max 3-5 ms to complete any OPP/COMMS
* operation, the operation could start just before jiffie is about
* to be incremented. So setting timeout value of 20ms = 2jiffies@100Hz
*/
#define TIMEOUT_US 20000
#define MAX_OPPS 8
#define CA15_DVFS 0
#define CA7_DVFS 1
#define SPC_SYS_CFG 2
#define STAT_COMPLETE(type) ((1 << 0) << (type << 2))
#define STAT_ERR(type) ((1 << 1) << (type << 2))
#define RESPONSE_MASK(type) (STAT_COMPLETE(type) | STAT_ERR(type))
struct ve_spc_opp {
unsigned long freq;
unsigned long u_volt;
};
struct ve_spc_drvdata { struct ve_spc_drvdata {
void __iomem *baseaddr; void __iomem *baseaddr;
/* /*
...@@ -49,6 +99,12 @@ struct ve_spc_drvdata { ...@@ -49,6 +99,12 @@ struct ve_spc_drvdata {
* It corresponds to A15 processors MPIDR[15:8] bitfield * It corresponds to A15 processors MPIDR[15:8] bitfield
*/ */
u32 a15_clusid; u32 a15_clusid;
uint32_t cur_rsp_mask;
uint32_t cur_rsp_stat;
struct semaphore sem;
struct completion done;
struct ve_spc_opp *opps[MAX_CLUSTERS];
int num_opps[MAX_CLUSTERS];
}; };
static struct ve_spc_drvdata *info; static struct ve_spc_drvdata *info;
...@@ -157,8 +213,197 @@ void ve_spc_powerdown(u32 cluster, bool enable) ...@@ -157,8 +213,197 @@ void ve_spc_powerdown(u32 cluster, bool enable)
writel_relaxed(enable, info->baseaddr + pwdrn_reg); writel_relaxed(enable, info->baseaddr + pwdrn_reg);
} }
int __init ve_spc_init(void __iomem *baseaddr, u32 a15_clusid) static int ve_spc_get_performance(int cluster, u32 *freq)
{
struct ve_spc_opp *opps = info->opps[cluster];
u32 perf_cfg_reg = 0;
u32 perf;
perf_cfg_reg = cluster_is_a15(cluster) ? PERF_LVL_A15 : PERF_LVL_A7;
perf = readl_relaxed(info->baseaddr + perf_cfg_reg);
if (perf >= info->num_opps[cluster])
return -EINVAL;
opps += perf;
*freq = opps->freq;
return 0;
}
/* find closest match to given frequency in OPP table */
static int ve_spc_round_performance(int cluster, u32 freq)
{
int idx, max_opp = info->num_opps[cluster];
struct ve_spc_opp *opps = info->opps[cluster];
u32 fmin = 0, fmax = ~0, ftmp;
freq /= 1000; /* OPP entries in kHz */
for (idx = 0; idx < max_opp; idx++, opps++) {
ftmp = opps->freq;
if (ftmp >= freq) {
if (ftmp <= fmax)
fmax = ftmp;
} else {
if (ftmp >= fmin)
fmin = ftmp;
}
}
if (fmax != ~0)
return fmax * 1000;
else
return fmin * 1000;
}
static int ve_spc_find_performance_index(int cluster, u32 freq)
{
int idx, max_opp = info->num_opps[cluster];
struct ve_spc_opp *opps = info->opps[cluster];
for (idx = 0; idx < max_opp; idx++, opps++)
if (opps->freq == freq)
break;
return (idx == max_opp) ? -EINVAL : idx;
}
static int ve_spc_waitforcompletion(int req_type)
{
int ret = wait_for_completion_interruptible_timeout(
&info->done, usecs_to_jiffies(TIMEOUT_US));
if (ret == 0)
ret = -ETIMEDOUT;
else if (ret > 0)
ret = info->cur_rsp_stat & STAT_COMPLETE(req_type) ? 0 : -EIO;
return ret;
}
static int ve_spc_set_performance(int cluster, u32 freq)
{
u32 perf_cfg_reg, perf_stat_reg;
int ret, perf, req_type;
if (cluster_is_a15(cluster)) {
req_type = CA15_DVFS;
perf_cfg_reg = PERF_LVL_A15;
perf_stat_reg = PERF_REQ_A15;
} else {
req_type = CA7_DVFS;
perf_cfg_reg = PERF_LVL_A7;
perf_stat_reg = PERF_REQ_A7;
}
perf = ve_spc_find_performance_index(cluster, freq);
if (perf < 0)
return perf;
if (down_timeout(&info->sem, usecs_to_jiffies(TIMEOUT_US)))
return -ETIME;
init_completion(&info->done);
info->cur_rsp_mask = RESPONSE_MASK(req_type);
writel(perf, info->baseaddr + perf_cfg_reg);
ret = ve_spc_waitforcompletion(req_type);
info->cur_rsp_mask = 0;
up(&info->sem);
return ret;
}
static int ve_spc_read_sys_cfg(int func, int offset, uint32_t *data)
{
int ret;
if (down_timeout(&info->sem, usecs_to_jiffies(TIMEOUT_US)))
return -ETIME;
init_completion(&info->done);
info->cur_rsp_mask = RESPONSE_MASK(SPC_SYS_CFG);
/* Set the control value */
writel(SYSCFG_START | func | offset >> 2, info->baseaddr + COMMS);
ret = ve_spc_waitforcompletion(SPC_SYS_CFG);
if (ret == 0)
*data = readl(info->baseaddr + SYSCFG_RDATA);
info->cur_rsp_mask = 0;
up(&info->sem);
return ret;
}
static irqreturn_t ve_spc_irq_handler(int irq, void *data)
{
struct ve_spc_drvdata *drv_data = data;
uint32_t status = readl_relaxed(drv_data->baseaddr + PWC_STATUS);
if (info->cur_rsp_mask & status) {
info->cur_rsp_stat = status;
complete(&drv_data->done);
}
return IRQ_HANDLED;
}
/*
* +--------------------------+
* | 31 20 | 19 0 |
* +--------------------------+
* | u_volt | freq(kHz) |
* +--------------------------+
*/
#define MULT_FACTOR 20
#define VOLT_SHIFT 20
#define FREQ_MASK (0xFFFFF)
static int ve_spc_populate_opps(uint32_t cluster)
{ {
uint32_t data = 0, off, ret, idx;
struct ve_spc_opp *opps;
opps = kzalloc(sizeof(*opps) * MAX_OPPS, GFP_KERNEL);
if (!opps)
return -ENOMEM;
info->opps[cluster] = opps;
off = cluster_is_a15(cluster) ? A15_PERFVAL_BASE : A7_PERFVAL_BASE;
for (idx = 0; idx < MAX_OPPS; idx++, off += 4, opps++) {
ret = ve_spc_read_sys_cfg(SYSCFG_SCC, off, &data);
if (!ret) {
opps->freq = (data & FREQ_MASK) * MULT_FACTOR;
opps->u_volt = data >> VOLT_SHIFT;
} else {
break;
}
}
info->num_opps[cluster] = idx;
return ret;
}
static int ve_init_opp_table(struct device *cpu_dev)
{
int cluster = topology_physical_package_id(cpu_dev->id);
int idx, ret = 0, max_opp = info->num_opps[cluster];
struct ve_spc_opp *opps = info->opps[cluster];
for (idx = 0; idx < max_opp; idx++, opps++) {
ret = dev_pm_opp_add(cpu_dev, opps->freq * 1000, opps->u_volt);
if (ret) {
dev_warn(cpu_dev, "failed to add opp %lu %lu\n",
opps->freq, opps->u_volt);
return ret;
}
}
return ret;
}
int __init ve_spc_init(void __iomem *baseaddr, u32 a15_clusid, int irq)
{
int ret;
info = kzalloc(sizeof(*info), GFP_KERNEL); info = kzalloc(sizeof(*info), GFP_KERNEL);
if (!info) { if (!info) {
pr_err(SPCLOG "unable to allocate mem\n"); pr_err(SPCLOG "unable to allocate mem\n");
...@@ -168,6 +413,25 @@ int __init ve_spc_init(void __iomem *baseaddr, u32 a15_clusid) ...@@ -168,6 +413,25 @@ int __init ve_spc_init(void __iomem *baseaddr, u32 a15_clusid)
info->baseaddr = baseaddr; info->baseaddr = baseaddr;
info->a15_clusid = a15_clusid; info->a15_clusid = a15_clusid;
if (irq <= 0) {
pr_err(SPCLOG "Invalid IRQ %d\n", irq);
kfree(info);
return -EINVAL;
}
init_completion(&info->done);
readl_relaxed(info->baseaddr + PWC_STATUS);
ret = request_irq(irq, ve_spc_irq_handler, IRQF_TRIGGER_HIGH
| IRQF_ONESHOT, "vexpress-spc", info);
if (ret) {
pr_err(SPCLOG "IRQ %d request failed\n", irq);
kfree(info);
return -ENODEV;
}
sema_init(&info->sem, 1);
/* /*
* Multi-cluster systems may need this data when non-coherent, during * Multi-cluster systems may need this data when non-coherent, during
* cluster power-up/power-down. Make sure driver info reaches main * cluster power-up/power-down. Make sure driver info reaches main
...@@ -178,3 +442,103 @@ int __init ve_spc_init(void __iomem *baseaddr, u32 a15_clusid) ...@@ -178,3 +442,103 @@ int __init ve_spc_init(void __iomem *baseaddr, u32 a15_clusid)
return 0; return 0;
} }
struct clk_spc {
struct clk_hw hw;
int cluster;
};
#define to_clk_spc(spc) container_of(spc, struct clk_spc, hw)
static unsigned long spc_recalc_rate(struct clk_hw *hw,
unsigned long parent_rate)
{
struct clk_spc *spc = to_clk_spc(hw);
u32 freq;
if (ve_spc_get_performance(spc->cluster, &freq))
return -EIO;
return freq * 1000;
}
static long spc_round_rate(struct clk_hw *hw, unsigned long drate,
unsigned long *parent_rate)
{
struct clk_spc *spc = to_clk_spc(hw);
return ve_spc_round_performance(spc->cluster, drate);
}
static int spc_set_rate(struct clk_hw *hw, unsigned long rate,
unsigned long parent_rate)
{
struct clk_spc *spc = to_clk_spc(hw);
return ve_spc_set_performance(spc->cluster, rate / 1000);
}
static struct clk_ops clk_spc_ops = {
.recalc_rate = spc_recalc_rate,
.round_rate = spc_round_rate,
.set_rate = spc_set_rate,
};
static struct clk *ve_spc_clk_register(struct device *cpu_dev)
{
struct clk_init_data init;
struct clk_spc *spc;
spc = kzalloc(sizeof(*spc), GFP_KERNEL);
if (!spc) {
pr_err("could not allocate spc clk\n");
return ERR_PTR(-ENOMEM);
}
spc->hw.init = &init;
spc->cluster = topology_physical_package_id(cpu_dev->id);
init.name = dev_name(cpu_dev);
init.ops = &clk_spc_ops;
init.flags = CLK_IS_ROOT | CLK_GET_RATE_NOCACHE;
init.num_parents = 0;
return devm_clk_register(cpu_dev, &spc->hw);
}
static int __init ve_spc_clk_init(void)
{
int cpu;
struct clk *clk;
if (!info)
return 0; /* Continue only if SPC is initialised */
if (ve_spc_populate_opps(0) || ve_spc_populate_opps(1)) {
pr_err("failed to build OPP table\n");
return -ENODEV;
}
for_each_possible_cpu(cpu) {
struct device *cpu_dev = get_cpu_device(cpu);
if (!cpu_dev) {
pr_warn("failed to get cpu%d device\n", cpu);
continue;
}
clk = ve_spc_clk_register(cpu_dev);
if (IS_ERR(clk)) {
pr_warn("failed to register cpu%d clock\n", cpu);
continue;
}
if (clk_register_clkdev(clk, NULL, dev_name(cpu_dev))) {
pr_warn("failed to register cpu%d clock lookup\n", cpu);
continue;
}
if (ve_init_opp_table(cpu_dev))
pr_warn("failed to initialise cpu%d opp table\n", cpu);
}
platform_device_register_simple("vexpress-spc-cpufreq", -1, NULL, 0);
return 0;
}
module_init(ve_spc_clk_init);
...@@ -15,7 +15,7 @@ ...@@ -15,7 +15,7 @@
#ifndef __SPC_H_ #ifndef __SPC_H_
#define __SPC_H_ #define __SPC_H_
int __init ve_spc_init(void __iomem *base, u32 a15_clusid); int __init ve_spc_init(void __iomem *base, u32 a15_clusid, int irq);
void ve_spc_global_wakeup_irq(bool set); void ve_spc_global_wakeup_irq(bool set);
void ve_spc_cpu_wakeup_irq(u32 cluster, u32 cpu, bool set); void ve_spc_cpu_wakeup_irq(u32 cluster, u32 cpu, bool set);
void ve_spc_set_resume_addr(u32 cluster, u32 cpu, u32 addr); void ve_spc_set_resume_addr(u32 cluster, u32 cpu, u32 addr);
......
...@@ -16,6 +16,7 @@ ...@@ -16,6 +16,7 @@
#include <linux/io.h> #include <linux/io.h>
#include <linux/kernel.h> #include <linux/kernel.h>
#include <linux/of_address.h> #include <linux/of_address.h>
#include <linux/of_irq.h>
#include <linux/spinlock.h> #include <linux/spinlock.h>
#include <linux/errno.h> #include <linux/errno.h>
#include <linux/irqchip/arm-gic.h> #include <linux/irqchip/arm-gic.h>
...@@ -311,7 +312,7 @@ static void __naked tc2_pm_power_up_setup(unsigned int affinity_level) ...@@ -311,7 +312,7 @@ static void __naked tc2_pm_power_up_setup(unsigned int affinity_level)
static int __init tc2_pm_init(void) static int __init tc2_pm_init(void)
{ {
int ret; int ret, irq;
void __iomem *scc; void __iomem *scc;
u32 a15_cluster_id, a7_cluster_id, sys_info; u32 a15_cluster_id, a7_cluster_id, sys_info;
struct device_node *np; struct device_node *np;
...@@ -336,13 +337,15 @@ static int __init tc2_pm_init(void) ...@@ -336,13 +337,15 @@ static int __init tc2_pm_init(void)
tc2_nr_cpus[a15_cluster_id] = (sys_info >> 16) & 0xf; tc2_nr_cpus[a15_cluster_id] = (sys_info >> 16) & 0xf;
tc2_nr_cpus[a7_cluster_id] = (sys_info >> 20) & 0xf; tc2_nr_cpus[a7_cluster_id] = (sys_info >> 20) & 0xf;
irq = irq_of_parse_and_map(np, 0);
/* /*
* A subset of the SCC registers is also used to communicate * A subset of the SCC registers is also used to communicate
* with the SPC (power controller). We need to be able to * with the SPC (power controller). We need to be able to
* drive it very early in the boot process to power up * drive it very early in the boot process to power up
* processors, so we initialize the SPC driver here. * processors, so we initialize the SPC driver here.
*/ */
ret = ve_spc_init(scc + SPC_BASE, a15_cluster_id); ret = ve_spc_init(scc + SPC_BASE, a15_cluster_id, irq);
if (ret) if (ret)
return ret; return ret;
......
...@@ -224,3 +224,11 @@ config ARM_TEGRA_CPUFREQ ...@@ -224,3 +224,11 @@ config ARM_TEGRA_CPUFREQ
default y default y
help help
This adds the CPUFreq driver support for TEGRA SOCs. This adds the CPUFreq driver support for TEGRA SOCs.
config ARM_VEXPRESS_SPC_CPUFREQ
tristate "Versatile Express SPC based CPUfreq driver"
select ARM_BIG_LITTLE_CPUFREQ
depends on ARCH_VEXPRESS_SPC
help
This add the CPUfreq driver support for Versatile Express
big.LITTLE platforms using SPC for power management.
...@@ -74,6 +74,7 @@ obj-$(CONFIG_ARM_SA1100_CPUFREQ) += sa1100-cpufreq.o ...@@ -74,6 +74,7 @@ obj-$(CONFIG_ARM_SA1100_CPUFREQ) += sa1100-cpufreq.o
obj-$(CONFIG_ARM_SA1110_CPUFREQ) += sa1110-cpufreq.o obj-$(CONFIG_ARM_SA1110_CPUFREQ) += sa1110-cpufreq.o
obj-$(CONFIG_ARM_SPEAR_CPUFREQ) += spear-cpufreq.o obj-$(CONFIG_ARM_SPEAR_CPUFREQ) += spear-cpufreq.o
obj-$(CONFIG_ARM_TEGRA_CPUFREQ) += tegra-cpufreq.o obj-$(CONFIG_ARM_TEGRA_CPUFREQ) += tegra-cpufreq.o
obj-$(CONFIG_ARM_VEXPRESS_SPC_CPUFREQ) += vexpress-spc-cpufreq.o
################################################################################## ##################################################################################
# PowerPC platform drivers # PowerPC platform drivers
......
...@@ -428,14 +428,10 @@ static int acpi_cpufreq_target(struct cpufreq_policy *policy, ...@@ -428,14 +428,10 @@ static int acpi_cpufreq_target(struct cpufreq_policy *policy,
{ {
struct acpi_cpufreq_data *data = per_cpu(acfreq_data, policy->cpu); struct acpi_cpufreq_data *data = per_cpu(acfreq_data, policy->cpu);
struct acpi_processor_performance *perf; struct acpi_processor_performance *perf;
struct cpufreq_freqs freqs;
struct drv_cmd cmd; struct drv_cmd cmd;
unsigned int next_perf_state = 0; /* Index into perf table */ unsigned int next_perf_state = 0; /* Index into perf table */
int result = 0; int result = 0;
pr_debug("acpi_cpufreq_target %d (%d)\n",
data->freq_table[index].frequency, policy->cpu);
if (unlikely(data == NULL || if (unlikely(data == NULL ||
data->acpi_data == NULL || data->freq_table == NULL)) { data->acpi_data == NULL || data->freq_table == NULL)) {
return -ENODEV; return -ENODEV;
...@@ -483,23 +479,17 @@ static int acpi_cpufreq_target(struct cpufreq_policy *policy, ...@@ -483,23 +479,17 @@ static int acpi_cpufreq_target(struct cpufreq_policy *policy,
else else
cmd.mask = cpumask_of(policy->cpu); cmd.mask = cpumask_of(policy->cpu);
freqs.old = perf->states[perf->state].core_frequency * 1000;
freqs.new = data->freq_table[index].frequency;
cpufreq_notify_transition(policy, &freqs, CPUFREQ_PRECHANGE);
drv_write(&cmd); drv_write(&cmd);
if (acpi_pstate_strict) { if (acpi_pstate_strict) {
if (!check_freqs(cmd.mask, freqs.new, data)) { if (!check_freqs(cmd.mask, data->freq_table[index].frequency,
data)) {
pr_debug("acpi_cpufreq_target failed (%d)\n", pr_debug("acpi_cpufreq_target failed (%d)\n",
policy->cpu); policy->cpu);
result = -EAGAIN; result = -EAGAIN;
freqs.new = freqs.old;
} }
} }
cpufreq_notify_transition(policy, &freqs, CPUFREQ_POSTCHANGE);
if (!result) if (!result)
perf->state = next_perf_state; perf->state = next_perf_state;
......
...@@ -24,91 +24,319 @@ ...@@ -24,91 +24,319 @@
#include <linux/cpufreq.h> #include <linux/cpufreq.h>
#include <linux/cpumask.h> #include <linux/cpumask.h>
#include <linux/export.h> #include <linux/export.h>
#include <linux/mutex.h>
#include <linux/of_platform.h> #include <linux/of_platform.h>
#include <linux/pm_opp.h> #include <linux/pm_opp.h>
#include <linux/slab.h> #include <linux/slab.h>
#include <linux/topology.h> #include <linux/topology.h>
#include <linux/types.h> #include <linux/types.h>
#include <asm/bL_switcher.h>
#include "arm_big_little.h" #include "arm_big_little.h"
/* Currently we support only two clusters */ /* Currently we support only two clusters */
#define A15_CLUSTER 0
#define A7_CLUSTER 1
#define MAX_CLUSTERS 2 #define MAX_CLUSTERS 2
#ifdef CONFIG_BL_SWITCHER
static bool bL_switching_enabled;
#define is_bL_switching_enabled() bL_switching_enabled
#define set_switching_enabled(x) (bL_switching_enabled = (x))
#else
#define is_bL_switching_enabled() false
#define set_switching_enabled(x) do { } while (0)
#endif
#define ACTUAL_FREQ(cluster, freq) ((cluster == A7_CLUSTER) ? freq << 1 : freq)
#define VIRT_FREQ(cluster, freq) ((cluster == A7_CLUSTER) ? freq >> 1 : freq)
static struct cpufreq_arm_bL_ops *arm_bL_ops; static 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]; static struct cpufreq_frequency_table *freq_table[MAX_CLUSTERS + 1];
static atomic_t cluster_usage[MAX_CLUSTERS] = {ATOMIC_INIT(0), ATOMIC_INIT(0)}; static atomic_t cluster_usage[MAX_CLUSTERS + 1];
static unsigned int clk_big_min; /* (Big) clock frequencies */
static unsigned int clk_little_max; /* Maximum clock frequency (Little) */
static DEFINE_PER_CPU(unsigned int, physical_cluster);
static DEFINE_PER_CPU(unsigned int, cpu_last_req_freq);
static struct mutex cluster_lock[MAX_CLUSTERS];
static inline int raw_cpu_to_cluster(int cpu)
{
return topology_physical_package_id(cpu);
}
static inline int cpu_to_cluster(int cpu)
{
return is_bL_switching_enabled() ?
MAX_CLUSTERS : raw_cpu_to_cluster(cpu);
}
static unsigned int find_cluster_maxfreq(int cluster)
{
int j;
u32 max_freq = 0, cpu_freq;
for_each_online_cpu(j) {
cpu_freq = per_cpu(cpu_last_req_freq, j);
if ((cluster == per_cpu(physical_cluster, j)) &&
(max_freq < cpu_freq))
max_freq = cpu_freq;
}
pr_debug("%s: cluster: %d, max freq: %d\n", __func__, cluster,
max_freq);
return max_freq;
}
static unsigned int clk_get_cpu_rate(unsigned int cpu)
{
u32 cur_cluster = per_cpu(physical_cluster, cpu);
u32 rate = clk_get_rate(clk[cur_cluster]) / 1000;
/* For switcher we use virtual A7 clock rates */
if (is_bL_switching_enabled())
rate = VIRT_FREQ(cur_cluster, rate);
pr_debug("%s: cpu: %d, cluster: %d, freq: %u\n", __func__, cpu,
cur_cluster, rate);
return rate;
}
static unsigned int bL_cpufreq_get_rate(unsigned int cpu)
{
if (is_bL_switching_enabled()) {
pr_debug("%s: freq: %d\n", __func__, per_cpu(cpu_last_req_freq,
cpu));
return per_cpu(cpu_last_req_freq, cpu);
} else {
return clk_get_cpu_rate(cpu);
}
}
static unsigned int bL_cpufreq_get(unsigned int cpu) static unsigned int
bL_cpufreq_set_rate(u32 cpu, u32 old_cluster, u32 new_cluster, u32 rate)
{ {
u32 cur_cluster = cpu_to_cluster(cpu); u32 new_rate, prev_rate;
int ret;
bool bLs = is_bL_switching_enabled();
mutex_lock(&cluster_lock[new_cluster]);
if (bLs) {
prev_rate = per_cpu(cpu_last_req_freq, cpu);
per_cpu(cpu_last_req_freq, cpu) = rate;
per_cpu(physical_cluster, cpu) = new_cluster;
new_rate = find_cluster_maxfreq(new_cluster);
new_rate = ACTUAL_FREQ(new_cluster, new_rate);
} else {
new_rate = rate;
}
pr_debug("%s: cpu: %d, old cluster: %d, new cluster: %d, freq: %d\n",
__func__, cpu, old_cluster, new_cluster, new_rate);
ret = clk_set_rate(clk[new_cluster], new_rate * 1000);
if (WARN_ON(ret)) {
pr_err("clk_set_rate failed: %d, new cluster: %d\n", ret,
new_cluster);
if (bLs) {
per_cpu(cpu_last_req_freq, cpu) = prev_rate;
per_cpu(physical_cluster, cpu) = old_cluster;
}
mutex_unlock(&cluster_lock[new_cluster]);
return ret;
}
mutex_unlock(&cluster_lock[new_cluster]);
/* Recalc freq for old cluster when switching clusters */
if (old_cluster != new_cluster) {
pr_debug("%s: cpu: %d, old cluster: %d, new cluster: %d\n",
__func__, cpu, old_cluster, new_cluster);
/* Switch cluster */
bL_switch_request(cpu, new_cluster);
mutex_lock(&cluster_lock[old_cluster]);
return clk_get_rate(clk[cur_cluster]) / 1000; /* Set freq of old cluster if there are cpus left on it */
new_rate = find_cluster_maxfreq(old_cluster);
new_rate = ACTUAL_FREQ(old_cluster, new_rate);
if (new_rate) {
pr_debug("%s: Updating rate of old cluster: %d, to freq: %d\n",
__func__, old_cluster, new_rate);
if (clk_set_rate(clk[old_cluster], new_rate * 1000))
pr_err("%s: clk_set_rate failed: %d, old cluster: %d\n",
__func__, ret, old_cluster);
}
mutex_unlock(&cluster_lock[old_cluster]);
}
return 0;
} }
/* Set clock frequency */ /* Set clock frequency */
static int bL_cpufreq_set_target(struct cpufreq_policy *policy, static int bL_cpufreq_set_target(struct cpufreq_policy *policy,
unsigned int index) unsigned int index)
{ {
struct cpufreq_freqs freqs; u32 cpu = policy->cpu, cur_cluster, new_cluster, actual_cluster;
u32 cpu = policy->cpu, cur_cluster; unsigned int freqs_new;
int ret = 0;
cur_cluster = cpu_to_cluster(cpu);
new_cluster = actual_cluster = per_cpu(physical_cluster, cpu);
freqs_new = freq_table[cur_cluster][index].frequency;
if (is_bL_switching_enabled()) {
if ((actual_cluster == A15_CLUSTER) &&
(freqs_new < clk_big_min)) {
new_cluster = A7_CLUSTER;
} else if ((actual_cluster == A7_CLUSTER) &&
(freqs_new > clk_little_max)) {
new_cluster = A15_CLUSTER;
}
}
cur_cluster = cpu_to_cluster(policy->cpu); return bL_cpufreq_set_rate(cpu, actual_cluster, new_cluster, freqs_new);
}
freqs.old = bL_cpufreq_get(policy->cpu); static inline u32 get_table_count(struct cpufreq_frequency_table *table)
freqs.new = freq_table[cur_cluster][index].frequency; {
int count;
pr_debug("%s: cpu: %d, cluster: %d, oldfreq: %d, target freq: %d, new freq: %d\n", for (count = 0; table[count].frequency != CPUFREQ_TABLE_END; count++)
__func__, cpu, cur_cluster, freqs.old, freqs.new, ;
freqs.new);
cpufreq_notify_transition(policy, &freqs, CPUFREQ_PRECHANGE); return count;
}
ret = clk_set_rate(clk[cur_cluster], freqs.new * 1000); /* get the minimum frequency in the cpufreq_frequency_table */
if (ret) { static inline u32 get_table_min(struct cpufreq_frequency_table *table)
pr_err("clk_set_rate failed: %d\n", ret); {
freqs.new = freqs.old; int i;
uint32_t min_freq = ~0;
for (i = 0; (table[i].frequency != CPUFREQ_TABLE_END); i++)
if (table[i].frequency < min_freq)
min_freq = table[i].frequency;
return min_freq;
}
/* get the maximum frequency in the cpufreq_frequency_table */
static inline u32 get_table_max(struct cpufreq_frequency_table *table)
{
int i;
uint32_t max_freq = 0;
for (i = 0; (table[i].frequency != CPUFREQ_TABLE_END); i++)
if (table[i].frequency > max_freq)
max_freq = table[i].frequency;
return max_freq;
}
static int merge_cluster_tables(void)
{
int i, j, k = 0, count = 1;
struct cpufreq_frequency_table *table;
for (i = 0; i < MAX_CLUSTERS; i++)
count += get_table_count(freq_table[i]);
table = kzalloc(sizeof(*table) * count, GFP_KERNEL);
if (!table)
return -ENOMEM;
freq_table[MAX_CLUSTERS] = table;
/* Add in reverse order to get freqs in increasing order */
for (i = MAX_CLUSTERS - 1; i >= 0; i--) {
for (j = 0; freq_table[i][j].frequency != CPUFREQ_TABLE_END;
j++) {
table[k].frequency = VIRT_FREQ(i,
freq_table[i][j].frequency);
pr_debug("%s: index: %d, freq: %d\n", __func__, k,
table[k].frequency);
k++;
}
} }
cpufreq_notify_transition(policy, &freqs, CPUFREQ_POSTCHANGE); table[k].driver_data = k;
table[k].frequency = CPUFREQ_TABLE_END;
return ret; pr_debug("%s: End, table: %p, count: %d\n", __func__, table, k);
return 0;
}
static void _put_cluster_clk_and_freq_table(struct device *cpu_dev)
{
u32 cluster = raw_cpu_to_cluster(cpu_dev->id);
if (!freq_table[cluster])
return;
clk_put(clk[cluster]);
dev_pm_opp_free_cpufreq_table(cpu_dev, &freq_table[cluster]);
dev_dbg(cpu_dev, "%s: cluster: %d\n", __func__, cluster);
} }
static void put_cluster_clk_and_freq_table(struct device *cpu_dev) static void put_cluster_clk_and_freq_table(struct device *cpu_dev)
{ {
u32 cluster = cpu_to_cluster(cpu_dev->id); u32 cluster = cpu_to_cluster(cpu_dev->id);
int i;
if (atomic_dec_return(&cluster_usage[cluster]))
return;
if (cluster < MAX_CLUSTERS)
return _put_cluster_clk_and_freq_table(cpu_dev);
for_each_present_cpu(i) {
struct device *cdev = get_cpu_device(i);
if (!cdev) {
pr_err("%s: failed to get cpu%d device\n", __func__, i);
return;
}
if (!atomic_dec_return(&cluster_usage[cluster])) { _put_cluster_clk_and_freq_table(cdev);
clk_put(clk[cluster]);
dev_pm_opp_free_cpufreq_table(cpu_dev, &freq_table[cluster]);
dev_dbg(cpu_dev, "%s: cluster: %d\n", __func__, cluster);
} }
/* free virtual table */
kfree(freq_table[cluster]);
} }
static int get_cluster_clk_and_freq_table(struct device *cpu_dev) static int _get_cluster_clk_and_freq_table(struct device *cpu_dev)
{ {
u32 cluster = cpu_to_cluster(cpu_dev->id); u32 cluster = raw_cpu_to_cluster(cpu_dev->id);
char name[14] = "cpu-cluster."; char name[14] = "cpu-cluster.";
int ret; int ret;
if (atomic_inc_return(&cluster_usage[cluster]) != 1) if (freq_table[cluster])
return 0; return 0;
ret = arm_bL_ops->init_opp_table(cpu_dev); ret = arm_bL_ops->init_opp_table(cpu_dev);
if (ret) { if (ret) {
dev_err(cpu_dev, "%s: init_opp_table failed, cpu: %d, err: %d\n", dev_err(cpu_dev, "%s: init_opp_table failed, cpu: %d, err: %d\n",
__func__, cpu_dev->id, ret); __func__, cpu_dev->id, ret);
goto atomic_dec; goto out;
} }
ret = dev_pm_opp_init_cpufreq_table(cpu_dev, &freq_table[cluster]); ret = dev_pm_opp_init_cpufreq_table(cpu_dev, &freq_table[cluster]);
if (ret) { if (ret) {
dev_err(cpu_dev, "%s: failed to init cpufreq table, cpu: %d, err: %d\n", dev_err(cpu_dev, "%s: failed to init cpufreq table, cpu: %d, err: %d\n",
__func__, cpu_dev->id, ret); __func__, cpu_dev->id, ret);
goto atomic_dec; goto out;
} }
name[12] = cluster + '0'; name[12] = cluster + '0';
...@@ -125,13 +353,72 @@ static int get_cluster_clk_and_freq_table(struct device *cpu_dev) ...@@ -125,13 +353,72 @@ static int get_cluster_clk_and_freq_table(struct device *cpu_dev)
ret = PTR_ERR(clk[cluster]); ret = PTR_ERR(clk[cluster]);
dev_pm_opp_free_cpufreq_table(cpu_dev, &freq_table[cluster]); dev_pm_opp_free_cpufreq_table(cpu_dev, &freq_table[cluster]);
atomic_dec: out:
atomic_dec(&cluster_usage[cluster]);
dev_err(cpu_dev, "%s: Failed to get data for cluster: %d\n", __func__, dev_err(cpu_dev, "%s: Failed to get data for cluster: %d\n", __func__,
cluster); cluster);
return ret; return ret;
} }
static int get_cluster_clk_and_freq_table(struct device *cpu_dev)
{
u32 cluster = cpu_to_cluster(cpu_dev->id);
int i, ret;
if (atomic_inc_return(&cluster_usage[cluster]) != 1)
return 0;
if (cluster < MAX_CLUSTERS) {
ret = _get_cluster_clk_and_freq_table(cpu_dev);
if (ret)
atomic_dec(&cluster_usage[cluster]);
return ret;
}
/*
* Get data for all clusters and fill virtual cluster with a merge of
* both
*/
for_each_present_cpu(i) {
struct device *cdev = get_cpu_device(i);
if (!cdev) {
pr_err("%s: failed to get cpu%d device\n", __func__, i);
return -ENODEV;
}
ret = _get_cluster_clk_and_freq_table(cdev);
if (ret)
goto put_clusters;
}
ret = merge_cluster_tables();
if (ret)
goto put_clusters;
/* Assuming 2 cluster, set clk_big_min and clk_little_max */
clk_big_min = get_table_min(freq_table[0]);
clk_little_max = VIRT_FREQ(1, get_table_max(freq_table[1]));
pr_debug("%s: cluster: %d, clk_big_min: %d, clk_little_max: %d\n",
__func__, cluster, clk_big_min, clk_little_max);
return 0;
put_clusters:
for_each_present_cpu(i) {
struct device *cdev = get_cpu_device(i);
if (!cdev) {
pr_err("%s: failed to get cpu%d device\n", __func__, i);
return -ENODEV;
}
_put_cluster_clk_and_freq_table(cdev);
}
atomic_dec(&cluster_usage[cluster]);
return ret;
}
/* Per-CPU initialization */ /* Per-CPU initialization */
static int bL_cpufreq_init(struct cpufreq_policy *policy) static int bL_cpufreq_init(struct cpufreq_policy *policy)
{ {
...@@ -158,13 +445,23 @@ static int bL_cpufreq_init(struct cpufreq_policy *policy) ...@@ -158,13 +445,23 @@ static int bL_cpufreq_init(struct cpufreq_policy *policy)
return ret; return ret;
} }
if (cur_cluster < MAX_CLUSTERS) {
cpumask_copy(policy->cpus, topology_core_cpumask(policy->cpu));
per_cpu(physical_cluster, policy->cpu) = cur_cluster;
} else {
/* Assumption: during init, we are always running on A15 */
per_cpu(physical_cluster, policy->cpu) = A15_CLUSTER;
}
if (arm_bL_ops->get_transition_latency) if (arm_bL_ops->get_transition_latency)
policy->cpuinfo.transition_latency = policy->cpuinfo.transition_latency =
arm_bL_ops->get_transition_latency(cpu_dev); arm_bL_ops->get_transition_latency(cpu_dev);
else else
policy->cpuinfo.transition_latency = CPUFREQ_ETERNAL; policy->cpuinfo.transition_latency = CPUFREQ_ETERNAL;
cpumask_copy(policy->cpus, topology_core_cpumask(policy->cpu)); if (is_bL_switching_enabled())
per_cpu(cpu_last_req_freq, policy->cpu) = clk_get_cpu_rate(policy->cpu);
dev_info(cpu_dev, "%s: CPU %d initialized\n", __func__, policy->cpu); dev_info(cpu_dev, "%s: CPU %d initialized\n", __func__, policy->cpu);
return 0; return 0;
...@@ -194,15 +491,47 @@ static struct cpufreq_driver bL_cpufreq_driver = { ...@@ -194,15 +491,47 @@ static struct cpufreq_driver bL_cpufreq_driver = {
CPUFREQ_HAVE_GOVERNOR_PER_POLICY, CPUFREQ_HAVE_GOVERNOR_PER_POLICY,
.verify = cpufreq_generic_frequency_table_verify, .verify = cpufreq_generic_frequency_table_verify,
.target_index = bL_cpufreq_set_target, .target_index = bL_cpufreq_set_target,
.get = bL_cpufreq_get, .get = bL_cpufreq_get_rate,
.init = bL_cpufreq_init, .init = bL_cpufreq_init,
.exit = bL_cpufreq_exit, .exit = bL_cpufreq_exit,
.attr = cpufreq_generic_attr, .attr = cpufreq_generic_attr,
}; };
static int bL_cpufreq_switcher_notifier(struct notifier_block *nfb,
unsigned long action, void *_arg)
{
pr_debug("%s: action: %ld\n", __func__, action);
switch (action) {
case BL_NOTIFY_PRE_ENABLE:
case BL_NOTIFY_PRE_DISABLE:
cpufreq_unregister_driver(&bL_cpufreq_driver);
break;
case BL_NOTIFY_POST_ENABLE:
set_switching_enabled(true);
cpufreq_register_driver(&bL_cpufreq_driver);
break;
case BL_NOTIFY_POST_DISABLE:
set_switching_enabled(false);
cpufreq_register_driver(&bL_cpufreq_driver);
break;
default:
return NOTIFY_DONE;
}
return NOTIFY_OK;
}
static struct notifier_block bL_switcher_notifier = {
.notifier_call = bL_cpufreq_switcher_notifier,
};
int bL_cpufreq_register(struct cpufreq_arm_bL_ops *ops) int bL_cpufreq_register(struct cpufreq_arm_bL_ops *ops)
{ {
int ret; int ret, i;
if (arm_bL_ops) { if (arm_bL_ops) {
pr_debug("%s: Already registered: %s, exiting\n", __func__, pr_debug("%s: Already registered: %s, exiting\n", __func__,
...@@ -217,16 +546,29 @@ int bL_cpufreq_register(struct cpufreq_arm_bL_ops *ops) ...@@ -217,16 +546,29 @@ int bL_cpufreq_register(struct cpufreq_arm_bL_ops *ops)
arm_bL_ops = ops; arm_bL_ops = ops;
ret = bL_switcher_get_enabled();
set_switching_enabled(ret);
for (i = 0; i < MAX_CLUSTERS; i++)
mutex_init(&cluster_lock[i]);
ret = cpufreq_register_driver(&bL_cpufreq_driver); ret = cpufreq_register_driver(&bL_cpufreq_driver);
if (ret) { if (ret) {
pr_info("%s: Failed registering platform driver: %s, err: %d\n", pr_info("%s: Failed registering platform driver: %s, err: %d\n",
__func__, ops->name, ret); __func__, ops->name, ret);
arm_bL_ops = NULL; arm_bL_ops = NULL;
} else { } else {
pr_info("%s: Registered platform driver: %s\n", __func__, ret = bL_switcher_register_notifier(&bL_switcher_notifier);
ops->name); if (ret) {
cpufreq_unregister_driver(&bL_cpufreq_driver);
arm_bL_ops = NULL;
} else {
pr_info("%s: Registered platform driver: %s\n",
__func__, ops->name);
}
} }
bL_switcher_put_enabled();
return ret; return ret;
} }
EXPORT_SYMBOL_GPL(bL_cpufreq_register); EXPORT_SYMBOL_GPL(bL_cpufreq_register);
...@@ -239,7 +581,10 @@ void bL_cpufreq_unregister(struct cpufreq_arm_bL_ops *ops) ...@@ -239,7 +581,10 @@ void bL_cpufreq_unregister(struct cpufreq_arm_bL_ops *ops)
return; return;
} }
bL_switcher_get_enabled();
bL_switcher_unregister_notifier(&bL_switcher_notifier);
cpufreq_unregister_driver(&bL_cpufreq_driver); cpufreq_unregister_driver(&bL_cpufreq_driver);
bL_switcher_put_enabled();
pr_info("%s: Un-registered platform driver: %s\n", __func__, pr_info("%s: Un-registered platform driver: %s\n", __func__,
arm_bL_ops->name); arm_bL_ops->name);
arm_bL_ops = NULL; arm_bL_ops = NULL;
......
...@@ -34,11 +34,6 @@ struct cpufreq_arm_bL_ops { ...@@ -34,11 +34,6 @@ struct cpufreq_arm_bL_ops {
int (*init_opp_table)(struct device *cpu_dev); int (*init_opp_table)(struct device *cpu_dev);
}; };
static inline int cpu_to_cluster(int cpu)
{
return topology_physical_package_id(cpu);
}
int bL_cpufreq_register(struct cpufreq_arm_bL_ops *ops); int bL_cpufreq_register(struct cpufreq_arm_bL_ops *ops);
void bL_cpufreq_unregister(struct cpufreq_arm_bL_ops *ops); void bL_cpufreq_unregister(struct cpufreq_arm_bL_ops *ops);
......
...@@ -37,27 +37,23 @@ static unsigned long loops_per_jiffy_ref; ...@@ -37,27 +37,23 @@ static unsigned long loops_per_jiffy_ref;
static int at32_set_target(struct cpufreq_policy *policy, unsigned int index) static int at32_set_target(struct cpufreq_policy *policy, unsigned int index)
{ {
struct cpufreq_freqs freqs; unsigned int old_freq, new_freq;
freqs.old = at32_get_speed(0); old_freq = at32_get_speed(0);
freqs.new = freq_table[index].frequency; new_freq = freq_table[index].frequency;
if (!ref_freq) { if (!ref_freq) {
ref_freq = freqs.old; ref_freq = old_freq;
loops_per_jiffy_ref = boot_cpu_data.loops_per_jiffy; loops_per_jiffy_ref = boot_cpu_data.loops_per_jiffy;
} }
cpufreq_notify_transition(policy, &freqs, CPUFREQ_PRECHANGE); if (old_freq < new_freq)
if (freqs.old < freqs.new)
boot_cpu_data.loops_per_jiffy = cpufreq_scale( boot_cpu_data.loops_per_jiffy = cpufreq_scale(
loops_per_jiffy_ref, ref_freq, freqs.new); loops_per_jiffy_ref, ref_freq, new_freq);
clk_set_rate(cpuclk, freqs.new * 1000); clk_set_rate(cpuclk, new_freq * 1000);
if (freqs.new < freqs.old) if (new_freq < old_freq)
boot_cpu_data.loops_per_jiffy = cpufreq_scale( boot_cpu_data.loops_per_jiffy = cpufreq_scale(
loops_per_jiffy_ref, ref_freq, freqs.new); loops_per_jiffy_ref, ref_freq, new_freq);
cpufreq_notify_transition(policy, &freqs, CPUFREQ_POSTCHANGE);
pr_debug("cpufreq: set frequency %u Hz\n", freqs.new * 1000);
return 0; return 0;
} }
......
...@@ -132,27 +132,23 @@ static int bfin_target(struct cpufreq_policy *policy, unsigned int index) ...@@ -132,27 +132,23 @@ static int bfin_target(struct cpufreq_policy *policy, unsigned int index)
#ifndef CONFIG_BF60x #ifndef CONFIG_BF60x
unsigned int plldiv; unsigned int plldiv;
#endif #endif
struct cpufreq_freqs freqs;
static unsigned long lpj_ref; static unsigned long lpj_ref;
static unsigned int lpj_ref_freq; static unsigned int lpj_ref_freq;
unsigned int old_freq, new_freq;
int ret = 0; int ret = 0;
#if defined(CONFIG_CYCLES_CLOCKSOURCE) #if defined(CONFIG_CYCLES_CLOCKSOURCE)
cycles_t cycles; cycles_t cycles;
#endif #endif
freqs.old = bfin_getfreq_khz(0); old_freq = bfin_getfreq_khz(0);
freqs.new = bfin_freq_table[index].frequency; new_freq = bfin_freq_table[index].frequency;
pr_debug("cpufreq: changing cclk to %lu; target = %u, oldfreq = %u\n",
freqs.new, freqs.new, freqs.old);
cpufreq_notify_transition(policy, &freqs, CPUFREQ_PRECHANGE);
#ifndef CONFIG_BF60x #ifndef CONFIG_BF60x
plldiv = (bfin_read_PLL_DIV() & SSEL) | dpm_state_table[index].csel; plldiv = (bfin_read_PLL_DIV() & SSEL) | dpm_state_table[index].csel;
bfin_write_PLL_DIV(plldiv); bfin_write_PLL_DIV(plldiv);
#else #else
ret = cpu_set_cclk(policy->cpu, freqs.new * 1000); ret = cpu_set_cclk(policy->cpu, new_freq * 1000);
if (ret != 0) { if (ret != 0) {
WARN_ONCE(ret, "cpufreq set freq failed %d\n", ret); WARN_ONCE(ret, "cpufreq set freq failed %d\n", ret);
return ret; return ret;
...@@ -168,17 +164,13 @@ static int bfin_target(struct cpufreq_policy *policy, unsigned int index) ...@@ -168,17 +164,13 @@ static int bfin_target(struct cpufreq_policy *policy, unsigned int index)
#endif #endif
if (!lpj_ref_freq) { if (!lpj_ref_freq) {
lpj_ref = loops_per_jiffy; lpj_ref = loops_per_jiffy;
lpj_ref_freq = freqs.old; lpj_ref_freq = old_freq;
} }
if (freqs.new != freqs.old) { if (new_freq != old_freq) {
loops_per_jiffy = cpufreq_scale(lpj_ref, loops_per_jiffy = cpufreq_scale(lpj_ref,
lpj_ref_freq, freqs.new); lpj_ref_freq, new_freq);
} }
/* TODO: just test case for cycles clock source, remove later */
cpufreq_notify_transition(policy, &freqs, CPUFREQ_POSTCHANGE);
pr_debug("cpufreq: done\n");
return ret; return ret;
} }
......
...@@ -37,20 +37,19 @@ static unsigned int cpu0_get_speed(unsigned int cpu) ...@@ -37,20 +37,19 @@ static unsigned int cpu0_get_speed(unsigned int cpu)
static int cpu0_set_target(struct cpufreq_policy *policy, unsigned int index) static int cpu0_set_target(struct cpufreq_policy *policy, unsigned int index)
{ {
struct cpufreq_freqs freqs;
struct dev_pm_opp *opp; struct dev_pm_opp *opp;
unsigned long volt = 0, volt_old = 0, tol = 0; unsigned long volt = 0, volt_old = 0, tol = 0;
unsigned int old_freq, new_freq;
long freq_Hz, freq_exact; long freq_Hz, freq_exact;
int ret; int ret;
freq_Hz = clk_round_rate(cpu_clk, freq_table[index].frequency * 1000); freq_Hz = clk_round_rate(cpu_clk, freq_table[index].frequency * 1000);
if (freq_Hz < 0) if (freq_Hz < 0)
freq_Hz = freq_table[index].frequency * 1000; freq_Hz = freq_table[index].frequency * 1000;
freq_exact = freq_Hz;
freqs.new = freq_Hz / 1000;
freqs.old = clk_get_rate(cpu_clk) / 1000;
cpufreq_notify_transition(policy, &freqs, CPUFREQ_PRECHANGE); freq_exact = freq_Hz;
new_freq = freq_Hz / 1000;
old_freq = clk_get_rate(cpu_clk) / 1000;
if (!IS_ERR(cpu_reg)) { if (!IS_ERR(cpu_reg)) {
rcu_read_lock(); rcu_read_lock();
...@@ -58,9 +57,7 @@ static int cpu0_set_target(struct cpufreq_policy *policy, unsigned int index) ...@@ -58,9 +57,7 @@ static int cpu0_set_target(struct cpufreq_policy *policy, unsigned int index)
if (IS_ERR(opp)) { if (IS_ERR(opp)) {
rcu_read_unlock(); rcu_read_unlock();
pr_err("failed to find OPP for %ld\n", freq_Hz); pr_err("failed to find OPP for %ld\n", freq_Hz);
freqs.new = freqs.old; return PTR_ERR(opp);
ret = PTR_ERR(opp);
goto post_notify;
} }
volt = dev_pm_opp_get_voltage(opp); volt = dev_pm_opp_get_voltage(opp);
rcu_read_unlock(); rcu_read_unlock();
...@@ -69,16 +66,15 @@ static int cpu0_set_target(struct cpufreq_policy *policy, unsigned int index) ...@@ -69,16 +66,15 @@ static int cpu0_set_target(struct cpufreq_policy *policy, unsigned int index)
} }
pr_debug("%u MHz, %ld mV --> %u MHz, %ld mV\n", pr_debug("%u MHz, %ld mV --> %u MHz, %ld mV\n",
freqs.old / 1000, volt_old ? volt_old / 1000 : -1, old_freq / 1000, volt_old ? volt_old / 1000 : -1,
freqs.new / 1000, volt ? volt / 1000 : -1); new_freq / 1000, volt ? volt / 1000 : -1);
/* scaling up? scale voltage before frequency */ /* scaling up? scale voltage before frequency */
if (!IS_ERR(cpu_reg) && freqs.new > freqs.old) { if (!IS_ERR(cpu_reg) && new_freq > old_freq) {
ret = regulator_set_voltage_tol(cpu_reg, volt, tol); ret = regulator_set_voltage_tol(cpu_reg, volt, tol);
if (ret) { if (ret) {
pr_err("failed to scale voltage up: %d\n", ret); pr_err("failed to scale voltage up: %d\n", ret);
freqs.new = freqs.old; return ret;
goto post_notify;
} }
} }
...@@ -87,23 +83,18 @@ static int cpu0_set_target(struct cpufreq_policy *policy, unsigned int index) ...@@ -87,23 +83,18 @@ static int cpu0_set_target(struct cpufreq_policy *policy, unsigned int index)
pr_err("failed to set clock rate: %d\n", ret); pr_err("failed to set clock rate: %d\n", ret);
if (!IS_ERR(cpu_reg)) if (!IS_ERR(cpu_reg))
regulator_set_voltage_tol(cpu_reg, volt_old, tol); regulator_set_voltage_tol(cpu_reg, volt_old, tol);
freqs.new = freqs.old; return ret;
goto post_notify;
} }
/* scaling down? scale voltage after frequency */ /* scaling down? scale voltage after frequency */
if (!IS_ERR(cpu_reg) && freqs.new < freqs.old) { if (!IS_ERR(cpu_reg) && new_freq < old_freq) {
ret = regulator_set_voltage_tol(cpu_reg, volt, tol); ret = regulator_set_voltage_tol(cpu_reg, volt, tol);
if (ret) { if (ret) {
pr_err("failed to scale voltage down: %d\n", ret); pr_err("failed to scale voltage down: %d\n", ret);
clk_set_rate(cpu_clk, freqs.old * 1000); clk_set_rate(cpu_clk, old_freq * 1000);
freqs.new = freqs.old;
} }
} }
post_notify:
cpufreq_notify_transition(policy, &freqs, CPUFREQ_POSTCHANGE);
return ret; return ret;
} }
......
...@@ -1669,6 +1669,8 @@ int __cpufreq_driver_target(struct cpufreq_policy *policy, ...@@ -1669,6 +1669,8 @@ int __cpufreq_driver_target(struct cpufreq_policy *policy,
retval = cpufreq_driver->target(policy, target_freq, relation); retval = cpufreq_driver->target(policy, target_freq, relation);
else if (cpufreq_driver->target_index) { else if (cpufreq_driver->target_index) {
struct cpufreq_frequency_table *freq_table; struct cpufreq_frequency_table *freq_table;
struct cpufreq_freqs freqs;
bool notify;
int index; int index;
freq_table = cpufreq_frequency_get_table(policy->cpu); freq_table = cpufreq_frequency_get_table(policy->cpu);
...@@ -1684,10 +1686,42 @@ int __cpufreq_driver_target(struct cpufreq_policy *policy, ...@@ -1684,10 +1686,42 @@ int __cpufreq_driver_target(struct cpufreq_policy *policy,
goto out; goto out;
} }
if (freq_table[index].frequency == policy->cur) if (freq_table[index].frequency == policy->cur) {
retval = 0; retval = 0;
else goto out;
retval = cpufreq_driver->target_index(policy, index); }
notify = !(cpufreq_driver->flags & CPUFREQ_ASYNC_NOTIFICATION);
if (notify) {
freqs.old = policy->cur;
freqs.new = freq_table[index].frequency;
freqs.flags = 0;
pr_debug("%s: cpu: %d, oldfreq: %u, new freq: %u\n",
__func__, policy->cpu, freqs.old,
freqs.new);
cpufreq_notify_transition(policy, &freqs,
CPUFREQ_PRECHANGE);
}
retval = cpufreq_driver->target_index(policy, index);
if (retval)
pr_err("%s: Failed to change cpu frequency: %d\n",
__func__, retval);
if (notify) {
/*
* Notify with old freq in case we failed to change
* frequency
*/
if (retval)
freqs.new = freqs.old;
cpufreq_notify_transition(policy, &freqs,
CPUFREQ_POSTCHANGE);
}
} }
out: out:
......
...@@ -168,7 +168,6 @@ static void od_check_cpu(int cpu, unsigned int load) ...@@ -168,7 +168,6 @@ static void od_check_cpu(int cpu, unsigned int load)
dbs_info->rate_mult = dbs_info->rate_mult =
od_tuners->sampling_down_factor; od_tuners->sampling_down_factor;
dbs_freq_increase(policy, policy->max); dbs_freq_increase(policy, policy->max);
return;
} else { } else {
/* Calculate the next frequency proportional to load */ /* Calculate the next frequency proportional to load */
unsigned int freq_next; unsigned int freq_next;
......
...@@ -29,15 +29,9 @@ static unsigned int cris_freq_get_cpu_frequency(unsigned int cpu) ...@@ -29,15 +29,9 @@ static unsigned int cris_freq_get_cpu_frequency(unsigned int cpu)
static int cris_freq_target(struct cpufreq_policy *policy, unsigned int state) static int cris_freq_target(struct cpufreq_policy *policy, unsigned int state)
{ {
struct cpufreq_freqs freqs;
reg_clkgen_rw_clk_ctrl clk_ctrl; reg_clkgen_rw_clk_ctrl clk_ctrl;
clk_ctrl = REG_RD(clkgen, regi_clkgen, rw_clk_ctrl); clk_ctrl = REG_RD(clkgen, regi_clkgen, rw_clk_ctrl);
freqs.old = cris_freq_get_cpu_frequency(policy->cpu);
freqs.new = cris_freq_table[state].frequency;
cpufreq_notify_transition(policy, &freqs, CPUFREQ_PRECHANGE);
local_irq_disable(); local_irq_disable();
/* Even though we may be SMP they will share the same clock /* Even though we may be SMP they will share the same clock
...@@ -50,8 +44,6 @@ static int cris_freq_target(struct cpufreq_policy *policy, unsigned int state) ...@@ -50,8 +44,6 @@ static int cris_freq_target(struct cpufreq_policy *policy, unsigned int state)
local_irq_enable(); local_irq_enable();
cpufreq_notify_transition(policy, &freqs, CPUFREQ_POSTCHANGE);
return 0; return 0;
} }
......
...@@ -29,15 +29,9 @@ static unsigned int cris_freq_get_cpu_frequency(unsigned int cpu) ...@@ -29,15 +29,9 @@ static unsigned int cris_freq_get_cpu_frequency(unsigned int cpu)
static int cris_freq_target(struct cpufreq_policy *policy, unsigned int state) static int cris_freq_target(struct cpufreq_policy *policy, unsigned int state)
{ {
struct cpufreq_freqs freqs;
reg_config_rw_clk_ctrl clk_ctrl; reg_config_rw_clk_ctrl clk_ctrl;
clk_ctrl = REG_RD(config, regi_config, rw_clk_ctrl); clk_ctrl = REG_RD(config, regi_config, rw_clk_ctrl);
freqs.old = cris_freq_get_cpu_frequency(policy->cpu);
freqs.new = cris_freq_table[state].frequency;
cpufreq_notify_transition(policy, &freqs, CPUFREQ_PRECHANGE);
local_irq_disable(); local_irq_disable();
/* Even though we may be SMP they will share the same clock /* Even though we may be SMP they will share the same clock
...@@ -50,8 +44,6 @@ static int cris_freq_target(struct cpufreq_policy *policy, unsigned int state) ...@@ -50,8 +44,6 @@ static int cris_freq_target(struct cpufreq_policy *policy, unsigned int state)
local_irq_enable(); local_irq_enable();
cpufreq_notify_transition(policy, &freqs, CPUFREQ_POSTCHANGE);
return 0; return 0;
} }
......
...@@ -68,46 +68,36 @@ static unsigned int davinci_getspeed(unsigned int cpu) ...@@ -68,46 +68,36 @@ static unsigned int davinci_getspeed(unsigned int cpu)
static int davinci_target(struct cpufreq_policy *policy, unsigned int idx) static int davinci_target(struct cpufreq_policy *policy, unsigned int idx)
{ {
int ret = 0;
struct cpufreq_freqs freqs;
struct davinci_cpufreq_config *pdata = cpufreq.dev->platform_data; struct davinci_cpufreq_config *pdata = cpufreq.dev->platform_data;
struct clk *armclk = cpufreq.armclk; struct clk *armclk = cpufreq.armclk;
unsigned int old_freq, new_freq;
int ret = 0;
freqs.old = davinci_getspeed(0); old_freq = davinci_getspeed(0);
freqs.new = pdata->freq_table[idx].frequency; new_freq = pdata->freq_table[idx].frequency;
dev_dbg(cpufreq.dev, "transition: %u --> %u\n", freqs.old, freqs.new);
cpufreq_notify_transition(policy, &freqs, CPUFREQ_PRECHANGE);
/* if moving to higher frequency, up the voltage beforehand */ /* if moving to higher frequency, up the voltage beforehand */
if (pdata->set_voltage && freqs.new > freqs.old) { if (pdata->set_voltage && new_freq > old_freq) {
ret = pdata->set_voltage(idx); ret = pdata->set_voltage(idx);
if (ret) if (ret)
goto out; return ret;
} }
ret = clk_set_rate(armclk, idx); ret = clk_set_rate(armclk, idx);
if (ret) if (ret)
goto out; return ret;
if (cpufreq.asyncclk) { if (cpufreq.asyncclk) {
ret = clk_set_rate(cpufreq.asyncclk, cpufreq.asyncrate); ret = clk_set_rate(cpufreq.asyncclk, cpufreq.asyncrate);
if (ret) if (ret)
goto out; return ret;
} }
/* if moving to lower freq, lower the voltage after lowering freq */ /* if moving to lower freq, lower the voltage after lowering freq */
if (pdata->set_voltage && freqs.new < freqs.old) if (pdata->set_voltage && new_freq < old_freq)
pdata->set_voltage(idx); pdata->set_voltage(idx);
out: return 0;
if (ret)
freqs.new = freqs.old;
cpufreq_notify_transition(policy, &freqs, CPUFREQ_POSTCHANGE);
return ret;
} }
static int davinci_cpu_init(struct cpufreq_policy *policy) static int davinci_cpu_init(struct cpufreq_policy *policy)
......
...@@ -22,28 +22,8 @@ static struct clk *armss_clk; ...@@ -22,28 +22,8 @@ static struct clk *armss_clk;
static int dbx500_cpufreq_target(struct cpufreq_policy *policy, static int dbx500_cpufreq_target(struct cpufreq_policy *policy,
unsigned int index) unsigned int index)
{ {
struct cpufreq_freqs freqs;
int ret;
freqs.old = policy->cur;
freqs.new = freq_table[index].frequency;
/* pre-change notification */
cpufreq_notify_transition(policy, &freqs, CPUFREQ_PRECHANGE);
/* update armss clk frequency */ /* update armss clk frequency */
ret = clk_set_rate(armss_clk, freqs.new * 1000); return clk_set_rate(armss_clk, freq_table[index].frequency * 1000);
if (ret) {
pr_err("dbx500-cpufreq: Failed to set armss_clk to %d Hz: error %d\n",
freqs.new * 1000, ret);
freqs.new = freqs.old;
}
/* post change notification */
cpufreq_notify_transition(policy, &freqs, CPUFREQ_POSTCHANGE);
return ret;
} }
static unsigned int dbx500_cpufreq_getspeed(unsigned int cpu) static unsigned int dbx500_cpufreq_getspeed(unsigned int cpu)
......
...@@ -107,15 +107,9 @@ static int eps_set_state(struct eps_cpu_data *centaur, ...@@ -107,15 +107,9 @@ static int eps_set_state(struct eps_cpu_data *centaur,
struct cpufreq_policy *policy, struct cpufreq_policy *policy,
u32 dest_state) u32 dest_state)
{ {
struct cpufreq_freqs freqs;
u32 lo, hi; u32 lo, hi;
int err = 0;
int i; int i;
freqs.old = eps_get(policy->cpu);
freqs.new = centaur->fsb * ((dest_state >> 8) & 0xff);
cpufreq_notify_transition(policy, &freqs, CPUFREQ_PRECHANGE);
/* Wait while CPU is busy */ /* Wait while CPU is busy */
rdmsr(MSR_IA32_PERF_STATUS, lo, hi); rdmsr(MSR_IA32_PERF_STATUS, lo, hi);
i = 0; i = 0;
...@@ -124,8 +118,7 @@ static int eps_set_state(struct eps_cpu_data *centaur, ...@@ -124,8 +118,7 @@ static int eps_set_state(struct eps_cpu_data *centaur,
rdmsr(MSR_IA32_PERF_STATUS, lo, hi); rdmsr(MSR_IA32_PERF_STATUS, lo, hi);
i++; i++;
if (unlikely(i > 64)) { if (unlikely(i > 64)) {
err = -ENODEV; return -ENODEV;
goto postchange;
} }
} }
/* Set new multiplier and voltage */ /* Set new multiplier and voltage */
...@@ -137,16 +130,10 @@ static int eps_set_state(struct eps_cpu_data *centaur, ...@@ -137,16 +130,10 @@ static int eps_set_state(struct eps_cpu_data *centaur,
rdmsr(MSR_IA32_PERF_STATUS, lo, hi); rdmsr(MSR_IA32_PERF_STATUS, lo, hi);
i++; i++;
if (unlikely(i > 64)) { if (unlikely(i > 64)) {
err = -ENODEV; return -ENODEV;
goto postchange;
} }
} while (lo & ((1 << 16) | (1 << 17))); } while (lo & ((1 << 16) | (1 << 17)));
/* Return current frequency */
postchange:
rdmsr(MSR_IA32_PERF_STATUS, lo, hi);
freqs.new = centaur->fsb * ((lo >> 8) & 0xff);
#ifdef DEBUG #ifdef DEBUG
{ {
u8 current_multiplier, current_voltage; u8 current_multiplier, current_voltage;
...@@ -161,11 +148,7 @@ static int eps_set_state(struct eps_cpu_data *centaur, ...@@ -161,11 +148,7 @@ static int eps_set_state(struct eps_cpu_data *centaur,
current_multiplier); current_multiplier);
} }
#endif #endif
if (err) return 0;
freqs.new = freqs.old;
cpufreq_notify_transition(policy, &freqs, CPUFREQ_POSTCHANGE);
return err;
} }
static int eps_target(struct cpufreq_policy *policy, unsigned int index) static int eps_target(struct cpufreq_policy *policy, unsigned int index)
......
...@@ -108,17 +108,6 @@ static unsigned int elanfreq_get_cpu_frequency(unsigned int cpu) ...@@ -108,17 +108,6 @@ static unsigned int elanfreq_get_cpu_frequency(unsigned int cpu)
static int elanfreq_target(struct cpufreq_policy *policy, static int elanfreq_target(struct cpufreq_policy *policy,
unsigned int state) unsigned int state)
{ {
struct cpufreq_freqs freqs;
freqs.old = elanfreq_get_cpu_frequency(0);
freqs.new = elan_multiplier[state].clock;
cpufreq_notify_transition(policy, &freqs, CPUFREQ_PRECHANGE);
printk(KERN_INFO "elanfreq: attempting to set frequency to %i kHz\n",
elan_multiplier[state].clock);
/* /*
* Access to the Elan's internal registers is indexed via * Access to the Elan's internal registers is indexed via
* 0x22: Chip Setup & Control Register Index Register (CSCI) * 0x22: Chip Setup & Control Register Index Register (CSCI)
...@@ -149,8 +138,6 @@ static int elanfreq_target(struct cpufreq_policy *policy, ...@@ -149,8 +138,6 @@ static int elanfreq_target(struct cpufreq_policy *policy,
udelay(10000); udelay(10000);
local_irq_enable(); local_irq_enable();
cpufreq_notify_transition(policy, &freqs, CPUFREQ_POSTCHANGE);
return 0; return 0;
} }
/* /*
......
...@@ -25,7 +25,6 @@ ...@@ -25,7 +25,6 @@
static struct exynos_dvfs_info *exynos_info; static struct exynos_dvfs_info *exynos_info;
static struct regulator *arm_regulator; static struct regulator *arm_regulator;
static struct cpufreq_freqs freqs;
static unsigned int locking_frequency; static unsigned int locking_frequency;
static bool frequency_locked; static bool frequency_locked;
...@@ -59,18 +58,18 @@ static int exynos_cpufreq_scale(unsigned int target_freq) ...@@ -59,18 +58,18 @@ static int exynos_cpufreq_scale(unsigned int target_freq)
struct cpufreq_policy *policy = cpufreq_cpu_get(0); struct cpufreq_policy *policy = cpufreq_cpu_get(0);
unsigned int arm_volt, safe_arm_volt = 0; unsigned int arm_volt, safe_arm_volt = 0;
unsigned int mpll_freq_khz = exynos_info->mpll_freq_khz; unsigned int mpll_freq_khz = exynos_info->mpll_freq_khz;
unsigned int old_freq;
int index, old_index; int index, old_index;
int ret = 0; int ret = 0;
freqs.old = policy->cur; old_freq = policy->cur;
freqs.new = target_freq;
/* /*
* The policy max have been changed so that we cannot get proper * The policy max have been changed so that we cannot get proper
* old_index with cpufreq_frequency_table_target(). Thus, ignore * old_index with cpufreq_frequency_table_target(). Thus, ignore
* policy and get the index from the raw freqeuncy table. * policy and get the index from the raw freqeuncy table.
*/ */
old_index = exynos_cpufreq_get_index(freqs.old); old_index = exynos_cpufreq_get_index(old_freq);
if (old_index < 0) { if (old_index < 0) {
ret = old_index; ret = old_index;
goto out; goto out;
...@@ -95,17 +94,14 @@ static int exynos_cpufreq_scale(unsigned int target_freq) ...@@ -95,17 +94,14 @@ static int exynos_cpufreq_scale(unsigned int target_freq)
} }
arm_volt = volt_table[index]; arm_volt = volt_table[index];
cpufreq_notify_transition(policy, &freqs, CPUFREQ_PRECHANGE);
/* When the new frequency is higher than current frequency */ /* When the new frequency is higher than current frequency */
if ((freqs.new > freqs.old) && !safe_arm_volt) { if ((target_freq > old_freq) && !safe_arm_volt) {
/* Firstly, voltage up to increase frequency */ /* Firstly, voltage up to increase frequency */
ret = regulator_set_voltage(arm_regulator, arm_volt, arm_volt); ret = regulator_set_voltage(arm_regulator, arm_volt, arm_volt);
if (ret) { if (ret) {
pr_err("%s: failed to set cpu voltage to %d\n", pr_err("%s: failed to set cpu voltage to %d\n",
__func__, arm_volt); __func__, arm_volt);
freqs.new = freqs.old; return ret;
goto post_notify;
} }
} }
...@@ -115,22 +111,15 @@ static int exynos_cpufreq_scale(unsigned int target_freq) ...@@ -115,22 +111,15 @@ static int exynos_cpufreq_scale(unsigned int target_freq)
if (ret) { if (ret) {
pr_err("%s: failed to set cpu voltage to %d\n", pr_err("%s: failed to set cpu voltage to %d\n",
__func__, safe_arm_volt); __func__, safe_arm_volt);
freqs.new = freqs.old; return ret;
goto post_notify;
} }
} }
exynos_info->set_freq(old_index, index); exynos_info->set_freq(old_index, index);
post_notify:
cpufreq_notify_transition(policy, &freqs, CPUFREQ_POSTCHANGE);
if (ret)
goto out;
/* When the new frequency is lower than current frequency */ /* When the new frequency is lower than current frequency */
if ((freqs.new < freqs.old) || if ((target_freq < old_freq) ||
((freqs.new > freqs.old) && safe_arm_volt)) { ((target_freq > old_freq) && safe_arm_volt)) {
/* down the voltage after frequency change */ /* down the voltage after frequency change */
ret = regulator_set_voltage(arm_regulator, arm_volt, ret = regulator_set_voltage(arm_regulator, arm_volt,
arm_volt); arm_volt);
...@@ -142,7 +131,6 @@ static int exynos_cpufreq_scale(unsigned int target_freq) ...@@ -142,7 +131,6 @@ static int exynos_cpufreq_scale(unsigned int target_freq)
} }
out: out:
cpufreq_cpu_put(policy); cpufreq_cpu_put(policy);
return ret; return ret;
......
...@@ -312,7 +312,7 @@ static int exynos_cpufreq_cpu_init(struct cpufreq_policy *policy) ...@@ -312,7 +312,7 @@ static int exynos_cpufreq_cpu_init(struct cpufreq_policy *policy)
} }
static struct cpufreq_driver exynos_driver = { static struct cpufreq_driver exynos_driver = {
.flags = CPUFREQ_STICKY, .flags = CPUFREQ_STICKY | CPUFREQ_ASYNC_NOTIFICATION,
.verify = cpufreq_generic_frequency_table_verify, .verify = cpufreq_generic_frequency_table_verify,
.target_index = exynos_target, .target_index = exynos_target,
.get = exynos_getspeed, .get = exynos_getspeed,
......
...@@ -141,7 +141,6 @@ processor_set_freq ( ...@@ -141,7 +141,6 @@ processor_set_freq (
{ {
int ret = 0; int ret = 0;
u32 value = 0; u32 value = 0;
struct cpufreq_freqs cpufreq_freqs;
cpumask_t saved_mask; cpumask_t saved_mask;
int retval; int retval;
...@@ -168,13 +167,6 @@ processor_set_freq ( ...@@ -168,13 +167,6 @@ processor_set_freq (
pr_debug("Transitioning from P%d to P%d\n", pr_debug("Transitioning from P%d to P%d\n",
data->acpi_data.state, state); data->acpi_data.state, state);
/* cpufreq frequency struct */
cpufreq_freqs.old = data->freq_table[data->acpi_data.state].frequency;
cpufreq_freqs.new = data->freq_table[state].frequency;
/* notify cpufreq */
cpufreq_notify_transition(policy, &cpufreq_freqs, CPUFREQ_PRECHANGE);
/* /*
* First we write the target state's 'control' value to the * First we write the target state's 'control' value to the
* control_register. * control_register.
...@@ -186,22 +178,11 @@ processor_set_freq ( ...@@ -186,22 +178,11 @@ processor_set_freq (
ret = processor_set_pstate(value); ret = processor_set_pstate(value);
if (ret) { if (ret) {
unsigned int tmp = cpufreq_freqs.new;
cpufreq_notify_transition(policy, &cpufreq_freqs,
CPUFREQ_POSTCHANGE);
cpufreq_freqs.new = cpufreq_freqs.old;
cpufreq_freqs.old = tmp;
cpufreq_notify_transition(policy, &cpufreq_freqs,
CPUFREQ_PRECHANGE);
cpufreq_notify_transition(policy, &cpufreq_freqs,
CPUFREQ_POSTCHANGE);
printk(KERN_WARNING "Transition failed with error %d\n", ret); printk(KERN_WARNING "Transition failed with error %d\n", ret);
retval = -ENODEV; retval = -ENODEV;
goto migrate_end; goto migrate_end;
} }
cpufreq_notify_transition(policy, &cpufreq_freqs, CPUFREQ_POSTCHANGE);
data->acpi_data.state = state; data->acpi_data.state = state;
retval = 0; retval = 0;
......
...@@ -42,14 +42,14 @@ static unsigned int imx6q_get_speed(unsigned int cpu) ...@@ -42,14 +42,14 @@ static unsigned int imx6q_get_speed(unsigned int cpu)
static int imx6q_set_target(struct cpufreq_policy *policy, unsigned int index) static int imx6q_set_target(struct cpufreq_policy *policy, unsigned int index)
{ {
struct cpufreq_freqs freqs;
struct dev_pm_opp *opp; struct dev_pm_opp *opp;
unsigned long freq_hz, volt, volt_old; unsigned long freq_hz, volt, volt_old;
unsigned int old_freq, new_freq;
int ret; int ret;
freqs.new = freq_table[index].frequency; new_freq = freq_table[index].frequency;
freq_hz = freqs.new * 1000; freq_hz = new_freq * 1000;
freqs.old = clk_get_rate(arm_clk) / 1000; old_freq = clk_get_rate(arm_clk) / 1000;
rcu_read_lock(); rcu_read_lock();
opp = dev_pm_opp_find_freq_ceil(cpu_dev, &freq_hz); opp = dev_pm_opp_find_freq_ceil(cpu_dev, &freq_hz);
...@@ -64,26 +64,23 @@ static int imx6q_set_target(struct cpufreq_policy *policy, unsigned int index) ...@@ -64,26 +64,23 @@ static int imx6q_set_target(struct cpufreq_policy *policy, unsigned int index)
volt_old = regulator_get_voltage(arm_reg); volt_old = regulator_get_voltage(arm_reg);
dev_dbg(cpu_dev, "%u MHz, %ld mV --> %u MHz, %ld mV\n", dev_dbg(cpu_dev, "%u MHz, %ld mV --> %u MHz, %ld mV\n",
freqs.old / 1000, volt_old / 1000, old_freq / 1000, volt_old / 1000,
freqs.new / 1000, volt / 1000); new_freq / 1000, volt / 1000);
cpufreq_notify_transition(policy, &freqs, CPUFREQ_PRECHANGE);
/* scaling up? scale voltage before frequency */ /* scaling up? scale voltage before frequency */
if (freqs.new > freqs.old) { if (new_freq > old_freq) {
ret = regulator_set_voltage_tol(arm_reg, volt, 0); ret = regulator_set_voltage_tol(arm_reg, volt, 0);
if (ret) { if (ret) {
dev_err(cpu_dev, dev_err(cpu_dev,
"failed to scale vddarm up: %d\n", ret); "failed to scale vddarm up: %d\n", ret);
freqs.new = freqs.old; return ret;
goto post_notify;
} }
/* /*
* Need to increase vddpu and vddsoc for safety * Need to increase vddpu and vddsoc for safety
* if we are about to run at 1.2 GHz. * if we are about to run at 1.2 GHz.
*/ */
if (freqs.new == FREQ_1P2_GHZ / 1000) { if (new_freq == FREQ_1P2_GHZ / 1000) {
regulator_set_voltage_tol(pu_reg, regulator_set_voltage_tol(pu_reg,
PU_SOC_VOLTAGE_HIGH, 0); PU_SOC_VOLTAGE_HIGH, 0);
regulator_set_voltage_tol(soc_reg, regulator_set_voltage_tol(soc_reg,
...@@ -103,21 +100,20 @@ static int imx6q_set_target(struct cpufreq_policy *policy, unsigned int index) ...@@ -103,21 +100,20 @@ static int imx6q_set_target(struct cpufreq_policy *policy, unsigned int index)
clk_set_parent(step_clk, pll2_pfd2_396m_clk); clk_set_parent(step_clk, pll2_pfd2_396m_clk);
clk_set_parent(pll1_sw_clk, step_clk); clk_set_parent(pll1_sw_clk, step_clk);
if (freq_hz > clk_get_rate(pll2_pfd2_396m_clk)) { if (freq_hz > clk_get_rate(pll2_pfd2_396m_clk)) {
clk_set_rate(pll1_sys_clk, freqs.new * 1000); clk_set_rate(pll1_sys_clk, new_freq * 1000);
clk_set_parent(pll1_sw_clk, pll1_sys_clk); clk_set_parent(pll1_sw_clk, pll1_sys_clk);
} }
/* Ensure the arm clock divider is what we expect */ /* Ensure the arm clock divider is what we expect */
ret = clk_set_rate(arm_clk, freqs.new * 1000); ret = clk_set_rate(arm_clk, new_freq * 1000);
if (ret) { if (ret) {
dev_err(cpu_dev, "failed to set clock rate: %d\n", ret); dev_err(cpu_dev, "failed to set clock rate: %d\n", ret);
regulator_set_voltage_tol(arm_reg, volt_old, 0); regulator_set_voltage_tol(arm_reg, volt_old, 0);
freqs.new = freqs.old; return ret;
goto post_notify;
} }
/* scaling down? scale voltage after frequency */ /* scaling down? scale voltage after frequency */
if (freqs.new < freqs.old) { if (new_freq < old_freq) {
ret = regulator_set_voltage_tol(arm_reg, volt, 0); ret = regulator_set_voltage_tol(arm_reg, volt, 0);
if (ret) { if (ret) {
dev_warn(cpu_dev, dev_warn(cpu_dev,
...@@ -125,7 +121,7 @@ static int imx6q_set_target(struct cpufreq_policy *policy, unsigned int index) ...@@ -125,7 +121,7 @@ static int imx6q_set_target(struct cpufreq_policy *policy, unsigned int index)
ret = 0; ret = 0;
} }
if (freqs.old == FREQ_1P2_GHZ / 1000) { if (old_freq == FREQ_1P2_GHZ / 1000) {
regulator_set_voltage_tol(pu_reg, regulator_set_voltage_tol(pu_reg,
PU_SOC_VOLTAGE_NORMAL, 0); PU_SOC_VOLTAGE_NORMAL, 0);
regulator_set_voltage_tol(soc_reg, regulator_set_voltage_tol(soc_reg,
...@@ -133,10 +129,7 @@ static int imx6q_set_target(struct cpufreq_policy *policy, unsigned int index) ...@@ -133,10 +129,7 @@ static int imx6q_set_target(struct cpufreq_policy *policy, unsigned int index)
} }
} }
post_notify: return 0;
cpufreq_notify_transition(policy, &freqs, CPUFREQ_POSTCHANGE);
return ret;
} }
static int imx6q_cpufreq_init(struct cpufreq_policy *policy) static int imx6q_cpufreq_init(struct cpufreq_policy *policy)
......
...@@ -25,6 +25,7 @@ ...@@ -25,6 +25,7 @@
#include <linux/types.h> #include <linux/types.h>
#include <linux/fs.h> #include <linux/fs.h>
#include <linux/debugfs.h> #include <linux/debugfs.h>
#include <linux/acpi.h>
#include <trace/events/power.h> #include <trace/events/power.h>
#include <asm/div64.h> #include <asm/div64.h>
...@@ -759,7 +760,7 @@ static int intel_pstate_msrs_not_valid(void) ...@@ -759,7 +760,7 @@ static int intel_pstate_msrs_not_valid(void)
return 0; return 0;
} }
void copy_pid_params(struct pstate_adjust_policy *policy) static void copy_pid_params(struct pstate_adjust_policy *policy)
{ {
pid_params.sample_rate_ms = policy->sample_rate_ms; pid_params.sample_rate_ms = policy->sample_rate_ms;
pid_params.p_gain_pct = policy->p_gain_pct; pid_params.p_gain_pct = policy->p_gain_pct;
...@@ -769,7 +770,7 @@ void copy_pid_params(struct pstate_adjust_policy *policy) ...@@ -769,7 +770,7 @@ void copy_pid_params(struct pstate_adjust_policy *policy)
pid_params.setpoint = policy->setpoint; pid_params.setpoint = policy->setpoint;
} }
void copy_cpu_funcs(struct pstate_funcs *funcs) static void copy_cpu_funcs(struct pstate_funcs *funcs)
{ {
pstate_funcs.get_max = funcs->get_max; pstate_funcs.get_max = funcs->get_max;
pstate_funcs.get_min = funcs->get_min; pstate_funcs.get_min = funcs->get_min;
...@@ -777,6 +778,72 @@ void copy_cpu_funcs(struct pstate_funcs *funcs) ...@@ -777,6 +778,72 @@ void copy_cpu_funcs(struct pstate_funcs *funcs)
pstate_funcs.set = funcs->set; pstate_funcs.set = funcs->set;
} }
#if IS_ENABLED(CONFIG_ACPI)
#include <acpi/processor.h>
static bool intel_pstate_no_acpi_pss(void)
{
int i;
for_each_possible_cpu(i) {
acpi_status status;
union acpi_object *pss;
struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL };
struct acpi_processor *pr = per_cpu(processors, i);
if (!pr)
continue;
status = acpi_evaluate_object(pr->handle, "_PSS", NULL, &buffer);
if (ACPI_FAILURE(status))
continue;
pss = buffer.pointer;
if (pss && pss->type == ACPI_TYPE_PACKAGE) {
kfree(pss);
return false;
}
kfree(pss);
}
return true;
}
struct hw_vendor_info {
u16 valid;
char oem_id[ACPI_OEM_ID_SIZE];
char oem_table_id[ACPI_OEM_TABLE_ID_SIZE];
};
/* Hardware vendor-specific info that has its own power management modes */
static struct hw_vendor_info vendor_info[] = {
{1, "HP ", "ProLiant"},
{0, "", ""},
};
static bool intel_pstate_platform_pwr_mgmt_exists(void)
{
struct acpi_table_header hdr;
struct hw_vendor_info *v_info;
if (acpi_disabled
|| ACPI_FAILURE(acpi_get_table_header(ACPI_SIG_FADT, 0, &hdr)))
return false;
for (v_info = vendor_info; v_info->valid; v_info++) {
if (!strncmp(hdr.oem_id, v_info->oem_id, ACPI_OEM_ID_SIZE)
&& !strncmp(hdr.oem_table_id, v_info->oem_table_id, ACPI_OEM_TABLE_ID_SIZE)
&& intel_pstate_no_acpi_pss())
return true;
}
return false;
}
#else /* CONFIG_ACPI not enabled */
static inline bool intel_pstate_platform_pwr_mgmt_exists(void) { return false; }
#endif /* CONFIG_ACPI */
static int __init intel_pstate_init(void) static int __init intel_pstate_init(void)
{ {
int cpu, rc = 0; int cpu, rc = 0;
...@@ -790,6 +857,13 @@ static int __init intel_pstate_init(void) ...@@ -790,6 +857,13 @@ static int __init intel_pstate_init(void)
if (!id) if (!id)
return -ENODEV; return -ENODEV;
/*
* The Intel pstate driver will be ignored if the platform
* firmware has its own power management modes.
*/
if (intel_pstate_platform_pwr_mgmt_exists())
return -ENODEV;
cpu_info = (struct cpu_defaults *)id->driver_data; cpu_info = (struct cpu_defaults *)id->driver_data;
copy_pid_params(&cpu_info->pid_policy); copy_pid_params(&cpu_info->pid_policy);
......
...@@ -58,48 +58,34 @@ static unsigned int kirkwood_cpufreq_get_cpu_frequency(unsigned int cpu) ...@@ -58,48 +58,34 @@ static unsigned int kirkwood_cpufreq_get_cpu_frequency(unsigned int cpu)
static int kirkwood_cpufreq_target(struct cpufreq_policy *policy, static int kirkwood_cpufreq_target(struct cpufreq_policy *policy,
unsigned int index) unsigned int index)
{ {
struct cpufreq_freqs freqs;
unsigned int state = kirkwood_freq_table[index].driver_data; unsigned int state = kirkwood_freq_table[index].driver_data;
unsigned long reg; unsigned long reg;
freqs.old = kirkwood_cpufreq_get_cpu_frequency(0); local_irq_disable();
freqs.new = kirkwood_freq_table[index].frequency;
cpufreq_notify_transition(policy, &freqs, CPUFREQ_PRECHANGE); /* Disable interrupts to the CPU */
reg = readl_relaxed(priv.base);
reg |= CPU_SW_INT_BLK;
writel_relaxed(reg, priv.base);
dev_dbg(priv.dev, "Attempting to set frequency to %i KHz\n", switch (state) {
kirkwood_freq_table[index].frequency); case STATE_CPU_FREQ:
dev_dbg(priv.dev, "old frequency was %i KHz\n", clk_disable(priv.powersave_clk);
kirkwood_cpufreq_get_cpu_frequency(0)); break;
case STATE_DDR_FREQ:
if (freqs.old != freqs.new) { clk_enable(priv.powersave_clk);
local_irq_disable(); break;
}
/* Disable interrupts to the CPU */
reg = readl_relaxed(priv.base);
reg |= CPU_SW_INT_BLK;
writel_relaxed(reg, priv.base);
switch (state) {
case STATE_CPU_FREQ:
clk_disable(priv.powersave_clk);
break;
case STATE_DDR_FREQ:
clk_enable(priv.powersave_clk);
break;
}
/* Wait-for-Interrupt, while the hardware changes frequency */ /* Wait-for-Interrupt, while the hardware changes frequency */
cpu_do_idle(); cpu_do_idle();
/* Enable interrupts to the CPU */ /* Enable interrupts to the CPU */
reg = readl_relaxed(priv.base); reg = readl_relaxed(priv.base);
reg &= ~CPU_SW_INT_BLK; reg &= ~CPU_SW_INT_BLK;
writel_relaxed(reg, priv.base); writel_relaxed(reg, priv.base);
local_irq_enable(); local_irq_enable();
}
cpufreq_notify_transition(policy, &freqs, CPUFREQ_POSTCHANGE);
return 0; return 0;
} }
......
...@@ -57,7 +57,6 @@ static int loongson2_cpufreq_target(struct cpufreq_policy *policy, ...@@ -57,7 +57,6 @@ static int loongson2_cpufreq_target(struct cpufreq_policy *policy,
{ {
unsigned int cpu = policy->cpu; unsigned int cpu = policy->cpu;
cpumask_t cpus_allowed; cpumask_t cpus_allowed;
struct cpufreq_freqs freqs;
unsigned int freq; unsigned int freq;
cpus_allowed = current->cpus_allowed; cpus_allowed = current->cpus_allowed;
...@@ -67,26 +66,11 @@ static int loongson2_cpufreq_target(struct cpufreq_policy *policy, ...@@ -67,26 +66,11 @@ static int loongson2_cpufreq_target(struct cpufreq_policy *policy,
((cpu_clock_freq / 1000) * ((cpu_clock_freq / 1000) *
loongson2_clockmod_table[index].driver_data) / 8; loongson2_clockmod_table[index].driver_data) / 8;
pr_debug("cpufreq: requested frequency %u Hz\n",
loongson2_clockmod_table[index].frequency * 1000);
freqs.old = loongson2_cpufreq_get(cpu);
freqs.new = freq;
freqs.flags = 0;
/* notifiers */
cpufreq_notify_transition(policy, &freqs, CPUFREQ_PRECHANGE);
set_cpus_allowed_ptr(current, &cpus_allowed); set_cpus_allowed_ptr(current, &cpus_allowed);
/* setting the cpu frequency */ /* setting the cpu frequency */
clk_set_rate(cpuclk, freq); clk_set_rate(cpuclk, freq);
/* notifiers */
cpufreq_notify_transition(policy, &freqs, CPUFREQ_POSTCHANGE);
pr_debug("cpufreq: set frequency %u kHz\n", freq);
return 0; return 0;
} }
......
...@@ -69,8 +69,6 @@ static struct cpufreq_frequency_table maple_cpu_freqs[] = { ...@@ -69,8 +69,6 @@ static struct cpufreq_frequency_table maple_cpu_freqs[] = {
*/ */
static int maple_pmode_cur; static int maple_pmode_cur;
static DEFINE_MUTEX(maple_switch_mutex);
static const u32 *maple_pmode_data; static const u32 *maple_pmode_data;
static int maple_pmode_max; static int maple_pmode_max;
...@@ -133,21 +131,7 @@ static int maple_scom_query_freq(void) ...@@ -133,21 +131,7 @@ static int maple_scom_query_freq(void)
static int maple_cpufreq_target(struct cpufreq_policy *policy, static int maple_cpufreq_target(struct cpufreq_policy *policy,
unsigned int index) unsigned int index)
{ {
struct cpufreq_freqs freqs; return maple_scom_switch_freq(index);
int rc;
mutex_lock(&maple_switch_mutex);
freqs.old = maple_cpu_freqs[maple_pmode_cur].frequency;
freqs.new = maple_cpu_freqs[index].frequency;
cpufreq_notify_transition(policy, &freqs, CPUFREQ_PRECHANGE);
rc = maple_scom_switch_freq(index);
cpufreq_notify_transition(policy, &freqs, CPUFREQ_POSTCHANGE);
mutex_unlock(&maple_switch_mutex);
return rc;
} }
static unsigned int maple_cpufreq_get_speed(unsigned int cpu) static unsigned int maple_cpufreq_get_speed(unsigned int cpu)
......
...@@ -53,15 +53,14 @@ static unsigned int omap_getspeed(unsigned int cpu) ...@@ -53,15 +53,14 @@ static unsigned int omap_getspeed(unsigned int cpu)
static int omap_target(struct cpufreq_policy *policy, unsigned int index) static int omap_target(struct cpufreq_policy *policy, unsigned int index)
{ {
int r, ret = 0;
struct cpufreq_freqs freqs;
struct dev_pm_opp *opp; struct dev_pm_opp *opp;
unsigned long freq, volt = 0, volt_old = 0, tol = 0; unsigned long freq, volt = 0, volt_old = 0, tol = 0;
unsigned int old_freq, new_freq;
freqs.old = omap_getspeed(policy->cpu); old_freq = omap_getspeed(policy->cpu);
freqs.new = freq_table[index].frequency; new_freq = freq_table[index].frequency;
freq = freqs.new * 1000; freq = new_freq * 1000;
ret = clk_round_rate(mpu_clk, freq); ret = clk_round_rate(mpu_clk, freq);
if (IS_ERR_VALUE(ret)) { if (IS_ERR_VALUE(ret)) {
dev_warn(mpu_dev, dev_warn(mpu_dev,
...@@ -77,7 +76,7 @@ static int omap_target(struct cpufreq_policy *policy, unsigned int index) ...@@ -77,7 +76,7 @@ static int omap_target(struct cpufreq_policy *policy, unsigned int index)
if (IS_ERR(opp)) { if (IS_ERR(opp)) {
rcu_read_unlock(); rcu_read_unlock();
dev_err(mpu_dev, "%s: unable to find MPU OPP for %d\n", dev_err(mpu_dev, "%s: unable to find MPU OPP for %d\n",
__func__, freqs.new); __func__, new_freq);
return -EINVAL; return -EINVAL;
} }
volt = dev_pm_opp_get_voltage(opp); volt = dev_pm_opp_get_voltage(opp);
...@@ -87,43 +86,32 @@ static int omap_target(struct cpufreq_policy *policy, unsigned int index) ...@@ -87,43 +86,32 @@ static int omap_target(struct cpufreq_policy *policy, unsigned int index)
} }
dev_dbg(mpu_dev, "cpufreq-omap: %u MHz, %ld mV --> %u MHz, %ld mV\n", dev_dbg(mpu_dev, "cpufreq-omap: %u MHz, %ld mV --> %u MHz, %ld mV\n",
freqs.old / 1000, volt_old ? volt_old / 1000 : -1, old_freq / 1000, volt_old ? volt_old / 1000 : -1,
freqs.new / 1000, volt ? volt / 1000 : -1); new_freq / 1000, volt ? volt / 1000 : -1);
/* notifiers */
cpufreq_notify_transition(policy, &freqs, CPUFREQ_PRECHANGE);
/* scaling up? scale voltage before frequency */ /* scaling up? scale voltage before frequency */
if (mpu_reg && (freqs.new > freqs.old)) { if (mpu_reg && (new_freq > old_freq)) {
r = regulator_set_voltage(mpu_reg, volt - tol, volt + tol); r = regulator_set_voltage(mpu_reg, volt - tol, volt + tol);
if (r < 0) { if (r < 0) {
dev_warn(mpu_dev, "%s: unable to scale voltage up.\n", dev_warn(mpu_dev, "%s: unable to scale voltage up.\n",
__func__); __func__);
freqs.new = freqs.old; return r;
goto done;
} }
} }
ret = clk_set_rate(mpu_clk, freqs.new * 1000); ret = clk_set_rate(mpu_clk, new_freq * 1000);
/* scaling down? scale voltage after frequency */ /* scaling down? scale voltage after frequency */
if (mpu_reg && (freqs.new < freqs.old)) { if (mpu_reg && (new_freq < old_freq)) {
r = regulator_set_voltage(mpu_reg, volt - tol, volt + tol); r = regulator_set_voltage(mpu_reg, volt - tol, volt + tol);
if (r < 0) { if (r < 0) {
dev_warn(mpu_dev, "%s: unable to scale voltage down.\n", dev_warn(mpu_dev, "%s: unable to scale voltage down.\n",
__func__); __func__);
ret = clk_set_rate(mpu_clk, freqs.old * 1000); clk_set_rate(mpu_clk, old_freq * 1000);
freqs.new = freqs.old; return r;
goto done;
} }
} }
freqs.new = omap_getspeed(policy->cpu);
done:
/* notifiers */
cpufreq_notify_transition(policy, &freqs, CPUFREQ_POSTCHANGE);
return ret; return ret;
} }
......
...@@ -107,15 +107,8 @@ static struct cpufreq_frequency_table p4clockmod_table[] = { ...@@ -107,15 +107,8 @@ static struct cpufreq_frequency_table p4clockmod_table[] = {
static int cpufreq_p4_target(struct cpufreq_policy *policy, unsigned int index) static int cpufreq_p4_target(struct cpufreq_policy *policy, unsigned int index)
{ {
struct cpufreq_freqs freqs;
int i; int i;
freqs.old = cpufreq_p4_get(policy->cpu);
freqs.new = stock_freq * p4clockmod_table[index].driver_data / 8;
/* notifiers */
cpufreq_notify_transition(policy, &freqs, CPUFREQ_PRECHANGE);
/* run on each logical CPU, /* run on each logical CPU,
* see section 13.15.3 of IA32 Intel Architecture Software * see section 13.15.3 of IA32 Intel Architecture Software
* Developer's Manual, Volume 3 * Developer's Manual, Volume 3
...@@ -123,9 +116,6 @@ static int cpufreq_p4_target(struct cpufreq_policy *policy, unsigned int index) ...@@ -123,9 +116,6 @@ static int cpufreq_p4_target(struct cpufreq_policy *policy, unsigned int index)
for_each_cpu(i, policy->cpus) for_each_cpu(i, policy->cpus)
cpufreq_p4_setdc(i, p4clockmod_table[index].driver_data); cpufreq_p4_setdc(i, p4clockmod_table[index].driver_data);
/* notifiers */
cpufreq_notify_transition(policy, &freqs, CPUFREQ_POSTCHANGE);
return 0; return 0;
} }
......
...@@ -51,8 +51,6 @@ ...@@ -51,8 +51,6 @@
static void __iomem *sdcpwr_mapbase; static void __iomem *sdcpwr_mapbase;
static void __iomem *sdcasr_mapbase; static void __iomem *sdcasr_mapbase;
static DEFINE_MUTEX(pas_switch_mutex);
/* Current astate, is used when waking up from power savings on /* Current astate, is used when waking up from power savings on
* one core, in case the other core has switched states during * one core, in case the other core has switched states during
* the idle time. * the idle time.
...@@ -242,15 +240,8 @@ static int pas_cpufreq_cpu_exit(struct cpufreq_policy *policy) ...@@ -242,15 +240,8 @@ static int pas_cpufreq_cpu_exit(struct cpufreq_policy *policy)
static int pas_cpufreq_target(struct cpufreq_policy *policy, static int pas_cpufreq_target(struct cpufreq_policy *policy,
unsigned int pas_astate_new) unsigned int pas_astate_new)
{ {
struct cpufreq_freqs freqs;
int i; int i;
freqs.old = policy->cur;
freqs.new = pas_freqs[pas_astate_new].frequency;
mutex_lock(&pas_switch_mutex);
cpufreq_notify_transition(policy, &freqs, CPUFREQ_PRECHANGE);
pr_debug("setting frequency for cpu %d to %d kHz, 1/%d of max frequency\n", pr_debug("setting frequency for cpu %d to %d kHz, 1/%d of max frequency\n",
policy->cpu, policy->cpu,
pas_freqs[pas_astate_new].frequency, pas_freqs[pas_astate_new].frequency,
...@@ -261,10 +252,7 @@ static int pas_cpufreq_target(struct cpufreq_policy *policy, ...@@ -261,10 +252,7 @@ static int pas_cpufreq_target(struct cpufreq_policy *policy,
for_each_online_cpu(i) for_each_online_cpu(i)
set_astate(i, pas_astate_new); set_astate(i, pas_astate_new);
cpufreq_notify_transition(policy, &freqs, CPUFREQ_POSTCHANGE); ppc_proc_freq = pas_freqs[pas_astate_new].frequency * 1000ul;
mutex_unlock(&pas_switch_mutex);
ppc_proc_freq = freqs.new * 1000ul;
return 0; return 0;
} }
......
...@@ -331,21 +331,11 @@ static int pmu_set_cpu_speed(int low_speed) ...@@ -331,21 +331,11 @@ static int pmu_set_cpu_speed(int low_speed)
return 0; return 0;
} }
static int do_set_cpu_speed(struct cpufreq_policy *policy, int speed_mode, static int do_set_cpu_speed(struct cpufreq_policy *policy, int speed_mode)
int notify)
{ {
struct cpufreq_freqs freqs;
unsigned long l3cr; unsigned long l3cr;
static unsigned long prev_l3cr; static unsigned long prev_l3cr;
freqs.old = cur_freq;
freqs.new = (speed_mode == CPUFREQ_HIGH) ? hi_freq : low_freq;
if (freqs.old == freqs.new)
return 0;
if (notify)
cpufreq_notify_transition(policy, &freqs, CPUFREQ_PRECHANGE);
if (speed_mode == CPUFREQ_LOW && if (speed_mode == CPUFREQ_LOW &&
cpu_has_feature(CPU_FTR_L3CR)) { cpu_has_feature(CPU_FTR_L3CR)) {
l3cr = _get_L3CR(); l3cr = _get_L3CR();
...@@ -361,8 +351,6 @@ static int do_set_cpu_speed(struct cpufreq_policy *policy, int speed_mode, ...@@ -361,8 +351,6 @@ static int do_set_cpu_speed(struct cpufreq_policy *policy, int speed_mode,
if ((prev_l3cr & L3CR_L3E) && l3cr != prev_l3cr) if ((prev_l3cr & L3CR_L3E) && l3cr != prev_l3cr)
_set_L3CR(prev_l3cr); _set_L3CR(prev_l3cr);
} }
if (notify)
cpufreq_notify_transition(policy, &freqs, CPUFREQ_POSTCHANGE);
cur_freq = (speed_mode == CPUFREQ_HIGH) ? hi_freq : low_freq; cur_freq = (speed_mode == CPUFREQ_HIGH) ? hi_freq : low_freq;
return 0; return 0;
...@@ -378,7 +366,7 @@ static int pmac_cpufreq_target( struct cpufreq_policy *policy, ...@@ -378,7 +366,7 @@ static int pmac_cpufreq_target( struct cpufreq_policy *policy,
{ {
int rc; int rc;
rc = do_set_cpu_speed(policy, index, 1); rc = do_set_cpu_speed(policy, index);
ppc_proc_freq = cur_freq * 1000ul; ppc_proc_freq = cur_freq * 1000ul;
return rc; return rc;
...@@ -420,7 +408,7 @@ static int pmac_cpufreq_suspend(struct cpufreq_policy *policy) ...@@ -420,7 +408,7 @@ static int pmac_cpufreq_suspend(struct cpufreq_policy *policy)
no_schedule = 1; no_schedule = 1;
sleep_freq = cur_freq; sleep_freq = cur_freq;
if (cur_freq == low_freq && !is_pmu_based) if (cur_freq == low_freq && !is_pmu_based)
do_set_cpu_speed(policy, CPUFREQ_HIGH, 0); do_set_cpu_speed(policy, CPUFREQ_HIGH);
return 0; return 0;
} }
...@@ -437,7 +425,7 @@ static int pmac_cpufreq_resume(struct cpufreq_policy *policy) ...@@ -437,7 +425,7 @@ static int pmac_cpufreq_resume(struct cpufreq_policy *policy)
* probably high speed due to our suspend() routine * probably high speed due to our suspend() routine
*/ */
do_set_cpu_speed(policy, sleep_freq == low_freq ? do_set_cpu_speed(policy, sleep_freq == low_freq ?
CPUFREQ_LOW : CPUFREQ_HIGH, 0); CPUFREQ_LOW : CPUFREQ_HIGH);
ppc_proc_freq = cur_freq * 1000ul; ppc_proc_freq = cur_freq * 1000ul;
......
...@@ -79,8 +79,6 @@ static void (*g5_switch_volt)(int speed_mode); ...@@ -79,8 +79,6 @@ static void (*g5_switch_volt)(int speed_mode);
static int (*g5_switch_freq)(int speed_mode); static int (*g5_switch_freq)(int speed_mode);
static int (*g5_query_freq)(void); static int (*g5_query_freq)(void);
static DEFINE_MUTEX(g5_switch_mutex);
static unsigned long transition_latency; static unsigned long transition_latency;
#ifdef CONFIG_PMAC_SMU #ifdef CONFIG_PMAC_SMU
...@@ -314,21 +312,7 @@ static int g5_pfunc_query_freq(void) ...@@ -314,21 +312,7 @@ static int g5_pfunc_query_freq(void)
static int g5_cpufreq_target(struct cpufreq_policy *policy, unsigned int index) static int g5_cpufreq_target(struct cpufreq_policy *policy, unsigned int index)
{ {
struct cpufreq_freqs freqs; return g5_switch_freq(index);
int rc;
mutex_lock(&g5_switch_mutex);
freqs.old = g5_cpu_freqs[g5_pmode_cur].frequency;
freqs.new = g5_cpu_freqs[index].frequency;
cpufreq_notify_transition(policy, &freqs, CPUFREQ_PRECHANGE);
rc = g5_switch_freq(index);
cpufreq_notify_transition(policy, &freqs, CPUFREQ_POSTCHANGE);
mutex_unlock(&g5_switch_mutex);
return rc;
} }
static unsigned int g5_cpufreq_get_speed(unsigned int cpu) static unsigned int g5_cpufreq_get_speed(unsigned int cpu)
......
...@@ -1204,6 +1204,7 @@ static unsigned int powernowk8_get(unsigned int cpu) ...@@ -1204,6 +1204,7 @@ static unsigned int powernowk8_get(unsigned int cpu)
} }
static struct cpufreq_driver cpufreq_amd64_driver = { static struct cpufreq_driver cpufreq_amd64_driver = {
.flags = CPUFREQ_ASYNC_NOTIFICATION,
.verify = cpufreq_generic_frequency_table_verify, .verify = cpufreq_generic_frequency_table_verify,
.target_index = powernowk8_target, .target_index = powernowk8_target,
.bios_limit = acpi_processor_get_bios_limit, .bios_limit = acpi_processor_get_bios_limit,
......
...@@ -69,8 +69,6 @@ static const struct soc_data sdata[] = { ...@@ -69,8 +69,6 @@ static const struct soc_data sdata[] = {
static u32 min_cpufreq; static u32 min_cpufreq;
static const u32 *fmask; static const u32 *fmask;
/* serialize frequency changes */
static DEFINE_MUTEX(cpufreq_lock);
static DEFINE_PER_CPU(struct cpu_data *, cpu_data); static DEFINE_PER_CPU(struct cpu_data *, cpu_data);
/* cpumask in a cluster */ /* cpumask in a cluster */
...@@ -253,26 +251,11 @@ static int __exit corenet_cpufreq_cpu_exit(struct cpufreq_policy *policy) ...@@ -253,26 +251,11 @@ static int __exit corenet_cpufreq_cpu_exit(struct cpufreq_policy *policy)
static int corenet_cpufreq_target(struct cpufreq_policy *policy, static int corenet_cpufreq_target(struct cpufreq_policy *policy,
unsigned int index) unsigned int index)
{ {
struct cpufreq_freqs freqs;
struct clk *parent; struct clk *parent;
int ret;
struct cpu_data *data = per_cpu(cpu_data, policy->cpu); struct cpu_data *data = per_cpu(cpu_data, policy->cpu);
freqs.old = policy->cur;
freqs.new = data->table[index].frequency;
mutex_lock(&cpufreq_lock);
cpufreq_notify_transition(policy, &freqs, CPUFREQ_PRECHANGE);
parent = of_clk_get(data->parent, data->table[index].driver_data); parent = of_clk_get(data->parent, data->table[index].driver_data);
ret = clk_set_parent(data->clk, parent); return clk_set_parent(data->clk, parent);
if (ret)
freqs.new = freqs.old;
cpufreq_notify_transition(policy, &freqs, CPUFREQ_POSTCHANGE);
mutex_unlock(&cpufreq_lock);
return ret;
} }
static struct cpufreq_driver ppc_corenet_cpufreq_driver = { static struct cpufreq_driver ppc_corenet_cpufreq_driver = {
......
...@@ -30,9 +30,6 @@ ...@@ -30,9 +30,6 @@
#include "ppc_cbe_cpufreq.h" #include "ppc_cbe_cpufreq.h"
static DEFINE_MUTEX(cbe_switch_mutex);
/* the CBE supports an 8 step frequency scaling */ /* the CBE supports an 8 step frequency scaling */
static struct cpufreq_frequency_table cbe_freqs[] = { static struct cpufreq_frequency_table cbe_freqs[] = {
{1, 0}, {1, 0},
...@@ -131,27 +128,13 @@ static int cbe_cpufreq_cpu_init(struct cpufreq_policy *policy) ...@@ -131,27 +128,13 @@ static int cbe_cpufreq_cpu_init(struct cpufreq_policy *policy)
static int cbe_cpufreq_target(struct cpufreq_policy *policy, static int cbe_cpufreq_target(struct cpufreq_policy *policy,
unsigned int cbe_pmode_new) unsigned int cbe_pmode_new)
{ {
int rc;
struct cpufreq_freqs freqs;
freqs.old = policy->cur;
freqs.new = cbe_freqs[cbe_pmode_new].frequency;
mutex_lock(&cbe_switch_mutex);
cpufreq_notify_transition(policy, &freqs, CPUFREQ_PRECHANGE);
pr_debug("setting frequency for cpu %d to %d kHz, " \ pr_debug("setting frequency for cpu %d to %d kHz, " \
"1/%d of max frequency\n", "1/%d of max frequency\n",
policy->cpu, policy->cpu,
cbe_freqs[cbe_pmode_new].frequency, cbe_freqs[cbe_pmode_new].frequency,
cbe_freqs[cbe_pmode_new].driver_data); cbe_freqs[cbe_pmode_new].driver_data);
rc = set_pmode(policy->cpu, cbe_pmode_new); return set_pmode(policy->cpu, cbe_pmode_new);
cpufreq_notify_transition(policy, &freqs, CPUFREQ_POSTCHANGE);
mutex_unlock(&cbe_switch_mutex);
return rc;
} }
static struct cpufreq_driver cbe_cpufreq_driver = { static struct cpufreq_driver cbe_cpufreq_driver = {
......
...@@ -271,7 +271,6 @@ static int pxa_set_target(struct cpufreq_policy *policy, unsigned int idx) ...@@ -271,7 +271,6 @@ 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;
pxa_freqs_t *pxa_freq_settings; pxa_freqs_t *pxa_freq_settings;
struct cpufreq_freqs freqs;
unsigned long flags; unsigned long flags;
unsigned int new_freq_cpu, new_freq_mem; unsigned int new_freq_cpu, new_freq_mem;
unsigned int unused, preset_mdrefr, postset_mdrefr, cclkcfg; unsigned int unused, preset_mdrefr, postset_mdrefr, cclkcfg;
...@@ -282,24 +281,17 @@ static int pxa_set_target(struct cpufreq_policy *policy, unsigned int idx) ...@@ -282,24 +281,17 @@ static int pxa_set_target(struct cpufreq_policy *policy, unsigned int idx)
new_freq_cpu = pxa_freq_settings[idx].khz; new_freq_cpu = pxa_freq_settings[idx].khz;
new_freq_mem = pxa_freq_settings[idx].membus; new_freq_mem = pxa_freq_settings[idx].membus;
freqs.old = policy->cur;
freqs.new = new_freq_cpu;
if (freq_debug) if (freq_debug)
pr_debug("Changing CPU frequency to %d Mhz, (SDRAM %d Mhz)\n", pr_debug("Changing CPU frequency to %d Mhz, (SDRAM %d Mhz)\n",
freqs.new / 1000, (pxa_freq_settings[idx].div2) ? new_freq_cpu / 1000, (pxa_freq_settings[idx].div2) ?
(new_freq_mem / 2000) : (new_freq_mem / 1000)); (new_freq_mem / 2000) : (new_freq_mem / 1000));
if (vcc_core && freqs.new > freqs.old) 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]);
if (ret) if (ret)
return ret; return ret;
/* }
* Tell everyone what we're about to do...
* you should add a notify client with any platform specific
* Vcc changing capability
*/
cpufreq_notify_transition(policy, &freqs, CPUFREQ_PRECHANGE);
/* Calculate the next MDREFR. If we're slowing down the SDRAM clock /* Calculate the next MDREFR. If we're slowing down the SDRAM clock
* we need to preset the smaller DRI before the change. If we're * we need to preset the smaller DRI before the change. If we're
...@@ -349,13 +341,6 @@ static int pxa_set_target(struct cpufreq_policy *policy, unsigned int idx) ...@@ -349,13 +341,6 @@ static int pxa_set_target(struct cpufreq_policy *policy, unsigned int idx)
: "r4", "r5"); : "r4", "r5");
local_irq_restore(flags); local_irq_restore(flags);
/*
* Tell everyone what we've just done...
* you should add a notify client with any platform specific
* SDRAM refresh timer adjustments
*/
cpufreq_notify_transition(policy, &freqs, CPUFREQ_POSTCHANGE);
/* /*
* 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
* change succeeded. The voltage reduction is not a critical failure, * change succeeded. The voltage reduction is not a critical failure,
...@@ -365,7 +350,7 @@ static int pxa_set_target(struct cpufreq_policy *policy, unsigned int idx) ...@@ -365,7 +350,7 @@ static int pxa_set_target(struct cpufreq_policy *policy, unsigned int idx)
* bug is triggered (seems a deadlock). Should anybody find out where, * bug is triggered (seems a deadlock). Should anybody find out where,
* the "return 0" should become a "return ret". * the "return 0" should become a "return ret".
*/ */
if (vcc_core && freqs.new < freqs.old) 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]);
return 0; return 0;
......
...@@ -158,7 +158,6 @@ static unsigned int pxa3xx_cpufreq_get(unsigned int cpu) ...@@ -158,7 +158,6 @@ static unsigned int pxa3xx_cpufreq_get(unsigned int cpu)
static int pxa3xx_cpufreq_set(struct cpufreq_policy *policy, unsigned int index) static int pxa3xx_cpufreq_set(struct cpufreq_policy *policy, unsigned int index)
{ {
struct pxa3xx_freq_info *next; struct pxa3xx_freq_info *next;
struct cpufreq_freqs freqs;
unsigned long flags; unsigned long flags;
if (policy->cpu != 0) if (policy->cpu != 0)
...@@ -166,22 +165,11 @@ static int pxa3xx_cpufreq_set(struct cpufreq_policy *policy, unsigned int index) ...@@ -166,22 +165,11 @@ static int pxa3xx_cpufreq_set(struct cpufreq_policy *policy, unsigned int index)
next = &pxa3xx_freqs[index]; next = &pxa3xx_freqs[index];
freqs.old = policy->cur;
freqs.new = next->cpufreq_mhz * 1000;
pr_debug("CPU frequency from %d MHz to %d MHz%s\n",
freqs.old / 1000, freqs.new / 1000,
(freqs.old == freqs.new) ? " (skipped)" : "");
cpufreq_notify_transition(policy, &freqs, CPUFREQ_PRECHANGE);
local_irq_save(flags); local_irq_save(flags);
__update_core_freq(next); __update_core_freq(next);
__update_bus_freq(next); __update_bus_freq(next);
local_irq_restore(flags); local_irq_restore(flags);
cpufreq_notify_transition(policy, &freqs, CPUFREQ_POSTCHANGE);
return 0; return 0;
} }
......
...@@ -220,7 +220,7 @@ static int s3c2416_cpufreq_set_target(struct cpufreq_policy *policy, ...@@ -220,7 +220,7 @@ static int s3c2416_cpufreq_set_target(struct cpufreq_policy *policy,
unsigned int index) unsigned int index)
{ {
struct s3c2416_data *s3c_freq = &s3c2416_cpufreq; struct s3c2416_data *s3c_freq = &s3c2416_cpufreq;
struct cpufreq_freqs freqs; unsigned int new_freq;
int idx, ret, to_dvs = 0; int idx, ret, to_dvs = 0;
mutex_lock(&cpufreq_lock); mutex_lock(&cpufreq_lock);
...@@ -237,25 +237,14 @@ static int s3c2416_cpufreq_set_target(struct cpufreq_policy *policy, ...@@ -237,25 +237,14 @@ static int s3c2416_cpufreq_set_target(struct cpufreq_policy *policy,
goto out; goto out;
} }
freqs.flags = 0;
freqs.old = s3c_freq->is_dvs ? FREQ_DVS
: clk_get_rate(s3c_freq->armclk) / 1000;
/* When leavin dvs mode, always switch the armdiv to the hclk rate /* When leavin dvs mode, always switch the armdiv to the hclk rate
* The S3C2416 has stability issues when switching directly to * The S3C2416 has stability issues when switching directly to
* higher frequencies. * higher frequencies.
*/ */
freqs.new = (s3c_freq->is_dvs && !to_dvs) new_freq = (s3c_freq->is_dvs && !to_dvs)
? clk_get_rate(s3c_freq->hclk) / 1000 ? clk_get_rate(s3c_freq->hclk) / 1000
: s3c_freq->freq_table[index].frequency; : s3c_freq->freq_table[index].frequency;
pr_debug("cpufreq: Transition %d-%dkHz\n", freqs.old, freqs.new);
if (!to_dvs && freqs.old == freqs.new)
goto out;
cpufreq_notify_transition(policy, &freqs, CPUFREQ_PRECHANGE);
if (to_dvs) { if (to_dvs) {
pr_debug("cpufreq: enter dvs\n"); pr_debug("cpufreq: enter dvs\n");
ret = s3c2416_cpufreq_enter_dvs(s3c_freq, idx); ret = s3c2416_cpufreq_enter_dvs(s3c_freq, idx);
...@@ -263,12 +252,10 @@ static int s3c2416_cpufreq_set_target(struct cpufreq_policy *policy, ...@@ -263,12 +252,10 @@ static int s3c2416_cpufreq_set_target(struct cpufreq_policy *policy,
pr_debug("cpufreq: leave dvs\n"); pr_debug("cpufreq: leave dvs\n");
ret = s3c2416_cpufreq_leave_dvs(s3c_freq, idx); ret = s3c2416_cpufreq_leave_dvs(s3c_freq, idx);
} else { } else {
pr_debug("cpufreq: change armdiv to %dkHz\n", freqs.new); pr_debug("cpufreq: change armdiv to %dkHz\n", new_freq);
ret = s3c2416_cpufreq_set_armdiv(s3c_freq, freqs.new); ret = s3c2416_cpufreq_set_armdiv(s3c_freq, new_freq);
} }
cpufreq_notify_transition(policy, &freqs, CPUFREQ_POSTCHANGE);
out: out:
mutex_unlock(&cpufreq_lock); mutex_unlock(&cpufreq_lock);
......
...@@ -65,54 +65,46 @@ static unsigned int s3c64xx_cpufreq_get_speed(unsigned int cpu) ...@@ -65,54 +65,46 @@ static unsigned int s3c64xx_cpufreq_get_speed(unsigned int cpu)
static int s3c64xx_cpufreq_set_target(struct cpufreq_policy *policy, static int s3c64xx_cpufreq_set_target(struct cpufreq_policy *policy,
unsigned int index) unsigned int index)
{ {
int ret;
struct cpufreq_freqs freqs;
struct s3c64xx_dvfs *dvfs; struct s3c64xx_dvfs *dvfs;
unsigned int old_freq, new_freq;
int ret;
freqs.old = clk_get_rate(armclk) / 1000; old_freq = clk_get_rate(armclk) / 1000;
freqs.new = s3c64xx_freq_table[index].frequency; new_freq = s3c64xx_freq_table[index].frequency;
freqs.flags = 0;
dvfs = &s3c64xx_dvfs_table[s3c64xx_freq_table[index].driver_data]; dvfs = &s3c64xx_dvfs_table[s3c64xx_freq_table[index].driver_data];
pr_debug("Transition %d-%dkHz\n", freqs.old, freqs.new);
cpufreq_notify_transition(policy, &freqs, CPUFREQ_PRECHANGE);
#ifdef CONFIG_REGULATOR #ifdef CONFIG_REGULATOR
if (vddarm && freqs.new > freqs.old) { if (vddarm && new_freq > old_freq) {
ret = regulator_set_voltage(vddarm, ret = regulator_set_voltage(vddarm,
dvfs->vddarm_min, dvfs->vddarm_min,
dvfs->vddarm_max); dvfs->vddarm_max);
if (ret != 0) { if (ret != 0) {
pr_err("Failed to set VDDARM for %dkHz: %d\n", pr_err("Failed to set VDDARM for %dkHz: %d\n",
freqs.new, ret); new_freq, ret);
freqs.new = freqs.old; return ret;
goto post_notify;
} }
} }
#endif #endif
ret = clk_set_rate(armclk, freqs.new * 1000); ret = clk_set_rate(armclk, new_freq * 1000);
if (ret < 0) { if (ret < 0) {
pr_err("Failed to set rate %dkHz: %d\n", pr_err("Failed to set rate %dkHz: %d\n",
freqs.new, ret); new_freq, ret);
freqs.new = freqs.old; return ret;
} }
post_notify:
cpufreq_notify_transition(policy, &freqs, CPUFREQ_POSTCHANGE);
if (ret)
goto err;
#ifdef CONFIG_REGULATOR #ifdef CONFIG_REGULATOR
if (vddarm && freqs.new < freqs.old) { if (vddarm && new_freq < old_freq) {
ret = regulator_set_voltage(vddarm, ret = regulator_set_voltage(vddarm,
dvfs->vddarm_min, dvfs->vddarm_min,
dvfs->vddarm_max); dvfs->vddarm_max);
if (ret != 0) { if (ret != 0) {
pr_err("Failed to set VDDARM for %dkHz: %d\n", pr_err("Failed to set VDDARM for %dkHz: %d\n",
freqs.new, ret); new_freq, ret);
goto err_clk; if (clk_set_rate(armclk, old_freq * 1000) < 0)
pr_err("Failed to restore original clock rate\n");
return ret;
} }
} }
#endif #endif
...@@ -121,14 +113,6 @@ static int s3c64xx_cpufreq_set_target(struct cpufreq_policy *policy, ...@@ -121,14 +113,6 @@ static int s3c64xx_cpufreq_set_target(struct cpufreq_policy *policy,
clk_get_rate(armclk) / 1000); clk_get_rate(armclk) / 1000);
return 0; return 0;
err_clk:
if (clk_set_rate(armclk, freqs.old * 1000) < 0)
pr_err("Failed to restore original clock rate\n");
err:
cpufreq_notify_transition(policy, &freqs, CPUFREQ_POSTCHANGE);
return ret;
} }
#ifdef CONFIG_REGULATOR #ifdef CONFIG_REGULATOR
......
...@@ -26,7 +26,6 @@ ...@@ -26,7 +26,6 @@
static struct clk *cpu_clk; static struct clk *cpu_clk;
static struct clk *dmc0_clk; static struct clk *dmc0_clk;
static struct clk *dmc1_clk; static struct clk *dmc1_clk;
static struct cpufreq_freqs freqs;
static DEFINE_MUTEX(set_freq_lock); static DEFINE_MUTEX(set_freq_lock);
/* APLL M,P,S values for 1G/800Mhz */ /* APLL M,P,S values for 1G/800Mhz */
...@@ -179,6 +178,7 @@ static int s5pv210_target(struct cpufreq_policy *policy, unsigned int index) ...@@ -179,6 +178,7 @@ static int s5pv210_target(struct cpufreq_policy *policy, unsigned int index)
unsigned int priv_index; unsigned int priv_index;
unsigned int pll_changing = 0; unsigned int pll_changing = 0;
unsigned int bus_speed_changing = 0; unsigned int bus_speed_changing = 0;
unsigned int old_freq, new_freq;
int arm_volt, int_volt; int arm_volt, int_volt;
int ret = 0; int ret = 0;
...@@ -193,12 +193,12 @@ static int s5pv210_target(struct cpufreq_policy *policy, unsigned int index) ...@@ -193,12 +193,12 @@ static int s5pv210_target(struct cpufreq_policy *policy, unsigned int index)
goto exit; goto exit;
} }
freqs.old = s5pv210_getspeed(0); old_freq = s5pv210_getspeed(0);
freqs.new = s5pv210_freq_table[index].frequency; new_freq = s5pv210_freq_table[index].frequency;
/* Finding current running level index */ /* Finding current running level index */
if (cpufreq_frequency_table_target(policy, s5pv210_freq_table, if (cpufreq_frequency_table_target(policy, s5pv210_freq_table,
freqs.old, CPUFREQ_RELATION_H, old_freq, CPUFREQ_RELATION_H,
&priv_index)) { &priv_index)) {
ret = -EINVAL; ret = -EINVAL;
goto exit; goto exit;
...@@ -207,7 +207,7 @@ static int s5pv210_target(struct cpufreq_policy *policy, unsigned int index) ...@@ -207,7 +207,7 @@ static int s5pv210_target(struct cpufreq_policy *policy, unsigned int index)
arm_volt = dvs_conf[index].arm_volt; arm_volt = dvs_conf[index].arm_volt;
int_volt = dvs_conf[index].int_volt; int_volt = dvs_conf[index].int_volt;
if (freqs.new > freqs.old) { if (new_freq > old_freq) {
ret = regulator_set_voltage(arm_regulator, ret = regulator_set_voltage(arm_regulator,
arm_volt, arm_volt_max); arm_volt, arm_volt_max);
if (ret) if (ret)
...@@ -219,8 +219,6 @@ static int s5pv210_target(struct cpufreq_policy *policy, unsigned int index) ...@@ -219,8 +219,6 @@ static int s5pv210_target(struct cpufreq_policy *policy, unsigned int index)
goto exit; goto exit;
} }
cpufreq_notify_transition(policy, &freqs, CPUFREQ_PRECHANGE);
/* Check if there need to change PLL */ /* Check if there need to change PLL */
if ((index == L0) || (priv_index == L0)) if ((index == L0) || (priv_index == L0))
pll_changing = 1; pll_changing = 1;
...@@ -431,9 +429,7 @@ static int s5pv210_target(struct cpufreq_policy *policy, unsigned int index) ...@@ -431,9 +429,7 @@ static int s5pv210_target(struct cpufreq_policy *policy, unsigned int index)
} }
} }
cpufreq_notify_transition(policy, &freqs, CPUFREQ_POSTCHANGE); if (new_freq < old_freq) {
if (freqs.new < freqs.old) {
regulator_set_voltage(int_regulator, regulator_set_voltage(int_regulator,
int_volt, int_volt_max); int_volt, int_volt_max);
......
...@@ -180,22 +180,17 @@ static void sa1100_update_dram_timings(int current_speed, int new_speed) ...@@ -180,22 +180,17 @@ static void sa1100_update_dram_timings(int current_speed, int new_speed)
static int sa1100_target(struct cpufreq_policy *policy, unsigned int ppcr) static int sa1100_target(struct cpufreq_policy *policy, unsigned int ppcr)
{ {
unsigned int cur = sa11x0_getspeed(0); unsigned int cur = sa11x0_getspeed(0);
struct cpufreq_freqs freqs; unsigned int new_freq;
freqs.old = cur; new_freq = sa11x0_freq_table[ppcr].frequency;
freqs.new = sa11x0_freq_table[ppcr].frequency;
cpufreq_notify_transition(policy, &freqs, CPUFREQ_PRECHANGE); if (new_freq > cur)
sa1100_update_dram_timings(cur, new_freq);
if (freqs.new > cur)
sa1100_update_dram_timings(cur, freqs.new);
PPCR = ppcr; PPCR = ppcr;
if (freqs.new < cur) if (new_freq < cur)
sa1100_update_dram_timings(cur, freqs.new); sa1100_update_dram_timings(cur, new_freq);
cpufreq_notify_transition(policy, &freqs, CPUFREQ_POSTCHANGE);
return 0; return 0;
} }
......
...@@ -232,15 +232,11 @@ sdram_update_refresh(u_int cpu_khz, struct sdram_params *sdram) ...@@ -232,15 +232,11 @@ sdram_update_refresh(u_int cpu_khz, struct sdram_params *sdram)
static int sa1110_target(struct cpufreq_policy *policy, unsigned int ppcr) static int sa1110_target(struct cpufreq_policy *policy, unsigned int ppcr)
{ {
struct sdram_params *sdram = &sdram_params; struct sdram_params *sdram = &sdram_params;
struct cpufreq_freqs freqs;
struct sdram_info sd; struct sdram_info sd;
unsigned long flags; unsigned long flags;
unsigned int unused; unsigned int unused;
freqs.old = sa11x0_getspeed(0); sdram_calculate_timing(&sd, sa11x0_freq_table[ppcr].frequency, sdram);
freqs.new = sa11x0_freq_table[ppcr].frequency;
sdram_calculate_timing(&sd, freqs.new, sdram);
#if 0 #if 0
/* /*
...@@ -259,8 +255,6 @@ static int sa1110_target(struct cpufreq_policy *policy, unsigned int ppcr) ...@@ -259,8 +255,6 @@ static int sa1110_target(struct cpufreq_policy *policy, unsigned int ppcr)
sd.mdcas[2] = 0xaaaaaaaa; sd.mdcas[2] = 0xaaaaaaaa;
#endif #endif
cpufreq_notify_transition(policy, &freqs, CPUFREQ_PRECHANGE);
/* /*
* The clock could be going away for some time. Set the SDRAMs * The clock could be going away for some time. Set the SDRAMs
* to refresh rapidly (every 64 memory clock cycles). To get * to refresh rapidly (every 64 memory clock cycles). To get
...@@ -305,9 +299,7 @@ static int sa1110_target(struct cpufreq_policy *policy, unsigned int ppcr) ...@@ -305,9 +299,7 @@ static int sa1110_target(struct cpufreq_policy *policy, unsigned int ppcr)
/* /*
* Now, return the SDRAM refresh back to normal. * Now, return the SDRAM refresh back to normal.
*/ */
sdram_update_refresh(freqs.new, sdram); sdram_update_refresh(sa11x0_freq_table[ppcr].frequency, sdram);
cpufreq_notify_transition(policy, &freqs, CPUFREQ_POSTCHANGE);
return 0; return 0;
} }
......
...@@ -56,17 +56,8 @@ static unsigned int sc520_freq_get_cpu_frequency(unsigned int cpu) ...@@ -56,17 +56,8 @@ static unsigned int sc520_freq_get_cpu_frequency(unsigned int cpu)
static int sc520_freq_target(struct cpufreq_policy *policy, unsigned int state) static int sc520_freq_target(struct cpufreq_policy *policy, unsigned int state)
{ {
struct cpufreq_freqs freqs;
u8 clockspeed_reg; u8 clockspeed_reg;
freqs.old = sc520_freq_get_cpu_frequency(0);
freqs.new = sc520_freq_table[state].frequency;
cpufreq_notify_transition(policy, &freqs, CPUFREQ_PRECHANGE);
pr_debug("attempting to set frequency to %i kHz\n",
sc520_freq_table[state].frequency);
local_irq_disable(); local_irq_disable();
clockspeed_reg = *cpuctl & ~0x03; clockspeed_reg = *cpuctl & ~0x03;
...@@ -74,8 +65,6 @@ static int sc520_freq_target(struct cpufreq_policy *policy, unsigned int state) ...@@ -74,8 +65,6 @@ static int sc520_freq_target(struct cpufreq_policy *policy, unsigned int state)
local_irq_enable(); local_irq_enable();
cpufreq_notify_transition(policy, &freqs, CPUFREQ_POSTCHANGE);
return 0; return 0;
} }
......
...@@ -251,7 +251,6 @@ static int us2e_freq_target(struct cpufreq_policy *policy, unsigned int index) ...@@ -251,7 +251,6 @@ static int us2e_freq_target(struct cpufreq_policy *policy, unsigned int index)
unsigned long new_bits, new_freq; unsigned long new_bits, new_freq;
unsigned long clock_tick, divisor, old_divisor, estar; unsigned long clock_tick, divisor, old_divisor, estar;
cpumask_t cpus_allowed; cpumask_t cpus_allowed;
struct cpufreq_freqs freqs;
cpumask_copy(&cpus_allowed, tsk_cpus_allowed(current)); cpumask_copy(&cpus_allowed, tsk_cpus_allowed(current));
set_cpus_allowed_ptr(current, cpumask_of(cpu)); set_cpus_allowed_ptr(current, cpumask_of(cpu));
...@@ -265,16 +264,10 @@ static int us2e_freq_target(struct cpufreq_policy *policy, unsigned int index) ...@@ -265,16 +264,10 @@ static int us2e_freq_target(struct cpufreq_policy *policy, unsigned int index)
old_divisor = estar_to_divisor(estar); old_divisor = estar_to_divisor(estar);
freqs.old = clock_tick / old_divisor;
freqs.new = new_freq;
cpufreq_notify_transition(policy, &freqs, CPUFREQ_PRECHANGE);
if (old_divisor != divisor) if (old_divisor != divisor)
us2e_transition(estar, new_bits, clock_tick * 1000, us2e_transition(estar, new_bits, clock_tick * 1000,
old_divisor, divisor); old_divisor, divisor);
cpufreq_notify_transition(policy, &freqs, CPUFREQ_POSTCHANGE);
set_cpus_allowed_ptr(current, &cpus_allowed); set_cpus_allowed_ptr(current, &cpus_allowed);
return 0; return 0;
......
...@@ -98,7 +98,6 @@ static int us3_freq_target(struct cpufreq_policy *policy, unsigned int index) ...@@ -98,7 +98,6 @@ static int us3_freq_target(struct cpufreq_policy *policy, unsigned int index)
unsigned int cpu = policy->cpu; unsigned int cpu = policy->cpu;
unsigned long new_bits, new_freq, reg; unsigned long new_bits, new_freq, reg;
cpumask_t cpus_allowed; cpumask_t cpus_allowed;
struct cpufreq_freqs freqs;
cpumask_copy(&cpus_allowed, tsk_cpus_allowed(current)); cpumask_copy(&cpus_allowed, tsk_cpus_allowed(current));
set_cpus_allowed_ptr(current, cpumask_of(cpu)); set_cpus_allowed_ptr(current, cpumask_of(cpu));
...@@ -124,16 +123,10 @@ static int us3_freq_target(struct cpufreq_policy *policy, unsigned int index) ...@@ -124,16 +123,10 @@ static int us3_freq_target(struct cpufreq_policy *policy, unsigned int index)
reg = read_safari_cfg(); reg = read_safari_cfg();
freqs.old = get_current_freq(cpu, reg);
freqs.new = new_freq;
cpufreq_notify_transition(policy, &freqs, CPUFREQ_PRECHANGE);
reg &= ~SAFARI_CFG_DIV_MASK; reg &= ~SAFARI_CFG_DIV_MASK;
reg |= new_bits; reg |= new_bits;
write_safari_cfg(reg); write_safari_cfg(reg);
cpufreq_notify_transition(policy, &freqs, CPUFREQ_POSTCHANGE);
set_cpus_allowed_ptr(current, &cpus_allowed); set_cpus_allowed_ptr(current, &cpus_allowed);
return 0; return 0;
......
...@@ -107,12 +107,10 @@ static int spear1340_set_cpu_rate(struct clk *sys_pclk, unsigned long newfreq) ...@@ -107,12 +107,10 @@ static int spear1340_set_cpu_rate(struct clk *sys_pclk, unsigned long newfreq)
static int spear_cpufreq_target(struct cpufreq_policy *policy, static int spear_cpufreq_target(struct cpufreq_policy *policy,
unsigned int index) unsigned int index)
{ {
struct cpufreq_freqs freqs;
long newfreq; long newfreq;
struct clk *srcclk; struct clk *srcclk;
int ret, mult = 1; int ret, mult = 1;
freqs.old = spear_cpufreq_get(0);
newfreq = spear_cpufreq.freq_tbl[index].frequency * 1000; newfreq = spear_cpufreq.freq_tbl[index].frequency * 1000;
if (of_machine_is_compatible("st,spear1340")) { if (of_machine_is_compatible("st,spear1340")) {
...@@ -145,23 +143,14 @@ static int spear_cpufreq_target(struct cpufreq_policy *policy, ...@@ -145,23 +143,14 @@ static int spear_cpufreq_target(struct cpufreq_policy *policy,
return newfreq; return newfreq;
} }
freqs.new = newfreq / 1000;
freqs.new /= mult;
cpufreq_notify_transition(policy, &freqs, CPUFREQ_PRECHANGE);
if (mult == 2) if (mult == 2)
ret = spear1340_set_cpu_rate(srcclk, newfreq); ret = spear1340_set_cpu_rate(srcclk, newfreq);
else else
ret = clk_set_rate(spear_cpufreq.clk, newfreq); ret = clk_set_rate(spear_cpufreq.clk, newfreq);
/* Get current rate after clk_set_rate, in case of failure */ if (ret)
if (ret) {
pr_err("CPU Freq: cpu clk_set_rate failed: %d\n", ret); pr_err("CPU Freq: cpu clk_set_rate failed: %d\n", ret);
freqs.new = clk_get_rate(spear_cpufreq.clk) / 1000;
}
cpufreq_notify_transition(policy, &freqs, CPUFREQ_POSTCHANGE);
return ret; return ret;
} }
......
...@@ -423,9 +423,8 @@ static int centrino_cpu_exit(struct cpufreq_policy *policy) ...@@ -423,9 +423,8 @@ static int centrino_cpu_exit(struct cpufreq_policy *policy)
static int centrino_target(struct cpufreq_policy *policy, unsigned int index) static int centrino_target(struct cpufreq_policy *policy, unsigned int index)
{ {
unsigned int msr, oldmsr = 0, h = 0, cpu = policy->cpu; unsigned int msr, oldmsr = 0, h = 0, cpu = policy->cpu;
struct cpufreq_freqs freqs;
int retval = 0; int retval = 0;
unsigned int j, first_cpu, tmp; unsigned int j, first_cpu;
struct cpufreq_frequency_table *op_points; struct cpufreq_frequency_table *op_points;
cpumask_var_t covered_cpus; cpumask_var_t covered_cpus;
...@@ -473,16 +472,6 @@ static int centrino_target(struct cpufreq_policy *policy, unsigned int index) ...@@ -473,16 +472,6 @@ static int centrino_target(struct cpufreq_policy *policy, unsigned int index)
goto out; goto out;
} }
freqs.old = extract_clock(oldmsr, cpu, 0);
freqs.new = extract_clock(msr, cpu, 0);
pr_debug("target=%dkHz old=%d new=%d msr=%04x\n",
op_points->frequency, freqs.old, freqs.new,
msr);
cpufreq_notify_transition(policy, &freqs,
CPUFREQ_PRECHANGE);
first_cpu = 0; first_cpu = 0;
/* all but 16 LSB are reserved, treat them with care */ /* all but 16 LSB are reserved, treat them with care */
oldmsr &= ~0xffff; oldmsr &= ~0xffff;
...@@ -497,8 +486,6 @@ static int centrino_target(struct cpufreq_policy *policy, unsigned int index) ...@@ -497,8 +486,6 @@ static int centrino_target(struct cpufreq_policy *policy, unsigned int index)
cpumask_set_cpu(j, covered_cpus); cpumask_set_cpu(j, covered_cpus);
} }
cpufreq_notify_transition(policy, &freqs, CPUFREQ_POSTCHANGE);
if (unlikely(retval)) { if (unlikely(retval)) {
/* /*
* We have failed halfway through the frequency change. * We have failed halfway through the frequency change.
...@@ -509,12 +496,6 @@ static int centrino_target(struct cpufreq_policy *policy, unsigned int index) ...@@ -509,12 +496,6 @@ static int centrino_target(struct cpufreq_policy *policy, unsigned int index)
for_each_cpu(j, covered_cpus) for_each_cpu(j, covered_cpus)
wrmsr_on_cpu(j, MSR_IA32_PERF_CTL, oldmsr, h); wrmsr_on_cpu(j, MSR_IA32_PERF_CTL, oldmsr, h);
tmp = freqs.new;
freqs.new = freqs.old;
freqs.old = tmp;
cpufreq_notify_transition(policy, &freqs, CPUFREQ_PRECHANGE);
cpufreq_notify_transition(policy, &freqs, CPUFREQ_POSTCHANGE);
} }
retval = 0; retval = 0;
......
...@@ -258,21 +258,12 @@ static unsigned int speedstep_get(unsigned int cpu) ...@@ -258,21 +258,12 @@ static unsigned int speedstep_get(unsigned int cpu)
static int speedstep_target(struct cpufreq_policy *policy, unsigned int index) static int speedstep_target(struct cpufreq_policy *policy, unsigned int index)
{ {
unsigned int policy_cpu; unsigned int policy_cpu;
struct cpufreq_freqs freqs;
policy_cpu = cpumask_any_and(policy->cpus, cpu_online_mask); policy_cpu = cpumask_any_and(policy->cpus, cpu_online_mask);
freqs.old = speedstep_get(policy_cpu);
freqs.new = speedstep_freqs[index].frequency;
pr_debug("transiting from %u to %u kHz\n", freqs.old, freqs.new);
cpufreq_notify_transition(policy, &freqs, CPUFREQ_PRECHANGE);
smp_call_function_single(policy_cpu, _speedstep_set_state, &index, smp_call_function_single(policy_cpu, _speedstep_set_state, &index,
true); true);
cpufreq_notify_transition(policy, &freqs, CPUFREQ_POSTCHANGE);
return 0; return 0;
} }
......
...@@ -241,14 +241,7 @@ static void speedstep_set_state(unsigned int state) ...@@ -241,14 +241,7 @@ static void speedstep_set_state(unsigned int state)
*/ */
static int speedstep_target(struct cpufreq_policy *policy, unsigned int index) static int speedstep_target(struct cpufreq_policy *policy, unsigned int index)
{ {
struct cpufreq_freqs freqs;
freqs.old = speedstep_freqs[speedstep_get_state()].frequency;
freqs.new = speedstep_freqs[index].frequency;
cpufreq_notify_transition(policy, &freqs, CPUFREQ_PRECHANGE);
speedstep_set_state(index); speedstep_set_state(index);
cpufreq_notify_transition(policy, &freqs, CPUFREQ_POSTCHANGE);
return 0; return 0;
} }
......
...@@ -102,12 +102,8 @@ static int tegra_update_cpu_speed(struct cpufreq_policy *policy, ...@@ -102,12 +102,8 @@ static int tegra_update_cpu_speed(struct cpufreq_policy *policy,
unsigned long rate) unsigned long rate)
{ {
int ret = 0; int ret = 0;
struct cpufreq_freqs freqs;
freqs.old = tegra_getspeed(0); if (tegra_getspeed(0) == rate)
freqs.new = rate;
if (freqs.old == freqs.new)
return ret; return ret;
/* /*
...@@ -121,21 +117,10 @@ static int tegra_update_cpu_speed(struct cpufreq_policy *policy, ...@@ -121,21 +117,10 @@ static int tegra_update_cpu_speed(struct cpufreq_policy *policy,
else else
clk_set_rate(emc_clk, 100000000); /* emc 50Mhz */ clk_set_rate(emc_clk, 100000000); /* emc 50Mhz */
cpufreq_notify_transition(policy, &freqs, CPUFREQ_PRECHANGE); ret = tegra_cpu_clk_set_rate(rate * 1000);
if (ret)
#ifdef CONFIG_CPU_FREQ_DEBUG pr_err("cpu-tegra: Failed to set cpu frequency to %lu kHz\n",
printk(KERN_DEBUG "cpufreq-tegra: transition: %u --> %u\n", rate);
freqs.old, freqs.new);
#endif
ret = tegra_cpu_clk_set_rate(freqs.new * 1000);
if (ret) {
pr_err("cpu-tegra: Failed to set cpu frequency to %d kHz\n",
freqs.new);
freqs.new = freqs.old;
}
cpufreq_notify_transition(policy, &freqs, CPUFREQ_POSTCHANGE);
return ret; return ret;
} }
......
/*
* Versatile Express SPC CPUFreq Interface driver
*
* It provides necessary ops to arm_big_little cpufreq driver.
*
* Copyright (C) 2013 ARM Ltd.
* Sudeep KarkadaNagesha <sudeep.karkadanagesha@arm.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.
*
* 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/cpufreq.h>
#include <linux/module.h>
#include <linux/platform_device.h>
#include <linux/pm_opp.h>
#include <linux/types.h>
#include "arm_big_little.h"
static int ve_spc_init_opp_table(struct device *cpu_dev)
{
/*
* platform specific SPC code must initialise the opp table
* so just check if the OPP count is non-zero
*/
return dev_pm_opp_get_opp_count(cpu_dev) <= 0;
}
static int ve_spc_get_transition_latency(struct device *cpu_dev)
{
return 1000000; /* 1 ms */
}
static struct cpufreq_arm_bL_ops ve_spc_cpufreq_ops = {
.name = "vexpress-spc",
.get_transition_latency = ve_spc_get_transition_latency,
.init_opp_table = ve_spc_init_opp_table,
};
static int ve_spc_cpufreq_probe(struct platform_device *pdev)
{
return bL_cpufreq_register(&ve_spc_cpufreq_ops);
}
static int ve_spc_cpufreq_remove(struct platform_device *pdev)
{
bL_cpufreq_unregister(&ve_spc_cpufreq_ops);
return 0;
}
static struct platform_driver ve_spc_cpufreq_platdrv = {
.driver = {
.name = "vexpress-spc-cpufreq",
.owner = THIS_MODULE,
},
.probe = ve_spc_cpufreq_probe,
.remove = ve_spc_cpufreq_remove,
};
module_platform_driver(ve_spc_cpufreq_platdrv);
MODULE_LICENSE("GPL");
...@@ -237,6 +237,13 @@ struct cpufreq_driver { ...@@ -237,6 +237,13 @@ struct cpufreq_driver {
*/ */
#define CPUFREQ_HAVE_GOVERNOR_PER_POLICY (1 << 3) #define CPUFREQ_HAVE_GOVERNOR_PER_POLICY (1 << 3)
/*
* Driver will do POSTCHANGE notifications from outside of their ->target()
* routine and so must set cpufreq_driver->flags with this flag, so that core
* can handle them specially.
*/
#define CPUFREQ_ASYNC_NOTIFICATION (1 << 4)
int cpufreq_register_driver(struct cpufreq_driver *driver_data); int cpufreq_register_driver(struct cpufreq_driver *driver_data);
int cpufreq_unregister_driver(struct cpufreq_driver *driver_data); int cpufreq_unregister_driver(struct cpufreq_driver *driver_data);
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册