-
Notifications
You must be signed in to change notification settings - Fork 9
/
Copy pathinterrupts.c
196 lines (165 loc) · 4.75 KB
/
interrupts.c
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
#include <stdint.h>
#include "audio.h"
#include "display.h"
#include "interrupts.h"
#include "ports.h"
#include "system.h"
#include "uart.h"
#include "util.h"
#include "fixed_addr.h"
extern uint32_t _ivt;
void usb1_hal_hcd_isr(uint8_t hostid);
void usb2_hal_hcd_isr(uint8_t hostid);
void usb3_hal_hcd_isr(uint8_t hostid);
int irq_pending(uint32_t irq)
{
volatile struct gicd_reg *gicd = (volatile struct gicd_reg *)GICD_BASE;
if (gicd->ispendr[irq / 32] & (1 << (irq % 32)))
return 1;
return 0;
}
void irq_unpend(uint32_t irq)
{
volatile struct gicd_reg *gicd = (volatile struct gicd_reg *)GICD_BASE;
gicd->icpendr[irq / 32] = (1 << (irq % 32));
}
void __attribute__((weak)) hook_display_vblank(void)
{
}
// analog audio codec interrupt handler
extern void codec_fiq_handler(void);
// Called when an interrupt is triggered
void
#ifndef JAILHOUSE
__attribute__((interrupt("IRQ")))
#endif
interrupt(void)
{
// PL EINT (reset button)
if (irq_pending(77)) {
gpio_irq_ack(PORTL);
sys_reset();
}
// digital audio
if (irq_pending(HDMI_AUDIO_IRQ))
audio_queue_samples();
#ifdef AWBM_PLATFORM_h3
// analog audio
if (irq_pending(82))
codec_fiq_handler();
#endif
#ifndef JAILHOUSE
// USB controllers
if (irq_pending(107))
usb1_hal_hcd_isr(0);
if (irq_pending(109))
usb2_hal_hcd_isr(0);
if (irq_pending(111))
usb3_hal_hcd_isr(0);
#endif
// LCD controllers 0 and 1
// NB: Only one of these will be enabled at any time.
if (irq_pending(LCD0_IRQ)) {
tick_counter++;
LCD0_GINT0 &= ~(1 << 14);
hook_display_vblank();
}
if (irq_pending(LCD1_IRQ)) {
tick_counter++;
LCD1_GINT0 &= ~(1 << 14);
hook_display_vblank();
}
#ifdef AWBM_PLATFORM_h3
// RT-WB
if (irq_pending(127)) {
// XXX: notify somebody???
DE_WB_STATUS |= 1;
}
#endif
}
// XXX: Something is really wrong here.
// Enabling _any_ interrupt enables all of them, and disabling them does not
// seem to have any effect. This is not much of a problem in practice
// because the device drivers silence the interrupts at the source, but
// something needs fixing here.
void irq_enable(uint32_t irq)
{
volatile struct gicd_reg *gicd = (volatile struct gicd_reg *)GICD_BASE;
#ifndef JAILHOUSE
#ifdef GDBSTUB
gicd->ctlr = BIT(1) | BIT(0);
#else
gicd->ctlr = BIT(1);
#endif
#endif
gicd->igroupr[irq / 32] |= 1UL << (irq % 32); // set to group 1
gicd->isenabler[irq / 32] = 1UL << (irq % 32);
#ifndef JAILHOUSE
gicd->itargetsr[irq] = 1; // target core 0
#endif
gicd->ipriorityr[irq] = 2; // lower than FIQ
}
void irq_enable_fiq(uint32_t irq)
{
volatile struct gicd_reg *gicd = (volatile struct gicd_reg *)GICD_BASE;
irq_enable(irq);
gicd->igroupr[irq / 32] &= ~(1UL << (irq % 32)); // set to group 0
gicd->ipriorityr[irq] = 1; // higher than IRQ
}
void irq_disable(uint32_t irq)
{
volatile struct gicd_reg *gicd = (volatile struct gicd_reg *)GICD_BASE;
gicd->icenabler[irq / 32] = 1 << (irq % 32);
}
void __attribute__((weak)) hook_data_abort(void)
{
for (;;);
}
#ifdef JAILHOUSE
#ifdef GDBSTUB
void _vec_jhirq(void);
void _vec_jhsvc(void);
#endif
void __attribute__((no_sanitize("all"))) install_ivt()
{
// Jailhouse doesn't seem to like it if we use our interrupt handler. It
// executes, but then the main thread seems to freeze, or is caught in an
// endless loop or something like that. When bouncing off the handler in
// the loader program, everything works. So we just do that.
// XXX: Is that still true?
*((void **)AWBM_IRQ_HANDLER_VECTOR) = interrupt;
#ifdef GDBSTUB
*((void **)GDBSTUB_IRQ_HANDLER_VECTOR) = _vec_jhirq;
*((void **)GDBSTUB_SVC_HANDLER_VECTOR) = _vec_jhsvc;
#endif
*((void **)AWBM_DABT_HANDLER_VECTOR) = hook_data_abort;
// XXX: Our exception handlers don't do much, so we just keep the ones
// from the Jailhouse demos.
// XXX: GIC seems to be set up reasonably well by Jailhouse.
asm("cpsie if;"); // Enable interrupts
}
#endif // JAILHOUSE
#ifndef JAILHOUSE
// Copy the interrupt table from _ivt to 0x0
void __attribute__((no_sanitize("all"))) install_ivt()
{
uint32_t *source = &_ivt;
uint32_t *destination = (uint32_t *)(0);
for (int n = 0; n < 2 * 8; n++)
destination[n] = source[n];
volatile struct gicc_reg *gicc = (volatile struct gicc_reg *)GICC_BASE;
#ifdef GDBSTUB
// enable interrupt groups 0 and 1, signal group 0 as FIQ
gicc->ctlr = BIT(3) | BIT(1) | BIT(0);
#else
// enable interrupt group 1 only
gicc->ctlr = BIT(1);
#endif
gicc->pmr = 10;
volatile struct gicd_reg *gicd = (volatile struct gicd_reg *)GICD_BASE;
// set all interrupts to group 1
for (int i = 0; i < 32; ++i)
gicd->igroupr[i] = 0xffffffff;
asm("cpsie if;"); // Enable interrupts
}
#endif // !JAILHOUSE