summaryrefslogtreecommitdiff
path: root/libhw_cr/rp2040_dma.h
diff options
context:
space:
mode:
Diffstat (limited to 'libhw_cr/rp2040_dma.h')
-rw-r--r--libhw_cr/rp2040_dma.h135
1 files changed, 71 insertions, 64 deletions
diff --git a/libhw_cr/rp2040_dma.h b/libhw_cr/rp2040_dma.h
index c7f5a8f..b382952 100644
--- a/libhw_cr/rp2040_dma.h
+++ b/libhw_cr/rp2040_dma.h
@@ -10,33 +10,20 @@
#ifndef _LIBHW_CR_RP2040_DMA_H_
#define _LIBHW_CR_RP2040_DMA_H_
-#include <assert.h>
#include <stddef.h> /* for offsetof() */
#include <stdint.h> /* for uint32_t */
#include <hardware/regs/dreq.h> /* for DREQ_* for use with DMA_CTRL_TREQ_SEL() */
-#include <hardware/structs/dma.h> /* for dma_hw, dma_channel_hw_t, DMA_NUM_CHANNELS */
+#include <hardware/structs/dma.h> /* for dma_hw, DMA_NUM_CHANNELS */
+#include <libmisc/assert.h>
#include <libmisc/macro.h> /* for LM_FLOORLOG2() */
-/* Borrowed from <hardware/dma.h> *********************************************/
-
-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)
-};
-
-/* Our own code ***************************************************************/
+/* IRQ ************************************************************************/
enum dmairq {
- DMAIRQ_0 = DMA_IRQ_0,
- DMAIRQ_1 = DMA_IRQ_1,
+ DMAIRQ_0 = 11,
+ DMAIRQ_1 = 12,
};
typedef void (*dmairq_handler_t)(void *arg, enum dmairq irq, uint channel);
@@ -46,61 +33,57 @@ typedef void (*dmairq_handler_t)(void *arg, enum dmairq irq, uint channel);
* has a NULL trigger (depending on the channel's configuration).
*
* Your handler does not need to acknowledge the IRQ; that will be
- * done for you after your handler is called.
+ * done for you before your handler is called.
*
* It is illegal to enable the same channel on more than one IRQ.
*/
void dmairq_set_and_enable_exclusive_handler(enum dmairq irq, uint channel, dmairq_handler_t fn, void *arg);
-#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 ; };
+/* Control blocks *************************************************************/
+
+/* types =================================================*/
+
+/* | elem | val | name */
+#define READ_ADDR /*|*/volatile const void/*|*/ * /*|*/read_addr
+#define WRITE_ADDR /*|*/volatile void/*|*/ * /*|*/write_addr
+#define XFER_COUNT /*|*/ /*|*/uint32_t/*|*/xfer_count
+#define CTRL /*|*/ /*|*/uint32_t/*|*/ctrl
+
+/* { +0x0 ; +0x4 ; +0x8 ; +0xC (Trigger) */
+struct dma_alias0 { READ_ADDR ; WRITE_ADDR ; XFER_COUNT ; CTRL ; };
+struct dma_alias1 { CTRL ; READ_ADDR ; WRITE_ADDR ; XFER_COUNT ; };
+struct dma_alias2 { CTRL ; XFER_COUNT ; READ_ADDR ; WRITE_ADDR ; };
+struct dma_alias3 { CTRL ; WRITE_ADDR ; XFER_COUNT ; READ_ADDR ; };
+struct dma_alias0_short2 { XFER_COUNT ; CTRL ; };
+struct dma_alias1_short2 { WRITE_ADDR ; XFER_COUNT ; };
+struct dma_alias2_short2 { READ_ADDR ; WRITE_ADDR ; };
+struct dma_alias3_short2 { XFER_COUNT ; READ_ADDR ; };
+struct dma_alias0_short3 { CTRL ; };
+struct dma_alias1_short3 { XFER_COUNT ; };
+struct dma_alias2_short3 { WRITE_ADDR ; };
+struct dma_alias3_short3 { READ_ADDR ; };
#undef CTRL
-#undef TRANS_COUNT
+#undef XFER_COUNT
#undef WRITE_ADDR
#undef READ_ADDR
+/* locations =============================================*/
+
+dma_channel_hw_t *dma_channel_hw_addr(uint channel);
+
#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, \
@@ -108,24 +91,48 @@ struct dma_alias3_short3 { READ_ADDR ; };
#define DMA_IS_TRIGGER(TYP, FIELD) (offsetof(TYP, FIELD) == 0xC)
-#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_xfer_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_xfer_count struct dma_alias1
#define _DMA_TRIGGER_ctrl struct dma_alias0
+/* block->ctrl register *******************************************************/
+
+enum dma_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) */
+};
+
+#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)
+
+/* Utilities to build control blocks that write to other control blocks *******/
+
+#define DMA_CHAN_WR_XFER_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))) \
+ )
+
#endif /* _LIBHW_CR_RP2040_DMA_H_ */