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},
245 { RTC_IRQ
, 4, 0, 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
;