diff mbox

[U-Boot,V4,1/2] sf: Add clear flag status register operation on Micron chips

Message ID 1437645249-39806-1-git-send-email-B48286@freescale.com
State Superseded
Delegated to: Jagannadha Sutradharudu Teki
Headers show

Commit Message

Zhiqiang Hou July 23, 2015, 9:54 a.m. UTC
From: Hou Zhiqiang <B48286@freescale.com>

Add clear flag status register operation that was required by Micron SPI
flash chips after reading the flag status register to check if the erase
and program operations complete or an error occur.

Signed-off-by: Hou Zhiqiang <B48286@freescale.com>
Signed-off-by: Mingkai.Hu <Mingkai.Hu@freescale.com>
---
 drivers/mtd/spi/sf_internal.h |  9 +++++++++
 drivers/mtd/spi/sf_ops.c      | 40 ++++++++++++++++++++++++++++++++--------
 2 files changed, 41 insertions(+), 8 deletions(-)

Comments

Zhiqiang Hou Aug. 7, 2015, 2:48 a.m. UTC | #1
Hi Jagan,

Do you have any feedback?

> -----Original Message-----

> From: Zhiqiang Hou [mailto:B48286@freescale.com]

> Sent: 2015年7月23日 17:54

> To: u-boot@lists.denx.de; jteki@openedev.com

> Cc: Sun York-R58495; Hu Mingkai-B21284; Hou Zhiqiang-B48286; Hu Mingkai-

> B21284

> Subject: [V4 1/2] sf: Add clear flag status register operation on Micron

> chips

> 

> From: Hou Zhiqiang <B48286@freescale.com>

> 

> Add clear flag status register operation that was required by Micron SPI

> flash chips after reading the flag status register to check if the erase

> and program operations complete or an error occur.

> 

> Signed-off-by: Hou Zhiqiang <B48286@freescale.com>

> Signed-off-by: Mingkai.Hu <Mingkai.Hu@freescale.com>

> ---

>  drivers/mtd/spi/sf_internal.h |  9 +++++++++

>  drivers/mtd/spi/sf_ops.c      | 40 ++++++++++++++++++++++++++++++++-----

> ---

>  2 files changed, 41 insertions(+), 8 deletions(-)

> 

> diff --git a/drivers/mtd/spi/sf_internal.h

> b/drivers/mtd/spi/sf_internal.h index 9fb5557..703d4a7 100644

> --- a/drivers/mtd/spi/sf_internal.h

> +++ b/drivers/mtd/spi/sf_internal.h

> @@ -73,6 +73,7 @@ enum {

>  #define CMD_WRITE_ENABLE		0x06

>  #define CMD_READ_CONFIG			0x35

>  #define CMD_FLAG_STATUS			0x70

> +#define CMD_CLEAR_FLAG_STATUS		0x50

> 

>  /* Read commands */

>  #define CMD_READ_ARRAY_SLOW		0x03

> @@ -96,6 +97,8 @@ enum {

>  #define STATUS_QEB_WINSPAN		(1 << 1)

>  #define STATUS_QEB_MXIC		(1 << 6)

>  #define STATUS_PEC			(1 << 7)

> +#define STATUS_PROT			(1 << 1)

> +#define STATUS_ERASE			(1 << 5)

> 

>  /* Flash timeout values */

>  #define SPI_FLASH_PROG_TIMEOUT		(2 * CONFIG_SYS_HZ)

> @@ -182,6 +185,12 @@ static inline int spi_flash_cmd_write_disable(struct

> spi_flash *flash)

>  	return spi_flash_cmd(flash->spi, CMD_WRITE_DISABLE, NULL, 0);  }

> 

> +/* Clear flag status register */

> +static inline int spi_flash_cmd_clear_flag_status(struct spi_slave

> +*spi) {

> +	return spi_flash_cmd(spi, CMD_CLEAR_FLAG_STATUS, NULL, 0); }

> +

>  /*

>   * Send the read status command to the device and wait for the wip

>   * (write-in-progress) bit to clear itself.

> diff --git a/drivers/mtd/spi/sf_ops.c b/drivers/mtd/spi/sf_ops.c index

> 38592f5..cbb9f00 100644

> --- a/drivers/mtd/spi/sf_ops.c

> +++ b/drivers/mtd/spi/sf_ops.c

> @@ -160,6 +160,7 @@ static int spi_flash_poll_status(struct spi_slave

> *spi, unsigned long timeout,

>  	unsigned long timebase;

>  	unsigned long flags = SPI_XFER_BEGIN;

>  	int ret;

> +	int out_of_time = 1;

>  	u8 status;

>  	u8 check_status = 0x0;

> 

> @@ -182,22 +183,45 @@ static int spi_flash_poll_status(struct spi_slave

> *spi, unsigned long timeout,

>  		WATCHDOG_RESET();

> 

>  		ret = spi_xfer(spi, 8, NULL, &status, 0);

> -		if (ret)

> +		if (ret) {

> +			spi_xfer(spi, 0, NULL, NULL, SPI_XFER_END);

>  			return -1;

> +		}

> 

> -		if ((status & poll_bit) == check_status)

> +		if ((status & poll_bit) == check_status) {

> +			out_of_time = 0;

>  			break;

> +		}

> 

>  	} while (get_timer(timebase) < timeout);

> 

>  	spi_xfer(spi, 0, NULL, NULL, SPI_XFER_END);

> 

> -	if ((status & poll_bit) == check_status)

> -		return 0;

> +	if (out_of_time) {

> +		/* Timed out */

> +		debug("SF: time out!\n");

> +		if (cmd == CMD_FLAG_STATUS) {

> +			if (spi_flash_cmd_clear_flag_status(spi) < 0)

> +				debug("SF: clear flag status failed\n");

> +		}

> +		ret = -1;

> +	}

> +#ifdef CONFIG_SPI_FLASH_STMICRO

> +	else if (cmd == CMD_FLAG_STATUS) {

> +		if (!(status & (STATUS_PROT | STATUS_ERASE))) {

> +			ret = 0;

> +		} else {

> +			debug("SF: flag status error");

> +			ret = -1;

> +		}

> 

> -	/* Timed out */

> -	debug("SF: time out!\n");

> -	return -1;

> +		if (spi_flash_cmd_clear_flag_status(spi) < 0) {

> +			debug("SF: clear flag status failed\n");

> +			ret = -1;

> +		}

> +	}

> +#endif

> +	return ret;

>  }

> 

>  int spi_flash_cmd_wait_ready(struct spi_flash *flash, unsigned long

> timeout) @@ -252,7 +276,7 @@ int spi_flash_write_common(struct spi_flash

> *flash, const u8 *cmd,

> 

>  	ret = spi_flash_cmd_wait_ready(flash, timeout);

>  	if (ret < 0) {

> -		debug("SF: write %s timed out\n",

> +		debug("SF: write %s failed\n",

>  		      timeout == SPI_FLASH_PROG_TIMEOUT ?

>  			"program" : "page erase");

>  		return ret;

> --

> 2.1.0.27.g96db324


Thanks,
Zhiqiang
Jagan Teki Aug. 7, 2015, 8:22 a.m. UTC | #2
On 23 July 2015 at 15:24, Zhiqiang Hou <B48286@freescale.com> wrote:
> From: Hou Zhiqiang <B48286@freescale.com>
>
> Add clear flag status register operation that was required by Micron SPI
> flash chips after reading the flag status register to check if the erase
> and program operations complete or an error occur.

Flag status requires N25Q512 + parts, so clear flag status we need add only
in this scenario is that true?

>
> Signed-off-by: Hou Zhiqiang <B48286@freescale.com>
> Signed-off-by: Mingkai.Hu <Mingkai.Hu@freescale.com>
> ---
>  drivers/mtd/spi/sf_internal.h |  9 +++++++++
>  drivers/mtd/spi/sf_ops.c      | 40 ++++++++++++++++++++++++++++++++--------
>  2 files changed, 41 insertions(+), 8 deletions(-)
>
> diff --git a/drivers/mtd/spi/sf_internal.h b/drivers/mtd/spi/sf_internal.h
> index 9fb5557..703d4a7 100644
> --- a/drivers/mtd/spi/sf_internal.h
> +++ b/drivers/mtd/spi/sf_internal.h
> @@ -73,6 +73,7 @@ enum {
>  #define CMD_WRITE_ENABLE               0x06
>  #define CMD_READ_CONFIG                        0x35
>  #define CMD_FLAG_STATUS                        0x70
> +#define CMD_CLEAR_FLAG_STATUS          0x50
>
>  /* Read commands */
>  #define CMD_READ_ARRAY_SLOW            0x03
> @@ -96,6 +97,8 @@ enum {
>  #define STATUS_QEB_WINSPAN             (1 << 1)
>  #define STATUS_QEB_MXIC                (1 << 6)
>  #define STATUS_PEC                     (1 << 7)
> +#define STATUS_PROT                    (1 << 1)
> +#define STATUS_ERASE                   (1 << 5)
>
>  /* Flash timeout values */
>  #define SPI_FLASH_PROG_TIMEOUT         (2 * CONFIG_SYS_HZ)
> @@ -182,6 +185,12 @@ static inline int spi_flash_cmd_write_disable(struct spi_flash *flash)
>         return spi_flash_cmd(flash->spi, CMD_WRITE_DISABLE, NULL, 0);
>  }
>
> +/* Clear flag status register */
> +static inline int spi_flash_cmd_clear_flag_status(struct spi_slave *spi)
> +{
> +       return spi_flash_cmd(spi, CMD_CLEAR_FLAG_STATUS, NULL, 0);
> +}
> +
>  /*
>   * Send the read status command to the device and wait for the wip
>   * (write-in-progress) bit to clear itself.
> diff --git a/drivers/mtd/spi/sf_ops.c b/drivers/mtd/spi/sf_ops.c
> index 38592f5..cbb9f00 100644
> --- a/drivers/mtd/spi/sf_ops.c
> +++ b/drivers/mtd/spi/sf_ops.c
> @@ -160,6 +160,7 @@ static int spi_flash_poll_status(struct spi_slave *spi, unsigned long timeout,
>         unsigned long timebase;
>         unsigned long flags = SPI_XFER_BEGIN;
>         int ret;
> +       int out_of_time = 1;
>         u8 status;
>         u8 check_status = 0x0;
>
> @@ -182,22 +183,45 @@ static int spi_flash_poll_status(struct spi_slave *spi, unsigned long timeout,
>                 WATCHDOG_RESET();
>
>                 ret = spi_xfer(spi, 8, NULL, &status, 0);
> -               if (ret)
> +               if (ret) {
> +                       spi_xfer(spi, 0, NULL, NULL, SPI_XFER_END);
>                         return -1;
> +               }
>
> -               if ((status & poll_bit) == check_status)
> +               if ((status & poll_bit) == check_status) {
> +                       out_of_time = 0;
>                         break;
> +               }
>
>         } while (get_timer(timebase) < timeout);
>
>         spi_xfer(spi, 0, NULL, NULL, SPI_XFER_END);
>
> -       if ((status & poll_bit) == check_status)
> -               return 0;
> +       if (out_of_time) {
> +               /* Timed out */
> +               debug("SF: time out!\n");
> +               if (cmd == CMD_FLAG_STATUS) {
> +                       if (spi_flash_cmd_clear_flag_status(spi) < 0)
> +                               debug("SF: clear flag status failed\n");
> +               }
> +               ret = -1;
> +       }
> +#ifdef CONFIG_SPI_FLASH_STMICRO
> +       else if (cmd == CMD_FLAG_STATUS) {
> +               if (!(status & (STATUS_PROT | STATUS_ERASE))) {
> +                       ret = 0;
> +               } else {
> +                       debug("SF: flag status error");
> +                       ret = -1;
> +               }
>
> -       /* Timed out */
> -       debug("SF: time out!\n");
> -       return -1;
> +               if (spi_flash_cmd_clear_flag_status(spi) < 0) {
> +                       debug("SF: clear flag status failed\n");
> +                       ret = -1;
> +               }
> +       }
> +#endif
> +       return ret;
>  }
>
>  int spi_flash_cmd_wait_ready(struct spi_flash *flash, unsigned long timeout)
> @@ -252,7 +276,7 @@ int spi_flash_write_common(struct spi_flash *flash, const u8 *cmd,
>
>         ret = spi_flash_cmd_wait_ready(flash, timeout);
>         if (ret < 0) {
> -               debug("SF: write %s timed out\n",
> +               debug("SF: write %s failed\n",
>                       timeout == SPI_FLASH_PROG_TIMEOUT ?
>                         "program" : "page erase");
>                 return ret;
> --
> 2.1.0.27.g96db324
>
> _______________________________________________
> U-Boot mailing list
> U-Boot@lists.denx.de
> http://lists.denx.de/mailman/listinfo/u-boot
Zhiqiang Hou Aug. 10, 2015, 2:52 a.m. UTC | #3
> -----Original Message-----

> From: Jagan Teki [mailto:jteki@openedev.com]

> Sent: 2015年8月7日 16:22

> To: Hou Zhiqiang-B48286

> Cc: u-boot@lists.denx.de; Hu Mingkai-B21284

> Subject: Re: [U-Boot] [V4 1/2] sf: Add clear flag status register

> operation on Micron chips

> 

> On 23 July 2015 at 15:24, Zhiqiang Hou <B48286@freescale.com> wrote:

> > From: Hou Zhiqiang <B48286@freescale.com>

> >

> > Add clear flag status register operation that was required by Micron

> > SPI flash chips after reading the flag status register to check if the

> > erase and program operations complete or an error occur.

> 

> Flag status requires N25Q512 + parts, so clear flag status we need add

> only in this scenario is that true?

> 


Yes, so the clear FSR operation will work only if the chip supports FSR.
And if the chip supports FSR, it will support both read and clear FSR.
So there is a condition branch "if (cmd == CMD_FLAG_STATUS)".

> >

> > Signed-off-by: Hou Zhiqiang <B48286@freescale.com>

> > Signed-off-by: Mingkai.Hu <Mingkai.Hu@freescale.com>

> > ---

> >  drivers/mtd/spi/sf_internal.h |  9 +++++++++

> >  drivers/mtd/spi/sf_ops.c      | 40 ++++++++++++++++++++++++++++++++---

> -----

> >  2 files changed, 41 insertions(+), 8 deletions(-)

> >

> > diff --git a/drivers/mtd/spi/sf_internal.h

> > b/drivers/mtd/spi/sf_internal.h index 9fb5557..703d4a7 100644

> > --- a/drivers/mtd/spi/sf_internal.h

> > +++ b/drivers/mtd/spi/sf_internal.h

> > @@ -73,6 +73,7 @@ enum {

> >  #define CMD_WRITE_ENABLE               0x06

> >  #define CMD_READ_CONFIG                        0x35

> >  #define CMD_FLAG_STATUS                        0x70

> > +#define CMD_CLEAR_FLAG_STATUS          0x50

> >

> >  /* Read commands */

> >  #define CMD_READ_ARRAY_SLOW            0x03

> > @@ -96,6 +97,8 @@ enum {

> >  #define STATUS_QEB_WINSPAN             (1 << 1)

> >  #define STATUS_QEB_MXIC                (1 << 6)

> >  #define STATUS_PEC                     (1 << 7)

> > +#define STATUS_PROT                    (1 << 1)

> > +#define STATUS_ERASE                   (1 << 5)

> >

> >  /* Flash timeout values */

> >  #define SPI_FLASH_PROG_TIMEOUT         (2 * CONFIG_SYS_HZ)

> > @@ -182,6 +185,12 @@ static inline int

> spi_flash_cmd_write_disable(struct spi_flash *flash)

> >         return spi_flash_cmd(flash->spi, CMD_WRITE_DISABLE, NULL, 0);

> > }

> >

> > +/* Clear flag status register */

> > +static inline int spi_flash_cmd_clear_flag_status(struct spi_slave

> > +*spi) {

> > +       return spi_flash_cmd(spi, CMD_CLEAR_FLAG_STATUS, NULL, 0); }

> > +

> >  /*

> >   * Send the read status command to the device and wait for the wip

> >   * (write-in-progress) bit to clear itself.

> > diff --git a/drivers/mtd/spi/sf_ops.c b/drivers/mtd/spi/sf_ops.c index

> > 38592f5..cbb9f00 100644

> > --- a/drivers/mtd/spi/sf_ops.c

> > +++ b/drivers/mtd/spi/sf_ops.c

> > @@ -160,6 +160,7 @@ static int spi_flash_poll_status(struct spi_slave

> *spi, unsigned long timeout,

> >         unsigned long timebase;

> >         unsigned long flags = SPI_XFER_BEGIN;

> >         int ret;

> > +       int out_of_time = 1;

> >         u8 status;

> >         u8 check_status = 0x0;

> >

> > @@ -182,22 +183,45 @@ static int spi_flash_poll_status(struct spi_slave

> *spi, unsigned long timeout,

> >                 WATCHDOG_RESET();

> >

> >                 ret = spi_xfer(spi, 8, NULL, &status, 0);

> > -               if (ret)

> > +               if (ret) {

> > +                       spi_xfer(spi, 0, NULL, NULL, SPI_XFER_END);

> >                         return -1;

> > +               }

> >

> > -               if ((status & poll_bit) == check_status)

> > +               if ((status & poll_bit) == check_status) {

> > +                       out_of_time = 0;

> >                         break;

> > +               }

> >

> >         } while (get_timer(timebase) < timeout);

> >

> >         spi_xfer(spi, 0, NULL, NULL, SPI_XFER_END);

> >

> > -       if ((status & poll_bit) == check_status)

> > -               return 0;

> > +       if (out_of_time) {

> > +               /* Timed out */

> > +               debug("SF: time out!\n");

> > +               if (cmd == CMD_FLAG_STATUS) {

> > +                       if (spi_flash_cmd_clear_flag_status(spi) < 0)

> > +                               debug("SF: clear flag status failed\n");

> > +               }

> > +               ret = -1;

> > +       }

> > +#ifdef CONFIG_SPI_FLASH_STMICRO

> > +       else if (cmd == CMD_FLAG_STATUS) {

> > +               if (!(status & (STATUS_PROT | STATUS_ERASE))) {

> > +                       ret = 0;

> > +               } else {

> > +                       debug("SF: flag status error");

> > +                       ret = -1;

> > +               }

> >

> > -       /* Timed out */

> > -       debug("SF: time out!\n");

> > -       return -1;

> > +               if (spi_flash_cmd_clear_flag_status(spi) < 0) {

> > +                       debug("SF: clear flag status failed\n");

> > +                       ret = -1;

> > +               }

> > +       }

> > +#endif

> > +       return ret;

> >  }

> >

> >  int spi_flash_cmd_wait_ready(struct spi_flash *flash, unsigned long

> > timeout) @@ -252,7 +276,7 @@ int spi_flash_write_common(struct

> > spi_flash *flash, const u8 *cmd,

> >

> >         ret = spi_flash_cmd_wait_ready(flash, timeout);

> >         if (ret < 0) {

> > -               debug("SF: write %s timed out\n",

> > +               debug("SF: write %s failed\n",

> >                       timeout == SPI_FLASH_PROG_TIMEOUT ?

> >                         "program" : "page erase");

> >                 return ret;

> > --

> > 2.1.0.27.g96db324

> >

> > _______________________________________________

> > U-Boot mailing list

> > U-Boot@lists.denx.de

> > http://lists.denx.de/mailman/listinfo/u-boot

> 

> 

> 

> --

> Jagan | openedev.
Jagan Teki Aug. 10, 2015, 5:05 p.m. UTC | #4
On 23 July 2015 at 15:24, Zhiqiang Hou <B48286@freescale.com> wrote:
> From: Hou Zhiqiang <B48286@freescale.com>
>
> Add clear flag status register operation that was required by Micron SPI
> flash chips after reading the flag status register to check if the erase
> and program operations complete or an error occur.
>
> Signed-off-by: Hou Zhiqiang <B48286@freescale.com>
> Signed-off-by: Mingkai.Hu <Mingkai.Hu@freescale.com>
> ---
>  drivers/mtd/spi/sf_internal.h |  9 +++++++++
>  drivers/mtd/spi/sf_ops.c      | 40 ++++++++++++++++++++++++++++++++--------
>  2 files changed, 41 insertions(+), 8 deletions(-)
>
> diff --git a/drivers/mtd/spi/sf_internal.h b/drivers/mtd/spi/sf_internal.h
> index 9fb5557..703d4a7 100644
> --- a/drivers/mtd/spi/sf_internal.h
> +++ b/drivers/mtd/spi/sf_internal.h
> @@ -73,6 +73,7 @@ enum {
>  #define CMD_WRITE_ENABLE               0x06
>  #define CMD_READ_CONFIG                        0x35
>  #define CMD_FLAG_STATUS                        0x70
> +#define CMD_CLEAR_FLAG_STATUS          0x50
>
>  /* Read commands */
>  #define CMD_READ_ARRAY_SLOW            0x03
> @@ -96,6 +97,8 @@ enum {
>  #define STATUS_QEB_WINSPAN             (1 << 1)
>  #define STATUS_QEB_MXIC                (1 << 6)
>  #define STATUS_PEC                     (1 << 7)
> +#define STATUS_PROT                    (1 << 1)
> +#define STATUS_ERASE                   (1 << 5)
>
>  /* Flash timeout values */
>  #define SPI_FLASH_PROG_TIMEOUT         (2 * CONFIG_SYS_HZ)
> @@ -182,6 +185,12 @@ static inline int spi_flash_cmd_write_disable(struct spi_flash *flash)
>         return spi_flash_cmd(flash->spi, CMD_WRITE_DISABLE, NULL, 0);
>  }
>
> +/* Clear flag status register */
> +static inline int spi_flash_cmd_clear_flag_status(struct spi_slave *spi)
> +{
> +       return spi_flash_cmd(spi, CMD_CLEAR_FLAG_STATUS, NULL, 0);
> +}
> +
>  /*
>   * Send the read status command to the device and wait for the wip
>   * (write-in-progress) bit to clear itself.
> diff --git a/drivers/mtd/spi/sf_ops.c b/drivers/mtd/spi/sf_ops.c
> index 38592f5..cbb9f00 100644
> --- a/drivers/mtd/spi/sf_ops.c
> +++ b/drivers/mtd/spi/sf_ops.c
> @@ -160,6 +160,7 @@ static int spi_flash_poll_status(struct spi_slave *spi, unsigned long timeout,
>         unsigned long timebase;
>         unsigned long flags = SPI_XFER_BEGIN;
>         int ret;
> +       int out_of_time = 1;
>         u8 status;
>         u8 check_status = 0x0;
>
> @@ -182,22 +183,45 @@ static int spi_flash_poll_status(struct spi_slave *spi, unsigned long timeout,
>                 WATCHDOG_RESET();
>
>                 ret = spi_xfer(spi, 8, NULL, &status, 0);
> -               if (ret)
> +               if (ret) {
> +                       spi_xfer(spi, 0, NULL, NULL, SPI_XFER_END);
>                         return -1;
> +               }
>
> -               if ((status & poll_bit) == check_status)
> +               if ((status & poll_bit) == check_status) {
> +                       out_of_time = 0;
>                         break;
> +               }
>
>         } while (get_timer(timebase) < timeout);
>
>         spi_xfer(spi, 0, NULL, NULL, SPI_XFER_END);
>
> -       if ((status & poll_bit) == check_status)
> -               return 0;
> +       if (out_of_time) {
> +               /* Timed out */
> +               debug("SF: time out!\n");
> +               if (cmd == CMD_FLAG_STATUS) {
> +                       if (spi_flash_cmd_clear_flag_status(spi) < 0)
> +                               debug("SF: clear flag status failed\n");
> +               }
> +               ret = -1;
> +       }
> +#ifdef CONFIG_SPI_FLASH_STMICRO
> +       else if (cmd == CMD_FLAG_STATUS) {
> +               if (!(status & (STATUS_PROT | STATUS_ERASE))) {
> +                       ret = 0;
> +               } else {
> +                       debug("SF: flag status error");
> +                       ret = -1;
> +               }

Don't add any #ifdef for STMICRO, as this clear status only require when FSR
used, so try to do that when ever FSR does.

Something like here:

/* read */
spi_xfer for FSR and then CFSR

/* status */
spi_xfer for FSR and then CFSR

Let me know if you need any inputs.

>
> -       /* Timed out */
> -       debug("SF: time out!\n");
> -       return -1;
> +               if (spi_flash_cmd_clear_flag_status(spi) < 0) {
> +                       debug("SF: clear flag status failed\n");
> +                       ret = -1;
> +               }
> +       }
> +#endif
> +       return ret;
>  }
>
>  int spi_flash_cmd_wait_ready(struct spi_flash *flash, unsigned long timeout)
> @@ -252,7 +276,7 @@ int spi_flash_write_common(struct spi_flash *flash, const u8 *cmd,
>
>         ret = spi_flash_cmd_wait_ready(flash, timeout);
>         if (ret < 0) {
> -               debug("SF: write %s timed out\n",
> +               debug("SF: write %s failed\n",
>                       timeout == SPI_FLASH_PROG_TIMEOUT ?
>                         "program" : "page erase");
>                 return ret;
> --
> 2.1.0.27.g96db324

thanks!
Zhiqiang Hou Aug. 11, 2015, 11:26 a.m. UTC | #5
> -----Original Message-----

> From: Jagan Teki [mailto:jteki@openedev.com]

> Sent: 2015年8月11日 1:06

> To: Hou Zhiqiang-B48286

> Cc: u-boot@lists.denx.de; Hu Mingkai-B21284

> Subject: Re: [U-Boot] [V4 1/2] sf: Add clear flag status register

> operation on Micron chips

> 

> On 23 July 2015 at 15:24, Zhiqiang Hou <B48286@freescale.com> wrote:

> > From: Hou Zhiqiang <B48286@freescale.com>

> >

> > Add clear flag status register operation that was required by Micron

> > SPI flash chips after reading the flag status register to check if the

> > erase and program operations complete or an error occur.

> >

> > Signed-off-by: Hou Zhiqiang <B48286@freescale.com>

> > Signed-off-by: Mingkai.Hu <Mingkai.Hu@freescale.com>

> > ---

> >  drivers/mtd/spi/sf_internal.h |  9 +++++++++

> >  drivers/mtd/spi/sf_ops.c      | 40 ++++++++++++++++++++++++++++++++---

> -----

> >  2 files changed, 41 insertions(+), 8 deletions(-)

> >

> > diff --git a/drivers/mtd/spi/sf_internal.h

> > b/drivers/mtd/spi/sf_internal.h index 9fb5557..703d4a7 100644

> > --- a/drivers/mtd/spi/sf_internal.h

> > +++ b/drivers/mtd/spi/sf_internal.h

> > @@ -73,6 +73,7 @@ enum {

> >  #define CMD_WRITE_ENABLE               0x06

> >  #define CMD_READ_CONFIG                        0x35

> >  #define CMD_FLAG_STATUS                        0x70

> > +#define CMD_CLEAR_FLAG_STATUS          0x50

> >

> >  /* Read commands */

> >  #define CMD_READ_ARRAY_SLOW            0x03

> > @@ -96,6 +97,8 @@ enum {

> >  #define STATUS_QEB_WINSPAN             (1 << 1)

> >  #define STATUS_QEB_MXIC                (1 << 6)

> >  #define STATUS_PEC                     (1 << 7)

> > +#define STATUS_PROT                    (1 << 1)

> > +#define STATUS_ERASE                   (1 << 5)

> >

> >  /* Flash timeout values */

> >  #define SPI_FLASH_PROG_TIMEOUT         (2 * CONFIG_SYS_HZ)

> > @@ -182,6 +185,12 @@ static inline int

> spi_flash_cmd_write_disable(struct spi_flash *flash)

> >         return spi_flash_cmd(flash->spi, CMD_WRITE_DISABLE, NULL, 0);

> > }

> >

> > +/* Clear flag status register */

> > +static inline int spi_flash_cmd_clear_flag_status(struct spi_slave

> > +*spi) {

> > +       return spi_flash_cmd(spi, CMD_CLEAR_FLAG_STATUS, NULL, 0); }

> > +

> >  /*

> >   * Send the read status command to the device and wait for the wip

> >   * (write-in-progress) bit to clear itself.

> > diff --git a/drivers/mtd/spi/sf_ops.c b/drivers/mtd/spi/sf_ops.c index

> > 38592f5..cbb9f00 100644

> > --- a/drivers/mtd/spi/sf_ops.c

> > +++ b/drivers/mtd/spi/sf_ops.c

> > @@ -160,6 +160,7 @@ static int spi_flash_poll_status(struct spi_slave

> *spi, unsigned long timeout,

> >         unsigned long timebase;

> >         unsigned long flags = SPI_XFER_BEGIN;

> >         int ret;

> > +       int out_of_time = 1;

> >         u8 status;

> >         u8 check_status = 0x0;

> >

> > @@ -182,22 +183,45 @@ static int spi_flash_poll_status(struct spi_slave

> *spi, unsigned long timeout,

> >                 WATCHDOG_RESET();

> >

> >                 ret = spi_xfer(spi, 8, NULL, &status, 0);

> > -               if (ret)

> > +               if (ret) {

> > +                       spi_xfer(spi, 0, NULL, NULL, SPI_XFER_END);

> >                         return -1;

> > +               }

> >

> > -               if ((status & poll_bit) == check_status)

> > +               if ((status & poll_bit) == check_status) {

> > +                       out_of_time = 0;

> >                         break;

> > +               }

> >

> >         } while (get_timer(timebase) < timeout);

> >

> >         spi_xfer(spi, 0, NULL, NULL, SPI_XFER_END);

> >

> > -       if ((status & poll_bit) == check_status)

> > -               return 0;

> > +       if (out_of_time) {

> > +               /* Timed out */

> > +               debug("SF: time out!\n");

> > +               if (cmd == CMD_FLAG_STATUS) {

> > +                       if (spi_flash_cmd_clear_flag_status(spi) < 0)

> > +                               debug("SF: clear flag status failed\n");

> > +               }

> > +               ret = -1;

> > +       }

> > +#ifdef CONFIG_SPI_FLASH_STMICRO

> > +       else if (cmd == CMD_FLAG_STATUS) {

> > +               if (!(status & (STATUS_PROT | STATUS_ERASE))) {

> > +                       ret = 0;

> > +               } else {

> > +                       debug("SF: flag status error");

> > +                       ret = -1;

> > +               }

> 

> Don't add any #ifdef for STMICRO, as this clear status only require when

> FSR used, so try to do that when ever FSR does.

> 

> Something like here:

> 

> /* read */

> spi_xfer for FSR and then CFSR

> 

> /* status */

> spi_xfer for FSR and then CFSR

> 

> Let me know if you need any inputs.

> 

 
Thanks for your suggestions!
In patch v5, removed the #ifdef and clear the FSR only when there is any error
Bit has been set.

> >

> > -       /* Timed out */

> > -       debug("SF: time out!\n");

> > -       return -1;

> > +               if (spi_flash_cmd_clear_flag_status(spi) < 0) {

> > +                       debug("SF: clear flag status failed\n");

> > +                       ret = -1;

> > +               }

> > +       }

> > +#endif

> > +       return ret;

> >  }

> >

> >  int spi_flash_cmd_wait_ready(struct spi_flash *flash, unsigned long

> > timeout) @@ -252,7 +276,7 @@ int spi_flash_write_common(struct

> > spi_flash *flash, const u8 *cmd,

> >

> >         ret = spi_flash_cmd_wait_ready(flash, timeout);

> >         if (ret < 0) {

> > -               debug("SF: write %s timed out\n",

> > +               debug("SF: write %s failed\n",

> >                       timeout == SPI_FLASH_PROG_TIMEOUT ?

> >                         "program" : "page erase");

> >                 return ret;

> > --

> > 2.1.0.27.g96db324

> 

> thanks!

> --

> Jagan | openedev.


Thanks,
Zhiqiang
diff mbox

Patch

diff --git a/drivers/mtd/spi/sf_internal.h b/drivers/mtd/spi/sf_internal.h
index 9fb5557..703d4a7 100644
--- a/drivers/mtd/spi/sf_internal.h
+++ b/drivers/mtd/spi/sf_internal.h
@@ -73,6 +73,7 @@  enum {
 #define CMD_WRITE_ENABLE		0x06
 #define CMD_READ_CONFIG			0x35
 #define CMD_FLAG_STATUS			0x70
+#define CMD_CLEAR_FLAG_STATUS		0x50
 
 /* Read commands */
 #define CMD_READ_ARRAY_SLOW		0x03
@@ -96,6 +97,8 @@  enum {
 #define STATUS_QEB_WINSPAN		(1 << 1)
 #define STATUS_QEB_MXIC		(1 << 6)
 #define STATUS_PEC			(1 << 7)
+#define STATUS_PROT			(1 << 1)
+#define STATUS_ERASE			(1 << 5)
 
 /* Flash timeout values */
 #define SPI_FLASH_PROG_TIMEOUT		(2 * CONFIG_SYS_HZ)
@@ -182,6 +185,12 @@  static inline int spi_flash_cmd_write_disable(struct spi_flash *flash)
 	return spi_flash_cmd(flash->spi, CMD_WRITE_DISABLE, NULL, 0);
 }
 
+/* Clear flag status register */
+static inline int spi_flash_cmd_clear_flag_status(struct spi_slave *spi)
+{
+	return spi_flash_cmd(spi, CMD_CLEAR_FLAG_STATUS, NULL, 0);
+}
+
 /*
  * Send the read status command to the device and wait for the wip
  * (write-in-progress) bit to clear itself.
diff --git a/drivers/mtd/spi/sf_ops.c b/drivers/mtd/spi/sf_ops.c
index 38592f5..cbb9f00 100644
--- a/drivers/mtd/spi/sf_ops.c
+++ b/drivers/mtd/spi/sf_ops.c
@@ -160,6 +160,7 @@  static int spi_flash_poll_status(struct spi_slave *spi, unsigned long timeout,
 	unsigned long timebase;
 	unsigned long flags = SPI_XFER_BEGIN;
 	int ret;
+	int out_of_time = 1;
 	u8 status;
 	u8 check_status = 0x0;
 
@@ -182,22 +183,45 @@  static int spi_flash_poll_status(struct spi_slave *spi, unsigned long timeout,
 		WATCHDOG_RESET();
 
 		ret = spi_xfer(spi, 8, NULL, &status, 0);
-		if (ret)
+		if (ret) {
+			spi_xfer(spi, 0, NULL, NULL, SPI_XFER_END);
 			return -1;
+		}
 
-		if ((status & poll_bit) == check_status)
+		if ((status & poll_bit) == check_status) {
+			out_of_time = 0;
 			break;
+		}
 
 	} while (get_timer(timebase) < timeout);
 
 	spi_xfer(spi, 0, NULL, NULL, SPI_XFER_END);
 
-	if ((status & poll_bit) == check_status)
-		return 0;
+	if (out_of_time) {
+		/* Timed out */
+		debug("SF: time out!\n");
+		if (cmd == CMD_FLAG_STATUS) {
+			if (spi_flash_cmd_clear_flag_status(spi) < 0)
+				debug("SF: clear flag status failed\n");
+		}
+		ret = -1;
+	}
+#ifdef CONFIG_SPI_FLASH_STMICRO
+	else if (cmd == CMD_FLAG_STATUS) {
+		if (!(status & (STATUS_PROT | STATUS_ERASE))) {
+			ret = 0;
+		} else {
+			debug("SF: flag status error");
+			ret = -1;
+		}
 
-	/* Timed out */
-	debug("SF: time out!\n");
-	return -1;
+		if (spi_flash_cmd_clear_flag_status(spi) < 0) {
+			debug("SF: clear flag status failed\n");
+			ret = -1;
+		}
+	}
+#endif
+	return ret;
 }
 
 int spi_flash_cmd_wait_ready(struct spi_flash *flash, unsigned long timeout)
@@ -252,7 +276,7 @@  int spi_flash_write_common(struct spi_flash *flash, const u8 *cmd,
 
 	ret = spi_flash_cmd_wait_ready(flash, timeout);
 	if (ret < 0) {
-		debug("SF: write %s timed out\n",
+		debug("SF: write %s failed\n",
 		      timeout == SPI_FLASH_PROG_TIMEOUT ?
 			"program" : "page erase");
 		return ret;