blob: 8901f0655b238a249fa31b0ef8304ec6fc5d379c (
plain)
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
|
/* libhw_cr/rp2040_dma.c - Utilities for sharing the DMA IRQs
*
* Copyright (c) 2020 Raspberry Pi (Trading) Ltd.
* SPDX-License-Identifier: BSD-3-Clause
*
* Copyright (C) 2025 Luke T. Shumaker <lukeshu@lukeshu.com>
* SPDX-License-Identifier: AGPL-3.0-or-later
*/
#include <hardware/irq.h> /* for irq_set_exclusive_handler() */
#include "rp2040_dma.h"
/* Borrowed from <hardware/dma.h> *********************************************/
dma_channel_hw_t *dma_channel_hw_addr(uint channel) {
assert(channel < NUM_DMA_CHANNELS);
return &dma_hw->ch[channel];
}
enum dma_channel_transfer_size {
DMA_SIZE_8 = 0, ///< Byte transfer (8 bits)
DMA_SIZE_16 = 1, ///< Half word transfer (16 bits)
DMA_SIZE_32 = 2 ///< Word transfer (32 bits)
};
/* Our own code ***************************************************************/
struct dmairq_handler_entry {
dmairq_handler_t fn;
void *arg;
};
struct dmairq_handler_entry dmairq_handlers[NUM_DMA_CHANNELS] = {};
bool dmairq_initialized[NUM_DMA_IRQS] = {};
static void dmairq_handler(void) {
enum dmairq irq = __get_current_exception() - VTABLE_FIRST_IRQ;
size_t irq_idx = irq - DMAIRQ_0;
assert(irq_idx < NUM_DMA_IRQS);
uint32_t regval = dma_hw->irq_ctrl[irq_idx].ints;
for (uint channel = 0; channel < NUM_DMA_CHANNELS; channel++) {
if (regval & 1u<<channel) {
struct dmairq_handler_entry *handler = &dmairq_handlers[channel];
if (handler->fn)
handler->fn(handler->arg, irq, channel);
}
}
/* acknowledge irq */
dma_hw->intr = regval;
}
void dmairq_set_and_enable_exclusive_handler(enum dmairq irq, uint channel, dmairq_handler_t fn, void *arg) {
assert(irq == DMAIRQ_0 || irq == DMAIRQ_1);
assert(channel < NUM_DMA_CHANNELS);
assert(fn);
assert(dmairq_handlers[channel].fn == NULL);
dmairq_handlers[channel].fn = fn;
dmairq_handlers[channel].arg = arg;
size_t irq_idx = irq - DMAIRQ_0;
hw_set_bits(&dma_hw->irq_ctrl[irq_idx].inte, 1u<<channel);
if (!dmairq_initialized[irq_idx]) {
irq_set_exclusive_handler(irq, dmairq_handler);
irq_set_enabled(irq, true);
dmairq_initialized[irq_idx] = true;
}
}
|