18c2ecf20Sopenharmony_ci/*
28c2ecf20Sopenharmony_ci * Amiga Linux interrupt handling code
38c2ecf20Sopenharmony_ci *
48c2ecf20Sopenharmony_ci * This file is subject to the terms and conditions of the GNU General Public
58c2ecf20Sopenharmony_ci * License.  See the file COPYING in the main directory of this archive
68c2ecf20Sopenharmony_ci * for more details.
78c2ecf20Sopenharmony_ci */
88c2ecf20Sopenharmony_ci
98c2ecf20Sopenharmony_ci#include <linux/init.h>
108c2ecf20Sopenharmony_ci#include <linux/interrupt.h>
118c2ecf20Sopenharmony_ci#include <linux/errno.h>
128c2ecf20Sopenharmony_ci#include <linux/irq.h>
138c2ecf20Sopenharmony_ci
148c2ecf20Sopenharmony_ci#include <asm/irq.h>
158c2ecf20Sopenharmony_ci#include <asm/traps.h>
168c2ecf20Sopenharmony_ci#include <asm/amigahw.h>
178c2ecf20Sopenharmony_ci#include <asm/amigaints.h>
188c2ecf20Sopenharmony_ci#include <asm/amipcmcia.h>
198c2ecf20Sopenharmony_ci
208c2ecf20Sopenharmony_ci
218c2ecf20Sopenharmony_ci/*
228c2ecf20Sopenharmony_ci * Enable/disable a particular machine specific interrupt source.
238c2ecf20Sopenharmony_ci * Note that this may affect other interrupts in case of a shared interrupt.
248c2ecf20Sopenharmony_ci * This function should only be called for a _very_ short time to change some
258c2ecf20Sopenharmony_ci * internal data, that may not be changed by the interrupt at the same time.
268c2ecf20Sopenharmony_ci */
278c2ecf20Sopenharmony_ci
288c2ecf20Sopenharmony_cistatic void amiga_irq_enable(struct irq_data *data)
298c2ecf20Sopenharmony_ci{
308c2ecf20Sopenharmony_ci	amiga_custom.intena = IF_SETCLR | (1 << (data->irq - IRQ_USER));
318c2ecf20Sopenharmony_ci}
328c2ecf20Sopenharmony_ci
338c2ecf20Sopenharmony_cistatic void amiga_irq_disable(struct irq_data *data)
348c2ecf20Sopenharmony_ci{
358c2ecf20Sopenharmony_ci	amiga_custom.intena = 1 << (data->irq - IRQ_USER);
368c2ecf20Sopenharmony_ci}
378c2ecf20Sopenharmony_ci
388c2ecf20Sopenharmony_cistatic struct irq_chip amiga_irq_chip = {
398c2ecf20Sopenharmony_ci	.name		= "amiga",
408c2ecf20Sopenharmony_ci	.irq_enable	= amiga_irq_enable,
418c2ecf20Sopenharmony_ci	.irq_disable	= amiga_irq_disable,
428c2ecf20Sopenharmony_ci};
438c2ecf20Sopenharmony_ci
448c2ecf20Sopenharmony_ci
458c2ecf20Sopenharmony_ci/*
468c2ecf20Sopenharmony_ci * The builtin Amiga hardware interrupt handlers.
478c2ecf20Sopenharmony_ci */
488c2ecf20Sopenharmony_ci
498c2ecf20Sopenharmony_cistatic void ami_int1(struct irq_desc *desc)
508c2ecf20Sopenharmony_ci{
518c2ecf20Sopenharmony_ci	unsigned short ints = amiga_custom.intreqr & amiga_custom.intenar;
528c2ecf20Sopenharmony_ci
538c2ecf20Sopenharmony_ci	/* if serial transmit buffer empty, interrupt */
548c2ecf20Sopenharmony_ci	if (ints & IF_TBE) {
558c2ecf20Sopenharmony_ci		amiga_custom.intreq = IF_TBE;
568c2ecf20Sopenharmony_ci		generic_handle_irq(IRQ_AMIGA_TBE);
578c2ecf20Sopenharmony_ci	}
588c2ecf20Sopenharmony_ci
598c2ecf20Sopenharmony_ci	/* if floppy disk transfer complete, interrupt */
608c2ecf20Sopenharmony_ci	if (ints & IF_DSKBLK) {
618c2ecf20Sopenharmony_ci		amiga_custom.intreq = IF_DSKBLK;
628c2ecf20Sopenharmony_ci		generic_handle_irq(IRQ_AMIGA_DSKBLK);
638c2ecf20Sopenharmony_ci	}
648c2ecf20Sopenharmony_ci
658c2ecf20Sopenharmony_ci	/* if software interrupt set, interrupt */
668c2ecf20Sopenharmony_ci	if (ints & IF_SOFT) {
678c2ecf20Sopenharmony_ci		amiga_custom.intreq = IF_SOFT;
688c2ecf20Sopenharmony_ci		generic_handle_irq(IRQ_AMIGA_SOFT);
698c2ecf20Sopenharmony_ci	}
708c2ecf20Sopenharmony_ci}
718c2ecf20Sopenharmony_ci
728c2ecf20Sopenharmony_cistatic void ami_int3(struct irq_desc *desc)
738c2ecf20Sopenharmony_ci{
748c2ecf20Sopenharmony_ci	unsigned short ints = amiga_custom.intreqr & amiga_custom.intenar;
758c2ecf20Sopenharmony_ci
768c2ecf20Sopenharmony_ci	/* if a blitter interrupt */
778c2ecf20Sopenharmony_ci	if (ints & IF_BLIT) {
788c2ecf20Sopenharmony_ci		amiga_custom.intreq = IF_BLIT;
798c2ecf20Sopenharmony_ci		generic_handle_irq(IRQ_AMIGA_BLIT);
808c2ecf20Sopenharmony_ci	}
818c2ecf20Sopenharmony_ci
828c2ecf20Sopenharmony_ci	/* if a copper interrupt */
838c2ecf20Sopenharmony_ci	if (ints & IF_COPER) {
848c2ecf20Sopenharmony_ci		amiga_custom.intreq = IF_COPER;
858c2ecf20Sopenharmony_ci		generic_handle_irq(IRQ_AMIGA_COPPER);
868c2ecf20Sopenharmony_ci	}
878c2ecf20Sopenharmony_ci
888c2ecf20Sopenharmony_ci	/* if a vertical blank interrupt */
898c2ecf20Sopenharmony_ci	if (ints & IF_VERTB) {
908c2ecf20Sopenharmony_ci		amiga_custom.intreq = IF_VERTB;
918c2ecf20Sopenharmony_ci		generic_handle_irq(IRQ_AMIGA_VERTB);
928c2ecf20Sopenharmony_ci	}
938c2ecf20Sopenharmony_ci}
948c2ecf20Sopenharmony_ci
958c2ecf20Sopenharmony_cistatic void ami_int4(struct irq_desc *desc)
968c2ecf20Sopenharmony_ci{
978c2ecf20Sopenharmony_ci	unsigned short ints = amiga_custom.intreqr & amiga_custom.intenar;
988c2ecf20Sopenharmony_ci
998c2ecf20Sopenharmony_ci	/* if audio 0 interrupt */
1008c2ecf20Sopenharmony_ci	if (ints & IF_AUD0) {
1018c2ecf20Sopenharmony_ci		amiga_custom.intreq = IF_AUD0;
1028c2ecf20Sopenharmony_ci		generic_handle_irq(IRQ_AMIGA_AUD0);
1038c2ecf20Sopenharmony_ci	}
1048c2ecf20Sopenharmony_ci
1058c2ecf20Sopenharmony_ci	/* if audio 1 interrupt */
1068c2ecf20Sopenharmony_ci	if (ints & IF_AUD1) {
1078c2ecf20Sopenharmony_ci		amiga_custom.intreq = IF_AUD1;
1088c2ecf20Sopenharmony_ci		generic_handle_irq(IRQ_AMIGA_AUD1);
1098c2ecf20Sopenharmony_ci	}
1108c2ecf20Sopenharmony_ci
1118c2ecf20Sopenharmony_ci	/* if audio 2 interrupt */
1128c2ecf20Sopenharmony_ci	if (ints & IF_AUD2) {
1138c2ecf20Sopenharmony_ci		amiga_custom.intreq = IF_AUD2;
1148c2ecf20Sopenharmony_ci		generic_handle_irq(IRQ_AMIGA_AUD2);
1158c2ecf20Sopenharmony_ci	}
1168c2ecf20Sopenharmony_ci
1178c2ecf20Sopenharmony_ci	/* if audio 3 interrupt */
1188c2ecf20Sopenharmony_ci	if (ints & IF_AUD3) {
1198c2ecf20Sopenharmony_ci		amiga_custom.intreq = IF_AUD3;
1208c2ecf20Sopenharmony_ci		generic_handle_irq(IRQ_AMIGA_AUD3);
1218c2ecf20Sopenharmony_ci	}
1228c2ecf20Sopenharmony_ci}
1238c2ecf20Sopenharmony_ci
1248c2ecf20Sopenharmony_cistatic void ami_int5(struct irq_desc *desc)
1258c2ecf20Sopenharmony_ci{
1268c2ecf20Sopenharmony_ci	unsigned short ints = amiga_custom.intreqr & amiga_custom.intenar;
1278c2ecf20Sopenharmony_ci
1288c2ecf20Sopenharmony_ci	/* if serial receive buffer full interrupt */
1298c2ecf20Sopenharmony_ci	if (ints & IF_RBF) {
1308c2ecf20Sopenharmony_ci		/* acknowledge of IF_RBF must be done by the serial interrupt */
1318c2ecf20Sopenharmony_ci		generic_handle_irq(IRQ_AMIGA_RBF);
1328c2ecf20Sopenharmony_ci	}
1338c2ecf20Sopenharmony_ci
1348c2ecf20Sopenharmony_ci	/* if a disk sync interrupt */
1358c2ecf20Sopenharmony_ci	if (ints & IF_DSKSYN) {
1368c2ecf20Sopenharmony_ci		amiga_custom.intreq = IF_DSKSYN;
1378c2ecf20Sopenharmony_ci		generic_handle_irq(IRQ_AMIGA_DSKSYN);
1388c2ecf20Sopenharmony_ci	}
1398c2ecf20Sopenharmony_ci}
1408c2ecf20Sopenharmony_ci
1418c2ecf20Sopenharmony_ci
1428c2ecf20Sopenharmony_ci/*
1438c2ecf20Sopenharmony_ci * void amiga_init_IRQ(void)
1448c2ecf20Sopenharmony_ci *
1458c2ecf20Sopenharmony_ci * Parameters:	None
1468c2ecf20Sopenharmony_ci *
1478c2ecf20Sopenharmony_ci * Returns:	Nothing
1488c2ecf20Sopenharmony_ci *
1498c2ecf20Sopenharmony_ci * This function should be called during kernel startup to initialize
1508c2ecf20Sopenharmony_ci * the amiga IRQ handling routines.
1518c2ecf20Sopenharmony_ci */
1528c2ecf20Sopenharmony_ci
1538c2ecf20Sopenharmony_civoid __init amiga_init_IRQ(void)
1548c2ecf20Sopenharmony_ci{
1558c2ecf20Sopenharmony_ci	m68k_setup_irq_controller(&amiga_irq_chip, handle_simple_irq, IRQ_USER,
1568c2ecf20Sopenharmony_ci				  AMI_STD_IRQS);
1578c2ecf20Sopenharmony_ci
1588c2ecf20Sopenharmony_ci	irq_set_chained_handler(IRQ_AUTO_1, ami_int1);
1598c2ecf20Sopenharmony_ci	irq_set_chained_handler(IRQ_AUTO_3, ami_int3);
1608c2ecf20Sopenharmony_ci	irq_set_chained_handler(IRQ_AUTO_4, ami_int4);
1618c2ecf20Sopenharmony_ci	irq_set_chained_handler(IRQ_AUTO_5, ami_int5);
1628c2ecf20Sopenharmony_ci
1638c2ecf20Sopenharmony_ci	/* turn off PCMCIA interrupts */
1648c2ecf20Sopenharmony_ci	if (AMIGAHW_PRESENT(PCMCIA))
1658c2ecf20Sopenharmony_ci		gayle.inten = GAYLE_IRQ_IDE;
1668c2ecf20Sopenharmony_ci
1678c2ecf20Sopenharmony_ci	/* turn off all interrupts and enable the master interrupt bit */
1688c2ecf20Sopenharmony_ci	amiga_custom.intena = 0x7fff;
1698c2ecf20Sopenharmony_ci	amiga_custom.intreq = 0x7fff;
1708c2ecf20Sopenharmony_ci	amiga_custom.intena = IF_SETCLR | IF_INTEN;
1718c2ecf20Sopenharmony_ci
1728c2ecf20Sopenharmony_ci	cia_init_IRQ(&ciaa_base);
1738c2ecf20Sopenharmony_ci	cia_init_IRQ(&ciab_base);
1748c2ecf20Sopenharmony_ci}
175