summaryrefslogtreecommitdiffstats
path: root/arch/ppc/platforms/adir_pic.c
diff options
context:
space:
mode:
Diffstat (limited to 'arch/ppc/platforms/adir_pic.c')
-rw-r--r--arch/ppc/platforms/adir_pic.c130
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;
+}