1*4882a593Smuzhiyun /*
2*4882a593Smuzhiyun * Amiga Linux interrupt handling code
3*4882a593Smuzhiyun *
4*4882a593Smuzhiyun * This file is subject to the terms and conditions of the GNU General Public
5*4882a593Smuzhiyun * License. See the file COPYING in the main directory of this archive
6*4882a593Smuzhiyun * for more details.
7*4882a593Smuzhiyun */
8*4882a593Smuzhiyun
9*4882a593Smuzhiyun #include <linux/init.h>
10*4882a593Smuzhiyun #include <linux/interrupt.h>
11*4882a593Smuzhiyun #include <linux/errno.h>
12*4882a593Smuzhiyun #include <linux/irq.h>
13*4882a593Smuzhiyun
14*4882a593Smuzhiyun #include <asm/irq.h>
15*4882a593Smuzhiyun #include <asm/traps.h>
16*4882a593Smuzhiyun #include <asm/amigahw.h>
17*4882a593Smuzhiyun #include <asm/amigaints.h>
18*4882a593Smuzhiyun #include <asm/amipcmcia.h>
19*4882a593Smuzhiyun
20*4882a593Smuzhiyun
21*4882a593Smuzhiyun /*
22*4882a593Smuzhiyun * Enable/disable a particular machine specific interrupt source.
23*4882a593Smuzhiyun * Note that this may affect other interrupts in case of a shared interrupt.
24*4882a593Smuzhiyun * This function should only be called for a _very_ short time to change some
25*4882a593Smuzhiyun * internal data, that may not be changed by the interrupt at the same time.
26*4882a593Smuzhiyun */
27*4882a593Smuzhiyun
amiga_irq_enable(struct irq_data * data)28*4882a593Smuzhiyun static void amiga_irq_enable(struct irq_data *data)
29*4882a593Smuzhiyun {
30*4882a593Smuzhiyun amiga_custom.intena = IF_SETCLR | (1 << (data->irq - IRQ_USER));
31*4882a593Smuzhiyun }
32*4882a593Smuzhiyun
amiga_irq_disable(struct irq_data * data)33*4882a593Smuzhiyun static void amiga_irq_disable(struct irq_data *data)
34*4882a593Smuzhiyun {
35*4882a593Smuzhiyun amiga_custom.intena = 1 << (data->irq - IRQ_USER);
36*4882a593Smuzhiyun }
37*4882a593Smuzhiyun
38*4882a593Smuzhiyun static struct irq_chip amiga_irq_chip = {
39*4882a593Smuzhiyun .name = "amiga",
40*4882a593Smuzhiyun .irq_enable = amiga_irq_enable,
41*4882a593Smuzhiyun .irq_disable = amiga_irq_disable,
42*4882a593Smuzhiyun };
43*4882a593Smuzhiyun
44*4882a593Smuzhiyun
45*4882a593Smuzhiyun /*
46*4882a593Smuzhiyun * The builtin Amiga hardware interrupt handlers.
47*4882a593Smuzhiyun */
48*4882a593Smuzhiyun
ami_int1(struct irq_desc * desc)49*4882a593Smuzhiyun static void ami_int1(struct irq_desc *desc)
50*4882a593Smuzhiyun {
51*4882a593Smuzhiyun unsigned short ints = amiga_custom.intreqr & amiga_custom.intenar;
52*4882a593Smuzhiyun
53*4882a593Smuzhiyun /* if serial transmit buffer empty, interrupt */
54*4882a593Smuzhiyun if (ints & IF_TBE) {
55*4882a593Smuzhiyun amiga_custom.intreq = IF_TBE;
56*4882a593Smuzhiyun generic_handle_irq(IRQ_AMIGA_TBE);
57*4882a593Smuzhiyun }
58*4882a593Smuzhiyun
59*4882a593Smuzhiyun /* if floppy disk transfer complete, interrupt */
60*4882a593Smuzhiyun if (ints & IF_DSKBLK) {
61*4882a593Smuzhiyun amiga_custom.intreq = IF_DSKBLK;
62*4882a593Smuzhiyun generic_handle_irq(IRQ_AMIGA_DSKBLK);
63*4882a593Smuzhiyun }
64*4882a593Smuzhiyun
65*4882a593Smuzhiyun /* if software interrupt set, interrupt */
66*4882a593Smuzhiyun if (ints & IF_SOFT) {
67*4882a593Smuzhiyun amiga_custom.intreq = IF_SOFT;
68*4882a593Smuzhiyun generic_handle_irq(IRQ_AMIGA_SOFT);
69*4882a593Smuzhiyun }
70*4882a593Smuzhiyun }
71*4882a593Smuzhiyun
ami_int3(struct irq_desc * desc)72*4882a593Smuzhiyun static void ami_int3(struct irq_desc *desc)
73*4882a593Smuzhiyun {
74*4882a593Smuzhiyun unsigned short ints = amiga_custom.intreqr & amiga_custom.intenar;
75*4882a593Smuzhiyun
76*4882a593Smuzhiyun /* if a blitter interrupt */
77*4882a593Smuzhiyun if (ints & IF_BLIT) {
78*4882a593Smuzhiyun amiga_custom.intreq = IF_BLIT;
79*4882a593Smuzhiyun generic_handle_irq(IRQ_AMIGA_BLIT);
80*4882a593Smuzhiyun }
81*4882a593Smuzhiyun
82*4882a593Smuzhiyun /* if a copper interrupt */
83*4882a593Smuzhiyun if (ints & IF_COPER) {
84*4882a593Smuzhiyun amiga_custom.intreq = IF_COPER;
85*4882a593Smuzhiyun generic_handle_irq(IRQ_AMIGA_COPPER);
86*4882a593Smuzhiyun }
87*4882a593Smuzhiyun
88*4882a593Smuzhiyun /* if a vertical blank interrupt */
89*4882a593Smuzhiyun if (ints & IF_VERTB) {
90*4882a593Smuzhiyun amiga_custom.intreq = IF_VERTB;
91*4882a593Smuzhiyun generic_handle_irq(IRQ_AMIGA_VERTB);
92*4882a593Smuzhiyun }
93*4882a593Smuzhiyun }
94*4882a593Smuzhiyun
ami_int4(struct irq_desc * desc)95*4882a593Smuzhiyun static void ami_int4(struct irq_desc *desc)
96*4882a593Smuzhiyun {
97*4882a593Smuzhiyun unsigned short ints = amiga_custom.intreqr & amiga_custom.intenar;
98*4882a593Smuzhiyun
99*4882a593Smuzhiyun /* if audio 0 interrupt */
100*4882a593Smuzhiyun if (ints & IF_AUD0) {
101*4882a593Smuzhiyun amiga_custom.intreq = IF_AUD0;
102*4882a593Smuzhiyun generic_handle_irq(IRQ_AMIGA_AUD0);
103*4882a593Smuzhiyun }
104*4882a593Smuzhiyun
105*4882a593Smuzhiyun /* if audio 1 interrupt */
106*4882a593Smuzhiyun if (ints & IF_AUD1) {
107*4882a593Smuzhiyun amiga_custom.intreq = IF_AUD1;
108*4882a593Smuzhiyun generic_handle_irq(IRQ_AMIGA_AUD1);
109*4882a593Smuzhiyun }
110*4882a593Smuzhiyun
111*4882a593Smuzhiyun /* if audio 2 interrupt */
112*4882a593Smuzhiyun if (ints & IF_AUD2) {
113*4882a593Smuzhiyun amiga_custom.intreq = IF_AUD2;
114*4882a593Smuzhiyun generic_handle_irq(IRQ_AMIGA_AUD2);
115*4882a593Smuzhiyun }
116*4882a593Smuzhiyun
117*4882a593Smuzhiyun /* if audio 3 interrupt */
118*4882a593Smuzhiyun if (ints & IF_AUD3) {
119*4882a593Smuzhiyun amiga_custom.intreq = IF_AUD3;
120*4882a593Smuzhiyun generic_handle_irq(IRQ_AMIGA_AUD3);
121*4882a593Smuzhiyun }
122*4882a593Smuzhiyun }
123*4882a593Smuzhiyun
ami_int5(struct irq_desc * desc)124*4882a593Smuzhiyun static void ami_int5(struct irq_desc *desc)
125*4882a593Smuzhiyun {
126*4882a593Smuzhiyun unsigned short ints = amiga_custom.intreqr & amiga_custom.intenar;
127*4882a593Smuzhiyun
128*4882a593Smuzhiyun /* if serial receive buffer full interrupt */
129*4882a593Smuzhiyun if (ints & IF_RBF) {
130*4882a593Smuzhiyun /* acknowledge of IF_RBF must be done by the serial interrupt */
131*4882a593Smuzhiyun generic_handle_irq(IRQ_AMIGA_RBF);
132*4882a593Smuzhiyun }
133*4882a593Smuzhiyun
134*4882a593Smuzhiyun /* if a disk sync interrupt */
135*4882a593Smuzhiyun if (ints & IF_DSKSYN) {
136*4882a593Smuzhiyun amiga_custom.intreq = IF_DSKSYN;
137*4882a593Smuzhiyun generic_handle_irq(IRQ_AMIGA_DSKSYN);
138*4882a593Smuzhiyun }
139*4882a593Smuzhiyun }
140*4882a593Smuzhiyun
141*4882a593Smuzhiyun
142*4882a593Smuzhiyun /*
143*4882a593Smuzhiyun * void amiga_init_IRQ(void)
144*4882a593Smuzhiyun *
145*4882a593Smuzhiyun * Parameters: None
146*4882a593Smuzhiyun *
147*4882a593Smuzhiyun * Returns: Nothing
148*4882a593Smuzhiyun *
149*4882a593Smuzhiyun * This function should be called during kernel startup to initialize
150*4882a593Smuzhiyun * the amiga IRQ handling routines.
151*4882a593Smuzhiyun */
152*4882a593Smuzhiyun
amiga_init_IRQ(void)153*4882a593Smuzhiyun void __init amiga_init_IRQ(void)
154*4882a593Smuzhiyun {
155*4882a593Smuzhiyun m68k_setup_irq_controller(&amiga_irq_chip, handle_simple_irq, IRQ_USER,
156*4882a593Smuzhiyun AMI_STD_IRQS);
157*4882a593Smuzhiyun
158*4882a593Smuzhiyun irq_set_chained_handler(IRQ_AUTO_1, ami_int1);
159*4882a593Smuzhiyun irq_set_chained_handler(IRQ_AUTO_3, ami_int3);
160*4882a593Smuzhiyun irq_set_chained_handler(IRQ_AUTO_4, ami_int4);
161*4882a593Smuzhiyun irq_set_chained_handler(IRQ_AUTO_5, ami_int5);
162*4882a593Smuzhiyun
163*4882a593Smuzhiyun /* turn off PCMCIA interrupts */
164*4882a593Smuzhiyun if (AMIGAHW_PRESENT(PCMCIA))
165*4882a593Smuzhiyun gayle.inten = GAYLE_IRQ_IDE;
166*4882a593Smuzhiyun
167*4882a593Smuzhiyun /* turn off all interrupts and enable the master interrupt bit */
168*4882a593Smuzhiyun amiga_custom.intena = 0x7fff;
169*4882a593Smuzhiyun amiga_custom.intreq = 0x7fff;
170*4882a593Smuzhiyun amiga_custom.intena = IF_SETCLR | IF_INTEN;
171*4882a593Smuzhiyun
172*4882a593Smuzhiyun cia_init_IRQ(&ciaa_base);
173*4882a593Smuzhiyun cia_init_IRQ(&ciab_base);
174*4882a593Smuzhiyun }
175