blob: 9947cba52af55dd60b6512bffb9ca303481ddd30 [file] [log] [blame]
/*
* 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;
}