diff options
Diffstat (limited to 'arch/arm/mach-tegra/irq.c')
-rw-r--r-- | arch/arm/mach-tegra/irq.c | 99 |
1 files changed, 95 insertions, 4 deletions
diff --git a/arch/arm/mach-tegra/irq.c b/arch/arm/mach-tegra/irq.c index 4956c3cea73..450295d901d 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-2012, 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 |
@@ -21,12 +21,16 @@ | |||
21 | #include <linux/interrupt.h> | 21 | #include <linux/interrupt.h> |
22 | #include <linux/irq.h> | 22 | #include <linux/irq.h> |
23 | #include <linux/io.h> | 23 | #include <linux/io.h> |
24 | #include <linux/syscore_ops.h> | ||
24 | 25 | ||
25 | #include <asm/hardware/gic.h> | 26 | #include <asm/hardware/gic.h> |
26 | 27 | ||
27 | #include <mach/iomap.h> | 28 | #include <mach/iomap.h> |
29 | #include <mach/legacy_irq.h> | ||
28 | 30 | ||
29 | #include "board.h" | 31 | #include "board.h" |
32 | #include "gic.h" | ||
33 | #include "pm-irq.h" | ||
30 | 34 | ||
31 | #define INT_SYS_NR (INT_GPIO_BASE - INT_PRI_BASE) | 35 | #define INT_SYS_NR (INT_GPIO_BASE - INT_PRI_BASE) |
32 | #define INT_SYS_SZ (INT_SEC_BASE - INT_PRI_BASE) | 36 | #define INT_SYS_SZ (INT_SEC_BASE - INT_PRI_BASE) |
@@ -47,7 +51,7 @@ | |||
47 | #define ICTLR_COP_IER_CLR 0x38 | 51 | #define ICTLR_COP_IER_CLR 0x38 |
48 | #define ICTLR_COP_IEP_CLASS 0x3c | 52 | #define ICTLR_COP_IEP_CLASS 0x3c |
49 | 53 | ||
50 | #define NUM_ICTLRS 4 | 54 | #define NUM_ICTLRS (INT_MAIN_NR/32) |
51 | #define FIRST_LEGACY_IRQ 32 | 55 | #define FIRST_LEGACY_IRQ 32 |
52 | 56 | ||
53 | static void __iomem *ictlr_reg_base[] = { | 57 | static void __iomem *ictlr_reg_base[] = { |
@@ -55,8 +59,17 @@ static void __iomem *ictlr_reg_base[] = { | |||
55 | IO_ADDRESS(TEGRA_SECONDARY_ICTLR_BASE), | 59 | IO_ADDRESS(TEGRA_SECONDARY_ICTLR_BASE), |
56 | IO_ADDRESS(TEGRA_TERTIARY_ICTLR_BASE), | 60 | IO_ADDRESS(TEGRA_TERTIARY_ICTLR_BASE), |
57 | IO_ADDRESS(TEGRA_QUATERNARY_ICTLR_BASE), | 61 | IO_ADDRESS(TEGRA_QUATERNARY_ICTLR_BASE), |
62 | #if (NUM_ICTLRS > 4) | ||
63 | IO_ADDRESS(TEGRA_QUINARY_ICTLR_BASE), | ||
64 | #endif | ||
58 | }; | 65 | }; |
59 | 66 | ||
67 | #ifdef CONFIG_PM_SLEEP | ||
68 | static u32 cop_ier[NUM_ICTLRS]; | ||
69 | static u32 cpu_ier[NUM_ICTLRS]; | ||
70 | static u32 cpu_iep[NUM_ICTLRS]; | ||
71 | #endif | ||
72 | |||
60 | static inline void tegra_irq_write_mask(unsigned int irq, unsigned long reg) | 73 | static inline void tegra_irq_write_mask(unsigned int irq, unsigned long reg) |
61 | { | 74 | { |
62 | void __iomem *base; | 75 | void __iomem *base; |
@@ -113,6 +126,70 @@ static int tegra_retrigger(struct irq_data *d) | |||
113 | return 1; | 126 | return 1; |
114 | } | 127 | } |
115 | 128 | ||
129 | static int tegra_set_type(struct irq_data *d, unsigned int flow_type) | ||
130 | { | ||
131 | return tegra_pm_irq_set_wake_type(d->irq, flow_type); | ||
132 | } | ||
133 | |||
134 | |||
135 | #ifdef CONFIG_PM_SLEEP | ||
136 | static int tegra_set_wake(struct irq_data *d, unsigned int enable) | ||
137 | { | ||
138 | return tegra_pm_irq_set_wake(d->irq, enable); | ||
139 | } | ||
140 | |||
141 | static int tegra_legacy_irq_suspend(void) | ||
142 | { | ||
143 | unsigned long flags; | ||
144 | int i; | ||
145 | |||
146 | local_irq_save(flags); | ||
147 | for (i = 0; i < NUM_ICTLRS; i++) { | ||
148 | void __iomem *ictlr = ictlr_reg_base[i]; | ||
149 | cpu_ier[i] = readl(ictlr + ICTLR_CPU_IER); | ||
150 | cpu_iep[i] = readl(ictlr + ICTLR_CPU_IEP_CLASS); | ||
151 | cop_ier[i] = readl(ictlr + ICTLR_COP_IER); | ||
152 | writel(~0, ictlr + ICTLR_COP_IER_CLR); | ||
153 | } | ||
154 | local_irq_restore(flags); | ||
155 | |||
156 | return 0; | ||
157 | } | ||
158 | |||
159 | static void tegra_legacy_irq_resume(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 | writel(cpu_iep[i], ictlr + ICTLR_CPU_IEP_CLASS); | ||
168 | writel(~0ul, ictlr + ICTLR_CPU_IER_CLR); | ||
169 | writel(cpu_ier[i], ictlr + ICTLR_CPU_IER_SET); | ||
170 | writel(0, ictlr + ICTLR_COP_IEP_CLASS); | ||
171 | writel(~0ul, ictlr + ICTLR_COP_IER_CLR); | ||
172 | writel(cop_ier[i], ictlr + ICTLR_COP_IER_SET); | ||
173 | } | ||
174 | local_irq_restore(flags); | ||
175 | } | ||
176 | |||
177 | static struct syscore_ops tegra_legacy_irq_syscore_ops = { | ||
178 | .suspend = tegra_legacy_irq_suspend, | ||
179 | .resume = tegra_legacy_irq_resume, | ||
180 | }; | ||
181 | |||
182 | static int tegra_legacy_irq_syscore_init(void) | ||
183 | { | ||
184 | register_syscore_ops(&tegra_legacy_irq_syscore_ops); | ||
185 | |||
186 | return 0; | ||
187 | } | ||
188 | subsys_initcall(tegra_legacy_irq_syscore_init); | ||
189 | #else | ||
190 | #define tegra_set_wake NULL | ||
191 | #endif | ||
192 | |||
116 | void __init tegra_init_irq(void) | 193 | void __init tegra_init_irq(void) |
117 | { | 194 | { |
118 | int i; | 195 | int i; |
@@ -121,6 +198,7 @@ void __init tegra_init_irq(void) | |||
121 | void __iomem *ictlr = ictlr_reg_base[i]; | 198 | void __iomem *ictlr = ictlr_reg_base[i]; |
122 | writel(~0, ictlr + ICTLR_CPU_IER_CLR); | 199 | writel(~0, ictlr + ICTLR_CPU_IER_CLR); |
123 | writel(0, ictlr + ICTLR_CPU_IEP_CLASS); | 200 | writel(0, ictlr + ICTLR_CPU_IEP_CLASS); |
201 | writel(~0, ictlr + ICTLR_CPU_IEP_FIR_CLR); | ||
124 | } | 202 | } |
125 | 203 | ||
126 | gic_arch_extn.irq_ack = tegra_ack; | 204 | gic_arch_extn.irq_ack = tegra_ack; |
@@ -128,7 +206,20 @@ void __init tegra_init_irq(void) | |||
128 | gic_arch_extn.irq_mask = tegra_mask; | 206 | gic_arch_extn.irq_mask = tegra_mask; |
129 | gic_arch_extn.irq_unmask = tegra_unmask; | 207 | gic_arch_extn.irq_unmask = tegra_unmask; |
130 | gic_arch_extn.irq_retrigger = tegra_retrigger; | 208 | gic_arch_extn.irq_retrigger = tegra_retrigger; |
209 | gic_arch_extn.irq_set_type = tegra_set_type; | ||
210 | gic_arch_extn.irq_set_wake = tegra_set_wake; | ||
211 | gic_arch_extn.flags = IRQCHIP_MASK_ON_SUSPEND; | ||
212 | |||
213 | tegra_gic_init(); | ||
214 | } | ||
131 | 215 | ||
132 | gic_init(0, 29, IO_ADDRESS(TEGRA_ARM_INT_DIST_BASE), | 216 | void tegra_init_legacy_irq_cop(void) |
133 | IO_ADDRESS(TEGRA_ARM_PERIF_BASE + 0x100)); | 217 | { |
218 | int i; | ||
219 | |||
220 | for (i = 0; i < NUM_ICTLRS; i++) { | ||
221 | void __iomem *ictlr = ictlr_reg_base[i]; | ||
222 | writel(~0, ictlr + ICTLR_COP_IER_CLR); | ||
223 | writel(0, ictlr + ICTLR_COP_IEP_CLASS); | ||
224 | } | ||
134 | } | 225 | } |