esp_hal/dma/pdma/
crypto.rs

1use enumset::EnumSet;
2use portable_atomic::{AtomicBool, Ordering};
3
4use crate::{
5    asynch::AtomicWaker,
6    dma::{
7        BurstConfig,
8        DmaChannel,
9        DmaChannelConvert,
10        DmaChannelExt,
11        DmaExtMemBKSize,
12        DmaPeripheral,
13        DmaRxChannel,
14        DmaRxInterrupt,
15        DmaTxChannel,
16        DmaTxInterrupt,
17        InterruptAccess,
18        PdmaChannel,
19        RegisterAccess,
20        RxRegisterAccess,
21        TxRegisterAccess,
22        asynch,
23    },
24    interrupt::{InterruptHandler, Priority},
25    peripherals::{DMA_CRYPTO, Interrupt},
26};
27
28pub(super) type CryptoRegisterBlock = crate::pac::crypto_dma::RegisterBlock;
29
30/// The RX half of a Crypto DMA channel.
31#[derive(Debug)]
32#[cfg_attr(feature = "defmt", derive(defmt::Format))]
33pub struct CryptoDmaRxChannel<'d>(pub(crate) DMA_CRYPTO<'d>);
34
35impl CryptoDmaRxChannel<'_> {
36    fn regs(&self) -> &CryptoRegisterBlock {
37        self.0.register_block()
38    }
39}
40
41impl crate::private::Sealed for CryptoDmaRxChannel<'_> {}
42impl DmaRxChannel for CryptoDmaRxChannel<'_> {}
43
44/// The TX half of a Crypto DMA channel.
45#[derive(Debug)]
46#[cfg_attr(feature = "defmt", derive(defmt::Format))]
47pub struct CryptoDmaTxChannel<'d>(pub(crate) DMA_CRYPTO<'d>);
48
49impl CryptoDmaTxChannel<'_> {
50    fn regs(&self) -> &CryptoRegisterBlock {
51        self.0.register_block()
52    }
53}
54
55impl crate::private::Sealed for CryptoDmaTxChannel<'_> {}
56impl DmaTxChannel for CryptoDmaTxChannel<'_> {}
57
58impl RegisterAccess for CryptoDmaTxChannel<'_> {
59    fn reset(&self) {
60        self.regs().conf().modify(|_, w| {
61            w.out_rst().set_bit();
62            w.ahbm_rst().set_bit();
63            w.ahbm_fifo_rst().set_bit()
64        });
65        self.regs().conf().modify(|_, w| {
66            w.out_rst().clear_bit();
67            w.ahbm_rst().clear_bit();
68            w.ahbm_fifo_rst().clear_bit()
69        });
70    }
71
72    fn set_burst_mode(&self, burst_mode: BurstConfig) {
73        self.regs()
74            .conf()
75            .modify(|_, w| w.out_data_burst_en().bit(burst_mode.is_burst_enabled()));
76    }
77
78    fn set_descr_burst_mode(&self, burst_mode: bool) {
79        self.regs()
80            .conf()
81            .modify(|_, w| w.outdscr_burst_en().bit(burst_mode));
82    }
83
84    fn set_peripheral(&self, peripheral: u8) {
85        use esp32s2::crypto_dma::aes_sha_select::SELECT;
86        let peripheral = match peripheral {
87            p if p == DmaPeripheral::Aes as u8 => SELECT::Aes,
88            p if p == DmaPeripheral::Sha as u8 => SELECT::Sha,
89            _ => unreachable!(),
90        };
91        self.regs()
92            .aes_sha_select()
93            .modify(|_, w| w.select().variant(peripheral));
94    }
95
96    fn set_link_addr(&self, address: u32) {
97        self.regs()
98            .out_link()
99            .modify(|_, w| unsafe { w.outlink_addr().bits(address) });
100    }
101
102    fn start(&self) {
103        self.regs()
104            .out_link()
105            .modify(|_, w| w.outlink_start().set_bit());
106    }
107
108    fn stop(&self) {
109        self.regs()
110            .out_link()
111            .modify(|_, w| w.outlink_stop().set_bit());
112    }
113
114    fn restart(&self) {
115        self.regs()
116            .out_link()
117            .modify(|_, w| w.outlink_restart().set_bit());
118    }
119
120    fn set_check_owner(&self, check_owner: Option<bool>) {
121        if check_owner == Some(true) {
122            panic!("Crypto DMA does not support checking descriptor ownership");
123        }
124    }
125
126    fn is_compatible_with(&self, peripheral: DmaPeripheral) -> bool {
127        self.0.is_compatible_with(peripheral)
128    }
129
130    #[cfg(psram_dma)]
131    fn set_ext_mem_block_size(&self, size: DmaExtMemBKSize) {
132        self.regs()
133            .conf1()
134            .modify(|_, w| unsafe { w.ext_mem_bk_size().bits(size as u8) });
135    }
136
137    #[cfg(psram_dma)]
138    fn can_access_psram(&self) -> bool {
139        true
140    }
141}
142
143impl TxRegisterAccess for CryptoDmaTxChannel<'_> {
144    fn is_fifo_empty(&self) -> bool {
145        self.regs().state1().read().outfifo_cnt_debug().bits() == 0
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 CryptoDmaTxChannel<'_> {
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.tx_waker()
242    }
243
244    fn is_async(&self) -> bool {
245        self.0.tx_async_flag().load(Ordering::Acquire)
246    }
247
248    fn set_async(&self, is_async: bool) {
249        self.0.tx_async_flag().store(is_async, Ordering::Release);
250    }
251}
252
253impl RegisterAccess for CryptoDmaRxChannel<'_> {
254    fn reset(&self) {
255        self.regs().conf().modify(|_, w| {
256            w.in_rst().set_bit();
257            w.ahbm_rst().set_bit();
258            w.ahbm_fifo_rst().set_bit()
259        });
260        self.regs().conf().modify(|_, w| {
261            w.in_rst().clear_bit();
262            w.ahbm_rst().clear_bit();
263            w.ahbm_fifo_rst().clear_bit()
264        });
265    }
266
267    fn set_burst_mode(&self, _burst_mode: BurstConfig) {}
268
269    fn set_descr_burst_mode(&self, burst_mode: bool) {
270        self.regs()
271            .conf()
272            .modify(|_, w| w.indscr_burst_en().bit(burst_mode));
273    }
274
275    fn set_peripheral(&self, peripheral: u8) {
276        use esp32s2::crypto_dma::aes_sha_select::SELECT;
277        let peripheral = match peripheral {
278            p if p == DmaPeripheral::Aes as u8 => SELECT::Aes,
279            p if p == DmaPeripheral::Sha as u8 => SELECT::Sha,
280            _ => unreachable!(),
281        };
282        self.regs()
283            .aes_sha_select()
284            .modify(|_, w| w.select().variant(peripheral));
285    }
286
287    fn set_link_addr(&self, address: u32) {
288        self.regs()
289            .in_link()
290            .modify(|_, w| unsafe { w.inlink_addr().bits(address) });
291    }
292
293    fn start(&self) {
294        self.regs()
295            .in_link()
296            .modify(|_, w| w.inlink_start().set_bit());
297    }
298
299    fn stop(&self) {
300        self.regs()
301            .in_link()
302            .modify(|_, w| w.inlink_stop().set_bit());
303    }
304
305    fn restart(&self) {
306        self.regs()
307            .in_link()
308            .modify(|_, w| w.inlink_restart().set_bit());
309    }
310
311    fn set_check_owner(&self, check_owner: Option<bool>) {
312        if check_owner == Some(true) {
313            panic!("Crypto DMA does not support checking descriptor ownership");
314        }
315    }
316
317    fn is_compatible_with(&self, peripheral: DmaPeripheral) -> bool {
318        self.0.is_compatible_with(peripheral)
319    }
320
321    #[cfg(psram_dma)]
322    fn set_ext_mem_block_size(&self, size: DmaExtMemBKSize) {
323        self.regs()
324            .conf1()
325            .modify(|_, w| unsafe { w.ext_mem_bk_size().bits(size as u8) });
326    }
327
328    #[cfg(psram_dma)]
329    fn can_access_psram(&self) -> bool {
330        true
331    }
332}
333
334impl RxRegisterAccess for CryptoDmaRxChannel<'_> {
335    fn peripheral_interrupt(&self) -> Option<Interrupt> {
336        // We don't know if the channel is used by AES or SHA, so interrupt handler
337        // setup is the responsibility of the peripheral driver.
338        None
339    }
340
341    fn async_handler(&self) -> Option<InterruptHandler> {
342        None
343    }
344}
345
346impl InterruptAccess<DmaRxInterrupt> for CryptoDmaRxChannel<'_> {
347    fn enable_listen(&self, interrupts: EnumSet<DmaRxInterrupt>, enable: bool) {
348        self.regs().int_ena().modify(|_, w| {
349            for interrupt in interrupts {
350                match interrupt {
351                    DmaRxInterrupt::SuccessfulEof => w.in_suc_eof().bit(enable),
352                    DmaRxInterrupt::ErrorEof => w.in_err_eof().bit(enable),
353                    DmaRxInterrupt::DescriptorError => w.in_dscr_err().bit(enable),
354                    DmaRxInterrupt::DescriptorEmpty => w.in_dscr_empty().bit(enable),
355                    DmaRxInterrupt::Done => w.in_done().bit(enable),
356                };
357            }
358            w
359        });
360    }
361
362    fn is_listening(&self) -> EnumSet<DmaRxInterrupt> {
363        let mut result = EnumSet::new();
364
365        let int_ena = self.regs().int_ena().read();
366        if int_ena.in_dscr_err().bit_is_set() {
367            result |= DmaRxInterrupt::DescriptorError;
368        }
369        if int_ena.in_dscr_err().bit_is_set() {
370            result |= DmaRxInterrupt::DescriptorEmpty;
371        }
372        if int_ena.in_suc_eof().bit_is_set() {
373            result |= DmaRxInterrupt::SuccessfulEof;
374        }
375        if int_ena.in_err_eof().bit_is_set() {
376            result |= DmaRxInterrupt::ErrorEof;
377        }
378        if int_ena.in_done().bit_is_set() {
379            result |= DmaRxInterrupt::Done;
380        }
381
382        result
383    }
384
385    fn clear(&self, interrupts: impl Into<EnumSet<DmaRxInterrupt>>) {
386        self.regs().int_clr().write(|w| {
387            for interrupt in interrupts.into() {
388                match interrupt {
389                    DmaRxInterrupt::SuccessfulEof => w.in_suc_eof().clear_bit_by_one(),
390                    DmaRxInterrupt::ErrorEof => w.in_err_eof().clear_bit_by_one(),
391                    DmaRxInterrupt::DescriptorError => w.in_dscr_err().clear_bit_by_one(),
392                    DmaRxInterrupt::DescriptorEmpty => w.in_dscr_empty().clear_bit_by_one(),
393                    DmaRxInterrupt::Done => w.in_done().clear_bit_by_one(),
394                };
395            }
396            w
397        });
398    }
399
400    fn pending_interrupts(&self) -> EnumSet<DmaRxInterrupt> {
401        let mut result = EnumSet::new();
402
403        let int_raw = self.regs().int_raw().read();
404        if int_raw.in_dscr_err().bit_is_set() {
405            result |= DmaRxInterrupt::DescriptorError;
406        }
407        if int_raw.in_dscr_empty().bit_is_set() {
408            result |= DmaRxInterrupt::DescriptorEmpty;
409        }
410        if int_raw.in_suc_eof().bit_is_set() {
411            result |= DmaRxInterrupt::SuccessfulEof;
412        }
413        if int_raw.in_err_eof().bit_is_set() {
414            result |= DmaRxInterrupt::ErrorEof;
415        }
416        if int_raw.in_done().bit_is_set() {
417            result |= DmaRxInterrupt::Done;
418        }
419
420        result
421    }
422
423    fn waker(&self) -> &'static AtomicWaker {
424        self.0.rx_waker()
425    }
426
427    fn is_async(&self) -> bool {
428        self.0.rx_async_flag().load(Ordering::Relaxed)
429    }
430
431    fn set_async(&self, _is_async: bool) {
432        self.0.rx_async_flag().store(_is_async, Ordering::Relaxed);
433    }
434}
435
436impl<'d> DmaChannel for DMA_CRYPTO<'d> {
437    type Rx = CryptoDmaRxChannel<'d>;
438    type Tx = CryptoDmaTxChannel<'d>;
439    unsafe fn split_internal(self, _: crate::private::Internal) -> (Self::Rx, Self::Tx) {
440        (
441            CryptoDmaRxChannel(unsafe { Self::steal() }),
442            CryptoDmaTxChannel(unsafe { Self::steal() }),
443        )
444    }
445}
446impl DmaChannelExt for DMA_CRYPTO<'_> {
447    fn rx_interrupts() -> impl InterruptAccess<DmaRxInterrupt> {
448        CryptoDmaRxChannel(unsafe { Self::steal() })
449    }
450    fn tx_interrupts() -> impl InterruptAccess<DmaTxInterrupt> {
451        CryptoDmaTxChannel(unsafe { Self::steal() })
452    }
453}
454impl PdmaChannel for DMA_CRYPTO<'_> {
455    type RegisterBlock = CryptoRegisterBlock;
456    fn register_block(&self) -> &Self::RegisterBlock {
457        DMA_CRYPTO::regs()
458    }
459    fn tx_waker(&self) -> &'static AtomicWaker {
460        static WAKER: AtomicWaker = AtomicWaker::new();
461        &WAKER
462    }
463    fn rx_waker(&self) -> &'static AtomicWaker {
464        static WAKER: AtomicWaker = AtomicWaker::new();
465        &WAKER
466    }
467    fn is_compatible_with(&self, peripheral: DmaPeripheral) -> bool {
468        let compatible_peripherals = [DmaPeripheral::Aes, DmaPeripheral::Sha];
469        compatible_peripherals.contains(&peripheral)
470    }
471    fn peripheral_interrupt(&self) -> Interrupt {
472        Interrupt::CRYPTO_DMA
473    }
474    fn async_handler(&self) -> InterruptHandler {
475        pub(crate) extern "C" fn __esp_hal_internal_interrupt_handler() {
476            asynch::handle_in_interrupt::<DMA_CRYPTO<'static>>();
477            asynch::handle_out_interrupt::<DMA_CRYPTO<'static>>();
478        }
479        #[allow(non_upper_case_globals)]
480        pub(crate) static interrupt_handler: InterruptHandler =
481            InterruptHandler::new(__esp_hal_internal_interrupt_handler, Priority::max());
482        interrupt_handler
483    }
484    fn rx_async_flag(&self) -> &'static AtomicBool {
485        static FLAG: AtomicBool = AtomicBool::new(false);
486        &FLAG
487    }
488    fn tx_async_flag(&self) -> &'static AtomicBool {
489        static FLAG: AtomicBool = AtomicBool::new(false);
490        &FLAG
491    }
492}
493impl<'d> DmaChannelConvert<CryptoDmaRxChannel<'d>> for DMA_CRYPTO<'d> {
494    fn degrade(self) -> CryptoDmaRxChannel<'d> {
495        CryptoDmaRxChannel(self)
496    }
497}
498impl<'d> DmaChannelConvert<CryptoDmaTxChannel<'d>> for DMA_CRYPTO<'d> {
499    fn degrade(self) -> CryptoDmaTxChannel<'d> {
500        CryptoDmaTxChannel(self)
501    }
502}