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