Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 7ed14c21 authored by Benjamin Herrenschmidt's avatar Benjamin Herrenschmidt Committed by Paul Mackerras
Browse files

[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: default avatarBenjamin Herrenschmidt <benh@kernel.crashing.org>
Signed-off-by: default avatarPaul Mackerras <paulus@samba.org>
parent 861fa773
Loading
Loading
Loading
Loading
+1 −1
Original line number Diff line number Diff line
@@ -504,7 +504,7 @@ config CPU_FREQ_PMAC

config CPU_FREQ_PMAC64
	bool "Support for some Apple G5s"
	depends on CPU_FREQ && PMAC_SMU && PPC64
	depends on CPU_FREQ && PPC64
	select CPU_FREQ_TABLE
	help
	  This adds support for frequency switching on Apple iMac G5,
+49 −29
Original line number Diff line number Diff line
@@ -10,6 +10,8 @@
 * that is iMac G5 and latest single CPU desktop.
 */

#undef DEBUG

#include <linux/module.h>
#include <linux/types.h>
#include <linux/errno.h>
@@ -30,13 +32,7 @@
#include <asm/smu.h>
#include <asm/pmac_pfunc.h>

#undef DEBUG

#ifdef DEBUG
#define DBG(fmt...) printk(fmt)
#else
#define DBG(fmt...)
#endif
#define DBG(fmt...) pr_debug(fmt)

/* see 970FX user manual */

@@ -82,8 +78,6 @@ static struct freq_attr* g5_cpu_freqs_attr[] = {
/* Power mode data is an array of the 32 bits PCR values to use for
 * the various frequencies, retrieved from the device-tree
 */
static u32 *g5_pmode_data;
static int g5_pmode_max;
static int g5_pmode_cur;

static void (*g5_switch_volt)(int speed_mode);
@@ -93,6 +87,11 @@ static int (*g5_query_freq)(void);
static DEFINE_MUTEX(g5_switch_mutex);


#ifdef CONFIG_PPC_SMU

static u32 *g5_pmode_data;
static int g5_pmode_max;

static struct smu_sdbp_fvt *g5_fvt_table;	/* table of op. points */
static int g5_fvt_count;			/* number of op. points */
static int g5_fvt_cur;				/* current op. point */
@@ -209,6 +208,16 @@ static int g5_scom_query_freq(void)
	return i;
}

/*
 * Fake voltage switching for platforms with missing support
 */

static void g5_dummy_switch_volt(int speed_mode)
{
}

#endif /* CONFIG_PPC_SMU */

/*
 * Platform function based voltage switching for PowerMac7,2 & 7,3
 */
@@ -248,6 +257,9 @@ static int g5_pfunc_switch_freq(int speed_mode)
	struct pmf_args args;
	u32 done = 0;
	unsigned long timeout;
	int rc;

	DBG("g5_pfunc_switch_freq(%d)\n", speed_mode);

	/* If frequency is going up, first ramp up the voltage */
	if (speed_mode < g5_pmode_cur)
@@ -255,9 +267,12 @@ static int g5_pfunc_switch_freq(int speed_mode)

	/* Do it */
	if (speed_mode == CPUFREQ_HIGH)
		pmf_call_one(pfunc_cpu_setfreq_high, NULL);
		rc = pmf_call_one(pfunc_cpu_setfreq_high, NULL);
	else
		pmf_call_one(pfunc_cpu_setfreq_low, NULL);
		rc = pmf_call_one(pfunc_cpu_setfreq_low, NULL);

	if (rc)
		printk(KERN_WARNING "cpufreq: pfunc switch error %d\n", rc);

	/* It's an irq GPIO so we should be able to just block here,
	 * 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)
	return val ? CPUFREQ_HIGH : CPUFREQ_LOW;
}

/*
 * Fake voltage switching for platforms with missing support
 */

static void g5_dummy_switch_volt(int speed_mode)
{
}

/*
 * Common interface to the cpufreq core
@@ -375,6 +383,8 @@ static struct cpufreq_driver g5_cpufreq_driver = {
};


#ifdef CONFIG_PPC_SMU

static int __init g5_neo2_cpufreq_init(struct device_node *cpus)
{
	struct device_node *cpunode;
@@ -525,6 +535,9 @@ static int __init g5_neo2_cpufreq_init(struct device_node *cpus)
	return rc;
}

#endif /* CONFIG_PPC_SMU */


static int __init g5_pm72_cpufreq_init(struct device_node *cpus)
{
	struct device_node *cpuid = NULL, *hwclock = NULL, *cpunode = NULL;
@@ -533,6 +546,9 @@ static int __init g5_pm72_cpufreq_init(struct device_node *cpus)
	u64 max_freq, min_freq, ih, il;
	int has_volt = 1, rc = 0;

	DBG("cpufreq: Initializing for PowerMac7,2, PowerMac7,3 and"
	    " RackMac3,1...\n");

	/* Get first CPU node */
	for (cpunode = NULL;
	     (cpunode = of_get_next_child(cpus, cpunode)) != NULL;) {
@@ -636,6 +652,15 @@ static int __init g5_pm72_cpufreq_init(struct device_node *cpus)
	 */
	ih = *((u32 *)(eeprom + 0x10));
	il = *((u32 *)(eeprom + 0x20));

	/* Check for machines with no useful settings */
	if (il == ih) {
		printk(KERN_WARNING "cpufreq: No low frequency mode available"
		       " on this model !\n");
		rc = -ENODEV;
		goto bail;
	}

	min_freq = 0;
	if (ih != 0 && il != 0)
		min_freq = (max_freq * il) / ih;
@@ -643,7 +668,7 @@ static int __init g5_pm72_cpufreq_init(struct device_node *cpus)
	/* Sanity check */
	if (min_freq >= max_freq || min_freq < 1000) {
		printk(KERN_ERR "cpufreq: Can't calculate low frequency !\n");
		rc = -ENODEV;
		rc = -ENXIO;
		goto bail;
	}
	g5_cpu_freqs[0].frequency = max_freq;
@@ -690,16 +715,10 @@ static int __init g5_pm72_cpufreq_init(struct device_node *cpus)
	return rc;
}

static int __init g5_rm31_cpufreq_init(struct device_node *cpus)
{
	/* NYI */
	return 0;
}

static int __init g5_cpufreq_init(void)
{
	struct device_node *cpus;
	int rc;
	int rc = 0;

	cpus = of_find_node_by_path("/cpus");
	if (cpus == NULL) {
@@ -708,12 +727,13 @@ static int __init g5_cpufreq_init(void)
	}

	if (machine_is_compatible("PowerMac7,2") ||
	    machine_is_compatible("PowerMac7,3"))
	    machine_is_compatible("PowerMac7,3") ||
	    machine_is_compatible("RackMac3,1"))
		rc = g5_pm72_cpufreq_init(cpus);
	else if (machine_is_compatible("RackMac3,1"))
		rc = g5_rm31_cpufreq_init(cpus);
#ifdef CONFIG_PPC_SMU
	else
		rc = g5_neo2_cpufreq_init(cpus);
#endif /* CONFIG_PPC_SMU */

	of_node_put(cpus);
	return rc;