1 | /* |
2 | * ints.c - Generic interrupt controller support |
3 | * |
4 | * This file is subject to the terms and conditions of the GNU General Public |
5 | * License. See the file COPYING in the main directory of this archive |
6 | * for more details. |
7 | * |
8 | * Copyright 1996 Roman Zippel |
9 | * Copyright 1999 D. Jeff Dionne <jeff@rt-control.com> |
10 | */ |
11 | |
12 | #include <linux/types.h> |
13 | #include <linux/kernel.h> |
14 | #include <linux/init.h> |
15 | #include <linux/interrupt.h> |
16 | #include <linux/irq.h> |
17 | #include <linux/cpu.h> |
18 | #include <asm/traps.h> |
19 | #include <asm/io.h> |
20 | #include <asm/machdep.h> |
21 | |
22 | #if defined(CONFIG_M68EZ328) |
23 | #include <asm/MC68EZ328.h> |
24 | #elif defined(CONFIG_M68VZ328) |
25 | #include <asm/MC68VZ328.h> |
26 | #else |
27 | #include <asm/MC68328.h> |
28 | #endif |
29 | |
30 | #include "ints.h" |
31 | |
32 | /* assembler routines */ |
33 | asmlinkage void system_call(void); |
34 | asmlinkage void buserr(void); |
35 | asmlinkage void trap(void); |
36 | asmlinkage void trap3(void); |
37 | asmlinkage void trap4(void); |
38 | asmlinkage void trap5(void); |
39 | asmlinkage void trap6(void); |
40 | asmlinkage void trap7(void); |
41 | asmlinkage void trap8(void); |
42 | asmlinkage void trap9(void); |
43 | asmlinkage void trap10(void); |
44 | asmlinkage void trap11(void); |
45 | asmlinkage void trap12(void); |
46 | asmlinkage void trap13(void); |
47 | asmlinkage void trap14(void); |
48 | asmlinkage void trap15(void); |
49 | asmlinkage void trap33(void); |
50 | asmlinkage void trap34(void); |
51 | asmlinkage void trap35(void); |
52 | asmlinkage void trap36(void); |
53 | asmlinkage void trap37(void); |
54 | asmlinkage void trap38(void); |
55 | asmlinkage void trap39(void); |
56 | asmlinkage void trap40(void); |
57 | asmlinkage void trap41(void); |
58 | asmlinkage void trap42(void); |
59 | asmlinkage void trap43(void); |
60 | asmlinkage void trap44(void); |
61 | asmlinkage void trap45(void); |
62 | asmlinkage void trap46(void); |
63 | asmlinkage void trap47(void); |
64 | asmlinkage irqreturn_t bad_interrupt(int, void *); |
65 | asmlinkage irqreturn_t inthandler(void); |
66 | asmlinkage irqreturn_t inthandler1(void); |
67 | asmlinkage irqreturn_t inthandler2(void); |
68 | asmlinkage irqreturn_t inthandler3(void); |
69 | asmlinkage irqreturn_t inthandler4(void); |
70 | asmlinkage irqreturn_t inthandler5(void); |
71 | asmlinkage irqreturn_t inthandler6(void); |
72 | asmlinkage irqreturn_t inthandler7(void); |
73 | |
74 | /* The 68k family did not have a good way to determine the source |
75 | * of interrupts until later in the family. The EC000 core does |
76 | * not provide the vector number on the stack, we vector everything |
77 | * into one vector and look in the blasted mask register... |
78 | * This code is designed to be fast, almost constant time, not clean! |
79 | */ |
80 | asmlinkage void process_int(int vec, struct pt_regs *fp) |
81 | { |
82 | int irq; |
83 | int mask; |
84 | |
85 | unsigned long pend = ISR; |
86 | |
87 | while (pend) { |
88 | if (pend & 0x0000ffff) { |
89 | if (pend & 0x000000ff) { |
90 | if (pend & 0x0000000f) { |
91 | mask = 0x00000001; |
92 | irq = 0; |
93 | } else { |
94 | mask = 0x00000010; |
95 | irq = 4; |
96 | } |
97 | } else { |
98 | if (pend & 0x00000f00) { |
99 | mask = 0x00000100; |
100 | irq = 8; |
101 | } else { |
102 | mask = 0x00001000; |
103 | irq = 12; |
104 | } |
105 | } |
106 | } else { |
107 | if (pend & 0x00ff0000) { |
108 | if (pend & 0x000f0000) { |
109 | mask = 0x00010000; |
110 | irq = 16; |
111 | } else { |
112 | mask = 0x00100000; |
113 | irq = 20; |
114 | } |
115 | } else { |
116 | if (pend & 0x0f000000) { |
117 | mask = 0x01000000; |
118 | irq = 24; |
119 | } else { |
120 | mask = 0x10000000; |
121 | irq = 28; |
122 | } |
123 | } |
124 | } |
125 | |
126 | while (! (mask & pend)) { |
127 | mask <<=1; |
128 | irq++; |
129 | } |
130 | |
131 | do_IRQ(irq, fp); |
132 | pend &= ~mask; |
133 | } |
134 | } |
135 | |
136 | static void intc_irq_unmask(struct irq_data *d) |
137 | { |
138 | IMR &= ~(1 << d->irq); |
139 | } |
140 | |
141 | static void intc_irq_mask(struct irq_data *d) |
142 | { |
143 | IMR |= (1 << d->irq); |
144 | } |
145 | |
146 | static struct irq_chip intc_irq_chip = { |
147 | .name = "M68K-INTC" , |
148 | .irq_mask = intc_irq_mask, |
149 | .irq_unmask = intc_irq_unmask, |
150 | }; |
151 | |
152 | /* |
153 | * This function should be called during kernel startup to initialize |
154 | * the machine vector table. |
155 | */ |
156 | void __init trap_init(void) |
157 | { |
158 | int i; |
159 | |
160 | /* set up the vectors */ |
161 | for (i = 72; i < 256; ++i) |
162 | _ramvec[i] = (e_vector) bad_interrupt; |
163 | |
164 | _ramvec[32] = system_call; |
165 | |
166 | _ramvec[65] = (e_vector) inthandler1; |
167 | _ramvec[66] = (e_vector) inthandler2; |
168 | _ramvec[67] = (e_vector) inthandler3; |
169 | _ramvec[68] = (e_vector) inthandler4; |
170 | _ramvec[69] = (e_vector) inthandler5; |
171 | _ramvec[70] = (e_vector) inthandler6; |
172 | _ramvec[71] = (e_vector) inthandler7; |
173 | } |
174 | |
175 | void __init init_IRQ(void) |
176 | { |
177 | int i; |
178 | |
179 | IVR = 0x40; /* Set DragonBall IVR (interrupt base) to 64 */ |
180 | |
181 | /* turn off all interrupts */ |
182 | IMR = ~0; |
183 | |
184 | for (i = 0; (i < NR_IRQS); i++) { |
185 | irq_set_chip(irq: i, chip: &intc_irq_chip); |
186 | irq_set_handler(irq: i, handle: handle_level_irq); |
187 | } |
188 | } |
189 | |
190 | |