summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorpatacongo <patacongo@42af7a65-404d-4744-a932-0658087f49c3>2010-04-10 23:16:51 +0000
committerpatacongo <patacongo@42af7a65-404d-4744-a932-0658087f49c3>2010-04-10 23:16:51 +0000
commit1ca794f2728207ce1320b07ed063aa54d2055dc7 (patch)
tree2aac9b4e40f0d975016bbe7080281808f1f3f31f
parentebbd43a116d01629817101f854d80ac0597ba20d (diff)
downloadnuttx-1ca794f2728207ce1320b07ed063aa54d2055dc7.tar.gz
nuttx-1ca794f2728207ce1320b07ed063aa54d2055dc7.tar.bz2
nuttx-1ca794f2728207ce1320b07ed063aa54d2055dc7.zip
SAM3U needs block info
git-svn-id: svn://svn.code.sf.net/p/nuttx/code/trunk@2584 42af7a65-404d-4744-a932-0658087f49c3
-rwxr-xr-xnuttx/arch/arm/src/sam3u/sam3u_hsmci.c148
-rw-r--r--nuttx/drivers/mmcsd/mmcsd_sdio.c5
-rwxr-xr-xnuttx/include/nuttx/sdio.h24
3 files changed, 115 insertions, 62 deletions
diff --git a/nuttx/arch/arm/src/sam3u/sam3u_hsmci.c b/nuttx/arch/arm/src/sam3u/sam3u_hsmci.c
index 1056fa1f0..e52129f6a 100755
--- a/nuttx/arch/arm/src/sam3u/sam3u_hsmci.c
+++ b/nuttx/arch/arm/src/sam3u/sam3u_hsmci.c
@@ -81,6 +81,10 @@
# error "Callback support requires CONFIG_SCHED_WORKQUEUE"
#endif
+#ifndef CONFIG_SDIO_BLOCKSETUP
+# error "This driver requires CONFIG_SDIO_BLOCKSETUP"
+#endif
+
#ifndef CONFIG_HSMCI_PRI
# define CONFIG_HSMCI_PRI NVIC_SYSH_PRIORITY_DEFAULT
#endif
@@ -89,6 +93,20 @@
# undef CONFIG_HSMCI_XFRDEBUG
#endif
+#ifdef CONFIG_SAM3U_HSMCI_RDPROOF
+# ifdef CONFIG_SAM3U_HSMCI_WRPROOF
+# define HSMCU_PROOF_BITS (HSMCI_MR_RDPROOF | HSMCI_MR_WRPROOF)
+# else
+# define HSMCU_PROOF_BITS HSMCI_MR_RDPROOF
+# endif
+#else
+# ifdef CONFIG_SAM3U_HSMCI_WRPROOF
+# define HSMCU_PROOF_BITS HSMCI_MR_WRPROOF
+# else
+# define HSMCU_PROOF_BITS (0)
+# endif
+#endif
+
/* Timing */
#define HSMCI_CMDTIMEOUT (100000)
@@ -344,8 +362,9 @@ static int sam3u_attach(FAR struct sdio_dev_s *dev);
static void sam3u_sendcmd(FAR struct sdio_dev_s *dev, uint32_t cmd,
uint32_t arg);
+static void sam3u_blocksetup(FAR struct sdio_dev_s *dev, unsigned int blocklen,
+ unsigned int nblocks);
static int sam3u_cancel(FAR struct sdio_dev_s *dev);
-
static int sam3u_waitresponse(FAR struct sdio_dev_s *dev, uint32_t cmd);
static int sam3u_recvshort(FAR struct sdio_dev_s *dev, uint32_t cmd,
uint32_t *rshort);
@@ -393,6 +412,7 @@ struct sam3u_dev_s g_sdiodev =
.clock = sam3u_clock,
.attach = sam3u_attach,
.sendcmd = sam3u_sendcmd,
+ .blocksetup = sam3u_blocksetup,
.recvsetup = sam3u_dmarecvsetup,
.sendsetup = sam3u_dmasendsetup,
.cancel = sam3u_cancel,
@@ -1334,12 +1354,12 @@ static void sam3u_sendcmd(FAR struct sdio_dev_s *dev, uint32_t cmd, uint32_t arg
case MMCSD_R5_RESPONSE:
case MMCSD_R6_RESPONSE:
priv->cmdrmask = HSMCI_CMDRESP_INTS;
- regval |= HSMCI_CMDR_RSPTYP_48BIT;
+ regval |= (HSMCI_CMDR_RSPTYP_48BIT | HSMCI_CMDR_MAXLAT);
break;
case MMCSD_R1B_RESPONSE:
priv->cmdrmask = HSMCI_CMDRESP_INTS;
- regval |= HSMCI_CMDR_RSPTYP_R1B;
+ regval |= (HSMCI_CMDR_RSPTYP_R1B | HSMCI_CMDR_MAXLAT);
break;
/* 48-bit response without CRC */
@@ -1347,14 +1367,14 @@ static void sam3u_sendcmd(FAR struct sdio_dev_s *dev, uint32_t cmd, uint32_t arg
case MMCSD_R3_RESPONSE:
case MMCSD_R7_RESPONSE:
priv->cmdrmask = HSMCI_CMDRESP_NOCRC_INTS;
- regval |= HSMCI_CMDR_RSPTYP_48BIT;
+ regval |= (HSMCI_CMDR_RSPTYP_48BIT | HSMCI_CMDR_MAXLAT);
break;
/* 136-bit response with CRC */
case MMCSD_R2_RESPONSE:
priv->cmdrmask = HSMCI_CMDRESP_INTS;
- regval |= HSMCI_CMDR_RSPTYP_136BIT;
+ regval |= (HSMCI_CMDR_RSPTYP_136BIT | HSMCI_CMDR_MAXLAT);
break;
}
@@ -1400,13 +1420,6 @@ static void sam3u_sendcmd(FAR struct sdio_dev_s *dev, uint32_t cmd, uint32_t arg
}
#endif
- /* Special case a couple of commands */
-
- if (cmdidx > MMC_CMDIDX3 && cmdidx != MMCSD_CMDIDX15 && cmd != MMCSD_CMDIDX27)
- {
- regval |= HSMCI_CMDR_MAXLAT; /* Max Latency for Command to Response */
- }
-
/* Write the fully decorated command to CMDR */
fvdbg("cmd: %08x arg: %08x regval: %08x\n", cmd, arg, regval);
@@ -1414,6 +1427,44 @@ static void sam3u_sendcmd(FAR struct sdio_dev_s *dev, uint32_t cmd, uint32_t arg
}
/****************************************************************************
+ * Name: sam3u_blocksetup
+ *
+ * Description:
+ * Some hardward needs to be informed of the selected blocksize.
+ *
+ * Input Parameters:
+ * dev - An instance of the SDIO device interface
+ * blocklen - The selected block size.
+ *
+ * Returned Value:
+ * None
+ *
+ ****************************************************************************/
+
+static void sam3u_blocksetup(FAR struct sdio_dev_s *dev, unsigned int blocklen,
+ unsigned int nblocks)
+{
+ uint32_t regval;
+
+ DEBUGASSERT(dev != NULL && nblocks > 0 && nblocks < 65535 && blocklen < 65535);
+
+ /* Set the block size */
+
+ regval = getreg32(SAM3U_HSMCI_MR);
+ regval &= ~(HSMCI_MR_RDPROOF | HSMCI_MR_WRPROOF | HSMCI_MR_BLKLEN_MASK);
+ regval |= HSMCU_PROOF_BITS;
+ regval |= (blocklen << HSMCI_MR_BLKLEN_SHIFT);
+ putreg32(regval, SAM3U_HSMCI_MR);
+
+ /* Set the block count */
+
+ regval = getreg32(SAM3U_HSMCI_BLKR);
+ regval &= ~HSMCI_BLKR_BCNT_MASK;
+ regval |= (nblocks << HSMCI_BLKR_BCNT_SHIFT);
+ putreg32(regval, SAM3U_HSMCI_BLKR);
+}
+
+/****************************************************************************
* Name: sam3u_cancel
*
* Description:
@@ -1988,39 +2039,26 @@ static int sam3u_dmarecvsetup(FAR struct sdio_dev_s *dev, FAR uint8_t *buffer,
size_t buflen)
{
struct sam3u_dev_s *priv = (struct sam3u_dev_s *)dev;
- int ret = -EINVAL;
DEBUGASSERT(priv != NULL && buffer != NULL && buflen > 0);
DEBUGASSERT(((uint32_t)buffer & 3) == 0);
- /* Reset the DPSM configuration */
-
-//TO BE PROVIDED
-
- /* Wide bus operation is required for DMA */
-
- if (priv->widebus)
- {
- sam3u_sampleinit();
- sam3u_sample(priv, SAMPLENDX_BEFORE_SETUP);
+ /* Setup register sampling */
- /* Then set up the HSMCI data path */
+ sam3u_sampleinit();
+ sam3u_sample(priv, SAMPLENDX_BEFORE_SETUP);
-//TO BE PROVIDED
+ /* Configure the RX DMA */
- /* Configure the RX DMA */
-
- sam3u_enablexfrints(priv, HSMCI_DMARECV_INTS);
- sam3u_dmarxsetup(priv->dma, SAM3U_HSMCI_FIFO, (uint32_t)buffer, buflen);
+ sam3u_enablexfrints(priv, HSMCI_DMARECV_INTS);
+ sam3u_dmarxsetup(priv->dma, SAM3U_HSMCI_FIFO, (uint32_t)buffer, buflen);
- /* Start the DMA */
+ /* Start the DMA */
- sam3u_sample(priv, SAMPLENDX_BEFORE_ENABLE);
- sam3u_dmastart(priv->dma, sam3u_dmacallback, priv);
- sam3u_sample(priv, SAMPLENDX_AFTER_SETUP);
- ret = OK;
- }
- return ret;
+ sam3u_sample(priv, SAMPLENDX_BEFORE_ENABLE);
+ sam3u_dmastart(priv->dma, sam3u_dmacallback, priv);
+ sam3u_sample(priv, SAMPLENDX_AFTER_SETUP);
+ return OK;
}
/****************************************************************************
@@ -2046,43 +2084,29 @@ static int sam3u_dmasendsetup(FAR struct sdio_dev_s *dev,
FAR const uint8_t *buffer, size_t buflen)
{
struct sam3u_dev_s *priv = (struct sam3u_dev_s *)dev;
- int ret = -EINVAL;
DEBUGASSERT(priv != NULL && buffer != NULL && buflen > 0);
DEBUGASSERT(((uint32_t)buffer & 3) == 0);
- /* Reset the DPSM configuration */
+ /* Setup register sampling */
-//TO BE PROVIDED
-
- /* Wide bus operation is required for DMA */
-
- if (priv->widebus)
- {
- sam3u_sampleinit();
- sam3u_sample(priv, SAMPLENDX_BEFORE_SETUP);
+ sam3u_sampleinit();
+ sam3u_sample(priv, SAMPLENDX_BEFORE_SETUP);
- /* Then set up the HSMCI data path */
+ /* Configure the TX DMA */
-//TO BE PROVIDED
+ sam3u_dmatxsetup(priv->dma, SAM3U_HSMCI_FIFO, (uint32_t)buffer, buflen);
+ sam3u_sample(priv, SAMPLENDX_BEFORE_ENABLE);
- /* Configure the TX DMA */
+ /* Start the DMA */
- sam3u_dmatxsetup(priv->dma, SAM3U_HSMCI_FIFO, (uint32_t)buffer, buflen);
- sam3u_sample(priv, SAMPLENDX_BEFORE_ENABLE);
+ sam3u_dmastart(priv->dma, sam3u_dmacallback, priv);
+ sam3u_sample(priv, SAMPLENDX_AFTER_SETUP);
- /* Start the DMA */
+ /* Enable TX interrrupts */
- sam3u_dmastart(priv->dma, sam3u_dmacallback, priv);
- sam3u_sample(priv, SAMPLENDX_AFTER_SETUP);
-
- /* Enable TX interrrupts */
-
- sam3u_enablexfrints(priv, HSMCI_DMASEND_INTS);
-
- ret = OK;
- }
- return ret;
+ sam3u_enablexfrints(priv, HSMCI_DMASEND_INTS);
+ return OK;
}
/****************************************************************************
diff --git a/nuttx/drivers/mmcsd/mmcsd_sdio.c b/nuttx/drivers/mmcsd/mmcsd_sdio.c
index b2c090182..ef3721066 100644
--- a/nuttx/drivers/mmcsd/mmcsd_sdio.c
+++ b/nuttx/drivers/mmcsd/mmcsd_sdio.c
@@ -461,6 +461,7 @@ static int mmcsd_getSCR(FAR struct mmcsd_state_s *priv, uint32_t scr[2])
/* Setup up to receive data with interrupt mode */
+ SDIO_BLOCKSETUP(priv->dev, 8, 1);
SDIO_RECVSETUP(priv->dev, (FAR uint8_t*)scr, 8);
/* Send ACMD51 SD_APP_SEND_SCR with argument as 0 to start data receipt */
@@ -1246,6 +1247,7 @@ static ssize_t mmcsd_readsingle(FAR struct mmcsd_state_s *priv,
/* Configure SDIO controller hardware for the read transfer */
+ SDIO_BLOCKSETUP(priv->dev, priv->blocksize, 1);
SDIO_WAITENABLE(priv->dev, SDIOWAIT_TRANSFERDONE|SDIOWAIT_TIMEOUT|SDIOWAIT_ERROR);
#ifdef CONFIG_SDIO_DMA
if (priv->dma)
@@ -1354,6 +1356,7 @@ static ssize_t mmcsd_readmultiple(FAR struct mmcsd_state_s *priv,
/* Configure SDIO controller hardware for the read transfer */
+ SDIO_BLOCKSETUP(priv->dev, priv->blocksize, nblocks);
SDIO_WAITENABLE(priv->dev, SDIOWAIT_TRANSFERDONE|SDIOWAIT_TIMEOUT|SDIOWAIT_ERROR);
#ifdef CONFIG_SDIO_DMA
if (priv->dma)
@@ -1511,6 +1514,7 @@ static ssize_t mmcsd_writesingle(FAR struct mmcsd_state_s *priv,
/* Configure SDIO controller hardware for the write transfer */
+ SDIO_BLOCKSETUP(priv->dev, priv->blocksize, 1);
SDIO_WAITENABLE(priv->dev, SDIOWAIT_TRANSFERDONE|SDIOWAIT_TIMEOUT|SDIOWAIT_ERROR);
#ifdef CONFIG_SDIO_DMA
if (priv->dma)
@@ -1655,6 +1659,7 @@ static ssize_t mmcsd_writemultiple(FAR struct mmcsd_state_s *priv,
/* Configure SDIO controller hardware for the write transfer */
+ SDIO_BLOCKSETUP(priv->dev, priv->blocksize, nblocks);
SDIO_WAITENABLE(priv->dev, SDIOWAIT_TRANSFERDONE|SDIOWAIT_TIMEOUT|SDIOWAIT_ERROR);
#ifdef CONFIG_SDIO_DMA
if (priv->dma)
diff --git a/nuttx/include/nuttx/sdio.h b/nuttx/include/nuttx/sdio.h
index 15cb6a4a2..8d4861c24 100755
--- a/nuttx/include/nuttx/sdio.h
+++ b/nuttx/include/nuttx/sdio.h
@@ -422,6 +422,29 @@
#define SDIO_SENDCMD(dev,cmd,arg) ((dev)->sendcmd(dev,cmd,arg))
/****************************************************************************
+ * Name: SDIO_BLOCKLEN
+ *
+ * Description:
+ * Some hardward needs to be informed of the selected blocksize and the
+ * number of blocks. Others just work on the byte stream.
+ *
+ * Input Parameters:
+ * dev - An instance of the SDIO device interface
+ * blocklen - The selected block size.
+ * nblocks - The number of blocks to be transferred.
+ *
+ * Returned Value:
+ * None
+ *
+ ****************************************************************************/
+
+#ifdef CONFIG_SDIO_BLOCKSETUP
+# define SDIO_BLOCKSETUP(dev,blocklen,nblocks) ((dev)->blocksetup(dev,blocklen,nblocks))
+#else
+# define SDIO_BLOCKSETUP(dev,blocklen,nblocks)
+#endif
+
+/****************************************************************************
* Name: SDIO_RECVSETUP
*
* Description:
@@ -744,6 +767,7 @@ struct sdio_dev_s
/* Command/Status/Data Transfer */
void (*sendcmd)(FAR struct sdio_dev_s *dev, uint32_t cmd, uint32_t arg);
+ void (*blocksetup)(FAR struct sdio_dev_s *dev, unsigned int blocklen, unsigned int nblocks);
int (*recvsetup)(FAR struct sdio_dev_s *dev, FAR uint8_t *buffer,
size_t nbytes);
int (*sendsetup)(FAR struct sdio_dev_s *dev, FAR const uint8_t *buffer,