diff options
Diffstat (limited to 'arch/mips/kernel/irq-msc01.c')
-rw-r--r-- | arch/mips/kernel/irq-msc01.c | 189 |
1 files changed, 189 insertions, 0 deletions
diff --git a/arch/mips/kernel/irq-msc01.c b/arch/mips/kernel/irq-msc01.c new file mode 100644 index 000000000000..43c00ac0b88d --- /dev/null +++ b/arch/mips/kernel/irq-msc01.c | |||
@@ -0,0 +1,189 @@ | |||
1 | /* | ||
2 | * Copyright (c) 2004 MIPS Inc | ||
3 | * Author: chris@mips.com | ||
4 | * | ||
5 | * This program is free software; you can redistribute it and/or modify it | ||
6 | * under the terms of the GNU General Public License as published by the | ||
7 | * Free Software Foundation; either version 2 of the License, or (at your | ||
8 | * option) any later version. | ||
9 | */ | ||
10 | #include <linux/module.h> | ||
11 | #include <linux/interrupt.h> | ||
12 | #include <linux/kernel.h> | ||
13 | #include <asm/ptrace.h> | ||
14 | #include <linux/sched.h> | ||
15 | #include <linux/kernel_stat.h> | ||
16 | #include <asm/io.h> | ||
17 | #include <asm/irq.h> | ||
18 | #include <asm/msc01_ic.h> | ||
19 | |||
20 | static unsigned long _icctrl_msc; | ||
21 | #define MSC01_IC_REG_BASE _icctrl_msc | ||
22 | |||
23 | #define MSCIC_WRITE(reg, data) do { *(volatile u32 *)(reg) = data; } while (0) | ||
24 | #define MSCIC_READ(reg, data) do { data = *(volatile u32 *)(reg); } while (0) | ||
25 | |||
26 | static unsigned int irq_base; | ||
27 | |||
28 | /* mask off an interrupt */ | ||
29 | static inline void mask_msc_irq(unsigned int irq) | ||
30 | { | ||
31 | if (irq < (irq_base + 32)) | ||
32 | MSCIC_WRITE(MSC01_IC_DISL, 1<<(irq - irq_base)); | ||
33 | else | ||
34 | MSCIC_WRITE(MSC01_IC_DISH, 1<<(irq - irq_base - 32)); | ||
35 | } | ||
36 | |||
37 | /* unmask an interrupt */ | ||
38 | static inline void unmask_msc_irq(unsigned int irq) | ||
39 | { | ||
40 | if (irq < (irq_base + 32)) | ||
41 | MSCIC_WRITE(MSC01_IC_ENAL, 1<<(irq - irq_base)); | ||
42 | else | ||
43 | MSCIC_WRITE(MSC01_IC_ENAH, 1<<(irq - irq_base - 32)); | ||
44 | } | ||
45 | |||
46 | /* | ||
47 | * Enables the IRQ on SOC-it | ||
48 | */ | ||
49 | static void enable_msc_irq(unsigned int irq) | ||
50 | { | ||
51 | unmask_msc_irq(irq); | ||
52 | } | ||
53 | |||
54 | /* | ||
55 | * Initialize the IRQ on SOC-it | ||
56 | */ | ||
57 | static unsigned int startup_msc_irq(unsigned int irq) | ||
58 | { | ||
59 | unmask_msc_irq(irq); | ||
60 | return 0; | ||
61 | } | ||
62 | |||
63 | /* | ||
64 | * Disables the IRQ on SOC-it | ||
65 | */ | ||
66 | static void disable_msc_irq(unsigned int irq) | ||
67 | { | ||
68 | mask_msc_irq(irq); | ||
69 | } | ||
70 | |||
71 | /* | ||
72 | * Masks and ACKs an IRQ | ||
73 | */ | ||
74 | static void level_mask_and_ack_msc_irq(unsigned int irq) | ||
75 | { | ||
76 | mask_msc_irq(irq); | ||
77 | if (!cpu_has_ei) | ||
78 | MSCIC_WRITE(MSC01_IC_EOI, 0); | ||
79 | } | ||
80 | |||
81 | /* | ||
82 | * Masks and ACKs an IRQ | ||
83 | */ | ||
84 | static void edge_mask_and_ack_msc_irq(unsigned int irq) | ||
85 | { | ||
86 | mask_msc_irq(irq); | ||
87 | if (!cpu_has_ei) | ||
88 | MSCIC_WRITE(MSC01_IC_EOI, 0); | ||
89 | else { | ||
90 | u32 r; | ||
91 | MSCIC_READ(MSC01_IC_SUP+irq*8, r); | ||
92 | MSCIC_WRITE(MSC01_IC_SUP+irq*8, r | ~MSC01_IC_SUP_EDGE_BIT); | ||
93 | MSCIC_WRITE(MSC01_IC_SUP+irq*8, r); | ||
94 | } | ||
95 | } | ||
96 | |||
97 | /* | ||
98 | * End IRQ processing | ||
99 | */ | ||
100 | static void end_msc_irq(unsigned int irq) | ||
101 | { | ||
102 | if (!(irq_desc[irq].status & (IRQ_DISABLED|IRQ_INPROGRESS))) | ||
103 | unmask_msc_irq(irq); | ||
104 | } | ||
105 | |||
106 | /* | ||
107 | * Interrupt handler for interrupts coming from SOC-it. | ||
108 | */ | ||
109 | void ll_msc_irq(struct pt_regs *regs) | ||
110 | { | ||
111 | unsigned int irq; | ||
112 | |||
113 | /* read the interrupt vector register */ | ||
114 | MSCIC_READ(MSC01_IC_VEC, irq); | ||
115 | if (irq < 64) | ||
116 | do_IRQ(irq + irq_base, regs); | ||
117 | else { | ||
118 | /* Ignore spurious interrupt */ | ||
119 | } | ||
120 | } | ||
121 | |||
122 | void | ||
123 | msc_bind_eic_interrupt (unsigned int irq, unsigned int set) | ||
124 | { | ||
125 | MSCIC_WRITE(MSC01_IC_RAMW, | ||
126 | (irq<<MSC01_IC_RAMW_ADDR_SHF) | (set<<MSC01_IC_RAMW_DATA_SHF)); | ||
127 | } | ||
128 | |||
129 | #define shutdown_msc_irq disable_msc_irq | ||
130 | |||
131 | struct hw_interrupt_type msc_levelirq_type = { | ||
132 | "SOC-it-Level", | ||
133 | startup_msc_irq, | ||
134 | shutdown_msc_irq, | ||
135 | enable_msc_irq, | ||
136 | disable_msc_irq, | ||
137 | level_mask_and_ack_msc_irq, | ||
138 | end_msc_irq, | ||
139 | NULL | ||
140 | }; | ||
141 | |||
142 | struct hw_interrupt_type msc_edgeirq_type = { | ||
143 | "SOC-it-Edge", | ||
144 | startup_msc_irq, | ||
145 | shutdown_msc_irq, | ||
146 | enable_msc_irq, | ||
147 | disable_msc_irq, | ||
148 | edge_mask_and_ack_msc_irq, | ||
149 | end_msc_irq, | ||
150 | NULL | ||
151 | }; | ||
152 | |||
153 | |||
154 | void __init init_msc_irqs(unsigned int base, msc_irqmap_t *imp, int nirq) | ||
155 | { | ||
156 | extern void (*board_bind_eic_interrupt)(unsigned int irq, unsigned int regset); | ||
157 | |||
158 | _icctrl_msc = (unsigned long) ioremap (MIPS_MSC01_IC_REG_BASE, 0x40000); | ||
159 | |||
160 | /* Reset interrupt controller - initialises all registers to 0 */ | ||
161 | MSCIC_WRITE(MSC01_IC_RST, MSC01_IC_RST_RST_BIT); | ||
162 | |||
163 | board_bind_eic_interrupt = &msc_bind_eic_interrupt; | ||
164 | |||
165 | for (; nirq >= 0; nirq--, imp++) { | ||
166 | int n = imp->im_irq; | ||
167 | |||
168 | switch (imp->im_type) { | ||
169 | case MSC01_IRQ_EDGE: | ||
170 | irq_desc[base+n].handler = &msc_edgeirq_type; | ||
171 | if (cpu_has_ei) | ||
172 | MSCIC_WRITE(MSC01_IC_SUP+n*8, MSC01_IC_SUP_EDGE_BIT); | ||
173 | else | ||
174 | MSCIC_WRITE(MSC01_IC_SUP+n*8, MSC01_IC_SUP_EDGE_BIT | imp->im_lvl); | ||
175 | break; | ||
176 | case MSC01_IRQ_LEVEL: | ||
177 | irq_desc[base+n].handler = &msc_levelirq_type; | ||
178 | if (cpu_has_ei) | ||
179 | MSCIC_WRITE(MSC01_IC_SUP+n*8, 0); | ||
180 | else | ||
181 | MSCIC_WRITE(MSC01_IC_SUP+n*8, imp->im_lvl); | ||
182 | } | ||
183 | } | ||
184 | |||
185 | irq_base = base; | ||
186 | |||
187 | MSCIC_WRITE(MSC01_IC_GENA, MSC01_IC_GENA_GENA_BIT); /* Enable interrupt generation */ | ||
188 | |||
189 | } | ||