aboutsummaryrefslogtreecommitdiff
path: root/embassy-imxrt/src/dma.rs
diff options
context:
space:
mode:
Diffstat (limited to 'embassy-imxrt/src/dma.rs')
-rw-r--r--embassy-imxrt/src/dma.rs418
1 files changed, 418 insertions, 0 deletions
diff --git a/embassy-imxrt/src/dma.rs b/embassy-imxrt/src/dma.rs
new file mode 100644
index 000000000..e141447f3
--- /dev/null
+++ b/embassy-imxrt/src/dma.rs
@@ -0,0 +1,418 @@
1//! DMA driver.
2
3use core::future::Future;
4use core::pin::Pin;
5use core::sync::atomic::{compiler_fence, Ordering};
6use core::task::{Context, Poll};
7
8use embassy_hal_internal::{impl_peripheral, Peri, PeripheralType};
9use embassy_sync::waitqueue::AtomicWaker;
10use pac::dma0::channel::cfg::Periphreqen;
11use pac::dma0::channel::xfercfg::{Dstinc, Srcinc, Width};
12
13use crate::clocks::enable_and_reset;
14use crate::interrupt::InterruptExt;
15use crate::peripherals::DMA0;
16use crate::sealed::Sealed;
17use crate::{interrupt, pac, peripherals, BitIter};
18
19#[cfg(feature = "rt")]
20#[interrupt]
21fn DMA0() {
22 let reg = unsafe { crate::pac::Dma0::steal() };
23
24 if reg.intstat().read().activeerrint().bit() {
25 let err = reg.errint0().read().bits();
26
27 for channel in BitIter(err) {
28 error!("DMA error interrupt on channel {}!", channel);
29 reg.errint0().write(|w| unsafe { w.err().bits(1 << channel) });
30 CHANNEL_WAKERS[channel as usize].wake();
31 }
32 }
33
34 if reg.intstat().read().activeint().bit() {
35 let ia = reg.inta0().read().bits();
36
37 for channel in BitIter(ia) {
38 reg.inta0().write(|w| unsafe { w.ia().bits(1 << channel) });
39 CHANNEL_WAKERS[channel as usize].wake();
40 }
41 }
42}
43
44/// Initialize DMA controllers (DMA0 only, for now)
45pub(crate) unsafe fn init() {
46 let sysctl0 = crate::pac::Sysctl0::steal();
47 let dmactl0 = crate::pac::Dma0::steal();
48
49 enable_and_reset::<DMA0>();
50
51 interrupt::DMA0.disable();
52 interrupt::DMA0.set_priority(interrupt::Priority::P3);
53
54 dmactl0.ctrl().modify(|_, w| w.enable().set_bit());
55
56 // Set channel descriptor SRAM base address
57 // Descriptor base must be 1K aligned
58 let descriptor_base = core::ptr::addr_of!(DESCRIPTORS.descs) as u32;
59 dmactl0.srambase().write(|w| w.bits(descriptor_base));
60
61 // Ensure AHB priority it highest (M4 == DMAC0)
62 sysctl0.ahbmatrixprior().modify(|_, w| w.m4().bits(0));
63
64 interrupt::DMA0.unpend();
65 interrupt::DMA0.enable();
66}
67
68/// DMA read.
69///
70/// SAFETY: Slice must point to a valid location reachable by DMA.
71pub unsafe fn read<'a, C: Channel, W: Word>(ch: Peri<'a, C>, from: *const W, to: *mut [W]) -> Transfer<'a, C> {
72 let count = ((to.len() / W::size() as usize) - 1) as isize;
73
74 copy_inner(
75 ch,
76 from as *const u32,
77 (to as *mut u32).byte_offset(count * W::size()),
78 W::width(),
79 count,
80 false,
81 true,
82 true,
83 )
84}
85
86/// DMA write.
87///
88/// SAFETY: Slice must point to a valid location reachable by DMA.
89pub unsafe fn write<'a, C: Channel, W: Word>(ch: Peri<'a, C>, from: *const [W], to: *mut W) -> Transfer<'a, C> {
90 let count = ((from.len() / W::size() as usize) - 1) as isize;
91
92 copy_inner(
93 ch,
94 (from as *const u32).byte_offset(count * W::size()),
95 to as *mut u32,
96 W::width(),
97 count,
98 true,
99 false,
100 true,
101 )
102}
103
104/// DMA copy between slices.
105///
106/// SAFETY: Slices must point to locations reachable by DMA.
107pub unsafe fn copy<'a, C: Channel, W: Word>(ch: Peri<'a, C>, from: &[W], to: &mut [W]) -> Transfer<'a, C> {
108 let from_len = from.len();
109 let to_len = to.len();
110 assert_eq!(from_len, to_len);
111
112 let count = ((from_len / W::size() as usize) - 1) as isize;
113
114 copy_inner(
115 ch,
116 from.as_ptr().byte_offset(count * W::size()) as *const u32,
117 to.as_mut_ptr().byte_offset(count * W::size()) as *mut u32,
118 W::width(),
119 count,
120 true,
121 true,
122 false,
123 )
124}
125
126fn copy_inner<'a, C: Channel>(
127 ch: Peri<'a, C>,
128 from: *const u32,
129 to: *mut u32,
130 width: Width,
131 count: isize,
132 incr_read: bool,
133 incr_write: bool,
134 periph: bool,
135) -> Transfer<'a, C> {
136 let p = ch.regs();
137
138 unsafe {
139 DESCRIPTORS.descs[ch.number() as usize].src = from as u32;
140 DESCRIPTORS.descs[ch.number() as usize].dest = to as u32;
141 }
142
143 compiler_fence(Ordering::SeqCst);
144
145 p.errint0().write(|w| unsafe { w.err().bits(1 << ch.number()) });
146 p.inta0().write(|w| unsafe { w.ia().bits(1 << ch.number()) });
147
148 p.channel(ch.number().into()).cfg().write(|w| {
149 unsafe { w.chpriority().bits(0) }
150 .periphreqen()
151 .variant(match periph {
152 false => Periphreqen::Disabled,
153 true => Periphreqen::Enabled,
154 })
155 .hwtrigen()
156 .clear_bit()
157 });
158
159 p.intenset0().write(|w| unsafe { w.inten().bits(1 << ch.number()) });
160
161 p.channel(ch.number().into()).xfercfg().write(|w| {
162 unsafe { w.xfercount().bits(count as u16) }
163 .cfgvalid()
164 .set_bit()
165 .clrtrig()
166 .set_bit()
167 .reload()
168 .clear_bit()
169 .setinta()
170 .set_bit()
171 .width()
172 .variant(width)
173 .srcinc()
174 .variant(match incr_read {
175 false => Srcinc::NoIncrement,
176 true => Srcinc::WidthX1,
177 // REVISIT: what about WidthX2 and WidthX4?
178 })
179 .dstinc()
180 .variant(match incr_write {
181 false => Dstinc::NoIncrement,
182 true => Dstinc::WidthX1,
183 // REVISIT: what about WidthX2 and WidthX4?
184 })
185 });
186
187 p.enableset0().write(|w| unsafe { w.ena().bits(1 << ch.number()) });
188
189 p.channel(ch.number().into())
190 .xfercfg()
191 .modify(|_, w| w.swtrig().set_bit());
192
193 compiler_fence(Ordering::SeqCst);
194
195 Transfer::new(ch)
196}
197
198/// DMA transfer driver.
199#[must_use = "futures do nothing unless you `.await` or poll them"]
200pub struct Transfer<'a, C: Channel> {
201 channel: Peri<'a, C>,
202}
203
204impl<'a, C: Channel> Transfer<'a, C> {
205 pub(crate) fn new(channel: Peri<'a, C>) -> Self {
206 Self { channel }
207 }
208
209 pub(crate) fn abort(&mut self) -> usize {
210 let p = self.channel.regs();
211
212 p.abort0().write(|w| w.channel(self.channel.number()).set_bit());
213 while p.busy0().read().bsy().bits() & (1 << self.channel.number()) != 0 {}
214
215 p.enableclr0()
216 .write(|w| unsafe { w.clr().bits(1 << self.channel.number()) });
217
218 let width: u8 = p
219 .channel(self.channel.number().into())
220 .xfercfg()
221 .read()
222 .width()
223 .variant()
224 .unwrap()
225 .into();
226
227 let count = p
228 .channel(self.channel.number().into())
229 .xfercfg()
230 .read()
231 .xfercount()
232 .bits()
233 + 1;
234
235 usize::from(count) * usize::from(width)
236 }
237}
238
239impl<'a, C: Channel> Drop for Transfer<'a, C> {
240 fn drop(&mut self) {
241 self.abort();
242 }
243}
244
245impl<'a, C: Channel> Unpin for Transfer<'a, C> {}
246impl<'a, C: Channel> Future for Transfer<'a, C> {
247 type Output = ();
248
249 fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
250 // Re-register the waker on each call to poll() because any calls to
251 // wake will deregister the waker.
252 CHANNEL_WAKERS[self.channel.number() as usize].register(cx.waker());
253
254 if self.channel.regs().active0().read().act().bits() & (1 << self.channel.number()) == 0 {
255 Poll::Ready(())
256 } else {
257 Poll::Pending
258 }
259 }
260}
261
262/// DMA channel descriptor
263#[derive(Copy, Clone)]
264#[repr(C)]
265struct Descriptor {
266 reserved: u32,
267 src: u32,
268 dest: u32,
269 link: u32,
270}
271
272impl Descriptor {
273 const fn new() -> Self {
274 Self {
275 reserved: 0,
276 src: 0,
277 dest: 0,
278 link: 0,
279 }
280 }
281}
282
283#[repr(align(1024))]
284struct Descriptors {
285 descs: [Descriptor; CHANNEL_COUNT],
286}
287
288impl Descriptors {
289 const fn new() -> Self {
290 Self {
291 descs: [const { Descriptor::new() }; CHANNEL_COUNT],
292 }
293 }
294}
295
296static mut DESCRIPTORS: Descriptors = Descriptors::new();
297static CHANNEL_WAKERS: [AtomicWaker; CHANNEL_COUNT] = [const { AtomicWaker::new() }; CHANNEL_COUNT];
298pub(crate) const CHANNEL_COUNT: usize = 33;
299
300/// DMA channel interface.
301#[allow(private_bounds)]
302pub trait Channel: PeripheralType + Sealed + Into<AnyChannel> + Sized + 'static {
303 /// Channel number.
304 fn number(&self) -> u8;
305
306 /// Channel registry block.
307 fn regs(&self) -> &'static pac::dma0::RegisterBlock {
308 unsafe { &*crate::pac::Dma0::ptr() }
309 }
310}
311
312/// DMA word.
313#[allow(private_bounds)]
314pub trait Word: Sealed {
315 /// Transfer width.
316 fn width() -> Width;
317
318 /// Size in bytes for the width.
319 fn size() -> isize;
320}
321
322impl Sealed for u8 {}
323impl Word for u8 {
324 fn width() -> Width {
325 Width::Bit8
326 }
327
328 fn size() -> isize {
329 1
330 }
331}
332
333impl Sealed for u16 {}
334impl Word for u16 {
335 fn width() -> Width {
336 Width::Bit16
337 }
338
339 fn size() -> isize {
340 2
341 }
342}
343
344impl Sealed for u32 {}
345impl Word for u32 {
346 fn width() -> Width {
347 Width::Bit32
348 }
349
350 fn size() -> isize {
351 4
352 }
353}
354
355/// Type erased DMA channel.
356pub struct AnyChannel {
357 number: u8,
358}
359
360impl_peripheral!(AnyChannel);
361
362impl Sealed for AnyChannel {}
363impl Channel for AnyChannel {
364 fn number(&self) -> u8 {
365 self.number
366 }
367}
368
369macro_rules! channel {
370 ($name:ident, $num:expr) => {
371 impl Sealed for peripherals::$name {}
372 impl Channel for peripherals::$name {
373 fn number(&self) -> u8 {
374 $num
375 }
376 }
377
378 impl From<peripherals::$name> for crate::dma::AnyChannel {
379 fn from(val: peripherals::$name) -> Self {
380 Self { number: val.number() }
381 }
382 }
383 };
384}
385
386channel!(DMA0_CH0, 0);
387channel!(DMA0_CH1, 1);
388channel!(DMA0_CH2, 2);
389channel!(DMA0_CH3, 3);
390channel!(DMA0_CH4, 4);
391channel!(DMA0_CH5, 5);
392channel!(DMA0_CH6, 6);
393channel!(DMA0_CH7, 7);
394channel!(DMA0_CH8, 8);
395channel!(DMA0_CH9, 9);
396channel!(DMA0_CH10, 10);
397channel!(DMA0_CH11, 11);
398channel!(DMA0_CH12, 12);
399channel!(DMA0_CH13, 13);
400channel!(DMA0_CH14, 14);
401channel!(DMA0_CH15, 15);
402channel!(DMA0_CH16, 16);
403channel!(DMA0_CH17, 17);
404channel!(DMA0_CH18, 18);
405channel!(DMA0_CH19, 19);
406channel!(DMA0_CH20, 20);
407channel!(DMA0_CH21, 21);
408channel!(DMA0_CH22, 22);
409channel!(DMA0_CH23, 23);
410channel!(DMA0_CH24, 24);
411channel!(DMA0_CH25, 25);
412channel!(DMA0_CH26, 26);
413channel!(DMA0_CH27, 27);
414channel!(DMA0_CH28, 28);
415channel!(DMA0_CH29, 29);
416channel!(DMA0_CH30, 30);
417channel!(DMA0_CH31, 31);
418channel!(DMA0_CH32, 32);