1
use super::*;
2

            
3
/// DMA transmit buffer
4
///
5
/// This is a contiguous buffer linked together by DMA descriptors of length
6
/// 4095 at most. It can only be used for transmitting data to a peripheral's
7
/// FIFO. See [ScopedDmaRxBuf] for receiving data.
8
#[derive(Debug)]
9
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
10
pub(crate) struct ScopedDmaTxBuf<'a> {
11
    descriptors: DescriptorSet<'a>,
12
    buffer: DmaAlignedMut<'a, [u8]>,
13
    burst: BurstConfig,
14
}
15

            
16
impl<'a> ScopedDmaTxBuf<'a> {
17
    /// Creates a new [ScopedDmaTxBuf] from some descriptors and a buffer.
18
    pub fn new(
19
        descriptors: DmaAlignedMut<'a, [DmaDescriptor]>,
20
        buffer: DmaAlignedMut<'a, [u8]>,
21
    ) -> Result<Self, DmaBufError> {
22
        Self::new_with_config(descriptors, buffer, BurstConfig::default())
23
    }
24

            
25
    /// Creates a new [ScopedDmaTxBuf] with a caller-chosen minimum alignment.
26
    ///
27
    /// There must be enough descriptors for the provided buffer.
28
    /// Depending on alignment requirements, each descriptor can handle at most
29
    /// 4095 bytes worth of buffer.
30
    ///
31
    /// Both the descriptors and buffer must be in DMA-capable memory.
32
    /// Only DRAM is supported for descriptors.
33
    pub fn new_with_config(
34
        descriptors: DmaAlignedMut<'a, [DmaDescriptor]>,
35
        buffer: DmaAlignedMut<'a, [u8]>,
36
        config: impl Into<BurstConfig>,
37
    ) -> Result<Self, DmaBufError> {
38
46
        let mut buf = Self {
39
1
            descriptors: DescriptorSet::new(descriptors)?,
40
            buffer,
41
            burst: BurstConfig::default(),
42
        };
43

            
44
        let capacity = buf.capacity();
45
        buf.configure(config, capacity)?;
46

            
47
46
        Ok(buf)
48
    }
49

            
50
    fn configure(
51
        &mut self,
52
        burst: impl Into<BurstConfig>,
53
        length: usize,
54
    ) -> Result<(), DmaBufError> {
55
        let burst = burst.into();
56
46
        self.set_length_fallible(length, burst)?;
57

            
58
        let max_chunk_size = burst.max_chunk_size_for(&self.buffer, TransferDirection::Out);
59
        self.descriptors
60
36
            .link_with_buffer(&mut self.buffer, max_chunk_size)?;
61

            
62
        self.burst = burst;
63
        Ok(())
64
    }
65

            
66
    /// Configures the DMA to use burst transfers to access this buffer.
67
    pub fn set_burst_config(&mut self, burst: BurstConfig) -> Result<(), DmaBufError> {
68
        let len = self.len();
69
        self.configure(burst, len)
70
    }
71

            
72
    /// Consumes the buf, returning the descriptors and buffer.
73
    pub fn split(self) -> (DmaAlignedMut<'a, [DmaDescriptor]>, DmaAlignedMut<'a, [u8]>) {
74
        (self.descriptors.descriptors, self.buffer)
75
    }
76

            
77
    /// Returns the size of the underlying buffer.
78
    pub fn capacity(&self) -> usize {
79
        self.buffer.len()
80
    }
81

            
82
    /// Returns the number of bytes that would be transmitted by this buf.
83
    #[allow(clippy::len_without_is_empty)]
84
    pub fn len(&self) -> usize {
85
        self.descriptors
86
            .linked_iter()
87
            .map(|d| d.len())
88
            .sum::<usize>()
89
    }
90

            
91
84
    fn set_length_fallible(&mut self, len: usize, burst: BurstConfig) -> Result<(), DmaBufError> {
92
84
        if len > self.capacity() {
93
            return Err(DmaBufError::BufferTooSmall);
94
        }
95
48
        burst.ensure_buffer_compatible(&self.buffer[..len], TransferDirection::Out)?;
96

            
97
        let max_chunk_size = burst.max_chunk_size_for(&self.buffer, TransferDirection::Out);
98
49
        self.descriptors.set_tx_length(len, max_chunk_size)?;
99

            
100
        // This only needs to be done once (after every significant length change) as
101
        // Self::prepare sets Preparation::auto_write_back to false.
102
        for desc in self.descriptors.linked_iter_mut() {
103
            // In non-circular mode, we only set `suc_eof` for the last descriptor to signal
104
            // the end of the transfer.
105
            desc.reset_for_tx(desc.next.is_null());
106
        }
107

            
108
        Ok(())
109
84
    }
110

            
111
    /// Resets the descriptors to only transmit `len` amount of bytes from this
112
    /// buf.
113
    ///
114
    /// The number of bytes in data must be less than or equal to the buffer
115
    /// size.
116
    pub fn set_length(&mut self, len: usize) {
117
11
        unwrap!(self.set_length_fallible(len, self.burst))
118
    }
119

            
120
    /// Fills the TX buffer with the bytes provided in `data` and reset the
121
    /// descriptors to only cover the filled section.
122
    ///
123
    /// The number of bytes in data must be less than or equal to the buffer
124
    /// size.
125
    pub fn fill(&mut self, data: &[u8]) {
126
        self.set_length(data.len());
127
        self.as_mut_slice()[..data.len()].copy_from_slice(data);
128
    }
129

            
130
    /// Returns the buf as a mutable slice that can be written.
131
    pub fn as_mut_slice(&mut self) -> &mut [u8] {
132
        &mut self.buffer
133
    }
134

            
135
    /// Returns the buf as a slice that can be read.
136
    pub fn as_slice(&self) -> &[u8] {
137
        &self.buffer
138
    }
139
}
140

            
141
unsafe impl<'a> DmaTxBuffer for ScopedDmaTxBuf<'a> {
142
    type View = BufView<ScopedDmaTxBuf<'a>>;
143
    type Final = ScopedDmaTxBuf<'a>;
144

            
145
    fn prepare(&mut self) -> Preparation {
146
        #[cfg(soc_internal_memory_cached)]
147
        self.descriptors.descriptors.writeback();
148

            
149
        #[cfg(dma_can_access_psram)]
150
        let is_data_in_psram = !is_valid_ram_address(self.buffer.as_ptr() as usize);
151

            
152
        #[cfg(any(soc_internal_memory_cached, dma_can_access_psram))]
153
        self.buffer.writeback();
154

            
155
4
        Preparation {
156
            start: self.descriptors.head(),
157
            #[cfg(dma_can_access_psram)]
158
            accesses_psram: is_data_in_psram,
159
6
            burst_transfer: self.burst,
160
            check_owner: None,
161
            auto_write_back: false,
162
        }
163
    }
164

            
165
    fn into_view(self) -> BufView<ScopedDmaTxBuf<'a>> {
166
        BufView(self)
167
    }
168

            
169
    fn from_view(view: Self::View) -> Self {
170
        view.0
171
    }
172
}
173

            
174
/// DMA receive buffer
175
///
176
/// This is a contiguous buffer linked together by DMA descriptors of length
177
/// 4092. It can only be used for receiving data from a peripheral's FIFO.
178
/// See [ScopedDmaTxBuf] for transmitting data.
179
#[derive(Debug)]
180
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
181
pub(crate) struct ScopedDmaRxBuf<'a> {
182
    descriptors: DescriptorSet<'a>,
183
    buffer: DmaAlignedMut<'a, [u8]>,
184
    burst: BurstConfig,
185
}
186

            
187
impl<'a> ScopedDmaRxBuf<'a> {
188
    /// Creates a new [ScopedDmaRxBuf] from some descriptors and a buffer.
189
    pub fn new(
190
        descriptors: DmaAlignedMut<'a, [DmaDescriptor]>,
191
        buffer: DmaAlignedMut<'a, [u8]>,
192
    ) -> Result<Self, DmaBufError> {
193
        Self::new_with_config(descriptors, buffer, BurstConfig::default())
194
    }
195

            
196
    /// Creates a new [ScopedDmaRxBuf] from some descriptors and a buffer.
197
    ///
198
    /// There must be enough descriptors for the provided buffer.
199
    /// Depending on alignment requirements, each descriptor can handle at most
200
    /// 4092 bytes worth of buffer.
201
    ///
202
    /// Both the descriptors and buffer must be in DMA-capable memory.
203
    /// Only DRAM is supported for descriptors.
204
    pub fn new_with_config(
205
        descriptors: DmaAlignedMut<'a, [DmaDescriptor]>,
206
        buffer: DmaAlignedMut<'a, [u8]>,
207
        config: impl Into<BurstConfig>,
208
    ) -> Result<Self, DmaBufError> {
209
40
        let mut buf = Self {
210
1
            descriptors: DescriptorSet::new(descriptors)?,
211
            buffer,
212
            burst: BurstConfig::default(),
213
        };
214

            
215
        buf.configure(config, buf.capacity())?;
216

            
217
40
        Ok(buf)
218
    }
219

            
220
    fn configure(
221
        &mut self,
222
        burst: impl Into<BurstConfig>,
223
        length: usize,
224
    ) -> Result<(), DmaBufError> {
225
        let burst = burst.into();
226
40
        self.set_length_fallible(length, burst)?;
227

            
228
        let max_chunk_size = burst.max_chunk_size_for(&self.buffer, TransferDirection::In);
229
        self.descriptors
230
40
            .link_with_buffer(&mut self.buffer, max_chunk_size)?;
231

            
232
1
        self.burst = burst;
233
        Ok(())
234
    }
235

            
236
    /// Configures the DMA to use burst transfers to access this buffer.
237
    pub fn set_burst_config(&mut self, burst: BurstConfig) -> Result<(), DmaBufError> {
238
        let len = self.len();
239
        self.configure(burst, len)
240
    }
241

            
242
    /// Consumes the buf, returning the descriptors and buffer.
243
    pub fn split(self) -> (DmaAlignedMut<'a, [DmaDescriptor]>, DmaAlignedMut<'a, [u8]>) {
244
        (self.descriptors.descriptors, self.buffer)
245
    }
246

            
247
    /// Returns the size of the underlying buffer.
248
    pub fn capacity(&self) -> usize {
249
        self.buffer.len()
250
    }
251

            
252
    /// Returns the maximum number of bytes that this buf has been configured to
253
    /// receive.
254
    #[allow(clippy::len_without_is_empty)]
255
    pub fn len(&self) -> usize {
256
        self.descriptors
257
            .linked_iter()
258
            .map(|d| d.size())
259
            .sum::<usize>()
260
    }
261

            
262
40
    fn set_length_fallible(&mut self, len: usize, burst: BurstConfig) -> Result<(), DmaBufError> {
263
40
        if len > self.capacity() {
264
            return Err(DmaBufError::BufferTooSmall);
265
        }
266
40
        burst.ensure_buffer_compatible(&self.buffer[..len], TransferDirection::In)?;
267

            
268
40
        self.descriptors.set_rx_length(
269
            len,
270
            burst.max_chunk_size_for(&self.buffer[..len], TransferDirection::In),
271
        )
272
40
    }
273

            
274
    /// Resets the descriptors to only receive `len` amount of bytes into this
275
    /// buf.
276
    ///
277
    /// The number of bytes in data must be less than or equal to the buffer
278
    /// size.
279
    pub fn set_length(&mut self, len: usize) {
280
        unwrap!(self.set_length_fallible(len, self.burst));
281
    }
282

            
283
    /// Returns the entire underlying buffer as a slice that can be read.
284
    pub fn as_slice(&self) -> &[u8] {
285
        &self.buffer
286
    }
287

            
288
    /// Returns the entire underlying buffer as a slice that can be written.
289
    pub fn as_mut_slice(&mut self) -> &mut [u8] {
290
        &mut self.buffer
291
    }
292

            
293
    /// Returns the number of bytes that was received by this buf.
294
    pub fn number_of_received_bytes(&self) -> usize {
295
        self.sync_received_from_dma();
296
        self.descriptors
297
            .linked_iter()
298
            .map(|d| d.len())
299
            .sum::<usize>()
300
    }
301

            
302
    /// Reads the received data into the provided `buf`.
303
    ///
304
    /// If `buf.len()` is less than the amount of received data then only the
305
    /// first `buf.len()` bytes of received data is written into `buf`.
306
    ///
307
    /// Returns the number of bytes written to `buf`.
308
    pub fn read_received_data(&self, mut buf: &mut [u8]) -> usize {
309
        // Note that due to an ESP32 quirk, the last received descriptor may not get
310
        // updated.
311
        let capacity = buf.len();
312
        for chunk in self.received_data() {
313
            if buf.is_empty() {
314
                break;
315
            }
316
            let to_fill;
317
            (to_fill, buf) = buf.split_at_mut(chunk.len());
318
            to_fill.copy_from_slice(chunk);
319
        }
320

            
321
        capacity - buf.len()
322
    }
323

            
324
    /// Returns the received data as an iterator of slices.
325
    pub fn received_data(&self) -> impl Iterator<Item = &[u8]> {
326
        self.sync_received_from_dma();
327
        self.descriptors.linked_iter().map(|desc| {
328
            // SAFETY: We set up the descriptor to point to a subslice of the buffer, and
329
            // here we are only recreating that slice with a perhaps shorter length.
330
            // We are also not accessing `self.buffer` while this slice is alive, so we
331
            // are not violating any aliasing rules.
332
            unsafe { core::slice::from_raw_parts(desc.buffer.cast_const(), desc.len()) }
333
        })
334
    }
335

            
336
    /// Reads DMA-written RX data from memory on cached SoCs.
337
    fn sync_received_from_dma(&self) {
338
        #[cfg(any(soc_internal_memory_cached, dma_can_access_psram))]
339
        {
340
            let descriptors = &*self.descriptors.descriptors;
341
            unsafe {
342
                crate::soc::cache_invalidate_addr(
343
                    descriptors.as_ptr() as u32,
344
                    core::mem::size_of_val(descriptors) as u32,
345
                );
346
            }
347
            for desc in self.descriptors.linked_iter() {
348
                let len = desc.len();
349
                if len > 0 {
350
                    unsafe {
351
                        crate::soc::cache_invalidate_addr(desc.buffer as u32, len as u32);
352
                    }
353
                }
354
            }
355
        }
356
    }
357
}
358

            
359
unsafe impl<'a> DmaRxBuffer for ScopedDmaRxBuf<'a> {
360
    type View = BufView<ScopedDmaRxBuf<'a>>;
361
    type Final = ScopedDmaRxBuf<'a>;
362

            
363
25
    fn prepare(&mut self) -> Preparation {
364
46
        for desc in self.descriptors.linked_iter_mut() {
365
            desc.reset_for_rx();
366
        }
367

            
368
        #[cfg(soc_internal_memory_cached)]
369
        self.descriptors.descriptors.writeback();
370

            
371
        #[cfg(dma_can_access_psram)]
372
        let is_data_in_psram = !is_valid_ram_address(self.buffer.as_ptr() as usize);
373

            
374
        #[cfg(any(soc_internal_memory_cached, dma_can_access_psram))]
375
        self.buffer.invalidate();
376

            
377
46
        Preparation {
378
            start: self.descriptors.head(),
379
            #[cfg(dma_can_access_psram)]
380
            accesses_psram: is_data_in_psram,
381
46
            burst_transfer: self.burst,
382
            check_owner: None,
383
            auto_write_back: true,
384
        }
385
25
    }
386

            
387
    fn into_view(self) -> BufView<Self> {
388
        BufView(self)
389
    }
390

            
391
    fn from_view(view: Self::View) -> Self {
392
        view.0
393
    }
394
}