131 lines
2.7 KiB
C
131 lines
2.7 KiB
C
|
/*
|
||
|
* 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;
|
||
|
}
|