1 /*
2  * FILE NAME
3  *	arch/mips/vr41xx/nec-eagle/irq.c
4  *
5  * BRIEF MODULE DESCRIPTION
6  *	Interrupt routines for the NEC Eagle/Hawk board.
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  *  - Added support for NEC Hawk.
37  *
38  *  MontaVista Software Inc. <yyuasa@mvista.com> or <source@mvista.com>
39  *  - New creation, NEC Eagle is supported.
40  */
41 #include <linux/init.h>
42 #include <linux/interrupt.h>
43 
44 #include <asm/io.h>
45 #include <asm/vr41xx/eagle.h>
46 
enable_pciint_irq(unsigned int irq)47 static void enable_pciint_irq(unsigned int irq)
48 {
49 	u8 val;
50 
51 	val = readb(NEC_EAGLE_PCIINTMSKREG);
52 	val |= (u8)1 << (irq - PCIINT_IRQ_BASE);
53 	writeb(val, NEC_EAGLE_PCIINTMSKREG);
54 }
55 
disable_pciint_irq(unsigned int irq)56 static void disable_pciint_irq(unsigned int irq)
57 {
58 	u8 val;
59 
60 	val = readb(NEC_EAGLE_PCIINTMSKREG);
61 	val &= ~((u8)1 << (irq - PCIINT_IRQ_BASE));
62 	writeb(val, NEC_EAGLE_PCIINTMSKREG);
63 }
64 
startup_pciint_irq(unsigned int irq)65 static unsigned int startup_pciint_irq(unsigned int irq)
66 {
67 	enable_pciint_irq(irq);
68 	return 0; /* never anything pending */
69 }
70 
71 #define shutdown_pciint_irq	disable_pciint_irq
72 #define ack_pciint_irq		disable_pciint_irq
73 
end_pciint_irq(unsigned int irq)74 static void end_pciint_irq(unsigned int irq)
75 {
76 	if (!(irq_desc[irq].status & (IRQ_DISABLED | IRQ_INPROGRESS)))
77 		enable_pciint_irq(irq);
78 }
79 
80 static struct hw_interrupt_type pciint_irq_type = {
81 	"PCIINT",
82 	startup_pciint_irq,
83 	shutdown_pciint_irq,
84        	enable_pciint_irq,
85 	disable_pciint_irq,
86 	ack_pciint_irq,
87 	end_pciint_irq,
88 	NULL
89 };
90 
enable_sdbint_irq(unsigned int irq)91 static void enable_sdbint_irq(unsigned int irq)
92 {
93 	u8 val;
94 
95 	val = readb(NEC_EAGLE_SDBINTMSK);
96 	val |= (u8)1 << (irq - SDBINT_IRQ_BASE);
97 	writeb(val, NEC_EAGLE_SDBINTMSK);
98 }
99 
disable_sdbint_irq(unsigned int irq)100 static void disable_sdbint_irq(unsigned int irq)
101 {
102 	u8 val;
103 
104 	val = readb(NEC_EAGLE_SDBINTMSK);
105 	val &= ~((u8)1 << (irq - SDBINT_IRQ_BASE));
106 	writeb(val, NEC_EAGLE_SDBINTMSK);
107 }
108 
startup_sdbint_irq(unsigned int irq)109 static unsigned int startup_sdbint_irq(unsigned int irq)
110 {
111 	enable_sdbint_irq(irq);
112 	return 0; /* never anything pending */
113 }
114 
115 #define shutdown_sdbint_irq	disable_sdbint_irq
116 #define ack_sdbint_irq		disable_sdbint_irq
117 
end_sdbint_irq(unsigned int irq)118 static void end_sdbint_irq(unsigned int irq)
119 {
120 	if (!(irq_desc[irq].status & (IRQ_DISABLED | IRQ_INPROGRESS)))
121 		enable_sdbint_irq(irq);
122 }
123 
124 static struct hw_interrupt_type sdbint_irq_type = {
125 	"SDBINT",
126 	startup_sdbint_irq,
127 	shutdown_sdbint_irq,
128        	enable_sdbint_irq,
129 	disable_sdbint_irq,
130 	ack_sdbint_irq,
131 	end_sdbint_irq,
132 	NULL
133 };
134 
eagle_get_irq_number(int irq)135 static int eagle_get_irq_number(int irq)
136 {
137 	u8 sdbint, pciint;
138 	int i;
139 
140 	sdbint = readb(NEC_EAGLE_SDBINT);
141 	sdbint &= (NEC_EAGLE_SDBINT_DEG | NEC_EAGLE_SDBINT_ENUM |
142 	           NEC_EAGLE_SDBINT_SIO1INT | NEC_EAGLE_SDBINT_SIO2INT |
143 	           NEC_EAGLE_SDBINT_PARINT);
144 	pciint = readb(NEC_EAGLE_PCIINTREG);
145 	pciint &= (NEC_EAGLE_PCIINT_CP_INTA | NEC_EAGLE_PCIINT_CP_INTB |
146 	           NEC_EAGLE_PCIINT_CP_INTC | NEC_EAGLE_PCIINT_CP_INTD |
147 	           NEC_EAGLE_PCIINT_LANINT);
148 
149 	for (i = 1; i < 6; i++)
150 		if (sdbint & (0x01 << i))
151 			return SDBINT_IRQ_BASE + i;
152 
153 	for (i = 0; i < 5; i++)
154 		if (pciint & (0x01 << i))
155 			return PCIINT_IRQ_BASE + i;
156 
157 	return -EINVAL;
158 }
159 
eagle_irq_init(void)160 void __init eagle_irq_init(void)
161 {
162 	int i;
163 
164 	writeb(0, NEC_EAGLE_SDBINTMSK);
165 	writeb(0, NEC_EAGLE_PCIINTMSKREG);
166 
167 	vr41xx_set_irq_trigger(PCISLOT_PIN, TRIGGER_LEVEL, SIGNAL_THROUGH);
168 	vr41xx_set_irq_level(PCISLOT_PIN, LEVEL_HIGH);
169 
170 	vr41xx_set_irq_trigger(FPGA_PIN, TRIGGER_LEVEL, SIGNAL_THROUGH);
171 	vr41xx_set_irq_level(FPGA_PIN, LEVEL_HIGH);
172 
173 	vr41xx_set_irq_trigger(DCD_PIN, TRIGGER_EDGE, SIGNAL_HOLD);
174 	vr41xx_set_irq_level(DCD_PIN, LEVEL_LOW);
175 
176 	for (i = SDBINT_IRQ_BASE; i <= SDBINT_IRQ_LAST; i++)
177 		irq_desc[i].handler = &sdbint_irq_type;
178 
179 	for (i = PCIINT_IRQ_BASE; i <= PCIINT_IRQ_LAST; i++)
180 		irq_desc[i].handler = &pciint_irq_type;
181 
182 	vr41xx_cascade_irq(FPGA_CASCADE_IRQ, eagle_get_irq_number);
183 }
184