1use enumset::EnumSet;
2use portable_atomic::{AtomicBool, Ordering};
3
4use crate::{
5 RegisterToggle,
6 asynch::AtomicWaker,
7 dma::{
8 BurstConfig,
9 DmaChannel,
10 DmaExtMemBKSize,
11 DmaRxChannel,
12 DmaRxInterrupt,
13 DmaTxChannel,
14 DmaTxInterrupt,
15 InterruptAccess,
16 RegisterAccess,
17 RxRegisterAccess,
18 TxRegisterAccess,
19 asynch,
20 },
21 interrupt::InterruptHandler,
22 peripherals::{DMA_COPY, Interrupt},
23 system::{Peripheral, PeripheralGuard},
24};
25
26#[doc(hidden)]
28pub struct ChannelInfo {
29 #[expect(dead_code)]
30 pub(crate) peripheral_interrupt: Interrupt,
31
32 #[expect(dead_code)]
33 pub(crate) async_handler: InterruptHandler,
34
35 pub(crate) compatible_peripherals: &'static [u8],
37}
38
39pub(crate) struct ChannelState {
41 pub(crate) tx_waker: AtomicWaker,
43
44 pub(crate) rx_waker: AtomicWaker,
46
47 pub(crate) tx_async_flag: portable_atomic::AtomicBool,
49
50 pub(crate) rx_async_flag: portable_atomic::AtomicBool,
52}
53
54pub(super) type CopyRegisterBlock = crate::pac::copy_dma::RegisterBlock;
55
56#[derive(Debug)]
58#[cfg_attr(feature = "defmt", derive(defmt::Format))]
59pub struct CopyDmaRxChannel<'d>(CopyDmaChannel<'d>);
60
61impl CopyDmaRxChannel<'_> {
62 fn regs(&self) -> &CopyRegisterBlock {
63 self.0.register_block()
64 }
65}
66
67impl crate::private::Sealed for CopyDmaRxChannel<'_> {}
68impl DmaRxChannel for CopyDmaRxChannel<'_> {}
69
70#[derive(Debug)]
72#[cfg_attr(feature = "defmt", derive(defmt::Format))]
73pub struct CopyDmaTxChannel<'d>(CopyDmaChannel<'d>);
74
75impl CopyDmaTxChannel<'_> {
76 fn regs(&self) -> &CopyRegisterBlock {
77 self.0.register_block()
78 }
79}
80
81impl crate::private::Sealed for CopyDmaTxChannel<'_> {}
82impl DmaTxChannel for CopyDmaTxChannel<'_> {}
83
84impl RegisterAccess for CopyDmaTxChannel<'_> {
85 #[allow(private_interfaces)]
86 fn enable(&self) -> Option<PeripheralGuard> {
87 Some(PeripheralGuard::new(Peripheral::CopyDma))
88 }
89
90 fn reset(&self) {
91 self.regs().conf().toggle(|w, bit| w.out_rst().bit(bit));
92 }
93
94 fn set_burst_mode(&self, _burst_mode: BurstConfig) {}
95
96 fn set_descr_burst_mode(&self, _burst_mode: bool) {}
97
98 fn set_link_addr(&self, address: u32) {
99 self.regs()
100 .out_link()
101 .modify(|_, w| unsafe { w.outlink_addr().bits(address) });
102 }
103
104 fn start(&self) {
105 self.regs()
106 .out_link()
107 .modify(|_, w| w.outlink_start().set_bit());
108 }
109
110 fn stop(&self) {
111 self.regs()
112 .out_link()
113 .modify(|_, w| w.outlink_stop().set_bit());
114 }
115
116 fn restart(&self) {
117 self.regs()
118 .out_link()
119 .modify(|_, w| w.outlink_restart().set_bit());
120 }
121
122 fn set_check_owner(&self, check_owner: Option<bool>) {
123 if check_owner == Some(true) {
124 panic!("Copy DMA does not support checking descriptor ownership");
125 }
126 }
127
128 #[cfg(dma_ext_mem_configurable_block_size)]
129 fn set_ext_mem_block_size(&self, _size: DmaExtMemBKSize) {
130 }
132
133 #[cfg(dma_can_access_psram)]
134 fn can_access_psram(&self) -> bool {
135 false
136 }
137
138 fn compatible_peripherals(&self) -> &[u8] {
139 self.0.info().compatible_peripherals
140 }
141}
142
143impl TxRegisterAccess for CopyDmaTxChannel<'_> {
144 fn is_fifo_empty(&self) -> bool {
145 self.regs().in_st().read().fifo_empty().bit()
146 }
147
148 fn set_auto_write_back(&self, enable: bool) {
149 self.regs()
150 .conf()
151 .modify(|_, w| w.out_auto_wrback().bit(enable));
152 }
153
154 fn last_dscr_address(&self) -> usize {
155 self.regs()
156 .out_eof_des_addr()
157 .read()
158 .out_eof_des_addr()
159 .bits() as usize
160 }
161
162 fn peripheral_interrupt(&self) -> Option<Interrupt> {
163 None
164 }
165
166 fn async_handler(&self) -> Option<InterruptHandler> {
167 None
168 }
169}
170
171impl InterruptAccess<DmaTxInterrupt> for CopyDmaTxChannel<'_> {
172 fn enable_listen(&self, interrupts: EnumSet<DmaTxInterrupt>, enable: bool) {
173 self.regs().int_ena().modify(|_, w| {
174 for interrupt in interrupts {
175 match interrupt {
176 DmaTxInterrupt::TotalEof => w.out_total_eof().bit(enable),
177 DmaTxInterrupt::DescriptorError => w.out_dscr_err().bit(enable),
178 DmaTxInterrupt::Eof => w.out_eof().bit(enable),
179 DmaTxInterrupt::Done => w.out_done().bit(enable),
180 };
181 }
182 w
183 });
184 }
185
186 fn is_listening(&self) -> EnumSet<DmaTxInterrupt> {
187 let mut result = EnumSet::new();
188
189 let int_ena = self.regs().int_ena().read();
190 if int_ena.out_total_eof().bit_is_set() {
191 result |= DmaTxInterrupt::TotalEof;
192 }
193 if int_ena.out_dscr_err().bit_is_set() {
194 result |= DmaTxInterrupt::DescriptorError;
195 }
196 if int_ena.out_eof().bit_is_set() {
197 result |= DmaTxInterrupt::Eof;
198 }
199 if int_ena.out_done().bit_is_set() {
200 result |= DmaTxInterrupt::Done;
201 }
202
203 result
204 }
205
206 fn clear(&self, interrupts: impl Into<EnumSet<DmaTxInterrupt>>) {
207 self.regs().int_clr().write(|w| {
208 for interrupt in interrupts.into() {
209 match interrupt {
210 DmaTxInterrupt::TotalEof => w.out_total_eof().clear_bit_by_one(),
211 DmaTxInterrupt::DescriptorError => w.out_dscr_err().clear_bit_by_one(),
212 DmaTxInterrupt::Eof => w.out_eof().clear_bit_by_one(),
213 DmaTxInterrupt::Done => w.out_done().clear_bit_by_one(),
214 };
215 }
216 w
217 });
218 }
219
220 fn pending_interrupts(&self) -> EnumSet<DmaTxInterrupt> {
221 let mut result = EnumSet::new();
222
223 let int_raw = self.regs().int_raw().read();
224 if int_raw.out_total_eof().bit_is_set() {
225 result |= DmaTxInterrupt::TotalEof;
226 }
227 if int_raw.out_dscr_err().bit_is_set() {
228 result |= DmaTxInterrupt::DescriptorError;
229 }
230 if int_raw.out_eof().bit_is_set() {
231 result |= DmaTxInterrupt::Eof;
232 }
233 if int_raw.out_done().bit_is_set() {
234 result |= DmaTxInterrupt::Done;
235 }
236
237 result
238 }
239
240 fn waker(&self) -> &'static AtomicWaker {
241 &self.0.state().tx_waker
242 }
243
244 fn is_async(&self) -> bool {
245 self.0.state().tx_async_flag.load(Ordering::Acquire)
246 }
247
248 fn set_async(&self, is_async: bool) {
249 self.0
250 .state()
251 .tx_async_flag
252 .store(is_async, Ordering::Release);
253 }
254}
255
256impl RegisterAccess for CopyDmaRxChannel<'_> {
257 #[allow(private_interfaces)]
258 fn enable(&self) -> Option<PeripheralGuard> {
259 Some(PeripheralGuard::new(Peripheral::CopyDma))
260 }
261
262 fn reset(&self) {
263 self.regs().conf().toggle(|w, bit| w.in_rst().bit(bit));
264 }
265
266 fn set_burst_mode(&self, _burst_mode: BurstConfig) {}
267
268 fn set_descr_burst_mode(&self, _burst_mode: bool) {}
269
270 fn set_link_addr(&self, address: u32) {
271 self.regs()
272 .in_link()
273 .modify(|_, w| unsafe { w.inlink_addr().bits(address) });
274 }
275
276 fn start(&self) {
277 self.regs()
278 .in_link()
279 .modify(|_, w| w.inlink_start().set_bit());
280 }
281
282 fn stop(&self) {
283 self.regs()
284 .in_link()
285 .modify(|_, w| w.inlink_stop().set_bit());
286 }
287
288 fn restart(&self) {
289 self.regs()
290 .in_link()
291 .modify(|_, w| w.inlink_restart().set_bit());
292 }
293
294 fn set_check_owner(&self, check_owner: Option<bool>) {
295 if check_owner == Some(true) {
296 panic!("Copy DMA does not support checking descriptor ownership");
297 }
298 }
299
300 #[cfg(dma_ext_mem_configurable_block_size)]
301 fn set_ext_mem_block_size(&self, _size: DmaExtMemBKSize) {
302 }
304
305 #[cfg(dma_can_access_psram)]
306 fn can_access_psram(&self) -> bool {
307 false
308 }
309
310 fn compatible_peripherals(&self) -> &[u8] {
311 self.0.info().compatible_peripherals
312 }
313}
314
315impl RxRegisterAccess for CopyDmaRxChannel<'_> {
316 #[cfg(dma_supports_mem2mem)]
317 fn set_mem2mem_mode(&self, _value: bool) {}
318
319 fn peripheral_interrupt(&self) -> Option<Interrupt> {
320 None
321 }
322
323 fn async_handler(&self) -> Option<InterruptHandler> {
324 None
325 }
326}
327
328impl InterruptAccess<DmaRxInterrupt> for CopyDmaRxChannel<'_> {
329 fn enable_listen(&self, interrupts: EnumSet<DmaRxInterrupt>, enable: bool) {
330 self.regs().int_ena().modify(|_, w| {
331 for interrupt in interrupts {
332 match interrupt {
333 DmaRxInterrupt::SuccessfulEof => w.in_suc_eof().bit(enable),
334 DmaRxInterrupt::ErrorEof => unimplemented!(),
335 DmaRxInterrupt::DescriptorError => w.in_dscr_err().bit(enable),
336 DmaRxInterrupt::DescriptorEmpty => w.in_dscr_empty().bit(enable),
337 DmaRxInterrupt::Done => w.in_done().bit(enable),
338 };
339 }
340 w
341 });
342 }
343
344 fn is_listening(&self) -> EnumSet<DmaRxInterrupt> {
345 let mut result = EnumSet::new();
346
347 let int_ena = self.regs().int_ena().read();
348 if int_ena.in_dscr_err().bit_is_set() {
349 result |= DmaRxInterrupt::DescriptorError;
350 }
351 if int_ena.in_dscr_empty().bit_is_set() {
352 result |= DmaRxInterrupt::DescriptorEmpty;
353 }
354 if int_ena.in_suc_eof().bit_is_set() {
355 result |= DmaRxInterrupt::SuccessfulEof;
356 }
357 if int_ena.in_done().bit_is_set() {
358 result |= DmaRxInterrupt::Done;
359 }
360
361 result
362 }
363
364 fn clear(&self, interrupts: impl Into<EnumSet<DmaRxInterrupt>>) {
365 self.regs().int_clr().write(|w| {
366 for interrupt in interrupts.into() {
367 match interrupt {
368 DmaRxInterrupt::SuccessfulEof => w.in_suc_eof().clear_bit_by_one(),
369 DmaRxInterrupt::ErrorEof => continue,
370 DmaRxInterrupt::DescriptorError => w.in_dscr_err().clear_bit_by_one(),
371 DmaRxInterrupt::DescriptorEmpty => w.in_dscr_empty().clear_bit_by_one(),
372 DmaRxInterrupt::Done => w.in_done().clear_bit_by_one(),
373 };
374 }
375 w
376 });
377 }
378
379 fn pending_interrupts(&self) -> EnumSet<DmaRxInterrupt> {
380 let mut result = EnumSet::new();
381
382 let int_raw = self.regs().int_raw().read();
383 if int_raw.in_dscr_err().bit_is_set() {
384 result |= DmaRxInterrupt::DescriptorError;
385 }
386 if int_raw.in_dscr_empty().bit_is_set() {
387 result |= DmaRxInterrupt::DescriptorEmpty;
388 }
389 if int_raw.in_suc_eof().bit_is_set() {
390 result |= DmaRxInterrupt::SuccessfulEof;
391 }
392 if int_raw.in_done().bit_is_set() {
393 result |= DmaRxInterrupt::Done;
394 }
395
396 result
397 }
398
399 fn waker(&self) -> &'static AtomicWaker {
400 &self.0.state().rx_waker
401 }
402
403 fn is_async(&self) -> bool {
404 self.0.state().rx_async_flag.load(Ordering::Relaxed)
405 }
406
407 fn set_async(&self, is_async: bool) {
408 self.0
409 .state()
410 .rx_async_flag
411 .store(is_async, Ordering::Relaxed);
412 }
413}
414
415pub type CopyDmaChannel<'d> = DMA_COPY<'d>;
417
418impl DMA_COPY<'_> {
419 pub(super) fn info(&self) -> &'static ChannelInfo {
420 #[crate::handler(priority = crate::interrupt::Priority::max())]
421 fn interrupt_handler() {
422 asynch::handle_in_interrupt::<DMA_COPY<'static>>();
423 asynch::handle_out_interrupt::<DMA_COPY<'static>>();
424 }
425 static INFO: ChannelInfo = ChannelInfo {
426 peripheral_interrupt: Interrupt::DMA_COPY,
427 async_handler: interrupt_handler,
428 compatible_peripherals: &[],
429 };
430 &INFO
431 }
432 pub(super) fn state(&self) -> &'static ChannelState {
433 static STATE: ChannelState = ChannelState {
434 tx_waker: AtomicWaker::new(),
435 rx_waker: AtomicWaker::new(),
436 tx_async_flag: AtomicBool::new(false),
437 rx_async_flag: AtomicBool::new(false),
438 };
439 &STATE
440 }
441}
442
443crate::dma::impl_channel_common!(CopyDma, DMA_COPY);