More Kinetis SDHC fixes

git-svn-id: svn://svn.code.sf.net/p/nuttx/code/trunk@3908 42af7a65-404d-4744-a932-0658087f49c3
This commit is contained in:
patacongo 2011-08-23 19:31:45 +00:00
parent 4d1dfb9002
commit 2b263f9031
2 changed files with 118 additions and 80 deletions

View File

@ -133,6 +133,10 @@
#define SDHC_DVS_MAXTIMEOUT (14) #define SDHC_DVS_MAXTIMEOUT (14)
#define SDHC_DVS_DATATIMEOUT (14) #define SDHC_DVS_DATATIMEOUT (14)
/* Maximum watermark value */
#define SDHC_MAX_WATERMARK 128
/* DMA CCR register settings */ /* DMA CCR register settings */
#define SDHC_RXDMA32_CONFIG (CONFIG_KINETIS_SDHC_DMAPRIO|DMA_CCR_MSIZE_32BITS|\ #define SDHC_RXDMA32_CONFIG (CONFIG_KINETIS_SDHC_DMAPRIO|DMA_CCR_MSIZE_32BITS|\
@ -144,11 +148,14 @@
#define SDHC_RESPERR_INTS (SDHC_INT_CCE|SDHC_INT_CTOE|SDHC_INT_CEBE|SDHC_INT_CIE) #define SDHC_RESPERR_INTS (SDHC_INT_CCE|SDHC_INT_CTOE|SDHC_INT_CEBE|SDHC_INT_CIE)
#define SDHC_RESPDONE_INTS (SDHC_RESPERR_INTS|SDHC_INT_CC) #define SDHC_RESPDONE_INTS (SDHC_RESPERR_INTS|SDHC_INT_CC)
#define SCHC_XFRERR_INTS (SDHC_INT_DCE|SDHC_INT_DTOE|SDHC_INT_DEBE) #define SCHC_XFRERR_INTS (SDHC_INT_DCE|SDHC_INT_DTOE|SDHC_INT_DEBE)
#define SDHC_RCVDONE_INTS (SCHC_XFRERR_INTS|SDHC_INT_BRR|SDHC_INT_TC) #define SDHC_RCVDONE_INTS (SCHC_XFRERR_INTS|SDHC_INT_BRR|SDHC_INT_TC)
#define SDHC_SNDDONE_INTS (SCHC_XFRERR_INTS|SDHC_INT_BWR|SDHC_INT_TC) #define SDHC_SNDDONE_INTS (SCHC_XFRERR_INTS|SDHC_INT_BWR|SDHC_INT_TC)
#define SDHC_XFRDONE_INTS (SCHC_XFRERR_INTS|SDHC_INT_BRR|SDHC_INT_BWR|SDHC_INT_TC) #define SDHC_XFRDONE_INTS (SCHC_XFRERR_INTS|SDHC_INT_BRR|SDHC_INT_BWR|SDHC_INT_TC)
#define SDHC_DMADONE_INTS (SCHC_XFRERR_INTS|SDHC_INT_DINT)
#define SCHC_DMAERR_INTS (SDHC_INT_DCE|SDHC_INT_DTOE|SDHC_INT_DEBE|SDHC_INT_DMAE)
#define SDHC_DMADONE_INTS (SCHC_DMAERR_INTS|SDHC_INT_DINT)
#define SDHC_WAITALL_INTS (SDHC_RESPDONE_INTS|SDHC_XFRDONE_INTS|SDHC_DMADONE_INTS) #define SDHC_WAITALL_INTS (SDHC_RESPDONE_INTS|SDHC_XFRDONE_INTS|SDHC_DMADONE_INTS)
@ -211,7 +218,6 @@ struct kinetis_dev_s
/* DMA data transfer support */ /* DMA data transfer support */
bool widebus; /* Required for DMA support */
#ifdef CONFIG_SDIO_DMA #ifdef CONFIG_SDIO_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 */
bool dmamode; /* true: DMA mode transfer */ bool dmamode; /* true: DMA mode transfer */
@ -791,18 +797,25 @@ static void kinetis_dataconfig(struct kinetis_dev_s *priv, bool bwrite,
if (bwrite) if (bwrite)
{ {
/* Write Watermark Level = 0: BWR will be set when the number of /* Write Watermark Level = 0: BWR will be set when the number of
* queued bytes is less than or equal to 0. * queued words is less than or equal to 0.
*/ */
putreg32(0, KINETIS_SDHC_WML); putreg32(0, KINETIS_SDHC_WML);
} }
else else
{ {
/* Read Watermark Level = 1: BRR will be set when the number of /* Set the Read Watermark Level to the blocksize to be read
* queued bytes is greater than or equal to 1. * (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.
*/ */
putreg32(1 << SDHC_WML_RD_SHIFT, KINETIS_SDHC_WML); unsigned int watermark = (blocksize + 3) >> 2;
if (watermark > (SDHC_MAX_WATERMARK / 2))
{
watermark = (SDHC_MAX_WATERMARK / 2);
}
putreg32(watermark << SDHC_WML_RD_SHIFT, KINETIS_SDHC_WML);
} }
} }
} }
@ -864,6 +877,12 @@ static void kinetis_transmit(struct kinetis_dev_s *priv)
while (priv->remaining > 0 && while (priv->remaining > 0 &&
(getreg32(KINETIS_SDHC_IRQSTAT) & SDHC_INT_BWR) != 0) (getreg32(KINETIS_SDHC_IRQSTAT) & SDHC_INT_BWR) != 0)
{ {
/* Clear BWR. If there is more data in the buffer, writing to the
* buffer should reset BRR.
*/
putreg32(SDHC_INT_BWR, KINETIS_SDHC_IRQSTAT);
/* Is there a full word remaining in the user buffer? */ /* Is there a full word remaining in the user buffer? */
if (priv->remaining >= sizeof(uint32_t)) if (priv->remaining >= sizeof(uint32_t))
@ -919,12 +938,19 @@ static void kinetis_transmit(struct kinetis_dev_s *priv)
static void kinetis_receive(struct kinetis_dev_s *priv) static void kinetis_receive(struct kinetis_dev_s *priv)
{ {
unsigned int watermark;
union union
{ {
uint32_t w; uint32_t w;
uint8_t b[4]; uint8_t b[4];
} data; } data;
/* Set the Read Watermark Level to 1: BRR will be set when the number of
* queued words is greater than or equal to 1.
*/
putreg32(1 << SDHC_WML_RD_SHIFT, KINETIS_SDHC_WML);
/* Loop while there is space to store the data, waiting for buffer read /* Loop while there is space to store the data, waiting for buffer read
* ready (BRR) * ready (BRR)
*/ */
@ -935,7 +961,13 @@ static void kinetis_receive(struct kinetis_dev_s *priv)
while (priv->remaining > 0 && while (priv->remaining > 0 &&
(getreg32(KINETIS_SDHC_IRQSTAT) & SDHC_INT_BRR) != 0) (getreg32(KINETIS_SDHC_IRQSTAT) & SDHC_INT_BRR) != 0)
{ {
/* Read the next word from the RX FIFO */ /* Clear BRR. If there is more data in the buffer, reading from the
* buffer should reset BRR.
*/
putreg32(SDHC_INT_BRR, KINETIS_SDHC_IRQSTAT);
/* Read the next word from the RX buffer */
data.w = getreg32(KINETIS_SDHC_DATPORT); data.w = getreg32(KINETIS_SDHC_DATPORT);
if (priv->remaining >= sizeof(uint32_t)) if (priv->remaining >= sizeof(uint32_t))
@ -963,8 +995,20 @@ static void kinetis_receive(struct kinetis_dev_s *priv)
} }
} }
fllvdbg("Exit: remaining: %d IRQSTAT: %08x\n", /* Set the Read Watermark Level either the number of remaining words to be
priv->remaining, getreg32(KINETIS_SDHC_IRQSTAT)); * read (limited to half of the maximum watermark value)
*/
watermark = ((priv->remaining + 3) >> 2);
if (watermark > (SDHC_MAX_WATERMARK / 2))
{
watermark = (SDHC_MAX_WATERMARK / 2);
}
putreg32(watermark << SDHC_WML_RD_SHIFT, KINETIS_SDHC_WML);
fllvdbg("Exit: remaining: %d IRQSTAT: %08x WML: %08x\n",
priv->remaining, getreg32(KINETIS_SDHC_IRQSTAT),
getreg32(KINETIS_SDHC_WML));
} }
@ -1384,7 +1428,6 @@ static void kinetis_reset(FAR struct sdio_dev_s *dev)
/* DMA data transfer support */ /* DMA data transfer support */
priv->widebus = false; /* Required for DMA support */
#ifdef CONFIG_SDIO_DMA #ifdef CONFIG_SDIO_DMA
priv->dmamode = false; /* true: DMA mode transfer */ priv->dmamode = false; /* true: DMA mode transfer */
#endif #endif
@ -1429,8 +1472,21 @@ static uint8_t kinetis_status(FAR struct sdio_dev_s *dev)
static void kinetis_widebus(FAR struct sdio_dev_s *dev, bool wide) static void kinetis_widebus(FAR struct sdio_dev_s *dev, bool wide)
{ {
struct kinetis_dev_s *priv = (struct kinetis_dev_s *)dev; uint32_t regval;
priv->widebus = wide;
/* Set the Data Transfer Width (DTW) field in the PROCTL register */
regval = getreg32(KINETIS_SDHC_PROCTL);
regval &= ~SDHC_PROCTL_DTW_MASK;
if (wide)
{
regval |= SDHC_PROCTL_DTW_4BIT;
}
else
{
regval |= SDHC_PROCTL_DTW_1BIT;
}
putreg32(regval, KINETIS_SDHC_PROCTL);
} }
/**************************************************************************** /****************************************************************************
@ -1794,15 +1850,6 @@ static int kinetis_sendcmd(FAR struct sdio_dev_s *dev, uint32_t cmd, uint32_t ar
if ((cmd & MMCSD_DATAXFR) != 0) if ((cmd & MMCSD_DATAXFR) != 0)
{ {
/* CCEN=1: The SDHC will check the CRC field in the response. If an
* error is detected, it is reported as a Command CRC Error.
*
* This probably should not always be set?
*/
#warning "Revisit"
regval |= SDHC_XFERTYP_CCCEN;
/* Yes.. Configure the data transfer */ /* Yes.. Configure the data transfer */
switch (cmd & MMCSD_DATAXFR_MASK) switch (cmd & MMCSD_DATAXFR_MASK)
@ -1860,24 +1907,24 @@ static int kinetis_sendcmd(FAR struct sdio_dev_s *dev, uint32_t cmd, uint32_t ar
break; break;
case MMCSD_R1B_RESPONSE: /* Response length 48, check busy & cmdindex*/ case MMCSD_R1B_RESPONSE: /* Response length 48, check busy & cmdindex*/
regval |= (SDHC_XFERTYP_RSPTYP_LEN48BSY | SDHC_XFERTYP_CICEN); regval |= (SDHC_XFERTYP_RSPTYP_LEN48BSY|SDHC_XFERTYP_CICEN|SDHC_XFERTYP_CCCEN);
break; break;
case MMCSD_R1_RESPONSE: /* Response length 48, check cmdindex */ case MMCSD_R1_RESPONSE: /* Response length 48, check cmdindex */
case MMCSD_R5_RESPONSE:
case MMCSD_R6_RESPONSE: case MMCSD_R6_RESPONSE:
regval |= (SDHC_XFERTYP_RSPTYP_LEN48 | SDHC_XFERTYP_CICEN); regval |= (SDHC_XFERTYP_RSPTYP_LEN48|SDHC_XFERTYP_CICEN|SDHC_XFERTYP_CCCEN);
break;
case MMCSD_R2_RESPONSE: /* Response length 136, check CRC */
regval |= (SDHC_XFERTYP_RSPTYP_LEN136|SDHC_XFERTYP_CCCEN);
break; break;
case MMCSD_R3_RESPONSE: /* Response length 48 */ case MMCSD_R3_RESPONSE: /* Response length 48 */
case MMCSD_R4_RESPONSE: case MMCSD_R4_RESPONSE:
case MMCSD_R5_RESPONSE:
case MMCSD_R7_RESPONSE: case MMCSD_R7_RESPONSE:
regval |= SDHC_XFERTYP_RSPTYP_LEN48; regval |= SDHC_XFERTYP_RSPTYP_LEN48;
break; break;
case MMCSD_R2_RESPONSE: /* Response length 136 */
regval |= SDHC_XFERTYP_RSPTYP_LEN136;
break;
} }
/* Enable DMA */ /* Enable DMA */
@ -2372,8 +2419,6 @@ static int kinetis_recvshort(FAR struct sdio_dev_s *dev, uint32_t cmd, uint32_t
static int kinetis_recvnotimpl(FAR struct sdio_dev_s *dev, uint32_t cmd, uint32_t *rnotimpl) static int kinetis_recvnotimpl(FAR struct sdio_dev_s *dev, uint32_t cmd, uint32_t *rnotimpl)
{ {
uint32_t regval;
/* Just return an error */ /* Just return an error */
return -ENOSYS; return -ENOSYS;
@ -2652,7 +2697,6 @@ static int kinetis_dmarecvsetup(FAR struct sdio_dev_s *dev, FAR uint8_t *buffer,
{ {
struct kinetis_dev_s *priv = (struct kinetis_dev_s *)dev; struct kinetis_dev_s *priv = (struct kinetis_dev_s *)dev;
uint32_t blocksize; uint32_t blocksize;
int ret = -EINVAL;
DEBUGASSERT(priv != NULL && buffer != NULL && buflen > 0); DEBUGASSERT(priv != NULL && buffer != NULL && buflen > 0);
DEBUGASSERT(((uint32_t)buffer & 3) == 0); DEBUGASSERT(((uint32_t)buffer & 3) == 0);
@ -2661,10 +2705,8 @@ static int kinetis_dmarecvsetup(FAR struct sdio_dev_s *dev, FAR uint8_t *buffer,
kinetis_datadisable(); kinetis_datadisable();
/* Wide bus operation is required for DMA */ /* Begin sampling register values */
if (priv->widebus)
{
kinetis_sampleinit(); kinetis_sampleinit();
kinetis_sample(priv, SAMPLENDX_BEFORE_SETUP); kinetis_sample(priv, SAMPLENDX_BEFORE_SETUP);
@ -2691,9 +2733,7 @@ static int kinetis_dmarecvsetup(FAR struct sdio_dev_s *dev, FAR uint8_t *buffer,
kinetis_sample(priv, SAMPLENDX_BEFORE_ENABLE); kinetis_sample(priv, SAMPLENDX_BEFORE_ENABLE);
kinetis_dmastart(priv->dma, kinetis_dmacallback, priv, false); kinetis_dmastart(priv->dma, kinetis_dmacallback, priv, false);
kinetis_sample(priv, SAMPLENDX_AFTER_SETUP); kinetis_sample(priv, SAMPLENDX_AFTER_SETUP);
ret = OK; return OK;
}
return ret;
} }
#endif #endif
@ -2722,7 +2762,6 @@ static int kinetis_dmasendsetup(FAR struct sdio_dev_s *dev,
{ {
struct kinetis_dev_s *priv = (struct kinetis_dev_s *)dev; struct kinetis_dev_s *priv = (struct kinetis_dev_s *)dev;
uint32_t blocksize; uint32_t blocksize;
int ret = -EINVAL;
DEBUGASSERT(priv != NULL && buffer != NULL && buflen > 0); DEBUGASSERT(priv != NULL && buffer != NULL && buflen > 0);
DEBUGASSERT(((uint32_t)buffer & 3) == 0); DEBUGASSERT(((uint32_t)buffer & 3) == 0);
@ -2731,10 +2770,8 @@ static int kinetis_dmasendsetup(FAR struct sdio_dev_s *dev,
kinetis_datadisable(); kinetis_datadisable();
/* Wide bus operation is required for DMA */ /* Begin sampling register values */
if (priv->widebus)
{
kinetis_sampleinit(); kinetis_sampleinit();
kinetis_sample(priv, SAMPLENDX_BEFORE_SETUP); kinetis_sample(priv, SAMPLENDX_BEFORE_SETUP);
@ -2764,10 +2801,7 @@ static int kinetis_dmasendsetup(FAR struct sdio_dev_s *dev,
/* Enable TX interrrupts */ /* Enable TX interrrupts */
kinetis_configxfrints(priv, SDHC_DMADONE_INTS); kinetis_configxfrints(priv, SDHC_DMADONE_INTS);
return OK;
ret = OK;
}
return ret;
} }
#endif #endif

View File

@ -331,6 +331,10 @@
#define SDHC_ADMAES_SHIFT (0) /* Bits 0-1: ADMA Error State (when ADMA Error is occurred) */ #define SDHC_ADMAES_SHIFT (0) /* Bits 0-1: ADMA Error State (when ADMA Error is occurred) */
#define SDHC_ADMAES_MASK (3 << SDHC_ADMAES_ADMAES_SHIFT) #define SDHC_ADMAES_MASK (3 << SDHC_ADMAES_ADMAES_SHIFT)
# define SDHC_ADMAES_STOP (0 << SDHC_ADMAES_ADMAES_SHIFT) /* Stop DMA */
# define SDHC_ADMAES_FDS (1 << SDHC_ADMAES_ADMAES_SHIFT) /* Fetch descriptor */
# define SDHC_ADMAES_CADR (2 << SDHC_ADMAES_ADMAES_SHIFT) /* Change address */
# define SDHC_ADMAES_TFR (3 << SDHC_ADMAES_ADMAES_SHIFT) /* Transfer data */
#define SDHC_ADMAES_LME (1 << 2) /* Bit 2: ADMA Length Mismatch Error */ #define SDHC_ADMAES_LME (1 << 2) /* Bit 2: ADMA Length Mismatch Error */
#define SDHC_ADMAES_DCE (1 << 3) /* Bit 3: ADMA Descriptor Error */ #define SDHC_ADMAES_DCE (1 << 3) /* Bit 3: ADMA Descriptor Error */
/* Bits 4-31: Reserved */ /* Bits 4-31: Reserved */