mtd: spi-nor: Recover from Spansion/Cypress errors
S25FL{128|256|512}S datasheets say: "When P_ERR or E_ERR bits are set to one, the WIP bit will remain set to one indicating the device remains busy and unable to receive new operation commands. A Clear Status Register (CLSR) command must be received to return the device to standby mode." Current spi-nor code works until first error occurs, but write/erase errors are not just rare hardware failures, they also occur if user tries to flash write-protected areas. After such attempt no SPI command can be executed any more and even read fails. This patch adds support for P_ERR and E_ERR bits in Status Register 1 (so that operation fails immediately and not after a long timeout) and proper recovery from the error condition. Tested on Spansion S25FS128S, which is supported by S25FL129P entry. Signed-off-by: Alexander Sverdlin <alexander.sverdlin@nokia.com> Signed-off-by: Cyrille Pitchen <cyrille.pitchen@wedev4u.fr>
This commit is contained in:

committed by
Cyrille Pitchen

parent
fe602838a6
commit
c4b3eacc1d
@@ -88,6 +88,7 @@ struct flash_info {
|
||||
*/
|
||||
#define NO_CHIP_ERASE BIT(12) /* Chip does not support chip erase */
|
||||
#define SPI_NOR_SKIP_SFDP BIT(13) /* Skip parsing of SFDP tables */
|
||||
#define USE_CLSR BIT(14) /* use CLSR command */
|
||||
};
|
||||
|
||||
#define JEDEC_MFR(info) ((info)->id[0])
|
||||
@@ -308,8 +309,18 @@ static inline int spi_nor_sr_ready(struct spi_nor *nor)
|
||||
int sr = read_sr(nor);
|
||||
if (sr < 0)
|
||||
return sr;
|
||||
else
|
||||
return !(sr & SR_WIP);
|
||||
|
||||
if (nor->flags & SNOR_F_USE_CLSR && sr & (SR_E_ERR | SR_P_ERR)) {
|
||||
if (sr & SR_E_ERR)
|
||||
dev_err(nor->dev, "Erase Error occurred\n");
|
||||
else
|
||||
dev_err(nor->dev, "Programming Error occurred\n");
|
||||
|
||||
nor->write_reg(nor, SPINOR_OP_CLSR, NULL, 0);
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
return !(sr & SR_WIP);
|
||||
}
|
||||
|
||||
static inline int spi_nor_fsr_ready(struct spi_nor *nor)
|
||||
@@ -1043,15 +1054,15 @@ static const struct flash_info spi_nor_ids[] = {
|
||||
*/
|
||||
{ "s25sl032p", INFO(0x010215, 0x4d00, 64 * 1024, 64, SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ) },
|
||||
{ "s25sl064p", INFO(0x010216, 0x4d00, 64 * 1024, 128, SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ) },
|
||||
{ "s25fl256s0", INFO(0x010219, 0x4d00, 256 * 1024, 128, 0) },
|
||||
{ "s25fl256s1", INFO(0x010219, 0x4d01, 64 * 1024, 512, SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ) },
|
||||
{ "s25fl512s", INFO(0x010220, 0x4d00, 256 * 1024, 256, SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ) },
|
||||
{ "s25fl256s0", INFO(0x010219, 0x4d00, 256 * 1024, 128, USE_CLSR) },
|
||||
{ "s25fl256s1", INFO(0x010219, 0x4d01, 64 * 1024, 512, SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ | USE_CLSR) },
|
||||
{ "s25fl512s", INFO(0x010220, 0x4d00, 256 * 1024, 256, SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ | USE_CLSR) },
|
||||
{ "s70fl01gs", INFO(0x010221, 0x4d00, 256 * 1024, 256, 0) },
|
||||
{ "s25sl12800", INFO(0x012018, 0x0300, 256 * 1024, 64, 0) },
|
||||
{ "s25sl12801", INFO(0x012018, 0x0301, 64 * 1024, 256, 0) },
|
||||
{ "s25fl128s", INFO6(0x012018, 0x4d0180, 64 * 1024, 256, SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ) },
|
||||
{ "s25fl129p0", INFO(0x012018, 0x4d00, 256 * 1024, 64, SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ) },
|
||||
{ "s25fl129p1", INFO(0x012018, 0x4d01, 64 * 1024, 256, SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ) },
|
||||
{ "s25fl128s", INFO6(0x012018, 0x4d0180, 64 * 1024, 256, SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ | USE_CLSR) },
|
||||
{ "s25fl129p0", INFO(0x012018, 0x4d00, 256 * 1024, 64, SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ | USE_CLSR) },
|
||||
{ "s25fl129p1", INFO(0x012018, 0x4d01, 64 * 1024, 256, SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ | USE_CLSR) },
|
||||
{ "s25sl004a", INFO(0x010212, 0, 64 * 1024, 8, 0) },
|
||||
{ "s25sl008a", INFO(0x010213, 0, 64 * 1024, 16, 0) },
|
||||
{ "s25sl016a", INFO(0x010214, 0, 64 * 1024, 32, 0) },
|
||||
@@ -2707,6 +2718,8 @@ int spi_nor_scan(struct spi_nor *nor, const char *name,
|
||||
nor->flags |= SNOR_F_HAS_SR_TB;
|
||||
if (info->flags & NO_CHIP_ERASE)
|
||||
nor->flags |= SNOR_F_NO_OP_CHIP_ERASE;
|
||||
if (info->flags & USE_CLSR)
|
||||
nor->flags |= SNOR_F_USE_CLSR;
|
||||
|
||||
if (info->flags & SPI_NOR_NO_ERASE)
|
||||
mtd->flags |= MTD_NO_ERASE;
|
||||
|
Reference in New Issue
Block a user