From: Dinh Nguyen <[email protected]>
For MX51 SRPG, we need to turn on the GPC clock in order to set the
SRPG registers.
Signed-off-by: Dinh Nguyen <[email protected]>
---
arch/arm/mach-mx5/clock-mx51-mx53.c | 8 ++++++++
1 files changed, 8 insertions(+), 0 deletions(-)
diff --git a/arch/arm/mach-mx5/clock-mx51-mx53.c b/arch/arm/mach-mx5/clock-mx51-mx53.c
index 652ace4..3eb1c6e 100644
--- a/arch/arm/mach-mx5/clock-mx51-mx53.c
+++ b/arch/arm/mach-mx5/clock-mx51-mx53.c
@@ -865,6 +865,13 @@ static struct clk aips_tz2_clk = {
.disable = _clk_ccgr_disable_inwait,
};
+static struct clk gpc_dvfs_clk = {
+ .enable_reg = MXC_CCM_CCGR5,
+ .enable_shift = MXC_CCM_CCGRx_CG12_OFFSET,
+ .enable = _clk_ccgr_enable,
+ .disable = _clk_ccgr_disable,
+};
+
static struct clk gpt_32k_clk = {
.id = 0,
.parent = &ckil_clk,
@@ -1448,6 +1455,7 @@ static struct clk_lookup mx51_lookups[] = {
_REGISTER_CLOCK("imx-ipuv3", NULL, ipu_clk)
_REGISTER_CLOCK("imx-ipuv3", "di0", ipu_di0_clk)
_REGISTER_CLOCK("imx-ipuv3", "di1", ipu_di1_clk)
+ _REGISTER_CLOCK(NULL, "gpc_dvfs", gpc_dvfs_clk)
};
static struct clk_lookup mx53_lookups[] = {
--
1.6.0.4
From: Dinh Nguyen <[email protected]>
Adds initial low power suspend functionality to MX51.
Supports "mem" and "standby" modes.
Tested on mx51-babbage.
Signed-off-by: Dinh Nguyen <[email protected]>
---
arch/arm/mach-mx5/Makefile | 1 +
arch/arm/mach-mx5/pm-imx51.c | 74 ++++++++++++++++++++++++++++++++++++++++++
2 files changed, 75 insertions(+), 0 deletions(-)
create mode 100644 arch/arm/mach-mx5/pm-imx51.c
diff --git a/arch/arm/mach-mx5/Makefile b/arch/arm/mach-mx5/Makefile
index 0b9338c..787cb80 100644
--- a/arch/arm/mach-mx5/Makefile
+++ b/arch/arm/mach-mx5/Makefile
@@ -6,6 +6,7 @@
obj-y := cpu.o mm.o clock-mx51-mx53.o devices.o ehci.o system.o
obj-$(CONFIG_SOC_IMX50) += mm-mx50.o
+obj-$(CONFIG_PM) += pm-imx51.o
obj-$(CONFIG_CPU_FREQ_IMX) += cpu_op-mx51.o
obj-$(CONFIG_MACH_MX51_BABBAGE) += board-mx51_babbage.o
obj-$(CONFIG_MACH_MX51_3DS) += board-mx51_3ds.o
diff --git a/arch/arm/mach-mx5/pm-imx51.c b/arch/arm/mach-mx5/pm-imx51.c
new file mode 100644
index 0000000..49186e3
--- /dev/null
+++ b/arch/arm/mach-mx5/pm-imx51.c
@@ -0,0 +1,74 @@
+/*
+ * Copyright (C) 2011 Freescale Semiconductor, Inc. All Rights Reserved.
+ *
+ * The code contained herein is licensed under the GNU General Public
+ * License. You may obtain a copy of the GNU General Public License
+ * Version 2 or later at the following locations:
+ *
+ * http://www.opensource.org/licenses/gpl-license.html
+ * http://www.gnu.org/copyleft/gpl.html
+ */
+#include <linux/suspend.h>
+#include <linux/clk.h>
+#include <asm/mach/map.h>
+#include <asm/cacheflush.h>
+#include <asm/tlb.h>
+#include <mach/system.h>
+#include "crm_regs.h"
+
+static struct clk *gpc_dvfs_clk;
+
+static int mx5_suspend_enter(suspend_state_t state)
+{
+ if (gpc_dvfs_clk == NULL)
+ gpc_dvfs_clk = clk_get(NULL, "gpc_dvfs");
+
+ if (gpc_dvfs_clk) {
+ clk_enable(gpc_dvfs_clk);
+ switch (state) {
+ case PM_SUSPEND_MEM:
+ mx5_cpu_lp_set(STOP_POWER_OFF);
+ break;
+ case PM_SUSPEND_STANDBY:
+ mx5_cpu_lp_set(WAIT_UNCLOCKED_POWER_OFF);
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ if (state == PM_SUSPEND_MEM) {
+ local_flush_tlb_all();
+ flush_cache_all();
+
+ /*clear the EMPGC0/1 bits */
+ __raw_writel(0, MXC_SRPG_EMPGC0_SRPGCR);
+ __raw_writel(0, MXC_SRPG_EMPGC1_SRPGCR);
+ }
+ cpu_do_idle();
+ clk_disable(gpc_dvfs_clk);
+ }else {
+ printk(KERN_ERR "Cannot enter SRPG suspend -no gpc_dvfs clock!\n");
+ return -EPERM;
+ }
+
+ return 0;
+}
+
+static int mx5_pm_valid(suspend_state_t state)
+{
+ return (state > PM_SUSPEND_ON && state <= PM_SUSPEND_MAX);
+}
+
+static const struct platform_suspend_ops mx5_suspend_ops = {
+ .valid = mx5_pm_valid,
+ .enter = mx5_suspend_enter,
+};
+
+static int __init mx5_pm_init(void)
+{
+ if (cpu_is_mx51())
+ suspend_set_ops(&mx5_suspend_ops);
+
+ return 0;
+}
+device_initcall(mx5_pm_init);
--
1.6.0.4
From: Dinh Nguyen <[email protected]>
Implement code for MX51 that allows the SoC to enter WFI when
arch_idle is called.
This patch is also necessary for correctly suspending the system.
Signed-off-by: Dinh Nguyen <[email protected]>
---
arch/arm/mach-mx5/Makefile | 2 +-
arch/arm/mach-mx5/system.c | 85 +++++++++++++++++++++++++++++++
arch/arm/plat-mxc/include/mach/mxc.h | 9 +++
arch/arm/plat-mxc/include/mach/system.h | 6 ++-
4 files changed, 100 insertions(+), 2 deletions(-)
create mode 100644 arch/arm/mach-mx5/system.c
diff --git a/arch/arm/mach-mx5/Makefile b/arch/arm/mach-mx5/Makefile
index 4f63048..0b9338c 100644
--- a/arch/arm/mach-mx5/Makefile
+++ b/arch/arm/mach-mx5/Makefile
@@ -3,7 +3,7 @@
#
# Object file lists.
-obj-y := cpu.o mm.o clock-mx51-mx53.o devices.o ehci.o
+obj-y := cpu.o mm.o clock-mx51-mx53.o devices.o ehci.o system.o
obj-$(CONFIG_SOC_IMX50) += mm-mx50.o
obj-$(CONFIG_CPU_FREQ_IMX) += cpu_op-mx51.o
diff --git a/arch/arm/mach-mx5/system.c b/arch/arm/mach-mx5/system.c
new file mode 100644
index 0000000..56c2bd1
--- /dev/null
+++ b/arch/arm/mach-mx5/system.c
@@ -0,0 +1,85 @@
+/*
+ * Copyright (C) 2011 Freescale Semiconductor, Inc. All Rights Reserved.
+ */
+
+/*
+ * The code contained herein is licensed under the GNU General Public
+ * License. You may obtain a copy of the GNU General Public License
+ * Version 2 or later at the following locations:
+ *
+ * http://www.opensource.org/licenses/gpl-license.html
+ * http://www.gnu.org/copyleft/gpl.html
+ */
+#include <linux/platform_device.h>
+#include <linux/io.h>
+#include <mach/hardware.h>
+#include "crm_regs.h"
+
+/* set cpu low power mode before WFI instruction. This function is called
+ * mx5 because it can be used for mx50, mx51, and mx53.*/
+void mx5_cpu_lp_set(enum mxc_cpu_pwr_mode mode)
+{
+ u32 plat_lpc, arm_srpgcr, ccm_clpcr;
+ u32 empgc0, empgc1;
+ int stop_mode = 0;
+
+ /* always allow platform to issue a deep sleep mode request */
+ plat_lpc = __raw_readl(MXC_CORTEXA8_PLAT_LPC) &
+ ~(MXC_CORTEXA8_PLAT_LPC_DSM);
+ ccm_clpcr = __raw_readl(MXC_CCM_CLPCR) & ~(MXC_CCM_CLPCR_LPM_MASK);
+ arm_srpgcr = __raw_readl(MXC_SRPG_ARM_SRPGCR) & ~(MXC_SRPGCR_PCR);
+ empgc0 = __raw_readl(MXC_SRPG_EMPGC0_SRPGCR) & ~(MXC_SRPGCR_PCR);
+ empgc1 = __raw_readl(MXC_SRPG_EMPGC1_SRPGCR) & ~(MXC_SRPGCR_PCR);
+
+ switch (mode) {
+ case WAIT_CLOCKED:
+ break;
+ case WAIT_UNCLOCKED:
+ ccm_clpcr |= 0x1 << MXC_CCM_CLPCR_LPM_OFFSET;
+ break;
+ case WAIT_UNCLOCKED_POWER_OFF:
+ case STOP_POWER_OFF:
+ plat_lpc |= MXC_CORTEXA8_PLAT_LPC_DSM
+ | MXC_CORTEXA8_PLAT_LPC_DBG_DSM;
+ if (mode == WAIT_UNCLOCKED_POWER_OFF) {
+ ccm_clpcr |= 0x1 << MXC_CCM_CLPCR_LPM_OFFSET;
+ ccm_clpcr &= ~MXC_CCM_CLPCR_VSTBY;
+ ccm_clpcr &= ~MXC_CCM_CLPCR_SBYOS;
+ stop_mode = 0;
+ } else {
+ ccm_clpcr |= 0x2 << MXC_CCM_CLPCR_LPM_OFFSET;
+ ccm_clpcr |= 0x3 << MXC_CCM_CLPCR_STBY_COUNT_OFFSET;
+ ccm_clpcr |= MXC_CCM_CLPCR_VSTBY;
+ ccm_clpcr |= MXC_CCM_CLPCR_SBYOS;
+ stop_mode = 1;
+ }
+ arm_srpgcr |= MXC_SRPGCR_PCR;
+
+ if (tzic_enable_wake(1) != 0)
+ return;
+ break;
+ case STOP_POWER_ON:
+ ccm_clpcr |= 0x2 << MXC_CCM_CLPCR_LPM_OFFSET;
+ break;
+ default:
+ printk(KERN_WARNING "UNKNOWN cpu power mode: %d\n", mode);
+ return;
+ }
+
+ __raw_writel(plat_lpc, MXC_CORTEXA8_PLAT_LPC);
+ __raw_writel(ccm_clpcr, MXC_CCM_CLPCR);
+ __raw_writel(arm_srpgcr, MXC_SRPG_ARM_SRPGCR);
+
+ /* Enable NEON SRPG for all but MX50TO1.0. */
+ if (cpu_is_mx51() || cpu_is_mx53())
+ __raw_writel(arm_srpgcr, MXC_SRPG_NEON_SRPGCR);
+
+ if (stop_mode) {
+ empgc0 |= MXC_SRPGCR_PCR;
+ empgc1 |= MXC_SRPGCR_PCR;
+
+ __raw_writel(empgc0, MXC_SRPG_EMPGC0_SRPGCR);
+ __raw_writel(empgc1, MXC_SRPG_EMPGC1_SRPGCR);
+ }
+}
+
diff --git a/arch/arm/plat-mxc/include/mach/mxc.h b/arch/arm/plat-mxc/include/mach/mxc.h
index 7e07263..6c2a371 100644
--- a/arch/arm/plat-mxc/include/mach/mxc.h
+++ b/arch/arm/plat-mxc/include/mach/mxc.h
@@ -181,6 +181,15 @@ struct cpu_op {
u32 cpu_rate;
};
+int tzic_enable_wake(int is_idle);
+enum mxc_cpu_pwr_mode {
+ WAIT_CLOCKED, /* wfi only */
+ WAIT_UNCLOCKED, /* WAIT */
+ WAIT_UNCLOCKED_POWER_OFF, /* WAIT + SRPG */
+ STOP_POWER_ON, /* just STOP */
+ STOP_POWER_OFF, /* STOP + SRPG */
+};
+
extern struct cpu_op *(*get_cpu_op)(int *op);
#endif
diff --git a/arch/arm/plat-mxc/include/mach/system.h b/arch/arm/plat-mxc/include/mach/system.h
index 95be51b..0417da9 100644
--- a/arch/arm/plat-mxc/include/mach/system.h
+++ b/arch/arm/plat-mxc/include/mach/system.h
@@ -20,6 +20,8 @@
#include <mach/hardware.h>
#include <mach/common.h>
+extern void mx5_cpu_lp_set(enum mxc_cpu_pwr_mode mode);
+
static inline void arch_idle(void)
{
#ifdef CONFIG_ARCH_MXC91231
@@ -54,7 +56,9 @@ static inline void arch_idle(void)
"orr %0, %0, #0x00000004\n"
"mcr p15, 0, %0, c1, c0, 0\n"
: "=r" (reg));
- } else
+ } else if (cpu_is_mx51())
+ mx5_cpu_lp_set(WAIT_UNCLOCKED_POWER_OFF);
+ else
cpu_do_idle();
}
--
1.6.0.4
On Fri, Mar 18, 2011 at 10:21:24AM -0500, [email protected] wrote:
> +#include <linux/suspend.h>
> +#include <linux/clk.h>
> +#include <asm/mach/map.h>
> +#include <asm/cacheflush.h>
> +#include <asm/tlb.h>
> +#include <mach/system.h>
> +#include "crm_regs.h"
Why does the code below require asm/mach/map.h ?
Why does it require asm/tlb.h ?
> +
> +static struct clk *gpc_dvfs_clk;
> +
> +static int mx5_suspend_enter(suspend_state_t state)
> +{
> + if (gpc_dvfs_clk == NULL)
> + gpc_dvfs_clk = clk_get(NULL, "gpc_dvfs");
> +
> + if (gpc_dvfs_clk) {
> + clk_enable(gpc_dvfs_clk);
> + switch (state) {
> + case PM_SUSPEND_MEM:
> + mx5_cpu_lp_set(STOP_POWER_OFF);
> + break;
> + case PM_SUSPEND_STANDBY:
> + mx5_cpu_lp_set(WAIT_UNCLOCKED_POWER_OFF);
> + break;
> + default:
> + return -EINVAL;
> + }
> +
> + if (state == PM_SUSPEND_MEM) {
> + local_flush_tlb_all();
> + flush_cache_all();
> +
> + /*clear the EMPGC0/1 bits */
> + __raw_writel(0, MXC_SRPG_EMPGC0_SRPGCR);
> + __raw_writel(0, MXC_SRPG_EMPGC1_SRPGCR);
> + }
> + cpu_do_idle();
> + clk_disable(gpc_dvfs_clk);
> + }else {
> + printk(KERN_ERR "Cannot enter SRPG suspend -no gpc_dvfs clock!\n");
> + return -EPERM;
> + }
> +
> + return 0;
> +}
> +
> +static int mx5_pm_valid(suspend_state_t state)
> +{
> + return (state > PM_SUSPEND_ON && state <= PM_SUSPEND_MAX);
> +}
> +
> +static const struct platform_suspend_ops mx5_suspend_ops = {
> + .valid = mx5_pm_valid,
> + .enter = mx5_suspend_enter,
> +};
> +
> +static int __init mx5_pm_init(void)
> +{
> + if (cpu_is_mx51())
> + suspend_set_ops(&mx5_suspend_ops);
> +
> + return 0;
> +}
> +device_initcall(mx5_pm_init);
> --
> 1.6.0.4
>
>
Hi Dinh,
On Fri, Mar 18, 2011 at 12:21 PM, <[email protected]> wrote:
...
> + /* Enable NEON SRPG for all but MX50TO1.0. */
> + if (cpu_is_mx51() || cpu_is_mx53())
> + __raw_writel(arm_srpgcr, MXC_SRPG_NEON_SRPGCR);
The comment says that NEON SRPG should not be enabled for MX50 TO1.0,
but your code does not check the MX50 silicon revision.
Regards,
Fabio Estevam
Hi Fabio,
>-----Original Message-----
>From: Fabio Estevam [mailto:[email protected]]
>Sent: Friday, March 18, 2011 10:31 AM
>To: Nguyen Dinh-R00091
>Cc: [email protected]; [email protected];
>[email protected]; [email protected]; u.kleine-
>[email protected]; [email protected]; Vaidyanathan Ranjani-
>RA5478; Zhang Lily-R58066
>Subject: Re: [PATCHv4 2/3] ARM: mx51: Implement code to allow mx51 to
>enter WFI
>
>Hi Dinh,
>
>On Fri, Mar 18, 2011 at 12:21 PM, <[email protected]> wrote:
>...
>> + /* Enable NEON SRPG for all but MX50TO1.0. */
>> + if (cpu_is_mx51() || cpu_is_mx53())
>> + __raw_writel(arm_srpgcr, MXC_SRPG_NEON_SRPGCR);
>
>The comment says that NEON SRPG should not be enabled for MX50 TO1.0,
>but your code does not check the MX50 silicon revision.
There is no mechanism for checking MX50 Revisions yet. I'll work on adding the MX50 revision check.
Dinh
>
>Regards,
>
>Fabio Estevam
????{.n?+???????+%?????ݶ??w??{.n?+????{??G?????{ay?ʇڙ?,j??f???h?????????z_??(?階?ݢj"???m??????G????????????&???~???iO???z??v?^?m????????????I?
Hi Russell,
>-----Original Message-----
>From: [email protected] [mailto:[email protected]] On Behalf Of
>Russell King - ARM Linux
>Sent: Friday, March 18, 2011 10:25 AM
>To: Nguyen Dinh-R00091
>Cc: [email protected]; [email protected]; [email protected];
>[email protected]; [email protected]; Vaidyanathan Ranjani-RA5478; Zhang Lily-
>R58066; [email protected]
>Subject: Re: [PATCHv4 3/3] ARM: mx51: Add support for low power suspend on MX51
>
>On Fri, Mar 18, 2011 at 10:21:24AM -0500, [email protected] wrote:
>> +#include <linux/suspend.h>
>> +#include <linux/clk.h>
>> +#include <asm/mach/map.h>
>> +#include <asm/cacheflush.h>
>> +#include <asm/tlb.h>
>> +#include <mach/system.h>
>> +#include "crm_regs.h"
>
>Why does the code below require asm/mach/map.h ?
map.h can be replaced by linux/io.h for the __raw_writel().
>Why does it require asm/tlb.h ?
asm/tlb is for the local_flush_tlb_all() call.
Thanks for your review.
Dinh
>
>> +
>> +static struct clk *gpc_dvfs_clk;
>> +
>> +static int mx5_suspend_enter(suspend_state_t state)
>> +{
>> + if (gpc_dvfs_clk == NULL)
>> + gpc_dvfs_clk = clk_get(NULL, "gpc_dvfs");
>> +
>> + if (gpc_dvfs_clk) {
>> + clk_enable(gpc_dvfs_clk);
>> + switch (state) {
>> + case PM_SUSPEND_MEM:
>> + mx5_cpu_lp_set(STOP_POWER_OFF);
>> + break;
>> + case PM_SUSPEND_STANDBY:
>> + mx5_cpu_lp_set(WAIT_UNCLOCKED_POWER_OFF);
>> + break;
>> + default:
>> + return -EINVAL;
>> + }
>> +
>> + if (state == PM_SUSPEND_MEM) {
>> + local_flush_tlb_all();
>> + flush_cache_all();
>> +
>> + /*clear the EMPGC0/1 bits */
>> + __raw_writel(0, MXC_SRPG_EMPGC0_SRPGCR);
>> + __raw_writel(0, MXC_SRPG_EMPGC1_SRPGCR);
>> + }
>> + cpu_do_idle();
>> + clk_disable(gpc_dvfs_clk);
>> + }else {
>> + printk(KERN_ERR "Cannot enter SRPG suspend -no gpc_dvfs clock!\n");
>> + return -EPERM;
>> + }
>> +
>> + return 0;
>> +}
>> +
>> +static int mx5_pm_valid(suspend_state_t state)
>> +{
>> + return (state > PM_SUSPEND_ON && state <= PM_SUSPEND_MAX);
>> +}
>> +
>> +static const struct platform_suspend_ops mx5_suspend_ops = {
>> + .valid = mx5_pm_valid,
>> + .enter = mx5_suspend_enter,
>> +};
>> +
>> +static int __init mx5_pm_init(void)
>> +{
>> + if (cpu_is_mx51())
>> + suspend_set_ops(&mx5_suspend_ops);
>> +
>> + return 0;
>> +}
>> +device_initcall(mx5_pm_init);
>> --
>> 1.6.0.4
>>
>>
>--
>To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
>the body of a message to [email protected]
>More majordomo info at http://vger.kernel.org/majordomo-info.html
>Please read the FAQ at http://www.tux.org/lkml/
On Mon, Mar 21, 2011 at 02:53:21PM +0000, Nguyen Dinh-R00091 wrote:
> >On Fri, Mar 18, 2011 at 10:21:24AM -0500, [email protected] wrote:
> >> +#include <linux/suspend.h>
> >> +#include <linux/clk.h>
> >> +#include <asm/mach/map.h>
> >> +#include <asm/cacheflush.h>
> >> +#include <asm/tlb.h>
> >> +#include <mach/system.h>
> >> +#include "crm_regs.h"
> >
> >Why does the code below require asm/mach/map.h ?
>
> map.h can be replaced by linux/io.h for the __raw_writel().
>
> >Why does it require asm/tlb.h ?
>
> asm/tlb is for the local_flush_tlb_all() call.
I think you want asm/tlbflush.h rather than the tlb shootdown stuff in
asm/tlb.h.