arch/arm/src/imxrt/imxrt_usdhc.c: Improve SD card handling in the DMA case. For now I think we can consider this complete for both Interrupt and DMA transfers. There is other stuff to add (high speed, low voltage, DDR etc.) later,

This commit is contained in:
Dave Marples
2018-11-13 06:41:27 -06:00
committed by Gregory Nutt
parent 50a1b9eddf
commit 9b68efe251
3 changed files with 67 additions and 49 deletions
+58 -42
View File
@@ -100,7 +100,7 @@
#define USDHC_CMDTIMEOUT MSEC2TICK(100)
#define USDHC_LONGTIMEOUT MSEC2TICK(500)
/* Big DTOCV setting. Range is 0=SDCLK*2^13 through 15=SDCLK*2^29 */
/* Big DTOCV setting. Range is 0 = SDCLK * 2^13 through 15 = SDCLK * 2^29 */
#define USDHC_DTOCV_MAXTIMEOUT (15)
@@ -110,20 +110,26 @@
/* Data transfer / Event waiting interrupt mask bits */
#define USDHC_RESPERR_INTS (USDHC_INT_CCE|USDHC_INT_CTOE|USDHC_INT_CEBE|USDHC_INT_CIE)
#define USDHC_RESPDONE_INTS (USDHC_RESPERR_INTS|USDHC_INT_CC)
#define USDHC_RESPERR_INTS (USDHC_INT_CCE | USDHC_INT_CTOE | \
USDHC_INT_CEBE | USDHC_INT_CIE)
#define USDHC_RESPDONE_INTS (USDHC_RESPERR_INTS | USDHC_INT_CC)
#define USDHC_XFRERR_INTS (USDHC_INT_DCE|USDHC_INT_DTOE|USDHC_INT_DEBE)
#define USDHC_RCVDONE_INTS (USDHC_XFRERR_INTS|USDHC_INT_BRR|USDHC_INT_TC)
#define USDHC_SNDDONE_INTS (USDHC_XFRERR_INTS|USDHC_INT_BWR|USDHC_INT_TC)
#define USDHC_XFRDONE_INTS (USDHC_XFRERR_INTS|USDHC_INT_BRR|USDHC_INT_BWR|USDHC_INT_TC)
#define USDHC_XFRERR_INTS (USDHC_INT_DCE | USDHC_INT_DTOE | \
USDHC_INT_DEBE)
#define USDHC_RCVDONE_INTS (USDHC_XFRERR_INTS | USDHC_INT_BRR | \
USDHC_INT_TC)
#define USDHC_SNDDONE_INTS (USDHC_XFRERR_INTS | USDHC_INT_BWR | \
USDHC_INT_TC)
#define USDHC_XFRDONE_INTS (USDHC_XFRERR_INTS | USDHC_INT_BRR | \
USDHC_INT_BWR | USDHC_INT_TC)
/* For DMA operations DINT is not interesting TC will indicate completions */
#define USDHC_DMAERR_INTS (USDHC_XFRERR_INTS|USDHC_INT_DMAE)
#define USDHC_DMADONE_INTS (USDHC_DMAERR_INTS|USDHC_INT_TC)
#define USDHC_DMAERR_INTS (USDHC_XFRERR_INTS | USDHC_INT_DMAE)
#define USDHC_DMADONE_INTS (USDHC_DMAERR_INTS | USDHC_INT_TC)
#define USDHC_WAITALL_INTS (USDHC_RESPDONE_INTS|USDHC_XFRDONE_INTS|USDHC_DMADONE_INTS)
#define USDHC_WAITALL_INTS (USDHC_RESPDONE_INTS | USDHC_XFRDONE_INTS | \
USDHC_DMADONE_INTS)
/* Register logging support */
@@ -170,7 +176,10 @@ struct imxrt_dev_s
/* DMA data transfer support */
#ifdef CONFIG_IMXRT_USDHC_DMA
volatile uint8_t xfrflags; /* Used to synchronize SDIO and DMA completion events */
volatile uint8_t xfrflags; /* Used to synchronize SDIO and DMA
* completion events */
uint32_t *bufferend; /* Far end of R/W buffer for cache
* invalidation purposes */
#endif
};
@@ -251,8 +260,10 @@ static void imxrt_transmit(struct imxrt_dev_s *priv);
static void imxrt_receive(struct imxrt_dev_s *priv);
#endif
static void imxrt_eventtimeout(int argc, uint32_t arg);
static void imxrt_endwait(struct imxrt_dev_s *priv, sdio_eventset_t wkupevent);
static void imxrt_endtransfer(struct imxrt_dev_s *priv, sdio_eventset_t wkupevent);
static void imxrt_endwait(struct imxrt_dev_s *priv,
sdio_eventset_t wkupevent);
static void imxrt_endtransfer(struct imxrt_dev_s *priv,
sdio_eventset_t wkupevent);
/* Interrupt Handling *******************************************************/
@@ -604,9 +615,12 @@ static void imxrt_dumpsample(struct imxrt_dev_s *priv,
#ifdef CONFIG_SDIO_XFRDEBUG
static void imxrt_dumpsamples(struct imxrt_dev_s *priv)
{
imxrt_dumpsample(priv, &g_sampleregs[SAMPLENDX_BEFORE_SETUP], "Before setup");
imxrt_dumpsample(priv, &g_sampleregs[SAMPLENDX_AFTER_SETUP], "After setup");
imxrt_dumpsample(priv, &g_sampleregs[SAMPLENDX_END_TRANSFER], "End of transfer");
imxrt_dumpsample(priv, &g_sampleregs[SAMPLENDX_BEFORE_SETUP],
"Before setup");
imxrt_dumpsample(priv, &g_sampleregs[SAMPLENDX_AFTER_SETUP],
"After setup");
imxrt_dumpsample(priv, &g_sampleregs[SAMPLENDX_END_TRANSFER],
"End of transfer");
}
#endif
@@ -646,7 +660,9 @@ static void imxrt_dataconfig(struct imxrt_dev_s *priv, bool bwrite,
unsigned int watermark;
uint32_t regval = 0;
/* Set the data timeout value in the USDHC_SYSCTL field to the selected value */
/* Set the data timeout value in the USDHC_SYSCTL field to the selected
* value.
*/
regval = getreg32(IMXRT_USDHC1_SYSCTL);
regval &= ~USDHC_SYSCTL_DTOCV_MASK;
@@ -925,7 +941,8 @@ static void imxrt_eventtimeout(int argc, uint32_t arg)
*
****************************************************************************/
static void imxrt_endwait(struct imxrt_dev_s *priv, sdio_eventset_t wkupevent)
static void imxrt_endwait(struct imxrt_dev_s *priv,
sdio_eventset_t wkupevent)
{
/* Cancel the watchdog timeout */
@@ -949,7 +966,7 @@ static void imxrt_endwait(struct imxrt_dev_s *priv, sdio_eventset_t wkupevent)
* are detected.
*
* Input Parameters:
* priv - An instance of the SDIO device interface
* priv - An instance of the SDIO device interface
* wkupevent - The event that caused the transfer to end
*
* Returned Value:
@@ -960,7 +977,8 @@ static void imxrt_endwait(struct imxrt_dev_s *priv, sdio_eventset_t wkupevent)
*
****************************************************************************/
static void imxrt_endtransfer(struct imxrt_dev_s *priv, sdio_eventset_t wkupevent)
static void imxrt_endtransfer(struct imxrt_dev_s *priv,
sdio_eventset_t wkupevent)
{
#ifdef CONFIG_IMXRT_USDHC_DMA
uint32_t regval;
@@ -973,27 +991,16 @@ static void imxrt_endtransfer(struct imxrt_dev_s *priv, sdio_eventset_t wkupeven
/* Clearing pending interrupt status on all transfer related interrupts */
putreg32(USDHC_XFRDONE_INTS, IMXRT_USDHC1_IRQSTAT);
/* If this was a DMA transfer, make sure that DMA is stopped */
#ifdef CONFIG_IMXRT_USDHC_DMA
/* Stop the DMA by resetting the data path but first save the
* state of the USDHC_PROCTL as it will be reset (in bits 24-0)
* and we will loose the DTW (4bit mode) setting
*/
proctl = getreg32(IMXRT_USDHC1_PROCTL);
regval = getreg32(IMXRT_USDHC1_SYSCTL);
regval |= USDHC_SYSCTL_RSTD;
putreg32(regval, IMXRT_USDHC1_SYSCTL);
putreg32(proctl, IMXRT_USDHC1_PROCTL);
#endif
putreg32(USDHC_XFRDONE_INTS | USDHC_DMADONE_INTS, IMXRT_USDHC1_IRQSTAT);
/* Mark the transfer finished */
priv->remaining = 0;
/* DMA modified the buffer, so we need to flush its cache lines. */
arch_invalidate_dcache(priv->buffer, priv->bufferend);
/* Debug instrumentation */
imxrt_sample(priv, SAMPLENDX_END_TRANSFER);
@@ -1230,7 +1237,8 @@ static void imxrt_reset(FAR struct sdio_dev_s *dev)
priv->waitints = 0; /* Interrupt enables for event waiting */
priv->wkupevent = 0; /* The event that caused the wakeup */
#ifdef CONFIG_IMXRT_USDHC_DMA
priv->xfrflags = 0; /* Used to synchronize SDIO and DMA completion events */
priv->xfrflags = 0; /* Used to synchronize SDIO and DMA completion
* events */
#endif
wd_cancel(priv->waitwdog); /* Cancel any timeouts */
@@ -1278,7 +1286,7 @@ static sdio_capset_t imxrt_capabilities(FAR struct sdio_dev_s *dev)
* Get SDIO status.
*
* Input Parameters:
* dev - Device-specific state data
* dev - Device-specific state data
*
* Returned Value:
* Returns a bitset of status values (see imxrt_status_* defines)
@@ -1719,7 +1727,7 @@ static int imxrt_sendcmd(FAR struct sdio_dev_s *dev, uint32_t cmd,
case MMCSD_R4_RESPONSE:
case MMCSD_R7_RESPONSE:
regval |= USDHC_XFERTYP_RSPTYP_LEN48;
break;
break;
}
/* Enable DMA */
@@ -1840,7 +1848,9 @@ static int imxrt_recvsetup(FAR struct sdio_dev_s *dev, FAR uint8_t *buffer,
imxrt_sampleinit();
imxrt_sample(priv, SAMPLENDX_BEFORE_SETUP);
/* Save the destination buffer information for use by the interrupt handler */
/* Save the destination buffer information for use by the interrupt handler
* and DMA memory invalidation.
*/
priv->buffer = (uint32_t *)buffer;
priv->remaining = nbytes;
@@ -2318,7 +2328,12 @@ static void imxrt_waitenable(FAR struct sdio_dev_s *dev,
if ((eventset & SDIOWAIT_TRANSFERDONE) != 0)
{
#ifdef CONFIG_IMXRT_USDHC_DMA
waitints |= USDHC_DMADONE_INTS;
#else
waitints |= USDHC_XFRDONE_INTS;
#endif
}
/* Enable event-related interrupts */
@@ -2472,9 +2487,9 @@ static void imxrt_callbackenable(FAR struct sdio_dev_s *dev,
* are enabled via a call to SDIO_CALLBACKENABLE
*
* Input Parameters:
* dev - Device-specific state data
* dev - Device-specific state data
* callback - The function to call on the media change
* arg - A caller provided value to return with the callback
* arg - A caller provided value to return with the callback
*
* Returned Value:
* 0 on success; negated errno on failure.
@@ -2534,6 +2549,7 @@ static int imxrt_dmarecvsetup(FAR struct sdio_dev_s *dev, FAR uint8_t *buffer,
priv->buffer = (uint32_t *)buffer;
priv->remaining = buflen;
priv->bufferend = (uint32_t *)(buffer + buflen);
/* Then set up the SDIO data path */
+8 -6
View File
@@ -4,6 +4,7 @@
* Copyright (C) 2018 Gregory Nutt. All rights reserved.
* Authors: Gregory Nutt <gnutt@nuttx.org>
* David Sidrane <david_s5@nscdg.com>
* Dave Marples <dave@marples.net>
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
@@ -170,13 +171,14 @@
/* SDIO *****************************************************************************/
/* Pin drive characteristics - drive strength in particular may need tuning for
* specific boards.
* specific boards, but has been checked by scope on the EVKB to make sure shapes
* are square with minimal ringing.
*/
#define PINSET_USDHC1_DATAX (IOMUX_SLEW_FAST | IOMUX_DRIVE_60OHM | \
#define PINSET_USDHC1_DATAX (IOMUX_SLEW_FAST | IOMUX_DRIVE_130OHM | \
IOMUX_PULL_UP_47K | IOMUX_SCHMITT_TRIGGER)
#define PINSET_USDHC1_CMD (PINSET_USDHC1_DATAX)
#define PINSET_USDHC1_CLK (IOMUX_SLEW_FAST | IOMUX_DRIVE_60OHM | IOMUX_SPEED_MAX)
#define PINSET_USDHC1_CLK (IOMUX_SLEW_FAST | IOMUX_DRIVE_130OHM | IOMUX_SPEED_MAX)
#define PINSET_USDHC1_CD (0)
#define PIN_USDHC1_D0 GPIO_USDHC1_DATA0
@@ -195,13 +197,13 @@
/* 24.8MHz for other modes */
#define BOARD_USDHC_MMCMODE_PRESCALER USDHC_SYSCTL_SDCLKFS_DIV8
#define BOARD_USDHC_MMCMODE_DIVISOR USDHC_SYSCTL_DVS_DIV(4) // FIXME 1
#define BOARD_USDHC_MMCMODE_DIVISOR USDHC_SYSCTL_DVS_DIV(1)
#define BOARD_USDHC_SD1MODE_PRESCALER USDHC_SYSCTL_SDCLKFS_DIV8
#define BOARD_USDHC_SD1MODE_DIVISOR USDHC_SYSCTL_DVS_DIV(4) // FIXME 1
#define BOARD_USDHC_SD1MODE_DIVISOR USDHC_SYSCTL_DVS_DIV(1)
#define BOARD_USDHC_SD4MODE_PRESCALER USDHC_SYSCTL_SDCLKFS_DIV8
#define BOARD_USDHC_SD4MODE_DIVISOR USDHC_SYSCTL_DVS_DIV(4) // FIXME 1
#define BOARD_USDHC_SD4MODE_DIVISOR USDHC_SYSCTL_DVS_DIV(1)
/* PIO Disambiguation ***************************************************************/
+1 -1
View File
@@ -58,7 +58,7 @@
* configuration for better standards compatibility.
*
* CONFIG_C99_BOOL8 - Means (1) your C++ compiler has sizeof(_Bool) == 8,
* (2) your C compiler supports the C99 _Bool intrinsic type, and (2) that
* (2) your C compiler supports the C99 _Bool intrinsic type, and (3) that
* the C99 _Bool type also has size 1.
*/