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