forked from xobs/fernly
-
Notifications
You must be signed in to change notification settings - Fork 0
/
irq.c
148 lines (121 loc) · 3.03 KB
/
irq.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
#include <inttypes.h>
#include "serial.h"
#include "printf.h"
#include "irq.h"
#include "memio.h"
static struct {
void (*handler)(enum irq_number irq_num, void *opaque);
void *opaque;
} handlers[__irq_max__];
int irq_init(void)
{
register int var;
/* Acknowledge all interrupts */
writel(0xffffffff, IRQ_BASE + IRQ_MASK_OFF + IRQ_NUM_ADJ(0));
writel(0xffffffff, IRQ_BASE + IRQ_MASK_OFF + IRQ_NUM_ADJ(32));
asm volatile ("mrs %0, cpsr":"=r" (var));
if (!(var & 0x80)) {
serial_puts("Interrupts already enabled\n");
return -1;
}
serial_puts("Interrupts were disabled. Re-enabling...\n");
var &= ~0x80;
var |= 0x40;
var &= ~0x1f;
var |= 0x10;
asm volatile ("msr cpsr, %0":"=r" (var));
return 0;
}
int fiq_init(void)
{
serial_puts("FIQs compiled out\n");
return -1;
/*
register int var;
asm volatile ("mrs %0, cpsr":"=r" (var));
if (!(var & 0x40)) {
serial_puts("FIQ already enabled\n");
return -1;
}
serial_puts("FIQ was disabled. Re-enabling...\n");
var &= ~0x40;
asm volatile ("msr cpsr, %0":"=r" (var));
return 0;
*/
}
int irq_enable(enum irq_number irq_num)
{
uint32_t reg = IRQ_BASE + IRQ_MASK_OFF + IRQ_CLR + IRQ_NUM_ADJ(irq_num);
if (irq_num >= __irq_max__)
return -1;
writel(1 << (irq_num & 31), reg);
return 0;
}
int irq_disable(enum irq_number irq_num)
{
uint32_t reg = IRQ_BASE + IRQ_MASK_OFF + IRQ_SET + IRQ_NUM_ADJ(irq_num);
if (irq_num >= __irq_max__)
return -1;
writel(1 << (irq_num & 31), reg);
return 0;
}
void irq_stimulate(enum irq_number irq_num)
{
uint32_t reg = IRQ_BASE + IRQ_STIM_OFF + IRQ_SET + IRQ_NUM_ADJ(irq_num);
writel(1 << (irq_num & 31), reg);
}
void irq_stimulate_reset(enum irq_number irq_num)
{
uint32_t reg = IRQ_BASE + IRQ_STIM_OFF + IRQ_CLR + IRQ_NUM_ADJ(irq_num);
writel(1 << (irq_num & 31), reg);
}
void irq_acknowledge(enum irq_number irq_num)
{
uint32_t reg = IRQ_BASE + IRQ_ACK_OFF + IRQ_NUM_ADJ(irq_num);
if (irq_num >= __irq_max__)
return;
writel(1 << (irq_num & 31), reg);
return;
}
void irq_mask_acknowledge(enum irq_number irq_num)
{
irq_disable(irq_num);
irq_acknowledge(irq_num);
}
void irq_register_handler(enum irq_number irq_num,
void (*handler)(enum irq_number irq_num, void *opaque),
void *opaque)
{
if (irq_num >= __irq_max__)
return;
handlers[irq_num].handler = handler;
handlers[irq_num].opaque = opaque;
}
static void irq_dispatch_one(enum irq_number irq_num)
{
if (handlers[irq_num].handler)
handlers[irq_num].handler(irq_num, handlers[irq_num].opaque);
else
printf("Unhandled IRQ: %d\n", irq_num);
irq_acknowledge(irq_num);
}
void irq_dispatch(void)
{
uint32_t reg;
uint32_t val;
int i;
printf("Dispatching IRQs...\n");
reg = IRQ_BASE + IRQ_STATUS_OFF;
val = readl(reg);
printf("Lower Mask: 0x%08"PRIx32"\n", val);
for (i = 0; i < 32; i++)
if (val & (1 << i))
irq_dispatch_one(i);
reg += IRQ_BASE + IRQ_STATUS_OFF + 4;
val = readl(reg);
printf("Upper Mask: 0x%08"PRIx32"\n", val);
for (i = 0; i < (__irq_max__ - 32); i++)
if (val & (1 << i))
irq_dispatch_one(32 + i);
printf("Done dispatch\n");
}