forked from luck/tmp_suning_uos_patched
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
This commit is contained in:
commit
15d4cb9013
@ -66,10 +66,22 @@ config ARCH_VEXPRESS_DCSCB
|
||||
This is needed to provide CPU and cluster power management
|
||||
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
|
||||
bool "Versatile Express TC2 power management"
|
||||
depends on MCPM
|
||||
select ARM_CCI
|
||||
select ARCH_VEXPRESS_SPC
|
||||
help
|
||||
Support for CPU and cluster power management on Versatile Express
|
||||
with a TC2 (A15x2 A7x3) big.LITTLE core tile.
|
||||
|
@ -8,7 +8,8 @@ obj-y := v2m.o
|
||||
obj-$(CONFIG_ARCH_VEXPRESS_CA9X4) += ct-ca9x4.o
|
||||
obj-$(CONFIG_ARCH_VEXPRESS_DCSCB) += dcscb.o dcscb_setup.o
|
||||
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
|
||||
obj-$(CONFIG_SMP) += platsmp.o
|
||||
obj-$(CONFIG_HOTPLUG_CPU) += hotplug.o
|
||||
|
@ -17,14 +17,31 @@
|
||||
* 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/interrupt.h>
|
||||
#include <linux/io.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/pm_opp.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/semaphore.h>
|
||||
|
||||
#include <asm/cacheflush.h>
|
||||
|
||||
#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 */
|
||||
#define WAKE_INT_MASK 0x24
|
||||
#define WAKE_INT_RAW 0x28
|
||||
@ -36,12 +53,45 @@
|
||||
#define A15_BX_ADDR0 0x68
|
||||
#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 */
|
||||
#define GBL_WAKEUP_INT_MSK (0x3 << 10)
|
||||
|
||||
/* TC2 static dual-cluster configuration */
|
||||
#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 {
|
||||
void __iomem *baseaddr;
|
||||
/*
|
||||
@ -49,6 +99,12 @@ struct ve_spc_drvdata {
|
||||
* It corresponds to A15 processors MPIDR[15:8] bitfield
|
||||
*/
|
||||
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;
|
||||
@ -157,8 +213,197 @@ void ve_spc_powerdown(u32 cluster, bool enable)
|
||||
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);
|
||||
if (!info) {
|
||||
pr_err(SPCLOG "unable to allocate mem\n");
|
||||
@ -168,6 +413,25 @@ int __init ve_spc_init(void __iomem *baseaddr, u32 a15_clusid)
|
||||
info->baseaddr = baseaddr;
|
||||
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
|
||||
* 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)
|
||||
|
||||
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 @@
|
||||
#ifndef __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_cpu_wakeup_irq(u32 cluster, u32 cpu, bool set);
|
||||
void ve_spc_set_resume_addr(u32 cluster, u32 cpu, u32 addr);
|
||||
|
@ -16,6 +16,7 @@
|
||||
#include <linux/io.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/of_address.h>
|
||||
#include <linux/of_irq.h>
|
||||
#include <linux/spinlock.h>
|
||||
#include <linux/errno.h>
|
||||
#include <linux/irqchip/arm-gic.h>
|
||||
@ -311,7 +312,7 @@ static void __naked tc2_pm_power_up_setup(unsigned int affinity_level)
|
||||
|
||||
static int __init tc2_pm_init(void)
|
||||
{
|
||||
int ret;
|
||||
int ret, irq;
|
||||
void __iomem *scc;
|
||||
u32 a15_cluster_id, a7_cluster_id, sys_info;
|
||||
struct device_node *np;
|
||||
@ -336,13 +337,15 @@ static int __init tc2_pm_init(void)
|
||||
tc2_nr_cpus[a15_cluster_id] = (sys_info >> 16) & 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
|
||||
* with the SPC (power controller). We need to be able to
|
||||
* drive it very early in the boot process to power up
|
||||
* 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)
|
||||
return ret;
|
||||
|
||||
|
@ -224,3 +224,11 @@ config ARM_TEGRA_CPUFREQ
|
||||
default y
|
||||
help
|
||||
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
|
||||
obj-$(CONFIG_ARM_SA1110_CPUFREQ) += sa1110-cpufreq.o
|
||||
obj-$(CONFIG_ARM_SPEAR_CPUFREQ) += spear-cpufreq.o
|
||||
obj-$(CONFIG_ARM_TEGRA_CPUFREQ) += tegra-cpufreq.o
|
||||
obj-$(CONFIG_ARM_VEXPRESS_SPC_CPUFREQ) += vexpress-spc-cpufreq.o
|
||||
|
||||
##################################################################################
|
||||
# PowerPC platform drivers
|
||||
|
@ -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_processor_performance *perf;
|
||||
struct cpufreq_freqs freqs;
|
||||
struct drv_cmd cmd;
|
||||
unsigned int next_perf_state = 0; /* Index into perf table */
|
||||
int result = 0;
|
||||
|
||||
pr_debug("acpi_cpufreq_target %d (%d)\n",
|
||||
data->freq_table[index].frequency, policy->cpu);
|
||||
|
||||
if (unlikely(data == NULL ||
|
||||
data->acpi_data == NULL || data->freq_table == NULL)) {
|
||||
return -ENODEV;
|
||||
@ -483,23 +479,17 @@ static int acpi_cpufreq_target(struct cpufreq_policy *policy,
|
||||
else
|
||||
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);
|
||||
|
||||
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",
|
||||
policy->cpu);
|
||||
result = -EAGAIN;
|
||||
freqs.new = freqs.old;
|
||||
}
|
||||
}
|
||||
|
||||
cpufreq_notify_transition(policy, &freqs, CPUFREQ_POSTCHANGE);
|
||||
|
||||
if (!result)
|
||||
perf->state = next_perf_state;
|
||||
|
||||
|
@ -24,91 +24,319 @@
|
||||
#include <linux/cpufreq.h>
|
||||
#include <linux/cpumask.h>
|
||||
#include <linux/export.h>
|
||||
#include <linux/mutex.h>
|
||||
#include <linux/of_platform.h>
|
||||
#include <linux/pm_opp.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/topology.h>
|
||||
#include <linux/types.h>
|
||||
#include <asm/bL_switcher.h>
|
||||
|
||||
#include "arm_big_little.h"
|
||||
|
||||
/* Currently we support only two clusters */
|
||||
#define A15_CLUSTER 0
|
||||
#define A7_CLUSTER 1
|
||||
#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 clk *clk[MAX_CLUSTERS];
|
||||
static struct cpufreq_frequency_table *freq_table[MAX_CLUSTERS];
|
||||
static atomic_t cluster_usage[MAX_CLUSTERS] = {ATOMIC_INIT(0), ATOMIC_INIT(0)};
|
||||
static struct cpufreq_frequency_table *freq_table[MAX_CLUSTERS + 1];
|
||||
static atomic_t cluster_usage[MAX_CLUSTERS + 1];
|
||||
|
||||
static unsigned int bL_cpufreq_get(unsigned int cpu)
|
||||
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)
|
||||
{
|
||||
u32 cur_cluster = cpu_to_cluster(cpu);
|
||||
return topology_physical_package_id(cpu);
|
||||
}
|
||||
|
||||
return clk_get_rate(clk[cur_cluster]) / 1000;
|
||||
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_set_rate(u32 cpu, u32 old_cluster, u32 new_cluster, u32 rate)
|
||||
{
|
||||
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]);
|
||||
|
||||
/* 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 */
|
||||
static int bL_cpufreq_set_target(struct cpufreq_policy *policy,
|
||||
unsigned int index)
|
||||
{
|
||||
struct cpufreq_freqs freqs;
|
||||
u32 cpu = policy->cpu, cur_cluster;
|
||||
int ret = 0;
|
||||
u32 cpu = policy->cpu, cur_cluster, new_cluster, actual_cluster;
|
||||
unsigned int freqs_new;
|
||||
|
||||
cur_cluster = cpu_to_cluster(policy->cpu);
|
||||
cur_cluster = cpu_to_cluster(cpu);
|
||||
new_cluster = actual_cluster = per_cpu(physical_cluster, cpu);
|
||||
|
||||
freqs.old = bL_cpufreq_get(policy->cpu);
|
||||
freqs.new = freq_table[cur_cluster][index].frequency;
|
||||
freqs_new = freq_table[cur_cluster][index].frequency;
|
||||
|
||||
pr_debug("%s: cpu: %d, cluster: %d, oldfreq: %d, target freq: %d, new freq: %d\n",
|
||||
__func__, cpu, cur_cluster, freqs.old, freqs.new,
|
||||
freqs.new);
|
||||
|
||||
cpufreq_notify_transition(policy, &freqs, CPUFREQ_PRECHANGE);
|
||||
|
||||
ret = clk_set_rate(clk[cur_cluster], freqs.new * 1000);
|
||||
if (ret) {
|
||||
pr_err("clk_set_rate failed: %d\n", ret);
|
||||
freqs.new = freqs.old;
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
cpufreq_notify_transition(policy, &freqs, CPUFREQ_POSTCHANGE);
|
||||
return bL_cpufreq_set_rate(cpu, actual_cluster, new_cluster, freqs_new);
|
||||
}
|
||||
|
||||
return ret;
|
||||
static inline u32 get_table_count(struct cpufreq_frequency_table *table)
|
||||
{
|
||||
int count;
|
||||
|
||||
for (count = 0; table[count].frequency != CPUFREQ_TABLE_END; count++)
|
||||
;
|
||||
|
||||
return count;
|
||||
}
|
||||
|
||||
/* get the minimum frequency in the cpufreq_frequency_table */
|
||||
static inline u32 get_table_min(struct cpufreq_frequency_table *table)
|
||||
{
|
||||
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++;
|
||||
}
|
||||
}
|
||||
|
||||
table[k].driver_data = k;
|
||||
table[k].frequency = CPUFREQ_TABLE_END;
|
||||
|
||||
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)
|
||||
{
|
||||
u32 cluster = cpu_to_cluster(cpu_dev->id);
|
||||
int i;
|
||||
|
||||
if (!atomic_dec_return(&cluster_usage[cluster])) {
|
||||
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);
|
||||
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;
|
||||
}
|
||||
|
||||
_put_cluster_clk_and_freq_table(cdev);
|
||||
}
|
||||
|
||||
/* 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.";
|
||||
int ret;
|
||||
|
||||
if (atomic_inc_return(&cluster_usage[cluster]) != 1)
|
||||
if (freq_table[cluster])
|
||||
return 0;
|
||||
|
||||
ret = arm_bL_ops->init_opp_table(cpu_dev);
|
||||
if (ret) {
|
||||
dev_err(cpu_dev, "%s: init_opp_table failed, cpu: %d, err: %d\n",
|
||||
__func__, cpu_dev->id, ret);
|
||||
goto atomic_dec;
|
||||
goto out;
|
||||
}
|
||||
|
||||
ret = dev_pm_opp_init_cpufreq_table(cpu_dev, &freq_table[cluster]);
|
||||
if (ret) {
|
||||
dev_err(cpu_dev, "%s: failed to init cpufreq table, cpu: %d, err: %d\n",
|
||||
__func__, cpu_dev->id, ret);
|
||||
goto atomic_dec;
|
||||
goto out;
|
||||
}
|
||||
|
||||
name[12] = cluster + '0';
|
||||
@ -125,13 +353,72 @@ static int get_cluster_clk_and_freq_table(struct device *cpu_dev)
|
||||
ret = PTR_ERR(clk[cluster]);
|
||||
dev_pm_opp_free_cpufreq_table(cpu_dev, &freq_table[cluster]);
|
||||
|
||||
atomic_dec:
|
||||
atomic_dec(&cluster_usage[cluster]);
|
||||
out:
|
||||
dev_err(cpu_dev, "%s: Failed to get data for cluster: %d\n", __func__,
|
||||
cluster);
|
||||
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 */
|
||||
static int bL_cpufreq_init(struct cpufreq_policy *policy)
|
||||
{
|
||||
@ -158,13 +445,23 @@ static int bL_cpufreq_init(struct cpufreq_policy *policy)
|
||||
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)
|
||||
policy->cpuinfo.transition_latency =
|
||||
arm_bL_ops->get_transition_latency(cpu_dev);
|
||||
else
|
||||
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);
|
||||
return 0;
|
||||
@ -194,15 +491,47 @@ static struct cpufreq_driver bL_cpufreq_driver = {
|
||||
CPUFREQ_HAVE_GOVERNOR_PER_POLICY,
|
||||
.verify = cpufreq_generic_frequency_table_verify,
|
||||
.target_index = bL_cpufreq_set_target,
|
||||
.get = bL_cpufreq_get,
|
||||
.get = bL_cpufreq_get_rate,
|
||||
.init = bL_cpufreq_init,
|
||||
.exit = bL_cpufreq_exit,
|
||||
.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 ret;
|
||||
int ret, i;
|
||||
|
||||
if (arm_bL_ops) {
|
||||
pr_debug("%s: Already registered: %s, exiting\n", __func__,
|
||||
@ -217,16 +546,29 @@ int bL_cpufreq_register(struct cpufreq_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);
|
||||
if (ret) {
|
||||
pr_info("%s: Failed registering platform driver: %s, err: %d\n",
|
||||
__func__, ops->name, ret);
|
||||
arm_bL_ops = NULL;
|
||||
} else {
|
||||
pr_info("%s: Registered platform driver: %s\n", __func__,
|
||||
ops->name);
|
||||
ret = bL_switcher_register_notifier(&bL_switcher_notifier);
|
||||
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;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(bL_cpufreq_register);
|
||||
@ -239,7 +581,10 @@ void bL_cpufreq_unregister(struct cpufreq_arm_bL_ops *ops)
|
||||
return;
|
||||
}
|
||||
|
||||
bL_switcher_get_enabled();
|
||||
bL_switcher_unregister_notifier(&bL_switcher_notifier);
|
||||
cpufreq_unregister_driver(&bL_cpufreq_driver);
|
||||
bL_switcher_put_enabled();
|
||||
pr_info("%s: Un-registered platform driver: %s\n", __func__,
|
||||
arm_bL_ops->name);
|
||||
arm_bL_ops = NULL;
|
||||
|
@ -34,11 +34,6 @@ struct cpufreq_arm_bL_ops {
|
||||
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);
|
||||
void bL_cpufreq_unregister(struct cpufreq_arm_bL_ops *ops);
|
||||
|
||||
|
@ -37,27 +37,23 @@ static unsigned long loops_per_jiffy_ref;
|
||||
|
||||
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);
|
||||
freqs.new = freq_table[index].frequency;
|
||||
old_freq = at32_get_speed(0);
|
||||
new_freq = freq_table[index].frequency;
|
||||
|
||||
if (!ref_freq) {
|
||||
ref_freq = freqs.old;
|
||||
ref_freq = old_freq;
|
||||
loops_per_jiffy_ref = boot_cpu_data.loops_per_jiffy;
|
||||
}
|
||||
|
||||
cpufreq_notify_transition(policy, &freqs, CPUFREQ_PRECHANGE);
|
||||
if (freqs.old < freqs.new)
|
||||
if (old_freq < new_freq)
|
||||
boot_cpu_data.loops_per_jiffy = cpufreq_scale(
|
||||
loops_per_jiffy_ref, ref_freq, freqs.new);
|
||||
clk_set_rate(cpuclk, freqs.new * 1000);
|
||||
if (freqs.new < freqs.old)
|
||||
loops_per_jiffy_ref, ref_freq, new_freq);
|
||||
clk_set_rate(cpuclk, new_freq * 1000);
|
||||
if (new_freq < old_freq)
|
||||
boot_cpu_data.loops_per_jiffy = cpufreq_scale(
|
||||
loops_per_jiffy_ref, ref_freq, freqs.new);
|
||||
cpufreq_notify_transition(policy, &freqs, CPUFREQ_POSTCHANGE);
|
||||
|
||||
pr_debug("cpufreq: set frequency %u Hz\n", freqs.new * 1000);
|
||||
loops_per_jiffy_ref, ref_freq, new_freq);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -132,27 +132,23 @@ static int bfin_target(struct cpufreq_policy *policy, unsigned int index)
|
||||
#ifndef CONFIG_BF60x
|
||||
unsigned int plldiv;
|
||||
#endif
|
||||
struct cpufreq_freqs freqs;
|
||||
static unsigned long lpj_ref;
|
||||
static unsigned int lpj_ref_freq;
|
||||
unsigned int old_freq, new_freq;
|
||||
int ret = 0;
|
||||
|
||||
#if defined(CONFIG_CYCLES_CLOCKSOURCE)
|
||||
cycles_t cycles;
|
||||
#endif
|
||||
|
||||
freqs.old = bfin_getfreq_khz(0);
|
||||
freqs.new = bfin_freq_table[index].frequency;
|
||||
old_freq = bfin_getfreq_khz(0);
|
||||
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
|
||||
plldiv = (bfin_read_PLL_DIV() & SSEL) | dpm_state_table[index].csel;
|
||||
bfin_write_PLL_DIV(plldiv);
|
||||
#else
|
||||
ret = cpu_set_cclk(policy->cpu, freqs.new * 1000);
|
||||
ret = cpu_set_cclk(policy->cpu, new_freq * 1000);
|
||||
if (ret != 0) {
|
||||
WARN_ONCE(ret, "cpufreq set freq failed %d\n", ret);
|
||||
return ret;
|
||||
@ -168,17 +164,13 @@ static int bfin_target(struct cpufreq_policy *policy, unsigned int index)
|
||||
#endif
|
||||
if (!lpj_ref_freq) {
|
||||
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,
|
||||
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;
|
||||
}
|
||||
|
||||
|
@ -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)
|
||||
{
|
||||
struct cpufreq_freqs freqs;
|
||||
struct dev_pm_opp *opp;
|
||||
unsigned long volt = 0, volt_old = 0, tol = 0;
|
||||
unsigned int old_freq, new_freq;
|
||||
long freq_Hz, freq_exact;
|
||||
int ret;
|
||||
|
||||
freq_Hz = clk_round_rate(cpu_clk, freq_table[index].frequency * 1000);
|
||||
if (freq_Hz < 0)
|
||||
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)) {
|
||||
rcu_read_lock();
|
||||
@ -58,9 +57,7 @@ static int cpu0_set_target(struct cpufreq_policy *policy, unsigned int index)
|
||||
if (IS_ERR(opp)) {
|
||||
rcu_read_unlock();
|
||||
pr_err("failed to find OPP for %ld\n", freq_Hz);
|
||||
freqs.new = freqs.old;
|
||||
ret = PTR_ERR(opp);
|
||||
goto post_notify;
|
||||
return PTR_ERR(opp);
|
||||
}
|
||||
volt = dev_pm_opp_get_voltage(opp);
|
||||
rcu_read_unlock();
|
||||
@ -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",
|
||||
freqs.old / 1000, volt_old ? volt_old / 1000 : -1,
|
||||
freqs.new / 1000, volt ? volt / 1000 : -1);
|
||||
old_freq / 1000, volt_old ? volt_old / 1000 : -1,
|
||||
new_freq / 1000, volt ? volt / 1000 : -1);
|
||||
|
||||
/* 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);
|
||||
if (ret) {
|
||||
pr_err("failed to scale voltage up: %d\n", ret);
|
||||
freqs.new = freqs.old;
|
||||
goto post_notify;
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
||||
@ -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);
|
||||
if (!IS_ERR(cpu_reg))
|
||||
regulator_set_voltage_tol(cpu_reg, volt_old, tol);
|
||||
freqs.new = freqs.old;
|
||||
goto post_notify;
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* 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);
|
||||
if (ret) {
|
||||
pr_err("failed to scale voltage down: %d\n", ret);
|
||||
clk_set_rate(cpu_clk, freqs.old * 1000);
|
||||
freqs.new = freqs.old;
|
||||
clk_set_rate(cpu_clk, old_freq * 1000);
|
||||
}
|
||||
}
|
||||
|
||||
post_notify:
|
||||
cpufreq_notify_transition(policy, &freqs, CPUFREQ_POSTCHANGE);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
@ -1669,6 +1669,8 @@ int __cpufreq_driver_target(struct cpufreq_policy *policy,
|
||||
retval = cpufreq_driver->target(policy, target_freq, relation);
|
||||
else if (cpufreq_driver->target_index) {
|
||||
struct cpufreq_frequency_table *freq_table;
|
||||
struct cpufreq_freqs freqs;
|
||||
bool notify;
|
||||
int index;
|
||||
|
||||
freq_table = cpufreq_frequency_get_table(policy->cpu);
|
||||
@ -1684,10 +1686,42 @@ int __cpufreq_driver_target(struct cpufreq_policy *policy,
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (freq_table[index].frequency == policy->cur)
|
||||
if (freq_table[index].frequency == policy->cur) {
|
||||
retval = 0;
|
||||
else
|
||||
retval = cpufreq_driver->target_index(policy, index);
|
||||
goto out;
|
||||
}
|
||||
|
||||
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:
|
||||
|
@ -168,7 +168,6 @@ static void od_check_cpu(int cpu, unsigned int load)
|
||||
dbs_info->rate_mult =
|
||||
od_tuners->sampling_down_factor;
|
||||
dbs_freq_increase(policy, policy->max);
|
||||
return;
|
||||
} else {
|
||||
/* Calculate the next frequency proportional to load */
|
||||
unsigned int freq_next;
|
||||
|
@ -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)
|
||||
{
|
||||
struct cpufreq_freqs freqs;
|
||||
reg_clkgen_rw_clk_ctrl 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();
|
||||
|
||||
/* 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)
|
||||
|
||||
local_irq_enable();
|
||||
|
||||
cpufreq_notify_transition(policy, &freqs, CPUFREQ_POSTCHANGE);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -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)
|
||||
{
|
||||
struct cpufreq_freqs freqs;
|
||||
reg_config_rw_clk_ctrl 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();
|
||||
|
||||
/* 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)
|
||||
|
||||
local_irq_enable();
|
||||
|
||||
cpufreq_notify_transition(policy, &freqs, CPUFREQ_POSTCHANGE);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -68,46 +68,36 @@ static unsigned int davinci_getspeed(unsigned int cpu)
|
||||
|
||||
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 clk *armclk = cpufreq.armclk;
|
||||
unsigned int old_freq, new_freq;
|
||||
int ret = 0;
|
||||
|
||||
freqs.old = davinci_getspeed(0);
|
||||
freqs.new = pdata->freq_table[idx].frequency;
|
||||
|
||||
dev_dbg(cpufreq.dev, "transition: %u --> %u\n", freqs.old, freqs.new);
|
||||
|
||||
cpufreq_notify_transition(policy, &freqs, CPUFREQ_PRECHANGE);
|
||||
old_freq = davinci_getspeed(0);
|
||||
new_freq = pdata->freq_table[idx].frequency;
|
||||
|
||||
/* 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);
|
||||
if (ret)
|
||||
goto out;
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = clk_set_rate(armclk, idx);
|
||||
if (ret)
|
||||
goto out;
|
||||
return ret;
|
||||
|
||||
if (cpufreq.asyncclk) {
|
||||
ret = clk_set_rate(cpufreq.asyncclk, cpufreq.asyncrate);
|
||||
if (ret)
|
||||
goto out;
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* 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);
|
||||
|
||||
out:
|
||||
if (ret)
|
||||
freqs.new = freqs.old;
|
||||
|
||||
cpufreq_notify_transition(policy, &freqs, CPUFREQ_POSTCHANGE);
|
||||
|
||||
return ret;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int davinci_cpu_init(struct cpufreq_policy *policy)
|
||||
|
@ -22,28 +22,8 @@ static struct clk *armss_clk;
|
||||
static int dbx500_cpufreq_target(struct cpufreq_policy *policy,
|
||||
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 */
|
||||
ret = clk_set_rate(armss_clk, freqs.new * 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;
|
||||
return clk_set_rate(armss_clk, freq_table[index].frequency * 1000);
|
||||
}
|
||||
|
||||
static unsigned int dbx500_cpufreq_getspeed(unsigned int cpu)
|
||||
|
@ -107,15 +107,9 @@ static int eps_set_state(struct eps_cpu_data *centaur,
|
||||
struct cpufreq_policy *policy,
|
||||
u32 dest_state)
|
||||
{
|
||||
struct cpufreq_freqs freqs;
|
||||
u32 lo, hi;
|
||||
int err = 0;
|
||||
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 */
|
||||
rdmsr(MSR_IA32_PERF_STATUS, lo, hi);
|
||||
i = 0;
|
||||
@ -124,8 +118,7 @@ static int eps_set_state(struct eps_cpu_data *centaur,
|
||||
rdmsr(MSR_IA32_PERF_STATUS, lo, hi);
|
||||
i++;
|
||||
if (unlikely(i > 64)) {
|
||||
err = -ENODEV;
|
||||
goto postchange;
|
||||
return -ENODEV;
|
||||
}
|
||||
}
|
||||
/* Set new multiplier and voltage */
|
||||
@ -137,16 +130,10 @@ static int eps_set_state(struct eps_cpu_data *centaur,
|
||||
rdmsr(MSR_IA32_PERF_STATUS, lo, hi);
|
||||
i++;
|
||||
if (unlikely(i > 64)) {
|
||||
err = -ENODEV;
|
||||
goto postchange;
|
||||
return -ENODEV;
|
||||
}
|
||||
} 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
|
||||
{
|
||||
u8 current_multiplier, current_voltage;
|
||||
@ -161,11 +148,7 @@ static int eps_set_state(struct eps_cpu_data *centaur,
|
||||
current_multiplier);
|
||||
}
|
||||
#endif
|
||||
if (err)
|
||||
freqs.new = freqs.old;
|
||||
|
||||
cpufreq_notify_transition(policy, &freqs, CPUFREQ_POSTCHANGE);
|
||||
return err;
|
||||
return 0;
|
||||
}
|
||||
|
||||
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)
|
||||
static int elanfreq_target(struct cpufreq_policy *policy,
|
||||
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
|
||||
* 0x22: Chip Setup & Control Register Index Register (CSCI)
|
||||
@ -149,8 +138,6 @@ static int elanfreq_target(struct cpufreq_policy *policy,
|
||||
udelay(10000);
|
||||
local_irq_enable();
|
||||
|
||||
cpufreq_notify_transition(policy, &freqs, CPUFREQ_POSTCHANGE);
|
||||
|
||||
return 0;
|
||||
}
|
||||
/*
|
||||
|
@ -25,7 +25,6 @@
|
||||
static struct exynos_dvfs_info *exynos_info;
|
||||
|
||||
static struct regulator *arm_regulator;
|
||||
static struct cpufreq_freqs freqs;
|
||||
|
||||
static unsigned int locking_frequency;
|
||||
static bool frequency_locked;
|
||||
@ -59,18 +58,18 @@ static int exynos_cpufreq_scale(unsigned int target_freq)
|
||||
struct cpufreq_policy *policy = cpufreq_cpu_get(0);
|
||||
unsigned int arm_volt, safe_arm_volt = 0;
|
||||
unsigned int mpll_freq_khz = exynos_info->mpll_freq_khz;
|
||||
unsigned int old_freq;
|
||||
int index, old_index;
|
||||
int ret = 0;
|
||||
|
||||
freqs.old = policy->cur;
|
||||
freqs.new = target_freq;
|
||||
old_freq = policy->cur;
|
||||
|
||||
/*
|
||||
* The policy max have been changed so that we cannot get proper
|
||||
* old_index with cpufreq_frequency_table_target(). Thus, ignore
|
||||
* 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) {
|
||||
ret = old_index;
|
||||
goto out;
|
||||
@ -95,17 +94,14 @@ static int exynos_cpufreq_scale(unsigned int target_freq)
|
||||
}
|
||||
arm_volt = volt_table[index];
|
||||
|
||||
cpufreq_notify_transition(policy, &freqs, CPUFREQ_PRECHANGE);
|
||||
|
||||
/* 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 */
|
||||
ret = regulator_set_voltage(arm_regulator, arm_volt, arm_volt);
|
||||
if (ret) {
|
||||
pr_err("%s: failed to set cpu voltage to %d\n",
|
||||
__func__, arm_volt);
|
||||
freqs.new = freqs.old;
|
||||
goto post_notify;
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
||||
@ -115,22 +111,15 @@ static int exynos_cpufreq_scale(unsigned int target_freq)
|
||||
if (ret) {
|
||||
pr_err("%s: failed to set cpu voltage to %d\n",
|
||||
__func__, safe_arm_volt);
|
||||
freqs.new = freqs.old;
|
||||
goto post_notify;
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
||||
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 */
|
||||
if ((freqs.new < freqs.old) ||
|
||||
((freqs.new > freqs.old) && safe_arm_volt)) {
|
||||
if ((target_freq < old_freq) ||
|
||||
((target_freq > old_freq) && safe_arm_volt)) {
|
||||
/* down the voltage after frequency change */
|
||||
ret = regulator_set_voltage(arm_regulator, arm_volt,
|
||||
arm_volt);
|
||||
@ -142,7 +131,6 @@ static int exynos_cpufreq_scale(unsigned int target_freq)
|
||||
}
|
||||
|
||||
out:
|
||||
|
||||
cpufreq_cpu_put(policy);
|
||||
|
||||
return ret;
|
||||
|
@ -312,7 +312,7 @@ static int exynos_cpufreq_cpu_init(struct cpufreq_policy *policy)
|
||||
}
|
||||
|
||||
static struct cpufreq_driver exynos_driver = {
|
||||
.flags = CPUFREQ_STICKY,
|
||||
.flags = CPUFREQ_STICKY | CPUFREQ_ASYNC_NOTIFICATION,
|
||||
.verify = cpufreq_generic_frequency_table_verify,
|
||||
.target_index = exynos_target,
|
||||
.get = exynos_getspeed,
|
||||
|
@ -141,7 +141,6 @@ processor_set_freq (
|
||||
{
|
||||
int ret = 0;
|
||||
u32 value = 0;
|
||||
struct cpufreq_freqs cpufreq_freqs;
|
||||
cpumask_t saved_mask;
|
||||
int retval;
|
||||
|
||||
@ -168,13 +167,6 @@ processor_set_freq (
|
||||
pr_debug("Transitioning from P%d to P%d\n",
|
||||
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
|
||||
* control_register.
|
||||
@ -186,22 +178,11 @@ processor_set_freq (
|
||||
|
||||
ret = processor_set_pstate(value);
|
||||
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);
|
||||
retval = -ENODEV;
|
||||
goto migrate_end;
|
||||
}
|
||||
|
||||
cpufreq_notify_transition(policy, &cpufreq_freqs, CPUFREQ_POSTCHANGE);
|
||||
|
||||
data->acpi_data.state = state;
|
||||
|
||||
retval = 0;
|
||||
|
@ -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)
|
||||
{
|
||||
struct cpufreq_freqs freqs;
|
||||
struct dev_pm_opp *opp;
|
||||
unsigned long freq_hz, volt, volt_old;
|
||||
unsigned int old_freq, new_freq;
|
||||
int ret;
|
||||
|
||||
freqs.new = freq_table[index].frequency;
|
||||
freq_hz = freqs.new * 1000;
|
||||
freqs.old = clk_get_rate(arm_clk) / 1000;
|
||||
new_freq = freq_table[index].frequency;
|
||||
freq_hz = new_freq * 1000;
|
||||
old_freq = clk_get_rate(arm_clk) / 1000;
|
||||
|
||||
rcu_read_lock();
|
||||
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)
|
||||
volt_old = regulator_get_voltage(arm_reg);
|
||||
|
||||
dev_dbg(cpu_dev, "%u MHz, %ld mV --> %u MHz, %ld mV\n",
|
||||
freqs.old / 1000, volt_old / 1000,
|
||||
freqs.new / 1000, volt / 1000);
|
||||
|
||||
cpufreq_notify_transition(policy, &freqs, CPUFREQ_PRECHANGE);
|
||||
old_freq / 1000, volt_old / 1000,
|
||||
new_freq / 1000, volt / 1000);
|
||||
|
||||
/* 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);
|
||||
if (ret) {
|
||||
dev_err(cpu_dev,
|
||||
"failed to scale vddarm up: %d\n", ret);
|
||||
freqs.new = freqs.old;
|
||||
goto post_notify;
|
||||
return ret;
|
||||
}
|
||||
|
||||
/*
|
||||
* Need to increase vddpu and vddsoc for safety
|
||||
* 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,
|
||||
PU_SOC_VOLTAGE_HIGH, 0);
|
||||
regulator_set_voltage_tol(soc_reg,
|
||||
@ -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(pll1_sw_clk, step_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);
|
||||
}
|
||||
|
||||
/* 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) {
|
||||
dev_err(cpu_dev, "failed to set clock rate: %d\n", ret);
|
||||
regulator_set_voltage_tol(arm_reg, volt_old, 0);
|
||||
freqs.new = freqs.old;
|
||||
goto post_notify;
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* 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);
|
||||
if (ret) {
|
||||
dev_warn(cpu_dev,
|
||||
@ -125,7 +121,7 @@ static int imx6q_set_target(struct cpufreq_policy *policy, unsigned int index)
|
||||
ret = 0;
|
||||
}
|
||||
|
||||
if (freqs.old == FREQ_1P2_GHZ / 1000) {
|
||||
if (old_freq == FREQ_1P2_GHZ / 1000) {
|
||||
regulator_set_voltage_tol(pu_reg,
|
||||
PU_SOC_VOLTAGE_NORMAL, 0);
|
||||
regulator_set_voltage_tol(soc_reg,
|
||||
@ -133,10 +129,7 @@ static int imx6q_set_target(struct cpufreq_policy *policy, unsigned int index)
|
||||
}
|
||||
}
|
||||
|
||||
post_notify:
|
||||
cpufreq_notify_transition(policy, &freqs, CPUFREQ_POSTCHANGE);
|
||||
|
||||
return ret;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int imx6q_cpufreq_init(struct cpufreq_policy *policy)
|
||||
|
@ -25,6 +25,7 @@
|
||||
#include <linux/types.h>
|
||||
#include <linux/fs.h>
|
||||
#include <linux/debugfs.h>
|
||||
#include <linux/acpi.h>
|
||||
#include <trace/events/power.h>
|
||||
|
||||
#include <asm/div64.h>
|
||||
@ -759,7 +760,7 @@ static int intel_pstate_msrs_not_valid(void)
|
||||
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.p_gain_pct = policy->p_gain_pct;
|
||||
@ -769,7 +770,7 @@ void copy_pid_params(struct pstate_adjust_policy *policy)
|
||||
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_min = funcs->get_min;
|
||||
@ -777,6 +778,72 @@ void copy_cpu_funcs(struct pstate_funcs *funcs)
|
||||
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)
|
||||
{
|
||||
int cpu, rc = 0;
|
||||
@ -790,6 +857,13 @@ static int __init intel_pstate_init(void)
|
||||
if (!id)
|
||||
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;
|
||||
|
||||
copy_pid_params(&cpu_info->pid_policy);
|
||||
|
@ -58,48 +58,34 @@ static unsigned int kirkwood_cpufreq_get_cpu_frequency(unsigned int cpu)
|
||||
static int kirkwood_cpufreq_target(struct cpufreq_policy *policy,
|
||||
unsigned int index)
|
||||
{
|
||||
struct cpufreq_freqs freqs;
|
||||
unsigned int state = kirkwood_freq_table[index].driver_data;
|
||||
unsigned long reg;
|
||||
|
||||
freqs.old = kirkwood_cpufreq_get_cpu_frequency(0);
|
||||
freqs.new = kirkwood_freq_table[index].frequency;
|
||||
local_irq_disable();
|
||||
|
||||
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",
|
||||
kirkwood_freq_table[index].frequency);
|
||||
dev_dbg(priv.dev, "old frequency was %i KHz\n",
|
||||
kirkwood_cpufreq_get_cpu_frequency(0));
|
||||
|
||||
if (freqs.old != freqs.new) {
|
||||
local_irq_disable();
|
||||
|
||||
/* 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 */
|
||||
cpu_do_idle();
|
||||
|
||||
/* Enable interrupts to the CPU */
|
||||
reg = readl_relaxed(priv.base);
|
||||
reg &= ~CPU_SW_INT_BLK;
|
||||
writel_relaxed(reg, priv.base);
|
||||
|
||||
local_irq_enable();
|
||||
switch (state) {
|
||||
case STATE_CPU_FREQ:
|
||||
clk_disable(priv.powersave_clk);
|
||||
break;
|
||||
case STATE_DDR_FREQ:
|
||||
clk_enable(priv.powersave_clk);
|
||||
break;
|
||||
}
|
||||
cpufreq_notify_transition(policy, &freqs, CPUFREQ_POSTCHANGE);
|
||||
|
||||
/* Wait-for-Interrupt, while the hardware changes frequency */
|
||||
cpu_do_idle();
|
||||
|
||||
/* Enable interrupts to the CPU */
|
||||
reg = readl_relaxed(priv.base);
|
||||
reg &= ~CPU_SW_INT_BLK;
|
||||
writel_relaxed(reg, priv.base);
|
||||
|
||||
local_irq_enable();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -57,7 +57,6 @@ static int loongson2_cpufreq_target(struct cpufreq_policy *policy,
|
||||
{
|
||||
unsigned int cpu = policy->cpu;
|
||||
cpumask_t cpus_allowed;
|
||||
struct cpufreq_freqs freqs;
|
||||
unsigned int freq;
|
||||
|
||||
cpus_allowed = current->cpus_allowed;
|
||||
@ -67,26 +66,11 @@ static int loongson2_cpufreq_target(struct cpufreq_policy *policy,
|
||||
((cpu_clock_freq / 1000) *
|
||||
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);
|
||||
|
||||
/* setting the cpu frequency */
|
||||
clk_set_rate(cpuclk, freq);
|
||||
|
||||
/* notifiers */
|
||||
cpufreq_notify_transition(policy, &freqs, CPUFREQ_POSTCHANGE);
|
||||
|
||||
pr_debug("cpufreq: set frequency %u kHz\n", freq);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -69,8 +69,6 @@ static struct cpufreq_frequency_table maple_cpu_freqs[] = {
|
||||
*/
|
||||
static int maple_pmode_cur;
|
||||
|
||||
static DEFINE_MUTEX(maple_switch_mutex);
|
||||
|
||||
static const u32 *maple_pmode_data;
|
||||
static int maple_pmode_max;
|
||||
|
||||
@ -133,21 +131,7 @@ static int maple_scom_query_freq(void)
|
||||
static int maple_cpufreq_target(struct cpufreq_policy *policy,
|
||||
unsigned int index)
|
||||
{
|
||||
struct cpufreq_freqs freqs;
|
||||
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;
|
||||
return maple_scom_switch_freq(index);
|
||||
}
|
||||
|
||||
static unsigned int maple_cpufreq_get_speed(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)
|
||||
{
|
||||
int r, ret = 0;
|
||||
struct cpufreq_freqs freqs;
|
||||
struct dev_pm_opp *opp;
|
||||
unsigned long freq, volt = 0, volt_old = 0, tol = 0;
|
||||
unsigned int old_freq, new_freq;
|
||||
|
||||
freqs.old = omap_getspeed(policy->cpu);
|
||||
freqs.new = freq_table[index].frequency;
|
||||
old_freq = omap_getspeed(policy->cpu);
|
||||
new_freq = freq_table[index].frequency;
|
||||
|
||||
freq = freqs.new * 1000;
|
||||
freq = new_freq * 1000;
|
||||
ret = clk_round_rate(mpu_clk, freq);
|
||||
if (IS_ERR_VALUE(ret)) {
|
||||
dev_warn(mpu_dev,
|
||||
@ -77,7 +76,7 @@ static int omap_target(struct cpufreq_policy *policy, unsigned int index)
|
||||
if (IS_ERR(opp)) {
|
||||
rcu_read_unlock();
|
||||
dev_err(mpu_dev, "%s: unable to find MPU OPP for %d\n",
|
||||
__func__, freqs.new);
|
||||
__func__, new_freq);
|
||||
return -EINVAL;
|
||||
}
|
||||
volt = dev_pm_opp_get_voltage(opp);
|
||||
@ -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",
|
||||
freqs.old / 1000, volt_old ? volt_old / 1000 : -1,
|
||||
freqs.new / 1000, volt ? volt / 1000 : -1);
|
||||
|
||||
/* notifiers */
|
||||
cpufreq_notify_transition(policy, &freqs, CPUFREQ_PRECHANGE);
|
||||
old_freq / 1000, volt_old ? volt_old / 1000 : -1,
|
||||
new_freq / 1000, volt ? volt / 1000 : -1);
|
||||
|
||||
/* 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);
|
||||
if (r < 0) {
|
||||
dev_warn(mpu_dev, "%s: unable to scale voltage up.\n",
|
||||
__func__);
|
||||
freqs.new = freqs.old;
|
||||
goto done;
|
||||
return r;
|
||||
}
|
||||
}
|
||||
|
||||
ret = clk_set_rate(mpu_clk, freqs.new * 1000);
|
||||
ret = clk_set_rate(mpu_clk, new_freq * 1000);
|
||||
|
||||
/* 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);
|
||||
if (r < 0) {
|
||||
dev_warn(mpu_dev, "%s: unable to scale voltage down.\n",
|
||||
__func__);
|
||||
ret = clk_set_rate(mpu_clk, freqs.old * 1000);
|
||||
freqs.new = freqs.old;
|
||||
goto done;
|
||||
clk_set_rate(mpu_clk, old_freq * 1000);
|
||||
return r;
|
||||
}
|
||||
}
|
||||
|
||||
freqs.new = omap_getspeed(policy->cpu);
|
||||
|
||||
done:
|
||||
/* notifiers */
|
||||
cpufreq_notify_transition(policy, &freqs, CPUFREQ_POSTCHANGE);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
@ -107,15 +107,8 @@ static struct cpufreq_frequency_table p4clockmod_table[] = {
|
||||
|
||||
static int cpufreq_p4_target(struct cpufreq_policy *policy, unsigned int index)
|
||||
{
|
||||
struct cpufreq_freqs freqs;
|
||||
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,
|
||||
* see section 13.15.3 of IA32 Intel Architecture Software
|
||||
* Developer's Manual, Volume 3
|
||||
@ -123,9 +116,6 @@ static int cpufreq_p4_target(struct cpufreq_policy *policy, unsigned int index)
|
||||
for_each_cpu(i, policy->cpus)
|
||||
cpufreq_p4_setdc(i, p4clockmod_table[index].driver_data);
|
||||
|
||||
/* notifiers */
|
||||
cpufreq_notify_transition(policy, &freqs, CPUFREQ_POSTCHANGE);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -51,8 +51,6 @@
|
||||
static void __iomem *sdcpwr_mapbase;
|
||||
static void __iomem *sdcasr_mapbase;
|
||||
|
||||
static DEFINE_MUTEX(pas_switch_mutex);
|
||||
|
||||
/* Current astate, is used when waking up from power savings on
|
||||
* one core, in case the other core has switched states during
|
||||
* the idle time.
|
||||
@ -242,15 +240,8 @@ static int pas_cpufreq_cpu_exit(struct cpufreq_policy *policy)
|
||||
static int pas_cpufreq_target(struct cpufreq_policy *policy,
|
||||
unsigned int pas_astate_new)
|
||||
{
|
||||
struct cpufreq_freqs freqs;
|
||||
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",
|
||||
policy->cpu,
|
||||
pas_freqs[pas_astate_new].frequency,
|
||||
@ -261,10 +252,7 @@ static int pas_cpufreq_target(struct cpufreq_policy *policy,
|
||||
for_each_online_cpu(i)
|
||||
set_astate(i, pas_astate_new);
|
||||
|
||||
cpufreq_notify_transition(policy, &freqs, CPUFREQ_POSTCHANGE);
|
||||
mutex_unlock(&pas_switch_mutex);
|
||||
|
||||
ppc_proc_freq = freqs.new * 1000ul;
|
||||
ppc_proc_freq = pas_freqs[pas_astate_new].frequency * 1000ul;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -331,21 +331,11 @@ static int pmu_set_cpu_speed(int low_speed)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int do_set_cpu_speed(struct cpufreq_policy *policy, int speed_mode,
|
||||
int notify)
|
||||
static int do_set_cpu_speed(struct cpufreq_policy *policy, int speed_mode)
|
||||
{
|
||||
struct cpufreq_freqs freqs;
|
||||
unsigned long 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 &&
|
||||
cpu_has_feature(CPU_FTR_L3CR)) {
|
||||
l3cr = _get_L3CR();
|
||||
@ -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)
|
||||
_set_L3CR(prev_l3cr);
|
||||
}
|
||||
if (notify)
|
||||
cpufreq_notify_transition(policy, &freqs, CPUFREQ_POSTCHANGE);
|
||||
cur_freq = (speed_mode == CPUFREQ_HIGH) ? hi_freq : low_freq;
|
||||
|
||||
return 0;
|
||||
@ -378,7 +366,7 @@ static int pmac_cpufreq_target( struct cpufreq_policy *policy,
|
||||
{
|
||||
int rc;
|
||||
|
||||
rc = do_set_cpu_speed(policy, index, 1);
|
||||
rc = do_set_cpu_speed(policy, index);
|
||||
|
||||
ppc_proc_freq = cur_freq * 1000ul;
|
||||
return rc;
|
||||
@ -420,7 +408,7 @@ static int pmac_cpufreq_suspend(struct cpufreq_policy *policy)
|
||||
no_schedule = 1;
|
||||
sleep_freq = cur_freq;
|
||||
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;
|
||||
}
|
||||
|
||||
@ -437,7 +425,7 @@ static int pmac_cpufreq_resume(struct cpufreq_policy *policy)
|
||||
* probably high speed due to our suspend() routine
|
||||
*/
|
||||
do_set_cpu_speed(policy, sleep_freq == low_freq ?
|
||||
CPUFREQ_LOW : CPUFREQ_HIGH, 0);
|
||||
CPUFREQ_LOW : CPUFREQ_HIGH);
|
||||
|
||||
ppc_proc_freq = cur_freq * 1000ul;
|
||||
|
||||
|
@ -79,8 +79,6 @@ static void (*g5_switch_volt)(int speed_mode);
|
||||
static int (*g5_switch_freq)(int speed_mode);
|
||||
static int (*g5_query_freq)(void);
|
||||
|
||||
static DEFINE_MUTEX(g5_switch_mutex);
|
||||
|
||||
static unsigned long transition_latency;
|
||||
|
||||
#ifdef CONFIG_PMAC_SMU
|
||||
@ -314,21 +312,7 @@ static int g5_pfunc_query_freq(void)
|
||||
|
||||
static int g5_cpufreq_target(struct cpufreq_policy *policy, unsigned int index)
|
||||
{
|
||||
struct cpufreq_freqs freqs;
|
||||
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;
|
||||
return g5_switch_freq(index);
|
||||
}
|
||||
|
||||
static unsigned int g5_cpufreq_get_speed(unsigned int cpu)
|
||||
|
@ -1204,6 +1204,7 @@ static unsigned int powernowk8_get(unsigned int cpu)
|
||||
}
|
||||
|
||||
static struct cpufreq_driver cpufreq_amd64_driver = {
|
||||
.flags = CPUFREQ_ASYNC_NOTIFICATION,
|
||||
.verify = cpufreq_generic_frequency_table_verify,
|
||||
.target_index = powernowk8_target,
|
||||
.bios_limit = acpi_processor_get_bios_limit,
|
||||
|
@ -69,8 +69,6 @@ static const struct soc_data sdata[] = {
|
||||
static u32 min_cpufreq;
|
||||
static const u32 *fmask;
|
||||
|
||||
/* serialize frequency changes */
|
||||
static DEFINE_MUTEX(cpufreq_lock);
|
||||
static DEFINE_PER_CPU(struct cpu_data *, cpu_data);
|
||||
|
||||
/* cpumask in a cluster */
|
||||
@ -253,26 +251,11 @@ static int __exit corenet_cpufreq_cpu_exit(struct cpufreq_policy *policy)
|
||||
static int corenet_cpufreq_target(struct cpufreq_policy *policy,
|
||||
unsigned int index)
|
||||
{
|
||||
struct cpufreq_freqs freqs;
|
||||
struct clk *parent;
|
||||
int ret;
|
||||
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);
|
||||
ret = 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;
|
||||
return clk_set_parent(data->clk, parent);
|
||||
}
|
||||
|
||||
static struct cpufreq_driver ppc_corenet_cpufreq_driver = {
|
||||
|
@ -30,9 +30,6 @@
|
||||
|
||||
#include "ppc_cbe_cpufreq.h"
|
||||
|
||||
static DEFINE_MUTEX(cbe_switch_mutex);
|
||||
|
||||
|
||||
/* the CBE supports an 8 step frequency scaling */
|
||||
static struct cpufreq_frequency_table cbe_freqs[] = {
|
||||
{1, 0},
|
||||
@ -131,27 +128,13 @@ static int cbe_cpufreq_cpu_init(struct cpufreq_policy *policy)
|
||||
static int cbe_cpufreq_target(struct cpufreq_policy *policy,
|
||||
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, " \
|
||||
"1/%d of max frequency\n",
|
||||
policy->cpu,
|
||||
cbe_freqs[cbe_pmode_new].frequency,
|
||||
cbe_freqs[cbe_pmode_new].driver_data);
|
||||
|
||||
rc = set_pmode(policy->cpu, cbe_pmode_new);
|
||||
|
||||
cpufreq_notify_transition(policy, &freqs, CPUFREQ_POSTCHANGE);
|
||||
mutex_unlock(&cbe_switch_mutex);
|
||||
|
||||
return rc;
|
||||
return set_pmode(policy->cpu, cbe_pmode_new);
|
||||
}
|
||||
|
||||
static struct cpufreq_driver cbe_cpufreq_driver = {
|
||||
|
@ -271,7 +271,6 @@ static int pxa_set_target(struct cpufreq_policy *policy, unsigned int idx)
|
||||
{
|
||||
struct cpufreq_frequency_table *pxa_freqs_table;
|
||||
pxa_freqs_t *pxa_freq_settings;
|
||||
struct cpufreq_freqs freqs;
|
||||
unsigned long flags;
|
||||
unsigned int new_freq_cpu, new_freq_mem;
|
||||
unsigned int unused, preset_mdrefr, postset_mdrefr, cclkcfg;
|
||||
@ -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_mem = pxa_freq_settings[idx].membus;
|
||||
freqs.old = policy->cur;
|
||||
freqs.new = new_freq_cpu;
|
||||
|
||||
if (freq_debug)
|
||||
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));
|
||||
|
||||
if (vcc_core && freqs.new > freqs.old)
|
||||
if (vcc_core && new_freq_cpu > policy->cur) {
|
||||
ret = pxa_cpufreq_change_voltage(&pxa_freq_settings[idx]);
|
||||
if (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);
|
||||
if (ret)
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* 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
|
||||
@ -349,13 +341,6 @@ static int pxa_set_target(struct cpufreq_policy *policy, unsigned int idx)
|
||||
: "r4", "r5");
|
||||
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
|
||||
* 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)
|
||||
* bug is triggered (seems a deadlock). Should anybody find out where,
|
||||
* 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]);
|
||||
|
||||
return 0;
|
||||
|
@ -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)
|
||||
{
|
||||
struct pxa3xx_freq_info *next;
|
||||
struct cpufreq_freqs freqs;
|
||||
unsigned long flags;
|
||||
|
||||
if (policy->cpu != 0)
|
||||
@ -166,22 +165,11 @@ static int pxa3xx_cpufreq_set(struct cpufreq_policy *policy, unsigned int 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);
|
||||
__update_core_freq(next);
|
||||
__update_bus_freq(next);
|
||||
local_irq_restore(flags);
|
||||
|
||||
cpufreq_notify_transition(policy, &freqs, CPUFREQ_POSTCHANGE);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -220,7 +220,7 @@ static int s3c2416_cpufreq_set_target(struct cpufreq_policy *policy,
|
||||
unsigned int index)
|
||||
{
|
||||
struct s3c2416_data *s3c_freq = &s3c2416_cpufreq;
|
||||
struct cpufreq_freqs freqs;
|
||||
unsigned int new_freq;
|
||||
int idx, ret, to_dvs = 0;
|
||||
|
||||
mutex_lock(&cpufreq_lock);
|
||||
@ -237,25 +237,14 @@ static int s3c2416_cpufreq_set_target(struct cpufreq_policy *policy,
|
||||
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
|
||||
* The S3C2416 has stability issues when switching directly to
|
||||
* 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
|
||||
: 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) {
|
||||
pr_debug("cpufreq: enter dvs\n");
|
||||
ret = s3c2416_cpufreq_enter_dvs(s3c_freq, idx);
|
||||
@ -263,12 +252,10 @@ static int s3c2416_cpufreq_set_target(struct cpufreq_policy *policy,
|
||||
pr_debug("cpufreq: leave dvs\n");
|
||||
ret = s3c2416_cpufreq_leave_dvs(s3c_freq, idx);
|
||||
} else {
|
||||
pr_debug("cpufreq: change armdiv to %dkHz\n", freqs.new);
|
||||
ret = s3c2416_cpufreq_set_armdiv(s3c_freq, freqs.new);
|
||||
pr_debug("cpufreq: change armdiv to %dkHz\n", new_freq);
|
||||
ret = s3c2416_cpufreq_set_armdiv(s3c_freq, new_freq);
|
||||
}
|
||||
|
||||
cpufreq_notify_transition(policy, &freqs, CPUFREQ_POSTCHANGE);
|
||||
|
||||
out:
|
||||
mutex_unlock(&cpufreq_lock);
|
||||
|
||||
|
@ -65,54 +65,46 @@ static unsigned int s3c64xx_cpufreq_get_speed(unsigned int cpu)
|
||||
static int s3c64xx_cpufreq_set_target(struct cpufreq_policy *policy,
|
||||
unsigned int index)
|
||||
{
|
||||
int ret;
|
||||
struct cpufreq_freqs freqs;
|
||||
struct s3c64xx_dvfs *dvfs;
|
||||
unsigned int old_freq, new_freq;
|
||||
int ret;
|
||||
|
||||
freqs.old = clk_get_rate(armclk) / 1000;
|
||||
freqs.new = s3c64xx_freq_table[index].frequency;
|
||||
freqs.flags = 0;
|
||||
old_freq = clk_get_rate(armclk) / 1000;
|
||||
new_freq = s3c64xx_freq_table[index].frequency;
|
||||
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
|
||||
if (vddarm && freqs.new > freqs.old) {
|
||||
if (vddarm && new_freq > old_freq) {
|
||||
ret = regulator_set_voltage(vddarm,
|
||||
dvfs->vddarm_min,
|
||||
dvfs->vddarm_max);
|
||||
if (ret != 0) {
|
||||
pr_err("Failed to set VDDARM for %dkHz: %d\n",
|
||||
freqs.new, ret);
|
||||
freqs.new = freqs.old;
|
||||
goto post_notify;
|
||||
new_freq, ret);
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
ret = clk_set_rate(armclk, freqs.new * 1000);
|
||||
ret = clk_set_rate(armclk, new_freq * 1000);
|
||||
if (ret < 0) {
|
||||
pr_err("Failed to set rate %dkHz: %d\n",
|
||||
freqs.new, ret);
|
||||
freqs.new = freqs.old;
|
||||
new_freq, ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
post_notify:
|
||||
cpufreq_notify_transition(policy, &freqs, CPUFREQ_POSTCHANGE);
|
||||
if (ret)
|
||||
goto err;
|
||||
|
||||
#ifdef CONFIG_REGULATOR
|
||||
if (vddarm && freqs.new < freqs.old) {
|
||||
if (vddarm && new_freq < old_freq) {
|
||||
ret = regulator_set_voltage(vddarm,
|
||||
dvfs->vddarm_min,
|
||||
dvfs->vddarm_max);
|
||||
if (ret != 0) {
|
||||
pr_err("Failed to set VDDARM for %dkHz: %d\n",
|
||||
freqs.new, ret);
|
||||
goto err_clk;
|
||||
new_freq, ret);
|
||||
if (clk_set_rate(armclk, old_freq * 1000) < 0)
|
||||
pr_err("Failed to restore original clock rate\n");
|
||||
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
@ -121,14 +113,6 @@ static int s3c64xx_cpufreq_set_target(struct cpufreq_policy *policy,
|
||||
clk_get_rate(armclk) / 1000);
|
||||
|
||||
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
|
||||
|
@ -26,7 +26,6 @@
|
||||
static struct clk *cpu_clk;
|
||||
static struct clk *dmc0_clk;
|
||||
static struct clk *dmc1_clk;
|
||||
static struct cpufreq_freqs freqs;
|
||||
static DEFINE_MUTEX(set_freq_lock);
|
||||
|
||||
/* APLL M,P,S values for 1G/800Mhz */
|
||||
@ -179,6 +178,7 @@ static int s5pv210_target(struct cpufreq_policy *policy, unsigned int index)
|
||||
unsigned int priv_index;
|
||||
unsigned int pll_changing = 0;
|
||||
unsigned int bus_speed_changing = 0;
|
||||
unsigned int old_freq, new_freq;
|
||||
int arm_volt, int_volt;
|
||||
int ret = 0;
|
||||
|
||||
@ -193,12 +193,12 @@ static int s5pv210_target(struct cpufreq_policy *policy, unsigned int index)
|
||||
goto exit;
|
||||
}
|
||||
|
||||
freqs.old = s5pv210_getspeed(0);
|
||||
freqs.new = s5pv210_freq_table[index].frequency;
|
||||
old_freq = s5pv210_getspeed(0);
|
||||
new_freq = s5pv210_freq_table[index].frequency;
|
||||
|
||||
/* Finding current running level index */
|
||||
if (cpufreq_frequency_table_target(policy, s5pv210_freq_table,
|
||||
freqs.old, CPUFREQ_RELATION_H,
|
||||
old_freq, CPUFREQ_RELATION_H,
|
||||
&priv_index)) {
|
||||
ret = -EINVAL;
|
||||
goto exit;
|
||||
@ -207,7 +207,7 @@ static int s5pv210_target(struct cpufreq_policy *policy, unsigned int index)
|
||||
arm_volt = dvs_conf[index].arm_volt;
|
||||
int_volt = dvs_conf[index].int_volt;
|
||||
|
||||
if (freqs.new > freqs.old) {
|
||||
if (new_freq > old_freq) {
|
||||
ret = regulator_set_voltage(arm_regulator,
|
||||
arm_volt, arm_volt_max);
|
||||
if (ret)
|
||||
@ -219,8 +219,6 @@ static int s5pv210_target(struct cpufreq_policy *policy, unsigned int index)
|
||||
goto exit;
|
||||
}
|
||||
|
||||
cpufreq_notify_transition(policy, &freqs, CPUFREQ_PRECHANGE);
|
||||
|
||||
/* Check if there need to change PLL */
|
||||
if ((index == L0) || (priv_index == L0))
|
||||
pll_changing = 1;
|
||||
@ -431,9 +429,7 @@ static int s5pv210_target(struct cpufreq_policy *policy, unsigned int index)
|
||||
}
|
||||
}
|
||||
|
||||
cpufreq_notify_transition(policy, &freqs, CPUFREQ_POSTCHANGE);
|
||||
|
||||
if (freqs.new < freqs.old) {
|
||||
if (new_freq < old_freq) {
|
||||
regulator_set_voltage(int_regulator,
|
||||
int_volt, int_volt_max);
|
||||
|
||||
|
@ -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)
|
||||
{
|
||||
unsigned int cur = sa11x0_getspeed(0);
|
||||
struct cpufreq_freqs freqs;
|
||||
unsigned int new_freq;
|
||||
|
||||
freqs.old = cur;
|
||||
freqs.new = sa11x0_freq_table[ppcr].frequency;
|
||||
new_freq = sa11x0_freq_table[ppcr].frequency;
|
||||
|
||||
cpufreq_notify_transition(policy, &freqs, CPUFREQ_PRECHANGE);
|
||||
|
||||
if (freqs.new > cur)
|
||||
sa1100_update_dram_timings(cur, freqs.new);
|
||||
if (new_freq > cur)
|
||||
sa1100_update_dram_timings(cur, new_freq);
|
||||
|
||||
PPCR = ppcr;
|
||||
|
||||
if (freqs.new < cur)
|
||||
sa1100_update_dram_timings(cur, freqs.new);
|
||||
|
||||
cpufreq_notify_transition(policy, &freqs, CPUFREQ_POSTCHANGE);
|
||||
if (new_freq < cur)
|
||||
sa1100_update_dram_timings(cur, new_freq);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -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)
|
||||
{
|
||||
struct sdram_params *sdram = &sdram_params;
|
||||
struct cpufreq_freqs freqs;
|
||||
struct sdram_info sd;
|
||||
unsigned long flags;
|
||||
unsigned int unused;
|
||||
|
||||
freqs.old = sa11x0_getspeed(0);
|
||||
freqs.new = sa11x0_freq_table[ppcr].frequency;
|
||||
|
||||
sdram_calculate_timing(&sd, freqs.new, sdram);
|
||||
sdram_calculate_timing(&sd, sa11x0_freq_table[ppcr].frequency, sdram);
|
||||
|
||||
#if 0
|
||||
/*
|
||||
@ -259,8 +255,6 @@ static int sa1110_target(struct cpufreq_policy *policy, unsigned int ppcr)
|
||||
sd.mdcas[2] = 0xaaaaaaaa;
|
||||
#endif
|
||||
|
||||
cpufreq_notify_transition(policy, &freqs, CPUFREQ_PRECHANGE);
|
||||
|
||||
/*
|
||||
* The clock could be going away for some time. Set the SDRAMs
|
||||
* 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)
|
||||
/*
|
||||
* Now, return the SDRAM refresh back to normal.
|
||||
*/
|
||||
sdram_update_refresh(freqs.new, sdram);
|
||||
|
||||
cpufreq_notify_transition(policy, &freqs, CPUFREQ_POSTCHANGE);
|
||||
sdram_update_refresh(sa11x0_freq_table[ppcr].frequency, sdram);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -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)
|
||||
{
|
||||
|
||||
struct cpufreq_freqs freqs;
|
||||
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();
|
||||
|
||||
clockspeed_reg = *cpuctl & ~0x03;
|
||||
@ -74,8 +65,6 @@ static int sc520_freq_target(struct cpufreq_policy *policy, unsigned int state)
|
||||
|
||||
local_irq_enable();
|
||||
|
||||
cpufreq_notify_transition(policy, &freqs, CPUFREQ_POSTCHANGE);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -251,7 +251,6 @@ static int us2e_freq_target(struct cpufreq_policy *policy, unsigned int index)
|
||||
unsigned long new_bits, new_freq;
|
||||
unsigned long clock_tick, divisor, old_divisor, estar;
|
||||
cpumask_t cpus_allowed;
|
||||
struct cpufreq_freqs freqs;
|
||||
|
||||
cpumask_copy(&cpus_allowed, tsk_cpus_allowed(current));
|
||||
set_cpus_allowed_ptr(current, cpumask_of(cpu));
|
||||
@ -265,16 +264,10 @@ static int us2e_freq_target(struct cpufreq_policy *policy, unsigned int index)
|
||||
|
||||
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)
|
||||
us2e_transition(estar, new_bits, clock_tick * 1000,
|
||||
old_divisor, divisor);
|
||||
|
||||
cpufreq_notify_transition(policy, &freqs, CPUFREQ_POSTCHANGE);
|
||||
|
||||
set_cpus_allowed_ptr(current, &cpus_allowed);
|
||||
|
||||
return 0;
|
||||
|
@ -98,7 +98,6 @@ static int us3_freq_target(struct cpufreq_policy *policy, unsigned int index)
|
||||
unsigned int cpu = policy->cpu;
|
||||
unsigned long new_bits, new_freq, reg;
|
||||
cpumask_t cpus_allowed;
|
||||
struct cpufreq_freqs freqs;
|
||||
|
||||
cpumask_copy(&cpus_allowed, tsk_cpus_allowed(current));
|
||||
set_cpus_allowed_ptr(current, cpumask_of(cpu));
|
||||
@ -124,16 +123,10 @@ static int us3_freq_target(struct cpufreq_policy *policy, unsigned int index)
|
||||
|
||||
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 |= new_bits;
|
||||
write_safari_cfg(reg);
|
||||
|
||||
cpufreq_notify_transition(policy, &freqs, CPUFREQ_POSTCHANGE);
|
||||
|
||||
set_cpus_allowed_ptr(current, &cpus_allowed);
|
||||
|
||||
return 0;
|
||||
|
@ -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,
|
||||
unsigned int index)
|
||||
{
|
||||
struct cpufreq_freqs freqs;
|
||||
long newfreq;
|
||||
struct clk *srcclk;
|
||||
int ret, mult = 1;
|
||||
|
||||
freqs.old = spear_cpufreq_get(0);
|
||||
newfreq = spear_cpufreq.freq_tbl[index].frequency * 1000;
|
||||
|
||||
if (of_machine_is_compatible("st,spear1340")) {
|
||||
@ -145,23 +143,14 @@ static int spear_cpufreq_target(struct cpufreq_policy *policy,
|
||||
return newfreq;
|
||||
}
|
||||
|
||||
freqs.new = newfreq / 1000;
|
||||
freqs.new /= mult;
|
||||
|
||||
cpufreq_notify_transition(policy, &freqs, CPUFREQ_PRECHANGE);
|
||||
|
||||
if (mult == 2)
|
||||
ret = spear1340_set_cpu_rate(srcclk, newfreq);
|
||||
else
|
||||
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);
|
||||
freqs.new = clk_get_rate(spear_cpufreq.clk) / 1000;
|
||||
}
|
||||
|
||||
cpufreq_notify_transition(policy, &freqs, CPUFREQ_POSTCHANGE);
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
@ -423,9 +423,8 @@ static int centrino_cpu_exit(struct cpufreq_policy *policy)
|
||||
static int centrino_target(struct cpufreq_policy *policy, unsigned int index)
|
||||
{
|
||||
unsigned int msr, oldmsr = 0, h = 0, cpu = policy->cpu;
|
||||
struct cpufreq_freqs freqs;
|
||||
int retval = 0;
|
||||
unsigned int j, first_cpu, tmp;
|
||||
unsigned int j, first_cpu;
|
||||
struct cpufreq_frequency_table *op_points;
|
||||
cpumask_var_t covered_cpus;
|
||||
|
||||
@ -473,16 +472,6 @@ static int centrino_target(struct cpufreq_policy *policy, unsigned int index)
|
||||
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;
|
||||
/* all but 16 LSB are reserved, treat them with care */
|
||||
oldmsr &= ~0xffff;
|
||||
@ -497,8 +486,6 @@ static int centrino_target(struct cpufreq_policy *policy, unsigned int index)
|
||||
cpumask_set_cpu(j, covered_cpus);
|
||||
}
|
||||
|
||||
cpufreq_notify_transition(policy, &freqs, CPUFREQ_POSTCHANGE);
|
||||
|
||||
if (unlikely(retval)) {
|
||||
/*
|
||||
* We have failed halfway through the frequency change.
|
||||
@ -509,12 +496,6 @@ static int centrino_target(struct cpufreq_policy *policy, unsigned int index)
|
||||
|
||||
for_each_cpu(j, covered_cpus)
|
||||
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;
|
||||
|
||||
|
@ -258,21 +258,12 @@ static unsigned int speedstep_get(unsigned int cpu)
|
||||
static int speedstep_target(struct cpufreq_policy *policy, unsigned int index)
|
||||
{
|
||||
unsigned int policy_cpu;
|
||||
struct cpufreq_freqs freqs;
|
||||
|
||||
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,
|
||||
true);
|
||||
|
||||
cpufreq_notify_transition(policy, &freqs, CPUFREQ_POSTCHANGE);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -241,14 +241,7 @@ static void speedstep_set_state(unsigned int state)
|
||||
*/
|
||||
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);
|
||||
cpufreq_notify_transition(policy, &freqs, CPUFREQ_POSTCHANGE);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -102,12 +102,8 @@ static int tegra_update_cpu_speed(struct cpufreq_policy *policy,
|
||||
unsigned long rate)
|
||||
{
|
||||
int ret = 0;
|
||||
struct cpufreq_freqs freqs;
|
||||
|
||||
freqs.old = tegra_getspeed(0);
|
||||
freqs.new = rate;
|
||||
|
||||
if (freqs.old == freqs.new)
|
||||
if (tegra_getspeed(0) == rate)
|
||||
return ret;
|
||||
|
||||
/*
|
||||
@ -121,21 +117,10 @@ static int tegra_update_cpu_speed(struct cpufreq_policy *policy,
|
||||
else
|
||||
clk_set_rate(emc_clk, 100000000); /* emc 50Mhz */
|
||||
|
||||
cpufreq_notify_transition(policy, &freqs, CPUFREQ_PRECHANGE);
|
||||
|
||||
#ifdef CONFIG_CPU_FREQ_DEBUG
|
||||
printk(KERN_DEBUG "cpufreq-tegra: transition: %u --> %u\n",
|
||||
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);
|
||||
ret = tegra_cpu_clk_set_rate(rate * 1000);
|
||||
if (ret)
|
||||
pr_err("cpu-tegra: Failed to set cpu frequency to %lu kHz\n",
|
||||
rate);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
70
drivers/cpufreq/vexpress-spc-cpufreq.c
Normal file
70
drivers/cpufreq/vexpress-spc-cpufreq.c
Normal file
@ -0,0 +1,70 @@
|
||||
/*
|
||||
* 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 {
|
||||
*/
|
||||
#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_unregister_driver(struct cpufreq_driver *driver_data);
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user