[U-Boot] [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;

From: Hou Zhiqiang B48286@freescale.com
For more than 16MiB Micron chips, there are 3-Byte and 4-Byte address mode, and only the 3-Byte address mode is supported in u-boot. So, reset the SPI flash to 3-Byte address mode in probe to ensure the SPI flash work correctly, because it may be in 4-Byte address mode after warm boot.
Signed-off-by: Hou Zhiqiang B48286@freescale.com --- drivers/mtd/spi/sf_internal.h | 8 ++++++++ drivers/mtd/spi/sf_ops.c | 24 ++++++++++++++++++++++++ drivers/mtd/spi/sf_probe.c | 5 +++++ 3 files changed, 37 insertions(+)
diff --git a/drivers/mtd/spi/sf_internal.h b/drivers/mtd/spi/sf_internal.h index 703d4a7..3d7ed24 100644 --- a/drivers/mtd/spi/sf_internal.h +++ b/drivers/mtd/spi/sf_internal.h @@ -75,6 +75,10 @@ enum { #define CMD_FLAG_STATUS 0x70 #define CMD_CLEAR_FLAG_STATUS 0x50
+/* Used for Macronix and Winbond flashes */ +#define CMD_ENTER_4B_ADDR 0xB7 +#define CMD_EXIT_4B_ADDR 0xE9 + /* Read commands */ #define CMD_READ_ARRAY_SLOW 0x03 #define CMD_READ_ARRAY_FAST 0x0b @@ -227,6 +231,10 @@ int spi_flash_read_common(struct spi_flash *flash, const u8 *cmd, int spi_flash_cmd_read_ops(struct spi_flash *flash, u32 offset, size_t len, void *data);
+#if defined(CONFIG_SPI_FLASH_STMICRO) +int spi_flash_cmd_4B_addr_switch(struct spi_flash *flash, int enable); +#endif + #ifdef CONFIG_SPI_FLASH_MTD int spi_flash_mtd_register(struct spi_flash *flash); void spi_flash_mtd_unregister(void); diff --git a/drivers/mtd/spi/sf_ops.c b/drivers/mtd/spi/sf_ops.c index cbb9f00..1ce14d1 100644 --- a/drivers/mtd/spi/sf_ops.c +++ b/drivers/mtd/spi/sf_ops.c @@ -93,6 +93,30 @@ int spi_flash_cmd_write_config(struct spi_flash *flash, u8 wc) } #endif
+#if defined(CONFIG_SPI_FLASH_STMICRO) +int spi_flash_cmd_4B_addr_switch(struct spi_flash *flash, int enable) +{ + int ret; + u8 cmd; + + cmd = enable ? CMD_ENTER_4B_ADDR : CMD_EXIT_4B_ADDR; + + ret = spi_claim_bus(flash->spi); + if (ret) { + debug("SF: unable to claim SPI bus\n"); + return ret; + } + + ret = spi_flash_cmd_write_enable(flash); + if (ret < 0) { + debug("SF: enabling write failed\n"); + return ret; + } + + return spi_flash_cmd(flash->spi, cmd, NULL, 0); +} +#endif + #ifdef CONFIG_SPI_FLASH_BAR static int spi_flash_cmd_bankaddr_write(struct spi_flash *flash, u8 bank_sel) { diff --git a/drivers/mtd/spi/sf_probe.c b/drivers/mtd/spi/sf_probe.c index e0283dc..5ba7dde 100644 --- a/drivers/mtd/spi/sf_probe.c +++ b/drivers/mtd/spi/sf_probe.c @@ -231,6 +231,11 @@ static int spi_flash_validate_params(struct spi_slave *spi, u8 *idcode, #ifdef CONFIG_SPI_FLASH_STMICRO if (params->flags & E_FSR) flash->poll_cmd = CMD_FLAG_STATUS; + + if (flash->size > SPI_FLASH_16MB_BOUN) { + if (spi_flash_cmd_4B_addr_switch(flash, 0) < 0) + debug("SF: enter 3B address mode failed\n"); + } #endif
/* Configure the BAR - discover bank cmds and read current bank */

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 Subject: [V4 2/2] sf: Turn SPI flash into 3-Byte address mode on Micron chips
From: Hou Zhiqiang B48286@freescale.com
For more than 16MiB Micron chips, there are 3-Byte and 4-Byte address mode, and only the 3-Byte address mode is supported in u-boot. So, reset the SPI flash to 3-Byte address mode in probe to ensure the SPI flash work correctly, because it may be in 4-Byte address mode after warm boot.
Signed-off-by: Hou Zhiqiang B48286@freescale.com
drivers/mtd/spi/sf_internal.h | 8 ++++++++ drivers/mtd/spi/sf_ops.c | 24 ++++++++++++++++++++++++ drivers/mtd/spi/sf_probe.c | 5 +++++ 3 files changed, 37 insertions(+)
diff --git a/drivers/mtd/spi/sf_internal.h b/drivers/mtd/spi/sf_internal.h index 703d4a7..3d7ed24 100644 --- a/drivers/mtd/spi/sf_internal.h +++ b/drivers/mtd/spi/sf_internal.h @@ -75,6 +75,10 @@ enum { #define CMD_FLAG_STATUS 0x70 #define CMD_CLEAR_FLAG_STATUS 0x50
+/* Used for Macronix and Winbond flashes */ +#define CMD_ENTER_4B_ADDR 0xB7 +#define CMD_EXIT_4B_ADDR 0xE9
/* Read commands */ #define CMD_READ_ARRAY_SLOW 0x03 #define CMD_READ_ARRAY_FAST 0x0b @@ -227,6 +231,10 @@ int spi_flash_read_common(struct spi_flash *flash, const u8 *cmd, int spi_flash_cmd_read_ops(struct spi_flash *flash, u32 offset, size_t len, void *data);
+#if defined(CONFIG_SPI_FLASH_STMICRO) +int spi_flash_cmd_4B_addr_switch(struct spi_flash *flash, int enable); +#endif
#ifdef CONFIG_SPI_FLASH_MTD int spi_flash_mtd_register(struct spi_flash *flash); void spi_flash_mtd_unregister(void); diff --git a/drivers/mtd/spi/sf_ops.c b/drivers/mtd/spi/sf_ops.c index cbb9f00..1ce14d1 100644 --- a/drivers/mtd/spi/sf_ops.c +++ b/drivers/mtd/spi/sf_ops.c @@ -93,6 +93,30 @@ int spi_flash_cmd_write_config(struct spi_flash *flash, u8 wc) } #endif
+#if defined(CONFIG_SPI_FLASH_STMICRO) +int spi_flash_cmd_4B_addr_switch(struct spi_flash *flash, int enable) {
- int ret;
- u8 cmd;
- cmd = enable ? CMD_ENTER_4B_ADDR : CMD_EXIT_4B_ADDR;
- ret = spi_claim_bus(flash->spi);
- if (ret) {
debug("SF: unable to claim SPI bus\n");
return ret;
- }
- ret = spi_flash_cmd_write_enable(flash);
- if (ret < 0) {
debug("SF: enabling write failed\n");
return ret;
- }
- return spi_flash_cmd(flash->spi, cmd, NULL, 0); } #endif
#ifdef CONFIG_SPI_FLASH_BAR static int spi_flash_cmd_bankaddr_write(struct spi_flash *flash, u8 bank_sel) { diff --git a/drivers/mtd/spi/sf_probe.c b/drivers/mtd/spi/sf_probe.c index e0283dc..5ba7dde 100644 --- a/drivers/mtd/spi/sf_probe.c +++ b/drivers/mtd/spi/sf_probe.c @@ -231,6 +231,11 @@ static int spi_flash_validate_params(struct spi_slave *spi, u8 *idcode, #ifdef CONFIG_SPI_FLASH_STMICRO if (params->flags & E_FSR) flash->poll_cmd = CMD_FLAG_STATUS;
- if (flash->size > SPI_FLASH_16MB_BOUN) {
if (spi_flash_cmd_4B_addr_switch(flash, 0) < 0)
debug("SF: enter 3B address mode failed\n");
- }
#endif
/* Configure the BAR - discover bank cmds and read current bank */
2.1.0.27.g96db324
Thanks, Zhiqiang

On 10 August 2015 at 08:28, Hou Zhiqiang B48286@freescale.com wrote:
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 Subject: [V4 2/2] sf: Turn SPI flash into 3-Byte address mode on Micron chips
From: Hou Zhiqiang B48286@freescale.com
For more than 16MiB Micron chips, there are 3-Byte and 4-Byte address mode, and only the 3-Byte address mode is supported in u-boot. So, reset the SPI flash to 3-Byte address mode in probe to ensure the SPI flash work correctly, because it may be in 4-Byte address mode after warm boot.
Signed-off-by: Hou Zhiqiang B48286@freescale.com
drivers/mtd/spi/sf_internal.h | 8 ++++++++ drivers/mtd/spi/sf_ops.c | 24 ++++++++++++++++++++++++ drivers/mtd/spi/sf_probe.c | 5 +++++ 3 files changed, 37 insertions(+)
diff --git a/drivers/mtd/spi/sf_internal.h b/drivers/mtd/spi/sf_internal.h index 703d4a7..3d7ed24 100644 --- a/drivers/mtd/spi/sf_internal.h +++ b/drivers/mtd/spi/sf_internal.h @@ -75,6 +75,10 @@ enum { #define CMD_FLAG_STATUS 0x70 #define CMD_CLEAR_FLAG_STATUS 0x50
+/* Used for Macronix and Winbond flashes */ +#define CMD_ENTER_4B_ADDR 0xB7 +#define CMD_EXIT_4B_ADDR 0xE9
/* Read commands */ #define CMD_READ_ARRAY_SLOW 0x03 #define CMD_READ_ARRAY_FAST 0x0b @@ -227,6 +231,10 @@ int spi_flash_read_common(struct spi_flash *flash, const u8 *cmd, int spi_flash_cmd_read_ops(struct spi_flash *flash, u32 offset, size_t len, void *data);
+#if defined(CONFIG_SPI_FLASH_STMICRO) +int spi_flash_cmd_4B_addr_switch(struct spi_flash *flash, int enable); +#endif
#ifdef CONFIG_SPI_FLASH_MTD int spi_flash_mtd_register(struct spi_flash *flash); void spi_flash_mtd_unregister(void); diff --git a/drivers/mtd/spi/sf_ops.c b/drivers/mtd/spi/sf_ops.c index cbb9f00..1ce14d1 100644 --- a/drivers/mtd/spi/sf_ops.c +++ b/drivers/mtd/spi/sf_ops.c @@ -93,6 +93,30 @@ int spi_flash_cmd_write_config(struct spi_flash *flash, u8 wc) } #endif
+#if defined(CONFIG_SPI_FLASH_STMICRO) +int spi_flash_cmd_4B_addr_switch(struct spi_flash *flash, int enable) {
int ret;
u8 cmd;
cmd = enable ? CMD_ENTER_4B_ADDR : CMD_EXIT_4B_ADDR;
ret = spi_claim_bus(flash->spi);
if (ret) {
debug("SF: unable to claim SPI bus\n");
return ret;
}
ret = spi_flash_cmd_write_enable(flash);
if (ret < 0) {
debug("SF: enabling write failed\n");
return ret;
}
return spi_flash_cmd(flash->spi, cmd, NULL, 0); } #endif
#ifdef CONFIG_SPI_FLASH_BAR static int spi_flash_cmd_bankaddr_write(struct spi_flash *flash, u8 bank_sel) { diff --git a/drivers/mtd/spi/sf_probe.c b/drivers/mtd/spi/sf_probe.c index e0283dc..5ba7dde 100644 --- a/drivers/mtd/spi/sf_probe.c +++ b/drivers/mtd/spi/sf_probe.c @@ -231,6 +231,11 @@ static int spi_flash_validate_params(struct spi_slave *spi, u8 *idcode, #ifdef CONFIG_SPI_FLASH_STMICRO if (params->flags & E_FSR) flash->poll_cmd = CMD_FLAG_STATUS;
if (flash->size > SPI_FLASH_16MB_BOUN) {
if (spi_flash_cmd_4B_addr_switch(flash, 0) < 0)
debug("SF: enter 3B address mode failed\n");
}
Don't add STMICRO specific macro, add something like 1. define a macro CONFIG_SF_EN4B 2. probe check for size > 16MiB, and try to set the 4byte addressing.
#endif
/* Configure the BAR - discover bank cmds and read current bank */
-- 2.1.0.27.g96db324
thanks!

-----Original Message----- From: Jagan Teki [mailto:jteki@openedev.com] Sent: 2015年8月11日 1:10 To: Hou Zhiqiang-B48286 Cc: u-boot@lists.denx.de; Sun York-R58495 Subject: Re: [U-Boot] [V4 2/2] sf: Turn SPI flash into 3-Byte address mode on Micron chips
On 10 August 2015 at 08:28, Hou Zhiqiang B48286@freescale.com wrote:
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 Subject: [V4 2/2] sf: Turn SPI flash into 3-Byte address mode on Micron chips
From: Hou Zhiqiang B48286@freescale.com
For more than 16MiB Micron chips, there are 3-Byte and 4-Byte address mode, and only the 3-Byte address mode is supported in u-boot. So, reset the SPI flash to 3-Byte address mode in probe to ensure the SPI flash work correctly, because it may be in 4-Byte address mode after warm boot.
Signed-off-by: Hou Zhiqiang B48286@freescale.com
drivers/mtd/spi/sf_internal.h | 8 ++++++++ drivers/mtd/spi/sf_ops.c | 24 ++++++++++++++++++++++++ drivers/mtd/spi/sf_probe.c | 5 +++++ 3 files changed, 37 insertions(+)
diff --git a/drivers/mtd/spi/sf_internal.h b/drivers/mtd/spi/sf_internal.h index 703d4a7..3d7ed24 100644 --- a/drivers/mtd/spi/sf_internal.h +++ b/drivers/mtd/spi/sf_internal.h @@ -75,6 +75,10 @@ enum { #define CMD_FLAG_STATUS 0x70 #define CMD_CLEAR_FLAG_STATUS 0x50
+/* Used for Macronix and Winbond flashes */ +#define CMD_ENTER_4B_ADDR 0xB7 +#define CMD_EXIT_4B_ADDR 0xE9
/* Read commands */ #define CMD_READ_ARRAY_SLOW 0x03 #define CMD_READ_ARRAY_FAST 0x0b @@ -227,6 +231,10 @@ int spi_flash_read_common(struct spi_flash *flash, const u8 *cmd, int spi_flash_cmd_read_ops(struct spi_flash *flash, u32 offset, size_t len, void *data);
+#if defined(CONFIG_SPI_FLASH_STMICRO) int +spi_flash_cmd_4B_addr_switch(struct spi_flash *flash, int enable); +#endif
#ifdef CONFIG_SPI_FLASH_MTD int spi_flash_mtd_register(struct spi_flash *flash); void spi_flash_mtd_unregister(void); diff --git a/drivers/mtd/spi/sf_ops.c b/drivers/mtd/spi/sf_ops.c index cbb9f00..1ce14d1 100644 --- a/drivers/mtd/spi/sf_ops.c +++ b/drivers/mtd/spi/sf_ops.c @@ -93,6 +93,30 @@ int spi_flash_cmd_write_config(struct spi_flash *flash, u8 wc) } #endif
+#if defined(CONFIG_SPI_FLASH_STMICRO) int +spi_flash_cmd_4B_addr_switch(struct spi_flash *flash, int enable) {
int ret;
u8 cmd;
cmd = enable ? CMD_ENTER_4B_ADDR : CMD_EXIT_4B_ADDR;
ret = spi_claim_bus(flash->spi);
if (ret) {
debug("SF: unable to claim SPI bus\n");
return ret;
}
ret = spi_flash_cmd_write_enable(flash);
if (ret < 0) {
debug("SF: enabling write failed\n");
return ret;
}
return spi_flash_cmd(flash->spi, cmd, NULL, 0); } #endif
#ifdef CONFIG_SPI_FLASH_BAR static int spi_flash_cmd_bankaddr_write(struct spi_flash *flash, u8 bank_sel) { diff --git a/drivers/mtd/spi/sf_probe.c b/drivers/mtd/spi/sf_probe.c index e0283dc..5ba7dde 100644 --- a/drivers/mtd/spi/sf_probe.c +++ b/drivers/mtd/spi/sf_probe.c @@ -231,6 +231,11 @@ static int spi_flash_validate_params(struct spi_slave *spi, u8 *idcode, #ifdef CONFIG_SPI_FLASH_STMICRO if (params->flags & E_FSR) flash->poll_cmd = CMD_FLAG_STATUS;
if (flash->size > SPI_FLASH_16MB_BOUN) {
if (spi_flash_cmd_4B_addr_switch(flash, 0) < 0)
debug("SF: enter 3B address mode failed\n");
}
Don't add STMICRO specific macro, add something like 1. define a macro CONFIG_SF_EN4B 2. probe check for size > 16MiB, and try to set the 4byte addressing.
Thanks for your suggestions and Patch version 5 has been pushed to upstream. In patch version 5: Removed the STMICRO specific macro and add Spansion chips address mode switch support.
Force the chips (>16MiB) switch to 3-Byte address mode in probe, due to the 4-Byte Mode isn't supported so far in U-Boot, so didn't define a macro CONFIG_SF_EN4B, and read/write >16MiB chips by the extend address register.
#endif
/* Configure the BAR - discover bank cmds and read current bank
*/
2.1.0.27.g96db324
thanks!
Jagan | openedev.
Thanks, Zhiqiang

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",
return ret;debug("SF: write %s failed\n", timeout == SPI_FLASH_PROG_TIMEOUT ? "program" : "page erase");
-- 2.1.0.27.g96db324
Thanks, Zhiqiang

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

-----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.

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!

-----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
participants (3)
-
Hou Zhiqiang
-
Jagan Teki
-
Zhiqiang Hou