diff mbox

[U-Boot,v2,4/5] mmc: add workaround for eSDHC erratum A009620

Message ID 1470129653-15854-4-git-send-email-yangbo.lu@nxp.com
State Changes Requested
Delegated to: York Sun
Headers show

Commit Message

Yangbo Lu Aug. 2, 2016, 9:20 a.m. UTC
Erratum Title:
Data timeout error not getting set in case of command with busy
response (R1b) as well as for busy period after last write block
transfer.

Description:
In the event that a busy timeout occurs for a command with a busy
response (e.g. R1b response) as well as busy period after the last
write block, the eSDHC does not set the IRQSTAT[DTOE] bit or the
IRQSTAT[TC]. Therefore, the current command transfer is never completed.

Workaround:
Workaround for CMD with busy:
Don't set the XFRTYP[RSP]=2'b11 for commands with busy response and
poll the busy status of the card from the PRSSTAT[DLSL]

Workaround for busy period after last write block:
1. After the command completion interrupt (IRQSTAT[CC]), wait for
   de-assertion of PRSTAT[WTA].
2. Once PRSTAT[WTA] is de-asserted, start the software timer and poll
   the busy signal (DAT0) using PRSTAT[DLSL[0]].
3. Wait for DAT0 signal to go high (which indicate transfer complete)
   or software timer expiry (which indicate data timeout error).
4. Issue soft reset for data (SYSCTL[RSTD]).
5. In case of data timeout error (detected in step 3) perform the
   error recovery.

The workaround for CMD with busy has already been applied in eSDHC
driver. This patch is to add workaround for the 2nd issue.

Signed-off-by: Yangbo Lu <yangbo.lu@nxp.com>
---
Changes for v2:
	- Split original patch into config part and mmc part
---
 drivers/mmc/fsl_esdhc.c | 26 ++++++++++++++++++++++++++
 include/fsl_esdhc.h     |  1 +
 2 files changed, 27 insertions(+)

Comments

Jaehoon Chung Sept. 19, 2016, 12:15 a.m. UTC | #1
On 08/02/2016 06:20 PM, Yangbo Lu wrote:
> Erratum Title:
> Data timeout error not getting set in case of command with busy
> response (R1b) as well as for busy period after last write block
> transfer.
> 
> Description:
> In the event that a busy timeout occurs for a command with a busy
> response (e.g. R1b response) as well as busy period after the last
> write block, the eSDHC does not set the IRQSTAT[DTOE] bit or the
> IRQSTAT[TC]. Therefore, the current command transfer is never completed.
> 
> Workaround:
> Workaround for CMD with busy:
> Don't set the XFRTYP[RSP]=2'b11 for commands with busy response and
> poll the busy status of the card from the PRSSTAT[DLSL]
> 
> Workaround for busy period after last write block:
> 1. After the command completion interrupt (IRQSTAT[CC]), wait for
>    de-assertion of PRSTAT[WTA].
> 2. Once PRSTAT[WTA] is de-asserted, start the software timer and poll
>    the busy signal (DAT0) using PRSTAT[DLSL[0]].
> 3. Wait for DAT0 signal to go high (which indicate transfer complete)
>    or software timer expiry (which indicate data timeout error).
> 4. Issue soft reset for data (SYSCTL[RSTD]).
> 5. In case of data timeout error (detected in step 3) perform the
>    error recovery.
> 
> The workaround for CMD with busy has already been applied in eSDHC
> driver. This patch is to add workaround for the 2nd issue.

This workaround is used the CONFIG_SYS_FSL_ERRATUM_ESDHC_A009620?..
Then if this config is disabled..how is it handling?

> 
> Signed-off-by: Yangbo Lu <yangbo.lu@nxp.com>
> ---
> Changes for v2:
> 	- Split original patch into config part and mmc part
> ---
>  drivers/mmc/fsl_esdhc.c | 26 ++++++++++++++++++++++++++
>  include/fsl_esdhc.h     |  1 +
>  2 files changed, 27 insertions(+)
> 
> diff --git a/drivers/mmc/fsl_esdhc.c b/drivers/mmc/fsl_esdhc.c
> index 80bc177..99cadae 100644
> --- a/drivers/mmc/fsl_esdhc.c
> +++ b/drivers/mmc/fsl_esdhc.c
> @@ -482,6 +482,32 @@ esdhc_send_cmd(struct mmc *mmc, struct mmc_cmd *cmd, struct mmc_data *data)
>  #ifdef CONFIG_SYS_FSL_ESDHC_USE_PIO
>  		esdhc_pio_read_write(mmc, data);
>  #else
> +#ifdef CONFIG_SYS_FSL_ERRATUM_ESDHC_A009620
> +		int timeout = 5000;
> +		if (data->flags & MMC_DATA_WRITE) {
> +			while (esdhc_read32(&regs->prsstat) & PRSSTAT_WTA)
> +				;

I don't want to have the potential infinite loop.

Best Regards,
Jaehoon Chung

> +
> +			/* Poll on DATA0 line for 500 ms */
> +			while (!(esdhc_read32(&regs->prsstat) & PRSSTAT_DAT0)) {
> +				udelay(100);
> +				timeout--;
> +				if (timeout <= 0) {
> +					err = TIMEOUT;
> +					break;
> +				}
> +			}
> +			if (!err) {
> +				esdhc_write32(&regs->sysctl,
> +					      esdhc_read32(&regs->sysctl) |
> +					      SYSCTL_RSTD);
> +				while ((esdhc_read32(&regs->sysctl) &
> +					SYSCTL_RSTD))
> +					;
> +			}
> +			goto out;
> +		}
> +#endif
>  		do {
>  			irqstat = esdhc_read32(&regs->irqstat);
>  
> diff --git a/include/fsl_esdhc.h b/include/fsl_esdhc.h
> index c6f4666..3f146f7 100644
> --- a/include/fsl_esdhc.h
> +++ b/include/fsl_esdhc.h
> @@ -97,6 +97,7 @@
>  #define PRSSTAT_CINS		(0x00010000)
>  #define PRSSTAT_BREN		(0x00000800)
>  #define PRSSTAT_BWEN		(0x00000400)
> +#define PRSSTAT_WTA		(0x00000100)
>  #define PRSSTAT_SDSTB		(0X00000008)
>  #define PRSSTAT_DLA		(0x00000004)
>  #define PRSSTAT_CICHB		(0x00000002)
>
Yangbo Lu Sept. 23, 2016, 7:58 a.m. UTC | #2
> -----Original Message-----
> From: Jaehoon Chung [mailto:jh80.chung@samsung.com]
> Sent: Monday, September 19, 2016 8:16 AM
> To: Y.B. Lu; u-boot@lists.denx.de
> Cc: york sun
> Subject: Re: [v2, 4/5] mmc: add workaround for eSDHC erratum A009620
> 
> On 08/02/2016 06:20 PM, Yangbo Lu wrote:
> > Erratum Title:
> > Data timeout error not getting set in case of command with busy
> > response (R1b) as well as for busy period after last write block
> > transfer.
> >
> > Description:
> > In the event that a busy timeout occurs for a command with a busy
> > response (e.g. R1b response) as well as busy period after the last
> > write block, the eSDHC does not set the IRQSTAT[DTOE] bit or the
> > IRQSTAT[TC]. Therefore, the current command transfer is never completed.
> >
> > Workaround:
> > Workaround for CMD with busy:
> > Don't set the XFRTYP[RSP]=2'b11 for commands with busy response and
> > poll the busy status of the card from the PRSSTAT[DLSL]
> >
> > Workaround for busy period after last write block:
> > 1. After the command completion interrupt (IRQSTAT[CC]), wait for
> >    de-assertion of PRSTAT[WTA].
> > 2. Once PRSTAT[WTA] is de-asserted, start the software timer and poll
> >    the busy signal (DAT0) using PRSTAT[DLSL[0]].
> > 3. Wait for DAT0 signal to go high (which indicate transfer complete)
> >    or software timer expiry (which indicate data timeout error).
> > 4. Issue soft reset for data (SYSCTL[RSTD]).
> > 5. In case of data timeout error (detected in step 3) perform the
> >    error recovery.
> >
> > The workaround for CMD with busy has already been applied in eSDHC
> > driver. This patch is to add workaround for the 2nd issue.
> 
> This workaround is used the CONFIG_SYS_FSL_ERRATUM_ESDHC_A009620?..
> Then if this config is disabled..how is it handling?
> 

[Lu Yangbo-B47093] Yes, it uses CONFIG_SYS_FSL_ERRATUM_ESDHC_A009620.
The erratum is hard to be reproduced normally because it occurs only when data has timeout.
If data timeout occurs, there will be not any data related interrupt. I think driver will hang at below while().

                do {
                        irqstat = esdhc_read32(&regs->irqstat);

                        if (irqstat & IRQSTAT_DTOE) {
                                err = -ETIMEDOUT;
                                goto out;
                        }

                        if (irqstat & DATA_ERR) {
                                err = -ECOMM;
                                goto out;
                        }
                } while ((irqstat & DATA_COMPLETE) != DATA_COMPLETE);

> >
> > Signed-off-by: Yangbo Lu <yangbo.lu@nxp.com>
> > ---
> > Changes for v2:
> > 	- Split original patch into config part and mmc part
> > ---
> >  drivers/mmc/fsl_esdhc.c | 26 ++++++++++++++++++++++++++
> >  include/fsl_esdhc.h     |  1 +
> >  2 files changed, 27 insertions(+)
> >
> > diff --git a/drivers/mmc/fsl_esdhc.c b/drivers/mmc/fsl_esdhc.c index
> > 80bc177..99cadae 100644
> > --- a/drivers/mmc/fsl_esdhc.c
> > +++ b/drivers/mmc/fsl_esdhc.c
> > @@ -482,6 +482,32 @@ esdhc_send_cmd(struct mmc *mmc, struct mmc_cmd
> > *cmd, struct mmc_data *data)  #ifdef CONFIG_SYS_FSL_ESDHC_USE_PIO
> >  		esdhc_pio_read_write(mmc, data);
> >  #else
> > +#ifdef CONFIG_SYS_FSL_ERRATUM_ESDHC_A009620
> > +		int timeout = 5000;
> > +		if (data->flags & MMC_DATA_WRITE) {
> > +			while (esdhc_read32(&regs->prsstat) & PRSSTAT_WTA)
> > +				;
> 
> I don't want to have the potential infinite loop.
> 

[Lu Yangbo-B47093] Sometimes we have to wait for some register status bit,
while the silicon RM believes it couldn't be unexpectable and it will be completed.

I'm not sure how to make it not infinite loop properly. 
Add timeout checking? What's the timeout value should we use ?

> Best Regards,
> Jaehoon Chung
> 
> > +
> > +			/* Poll on DATA0 line for 500 ms */
> > +			while (!(esdhc_read32(&regs->prsstat) & PRSSTAT_DAT0))
> {
> > +				udelay(100);
> > +				timeout--;
> > +				if (timeout <= 0) {
> > +					err = TIMEOUT;
> > +					break;
> > +				}
> > +			}
> > +			if (!err) {
> > +				esdhc_write32(&regs->sysctl,
> > +					      esdhc_read32(&regs->sysctl) |
> > +					      SYSCTL_RSTD);
> > +				while ((esdhc_read32(&regs->sysctl) &
> > +					SYSCTL_RSTD))
> > +					;
> > +			}
> > +			goto out;
> > +		}
> > +#endif
> >  		do {
> >  			irqstat = esdhc_read32(&regs->irqstat);
> >
> > diff --git a/include/fsl_esdhc.h b/include/fsl_esdhc.h index
> > c6f4666..3f146f7 100644
> > --- a/include/fsl_esdhc.h
> > +++ b/include/fsl_esdhc.h
> > @@ -97,6 +97,7 @@
> >  #define PRSSTAT_CINS		(0x00010000)
> >  #define PRSSTAT_BREN		(0x00000800)
> >  #define PRSSTAT_BWEN		(0x00000400)
> > +#define PRSSTAT_WTA		(0x00000100)
> >  #define PRSSTAT_SDSTB		(0X00000008)
> >  #define PRSSTAT_DLA		(0x00000004)
> >  #define PRSSTAT_CICHB		(0x00000002)
> >
diff mbox

Patch

diff --git a/drivers/mmc/fsl_esdhc.c b/drivers/mmc/fsl_esdhc.c
index 80bc177..99cadae 100644
--- a/drivers/mmc/fsl_esdhc.c
+++ b/drivers/mmc/fsl_esdhc.c
@@ -482,6 +482,32 @@  esdhc_send_cmd(struct mmc *mmc, struct mmc_cmd *cmd, struct mmc_data *data)
 #ifdef CONFIG_SYS_FSL_ESDHC_USE_PIO
 		esdhc_pio_read_write(mmc, data);
 #else
+#ifdef CONFIG_SYS_FSL_ERRATUM_ESDHC_A009620
+		int timeout = 5000;
+		if (data->flags & MMC_DATA_WRITE) {
+			while (esdhc_read32(&regs->prsstat) & PRSSTAT_WTA)
+				;
+
+			/* Poll on DATA0 line for 500 ms */
+			while (!(esdhc_read32(&regs->prsstat) & PRSSTAT_DAT0)) {
+				udelay(100);
+				timeout--;
+				if (timeout <= 0) {
+					err = TIMEOUT;
+					break;
+				}
+			}
+			if (!err) {
+				esdhc_write32(&regs->sysctl,
+					      esdhc_read32(&regs->sysctl) |
+					      SYSCTL_RSTD);
+				while ((esdhc_read32(&regs->sysctl) &
+					SYSCTL_RSTD))
+					;
+			}
+			goto out;
+		}
+#endif
 		do {
 			irqstat = esdhc_read32(&regs->irqstat);
 
diff --git a/include/fsl_esdhc.h b/include/fsl_esdhc.h
index c6f4666..3f146f7 100644
--- a/include/fsl_esdhc.h
+++ b/include/fsl_esdhc.h
@@ -97,6 +97,7 @@ 
 #define PRSSTAT_CINS		(0x00010000)
 #define PRSSTAT_BREN		(0x00000800)
 #define PRSSTAT_BWEN		(0x00000400)
+#define PRSSTAT_WTA		(0x00000100)
 #define PRSSTAT_SDSTB		(0X00000008)
 #define PRSSTAT_DLA		(0x00000004)
 #define PRSSTAT_CICHB		(0x00000002)