1 /* $Id: irq_ipr.c,v 1.1.2.1 2002/11/17 10:53:43 mrbrown Exp $
3 * linux/arch/sh/kernel/irq_ipr.c
5 * Copyright (C) 1999 Niibe Yutaka & Takeshi Yaegashi
6 * Copyright (C) 2000 Kazumoto Kojima
7 * Copyright (C) 2003 Takashi Kusuda <kusuda-takashi@hitachi-ul.co.jp>
9 * Interrupt handling for IPR-based IRQ.
12 * On-chip supporting modules (TMU, RTC, etc.).
13 * On-chip supporting modules for SH7709/SH7709A/SH7729/SH7300.
14 * Hitachi SolutionEngine external I/O:
15 * MS7709SE01, MS7709ASE01, and MS7750SE01
19 #include <linux/config.h>
20 #include <linux/init.h>
21 #include <linux/irq.h>
22 #include <linux/module.h>
24 #include <asm/system.h>
26 #include <asm/machvec.h>
29 unsigned int addr
; /* Address of Interrupt Priority Register */
30 int shift
; /* Shifts of the 16-bit data */
31 int priority
; /* The priority */
33 static struct ipr_data ipr_data
[NR_IRQS
];
35 static void enable_ipr_irq(unsigned int irq
);
36 static void disable_ipr_irq(unsigned int irq
);
38 /* shutdown is same as "disable" */
39 #define shutdown_ipr_irq disable_ipr_irq
41 static void mask_and_ack_ipr(unsigned int);
42 static void end_ipr_irq(unsigned int irq
);
44 static unsigned int startup_ipr_irq(unsigned int irq
)
47 return 0; /* never anything pending */
50 static struct hw_interrupt_type ipr_irq_type
= {
60 static void disable_ipr_irq(unsigned int irq
)
62 unsigned long val
, flags
;
63 unsigned int addr
= ipr_data
[irq
].addr
;
64 unsigned short mask
= 0xffff ^ (0x0f << ipr_data
[irq
].shift
);
66 /* Set the priority in IPR to 0 */
67 local_irq_save(flags
);
71 local_irq_restore(flags
);
74 static void enable_ipr_irq(unsigned int irq
)
76 unsigned long val
, flags
;
77 unsigned int addr
= ipr_data
[irq
].addr
;
78 int priority
= ipr_data
[irq
].priority
;
79 unsigned short value
= (priority
<< ipr_data
[irq
].shift
);
81 /* Set priority in IPR back to original value */
82 local_irq_save(flags
);
86 local_irq_restore(flags
);
89 static void mask_and_ack_ipr(unsigned int irq
)
93 #if defined(CONFIG_CPU_SUBTYPE_SH7707) || defined(CONFIG_CPU_SUBTYPE_SH7709) || \
94 defined(CONFIG_CPU_SUBTYPE_SH7300) || defined(CONFIG_CPU_SUBTYPE_SH7705)
95 /* This is needed when we use edge triggered setting */
96 /* XXX: Is it really needed? */
97 if (IRQ0_IRQ
<= irq
&& irq
<= IRQ5_IRQ
) {
98 /* Clear external interrupt request */
99 int a
= ctrl_inb(INTC_IRR0
);
100 a
&= ~(1 << (irq
- IRQ0_IRQ
));
101 ctrl_outb(a
, INTC_IRR0
);
106 static void end_ipr_irq(unsigned int irq
)
108 if (!(irq_desc
[irq
].status
& (IRQ_DISABLED
|IRQ_INPROGRESS
)))
112 void make_ipr_irq(unsigned int irq
, unsigned int addr
, int pos
, int priority
)
114 disable_irq_nosync(irq
);
115 ipr_data
[irq
].addr
= addr
;
116 ipr_data
[irq
].shift
= pos
*4; /* POSition (0-3) x 4 means shift */
117 ipr_data
[irq
].priority
= priority
;
119 irq_desc
[irq
].handler
= &ipr_irq_type
;
120 disable_ipr_irq(irq
);
123 #if defined(CONFIG_CPU_SUBTYPE_SH7705) || \
124 defined(CONFIG_CPU_SUBTYPE_SH7707) || \
125 defined(CONFIG_CPU_SUBTYPE_SH7709)
126 static unsigned char pint_map
[256];
127 static unsigned long portcr_mask
= 0;
129 static void enable_pint_irq(unsigned int irq
);
130 static void disable_pint_irq(unsigned int irq
);
132 /* shutdown is same as "disable" */
133 #define shutdown_pint_irq disable_pint_irq
135 static void mask_and_ack_pint(unsigned int);
136 static void end_pint_irq(unsigned int irq
);
138 static unsigned int startup_pint_irq(unsigned int irq
)
140 enable_pint_irq(irq
);
141 return 0; /* never anything pending */
144 static struct hw_interrupt_type pint_irq_type
= {
154 static void disable_pint_irq(unsigned int irq
)
156 unsigned long val
, flags
;
158 local_irq_save(flags
);
159 val
= ctrl_inw(INTC_INTER
);
160 val
&= ~(1 << (irq
- PINT_IRQ_BASE
));
161 ctrl_outw(val
, INTC_INTER
); /* disable PINTn */
162 portcr_mask
&= ~(3 << (irq
- PINT_IRQ_BASE
)*2);
163 local_irq_restore(flags
);
166 static void enable_pint_irq(unsigned int irq
)
168 unsigned long val
, flags
;
170 local_irq_save(flags
);
171 val
= ctrl_inw(INTC_INTER
);
172 val
|= 1 << (irq
- PINT_IRQ_BASE
);
173 ctrl_outw(val
, INTC_INTER
); /* enable PINTn */
174 portcr_mask
|= 3 << (irq
- PINT_IRQ_BASE
)*2;
175 local_irq_restore(flags
);
178 static void mask_and_ack_pint(unsigned int irq
)
180 disable_pint_irq(irq
);
183 static void end_pint_irq(unsigned int irq
)
185 if (!(irq_desc
[irq
].status
& (IRQ_DISABLED
|IRQ_INPROGRESS
)))
186 enable_pint_irq(irq
);
189 void make_pint_irq(unsigned int irq
)
191 disable_irq_nosync(irq
);
192 irq_desc
[irq
].handler
= &pint_irq_type
;
193 disable_pint_irq(irq
);
197 void __init
init_IRQ(void)
199 #if defined(CONFIG_CPU_SUBTYPE_SH7705) || \
200 defined(CONFIG_CPU_SUBTYPE_SH7707) || \
201 defined(CONFIG_CPU_SUBTYPE_SH7709)
205 make_ipr_irq(TIMER_IRQ
, TIMER_IPR_ADDR
, TIMER_IPR_POS
, TIMER_PRIORITY
);
206 make_ipr_irq(TIMER1_IRQ
, TIMER1_IPR_ADDR
, TIMER1_IPR_POS
, TIMER1_PRIORITY
);
207 #if defined(CONFIG_SH_RTC)
208 make_ipr_irq(RTC_IRQ
, RTC_IPR_ADDR
, RTC_IPR_POS
, RTC_PRIORITY
);
212 make_ipr_irq(SCI_ERI_IRQ
, SCI_IPR_ADDR
, SCI_IPR_POS
, SCI_PRIORITY
);
213 make_ipr_irq(SCI_RXI_IRQ
, SCI_IPR_ADDR
, SCI_IPR_POS
, SCI_PRIORITY
);
214 make_ipr_irq(SCI_TXI_IRQ
, SCI_IPR_ADDR
, SCI_IPR_POS
, SCI_PRIORITY
);
218 make_ipr_irq(SCIF1_ERI_IRQ
, SCIF1_IPR_ADDR
, SCIF1_IPR_POS
, SCIF1_PRIORITY
);
219 make_ipr_irq(SCIF1_RXI_IRQ
, SCIF1_IPR_ADDR
, SCIF1_IPR_POS
, SCIF1_PRIORITY
);
220 make_ipr_irq(SCIF1_BRI_IRQ
, SCIF1_IPR_ADDR
, SCIF1_IPR_POS
, SCIF1_PRIORITY
);
221 make_ipr_irq(SCIF1_TXI_IRQ
, SCIF1_IPR_ADDR
, SCIF1_IPR_POS
, SCIF1_PRIORITY
);
224 #if defined(CONFIG_CPU_SUBTYPE_SH7300)
225 make_ipr_irq(SCIF0_IRQ
, SCIF0_IPR_ADDR
, SCIF0_IPR_POS
, SCIF0_PRIORITY
);
226 make_ipr_irq(DMTE2_IRQ
, DMA1_IPR_ADDR
, DMA1_IPR_POS
, DMA1_PRIORITY
);
227 make_ipr_irq(DMTE3_IRQ
, DMA1_IPR_ADDR
, DMA1_IPR_POS
, DMA1_PRIORITY
);
228 make_ipr_irq(VIO_IRQ
, VIO_IPR_ADDR
, VIO_IPR_POS
, VIO_PRIORITY
);
232 make_ipr_irq(SCIF_ERI_IRQ
, SCIF_IPR_ADDR
, SCIF_IPR_POS
, SCIF_PRIORITY
);
233 make_ipr_irq(SCIF_RXI_IRQ
, SCIF_IPR_ADDR
, SCIF_IPR_POS
, SCIF_PRIORITY
);
234 make_ipr_irq(SCIF_BRI_IRQ
, SCIF_IPR_ADDR
, SCIF_IPR_POS
, SCIF_PRIORITY
);
235 make_ipr_irq(SCIF_TXI_IRQ
, SCIF_IPR_ADDR
, SCIF_IPR_POS
, SCIF_PRIORITY
);
239 make_ipr_irq(IRDA_ERI_IRQ
, IRDA_IPR_ADDR
, IRDA_IPR_POS
, IRDA_PRIORITY
);
240 make_ipr_irq(IRDA_RXI_IRQ
, IRDA_IPR_ADDR
, IRDA_IPR_POS
, IRDA_PRIORITY
);
241 make_ipr_irq(IRDA_BRI_IRQ
, IRDA_IPR_ADDR
, IRDA_IPR_POS
, IRDA_PRIORITY
);
242 make_ipr_irq(IRDA_TXI_IRQ
, IRDA_IPR_ADDR
, IRDA_IPR_POS
, IRDA_PRIORITY
);
245 #if defined(CONFIG_CPU_SUBTYPE_SH7707) || defined(CONFIG_CPU_SUBTYPE_SH7709) || \
246 defined(CONFIG_CPU_SUBTYPE_SH7300) || defined(CONFIG_CPU_SUBTYPE_SH7705)
248 * Initialize the Interrupt Controller (INTC)
249 * registers to their power on values
253 * Enable external irq (INTC IRQ mode).
254 * You should set corresponding bits of PFC to "00"
255 * to enable these interrupts.
257 make_ipr_irq(IRQ0_IRQ
, IRQ0_IPR_ADDR
, IRQ0_IPR_POS
, IRQ0_PRIORITY
);
258 make_ipr_irq(IRQ1_IRQ
, IRQ1_IPR_ADDR
, IRQ1_IPR_POS
, IRQ1_PRIORITY
);
259 make_ipr_irq(IRQ2_IRQ
, IRQ2_IPR_ADDR
, IRQ2_IPR_POS
, IRQ2_PRIORITY
);
260 make_ipr_irq(IRQ3_IRQ
, IRQ3_IPR_ADDR
, IRQ3_IPR_POS
, IRQ3_PRIORITY
);
261 make_ipr_irq(IRQ4_IRQ
, IRQ4_IPR_ADDR
, IRQ4_IPR_POS
, IRQ4_PRIORITY
);
262 make_ipr_irq(IRQ5_IRQ
, IRQ5_IPR_ADDR
, IRQ5_IPR_POS
, IRQ5_PRIORITY
);
263 #if !defined(CONFIG_CPU_SUBTYPE_SH7300)
264 make_ipr_irq(PINT0_IRQ
, PINT0_IPR_ADDR
, PINT0_IPR_POS
, PINT0_PRIORITY
);
265 make_ipr_irq(PINT8_IRQ
, PINT8_IPR_ADDR
, PINT8_IPR_POS
, PINT8_PRIORITY
);
266 enable_ipr_irq(PINT0_IRQ
);
267 enable_ipr_irq(PINT8_IRQ
);
269 for(i
= 0; i
< 16; i
++)
270 make_pint_irq(PINT_IRQ_BASE
+ i
);
271 for(i
= 0; i
< 256; i
++)
273 if(i
& 1) pint_map
[i
] = 0;
274 else if(i
& 2) pint_map
[i
] = 1;
275 else if(i
& 4) pint_map
[i
] = 2;
276 else if(i
& 8) pint_map
[i
] = 3;
277 else if(i
& 0x10) pint_map
[i
] = 4;
278 else if(i
& 0x20) pint_map
[i
] = 5;
279 else if(i
& 0x40) pint_map
[i
] = 6;
280 else if(i
& 0x80) pint_map
[i
] = 7;
282 #endif /* !CONFIG_CPU_SUBTYPE_SH7300 */
283 #endif /* CONFIG_CPU_SUBTYPE_SH7707 || CONFIG_CPU_SUBTYPE_SH7709 || CONFIG_CPU_SUBTYPE_SH7300*/
285 #ifdef CONFIG_CPU_SUBTYPE_ST40
289 /* Perform the machine specific initialisation */
290 if (sh_mv
.mv_init_irq
!= NULL
) {
294 #if defined(CONFIG_CPU_SUBTYPE_SH7707) || defined(CONFIG_CPU_SUBTYPE_SH7709) || \
295 defined(CONFIG_CPU_SUBTYPE_SH7300) || defined(CONFIG_CPU_SUBTYPE_SH7705)
296 int ipr_irq_demux(int irq
)
298 #if !defined(CONFIG_CPU_SUBTYPE_SH7300)
299 unsigned long creg
, dreg
, d
, sav
;
303 #if defined(CONFIG_CPU_SUBTYPE_SH7707)
310 sav
= ctrl_inw(creg
);
311 ctrl_outw(sav
| portcr_mask
, creg
);
312 d
= (~ctrl_inb(dreg
) ^ ctrl_inw(INTC_ICR2
)) & ctrl_inw(INTC_INTER
) & 0xff;
313 ctrl_outw(sav
, creg
);
314 if(d
== 0) return irq
;
315 return PINT_IRQ_BASE
+ pint_map
[d
];
317 else if(irq
== PINT8_IRQ
)
319 #if defined(CONFIG_CPU_SUBTYPE_SH7707)
326 sav
= ctrl_inw(creg
);
327 ctrl_outw(sav
| (portcr_mask
>> 16), creg
);
328 d
= (~ctrl_inb(dreg
) ^ (ctrl_inw(INTC_ICR2
) >> 8)) & (ctrl_inw(INTC_INTER
) >> 8) & 0xff;
329 ctrl_outw(sav
, creg
);
330 if(d
== 0) return irq
;
331 return PINT_IRQ_BASE
+ 8 + pint_map
[d
];
338 EXPORT_SYMBOL(make_ipr_irq
);