summaryrefslogtreecommitdiff
path: root/arch/mips/pmc-sierra/msp71xx/msp_irq.c
blob: d3c3d81757a538ea13ee3ab56942d1aeea00df3c (plain) (blame)
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
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
/*
 * IRQ vector handles
 *
 * Copyright (C) 1995, 1996, 1997, 2003 by Ralf Baechle
 *
 * 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.
 */

#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/irq.h>
#include <linux/interrupt.h>
#include <linux/ptrace.h>
#include <linux/time.h>

#include <asm/irq_cpu.h>

#include <msp_int.h>

/* SLP bases systems */
extern void msp_slp_irq_init(void);
extern void msp_slp_irq_dispatch(void);

/* CIC based systems */
extern void msp_cic_irq_init(void);
extern void msp_cic_irq_dispatch(void);

/* VSMP support init */
extern void msp_vsmp_int_init(void);

/* vectored interrupt implementation */

/* SW0/1 interrupts are used for SMP/SMTC */
static inline void mac0_int_dispatch(void) { do_IRQ(MSP_INT_MAC0); }
static inline void mac1_int_dispatch(void) { do_IRQ(MSP_INT_MAC1); }
static inline void mac2_int_dispatch(void) { do_IRQ(MSP_INT_SAR); }
static inline void usb_int_dispatch(void)  { do_IRQ(MSP_INT_USB);  }
static inline void sec_int_dispatch(void)  { do_IRQ(MSP_INT_SEC);  }

/*
 * The PMC-Sierra MSP interrupts are arranged in a 3 level cascaded
 * hierarchical system.  The first level are the direct MIPS interrupts
 * and are assigned the interrupt range 0-7.  The second level is the SLM
 * interrupt controller and is assigned the range 8-39.  The third level
 * comprises the Peripherial block, the PCI block, the PCI MSI block and
 * the SLP.  The PCI interrupts and the SLP errors are handled by the
 * relevant subsystems so the core interrupt code needs only concern
 * itself with the Peripheral block.  These are assigned interrupts in
 * the range 40-71.
 */

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

	pending = read_c0_status() & read_c0_cause();

	/*
	 * jump to the correct interrupt routine
	 * These are arranged in priority order and the timer
	 * comes first!
	 */

#ifdef CONFIG_IRQ_MSP_CIC	/* break out the CIC stuff for now */
	if (pending & C_IRQ4)	/* do the peripherals first, that's the timer */
		msp_cic_irq_dispatch();

	else if (pending & C_IRQ0)
		do_IRQ(MSP_INT_MAC0);

	else if (pending & C_IRQ1)
		do_IRQ(MSP_INT_MAC1);

	else if (pending & C_IRQ2)
		do_IRQ(MSP_INT_USB);

	else if (pending & C_IRQ3)
		do_IRQ(MSP_INT_SAR);

	else if (pending & C_IRQ5)
		do_IRQ(MSP_INT_SEC);

#else
	if (pending & C_IRQ5)
		do_IRQ(MSP_INT_TIMER);

	else if (pending & C_IRQ0)
		do_IRQ(MSP_INT_MAC0);

	else if (pending & C_IRQ1)
		do_IRQ(MSP_INT_MAC1);

	else if (pending & C_IRQ3)
		do_IRQ(MSP_INT_VE);

	else if (pending & C_IRQ4)
		msp_slp_irq_dispatch();
#endif

	else if (pending & C_SW0)	/* do software after hardware */
		do_IRQ(MSP_INT_SW0);

	else if (pending & C_SW1)
		do_IRQ(MSP_INT_SW1);
}

static struct irqaction cic_cascade_msp = {
	.handler = no_action,
	.name	 = "MSP CIC cascade",
	.flags	 = IRQF_NO_THREAD,
};

static struct irqaction per_cascade_msp = {
	.handler = no_action,
	.name	 = "MSP PER cascade",
	.flags	 = IRQF_NO_THREAD,
};

void __init arch_init_irq(void)
{
	/* assume we'll be using vectored interrupt mode except in UP mode*/
#ifdef CONFIG_MIPS_MT
	BUG_ON(!cpu_has_vint);
#endif
	/* initialize the 1st-level CPU based interrupt controller */
	mips_cpu_irq_init();

#ifdef CONFIG_IRQ_MSP_CIC
	msp_cic_irq_init();
#ifdef CONFIG_MIPS_MT
	set_vi_handler(MSP_INT_CIC, msp_cic_irq_dispatch);
	set_vi_handler(MSP_INT_MAC0, mac0_int_dispatch);
	set_vi_handler(MSP_INT_MAC1, mac1_int_dispatch);
	set_vi_handler(MSP_INT_SAR, mac2_int_dispatch);
	set_vi_handler(MSP_INT_USB, usb_int_dispatch);
	set_vi_handler(MSP_INT_SEC, sec_int_dispatch);
#ifdef CONFIG_MIPS_MT_SMP
	msp_vsmp_int_init();
#elif defined CONFIG_MIPS_MT_SMTC
	/*Set hwmask for all platform devices */
	irq_hwmask[MSP_INT_MAC0] = C_IRQ0;
	irq_hwmask[MSP_INT_MAC1] = C_IRQ1;
	irq_hwmask[MSP_INT_USB] = C_IRQ2;
	irq_hwmask[MSP_INT_SAR] = C_IRQ3;
	irq_hwmask[MSP_INT_SEC] = C_IRQ5;

#endif	/* CONFIG_MIPS_MT_SMP */
#endif	/* CONFIG_MIPS_MT */
	/* setup the cascaded interrupts */
	setup_irq(MSP_INT_CIC, &cic_cascade_msp);
	setup_irq(MSP_INT_PER, &per_cascade_msp);

#else
	/* setup the 2nd-level SLP register based interrupt controller */
	/* VSMP /SMTC support support is not enabled for SLP */
	msp_slp_irq_init();

	/* setup the cascaded SLP/PER interrupts */
	setup_irq(MSP_INT_SLP, &cic_cascade_msp);
	setup_irq(MSP_INT_PER, &per_cascade_msp);
#endif
}