]>
Commit | Line | Data |
---|---|---|
507bbe3e | 1 | /* |
cfc67116 | 2 | * (C) Copyright 2007 Michal Simek |
507bbe3e WD |
3 | * (C) Copyright 2004 Atmark Techno, Inc. |
4 | * | |
cfc67116 | 5 | * Michal SIMEK <monstr@monstr.eu> |
507bbe3e WD |
6 | * Yasushi SHOJI <yashi@atmark-techno.com> |
7 | * | |
8 | * See file CREDITS for list of people who contributed to this | |
9 | * project. | |
10 | * | |
11 | * This program is free software; you can redistribute it and/or | |
12 | * modify it under the terms of the GNU General Public License as | |
13 | * published by the Free Software Foundation; either version 2 of | |
14 | * the License, or (at your option) any later version. | |
15 | * | |
16 | * This program is distributed in the hope that it will be useful, | |
17 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
cfc67116 | 18 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
507bbe3e WD |
19 | * GNU General Public License for more details. |
20 | * | |
21 | * You should have received a copy of the GNU General Public License | |
22 | * along with this program; if not, write to the Free Software | |
23 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, | |
24 | * MA 02111-1307 USA | |
25 | */ | |
26 | ||
cfc67116 MS |
27 | #include <common.h> |
28 | #include <command.h> | |
29 | #include <asm/microblaze_intc.h> | |
42efed61 | 30 | #include <asm/asm.h> |
cfc67116 MS |
31 | |
32 | #undef DEBUG_INT | |
33 | ||
34 | extern void microblaze_disable_interrupts (void); | |
35 | extern void microblaze_enable_interrupts (void); | |
36 | ||
37 | void enable_interrupts (void) | |
507bbe3e | 38 | { |
fb05f6da | 39 | MSRSET(0x2); |
507bbe3e WD |
40 | } |
41 | ||
cfc67116 | 42 | int disable_interrupts (void) |
507bbe3e | 43 | { |
fb05f6da | 44 | MSRCLR(0x2); |
507bbe3e WD |
45 | return 0; |
46 | } | |
cfc67116 MS |
47 | |
48 | #ifdef CFG_INTC_0 | |
49 | #ifdef CFG_TIMER_0 | |
50 | extern void timer_init (void); | |
51 | #endif | |
fb7c2dbe MS |
52 | #ifdef CFG_FSL_2 |
53 | extern void fsl_init2 (void); | |
54 | #endif | |
55 | ||
cfc67116 MS |
56 | |
57 | static struct irq_action vecs[CFG_INTC_0_NUM]; | |
58 | ||
59 | /* mapping structure to interrupt controller */ | |
60 | microblaze_intc_t *intc = (microblaze_intc_t *) (CFG_INTC_0_ADDR); | |
61 | ||
62 | /* default handler */ | |
63 | void def_hdlr (void) | |
64 | { | |
65 | puts ("def_hdlr\n"); | |
66 | } | |
67 | ||
68 | void enable_one_interrupt (int irq) | |
69 | { | |
70 | int mask; | |
71 | int offset = 1; | |
72 | offset <<= irq; | |
73 | mask = intc->ier; | |
74 | intc->ier = (mask | offset); | |
75 | #ifdef DEBUG_INT | |
76 | printf ("Enable one interrupt irq %x - mask %x,ier %x\n", offset, mask, | |
77 | intc->ier); | |
78 | printf ("INTC isr %x, ier %x, iar %x, mer %x\n", intc->isr, intc->ier, | |
79 | intc->iar, intc->mer); | |
80 | #endif | |
81 | } | |
82 | ||
83 | void disable_one_interrupt (int irq) | |
84 | { | |
85 | int mask; | |
86 | int offset = 1; | |
87 | offset <<= irq; | |
88 | mask = intc->ier; | |
89 | intc->ier = (mask & ~offset); | |
90 | #ifdef DEBUG_INT | |
91 | printf ("Disable one interrupt irq %x - mask %x,ier %x\n", irq, mask, | |
92 | intc->ier); | |
93 | printf ("INTC isr %x, ier %x, iar %x, mer %x\n", intc->isr, intc->ier, | |
94 | intc->iar, intc->mer); | |
95 | #endif | |
96 | } | |
97 | ||
98 | /* adding new handler for interrupt */ | |
99 | void install_interrupt_handler (int irq, interrupt_handler_t * hdlr, void *arg) | |
100 | { | |
101 | struct irq_action *act; | |
102 | /* irq out of range */ | |
17980495 | 103 | if ((irq < 0) || (irq > CFG_INTC_0_NUM)) { |
cfc67116 MS |
104 | puts ("IRQ out of range\n"); |
105 | return; | |
106 | } | |
107 | act = &vecs[irq]; | |
108 | if (hdlr) { /* enable */ | |
109 | act->handler = hdlr; | |
110 | act->arg = arg; | |
111 | act->count = 0; | |
112 | enable_one_interrupt (irq); | |
113 | } else { /* disable */ | |
cfc67116 MS |
114 | act->handler = (interrupt_handler_t *) def_hdlr; |
115 | act->arg = (void *)irq; | |
116 | disable_one_interrupt (irq); | |
117 | } | |
118 | } | |
119 | ||
120 | /* initialization interrupt controller - hardware */ | |
121 | void intc_init (void) | |
122 | { | |
123 | intc->mer = 0; | |
124 | intc->ier = 0; | |
125 | intc->iar = 0xFFFFFFFF; | |
126 | /* XIntc_Start - hw_interrupt enable and all interrupt enable */ | |
127 | intc->mer = 0x3; | |
128 | #ifdef DEBUG_INT | |
129 | printf ("INTC isr %x, ier %x, iar %x, mer %x\n", intc->isr, intc->ier, | |
130 | intc->iar, intc->mer); | |
131 | #endif | |
132 | } | |
133 | ||
134 | int interrupts_init (void) | |
135 | { | |
136 | int i; | |
137 | /* initialize irq list */ | |
17980495 | 138 | for (i = 0; i < CFG_INTC_0_NUM; i++) { |
cfc67116 MS |
139 | vecs[i].handler = (interrupt_handler_t *) def_hdlr; |
140 | vecs[i].arg = (void *)i; | |
141 | vecs[i].count = 0; | |
142 | } | |
143 | /* initialize intc controller */ | |
144 | intc_init (); | |
145 | #ifdef CFG_TIMER_0 | |
146 | timer_init (); | |
fb7c2dbe MS |
147 | #endif |
148 | #ifdef CFG_FSL_2 | |
149 | fsl_init2 (); | |
cfc67116 MS |
150 | #endif |
151 | enable_interrupts (); | |
152 | return 0; | |
153 | } | |
154 | ||
155 | void interrupt_handler (void) | |
156 | { | |
42efed61 MS |
157 | int irqs = (intc->isr & intc->ier); /* find active interrupt */ |
158 | int i = 1; | |
cfc67116 | 159 | #ifdef DEBUG_INT |
42efed61 | 160 | int value; |
cfc67116 MS |
161 | printf ("INTC isr %x, ier %x, iar %x, mer %x\n", intc->isr, intc->ier, |
162 | intc->iar, intc->mer); | |
42efed61 | 163 | R14(value); |
cfc67116 MS |
164 | printf ("Interrupt handler on %x line, r14 %x\n", irqs, value); |
165 | #endif | |
166 | struct irq_action *act = vecs; | |
167 | while (irqs) { | |
168 | if (irqs & 1) { | |
169 | #ifdef DEBUG_INT | |
170 | printf | |
171 | ("Jumping to interrupt handler rutine addr %x,count %x,arg %x\n", | |
172 | act->handler, act->count, act->arg); | |
173 | #endif | |
174 | act->handler (act->arg); | |
175 | act->count++; | |
42efed61 MS |
176 | intc->iar = i; |
177 | return; | |
cfc67116 MS |
178 | } |
179 | irqs >>= 1; | |
180 | act++; | |
42efed61 | 181 | i <<= 1; |
cfc67116 | 182 | } |
42efed61 MS |
183 | |
184 | #ifdef DEBUG_INT | |
cfc67116 MS |
185 | printf ("Dump INTC reg, isr %x, ier %x, iar %x, mer %x\n", intc->isr, |
186 | intc->ier, intc->iar, intc->mer); | |
42efed61 MS |
187 | R14(value); |
188 | printf ("Interrupt handler on %x line, r14 %x\n", irqs, value); | |
cfc67116 MS |
189 | #endif |
190 | } | |
191 | #endif | |
192 | ||
4431283c | 193 | #if defined(CONFIG_CMD_IRQ) |
cfc67116 MS |
194 | #ifdef CFG_INTC_0 |
195 | int do_irqinfo (cmd_tbl_t * cmdtp, int flag, int argc, char *argv[]) | |
196 | { | |
197 | int i; | |
198 | struct irq_action *act = vecs; | |
199 | ||
200 | puts ("\nInterrupt-Information:\n\n" | |
201 | "Nr Routine Arg Count\n" | |
202 | "-----------------------------\n"); | |
203 | ||
17980495 | 204 | for (i = 0; i < CFG_INTC_0_NUM; i++) { |
cfc67116 MS |
205 | if (act->handler != (interrupt_handler_t*) def_hdlr) { |
206 | printf ("%02d %08lx %08lx %d\n", i, | |
207 | (int)act->handler, (int)act->arg, act->count); | |
208 | } | |
209 | act++; | |
210 | } | |
211 | puts ("\n"); | |
212 | return (0); | |
213 | } | |
214 | #else | |
215 | int do_irqinfo (cmd_tbl_t * cmdtp, int flag, int argc, char *argv[]) | |
216 | { | |
217 | puts ("Undefined interrupt controller\n"); | |
218 | } | |
219 | #endif | |
4431283c | 220 | #endif |