1 /* 2 * (C) Copyright 2007 Michal Simek 3 * (C) Copyright 2004 Atmark Techno, Inc. 4 * 5 * Michal SIMEK <monstr@monstr.eu> 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 18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 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 27 #include <common.h> 28 #include <command.h> 29 #include <malloc.h> 30 #include <asm/microblaze_intc.h> 31 #include <asm/asm.h> 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) 39 { 40 MSRSET(0x2); 41 } 42 43 int disable_interrupts (void) 44 { 45 unsigned int msr; 46 47 MFS(msr, rmsr); 48 MSRCLR(0x2); 49 return (msr & 0x2) != 0; 50 } 51 52 static struct irq_action *vecs; 53 static u32 irq_no; 54 55 /* mapping structure to interrupt controller */ 56 microblaze_intc_t *intc; 57 58 /* default handler */ 59 static void def_hdlr(void) 60 { 61 puts ("def_hdlr\n"); 62 } 63 64 static void enable_one_interrupt(int irq) 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 79 static void disable_one_interrupt(int irq) 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 */ 99 if ((irq < 0) || (irq > irq_no)) { 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 */ 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 */ 117 static void intc_init(void) 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 130 int interrupts_init(void) 131 { 132 int i; 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"); 156 } 157 return 0; 158 } 159 160 void interrupt_handler (void) 161 { 162 int irqs = intc->ivr; /* find active interrupt */ 163 int mask = 1; 164 #ifdef DEBUG_INT 165 int value; 166 printf ("INTC isr %x, ier %x, iar %x, mer %x\n", intc->isr, intc->ier, 167 intc->iar, intc->mer); 168 R14(value); 169 printf ("Interrupt handler on %x line, r14 %x\n", irqs, value); 170 #endif 171 struct irq_action *act = vecs + irqs; 172 173 #ifdef DEBUG_INT 174 printf 175 ("Jumping to interrupt handler rutine addr %x,count %x,arg %x\n", 176 act->handler, act->count, act->arg); 177 #endif 178 act->handler (act->arg); 179 act->count++; 180 181 intc->iar = mask << irqs; 182 183 #ifdef DEBUG_INT 184 printf ("Dump INTC reg, isr %x, ier %x, iar %x, mer %x\n", intc->isr, 185 intc->ier, intc->iar, intc->mer); 186 R14(value); 187 printf ("Interrupt handler on %x line, r14 %x\n", irqs, value); 188 #endif 189 } 190 191 #if defined(CONFIG_CMD_IRQ) 192 int do_irqinfo(cmd_tbl_t *cmdtp, int flag, int argc, const char *argv[]) 193 { 194 int i; 195 struct irq_action *act = vecs; 196 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++; 209 } 210 puts("\n"); 211 } else { 212 puts("Undefined interrupt controller\n"); 213 } 214 return 0; 215 } 216 #endif 217