]>
Commit | Line | Data |
---|---|---|
bf3a00f8 PM |
1 | /* |
2 | * arch/sh/kernel/cpu/irq/ipr.c | |
1da177e4 LT |
3 | * |
4 | * Copyright (C) 1999 Niibe Yutaka & Takeshi Yaegashi | |
5 | * Copyright (C) 2000 Kazumoto Kojima | |
6 | * Copyright (C) 2003 Takashi Kusuda <kusuda-takashi@hitachi-ul.co.jp> | |
7 | * | |
8 | * Interrupt handling for IPR-based IRQ. | |
9 | * | |
10 | * Supported system: | |
11 | * On-chip supporting modules (TMU, RTC, etc.). | |
12 | * On-chip supporting modules for SH7709/SH7709A/SH7729/SH7300. | |
13 | * Hitachi SolutionEngine external I/O: | |
14 | * MS7709SE01, MS7709ASE01, and MS7750SE01 | |
15 | * | |
16 | */ | |
17 | ||
1da177e4 LT |
18 | #include <linux/init.h> |
19 | #include <linux/irq.h> | |
20 | #include <linux/module.h> | |
21 | ||
22 | #include <asm/system.h> | |
23 | #include <asm/io.h> | |
24 | #include <asm/machvec.h> | |
25 | ||
26 | struct ipr_data { | |
27 | unsigned int addr; /* Address of Interrupt Priority Register */ | |
28 | int shift; /* Shifts of the 16-bit data */ | |
29 | int priority; /* The priority */ | |
30 | }; | |
31 | static struct ipr_data ipr_data[NR_IRQS]; | |
32 | ||
33 | static void enable_ipr_irq(unsigned int irq); | |
34 | static void disable_ipr_irq(unsigned int irq); | |
35 | ||
36 | /* shutdown is same as "disable" */ | |
37 | #define shutdown_ipr_irq disable_ipr_irq | |
38 | ||
39 | static void mask_and_ack_ipr(unsigned int); | |
40 | static void end_ipr_irq(unsigned int irq); | |
41 | ||
42 | static unsigned int startup_ipr_irq(unsigned int irq) | |
43 | { | |
44 | enable_ipr_irq(irq); | |
45 | return 0; /* never anything pending */ | |
46 | } | |
47 | ||
48 | static struct hw_interrupt_type ipr_irq_type = { | |
08d0fd07 TG |
49 | .typename = "IPR-IRQ", |
50 | .startup = startup_ipr_irq, | |
51 | .shutdown = shutdown_ipr_irq, | |
52 | .enable = enable_ipr_irq, | |
53 | .disable = disable_ipr_irq, | |
54 | .ack = mask_and_ack_ipr, | |
55 | .end = end_ipr_irq | |
1da177e4 LT |
56 | }; |
57 | ||
58 | static void disable_ipr_irq(unsigned int irq) | |
59 | { | |
60 | unsigned long val, flags; | |
61 | unsigned int addr = ipr_data[irq].addr; | |
62 | unsigned short mask = 0xffff ^ (0x0f << ipr_data[irq].shift); | |
63 | ||
64 | /* Set the priority in IPR to 0 */ | |
65 | local_irq_save(flags); | |
66 | val = ctrl_inw(addr); | |
67 | val &= mask; | |
68 | ctrl_outw(val, addr); | |
69 | local_irq_restore(flags); | |
70 | } | |
71 | ||
72 | static void enable_ipr_irq(unsigned int irq) | |
73 | { | |
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); | |
78 | ||
79 | /* Set priority in IPR back to original value */ | |
80 | local_irq_save(flags); | |
81 | val = ctrl_inw(addr); | |
82 | val |= value; | |
83 | ctrl_outw(val, addr); | |
84 | local_irq_restore(flags); | |
85 | } | |
86 | ||
87 | static void mask_and_ack_ipr(unsigned int irq) | |
88 | { | |
89 | disable_ipr_irq(irq); | |
90 | ||
91 | #if defined(CONFIG_CPU_SUBTYPE_SH7707) || defined(CONFIG_CPU_SUBTYPE_SH7709) || \ | |
92 | defined(CONFIG_CPU_SUBTYPE_SH7300) || defined(CONFIG_CPU_SUBTYPE_SH7705) | |
93 | /* This is needed when we use edge triggered setting */ | |
94 | /* XXX: Is it really needed? */ | |
95 | if (IRQ0_IRQ <= irq && irq <= IRQ5_IRQ) { | |
96 | /* Clear external interrupt request */ | |
97 | int a = ctrl_inb(INTC_IRR0); | |
98 | a &= ~(1 << (irq - IRQ0_IRQ)); | |
99 | ctrl_outb(a, INTC_IRR0); | |
100 | } | |
101 | #endif | |
102 | } | |
103 | ||
104 | static void end_ipr_irq(unsigned int irq) | |
105 | { | |
106 | if (!(irq_desc[irq].status & (IRQ_DISABLED|IRQ_INPROGRESS))) | |
107 | enable_ipr_irq(irq); | |
108 | } | |
109 | ||
8d27e081 | 110 | void make_ipr_irq(unsigned int irq, unsigned int addr, int pos, int priority) |
1da177e4 LT |
111 | { |
112 | disable_irq_nosync(irq); | |
113 | ipr_data[irq].addr = addr; | |
114 | ipr_data[irq].shift = pos*4; /* POSition (0-3) x 4 means shift */ | |
115 | ipr_data[irq].priority = priority; | |
116 | ||
d1bef4ed | 117 | irq_desc[irq].chip = &ipr_irq_type; |
1da177e4 LT |
118 | disable_ipr_irq(irq); |
119 | } | |
120 | ||
1da177e4 LT |
121 | void __init init_IRQ(void) |
122 | { | |
bf3a00f8 | 123 | #ifndef CONFIG_CPU_SUBTYPE_SH7780 |
8d27e081 PM |
124 | make_ipr_irq(TIMER_IRQ, TIMER_IPR_ADDR, TIMER_IPR_POS, TIMER_PRIORITY); |
125 | make_ipr_irq(TIMER1_IRQ, TIMER1_IPR_ADDR, TIMER1_IPR_POS, TIMER1_PRIORITY); | |
1da177e4 | 126 | #if defined(CONFIG_SH_RTC) |
8d27e081 | 127 | make_ipr_irq(RTC_IRQ, RTC_IPR_ADDR, RTC_IPR_POS, RTC_PRIORITY); |
1da177e4 LT |
128 | #endif |
129 | ||
130 | #ifdef SCI_ERI_IRQ | |
8d27e081 PM |
131 | make_ipr_irq(SCI_ERI_IRQ, SCI_IPR_ADDR, SCI_IPR_POS, SCI_PRIORITY); |
132 | make_ipr_irq(SCI_RXI_IRQ, SCI_IPR_ADDR, SCI_IPR_POS, SCI_PRIORITY); | |
133 | make_ipr_irq(SCI_TXI_IRQ, SCI_IPR_ADDR, SCI_IPR_POS, SCI_PRIORITY); | |
1da177e4 LT |
134 | #endif |
135 | ||
136 | #ifdef SCIF1_ERI_IRQ | |
8d27e081 PM |
137 | make_ipr_irq(SCIF1_ERI_IRQ, SCIF1_IPR_ADDR, SCIF1_IPR_POS, SCIF1_PRIORITY); |
138 | make_ipr_irq(SCIF1_RXI_IRQ, SCIF1_IPR_ADDR, SCIF1_IPR_POS, SCIF1_PRIORITY); | |
139 | make_ipr_irq(SCIF1_BRI_IRQ, SCIF1_IPR_ADDR, SCIF1_IPR_POS, SCIF1_PRIORITY); | |
140 | make_ipr_irq(SCIF1_TXI_IRQ, SCIF1_IPR_ADDR, SCIF1_IPR_POS, SCIF1_PRIORITY); | |
1da177e4 LT |
141 | #endif |
142 | ||
143 | #if defined(CONFIG_CPU_SUBTYPE_SH7300) | |
8d27e081 PM |
144 | make_ipr_irq(SCIF0_IRQ, SCIF0_IPR_ADDR, SCIF0_IPR_POS, SCIF0_PRIORITY); |
145 | make_ipr_irq(DMTE2_IRQ, DMA1_IPR_ADDR, DMA1_IPR_POS, DMA1_PRIORITY); | |
146 | make_ipr_irq(DMTE3_IRQ, DMA1_IPR_ADDR, DMA1_IPR_POS, DMA1_PRIORITY); | |
147 | make_ipr_irq(VIO_IRQ, VIO_IPR_ADDR, VIO_IPR_POS, VIO_PRIORITY); | |
1da177e4 LT |
148 | #endif |
149 | ||
150 | #ifdef SCIF_ERI_IRQ | |
8d27e081 PM |
151 | make_ipr_irq(SCIF_ERI_IRQ, SCIF_IPR_ADDR, SCIF_IPR_POS, SCIF_PRIORITY); |
152 | make_ipr_irq(SCIF_RXI_IRQ, SCIF_IPR_ADDR, SCIF_IPR_POS, SCIF_PRIORITY); | |
153 | make_ipr_irq(SCIF_BRI_IRQ, SCIF_IPR_ADDR, SCIF_IPR_POS, SCIF_PRIORITY); | |
154 | make_ipr_irq(SCIF_TXI_IRQ, SCIF_IPR_ADDR, SCIF_IPR_POS, SCIF_PRIORITY); | |
1da177e4 LT |
155 | #endif |
156 | ||
157 | #ifdef IRDA_ERI_IRQ | |
8d27e081 PM |
158 | make_ipr_irq(IRDA_ERI_IRQ, IRDA_IPR_ADDR, IRDA_IPR_POS, IRDA_PRIORITY); |
159 | make_ipr_irq(IRDA_RXI_IRQ, IRDA_IPR_ADDR, IRDA_IPR_POS, IRDA_PRIORITY); | |
160 | make_ipr_irq(IRDA_BRI_IRQ, IRDA_IPR_ADDR, IRDA_IPR_POS, IRDA_PRIORITY); | |
161 | make_ipr_irq(IRDA_TXI_IRQ, IRDA_IPR_ADDR, IRDA_IPR_POS, IRDA_PRIORITY); | |
1da177e4 LT |
162 | #endif |
163 | ||
164 | #if defined(CONFIG_CPU_SUBTYPE_SH7707) || defined(CONFIG_CPU_SUBTYPE_SH7709) || \ | |
165 | defined(CONFIG_CPU_SUBTYPE_SH7300) || defined(CONFIG_CPU_SUBTYPE_SH7705) | |
166 | /* | |
167 | * Initialize the Interrupt Controller (INTC) | |
168 | * registers to their power on values | |
169 | */ | |
170 | ||
171 | /* | |
172 | * Enable external irq (INTC IRQ mode). | |
173 | * You should set corresponding bits of PFC to "00" | |
174 | * to enable these interrupts. | |
175 | */ | |
8d27e081 PM |
176 | make_ipr_irq(IRQ0_IRQ, IRQ0_IPR_ADDR, IRQ0_IPR_POS, IRQ0_PRIORITY); |
177 | make_ipr_irq(IRQ1_IRQ, IRQ1_IPR_ADDR, IRQ1_IPR_POS, IRQ1_PRIORITY); | |
178 | make_ipr_irq(IRQ2_IRQ, IRQ2_IPR_ADDR, IRQ2_IPR_POS, IRQ2_PRIORITY); | |
179 | make_ipr_irq(IRQ3_IRQ, IRQ3_IPR_ADDR, IRQ3_IPR_POS, IRQ3_PRIORITY); | |
180 | make_ipr_irq(IRQ4_IRQ, IRQ4_IPR_ADDR, IRQ4_IPR_POS, IRQ4_PRIORITY); | |
181 | make_ipr_irq(IRQ5_IRQ, IRQ5_IPR_ADDR, IRQ5_IPR_POS, IRQ5_PRIORITY); | |
bf3a00f8 PM |
182 | #endif |
183 | #endif | |
1da177e4 | 184 | |
bf3a00f8 PM |
185 | #ifdef CONFIG_CPU_HAS_PINT_IRQ |
186 | init_IRQ_pint(); | |
187 | #endif | |
1da177e4 | 188 | |
bf3a00f8 | 189 | #ifdef CONFIG_CPU_HAS_INTC2_IRQ |
1da177e4 LT |
190 | init_IRQ_intc2(); |
191 | #endif | |
1da177e4 | 192 | /* Perform the machine specific initialisation */ |
bf3a00f8 | 193 | if (sh_mv.mv_init_irq != NULL) |
1da177e4 | 194 | sh_mv.mv_init_irq(); |
1da177e4 | 195 | } |
bf3a00f8 PM |
196 | |
197 | #if !defined(CONFIG_CPU_HAS_PINT_IRQ) | |
1da177e4 LT |
198 | int ipr_irq_demux(int irq) |
199 | { | |
1da177e4 LT |
200 | return irq; |
201 | } | |
202 | #endif | |
203 | ||
204 | EXPORT_SYMBOL(make_ipr_irq); |