diff options
author | Gregory Nutt <gnutt@nuttx.org> | 2014-06-17 13:18:52 -0600 |
---|---|---|
committer | Gregory Nutt <gnutt@nuttx.org> | 2014-06-17 13:18:52 -0600 |
commit | 046597e8450f5f588d96307674a3ffd21d6ae779 (patch) | |
tree | 62292fba0238a0b47dbae3ec4487e053ac732372 | |
parent | 2d4eb806259e4c25892ee0a9f882654d49a5cec6 (diff) | |
download | nuttx-046597e8450f5f588d96307674a3ffd21d6ae779.tar.gz nuttx-046597e8450f5f588d96307674a3ffd21d6ae779.tar.bz2 nuttx-046597e8450f5f588d96307674a3ffd21d6ae779.zip |
SAMA5D4: More progress on XDMAC driver (still no complete); Also fixes some critical errors in the SAMA5D3 DMA definitions
-rw-r--r-- | apps/include/hex2bin.h | 2 | ||||
-rw-r--r-- | nuttx/arch/arm/src/sama5/chip/sam_xdmac.h | 51 | ||||
-rw-r--r-- | nuttx/arch/arm/src/sama5/sam_dmac.h | 200 | ||||
-rw-r--r-- | nuttx/arch/arm/src/sama5/sam_xdmac.c | 912 |
4 files changed, 584 insertions, 581 deletions
diff --git a/apps/include/hex2bin.h b/apps/include/hex2bin.h index 73512a3c3..366ee5479 100644 --- a/apps/include/hex2bin.h +++ b/apps/include/hex2bin.h @@ -116,7 +116,7 @@ enum hex2bin_swap_e { - HEX2BIN_NOSWAP = 0, /* No swap, stream is the correct byte order */ + HEX2BIN_NOSWAP = 0, /* No swap, stream is in the correct byte order */ HEX2BIN_SWAP16 = 1, /* Swap bytes in 16-bit values */ HEX2BIN_SWAP32 = 2 /* Swap bytes in 32-bit values */ }; diff --git a/nuttx/arch/arm/src/sama5/chip/sam_xdmac.h b/nuttx/arch/arm/src/sama5/chip/sam_xdmac.h index c56052577..fc699271b 100644 --- a/nuttx/arch/arm/src/sama5/chip/sam_xdmac.h +++ b/nuttx/arch/arm/src/sama5/chip/sam_xdmac.h @@ -272,6 +272,7 @@ */ #define XDMAC_CHAN(n) (1 << (n)) +#define XDMAC_CHAN_ALL (0x0000ffff) /* Channel Interrupt Enable Register, Channel Interrupt Disable Register, Channel * Interrupt Mask Register, and Channel Interrupt Status Register. @@ -285,6 +286,9 @@ #define XDMAC_CHINT_WBI (1 << 5) /* Bit 5: Write Bus Error Interrupt */ #define XDMAC_CHINT_ROI (1 << 6) /* Bit 6: Request Overflow Error Interrupt Disable Bit */ +#define XDMAC_CHINT_ERRORS (0x00000070) +#define XDMAC_CHINT_ALL (0x0000007f) + /* Channel Source Address Register (32-bit address) */ /* Channel Destination Address Register (32-bit address) */ /* Channel Next Descriptor Address Register (32-bit address) */ @@ -303,7 +307,9 @@ /* Channel Microblock Control Register */ -#define XDMACH_CUBC_UBLEN_MASK (0x00ffffff) /* Bits 0-23: Channel Microblock Length */ +#define XDMACH_CUBC_UBLEN_SHIFT (0) /* Bits 0-23: Channel Microblock Length */ +#define XDMACH_CUBC_UBLEN_MASK (0x00ffffff << XDMACH_CUBC_UBLEN_SHIFT) +#define XDMACH_CUBC_UBLEN_MAX (0x00ffffff) /* Channel Block Control Register */ @@ -314,6 +320,7 @@ #define XDMACH_CC_TYPE (1 << 0) /* Bit 0: Channel Transfer Type */ #define XDMACH_CC_MBSIZE_SHIFT (1) /* Bits 1-2: Channel Memory Burst Size */ #define XDMACH_CC_MBSIZE_MASK (3 << XDMACH_CC_MBSIZE_SHIFT) +# define XDMACH_CC_MBSIZE(n) ((uint32_t)(n) << XDMACH_CC_MBSIZE_SHIFT) /* n=0-3 */ # define XDMACH_CC_MBSIZE_1 (0 << XDMACH_CC_MBSIZE_SHIFT) /* The memory burst size is set to one */ # define XDMACH_CC_MBSIZE_4 (1 << XDMACH_CC_MBSIZE_SHIFT) /* The memory burst size is set to four */ # define XDMACH_CC_MBSIZE_8 (2 << XDMACH_CC_MBSIZE_SHIFT) /* The memory burst size is set to eight */ @@ -496,39 +503,39 @@ struct chnext_view0_s { - uint32_t nda; /* Next Descriptor Address */ - uint32_t ubc; /* Microblock Control */ - uint32_t ta; /* Transfer Address */ + uint32_t cnda; /* Next Descriptor Address */ + uint32_t cubc; /* Microblock Control */ + uint32_t cta; /* Transfer Address */ }; struct chnext_view1_s { - uint32_t nda; /* Next Descriptor Address */ - uint32_t ubc; /* Microblock Control */ - uint32_t sa; /* Source Address */ - uint32_t da; /* Destination Address */ + uint32_t cnda; /* Next Descriptor Address */ + uint32_t cubc; /* Microblock Control */ + uint32_t csa; /* Source Address */ + uint32_t cda; /* Destination Address */ }; struct chnext_view2_s { - uint32_t nda; /* Next Descriptor Address */ - uint32_t ubc; /* Microblock Control */ - uint32_t sa; /* Source Address */ - uint32_t da; /* Destination Address */ - uint32_t cfg; /* Configuration Register */ + uint32_t cnda; /* Next Descriptor Address */ + uint32_t cubc; /* Microblock Control */ + uint32_t csa; /* Source Address */ + uint32_t cda; /* Destination Address */ + uint32_t cc; /* Configuration Register */ }; struct chnext_view3_s { - uint32_t nda; /* Next Descriptor Address */ - uint32_t ubc; /* Microblock Control */ - uint32_t sa; /* Source Address */ - uint32_t da; /* Destination Address */ - uint32_t cfg; /* Configuration Register */ - uint32_t bc; /* Block Control */ - uint32_t ds; /* Data Stride */ - uint32_t sus; /* Source Microblock Stride */ - uint32_t dus; /* Destination Microblock Stride */ + uint32_t cnda; /* Next Descriptor Address */ + uint32_t cubc; /* Microblock Control */ + uint32_t csa; /* Source Address */ + uint32_t cda; /* Destination Address */ + uint32_t cc; /* Configuration Register */ + uint32_t cbc; /* Block Control */ + uint32_t cds; /* Data Stride */ + uint32_t csus; /* Source Microblock Stride */ + uint32_t cdus; /* Destination Microblock Stride */ }; #endif /* __ARCH_ARM_SRC_SAMA5_CHIP_SAM_XDMAC_H */ diff --git a/nuttx/arch/arm/src/sama5/sam_dmac.h b/nuttx/arch/arm/src/sama5/sam_dmac.h index 80910d27f..f90988350 100644 --- a/nuttx/arch/arm/src/sama5/sam_dmac.h +++ b/nuttx/arch/arm/src/sama5/sam_dmac.h @@ -64,9 +64,17 @@ * awkward) */ -/* Configurable properties of the channel */ - #if defined(ATSAMA5D3) +/* MMMM MMMM MMMM MMMP PPPP PPPP PPPP PPFF + * .... .... .... .... .... .... .... ..FF Configurable properties of the channel + * .... .... .... ...P PPPP PPPP PPPP PP.. Peripheral endpoint characteristics + * MMMM MMMM MMMM MMM. .... .... .... .... Memory endpoint characteristics + */ + +/* Bits 0-1: Configurable properties of the channel + * + * .... .... .... .... .... .... .... ..FF Configurable properties of the channel + */ # define DMACH_FLAG_BURST_LARGEST 0 /* Largest length AHB burst */ # define DMACH_FLAG_BURST_HALF 1 /* Half FIFO size */ @@ -78,35 +86,58 @@ # define DMACH_FLAG_FIFOCFG_HALF (DMACH_FLAG_BURST_HALF << DMACH_FLAG_FIFOCFG_SHIFT) # define DMACH_FLAG_FIFOCFG_SINGLE (DMACH_FLAG_BURST_SINGLE << DMACH_FLAG_FIFOCFG_SHIFT) -/* Peripheral endpoint characteristics */ +/* Bits 2-16: Peripheral endpoint characteristics + * + * .... .... .... ...P PPPP PPPP PPPP PP.. Peripheral endpoint characteristics + * .... .... .... .... .... .... IIII II.. Peripheral ID, range 0-49 + * .... .... .... .... .... ...H .... .... HW Handshaking + * .... .... .... .... .... ..P. .... .... 0=memory; 1=peripheral + * .... .... .... .... .... NN.. .... .... Peripheral ABH layer number + * .... .... .... .... ..WW .... .... .... Peripheral width + * .... .... .... .... .A.. .... .... .... Auto-increment peripheral address + * .... .... .... ...S S... .... .... .... Peripheral chunk size + */ -# define DMACH_FLAG_PERIPHPID_SHIFT (2) /* Bits 0-6: Peripheral PID */ -# define DMACH_FLAG_PERIPHPID_MASK (0x7f << DMACH_FLAG_PERIPHPID_SHIFT) -# define DMACH_FLAG_PERIPHH2SEL (1 << 7) /* Bits 7: HW handshaking */ -# define DMACH_FLAG_PERIPHISPERIPH (1 << 8) /* Bits 8: 0=memory; 1=peripheral */ -# define DMACH_FLAG_PERIPHAHB_SHIFT (9) /* Bits 9-10: Peripheral ABH layer number */ +# define DMACH_FLAG_PERIPHPID_SHIFT (2) /* Bits 1-7: Peripheral PID */ +# define DMACH_FLAG_PERIPHPID_MASK (0x3f << DMACH_FLAG_PERIPHPID_SHIFT) +# define DMACH_FLAG_PERIPHPID(n) ((uint32_t) << DMACH_FLAG_PERIPHPID_SHIFT) +# define DMACH_FLAG_PERIPHH2SEL (1 << 8) /* Bits 8: HW handshaking */ +# define DMACH_FLAG_PERIPHISPERIPH (1 << 9) /* Bits 9: 0=memory; 1=peripheral */ +# define DMACH_FLAG_PERIPHAHB_SHIFT (10) /* Bits 10-11: Peripheral ABH layer number */ # define DMACH_FLAG_PERIPHAHB_MASK (3 << DMACH_FLAG_PERIPHAHB_SHIFT) # define DMACH_FLAG_PERIPHAHB_AHB_IF0 (0 << DMACH_FLAG_PERIPHAHB_SHIFT) /* AHB-Lite Interface 0 */ # define DMACH_FLAG_PERIPHAHB_AHB_IF1 (1 << DMACH_FLAG_PERIPHAHB_SHIFT) /* AHB-Lite Interface 1 */ # define DMACH_FLAG_PERIPHAHB_AHB_IF2 (2 << DMACH_FLAG_PERIPHAHB_SHIFT) /* AHB-Lite Interface 2 */ -# define DMACH_FLAG_PERIPHWIDTH_SHIFT (11) /* Bits 11-12: Peripheral width */ +# define DMACH_FLAG_PERIPHWIDTH_SHIFT (12) /* Bits 12-13: Peripheral width */ # define DMACH_FLAG_PERIPHWIDTH_MASK (3 << DMACH_FLAG_PERIPHWIDTH_SHIFT) # define DMACH_FLAG_PERIPHWIDTH_8BITS (0 << DMACH_FLAG_PERIPHWIDTH_SHIFT) /* 8 bits */ # define DMACH_FLAG_PERIPHWIDTH_16BITS (1 << DMACH_FLAG_PERIPHWIDTH_SHIFT) /* 16 bits */ # define DMACH_FLAG_PERIPHWIDTH_32BITS (2 << DMACH_FLAG_PERIPHWIDTH_SHIFT) /* 32 bits */ # define DMACH_FLAG_PERIPHWIDTH_64BITS (3 << DMACH_FLAG_PERIPHWIDTH_SHIFT) /* 64 bits */ -# define DMACH_FLAG_PERIPHINCREMENT (1 << 13) /* Bit 13: Autoincrement peripheral address */ -# define DMACH_FLAG_PERIPHCHUNKSIZE_SHIFT (14) /* Bits 14-15: Peripheral chunk size */ +# define DMACH_FLAG_PERIPHINCREMENT (1 << 14) /* Bit 14: Auto-increment peripheral address */ +# define DMACH_FLAG_PERIPHCHUNKSIZE_SHIFT (15) /* Bits 15-16: Peripheral chunk size */ # define DMACH_FLAG_PERIPHCHUNKSIZE_MASK (3 << DMACH_FLAG_PERIPHCHUNKSIZE_SHIFT) -# define DMACH_FLAG_PERIPHCHUNKSIZE_1 (0 << DMACH_FLAG_PERIPHCHUNKSIZE_SHIFT) /* Peripheral chunksize=1 */ -# define DMACH_FLAG_PERIPHCHUNKSIZE_4 (1 << DMACH_FLAG_PERIPHCHUNKSIZE_SHIFT) /* Peripheral chunksize=4 */ -# define DMACH_FLAG_PERIPHCHUNKSIZE_8 (3 << DMACH_FLAG_PERIPHCHUNKSIZE_SHIFT) /* Peripheral chunksize=8 */ -# define DMACH_FLAG_PERIPHCHUNKSIZE_16 (4 << DMACH_FLAG_PERIPHCHUNKSIZE_SHIFT) /* Peripheral chunksize=16 */ +# define DMACH_FLAG_PERIPHCHUNKSIZE_1 (0 << DMACH_FLAG_PERIPHCHUNKSIZE_SHIFT) /* Peripheral chunksize = 1 */ +# define DMACH_FLAG_PERIPHCHUNKSIZE_2 (0 << DMACH_FLAG_PERIPHCHUNKSIZE_SHIFT) /* No chunksize = 2 */ +# define DMACH_FLAG_PERIPHCHUNKSIZE_4 (1 << DMACH_FLAG_PERIPHCHUNKSIZE_SHIFT) /* Peripheral chunksize = 4 */ +# define DMACH_FLAG_PERIPHCHUNKSIZE_8 (2 << DMACH_FLAG_PERIPHCHUNKSIZE_SHIFT) /* Peripheral chunksize = 8 */ +# define DMACH_FLAG_PERIPHCHUNKSIZE_16 (3 << DMACH_FLAG_PERIPHCHUNKSIZE_SHIFT) /* Peripheral chunksize = 16 */ -/* Memory endpoint characteristics */ +/* Bits 17-31: Memory endpoint characteristics + * + * MMMM MMMM MMMM MMM. .... .... .... .... Memory endpoint characteristics + * .... .... .III III. .... .... .... .... Memory/peripheral ID, range 0-49 + * .... .... H... .... .... .... .... .... HW Handshaking + * .... ...P .... .... .... .... .... .... 0=memory; 1=peripheral + * .... .NN. .... .... .... .... .... .... Peripheral ABH layer number + * ...W W... .... .... .... .... .... .... Peripheral width + * ..A. .... .... .... .... .... .... .... Auto-increment peripheral address + * SS.. .... .... .... .... .... .... .... Peripheral chunk size + */ -# define DMACH_FLAG_MEMPID_SHIFT (16) /* Bits 16-22: Memory PID */ -# define DMACH_FLAG_MEMPID_MASK (0x75 << DMACH_FLAG_MEMPID_SHIFT) +# define DMACH_FLAG_MEMPID_SHIFT (17) /* Bits 17-22: Memory PID */ +# define DMACH_FLAG_MEMPID_MASK (0x3f << DMACH_FLAG_MEMPID_SHIFT) +# define DMACH_FLAG_MEMPID(n) ((uint32_t)(n) << DMACH_FLAG_MEMPID_SHIFT) # define DMACH_FLAG_MEMH2SEL (1 << 23) /* Bits 23: HW handshaking */ # define DMACH_FLAG_MEMISPERIPH (1 << 24) /* Bits 24: 0=memory; 1=peripheral */ # define DMACH_FLAG_MEMAHB_SHIFT (25) /* Bits 25-26: Peripheral ABH layer number */ @@ -120,69 +151,114 @@ # define DMACH_FLAG_MEMWIDTH_16BITS (1 << DMACH_FLAG_MEMWIDTH_SHIFT) /* 16 bits */ # define DMACH_FLAG_MEMWIDTH_32BITS (2 << DMACH_FLAG_MEMWIDTH_SHIFT) /* 32 bits */ # define DMACH_FLAG_MEMWIDTH_64BITS (3 << DMACH_FLAG_MEMWIDTH_SHIFT) /* 64 bits */ -# define DMACH_FLAG_MEMINCREMENT (1 << 29) /* Bit 29: Autoincrement memory address */ +# define DMACH_FLAG_MEMINCREMENT (1 << 29) /* Bit 29: Auto-increment memory address */ # define DMACH_FLAG_MEMCHUNKSIZE_SHIFT (30) /* Bit 30-31: Memory chunk size */ # define DMACH_FLAG_MEMCHUNKSIZE_MASK (3 << DMACH_FLAG_MEMCHUNKSIZE_SHIFT) # define DMACH_FLAG_MEMCHUNKSIZE_1 (0 << DMACH_FLAG_MEMCHUNKSIZE_SHIFT) /* Peripheral chunksize = 1 */ +# define DMACH_FLAG_MEMCHUNKSIZE_2 (0 << DMACH_FLAG_MEMCHUNKSIZE_SHIFT) /* No chunksize = 2 */ # define DMACH_FLAG_MEMCHUNKSIZE_4 (1 << DMACH_FLAG_MEMCHUNKSIZE_SHIFT) /* Peripheral chunksize = 4 */ -# define DMACH_FLAG_MEMCHUNKSIZE_8 (3 << DMACH_FLAG_MEMCHUNKSIZE_SHIFT) /* Peripheral chunksize = 8 */ -# define DMACH_FLAG_MEMCHUNKSIZE_16 (4 << DMACH_FLAG_MEMCHUNKSIZE_SHIFT) /* Peripheral chunksize = 16 */ +# define DMACH_FLAG_MEMCHUNKSIZE_8 (2 << DMACH_FLAG_MEMCHUNKSIZE_SHIFT) /* Peripheral chunksize = 8 */ +# define DMACH_FLAG_MEMCHUNKSIZE_16 (3 << DMACH_FLAG_MEMCHUNKSIZE_SHIFT) /* Peripheral chunksize = 16 */ + +# define DMACH_FLAG_MEMBURST_1 (0) /* No memory burst size */ +# define DMACH_FLAG_MEMBURST_4 (0) +# define DMACH_FLAG_MEMBURST_8 (0) +# define DMACH_FLAG_MEMBURST_16 (0) #elif defined(ATSAMA5D4) +/* .... .... .... MMMM .PPP PPPP PPPP PPPP + * .... .... .... .... .... .... .... .... Configurable properties of the channel + * .... .... .... .... .PPP PPPP PPPP PPPP Peripheral endpoint characteristics + * .... .... .... MMMM .... .... .... .... Memory endpoint characteristics + */ -# define DMACH_FLAG_FIFOCFG_LARGEST (0) /* Not used */ -# define DMACH_FLAG_FIFOCFG_HALF (0) /* Not used */ -# define DMACH_FLAG_FIFOCFG_SINGLE (0) /* Not used */ +/* Bits 0-1: Configurable properties of the channel + * + * .... .... .... .... .... .... .... .... Configurable properties of the channel + * + * NOTE: Many "peripheral" attributes are really "channel" attributes for + * the SAMA5D4's XDMAC since it does not support peripheral-to-peripheral + * DMA. + */ -/* Peripheral endpoint characteristics */ +# define DMACH_FLAG_FIFOCFG_LARGEST (0) /* No FIFO controls */ +# define DMACH_FLAG_FIFOCFG_HALF (0) +# define DMACH_FLAG_FIFOCFG_SINGLE (0) -# define DMACH_FLAG_PERIPHPID_SHIFT (2) /* Bits 2-7: Peripheral PID */ -# define DMACH_FLAG_PERIPHPID_MASK (63 << DMACH_FLAG_PERIPHPID_SHIFT) -# define DMACH_FLAG_PERIPHH2SEL (1 << 8) /* Bits 8: HW handshaking */ -# define DMACH_FLAG_PERIPHISPERIPH (1 << 9) /* Bits 9: 0=memory; 1=peripheral */ -# define DMACH_FLAG_PERIPHAHB_SHIFT (10) /* Bits 10-11: Peripheral ABH layer number */ -# define DMACH_FLAG_PERIPHAHB_MASK (3 << DMACH_FLAG_PERIPHAHB_SHIFT) -# define DMACH_FLAG_PERIPHAHB_AHB_IF0 (0 << DMACH_FLAG_PERIPHAHB_SHIFT) /* AHB-Lite Interface 0 */ -# define DMACH_FLAG_PERIPHAHB_AHB_IF1 (1 << DMACH_FLAG_PERIPHAHB_SHIFT) /* AHB-Lite Interface 1 */ -# define DMACH_FLAG_PERIPHAHB_AHB_IF2 (2 << DMACH_FLAG_PERIPHAHB_SHIFT) /* AHB-Lite Interface 2 */ -# define DMACH_FLAG_PERIPHWIDTH_SHIFT (12) /* Bits 12-13: Peripheral width */ +/* Bits 0-15: Peripheral endpoint characteristics + * + * .... .... .... .... .PPP PPPP PPPP PPPP Peripheral endpoint characteristics + * .... .... .... .... .... .... .III IIII Peripheral ID, range 0-67 + * .... .... .... .... .... .... .... .... No HW Handshaking + * .... .... .... .... .... .... P... .... 0=memory; 1=peripheral + * .... .... .... .... .... ...N .... .... Peripheral ABH layer number + * .... .... .... .... .... .WW. .... .... Peripheral width + * .... .... .... .... .... A... .... .... Auto-increment peripheral address + * .... .... .... .... .SSS .... .... .... Peripheral chunk size + */ + +# define DMACH_FLAG_PERIPHPID_SHIFT (0) /* Bits 0-7: Peripheral PID */ +# define DMACH_FLAG_PERIPHPID_MASK (0x7f << DMACH_FLAG_PERIPHPID_SHIFT) +# define DMACH_FLAG_PERIPHPID(n) ((uint32_t) << DMACH_FLAG_PERIPHPID_SHIFT) +# define DMACH_FLAG_PERIPHH2SEL (0) /* No HW handshaking */ +# define DMACH_FLAG_PERIPHISPERIPH (1 << 7) /* Bit 7: 0=memory; 1=peripheral */ +# define DMACH_FLAG_PERIPHAHB_MASK (1 << 8) /* Bit 8: Peripheral ABH layer 1 */ +# define DMACH_FLAG_PERIPHAHB_AHB_IF0 (0) +# define DMACH_FLAG_PERIPHAHB_AHB_IF1 DMACH_FLAG_PERIPHAHB_MASK +# define DMACH_FLAG_PERIPHWIDTH_SHIFT (9) /* Bits 9-10: Peripheral width */ # define DMACH_FLAG_PERIPHWIDTH_MASK (3 << DMACH_FLAG_PERIPHWIDTH_SHIFT) # define DMACH_FLAG_PERIPHWIDTH_8BITS (0 << DMACH_FLAG_PERIPHWIDTH_SHIFT) /* 8 bits */ # define DMACH_FLAG_PERIPHWIDTH_16BITS (1 << DMACH_FLAG_PERIPHWIDTH_SHIFT) /* 16 bits */ # define DMACH_FLAG_PERIPHWIDTH_32BITS (2 << DMACH_FLAG_PERIPHWIDTH_SHIFT) /* 32 bits */ # define DMACH_FLAG_PERIPHWIDTH_64BITS (3 << DMACH_FLAG_PERIPHWIDTH_SHIFT) /* 64 bits */ -# define DMACH_FLAG_PERIPHINCREMENT (1 << 14) /* Bit 14: Autoincrement peripheral address */ -# define DMACH_FLAG_PERIPHCHUNKSIZE_SHIFT (15) /* Bits 15-16: Peripheral chunk size */ -# define DMACH_FLAG_PERIPHCHUNKSIZE_MASK (3 << DMACH_FLAG_PERIPHCHUNKSIZE_SHIFT) +# define DMACH_FLAG_PERIPHINCREMENT (1 << 11) /* Bit 11: Auto-increment peripheral address */ +# define DMACH_FLAG_PERIPHCHUNKSIZE_SHIFT (12) /* Bits 12-14: Peripheral chunk size */ +# define DMACH_FLAG_PERIPHCHUNKSIZE_MASK (7 << DMACH_FLAG_PERIPHCHUNKSIZE_SHIFT) # define DMACH_FLAG_PERIPHCHUNKSIZE_1 (0 << DMACH_FLAG_PERIPHCHUNKSIZE_SHIFT) /* Peripheral chunksize=1 */ -# define DMACH_FLAG_PERIPHCHUNKSIZE_4 (1 << DMACH_FLAG_PERIPHCHUNKSIZE_SHIFT) /* Peripheral chunksize=4 */ +# define DMACH_FLAG_PERIPHCHUNKSIZE_2 (1 << DMACH_FLAG_PERIPHCHUNKSIZE_SHIFT) /* No chunksize=2 */ +# define DMACH_FLAG_PERIPHCHUNKSIZE_4 (2 << DMACH_FLAG_PERIPHCHUNKSIZE_SHIFT) /* Peripheral chunksize=4 */ # define DMACH_FLAG_PERIPHCHUNKSIZE_8 (3 << DMACH_FLAG_PERIPHCHUNKSIZE_SHIFT) /* Peripheral chunksize=8 */ # define DMACH_FLAG_PERIPHCHUNKSIZE_16 (4 << DMACH_FLAG_PERIPHCHUNKSIZE_SHIFT) /* Peripheral chunksize=16 */ -/* Memory endpoint characteristics */ +/* Bits 16-19: Memory endpoint characteristics + * + * .... .... .... MMMM .... .... .... .... Memory endpoint characteristics + * .... .... .... .... .... .... .... .... No memory peripheral ID, range 0-49 + * .... .... .... .... .... .... .... .... No HW Handshaking + * .... .... .... .... .... .... .... .... No peripheral-to-peripheral + * .... .... .... ...N .... .... .... .... Memory ABH layer number + * .... .... .... .... .... .... .... .... No memory width + * .... .... .... ..A. .... .... .... .... Auto-increment memory address + * .... .... .... .... .... .... .... .... No memory chunk size + * .... .... .... BB.. .... .... .... .... Memory burst size + */ -# define DMACH_FLAG_MEMPID_SHIFT (17) /* Bits 17-22: Memory PID */ -# define DMACH_FLAG_MEMPID_MASK (63 << DMACH_FLAG_MEMPID_SHIFT) -# define DMACH_FLAG_MEMH2SEL (1 << 23) /* Bits 23: HW handshaking */ -# define DMACH_FLAG_MEMISPERIPH (1 << 24) /* Bits 24: 0=memory; 1=peripheral */ -# define DMACH_FLAG_MEMAHB_SHIFT (25) /* Bits 25-26: Peripheral ABH layer number */ -# define DMACH_FLAG_MEMAHB_MASK (3 << DMACH_FLAG_MEMAHB_SHIFT) -# define DMACH_FLAG_MEMAHB_AHB_IF0 (0 << DMACH_FLAG_MEMAHB_SHIFT) /* AHB-Lite Interface 0 */ -# define DMACH_FLAG_MEMAHB_AHB_IF1 (1 << DMACH_FLAG_MEMAHB_SHIFT) /* AHB-Lite Interface 1 */ -# define DMACH_FLAG_MEMAHB_AHB_IF2 (2 << DMACH_FLAG_MEMAHB_SHIFT) /* AHB-Lite Interface 2 */ -# define DMACH_FLAG_MEMWIDTH_SHIFT (27) /* Bits 27-28: Memory width */ -# define DMACH_FLAG_MEMWIDTH_MASK (3 << DMACH_FLAG_MEMWIDTH_SHIFT) -# define DMACH_FLAG_MEMWIDTH_8BITS (0 << DMACH_FLAG_MEMWIDTH_SHIFT) /* 8 bits */ -# define DMACH_FLAG_MEMWIDTH_16BITS (1 << DMACH_FLAG_MEMWIDTH_SHIFT) /* 16 bits */ -# define DMACH_FLAG_MEMWIDTH_32BITS (2 << DMACH_FLAG_MEMWIDTH_SHIFT) /* 32 bits */ -# define DMACH_FLAG_MEMWIDTH_64BITS (3 << DMACH_FLAG_MEMWIDTH_SHIFT) /* 64 bits */ -# define DMACH_FLAG_MEMINCREMENT (1 << 29) /* Bit 29: Autoincrement memory address */ -# define DMACH_FLAG_MEMCHUNKSIZE_SHIFT (30) /* Bit 30-31: Memory chunk size */ -# define DMACH_FLAG_MEMCHUNKSIZE_MASK (3 << DMACH_FLAG_MEMCHUNKSIZE_SHIFT) -# define DMACH_FLAG_MEMCHUNKSIZE_1 (0 << DMACH_FLAG_MEMCHUNKSIZE_SHIFT) /* Peripheral chunksize = 1 */ -# define DMACH_FLAG_MEMCHUNKSIZE_4 (1 << DMACH_FLAG_MEMCHUNKSIZE_SHIFT) /* Peripheral chunksize = 4 */ -# define DMACH_FLAG_MEMCHUNKSIZE_8 (3 << DMACH_FLAG_MEMCHUNKSIZE_SHIFT) /* Peripheral chunksize = 8 */ -# define DMACH_FLAG_MEMCHUNKSIZE_16 (4 << DMACH_FLAG_MEMCHUNKSIZE_SHIFT) /* Peripheral chunksize = 16 */ +# define DMACH_FLAG_MEMPID(n) (0) /* No memory peripheral identifier */ +# define DMACH_FLAG_MEMH2SEL (0) /* No HW handshaking */ +# define DMACH_FLAG_MEMISPERIPH (0) /* No peripheral-to-peripheral */ +# define DMACH_FLAG_MEMAHB_MASK (1 << 16) /* Bit 16: Memory ABH layer 1 */ +# define DMACH_FLAG_MEMAHB_AHB_IF0 (0) +# define DMACH_FLAG_MEMAHB_AHB_IF1 DMACH_FLAG_MEMAHB_MASK + +# define DMACH_FLAG_MEMWIDTH_8BITS (0) /* Only peripheral data width */ +# define DMACH_FLAG_MEMWIDTH_16BITS (0) +# define DMACH_FLAG_MEMWIDTH_32BITS (0) +# define DMACH_FLAG_MEMWIDTH_64BITS (0) + +# define DMACH_FLAG_MEMINCREMENT (1 << 17) /* Bit 17: Auto-increment memory address */ + +# define DMACH_FLAG_MEMCHUNKSIZE_1 (0) /* Only peripheral chunk size */ +# define DMACH_FLAG_MEMCHUNKSIZE_2 (0) +# define DMACH_FLAG_MEMCHUNKSIZE_4 (0) +# define DMACH_FLAG_MEMCHUNKSIZE_8 (0) +# define DMACH_FLAG_MEMCHUNKSIZE_16 (0) + +# define DMACH_FLAG_MEMBURST_SHIFT (18) /* Bits 18-19: Memory burst size */ +# define DMACH_FLAG_MEMBURST_MASK (3 << DMACH_FLAG_MEMBURST_SHIFT) +# define DMACH_FLAG_MEMBURST_1 (0 << DMACH_FLAG_MEMBURST_SHIFT) +# define DMACH_FLAG_MEMBURST_4 (1 << DMACH_FLAG_MEMBURST_SHIFT) +# define DMACH_FLAG_MEMBURST_8 (2 << DMACH_FLAG_MEMBURST_SHIFT) +# define DMACH_FLAG_MEMBURST_16 (3 << DMACH_FLAG_MEMBURST_SHIFT) #endif /* ATSAMA5D4 */ diff --git a/nuttx/arch/arm/src/sama5/sam_xdmac.c b/nuttx/arch/arm/src/sama5/sam_xdmac.c index fd0118cb8..f39fb57b5 100644 --- a/nuttx/arch/arm/src/sama5/sam_xdmac.c +++ b/nuttx/arch/arm/src/sama5/sam_xdmac.c @@ -106,8 +106,8 @@ /* Register values **********************************************************/ -#define XDMAC_CH_CTRLB_BOTHDSCR \ - (XDMAC_CH_CTRLB_SRCDSCR | XDMAC_CH_CTRLB_DSTDSCR) +#define XDMAC_CH_CC_BOTHDSCR \ + (XDMAC_CH_CC_SRCDSCR | XDMAC_CH_CC_DSTDSCR) /**************************************************************************** * Private Types @@ -164,7 +164,7 @@ struct sam_xdmac_s * Private Data ****************************************************************************/ -/* CTRLA field lookups */ +/* Channel Control (CC) Register field lookups */ static const uint32_t g_chanwidth[4] = { @@ -174,13 +174,6 @@ static const uint32_t g_chanwidth[4] = XDMACH_CC_DWIDTH_DWORD }; -static const uint32_t g_fifocfg[3] = -{ - XDMAC_CH_CFG_FIFOCFG_ALAP, - XDMAC_CH_CFG_FIFOCFG_HALF, - XDMAC_CH_CFG_FIFOCFG_ASAP -}; - /* These tables map peripheral IDs to channels. A lookup is performed * before each DMA transfer in order to map the peripheral IDs to the * correct channel. This must be done because the channel can change with @@ -825,20 +818,11 @@ static uint8_t sam_channel(uint8_t pid, const struct sam_pidmap_s *table, return 0x3f; } -static uint32_t sam_source_channel(struct sam_xdmach_s *xdmach, uint8_t pid, - bool isperiph) +static uint32_t sam_source_channel(struct sam_xdmach_s *xdmach, uint8_t pid) { const struct sam_pidmap_s *table; unsigned int nentries; - if (!isperiph) - { - /* The source is memory, not a peripheral. */ - - return 0x3f; - } - else - #ifdef CONFIG_SAMA5_XDMAC0 #ifdef CONFIG_SAMA5_XDMAC1 if (xdmach->xdmac == 0) @@ -866,20 +850,11 @@ static uint32_t sam_source_channel(struct sam_xdmach_s *xdmach, uint8_t pid, return (uint32_t)sam_channel(pid, table, nentries); } -static uint32_t sam_sink_channel(struct sam_xdmach_s *xdmach, uint8_t pid, - bool isperiph) +static uint32_t sam_sink_channel(struct sam_xdmach_s *xdmach, uint8_t pid) { const struct sam_pidmap_s *table; unsigned int nentries; - if (!isperiph) - { - /* The source is memory, not a peripheral. */ - - return 0x3f; - } - else - #ifdef CONFIG_SAMA5_XDMAC0 #ifdef CONFIG_SAMA5_XDMAC1 if (xdmach->xdmac == 0) @@ -908,173 +883,40 @@ static uint32_t sam_sink_channel(struct sam_xdmach_s *xdmach, uint8_t pid, } /**************************************************************************** - * Name: sam_txcfg - * - * Description: - * Decode the flags to get the correct CFG register bit settings for - * a transmit (memory to peripheral) transfer. - * - ****************************************************************************/ - -static inline uint32_t sam_txcfg(struct sam_xdmach_s *xdmach) -{ - uint32_t regval; - unsigned int pid; - unsigned int pchan; - bool isperiph; - - /* Set transfer (memory to peripheral) DMA channel configuration register */ - - regval = XDMAC_CH_CFG_SOD; - - pid = (xdmach->flags & DMACH_FLAG_MEMPID_MASK) >> DMACH_FLAG_MEMPID_SHIFT; - isperiph = ((xdmach->flags & DMACH_FLAG_MEMISPERIPH) != 0); - pchan = sam_source_channel(xdmach, pid, isperiph); - - regval |= ((pchan & 0x0f) << XDMAC_CH_CFG_SRCPER_SHIFT); - regval |= ((pchan & 0x30) << (XDMAC_CH_CFG_SRCPERMSB_SHIFT-4)); - regval |= (xdmach->flags & DMACH_FLAG_MEMH2SEL) != 0 ? XDMAC_CH_CFG_SRCH2SEL : 0; - - pid = (xdmach->flags & DMACH_FLAG_PERIPHPID_MASK) >> DMACH_FLAG_PERIPHPID_SHIFT; - isperiph = ((xdmach->flags & DMACH_FLAG_PERIPHISPERIPH) != 0); - pchan = sam_sink_channel(xdmach, pid, isperiph); - - regval |= ((pchan & 0x0f) << XDMAC_CH_CFG_DSTPER_SHIFT); - regval |= ((pchan & 0x30) << (XDMAC_CH_CFG_DSTPERMSB_SHIFT-4)); - regval |= (xdmach->flags & DMACH_FLAG_PERIPHH2SEL) != 0 ? XDMAC_CH_CFG_DSTH2SEL : 0; - - return regval; -} - -/**************************************************************************** - * Name: sam_rxcfg - * - * Description: - * Decode the flags to get the correct CFG register bit settings for - * a receive (peripheral to memory) transfer. - * - ****************************************************************************/ - -static inline uint32_t sam_rxcfg(struct sam_xdmach_s *xdmach) -{ - uint32_t regval; - unsigned int pid; - unsigned int pchan; - bool isperiph; - - /* Set received (peripheral to memory) DMA channel config */ - - regval = XDMAC_CH_CFG_SOD; - - pid = (xdmach->flags & DMACH_FLAG_PERIPHPID_MASK) >> DMACH_FLAG_PERIPHPID_SHIFT; - isperiph = ((xdmach->flags & DMACH_FLAG_PERIPHISPERIPH) != 0); - pchan = sam_source_channel(xdmach, pid, isperiph); - - regval |= ((pchan & 0x0f) << XDMAC_CH_CFG_SRCPER_SHIFT); - regval |= ((pchan & 0x30) << (XDMAC_CH_CFG_SRCPERMSB_SHIFT-4)); - regval |= (xdmach->flags & DMACH_FLAG_PERIPHH2SEL) != 0 ? XDMAC_CH_CFG_SRCH2SEL : 0; - - pid = (xdmach->flags & DMACH_FLAG_MEMPID_MASK) >> DMACH_FLAG_MEMPID_SHIFT; - isperiph = ((xdmach->flags & DMACH_FLAG_MEMISPERIPH) != 0); - pchan = sam_sink_channel(xdmach, pid, isperiph); - - regval |= ((pchan & 0x0f) << XDMAC_CH_CFG_DSTPER_SHIFT); - regval |= ((pchan & 0x30) << (XDMAC_CH_CFG_DSTPERMSB_SHIFT-4)); - regval |= (xdmach->flags & DMACH_FLAG_MEMH2SEL) != 0 ? XDMAC_CH_CFG_DSTH2SEL : 0; - - return regval; -} - -/**************************************************************************** - * Name: sam_txctrlabits - * - * Description: - * Decode the flags to get the correct CTRLA register bit settings for - * a transmit (memory to peripheral) transfer. These are only the "fixed" - * CTRLA values and need to be updated with the actual transfer size before - * being written to CTRLA sam_txctrla). - * - ****************************************************************************/ - -static inline uint32_t sam_txctrlabits(struct sam_xdmach_s *xdmach) -{ - uint32_t regval; - unsigned int ndx; - unsigned int chunksize; - - DEBUGASSERT(xdmach); - - /* Since this is a transmit, the source is described by the memory selections. - * Set the source width (memory width). - */ - - ndx = (xdmach->flags & DMACH_FLAG_MEMWIDTH_MASK) >> DMACH_FLAG_MEMWIDTH_SHIFT; - DEBUGASSERT(ndx < 4); - regval = g_chanwidth[ndx]; - - /* Set the source chunk size (memory chunk size) */ - - chunksize = (xdmach->flags & DMACH_FLAG_MEMCHUNKSIZE_MASK) - >> DMACH_FLAG_MEMCHUNKSIZE_SHIFT; - regval |= chunksize << XDMAC_CH_CTRLA_SCSIZE_SHIFT; - - /* Since this is a transmit, the destination is described by the peripheral selections. - * Set the destination width (peripheral width). - */ - - ndx = (xdmach->flags & DMACH_FLAG_PERIPHWIDTH_MASK) >> DMACH_FLAG_PERIPHWIDTH_SHIFT; - DEBUGASSERT(ndx < 4); - regval |= g_chanwidth[ndx]; - - /* Set the destination chunk size (peripheral chunk size) */ - - chunksize = (xdmach->flags & DMACH_FLAG_PERIPHCHUNKSIZE_MASK) - >> DMACH_FLAG_PERIPHCHUNKSIZE_SHIFT; - regval |= chunksize << XDMAC_CH_CTRLA_DCSIZE_SHIFT; - - return regval; -} - -/**************************************************************************** - * Name: sam_maxtxtransfer + * Name: sam_maxtransfer * * Description: - * Maximum number of bytes that can be sent in on transfer + * Maximum number of bytes that can be sent in one transfer * ****************************************************************************/ -static size_t sam_maxtxtransfer(struct sam_xdmach_s *xdmach) +static size_t sam_maxtransfer(struct sam_xdmach_s *xdmach) { - unsigned int srcwidth; + unsigned int xfrwidth; size_t maxtransfer; - /* Get the maximum transfer size in bytes. BTSIZE is "the number of - * transfers to be performed, that is, for writes it refers to the number - * of source width transfers to perform when XDMAC is flow controller. For - * Reads, BTSIZE refers to the number of transfers completed on the Source - * Interface. ..." - */ + /* Get the maximum transfer size in bytes */ - srcwidth = (xdmach->flags & DMACH_FLAG_MEMWIDTH_MASK) - >> DMACH_FLAG_MEMWIDTH_SHIFT; + xfrwidth = (xdmach->flags & DMACH_FLAG_PERIPHWIDTH_MASK) >> + DMACH_FLAG_PERIPHWIDTH_SHIFT; - switch (srcwidth) + switch (xfrwidth) { default: case 0: /* 8 bits, 1 byte */ - maxtransfer = XDMAC_CH_CTRLA_BTSIZE_MAX; + maxtransfer = XDMACH_CUBC_UBLEN_MAX; break; case 1: /* 16 bits, 2 bytes */ - maxtransfer = 2 * XDMAC_CH_CTRLA_BTSIZE_MAX; + maxtransfer = 2 * XDMACH_CUBC_UBLEN_MAX; break; case 2: /* 32 bits 4 bytes */ - maxtransfer = 4 * XDMAC_CH_CTRLA_BTSIZE_MAX; + maxtransfer = 4 * XDMACH_CUBC_UBLEN_MAX; break; case 3: /* 64 bits, 8 bytes */ - maxtransfer = 8 * XDMAC_CH_CTRLA_BTSIZE_MAX; + maxtransfer = 8 * XDMACH_CUBC_UBLEN_MAX; break; } @@ -1100,8 +942,8 @@ static uint32_t sam_ntxtransfers(struct sam_xdmach_s *xdmach, uint32_t dmasize) * the number of transfers completed on the Source Interface. ..." */ - srcwidth = (xdmach->flags & DMACH_FLAG_MEMWIDTH_MASK) - >> DMACH_FLAG_MEMWIDTH_SHIFT; + srcwidth = (xdmach->flags & DMACH_FLAG_PERIPHWIDTH_MASK) >> + DMACH_FLAG_PERIPHWIDTH_SHIFT; switch (srcwidth) { @@ -1126,15 +968,15 @@ static uint32_t sam_ntxtransfers(struct sam_xdmach_s *xdmach, uint32_t dmasize) } /**************************************************************************** - * Name: sam_txctrla + * Name: sam_txcubc * * Description: - * 'OR' in the variable CTRLA bits + * 'OR' in the variable CUBC bits * ****************************************************************************/ -static inline uint32_t sam_txctrla(struct sam_xdmach_s *xdmach, - uint32_t ctrla, uint32_t dmasize) +static inline uint32_t sam_txcubc(struct sam_xdmach_s *xdmach, + uint32_t cubc, uint32_t dmasize) { uint32_t ntransfers; @@ -1144,109 +986,9 @@ static inline uint32_t sam_txctrla(struct sam_xdmach_s *xdmach, ntransfers = sam_ntxtransfers(xdmach, dmasize); - DEBUGASSERT(ntransfers <= XDMAC_CH_CTRLA_BTSIZE_MAX); - return (ctrla & ~XDMAC_CH_CTRLA_BTSIZE_MASK) | - (ntransfers << XDMAC_CH_CTRLA_BTSIZE_SHIFT); -} - -/**************************************************************************** - * Name: sam_rxctrlabits - * - * Description: - * Decode the flags to get the correct CTRLA register bit settings for - * a read (peripheral to memory) transfer. These are only the "fixed" CTRLA - * values and need to be updated with the actual transfer size before being - * written to CTRLA sam_rxctrla). - * - ****************************************************************************/ - -static inline uint32_t sam_rxctrlabits(struct sam_xdmach_s *xdmach) -{ - uint32_t regval; - unsigned int ndx; - unsigned int chunksize; - - DEBUGASSERT(xdmach); - - /* Since this is a receive, the source is described by the peripheral - * selections. Set the source width (peripheral width). - */ - - ndx = (xdmach->flags & DMACH_FLAG_PERIPHWIDTH_MASK) - >> DMACH_FLAG_PERIPHWIDTH_SHIFT; - - DEBUGASSERT(ndx < 4); - regval = g_chanwidth[ndx]; - - /* Set the source chunk size (peripheral chunk size) */ - - chunksize = (xdmach->flags & DMACH_FLAG_PERIPHCHUNKSIZE_MASK) - >> DMACH_FLAG_PERIPHCHUNKSIZE_SHIFT; - regval |= chunksize << XDMAC_CH_CTRLA_SCSIZE_SHIFT; - - /* Since this is a receive, the destination is described by the memory - * selections. Set the destination width (memory width). - */ - - ndx = (xdmach->flags & DMACH_FLAG_MEMWIDTH_MASK) - >> DMACH_FLAG_MEMWIDTH_SHIFT; - - DEBUGASSERT(ndx < 4); - regval |= g_chanwidth[ndx]; - - /* Set the destination chunk size (memory chunk size) */ - - chunksize = (xdmach->flags & DMACH_FLAG_MEMCHUNKSIZE_MASK) - >> DMACH_FLAG_MEMCHUNKSIZE_SHIFT; - regval |= chunksize << XDMAC_CH_CTRLA_DCSIZE_SHIFT; - - return regval; -} - -/**************************************************************************** - * Name: sam_maxrxtransfer - * - * Description: - * Maximum number of bytes that can be sent in on transfer - * - ****************************************************************************/ - -static size_t sam_maxrxtransfer(struct sam_xdmach_s *xdmach) -{ - unsigned int srcwidth; - size_t maxtransfer; - - /* Get the maximum transfer size in bytes. BTSIZE is "the number of - * transfers to be performed, that is, for writes it refers to the number - * of source width transfers to perform when XDMAC is flow controller. For - * Reads, BTSIZE refers to the number of transfers completed on the Source - * Interface. ..." - */ - - srcwidth = (xdmach->flags & DMACH_FLAG_PERIPHWIDTH_MASK) - >> DMACH_FLAG_PERIPHWIDTH_SHIFT; - - switch (srcwidth) - { - default: - case 0: /* 8 bits, 1 byte */ - maxtransfer = XDMAC_CH_CTRLA_BTSIZE_MAX; - break; - - case 1: /* 16 bits, 2 bytes */ - maxtransfer = 2 * XDMAC_CH_CTRLA_BTSIZE_MAX; - break; - - case 2: /* 32 bits, 4 bytes */ - maxtransfer = 4 * XDMAC_CH_CTRLA_BTSIZE_MAX; - break; - - case 3: /* 64 bits, 8 bytes */ - maxtransfer = 8 * XDMAC_CH_CTRLA_BTSIZE_MAX; - break; - } - - return maxtransfer; + DEBUGASSERT(ntransfers <= XDMACH_CUBC_UBLEN_MAX); + return (cubc & ~XDMACH_CUBC_UBLEN_MASK) | + (ntransfers << XDMACH_CUBC_UBLEN_SHIFT); } /**************************************************************************** @@ -1294,15 +1036,15 @@ static uint32_t sam_nrxtransfers(struct sam_xdmach_s *xdmach, uint32_t dmasize) } /**************************************************************************** - * Name: sam_rxctrla + * Name: sam_rxcubc * * Description: - * 'OR' in the variable CTRLA bits + * 'OR' in the variable CUBC bits * ****************************************************************************/ -static inline uint32_t sam_rxctrla(struct sam_xdmach_s *xdmach, - uint32_t ctrla, uint32_t dmasize) +static inline uint32_t sam_rxcubc(struct sam_xdmach_s *xdmach, + uint32_t cubc, uint32_t dmasize) { uint32_t ntransfers; @@ -1312,188 +1054,319 @@ static inline uint32_t sam_rxctrla(struct sam_xdmach_s *xdmach, ntransfers = sam_nrxtransfers(xdmach, dmasize); - DEBUGASSERT(ntransfers <= XDMAC_CH_CTRLA_BTSIZE_MAX); - return (ctrla & ~XDMAC_CH_CTRLA_BTSIZE_MASK) | - (ntransfers << XDMAC_CH_CTRLA_BTSIZE_SHIFT); + DEBUGASSERT(ntransfers <= XDMACH_CUBC_UBLEN_MAX); + return (cubc & ~XDMACH_CUBC_UBLEN_MASK) | + (ntransfers << XDMACH_CUBC_UBLEN_SHIFT); } /**************************************************************************** - * Name: sam_txctrlb + * Name: sam_txcc * * Description: - * Decode the flags to get the correct CTRLB register bit settings for - * a transmit (memory to peripheral) transfer. + * Decode the flags to get the correct Channel Control (CC) Register bit + * settings for a transmit (memory to peripheral) transfer. + * + * Single Block: + * 1. Clear TYPE for a memory to memory transfer, otherwise set + * this bit for memory to/from peripheral transfer. + * 2. Program MBSIZE to the memory burst size used. + * 3. Program SAM/DAM to the memory addressing scheme. + * 4. Program SYNC to select the peripheral transfer direction. + * 5. Set PROT to activate a secure channel. + * 6. Program CSIZE to configure the channel chunk size (only + * relevant for peripheral synchronized transfer). + * 7. Program DWIDTH to configure the transfer data width. + * 8. Program SIF, DIF to configure the master interface + * used to read data and write data respectively. + * 9. Program PERID to select the active hardware request line + * (only relevant for a peripheral synchronized transfer). + * 10. Set SWREQ to use software request (only relevant for a + * peripheral synchronized transfer). * ****************************************************************************/ -static inline uint32_t sam_txctrlb(struct sam_xdmach_s *xdmach) +static inline uint32_t sam_txcc(struct sam_xdmach_s *xdmach) { uint32_t regval; - unsigned int ahbif; + uint32_t field; - /* Assume that we will not be using the link list and disable the source - * and destination descriptors. The default will be single transfer mode. + regval = 0; + + /* 1. Clear TYPE for a memory to memory transfer, otherwise set + * this bit for memory to/from peripheral transfer. + * + * By convention, TX refers to a memory to peripheral transfer. So the + * source is memory. Is the "peripheral" destination a peripheral? or + * it is really memory? */ - regval = XDMAC_CH_CTRLB_BOTHDSCR | XDMAC_CH_CTRLB_IEN; + if ((xdmach->flags & DMACH_FLAG_PERIPHISPERIPH) != 0) + { + /* Yes.. Use peripheral synchronized mode */ + + regval |= XDMACH_CC_TYPE; + } - /* Select flow control (even if the channel doesn't support it). The - * naming convention from TX is memory to peripheral, but that is really - * be determined by bits in the DMA flags. + /* 2. Program MBSIZE to the memory burst size used. + * + * NOTE: This assumes the same encoding in the DMACH flags as in the CC + * register MBSIZE field. */ - /* Is the memory source really a peripheral? */ + field = (xdmach->flags & DMACH_FLAG_MEMBURST_MASK) >> + DMACH_FLAG_MEMBURST_SHIFT; + regval |= (field << XDMACH_CC_MBSIZE_SHIFT); - if ((xdmach->flags & DMACH_FLAG_MEMISPERIPH) != 0) - { - /* Yes.. is the peripheral destination also a peripheral? */ + /* 3. Program SAM/DAM to the memory addressing scheme. + * + * NOTE: This assumes that 0 means non-incrementing. + * TX -> Source is memory. + */ - if ((xdmach->flags & DMACH_FLAG_PERIPHISPERIPH) != 0) - { - /* Yes.. Use peripheral-to-peripheral flow control */ + if ((xdmach->flags & DMACH_FLAG_MEMINCREMENT) != 0) + { + regval |= XDMACH_CC_SAM_INCR; + } - regval |= XDMAC_CH_CTRLB_FC_P2P; - } - else - { - /* No.. Use peripheral-to-memory flow control */ + /* TX -> Destination is peripheral. */ - regval |= XDMAC_CH_CTRLB_FC_P2M; - } - } - else + if ((xdmach->flags & DMACH_FLAG_PERIPHINCREMENT) != 0) { - /* No, the source is memory. Is the peripheral destination a - * peripheral - */ + regval |= XDMACH_CC_DAM_INCR; + } - if ((xdmach->flags & DMACH_FLAG_PERIPHISPERIPH) != 0) - { - /* Yes.. Use memory-to-peripheral flow control */ + /* 4. Program DSYNC to select the peripheral transfer direction. + * + * TX -> Memory to peripheral + */ - regval |= XDMAC_CH_CTRLB_FC_M2P; - } - else - { - /* No.. Use memory-to-memory flow control */ + regval |= XDMACH_CC_DSYNC; - regval |= XDMAC_CH_CTRLB_FC_M2M; - } + /* 5. Set PROT to activate a secure channel (REVISIT). */ + + regval |= XDMACH_CC_PROT; /* Channel is unsecured */ + + /* 6. Program CSIZE to configure the channel chunk size (only + * relevant for peripheral synchronized transfer). + */ + + if ((xdmach->flags & DMACH_FLAG_PERIPHISPERIPH) != 0) + { + /* Peripheral synchronized mode -- set chunk size. + * NOTE that we assume that encoding in the XDMACH flags is the same + * as in the CC register CSIZE field. + */ + + field = (xdmach->flags & DMACH_FLAG_PERIPHCHUNKSIZE_MASK) >> + DMACH_FLAG_PERIPHCHUNKSIZE_SHIFT; + regval |= (field << XDMACH_CC_CSIZE_SHIFT); } - /* Source ABH layer */ + /* 7. Program DWIDTH to configure the transfer data width. + * + * NOTE that we assume that encoding in the XDMACH flags is the same as in + * the CC register CSIZE field. + */ - ahbif = (xdmach->flags & DMACH_FLAG_MEMAHB_MASK) >> DMACH_FLAG_MEMAHB_SHIFT; - regval |= (ahbif << XDMAC_CH_CTRLB_SIF_SHIFT); + field = (xdmach->flags & DMACH_FLAG_PERIPHWIDTH_MASK) >> + DMACH_FLAG_PERIPHWIDTH_SHIFT; + regval |= (field << XDMACH_CC_DWIDTH_SHIFT); - /* Select source address incrementing */ + /* 8. Program SIF, DIF to configure the master interface + * used to read data and write data respectively. + * + * TX -> Source is memory + */ - if ((xdmach->flags & DMACH_FLAG_MEMINCREMENT) == 0) + if ((xdmach->flags & DMACH_FLAG_MEMAHB_MASK) == DMACH_FLAG_MEMAHB_AHB_IF1) { - regval |= XDMAC_CH_CTRLB_SRCINCR_FIXED; + regval |= XDMACH_CC_SIF; } - /* Destination ABH layer */ + /* TX -> Destination is peripheral */ - ahbif = (xdmach->flags & DMACH_FLAG_PERIPHAHB_MASK) >> DMACH_FLAG_PERIPHAHB_SHIFT; - regval |= (ahbif << XDMAC_CH_CTRLB_DIF_SHIFT); + if ((xdmach->flags & DMACH_FLAG_PERIPHAHB_MASK) == DMACH_FLAG_PERIPHAHB_AHB_IF1) + { + regval |= XDMACH_CC_DIF; + } - /* Select destination address incrementing */ + /* 9. Program PERID to select the active hardware request line + * (only relevant for a peripheral synchronized transfer). + */ - if ((xdmach->flags & DMACH_FLAG_PERIPHINCREMENT) == 0) + if ((xdmach->flags & DMACH_FLAG_PERIPHISPERIPH) != 0) { - regval |= XDMAC_CH_CTRLB_DSTINCR_FIXED; + int pid; + + /* Get the PID from the DMACH flags */ + + pid = (xdmach->flags & DMACH_FLAG_PERIPHPID_MASK) >> + DMACH_FLAG_PERIPHPID_SHIFT; + + /* Look up the DMA channel code for TX: Peripheral is the sink. */ + + field = sam_sink_channel(xdmach, pid); + regval |= (field << XDMACH_CC_CSIZE_SHIFT); + + /* 10. Set SWREQ to use software request (only relevant for a + * peripheral synchronized transfer). + */ + + regval |= XDMACH_CC_SWREQ; } return regval; } /**************************************************************************** - * Name: sam_rxctrlb + * Name: sam_rxcc * * Description: - * Decode the flags to get the correct CTRLB register bit settings for - * a receive (peripheral to memory) transfer. + * Decode the flags to get the correct Channel Control (CC) Register bit + * settings for a receive (peripheral to memory) transfer. + * + * 1. Clear TYPE for a memory to memory transfer, otherwise set + * this bit for memory to/from peripheral transfer. + * 2. Program MBSIZE to the memory burst size used. + * 3. Program SAM/DAM to the memory addressing scheme. + * 4. Program SYNC to select the peripheral transfer direction. + * 5. Set PROT to activate a secure channel. + * 6. Program CSIZE to configure the channel chunk size (only + * relevant for peripheral synchronized transfer). + * 7. Program DWIDTH to configure the transfer data width. + * 8. Program SIF, DIF to configure the master interface + * used to read data and write data respectively. + * 9. Program PERID to select the active hardware request line + * (only relevant for a peripheral synchronized transfer). + * 10. Set SWREQ to use software request (only relevant for a + * peripheral synchronized transfer). * ****************************************************************************/ -static inline uint32_t sam_rxctrlb(struct sam_xdmach_s *xdmach) +static inline uint32_t sam_rxcc(struct sam_xdmach_s *xdmach) { uint32_t regval; - unsigned int ahbif; + uint32_t field; - /* Assume that we will not be using the link list and disable the source - * and destination descriptors. The default will be single transfer mode. + /* 1. Clear TYPE for a memory to memory transfer, otherwise set + * this bit for memory to/from peripheral transfer. + * + * By convention, RX refers to a peripheral to memory transfer. So the + * source is peripheral. Is the "peripheral" source a peripheral? or + * is it also memory? */ - regval = XDMAC_CH_CTRLB_BOTHDSCR | XDMAC_CH_CTRLB_IEN; + if ((xdmach->flags & DMACH_FLAG_PERIPHISPERIPH) != 0) + { + /* Yes.. Use peripheral synchronized mode */ + + regval |= XDMACH_CC_TYPE; + } - /* Select flow control (even if the channel doesn't support it). The - * naming convention from RX is peripheral to memory, but that is really - * be determined by bits in the DMA flags. + /* 2. Program MBSIZE to the memory burst size used. + * + * NOTE: This assumes the same encoding in the DMACH flags as in the CC + * register MBSIZE field. */ - /* Is the peripheral source really a peripheral? */ + field = (xdmach->flags & DMACH_FLAG_MEMBURST_MASK) >> + DMACH_FLAG_MEMBURST_SHIFT; + regval |= (field << XDMACH_CC_MBSIZE_SHIFT); - if ((xdmach->flags & DMACH_FLAG_PERIPHISPERIPH) != 0) + /* 3. Program SAM/DAM to the memory addressing scheme. + * + * NOTE: This assumes that 0 means non-incrementing. + * RX -> Source is peripheral. + */ + + if ((xdmach->flags & DMACH_FLAG_PERIPHINCREMENT) != 0) { - /* Yes.. is the memory destination also a peripheral? */ + regval |= XDMACH_CC_SAM_INCR; + } - if ((xdmach->flags & DMACH_FLAG_MEMISPERIPH) != 0) - { - /* Yes.. Use peripheral-to-peripheral flow control */ + /* RX -> Destination is memory. */ - regval |= XDMAC_CH_CTRLB_FC_P2P; - } - else - { - /* No.. Use peripheral-to-memory flow control */ - - regval |= XDMAC_CH_CTRLB_FC_P2M; - } - } - else + if ((xdmach->flags & DMACH_FLAG_MEMINCREMENT) != 0) { - /* No, the peripheral source is memory. Is the memory destination - * a peripheral - */ + regval |= XDMACH_CC_DAM_INCR; + } - if ((xdmach->flags & DMACH_FLAG_MEMISPERIPH) != 0) - { - /* Yes.. Use memory-to-peripheral flow control */ + /* 4. Program DSYNC to select the peripheral transfer direction. + * + * RX -> Peripheral to memory (DSYNC == 0) + */ - regval |= XDMAC_CH_CTRLB_FC_M2P; - } - else - { - /* No.. Use memory-to-memory flow control */ + /* 5. Set PROT to activate a secure channel (REVISIT) */ - regval |= XDMAC_CH_CTRLB_FC_M2M; - } + regval |= XDMACH_CC_PROT; /* Channel is unsecured */ + + /* 6. Program CSIZE to configure the channel chunk size (only + * relevant for peripheral synchronized transfer). + */ + + if ((xdmach->flags & DMACH_FLAG_PERIPHISPERIPH) != 0) + { + /* Peripheral synchronized mode -- set chunk size. + * NOTE that we assume that encoding in the XDMACH flags is the same + * as in the CC register CSIZE field. + */ + + field = (xdmach->flags & DMACH_FLAG_PERIPHCHUNKSIZE_MASK) >> + DMACH_FLAG_PERIPHCHUNKSIZE_SHIFT; + regval |= (field << XDMACH_CC_CSIZE_SHIFT); } - /* Source ABH layer */ + /* 7. Program DWIDTH to configure the transfer data width. + * + * NOTE that we assume that encoding in the XDMACH flags is the same as in + * the CC register CSIZE field. + */ - ahbif = (xdmach->flags & DMACH_FLAG_PERIPHAHB_MASK) >> DMACH_FLAG_PERIPHAHB_SHIFT; - regval |= (ahbif << XDMAC_CH_CTRLB_SIF_SHIFT); + field = (xdmach->flags & DMACH_FLAG_PERIPHWIDTH_MASK) >> + DMACH_FLAG_PERIPHWIDTH_SHIFT; + regval |= (field << XDMACH_CC_DWIDTH_SHIFT); - /* Select source address incrementing */ + /* 8. Program SIF, DIF to configure the master interface + * used to read data and write data respectively. + * + * RX -> Source is peripheral + */ - if ((xdmach->flags & DMACH_FLAG_PERIPHINCREMENT) == 0) + if ((xdmach->flags & DMACH_FLAG_PERIPHAHB_MASK) == DMACH_FLAG_PERIPHAHB_AHB_IF1) { - regval |= XDMAC_CH_CTRLB_SRCINCR_FIXED; + regval |= XDMACH_CC_SIF; } - /* Destination ABH layer */ + /* RX -> Destination is memory */ - ahbif = (xdmach->flags & DMACH_FLAG_MEMAHB_MASK) >> DMACH_FLAG_MEMAHB_SHIFT; - regval |= (ahbif << XDMAC_CH_CTRLB_DIF_SHIFT); + if ((xdmach->flags & DMACH_FLAG_MEMAHB_MASK) == DMACH_FLAG_MEMAHB_AHB_IF1) + { + regval |= XDMACH_CC_DIF; + } - /* Select address incrementing */ + /* 9. Program PERID to select the active hardware request line + * (only relevant for a peripheral synchronized transfer). + */ - if ((xdmach->flags & DMACH_FLAG_MEMINCREMENT) == 0) + if ((xdmach->flags & DMACH_FLAG_PERIPHISPERIPH) != 0) { - regval |= XDMAC_CH_CTRLB_DSTINCR_FIXED; + int pid; + + /* Get the PID from the DMACH flags */ + + pid = (xdmach->flags & DMACH_FLAG_PERIPHPID_MASK) >> + DMACH_FLAG_PERIPHPID_SHIFT; + + /* Look up the DMA channel code for RX: Peripheral is the source. */ + + field = sam_source_channel(xdmach, pid); + regval |= (field << XDMACH_CC_CSIZE_SHIFT); + + /* 10. Set SWREQ to use software request (only relevant for a + * peripheral synchronized transfer). + */ + + regval |= XDMACH_CC_SWREQ; } return regval; @@ -1515,7 +1388,7 @@ static inline uint32_t sam_rxctrlb(struct sam_xdmach_s *xdmach) static struct dma_linklist_s * sam_allocdesc(struct sam_xdmach_s *xdmach, struct dma_linklist_s *prev, - uint32_t csa, uint32_t cda, uint32_t ctrla, uint32_t ctrlb) + uint32_t csa, uint32_t cda, uint32_t cubc, uint32_t cc) { struct sam_xdmac_s *xdmac = sam_controller(xdmach); struct dma_linklist_s *desc = NULL; @@ -1551,9 +1424,9 @@ sam_allocdesc(struct sam_xdmach_s *xdmach, struct dma_linklist_s *prev, desc = &xdmac->desc[i]; desc->csa = csa; /* Source address */ desc->cda = cda; /* Destination address */ - desc->ctrla = ctrla; /* Control A value */ - desc->ctrlb = ctrlb; /* Control B value */ - desc->dscr = 0; /* Next descriptor address */ + desc->cubc = cubc; /* Control A value */ + desc->cc = cc; /* Control B value */ + desc->dscr = 0; /* Next descriptor address */ /* And then hook it at the tail of the link list */ @@ -1579,7 +1452,7 @@ sam_allocdesc(struct sam_xdmach_s *xdmach, struct dma_linklist_s *prev, * this should work even if that is not the case. */ - prev->ctrlb &= ~XDMAC_CH_CTRLB_BOTHDSCR; + prev->cc &= ~XDMAC_CH_CC_BOTHDSCR; /* Link the previous tail to the new tail. * REVISIT: This assumes that the next description is fetched @@ -1593,7 +1466,7 @@ sam_allocdesc(struct sam_xdmach_s *xdmach, struct dma_linklist_s *prev, * and destination descriptors must be disabled for the last entry * in the link list. */ - desc->ctrlb |= XDMAC_CH_CTRLB_BOTHDSCR; + desc->cc |= XDMAC_CH_CC_BOTHDSCR; xdmach->lltail = desc; /* Assume that we will be doing multple buffer transfers and that @@ -1678,38 +1551,32 @@ static int sam_txbuffer(struct sam_xdmach_s *xdmach, uint32_t paddr, uint32_t maddr, size_t nbytes) { uint32_t regval; - uint32_t ctrla; - uint32_t ctrlb; + uint32_t cubc; + uint32_t cc; - /* If we are appending a buffer to a linklist, then re-use the CTRLA/B - * values. Otherwise, create them from the properties of the transfer. + /* If we are appending a buffer to a linklist, then re-use the previously + * calculated CC register value. Otherwise, create the CC register value + * from the properties of the transfer. */ if (xdmach->llhead) { - regval = xdmach->llhead->ctrla; - ctrlb = xdmach->llhead->ctrlb; + cc = xdmach->llhead->cc; } else { - regval = sam_txctrlabits(xdmach); - ctrlb = sam_txctrlb(xdmach); + cc = sam_txcc(xdmach); } - ctrla = sam_txctrla(xdmach, regval, nbytes); + cubc = sam_txcubc(xdmach, regval, nbytes); /* Add the new link list entry */ - if (!sam_allocdesc(xdmach, xdmach->lltail, maddr, paddr, ctrla, ctrlb)) + if (!sam_allocdesc(xdmach, xdmach->lltail, maddr, paddr, cubc, cc)) { return -ENOMEM; } - /* Pre-calculate the transmit CFG register setting (it won't be used until - * the DMA is started). - */ - - xdmach->cfg = sam_txcfg(xdmach); return OK; } @@ -1727,38 +1594,32 @@ static int sam_rxbuffer(struct sam_xdmach_s *xdmach, uint32_t paddr, uint32_t maddr, size_t nbytes) { uint32_t regval; - uint32_t ctrla; - uint32_t ctrlb; + uint32_t cubc; + uint32_t cc; - /* If we are appending a buffer to a linklist, then re-use the CTRLA/B - * values. Otherwise, create them from the properties of the transfer. + /* If we are appending a buffer to a linklist, then re-use the previously + * calculated CC register value. Otherwise, create the CC register value + * from the properties of the transfer. */ if (xdmach->llhead) { - regval = xdmach->llhead->ctrla; - ctrlb = xdmach->llhead->ctrlb; + cc = xdmach->llhead->cc; } else { - regval = sam_rxctrlabits(xdmach); - ctrlb = sam_rxctrlb(xdmach); + cc = sam_rxcc(xdmach); } - ctrla = sam_rxctrla(xdmach, regval, nbytes); + cubc = sam_rxcubc(xdmach, regval, nbytes); /* Add the new link list entry */ - if (!sam_allocdesc(xdmach, xdmach->lltail, paddr, maddr, ctrla, ctrlb)) + if (!sam_allocdesc(xdmach, xdmach->lltail, paddr, maddr, cubc, cc)) { return -ENOMEM; } - /* Pre-calculate the receive CFG register setting (it won't be used until - * the DMA is started). - */ - - xdmach->cfg = sam_rxcfg(xdmach); return OK; } @@ -1775,60 +1636,86 @@ static inline int sam_single(struct sam_xdmach_s *xdmach) struct sam_xdmac_s *xdmac = sam_controller(xdmach); struct dma_linklist_s *llhead = xdmach->llhead; - /* Clear any pending interrupts from any previous XDMAC transfer by - * reading the XDMAC Channel Interrupt Status Register (CIS). + /* 1. Read the XDMAC Global Channel Status Register (XDMAC_GS) to choose a + * free channel. + * + * In this implementation, the free channel is assigned in a different + * manner. + */ + + /* 2. Clear any pending interrupts from any previous XDMAC transfer by + * reading the XDMAC Channel Interrupt Status Register (CIS). */ (void)sam_getdmach(xdmach, SAM_XDMACH_CIS_OFFSET); - /* Write the starting source address in the Channel Source Address (CSA) - * Register. + /* 3. Write the starting source address in the Channel Source Address (CSA) + * Register. */ DEBUGASSERT(llhead != NULL && llhead->csa != 0); sam_putdmach(xdmach, llhead->csa, SAM_XDMACH_CSA_OFFSET); - /* Write the starting destination address in the Channel Destination - * Address Register (CDA). + /* 4. Write the starting destination address in the Channel Destination + * Address Register (CDA). */ sam_putdmach(xdmach, llhead->cda, SAM_XDMACH_CDA_OFFSET); - /* Clear the next descriptor address */ + /* 5. Program field UBLEN in the XDMAC Channel Microblock Control (CUBC) + * Register with the number of data. + */ - sam_putdmach(xdmach, 0, SAM_XDMAC_CH_DSCR_OFFSET); + sam_putdmach(xdmach, llhead->cubc, SAM_XDMACH_CUBC_OFFSET); - /* Set up the CTRLA register */ + /* 6. Program the Channel Control (CC) Register */ - sam_putdmach(xdmach, llhead->ctrla, SAM_XDMAC_CH_CTRLA_OFFSET); + sam_putdmach(xdmach, llhead->cc, SAM_XDMACH_CC_OFFSET); - /* Set up the CTRLB register */ + /* 7. Clear the following five registers: + * + * XDMAC Channel Next Descriptor Control (CNDC) Register + * XDMAC Channel Block Control (CBC) Register + * XDMAC Channel Data Stride Memory Set Pattern (CDSMSP) Register + * XDMAC Channel Source Microblock Stride (CSUS) Register + * XDMAC Channel Destination Microblock Stride (CDUS)Register + * + * This respectively indicates that the linked list is disabled, there is + * only one block and striding is disabled + */ - sam_putdmach(xdmach, llhead->ctrlb, SAM_XDMAC_CH_CTRLB_OFFSET); + sam_putdmach(xdmach, 0, SAM_XDMACH_CNDC_OFFSET); + sam_putdmach(xdmach, 0, SAM_XDMACH_CBC_OFFSET); + sam_putdmach(xdmach, 0, SAM_XDMACH_CDSMSP_OFFSET); + sam_putdmach(xdmach, 0, SAM_XDMACH_CSUS_OFFSET); + sam_putdmach(xdmach, 0, SAM_XDMACH_CDUS_OFFSET); - /* Both the DST and SRC DSCR bits should be '1' in CTRLB */ + /* 8. Enable the Microblock interrupt by setting the "End of Block" + * interrupt bit in the XDMAC Channel Interrupt Enable (CIE) Register. + */ - DEBUGASSERT((llhead->ctrlb & XDMAC_CH_CTRLB_BOTHDSCR) == - XDMAC_CH_CTRLB_BOTHDSCR); + sam_putdmach(xdmach, XDMAC_CHINT_BI | XDMAC_CHINT_ERRORS, + SAM_XDMACH_CIE_OFFSET); - /* Set up the CFG register */ + /* Enable the Channel Interrupt Enable bit by setting the corresponding + * bit in the XDMAC Global Interrupt Enable (GIE) Register. + */ - sam_putdmach(xdmach, xdmach->cfg, SAM_XDMAC_CH_CFG_OFFSET); + sam_putdmac(xdmac, XDMAC_CHAN(xdmach->chan), SAM_XDMAC_GIE_OFFSET); - /* Enable the channel by writing a ‘1’ to the CHER enable bit */ + /* 9. Enable the channel by setting the corresponding bit in the + * XDMAC Global Channel Enable (GE) Register. The channel bit will + * be set in the GS register by hardware. + */ - sam_putdmac(xdmac, XDMAC_CHER_ENA(xdmach->chan), SAM_XDMAC_CHER_OFFSET); + sam_putdmac(xdmac, XDMAC_CHAN(xdmach->chan), SAM_XDMAC_GE_OFFSET); - /* The DMA has been started. Once the transfer completes, hardware sets - * the interrupts and disables the channel. We will receive buffer - * complete and transfer complete interrupts. - * - * Enable error, buffer complete and transfer complete interrupts. - * (Since there is only a single buffer, we don't need the buffer - * complete interrupt). + /* 10. The DMA has been started. Once completed, the DMA channel sets the + * corresponding "End of Block Interrupt" Status bit in the channel + * CIS register and generates an global interrupt for the channel. + * The channel bit will be cleared in the GS register by hardware. */ - sam_putdmac(xdmac, XDMAC_EBC_CBTCINTS(xdmach->chan), SAM_XDMAC_EBCIER_OFFSET); return OK; } @@ -1847,52 +1734,78 @@ static inline int sam_multiple(struct sam_xdmach_s *xdmach) DEBUGASSERT(llhead != NULL && llhead->csa != 0); - /* Check the first and last CTRLB values */ + /* Check the first and last Channel Control (CC) Register values */ - DEBUGASSERT((llhead->ctrlb & XDMAC_CH_CTRLB_BOTHDSCR) == 0); - DEBUGASSERT((xdmach->lltail->ctrlb & XDMAC_CH_CTRLB_BOTHDSCR) == - XDMAC_CH_CTRLB_BOTHDSCR); + DEBUGASSERT((llhead->cc & XDMAC_CH_CC_BOTHDSCR) == 0); + DEBUGASSERT((xdmach->lltail->cc & XDMAC_CH_CC_BOTHDSCR) == + XDMAC_CH_CC_BOTHDSCR); - /* Clear any pending interrupts from any previous XDMAC transfer by - * reading the XDMAC Channel Interrupt Status Register (CIS). + /* 1. Read the XDMAC Global Channel Status Register (XDMAC_GS) to choose a + * free channel. + * + * In this implementation, the free channel is assigned in a different + * manner. */ - (void)sam_getdmach(xdmach, SAM_XDMACH_CIS_OFFSET); + /* 2. Clear any pending interrupts from any previous XDMAC transfer by + * reading the XDMAC Channel Interrupt Status Register (CIS). + */ - /* Set up the initial CTRLA register */ + (void)sam_getdmach(xdmach, SAM_XDMACH_CIS_OFFSET); - sam_putdmach(xdmach, llhead->ctrla, SAM_XDMAC_CH_CTRLA_OFFSET); + /* 3. Build a linked list of transfer descriptors in memory. The + * descriptor view is programmable on a per descriptor basis. The + * linked list items structure must be word aligned. MBR_UBC.NDE + * must be configured to 0 in the last descriptor to terminate the + * list. + * + * This was done during the RX/TX setup phases of the DMA transfer. + */ - /* Set up the CTRLB register (will enable descriptors) */ + /* 4. Program field NDA in the XDMAC Channel Next Descriptor Address + * (CNDA) Register (XDMAC_CNDAx) with the first descriptor address + * and bit XDMAC_CNDAx.NDAIF with the master interface identifier. + */ +#warning Missing logic - sam_putdmach(xdmach, llhead->ctrlb, SAM_XDMAC_CH_CTRLB_OFFSET); + /* 5. Program the CNDC register: + * + * a. Set NDE to enable the descriptor fetch. + * b. Set NDSUP to update the source address at the descriptor fetch + * time, otherwise clear this bit. + * c. Set NDDUP to update the destination address at the descriptor + * fetch time, otherwise clear this bit. + * d. Program theNDVIEW field to define the length of the first + * descriptor. + */ +#warning Missing logic - /* Write the channel configuration information into the CFG register */ + /* 6. Enable the End of Linked List interrupt by setting the LI bit in the + * CIE register. + */ - sam_putdmach(xdmach, xdmach->cfg, SAM_XDMAC_CH_CFG_OFFSET); + sam_putdmach(xdmach, XDMAC_CHINT_LI | XDMAC_CHINT_ERRORS, + SAM_XDMACH_CIE_OFFSET); - /* Program the DSCR register with the pointer to the firstlink list entry. */ + /* Enable the Channel Interrupt Enable bit by setting the corresponding + * bit in the XDMAC Global Interrupt Enable (GIE) Register. + */ - sam_putdmach(xdmach, (uint32_t)llhead, SAM_XDMAC_CH_DSCR_OFFSET); + sam_putdmac(xdmac, XDMAC_CHAN(xdmach->chan), SAM_XDMAC_GIE_OFFSET); - /* Finally, enable the channel by writing a ‘1’ to the CHER enable */ + /* 7. Enable the channel by setting the corresponding bit in the + * XDMAC Global Channel Enable (GE) Register. The channel bit will + * be set in the GS register by hardware. + */ - sam_putdmac(xdmac, XDMAC_CHER_ENA(xdmach->chan), SAM_XDMAC_CHER_OFFSET); + sam_putdmac(xdmac, XDMAC_CHAN(xdmach->chan), SAM_XDMAC_GE_OFFSET); - /* As each buffer of data is transferred, the CTRLA register is written - * back into the link list entry. The CTRLA contains updated BTSIZE and - * DONE bits. Additionally, the CTRLA DONE bit is asserted when the - * buffer transfer has completed. - * - * The XDMAC transfer continues until the CTRLB register disables the - * descriptor (DSCR bits) registers at the final buffer transfer. - * - * Enable error, buffer complete and transfer complete interrupts. We - * don't really need the buffer complete interrupts, but we will take them - * just to handle stall conditions. + /* 8. The DMA has been started. Once completed, the DMA channel sets the + * corresponding "End of Block Interrupt" Status bit in the channel + * CIS register and generates an global interrupt for the channel. + * The channel bit will be cleared in the GS register by hardware. */ - sam_putdmac(xdmac, XDMAC_EBC_CHANINTS(xdmach->chan), SAM_XDMAC_EBCIER_OFFSET); return OK; } @@ -1907,16 +1820,23 @@ static inline int sam_multiple(struct sam_xdmach_s *xdmach) static void sam_dmaterminate(struct sam_xdmach_s *xdmach, int result) { struct sam_xdmac_s *xdmac = sam_controller(xdmach); + uint32_t chanbit = XDMAC_CHAN(xdmach->chan); /* Disable all channel interrupts */ - sam_putdmac(xdmac, XDMAC_EBC_CHANINTS(xdmach->chan), SAM_XDMAC_EBCIDR_OFFSET); + sam_putdmac(xdmac, chanbit, SAM_XDMAC_GID_OFFSET); + sam_putdmach(xdmach, XDMAC_CHINT_ALL, SAM_XDMAC_CDI_OFFSET); - /* Disable the channel by writing one to the write-only channel disable - * register. + /* Under normal operation, the software enables a channel by setting the + * associated bit in the Global Channel Enable (GE) Register. The hardware + * then disables a channel on transfer completion by clearing channel bit + * in the GS register. To disable a channel, setting the channel bit in the + * GD register and poll the channel bit in GS register to determine when + * the channel has been disabled. */ - sam_putdmac(xdmac, XDMAC_CHDR_DIS(xdmach->chan), SAM_XDMAC_CHDR_OFFSET); + sam_putdmac(xdmac, chanbit, SAM_XDMAC_GD_OFFSET); + while ((sam_getdma(xdmac, chanbit, SAM_XDMAC_GS_OFFSET) & chanbit) != 0); /* Free the linklist */ @@ -2051,15 +1971,15 @@ void sam_dmainitialize(struct sam_xdmac_s *xdmac) { /* Disable all DMA interrupts */ - sam_putdmac(xdmac, XDMAC_EBC_ALLINTS, SAM_XDMAC_EBCIDR_OFFSET); + sam_putdmac(xdmac, XDMAC_CHAN_ALL, SAM_XDMAC_GID_OFFSET); /* Disable all DMA channels */ - sam_putdmac(xdmac, XDMAC_CHDR_DIS_ALL, SAM_XDMAC_CHDR_OFFSET); + sam_putdmac(xdmac, XDMAC_CHAN_ALL, SAM_XDMAC_GD_OFFSET); /* Enable the DMA controller */ - sam_putdmac(xdmac,XDMAC_EN_ENABLE, SAM_XDMAC_EN_OFFSET); + sam_putdmac(xdmac, XDMAC_EN_ENABLE, SAM_XDMAC_EN_OFFSET); /* Initialize semaphores */ @@ -2320,7 +2240,7 @@ int sam_dmatxsetup(DMA_HANDLE handle, uint32_t paddr, uint32_t maddr, * transfers and the number of bytes per transfer. */ - maxtransfer = sam_maxtxtransfer(xdmach); + maxtransfer = sam_maxtransfer(xdmach); remaining = nbytes; /* If this is a large transfer, break it up into smaller buffers */ @@ -2399,7 +2319,7 @@ int sam_dmarxsetup(DMA_HANDLE handle, uint32_t paddr, uint32_t maddr, * transfers and the number of bytes per transfer. */ - maxtransfer = sam_maxrxtransfer(xdmach); + maxtransfer = sam_maxtransfer(xdmach); remaining = nbytes; /* If this is a large transfer, break it up into smaller buffers */ |