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