* Re: [PATCH v2 06/15] powerpc/85xx: add support to JOG feature using cpufreq interface
[not found] <20130419110057.GC29421@localhost.localdomain>
@ 2013-04-21 23:43 ` Rafael J. Wysocki
2013-04-22 10:57 ` Zhao Chenhui
0 siblings, 1 reply; 5+ messages in thread
From: Rafael J. Wysocki @ 2013-04-21 23:43 UTC (permalink / raw)
To: Zhao Chenhui; +Cc: linuxppc-dev, cpufreq, linux-pm
On Friday, April 19, 2013 07:00:57 PM Zhao Chenhui wrote:
> ----- Forwarded message from Zhao Chenhui <chenhui.zhao@freescale.com> -----
>
> Date: Fri, 19 Apr 2013 18:47:39 +0800
> From: Zhao Chenhui <chenhui.zhao@freescale.com>
> To: linuxppc-dev@lists.ozlabs.org
> CC: linux-kernel@vger.kernel.org
> Subject: [linuxppc-release] [PATCH v2 06/15] powerpc/85xx: add support to JOG feature using cpufreq interface
> X-Mailer: git-send-email 1.7.3
>
> From: chenhui zhao <chenhui.zhao@freescale.com>
>
> Some 85xx silicons like MPC8536 and P1022 have a JOG feature, which provides
> a dynamic mechanism to lower or raise the CPU core clock at runtime.
>
> This patch adds the support to change CPU frequency using the standard
> cpufreq interface. The ratio CORE to CCB can be 1:1(except MPC8536), 3:2,
> 2:1, 5:2, 3:1, 7:2 and 4:1.
>
> Two CPU cores on P1022 must not in the low power state during the frequency
> transition. The driver uses a atomic counter to meet the requirement.
>
> The jog mode frequency transition process on the MPC8536 is similar to
> the deep sleep process. The driver need save the CPU state and restore
> it after CPU warm reset.
>
> Note:
> * The I/O peripherals such as PCIe and eTSEC may lose packets during
> the jog mode frequency transition.
> * The driver doesn't support MPC8536 Rev 1.0 due to a JOG erratum.
> Subsequent revisions of MPC8536 have corrected the erratum.
>
> Signed-off-by: Dave Liu <daveliu@freescale.com>
> Signed-off-by: Li Yang <leoli@freescale.com>
> Signed-off-by: Jerry Huang <Chang-Ming.Huang@freescale.com>
> Signed-off-by: Zhao Chenhui <chenhui.zhao@freescale.com>
> CC: Scott Wood <scottwood@freescale.com>
Well, I'd like someone from the PowerPC camp to comment on this before I take it.
Thanks,
Rafael
> ---
> arch/powerpc/platforms/85xx/Makefile | 1 +
> drivers/cpufreq/Kconfig.powerpc | 10 +
> drivers/cpufreq/Makefile | 1 +
> drivers/cpufreq/mpc85xx-cpufreq.c | 390 ++++++++++++++++++++++++++++++++++
> 4 files changed, 402 insertions(+), 0 deletions(-)
> create mode 100644 drivers/cpufreq/mpc85xx-cpufreq.c
>
> diff --git a/arch/powerpc/platforms/85xx/Makefile b/arch/powerpc/platforms/85xx/Makefile
> index a35bab7..da53bde 100644
> --- a/arch/powerpc/platforms/85xx/Makefile
> +++ b/arch/powerpc/platforms/85xx/Makefile
> @@ -3,6 +3,7 @@
> #
> obj-$(CONFIG_SMP) += smp.o
> obj-$(CONFIG_FSL_PMC) += sleep.o
> +obj-$(CONFIG_CPU_FREQ_MPC85xx) += sleep.o
>
> obj-y += common.o
>
> diff --git a/drivers/cpufreq/Kconfig.powerpc b/drivers/cpufreq/Kconfig.powerpc
> index e76992f..ba06a00 100644
> --- a/drivers/cpufreq/Kconfig.powerpc
> +++ b/drivers/cpufreq/Kconfig.powerpc
> @@ -5,3 +5,13 @@ config CPU_FREQ_MAPLE
> help
> This adds support for frequency switching on Maple 970FX
> Evaluation Board and compatible boards (IBM JS2x blades).
> +
> +config CPU_FREQ_MPC85xx
> + bool "Support for Freescale MPC85xx CPU freq"
> + depends on PPC_85xx && PPC32 && !PPC_E500MC
> + select CPU_FREQ_TABLE
> + help
> + This adds support for dynamic frequency switching on
> + Freescale MPC85xx by cpufreq interface. MPC8536 and P1022
> + have a JOG feature, which provides a dynamic mechanism
> + to lower or raise the CPU core clock at runtime.
> diff --git a/drivers/cpufreq/Makefile b/drivers/cpufreq/Makefile
> index 863fd18..e7aecc5 100644
> --- a/drivers/cpufreq/Makefile
> +++ b/drivers/cpufreq/Makefile
> @@ -61,3 +61,4 @@ obj-$(CONFIG_ARM_IMX6Q_CPUFREQ) += imx6q-cpufreq.o
> ##################################################################################
> # PowerPC platform drivers
> obj-$(CONFIG_CPU_FREQ_MAPLE) += maple-cpufreq.o
> +obj-$(CONFIG_CPU_FREQ_MPC85xx) += mpc85xx-cpufreq.o
> diff --git a/drivers/cpufreq/mpc85xx-cpufreq.c b/drivers/cpufreq/mpc85xx-cpufreq.c
> new file mode 100644
> index 0000000..f56c826
> --- /dev/null
> +++ b/drivers/cpufreq/mpc85xx-cpufreq.c
> @@ -0,0 +1,390 @@
> +/*
> + * Copyright (C) 2008-2012 Freescale Semiconductor, Inc.
> + * Author: Dave Liu <daveliu@freescale.com>
> + * Modifier: Chenhui Zhao <chenhui.zhao@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/module.h>
> +#include <linux/cpufreq.h>
> +#include <linux/of_platform.h>
> +#include <linux/suspend.h>
> +#include <linux/cpu.h>
> +#include <linux/time.h>
> +#include <linux/io.h>
> +#include <linux/smp.h>
> +
> +#include <asm/prom.h>
> +#include <asm/reg.h>
> +#include <asm/machdep.h>
> +
> +#include <sysdev/fsl_soc.h>
> +
> +static DEFINE_MUTEX(mpc85xx_switch_mutex);
> +static void __iomem *guts;
> +
> +static u32 sysfreq;
> +static unsigned int max_pll[2];
> +static atomic_t in_jog_process;
> +static struct cpufreq_frequency_table *mpc85xx_freqs;
> +static int (*set_pll)(unsigned int cpu, unsigned int pll);
> +
> +static struct cpufreq_frequency_table mpc8536_freqs_table[] = {
> + {3, 0},
> + {4, 0},
> + {5, 0},
> + {6, 0},
> + {7, 0},
> + {8, 0},
> + {0, CPUFREQ_TABLE_END},
> +};
> +
> +static struct cpufreq_frequency_table p1022_freqs_table[] = {
> + {2, 0},
> + {3, 0},
> + {4, 0},
> + {5, 0},
> + {6, 0},
> + {7, 0},
> + {8, 0},
> + {0, CPUFREQ_TABLE_END},
> +};
> +
> +#define FREQ_500MHz 500000000
> +#define FREQ_800MHz 800000000
> +
> +#define CORE_RATIO_STRIDE 8
> +#define CORE_RATIO_MASK 0x3f
> +#define CORE_RATIO_SHIFT 16
> +
> +#define PORPLLSR 0x0 /* Power-On Reset PLL ratio status register */
> +
> +#define PMJCR 0x7c /* Power Management Jog Control Register */
> +#define PMJCR_CORE0_SPD 0x00001000
> +#define PMJCR_CORE_SPD 0x00002000
> +
> +#define POWMGTCSR 0x80 /* Power management control and status register */
> +#define POWMGTCSR_JOG 0x00200000
> +#define POWMGTCSR_INT_MASK 0x00000f00
> +
> +static void spin_while_jogging(void *dummy)
> +{
> + unsigned long flags;
> +
> + local_irq_save(flags);
> +
> + atomic_inc(&in_jog_process);
> +
> + while (atomic_read(&in_jog_process) != 0)
> + barrier();
> +
> + local_irq_restore(flags);
> +}
> +
> +static int get_pll(int hw_cpu)
> +{
> + int shift;
> + u32 val = in_be32(guts + PORPLLSR);
> +
> + shift = hw_cpu * CORE_RATIO_STRIDE + CORE_RATIO_SHIFT;
> +
> + return (val >> shift) & CORE_RATIO_MASK;
> +}
> +
> +static int mpc8536_set_pll(unsigned int cpu, unsigned int pll)
> +{
> + u32 corefreq, val, mask;
> + unsigned int cur_pll = get_pll(0);
> + unsigned long flags;
> +
> + if (pll == cur_pll)
> + return 0;
> +
> + val = (pll & CORE_RATIO_MASK) << CORE_RATIO_SHIFT;
> +
> + corefreq = sysfreq * pll / 2;
> + /*
> + * Set the COREx_SPD bit if the requested core frequency
> + * is larger than the threshold frequency.
> + */
> + if (corefreq > FREQ_800MHz)
> + val |= PMJCR_CORE_SPD;
> +
> + mask = (CORE_RATIO_MASK << CORE_RATIO_SHIFT) | PMJCR_CORE_SPD;
> + clrsetbits_be32(guts + PMJCR, mask, val);
> +
> + /* readback to sync write */
> + in_be32(guts + PMJCR);
> +
> + local_irq_save(flags);
> + mpc85xx_enter_deep_sleep(get_immrbase(), POWMGTCSR_JOG);
> + local_irq_restore(flags);
> +
> + /* verify */
> + cur_pll = get_pll(0);
> + if (cur_pll != pll) {
> + pr_err("%s: error. The current PLL is %d instead of %d.\n",
> + __func__, cur_pll, pll);
> + return -1;
> + }
> +
> + return 0;
> +}
> +
> +static int p1022_set_pll(unsigned int cpu, unsigned int pll)
> +{
> + int index, hw_cpu = get_hard_smp_processor_id(cpu);
> + int shift;
> + u32 corefreq, val, mask = 0;
> + unsigned int cur_pll = get_pll(hw_cpu);
> + unsigned long flags;
> + int ret = 0;
> +
> + if (pll == cur_pll)
> + return 0;
> +
> + shift = hw_cpu * CORE_RATIO_STRIDE + CORE_RATIO_SHIFT;
> + val = (pll & CORE_RATIO_MASK) << shift;
> +
> + corefreq = sysfreq * pll / 2;
> + /*
> + * Set the COREx_SPD bit if the requested core frequency
> + * is larger than the threshold frequency.
> + */
> + if (corefreq > FREQ_500MHz)
> + val |= PMJCR_CORE0_SPD << hw_cpu;
> +
> + mask = (CORE_RATIO_MASK << shift) | (PMJCR_CORE0_SPD << hw_cpu);
> + clrsetbits_be32(guts + PMJCR, mask, val);
> +
> + /* readback to sync write */
> + in_be32(guts + PMJCR);
> +
> + get_online_cpus();
> + /*
> + * A Jog request can not be asserted when any core is in a low
> + * power state on P1022. Before executing a jog request, any
> + * core which is in a low power state must be waked by a
> + * interrupt, and keep waking up until the sequence is
> + * finished.
> + */
> + for_each_present_cpu(index) {
> + if (!cpu_online(index)) {
> + put_online_cpus();
> + pr_err("%s: error, core%d is down.\n", __func__, index);
> + return -1;
> + }
> + }
> +
> + atomic_set(&in_jog_process, 0);
> + smp_call_function(spin_while_jogging, NULL, 0);
> +
> + local_irq_save(flags);
> +
> + /* Wait for the other core to wake. */
> + if (!spin_event_timeout(atomic_read(&in_jog_process) == 1, 1000, 100)) {
> + pr_err("%s: timeout, the other core is not at running state.\n",
> + __func__);
> + ret = -1;
> + goto err;
> + }
> +
> + out_be32(guts + POWMGTCSR, POWMGTCSR_JOG | POWMGTCSR_INT_MASK);
> +
> + if (!spin_event_timeout(
> + (in_be32(guts + POWMGTCSR) & POWMGTCSR_JOG) == 0, 1000, 100)) {
> + pr_err("%s: timeout, fail to switch the core frequency.\n",
> + __func__);
> + ret = -1;
> + goto err;
> + }
> +
> + clrbits32(guts + POWMGTCSR, POWMGTCSR_INT_MASK);
> + in_be32(guts + POWMGTCSR);
> +
> + atomic_set(&in_jog_process, 0);
> +err:
> + local_irq_restore(flags);
> + put_online_cpus();
> +
> + /* verify */
> + cur_pll = get_pll(hw_cpu);
> + if (cur_pll != pll) {
> + pr_err("%s: error, the current PLL of core %d is %d instead of %d.\n",
> + __func__, hw_cpu, cur_pll, pll);
> + return -1;
> + }
> +
> + return ret;
> +}
> +
> +/*
> + * cpufreq functions
> + */
> +static int mpc85xx_cpufreq_cpu_init(struct cpufreq_policy *policy)
> +{
> + unsigned int i, cur_pll;
> + int hw_cpu = get_hard_smp_processor_id(policy->cpu);
> +
> + if (!cpu_present(policy->cpu))
> + return -ENODEV;
> +
> + /* the latency of a transition, the unit is ns */
> + policy->cpuinfo.transition_latency = 2000;
> +
> + cur_pll = get_pll(hw_cpu);
> +
> + /* initialize frequency table */
> + pr_debug("core%d frequency table:\n", hw_cpu);
> + for (i = 0; mpc85xx_freqs[i].frequency != CPUFREQ_TABLE_END; i++) {
> + if (mpc85xx_freqs[i].index <= max_pll[hw_cpu]) {
> + /* The frequency unit is kHz. */
> + mpc85xx_freqs[i].frequency =
> + (sysfreq * mpc85xx_freqs[i].index / 2) / 1000;
> + } else {
> + mpc85xx_freqs[i].frequency = CPUFREQ_ENTRY_INVALID;
> + }
> +
> + pr_debug("%d: %dkHz\n", i, mpc85xx_freqs[i].frequency);
> +
> + if (mpc85xx_freqs[i].index == cur_pll)
> + policy->cur = mpc85xx_freqs[i].frequency;
> + }
> + pr_debug("current pll is at %d, and core freq is%d\n",
> + cur_pll, 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;
> + int ret = 0;
> +
> + if (!set_pll)
> + return -ENODEV;
> +
> + 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);
> +
> + ret = set_pll(policy->cpu, mpc85xx_freqs[new].index);
> + if (!ret) {
> + pr_info("cpufreq: Setting core%d frequency to %d kHz and PLL ratio to %d:2\n",
> + policy->cpu, mpc85xx_freqs[new].frequency,
> + mpc85xx_freqs[new].index);
> +
> + ppc_proc_freq = freqs.new * 1000ul;
> + }
> + cpufreq_notify_transition(&freqs, CPUFREQ_POSTCHANGE);
> + mutex_unlock(&mpc85xx_switch_mutex);
> +
> + return ret;
> +}
> +
> +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-JOG",
> + .owner = THIS_MODULE,
> + .flags = CPUFREQ_CONST_LOOPS,
> +};
> +
> +static struct of_device_id mpc85xx_jog_ids[] = {
> + { .compatible = "fsl,mpc8536-guts", },
> + { .compatible = "fsl,p1022-guts", },
> + {}
> +};
> +
> +static int __init mpc85xx_jog_init(void)
> +{
> + struct device_node *np;
> + unsigned int svr;
> +
> + np = of_find_matching_node(NULL, mpc85xx_jog_ids);
> + if (!np)
> + return -ENODEV;
> +
> + guts = of_iomap(np, 0);
> + if (!guts) {
> + of_node_put(np);
> + return -ENODEV;
> + }
> +
> + sysfreq = fsl_get_sys_freq();
> +
> + if (of_device_is_compatible(np, "fsl,mpc8536-guts")) {
> + svr = mfspr(SPRN_SVR);
> + if ((svr & 0x7fff) == 0x10) {
> + pr_err("MPC8536 Rev 1.0 does not support cpufreq(JOG).\n");
> + of_node_put(np);
> + return -ENODEV;
> + }
> + mpc85xx_freqs = mpc8536_freqs_table;
> + set_pll = mpc8536_set_pll;
> + max_pll[0] = get_pll(0);
> +
> + } else if (of_device_is_compatible(np, "fsl,p1022-guts")) {
> + mpc85xx_freqs = p1022_freqs_table;
> + set_pll = p1022_set_pll;
> + max_pll[0] = get_pll(0);
> + max_pll[1] = get_pll(1);
> + }
> +
> + pr_info("Freescale MPC85xx cpufreq(JOG) driver\n");
> +
> + of_node_put(np);
> + return cpufreq_register_driver(&mpc85xx_cpufreq_driver);
> +}
> +
> +device_initcall(mpc85xx_jog_init);
>
--
I speak only for myself.
Rafael J. Wysocki, Intel Open Source Technology Center.
^ permalink raw reply [flat|nested] 5+ messages in thread* Re: [PATCH v2 06/15] powerpc/85xx: add support to JOG feature using cpufreq interface
2013-04-21 23:43 ` [PATCH v2 06/15] powerpc/85xx: add support to JOG feature using cpufreq interface Rafael J. Wysocki
@ 2013-04-22 10:57 ` Zhao Chenhui
0 siblings, 0 replies; 5+ messages in thread
From: Zhao Chenhui @ 2013-04-22 10:57 UTC (permalink / raw)
To: Rafael J. Wysocki; +Cc: linuxppc-dev, cpufreq, linux-pm
On Mon, Apr 22, 2013 at 01:43:29AM +0200, Rafael J. Wysocki wrote:
> On Friday, April 19, 2013 07:00:57 PM Zhao Chenhui wrote:
> > ----- Forwarded message from Zhao Chenhui <chenhui.zhao@freescale.com> -----
> >
> > Date: Fri, 19 Apr 2013 18:47:39 +0800
> > From: Zhao Chenhui <chenhui.zhao@freescale.com>
> > To: linuxppc-dev@lists.ozlabs.org
> > CC: linux-kernel@vger.kernel.org
> > Subject: [linuxppc-release] [PATCH v2 06/15] powerpc/85xx: add support to JOG feature using cpufreq interface
> > X-Mailer: git-send-email 1.7.3
> >
> > From: chenhui zhao <chenhui.zhao@freescale.com>
> >
> > Some 85xx silicons like MPC8536 and P1022 have a JOG feature, which provides
> > a dynamic mechanism to lower or raise the CPU core clock at runtime.
> >
> > This patch adds the support to change CPU frequency using the standard
> > cpufreq interface. The ratio CORE to CCB can be 1:1(except MPC8536), 3:2,
> > 2:1, 5:2, 3:1, 7:2 and 4:1.
> >
> > Two CPU cores on P1022 must not in the low power state during the frequency
> > transition. The driver uses a atomic counter to meet the requirement.
> >
> > The jog mode frequency transition process on the MPC8536 is similar to
> > the deep sleep process. The driver need save the CPU state and restore
> > it after CPU warm reset.
> >
> > Note:
> > * The I/O peripherals such as PCIe and eTSEC may lose packets during
> > the jog mode frequency transition.
> > * The driver doesn't support MPC8536 Rev 1.0 due to a JOG erratum.
> > Subsequent revisions of MPC8536 have corrected the erratum.
> >
> > Signed-off-by: Dave Liu <daveliu@freescale.com>
> > Signed-off-by: Li Yang <leoli@freescale.com>
> > Signed-off-by: Jerry Huang <Chang-Ming.Huang@freescale.com>
> > Signed-off-by: Zhao Chenhui <chenhui.zhao@freescale.com>
> > CC: Scott Wood <scottwood@freescale.com>
>
> Well, I'd like someone from the PowerPC camp to comment on this before I take it.
>
> Thanks,
> Rafael
>
OK. Thanks.
-Chenhui
^ permalink raw reply [flat|nested] 5+ messages in thread
* [PATCH v2 01/15] powerpc/85xx: cache operations for Freescale SoCs based on BOOK3E
@ 2013-04-19 10:47 Zhao Chenhui
2013-04-19 10:47 ` [PATCH v2 06/15] powerpc/85xx: add support to JOG feature using cpufreq interface Zhao Chenhui
0 siblings, 1 reply; 5+ messages in thread
From: Zhao Chenhui @ 2013-04-19 10:47 UTC (permalink / raw)
To: linuxppc-dev; +Cc: linux-kernel
These cache operations support Freescale SoCs based on BOOK3E.
Move L1 cache operations to fsl_booke_cache.S in order to maintain
easily. And, add cache operations for backside L2 cache and platform cache.
The backside L2 cache appears on e500mc and e5500 core. The platform cache
supported by this patch is L2 Look-Aside Cache, which appears on SoCs
with e500v1/e500v2 core, such as MPC8572, P1020, etc.
Signed-off-by: Zhao Chenhui <chenhui.zhao@freescale.com>
Signed-off-by: Li Yang <leoli@freescale.com>
---
arch/powerpc/include/asm/cacheflush.h | 8 ++
arch/powerpc/kernel/Makefile | 1 +
arch/powerpc/kernel/fsl_booke_cache.S | 210 +++++++++++++++++++++++++++++++++
arch/powerpc/kernel/head_fsl_booke.S | 74 ------------
4 files changed, 219 insertions(+), 74 deletions(-)
create mode 100644 arch/powerpc/kernel/fsl_booke_cache.S
diff --git a/arch/powerpc/include/asm/cacheflush.h b/arch/powerpc/include/asm/cacheflush.h
index b843e35..bc3f937 100644
--- a/arch/powerpc/include/asm/cacheflush.h
+++ b/arch/powerpc/include/asm/cacheflush.h
@@ -32,6 +32,14 @@ extern void flush_dcache_page(struct page *page);
extern void __flush_disable_L1(void);
+#ifdef CONFIG_FSL_SOC_BOOKE
+void flush_dcache_L1(void);
+void flush_backside_L2_cache(void);
+void disable_backside_L2_cache(void);
+void flush_disable_L2(void);
+void invalidate_enable_L2(void);
+#endif
+
extern void __flush_icache_range(unsigned long, unsigned long);
static inline void flush_icache_range(unsigned long start, unsigned long stop)
{
diff --git a/arch/powerpc/kernel/Makefile b/arch/powerpc/kernel/Makefile
index f960a79..4acf739 100644
--- a/arch/powerpc/kernel/Makefile
+++ b/arch/powerpc/kernel/Makefile
@@ -87,6 +87,7 @@ extra-$(CONFIG_8xx) := head_8xx.o
extra-y += vmlinux.lds
obj-$(CONFIG_RELOCATABLE_PPC32) += reloc_32.o
+obj-$(CONFIG_FSL_SOC_BOOKE) += fsl_booke_cache.o
obj-$(CONFIG_PPC32) += entry_32.o setup_32.o
obj-$(CONFIG_PPC64) += dma-iommu.o iommu.o
diff --git a/arch/powerpc/kernel/fsl_booke_cache.S b/arch/powerpc/kernel/fsl_booke_cache.S
new file mode 100644
index 0000000..232c47b
--- /dev/null
+++ b/arch/powerpc/kernel/fsl_booke_cache.S
@@ -0,0 +1,210 @@
+/*
+ * Copyright 2009-2013 Freescale Semiconductor, Inc.
+ * Scott Wood <scottwood@freescale.com>
+ * Dave Liu <daveliu@freescale.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 of the License, or (at your option) any later version.
+ */
+
+#include <asm/reg.h>
+#include <asm/page.h>
+#include <asm/ppc_asm.h>
+#include <asm/asm-offsets.h>
+
+ .section .text
+
+/******** L1 Cache ********/
+
+/* flush L1 d-cache */
+_GLOBAL(flush_dcache_L1)
+ mfspr r3,SPRN_L1CFG0
+
+ rlwinm r5,r3,9,3 /* Extract cache block size */
+ twlgti r5,1 /* Only 32 and 64 byte cache blocks
+ * are currently defined.
+ */
+ li r4,32
+ subfic r6,r5,2 /* r6 = log2(1KiB / cache block size) -
+ * log2(number of ways)
+ */
+ slw r5,r4,r5 /* r5 = cache block size */
+
+ rlwinm r7,r3,0,0xff /* Extract number of KiB in the cache */
+ mulli r7,r7,13 /* An 8-way cache will require 13
+ * loads per set.
+ */
+ slw r7,r7,r6
+
+ /* save off HID0 and set DCFA */
+ mfspr r8,SPRN_HID0
+ ori r9,r8,HID0_DCFA@l
+ mtspr SPRN_HID0,r9
+ isync
+
+ LOAD_REG_IMMEDIATE(r4, KERNELBASE)
+ mtctr r7
+
+1: lwz r3,0(r4) /* Load... */
+ add r4,r4,r5
+ bdnz 1b
+
+ msync
+ LOAD_REG_IMMEDIATE(r4, KERNELBASE)
+ mtctr r7
+
+1: dcbf 0,r4 /* ...and flush. */
+ add r4,r4,r5
+ bdnz 1b
+
+ /* restore HID0 */
+ mtspr SPRN_HID0,r8
+ isync
+
+ blr
+
+/* Flush L1 d-cache, invalidate and disable d-cache and i-cache */
+_GLOBAL(__flush_disable_L1)
+ mflr r10
+ bl flush_dcache_L1 /* Flush L1 d-cache */
+ mtlr r10
+
+ msync
+ mfspr r4, SPRN_L1CSR0 /* Invalidate and disable d-cache */
+ li r5, 2
+ rlwimi r4, r5, 0, 3
+
+ msync
+ isync
+ mtspr SPRN_L1CSR0, r4
+ isync
+
+ msync
+1: mfspr r4, SPRN_L1CSR0 /* Wait for the invalidate to finish */
+ andi. r4, r4, 2
+ bne 1b
+
+ msync
+ mfspr r4, SPRN_L1CSR1 /* Invalidate and disable i-cache */
+ li r5, 2
+ rlwimi r4, r5, 0, 3
+
+ msync
+ isync
+ mtspr SPRN_L1CSR1, r4
+ isync
+ msync
+
+ blr
+
+/******** Backside L2 Cache ********/
+
+#define SVR_P2040 0x821000
+
+need_L2_cache:
+ /* skip L2 cache on P2040/P2040E as they have no L2 cache */
+ mfspr r3, SPRN_SVR
+ /* shift right by 8 bits and clear E bit of SVR */
+ rlwinm r4, r3, 24, ~0x800
+
+ lis r3, SVR_P2040@h
+ ori r3, r3, SVR_P2040@l
+ cmpw r4, r3
+ beq 1f
+
+ /* If L2 cache is disabled, skip it */
+ mfspr r3, SPRN_L2CSR0
+ andis. r3, r3, L2CSR0_L2E@h
+ beq 1f
+
+ li r3, 0
+ blr
+1:
+ li r3, 1
+ blr
+
+/* flush backside L2 cache */
+_GLOBAL(flush_backside_L2_cache)
+ mflr r10
+ bl need_L2_cache
+ mtlr r10
+ cmpwi r3, 0
+ bne 2f
+
+__flush_backside_L2_cache:
+ /* Flush the L2 cache */
+ mfspr r3, SPRN_L2CSR0
+ ori r3, r3, L2CSR0_L2FL@l
+ msync
+ isync
+ mtspr SPRN_L2CSR0,r3
+ isync
+1:
+ mfspr r3,SPRN_L2CSR0
+ andi. r3, r3, L2CSR0_L2FL@l
+ bne 1b
+2:
+ blr
+
+/* flush and disable backside L2 cache */
+_GLOBAL(disable_backside_L2_cache)
+ mflr r10
+ bl need_L2_cache
+ mtlr r10
+ cmpwi r3, 0
+ bne 1f
+
+ mflr r10
+ bl __flush_backside_L2_cache
+ mtlr r10
+
+ /* disable L2 cache */
+ li r3, 0
+ msync
+ isync
+ mtspr SPRN_L2CSR0, r3
+ isync
+1:
+ blr
+
+/******** Platform Cache ********/
+
+#define L2CTL_L2E 0x80000000
+#define L2CTL_L2I 0x40000000
+
+/* r3 = base address of L2 controller registers */
+_GLOBAL(flush_disable_L2)
+ /* It's a write-through cache, so only invalidation is needed. */
+ mbar
+ isync
+ lwz r4, 0(r3)
+ li r5, 1
+ rlwimi r4, r5, 30, L2CTL_L2E | L2CTL_L2I
+ stw r4, 0(r3)
+
+ /* Wait for the invalidate to finish */
+1: lwz r4, 0(r3)
+ andis. r4, r4, L2CTL_L2I@h
+ bne 1b
+ mbar
+
+ blr
+
+/* r3 = base address of L2 controller registers */
+_GLOBAL(invalidate_enable_L2)
+ mbar
+ isync
+ lwz r4, 0(r3)
+ li r5, 3
+ rlwimi r4, r5, 30, L2CTL_L2E | L2CTL_L2I
+ stw r4, 0(r3)
+
+ /* Wait for the invalidate to finish */
+1: lwz r4, 0(r3)
+ andis. r4, r4, L2CTL_L2I@h
+ bne 1b
+ mbar
+
+ blr
diff --git a/arch/powerpc/kernel/head_fsl_booke.S b/arch/powerpc/kernel/head_fsl_booke.S
index 6f62a73..58925b6 100644
--- a/arch/powerpc/kernel/head_fsl_booke.S
+++ b/arch/powerpc/kernel/head_fsl_booke.S
@@ -987,80 +987,6 @@ _GLOBAL(set_context)
isync /* Force context change */
blr
-_GLOBAL(flush_dcache_L1)
- mfspr r3,SPRN_L1CFG0
-
- rlwinm r5,r3,9,3 /* Extract cache block size */
- twlgti r5,1 /* Only 32 and 64 byte cache blocks
- * are currently defined.
- */
- li r4,32
- subfic r6,r5,2 /* r6 = log2(1KiB / cache block size) -
- * log2(number of ways)
- */
- slw r5,r4,r5 /* r5 = cache block size */
-
- rlwinm r7,r3,0,0xff /* Extract number of KiB in the cache */
- mulli r7,r7,13 /* An 8-way cache will require 13
- * loads per set.
- */
- slw r7,r7,r6
-
- /* save off HID0 and set DCFA */
- mfspr r8,SPRN_HID0
- ori r9,r8,HID0_DCFA@l
- mtspr SPRN_HID0,r9
- isync
-
- lis r4,KERNELBASE@h
- mtctr r7
-
-1: lwz r3,0(r4) /* Load... */
- add r4,r4,r5
- bdnz 1b
-
- msync
- lis r4,KERNELBASE@h
- mtctr r7
-
-1: dcbf 0,r4 /* ...and flush. */
- add r4,r4,r5
- bdnz 1b
-
- /* restore HID0 */
- mtspr SPRN_HID0,r8
- isync
-
- blr
-
-/* Flush L1 d-cache, invalidate and disable d-cache and i-cache */
-_GLOBAL(__flush_disable_L1)
- mflr r10
- bl flush_dcache_L1 /* Flush L1 d-cache */
- mtlr r10
-
- mfspr r4, SPRN_L1CSR0 /* Invalidate and disable d-cache */
- li r5, 2
- rlwimi r4, r5, 0, 3
-
- msync
- isync
- mtspr SPRN_L1CSR0, r4
- isync
-
-1: mfspr r4, SPRN_L1CSR0 /* Wait for the invalidate to finish */
- andi. r4, r4, 2
- bne 1b
-
- mfspr r4, SPRN_L1CSR1 /* Invalidate and disable i-cache */
- li r5, 2
- rlwimi r4, r5, 0, 3
-
- mtspr SPRN_L1CSR1, r4
- isync
-
- blr
-
#ifdef CONFIG_SMP
/* When we get here, r24 needs to hold the CPU # */
.globl __secondary_start
--
1.7.3
^ permalink raw reply related [flat|nested] 5+ messages in thread* [PATCH v2 06/15] powerpc/85xx: add support to JOG feature using cpufreq interface
2013-04-19 10:47 [PATCH v2 01/15] powerpc/85xx: cache operations for Freescale SoCs based on BOOK3E Zhao Chenhui
@ 2013-04-19 10:47 ` Zhao Chenhui
2013-04-22 3:25 ` Viresh Kumar
0 siblings, 1 reply; 5+ messages in thread
From: Zhao Chenhui @ 2013-04-19 10:47 UTC (permalink / raw)
To: linuxppc-dev; +Cc: linux-kernel
From: chenhui zhao <chenhui.zhao@freescale.com>
Some 85xx silicons like MPC8536 and P1022 have a JOG feature, which provides
a dynamic mechanism to lower or raise the CPU core clock at runtime.
This patch adds the support to change CPU frequency using the standard
cpufreq interface. The ratio CORE to CCB can be 1:1(except MPC8536), 3:2,
2:1, 5:2, 3:1, 7:2 and 4:1.
Two CPU cores on P1022 must not in the low power state during the frequency
transition. The driver uses a atomic counter to meet the requirement.
The jog mode frequency transition process on the MPC8536 is similar to
the deep sleep process. The driver need save the CPU state and restore
it after CPU warm reset.
Note:
* The I/O peripherals such as PCIe and eTSEC may lose packets during
the jog mode frequency transition.
* The driver doesn't support MPC8536 Rev 1.0 due to a JOG erratum.
Subsequent revisions of MPC8536 have corrected the erratum.
Signed-off-by: Dave Liu <daveliu@freescale.com>
Signed-off-by: Li Yang <leoli@freescale.com>
Signed-off-by: Jerry Huang <Chang-Ming.Huang@freescale.com>
Signed-off-by: Zhao Chenhui <chenhui.zhao@freescale.com>
CC: Scott Wood <scottwood@freescale.com>
---
arch/powerpc/platforms/85xx/Makefile | 1 +
drivers/cpufreq/Kconfig.powerpc | 10 +
drivers/cpufreq/Makefile | 1 +
drivers/cpufreq/mpc85xx-cpufreq.c | 390 ++++++++++++++++++++++++++++++++++
4 files changed, 402 insertions(+), 0 deletions(-)
create mode 100644 drivers/cpufreq/mpc85xx-cpufreq.c
diff --git a/arch/powerpc/platforms/85xx/Makefile b/arch/powerpc/platforms/85xx/Makefile
index a35bab7..da53bde 100644
--- a/arch/powerpc/platforms/85xx/Makefile
+++ b/arch/powerpc/platforms/85xx/Makefile
@@ -3,6 +3,7 @@
#
obj-$(CONFIG_SMP) += smp.o
obj-$(CONFIG_FSL_PMC) += sleep.o
+obj-$(CONFIG_CPU_FREQ_MPC85xx) += sleep.o
obj-y += common.o
diff --git a/drivers/cpufreq/Kconfig.powerpc b/drivers/cpufreq/Kconfig.powerpc
index e76992f..ba06a00 100644
--- a/drivers/cpufreq/Kconfig.powerpc
+++ b/drivers/cpufreq/Kconfig.powerpc
@@ -5,3 +5,13 @@ config CPU_FREQ_MAPLE
help
This adds support for frequency switching on Maple 970FX
Evaluation Board and compatible boards (IBM JS2x blades).
+
+config CPU_FREQ_MPC85xx
+ bool "Support for Freescale MPC85xx CPU freq"
+ depends on PPC_85xx && PPC32 && !PPC_E500MC
+ select CPU_FREQ_TABLE
+ help
+ This adds support for dynamic frequency switching on
+ Freescale MPC85xx by cpufreq interface. MPC8536 and P1022
+ have a JOG feature, which provides a dynamic mechanism
+ to lower or raise the CPU core clock at runtime.
diff --git a/drivers/cpufreq/Makefile b/drivers/cpufreq/Makefile
index 863fd18..e7aecc5 100644
--- a/drivers/cpufreq/Makefile
+++ b/drivers/cpufreq/Makefile
@@ -61,3 +61,4 @@ obj-$(CONFIG_ARM_IMX6Q_CPUFREQ) += imx6q-cpufreq.o
##################################################################################
# PowerPC platform drivers
obj-$(CONFIG_CPU_FREQ_MAPLE) += maple-cpufreq.o
+obj-$(CONFIG_CPU_FREQ_MPC85xx) += mpc85xx-cpufreq.o
diff --git a/drivers/cpufreq/mpc85xx-cpufreq.c b/drivers/cpufreq/mpc85xx-cpufreq.c
new file mode 100644
index 0000000..f56c826
--- /dev/null
+++ b/drivers/cpufreq/mpc85xx-cpufreq.c
@@ -0,0 +1,390 @@
+/*
+ * Copyright (C) 2008-2012 Freescale Semiconductor, Inc.
+ * Author: Dave Liu <daveliu@freescale.com>
+ * Modifier: Chenhui Zhao <chenhui.zhao@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/module.h>
+#include <linux/cpufreq.h>
+#include <linux/of_platform.h>
+#include <linux/suspend.h>
+#include <linux/cpu.h>
+#include <linux/time.h>
+#include <linux/io.h>
+#include <linux/smp.h>
+
+#include <asm/prom.h>
+#include <asm/reg.h>
+#include <asm/machdep.h>
+
+#include <sysdev/fsl_soc.h>
+
+static DEFINE_MUTEX(mpc85xx_switch_mutex);
+static void __iomem *guts;
+
+static u32 sysfreq;
+static unsigned int max_pll[2];
+static atomic_t in_jog_process;
+static struct cpufreq_frequency_table *mpc85xx_freqs;
+static int (*set_pll)(unsigned int cpu, unsigned int pll);
+
+static struct cpufreq_frequency_table mpc8536_freqs_table[] = {
+ {3, 0},
+ {4, 0},
+ {5, 0},
+ {6, 0},
+ {7, 0},
+ {8, 0},
+ {0, CPUFREQ_TABLE_END},
+};
+
+static struct cpufreq_frequency_table p1022_freqs_table[] = {
+ {2, 0},
+ {3, 0},
+ {4, 0},
+ {5, 0},
+ {6, 0},
+ {7, 0},
+ {8, 0},
+ {0, CPUFREQ_TABLE_END},
+};
+
+#define FREQ_500MHz 500000000
+#define FREQ_800MHz 800000000
+
+#define CORE_RATIO_STRIDE 8
+#define CORE_RATIO_MASK 0x3f
+#define CORE_RATIO_SHIFT 16
+
+#define PORPLLSR 0x0 /* Power-On Reset PLL ratio status register */
+
+#define PMJCR 0x7c /* Power Management Jog Control Register */
+#define PMJCR_CORE0_SPD 0x00001000
+#define PMJCR_CORE_SPD 0x00002000
+
+#define POWMGTCSR 0x80 /* Power management control and status register */
+#define POWMGTCSR_JOG 0x00200000
+#define POWMGTCSR_INT_MASK 0x00000f00
+
+static void spin_while_jogging(void *dummy)
+{
+ unsigned long flags;
+
+ local_irq_save(flags);
+
+ atomic_inc(&in_jog_process);
+
+ while (atomic_read(&in_jog_process) != 0)
+ barrier();
+
+ local_irq_restore(flags);
+}
+
+static int get_pll(int hw_cpu)
+{
+ int shift;
+ u32 val = in_be32(guts + PORPLLSR);
+
+ shift = hw_cpu * CORE_RATIO_STRIDE + CORE_RATIO_SHIFT;
+
+ return (val >> shift) & CORE_RATIO_MASK;
+}
+
+static int mpc8536_set_pll(unsigned int cpu, unsigned int pll)
+{
+ u32 corefreq, val, mask;
+ unsigned int cur_pll = get_pll(0);
+ unsigned long flags;
+
+ if (pll == cur_pll)
+ return 0;
+
+ val = (pll & CORE_RATIO_MASK) << CORE_RATIO_SHIFT;
+
+ corefreq = sysfreq * pll / 2;
+ /*
+ * Set the COREx_SPD bit if the requested core frequency
+ * is larger than the threshold frequency.
+ */
+ if (corefreq > FREQ_800MHz)
+ val |= PMJCR_CORE_SPD;
+
+ mask = (CORE_RATIO_MASK << CORE_RATIO_SHIFT) | PMJCR_CORE_SPD;
+ clrsetbits_be32(guts + PMJCR, mask, val);
+
+ /* readback to sync write */
+ in_be32(guts + PMJCR);
+
+ local_irq_save(flags);
+ mpc85xx_enter_deep_sleep(get_immrbase(), POWMGTCSR_JOG);
+ local_irq_restore(flags);
+
+ /* verify */
+ cur_pll = get_pll(0);
+ if (cur_pll != pll) {
+ pr_err("%s: error. The current PLL is %d instead of %d.\n",
+ __func__, cur_pll, pll);
+ return -1;
+ }
+
+ return 0;
+}
+
+static int p1022_set_pll(unsigned int cpu, unsigned int pll)
+{
+ int index, hw_cpu = get_hard_smp_processor_id(cpu);
+ int shift;
+ u32 corefreq, val, mask = 0;
+ unsigned int cur_pll = get_pll(hw_cpu);
+ unsigned long flags;
+ int ret = 0;
+
+ if (pll == cur_pll)
+ return 0;
+
+ shift = hw_cpu * CORE_RATIO_STRIDE + CORE_RATIO_SHIFT;
+ val = (pll & CORE_RATIO_MASK) << shift;
+
+ corefreq = sysfreq * pll / 2;
+ /*
+ * Set the COREx_SPD bit if the requested core frequency
+ * is larger than the threshold frequency.
+ */
+ if (corefreq > FREQ_500MHz)
+ val |= PMJCR_CORE0_SPD << hw_cpu;
+
+ mask = (CORE_RATIO_MASK << shift) | (PMJCR_CORE0_SPD << hw_cpu);
+ clrsetbits_be32(guts + PMJCR, mask, val);
+
+ /* readback to sync write */
+ in_be32(guts + PMJCR);
+
+ get_online_cpus();
+ /*
+ * A Jog request can not be asserted when any core is in a low
+ * power state on P1022. Before executing a jog request, any
+ * core which is in a low power state must be waked by a
+ * interrupt, and keep waking up until the sequence is
+ * finished.
+ */
+ for_each_present_cpu(index) {
+ if (!cpu_online(index)) {
+ put_online_cpus();
+ pr_err("%s: error, core%d is down.\n", __func__, index);
+ return -1;
+ }
+ }
+
+ atomic_set(&in_jog_process, 0);
+ smp_call_function(spin_while_jogging, NULL, 0);
+
+ local_irq_save(flags);
+
+ /* Wait for the other core to wake. */
+ if (!spin_event_timeout(atomic_read(&in_jog_process) == 1, 1000, 100)) {
+ pr_err("%s: timeout, the other core is not at running state.\n",
+ __func__);
+ ret = -1;
+ goto err;
+ }
+
+ out_be32(guts + POWMGTCSR, POWMGTCSR_JOG | POWMGTCSR_INT_MASK);
+
+ if (!spin_event_timeout(
+ (in_be32(guts + POWMGTCSR) & POWMGTCSR_JOG) == 0, 1000, 100)) {
+ pr_err("%s: timeout, fail to switch the core frequency.\n",
+ __func__);
+ ret = -1;
+ goto err;
+ }
+
+ clrbits32(guts + POWMGTCSR, POWMGTCSR_INT_MASK);
+ in_be32(guts + POWMGTCSR);
+
+ atomic_set(&in_jog_process, 0);
+err:
+ local_irq_restore(flags);
+ put_online_cpus();
+
+ /* verify */
+ cur_pll = get_pll(hw_cpu);
+ if (cur_pll != pll) {
+ pr_err("%s: error, the current PLL of core %d is %d instead of %d.\n",
+ __func__, hw_cpu, cur_pll, pll);
+ return -1;
+ }
+
+ return ret;
+}
+
+/*
+ * cpufreq functions
+ */
+static int mpc85xx_cpufreq_cpu_init(struct cpufreq_policy *policy)
+{
+ unsigned int i, cur_pll;
+ int hw_cpu = get_hard_smp_processor_id(policy->cpu);
+
+ if (!cpu_present(policy->cpu))
+ return -ENODEV;
+
+ /* the latency of a transition, the unit is ns */
+ policy->cpuinfo.transition_latency = 2000;
+
+ cur_pll = get_pll(hw_cpu);
+
+ /* initialize frequency table */
+ pr_debug("core%d frequency table:\n", hw_cpu);
+ for (i = 0; mpc85xx_freqs[i].frequency != CPUFREQ_TABLE_END; i++) {
+ if (mpc85xx_freqs[i].index <= max_pll[hw_cpu]) {
+ /* The frequency unit is kHz. */
+ mpc85xx_freqs[i].frequency =
+ (sysfreq * mpc85xx_freqs[i].index / 2) / 1000;
+ } else {
+ mpc85xx_freqs[i].frequency = CPUFREQ_ENTRY_INVALID;
+ }
+
+ pr_debug("%d: %dkHz\n", i, mpc85xx_freqs[i].frequency);
+
+ if (mpc85xx_freqs[i].index == cur_pll)
+ policy->cur = mpc85xx_freqs[i].frequency;
+ }
+ pr_debug("current pll is at %d, and core freq is%d\n",
+ cur_pll, 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;
+ int ret = 0;
+
+ if (!set_pll)
+ return -ENODEV;
+
+ 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);
+
+ ret = set_pll(policy->cpu, mpc85xx_freqs[new].index);
+ if (!ret) {
+ pr_info("cpufreq: Setting core%d frequency to %d kHz and PLL ratio to %d:2\n",
+ policy->cpu, mpc85xx_freqs[new].frequency,
+ mpc85xx_freqs[new].index);
+
+ ppc_proc_freq = freqs.new * 1000ul;
+ }
+ cpufreq_notify_transition(&freqs, CPUFREQ_POSTCHANGE);
+ mutex_unlock(&mpc85xx_switch_mutex);
+
+ return ret;
+}
+
+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-JOG",
+ .owner = THIS_MODULE,
+ .flags = CPUFREQ_CONST_LOOPS,
+};
+
+static struct of_device_id mpc85xx_jog_ids[] = {
+ { .compatible = "fsl,mpc8536-guts", },
+ { .compatible = "fsl,p1022-guts", },
+ {}
+};
+
+static int __init mpc85xx_jog_init(void)
+{
+ struct device_node *np;
+ unsigned int svr;
+
+ np = of_find_matching_node(NULL, mpc85xx_jog_ids);
+ if (!np)
+ return -ENODEV;
+
+ guts = of_iomap(np, 0);
+ if (!guts) {
+ of_node_put(np);
+ return -ENODEV;
+ }
+
+ sysfreq = fsl_get_sys_freq();
+
+ if (of_device_is_compatible(np, "fsl,mpc8536-guts")) {
+ svr = mfspr(SPRN_SVR);
+ if ((svr & 0x7fff) == 0x10) {
+ pr_err("MPC8536 Rev 1.0 does not support cpufreq(JOG).\n");
+ of_node_put(np);
+ return -ENODEV;
+ }
+ mpc85xx_freqs = mpc8536_freqs_table;
+ set_pll = mpc8536_set_pll;
+ max_pll[0] = get_pll(0);
+
+ } else if (of_device_is_compatible(np, "fsl,p1022-guts")) {
+ mpc85xx_freqs = p1022_freqs_table;
+ set_pll = p1022_set_pll;
+ max_pll[0] = get_pll(0);
+ max_pll[1] = get_pll(1);
+ }
+
+ pr_info("Freescale MPC85xx cpufreq(JOG) driver\n");
+
+ of_node_put(np);
+ return cpufreq_register_driver(&mpc85xx_cpufreq_driver);
+}
+
+device_initcall(mpc85xx_jog_init);
--
1.7.3
^ permalink raw reply related [flat|nested] 5+ messages in thread* Re: [PATCH v2 06/15] powerpc/85xx: add support to JOG feature using cpufreq interface
2013-04-19 10:47 ` [PATCH v2 06/15] powerpc/85xx: add support to JOG feature using cpufreq interface Zhao Chenhui
@ 2013-04-22 3:25 ` Viresh Kumar
2013-04-22 10:56 ` Zhao Chenhui
0 siblings, 1 reply; 5+ messages in thread
From: Viresh Kumar @ 2013-04-22 3:25 UTC (permalink / raw)
To: Zhao Chenhui; +Cc: linuxppc-dev, linux-kernel
On Fri, Apr 19, 2013 at 4:17 PM, Zhao Chenhui
<chenhui.zhao@freescale.com> wrote:
> diff --git a/drivers/cpufreq/mpc85xx-cpufreq.c b/drivers/cpufreq/mpc85xx-cpufreq.c
> +#include <linux/module.h>
> +#include <linux/cpufreq.h>
> +#include <linux/of_platform.h>
> +#include <linux/suspend.h>
> +#include <linux/cpu.h>
> +#include <linux/time.h>
> +#include <linux/io.h>
> +#include <linux/smp.h>
Would be better to keep them in alphabetical order, so that we don't add
anything twice.
> +static int mpc85xx_cpufreq_cpu_init(struct cpufreq_policy *policy)
> +{
> + unsigned int i, cur_pll;
> + int hw_cpu = get_hard_smp_processor_id(policy->cpu);
> +
> + if (!cpu_present(policy->cpu))
This can't happen and so no need to check it.
> + return -ENODEV;
> +
> + /* the latency of a transition, the unit is ns */
> + policy->cpuinfo.transition_latency = 2000;
> +
> + cur_pll = get_pll(hw_cpu);
> +
> + /* initialize frequency table */
> + pr_debug("core%d frequency table:\n", hw_cpu);
> + for (i = 0; mpc85xx_freqs[i].frequency != CPUFREQ_TABLE_END; i++) {
> + if (mpc85xx_freqs[i].index <= max_pll[hw_cpu]) {
> + /* The frequency unit is kHz. */
> + mpc85xx_freqs[i].frequency =
> + (sysfreq * mpc85xx_freqs[i].index / 2) / 1000;
> + } else {
> + mpc85xx_freqs[i].frequency = CPUFREQ_ENTRY_INVALID;
> + }
> +
> + pr_debug("%d: %dkHz\n", i, mpc85xx_freqs[i].frequency);
> +
> + if (mpc85xx_freqs[i].index == cur_pll)
> + policy->cur = mpc85xx_freqs[i].frequency;
> + }
> + pr_debug("current pll is at %d, and core freq is%d\n",
> + cur_pll, 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);
Call cpufreq_frequency_table_get_attr() at the end after above call is
successful.
> +}
> +static int mpc85xx_cpufreq_target(struct cpufreq_policy *policy,
> + unsigned int target_freq,
> + unsigned int relation)
merge above two lines.
> +{
> + struct cpufreq_freqs freqs;
> + unsigned int new;
> + int ret = 0;
> +
> + if (!set_pll)
> + return -ENODEV;
> +
> + cpufreq_frequency_table_target(policy,
> + mpc85xx_freqs,
> + target_freq,
> + relation,
> + &new);
same.. merge all above to put it in a single line.
> + freqs.old = policy->cur;
> + freqs.new = mpc85xx_freqs[new].frequency;
> + freqs.cpu = policy->cpu;
not required now.
> + mutex_lock(&mpc85xx_switch_mutex);
> + cpufreq_notify_transition(&freqs, CPUFREQ_PRECHANGE);
ditto. Rebase over latest code from linux-next. This call has changed.
> + ret = set_pll(policy->cpu, mpc85xx_freqs[new].index);
> + if (!ret) {
> + pr_info("cpufreq: Setting core%d frequency to %d kHz and PLL ratio to %d:2\n",
> + policy->cpu, mpc85xx_freqs[new].frequency,
> + mpc85xx_freqs[new].index);
> +
> + ppc_proc_freq = freqs.new * 1000ul;
> + }
> + cpufreq_notify_transition(&freqs, CPUFREQ_POSTCHANGE);
> + mutex_unlock(&mpc85xx_switch_mutex);
> +
> + return ret;
> +}
> +static int __init mpc85xx_jog_init(void)
> +{
> + struct device_node *np;
> + unsigned int svr;
> +
> + np = of_find_matching_node(NULL, mpc85xx_jog_ids);
> + if (!np)
> + return -ENODEV;
> +
> + guts = of_iomap(np, 0);
> + if (!guts) {
> + of_node_put(np);
> + return -ENODEV;
> + }
> +
> + sysfreq = fsl_get_sys_freq();
> +
> + if (of_device_is_compatible(np, "fsl,mpc8536-guts")) {
> + svr = mfspr(SPRN_SVR);
> + if ((svr & 0x7fff) == 0x10) {
> + pr_err("MPC8536 Rev 1.0 does not support cpufreq(JOG).\n");
> + of_node_put(np);
unmap too??
> + return -ENODEV;
> + }
> + mpc85xx_freqs = mpc8536_freqs_table;
> + set_pll = mpc8536_set_pll;
> + max_pll[0] = get_pll(0);
> +
> + } else if (of_device_is_compatible(np, "fsl,p1022-guts")) {
> + mpc85xx_freqs = p1022_freqs_table;
> + set_pll = p1022_set_pll;
> + max_pll[0] = get_pll(0);
> + max_pll[1] = get_pll(1);
> + }
> +
> + pr_info("Freescale MPC85xx cpufreq(JOG) driver\n");
> +
> + of_node_put(np);
> + return cpufreq_register_driver(&mpc85xx_cpufreq_driver);
> +}
> +
> +device_initcall(mpc85xx_jog_init);
^ permalink raw reply [flat|nested] 5+ messages in thread* Re: [PATCH v2 06/15] powerpc/85xx: add support to JOG feature using cpufreq interface
2013-04-22 3:25 ` Viresh Kumar
@ 2013-04-22 10:56 ` Zhao Chenhui
0 siblings, 0 replies; 5+ messages in thread
From: Zhao Chenhui @ 2013-04-22 10:56 UTC (permalink / raw)
To: Viresh Kumar; +Cc: linuxppc-dev, linux-kernel, cpufreq, linux-pm
On Mon, Apr 22, 2013 at 08:55:35AM +0530, Viresh Kumar wrote:
> On Fri, Apr 19, 2013 at 4:17 PM, Zhao Chenhui
> <chenhui.zhao@freescale.com> wrote:
> > diff --git a/drivers/cpufreq/mpc85xx-cpufreq.c b/drivers/cpufreq/mpc85xx-cpufreq.c
>
> > +#include <linux/module.h>
> > +#include <linux/cpufreq.h>
> > +#include <linux/of_platform.h>
> > +#include <linux/suspend.h>
> > +#include <linux/cpu.h>
> > +#include <linux/time.h>
> > +#include <linux/io.h>
> > +#include <linux/smp.h>
>
> Would be better to keep them in alphabetical order, so that we don't add
> anything twice.
Good idea.
>
> > +static int mpc85xx_cpufreq_cpu_init(struct cpufreq_policy *policy)
> > +{
> > + unsigned int i, cur_pll;
> > + int hw_cpu = get_hard_smp_processor_id(policy->cpu);
> > +
> > + if (!cpu_present(policy->cpu))
>
> This can't happen and so no need to check it.
>
> > + return -ENODEV;
> > +
> > + /* the latency of a transition, the unit is ns */
> > + policy->cpuinfo.transition_latency = 2000;
> > +
> > + cur_pll = get_pll(hw_cpu);
> > +
> > + /* initialize frequency table */
> > + pr_debug("core%d frequency table:\n", hw_cpu);
> > + for (i = 0; mpc85xx_freqs[i].frequency != CPUFREQ_TABLE_END; i++) {
> > + if (mpc85xx_freqs[i].index <= max_pll[hw_cpu]) {
> > + /* The frequency unit is kHz. */
> > + mpc85xx_freqs[i].frequency =
> > + (sysfreq * mpc85xx_freqs[i].index / 2) / 1000;
> > + } else {
> > + mpc85xx_freqs[i].frequency = CPUFREQ_ENTRY_INVALID;
> > + }
> > +
> > + pr_debug("%d: %dkHz\n", i, mpc85xx_freqs[i].frequency);
> > +
> > + if (mpc85xx_freqs[i].index == cur_pll)
> > + policy->cur = mpc85xx_freqs[i].frequency;
> > + }
> > + pr_debug("current pll is at %d, and core freq is%d\n",
> > + cur_pll, 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);
>
> Call cpufreq_frequency_table_get_attr() at the end after above call is
> successful.
>
> > +}
>
> > +static int mpc85xx_cpufreq_target(struct cpufreq_policy *policy,
> > + unsigned int target_freq,
> > + unsigned int relation)
>
> merge above two lines.
>
> > +{
> > + struct cpufreq_freqs freqs;
> > + unsigned int new;
> > + int ret = 0;
> > +
> > + if (!set_pll)
> > + return -ENODEV;
> > +
> > + cpufreq_frequency_table_target(policy,
> > + mpc85xx_freqs,
> > + target_freq,
> > + relation,
> > + &new);
>
> same.. merge all above to put it in a single line.
>
> > + freqs.old = policy->cur;
> > + freqs.new = mpc85xx_freqs[new].frequency;
> > + freqs.cpu = policy->cpu;
>
> not required now.
>
> > + mutex_lock(&mpc85xx_switch_mutex);
> > + cpufreq_notify_transition(&freqs, CPUFREQ_PRECHANGE);
>
> ditto. Rebase over latest code from linux-next. This call has changed.
>
> > + ret = set_pll(policy->cpu, mpc85xx_freqs[new].index);
> > + if (!ret) {
> > + pr_info("cpufreq: Setting core%d frequency to %d kHz and PLL ratio to %d:2\n",
> > + policy->cpu, mpc85xx_freqs[new].frequency,
> > + mpc85xx_freqs[new].index);
> > +
> > + ppc_proc_freq = freqs.new * 1000ul;
> > + }
> > + cpufreq_notify_transition(&freqs, CPUFREQ_POSTCHANGE);
> > + mutex_unlock(&mpc85xx_switch_mutex);
> > +
> > + return ret;
> > +}
>
> > +static int __init mpc85xx_jog_init(void)
> > +{
> > + struct device_node *np;
> > + unsigned int svr;
> > +
> > + np = of_find_matching_node(NULL, mpc85xx_jog_ids);
> > + if (!np)
> > + return -ENODEV;
> > +
> > + guts = of_iomap(np, 0);
> > + if (!guts) {
> > + of_node_put(np);
> > + return -ENODEV;
> > + }
> > +
> > + sysfreq = fsl_get_sys_freq();
> > +
> > + if (of_device_is_compatible(np, "fsl,mpc8536-guts")) {
> > + svr = mfspr(SPRN_SVR);
> > + if ((svr & 0x7fff) == 0x10) {
> > + pr_err("MPC8536 Rev 1.0 does not support cpufreq(JOG).\n");
> > + of_node_put(np);
>
> unmap too??
>
> > + return -ENODEV;
> > + }
> > + mpc85xx_freqs = mpc8536_freqs_table;
> > + set_pll = mpc8536_set_pll;
> > + max_pll[0] = get_pll(0);
> > +
> > + } else if (of_device_is_compatible(np, "fsl,p1022-guts")) {
> > + mpc85xx_freqs = p1022_freqs_table;
> > + set_pll = p1022_set_pll;
> > + max_pll[0] = get_pll(0);
> > + max_pll[1] = get_pll(1);
> > + }
> > +
> > + pr_info("Freescale MPC85xx cpufreq(JOG) driver\n");
> > +
> > + of_node_put(np);
> > + return cpufreq_register_driver(&mpc85xx_cpufreq_driver);
> > +}
> > +
> > +device_initcall(mpc85xx_jog_init);
>
Thanks. I will fix them.
-Chenhui
^ permalink raw reply [flat|nested] 5+ messages in thread
end of thread, other threads:[~2013-04-22 10:57 UTC | newest]
Thread overview: 5+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
[not found] <20130419110057.GC29421@localhost.localdomain>
2013-04-21 23:43 ` [PATCH v2 06/15] powerpc/85xx: add support to JOG feature using cpufreq interface Rafael J. Wysocki
2013-04-22 10:57 ` Zhao Chenhui
2013-04-19 10:47 [PATCH v2 01/15] powerpc/85xx: cache operations for Freescale SoCs based on BOOK3E Zhao Chenhui
2013-04-19 10:47 ` [PATCH v2 06/15] powerpc/85xx: add support to JOG feature using cpufreq interface Zhao Chenhui
2013-04-22 3:25 ` Viresh Kumar
2013-04-22 10:56 ` Zhao Chenhui
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox