From patchwork Tue Mar 12 04:02:23 2013 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Joseph Lo X-Patchwork-Id: 2252741 Return-Path: X-Original-To: patchwork-linux-arm@patchwork.kernel.org Delivered-To: patchwork-process-083081@patchwork1.kernel.org Received: from merlin.infradead.org (merlin.infradead.org [205.233.59.134]) by patchwork1.kernel.org (Postfix) with ESMTP id 4D73F3FCF6 for ; Tue, 12 Mar 2013 04:05:37 +0000 (UTC) Received: from localhost ([::1] helo=merlin.infradead.org) by merlin.infradead.org with esmtp (Exim 4.80.1 #2 (Red Hat Linux)) id 1UFGQ7-0005w2-VW; Tue, 12 Mar 2013 04:02:36 +0000 Received: from hqemgate04.nvidia.com ([216.228.121.35]) by merlin.infradead.org with esmtps (Exim 4.80.1 #2 (Red Hat Linux)) id 1UFGQ2-0005ug-F4 for linux-arm-kernel@lists.infradead.org; Tue, 12 Mar 2013 04:02:31 +0000 Received: from hqnvupgp07.nvidia.com (Not Verified[216.228.121.13]) by hqemgate04.nvidia.com id ; Mon, 11 Mar 2013 21:02:25 -0700 Received: from hqemhub03.nvidia.com ([172.17.108.22]) by hqnvupgp07.nvidia.com (PGP Universal service); Mon, 11 Mar 2013 21:02:29 -0700 X-PGP-Universal: processed; by hqnvupgp07.nvidia.com on Mon, 11 Mar 2013 21:02:29 -0700 Received: from jlo-ubuntu-64.nvidia.com (172.20.144.16) by hqemhub03.nvidia.com (172.20.150.15) with Microsoft SMTP Server (TLS) id 8.3.298.1; Mon, 11 Mar 2013 21:02:28 -0700 From: Joseph Lo To: Stephen Warren Subject: [PATCH V2 2/9] ARM: tegra: irq: add wake up handling Date: Tue, 12 Mar 2013 12:02:23 +0800 Message-ID: <1363060943-9070-1-git-send-email-josephl@nvidia.com> X-Mailer: git-send-email 1.8.1.5 X-NVConfidentiality: public MIME-Version: 1.0 X-CRM114-Version: 20100106-BlameMichelson ( TRE 0.8.0 (BSD) ) MR-646709E3 X-CRM114-CacheID: sfid-20130312_000230_712783_E6888DC9 X-CRM114-Status: GOOD ( 18.17 ) X-Spam-Score: -9.3 (---------) X-Spam-Report: SpamAssassin version 3.3.2 on merlin.infradead.org summary: Content analysis details: (-9.3 points) pts rule name description ---- ---------------------- -------------------------------------------------- -5.0 RCVD_IN_DNSWL_HI RBL: Sender listed at http://www.dnswl.org/, high trust [216.228.121.35 listed in list.dnswl.org] -0.0 SPF_HELO_PASS SPF: HELO matches SPF record -0.0 SPF_PASS SPF: sender matches SPF record -2.4 RP_MATCHES_RCVD Envelope sender domain matches handover relay domain -1.9 BAYES_00 BODY: Bayes spam probability is 0 to 1% [score: 0.0000] Cc: linux-tegra@vger.kernel.org, linux-arm-kernel@lists.infradead.org, Joseph Lo X-BeenThere: linux-arm-kernel@lists.infradead.org X-Mailman-Version: 2.1.15 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Sender: "linux-arm-kernel" Errors-To: linux-arm-kernel-bounces+patchwork-linux-arm=patchwork.kernel.org@lists.infradead.org Add the wake up handling for legacy irq controller, and using IRQCHIP_MASK_ON_SUSPEND for wake irq handling. Based on the work by: Varun Wadekar Signed-off-by: Joseph Lo --- V2: * no change --- arch/arm/mach-tegra/common.c | 2 + arch/arm/mach-tegra/irq.c | 95 +++++++++++++++++++++++++++++++++++++++++++- arch/arm/mach-tegra/irq.h | 6 +++ 3 files changed, 102 insertions(+), 1 deletion(-) diff --git a/arch/arm/mach-tegra/common.c b/arch/arm/mach-tegra/common.c index f0315c9..bc7268a 100644 --- a/arch/arm/mach-tegra/common.c +++ b/arch/arm/mach-tegra/common.c @@ -33,6 +33,7 @@ #include "common.h" #include "fuse.h" #include "iomap.h" +#include "irq.h" #include "pmc.h" #include "apbio.h" #include "sleep.h" @@ -63,6 +64,7 @@ void __init tegra_dt_init_irq(void) tegra_clocks_init(); tegra_init_irq(); irqchip_init(); + tegra_legacy_irq_syscore_init(); } #endif diff --git a/arch/arm/mach-tegra/irq.c b/arch/arm/mach-tegra/irq.c index 1952e82..efa85ef 100644 --- a/arch/arm/mach-tegra/irq.c +++ b/arch/arm/mach-tegra/irq.c @@ -4,7 +4,7 @@ * Author: * Colin Cross * - * Copyright (C) 2010, NVIDIA Corporation + * Copyright (C) 2010,2013, NVIDIA Corporation * * This software is licensed under the terms of the GNU General Public * License version 2, as published by the Free Software Foundation, and @@ -23,6 +23,7 @@ #include #include #include +#include #include "board.h" #include "iomap.h" @@ -43,6 +44,7 @@ #define ICTLR_COP_IEP_CLASS 0x3c #define FIRST_LEGACY_IRQ 32 +#define TEGRA_MAX_NUM_ICTLRS 5 #define SGI_MASK 0xFFFF @@ -56,6 +58,15 @@ static void __iomem *ictlr_reg_base[] = { IO_ADDRESS(TEGRA_QUINARY_ICTLR_BASE), }; +#ifdef CONFIG_PM_SLEEP +static u32 cop_ier[TEGRA_MAX_NUM_ICTLRS]; +static u32 cop_iep[TEGRA_MAX_NUM_ICTLRS]; +static u32 cpu_ier[TEGRA_MAX_NUM_ICTLRS]; +static u32 cpu_iep[TEGRA_MAX_NUM_ICTLRS]; + +static u32 ictlr_wake_mask[TEGRA_MAX_NUM_ICTLRS]; +#endif + bool tegra_pending_sgi(void) { u32 pending_set; @@ -125,6 +136,86 @@ static int tegra_retrigger(struct irq_data *d) return 1; } +#ifdef CONFIG_PM_SLEEP +static int tegra_set_wake(struct irq_data *d, unsigned int enable) +{ + u32 irq = d->irq; + u32 index, mask; + + BUG_ON(irq < FIRST_LEGACY_IRQ || + irq >= FIRST_LEGACY_IRQ + num_ictlrs * 32); + + index = ((irq - FIRST_LEGACY_IRQ) / 32); + mask = BIT((irq - FIRST_LEGACY_IRQ) % 32); + if (enable) + ictlr_wake_mask[index] |= mask; + else + ictlr_wake_mask[index] &= ~mask; + + return 0; +} + +static int tegra_legacy_irq_suspend(void) +{ + unsigned long flags; + int i; + + local_irq_save(flags); + for (i = 0; i < num_ictlrs; i++) { + void __iomem *ictlr = ictlr_reg_base[i]; + /* Save interrupt state */ + cpu_ier[i] = readl_relaxed(ictlr + ICTLR_CPU_IER); + cpu_iep[i] = readl_relaxed(ictlr + ICTLR_CPU_IEP_CLASS); + cop_ier[i] = readl_relaxed(ictlr + ICTLR_COP_IER); + cop_iep[i] = readl_relaxed(ictlr + ICTLR_COP_IEP_CLASS); + + /* Disable COP interrupts */ + writel_relaxed(~0ul, ictlr + ICTLR_COP_IER_CLR); + + /* Disable CPU interrupts */ + writel_relaxed(~0ul, ictlr + ICTLR_CPU_IER_CLR); + + /* Enable the wakeup sources of ictlr */ + writel_relaxed(ictlr_wake_mask[i], ictlr + ICTLR_CPU_IER_SET); + } + local_irq_restore(flags); + + return 0; +} + +static void tegra_legacy_irq_resume(void) +{ + unsigned long flags; + int i; + + local_irq_save(flags); + for (i = 0; i < num_ictlrs; i++) { + void __iomem *ictlr = ictlr_reg_base[i]; + writel_relaxed(cpu_iep[i], ictlr + ICTLR_CPU_IEP_CLASS); + writel_relaxed(~0ul, ictlr + ICTLR_CPU_IER_CLR); + writel_relaxed(cpu_ier[i], ictlr + ICTLR_CPU_IER_SET); + writel_relaxed(cop_iep[i], ictlr + ICTLR_COP_IEP_CLASS); + writel_relaxed(~0ul, ictlr + ICTLR_COP_IER_CLR); + writel_relaxed(cop_ier[i], ictlr + ICTLR_COP_IER_SET); + } + local_irq_restore(flags); +} + +static struct syscore_ops tegra_legacy_irq_syscore_ops = { + .suspend = tegra_legacy_irq_suspend, + .resume = tegra_legacy_irq_resume, +}; + +int tegra_legacy_irq_syscore_init(void) +{ + register_syscore_ops(&tegra_legacy_irq_syscore_ops); + + return 0; +} +#else +#define tegra_set_wake NULL +#endif + void __init tegra_init_irq(void) { int i; @@ -150,6 +241,8 @@ void __init tegra_init_irq(void) gic_arch_extn.irq_mask = tegra_mask; gic_arch_extn.irq_unmask = tegra_unmask; gic_arch_extn.irq_retrigger = tegra_retrigger; + gic_arch_extn.irq_set_wake = tegra_set_wake; + gic_arch_extn.flags = IRQCHIP_MASK_ON_SUSPEND; /* * Check if there is a devicetree present, since the GIC will be diff --git a/arch/arm/mach-tegra/irq.h b/arch/arm/mach-tegra/irq.h index 5142649..bc05ce5 100644 --- a/arch/arm/mach-tegra/irq.h +++ b/arch/arm/mach-tegra/irq.h @@ -19,4 +19,10 @@ bool tegra_pending_sgi(void); +#ifdef CONFIG_PM_SLEEP +int tegra_legacy_irq_syscore_init(void); +#else +static inline int tegra_legacy_irq_syscore_init(void) { return 0; } +#endif + #endif