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