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 #include "hardware/regs/intctrl.h"
15 
16 #ifdef __cplusplus
17 extern "C" {
18 #endif
19 
20 /** \file hardware/dma.h
21  *  \defgroup hardware_dma hardware_dma
22  *
23  * \brief DMA Controller API
24  *
25  * The RP-series microcontroller Direct Memory Access (DMA) master performs bulk data transfers on a processor’s
26  * behalf. This leaves processors free to attend to other tasks, or enter low-power sleep states. The
27  * data throughput of the DMA is also significantly higher than one of RP-series microcontroller’s processors.
28  *
29  * The DMA can perform one read access and one write access, up to 32 bits in size, every clock cycle.
30  * There are 12 independent channels, which each supervise a sequence of bus transfers, usually in
31  * one of the following scenarios:
32  *
33  * * Memory to peripheral
34  * * Peripheral to memory
35  * * Memory to memory
36  */
37 
38 // PICO_CONFIG: PARAM_ASSERTIONS_ENABLED_HARDWARE_DMA, Enable/disable hardware_dma assertions, type=bool, default=0, group=hardware_dma
39 #ifndef PARAM_ASSERTIONS_ENABLED_HARDWARE_DMA
40 #ifdef PARAM_ASSERTIONS_ENABLED_DMA // backwards compatibility with SDK < 2.0.0
41 #define PARAM_ASSERTIONS_ENABLED_HARDWARE_DMA PARAM_ASSERTIONS_ENABLED_DMA
42 #else
43 #define PARAM_ASSERTIONS_ENABLED_HARDWARE_DMA 0
44 #endif
45 #endif
46 
47 /**
48  * \def DMA_IRQ_NUM(n)
49  * \ingroup hardware_dma
50  * \hideinitializer
51  * \brief Returns the \ref irq_num_t for the nth DMA interrupt
52  *
53  * Note this macro is intended to resolve at compile time, and does no parameter checking
54  */
55 #ifndef DMA_IRQ_NUM
56 #define DMA_IRQ_NUM(irq_index) (DMA_IRQ_0 + (irq_index))
57 #endif
58 
check_dma_channel_param(__unused uint channel)59 static inline void check_dma_channel_param(__unused uint channel) {
60 #if PARAM_ASSERTIONS_ENABLED(HARDWARE_DMA)
61     // this method is used a lot by inline functions so avoid code bloat by deferring to function
62     extern void check_dma_channel_param_impl(uint channel);
63     check_dma_channel_param_impl(channel);
64 #endif
65 }
66 
check_dma_timer_param(__unused uint timer_num)67 static inline void check_dma_timer_param(__unused uint timer_num) {
68     valid_params_if(HARDWARE_DMA, timer_num < NUM_DMA_TIMERS);
69 }
70 
dma_channel_hw_addr(uint channel)71 inline static dma_channel_hw_t *dma_channel_hw_addr(uint channel) {
72     check_dma_channel_param(channel);
73     return &dma_hw->ch[channel];
74 }
75 
76 /*! \brief Mark a dma channel as used
77  *  \ingroup hardware_dma
78  *
79  * Method for cooperative claiming of hardware. Will cause a panic if the channel
80  * is already claimed. Use of this method by libraries detects accidental
81  * configurations that would fail in unpredictable ways.
82  *
83  * \param channel the dma channel
84  */
85 void dma_channel_claim(uint channel);
86 
87 /*! \brief Mark multiple dma channels as used
88  *  \ingroup hardware_dma
89  *
90  * Method for cooperative claiming of hardware. Will cause a panic if any of the channels
91  * are already claimed. Use of this method by libraries detects accidental
92  * configurations that would fail in unpredictable ways.
93  *
94  * \param channel_mask Bitfield of all required channels to claim (bit 0 == channel 0, bit 1 == channel 1 etc)
95  */
96 void dma_claim_mask(uint32_t channel_mask);
97 
98 /*! \brief Mark a dma channel as no longer used
99  *  \ingroup hardware_dma
100  *
101  * \param channel the dma channel to release
102  */
103 void dma_channel_unclaim(uint channel);
104 
105 /*! \brief Mark multiple dma channels as no longer used
106  *  \ingroup hardware_dma
107  *
108  * \param channel_mask Bitfield of all channels to unclaim (bit 0 == channel 0, bit 1 == channel 1 etc)
109  */
110 void dma_unclaim_mask(uint32_t channel_mask);
111 
112 /*! \brief Claim a free dma channel
113  *  \ingroup hardware_dma
114  *
115  * \param required if true the function will panic if none are available
116  * \return the dma channel number or -1 if required was false, and none were free
117  */
118 int dma_claim_unused_channel(bool required);
119 
120 /*! \brief Determine if a dma channel is claimed
121  *  \ingroup hardware_dma
122  *
123  * \param channel the dma channel
124  * \return true if the channel is claimed, false otherwise
125  * \see dma_channel_claim
126  * \see dma_channel_claim_mask
127  */
128 bool dma_channel_is_claimed(uint channel);
129 
130 /** \brief DMA channel configuration
131  *  \defgroup channel_config channel_config
132  *  \ingroup hardware_dma
133  *
134  * A DMA channel needs to be configured, these functions provide handy helpers to set up configuration
135  * structures. See \ref dma_channel_config
136  */
137 
138 /*! \brief Enumeration of available DMA channel transfer sizes.
139  *  \ingroup hardware_dma
140  *
141  * Names indicate the number of bits.
142  */
143 enum dma_channel_transfer_size {
144     DMA_SIZE_8 = 0,    ///< Byte transfer (8 bits)
145     DMA_SIZE_16 = 1,   ///< Half word transfer (16 bits)
146     DMA_SIZE_32 = 2    ///< Word transfer (32 bits)
147 };
148 
149 typedef struct {
150     uint32_t ctrl;
151 } dma_channel_config;
152 
153 /*! \brief  Set DMA channel read increment in a channel configuration object
154  *  \ingroup channel_config
155  *
156  * \param c Pointer to channel configuration object
157  * \param incr True to enable read address increments, if false, each read will be from the same address
158  *             Usually disabled for peripheral to memory transfers
159  */
channel_config_set_read_increment(dma_channel_config * c,bool incr)160 static inline void channel_config_set_read_increment(dma_channel_config *c, bool incr) {
161     c->ctrl = incr ? (c->ctrl | DMA_CH0_CTRL_TRIG_INCR_READ_BITS) : (c->ctrl & ~DMA_CH0_CTRL_TRIG_INCR_READ_BITS);
162 }
163 
164 /*! \brief  Set DMA channel write increment in a channel configuration object
165  *  \ingroup channel_config
166  *
167  * \param c Pointer to channel configuration object
168  * \param incr True to enable write address increments, if false, each write will be to the same address
169  *             Usually disabled for memory to peripheral transfers
170  */
channel_config_set_write_increment(dma_channel_config * c,bool incr)171 static inline void channel_config_set_write_increment(dma_channel_config *c, bool incr) {
172     c->ctrl = incr ? (c->ctrl | DMA_CH0_CTRL_TRIG_INCR_WRITE_BITS) : (c->ctrl & ~DMA_CH0_CTRL_TRIG_INCR_WRITE_BITS);
173 }
174 
175 /*! \brief  Select a transfer request signal in a channel configuration object
176  *  \ingroup channel_config
177  *
178  * The channel uses the transfer request signal to pace its data transfer rate.
179  * Sources for TREQ signals are internal (TIMERS) or external (DREQ, a Data Request from the system).
180  * 0x0 to 0x3a -> select DREQ n as TREQ
181  * 0x3b -> Select Timer 0 as TREQ
182  * 0x3c -> Select Timer 1 as TREQ
183  * 0x3d -> Select Timer 2 as TREQ (Optional)
184  * 0x3e -> Select Timer 3 as TREQ (Optional)
185  * 0x3f -> Permanent request, for unpaced transfers.
186  *
187  * \param c Pointer to channel configuration data
188  * \param dreq Source (see description)
189  */
channel_config_set_dreq(dma_channel_config * c,uint dreq)190 static inline void channel_config_set_dreq(dma_channel_config *c, uint dreq) {
191     assert(dreq <= DREQ_FORCE);
192     c->ctrl = (c->ctrl & ~DMA_CH0_CTRL_TRIG_TREQ_SEL_BITS) | (dreq << DMA_CH0_CTRL_TRIG_TREQ_SEL_LSB);
193 }
194 
195 /*! \brief  Set DMA channel chain_to channel in a channel configuration object
196  *  \ingroup channel_config
197  *
198  * When this channel completes, it will trigger the channel indicated by chain_to. Disable by
199  * setting chain_to to itself (the same channel)
200  *
201  * \param c Pointer to channel configuration object
202  * \param chain_to Channel to trigger when this channel completes.
203  */
channel_config_set_chain_to(dma_channel_config * c,uint chain_to)204 static inline void channel_config_set_chain_to(dma_channel_config *c, uint chain_to) {
205     assert(chain_to <= NUM_DMA_CHANNELS);
206     c->ctrl = (c->ctrl & ~DMA_CH0_CTRL_TRIG_CHAIN_TO_BITS) | (chain_to << DMA_CH0_CTRL_TRIG_CHAIN_TO_LSB);
207 }
208 
209 /*! \brief Set the size of each DMA bus transfer in a channel configuration object
210  *  \ingroup channel_config
211  *
212  * Set the size of each bus transfer (byte/halfword/word). The read and write addresses
213  * advance by the specific amount (1/2/4 bytes) with each transfer.
214  *
215  * \param c Pointer to channel configuration object
216  * \param size See enum for possible values.
217  */
channel_config_set_transfer_data_size(dma_channel_config * c,enum dma_channel_transfer_size size)218 static inline void channel_config_set_transfer_data_size(dma_channel_config *c, enum dma_channel_transfer_size size) {
219     assert(size == DMA_SIZE_8 || size == DMA_SIZE_16 || size == DMA_SIZE_32);
220     c->ctrl = (c->ctrl & ~DMA_CH0_CTRL_TRIG_DATA_SIZE_BITS) | (((uint)size) << DMA_CH0_CTRL_TRIG_DATA_SIZE_LSB);
221 }
222 
223 /*! \brief  Set address wrapping parameters in a channel configuration object
224  *  \ingroup channel_config
225  *
226  * Size of address wrap region. If 0, don’t wrap. For values n > 0, only the lower n bits of the address
227  * will change. This wraps the address on a (1 << n) byte boundary, facilitating access to naturally-aligned
228  * ring buffers.
229  * Ring sizes between 2 and 32768 bytes are possible (size_bits from 1 - 15)
230  *
231  * 0x0 -> No wrapping.
232  *
233  * \param c Pointer to channel configuration object
234  * \param write True to apply to write addresses, false to apply to read addresses
235  * \param size_bits 0 to disable wrapping. Otherwise the size in bits of the changing part of the address.
236  *        Effectively wraps the address on a (1 << size_bits) byte boundary.
237  */
channel_config_set_ring(dma_channel_config * c,bool write,uint size_bits)238 static inline void channel_config_set_ring(dma_channel_config *c, bool write, uint size_bits) {
239     assert(size_bits < 32);
240     c->ctrl = (c->ctrl & ~(DMA_CH0_CTRL_TRIG_RING_SIZE_BITS | DMA_CH0_CTRL_TRIG_RING_SEL_BITS)) |
241               (size_bits << DMA_CH0_CTRL_TRIG_RING_SIZE_LSB) |
242               (write ? DMA_CH0_CTRL_TRIG_RING_SEL_BITS : 0);
243 }
244 
245 /*! \brief  Set DMA byte swapping config in a channel configuration object
246  *  \ingroup channel_config
247  *
248  * No effect for byte data, for halfword data, the two bytes of each halfword are
249  * swapped. For word data, the four bytes of each word are swapped to reverse their order.
250  *
251  * \param c Pointer to channel configuration object
252  * \param bswap True to enable byte swapping
253  */
channel_config_set_bswap(dma_channel_config * c,bool bswap)254 static inline void channel_config_set_bswap(dma_channel_config *c, bool bswap) {
255     c->ctrl = bswap ? (c->ctrl | DMA_CH0_CTRL_TRIG_BSWAP_BITS) : (c->ctrl & ~DMA_CH0_CTRL_TRIG_BSWAP_BITS);
256 }
257 
258 /*! \brief  Set IRQ quiet mode in a channel configuration object
259  *  \ingroup channel_config
260  *
261  * In QUIET mode, the channel does not generate IRQs at the end of every transfer block. Instead,
262  * an IRQ is raised when NULL is written to a trigger register, indicating the end of a control
263  * block chain.
264  *
265  * \param c Pointer to channel configuration object
266  * \param irq_quiet True to enable quiet mode, false to disable.
267  */
channel_config_set_irq_quiet(dma_channel_config * c,bool irq_quiet)268 static inline void channel_config_set_irq_quiet(dma_channel_config *c, bool irq_quiet) {
269     c->ctrl = irq_quiet ? (c->ctrl | DMA_CH0_CTRL_TRIG_IRQ_QUIET_BITS) : (c->ctrl & ~DMA_CH0_CTRL_TRIG_IRQ_QUIET_BITS);
270 }
271 
272 /*!
273  *  \brief Set the channel priority in a channel configuration object
274  *  \ingroup channel_config
275  *
276  * When true, gives a channel preferential treatment in issue scheduling: in each scheduling round,
277  * all high priority channels are considered first, and then only a single low
278  * priority channel, before returning to the high priority channels.
279  *
280  * This only affects the order in which the DMA schedules channels. The DMA's bus priority is not changed.
281  * If the DMA is not saturated then a low priority channel will see no loss of throughput.
282  *
283  * \param c Pointer to channel configuration object
284  * \param high_priority True to enable high priority
285  */
channel_config_set_high_priority(dma_channel_config * c,bool high_priority)286 static inline void channel_config_set_high_priority(dma_channel_config *c, bool high_priority) {
287     c->ctrl = high_priority ? (c->ctrl | DMA_CH0_CTRL_TRIG_HIGH_PRIORITY_BITS) : (c->ctrl & ~DMA_CH0_CTRL_TRIG_HIGH_PRIORITY_BITS);
288 }
289 
290 /*!
291  *  \brief Enable/Disable the DMA channel in a channel configuration object
292  *  \ingroup channel_config
293  *
294  * When false, the channel will ignore triggers, stop issuing transfers, and pause the current transfer sequence (i.e. BUSY will
295  * remain high if already high)
296  *
297  * \param c Pointer to channel configuration object
298  * \param enable True to enable the DMA channel. When enabled, the channel will respond to triggering events, and start transferring data.
299  *
300  */
channel_config_set_enable(dma_channel_config * c,bool enable)301 static inline void channel_config_set_enable(dma_channel_config *c, bool enable) {
302     c->ctrl = enable ? (c->ctrl | DMA_CH0_CTRL_TRIG_EN_BITS) : (c->ctrl & ~DMA_CH0_CTRL_TRIG_EN_BITS);
303 }
304 
305 /*! \brief  Enable access to channel by sniff hardware in a channel configuration object
306  *  \ingroup channel_config
307  *
308  * Sniff HW must be enabled and have this channel selected.
309  *
310  * \param c Pointer to channel configuration object
311  * \param sniff_enable True to enable the Sniff HW access to this DMA channel.
312  */
channel_config_set_sniff_enable(dma_channel_config * c,bool sniff_enable)313 static inline void channel_config_set_sniff_enable(dma_channel_config *c, bool sniff_enable) {
314     c->ctrl = sniff_enable ? (c->ctrl | DMA_CH0_CTRL_TRIG_SNIFF_EN_BITS) : (c->ctrl &
315                                                                              ~DMA_CH0_CTRL_TRIG_SNIFF_EN_BITS);
316 }
317 
318 /*! \brief  Get the default channel configuration for a given channel
319  *  \ingroup channel_config
320  *
321  * Setting | Default
322  * --------|--------
323  * Read Increment | true
324  * Write Increment | false
325  * DReq | DREQ_FORCE
326  * Chain to | self
327  * Data size | DMA_SIZE_32
328  * Ring | write=false, size=0 (i.e. off)
329  * Byte Swap | false
330  * Quiet IRQs | false
331  * High Priority | false
332  * Channel Enable | true
333  * Sniff Enable | false
334  *
335  * \param channel DMA channel
336  * \return the default configuration which can then be modified.
337  */
dma_channel_get_default_config(uint channel)338 static inline dma_channel_config dma_channel_get_default_config(uint channel) {
339     dma_channel_config c = {0};
340     channel_config_set_read_increment(&c, true);
341     channel_config_set_write_increment(&c, false);
342     channel_config_set_dreq(&c, DREQ_FORCE);
343     channel_config_set_chain_to(&c, channel);
344     channel_config_set_transfer_data_size(&c, DMA_SIZE_32);
345     channel_config_set_ring(&c, false, 0);
346     channel_config_set_bswap(&c, false);
347     channel_config_set_irq_quiet(&c, false);
348     channel_config_set_enable(&c, true);
349     channel_config_set_sniff_enable(&c, false);
350     channel_config_set_high_priority( &c, false);
351     return c;
352 }
353 
354 /*! \brief  Get the current configuration for the specified channel.
355  *  \ingroup channel_config
356  *
357  * \param channel DMA channel
358  * \return The current configuration as read from the HW register (not cached)
359  */
dma_get_channel_config(uint channel)360 static inline dma_channel_config dma_get_channel_config(uint channel) {
361     dma_channel_config c;
362     c.ctrl = dma_channel_hw_addr(channel)->ctrl_trig;
363     return c;
364 }
365 
366 /*! \brief  Get the raw configuration register from a channel configuration
367  *  \ingroup channel_config
368  *
369  * \param config Pointer to a config structure.
370  * \return Register content
371  */
channel_config_get_ctrl_value(const dma_channel_config * config)372 static inline uint32_t channel_config_get_ctrl_value(const dma_channel_config *config) {
373     return config->ctrl;
374 }
375 
376 /*! \brief  Set a channel configuration
377  *  \ingroup hardware_dma
378  *
379  * \param channel DMA channel
380  * \param config Pointer to a config structure with required configuration
381  * \param trigger True to trigger the transfer immediately
382  */
dma_channel_set_config(uint channel,const dma_channel_config * config,bool trigger)383 static inline void dma_channel_set_config(uint channel, const dma_channel_config *config, bool trigger) {
384     // Don't use CTRL_TRIG since we don't want to start a transfer
385     if (!trigger) {
386         dma_channel_hw_addr(channel)->al1_ctrl = channel_config_get_ctrl_value(config);
387     } else {
388         dma_channel_hw_addr(channel)->ctrl_trig = channel_config_get_ctrl_value(config);
389     }
390 }
391 
392 /*! \brief  Set the DMA initial read address.
393  *  \ingroup hardware_dma
394  *
395  * \param channel DMA channel
396  * \param read_addr Initial read address of transfer.
397  * \param trigger True to start the transfer immediately
398  */
dma_channel_set_read_addr(uint channel,const volatile void * read_addr,bool trigger)399 static inline void dma_channel_set_read_addr(uint channel, const volatile void *read_addr, bool trigger) {
400     if (!trigger) {
401         dma_channel_hw_addr(channel)->read_addr = (uintptr_t) read_addr;
402     } else {
403         dma_channel_hw_addr(channel)->al3_read_addr_trig = (uintptr_t) read_addr;
404     }
405 }
406 
407 /*! \brief  Set the DMA initial write address
408  *  \ingroup hardware_dma
409  *
410  * \param channel DMA channel
411  * \param write_addr Initial write address of transfer.
412  * \param trigger True to start the transfer immediately
413  */
dma_channel_set_write_addr(uint channel,volatile void * write_addr,bool trigger)414 static inline void dma_channel_set_write_addr(uint channel, volatile void *write_addr, bool trigger) {
415     if (!trigger) {
416         dma_channel_hw_addr(channel)->write_addr = (uintptr_t) write_addr;
417     } else {
418         dma_channel_hw_addr(channel)->al2_write_addr_trig = (uintptr_t) write_addr;
419     }
420 }
421 
422 /*! \brief  Set the number of bus transfers the channel will do
423  *  \ingroup hardware_dma
424  *
425  * \param channel DMA channel
426  * \param trans_count The number of transfers (not NOT bytes, see channel_config_set_transfer_data_size)
427  * \param trigger True to start the transfer immediately
428  */
dma_channel_set_trans_count(uint channel,uint32_t trans_count,bool trigger)429 static inline void dma_channel_set_trans_count(uint channel, uint32_t trans_count, bool trigger) {
430     if (!trigger) {
431         dma_channel_hw_addr(channel)->transfer_count = trans_count;
432     } else {
433         dma_channel_hw_addr(channel)->al1_transfer_count_trig = trans_count;
434     }
435 }
436 
437 /*! \brief  Configure all DMA parameters and optionally start transfer
438  *  \ingroup hardware_dma
439  *
440  * \param channel DMA channel
441  * \param config Pointer to DMA config structure
442  * \param write_addr Initial write address
443  * \param read_addr Initial read address
444  * \param transfer_count Number of transfers to perform
445  * \param trigger True to start the transfer immediately
446  */
dma_channel_configure(uint channel,const dma_channel_config * config,volatile void * write_addr,const volatile void * read_addr,uint transfer_count,bool trigger)447 static inline void dma_channel_configure(uint channel, const dma_channel_config *config, volatile void *write_addr,
448                                          const volatile void *read_addr,
449                                          uint transfer_count, bool trigger) {
450     dma_channel_set_read_addr(channel, read_addr, false);
451     dma_channel_set_write_addr(channel, write_addr, false);
452     dma_channel_set_trans_count(channel, transfer_count, false);
453     dma_channel_set_config(channel, config, trigger);
454 }
455 
456 /*! \brief Start a DMA transfer from a buffer immediately
457  *  \ingroup hardware_dma
458  *
459  * \param channel DMA channel
460  * \param read_addr Sets the initial read address
461  * \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.
462  */
dma_channel_transfer_from_buffer_now(uint channel,const volatile void * read_addr,uint32_t transfer_count)463 inline static void __attribute__((always_inline)) dma_channel_transfer_from_buffer_now(uint channel,
464                                                                                        const volatile void *read_addr,
465                                                                                        uint32_t transfer_count) {
466 //    check_dma_channel_param(channel);
467     dma_channel_hw_t *hw = dma_channel_hw_addr(channel);
468     hw->read_addr = (uintptr_t) read_addr;
469     hw->al1_transfer_count_trig = transfer_count;
470 }
471 
472 /*! \brief Start a DMA transfer to a buffer immediately
473  *  \ingroup hardware_dma
474  *
475  * \param channel DMA channel
476  * \param write_addr Sets the initial write address
477  * \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.
478  */
dma_channel_transfer_to_buffer_now(uint channel,volatile void * write_addr,uint32_t transfer_count)479 inline static void dma_channel_transfer_to_buffer_now(uint channel, volatile void *write_addr, uint32_t transfer_count) {
480     dma_channel_hw_t *hw = dma_channel_hw_addr(channel);
481     hw->write_addr = (uintptr_t) write_addr;
482     hw->al1_transfer_count_trig = transfer_count;
483 }
484 
485 /*! \brief  Start one or more channels simultaneously
486  *  \ingroup hardware_dma
487  *
488  * \param chan_mask Bitmask of all the channels requiring starting. Channel 0 = bit 0, channel 1 = bit 1 etc.
489  */
dma_start_channel_mask(uint32_t chan_mask)490 static inline void dma_start_channel_mask(uint32_t chan_mask) {
491     valid_params_if(HARDWARE_DMA, chan_mask && chan_mask < (1u << NUM_DMA_CHANNELS));
492     dma_hw->multi_channel_trigger = chan_mask;
493 }
494 
495 /*! \brief  Start a single DMA channel
496  *  \ingroup hardware_dma
497  *
498  * \param channel DMA channel
499  */
dma_channel_start(uint channel)500 static inline void dma_channel_start(uint channel) {
501     dma_start_channel_mask(1u << channel);
502 }
503 
504 /*! \brief  Stop a DMA transfer
505  *  \ingroup hardware_dma
506  *
507  * Function will only return once the DMA has stopped.
508  *
509  * \if rp2040_specific
510  * RP2040 only: Note that due to errata RP2040-E13, aborting a channel which has transfers
511  * in-flight (i.e. an individual read has taken place but the corresponding write has not), the ABORT
512  * status bit will clear prematurely, and subsequently the in-flight
513  * transfers will trigger a completion interrupt once they complete.
514  *\endif
515  *
516  * The effect of this is that you \em may see a spurious completion interrupt
517  * on the channel as a result of calling this method.
518  *
519  * The calling code should be sure to ignore a completion IRQ as a result of this method. This may
520  * not require any additional work, as aborting a channel which may be about to complete, when you have a completion
521  * IRQ handler registered, is inherently race-prone, and so code is likely needed to disambiguate the two occurrences.
522  *
523  * If that is not the case, but you do have a channel completion IRQ handler registered, you can simply
524  * disable/re-enable the IRQ around the call to this method as shown by this code fragment (using DMA IRQ0).
525  *
526  * \code
527  *  // disable the channel on IRQ0
528  *  dma_channel_set_irq0_enabled(channel, false);
529  *  // abort the channel
530  *  dma_channel_abort(channel);
531  *  // clear the spurious IRQ (if there was one)
532  *  dma_channel_acknowledge_irq0(channel);
533  *  // re-enable the channel on IRQ0
534  *  dma_channel_set_irq0_enabled(channel, true);
535  *\endcode
536  *
537  * \if rp2350_specific
538  * RP2350 only: Due to errata RP12350-E5 (see the RP2350 datasheet for further detail), it is necessary to clear the enable bit of
539  * the aborted channel and any chained channels prior to the abort to prevent re-triggering.
540  * \endif
541  *
542  * \param channel DMA channel
543  */
dma_channel_abort(uint channel)544 static inline void dma_channel_abort(uint channel) {
545     check_dma_channel_param(channel);
546     dma_hw->abort = 1u << channel;
547     // Bit will go 0 once channel has reached safe state
548     // (i.e. any in-flight transfers have retired)
549     while (dma_hw->ch[channel].ctrl_trig & DMA_CH0_CTRL_TRIG_BUSY_BITS) tight_loop_contents();
550 }
551 
552 /*! \brief  Enable single DMA channel's interrupt via DMA_IRQ_0
553  *  \ingroup hardware_dma
554  *
555  * \param channel DMA channel
556  * \param enabled true to enable interrupt 0 on specified channel, false to disable.
557  */
dma_channel_set_irq0_enabled(uint channel,bool enabled)558 static inline void dma_channel_set_irq0_enabled(uint channel, bool enabled) {
559     check_dma_channel_param(channel);
560     check_hw_layout(dma_hw_t, inte0, DMA_INTE0_OFFSET);
561     if (enabled)
562         hw_set_bits(&dma_hw->inte0, 1u << channel);
563     else
564         hw_clear_bits(&dma_hw->inte0, 1u << channel);
565 }
566 
567 /*! \brief  Enable multiple DMA channels' interrupts via DMA_IRQ_0
568  *  \ingroup hardware_dma
569  *
570  * \param channel_mask Bitmask of all the channels to enable/disable. Channel 0 = bit 0, channel 1 = bit 1 etc.
571  * \param enabled true to enable all the interrupts specified in the mask, false to disable all the interrupts specified in the mask.
572  */
dma_set_irq0_channel_mask_enabled(uint32_t channel_mask,bool enabled)573 static inline void dma_set_irq0_channel_mask_enabled(uint32_t channel_mask, bool enabled) {
574     if (enabled) {
575         hw_set_bits(&dma_hw->inte0, channel_mask);
576     } else {
577         hw_clear_bits(&dma_hw->inte0, channel_mask);
578     }
579 }
580 
581 /*! \brief  Enable single DMA channel's interrupt via DMA_IRQ_1
582  *  \ingroup hardware_dma
583  *
584  * \param channel DMA channel
585  * \param enabled true to enable interrupt 1 on specified channel, false to disable.
586  */
dma_channel_set_irq1_enabled(uint channel,bool enabled)587 static inline void dma_channel_set_irq1_enabled(uint channel, bool enabled) {
588     check_dma_channel_param(channel);
589     check_hw_layout(dma_hw_t, inte1, DMA_INTE1_OFFSET);
590     if (enabled)
591         hw_set_bits(&dma_hw->inte1, 1u << channel);
592     else
593         hw_clear_bits(&dma_hw->inte1, 1u << channel);
594 }
595 
596 /*! \brief  Enable multiple DMA channels' interrupts via DMA_IRQ_1
597  *  \ingroup hardware_dma
598  *
599  * \param channel_mask Bitmask of all the channels to enable/disable. Channel 0 = bit 0, channel 1 = bit 1 etc.
600  * \param enabled true to enable all the interrupts specified in the mask, false to disable all the interrupts specified in the mask.
601  */
dma_set_irq1_channel_mask_enabled(uint32_t channel_mask,bool enabled)602 static inline void dma_set_irq1_channel_mask_enabled(uint32_t channel_mask, bool enabled) {
603     if (enabled) {
604         hw_set_bits(&dma_hw->inte1, channel_mask);
605     } else {
606         hw_clear_bits(&dma_hw->inte1, channel_mask);
607     }
608 }
609 
610 /*! \brief  Enable single DMA channel interrupt on either DMA_IRQ_0 or DMA_IRQ_1
611  *  \ingroup hardware_dma
612  *
613  * \param irq_index the IRQ index; either 0 or 1 for DMA_IRQ_0 or DMA_IRQ_1
614  * \param channel DMA channel
615  * \param enabled true to enable interrupt via irq_index for specified channel, false to disable.
616  */
dma_irqn_set_channel_enabled(uint irq_index,uint channel,bool enabled)617 static inline void dma_irqn_set_channel_enabled(uint irq_index, uint channel, bool enabled) {
618     invalid_params_if(HARDWARE_DMA, irq_index >= NUM_DMA_IRQS);
619 
620     if (enabled)
621         hw_set_bits(&dma_hw->irq_ctrl[irq_index].inte, 1u << channel);
622     else
623         hw_clear_bits(&dma_hw->irq_ctrl[irq_index].inte, 1u << channel);
624 }
625 
626 /*! \brief  Enable multiple DMA channels' interrupt via either DMA_IRQ_0 or DMA_IRQ_1
627  *  \ingroup hardware_dma
628  *
629  * \param irq_index the IRQ index; either 0 or 1 for DMA_IRQ_0 or DMA_IRQ_1
630  * \param channel_mask Bitmask of all the channels to enable/disable. Channel 0 = bit 0, channel 1 = bit 1 etc.
631  * \param enabled true to enable all the interrupts specified in the mask, false to disable all the interrupts specified in the mask.
632  */
dma_irqn_set_channel_mask_enabled(uint irq_index,uint32_t channel_mask,bool enabled)633 static inline void dma_irqn_set_channel_mask_enabled(uint irq_index, uint32_t channel_mask,  bool enabled) {
634     invalid_params_if(HARDWARE_DMA, irq_index >= NUM_DMA_IRQS);
635     if (enabled) {
636         hw_set_bits(&dma_hw->irq_ctrl[irq_index].inte, channel_mask);
637     } else {
638         hw_clear_bits(&dma_hw->irq_ctrl[irq_index].inte, channel_mask);
639     }
640 }
641 
642 /*! \brief  Determine if a particular channel is a cause of DMA_IRQ_0
643  *  \ingroup hardware_dma
644  *
645  * \param channel DMA channel
646  * \return true if the channel is a cause of DMA_IRQ_0, false otherwise
647  */
dma_channel_get_irq0_status(uint channel)648 static inline bool dma_channel_get_irq0_status(uint channel) {
649     check_dma_channel_param(channel);
650     return dma_hw->ints0 & (1u << channel);
651 }
652 
653 /*! \brief  Determine if a particular channel is a cause of DMA_IRQ_1
654  *  \ingroup hardware_dma
655  *
656  * \param channel DMA channel
657  * \return true if the channel is a cause of DMA_IRQ_1, false otherwise
658  */
dma_channel_get_irq1_status(uint channel)659 static inline bool dma_channel_get_irq1_status(uint channel) {
660     check_dma_channel_param(channel);
661     return dma_hw->ints1 & (1u << channel);
662 }
663 
664 /*! \brief  Determine if a particular channel is a cause of DMA_IRQ_N
665  *  \ingroup hardware_dma
666  *
667  * \param irq_index the IRQ index; either 0 or 1 for DMA_IRQ_0 or DMA_IRQ_1
668  * \param channel DMA channel
669  * \return true if the channel is a cause of the DMA_IRQ_N, false otherwise
670  */
dma_irqn_get_channel_status(uint irq_index,uint channel)671 static inline bool dma_irqn_get_channel_status(uint irq_index, uint channel) {
672     invalid_params_if(HARDWARE_DMA, irq_index >= NUM_DMA_IRQS);
673     check_dma_channel_param(channel);
674     return dma_hw->irq_ctrl[irq_index].ints & (1u << channel);
675 }
676 
677 /*! \brief  Acknowledge a channel IRQ, resetting it as the cause of DMA_IRQ_0
678  *  \ingroup hardware_dma
679  *
680  * \param channel DMA channel
681  */
dma_channel_acknowledge_irq0(uint channel)682 static inline void dma_channel_acknowledge_irq0(uint channel) {
683     check_dma_channel_param(channel);
684     dma_hw->ints0 = 1u << channel;
685 }
686 
687 /*! \brief  Acknowledge a channel IRQ, resetting it as the cause of DMA_IRQ_1
688  *  \ingroup hardware_dma
689  *
690  * \param channel DMA channel
691  */
dma_channel_acknowledge_irq1(uint channel)692 static inline void dma_channel_acknowledge_irq1(uint channel) {
693     check_dma_channel_param(channel);
694     dma_hw->ints1 = 1u << channel;
695 }
696 
697 /*! \brief  Acknowledge a channel IRQ, resetting it as the cause of DMA_IRQ_N
698  *  \ingroup hardware_dma
699  *
700  * \param irq_index the IRQ index; either 0 or 1 for DMA_IRQ_0 or DMA_IRQ_1
701  * \param channel DMA channel
702  */
dma_irqn_acknowledge_channel(uint irq_index,uint channel)703 static inline void dma_irqn_acknowledge_channel(uint irq_index, uint channel) {
704     invalid_params_if(HARDWARE_DMA, irq_index >= NUM_DMA_IRQS);
705     check_dma_channel_param(channel);
706     dma_hw->irq_ctrl[irq_index].ints = 1u << channel;
707 }
708 
709 /*! \brief  Check if DMA channel is busy
710  *  \ingroup hardware_dma
711  *
712  * \param channel DMA channel
713  * \return true if the channel is currently busy
714  */
dma_channel_is_busy(uint channel)715 inline static bool dma_channel_is_busy(uint channel) {
716     check_dma_channel_param(channel);
717     return dma_hw->ch[channel].al1_ctrl & DMA_CH0_CTRL_TRIG_BUSY_BITS;
718 }
719 
720 /*! \brief  Wait for a DMA channel transfer to complete
721  *  \ingroup hardware_dma
722  *
723  * \param channel DMA channel
724  */
dma_channel_wait_for_finish_blocking(uint channel)725 inline static void dma_channel_wait_for_finish_blocking(uint channel) {
726     while (dma_channel_is_busy(channel)) tight_loop_contents();
727     // stop the compiler hoisting a non-volatile buffer access above the DMA completion.
728     __compiler_memory_barrier();
729 }
730 
731 /*! \brief Enable the DMA sniffing targeting the specified channel
732  *  \ingroup hardware_dma
733  *
734  * The mode can be one of the following:
735  *
736  * Mode | Function
737  * -----|---------
738  * 0x0 | Calculate a CRC-32 (IEEE802.3 polynomial)
739  * 0x1 | Calculate a CRC-32 (IEEE802.3 polynomial) with bit reversed data
740  * 0x2 | Calculate a CRC-16-CCITT
741  * 0x3 | Calculate a CRC-16-CCITT with bit reversed data
742  * 0xe | XOR reduction over all data. == 1 if the total 1 population count is odd.
743  * 0xf | Calculate a simple 32-bit checksum (addition with a 32 bit accumulator)
744  *
745  * \param channel DMA channel
746  * \param mode See description
747  * \param force_channel_enable Set true to also turn on sniffing in the channel configuration (this
748  * is usually what you want, but sometimes you might have a chain DMA with only certain segments
749  * of the chain sniffed, in which case you might pass false).
750  */
dma_sniffer_enable(uint channel,uint mode,bool force_channel_enable)751 inline static void dma_sniffer_enable(uint channel, uint mode, bool force_channel_enable) {
752     check_dma_channel_param(channel);
753     check_hw_layout(dma_hw_t, sniff_ctrl, DMA_SNIFF_CTRL_OFFSET);
754     if (force_channel_enable) {
755         hw_set_bits(&dma_hw->ch[channel].al1_ctrl, DMA_CH0_CTRL_TRIG_SNIFF_EN_BITS);
756     }
757     hw_write_masked(&dma_hw->sniff_ctrl,
758         (((channel << DMA_SNIFF_CTRL_DMACH_LSB) & DMA_SNIFF_CTRL_DMACH_BITS) |
759          ((mode << DMA_SNIFF_CTRL_CALC_LSB) & DMA_SNIFF_CTRL_CALC_BITS) |
760          DMA_SNIFF_CTRL_EN_BITS),
761         (DMA_SNIFF_CTRL_DMACH_BITS |
762          DMA_SNIFF_CTRL_CALC_BITS |
763          DMA_SNIFF_CTRL_EN_BITS));
764 }
765 
766 /*! \brief Enable the Sniffer byte swap function
767  *  \ingroup hardware_dma
768  *
769  * Locally perform a byte reverse on the sniffed data, before feeding into checksum.
770  *
771  * Note that the sniff hardware is downstream of the DMA channel byteswap performed in the
772  * read master: if channel_config_set_bswap() and dma_sniffer_set_byte_swap_enabled() are both enabled,
773  * their effects cancel from the sniffer’s point of view.
774  *
775  * \param swap Set true to enable byte swapping
776  */
dma_sniffer_set_byte_swap_enabled(bool swap)777 inline static void dma_sniffer_set_byte_swap_enabled(bool swap) {
778     if (swap)
779         hw_set_bits(&dma_hw->sniff_ctrl, DMA_SNIFF_CTRL_BSWAP_BITS);
780     else
781         hw_clear_bits(&dma_hw->sniff_ctrl, DMA_SNIFF_CTRL_BSWAP_BITS);
782 }
783 
784 /*! \brief Enable the Sniffer output invert function
785  *  \ingroup hardware_dma
786  *
787  * If enabled, the sniff data result appears bit-inverted when read.
788  * This does not affect the way the checksum is calculated.
789  *
790  * \param invert Set true to enable output bit inversion
791  */
dma_sniffer_set_output_invert_enabled(bool invert)792 inline static void dma_sniffer_set_output_invert_enabled(bool invert) {
793     if (invert)
794         hw_set_bits(&dma_hw->sniff_ctrl, DMA_SNIFF_CTRL_OUT_INV_BITS);
795     else
796         hw_clear_bits(&dma_hw->sniff_ctrl, DMA_SNIFF_CTRL_OUT_INV_BITS);
797 }
798 
799 /*! \brief Enable the Sniffer output bit reversal function
800  *  \ingroup hardware_dma
801  *
802  * If enabled, the sniff data result appears bit-reversed when read.
803  * This does not affect the way the checksum is calculated.
804  *
805  * \param reverse Set true to enable output bit reversal
806  */
dma_sniffer_set_output_reverse_enabled(bool reverse)807 inline static void dma_sniffer_set_output_reverse_enabled(bool reverse) {
808     if (reverse)
809         hw_set_bits(&dma_hw->sniff_ctrl, DMA_SNIFF_CTRL_OUT_REV_BITS);
810     else
811         hw_clear_bits(&dma_hw->sniff_ctrl, DMA_SNIFF_CTRL_OUT_REV_BITS);
812 }
813 
814 /*! \brief Disable the DMA sniffer
815  *  \ingroup hardware_dma
816  *
817  */
dma_sniffer_disable(void)818 inline static void dma_sniffer_disable(void) {
819     dma_hw->sniff_ctrl = 0;
820 }
821 
822 /*! \brief Set the sniffer's data accumulator with initial value
823  *  \ingroup hardware_dma
824  *
825  * Generally, CRC algorithms are used with the data accumulator initially
826  * seeded with 0xFFFF or 0xFFFFFFFF (for crc16 and crc32 algorithms)
827  *
828  * \param seed_value value to set data accumulator
829  */
dma_sniffer_set_data_accumulator(uint32_t seed_value)830 inline static void dma_sniffer_set_data_accumulator(uint32_t seed_value) {
831     dma_hw->sniff_data = seed_value;
832 }
833 
834 /*! \brief Get the sniffer's data accumulator value
835  *  \ingroup hardware_dma
836  *
837  * Read value calculated by the hardware from sniffing the DMA stream
838  */
dma_sniffer_get_data_accumulator(void)839 inline static uint32_t dma_sniffer_get_data_accumulator(void) {
840     return dma_hw->sniff_data;
841 }
842 
843 /*! \brief Mark a dma timer as used
844  *  \ingroup hardware_dma
845  *
846  * Method for cooperative claiming of hardware. Will cause a panic if the timer
847  * is already claimed. Use of this method by libraries detects accidental
848  * configurations that would fail in unpredictable ways.
849  *
850  * \param timer the dma timer
851  */
852 void dma_timer_claim(uint timer);
853 
854 /*! \brief Mark a dma timer as no longer used
855  *  \ingroup hardware_dma
856  *
857  * Method for cooperative claiming of hardware.
858  *
859  * \param timer the dma timer to release
860  */
861 void dma_timer_unclaim(uint timer);
862 
863 /*! \brief Claim a free dma timer
864  *  \ingroup hardware_dma
865  *
866  * \param required if true the function will panic if none are available
867  * \return the dma timer number or -1 if required was false, and none were free
868  */
869 int dma_claim_unused_timer(bool required);
870 
871 /*! \brief Determine if a dma timer is claimed
872  *  \ingroup hardware_dma
873  *
874  * \param timer the dma timer
875  * \return true if the timer is claimed, false otherwise
876  * \see dma_timer_claim
877  */
878 bool dma_timer_is_claimed(uint timer);
879 
880 /*! \brief Set the multiplier for the given DMA timer
881  *  \ingroup hardware_dma
882  *
883  * The timer will run at the system_clock_freq * numerator / denominator, so this is the speed
884  * that data elements will be transferred at via a DMA channel using this timer as a DREQ. The
885  * multiplier must be less than or equal to one.
886  *
887  * \param timer the dma timer
888  * \param numerator the fraction's numerator
889  * \param denominator the fraction's denominator
890  */
dma_timer_set_fraction(uint timer,uint16_t numerator,uint16_t denominator)891 static inline void dma_timer_set_fraction(uint timer, uint16_t numerator, uint16_t denominator) {
892     check_dma_timer_param(timer);
893     invalid_params_if(HARDWARE_DMA, numerator > denominator);
894     dma_hw->timer[timer] = (((uint32_t)numerator) << DMA_TIMER0_X_LSB) | (((uint32_t)denominator) << DMA_TIMER0_Y_LSB);
895 }
896 
897 /*! \brief Return the DREQ number for a given DMA timer
898  *  \ingroup hardware_dma
899  *
900  * \param timer_num DMA timer number 0-3
901  */
dma_get_timer_dreq(uint timer_num)902 static inline uint dma_get_timer_dreq(uint timer_num) {
903     static_assert(DREQ_DMA_TIMER1 == DREQ_DMA_TIMER0 + 1, "");
904     static_assert(DREQ_DMA_TIMER2 == DREQ_DMA_TIMER0 + 2, "");
905     static_assert(DREQ_DMA_TIMER3 == DREQ_DMA_TIMER0 + 3, "");
906     check_dma_timer_param(timer_num);
907     return DREQ_DMA_TIMER0 + timer_num;
908 }
909 
910 /*! \brief Return DMA_IRQ_<irqn>
911  *  \ingroup hardware_dma
912  *
913  * \param irq_index 0 the DMA irq index
914  * \return The \ref irq_num_t to use for DMA
915  */
dma_get_irq_num(uint irq_index)916 static inline int dma_get_irq_num(uint irq_index) {
917     valid_params_if(HARDWARE_DMA, irq_index < NUM_DMA_IRQS);
918     return DMA_IRQ_NUM(irq_index);
919 }
920 
921 /*! \brief Performs DMA channel cleanup after use
922  *  \ingroup hardware_dma
923  *
924  * This can be used to cleanup dma channels when they're no longer needed, such that they are in a clean state for reuse.
925  * IRQ's for the channel are disabled, any in flight-transfer is aborted and any outstanding interrupts are cleared.
926  * The channel is then clear to be reused for other purposes.
927  *
928  * \code
929  * if (dma_channel >= 0) {
930  *     dma_channel_cleanup(dma_channel);
931  *     dma_channel_unclaim(dma_channel);
932  *     dma_channel = -1;
933  * }
934  * \endcode
935  *
936  * \param channel DMA channel
937  */
938 void dma_channel_cleanup(uint channel);
939 
940 #ifndef NDEBUG
941 void print_dma_ctrl(dma_channel_hw_t *channel);
942 #endif
943 
944 #ifdef __cplusplus
945 }
946 #endif
947 
948 #endif
949