From f6c6723d88de06a7c015efdcb7666166bb1452c5 Mon Sep 17 00:00:00 2001 From: Gregory Nutt Date: Fri, 21 Aug 2015 12:30:29 -0600 Subject: [PATCH] SAMV7 USBHS Device: After aligning DMA buffers and disabling write-back data cache, the DCD driver is fully functional using the CDC/ACM device --- arch/arm/src/samv7/sam_usbdevhs.c | 46 ++++++++++++++++++++++++++++--- 1 file changed, 42 insertions(+), 4 deletions(-) diff --git a/arch/arm/src/samv7/sam_usbdevhs.c b/arch/arm/src/samv7/sam_usbdevhs.c index f1b45120b05..31b9b1923f1 100644 --- a/arch/arm/src/samv7/sam_usbdevhs.c +++ b/arch/arm/src/samv7/sam_usbdevhs.c @@ -72,6 +72,7 @@ #include "up_internal.h" #include "cache.h" +#include "chip.h" #include "sam_periphclks.h" #include "chip/sam_usbhs.h" #include "sam_clockconfig.h" @@ -146,6 +147,36 @@ #define sam_rqempty(q) ((q)->head == NULL) #define sam_rqpeek(q) ((q)->head) +/* Buffer Alignment ********************************************************* + * + * DMA buffers be aligned the 8-byte (2 word boundaries). However, if the + * data cache is enabled the a higher level of alignment is required. That + * is because the data will need to be invalidated and that cache + * invalidation will occur in multiples of full cache lines. + */ + +#ifdef CONFIG_ARMV7M_DCACHE +/* Align to the cache line size which we assume is >= 8 */ + +# define USBHS_ALIGN ARMV7M_DCACHE_LINESIZE +# define USBHS_ALIGN_MASK (USBHS_ALIGN-1) +# define USBHS_ALIGN_DOWN(n) ((n) & ~USBHS_ALIGN_MASK) +# define USBHS_ALIGN_UP(n) (((n) + USBHS_ALIGN_MASK) & ~USBHS_ALIGN_MASK) + +# ifndef CONFIG_ARMV7M_DCACHE_WRITETHROUGH +# warning !!! This driver will not work without CONFIG_ARMV7M_DCACHE_WRITETHROUGH=y!!! +# endif + +#else +/* Use the minimum alignment requirement */ + +# define USBHS_ALIGN 8 +# define USBHS_ALIGN_MASK 7 +# define USBHS_ALIGN_DOWN(n) ((n) & ~7) +# define USBHS_ALIGN_UP(n) (((n) + 7) & ~7) + +#endif + /* USB trace ****************************************************************/ /* Trace error codes */ @@ -1635,10 +1666,17 @@ static int sam_req_read(struct sam_usbdev_s *priv, struct sam_ep_s *privep, if ((SAM_EPSET_DMA & SAM_EP_BIT(epno)) != 0) { - /* Set up the next DMA */ + /* Set up the next DMA. We will come through this logic path + * again with xrfd != 0 when the DMA completes. + */ sam_dma_rdsetup(priv, privep, privreq); } + + /* No DMA for this endpoint and we have an available, empty read + * request. We need to wait for data to become avaialable. + */ + else { /* Enable endpoint RXRDY_TXTK interrupts */ @@ -3686,9 +3724,9 @@ static void sam_ep_freereq(struct usbdev_ep_s *ep, struct usbdev_req_s *req) #ifdef CONFIG_USBDEV_DMA static void *sam_ep_allocbuffer(struct usbdev_ep_s *ep, uint16_t nbytes) { - /* There is not special buffer allocation requirement */ + /* Allocate properly aligned memory */ - return kumm_malloc(nbytes); + return kmm_memalign(USBHS_ALIGN, USBHS_ALIGN_UP(nbytes)); } #endif @@ -3703,7 +3741,7 @@ static void *sam_ep_allocbuffer(struct usbdev_ep_s *ep, uint16_t nbytes) #ifdef CONFIG_USBDEV_DMA static void sam_ep_freebuffer(struct usbdev_ep_s *ep, void *buf) { - /* There is not special buffer allocation requirement */ + /* There is no special buffer requirement to free aligned DMA buffers */ kumm_free(buf); }