2 * Interrupt handling for INTC2-based IRQ.
4 * Copyright (C) 2001 David J. Mckay (david.mckay@st.com)
5 * Copyright (C) 2005, 2006 Paul Mundt (lethal@linux-sh.org)
7 * May be copied or modified under the terms of the GNU General Public
8 * License. See linux/COPYING for more information.
10 * These are the "new Hitachi style" interrupts, as present on the
11 * Hitachi 7751, the STM ST40 STB1, SH7760, and SH7780.
14 #include <linux/kernel.h>
15 #include <linux/init.h>
16 #include <linux/irq.h>
17 #include <asm/system.h>
19 #include <asm/machvec.h>
22 unsigned char msk_offset;
23 unsigned char msk_shift;
25 int (*clear_irq) (int);
28 static struct intc2_data intc2_data[NR_INTC2_IRQS];
30 static void enable_intc2_irq(unsigned int irq);
31 static void disable_intc2_irq(unsigned int irq);
33 /* shutdown is same as "disable" */
34 #define shutdown_intc2_irq disable_intc2_irq
36 static void mask_and_ack_intc2(unsigned int);
37 static void end_intc2_irq(unsigned int irq);
39 static unsigned int startup_intc2_irq(unsigned int irq)
41 enable_intc2_irq(irq);
42 return 0; /* never anything pending */
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,
55 static void disable_intc2_irq(unsigned int irq)
57 int irq_offset = irq - INTC2_FIRST_IRQ;
58 int msk_shift, msk_offset;
61 if (unlikely(irq_offset < 0 || irq_offset >= NR_INTC2_IRQS))
64 msk_shift = intc2_data[irq_offset].msk_shift;
65 msk_offset = intc2_data[irq_offset].msk_offset;
67 ctrl_outl(1 << msk_shift,
68 INTC2_BASE + INTC2_INTMSK_OFFSET + msk_offset);
71 static void enable_intc2_irq(unsigned int irq)
73 int irq_offset = irq - INTC2_FIRST_IRQ;
74 int msk_shift, msk_offset;
77 if (unlikely(irq_offset < 0 || irq_offset >= NR_INTC2_IRQS))
80 msk_shift = intc2_data[irq_offset].msk_shift;
81 msk_offset = intc2_data[irq_offset].msk_offset;
83 ctrl_outl(1 << msk_shift,
84 INTC2_BASE + INTC2_INTMSKCLR_OFFSET + msk_offset);
87 static void mask_and_ack_intc2(unsigned int irq)
89 disable_intc2_irq(irq);
92 static void end_intc2_irq(unsigned int irq)
94 if (!(irq_desc[irq].status & (IRQ_DISABLED|IRQ_INPROGRESS)))
95 enable_intc2_irq(irq);
97 if (unlikely(intc2_data[irq - INTC2_FIRST_IRQ].clear_irq))
98 intc2_data[irq - INTC2_FIRST_IRQ].clear_irq(irq);
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.
106 * PIO1 which is INTPRI00[19,16] and INTMSK00[13]
109 * make_intc2_irq(84, 0, 16, 0, 13);
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)
116 int irq_offset = irq - INTC2_FIRST_IRQ;
120 if (unlikely(irq_offset < 0 || irq_offset >= NR_INTC2_IRQS))
123 disable_irq_nosync(irq);
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;
130 /* Set the priority level */
131 local_irq_save(flags);
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);
138 local_irq_restore(flags);
140 irq_desc[irq].chip = &intc2_irq_type;
142 disable_intc2_irq(irq);
145 static struct intc2_init {
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 */
186 #elif defined(CONFIG_CPU_SUBTYPE_SH7760)
188 * SH7760 INTC2-Style interrupts, vectors IRQ48-111 INTEVT 0x800-0xFE0
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 */
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 */
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 */
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 },
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 },
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 },
265 void __init init_IRQ_intc2(void)
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);
276 /* Adds a termination callback to the interrupt */
277 void intc2_add_clear_irq(int irq, int (*fn)(int))
279 if (unlikely(irq < INTC2_FIRST_IRQ))
282 intc2_data[irq - INTC2_FIRST_IRQ].clear_irq = fn;