1 /*
2  * Carsten Langgaard, carstenl@mips.com
3  * Copyright (C) 2002 MIPS Technologies, Inc.  All rights reserved.
4  *
5  * ########################################################################
6  *
7  *  This program is free software; you can distribute it and/or modify it
8  *  under the terms of the GNU General Public License (Version 2) as
9  *  published by the Free Software Foundation.
10  *
11  *  This program is distributed in the hope it will be useful, but WITHOUT
12  *  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13  *  FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
14  *  for more details.
15  *
16  *  You should have received a copy of the GNU General Public License along
17  *  with this program; if not, write to the Free Software Foundation, Inc.,
18  *  59 Temple Place - Suite 330, Boston MA 02111-1307, USA.
19  *
20  * ########################################################################
21  *
22  * Routines for generic manipulation of the interrupts found on the MIPS
23  * Sead board.
24  *
25  */
26 #include <linux/config.h>
27 #include <linux/init.h>
28 #include <linux/irq.h>
29 #include <linux/sched.h>
30 #include <linux/slab.h>
31 #include <linux/interrupt.h>
32 #include <linux/kernel_stat.h>
33 
34 #include <asm/mips-boards/sead.h>
35 #include <asm/mips-boards/seadint.h>
36 
37 extern asmlinkage void mipsIRQ(void);
38 
disable_sead_irq(unsigned int irq_nr)39 void disable_sead_irq(unsigned int irq_nr)
40 {
41 	if (irq_nr == SEADINT_UART0)
42 		clear_c0_status(0x00000400);
43 	else
44 		if (irq_nr == SEADINT_UART1)
45 			clear_c0_status(0x00000800);
46 }
47 
enable_sead_irq(unsigned int irq_nr)48 void enable_sead_irq(unsigned int irq_nr)
49 {
50 	if (irq_nr == SEADINT_UART0)
51 		set_c0_status(0x00000400);
52 	else
53 		if (irq_nr == SEADINT_UART1)
54 			set_c0_status(0x00000800);
55 }
56 
startup_sead_irq(unsigned int irq)57 static unsigned int startup_sead_irq(unsigned int irq)
58 {
59 	enable_sead_irq(irq);
60 	return 0; /* never anything pending */
61 }
62 
63 #define shutdown_sead_irq	disable_sead_irq
64 
65 #define mask_and_ack_sead_irq disable_sead_irq
66 
end_sead_irq(unsigned int irq)67 static void end_sead_irq(unsigned int irq)
68 {
69 	if (!(irq_desc[irq].status & (IRQ_DISABLED|IRQ_INPROGRESS)))
70 		enable_sead_irq(irq);
71 }
72 
73 static struct hw_interrupt_type sead_irq_type = {
74 	"SEAD",
75 	startup_sead_irq,
76 	shutdown_sead_irq,
77 	enable_sead_irq,
78 	disable_sead_irq,
79 	mask_and_ack_sead_irq,
80 	end_sead_irq,
81 	NULL
82 };
83 
sead_hw0_irqdispatch(struct pt_regs * regs)84 void sead_hw0_irqdispatch(struct pt_regs *regs)
85 {
86 	do_IRQ(0, regs);
87 }
88 
sead_hw1_irqdispatch(struct pt_regs * regs)89 void sead_hw1_irqdispatch(struct pt_regs *regs)
90 {
91 	do_IRQ(1, regs);
92 }
93 
init_IRQ(void)94 void __init init_IRQ(void)
95 {
96 	int i;
97 
98         /*
99          * Mask out all interrupt
100 	 */
101 	clear_c0_status(0x0000ff00);
102 
103 	/* Now safe to set the exception vector. */
104 	set_except_vector(0, mipsIRQ);
105 
106 	init_generic_irq();
107 
108 	for (i = 0; i < SEADINT_END; i++) {
109 		irq_desc[i].status	= IRQ_DISABLED;
110 		irq_desc[i].action	= NULL;
111 		irq_desc[i].depth	= 1;
112 		irq_desc[i].lock	= SPIN_LOCK_UNLOCKED;
113 		irq_desc[i].handler	= &sead_irq_type;
114 	}
115 }
116