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