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#[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#[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 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}