arch/arm/src/imxrt: This commit complete the interrupt driven USDHC1 functionality for the IMXRT EVKB. There is more work to be done to complete DMA mode and further changes will follow.

This commit is contained in:
Dave Marples 2018-11-12 13:47:44 -06:00 committed by Gregory Nutt
parent a42c5e57fc
commit 50a1b9eddf
4 changed files with 221 additions and 246 deletions

View File

@ -155,10 +155,12 @@
/* Block Attributes Register */
#define USDHC_BLKATTR_SIZE_SHIFT (0) /* Bits 0-12: Transfer Block Size */
#define USDHC_BLKATTR_SIZE_MASK (0x1fff << USDHC_BLKATTR_BLKSIZE_SHIFT)
#define USDHC_BLKATTR_SIZE_MASK (0x1fff << USDHC_BLKATTR_SIZE_SHIFT)
# define USDHC_BLKATTR_SIZE(n) ((n) << USDHC_BLKATTR_SIZE_SHIFT)
/* Bits 13-15: Reserved */
#define USDHC_BLKATTR_CNT_SHIFT (16) /* Bits 16-31: Blocks Count For Current Transfer */
#define USDHC_BLKATTR_CNT_MASK (0xffff << USDHC_BLKATTR_BLKCNT_SHIFT)
#define USDHC_BLKATTR_CNT_MASK (0xffff << USDHC_BLKATTR_CNT_SHIFT)
# define USDHC_BLKATTR_CNT(n) ((n) << USDHC_BLKATTR_CNT_SHIFT)
/* Command Argument Register (32-bit cmd/arg data) */
@ -266,7 +268,7 @@
#define USDHC_SYSCTL_RES0 (0x0F << 0) /* Bit 0-3: Reserved, set to 1 */
#define USDHC_SYSCTL_DVS_SHIFT (4) /* Bits 4-7: Divisor */
#define USDHC_SYSCTL_DVS_MASK (0x0f << USDHC_SYSCTL_DVS_SHIFT)
# define USDHC_SYSCTL_DVS_DIV(n) (((n)-1) << USDHC_SYSCTL_DVS_SHIFT) /* Divide by n, n=1..16 */
# define USDHC_SYSCTL_DVS_DIV(n) (((n) - 1) << USDHC_SYSCTL_DVS_SHIFT) /* Divide by n, n=1..16 */
#define USDHC_SYSCTL_SDCLKFS_SHIFT (8) /* Bits 8-15: SDCLK Frequency Select */
#define USDHC_SYSCTL_SDCLKFS_MASK (0xff << USDHC_SYSCTL_SDCLKFS_SHIFT)
# define USDHC_SYSCTL_SDCLKFS_BYPASS (0x00 << USDHC_SYSCTL_SDCLKFS_SHIFT) /* Bypass the prescaler */
@ -280,7 +282,7 @@
# define USDHC_SYSCTL_SDCLKFS_DIV256 (0x80 << USDHC_SYSCTL_SDCLKFS_SHIFT) /* Base clock / 256 */
#define USDHC_SYSCTL_DTOCV_SHIFT (16) /* Bits 16-19: Data Timeout Counter Value */
#define USDHC_SYSCTL_DTOCV_MASK (0x0f << USDHC_SYSCTL_DTOCV_SHIFT)
# define USDHC_SYSCTL_DTOCV_MUL(n) (((n)-213) << USDHC_SYSCTL_DTOCV_SHIFT) /* SDCLK x n, n=213..227 */
# define USDHC_SYSCTL_DTOCV_MUL(n) (((n) - 213) << USDHC_SYSCTL_DTOCV_SHIFT) /* SDCLK x n, n=213..227 */
/* Bits 20-22: Reserved */
#define USDHC_SYSCTL_IPPRSTN (1 << 23) /* Bit 23: Card /reset (default 1) */
#define USDHC_SYSCTL_RSTA (1 << 24) /* Bit 24: Software Reset For ALL */
@ -346,7 +348,7 @@
/* Bits 3-7: Reserved */
#define USDHC_HTCAPBLT_TCR_SHIFT (8) /* Bits 8-11: Time count retuning */
#define USDHC_HTCAPBLT_TCR_MASK (0xF << USDHC_HTCAPBLT_TCR_SHIFT)
#define USDHC_HTCAPBLT_TCR(x) (((x)&0x0f) << USDHC_HTCAPBLT_TCR_SHIFT)
# define USDHC_HTCAPBLT_TCR(n) ((n) << USDHC_HTCAPBLT_TCR_SHIFT)
#define USDHC_HTCAPBLT_USE_TUNING_SDR50 (1 << 13) /* Bit 13: Use tuning for SDR50 */
#define USDHC_HTCAPBLT_RET_MODE_SHIFT (14) /* bit 14-15: Retuning mode */
#define USDHC_HTCAPBLT_RET_MODE_MASK (3<<SDHC_HTCAPBLT_RET_MODE_SHIFT)
@ -373,17 +375,17 @@
#define USDHC_WML_RD_SHIFT (0) /* Bits 0-7: Read Watermark Level */
#define USDHC_WML_RD_MASK (0xff << USDHC_WML_RDWML_SHIFT)
#define USDHC_WML_RD(x) ((x)&0xff)<<SDHC_WML_RDWML_SHIFT)
# define USDHC_WML_RD(n) ((n) << SDHC_WML_RDWML_SHIFT)
#define USDHC_WML_RD_BL_SHIFT (8) /* Bits 8-12: Read Watermark Burst Length */
#define USDHC_WML_RD_BL_MASK (0x1f << USDHC_WML_RD_BL_SHIFT)
#define USDHC_WML_RD_BL(x) (((x)&0x1f)<<SDHC_WML_RD_BLL_SHIFT)
# define USDHC_WML_RD_BL(n) ((n) << SDHC_WML_RD_BLL_SHIFT)
/* Bits 13-15: Reserved */
#define USDHC_WML_WR_SHIFT (16) /* Bits 16-23: Write Watermark Level */
#define USDHC_WML_WR_MASK (0xff << USDHC_WML_WRWML_SHIFT)
#define USDHC_WML_WR(x) ((x)&0xff)<<SDHC_WML_WRWML_SHIFT)
# define USDHC_WML_WR(n) ((n) << SDHC_WML_WRWML_SHIFT)
#define USDHC_WML_WR_BL_SHIFT (24) /* Bits 24-28: Write Watermark Burst Length */
#define USDHC_WML_WR_BL_MASK (0x1f << USDHC_WML_WD_BL_SHIFT)
#define USDHC_WML_WR_BL(x) (((x)&0x1f)<<SDHC_WML_WD_BLL_SHIFT)
# define USDHC_WML_WR_BL(n) ((n) << SDHC_WML_WD_BLL_SHIFT)
/* Bits 29-31: Reserved */
/* Mixer Control Register */
@ -453,22 +455,22 @@
#define USDHC_DL_CTRL_SLV_FORCE_UP (1 << 2) /* Bit 2: SLV Force update */
#define USDHC_DL_SLV_DLY_TGT0_SHIFT (3) /* Bits 3-6: Delay Target 0 */
#define USDHC_DL_SLV_DLY_TGT0_MASK (0xf << USDHC_DL_SLV_DLY_TGT0_SHIFT)
# define USDHC_DL_SLV_DLY_TGT0(x) (((x)&0x0f) << USDHC_DL_SLV_DLY_TGT0_SHIFT)
# define USDHC_DL_SLV_DLY_TGT0(n) ((n) << USDHC_DL_SLV_DLY_TGT0_SHIFT)
#define USDHC_DL_CTRL_SLV_UPD (1 << 7) /* Bit 7: Delay Control Gate update */
#define USDHC_DL_CTRL_SLV_OVR (1 << 8) /* Bit 8: Delay Control Gate override */
#define USDHC_DL_CTRL_OVR_VAL_SHIFT (9) /* Bits 9-15: Override Value */
#define USDHC_DL_CTRL_OVR_VAL_MASK (0x7f << USDHC_DL_CTRL_OVR_VAL_SHIFT)
# define USDHC_DL_CTRL_OVR_VAL(x) (((x)&0x7f) << USDHC_DL_CTRL_OVR_VAL_SHIFT)
# define USDHC_DL_CTRL_OVR_VAL(n) ((n) << USDHC_DL_CTRL_OVR_VAL_SHIFT)
#define USDHC_DL_SLV_DLY_TGT1_SHIFT (16) /* Bits 16-18: Delay Target 1 */
#define USDHC_DL_SLV_DLY_TGT1_MASK (0x7 << USDHC_DL_SLV_DLY_TGT1_SHIFT)
# define USDHC_DL_SLV_DLY_TGT1(x) (((x)&0x07) << USDHC_DL_SLV_DLY_TGT1_SHIFT)
# define USDHC_DL_SLV_DLY_TGT1(n) ((n) << USDHC_DL_SLV_DLY_TGT1_SHIFT)
/* Bit 19: Reserved */
#define USDHC_DL_CTRL_SLV_UPDINT_SHIFT (20) /* Bits 20-27: DLL Control SLV Update Interval */
#define USDHC_DL_CTRL_SLV_UPDINT_MASK (0xff << USDHC_DL_CTRL_SLV_UPDINT_SHIFT)
# define USDHC_DL_CTRL_SLV_UPDINT(x) (((x)&0xff) << USDHC_DL_CTRL_SLV_UPDINT_SHIFT)
# define USDHC_DL_CTRL_SLV_UPDINT(n) ((n) << USDHC_DL_CTRL_SLV_UPDINT_SHIFT)
#define USDHC_DL_CTRL_REF_UPDINT_SHIFT (28) /* Bits 28-31: DLL Control Refernce Update Interval */
#define USDHC_DL_CTRL_REF_UPDINT_MASK (0xf << USDHC_DL_CTRL_REF_UPDINT_SHIFT)
# define USDHC_DL_CTRL_REF_UPDINT(x) (((x)&0xf) << USDHC_DL_CTRL_REF_UPDINT_SHIFT)
# define USDHC_DL_CTRL_REF_UPDINT(n) ((n)<< USDHC_DL_CTRL_REF_UPDINT_SHIFT)
/* Delay Line Status */
@ -476,10 +478,10 @@
#define USDHC_DL_STAT_REF_LOCK (1 << 1) /* Bit 1: Reference delay-line lock status */
#define USDHC_DL_STAT_SLV_SEL_SHIFT (2) /* Bits 2-8: Slave delay line select status */
#define USDHC_DL_STAT_SLV_SEL_MASK (0x7f << USDHC_DL_STAT_SLV_SEL_SHIFT)
# define USDHC_DL_STAT_SLV_SEL(x) (((x)&0x07f) << USDHC_DL_STAT_SLV_SEL_SHIFT)
# define USDHC_DL_STAT_SLV_SEL(n) ((n) << USDHC_DL_STAT_SLV_SEL_SHIFT)
#define USDHC_DL_STAT_REF_SEL_SHIFT (9) /* Bits 9-15: Reference delay line select taps */
#define USDHC_DL_STAT_REF_SEL_MASK (0x7f << USDHC_DL_STAT_REF_SEL_SHIFT)
# define USDHC_DL_STAT_REF_SEL(x) (((x)&0x07f) << USDHC_DL_STAT_REF_SEL_SHIFT)
# define USDHC_DL_STAT_REF_SEL(n) ((n) << USDHC_DL_STAT_REF_SEL_SHIFT)
/* Bits 16-31: Reserved */
/* Clk tuning control and status */
@ -500,7 +502,7 @@
#define USDHC_MMCBOOT_DTOCVACK_SHIFT (0) /* Bits 0-3: Boot ACK time out counter value */
#define USDHC_MMCBOOT_DTOCVACK_MASK (0x0f << USDHC_MMCBOOT_DTOCVACK_SHIFT)
# define USDHC_MMCBOOT_DTOCVACK_MUL(n) ((n-8) << USDHC_MMCBOOT_DTOCVACK_SHIFT) /* SDCLK x 2^n, n=8..22 */
# define USDHC_MMCBOOT_DTOCVACK_MUL(n) ((n - 8) << USDHC_MMCBOOT_DTOCVACK_SHIFT) /* SDCLK x 2^n, n=8..22 */
#define USDHC_MMCBOOT_BOOTACK (1 << 4) /* Bit 4: Boot ack mode select */
#define USDHC_MMCBOOT_BOOTMODE (1 << 5) /* Bit 5: Boot mode select */
#define USDHC_MMCBOOT_BOOTEN (1 << 6) /* Bit 6: Boot mode enable */
@ -526,14 +528,14 @@
#define USDHC_TC_STARTTAP_SHIFT (0) /* Bits 0-7: Start TAP for CMD19 tuning */
#define USDHC_TC_STARTTAP_MASK (0xff << USDHC_TC_STARTTAP_SHIFT)
# define USDHC_TC_STARTTAP(x) (((x)&0xff) << USDHC_TC_STARTTAP_SHIFT)
# define USDHC_TC_STARTTAP(n) ((n) << USDHC_TC_STARTTAP_SHIFT)
#define USDHC_TC_COUNT_SHIFT (8) /* Bits 8-25: Count for CMD19 tuning */
#define USDHC_TC_COUNT_MASK (0xff << USDHC_TC_COUNT_SHIFT)
# define USDHC_TC_COUNT(x) (((x)&0xff) << USDHC_TC_COUNT_SHIFT)
# define USDHC_TC_COUNT(n) ((n) << USDHC_TC_COUNT_SHIFT)
/* Bit 19: Reserved */
#define USDHC_TC_WINDOW_SHIFT (20) /* Bits 20-22: Tuning window */
#define USDHC_TC_WINDOW_MASK (0x7 << USDHC_TC_WINDOWS_SHIFT)
# define USDHC_TC_WINDOW(x) (((x)&7) << USDHC_TC_WINDOW_SHIFT)
# define USDHC_TC_WINDOW(n) ((n) << USDHC_TC_WINDOW_SHIFT)
/* Bit 23: Reserved */
#define USDHC_TC_TUNINGEN (1 << 24) /* Bit 24: Tuning enable */
/* Bits 25-31: Reserved */

View File

@ -234,10 +234,10 @@ void imxrt_clockconfig(void)
reg = getreg32(IMXRT_CCM_CSCMR1);
reg &= ~(CCM_CSCMR1_USDHC1_CLK_SEL | CCM_CSCMR1_USDHC2_CLK_SEL);
#if defined(IMXRT_USDHC1_CLK_SELECT)
reg |= IMXRT_USDHC1_CLK_SELECT
reg |= IMXRT_USDHC1_CLK_SELECT;
#endif
#if defined(IMXRT_USDHC2_CLK_SELECT)
reg |= IMXRT_USDHC2_CLK_SELECT
reg |= IMXRT_USDHC2_CLK_SELECT;
#endif
putreg32(reg, IMXRT_CCM_CSCMR1);

View File

@ -3,6 +3,7 @@
*
* Copyright (C) 2018 Gregory Nutt. All rights reserved.
* Author: Gregory Nutt <gnutt@nuttx.org>
* Dave Marples <dave@marples.net>
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
@ -86,19 +87,14 @@
# error "Callback support requires CONFIG_SCHED_WORKQUEUE and CONFIG_SCHED_HPWORK"
#endif
#if !defined(CONFIG_SDIO_BLOCKSETUP)
# error "CONFIG_SDIO_BLOCKSETUP is mandatory for this driver"
#endif
#ifndef CONFIG_DEBUG_MEMCARD_INFO
# undef CONFIG_SDIO_XFRDEBUG
#endif
/* SDCLK frequencies corresponding to various modes of operation. These
* values may be provided in either the NuttX configuration file or in
* the board.h file
*
* NOTE: These settings are not currently used. Since there are only four
* frequencies, it makes more sense to just "can" the fixed frequency prescaler
* and divider values.
*/
/* Timing in ms for commands wait response */
#define USDHC_CMDTIMEOUT MSEC2TICK(100)
@ -249,9 +245,7 @@ static void imxrt_showregs(struct imxrt_dev_s *priv, const char *msg);
/* Data Transfer Helpers ****************************************************/
static void imxrt_dataconfig(struct imxrt_dev_s *priv, bool bwrite,
unsigned int blocksize, unsigned int nblocks,
unsigned int timeout);
static void imxrt_datadisable(void);
unsigned int dataLen, unsigned int timeout);
#ifndef CONFIG_IMXRT_USDHC_DMA
static void imxrt_transmit(struct imxrt_dev_s *priv);
static void imxrt_receive(struct imxrt_dev_s *priv);
@ -289,6 +283,11 @@ static int imxrt_attach(FAR struct sdio_dev_s *dev);
static int imxrt_sendcmd(FAR struct sdio_dev_s *dev, uint32_t cmd,
uint32_t arg);
#ifdef CONFIG_SDIO_BLOCKSETUP
static void imxrt_blocksetup(FAR struct sdio_dev_s *dev,
unsigned int blocklen, unsigned int nblocks);
#endif
#ifndef CONFIG_IMXRT_USDHC_DMA
static int imxrt_recvsetup(FAR struct sdio_dev_s *dev, FAR uint8_t *buffer,
size_t nbytes);
@ -349,6 +348,10 @@ struct imxrt_dev_s g_sdhcdev =
.clock = imxrt_clock,
.attach = imxrt_attach,
.sendcmd = imxrt_sendcmd,
#ifdef CONFIG_SDIO_BLOCKSETUP
.blocksetup = imxrt_blocksetup,
#endif
#ifndef CONFIG_IMXRT_USDHC_DMA
.recvsetup = imxrt_recvsetup,
.sendsetup = imxrt_sendsetup,
@ -459,8 +462,7 @@ static void imxrt_configwaitints(struct imxrt_dev_s *priv, uint32_t waitints,
#ifdef CONFIG_IMXRT_USDHC_DMA
priv->xfrflags = 0;
#endif
putreg32(priv->xfrints | priv->waitints | USDHC_INT_CINT,
IMXRT_USDHC1_IRQSIGEN);
putreg32(priv->xfrints | priv->waitints, IMXRT_USDHC1_IRQSIGEN);
leave_critical_section(flags);
}
@ -485,8 +487,7 @@ static void imxrt_configxfrints(struct imxrt_dev_s *priv, uint32_t xfrints)
flags = enter_critical_section();
priv->xfrints = xfrints;
putreg32(priv->xfrints | priv->waitints | USDHC_INT_CINT,
IMXRT_USDHC1_IRQSIGEN);
putreg32(priv->xfrints | priv->waitints, IMXRT_USDHC1_IRQSIGEN);
leave_critical_section(flags);
}
@ -640,8 +641,7 @@ static void imxrt_showregs(struct imxrt_dev_s *priv, const char *msg)
****************************************************************************/
static void imxrt_dataconfig(struct imxrt_dev_s *priv, bool bwrite,
unsigned int blocksize, unsigned int nblocks,
unsigned int timeout)
unsigned int dataLen, unsigned int timeout)
{
unsigned int watermark;
uint32_t regval = 0;
@ -653,23 +653,15 @@ static void imxrt_dataconfig(struct imxrt_dev_s *priv, bool bwrite,
regval |= timeout << USDHC_SYSCTL_DTOCV_SHIFT;
putreg32(regval, IMXRT_USDHC1_SYSCTL);
/* Set the block size and count in the USDHC_BLKATTR register. The block
* size is only valid for multiple block transfers.
*/
regval = blocksize << USDHC_BLKATTR_SIZE_SHIFT |
nblocks << USDHC_BLKATTR_CNT_SHIFT;
putreg32(regval, IMXRT_USDHC1_BLKATTR);
/* Set the watermark level */
/* Set the Read Watermark Level to the blocksize to be read
/* Set the Read Watermark Level to the dataLen to be read
* (limited to half of the maximum watermark value). BRR will be
* set when the number of queued words is greater than or equal
* to this value.
*/
watermark = (blocksize + 3) >> 2;
watermark = (dataLen + 3) >> 2;
if (watermark > (USDHC_MAX_WATERMARK / 2))
{
watermark = (USDHC_MAX_WATERMARK / 2);
@ -704,28 +696,6 @@ static void imxrt_dataconfig(struct imxrt_dev_s *priv, bool bwrite,
}
}
/****************************************************************************
* Name: imxrt_datadisable
*
* Description:
* Disable the SDIO data path setup by imxrt_dataconfig() and
* disable DMA.
*
****************************************************************************/
static void imxrt_datadisable(void)
{
/* Set the data timeout value in the USDHC_SYSCTL field to the maximum value */
modifyreg32(IMXRT_USDHC1_SYSCTL,
USDHC_SYSCTL_DTOCV_MASK,
USDHC_DTOCV_MAXTIMEOUT << USDHC_SYSCTL_DTOCV_SHIFT);
/* Set the block size to zero (no transfer) */
putreg32(0, IMXRT_USDHC1_BLKATTR);
}
/****************************************************************************
* Name: imxrt_transmit
*
@ -1065,17 +1035,12 @@ static int imxrt_interrupt(int irq, void *context, FAR void *arg)
* there are non-zero bits remaining, then we have work to do here.
*/
mcerr("**");
regval = getreg32(IMXRT_USDHC1_IRQSIGEN);
enabled = getreg32(IMXRT_USDHC1_IRQSTAT) & regval;
mcinfo("IRQSTAT: %08x IRQSIGEN %08x enabled: %08x\n",
getreg32(IMXRT_USDHC1_IRQSTAT), regval, enabled);
/* Disable card interrupts to clear the card interrupt to the host system. */
regval &= ~USDHC_INT_CINT;
putreg32(regval, IMXRT_USDHC1_IRQSIGEN);
/* Clear all pending interrupts */
putreg32(enabled, IMXRT_USDHC1_IRQSTAT);
@ -1164,12 +1129,6 @@ static int imxrt_interrupt(int irq, void *context, FAR void *arg)
}
}
/* Re-enable card interrupts */
regval = getreg32(IMXRT_USDHC1_IRQSIGEN);
regval |= USDHC_INT_CINT;
putreg32(regval, IMXRT_USDHC1_IRQSIGEN);
return OK;
}
@ -1244,7 +1203,7 @@ static void imxrt_reset(FAR struct sdio_dev_s *dev)
{
}
minfo("Reset complete\n");
mcinfo("Reset complete\n");
/* Make sure that all clocking is disabled */
@ -1255,7 +1214,6 @@ static void imxrt_reset(FAR struct sdio_dev_s *dev)
*/
putreg32(USDHC_INT_ALL, IMXRT_USDHC1_IRQSTATEN);
imxrt_datadisable();
mcinfo("SYSCTL: %08x PRSSTAT: %08x IRQSTATEN: %08x\n",
getreg32(IMXRT_USDHC1_SYSCTL), getreg32(IMXRT_USDHC1_PRSSTAT),
@ -1550,8 +1508,8 @@ static void imxrt_clock(FAR struct sdio_dev_s *dev, enum sdio_clock_e rate)
/* Select the new prescaler and divisor values based on the requested mode
* and the settings from the board.h file.
*
* TODO: Investigate using the automatically gated clocks to reduce power
* consumption.
* Clocks are automatically gated by the driver when not needed.
*
*/
switch (rate)
@ -1568,26 +1526,36 @@ static void imxrt_clock(FAR struct sdio_dev_s *dev, enum sdio_clock_e rate)
case CLOCK_IDMODE : /* Initial ID mode clocking (<400KHz) */
mcinfo("IDMODE\n");
regval |= (BOARD_USDHC_IDMODE_PRESCALER | BOARD_USDHC_IDMODE_DIVISOR);
/* Put out an additional 80 clocks in case this is a power-up sequence */
regval |= (BOARD_USDHC_IDMODE_PRESCALER |
BOARD_USDHC_IDMODE_DIVISOR | USDHC_SYSCTL_INITA);
break;
case CLOCK_MMC_TRANSFER : /* MMC normal operation clocking */
mcinfo("MMCTRANSFER\n");
regval |= (BOARD_USDHC_MMCMODE_PRESCALER | BOARD_USDHC_MMCMODE_DIVISOR);
regval |= (BOARD_USDHC_MMCMODE_PRESCALER |
BOARD_USDHC_MMCMODE_DIVISOR);
break;
case CLOCK_SD_TRANSFER_1BIT : /* SD normal operation clocking (narrow
* 1-bit mode) */
#ifndef CONFIG_IMXRT_USDHC_WIDTH_D1_ONLY
mcinfo("1BITTRANSFER\n");
regval |= (BOARD_USDHC_SD1MODE_PRESCALER | BOARD_USDHC_SD1MODE_DIVISOR);
regval |= (BOARD_USDHC_SD1MODE_PRESCALER |
BOARD_USDHC_SD1MODE_DIVISOR);
break;
#endif
case CLOCK_SD_TRANSFER_4BIT : /* SD normal operation clocking (wide
* 4-bit mode) */
mcinfo("4BITTRANSFER\n");
regval |= (BOARD_USDHC_SD4MODE_PRESCALER | BOARD_USDHC_SD4MODE_DIVISOR);
regval |= (BOARD_USDHC_SD4MODE_PRESCALER |
BOARD_USDHC_SD4MODE_DIVISOR);
break;
}
@ -1657,8 +1625,9 @@ static int imxrt_attach(FAR struct sdio_dev_s *dev)
* None
*
****************************************************************************/
static int imxrt_sendcmd(FAR struct sdio_dev_s *dev, uint32_t cmd,
uint32_t arg)
uint32_t arg)
{
clock_t timeout;
clock_t start;
@ -1667,111 +1636,90 @@ static int imxrt_sendcmd(FAR struct sdio_dev_s *dev, uint32_t cmd,
uint32_t mcrregval;
uint32_t cmdidx;
#if 1==0
regval = getreg32(IMXRT_USDHC1_SYSCTL);
regval |= USDHC_SYSCTL_RSTC;
putreg32(regval, IMXRT_USDHC1_SYSCTL);
while ((getreg32(IMXRT_USDHC1_SYSCTL) & USDHC_SYSCTL_RSTC) != 0)
{
}
#endif
regval = getreg32(IMXRT_USDHC1_PRSSTAT);
/* Initialize the command index */
cmdidx = (cmd & MMCSD_CMDIDX_MASK) >> MMCSD_CMDIDX_SHIFT;
regval = cmdidx << USDHC_XFERTYP_CMDINX_SHIFT;
mcrregval = USDHC_MC_DEFAULTVAL;
/* Does a data transfer accompany the command? */
/* Check if a data transfer accompanies the command */
if ((cmd & MMCSD_DATAXFR) != 0)
switch (cmd & MMCSD_DATAXFR_MASK)
{
/* Yes.. Configure the data transfer */
default:
case MMCSD_NODATAXFR : /* No.. no data transfer */
break;
switch (cmd & MMCSD_DATAXFR_MASK)
{
default:
case MMCSD_NODATAXFR : /* No.. no data transfer */
break;
/* The following two cases are probably missing some setup logic */
/* The following two cases are probably missing some setup logic */
case MMCSD_RDSTREAM : /* Yes.. streaming read data transfer */
regval |= USDHC_XFERTYP_DPSEL;
mcrregval |= USDHC_MC_DTDSEL;
break;
case MMCSD_RDSTREAM : /* Yes.. streaming read data transfer */
regval |= USDHC_XFERTYP_DPSEL;
mcrregval |= USDHC_MC_DTDSEL;
break;
case MMCSD_WRSTREAM : /* Yes.. streaming write data transfer */
regval |= USDHC_XFERTYP_DPSEL;
break;
case MMCSD_WRSTREAM : /* Yes.. streaming write data transfer */
regval |= USDHC_XFERTYP_DPSEL;
break;
case MMCSD_RDDATAXFR : /* Yes.. normal read data transfer */
regval |= USDHC_XFERTYP_DPSEL;
mcrregval |= USDHC_MC_DTDSEL;
break;
case MMCSD_RDDATAXFR : /* Yes.. normal read data transfer */
regval |= USDHC_XFERTYP_DPSEL;
mcrregval |= USDHC_MC_DTDSEL;
break;
case MMCSD_WRDATAXFR : /* Yes.. normal write data transfer */
regval |= USDHC_XFERTYP_DPSEL;
break;
}
/* Is it a multi-block transfer? */
if ((cmd & MMCSD_MULTIBLOCK) != 0)
{
/* Yes.. should the transfer be stopped with ACMD12? */
if ((cmd & MMCSD_STOPXFR) != 0)
{
/* Yes.. Indefinite block transfer */
mcrregval |= USDHC_MC_MSBSEL | USDHC_MC_AC12EN;
}
else
{
/* No.. Fixed block transfer */
mcrregval |= USDHC_MC_MSBSEL | USDHC_MC_BCEN;
}
}
case MMCSD_WRDATAXFR : /* Yes.. normal write data transfer */
regval |= USDHC_XFERTYP_DPSEL;
break;
}
else
/* Is it a multi-block transfer? */
if ((cmd & MMCSD_MULTIBLOCK) != 0)
{
mcrregval |= USDHC_MC_DTDSEL;
/* Yes.. should the transfer be stopped with ACMD12? */
if ((cmd & MMCSD_STOPXFR) != 0)
{
/* Yes.. Indefinite block transfer */
mcrregval |= USDHC_MC_MSBSEL | USDHC_MC_AC12EN;
}
else
{
/* No.. Fixed block transfer */
mcrregval |= USDHC_MC_MSBSEL | USDHC_MC_BCEN;
}
}
/* Configure response type bits */
switch (cmd & MMCSD_RESPONSE_MASK)
{
case MMCSD_NO_RESPONSE: /* No response */
regval |= USDHC_XFERTYP_RSPTYP_NONE;
break;
case MMCSD_NO_RESPONSE: /* No response */
regval |= USDHC_XFERTYP_RSPTYP_NONE;
break;
case MMCSD_R1B_RESPONSE: /* Response length 48, check busy & cmdindex */
regval |= (USDHC_XFERTYP_RSPTYP_LEN48BSY | USDHC_XFERTYP_CICEN |
USDHC_XFERTYP_CCCEN);
break;
case MMCSD_R1B_RESPONSE: /* Response length 48, check busy & cmdindex */
regval |= (USDHC_XFERTYP_RSPTYP_LEN48BSY | USDHC_XFERTYP_CICEN |
USDHC_XFERTYP_CCCEN);
break;
case MMCSD_R1_RESPONSE: /* Response length 48, check cmdindex */
case MMCSD_R5_RESPONSE:
case MMCSD_R6_RESPONSE:
regval |= (USDHC_XFERTYP_RSPTYP_LEN48 | USDHC_XFERTYP_CICEN |
USDHC_XFERTYP_CCCEN);
break;
case MMCSD_R1_RESPONSE: /* Response length 48, check cmdindex */
case MMCSD_R5_RESPONSE:
case MMCSD_R6_RESPONSE:
regval |= (USDHC_XFERTYP_RSPTYP_LEN48 | USDHC_XFERTYP_CICEN |
USDHC_XFERTYP_CCCEN);
break;
case MMCSD_R2_RESPONSE: /* Response length 136, check CRC */
regval |= (USDHC_XFERTYP_RSPTYP_LEN136 | USDHC_XFERTYP_CCCEN);
break;
case MMCSD_R2_RESPONSE: /* Response length 136, check CRC */
regval |= (USDHC_XFERTYP_RSPTYP_LEN136 | USDHC_XFERTYP_CCCEN);
break;
case MMCSD_R3_RESPONSE: /* Response length 48 */
case MMCSD_R4_RESPONSE:
case MMCSD_R7_RESPONSE:
regval |= USDHC_XFERTYP_RSPTYP_LEN48;
break;
case MMCSD_R3_RESPONSE: /* Response length 48 */
case MMCSD_R4_RESPONSE:
case MMCSD_R7_RESPONSE:
regval |= USDHC_XFERTYP_RSPTYP_LEN48;
break;
}
/* Enable DMA */
@ -1793,7 +1741,8 @@ static int imxrt_sendcmd(FAR struct sdio_dev_s *dev, uint32_t cmd,
* indicates that the CMD line is not in use and the USDHC can issue a
* SD/MMC Command using the CMD line.
*
* CIHB should always be clear before this function is called.
* CIHB should always be clear before this function is called, but this
* check is performed here to provide overlap and maximum performance.
*/
timeout = USDHC_CMDTIMEOUT;
@ -1806,7 +1755,7 @@ static int imxrt_sendcmd(FAR struct sdio_dev_s *dev, uint32_t cmd,
elapsed = clock_systimer() - start;
if (elapsed >= timeout)
{
mcerr("ERROR: Timeout cmd: %08x PRSSTAT: %08x\n",
mcerr("ERROR: Timeout (waiting CIHB) cmd: %08x PRSSTAT: %08x\n",
cmd, getreg32(IMXRT_USDHC1_PRSSTAT));
return -EBUSY;
@ -1823,15 +1772,39 @@ static int imxrt_sendcmd(FAR struct sdio_dev_s *dev, uint32_t cmd,
putreg32(mcrregval, IMXRT_USDHC1_MIX);
putreg32(regval, IMXRT_USDHC1_XFERTYP);
start = 0;
while ((getreg32(IMXRT_USDHC1_PRSSTAT) & USDHC_PRSSTAT_CIHB) != 0)
{
start++;
}
return OK;
}
/****************************************************************************
* Name: imxrt_blocksetup
*
* Description:
* Configure block size and the number of blocks for next transfer
*
* Input Parameters:
* dev - An instance of the SDIO device interface
* blocklen - The selected block size.
* nblocklen - The number of blocks to transfer
*
* Returned Value:
* None
*
****************************************************************************/
#ifdef CONFIG_SDIO_BLOCKSETUP
static void imxrt_blocksetup(FAR struct sdio_dev_s *dev,
unsigned int blocklen, unsigned int nblocks)
{
mcinfo("blocklen=%ld, total transfer=%ld (%ld blocks)\n",
blocklen, blocklen * nblocks, nblocks);
/* Configure block size for next transfer */
putreg32(USDHC_BLKATTR_SIZE(blocklen) | USDHC_BLKATTR_CNT(nblocks),
IMXRT_USDHC1_BLKATTR);
}
#endif
/****************************************************************************
* Name: imxrt_recvsetup
*
@ -1864,7 +1837,6 @@ static int imxrt_recvsetup(FAR struct sdio_dev_s *dev, FAR uint8_t *buffer,
/* Reset the DPSM configuration */
imxrt_datadisable();
imxrt_sampleinit();
imxrt_sample(priv, SAMPLENDX_BEFORE_SETUP);
@ -1875,7 +1847,7 @@ static int imxrt_recvsetup(FAR struct sdio_dev_s *dev, FAR uint8_t *buffer,
/* Then set up the SDIO data path */
imxrt_dataconfig(priv, false, nbytes, 1, USDHC_DTOCV_MAXTIMEOUT);
imxrt_dataconfig(priv, false, nbytes, USDHC_DTOCV_MAXTIMEOUT);
/* And enable interrupts */
@ -1915,7 +1887,6 @@ static int imxrt_sendsetup(FAR struct sdio_dev_s *dev,
/* Reset the DPSM configuration */
imxrt_datadisable();
imxrt_sampleinit();
imxrt_sample(priv, SAMPLENDX_BEFORE_SETUP);
@ -1926,7 +1897,7 @@ static int imxrt_sendsetup(FAR struct sdio_dev_s *dev,
/* Then set up the SDIO data path */
imxrt_dataconfig(priv, true, nbytes, 1, USDHC_DTOCV_MAXTIMEOUT);
imxrt_dataconfig(priv, true, nbytes, USDHC_DTOCV_MAXTIMEOUT);
/* Enable TX interrupts */
@ -2019,31 +1990,31 @@ static int imxrt_waitresponse(FAR struct sdio_dev_s *dev, uint32_t cmd)
switch (cmd & MMCSD_RESPONSE_MASK)
{
case MMCSD_NO_RESPONSE:
timeout = USDHC_CMDTIMEOUT;
errors = 0;
return OK;
case MMCSD_NO_RESPONSE:
timeout = USDHC_CMDTIMEOUT;
errors = 0;
return OK;
case MMCSD_R1_RESPONSE:
case MMCSD_R1B_RESPONSE:
case MMCSD_R2_RESPONSE:
case MMCSD_R6_RESPONSE:
timeout = USDHC_LONGTIMEOUT;
errors = USDHC_RESPERR_INTS;
break;
case MMCSD_R1_RESPONSE:
case MMCSD_R1B_RESPONSE:
case MMCSD_R2_RESPONSE:
case MMCSD_R6_RESPONSE:
timeout = USDHC_LONGTIMEOUT;
errors = USDHC_RESPERR_INTS;
break;
case MMCSD_R4_RESPONSE:
case MMCSD_R5_RESPONSE:
return -ENOSYS;
case MMCSD_R4_RESPONSE:
case MMCSD_R5_RESPONSE:
return -ENOSYS;
case MMCSD_R3_RESPONSE:
case MMCSD_R7_RESPONSE:
timeout = USDHC_CMDTIMEOUT;
errors = USDHC_RESPERR_INTS;
break;
case MMCSD_R3_RESPONSE:
case MMCSD_R7_RESPONSE:
timeout = USDHC_CMDTIMEOUT;
errors = USDHC_RESPERR_INTS;
break;
default:
return -EINVAL;
default:
return -EINVAL;
}
/* Then wait for the Command Complete (CC) indication (or timeout). The
@ -2097,9 +2068,9 @@ static int imxrt_waitresponse(FAR struct sdio_dev_s *dev, uint32_t cmd)
*
* Returned Value:
* Number of bytes sent on success; a negated errno on failure. Here a
* failure means only a faiure to obtain the requested reponse (due to
* failure means only a failure to obtain the requested response (due to
* transport problem -- timeout, CRC, etc.). The implementation only
* assures that the response is returned intacta and does not check errors
* assures that the response is returned intact and does not check errors
* within the response itself.
*
****************************************************************************/
@ -2554,10 +2525,6 @@ static int imxrt_dmarecvsetup(FAR struct sdio_dev_s *dev, FAR uint8_t *buffer,
DEBUGASSERT(priv != NULL && buffer != NULL && buflen > 0);
DEBUGASSERT(((uint32_t)buffer & 3) == 0);
/* Reset the DPSM configuration */
imxrt_datadisable();
/* Begin sampling register values */
imxrt_sampleinit();
@ -2570,7 +2537,7 @@ static int imxrt_dmarecvsetup(FAR struct sdio_dev_s *dev, FAR uint8_t *buffer,
/* Then set up the SDIO data path */
imxrt_dataconfig(priv, false, buflen, 1, USDHC_DTOCV_MAXTIMEOUT);
imxrt_dataconfig(priv, false, buflen, USDHC_DTOCV_MAXTIMEOUT);
/* Configure the RX DMA */
@ -2612,10 +2579,6 @@ static int imxrt_dmasendsetup(FAR struct sdio_dev_s *dev,
DEBUGASSERT(priv != NULL && buffer != NULL && buflen > 0);
DEBUGASSERT(((uint32_t)buffer & 3) == 0);
/* Reset the DPSM configuration */
imxrt_datadisable();
/* Begin sampling register values */
imxrt_sampleinit();
@ -2628,7 +2591,7 @@ static int imxrt_dmasendsetup(FAR struct sdio_dev_s *dev,
/* Then set up the SDIO data path */
imxrt_dataconfig(priv, true, buflen, 1, USDHC_DTOCV_MAXTIMEOUT);
imxrt_dataconfig(priv, true, buflen, USDHC_DTOCV_MAXTIMEOUT);
/* Configure the TX DMA */
@ -2710,14 +2673,18 @@ static void imxrt_callback(void *arg)
{
/* Yes.. queue it */
mcinfo("Queuing callback to %p(%p)\n", priv->callback, priv->cbarg);
(void)work_queue(HPWORK, &priv->cbwork, (worker_t)priv->callback, priv->cbarg, 0);
mcinfo("Queuing callback to %p(%p)\n",
priv->callback, priv->cbarg);
(void)work_queue(HPWORK, &priv->cbwork, (worker_t)priv->callback,
priv->cbarg, 0);
}
else
{
/* No.. then just call the callback here */
mcinfo("Callback to %p(%p)\n", priv->callback, priv->cbarg);
priv->callback(priv->cbarg);
}
}
@ -2774,33 +2741,33 @@ FAR struct sdio_dev_s *imxrt_usdhc_initialize(int slotno)
#ifndef CONFIG_SDIO_MUXBUS
/* Data width 1, 4 or 8 */
(void)imxrt_config_gpio(PIN_USDHC1_D0 | PADCTL_USDHC1_DATAX);
(void)imxrt_config_gpio(PIN_USDHC1_D0 | PINSET_USDHC1_DATAX);
/* Data width 4 or 8 */
#ifndef CONFIG_IMXRT_USDHC_WIDTH_D1_ONLY
(void)imxrt_config_gpio(PIN_USDHC1_D1 | PADCTL_USDHC1_DATAX);
(void)imxrt_config_gpio(PIN_USDHC1_D2 | PADCTL_USDHC1_DATAX);
(void)imxrt_config_gpio(PIN_USDHC1_D3 | PADCTL_USDHC1_DATAX);
(void)imxrt_config_gpio(PIN_USDHC1_D1 | PINSET_USDHC1_DATAX);
(void)imxrt_config_gpio(PIN_USDHC1_D2 | PINSET_USDHC1_DATAX);
(void)imxrt_config_gpio(PIN_USDHC1_D3 | PINSET_USDHC1_DATAX);
/* Data width 8 (not supported) */
#if 0
(void)imxrt_config_gpio(PIN_USDHC1_D4 | PADCTL_USDHC1_DATAX);
(void)imxrt_config_gpio(PIN_USDHC1_D5 | PADCTL_USDHC1_DATAX);
(void)imxrt_config_gpio(PIN_USDHC1_D6 | PADCTL_USDHC1_DATAX);
(void)imxrt_config_gpio(PIN_USDHC1_D7 | PADCTL_USDHC1_DATAX);
(void)imxrt_config_gpio(PIN_USDHC1_D4 | PINSET_USDHC1_DATAX);
(void)imxrt_config_gpio(PIN_USDHC1_D5 | PINSET_USDHC1_DATAX);
(void)imxrt_config_gpio(PIN_USDHC1_D6 | PINSET_USDHC1_DATAX);
(void)imxrt_config_gpio(PIN_USDHC1_D7 | PINSET_USDHC1_DATAX);
#endif
#endif
/* Clocking and CMD pins (all data widths) */
(void)imxrt_config_gpio(PIN_USDHC1_DCLK | PADCTL_USDHC1_CLK);
(void)imxrt_config_gpio(PIN_USDHC1_CMD | PADCTL_USDHC1_CMD);
(void)imxrt_config_gpio(PIN_USDHC1_DCLK | PINSET_USDHC1_CLK);
(void)imxrt_config_gpio(PIN_USDHC1_CMD | PINSET_USDHC1_CMD);
#endif
#if defined(CONFIG_MMCSD_HAVE_CARDDETECT) && defined(PIN_USDHC1_CD)
(void)imxrt_config_gpio(PIN_USDHC1_CD | PADCTL_USDHC1_CD);
(void)imxrt_config_gpio(PIN_USDHC1_CD | PINSET_USDHC1_CD);
/* Daisy chain select the CD pin */

View File

@ -108,6 +108,7 @@
(BOARD_XTAL_FREQUENCY * (IMXRT_ARM_PLL_DIV_SELECT / 2)) / IMXRT_ARM_PODF_DIVIDER
/* LED definitions ******************************************************************/
/* There are four LED status indicators located on the EVK Board. The functions of
* these LEDs include:
*
@ -156,6 +157,7 @@
*/
/* Button definitions ***************************************************************/
/* The IMXRT board has one external user button
*
* 1. SW8 (IRQ88) GPIO5-00
@ -167,20 +169,23 @@
/* SDIO *****************************************************************************/
/* Pin drive characteristics - drive strength in particular may need tuning for specific boards */
/* Pin drive characteristics - drive strength in particular may need tuning for
* specific boards.
*/
#define PADCTL_USDHC1_DATAX (PADCTL_SRE|PADCTL_DSE_60OHM|PADCTL_HYS)
#define PADCTL_USDHC1_CMD PADCTL_USDHC1_DATAX
#define PADCTL_USDHC1_CLK (PADCTL_SRE|PADCTL_DSE_60OHM|PADCTL_SPEED_MAX)
#define PADCTL_USDHC1_CD (0)
#define PINSET_USDHC1_DATAX (IOMUX_SLEW_FAST | IOMUX_DRIVE_60OHM | \
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_CD (0)
#define PIN_USDHC1_D0 GPIO_USDHC1_DATA0
#define PIN_USDHC1_D1 GPIO_USDHC1_DATA1
#define PIN_USDHC1_D2 GPIO_USDHC1_DATA2
#define PIN_USDHC1_D3 GPIO_USDHC1_DATA3
#define PIN_USDHC1_DCLK GPIO_USDHC1_CLK
#define PIN_USDHC1_CMD GPIO_USDHC1_CMD
#define PIN_USDHC1_CD GPIO_USDHC1_CD_2
#define PIN_USDHC1_D0 GPIO_USDHC1_DATA0
#define PIN_USDHC1_D1 GPIO_USDHC1_DATA1
#define PIN_USDHC1_D2 GPIO_USDHC1_DATA2
#define PIN_USDHC1_D3 GPIO_USDHC1_DATA3
#define PIN_USDHC1_DCLK GPIO_USDHC1_CLK
#define PIN_USDHC1_CMD GPIO_USDHC1_CMD
#define PIN_USDHC1_CD GPIO_USDHC1_CD_2
/* 386 KHz for initial inquiry stuff */
@ -190,15 +195,16 @@
/* 24.8MHz for other modes */
#define BOARD_USDHC_MMCMODE_PRESCALER USDHC_SYSCTL_SDCLKFS_DIV8
#define BOARD_USDHC_MMCMODE_DIVISOR USDHC_SYSCTL_DVS_DIV(1)
#define BOARD_USDHC_MMCMODE_DIVISOR USDHC_SYSCTL_DVS_DIV(4) // FIXME 1
#define BOARD_USDHC_SD1MODE_PRESCALER USDHC_SYSCTL_SDCLKFS_DIV8
#define BOARD_USDHC_SD1MODE_DIVISOR USDHC_SYSCTL_DVS_DIV(1)
#define BOARD_USDHC_SD1MODE_DIVISOR USDHC_SYSCTL_DVS_DIV(4) // FIXME 1
#define BOARD_USDHC_SD4MODE_PRESCALER USDHC_SYSCTL_SDCLKFS_DIV8
#define BOARD_USDHC_SD4MODE_DIVISOR USDHC_SYSCTL_DVS_DIV(1)
#define BOARD_USDHC_SD4MODE_DIVISOR USDHC_SYSCTL_DVS_DIV(4) // FIXME 1
/* PIO Disambiguation ***************************************************************/
/* LPUARTs
*
* Virtual console port provided by OpenSDA: