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