aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorBenjamin Herrenschmidt <benh@kernel.crashing.org>2006-07-06 01:09:19 -0400
committerPaul Mackerras <paulus@samba.org>2006-07-07 06:19:16 -0400
commit7ed14c2177694ce086180eb9ca9ca4c6cd72c7ef (patch)
tree3ae86ab89905167c8fdc9f220524d4d693895108
parent861fa7737db889ae1701ba58c083d4a7bd8705d3 (diff)
[POWERPC] Add cpufreq support for Xserve G5
The Xserve G5 are capable of frequency switching like other desktop G5s. This enables it. It also fix a Kconfig issue which prevented from building the G5 cpufreq support if CONFIG_PMAC_SMU was not set (the first version of that driver only worked with SMU based macs, but this isn't the case anymore). Signed-off-by: Benjamin Herrenschmidt <benh@kernel.crashing.org> Signed-off-by: Paul Mackerras <paulus@samba.org>
-rw-r--r--arch/powerpc/Kconfig2
-rw-r--r--arch/powerpc/platforms/powermac/cpufreq_64.c78
2 files changed, 50 insertions, 30 deletions
diff --git a/arch/powerpc/Kconfig b/arch/powerpc/Kconfig
index 2643dbc3f289..13e583f16ede 100644
--- a/arch/powerpc/Kconfig
+++ b/arch/powerpc/Kconfig
@@ -504,7 +504,7 @@ config CPU_FREQ_PMAC
504 504
505config CPU_FREQ_PMAC64 505config CPU_FREQ_PMAC64
506 bool "Support for some Apple G5s" 506 bool "Support for some Apple G5s"
507 depends on CPU_FREQ && PMAC_SMU && PPC64 507 depends on CPU_FREQ && PPC64
508 select CPU_FREQ_TABLE 508 select CPU_FREQ_TABLE
509 help 509 help
510 This adds support for frequency switching on Apple iMac G5, 510 This adds support for frequency switching on Apple iMac G5,
diff --git a/arch/powerpc/platforms/powermac/cpufreq_64.c b/arch/powerpc/platforms/powermac/cpufreq_64.c
index f08a14516139..a6a84ac5433e 100644
--- a/arch/powerpc/platforms/powermac/cpufreq_64.c
+++ b/arch/powerpc/platforms/powermac/cpufreq_64.c
@@ -10,6 +10,8 @@
10 * that is iMac G5 and latest single CPU desktop. 10 * that is iMac G5 and latest single CPU desktop.
11 */ 11 */
12 12
13#undef DEBUG
14
13#include <linux/module.h> 15#include <linux/module.h>
14#include <linux/types.h> 16#include <linux/types.h>
15#include <linux/errno.h> 17#include <linux/errno.h>
@@ -30,13 +32,7 @@
30#include <asm/smu.h> 32#include <asm/smu.h>
31#include <asm/pmac_pfunc.h> 33#include <asm/pmac_pfunc.h>
32 34
33#undef DEBUG 35#define DBG(fmt...) pr_debug(fmt)
34
35#ifdef DEBUG
36#define DBG(fmt...) printk(fmt)
37#else
38#define DBG(fmt...)
39#endif
40 36
41/* see 970FX user manual */ 37/* see 970FX user manual */
42 38
@@ -82,8 +78,6 @@ static struct freq_attr* g5_cpu_freqs_attr[] = {
82/* Power mode data is an array of the 32 bits PCR values to use for 78/* Power mode data is an array of the 32 bits PCR values to use for
83 * the various frequencies, retrieved from the device-tree 79 * the various frequencies, retrieved from the device-tree
84 */ 80 */
85static u32 *g5_pmode_data;
86static int g5_pmode_max;
87static int g5_pmode_cur; 81static int g5_pmode_cur;
88 82
89static void (*g5_switch_volt)(int speed_mode); 83static void (*g5_switch_volt)(int speed_mode);
@@ -93,6 +87,11 @@ static int (*g5_query_freq)(void);
93static DEFINE_MUTEX(g5_switch_mutex); 87static DEFINE_MUTEX(g5_switch_mutex);
94 88
95 89
90#ifdef CONFIG_PPC_SMU
91
92static u32 *g5_pmode_data;
93static int g5_pmode_max;
94
96static struct smu_sdbp_fvt *g5_fvt_table; /* table of op. points */ 95static struct smu_sdbp_fvt *g5_fvt_table; /* table of op. points */
97static int g5_fvt_count; /* number of op. points */ 96static int g5_fvt_count; /* number of op. points */
98static int g5_fvt_cur; /* current op. point */ 97static int g5_fvt_cur; /* current op. point */
@@ -210,6 +209,16 @@ static int g5_scom_query_freq(void)
210} 209}
211 210
212/* 211/*
212 * Fake voltage switching for platforms with missing support
213 */
214
215static void g5_dummy_switch_volt(int speed_mode)
216{
217}
218
219#endif /* CONFIG_PPC_SMU */
220
221/*
213 * Platform function based voltage switching for PowerMac7,2 & 7,3 222 * Platform function based voltage switching for PowerMac7,2 & 7,3
214 */ 223 */
215 224
@@ -248,6 +257,9 @@ static int g5_pfunc_switch_freq(int speed_mode)
248 struct pmf_args args; 257 struct pmf_args args;
249 u32 done = 0; 258 u32 done = 0;
250 unsigned long timeout; 259 unsigned long timeout;
260 int rc;
261
262 DBG("g5_pfunc_switch_freq(%d)\n", speed_mode);
251 263
252 /* If frequency is going up, first ramp up the voltage */ 264 /* If frequency is going up, first ramp up the voltage */
253 if (speed_mode < g5_pmode_cur) 265 if (speed_mode < g5_pmode_cur)
@@ -255,9 +267,12 @@ static int g5_pfunc_switch_freq(int speed_mode)
255 267
256 /* Do it */ 268 /* Do it */
257 if (speed_mode == CPUFREQ_HIGH) 269 if (speed_mode == CPUFREQ_HIGH)
258 pmf_call_one(pfunc_cpu_setfreq_high, NULL); 270 rc = pmf_call_one(pfunc_cpu_setfreq_high, NULL);
259 else 271 else
260 pmf_call_one(pfunc_cpu_setfreq_low, NULL); 272 rc = pmf_call_one(pfunc_cpu_setfreq_low, NULL);
273
274 if (rc)
275 printk(KERN_WARNING "cpufreq: pfunc switch error %d\n", rc);
261 276
262 /* It's an irq GPIO so we should be able to just block here, 277 /* 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 278 * I'll do that later after I've properly tested the IRQ code for
@@ -296,13 +311,6 @@ static int g5_pfunc_query_freq(void)
296 return val ? CPUFREQ_HIGH : CPUFREQ_LOW; 311 return val ? CPUFREQ_HIGH : CPUFREQ_LOW;
297} 312}
298 313
299/*
300 * Fake voltage switching for platforms with missing support
301 */
302
303static void g5_dummy_switch_volt(int speed_mode)
304{
305}
306 314
307/* 315/*
308 * Common interface to the cpufreq core 316 * Common interface to the cpufreq core
@@ -375,6 +383,8 @@ static struct cpufreq_driver g5_cpufreq_driver = {
375}; 383};
376 384
377 385
386#ifdef CONFIG_PPC_SMU
387
378static int __init g5_neo2_cpufreq_init(struct device_node *cpus) 388static int __init g5_neo2_cpufreq_init(struct device_node *cpus)
379{ 389{
380 struct device_node *cpunode; 390 struct device_node *cpunode;
@@ -525,6 +535,9 @@ static int __init g5_neo2_cpufreq_init(struct device_node *cpus)
525 return rc; 535 return rc;
526} 536}
527 537
538#endif /* CONFIG_PPC_SMU */
539
540
528static int __init g5_pm72_cpufreq_init(struct device_node *cpus) 541static int __init g5_pm72_cpufreq_init(struct device_node *cpus)
529{ 542{
530 struct device_node *cpuid = NULL, *hwclock = NULL, *cpunode = NULL; 543 struct device_node *cpuid = NULL, *hwclock = NULL, *cpunode = NULL;
@@ -533,6 +546,9 @@ static int __init g5_pm72_cpufreq_init(struct device_node *cpus)
533 u64 max_freq, min_freq, ih, il; 546 u64 max_freq, min_freq, ih, il;
534 int has_volt = 1, rc = 0; 547 int has_volt = 1, rc = 0;
535 548
549 DBG("cpufreq: Initializing for PowerMac7,2, PowerMac7,3 and"
550 " RackMac3,1...\n");
551
536 /* Get first CPU node */ 552 /* Get first CPU node */
537 for (cpunode = NULL; 553 for (cpunode = NULL;
538 (cpunode = of_get_next_child(cpus, cpunode)) != NULL;) { 554 (cpunode = of_get_next_child(cpus, cpunode)) != NULL;) {
@@ -636,6 +652,15 @@ static int __init g5_pm72_cpufreq_init(struct device_node *cpus)
636 */ 652 */
637 ih = *((u32 *)(eeprom + 0x10)); 653 ih = *((u32 *)(eeprom + 0x10));
638 il = *((u32 *)(eeprom + 0x20)); 654 il = *((u32 *)(eeprom + 0x20));
655
656 /* Check for machines with no useful settings */
657 if (il == ih) {
658 printk(KERN_WARNING "cpufreq: No low frequency mode available"
659 " on this model !\n");
660 rc = -ENODEV;
661 goto bail;
662 }
663
639 min_freq = 0; 664 min_freq = 0;
640 if (ih != 0 && il != 0) 665 if (ih != 0 && il != 0)
641 min_freq = (max_freq * il) / ih; 666 min_freq = (max_freq * il) / ih;
@@ -643,7 +668,7 @@ static int __init g5_pm72_cpufreq_init(struct device_node *cpus)
643 /* Sanity check */ 668 /* Sanity check */
644 if (min_freq >= max_freq || min_freq < 1000) { 669 if (min_freq >= max_freq || min_freq < 1000) {
645 printk(KERN_ERR "cpufreq: Can't calculate low frequency !\n"); 670 printk(KERN_ERR "cpufreq: Can't calculate low frequency !\n");
646 rc = -ENODEV; 671 rc = -ENXIO;
647 goto bail; 672 goto bail;
648 } 673 }
649 g5_cpu_freqs[0].frequency = max_freq; 674 g5_cpu_freqs[0].frequency = max_freq;
@@ -690,16 +715,10 @@ static int __init g5_pm72_cpufreq_init(struct device_node *cpus)
690 return rc; 715 return rc;
691} 716}
692 717
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) 718static int __init g5_cpufreq_init(void)
700{ 719{
701 struct device_node *cpus; 720 struct device_node *cpus;
702 int rc; 721 int rc = 0;
703 722
704 cpus = of_find_node_by_path("/cpus"); 723 cpus = of_find_node_by_path("/cpus");
705 if (cpus == NULL) { 724 if (cpus == NULL) {
@@ -708,12 +727,13 @@ static int __init g5_cpufreq_init(void)
708 } 727 }
709 728
710 if (machine_is_compatible("PowerMac7,2") || 729 if (machine_is_compatible("PowerMac7,2") ||
711 machine_is_compatible("PowerMac7,3")) 730 machine_is_compatible("PowerMac7,3") ||
731 machine_is_compatible("RackMac3,1"))
712 rc = g5_pm72_cpufreq_init(cpus); 732 rc = g5_pm72_cpufreq_init(cpus);
713 else if (machine_is_compatible("RackMac3,1")) 733#ifdef CONFIG_PPC_SMU
714 rc = g5_rm31_cpufreq_init(cpus);
715 else 734 else
716 rc = g5_neo2_cpufreq_init(cpus); 735 rc = g5_neo2_cpufreq_init(cpus);
736#endif /* CONFIG_PPC_SMU */
717 737
718 of_node_put(cpus); 738 of_node_put(cpus);
719 return rc; 739 return rc;