1use core::marker::PhantomData;
8
9use crate::{
10 RegisterToggle,
11 asynch::AtomicWaker,
12 dma::*,
13 handler,
14 interrupt::Priority,
15 peripherals::{AXI_GDMA, Interrupt, pac},
16 system::{Peripheral, PeripheralGuard},
17};
18
19pub(crate) struct ChannelInfo {
21 pub(crate) channel: u8,
22 pub(crate) handler_in: Option<InterruptHandler>,
23 pub(crate) handler_out: Option<InterruptHandler>,
24 pub(crate) isr_in: Option<Interrupt>,
25 pub(crate) isr_out: Option<Interrupt>,
26 pub(crate) compatible_peripherals: &'static [u8],
27}
28
29pub(crate) struct ChannelState {
31 pub(crate) tx_waker: AtomicWaker,
32 pub(crate) rx_waker: AtomicWaker,
33}
34
35pub struct AxiGdmaChannel<'d> {
37 info: &'static ChannelInfo,
38 state: &'static ChannelState,
39 _lifetime: PhantomData<&'d mut ()>,
40}
41
42impl core::fmt::Debug for AxiGdmaChannel<'_> {
43 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
44 f.debug_struct("AxiGdmaChannel")
45 .field("channel", &self.info.channel)
46 .finish()
47 }
48}
49
50#[cfg(feature = "defmt")]
51impl defmt::Format for AxiGdmaChannel<'_> {
52 fn format(&self, fmt: defmt::Formatter<'_>) {
53 defmt::write!(fmt, "AxiGdmaChannel {{ channel: {} }}", self.info.channel)
54 }
55}
56
57impl AxiGdmaChannel<'_> {
58 pub(crate) fn channel_index(&self) -> u8 {
59 self.info.channel
60 }
61
62 pub(crate) unsafe fn clone_unchecked(&self) -> Self {
63 Self {
64 info: self.info,
65 state: self.state,
66 _lifetime: PhantomData,
67 }
68 }
69}
70
71impl crate::private::Sealed for AxiGdmaChannel<'_> {}
72impl<'d> DmaChannel for AxiGdmaChannel<'d> {
73 type Rx = AxiGdmaRxChannel<'d>;
74 type Tx = AxiGdmaTxChannel<'d>;
75
76 unsafe fn split_internal(self, _: crate::private::Internal) -> (Self::Rx, Self::Tx) {
77 (
78 AxiGdmaRxChannel(unsafe { self.clone_unchecked() }),
79 AxiGdmaTxChannel(self),
80 )
81 }
82}
83
84#[derive(Debug)]
86#[cfg_attr(feature = "defmt", derive(defmt::Format))]
87pub struct AxiGdmaRxChannel<'d>(AxiGdmaChannel<'d>);
88
89#[derive(Debug)]
91#[cfg_attr(feature = "defmt", derive(defmt::Format))]
92pub struct AxiGdmaTxChannel<'d>(AxiGdmaChannel<'d>);
93
94impl crate::private::Sealed for AxiGdmaTxChannel<'_> {}
95impl DmaTxChannel for AxiGdmaTxChannel<'_> {}
96
97impl crate::private::Sealed for AxiGdmaRxChannel<'_> {}
98impl DmaRxChannel for AxiGdmaRxChannel<'_> {}
99
100impl<'d> From<AxiGdmaChannel<'d>> for AxiGdmaRxChannel<'d> {
101 fn from(this: AxiGdmaChannel<'d>) -> AxiGdmaRxChannel<'d> {
102 AxiGdmaRxChannel(this)
103 }
104}
105
106impl<'d> From<AxiGdmaChannel<'d>> for AxiGdmaTxChannel<'d> {
107 fn from(this: AxiGdmaChannel<'d>) -> AxiGdmaTxChannel<'d> {
108 AxiGdmaTxChannel(this)
109 }
110}
111
112impl AxiGdmaTxChannel<'_> {
113 #[inline(always)]
114 fn ch(&self) -> &pac::axi_dma::OUT_CH {
115 AXI_GDMA::regs().out_ch(self.0.info.channel as usize)
116 }
117}
118
119impl RegisterAccess for AxiGdmaTxChannel<'_> {
120 #[allow(private_interfaces)]
121 fn enable(&self) -> Option<PeripheralGuard> {
122 Some(PeripheralGuard::new_with(
123 Peripheral::AxiGdma,
124 init_axi_dma_racey,
125 ))
126 }
127
128 fn reset(&self) {
129 self.ch().out_conf0().toggle(|w, en| w.out_rst().bit(en));
130 }
131
132 fn set_burst_mode(&self, _burst_mode: BurstConfig) {}
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 .write(|w| unsafe { w.peri_out_sel().bits(peripheral) });
151 }
152
153 fn set_link_addr(&self, address: u32) {
154 trace!("Setting out-link address to 0x{:08X}", address);
155 self.ch()
156 .out_link2()
157 .write(|w| unsafe { w.outlink_addr().bits(address) });
158 }
159
160 fn start(&self) {
161 self.ch()
162 .out_link1()
163 .modify(|_, w| w.outlink_start().set_bit());
164 }
165
166 fn stop(&self) {
167 self.ch()
168 .out_link1()
169 .modify(|_, w| w.outlink_stop().set_bit());
170 }
171
172 fn restart(&self) {
173 self.ch()
174 .out_link1()
175 .modify(|_, w| w.outlink_restart().set_bit());
176 }
177
178 fn set_check_owner(&self, check_owner: Option<bool>) {
179 self.ch()
180 .out_conf1()
181 .modify(|_, w| w.out_check_owner().bit(check_owner.unwrap_or(true)));
182 }
183
184 #[cfg(dma_can_access_psram)]
185 fn can_access_psram(&self) -> bool {
186 true
187 }
188
189 fn compatible_peripherals(&self) -> &[u8] {
190 self.0.info.compatible_peripherals
191 }
192}
193
194impl TxRegisterAccess for AxiGdmaTxChannel<'_> {
195 fn is_fifo_empty(&self) -> bool {
196 self.ch()
197 .outfifo_status()
198 .read()
199 .outfifo_l3_empty()
200 .bit_is_set()
201 }
202
203 fn set_auto_write_back(&self, enable: bool) {
204 self.ch()
205 .out_conf0()
206 .modify(|_, w| w.out_auto_wrback().bit(enable));
207 }
208
209 fn last_dscr_address(&self) -> usize {
210 self.ch()
211 .out_eof_des_addr()
212 .read()
213 .out_eof_des_addr()
214 .bits() as _
215 }
216
217 fn async_handler(&self) -> Option<InterruptHandler> {
218 self.0.info.handler_out
219 }
220
221 fn peripheral_interrupt(&self) -> Option<Interrupt> {
222 self.0.info.isr_out
223 }
224}
225
226impl InterruptAccess<DmaTxInterrupt> for AxiGdmaTxChannel<'_> {
227 fn enable_listen(&self, interrupts: EnumSet<DmaTxInterrupt>, enable: bool) {
228 self.ch().out_int().ena().modify(|_, w| {
229 for interrupt in interrupts {
230 match interrupt {
231 DmaTxInterrupt::TotalEof => w.out_total_eof().bit(enable),
232 DmaTxInterrupt::DescriptorError => w.out_dscr_err().bit(enable),
233 DmaTxInterrupt::Eof => w.out_eof().bit(enable),
234 DmaTxInterrupt::Done => w.out_done().bit(enable),
235 };
236 }
237 w
238 });
239 }
240
241 fn is_listening(&self) -> EnumSet<DmaTxInterrupt> {
242 let mut result = EnumSet::new();
243 let ena = self.ch().out_int().ena().read();
244 if ena.out_total_eof().bit_is_set() {
245 result |= DmaTxInterrupt::TotalEof;
246 }
247 if ena.out_dscr_err().bit_is_set() {
248 result |= DmaTxInterrupt::DescriptorError;
249 }
250 if ena.out_eof().bit_is_set() {
251 result |= DmaTxInterrupt::Eof;
252 }
253 if ena.out_done().bit_is_set() {
254 result |= DmaTxInterrupt::Done;
255 }
256 result
257 }
258
259 fn clear(&self, interrupts: impl Into<EnumSet<DmaTxInterrupt>>) {
260 self.ch().out_int().clr().write(|w| {
261 for interrupt in interrupts.into() {
262 match interrupt {
263 DmaTxInterrupt::TotalEof => w.out_total_eof().clear_bit_by_one(),
264 DmaTxInterrupt::DescriptorError => w.out_dscr_err().clear_bit_by_one(),
265 DmaTxInterrupt::Eof => w.out_eof().clear_bit_by_one(),
266 DmaTxInterrupt::Done => w.out_done().clear_bit_by_one(),
267 };
268 }
269 w
270 });
271 }
272
273 fn pending_interrupts(&self) -> EnumSet<DmaTxInterrupt> {
274 let mut result = EnumSet::new();
275 let raw = self.ch().out_int().raw().read();
276 if raw.out_total_eof().bit_is_set() {
277 result |= DmaTxInterrupt::TotalEof;
278 }
279 if raw.out_dscr_err().bit_is_set() {
280 result |= DmaTxInterrupt::DescriptorError;
281 }
282 if raw.out_eof().bit_is_set() {
283 result |= DmaTxInterrupt::Eof;
284 }
285 if raw.out_done().bit_is_set() {
286 result |= DmaTxInterrupt::Done;
287 }
288 result
289 }
290
291 fn waker(&self) -> &'static AtomicWaker {
292 &self.0.state.tx_waker
293 }
294
295 fn is_async(&self) -> bool {
296 true
297 }
298
299 fn set_async(&self, _is_async: bool) {}
300}
301
302impl AxiGdmaRxChannel<'_> {
303 #[inline(always)]
304 fn ch(&self) -> &pac::axi_dma::IN_CH {
305 AXI_GDMA::regs().in_ch(self.0.info.channel as usize)
306 }
307}
308
309impl RegisterAccess for AxiGdmaRxChannel<'_> {
310 #[allow(private_interfaces)]
311 fn enable(&self) -> Option<PeripheralGuard> {
312 Some(PeripheralGuard::new_with(
313 Peripheral::AxiGdma,
314 init_axi_dma_racey,
315 ))
316 }
317
318 fn reset(&self) {
319 self.ch().in_conf0().toggle(|w, en| w.in_rst().bit(en));
320 }
321
322 fn set_burst_mode(&self, _burst_mode: BurstConfig) {}
324
325 fn set_descr_burst_mode(&self, burst_mode: bool) {
326 self.ch()
327 .in_conf0()
328 .modify(|_, w| w.indscr_burst_en().bit(burst_mode));
329 }
330
331 fn set_priority(&self, priority: DmaPriority) {
332 self.ch()
333 .in_pri()
334 .write(|w| unsafe { w.rx_pri().bits(priority as u8) });
335 }
336
337 fn set_peripheral(&self, peripheral: u8) {
338 self.ch()
339 .in_peri_sel()
340 .write(|w| unsafe { w.peri_in_sel().bits(peripheral) });
341 }
342
343 fn set_link_addr(&self, address: u32) {
344 trace!("Setting in-link address to 0x{:08X}", address);
345 self.ch()
346 .in_link2()
347 .write(|w| unsafe { w.inlink_addr().bits(address) });
348 }
349
350 fn start(&self) {
351 self.ch()
352 .in_link1()
353 .modify(|_, w| w.inlink_start().set_bit());
354 }
355
356 fn stop(&self) {
357 self.ch()
358 .in_link1()
359 .modify(|_, w| w.inlink_stop().set_bit());
360 }
361
362 fn restart(&self) {
363 self.ch()
364 .in_link1()
365 .modify(|_, w| w.inlink_restart().set_bit());
366 }
367
368 fn set_check_owner(&self, check_owner: Option<bool>) {
369 self.ch()
370 .in_conf1()
371 .modify(|_, w| w.in_check_owner().bit(check_owner.unwrap_or(true)));
372 }
373
374 #[cfg(dma_can_access_psram)]
375 fn can_access_psram(&self) -> bool {
376 true
377 }
378
379 fn compatible_peripherals(&self) -> &[u8] {
380 self.0.info.compatible_peripherals
381 }
382}
383
384impl RxRegisterAccess for AxiGdmaRxChannel<'_> {
385 #[cfg(dma_supports_mem2mem)]
386 fn set_mem2mem_mode(&self, value: bool) {
387 self.ch()
388 .in_conf0()
389 .modify(|_, w| w.mem_trans_en().bit(value));
390 }
391
392 fn async_handler(&self) -> Option<InterruptHandler> {
393 self.0.info.handler_in
394 }
395
396 fn peripheral_interrupt(&self) -> Option<Interrupt> {
397 self.0.info.isr_in
398 }
399}
400
401impl InterruptAccess<DmaRxInterrupt> for AxiGdmaRxChannel<'_> {
402 fn enable_listen(&self, interrupts: EnumSet<DmaRxInterrupt>, enable: bool) {
403 self.ch().in_int().ena().modify(|_, w| {
404 for interrupt in interrupts {
405 match interrupt {
406 DmaRxInterrupt::SuccessfulEof => w.in_suc_eof().bit(enable),
407 DmaRxInterrupt::ErrorEof => w.in_err_eof().bit(enable),
408 DmaRxInterrupt::DescriptorError => w.in_dscr_err().bit(enable),
409 DmaRxInterrupt::DescriptorEmpty => w.in_dscr_empty().bit(enable),
410 DmaRxInterrupt::Done => w.in_done().bit(enable),
411 };
412 }
413 w
414 });
415 }
416
417 fn is_listening(&self) -> EnumSet<DmaRxInterrupt> {
418 let mut result = EnumSet::new();
419 let ena = self.ch().in_int().ena().read();
420 if ena.in_suc_eof().bit_is_set() {
421 result |= DmaRxInterrupt::SuccessfulEof;
422 }
423 if ena.in_err_eof().bit_is_set() {
424 result |= DmaRxInterrupt::ErrorEof;
425 }
426 if ena.in_dscr_err().bit_is_set() {
427 result |= DmaRxInterrupt::DescriptorError;
428 }
429 if ena.in_dscr_empty().bit_is_set() {
430 result |= DmaRxInterrupt::DescriptorEmpty;
431 }
432 if ena.in_done().bit_is_set() {
433 result |= DmaRxInterrupt::Done;
434 }
435 result
436 }
437
438 fn clear(&self, interrupts: impl Into<EnumSet<DmaRxInterrupt>>) {
439 self.ch().in_int().clr().write(|w| {
440 for interrupt in interrupts.into() {
441 match interrupt {
442 DmaRxInterrupt::SuccessfulEof => w.in_suc_eof().clear_bit_by_one(),
443 DmaRxInterrupt::ErrorEof => w.in_err_eof().clear_bit_by_one(),
444 DmaRxInterrupt::DescriptorError => w.in_dscr_err().clear_bit_by_one(),
445 DmaRxInterrupt::DescriptorEmpty => w.in_dscr_empty().clear_bit_by_one(),
446 DmaRxInterrupt::Done => w.in_done().clear_bit_by_one(),
447 };
448 }
449 w
450 });
451 }
452
453 fn pending_interrupts(&self) -> EnumSet<DmaRxInterrupt> {
454 let mut result = EnumSet::new();
455 let raw = self.ch().in_int().raw().read();
456 if raw.in_suc_eof().bit_is_set() {
457 result |= DmaRxInterrupt::SuccessfulEof;
458 }
459 if raw.in_err_eof().bit_is_set() {
460 result |= DmaRxInterrupt::ErrorEof;
461 }
462 if raw.in_dscr_err().bit_is_set() {
463 result |= DmaRxInterrupt::DescriptorError;
464 }
465 if raw.in_dscr_empty().bit_is_set() {
466 result |= DmaRxInterrupt::DescriptorEmpty;
467 }
468 if raw.in_done().bit_is_set() {
469 result |= DmaRxInterrupt::Done;
470 }
471 result
472 }
473
474 fn waker(&self) -> &'static AtomicWaker {
475 &self.0.state.rx_waker
476 }
477
478 fn is_async(&self) -> bool {
479 true
480 }
481
482 fn set_async(&self, _is_async: bool) {}
483}
484
485macro_rules! impl_channel {
486 ($ch:ident, $num:literal, $interrupt_in:ident, $interrupt_out:ident, compatible = [$($compatible:ident),*]) => {
487 use $crate::peripherals::$ch;
488 impl $ch<'_> {
489 pub(super) fn info() -> &'static ChannelInfo {
490 #[handler(priority = Priority::max())]
491 fn interrupt_handler_in() {
492 asynch::handle_in_interrupt::<$ch<'static>>();
493 }
494
495 #[handler(priority = Priority::max())]
496 fn interrupt_handler_out() {
497 asynch::handle_out_interrupt::<$ch<'static>>();
498 }
499
500 static INFO: ChannelInfo = ChannelInfo {
501 channel: $num,
502 handler_in: Some(interrupt_handler_in),
503 handler_out: Some(interrupt_handler_out),
504 isr_in: Some(Interrupt::$interrupt_in),
505 isr_out: Some(Interrupt::$interrupt_out),
506 compatible_peripherals: &[$(crate::dma::DmaPeripheral::$compatible.0),*],
507 };
508 &INFO
509 }
510
511 pub(super) fn state() -> &'static ChannelState {
512 static STATE: ChannelState = ChannelState {
513 tx_waker: AtomicWaker::new(),
514 rx_waker: AtomicWaker::new(),
515 };
516 &STATE
517 }
518 }
519
520 impl<'d> From<$ch<'d>> for AxiGdmaChannel<'d> {
521 fn from(_ch: $ch<'d>) -> AxiGdmaChannel<'d> {
522 AxiGdmaChannel {
523 info: $ch::info(),
524 state: $ch::state(),
525 _lifetime: core::marker::PhantomData,
526 }
527 }
528 }
529 crate::dma::impl_channel_common!(AxiGdma, $ch);
530 };
531}
532
533for_each_dma_channel! {
534 ("AXI_GDMA", $ch:ident, $num:literal, interrupt_in = $interrupt_in:ident, interrupt_out = $interrupt_out:ident, compatible = [$($compatible:ident),*]) => {
535 impl_channel!($ch, $num, $interrupt_in, $interrupt_out, compatible = [$($compatible),*]);
536 };
537}
538
539fn init_axi_dma_racey() {
540 let regs = AXI_GDMA::regs();
541
542 regs.misc_conf().toggle(|w, en| {
544 w.axim_rst_rd_inter().bit(en);
545 w.axim_rst_wr_inter().bit(en)
546 });
547
548 regs.misc_conf().modify(|_, w| w.clk_en().set_bit());
549
550 cfg_select! {
553 esp32s31 => {
554 regs.intr_mem_start_addr()
555 .write(|w| unsafe { w.access_intr_mem_start_addr().bits(0x2F00_0000) });
556 regs.intr_mem_end_addr()
557 .write(|w| unsafe { w.access_intr_mem_end_addr().bits(0x2F07_FFFF) });
558 regs.extr_mem_start_addr()
559 .write(|w| unsafe { w.access_extr_mem_start_addr().bits(0x4000_0000) });
560 regs.extr_mem_end_addr()
561 .write(|w| unsafe { w.access_extr_mem_end_addr().bits(0x53FF_FFFF) });
562 }
563 _ => {
564 regs.intr_mem_start_addr()
565 .write(|w| unsafe { w.access_intr_mem_start_addr().bits(0x4FC0_0000) });
566 regs.intr_mem_end_addr()
567 .write(|w| unsafe { w.access_intr_mem_end_addr().bits(0x4FFC_0000) });
568 regs.extr_mem_start_addr()
569 .write(|w| unsafe { w.access_extr_mem_start_addr().bits(0x4000_0000) });
570 regs.extr_mem_end_addr()
571 .write(|w| unsafe { w.access_extr_mem_end_addr().bits(0x4C00_0000) });
572 }
573 }
574}