/* libhw/rp2040_dma.h - Utilities for using DMA on the RP2040 (replaces ) * * Copyright (c) 2020 Raspberry Pi (Trading) Ltd. * SPDX-License-Identifier: BSD-3-Clause * * Copyright (C) 2025 Luke T. Shumaker * SPDX-License-Identifier: AGPL-3.0-or-later */ #ifndef _LIBHW_RP2040_DMA_H_ #define _LIBHW_RP2040_DMA_H_ #include #include /* for uint32_t */ #include /* for DREQ_* for use with DMA_CTRL_TREQ_SEL() */ #include /* for dma_hw, dma_channel_hw_t, DMA_NUM_CHANNELS */ #include /* for LM_FLOORLOG2() */ /* Borrowed from *********************************************/ static inline dma_channel_hw_t *dma_channel_hw_addr(uint channel) { assert(channel < NUM_DMA_CHANNELS); return &dma_hw->ch[channel]; } enum dma_channel_transfer_size { DMA_SIZE_8 = 0, ///< Byte transfer (8 bits) DMA_SIZE_16 = 1, ///< Half word transfer (16 bits) DMA_SIZE_32 = 2 ///< Word transfer (32 bits) }; static inline bool dma_channel_is_busy(uint channel) { assert(channel < NUM_DMA_CHANNELS); return dma_hw->ch[channel].al1_ctrl & DMA_CH0_CTRL_TRIG_BUSY_BITS; } /* Our own code ***************************************************************/ #define DMA_CTRL_ENABLE (1<<0) #define DMA_CTRL_HI_PRIO (1<<1) #define DMA_CTRL_DATA_SIZE(sz) ((sz)<<2) #define DMA_CTRL_INCR_READ (1<<4) #define DMA_CTRL_INCR_WRITE (1<<5) #define _DMA_CTRL_RING_BITS(b) ((b)<<6) #define _DMA_CTRL_RING_RD (0) #define _DMA_CTRL_RING_WR (1<<10) #define DMA_CTRL_RING(rdwr, bits) (_DMA_CTRL_RING_##rdwr | _DMA_CTRL_RING_BITS(bits)) #define DMA_CTRL_CHAIN_TO(ch) ((ch)<<11) #define DMA_CTRL_TREQ_SEL(dreq) ((dreq)<<15) #define DMA_CTRL_IRQ_QUIET (1<<21) #define DMA_CTRL_BSWAP (1<<22) #define DMA_CTRL_SNIFF_EN (1<<23) /* | elem | val | name */ #define READ_ADDR /*|*/volatile const void/*|*/ * /*|*/read_addr #define WRITE_ADDR /*|*/volatile void/*|*/ * /*|*/write_addr #define TRANS_COUNT /*|*/ /*|*/uint32_t/*|*/trans_count #define CTRL /*|*/ /*|*/uint32_t/*|*/ctrl /* { +0x0 ; +0x4 ; +0x8 ; +0xC (Trigger) */ struct dma_alias0 { READ_ADDR ; WRITE_ADDR ; TRANS_COUNT ; CTRL ; }; struct dma_alias1 { CTRL ; READ_ADDR ; WRITE_ADDR ; TRANS_COUNT ; }; struct dma_alias2 { CTRL ; TRANS_COUNT ; READ_ADDR ; WRITE_ADDR ; }; struct dma_alias3 { CTRL ; WRITE_ADDR ; TRANS_COUNT ; READ_ADDR ; }; struct dma_alias0_short2 { TRANS_COUNT ; CTRL ; }; struct dma_alias1_short2 { WRITE_ADDR ; TRANS_COUNT ; }; struct dma_alias2_short2 { READ_ADDR ; WRITE_ADDR ; }; struct dma_alias3_short2 { TRANS_COUNT ; READ_ADDR ; }; struct dma_alias0_short3 { CTRL ; }; struct dma_alias1_short3 { TRANS_COUNT ; }; struct dma_alias2_short3 { WRITE_ADDR ; }; struct dma_alias3_short3 { READ_ADDR ; }; #undef CTRL #undef TRANS_COUNT #undef WRITE_ADDR #undef READ_ADDR #define DMA_CHAN_ADDR(CH, TYP) ((TYP *volatile)_Generic((TYP){}, \ struct dma_alias0: &dma_channel_hw_addr(CH)->read_addr, \ struct dma_alias1: &dma_channel_hw_addr(CH)->al1_ctrl, \ struct dma_alias2: &dma_channel_hw_addr(CH)->al2_ctrl, \ struct dma_alias3: &dma_channel_hw_addr(CH)->al3_ctrl, \ struct dma_alias0_short2: &dma_channel_hw_addr(CH)->transfer_count, \ struct dma_alias1_short2: &dma_channel_hw_addr(CH)->al1_write_addr, \ struct dma_alias2_short2: &dma_channel_hw_addr(CH)->al2_read_addr, \ struct dma_alias3_short2: &dma_channel_hw_addr(CH)->al3_transfer_count, \ struct dma_alias0_short3: &dma_channel_hw_addr(CH)->ctrl_trig, \ struct dma_alias1_short3: &dma_channel_hw_addr(CH)->al1_transfer_count_trig, \ struct dma_alias2_short3: &dma_channel_hw_addr(CH)->al2_write_addr_trig, \ struct dma_alias3_short3: &dma_channel_hw_addr(CH)->al3_read_addr_trig)) #define DMA_CHAN_WR_TRANS_COUNT(TYP) \ (sizeof(TYP)/4) #define DMA_CHAN_WR_CTRL(TYP) ( DMA_CTRL_DATA_SIZE(DMA_SIZE_32) \ | DMA_CTRL_INCR_WRITE \ | DMA_CTRL_RING(WR, LM_FLOORLOG2(sizeof(TYP))) \ ) #define DMA_NONTRIGGER(CH, FIELD) (DMA_CHAN_ADDR(CH, _DMA_NONTRIGGER_##FIELD)->FIELD) #define _DMA_NONTRIGGER_read_addr struct dma_alias0 #define _DMA_NONTRIGGER_write_addr struct dma_alias0 #define _DMA_NONTRIGGER_trans_count struct dma_alias0 #define _DMA_NONTRIGGER_ctrl struct dma_alias1 #define DMA_TRIGGER(CH, FIELD) (DMA_CHAN_ADDR(CH, _DMA_TRIGGER_##FIELD)->FIELD) #define _DMA_TRIGGER_read_addr struct dma_alias3 #define _DMA_TRIGGER_write_addr struct dma_alias2 #define _DMA_TRIGGER_trans_count struct dma_alias1 #define _DMA_TRIGGER_ctrl struct dma_alias0 #endif /* _LIBHW_RP2040_DMA_H_ */