1 /*
2 * FILE NAME
3 * arch/mips/vr41xx/common/giu.c
4 *
5 * BRIEF MODULE DESCRIPTION
6 * General-purpose I/O Unit Interrupt routines for NEC VR4100 series.
7 *
8 * Author: Yoichi Yuasa
9 * yyuasa@mvista.com or source@mvista.com
10 *
11 * Copyright 2002 MontaVista Software Inc.
12 *
13 * This program is free software; you can redistribute it and/or modify it
14 * under the terms of the GNU General Public License as published by the
15 * Free Software Foundation; either version 2 of the License, or (at your
16 * option) any later version.
17 *
18 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
19 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
20 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
21 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
22 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
23 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
24 * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
25 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
26 * TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
27 * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28 *
29 * You should have received a copy of the GNU General Public License along
30 * with this program; if not, write to the Free Software Foundation, Inc.,
31 * 675 Mass Ave, Cambridge, MA 02139, USA.
32 */
33 /*
34 * Changes:
35 * MontaVista Software Inc. <yyuasa@mvista.com> or <source@mvista.com>
36 * - New creation, NEC VR4111, VR4121, VR4122 and VR4131 are supported.
37 *
38 * Yoichi Yuasa <yuasa@hh.iij4u.or.jp>
39 * - Added support for NEC VR4133.
40 */
41 #include <linux/errno.h>
42 #include <linux/init.h>
43 #include <linux/irq.h>
44 #include <linux/kernel.h>
45 #include <linux/types.h>
46
47 #include <asm/cpu.h>
48 #include <asm/io.h>
49 #include <asm/vr41xx/vr41xx.h>
50
51 #define GIUIOSELL_TYPE1 KSEG1ADDR(0x0b000100)
52 #define GIUIOSELL_TYPE2 KSEG1ADDR(0x0f000140)
53
54 #define GIUIOSELL 0x00
55 #define GIUIOSELH 0x02
56 #define GIUINTSTATL 0x08
57 #define GIUINTSTATH 0x0a
58 #define GIUINTENL 0x0c
59 #define GIUINTENH 0x0e
60 #define GIUINTTYPL 0x10
61 #define GIUINTTYPH 0x12
62 #define GIUINTALSELL 0x14
63 #define GIUINTALSELH 0x16
64 #define GIUINTHTSELL 0x18
65 #define GIUINTHTSELH 0x1a
66 #define GIUFEDGEINHL 0x20
67 #define GIUFEDGEINHH 0x22
68 #define GIUREDGEINHL 0x24
69 #define GIUREDGEINHH 0x26
70
71 static uint32_t giu_base;
72
73 #define read_giuint(offset) readw(giu_base + (offset))
74 #define write_giuint(val, offset) writew((val), giu_base + (offset))
75
set_giuint(uint8_t offset,uint16_t set)76 static inline uint16_t set_giuint(uint8_t offset, uint16_t set)
77 {
78 uint16_t res;
79
80 res = read_giuint(offset);
81 res |= set;
82 write_giuint(res, offset);
83
84 return res;
85 }
86
clear_giuint(uint8_t offset,uint16_t clear)87 static inline uint16_t clear_giuint(uint8_t offset, uint16_t clear)
88 {
89 uint16_t res;
90
91 res = read_giuint(offset);
92 res &= ~clear;
93 write_giuint(res, offset);
94
95 return res;
96 }
97
vr41xx_enable_giuint(int pin)98 void vr41xx_enable_giuint(int pin)
99 {
100 if (pin < 16)
101 set_giuint(GIUINTENL, (uint16_t)1 << pin);
102 else
103 set_giuint(GIUINTENH, (uint16_t)1 << (pin - 16));
104 }
105
vr41xx_disable_giuint(int pin)106 void vr41xx_disable_giuint(int pin)
107 {
108 if (pin < 16)
109 clear_giuint(GIUINTENL, (uint16_t)1 << pin);
110 else
111 clear_giuint(GIUINTENH, (uint16_t)1 << (pin - 16));
112 }
113
vr41xx_clear_giuint(int pin)114 void vr41xx_clear_giuint(int pin)
115 {
116 if (pin < 16)
117 write_giuint((uint16_t)1 << pin, GIUINTSTATL);
118 else
119 write_giuint((uint16_t)1 << (pin - 16), GIUINTSTATH);
120 }
121
vr41xx_set_irq_trigger(int pin,int trigger,int hold)122 void vr41xx_set_irq_trigger(int pin, int trigger, int hold)
123 {
124 uint16_t mask;
125
126 if (pin < 16) {
127 mask = (uint16_t)1 << pin;
128 if (trigger != TRIGGER_LEVEL) {
129 set_giuint(GIUINTTYPL, mask);
130 if (hold == SIGNAL_HOLD)
131 set_giuint(GIUINTHTSELL, mask);
132 else
133 clear_giuint(GIUINTHTSELL, mask);
134 if (current_cpu_data.cputype == CPU_VR4133) {
135 switch (trigger) {
136 case TRIGGER_EDGE_FALLING:
137 set_giuint(GIUFEDGEINHL, mask);
138 clear_giuint(GIUREDGEINHL, mask);
139 break;
140 case TRIGGER_EDGE_RISING:
141 clear_giuint(GIUFEDGEINHL, mask);
142 set_giuint(GIUREDGEINHL, mask);
143 break;
144 default:
145 set_giuint(GIUFEDGEINHL, mask);
146 set_giuint(GIUREDGEINHL, mask);
147 break;
148 }
149 }
150 } else {
151 clear_giuint(GIUINTTYPL, mask);
152 clear_giuint(GIUINTHTSELL, mask);
153 }
154 } else {
155 mask = (uint16_t)1 << (pin - 16);
156 if (trigger != TRIGGER_LEVEL) {
157 set_giuint(GIUINTTYPH, mask);
158 if (hold == SIGNAL_HOLD)
159 set_giuint(GIUINTHTSELH, mask);
160 else
161 clear_giuint(GIUINTHTSELH, mask);
162 if (current_cpu_data.cputype == CPU_VR4133) {
163 switch (trigger) {
164 case TRIGGER_EDGE_FALLING:
165 set_giuint(GIUFEDGEINHH, mask);
166 clear_giuint(GIUREDGEINHH, mask);
167 break;
168 case TRIGGER_EDGE_RISING:
169 clear_giuint(GIUFEDGEINHH, mask);
170 set_giuint(GIUREDGEINHH, mask);
171 break;
172 default:
173 set_giuint(GIUFEDGEINHH, mask);
174 set_giuint(GIUREDGEINHH, mask);
175 break;
176 }
177 }
178 } else {
179 clear_giuint(GIUINTTYPH, mask);
180 clear_giuint(GIUINTHTSELH, mask);
181 }
182 }
183
184 vr41xx_clear_giuint(pin);
185 }
186
vr41xx_set_irq_level(int pin,int level)187 void vr41xx_set_irq_level(int pin, int level)
188 {
189 uint16_t mask;
190
191 if (pin < 16) {
192 mask = (uint16_t)1 << pin;
193 if (level == LEVEL_HIGH)
194 set_giuint(GIUINTALSELL, mask);
195 else
196 clear_giuint(GIUINTALSELL, mask);
197 } else {
198 mask = (uint16_t)1 << (pin - 16);
199 if (level == LEVEL_HIGH)
200 set_giuint(GIUINTALSELH, mask);
201 else
202 clear_giuint(GIUINTALSELH, mask);
203 }
204
205 vr41xx_clear_giuint(pin);
206 }
207
208 #define GIUINT_NR_IRQS 32
209
210 enum {
211 GIUINT_NO_CASCADE,
212 GIUINT_CASCADE
213 };
214
215 struct vr41xx_giuint_cascade {
216 unsigned int flag;
217 int (*get_irq_number)(int irq);
218 };
219
220 static struct vr41xx_giuint_cascade giuint_cascade[GIUINT_NR_IRQS];
221 static struct irqaction giu_cascade = {no_action, 0, 0, "cascade", NULL, NULL};
222
no_irq_number(int irq)223 static int no_irq_number(int irq)
224 {
225 return -EINVAL;
226 }
227
vr41xx_cascade_irq(unsigned int irq,int (* get_irq_number)(int irq))228 int vr41xx_cascade_irq(unsigned int irq, int (*get_irq_number)(int irq))
229 {
230 unsigned int pin;
231 int retval;
232
233 if (irq < GIU_IRQ(0) || irq > GIU_IRQ(31))
234 return -EINVAL;
235
236 if(!get_irq_number)
237 return -EINVAL;
238
239 pin = GIU_IRQ_TO_PIN(irq);
240 giuint_cascade[pin].flag = GIUINT_CASCADE;
241 giuint_cascade[pin].get_irq_number = get_irq_number;
242
243 retval = setup_irq(irq, &giu_cascade);
244 if (retval) {
245 giuint_cascade[pin].flag = GIUINT_NO_CASCADE;
246 giuint_cascade[pin].get_irq_number = no_irq_number;
247 }
248
249 return retval;
250 }
251
giuint_do_IRQ(int pin,struct pt_regs * regs)252 unsigned int giuint_do_IRQ(int pin, struct pt_regs *regs)
253 {
254 struct vr41xx_giuint_cascade *cascade;
255 unsigned int retval = 0;
256 int giuint_irq, cascade_irq;
257
258 disable_irq(GIUINT_CASCADE_IRQ);
259 cascade = &giuint_cascade[pin];
260 giuint_irq = GIU_IRQ(pin);
261 if (cascade->flag == GIUINT_CASCADE) {
262 cascade_irq = cascade->get_irq_number(giuint_irq);
263 disable_irq(giuint_irq);
264 if (cascade_irq > 0)
265 retval = do_IRQ(cascade_irq, regs);
266 enable_irq(giuint_irq);
267 } else
268 retval = do_IRQ(giuint_irq, regs);
269 enable_irq(GIUINT_CASCADE_IRQ);
270
271 return retval;
272 }
273
274 void (*board_irq_init)(void) = NULL;
275
vr41xx_giuint_init(void)276 void __init vr41xx_giuint_init(void)
277 {
278 int i;
279
280 switch (current_cpu_data.cputype) {
281 case CPU_VR4111:
282 case CPU_VR4121:
283 giu_base = GIUIOSELL_TYPE1;
284 break;
285 case CPU_VR4122:
286 case CPU_VR4131:
287 case CPU_VR4133:
288 giu_base = GIUIOSELL_TYPE2;
289 break;
290 default:
291 panic("GIU: Unexpected CPU of NEC VR4100 series");
292 break;
293 }
294
295 for (i = 0; i < GIUINT_NR_IRQS; i++) {
296 vr41xx_disable_giuint(i);
297 giuint_cascade[i].flag = GIUINT_NO_CASCADE;
298 giuint_cascade[i].get_irq_number = no_irq_number;
299 }
300
301 if (setup_irq(GIUINT_CASCADE_IRQ, &giu_cascade))
302 printk("GIUINT: Can not cascade IRQ %d.\n", GIUINT_CASCADE_IRQ);
303
304 if (board_irq_init)
305 board_irq_init();
306 }
307