diff options
Diffstat (limited to 'arch/ppc/platforms/adir_pic.c')
-rw-r--r-- | arch/ppc/platforms/adir_pic.c | 130 |
1 files changed, 130 insertions, 0 deletions
diff --git a/arch/ppc/platforms/adir_pic.c b/arch/ppc/platforms/adir_pic.c new file mode 100644 index 00000000000..9947cba52af --- /dev/null +++ b/arch/ppc/platforms/adir_pic.c @@ -0,0 +1,130 @@ +/* + * arch/ppc/platforms/adir_pic.c + * + * Interrupt controller support for SBS Adirondack + * + * By Michael Sokolov <msokolov@ivan.Harhan.ORG> + * based on the K2 and SCM versions by Matt Porter <mporter@mvista.com> + */ + +#include <linux/stddef.h> +#include <linux/init.h> +#include <linux/sched.h> +#include <linux/pci.h> +#include <linux/interrupt.h> + +#include <asm/io.h> +#include <asm/i8259.h> +#include "adir.h" + +static void adir_onboard_pic_enable(unsigned int irq); +static void adir_onboard_pic_disable(unsigned int irq); + +__init static void +adir_onboard_pic_init(void) +{ + volatile u_short *maskreg = (volatile u_short *) ADIR_PROCA_INT_MASK; + + /* Disable all Adirondack onboard interrupts */ + out_be16(maskreg, 0xFFFF); +} + +static int +adir_onboard_pic_get_irq(void) +{ + volatile u_short *statreg = (volatile u_short *) ADIR_PROCA_INT_STAT; + int irq; + u_short int_status, int_test; + + int_status = in_be16(statreg); + for (irq = 0, int_test = 1; irq < 16; irq++, int_test <<= 1) { + if (int_status & int_test) + break; + } + + if (irq == 16) + return -1; + + return (irq+16); +} + +static void +adir_onboard_pic_enable(unsigned int irq) +{ + volatile u_short *maskreg = (volatile u_short *) ADIR_PROCA_INT_MASK; + + /* Change irq to Adirondack onboard native value */ + irq -= 16; + + /* Enable requested irq number */ + out_be16(maskreg, in_be16(maskreg) & ~(1 << irq)); +} + +static void +adir_onboard_pic_disable(unsigned int irq) +{ + volatile u_short *maskreg = (volatile u_short *) ADIR_PROCA_INT_MASK; + + /* Change irq to Adirondack onboard native value */ + irq -= 16; + + /* Disable requested irq number */ + out_be16(maskreg, in_be16(maskreg) | (1 << irq)); +} + +static struct hw_interrupt_type adir_onboard_pic = { + " ADIR PIC ", + NULL, + NULL, + adir_onboard_pic_enable, /* unmask */ + adir_onboard_pic_disable, /* mask */ + adir_onboard_pic_disable, /* mask and ack */ + NULL, + NULL +}; + +static struct irqaction noop_action = { + .handler = no_action, + .flags = SA_INTERRUPT, + .mask = CPU_MASK_NONE, + .name = "82c59 primary cascade", +}; + +/* + * Linux interrupt values are assigned as follows: + * + * 0-15 VT82C686 8259 interrupts + * 16-31 Adirondack CPLD interrupts + */ +__init void +adir_init_IRQ(void) +{ + int i; + + /* Initialize the cascaded 8259's on the VT82C686 */ + for (i=0; i<16; i++) + irq_desc[i].handler = &i8259_pic; + i8259_init(NULL); + + /* Initialize Adirondack CPLD PIC and enable 8259 interrupt cascade */ + for (i=16; i<32; i++) + irq_desc[i].handler = &adir_onboard_pic; + adir_onboard_pic_init(); + + /* Enable 8259 interrupt cascade */ + setup_irq(ADIR_IRQ_VT82C686_INTR, &noop_action); +} + +int +adir_get_irq(struct pt_regs *regs) +{ + int irq; + + if ((irq = adir_onboard_pic_get_irq()) < 0) + return irq; + + if (irq == ADIR_IRQ_VT82C686_INTR) + irq = i8259_irq(regs); + + return irq; +} |