esp_hal/dma/pdma/
crypto.rs

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