diff options
Diffstat (limited to 'libhw_cr/rp2040_dma.h')
-rw-r--r-- | libhw_cr/rp2040_dma.h | 135 |
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_ */ |