aboutsummaryrefslogtreecommitdiffstats
path: root/arch
diff options
context:
space:
mode:
authorBenjamin Herrenschmidt <benh@kernel.crashing.org>2006-01-06 19:45:28 -0500
committerPaul Mackerras <paulus@samba.org>2006-01-08 23:47:19 -0500
commit9a699aefa87cb0379a67741926820c9271d748a9 (patch)
tree18e498b6ea54ae229bf7a01ac1c1448fbb03b6a3 /arch
parent5b9ca526917b7bc7d1da3beaccb2251a8f0b5fe2 (diff)
[PATCH] 4/5 powerpc: Add cpufreq support for all desktop G5
This patch adds cpufreq support for all desktop "tower" G5 models. The only G5 models still lacking cpufreq support at this point are the Xserve and possibly the new iMac iSight (not tested). I'll have those added soon. That patch uses the new platform functions interpreter to implement frequency and voltage switching on most models. Note that in order to find the low frequency value, I had to hack something that might now work properly on all models, so if the frequency value reported when running low speed looks bogus to you, please report it to me. (Appart from a bogus reported value, things should work fine). Signed-off-by: Benjamin Herrenschmidt <benh@kernel.crashing.org> Signed-off-by: Paul Mackerras <paulus@samba.org>
Diffstat (limited to 'arch')
-rw-r--r--arch/powerpc/platforms/powermac/cpufreq_64.c496
1 files changed, 449 insertions, 47 deletions
diff --git a/arch/powerpc/platforms/powermac/cpufreq_64.c b/arch/powerpc/platforms/powermac/cpufreq_64.c
index 39150342c6f1..a4b50c4109c2 100644
--- a/arch/powerpc/platforms/powermac/cpufreq_64.c
+++ b/arch/powerpc/platforms/powermac/cpufreq_64.c
@@ -28,6 +28,7 @@
28#include <asm/cputable.h> 28#include <asm/cputable.h>
29#include <asm/time.h> 29#include <asm/time.h>
30#include <asm/smu.h> 30#include <asm/smu.h>
31#include <asm/pmac_pfunc.h>
31 32
32#undef DEBUG 33#undef DEBUG
33 34
@@ -85,6 +86,10 @@ static u32 *g5_pmode_data;
85static int g5_pmode_max; 86static int g5_pmode_max;
86static int g5_pmode_cur; 87static int g5_pmode_cur;
87 88
89static void (*g5_switch_volt)(int speed_mode);
90static int (*g5_switch_freq)(int speed_mode);
91static int (*g5_query_freq)(void);
92
88static DECLARE_MUTEX(g5_switch_mutex); 93static DECLARE_MUTEX(g5_switch_mutex);
89 94
90 95
@@ -92,9 +97,11 @@ static struct smu_sdbp_fvt *g5_fvt_table; /* table of op. points */
92static int g5_fvt_count; /* number of op. points */ 97static int g5_fvt_count; /* number of op. points */
93static int g5_fvt_cur; /* current op. point */ 98static int g5_fvt_cur; /* current op. point */
94 99
95/* ----------------- real hardware interface */ 100/*
101 * SMU based voltage switching for Neo2 platforms
102 */
96 103
97static void g5_switch_volt(int speed_mode) 104static void g5_smu_switch_volt(int speed_mode)
98{ 105{
99 struct smu_simple_cmd cmd; 106 struct smu_simple_cmd cmd;
100 107
@@ -105,26 +112,57 @@ static void g5_switch_volt(int speed_mode)
105 wait_for_completion(&comp); 112 wait_for_completion(&comp);
106} 113}
107 114
108static int g5_switch_freq(int speed_mode) 115/*
116 * Platform function based voltage/vdnap switching for Neo2
117 */
118
119static struct pmf_function *pfunc_set_vdnap0;
120static struct pmf_function *pfunc_vdnap0_complete;
121
122static void g5_vdnap_switch_volt(int speed_mode)
109{ 123{
110 struct cpufreq_freqs freqs; 124 struct pmf_args args;
111 int to; 125 u32 slew, done = 0;
126 unsigned long timeout;
112 127
113 if (g5_pmode_cur == speed_mode) 128 slew = (speed_mode == CPUFREQ_LOW) ? 1 : 0;
114 return 0; 129 args.count = 1;
130 args.u[0].p = &slew;
115 131
116 down(&g5_switch_mutex); 132 pmf_call_one(pfunc_set_vdnap0, &args);
117 133
118 freqs.old = g5_cpu_freqs[g5_pmode_cur].frequency; 134 /* It's an irq GPIO so we should be able to just block here,
119 freqs.new = g5_cpu_freqs[speed_mode].frequency; 135 * I'll do that later after I've properly tested the IRQ code for
120 freqs.cpu = 0; 136 * platform functions
137 */
138 timeout = jiffies + HZ/10;
139 while(!time_after(jiffies, timeout)) {
140 args.count = 1;
141 args.u[0].p = &done;
142 pmf_call_one(pfunc_vdnap0_complete, &args);
143 if (done)
144 break;
145 msleep(1);
146 }
147 if (done == 0)
148 printk(KERN_WARNING "cpufreq: Timeout in clock slewing !\n");
149}
121 150
122 cpufreq_notify_transition(&freqs, CPUFREQ_PRECHANGE); 151
152/*
153 * SCOM based frequency switching for 970FX rev3
154 */
155static int g5_scom_switch_freq(int speed_mode)
156{
157 unsigned long flags;
158 int to;
123 159
124 /* If frequency is going up, first ramp up the voltage */ 160 /* If frequency is going up, first ramp up the voltage */
125 if (speed_mode < g5_pmode_cur) 161 if (speed_mode < g5_pmode_cur)
126 g5_switch_volt(speed_mode); 162 g5_switch_volt(speed_mode);
127 163
164 local_irq_save(flags);
165
128 /* Clear PCR high */ 166 /* Clear PCR high */
129 scom970_write(SCOM_PCR, 0); 167 scom970_write(SCOM_PCR, 0);
130 /* Clear PCR low */ 168 /* Clear PCR low */
@@ -147,6 +185,8 @@ static int g5_switch_freq(int speed_mode)
147 udelay(100); 185 udelay(100);
148 } 186 }
149 187
188 local_irq_restore(flags);
189
150 /* If frequency is going down, last ramp the voltage */ 190 /* If frequency is going down, last ramp the voltage */
151 if (speed_mode > g5_pmode_cur) 191 if (speed_mode > g5_pmode_cur)
152 g5_switch_volt(speed_mode); 192 g5_switch_volt(speed_mode);
@@ -154,14 +194,10 @@ static int g5_switch_freq(int speed_mode)
154 g5_pmode_cur = speed_mode; 194 g5_pmode_cur = speed_mode;
155 ppc_proc_freq = g5_cpu_freqs[speed_mode].frequency * 1000ul; 195 ppc_proc_freq = g5_cpu_freqs[speed_mode].frequency * 1000ul;
156 196
157 cpufreq_notify_transition(&freqs, CPUFREQ_POSTCHANGE);
158
159 up(&g5_switch_mutex);
160
161 return 0; 197 return 0;
162} 198}
163 199
164static int g5_query_freq(void) 200static int g5_scom_query_freq(void)
165{ 201{
166 unsigned long psr = scom970_read(SCOM_PSR); 202 unsigned long psr = scom970_read(SCOM_PSR);
167 int i; 203 int i;
@@ -173,7 +209,104 @@ static int g5_query_freq(void)
173 return i; 209 return i;
174} 210}
175 211
176/* ----------------- cpufreq bookkeeping */ 212/*
213 * Platform function based voltage switching for PowerMac7,2 & 7,3
214 */
215
216static struct pmf_function *pfunc_cpu0_volt_high;
217static struct pmf_function *pfunc_cpu0_volt_low;
218static struct pmf_function *pfunc_cpu1_volt_high;
219static struct pmf_function *pfunc_cpu1_volt_low;
220
221static void g5_pfunc_switch_volt(int speed_mode)
222{
223 if (speed_mode == CPUFREQ_HIGH) {
224 if (pfunc_cpu0_volt_high)
225 pmf_call_one(pfunc_cpu0_volt_high, NULL);
226 if (pfunc_cpu1_volt_high)
227 pmf_call_one(pfunc_cpu1_volt_high, NULL);
228 } else {
229 if (pfunc_cpu0_volt_low)
230 pmf_call_one(pfunc_cpu0_volt_low, NULL);
231 if (pfunc_cpu1_volt_low)
232 pmf_call_one(pfunc_cpu1_volt_low, NULL);
233 }
234 msleep(10); /* should be faster , to fix */
235}
236
237/*
238 * Platform function based frequency switching for PowerMac7,2 & 7,3
239 */
240
241static struct pmf_function *pfunc_cpu_setfreq_high;
242static struct pmf_function *pfunc_cpu_setfreq_low;
243static struct pmf_function *pfunc_cpu_getfreq;
244static struct pmf_function *pfunc_slewing_done;;
245
246static int g5_pfunc_switch_freq(int speed_mode)
247{
248 struct pmf_args args;
249 u32 done = 0;
250 unsigned long timeout;
251
252 /* If frequency is going up, first ramp up the voltage */
253 if (speed_mode < g5_pmode_cur)
254 g5_switch_volt(speed_mode);
255
256 /* Do it */
257 if (speed_mode == CPUFREQ_HIGH)
258 pmf_call_one(pfunc_cpu_setfreq_high, NULL);
259 else
260 pmf_call_one(pfunc_cpu_setfreq_low, NULL);
261
262 /* It's an irq GPIO so we should be able to just block here,
263 * I'll do that later after I've properly tested the IRQ code for
264 * platform functions
265 */
266 timeout = jiffies + HZ/10;
267 while(!time_after(jiffies, timeout)) {
268 args.count = 1;
269 args.u[0].p = &done;
270 pmf_call_one(pfunc_slewing_done, &args);
271 if (done)
272 break;
273 msleep(1);
274 }
275 if (done == 0)
276 printk(KERN_WARNING "cpufreq: Timeout in clock slewing !\n");
277
278 /* If frequency is going down, last ramp the voltage */
279 if (speed_mode > g5_pmode_cur)
280 g5_switch_volt(speed_mode);
281
282 g5_pmode_cur = speed_mode;
283 ppc_proc_freq = g5_cpu_freqs[speed_mode].frequency * 1000ul;
284
285 return 0;
286}
287
288static int g5_pfunc_query_freq(void)
289{
290 struct pmf_args args;
291 u32 val = 0;
292
293 args.count = 1;
294 args.u[0].p = &val;
295 pmf_call_one(pfunc_cpu_getfreq, &args);
296 return val ? CPUFREQ_HIGH : CPUFREQ_LOW;
297}
298
299/*
300 * Fake voltage switching for platforms with missing support
301 */
302
303static void g5_dummy_switch_volt(int speed_mode)
304{
305}
306
307/*
308 * Common interface to the cpufreq core
309 */
177 310
178static int g5_cpufreq_verify(struct cpufreq_policy *policy) 311static int g5_cpufreq_verify(struct cpufreq_policy *policy)
179{ 312{
@@ -183,13 +316,30 @@ static int g5_cpufreq_verify(struct cpufreq_policy *policy)
183static int g5_cpufreq_target(struct cpufreq_policy *policy, 316static int g5_cpufreq_target(struct cpufreq_policy *policy,
184 unsigned int target_freq, unsigned int relation) 317 unsigned int target_freq, unsigned int relation)
185{ 318{
186 unsigned int newstate = 0; 319 unsigned int newstate = 0;
320 struct cpufreq_freqs freqs;
321 int rc;
187 322
188 if (cpufreq_frequency_table_target(policy, g5_cpu_freqs, 323 if (cpufreq_frequency_table_target(policy, g5_cpu_freqs,
189 target_freq, relation, &newstate)) 324 target_freq, relation, &newstate))
190 return -EINVAL; 325 return -EINVAL;
191 326
192 return g5_switch_freq(newstate); 327 if (g5_pmode_cur == newstate)
328 return 0;
329
330 down(&g5_switch_mutex);
331
332 freqs.old = g5_cpu_freqs[g5_pmode_cur].frequency;
333 freqs.new = g5_cpu_freqs[newstate].frequency;
334 freqs.cpu = 0;
335
336 cpufreq_notify_transition(&freqs, CPUFREQ_PRECHANGE);
337 rc = g5_switch_freq(newstate);
338 cpufreq_notify_transition(&freqs, CPUFREQ_POSTCHANGE);
339
340 up(&g5_switch_mutex);
341
342 return rc;
193} 343}
194 344
195static unsigned int g5_cpufreq_get_speed(unsigned int cpu) 345static unsigned int g5_cpufreq_get_speed(unsigned int cpu)
@@ -205,6 +355,7 @@ static int g5_cpufreq_cpu_init(struct cpufreq_policy *policy)
205 policy->governor = CPUFREQ_DEFAULT_GOVERNOR; 355 policy->governor = CPUFREQ_DEFAULT_GOVERNOR;
206 policy->cpuinfo.transition_latency = CPUFREQ_ETERNAL; 356 policy->cpuinfo.transition_latency = CPUFREQ_ETERNAL;
207 policy->cur = g5_cpu_freqs[g5_query_freq()].frequency; 357 policy->cur = g5_cpu_freqs[g5_query_freq()].frequency;
358 policy->cpus = cpu_possible_map;
208 cpufreq_frequency_table_get_attr(g5_cpu_freqs, policy->cpu); 359 cpufreq_frequency_table_get_attr(g5_cpu_freqs, policy->cpu);
209 360
210 return cpufreq_frequency_table_cpuinfo(policy, 361 return cpufreq_frequency_table_cpuinfo(policy,
@@ -224,19 +375,39 @@ static struct cpufreq_driver g5_cpufreq_driver = {
224}; 375};
225 376
226 377
227static int __init g5_cpufreq_init(void) 378static int __init g5_neo2_cpufreq_init(struct device_node *cpus)
228{ 379{
229 struct device_node *cpunode; 380 struct device_node *cpunode;
230 unsigned int psize, ssize; 381 unsigned int psize, ssize;
231 struct smu_sdbp_header *shdr;
232 unsigned long max_freq; 382 unsigned long max_freq;
233 u32 *valp; 383 char *freq_method, *volt_method;
384 u32 *valp, pvr_hi;
385 int use_volts_vdnap = 0;
386 int use_volts_smu = 0;
234 int rc = -ENODEV; 387 int rc = -ENODEV;
235 388
236 /* Look for CPU and SMU nodes */ 389 /* Check supported platforms */
237 cpunode = of_find_node_by_type(NULL, "cpu"); 390 if (machine_is_compatible("PowerMac8,1") ||
238 if (!cpunode) { 391 machine_is_compatible("PowerMac8,2") ||
239 DBG("No CPU node !\n"); 392 machine_is_compatible("PowerMac9,1"))
393 use_volts_smu = 1;
394 else if (machine_is_compatible("PowerMac11,2"))
395 use_volts_vdnap = 1;
396 else
397 return -ENODEV;
398
399 /* Get first CPU node */
400 for (cpunode = NULL;
401 (cpunode = of_get_next_child(cpus, cpunode)) != NULL;) {
402 u32 *reg =
403 (u32 *)get_property(cpunode, "reg", NULL);
404 if (reg == NULL || (*reg) != 0)
405 continue;
406 if (!strcmp(cpunode->type, "cpu"))
407 break;
408 }
409 if (cpunode == NULL) {
410 printk(KERN_ERR "cpufreq: Can't find any CPU 0 node\n");
240 return -ENODEV; 411 return -ENODEV;
241 } 412 }
242 413
@@ -246,8 +417,9 @@ static int __init g5_cpufreq_init(void)
246 DBG("No cpu-version property !\n"); 417 DBG("No cpu-version property !\n");
247 goto bail_noprops; 418 goto bail_noprops;
248 } 419 }
249 if (((*valp) >> 16) != 0x3c) { 420 pvr_hi = (*valp) >> 16;
250 DBG("Wrong CPU version: %08x\n", *valp); 421 if (pvr_hi != 0x3c && pvr_hi != 0x44) {
422 printk(KERN_ERR "cpufreq: Unsupported CPU version\n");
251 goto bail_noprops; 423 goto bail_noprops;
252 } 424 }
253 425
@@ -259,18 +431,50 @@ static int __init g5_cpufreq_init(void)
259 } 431 }
260 g5_pmode_max = psize / sizeof(u32) - 1; 432 g5_pmode_max = psize / sizeof(u32) - 1;
261 433
262 /* Look for the FVT table */ 434 if (use_volts_smu) {
263 shdr = smu_get_sdb_partition(SMU_SDB_FVT_ID, NULL); 435 struct smu_sdbp_header *shdr;
264 if (!shdr) 436
265 goto bail_noprops; 437 /* Look for the FVT table */
266 g5_fvt_table = (struct smu_sdbp_fvt *)&shdr[1]; 438 shdr = smu_get_sdb_partition(SMU_SDB_FVT_ID, NULL);
267 ssize = (shdr->len * sizeof(u32)) - sizeof(struct smu_sdbp_header); 439 if (!shdr)
268 g5_fvt_count = ssize / sizeof(struct smu_sdbp_fvt); 440 goto bail_noprops;
269 g5_fvt_cur = 0; 441 g5_fvt_table = (struct smu_sdbp_fvt *)&shdr[1];
270 442 ssize = (shdr->len * sizeof(u32)) -
271 /* Sanity checking */ 443 sizeof(struct smu_sdbp_header);
272 if (g5_fvt_count < 1 || g5_pmode_max < 1) 444 g5_fvt_count = ssize / sizeof(struct smu_sdbp_fvt);
273 goto bail_noprops; 445 g5_fvt_cur = 0;
446
447 /* Sanity checking */
448 if (g5_fvt_count < 1 || g5_pmode_max < 1)
449 goto bail_noprops;
450
451 g5_switch_volt = g5_smu_switch_volt;
452 volt_method = "SMU";
453 } else if (use_volts_vdnap) {
454 struct device_node *root;
455
456 root = of_find_node_by_path("/");
457 if (root == NULL) {
458 printk(KERN_ERR "cpufreq: Can't find root of "
459 "device tree\n");
460 goto bail_noprops;
461 }
462 pfunc_set_vdnap0 = pmf_find_function(root, "set-vdnap0");
463 pfunc_vdnap0_complete =
464 pmf_find_function(root, "slewing-done");
465 if (pfunc_set_vdnap0 == NULL ||
466 pfunc_vdnap0_complete == NULL) {
467 printk(KERN_ERR "cpufreq: Can't find required "
468 "platform function\n");
469 goto bail_noprops;
470 }
471
472 g5_switch_volt = g5_vdnap_switch_volt;
473 volt_method = "GPIO";
474 } else {
475 g5_switch_volt = g5_dummy_switch_volt;
476 volt_method = "none";
477 }
274 478
275 /* 479 /*
276 * From what I see, clock-frequency is always the maximal frequency. 480 * From what I see, clock-frequency is always the maximal frequency.
@@ -286,19 +490,23 @@ static int __init g5_cpufreq_init(void)
286 g5_cpu_freqs[0].frequency = max_freq; 490 g5_cpu_freqs[0].frequency = max_freq;
287 g5_cpu_freqs[1].frequency = max_freq/2; 491 g5_cpu_freqs[1].frequency = max_freq/2;
288 492
289 /* Check current frequency */ 493 /* Set callbacks */
290 g5_pmode_cur = g5_query_freq(); 494 g5_switch_freq = g5_scom_switch_freq;
291 if (g5_pmode_cur > 1) 495 g5_query_freq = g5_scom_query_freq;
292 /* We don't support anything but 1:1 and 1:2, fixup ... */ 496 freq_method = "SCOM";
293 g5_pmode_cur = 1;
294 497
295 /* Force apply current frequency to make sure everything is in 498 /* Force apply current frequency to make sure everything is in
296 * sync (voltage is right for example). Firmware may leave us with 499 * sync (voltage is right for example). Firmware may leave us with
297 * a strange setting ... 500 * a strange setting ...
298 */ 501 */
299 g5_switch_freq(g5_pmode_cur); 502 g5_switch_volt(CPUFREQ_HIGH);
503 msleep(10);
504 g5_pmode_cur = -1;
505 g5_switch_freq(g5_query_freq());
300 506
301 printk(KERN_INFO "Registering G5 CPU frequency driver\n"); 507 printk(KERN_INFO "Registering G5 CPU frequency driver\n");
508 printk(KERN_INFO "Frequency method: %s, Voltage method: %s\n",
509 freq_method, volt_method);
302 printk(KERN_INFO "Low: %d Mhz, High: %d Mhz, Cur: %d MHz\n", 510 printk(KERN_INFO "Low: %d Mhz, High: %d Mhz, Cur: %d MHz\n",
303 g5_cpu_freqs[1].frequency/1000, 511 g5_cpu_freqs[1].frequency/1000,
304 g5_cpu_freqs[0].frequency/1000, 512 g5_cpu_freqs[0].frequency/1000,
@@ -317,6 +525,200 @@ static int __init g5_cpufreq_init(void)
317 return rc; 525 return rc;
318} 526}
319 527
528static int __init g5_pm72_cpufreq_init(struct device_node *cpus)
529{
530 struct device_node *cpuid = NULL, *hwclock = NULL, *cpunode = NULL;
531 u8 *eeprom = NULL;
532 u32 *valp;
533 u64 max_freq, min_freq, ih, il;
534 int has_volt = 1, rc = 0;
535
536 /* Get first CPU node */
537 for (cpunode = NULL;
538 (cpunode = of_get_next_child(cpus, cpunode)) != NULL;) {
539 if (!strcmp(cpunode->type, "cpu"))
540 break;
541 }
542 if (cpunode == NULL) {
543 printk(KERN_ERR "cpufreq: Can't find any CPU node\n");
544 return -ENODEV;
545 }
546
547 /* Lookup the cpuid eeprom node */
548 cpuid = of_find_node_by_path("/u3@0,f8000000/i2c@f8001000/cpuid@a0");
549 if (cpuid != NULL)
550 eeprom = (u8 *)get_property(cpuid, "cpuid", NULL);
551 if (eeprom == NULL) {
552 printk(KERN_ERR "cpufreq: Can't find cpuid EEPROM !\n");
553 rc = -ENODEV;
554 goto bail;
555 }
556
557 /* Lookup the i2c hwclock */
558 for (hwclock = NULL;
559 (hwclock = of_find_node_by_name(hwclock, "i2c-hwclock")) != NULL;){
560 char *loc = get_property(hwclock, "hwctrl-location", NULL);
561 if (loc == NULL)
562 continue;
563 if (strcmp(loc, "CPU CLOCK"))
564 continue;
565 if (!get_property(hwclock, "platform-get-frequency", NULL))
566 continue;
567 break;
568 }
569 if (hwclock == NULL) {
570 printk(KERN_ERR "cpufreq: Can't find i2c clock chip !\n");
571 rc = -ENODEV;
572 goto bail;
573 }
574
575 DBG("cpufreq: i2c clock chip found: %s\n", hwclock->full_name);
576
577 /* Now get all the platform functions */
578 pfunc_cpu_getfreq =
579 pmf_find_function(hwclock, "get-frequency");
580 pfunc_cpu_setfreq_high =
581 pmf_find_function(hwclock, "set-frequency-high");
582 pfunc_cpu_setfreq_low =
583 pmf_find_function(hwclock, "set-frequency-low");
584 pfunc_slewing_done =
585 pmf_find_function(hwclock, "slewing-done");
586 pfunc_cpu0_volt_high =
587 pmf_find_function(hwclock, "set-voltage-high-0");
588 pfunc_cpu0_volt_low =
589 pmf_find_function(hwclock, "set-voltage-low-0");
590 pfunc_cpu1_volt_high =
591 pmf_find_function(hwclock, "set-voltage-high-1");
592 pfunc_cpu1_volt_low =
593 pmf_find_function(hwclock, "set-voltage-low-1");
594
595 /* Check we have minimum requirements */
596 if (pfunc_cpu_getfreq == NULL || pfunc_cpu_setfreq_high == NULL ||
597 pfunc_cpu_setfreq_low == NULL || pfunc_slewing_done == NULL) {
598 printk(KERN_ERR "cpufreq: Can't find platform functions !\n");
599 rc = -ENODEV;
600 goto bail;
601 }
602
603 /* Check that we have complete sets */
604 if (pfunc_cpu0_volt_high == NULL || pfunc_cpu0_volt_low == NULL) {
605 pmf_put_function(pfunc_cpu0_volt_high);
606 pmf_put_function(pfunc_cpu0_volt_low);
607 pfunc_cpu0_volt_high = pfunc_cpu0_volt_low = NULL;
608 has_volt = 0;
609 }
610 if (!has_volt ||
611 pfunc_cpu1_volt_high == NULL || pfunc_cpu1_volt_low == NULL) {
612 pmf_put_function(pfunc_cpu1_volt_high);
613 pmf_put_function(pfunc_cpu1_volt_low);
614 pfunc_cpu1_volt_high = pfunc_cpu1_volt_low = NULL;
615 }
616
617 /* Note: The device tree also contains a "platform-set-values"
618 * function for which I haven't quite figured out the usage. It
619 * might have to be called on init and/or wakeup, I'm not too sure
620 * but things seem to work fine without it so far ...
621 */
622
623 /* Get max frequency from device-tree */
624 valp = (u32 *)get_property(cpunode, "clock-frequency", NULL);
625 if (!valp) {
626 printk(KERN_ERR "cpufreq: Can't find CPU frequency !\n");
627 rc = -ENODEV;
628 goto bail;
629 }
630
631 max_freq = (*valp)/1000;
632
633 /* Now calculate reduced frequency by using the cpuid input freq
634 * ratio. This requires 64 bits math unless we are willing to lose
635 * some precision
636 */
637 ih = *((u32 *)(eeprom + 0x10));
638 il = *((u32 *)(eeprom + 0x20));
639 min_freq = 0;
640 if (ih != 0 && il != 0)
641 min_freq = (max_freq * il) / ih;
642
643 /* Sanity check */
644 if (min_freq >= max_freq || min_freq < 1000) {
645 printk(KERN_ERR "cpufreq: Can't calculate low frequency !\n");
646 rc = -ENODEV;
647 goto bail;
648 }
649 g5_cpu_freqs[0].frequency = max_freq;
650 g5_cpu_freqs[1].frequency = min_freq;
651
652 /* Set callbacks */
653 g5_switch_volt = g5_pfunc_switch_volt;
654 g5_switch_freq = g5_pfunc_switch_freq;
655 g5_query_freq = g5_pfunc_query_freq;
656
657 /* Force apply current frequency to make sure everything is in
658 * sync (voltage is right for example). Firmware may leave us with
659 * a strange setting ...
660 */
661 g5_switch_volt(CPUFREQ_HIGH);
662 msleep(10);
663 g5_pmode_cur = -1;
664 g5_switch_freq(g5_query_freq());
665
666 printk(KERN_INFO "Registering G5 CPU frequency driver\n");
667 printk(KERN_INFO "Frequency method: i2c/pfunc, "
668 "Voltage method: %s\n", has_volt ? "i2c/pfunc" : "none");
669 printk(KERN_INFO "Low: %d Mhz, High: %d Mhz, Cur: %d MHz\n",
670 g5_cpu_freqs[1].frequency/1000,
671 g5_cpu_freqs[0].frequency/1000,
672 g5_cpu_freqs[g5_pmode_cur].frequency/1000);
673
674 rc = cpufreq_register_driver(&g5_cpufreq_driver);
675 bail:
676 if (rc != 0) {
677 pmf_put_function(pfunc_cpu_getfreq);
678 pmf_put_function(pfunc_cpu_setfreq_high);
679 pmf_put_function(pfunc_cpu_setfreq_low);
680 pmf_put_function(pfunc_slewing_done);
681 pmf_put_function(pfunc_cpu0_volt_high);
682 pmf_put_function(pfunc_cpu0_volt_low);
683 pmf_put_function(pfunc_cpu1_volt_high);
684 pmf_put_function(pfunc_cpu1_volt_low);
685 }
686 of_node_put(hwclock);
687 of_node_put(cpuid);
688 of_node_put(cpunode);
689
690 return rc;
691}
692
693static int __init g5_rm31_cpufreq_init(struct device_node *cpus)
694{
695 /* NYI */
696 return 0;
697}
698
699static int __init g5_cpufreq_init(void)
700{
701 struct device_node *cpus;
702 int rc;
703
704 cpus = of_find_node_by_path("/cpus");
705 if (cpus == NULL) {
706 DBG("No /cpus node !\n");
707 return -ENODEV;
708 }
709
710 if (machine_is_compatible("PowerMac7,2") ||
711 machine_is_compatible("PowerMac7,3"))
712 rc = g5_pm72_cpufreq_init(cpus);
713 else if (machine_is_compatible("RackMac3,1"))
714 rc = g5_rm31_cpufreq_init(cpus);
715 else
716 rc = g5_neo2_cpufreq_init(cpus);
717
718 of_node_put(cpus);
719 return rc;
720}
721
320module_init(g5_cpufreq_init); 722module_init(g5_cpufreq_init);
321 723
322 724