diff options
Diffstat (limited to 'arch/arm/mach-at91/irq.c')
-rw-r--r-- | arch/arm/mach-at91/irq.c | 414 |
1 files changed, 357 insertions, 57 deletions
diff --git a/arch/arm/mach-at91/irq.c b/arch/arm/mach-at91/irq.c index cfcfcbe36269..1e02c0e49dcc 100644 --- a/arch/arm/mach-at91/irq.c +++ b/arch/arm/mach-at91/irq.c | |||
@@ -23,6 +23,7 @@ | |||
23 | #include <linux/init.h> | 23 | #include <linux/init.h> |
24 | #include <linux/module.h> | 24 | #include <linux/module.h> |
25 | #include <linux/mm.h> | 25 | #include <linux/mm.h> |
26 | #include <linux/bitmap.h> | ||
26 | #include <linux/types.h> | 27 | #include <linux/types.h> |
27 | #include <linux/irq.h> | 28 | #include <linux/irq.h> |
28 | #include <linux/of.h> | 29 | #include <linux/of.h> |
@@ -30,38 +31,218 @@ | |||
30 | #include <linux/of_irq.h> | 31 | #include <linux/of_irq.h> |
31 | #include <linux/irqdomain.h> | 32 | #include <linux/irqdomain.h> |
32 | #include <linux/err.h> | 33 | #include <linux/err.h> |
34 | #include <linux/slab.h> | ||
33 | 35 | ||
34 | #include <mach/hardware.h> | 36 | #include <mach/hardware.h> |
35 | #include <asm/irq.h> | 37 | #include <asm/irq.h> |
36 | #include <asm/setup.h> | 38 | #include <asm/setup.h> |
37 | 39 | ||
40 | #include <asm/exception.h> | ||
38 | #include <asm/mach/arch.h> | 41 | #include <asm/mach/arch.h> |
39 | #include <asm/mach/irq.h> | 42 | #include <asm/mach/irq.h> |
40 | #include <asm/mach/map.h> | 43 | #include <asm/mach/map.h> |
41 | 44 | ||
45 | #include <mach/at91_aic.h> | ||
46 | |||
42 | void __iomem *at91_aic_base; | 47 | void __iomem *at91_aic_base; |
43 | static struct irq_domain *at91_aic_domain; | 48 | static struct irq_domain *at91_aic_domain; |
44 | static struct device_node *at91_aic_np; | 49 | static struct device_node *at91_aic_np; |
50 | static unsigned int n_irqs = NR_AIC_IRQS; | ||
51 | static unsigned long at91_aic_caps = 0; | ||
52 | |||
53 | /* AIC5 introduces a Source Select Register */ | ||
54 | #define AT91_AIC_CAP_AIC5 (1 << 0) | ||
55 | #define has_aic5() (at91_aic_caps & AT91_AIC_CAP_AIC5) | ||
56 | |||
57 | #ifdef CONFIG_PM | ||
58 | |||
59 | static unsigned long *wakeups; | ||
60 | static unsigned long *backups; | ||
61 | |||
62 | #define set_backup(bit) set_bit(bit, backups) | ||
63 | #define clear_backup(bit) clear_bit(bit, backups) | ||
64 | |||
65 | static int at91_aic_pm_init(void) | ||
66 | { | ||
67 | backups = kzalloc(BITS_TO_LONGS(n_irqs) * sizeof(*backups), GFP_KERNEL); | ||
68 | if (!backups) | ||
69 | return -ENOMEM; | ||
70 | |||
71 | wakeups = kzalloc(BITS_TO_LONGS(n_irqs) * sizeof(*backups), GFP_KERNEL); | ||
72 | if (!wakeups) { | ||
73 | kfree(backups); | ||
74 | return -ENOMEM; | ||
75 | } | ||
76 | |||
77 | return 0; | ||
78 | } | ||
79 | |||
80 | static int at91_aic_set_wake(struct irq_data *d, unsigned value) | ||
81 | { | ||
82 | if (unlikely(d->hwirq >= n_irqs)) | ||
83 | return -EINVAL; | ||
84 | |||
85 | if (value) | ||
86 | set_bit(d->hwirq, wakeups); | ||
87 | else | ||
88 | clear_bit(d->hwirq, wakeups); | ||
89 | |||
90 | return 0; | ||
91 | } | ||
92 | |||
93 | void at91_irq_suspend(void) | ||
94 | { | ||
95 | int i = 0, bit; | ||
96 | |||
97 | if (has_aic5()) { | ||
98 | /* disable enabled irqs */ | ||
99 | while ((bit = find_next_bit(backups, n_irqs, i)) < n_irqs) { | ||
100 | at91_aic_write(AT91_AIC5_SSR, | ||
101 | bit & AT91_AIC5_INTSEL_MSK); | ||
102 | at91_aic_write(AT91_AIC5_IDCR, 1); | ||
103 | i = bit; | ||
104 | } | ||
105 | /* enable wakeup irqs */ | ||
106 | i = 0; | ||
107 | while ((bit = find_next_bit(wakeups, n_irqs, i)) < n_irqs) { | ||
108 | at91_aic_write(AT91_AIC5_SSR, | ||
109 | bit & AT91_AIC5_INTSEL_MSK); | ||
110 | at91_aic_write(AT91_AIC5_IECR, 1); | ||
111 | i = bit; | ||
112 | } | ||
113 | } else { | ||
114 | at91_aic_write(AT91_AIC_IDCR, *backups); | ||
115 | at91_aic_write(AT91_AIC_IECR, *wakeups); | ||
116 | } | ||
117 | } | ||
118 | |||
119 | void at91_irq_resume(void) | ||
120 | { | ||
121 | int i = 0, bit; | ||
122 | |||
123 | if (has_aic5()) { | ||
124 | /* disable wakeup irqs */ | ||
125 | while ((bit = find_next_bit(wakeups, n_irqs, i)) < n_irqs) { | ||
126 | at91_aic_write(AT91_AIC5_SSR, | ||
127 | bit & AT91_AIC5_INTSEL_MSK); | ||
128 | at91_aic_write(AT91_AIC5_IDCR, 1); | ||
129 | i = bit; | ||
130 | } | ||
131 | /* enable irqs disabled for suspend */ | ||
132 | i = 0; | ||
133 | while ((bit = find_next_bit(backups, n_irqs, i)) < n_irqs) { | ||
134 | at91_aic_write(AT91_AIC5_SSR, | ||
135 | bit & AT91_AIC5_INTSEL_MSK); | ||
136 | at91_aic_write(AT91_AIC5_IECR, 1); | ||
137 | i = bit; | ||
138 | } | ||
139 | } else { | ||
140 | at91_aic_write(AT91_AIC_IDCR, *wakeups); | ||
141 | at91_aic_write(AT91_AIC_IECR, *backups); | ||
142 | } | ||
143 | } | ||
144 | |||
145 | #else | ||
146 | static inline int at91_aic_pm_init(void) | ||
147 | { | ||
148 | return 0; | ||
149 | } | ||
150 | |||
151 | #define set_backup(bit) | ||
152 | #define clear_backup(bit) | ||
153 | #define at91_aic_set_wake NULL | ||
154 | |||
155 | #endif /* CONFIG_PM */ | ||
156 | |||
157 | asmlinkage void __exception_irq_entry | ||
158 | at91_aic_handle_irq(struct pt_regs *regs) | ||
159 | { | ||
160 | u32 irqnr; | ||
161 | u32 irqstat; | ||
162 | |||
163 | irqnr = at91_aic_read(AT91_AIC_IVR); | ||
164 | irqstat = at91_aic_read(AT91_AIC_ISR); | ||
165 | |||
166 | /* | ||
167 | * ISR value is 0 when there is no current interrupt or when there is | ||
168 | * a spurious interrupt | ||
169 | */ | ||
170 | if (!irqstat) | ||
171 | at91_aic_write(AT91_AIC_EOICR, 0); | ||
172 | else | ||
173 | handle_IRQ(irqnr, regs); | ||
174 | } | ||
175 | |||
176 | asmlinkage void __exception_irq_entry | ||
177 | at91_aic5_handle_irq(struct pt_regs *regs) | ||
178 | { | ||
179 | u32 irqnr; | ||
180 | u32 irqstat; | ||
181 | |||
182 | irqnr = at91_aic_read(AT91_AIC5_IVR); | ||
183 | irqstat = at91_aic_read(AT91_AIC5_ISR); | ||
184 | |||
185 | if (!irqstat) | ||
186 | at91_aic_write(AT91_AIC5_EOICR, 0); | ||
187 | else | ||
188 | handle_IRQ(irqnr, regs); | ||
189 | } | ||
45 | 190 | ||
46 | static void at91_aic_mask_irq(struct irq_data *d) | 191 | static void at91_aic_mask_irq(struct irq_data *d) |
47 | { | 192 | { |
48 | /* Disable interrupt on AIC */ | 193 | /* Disable interrupt on AIC */ |
49 | at91_aic_write(AT91_AIC_IDCR, 1 << d->hwirq); | 194 | at91_aic_write(AT91_AIC_IDCR, 1 << d->hwirq); |
195 | /* Update ISR cache */ | ||
196 | clear_backup(d->hwirq); | ||
197 | } | ||
198 | |||
199 | static void __maybe_unused at91_aic5_mask_irq(struct irq_data *d) | ||
200 | { | ||
201 | /* Disable interrupt on AIC5 */ | ||
202 | at91_aic_write(AT91_AIC5_SSR, d->hwirq & AT91_AIC5_INTSEL_MSK); | ||
203 | at91_aic_write(AT91_AIC5_IDCR, 1); | ||
204 | /* Update ISR cache */ | ||
205 | clear_backup(d->hwirq); | ||
50 | } | 206 | } |
51 | 207 | ||
52 | static void at91_aic_unmask_irq(struct irq_data *d) | 208 | static void at91_aic_unmask_irq(struct irq_data *d) |
53 | { | 209 | { |
54 | /* Enable interrupt on AIC */ | 210 | /* Enable interrupt on AIC */ |
55 | at91_aic_write(AT91_AIC_IECR, 1 << d->hwirq); | 211 | at91_aic_write(AT91_AIC_IECR, 1 << d->hwirq); |
212 | /* Update ISR cache */ | ||
213 | set_backup(d->hwirq); | ||
214 | } | ||
215 | |||
216 | static void __maybe_unused at91_aic5_unmask_irq(struct irq_data *d) | ||
217 | { | ||
218 | /* Enable interrupt on AIC5 */ | ||
219 | at91_aic_write(AT91_AIC5_SSR, d->hwirq & AT91_AIC5_INTSEL_MSK); | ||
220 | at91_aic_write(AT91_AIC5_IECR, 1); | ||
221 | /* Update ISR cache */ | ||
222 | set_backup(d->hwirq); | ||
56 | } | 223 | } |
57 | 224 | ||
58 | unsigned int at91_extern_irq; | 225 | static void at91_aic_eoi(struct irq_data *d) |
226 | { | ||
227 | /* | ||
228 | * Mark end-of-interrupt on AIC, the controller doesn't care about | ||
229 | * the value written. Moreover it's a write-only register. | ||
230 | */ | ||
231 | at91_aic_write(AT91_AIC_EOICR, 0); | ||
232 | } | ||
233 | |||
234 | static void __maybe_unused at91_aic5_eoi(struct irq_data *d) | ||
235 | { | ||
236 | at91_aic_write(AT91_AIC5_EOICR, 0); | ||
237 | } | ||
59 | 238 | ||
60 | #define is_extern_irq(hwirq) ((1 << (hwirq)) & at91_extern_irq) | 239 | unsigned long *at91_extern_irq; |
61 | 240 | ||
62 | static int at91_aic_set_type(struct irq_data *d, unsigned type) | 241 | #define is_extern_irq(hwirq) test_bit(hwirq, at91_extern_irq) |
242 | |||
243 | static int at91_aic_compute_srctype(struct irq_data *d, unsigned type) | ||
63 | { | 244 | { |
64 | unsigned int smr, srctype; | 245 | int srctype; |
65 | 246 | ||
66 | switch (type) { | 247 | switch (type) { |
67 | case IRQ_TYPE_LEVEL_HIGH: | 248 | case IRQ_TYPE_LEVEL_HIGH: |
@@ -74,65 +255,51 @@ static int at91_aic_set_type(struct irq_data *d, unsigned type) | |||
74 | if ((d->hwirq == AT91_ID_FIQ) || is_extern_irq(d->hwirq)) /* only supported on external interrupts */ | 255 | if ((d->hwirq == AT91_ID_FIQ) || is_extern_irq(d->hwirq)) /* only supported on external interrupts */ |
75 | srctype = AT91_AIC_SRCTYPE_LOW; | 256 | srctype = AT91_AIC_SRCTYPE_LOW; |
76 | else | 257 | else |
77 | return -EINVAL; | 258 | srctype = -EINVAL; |
78 | break; | 259 | break; |
79 | case IRQ_TYPE_EDGE_FALLING: | 260 | case IRQ_TYPE_EDGE_FALLING: |
80 | if ((d->hwirq == AT91_ID_FIQ) || is_extern_irq(d->hwirq)) /* only supported on external interrupts */ | 261 | if ((d->hwirq == AT91_ID_FIQ) || is_extern_irq(d->hwirq)) /* only supported on external interrupts */ |
81 | srctype = AT91_AIC_SRCTYPE_FALLING; | 262 | srctype = AT91_AIC_SRCTYPE_FALLING; |
82 | else | 263 | else |
83 | return -EINVAL; | 264 | srctype = -EINVAL; |
84 | break; | 265 | break; |
85 | default: | 266 | default: |
86 | return -EINVAL; | 267 | srctype = -EINVAL; |
87 | } | 268 | } |
88 | 269 | ||
89 | smr = at91_aic_read(AT91_AIC_SMR(d->hwirq)) & ~AT91_AIC_SRCTYPE; | 270 | return srctype; |
90 | at91_aic_write(AT91_AIC_SMR(d->hwirq), smr | srctype); | ||
91 | return 0; | ||
92 | } | 271 | } |
93 | 272 | ||
94 | #ifdef CONFIG_PM | 273 | static int at91_aic_set_type(struct irq_data *d, unsigned type) |
95 | |||
96 | static u32 wakeups; | ||
97 | static u32 backups; | ||
98 | |||
99 | static int at91_aic_set_wake(struct irq_data *d, unsigned value) | ||
100 | { | 274 | { |
101 | if (unlikely(d->hwirq >= NR_AIC_IRQS)) | 275 | unsigned int smr; |
102 | return -EINVAL; | 276 | int srctype; |
103 | 277 | ||
104 | if (value) | 278 | srctype = at91_aic_compute_srctype(d, type); |
105 | wakeups |= (1 << d->hwirq); | 279 | if (srctype < 0) |
106 | else | 280 | return srctype; |
107 | wakeups &= ~(1 << d->hwirq); | 281 | |
282 | if (has_aic5()) { | ||
283 | at91_aic_write(AT91_AIC5_SSR, | ||
284 | d->hwirq & AT91_AIC5_INTSEL_MSK); | ||
285 | smr = at91_aic_read(AT91_AIC5_SMR) & ~AT91_AIC_SRCTYPE; | ||
286 | at91_aic_write(AT91_AIC5_SMR, smr | srctype); | ||
287 | } else { | ||
288 | smr = at91_aic_read(AT91_AIC_SMR(d->hwirq)) | ||
289 | & ~AT91_AIC_SRCTYPE; | ||
290 | at91_aic_write(AT91_AIC_SMR(d->hwirq), smr | srctype); | ||
291 | } | ||
108 | 292 | ||
109 | return 0; | 293 | return 0; |
110 | } | 294 | } |
111 | 295 | ||
112 | void at91_irq_suspend(void) | ||
113 | { | ||
114 | backups = at91_aic_read(AT91_AIC_IMR); | ||
115 | at91_aic_write(AT91_AIC_IDCR, backups); | ||
116 | at91_aic_write(AT91_AIC_IECR, wakeups); | ||
117 | } | ||
118 | |||
119 | void at91_irq_resume(void) | ||
120 | { | ||
121 | at91_aic_write(AT91_AIC_IDCR, wakeups); | ||
122 | at91_aic_write(AT91_AIC_IECR, backups); | ||
123 | } | ||
124 | |||
125 | #else | ||
126 | #define at91_aic_set_wake NULL | ||
127 | #endif | ||
128 | |||
129 | static struct irq_chip at91_aic_chip = { | 296 | static struct irq_chip at91_aic_chip = { |
130 | .name = "AIC", | 297 | .name = "AIC", |
131 | .irq_ack = at91_aic_mask_irq, | ||
132 | .irq_mask = at91_aic_mask_irq, | 298 | .irq_mask = at91_aic_mask_irq, |
133 | .irq_unmask = at91_aic_unmask_irq, | 299 | .irq_unmask = at91_aic_unmask_irq, |
134 | .irq_set_type = at91_aic_set_type, | 300 | .irq_set_type = at91_aic_set_type, |
135 | .irq_set_wake = at91_aic_set_wake, | 301 | .irq_set_wake = at91_aic_set_wake, |
302 | .irq_eoi = at91_aic_eoi, | ||
136 | }; | 303 | }; |
137 | 304 | ||
138 | static void __init at91_aic_hw_init(unsigned int spu_vector) | 305 | static void __init at91_aic_hw_init(unsigned int spu_vector) |
@@ -161,41 +328,172 @@ static void __init at91_aic_hw_init(unsigned int spu_vector) | |||
161 | at91_aic_write(AT91_AIC_ICCR, 0xFFFFFFFF); | 328 | at91_aic_write(AT91_AIC_ICCR, 0xFFFFFFFF); |
162 | } | 329 | } |
163 | 330 | ||
331 | static void __init __maybe_unused at91_aic5_hw_init(unsigned int spu_vector) | ||
332 | { | ||
333 | int i; | ||
334 | |||
335 | /* | ||
336 | * Perform 8 End Of Interrupt Command to make sure AIC | ||
337 | * will not Lock out nIRQ | ||
338 | */ | ||
339 | for (i = 0; i < 8; i++) | ||
340 | at91_aic_write(AT91_AIC5_EOICR, 0); | ||
341 | |||
342 | /* | ||
343 | * Spurious Interrupt ID in Spurious Vector Register. | ||
344 | * When there is no current interrupt, the IRQ Vector Register | ||
345 | * reads the value stored in AIC_SPU | ||
346 | */ | ||
347 | at91_aic_write(AT91_AIC5_SPU, spu_vector); | ||
348 | |||
349 | /* No debugging in AIC: Debug (Protect) Control Register */ | ||
350 | at91_aic_write(AT91_AIC5_DCR, 0); | ||
351 | |||
352 | /* Disable and clear all interrupts initially */ | ||
353 | for (i = 0; i < n_irqs; i++) { | ||
354 | at91_aic_write(AT91_AIC5_SSR, i & AT91_AIC5_INTSEL_MSK); | ||
355 | at91_aic_write(AT91_AIC5_IDCR, 1); | ||
356 | at91_aic_write(AT91_AIC5_ICCR, 1); | ||
357 | } | ||
358 | } | ||
359 | |||
164 | #if defined(CONFIG_OF) | 360 | #if defined(CONFIG_OF) |
361 | static unsigned int *at91_aic_irq_priorities; | ||
362 | |||
165 | static int at91_aic_irq_map(struct irq_domain *h, unsigned int virq, | 363 | static int at91_aic_irq_map(struct irq_domain *h, unsigned int virq, |
166 | irq_hw_number_t hw) | 364 | irq_hw_number_t hw) |
167 | { | 365 | { |
168 | /* Put virq number in Source Vector Register */ | 366 | /* Put virq number in Source Vector Register */ |
169 | at91_aic_write(AT91_AIC_SVR(hw), virq); | 367 | at91_aic_write(AT91_AIC_SVR(hw), virq); |
170 | 368 | ||
171 | /* Active Low interrupt, without priority */ | 369 | /* Active Low interrupt, with priority */ |
172 | at91_aic_write(AT91_AIC_SMR(hw), AT91_AIC_SRCTYPE_LOW); | 370 | at91_aic_write(AT91_AIC_SMR(hw), |
371 | AT91_AIC_SRCTYPE_LOW | at91_aic_irq_priorities[hw]); | ||
173 | 372 | ||
174 | irq_set_chip_and_handler(virq, &at91_aic_chip, handle_level_irq); | 373 | irq_set_chip_and_handler(virq, &at91_aic_chip, handle_fasteoi_irq); |
175 | set_irq_flags(virq, IRQF_VALID | IRQF_PROBE); | 374 | set_irq_flags(virq, IRQF_VALID | IRQF_PROBE); |
176 | 375 | ||
177 | return 0; | 376 | return 0; |
178 | } | 377 | } |
179 | 378 | ||
379 | static int at91_aic5_irq_map(struct irq_domain *h, unsigned int virq, | ||
380 | irq_hw_number_t hw) | ||
381 | { | ||
382 | at91_aic_write(AT91_AIC5_SSR, hw & AT91_AIC5_INTSEL_MSK); | ||
383 | |||
384 | /* Put virq number in Source Vector Register */ | ||
385 | at91_aic_write(AT91_AIC5_SVR, virq); | ||
386 | |||
387 | /* Active Low interrupt, with priority */ | ||
388 | at91_aic_write(AT91_AIC5_SMR, | ||
389 | AT91_AIC_SRCTYPE_LOW | at91_aic_irq_priorities[hw]); | ||
390 | |||
391 | irq_set_chip_and_handler(virq, &at91_aic_chip, handle_fasteoi_irq); | ||
392 | set_irq_flags(virq, IRQF_VALID | IRQF_PROBE); | ||
393 | |||
394 | return 0; | ||
395 | } | ||
396 | |||
397 | static int at91_aic_irq_domain_xlate(struct irq_domain *d, struct device_node *ctrlr, | ||
398 | const u32 *intspec, unsigned int intsize, | ||
399 | irq_hw_number_t *out_hwirq, unsigned int *out_type) | ||
400 | { | ||
401 | if (WARN_ON(intsize < 3)) | ||
402 | return -EINVAL; | ||
403 | if (WARN_ON(intspec[0] >= n_irqs)) | ||
404 | return -EINVAL; | ||
405 | if (WARN_ON((intspec[2] < AT91_AIC_IRQ_MIN_PRIORITY) | ||
406 | || (intspec[2] > AT91_AIC_IRQ_MAX_PRIORITY))) | ||
407 | return -EINVAL; | ||
408 | |||
409 | *out_hwirq = intspec[0]; | ||
410 | *out_type = intspec[1] & IRQ_TYPE_SENSE_MASK; | ||
411 | at91_aic_irq_priorities[*out_hwirq] = intspec[2]; | ||
412 | |||
413 | return 0; | ||
414 | } | ||
415 | |||
180 | static struct irq_domain_ops at91_aic_irq_ops = { | 416 | static struct irq_domain_ops at91_aic_irq_ops = { |
181 | .map = at91_aic_irq_map, | 417 | .map = at91_aic_irq_map, |
182 | .xlate = irq_domain_xlate_twocell, | 418 | .xlate = at91_aic_irq_domain_xlate, |
183 | }; | 419 | }; |
184 | 420 | ||
185 | int __init at91_aic_of_init(struct device_node *node, | 421 | int __init at91_aic_of_common_init(struct device_node *node, |
186 | struct device_node *parent) | 422 | struct device_node *parent) |
187 | { | 423 | { |
424 | struct property *prop; | ||
425 | const __be32 *p; | ||
426 | u32 val; | ||
427 | |||
428 | at91_extern_irq = kzalloc(BITS_TO_LONGS(n_irqs) | ||
429 | * sizeof(*at91_extern_irq), GFP_KERNEL); | ||
430 | if (!at91_extern_irq) | ||
431 | return -ENOMEM; | ||
432 | |||
433 | if (at91_aic_pm_init()) { | ||
434 | kfree(at91_extern_irq); | ||
435 | return -ENOMEM; | ||
436 | } | ||
437 | |||
438 | at91_aic_irq_priorities = kzalloc(n_irqs | ||
439 | * sizeof(*at91_aic_irq_priorities), | ||
440 | GFP_KERNEL); | ||
441 | if (!at91_aic_irq_priorities) | ||
442 | return -ENOMEM; | ||
443 | |||
188 | at91_aic_base = of_iomap(node, 0); | 444 | at91_aic_base = of_iomap(node, 0); |
189 | at91_aic_np = node; | 445 | at91_aic_np = node; |
190 | 446 | ||
191 | at91_aic_domain = irq_domain_add_linear(at91_aic_np, NR_AIC_IRQS, | 447 | at91_aic_domain = irq_domain_add_linear(at91_aic_np, n_irqs, |
192 | &at91_aic_irq_ops, NULL); | 448 | &at91_aic_irq_ops, NULL); |
193 | if (!at91_aic_domain) | 449 | if (!at91_aic_domain) |
194 | panic("Unable to add AIC irq domain (DT)\n"); | 450 | panic("Unable to add AIC irq domain (DT)\n"); |
195 | 451 | ||
452 | of_property_for_each_u32(node, "atmel,external-irqs", prop, p, val) { | ||
453 | if (val >= n_irqs) | ||
454 | pr_warn("AIC: external irq %d >= %d skip it\n", | ||
455 | val, n_irqs); | ||
456 | else | ||
457 | set_bit(val, at91_extern_irq); | ||
458 | } | ||
459 | |||
196 | irq_set_default_host(at91_aic_domain); | 460 | irq_set_default_host(at91_aic_domain); |
197 | 461 | ||
198 | at91_aic_hw_init(NR_AIC_IRQS); | 462 | return 0; |
463 | } | ||
464 | |||
465 | int __init at91_aic_of_init(struct device_node *node, | ||
466 | struct device_node *parent) | ||
467 | { | ||
468 | int err; | ||
469 | |||
470 | err = at91_aic_of_common_init(node, parent); | ||
471 | if (err) | ||
472 | return err; | ||
473 | |||
474 | at91_aic_hw_init(n_irqs); | ||
475 | |||
476 | return 0; | ||
477 | } | ||
478 | |||
479 | int __init at91_aic5_of_init(struct device_node *node, | ||
480 | struct device_node *parent) | ||
481 | { | ||
482 | int err; | ||
483 | |||
484 | at91_aic_caps |= AT91_AIC_CAP_AIC5; | ||
485 | n_irqs = NR_AIC5_IRQS; | ||
486 | at91_aic_chip.irq_ack = at91_aic5_mask_irq; | ||
487 | at91_aic_chip.irq_mask = at91_aic5_mask_irq; | ||
488 | at91_aic_chip.irq_unmask = at91_aic5_unmask_irq; | ||
489 | at91_aic_chip.irq_eoi = at91_aic5_eoi; | ||
490 | at91_aic_irq_ops.map = at91_aic5_irq_map; | ||
491 | |||
492 | err = at91_aic_of_common_init(node, parent); | ||
493 | if (err) | ||
494 | return err; | ||
495 | |||
496 | at91_aic5_hw_init(n_irqs); | ||
199 | 497 | ||
200 | return 0; | 498 | return 0; |
201 | } | 499 | } |
@@ -204,22 +502,25 @@ int __init at91_aic_of_init(struct device_node *node, | |||
204 | /* | 502 | /* |
205 | * Initialize the AIC interrupt controller. | 503 | * Initialize the AIC interrupt controller. |
206 | */ | 504 | */ |
207 | void __init at91_aic_init(unsigned int priority[NR_AIC_IRQS]) | 505 | void __init at91_aic_init(unsigned int *priority) |
208 | { | 506 | { |
209 | unsigned int i; | 507 | unsigned int i; |
210 | int irq_base; | 508 | int irq_base; |
211 | 509 | ||
510 | if (at91_aic_pm_init()) | ||
511 | panic("Unable to allocate bit maps\n"); | ||
512 | |||
212 | at91_aic_base = ioremap(AT91_AIC, 512); | 513 | at91_aic_base = ioremap(AT91_AIC, 512); |
213 | if (!at91_aic_base) | 514 | if (!at91_aic_base) |
214 | panic("Unable to ioremap AIC registers\n"); | 515 | panic("Unable to ioremap AIC registers\n"); |
215 | 516 | ||
216 | /* Add irq domain for AIC */ | 517 | /* Add irq domain for AIC */ |
217 | irq_base = irq_alloc_descs(-1, 0, NR_AIC_IRQS, 0); | 518 | irq_base = irq_alloc_descs(-1, 0, n_irqs, 0); |
218 | if (irq_base < 0) { | 519 | if (irq_base < 0) { |
219 | WARN(1, "Cannot allocate irq_descs, assuming pre-allocated\n"); | 520 | WARN(1, "Cannot allocate irq_descs, assuming pre-allocated\n"); |
220 | irq_base = 0; | 521 | irq_base = 0; |
221 | } | 522 | } |
222 | at91_aic_domain = irq_domain_add_legacy(at91_aic_np, NR_AIC_IRQS, | 523 | at91_aic_domain = irq_domain_add_legacy(at91_aic_np, n_irqs, |
223 | irq_base, 0, | 524 | irq_base, 0, |
224 | &irq_domain_simple_ops, NULL); | 525 | &irq_domain_simple_ops, NULL); |
225 | 526 | ||
@@ -232,15 +533,14 @@ void __init at91_aic_init(unsigned int priority[NR_AIC_IRQS]) | |||
232 | * The IVR is used by macro get_irqnr_and_base to read and verify. | 533 | * The IVR is used by macro get_irqnr_and_base to read and verify. |
233 | * The irq number is NR_AIC_IRQS when a spurious interrupt has occurred. | 534 | * The irq number is NR_AIC_IRQS when a spurious interrupt has occurred. |
234 | */ | 535 | */ |
235 | for (i = 0; i < NR_AIC_IRQS; i++) { | 536 | for (i = 0; i < n_irqs; i++) { |
236 | /* Put hardware irq number in Source Vector Register: */ | 537 | /* Put hardware irq number in Source Vector Register: */ |
237 | at91_aic_write(AT91_AIC_SVR(i), i); | 538 | at91_aic_write(AT91_AIC_SVR(i), NR_IRQS_LEGACY + i); |
238 | /* Active Low interrupt, with the specified priority */ | 539 | /* Active Low interrupt, with the specified priority */ |
239 | at91_aic_write(AT91_AIC_SMR(i), AT91_AIC_SRCTYPE_LOW | priority[i]); | 540 | at91_aic_write(AT91_AIC_SMR(i), AT91_AIC_SRCTYPE_LOW | priority[i]); |
240 | 541 | irq_set_chip_and_handler(NR_IRQS_LEGACY + i, &at91_aic_chip, handle_fasteoi_irq); | |
241 | irq_set_chip_and_handler(i, &at91_aic_chip, handle_level_irq); | ||
242 | set_irq_flags(i, IRQF_VALID | IRQF_PROBE); | 542 | set_irq_flags(i, IRQF_VALID | IRQF_PROBE); |
243 | } | 543 | } |
244 | 544 | ||
245 | at91_aic_hw_init(NR_AIC_IRQS); | 545 | at91_aic_hw_init(n_irqs); |
246 | } | 546 | } |