1 /*
2  * Copyright (c) 2020 Raspberry Pi (Trading) Ltd.
3  *
4  * SPDX-License-Identifier: BSD-3-Clause
5  */
6 
7 #ifndef _HARDWARE_DMA_H_
8 #define _HARDWARE_DMA_H_
9 
10 #include "pico.h"
11 #include "hardware/structs/dma.h"
12 #include "hardware/regs/dreq.h"
13 #include "pico/assert.h"
14 
15 #ifdef __cplusplus
16 extern "C" {
17 #endif
18 
19 /** \file hardware/dma.h
20  *  \defgroup hardware_dma hardware_dma
21  *
22  * DMA Controller API
23  *
24  * The RP2040 Direct Memory Access (DMA) master performs bulk data transfers on a processor’s
25  * behalf. This leaves processors free to attend to other tasks, or enter low-power sleep states. The
26  * data throughput of the DMA is also significantly higher than one of RP2040’s processors.
27  *
28  * The DMA can perform one read access and one write access, up to 32 bits in size, every clock cycle.
29  * There are 12 independent channels, which each supervise a sequence of bus transfers, usually in
30  * one of the following scenarios:
31  *
32  * * Memory to peripheral
33  * * Peripheral to memory
34  * * Memory to memory
35  */
36 
37 // this is not defined in generated dreq.h
38 #define DREQ_FORCE  63
39 
40 // PICO_CONFIG: PARAM_ASSERTIONS_ENABLED_DMA, Enable/disable DMA assertions, type=bool, default=0, group=hardware_dma
41 #ifndef PARAM_ASSERTIONS_ENABLED_DMA
42 #define PARAM_ASSERTIONS_ENABLED_DMA 0
43 #endif
44 
check_dma_channel_param(uint channel)45 static inline void check_dma_channel_param(uint channel) {
46 #if PARAM_ASSERTIONS_ENABLED(DMA)
47     // this method is used a lot by inline functions so avoid code bloat by deferring to function
48     extern void check_dma_channel_param_impl(uint channel);
49     check_dma_channel_param_impl(channel);
50 #endif
51 }
52 
dma_channel_hw_addr(uint channel)53 inline static dma_channel_hw_t *dma_channel_hw_addr(uint channel) {
54     check_dma_channel_param(channel);
55     return &dma_hw->ch[channel];
56 }
57 
58 /*! \brief Mark a dma channel as used
59  *  \ingroup hardware_dma
60  *
61  * Method for cooperative claiming of hardware. Will cause a panic if the channel
62  * is already claimed. Use of this method by libraries detects accidental
63  * configurations that would fail in unpredictable ways.
64  *
65  * \param channel the dma channel
66  */
67 void dma_channel_claim(uint channel);
68 
69 /*! \brief Mark multiple dma channels as used
70  *  \ingroup hardware_dma
71  *
72  * Method for cooperative claiming of hardware. Will cause a panic if any of the channels
73  * are already claimed. Use of this method by libraries detects accidental
74  * configurations that would fail in unpredictable ways.
75  *
76  * \param channel_mask Bitfield of all required channels to claim (bit 0 == channel 0, bit 1 == channel 1 etc)
77  */
78 void dma_claim_mask(uint32_t channel_mask);
79 
80 /*! \brief Mark a dma channel as no longer used
81  *  \ingroup hardware_dma
82  *
83  * Method for cooperative claiming of hardware.
84  *
85  * \param channel the dma channel to release
86  */
87 void dma_channel_unclaim(uint channel);
88 
89 /*! \brief Claim a free dma channel
90  *  \ingroup hardware_dma
91  *
92  * \param required if true the function will panic if none are available
93  * \return the dma channel number or -1 if required was false, and none were free
94  */
95 int dma_claim_unused_channel(bool required);
96 
97 /** \brief DMA channel configuration
98  *  \defgroup channel_config channel_config
99  *  \ingroup hardware_dma
100  *
101  * A DMA channel needs to be configured, these functions provide handy helpers to set up configuration
102  * structures. See \ref dma_channel_config
103  *
104  */
105 
106 /*! \brief Enumeration of available DMA channel transfer sizes.
107  *  \ingroup hardware_dma
108  *
109  * Names indicate the number of bits.
110  */
111 enum dma_channel_transfer_size {
112     DMA_SIZE_8 = 0,    ///< Byte transfer (8 bits)
113     DMA_SIZE_16 = 1,   ///< Half word transfer (16 bits)
114     DMA_SIZE_32 = 2    ///< Word transfer (32 bits)
115 };
116 
117 typedef struct {
118     uint32_t ctrl;
119 } dma_channel_config;
120 
121 /*! \brief  Set DMA channel read increment
122  *  \ingroup channel_config
123  *
124  * \param c Pointer to channel configuration data
125  * \param incr True to enable read address increments, if false, each read will be from the same address
126  *             Usually disabled for peripheral to memory transfers
127  */
channel_config_set_read_increment(dma_channel_config * c,bool incr)128 static inline void channel_config_set_read_increment(dma_channel_config *c, bool incr) {
129     c->ctrl = incr ? (c->ctrl | DMA_CH0_CTRL_TRIG_INCR_READ_BITS) : (c->ctrl & ~DMA_CH0_CTRL_TRIG_INCR_READ_BITS);
130 }
131 
132 /*! \brief  Set DMA channel write increment
133  *  \ingroup channel_config
134  *
135  * \param c Pointer to channel configuration data
136  * \param incr True to enable write address increments, if false, each write will be to the same address
137  *             Usually disabled for memory to peripheral transfers
138  * Usually disabled for memory to peripheral transfers
139  */
channel_config_set_write_increment(dma_channel_config * c,bool incr)140 static inline void channel_config_set_write_increment(dma_channel_config *c, bool incr) {
141     c->ctrl = incr ? (c->ctrl | DMA_CH0_CTRL_TRIG_INCR_WRITE_BITS) : (c->ctrl & ~DMA_CH0_CTRL_TRIG_INCR_WRITE_BITS);
142 }
143 
144 /*! \brief  Select a transfer request signal
145  *  \ingroup channel_config
146  *
147  * The channel uses the transfer request signal to pace its data transfer rate.
148  * Sources for TREQ signals are internal (TIMERS) or external (DREQ, a Data Request from the system).
149  * 0x0 to 0x3a -> select DREQ n as TREQ
150  * 0x3b -> Select Timer 0 as TREQ
151  * 0x3c -> Select Timer 1 as TREQ
152  * 0x3d -> Select Timer 2 as TREQ (Optional)
153  * 0x3e -> Select Timer 3 as TREQ (Optional)
154  * 0x3f -> Permanent request, for unpaced transfers.
155  *
156  * \param c Pointer to channel configuration data
157  * \param dreq Source (see description)
158  */
channel_config_set_dreq(dma_channel_config * c,uint dreq)159 static inline void channel_config_set_dreq(dma_channel_config *c, uint dreq) {
160     assert(dreq <= DREQ_FORCE);
161     c->ctrl = (c->ctrl & ~DMA_CH0_CTRL_TRIG_TREQ_SEL_BITS) | (dreq << DMA_CH0_CTRL_TRIG_TREQ_SEL_LSB);
162 }
163 
164 /*! \brief  Set DMA channel completion channel
165  *  \ingroup channel_config
166  *
167  * When this channel completes, it will trigger the channel indicated by chain_to. Disable by
168  * setting chain_to to itself (the same channel)
169  *
170  * \param c Pointer to channel configuration data
171  * \param chain_to Channel to trigger when this channel completes.
172  */
channel_config_set_chain_to(dma_channel_config * c,uint chain_to)173 static inline void channel_config_set_chain_to(dma_channel_config *c, uint chain_to) {
174     assert(chain_to <= NUM_DMA_CHANNELS);
175     c->ctrl = (c->ctrl & ~DMA_CH0_CTRL_TRIG_CHAIN_TO_BITS) | (chain_to << DMA_CH0_CTRL_TRIG_CHAIN_TO_LSB);
176 }
177 
178 /*! \brief Set the size of each DMA bus transfer
179  *  \ingroup channel_config
180  *
181  * Set the size of each bus transfer (byte/halfword/word). The read and write addresses
182  * advance by the specific amount (1/2/4 bytes) with each transfer.
183  *
184  * \param c Pointer to channel configuration data
185  * \param size See enum for possible values.
186  */
channel_config_set_transfer_data_size(dma_channel_config * c,enum dma_channel_transfer_size size)187 static inline void channel_config_set_transfer_data_size(dma_channel_config *c, enum dma_channel_transfer_size size) {
188     assert(size == DMA_SIZE_8 || size == DMA_SIZE_16 || size == DMA_SIZE_32);
189     c->ctrl = (c->ctrl & ~DMA_CH0_CTRL_TRIG_DATA_SIZE_BITS) | (size << DMA_CH0_CTRL_TRIG_DATA_SIZE_LSB);
190 }
191 
192 /*! \brief  Set address wrapping parameters
193  *  \ingroup channel_config
194  *
195  * Size of address wrap region. If 0, don’t wrap. For values n > 0, only the lower n bits of the address
196  * will change. This wraps the address on a (1 << n) byte boundary, facilitating access to naturally-aligned
197  * ring buffers.
198  * Ring sizes between 2 and 32768 bytes are possible (size_bits from 1 - 15)
199  *
200  * 0x0 -> No wrapping.
201  *
202  * \param c Pointer to channel configuration data
203  * \param write True to apply to write addresses, false to apply to read addresses
204  * \param size_bits 0 to disable wrapping. Otherwise the size in bits of the changing part of the address.
205  *        Effectively wraps the address on a (1 << size_bits) byte boundary.
206  */
channel_config_set_ring(dma_channel_config * c,bool write,uint size_bits)207 static inline void channel_config_set_ring(dma_channel_config *c, bool write, uint size_bits) {
208     assert(size_bits < 32);
209     c->ctrl = (c->ctrl & ~(DMA_CH0_CTRL_TRIG_RING_SIZE_BITS | DMA_CH0_CTRL_TRIG_RING_SEL_BITS)) |
210               (size_bits << DMA_CH0_CTRL_TRIG_RING_SIZE_LSB) |
211               (write ? DMA_CH0_CTRL_TRIG_RING_SEL_BITS : 0);
212 }
213 
214 /*! \brief  Set DMA byte swapping
215  *  \ingroup channel_config
216  *
217  * No effect for byte data, for halfword data, the two bytes of each halfword are
218  * swapped. For word data, the four bytes of each word are swapped to reverse their order.
219  *
220  * \param c Pointer to channel configuration data
221  * \param bswap True to enable byte swapping
222  */
channel_config_set_bswap(dma_channel_config * c,bool bswap)223 static inline void channel_config_set_bswap(dma_channel_config *c, bool bswap) {
224     c->ctrl = bswap ? (c->ctrl | DMA_CH0_CTRL_TRIG_BSWAP_BITS) : (c->ctrl & ~DMA_CH0_CTRL_TRIG_BSWAP_BITS);
225 }
226 
227 /*! \brief  Set IRQ quiet mode
228  *  \ingroup channel_config
229  *
230  * In QUIET mode, the channel does not generate IRQs at the end of every transfer block. Instead,
231  * an IRQ is raised when NULL is written to a trigger register, indicating the end of a control
232  * block chain.
233  *
234  * \param c Pointer to channel configuration data
235  * \param irq_quiet True to enable quiet mode, false to disable.
236  */
channel_config_set_irq_quiet(dma_channel_config * c,bool irq_quiet)237 static inline void channel_config_set_irq_quiet(dma_channel_config *c, bool irq_quiet) {
238     c->ctrl = irq_quiet ? (c->ctrl | DMA_CH0_CTRL_TRIG_IRQ_QUIET_BITS) : (c->ctrl & ~DMA_CH0_CTRL_TRIG_IRQ_QUIET_BITS);
239 }
240 
241 /*!
242  *  \brief Enable/Disable the DMA channel
243  *  \ingroup channel_config
244  *
245  * When false, the channel will ignore triggers, stop issuing transfers, and pause the current transfer sequence (i.e. BUSY will
246  * remain high if already high)
247  *
248  * \param c Pointer to channel configuration data
249  * \param enable True to enable the DMA channel. When enabled, the channel will respond to triggering events, and start transferring data.
250  *
251  */
channel_config_set_enable(dma_channel_config * c,bool enable)252 static inline void channel_config_set_enable(dma_channel_config *c, bool enable) {
253     c->ctrl = enable ? (c->ctrl | DMA_CH0_CTRL_TRIG_EN_BITS) : (c->ctrl & ~DMA_CH0_CTRL_TRIG_EN_BITS);
254 }
255 
256 /*! \brief  Enable access to channel by sniff hardware.
257  *  \ingroup channel_config
258  *
259  * Sniff HW must be enabled and have this channel selected.
260  *
261  * \param c Pointer to channel configuration data
262  * \param sniff_enable True to enable the Sniff HW access to this DMA channel.
263  */
channel_config_set_sniff_enable(dma_channel_config * c,bool sniff_enable)264 static inline void channel_config_set_sniff_enable(dma_channel_config *c, bool sniff_enable) {
265     c->ctrl = sniff_enable ? (c->ctrl | DMA_CH0_CTRL_TRIG_SNIFF_EN_BITS) : (c->ctrl &
266                                                                              ~DMA_CH0_CTRL_TRIG_SNIFF_EN_BITS);
267 }
268 
269 /*! \brief  Get the default channel configuration for a given channel
270  *  \ingroup channel_config
271  *
272  * Setting | Default
273  * --------|--------
274  * Read Increment | true
275  * Write Increment | false
276  * DReq | DREQ_FORCE
277  * Chain to | self
278  * Data size | DMA_SIZE_32
279  * Ring | write=false, size=0 (i.e. off)
280  * Byte Swap | false
281  * Quiet IRQs | false
282  * Channel Enable | true
283  * Sniff Enable | false
284  *
285  * \param channel DMA channel
286  * \return the default configuration which can then be modified.
287  */
dma_channel_get_default_config(uint channel)288 static inline dma_channel_config dma_channel_get_default_config(uint channel) {
289     dma_channel_config c = {0};
290     channel_config_set_read_increment(&c, true);
291     channel_config_set_write_increment(&c, false);
292     channel_config_set_dreq(&c, DREQ_FORCE);
293     channel_config_set_chain_to(&c, channel);
294     channel_config_set_transfer_data_size(&c, DMA_SIZE_32);
295     channel_config_set_ring(&c, false, 0);
296     channel_config_set_bswap(&c, false);
297     channel_config_set_irq_quiet(&c, false);
298     channel_config_set_enable(&c, true);
299     channel_config_set_sniff_enable(&c, false);
300     return c;
301 }
302 
303 /*! \brief  Get the current configuration for the specified channel.
304  *  \ingroup channel_config
305  *
306  * \param channel DMA channel
307  * \return The current configuration as read from the HW register (not cached)
308  */
dma_get_channel_config(uint channel)309 static inline dma_channel_config dma_get_channel_config(uint channel) {
310     dma_channel_config c;
311     c.ctrl = dma_channel_hw_addr(channel)->ctrl_trig;
312     return c;
313 }
314 
315 /*! \brief  Get the raw configuration register from a channel configuration
316  *  \ingroup channel_config
317  *
318  * \param config Pointer to a config structure.
319  * \return Register content
320  */
channel_config_get_ctrl_value(const dma_channel_config * config)321 static inline uint32_t channel_config_get_ctrl_value(const dma_channel_config *config) {
322     return config->ctrl;
323 }
324 
325 /*! \brief  Set a channel configuration
326  *  \ingroup hardware_dma
327  *
328  * \param channel DMA channel
329  * \param config Pointer to a config structure with required configuration
330  * \param trigger True to trigger the transfer immediately
331  */
dma_channel_set_config(uint channel,const dma_channel_config * config,bool trigger)332 static inline void dma_channel_set_config(uint channel, const dma_channel_config *config, bool trigger) {
333     // Don't use CTRL_TRIG since we don't want to start a transfer
334     if (!trigger) {
335         dma_channel_hw_addr(channel)->al1_ctrl = channel_config_get_ctrl_value(config);
336     } else {
337         dma_channel_hw_addr(channel)->ctrl_trig = channel_config_get_ctrl_value(config);
338     }
339 }
340 
341 /*! \brief  Set the DMA initial read address.
342  *  \ingroup hardware_dma
343  *
344  * \param channel DMA channel
345  * \param read_addr Initial read address of transfer.
346  * \param trigger True to start the transfer immediately
347  */
dma_channel_set_read_addr(uint channel,const volatile void * read_addr,bool trigger)348 static inline void dma_channel_set_read_addr(uint channel, const volatile void *read_addr, bool trigger) {
349     if (!trigger) {
350         dma_channel_hw_addr(channel)->read_addr = (uintptr_t) read_addr;
351     } else {
352         dma_channel_hw_addr(channel)->al3_read_addr_trig = (uintptr_t) read_addr;
353     }
354 }
355 
356 /*! \brief  Set the DMA initial read address
357  *  \ingroup hardware_dma
358  *
359  * \param channel DMA channel
360  * \param write_addr Initial write address of transfer.
361  * \param trigger True to start the transfer immediately
362  */
dma_channel_set_write_addr(uint channel,volatile void * write_addr,bool trigger)363 static inline void dma_channel_set_write_addr(uint channel, volatile void *write_addr, bool trigger) {
364     if (!trigger) {
365         dma_channel_hw_addr(channel)->write_addr = (uintptr_t) write_addr;
366     } else {
367         dma_channel_hw_addr(channel)->al2_write_addr_trig = (uintptr_t) write_addr;
368     }
369 }
370 
371 /*! \brief  Set the number of bus transfers the channel will do
372  *  \ingroup hardware_dma
373  *
374  * \param channel DMA channel
375  * \param trans_count The number of transfers (not NOT bytes, see channel_config_set_transfer_data_size)
376  * \param trigger True to start the transfer immediately
377  */
dma_channel_set_trans_count(uint channel,uint32_t trans_count,bool trigger)378 static inline void dma_channel_set_trans_count(uint channel, uint32_t trans_count, bool trigger) {
379     if (!trigger) {
380         dma_channel_hw_addr(channel)->transfer_count = trans_count;
381     } else {
382         dma_channel_hw_addr(channel)->al1_transfer_count_trig = trans_count;
383     }
384 }
385 
386 /*! \brief  Configure all DMA parameters and optionally start transfer
387  *  \ingroup hardware_dma
388  *
389  * \param channel DMA channel
390  * \param config Pointer to DMA config structure
391  * \param write_addr Initial write address
392  * \param read_addr Initial read address
393  * \param transfer_count Number of transfers to perform
394  * \param trigger True to start the transfer immediately
395  */
dma_channel_configure(uint channel,const dma_channel_config * config,volatile void * write_addr,const volatile void * read_addr,uint transfer_count,bool trigger)396 static inline void dma_channel_configure(uint channel, const dma_channel_config *config, volatile void *write_addr,
397                                          const volatile void *read_addr,
398                                          uint transfer_count, bool trigger) {
399     dma_channel_set_read_addr(channel, read_addr, false);
400     dma_channel_set_write_addr(channel, write_addr, false);
401     dma_channel_set_trans_count(channel, transfer_count, false);
402     dma_channel_set_config(channel, config, trigger);
403 }
404 
405 /*! \brief Start a DMA transfer from a buffer immediately
406  *  \ingroup hardware_dma
407  *
408  * \param channel DMA channel
409  * \param read_addr Sets the initial read address
410  * \param transfer_count Number of transfers to make. Not bytes, but the number of transfers of channel_config_set_transfer_data_size() to be sent.
411  */
dma_channel_transfer_from_buffer_now(uint channel,void * read_addr,uint32_t transfer_count)412 inline static void __attribute__((always_inline)) dma_channel_transfer_from_buffer_now(uint channel, void *read_addr,
413                                                                                        uint32_t transfer_count) {
414 //    check_dma_channel_param(channel);
415     dma_channel_hw_t *hw = dma_channel_hw_addr(channel);
416     hw->read_addr = (uintptr_t) read_addr;
417     hw->al1_transfer_count_trig = transfer_count;
418 }
419 
420 /*! \brief Start a DMA transfer to a buffer immediately
421  *  \ingroup hardware_dma
422  *
423  * \param channel DMA channel
424  * \param write_addr Sets the initial write address
425  * \param transfer_count Number of transfers to make. Not bytes, but the number of transfers of channel_config_set_transfer_data_size() to be sent.
426  */
dma_channel_transfer_to_buffer_now(uint channel,void * write_addr,uint32_t transfer_count)427 inline static void dma_channel_transfer_to_buffer_now(uint channel, void *write_addr, uint32_t transfer_count) {
428     dma_channel_hw_t *hw = dma_channel_hw_addr(channel);
429     hw->write_addr = (uintptr_t) write_addr;
430     hw->al1_transfer_count_trig = transfer_count;
431 }
432 
433 /*! \brief  Start one or more channels simultaneously
434  *  \ingroup hardware_dma
435  *
436  * \param chan_mask Bitmask of all the channels requiring starting. Channel 0 = bit 0, channel 1 = bit 1 etc.
437  */
dma_start_channel_mask(uint32_t chan_mask)438 static inline void dma_start_channel_mask(uint32_t chan_mask) {
439     valid_params_if(DMA, chan_mask && chan_mask < (1u << NUM_DMA_CHANNELS));
440     dma_hw->multi_channel_trigger = chan_mask;
441 }
442 
443 /*! \brief  Start a single DMA channel
444  *  \ingroup hardware_dma
445  *
446  * \param channel DMA channel
447  */
dma_channel_start(uint channel)448 static inline void dma_channel_start(uint channel) {
449     dma_start_channel_mask(1u << channel);
450 }
451 
452 /*! \brief  Stop a DMA transfer
453  *  \ingroup hardware_dma
454  *
455  * Function will only return once the DMA has stopped.
456  *
457  * \param channel DMA channel
458  */
dma_channel_abort(uint channel)459 static inline void dma_channel_abort(uint channel) {
460     check_dma_channel_param(channel);
461     dma_hw->abort = 1u << channel;
462     // Bit will go 0 once channel has reached safe state
463     // (i.e. any in-flight transfers have retired)
464     while (dma_hw->abort & (1ul << channel)) tight_loop_contents();
465 }
466 
467 /*! \brief  Enable single DMA channel interrupt 0
468  *  \ingroup hardware_dma
469  *
470  * \param channel DMA channel
471  * \param enabled true to enable interrupt 0 on specified channel, false to disable.
472  */
dma_channel_set_irq0_enabled(uint channel,bool enabled)473 static inline void dma_channel_set_irq0_enabled(uint channel, bool enabled) {
474     check_dma_channel_param(channel);
475     check_hw_layout(dma_hw_t, inte0, DMA_INTE0_OFFSET);
476     if (enabled)
477         hw_set_bits(&dma_hw->inte0, 1u << channel);
478     else
479         hw_clear_bits(&dma_hw->inte0, 1u << channel);
480 }
481 
482 /*! \brief  Enable multiple DMA channels interrupt 0
483  *  \ingroup hardware_dma
484  *
485  * \param channel_mask Bitmask of all the channels to enable/disable. Channel 0 = bit 0, channel 1 = bit 1 etc.
486  * \param enabled true to enable all the interrupts specified in the mask, false to disable all the interrupts specified in the mask.
487  */
dma_set_irq0_channel_mask_enabled(uint32_t channel_mask,bool enabled)488 static inline void dma_set_irq0_channel_mask_enabled(uint32_t channel_mask, bool enabled) {
489     if (enabled) {
490         hw_set_bits(&dma_hw->inte0, channel_mask);
491     } else {
492         hw_clear_bits(&dma_hw->inte0, channel_mask);
493     }
494 }
495 
496 /*! \brief  Enable single DMA channel interrupt 1
497  *  \ingroup hardware_dma
498  *
499  * \param channel DMA channel
500  * \param enabled true to enable interrupt 1 on specified channel, false to disable.
501  */
dma_channel_set_irq1_enabled(uint channel,bool enabled)502 static inline void dma_channel_set_irq1_enabled(uint channel, bool enabled) {
503     check_dma_channel_param(channel);
504     check_hw_layout(dma_hw_t, inte1, DMA_INTE1_OFFSET);
505     if (enabled)
506         hw_set_bits(&dma_hw->inte1, 1u << channel);
507     else
508         hw_clear_bits(&dma_hw->inte1, 1u << channel);
509 }
510 
511 /*! \brief  Enable multiple DMA channels interrupt 0
512  *  \ingroup hardware_dma
513  *
514  * \param channel_mask Bitmask of all the channels to enable/disable. Channel 0 = bit 0, channel 1 = bit 1 etc.
515  * \param enabled true to enable all the interrupts specified in the mask, false to disable all the interrupts specified in the mask.
516  */
dma_set_irq1_channel_mask_enabled(uint32_t channel_mask,bool enabled)517 static inline void dma_set_irq1_channel_mask_enabled(uint32_t channel_mask, bool enabled) {
518     if (enabled) {
519         hw_set_bits(&dma_hw->inte1, channel_mask);
520     } else {
521         hw_clear_bits(&dma_hw->inte1, channel_mask);
522     }
523 }
524 
525 /*! \brief  Check if DMA channel is busy
526  *  \ingroup hardware_dma
527  *
528  * \param channel DMA channel
529  * \return true if the channel is currently busy
530  */
dma_channel_is_busy(uint channel)531 inline static bool dma_channel_is_busy(uint channel) {
532     check_dma_channel_param(channel);
533     return !!(dma_hw->ch[channel].al1_ctrl & DMA_CH0_CTRL_TRIG_BUSY_BITS);
534 }
535 
536 /*! \brief  Wait for a DMA channel transfer to complete
537  *  \ingroup hardware_dma
538  *
539  * \param channel DMA channel
540  */
dma_channel_wait_for_finish_blocking(uint channel)541 inline static void dma_channel_wait_for_finish_blocking(uint channel) {
542     while (dma_channel_is_busy(channel)) tight_loop_contents();
543 }
544 
545 /*! \brief Enable the DMA sniffing targeting the specified channel
546  *  \ingroup hardware_dma
547  *
548  * The mode can be one of the following:
549  *
550  * Mode | Function
551  * -----|---------
552  * 0x0 | Calculate a CRC-32 (IEEE802.3 polynomial)
553  * 0x1 | Calculate a CRC-32 (IEEE802.3 polynomial) with bit reversed data
554  * 0x2 | Calculate a CRC-16-CCITT
555  * 0x3 | Calculate a CRC-16-CCITT with bit reversed data
556  * 0xe | XOR reduction over all data. == 1 if the total 1 population count is odd.
557  * 0xf | Calculate a simple 32-bit checksum (addition with a 32 bit accumulator)
558  *
559  * \param channel DMA channel
560  * \param mode See description
561  * \param force_channel_enable Set true to also turn on sniffing in the channel configuration (this
562  * is usually what you want, but sometimes you might have a chain DMA with only certain segments
563  * of the chain sniffed, in which case you might pass false).
564  */
dma_sniffer_enable(uint channel,uint mode,bool force_channel_enable)565 inline static void dma_sniffer_enable(uint channel, uint mode, bool force_channel_enable) {
566     check_dma_channel_param(channel);
567     check_hw_layout(dma_hw_t, sniff_ctrl, DMA_SNIFF_CTRL_OFFSET);
568     if (force_channel_enable) {
569         hw_set_bits(&dma_hw->ch[channel].al1_ctrl, DMA_CH0_CTRL_TRIG_SNIFF_EN_BITS);
570     }
571     dma_hw->sniff_ctrl = ((channel << DMA_SNIFF_CTRL_DMACH_LSB) & DMA_SNIFF_CTRL_DMACH_BITS) |
572                          ((mode << DMA_SNIFF_CTRL_CALC_LSB) & DMA_SNIFF_CTRL_CALC_BITS) |
573                          DMA_SNIFF_CTRL_EN_BITS;
574 }
575 
576 /*! \brief Enable the Sniffer byte swap function
577  *  \ingroup hardware_dma
578  *
579  * Locally perform a byte reverse on the sniffed data, before feeding into checksum.
580  *
581  * Note that the sniff hardware is downstream of the DMA channel byteswap performed in the
582  * read master: if channel_config_set_bswap() and dma_sniffer_set_byte_swap_enabled() are both enabled,
583  * their effects cancel from the sniffer’s point of view.
584  *
585  * \param swap Set true to enable byte swapping
586  */
dma_sniffer_set_byte_swap_enabled(bool swap)587 inline static void dma_sniffer_set_byte_swap_enabled(bool swap) {
588     if (swap)
589         hw_set_bits(&dma_hw->sniff_ctrl, DMA_SNIFF_CTRL_BSWAP_BITS);
590     else
591         hw_clear_bits(&dma_hw->sniff_ctrl, DMA_SNIFF_CTRL_BSWAP_BITS);
592 }
593 
594 /*! \brief Disable the DMA sniffer
595  *  \ingroup hardware_dma
596  *
597  */
dma_sniffer_disable(void)598 inline static void dma_sniffer_disable(void) {
599     dma_hw->sniff_ctrl = 0;
600 }
601 
602 #ifndef NDEBUG
603 void print_dma_ctrl(dma_channel_hw_t *channel);
604 #endif
605 
606 #ifdef __cplusplus
607 }
608 #endif
609 
610 #endif
611