Fix HSMCI command and wait logic

git-svn-id: svn://svn.code.sf.net/p/nuttx/code/trunk@2582 42af7a65-404d-4744-a932-0658087f49c3
This commit is contained in:
patacongo 2010-04-10 21:57:17 +00:00
parent 63d25971ca
commit da2bc4cc04
4 changed files with 281 additions and 113 deletions

View File

@ -140,6 +140,9 @@
#define HSMCI_RESPONSE_ERRORS \ #define HSMCI_RESPONSE_ERRORS \
( HSMCI_INT_CSTOE | HSMCI_INT_RTOE | HSMCI_INT_RENDE | HSMCI_INT_RCRCE | \ ( HSMCI_INT_CSTOE | HSMCI_INT_RTOE | HSMCI_INT_RENDE | HSMCI_INT_RCRCE | \
HSMCI_INT_RDIRE | HSMCI_INT_RINDE ) HSMCI_INT_RDIRE | HSMCI_INT_RINDE )
#define HSMCI_RESPONSE_NOCRC_ERRORS \
( HSMCI_INT_CSTOE | HSMCI_INT_RTOE | HSMCI_INT_RENDE | HSMCI_INT_RDIRE | \
HSMCI_INT_RINDE )
#define HSMCI_RESPONSE_TIMEOUT_ERRORS \ #define HSMCI_RESPONSE_TIMEOUT_ERRORS \
( HSMCI_INT_CSTOE | HSMCI_INT_RTOE ) ( HSMCI_INT_CSTOE | HSMCI_INT_RTOE )
@ -167,19 +170,38 @@
#define HSMCI_DATA_DMASEND_ERRORS \ #define HSMCI_DATA_DMASEND_ERRORS \
( HSMCI_INT_UNRE | HSMCI_INT_CSTOE | HSMCI_INT_DTOE | HSMCI_INT_DCRCE ) ( HSMCI_INT_UNRE | HSMCI_INT_CSTOE | HSMCI_INT_DTOE | HSMCI_INT_DCRCE )
/* Data transfer status and interrupt mask bits */ /* Data transfer status and interrupt mask bits.
*
* The XFRDONE flag in the HSMCI_SR indicates exactly when the read or
* write sequence is finished.
*
* 0: A transfer is in progress.
* 1: Command register is ready to operate and the data bus is in the idle state.
*
* DMADONE: DMA Transfer done
*
* 0: DMA buffer transfer has not completed since the last read of HSMCI_SR register.
* 1: DMA buffer transfer has completed.
*/
#define HSMCI_DMARECV_INTS \ #define HSMCI_DMARECV_INTS \
( HSMCI_DATA_DMARECV_ERRORS | HSMCI_INT_XFRDONE | HSMCI_INT_DMADONE ) ( HSMCI_DATA_DMARECV_ERRORS | HSMCI_INT_XFRDONE /* | HSMCI_INT_DMADONE */ )
#define HSMCI_DMASEND_INTS \ #define HSMCI_DMASEND_INTS \
( HSMCI_DATA_DMASEND_ERRORS | HSMCI_INT_XFRDONE | HSMCI_INT_DMADONE ) ( HSMCI_DATA_DMASEND_ERRORS | HSMCI_INT_XFRDONE /* | HSMCI_INT_DMADONE */ )
/* Event waiting interrupt mask bits */ /* Event waiting interrupt mask bits.
*
* CMDRDY (Command Ready):
*
* 0: A command is in progress
* 1: The last command has been sent. The CMDRDY flag is released 8 bits
* after the end of the card response. Cleared when writing in the HSMCI_CMDR
*/
#define HSMCI_CMDRESP_INTS \ #define HSMCI_CMDRESP_INTS \
( HSMCI_RESPONSE_ERRORS | HSMCI_INT_CMDRDY ) ( HSMCI_RESPONSE_ERRORS | HSMCI_INT_CMDRDY )
#define HSMCI_XFRDONE_INTS \ #define HSMCI_CMDRESP_NOCRC_INTS \
( 0 ) ( HSMCI_RESPONSE_NOCRC_ERRORS | HSMCI_INT_CMDRDY )
/* Register logging support */ /* Register logging support */
@ -215,6 +237,7 @@ struct sam3u_dev_s
sem_t waitsem; /* Implements event waiting */ sem_t waitsem; /* Implements event waiting */
sdio_eventset_t waitevents; /* Set of events to be waited for */ sdio_eventset_t waitevents; /* Set of events to be waited for */
uint32_t waitmask; /* Interrupt enables for event waiting */ uint32_t waitmask; /* Interrupt enables for event waiting */
uint32_t cmdrmask; /* Interrupt enables for this particular cmd/response */
volatile sdio_eventset_t wkupevent; /* The event that caused the wakeup */ volatile sdio_eventset_t wkupevent; /* The event that caused the wakeup */
WDOG_ID waitwdog; /* Watchdog that handles event timeouts */ WDOG_ID waitwdog; /* Watchdog that handles event timeouts */
@ -228,8 +251,6 @@ struct sam3u_dev_s
/* Interrupt mode data transfer support */ /* Interrupt mode data transfer support */
uint32_t *buffer; /* Address of current R/W buffer */
size_t remaining; /* Number of bytes remaining in the transfer */
uint32_t xfrmask; /* Interrupt enables for data transfer */ uint32_t xfrmask; /* Interrupt enables for data transfer */
/* DMA data transfer support */ /* DMA data transfer support */
@ -302,6 +323,7 @@ static void sam3u_dmacallback(DMA_HANDLE handle, void *arg, int result);
static void sam3u_eventtimeout(int argc, uint32_t arg); static void sam3u_eventtimeout(int argc, uint32_t arg);
static void sam3u_endwait(struct sam3u_dev_s *priv, sdio_eventset_t wkupevent); static void sam3u_endwait(struct sam3u_dev_s *priv, sdio_eventset_t wkupevent);
static void sam3u_endtransfer(struct sam3u_dev_s *priv, sdio_eventset_t wkupevent); static void sam3u_endtransfer(struct sam3u_dev_s *priv, sdio_eventset_t wkupevent);
static void sam3u_notransfer(struct sam3u_dev_s *priv);
/* Interrupt Handling *******************************************************/ /* Interrupt Handling *******************************************************/
@ -325,12 +347,10 @@ static void sam3u_sendcmd(FAR struct sdio_dev_s *dev, uint32_t cmd,
static int sam3u_cancel(FAR struct sdio_dev_s *dev); 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_waitresponse(FAR struct sdio_dev_s *dev, uint32_t cmd);
static int sam3u_recvshortcrc(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); uint32_t *rshort);
static int sam3u_recvlong(FAR struct sdio_dev_s *dev, uint32_t cmd, static int sam3u_recvlong(FAR struct sdio_dev_s *dev, uint32_t cmd,
uint32_t rlong[4]); uint32_t rlong[4]);
static int sam3u_recvshort(FAR struct sdio_dev_s *dev, uint32_t cmd,
uint32_t *rshort);
static int sam3u_recvnotimpl(FAR struct sdio_dev_s *dev, uint32_t cmd, static int sam3u_recvnotimpl(FAR struct sdio_dev_s *dev, uint32_t cmd,
uint32_t *rnotimpl); uint32_t *rnotimpl);
@ -377,12 +397,12 @@ struct sam3u_dev_s g_sdiodev =
.sendsetup = sam3u_dmasendsetup, .sendsetup = sam3u_dmasendsetup,
.cancel = sam3u_cancel, .cancel = sam3u_cancel,
.waitresponse = sam3u_waitresponse, .waitresponse = sam3u_waitresponse,
.recvR1 = sam3u_recvshortcrc, .recvR1 = sam3u_recvshort,
.recvR2 = sam3u_recvlong, .recvR2 = sam3u_recvlong,
.recvR3 = sam3u_recvshort, .recvR3 = sam3u_recvshort,
.recvR4 = sam3u_recvnotimpl, .recvR4 = sam3u_recvnotimpl,
.recvR5 = sam3u_recvnotimpl, .recvR5 = sam3u_recvnotimpl,
.recvR6 = sam3u_recvshortcrc, .recvR6 = sam3u_recvshort,
.recvR7 = sam3u_recvshort, .recvR7 = sam3u_recvshort,
.waitenable = sam3u_waitenable, .waitenable = sam3u_waitenable,
.eventwait = sam3u_eventwait, .eventwait = sam3u_eventwait,
@ -728,15 +748,8 @@ static void sam3u_dumpsamples(struct sam3u_dev_s *priv)
static void sam3u_dmacallback(DMA_HANDLE handle, void *arg, int result) static void sam3u_dmacallback(DMA_HANDLE handle, void *arg, int result)
{ {
/* FAR struct sam3u_spidev_s *priv = (FAR struct sam3u_spidev_s *)arg; */
/* We don't really do anything at the completion of DMA. The termination /* We don't really do anything at the completion of DMA. The termination
* of the transfer is driven by the HSMCI interrupts. * of the transfer is driven by the HSMCI interrupts.
*
* In fact, we won't normally get the DMA callback at all! The HSMCI
* appears to handle the End-Of-Transfer interrupt first and it will can
* sam3u_dmastop() which will disable and clear the interrupt that performs
* this callback.
*/ */
sam3u_sample((struct sam3u_dev_s*)arg, SAMPLENDX_DMA_CALLBACK); sam3u_sample((struct sam3u_dev_s*)arg, SAMPLENDX_DMA_CALLBACK);
@ -779,7 +792,7 @@ static void sam3u_eventtimeout(int argc, uint32_t arg)
/* Yes.. wake up any waiting threads */ /* Yes.. wake up any waiting threads */
sam3u_endwait(priv, SDIOWAIT_TIMEOUT); sam3u_endwait(priv, SDIOWAIT_TIMEOUT);
flldbg("Timeout: remaining: %d\n", priv->remaining); flldbg("Timeout\n");
} }
} }
@ -842,6 +855,10 @@ static void sam3u_endtransfer(struct sam3u_dev_s *priv, sdio_eventset_t wkupeven
sam3u_disablexfrints(priv); sam3u_disablexfrints(priv);
/* No data transfer */
sam3u_notransfer(priv);
/* DMA debug instrumentation */ /* DMA debug instrumentation */
sam3u_sample(priv, SAMPLENDX_END_TRANSFER); sam3u_sample(priv, SAMPLENDX_END_TRANSFER);
@ -853,10 +870,6 @@ static void sam3u_endtransfer(struct sam3u_dev_s *priv, sdio_eventset_t wkupeven
sam3u_dmastop(priv->dma); sam3u_dmastop(priv->dma);
/* Mark the transfer finished */
priv->remaining = 0;
/* Is a thread wait for these data transfer complete events? */ /* Is a thread wait for these data transfer complete events? */
if ((priv->waitevents & wkupevent) != 0) if ((priv->waitevents & wkupevent) != 0)
@ -867,6 +880,28 @@ static void sam3u_endtransfer(struct sam3u_dev_s *priv, sdio_eventset_t wkupeven
} }
} }
/****************************************************************************
* Name: sam3u_notransfer
*
* Description:
* Setup for no transfer. This is the default setup that is overriddden
* by sam3u_dmarecvsetup or sam3u_dmasendsetup
*
* Input Parameters:
* priv - An instance of the HSMCI device interface
*
* Returned Value:
* None
*
****************************************************************************/
static void sam3u_notransfer(struct sam3u_dev_s *priv)
{
uint32_t regval = getreg32(SAM3U_HSMCI_MR);
regval &= ~(HSMCI_MR_RDPROOF | HSMCI_MR_WRPROOF | HSMCI_MR_BLKLEN_MASK);
putreg32(regval, SAM3U_HSMCI_MR);
}
/**************************************************************************** /****************************************************************************
* Interrrupt Handling * Interrrupt Handling
****************************************************************************/ ****************************************************************************/
@ -945,7 +980,7 @@ static int sam3u_interrupt(int irq, void *context)
/* Is this a Command-Response sequence completion event? */ /* Is this a Command-Response sequence completion event? */
if ((pending & HSMCI_CMDRESP_INTS) != 0) if ((pending & priv->cmdrmask) != 0)
{ {
/* Yes.. Did the Command-Response sequence end with an error? */ /* Yes.. Did the Command-Response sequence end with an error? */
@ -954,7 +989,7 @@ static int sam3u_interrupt(int irq, void *context)
/* Yes.. Was the error some kind of timeout? */ /* Yes.. Was the error some kind of timeout? */
fllvdbg("ERROR:events: %08x SR: %08x\n", fllvdbg("ERROR:events: %08x SR: %08x\n",
HSMCI_CMDRESP_INTS, enabled); priv->cmdrmask, enabled);
if ((pending & HSMCI_RESPONSE_TIMEOUT_ERRORS) != 0) if ((pending & HSMCI_RESPONSE_TIMEOUT_ERRORS) != 0)
{ {
@ -1055,6 +1090,10 @@ static void sam3u_reset(FAR struct sdio_dev_s *dev)
putreg32(HSMCI_CFG_FIFOMODE, SAM3U_HSMCI_CFG); putreg32(HSMCI_CFG_FIFOMODE, SAM3U_HSMCI_CFG);
/* No data transfer */
sam3u_notransfer(priv);
/* Disable the MCI peripheral clock */ /* Disable the MCI peripheral clock */
putreg32((1 << SAM3U_PID_HSMCI), SAM3U_PMC_PCDR); putreg32((1 << SAM3U_PID_HSMCI), SAM3U_PMC_PCDR);
@ -1068,8 +1107,6 @@ static void sam3u_reset(FAR struct sdio_dev_s *dev)
/* Interrupt mode data transfer support */ /* Interrupt mode data transfer support */
priv->buffer = 0; /* Address of current R/W buffer */
priv->remaining = 0; /* Number of bytes remaining in the transfer */
priv->xfrmask = 0; /* Interrupt enables for data transfer */ priv->xfrmask = 0; /* Interrupt enables for data transfer */
/* DMA data transfer support */ /* DMA data transfer support */
@ -1265,51 +1302,114 @@ 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_sendcmd(FAR struct sdio_dev_s *dev, uint32_t cmd, uint32_t arg)
{ {
struct sam3u_dev_s *priv = (struct sam3u_dev_s*)dev;
uint32_t regval; uint32_t regval;
uint32_t cmdidx = (cmd & MMCSD_CMDIDX_MASK) >> MMCSD_CMDIDX_SHIFT; uint32_t cmdidx;
/* Set the HSMCI Argument value */ /* Set the HSMCI Argument value */
putreg32(arg, SAM3U_HSMCI_ARGR); putreg32(arg, SAM3U_HSMCI_ARGR);
/* Clear CMDINDEX, WAITRESP, WAITINT, WAITPEND, and CPSMEN bits */ /* Construct the command valid, starting with the command index */
regval = getreg32(SAM3U_HSMCI_CMDR); cmdidx = (cmd & MMCSD_CMDIDX_MASK) >> MMCSD_CMDIDX_SHIFT;
regval &= ~(HSMCI_CMDR_CMDINDEX_MASK|HSMCI_CMDR_WAITRESP_MASK| regval = cmdidx << HSMCI_CMDR_CMDNB_SHIFT;
HSMCI_CMDR_WAITINT|HSMCI_CMDR_WAITPEND|HSMCI_CMDR_CPSMEN);
/* Set WAITRESP bits */ /* 'OR' in response related bits */
switch (cmd & MMCSD_RESPONSE_MASK) switch (cmd & MMCSD_RESPONSE_MASK)
{ {
/* No response */
case MMCSD_NO_RESPONSE: case MMCSD_NO_RESPONSE:
regval |= HSMCI_CMDR_NORESPONSE; priv->cmdrmask = HSMCI_CMDRESP_INTS;
regval |= HSMCI_CMDR_RSPTYP_NONE;
break; break;
/* 48-bit response with CRC */
case MMCSD_R1_RESPONSE: case MMCSD_R1_RESPONSE:
case MMCSD_R1B_RESPONSE:
case MMCSD_R3_RESPONSE:
case MMCSD_R4_RESPONSE: case MMCSD_R4_RESPONSE:
case MMCSD_R5_RESPONSE: case MMCSD_R5_RESPONSE:
case MMCSD_R6_RESPONSE: case MMCSD_R6_RESPONSE:
case MMCSD_R7_RESPONSE: priv->cmdrmask = HSMCI_CMDRESP_INTS;
regval |= HSMCI_CMDR_SHORTRESPONSE; regval |= HSMCI_CMDR_RSPTYP_48BIT;
break; break;
case MMCSD_R1B_RESPONSE:
priv->cmdrmask = HSMCI_CMDRESP_INTS;
regval |= HSMCI_CMDR_RSPTYP_R1B;
break;
/* 48-bit response without CRC */
case MMCSD_R3_RESPONSE:
case MMCSD_R7_RESPONSE:
priv->cmdrmask = HSMCI_CMDRESP_NOCRC_INTS;
regval |= HSMCI_CMDR_RSPTYP_48BIT;
break;
/* 136-bit response with CRC */
case MMCSD_R2_RESPONSE: case MMCSD_R2_RESPONSE:
regval |= HSMCI_CMDR_LONGRESPONSE; priv->cmdrmask = HSMCI_CMDRESP_INTS;
regval |= HSMCI_CMDR_RSPTYP_136BIT;
break; break;
} }
/* Set CPSMEN and the command index */ /* 'OR' in data transer related bits */
switch (cmd & MMCSD_DATAXFR_MASK)
{
#if 0 /* No MMC support */
case MMCSD_RDSTREAM: /* MMC Read stream */
regval |= (HSMCI_CMDR_TRCMD_START | HSMCI_CMDR_TRTYP_STREAM | HSMCI_CMDR_TRDIR_READ);
break;
case MMCSD_WRSTREAM: /* MMC Write stream */
regval |= (HSMCI_CMDR_TRCMD_START | HSMCI_CMDR_TRTYP_STREAM | HSMCI_CMDR_TRDIR_WRITE);
break;
#endif
case MMCSD_RDDATAXFR: /* Read block transfer */
regval |= (HSMCI_CMDR_TRCMD_START | HSMCI_CMDR_TRDIR_READ);
regval |= (cmd & MMCSD_MULTIBLOCK) ? HSMCI_CMDR_TRTYP_MULTI : HSMCI_CMDR_TRTYP_SINGLE;
break;
case MMCSD_WRDATAXFR: /* Write block transfer */
regval |= (HSMCI_CMDR_TRCMD_START | HSMCI_CMDR_TRDIR_WRITE);
regval |= (cmd & MMCSD_MULTIBLOCK) ? HSMCI_CMDR_TRTYP_MULTI : HSMCI_CMDR_TRTYP_SINGLE;
break;
case MMCSD_NODATAXFR:
default:
if ((cmd & MMCSD_STOPXFR) != 0)
{
regval |= HSMCI_CMDR_TRCMD_STOP;
}
break;
}
/* 'OR' in Open Drain option */
#if 0 /* No MMC support */
if ((cmd & MMCSD_OPENDRAN) != 0)
{
regval |= HSMCI_CMDR_OPDCMD;
}
#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 */
cmdidx = (cmd & MMCSD_CMDIDX_MASK) >> MMCSD_CMDIDX_SHIFT;
regval |= cmdidx | HSMCI_CMDR_CPSMEN;
fvdbg("cmd: %08x arg: %08x regval: %08x\n", cmd, arg, regval); fvdbg("cmd: %08x arg: %08x regval: %08x\n", cmd, arg, regval);
/* Write the SDIO CMD */
putreg32(regval, SAM3U_HSMCI_CMDR); putreg32(regval, SAM3U_HSMCI_CMDR);
} }
@ -1339,6 +1439,10 @@ static int sam3u_cancel(FAR struct sdio_dev_s *dev)
sam3u_disablexfrints(priv); sam3u_disablexfrints(priv);
sam3u_disablewaitints(priv, 0); sam3u_disablewaitints(priv, 0);
/* No data transfer */
sam3u_notransfer(priv);
/* Clearing (most) pending interrupt status by reading the status register */ /* Clearing (most) pending interrupt status by reading the status register */
(void)getreg32(SAM3U_HSMCI_SR); (void)getreg32(SAM3U_HSMCI_SR);
@ -1353,10 +1457,6 @@ static int sam3u_cancel(FAR struct sdio_dev_s *dev)
*/ */
sam3u_dmastop(priv->dma); sam3u_dmastop(priv->dma);
/* Mark no transfer in progress */
priv->remaining = 0;
return OK; return OK;
} }
@ -1377,6 +1477,7 @@ 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_waitresponse(FAR struct sdio_dev_s *dev, uint32_t cmd)
{ {
struct sam3u_dev_s *priv = (struct sam3u_dev_s*)dev;
uint32_t sr; uint32_t sr;
int32_t timeout; int32_t timeout;
@ -1410,7 +1511,7 @@ static int sam3u_waitresponse(FAR struct sdio_dev_s *dev, uint32_t cmd)
/* Did a Command-Response sequence termination evernt occur? */ /* Did a Command-Response sequence termination evernt occur? */
sr = getreg32(SAM3U_HSMCI_SR); sr = getreg32(SAM3U_HSMCI_SR);
if ((sr & HSMCI_CMDRESP_INTS) != 0) if ((sr & priv->cmdrmask) != 0)
{ {
/* Yes.. Did the Command-Response sequence end with an error? */ /* Yes.. Did the Command-Response sequence end with an error? */
@ -1419,18 +1520,20 @@ static int sam3u_waitresponse(FAR struct sdio_dev_s *dev, uint32_t cmd)
/* Yes.. Was the error some kind of timeout? */ /* Yes.. Was the error some kind of timeout? */
fdbg("ERROR: cmd: %08x events: %08x SR: %08x\n", fdbg("ERROR: cmd: %08x events: %08x SR: %08x\n",
cmd, HSMCI_CMDRESP_INTS, sr); cmd, priv->cmdrmask, sr);
if ((sr & HSMCI_RESPONSE_TIMEOUT_ERRORS) != 0) if ((sr & HSMCI_RESPONSE_TIMEOUT_ERRORS) != 0)
{ {
/* Yes.. return a timeout error */ /* Yes.. return a timeout error */
priv->wkupevent = SDIOWAIT_CMDDONE|SDIOWAIT_RESPONSEDONE|SDIOWAIT_TIMEOUT;
return -ETIMEDOUT; return -ETIMEDOUT;
} }
else else
{ {
/* No.. return some generic I/O error */ /* No.. return some generic I/O error */
priv->wkupevent = SDIOWAIT_CMDDONE|SDIOWAIT_RESPONSEDONE|SDIOWAIT_ERROR;
return -EIO; return -EIO;
} }
} }
@ -1438,14 +1541,16 @@ static int sam3u_waitresponse(FAR struct sdio_dev_s *dev, uint32_t cmd)
{ {
/* The Command-Response sequence ended with no error */ /* The Command-Response sequence ended with no error */
priv->wkupevent = SDIOWAIT_CMDDONE|SDIOWAIT_RESPONSEDONE;
return OK; return OK;
} }
} }
else if (--timeout <= 0) else if (--timeout <= 0)
{ {
fdbg("ERROR: Timeout cmd: %08x events: %08x SR: %08x\n", fdbg("ERROR: Timeout cmd: %08x events: %08x SR: %08x\n",
cmd, HSMCI_CMDRESP_INTS, sr); cmd, priv->cmdrmask, sr);
priv->wkupevent = SDIOWAIT_TIMEOUT;
return -ETIMEDOUT; return -ETIMEDOUT;
} }
} }
@ -1473,11 +1578,14 @@ static int sam3u_waitresponse(FAR struct sdio_dev_s *dev, uint32_t cmd)
* *
****************************************************************************/ ****************************************************************************/
static int sam3u_recvshortcrc(FAR struct sdio_dev_s *dev, uint32_t cmd, uint32_t *rshort) static int sam3u_recvshort(FAR struct sdio_dev_s *dev, uint32_t cmd, uint32_t *rshort)
{ {
struct sam3u_dev_s *priv = (struct sam3u_dev_s*)dev;
int ret = OK; int ret = OK;
/* R1 Command response (48-bit) /* These responses could have CRC errors:
*
* R1 Command response (48-bit)
* 47 0 Start bit * 47 0 Start bit
* 46 0 Transmission bit (0=from card) * 46 0 Transmission bit (0=from card)
* 45:40 bit5 - bit0 Command index (0-63) * 45:40 bit5 - bit0 Command index (0-63)
@ -1497,9 +1605,19 @@ static int sam3u_recvshortcrc(FAR struct sdio_dev_s *dev, uint32_t cmd, uint32_t
* [15:0] Card status bits {23,22,19,12:0} * [15:0] Card status bits {23,22,19,12:0}
* 7:1 bit6 - bit0 CRC7 * 7:1 bit6 - bit0 CRC7
* 0 1 End bit * 0 1 End bit
*
* But there is no parity on the R3 response and parity errors should
* be ignored.
*
* R3 OCR (48-bit)
* 47 0 Start bit
* 46 0 Transmission bit (0=from card)
* 45:40 bit5 - bit0 Reserved
* 39:8 bit31 - bit0 32-bit OCR register
* 7:1 bit6 - bit0 Reserved
* 0 1 End bit
*/ */
#ifdef CONFIG_DEBUG #ifdef CONFIG_DEBUG
if (!rshort) if (!rshort)
{ {
@ -1511,21 +1629,44 @@ static int sam3u_recvshortcrc(FAR struct sdio_dev_s *dev, uint32_t cmd, uint32_t
else if ((cmd & MMCSD_RESPONSE_MASK) != MMCSD_R1_RESPONSE && else if ((cmd & MMCSD_RESPONSE_MASK) != MMCSD_R1_RESPONSE &&
(cmd & MMCSD_RESPONSE_MASK) != MMCSD_R1B_RESPONSE && (cmd & MMCSD_RESPONSE_MASK) != MMCSD_R1B_RESPONSE &&
(cmd & MMCSD_RESPONSE_MASK) != MMCSD_R6_RESPONSE) (cmd & MMCSD_RESPONSE_MASK) != MMCSD_R6_RESPONSE &&
(cmd & MMCSD_RESPONSE_MASK) != MMCSD_R3_RESPONSE &&
(cmd & MMCSD_RESPONSE_MASK) != MMCSD_R7_RESPONSE)
{ {
fdbg("ERROR: Wrong response CMD=%08x\n", cmd); fdbg("ERROR: Wrong response CMD=%08x\n", cmd);
ret = -EINVAL; ret = -EINVAL;
} }
else
#endif #endif
/* Check for timeout errors */
if ((priv->wkupevent & SDIOWAIT_TIMEOUT) != 0)
{
ret = -EINVAL;
}
/* Check for other errors */
else if ((priv->wkupevent & SDIOWAIT_ERROR) != 0)
{
ret = -EIO;
}
/* Return the R1/R6 response */ /* Return the R1/R6 response */
*rshort = getreg32(SAM3U_HSMCI_RSPR0); else if (rshort)
{
*rshort = getreg32(SAM3U_HSMCI_RSPR0);
}
priv->wkupevent = 0;
return ret; return ret;
} }
static int sam3u_recvlong(FAR struct sdio_dev_s *dev, uint32_t cmd, uint32_t rlong[4]) static int sam3u_recvlong(FAR struct sdio_dev_s *dev, uint32_t cmd, uint32_t rlong[4])
{ {
struct sam3u_dev_s *priv = (struct sam3u_dev_s*)dev;
int ret = OK; int ret = OK;
/* R2 CID, CSD register (136-bit) /* R2 CID, CSD register (136-bit)
@ -1545,50 +1686,34 @@ static int sam3u_recvlong(FAR struct sdio_dev_s *dev, uint32_t cmd, uint32_t rlo
fdbg("ERROR: Wrong response CMD=%08x\n", cmd); fdbg("ERROR: Wrong response CMD=%08x\n", cmd);
ret = -EINVAL; ret = -EINVAL;
} }
else
#endif #endif
/* Check for timeout errors */
if ((priv->wkupevent & SDIOWAIT_TIMEOUT) != 0)
{
ret = -EINVAL;
}
/* Check for other errors */
else if ((priv->wkupevent & SDIOWAIT_ERROR) != 0)
{
ret = -EIO;
}
/* Return the long response */ /* Return the long response */
if (rlong) else if (rlong)
{ {
rlong[0] = getreg32(SAM3U_HSMCI_RSPR0); rlong[0] = getreg32(SAM3U_HSMCI_RSPR0);
rlong[1] = getreg32(SAM3U_HSMCI_RSPR1); rlong[1] = getreg32(SAM3U_HSMCI_RSPR1);
rlong[2] = getreg32(SAM3U_HSMCI_RSPR2); rlong[2] = getreg32(SAM3U_HSMCI_RSPR2);
rlong[3] = getreg32(SAM3U_HSMCI_RSPR3); rlong[3] = getreg32(SAM3U_HSMCI_RSPR3);
} }
return ret;
}
static int sam3u_recvshort(FAR struct sdio_dev_s *dev, uint32_t cmd, uint32_t *rshort) priv->wkupevent = 0;
{
int ret = OK;
/* R3 OCR (48-bit)
* 47 0 Start bit
* 46 0 Transmission bit (0=from card)
* 45:40 bit5 - bit0 Reserved
* 39:8 bit31 - bit0 32-bit OCR register
* 7:1 bit6 - bit0 Reserved
* 0 1 End bit
*/
/* Check that this is the correct response to this command */
#ifdef CONFIG_DEBUG
if ((cmd & MMCSD_RESPONSE_MASK) != MMCSD_R3_RESPONSE &&
(cmd & MMCSD_RESPONSE_MASK) != MMCSD_R7_RESPONSE)
{
fdbg("ERROR: Wrong response CMD=%08x\n", cmd);
ret = -EINVAL;
}
#endif
/* Return the short response */
if (rshort)
{
*rshort = getreg32(SAM3U_HSMCI_RSPR0);
}
return ret; return ret;
} }
@ -1596,6 +1721,8 @@ static int sam3u_recvshort(FAR struct sdio_dev_s *dev, uint32_t cmd, uint32_t *r
static int sam3u_recvnotimpl(FAR struct sdio_dev_s *dev, uint32_t cmd, uint32_t *rnotimpl) static int sam3u_recvnotimpl(FAR struct sdio_dev_s *dev, uint32_t cmd, uint32_t *rnotimpl)
{ {
struct sam3u_dev_s *priv = (struct sam3u_dev_s*)dev;
priv->wkupevent = 0;
return -ENOSYS; return -ENOSYS;
} }
@ -1642,12 +1769,7 @@ static void sam3u_waitenable(FAR struct sdio_dev_s *dev,
waitmask = 0; waitmask = 0;
if ((eventset & (SDIOWAIT_CMDDONE|SDIOWAIT_RESPONSEDONE)) != 0) if ((eventset & (SDIOWAIT_CMDDONE|SDIOWAIT_RESPONSEDONE)) != 0)
{ {
waitmask |= HSMCI_CMDRESP_INTS; waitmask |= priv->cmdrmask;
}
if ((eventset & SDIOWAIT_TRANSFERDONE) != 0)
{
waitmask |= HSMCI_XFRDONE_INTS;
} }
/* Enable event-related interrupts */ /* Enable event-related interrupts */
@ -1734,6 +1856,8 @@ static sdio_eventset_t sam3u_eventwait(FAR struct sdio_dev_s *dev,
/* Check if the event has occurred. When the event has occurred, then /* Check if the event has occurred. When the event has occurred, then
* evenset will be set to 0 and wkupevent will be set to a nonzero value. * evenset will be set to 0 and wkupevent will be set to a nonzero value.
* When wkupevent becomes non-zero, further interrupts will have already
* been disabled.
*/ */
if (wkupevent != 0) if (wkupevent != 0)
@ -1744,9 +1868,6 @@ static sdio_eventset_t sam3u_eventwait(FAR struct sdio_dev_s *dev,
} }
} }
/* Disable event-related interrupts */
sam3u_disablewaitints(priv, 0);
sam3u_dumpsamples(priv); sam3u_dumpsamples(priv);
return wkupevent; return wkupevent;
} }
@ -1883,11 +2004,6 @@ static int sam3u_dmarecvsetup(FAR struct sdio_dev_s *dev, FAR uint8_t *buffer,
sam3u_sampleinit(); sam3u_sampleinit();
sam3u_sample(priv, SAMPLENDX_BEFORE_SETUP); sam3u_sample(priv, SAMPLENDX_BEFORE_SETUP);
/* Save the destination buffer information for use by the interrupt handler */
priv->buffer = (uint32_t*)buffer;
priv->remaining = buflen;
/* Then set up the HSMCI data path */ /* Then set up the HSMCI data path */
//TO BE PROVIDED //TO BE PROVIDED
@ -1946,11 +2062,6 @@ static int sam3u_dmasendsetup(FAR struct sdio_dev_s *dev,
sam3u_sampleinit(); sam3u_sampleinit();
sam3u_sample(priv, SAMPLENDX_BEFORE_SETUP); sam3u_sample(priv, SAMPLENDX_BEFORE_SETUP);
/* Save the source buffer information for use by the interrupt handler */
priv->buffer = (uint32_t*)buffer;
priv->remaining = buflen;
/* Then set up the HSMCI data path */ /* Then set up the HSMCI data path */
//TO BE PROVIDED //TO BE PROVIDED

View File

@ -185,6 +185,8 @@
# define HSMCI_CMDR_TRCMD_START (1 << HSMCI_CMDR_TRCMD_SHIFT) /* Start data transfer */ # define HSMCI_CMDR_TRCMD_START (1 << HSMCI_CMDR_TRCMD_SHIFT) /* Start data transfer */
# define HSMCI_CMDR_TRCMD_STOP (2 << HSMCI_CMDR_TRCMD_SHIFT) /* Stop data transfer */ # define HSMCI_CMDR_TRCMD_STOP (2 << HSMCI_CMDR_TRCMD_SHIFT) /* Stop data transfer */
#define HSMCI_CMDR_TRDIR (1 << 18) /* Bit 18: Transfer Direction */ #define HSMCI_CMDR_TRDIR (1 << 18) /* Bit 18: Transfer Direction */
# define HSMCI_CMDR_TRDIR_WRITE (0 << 18)
# define HSMCI_CMDR_TRDIR_READ (1 << 18)
#define HSMCI_CMDR_TRTYP_SHIFT (19) /* Bits 19-21: Transfer Type */ #define HSMCI_CMDR_TRTYP_SHIFT (19) /* Bits 19-21: Transfer Type */
#define HSMCI_CMDR_TRTYP_MASK (7 << HSMCI_CMDR_TRTYP_SHIFT) #define HSMCI_CMDR_TRTYP_MASK (7 << HSMCI_CMDR_TRTYP_SHIFT)
# define HSMCI_CMDR_TRTYP_SINGLE (0 << HSMCI_CMDR_TRTYP_SHIFT) /* MMC/SDCard Single Block */ # define HSMCI_CMDR_TRTYP_SINGLE (0 << HSMCI_CMDR_TRTYP_SHIFT) /* MMC/SDCard Single Block */

View File

@ -634,6 +634,61 @@ EXTERN void sam3u_dmadump(DMA_HANDLE handle, const struct sam3u_dmaregs_s *regs,
# define sam3u_dmadump(handle,regs,msg) # define sam3u_dmadump(handle,regs,msg)
#endif #endif
/****************************************************************************
* Name: sdio_initialize
*
* Description:
* Initialize SDIO for operation.
*
* Input Parameters:
* slotno - Not used.
*
* Returned Values:
* A reference to an SDIO interface structure. NULL is returned on failures.
*
****************************************************************************/
struct sdio_dev_s; /* See include/nuttx/sdio.h */
EXTERN FAR struct sdio_dev_s *sdio_initialize(int slotno);
/****************************************************************************
* Name: sdio_mediachange
*
* Description:
* Called by board-specific logic -- posssible from an interrupt handler --
* in order to signal to the driver that a card has been inserted or
* removed from the slot
*
* Input Parameters:
* dev - An instance of the SDIO driver device state structure.
* cardinslot - true is a card has been detected in the slot; false if a
* card has been removed from the slot. Only transitions
* (inserted->removed or removed->inserted should be reported)
*
* Returned Values:
* None
*
****************************************************************************/
EXTERN void sdio_mediachange(FAR struct sdio_dev_s *dev, bool cardinslot);
/****************************************************************************
* Name: sdio_wrprotect
*
* Description:
* Called by board-specific logic to report if the card in the slot is
* mechanically write protected.
*
* Input Parameters:
* dev - An instance of the SDIO driver device state structure.
* wrprotect - true is a card is writeprotected.
*
* Returned Values:
* None
*
****************************************************************************/
EXTERN void sdio_wrprotect(FAR struct sdio_dev_s *dev, bool wrprotect);
#undef EXTERN #undef EXTERN
#if defined(__cplusplus) #if defined(__cplusplus)

View File

@ -1496,7 +1496,7 @@ static int stm32_attach(FAR struct sdio_dev_s *dev)
static void stm32_sendcmd(FAR struct sdio_dev_s *dev, uint32_t cmd, uint32_t arg) static void stm32_sendcmd(FAR struct sdio_dev_s *dev, uint32_t cmd, uint32_t arg)
{ {
uint32_t regval; uint32_t regval;
uint32_t cmdidx = (cmd & MMCSD_CMDIDX_MASK) >> MMCSD_CMDIDX_SHIFT; uint32_t cmdidx;
/* Set the SDIO Argument value */ /* Set the SDIO Argument value */