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