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
8 * Interrupt handling for IPR-based IRQ.
11 * On-chip supporting modules (TMU, RTC, etc.).
12 * On-chip supporting modules for SH7709/SH7709A/SH7729.
13 * Hitachi SolutionEngine external I/O:
14 * MS7709SE01, MS7709ASE01, and MS7750SE01
18 #include <linux/config.h>
19 #include <linux/init.h>
20 #include <linux/irq.h>
22 #include <asm/system.h>
24 #include <asm/machvec.h>
27 unsigned int addr
; /* Address of Interrupt Priority Register */
28 int shift
; /* Shifts of the 16-bit data */
29 int priority
; /* The priority */
31 static struct ipr_data ipr_data
[NR_IRQS
];
33 static void enable_ipr_irq(unsigned int irq
);
34 static void disable_ipr_irq(unsigned int irq
);
36 /* shutdown is same as "disable" */
37 #define shutdown_ipr_irq disable_ipr_irq
39 static void mask_and_ack_ipr(unsigned int);
40 static void end_ipr_irq(unsigned int irq
);
42 static unsigned int startup_ipr_irq(unsigned int irq
)
45 return 0; /* never anything pending */
48 static struct hw_interrupt_type ipr_irq_type
= {
58 static void disable_ipr_irq(unsigned int irq
)
60 unsigned long val
, flags
;
61 unsigned int addr
= ipr_data
[irq
].addr
;
62 unsigned short mask
= 0xffff ^ (0x0f << ipr_data
[irq
].shift
);
64 /* Set the priority in IPR to 0 */
65 local_irq_save(flags
);
69 local_irq_restore(flags
);
72 static void enable_ipr_irq(unsigned int irq
)
74 unsigned long val
, flags
;
75 unsigned int addr
= ipr_data
[irq
].addr
;
76 int priority
= ipr_data
[irq
].priority
;
77 unsigned short value
= (priority
<< ipr_data
[irq
].shift
);
79 /* Set priority in IPR back to original value */
80 local_irq_save(flags
);
84 local_irq_restore(flags
);
87 static void mask_and_ack_ipr(unsigned int irq
)
91 #if defined(CONFIG_CPU_SUBTYPE_SH7707) || defined(CONFIG_CPU_SUBTYPE_SH7709)
92 /* This is needed when we use edge triggered setting */
93 /* XXX: Is it really needed? */
94 if (IRQ0_IRQ
<= irq
&& irq
<= IRQ5_IRQ
) {
95 /* Clear external interrupt request */
96 int a
= ctrl_inb(INTC_IRR0
);
97 a
&= ~(1 << (irq
- IRQ0_IRQ
));
98 ctrl_outb(a
, INTC_IRR0
);
103 static void end_ipr_irq(unsigned int irq
)
105 if (!(irq_desc
[irq
].status
& (IRQ_DISABLED
|IRQ_INPROGRESS
)))
109 void make_ipr_irq(unsigned int irq
, unsigned int addr
, int pos
, int priority
)
111 disable_irq_nosync(irq
);
112 ipr_data
[irq
].addr
= addr
;
113 ipr_data
[irq
].shift
= pos
*4; /* POSition (0-3) x 4 means shift */
114 ipr_data
[irq
].priority
= priority
;
116 irq_desc
[irq
].handler
= &ipr_irq_type
;
117 disable_ipr_irq(irq
);
120 #if defined(CONFIG_CPU_SUBTYPE_SH7707) || defined(CONFIG_CPU_SUBTYPE_SH7709)
121 static unsigned char pint_map
[256];
122 static unsigned long portcr_mask
= 0;
124 static void enable_pint_irq(unsigned int irq
);
125 static void disable_pint_irq(unsigned int irq
);
127 /* shutdown is same as "disable" */
128 #define shutdown_pint_irq disable_pint_irq
130 static void mask_and_ack_pint(unsigned int);
131 static void end_pint_irq(unsigned int irq
);
133 static unsigned int startup_pint_irq(unsigned int irq
)
135 enable_pint_irq(irq
);
136 return 0; /* never anything pending */
139 static struct hw_interrupt_type pint_irq_type
= {
149 static void disable_pint_irq(unsigned int irq
)
151 unsigned long val
, flags
;
153 local_irq_save(flags
);
154 val
= ctrl_inw(INTC_INTER
);
155 val
&= ~(1 << (irq
- PINT_IRQ_BASE
));
156 ctrl_outw(val
, INTC_INTER
); /* disable PINTn */
157 portcr_mask
&= ~(3 << (irq
- PINT_IRQ_BASE
)*2);
158 local_irq_restore(flags
);
161 static void enable_pint_irq(unsigned int irq
)
163 unsigned long val
, flags
;
165 local_irq_save(flags
);
166 val
= ctrl_inw(INTC_INTER
);
167 val
|= 1 << (irq
- PINT_IRQ_BASE
);
168 ctrl_outw(val
, INTC_INTER
); /* enable PINTn */
169 portcr_mask
|= 3 << (irq
- PINT_IRQ_BASE
)*2;
170 local_irq_restore(flags
);
173 static void mask_and_ack_pint(unsigned int irq
)
175 disable_pint_irq(irq
);
178 static void end_pint_irq(unsigned int irq
)
180 if (!(irq_desc
[irq
].status
& (IRQ_DISABLED
|IRQ_INPROGRESS
)))
181 enable_pint_irq(irq
);
184 void make_pint_irq(unsigned int irq
)
186 disable_irq_nosync(irq
);
187 irq_desc
[irq
].handler
= &pint_irq_type
;
188 disable_pint_irq(irq
);
192 void __init
init_IRQ(void)
194 #if defined(CONFIG_CPU_SUBTYPE_SH7707) || defined(CONFIG_CPU_SUBTYPE_SH7709)
198 make_ipr_irq(TIMER_IRQ
, TIMER_IPR_ADDR
, TIMER_IPR_POS
, TIMER_PRIORITY
);
199 make_ipr_irq(RTC_IRQ
, RTC_IPR_ADDR
, RTC_IPR_POS
, RTC_PRIORITY
);
202 make_ipr_irq(SCI_ERI_IRQ
, SCI_IPR_ADDR
, SCI_IPR_POS
, SCI_PRIORITY
);
203 make_ipr_irq(SCI_RXI_IRQ
, SCI_IPR_ADDR
, SCI_IPR_POS
, SCI_PRIORITY
);
204 make_ipr_irq(SCI_TXI_IRQ
, SCI_IPR_ADDR
, SCI_IPR_POS
, SCI_PRIORITY
);
208 make_ipr_irq(SCIF1_ERI_IRQ
, SCIF1_IPR_ADDR
, SCIF1_IPR_POS
, SCIF1_PRIORITY
);
209 make_ipr_irq(SCIF1_RXI_IRQ
, SCIF1_IPR_ADDR
, SCIF1_IPR_POS
, SCIF1_PRIORITY
);
210 make_ipr_irq(SCIF1_BRI_IRQ
, SCIF1_IPR_ADDR
, SCIF1_IPR_POS
, SCIF1_PRIORITY
);
211 make_ipr_irq(SCIF1_TXI_IRQ
, SCIF1_IPR_ADDR
, SCIF1_IPR_POS
, SCIF1_PRIORITY
);
215 make_ipr_irq(SCIF_ERI_IRQ
, SCIF_IPR_ADDR
, SCIF_IPR_POS
, SCIF_PRIORITY
);
216 make_ipr_irq(SCIF_RXI_IRQ
, SCIF_IPR_ADDR
, SCIF_IPR_POS
, SCIF_PRIORITY
);
217 make_ipr_irq(SCIF_BRI_IRQ
, SCIF_IPR_ADDR
, SCIF_IPR_POS
, SCIF_PRIORITY
);
218 make_ipr_irq(SCIF_TXI_IRQ
, SCIF_IPR_ADDR
, SCIF_IPR_POS
, SCIF_PRIORITY
);
222 make_ipr_irq(IRDA_ERI_IRQ
, IRDA_IPR_ADDR
, IRDA_IPR_POS
, IRDA_PRIORITY
);
223 make_ipr_irq(IRDA_RXI_IRQ
, IRDA_IPR_ADDR
, IRDA_IPR_POS
, IRDA_PRIORITY
);
224 make_ipr_irq(IRDA_BRI_IRQ
, IRDA_IPR_ADDR
, IRDA_IPR_POS
, IRDA_PRIORITY
);
225 make_ipr_irq(IRDA_TXI_IRQ
, IRDA_IPR_ADDR
, IRDA_IPR_POS
, IRDA_PRIORITY
);
228 #if defined(CONFIG_CPU_SUBTYPE_SH7707) || defined(CONFIG_CPU_SUBTYPE_SH7709)
230 * Initialize the Interrupt Controller (INTC)
231 * registers to their power on values
235 * Enable external irq (INTC IRQ mode).
236 * You should set corresponding bits of PFC to "00"
237 * to enable these interrupts.
239 make_ipr_irq(IRQ0_IRQ
, IRQ0_IPR_ADDR
, IRQ0_IPR_POS
, IRQ0_PRIORITY
);
240 make_ipr_irq(IRQ1_IRQ
, IRQ1_IPR_ADDR
, IRQ1_IPR_POS
, IRQ1_PRIORITY
);
241 make_ipr_irq(IRQ2_IRQ
, IRQ2_IPR_ADDR
, IRQ2_IPR_POS
, IRQ2_PRIORITY
);
242 make_ipr_irq(IRQ3_IRQ
, IRQ3_IPR_ADDR
, IRQ3_IPR_POS
, IRQ3_PRIORITY
);
243 make_ipr_irq(IRQ4_IRQ
, IRQ4_IPR_ADDR
, IRQ4_IPR_POS
, IRQ4_PRIORITY
);
244 make_ipr_irq(IRQ5_IRQ
, IRQ5_IPR_ADDR
, IRQ5_IPR_POS
, IRQ5_PRIORITY
);
245 make_ipr_irq(PINT0_IRQ
, PINT0_IPR_ADDR
, PINT0_IPR_POS
, PINT0_PRIORITY
);
246 make_ipr_irq(PINT8_IRQ
, PINT8_IPR_ADDR
, PINT8_IPR_POS
, PINT8_PRIORITY
);
247 enable_ipr_irq(PINT0_IRQ
);
248 enable_ipr_irq(PINT8_IRQ
);
250 for(i
= 0; i
< 16; i
++)
251 make_pint_irq(PINT_IRQ_BASE
+ i
);
252 for(i
= 0; i
< 256; i
++)
254 if(i
& 1) pint_map
[i
] = 0;
255 else if(i
& 2) pint_map
[i
] = 1;
256 else if(i
& 4) pint_map
[i
] = 2;
257 else if(i
& 8) pint_map
[i
] = 3;
258 else if(i
& 0x10) pint_map
[i
] = 4;
259 else if(i
& 0x20) pint_map
[i
] = 5;
260 else if(i
& 0x40) pint_map
[i
] = 6;
261 else if(i
& 0x80) pint_map
[i
] = 7;
263 #endif /* CONFIG_CPU_SUBTYPE_SH7707 || CONFIG_CPU_SUBTYPE_SH7709 */
265 /* Perform the machine specific initialisation */
266 if (sh_mv
.mv_init_irq
!= NULL
) {
270 #if defined(CONFIG_CPU_SUBTYPE_SH7707) || defined(CONFIG_CPU_SUBTYPE_SH7709)
271 int ipr_irq_demux(int irq
)
273 unsigned long creg
, dreg
, d
, sav
;
277 #if defined(CONFIG_CPU_SUBTYPE_SH7707)
284 sav
= ctrl_inw(creg
);
285 ctrl_outw(sav
| portcr_mask
, creg
);
286 d
= (~ctrl_inb(dreg
) ^ ctrl_inw(INTC_ICR2
)) & ctrl_inw(INTC_INTER
) & 0xff;
287 ctrl_outw(sav
, creg
);
288 if(d
== 0) return irq
;
289 return PINT_IRQ_BASE
+ pint_map
[d
];
291 else if(irq
== PINT8_IRQ
)
293 #if defined(CONFIG_CPU_SUBTYPE_SH7707)
300 sav
= ctrl_inw(creg
);
301 ctrl_outw(sav
| (portcr_mask
>> 16), creg
);
302 d
= (~ctrl_inb(dreg
) ^ (ctrl_inw(INTC_ICR2
) >> 8)) & (ctrl_inw(INTC_INTER
) >> 8) & 0xff;
303 ctrl_outw(sav
, creg
);
304 if(d
== 0) return irq
;
305 return PINT_IRQ_BASE
+ 8 + pint_map
[d
];