diff options
| author | Joseph Lo <josephl@nvidia.com> | 2013-04-03 07:31:45 -0400 |
|---|---|---|
| committer | Stephen Warren <swarren@nvidia.com> | 2013-04-03 16:31:32 -0400 |
| commit | e307cc8941fc420f008e1f3cb86e16a4269aa2af (patch) | |
| tree | 7843b95d6e5e662da17289e2fc1eaecc5106be9b | |
| parent | 203f31cb86eb6aa4c49711e7ca25a7660efc39b8 (diff) | |
ARM: tegra: irq: add wake up handling
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 <vwadekar@nvidia.com>
Signed-off-by: Joseph Lo <josephl@nvidia.com>
Signed-off-by: Stephen Warren <swarren@nvidia.com>
| -rw-r--r-- | arch/arm/mach-tegra/common.c | 2 | ||||
| -rw-r--r-- | arch/arm/mach-tegra/irq.c | 96 | ||||
| -rw-r--r-- | arch/arm/mach-tegra/irq.h | 6 |
3 files changed, 103 insertions, 1 deletions
diff --git a/arch/arm/mach-tegra/common.c b/arch/arm/mach-tegra/common.c index b02ebe767e7f..c84505c1f644 100644 --- a/arch/arm/mach-tegra/common.c +++ b/arch/arm/mach-tegra/common.c | |||
| @@ -33,6 +33,7 @@ | |||
| 33 | #include "common.h" | 33 | #include "common.h" |
| 34 | #include "fuse.h" | 34 | #include "fuse.h" |
| 35 | #include "iomap.h" | 35 | #include "iomap.h" |
| 36 | #include "irq.h" | ||
| 36 | #include "pmc.h" | 37 | #include "pmc.h" |
| 37 | #include "apbio.h" | 38 | #include "apbio.h" |
| 38 | #include "sleep.h" | 39 | #include "sleep.h" |
| @@ -64,6 +65,7 @@ void __init tegra_dt_init_irq(void) | |||
| 64 | tegra_pmc_init(); | 65 | tegra_pmc_init(); |
| 65 | tegra_init_irq(); | 66 | tegra_init_irq(); |
| 66 | irqchip_init(); | 67 | irqchip_init(); |
| 68 | tegra_legacy_irq_syscore_init(); | ||
| 67 | } | 69 | } |
| 68 | #endif | 70 | #endif |
| 69 | 71 | ||
diff --git a/arch/arm/mach-tegra/irq.c b/arch/arm/mach-tegra/irq.c index 1952e82797cc..0de4eed1493d 100644 --- a/arch/arm/mach-tegra/irq.c +++ b/arch/arm/mach-tegra/irq.c | |||
| @@ -4,7 +4,7 @@ | |||
| 4 | * Author: | 4 | * Author: |
| 5 | * Colin Cross <ccross@android.com> | 5 | * Colin Cross <ccross@android.com> |
| 6 | * | 6 | * |
| 7 | * Copyright (C) 2010, NVIDIA Corporation | 7 | * Copyright (C) 2010,2013, NVIDIA Corporation |
| 8 | * | 8 | * |
| 9 | * This software is licensed under the terms of the GNU General Public | 9 | * This software is licensed under the terms of the GNU General Public |
| 10 | * License version 2, as published by the Free Software Foundation, and | 10 | * License version 2, as published by the Free Software Foundation, and |
| @@ -23,6 +23,7 @@ | |||
| 23 | #include <linux/io.h> | 23 | #include <linux/io.h> |
| 24 | #include <linux/of.h> | 24 | #include <linux/of.h> |
| 25 | #include <linux/irqchip/arm-gic.h> | 25 | #include <linux/irqchip/arm-gic.h> |
| 26 | #include <linux/syscore_ops.h> | ||
| 26 | 27 | ||
| 27 | #include "board.h" | 28 | #include "board.h" |
| 28 | #include "iomap.h" | 29 | #include "iomap.h" |
| @@ -43,6 +44,7 @@ | |||
| 43 | #define ICTLR_COP_IEP_CLASS 0x3c | 44 | #define ICTLR_COP_IEP_CLASS 0x3c |
| 44 | 45 | ||
| 45 | #define FIRST_LEGACY_IRQ 32 | 46 | #define FIRST_LEGACY_IRQ 32 |
| 47 | #define TEGRA_MAX_NUM_ICTLRS 5 | ||
| 46 | 48 | ||
| 47 | #define SGI_MASK 0xFFFF | 49 | #define SGI_MASK 0xFFFF |
| 48 | 50 | ||
| @@ -56,6 +58,15 @@ static void __iomem *ictlr_reg_base[] = { | |||
| 56 | IO_ADDRESS(TEGRA_QUINARY_ICTLR_BASE), | 58 | IO_ADDRESS(TEGRA_QUINARY_ICTLR_BASE), |
| 57 | }; | 59 | }; |
| 58 | 60 | ||
| 61 | #ifdef CONFIG_PM_SLEEP | ||
| 62 | static u32 cop_ier[TEGRA_MAX_NUM_ICTLRS]; | ||
| 63 | static u32 cop_iep[TEGRA_MAX_NUM_ICTLRS]; | ||
| 64 | static u32 cpu_ier[TEGRA_MAX_NUM_ICTLRS]; | ||
| 65 | static u32 cpu_iep[TEGRA_MAX_NUM_ICTLRS]; | ||
| 66 | |||
| 67 | static u32 ictlr_wake_mask[TEGRA_MAX_NUM_ICTLRS]; | ||
| 68 | #endif | ||
| 69 | |||
| 59 | bool tegra_pending_sgi(void) | 70 | bool tegra_pending_sgi(void) |
| 60 | { | 71 | { |
| 61 | u32 pending_set; | 72 | u32 pending_set; |
| @@ -125,6 +136,87 @@ static int tegra_retrigger(struct irq_data *d) | |||
| 125 | return 1; | 136 | return 1; |
| 126 | } | 137 | } |
| 127 | 138 | ||
| 139 | #ifdef CONFIG_PM_SLEEP | ||
| 140 | static int tegra_set_wake(struct irq_data *d, unsigned int enable) | ||
| 141 | { | ||
| 142 | u32 irq = d->irq; | ||
| 143 | u32 index, mask; | ||
| 144 | |||
| 145 | if (irq < FIRST_LEGACY_IRQ || | ||
| 146 | irq >= FIRST_LEGACY_IRQ + num_ictlrs * 32) | ||
| 147 | return -EINVAL; | ||
| 148 | |||
| 149 | index = ((irq - FIRST_LEGACY_IRQ) / 32); | ||
| 150 | mask = BIT((irq - FIRST_LEGACY_IRQ) % 32); | ||
| 151 | if (enable) | ||
| 152 | ictlr_wake_mask[index] |= mask; | ||
| 153 | else | ||
| 154 | ictlr_wake_mask[index] &= ~mask; | ||
| 155 | |||
| 156 | return 0; | ||
| 157 | } | ||
| 158 | |||
| 159 | static int tegra_legacy_irq_suspend(void) | ||
| 160 | { | ||
| 161 | unsigned long flags; | ||
| 162 | int i; | ||
| 163 | |||
| 164 | local_irq_save(flags); | ||
| 165 | for (i = 0; i < num_ictlrs; i++) { | ||
| 166 | void __iomem *ictlr = ictlr_reg_base[i]; | ||
| 167 | /* Save interrupt state */ | ||
| 168 | cpu_ier[i] = readl_relaxed(ictlr + ICTLR_CPU_IER); | ||
| 169 | cpu_iep[i] = readl_relaxed(ictlr + ICTLR_CPU_IEP_CLASS); | ||
| 170 | cop_ier[i] = readl_relaxed(ictlr + ICTLR_COP_IER); | ||
| 171 | cop_iep[i] = readl_relaxed(ictlr + ICTLR_COP_IEP_CLASS); | ||
| 172 | |||
| 173 | /* Disable COP interrupts */ | ||
| 174 | writel_relaxed(~0ul, ictlr + ICTLR_COP_IER_CLR); | ||
| 175 | |||
| 176 | /* Disable CPU interrupts */ | ||
| 177 | writel_relaxed(~0ul, ictlr + ICTLR_CPU_IER_CLR); | ||
| 178 | |||
| 179 | /* Enable the wakeup sources of ictlr */ | ||
| 180 | writel_relaxed(ictlr_wake_mask[i], ictlr + ICTLR_CPU_IER_SET); | ||
| 181 | } | ||
| 182 | local_irq_restore(flags); | ||
| 183 | |||
| 184 | return 0; | ||
| 185 | } | ||
| 186 | |||
| 187 | static void tegra_legacy_irq_resume(void) | ||
| 188 | { | ||
| 189 | unsigned long flags; | ||
| 190 | int i; | ||
| 191 | |||
| 192 | local_irq_save(flags); | ||
| 193 | for (i = 0; i < num_ictlrs; i++) { | ||
| 194 | void __iomem *ictlr = ictlr_reg_base[i]; | ||
| 195 | writel_relaxed(cpu_iep[i], ictlr + ICTLR_CPU_IEP_CLASS); | ||
| 196 | writel_relaxed(~0ul, ictlr + ICTLR_CPU_IER_CLR); | ||
| 197 | writel_relaxed(cpu_ier[i], ictlr + ICTLR_CPU_IER_SET); | ||
| 198 | writel_relaxed(cop_iep[i], ictlr + ICTLR_COP_IEP_CLASS); | ||
| 199 | writel_relaxed(~0ul, ictlr + ICTLR_COP_IER_CLR); | ||
| 200 | writel_relaxed(cop_ier[i], ictlr + ICTLR_COP_IER_SET); | ||
| 201 | } | ||
| 202 | local_irq_restore(flags); | ||
| 203 | } | ||
| 204 | |||
| 205 | static struct syscore_ops tegra_legacy_irq_syscore_ops = { | ||
| 206 | .suspend = tegra_legacy_irq_suspend, | ||
| 207 | .resume = tegra_legacy_irq_resume, | ||
| 208 | }; | ||
| 209 | |||
| 210 | int tegra_legacy_irq_syscore_init(void) | ||
| 211 | { | ||
| 212 | register_syscore_ops(&tegra_legacy_irq_syscore_ops); | ||
| 213 | |||
| 214 | return 0; | ||
| 215 | } | ||
| 216 | #else | ||
| 217 | #define tegra_set_wake NULL | ||
| 218 | #endif | ||
| 219 | |||
| 128 | void __init tegra_init_irq(void) | 220 | void __init tegra_init_irq(void) |
| 129 | { | 221 | { |
| 130 | int i; | 222 | int i; |
| @@ -150,6 +242,8 @@ void __init tegra_init_irq(void) | |||
| 150 | gic_arch_extn.irq_mask = tegra_mask; | 242 | gic_arch_extn.irq_mask = tegra_mask; |
| 151 | gic_arch_extn.irq_unmask = tegra_unmask; | 243 | gic_arch_extn.irq_unmask = tegra_unmask; |
| 152 | gic_arch_extn.irq_retrigger = tegra_retrigger; | 244 | gic_arch_extn.irq_retrigger = tegra_retrigger; |
| 245 | gic_arch_extn.irq_set_wake = tegra_set_wake; | ||
| 246 | gic_arch_extn.flags = IRQCHIP_MASK_ON_SUSPEND; | ||
| 153 | 247 | ||
| 154 | /* | 248 | /* |
| 155 | * Check if there is a devicetree present, since the GIC will be | 249 | * 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 5142649bba05..bc05ce5613fb 100644 --- a/arch/arm/mach-tegra/irq.h +++ b/arch/arm/mach-tegra/irq.h | |||
| @@ -19,4 +19,10 @@ | |||
| 19 | 19 | ||
| 20 | bool tegra_pending_sgi(void); | 20 | bool tegra_pending_sgi(void); |
| 21 | 21 | ||
| 22 | #ifdef CONFIG_PM_SLEEP | ||
| 23 | int tegra_legacy_irq_syscore_init(void); | ||
| 24 | #else | ||
| 25 | static inline int tegra_legacy_irq_syscore_init(void) { return 0; } | ||
| 26 | #endif | ||
| 27 | |||
| 22 | #endif | 28 | #endif |
