From patchwork Fri Sep 30 06:37:22 2011 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Jason Wang X-Patchwork-Id: 117037 Return-Path: X-Original-To: incoming-imx@patchwork.ozlabs.org Delivered-To: patchwork-incoming-imx@bilbo.ozlabs.org Received: from merlin.infradead.org (merlin.infradead.org [IPv6:2001:4978:20e::2]) (using TLSv1 with cipher DHE-RSA-AES256-SHA (256/256 bits)) (Client did not present a certificate) by ozlabs.org (Postfix) with ESMTPS id B9E93100935 for ; Fri, 30 Sep 2011 16:37:44 +1000 (EST) Received: from canuck.infradead.org ([2001:4978:20e::1]) by merlin.infradead.org with esmtps (Exim 4.76 #1 (Red Hat Linux)) id 1R9Wiy-0001h2-VD; Fri, 30 Sep 2011 06:37:33 +0000 Received: from localhost ([127.0.0.1] helo=canuck.infradead.org) by canuck.infradead.org with esmtp (Exim 4.76 #1 (Red Hat Linux)) id 1R9Wiy-0004oG-Ii; Fri, 30 Sep 2011 06:37:32 +0000 Received: from mail.windriver.com ([147.11.1.11]) by canuck.infradead.org with esmtps (Exim 4.76 #1 (Red Hat Linux)) id 1R9Wiu-0004nx-Px for linux-arm-kernel@lists.infradead.org; Fri, 30 Sep 2011 06:37:30 +0000 Received: from ALA-HCA.corp.ad.wrs.com (ala-hca [147.11.189.40]) by mail.windriver.com (8.14.3/8.14.3) with ESMTP id p8U6bM2r008172 (version=TLSv1/SSLv3 cipher=AES128-SHA bits=128 verify=FAIL); Thu, 29 Sep 2011 23:37:22 -0700 (PDT) Received: from localhost.localdomain (128.224.163.220) by ALA-HCA.corp.ad.wrs.com (147.11.189.50) with Microsoft SMTP Server id 14.1.255.0; Thu, 29 Sep 2011 23:37:21 -0700 From: Hui Wang To: , , Subject: [PATCH] mx5: modify pm and idle Date: Fri, 30 Sep 2011 14:37:22 +0800 Message-ID: <1317364642-22956-1-git-send-email-jason77.wang@gmail.com> X-Mailer: git-send-email 1.5.6.5 MIME-Version: 1.0 X-CRM114-Version: 20090807-BlameThorstenAndJenny ( TRE 0.7.6 (BSD) ) MR-646709E3 X-CRM114-CacheID: sfid-20110930_023729_020687_7DFE77F2 X-CRM114-Status: GOOD ( 19.47 ) X-Spam-Score: 0.5 (/) X-Spam-Report: SpamAssassin version 3.3.1 on canuck.infradead.org summary: Content analysis details: (0.5 points) pts rule name description ---- ---------------------- -------------------------------------------------- 0.0 FREEMAIL_FROM Sender email is commonly abused enduser mail provider (jason77.wang[at]gmail.com) 0.0 DKIM_ADSP_CUSTOM_MED No valid author signature, adsp_override is CUSTOM_MED -0.7 RCVD_IN_DNSWL_LOW RBL: Sender listed at http://www.dnswl.org/, low trust [147.11.1.11 listed in list.dnswl.org] 1.2 NML_ADSP_CUSTOM_MED ADSP custom_med hit, and not from a mailing list Cc: linux-arm-kernel@lists.infradead.org X-BeenThere: linux-arm-kernel@lists.infradead.org X-Mailman-Version: 2.1.12 Precedence: list List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Sender: linux-arm-kernel-bounces@lists.infradead.org Errors-To: linux-arm-kernel-bounces+incoming-imx=patchwork.ozlabs.org@lists.infradead.org List-Id: linux-imx-kernel.lists.patchwork.ozlabs.org Two problems exist in the current i.MX5 pm suspend/resume and idle functions. The first is the current i.MX5 suspend routine will call tzic_enable_wake(1) to set wake source, this will set all enabled irq as wake source rather than those wake capable. The second is i.MX5 idle will call mx5_cpu_lp_set() to prepare enter low power mode, but it forgets to call wfi instruction to enter this mode. To fix these two problems, using generic irq chip pm interface and adding a new function mx5_arch_idle(). Signed-off-by: Hui Wang Tested-by: Shawn Guo --- This patch is basing on the latest imx-features branch. This patch is validated on the i.MX51 PDK board (CPU revision 2.0). Since both pm suspend/resume and idle has close relation with mx5_cpu_lp_set() and tzic_enable_wake(), i choose to use one patch instead of independent two to address existing problems. arch/arm/mach-mx5/system.c | 24 +++++++++++++++-- arch/arm/plat-mxc/include/mach/mxc.h | 2 +- arch/arm/plat-mxc/include/mach/system.h | 3 +- arch/arm/plat-mxc/tzic.c | 42 ++++++++++++++++++++++--------- 4 files changed, 54 insertions(+), 17 deletions(-) diff --git a/arch/arm/mach-mx5/system.c b/arch/arm/mach-mx5/system.c index 76ae8dc..92bf341 100644 --- a/arch/arm/mach-mx5/system.c +++ b/arch/arm/mach-mx5/system.c @@ -10,11 +10,17 @@ * http://www.opensource.org/licenses/gpl-license.html * http://www.gnu.org/copyleft/gpl.html */ +#include +#include #include #include #include +#include + #include "crm_regs.h" +static struct clk *gpc_dvfs_clk; + /* 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) @@ -54,9 +60,6 @@ void mx5_cpu_lp_set(enum mxc_cpu_pwr_mode mode) 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; @@ -82,3 +85,18 @@ void mx5_cpu_lp_set(enum mxc_cpu_pwr_mode mode) __raw_writel(empgc1, MXC_SRPG_EMPGC1_SRPGCR); } } + +void mx5_arch_idle(void) +{ + if (gpc_dvfs_clk == NULL) + gpc_dvfs_clk = clk_get(NULL, "gpc_dvfs"); + + /* gpc clock is needed for SRPG */ + clk_enable(gpc_dvfs_clk); + mx5_cpu_lp_set(WAIT_UNCLOCKED_POWER_OFF); + if (tzic_enable_wake() != 0) + goto exit; + cpu_do_idle(); +exit: + clk_disable(gpc_dvfs_clk); +} diff --git a/arch/arm/plat-mxc/include/mach/mxc.h b/arch/arm/plat-mxc/include/mach/mxc.h index 0987923..c4d324a 100644 --- a/arch/arm/plat-mxc/include/mach/mxc.h +++ b/arch/arm/plat-mxc/include/mach/mxc.h @@ -182,7 +182,7 @@ struct cpu_op { u32 cpu_rate; }; -int tzic_enable_wake(int is_idle); +int tzic_enable_wake(void); enum mxc_cpu_pwr_mode { WAIT_CLOCKED, /* wfi only */ WAIT_UNCLOCKED, /* WAIT */ diff --git a/arch/arm/plat-mxc/include/mach/system.h b/arch/arm/plat-mxc/include/mach/system.h index 51f02a9..5b6f991 100644 --- a/arch/arm/plat-mxc/include/mach/system.h +++ b/arch/arm/plat-mxc/include/mach/system.h @@ -21,6 +21,7 @@ #include extern void mx5_cpu_lp_set(enum mxc_cpu_pwr_mode mode); +extern void mx5_arch_idle(void); static inline void arch_idle(void) { @@ -51,7 +52,7 @@ static inline void arch_idle(void) "mcr p15, 0, %0, c1, c0, 0\n" : "=r" (reg)); } else if (cpu_is_mx51()) - mx5_cpu_lp_set(WAIT_UNCLOCKED_POWER_OFF); + mx5_arch_idle(); else cpu_do_idle(); } diff --git a/arch/arm/plat-mxc/tzic.c b/arch/arm/plat-mxc/tzic.c index e993a18..bd73910 100644 --- a/arch/arm/plat-mxc/tzic.c +++ b/arch/arm/plat-mxc/tzic.c @@ -72,14 +72,35 @@ static int tzic_set_irq_fiq(unsigned int irq, unsigned int type) #define tzic_set_irq_fiq NULL #endif -static unsigned int *wakeup_intr[4]; - static struct mxc_extra_irq tzic_extra_irq = { #ifdef CONFIG_FIQ .set_irq_fiq = tzic_set_irq_fiq, #endif }; +#ifdef CONFIG_PM +static void tzic_irq_suspend(struct irq_data *d) +{ + struct irq_chip_generic *gc = irq_data_get_irq_chip_data(d); + int idx = gc->irq_base >> 5; + + __raw_writel(gc->wake_active, tzic_base + TZIC_WAKEUP0(idx)); +} + +static void tzic_irq_resume(struct irq_data *d) +{ + struct irq_chip_generic *gc = irq_data_get_irq_chip_data(d); + int idx = gc->irq_base >> 5; + + __raw_writel(__raw_readl(tzic_base + TZIC_ENSET0(idx)), + tzic_base + TZIC_WAKEUP0(idx)); +} + +#else +#define tzic_irq_suspend NULL +#define tzic_irq_resume NULL +#endif + static __init void tzic_init_gc(unsigned int irq_start) { struct irq_chip_generic *gc; @@ -90,12 +111,13 @@ static __init void tzic_init_gc(unsigned int irq_start) handle_level_irq); gc->private = &tzic_extra_irq; gc->wake_enabled = IRQ_MSK(32); - wakeup_intr[idx] = &gc->wake_active; ct = gc->chip_types; ct->chip.irq_mask = irq_gc_mask_disable_reg; ct->chip.irq_unmask = irq_gc_unmask_enable_reg; ct->chip.irq_set_wake = irq_gc_set_wake; + ct->chip.irq_suspend = tzic_irq_suspend; + ct->chip.irq_resume = tzic_irq_resume; ct->regs.disable = TZIC_ENCLEAR0(idx); ct->regs.enable = TZIC_ENSET0(idx); @@ -166,23 +188,19 @@ void __init tzic_init_irq(void __iomem *irqbase) /** * tzic_enable_wake() - enable wakeup interrupt * - * @param is_idle 1 if called in idle loop (ENSET0 register); - * 0 to be used when called from low power entry * @return 0 if successful; non-zero otherwise */ -int tzic_enable_wake(int is_idle) +int tzic_enable_wake(void) { - unsigned int i, v; + unsigned int i; __raw_writel(1, tzic_base + TZIC_DSMINT); if (unlikely(__raw_readl(tzic_base + TZIC_DSMINT) == 0)) return -EAGAIN; - for (i = 0; i < 4; i++) { - v = is_idle ? __raw_readl(tzic_base + TZIC_ENSET0(i)) : - *wakeup_intr[i]; - __raw_writel(v, tzic_base + TZIC_WAKEUP0(i)); - } + for (i = 0; i < 4; i++) + __raw_writel(__raw_readl(tzic_base + TZIC_ENSET0(i)), + tzic_base + TZIC_WAKEUP0(i)); return 0; }