[U-Boot] [PATCH V5 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, which support FSR. And if an error bit of FSR have been set, it must be cleared by the clear FSR operation.
Signed-off-by: Hou Zhiqiang B48286@freescale.com Signed-off-by: Mingkai.Hu Mingkai.Hu@freescale.com --- Tested on T1042RDB board.
V5: 1. Removed #ifdef for STMICRO. 2. Add checking Protection and Voltage error bits. 3. Only if there is any error bit set, issue the clear FSR command. V4: Split the the patch to 2 patches for clear FSR and SPI flash address mode. V3: Generate the patch based on the latest tree git://git.denx.de/u-boot.git. V2: Add the operation of enter 3 Byte address mode in probe. V1: Based on git://git.denx.de/u-boot.git.
drivers/mtd/spi/sf_internal.h | 13 +++++++++++++ drivers/mtd/spi/sf_ops.c | 29 +++++++++++++++++++++-------- 2 files changed, 34 insertions(+), 8 deletions(-)
diff --git a/drivers/mtd/spi/sf_internal.h b/drivers/mtd/spi/sf_internal.h index 9fb5557..1de1dac 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,12 @@ enum { #define STATUS_QEB_WINSPAN (1 << 1) #define STATUS_QEB_MXIC (1 << 6) #define STATUS_PEC (1 << 7) +#define STATUS_PROT_ERR (1 << 1) +#define STATUS_VOLT_ERR (1 << 3) +#define STATUS_PROG_ERR (1 << 4) +#define STATUS_ERASE_ERR (1 << 5) +#define FLAG_ERR_MASK (STATUS_PROT_ERR | STATUS_VOLT_ERR | \ + STATUS_PROG_ERR | STATUS_ERASE_ERR)
/* Flash timeout values */ #define SPI_FLASH_PROG_TIMEOUT (2 * CONFIG_SYS_HZ) @@ -182,6 +189,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..deebcab 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,34 @@ 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"); + ret = -1; + } + + if (cmd == CMD_FLAG_STATUS && status & FLAG_ERR_MASK) { + debug("SF: flag status(0x%x) error occured!\n", status); + if (spi_flash_cmd_clear_flag_status(spi) < 0) + debug("SF: clear flag status failed!\n"); + ret = -1; + }
- /* Timed out */ - debug("SF: time out!\n"); - return -1; + return ret; }
int spi_flash_cmd_wait_ready(struct spi_flash *flash, unsigned long timeout) @@ -252,7 +265,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 SPI flash chips, there are 3-Byte and 4-Byte address mode, and only the 3-Byte address mode is supported in U-Boot so far. So, reset the SPI flash to 3-Byte address mode in probe to ensure the SPI flash work correctly, because it may has been set to 4-Byte address mode after warm boot.
Signed-off-by: Hou Zhiqiang B48286@freescale.com --- Tested on T1042RDB board.
V5: 1. Removed #ifdef for STMICRO. 2. Add support for Spansion chips (>16MiB) switch to 3-Byte address mode. V4: Split the the patch to 2 patches for clear FSR and SPI flash address mode. V3: Generate the patch based on the latest tree git://git.denx.de/u-boot.git. V2: Add the operation of enter 3 Byte address mode in probe. V1: Based on git://git.denx.de/u-boot.git.
drivers/mtd/spi/sf_internal.h | 7 +++++++ drivers/mtd/spi/sf_ops.c | 36 ++++++++++++++++++++++++++++++++++++ drivers/mtd/spi/sf_probe.c | 10 ++++++++++ 3 files changed, 53 insertions(+)
diff --git a/drivers/mtd/spi/sf_internal.h b/drivers/mtd/spi/sf_internal.h index 1de1dac..9519bd8 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 Micron, 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 @@ -231,6 +235,9 @@ 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);
+int spi_flash_cmd_4B_addr_switch(struct spi_flash *flash, + int enable, u8 idcode0); + #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 deebcab..ace1156 100644 --- a/drivers/mtd/spi/sf_ops.c +++ b/drivers/mtd/spi/sf_ops.c @@ -93,6 +93,42 @@ int spi_flash_cmd_write_config(struct spi_flash *flash, u8 wc) } #endif
+int spi_flash_cmd_4B_addr_switch(struct spi_flash *flash, + int enable, u8 idcode0) +{ + int ret; + u8 cmd, bar; + bool need_wren = false; + + ret = spi_claim_bus(flash->spi); + if (ret) { + debug("SF: unable to claim SPI bus\n"); + return ret; + } + + switch (idcode0) { + case SPI_FLASH_CFI_MFR_STMICRO: + /* Some Micron need WREN command; all will accept it */ + need_wren = true; + case SPI_FLASH_CFI_MFR_MACRONIX: + case SPI_FLASH_CFI_MFR_WINBOND: + if (need_wren) + spi_flash_cmd_write_enable(flash); + + cmd = enable ? CMD_ENTER_4B_ADDR : CMD_EXIT_4B_ADDR; + ret = spi_flash_cmd(flash->spi, cmd, NULL, 0); + if (need_wren) + spi_flash_cmd_write_disable(flash); + + return ret; + default: + /* Spansion style */ + bar = enable << 7; + cmd = CMD_BANKADDR_BRWR; + return spi_flash_cmd_write(flash->spi, &cmd, 1, &bar, 1); + } +} + #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..3b204f8 100644 --- a/drivers/mtd/spi/sf_probe.c +++ b/drivers/mtd/spi/sf_probe.c @@ -170,6 +170,16 @@ static int spi_flash_validate_params(struct spi_slave *spi, u8 *idcode, flash->page_size <<= flash->shift; flash->sector_size = params->sector_size << flash->shift; flash->size = flash->sector_size * params->nr_sectors << flash->shift; + + /* + * So far, the 4-byte address mode haven't been supported in U-Boot, + * and make sure the chip (> 16MiB) in default 3-byte address mode, + * in case of warm bootup, the chip was set to 4-byte mode in kernel. + */ + if (flash->size > SPI_FLASH_16MB_BOUN) { + if (spi_flash_cmd_4B_addr_switch(flash, false, idcode[0]) < 0) + debug("SF: enter 3B address mode failed\n"); + } #ifdef CONFIG_SF_DUAL_FLASH if (flash->dual_flash & SF_DUAL_STACKED_FLASH) flash->size <<= 1;

On 11 August 2015 at 16:25, Zhiqiang Hou B48286@freescale.com wrote:
From: Hou Zhiqiang B48286@freescale.com
For more than 16MiB SPI flash chips, there are 3-Byte and 4-Byte address mode, and only the 3-Byte address mode is supported in U-Boot so far. So, reset the SPI flash to 3-Byte address mode in probe to ensure the SPI flash work correctly, because it may has been set to 4-Byte address mode after warm boot.
Signed-off-by: Hou Zhiqiang B48286@freescale.com
Tested on T1042RDB board.
V5: 1. Removed #ifdef for STMICRO. 2. Add support for Spansion chips (>16MiB) switch to 3-Byte address mode. V4: Split the the patch to 2 patches for clear FSR and SPI flash address mode. V3: Generate the patch based on the latest tree git://git.denx.de/u-boot.git. V2: Add the operation of enter 3 Byte address mode in probe. V1: Based on git://git.denx.de/u-boot.git.
drivers/mtd/spi/sf_internal.h | 7 +++++++ drivers/mtd/spi/sf_ops.c | 36 ++++++++++++++++++++++++++++++++++++ drivers/mtd/spi/sf_probe.c | 10 ++++++++++ 3 files changed, 53 insertions(+)
diff --git a/drivers/mtd/spi/sf_internal.h b/drivers/mtd/spi/sf_internal.h index 1de1dac..9519bd8 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 Micron, 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 @@ -231,6 +235,9 @@ 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);
+int spi_flash_cmd_4B_addr_switch(struct spi_flash *flash,
int enable, u8 idcode0);
#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 deebcab..ace1156 100644 --- a/drivers/mtd/spi/sf_ops.c +++ b/drivers/mtd/spi/sf_ops.c @@ -93,6 +93,42 @@ int spi_flash_cmd_write_config(struct spi_flash *flash, u8 wc) } #endif
+int spi_flash_cmd_4B_addr_switch(struct spi_flash *flash,
int enable, u8 idcode0)
+{
int ret;
u8 cmd, bar;
bool need_wren = false;
ret = spi_claim_bus(flash->spi);
if (ret) {
debug("SF: unable to claim SPI bus\n");
return ret;
}
switch (idcode0) {
case SPI_FLASH_CFI_MFR_STMICRO:
/* Some Micron need WREN command; all will accept it */
need_wren = true;
case SPI_FLASH_CFI_MFR_MACRONIX:
case SPI_FLASH_CFI_MFR_WINBOND:
if (need_wren)
spi_flash_cmd_write_enable(flash);
cmd = enable ? CMD_ENTER_4B_ADDR : CMD_EXIT_4B_ADDR;
ret = spi_flash_cmd(flash->spi, cmd, NULL, 0);
if (need_wren)
spi_flash_cmd_write_disable(flash);
return ret;
default:
/* Spansion style */
bar = enable << 7;
cmd = CMD_BANKADDR_BRWR;
return spi_flash_cmd_write(flash->spi, &cmd, 1, &bar, 1);
}
+}
#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..3b204f8 100644 --- a/drivers/mtd/spi/sf_probe.c +++ b/drivers/mtd/spi/sf_probe.c @@ -170,6 +170,16 @@ static int spi_flash_validate_params(struct spi_slave *spi, u8 *idcode, flash->page_size <<= flash->shift; flash->sector_size = params->sector_size << flash->shift; flash->size = flash->sector_size * params->nr_sectors << flash->shift;
/*
* So far, the 4-byte address mode haven't been supported in U-Boot,
* and make sure the chip (> 16MiB) in default 3-byte address mode,
* in case of warm bootup, the chip was set to 4-byte mode in kernel.
*/
if (flash->size > SPI_FLASH_16MB_BOUN) {
if (spi_flash_cmd_4B_addr_switch(flash, false, idcode[0]) < 0)
debug("SF: enter 3B address mode failed\n");
}
Flash can operate > 16MiB w/o switching to 4B addressing so, this will fire an issue who all using BAR.
#ifdef CONFIG_SF_DUAL_FLASH if (flash->dual_flash & SF_DUAL_STACKED_FLASH) flash->size <<= 1;
thanks!

-----Original Message----- From: Jagan Teki [mailto:jteki@openedev.com] Sent: 2015年8月11日 19:45 To: Hou Zhiqiang-B48286 Cc: u-boot@lists.denx.de; Siva Durga Prasad Paladugu; Sun York-R58495 Subject: Re: [U-Boot] [PATCH V5 2/2] sf: Turn SPI flash chip into 3-Byte address mode
On 11 August 2015 at 16:25, Zhiqiang Hou B48286@freescale.com wrote:
From: Hou Zhiqiang B48286@freescale.com
For more than 16MiB SPI flash chips, there are 3-Byte and 4-Byte address mode, and only the 3-Byte address mode is supported in U-Boot
so far.
So, reset the SPI flash to 3-Byte address mode in probe to ensure the SPI flash work correctly, because it may has been set to 4-Byte address mode after warm boot.
Signed-off-by: Hou Zhiqiang B48286@freescale.com
Tested on T1042RDB board.
V5: 1. Removed #ifdef for STMICRO. 2. Add support for Spansion chips (>16MiB) switch to 3-Byte address
mode.
V4: Split the the patch to 2 patches for clear FSR and SPI flash
address mode.
V3: Generate the patch based on the latest tree git://git.denx.de/u-
boot.git.
V2: Add the operation of enter 3 Byte address mode in probe. V1: Based on git://git.denx.de/u-boot.git.
drivers/mtd/spi/sf_internal.h | 7 +++++++ drivers/mtd/spi/sf_ops.c | 36
++++++++++++++++++++++++++++++++++++
drivers/mtd/spi/sf_probe.c | 10 ++++++++++ 3 files changed, 53 insertions(+)
diff --git a/drivers/mtd/spi/sf_internal.h b/drivers/mtd/spi/sf_internal.h index 1de1dac..9519bd8 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 Micron, 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 @@ -231,6 +235,9 @@ 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);
+int spi_flash_cmd_4B_addr_switch(struct spi_flash *flash,
int enable, u8 idcode0);
#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 deebcab..ace1156 100644 --- a/drivers/mtd/spi/sf_ops.c +++ b/drivers/mtd/spi/sf_ops.c @@ -93,6 +93,42 @@ int spi_flash_cmd_write_config(struct spi_flash *flash, u8 wc) } #endif
+int spi_flash_cmd_4B_addr_switch(struct spi_flash *flash,
int enable, u8 idcode0) {
int ret;
u8 cmd, bar;
bool need_wren = false;
ret = spi_claim_bus(flash->spi);
if (ret) {
debug("SF: unable to claim SPI bus\n");
return ret;
}
switch (idcode0) {
case SPI_FLASH_CFI_MFR_STMICRO:
/* Some Micron need WREN command; all will accept it */
need_wren = true;
case SPI_FLASH_CFI_MFR_MACRONIX:
case SPI_FLASH_CFI_MFR_WINBOND:
if (need_wren)
spi_flash_cmd_write_enable(flash);
cmd = enable ? CMD_ENTER_4B_ADDR : CMD_EXIT_4B_ADDR;
ret = spi_flash_cmd(flash->spi, cmd, NULL, 0);
if (need_wren)
spi_flash_cmd_write_disable(flash);
return ret;
default:
/* Spansion style */
bar = enable << 7;
cmd = CMD_BANKADDR_BRWR;
return spi_flash_cmd_write(flash->spi, &cmd, 1, &bar,
1);
}
+}
#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..3b204f8 100644 --- a/drivers/mtd/spi/sf_probe.c +++ b/drivers/mtd/spi/sf_probe.c @@ -170,6 +170,16 @@ static int spi_flash_validate_params(struct
spi_slave *spi, u8 *idcode,
flash->page_size <<= flash->shift; flash->sector_size = params->sector_size << flash->shift; flash->size = flash->sector_size * params->nr_sectors <<
flash->shift;
/*
* So far, the 4-byte address mode haven't been supported in U-
Boot,
* and make sure the chip (> 16MiB) in default 3-byte address
mode,
* in case of warm bootup, the chip was set to 4-byte mode in
kernel.
*/
if (flash->size > SPI_FLASH_16MB_BOUN) {
if (spi_flash_cmd_4B_addr_switch(flash, false,
idcode[0]) < 0)
debug("SF: enter 3B address mode failed\n");
}
Flash can operate > 16MiB w/o switching to 4B addressing so, this will fire an issue who all using BAR.
No, it won't fire the issue, because this operation switching to 3B mode in the front of func spi_flash_validate_params, and the 3B address mode is the default mode, as if the system cold boot up. If the chip always using BAR, the post process will re-initial the BAR to 4B addressing.
#ifdef CONFIG_SF_DUAL_FLASH if (flash->dual_flash & SF_DUAL_STACKED_FLASH) flash->size <<= 1;
thanks!
Jagan | openedev.
Thanks, Zhiqiang
participants (3)
-
Hou Zhiqiang
-
Jagan Teki
-
Zhiqiang Hou