1use core::marker::PhantomData;
12
13use crate::{
14 dma::*,
15 handler,
16 interrupt::Priority,
17 peripherals::{DMA, Interrupt, pac},
18};
19
20#[cfg_attr(dma_gdma_version = "1", path = "ahb_v1.rs")]
21#[cfg_attr(dma_gdma_version = "2", path = "ahb_v2.rs")]
22mod implementation;
23
24#[derive(Debug)]
26#[cfg_attr(feature = "defmt", derive(defmt::Format))]
27pub struct AnyGdmaChannel<'d> {
28 channel: u8,
29 _lifetime: PhantomData<&'d mut ()>,
30}
31
32impl AnyGdmaChannel<'_> {
33 #[cfg_attr(any(esp32c2, esp32c61), expect(unused))]
34 pub(crate) unsafe fn clone_unchecked(&self) -> Self {
35 Self {
36 channel: self.channel,
37 _lifetime: PhantomData,
38 }
39 }
40}
41
42impl crate::private::Sealed for AnyGdmaChannel<'_> {}
43impl<'d> DmaChannel for AnyGdmaChannel<'d> {
44 type Rx = AnyGdmaRxChannel<'d>;
45 type Tx = AnyGdmaTxChannel<'d>;
46
47 unsafe fn split_internal(self, _: crate::private::Internal) -> (Self::Rx, Self::Tx) {
48 (
49 AnyGdmaRxChannel {
50 channel: self.channel,
51 _lifetime: PhantomData,
52 },
53 AnyGdmaTxChannel {
54 channel: self.channel,
55 _lifetime: PhantomData,
56 },
57 )
58 }
59}
60
61#[derive(Debug)]
63#[cfg_attr(feature = "defmt", derive(defmt::Format))]
64pub struct AnyGdmaRxChannel<'d> {
65 channel: u8,
66 _lifetime: PhantomData<&'d mut ()>,
67}
68
69impl<'d> DmaChannelConvert<AnyGdmaRxChannel<'d>> for AnyGdmaRxChannel<'d> {
70 fn degrade(self) -> AnyGdmaRxChannel<'d> {
71 self
72 }
73}
74
75#[derive(Debug)]
77#[cfg_attr(feature = "defmt", derive(defmt::Format))]
78pub struct AnyGdmaTxChannel<'d> {
79 channel: u8,
80 _lifetime: PhantomData<&'d mut ()>,
81}
82
83impl<'d> DmaChannelConvert<AnyGdmaTxChannel<'d>> for AnyGdmaTxChannel<'d> {
84 fn degrade(self) -> AnyGdmaTxChannel<'d> {
85 self
86 }
87}
88
89use crate::asynch::AtomicWaker;
90
91static TX_WAKERS: [AtomicWaker; CHANNEL_COUNT] = [const { AtomicWaker::new() }; CHANNEL_COUNT];
92static RX_WAKERS: [AtomicWaker; CHANNEL_COUNT] = [const { AtomicWaker::new() }; CHANNEL_COUNT];
93
94cfg_if::cfg_if! {
95 if #[cfg(any(esp32c2, esp32c3))] {
96 use portable_atomic::AtomicBool;
97 static TX_IS_ASYNC: [AtomicBool; CHANNEL_COUNT] = [const { AtomicBool::new(false) }; CHANNEL_COUNT];
98 static RX_IS_ASYNC: [AtomicBool; CHANNEL_COUNT] = [const { AtomicBool::new(false) }; CHANNEL_COUNT];
99 }
100}
101
102impl crate::private::Sealed for AnyGdmaTxChannel<'_> {}
103impl DmaTxChannel for AnyGdmaTxChannel<'_> {}
104
105impl crate::private::Sealed for AnyGdmaRxChannel<'_> {}
106impl DmaRxChannel for AnyGdmaRxChannel<'_> {}
107
108impl<CH: DmaChannel, Dm: DriverMode> Channel<Dm, CH> {
109 pub fn runtime_ensure_compatible<P: DmaEligible>(&self, _peripheral: &P) {
111 }
113}
114
115macro_rules! impl_channel {
116 ($num:literal, $interrupt_in:ident $(, $interrupt_out:ident)? ) => {
117 paste::paste! {
118 use $crate::peripherals::[<DMA_CH $num>];
119 impl [<DMA_CH $num>]<'_> {
120 fn handler_in() -> Option<InterruptHandler> {
121 $crate::if_set! {
122 $({
123 #[handler(priority = Priority::max())]
125 fn interrupt_handler_in() {
126 $crate::ignore!($interrupt_out);
127 super::asynch::handle_in_interrupt::<[< DMA_CH $num >]<'static>>();
128 }
129 Some(interrupt_handler_in)
130 })?,
131 {
132 #[handler(priority = Priority::max())]
133 fn interrupt_handler() {
134 super::asynch::handle_in_interrupt::<[< DMA_CH $num >]<'static>>();
135 super::asynch::handle_out_interrupt::<[< DMA_CH $num >]<'static>>();
136 }
137 Some(interrupt_handler)
138 }
139 }
140 }
141
142 fn isr_in() -> Option<Interrupt> {
143 Some(Interrupt::$interrupt_in)
144 }
145
146 fn handler_out() -> Option<InterruptHandler> {
147 $crate::if_set! {
148 $({
149 #[handler(priority = Priority::max())]
150 fn interrupt_handler_out() {
151 $crate::ignore!($interrupt_out);
152 super::asynch::handle_out_interrupt::<[< DMA_CH $num >]<'static>>();
153 }
154 Some(interrupt_handler_out)
155 })?,
156 None
157 }
158 }
159
160 fn isr_out() -> Option<Interrupt> {
161 $crate::if_set! { $(Some(Interrupt::$interrupt_out))?, None }
162 }
163 }
164
165 impl<'d> DmaChannel for [<DMA_CH $num>]<'d> {
166 type Rx = AnyGdmaRxChannel<'d>;
167 type Tx = AnyGdmaTxChannel<'d>;
168
169 unsafe fn split_internal(self, _: $crate::private::Internal) -> (Self::Rx, Self::Tx) {
170 (
171 AnyGdmaRxChannel {
172 channel: $num,
173 _lifetime: core::marker::PhantomData,
174 },
175 AnyGdmaTxChannel {
176 channel: $num,
177 _lifetime: core::marker::PhantomData,
178 },
179 )
180 }
181 }
182
183 impl<'d> DmaChannelConvert<AnyGdmaChannel<'d>> for [<DMA_CH $num>]<'d> {
184 fn degrade(self) -> AnyGdmaChannel<'d> {
185 AnyGdmaChannel {
186 channel: $num,
187 _lifetime: core::marker::PhantomData,
188 }
189 }
190 }
191
192 impl<'d> DmaChannelConvert<AnyGdmaRxChannel<'d>> for [<DMA_CH $num>]<'d> {
193 fn degrade(self) -> AnyGdmaRxChannel<'d> {
194 AnyGdmaRxChannel {
195 channel: $num,
196 _lifetime: core::marker::PhantomData,
197 }
198 }
199 }
200
201 impl<'d> DmaChannelConvert<AnyGdmaTxChannel<'d>> for [<DMA_CH $num>]<'d> {
202 fn degrade(self) -> AnyGdmaTxChannel<'d> {
203 AnyGdmaTxChannel {
204 channel: $num,
205 _lifetime: core::marker::PhantomData,
206 }
207 }
208 }
209
210 impl DmaChannelExt for [<DMA_CH $num>]<'_> {
211 fn rx_interrupts() -> impl InterruptAccess<DmaRxInterrupt> {
212 AnyGdmaRxChannel {
213 channel: $num,
214 _lifetime: core::marker::PhantomData,
215 }
216 }
217
218 fn tx_interrupts() -> impl InterruptAccess<DmaTxInterrupt> {
219 AnyGdmaTxChannel {
220 channel: $num,
221 _lifetime: core::marker::PhantomData,
222 }
223 }
224 }
225 }
226 };
227}
228
229const CHANNEL_COUNT: usize = cfg!(soc_has_dma_ch0) as usize
230 + cfg!(soc_has_dma_ch1) as usize
231 + cfg!(soc_has_dma_ch2) as usize
232 + cfg!(soc_has_dma_ch3) as usize
233 + cfg!(soc_has_dma_ch4) as usize;
234
235cfg_if::cfg_if! {
236 if #[cfg(dma_separate_in_out_interrupts)] {
237 #[cfg(soc_has_dma_ch0)]
238 impl_channel!(0, DMA_IN_CH0, DMA_OUT_CH0);
239 #[cfg(soc_has_dma_ch1)]
240 impl_channel!(1, DMA_IN_CH1, DMA_OUT_CH1);
241 #[cfg(soc_has_dma_ch2)]
242 impl_channel!(2, DMA_IN_CH2, DMA_OUT_CH2);
243 #[cfg(soc_has_dma_ch3)]
244 impl_channel!(3, DMA_IN_CH3, DMA_OUT_CH3);
245 #[cfg(soc_has_dma_ch4)]
246 impl_channel!(4, DMA_IN_CH4, DMA_OUT_CH4);
247 } else {
248 #[cfg(soc_has_dma_ch0)]
249 impl_channel!(0, DMA_CH0);
250 #[cfg(soc_has_dma_ch1)]
251 impl_channel!(1, DMA_CH1);
252 #[cfg(soc_has_dma_ch2)]
253 impl_channel!(2, DMA_CH2);
254 #[cfg(soc_has_dma_ch3)]
255 impl_channel!(3, DMA_CH3);
256 #[cfg(soc_has_dma_ch4)]
257 impl_channel!(4, DMA_CH4);
258 }
259}
260
261for_each_peripheral! {
262 (dma_eligible $(( $peri:ident, $name:ident, $id:literal )),*) => {
263 crate::dma::impl_dma_eligible! {
264 AnyGdmaChannel {
265 $($peri => $name,)*
266 }
267 }
268 };
269}
270
271pub(super) fn init_dma_racey() {
272 DMA::regs()
273 .misc_conf()
274 .modify(|_, w| w.ahbm_rst_inter().set_bit());
275 DMA::regs()
276 .misc_conf()
277 .modify(|_, w| w.ahbm_rst_inter().clear_bit());
278 DMA::regs().misc_conf().modify(|_, w| w.clk_en().set_bit());
279
280 implementation::setup();
281}