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