Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
CTCaer
GitHub Repository: CTCaer/hekate
Path: blob/master/bdk/soc/irq.c
1476 views
1
/*
2
* BPMP-Lite IRQ driver for Tegra X1
3
*
4
* Copyright (c) 2019-2024 CTCaer
5
*
6
* This program is free software; you can redistribute it and/or modify it
7
* under the terms and conditions of the GNU General Public License,
8
* version 2, as published by the Free Software Foundation.
9
*
10
* This program is distributed in the hope it will be useful, but WITHOUT
11
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
12
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
13
* more details.
14
*
15
* You should have received a copy of the GNU General Public License
16
* along with this program. If not, see <http://www.gnu.org/licenses/>.
17
*/
18
19
#include <string.h>
20
21
#include "irq.h"
22
#include <soc/timer.h>
23
#include <soc/t210.h>
24
#include <gfx_utils.h>
25
#include <mem/heap.h>
26
27
//#define DPRINTF(...) gfx_printf(__VA_ARGS__)
28
#define DPRINTF(...)
29
30
extern void excp_reset();
31
extern void irq_disable();
32
extern void irq_enable_cpu_irq_exceptions();
33
extern void irq_disable_cpu_irq_exceptions();
34
35
typedef struct _irq_ctxt_t
36
{
37
u32 irq;
38
int (*handler)(u32 irq, void *data);
39
void *data;
40
u32 flags;
41
} irq_ctxt_t;
42
43
bool irq_init_done = false;
44
irq_ctxt_t irqs[IRQ_MAX_HANDLERS];
45
46
static void _irq_enable_source(u32 irq)
47
{
48
u32 ctrl_idx = irq >> 5;
49
u32 bit = irq % 32;
50
51
// Set as normal IRQ.
52
ICTLR(ctrl_idx, PRI_ICTLR_COP_IEP_CLASS) &= ~BIT(bit);
53
54
// Enable IRQ source.
55
ICTLR(ctrl_idx, PRI_ICTLR_COP_IER_SET) = BIT(bit);
56
}
57
58
static void _irq_disable_source(u32 irq)
59
{
60
u32 ctrl_idx = irq >> 5;
61
u32 bit = irq % 32;
62
63
// Disable IRQ source.
64
ICTLR(ctrl_idx, PRI_ICTLR_COP_IER_CLR) = BIT(bit);
65
}
66
67
static void _irq_disable_and_ack_all()
68
{
69
// Disable and ack all IRQ sources.
70
for (u32 ctrl_idx = 0; ctrl_idx < 6; ctrl_idx++)
71
{
72
u32 enabled_irqs = ICTLR(ctrl_idx, PRI_ICTLR_COP_IER);
73
ICTLR(ctrl_idx, PRI_ICTLR_COP_IER_CLR) = enabled_irqs;
74
}
75
}
76
77
void irq_free(u32 irq)
78
{
79
for (u32 idx = 0; idx < IRQ_MAX_HANDLERS; idx++)
80
{
81
if (irqs[idx].irq == irq && irqs[idx].handler)
82
{
83
irqs[idx].irq = 0;
84
irqs[idx].handler = NULL;
85
irqs[idx].data = NULL;
86
irqs[idx].flags = 0;
87
88
_irq_disable_source(irq);
89
}
90
}
91
}
92
93
static void _irq_free_all()
94
{
95
for (u32 idx = 0; idx < IRQ_MAX_HANDLERS; idx++)
96
{
97
if (irqs[idx].handler)
98
{
99
_irq_disable_source(irqs[idx].irq);
100
101
irqs[idx].irq = 0;
102
irqs[idx].handler = NULL;
103
irqs[idx].data = NULL;
104
irqs[idx].flags = 0;
105
}
106
}
107
}
108
109
static irq_status_t _irq_handle_source(u32 irq)
110
{
111
int status = IRQ_NONE;
112
113
_irq_disable_source(irq);
114
115
u32 idx;
116
for (idx = 0; idx < IRQ_MAX_HANDLERS; idx++)
117
{
118
if (irqs[idx].irq == irq)
119
{
120
status = irqs[idx].handler(irqs[idx].irq, irqs[idx].data);
121
122
if (status == IRQ_HANDLED)
123
break;
124
}
125
}
126
127
// Do not re-enable if not handled or error.
128
if (status != IRQ_HANDLED)
129
return status;
130
131
if (irqs[idx].flags & IRQ_FLAG_ONE_OFF)
132
irq_free(irq);
133
else
134
_irq_enable_source(irq);
135
136
return status;
137
}
138
139
void irq_handler()
140
{
141
// Get IRQ source.
142
u32 irq = EXCP_VEC(EVP_COP_IRQ_STS) & 0xFF;
143
144
if (!irq_init_done)
145
{
146
_irq_disable_source(irq);
147
148
return;
149
}
150
151
DPRINTF("IRQ: %d\n", irq);
152
153
int err = _irq_handle_source(irq);
154
155
if (err == IRQ_NONE)
156
{
157
DPRINTF("Unhandled IRQ got disabled: %d!\n", irq);
158
}
159
}
160
161
static void _irq_init()
162
{
163
_irq_disable_and_ack_all();
164
memset(irqs, 0, sizeof(irq_ctxt_t) * IRQ_MAX_HANDLERS);
165
irq_init_done = true;
166
}
167
168
void irq_end()
169
{
170
if (!irq_init_done)
171
return;
172
173
_irq_free_all();
174
irq_disable_cpu_irq_exceptions();
175
irq_init_done = false;
176
}
177
178
void irq_wait_event(u32 irq)
179
{
180
irq_disable_cpu_irq_exceptions();
181
182
_irq_enable_source(irq);
183
184
// Halt BPMP and wait for the IRQ. No need to use WAIT_EVENT + LIC_IRQ when BPMP serves the IRQ.
185
FLOW_CTLR(FLOW_CTLR_HALT_COP_EVENTS) = HALT_MODE_STOP_UNTIL_IRQ;
186
187
_irq_disable_source(irq);
188
189
irq_enable_cpu_irq_exceptions();
190
}
191
192
void irq_disable_wait_event()
193
{
194
irq_enable_cpu_irq_exceptions();
195
}
196
197
irq_status_t irq_request(u32 irq, irq_handler_t handler, void *data, irq_flags_t flags)
198
{
199
if (!irq_init_done)
200
_irq_init();
201
202
for (u32 idx = 0; idx < IRQ_MAX_HANDLERS; idx++)
203
{
204
if (irqs[idx].handler == NULL ||
205
(irqs[idx].irq == irq && irqs[idx].flags & IRQ_FLAG_REPLACEABLE))
206
{
207
DPRINTF("Registered handler, IRQ: %d, Slot: %d\n", irq, idx);
208
DPRINTF("Handler: %08p, Flags: %x\n", (u32)handler, flags);
209
210
irqs[idx].irq = irq;
211
irqs[idx].handler = handler;
212
irqs[idx].data = data;
213
irqs[idx].flags = flags;
214
215
_irq_enable_source(irq);
216
217
return IRQ_ENABLED;
218
}
219
else if (irqs[idx].irq == irq)
220
return IRQ_ALREADY_REGISTERED;
221
}
222
223
return IRQ_NO_SLOTS_AVAILABLE;
224
}
225
226
void __attribute__ ((target("arm"))) fiq_setup()
227
{
228
/*
229
asm volatile("mrs r12, cpsr\n\t"
230
"bic r12, r12, #0x1F\n\t"
231
"orr r12, r12, #0x11\n\t"
232
"msr cpsr_c, r12\n\t");
233
234
register volatile char *text asm ("r8");
235
register volatile char *uart_tx asm ("r9");
236
register int len asm ("r10");
237
238
len = 5;
239
uart_tx = (char *)0x70006040;
240
memcpy((char *)text, "FIQ\r\n", len);
241
*uart_tx = 0;
242
243
asm volatile("mrs r12, cpsr\n"
244
"orr r12, r12, #0x1F\n"
245
"msr cpsr_c, r12");
246
*/
247
}
248
249
void __attribute__ ((target("arm"), interrupt ("FIQ"))) fiq_handler()
250
{
251
/*
252
register volatile char *text asm ("r8");
253
register volatile char *uart_tx asm ("r9");
254
register int len asm ("r10");
255
256
while (len)
257
{
258
*uart_tx = *text++;
259
len--;
260
}
261
*/
262
#ifdef BDK_WATCHDOG_FIQ_ENABLE
263
// Set watchdog timeout status and disable WDT and its FIQ signal.
264
watchdog_handle();
265
266
#ifdef BDK_RESTART_BL_ON_WDT
267
// Restart bootloader.
268
excp_reset();
269
#endif
270
271
#endif
272
}
273
274