xref: /linux/arch/mips/rb532/irq.c (revision 73b4390fb23456964201abda79f1210fe337d01a)
1*73b4390fSRalf Baechle /*
2*73b4390fSRalf Baechle  *  This program is free software; you can redistribute  it and/or modify it
3*73b4390fSRalf Baechle  *  under  the terms of  the GNU General  Public License as published by the
4*73b4390fSRalf Baechle  *  Free Software Foundation;  either version 2 of the  License, or (at your
5*73b4390fSRalf Baechle  *  option) any later version.
6*73b4390fSRalf Baechle  *
7*73b4390fSRalf Baechle  *  THIS  SOFTWARE  IS PROVIDED   ``AS  IS'' AND   ANY  EXPRESS OR IMPLIED
8*73b4390fSRalf Baechle  *  WARRANTIES,   INCLUDING, BUT NOT  LIMITED  TO, THE IMPLIED WARRANTIES OF
9*73b4390fSRalf Baechle  *  MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN
10*73b4390fSRalf Baechle  *  NO  EVENT  SHALL   THE AUTHOR  BE    LIABLE FOR ANY   DIRECT, INDIRECT,
11*73b4390fSRalf Baechle  *  INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
12*73b4390fSRalf Baechle  *  NOT LIMITED   TO, PROCUREMENT OF  SUBSTITUTE GOODS  OR SERVICES; LOSS OF
13*73b4390fSRalf Baechle  *  USE, DATA,  OR PROFITS; OR  BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
14*73b4390fSRalf Baechle  *  ANY THEORY OF LIABILITY, WHETHER IN  CONTRACT, STRICT LIABILITY, OR TORT
15*73b4390fSRalf Baechle  *  (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
16*73b4390fSRalf Baechle  *  THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
17*73b4390fSRalf Baechle  *
18*73b4390fSRalf Baechle  *  You should have received a copy of the  GNU General Public License along
19*73b4390fSRalf Baechle  *  with this program; if not, write  to the Free Software Foundation, Inc.,
20*73b4390fSRalf Baechle  *  675 Mass Ave, Cambridge, MA 02139, USA.
21*73b4390fSRalf Baechle  *
22*73b4390fSRalf Baechle  * Copyright 2002 MontaVista Software Inc.
23*73b4390fSRalf Baechle  * Author: MontaVista Software, Inc.
24*73b4390fSRalf Baechle  *              stevel@mvista.com or source@mvista.com
25*73b4390fSRalf Baechle  */
26*73b4390fSRalf Baechle 
27*73b4390fSRalf Baechle #include <linux/bitops.h>
28*73b4390fSRalf Baechle #include <linux/errno.h>
29*73b4390fSRalf Baechle #include <linux/init.h>
30*73b4390fSRalf Baechle #include <linux/io.h>
31*73b4390fSRalf Baechle #include <linux/kernel_stat.h>
32*73b4390fSRalf Baechle #include <linux/module.h>
33*73b4390fSRalf Baechle #include <linux/signal.h>
34*73b4390fSRalf Baechle #include <linux/sched.h>
35*73b4390fSRalf Baechle #include <linux/types.h>
36*73b4390fSRalf Baechle #include <linux/interrupt.h>
37*73b4390fSRalf Baechle #include <linux/ioport.h>
38*73b4390fSRalf Baechle #include <linux/timex.h>
39*73b4390fSRalf Baechle #include <linux/slab.h>
40*73b4390fSRalf Baechle #include <linux/random.h>
41*73b4390fSRalf Baechle #include <linux/delay.h>
42*73b4390fSRalf Baechle 
43*73b4390fSRalf Baechle #include <asm/bootinfo.h>
44*73b4390fSRalf Baechle #include <asm/time.h>
45*73b4390fSRalf Baechle #include <asm/mipsregs.h>
46*73b4390fSRalf Baechle #include <asm/system.h>
47*73b4390fSRalf Baechle 
48*73b4390fSRalf Baechle #include <asm/mach-rc32434/rc32434.h>
49*73b4390fSRalf Baechle 
50*73b4390fSRalf Baechle struct intr_group {
51*73b4390fSRalf Baechle 	u32 mask;	/* mask of valid bits in pending/mask registers */
52*73b4390fSRalf Baechle 	volatile u32 *base_addr;
53*73b4390fSRalf Baechle };
54*73b4390fSRalf Baechle 
55*73b4390fSRalf Baechle #define RC32434_NR_IRQS  (GROUP4_IRQ_BASE + 32)
56*73b4390fSRalf Baechle 
57*73b4390fSRalf Baechle #if (NR_IRQS < RC32434_NR_IRQS)
58*73b4390fSRalf Baechle #error Too little irqs defined. Did you override <asm/irq.h> ?
59*73b4390fSRalf Baechle #endif
60*73b4390fSRalf Baechle 
61*73b4390fSRalf Baechle static const struct intr_group intr_group[NUM_INTR_GROUPS] = {
62*73b4390fSRalf Baechle 	{
63*73b4390fSRalf Baechle 		.mask	= 0x0000efff,
64*73b4390fSRalf Baechle 		.base_addr = (u32 *) KSEG1ADDR(IC_GROUP0_PEND + 0 * IC_GROUP_OFFSET)},
65*73b4390fSRalf Baechle 	{
66*73b4390fSRalf Baechle 		.mask	= 0x00001fff,
67*73b4390fSRalf Baechle 		.base_addr = (u32 *) KSEG1ADDR(IC_GROUP0_PEND + 1 * IC_GROUP_OFFSET)},
68*73b4390fSRalf Baechle 	{
69*73b4390fSRalf Baechle 		.mask	= 0x00000007,
70*73b4390fSRalf Baechle 		.base_addr = (u32 *) KSEG1ADDR(IC_GROUP0_PEND + 2 * IC_GROUP_OFFSET)},
71*73b4390fSRalf Baechle 	{
72*73b4390fSRalf Baechle 		.mask	= 0x0003ffff,
73*73b4390fSRalf Baechle 		.base_addr = (u32 *) KSEG1ADDR(IC_GROUP0_PEND + 3 * IC_GROUP_OFFSET)},
74*73b4390fSRalf Baechle 	{
75*73b4390fSRalf Baechle 		.mask	= 0xffffffff,
76*73b4390fSRalf Baechle 		.base_addr = (u32 *) KSEG1ADDR(IC_GROUP0_PEND + 4 * IC_GROUP_OFFSET)}
77*73b4390fSRalf Baechle };
78*73b4390fSRalf Baechle 
79*73b4390fSRalf Baechle #define READ_PEND(base) (*(base))
80*73b4390fSRalf Baechle #define READ_MASK(base) (*(base + 2))
81*73b4390fSRalf Baechle #define WRITE_MASK(base, val) (*(base + 2) = (val))
82*73b4390fSRalf Baechle 
83*73b4390fSRalf Baechle static inline int irq_to_group(unsigned int irq_nr)
84*73b4390fSRalf Baechle {
85*73b4390fSRalf Baechle 	return (irq_nr - GROUP0_IRQ_BASE) >> 5;
86*73b4390fSRalf Baechle }
87*73b4390fSRalf Baechle 
88*73b4390fSRalf Baechle static inline int group_to_ip(unsigned int group)
89*73b4390fSRalf Baechle {
90*73b4390fSRalf Baechle 	return group + 2;
91*73b4390fSRalf Baechle }
92*73b4390fSRalf Baechle 
93*73b4390fSRalf Baechle static inline void enable_local_irq(unsigned int ip)
94*73b4390fSRalf Baechle {
95*73b4390fSRalf Baechle 	int ipnum = 0x100 << ip;
96*73b4390fSRalf Baechle 
97*73b4390fSRalf Baechle 	set_c0_status(ipnum);
98*73b4390fSRalf Baechle }
99*73b4390fSRalf Baechle 
100*73b4390fSRalf Baechle static inline void disable_local_irq(unsigned int ip)
101*73b4390fSRalf Baechle {
102*73b4390fSRalf Baechle 	int ipnum = 0x100 << ip;
103*73b4390fSRalf Baechle 
104*73b4390fSRalf Baechle 	clear_c0_status(ipnum);
105*73b4390fSRalf Baechle }
106*73b4390fSRalf Baechle 
107*73b4390fSRalf Baechle static inline void ack_local_irq(unsigned int ip)
108*73b4390fSRalf Baechle {
109*73b4390fSRalf Baechle 	int ipnum = 0x100 << ip;
110*73b4390fSRalf Baechle 
111*73b4390fSRalf Baechle 	clear_c0_cause(ipnum);
112*73b4390fSRalf Baechle }
113*73b4390fSRalf Baechle 
114*73b4390fSRalf Baechle static void rb532_enable_irq(unsigned int irq_nr)
115*73b4390fSRalf Baechle {
116*73b4390fSRalf Baechle 	int ip = irq_nr - GROUP0_IRQ_BASE;
117*73b4390fSRalf Baechle 	unsigned int group, intr_bit;
118*73b4390fSRalf Baechle 	volatile unsigned int *addr;
119*73b4390fSRalf Baechle 
120*73b4390fSRalf Baechle 	if (ip < 0)
121*73b4390fSRalf Baechle 		enable_local_irq(irq_nr);
122*73b4390fSRalf Baechle 	else {
123*73b4390fSRalf Baechle 		group = ip >> 5;
124*73b4390fSRalf Baechle 
125*73b4390fSRalf Baechle 		ip &= (1 << 5) - 1;
126*73b4390fSRalf Baechle 		intr_bit = 1 << ip;
127*73b4390fSRalf Baechle 
128*73b4390fSRalf Baechle 		enable_local_irq(group_to_ip(group));
129*73b4390fSRalf Baechle 
130*73b4390fSRalf Baechle 		addr = intr_group[group].base_addr;
131*73b4390fSRalf Baechle 		WRITE_MASK(addr, READ_MASK(addr) & ~intr_bit);
132*73b4390fSRalf Baechle 	}
133*73b4390fSRalf Baechle }
134*73b4390fSRalf Baechle 
135*73b4390fSRalf Baechle static void rb532_disable_irq(unsigned int irq_nr)
136*73b4390fSRalf Baechle {
137*73b4390fSRalf Baechle 	int ip = irq_nr - GROUP0_IRQ_BASE;
138*73b4390fSRalf Baechle 	unsigned int group, intr_bit, mask;
139*73b4390fSRalf Baechle 	volatile unsigned int *addr;
140*73b4390fSRalf Baechle 
141*73b4390fSRalf Baechle 	if (ip < 0) {
142*73b4390fSRalf Baechle 		disable_local_irq(irq_nr);
143*73b4390fSRalf Baechle 	} else {
144*73b4390fSRalf Baechle 		group = ip >> 5;
145*73b4390fSRalf Baechle 
146*73b4390fSRalf Baechle 		ip &= (1 << 5) - 1;
147*73b4390fSRalf Baechle 		intr_bit = 1 << ip;
148*73b4390fSRalf Baechle 		addr = intr_group[group].base_addr;
149*73b4390fSRalf Baechle 		mask = READ_MASK(addr);
150*73b4390fSRalf Baechle 		mask |= intr_bit;
151*73b4390fSRalf Baechle 		WRITE_MASK(addr, mask);
152*73b4390fSRalf Baechle 
153*73b4390fSRalf Baechle 		/*
154*73b4390fSRalf Baechle 		 * if there are no more interrupts enabled in this
155*73b4390fSRalf Baechle 		 * group, disable corresponding IP
156*73b4390fSRalf Baechle 		 */
157*73b4390fSRalf Baechle 		if (mask == intr_group[group].mask)
158*73b4390fSRalf Baechle 			disable_local_irq(group_to_ip(group));
159*73b4390fSRalf Baechle 	}
160*73b4390fSRalf Baechle }
161*73b4390fSRalf Baechle 
162*73b4390fSRalf Baechle static void rb532_mask_and_ack_irq(unsigned int irq_nr)
163*73b4390fSRalf Baechle {
164*73b4390fSRalf Baechle 	rb532_disable_irq(irq_nr);
165*73b4390fSRalf Baechle 	ack_local_irq(group_to_ip(irq_to_group(irq_nr)));
166*73b4390fSRalf Baechle }
167*73b4390fSRalf Baechle 
168*73b4390fSRalf Baechle static struct irq_chip rc32434_irq_type = {
169*73b4390fSRalf Baechle 	.name		= "RB532",
170*73b4390fSRalf Baechle 	.ack		= rb532_disable_irq,
171*73b4390fSRalf Baechle 	.mask		= rb532_disable_irq,
172*73b4390fSRalf Baechle 	.mask_ack	= rb532_mask_and_ack_irq,
173*73b4390fSRalf Baechle 	.unmask		= rb532_enable_irq,
174*73b4390fSRalf Baechle };
175*73b4390fSRalf Baechle 
176*73b4390fSRalf Baechle void __init arch_init_irq(void)
177*73b4390fSRalf Baechle {
178*73b4390fSRalf Baechle 	int i;
179*73b4390fSRalf Baechle 
180*73b4390fSRalf Baechle 	pr_info("Initializing IRQ's: %d out of %d\n", RC32434_NR_IRQS, NR_IRQS);
181*73b4390fSRalf Baechle 
182*73b4390fSRalf Baechle 	for (i = 0; i < RC32434_NR_IRQS; i++)
183*73b4390fSRalf Baechle 		set_irq_chip_and_handler(i,  &rc32434_irq_type,
184*73b4390fSRalf Baechle 					handle_level_irq);
185*73b4390fSRalf Baechle }
186*73b4390fSRalf Baechle 
187*73b4390fSRalf Baechle /* Main Interrupt dispatcher */
188*73b4390fSRalf Baechle asmlinkage void plat_irq_dispatch(void)
189*73b4390fSRalf Baechle {
190*73b4390fSRalf Baechle 	unsigned int ip, pend, group;
191*73b4390fSRalf Baechle 	volatile unsigned int *addr;
192*73b4390fSRalf Baechle 	unsigned int cp0_cause = read_c0_cause() & read_c0_status();
193*73b4390fSRalf Baechle 
194*73b4390fSRalf Baechle 	if (cp0_cause & CAUSEF_IP7) {
195*73b4390fSRalf Baechle 		do_IRQ(7);
196*73b4390fSRalf Baechle 	} else {
197*73b4390fSRalf Baechle 		ip = (cp0_cause & 0x7c00);
198*73b4390fSRalf Baechle 		if (ip) {
199*73b4390fSRalf Baechle 			group = 21 + (fls(ip) - 32);
200*73b4390fSRalf Baechle 
201*73b4390fSRalf Baechle 			addr = intr_group[group].base_addr;
202*73b4390fSRalf Baechle 
203*73b4390fSRalf Baechle 			pend = READ_PEND(addr);
204*73b4390fSRalf Baechle 			pend &= ~READ_MASK(addr);	/* only unmasked interrupts */
205*73b4390fSRalf Baechle 			pend = 39 + (fls(pend) - 32);
206*73b4390fSRalf Baechle 			do_IRQ((group << 5) + pend);
207*73b4390fSRalf Baechle 		}
208*73b4390fSRalf Baechle 	}
209*73b4390fSRalf Baechle }
210