1 /*
2  * Copyright 2004 PMC-Sierra Inc.
3  * Author: Manish Lachwani (lachwani@pmc-sierra.com)
4  *
5  * arch/mips/pmc-sierra/big_sur/big_sur_irq.c
6  *     Interrupt routines for Xilinx system controller.  Interrupt numbers
7  *     are assigned from BIG_SUR_IRQ_BASE to BIG_SUR_IRQ_BASE + 10
8  *
9  * This program is free software; you can redistribute  it and/or modify it
10  * under  the terms of  the GNU General  Public License as published by the
11  * Free Software Foundation;  either version 2 of the  License, or (at your
12  * option) any later version.
13  */
14 
15 #include <linux/interrupt.h>
16 #include <linux/kernel.h>
17 #include <asm/ptrace.h>
18 #include <linux/config.h>
19 #include <linux/sched.h>
20 #include <linux/kernel_stat.h>
21 #include <asm/io.h>
22 #include <asm/irq.h>
23 
24 #include "xilinx_irq.h"
25 
26 #define	BIG_SUR_IRQ_BASE	16
27 
28 /* mask off an interrupt -- 1 is enable, 0 is disable */
mask_big_sur_irq(unsigned int irq)29 static inline void mask_big_sur_irq(unsigned int irq)
30 {
31 	unsigned long reg_data;
32 
33 	reg_data = BIG_SUR_READ(BIG_SUR_INTERRUPT_MASK_1);
34 	reg_data &= ~(1 << (irq - BIG_SUR_IRQ_BASE));
35 	BIG_SUR_WRITE(BIG_SUR_INTERRUPT_MASK_1, reg_data);
36 }
37 
38 /* unmask an interrupt -- 1 is enable, 0 is disable */
unmask_big_sur_irq(unsigned int irq)39 static inline void unmask_big_sur_irq(unsigned int irq)
40 {
41 	unsigned long reg_data;
42 
43 	reg_data = BIG_SUR_READ(BIG_SUR_INTERRUPT_MASK_1);
44 	reg_data |= (1 << (irq - BIG_SUR_IRQ_BASE));
45 	BIG_SUR_WRITE(BIG_SUR_INTERRUPT_MASK_1, reg_data);
46 }
47 
48 /* Enable IRQ on the Xilinx FPGA */
enable_big_sur_irq(unsigned int irq)49 static void enable_big_sur_irq(unsigned int irq)
50 {
51 	unmask_big_sur_irq(irq);
52 }
53 
54 /* Initialize IRQ on the Xilinx FPGA */
startup_big_sur_irq(unsigned int irq)55 static unsigned int startup_big_sur_irq(unsigned int irq)
56 {
57 	unmask_big_sur_irq(irq);
58 	return 0;
59 }
60 
61 /* Disable the IRQ on the Xilinx FPGA */
disable_big_sur_irq(unsigned int irq)62 static void disable_big_sur_irq(unsigned int irq)
63 {
64 	mask_big_sur_irq(irq);
65 }
66 
67 /* Mask and ack an IRQ on the Xilinx FPGA */
mask_and_ack_big_sur_irq(unsigned int irq)68 static void mask_and_ack_big_sur_irq(unsigned int irq)
69 {
70 	mask_big_sur_irq(irq);
71 }
72 
73 /* End IRQ processing on the Xilinx FPGA */
end_big_sur_irq(unsigned int irq)74 static void end_big_sur_irq(unsigned int irq)
75 {
76 	if (!(irq_desc[irq].status & (IRQ_DISABLED|IRQ_INPROGRESS)))
77 		unmask_big_sur_irq(irq);
78 }
79 
80 /*
81  * Main interrupt handler for the Xilinx FPGA on the
82  * Big Sur board. These interrupts could be coming
83  * from the IDE, PCI, UART etc.
84  */
big_sur_irq_handler(struct pt_regs * regs)85 void big_sur_irq_handler(struct pt_regs *regs)
86 {
87 	unsigned long reg_data;
88 
89 	reg_data = BIG_SUR_READ(BIG_SUR_INTERRUPT_STATUS_1);
90 
91 	/* Now check for the UART 1 interrupts */
92 	if (reg_data & 0x38)
93 		do_IRQ(BIG_SUR_UART1_IRQ + BIG_SUR_IRQ_BASE, regs);
94 
95 	/* Now check for the UART 2 interrupts */
96 	if (reg_data & 0x1c0)
97 		do_IRQ(BIG_SUR_UART2_IRQ + BIG_SUR_IRQ_BASE, regs);
98 
99 	/* Now check for the Timer interrupt */
100 	if (reg_data & 0x800)
101 		do_IRQ(BIG_SUR_TIMER_IRQ + BIG_SUR_IRQ_BASE, regs);
102 
103 	/* Now check for the PCI interrupt, INTA */
104 	if (reg_data & 0x2)
105 		do_IRQ(BIG_SUR_PCI_IRQ + BIG_SUR_IRQ_BASE, regs);
106 
107 	/* Now check for the IDE interrupts */
108 	if (reg_data & 0x1)
109 		do_IRQ(BIG_SUR_IDE_IRQ + BIG_SUR_IRQ_BASE, regs);
110 }
111 
112 #define	shutdown_big_sur_irq	disable_big_sur_irq
113 
114 struct hw_interrupt_type big_sur_irq_type = {
115 	"BIG-SUR",
116 	startup_big_sur_irq,
117 	shutdown_big_sur_irq,
118 	enable_big_sur_irq,
119 	disable_big_sur_irq,
120 	mask_and_ack_big_sur_irq,
121 	end_big_sur_irq,
122 	NULL
123 };
124 
big_sur_irq_init(void)125 void big_sur_irq_init(void)
126 {
127 	int i;
128 
129 	/* Reset irq handlers pointers to NULL */
130 	for (i = BIG_SUR_IRQ_BASE; i < (BIG_SUR_IRQ_BASE + 10); i++) {
131 		irq_desc[i].status = IRQ_DISABLED;
132 		irq_desc[i].action = 0;
133 		irq_desc[i].depth = 2;
134 		irq_desc[i].handler = &big_sur_irq_type;
135 	}
136 }
137 
138