aboutsummaryrefslogtreecommitdiffstats
path: root/arch
diff options
context:
space:
mode:
authorLudovic Desroches <ludovic.desroches@atmel.com>2012-05-30 04:01:09 -0400
committerNicolas Ferre <nicolas.ferre@atmel.com>2012-07-02 08:31:00 -0400
commitc4b68520dc0ec96153bc0d87bca5ffba508edfcf (patch)
tree374f84ee13239586a6754be3cab60e81bfe7ddeb /arch
parent4c6971a6debb340d487cf6189f15a1332702330f (diff)
ARM: at91: add AIC5 support
The number of lines of AIC5 has increased from 32 to 128. Due to this increase, a source select register has been introduced for the interrupt line selection. Moreover, register mapping has been changed. For that reasons, we need some dedicated callbacks for AIC5. Power management is also concerned by these changes. On suspend, we can't get the whole interrupt mask register as before, we have to read this register 128 times. To reduce this overhead, a snapshot of the whole IMR is maintained. Signed-off-by: Ludovic Desroches <ludovic.desroches@atmel.com> Signed-off-by: Nicolas Ferre <nicolas.ferre@atmel.com>
Diffstat (limited to 'arch')
-rw-r--r--arch/arm/mach-at91/generic.h2
-rw-r--r--arch/arm/mach-at91/include/mach/at91_aic.h26
-rw-r--r--arch/arm/mach-at91/irq.c343
3 files changed, 314 insertions, 57 deletions
diff --git a/arch/arm/mach-at91/generic.h b/arch/arm/mach-at91/generic.h
index 0a60bf837037..f49650677653 100644
--- a/arch/arm/mach-at91/generic.h
+++ b/arch/arm/mach-at91/generic.h
@@ -29,6 +29,8 @@ extern void __init at91x40_init_interrupts(unsigned int priority[]);
29extern void __init at91_aic_init(unsigned int priority[]); 29extern void __init at91_aic_init(unsigned int priority[]);
30extern int __init at91_aic_of_init(struct device_node *node, 30extern int __init at91_aic_of_init(struct device_node *node,
31 struct device_node *parent); 31 struct device_node *parent);
32extern int __init at91_aic5_of_init(struct device_node *node,
33 struct device_node *parent);
32 34
33 35
34 /* Timer */ 36 /* Timer */
diff --git a/arch/arm/mach-at91/include/mach/at91_aic.h b/arch/arm/mach-at91/include/mach/at91_aic.h
index fd42a85b7eb1..eaea66197fa1 100644
--- a/arch/arm/mach-at91/include/mach/at91_aic.h
+++ b/arch/arm/mach-at91/include/mach/at91_aic.h
@@ -30,11 +30,16 @@ extern void __iomem *at91_aic_base;
30 30
31/* Number of irq lines managed by AIC */ 31/* Number of irq lines managed by AIC */
32#define NR_AIC_IRQS 32 32#define NR_AIC_IRQS 32
33#define NR_AIC5_IRQS 128
34
35#define AT91_AIC5_SSR 0x0 /* Source Select Register [AIC5] */
36#define AT91_AIC5_INTSEL_MSK (0x7f << 0) /* Interrupt Line Selection Mask */
33 37
34#define AT91_AIC_IRQ_MIN_PRIORITY 0 38#define AT91_AIC_IRQ_MIN_PRIORITY 0
35#define AT91_AIC_IRQ_MAX_PRIORITY 7 39#define AT91_AIC_IRQ_MAX_PRIORITY 7
36 40
37#define AT91_AIC_SMR(n) ((n) * 4) /* Source Mode Registers 0-31 */ 41#define AT91_AIC_SMR(n) ((n) * 4) /* Source Mode Registers 0-31 */
42#define AT91_AIC5_SMR 0x4 /* Source Mode Register [AIC5] */
38#define AT91_AIC_PRIOR (7 << 0) /* Priority Level */ 43#define AT91_AIC_PRIOR (7 << 0) /* Priority Level */
39#define AT91_AIC_SRCTYPE (3 << 5) /* Interrupt Source Type */ 44#define AT91_AIC_SRCTYPE (3 << 5) /* Interrupt Source Type */
40#define AT91_AIC_SRCTYPE_LOW (0 << 5) 45#define AT91_AIC_SRCTYPE_LOW (0 << 5)
@@ -43,31 +48,52 @@ extern void __iomem *at91_aic_base;
43#define AT91_AIC_SRCTYPE_RISING (3 << 5) 48#define AT91_AIC_SRCTYPE_RISING (3 << 5)
44 49
45#define AT91_AIC_SVR(n) (0x80 + ((n) * 4)) /* Source Vector Registers 0-31 */ 50#define AT91_AIC_SVR(n) (0x80 + ((n) * 4)) /* Source Vector Registers 0-31 */
51#define AT91_AIC5_SVR 0x8 /* Source Vector Register [AIC5] */
46#define AT91_AIC_IVR 0x100 /* Interrupt Vector Register */ 52#define AT91_AIC_IVR 0x100 /* Interrupt Vector Register */
53#define AT91_AIC5_IVR 0x10 /* Interrupt Vector Register [AIC5] */
47#define AT91_AIC_FVR 0x104 /* Fast Interrupt Vector Register */ 54#define AT91_AIC_FVR 0x104 /* Fast Interrupt Vector Register */
55#define AT91_AIC5_FVR 0x14 /* Fast Interrupt Vector Register [AIC5] */
48#define AT91_AIC_ISR 0x108 /* Interrupt Status Register */ 56#define AT91_AIC_ISR 0x108 /* Interrupt Status Register */
57#define AT91_AIC5_ISR 0x18 /* Interrupt Status Register [AIC5] */
49#define AT91_AIC_IRQID (0x1f << 0) /* Current Interrupt Identifier */ 58#define AT91_AIC_IRQID (0x1f << 0) /* Current Interrupt Identifier */
50 59
51#define AT91_AIC_IPR 0x10c /* Interrupt Pending Register */ 60#define AT91_AIC_IPR 0x10c /* Interrupt Pending Register */
61#define AT91_AIC5_IPR0 0x20 /* Interrupt Pending Register 0 [AIC5] */
62#define AT91_AIC5_IPR1 0x24 /* Interrupt Pending Register 1 [AIC5] */
63#define AT91_AIC5_IPR2 0x28 /* Interrupt Pending Register 2 [AIC5] */
64#define AT91_AIC5_IPR3 0x2c /* Interrupt Pending Register 3 [AIC5] */
52#define AT91_AIC_IMR 0x110 /* Interrupt Mask Register */ 65#define AT91_AIC_IMR 0x110 /* Interrupt Mask Register */
66#define AT91_AIC5_IMR 0x30 /* Interrupt Mask Register [AIC5] */
53#define AT91_AIC_CISR 0x114 /* Core Interrupt Status Register */ 67#define AT91_AIC_CISR 0x114 /* Core Interrupt Status Register */
68#define AT91_AIC5_CISR 0x34 /* Core Interrupt Status Register [AIC5] */
54#define AT91_AIC_NFIQ (1 << 0) /* nFIQ Status */ 69#define AT91_AIC_NFIQ (1 << 0) /* nFIQ Status */
55#define AT91_AIC_NIRQ (1 << 1) /* nIRQ Status */ 70#define AT91_AIC_NIRQ (1 << 1) /* nIRQ Status */
56 71
57#define AT91_AIC_IECR 0x120 /* Interrupt Enable Command Register */ 72#define AT91_AIC_IECR 0x120 /* Interrupt Enable Command Register */
73#define AT91_AIC5_IECR 0x40 /* Interrupt Enable Command Register [AIC5] */
58#define AT91_AIC_IDCR 0x124 /* Interrupt Disable Command Register */ 74#define AT91_AIC_IDCR 0x124 /* Interrupt Disable Command Register */
75#define AT91_AIC5_IDCR 0x44 /* Interrupt Disable Command Register [AIC5] */
59#define AT91_AIC_ICCR 0x128 /* Interrupt Clear Command Register */ 76#define AT91_AIC_ICCR 0x128 /* Interrupt Clear Command Register */
77#define AT91_AIC5_ICCR 0x48 /* Interrupt Clear Command Register [AIC5] */
60#define AT91_AIC_ISCR 0x12c /* Interrupt Set Command Register */ 78#define AT91_AIC_ISCR 0x12c /* Interrupt Set Command Register */
79#define AT91_AIC5_ISCR 0x4c /* Interrupt Set Command Register [AIC5] */
61#define AT91_AIC_EOICR 0x130 /* End of Interrupt Command Register */ 80#define AT91_AIC_EOICR 0x130 /* End of Interrupt Command Register */
81#define AT91_AIC5_EOICR 0x38 /* End of Interrupt Command Register [AIC5] */
62#define AT91_AIC_SPU 0x134 /* Spurious Interrupt Vector Register */ 82#define AT91_AIC_SPU 0x134 /* Spurious Interrupt Vector Register */
83#define AT91_AIC5_SPU 0x3c /* Spurious Interrupt Vector Register [AIC5] */
63#define AT91_AIC_DCR 0x138 /* Debug Control Register */ 84#define AT91_AIC_DCR 0x138 /* Debug Control Register */
85#define AT91_AIC5_DCR 0x6c /* Debug Control Register [AIC5] */
64#define AT91_AIC_DCR_PROT (1 << 0) /* Protection Mode */ 86#define AT91_AIC_DCR_PROT (1 << 0) /* Protection Mode */
65#define AT91_AIC_DCR_GMSK (1 << 1) /* General Mask */ 87#define AT91_AIC_DCR_GMSK (1 << 1) /* General Mask */
66 88
67#define AT91_AIC_FFER 0x140 /* Fast Forcing Enable Register [SAM9 only] */ 89#define AT91_AIC_FFER 0x140 /* Fast Forcing Enable Register [SAM9 only] */
90#define AT91_AIC5_FFER 0x50 /* Fast Forcing Enable Register [AIC5] */
68#define AT91_AIC_FFDR 0x144 /* Fast Forcing Disable Register [SAM9 only] */ 91#define AT91_AIC_FFDR 0x144 /* Fast Forcing Disable Register [SAM9 only] */
92#define AT91_AIC5_FFDR 0x54 /* Fast Forcing Disable Register [AIC5] */
69#define AT91_AIC_FFSR 0x148 /* Fast Forcing Status Register [SAM9 only] */ 93#define AT91_AIC_FFSR 0x148 /* Fast Forcing Status Register [SAM9 only] */
94#define AT91_AIC5_FFSR 0x58 /* Fast Forcing Status Register [AIC5] */
70 95
71void at91_aic_handle_irq(struct pt_regs *regs); 96void at91_aic_handle_irq(struct pt_regs *regs);
97void at91_aic5_handle_irq(struct pt_regs *regs);
72 98
73#endif 99#endif
diff --git a/arch/arm/mach-at91/irq.c b/arch/arm/mach-at91/irq.c
index 75ca2f44c78e..c5eaaa060bd8 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>
@@ -46,9 +47,116 @@
46void __iomem *at91_aic_base; 47void __iomem *at91_aic_base;
47static struct irq_domain *at91_aic_domain; 48static struct irq_domain *at91_aic_domain;
48static struct device_node *at91_aic_np; 49static struct device_node *at91_aic_np;
50static unsigned int n_irqs = NR_AIC_IRQS;
51static unsigned long at91_aic_caps = 0;
49static unsigned int *at91_aic_irq_priorities; 52static unsigned int *at91_aic_irq_priorities;
50 53
51asmlinkage void __exception_irq_entry at91_aic_handle_irq(struct pt_regs *regs) 54/* AIC5 introduces a Source Select Register */
55#define AT91_AIC_CAP_AIC5 (1 << 0)
56#define has_aic5() (at91_aic_caps & AT91_AIC_CAP_AIC5)
57
58#ifdef CONFIG_PM
59
60static unsigned long *wakeups;
61static unsigned long *backups;
62
63#define set_backup(bit) set_bit(bit, backups)
64#define clear_backup(bit) clear_bit(bit, backups)
65
66static int at91_aic_pm_init(void)
67{
68 backups = kzalloc(BITS_TO_LONGS(n_irqs) * sizeof(*backups), GFP_KERNEL);
69 if (!backups)
70 return -ENOMEM;
71
72 wakeups = kzalloc(BITS_TO_LONGS(n_irqs) * sizeof(*backups), GFP_KERNEL);
73 if (!wakeups) {
74 kfree(backups);
75 return -ENOMEM;
76 }
77
78 return 0;
79}
80
81static int at91_aic_set_wake(struct irq_data *d, unsigned value)
82{
83 if (unlikely(d->hwirq >= n_irqs))
84 return -EINVAL;
85
86 if (value)
87 set_bit(d->hwirq, wakeups);
88 else
89 clear_bit(d->hwirq, wakeups);
90
91 return 0;
92}
93
94void at91_irq_suspend(void)
95{
96 int i = 0, bit;
97
98 if (has_aic5()) {
99 /* disable enabled irqs */
100 while ((bit = find_next_bit(backups, n_irqs, i)) < n_irqs) {
101 at91_aic_write(AT91_AIC5_SSR,
102 bit & AT91_AIC5_INTSEL_MSK);
103 at91_aic_write(AT91_AIC5_IDCR, 1);
104 i = bit;
105 }
106 /* enable wakeup irqs */
107 i = 0;
108 while ((bit = find_next_bit(wakeups, n_irqs, i)) < n_irqs) {
109 at91_aic_write(AT91_AIC5_SSR,
110 bit & AT91_AIC5_INTSEL_MSK);
111 at91_aic_write(AT91_AIC5_IECR, 1);
112 i = bit;
113 }
114 } else {
115 at91_aic_write(AT91_AIC_IDCR, *backups);
116 at91_aic_write(AT91_AIC_IECR, *wakeups);
117 }
118}
119
120void at91_irq_resume(void)
121{
122 int i = 0, bit;
123
124 if (has_aic5()) {
125 /* disable wakeup irqs */
126 while ((bit = find_next_bit(wakeups, n_irqs, i)) < n_irqs) {
127 at91_aic_write(AT91_AIC5_SSR,
128 bit & AT91_AIC5_INTSEL_MSK);
129 at91_aic_write(AT91_AIC5_IDCR, 1);
130 i = bit;
131 }
132 /* enable irqs disabled for suspend */
133 i = 0;
134 while ((bit = find_next_bit(backups, n_irqs, i)) < n_irqs) {
135 at91_aic_write(AT91_AIC5_SSR,
136 bit & AT91_AIC5_INTSEL_MSK);
137 at91_aic_write(AT91_AIC5_IECR, 1);
138 i = bit;
139 }
140 } else {
141 at91_aic_write(AT91_AIC_IDCR, *wakeups);
142 at91_aic_write(AT91_AIC_IECR, *backups);
143 }
144}
145
146#else
147static inline int at91_aic_pm_init(void)
148{
149 return 0;
150}
151
152#define set_backup(bit)
153#define clear_backup(bit)
154#define at91_aic_set_wake NULL
155
156#endif /* CONFIG_PM */
157
158asmlinkage void __exception_irq_entry
159at91_aic_handle_irq(struct pt_regs *regs)
52{ 160{
53 u32 irqnr; 161 u32 irqnr;
54 u32 irqstat; 162 u32 irqstat;
@@ -66,16 +174,53 @@ asmlinkage void __exception_irq_entry at91_aic_handle_irq(struct pt_regs *regs)
66 handle_IRQ(irqnr, regs); 174 handle_IRQ(irqnr, regs);
67} 175}
68 176
177asmlinkage void __exception_irq_entry
178at91_aic5_handle_irq(struct pt_regs *regs)
179{
180 u32 irqnr;
181 u32 irqstat;
182
183 irqnr = at91_aic_read(AT91_AIC5_IVR);
184 irqstat = at91_aic_read(AT91_AIC5_ISR);
185
186 if (!irqstat)
187 at91_aic_write(AT91_AIC5_EOICR, 0);
188 else
189 handle_IRQ(irqnr, regs);
190}
191
69static void at91_aic_mask_irq(struct irq_data *d) 192static void at91_aic_mask_irq(struct irq_data *d)
70{ 193{
71 /* Disable interrupt on AIC */ 194 /* Disable interrupt on AIC */
72 at91_aic_write(AT91_AIC_IDCR, 1 << d->hwirq); 195 at91_aic_write(AT91_AIC_IDCR, 1 << d->hwirq);
196 /* Update ISR cache */
197 clear_backup(d->hwirq);
198}
199
200static void __maybe_unused at91_aic5_mask_irq(struct irq_data *d)
201{
202 /* Disable interrupt on AIC5 */
203 at91_aic_write(AT91_AIC5_SSR, d->hwirq & AT91_AIC5_INTSEL_MSK);
204 at91_aic_write(AT91_AIC5_IDCR, 1);
205 /* Update ISR cache */
206 clear_backup(d->hwirq);
73} 207}
74 208
75static void at91_aic_unmask_irq(struct irq_data *d) 209static void at91_aic_unmask_irq(struct irq_data *d)
76{ 210{
77 /* Enable interrupt on AIC */ 211 /* Enable interrupt on AIC */
78 at91_aic_write(AT91_AIC_IECR, 1 << d->hwirq); 212 at91_aic_write(AT91_AIC_IECR, 1 << d->hwirq);
213 /* Update ISR cache */
214 set_backup(d->hwirq);
215}
216
217static void __maybe_unused at91_aic5_unmask_irq(struct irq_data *d)
218{
219 /* Enable interrupt on AIC5 */
220 at91_aic_write(AT91_AIC5_SSR, d->hwirq & AT91_AIC5_INTSEL_MSK);
221 at91_aic_write(AT91_AIC5_IECR, 1);
222 /* Update ISR cache */
223 set_backup(d->hwirq);
79} 224}
80 225
81static void at91_aic_eoi(struct irq_data *d) 226static void at91_aic_eoi(struct irq_data *d)
@@ -87,13 +232,18 @@ static void at91_aic_eoi(struct irq_data *d)
87 at91_aic_write(AT91_AIC_EOICR, 0); 232 at91_aic_write(AT91_AIC_EOICR, 0);
88} 233}
89 234
90unsigned int at91_extern_irq; 235static void __maybe_unused at91_aic5_eoi(struct irq_data *d)
236{
237 at91_aic_write(AT91_AIC5_EOICR, 0);
238}
91 239
92#define is_extern_irq(hwirq) ((1 << (hwirq)) & at91_extern_irq) 240unsigned long *at91_extern_irq;
93 241
94static int at91_aic_set_type(struct irq_data *d, unsigned type) 242#define is_extern_irq(hwirq) test_bit(hwirq, at91_extern_irq)
243
244static int at91_aic_compute_srctype(struct irq_data *d, unsigned type)
95{ 245{
96 unsigned int smr, srctype; 246 int srctype;
97 247
98 switch (type) { 248 switch (type) {
99 case IRQ_TYPE_LEVEL_HIGH: 249 case IRQ_TYPE_LEVEL_HIGH:
@@ -106,58 +256,44 @@ static int at91_aic_set_type(struct irq_data *d, unsigned type)
106 if ((d->hwirq == AT91_ID_FIQ) || is_extern_irq(d->hwirq)) /* only supported on external interrupts */ 256 if ((d->hwirq == AT91_ID_FIQ) || is_extern_irq(d->hwirq)) /* only supported on external interrupts */
107 srctype = AT91_AIC_SRCTYPE_LOW; 257 srctype = AT91_AIC_SRCTYPE_LOW;
108 else 258 else
109 return -EINVAL; 259 srctype = -EINVAL;
110 break; 260 break;
111 case IRQ_TYPE_EDGE_FALLING: 261 case IRQ_TYPE_EDGE_FALLING:
112 if ((d->hwirq == AT91_ID_FIQ) || is_extern_irq(d->hwirq)) /* only supported on external interrupts */ 262 if ((d->hwirq == AT91_ID_FIQ) || is_extern_irq(d->hwirq)) /* only supported on external interrupts */
113 srctype = AT91_AIC_SRCTYPE_FALLING; 263 srctype = AT91_AIC_SRCTYPE_FALLING;
114 else 264 else
115 return -EINVAL; 265 srctype = -EINVAL;
116 break; 266 break;
117 default: 267 default:
118 return -EINVAL; 268 srctype = -EINVAL;
119 } 269 }
120 270
121 smr = at91_aic_read(AT91_AIC_SMR(d->hwirq)) & ~AT91_AIC_SRCTYPE; 271 return srctype;
122 at91_aic_write(AT91_AIC_SMR(d->hwirq), smr | srctype);
123 return 0;
124} 272}
125 273
126#ifdef CONFIG_PM 274static int at91_aic_set_type(struct irq_data *d, unsigned type)
127
128static u32 wakeups;
129static u32 backups;
130
131static int at91_aic_set_wake(struct irq_data *d, unsigned value)
132{ 275{
133 if (unlikely(d->hwirq >= NR_AIC_IRQS)) 276 unsigned int smr;
134 return -EINVAL; 277 int srctype;
135 278
136 if (value) 279 srctype = at91_aic_compute_srctype(d, type);
137 wakeups |= (1 << d->hwirq); 280 if (srctype < 0)
138 else 281 return srctype;
139 wakeups &= ~(1 << d->hwirq); 282
283 if (has_aic5()) {
284 at91_aic_write(AT91_AIC5_SSR,
285 d->hwirq & AT91_AIC5_INTSEL_MSK);
286 smr = at91_aic_read(AT91_AIC5_SMR) & ~AT91_AIC_SRCTYPE;
287 at91_aic_write(AT91_AIC5_SMR, smr | srctype);
288 } else {
289 smr = at91_aic_read(AT91_AIC_SMR(d->hwirq))
290 & ~AT91_AIC_SRCTYPE;
291 at91_aic_write(AT91_AIC_SMR(d->hwirq), smr | srctype);
292 }
140 293
141 return 0; 294 return 0;
142} 295}
143 296
144void at91_irq_suspend(void)
145{
146 backups = at91_aic_read(AT91_AIC_IMR);
147 at91_aic_write(AT91_AIC_IDCR, backups);
148 at91_aic_write(AT91_AIC_IECR, wakeups);
149}
150
151void at91_irq_resume(void)
152{
153 at91_aic_write(AT91_AIC_IDCR, wakeups);
154 at91_aic_write(AT91_AIC_IECR, backups);
155}
156
157#else
158#define at91_aic_set_wake NULL
159#endif
160
161static struct irq_chip at91_aic_chip = { 297static struct irq_chip at91_aic_chip = {
162 .name = "AIC", 298 .name = "AIC",
163 .irq_mask = at91_aic_mask_irq, 299 .irq_mask = at91_aic_mask_irq,
@@ -193,6 +329,35 @@ static void __init at91_aic_hw_init(unsigned int spu_vector)
193 at91_aic_write(AT91_AIC_ICCR, 0xFFFFFFFF); 329 at91_aic_write(AT91_AIC_ICCR, 0xFFFFFFFF);
194} 330}
195 331
332static void __init __maybe_unused at91_aic5_hw_init(unsigned int spu_vector)
333{
334 int i;
335
336 /*
337 * Perform 8 End Of Interrupt Command to make sure AIC
338 * will not Lock out nIRQ
339 */
340 for (i = 0; i < 8; i++)
341 at91_aic_write(AT91_AIC5_EOICR, 0);
342
343 /*
344 * Spurious Interrupt ID in Spurious Vector Register.
345 * When there is no current interrupt, the IRQ Vector Register
346 * reads the value stored in AIC_SPU
347 */
348 at91_aic_write(AT91_AIC5_SPU, spu_vector);
349
350 /* No debugging in AIC: Debug (Protect) Control Register */
351 at91_aic_write(AT91_AIC5_DCR, 0);
352
353 /* Disable and clear all interrupts initially */
354 for (i = 0; i < n_irqs; i++) {
355 at91_aic_write(AT91_AIC5_SSR, i & AT91_AIC5_INTSEL_MSK);
356 at91_aic_write(AT91_AIC5_IDCR, 1);
357 at91_aic_write(AT91_AIC5_ICCR, 1);
358 }
359}
360
196#if defined(CONFIG_OF) 361#if defined(CONFIG_OF)
197static int at91_aic_irq_map(struct irq_domain *h, unsigned int virq, 362static int at91_aic_irq_map(struct irq_domain *h, unsigned int virq,
198 irq_hw_number_t hw) 363 irq_hw_number_t hw)
@@ -210,13 +375,31 @@ static int at91_aic_irq_map(struct irq_domain *h, unsigned int virq,
210 return 0; 375 return 0;
211} 376}
212 377
378static int at91_aic5_irq_map(struct irq_domain *h, unsigned int virq,
379 irq_hw_number_t hw)
380{
381 at91_aic_write(AT91_AIC5_SSR, hw & AT91_AIC5_INTSEL_MSK);
382
383 /* Put virq number in Source Vector Register */
384 at91_aic_write(AT91_AIC5_SVR, virq);
385
386 /* Active Low interrupt, with priority */
387 at91_aic_write(AT91_AIC5_SMR,
388 AT91_AIC_SRCTYPE_LOW | at91_aic_irq_priorities[hw]);
389
390 irq_set_chip_and_handler(virq, &at91_aic_chip, handle_fasteoi_irq);
391 set_irq_flags(virq, IRQF_VALID | IRQF_PROBE);
392
393 return 0;
394}
395
213static int at91_aic_irq_domain_xlate(struct irq_domain *d, struct device_node *ctrlr, 396static int at91_aic_irq_domain_xlate(struct irq_domain *d, struct device_node *ctrlr,
214 const u32 *intspec, unsigned int intsize, 397 const u32 *intspec, unsigned int intsize,
215 irq_hw_number_t *out_hwirq, unsigned int *out_type) 398 irq_hw_number_t *out_hwirq, unsigned int *out_type)
216{ 399{
217 if (WARN_ON(intsize < 3)) 400 if (WARN_ON(intsize < 3))
218 return -EINVAL; 401 return -EINVAL;
219 if (WARN_ON(intspec[0] >= NR_AIC_IRQS)) 402 if (WARN_ON(intspec[0] >= n_irqs))
220 return -EINVAL; 403 return -EINVAL;
221 if (WARN_ON((intspec[2] < AT91_AIC_IRQ_MIN_PRIORITY) 404 if (WARN_ON((intspec[2] < AT91_AIC_IRQ_MIN_PRIORITY)
222 || (intspec[2] > AT91_AIC_IRQ_MAX_PRIORITY))) 405 || (intspec[2] > AT91_AIC_IRQ_MAX_PRIORITY)))
@@ -234,14 +417,24 @@ static struct irq_domain_ops at91_aic_irq_ops = {
234 .xlate = at91_aic_irq_domain_xlate, 417 .xlate = at91_aic_irq_domain_xlate,
235}; 418};
236 419
237int __init at91_aic_of_init(struct device_node *node, 420int __init at91_aic_of_common_init(struct device_node *node,
238 struct device_node *parent) 421 struct device_node *parent)
239{ 422{
240 struct property *prop; 423 struct property *prop;
241 const __be32 *p; 424 const __be32 *p;
242 u32 val; 425 u32 val;
243 426
244 at91_aic_irq_priorities = kzalloc(NR_AIC_IRQS 427 at91_extern_irq = kzalloc(BITS_TO_LONGS(n_irqs)
428 * sizeof(*at91_extern_irq), GFP_KERNEL);
429 if (!at91_extern_irq)
430 return -ENOMEM;
431
432 if (at91_aic_pm_init()) {
433 kfree(at91_extern_irq);
434 return -ENOMEM;
435 }
436
437 at91_aic_irq_priorities = kzalloc(n_irqs
245 * sizeof(*at91_aic_irq_priorities), 438 * sizeof(*at91_aic_irq_priorities),
246 GFP_KERNEL); 439 GFP_KERNEL);
247 if (!at91_aic_irq_priorities) 440 if (!at91_aic_irq_priorities)
@@ -250,22 +443,56 @@ int __init at91_aic_of_init(struct device_node *node,
250 at91_aic_base = of_iomap(node, 0); 443 at91_aic_base = of_iomap(node, 0);
251 at91_aic_np = node; 444 at91_aic_np = node;
252 445
253 at91_aic_domain = irq_domain_add_linear(at91_aic_np, NR_AIC_IRQS, 446 at91_aic_domain = irq_domain_add_linear(at91_aic_np, n_irqs,
254 &at91_aic_irq_ops, NULL); 447 &at91_aic_irq_ops, NULL);
255 if (!at91_aic_domain) 448 if (!at91_aic_domain)
256 panic("Unable to add AIC irq domain (DT)\n"); 449 panic("Unable to add AIC irq domain (DT)\n");
257 450
258 at91_extern_irq = 0;
259 of_property_for_each_u32(node, "atmel,external-irqs", prop, p, val) { 451 of_property_for_each_u32(node, "atmel,external-irqs", prop, p, val) {
260 if (val > 31) 452 if (val >= n_irqs)
261 pr_warn("AIC: external irq %d > 31 skip it\n", val); 453 pr_warn("AIC: external irq %d >= %d skip it\n",
454 val, n_irqs);
262 else 455 else
263 at91_extern_irq |= (1 << val); 456 set_bit(val, at91_extern_irq);
264 } 457 }
265 458
266 irq_set_default_host(at91_aic_domain); 459 irq_set_default_host(at91_aic_domain);
267 460
268 at91_aic_hw_init(NR_AIC_IRQS); 461 return 0;
462}
463
464int __init at91_aic_of_init(struct device_node *node,
465 struct device_node *parent)
466{
467 int err;
468
469 err = at91_aic_of_common_init(node, parent);
470 if (err)
471 return err;
472
473 at91_aic_hw_init(n_irqs);
474
475 return 0;
476}
477
478int __init at91_aic5_of_init(struct device_node *node,
479 struct device_node *parent)
480{
481 int err;
482
483 at91_aic_caps |= AT91_AIC_CAP_AIC5;
484 n_irqs = NR_AIC5_IRQS;
485 at91_aic_chip.irq_ack = at91_aic5_mask_irq;
486 at91_aic_chip.irq_mask = at91_aic5_mask_irq;
487 at91_aic_chip.irq_unmask = at91_aic5_unmask_irq;
488 at91_aic_chip.irq_eoi = at91_aic5_eoi;
489 at91_aic_irq_ops.map = at91_aic5_irq_map;
490
491 err = at91_aic_of_common_init(node, parent);
492 if (err)
493 return err;
494
495 at91_aic5_hw_init(n_irqs);
269 496
270 return 0; 497 return 0;
271} 498}
@@ -274,22 +501,25 @@ int __init at91_aic_of_init(struct device_node *node,
274/* 501/*
275 * Initialize the AIC interrupt controller. 502 * Initialize the AIC interrupt controller.
276 */ 503 */
277void __init at91_aic_init(unsigned int priority[NR_AIC_IRQS]) 504void __init at91_aic_init(unsigned int *priority)
278{ 505{
279 unsigned int i; 506 unsigned int i;
280 int irq_base; 507 int irq_base;
281 508
509 if (at91_aic_pm_init())
510 panic("Unable to allocate bit maps\n");
511
282 at91_aic_base = ioremap(AT91_AIC, 512); 512 at91_aic_base = ioremap(AT91_AIC, 512);
283 if (!at91_aic_base) 513 if (!at91_aic_base)
284 panic("Unable to ioremap AIC registers\n"); 514 panic("Unable to ioremap AIC registers\n");
285 515
286 /* Add irq domain for AIC */ 516 /* Add irq domain for AIC */
287 irq_base = irq_alloc_descs(-1, 0, NR_AIC_IRQS, 0); 517 irq_base = irq_alloc_descs(-1, 0, n_irqs, 0);
288 if (irq_base < 0) { 518 if (irq_base < 0) {
289 WARN(1, "Cannot allocate irq_descs, assuming pre-allocated\n"); 519 WARN(1, "Cannot allocate irq_descs, assuming pre-allocated\n");
290 irq_base = 0; 520 irq_base = 0;
291 } 521 }
292 at91_aic_domain = irq_domain_add_legacy(at91_aic_np, NR_AIC_IRQS, 522 at91_aic_domain = irq_domain_add_legacy(at91_aic_np, n_irqs,
293 irq_base, 0, 523 irq_base, 0,
294 &irq_domain_simple_ops, NULL); 524 &irq_domain_simple_ops, NULL);
295 525
@@ -302,15 +532,14 @@ void __init at91_aic_init(unsigned int priority[NR_AIC_IRQS])
302 * The IVR is used by macro get_irqnr_and_base to read and verify. 532 * The IVR is used by macro get_irqnr_and_base to read and verify.
303 * The irq number is NR_AIC_IRQS when a spurious interrupt has occurred. 533 * The irq number is NR_AIC_IRQS when a spurious interrupt has occurred.
304 */ 534 */
305 for (i = 0; i < NR_AIC_IRQS; i++) { 535 for (i = 0; i < n_irqs; i++) {
306 /* Put hardware irq number in Source Vector Register: */ 536 /* Put hardware irq number in Source Vector Register: */
307 at91_aic_write(AT91_AIC_SVR(i), NR_IRQS_LEGACY + i); 537 at91_aic_write(AT91_AIC_SVR(i), NR_IRQS_LEGACY + i);
308 /* Active Low interrupt, with the specified priority */ 538 /* Active Low interrupt, with the specified priority */
309 at91_aic_write(AT91_AIC_SMR(i), AT91_AIC_SRCTYPE_LOW | priority[i]); 539 at91_aic_write(AT91_AIC_SMR(i), AT91_AIC_SRCTYPE_LOW | priority[i]);
310
311 irq_set_chip_and_handler(NR_IRQS_LEGACY + i, &at91_aic_chip, handle_fasteoi_irq); 540 irq_set_chip_and_handler(NR_IRQS_LEGACY + i, &at91_aic_chip, handle_fasteoi_irq);
312 set_irq_flags(i, IRQF_VALID | IRQF_PROBE); 541 set_irq_flags(i, IRQF_VALID | IRQF_PROBE);
313 } 542 }
314 543
315 at91_aic_hw_init(NR_AIC_IRQS); 544 at91_aic_hw_init(n_irqs);
316} 545}