diff options
author | Manuel Lauss <mano@roarinelk.homelinux.net> | 2008-12-21 03:26:17 -0500 |
---|---|---|
committer | Ralf Baechle <ralf@linux-mips.org> | 2009-01-11 04:57:26 -0500 |
commit | 785e3268e2951d4c0c21417c8e5d8004b2ab2480 (patch) | |
tree | 3e7e98dbaf2592f22f65090325a823d36caa13f7 /arch/mips/alchemy/common/irq.c | |
parent | 7179380ee9bdeb5fa2ff07581f512fe0f5382e5b (diff) |
MIPS: Alchemy: update core interrupt code.
This patch attempts to modernize core Alchemy interrupt handling code.
- add irq_chips for irq controllers instead of irq type,
- add a set_type() hook to change irq trigger type during runtime,
- add a set_wake() hook to control GPIO0..7 based wakeup,
- use linux' IRQF_TRIGGER_ constants instead of homebrew ones,
- enable GENERIC_HARDIRQS_NO__DO_IRQ.
- simplify plat_irq_dispatch
- merge au1xxx_irqmap into irq.c file, the only place where its
contents are referenced.
- board_init_irq() is now mandatory for every board; use it to register
the remaining (gpio-based) interrupt sources; update all boards
accordingly.
Run-tested on Db1200 and other Au1200 based platforms.
Signed-off-by: Manuel Lauss <mano@roarinelk.homelinux.net>
Signed-off-by: Ralf Baechle <ralf@linux-mips.org>
delete mode 100644 arch/mips/alchemy/common/au1xxx_irqmap.c
Diffstat (limited to 'arch/mips/alchemy/common/irq.c')
-rw-r--r-- | arch/mips/alchemy/common/irq.c | 785 |
1 files changed, 422 insertions, 363 deletions
diff --git a/arch/mips/alchemy/common/irq.c b/arch/mips/alchemy/common/irq.c index 40c6ceceb5f9..c54384779fb9 100644 --- a/arch/mips/alchemy/common/irq.c +++ b/arch/mips/alchemy/common/irq.c | |||
@@ -24,6 +24,7 @@ | |||
24 | * with this program; if not, write to the Free Software Foundation, Inc., | 24 | * with this program; if not, write to the Free Software Foundation, Inc., |
25 | * 675 Mass Ave, Cambridge, MA 02139, USA. | 25 | * 675 Mass Ave, Cambridge, MA 02139, USA. |
26 | */ | 26 | */ |
27 | |||
27 | #include <linux/bitops.h> | 28 | #include <linux/bitops.h> |
28 | #include <linux/init.h> | 29 | #include <linux/init.h> |
29 | #include <linux/interrupt.h> | 30 | #include <linux/interrupt.h> |
@@ -36,15 +37,174 @@ | |||
36 | #include <asm/mach-pb1x00/pb1000.h> | 37 | #include <asm/mach-pb1x00/pb1000.h> |
37 | #endif | 38 | #endif |
38 | 39 | ||
39 | #define EXT_INTC0_REQ0 2 /* IP 2 */ | 40 | static DEFINE_SPINLOCK(irq_lock); |
40 | #define EXT_INTC0_REQ1 3 /* IP 3 */ | ||
41 | #define EXT_INTC1_REQ0 4 /* IP 4 */ | ||
42 | #define EXT_INTC1_REQ1 5 /* IP 5 */ | ||
43 | #define MIPS_TIMER_IP 7 /* IP 7 */ | ||
44 | 41 | ||
45 | void (*board_init_irq)(void) __initdata = NULL; | 42 | static int au1x_ic_settype(unsigned int irq, unsigned int flow_type); |
43 | |||
44 | /* per-processor fixed function irqs */ | ||
45 | struct au1xxx_irqmap au1xxx_ic0_map[] __initdata = { | ||
46 | |||
47 | #if defined(CONFIG_SOC_AU1000) | ||
48 | { AU1000_UART0_INT, IRQ_TYPE_LEVEL_HIGH, 0 }, | ||
49 | { AU1000_UART1_INT, IRQ_TYPE_LEVEL_HIGH, 0 }, | ||
50 | { AU1000_UART2_INT, IRQ_TYPE_LEVEL_HIGH, 0 }, | ||
51 | { AU1000_UART3_INT, IRQ_TYPE_LEVEL_HIGH, 0 }, | ||
52 | { AU1000_SSI0_INT, IRQ_TYPE_LEVEL_HIGH, 0 }, | ||
53 | { AU1000_SSI1_INT, IRQ_TYPE_LEVEL_HIGH, 0 }, | ||
54 | { AU1000_DMA_INT_BASE, IRQ_TYPE_LEVEL_HIGH, 0 }, | ||
55 | { AU1000_DMA_INT_BASE+1, IRQ_TYPE_LEVEL_HIGH, 0 }, | ||
56 | { AU1000_DMA_INT_BASE+2, IRQ_TYPE_LEVEL_HIGH, 0 }, | ||
57 | { AU1000_DMA_INT_BASE+3, IRQ_TYPE_LEVEL_HIGH, 0 }, | ||
58 | { AU1000_DMA_INT_BASE+4, IRQ_TYPE_LEVEL_HIGH, 0 }, | ||
59 | { AU1000_DMA_INT_BASE+5, IRQ_TYPE_LEVEL_HIGH, 0 }, | ||
60 | { AU1000_DMA_INT_BASE+6, IRQ_TYPE_LEVEL_HIGH, 0 }, | ||
61 | { AU1000_DMA_INT_BASE+7, IRQ_TYPE_LEVEL_HIGH, 0 }, | ||
62 | { AU1000_TOY_INT, IRQ_TYPE_EDGE_RISING, 0 }, | ||
63 | { AU1000_TOY_MATCH0_INT, IRQ_TYPE_EDGE_RISING, 0 }, | ||
64 | { AU1000_TOY_MATCH1_INT, IRQ_TYPE_EDGE_RISING, 0 }, | ||
65 | { AU1000_TOY_MATCH2_INT, IRQ_TYPE_EDGE_RISING, 1 }, | ||
66 | { AU1000_RTC_INT, IRQ_TYPE_EDGE_RISING, 0 }, | ||
67 | { AU1000_RTC_MATCH0_INT, IRQ_TYPE_EDGE_RISING, 0 }, | ||
68 | { AU1000_RTC_MATCH1_INT, IRQ_TYPE_EDGE_RISING, 0 }, | ||
69 | { AU1000_RTC_MATCH2_INT, IRQ_TYPE_EDGE_RISING, 0 }, | ||
70 | { AU1000_IRDA_TX_INT, IRQ_TYPE_LEVEL_HIGH, 0 }, | ||
71 | { AU1000_IRDA_RX_INT, IRQ_TYPE_LEVEL_HIGH, 0 }, | ||
72 | { AU1000_USB_DEV_REQ_INT, IRQ_TYPE_LEVEL_HIGH, 0 }, | ||
73 | { AU1000_USB_DEV_SUS_INT, IRQ_TYPE_EDGE_RISING, 0 }, | ||
74 | { AU1000_USB_HOST_INT, IRQ_TYPE_LEVEL_LOW, 0 }, | ||
75 | { AU1000_ACSYNC_INT, IRQ_TYPE_EDGE_RISING, 0 }, | ||
76 | { AU1000_MAC0_DMA_INT, IRQ_TYPE_LEVEL_HIGH, 0 }, | ||
77 | { AU1000_MAC1_DMA_INT, IRQ_TYPE_LEVEL_HIGH, 0 }, | ||
78 | { AU1000_AC97C_INT, IRQ_TYPE_EDGE_RISING, 0 }, | ||
79 | |||
80 | #elif defined(CONFIG_SOC_AU1500) | ||
81 | |||
82 | { AU1500_UART0_INT, IRQ_TYPE_LEVEL_HIGH, 0 }, | ||
83 | { AU1000_PCI_INTA, IRQ_TYPE_LEVEL_LOW, 0 }, | ||
84 | { AU1000_PCI_INTB, IRQ_TYPE_LEVEL_LOW, 0 }, | ||
85 | { AU1500_UART3_INT, IRQ_TYPE_LEVEL_HIGH, 0 }, | ||
86 | { AU1000_PCI_INTC, IRQ_TYPE_LEVEL_LOW, 0 }, | ||
87 | { AU1000_PCI_INTD, IRQ_TYPE_LEVEL_LOW, 0 }, | ||
88 | { AU1000_DMA_INT_BASE, IRQ_TYPE_LEVEL_HIGH, 0 }, | ||
89 | { AU1000_DMA_INT_BASE+1, IRQ_TYPE_LEVEL_HIGH, 0 }, | ||
90 | { AU1000_DMA_INT_BASE+2, IRQ_TYPE_LEVEL_HIGH, 0 }, | ||
91 | { AU1000_DMA_INT_BASE+3, IRQ_TYPE_LEVEL_HIGH, 0 }, | ||
92 | { AU1000_DMA_INT_BASE+4, IRQ_TYPE_LEVEL_HIGH, 0 }, | ||
93 | { AU1000_DMA_INT_BASE+5, IRQ_TYPE_LEVEL_HIGH, 0 }, | ||
94 | { AU1000_DMA_INT_BASE+6, IRQ_TYPE_LEVEL_HIGH, 0 }, | ||
95 | { AU1000_DMA_INT_BASE+7, IRQ_TYPE_LEVEL_HIGH, 0 }, | ||
96 | { AU1000_TOY_INT, IRQ_TYPE_EDGE_RISING, 0 }, | ||
97 | { AU1000_TOY_MATCH0_INT, IRQ_TYPE_EDGE_RISING, 0 }, | ||
98 | { AU1000_TOY_MATCH1_INT, IRQ_TYPE_EDGE_RISING, 0 }, | ||
99 | { AU1000_TOY_MATCH2_INT, IRQ_TYPE_EDGE_RISING, 1 }, | ||
100 | { AU1000_RTC_INT, IRQ_TYPE_EDGE_RISING, 0 }, | ||
101 | { AU1000_RTC_MATCH0_INT, IRQ_TYPE_EDGE_RISING, 0 }, | ||
102 | { AU1000_RTC_MATCH1_INT, IRQ_TYPE_EDGE_RISING, 0 }, | ||
103 | { AU1000_RTC_MATCH2_INT, IRQ_TYPE_EDGE_RISING, 0 }, | ||
104 | { AU1000_USB_DEV_REQ_INT, IRQ_TYPE_LEVEL_HIGH, 0 }, | ||
105 | { AU1000_USB_DEV_SUS_INT, IRQ_TYPE_EDGE_RISING, 0 }, | ||
106 | { AU1000_USB_HOST_INT, IRQ_TYPE_LEVEL_LOW, 0 }, | ||
107 | { AU1000_ACSYNC_INT, IRQ_TYPE_EDGE_RISING, 0 }, | ||
108 | { AU1500_MAC0_DMA_INT, IRQ_TYPE_LEVEL_HIGH, 0 }, | ||
109 | { AU1500_MAC1_DMA_INT, IRQ_TYPE_LEVEL_HIGH, 0 }, | ||
110 | { AU1000_AC97C_INT, IRQ_TYPE_EDGE_RISING, 0 }, | ||
111 | |||
112 | #elif defined(CONFIG_SOC_AU1100) | ||
113 | |||
114 | { AU1100_UART0_INT, IRQ_TYPE_LEVEL_HIGH, 0 }, | ||
115 | { AU1100_UART1_INT, IRQ_TYPE_LEVEL_HIGH, 0 }, | ||
116 | { AU1100_SD_INT, IRQ_TYPE_LEVEL_HIGH, 0 }, | ||
117 | { AU1100_UART3_INT, IRQ_TYPE_LEVEL_HIGH, 0 }, | ||
118 | { AU1000_SSI0_INT, IRQ_TYPE_LEVEL_HIGH, 0 }, | ||
119 | { AU1000_SSI1_INT, IRQ_TYPE_LEVEL_HIGH, 0 }, | ||
120 | { AU1000_DMA_INT_BASE, IRQ_TYPE_LEVEL_HIGH, 0 }, | ||
121 | { AU1000_DMA_INT_BASE+1, IRQ_TYPE_LEVEL_HIGH, 0 }, | ||
122 | { AU1000_DMA_INT_BASE+2, IRQ_TYPE_LEVEL_HIGH, 0 }, | ||
123 | { AU1000_DMA_INT_BASE+3, IRQ_TYPE_LEVEL_HIGH, 0 }, | ||
124 | { AU1000_DMA_INT_BASE+4, IRQ_TYPE_LEVEL_HIGH, 0 }, | ||
125 | { AU1000_DMA_INT_BASE+5, IRQ_TYPE_LEVEL_HIGH, 0 }, | ||
126 | { AU1000_DMA_INT_BASE+6, IRQ_TYPE_LEVEL_HIGH, 0 }, | ||
127 | { AU1000_DMA_INT_BASE+7, IRQ_TYPE_LEVEL_HIGH, 0 }, | ||
128 | { AU1000_TOY_INT, IRQ_TYPE_EDGE_RISING, 0 }, | ||
129 | { AU1000_TOY_MATCH0_INT, IRQ_TYPE_EDGE_RISING, 0 }, | ||
130 | { AU1000_TOY_MATCH1_INT, IRQ_TYPE_EDGE_RISING, 0 }, | ||
131 | { AU1000_TOY_MATCH2_INT, IRQ_TYPE_EDGE_RISING, 1 }, | ||
132 | { AU1000_RTC_INT, IRQ_TYPE_EDGE_RISING, 0 }, | ||
133 | { AU1000_RTC_MATCH0_INT, IRQ_TYPE_EDGE_RISING, 0 }, | ||
134 | { AU1000_RTC_MATCH1_INT, IRQ_TYPE_EDGE_RISING, 0 }, | ||
135 | { AU1000_RTC_MATCH2_INT, IRQ_TYPE_EDGE_RISING, 0 }, | ||
136 | { AU1000_IRDA_TX_INT, IRQ_TYPE_LEVEL_HIGH, 0 }, | ||
137 | { AU1000_IRDA_RX_INT, IRQ_TYPE_LEVEL_HIGH, 0 }, | ||
138 | { AU1000_USB_DEV_REQ_INT, IRQ_TYPE_LEVEL_HIGH, 0 }, | ||
139 | { AU1000_USB_DEV_SUS_INT, IRQ_TYPE_EDGE_RISING, 0 }, | ||
140 | { AU1000_USB_HOST_INT, IRQ_TYPE_LEVEL_LOW, 0 }, | ||
141 | { AU1000_ACSYNC_INT, IRQ_TYPE_EDGE_RISING, 0 }, | ||
142 | { AU1100_MAC0_DMA_INT, IRQ_TYPE_LEVEL_HIGH, 0 }, | ||
143 | { AU1100_LCD_INT, IRQ_TYPE_LEVEL_HIGH, 0 }, | ||
144 | { AU1000_AC97C_INT, IRQ_TYPE_EDGE_RISING, 0 }, | ||
145 | |||
146 | #elif defined(CONFIG_SOC_AU1550) | ||
147 | |||
148 | { AU1550_UART0_INT, IRQ_TYPE_LEVEL_HIGH, 0 }, | ||
149 | { AU1550_PCI_INTA, IRQ_TYPE_LEVEL_LOW, 0 }, | ||
150 | { AU1550_PCI_INTB, IRQ_TYPE_LEVEL_LOW, 0 }, | ||
151 | { AU1550_DDMA_INT, IRQ_TYPE_LEVEL_HIGH, 0 }, | ||
152 | { AU1550_CRYPTO_INT, IRQ_TYPE_LEVEL_HIGH, 0 }, | ||
153 | { AU1550_PCI_INTC, IRQ_TYPE_LEVEL_LOW, 0 }, | ||
154 | { AU1550_PCI_INTD, IRQ_TYPE_LEVEL_LOW, 0 }, | ||
155 | { AU1550_PCI_RST_INT, IRQ_TYPE_LEVEL_LOW, 0 }, | ||
156 | { AU1550_UART1_INT, IRQ_TYPE_LEVEL_HIGH, 0 }, | ||
157 | { AU1550_UART3_INT, IRQ_TYPE_LEVEL_HIGH, 0 }, | ||
158 | { AU1550_PSC0_INT, IRQ_TYPE_LEVEL_HIGH, 0 }, | ||
159 | { AU1550_PSC1_INT, IRQ_TYPE_LEVEL_HIGH, 0 }, | ||
160 | { AU1550_PSC2_INT, IRQ_TYPE_LEVEL_HIGH, 0 }, | ||
161 | { AU1550_PSC3_INT, IRQ_TYPE_LEVEL_HIGH, 0 }, | ||
162 | { AU1000_TOY_INT, IRQ_TYPE_EDGE_RISING, 0 }, | ||
163 | { AU1000_TOY_MATCH0_INT, IRQ_TYPE_EDGE_RISING, 0 }, | ||
164 | { AU1000_TOY_MATCH1_INT, IRQ_TYPE_EDGE_RISING, 0 }, | ||
165 | { AU1000_TOY_MATCH2_INT, IRQ_TYPE_EDGE_RISING, 1 }, | ||
166 | { AU1000_RTC_INT, IRQ_TYPE_EDGE_RISING, 0 }, | ||
167 | { AU1000_RTC_MATCH0_INT, IRQ_TYPE_EDGE_RISING, 0 }, | ||
168 | { AU1000_RTC_MATCH1_INT, IRQ_TYPE_EDGE_RISING, 0 }, | ||
169 | { AU1000_RTC_MATCH2_INT, IRQ_TYPE_EDGE_RISING, 0 }, | ||
170 | { AU1550_NAND_INT, IRQ_TYPE_EDGE_RISING, 0 }, | ||
171 | { AU1550_USB_DEV_REQ_INT, IRQ_TYPE_LEVEL_HIGH, 0 }, | ||
172 | { AU1550_USB_DEV_SUS_INT, IRQ_TYPE_EDGE_RISING, 0 }, | ||
173 | { AU1550_USB_HOST_INT, IRQ_TYPE_LEVEL_LOW, 0 }, | ||
174 | { AU1550_MAC0_DMA_INT, IRQ_TYPE_LEVEL_HIGH, 0 }, | ||
175 | { AU1550_MAC1_DMA_INT, IRQ_TYPE_LEVEL_HIGH, 0 }, | ||
176 | |||
177 | #elif defined(CONFIG_SOC_AU1200) | ||
178 | |||
179 | { AU1200_UART0_INT, IRQ_TYPE_LEVEL_HIGH, 0 }, | ||
180 | { AU1200_SWT_INT, IRQ_TYPE_EDGE_RISING, 0 }, | ||
181 | { AU1200_SD_INT, IRQ_TYPE_LEVEL_HIGH, 0 }, | ||
182 | { AU1200_DDMA_INT, IRQ_TYPE_LEVEL_HIGH, 0 }, | ||
183 | { AU1200_MAE_BE_INT, IRQ_TYPE_LEVEL_HIGH, 0 }, | ||
184 | { AU1200_UART1_INT, IRQ_TYPE_LEVEL_HIGH, 0 }, | ||
185 | { AU1200_MAE_FE_INT, IRQ_TYPE_LEVEL_HIGH, 0 }, | ||
186 | { AU1200_PSC0_INT, IRQ_TYPE_LEVEL_HIGH, 0 }, | ||
187 | { AU1200_PSC1_INT, IRQ_TYPE_LEVEL_HIGH, 0 }, | ||
188 | { AU1200_AES_INT, IRQ_TYPE_LEVEL_HIGH, 0 }, | ||
189 | { AU1200_CAMERA_INT, IRQ_TYPE_LEVEL_HIGH, 0 }, | ||
190 | { AU1000_TOY_INT, IRQ_TYPE_EDGE_RISING, 0 }, | ||
191 | { AU1000_TOY_MATCH0_INT, IRQ_TYPE_EDGE_RISING, 0 }, | ||
192 | { AU1000_TOY_MATCH1_INT, IRQ_TYPE_EDGE_RISING, 0 }, | ||
193 | { AU1000_TOY_MATCH2_INT, IRQ_TYPE_EDGE_RISING, 1 }, | ||
194 | { AU1000_RTC_INT, IRQ_TYPE_EDGE_RISING, 0 }, | ||
195 | { AU1000_RTC_MATCH0_INT, IRQ_TYPE_EDGE_RISING, 0 }, | ||
196 | { AU1000_RTC_MATCH1_INT, IRQ_TYPE_EDGE_RISING, 0 }, | ||
197 | { AU1000_RTC_MATCH2_INT, IRQ_TYPE_EDGE_RISING, 0 }, | ||
198 | { AU1200_NAND_INT, IRQ_TYPE_EDGE_RISING, 0 }, | ||
199 | { AU1200_USB_INT, IRQ_TYPE_LEVEL_HIGH, 0 }, | ||
200 | { AU1200_LCD_INT, IRQ_TYPE_LEVEL_HIGH, 0 }, | ||
201 | { AU1200_MAE_BOTH_INT, IRQ_TYPE_LEVEL_HIGH, 0 }, | ||
202 | |||
203 | #else | ||
204 | #error "Error: Unknown Alchemy SOC" | ||
205 | #endif | ||
206 | }; | ||
46 | 207 | ||
47 | static DEFINE_SPINLOCK(irq_lock); | ||
48 | 208 | ||
49 | #ifdef CONFIG_PM | 209 | #ifdef CONFIG_PM |
50 | 210 | ||
@@ -130,67 +290,47 @@ void restore_au1xxx_intctl(void) | |||
130 | #endif /* CONFIG_PM */ | 290 | #endif /* CONFIG_PM */ |
131 | 291 | ||
132 | 292 | ||
133 | inline void local_enable_irq(unsigned int irq_nr) | 293 | static void au1x_ic0_unmask(unsigned int irq_nr) |
134 | { | 294 | { |
135 | unsigned int bit = irq_nr - AU1000_INTC0_INT_BASE; | 295 | unsigned int bit = irq_nr - AU1000_INTC0_INT_BASE; |
136 | 296 | au_writel(1 << bit, IC0_MASKSET); | |
137 | if (bit >= 32) { | 297 | au_writel(1 << bit, IC0_WAKESET); |
138 | au_writel(1 << (bit - 32), IC1_MASKSET); | ||
139 | au_writel(1 << (bit - 32), IC1_WAKESET); | ||
140 | } else { | ||
141 | au_writel(1 << bit, IC0_MASKSET); | ||
142 | au_writel(1 << bit, IC0_WAKESET); | ||
143 | } | ||
144 | au_sync(); | 298 | au_sync(); |
145 | } | 299 | } |
146 | 300 | ||
147 | 301 | static void au1x_ic1_unmask(unsigned int irq_nr) | |
148 | inline void local_disable_irq(unsigned int irq_nr) | ||
149 | { | 302 | { |
150 | unsigned int bit = irq_nr - AU1000_INTC0_INT_BASE; | 303 | unsigned int bit = irq_nr - AU1000_INTC1_INT_BASE; |
304 | au_writel(1 << bit, IC1_MASKSET); | ||
305 | au_writel(1 << bit, IC1_WAKESET); | ||
151 | 306 | ||
152 | if (bit >= 32) { | 307 | /* very hacky. does the pb1000 cpld auto-disable this int? |
153 | au_writel(1 << (bit - 32), IC1_MASKCLR); | 308 | * nowhere in the current kernel sources is it disabled. --mlau |
154 | au_writel(1 << (bit - 32), IC1_WAKECLR); | 309 | */ |
155 | } else { | 310 | #if defined(CONFIG_MIPS_PB1000) |
156 | au_writel(1 << bit, IC0_MASKCLR); | 311 | if (irq_nr == AU1000_GPIO_15) |
157 | au_writel(1 << bit, IC0_WAKECLR); | 312 | au_writel(0x4000, PB1000_MDR); /* enable int */ |
158 | } | 313 | #endif |
159 | au_sync(); | 314 | au_sync(); |
160 | } | 315 | } |
161 | 316 | ||
162 | 317 | static void au1x_ic0_mask(unsigned int irq_nr) | |
163 | static inline void mask_and_ack_rise_edge_irq(unsigned int irq_nr) | ||
164 | { | 318 | { |
165 | unsigned int bit = irq_nr - AU1000_INTC0_INT_BASE; | 319 | unsigned int bit = irq_nr - AU1000_INTC0_INT_BASE; |
166 | 320 | au_writel(1 << bit, IC0_MASKCLR); | |
167 | if (bit >= 32) { | 321 | au_writel(1 << bit, IC0_WAKECLR); |
168 | au_writel(1 << (bit - 32), IC1_RISINGCLR); | ||
169 | au_writel(1 << (bit - 32), IC1_MASKCLR); | ||
170 | } else { | ||
171 | au_writel(1 << bit, IC0_RISINGCLR); | ||
172 | au_writel(1 << bit, IC0_MASKCLR); | ||
173 | } | ||
174 | au_sync(); | 322 | au_sync(); |
175 | } | 323 | } |
176 | 324 | ||
177 | 325 | static void au1x_ic1_mask(unsigned int irq_nr) | |
178 | static inline void mask_and_ack_fall_edge_irq(unsigned int irq_nr) | ||
179 | { | 326 | { |
180 | unsigned int bit = irq_nr - AU1000_INTC0_INT_BASE; | 327 | unsigned int bit = irq_nr - AU1000_INTC1_INT_BASE; |
181 | 328 | au_writel(1 << bit, IC1_MASKCLR); | |
182 | if (bit >= 32) { | 329 | au_writel(1 << bit, IC1_WAKECLR); |
183 | au_writel(1 << (bit - 32), IC1_FALLINGCLR); | ||
184 | au_writel(1 << (bit - 32), IC1_MASKCLR); | ||
185 | } else { | ||
186 | au_writel(1 << bit, IC0_FALLINGCLR); | ||
187 | au_writel(1 << bit, IC0_MASKCLR); | ||
188 | } | ||
189 | au_sync(); | 330 | au_sync(); |
190 | } | 331 | } |
191 | 332 | ||
192 | 333 | static void au1x_ic0_ack(unsigned int irq_nr) | |
193 | static inline void mask_and_ack_either_edge_irq(unsigned int irq_nr) | ||
194 | { | 334 | { |
195 | unsigned int bit = irq_nr - AU1000_INTC0_INT_BASE; | 335 | unsigned int bit = irq_nr - AU1000_INTC0_INT_BASE; |
196 | 336 | ||
@@ -198,349 +338,229 @@ static inline void mask_and_ack_either_edge_irq(unsigned int irq_nr) | |||
198 | * This may assume that we don't get interrupts from | 338 | * This may assume that we don't get interrupts from |
199 | * both edges at once, or if we do, that we don't care. | 339 | * both edges at once, or if we do, that we don't care. |
200 | */ | 340 | */ |
201 | if (bit >= 32) { | 341 | au_writel(1 << bit, IC0_FALLINGCLR); |
202 | au_writel(1 << (bit - 32), IC1_FALLINGCLR); | 342 | au_writel(1 << bit, IC0_RISINGCLR); |
203 | au_writel(1 << (bit - 32), IC1_RISINGCLR); | ||
204 | au_writel(1 << (bit - 32), IC1_MASKCLR); | ||
205 | } else { | ||
206 | au_writel(1 << bit, IC0_FALLINGCLR); | ||
207 | au_writel(1 << bit, IC0_RISINGCLR); | ||
208 | au_writel(1 << bit, IC0_MASKCLR); | ||
209 | } | ||
210 | au_sync(); | 343 | au_sync(); |
211 | } | 344 | } |
212 | 345 | ||
213 | static inline void mask_and_ack_level_irq(unsigned int irq_nr) | 346 | static void au1x_ic1_ack(unsigned int irq_nr) |
214 | { | ||
215 | local_disable_irq(irq_nr); | ||
216 | au_sync(); | ||
217 | #if defined(CONFIG_MIPS_PB1000) | ||
218 | if (irq_nr == AU1000_GPIO_15) { | ||
219 | au_writel(0x8000, PB1000_MDR); /* ack int */ | ||
220 | au_sync(); | ||
221 | } | ||
222 | #endif | ||
223 | } | ||
224 | |||
225 | static void end_irq(unsigned int irq_nr) | ||
226 | { | 347 | { |
227 | if (!(irq_desc[irq_nr].status & (IRQ_DISABLED | IRQ_INPROGRESS))) | 348 | unsigned int bit = irq_nr - AU1000_INTC1_INT_BASE; |
228 | local_enable_irq(irq_nr); | ||
229 | |||
230 | #if defined(CONFIG_MIPS_PB1000) | ||
231 | if (irq_nr == AU1000_GPIO_15) { | ||
232 | au_writel(0x4000, PB1000_MDR); /* enable int */ | ||
233 | au_sync(); | ||
234 | } | ||
235 | #endif | ||
236 | } | ||
237 | |||
238 | unsigned long save_local_and_disable(int controller) | ||
239 | { | ||
240 | int i; | ||
241 | unsigned long flags, mask; | ||
242 | |||
243 | spin_lock_irqsave(&irq_lock, flags); | ||
244 | if (controller) { | ||
245 | mask = au_readl(IC1_MASKSET); | ||
246 | for (i = 32; i < 64; i++) | ||
247 | local_disable_irq(i); | ||
248 | } else { | ||
249 | mask = au_readl(IC0_MASKSET); | ||
250 | for (i = 0; i < 32; i++) | ||
251 | local_disable_irq(i); | ||
252 | } | ||
253 | spin_unlock_irqrestore(&irq_lock, flags); | ||
254 | 349 | ||
255 | return mask; | 350 | /* |
351 | * This may assume that we don't get interrupts from | ||
352 | * both edges at once, or if we do, that we don't care. | ||
353 | */ | ||
354 | au_writel(1 << bit, IC1_FALLINGCLR); | ||
355 | au_writel(1 << bit, IC1_RISINGCLR); | ||
356 | au_sync(); | ||
256 | } | 357 | } |
257 | 358 | ||
258 | void restore_local_and_enable(int controller, unsigned long mask) | 359 | static int au1x_ic1_setwake(unsigned int irq, unsigned int on) |
259 | { | 360 | { |
260 | int i; | 361 | unsigned int bit = irq - AU1000_INTC1_INT_BASE; |
261 | unsigned long flags, new_mask; | 362 | unsigned long wakemsk, flags; |
262 | 363 | ||
263 | spin_lock_irqsave(&irq_lock, flags); | 364 | /* only GPIO 0-7 can act as wakeup source: */ |
264 | for (i = 0; i < 32; i++) | 365 | if ((irq < AU1000_GPIO_0) || (irq > AU1000_GPIO_7)) |
265 | if (mask & (1 << i)) { | 366 | return -EINVAL; |
266 | if (controller) | ||
267 | local_enable_irq(i + 32); | ||
268 | else | ||
269 | local_enable_irq(i); | ||
270 | } | ||
271 | 367 | ||
272 | if (controller) | 368 | local_irq_save(flags); |
273 | new_mask = au_readl(IC1_MASKSET); | 369 | wakemsk = au_readl(SYS_WAKEMSK); |
370 | if (on) | ||
371 | wakemsk |= 1 << bit; | ||
274 | else | 372 | else |
275 | new_mask = au_readl(IC0_MASKSET); | 373 | wakemsk &= ~(1 << bit); |
374 | au_writel(wakemsk, SYS_WAKEMSK); | ||
375 | au_sync(); | ||
376 | local_irq_restore(flags); | ||
276 | 377 | ||
277 | spin_unlock_irqrestore(&irq_lock, flags); | 378 | return 0; |
278 | } | 379 | } |
279 | 380 | ||
280 | 381 | /* | |
281 | static struct irq_chip rise_edge_irq_type = { | 382 | * irq_chips for both ICs; this way the mask handlers can be |
282 | .name = "Au1000 Rise Edge", | 383 | * as short as possible. |
283 | .ack = mask_and_ack_rise_edge_irq, | 384 | * |
284 | .mask = local_disable_irq, | 385 | * NOTE: the ->ack() callback is used by the handle_edge_irq |
285 | .mask_ack = mask_and_ack_rise_edge_irq, | 386 | * flowhandler only, the ->mask_ack() one by handle_level_irq, |
286 | .unmask = local_enable_irq, | 387 | * so no need for an irq_chip for each type of irq (level/edge). |
287 | .end = end_irq, | 388 | */ |
288 | }; | 389 | static struct irq_chip au1x_ic0_chip = { |
289 | 390 | .name = "Alchemy-IC0", | |
290 | static struct irq_chip fall_edge_irq_type = { | 391 | .ack = au1x_ic0_ack, /* edge */ |
291 | .name = "Au1000 Fall Edge", | 392 | .mask = au1x_ic0_mask, |
292 | .ack = mask_and_ack_fall_edge_irq, | 393 | .mask_ack = au1x_ic0_mask, /* level */ |
293 | .mask = local_disable_irq, | 394 | .unmask = au1x_ic0_unmask, |
294 | .mask_ack = mask_and_ack_fall_edge_irq, | 395 | .set_type = au1x_ic_settype, |
295 | .unmask = local_enable_irq, | ||
296 | .end = end_irq, | ||
297 | }; | ||
298 | |||
299 | static struct irq_chip either_edge_irq_type = { | ||
300 | .name = "Au1000 Rise or Fall Edge", | ||
301 | .ack = mask_and_ack_either_edge_irq, | ||
302 | .mask = local_disable_irq, | ||
303 | .mask_ack = mask_and_ack_either_edge_irq, | ||
304 | .unmask = local_enable_irq, | ||
305 | .end = end_irq, | ||
306 | }; | 396 | }; |
307 | 397 | ||
308 | static struct irq_chip level_irq_type = { | 398 | static struct irq_chip au1x_ic1_chip = { |
309 | .name = "Au1000 Level", | 399 | .name = "Alchemy-IC1", |
310 | .ack = mask_and_ack_level_irq, | 400 | .ack = au1x_ic1_ack, /* edge */ |
311 | .mask = local_disable_irq, | 401 | .mask = au1x_ic1_mask, |
312 | .mask_ack = mask_and_ack_level_irq, | 402 | .mask_ack = au1x_ic1_mask, /* level */ |
313 | .unmask = local_enable_irq, | 403 | .unmask = au1x_ic1_unmask, |
314 | .end = end_irq, | 404 | .set_type = au1x_ic_settype, |
405 | .set_wake = au1x_ic1_setwake, | ||
315 | }; | 406 | }; |
316 | 407 | ||
317 | static void __init setup_local_irq(unsigned int irq_nr, int type, int int_req) | 408 | static int au1x_ic_settype(unsigned int irq, unsigned int flow_type) |
318 | { | 409 | { |
319 | unsigned int bit = irq_nr - AU1000_INTC0_INT_BASE; | 410 | struct irq_chip *chip; |
320 | 411 | unsigned long icr[6]; | |
321 | if (irq_nr > AU1000_MAX_INTR) | 412 | unsigned int bit, ic; |
322 | return; | 413 | int ret; |
323 | 414 | ||
324 | /* Config2[n], Config1[n], Config0[n] */ | 415 | if (irq >= AU1000_INTC1_INT_BASE) { |
325 | if (bit >= 32) { | 416 | bit = irq - AU1000_INTC1_INT_BASE; |
326 | switch (type) { | 417 | chip = &au1x_ic1_chip; |
327 | case INTC_INT_RISE_EDGE: /* 0:0:1 */ | 418 | ic = 1; |
328 | au_writel(1 << (bit - 32), IC1_CFG2CLR); | ||
329 | au_writel(1 << (bit - 32), IC1_CFG1CLR); | ||
330 | au_writel(1 << (bit - 32), IC1_CFG0SET); | ||
331 | set_irq_chip(irq_nr, &rise_edge_irq_type); | ||
332 | break; | ||
333 | case INTC_INT_FALL_EDGE: /* 0:1:0 */ | ||
334 | au_writel(1 << (bit - 32), IC1_CFG2CLR); | ||
335 | au_writel(1 << (bit - 32), IC1_CFG1SET); | ||
336 | au_writel(1 << (bit - 32), IC1_CFG0CLR); | ||
337 | set_irq_chip(irq_nr, &fall_edge_irq_type); | ||
338 | break; | ||
339 | case INTC_INT_RISE_AND_FALL_EDGE: /* 0:1:1 */ | ||
340 | au_writel(1 << (bit - 32), IC1_CFG2CLR); | ||
341 | au_writel(1 << (bit - 32), IC1_CFG1SET); | ||
342 | au_writel(1 << (bit - 32), IC1_CFG0SET); | ||
343 | set_irq_chip(irq_nr, &either_edge_irq_type); | ||
344 | break; | ||
345 | case INTC_INT_HIGH_LEVEL: /* 1:0:1 */ | ||
346 | au_writel(1 << (bit - 32), IC1_CFG2SET); | ||
347 | au_writel(1 << (bit - 32), IC1_CFG1CLR); | ||
348 | au_writel(1 << (bit - 32), IC1_CFG0SET); | ||
349 | set_irq_chip(irq_nr, &level_irq_type); | ||
350 | break; | ||
351 | case INTC_INT_LOW_LEVEL: /* 1:1:0 */ | ||
352 | au_writel(1 << (bit - 32), IC1_CFG2SET); | ||
353 | au_writel(1 << (bit - 32), IC1_CFG1SET); | ||
354 | au_writel(1 << (bit - 32), IC1_CFG0CLR); | ||
355 | set_irq_chip(irq_nr, &level_irq_type); | ||
356 | break; | ||
357 | case INTC_INT_DISABLED: /* 0:0:0 */ | ||
358 | au_writel(1 << (bit - 32), IC1_CFG0CLR); | ||
359 | au_writel(1 << (bit - 32), IC1_CFG1CLR); | ||
360 | au_writel(1 << (bit - 32), IC1_CFG2CLR); | ||
361 | break; | ||
362 | default: /* disable the interrupt */ | ||
363 | printk(KERN_WARNING "unexpected int type %d (irq %d)\n", | ||
364 | type, irq_nr); | ||
365 | au_writel(1 << (bit - 32), IC1_CFG0CLR); | ||
366 | au_writel(1 << (bit - 32), IC1_CFG1CLR); | ||
367 | au_writel(1 << (bit - 32), IC1_CFG2CLR); | ||
368 | return; | ||
369 | } | ||
370 | if (int_req) /* assign to interrupt request 1 */ | ||
371 | au_writel(1 << (bit - 32), IC1_ASSIGNCLR); | ||
372 | else /* assign to interrupt request 0 */ | ||
373 | au_writel(1 << (bit - 32), IC1_ASSIGNSET); | ||
374 | au_writel(1 << (bit - 32), IC1_SRCSET); | ||
375 | au_writel(1 << (bit - 32), IC1_MASKCLR); | ||
376 | au_writel(1 << (bit - 32), IC1_WAKECLR); | ||
377 | } else { | 419 | } else { |
378 | switch (type) { | 420 | bit = irq - AU1000_INTC0_INT_BASE; |
379 | case INTC_INT_RISE_EDGE: /* 0:0:1 */ | 421 | chip = &au1x_ic0_chip; |
380 | au_writel(1 << bit, IC0_CFG2CLR); | 422 | ic = 0; |
381 | au_writel(1 << bit, IC0_CFG1CLR); | 423 | } |
382 | au_writel(1 << bit, IC0_CFG0SET); | 424 | |
383 | set_irq_chip(irq_nr, &rise_edge_irq_type); | 425 | if (bit > 31) |
384 | break; | 426 | return -EINVAL; |
385 | case INTC_INT_FALL_EDGE: /* 0:1:0 */ | 427 | |
386 | au_writel(1 << bit, IC0_CFG2CLR); | 428 | icr[0] = ic ? IC1_CFG0SET : IC0_CFG0SET; |
387 | au_writel(1 << bit, IC0_CFG1SET); | 429 | icr[1] = ic ? IC1_CFG1SET : IC0_CFG1SET; |
388 | au_writel(1 << bit, IC0_CFG0CLR); | 430 | icr[2] = ic ? IC1_CFG2SET : IC0_CFG2SET; |
389 | set_irq_chip(irq_nr, &fall_edge_irq_type); | 431 | icr[3] = ic ? IC1_CFG0CLR : IC0_CFG0CLR; |
390 | break; | 432 | icr[4] = ic ? IC1_CFG1CLR : IC0_CFG1CLR; |
391 | case INTC_INT_RISE_AND_FALL_EDGE: /* 0:1:1 */ | 433 | icr[5] = ic ? IC1_CFG2CLR : IC0_CFG2CLR; |
392 | au_writel(1 << bit, IC0_CFG2CLR); | 434 | |
393 | au_writel(1 << bit, IC0_CFG1SET); | 435 | ret = 0; |
394 | au_writel(1 << bit, IC0_CFG0SET); | 436 | |
395 | set_irq_chip(irq_nr, &either_edge_irq_type); | 437 | switch (flow_type) { /* cfgregs 2:1:0 */ |
396 | break; | 438 | case IRQ_TYPE_EDGE_RISING: /* 0:0:1 */ |
397 | case INTC_INT_HIGH_LEVEL: /* 1:0:1 */ | 439 | au_writel(1 << bit, icr[5]); |
398 | au_writel(1 << bit, IC0_CFG2SET); | 440 | au_writel(1 << bit, icr[4]); |
399 | au_writel(1 << bit, IC0_CFG1CLR); | 441 | au_writel(1 << bit, icr[0]); |
400 | au_writel(1 << bit, IC0_CFG0SET); | 442 | set_irq_chip_and_handler_name(irq, chip, |
401 | set_irq_chip(irq_nr, &level_irq_type); | 443 | handle_edge_irq, "riseedge"); |
402 | break; | 444 | break; |
403 | case INTC_INT_LOW_LEVEL: /* 1:1:0 */ | 445 | case IRQ_TYPE_EDGE_FALLING: /* 0:1:0 */ |
404 | au_writel(1 << bit, IC0_CFG2SET); | 446 | au_writel(1 << bit, icr[5]); |
405 | au_writel(1 << bit, IC0_CFG1SET); | 447 | au_writel(1 << bit, icr[1]); |
406 | au_writel(1 << bit, IC0_CFG0CLR); | 448 | au_writel(1 << bit, icr[3]); |
407 | set_irq_chip(irq_nr, &level_irq_type); | 449 | set_irq_chip_and_handler_name(irq, chip, |
408 | break; | 450 | handle_edge_irq, "falledge"); |
409 | case INTC_INT_DISABLED: /* 0:0:0 */ | 451 | break; |
410 | au_writel(1 << bit, IC0_CFG0CLR); | 452 | case IRQ_TYPE_EDGE_BOTH: /* 0:1:1 */ |
411 | au_writel(1 << bit, IC0_CFG1CLR); | 453 | au_writel(1 << bit, icr[5]); |
412 | au_writel(1 << bit, IC0_CFG2CLR); | 454 | au_writel(1 << bit, icr[1]); |
413 | break; | 455 | au_writel(1 << bit, icr[0]); |
414 | default: /* disable the interrupt */ | 456 | set_irq_chip_and_handler_name(irq, chip, |
415 | printk(KERN_WARNING "unexpected int type %d (irq %d)\n", | 457 | handle_edge_irq, "bothedge"); |
416 | type, irq_nr); | 458 | break; |
417 | au_writel(1 << bit, IC0_CFG0CLR); | 459 | case IRQ_TYPE_LEVEL_HIGH: /* 1:0:1 */ |
418 | au_writel(1 << bit, IC0_CFG1CLR); | 460 | au_writel(1 << bit, icr[2]); |
419 | au_writel(1 << bit, IC0_CFG2CLR); | 461 | au_writel(1 << bit, icr[4]); |
420 | return; | 462 | au_writel(1 << bit, icr[0]); |
421 | } | 463 | set_irq_chip_and_handler_name(irq, chip, |
422 | if (int_req) /* assign to interrupt request 1 */ | 464 | handle_level_irq, "hilevel"); |
423 | au_writel(1 << bit, IC0_ASSIGNCLR); | 465 | break; |
424 | else /* assign to interrupt request 0 */ | 466 | case IRQ_TYPE_LEVEL_LOW: /* 1:1:0 */ |
425 | au_writel(1 << bit, IC0_ASSIGNSET); | 467 | au_writel(1 << bit, icr[2]); |
426 | au_writel(1 << bit, IC0_SRCSET); | 468 | au_writel(1 << bit, icr[1]); |
427 | au_writel(1 << bit, IC0_MASKCLR); | 469 | au_writel(1 << bit, icr[3]); |
428 | au_writel(1 << bit, IC0_WAKECLR); | 470 | set_irq_chip_and_handler_name(irq, chip, |
471 | handle_level_irq, "lowlevel"); | ||
472 | break; | ||
473 | case IRQ_TYPE_NONE: /* 0:0:0 */ | ||
474 | au_writel(1 << bit, icr[5]); | ||
475 | au_writel(1 << bit, icr[4]); | ||
476 | au_writel(1 << bit, icr[3]); | ||
477 | /* set at least chip so we can call set_irq_type() on it */ | ||
478 | set_irq_chip(irq, chip); | ||
479 | break; | ||
480 | default: | ||
481 | ret = -EINVAL; | ||
429 | } | 482 | } |
430 | au_sync(); | 483 | au_sync(); |
431 | } | ||
432 | 484 | ||
433 | /* | 485 | return ret; |
434 | * Interrupts are nested. Even if an interrupt handler is registered | 486 | } |
435 | * as "fast", we might get another interrupt before we return from | ||
436 | * intcX_reqX_irqdispatch(). | ||
437 | */ | ||
438 | 487 | ||
439 | static void intc0_req0_irqdispatch(void) | 488 | asmlinkage void plat_irq_dispatch(void) |
440 | { | 489 | { |
441 | static unsigned long intc0_req0; | 490 | unsigned int pending = read_c0_status() & read_c0_cause(); |
442 | unsigned int bit; | 491 | unsigned long s, off, bit; |
443 | |||
444 | intc0_req0 |= au_readl(IC0_REQ0INT); | ||
445 | 492 | ||
446 | if (!intc0_req0) | 493 | if (pending & CAUSEF_IP7) { |
494 | do_IRQ(MIPS_CPU_IRQ_BASE + 7); | ||
447 | return; | 495 | return; |
448 | 496 | } else if (pending & CAUSEF_IP2) { | |
497 | s = IC0_REQ0INT; | ||
498 | off = AU1000_INTC0_INT_BASE; | ||
499 | } else if (pending & CAUSEF_IP3) { | ||
500 | s = IC0_REQ1INT; | ||
501 | off = AU1000_INTC0_INT_BASE; | ||
502 | } else if (pending & CAUSEF_IP4) { | ||
503 | s = IC1_REQ0INT; | ||
504 | off = AU1000_INTC1_INT_BASE; | ||
505 | } else if (pending & CAUSEF_IP5) { | ||
506 | s = IC1_REQ1INT; | ||
507 | off = AU1000_INTC1_INT_BASE; | ||
508 | } else | ||
509 | goto spurious; | ||
510 | |||
511 | bit = 0; | ||
512 | s = au_readl(s); | ||
513 | if (unlikely(!s)) { | ||
514 | spurious: | ||
515 | spurious_interrupt(); | ||
516 | return; | ||
517 | } | ||
449 | #ifdef AU1000_USB_DEV_REQ_INT | 518 | #ifdef AU1000_USB_DEV_REQ_INT |
450 | /* | 519 | /* |
451 | * Because of the tight timing of SETUP token to reply | 520 | * Because of the tight timing of SETUP token to reply |
452 | * transactions, the USB devices-side packet complete | 521 | * transactions, the USB devices-side packet complete |
453 | * interrupt needs the highest priority. | 522 | * interrupt needs the highest priority. |
454 | */ | 523 | */ |
455 | if ((intc0_req0 & (1 << AU1000_USB_DEV_REQ_INT))) { | 524 | bit = 1 << (AU1000_USB_DEV_REQ_INT - AU1000_INTC0_INT_BASE); |
456 | intc0_req0 &= ~(1 << AU1000_USB_DEV_REQ_INT); | 525 | if ((pending & CAUSEF_IP2) && (s & bit)) { |
457 | do_IRQ(AU1000_USB_DEV_REQ_INT); | 526 | do_IRQ(AU1000_USB_DEV_REQ_INT); |
458 | return; | 527 | return; |
459 | } | 528 | } |
460 | #endif | 529 | #endif |
461 | bit = __ffs(intc0_req0); | 530 | do_IRQ(__ffs(s) + off); |
462 | intc0_req0 &= ~(1 << bit); | ||
463 | do_IRQ(AU1000_INTC0_INT_BASE + bit); | ||
464 | } | 531 | } |
465 | 532 | ||
466 | 533 | /* setup edge/level and assign request 0/1 */ | |
467 | static void intc0_req1_irqdispatch(void) | 534 | void __init au1xxx_setup_irqmap(struct au1xxx_irqmap *map, int count) |
468 | { | 535 | { |
469 | static unsigned long intc0_req1; | 536 | unsigned int bit, irq_nr; |
470 | unsigned int bit; | 537 | |
471 | 538 | while (count--) { | |
472 | intc0_req1 |= au_readl(IC0_REQ1INT); | 539 | irq_nr = map[count].im_irq; |
473 | 540 | ||
474 | if (!intc0_req1) | 541 | if (((irq_nr < AU1000_INTC0_INT_BASE) || |
475 | return; | 542 | (irq_nr >= AU1000_INTC0_INT_BASE + 32)) && |
476 | 543 | ((irq_nr < AU1000_INTC1_INT_BASE) || | |
477 | bit = __ffs(intc0_req1); | 544 | (irq_nr >= AU1000_INTC1_INT_BASE + 32))) |
478 | intc0_req1 &= ~(1 << bit); | 545 | continue; |
479 | do_IRQ(AU1000_INTC0_INT_BASE + bit); | 546 | |
480 | } | 547 | if (irq_nr >= AU1000_INTC1_INT_BASE) { |
481 | 548 | bit = irq_nr - AU1000_INTC1_INT_BASE; | |
482 | 549 | if (map[count].im_request) | |
483 | /* | 550 | au_writel(1 << bit, IC1_ASSIGNCLR); |
484 | * Interrupt Controller 1: | 551 | } else { |
485 | * interrupts 32 - 63 | 552 | bit = irq_nr - AU1000_INTC0_INT_BASE; |
486 | */ | 553 | if (map[count].im_request) |
487 | static void intc1_req0_irqdispatch(void) | 554 | au_writel(1 << bit, IC0_ASSIGNCLR); |
488 | { | 555 | } |
489 | static unsigned long intc1_req0; | ||
490 | unsigned int bit; | ||
491 | |||
492 | intc1_req0 |= au_readl(IC1_REQ0INT); | ||
493 | |||
494 | if (!intc1_req0) | ||
495 | return; | ||
496 | |||
497 | bit = __ffs(intc1_req0); | ||
498 | intc1_req0 &= ~(1 << bit); | ||
499 | do_IRQ(AU1000_INTC1_INT_BASE + bit); | ||
500 | } | ||
501 | |||
502 | |||
503 | static void intc1_req1_irqdispatch(void) | ||
504 | { | ||
505 | static unsigned long intc1_req1; | ||
506 | unsigned int bit; | ||
507 | |||
508 | intc1_req1 |= au_readl(IC1_REQ1INT); | ||
509 | |||
510 | if (!intc1_req1) | ||
511 | return; | ||
512 | |||
513 | bit = __ffs(intc1_req1); | ||
514 | intc1_req1 &= ~(1 << bit); | ||
515 | do_IRQ(AU1000_INTC1_INT_BASE + bit); | ||
516 | } | ||
517 | |||
518 | asmlinkage void plat_irq_dispatch(void) | ||
519 | { | ||
520 | unsigned int pending = read_c0_status() & read_c0_cause(); | ||
521 | 556 | ||
522 | if (pending & CAUSEF_IP7) | 557 | au1x_ic_settype(irq_nr, map[count].im_type); |
523 | do_IRQ(MIPS_CPU_IRQ_BASE + 7); | 558 | } |
524 | else if (pending & CAUSEF_IP2) | ||
525 | intc0_req0_irqdispatch(); | ||
526 | else if (pending & CAUSEF_IP3) | ||
527 | intc0_req1_irqdispatch(); | ||
528 | else if (pending & CAUSEF_IP4) | ||
529 | intc1_req0_irqdispatch(); | ||
530 | else if (pending & CAUSEF_IP5) | ||
531 | intc1_req1_irqdispatch(); | ||
532 | else | ||
533 | spurious_interrupt(); | ||
534 | } | 559 | } |
535 | 560 | ||
536 | void __init arch_init_irq(void) | 561 | void __init arch_init_irq(void) |
537 | { | 562 | { |
538 | int i; | 563 | int i; |
539 | struct au1xxx_irqmap *imp; | ||
540 | extern struct au1xxx_irqmap au1xxx_irq_map[]; | ||
541 | extern struct au1xxx_irqmap au1xxx_ic0_map[]; | ||
542 | extern int au1xxx_nr_irqs; | ||
543 | extern int au1xxx_ic0_nr_irqs; | ||
544 | 564 | ||
545 | /* | 565 | /* |
546 | * Initialize interrupt controllers to a safe state. | 566 | * Initialize interrupt controllers to a safe state. |
@@ -569,28 +589,67 @@ void __init arch_init_irq(void) | |||
569 | 589 | ||
570 | mips_cpu_irq_init(); | 590 | mips_cpu_irq_init(); |
571 | 591 | ||
572 | /* | 592 | /* register all 64 possible IC0+IC1 irq sources as type "none". |
573 | * Initialize IC0, which is fixed per processor. | 593 | * Use set_irq_type() to set edge/level behaviour at runtime. |
574 | */ | 594 | */ |
575 | imp = au1xxx_ic0_map; | 595 | for (i = AU1000_INTC0_INT_BASE; |
576 | for (i = 0; i < au1xxx_ic0_nr_irqs; i++) { | 596 | (i < AU1000_INTC0_INT_BASE + 32); i++) |
577 | setup_local_irq(imp->im_irq, imp->im_type, imp->im_request); | 597 | au1x_ic_settype(i, IRQ_TYPE_NONE); |
578 | imp++; | 598 | |
579 | } | 599 | for (i = AU1000_INTC1_INT_BASE; |
600 | (i < AU1000_INTC1_INT_BASE + 32); i++) | ||
601 | au1x_ic_settype(i, IRQ_TYPE_NONE); | ||
580 | 602 | ||
581 | /* | 603 | /* |
582 | * Now set up the irq mapping for the board. | 604 | * Initialize IC0, which is fixed per processor. |
583 | */ | 605 | */ |
584 | imp = au1xxx_irq_map; | 606 | au1xxx_setup_irqmap(au1xxx_ic0_map, ARRAY_SIZE(au1xxx_ic0_map)); |
585 | for (i = 0; i < au1xxx_nr_irqs; i++) { | 607 | |
586 | setup_local_irq(imp->im_irq, imp->im_type, imp->im_request); | 608 | /* Boards can register additional (GPIO-based) IRQs. |
587 | imp++; | 609 | */ |
610 | board_init_irq(); | ||
611 | |||
612 | set_c0_status(IE_IRQ0 | IE_IRQ1 | IE_IRQ2 | IE_IRQ3); | ||
613 | } | ||
614 | |||
615 | unsigned long save_local_and_disable(int controller) | ||
616 | { | ||
617 | int i; | ||
618 | unsigned long flags, mask; | ||
619 | |||
620 | spin_lock_irqsave(&irq_lock, flags); | ||
621 | if (controller) { | ||
622 | mask = au_readl(IC1_MASKSET); | ||
623 | for (i = 0; i < 32; i++) | ||
624 | au1x_ic1_mask(i + AU1000_INTC1_INT_BASE); | ||
625 | } else { | ||
626 | mask = au_readl(IC0_MASKSET); | ||
627 | for (i = 0; i < 32; i++) | ||
628 | au1x_ic0_mask(i + AU1000_INTC0_INT_BASE); | ||
588 | } | 629 | } |
630 | spin_unlock_irqrestore(&irq_lock, flags); | ||
589 | 631 | ||
590 | set_c0_status(IE_IRQ0 | IE_IRQ1 | IE_IRQ2 | IE_IRQ3 | IE_IRQ4); | 632 | return mask; |
633 | } | ||
591 | 634 | ||
592 | /* Board specific IRQ initialization. | 635 | void restore_local_and_enable(int controller, unsigned long mask) |
593 | */ | 636 | { |
594 | if (board_init_irq) | 637 | int i; |
595 | board_init_irq(); | 638 | unsigned long flags, new_mask; |
639 | |||
640 | spin_lock_irqsave(&irq_lock, flags); | ||
641 | for (i = 0; i < 32; i++) | ||
642 | if (mask & (1 << i)) { | ||
643 | if (controller) | ||
644 | au1x_ic1_unmask(i + AU1000_INTC1_INT_BASE); | ||
645 | else | ||
646 | au1x_ic0_unmask(i + AU1000_INTC0_INT_BASE); | ||
647 | } | ||
648 | |||
649 | if (controller) | ||
650 | new_mask = au_readl(IC1_MASKSET); | ||
651 | else | ||
652 | new_mask = au_readl(IC0_MASKSET); | ||
653 | |||
654 | spin_unlock_irqrestore(&irq_lock, flags); | ||
596 | } | 655 | } |