Merge branch 'master' of git://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux-2.6
[pandora-kernel.git] / arch / sh / kernel / cpu / irq / intc2.c
1 /*
2  * Interrupt handling for INTC2-based IRQ.
3  *
4  * Copyright (C) 2001 David J. Mckay (david.mckay@st.com)
5  * Copyright (C) 2005, 2006 Paul Mundt (lethal@linux-sh.org)
6  *
7  * May be copied or modified under the terms of the GNU General Public
8  * License.  See linux/COPYING for more information.
9  *
10  * These are the "new Hitachi style" interrupts, as present on the
11  * Hitachi 7751, the STM ST40 STB1, SH7760, and SH7780.
12  */
13
14 #include <linux/kernel.h>
15 #include <linux/init.h>
16 #include <linux/irq.h>
17 #include <asm/system.h>
18 #include <asm/io.h>
19 #include <asm/machvec.h>
20
21 struct intc2_data {
22         unsigned char msk_offset;
23         unsigned char msk_shift;
24
25         int (*clear_irq) (int);
26 };
27
28 static struct intc2_data intc2_data[NR_INTC2_IRQS];
29
30 static void enable_intc2_irq(unsigned int irq);
31 static void disable_intc2_irq(unsigned int irq);
32
33 /* shutdown is same as "disable" */
34 #define shutdown_intc2_irq disable_intc2_irq
35
36 static void mask_and_ack_intc2(unsigned int);
37 static void end_intc2_irq(unsigned int irq);
38
39 static unsigned int startup_intc2_irq(unsigned int irq)
40 {
41         enable_intc2_irq(irq);
42         return 0; /* never anything pending */
43 }
44
45 static struct hw_interrupt_type intc2_irq_type = {
46         .typename       = "INTC2-IRQ",
47         .startup        = startup_intc2_irq,
48         .shutdown       = shutdown_intc2_irq,
49         .enable         = enable_intc2_irq,
50         .disable        = disable_intc2_irq,
51         .ack            = mask_and_ack_intc2,
52         .end            = end_intc2_irq
53 };
54
55 static void disable_intc2_irq(unsigned int irq)
56 {
57         int irq_offset = irq - INTC2_FIRST_IRQ;
58         int msk_shift, msk_offset;
59
60         /* Sanity check */
61         if (unlikely(irq_offset < 0 || irq_offset >= NR_INTC2_IRQS))
62                 return;
63
64         msk_shift = intc2_data[irq_offset].msk_shift;
65         msk_offset = intc2_data[irq_offset].msk_offset;
66
67         ctrl_outl(1 << msk_shift,
68                   INTC2_BASE + INTC2_INTMSK_OFFSET + msk_offset);
69 }
70
71 static void enable_intc2_irq(unsigned int irq)
72 {
73         int irq_offset = irq - INTC2_FIRST_IRQ;
74         int msk_shift, msk_offset;
75
76         /* Sanity check */
77         if (unlikely(irq_offset < 0 || irq_offset >= NR_INTC2_IRQS))
78                 return;
79
80         msk_shift = intc2_data[irq_offset].msk_shift;
81         msk_offset = intc2_data[irq_offset].msk_offset;
82
83         ctrl_outl(1 << msk_shift,
84                   INTC2_BASE + INTC2_INTMSKCLR_OFFSET + msk_offset);
85 }
86
87 static void mask_and_ack_intc2(unsigned int irq)
88 {
89         disable_intc2_irq(irq);
90 }
91
92 static void end_intc2_irq(unsigned int irq)
93 {
94         if (!(irq_desc[irq].status & (IRQ_DISABLED|IRQ_INPROGRESS)))
95                 enable_intc2_irq(irq);
96
97         if (unlikely(intc2_data[irq - INTC2_FIRST_IRQ].clear_irq))
98                 intc2_data[irq - INTC2_FIRST_IRQ].clear_irq(irq);
99 }
100
101 /*
102  * Setup an INTC2 style interrupt.
103  * NOTE: Unlike IPR interrupts, parameters are not shifted by this code,
104  * allowing the use of the numbers straight out of the datasheet.
105  * For example:
106  *    PIO1 which is INTPRI00[19,16] and INTMSK00[13]
107  * would be:               ^     ^             ^  ^
108  *                         |     |             |  |
109  *    make_intc2_irq(84,   0,   16,            0, 13);
110  */
111 void make_intc2_irq(unsigned int irq,
112                     unsigned int ipr_offset, unsigned int ipr_shift,
113                     unsigned int msk_offset, unsigned int msk_shift,
114                     unsigned int priority)
115 {
116         int irq_offset = irq - INTC2_FIRST_IRQ;
117         unsigned int flags;
118         unsigned long ipr;
119
120         if (unlikely(irq_offset < 0 || irq_offset >= NR_INTC2_IRQS))
121                 return;
122
123         disable_irq_nosync(irq);
124
125         /* Fill the data we need */
126         intc2_data[irq_offset].msk_offset = msk_offset;
127         intc2_data[irq_offset].msk_shift  = msk_shift;
128         intc2_data[irq_offset].clear_irq = NULL;
129
130         /* Set the priority level */
131         local_irq_save(flags);
132
133         ipr = ctrl_inl(INTC2_BASE + INTC2_INTPRI_OFFSET + ipr_offset);
134         ipr &= ~(0xf << ipr_shift);
135         ipr |= priority << ipr_shift;
136         ctrl_outl(ipr, INTC2_BASE + INTC2_INTPRI_OFFSET + ipr_offset);
137
138         local_irq_restore(flags);
139
140         irq_desc[irq].chip = &intc2_irq_type;
141
142         disable_intc2_irq(irq);
143 }
144
145 static struct intc2_init {
146         unsigned short irq;
147         unsigned char ipr_offset, ipr_shift;
148         unsigned char msk_offset, msk_shift;
149         unsigned char priority;
150 } intc2_init_data[]  __initdata = {
151 #if defined(CONFIG_CPU_SUBTYPE_ST40)
152         {64,  0,  0, 0,  0, 13},        /* PCI serr */
153         {65,  0,  4, 0,  1, 13},        /* PCI err */
154         {66,  0,  4, 0,  2, 13},        /* PCI ad */
155         {67,  0,  4, 0,  3, 13},        /* PCI pwd down */
156         {72,  0,  8, 0,  5, 13},        /* DMAC INT0 */
157         {73,  0,  8, 0,  6, 13},        /* DMAC INT1 */
158         {74,  0,  8, 0,  7, 13},        /* DMAC INT2 */
159         {75,  0,  8, 0,  8, 13},        /* DMAC INT3 */
160         {76,  0,  8, 0,  9, 13},        /* DMAC INT4 */
161         {78,  0,  8, 0, 11, 13},        /* DMAC ERR */
162         {80,  0, 12, 0, 12, 13},        /* PIO0 */
163         {84,  0, 16, 0, 13, 13},        /* PIO1 */
164         {88,  0, 20, 0, 14, 13},        /* PIO2 */
165         {112, 4,  0, 4,  0, 13},        /* Mailbox */
166  #ifdef CONFIG_CPU_SUBTYPE_ST40GX1
167         {116, 4,  4, 4,  4, 13},        /* SSC0 */
168         {120, 4,  8, 4,  8, 13},        /* IR Blaster */
169         {124, 4, 12, 4, 12, 13},        /* USB host */
170         {128, 4, 16, 4, 16, 13},        /* Video processor BLITTER */
171         {132, 4, 20, 4, 20, 13},        /* UART0 */
172         {134, 4, 20, 4, 22, 13},        /* UART2 */
173         {136, 4, 24, 4, 24, 13},        /* IO_PIO0 */
174         {140, 4, 28, 4, 28, 13},        /* EMPI */
175         {144, 8,  0, 8,  0, 13},        /* MAFE */
176         {148, 8,  4, 8,  4, 13},        /* PWM */
177         {152, 8,  8, 8,  8, 13},        /* SSC1 */
178         {156, 8, 12, 8, 12, 13},        /* IO_PIO1 */
179         {160, 8, 16, 8, 16, 13},        /* USB target */
180         {164, 8, 20, 8, 20, 13},        /* UART1 */
181         {168, 8, 24, 8, 24, 13},        /* Teletext */
182         {172, 8, 28, 8, 28, 13},        /* VideoSync VTG */
183         {173, 8, 28, 8, 29, 13},        /* VideoSync DVP0 */
184         {174, 8, 28, 8, 30, 13},        /* VideoSync DVP1 */
185 #endif
186 #elif defined(CONFIG_CPU_SUBTYPE_SH7760)
187 /*
188  * SH7760 INTC2-Style interrupts, vectors IRQ48-111 INTEVT 0x800-0xFE0
189  */
190         /* INTPRIO0 | INTMSK0 */
191         {48,  0, 28, 0, 31,  3},        /* IRQ 4 */
192         {49,  0, 24, 0, 30,  3},        /* IRQ 3 */
193         {50,  0, 20, 0, 29,  3},        /* IRQ 2 */
194         {51,  0, 16, 0, 28,  3},        /* IRQ 1 */
195         /* 52-55 (INTEVT 0x880-0x8E0) unused/reserved */
196         /* INTPRIO4 | INTMSK0 */
197         {56,  4, 28, 0, 25,  3},        /* HCAN2_CHAN0 */
198         {57,  4, 24, 0, 24,  3},        /* HCAN2_CHAN1 */
199         {58,  4, 20, 0, 23,  3},        /* I2S_CHAN0   */
200         {59,  4, 16, 0, 22,  3},        /* I2S_CHAN1   */
201         {60,  4, 12, 0, 21,  3},        /* AC97_CHAN0  */
202         {61,  4,  8, 0, 20,  3},        /* AC97_CHAN1  */
203         {62,  4,  4, 0, 19,  3},        /* I2C_CHAN0   */
204         {63,  4,  0, 0, 18,  3},        /* I2C_CHAN1   */
205         /* INTPRIO8 | INTMSK0 */
206         {52,  8, 16, 0, 11,  3},        /* SCIF0_ERI_IRQ */
207         {53,  8, 16, 0, 10,  3},        /* SCIF0_RXI_IRQ */
208         {54,  8, 16, 0,  9,  3},        /* SCIF0_BRI_IRQ */
209         {55,  8, 16, 0,  8,  3},        /* SCIF0_TXI_IRQ */
210         {64,  8, 28, 0, 17,  3},        /* USBHI_IRQ */
211         {65,  8, 24, 0, 16,  3},        /* LCDC      */
212         /* 66, 67 unused */
213         {68,  8, 20, 0, 14, 13},        /* DMABRGI0_IRQ */
214         {69,  8, 20, 0, 13, 13},        /* DMABRGI1_IRQ */
215         {70,  8, 20, 0, 12, 13},        /* DMABRGI2_IRQ */
216         /* 71 unused */
217         {72,  8, 12, 0,  7,  3},        /* SCIF1_ERI_IRQ */
218         {73,  8, 12, 0,  6,  3},        /* SCIF1_RXI_IRQ */
219         {74,  8, 12, 0,  5,  3},        /* SCIF1_BRI_IRQ */
220         {75,  8, 12, 0,  4,  3},        /* SCIF1_TXI_IRQ */
221         {76,  8,  8, 0,  3,  3},        /* SCIF2_ERI_IRQ */
222         {77,  8,  8, 0,  2,  3},        /* SCIF2_RXI_IRQ */
223         {78,  8,  8, 0,  1,  3},        /* SCIF2_BRI_IRQ */
224         {79,  8,  8, 0,  0,  3},        /* SCIF2_TXI_IRQ */
225         /*          | INTMSK4 */
226         {80,  8,  4, 4, 23,  3},        /* SIM_ERI */
227         {81,  8,  4, 4, 22,  3},        /* SIM_RXI */
228         {82,  8,  4, 4, 21,  3},        /* SIM_TXI */
229         {83,  8,  4, 4, 20,  3},        /* SIM_TEI */
230         {84,  8,  0, 4, 19,  3},        /* HSPII */
231         /* INTPRIOC | INTMSK4 */
232         /* 85-87 unused/reserved */
233         {88, 12, 20, 4, 18,  3},        /* MMCI0 */
234         {89, 12, 20, 4, 17,  3},        /* MMCI1 */
235         {90, 12, 20, 4, 16,  3},        /* MMCI2 */
236         {91, 12, 20, 4, 15,  3},        /* MMCI3 */
237         {92, 12, 12, 4,  6,  3},        /* MFI (unsure, bug? in my 7760 manual*/
238         /* 93-107 reserved/undocumented */
239         {108,12,  4, 4,  1,  3},        /* ADC  */
240         {109,12,  0, 4,  0,  3},        /* CMTI */
241         /* 110-111 reserved/unused */
242 #elif defined(CONFIG_CPU_SUBTYPE_SH7780)
243         { TIMER_IRQ, 0, 24, 0, INTC_TMU0_MSK, 2},
244         { 21, 1, 0, 0, INTC_RTC_MSK, TIMER_PRIORITY },
245         { 22, 1, 1, 0, INTC_RTC_MSK, TIMER_PRIORITY },
246         { 23, 1, 2, 0, INTC_RTC_MSK, TIMER_PRIORITY },
247         { SCIF0_ERI_IRQ, 8, 24, 0, INTC_SCIF0_MSK, SCIF0_PRIORITY },
248         { SCIF0_RXI_IRQ, 8, 24, 0, INTC_SCIF0_MSK, SCIF0_PRIORITY },
249         { SCIF0_BRI_IRQ, 8, 24, 0, INTC_SCIF0_MSK, SCIF0_PRIORITY },
250         { SCIF0_TXI_IRQ, 8, 24, 0, INTC_SCIF0_MSK, SCIF0_PRIORITY },
251
252         { SCIF1_ERI_IRQ, 8, 16, 0, INTC_SCIF1_MSK, SCIF1_PRIORITY },
253         { SCIF1_RXI_IRQ, 8, 16, 0, INTC_SCIF1_MSK, SCIF1_PRIORITY },
254         { SCIF1_BRI_IRQ, 8, 16, 0, INTC_SCIF1_MSK, SCIF1_PRIORITY },
255         { SCIF1_TXI_IRQ, 8, 16, 0, INTC_SCIF1_MSK, SCIF1_PRIORITY },
256
257         { PCIC0_IRQ, 0x10,  8, 0, INTC_PCIC0_MSK, PCIC0_PRIORITY },
258         { PCIC1_IRQ, 0x10,  0, 0, INTC_PCIC1_MSK, PCIC1_PRIORITY },
259         { PCIC2_IRQ, 0x14, 24, 0, INTC_PCIC2_MSK, PCIC2_PRIORITY },
260         { PCIC3_IRQ, 0x14, 16, 0, INTC_PCIC3_MSK, PCIC3_PRIORITY },
261         { PCIC4_IRQ, 0x14,  8, 0, INTC_PCIC4_MSK, PCIC4_PRIORITY },
262 #endif
263 };
264
265 void __init init_IRQ_intc2(void)
266 {
267         int i;
268
269         for (i = 0; i < ARRAY_SIZE(intc2_init_data); i++) {
270                 struct intc2_init *p = intc2_init_data + i;
271                 make_intc2_irq(p->irq, p->ipr_offset, p->ipr_shift,
272                                p-> msk_offset, p->msk_shift, p->priority);
273         }
274 }
275
276 /* Adds a termination callback to the interrupt */
277 void intc2_add_clear_irq(int irq, int (*fn)(int))
278 {
279         if (unlikely(irq < INTC2_FIRST_IRQ))
280                 return;
281
282         intc2_data[irq - INTC2_FIRST_IRQ].clear_irq = fn;
283 }
284