From 893855007295b2caae2d70560a34c387835bcd0c Mon Sep 17 00:00:00 2001 From: Gregory Nutt Date: Wed, 20 Dec 2017 14:38:09 -0600 Subject: [PATCH] arch/arm/src/lpc54xx: In SDMMC driver, don't do DMA if the entire transfer will fit in the FIFO. --- arch/arm/src/lpc54xx/chip/lpc54_sdmmc.h | 5 + arch/arm/src/lpc54xx/lpc54_sdmmc.c | 238 ++++++++++++------------ 2 files changed, 122 insertions(+), 121 deletions(-) diff --git a/arch/arm/src/lpc54xx/chip/lpc54_sdmmc.h b/arch/arm/src/lpc54xx/chip/lpc54_sdmmc.h index 0b672595fc..f873721f98 100644 --- a/arch/arm/src/lpc54xx/chip/lpc54_sdmmc.h +++ b/arch/arm/src/lpc54xx/chip/lpc54_sdmmc.h @@ -47,6 +47,11 @@ * Pre-processor Definitions ************************************************************************************************/ +#define LPC54_TXFIFO_DEPTH 32 +#define LPC54_TXFIFO_WIDTH 4 +#define LPC54_RXFIFO_DEPTH 32 +#define LPC54_RXFIFO_WIDTH 4 + /* MCI register offsets (with respect to the MCI base) ******************************************/ #define LPC54_SDMMC_CTRL_OFFSET 0x0000 /* Control register */ diff --git a/arch/arm/src/lpc54xx/lpc54_sdmmc.c b/arch/arm/src/lpc54xx/lpc54_sdmmc.c index 268acd2f1c..b274daaf6d 100644 --- a/arch/arm/src/lpc54xx/lpc54_sdmmc.c +++ b/arch/arm/src/lpc54xx/lpc54_sdmmc.c @@ -135,6 +135,11 @@ #define SDCARD_BUS_D4 1 #define SDCARD_BUS_D8 0x100 +/* FIFO size in bytes */ + +#define LPC54_TXFIFO_SIZE (LPC54_TXFIFO_DEPTH | LPC54_TXFIFO_WIDTH) +#define LPC54_RXFIFO_SIZE (LPC54_RXFIFO_DEPTH | LPC54_RXFIFO_WIDTH) + /* Data transfer interrupt mask bits */ #define SDCARD_RECV_MASK (SDMMC_INT_DCRC | SDMMC_INT_RCRC | SDMMC_INT_DRTO | \ @@ -187,7 +192,6 @@ #define SDCARD_DMADONE_FLAG (2) #define SDCARD_ALLDONE (3) - /* Card debounce time. Number of host clocks (SD_CLK) used by debounce * filter logic for card detect. typical debounce time is 5-25 ms. * @@ -1595,20 +1599,6 @@ static int lpc54_cancel(FAR struct sdio_dev_s *dev) (void)wd_cancel(priv->waitwdog); - /* If this was a DMA transfer, make sure that DMA is stopped */ - -#ifdef CONFIG_LPC54_SDMMC_DMA - if (priv->dmamode) - { - /* Make sure that the DMA is stopped (it will be stopped automatically - * on normal transfers, but not necessarily when the transfer terminates - * on an error condition. - */ - - //lpc54_dmastop(priv->dma); - } -#endif - /* Mark no transfer in progress */ priv->remaining = 0; @@ -2182,95 +2172,97 @@ static int lpc54_registercallback(FAR struct sdio_dev_s *dev, static int lpc54_dmarecvsetup(FAR struct sdio_dev_s *dev, FAR uint8_t *buffer, size_t buflen) { - struct lpc54_dev_s *priv = (struct lpc54_dev_s *)dev; + struct lpc54_dev_s *priv; uint32_t regval; - uint32_t ctrl = 0; - uint32_t maxs = 0; - int ret = OK; - int i = 0; + uint32_t ctrl; + uint32_t maxs; + int ret; + int i; - mcinfo("DMA size: %d\n", buflen); + /* Don't bother with DMA if the entire transfer will fit in the RX FIFO or + * if we do not have a 4-bit wide bus. + */ + if (buflen <= LPC54_RXFIFO_SIZE || !priv->widebus) + { + return lpc54_recvsetup(dev, buffer, buflen); + } + + mcinfo("buflen=%lu\n", (unsigned long)buflen); + + priv = (struct lpc54_dev_s *)dev; DEBUGASSERT(priv != NULL && buffer != NULL && buflen > 0); DEBUGASSERT(((uint32_t)buffer & 3) == 0); - ctrl = MCI_DMADES0_OWN | MCI_DMADES0_CH; + /* Save the destination buffer information for use by the interrupt handler */ - /* Wide bus operation is required for DMA */ + priv->buffer = (uint32_t *)buffer; + priv->remaining = buflen; + priv->dmamode = true; - if (priv->widebus) + /* Reset DMA */ + + regval = lpc54_getreg(LPC54_SDMMC_CTRL); + regval |= SDMMC_CTRL_FIFORESET | SDMMC_CTRL_DMARESET; + lpc54_putreg(regval, LPC54_SDMMC_CTRL); + + while (lpc54_getreg(LPC54_SDMMC_CTRL) & SDMMC_CTRL_DMARESET) { - /* Save the destination buffer information for use by the interrupt handler */ - - priv->buffer = (uint32_t *)buffer; - priv->remaining = buflen; - priv->dmamode = true; - - /* Reset DMA */ - - regval = lpc54_getreg(LPC54_SDMMC_CTRL); - regval |= SDMMC_CTRL_FIFORESET | SDMMC_CTRL_DMARESET; - lpc54_putreg(regval, LPC54_SDMMC_CTRL); - - while (lpc54_getreg(LPC54_SDMMC_CTRL) & SDMMC_CTRL_DMARESET) - { - } - - /* Setup DMA list */ - - while(buflen > 0) - { - /* Limit size of the transfer to maximum buffer size */ - - maxs = buflen; - - if (maxs > MCI_DMADES1_MAXTR) - { - maxs = MCI_DMADES1_MAXTR; - } - - buflen -= maxs; - - /* Set buffer size */ - - g_sdmmc_dmadd[i].des1 = MCI_DMADES1_BS1(maxs); - - /* Setup buffer address (chained) */ - - g_sdmmc_dmadd[i].des2 = (uint32_t) priv->buffer + (i * MCI_DMADES1_MAXTR); - - /* Setup basic control */ - - ctrl = MCI_DMADES0_OWN | MCI_DMADES0_CH; - - if (i == 0) - { - ctrl |= MCI_DMADES0_FS; /* First DMA buffer */ - } - - /* No more data? Then this is the last descriptor */ - - if (!buflen) - { - ctrl |= MCI_DMADES0_LD; - } - else - { - ctrl |= MCI_DMADES0_DIC; - } - - /* Another descriptor is needed */ - - g_sdmmc_dmadd[i].des0 = ctrl; - g_sdmmc_dmadd[i].des3 = (uint32_t) &g_sdmmc_dmadd[i + 1]; - - i++; - } - - lpc54_putreg((uint32_t) &g_sdmmc_dmadd[0], LPC54_SDMMC_DBADDR); } - return ret; + /* Setup DMA list */ + + i = 0; + while (buflen > 0) + { + /* Limit size of the transfer to maximum buffer size */ + + maxs = buflen; + + if (maxs > MCI_DMADES1_MAXTR) + { + maxs = MCI_DMADES1_MAXTR; + } + + buflen -= maxs; + + /* Set buffer size */ + + g_sdmmc_dmadd[i].des1 = MCI_DMADES1_BS1(maxs); + + /* Setup buffer address (chained) */ + + g_sdmmc_dmadd[i].des2 = (uint32_t) priv->buffer + (i * MCI_DMADES1_MAXTR); + + /* Setup basic control */ + + ctrl = MCI_DMADES0_OWN | MCI_DMADES0_CH; + + if (i == 0) + { + ctrl |= MCI_DMADES0_FS; /* First DMA buffer */ + } + + /* No more data? Then this is the last descriptor */ + + if (!buflen) + { + ctrl |= MCI_DMADES0_LD; + } + else + { + ctrl |= MCI_DMADES0_DIC; + } + + /* Another descriptor is needed */ + + g_sdmmc_dmadd[i].des0 = ctrl; + g_sdmmc_dmadd[i].des3 = (uint32_t) &g_sdmmc_dmadd[i + 1]; + i++; + } + + lpc54_putreg((uint32_t) &g_sdmmc_dmadd[0], LPC54_SDMMC_DBADDR); + return OK; } #endif @@ -2299,44 +2291,48 @@ static int lpc54_dmasendsetup(FAR struct sdio_dev_s *dev, { struct lpc54_dev_s *priv = (struct lpc54_dev_s *)dev; uint32_t regval; - int ret = -EPERM; + + /* Don't bother with DMA if the entire transfer will fit in the TX FIFO or + * if we do not have a 4-bit wide bus. + */ + + if (buflen <= LPC54_TXFIFO_SIZE || !priv->widebus) + { + return lpc54_sendsetup(dev, buffer, buflen); + } mcinfo("buflen=%lu\n", (unsigned long)buflen); + priv = (struct lpc54_dev_s *)dev; DEBUGASSERT(priv != NULL && buffer != NULL && buflen > 0); DEBUGASSERT(((uint32_t)buffer & 3) == 0); - /* Wide bus operation is required for DMA */ + /* Save the destination buffer information for use by the interrupt + * handler. + */ - if (priv->widebus) + priv->buffer = (uint32_t *)buffer; + priv->remaining = buflen; + priv->dmamode = true; + + /* Reset DMA */ + + regval = lpc54_getreg(LPC54_SDMMC_CTRL); + regval |= SDMMC_CTRL_FIFORESET | SDMMC_CTRL_DMARESET; + lpc54_putreg(regval, LPC54_SDMMC_CTRL); + while (lpc54_getreg(LPC54_SDMMC_CTRL) & SDMMC_CTRL_DMARESET) { - /* Save the destination buffer information for use by the interrupt - * handler. - */ - - priv->buffer = (uint32_t *)buffer; - priv->remaining = buflen; - priv->dmamode = true; - - /* Reset DMA */ - - regval = lpc54_getreg(LPC54_SDMMC_CTRL); - regval |= SDMMC_CTRL_FIFORESET | SDMMC_CTRL_DMARESET; - lpc54_putreg(regval, LPC54_SDMMC_CTRL); - while (lpc54_getreg(LPC54_SDMMC_CTRL) & SDMMC_CTRL_DMARESET); - - /* Setup DMA descriptor list */ - - g_sdmmc_dmadd[0].des0 = MCI_DMADES0_OWN | MCI_DMADES0_CH | MCI_DMADES0_LD; - g_sdmmc_dmadd[0].des1 = 512; - g_sdmmc_dmadd[0].des2 = (uint32_t)priv->buffer; - g_sdmmc_dmadd[0].des3 = (uint32_t)&g_sdmmc_dmadd[1]; - - lpc54_putreg((uint32_t) &g_sdmmc_dmadd[0], LPC54_SDMMC_DBADDR); - ret = OK; } - return ret; + /* Setup DMA descriptor list */ + + g_sdmmc_dmadd[0].des0 = MCI_DMADES0_OWN | MCI_DMADES0_CH | MCI_DMADES0_LD; + g_sdmmc_dmadd[0].des1 = 512; + g_sdmmc_dmadd[0].des2 = (uint32_t)priv->buffer; + g_sdmmc_dmadd[0].des3 = (uint32_t)&g_sdmmc_dmadd[1]; + + lpc54_putreg((uint32_t) &g_sdmmc_dmadd[0], LPC54_SDMMC_DBADDR); + return OK; } #endif