a8da471265844df9f7b3c03918d0b3162da05853
[platform/adaptation/renesas_rcar/renesas_kernel.git] / arch / m68k / amiga / amiints.c
1 /*
2  * Amiga Linux interrupt handling code
3  *
4  * This file is subject to the terms and conditions of the GNU General Public
5  * License.  See the file COPYING in the main directory of this archive
6  * for more details.
7  */
8
9 #include <linux/init.h>
10 #include <linux/interrupt.h>
11 #include <linux/errno.h>
12 #ifdef CONFIG_GENERIC_HARDIRQS
13 #include <linux/irq.h>
14 #endif
15
16 #include <asm/irq.h>
17 #include <asm/traps.h>
18 #include <asm/amigahw.h>
19 #include <asm/amigaints.h>
20 #include <asm/amipcmcia.h>
21
22
23 /*
24  * Enable/disable a particular machine specific interrupt source.
25  * Note that this may affect other interrupts in case of a shared interrupt.
26  * This function should only be called for a _very_ short time to change some
27  * internal data, that may not be changed by the interrupt at the same time.
28  */
29
30 static void amiga_irq_enable(struct irq_data *data)
31 {
32         amiga_custom.intena = IF_SETCLR | (1 << (data->irq - IRQ_USER));
33 }
34
35 static void amiga_irq_disable(struct irq_data *data)
36 {
37         amiga_custom.intena = 1 << (data->irq - IRQ_USER);
38 }
39
40 static struct irq_chip amiga_irq_chip = {
41         .name           = "amiga",
42         .irq_enable     = amiga_irq_enable,
43         .irq_disable    = amiga_irq_disable,
44 };
45
46
47 /*
48  * The builtin Amiga hardware interrupt handlers.
49  */
50
51 #ifdef CONFIG_GENERIC_HARDIRQS
52 static void ami_int1(unsigned int irq, struct irq_desc *desc)
53 {
54         unsigned short ints = amiga_custom.intreqr & amiga_custom.intenar;
55
56         /* if serial transmit buffer empty, interrupt */
57         if (ints & IF_TBE) {
58                 amiga_custom.intreq = IF_TBE;
59                 generic_handle_irq(IRQ_AMIGA_TBE);
60         }
61
62         /* if floppy disk transfer complete, interrupt */
63         if (ints & IF_DSKBLK) {
64                 amiga_custom.intreq = IF_DSKBLK;
65                 generic_handle_irq(IRQ_AMIGA_DSKBLK);
66         }
67
68         /* if software interrupt set, interrupt */
69         if (ints & IF_SOFT) {
70                 amiga_custom.intreq = IF_SOFT;
71                 generic_handle_irq(IRQ_AMIGA_SOFT);
72         }
73 }
74
75 static void ami_int3(unsigned int irq, struct irq_desc *desc)
76 {
77         unsigned short ints = amiga_custom.intreqr & amiga_custom.intenar;
78
79         /* if a blitter interrupt */
80         if (ints & IF_BLIT) {
81                 amiga_custom.intreq = IF_BLIT;
82                 generic_handle_irq(IRQ_AMIGA_BLIT);
83         }
84
85         /* if a copper interrupt */
86         if (ints & IF_COPER) {
87                 amiga_custom.intreq = IF_COPER;
88                 generic_handle_irq(IRQ_AMIGA_COPPER);
89         }
90
91         /* if a vertical blank interrupt */
92         if (ints & IF_VERTB) {
93                 amiga_custom.intreq = IF_VERTB;
94                 generic_handle_irq(IRQ_AMIGA_VERTB);
95         }
96 }
97
98 static void ami_int4(unsigned int irq, struct irq_desc *desc)
99 {
100         unsigned short ints = amiga_custom.intreqr & amiga_custom.intenar;
101
102         /* if audio 0 interrupt */
103         if (ints & IF_AUD0) {
104                 amiga_custom.intreq = IF_AUD0;
105                 generic_handle_irq(IRQ_AMIGA_AUD0);
106         }
107
108         /* if audio 1 interrupt */
109         if (ints & IF_AUD1) {
110                 amiga_custom.intreq = IF_AUD1;
111                 generic_handle_irq(IRQ_AMIGA_AUD1);
112         }
113
114         /* if audio 2 interrupt */
115         if (ints & IF_AUD2) {
116                 amiga_custom.intreq = IF_AUD2;
117                 generic_handle_irq(IRQ_AMIGA_AUD2);
118         }
119
120         /* if audio 3 interrupt */
121         if (ints & IF_AUD3) {
122                 amiga_custom.intreq = IF_AUD3;
123                 generic_handle_irq(IRQ_AMIGA_AUD3);
124         }
125 }
126
127 static void ami_int5(unsigned int irq, struct irq_desc *desc)
128 {
129         unsigned short ints = amiga_custom.intreqr & amiga_custom.intenar;
130
131         /* if serial receive buffer full interrupt */
132         if (ints & IF_RBF) {
133                 /* acknowledge of IF_RBF must be done by the serial interrupt */
134                 generic_handle_irq(IRQ_AMIGA_RBF);
135         }
136
137         /* if a disk sync interrupt */
138         if (ints & IF_DSKSYN) {
139                 amiga_custom.intreq = IF_DSKSYN;
140                 generic_handle_irq(IRQ_AMIGA_DSKSYN);
141         }
142 }
143 #else /* !CONFIG_GENERIC_HARDIRQS */
144 static irqreturn_t ami_int1(int irq, void *dev_id)
145 {
146         unsigned short ints = amiga_custom.intreqr & amiga_custom.intenar;
147
148         /* if serial transmit buffer empty, interrupt */
149         if (ints & IF_TBE) {
150                 amiga_custom.intreq = IF_TBE;
151                 generic_handle_irq(IRQ_AMIGA_TBE);
152         }
153
154         /* if floppy disk transfer complete, interrupt */
155         if (ints & IF_DSKBLK) {
156                 amiga_custom.intreq = IF_DSKBLK;
157                 generic_handle_irq(IRQ_AMIGA_DSKBLK);
158         }
159
160         /* if software interrupt set, interrupt */
161         if (ints & IF_SOFT) {
162                 amiga_custom.intreq = IF_SOFT;
163                 generic_handle_irq(IRQ_AMIGA_SOFT);
164         }
165         return IRQ_HANDLED;
166 }
167
168 static irqreturn_t ami_int3(int irq, void *dev_id)
169 {
170         unsigned short ints = amiga_custom.intreqr & amiga_custom.intenar;
171
172         /* if a blitter interrupt */
173         if (ints & IF_BLIT) {
174                 amiga_custom.intreq = IF_BLIT;
175                 generic_handle_irq(IRQ_AMIGA_BLIT);
176         }
177
178         /* if a copper interrupt */
179         if (ints & IF_COPER) {
180                 amiga_custom.intreq = IF_COPER;
181                 generic_handle_irq(IRQ_AMIGA_COPPER);
182         }
183
184         /* if a vertical blank interrupt */
185         if (ints & IF_VERTB) {
186                 amiga_custom.intreq = IF_VERTB;
187                 generic_handle_irq(IRQ_AMIGA_VERTB);
188         }
189         return IRQ_HANDLED;
190 }
191
192 static irqreturn_t ami_int4(int irq, void *dev_id)
193 {
194         unsigned short ints = amiga_custom.intreqr & amiga_custom.intenar;
195
196         /* if audio 0 interrupt */
197         if (ints & IF_AUD0) {
198                 amiga_custom.intreq = IF_AUD0;
199                 generic_handle_irq(IRQ_AMIGA_AUD0);
200         }
201
202         /* if audio 1 interrupt */
203         if (ints & IF_AUD1) {
204                 amiga_custom.intreq = IF_AUD1;
205                 generic_handle_irq(IRQ_AMIGA_AUD1);
206         }
207
208         /* if audio 2 interrupt */
209         if (ints & IF_AUD2) {
210                 amiga_custom.intreq = IF_AUD2;
211                 generic_handle_irq(IRQ_AMIGA_AUD2);
212         }
213
214         /* if audio 3 interrupt */
215         if (ints & IF_AUD3) {
216                 amiga_custom.intreq = IF_AUD3;
217                 generic_handle_irq(IRQ_AMIGA_AUD3);
218         }
219         return IRQ_HANDLED;
220 }
221
222 static irqreturn_t ami_int5(int irq, void *dev_id)
223 {
224         unsigned short ints = amiga_custom.intreqr & amiga_custom.intenar;
225
226         /* if serial receive buffer full interrupt */
227         if (ints & IF_RBF) {
228                 /* acknowledge of IF_RBF must be done by the serial interrupt */
229                 generic_handle_irq(IRQ_AMIGA_RBF);
230         }
231
232         /* if a disk sync interrupt */
233         if (ints & IF_DSKSYN) {
234                 amiga_custom.intreq = IF_DSKSYN;
235                 generic_handle_irq(IRQ_AMIGA_DSKSYN);
236         }
237         return IRQ_HANDLED;
238 }
239 #endif /* !CONFIG_GENERIC_HARDIRQS */
240
241
242 /*
243  * void amiga_init_IRQ(void)
244  *
245  * Parameters:  None
246  *
247  * Returns:     Nothing
248  *
249  * This function should be called during kernel startup to initialize
250  * the amiga IRQ handling routines.
251  */
252
253 void __init amiga_init_IRQ(void)
254 {
255 #ifdef CONFIG_GENERIC_HARDIRQS
256         m68k_setup_irq_controller(&amiga_irq_chip, handle_simple_irq, IRQ_USER,
257                                   AMI_STD_IRQS);
258
259         irq_set_chained_handler(IRQ_AUTO_1, ami_int1);
260         irq_set_chained_handler(IRQ_AUTO_3, ami_int3);
261         irq_set_chained_handler(IRQ_AUTO_4, ami_int4);
262         irq_set_chained_handler(IRQ_AUTO_5, ami_int5);
263 #else /* !CONFIG_GENERIC_HARDIRQS */
264         if (request_irq(IRQ_AUTO_1, ami_int1, 0, "int1", NULL))
265                 pr_err("Couldn't register int%d\n", 1);
266         if (request_irq(IRQ_AUTO_3, ami_int3, 0, "int3", NULL))
267                 pr_err("Couldn't register int%d\n", 3);
268         if (request_irq(IRQ_AUTO_4, ami_int4, 0, "int4", NULL))
269                 pr_err("Couldn't register int%d\n", 4);
270         if (request_irq(IRQ_AUTO_5, ami_int5, 0, "int5", NULL))
271                 pr_err("Couldn't register int%d\n", 5);
272
273         m68k_setup_irq_controller(&amiga_irq_chip, handle_simple_irq, IRQ_USER,
274                                   AMI_STD_IRQS);
275 #endif /* !CONFIG_GENERIC_HARDIRQS */
276
277         /* turn off PCMCIA interrupts */
278         if (AMIGAHW_PRESENT(PCMCIA))
279                 gayle.inten = GAYLE_IRQ_IDE;
280
281         /* turn off all interrupts and enable the master interrupt bit */
282         amiga_custom.intena = 0x7fff;
283         amiga_custom.intreq = 0x7fff;
284         amiga_custom.intena = IF_SETCLR | IF_INTEN;
285
286         cia_init_IRQ(&ciaa_base);
287         cia_init_IRQ(&ciab_base);
288 }