1use core::marker::PhantomData;
18
19use crate::{
20    dma::*,
21    handler,
22    interrupt::Priority,
23    peripherals::{DMA, Interrupt, pac},
24};
25
26#[derive(Debug)]
28#[cfg_attr(feature = "defmt", derive(defmt::Format))]
29pub struct AnyGdmaChannel<'d> {
30    channel: u8,
31    _lifetime: PhantomData<&'d mut ()>,
32}
33
34impl AnyGdmaChannel<'_> {
35    #[cfg_attr(esp32c2, expect(unused))]
36    pub(crate) unsafe fn clone_unchecked(&self) -> Self {
37        Self {
38            channel: self.channel,
39            _lifetime: PhantomData,
40        }
41    }
42}
43
44impl crate::private::Sealed for AnyGdmaChannel<'_> {}
45impl<'d> DmaChannel for AnyGdmaChannel<'d> {
46    type Rx = AnyGdmaRxChannel<'d>;
47    type Tx = AnyGdmaTxChannel<'d>;
48
49    unsafe fn split_internal(self, _: crate::private::Internal) -> (Self::Rx, Self::Tx) {
50        (
51            AnyGdmaRxChannel {
52                channel: self.channel,
53                _lifetime: PhantomData,
54            },
55            AnyGdmaTxChannel {
56                channel: self.channel,
57                _lifetime: PhantomData,
58            },
59        )
60    }
61}
62
63#[derive(Debug)]
65#[cfg_attr(feature = "defmt", derive(defmt::Format))]
66pub struct AnyGdmaRxChannel<'d> {
67    channel: u8,
68    _lifetime: PhantomData<&'d mut ()>,
69}
70
71impl<'d> DmaChannelConvert<AnyGdmaRxChannel<'d>> for AnyGdmaRxChannel<'d> {
72    fn degrade(self) -> AnyGdmaRxChannel<'d> {
73        self
74    }
75}
76
77#[derive(Debug)]
79#[cfg_attr(feature = "defmt", derive(defmt::Format))]
80pub struct AnyGdmaTxChannel<'d> {
81    channel: u8,
82    _lifetime: PhantomData<&'d mut ()>,
83}
84
85impl<'d> DmaChannelConvert<AnyGdmaTxChannel<'d>> for AnyGdmaTxChannel<'d> {
86    fn degrade(self) -> AnyGdmaTxChannel<'d> {
87        self
88    }
89}
90
91use crate::asynch::AtomicWaker;
92
93static TX_WAKERS: [AtomicWaker; CHANNEL_COUNT] = [const { AtomicWaker::new() }; CHANNEL_COUNT];
94static RX_WAKERS: [AtomicWaker; CHANNEL_COUNT] = [const { AtomicWaker::new() }; CHANNEL_COUNT];
95
96cfg_if::cfg_if! {
97    if #[cfg(any(esp32c2, esp32c3))] {
98        use portable_atomic::AtomicBool;
99        static TX_IS_ASYNC: [AtomicBool; CHANNEL_COUNT] = [const { AtomicBool::new(false) }; CHANNEL_COUNT];
100        static RX_IS_ASYNC: [AtomicBool; CHANNEL_COUNT] = [const { AtomicBool::new(false) }; CHANNEL_COUNT];
101    }
102}
103
104impl crate::private::Sealed for AnyGdmaTxChannel<'_> {}
105impl DmaTxChannel for AnyGdmaTxChannel<'_> {}
106
107impl AnyGdmaTxChannel<'_> {
108    #[inline(always)]
109    fn ch(&self) -> &pac::dma::ch::CH {
110        DMA::regs().ch(self.channel as usize)
111    }
112
113    #[cfg(any(esp32c2, esp32c3))]
114    #[inline(always)]
115    fn int(&self) -> &pac::dma::int_ch::INT_CH {
116        DMA::regs().int_ch(self.channel as usize)
117    }
118    #[inline(always)]
119    #[cfg(any(esp32c6, esp32h2))]
120    fn int(&self) -> &pac::dma::out_int_ch::OUT_INT_CH {
121        DMA::regs().out_int_ch(self.channel as usize)
122    }
123    #[cfg(esp32s3)]
124    #[inline(always)]
125    fn int(&self) -> &pac::dma::ch::out_int::OUT_INT {
126        DMA::regs().ch(self.channel as usize).out_int()
127    }
128}
129
130impl RegisterAccess for AnyGdmaTxChannel<'_> {
131    fn reset(&self) {
132        let conf0 = self.ch().out_conf0();
133        conf0.modify(|_, w| w.out_rst().set_bit());
134        conf0.modify(|_, w| w.out_rst().clear_bit());
135    }
136
137    fn set_burst_mode(&self, burst_mode: BurstConfig) {
138        self.ch()
139            .out_conf0()
140            .modify(|_, w| w.out_data_burst_en().bit(burst_mode.is_burst_enabled()));
141    }
142
143    fn set_descr_burst_mode(&self, burst_mode: bool) {
144        self.ch()
145            .out_conf0()
146            .modify(|_, w| w.outdscr_burst_en().bit(burst_mode));
147    }
148
149    fn set_priority(&self, priority: DmaPriority) {
150        self.ch()
151            .out_pri()
152            .write(|w| unsafe { w.tx_pri().bits(priority as u8) });
153    }
154
155    fn set_peripheral(&self, peripheral: u8) {
156        self.ch()
157            .out_peri_sel()
158            .modify(|_, w| unsafe { w.peri_out_sel().bits(peripheral) });
159    }
160
161    fn set_link_addr(&self, address: u32) {
162        self.ch()
163            .out_link()
164            .modify(|_, w| unsafe { w.outlink_addr().bits(address) });
165    }
166
167    fn start(&self) {
168        self.ch()
169            .out_link()
170            .modify(|_, w| w.outlink_start().set_bit());
171    }
172
173    fn stop(&self) {
174        self.ch()
175            .out_link()
176            .modify(|_, w| w.outlink_stop().set_bit());
177    }
178
179    fn restart(&self) {
180        self.ch()
181            .out_link()
182            .modify(|_, w| w.outlink_restart().set_bit());
183    }
184
185    fn set_check_owner(&self, check_owner: Option<bool>) {
186        self.ch()
187            .out_conf1()
188            .modify(|_, w| w.out_check_owner().bit(check_owner.unwrap_or(true)));
189    }
190
191    #[cfg(esp32s3)]
192    fn set_ext_mem_block_size(&self, size: DmaExtMemBKSize) {
193        self.ch()
194            .out_conf1()
195            .modify(|_, w| unsafe { w.out_ext_mem_bk_size().bits(size as u8) });
196    }
197
198    #[cfg(psram_dma)]
199    fn can_access_psram(&self) -> bool {
200        true
201    }
202}
203
204impl TxRegisterAccess for AnyGdmaTxChannel<'_> {
205    fn is_fifo_empty(&self) -> bool {
206        cfg_if::cfg_if! {
207            if #[cfg(esp32s3)] {
208                 self.ch().outfifo_status().read().outfifo_empty_l3().bit_is_set()
209            } else {
210                 self.ch().outfifo_status().read().outfifo_empty().bit_is_set()
211            }
212        }
213    }
214
215    fn set_auto_write_back(&self, enable: bool) {
216        self.ch()
217            .out_conf0()
218            .modify(|_, w| w.out_auto_wrback().bit(enable));
219    }
220
221    fn last_dscr_address(&self) -> usize {
222        self.ch()
223            .out_eof_des_addr()
224            .read()
225            .out_eof_des_addr()
226            .bits() as _
227    }
228
229    fn async_handler(&self) -> Option<InterruptHandler> {
230        match self.channel {
231            0 => DMA_CH0::handler_out(),
232            #[cfg(not(esp32c2))]
233            1 => DMA_CH1::handler_out(),
234            #[cfg(not(esp32c2))]
235            2 => DMA_CH2::handler_out(),
236            #[cfg(esp32s3)]
237            3 => DMA_CH3::handler_out(),
238            #[cfg(esp32s3)]
239            4 => DMA_CH4::handler_out(),
240            _ => unreachable!(),
241        }
242    }
243
244    fn peripheral_interrupt(&self) -> Option<Interrupt> {
245        match self.channel {
246            0 => DMA_CH0::isr_out(),
247            #[cfg(not(esp32c2))]
248            1 => DMA_CH1::isr_out(),
249            #[cfg(not(esp32c2))]
250            2 => DMA_CH2::isr_out(),
251            #[cfg(esp32s3)]
252            3 => DMA_CH3::isr_out(),
253            #[cfg(esp32s3)]
254            4 => DMA_CH4::isr_out(),
255            _ => unreachable!(),
256        }
257    }
258}
259
260impl InterruptAccess<DmaTxInterrupt> for AnyGdmaTxChannel<'_> {
261    fn enable_listen(&self, interrupts: EnumSet<DmaTxInterrupt>, enable: bool) {
262        self.int().ena().modify(|_, w| {
263            for interrupt in interrupts {
264                match interrupt {
265                    DmaTxInterrupt::TotalEof => w.out_total_eof().bit(enable),
266                    DmaTxInterrupt::DescriptorError => w.out_dscr_err().bit(enable),
267                    DmaTxInterrupt::Eof => w.out_eof().bit(enable),
268                    DmaTxInterrupt::Done => w.out_done().bit(enable),
269                };
270            }
271            w
272        });
273    }
274
275    fn is_listening(&self) -> EnumSet<DmaTxInterrupt> {
276        let mut result = EnumSet::new();
277
278        let int_ena = self.int().ena().read();
279        if int_ena.out_total_eof().bit_is_set() {
280            result |= DmaTxInterrupt::TotalEof;
281        }
282        if int_ena.out_dscr_err().bit_is_set() {
283            result |= DmaTxInterrupt::DescriptorError;
284        }
285        if int_ena.out_eof().bit_is_set() {
286            result |= DmaTxInterrupt::Eof;
287        }
288        if int_ena.out_done().bit_is_set() {
289            result |= DmaTxInterrupt::Done;
290        }
291
292        result
293    }
294
295    fn clear(&self, interrupts: impl Into<EnumSet<DmaTxInterrupt>>) {
296        self.int().clr().write(|w| {
297            for interrupt in interrupts.into() {
298                match interrupt {
299                    DmaTxInterrupt::TotalEof => w.out_total_eof().clear_bit_by_one(),
300                    DmaTxInterrupt::DescriptorError => w.out_dscr_err().clear_bit_by_one(),
301                    DmaTxInterrupt::Eof => w.out_eof().clear_bit_by_one(),
302                    DmaTxInterrupt::Done => w.out_done().clear_bit_by_one(),
303                };
304            }
305            w
306        });
307    }
308
309    fn pending_interrupts(&self) -> EnumSet<DmaTxInterrupt> {
310        let mut result = EnumSet::new();
311
312        let int_raw = self.int().raw().read();
313        if int_raw.out_total_eof().bit_is_set() {
314            result |= DmaTxInterrupt::TotalEof;
315        }
316        if int_raw.out_dscr_err().bit_is_set() {
317            result |= DmaTxInterrupt::DescriptorError;
318        }
319        if int_raw.out_eof().bit_is_set() {
320            result |= DmaTxInterrupt::Eof;
321        }
322        if int_raw.out_done().bit_is_set() {
323            result |= DmaTxInterrupt::Done;
324        }
325
326        result
327    }
328
329    fn waker(&self) -> &'static AtomicWaker {
330        &TX_WAKERS[self.channel as usize]
331    }
332
333    fn is_async(&self) -> bool {
334        cfg_if::cfg_if! {
335            if #[cfg(any(esp32c2, esp32c3))] {
336                TX_IS_ASYNC[self.channel as usize].load(portable_atomic::Ordering::Acquire)
337            } else {
338                true
339            }
340        }
341    }
342
343    fn set_async(&self, _is_async: bool) {
344        cfg_if::cfg_if! {
345            if #[cfg(any(esp32c2, esp32c3))] {
346                TX_IS_ASYNC[self.channel as usize].store(_is_async, portable_atomic::Ordering::Release);
347            }
348        }
349    }
350}
351
352impl crate::private::Sealed for AnyGdmaRxChannel<'_> {}
353impl DmaRxChannel for AnyGdmaRxChannel<'_> {}
354
355impl AnyGdmaRxChannel<'_> {
356    #[inline(always)]
357    fn ch(&self) -> &pac::dma::ch::CH {
358        DMA::regs().ch(self.channel as usize)
359    }
360
361    #[cfg(any(esp32c2, esp32c3))]
362    #[inline(always)]
363    fn int(&self) -> &pac::dma::int_ch::INT_CH {
364        DMA::regs().int_ch(self.channel as usize)
365    }
366
367    #[inline(always)]
368    #[cfg(any(esp32c6, esp32h2))]
369    fn int(&self) -> &pac::dma::in_int_ch::IN_INT_CH {
370        DMA::regs().in_int_ch(self.channel as usize)
371    }
372
373    #[cfg(esp32s3)]
374    #[inline(always)]
375    fn int(&self) -> &pac::dma::ch::in_int::IN_INT {
376        DMA::regs().ch(self.channel as usize).in_int()
377    }
378}
379
380impl RegisterAccess for AnyGdmaRxChannel<'_> {
381    fn reset(&self) {
382        let conf0 = self.ch().in_conf0();
383        conf0.modify(|_, w| w.in_rst().set_bit());
384        conf0.modify(|_, w| w.in_rst().clear_bit());
385    }
386
387    fn set_burst_mode(&self, burst_mode: BurstConfig) {
388        self.ch()
389            .in_conf0()
390            .modify(|_, w| w.in_data_burst_en().bit(burst_mode.is_burst_enabled()));
391    }
392
393    fn set_descr_burst_mode(&self, burst_mode: bool) {
394        self.ch()
395            .in_conf0()
396            .modify(|_, w| w.indscr_burst_en().bit(burst_mode));
397    }
398
399    fn set_priority(&self, priority: DmaPriority) {
400        self.ch()
401            .in_pri()
402            .write(|w| unsafe { w.rx_pri().bits(priority as u8) });
403    }
404
405    fn set_peripheral(&self, peripheral: u8) {
406        self.ch()
407            .in_peri_sel()
408            .modify(|_, w| unsafe { w.peri_in_sel().bits(peripheral) });
409    }
410
411    fn set_link_addr(&self, address: u32) {
412        self.ch()
413            .in_link()
414            .modify(|_, w| unsafe { w.inlink_addr().bits(address) });
415    }
416
417    fn start(&self) {
418        self.ch()
419            .in_link()
420            .modify(|_, w| w.inlink_start().set_bit());
421    }
422
423    fn stop(&self) {
424        self.ch().in_link().modify(|_, w| w.inlink_stop().set_bit());
425    }
426
427    fn restart(&self) {
428        self.ch()
429            .in_link()
430            .modify(|_, w| w.inlink_restart().set_bit());
431    }
432
433    fn set_check_owner(&self, check_owner: Option<bool>) {
434        self.ch()
435            .in_conf1()
436            .modify(|_, w| w.in_check_owner().bit(check_owner.unwrap_or(true)));
437    }
438
439    #[cfg(esp32s3)]
440    fn set_ext_mem_block_size(&self, size: DmaExtMemBKSize) {
441        self.ch()
442            .in_conf1()
443            .modify(|_, w| unsafe { w.in_ext_mem_bk_size().bits(size as u8) });
444    }
445
446    #[cfg(psram_dma)]
447    fn can_access_psram(&self) -> bool {
448        true
449    }
450}
451
452impl RxRegisterAccess for AnyGdmaRxChannel<'_> {
453    fn set_mem2mem_mode(&self, value: bool) {
454        self.ch()
455            .in_conf0()
456            .modify(|_, w| w.mem_trans_en().bit(value));
457    }
458
459    fn async_handler(&self) -> Option<InterruptHandler> {
460        match self.channel {
461            0 => DMA_CH0::handler_in(),
462            #[cfg(not(esp32c2))]
463            1 => DMA_CH1::handler_in(),
464            #[cfg(not(esp32c2))]
465            2 => DMA_CH2::handler_in(),
466            #[cfg(esp32s3)]
467            3 => DMA_CH3::handler_in(),
468            #[cfg(esp32s3)]
469            4 => DMA_CH4::handler_in(),
470            _ => unreachable!(),
471        }
472    }
473
474    fn peripheral_interrupt(&self) -> Option<Interrupt> {
475        match self.channel {
476            0 => DMA_CH0::isr_in(),
477            #[cfg(not(esp32c2))]
478            1 => DMA_CH1::isr_in(),
479            #[cfg(not(esp32c2))]
480            2 => DMA_CH2::isr_in(),
481            #[cfg(esp32s3)]
482            3 => DMA_CH3::isr_in(),
483            #[cfg(esp32s3)]
484            4 => DMA_CH4::isr_in(),
485            _ => unreachable!(),
486        }
487    }
488}
489
490impl InterruptAccess<DmaRxInterrupt> for AnyGdmaRxChannel<'_> {
491    fn enable_listen(&self, interrupts: EnumSet<DmaRxInterrupt>, enable: bool) {
492        self.int().ena().modify(|_, w| {
493            for interrupt in interrupts {
494                match interrupt {
495                    DmaRxInterrupt::SuccessfulEof => w.in_suc_eof().bit(enable),
496                    DmaRxInterrupt::ErrorEof => w.in_err_eof().bit(enable),
497                    DmaRxInterrupt::DescriptorError => w.in_dscr_err().bit(enable),
498                    DmaRxInterrupt::DescriptorEmpty => w.in_dscr_empty().bit(enable),
499                    DmaRxInterrupt::Done => w.in_done().bit(enable),
500                };
501            }
502            w
503        });
504    }
505
506    fn is_listening(&self) -> EnumSet<DmaRxInterrupt> {
507        let mut result = EnumSet::new();
508
509        let int_ena = self.int().ena().read();
510        if int_ena.in_dscr_err().bit_is_set() {
511            result |= DmaRxInterrupt::DescriptorError;
512        }
513        if int_ena.in_dscr_empty().bit_is_set() {
514            result |= DmaRxInterrupt::DescriptorEmpty;
515        }
516        if int_ena.in_suc_eof().bit_is_set() {
517            result |= DmaRxInterrupt::SuccessfulEof;
518        }
519        if int_ena.in_err_eof().bit_is_set() {
520            result |= DmaRxInterrupt::ErrorEof;
521        }
522        if int_ena.in_done().bit_is_set() {
523            result |= DmaRxInterrupt::Done;
524        }
525
526        result
527    }
528
529    fn clear(&self, interrupts: impl Into<EnumSet<DmaRxInterrupt>>) {
530        self.int().clr().write(|w| {
531            for interrupt in interrupts.into() {
532                match interrupt {
533                    DmaRxInterrupt::SuccessfulEof => w.in_suc_eof().clear_bit_by_one(),
534                    DmaRxInterrupt::ErrorEof => w.in_err_eof().clear_bit_by_one(),
535                    DmaRxInterrupt::DescriptorError => w.in_dscr_err().clear_bit_by_one(),
536                    DmaRxInterrupt::DescriptorEmpty => w.in_dscr_empty().clear_bit_by_one(),
537                    DmaRxInterrupt::Done => w.in_done().clear_bit_by_one(),
538                };
539            }
540            w
541        });
542    }
543
544    fn pending_interrupts(&self) -> EnumSet<DmaRxInterrupt> {
545        let mut result = EnumSet::new();
546
547        let int_raw = self.int().raw().read();
548        if int_raw.in_dscr_err().bit_is_set() {
549            result |= DmaRxInterrupt::DescriptorError;
550        }
551        if int_raw.in_dscr_empty().bit_is_set() {
552            result |= DmaRxInterrupt::DescriptorEmpty;
553        }
554        if int_raw.in_suc_eof().bit_is_set() {
555            result |= DmaRxInterrupt::SuccessfulEof;
556        }
557        if int_raw.in_err_eof().bit_is_set() {
558            result |= DmaRxInterrupt::ErrorEof;
559        }
560        if int_raw.in_done().bit_is_set() {
561            result |= DmaRxInterrupt::Done;
562        }
563
564        result
565    }
566
567    fn waker(&self) -> &'static AtomicWaker {
568        &RX_WAKERS[self.channel as usize]
569    }
570
571    fn is_async(&self) -> bool {
572        cfg_if::cfg_if! {
573            if #[cfg(any(esp32c2, esp32c3))] {
574                RX_IS_ASYNC[self.channel as usize].load(portable_atomic::Ordering::Acquire)
575            } else {
576                true
577            }
578        }
579    }
580
581    fn set_async(&self, _is_async: bool) {
582        cfg_if::cfg_if! {
583            if #[cfg(any(esp32c2, esp32c3))] {
584                RX_IS_ASYNC[self.channel as usize].store(_is_async, portable_atomic::Ordering::Release);
585            }
586        }
587    }
588}
589
590impl<CH: DmaChannel, Dm: DriverMode> Channel<Dm, CH> {
591    pub fn runtime_ensure_compatible<P: DmaEligible>(&self, _peripheral: &P) {
593        }
595}
596
597macro_rules! impl_channel {
598    ($num:literal, $interrupt_in:ident $(, $interrupt_out:ident)? ) => {
599        paste::paste! {
600            use $crate::peripherals::[<DMA_CH $num>];
601            impl [<DMA_CH $num>]<'_> {
602                fn handler_in() -> Option<InterruptHandler> {
603                    $crate::if_set! {
604                        $({
605                            #[handler(priority = Priority::max())]
607                            fn interrupt_handler_in() {
608                                $crate::ignore!($interrupt_out);
609                                super::asynch::handle_in_interrupt::<[< DMA_CH $num >]<'static>>();
610                            }
611                            Some(interrupt_handler_in)
612                        })?,
613                        {
614                            #[handler(priority = Priority::max())]
615                            fn interrupt_handler() {
616                                super::asynch::handle_in_interrupt::<[< DMA_CH $num >]<'static>>();
617                                super::asynch::handle_out_interrupt::<[< DMA_CH $num >]<'static>>();
618                            }
619                            Some(interrupt_handler)
620                        }
621                    }
622                }
623
624                fn isr_in() -> Option<Interrupt> {
625                    Some(Interrupt::$interrupt_in)
626                }
627
628                fn handler_out() -> Option<InterruptHandler> {
629                    $crate::if_set! {
630                        $({
631                            #[handler(priority = Priority::max())]
632                            fn interrupt_handler_out() {
633                                $crate::ignore!($interrupt_out);
634                                super::asynch::handle_out_interrupt::<[< DMA_CH $num >]<'static>>();
635                            }
636                            Some(interrupt_handler_out)
637                        })?,
638                        None
639                    }
640                }
641
642                fn isr_out() -> Option<Interrupt> {
643                    $crate::if_set! { $(Some(Interrupt::$interrupt_out))?, None }
644                }
645            }
646
647            impl<'d> DmaChannel for [<DMA_CH $num>]<'d> {
648                type Rx = AnyGdmaRxChannel<'d>;
649                type Tx = AnyGdmaTxChannel<'d>;
650
651                unsafe fn split_internal(self, _: $crate::private::Internal) -> (Self::Rx, Self::Tx) {
652                    (
653                        AnyGdmaRxChannel {
654                            channel: $num,
655                            _lifetime: core::marker::PhantomData,
656                        },
657                        AnyGdmaTxChannel {
658                            channel: $num,
659                            _lifetime: core::marker::PhantomData,
660                        },
661                    )
662                }
663            }
664
665            impl<'d> DmaChannelConvert<AnyGdmaChannel<'d>> for [<DMA_CH $num>]<'d> {
666                fn degrade(self) -> AnyGdmaChannel<'d> {
667                    AnyGdmaChannel {
668                        channel: $num,
669                        _lifetime: core::marker::PhantomData,
670                    }
671                }
672            }
673
674            impl<'d> DmaChannelConvert<AnyGdmaRxChannel<'d>> for [<DMA_CH $num>]<'d> {
675                fn degrade(self) -> AnyGdmaRxChannel<'d> {
676                    AnyGdmaRxChannel {
677                        channel: $num,
678                        _lifetime: core::marker::PhantomData,
679                    }
680                }
681            }
682
683            impl<'d> DmaChannelConvert<AnyGdmaTxChannel<'d>> for [<DMA_CH $num>]<'d> {
684                fn degrade(self) -> AnyGdmaTxChannel<'d> {
685                    AnyGdmaTxChannel {
686                        channel: $num,
687                        _lifetime: core::marker::PhantomData,
688                    }
689                }
690            }
691
692            impl DmaChannelExt for [<DMA_CH $num>]<'_> {
693                fn rx_interrupts() -> impl InterruptAccess<DmaRxInterrupt> {
694                    AnyGdmaRxChannel {
695                        channel: $num,
696                        _lifetime: core::marker::PhantomData,
697                    }
698                }
699
700                fn tx_interrupts() -> impl InterruptAccess<DmaTxInterrupt> {
701                    AnyGdmaTxChannel {
702                        channel: $num,
703                        _lifetime: core::marker::PhantomData,
704                    }
705                }
706            }
707        }
708    };
709}
710
711cfg_if::cfg_if! {
712    if #[cfg(esp32c2)] {
713        const CHANNEL_COUNT: usize = 1;
714        impl_channel!(0, DMA_CH0);
715    } else if #[cfg(esp32c3)] {
716        const CHANNEL_COUNT: usize = 3;
717        impl_channel!(0, DMA_CH0);
718        impl_channel!(1, DMA_CH1);
719        impl_channel!(2, DMA_CH2);
720    } else if #[cfg(any(esp32c6, esp32h2))] {
721        const CHANNEL_COUNT: usize = 3;
722        impl_channel!(0, DMA_IN_CH0, DMA_OUT_CH0);
723        impl_channel!(1, DMA_IN_CH1, DMA_OUT_CH1);
724        impl_channel!(2, DMA_IN_CH2, DMA_OUT_CH2);
725    } else if #[cfg(esp32s3)] {
726        const CHANNEL_COUNT: usize = 5;
727        impl_channel!(0, DMA_IN_CH0, DMA_OUT_CH0);
728        impl_channel!(1, DMA_IN_CH1, DMA_OUT_CH1);
729        impl_channel!(2, DMA_IN_CH2, DMA_OUT_CH2);
730        impl_channel!(3, DMA_IN_CH3, DMA_OUT_CH3);
731        impl_channel!(4, DMA_IN_CH4, DMA_OUT_CH4);
732    }
733}
734
735crate::dma::impl_dma_eligible! {
736    AnyGdmaChannel {
737        #[cfg(soc_has_spi2)]
738        SPI2 => Spi2,
739
740        #[cfg(soc_has_spi3)]
741        SPI3 => Spi3,
742
743        #[cfg(soc_has_uhci0)]
744        UHCI0 => Uhci0,
745
746        #[cfg(soc_has_i2s0)]
747        I2S0 => I2s0,
748
749        #[cfg(soc_has_i2s1)]
750        I2S1 => I2s1,
751
752        #[cfg(esp32s3)]
753        LCD_CAM => LcdCam,
754
755        #[cfg(all(gdma, soc_has_aes))]
756        AES => Aes,
757
758        #[cfg(all(gdma, soc_has_sha))]
759        SHA => Sha,
760
761        #[cfg(any(esp32c3, esp32c6, esp32h2, esp32s3))]
762        ADC1 => Adc,
763
764        #[cfg(any(esp32c3, esp32s3))]
765        ADC2 => Adc,
766
767        #[cfg(esp32s3)]
768        RMT => Rmt,
769
770        #[cfg(soc_has_parl_io)]
771        PARL_IO => ParlIo,
772
773        #[cfg(any(esp32c2, esp32c6, esp32h2))]
774        MEM2MEM1 => Mem2Mem1,
775    }
776}
777
778#[cfg(any(esp32c6, esp32h2))]
779crate::dma::impl_dma_eligible! {
780    AnyGdmaChannel {
781        MEM2MEM4 => Mem2Mem4,
782        MEM2MEM5 => Mem2Mem5,
783        MEM2MEM10 => Mem2Mem10,
784        MEM2MEM11 => Mem2Mem11,
785        MEM2MEM12 => Mem2Mem12,
786        MEM2MEM13 => Mem2Mem13,
787        MEM2MEM14 => Mem2Mem14,
788        MEM2MEM15 => Mem2Mem15,
789    }
790}
791
792pub(super) fn init_dma_racey() {
793    DMA::regs()
794        .misc_conf()
795        .modify(|_, w| w.ahbm_rst_inter().set_bit());
796    DMA::regs()
797        .misc_conf()
798        .modify(|_, w| w.ahbm_rst_inter().clear_bit());
799    DMA::regs().misc_conf().modify(|_, w| w.clk_en().set_bit());
800}