--- a/drivers/mtd/spi-nor/spi-nor.c +++ b/drivers/mtd/spi-nor/spi-nor.c @@ -107,6 +107,34 @@ return val; } +static int read_sr2(struct spi_nor *nor) +{ + int ret; + u8 val; + + ret = nor->read_reg(nor, SPINOR_OP_RDSR2, &val, 1); + if (ret < 0) { + pr_err("error %d reading SR2\n", (int) ret); + return ret; + } + + return val; +} + +static int read_sr3(struct spi_nor *nor) +{ + int ret; + u8 val; + + ret = nor->read_reg(nor, SPINOR_OP_RDSR3, &val, 1); + if (ret < 0) { + pr_err("error %d reading SR3\n", (int) ret); + return ret; + } + + return val; +} + /* * Read the flag status register, returning its value in the location * Return the status register value. @@ -166,6 +194,12 @@ return nor->write_reg(nor, SPINOR_OP_WRSR2, nor->cmd_buf, 1); } +static inline int write_sr3(struct spi_nor *nor, u8 val) +{ + nor->cmd_buf[0] = val; + return nor->write_reg(nor, SPINOR_OP_WRSR3, nor->cmd_buf, 1); +} + /* * Set write enable latch with Write Enable command. * Returns negative if error occurred. @@ -2178,7 +2212,7 @@ if (!nor->level) { nor->end_addr = 0; - dev_warn(nor->dev, "all blocks is unlocked.\n"); + dev_warn(nor->dev, "all blocks are unlocked.\n"); return; } @@ -2261,6 +2295,48 @@ return level; } +static void bsp_global_unlock(struct spi_nor *nor) { + int val; + + dev_info(nor->dev, "Force global unlock\n"); + write_enable(nor); + /* Global Block/Sector Unlock, + * see 8.2.42 Global Block/Sector Unlock (98h) */ + nor->write_reg(nor, 0x98, NULL, 0); + spi_nor_wait_till_ready(nor); + + val = read_sr(nor); + if (val){ + dev_info(nor->dev, "SR1:[%02x]->[00] ", val); + val=0; + write_enable(nor); + write_sr(nor, val); + if(spi_nor_wait_till_ready(nor)) + dev_err(nor->dev, "error while writing SR1.\n"); + } + + val = read_sr2(nor); + if (val){ + dev_info(nor->dev, "SR2:[%02x]->[00]", val); + val = 0; + write_enable(nor); + write_sr2(nor, val); + if(spi_nor_wait_till_ready(nor)) + dev_err(nor->dev, "error while writing SR2.\n"); + } + + val = read_sr3(nor); + if (val & 4){ + dev_info(nor->dev, "SR3:[%02x]->[%02x]", val, val ^ 4); + val ^= 4; // Remove SR3_WPS + write_enable(nor); + write_sr3(nor, val); + if(spi_nor_wait_till_ready(nor)) + dev_err(nor->dev, "error while writing SR3.\n"); + } + +} + static void bsp_get_spi_lock_info(struct spi_nor *nor, const struct flash_info *info) { unsigned int chipsize; @@ -2275,18 +2351,12 @@ case SNOR_MFR_ESMT: case SNOR_MFR_EON: case SNOR_MFR_SPANSION: + bsp_global_unlock(nor); /* BP bit convert to lock level */ nor->level = bsp_bp_to_level(nor, info, BP_NUM_3); break; case SNOR_MFR_WINBOND: - if (!strcmp("w25q128(b/f)v", info->name)) { - dev_info(nor->dev, "Force global unlock\n"); - write_enable(nor); - /* Global Block/Sector Unlock, - * see 8.2.42 Global Block/Sector Unlock (98h) */ - nor->write_reg(nor, 0x98, NULL, 0); - write_disable(nor); - } + bsp_global_unlock(nor); /* BP bit convert to lock level */ if (chipsize <= _16M) nor->level = bsp_bp_to_level(nor, info, BP_NUM_3); @@ -2294,7 +2364,8 @@ nor->level = bsp_bp_to_level(nor, info, BP_NUM_4); break; case SNOR_MFR_MACRONIX: - + case SNOR_MFR_XMC: + bsp_global_unlock(nor); /* BP bit convert to lock level */ if (chipsize <= _8M) nor->level = bsp_bp_to_level(nor, info, BP_NUM_3); @@ -2302,6 +2373,7 @@ nor->level = bsp_bp_to_level(nor, info, BP_NUM_4); break; case SNOR_MFR_XTX: + bsp_global_unlock(nor); /* BP bit convert to lock level */ nor->level = bsp_bp_to_level(nor, info, BP_NUM_4); break; @@ -2562,6 +2634,8 @@ { int ret; unsigned char cval,val; + unsigned char sr1, sr2, sr3; + char sr1txt[256] = {0}, sr2txt[256] = {0}, sr3txt[256] = {0}; if (JEDEC_MFR(info) == SNOR_MFR_MACRONIX){ val = read_sr(nor); @@ -2583,26 +2657,24 @@ nor->cmd_buf[1]=(cval & (~CR_DUMMY_CYCLE)); ret = nor->write_reg(nor, SPINOR_OP_WRSR, nor->cmd_buf, 2); } - } else if (JEDEC_MFR(info) == SNOR_MFR_WINBOND) { - unsigned char sr1, sr2, sr3; - char sr1txt[256] = {0}, sr2txt[256] = {0}, sr3txt[256] = {0}; - - sr1 = read_sr(nor); - if (sr1 < 0) - return sr1; - ret = nor->read_reg(nor, SPINOR_OP_RDSR2, &sr2, 1); - if(ret < 0){ - dev_err(nor->dev, "error %d reading config Reg.\n", ret); - return ret; - } - ret = nor->read_reg(nor, SPINOR_OP_RDSR3, &sr3, 1); - if(ret < 0){ - dev_err(nor->dev, "error %d reading config Reg.\n", ret); - return ret; - } - dev_info(nor->dev, "Winbond: SR1 [%s], SR2 [%s], SR3 [%s]\n", - winbond_sr1txt(sr1txt, sr1), winbond_sr2txt(sr2txt, sr2), - winbond_sr3txt(sr3txt, sr3)); + } + + sr1 = read_sr(nor); + if (sr1 < 0) + return sr1; + sr2 = read_sr2(nor); + if (sr2 < 0) + return sr2; + sr3 = read_sr3(nor); + if (sr3 < 0) + return sr3; + if (JEDEC_MFR(info) == SNOR_MFR_WINBOND) { + dev_info(nor->dev, "Winbond: SR1 [%s], SR2 [%s], SR3 [%s]\n", + winbond_sr1txt(sr1txt, sr1), winbond_sr2txt(sr2txt, sr2), + winbond_sr3txt(sr3txt, sr3)); + } else { + dev_info(nor->dev, "SR1 [%02x], SR2 [%02x], SR3 [%02x]\n", + sr1, sr2, sr3); } if (params) { --- a/include/linux/mtd/spi-nor.h +++ b/include/linux/mtd/spi-nor.h @@ -30,6 +30,7 @@ #define SNOR_MFR_ESMT 0x8c #define SNOR_MFR_GD 0xc8 #define SNOR_MFR_XTX 0x0b +#define SNOR_MFR_XMC 0x20 #define SNOR_MFR_PUYA 0x85 #define SNOR_MFR_FM 0xa1 #define SNOR_MFR_ISSI 0x9d