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