]> git.sur5r.net Git - u-boot/blob - arch/nios2/cpu/interrupts.c
nios2: Switch to generic timer
[u-boot] / arch / nios2 / cpu / interrupts.c
1 /*
2  * (C) Copyright 2000-2002
3  * Wolfgang Denk, DENX Software Engineering, wd@denx.de.
4  *
5  * (C) Copyright 2004, Psyent Corporation <www.psyent.com>
6  * Scott McNutt <smcnutt@psyent.com>
7  *
8  * SPDX-License-Identifier:     GPL-2.0+
9  */
10
11 #include <asm/nios2.h>
12 #include <asm/types.h>
13 #include <asm/io.h>
14 #include <asm/ptrace.h>
15 #include <common.h>
16 #include <command.h>
17 #include <watchdog.h>
18 #ifdef CONFIG_STATUS_LED
19 #include <status_led.h>
20 #endif
21
22 struct nios_timer {
23         u32     status;         /* Timer status reg */
24         u32     control;        /* Timer control reg */
25         u32     periodl;        /* Timeout period low */
26         u32     periodh;        /* Timeout period high */
27         u32     snapl;          /* Snapshot low */
28         u32     snaph;          /* Snapshot high */
29 };
30
31 /* status register */
32 #define NIOS_TIMER_TO           (1 << 0)        /* Timeout */
33 #define NIOS_TIMER_RUN          (1 << 1)        /* Timer running */
34
35 /* control register */
36 #define NIOS_TIMER_ITO          (1 << 0)        /* Timeout int ena */
37 #define NIOS_TIMER_CONT         (1 << 1)        /* Continuous mode */
38 #define NIOS_TIMER_START        (1 << 2)        /* Start timer */
39 #define NIOS_TIMER_STOP         (1 << 3)        /* Stop timer */
40
41 #if defined(CONFIG_SYS_TIMER_BASE) && !defined(CONFIG_SYS_TIMER_IRQ)
42 #error CONFIG_SYS_TIMER_IRQ not defined (see documentation)
43 #endif
44
45 /****************************************************************************/
46
47 struct  irq_action {
48         interrupt_handler_t *handler;
49         void *arg;
50         int count;
51 };
52
53 static struct irq_action vecs[32];
54
55 /*************************************************************************/
56 static volatile ulong timestamp;
57
58 /*
59  * The board must handle this interrupt if a timer is not
60  * provided.
61  */
62 void tmr_isr (void *arg)
63 {
64         struct nios_timer *tmr = (struct nios_timer *)arg;
65         /* Interrupt is cleared by writing anything to the
66          * status register.
67          */
68         writel (0, &tmr->status);
69         timestamp += CONFIG_SYS_NIOS_TMRMS;
70 #ifdef CONFIG_STATUS_LED
71         status_led_tick(timestamp);
72 #endif
73 }
74
75 unsigned long notrace timer_read_counter(void)
76 {
77         struct nios_timer *tmr = (struct nios_timer *)CONFIG_SYS_TIMER_BASE;
78         u32 val;
79
80         /* Trigger update */
81         writel(0x0, &tmr->snapl);
82
83         /* Read timer value */
84         val = readl(&tmr->snapl) & 0xffff;
85         val |= (readl(&tmr->snaph) & 0xffff) << 16;
86
87         return ~val;
88 }
89
90 int timer_init(void)
91 {
92         struct nios_timer *tmr = (struct nios_timer *)CONFIG_SYS_TIMER_BASE;
93
94         writel (0, &tmr->status);
95         writel (0, &tmr->control);
96         writel (NIOS_TIMER_STOP, &tmr->control);
97
98         writel (0xffff, &tmr->periodl);
99         writel (0xffff, &tmr->periodh);
100
101         writel (NIOS_TIMER_CONT | NIOS_TIMER_START, &tmr->control);
102         /* FIXME */
103         irq_install_handler(CONFIG_SYS_TIMER_IRQ, tmr_isr, (void *)tmr);
104
105         return 0;
106 }
107
108 /*************************************************************************/
109 int disable_interrupts (void)
110 {
111         int val = rdctl (CTL_STATUS);
112         wrctl (CTL_STATUS, val & ~STATUS_IE);
113         return (val & STATUS_IE);
114 }
115
116 void enable_interrupts( void )
117 {
118         int val = rdctl (CTL_STATUS);
119         wrctl (CTL_STATUS, val | STATUS_IE);
120 }
121
122 void external_interrupt (struct pt_regs *regs)
123 {
124         unsigned irqs;
125         struct irq_action *act;
126
127         /* Evaluate only irqs that are both enabled AND pending */
128         irqs = rdctl (CTL_IENABLE) & rdctl (CTL_IPENDING);
129         act = vecs;
130
131         /* Assume (as does the Nios2 HAL) that bit 0 is highest
132          * priority. NOTE: There is ALWAYS a handler assigned
133          * (the default if no other).
134          */
135         while (irqs) {
136                 if (irqs & 1) {
137                         act->handler (act->arg);
138                         act->count++;
139                 }
140                 irqs >>=1;
141                 act++;
142         }
143 }
144
145 static void def_hdlr (void *arg)
146 {
147         unsigned irqs = rdctl (CTL_IENABLE);
148
149         /* Disable the individual interrupt -- with gratuitous
150          * warning.
151          */
152         irqs &= ~(1 << (int)arg);
153         wrctl (CTL_IENABLE, irqs);
154         printf ("WARNING: Disabling unhandled interrupt: %d\n",
155                         (int)arg);
156 }
157
158 /*************************************************************************/
159 void irq_install_handler (int irq, interrupt_handler_t *hdlr, void *arg)
160 {
161
162         int flag;
163         struct irq_action *act;
164         unsigned ena = rdctl (CTL_IENABLE);
165
166         if ((irq < 0) || (irq > 31))
167                 return;
168         act = &vecs[irq];
169
170         flag = disable_interrupts ();
171         if (hdlr) {
172                 act->handler = hdlr;
173                 act->arg = arg;
174                 ena |= (1 << irq);              /* enable */
175         } else {
176                 act->handler = def_hdlr;
177                 act->arg = (void *)irq;
178                 ena &= ~(1 << irq);             /* disable */
179         }
180         wrctl (CTL_IENABLE, ena);
181         if (flag) enable_interrupts ();
182 }
183
184
185 int interrupt_init (void)
186 {
187         int i;
188
189         /* Assign the default handler to all */
190         for (i = 0; i < 32; i++) {
191                 vecs[i].handler = def_hdlr;
192                 vecs[i].arg = (void *)i;
193                 vecs[i].count = 0;
194         }
195
196         enable_interrupts ();
197         return (0);
198 }
199
200
201 /*************************************************************************/
202 #if defined(CONFIG_CMD_IRQ)
203 int do_irqinfo (cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
204 {
205         int i;
206         struct irq_action *act = vecs;
207
208         printf ("\nInterrupt-Information:\n\n");
209         printf ("Nr  Routine   Arg       Count\n");
210         printf ("-----------------------------\n");
211
212         for (i=0; i<32; i++) {
213                 if (act->handler != def_hdlr) {
214                         printf ("%02d  %08lx  %08lx  %d\n",
215                                 i,
216                                 (ulong)act->handler,
217                                 (ulong)act->arg,
218                                 act->count);
219                 }
220                 act++;
221         }
222         printf ("\n");
223
224         return (0);
225 }
226 #endif