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