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