]>
Commit | Line | Data |
---|---|---|
1da177e4 | 1 | /* |
01675095 SS |
2 | * Copyright 2001, 2007-2008 MontaVista Software Inc. |
3 | * Author: MontaVista Software, Inc. <source@mvista.com> | |
1da177e4 | 4 | * |
f3e8d1da RB |
5 | * Copyright (C) 2007 Ralf Baechle (ralf@linux-mips.org) |
6 | * | |
1da177e4 LT |
7 | * This program is free software; you can redistribute it and/or modify it |
8 | * under the terms of the GNU General Public License as published by the | |
9 | * Free Software Foundation; either version 2 of the License, or (at your | |
10 | * option) any later version. | |
11 | * | |
12 | * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED | |
13 | * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF | |
14 | * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN | |
15 | * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, | |
16 | * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT | |
17 | * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF | |
18 | * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON | |
19 | * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | |
20 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF | |
21 | * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | |
22 | * | |
23 | * You should have received a copy of the GNU General Public License along | |
24 | * with this program; if not, write to the Free Software Foundation, Inc., | |
25 | * 675 Mass Ave, Cambridge, MA 02139, USA. | |
26 | */ | |
785e3268 | 27 | |
41bd61a8 | 28 | #include <linux/bitops.h> |
1da177e4 | 29 | #include <linux/init.h> |
1da177e4 | 30 | #include <linux/interrupt.h> |
41bd61a8 | 31 | #include <linux/irq.h> |
1da177e4 | 32 | |
f3e8d1da | 33 | #include <asm/irq_cpu.h> |
1da177e4 | 34 | #include <asm/mipsregs.h> |
1da177e4 LT |
35 | #include <asm/mach-au1x00/au1000.h> |
36 | #ifdef CONFIG_MIPS_PB1000 | |
37 | #include <asm/mach-pb1x00/pb1000.h> | |
38 | #endif | |
39 | ||
785e3268 ML |
40 | static int au1x_ic_settype(unsigned int irq, unsigned int flow_type); |
41 | ||
42 | /* per-processor fixed function irqs */ | |
7e50b2b7 ML |
43 | struct au1xxx_irqmap { |
44 | int im_irq; | |
45 | int im_type; | |
46 | int im_request; | |
47 | } au1xxx_ic0_map[] __initdata = { | |
785e3268 ML |
48 | #if defined(CONFIG_SOC_AU1000) |
49 | { AU1000_UART0_INT, IRQ_TYPE_LEVEL_HIGH, 0 }, | |
50 | { AU1000_UART1_INT, IRQ_TYPE_LEVEL_HIGH, 0 }, | |
51 | { AU1000_UART2_INT, IRQ_TYPE_LEVEL_HIGH, 0 }, | |
52 | { AU1000_UART3_INT, IRQ_TYPE_LEVEL_HIGH, 0 }, | |
53 | { AU1000_SSI0_INT, IRQ_TYPE_LEVEL_HIGH, 0 }, | |
54 | { AU1000_SSI1_INT, IRQ_TYPE_LEVEL_HIGH, 0 }, | |
55 | { AU1000_DMA_INT_BASE, IRQ_TYPE_LEVEL_HIGH, 0 }, | |
56 | { AU1000_DMA_INT_BASE+1, IRQ_TYPE_LEVEL_HIGH, 0 }, | |
57 | { AU1000_DMA_INT_BASE+2, IRQ_TYPE_LEVEL_HIGH, 0 }, | |
58 | { AU1000_DMA_INT_BASE+3, IRQ_TYPE_LEVEL_HIGH, 0 }, | |
59 | { AU1000_DMA_INT_BASE+4, IRQ_TYPE_LEVEL_HIGH, 0 }, | |
60 | { AU1000_DMA_INT_BASE+5, IRQ_TYPE_LEVEL_HIGH, 0 }, | |
61 | { AU1000_DMA_INT_BASE+6, IRQ_TYPE_LEVEL_HIGH, 0 }, | |
62 | { AU1000_DMA_INT_BASE+7, IRQ_TYPE_LEVEL_HIGH, 0 }, | |
63 | { AU1000_TOY_INT, IRQ_TYPE_EDGE_RISING, 0 }, | |
64 | { AU1000_TOY_MATCH0_INT, IRQ_TYPE_EDGE_RISING, 0 }, | |
65 | { AU1000_TOY_MATCH1_INT, IRQ_TYPE_EDGE_RISING, 0 }, | |
66 | { AU1000_TOY_MATCH2_INT, IRQ_TYPE_EDGE_RISING, 1 }, | |
67 | { AU1000_RTC_INT, IRQ_TYPE_EDGE_RISING, 0 }, | |
68 | { AU1000_RTC_MATCH0_INT, IRQ_TYPE_EDGE_RISING, 0 }, | |
69 | { AU1000_RTC_MATCH1_INT, IRQ_TYPE_EDGE_RISING, 0 }, | |
70 | { AU1000_RTC_MATCH2_INT, IRQ_TYPE_EDGE_RISING, 0 }, | |
71 | { AU1000_IRDA_TX_INT, IRQ_TYPE_LEVEL_HIGH, 0 }, | |
72 | { AU1000_IRDA_RX_INT, IRQ_TYPE_LEVEL_HIGH, 0 }, | |
73 | { AU1000_USB_DEV_REQ_INT, IRQ_TYPE_LEVEL_HIGH, 0 }, | |
74 | { AU1000_USB_DEV_SUS_INT, IRQ_TYPE_EDGE_RISING, 0 }, | |
75 | { AU1000_USB_HOST_INT, IRQ_TYPE_LEVEL_LOW, 0 }, | |
76 | { AU1000_ACSYNC_INT, IRQ_TYPE_EDGE_RISING, 0 }, | |
77 | { AU1000_MAC0_DMA_INT, IRQ_TYPE_LEVEL_HIGH, 0 }, | |
78 | { AU1000_MAC1_DMA_INT, IRQ_TYPE_LEVEL_HIGH, 0 }, | |
79 | { AU1000_AC97C_INT, IRQ_TYPE_EDGE_RISING, 0 }, | |
80 | ||
81 | #elif defined(CONFIG_SOC_AU1500) | |
82 | ||
83 | { AU1500_UART0_INT, IRQ_TYPE_LEVEL_HIGH, 0 }, | |
84 | { AU1000_PCI_INTA, IRQ_TYPE_LEVEL_LOW, 0 }, | |
85 | { AU1000_PCI_INTB, IRQ_TYPE_LEVEL_LOW, 0 }, | |
86 | { AU1500_UART3_INT, IRQ_TYPE_LEVEL_HIGH, 0 }, | |
87 | { AU1000_PCI_INTC, IRQ_TYPE_LEVEL_LOW, 0 }, | |
88 | { AU1000_PCI_INTD, IRQ_TYPE_LEVEL_LOW, 0 }, | |
89 | { AU1000_DMA_INT_BASE, IRQ_TYPE_LEVEL_HIGH, 0 }, | |
90 | { AU1000_DMA_INT_BASE+1, IRQ_TYPE_LEVEL_HIGH, 0 }, | |
91 | { AU1000_DMA_INT_BASE+2, IRQ_TYPE_LEVEL_HIGH, 0 }, | |
92 | { AU1000_DMA_INT_BASE+3, IRQ_TYPE_LEVEL_HIGH, 0 }, | |
93 | { AU1000_DMA_INT_BASE+4, IRQ_TYPE_LEVEL_HIGH, 0 }, | |
94 | { AU1000_DMA_INT_BASE+5, IRQ_TYPE_LEVEL_HIGH, 0 }, | |
95 | { AU1000_DMA_INT_BASE+6, IRQ_TYPE_LEVEL_HIGH, 0 }, | |
96 | { AU1000_DMA_INT_BASE+7, IRQ_TYPE_LEVEL_HIGH, 0 }, | |
97 | { AU1000_TOY_INT, IRQ_TYPE_EDGE_RISING, 0 }, | |
98 | { AU1000_TOY_MATCH0_INT, IRQ_TYPE_EDGE_RISING, 0 }, | |
99 | { AU1000_TOY_MATCH1_INT, IRQ_TYPE_EDGE_RISING, 0 }, | |
100 | { AU1000_TOY_MATCH2_INT, IRQ_TYPE_EDGE_RISING, 1 }, | |
101 | { AU1000_RTC_INT, IRQ_TYPE_EDGE_RISING, 0 }, | |
102 | { AU1000_RTC_MATCH0_INT, IRQ_TYPE_EDGE_RISING, 0 }, | |
103 | { AU1000_RTC_MATCH1_INT, IRQ_TYPE_EDGE_RISING, 0 }, | |
104 | { AU1000_RTC_MATCH2_INT, IRQ_TYPE_EDGE_RISING, 0 }, | |
105 | { AU1000_USB_DEV_REQ_INT, IRQ_TYPE_LEVEL_HIGH, 0 }, | |
106 | { AU1000_USB_DEV_SUS_INT, IRQ_TYPE_EDGE_RISING, 0 }, | |
107 | { AU1000_USB_HOST_INT, IRQ_TYPE_LEVEL_LOW, 0 }, | |
108 | { AU1000_ACSYNC_INT, IRQ_TYPE_EDGE_RISING, 0 }, | |
109 | { AU1500_MAC0_DMA_INT, IRQ_TYPE_LEVEL_HIGH, 0 }, | |
110 | { AU1500_MAC1_DMA_INT, IRQ_TYPE_LEVEL_HIGH, 0 }, | |
111 | { AU1000_AC97C_INT, IRQ_TYPE_EDGE_RISING, 0 }, | |
112 | ||
113 | #elif defined(CONFIG_SOC_AU1100) | |
114 | ||
115 | { AU1100_UART0_INT, IRQ_TYPE_LEVEL_HIGH, 0 }, | |
116 | { AU1100_UART1_INT, IRQ_TYPE_LEVEL_HIGH, 0 }, | |
117 | { AU1100_SD_INT, IRQ_TYPE_LEVEL_HIGH, 0 }, | |
118 | { AU1100_UART3_INT, IRQ_TYPE_LEVEL_HIGH, 0 }, | |
119 | { AU1000_SSI0_INT, IRQ_TYPE_LEVEL_HIGH, 0 }, | |
120 | { AU1000_SSI1_INT, IRQ_TYPE_LEVEL_HIGH, 0 }, | |
121 | { AU1000_DMA_INT_BASE, IRQ_TYPE_LEVEL_HIGH, 0 }, | |
122 | { AU1000_DMA_INT_BASE+1, IRQ_TYPE_LEVEL_HIGH, 0 }, | |
123 | { AU1000_DMA_INT_BASE+2, IRQ_TYPE_LEVEL_HIGH, 0 }, | |
124 | { AU1000_DMA_INT_BASE+3, IRQ_TYPE_LEVEL_HIGH, 0 }, | |
125 | { AU1000_DMA_INT_BASE+4, IRQ_TYPE_LEVEL_HIGH, 0 }, | |
126 | { AU1000_DMA_INT_BASE+5, IRQ_TYPE_LEVEL_HIGH, 0 }, | |
127 | { AU1000_DMA_INT_BASE+6, IRQ_TYPE_LEVEL_HIGH, 0 }, | |
128 | { AU1000_DMA_INT_BASE+7, IRQ_TYPE_LEVEL_HIGH, 0 }, | |
129 | { AU1000_TOY_INT, IRQ_TYPE_EDGE_RISING, 0 }, | |
130 | { AU1000_TOY_MATCH0_INT, IRQ_TYPE_EDGE_RISING, 0 }, | |
131 | { AU1000_TOY_MATCH1_INT, IRQ_TYPE_EDGE_RISING, 0 }, | |
132 | { AU1000_TOY_MATCH2_INT, IRQ_TYPE_EDGE_RISING, 1 }, | |
133 | { AU1000_RTC_INT, IRQ_TYPE_EDGE_RISING, 0 }, | |
134 | { AU1000_RTC_MATCH0_INT, IRQ_TYPE_EDGE_RISING, 0 }, | |
135 | { AU1000_RTC_MATCH1_INT, IRQ_TYPE_EDGE_RISING, 0 }, | |
136 | { AU1000_RTC_MATCH2_INT, IRQ_TYPE_EDGE_RISING, 0 }, | |
137 | { AU1000_IRDA_TX_INT, IRQ_TYPE_LEVEL_HIGH, 0 }, | |
138 | { AU1000_IRDA_RX_INT, IRQ_TYPE_LEVEL_HIGH, 0 }, | |
139 | { AU1000_USB_DEV_REQ_INT, IRQ_TYPE_LEVEL_HIGH, 0 }, | |
140 | { AU1000_USB_DEV_SUS_INT, IRQ_TYPE_EDGE_RISING, 0 }, | |
141 | { AU1000_USB_HOST_INT, IRQ_TYPE_LEVEL_LOW, 0 }, | |
142 | { AU1000_ACSYNC_INT, IRQ_TYPE_EDGE_RISING, 0 }, | |
143 | { AU1100_MAC0_DMA_INT, IRQ_TYPE_LEVEL_HIGH, 0 }, | |
144 | { AU1100_LCD_INT, IRQ_TYPE_LEVEL_HIGH, 0 }, | |
145 | { AU1000_AC97C_INT, IRQ_TYPE_EDGE_RISING, 0 }, | |
146 | ||
147 | #elif defined(CONFIG_SOC_AU1550) | |
148 | ||
149 | { AU1550_UART0_INT, IRQ_TYPE_LEVEL_HIGH, 0 }, | |
150 | { AU1550_PCI_INTA, IRQ_TYPE_LEVEL_LOW, 0 }, | |
151 | { AU1550_PCI_INTB, IRQ_TYPE_LEVEL_LOW, 0 }, | |
152 | { AU1550_DDMA_INT, IRQ_TYPE_LEVEL_HIGH, 0 }, | |
153 | { AU1550_CRYPTO_INT, IRQ_TYPE_LEVEL_HIGH, 0 }, | |
154 | { AU1550_PCI_INTC, IRQ_TYPE_LEVEL_LOW, 0 }, | |
155 | { AU1550_PCI_INTD, IRQ_TYPE_LEVEL_LOW, 0 }, | |
156 | { AU1550_PCI_RST_INT, IRQ_TYPE_LEVEL_LOW, 0 }, | |
157 | { AU1550_UART1_INT, IRQ_TYPE_LEVEL_HIGH, 0 }, | |
158 | { AU1550_UART3_INT, IRQ_TYPE_LEVEL_HIGH, 0 }, | |
159 | { AU1550_PSC0_INT, IRQ_TYPE_LEVEL_HIGH, 0 }, | |
160 | { AU1550_PSC1_INT, IRQ_TYPE_LEVEL_HIGH, 0 }, | |
161 | { AU1550_PSC2_INT, IRQ_TYPE_LEVEL_HIGH, 0 }, | |
162 | { AU1550_PSC3_INT, IRQ_TYPE_LEVEL_HIGH, 0 }, | |
163 | { AU1000_TOY_INT, IRQ_TYPE_EDGE_RISING, 0 }, | |
164 | { AU1000_TOY_MATCH0_INT, IRQ_TYPE_EDGE_RISING, 0 }, | |
165 | { AU1000_TOY_MATCH1_INT, IRQ_TYPE_EDGE_RISING, 0 }, | |
166 | { AU1000_TOY_MATCH2_INT, IRQ_TYPE_EDGE_RISING, 1 }, | |
167 | { AU1000_RTC_INT, IRQ_TYPE_EDGE_RISING, 0 }, | |
168 | { AU1000_RTC_MATCH0_INT, IRQ_TYPE_EDGE_RISING, 0 }, | |
169 | { AU1000_RTC_MATCH1_INT, IRQ_TYPE_EDGE_RISING, 0 }, | |
170 | { AU1000_RTC_MATCH2_INT, IRQ_TYPE_EDGE_RISING, 0 }, | |
171 | { AU1550_NAND_INT, IRQ_TYPE_EDGE_RISING, 0 }, | |
172 | { AU1550_USB_DEV_REQ_INT, IRQ_TYPE_LEVEL_HIGH, 0 }, | |
173 | { AU1550_USB_DEV_SUS_INT, IRQ_TYPE_EDGE_RISING, 0 }, | |
174 | { AU1550_USB_HOST_INT, IRQ_TYPE_LEVEL_LOW, 0 }, | |
175 | { AU1550_MAC0_DMA_INT, IRQ_TYPE_LEVEL_HIGH, 0 }, | |
176 | { AU1550_MAC1_DMA_INT, IRQ_TYPE_LEVEL_HIGH, 0 }, | |
177 | ||
178 | #elif defined(CONFIG_SOC_AU1200) | |
179 | ||
180 | { AU1200_UART0_INT, IRQ_TYPE_LEVEL_HIGH, 0 }, | |
181 | { AU1200_SWT_INT, IRQ_TYPE_EDGE_RISING, 0 }, | |
182 | { AU1200_SD_INT, IRQ_TYPE_LEVEL_HIGH, 0 }, | |
183 | { AU1200_DDMA_INT, IRQ_TYPE_LEVEL_HIGH, 0 }, | |
184 | { AU1200_MAE_BE_INT, IRQ_TYPE_LEVEL_HIGH, 0 }, | |
185 | { AU1200_UART1_INT, IRQ_TYPE_LEVEL_HIGH, 0 }, | |
186 | { AU1200_MAE_FE_INT, IRQ_TYPE_LEVEL_HIGH, 0 }, | |
187 | { AU1200_PSC0_INT, IRQ_TYPE_LEVEL_HIGH, 0 }, | |
188 | { AU1200_PSC1_INT, IRQ_TYPE_LEVEL_HIGH, 0 }, | |
189 | { AU1200_AES_INT, IRQ_TYPE_LEVEL_HIGH, 0 }, | |
190 | { AU1200_CAMERA_INT, IRQ_TYPE_LEVEL_HIGH, 0 }, | |
191 | { AU1000_TOY_INT, IRQ_TYPE_EDGE_RISING, 0 }, | |
192 | { AU1000_TOY_MATCH0_INT, IRQ_TYPE_EDGE_RISING, 0 }, | |
193 | { AU1000_TOY_MATCH1_INT, IRQ_TYPE_EDGE_RISING, 0 }, | |
194 | { AU1000_TOY_MATCH2_INT, IRQ_TYPE_EDGE_RISING, 1 }, | |
195 | { AU1000_RTC_INT, IRQ_TYPE_EDGE_RISING, 0 }, | |
196 | { AU1000_RTC_MATCH0_INT, IRQ_TYPE_EDGE_RISING, 0 }, | |
197 | { AU1000_RTC_MATCH1_INT, IRQ_TYPE_EDGE_RISING, 0 }, | |
198 | { AU1000_RTC_MATCH2_INT, IRQ_TYPE_EDGE_RISING, 0 }, | |
199 | { AU1200_NAND_INT, IRQ_TYPE_EDGE_RISING, 0 }, | |
200 | { AU1200_USB_INT, IRQ_TYPE_LEVEL_HIGH, 0 }, | |
201 | { AU1200_LCD_INT, IRQ_TYPE_LEVEL_HIGH, 0 }, | |
202 | { AU1200_MAE_BOTH_INT, IRQ_TYPE_LEVEL_HIGH, 0 }, | |
203 | ||
204 | #else | |
205 | #error "Error: Unknown Alchemy SOC" | |
206 | #endif | |
207 | }; | |
1da177e4 | 208 | |
1da177e4 | 209 | |
41bd61a8 RB |
210 | #ifdef CONFIG_PM |
211 | ||
212 | /* | |
213 | * Save/restore the interrupt controller state. | |
214 | * Called from the save/restore core registers as part of the | |
215 | * au_sleep function in power.c.....maybe I should just pm_register() | |
216 | * them instead? | |
217 | */ | |
218 | static unsigned int sleep_intctl_config0[2]; | |
219 | static unsigned int sleep_intctl_config1[2]; | |
220 | static unsigned int sleep_intctl_config2[2]; | |
221 | static unsigned int sleep_intctl_src[2]; | |
222 | static unsigned int sleep_intctl_assign[2]; | |
223 | static unsigned int sleep_intctl_wake[2]; | |
224 | static unsigned int sleep_intctl_mask[2]; | |
225 | ||
226 | void save_au1xxx_intctl(void) | |
227 | { | |
228 | sleep_intctl_config0[0] = au_readl(IC0_CFG0RD); | |
229 | sleep_intctl_config1[0] = au_readl(IC0_CFG1RD); | |
230 | sleep_intctl_config2[0] = au_readl(IC0_CFG2RD); | |
231 | sleep_intctl_src[0] = au_readl(IC0_SRCRD); | |
232 | sleep_intctl_assign[0] = au_readl(IC0_ASSIGNRD); | |
233 | sleep_intctl_wake[0] = au_readl(IC0_WAKERD); | |
234 | sleep_intctl_mask[0] = au_readl(IC0_MASKRD); | |
235 | ||
236 | sleep_intctl_config0[1] = au_readl(IC1_CFG0RD); | |
237 | sleep_intctl_config1[1] = au_readl(IC1_CFG1RD); | |
238 | sleep_intctl_config2[1] = au_readl(IC1_CFG2RD); | |
239 | sleep_intctl_src[1] = au_readl(IC1_SRCRD); | |
240 | sleep_intctl_assign[1] = au_readl(IC1_ASSIGNRD); | |
241 | sleep_intctl_wake[1] = au_readl(IC1_WAKERD); | |
242 | sleep_intctl_mask[1] = au_readl(IC1_MASKRD); | |
243 | } | |
244 | ||
245 | /* | |
246 | * For most restore operations, we clear the entire register and | |
247 | * then set the bits we found during the save. | |
248 | */ | |
249 | void restore_au1xxx_intctl(void) | |
250 | { | |
251 | au_writel(0xffffffff, IC0_MASKCLR); au_sync(); | |
252 | ||
253 | au_writel(0xffffffff, IC0_CFG0CLR); au_sync(); | |
254 | au_writel(sleep_intctl_config0[0], IC0_CFG0SET); au_sync(); | |
255 | au_writel(0xffffffff, IC0_CFG1CLR); au_sync(); | |
256 | au_writel(sleep_intctl_config1[0], IC0_CFG1SET); au_sync(); | |
257 | au_writel(0xffffffff, IC0_CFG2CLR); au_sync(); | |
258 | au_writel(sleep_intctl_config2[0], IC0_CFG2SET); au_sync(); | |
259 | au_writel(0xffffffff, IC0_SRCCLR); au_sync(); | |
260 | au_writel(sleep_intctl_src[0], IC0_SRCSET); au_sync(); | |
261 | au_writel(0xffffffff, IC0_ASSIGNCLR); au_sync(); | |
262 | au_writel(sleep_intctl_assign[0], IC0_ASSIGNSET); au_sync(); | |
263 | au_writel(0xffffffff, IC0_WAKECLR); au_sync(); | |
264 | au_writel(sleep_intctl_wake[0], IC0_WAKESET); au_sync(); | |
265 | au_writel(0xffffffff, IC0_RISINGCLR); au_sync(); | |
266 | au_writel(0xffffffff, IC0_FALLINGCLR); au_sync(); | |
267 | au_writel(0x00000000, IC0_TESTBIT); au_sync(); | |
268 | ||
269 | au_writel(0xffffffff, IC1_MASKCLR); au_sync(); | |
270 | ||
271 | au_writel(0xffffffff, IC1_CFG0CLR); au_sync(); | |
272 | au_writel(sleep_intctl_config0[1], IC1_CFG0SET); au_sync(); | |
273 | au_writel(0xffffffff, IC1_CFG1CLR); au_sync(); | |
274 | au_writel(sleep_intctl_config1[1], IC1_CFG1SET); au_sync(); | |
275 | au_writel(0xffffffff, IC1_CFG2CLR); au_sync(); | |
276 | au_writel(sleep_intctl_config2[1], IC1_CFG2SET); au_sync(); | |
277 | au_writel(0xffffffff, IC1_SRCCLR); au_sync(); | |
278 | au_writel(sleep_intctl_src[1], IC1_SRCSET); au_sync(); | |
279 | au_writel(0xffffffff, IC1_ASSIGNCLR); au_sync(); | |
280 | au_writel(sleep_intctl_assign[1], IC1_ASSIGNSET); au_sync(); | |
281 | au_writel(0xffffffff, IC1_WAKECLR); au_sync(); | |
282 | au_writel(sleep_intctl_wake[1], IC1_WAKESET); au_sync(); | |
283 | au_writel(0xffffffff, IC1_RISINGCLR); au_sync(); | |
284 | au_writel(0xffffffff, IC1_FALLINGCLR); au_sync(); | |
285 | au_writel(0x00000000, IC1_TESTBIT); au_sync(); | |
286 | ||
287 | au_writel(sleep_intctl_mask[1], IC1_MASKSET); au_sync(); | |
288 | ||
289 | au_writel(sleep_intctl_mask[0], IC0_MASKSET); au_sync(); | |
290 | } | |
291 | #endif /* CONFIG_PM */ | |
292 | ||
1da177e4 | 293 | |
785e3268 | 294 | static void au1x_ic0_unmask(unsigned int irq_nr) |
1da177e4 | 295 | { |
f3e8d1da | 296 | unsigned int bit = irq_nr - AU1000_INTC0_INT_BASE; |
785e3268 ML |
297 | au_writel(1 << bit, IC0_MASKSET); |
298 | au_writel(1 << bit, IC0_WAKESET); | |
1da177e4 LT |
299 | au_sync(); |
300 | } | |
301 | ||
785e3268 | 302 | static void au1x_ic1_unmask(unsigned int irq_nr) |
1da177e4 | 303 | { |
785e3268 ML |
304 | unsigned int bit = irq_nr - AU1000_INTC1_INT_BASE; |
305 | au_writel(1 << bit, IC1_MASKSET); | |
306 | au_writel(1 << bit, IC1_WAKESET); | |
f3e8d1da | 307 | |
785e3268 ML |
308 | /* very hacky. does the pb1000 cpld auto-disable this int? |
309 | * nowhere in the current kernel sources is it disabled. --mlau | |
310 | */ | |
311 | #if defined(CONFIG_MIPS_PB1000) | |
312 | if (irq_nr == AU1000_GPIO_15) | |
313 | au_writel(0x4000, PB1000_MDR); /* enable int */ | |
314 | #endif | |
1da177e4 LT |
315 | au_sync(); |
316 | } | |
317 | ||
785e3268 | 318 | static void au1x_ic0_mask(unsigned int irq_nr) |
1da177e4 | 319 | { |
f3e8d1da | 320 | unsigned int bit = irq_nr - AU1000_INTC0_INT_BASE; |
785e3268 ML |
321 | au_writel(1 << bit, IC0_MASKCLR); |
322 | au_writel(1 << bit, IC0_WAKECLR); | |
1da177e4 LT |
323 | au_sync(); |
324 | } | |
325 | ||
785e3268 | 326 | static void au1x_ic1_mask(unsigned int irq_nr) |
1da177e4 | 327 | { |
785e3268 ML |
328 | unsigned int bit = irq_nr - AU1000_INTC1_INT_BASE; |
329 | au_writel(1 << bit, IC1_MASKCLR); | |
330 | au_writel(1 << bit, IC1_WAKECLR); | |
1da177e4 LT |
331 | au_sync(); |
332 | } | |
333 | ||
785e3268 | 334 | static void au1x_ic0_ack(unsigned int irq_nr) |
1da177e4 | 335 | { |
f3e8d1da RB |
336 | unsigned int bit = irq_nr - AU1000_INTC0_INT_BASE; |
337 | ||
338 | /* | |
339 | * This may assume that we don't get interrupts from | |
1da177e4 LT |
340 | * both edges at once, or if we do, that we don't care. |
341 | */ | |
785e3268 ML |
342 | au_writel(1 << bit, IC0_FALLINGCLR); |
343 | au_writel(1 << bit, IC0_RISINGCLR); | |
1da177e4 LT |
344 | au_sync(); |
345 | } | |
346 | ||
785e3268 | 347 | static void au1x_ic1_ack(unsigned int irq_nr) |
1da177e4 | 348 | { |
785e3268 | 349 | unsigned int bit = irq_nr - AU1000_INTC1_INT_BASE; |
1da177e4 | 350 | |
785e3268 ML |
351 | /* |
352 | * This may assume that we don't get interrupts from | |
353 | * both edges at once, or if we do, that we don't care. | |
354 | */ | |
355 | au_writel(1 << bit, IC1_FALLINGCLR); | |
356 | au_writel(1 << bit, IC1_RISINGCLR); | |
357 | au_sync(); | |
1da177e4 LT |
358 | } |
359 | ||
44f2c586 ML |
360 | static void au1x_ic0_maskack(unsigned int irq_nr) |
361 | { | |
362 | unsigned int bit = irq_nr - AU1000_INTC0_INT_BASE; | |
363 | ||
364 | au_writel(1 << bit, IC0_WAKECLR); | |
365 | au_writel(1 << bit, IC0_MASKCLR); | |
366 | au_writel(1 << bit, IC0_RISINGCLR); | |
367 | au_writel(1 << bit, IC0_FALLINGCLR); | |
368 | au_sync(); | |
369 | } | |
370 | ||
371 | static void au1x_ic1_maskack(unsigned int irq_nr) | |
372 | { | |
373 | unsigned int bit = irq_nr - AU1000_INTC1_INT_BASE; | |
374 | ||
375 | au_writel(1 << bit, IC1_WAKECLR); | |
376 | au_writel(1 << bit, IC1_MASKCLR); | |
377 | au_writel(1 << bit, IC1_RISINGCLR); | |
378 | au_writel(1 << bit, IC1_FALLINGCLR); | |
379 | au_sync(); | |
380 | } | |
381 | ||
785e3268 | 382 | static int au1x_ic1_setwake(unsigned int irq, unsigned int on) |
1da177e4 | 383 | { |
785e3268 ML |
384 | unsigned int bit = irq - AU1000_INTC1_INT_BASE; |
385 | unsigned long wakemsk, flags; | |
1da177e4 | 386 | |
785e3268 ML |
387 | /* only GPIO 0-7 can act as wakeup source: */ |
388 | if ((irq < AU1000_GPIO_0) || (irq > AU1000_GPIO_7)) | |
389 | return -EINVAL; | |
c1dcb14e | 390 | |
785e3268 ML |
391 | local_irq_save(flags); |
392 | wakemsk = au_readl(SYS_WAKEMSK); | |
393 | if (on) | |
394 | wakemsk |= 1 << bit; | |
1da177e4 | 395 | else |
785e3268 ML |
396 | wakemsk &= ~(1 << bit); |
397 | au_writel(wakemsk, SYS_WAKEMSK); | |
398 | au_sync(); | |
399 | local_irq_restore(flags); | |
1da177e4 | 400 | |
785e3268 | 401 | return 0; |
1da177e4 LT |
402 | } |
403 | ||
785e3268 ML |
404 | /* |
405 | * irq_chips for both ICs; this way the mask handlers can be | |
406 | * as short as possible. | |
785e3268 ML |
407 | */ |
408 | static struct irq_chip au1x_ic0_chip = { | |
409 | .name = "Alchemy-IC0", | |
44f2c586 | 410 | .ack = au1x_ic0_ack, |
785e3268 | 411 | .mask = au1x_ic0_mask, |
44f2c586 | 412 | .mask_ack = au1x_ic0_maskack, |
785e3268 ML |
413 | .unmask = au1x_ic0_unmask, |
414 | .set_type = au1x_ic_settype, | |
1da177e4 LT |
415 | }; |
416 | ||
785e3268 ML |
417 | static struct irq_chip au1x_ic1_chip = { |
418 | .name = "Alchemy-IC1", | |
44f2c586 | 419 | .ack = au1x_ic1_ack, |
785e3268 | 420 | .mask = au1x_ic1_mask, |
44f2c586 | 421 | .mask_ack = au1x_ic1_maskack, |
785e3268 ML |
422 | .unmask = au1x_ic1_unmask, |
423 | .set_type = au1x_ic_settype, | |
424 | .set_wake = au1x_ic1_setwake, | |
1da177e4 LT |
425 | }; |
426 | ||
785e3268 | 427 | static int au1x_ic_settype(unsigned int irq, unsigned int flow_type) |
1da177e4 | 428 | { |
785e3268 ML |
429 | struct irq_chip *chip; |
430 | unsigned long icr[6]; | |
431 | unsigned int bit, ic; | |
432 | int ret; | |
433 | ||
434 | if (irq >= AU1000_INTC1_INT_BASE) { | |
435 | bit = irq - AU1000_INTC1_INT_BASE; | |
436 | chip = &au1x_ic1_chip; | |
437 | ic = 1; | |
41bd61a8 | 438 | } else { |
785e3268 ML |
439 | bit = irq - AU1000_INTC0_INT_BASE; |
440 | chip = &au1x_ic0_chip; | |
441 | ic = 0; | |
442 | } | |
443 | ||
444 | if (bit > 31) | |
445 | return -EINVAL; | |
446 | ||
447 | icr[0] = ic ? IC1_CFG0SET : IC0_CFG0SET; | |
448 | icr[1] = ic ? IC1_CFG1SET : IC0_CFG1SET; | |
449 | icr[2] = ic ? IC1_CFG2SET : IC0_CFG2SET; | |
450 | icr[3] = ic ? IC1_CFG0CLR : IC0_CFG0CLR; | |
451 | icr[4] = ic ? IC1_CFG1CLR : IC0_CFG1CLR; | |
452 | icr[5] = ic ? IC1_CFG2CLR : IC0_CFG2CLR; | |
453 | ||
454 | ret = 0; | |
455 | ||
456 | switch (flow_type) { /* cfgregs 2:1:0 */ | |
457 | case IRQ_TYPE_EDGE_RISING: /* 0:0:1 */ | |
458 | au_writel(1 << bit, icr[5]); | |
459 | au_writel(1 << bit, icr[4]); | |
460 | au_writel(1 << bit, icr[0]); | |
461 | set_irq_chip_and_handler_name(irq, chip, | |
462 | handle_edge_irq, "riseedge"); | |
463 | break; | |
464 | case IRQ_TYPE_EDGE_FALLING: /* 0:1:0 */ | |
465 | au_writel(1 << bit, icr[5]); | |
466 | au_writel(1 << bit, icr[1]); | |
467 | au_writel(1 << bit, icr[3]); | |
468 | set_irq_chip_and_handler_name(irq, chip, | |
469 | handle_edge_irq, "falledge"); | |
470 | break; | |
471 | case IRQ_TYPE_EDGE_BOTH: /* 0:1:1 */ | |
472 | au_writel(1 << bit, icr[5]); | |
473 | au_writel(1 << bit, icr[1]); | |
474 | au_writel(1 << bit, icr[0]); | |
475 | set_irq_chip_and_handler_name(irq, chip, | |
476 | handle_edge_irq, "bothedge"); | |
477 | break; | |
478 | case IRQ_TYPE_LEVEL_HIGH: /* 1:0:1 */ | |
479 | au_writel(1 << bit, icr[2]); | |
480 | au_writel(1 << bit, icr[4]); | |
481 | au_writel(1 << bit, icr[0]); | |
482 | set_irq_chip_and_handler_name(irq, chip, | |
483 | handle_level_irq, "hilevel"); | |
484 | break; | |
485 | case IRQ_TYPE_LEVEL_LOW: /* 1:1:0 */ | |
486 | au_writel(1 << bit, icr[2]); | |
487 | au_writel(1 << bit, icr[1]); | |
488 | au_writel(1 << bit, icr[3]); | |
489 | set_irq_chip_and_handler_name(irq, chip, | |
490 | handle_level_irq, "lowlevel"); | |
491 | break; | |
492 | case IRQ_TYPE_NONE: /* 0:0:0 */ | |
493 | au_writel(1 << bit, icr[5]); | |
494 | au_writel(1 << bit, icr[4]); | |
495 | au_writel(1 << bit, icr[3]); | |
496 | /* set at least chip so we can call set_irq_type() on it */ | |
497 | set_irq_chip(irq, chip); | |
498 | break; | |
499 | default: | |
500 | ret = -EINVAL; | |
1da177e4 LT |
501 | } |
502 | au_sync(); | |
1da177e4 | 503 | |
785e3268 ML |
504 | return ret; |
505 | } | |
1da177e4 | 506 | |
785e3268 | 507 | asmlinkage void plat_irq_dispatch(void) |
1da177e4 | 508 | { |
785e3268 ML |
509 | unsigned int pending = read_c0_status() & read_c0_cause(); |
510 | unsigned long s, off, bit; | |
1da177e4 | 511 | |
785e3268 ML |
512 | if (pending & CAUSEF_IP7) { |
513 | do_IRQ(MIPS_CPU_IRQ_BASE + 7); | |
937a8015 | 514 | return; |
785e3268 ML |
515 | } else if (pending & CAUSEF_IP2) { |
516 | s = IC0_REQ0INT; | |
517 | off = AU1000_INTC0_INT_BASE; | |
518 | } else if (pending & CAUSEF_IP3) { | |
519 | s = IC0_REQ1INT; | |
520 | off = AU1000_INTC0_INT_BASE; | |
521 | } else if (pending & CAUSEF_IP4) { | |
522 | s = IC1_REQ0INT; | |
523 | off = AU1000_INTC1_INT_BASE; | |
524 | } else if (pending & CAUSEF_IP5) { | |
525 | s = IC1_REQ1INT; | |
526 | off = AU1000_INTC1_INT_BASE; | |
527 | } else | |
528 | goto spurious; | |
529 | ||
530 | bit = 0; | |
531 | s = au_readl(s); | |
532 | if (unlikely(!s)) { | |
533 | spurious: | |
534 | spurious_interrupt(); | |
535 | return; | |
536 | } | |
e3ad1c23 | 537 | #ifdef AU1000_USB_DEV_REQ_INT |
1da177e4 LT |
538 | /* |
539 | * Because of the tight timing of SETUP token to reply | |
540 | * transactions, the USB devices-side packet complete | |
541 | * interrupt needs the highest priority. | |
542 | */ | |
785e3268 ML |
543 | bit = 1 << (AU1000_USB_DEV_REQ_INT - AU1000_INTC0_INT_BASE); |
544 | if ((pending & CAUSEF_IP2) && (s & bit)) { | |
937a8015 | 545 | do_IRQ(AU1000_USB_DEV_REQ_INT); |
1da177e4 LT |
546 | return; |
547 | } | |
e3ad1c23 | 548 | #endif |
785e3268 | 549 | do_IRQ(__ffs(s) + off); |
1da177e4 LT |
550 | } |
551 | ||
785e3268 | 552 | /* setup edge/level and assign request 0/1 */ |
7e50b2b7 | 553 | static void __init setup_irqmap(struct au1xxx_irqmap *map, int count) |
1da177e4 | 554 | { |
785e3268 ML |
555 | unsigned int bit, irq_nr; |
556 | ||
557 | while (count--) { | |
558 | irq_nr = map[count].im_irq; | |
559 | ||
560 | if (((irq_nr < AU1000_INTC0_INT_BASE) || | |
561 | (irq_nr >= AU1000_INTC0_INT_BASE + 32)) && | |
562 | ((irq_nr < AU1000_INTC1_INT_BASE) || | |
563 | (irq_nr >= AU1000_INTC1_INT_BASE + 32))) | |
564 | continue; | |
565 | ||
566 | if (irq_nr >= AU1000_INTC1_INT_BASE) { | |
567 | bit = irq_nr - AU1000_INTC1_INT_BASE; | |
568 | if (map[count].im_request) | |
569 | au_writel(1 << bit, IC1_ASSIGNCLR); | |
570 | } else { | |
571 | bit = irq_nr - AU1000_INTC0_INT_BASE; | |
572 | if (map[count].im_request) | |
573 | au_writel(1 << bit, IC0_ASSIGNCLR); | |
574 | } | |
e4ac58af | 575 | |
785e3268 ML |
576 | au1x_ic_settype(irq_nr, map[count].im_type); |
577 | } | |
e4ac58af | 578 | } |
41bd61a8 RB |
579 | |
580 | void __init arch_init_irq(void) | |
581 | { | |
582 | int i; | |
41bd61a8 | 583 | |
f3e8d1da RB |
584 | /* |
585 | * Initialize interrupt controllers to a safe state. | |
586 | */ | |
41bd61a8 RB |
587 | au_writel(0xffffffff, IC0_CFG0CLR); |
588 | au_writel(0xffffffff, IC0_CFG1CLR); | |
589 | au_writel(0xffffffff, IC0_CFG2CLR); | |
590 | au_writel(0xffffffff, IC0_MASKCLR); | |
591 | au_writel(0xffffffff, IC0_ASSIGNSET); | |
592 | au_writel(0xffffffff, IC0_WAKECLR); | |
593 | au_writel(0xffffffff, IC0_SRCSET); | |
594 | au_writel(0xffffffff, IC0_FALLINGCLR); | |
595 | au_writel(0xffffffff, IC0_RISINGCLR); | |
596 | au_writel(0x00000000, IC0_TESTBIT); | |
597 | ||
598 | au_writel(0xffffffff, IC1_CFG0CLR); | |
599 | au_writel(0xffffffff, IC1_CFG1CLR); | |
600 | au_writel(0xffffffff, IC1_CFG2CLR); | |
601 | au_writel(0xffffffff, IC1_MASKCLR); | |
602 | au_writel(0xffffffff, IC1_ASSIGNSET); | |
603 | au_writel(0xffffffff, IC1_WAKECLR); | |
604 | au_writel(0xffffffff, IC1_SRCSET); | |
605 | au_writel(0xffffffff, IC1_FALLINGCLR); | |
606 | au_writel(0xffffffff, IC1_RISINGCLR); | |
607 | au_writel(0x00000000, IC1_TESTBIT); | |
608 | ||
f3e8d1da RB |
609 | mips_cpu_irq_init(); |
610 | ||
785e3268 ML |
611 | /* register all 64 possible IC0+IC1 irq sources as type "none". |
612 | * Use set_irq_type() to set edge/level behaviour at runtime. | |
f3e8d1da | 613 | */ |
785e3268 ML |
614 | for (i = AU1000_INTC0_INT_BASE; |
615 | (i < AU1000_INTC0_INT_BASE + 32); i++) | |
616 | au1x_ic_settype(i, IRQ_TYPE_NONE); | |
617 | ||
618 | for (i = AU1000_INTC1_INT_BASE; | |
619 | (i < AU1000_INTC1_INT_BASE + 32); i++) | |
620 | au1x_ic_settype(i, IRQ_TYPE_NONE); | |
41bd61a8 | 621 | |
f3e8d1da | 622 | /* |
785e3268 | 623 | * Initialize IC0, which is fixed per processor. |
f3e8d1da | 624 | */ |
7e50b2b7 | 625 | setup_irqmap(au1xxx_ic0_map, ARRAY_SIZE(au1xxx_ic0_map)); |
785e3268 ML |
626 | |
627 | set_c0_status(IE_IRQ0 | IE_IRQ1 | IE_IRQ2 | IE_IRQ3); | |
628 | } |