Skip to main content

esp_hal/dma/pdma/
crypto.rs

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_CRYPTO, Interrupt},
27    system::Peripheral,
28};
29
30pub(super) type CryptoRegisterBlock = crate::pac::crypto_dma::RegisterBlock;
31
32/// The RX half of a Crypto DMA channel.
33#[derive(Debug)]
34#[cfg_attr(feature = "defmt", derive(defmt::Format))]
35pub struct CryptoDmaRxChannel<'d>(pub(crate) DMA_CRYPTO<'d>);
36
37impl CryptoDmaRxChannel<'_> {
38    fn regs(&self) -> &CryptoRegisterBlock {
39        self.0.register_block()
40    }
41}
42
43impl crate::private::Sealed for CryptoDmaRxChannel<'_> {}
44impl DmaRxChannel for CryptoDmaRxChannel<'_> {}
45
46/// The TX half of a Crypto DMA channel.
47#[derive(Debug)]
48#[cfg_attr(feature = "defmt", derive(defmt::Format))]
49pub struct CryptoDmaTxChannel<'d>(pub(crate) DMA_CRYPTO<'d>);
50
51impl CryptoDmaTxChannel<'_> {
52    fn regs(&self) -> &CryptoRegisterBlock {
53        self.0.register_block()
54    }
55}
56
57impl crate::private::Sealed for CryptoDmaTxChannel<'_> {}
58impl DmaTxChannel for CryptoDmaTxChannel<'_> {}
59
60impl RegisterAccess for CryptoDmaTxChannel<'_> {
61    fn peripheral_clock(&self) -> Option<Peripheral> {
62        Some(Peripheral::CryptoDma)
63    }
64
65    fn reset(&self) {
66        self.regs().conf().toggle(|w, bit| {
67            w.out_rst().bit(bit);
68            w.ahbm_rst().bit(bit);
69            w.ahbm_fifo_rst().bit(bit)
70        });
71    }
72
73    fn set_burst_mode(&self, burst_mode: BurstConfig) {
74        self.regs()
75            .conf()
76            .modify(|_, w| w.out_data_burst_en().bit(burst_mode.is_burst_enabled()));
77    }
78
79    fn set_descr_burst_mode(&self, burst_mode: bool) {
80        self.regs()
81            .conf()
82            .modify(|_, w| w.outdscr_burst_en().bit(burst_mode));
83    }
84
85    fn set_peripheral(&self, peripheral: u8) {
86        use esp32s2::crypto_dma::aes_sha_select::SELECT;
87        let peripheral = match peripheral {
88            p if p == DmaPeripheral::Aes as u8 => SELECT::Aes,
89            p if p == DmaPeripheral::Sha as u8 => SELECT::Sha,
90            _ => unreachable!(),
91        };
92        self.regs()
93            .aes_sha_select()
94            .modify(|_, w| w.select().variant(peripheral));
95    }
96
97    fn set_link_addr(&self, address: u32) {
98        self.regs()
99            .out_link()
100            .modify(|_, w| unsafe { w.outlink_addr().bits(address) });
101    }
102
103    fn start(&self) {
104        self.regs()
105            .out_link()
106            .modify(|_, w| w.outlink_start().set_bit());
107    }
108
109    fn stop(&self) {
110        self.regs()
111            .out_link()
112            .modify(|_, w| w.outlink_stop().set_bit());
113    }
114
115    fn restart(&self) {
116        self.regs()
117            .out_link()
118            .modify(|_, w| w.outlink_restart().set_bit());
119    }
120
121    fn set_check_owner(&self, check_owner: Option<bool>) {
122        if check_owner == Some(true) {
123            panic!("Crypto DMA does not support checking descriptor ownership");
124        }
125    }
126
127    fn is_compatible_with(&self, peripheral: DmaPeripheral) -> bool {
128        self.0.is_compatible_with(peripheral)
129    }
130
131    #[cfg(dma_ext_mem_configurable_block_size)]
132    fn set_ext_mem_block_size(&self, size: DmaExtMemBKSize) {
133        self.regs()
134            .conf1()
135            .modify(|_, w| unsafe { w.ext_mem_bk_size().bits(size as u8) });
136    }
137
138    #[cfg(dma_can_access_psram)]
139    fn can_access_psram(&self) -> bool {
140        true
141    }
142}
143
144impl TxRegisterAccess for CryptoDmaTxChannel<'_> {
145    fn is_fifo_empty(&self) -> bool {
146        self.regs().state1().read().outfifo_cnt_debug().bits() == 0
147    }
148
149    fn set_auto_write_back(&self, enable: bool) {
150        self.regs()
151            .conf()
152            .modify(|_, w| w.out_auto_wrback().bit(enable));
153    }
154
155    fn last_dscr_address(&self) -> usize {
156        self.regs()
157            .out_eof_des_addr()
158            .read()
159            .out_eof_des_addr()
160            .bits() as usize
161    }
162
163    fn peripheral_interrupt(&self) -> Option<Interrupt> {
164        None
165    }
166
167    fn async_handler(&self) -> Option<InterruptHandler> {
168        None
169    }
170}
171
172impl InterruptAccess<DmaTxInterrupt> for CryptoDmaTxChannel<'_> {
173    fn enable_listen(&self, interrupts: EnumSet<DmaTxInterrupt>, enable: bool) {
174        self.regs().int_ena().modify(|_, w| {
175            for interrupt in interrupts {
176                match interrupt {
177                    DmaTxInterrupt::TotalEof => w.out_total_eof().bit(enable),
178                    DmaTxInterrupt::DescriptorError => w.out_dscr_err().bit(enable),
179                    DmaTxInterrupt::Eof => w.out_eof().bit(enable),
180                    DmaTxInterrupt::Done => w.out_done().bit(enable),
181                };
182            }
183            w
184        });
185    }
186
187    fn is_listening(&self) -> EnumSet<DmaTxInterrupt> {
188        let mut result = EnumSet::new();
189
190        let int_ena = self.regs().int_ena().read();
191        if int_ena.out_total_eof().bit_is_set() {
192            result |= DmaTxInterrupt::TotalEof;
193        }
194        if int_ena.out_dscr_err().bit_is_set() {
195            result |= DmaTxInterrupt::DescriptorError;
196        }
197        if int_ena.out_eof().bit_is_set() {
198            result |= DmaTxInterrupt::Eof;
199        }
200        if int_ena.out_done().bit_is_set() {
201            result |= DmaTxInterrupt::Done;
202        }
203
204        result
205    }
206
207    fn clear(&self, interrupts: impl Into<EnumSet<DmaTxInterrupt>>) {
208        self.regs().int_clr().write(|w| {
209            for interrupt in interrupts.into() {
210                match interrupt {
211                    DmaTxInterrupt::TotalEof => w.out_total_eof().clear_bit_by_one(),
212                    DmaTxInterrupt::DescriptorError => w.out_dscr_err().clear_bit_by_one(),
213                    DmaTxInterrupt::Eof => w.out_eof().clear_bit_by_one(),
214                    DmaTxInterrupt::Done => w.out_done().clear_bit_by_one(),
215                };
216            }
217            w
218        });
219    }
220
221    fn pending_interrupts(&self) -> EnumSet<DmaTxInterrupt> {
222        let mut result = EnumSet::new();
223
224        let int_raw = self.regs().int_raw().read();
225        if int_raw.out_total_eof().bit_is_set() {
226            result |= DmaTxInterrupt::TotalEof;
227        }
228        if int_raw.out_dscr_err().bit_is_set() {
229            result |= DmaTxInterrupt::DescriptorError;
230        }
231        if int_raw.out_eof().bit_is_set() {
232            result |= DmaTxInterrupt::Eof;
233        }
234        if int_raw.out_done().bit_is_set() {
235            result |= DmaTxInterrupt::Done;
236        }
237
238        result
239    }
240
241    fn waker(&self) -> &'static AtomicWaker {
242        self.0.tx_waker()
243    }
244
245    fn is_async(&self) -> bool {
246        self.0.tx_async_flag().load(Ordering::Acquire)
247    }
248
249    fn set_async(&self, is_async: bool) {
250        self.0.tx_async_flag().store(is_async, Ordering::Release);
251    }
252}
253
254impl RegisterAccess for CryptoDmaRxChannel<'_> {
255    fn peripheral_clock(&self) -> Option<Peripheral> {
256        Some(Peripheral::CryptoDma)
257    }
258
259    fn reset(&self) {
260        self.regs().conf().toggle(|w, bit| {
261            w.in_rst().bit(bit);
262            w.ahbm_rst().bit(bit);
263            w.ahbm_fifo_rst().bit(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(dma_ext_mem_configurable_block_size)]
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(dma_can_access_psram)]
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        pub(crate) static INTERRUPT_HANDLER: InterruptHandler =
480            InterruptHandler::new(__esp_hal_internal_interrupt_handler, Priority::max());
481        INTERRUPT_HANDLER
482    }
483    fn rx_async_flag(&self) -> &'static AtomicBool {
484        static FLAG: AtomicBool = AtomicBool::new(false);
485        &FLAG
486    }
487    fn tx_async_flag(&self) -> &'static AtomicBool {
488        static FLAG: AtomicBool = AtomicBool::new(false);
489        &FLAG
490    }
491}
492impl<'d> DmaChannelConvert<CryptoDmaRxChannel<'d>> for DMA_CRYPTO<'d> {
493    fn degrade(self) -> CryptoDmaRxChannel<'d> {
494        CryptoDmaRxChannel(self)
495    }
496}
497impl<'d> DmaChannelConvert<CryptoDmaTxChannel<'d>> for DMA_CRYPTO<'d> {
498    fn degrade(self) -> CryptoDmaTxChannel<'d> {
499        CryptoDmaTxChannel(self)
500    }
501}