diff --git a/arch/arm/src/samv7/sam_hsmci.c b/arch/arm/src/samv7/sam_hsmci.c index 33761fba59..2517351fd5 100644 --- a/arch/arm/src/samv7/sam_hsmci.c +++ b/arch/arm/src/samv7/sam_hsmci.c @@ -120,10 +120,10 @@ #undef HSCMI_NORXDMA /* Define to disable RX DMA */ #undef HSCMI_NOTXDMA /* Define to disable TX DMA */ -/* Timing */ +/* Timing : 100mS short timeout, 2 seconds for long one */ -#define HSMCI_CMDTIMEOUT (100000) -#define HSMCI_LONGTIMEOUT (0x7fffffff) +#define HSMCI_CMDTIMEOUT MSEC2TICK(100) +#define HSMCI_LONGTIMEOUT MSEC2TICK(2000) /* Big DTIMER setting */ @@ -404,16 +404,17 @@ static bool sam_checkreg(struct sam_dev_s *priv, bool wr, #endif static inline uint32_t sam_getreg(struct sam_dev_s *priv, - unsigned int offset); + unsigned int offset); static inline void sam_putreg(struct sam_dev_s *priv, uint32_t value, - unsigned int offset); + unsigned int offset); static inline void sam_configwaitints(struct sam_dev_s *priv, - uint32_t waitmask, sdio_eventset_t waitevents); + uint32_t waitmask, + sdio_eventset_t waitevents); static void sam_disablewaitints(struct sam_dev_s *priv, - sdio_eventset_t wkupevent); + sdio_eventset_t wkupevent); static inline void sam_configxfrints(struct sam_dev_s *priv, - uint32_t xfrmask); + uint32_t xfrmask); static void sam_disablexfrints(struct sam_dev_s *priv); static inline void sam_enableints(struct sam_dev_s *priv); @@ -458,14 +459,14 @@ static void sam_cmddump(struct sam_dev_s *priv); static void sam_dmacallback(DMA_HANDLE handle, void *arg, int result); static inline uintptr_t hsmci_regaddr(struct sam_dev_s *priv, - unsigned int offset); + unsigned int offset); /* Data Transfer Helpers ****************************************************/ static void sam_eventtimeout(wdparm_t arg); static void sam_endwait(struct sam_dev_s *priv, sdio_eventset_t wkupevent); static void sam_endtransfer(struct sam_dev_s *priv, - sdio_eventset_t wkupevent); + sdio_eventset_t wkupevent); static void sam_notransfer(struct sam_dev_s *priv); /* Interrupt Handling *******************************************************/ @@ -481,48 +482,48 @@ static sdio_capset_t sam_capabilities(struct sdio_dev_s *dev); static sdio_statset_t sam_status(struct sdio_dev_s *dev); static void sam_widebus(struct sdio_dev_s *dev, bool enable); static void sam_clock(struct sdio_dev_s *dev, - enum sdio_clock_e rate); + enum sdio_clock_e rate); static int sam_attach(struct sdio_dev_s *dev); /* Command/Status/Data Transfer */ static int sam_sendcmd(struct sdio_dev_s *dev, uint32_t cmd, - uint32_t arg); + uint32_t arg); static void sam_blocksetup(struct sdio_dev_s *dev, unsigned int blocklen, - unsigned int nblocks); + unsigned int nblocks); static int sam_recvsetup(struct sdio_dev_s *dev, uint8_t *buffer, - size_t nbytes); + size_t nbytes); static int sam_sendsetup(struct sdio_dev_s *dev, - const uint8_t *buffer, size_t nbytes); + const uint8_t *buffer, size_t nbytes); static int sam_cancel(struct sdio_dev_s *dev); static int sam_waitresponse(struct sdio_dev_s *dev, uint32_t cmd); static int sam_recvshort(struct sdio_dev_s *dev, uint32_t cmd, - uint32_t *rshort); + uint32_t *rshort); static int sam_recvlong(struct sdio_dev_s *dev, uint32_t cmd, - uint32_t rlong[4]); + uint32_t rlong[4]); static int sam_recvnotimpl(struct sdio_dev_s *dev, uint32_t cmd, - uint32_t *rnotimpl); + uint32_t *rnotimpl); /* EVENT handler */ static void sam_waitenable(struct sdio_dev_s *dev, - sdio_eventset_t eventset, uint32_t timeout); + sdio_eventset_t eventset, uint32_t timeout); static sdio_eventset_t sam_eventwait(struct sdio_dev_s *dev); static void sam_callbackenable(struct sdio_dev_s *dev, - sdio_eventset_t eventset); + sdio_eventset_t eventset); static int sam_registercallback(struct sdio_dev_s *dev, - worker_t callback, void *arg); + worker_t callback, void *arg); /* DMA */ #ifdef CONFIG_SAMV7_HSMCI_DMA #ifndef HSCMI_NORXDMA static int sam_dmarecvsetup(struct sdio_dev_s *dev, - uint8_t *buffer, size_t buflen); + uint8_t *buffer, size_t buflen); #endif #ifndef HSCMI_NOTXDMA static int sam_dmasendsetup(struct sdio_dev_s *dev, - const uint8_t *buffer, size_t buflen); + const uint8_t *buffer, size_t buflen); #endif #endif @@ -1572,6 +1573,21 @@ static int sam_hsmci_interrupt(int irq, void *context, void *arg) else { + /* If buffer is not NULL that means that RX DMA is finished. + * We need to invalidate RX buffer + */ + + if (priv->buffer != NULL) + { + DEBUGASSERT(priv->remaining > 0); + + up_invalidate_dcache((uintptr_t)priv->buffer, + (uintptr_t)priv->buffer + + priv->remaining); + priv->buffer = NULL; + priv->remaining = 0; + } + /* End the transfer */ sam_endtransfer(priv, SDIOWAIT_TRANSFERDONE); @@ -2388,6 +2404,7 @@ static int sam_waitresponse(struct sdio_dev_s *dev, uint32_t cmd) struct sam_dev_s *priv = (struct sam_dev_s *)dev; uint32_t sr; uint32_t pending; + clock_t watchtime; int32_t timeout; switch (cmd & MMCSD_RESPONSE_MASK) @@ -2415,6 +2432,7 @@ static int sam_waitresponse(struct sdio_dev_s *dev, uint32_t cmd) /* Then wait for the response (or timeout) */ + watchtime = clock_systime_ticks(); for (; ; ) { /* Did a Command-Response sequence termination event occur? */ @@ -2464,7 +2482,7 @@ static int sam_waitresponse(struct sdio_dev_s *dev, uint32_t cmd) return OK; } } - else if (--timeout <= 0) + else if (clock_systime_ticks() - watchtime > timeout) { mcerr("ERROR: Timeout cmd: %08" PRIx32 " events: %08" PRIx32 " SR: %08" PRIx32 "\n", @@ -3008,9 +3026,11 @@ static int sam_dmarecvsetup(struct sdio_dev_s *dev, uint8_t *buffer, /* Start the DMA */ - priv->dmabusy = true; - priv->xfrbusy = true; - priv->txbusy = false; + priv->dmabusy = true; + priv->xfrbusy = true; + priv->txbusy = false; + priv->buffer = (uint32_t *)buffer; + priv->remaining = buflen; sam_dmastart(priv->dma, sam_dmacallback, priv); /* Configure transfer-related interrupts. Transfer interrupts are not