/* * (C) Copyright 2007 Michal Simek * (C) Copyright 2004 Atmark Techno, Inc. * * Michal SIMEK * Yasushi SHOJI * * SPDX-License-Identifier: GPL-2.0+ */ #include #include #include #include #include #undef DEBUG_INT void enable_interrupts(void) { MSRSET(0x2); } int disable_interrupts(void) { unsigned int msr; MFS(msr, rmsr); MSRCLR(0x2); return (msr & 0x2) != 0; } static struct irq_action *vecs; static u32 irq_no; /* mapping structure to interrupt controller */ microblaze_intc_t *intc; /* default handler */ static void def_hdlr(void) { puts("def_hdlr\n"); } static void enable_one_interrupt(int irq) { int mask; int offset = 1; offset <<= irq; mask = intc->ier; intc->ier = (mask | offset); #ifdef DEBUG_INT printf("Enable one interrupt irq %x - mask %x,ier %x\n", offset, mask, intc->ier); printf("INTC isr %x, ier %x, iar %x, mer %x\n", intc->isr, intc->ier, intc->iar, intc->mer); #endif } static void disable_one_interrupt(int irq) { int mask; int offset = 1; offset <<= irq; mask = intc->ier; intc->ier = (mask & ~offset); #ifdef DEBUG_INT printf("Disable one interrupt irq %x - mask %x,ier %x\n", irq, mask, intc->ier); printf("INTC isr %x, ier %x, iar %x, mer %x\n", intc->isr, intc->ier, intc->iar, intc->mer); #endif } int install_interrupt_handler(int irq, interrupt_handler_t *hdlr, void *arg) { struct irq_action *act; /* irq out of range */ if ((irq < 0) || (irq > irq_no)) { puts("IRQ out of range\n"); return -1; } act = &vecs[irq]; if (hdlr) { /* enable */ act->handler = hdlr; act->arg = arg; act->count = 0; enable_one_interrupt (irq); return 0; } /* Disable */ act->handler = (interrupt_handler_t *) def_hdlr; act->arg = (void *)irq; disable_one_interrupt(irq); return 1; } /* initialization interrupt controller - hardware */ static void intc_init(void) { intc->mer = 0; intc->ier = 0; intc->iar = 0xFFFFFFFF; /* XIntc_Start - hw_interrupt enable and all interrupt enable */ intc->mer = 0x3; #ifdef DEBUG_INT printf("INTC isr %x, ier %x, iar %x, mer %x\n", intc->isr, intc->ier, intc->iar, intc->mer); #endif } int interrupts_init(void) { int i; #if defined(CONFIG_SYS_INTC_0_ADDR) && defined(CONFIG_SYS_INTC_0_NUM) intc = (microblaze_intc_t *) (CONFIG_SYS_INTC_0_ADDR); irq_no = CONFIG_SYS_INTC_0_NUM; #endif if (irq_no) { vecs = calloc(1, sizeof(struct irq_action) * irq_no); if (vecs == NULL) { puts("Interrupt vector allocation failed\n"); return -1; } /* initialize irq list */ for (i = 0; i < irq_no; i++) { vecs[i].handler = (interrupt_handler_t *) def_hdlr; vecs[i].arg = (void *)i; vecs[i].count = 0; } /* initialize intc controller */ intc_init(); enable_interrupts(); } else { puts("Undefined interrupt controller\n"); } return 0; } void interrupt_handler(void) { int irqs = intc->ivr; /* find active interrupt */ int mask = 1; #ifdef DEBUG_INT int value; printf ("INTC isr %x, ier %x, iar %x, mer %x\n", intc->isr, intc->ier, intc->iar, intc->mer); R14(value); printf ("Interrupt handler on %x line, r14 %x\n", irqs, value); #endif struct irq_action *act = vecs + irqs; #ifdef DEBUG_INT printf ("Jumping to interrupt handler rutine addr %x,count %x,arg %x\n", act->handler, act->count, act->arg); #endif act->handler (act->arg); act->count++; intc->iar = mask << irqs; #ifdef DEBUG_INT printf ("Dump INTC reg, isr %x, ier %x, iar %x, mer %x\n", intc->isr, intc->ier, intc->iar, intc->mer); R14(value); printf ("Interrupt handler on %x line, r14 %x\n", irqs, value); #endif } #if defined(CONFIG_CMD_IRQ) int do_irqinfo(cmd_tbl_t *cmdtp, int flag, int argc, const char *argv[]) { int i; struct irq_action *act = vecs; if (irq_no) { puts("\nInterrupt-Information:\n\n" "Nr Routine Arg Count\n" "-----------------------------\n"); for (i = 0; i < irq_no; i++) { if (act->handler != (interrupt_handler_t *) def_hdlr) { printf("%02d %08x %08x %d\n", i, (int)act->handler, (int)act->arg, act->count); } act++; } puts("\n"); } else { puts("Undefined interrupt controller\n"); } return 0; } #endif