Patchwork [4/7] powerpc/85xx: add support to JOG feature using cpufreq interface

login
register
mail settings
Submitter Yang Li
Date Dec. 3, 2010, 12:34 p.m.
Message ID <1291379651-8822-4-git-send-email-leoli@freescale.com>
Download mbox | patch
Permalink /patch/74119/
State Superseded
Delegated to: Kumar Gala
Headers show

Comments

Yang Li - Dec. 3, 2010, 12:34 p.m.
Some 85xx silicons like MPC8536 and P1022 has the JOG PM feature.

The patch adds the support to change CPU frequency using the standard
cpufreq interface.

Signed-off-by: Dave Liu <daveliu@freescale.com>
Signed-off-by: Li Yang <leoli@freescale.com>
---
 arch/powerpc/platforms/85xx/Makefile  |    1 +
 arch/powerpc/platforms/85xx/cpufreq.c |  236 +++++++++++++++++++++++++++++++++
 arch/powerpc/platforms/Kconfig        |    8 +
 3 files changed, 245 insertions(+), 0 deletions(-)
 create mode 100644 arch/powerpc/platforms/85xx/cpufreq.c

Patch

diff --git a/arch/powerpc/platforms/85xx/Makefile b/arch/powerpc/platforms/85xx/Makefile
index 6bbcf22..11cedde 100644
--- a/arch/powerpc/platforms/85xx/Makefile
+++ b/arch/powerpc/platforms/85xx/Makefile
@@ -4,6 +4,7 @@ 
 obj-$(CONFIG_SMP)         += smp.o
 obj-$(CONFIG_HOTPLUG_CPU) += bootpage.o
 obj-$(CONFIG_SUSPEND)     += suspend-asm.o
+obj-$(CONFIG_MPC85xx_CPUFREQ) += cpufreq.o
 
 obj-$(CONFIG_MPC8540_ADS) += mpc85xx_ads.o
 obj-$(CONFIG_MPC8560_ADS) += mpc85xx_ads.o
diff --git a/arch/powerpc/platforms/85xx/cpufreq.c b/arch/powerpc/platforms/85xx/cpufreq.c
new file mode 100644
index 0000000..f729c3d
--- /dev/null
+++ b/arch/powerpc/platforms/85xx/cpufreq.c
@@ -0,0 +1,236 @@ 
+/*
+ * Copyright (C) 2008-2010 Freescale Semiconductor, Inc.
+ * 	Dave Liu <daveliu@freescale.com>
+ *
+ * The cpufreq driver is for Freescale 85xx processor,
+ * based on arch/powerpc/platforms/cell/cbe_cpufreq.c
+ * (C) Copyright IBM Deutschland Entwicklung GmbH 2005-2007
+ *	Christian Krafft <krafft@de.ibm.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <linux/cpufreq.h>
+#include <linux/of_platform.h>
+
+#include <asm/prom.h>
+#include <asm/time.h>
+#include <asm/reg.h>
+#include <asm/io.h>
+
+#include <sysdev/fsl_soc.h>
+
+static DEFINE_MUTEX(mpc85xx_switch_mutex);
+
+static void __iomem *guts;
+
+#define PORPLLSR	0x0
+#define PMJCR		0x7c
+#define POWMGTCSR	0x80
+
+static struct cpufreq_frequency_table mpc85xx_freqs[] = {
+	{2,	0},
+	{3,	0},
+	{4,	0},
+	{0,	CPUFREQ_TABLE_END},
+};
+
+/*
+ * hardware specific functions
+ */
+static int get_pll(int cpu)
+{
+	int ret, shift;
+	u32 pll = in_be32(guts + PORPLLSR);
+	shift = (cpu == 1) ? 24 : 16;
+	ret = (pll >> shift) & 0x3f;
+
+	return ret;
+}
+
+static void set_pll(unsigned int pll, int cpu)
+{
+	int shift;
+	u32 busfreq, corefreq, val;
+	u32 core_spd, mask, tmp;
+
+	tmp = in_be32(guts + PMJCR);
+	shift = (cpu == 1) ? 24 : 16;
+	busfreq = fsl_get_sys_freq();
+	val = (pll & 0x3f) << shift;
+
+	corefreq = ((busfreq * pll) >> 1);
+	/* must set the bit[18/19] if the requested core freq > 533 MHz */
+	core_spd = (cpu == 1) ? 0x00002000 : 0x00001000;
+	if (corefreq > 533000000)
+		val |= core_spd;
+
+	mask = (cpu == 1) ? 0x3f002000 : 0x003f1000;
+	tmp &= ~mask;
+	tmp |= val;
+	out_be32(guts + PMJCR, tmp);
+	val = in_be32(guts + PMJCR);
+	out_be32(guts + POWMGTCSR, 0x00600000);
+	printk("PMJCR request %08x at CPU %d\n", tmp, cpu);
+}
+
+static void verify_pll(int cpu)
+{
+	int shift;
+	u32 busfreq, pll, corefreq;
+
+	shift = (cpu == 1) ? 24 : 16;
+	busfreq = fsl_get_sys_freq();
+	pll = (in_be32(guts + PORPLLSR) >> shift) & 0x3f;
+
+	corefreq = (busfreq * pll) >> 1;
+	corefreq /= 1000000;
+	printk("PORPLLSR core freq %dMHz at CPU %d\n", corefreq, cpu);
+}
+
+/*
+ * cpufreq functions
+ */
+
+static int mpc85xx_cpufreq_cpu_init(struct cpufreq_policy *policy)
+{
+	u32 busfreq = fsl_get_sys_freq();
+	int i, cur_pll;
+
+	/* we need the freq unit with kHz */
+	busfreq /= 1000;
+
+	/* initialize frequency table */
+	for (i = 0; mpc85xx_freqs[i].frequency != CPUFREQ_TABLE_END; i++) {
+		mpc85xx_freqs[i].frequency = (busfreq * mpc85xx_freqs[i].index) >> 1;
+		printk("%d: %dkHz\n", i, mpc85xx_freqs[i].frequency);
+	}
+
+	/* the latency of a transition, the unit is ns */
+	policy->cpuinfo.transition_latency = 2000;
+
+	cur_pll = get_pll(policy->cpu);
+	pr_debug("current pll is at %d\n", cur_pll);
+
+	for (i = 0; mpc85xx_freqs[i].frequency != CPUFREQ_TABLE_END; i++) {
+		if (mpc85xx_freqs[i].index == cur_pll)
+			policy->cur = mpc85xx_freqs[i].frequency;
+	}
+	pr_debug("current core freq is %d\n", policy->cur);
+
+	cpufreq_frequency_table_get_attr(mpc85xx_freqs, policy->cpu);
+
+	/* this ensures that policy->cpuinfo_min
+	 * and policy->cpuinfo_max are set correctly */
+	return cpufreq_frequency_table_cpuinfo(policy, mpc85xx_freqs);
+}
+
+static int mpc85xx_cpufreq_cpu_exit(struct cpufreq_policy *policy)
+{
+	cpufreq_frequency_table_put_attr(policy->cpu);
+	return 0;
+}
+
+static int mpc85xx_cpufreq_verify(struct cpufreq_policy *policy)
+{
+	return cpufreq_frequency_table_verify(policy, mpc85xx_freqs);
+}
+
+static int mpc85xx_cpufreq_target(struct cpufreq_policy *policy,
+			      unsigned int target_freq,
+			      unsigned int relation)
+{
+	struct cpufreq_freqs freqs;
+	unsigned int new;
+
+	cpufreq_frequency_table_target(policy,
+				       mpc85xx_freqs,
+				       target_freq,
+				       relation,
+				       &new);
+
+	freqs.old = policy->cur;
+	freqs.new = mpc85xx_freqs[new].frequency;
+	freqs.cpu = policy->cpu;
+
+	mutex_lock(&mpc85xx_switch_mutex);
+	cpufreq_notify_transition(&freqs, CPUFREQ_PRECHANGE);
+
+	printk("setting frequency for cpu %d to %d kHz, " \
+		 "PLL ratio is %d/2\n",
+		 policy->cpu,
+		 mpc85xx_freqs[new].frequency,
+		 mpc85xx_freqs[new].index);
+
+	set_pll(mpc85xx_freqs[new].index, policy->cpu);
+
+	cpufreq_notify_transition(&freqs, CPUFREQ_POSTCHANGE);
+	mutex_unlock(&mpc85xx_switch_mutex);
+
+	ppc_proc_freq = freqs.new * 1000ul;
+
+	verify_pll(policy->cpu);
+
+	return 0;
+}
+
+static struct cpufreq_driver mpc85xx_cpufreq_driver = {
+	.verify		= mpc85xx_cpufreq_verify,
+	.target		= mpc85xx_cpufreq_target,
+	.init		= mpc85xx_cpufreq_cpu_init,
+	.exit		= mpc85xx_cpufreq_cpu_exit,
+	.name		= "mpc85xx-cpufreq",
+	.owner		= THIS_MODULE,
+	.flags		= CPUFREQ_CONST_LOOPS,
+};
+
+/*
+ * module init and destoy
+ */
+
+static struct of_device_id mpc85xx_jog_ids[] __initdata = {
+	{ .compatible = "fsl,mpc8536-guts", },
+	{ .compatible = "fsl,p1022-guts", },
+	{}
+};
+
+static int __init mpc85xx_cpufreq_init(void)
+{
+	struct device_node *np;
+
+	np = of_find_matching_node(NULL, mpc85xx_jog_ids);
+	if (np == NULL)
+		return -ENODEV;
+
+	guts = of_iomap(np, 0);
+	of_node_put(np);
+	if (guts == NULL)
+		return -ENOMEM;
+
+	return cpufreq_register_driver(&mpc85xx_cpufreq_driver);
+}
+
+static void __exit mpc85xx_cpufreq_exit(void)
+{
+	iounmap(guts);
+
+	cpufreq_unregister_driver(&mpc85xx_cpufreq_driver);
+}
+
+module_init(mpc85xx_cpufreq_init);
+module_exit(mpc85xx_cpufreq_exit);
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Dave Liu <daveliu@freescale.com>");
diff --git a/arch/powerpc/platforms/Kconfig b/arch/powerpc/platforms/Kconfig
index 956154f..df529f9 100644
--- a/arch/powerpc/platforms/Kconfig
+++ b/arch/powerpc/platforms/Kconfig
@@ -178,6 +178,14 @@  config CPU_FREQ_PMAC64
 	  This adds support for frequency switching on Apple iMac G5,
 	  and some of the more recent desktop G5 machines as well.
 
+config MPC85xx_CPUFREQ
+	bool "Support for Freescale MPC85xx CPU freq"
+	depends on PPC_85xx && PPC32
+	select CPU_FREQ_TABLE
+	help
+	  This adds support for frequency switching on Freescale MPC85xx,
+	  this currently includes P1022 processor.
+
 config PPC_PASEMI_CPUFREQ
 	bool "Support for PA Semi PWRficient"
 	depends on PPC_PASEMI