Skip to content

Commit

Permalink
Merge branch 'next' of git://github.com/kernelslacker/cpufreq
Browse files Browse the repository at this point in the history
* 'next' of git://github.com/kernelslacker/cpufreq:
  [CPUFREQ] db8500: support all frequencies
  [CPUFREQ] db8500: remove unneeded for loop iteration over freq_table
  [CPUFREQ] ARM Exynos4210 PM/Suspend compatibility with different bootloaders
  [CPUFREQ] ARM: ux500: send cpufreq notification for all cpus
  [CPUFREQ] e_powersaver: Allow user to lower maximum voltage
  [CPUFREQ] e_powersaver: Check BIOS limit for CPU frequency
  [CPUFREQ] e_powersaver: Additional checks
  [CPUFREQ] exynos4210: Show list of available frequencies
  • Loading branch information
Linus Torvalds committed Nov 3, 2011
2 parents a0a4194 + 6283e32 commit 70c9f18
Show file tree
Hide file tree
Showing 3 changed files with 268 additions and 32 deletions.
36 changes: 20 additions & 16 deletions drivers/cpufreq/db8500-cpufreq.c
Original file line number Diff line number Diff line change
Expand Up @@ -18,24 +18,29 @@
static struct cpufreq_frequency_table freq_table[] = {
[0] = {
.index = 0,
.frequency = 300000,
.frequency = 200000,
},
[1] = {
.index = 1,
.frequency = 600000,
.frequency = 300000,
},
[2] = {
/* Used for MAX_OPP, if available */
.index = 2,
.frequency = CPUFREQ_TABLE_END,
.frequency = 600000,
},
[3] = {
/* Used for MAX_OPP, if available */
.index = 3,
.frequency = CPUFREQ_TABLE_END,
},
[4] = {
.index = 4,
.frequency = CPUFREQ_TABLE_END,
},
};

static enum arm_opp idx2opp[] = {
ARM_EXTCLK,
ARM_50_OPP,
ARM_100_OPP,
ARM_MAX_OPP
Expand Down Expand Up @@ -72,13 +77,13 @@ static int db8500_cpufreq_target(struct cpufreq_policy *policy,

freqs.old = policy->cur;
freqs.new = freq_table[idx].frequency;
freqs.cpu = policy->cpu;

if (freqs.old == freqs.new)
return 0;

/* pre-change notification */
cpufreq_notify_transition(&freqs, CPUFREQ_PRECHANGE);
for_each_cpu(freqs.cpu, policy->cpus)
cpufreq_notify_transition(&freqs, CPUFREQ_PRECHANGE);

/* request the PRCM unit for opp change */
if (prcmu_set_arm_opp(idx2opp[idx])) {
Expand All @@ -87,7 +92,8 @@ static int db8500_cpufreq_target(struct cpufreq_policy *policy,
}

/* post change notification */
cpufreq_notify_transition(&freqs, CPUFREQ_POSTCHANGE);
for_each_cpu(freqs.cpu, policy->cpus)
cpufreq_notify_transition(&freqs, CPUFREQ_POSTCHANGE);

return 0;
}
Expand All @@ -104,16 +110,18 @@ static unsigned int db8500_cpufreq_getspeed(unsigned int cpu)
static int __cpuinit db8500_cpufreq_init(struct cpufreq_policy *policy)
{
int res;
int i;

BUILD_BUG_ON(ARRAY_SIZE(idx2opp) + 1 != ARRAY_SIZE(freq_table));

if (cpu_is_u8500v2() && !prcmu_is_u8400()) {
freq_table[0].frequency = 400000;
freq_table[1].frequency = 800000;
if (!prcmu_is_u8400()) {
freq_table[1].frequency = 400000;
freq_table[2].frequency = 800000;
if (prcmu_has_arm_maxopp())
freq_table[2].frequency = 1000000;
freq_table[3].frequency = 1000000;
}
pr_info("db8500-cpufreq : Available frequencies:\n");
while (freq_table[i].frequency != CPUFREQ_TABLE_END)
pr_info(" %d Mhz\n", freq_table[i++].frequency/1000);

/* get policy fields based on the table */
res = cpufreq_frequency_table_cpuinfo(policy, freq_table);
Expand All @@ -127,10 +135,6 @@ static int __cpuinit db8500_cpufreq_init(struct cpufreq_policy *policy)
policy->min = policy->cpuinfo.min_freq;
policy->max = policy->cpuinfo.max_freq;
policy->cur = db8500_cpufreq_getspeed(policy->cpu);

for (i = 0; freq_table[i].frequency != policy->cur; i++)
;

policy->governor = CPUFREQ_DEFAULT_GOVERNOR;

/*
Expand Down
135 changes: 124 additions & 11 deletions drivers/cpufreq/e_powersaver.c
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,11 @@
#include <asm/msr.h>
#include <asm/tsc.h>

#if defined CONFIG_ACPI_PROCESSOR || defined CONFIG_ACPI_PROCESSOR_MODULE
#include <linux/acpi.h>
#include <acpi/processor.h>
#endif

#define EPS_BRAND_C7M 0
#define EPS_BRAND_C7 1
#define EPS_BRAND_EDEN 2
Expand All @@ -27,11 +32,59 @@

struct eps_cpu_data {
u32 fsb;
#if defined CONFIG_ACPI_PROCESSOR || defined CONFIG_ACPI_PROCESSOR_MODULE
u32 bios_limit;
#endif
struct cpufreq_frequency_table freq_table[];
};

static struct eps_cpu_data *eps_cpu[NR_CPUS];

/* Module parameters */
static int freq_failsafe_off;
static int voltage_failsafe_off;
static int set_max_voltage;

#if defined CONFIG_ACPI_PROCESSOR || defined CONFIG_ACPI_PROCESSOR_MODULE
static int ignore_acpi_limit;

static struct acpi_processor_performance *eps_acpi_cpu_perf;

/* Minimum necessary to get acpi_processor_get_bios_limit() working */
static int eps_acpi_init(void)
{
eps_acpi_cpu_perf = kzalloc(sizeof(struct acpi_processor_performance),
GFP_KERNEL);
if (!eps_acpi_cpu_perf)
return -ENOMEM;

if (!zalloc_cpumask_var(&eps_acpi_cpu_perf->shared_cpu_map,
GFP_KERNEL)) {
kfree(eps_acpi_cpu_perf);
eps_acpi_cpu_perf = NULL;
return -ENOMEM;
}

if (acpi_processor_register_performance(eps_acpi_cpu_perf, 0)) {
free_cpumask_var(eps_acpi_cpu_perf->shared_cpu_map);
kfree(eps_acpi_cpu_perf);
eps_acpi_cpu_perf = NULL;
return -EIO;
}
return 0;
}

static int eps_acpi_exit(struct cpufreq_policy *policy)
{
if (eps_acpi_cpu_perf) {
acpi_processor_unregister_performance(eps_acpi_cpu_perf, 0);
free_cpumask_var(eps_acpi_cpu_perf->shared_cpu_map);
kfree(eps_acpi_cpu_perf);
eps_acpi_cpu_perf = NULL;
}
return 0;
}
#endif

static unsigned int eps_get(unsigned int cpu)
{
Expand Down Expand Up @@ -164,6 +217,9 @@ static int eps_cpu_init(struct cpufreq_policy *policy)
int k, step, voltage;
int ret;
int states;
#if defined CONFIG_ACPI_PROCESSOR || defined CONFIG_ACPI_PROCESSOR_MODULE
unsigned int limit;
#endif

if (policy->cpu != 0)
return -ENODEV;
Expand Down Expand Up @@ -244,11 +300,62 @@ static int eps_cpu_init(struct cpufreq_policy *policy)
return -EINVAL;
if (current_voltage > 0x1f || max_voltage > 0x1f)
return -EINVAL;
if (max_voltage < min_voltage)
if (max_voltage < min_voltage
|| current_voltage < min_voltage
|| current_voltage > max_voltage)
return -EINVAL;

/* Check for systems using underclocked CPU */
if (!freq_failsafe_off && max_multiplier != current_multiplier) {
printk(KERN_INFO "eps: Your processor is running at different "
"frequency then its maximum. Aborting.\n");
printk(KERN_INFO "eps: You can use freq_failsafe_off option "
"to disable this check.\n");
return -EINVAL;
}
if (!voltage_failsafe_off && max_voltage != current_voltage) {
printk(KERN_INFO "eps: Your processor is running at different "
"voltage then its maximum. Aborting.\n");
printk(KERN_INFO "eps: You can use voltage_failsafe_off "
"option to disable this check.\n");
return -EINVAL;
}

/* Calc FSB speed */
fsb = cpu_khz / current_multiplier;

#if defined CONFIG_ACPI_PROCESSOR || defined CONFIG_ACPI_PROCESSOR_MODULE
/* Check for ACPI processor speed limit */
if (!ignore_acpi_limit && !eps_acpi_init()) {
if (!acpi_processor_get_bios_limit(policy->cpu, &limit)) {
printk(KERN_INFO "eps: ACPI limit %u.%uGHz\n",
limit/1000000,
(limit%1000000)/10000);
eps_acpi_exit(policy);
/* Check if max_multiplier is in BIOS limits */
if (limit && max_multiplier * fsb > limit) {
printk(KERN_INFO "eps: Aborting.\n");
return -EINVAL;
}
}
}
#endif

/* Allow user to set lower maximum voltage then that reported
* by processor */
if (brand == EPS_BRAND_C7M && set_max_voltage) {
u32 v;

/* Change mV to something hardware can use */
v = (set_max_voltage - 700) / 16;
/* Check if voltage is within limits */
if (v >= min_voltage && v <= max_voltage) {
printk(KERN_INFO "eps: Setting %dmV as maximum.\n",
v * 16 + 700);
max_voltage = v;
}
}

/* Calc number of p-states supported */
if (brand == EPS_BRAND_C7M)
states = max_multiplier - min_multiplier + 1;
Expand All @@ -265,6 +372,9 @@ static int eps_cpu_init(struct cpufreq_policy *policy)

/* Copy basic values */
centaur->fsb = fsb;
#if defined CONFIG_ACPI_PROCESSOR || defined CONFIG_ACPI_PROCESSOR_MODULE
centaur->bios_limit = limit;
#endif

/* Fill frequency and MSR value table */
f_table = &centaur->freq_table[0];
Expand Down Expand Up @@ -303,17 +413,7 @@ static int eps_cpu_init(struct cpufreq_policy *policy)
static int eps_cpu_exit(struct cpufreq_policy *policy)
{
unsigned int cpu = policy->cpu;
struct eps_cpu_data *centaur;
u32 lo, hi;

if (eps_cpu[cpu] == NULL)
return -ENODEV;
centaur = eps_cpu[cpu];

/* Get max frequency */
rdmsr(MSR_IA32_PERF_STATUS, lo, hi);
/* Set max frequency */
eps_set_state(centaur, cpu, hi & 0xffff);
/* Bye */
cpufreq_frequency_table_put_attr(policy->cpu);
kfree(eps_cpu[cpu]);
Expand Down Expand Up @@ -359,6 +459,19 @@ static void __exit eps_exit(void)
cpufreq_unregister_driver(&eps_driver);
}

/* Allow user to overclock his machine or to change frequency to higher after
* unloading module */
module_param(freq_failsafe_off, int, 0644);
MODULE_PARM_DESC(freq_failsafe_off, "Disable current vs max frequency check");
module_param(voltage_failsafe_off, int, 0644);
MODULE_PARM_DESC(voltage_failsafe_off, "Disable current vs max voltage check");
#if defined CONFIG_ACPI_PROCESSOR || defined CONFIG_ACPI_PROCESSOR_MODULE
module_param(ignore_acpi_limit, int, 0644);
MODULE_PARM_DESC(ignore_acpi_limit, "Don't check ACPI's processor speed limit");
#endif
module_param(set_max_voltage, int, 0644);
MODULE_PARM_DESC(set_max_voltage, "Set maximum CPU voltage (mV) C7-M only");

MODULE_AUTHOR("Rafal Bilski <rafalbilski@interia.pl>");
MODULE_DESCRIPTION("Enhanced PowerSaver driver for VIA C7 CPU's.");
MODULE_LICENSE("GPL");
Expand Down
Loading

0 comments on commit 70c9f18

Please sign in to comment.