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