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 <dave...@freescale.com>
Signed-off-by: Li Yang <le...@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

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 <dave...@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 <kra...@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 <dave...@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
-- 
1.6.6-rc1.GIT


_______________________________________________
Linuxppc-dev mailing list
Linuxppc-dev@lists.ozlabs.org
https://lists.ozlabs.org/listinfo/linuxppc-dev

Reply via email to