Project

General

Profile

Statistics
| Branch: | Revision:

scoutos / prex-0.9.0 / bsp / hal / arm / gba / interrupt.c @ 03e9c04a

History | View | Annotate | Download (4.99 KB)

1 03e9c04a Brad Neuman
/*-
2
 * Copyright (c) 2005-2007, Kohsuke Ohtani
3
 * All rights reserved.
4
 *
5
 * Redistribution and use in source and binary forms, with or without
6
 * modification, are permitted provided that the following conditions
7
 * are met:
8
 * 1. Redistributions of source code must retain the above copyright
9
 *    notice, this list of conditions and the following disclaimer.
10
 * 2. Redistributions in binary form must reproduce the above copyright
11
 *    notice, this list of conditions and the following disclaimer in the
12
 *    documentation and/or other materials provided with the distribution.
13
 * 3. Neither the name of the author nor the names of any co-contributors
14
 *    may be used to endorse or promote products derived from this software
15
 *    without specific prior written permission.
16
 *
17
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
18
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20
 * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
21
 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22
 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
23
 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26
 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27
 * SUCH DAMAGE.
28
 */
29
30
/*
31
 * interrupt.c - interrupt handling routines for GBA
32
 */
33
34
#include <sys/ipl.h>
35
#include <kernel.h>
36
#include <hal.h>
37
#include <irq.h>
38
#include <locore.h>
39
#include <cpufunc.h>
40
#include <context.h>
41
42
/* Number of IRQ lines */
43
#define NIRQS                14
44
45
/* Interrupt hook vector */
46
#define IRQ_VECTOR        *(uint32_t *)0x3007ffc
47
48
/* Registers for interrupt control unit - enable/flag/master */
49
#define ICU_IE                (*(volatile uint16_t *)0x4000200)
50
#define ICU_IF                (*(volatile uint16_t *)0x4000202)
51
#define ICU_IME                (*(volatile uint16_t *)0x4000208)
52
53
/* ICU_IE */
54
#define IRQ_VALID        0x3fff
55
56
/* ICU_IME */
57
#define IRQ_OFF                0
58
#define IRQ_ON                1
59
60
/*
61
 * Interrupt priority level
62
 *
63
 * Each interrupt has its logical priority level, with 0 being
64
 * the lowest priority. While some ISR is running, all lower
65
 * priority interrupts are masked off.
66
 */
67
volatile int irq_level;
68
69
/*
70
 * Interrupt mapping table
71
 */
72
static int ipl_table[NIRQS];                /* Vector -> level */
73
static uint16_t mask_table[NIPLS];        /* Level -> mask */
74
75
/*
76
 * Set mask for current ipl
77
 */
78
#define update_mask()        ICU_IE = mask_table[irq_level]
79
80
/*
81
 * Unmask interrupt in PIC for specified irq.
82
 * The interrupt mask table is also updated.
83
 * Assumes CPU interrupt is disabled in caller.
84
 */
85
void
86
interrupt_unmask(int vector, int level)
87
{
88
        int i;
89
        uint16_t unmask = (uint16_t)1 << vector;
90
91
        /* Save level mapping */
92
        ipl_table[vector] = level;
93
94
        /*
95
         * Unmask target interrupt for all
96
         * lower interrupt levels.
97
         */
98
        for (i = 0; i < level; i++)
99
                mask_table[i] |= unmask;
100
        update_mask();
101
}
102
103
/*
104
 * Mask interrupt in PIC for specified irq.
105
 * Interrupt must be disabled when this routine is called.
106
 */
107
void
108
interrupt_mask(int vector)
109
{
110
        int i, level;
111
        u_int mask = (uint16_t)~(1 << vector);
112
113
        level = ipl_table[vector];
114
        for (i = 0; i < level; i++)
115
                mask_table[i] &= mask;
116
        ipl_table[vector] = IPL_NONE;
117
        update_mask();
118
}
119
120
/*
121
 * Setup interrupt mode.
122
 * Select whether an interrupt trigger is edge or level.
123
 */
124
void
125
interrupt_setup(int vector, int mode)
126
{
127
        /* nop */
128
}
129
130
/*
131
 * Dispatch interrupt
132
 */
133
void
134
interrupt_dispatch(int vector)
135
{
136
        int old_ipl;
137
138
        /* Save & update interrupt level */
139
        old_ipl = irq_level;
140
        irq_level = ipl_table[vector];
141
        update_mask();
142
143
        /* Send acknowledge to ICU for this irq */
144
        ICU_IF = (uint16_t)(1 << vector);
145
146
        /* Allow another interrupt that has higher priority */
147
        splon();
148
149
        /* Dispatch interrupt */
150
        irq_handler(vector);
151
152
        sploff();
153
154
        /* Restore interrupt level */
155
        irq_level = old_ipl;
156
        update_mask();
157
}
158
159
/*
160
 * Common interrupt handler.
161
 */
162
void
163
interrupt_handler(void)
164
{
165
        uint16_t bits;
166
        int vector;
167
168
        bits = ICU_IF;
169
retry:
170
        for (vector = 0; vector < NIRQS; vector++) {
171
                if (bits & (uint16_t)(1 << vector))
172
                        break;
173
        }
174
        if (vector == NIRQS)
175
                goto out;
176
177
        interrupt_dispatch(vector);
178
179
        /*
180
         * Multiple interrupts can be fired in case of GBA.
181
         * So, we have to check the interrupt status, again.
182
         */
183
        bits = ICU_IF;
184
        if (bits & IRQ_VALID)
185
                goto retry;
186
out:
187
        return;
188
}
189
190
/*
191
 * Initialize interrupt controllers.
192
 * All interrupts will be masked off.
193
 */
194
void
195
interrupt_init(void)
196
{
197
        int i;
198
199
        irq_level = IPL_NONE;
200
201
        for (i = 0; i < NIRQS; i++)
202
                ipl_table[i] = IPL_NONE;
203
204
        for (i = 0; i < NIPLS; i++)
205
                mask_table[i] = 0;
206
207
        ICU_IME = IRQ_OFF;
208
209
        /*
210
         * Since GBA has its own interrupt vector in ROM area,
211
         * we can not modify it. Instead, the GBA BIOS will
212
         * call the user's interrupt hook routine placed in
213
         * the address in 0x3007ffc.
214
         */
215
        IRQ_VECTOR = (uint32_t)interrupt_entry; /* Interrupt hook address */
216
        ICU_IE = 0;                        /* Mask all interrupts */
217
        ICU_IME = IRQ_ON;
218
}