957338aef765c06205b8f9ab399f373689f1ea46
[linux-2.6.git] / arch / arm / mach-tegra / irq.c
1 /*
2  * Copyright (C) 2011 Google, Inc.
3  *
4  * Author:
5  *      Colin Cross <ccross@android.com>
6  *
7  * Copyright (C) 2010, NVIDIA Corporation
8  *
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
11  * may be copied, distributed, and modified under those terms.
12  *
13  * This program is distributed in the hope that it will be useful,
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16  * GNU General Public License for more details.
17  *
18  */
19
20 #include <linux/kernel.h>
21 #include <linux/interrupt.h>
22 #include <linux/irq.h>
23 #include <linux/io.h>
24 #include <linux/syscore_ops.h>
25
26 #include <asm/hardware/gic.h>
27
28 #include <mach/iomap.h>
29
30 #include "board.h"
31 #include "pm-irq.h"
32
33 #define INT_SYS_NR      (INT_GPIO_BASE - INT_PRI_BASE)
34 #define INT_SYS_SZ      (INT_SEC_BASE - INT_PRI_BASE)
35 #define PPI_NR          ((INT_SYS_NR+INT_SYS_SZ-1)/INT_SYS_SZ)
36
37 #define ICTLR_CPU_IEP_VFIQ      0x08
38 #define ICTLR_CPU_IEP_FIR       0x14
39 #define ICTLR_CPU_IEP_FIR_SET   0x18
40 #define ICTLR_CPU_IEP_FIR_CLR   0x1c
41
42 #define ICTLR_CPU_IER           0x20
43 #define ICTLR_CPU_IER_SET       0x24
44 #define ICTLR_CPU_IER_CLR       0x28
45 #define ICTLR_CPU_IEP_CLASS     0x2C
46
47 #define ICTLR_COP_IER           0x30
48 #define ICTLR_COP_IER_SET       0x34
49 #define ICTLR_COP_IER_CLR       0x38
50 #define ICTLR_COP_IEP_CLASS     0x3c
51
52 #define NUM_ICTLRS (INT_MAIN_NR/32)
53 #define FIRST_LEGACY_IRQ 32
54
55 static void __iomem *ictlr_reg_base[] = {
56         IO_ADDRESS(TEGRA_PRIMARY_ICTLR_BASE),
57         IO_ADDRESS(TEGRA_SECONDARY_ICTLR_BASE),
58         IO_ADDRESS(TEGRA_TERTIARY_ICTLR_BASE),
59         IO_ADDRESS(TEGRA_QUATERNARY_ICTLR_BASE),
60 #if (NUM_ICTLRS > 4)
61         IO_ADDRESS(TEGRA_QUINARY_ICTLR_BASE),
62 #endif
63 };
64
65 #ifdef CONFIG_PM
66 static u32 cop_ier[NUM_ICTLRS];
67 static u32 cpu_ier[NUM_ICTLRS];
68 static u32 cpu_iep[NUM_ICTLRS];
69 #endif
70
71 static inline void tegra_irq_write_mask(unsigned int irq, unsigned long reg)
72 {
73         void __iomem *base;
74         u32 mask;
75
76         BUG_ON(irq < FIRST_LEGACY_IRQ ||
77                 irq >= FIRST_LEGACY_IRQ + NUM_ICTLRS * 32);
78
79         base = ictlr_reg_base[(irq - FIRST_LEGACY_IRQ) / 32];
80         mask = BIT((irq - FIRST_LEGACY_IRQ) % 32);
81
82         __raw_writel(mask, base + reg);
83 }
84
85 static void tegra_mask(struct irq_data *d)
86 {
87         if (d->irq < FIRST_LEGACY_IRQ)
88                 return;
89
90         tegra_irq_write_mask(d->irq, ICTLR_CPU_IER_CLR);
91 }
92
93 static void tegra_unmask(struct irq_data *d)
94 {
95         if (d->irq < FIRST_LEGACY_IRQ)
96                 return;
97
98         tegra_irq_write_mask(d->irq, ICTLR_CPU_IER_SET);
99 }
100
101 static void tegra_ack(struct irq_data *d)
102 {
103         if (d->irq < FIRST_LEGACY_IRQ)
104                 return;
105
106         tegra_irq_write_mask(d->irq, ICTLR_CPU_IEP_FIR_CLR);
107 }
108
109 static void tegra_eoi(struct irq_data *d)
110 {
111         if (d->irq < FIRST_LEGACY_IRQ)
112                 return;
113
114         tegra_irq_write_mask(d->irq, ICTLR_CPU_IEP_FIR_CLR);
115 }
116
117 static int tegra_retrigger(struct irq_data *d)
118 {
119         if (d->irq < FIRST_LEGACY_IRQ)
120                 return 0;
121
122         tegra_irq_write_mask(d->irq, ICTLR_CPU_IEP_FIR_SET);
123
124         return 1;
125 }
126
127 static int tegra_set_type(struct irq_data *d, unsigned int flow_type)
128 {
129         return tegra_pm_irq_set_wake_type(d->irq, flow_type);
130 }
131
132
133 #ifdef CONFIG_PM
134 static int tegra_set_wake(struct irq_data *d, unsigned int enable)
135 {
136         return tegra_pm_irq_set_wake(d->irq, enable);
137 }
138
139 static int tegra_legacy_irq_suspend(void)
140 {
141         unsigned long flags;
142         int i;
143
144         local_irq_save(flags);
145         for (i = 0; i < NUM_ICTLRS; i++) {
146                 void __iomem *ictlr = ictlr_reg_base[i];
147                 cpu_ier[i] = readl(ictlr + ICTLR_CPU_IER);
148                 cpu_iep[i] = readl(ictlr + ICTLR_CPU_IEP_CLASS);
149                 cop_ier[i] = readl(ictlr + ICTLR_COP_IER);
150                 writel(~0, ictlr + ICTLR_COP_IER_CLR);
151         }
152         local_irq_restore(flags);
153
154         return 0;
155 }
156
157 static void tegra_legacy_irq_resume(void)
158 {
159         unsigned long flags;
160         int i;
161
162         local_irq_save(flags);
163         for (i = 0; i < NUM_ICTLRS; i++) {
164                 void __iomem *ictlr = ictlr_reg_base[i];
165                 writel(cpu_iep[i], ictlr + ICTLR_CPU_IEP_CLASS);
166                 writel(~0ul, ictlr + ICTLR_CPU_IER_CLR);
167                 writel(cpu_ier[i], ictlr + ICTLR_CPU_IER_SET);
168                 writel(0, ictlr + ICTLR_COP_IEP_CLASS);
169                 writel(~0ul, ictlr + ICTLR_COP_IER_CLR);
170                 writel(cop_ier[i], ictlr + ICTLR_COP_IER_SET);
171         }
172         local_irq_restore(flags);
173 }
174
175 static struct syscore_ops tegra_legacy_irq_syscore_ops = {
176         .suspend = tegra_legacy_irq_suspend,
177         .resume = tegra_legacy_irq_resume,
178 };
179
180 static int tegra_legacy_irq_syscore_init(void)
181 {
182         register_syscore_ops(&tegra_legacy_irq_syscore_ops);
183
184         return 0;
185 }
186 subsys_initcall(tegra_legacy_irq_syscore_init);
187 #else
188 #define tegra_set_wake NULL
189 #endif
190
191 void __init tegra_init_irq(void)
192 {
193         int i;
194
195         for (i = 0; i < NUM_ICTLRS; i++) {
196                 void __iomem *ictlr = ictlr_reg_base[i];
197                 writel(~0, ictlr + ICTLR_CPU_IER_CLR);
198                 writel(0, ictlr + ICTLR_CPU_IEP_CLASS);
199         }
200
201         gic_arch_extn.irq_ack = tegra_ack;
202         gic_arch_extn.irq_eoi = tegra_eoi;
203         gic_arch_extn.irq_mask = tegra_mask;
204         gic_arch_extn.irq_unmask = tegra_unmask;
205         gic_arch_extn.irq_retrigger = tegra_retrigger;
206         gic_arch_extn.irq_set_type = tegra_set_type;
207         gic_arch_extn.irq_set_wake = tegra_set_wake;
208         gic_arch_extn.flags = IRQCHIP_MASK_ON_SUSPEND;
209
210         gic_init(0, 29, IO_ADDRESS(TEGRA_ARM_INT_DIST_BASE),
211                  IO_ADDRESS(TEGRA_ARM_PERIF_BASE + 0x100));
212 }