|  | /* | 
|  | * (C) Copyright 2007 Michal Simek | 
|  | * (C) Copyright 2004 Atmark Techno, Inc. | 
|  | * | 
|  | * Michal  SIMEK <monstr@monstr.eu> | 
|  | * Yasushi SHOJI <yashi@atmark-techno.com> | 
|  | * | 
|  | * See file CREDITS for list of people who contributed to this | 
|  | * project. | 
|  | * | 
|  | * This program is free software; you can redistribute it and/or | 
|  | * modify it under the terms of the GNU General Public License as | 
|  | * published by the Free Software Foundation; either version 2 of | 
|  | * the License, or (at your option) any later version. | 
|  | * | 
|  | * This program is distributed in the hope that it will be useful, | 
|  | * but WITHOUT ANY WARRANTY; without even the implied warranty of | 
|  | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | 
|  | * GNU General Public License for more details. | 
|  | * | 
|  | * You should have received a copy of the GNU General Public License | 
|  | * along with this program; if not, write to the Free Software | 
|  | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, | 
|  | * MA 02111-1307 USA | 
|  | */ | 
|  |  | 
|  | #include <common.h> | 
|  | #include <command.h> | 
|  | #include <asm/microblaze_intc.h> | 
|  | #include <asm/asm.h> | 
|  |  | 
|  | #undef DEBUG_INT | 
|  |  | 
|  | extern void microblaze_disable_interrupts (void); | 
|  | extern void microblaze_enable_interrupts (void); | 
|  |  | 
|  | void enable_interrupts (void) | 
|  | { | 
|  | MSRSET(0x2); | 
|  | } | 
|  |  | 
|  | int disable_interrupts (void) | 
|  | { | 
|  | MSRCLR(0x2); | 
|  | return 0; | 
|  | } | 
|  |  | 
|  | #ifdef CFG_INTC_0 | 
|  | #ifdef CFG_TIMER_0 | 
|  | extern void timer_init (void); | 
|  | #endif | 
|  | #ifdef CFG_FSL_2 | 
|  | extern void fsl_init2 (void); | 
|  | #endif | 
|  |  | 
|  |  | 
|  | static struct irq_action vecs[CFG_INTC_0_NUM]; | 
|  |  | 
|  | /* mapping structure to interrupt controller */ | 
|  | microblaze_intc_t *intc = (microblaze_intc_t *) (CFG_INTC_0_ADDR); | 
|  |  | 
|  | /* default handler */ | 
|  | void def_hdlr (void) | 
|  | { | 
|  | puts ("def_hdlr\n"); | 
|  | } | 
|  |  | 
|  | 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 | 
|  | } | 
|  |  | 
|  | 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 | 
|  | } | 
|  |  | 
|  | /* adding new handler for interrupt */ | 
|  | void install_interrupt_handler (int irq, interrupt_handler_t * hdlr, void *arg) | 
|  | { | 
|  | struct irq_action *act; | 
|  | /* irq out of range */ | 
|  | if ((irq < 0) || (irq > CFG_INTC_0_NUM)) { | 
|  | puts ("IRQ out of range\n"); | 
|  | return; | 
|  | } | 
|  | act = &vecs[irq]; | 
|  | if (hdlr) {		/* enable */ | 
|  | act->handler = hdlr; | 
|  | act->arg = arg; | 
|  | act->count = 0; | 
|  | enable_one_interrupt (irq); | 
|  | } else {		/* disable */ | 
|  | act->handler = (interrupt_handler_t *) def_hdlr; | 
|  | act->arg = (void *)irq; | 
|  | disable_one_interrupt (irq); | 
|  | } | 
|  | } | 
|  |  | 
|  | /* initialization interrupt controller - hardware */ | 
|  | 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; | 
|  | /* initialize irq list */ | 
|  | for (i = 0; i < CFG_INTC_0_NUM; i++) { | 
|  | vecs[i].handler = (interrupt_handler_t *) def_hdlr; | 
|  | vecs[i].arg = (void *)i; | 
|  | vecs[i].count = 0; | 
|  | } | 
|  | /* initialize intc controller */ | 
|  | intc_init (); | 
|  | #ifdef CFG_TIMER_0 | 
|  | timer_init (); | 
|  | #endif | 
|  | #ifdef CFG_FSL_2 | 
|  | fsl_init2 (); | 
|  | #endif | 
|  | enable_interrupts (); | 
|  | return 0; | 
|  | } | 
|  |  | 
|  | void interrupt_handler (void) | 
|  | { | 
|  | int irqs = (intc->isr & intc->ier);	/* find active interrupt */ | 
|  | int i = 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; | 
|  | while (irqs) { | 
|  | if (irqs & 1) { | 
|  | #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 = i; | 
|  | return; | 
|  | } | 
|  | irqs >>= 1; | 
|  | act++; | 
|  | i <<= 1; | 
|  | } | 
|  |  | 
|  | #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 | 
|  | } | 
|  | #endif | 
|  |  | 
|  | #if defined(CONFIG_CMD_IRQ) | 
|  | #ifdef CFG_INTC_0 | 
|  | int do_irqinfo (cmd_tbl_t * cmdtp, int flag, int argc, char *argv[]) | 
|  | { | 
|  | int i; | 
|  | struct irq_action *act = vecs; | 
|  |  | 
|  | puts ("\nInterrupt-Information:\n\n" | 
|  | "Nr  Routine   Arg       Count\n" | 
|  | "-----------------------------\n"); | 
|  |  | 
|  | for (i = 0; i < CFG_INTC_0_NUM; i++) { | 
|  | if (act->handler != (interrupt_handler_t*) def_hdlr) { | 
|  | printf ("%02d  %08lx  %08lx  %d\n", i, | 
|  | (int)act->handler, (int)act->arg, act->count); | 
|  | } | 
|  | act++; | 
|  | } | 
|  | puts ("\n"); | 
|  | return (0); | 
|  | } | 
|  | #else | 
|  | int do_irqinfo (cmd_tbl_t * cmdtp, int flag, int argc, char *argv[]) | 
|  | { | 
|  | puts ("Undefined interrupt controller\n"); | 
|  | } | 
|  | #endif | 
|  | #endif |