1/*
2 * IRQ vector handles
3 *
4 * This file is subject to the terms and conditions of the GNU General Public
5 * License.  See the file "COPYING" in the main directory of this archive
6 * for more details.
7 *
8 * Copyright (C) 1995, 1996, 1997 by Ralf Baechle
9 * Copyright (C) 2001 by Liam Davies (ldavies@agile.tv)
10 *
11 */
12
13#include <linux/kernel.h>
14#include <linux/init.h>
15#include <linux/spinlock.h>
16#include <linux/interrupt.h>
17#include <linux/ioport.h>
18
19#include <asm/bootinfo.h>
20#include <asm/io.h>
21#include <asm/irq.h>
22#include <asm/mipsregs.h>
23#include <asm/system.h>
24
25#include <asm/cobalt/cobalt.h>
26
27/* Cobalt Exception handler */
28extern void cobalt_handle_int(void);
29
30/* Via masking routines */
31extern void unmask_irq(unsigned int irqr);
32extern void mask_irq(unsigned int irq);
33
34
35/*
36 * We have two types of interrupts that we handle, ones that come
37 *  in through the CPU interrupt lines, and ones that come in on
38 *  the via chip. The CPU mappings are:
39 *    0,1 - S/W (ignored)
40 *    2   - Galileo chip (timer)
41 *    3   - Tulip 0 + NCR SCSI
42 *    4   - Tulip 1
43 *    5   - 16550 UART
44 *    6   - VIA southbridge PIC
45 *    7   - unused
46 *
47 * The VIA chip is a master/slave 8259 setup and has the
48 *  following interrupts
49 *    8   - RTC
50 *    9   - PCI
51 *    14  - IDE0
52 *    15  - IDE1
53 *
54 * In the table we use a 1 to indicate that we use a VIA interrupt
55 *  line, and IE_IRQx to indicate that we use a CPU interrupt line
56 *
57 * We map all of these onto linux IRQ #s 0-15 and forget the rest
58 */
59#define NOINT_LINE	0
60#define CPUINT_LINE(x)	IE_IRQ##x
61#define VIAINT_LINE	1
62
63#define COBALT_IRQS	16
64
65static unsigned short irqnr_to_type[COBALT_IRQS] =
66{ CPUINT_LINE(0),  NOINT_LINE,      VIAINT_LINE,  NOINT_LINE,
67  CPUINT_LINE(1),  NOINT_LINE,      NOINT_LINE,   CPUINT_LINE(3),
68  VIAINT_LINE,     VIAINT_LINE,     NOINT_LINE,   NOINT_LINE,
69  NOINT_LINE,      CPUINT_LINE(2),  VIAINT_LINE,  VIAINT_LINE };
70
71/*
72 * Cobalt CPU irq
73 */
74
75static void enable_cpu_irq(unsigned int irq)
76{
77	unsigned long flags;
78
79	save_and_cli(flags);
80	change_c0_status(irqnr_to_type[irq], irqnr_to_type[irq]);
81	restore_flags(flags);
82}
83
84static unsigned startup_cpu_irq(unsigned int irq)
85{
86	enable_cpu_irq(irq);
87
88	return 0;
89}
90
91static void disable_cpu_irq(unsigned int irq)
92{
93	unsigned long flags;
94
95	save_and_cli(flags);
96	change_c0_status(irqnr_to_type[irq], ~(irqnr_to_type[irq]));
97	restore_flags(flags);
98}
99
100#define shutdown_cpu_irq	disable_cpu_irq
101#define mask_and_ack_cpu_irq	disable_cpu_irq
102
103static void end_cpu_irq(unsigned int irq)
104{
105	if (!(irq_desc[irq].status & (IRQ_DISABLED|IRQ_INPROGRESS)))
106		enable_cpu_irq(irq);
107}
108
109static struct hw_interrupt_type cobalt_cpu_irq_type = {
110	"Cobalt CPU",
111	startup_cpu_irq,
112	shutdown_cpu_irq,
113	enable_cpu_irq,
114	disable_cpu_irq,
115	mask_and_ack_cpu_irq,
116	end_cpu_irq,
117	NULL
118};
119
120void __init init_IRQ(void)
121{
122	int i;
123
124	/* Initialise all of the IRQ descriptors */
125	init_i8259_irqs();
126
127	/* Map the irqnr to the type int we have */
128	for (i=0; i < COBALT_IRQS; i++) {
129		if (irqnr_to_type[i] >= CPUINT_LINE(0))
130			/* cobalt_cpu_irq_type */
131			irq_desc[i].handler = &cobalt_cpu_irq_type;
132	}
133
134	/* Mask all cpu interrupts
135	    (except IE4, we already masked those at VIA level) */
136	clear_c0_status(ST0_IM);
137	set_c0_status(IE_IRQ4);
138
139	cli();
140
141	set_except_vector(0, cobalt_handle_int);
142}
143