1use core::{marker::PhantomData, task::Poll};
13
14use bitbybit::{bitenum, bitfield};
15use cortex_m::interrupt::InterruptNumber;
16use embassy_hal_internal::{Peri, PeripheralType, interrupt::InterruptExt as _};
17use embassy_sync::waitqueue::AtomicWaker;
18
19use crate::{
20 NUM_INTERRUPTS,
21 event_link::{IcuInterrupt as _, InterruptEvent},
22 interrupt::{
23 self,
24 typelevel::{Handler as InterruptHandler, Interrupt as InterruptType},
25 },
26 module_stop::ModuleStop as _,
27 pac,
28};
29
30static mut DTC_VECTOR_TABLE: VectorTable = VectorTable::new();
33
34cfg_select! {
35 feature = "defmt" => {
36 #[allow(private_bounds)]
38 pub trait Word: SealedWord + defmt::Format {}
39 }
40 _ => {
41 #[allow(private_bounds)]
43 pub trait Word: SealedWord {}
44 }
45}
46
47trait SealedWord: Copy {
48 const WORD_SIZE: WordSize;
49}
50
51impl Word for u8 {}
53impl SealedWord for u8 {
54 const WORD_SIZE: WordSize = WordSize::Byte;
55}
56
57impl Word for u16 {}
59impl SealedWord for u16 {
60 const WORD_SIZE: WordSize = WordSize::HalfWord;
61}
62
63impl Word for u32 {}
65impl SealedWord for u32 {
66 const WORD_SIZE: WordSize = WordSize::Word;
67}
68
69pub struct DtcInterruptHandler<C: Instance> {
73 phantom: PhantomData<C>,
74}
75
76pub struct Channel<C: Instance> {
80 entry: DtcEntry,
81 phantom: PhantomData<C>,
82}
83
84#[bitenum(u2)]
86#[allow(dead_code)]
87#[cfg_attr(feature = "defmt", derive(defmt::Format))]
88enum AddressMode {
89 Fixed = 0b00,
91
92 Increment = 0b10,
94
95 Decrement = 0b11,
97}
98
99#[bitenum(u1, exhaustive = true)]
101#[allow(dead_code)]
102#[cfg_attr(feature = "defmt", derive(defmt::Format))]
103enum RepeatMode {
104 Destination = 0,
106
107 Source = 1,
109}
110
111#[bitenum(u1, exhaustive = true)]
116#[allow(dead_code)]
117#[cfg_attr(feature = "defmt", derive(defmt::Format))]
118enum InterruptMode {
119 OnCompletion = 0,
120 PerTransfer = 1,
121}
122
123#[bitenum(u2)]
125#[allow(dead_code)]
126#[cfg_attr(feature = "defmt", derive(defmt::Format))]
127enum ChainMode {
128 Disabled = 0b00,
129 Continuous = 0b01,
130 Penultimate = 0b11,
131}
132
133#[bitenum(u2)]
135#[allow(dead_code)]
136#[cfg_attr(feature = "defmt", derive(defmt::Format))]
137enum WordSize {
138 Byte = 0b00,
140
141 HalfWord = 0b01,
143
144 Word = 0b10,
146}
147
148#[bitenum(u2)]
150#[allow(dead_code)]
151#[cfg_attr(feature = "defmt", derive(defmt::Format))]
152enum TransferMode {
153 Normal = 0b00,
154 Repeat = 0b01,
155 Block = 0b10,
156}
157
158#[bitfield(u128, default = 0)]
159#[cfg_attr(feature = "defmt", derive(defmt::Format))]
160pub(crate) struct DtcEntry {
161 #[bits(0..=15)]
162 reserved: u16,
163
164 #[bits(16..=17)]
166 reserved: u2,
167 #[bits(18..=19, rw)]
169 dest_address_mode: Option<AddressMode>,
170 #[bit(20, rw)]
172 repeat_mode: RepeatMode,
173 #[bit(21, rw)]
175 interrupt_mode: InterruptMode,
176 #[bits(22..=23, rw)]
178 chain_mode: Option<ChainMode>,
179
180 #[bits(24..=25)]
182 reserved: u2,
183 #[bits(26..=27, rw)]
185 source_address_mode: Option<AddressMode>,
186 #[bits(28..=29, rw)]
188 word_size: Option<WordSize>,
189 #[bits(30..=31, rw)]
191 transfer_mode: Option<TransferMode>,
192
193 #[bits(32..=63, rw)]
195 source_address: u32,
196
197 #[bits(64..=95, rw)]
199 dest_address: u32,
200
201 #[bits(96..=111, rw)]
203 count_b: u16,
204
205 #[bits(112..=119, rw)]
207 count_a_low: u8,
208 #[bits(120..=127, rw)]
209 count_a_high: u8,
210}
211
212#[repr(C, align(1024))]
213#[cfg_attr(feature = "defmt", derive(defmt::Format))]
214struct VectorTable {
215 vectors: [u32; NUM_INTERRUPTS],
216}
217
218impl Default for VectorTable {
219 fn default() -> Self {
220 Self {
221 vectors: [0; NUM_INTERRUPTS],
222 }
223 }
224}
225
226#[allow(private_bounds)]
228pub trait Instance: SealedInstance {
229 type Int: interrupt::typelevel::Interrupt;
231}
232
233pub(crate) trait SealedInstance: PeripheralType {}
234
235impl VectorTable {
236 const fn new() -> Self {
237 Self {
238 vectors: [0; NUM_INTERRUPTS],
239 }
240 }
241}
242
243pub struct Transfer<'d, C: Instance> {
245 event: InterruptEvent,
246 phantom: PhantomData<&'d C>,
247}
248
249impl<'d, C: Instance> Transfer<'d, C> {
250 fn new(event: InterruptEvent) -> Self {
251 Self {
252 event,
253 phantom: PhantomData,
254 }
255 }
256
257 #[inline(always)]
258 pub fn start(&mut self) {
261 trace!("DTC{}: Enable for: {}", C::Int::IRQ.number(), self.event);
262 C::Int::IRQ.dtc_enable(self.event);
263 }
264
265 #[inline(always)]
268 pub fn stop(&mut self) {
269 C::Int::IRQ.icu_disable();
270 }
271}
272
273pub(crate) fn init() {
274 let dtc = pac::DTC;
275
276 crate::peripherals::DTC::start_module();
278
279 let vector_base = unsafe { core::ptr::addr_of!(DTC_VECTOR_TABLE.vectors) as u32 };
280
281 cfg_select! {
283 trust_zone => dtc.dtcvbr_sec().write_value(vector_base),
284 _ => dtc.dtcvbr().write_value(vector_base),
285 }
286
287 cfg_select! {
288 all(trust_zone_v2, secure) => {
289 dtc.dtccr_sec().modify(|r| r.set_rrs(false));
290 dtc.dtcst().modify(|r| r.set_dtcst(true));
291 },
292 _ => {
293 dtc.dtccr().modify(|r| r.set_rrs(false));
294 dtc.dtcst().modify(|r| r.set_dtcst(true));
295 }
296 }
297}
298
299impl<C: Instance> Channel<C> {
300 fn waker() -> &'static AtomicWaker {
301 static WAKER: AtomicWaker = AtomicWaker::new();
302 &WAKER
303 }
304
305 #[allow(private_bounds)]
307 pub fn new<'d>(
308 peri: Peri<'d, C>,
309 irqs: impl interrupt::typelevel::Binding<C::Int, DtcInterruptHandler<C>>,
310 ) -> Self {
311 let _ = peri;
312 let _ = irqs;
313
314 let this = Self {
315 entry: Default::default(),
316 phantom: PhantomData,
317 };
318
319 unsafe { C::Int::IRQ.enable() };
320 C::Int::IRQ.icu_disable();
321
322 this
323 }
324
325 pub unsafe fn copy_slice<'d, W: Word>(
333 &mut self,
334 source: &'d [W],
335 dest: &'d mut [W],
336 increment_on: InterruptEvent,
337 ) -> Transfer<'d, C> {
338 let len = source.len() as u8;
339 let transfer_entry = DtcEntry::builder()
340 .with_chain_mode(ChainMode::Disabled)
341 .with_source_address_mode(AddressMode::Increment)
342 .with_dest_address_mode(AddressMode::Increment)
343 .with_word_size(W::WORD_SIZE)
344 .with_transfer_mode(TransferMode::Block)
345 .with_repeat_mode(RepeatMode::Destination)
346 .with_interrupt_mode(InterruptMode::OnCompletion)
347 .with_source_address(source.as_ptr() as u32)
348 .with_dest_address(dest.as_ptr() as u32)
349 .with_count_b(1)
350 .with_count_a_low(len)
351 .with_count_a_high(len)
352 .build();
353 self.update_entry(transfer_entry);
354
355 let mut transfer = Transfer::new(increment_on);
356 transfer.start();
357
358 transfer
359 }
360
361 pub unsafe fn write<'d, W: Word>(
363 &mut self,
364 source: &'d [W],
365 dest: *mut W,
366 increment_on: InterruptEvent,
367 repeat: bool,
368 ) -> Transfer<'d, C> {
369 let (transfer_mode, low_count, high_count) = match repeat {
372 false => (TransferMode::Normal, source.len() as u8, 0),
373 true => (TransferMode::Repeat, source.len() as u8, source.len() as u8),
374 };
375
376 let transfer_entry = DtcEntry::builder()
377 .with_chain_mode(ChainMode::Disabled)
378 .with_source_address_mode(AddressMode::Increment)
379 .with_dest_address_mode(AddressMode::Fixed)
380 .with_word_size(W::WORD_SIZE)
381 .with_transfer_mode(transfer_mode)
382 .with_repeat_mode(RepeatMode::Source)
383 .with_interrupt_mode(InterruptMode::OnCompletion)
384 .with_source_address(source.as_ptr() as u32)
385 .with_dest_address(dest as u32)
386 .with_count_b(0)
387 .with_count_a_low(low_count)
388 .with_count_a_high(high_count)
389 .build();
390 self.update_entry(transfer_entry);
391
392 let mut transfer = Transfer::new(increment_on);
393 transfer.start();
394
395 transfer
396 }
397
398 pub(crate) fn prepare_write<'d, W: Word>(
399 &'d mut self,
400 source: &'d [W],
401 dest: *mut W,
402 last: bool,
403 ) -> DtcEntry {
404 let chain_mode = match last {
405 true => ChainMode::Disabled,
406 false => ChainMode::Penultimate,
407 };
408
409 DtcEntry::builder()
410 .with_chain_mode(chain_mode)
411 .with_source_address_mode(AddressMode::Increment)
412 .with_dest_address_mode(AddressMode::Fixed)
413 .with_word_size(W::WORD_SIZE)
414 .with_transfer_mode(TransferMode::Normal)
415 .with_repeat_mode(RepeatMode::Source)
416 .with_interrupt_mode(InterruptMode::OnCompletion)
417 .with_source_address(source.as_ptr() as u32)
418 .with_dest_address(dest as u32)
419 .with_count_b(0)
420 .with_count_a_low(source.len() as u8)
421 .with_count_a_high(0)
422 .build()
423 }
424
425 pub(crate) unsafe fn write_chain<'d>(
427 &mut self,
428 chain: &'d [DtcEntry],
429 increment_on: InterruptEvent,
430 ) -> Transfer<'d, C> {
431 unsafe { DTC_VECTOR_TABLE.vectors[C::Int::IRQ.number() as usize] = chain.as_ptr() as u32 };
432
433 let dtc = crate::pac::DTC;
435 dtc.dtccr().modify(|r| r.set_rrs(false));
436 dtc.dtccr().modify(|r| r.set_rrs(true));
437
438 let mut transfer = Transfer::new(increment_on);
439 transfer.start();
440
441 transfer
442 }
443
444 pub unsafe fn read<'d, W: Word>(
446 &mut self,
447 source: *const W,
448 dest: &'d mut [W],
449 increment_on: InterruptEvent,
450 repeat: bool,
451 ) -> Transfer<'d, C> {
452 let (transfer_mode, low_count, high_count) = match repeat {
455 false => (TransferMode::Normal, dest.len() as u8, 0),
456 true => (TransferMode::Repeat, dest.len() as u8, dest.len() as u8),
457 };
458
459 let transfer_entry = DtcEntry::builder()
460 .with_chain_mode(ChainMode::Disabled)
461 .with_source_address_mode(AddressMode::Fixed)
462 .with_dest_address_mode(AddressMode::Increment)
463 .with_word_size(W::WORD_SIZE)
464 .with_transfer_mode(transfer_mode)
465 .with_repeat_mode(RepeatMode::Destination)
466 .with_interrupt_mode(InterruptMode::OnCompletion)
467 .with_source_address(source as u32)
468 .with_dest_address(dest.as_ptr() as u32)
469 .with_count_b(0)
470 .with_count_a_low(low_count)
471 .with_count_a_high(high_count)
472 .build();
473 self.update_entry(transfer_entry);
474
475 let mut transfer = Transfer::new(increment_on);
476 transfer.start();
477
478 transfer
479 }
480
481 #[inline(always)]
482 fn update_entry(&mut self, entry: DtcEntry) {
483 self.entry = entry;
484 let entry_addr = &self.entry as *const _;
485 unsafe { DTC_VECTOR_TABLE.vectors[C::Int::IRQ.number() as usize] = entry_addr as u32 };
486
487 let dtc = crate::pac::DTC;
489 dtc.dtccr().modify(|r| r.set_rrs(false));
490 dtc.dtccr().modify(|r| r.set_rrs(true));
491 }
492}
493
494impl<'d, C: Instance> Drop for Transfer<'d, C> {
495 fn drop(&mut self) {
496 trace!(
497 "DTC{}: Dropping transfer status={}",
498 C::Int::IRQ.number(),
499 pac::DTC.dtcsts().read()
500 );
501 }
502}
503
504impl<C: Instance> Drop for Channel<C> {
505 fn drop(&mut self) {
506 trace!("DTC{}: Drop", C::Int::IRQ.number());
507 unsafe { DTC_VECTOR_TABLE.vectors[C::Int::IRQ.number() as usize] = 0 };
508 C::Int::IRQ.dtc_disable();
509 }
510}
511
512impl<C: Instance> InterruptHandler<C::Int> for DtcInterruptHandler<C> {
513 unsafe fn on_interrupt() {
514 C::Int::IRQ.icu_unpend();
515
516 Channel::<C>::waker().wake();
517 }
518}
519
520impl<'d, C: Instance> Future for Transfer<'d, C> {
522 type Output = Result<(), ()>;
523
524 fn poll(
525 self: core::pin::Pin<&mut Self>,
526 ctx: &mut core::task::Context<'_>,
527 ) -> Poll<Self::Output> {
528 Channel::<C>::waker().register(ctx.waker());
529
530 #[cfg(dtc_sec)]
531 {
532 let dtc = crate::pac::DTC;
533
534 let err = dtc.dtevr().read();
535 if err.dtesta() && u16::from(err.dtev()) == C::Int::IRQ.number() {
536 error!("DTC Error: {}", err);
537
538 let bus = pac::BUS;
539
540 return Poll::Ready(Err(()));
541 }
542 }
543
544 if !C::Int::IRQ.is_dtc() {
547 C::Int::IRQ.icu_disable();
548 return Poll::Ready(Ok(()));
549 }
550
551 Poll::Pending
552 }
553}
554
555macro_rules! dtc_link {
556 ($index:literal) => {
557 paste::paste! {
558 impl crate::dtc::Instance for crate::peripherals::[< DTC_CHAN $index >] {
559 type Int = interrupt::typelevel::[< IEL $index >];
560 }
561
562 impl crate::dtc::SealedInstance for crate::peripherals::[< DTC_CHAN $index >] {
563 }
564 }
565 };
566}
567pub(crate) use dtc_link;