diff options
Diffstat (limited to 'arch/powerpc/platforms/powermac/pmac_cpufreq.c')
-rw-r--r-- | arch/powerpc/platforms/powermac/pmac_cpufreq.c | 728 |
1 files changed, 728 insertions, 0 deletions
diff --git a/arch/powerpc/platforms/powermac/pmac_cpufreq.c b/arch/powerpc/platforms/powermac/pmac_cpufreq.c new file mode 100644 index 000000000000..6d32d99402be --- /dev/null +++ b/arch/powerpc/platforms/powermac/pmac_cpufreq.c | |||
@@ -0,0 +1,728 @@ | |||
1 | /* | ||
2 | * arch/ppc/platforms/pmac_cpufreq.c | ||
3 | * | ||
4 | * Copyright (C) 2002 - 2005 Benjamin Herrenschmidt <benh@kernel.crashing.org> | ||
5 | * Copyright (C) 2004 John Steele Scott <toojays@toojays.net> | ||
6 | * | ||
7 | * This program is free software; you can redistribute it and/or modify | ||
8 | * it under the terms of the GNU General Public License version 2 as | ||
9 | * published by the Free Software Foundation. | ||
10 | * | ||
11 | * TODO: Need a big cleanup here. Basically, we need to have different | ||
12 | * cpufreq_driver structures for the different type of HW instead of the | ||
13 | * current mess. We also need to better deal with the detection of the | ||
14 | * type of machine. | ||
15 | * | ||
16 | */ | ||
17 | |||
18 | #include <linux/config.h> | ||
19 | #include <linux/module.h> | ||
20 | #include <linux/types.h> | ||
21 | #include <linux/errno.h> | ||
22 | #include <linux/kernel.h> | ||
23 | #include <linux/delay.h> | ||
24 | #include <linux/sched.h> | ||
25 | #include <linux/adb.h> | ||
26 | #include <linux/pmu.h> | ||
27 | #include <linux/slab.h> | ||
28 | #include <linux/cpufreq.h> | ||
29 | #include <linux/init.h> | ||
30 | #include <linux/sysdev.h> | ||
31 | #include <linux/i2c.h> | ||
32 | #include <linux/hardirq.h> | ||
33 | #include <asm/prom.h> | ||
34 | #include <asm/machdep.h> | ||
35 | #include <asm/irq.h> | ||
36 | #include <asm/pmac_feature.h> | ||
37 | #include <asm/mmu_context.h> | ||
38 | #include <asm/sections.h> | ||
39 | #include <asm/cputable.h> | ||
40 | #include <asm/time.h> | ||
41 | #include <asm/system.h> | ||
42 | #include <asm/mpic.h> | ||
43 | #include <asm/keylargo.h> | ||
44 | |||
45 | /* WARNING !!! This will cause calibrate_delay() to be called, | ||
46 | * but this is an __init function ! So you MUST go edit | ||
47 | * init/main.c to make it non-init before enabling DEBUG_FREQ | ||
48 | */ | ||
49 | #undef DEBUG_FREQ | ||
50 | |||
51 | /* | ||
52 | * There is a problem with the core cpufreq code on SMP kernels, | ||
53 | * it won't recalculate the Bogomips properly | ||
54 | */ | ||
55 | #ifdef CONFIG_SMP | ||
56 | #warning "WARNING, CPUFREQ not recommended on SMP kernels" | ||
57 | #endif | ||
58 | |||
59 | extern void low_choose_7447a_dfs(int dfs); | ||
60 | extern void low_choose_750fx_pll(int pll); | ||
61 | extern void low_sleep_handler(void); | ||
62 | |||
63 | /* | ||
64 | * Currently, PowerMac cpufreq supports only high & low frequencies | ||
65 | * that are set by the firmware | ||
66 | */ | ||
67 | static unsigned int low_freq; | ||
68 | static unsigned int hi_freq; | ||
69 | static unsigned int cur_freq; | ||
70 | static unsigned int sleep_freq; | ||
71 | |||
72 | /* | ||
73 | * Different models uses different mecanisms to switch the frequency | ||
74 | */ | ||
75 | static int (*set_speed_proc)(int low_speed); | ||
76 | static unsigned int (*get_speed_proc)(void); | ||
77 | |||
78 | /* | ||
79 | * Some definitions used by the various speedprocs | ||
80 | */ | ||
81 | static u32 voltage_gpio; | ||
82 | static u32 frequency_gpio; | ||
83 | static u32 slew_done_gpio; | ||
84 | static int no_schedule; | ||
85 | static int has_cpu_l2lve; | ||
86 | static int is_pmu_based; | ||
87 | |||
88 | /* There are only two frequency states for each processor. Values | ||
89 | * are in kHz for the time being. | ||
90 | */ | ||
91 | #define CPUFREQ_HIGH 0 | ||
92 | #define CPUFREQ_LOW 1 | ||
93 | |||
94 | static struct cpufreq_frequency_table pmac_cpu_freqs[] = { | ||
95 | {CPUFREQ_HIGH, 0}, | ||
96 | {CPUFREQ_LOW, 0}, | ||
97 | {0, CPUFREQ_TABLE_END}, | ||
98 | }; | ||
99 | |||
100 | static struct freq_attr* pmac_cpu_freqs_attr[] = { | ||
101 | &cpufreq_freq_attr_scaling_available_freqs, | ||
102 | NULL, | ||
103 | }; | ||
104 | |||
105 | static inline void local_delay(unsigned long ms) | ||
106 | { | ||
107 | if (no_schedule) | ||
108 | mdelay(ms); | ||
109 | else | ||
110 | msleep(ms); | ||
111 | } | ||
112 | |||
113 | static inline void wakeup_decrementer(void) | ||
114 | { | ||
115 | set_dec(tb_ticks_per_jiffy); | ||
116 | /* No currently-supported powerbook has a 601, | ||
117 | * so use get_tbl, not native | ||
118 | */ | ||
119 | last_jiffy_stamp(0) = tb_last_stamp = get_tbl(); | ||
120 | } | ||
121 | |||
122 | #ifdef DEBUG_FREQ | ||
123 | static inline void debug_calc_bogomips(void) | ||
124 | { | ||
125 | /* This will cause a recalc of bogomips and display the | ||
126 | * result. We backup/restore the value to avoid affecting the | ||
127 | * core cpufreq framework's own calculation. | ||
128 | */ | ||
129 | extern void calibrate_delay(void); | ||
130 | |||
131 | unsigned long save_lpj = loops_per_jiffy; | ||
132 | calibrate_delay(); | ||
133 | loops_per_jiffy = save_lpj; | ||
134 | } | ||
135 | #endif /* DEBUG_FREQ */ | ||
136 | |||
137 | /* Switch CPU speed under 750FX CPU control | ||
138 | */ | ||
139 | static int cpu_750fx_cpu_speed(int low_speed) | ||
140 | { | ||
141 | u32 hid2; | ||
142 | |||
143 | if (low_speed == 0) { | ||
144 | /* ramping up, set voltage first */ | ||
145 | pmac_call_feature(PMAC_FTR_WRITE_GPIO, NULL, voltage_gpio, 0x05); | ||
146 | /* Make sure we sleep for at least 1ms */ | ||
147 | local_delay(10); | ||
148 | |||
149 | /* tweak L2 for high voltage */ | ||
150 | if (has_cpu_l2lve) { | ||
151 | hid2 = mfspr(SPRN_HID2); | ||
152 | hid2 &= ~0x2000; | ||
153 | mtspr(SPRN_HID2, hid2); | ||
154 | } | ||
155 | } | ||
156 | #ifdef CONFIG_6xx | ||
157 | low_choose_750fx_pll(low_speed); | ||
158 | #endif | ||
159 | if (low_speed == 1) { | ||
160 | /* tweak L2 for low voltage */ | ||
161 | if (has_cpu_l2lve) { | ||
162 | hid2 = mfspr(SPRN_HID2); | ||
163 | hid2 |= 0x2000; | ||
164 | mtspr(SPRN_HID2, hid2); | ||
165 | } | ||
166 | |||
167 | /* ramping down, set voltage last */ | ||
168 | pmac_call_feature(PMAC_FTR_WRITE_GPIO, NULL, voltage_gpio, 0x04); | ||
169 | local_delay(10); | ||
170 | } | ||
171 | |||
172 | return 0; | ||
173 | } | ||
174 | |||
175 | static unsigned int cpu_750fx_get_cpu_speed(void) | ||
176 | { | ||
177 | if (mfspr(SPRN_HID1) & HID1_PS) | ||
178 | return low_freq; | ||
179 | else | ||
180 | return hi_freq; | ||
181 | } | ||
182 | |||
183 | /* Switch CPU speed using DFS */ | ||
184 | static int dfs_set_cpu_speed(int low_speed) | ||
185 | { | ||
186 | if (low_speed == 0) { | ||
187 | /* ramping up, set voltage first */ | ||
188 | pmac_call_feature(PMAC_FTR_WRITE_GPIO, NULL, voltage_gpio, 0x05); | ||
189 | /* Make sure we sleep for at least 1ms */ | ||
190 | local_delay(1); | ||
191 | } | ||
192 | |||
193 | /* set frequency */ | ||
194 | #ifdef CONFIG_6xx | ||
195 | low_choose_7447a_dfs(low_speed); | ||
196 | #endif | ||
197 | udelay(100); | ||
198 | |||
199 | if (low_speed == 1) { | ||
200 | /* ramping down, set voltage last */ | ||
201 | pmac_call_feature(PMAC_FTR_WRITE_GPIO, NULL, voltage_gpio, 0x04); | ||
202 | local_delay(1); | ||
203 | } | ||
204 | |||
205 | return 0; | ||
206 | } | ||
207 | |||
208 | static unsigned int dfs_get_cpu_speed(void) | ||
209 | { | ||
210 | if (mfspr(SPRN_HID1) & HID1_DFS) | ||
211 | return low_freq; | ||
212 | else | ||
213 | return hi_freq; | ||
214 | } | ||
215 | |||
216 | |||
217 | /* Switch CPU speed using slewing GPIOs | ||
218 | */ | ||
219 | static int gpios_set_cpu_speed(int low_speed) | ||
220 | { | ||
221 | int gpio, timeout = 0; | ||
222 | |||
223 | /* If ramping up, set voltage first */ | ||
224 | if (low_speed == 0) { | ||
225 | pmac_call_feature(PMAC_FTR_WRITE_GPIO, NULL, voltage_gpio, 0x05); | ||
226 | /* Delay is way too big but it's ok, we schedule */ | ||
227 | local_delay(10); | ||
228 | } | ||
229 | |||
230 | /* Set frequency */ | ||
231 | gpio = pmac_call_feature(PMAC_FTR_READ_GPIO, NULL, frequency_gpio, 0); | ||
232 | if (low_speed == ((gpio & 0x01) == 0)) | ||
233 | goto skip; | ||
234 | |||
235 | pmac_call_feature(PMAC_FTR_WRITE_GPIO, NULL, frequency_gpio, | ||
236 | low_speed ? 0x04 : 0x05); | ||
237 | udelay(200); | ||
238 | do { | ||
239 | if (++timeout > 100) | ||
240 | break; | ||
241 | local_delay(1); | ||
242 | gpio = pmac_call_feature(PMAC_FTR_READ_GPIO, NULL, slew_done_gpio, 0); | ||
243 | } while((gpio & 0x02) == 0); | ||
244 | skip: | ||
245 | /* If ramping down, set voltage last */ | ||
246 | if (low_speed == 1) { | ||
247 | pmac_call_feature(PMAC_FTR_WRITE_GPIO, NULL, voltage_gpio, 0x04); | ||
248 | /* Delay is way too big but it's ok, we schedule */ | ||
249 | local_delay(10); | ||
250 | } | ||
251 | |||
252 | #ifdef DEBUG_FREQ | ||
253 | debug_calc_bogomips(); | ||
254 | #endif | ||
255 | |||
256 | return 0; | ||
257 | } | ||
258 | |||
259 | /* Switch CPU speed under PMU control | ||
260 | */ | ||
261 | static int pmu_set_cpu_speed(int low_speed) | ||
262 | { | ||
263 | struct adb_request req; | ||
264 | unsigned long save_l2cr; | ||
265 | unsigned long save_l3cr; | ||
266 | unsigned int pic_prio; | ||
267 | unsigned long flags; | ||
268 | |||
269 | preempt_disable(); | ||
270 | |||
271 | #ifdef DEBUG_FREQ | ||
272 | printk(KERN_DEBUG "HID1, before: %x\n", mfspr(SPRN_HID1)); | ||
273 | #endif | ||
274 | pmu_suspend(); | ||
275 | |||
276 | /* Disable all interrupt sources on openpic */ | ||
277 | pic_prio = mpic_cpu_get_priority(); | ||
278 | mpic_cpu_set_priority(0xf); | ||
279 | |||
280 | /* Make sure the decrementer won't interrupt us */ | ||
281 | asm volatile("mtdec %0" : : "r" (0x7fffffff)); | ||
282 | /* Make sure any pending DEC interrupt occuring while we did | ||
283 | * the above didn't re-enable the DEC */ | ||
284 | mb(); | ||
285 | asm volatile("mtdec %0" : : "r" (0x7fffffff)); | ||
286 | |||
287 | /* We can now disable MSR_EE */ | ||
288 | local_irq_save(flags); | ||
289 | |||
290 | /* Giveup the FPU & vec */ | ||
291 | enable_kernel_fp(); | ||
292 | |||
293 | #ifdef CONFIG_ALTIVEC | ||
294 | if (cpu_has_feature(CPU_FTR_ALTIVEC)) | ||
295 | enable_kernel_altivec(); | ||
296 | #endif /* CONFIG_ALTIVEC */ | ||
297 | |||
298 | /* Save & disable L2 and L3 caches */ | ||
299 | save_l3cr = _get_L3CR(); /* (returns -1 if not available) */ | ||
300 | save_l2cr = _get_L2CR(); /* (returns -1 if not available) */ | ||
301 | |||
302 | /* Send the new speed command. My assumption is that this command | ||
303 | * will cause PLL_CFG[0..3] to be changed next time CPU goes to sleep | ||
304 | */ | ||
305 | pmu_request(&req, NULL, 6, PMU_CPU_SPEED, 'W', 'O', 'O', 'F', low_speed); | ||
306 | while (!req.complete) | ||
307 | pmu_poll(); | ||
308 | |||
309 | /* Prepare the northbridge for the speed transition */ | ||
310 | pmac_call_feature(PMAC_FTR_SLEEP_STATE,NULL,1,1); | ||
311 | |||
312 | /* Call low level code to backup CPU state and recover from | ||
313 | * hardware reset | ||
314 | */ | ||
315 | low_sleep_handler(); | ||
316 | |||
317 | /* Restore the northbridge */ | ||
318 | pmac_call_feature(PMAC_FTR_SLEEP_STATE,NULL,1,0); | ||
319 | |||
320 | /* Restore L2 cache */ | ||
321 | if (save_l2cr != 0xffffffff && (save_l2cr & L2CR_L2E) != 0) | ||
322 | _set_L2CR(save_l2cr); | ||
323 | /* Restore L3 cache */ | ||
324 | if (save_l3cr != 0xffffffff && (save_l3cr & L3CR_L3E) != 0) | ||
325 | _set_L3CR(save_l3cr); | ||
326 | |||
327 | /* Restore userland MMU context */ | ||
328 | set_context(current->active_mm->context, current->active_mm->pgd); | ||
329 | |||
330 | #ifdef DEBUG_FREQ | ||
331 | printk(KERN_DEBUG "HID1, after: %x\n", mfspr(SPRN_HID1)); | ||
332 | #endif | ||
333 | |||
334 | /* Restore low level PMU operations */ | ||
335 | pmu_unlock(); | ||
336 | |||
337 | /* Restore decrementer */ | ||
338 | wakeup_decrementer(); | ||
339 | |||
340 | /* Restore interrupts */ | ||
341 | mpic_cpu_set_priority(pic_prio); | ||
342 | |||
343 | /* Let interrupts flow again ... */ | ||
344 | local_irq_restore(flags); | ||
345 | |||
346 | #ifdef DEBUG_FREQ | ||
347 | debug_calc_bogomips(); | ||
348 | #endif | ||
349 | |||
350 | pmu_resume(); | ||
351 | |||
352 | preempt_enable(); | ||
353 | |||
354 | return 0; | ||
355 | } | ||
356 | |||
357 | static int do_set_cpu_speed(int speed_mode, int notify) | ||
358 | { | ||
359 | struct cpufreq_freqs freqs; | ||
360 | unsigned long l3cr; | ||
361 | static unsigned long prev_l3cr; | ||
362 | |||
363 | freqs.old = cur_freq; | ||
364 | freqs.new = (speed_mode == CPUFREQ_HIGH) ? hi_freq : low_freq; | ||
365 | freqs.cpu = smp_processor_id(); | ||
366 | |||
367 | if (freqs.old == freqs.new) | ||
368 | return 0; | ||
369 | |||
370 | if (notify) | ||
371 | cpufreq_notify_transition(&freqs, CPUFREQ_PRECHANGE); | ||
372 | if (speed_mode == CPUFREQ_LOW && | ||
373 | cpu_has_feature(CPU_FTR_L3CR)) { | ||
374 | l3cr = _get_L3CR(); | ||
375 | if (l3cr & L3CR_L3E) { | ||
376 | prev_l3cr = l3cr; | ||
377 | _set_L3CR(0); | ||
378 | } | ||
379 | } | ||
380 | set_speed_proc(speed_mode == CPUFREQ_LOW); | ||
381 | if (speed_mode == CPUFREQ_HIGH && | ||
382 | cpu_has_feature(CPU_FTR_L3CR)) { | ||
383 | l3cr = _get_L3CR(); | ||
384 | if ((prev_l3cr & L3CR_L3E) && l3cr != prev_l3cr) | ||
385 | _set_L3CR(prev_l3cr); | ||
386 | } | ||
387 | if (notify) | ||
388 | cpufreq_notify_transition(&freqs, CPUFREQ_POSTCHANGE); | ||
389 | cur_freq = (speed_mode == CPUFREQ_HIGH) ? hi_freq : low_freq; | ||
390 | |||
391 | return 0; | ||
392 | } | ||
393 | |||
394 | static unsigned int pmac_cpufreq_get_speed(unsigned int cpu) | ||
395 | { | ||
396 | return cur_freq; | ||
397 | } | ||
398 | |||
399 | static int pmac_cpufreq_verify(struct cpufreq_policy *policy) | ||
400 | { | ||
401 | return cpufreq_frequency_table_verify(policy, pmac_cpu_freqs); | ||
402 | } | ||
403 | |||
404 | static int pmac_cpufreq_target( struct cpufreq_policy *policy, | ||
405 | unsigned int target_freq, | ||
406 | unsigned int relation) | ||
407 | { | ||
408 | unsigned int newstate = 0; | ||
409 | |||
410 | if (cpufreq_frequency_table_target(policy, pmac_cpu_freqs, | ||
411 | target_freq, relation, &newstate)) | ||
412 | return -EINVAL; | ||
413 | |||
414 | return do_set_cpu_speed(newstate, 1); | ||
415 | } | ||
416 | |||
417 | unsigned int pmac_get_one_cpufreq(int i) | ||
418 | { | ||
419 | /* Supports only one CPU for now */ | ||
420 | return (i == 0) ? cur_freq : 0; | ||
421 | } | ||
422 | |||
423 | static int pmac_cpufreq_cpu_init(struct cpufreq_policy *policy) | ||
424 | { | ||
425 | if (policy->cpu != 0) | ||
426 | return -ENODEV; | ||
427 | |||
428 | policy->governor = CPUFREQ_DEFAULT_GOVERNOR; | ||
429 | policy->cpuinfo.transition_latency = CPUFREQ_ETERNAL; | ||
430 | policy->cur = cur_freq; | ||
431 | |||
432 | cpufreq_frequency_table_get_attr(pmac_cpu_freqs, policy->cpu); | ||
433 | return cpufreq_frequency_table_cpuinfo(policy, pmac_cpu_freqs); | ||
434 | } | ||
435 | |||
436 | static u32 read_gpio(struct device_node *np) | ||
437 | { | ||
438 | u32 *reg = (u32 *)get_property(np, "reg", NULL); | ||
439 | u32 offset; | ||
440 | |||
441 | if (reg == NULL) | ||
442 | return 0; | ||
443 | /* That works for all keylargos but shall be fixed properly | ||
444 | * some day... The problem is that it seems we can't rely | ||
445 | * on the "reg" property of the GPIO nodes, they are either | ||
446 | * relative to the base of KeyLargo or to the base of the | ||
447 | * GPIO space, and the device-tree doesn't help. | ||
448 | */ | ||
449 | offset = *reg; | ||
450 | if (offset < KEYLARGO_GPIO_LEVELS0) | ||
451 | offset += KEYLARGO_GPIO_LEVELS0; | ||
452 | return offset; | ||
453 | } | ||
454 | |||
455 | static int pmac_cpufreq_suspend(struct cpufreq_policy *policy, pm_message_t pmsg) | ||
456 | { | ||
457 | /* Ok, this could be made a bit smarter, but let's be robust for now. We | ||
458 | * always force a speed change to high speed before sleep, to make sure | ||
459 | * we have appropriate voltage and/or bus speed for the wakeup process, | ||
460 | * and to make sure our loops_per_jiffies are "good enough", that is will | ||
461 | * not cause too short delays if we sleep in low speed and wake in high | ||
462 | * speed.. | ||
463 | */ | ||
464 | no_schedule = 1; | ||
465 | sleep_freq = cur_freq; | ||
466 | if (cur_freq == low_freq && !is_pmu_based) | ||
467 | do_set_cpu_speed(CPUFREQ_HIGH, 0); | ||
468 | return 0; | ||
469 | } | ||
470 | |||
471 | static int pmac_cpufreq_resume(struct cpufreq_policy *policy) | ||
472 | { | ||
473 | /* If we resume, first check if we have a get() function */ | ||
474 | if (get_speed_proc) | ||
475 | cur_freq = get_speed_proc(); | ||
476 | else | ||
477 | cur_freq = 0; | ||
478 | |||
479 | /* We don't, hrm... we don't really know our speed here, best | ||
480 | * is that we force a switch to whatever it was, which is | ||
481 | * probably high speed due to our suspend() routine | ||
482 | */ | ||
483 | do_set_cpu_speed(sleep_freq == low_freq ? | ||
484 | CPUFREQ_LOW : CPUFREQ_HIGH, 0); | ||
485 | |||
486 | no_schedule = 0; | ||
487 | return 0; | ||
488 | } | ||
489 | |||
490 | static struct cpufreq_driver pmac_cpufreq_driver = { | ||
491 | .verify = pmac_cpufreq_verify, | ||
492 | .target = pmac_cpufreq_target, | ||
493 | .get = pmac_cpufreq_get_speed, | ||
494 | .init = pmac_cpufreq_cpu_init, | ||
495 | .suspend = pmac_cpufreq_suspend, | ||
496 | .resume = pmac_cpufreq_resume, | ||
497 | .flags = CPUFREQ_PM_NO_WARN, | ||
498 | .attr = pmac_cpu_freqs_attr, | ||
499 | .name = "powermac", | ||
500 | .owner = THIS_MODULE, | ||
501 | }; | ||
502 | |||
503 | |||
504 | static int pmac_cpufreq_init_MacRISC3(struct device_node *cpunode) | ||
505 | { | ||
506 | struct device_node *volt_gpio_np = of_find_node_by_name(NULL, | ||
507 | "voltage-gpio"); | ||
508 | struct device_node *freq_gpio_np = of_find_node_by_name(NULL, | ||
509 | "frequency-gpio"); | ||
510 | struct device_node *slew_done_gpio_np = of_find_node_by_name(NULL, | ||
511 | "slewing-done"); | ||
512 | u32 *value; | ||
513 | |||
514 | /* | ||
515 | * Check to see if it's GPIO driven or PMU only | ||
516 | * | ||
517 | * The way we extract the GPIO address is slightly hackish, but it | ||
518 | * works well enough for now. We need to abstract the whole GPIO | ||
519 | * stuff sooner or later anyway | ||
520 | */ | ||
521 | |||
522 | if (volt_gpio_np) | ||
523 | voltage_gpio = read_gpio(volt_gpio_np); | ||
524 | if (freq_gpio_np) | ||
525 | frequency_gpio = read_gpio(freq_gpio_np); | ||
526 | if (slew_done_gpio_np) | ||
527 | slew_done_gpio = read_gpio(slew_done_gpio_np); | ||
528 | |||
529 | /* If we use the frequency GPIOs, calculate the min/max speeds based | ||
530 | * on the bus frequencies | ||
531 | */ | ||
532 | if (frequency_gpio && slew_done_gpio) { | ||
533 | int lenp, rc; | ||
534 | u32 *freqs, *ratio; | ||
535 | |||
536 | freqs = (u32 *)get_property(cpunode, "bus-frequencies", &lenp); | ||
537 | lenp /= sizeof(u32); | ||
538 | if (freqs == NULL || lenp != 2) { | ||
539 | printk(KERN_ERR "cpufreq: bus-frequencies incorrect or missing\n"); | ||
540 | return 1; | ||
541 | } | ||
542 | ratio = (u32 *)get_property(cpunode, "processor-to-bus-ratio*2", NULL); | ||
543 | if (ratio == NULL) { | ||
544 | printk(KERN_ERR "cpufreq: processor-to-bus-ratio*2 missing\n"); | ||
545 | return 1; | ||
546 | } | ||
547 | |||
548 | /* Get the min/max bus frequencies */ | ||
549 | low_freq = min(freqs[0], freqs[1]); | ||
550 | hi_freq = max(freqs[0], freqs[1]); | ||
551 | |||
552 | /* Grrrr.. It _seems_ that the device-tree is lying on the low bus | ||
553 | * frequency, it claims it to be around 84Mhz on some models while | ||
554 | * it appears to be approx. 101Mhz on all. Let's hack around here... | ||
555 | * fortunately, we don't need to be too precise | ||
556 | */ | ||
557 | if (low_freq < 98000000) | ||
558 | low_freq = 101000000; | ||
559 | |||
560 | /* Convert those to CPU core clocks */ | ||
561 | low_freq = (low_freq * (*ratio)) / 2000; | ||
562 | hi_freq = (hi_freq * (*ratio)) / 2000; | ||
563 | |||
564 | /* Now we get the frequencies, we read the GPIO to see what is out current | ||
565 | * speed | ||
566 | */ | ||
567 | rc = pmac_call_feature(PMAC_FTR_READ_GPIO, NULL, frequency_gpio, 0); | ||
568 | cur_freq = (rc & 0x01) ? hi_freq : low_freq; | ||
569 | |||
570 | set_speed_proc = gpios_set_cpu_speed; | ||
571 | return 1; | ||
572 | } | ||
573 | |||
574 | /* If we use the PMU, look for the min & max frequencies in the | ||
575 | * device-tree | ||
576 | */ | ||
577 | value = (u32 *)get_property(cpunode, "min-clock-frequency", NULL); | ||
578 | if (!value) | ||
579 | return 1; | ||
580 | low_freq = (*value) / 1000; | ||
581 | /* The PowerBook G4 12" (PowerBook6,1) has an error in the device-tree | ||
582 | * here */ | ||
583 | if (low_freq < 100000) | ||
584 | low_freq *= 10; | ||
585 | |||
586 | value = (u32 *)get_property(cpunode, "max-clock-frequency", NULL); | ||
587 | if (!value) | ||
588 | return 1; | ||
589 | hi_freq = (*value) / 1000; | ||
590 | set_speed_proc = pmu_set_cpu_speed; | ||
591 | is_pmu_based = 1; | ||
592 | |||
593 | return 0; | ||
594 | } | ||
595 | |||
596 | static int pmac_cpufreq_init_7447A(struct device_node *cpunode) | ||
597 | { | ||
598 | struct device_node *volt_gpio_np; | ||
599 | |||
600 | if (get_property(cpunode, "dynamic-power-step", NULL) == NULL) | ||
601 | return 1; | ||
602 | |||
603 | volt_gpio_np = of_find_node_by_name(NULL, "cpu-vcore-select"); | ||
604 | if (volt_gpio_np) | ||
605 | voltage_gpio = read_gpio(volt_gpio_np); | ||
606 | if (!voltage_gpio){ | ||
607 | printk(KERN_ERR "cpufreq: missing cpu-vcore-select gpio\n"); | ||
608 | return 1; | ||
609 | } | ||
610 | |||
611 | /* OF only reports the high frequency */ | ||
612 | hi_freq = cur_freq; | ||
613 | low_freq = cur_freq/2; | ||
614 | |||
615 | /* Read actual frequency from CPU */ | ||
616 | cur_freq = dfs_get_cpu_speed(); | ||
617 | set_speed_proc = dfs_set_cpu_speed; | ||
618 | get_speed_proc = dfs_get_cpu_speed; | ||
619 | |||
620 | return 0; | ||
621 | } | ||
622 | |||
623 | static int pmac_cpufreq_init_750FX(struct device_node *cpunode) | ||
624 | { | ||
625 | struct device_node *volt_gpio_np; | ||
626 | u32 pvr, *value; | ||
627 | |||
628 | if (get_property(cpunode, "dynamic-power-step", NULL) == NULL) | ||
629 | return 1; | ||
630 | |||
631 | hi_freq = cur_freq; | ||
632 | value = (u32 *)get_property(cpunode, "reduced-clock-frequency", NULL); | ||
633 | if (!value) | ||
634 | return 1; | ||
635 | low_freq = (*value) / 1000; | ||
636 | |||
637 | volt_gpio_np = of_find_node_by_name(NULL, "cpu-vcore-select"); | ||
638 | if (volt_gpio_np) | ||
639 | voltage_gpio = read_gpio(volt_gpio_np); | ||
640 | |||
641 | pvr = mfspr(SPRN_PVR); | ||
642 | has_cpu_l2lve = !((pvr & 0xf00) == 0x100); | ||
643 | |||
644 | set_speed_proc = cpu_750fx_cpu_speed; | ||
645 | get_speed_proc = cpu_750fx_get_cpu_speed; | ||
646 | cur_freq = cpu_750fx_get_cpu_speed(); | ||
647 | |||
648 | return 0; | ||
649 | } | ||
650 | |||
651 | /* Currently, we support the following machines: | ||
652 | * | ||
653 | * - Titanium PowerBook 1Ghz (PMU based, 667Mhz & 1Ghz) | ||
654 | * - Titanium PowerBook 800 (PMU based, 667Mhz & 800Mhz) | ||
655 | * - Titanium PowerBook 400 (PMU based, 300Mhz & 400Mhz) | ||
656 | * - Titanium PowerBook 500 (PMU based, 300Mhz & 500Mhz) | ||
657 | * - iBook2 500/600 (PMU based, 400Mhz & 500/600Mhz) | ||
658 | * - iBook2 700 (CPU based, 400Mhz & 700Mhz, support low voltage) | ||
659 | * - Recent MacRISC3 laptops | ||
660 | * - All new machines with 7447A CPUs | ||
661 | */ | ||
662 | static int __init pmac_cpufreq_setup(void) | ||
663 | { | ||
664 | struct device_node *cpunode; | ||
665 | u32 *value; | ||
666 | |||
667 | if (strstr(cmd_line, "nocpufreq")) | ||
668 | return 0; | ||
669 | |||
670 | /* Assume only one CPU */ | ||
671 | cpunode = find_type_devices("cpu"); | ||
672 | if (!cpunode) | ||
673 | goto out; | ||
674 | |||
675 | /* Get current cpu clock freq */ | ||
676 | value = (u32 *)get_property(cpunode, "clock-frequency", NULL); | ||
677 | if (!value) | ||
678 | goto out; | ||
679 | cur_freq = (*value) / 1000; | ||
680 | |||
681 | /* Check for 7447A based MacRISC3 */ | ||
682 | if (machine_is_compatible("MacRISC3") && | ||
683 | get_property(cpunode, "dynamic-power-step", NULL) && | ||
684 | PVR_VER(mfspr(SPRN_PVR)) == 0x8003) { | ||
685 | pmac_cpufreq_init_7447A(cpunode); | ||
686 | /* Check for other MacRISC3 machines */ | ||
687 | } else if (machine_is_compatible("PowerBook3,4") || | ||
688 | machine_is_compatible("PowerBook3,5") || | ||
689 | machine_is_compatible("MacRISC3")) { | ||
690 | pmac_cpufreq_init_MacRISC3(cpunode); | ||
691 | /* Else check for iBook2 500/600 */ | ||
692 | } else if (machine_is_compatible("PowerBook4,1")) { | ||
693 | hi_freq = cur_freq; | ||
694 | low_freq = 400000; | ||
695 | set_speed_proc = pmu_set_cpu_speed; | ||
696 | is_pmu_based = 1; | ||
697 | } | ||
698 | /* Else check for TiPb 400 & 500 */ | ||
699 | else if (machine_is_compatible("PowerBook3,2")) { | ||
700 | /* We only know about the 400 MHz and the 500Mhz model | ||
701 | * they both have 300 MHz as low frequency | ||
702 | */ | ||
703 | if (cur_freq < 350000 || cur_freq > 550000) | ||
704 | goto out; | ||
705 | hi_freq = cur_freq; | ||
706 | low_freq = 300000; | ||
707 | set_speed_proc = pmu_set_cpu_speed; | ||
708 | is_pmu_based = 1; | ||
709 | } | ||
710 | /* Else check for 750FX */ | ||
711 | else if (PVR_VER(mfspr(SPRN_PVR)) == 0x7000) | ||
712 | pmac_cpufreq_init_750FX(cpunode); | ||
713 | out: | ||
714 | if (set_speed_proc == NULL) | ||
715 | return -ENODEV; | ||
716 | |||
717 | pmac_cpu_freqs[CPUFREQ_LOW].frequency = low_freq; | ||
718 | pmac_cpu_freqs[CPUFREQ_HIGH].frequency = hi_freq; | ||
719 | |||
720 | printk(KERN_INFO "Registering PowerMac CPU frequency driver\n"); | ||
721 | printk(KERN_INFO "Low: %d Mhz, High: %d Mhz, Boot: %d Mhz\n", | ||
722 | low_freq/1000, hi_freq/1000, cur_freq/1000); | ||
723 | |||
724 | return cpufreq_register_driver(&pmac_cpufreq_driver); | ||
725 | } | ||
726 | |||
727 | module_init(pmac_cpufreq_setup); | ||
728 | |||