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}