uboot/cpu/nios/interrupts.c
<<
>>
Prefs
   1/*
   2 * (C) Copyright 2000-2002
   3 * Wolfgang Denk, DENX Software Engineering, wd@denx.de.
   4 *
   5 * (C) Copyright 2003, Psyent Corporation <www.psyent.com>
   6 * Scott McNutt <smcnutt@psyent.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
  28#include <nios.h>
  29#include <nios-io.h>
  30#include <asm/ptrace.h>
  31#include <common.h>
  32#include <command.h>
  33#include <watchdog.h>
  34#ifdef CONFIG_STATUS_LED
  35#include <status_led.h>
  36#endif
  37
  38/****************************************************************************/
  39
  40struct  irq_action {
  41        interrupt_handler_t *handler;
  42        void *arg;
  43        int count;
  44};
  45
  46static struct irq_action irq_vecs[64];
  47
  48/*************************************************************************/
  49volatile ulong timestamp = 0;
  50
  51void reset_timer (void)
  52{
  53        timestamp = 0;
  54}
  55
  56ulong get_timer (ulong base)
  57{
  58        WATCHDOG_RESET ();
  59        return (timestamp - base);
  60}
  61
  62void set_timer (ulong t)
  63{
  64        timestamp = t;
  65}
  66
  67
  68/* The board must handle this interrupt if a timer is not
  69 * provided.
  70 */
  71#if defined(CONFIG_SYS_NIOS_TMRBASE)
  72void timer_interrupt (struct pt_regs *regs)
  73{
  74        /* Interrupt is cleared by writing anything to the
  75         * status register.
  76         */
  77        nios_timer_t *tmr = (nios_timer_t *)CONFIG_SYS_NIOS_TMRBASE;
  78        tmr->status = 0;
  79        timestamp += CONFIG_SYS_NIOS_TMRMS;
  80#ifdef CONFIG_STATUS_LED
  81        status_led_tick(timestamp);
  82#endif
  83}
  84#endif
  85
  86/*************************************************************************/
  87int disable_interrupts (void)
  88{
  89        int val = 0;
  90
  91        /* Writing anything to CLR_IE disables interrupts */
  92        val = rdctl (CTL_STATUS);
  93        wrctl (CTL_CLR_IE, 0);
  94        return (val & STATUS_IE);
  95}
  96
  97void enable_interrupts( void )
  98{
  99        /* Writing anything SET_IE enables interrupts */
 100        wrctl (CTL_SET_IE, 0);
 101}
 102
 103void external_interrupt (struct pt_regs *regs)
 104{
 105        unsigned vec;
 106
 107        vec = (regs->status & STATUS_IPRI) >> 9;        /* ipri */
 108
 109        irq_vecs[vec].count++;
 110        if (irq_vecs[vec].handler != NULL) {
 111                (*irq_vecs[vec].handler)(irq_vecs[vec].arg);
 112        } else {
 113                /* A sad side-effect of masking a bogus interrupt is
 114                 * that lower priority interrupts will also be disabled.
 115                 * This is probably not what we want ... so hang insted.
 116                 */
 117                printf ("Unhandled interrupt: 0x%x\n", vec);
 118                disable_interrupts ();
 119                hang ();
 120        }
 121}
 122
 123/*************************************************************************/
 124int interrupt_init (void)
 125{
 126        int vec;
 127
 128#if defined(CONFIG_SYS_NIOS_TMRBASE)
 129        nios_timer_t *tmr = (nios_timer_t *)CONFIG_SYS_NIOS_TMRBASE;
 130
 131        tmr->control &= ~NIOS_TIMER_ITO;
 132        tmr->control |= NIOS_TIMER_STOP;
 133#if defined(CONFIG_SYS_NIOS_TMRCNT)
 134        tmr->periodl = CONFIG_SYS_NIOS_TMRCNT & 0xffff;
 135        tmr->periodh = (CONFIG_SYS_NIOS_TMRCNT >> 16) & 0xffff;
 136#endif
 137#endif
 138
 139        for (vec=0; vec<64; vec++ ) {
 140                irq_vecs[vec].handler = NULL;
 141                irq_vecs[vec].arg = NULL;
 142                irq_vecs[vec].count = 0;
 143        }
 144
 145        /* Need timus interruptus -- start the lopri timer */
 146#if defined(CONFIG_SYS_NIOS_TMRBASE)
 147        tmr->control |= ( NIOS_TIMER_ITO |
 148                          NIOS_TIMER_CONT |
 149                          NIOS_TIMER_START );
 150        ipri (CONFIG_SYS_NIOS_TMRIRQ + 1);
 151#endif
 152        enable_interrupts ();
 153        return (0);
 154}
 155
 156void irq_install_handler (int vec, interrupt_handler_t *handler, void *arg)
 157{
 158        struct irq_action *irqa = irq_vecs;
 159        int   i = vec;
 160        int flag;
 161
 162        if (irqa[i].handler != NULL) {
 163                printf ("Interrupt vector %d: handler 0x%x "
 164                        "replacing 0x%x\n",
 165                        vec, (uint)handler, (uint)irqa[i].handler);
 166        }
 167
 168        flag = disable_interrupts ();
 169        irqa[i].handler = handler;
 170        irqa[i].arg = arg;
 171        if (flag )
 172                enable_interrupts ();
 173}
 174
 175/*************************************************************************/
 176#if defined(CONFIG_CMD_IRQ)
 177int do_irqinfo (cmd_tbl_t *cmdtp, int flag, int argc, char *argv[])
 178{
 179        int vec;
 180
 181        printf ("\nInterrupt-Information:\n");
 182        printf ("Nr  Routine   Arg       Count\n");
 183
 184        for (vec=0; vec<64; vec++) {
 185                if (irq_vecs[vec].handler != NULL) {
 186                        printf ("%02d  %08lx  %08lx  %d\n",
 187                                vec,
 188                                (ulong)irq_vecs[vec].handler<<1,
 189                                (ulong)irq_vecs[vec].arg,
 190                                irq_vecs[vec].count);
 191                }
 192        }
 193
 194        return (0);
 195}
 196#endif
 197