diff options
Diffstat (limited to 'arch/ppc/syslib/ppc403_pic.c')
-rw-r--r-- | arch/ppc/syslib/ppc403_pic.c | 127 |
1 files changed, 127 insertions, 0 deletions
diff --git a/arch/ppc/syslib/ppc403_pic.c b/arch/ppc/syslib/ppc403_pic.c new file mode 100644 index 00000000000..06cb0af2a58 --- /dev/null +++ b/arch/ppc/syslib/ppc403_pic.c @@ -0,0 +1,127 @@ +/* + * + * Copyright (c) 1999 Grant Erickson <grant@lcse.umn.edu> + * + * Module name: ppc403_pic.c + * + * Description: + * Interrupt controller driver for PowerPC 403-based processors. + */ + +/* + * The PowerPC 403 cores' Asynchronous Interrupt Controller (AIC) has + * 32 possible interrupts, a majority of which are not implemented on + * all cores. There are six configurable, external interrupt pins and + * there are eight internal interrupts for the on-chip serial port + * (SPU), DMA controller, and JTAG controller. + * + */ + +#include <linux/init.h> +#include <linux/sched.h> +#include <linux/signal.h> +#include <linux/stddef.h> + +#include <asm/processor.h> +#include <asm/system.h> +#include <asm/irq.h> +#include <asm/ppc4xx_pic.h> + +/* Function Prototypes */ + +static void ppc403_aic_enable(unsigned int irq); +static void ppc403_aic_disable(unsigned int irq); +static void ppc403_aic_disable_and_ack(unsigned int irq); + +static struct hw_interrupt_type ppc403_aic = { + "403GC AIC", + NULL, + NULL, + ppc403_aic_enable, + ppc403_aic_disable, + ppc403_aic_disable_and_ack, + 0 +}; + +int +ppc403_pic_get_irq(struct pt_regs *regs) +{ + int irq; + unsigned long bits; + + /* + * Only report the status of those interrupts that are actually + * enabled. + */ + + bits = mfdcr(DCRN_EXISR) & mfdcr(DCRN_EXIER); + + /* + * Walk through the interrupts from highest priority to lowest, and + * report the first pending interrupt found. + * We want PPC, not C bit numbering, so just subtract the ffs() + * result from 32. + */ + irq = 32 - ffs(bits); + + if (irq == NR_AIC_IRQS) + irq = -1; + + return (irq); +} + +static void +ppc403_aic_enable(unsigned int irq) +{ + int bit, word; + + bit = irq & 0x1f; + word = irq >> 5; + + ppc_cached_irq_mask[word] |= (1 << (31 - bit)); + mtdcr(DCRN_EXIER, ppc_cached_irq_mask[word]); +} + +static void +ppc403_aic_disable(unsigned int irq) +{ + int bit, word; + + bit = irq & 0x1f; + word = irq >> 5; + + ppc_cached_irq_mask[word] &= ~(1 << (31 - bit)); + mtdcr(DCRN_EXIER, ppc_cached_irq_mask[word]); +} + +static void +ppc403_aic_disable_and_ack(unsigned int irq) +{ + int bit, word; + + bit = irq & 0x1f; + word = irq >> 5; + + ppc_cached_irq_mask[word] &= ~(1 << (31 - bit)); + mtdcr(DCRN_EXIER, ppc_cached_irq_mask[word]); + mtdcr(DCRN_EXISR, (1 << (31 - bit))); +} + +void __init +ppc4xx_pic_init(void) +{ + int i; + + /* + * Disable all external interrupts until they are + * explicity requested. + */ + ppc_cached_irq_mask[0] = 0; + + mtdcr(DCRN_EXIER, ppc_cached_irq_mask[0]); + + ppc_md.get_irq = ppc403_pic_get_irq; + + for (i = 0; i < NR_IRQS; i++) + irq_desc[i].handler = &ppc403_aic; +} |