~pmdj/ubuntu/trusty/qemu/2.9+applesmc+fadtv3

« back to all changes in this revision

Viewing changes to roms/u-boot/arch/nios2/cpu/interrupts.c

  • Committer: Phil Dennis-Jordan
  • Date: 2017-07-21 08:03:43 UTC
  • mfrom: (1.1.1)
  • Revision ID: phil@philjordan.eu-20170721080343-2yr2vdj7713czahv
New upstream release 2.9.0.

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
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
 
 
12
#include <nios2.h>
 
13
#include <nios2-io.h>
 
14
#include <asm/types.h>
 
15
#include <asm/io.h>
 
16
#include <asm/ptrace.h>
 
17
#include <common.h>
 
18
#include <command.h>
 
19
#include <watchdog.h>
 
20
#ifdef CONFIG_STATUS_LED
 
21
#include <status_led.h>
 
22
#endif
 
23
 
 
24
#if defined(CONFIG_SYS_NIOS_TMRBASE) && !defined(CONFIG_SYS_NIOS_TMRIRQ)
 
25
#error CONFIG_SYS_NIOS_TMRIRQ not defined (see documentation)
 
26
#endif
 
27
 
 
28
/****************************************************************************/
 
29
 
 
30
struct  irq_action {
 
31
        interrupt_handler_t *handler;
 
32
        void *arg;
 
33
        int count;
 
34
};
 
35
 
 
36
static struct irq_action vecs[32];
 
37
 
 
38
/*************************************************************************/
 
39
volatile ulong timestamp = 0;
 
40
 
 
41
void reset_timer (void)
 
42
{
 
43
        nios_timer_t *tmr =(nios_timer_t *)CONFIG_SYS_NIOS_TMRBASE;
 
44
 
 
45
        /* From Embedded Peripherals Handbook:
 
46
         *
 
47
         * "When the hardware is configured with Writeable period
 
48
         * disabled, writing to one of the period_n registers causes
 
49
         * the counter to reset to the fixed Timeout Period specified
 
50
         * at system generation time."
 
51
         *
 
52
         * Here we force a reload to prevent early timeouts from
 
53
         * get_timer() when the interrupt period is greater than
 
54
         * than 1 msec.
 
55
         *
 
56
         * Simply write to periodl with its own value to force an
 
57
         * internal counter reload, THEN reset the timestamp.
 
58
         */
 
59
        writel (readl (&tmr->periodl), &tmr->periodl);
 
60
        timestamp = 0;
 
61
 
 
62
        /* From Embedded Peripherals Handbook:
 
63
         *
 
64
         * "Writing to one of the period_n registers stops the internal
 
65
         * counter, except when the hardware is configured with Start/Stop
 
66
         * control bits off. If Start/Stop control bits is off, writing
 
67
         * either register does not stop the counter."
 
68
         *
 
69
         * In order to accomodate either configuration, the control
 
70
         * register is re-written. If the counter is stopped, it will
 
71
         * be restarted. If it is running, the write is essentially
 
72
         * a nop.
 
73
         */
 
74
        writel (NIOS_TIMER_ITO | NIOS_TIMER_CONT | NIOS_TIMER_START,
 
75
                        &tmr->control);
 
76
 
 
77
}
 
78
 
 
79
ulong get_timer (ulong base)
 
80
{
 
81
        WATCHDOG_RESET ();
 
82
        return (timestamp - base);
 
83
}
 
84
 
 
85
/*
 
86
 * This function is derived from Blackfin code (read timebase as long long).
 
87
 * On Nios2 it just returns the timer value.
 
88
 */
 
89
unsigned long long get_ticks(void)
 
90
{
 
91
        return get_timer(0);
 
92
}
 
93
 
 
94
/*
 
95
 * This function is derived from Blackfin code.
 
96
 * On Nios2 it returns the number of timer ticks per second.
 
97
 */
 
98
ulong get_tbclk(void)
 
99
{
 
100
        ulong tbclk;
 
101
 
 
102
        tbclk = CONFIG_SYS_HZ;
 
103
        return tbclk;
 
104
}
 
105
 
 
106
/* The board must handle this interrupt if a timer is not
 
107
 * provided.
 
108
 */
 
109
#if defined(CONFIG_SYS_NIOS_TMRBASE)
 
110
void tmr_isr (void *arg)
 
111
{
 
112
        nios_timer_t *tmr = (nios_timer_t *)arg;
 
113
        /* Interrupt is cleared by writing anything to the
 
114
         * status register.
 
115
         */
 
116
        writel (0, &tmr->status);
 
117
        timestamp += CONFIG_SYS_NIOS_TMRMS;
 
118
#ifdef CONFIG_STATUS_LED
 
119
        status_led_tick(timestamp);
 
120
#endif
 
121
}
 
122
 
 
123
static void tmr_init (void)
 
124
{
 
125
        nios_timer_t *tmr =(nios_timer_t *)CONFIG_SYS_NIOS_TMRBASE;
 
126
 
 
127
        writel (0, &tmr->status);
 
128
        writel (0, &tmr->control);
 
129
        writel (NIOS_TIMER_STOP, &tmr->control);
 
130
 
 
131
#if defined(CONFIG_SYS_NIOS_TMRCNT)
 
132
        writel (CONFIG_SYS_NIOS_TMRCNT & 0xffff, &tmr->periodl);
 
133
        writel ((CONFIG_SYS_NIOS_TMRCNT >> 16) & 0xffff, &tmr->periodh);
 
134
#endif
 
135
        writel (NIOS_TIMER_ITO | NIOS_TIMER_CONT | NIOS_TIMER_START,
 
136
                        &tmr->control);
 
137
        irq_install_handler (CONFIG_SYS_NIOS_TMRIRQ, tmr_isr, (void *)tmr);
 
138
}
 
139
 
 
140
#endif /* CONFIG_SYS_NIOS_TMRBASE */
 
141
 
 
142
/*************************************************************************/
 
143
int disable_interrupts (void)
 
144
{
 
145
        int val = rdctl (CTL_STATUS);
 
146
        wrctl (CTL_STATUS, val & ~STATUS_IE);
 
147
        return (val & STATUS_IE);
 
148
}
 
149
 
 
150
void enable_interrupts( void )
 
151
{
 
152
        int val = rdctl (CTL_STATUS);
 
153
        wrctl (CTL_STATUS, val | STATUS_IE);
 
154
}
 
155
 
 
156
void external_interrupt (struct pt_regs *regs)
 
157
{
 
158
        unsigned irqs;
 
159
        struct irq_action *act;
 
160
 
 
161
        /* Evaluate only irqs that are both enabled AND pending */
 
162
        irqs = rdctl (CTL_IENABLE) & rdctl (CTL_IPENDING);
 
163
        act = vecs;
 
164
 
 
165
        /* Assume (as does the Nios2 HAL) that bit 0 is highest
 
166
         * priority. NOTE: There is ALWAYS a handler assigned
 
167
         * (the default if no other).
 
168
         */
 
169
        while (irqs) {
 
170
                if (irqs & 1) {
 
171
                        act->handler (act->arg);
 
172
                        act->count++;
 
173
                }
 
174
                irqs >>=1;
 
175
                act++;
 
176
        }
 
177
}
 
178
 
 
179
static void def_hdlr (void *arg)
 
180
{
 
181
        unsigned irqs = rdctl (CTL_IENABLE);
 
182
 
 
183
        /* Disable the individual interrupt -- with gratuitous
 
184
         * warning.
 
185
         */
 
186
        irqs &= ~(1 << (int)arg);
 
187
        wrctl (CTL_IENABLE, irqs);
 
188
        printf ("WARNING: Disabling unhandled interrupt: %d\n",
 
189
                        (int)arg);
 
190
}
 
191
 
 
192
/*************************************************************************/
 
193
void irq_install_handler (int irq, interrupt_handler_t *hdlr, void *arg)
 
194
{
 
195
 
 
196
        int flag;
 
197
        struct irq_action *act;
 
198
        unsigned ena = rdctl (CTL_IENABLE);
 
199
 
 
200
        if ((irq < 0) || (irq > 31))
 
201
                return;
 
202
        act = &vecs[irq];
 
203
 
 
204
        flag = disable_interrupts ();
 
205
        if (hdlr) {
 
206
                act->handler = hdlr;
 
207
                act->arg = arg;
 
208
                ena |= (1 << irq);              /* enable */
 
209
        } else {
 
210
                act->handler = def_hdlr;
 
211
                act->arg = (void *)irq;
 
212
                ena &= ~(1 << irq);             /* disable */
 
213
        }
 
214
        wrctl (CTL_IENABLE, ena);
 
215
        if (flag) enable_interrupts ();
 
216
}
 
217
 
 
218
 
 
219
int interrupt_init (void)
 
220
{
 
221
        int i;
 
222
 
 
223
        /* Assign the default handler to all */
 
224
        for (i = 0; i < 32; i++) {
 
225
                vecs[i].handler = def_hdlr;
 
226
                vecs[i].arg = (void *)i;
 
227
                vecs[i].count = 0;
 
228
        }
 
229
 
 
230
#if defined(CONFIG_SYS_NIOS_TMRBASE)
 
231
        tmr_init ();
 
232
#endif
 
233
 
 
234
        enable_interrupts ();
 
235
        return (0);
 
236
}
 
237
 
 
238
 
 
239
/*************************************************************************/
 
240
#if defined(CONFIG_CMD_IRQ)
 
241
int do_irqinfo (cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
 
242
{
 
243
        int i;
 
244
        struct irq_action *act = vecs;
 
245
 
 
246
        printf ("\nInterrupt-Information:\n\n");
 
247
        printf ("Nr  Routine   Arg       Count\n");
 
248
        printf ("-----------------------------\n");
 
249
 
 
250
        for (i=0; i<32; i++) {
 
251
                if (act->handler != def_hdlr) {
 
252
                        printf ("%02d  %08lx  %08lx  %d\n",
 
253
                                i,
 
254
                                (ulong)act->handler,
 
255
                                (ulong)act->arg,
 
256
                                act->count);
 
257
                }
 
258
                act++;
 
259
        }
 
260
        printf ("\n");
 
261
 
 
262
        return (0);
 
263
}
 
264
#endif