16 #include <linux/module.h>
17 #include <linux/types.h>
18 #include <linux/errno.h>
19 #include <linux/kernel.h>
21 #include <linux/sched.h>
22 #include <linux/adb.h>
23 #include <linux/pmu.h>
26 #include <linux/device.h>
29 #include <asm/machdep.h>
32 #include <asm/mmu_context.h>
33 #include <asm/sections.h>
34 #include <asm/cputable.h>
38 #include <asm/switch_to.h>
54 static unsigned int low_freq;
55 static unsigned int hi_freq;
56 static unsigned int cur_freq;
57 static unsigned int sleep_freq;
62 static int (*set_speed_proc)(
int low_speed);
63 static unsigned int (*get_speed_proc)(
void);
68 static u32 voltage_gpio;
69 static u32 frequency_gpio;
70 static u32 slew_done_gpio;
71 static int no_schedule;
72 static int has_cpu_l2lve;
73 static int is_pmu_based;
78 #define CPUFREQ_HIGH 0
87 static struct freq_attr* pmac_cpu_freqs_attr[] = {
92 static inline void local_delay(
unsigned long ms)
101 static inline void debug_calc_bogomips(
void)
115 static int cpu_750fx_cpu_speed(
int low_speed)
119 if (low_speed == 0) {
121 pmac_call_feature(PMAC_FTR_WRITE_GPIO,
NULL, voltage_gpio, 0x05);
127 hid2 =
mfspr(SPRN_HID2);
129 mtspr(SPRN_HID2, hid2);
135 if (low_speed == 1) {
138 hid2 =
mfspr(SPRN_HID2);
140 mtspr(SPRN_HID2, hid2);
144 pmac_call_feature(PMAC_FTR_WRITE_GPIO,
NULL, voltage_gpio, 0x04);
151 static unsigned int cpu_750fx_get_cpu_speed(
void)
153 if (
mfspr(SPRN_HID1) & HID1_PS)
160 static int dfs_set_cpu_speed(
int low_speed)
162 if (low_speed == 0) {
164 pmac_call_feature(PMAC_FTR_WRITE_GPIO,
NULL, voltage_gpio, 0x05);
175 if (low_speed == 1) {
177 pmac_call_feature(PMAC_FTR_WRITE_GPIO,
NULL, voltage_gpio, 0x04);
184 static unsigned int dfs_get_cpu_speed(
void)
186 if (
mfspr(SPRN_HID1) & HID1_DFS)
195 static int gpios_set_cpu_speed(
int low_speed)
200 if (low_speed == 0) {
201 pmac_call_feature(PMAC_FTR_WRITE_GPIO,
NULL, voltage_gpio, 0x05);
207 gpio = pmac_call_feature(PMAC_FTR_READ_GPIO,
NULL, frequency_gpio, 0);
208 if (low_speed == ((gpio & 0x01) == 0))
211 pmac_call_feature(PMAC_FTR_WRITE_GPIO,
NULL, frequency_gpio,
212 low_speed ? 0x04 : 0x05);
218 gpio = pmac_call_feature(PMAC_FTR_READ_GPIO,
NULL, slew_done_gpio, 0);
219 }
while((gpio & 0x02) == 0);
222 if (low_speed == 1) {
223 pmac_call_feature(PMAC_FTR_WRITE_GPIO,
NULL, voltage_gpio, 0x04);
229 debug_calc_bogomips();
237 static int pmu_set_cpu_speed(
int low_speed)
240 unsigned long save_l2cr;
241 unsigned long save_l3cr;
242 unsigned int pic_prio;
257 asm volatile(
"mtdec %0" : :
"r" (0x7fffffff));
261 asm volatile(
"mtdec %0" : :
"r" (0x7fffffff));
269 #ifdef CONFIG_ALTIVEC
275 save_l3cr = _get_L3CR();
276 save_l2cr = _get_L2CR();
282 while (!
req.complete)
286 pmac_call_feature(PMAC_FTR_SLEEP_STATE,
NULL,1,1);
294 pmac_call_feature(PMAC_FTR_SLEEP_STATE,
NULL,1,0);
297 if (save_l2cr != 0xffffffff && (save_l2cr & L2CR_L2E) != 0)
298 _set_L2CR(save_l2cr);
300 if (save_l3cr != 0xffffffff && (save_l3cr & L3CR_L3E) != 0)
301 _set_L3CR(save_l3cr);
327 debug_calc_bogomips();
337 static int do_set_cpu_speed(
int speed_mode,
int notify)
341 static unsigned long prev_l3cr;
343 freqs.
old = cur_freq;
344 freqs.new = (speed_mode ==
CPUFREQ_HIGH) ? hi_freq : low_freq;
347 if (freqs.old == freqs.new)
355 if (l3cr & L3CR_L3E) {
364 if ((prev_l3cr & L3CR_L3E) && l3cr != prev_l3cr)
365 _set_L3CR(prev_l3cr);
369 cur_freq = (speed_mode ==
CPUFREQ_HIGH) ? hi_freq : low_freq;
374 static unsigned int pmac_cpufreq_get_speed(
unsigned int cpu)
385 unsigned int target_freq,
386 unsigned int relation)
388 unsigned int newstate = 0;
392 target_freq, relation, &newstate))
395 rc = do_set_cpu_speed(newstate, 1);
403 if (policy->
cpu != 0)
407 policy->
cur = cur_freq;
427 if (offset < KEYLARGO_GPIO_LEVELS0)
428 offset += KEYLARGO_GPIO_LEVELS0;
442 sleep_freq = cur_freq;
443 if (cur_freq == low_freq && !is_pmu_based)
452 cur_freq = get_speed_proc();
460 do_set_cpu_speed(sleep_freq == low_freq ?
470 .verify = pmac_cpufreq_verify,
471 .target = pmac_cpufreq_target,
472 .get = pmac_cpufreq_get_speed,
473 .init = pmac_cpufreq_cpu_init,
474 .suspend = pmac_cpufreq_suspend,
475 .resume = pmac_cpufreq_resume,
477 .attr = pmac_cpu_freqs_attr,
483 static int pmac_cpufreq_init_MacRISC3(
struct device_node *cpunode)
502 voltage_gpio = read_gpio(volt_gpio_np);
504 frequency_gpio = read_gpio(freq_gpio_np);
505 if (slew_done_gpio_np)
506 slew_done_gpio = read_gpio(slew_done_gpio_np);
511 if (frequency_gpio && slew_done_gpio) {
517 if (freqs ==
NULL || lenp != 2) {
518 printk(
KERN_ERR "cpufreq: bus-frequencies incorrect or missing\n");
529 low_freq =
min(freqs[0], freqs[1]);
530 hi_freq =
max(freqs[0], freqs[1]);
537 if (low_freq < 98000000)
538 low_freq = 101000000;
541 low_freq = (low_freq * (*ratio)) / 2000;
542 hi_freq = (hi_freq * (*ratio)) / 2000;
547 rc = pmac_call_feature(PMAC_FTR_READ_GPIO,
NULL, frequency_gpio, 0);
548 cur_freq = (rc & 0x01) ? hi_freq : low_freq;
550 set_speed_proc = gpios_set_cpu_speed;
560 low_freq = (*value) / 1000;
563 if (low_freq < 100000)
569 hi_freq = (*value) / 1000;
570 set_speed_proc = pmu_set_cpu_speed;
576 static int pmac_cpufreq_init_7447A(
struct device_node *cpunode)
585 voltage_gpio = read_gpio(volt_gpio_np);
593 low_freq = cur_freq/2;
596 cur_freq = dfs_get_cpu_speed();
597 set_speed_proc = dfs_set_cpu_speed;
598 get_speed_proc = dfs_get_cpu_speed;
603 static int pmac_cpufreq_init_750FX(
struct device_node *cpunode)
616 low_freq = (*value) / 1000;
620 voltage_gpio = read_gpio(volt_gpio_np);
623 has_cpu_l2lve = !((pvr & 0xf00) == 0x100);
625 set_speed_proc = cpu_750fx_cpu_speed;
626 get_speed_proc = cpu_750fx_get_cpu_speed;
627 cur_freq = cpu_750fx_get_cpu_speed();
643 static int __init pmac_cpufreq_setup(
void)
648 if (
strstr(cmd_line,
"nocpufreq"))
660 cur_freq = (*value) / 1000;
666 pmac_cpufreq_init_7447A(cpunode);
671 pmac_cpufreq_init_MacRISC3(cpunode);
676 set_speed_proc = pmu_set_cpu_speed;
683 set_speed_proc = pmu_set_cpu_speed;
691 if (cur_freq < 350000 || cur_freq > 550000)
695 set_speed_proc = pmu_set_cpu_speed;
700 pmac_cpufreq_init_750FX(cpunode);
702 of_node_put(cpunode);
703 if (set_speed_proc ==
NULL)
712 low_freq/1000, hi_freq/1000, cur_freq/1000);