summaryrefslogtreecommitdiff
path: root/arch/mips/cobalt/irq.c
blob: 0b75f4fb719570ef4a8f29be227e8c1f3d5d00d0 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
/*
 * 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, 2003 by Ralf Baechle
 */
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/irq.h>
#include <linux/interrupt.h>
#include <linux/pci.h>

#include <asm/i8259.h>
#include <asm/irq_cpu.h>
#include <asm/gt64120.h>
#include <asm/ptrace.h>

#include <asm/mach-cobalt/cobalt.h>

/*
 * 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:
 *
 *    16   - Software interrupt 0 (unused)	IE_SW0
 *    17   - Software interrupt 1 (unused)	IE_SW1
 *    18   - Galileo chip (timer)		IE_IRQ0
 *    19   - Tulip 0 + NCR SCSI			IE_IRQ1
 *    20   - Tulip 1				IE_IRQ2
 *    21   - 16550 UART				IE_IRQ3
 *    22   - VIA southbridge PIC		IE_IRQ4
 *    23   - unused				IE_IRQ5
 *
 * The VIA chip is a master/slave 8259 setup and has the following interrupts:
 *
 *     8  - RTC
 *     9  - PCI
 *    14  - IDE0
 *    15  - IDE1
 */

static inline void galileo_irq(struct pt_regs *regs)
{
	unsigned int mask, pending, devfn;

	mask = GALILEO_INL(GT_INTRMASK_OFS);
	pending = GALILEO_INL(GT_INTRCAUSE_OFS) & mask;

	if (pending & GALILEO_INTR_T0EXP) {

		GALILEO_OUTL(~GALILEO_INTR_T0EXP, GT_INTRCAUSE_OFS);
		do_IRQ(COBALT_GALILEO_IRQ, regs);

	} else if (pending & GALILEO_INTR_RETRY_CTR) {

		devfn = GALILEO_INL(GT_PCI0_CFGADDR_OFS) >> 8;
		GALILEO_OUTL(~GALILEO_INTR_RETRY_CTR, GT_INTRCAUSE_OFS);
		printk(KERN_WARNING "Galileo: PCI retry count exceeded (%02x.%u)\n",
			PCI_SLOT(devfn), PCI_FUNC(devfn));

	} else {

		GALILEO_OUTL(mask & ~pending, GT_INTRMASK_OFS);
		printk(KERN_WARNING "Galileo: masking unexpected interrupt %08x\n", pending);
	}
}

static inline void via_pic_irq(struct pt_regs *regs)
{
	int irq;

	irq = i8259_irq();
	if (irq >= 0)
		do_IRQ(irq, regs);
}

asmlinkage void plat_irq_dispatch(struct pt_regs *regs)
{
	unsigned pending;

	pending = read_c0_status() & read_c0_cause();

	if (pending & CAUSEF_IP2)			/* COBALT_GALILEO_IRQ (18) */

		galileo_irq(regs);

	else if (pending & CAUSEF_IP6)			/* COBALT_VIA_IRQ (22) */

		via_pic_irq(regs);

	else if (pending & CAUSEF_IP3)			/* COBALT_ETH0_IRQ (19) */

		do_IRQ(COBALT_CPU_IRQ + 3, regs);

	else if (pending & CAUSEF_IP4)			/* COBALT_ETH1_IRQ (20) */

		do_IRQ(COBALT_CPU_IRQ + 4, regs);

	else if (pending & CAUSEF_IP5)			/* COBALT_SERIAL_IRQ (21) */

		do_IRQ(COBALT_CPU_IRQ + 5, regs);

	else if (pending & CAUSEF_IP7)			/* IRQ 23 */

		do_IRQ(COBALT_CPU_IRQ + 7, regs);
}

static struct irqaction irq_via = {
	no_action, 0, { { 0, } }, "cascade", NULL, NULL
};

void __init arch_init_irq(void)
{
	/*
	 * Mask all Galileo interrupts. The Galileo
	 * handler is set in cobalt_timer_setup()
	 */
	GALILEO_OUTL(0, GT_INTRMASK_OFS);

	init_i8259_irqs();				/*  0 ... 15 */
	mips_cpu_irq_init(COBALT_CPU_IRQ);		/* 16 ... 23 */

	/*
	 * Mask all cpu interrupts
	 *  (except IE4, we already masked those at VIA level)
	 */
	change_c0_status(ST0_IM, IE_IRQ4);

	setup_irq(COBALT_VIA_IRQ, &irq_via);
}