diff --git a/arch/arm/src/stm32f7/Kconfig b/arch/arm/src/stm32f7/Kconfig index 9e80a64934b..4f07188d097 100644 --- a/arch/arm/src/stm32f7/Kconfig +++ b/arch/arm/src/stm32f7/Kconfig @@ -1430,6 +1430,7 @@ config STM32F7_SDMMC1 select ARCH_HAVE_SDIO select ARCH_HAVE_SDIOWAIT_WRCOMPLETE select SDIO_PREFLIGHT + select SDIO_BLOCKSETUP config STM32F7_SDMMC2 bool "SDMMC2" @@ -1439,6 +1440,7 @@ config STM32F7_SDMMC2 select ARCH_HAVE_SDIO select ARCH_HAVE_SDIOWAIT_WRCOMPLETE select SDIO_PREFLIGHT + select SDIO_BLOCKSETUP config STM32F7_SPDIFRX bool "SPDIFRX" diff --git a/arch/arm/src/stm32f7/stm32_sdmmc.c b/arch/arm/src/stm32f7/stm32_sdmmc.c index e6168ad6631..e5ac6632df6 100644 --- a/arch/arm/src/stm32f7/stm32_sdmmc.c +++ b/arch/arm/src/stm32f7/stm32_sdmmc.c @@ -1,7 +1,7 @@ /**************************************************************************** * arch/arm/src/stm32f7/stm32_sdmmc.c * - * Copyright (C) 2009, 2011-2017 Gregory Nutt. All rights reserved. + * Copyright (C) 2009, 2011-2018 Gregory Nutt. All rights reserved. * Authors: Gregory Nutt * David Sidrane * @@ -388,6 +388,10 @@ struct stm32_dev_s bool dmamode; /* true: DMA mode transfer */ DMA_HANDLE dma; /* Handle for DMA channel */ #endif + + /* Misc */ + + uint32_t blocksize; /* Current block size */ }; /* Register logging support */ @@ -421,8 +425,8 @@ struct stm32_sampleregs_s /* Low-level helpers ********************************************************/ -static inline void sdmmc_putreg32(struct stm32_dev_s *priv, uint32_t value,\ - int offset); +static inline void sdmmc_putreg32(struct stm32_dev_s *priv, uint32_t value, + int offset); static inline uint32_t sdmmc_getreg32(struct stm32_dev_s *priv, int offset); static void stm32_takesem(struct stm32_dev_s *priv); #define stm32_givesem(priv) (nxsem_post(&priv->waitsem)) @@ -438,7 +442,7 @@ static inline uint32_t stm32_getpwrctrl(struct stm32_dev_s *priv); #ifdef CONFIG_STM32F7_SDMMC_XFRDEBUG static void stm32_sampleinit(void); static void stm32_sdiosample(struct stm32_dev_s *priv, - struct stm32_sdioregs_s *regs); + struct stm32_sdioregs_s *regs); static void stm32_sample(struct stm32_dev_s *priv, int index); static void stm32_sdiodump(struct stm32_sdioregs_s *regs, const char *msg); static void stm32_dumpsample(struct stm32_dev_s *priv, @@ -458,13 +462,15 @@ static void stm32_dmacallback(DMA_HANDLE handle, uint8_t status, void *arg); static uint8_t stm32_log2(uint16_t value); static void stm32_dataconfig(struct stm32_dev_s *priv, uint32_t timeout, - uint32_t dlen, uint32_t dctrl); + uint32_t dlen, uint32_t dctrl); static void stm32_datadisable(struct stm32_dev_s *priv); static void stm32_sendfifo(struct stm32_dev_s *priv); static void stm32_recvfifo(struct stm32_dev_s *priv); static void stm32_eventtimeout(int argc, uint32_t arg); -static void stm32_endwait(struct stm32_dev_s *priv, sdio_eventset_t wkupevent); -static void stm32_endtransfer(struct stm32_dev_s *priv, sdio_eventset_t wkupevent); +static void stm32_endwait(struct stm32_dev_s *priv, + sdio_eventset_t wkupevent); +static void stm32_endtransfer(struct stm32_dev_s *priv, + sdio_eventset_t wkupevent); /* Interrupt Handling *******************************************************/ @@ -495,6 +501,8 @@ static int stm32_attach(FAR struct sdio_dev_s *dev); static int stm32_sendcmd(FAR struct sdio_dev_s *dev, uint32_t cmd, uint32_t arg); +static void stm32_blocksetup(FAR struct sdio_dev_s *dev, + unsigned int blocksize, unsigned int nblocks); static int stm32_recvsetup(FAR struct sdio_dev_s *dev, FAR uint8_t *buffer, size_t nbytes); static int stm32_sendsetup(FAR struct sdio_dev_s *dev, @@ -543,6 +551,7 @@ static void stm32_default(struct stm32_dev_s *priv); /**************************************************************************** * Private Data ****************************************************************************/ + #ifdef CONFIG_STM32F7_SDMMC1 struct stm32_dev_s g_sdmmcdev1 = { @@ -558,9 +567,7 @@ struct stm32_dev_s g_sdmmcdev1 = .clock = stm32_clock, .attach = stm32_attach, .sendcmd = stm32_sendcmd, -#ifdef CONFIG_SDIO_BLOCKSETUP - .blocksetup = stm32_blocksetup, /* Not implemented yet */ -#endif + .blocksetup = stm32_blocksetup, .recvsetup = stm32_recvsetup, .sendsetup = stm32_sendsetup, .cancel = stm32_cancel, @@ -620,9 +627,7 @@ struct stm32_dev_s g_sdmmcdev2 = .clock = stm32_clock, .attach = stm32_attach, .sendcmd = stm32_sendcmd, -#ifdef CONFIG_SDIO_BLOCKSETUP - .blocksetup = stm32_blocksetup, /* Not implemented yet */ -#endif + .blocksetup = stm32_blocksetup, .recvsetup = stm32_recvsetup, .sendsetup = stm32_sendsetup, .cancel = stm32_cancel, @@ -1433,6 +1438,19 @@ static void stm32_endwait(struct stm32_dev_s *priv, sdio_eventset_t wkupevent) static void stm32_endtransfer(struct stm32_dev_s *priv, sdio_eventset_t wkupevent) { + /* Disable the DTEN bit (it should not be left set after previous read when + * the next write initialization starts). + */ + +#if 1 + sdmmc_putreg32(priv, + sdmmc_getreg32(priv, STM32_SDMMC_DCTRL_OFFSET) & + ~STM32_SDMMC_DCTRL_DTEN, + STM32_SDMMC_DCTRL_OFFSET); +#else + stm32_datadisable(priv); +#endif + /* Disable all transfer related interrupts */ stm32_configxfrints(priv, 0); @@ -2057,6 +2075,30 @@ static int stm32_sendcmd(FAR struct sdio_dev_s *dev, uint32_t cmd, uint32_t arg) return OK; } +/**************************************************************************** + * Name: stm32_blocksetup + * + * Description: + * Configure block size and the number of blocks for next transfer. + * + * Input Parameters: + * dev - An instance of the SDIO device interface. + * blocksize - The selected block size. + * nblocks - The number of blocks to transfer. + * + * Returned Value: + * None + * + ****************************************************************************/ + +static void stm32_blocksetup(FAR struct sdio_dev_s *dev, unsigned int blocksize, + unsigned int nblocks) +{ + struct stm32_dev_s *priv = (struct stm32_dev_s *)dev; + + priv->blocksize = blocksize; +} + /**************************************************************************** * Name: stm32_recvsetup * @@ -2103,7 +2145,7 @@ static int stm32_recvsetup(FAR struct sdio_dev_s *dev, FAR uint8_t *buffer, /* Then set up the SDIO data path */ - dblocksize = stm32_log2(nbytes) << STM32_SDMMC_DCTRL_DBLOCKSIZE_SHIFT; + dblocksize = stm32_log2(priv->blocksize) << STM32_SDMMC_DCTRL_DBLOCKSIZE_SHIFT; stm32_dataconfig(priv, SDMMC_DTIMER_DATATIMEOUT, nbytes, dblocksize | STM32_SDMMC_DCTRL_DTDIR); @@ -2158,7 +2200,7 @@ static int stm32_sendsetup(FAR struct sdio_dev_s *dev, FAR const /* Then set up the SDIO data path */ - dblocksize = stm32_log2(nbytes) << STM32_SDMMC_DCTRL_DBLOCKSIZE_SHIFT; + dblocksize = stm32_log2(priv->blocksize) << STM32_SDMMC_DCTRL_DBLOCKSIZE_SHIFT; stm32_dataconfig(priv, SDMMC_DTIMER_DATATIMEOUT, nbytes, dblocksize); /* Enable TX interrupts */ @@ -2882,7 +2924,7 @@ static int stm32_dmarecvsetup(FAR struct sdio_dev_s *dev, FAR uint8_t *buffer, /* Then set up the SDIO data path */ - dblocksize = stm32_log2(buflen) << STM32_SDMMC_DCTRL_DBLOCKSIZE_SHIFT; + dblocksize = stm32_log2(priv->blocksize) << STM32_SDMMC_DCTRL_DBLOCKSIZE_SHIFT; stm32_dataconfig(priv, SDMMC_DTIMER_DATATIMEOUT, buflen, dblocksize | STM32_SDMMC_DCTRL_DTDIR); @@ -2975,7 +3017,7 @@ static int stm32_dmasendsetup(FAR struct sdio_dev_s *dev, /* Then set up the SDIO data path */ - dblocksize = stm32_log2(buflen) << STM32_SDMMC_DCTRL_DBLOCKSIZE_SHIFT; + dblocksize = stm32_log2(priv->blocksize) << STM32_SDMMC_DCTRL_DBLOCKSIZE_SHIFT; stm32_dataconfig(priv, SDMMC_DTIMER_DATATIMEOUT, buflen, dblocksize); /* Configure the TX DMA */ diff --git a/drivers/mmcsd/mmcsd_sdio.c b/drivers/mmcsd/mmcsd_sdio.c index 3d890287010..9cb491feb7d 100644 --- a/drivers/mmcsd/mmcsd_sdio.c +++ b/drivers/mmcsd/mmcsd_sdio.c @@ -1895,6 +1895,25 @@ static ssize_t mmcsd_writemultiple(FAR struct mmcsd_state_s *priv, } } + /* If Controller does not need DMA setup before the write then send CMD25 + * now. + */ + + if ((priv->caps & SDIO_CAPS_DMABEFOREWRITE) == 0) + { + /* Send CMD25, WRITE_MULTIPLE_BLOCK, and verify that good R1 status + * is returned + */ + + mmcsd_sendcmdpoll(priv, MMCSD_CMD25, offset); + ret = mmcsd_recvR1(priv, MMCSD_CMD25); + if (ret != OK) + { + ferr("ERROR: mmcsd_recvR1 for CMD25 failed: %d\n", ret); + return ret; + } + } + /* Configure SDIO controller hardware for the write transfer */ SDIO_BLOCKSETUP(priv->dev, priv->blocksize, nblocks); @@ -1923,24 +1942,30 @@ static ssize_t mmcsd_writemultiple(FAR struct mmcsd_state_s *priv, priv->wrbusy = true; - /* Send CMD25, WRITE_MULTIPLE_BLOCK, and verify that good R1 status - * is returned - */ + /* If Controller needs DMA setup before write then only send CMD25 now. */ - mmcsd_sendcmdpoll(priv, MMCSD_CMD25, offset); - ret = mmcsd_recvR1(priv, MMCSD_CMD25); - if (ret != OK) + if ((priv->caps & SDIO_CAPS_DMABEFOREWRITE) != 0) { - ferr("ERROR: mmcsd_recvR1 for CMD25 failed: %d\n", ret); - return ret; + /* Send CMD25, WRITE_MULTIPLE_BLOCK, and verify that good R1 status + * is returned + */ + + mmcsd_sendcmdpoll(priv, MMCSD_CMD25, offset); + ret = mmcsd_recvR1(priv, MMCSD_CMD25); + if (ret != OK) + { + ferr("ERROR: mmcsd_recvR1 for CMD25 failed: %d\n", ret); + return ret; + } } /* Wait for the transfer to complete */ - ret = mmcsd_eventwait(priv, SDIOWAIT_TIMEOUT | SDIOWAIT_ERROR, nblocks * MMCSD_BLOCK_WDATADELAY); + ret = mmcsd_eventwait(priv, SDIOWAIT_TIMEOUT | SDIOWAIT_ERROR, + nblocks * MMCSD_BLOCK_WDATADELAY); if (ret != OK) { - ferr("ERROR: CMD18 transfer failed: %d\n", ret); + ferr("ERROR: CMD25 transfer failed: %d\n", ret); return ret; }