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