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 | |
3eab8095 | 28 | #include <linux/export.h> |
1da177e4 | 29 | #include <linux/init.h> |
1da177e4 | 30 | #include <linux/interrupt.h> |
0f0d85bc | 31 | #include <linux/slab.h> |
4b5c82b5 | 32 | #include <linux/syscore_ops.h> |
1da177e4 | 33 | |
f3e8d1da | 34 | #include <asm/irq_cpu.h> |
1da177e4 | 35 | #include <asm/mach-au1x00/au1000.h> |
3eab8095 | 36 | #include <asm/mach-au1x00/gpio-au1300.h> |
1da177e4 | 37 | |
dca75871 ML |
38 | /* Interrupt Controller register offsets */ |
39 | #define IC_CFG0RD 0x40 | |
40 | #define IC_CFG0SET 0x40 | |
41 | #define IC_CFG0CLR 0x44 | |
42 | #define IC_CFG1RD 0x48 | |
43 | #define IC_CFG1SET 0x48 | |
44 | #define IC_CFG1CLR 0x4C | |
45 | #define IC_CFG2RD 0x50 | |
46 | #define IC_CFG2SET 0x50 | |
47 | #define IC_CFG2CLR 0x54 | |
48 | #define IC_REQ0INT 0x54 | |
49 | #define IC_SRCRD 0x58 | |
50 | #define IC_SRCSET 0x58 | |
51 | #define IC_SRCCLR 0x5C | |
52 | #define IC_REQ1INT 0x5C | |
53 | #define IC_ASSIGNRD 0x60 | |
54 | #define IC_ASSIGNSET 0x60 | |
55 | #define IC_ASSIGNCLR 0x64 | |
56 | #define IC_WAKERD 0x68 | |
57 | #define IC_WAKESET 0x68 | |
58 | #define IC_WAKECLR 0x6C | |
59 | #define IC_MASKRD 0x70 | |
60 | #define IC_MASKSET 0x70 | |
61 | #define IC_MASKCLR 0x74 | |
62 | #define IC_RISINGRD 0x78 | |
63 | #define IC_RISINGCLR 0x78 | |
64 | #define IC_FALLINGRD 0x7C | |
65 | #define IC_FALLINGCLR 0x7C | |
66 | #define IC_TESTBIT 0x80 | |
67 | ||
3eab8095 ML |
68 | /* per-processor fixed function irqs */ |
69 | struct alchemy_irqmap { | |
70 | int irq; /* linux IRQ number */ | |
71 | int type; /* IRQ_TYPE_ */ | |
72 | int prio; /* irq priority, 0 highest, 3 lowest */ | |
73 | int internal; /* GPIC: internal source (no ext. pin)? */ | |
74 | }; | |
75 | ||
76 | static int au1x_ic_settype(struct irq_data *d, unsigned int type); | |
77 | static int au1300_gpic_settype(struct irq_data *d, unsigned int type); | |
78 | ||
785e3268 | 79 | |
5047201b ML |
80 | /* NOTE on interrupt priorities: The original writers of this code said: |
81 | * | |
82 | * Because of the tight timing of SETUP token to reply transactions, | |
83 | * the USB devices-side packet complete interrupt (USB_DEV_REQ_INT) | |
84 | * needs the highest priority. | |
85 | */ | |
3eab8095 | 86 | struct alchemy_irqmap au1000_irqmap[] __initdata = { |
70342287 RB |
87 | { AU1000_UART0_INT, IRQ_TYPE_LEVEL_HIGH, 1, 0 }, |
88 | { AU1000_UART1_INT, IRQ_TYPE_LEVEL_HIGH, 1, 0 }, | |
89 | { AU1000_UART2_INT, IRQ_TYPE_LEVEL_HIGH, 1, 0 }, | |
90 | { AU1000_UART3_INT, IRQ_TYPE_LEVEL_HIGH, 1, 0 }, | |
91 | { AU1000_SSI0_INT, IRQ_TYPE_LEVEL_HIGH, 1, 0 }, | |
92 | { AU1000_SSI1_INT, IRQ_TYPE_LEVEL_HIGH, 1, 0 }, | |
93 | { AU1000_DMA_INT_BASE, IRQ_TYPE_LEVEL_HIGH, 1, 0 }, | |
94 | { AU1000_DMA_INT_BASE+1, IRQ_TYPE_LEVEL_HIGH, 1, 0 }, | |
95 | { AU1000_DMA_INT_BASE+2, IRQ_TYPE_LEVEL_HIGH, 1, 0 }, | |
96 | { AU1000_DMA_INT_BASE+3, IRQ_TYPE_LEVEL_HIGH, 1, 0 }, | |
97 | { AU1000_DMA_INT_BASE+4, IRQ_TYPE_LEVEL_HIGH, 1, 0 }, | |
98 | { AU1000_DMA_INT_BASE+5, IRQ_TYPE_LEVEL_HIGH, 1, 0 }, | |
99 | { AU1000_DMA_INT_BASE+6, IRQ_TYPE_LEVEL_HIGH, 1, 0 }, | |
100 | { AU1000_DMA_INT_BASE+7, IRQ_TYPE_LEVEL_HIGH, 1, 0 }, | |
3eab8095 ML |
101 | { AU1000_TOY_INT, IRQ_TYPE_EDGE_RISING, 1, 0 }, |
102 | { AU1000_TOY_MATCH0_INT, IRQ_TYPE_EDGE_RISING, 1, 0 }, | |
103 | { AU1000_TOY_MATCH1_INT, IRQ_TYPE_EDGE_RISING, 1, 0 }, | |
104 | { AU1000_TOY_MATCH2_INT, IRQ_TYPE_EDGE_RISING, 1, 0 }, | |
105 | { AU1000_RTC_INT, IRQ_TYPE_EDGE_RISING, 1, 0 }, | |
106 | { AU1000_RTC_MATCH0_INT, IRQ_TYPE_EDGE_RISING, 1, 0 }, | |
107 | { AU1000_RTC_MATCH1_INT, IRQ_TYPE_EDGE_RISING, 1, 0 }, | |
108 | { AU1000_RTC_MATCH2_INT, IRQ_TYPE_EDGE_RISING, 0, 0 }, | |
70342287 RB |
109 | { AU1000_IRDA_TX_INT, IRQ_TYPE_LEVEL_HIGH, 1, 0 }, |
110 | { AU1000_IRDA_RX_INT, IRQ_TYPE_LEVEL_HIGH, 1, 0 }, | |
111 | { AU1000_USB_DEV_REQ_INT, IRQ_TYPE_LEVEL_HIGH, 0, 0 }, | |
3eab8095 | 112 | { AU1000_USB_DEV_SUS_INT, IRQ_TYPE_EDGE_RISING, 1, 0 }, |
70342287 | 113 | { AU1000_USB_HOST_INT, IRQ_TYPE_LEVEL_LOW, 1, 0 }, |
3eab8095 | 114 | { AU1000_ACSYNC_INT, IRQ_TYPE_EDGE_RISING, 1, 0 }, |
70342287 RB |
115 | { AU1000_MAC0_DMA_INT, IRQ_TYPE_LEVEL_HIGH, 1, 0 }, |
116 | { AU1000_MAC1_DMA_INT, IRQ_TYPE_LEVEL_HIGH, 1, 0 }, | |
3eab8095 ML |
117 | { AU1000_AC97C_INT, IRQ_TYPE_EDGE_RISING, 1, 0 }, |
118 | { -1, }, | |
ef6c1fd6 ML |
119 | }; |
120 | ||
3eab8095 | 121 | struct alchemy_irqmap au1500_irqmap[] __initdata = { |
70342287 RB |
122 | { AU1500_UART0_INT, IRQ_TYPE_LEVEL_HIGH, 1, 0 }, |
123 | { AU1500_PCI_INTA, IRQ_TYPE_LEVEL_LOW, 1, 0 }, | |
124 | { AU1500_PCI_INTB, IRQ_TYPE_LEVEL_LOW, 1, 0 }, | |
125 | { AU1500_UART3_INT, IRQ_TYPE_LEVEL_HIGH, 1, 0 }, | |
126 | { AU1500_PCI_INTC, IRQ_TYPE_LEVEL_LOW, 1, 0 }, | |
127 | { AU1500_PCI_INTD, IRQ_TYPE_LEVEL_LOW, 1, 0 }, | |
128 | { AU1500_DMA_INT_BASE, IRQ_TYPE_LEVEL_HIGH, 1, 0 }, | |
129 | { AU1500_DMA_INT_BASE+1, IRQ_TYPE_LEVEL_HIGH, 1, 0 }, | |
130 | { AU1500_DMA_INT_BASE+2, IRQ_TYPE_LEVEL_HIGH, 1, 0 }, | |
131 | { AU1500_DMA_INT_BASE+3, IRQ_TYPE_LEVEL_HIGH, 1, 0 }, | |
132 | { AU1500_DMA_INT_BASE+4, IRQ_TYPE_LEVEL_HIGH, 1, 0 }, | |
133 | { AU1500_DMA_INT_BASE+5, IRQ_TYPE_LEVEL_HIGH, 1, 0 }, | |
134 | { AU1500_DMA_INT_BASE+6, IRQ_TYPE_LEVEL_HIGH, 1, 0 }, | |
135 | { AU1500_DMA_INT_BASE+7, IRQ_TYPE_LEVEL_HIGH, 1, 0 }, | |
3eab8095 ML |
136 | { AU1500_TOY_INT, IRQ_TYPE_EDGE_RISING, 1, 0 }, |
137 | { AU1500_TOY_MATCH0_INT, IRQ_TYPE_EDGE_RISING, 1, 0 }, | |
138 | { AU1500_TOY_MATCH1_INT, IRQ_TYPE_EDGE_RISING, 1, 0 }, | |
139 | { AU1500_TOY_MATCH2_INT, IRQ_TYPE_EDGE_RISING, 1, 0 }, | |
140 | { AU1500_RTC_INT, IRQ_TYPE_EDGE_RISING, 1, 0 }, | |
141 | { AU1500_RTC_MATCH0_INT, IRQ_TYPE_EDGE_RISING, 1, 0 }, | |
142 | { AU1500_RTC_MATCH1_INT, IRQ_TYPE_EDGE_RISING, 1, 0 }, | |
143 | { AU1500_RTC_MATCH2_INT, IRQ_TYPE_EDGE_RISING, 0, 0 }, | |
70342287 | 144 | { AU1500_USB_DEV_REQ_INT, IRQ_TYPE_LEVEL_HIGH, 0, 0 }, |
3eab8095 | 145 | { AU1500_USB_DEV_SUS_INT, IRQ_TYPE_EDGE_RISING, 1, 0 }, |
70342287 | 146 | { AU1500_USB_HOST_INT, IRQ_TYPE_LEVEL_LOW, 1, 0 }, |
3eab8095 | 147 | { AU1500_ACSYNC_INT, IRQ_TYPE_EDGE_RISING, 1, 0 }, |
70342287 RB |
148 | { AU1500_MAC0_DMA_INT, IRQ_TYPE_LEVEL_HIGH, 1, 0 }, |
149 | { AU1500_MAC1_DMA_INT, IRQ_TYPE_LEVEL_HIGH, 1, 0 }, | |
3eab8095 | 150 | { AU1500_AC97C_INT, IRQ_TYPE_EDGE_RISING, 1, 0 }, |
ef6c1fd6 ML |
151 | { -1, }, |
152 | }; | |
785e3268 | 153 | |
3eab8095 | 154 | struct alchemy_irqmap au1100_irqmap[] __initdata = { |
70342287 RB |
155 | { AU1100_UART0_INT, IRQ_TYPE_LEVEL_HIGH, 1, 0 }, |
156 | { AU1100_UART1_INT, IRQ_TYPE_LEVEL_HIGH, 1, 0 }, | |
157 | { AU1100_SD_INT, IRQ_TYPE_LEVEL_HIGH, 1, 0 }, | |
158 | { AU1100_UART3_INT, IRQ_TYPE_LEVEL_HIGH, 1, 0 }, | |
159 | { AU1100_SSI0_INT, IRQ_TYPE_LEVEL_HIGH, 1, 0 }, | |
160 | { AU1100_SSI1_INT, IRQ_TYPE_LEVEL_HIGH, 1, 0 }, | |
161 | { AU1100_DMA_INT_BASE, IRQ_TYPE_LEVEL_HIGH, 1, 0 }, | |
162 | { AU1100_DMA_INT_BASE+1, IRQ_TYPE_LEVEL_HIGH, 1, 0 }, | |
163 | { AU1100_DMA_INT_BASE+2, IRQ_TYPE_LEVEL_HIGH, 1, 0 }, | |
164 | { AU1100_DMA_INT_BASE+3, IRQ_TYPE_LEVEL_HIGH, 1, 0 }, | |
165 | { AU1100_DMA_INT_BASE+4, IRQ_TYPE_LEVEL_HIGH, 1, 0 }, | |
166 | { AU1100_DMA_INT_BASE+5, IRQ_TYPE_LEVEL_HIGH, 1, 0 }, | |
167 | { AU1100_DMA_INT_BASE+6, IRQ_TYPE_LEVEL_HIGH, 1, 0 }, | |
168 | { AU1100_DMA_INT_BASE+7, IRQ_TYPE_LEVEL_HIGH, 1, 0 }, | |
3eab8095 ML |
169 | { AU1100_TOY_INT, IRQ_TYPE_EDGE_RISING, 1, 0 }, |
170 | { AU1100_TOY_MATCH0_INT, IRQ_TYPE_EDGE_RISING, 1, 0 }, | |
171 | { AU1100_TOY_MATCH1_INT, IRQ_TYPE_EDGE_RISING, 1, 0 }, | |
172 | { AU1100_TOY_MATCH2_INT, IRQ_TYPE_EDGE_RISING, 1, 0 }, | |
173 | { AU1100_RTC_INT, IRQ_TYPE_EDGE_RISING, 1, 0 }, | |
174 | { AU1100_RTC_MATCH0_INT, IRQ_TYPE_EDGE_RISING, 1, 0 }, | |
175 | { AU1100_RTC_MATCH1_INT, IRQ_TYPE_EDGE_RISING, 1, 0 }, | |
176 | { AU1100_RTC_MATCH2_INT, IRQ_TYPE_EDGE_RISING, 0, 0 }, | |
70342287 RB |
177 | { AU1100_IRDA_TX_INT, IRQ_TYPE_LEVEL_HIGH, 1, 0 }, |
178 | { AU1100_IRDA_RX_INT, IRQ_TYPE_LEVEL_HIGH, 1, 0 }, | |
179 | { AU1100_USB_DEV_REQ_INT, IRQ_TYPE_LEVEL_HIGH, 0, 0 }, | |
3eab8095 | 180 | { AU1100_USB_DEV_SUS_INT, IRQ_TYPE_EDGE_RISING, 1, 0 }, |
70342287 | 181 | { AU1100_USB_HOST_INT, IRQ_TYPE_LEVEL_LOW, 1, 0 }, |
3eab8095 | 182 | { AU1100_ACSYNC_INT, IRQ_TYPE_EDGE_RISING, 1, 0 }, |
70342287 RB |
183 | { AU1100_MAC0_DMA_INT, IRQ_TYPE_LEVEL_HIGH, 1, 0 }, |
184 | { AU1100_LCD_INT, IRQ_TYPE_LEVEL_HIGH, 1, 0 }, | |
3eab8095 | 185 | { AU1100_AC97C_INT, IRQ_TYPE_EDGE_RISING, 1, 0 }, |
ef6c1fd6 ML |
186 | { -1, }, |
187 | }; | |
785e3268 | 188 | |
3eab8095 | 189 | struct alchemy_irqmap au1550_irqmap[] __initdata = { |
70342287 RB |
190 | { AU1550_UART0_INT, IRQ_TYPE_LEVEL_HIGH, 1, 0 }, |
191 | { AU1550_PCI_INTA, IRQ_TYPE_LEVEL_LOW, 1, 0 }, | |
192 | { AU1550_PCI_INTB, IRQ_TYPE_LEVEL_LOW, 1, 0 }, | |
193 | { AU1550_DDMA_INT, IRQ_TYPE_LEVEL_HIGH, 1, 0 }, | |
194 | { AU1550_CRYPTO_INT, IRQ_TYPE_LEVEL_HIGH, 1, 0 }, | |
195 | { AU1550_PCI_INTC, IRQ_TYPE_LEVEL_LOW, 1, 0 }, | |
196 | { AU1550_PCI_INTD, IRQ_TYPE_LEVEL_LOW, 1, 0 }, | |
197 | { AU1550_PCI_RST_INT, IRQ_TYPE_LEVEL_LOW, 1, 0 }, | |
198 | { AU1550_UART1_INT, IRQ_TYPE_LEVEL_HIGH, 1, 0 }, | |
199 | { AU1550_UART3_INT, IRQ_TYPE_LEVEL_HIGH, 1, 0 }, | |
200 | { AU1550_PSC0_INT, IRQ_TYPE_LEVEL_HIGH, 1, 0 }, | |
201 | { AU1550_PSC1_INT, IRQ_TYPE_LEVEL_HIGH, 1, 0 }, | |
202 | { AU1550_PSC2_INT, IRQ_TYPE_LEVEL_HIGH, 1, 0 }, | |
203 | { AU1550_PSC3_INT, IRQ_TYPE_LEVEL_HIGH, 1, 0 }, | |
3eab8095 ML |
204 | { AU1550_TOY_INT, IRQ_TYPE_EDGE_RISING, 1, 0 }, |
205 | { AU1550_TOY_MATCH0_INT, IRQ_TYPE_EDGE_RISING, 1, 0 }, | |
206 | { AU1550_TOY_MATCH1_INT, IRQ_TYPE_EDGE_RISING, 1, 0 }, | |
207 | { AU1550_TOY_MATCH2_INT, IRQ_TYPE_EDGE_RISING, 1, 0 }, | |
208 | { AU1550_RTC_INT, IRQ_TYPE_EDGE_RISING, 1, 0 }, | |
209 | { AU1550_RTC_MATCH0_INT, IRQ_TYPE_EDGE_RISING, 1, 0 }, | |
210 | { AU1550_RTC_MATCH1_INT, IRQ_TYPE_EDGE_RISING, 1, 0 }, | |
211 | { AU1550_RTC_MATCH2_INT, IRQ_TYPE_EDGE_RISING, 0, 0 }, | |
212 | { AU1550_NAND_INT, IRQ_TYPE_EDGE_RISING, 1, 0 }, | |
70342287 | 213 | { AU1550_USB_DEV_REQ_INT, IRQ_TYPE_LEVEL_HIGH, 0, 0 }, |
3eab8095 | 214 | { AU1550_USB_DEV_SUS_INT, IRQ_TYPE_EDGE_RISING, 1, 0 }, |
70342287 RB |
215 | { AU1550_USB_HOST_INT, IRQ_TYPE_LEVEL_LOW, 1, 0 }, |
216 | { AU1550_MAC0_DMA_INT, IRQ_TYPE_LEVEL_HIGH, 1, 0 }, | |
217 | { AU1550_MAC1_DMA_INT, IRQ_TYPE_LEVEL_HIGH, 1, 0 }, | |
ef6c1fd6 ML |
218 | { -1, }, |
219 | }; | |
785e3268 | 220 | |
3eab8095 | 221 | struct alchemy_irqmap au1200_irqmap[] __initdata = { |
70342287 | 222 | { AU1200_UART0_INT, IRQ_TYPE_LEVEL_HIGH, 1, 0 }, |
3eab8095 | 223 | { AU1200_SWT_INT, IRQ_TYPE_EDGE_RISING, 1, 0 }, |
70342287 RB |
224 | { AU1200_SD_INT, IRQ_TYPE_LEVEL_HIGH, 1, 0 }, |
225 | { AU1200_DDMA_INT, IRQ_TYPE_LEVEL_HIGH, 1, 0 }, | |
226 | { AU1200_MAE_BE_INT, IRQ_TYPE_LEVEL_HIGH, 1, 0 }, | |
227 | { AU1200_UART1_INT, IRQ_TYPE_LEVEL_HIGH, 1, 0 }, | |
228 | { AU1200_MAE_FE_INT, IRQ_TYPE_LEVEL_HIGH, 1, 0 }, | |
229 | { AU1200_PSC0_INT, IRQ_TYPE_LEVEL_HIGH, 1, 0 }, | |
230 | { AU1200_PSC1_INT, IRQ_TYPE_LEVEL_HIGH, 1, 0 }, | |
231 | { AU1200_AES_INT, IRQ_TYPE_LEVEL_HIGH, 1, 0 }, | |
232 | { AU1200_CAMERA_INT, IRQ_TYPE_LEVEL_HIGH, 1, 0 }, | |
3eab8095 ML |
233 | { AU1200_TOY_INT, IRQ_TYPE_EDGE_RISING, 1, 0 }, |
234 | { AU1200_TOY_MATCH0_INT, IRQ_TYPE_EDGE_RISING, 1, 0 }, | |
235 | { AU1200_TOY_MATCH1_INT, IRQ_TYPE_EDGE_RISING, 1, 0 }, | |
236 | { AU1200_TOY_MATCH2_INT, IRQ_TYPE_EDGE_RISING, 1, 0 }, | |
237 | { AU1200_RTC_INT, IRQ_TYPE_EDGE_RISING, 1, 0 }, | |
238 | { AU1200_RTC_MATCH0_INT, IRQ_TYPE_EDGE_RISING, 1, 0 }, | |
239 | { AU1200_RTC_MATCH1_INT, IRQ_TYPE_EDGE_RISING, 1, 0 }, | |
240 | { AU1200_RTC_MATCH2_INT, IRQ_TYPE_EDGE_RISING, 0, 0 }, | |
241 | { AU1200_NAND_INT, IRQ_TYPE_EDGE_RISING, 1, 0 }, | |
70342287 RB |
242 | { AU1200_USB_INT, IRQ_TYPE_LEVEL_HIGH, 1, 0 }, |
243 | { AU1200_LCD_INT, IRQ_TYPE_LEVEL_HIGH, 1, 0 }, | |
244 | { AU1200_MAE_BOTH_INT, IRQ_TYPE_LEVEL_HIGH, 1, 0 }, | |
ef6c1fd6 ML |
245 | { -1, }, |
246 | }; | |
785e3268 | 247 | |
3eab8095 ML |
248 | static struct alchemy_irqmap au1300_irqmap[] __initdata = { |
249 | /* multifunction: gpio pin or device */ | |
250 | { AU1300_UART1_INT, IRQ_TYPE_LEVEL_HIGH, 1, 0, }, | |
251 | { AU1300_UART2_INT, IRQ_TYPE_LEVEL_HIGH, 1, 0, }, | |
252 | { AU1300_UART3_INT, IRQ_TYPE_LEVEL_HIGH, 1, 0, }, | |
253 | { AU1300_SD1_INT, IRQ_TYPE_LEVEL_HIGH, 1, 0, }, | |
254 | { AU1300_SD2_INT, IRQ_TYPE_LEVEL_HIGH, 1, 0, }, | |
255 | { AU1300_PSC0_INT, IRQ_TYPE_LEVEL_HIGH, 1, 0, }, | |
256 | { AU1300_PSC1_INT, IRQ_TYPE_LEVEL_HIGH, 1, 0, }, | |
257 | { AU1300_PSC2_INT, IRQ_TYPE_LEVEL_HIGH, 1, 0, }, | |
258 | { AU1300_PSC3_INT, IRQ_TYPE_LEVEL_HIGH, 1, 0, }, | |
259 | { AU1300_NAND_INT, IRQ_TYPE_LEVEL_HIGH, 1, 0, }, | |
260 | /* au1300 internal */ | |
261 | { AU1300_DDMA_INT, IRQ_TYPE_LEVEL_HIGH, 1, 1, }, | |
262 | { AU1300_MMU_INT, IRQ_TYPE_LEVEL_HIGH, 1, 1, }, | |
263 | { AU1300_MPU_INT, IRQ_TYPE_LEVEL_HIGH, 1, 1, }, | |
264 | { AU1300_GPU_INT, IRQ_TYPE_LEVEL_HIGH, 1, 1, }, | |
265 | { AU1300_UDMA_INT, IRQ_TYPE_LEVEL_HIGH, 1, 1, }, | |
266 | { AU1300_TOY_INT, IRQ_TYPE_EDGE_RISING, 1, 1, }, | |
267 | { AU1300_TOY_MATCH0_INT, IRQ_TYPE_EDGE_RISING, 1, 1, }, | |
268 | { AU1300_TOY_MATCH1_INT, IRQ_TYPE_EDGE_RISING, 1, 1, }, | |
269 | { AU1300_TOY_MATCH2_INT, IRQ_TYPE_EDGE_RISING, 1, 1, }, | |
270 | { AU1300_RTC_INT, IRQ_TYPE_EDGE_RISING, 1, 1, }, | |
271 | { AU1300_RTC_MATCH0_INT, IRQ_TYPE_EDGE_RISING, 1, 1, }, | |
272 | { AU1300_RTC_MATCH1_INT, IRQ_TYPE_EDGE_RISING, 1, 1, }, | |
273 | { AU1300_RTC_MATCH2_INT, IRQ_TYPE_EDGE_RISING, 0, 1, }, | |
274 | { AU1300_UART0_INT, IRQ_TYPE_LEVEL_HIGH, 1, 1, }, | |
275 | { AU1300_SD0_INT, IRQ_TYPE_LEVEL_HIGH, 1, 1, }, | |
276 | { AU1300_USB_INT, IRQ_TYPE_LEVEL_HIGH, 1, 1, }, | |
277 | { AU1300_LCD_INT, IRQ_TYPE_LEVEL_HIGH, 1, 1, }, | |
278 | { AU1300_BSA_INT, IRQ_TYPE_LEVEL_HIGH, 1, 1, }, | |
279 | { AU1300_MPE_INT, IRQ_TYPE_EDGE_RISING, 1, 1, }, | |
280 | { AU1300_ITE_INT, IRQ_TYPE_LEVEL_HIGH, 1, 1, }, | |
281 | { AU1300_AES_INT, IRQ_TYPE_LEVEL_HIGH, 1, 1, }, | |
282 | { AU1300_CIM_INT, IRQ_TYPE_LEVEL_HIGH, 1, 1, }, | |
283 | { -1, }, /* terminator */ | |
785e3268 | 284 | }; |
1da177e4 | 285 | |
3eab8095 | 286 | /******************************************************************************/ |
1da177e4 | 287 | |
d24c1a26 | 288 | static void au1x_ic0_unmask(struct irq_data *d) |
1da177e4 | 289 | { |
d24c1a26 | 290 | unsigned int bit = d->irq - AU1000_INTC0_INT_BASE; |
dca75871 ML |
291 | void __iomem *base = (void __iomem *)KSEG1ADDR(AU1000_IC0_PHYS_ADDR); |
292 | ||
293 | __raw_writel(1 << bit, base + IC_MASKSET); | |
294 | __raw_writel(1 << bit, base + IC_WAKESET); | |
295 | wmb(); | |
1da177e4 LT |
296 | } |
297 | ||
d24c1a26 | 298 | static void au1x_ic1_unmask(struct irq_data *d) |
1da177e4 | 299 | { |
d24c1a26 | 300 | unsigned int bit = d->irq - AU1000_INTC1_INT_BASE; |
dca75871 ML |
301 | void __iomem *base = (void __iomem *)KSEG1ADDR(AU1000_IC1_PHYS_ADDR); |
302 | ||
303 | __raw_writel(1 << bit, base + IC_MASKSET); | |
304 | __raw_writel(1 << bit, base + IC_WAKESET); | |
dca75871 | 305 | wmb(); |
1da177e4 LT |
306 | } |
307 | ||
d24c1a26 | 308 | static void au1x_ic0_mask(struct irq_data *d) |
1da177e4 | 309 | { |
d24c1a26 | 310 | unsigned int bit = d->irq - AU1000_INTC0_INT_BASE; |
dca75871 ML |
311 | void __iomem *base = (void __iomem *)KSEG1ADDR(AU1000_IC0_PHYS_ADDR); |
312 | ||
313 | __raw_writel(1 << bit, base + IC_MASKCLR); | |
314 | __raw_writel(1 << bit, base + IC_WAKECLR); | |
315 | wmb(); | |
1da177e4 LT |
316 | } |
317 | ||
d24c1a26 | 318 | static void au1x_ic1_mask(struct irq_data *d) |
1da177e4 | 319 | { |
d24c1a26 | 320 | unsigned int bit = d->irq - AU1000_INTC1_INT_BASE; |
dca75871 ML |
321 | void __iomem *base = (void __iomem *)KSEG1ADDR(AU1000_IC1_PHYS_ADDR); |
322 | ||
323 | __raw_writel(1 << bit, base + IC_MASKCLR); | |
324 | __raw_writel(1 << bit, base + IC_WAKECLR); | |
325 | wmb(); | |
1da177e4 LT |
326 | } |
327 | ||
d24c1a26 | 328 | static void au1x_ic0_ack(struct irq_data *d) |
1da177e4 | 329 | { |
d24c1a26 | 330 | unsigned int bit = d->irq - AU1000_INTC0_INT_BASE; |
dca75871 | 331 | void __iomem *base = (void __iomem *)KSEG1ADDR(AU1000_IC0_PHYS_ADDR); |
f3e8d1da RB |
332 | |
333 | /* | |
334 | * This may assume that we don't get interrupts from | |
1da177e4 LT |
335 | * both edges at once, or if we do, that we don't care. |
336 | */ | |
dca75871 ML |
337 | __raw_writel(1 << bit, base + IC_FALLINGCLR); |
338 | __raw_writel(1 << bit, base + IC_RISINGCLR); | |
339 | wmb(); | |
1da177e4 LT |
340 | } |
341 | ||
d24c1a26 | 342 | static void au1x_ic1_ack(struct irq_data *d) |
1da177e4 | 343 | { |
d24c1a26 | 344 | unsigned int bit = d->irq - AU1000_INTC1_INT_BASE; |
dca75871 | 345 | void __iomem *base = (void __iomem *)KSEG1ADDR(AU1000_IC1_PHYS_ADDR); |
1da177e4 | 346 | |
785e3268 ML |
347 | /* |
348 | * This may assume that we don't get interrupts from | |
349 | * both edges at once, or if we do, that we don't care. | |
350 | */ | |
dca75871 ML |
351 | __raw_writel(1 << bit, base + IC_FALLINGCLR); |
352 | __raw_writel(1 << bit, base + IC_RISINGCLR); | |
353 | wmb(); | |
1da177e4 LT |
354 | } |
355 | ||
d24c1a26 | 356 | static void au1x_ic0_maskack(struct irq_data *d) |
44f2c586 | 357 | { |
d24c1a26 | 358 | unsigned int bit = d->irq - AU1000_INTC0_INT_BASE; |
dca75871 | 359 | void __iomem *base = (void __iomem *)KSEG1ADDR(AU1000_IC0_PHYS_ADDR); |
44f2c586 | 360 | |
dca75871 ML |
361 | __raw_writel(1 << bit, base + IC_WAKECLR); |
362 | __raw_writel(1 << bit, base + IC_MASKCLR); | |
363 | __raw_writel(1 << bit, base + IC_RISINGCLR); | |
364 | __raw_writel(1 << bit, base + IC_FALLINGCLR); | |
365 | wmb(); | |
44f2c586 ML |
366 | } |
367 | ||
d24c1a26 | 368 | static void au1x_ic1_maskack(struct irq_data *d) |
44f2c586 | 369 | { |
d24c1a26 | 370 | unsigned int bit = d->irq - AU1000_INTC1_INT_BASE; |
dca75871 | 371 | void __iomem *base = (void __iomem *)KSEG1ADDR(AU1000_IC1_PHYS_ADDR); |
44f2c586 | 372 | |
dca75871 ML |
373 | __raw_writel(1 << bit, base + IC_WAKECLR); |
374 | __raw_writel(1 << bit, base + IC_MASKCLR); | |
375 | __raw_writel(1 << bit, base + IC_RISINGCLR); | |
376 | __raw_writel(1 << bit, base + IC_FALLINGCLR); | |
377 | wmb(); | |
44f2c586 ML |
378 | } |
379 | ||
d24c1a26 | 380 | static int au1x_ic1_setwake(struct irq_data *d, unsigned int on) |
1da177e4 | 381 | { |
d24c1a26 | 382 | int bit = d->irq - AU1000_INTC1_INT_BASE; |
785e3268 | 383 | unsigned long wakemsk, flags; |
1da177e4 | 384 | |
78814465 ML |
385 | /* only GPIO 0-7 can act as wakeup source. Fortunately these |
386 | * are wired up identically on all supported variants. | |
387 | */ | |
388 | if ((bit < 0) || (bit > 7)) | |
785e3268 | 389 | return -EINVAL; |
c1dcb14e | 390 | |
785e3268 | 391 | local_irq_save(flags); |
dca75871 | 392 | wakemsk = __raw_readl((void __iomem *)SYS_WAKEMSK); |
785e3268 ML |
393 | if (on) |
394 | wakemsk |= 1 << bit; | |
1da177e4 | 395 | else |
785e3268 | 396 | wakemsk &= ~(1 << bit); |
dca75871 ML |
397 | __raw_writel(wakemsk, (void __iomem *)SYS_WAKEMSK); |
398 | wmb(); | |
785e3268 | 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", | |
d24c1a26 TG |
410 | .irq_ack = au1x_ic0_ack, |
411 | .irq_mask = au1x_ic0_mask, | |
412 | .irq_mask_ack = au1x_ic0_maskack, | |
413 | .irq_unmask = au1x_ic0_unmask, | |
414 | .irq_set_type = au1x_ic_settype, | |
1da177e4 LT |
415 | }; |
416 | ||
785e3268 ML |
417 | static struct irq_chip au1x_ic1_chip = { |
418 | .name = "Alchemy-IC1", | |
d24c1a26 TG |
419 | .irq_ack = au1x_ic1_ack, |
420 | .irq_mask = au1x_ic1_mask, | |
421 | .irq_mask_ack = au1x_ic1_maskack, | |
422 | .irq_unmask = au1x_ic1_unmask, | |
423 | .irq_set_type = au1x_ic_settype, | |
424 | .irq_set_wake = au1x_ic1_setwake, | |
1da177e4 LT |
425 | }; |
426 | ||
d24c1a26 | 427 | static int au1x_ic_settype(struct irq_data *d, unsigned int flow_type) |
1da177e4 | 428 | { |
785e3268 | 429 | struct irq_chip *chip; |
dca75871 | 430 | unsigned int bit, irq = d->irq; |
d24c1a26 TG |
431 | irq_flow_handler_t handler = NULL; |
432 | unsigned char *name = NULL; | |
dca75871 | 433 | void __iomem *base; |
785e3268 ML |
434 | int ret; |
435 | ||
436 | if (irq >= AU1000_INTC1_INT_BASE) { | |
437 | bit = irq - AU1000_INTC1_INT_BASE; | |
438 | chip = &au1x_ic1_chip; | |
dca75871 | 439 | base = (void __iomem *)KSEG1ADDR(AU1000_IC1_PHYS_ADDR); |
41bd61a8 | 440 | } else { |
785e3268 ML |
441 | bit = irq - AU1000_INTC0_INT_BASE; |
442 | chip = &au1x_ic0_chip; | |
dca75871 | 443 | base = (void __iomem *)KSEG1ADDR(AU1000_IC0_PHYS_ADDR); |
785e3268 ML |
444 | } |
445 | ||
446 | if (bit > 31) | |
447 | return -EINVAL; | |
448 | ||
785e3268 ML |
449 | ret = 0; |
450 | ||
451 | switch (flow_type) { /* cfgregs 2:1:0 */ | |
452 | case IRQ_TYPE_EDGE_RISING: /* 0:0:1 */ | |
dca75871 ML |
453 | __raw_writel(1 << bit, base + IC_CFG2CLR); |
454 | __raw_writel(1 << bit, base + IC_CFG1CLR); | |
455 | __raw_writel(1 << bit, base + IC_CFG0SET); | |
d24c1a26 TG |
456 | handler = handle_edge_irq; |
457 | name = "riseedge"; | |
785e3268 ML |
458 | break; |
459 | case IRQ_TYPE_EDGE_FALLING: /* 0:1:0 */ | |
dca75871 ML |
460 | __raw_writel(1 << bit, base + IC_CFG2CLR); |
461 | __raw_writel(1 << bit, base + IC_CFG1SET); | |
462 | __raw_writel(1 << bit, base + IC_CFG0CLR); | |
d24c1a26 TG |
463 | handler = handle_edge_irq; |
464 | name = "falledge"; | |
785e3268 ML |
465 | break; |
466 | case IRQ_TYPE_EDGE_BOTH: /* 0:1:1 */ | |
dca75871 ML |
467 | __raw_writel(1 << bit, base + IC_CFG2CLR); |
468 | __raw_writel(1 << bit, base + IC_CFG1SET); | |
469 | __raw_writel(1 << bit, base + IC_CFG0SET); | |
d24c1a26 TG |
470 | handler = handle_edge_irq; |
471 | name = "bothedge"; | |
785e3268 ML |
472 | break; |
473 | case IRQ_TYPE_LEVEL_HIGH: /* 1:0:1 */ | |
dca75871 ML |
474 | __raw_writel(1 << bit, base + IC_CFG2SET); |
475 | __raw_writel(1 << bit, base + IC_CFG1CLR); | |
476 | __raw_writel(1 << bit, base + IC_CFG0SET); | |
d24c1a26 TG |
477 | handler = handle_level_irq; |
478 | name = "hilevel"; | |
785e3268 ML |
479 | break; |
480 | case IRQ_TYPE_LEVEL_LOW: /* 1:1:0 */ | |
dca75871 ML |
481 | __raw_writel(1 << bit, base + IC_CFG2SET); |
482 | __raw_writel(1 << bit, base + IC_CFG1SET); | |
483 | __raw_writel(1 << bit, base + IC_CFG0CLR); | |
d24c1a26 TG |
484 | handler = handle_level_irq; |
485 | name = "lowlevel"; | |
785e3268 ML |
486 | break; |
487 | case IRQ_TYPE_NONE: /* 0:0:0 */ | |
dca75871 ML |
488 | __raw_writel(1 << bit, base + IC_CFG2CLR); |
489 | __raw_writel(1 << bit, base + IC_CFG1CLR); | |
490 | __raw_writel(1 << bit, base + IC_CFG0CLR); | |
785e3268 ML |
491 | break; |
492 | default: | |
493 | ret = -EINVAL; | |
1da177e4 | 494 | } |
d24c1a26 TG |
495 | __irq_set_chip_handler_name_locked(d->irq, chip, handler, name); |
496 | ||
dca75871 | 497 | wmb(); |
1da177e4 | 498 | |
785e3268 ML |
499 | return ret; |
500 | } | |
1da177e4 | 501 | |
3eab8095 ML |
502 | /******************************************************************************/ |
503 | ||
504 | /* | |
505 | * au1300_gpic_chgcfg - change PIN configuration. | |
506 | * @gpio: pin to change (0-based GPIO number from datasheet). | |
507 | * @clr: clear all bits set in 'clr'. | |
508 | * @set: set these bits. | |
509 | * | |
510 | * modifies a pins' configuration register, bits set in @clr will | |
511 | * be cleared in the register, bits in @set will be set. | |
512 | */ | |
513 | static inline void au1300_gpic_chgcfg(unsigned int gpio, | |
514 | unsigned long clr, | |
515 | unsigned long set) | |
516 | { | |
517 | void __iomem *r = AU1300_GPIC_ADDR; | |
518 | unsigned long l; | |
519 | ||
520 | r += gpio * 4; /* offset into pin config array */ | |
521 | l = __raw_readl(r + AU1300_GPIC_PINCFG); | |
522 | l &= ~clr; | |
523 | l |= set; | |
524 | __raw_writel(l, r + AU1300_GPIC_PINCFG); | |
525 | wmb(); | |
526 | } | |
527 | ||
528 | /* | |
529 | * au1300_pinfunc_to_gpio - assign a pin as GPIO input (GPIO ctrl). | |
530 | * @pin: pin (0-based GPIO number from datasheet). | |
531 | * | |
532 | * Assigns a GPIO pin to the GPIO controller, so its level can either | |
533 | * be read or set through the generic GPIO functions. | |
534 | * If you need a GPOUT, use au1300_gpio_set_value(pin, 0/1). | |
535 | * REVISIT: is this function really necessary? | |
536 | */ | |
537 | void au1300_pinfunc_to_gpio(enum au1300_multifunc_pins gpio) | |
538 | { | |
539 | au1300_gpio_direction_input(gpio + AU1300_GPIO_BASE); | |
540 | } | |
541 | EXPORT_SYMBOL_GPL(au1300_pinfunc_to_gpio); | |
542 | ||
543 | /* | |
544 | * au1300_pinfunc_to_dev - assign a pin to the device function. | |
545 | * @pin: pin (0-based GPIO number from datasheet). | |
546 | * | |
547 | * Assigns a GPIO pin to its associated device function; the pin will be | |
548 | * driven by the device and not through GPIO functions. | |
549 | */ | |
550 | void au1300_pinfunc_to_dev(enum au1300_multifunc_pins gpio) | |
551 | { | |
552 | void __iomem *r = AU1300_GPIC_ADDR; | |
553 | unsigned long bit; | |
554 | ||
555 | r += GPIC_GPIO_BANKOFF(gpio); | |
556 | bit = GPIC_GPIO_TO_BIT(gpio); | |
557 | __raw_writel(bit, r + AU1300_GPIC_DEVSEL); | |
558 | wmb(); | |
559 | } | |
560 | EXPORT_SYMBOL_GPL(au1300_pinfunc_to_dev); | |
561 | ||
562 | /* | |
563 | * au1300_set_irq_priority - set internal priority of IRQ. | |
564 | * @irq: irq to set priority (linux irq number). | |
565 | * @p: priority (0 = highest, 3 = lowest). | |
566 | */ | |
567 | void au1300_set_irq_priority(unsigned int irq, int p) | |
568 | { | |
569 | irq -= ALCHEMY_GPIC_INT_BASE; | |
570 | au1300_gpic_chgcfg(irq, GPIC_CFG_IL_MASK, GPIC_CFG_IL_SET(p)); | |
571 | } | |
572 | EXPORT_SYMBOL_GPL(au1300_set_irq_priority); | |
573 | ||
574 | /* | |
575 | * au1300_set_dbdma_gpio - assign a gpio to one of the DBDMA triggers. | |
576 | * @dchan: dbdma trigger select (0, 1). | |
577 | * @gpio: pin to assign as trigger. | |
578 | * | |
579 | * DBDMA controller has 2 external trigger sources; this function | |
580 | * assigns a GPIO to the selected trigger. | |
581 | */ | |
582 | void au1300_set_dbdma_gpio(int dchan, unsigned int gpio) | |
583 | { | |
584 | unsigned long r; | |
585 | ||
586 | if ((dchan >= 0) && (dchan <= 1)) { | |
587 | r = __raw_readl(AU1300_GPIC_ADDR + AU1300_GPIC_DMASEL); | |
588 | r &= ~(0xff << (8 * dchan)); | |
589 | r |= (gpio & 0x7f) << (8 * dchan); | |
590 | __raw_writel(r, AU1300_GPIC_ADDR + AU1300_GPIC_DMASEL); | |
591 | wmb(); | |
592 | } | |
593 | } | |
594 | ||
595 | static inline void gpic_pin_set_idlewake(unsigned int gpio, int allow) | |
596 | { | |
597 | au1300_gpic_chgcfg(gpio, GPIC_CFG_IDLEWAKE, | |
598 | allow ? GPIC_CFG_IDLEWAKE : 0); | |
599 | } | |
600 | ||
601 | static void au1300_gpic_mask(struct irq_data *d) | |
602 | { | |
603 | void __iomem *r = AU1300_GPIC_ADDR; | |
604 | unsigned long bit, irq = d->irq; | |
605 | ||
606 | irq -= ALCHEMY_GPIC_INT_BASE; | |
607 | r += GPIC_GPIO_BANKOFF(irq); | |
608 | bit = GPIC_GPIO_TO_BIT(irq); | |
609 | __raw_writel(bit, r + AU1300_GPIC_IDIS); | |
610 | wmb(); | |
611 | ||
612 | gpic_pin_set_idlewake(irq, 0); | |
613 | } | |
614 | ||
615 | static void au1300_gpic_unmask(struct irq_data *d) | |
616 | { | |
617 | void __iomem *r = AU1300_GPIC_ADDR; | |
618 | unsigned long bit, irq = d->irq; | |
619 | ||
620 | irq -= ALCHEMY_GPIC_INT_BASE; | |
621 | ||
622 | gpic_pin_set_idlewake(irq, 1); | |
623 | ||
624 | r += GPIC_GPIO_BANKOFF(irq); | |
625 | bit = GPIC_GPIO_TO_BIT(irq); | |
626 | __raw_writel(bit, r + AU1300_GPIC_IEN); | |
627 | wmb(); | |
628 | } | |
629 | ||
630 | static void au1300_gpic_maskack(struct irq_data *d) | |
631 | { | |
632 | void __iomem *r = AU1300_GPIC_ADDR; | |
633 | unsigned long bit, irq = d->irq; | |
634 | ||
635 | irq -= ALCHEMY_GPIC_INT_BASE; | |
636 | r += GPIC_GPIO_BANKOFF(irq); | |
637 | bit = GPIC_GPIO_TO_BIT(irq); | |
638 | __raw_writel(bit, r + AU1300_GPIC_IPEND); /* ack */ | |
639 | __raw_writel(bit, r + AU1300_GPIC_IDIS); /* mask */ | |
640 | wmb(); | |
641 | ||
642 | gpic_pin_set_idlewake(irq, 0); | |
643 | } | |
644 | ||
645 | static void au1300_gpic_ack(struct irq_data *d) | |
646 | { | |
647 | void __iomem *r = AU1300_GPIC_ADDR; | |
648 | unsigned long bit, irq = d->irq; | |
649 | ||
650 | irq -= ALCHEMY_GPIC_INT_BASE; | |
651 | r += GPIC_GPIO_BANKOFF(irq); | |
652 | bit = GPIC_GPIO_TO_BIT(irq); | |
653 | __raw_writel(bit, r + AU1300_GPIC_IPEND); /* ack */ | |
654 | wmb(); | |
655 | } | |
656 | ||
657 | static struct irq_chip au1300_gpic = { | |
658 | .name = "GPIOINT", | |
659 | .irq_ack = au1300_gpic_ack, | |
660 | .irq_mask = au1300_gpic_mask, | |
661 | .irq_mask_ack = au1300_gpic_maskack, | |
662 | .irq_unmask = au1300_gpic_unmask, | |
663 | .irq_set_type = au1300_gpic_settype, | |
664 | }; | |
665 | ||
666 | static int au1300_gpic_settype(struct irq_data *d, unsigned int type) | |
667 | { | |
668 | unsigned long s; | |
669 | unsigned char *name = NULL; | |
670 | irq_flow_handler_t hdl = NULL; | |
671 | ||
672 | switch (type) { | |
673 | case IRQ_TYPE_LEVEL_HIGH: | |
674 | s = GPIC_CFG_IC_LEVEL_HIGH; | |
675 | name = "high"; | |
676 | hdl = handle_level_irq; | |
677 | break; | |
678 | case IRQ_TYPE_LEVEL_LOW: | |
679 | s = GPIC_CFG_IC_LEVEL_LOW; | |
680 | name = "low"; | |
681 | hdl = handle_level_irq; | |
682 | break; | |
683 | case IRQ_TYPE_EDGE_RISING: | |
684 | s = GPIC_CFG_IC_EDGE_RISE; | |
685 | name = "posedge"; | |
686 | hdl = handle_edge_irq; | |
687 | break; | |
688 | case IRQ_TYPE_EDGE_FALLING: | |
689 | s = GPIC_CFG_IC_EDGE_FALL; | |
690 | name = "negedge"; | |
691 | hdl = handle_edge_irq; | |
692 | break; | |
693 | case IRQ_TYPE_EDGE_BOTH: | |
694 | s = GPIC_CFG_IC_EDGE_BOTH; | |
695 | name = "bothedge"; | |
696 | hdl = handle_edge_irq; | |
697 | break; | |
698 | case IRQ_TYPE_NONE: | |
699 | s = GPIC_CFG_IC_OFF; | |
700 | name = "disabled"; | |
701 | hdl = handle_level_irq; | |
702 | break; | |
703 | default: | |
704 | return -EINVAL; | |
705 | } | |
706 | ||
707 | __irq_set_chip_handler_name_locked(d->irq, &au1300_gpic, hdl, name); | |
708 | ||
709 | au1300_gpic_chgcfg(d->irq - ALCHEMY_GPIC_INT_BASE, GPIC_CFG_IC_MASK, s); | |
710 | ||
711 | return 0; | |
712 | } | |
713 | ||
714 | /******************************************************************************/ | |
715 | ||
dca75871 ML |
716 | static inline void ic_init(void __iomem *base) |
717 | { | |
718 | /* initialize interrupt controller to a safe state */ | |
719 | __raw_writel(0xffffffff, base + IC_CFG0CLR); | |
720 | __raw_writel(0xffffffff, base + IC_CFG1CLR); | |
721 | __raw_writel(0xffffffff, base + IC_CFG2CLR); | |
722 | __raw_writel(0xffffffff, base + IC_MASKCLR); | |
723 | __raw_writel(0xffffffff, base + IC_ASSIGNCLR); | |
724 | __raw_writel(0xffffffff, base + IC_WAKECLR); | |
725 | __raw_writel(0xffffffff, base + IC_SRCSET); | |
726 | __raw_writel(0xffffffff, base + IC_FALLINGCLR); | |
727 | __raw_writel(0xffffffff, base + IC_RISINGCLR); | |
728 | __raw_writel(0x00000000, base + IC_TESTBIT); | |
729 | wmb(); | |
730 | } | |
731 | ||
3eab8095 | 732 | static unsigned long alchemy_gpic_pmdata[ALCHEMY_GPIC_INT_NUM + 6]; |
f267c882 ML |
733 | |
734 | static inline void alchemy_ic_suspend_one(void __iomem *base, unsigned long *d) | |
735 | { | |
736 | d[0] = __raw_readl(base + IC_CFG0RD); | |
737 | d[1] = __raw_readl(base + IC_CFG1RD); | |
738 | d[2] = __raw_readl(base + IC_CFG2RD); | |
739 | d[3] = __raw_readl(base + IC_SRCRD); | |
740 | d[4] = __raw_readl(base + IC_ASSIGNRD); | |
741 | d[5] = __raw_readl(base + IC_WAKERD); | |
742 | d[6] = __raw_readl(base + IC_MASKRD); | |
743 | ic_init(base); /* shut it up too while at it */ | |
744 | } | |
745 | ||
746 | static inline void alchemy_ic_resume_one(void __iomem *base, unsigned long *d) | |
747 | { | |
748 | ic_init(base); | |
749 | ||
750 | __raw_writel(d[0], base + IC_CFG0SET); | |
751 | __raw_writel(d[1], base + IC_CFG1SET); | |
752 | __raw_writel(d[2], base + IC_CFG2SET); | |
753 | __raw_writel(d[3], base + IC_SRCSET); | |
754 | __raw_writel(d[4], base + IC_ASSIGNSET); | |
755 | __raw_writel(d[5], base + IC_WAKESET); | |
756 | wmb(); | |
757 | ||
758 | __raw_writel(d[6], base + IC_MASKSET); | |
759 | wmb(); | |
760 | } | |
761 | ||
762 | static int alchemy_ic_suspend(void) | |
763 | { | |
764 | alchemy_ic_suspend_one((void __iomem *)KSEG1ADDR(AU1000_IC0_PHYS_ADDR), | |
3eab8095 | 765 | alchemy_gpic_pmdata); |
f267c882 | 766 | alchemy_ic_suspend_one((void __iomem *)KSEG1ADDR(AU1000_IC1_PHYS_ADDR), |
3eab8095 | 767 | &alchemy_gpic_pmdata[7]); |
f267c882 ML |
768 | return 0; |
769 | } | |
770 | ||
771 | static void alchemy_ic_resume(void) | |
772 | { | |
773 | alchemy_ic_resume_one((void __iomem *)KSEG1ADDR(AU1000_IC1_PHYS_ADDR), | |
3eab8095 | 774 | &alchemy_gpic_pmdata[7]); |
f267c882 | 775 | alchemy_ic_resume_one((void __iomem *)KSEG1ADDR(AU1000_IC0_PHYS_ADDR), |
3eab8095 | 776 | alchemy_gpic_pmdata); |
f267c882 ML |
777 | } |
778 | ||
3eab8095 ML |
779 | static int alchemy_gpic_suspend(void) |
780 | { | |
781 | void __iomem *base = (void __iomem *)KSEG1ADDR(AU1300_GPIC_PHYS_ADDR); | |
782 | int i; | |
783 | ||
784 | /* save 4 interrupt mask status registers */ | |
785 | alchemy_gpic_pmdata[0] = __raw_readl(base + AU1300_GPIC_IEN + 0x0); | |
786 | alchemy_gpic_pmdata[1] = __raw_readl(base + AU1300_GPIC_IEN + 0x4); | |
787 | alchemy_gpic_pmdata[2] = __raw_readl(base + AU1300_GPIC_IEN + 0x8); | |
788 | alchemy_gpic_pmdata[3] = __raw_readl(base + AU1300_GPIC_IEN + 0xc); | |
789 | ||
790 | /* save misc register(s) */ | |
791 | alchemy_gpic_pmdata[4] = __raw_readl(base + AU1300_GPIC_DMASEL); | |
792 | ||
793 | /* molto silenzioso */ | |
794 | __raw_writel(~0UL, base + AU1300_GPIC_IDIS + 0x0); | |
795 | __raw_writel(~0UL, base + AU1300_GPIC_IDIS + 0x4); | |
796 | __raw_writel(~0UL, base + AU1300_GPIC_IDIS + 0x8); | |
797 | __raw_writel(~0UL, base + AU1300_GPIC_IDIS + 0xc); | |
798 | wmb(); | |
799 | ||
800 | /* save pin/int-type configuration */ | |
801 | base += AU1300_GPIC_PINCFG; | |
802 | for (i = 0; i < ALCHEMY_GPIC_INT_NUM; i++) | |
803 | alchemy_gpic_pmdata[i + 5] = __raw_readl(base + (i << 2)); | |
804 | ||
805 | wmb(); | |
806 | ||
807 | return 0; | |
808 | } | |
809 | ||
810 | static void alchemy_gpic_resume(void) | |
811 | { | |
812 | void __iomem *base = (void __iomem *)KSEG1ADDR(AU1300_GPIC_PHYS_ADDR); | |
813 | int i; | |
814 | ||
815 | /* disable all first */ | |
816 | __raw_writel(~0UL, base + AU1300_GPIC_IDIS + 0x0); | |
817 | __raw_writel(~0UL, base + AU1300_GPIC_IDIS + 0x4); | |
818 | __raw_writel(~0UL, base + AU1300_GPIC_IDIS + 0x8); | |
819 | __raw_writel(~0UL, base + AU1300_GPIC_IDIS + 0xc); | |
820 | wmb(); | |
821 | ||
822 | /* restore pin/int-type configurations */ | |
823 | base += AU1300_GPIC_PINCFG; | |
824 | for (i = 0; i < ALCHEMY_GPIC_INT_NUM; i++) | |
825 | __raw_writel(alchemy_gpic_pmdata[i + 5], base + (i << 2)); | |
826 | wmb(); | |
827 | ||
828 | /* restore misc register(s) */ | |
829 | base = (void __iomem *)KSEG1ADDR(AU1300_GPIC_PHYS_ADDR); | |
830 | __raw_writel(alchemy_gpic_pmdata[4], base + AU1300_GPIC_DMASEL); | |
831 | wmb(); | |
832 | ||
833 | /* finally restore masks */ | |
834 | __raw_writel(alchemy_gpic_pmdata[0], base + AU1300_GPIC_IEN + 0x0); | |
835 | __raw_writel(alchemy_gpic_pmdata[1], base + AU1300_GPIC_IEN + 0x4); | |
836 | __raw_writel(alchemy_gpic_pmdata[2], base + AU1300_GPIC_IEN + 0x8); | |
837 | __raw_writel(alchemy_gpic_pmdata[3], base + AU1300_GPIC_IEN + 0xc); | |
838 | wmb(); | |
839 | } | |
840 | ||
841 | static struct syscore_ops alchemy_ic_pmops = { | |
f267c882 ML |
842 | .suspend = alchemy_ic_suspend, |
843 | .resume = alchemy_ic_resume, | |
844 | }; | |
845 | ||
3eab8095 ML |
846 | static struct syscore_ops alchemy_gpic_pmops = { |
847 | .suspend = alchemy_gpic_suspend, | |
848 | .resume = alchemy_gpic_resume, | |
849 | }; | |
850 | ||
851 | /******************************************************************************/ | |
852 | ||
894cc87e ML |
853 | /* create chained handlers for the 4 IC requests to the MIPS IRQ ctrl */ |
854 | #define DISP(name, base, addr) \ | |
855 | static void au1000_##name##_dispatch(unsigned int irq, struct irq_desc *d) \ | |
856 | { \ | |
857 | unsigned long r = __raw_readl((void __iomem *)KSEG1ADDR(addr)); \ | |
858 | if (likely(r)) \ | |
859 | generic_handle_irq(base + __ffs(r)); \ | |
860 | else \ | |
861 | spurious_interrupt(); \ | |
862 | } | |
863 | ||
864 | DISP(ic0r0, AU1000_INTC0_INT_BASE, AU1000_IC0_PHYS_ADDR + IC_REQ0INT) | |
865 | DISP(ic0r1, AU1000_INTC0_INT_BASE, AU1000_IC0_PHYS_ADDR + IC_REQ1INT) | |
866 | DISP(ic1r0, AU1000_INTC1_INT_BASE, AU1000_IC1_PHYS_ADDR + IC_REQ0INT) | |
867 | DISP(ic1r1, AU1000_INTC1_INT_BASE, AU1000_IC1_PHYS_ADDR + IC_REQ1INT) | |
868 | ||
3eab8095 ML |
869 | static void alchemy_gpic_dispatch(unsigned int irq, struct irq_desc *d) |
870 | { | |
871 | int i = __raw_readl(AU1300_GPIC_ADDR + AU1300_GPIC_PRIENC); | |
872 | generic_handle_irq(ALCHEMY_GPIC_INT_BASE + i); | |
873 | } | |
874 | ||
875 | /******************************************************************************/ | |
876 | ||
877 | static void __init au1000_init_irq(struct alchemy_irqmap *map) | |
1da177e4 | 878 | { |
785e3268 | 879 | unsigned int bit, irq_nr; |
dca75871 | 880 | void __iomem *base; |
41bd61a8 | 881 | |
dca75871 ML |
882 | ic_init((void __iomem *)KSEG1ADDR(AU1000_IC0_PHYS_ADDR)); |
883 | ic_init((void __iomem *)KSEG1ADDR(AU1000_IC1_PHYS_ADDR)); | |
3eab8095 | 884 | register_syscore_ops(&alchemy_ic_pmops); |
f3e8d1da RB |
885 | mips_cpu_irq_init(); |
886 | ||
785e3268 ML |
887 | /* register all 64 possible IC0+IC1 irq sources as type "none". |
888 | * Use set_irq_type() to set edge/level behaviour at runtime. | |
f3e8d1da | 889 | */ |
dca75871 ML |
890 | for (irq_nr = AU1000_INTC0_INT_BASE; |
891 | (irq_nr < AU1000_INTC0_INT_BASE + 32); irq_nr++) | |
892 | au1x_ic_settype(irq_get_irq_data(irq_nr), IRQ_TYPE_NONE); | |
785e3268 | 893 | |
dca75871 ML |
894 | for (irq_nr = AU1000_INTC1_INT_BASE; |
895 | (irq_nr < AU1000_INTC1_INT_BASE + 32); irq_nr++) | |
896 | au1x_ic_settype(irq_get_irq_data(irq_nr), IRQ_TYPE_NONE); | |
41bd61a8 | 897 | |
f3e8d1da | 898 | /* |
785e3268 | 899 | * Initialize IC0, which is fixed per processor. |
f3e8d1da | 900 | */ |
3eab8095 ML |
901 | while (map->irq != -1) { |
902 | irq_nr = map->irq; | |
ef6c1fd6 ML |
903 | |
904 | if (irq_nr >= AU1000_INTC1_INT_BASE) { | |
905 | bit = irq_nr - AU1000_INTC1_INT_BASE; | |
dca75871 | 906 | base = (void __iomem *)KSEG1ADDR(AU1000_IC1_PHYS_ADDR); |
ef6c1fd6 ML |
907 | } else { |
908 | bit = irq_nr - AU1000_INTC0_INT_BASE; | |
dca75871 | 909 | base = (void __iomem *)KSEG1ADDR(AU1000_IC0_PHYS_ADDR); |
ef6c1fd6 | 910 | } |
3eab8095 | 911 | if (map->prio == 0) |
dca75871 | 912 | __raw_writel(1 << bit, base + IC_ASSIGNSET); |
ef6c1fd6 | 913 | |
3eab8095 | 914 | au1x_ic_settype(irq_get_irq_data(irq_nr), map->type); |
ef6c1fd6 ML |
915 | ++map; |
916 | } | |
785e3268 | 917 | |
894cc87e ML |
918 | irq_set_chained_handler(MIPS_CPU_IRQ_BASE + 2, au1000_ic0r0_dispatch); |
919 | irq_set_chained_handler(MIPS_CPU_IRQ_BASE + 3, au1000_ic0r1_dispatch); | |
920 | irq_set_chained_handler(MIPS_CPU_IRQ_BASE + 4, au1000_ic1r0_dispatch); | |
921 | irq_set_chained_handler(MIPS_CPU_IRQ_BASE + 5, au1000_ic1r1_dispatch); | |
785e3268 | 922 | } |
ef6c1fd6 | 923 | |
3eab8095 ML |
924 | static void __init alchemy_gpic_init_irq(const struct alchemy_irqmap *dints) |
925 | { | |
926 | int i; | |
927 | void __iomem *bank_base; | |
928 | ||
929 | register_syscore_ops(&alchemy_gpic_pmops); | |
930 | mips_cpu_irq_init(); | |
931 | ||
932 | /* disable & ack all possible interrupt sources */ | |
933 | for (i = 0; i < 4; i++) { | |
934 | bank_base = AU1300_GPIC_ADDR + (i * 4); | |
935 | __raw_writel(~0UL, bank_base + AU1300_GPIC_IDIS); | |
936 | wmb(); | |
937 | __raw_writel(~0UL, bank_base + AU1300_GPIC_IPEND); | |
938 | wmb(); | |
939 | } | |
940 | ||
941 | /* register an irq_chip for them, with 2nd highest priority */ | |
942 | for (i = ALCHEMY_GPIC_INT_BASE; i <= ALCHEMY_GPIC_INT_LAST; i++) { | |
943 | au1300_set_irq_priority(i, 1); | |
944 | au1300_gpic_settype(irq_get_irq_data(i), IRQ_TYPE_NONE); | |
945 | } | |
946 | ||
947 | /* setup known on-chip sources */ | |
948 | while ((i = dints->irq) != -1) { | |
949 | au1300_gpic_settype(irq_get_irq_data(i), dints->type); | |
950 | au1300_set_irq_priority(i, dints->prio); | |
951 | ||
952 | if (dints->internal) | |
953 | au1300_pinfunc_to_dev(i - ALCHEMY_GPIC_INT_BASE); | |
954 | ||
955 | dints++; | |
956 | } | |
957 | ||
958 | irq_set_chained_handler(MIPS_CPU_IRQ_BASE + 2, alchemy_gpic_dispatch); | |
959 | irq_set_chained_handler(MIPS_CPU_IRQ_BASE + 3, alchemy_gpic_dispatch); | |
960 | irq_set_chained_handler(MIPS_CPU_IRQ_BASE + 4, alchemy_gpic_dispatch); | |
961 | irq_set_chained_handler(MIPS_CPU_IRQ_BASE + 5, alchemy_gpic_dispatch); | |
962 | } | |
963 | ||
964 | /******************************************************************************/ | |
965 | ||
ef6c1fd6 ML |
966 | void __init arch_init_irq(void) |
967 | { | |
968 | switch (alchemy_get_cputype()) { | |
969 | case ALCHEMY_CPU_AU1000: | |
970 | au1000_init_irq(au1000_irqmap); | |
971 | break; | |
972 | case ALCHEMY_CPU_AU1500: | |
973 | au1000_init_irq(au1500_irqmap); | |
974 | break; | |
975 | case ALCHEMY_CPU_AU1100: | |
976 | au1000_init_irq(au1100_irqmap); | |
977 | break; | |
978 | case ALCHEMY_CPU_AU1550: | |
979 | au1000_init_irq(au1550_irqmap); | |
980 | break; | |
981 | case ALCHEMY_CPU_AU1200: | |
982 | au1000_init_irq(au1200_irqmap); | |
983 | break; | |
3eab8095 ML |
984 | case ALCHEMY_CPU_AU1300: |
985 | alchemy_gpic_init_irq(au1300_irqmap); | |
986 | break; | |
987 | default: | |
988 | pr_err("unknown Alchemy IRQ core\n"); | |
989 | break; | |
ef6c1fd6 ML |
990 | } |
991 | } | |
894cc87e ML |
992 | |
993 | asmlinkage void plat_irq_dispatch(void) | |
994 | { | |
995 | unsigned long r = (read_c0_status() & read_c0_cause()) >> 8; | |
996 | do_IRQ(MIPS_CPU_IRQ_BASE + __ffs(r & 0xff)); | |
997 | } |