Commit bdfd71e6 authored by Russell King's avatar Russell King

[CPUFREQ] Update ARM CPUFREQ drivers

A 4 patch set from Dominik Brodowski, tested and fixed up by rmk
for ARM.

(1)

- the system3.c cpufreq notifier couldn't possibly compile before because
      cpufreq_updateminmax has been undefined for ages.
- clean up sa1100fb.c notifier to specify exactly what's left TBD.
- double #include of cpufreq.c in drivers/pcmcia/sa1100_generic.c

(2)

Split up config symbols, add help text for CPU_FREQ_PROC_INTF

(3)

- update the Integrator CPUfreq driver so that it can get along with
  cpufreq policies.
- modularize Integrator CPUfreq driver (all it did with
  !CONFIG_CPU_FREQ was to print out some debug information)

(4)

- update the SA11x0 CPUfreq drivers so that they can get along with
  cpufreq policies and governors.
- update the cpufreq core so that cpufreq_get() returns something
  sensible during the first ->setpolicy or ->target call.
parent e3c33e3b
...@@ -534,15 +534,43 @@ config CPU_FREQ ...@@ -534,15 +534,43 @@ config CPU_FREQ
written) to implement the policy. If you don't understand what this written) to implement the policy. If you don't understand what this
is all about, it's safe to say 'N'. is all about, it's safe to say 'N'.
config CPU_FREQ_SA1100
bool
depends on CPU_FREQ && SA1100_LART
default y
config CPU_FREQ_SA1110
bool
depends on CPU_FREQ && (SA1100_ASSABET || SA1100_CERF || SA1100_PT_SYSTEM3)
default y
config CPU_FREQ_INTEGRATOR
tristate "CPUfreq driver for ARM Integrator CPUs"
depends on ARCH_INTEGRATOR && CPU_FREQ
default y
help
This enables the CPUfreq driver for ARM Integrator CPUs.
For details, take a look at linux/Documentation/cpufreq.
If in doubt, say Y.
config CPU_FREQ_24_API config CPU_FREQ_24_API
bool bool
depends on CPU_FREQ depends on CPU_FREQ
default y default y
config CPU_FREQ_PROC_INTF config CPU_FREQ_PROC_INTF
tristate tristate "/proc/cpufreq interface (deprecated)"
depends on CPU_FREQ depends on CPU_FREQ && PROC_FS
default y help
This enables the /proc/cpufreq interface for controlling
CPUFreq. Please note that it is recommended to use the sysfs
interface instead (which is built automatically).
For details, take a look at linux/Documentation/cpufreq.
If in doubt, say N.
source "drivers/pci/Kconfig" source "drivers/pci/Kconfig"
......
...@@ -4,10 +4,11 @@ ...@@ -4,10 +4,11 @@
# Object file lists. # Object file lists.
obj-y := arch.o cpu.o irq.o mm.o time.o obj-y := arch.o irq.o mm.o time.o
obj-m := obj-m :=
obj-n := obj-n :=
obj- := obj- :=
obj-$(CONFIG_LEDS) += leds.o obj-$(CONFIG_LEDS) += leds.o
obj-$(CONFIG_PCI) += pci_v3.o pci.o obj-$(CONFIG_PCI) += pci_v3.o pci.o
obj-$(CONFIG_CPU_FREQ_INTEGRATOR) += cpu.o
...@@ -23,6 +23,8 @@ ...@@ -23,6 +23,8 @@
#include <asm/hardware.h> #include <asm/hardware.h>
#include <asm/io.h> #include <asm/io.h>
static struct cpufreq_driver integrator_driver;
#define CM_ID (IO_ADDRESS(INTEGRATOR_HDR_BASE)+INTEGRATOR_HDR_ID_OFFSET) #define CM_ID (IO_ADDRESS(INTEGRATOR_HDR_BASE)+INTEGRATOR_HDR_ID_OFFSET)
#define CM_OSC (IO_ADDRESS(INTEGRATOR_HDR_BASE)+INTEGRATOR_HDR_OSC_OFFSET) #define CM_OSC (IO_ADDRESS(INTEGRATOR_HDR_BASE)+INTEGRATOR_HDR_OSC_OFFSET)
#define CM_STAT (IO_ADDRESS(INTEGRATOR_HDR_BASE)+INTEGRATOR_HDR_STAT_OFFSET) #define CM_STAT (IO_ADDRESS(INTEGRATOR_HDR_BASE)+INTEGRATOR_HDR_STAT_OFFSET)
...@@ -43,7 +45,6 @@ static unsigned int vco_to_freq(struct vco vco, int factor) ...@@ -43,7 +45,6 @@ static unsigned int vco_to_freq(struct vco vco, int factor)
return 2000 * (vco.vdw + 8) / cc_divisor[vco.od] / factor; return 2000 * (vco.vdw + 8) / cc_divisor[vco.od] / factor;
} }
#ifdef CONFIG_CPU_FREQ
/* /*
* Divisor indexes in ascending divisor order * Divisor indexes in ascending divisor order
*/ */
...@@ -69,21 +70,17 @@ static struct vco freq_to_vco(unsigned int freq_khz, int factor) ...@@ -69,21 +70,17 @@ static struct vco freq_to_vco(unsigned int freq_khz, int factor)
return vco; return vco;
} }
/* /*
* Validate the speed in khz. If it is outside our * Validate the speed policy.
* range, then return the lowest.
*/ */
static int integrator_verify_speed(struct cpufreq_policy *policy) static int integrator_verify_policy(struct cpufreq_policy *policy)
{ {
struct vco vco; struct vco vco;
if (policy->max > policy->cpuinfo.max_freq) cpufreq_verify_within_limits(policy,
policy->max = policy->cpuinfo.max_freq; policy->cpuinfo.min_freq,
policy->cpuinfo.max_freq);
if (policy->max < 12000)
policy->max = 12000;
if (policy->max > 160000)
policy->max = 160000;
vco = freq_to_vco(policy->max, 1); vco = freq_to_vco(policy->max, 1);
...@@ -92,12 +89,28 @@ static int integrator_verify_speed(struct cpufreq_policy *policy) ...@@ -92,12 +89,28 @@ static int integrator_verify_speed(struct cpufreq_policy *policy)
if (vco.vdw > 152) if (vco.vdw > 152)
vco.vdw = 152; vco.vdw = 152;
policy->min = policy->max = vco_to_freq(vco, 1); policy->max = vco_to_freq(vco, 1);
vco = freq_to_vco(policy->min, 1);
if (vco.vdw < 4)
vco.vdw = 4;
if (vco.vdw > 152)
vco.vdw = 152;
policy->min = vco_to_freq(vco, 1);
cpufreq_verify_within_limits(policy,
policy->cpuinfo.min_freq,
policy->cpuinfo.max_freq);
return 0; return 0;
} }
static int integrator_set_policy(struct cpufreq_policy *policy)
static int integrator_set_target(struct cpufreq_policy *policy,
unsigned int target_freq,
unsigned int relation)
{ {
unsigned long cpus_allowed; unsigned long cpus_allowed;
int cpu = policy->cpu; int cpu = policy->cpu;
...@@ -121,9 +134,18 @@ static int integrator_set_policy(struct cpufreq_policy *policy) ...@@ -121,9 +134,18 @@ static int integrator_set_policy(struct cpufreq_policy *policy)
cm_osc = __raw_readl(CM_OSC); cm_osc = __raw_readl(CM_OSC);
vco.od = (cm_osc >> 8) & 7; vco.od = (cm_osc >> 8) & 7;
vco.vdw = cm_osc & 255; vco.vdw = cm_osc & 255;
freqs.old = vco_to_freq(vco, 1); freqs.old = vco_to_freq(vco, 1);
freqs.new = target_freq;
/* freq_to_vco rounds down -- so we need the next larger freq in
* case of CPUFREQ_RELATION_L.
*/
if (relation == CPUFREQ_RELATION_L)
target_freq += 1999;
if (target_freq > policy->max)
target_freq = policy->max;
vco = freq_to_vco(target_freq, 1);
freqs.new = vco_to_freq(vco, 1);
freqs.cpu = policy->cpu; freqs.cpu = policy->cpu;
if (freqs.old == freqs.new) { if (freqs.old == freqs.new) {
...@@ -132,7 +154,6 @@ static int integrator_set_policy(struct cpufreq_policy *policy) ...@@ -132,7 +154,6 @@ static int integrator_set_policy(struct cpufreq_policy *policy)
} }
cpufreq_notify_transition(&freqs, CPUFREQ_PRECHANGE); cpufreq_notify_transition(&freqs, CPUFREQ_PRECHANGE);
vco = freq_to_vco(policy->max, 1);
cm_osc = __raw_readl(CM_OSC); cm_osc = __raw_readl(CM_OSC);
cm_osc &= 0xfffff800; cm_osc &= 0xfffff800;
...@@ -152,80 +173,64 @@ static int integrator_set_policy(struct cpufreq_policy *policy) ...@@ -152,80 +173,64 @@ static int integrator_set_policy(struct cpufreq_policy *policy)
return 0; return 0;
} }
static struct cpufreq_policy integrator_policy = { static int integrator_cpufreq_init(struct cpufreq *policy)
.cpu = 0, {
.policy = CPUFREQ_POLICY_POWERSAVE, unsigned long cus_allowed;
.cpuinfo = { unsigned int cpu = policy->cpu;
.max_freq = 160000, u_int cm_osc, cm_stat, mem_freq_khz;
.min_freq = 12000, struct vco vco;
.transition_latency = CPUFREQ_ETERNAL,
},
};
static struct cpufreq_driver integrator_driver = { cpus_allowed = current->cpus_allowed;
.verify = integrator_verify_speed,
.setpolicy = integrator_set_policy,
.policy = &integrator_policy,
.name = "integrator",
};
#endif
static int __init integrator_cpu_init(void) set_cpus_allowed(current, 1 << cpu);
{ BUG_ON(cpu != smp_processor_id());
struct cpufreq_policy *policies;
unsigned long cpus_allowed;
int cpu;
policies = kmalloc(sizeof(struct cpufreq_policy) * NR_CPUS, /* detect memory etc. */
GFP_KERNEL); cm_stat = __raw_readl(CM_STAT);
if (!policies) { cm_osc = __raw_readl(CM_OSC);
printk(KERN_ERR "CPU: unable to allocate policies structure\n"); vco.od = (cm_osc >> 20) & 7;
return -ENOMEM; vco.vdw = (cm_osc >> 12) & 255;
} mem_freq_khz = vco_to_freq(vco, 2);
cpus_allowed = current->cpus_allowed; printk(KERN_INFO "CPU%d: Module id: %d\n", cpu, cm_stat & 255);
for (cpu = 0; cpu < NR_CPUS; cpu++) { printk(KERN_INFO "CPU%d: Memory clock = %d.%03d MHz\n",
u_int cm_osc, cm_stat, mem_freq_khz; cpu, mem_freq_khz / 1000, mem_freq_khz % 1000);
struct vco vco;
if (!cpu_online(cpu))
continue;
set_cpus_allowed(current, 1 << cpu);
BUG_ON(cpu != smp_processor_id());
cm_stat = __raw_readl(CM_STAT);
cm_osc = __raw_readl(CM_OSC);
vco.od = (cm_osc >> 20) & 7;
vco.vdw = (cm_osc >> 12) & 255;
mem_freq_khz = vco_to_freq(vco, 2);
printk(KERN_INFO "CPU%d: Module id: %d\n", cpu, cm_stat & 255);
printk(KERN_INFO "CPU%d: Memory clock = %d.%03d MHz\n",
cpu, mem_freq_khz / 1000, mem_freq_khz % 1000);
vco.od = (cm_osc >> 8) & 7;
vco.vdw = cm_osc & 255;
policies[cpu].cpu = cpu;
policies[cpu].policy = CPUFREQ_POLICY_POWERSAVE,
policies[cpu].cpuinfo.max_freq = 160000;
policies[cpu].cpuinfo.min_freq = 12000;
policies[cpu].cpuinfo.transition_latency = CPUFREQ_ETERNAL;
policies[cpu].min =
policies[cpu].max = vco_to_freq(vco, 1);
}
set_cpus_allowed(current, cpus_allowed); vco.od = (cm_osc >> 8) & 7;
vco.vdw = cm_osc & 255;
/* set default policy and cpuinfo */
policy->policy = CPUFREQ_POLICY_PERFORMANCE;
policy->cpuinfo.max_freq = 160000;
policy->cpuinfo.min_freq = 12000;
policy->cpuinfo.transition_latency = 1000; /* 1 ms, assumed */
integrator_driver.cpu_cur_freq[policy->cpu] = policy->min = policy->max = vco_to_freq(vco, 1); /* current freq */
#ifdef CONFIG_CPU_FREQ set_cpus_allowed(current, cpus_allowed);
integrator_driver.policy = policies;
cpufreq_register(&integrator_driver);
#else
kfree(policies);
#endif
return 0; return 0;
} }
arch_initcall(integrator_cpu_init); static struct cpufreq_driver integrator_driver = {
.verify = integrator_verify_policy,
.target = integrator_set_target,
.init = integrator_cpufreq_init,
.name = "integrator",
};
static int __init integrator_cpu_init(void)
{
return cpufreq_register_driver(&integrator_driver);
}
static void __exit integrator_cpu_exit(void)
{
cpufreq_unregister_driver(&integrator_driver);
}
MODULE_AUTHOR ("Russell M. King");
MODULE_DESCRIPTION ("cpufreq driver for ARM Integrator CPUs");
MODULE_LICENSE ("GPL");
module_init(integrator_cpu_init);
module_exit(integrator_cpu_exit);
...@@ -9,15 +9,8 @@ obj-n := ...@@ -9,15 +9,8 @@ obj-n :=
obj- := obj- :=
led-y := leds.o led-y := leds.o
# This needs to be cleaned up. We probably need to have SA1100 obj-$(CONFIG_CPU_FREQ_SA1100) += cpu-sa1100.o
# and SA1110 config symbols. obj-$(CONFIG_CPU_FREQ_SA1110) += cpu-sa1110.o
ifeq ($(CONFIG_CPU_FREQ),y)
obj-$(CONFIG_SA1100_ASSABET) += cpu-sa1110.o
obj-$(CONFIG_SA1100_CERF) += cpu-sa1110.o
obj-$(CONFIG_SA1100_HACKKIT) += cpu-sa1110.o
obj-$(CONFIG_SA1100_LART) += cpu-sa1100.o
obj-$(CONFIG_SA1100_PT_SYSTEM3) += cpu-sa1110.o
endif
# Specific board support # Specific board support
obj-$(CONFIG_SA1100_ADSBITSY) += adsbitsy.o obj-$(CONFIG_SA1100_ADSBITSY) += adsbitsy.o
......
...@@ -101,7 +101,7 @@ typedef struct { ...@@ -101,7 +101,7 @@ typedef struct {
} sa1100_dram_regs_t; } sa1100_dram_regs_t;
static struct cpufreq_driver sa1100_driver;
static sa1100_dram_regs_t sa1100_dram_settings[] = static sa1100_dram_regs_t sa1100_dram_settings[] =
{ {
...@@ -176,60 +176,72 @@ static void sa1100_update_dram_timings(int current_speed, int new_speed) ...@@ -176,60 +176,72 @@ static void sa1100_update_dram_timings(int current_speed, int new_speed)
} }
} }
static int sa1100_setspeed(struct cpufreq_policy *policy) static int sa1100_target(struct cpufreq_policy *policy,
unsigned int target_freq,
unsigned int relation)
{ {
unsigned int cur = sa11x0_getspeed(); unsigned int cur = sa11x0_getspeed();
unsigned int new_ppcr;
struct cpufreq_freqs freqs; struct cpufreq_freqs freqs;
switch(relation){
case CPUFREQ_RELATION_L:
new_ppcr = sa11x0_freq_to_ppcr(target_freq);
if (sa11x0_ppcr_to_freq(new_ppcr) > policy->max)
new_ppcr--;
break;
case CPUFREQ_RELATION_H:
new_ppcr = sa11x0_freq_to_ppcr(target_freq);
if ((sa11x0_ppcr_to_freq(new_ppcr) > target_freq) &&
(sa11x0_ppcr_to_freq(new_ppcr - 1) >= policy->min))
mew_ppcr--;
break;
}
freqs.old = cur; freqs.old = cur;
freqs.new = policy->max; freqs.new = sa11x0_ppcr_to_freq(new_ppcr);
freqs.cpu = 0; freqs.cpu = 0;
cpufreq_notify_transition(&freqs, CPUFREQ_PRECHANGE); cpufreq_notify_transition(&freqs, CPUFREQ_PRECHANGE);
if (policy->max > cur) if (freqs.new > cur)
sa1100_update_dram_timings(cur, policy->max); sa1100_update_dram_timings(cur, freqs.new);
PPCR = sa11x0_freq_to_ppcr(policy->max); PPCR = new_ppcr;
if (policy->max < cur) if (freqs.new < cur)
sa1100_update_dram_timings(cur, policy->max); sa1100_update_dram_timings(cur, freqs.new);
cpufreq_notify_transition(&freqs, CPUFREQ_POSTCHANGE); cpufreq_notify_transition(&freqs, CPUFREQ_POSTCHANGE);
return 0; return 0;
} }
static struct cpufreq_policy sa1100_policy = { static int __init sa1100_cpu_init(struct cpufreq_policy *policy)
.cpu = 0, {
.policy = CPUFREQ_POLICY_POWERSAVE, if (policy->cpu != 0)
.cpuinfo = { return -EINVAL;
.max_freq = 287000, sa1100_driver.cpu_cur_freq[policy->cpu] = policy->min = policy->max = sa11x0_getspeed();
.min_freq = 59000, policy->policy = CPUFREQ_POLICY_POWERSAVE;
.transition_latency = CPUFREQ_ETERNAL, policy->cpuinfo.min_freq = 59000;
}, policy->cpuinfo.max_freq = 287000;
}; policy->cpuinfo.transition_latency = CPUFREQ_ETERNAL;
return 0;
}
static struct cpufreq_driver sa1100_driver = { static struct cpufreq_driver sa1100_driver = {
.verify = sa11x0_verify_speed, .verify = sa11x0_verify_speed,
.setpolicy = sa1100_setspeed, .target = sa1100_target,
.policy = &sa1100_policy, .init = sa1100_cpu_init,
.name = "sa1100", .name = "sa1100",
}; };
static int __init sa1100_dram_init(void) static int __init sa1100_dram_init(void)
{ {
int ret = -ENODEV; if ((processor_id & CPU_SA1100_MASK) == CPU_SA1100_ID)
return cpufreq_register_driver(&sa1100_driver);
if ((processor_id & CPU_SA1100_MASK) == CPU_SA1100_ID) { else
sa1100_driver.cpu_cur_freq[0] = return -ENODEV;
sa1100_policy.min =
sa1100_policy.max = sa11x0_getspeed();
ret = cpufreq_register(&sa1100_driver);
}
return ret;
} }
arch_initcall(sa1100_dram_init); arch_initcall(sa1100_dram_init);
...@@ -32,6 +32,8 @@ ...@@ -32,6 +32,8 @@
#undef DEBUG #undef DEBUG
static struct cpufreq_driver sa1110_driver;
struct sdram_params { struct sdram_params {
u_char rows; /* bits */ u_char rows; /* bits */
u_char cas_latency; /* cycles */ u_char cas_latency; /* cycles */
...@@ -208,11 +210,11 @@ sdram_update_refresh(u_int cpu_khz, struct sdram_params *sdram) ...@@ -208,11 +210,11 @@ sdram_update_refresh(u_int cpu_khz, struct sdram_params *sdram)
} }
/* /*
* Ok, set the CPU frequency. Since we've done the validation * Ok, set the CPU frequency.
* above, we can match for an exact frequency. If we don't find
* an exact match, we will to set the lowest frequency to be safe.
*/ */
static int sa1110_setspeed(struct cpufreq_policy *policy) static int sa1110_target(struct cpufreq_policy *policy,
unsigned int target_freq,
unsigned int relation)
{ {
struct sdram_params *sdram = &sdram_params; struct sdram_params *sdram = &sdram_params;
struct cpufreq_freqs freqs; struct cpufreq_freqs freqs;
...@@ -220,8 +222,25 @@ static int sa1110_setspeed(struct cpufreq_policy *policy) ...@@ -220,8 +222,25 @@ static int sa1110_setspeed(struct cpufreq_policy *policy)
unsigned long flags; unsigned long flags;
unsigned int ppcr, unused; unsigned int ppcr, unused;
ppcr = sa11x0_freq_to_ppcr(policy->max); switch(relation){
sdram_calculate_timing(&sd, policy->max, sdram); case CPUFREQ_RELATION_L:
ppcr = sa11x0_freq_to_ppcr(target_freq);
if (sa11x0_ppcr_to_freq(ppcr) > policy->max)
ppcr--;
break;
case CPUFREQ_RELATION_H:
ppcr = sa11x0_freq_to_ppcr(target_freq);
if (ppcr && (sa11x0_ppcr_to_freq(ppcr) > target_freq) &&
(sa11x0_ppcr_to_freq(ppcr-1) >= policy->min))
ppcr--;
break;
}
freqs.old = sa11x0_getspeed();
freqs.new = sa11x0_ppcr_to_freq(ppcr);
freqs.cpu = 0;
sdram_calculate_timing(&sd, freqs.new, sdram);
#if 0 #if 0
/* /*
...@@ -240,10 +259,6 @@ static int sa1110_setspeed(struct cpufreq_policy *policy) ...@@ -240,10 +259,6 @@ static int sa1110_setspeed(struct cpufreq_policy *policy)
sd.mdcas[2] = 0xaaaaaaaa; sd.mdcas[2] = 0xaaaaaaaa;
#endif #endif
freqs.old = sa11x0_getspeed();
freqs.new = policy->max;
freqs.cpu = 0;
cpufreq_notify_transition(&freqs, CPUFREQ_PRECHANGE); cpufreq_notify_transition(&freqs, CPUFREQ_PRECHANGE);
/* /*
...@@ -288,27 +303,29 @@ static int sa1110_setspeed(struct cpufreq_policy *policy) ...@@ -288,27 +303,29 @@ static int sa1110_setspeed(struct cpufreq_policy *policy)
/* /*
* Now, return the SDRAM refresh back to normal. * Now, return the SDRAM refresh back to normal.
*/ */
sdram_update_refresh(policy->max, sdram); sdram_update_refresh(freqs.new, sdram);
cpufreq_notify_transition(&freqs, CPUFREQ_POSTCHANGE); cpufreq_notify_transition(&freqs, CPUFREQ_POSTCHANGE);
return 0; return 0;
} }
static struct cpufreq_policy sa1110_policy = { static int __init sa1110_cpu_init(struct cpufreq_policy *policy)
.cpu = 0, {
.policy = CPUFREQ_POLICY_POWERSAVE, if (policy->cpu != 0)
.cpuinfo = { return -EINVAL;
.max_freq = 287000, sa1110_driver.cpu_cur_freq[policy->cpu] = policy->min = policy->max = sa11x0_getspeed();
.min_freq = 59000, policy->policy = CPUFREQ_POLICY_POWERSAVE;
.transition_latency = CPUFREQ_ETERNAL, policy->cpuinfo.min_freq = 59000;
}, policy->cpuinfo.max_freq = 287000;
}; policy->cpuinfo.transition_latency = CPUFREQ_ETERNAL;
return 0;
}
static struct cpufreq_driver sa1110_driver = { static struct cpufreq_driver sa1110_driver = {
.verify = sa11x0_verify_speed, .verify = sa11x0_verify_speed,
.setpolicy = sa1110_setspeed, .target = sa1110_target,
.policy = &sa1110_policy, .init = sa1110_cpu_init,
.name = "sa1110", .name = "sa1110",
}; };
...@@ -333,13 +350,7 @@ static int __init sa1110_clk_init(void) ...@@ -333,13 +350,7 @@ static int __init sa1110_clk_init(void)
memcpy(&sdram_params, sdram, sizeof(sdram_params)); memcpy(&sdram_params, sdram, sizeof(sdram_params));
sa1110_driver.cpu_cur_freq[0] = return cpufreq_register_driver(&sa1110_driver);
sa1110_policy.min =
sa1110_policy.max = sa11x0_getspeed();
sa1110_setspeed(&sa1110_policy);
return cpufreq_register(&sa1110_driver);
} }
return 0; return 0;
......
...@@ -48,33 +48,48 @@ static const unsigned short cclk_frequency_100khz[NR_FREQS] = { ...@@ -48,33 +48,48 @@ static const unsigned short cclk_frequency_100khz[NR_FREQS] = {
2802 /* 280.2 MHz */ 2802 /* 280.2 MHz */
}; };
#ifdef CONFIG_CPU_FREQ #if defined(CONFIG_CPU_FREQ_SA1100) || defined(CONFIG_CPU_FREQ_SA1110)
/* rounds up(!) */
unsigned int sa11x0_freq_to_ppcr(unsigned int khz) unsigned int sa11x0_freq_to_ppcr(unsigned int khz)
{ {
int i; int i;
khz /= 100; khz /= 100;
for (i = NR_FREQS - 1; i > 0; i--) for (i = 0; i < NR_FREQS; i++)
if (cclk_frequency_100khz[i] <= khz) if (cclk_frequency_100khz[i] >= khz)
break; break;
return i; return i;
} }
/* unsigned int sa11x0_ppcr_to_freq(unsigned int idx)
* Validate the policy. We aren't able to do any fancy in-kernel {
* scaling, so we force min=max, and set the policy to "performance". if (idx >= NR_FREQS)
* If we can't generate the precise frequency requested, round it up. return 0;
else
return cclk_frequency_100khz[idx];
}
/* make sure that only the "userspace" governor is run -- anything else wouldn't make sense on
* this platform, anyway.
*/ */
int sa11x0_verify_speed(struct cpufreq_policy *policy) int sa11x0_verify_speed(struct cpufreq_policy *policy)
{ {
if (policy->max > policy->cpuinfo.max_freq) unsigned int tmp;
policy->max = policy->cpuinfo.max_freq; if (policy->cpu)
return -EINVAL;
cpufreq_verify_within_limits(policy, policy->cpuinfo.min_freq, policy->cpuinfo.max_freq);
/* make sure that at least one frequency is within the policy */
tmp = cclk_frequency_100khz[sa11x0_freq_to_ppcr(policy->min)] * 100;
if (tmp > policy->max)
policy->max = tmp;
cpufreq_verify_within_limits(policy, policy->cpuinfo.min_freq, policy->cpuinfo.max_freq);
policy->max = cclk_frequency_100khz[sa11x0_freq_to_ppcr(policy->max)] * 100;
policy->min = policy->max;
policy->policy = CPUFREQ_POLICY_POWERSAVE;
return 0; return 0;
} }
......
...@@ -23,3 +23,4 @@ struct cpufreq_policy; ...@@ -23,3 +23,4 @@ struct cpufreq_policy;
extern unsigned int sa11x0_freq_to_ppcr(unsigned int khz); extern unsigned int sa11x0_freq_to_ppcr(unsigned int khz);
extern int sa11x0_verify_speed(struct cpufreq_policy *policy); extern int sa11x0_verify_speed(struct cpufreq_policy *policy);
extern unsigned int sa11x0_getspeed(void); extern unsigned int sa11x0_getspeed(void);
extern unsigned int sa11x0_ppcr_to_freq(unsigned int idx);
...@@ -213,11 +213,17 @@ static void __init system3_init_irq(void) ...@@ -213,11 +213,17 @@ static void __init system3_init_irq(void)
static int sdram_notifier(struct notifier_block *nb, unsigned long event, static int sdram_notifier(struct notifier_block *nb, unsigned long event,
void *data) void *data)
{ {
struct cpufreq_policy *policy = data;
switch (event) { switch (event) {
case CPUFREQ_MINMAX: case CPUFREQ_ADJUST:
cpufreq_updateminmax(data, 147500, 206000); case CPUFREQ_INCOMPATIBLE:
cpufreq_verify_within_limits(policy, 147500, 206000);
break;
case CPUFREQ_NOTIFY:
if ((policy->min < 147500) ||
(policy->max > 206000))
panic("cpufreq failed to limit the speed\n");
break; break;
} }
return 0; return 0;
} }
...@@ -405,7 +411,7 @@ static int __init system3_init(void) ...@@ -405,7 +411,7 @@ static int __init system3_init(void)
goto DONE; goto DONE;
} }
#if defined( CONFIG_CPU_FREQ ) #ifdef CONFIG_CPU_FREQ
ret = cpufreq_register_notifier(&system3_clkchg_block); ret = cpufreq_register_notifier(&system3_clkchg_block);
if ( ret != 0 ) { if ( ret != 0 ) {
printk( KERN_WARNING"PT Digital Board: could not register clock scale callback\n" ); printk( KERN_WARNING"PT Digital Board: could not register clock scale callback\n" );
......
...@@ -47,7 +47,6 @@ ...@@ -47,7 +47,6 @@
#include <linux/notifier.h> #include <linux/notifier.h>
#include <linux/proc_fs.h> #include <linux/proc_fs.h>
#include <linux/version.h> #include <linux/version.h>
#include <linux/cpufreq.h>
#include <pcmcia/version.h> #include <pcmcia/version.h>
#include <pcmcia/cs_types.h> #include <pcmcia/cs_types.h>
......
...@@ -1590,11 +1590,21 @@ sa1100fb_freq_policy(struct notifier_block *nb, unsigned long val, ...@@ -1590,11 +1590,21 @@ sa1100fb_freq_policy(struct notifier_block *nb, unsigned long val,
struct sa1100fb_info *fbi = TO_INF(nb, freq_policy); struct sa1100fb_info *fbi = TO_INF(nb, freq_policy);
struct cpufreq_policy *policy = data; struct cpufreq_policy *policy = data;
if (val == CPUFREQ_INCOMPATIBLE) { switch (val) {
case CPUFREQ_ADJUST:
case CPUFREQ_INCOMPATIBLE:
printk(KERN_DEBUG "min dma period: %d ps, " printk(KERN_DEBUG "min dma period: %d ps, "
"new clock %d kHz\n", sa1100fb_min_dma_period(fbi), "new clock %d kHz\n", sa1100fb_min_dma_period(fbi),
policy->max); policy->max);
/* todo: fill in min/max values */ /* todo: fill in min/max values */
break;
case CPUFREQ_NOTIFY:
do {} while(0);
/* todo: panic if min/max values aren't fulfilled
* [can't really happen unless there's a bug in the
* CPU policy verififcation process *
*/
break;
} }
return 0; return 0;
} }
......
...@@ -336,6 +336,13 @@ static int cpufreq_add_dev (struct device * dev) ...@@ -336,6 +336,13 @@ static int cpufreq_add_dev (struct device * dev)
&cpufreq_driver->policy[cpu], &cpufreq_driver->policy[cpu],
sizeof(struct cpufreq_policy)); sizeof(struct cpufreq_policy));
/* 2.4-API init for this CPU */
#ifdef CONFIG_CPU_FREQ_24_API
cpu_min_freq[cpu] = cpufreq_driver->policy[cpu].cpuinfo.min_freq;
cpu_max_freq[cpu] = cpufreq_driver->policy[cpu].cpuinfo.max_freq;
cpu_cur_freq[cpu] = cpufreq_driver->cpu_cur_freq[cpu];
#endif
if (cpufreq_driver->target) if (cpufreq_driver->target)
cpufreq_governor(cpu, CPUFREQ_GOV_START); cpufreq_governor(cpu, CPUFREQ_GOV_START);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment