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