rp2040/
dma.rs

1// Licensed under the Apache License, Version 2.0 or the MIT License.
2// SPDX-License-Identifier: Apache-2.0 OR MIT
3// Copyright OxidOS Automotive 2025.
4
5use crate::pio;
6use kernel::utilities::cells::OptionalCell;
7use kernel::utilities::registers::interfaces::{Readable, Writeable};
8use kernel::utilities::registers::{register_bitfields, register_structs, FieldValue, ReadWrite};
9use kernel::utilities::StaticRef;
10
11register_structs! {
12        pub ChannelRegisters {
13                (0x000 => read_addr: ReadWrite<u32, READ_ADDR::Register>),
14                (0x004 => write_addr: ReadWrite<u32, WRITE_ADDR::Register>),
15                (0x008 => trans_count: ReadWrite<u32, TRANS_COUNT::Register>),
16                (0x00C => ctrl_trig: ReadWrite<u32, CTRL_TRIG::Register>),
17                (0x010 => _reserved0),
18                (0x040 => @END),
19        },
20        pub DmaRegisters {
21                (0x000 => channels: [ChannelRegisters; 12]),
22                (0x300 => _reserved),
23
24                (0x400 => intr: ReadWrite<u32, INTR::Register>),
25                (0x404 => inte0: ReadWrite<u32, INTE::Register>),
26                (0x408 => intf0: ReadWrite<u32, INTF::Register>),
27                (0x40C => ints0: ReadWrite<u32, INTS::Register>),
28                (0x410 => _reserved1),
29                (0x414 => inte1: ReadWrite<u32, INTE::Register>),
30                (0x418 => intf1: ReadWrite<u32, INTF::Register>),
31                (0x41C => ints1: ReadWrite<u32, INTS::Register>),
32                (0x420 => timer0: ReadWrite<u32, TIMER0::Register>),
33                (0x424 => timer1: ReadWrite<u32, TIMER1::Register>),
34                (0x428 => timer2: ReadWrite<u32, TIMER2::Register>),
35                (0x42C => timer3: ReadWrite<u32, TIMER3::Register>),
36                (0x430 => multi_chan_trigger: ReadWrite<u32>),
37                (0x434 => sniff_ctrl: ReadWrite<u32, SNIFF_CTRL::Register>),
38                (0x438 => sniff_data: ReadWrite<u32>),
39                (0x43C => _reserved13),
40
41                (0x440 => fifo_levels: ReadWrite<u32, FIFO_LEVELS::Register>),
42                (0x444 => chan_abort: ReadWrite<u32>),
43                (0x448 => n_channels: ReadWrite<u32>),
44                (0x44C => _reserved14),
45
46                (0x800 => ch0_dbg_ctdreq: ReadWrite<u32>),
47                (0x804 => ch0_dbg_tcr: ReadWrite<u32>),
48                (0x808 => _reserved15),
49
50                (0x840 => ch1_dbg_ctdreq: ReadWrite<u32>),
51                (0x844 => ch1_dbg_tcr: ReadWrite<u32>),
52                (0x848 => _reserved16),
53
54                (0x880 => ch2_dbg_ctdreq: ReadWrite<u32>),
55                (0x884 => ch2_dbg_tcr: ReadWrite<u32>),
56                (0x888 => _reserved17),
57
58                (0x8C0 => ch3_dbg_ctdreq: ReadWrite<u32>),
59                (0x8C4 => ch3_dbg_tcr: ReadWrite<u32>),
60                (0x8C8 => _reserved18),
61
62                (0x900 => ch4_dbg_ctdreq: ReadWrite<u32>),
63                (0x904 => ch4_dbg_tcr: ReadWrite<u32>),
64                (0x908 => _reserved19),
65
66                (0x940 => ch5_dbg_ctdreq: ReadWrite<u32>),
67                (0x944 => ch5_dbg_tcr: ReadWrite<u32>),
68                (0x948 => _reserved20),
69
70                (0x980 => ch6_dbg_ctdreq: ReadWrite<u32>),
71                (0x984 => ch6_dbg_tcr: ReadWrite<u32>),
72                (0x988 => _reserved21),
73
74                (0x9C0 => ch7_dbg_ctdreq: ReadWrite<u32>),
75                (0x9C4 => ch7_dbg_tcr: ReadWrite<u32>),
76                (0x9C8 => _reserved22),
77
78                (0xA00 => ch8_dbg_ctdreq: ReadWrite<u32>),
79                (0xA04 => ch8_dbg_tcr: ReadWrite<u32>),
80                (0xA08 => _reserved23),
81
82                (0xA40 => ch9_dbg_ctdreq: ReadWrite<u32>),
83                (0xA44 => ch9_dbg_tcr: ReadWrite<u32>),
84                (0xA48 => _reserved24),
85
86                (0xA80 => ch10_dbg_ctdreq: ReadWrite<u32>),
87                (0xA84 => ch10_dbg_tcr: ReadWrite<u32>),
88                (0xA88 => _reserved25),
89
90                (0xAC0 => ch11_dbg_ctdreq: ReadWrite<u32>),
91                (0xAC4 => ch11_dbg_tcr: ReadWrite<u32>),
92                (0xAC8 => @END),
93    }
94}
95register_bitfields![u32,
96    READ_ADDR [
97        READ_ADDR OFFSET(0) NUMBITS(32) []
98    ],
99    WRITE_ADDR [
100        WRITE_ADDR OFFSET(0) NUMBITS(32) []
101    ],
102    TRANS_COUNT [
103        TRANS_COUNT OFFSET(0) NUMBITS(32) []
104    ],
105    CTRL_TRIG [
106        AHB_ERROR OFFSET(31) NUMBITS(1) [],
107        READ_ERROR OFFSET(30) NUMBITS(1) [],
108        WRITE_ERROR OFFSET(29) NUMBITS(1) [],
109        BUSY OFFSET(24) NUMBITS(1) [],
110        SNIFF_EN OFFSET(23) NUMBITS(1) [],
111        BSWAP OFFSET(22) NUMBITS(1) [],
112        IRQ_QUIET OFFSET(21) NUMBITS(1) [],
113        TREQ_SEL OFFSET(15) NUMBITS(6) [
114            /// Select PIO0's TX FIFO 0 as TREQ
115            SelectPIO0STXFIFO0AsTREQ = 0,
116            /// Select PIO0's TX FIFO 1 as TREQ
117            SelectPIO0STXFIFO1AsTREQ = 1,
118            /// Select PIO0's TX FIFO 2 as TREQ
119            SelectPIO0STXFIFO2AsTREQ = 2,
120            /// Select PIO0's TX FIFO 3 as TREQ
121            SelectPIO0STXFIFO3AsTREQ = 3,
122            /// Select PIO0's RX FIFO 0 as TREQ
123            SelectPIO0SRXFIFO0AsTREQ = 4,
124            /// Select PIO0's RX FIFO 1 as TREQ
125            SelectPIO0SRXFIFO1AsTREQ = 5,
126            /// Select PIO0's RX FIFO 2 as TREQ
127            SelectPIO0SRXFIFO2AsTREQ = 6,
128            /// Select PIO0's RX FIFO 3 as TREQ
129            SelectPIO0SRXFIFO3AsTREQ = 7,
130            /// Select PIO1's TX FIFO 0 as TREQ
131            SelectPIO1STXFIFO0AsTREQ = 8,
132            /// Select PIO1's TX FIFO 1 as TREQ
133            SelectPIO1STXFIFO1AsTREQ = 9,
134            /// Select PIO1's TX FIFO 2 as TREQ
135            SelectPIO1STXFIFO2AsTREQ = 10,
136            /// Select PIO1's TX FIFO 3 as TREQ
137            SelectPIO1STXFIFO3AsTREQ = 11,
138            /// Select PIO1's RX FIFO 0 as TREQ
139            SelectPIO1SRXFIFO0AsTREQ = 12,
140            /// Select PIO1's RX FIFO 1 as TREQ
141            SelectPIO1SRXFIFO1AsTREQ = 13,
142            /// Select PIO1's RX FIFO 2 as TREQ
143            SelectPIO1SRXFIFO2AsTREQ = 14,
144            /// Select PIO1's RX FIFO 3 as TREQ
145            SelectPIO1SRXFIFO3AsTREQ = 15,
146            /// Select SPI0's TX FIFO as TREQ
147            SelectSPI0STXFIFOAsTREQ = 16,
148            /// Select SPI0's RX FIFO as TREQ
149            SelectSPI0SRXFIFOAsTREQ = 17,
150            /// Select SPI1's TX FIFO as TREQ
151            SelectSPI1STXFIFOAsTREQ = 18,
152            /// Select SPI1's RX FIFO as TREQ
153            SelectSPI1SRXFIFOAsTREQ = 19,
154            /// Select UART0's TX FIFO as TREQ
155            SelectUART0STXFIFOAsTREQ = 20,
156            /// Select UART0's RX FIFO as TREQ
157            SelectUART0SRXFIFOAsTREQ = 21,
158            /// Select UART1's TX FIFO as TREQ
159            SelectUART1STXFIFOAsTREQ = 22,
160            /// Select UART1's RX FIFO as TREQ
161            SelectUART1SRXFIFOAsTREQ = 23,
162            /// Select PWM Counter 0's Wrap Value as TREQ
163            SelectPWMCounter0SWrapValueAsTREQ = 24,
164            /// Select PWM Counter 1's Wrap Value as TREQ
165            SelectPWMCounter1SWrapValueAsTREQ = 25,
166            /// Select PWM Counter 2's Wrap Value as TREQ
167            SelectPWMCounter2SWrapValueAsTREQ = 26,
168            /// Select PWM Counter 3's Wrap Value as TREQ
169            SelectPWMCounter3SWrapValueAsTREQ = 27,
170            /// Select PWM Counter 4's Wrap Value as TREQ
171            SelectPWMCounter4SWrapValueAsTREQ = 28,
172            /// Select PWM Counter 5's Wrap Value as TREQ
173            SelectPWMCounter5SWrapValueAsTREQ = 29,
174            /// Select PWM Counter 6's Wrap Value as TREQ
175            SelectPWMCounter6SWrapValueAsTREQ = 30,
176            /// Select PWM Counter 7's Wrap Value as TREQ
177            SelectPWMCounter7SWrapValueAsTREQ = 31,
178            /// Select I2C0's TX FIFO as TREQ
179            SelectI2C0STXFIFOAsTREQ = 32,
180            /// Select I2C0's RX FIFO as TREQ
181            SelectI2C0SRXFIFOAsTREQ = 33,
182            /// Select I2C1's TX FIFO as TREQ
183            SelectI2C1STXFIFOAsTREQ = 34,
184            /// Select I2C1's RX FIFO as TREQ
185            SelectI2C1SRXFIFOAsTREQ = 35,
186            /// Select the ADC as TREQ
187            SelectTheADCAsTREQ = 36,
188            /// Select the XIP Streaming FIFO as TREQ
189            SelectTheXIPStreamingFIFOAsTREQ = 37,
190            /// Select the XIP SSI TX FIFO as TREQ
191            SelectTheXIPSSITXFIFOAsTREQ = 38,
192            /// Select the XIP SSI RX FIFO as TREQ
193            SelectTheXIPSSIRXFIFOAsTREQ = 39,
194            /// Select Timer 0 as TREQ
195            SelectTimer0AsTREQ = 59,
196            /// Select Timer 1 as TREQ
197            SelectTimer1AsTREQ = 60,
198            /// Select Timer 2 as TREQ (Optional)
199            SelectTimer2AsTREQOptional = 61,
200            /// Select Timer 3 as TREQ (Optional)
201            SelectTimer3AsTREQOptional = 62,
202            /// Permanent request, for unpaced transfers.
203            PermanentRequestForUnpacedTransfers = 63
204        ],
205        /// When this channel completes, it will trigger the channel indicated by CHAIN_TO.
206        CHAIN_TO OFFSET(11) NUMBITS(4) [],
207        /// Select whether RING_SIZE applies to read or write addresses.
208        /// If 0, read addresses are wrapped on a (1 << RING_SIZ
209        RING_SEL OFFSET(10) NUMBITS(1) [],
210        /// Size of address wrap region. If 0, don't wrap. For values n > 0, only the lower
211        ///
212        /// Ring sizes between 2 and 32768 bytes are possible. T
213        RING_SIZE OFFSET(6) NUMBITS(4) [
214            RING_NONE = 0
215        ],
216        INCR_WRITE OFFSET(5) NUMBITS(1) [],
217        INCR_READ OFFSET(4) NUMBITS(1) [],
218        DATA_SIZE OFFSET(2) NUMBITS(2) [
219            SIZE_BYTE = 0b00,
220            SIZE_HALFWORD = 0b01,
221            SIZE_WORD = 0b10
222        ],
223        HIGH_PRIORITY OFFSET(1) NUMBITS(1) [],
224        EN OFFSET(0) NUMBITS(1) []
225    ],
226    INTR [
227        INTR OFFSET(0) NUMBITS(16) []
228    ],
229    INTE [
230        CH11 OFFSET(11) NUMBITS(1) [],
231        CH10 OFFSET(10) NUMBITS(1) [],
232        CH9 OFFSET(9) NUMBITS(1) [],
233        CH8 OFFSET(8) NUMBITS(1) [],
234        CH7 OFFSET(7) NUMBITS(1) [],
235        CH6 OFFSET(6) NUMBITS(1) [],
236        CH5 OFFSET(5) NUMBITS(1) [],
237        CH4 OFFSET(4) NUMBITS(1) [],
238        CH3 OFFSET(3) NUMBITS(1) [],
239        CH2 OFFSET(2) NUMBITS(1) [],
240        CH1 OFFSET(1) NUMBITS(1) [],
241        CH0 OFFSET(0) NUMBITS(1) [],
242    ],
243    INTF [
244        CH11 OFFSET(11) NUMBITS(1) [],
245        CH10 OFFSET(10) NUMBITS(1) [],
246        CH9 OFFSET(9) NUMBITS(1) [],
247        CH8 OFFSET(8) NUMBITS(1) [],
248        CH7 OFFSET(7) NUMBITS(1) [],
249        CH6 OFFSET(6) NUMBITS(1) [],
250        CH5 OFFSET(5) NUMBITS(1) [],
251        CH4 OFFSET(4) NUMBITS(1) [],
252        CH3 OFFSET(3) NUMBITS(1) [],
253        CH2 OFFSET(2) NUMBITS(1) [],
254        CH1 OFFSET(1) NUMBITS(1) [],
255        CH0 OFFSET(0) NUMBITS(1) [],
256    ],
257    INTS [
258        /// Indicates active channel interrupt requests which are currently causing IRQ 0 to
259        /// Channel interrupts can be cleared by writing a bit m
260        CH11 OFFSET(11) NUMBITS(1) [],
261        CH10 OFFSET(10) NUMBITS(1) [],
262        CH9 OFFSET(9) NUMBITS(1) [],
263        CH8 OFFSET(8) NUMBITS(1) [],
264        CH7 OFFSET(7) NUMBITS(1) [],
265        CH6 OFFSET(6) NUMBITS(1) [],
266        CH5 OFFSET(5) NUMBITS(1) [],
267        CH4 OFFSET(4) NUMBITS(1) [],
268        CH3 OFFSET(3) NUMBITS(1) [],
269        CH2 OFFSET(2) NUMBITS(1) [],
270        CH1 OFFSET(1) NUMBITS(1) [],
271        CH0 OFFSET(0) NUMBITS(1) [],
272    ],
273    TIMER0 [
274        /// Pacing Timer Dividend. Specifies the X value for the (X/Y) fractional timer.
275        X OFFSET(16) NUMBITS(16) [],
276        /// Pacing Timer Divisor. Specifies the Y value for the (X/Y) fractional timer.
277        Y OFFSET(0) NUMBITS(16) []
278    ],
279    TIMER1 [
280        /// Pacing Timer Dividend. Specifies the X value for the (X/Y) fractional timer.
281        X OFFSET(16) NUMBITS(16) [],
282        /// Pacing Timer Divisor. Specifies the Y value for the (X/Y) fractional timer.
283        Y OFFSET(0) NUMBITS(16) []
284    ],
285    TIMER2 [
286        X OFFSET(16) NUMBITS(16) [],
287        Y OFFSET(0) NUMBITS(16) []
288    ],
289    TIMER3 [
290        X OFFSET(16) NUMBITS(16) [],
291        Y OFFSET(0) NUMBITS(16) []
292    ],
293    MULTI_CHAN_TRIGGER [
294        MULTI_CHAN_TRIGGER OFFSET(0) NUMBITS(16) []
295    ],
296    SNIFF_CTRL [
297        OUT_INV OFFSET(11) NUMBITS(1) [],
298        OUT_REV OFFSET(10) NUMBITS(1) [],
299        BSWAP OFFSET(9) NUMBITS(1) [],
300
301        CALC OFFSET(5) NUMBITS(4) [
302            /// Calculate a CRC-32 (IEEE802.3 polynomial)
303            CalculateACRC32IEEE8023Polynomial = 0,
304            /// Calculate a CRC-32 (IEEE802.3 polynomial) with bit reversed data
305            CalculateACRC32IEEE8023PolynomialWithBitReversedData = 1,
306            /// Calculate a CRC-16-CCITT
307            CalculateACRC16CCITT = 2,
308            /// Calculate a CRC-16-CCITT with bit reversed data
309            CalculateACRC16CCITTWithBitReversedData = 3,
310            /// XOR reduction over all data. == 1 if the total 1 population count is odd.
311            XORReductionOverAllData1IfTheTotal1PopulationCountIsOdd = 14,
312            /// Calculate a simple 32-bit checksum (addition with a 32 bit accumulator)
313            CalculateASimple32BitChecksumAdditionWithA32BitAccumulator = 15
314        ],
315        /// DMA channel for Sniffer to observe
316        DMACH OFFSET(1) NUMBITS(4) [],
317        /// Enable sniffer
318        EN OFFSET(0) NUMBITS(1) []
319    ],
320    SNIFF_DATA [
321        SNIFF_DATA OFFSET(0) NUMBITS(32) []
322    ],
323    FIFO_LEVELS [
324        /// Current Read-Address-FIFO fill level
325        RAF_LVL OFFSET(16) NUMBITS(8) [],
326        /// Current Write-Address-FIFO fill level
327        WAF_LVL OFFSET(8) NUMBITS(8) [],
328        /// Current Transfer-Data-FIFO fill level
329        TDF_LVL OFFSET(0) NUMBITS(8) []
330    ],
331    CHAN_ABORT [
332        CHAN_ABORT OFFSET(0) NUMBITS(16) []
333    ],
334    N_CHANNELS [
335        N_CHANNELS OFFSET(0) NUMBITS(5) []
336    ],
337    DBG_CTDREQ [
338        DBG_CTDREQ OFFSET(0) NUMBITS(6) []
339    ],
340    DBG_TCR [
341        DBG_TCR OFFSET(0) NUMBITS(32) []
342    ]
343];
344
345const DMA_BASE: StaticRef<DmaRegisters> =
346    unsafe { StaticRef::new(0x50000000 as *const DmaRegisters) };
347
348#[derive(Clone, Copy)]
349pub enum Channel {
350    Channel0 = 0,
351    Channel1 = 1,
352    Channel2 = 2,
353    Channel3 = 3,
354    Channel4 = 4,
355    Channel5 = 5,
356    Channel6 = 6,
357    Channel7 = 7,
358    Channel8 = 8,
359    Channel9 = 9,
360    Channel10 = 10,
361    Channel11 = 11,
362}
363
364pub enum Transfer {
365    PeripheralToMemory,
366    MemoryToPeripheral,
367}
368
369pub enum DataSize {
370    Byte = 0x0,
371    HalfWord = 0x1,
372    Word = 0x2,
373}
374
375impl From<DataSize> for FieldValue<u32, CTRL_TRIG::Register> {
376    fn from(value: DataSize) -> Self {
377        match value {
378            DataSize::Byte => CTRL_TRIG::DATA_SIZE::SIZE_BYTE,
379            DataSize::HalfWord => CTRL_TRIG::DATA_SIZE::SIZE_HALFWORD,
380            DataSize::Word => CTRL_TRIG::DATA_SIZE::SIZE_WORD,
381        }
382    }
383}
384
385pub enum DmaPeripheral {
386    PioRxFifo(pio::PIONumber, pio::SMNumber),
387    PioTxFifo(pio::PIONumber, pio::SMNumber),
388}
389
390impl From<DmaPeripheral> for FieldValue<u32, CTRL_TRIG::Register> {
391    fn from(value: DmaPeripheral) -> Self {
392        match value {
393            DmaPeripheral::PioRxFifo(pio::PIONumber::PIO0, pio::SMNumber::SM0) => {
394                CTRL_TRIG::TREQ_SEL::SelectPIO0SRXFIFO0AsTREQ
395            }
396            DmaPeripheral::PioRxFifo(pio::PIONumber::PIO0, pio::SMNumber::SM1) => {
397                CTRL_TRIG::TREQ_SEL::SelectPIO0SRXFIFO1AsTREQ
398            }
399            DmaPeripheral::PioRxFifo(pio::PIONumber::PIO0, pio::SMNumber::SM2) => {
400                CTRL_TRIG::TREQ_SEL::SelectPIO0SRXFIFO2AsTREQ
401            }
402            DmaPeripheral::PioRxFifo(pio::PIONumber::PIO0, pio::SMNumber::SM3) => {
403                CTRL_TRIG::TREQ_SEL::SelectPIO0SRXFIFO3AsTREQ
404            }
405            DmaPeripheral::PioRxFifo(pio::PIONumber::PIO1, pio::SMNumber::SM0) => {
406                CTRL_TRIG::TREQ_SEL::SelectPIO1SRXFIFO0AsTREQ
407            }
408            DmaPeripheral::PioRxFifo(pio::PIONumber::PIO1, pio::SMNumber::SM1) => {
409                CTRL_TRIG::TREQ_SEL::SelectPIO1SRXFIFO1AsTREQ
410            }
411            DmaPeripheral::PioRxFifo(pio::PIONumber::PIO1, pio::SMNumber::SM2) => {
412                CTRL_TRIG::TREQ_SEL::SelectPIO1SRXFIFO2AsTREQ
413            }
414            DmaPeripheral::PioRxFifo(pio::PIONumber::PIO1, pio::SMNumber::SM3) => {
415                CTRL_TRIG::TREQ_SEL::SelectPIO1SRXFIFO3AsTREQ
416            }
417            DmaPeripheral::PioTxFifo(pio::PIONumber::PIO0, pio::SMNumber::SM0) => {
418                CTRL_TRIG::TREQ_SEL::SelectPIO0STXFIFO0AsTREQ
419            }
420            DmaPeripheral::PioTxFifo(pio::PIONumber::PIO0, pio::SMNumber::SM1) => {
421                CTRL_TRIG::TREQ_SEL::SelectPIO0STXFIFO1AsTREQ
422            }
423            DmaPeripheral::PioTxFifo(pio::PIONumber::PIO0, pio::SMNumber::SM2) => {
424                CTRL_TRIG::TREQ_SEL::SelectPIO0STXFIFO2AsTREQ
425            }
426            DmaPeripheral::PioTxFifo(pio::PIONumber::PIO0, pio::SMNumber::SM3) => {
427                CTRL_TRIG::TREQ_SEL::SelectPIO0STXFIFO3AsTREQ
428            }
429            DmaPeripheral::PioTxFifo(pio::PIONumber::PIO1, pio::SMNumber::SM0) => {
430                CTRL_TRIG::TREQ_SEL::SelectPIO1STXFIFO0AsTREQ
431            }
432            DmaPeripheral::PioTxFifo(pio::PIONumber::PIO1, pio::SMNumber::SM1) => {
433                CTRL_TRIG::TREQ_SEL::SelectPIO1STXFIFO1AsTREQ
434            }
435            DmaPeripheral::PioTxFifo(pio::PIONumber::PIO1, pio::SMNumber::SM2) => {
436                CTRL_TRIG::TREQ_SEL::SelectPIO1STXFIFO2AsTREQ
437            }
438            DmaPeripheral::PioTxFifo(pio::PIONumber::PIO1, pio::SMNumber::SM3) => {
439                CTRL_TRIG::TREQ_SEL::SelectPIO1STXFIFO3AsTREQ
440            }
441        }
442    }
443}
444
445pub enum Irq {
446    Irq0,
447    Irq1,
448}
449
450pub trait DmaChannelClient {
451    fn transfer_done(&self);
452}
453
454#[derive(Clone, Copy)]
455pub struct DmaChannel<'a> {
456    dma: &'a Dma<'a>,
457    ch: Channel,
458}
459
460impl<'a> DmaChannel<'a> {
461    pub const fn new(dma: &'a Dma<'a>, ch: Channel) -> Self {
462        Self { dma, ch }
463    }
464    pub fn set_client(&self, client: &'a dyn DmaChannelClient) {
465        self.dma.set_channel_client(self.ch, client);
466    }
467}
468
469pub struct Dma<'a> {
470    registers: StaticRef<DmaRegisters>,
471    clients: [OptionalCell<&'a dyn DmaChannelClient>; 12],
472}
473
474impl<'a> Dma<'a> {
475    pub const fn new() -> Self {
476        Self {
477            registers: DMA_BASE,
478            clients: [const { OptionalCell::empty() }; 12],
479        }
480    }
481
482    pub fn channel(&'a self, ch: Channel) -> DmaChannel<'a> {
483        DmaChannel::new(self, ch)
484    }
485}
486
487impl<'a> Dma<'a> {
488    pub fn handle_interrupt0(&self) {
489        let value = self.registers.ints0.get();
490        self.registers.ints0.set(value);
491
492        self.handle_channels(value);
493    }
494
495    pub fn handle_interrupt1(&self) {
496        let value = self.registers.ints1.get();
497        self.registers.ints1.set(value);
498
499        self.handle_channels(value);
500    }
501
502    #[inline]
503    fn handle_channels(&self, mut ints: u32) {
504        ints &= 0xfff;
505        while ints != 0 {
506            let channel = ints.trailing_zeros();
507            self.clients[channel as usize].map(|client| client.transfer_done());
508            ints ^= 1 << channel;
509        }
510    }
511
512    fn enable_interrupt(&self, channel: Channel, irq: Irq) {
513        let irq = match irq {
514            Irq::Irq0 => &self.registers.inte0,
515            Irq::Irq1 => &self.registers.inte1,
516        };
517        let mut value = irq.get();
518        value |= 1 << (channel as usize);
519        irq.set(value);
520    }
521
522    fn disable_interrupt(&self, channel: Channel, irq: Irq) {
523        let irq = match irq {
524            Irq::Irq0 => &self.registers.inte0,
525            Irq::Irq1 => &self.registers.inte1,
526        };
527        let mut value = irq.get();
528        value &= !(1 << (channel as usize));
529        irq.set(value);
530    }
531
532    fn channel_registers(&self, channel: Channel) -> &ChannelRegisters {
533        &self.registers.channels[channel as usize]
534    }
535
536    fn set_channel_client(&self, channel: Channel, client: &'a dyn DmaChannelClient) {
537        self.clients[channel as usize].set(client)
538    }
539}
540
541impl DmaChannel<'_> {
542    pub fn trans_count(&self) -> u32 {
543        let regs = &self.dma.channel_registers(self.ch);
544        regs.trans_count.get()
545    }
546
547    pub fn busy(&self) -> bool {
548        let regs = &self.dma.channel_registers(self.ch);
549        match regs.ctrl_trig.read(CTRL_TRIG::BUSY) {
550            0 => false,
551            _ => true,
552        }
553    }
554
555    pub fn set_read_addr(&self, addr: u32) {
556        let regs = &self.dma.channel_registers(self.ch);
557        regs.read_addr.write(READ_ADDR::READ_ADDR.val(addr));
558    }
559
560    pub fn set_write_addr(&self, addr: u32) {
561        let regs = &self.dma.channel_registers(self.ch);
562        regs.write_addr.write(WRITE_ADDR::WRITE_ADDR.val(addr));
563    }
564
565    pub fn set_len(&self, len: u32) {
566        let regs = &self.dma.channel_registers(self.ch);
567        regs.trans_count.write(TRANS_COUNT::TRANS_COUNT.val(len));
568    }
569
570    pub fn enable_interrupt(&self, irq: Irq) {
571        self.dma.enable_interrupt(self.ch, irq);
572    }
573
574    pub fn disable_interrupt(&self, irq: Irq) {
575        self.dma.disable_interrupt(self.ch, irq);
576    }
577
578    pub fn enable(
579        &self,
580        treq: DmaPeripheral,
581        data_size: DataSize,
582        transfer: Transfer,
583        bswap: bool,
584    ) {
585        let regs = &self.dma.channel_registers(self.ch);
586
587        let bswap = match bswap {
588            true => CTRL_TRIG::BSWAP::SET,
589            false => CTRL_TRIG::BSWAP::CLEAR,
590        };
591        let (incr_rd, incr_wr) = match transfer {
592            Transfer::MemoryToPeripheral => {
593                (CTRL_TRIG::INCR_READ::SET, CTRL_TRIG::INCR_WRITE::CLEAR)
594            }
595            Transfer::PeripheralToMemory => {
596                (CTRL_TRIG::INCR_READ::CLEAR, CTRL_TRIG::INCR_WRITE::SET)
597            }
598        };
599        let treq = FieldValue::from(treq);
600        let data_size = FieldValue::from(data_size);
601        let chain_to = CTRL_TRIG::CHAIN_TO.val(self.ch as u32);
602
603        let fv = treq + data_size + bswap + incr_rd + incr_wr + chain_to + CTRL_TRIG::EN::SET;
604        regs.ctrl_trig.write(fv);
605    }
606}