diff options
-rw-r--r-- | arch/arm/mach-at91/generic.h | 2 | ||||
-rw-r--r-- | arch/arm/mach-at91/include/mach/at91_aic.h | 26 | ||||
-rw-r--r-- | arch/arm/mach-at91/irq.c | 343 |
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[]); | |||
29 | extern void __init at91_aic_init(unsigned int priority[]); | 29 | extern void __init at91_aic_init(unsigned int priority[]); |
30 | extern int __init at91_aic_of_init(struct device_node *node, | 30 | extern int __init at91_aic_of_init(struct device_node *node, |
31 | struct device_node *parent); | 31 | struct device_node *parent); |
32 | extern 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 | ||
71 | void at91_aic_handle_irq(struct pt_regs *regs); | 96 | void at91_aic_handle_irq(struct pt_regs *regs); |
97 | void 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 @@ | |||
46 | void __iomem *at91_aic_base; | 47 | void __iomem *at91_aic_base; |
47 | static struct irq_domain *at91_aic_domain; | 48 | static struct irq_domain *at91_aic_domain; |
48 | 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; | ||
49 | static unsigned int *at91_aic_irq_priorities; | 52 | static unsigned int *at91_aic_irq_priorities; |
50 | 53 | ||
51 | asmlinkage 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 | |||
60 | static unsigned long *wakeups; | ||
61 | static unsigned long *backups; | ||
62 | |||
63 | #define set_backup(bit) set_bit(bit, backups) | ||
64 | #define clear_backup(bit) clear_bit(bit, backups) | ||
65 | |||
66 | static 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 | |||
81 | static 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 | |||
94 | void 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 | |||
120 | void 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 | ||
147 | static 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 | |||
158 | asmlinkage void __exception_irq_entry | ||
159 | at91_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 | ||
177 | asmlinkage void __exception_irq_entry | ||
178 | at91_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 | |||
69 | static void at91_aic_mask_irq(struct irq_data *d) | 192 | static 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 | |||
200 | static 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 | ||
75 | static void at91_aic_unmask_irq(struct irq_data *d) | 209 | static 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 | |||
217 | static 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 | ||
81 | static void at91_aic_eoi(struct irq_data *d) | 226 | static 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 | ||
90 | unsigned int at91_extern_irq; | 235 | static 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) | 240 | unsigned long *at91_extern_irq; |
93 | 241 | ||
94 | static int at91_aic_set_type(struct irq_data *d, unsigned type) | 242 | #define is_extern_irq(hwirq) test_bit(hwirq, at91_extern_irq) |
243 | |||
244 | static 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 | 274 | static int at91_aic_set_type(struct irq_data *d, unsigned type) |
127 | |||
128 | static u32 wakeups; | ||
129 | static u32 backups; | ||
130 | |||
131 | static 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 | ||
144 | void 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 | |||
151 | void 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 | |||
161 | static struct irq_chip at91_aic_chip = { | 297 | static 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 | ||
332 | static 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) |
197 | static int at91_aic_irq_map(struct irq_domain *h, unsigned int virq, | 362 | static 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 | ||
378 | static 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 | |||
213 | static int at91_aic_irq_domain_xlate(struct irq_domain *d, struct device_node *ctrlr, | 396 | static 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 | ||
237 | int __init at91_aic_of_init(struct device_node *node, | 420 | int __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 | |||
464 | int __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 | |||
478 | int __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 | */ |
277 | void __init at91_aic_init(unsigned int priority[NR_AIC_IRQS]) | 504 | void __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 | } |