]>
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> | |
575a3d21 | 29 | #include <malloc.h> |
cfc67116 | 30 | #include <asm/microblaze_intc.h> |
42efed61 | 31 | #include <asm/asm.h> |
cfc67116 MS |
32 | |
33 | #undef DEBUG_INT | |
34 | ||
35 | extern void microblaze_disable_interrupts (void); | |
36 | extern void microblaze_enable_interrupts (void); | |
37 | ||
38 | void enable_interrupts (void) | |
507bbe3e | 39 | { |
fb05f6da | 40 | MSRSET(0x2); |
507bbe3e WD |
41 | } |
42 | ||
cfc67116 | 43 | int disable_interrupts (void) |
507bbe3e | 44 | { |
68e99e54 MS |
45 | unsigned int msr; |
46 | ||
47 | MFS(msr, rmsr); | |
fb05f6da | 48 | MSRCLR(0x2); |
68e99e54 | 49 | return (msr & 0x2) != 0; |
507bbe3e | 50 | } |
cfc67116 | 51 | |
575a3d21 MS |
52 | static struct irq_action *vecs; |
53 | static u32 irq_no; | |
cfc67116 MS |
54 | |
55 | /* mapping structure to interrupt controller */ | |
575a3d21 | 56 | microblaze_intc_t *intc; |
cfc67116 MS |
57 | |
58 | /* default handler */ | |
575a3d21 | 59 | static void def_hdlr(void) |
cfc67116 MS |
60 | { |
61 | puts ("def_hdlr\n"); | |
62 | } | |
63 | ||
575a3d21 | 64 | static void enable_one_interrupt(int irq) |
cfc67116 MS |
65 | { |
66 | int mask; | |
67 | int offset = 1; | |
68 | offset <<= irq; | |
69 | mask = intc->ier; | |
70 | intc->ier = (mask | offset); | |
71 | #ifdef DEBUG_INT | |
72 | printf ("Enable one interrupt irq %x - mask %x,ier %x\n", offset, mask, | |
73 | intc->ier); | |
74 | printf ("INTC isr %x, ier %x, iar %x, mer %x\n", intc->isr, intc->ier, | |
75 | intc->iar, intc->mer); | |
76 | #endif | |
77 | } | |
78 | ||
575a3d21 | 79 | static void disable_one_interrupt(int irq) |
cfc67116 MS |
80 | { |
81 | int mask; | |
82 | int offset = 1; | |
83 | offset <<= irq; | |
84 | mask = intc->ier; | |
85 | intc->ier = (mask & ~offset); | |
86 | #ifdef DEBUG_INT | |
87 | printf ("Disable one interrupt irq %x - mask %x,ier %x\n", irq, mask, | |
88 | intc->ier); | |
89 | printf ("INTC isr %x, ier %x, iar %x, mer %x\n", intc->isr, intc->ier, | |
90 | intc->iar, intc->mer); | |
91 | #endif | |
92 | } | |
93 | ||
94 | /* adding new handler for interrupt */ | |
95 | void install_interrupt_handler (int irq, interrupt_handler_t * hdlr, void *arg) | |
96 | { | |
97 | struct irq_action *act; | |
98 | /* irq out of range */ | |
575a3d21 | 99 | if ((irq < 0) || (irq > irq_no)) { |
cfc67116 MS |
100 | puts ("IRQ out of range\n"); |
101 | return; | |
102 | } | |
103 | act = &vecs[irq]; | |
104 | if (hdlr) { /* enable */ | |
105 | act->handler = hdlr; | |
106 | act->arg = arg; | |
107 | act->count = 0; | |
108 | enable_one_interrupt (irq); | |
109 | } else { /* disable */ | |
cfc67116 MS |
110 | act->handler = (interrupt_handler_t *) def_hdlr; |
111 | act->arg = (void *)irq; | |
112 | disable_one_interrupt (irq); | |
113 | } | |
114 | } | |
115 | ||
116 | /* initialization interrupt controller - hardware */ | |
575a3d21 | 117 | static void intc_init(void) |
cfc67116 MS |
118 | { |
119 | intc->mer = 0; | |
120 | intc->ier = 0; | |
121 | intc->iar = 0xFFFFFFFF; | |
122 | /* XIntc_Start - hw_interrupt enable and all interrupt enable */ | |
123 | intc->mer = 0x3; | |
124 | #ifdef DEBUG_INT | |
125 | printf ("INTC isr %x, ier %x, iar %x, mer %x\n", intc->isr, intc->ier, | |
126 | intc->iar, intc->mer); | |
127 | #endif | |
128 | } | |
129 | ||
575a3d21 | 130 | int interrupts_init(void) |
cfc67116 MS |
131 | { |
132 | int i; | |
575a3d21 MS |
133 | |
134 | #if defined(CONFIG_SYS_INTC_0_ADDR) && defined(CONFIG_SYS_INTC_0_NUM) | |
135 | intc = (microblaze_intc_t *) (CONFIG_SYS_INTC_0_ADDR); | |
136 | irq_no = CONFIG_SYS_INTC_0_NUM; | |
137 | #endif | |
138 | if (irq_no) { | |
139 | vecs = calloc(1, sizeof(struct irq_action) * irq_no); | |
140 | if (vecs == NULL) { | |
141 | puts("Interrupt vector allocation failed\n"); | |
142 | return -1; | |
143 | } | |
144 | ||
145 | /* initialize irq list */ | |
146 | for (i = 0; i < irq_no; i++) { | |
147 | vecs[i].handler = (interrupt_handler_t *) def_hdlr; | |
148 | vecs[i].arg = (void *)i; | |
149 | vecs[i].count = 0; | |
150 | } | |
151 | /* initialize intc controller */ | |
152 | intc_init(); | |
153 | enable_interrupts(); | |
154 | } else { | |
155 | puts("Undefined interrupt controller\n"); | |
cfc67116 | 156 | } |
cfc67116 MS |
157 | return 0; |
158 | } | |
159 | ||
160 | void interrupt_handler (void) | |
161 | { | |
8125c980 MS |
162 | int irqs = intc->ivr; /* find active interrupt */ |
163 | int mask = 1; | |
cfc67116 | 164 | #ifdef DEBUG_INT |
42efed61 | 165 | int value; |
cfc67116 MS |
166 | printf ("INTC isr %x, ier %x, iar %x, mer %x\n", intc->isr, intc->ier, |
167 | intc->iar, intc->mer); | |
42efed61 | 168 | R14(value); |
cfc67116 MS |
169 | printf ("Interrupt handler on %x line, r14 %x\n", irqs, value); |
170 | #endif | |
8125c980 MS |
171 | struct irq_action *act = vecs + irqs; |
172 | ||
cfc67116 | 173 | #ifdef DEBUG_INT |
8125c980 MS |
174 | printf |
175 | ("Jumping to interrupt handler rutine addr %x,count %x,arg %x\n", | |
176 | act->handler, act->count, act->arg); | |
cfc67116 | 177 | #endif |
8125c980 MS |
178 | act->handler (act->arg); |
179 | act->count++; | |
42efed61 | 180 | |
0f883267 SL |
181 | intc->iar = mask << irqs; |
182 | ||
42efed61 | 183 | #ifdef DEBUG_INT |
cfc67116 MS |
184 | printf ("Dump INTC reg, isr %x, ier %x, iar %x, mer %x\n", intc->isr, |
185 | intc->ier, intc->iar, intc->mer); | |
42efed61 MS |
186 | R14(value); |
187 | printf ("Interrupt handler on %x line, r14 %x\n", irqs, value); | |
cfc67116 MS |
188 | #endif |
189 | } | |
cfc67116 | 190 | |
4431283c | 191 | #if defined(CONFIG_CMD_IRQ) |
575a3d21 | 192 | int do_irqinfo(cmd_tbl_t *cmdtp, int flag, int argc, const char *argv[]) |
cfc67116 MS |
193 | { |
194 | int i; | |
195 | struct irq_action *act = vecs; | |
196 | ||
575a3d21 MS |
197 | if (irq_no) { |
198 | puts("\nInterrupt-Information:\n\n" | |
199 | "Nr Routine Arg Count\n" | |
200 | "-----------------------------\n"); | |
201 | ||
202 | for (i = 0; i < irq_no; i++) { | |
203 | if (act->handler != (interrupt_handler_t *) def_hdlr) { | |
204 | printf("%02d %08x %08x %d\n", i, | |
205 | (int)act->handler, (int)act->arg, | |
206 | act->count); | |
207 | } | |
208 | act++; | |
cfc67116 | 209 | } |
575a3d21 MS |
210 | puts("\n"); |
211 | } else { | |
212 | puts("Undefined interrupt controller\n"); | |
cfc67116 | 213 | } |
575a3d21 | 214 | return 0; |
cfc67116 MS |
215 | } |
216 | #endif |