/*
* IRQ vector handles
*
* This file is subject to the terms and conditions of the GNU General Public
* License. See the file "COPYING" in the main directory of this archive
* for more details.
*
* Copyright (C) 1995, 1996, 1997 by Ralf Baechle
* Copyright (C) 2001 by Liam Davies (ldavies@agile.tv)
*
*/
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/spinlock.h>
#include <linux/interrupt.h>
#include <linux/ioport.h>
#include <asm/bootinfo.h>
#include <asm/i8259.h>
#include <asm/io.h>
#include <asm/irq.h>
#include <asm/mipsregs.h>
#include <asm/system.h>
#include <asm/cobalt/cobalt.h>
/* Cobalt Exception handler */
extern void cobalt_handle_int(void);
/* Via masking routines */
extern void unmask_irq(unsigned int irqr);
extern void mask_irq(unsigned int irq);
/*
* We have two types of interrupts that we handle, ones that come
* in through the CPU interrupt lines, and ones that come in on
* the via chip. The CPU mappings are:
* 0,1 - S/W (ignored)
* 2 - Galileo chip (timer)
* 3 - Tulip 0 + NCR SCSI
* 4 - Tulip 1
* 5 - 16550 UART
* 6 - VIA southbridge PIC
* 7 - unused
*
* The VIA chip is a master/slave 8259 setup and has the
* following interrupts
* 8 - RTC
* 9 - PCI
* 14 - IDE0
* 15 - IDE1
*
* In the table we use a 1 to indicate that we use a VIA interrupt
* line, and IE_IRQx to indicate that we use a CPU interrupt line
*
* We map all of these onto linux IRQ #s 0-15 and forget the rest
*/
#define NOINT_LINE 0
#define CPUINT_LINE(x) IE_IRQ##x
#define VIAINT_LINE 1
#define COBALT_IRQS 16
static unsigned short irqnr_to_type[COBALT_IRQS] =
{ CPUINT_LINE(0), NOINT_LINE, VIAINT_LINE, NOINT_LINE,
CPUINT_LINE(1), NOINT_LINE, NOINT_LINE, CPUINT_LINE(3),
VIAINT_LINE, VIAINT_LINE, NOINT_LINE, NOINT_LINE,
NOINT_LINE, CPUINT_LINE(2), VIAINT_LINE, VIAINT_LINE };
/*
* Cobalt CPU irq
*/
static void enable_cpu_irq(unsigned int irq)
{
unsigned long flags;
local_irq_save(flags);
change_c0_status(irqnr_to_type[irq], irqnr_to_type[irq]);
local_irq_restore(flags);
}
static unsigned startup_cpu_irq(unsigned int irq)
{
enable_cpu_irq(irq);
return 0;
}
static void disable_cpu_irq(unsigned int irq)
{
unsigned long flags;
local_irq_save(flags);
change_c0_status(irqnr_to_type[irq], ~(irqnr_to_type[irq]));
local_irq_restore(flags);
}
#define shutdown_cpu_irq disable_cpu_irq
#define mask_and_ack_cpu_irq disable_cpu_irq
static void end_cpu_irq(unsigned int irq)
{
if (!(irq_desc[irq].status & (IRQ_DISABLED|IRQ_INPROGRESS)))
enable_cpu_irq(irq);
}
static struct hw_interrupt_type cobalt_cpu_irq_type = {
"Cobalt CPU",
startup_cpu_irq,
shutdown_cpu_irq,
enable_cpu_irq,
disable_cpu_irq,
mask_and_ack_cpu_irq,
end_cpu_irq,
NULL
};
void __init init_IRQ(void)
{
int i;
/* Initialise all of the IRQ descriptors */
init_i8259_irqs();
/* Map the irqnr to the type int we have */
for (i=0; i < COBALT_IRQS; i++) {
if (irqnr_to_type[i] >= CPUINT_LINE(0))
/* cobalt_cpu_irq_type */
irq_desc[i].handler = &cobalt_cpu_irq_type;
}
/* Mask all cpu interrupts
(except IE4, we already masked those at VIA level) */
clear_c0_status(ST0_IM);
set_c0_status(IE_IRQ4);
cli();
set_except_vector(0, cobalt_handle_int);
}